501
489
def test_signatures_default(self):
502
490
my_config = config.Config()
503
self.assertFalse(my_config.signature_needed())
492
self.applyDeprecated(deprecated_in((2, 5, 0)),
493
my_config.signature_needed))
504
494
self.assertEqual(config.CHECK_IF_POSSIBLE,
505
my_config.signature_checking())
495
self.applyDeprecated(deprecated_in((2, 5, 0)),
496
my_config.signature_checking))
506
497
self.assertEqual(config.SIGN_WHEN_REQUIRED,
507
my_config.signing_policy())
498
self.applyDeprecated(deprecated_in((2, 5, 0)),
499
my_config.signing_policy))
509
501
def test_signatures_template_method(self):
510
502
my_config = InstrumentedConfig()
511
self.assertEqual(config.CHECK_NEVER, my_config.signature_checking())
503
self.assertEqual(config.CHECK_NEVER,
504
self.applyDeprecated(deprecated_in((2, 5, 0)),
505
my_config.signature_checking))
512
506
self.assertEqual(['_get_signature_checking'], my_config._calls)
514
508
def test_signatures_template_method_none(self):
515
509
my_config = InstrumentedConfig()
516
510
my_config._signatures = None
517
511
self.assertEqual(config.CHECK_IF_POSSIBLE,
518
my_config.signature_checking())
512
self.applyDeprecated(deprecated_in((2, 5, 0)),
513
my_config.signature_checking))
519
514
self.assertEqual(['_get_signature_checking'], my_config._calls)
521
516
def test_gpg_signing_command_default(self):
522
517
my_config = config.Config()
523
self.assertEqual('gpg', my_config.gpg_signing_command())
518
self.assertEqual('gpg',
519
self.applyDeprecated(deprecated_in((2, 5, 0)),
520
my_config.gpg_signing_command))
525
522
def test_get_user_option_default(self):
526
523
my_config = config.Config()
673
678
def test_saved_with_content(self):
674
679
content = 'foo = bar\n'
675
conf = config.IniBasedConfig.from_string(
676
content, file_name='./test.conf', save=True)
680
config.IniBasedConfig.from_string(content, file_name='./test.conf',
677
682
self.assertFileEqual(content, 'test.conf')
680
class TestIniConfigOptionExpansionDefaultValue(tests.TestCaseInTempDir):
681
"""What is the default value of expand for config options.
683
This is an opt-in beta feature used to evaluate whether or not option
684
references can appear in dangerous place raising exceptions, disapearing
685
(and as such corrupting data) or if it's safe to activate the option by
688
Note that these tests relies on config._expand_default_value being already
689
overwritten in the parent class setUp.
693
super(TestIniConfigOptionExpansionDefaultValue, self).setUp()
697
self.warnings.append(args[0] % args[1:])
698
self.overrideAttr(trace, 'warning', warning)
700
def get_config(self, expand):
701
c = config.GlobalConfig.from_string('bzr.config.expand=%s' % (expand,),
705
def assertExpandIs(self, expected):
706
actual = config._get_expand_default_value()
707
#self.config.get_user_option_as_bool('bzr.config.expand')
708
self.assertEquals(expected, actual)
710
def test_default_is_None(self):
711
self.assertEquals(None, config._expand_default_value)
713
def test_default_is_False_even_if_None(self):
714
self.config = self.get_config(None)
715
self.assertExpandIs(False)
717
def test_default_is_False_even_if_invalid(self):
718
self.config = self.get_config('<your choice>')
719
self.assertExpandIs(False)
721
# Huh ? My choice is False ? Thanks, always happy to hear that :D
722
# Wait, you've been warned !
723
self.assertLength(1, self.warnings)
725
'Value "<your choice>" is not a boolean for "bzr.config.expand"',
728
def test_default_is_True(self):
729
self.config = self.get_config(True)
730
self.assertExpandIs(True)
732
def test_default_is_False(self):
733
self.config = self.get_config(False)
734
self.assertExpandIs(False)
737
685
class TestIniConfigOptionExpansion(tests.TestCase):
738
686
"""Test option expansion from the IniConfig level.
1226
1187
my_config = config.GlobalConfig()
1227
1188
self.assertEqual(None, my_config._get_user_id())
1229
def test_configured_editor(self):
1230
my_config = config.GlobalConfig.from_string(sample_config_text)
1231
editor = self.applyDeprecated(
1232
deprecated_in((2, 4, 0)), my_config.get_editor)
1233
self.assertEqual('vim', editor)
1235
1190
def test_signatures_always(self):
1236
1191
my_config = config.GlobalConfig.from_string(sample_always_signatures)
1237
1192
self.assertEqual(config.CHECK_NEVER,
1238
my_config.signature_checking())
1193
self.applyDeprecated(deprecated_in((2, 5, 0)),
1194
my_config.signature_checking))
1239
1195
self.assertEqual(config.SIGN_ALWAYS,
1240
my_config.signing_policy())
1241
self.assertEqual(True, my_config.signature_needed())
1196
self.applyDeprecated(deprecated_in((2, 5, 0)),
1197
my_config.signing_policy))
1198
self.assertEqual(True,
1199
self.applyDeprecated(deprecated_in((2, 5, 0)),
1200
my_config.signature_needed))
1243
1202
def test_signatures_if_possible(self):
1244
1203
my_config = config.GlobalConfig.from_string(sample_maybe_signatures)
1245
1204
self.assertEqual(config.CHECK_NEVER,
1246
my_config.signature_checking())
1205
self.applyDeprecated(deprecated_in((2, 5, 0)),
1206
my_config.signature_checking))
1247
1207
self.assertEqual(config.SIGN_WHEN_REQUIRED,
1248
my_config.signing_policy())
1249
self.assertEqual(False, my_config.signature_needed())
1208
self.applyDeprecated(deprecated_in((2, 5, 0)),
1209
my_config.signing_policy))
1210
self.assertEqual(False, self.applyDeprecated(deprecated_in((2, 5, 0)),
1211
my_config.signature_needed))
1251
1213
def test_signatures_ignore(self):
1252
1214
my_config = config.GlobalConfig.from_string(sample_ignore_signatures)
1253
1215
self.assertEqual(config.CHECK_ALWAYS,
1254
my_config.signature_checking())
1216
self.applyDeprecated(deprecated_in((2, 5, 0)),
1217
my_config.signature_checking))
1255
1218
self.assertEqual(config.SIGN_NEVER,
1256
my_config.signing_policy())
1257
self.assertEqual(False, my_config.signature_needed())
1219
self.applyDeprecated(deprecated_in((2, 5, 0)),
1220
my_config.signing_policy))
1221
self.assertEqual(False, self.applyDeprecated(deprecated_in((2, 5, 0)),
1222
my_config.signature_needed))
1259
1224
def _get_sample_config(self):
1260
1225
my_config = config.GlobalConfig.from_string(sample_config_text)
1538
1518
self.get_branch_config('http://www.example.com',
1539
1519
global_config=sample_ignore_signatures)
1540
1520
self.assertEqual(config.CHECK_ALWAYS,
1541
self.my_config.signature_checking())
1521
self.applyDeprecated(deprecated_in((2, 5, 0)),
1522
self.my_config.signature_checking))
1542
1523
self.assertEqual(config.SIGN_NEVER,
1543
self.my_config.signing_policy())
1524
self.applyDeprecated(deprecated_in((2, 5, 0)),
1525
self.my_config.signing_policy))
1545
1527
def test_signatures_never(self):
1546
1528
self.get_branch_config('/a/c')
1547
1529
self.assertEqual(config.CHECK_NEVER,
1548
self.my_config.signature_checking())
1530
self.applyDeprecated(deprecated_in((2, 5, 0)),
1531
self.my_config.signature_checking))
1550
1533
def test_signatures_when_available(self):
1551
1534
self.get_branch_config('/a/', global_config=sample_ignore_signatures)
1552
1535
self.assertEqual(config.CHECK_IF_POSSIBLE,
1553
self.my_config.signature_checking())
1536
self.applyDeprecated(deprecated_in((2, 5, 0)),
1537
self.my_config.signature_checking))
1555
1539
def test_signatures_always(self):
1556
1540
self.get_branch_config('/b')
1557
1541
self.assertEqual(config.CHECK_ALWAYS,
1558
self.my_config.signature_checking())
1542
self.applyDeprecated(deprecated_in((2, 5, 0)),
1543
self.my_config.signature_checking))
1560
1545
def test_gpg_signing_command(self):
1561
1546
self.get_branch_config('/b')
1562
self.assertEqual("gnome-gpg", self.my_config.gpg_signing_command())
1547
self.assertEqual("gnome-gpg",
1548
self.applyDeprecated(deprecated_in((2, 5, 0)),
1549
self.my_config.gpg_signing_command))
1564
1551
def test_gpg_signing_command_missing(self):
1565
1552
self.get_branch_config('/a')
1566
self.assertEqual("false", self.my_config.gpg_signing_command())
1553
self.assertEqual("false",
1554
self.applyDeprecated(deprecated_in((2, 5, 0)),
1555
self.my_config.gpg_signing_command))
1568
1557
def test_gpg_signing_key(self):
1569
1558
self.get_branch_config('/b')
1570
self.assertEqual("DD4D5088", self.my_config.gpg_signing_key())
1559
self.assertEqual("DD4D5088", self.applyDeprecated(deprecated_in((2, 5, 0)),
1560
self.my_config.gpg_signing_key))
1572
1562
def test_gpg_signing_key_default(self):
1573
1563
self.get_branch_config('/a')
1574
self.assertEqual("erik@bagfors.nu", self.my_config.gpg_signing_key())
1564
self.assertEqual("erik@bagfors.nu",
1565
self.applyDeprecated(deprecated_in((2, 5, 0)),
1566
self.my_config.gpg_signing_key))
1576
1568
def test_get_user_option_global(self):
1577
1569
self.get_branch_config('/a')
1790
1771
def test_signatures_forced(self):
1791
1772
my_config = self.get_branch_config(
1792
1773
global_config=sample_always_signatures)
1793
self.assertEqual(config.CHECK_NEVER, my_config.signature_checking())
1794
self.assertEqual(config.SIGN_ALWAYS, my_config.signing_policy())
1795
self.assertTrue(my_config.signature_needed())
1774
self.assertEqual(config.CHECK_NEVER,
1775
self.applyDeprecated(deprecated_in((2, 5, 0)),
1776
my_config.signature_checking))
1777
self.assertEqual(config.SIGN_ALWAYS,
1778
self.applyDeprecated(deprecated_in((2, 5, 0)),
1779
my_config.signing_policy))
1780
self.assertTrue(self.applyDeprecated(deprecated_in((2, 5, 0)),
1781
my_config.signature_needed))
1797
1783
def test_signatures_forced_branch(self):
1798
1784
my_config = self.get_branch_config(
1799
1785
global_config=sample_ignore_signatures,
1800
1786
branch_data_config=sample_always_signatures)
1801
self.assertEqual(config.CHECK_NEVER, my_config.signature_checking())
1802
self.assertEqual(config.SIGN_ALWAYS, my_config.signing_policy())
1803
self.assertTrue(my_config.signature_needed())
1787
self.assertEqual(config.CHECK_NEVER,
1788
self.applyDeprecated(deprecated_in((2, 5, 0)),
1789
my_config.signature_checking))
1790
self.assertEqual(config.SIGN_ALWAYS,
1791
self.applyDeprecated(deprecated_in((2, 5, 0)),
1792
my_config.signing_policy))
1793
self.assertTrue(self.applyDeprecated(deprecated_in((2, 5, 0)),
1794
my_config.signature_needed))
1805
1796
def test_gpg_signing_command(self):
1806
1797
my_config = self.get_branch_config(
1807
1798
global_config=sample_config_text,
1808
1799
# branch data cannot set gpg_signing_command
1809
1800
branch_data_config="gpg_signing_command=pgp")
1810
self.assertEqual('gnome-gpg', my_config.gpg_signing_command())
1801
self.assertEqual('gnome-gpg',
1802
self.applyDeprecated(deprecated_in((2, 5, 0)),
1803
my_config.gpg_signing_command))
1812
1805
def test_get_user_option_global(self):
1813
1806
my_config = self.get_branch_config(global_config=sample_config_text)
2265
2220
def test_save_hook_remote_bzrdir(self):
2266
2221
remote_branch = branch.Branch.open(self.get_url('tree'))
2267
2222
self.addCleanup(remote_branch.lock_write().unlock)
2268
remote_bzrdir = bzrdir.BzrDir.open(self.get_url('tree'))
2223
remote_bzrdir = controldir.ControlDir.open(self.get_url('tree'))
2269
2224
self.assertSaveHook(remote_bzrdir._get_config())
2227
class TestOptionNames(tests.TestCase):
2229
def is_valid(self, name):
2230
return config._option_ref_re.match('{%s}' % name) is not None
2232
def test_valid_names(self):
2233
self.assertTrue(self.is_valid('foo'))
2234
self.assertTrue(self.is_valid('foo.bar'))
2235
self.assertTrue(self.is_valid('f1'))
2236
self.assertTrue(self.is_valid('_'))
2237
self.assertTrue(self.is_valid('__bar__'))
2238
self.assertTrue(self.is_valid('a_'))
2239
self.assertTrue(self.is_valid('a1'))
2241
def test_invalid_names(self):
2242
self.assertFalse(self.is_valid(' foo'))
2243
self.assertFalse(self.is_valid('foo '))
2244
self.assertFalse(self.is_valid('1'))
2245
self.assertFalse(self.is_valid('1,2'))
2246
self.assertFalse(self.is_valid('foo$'))
2247
self.assertFalse(self.is_valid('!foo'))
2248
self.assertFalse(self.is_valid('foo.'))
2249
self.assertFalse(self.is_valid('foo..bar'))
2250
self.assertFalse(self.is_valid('{}'))
2251
self.assertFalse(self.is_valid('{a}'))
2252
self.assertFalse(self.is_valid('a\n'))
2254
def assertSingleGroup(self, reference):
2255
# the regexp is used with split and as such should match the reference
2256
# *only*, if more groups needs to be defined, (?:...) should be used.
2257
m = config._option_ref_re.match('{a}')
2258
self.assertLength(1, m.groups())
2260
def test_valid_references(self):
2261
self.assertSingleGroup('{a}')
2262
self.assertSingleGroup('{{a}}')
2272
2265
class TestOption(tests.TestCase):
2274
2267
def test_default_value(self):
2275
2268
opt = config.Option('foo', default='bar')
2276
2269
self.assertEquals('bar', opt.get_default())
2271
def test_callable_default_value(self):
2272
def bar_as_unicode():
2274
opt = config.Option('foo', default=bar_as_unicode)
2275
self.assertEquals('bar', opt.get_default())
2278
2277
def test_default_value_from_env(self):
2279
2278
opt = config.Option('foo', default='bar', default_from_env=['FOO'])
2280
2279
self.overrideEnv('FOO', 'quux')
2296
2295
self.assertRaises(AssertionError, config.Option, 'foo',
2297
2296
default=object())
2300
class TestOptionConverterMixin(object):
2302
def assertConverted(self, expected, opt, value):
2303
self.assertEquals(expected, opt.convert_from_unicode(value))
2305
def assertWarns(self, opt, value):
2308
warnings.append(args[0] % args[1:])
2309
self.overrideAttr(trace, 'warning', warning)
2310
self.assertEquals(None, opt.convert_from_unicode(value))
2311
self.assertLength(1, warnings)
2313
'Value "%s" is not valid for "%s"' % (value, opt.name),
2316
def assertErrors(self, opt, value):
2317
self.assertRaises(errors.ConfigOptionValueError,
2318
opt.convert_from_unicode, value)
2320
def assertConvertInvalid(self, opt, invalid_value):
2322
self.assertEquals(None, opt.convert_from_unicode(invalid_value))
2323
opt.invalid = 'warning'
2324
self.assertWarns(opt, invalid_value)
2325
opt.invalid = 'error'
2326
self.assertErrors(opt, invalid_value)
2329
class TestOptionWithBooleanConverter(tests.TestCase, TestOptionConverterMixin):
2331
def get_option(self):
2332
return config.Option('foo', help='A boolean.',
2333
from_unicode=config.bool_from_store)
2335
def test_convert_invalid(self):
2336
opt = self.get_option()
2337
# A string that is not recognized as a boolean
2338
self.assertConvertInvalid(opt, u'invalid-boolean')
2339
# A list of strings is never recognized as a boolean
2340
self.assertConvertInvalid(opt, [u'not', u'a', u'boolean'])
2342
def test_convert_valid(self):
2343
opt = self.get_option()
2344
self.assertConverted(True, opt, u'True')
2345
self.assertConverted(True, opt, u'1')
2346
self.assertConverted(False, opt, u'False')
2349
class TestOptionWithIntegerConverter(tests.TestCase, TestOptionConverterMixin):
2351
def get_option(self):
2352
return config.Option('foo', help='An integer.',
2353
from_unicode=config.int_from_store)
2355
def test_convert_invalid(self):
2356
opt = self.get_option()
2357
# A string that is not recognized as an integer
2358
self.assertConvertInvalid(opt, u'forty-two')
2359
# A list of strings is never recognized as an integer
2360
self.assertConvertInvalid(opt, [u'a', u'list'])
2362
def test_convert_valid(self):
2363
opt = self.get_option()
2364
self.assertConverted(16, opt, u'16')
2366
class TestOptionWithListConverter(tests.TestCase, TestOptionConverterMixin):
2368
def get_option(self):
2369
return config.Option('foo', help='A list.',
2370
from_unicode=config.list_from_store)
2372
def test_convert_invalid(self):
2373
# No string is invalid as all forms can be converted to a list
2376
def test_convert_valid(self):
2377
opt = self.get_option()
2378
# An empty string is an empty list
2379
self.assertConverted([], opt, '') # Using a bare str() just in case
2380
self.assertConverted([], opt, u'')
2382
self.assertConverted([u'True'], opt, u'True')
2384
self.assertConverted([u'42'], opt, u'42')
2386
self.assertConverted([u'bar'], opt, u'bar')
2387
# A list remains a list (configObj will turn a string containing commas
2388
# into a list, but that's not what we're testing here)
2389
self.assertConverted([u'foo', u'1', u'True'],
2390
opt, [u'foo', u'1', u'True'])
2393
class TestOptionConverterMixin(object):
2395
def assertConverted(self, expected, opt, value):
2396
self.assertEquals(expected, opt.convert_from_unicode(value))
2398
def assertWarns(self, opt, value):
2401
warnings.append(args[0] % args[1:])
2402
self.overrideAttr(trace, 'warning', warning)
2403
self.assertEquals(None, opt.convert_from_unicode(value))
2404
self.assertLength(1, warnings)
2406
'Value "%s" is not valid for "%s"' % (value, opt.name),
2409
def assertErrors(self, opt, value):
2410
self.assertRaises(errors.ConfigOptionValueError,
2411
opt.convert_from_unicode, value)
2413
def assertConvertInvalid(self, opt, invalid_value):
2415
self.assertEquals(None, opt.convert_from_unicode(invalid_value))
2416
opt.invalid = 'warning'
2417
self.assertWarns(opt, invalid_value)
2418
opt.invalid = 'error'
2419
self.assertErrors(opt, invalid_value)
2422
class TestOptionWithBooleanConverter(tests.TestCase, TestOptionConverterMixin):
2424
def get_option(self):
2425
return config.Option('foo', help='A boolean.',
2426
from_unicode=config.bool_from_store)
2428
def test_convert_invalid(self):
2429
opt = self.get_option()
2430
# A string that is not recognized as a boolean
2431
self.assertConvertInvalid(opt, u'invalid-boolean')
2432
# A list of strings is never recognized as a boolean
2433
self.assertConvertInvalid(opt, [u'not', u'a', u'boolean'])
2435
def test_convert_valid(self):
2436
opt = self.get_option()
2437
self.assertConverted(True, opt, u'True')
2438
self.assertConverted(True, opt, u'1')
2439
self.assertConverted(False, opt, u'False')
2442
class TestOptionWithIntegerConverter(tests.TestCase, TestOptionConverterMixin):
2444
def get_option(self):
2445
return config.Option('foo', help='An integer.',
2446
from_unicode=config.int_from_store)
2448
def test_convert_invalid(self):
2449
opt = self.get_option()
2450
# A string that is not recognized as an integer
2451
self.assertConvertInvalid(opt, u'forty-two')
2452
# A list of strings is never recognized as an integer
2453
self.assertConvertInvalid(opt, [u'a', u'list'])
2455
def test_convert_valid(self):
2456
opt = self.get_option()
2457
self.assertConverted(16, opt, u'16')
2460
class TestOptionWithListConverter(tests.TestCase, TestOptionConverterMixin):
2462
def get_option(self):
2463
return config.Option('foo', help='A list.',
2464
from_unicode=config.list_from_store)
2298
def test_not_supported_callable_default_value_not_unicode(self):
2299
def bar_not_unicode():
2301
opt = config.Option('foo', default=bar_not_unicode)
2302
self.assertRaises(AssertionError, opt.get_default)
2304
def test_get_help_topic(self):
2305
opt = config.Option('foo')
2306
self.assertEquals('foo', opt.get_help_topic())
2309
class TestOptionConverterMixin(object):
2311
def assertConverted(self, expected, opt, value):
2312
self.assertEquals(expected, opt.convert_from_unicode(None, value))
2314
def assertWarns(self, opt, value):
2317
warnings.append(args[0] % args[1:])
2318
self.overrideAttr(trace, 'warning', warning)
2319
self.assertEquals(None, opt.convert_from_unicode(None, value))
2320
self.assertLength(1, warnings)
2322
'Value "%s" is not valid for "%s"' % (value, opt.name),
2325
def assertErrors(self, opt, value):
2326
self.assertRaises(errors.ConfigOptionValueError,
2327
opt.convert_from_unicode, None, value)
2329
def assertConvertInvalid(self, opt, invalid_value):
2331
self.assertEquals(None, opt.convert_from_unicode(None, invalid_value))
2332
opt.invalid = 'warning'
2333
self.assertWarns(opt, invalid_value)
2334
opt.invalid = 'error'
2335
self.assertErrors(opt, invalid_value)
2338
class TestOptionWithBooleanConverter(tests.TestCase, TestOptionConverterMixin):
2340
def get_option(self):
2341
return config.Option('foo', help='A boolean.',
2342
from_unicode=config.bool_from_store)
2344
def test_convert_invalid(self):
2345
opt = self.get_option()
2346
# A string that is not recognized as a boolean
2347
self.assertConvertInvalid(opt, u'invalid-boolean')
2348
# A list of strings is never recognized as a boolean
2349
self.assertConvertInvalid(opt, [u'not', u'a', u'boolean'])
2351
def test_convert_valid(self):
2352
opt = self.get_option()
2353
self.assertConverted(True, opt, u'True')
2354
self.assertConverted(True, opt, u'1')
2355
self.assertConverted(False, opt, u'False')
2358
class TestOptionWithIntegerConverter(tests.TestCase, TestOptionConverterMixin):
2360
def get_option(self):
2361
return config.Option('foo', help='An integer.',
2362
from_unicode=config.int_from_store)
2364
def test_convert_invalid(self):
2365
opt = self.get_option()
2366
# A string that is not recognized as an integer
2367
self.assertConvertInvalid(opt, u'forty-two')
2368
# A list of strings is never recognized as an integer
2369
self.assertConvertInvalid(opt, [u'a', u'list'])
2371
def test_convert_valid(self):
2372
opt = self.get_option()
2373
self.assertConverted(16, opt, u'16')
2376
class TestOptionWithSIUnitConverter(tests.TestCase, TestOptionConverterMixin):
2378
def get_option(self):
2379
return config.Option('foo', help='An integer in SI units.',
2380
from_unicode=config.int_SI_from_store)
2382
def test_convert_invalid(self):
2383
opt = self.get_option()
2384
self.assertConvertInvalid(opt, u'not-a-unit')
2385
self.assertConvertInvalid(opt, u'Gb') # Forgot the int
2386
self.assertConvertInvalid(opt, u'1b') # Forgot the unit
2387
self.assertConvertInvalid(opt, u'1GG')
2388
self.assertConvertInvalid(opt, u'1Mbb')
2389
self.assertConvertInvalid(opt, u'1MM')
2391
def test_convert_valid(self):
2392
opt = self.get_option()
2393
self.assertConverted(int(5e3), opt, u'5kb')
2394
self.assertConverted(int(5e6), opt, u'5M')
2395
self.assertConverted(int(5e6), opt, u'5MB')
2396
self.assertConverted(int(5e9), opt, u'5g')
2397
self.assertConverted(int(5e9), opt, u'5gB')
2398
self.assertConverted(100, opt, u'100')
2401
class TestListOption(tests.TestCase, TestOptionConverterMixin):
2403
def get_option(self):
2404
return config.ListOption('foo', help='A list.')
2466
2406
def test_convert_invalid(self):
2467
2407
opt = self.get_option()
2702
2726
self.assertRaises(AssertionError, store._load_from_string, 'bar=baz')
2729
class TestStoreQuoting(TestStore):
2731
scenarios = [(key, {'get_store': builder}) for key, builder
2732
in config.test_store_builder_registry.iteritems()]
2735
super(TestStoreQuoting, self).setUp()
2736
self.store = self.get_store(self)
2737
# We need a loaded store but any content will do
2738
self.store._load_from_string('')
2740
def assertIdempotent(self, s):
2741
"""Assert that quoting an unquoted string is a no-op and vice-versa.
2743
What matters here is that option values, as they appear in a store, can
2744
be safely round-tripped out of the store and back.
2746
:param s: A string, quoted if required.
2748
self.assertEquals(s, self.store.quote(self.store.unquote(s)))
2749
self.assertEquals(s, self.store.unquote(self.store.quote(s)))
2751
def test_empty_string(self):
2752
if isinstance(self.store, config.IniFileStore):
2753
# configobj._quote doesn't handle empty values
2754
self.assertRaises(AssertionError,
2755
self.assertIdempotent, '')
2757
self.assertIdempotent('')
2758
# But quoted empty strings are ok
2759
self.assertIdempotent('""')
2761
def test_embedded_spaces(self):
2762
self.assertIdempotent('" a b c "')
2764
def test_embedded_commas(self):
2765
self.assertIdempotent('" a , b c "')
2767
def test_simple_comma(self):
2768
if isinstance(self.store, config.IniFileStore):
2769
# configobj requires that lists are special-cased
2770
self.assertRaises(AssertionError,
2771
self.assertIdempotent, ',')
2773
self.assertIdempotent(',')
2774
# When a single comma is required, quoting is also required
2775
self.assertIdempotent('","')
2777
def test_list(self):
2778
if isinstance(self.store, config.IniFileStore):
2779
# configobj requires that lists are special-cased
2780
self.assertRaises(AssertionError,
2781
self.assertIdempotent, 'a,b')
2783
self.assertIdempotent('a,b')
2786
class TestDictFromStore(tests.TestCase):
2788
def test_unquote_not_string(self):
2789
conf = config.MemoryStack('x=2\n[a_section]\na=1\n')
2790
value = conf.get('a_section')
2791
# Urgh, despite 'conf' asking for the no-name section, we get the
2792
# content of another section as a dict o_O
2793
self.assertEquals({'a': '1'}, value)
2794
unquoted = conf.store.unquote(value)
2795
# Which cannot be unquoted but shouldn't crash either (the use cases
2796
# are getting the value or displaying it. In the later case, '%s' will
2798
self.assertEquals({'a': '1'}, unquoted)
2799
self.assertEquals("{u'a': u'1'}", '%s' % (unquoted,))
2705
2802
class TestIniFileStoreContent(tests.TestCaseWithTransport):
2706
2803
"""Simulate loading a config store with content of various encodings.
2906
3042
config.ConfigHooks.install_named_hook('save', hook, None)
2907
3043
self.assertLength(0, calls)
2908
3044
store = self.get_store(self)
3045
# FIXME: There should be a better way than relying on the test
3046
# parametrization to identify branch.conf -- vila 2011-0526
3047
if self.store_id in ('branch', 'remote_branch'):
3048
# branch stores requires write locked branches
3049
self.addCleanup(store.branch.lock_write().unlock)
2909
3050
section = store.get_mutable_section('baz')
2910
3051
section.set('foo', 'bar')
2912
3053
self.assertLength(1, calls)
2913
3054
self.assertEquals((store,), calls[0])
3056
def test_set_mark_dirty(self):
3057
stack = config.MemoryStack('')
3058
self.assertLength(0, stack.store.dirty_sections)
3059
stack.set('foo', 'baz')
3060
self.assertLength(1, stack.store.dirty_sections)
3061
self.assertTrue(stack.store._need_saving())
3063
def test_remove_mark_dirty(self):
3064
stack = config.MemoryStack('foo=bar')
3065
self.assertLength(0, stack.store.dirty_sections)
3067
self.assertLength(1, stack.store.dirty_sections)
3068
self.assertTrue(stack.store._need_saving())
3071
class TestStoreSaveChanges(tests.TestCaseWithTransport):
3072
"""Tests that config changes are kept in memory and saved on-demand."""
3075
super(TestStoreSaveChanges, self).setUp()
3076
self.transport = self.get_transport()
3077
# Most of the tests involve two stores pointing to the same persistent
3078
# storage to observe the effects of concurrent changes
3079
self.st1 = config.TransportIniFileStore(self.transport, 'foo.conf')
3080
self.st2 = config.TransportIniFileStore(self.transport, 'foo.conf')
3083
self.warnings.append(args[0] % args[1:])
3084
self.overrideAttr(trace, 'warning', warning)
3086
def has_store(self, store):
3087
store_basename = urlutils.relative_url(self.transport.external_url(),
3088
store.external_url())
3089
return self.transport.has(store_basename)
3091
def get_stack(self, store):
3092
# Any stack will do as long as it uses the right store, just a single
3093
# no-name section is enough
3094
return config.Stack([store.get_sections], store)
3096
def test_no_changes_no_save(self):
3097
s = self.get_stack(self.st1)
3098
s.store.save_changes()
3099
self.assertEquals(False, self.has_store(self.st1))
3101
def test_unrelated_concurrent_update(self):
3102
s1 = self.get_stack(self.st1)
3103
s2 = self.get_stack(self.st2)
3104
s1.set('foo', 'bar')
3105
s2.set('baz', 'quux')
3107
# Changes don't propagate magically
3108
self.assertEquals(None, s1.get('baz'))
3109
s2.store.save_changes()
3110
self.assertEquals('quux', s2.get('baz'))
3111
# Changes are acquired when saving
3112
self.assertEquals('bar', s2.get('foo'))
3113
# Since there is no overlap, no warnings are emitted
3114
self.assertLength(0, self.warnings)
3116
def test_concurrent_update_modified(self):
3117
s1 = self.get_stack(self.st1)
3118
s2 = self.get_stack(self.st2)
3119
s1.set('foo', 'bar')
3120
s2.set('foo', 'baz')
3123
s2.store.save_changes()
3124
self.assertEquals('baz', s2.get('foo'))
3125
# But the user get a warning
3126
self.assertLength(1, self.warnings)
3127
warning = self.warnings[0]
3128
self.assertStartsWith(warning, 'Option foo in section None')
3129
self.assertEndsWith(warning, 'was changed from <CREATED> to bar.'
3130
' The baz value will be saved.')
3132
def test_concurrent_deletion(self):
3133
self.st1._load_from_string('foo=bar')
3135
s1 = self.get_stack(self.st1)
3136
s2 = self.get_stack(self.st2)
3139
s1.store.save_changes()
3141
self.assertLength(0, self.warnings)
3142
s2.store.save_changes()
3144
self.assertLength(1, self.warnings)
3145
warning = self.warnings[0]
3146
self.assertStartsWith(warning, 'Option foo in section None')
3147
self.assertEndsWith(warning, 'was changed from bar to <CREATED>.'
3148
' The <DELETED> value will be saved.')
3151
class TestQuotingIniFileStore(tests.TestCaseWithTransport):
3153
def get_store(self):
3154
return config.TransportIniFileStore(self.get_transport(), 'foo.conf')
3156
def test_get_quoted_string(self):
3157
store = self.get_store()
3158
store._load_from_string('foo= " abc "')
3159
stack = config.Stack([store.get_sections])
3160
self.assertEquals(' abc ', stack.get('foo'))
3162
def test_set_quoted_string(self):
3163
store = self.get_store()
3164
stack = config.Stack([store.get_sections], store)
3165
stack.set('foo', ' a b c ')
3167
self.assertFileEqual('foo = " a b c "' + os.linesep, 'foo.conf')
2916
3170
class TestTransportIniFileStore(TestStore):
3230
3479
matcher = config.LocationMatcher(store, expected_url)
3231
3480
self.assertEquals(expected_location, matcher.location)
3482
def test_branch_name_colo(self):
3483
store = self.get_store(self)
3484
store._load_from_string(dedent("""\
3486
push_location=my{branchname}
3488
matcher = config.LocationMatcher(store, 'file:///,branch=example%3c')
3489
self.assertEqual('example<', matcher.branch_name)
3490
((_, section),) = matcher.get_sections()
3491
self.assertEqual('example<', section.locals['branchname'])
3493
def test_branch_name_basename(self):
3494
store = self.get_store(self)
3495
store._load_from_string(dedent("""\
3497
push_location=my{branchname}
3499
matcher = config.LocationMatcher(store, 'file:///parent/example%3c')
3500
self.assertEqual('example<', matcher.branch_name)
3501
((_, section),) = matcher.get_sections()
3502
self.assertEqual('example<', section.locals['branchname'])
3505
class TestStartingPathMatcher(TestStore):
3508
super(TestStartingPathMatcher, self).setUp()
3509
# Any simple store is good enough
3510
self.store = config.IniFileStore()
3512
def assertSectionIDs(self, expected, location, content):
3513
self.store._load_from_string(content)
3514
matcher = config.StartingPathMatcher(self.store, location)
3515
sections = list(matcher.get_sections())
3516
self.assertLength(len(expected), sections)
3517
self.assertEqual(expected, [section.id for _, section in sections])
3520
def test_empty(self):
3521
self.assertSectionIDs([], self.get_url(), '')
3523
def test_url_vs_local_paths(self):
3524
# The matcher location is an url and the section names are local paths
3525
self.assertSectionIDs(['/foo/bar', '/foo'],
3526
'file:///foo/bar/baz', '''\
3531
def test_local_path_vs_url(self):
3532
# The matcher location is a local path and the section names are urls
3533
self.assertSectionIDs(['file:///foo/bar', 'file:///foo'],
3534
'/foo/bar/baz', '''\
3540
def test_no_name_section_included_when_present(self):
3541
# Note that other tests will cover the case where the no-name section
3542
# is empty and as such, not included.
3543
sections = self.assertSectionIDs(['/foo/bar', '/foo', None],
3544
'/foo/bar/baz', '''\
3545
option = defined so the no-name section exists
3549
self.assertEquals(['baz', 'bar/baz', '/foo/bar/baz'],
3550
[s.locals['relpath'] for _, s in sections])
3552
def test_order_reversed(self):
3553
self.assertSectionIDs(['/foo/bar', '/foo'], '/foo/bar/baz', '''\
3558
def test_unrelated_section_excluded(self):
3559
self.assertSectionIDs(['/foo/bar', '/foo'], '/foo/bar/baz', '''\
3565
def test_glob_included(self):
3566
sections = self.assertSectionIDs(['/foo/*/baz', '/foo/b*', '/foo'],
3567
'/foo/bar/baz', '''\
3573
# Note that 'baz' as a relpath for /foo/b* is not fully correct, but
3574
# nothing really is... as far using {relpath} to append it to something
3575
# else, this seems good enough though.
3576
self.assertEquals(['', 'baz', 'bar/baz'],
3577
[s.locals['relpath'] for _, s in sections])
3579
def test_respect_order(self):
3580
self.assertSectionIDs(['/foo', '/foo/b*', '/foo/*/baz'],
3581
'/foo/bar/baz', '''\
3234
3589
class TestNameMatcher(TestStore):
3262
3617
self.assertLength(0, sections)
3265
class TestStackGet(tests.TestCase):
3267
# FIXME: This should be parametrized for all known Stack or dedicated
3268
# paramerized tests created to avoid bloating -- vila 2011-03-31
3270
def overrideOptionRegistry(self):
3620
class TestBaseStackGet(tests.TestCase):
3623
super(TestBaseStackGet, self).setUp()
3271
3624
self.overrideAttr(config, 'option_registry', config.OptionRegistry())
3273
def test_single_config_get(self):
3274
conf = dict(foo='bar')
3275
conf_stack = config.Stack([conf])
3276
self.assertEquals('bar', conf_stack.get('foo'))
3626
def test_get_first_definition(self):
3627
store1 = config.IniFileStore()
3628
store1._load_from_string('foo=bar')
3629
store2 = config.IniFileStore()
3630
store2._load_from_string('foo=baz')
3631
conf = config.Stack([store1.get_sections, store2.get_sections])
3632
self.assertEquals('bar', conf.get('foo'))
3278
3634
def test_get_with_registered_default_value(self):
3279
conf_stack = config.Stack([dict()])
3280
opt = config.Option('foo', default='bar')
3281
self.overrideOptionRegistry()
3282
config.option_registry.register('foo', opt)
3635
config.option_registry.register(config.Option('foo', default='bar'))
3636
conf_stack = config.Stack([])
3283
3637
self.assertEquals('bar', conf_stack.get('foo'))
3285
3639
def test_get_without_registered_default_value(self):
3286
conf_stack = config.Stack([dict()])
3287
opt = config.Option('foo')
3288
self.overrideOptionRegistry()
3289
config.option_registry.register('foo', opt)
3640
config.option_registry.register(config.Option('foo'))
3641
conf_stack = config.Stack([])
3290
3642
self.assertEquals(None, conf_stack.get('foo'))
3292
3644
def test_get_without_default_value_for_not_registered(self):
3293
conf_stack = config.Stack([dict()])
3294
opt = config.Option('foo')
3295
self.overrideOptionRegistry()
3645
conf_stack = config.Stack([])
3296
3646
self.assertEquals(None, conf_stack.get('foo'))
3298
def test_get_first_definition(self):
3299
conf1 = dict(foo='bar')
3300
conf2 = dict(foo='baz')
3301
conf_stack = config.Stack([conf1, conf2])
3302
self.assertEquals('bar', conf_stack.get('foo'))
3304
def test_get_embedded_definition(self):
3305
conf1 = dict(yy='12')
3306
conf2 = config.Stack([dict(xx='42'), dict(foo='baz')])
3307
conf_stack = config.Stack([conf1, conf2])
3308
self.assertEquals('baz', conf_stack.get('foo'))
3310
3648
def test_get_for_empty_section_callable(self):
3311
3649
conf_stack = config.Stack([lambda : []])
3312
3650
self.assertEquals(None, conf_stack.get('foo'))
3314
3652
def test_get_for_broken_callable(self):
3315
3653
# Trying to use and invalid callable raises an exception on first use
3316
conf_stack = config.Stack([lambda : object()])
3654
conf_stack = config.Stack([object])
3317
3655
self.assertRaises(TypeError, conf_stack.get, 'foo')
3658
class TestStackWithSimpleStore(tests.TestCase):
3661
super(TestStackWithSimpleStore, self).setUp()
3662
self.overrideAttr(config, 'option_registry', config.OptionRegistry())
3663
self.registry = config.option_registry
3665
def get_conf(self, content=None):
3666
return config.MemoryStack(content)
3668
def test_override_value_from_env(self):
3669
self.overrideEnv('FOO', None)
3670
self.registry.register(
3671
config.Option('foo', default='bar', override_from_env=['FOO']))
3672
self.overrideEnv('FOO', 'quux')
3673
# Env variable provides a default taking over the option one
3674
conf = self.get_conf('foo=store')
3675
self.assertEquals('quux', conf.get('foo'))
3677
def test_first_override_value_from_env_wins(self):
3678
self.overrideEnv('NO_VALUE', None)
3679
self.overrideEnv('FOO', None)
3680
self.overrideEnv('BAZ', None)
3681
self.registry.register(
3682
config.Option('foo', default='bar',
3683
override_from_env=['NO_VALUE', 'FOO', 'BAZ']))
3684
self.overrideEnv('FOO', 'foo')
3685
self.overrideEnv('BAZ', 'baz')
3686
# The first env var set wins
3687
conf = self.get_conf('foo=store')
3688
self.assertEquals('foo', conf.get('foo'))
3691
class TestMemoryStack(tests.TestCase):
3694
conf = config.MemoryStack('foo=bar')
3695
self.assertEquals('bar', conf.get('foo'))
3698
conf = config.MemoryStack('foo=bar')
3699
conf.set('foo', 'baz')
3700
self.assertEquals('baz', conf.get('foo'))
3702
def test_no_content(self):
3703
conf = config.MemoryStack()
3704
# No content means no loading
3705
self.assertFalse(conf.store.is_loaded())
3706
self.assertRaises(NotImplementedError, conf.get, 'foo')
3707
# But a content can still be provided
3708
conf.store._load_from_string('foo=bar')
3709
self.assertEquals('bar', conf.get('foo'))
3712
class TestStackIterSections(tests.TestCase):
3714
def test_empty_stack(self):
3715
conf = config.Stack([])
3716
sections = list(conf.iter_sections())
3717
self.assertLength(0, sections)
3719
def test_empty_store(self):
3720
store = config.IniFileStore()
3721
store._load_from_string('')
3722
conf = config.Stack([store.get_sections])
3723
sections = list(conf.iter_sections())
3724
self.assertLength(0, sections)
3726
def test_simple_store(self):
3727
store = config.IniFileStore()
3728
store._load_from_string('foo=bar')
3729
conf = config.Stack([store.get_sections])
3730
tuples = list(conf.iter_sections())
3731
self.assertLength(1, tuples)
3732
(found_store, found_section) = tuples[0]
3733
self.assertIs(store, found_store)
3735
def test_two_stores(self):
3736
store1 = config.IniFileStore()
3737
store1._load_from_string('foo=bar')
3738
store2 = config.IniFileStore()
3739
store2._load_from_string('bar=qux')
3740
conf = config.Stack([store1.get_sections, store2.get_sections])
3741
tuples = list(conf.iter_sections())
3742
self.assertLength(2, tuples)
3743
self.assertIs(store1, tuples[0][0])
3744
self.assertIs(store2, tuples[1][0])
3320
3747
class TestStackWithTransport(tests.TestCaseWithTransport):
3322
3749
scenarios = [(key, {'get_stack': builder}) for key, builder
3406
3836
def test_get_default_integer_None(self):
3407
3837
self.register_integer_option('foo')
3408
self.assertEquals(None, self.conf.get('foo'))
3838
conf = self.get_conf('')
3839
self.assertEquals(None, conf.get('foo'))
3410
3841
def test_get_default_integer(self):
3411
3842
self.register_integer_option('foo', 42)
3412
self.assertEquals(42, self.conf.get('foo'))
3843
conf = self.get_conf('')
3844
self.assertEquals(42, conf.get('foo'))
3414
3846
def test_get_default_integer_as_string(self):
3415
3847
self.register_integer_option('foo', u'42')
3416
self.assertEquals(42, self.conf.get('foo'))
3848
conf = self.get_conf('')
3849
self.assertEquals(42, conf.get('foo'))
3418
3851
def test_get_default_integer_from_env(self):
3419
3852
self.register_integer_option('foo', default_from_env=['FOO'])
3420
3853
self.overrideEnv('FOO', '18')
3421
self.assertEquals(18, self.conf.get('foo'))
3854
conf = self.get_conf('')
3855
self.assertEquals(18, conf.get('foo'))
3423
3857
def test_get_default_integer_when_conversion_fails(self):
3424
3858
self.register_integer_option('foo', default='12')
3425
self.conf.store._load_from_string('foo=invalid integer')
3426
self.assertEquals(12, self.conf.get('foo'))
3859
conf = self.get_conf('foo=invalid integer')
3860
self.assertEquals(12, conf.get('foo'))
3428
3862
def register_list_option(self, name, default=None, default_from_env=None):
3429
l = config.Option(name, help='A list.',
3430
default=default, default_from_env=default_from_env,
3431
from_unicode=config.list_from_store)
3863
l = config.ListOption(name, help='A list.', default=default,
3864
default_from_env=default_from_env)
3432
3865
self.registry.register(l)
3434
3867
def test_get_default_list_None(self):
3435
3868
self.register_list_option('foo')
3436
self.assertEquals(None, self.conf.get('foo'))
3869
conf = self.get_conf('')
3870
self.assertEquals(None, conf.get('foo'))
3438
3872
def test_get_default_list_empty(self):
3439
3873
self.register_list_option('foo', '')
3440
self.assertEquals([], self.conf.get('foo'))
3874
conf = self.get_conf('')
3875
self.assertEquals([], conf.get('foo'))
3442
3877
def test_get_default_list_from_env(self):
3443
3878
self.register_list_option('foo', default_from_env=['FOO'])
3444
3879
self.overrideEnv('FOO', '')
3445
self.assertEquals([], self.conf.get('foo'))
3880
conf = self.get_conf('')
3881
self.assertEquals([], conf.get('foo'))
3447
3883
def test_get_with_list_converter_no_item(self):
3448
3884
self.register_list_option('foo', None)
3449
self.conf.store._load_from_string('foo=,')
3450
self.assertEquals([], self.conf.get('foo'))
3885
conf = self.get_conf('foo=,')
3886
self.assertEquals([], conf.get('foo'))
3452
3888
def test_get_with_list_converter_many_items(self):
3453
3889
self.register_list_option('foo', None)
3454
self.conf.store._load_from_string('foo=m,o,r,e')
3455
self.assertEquals(['m', 'o', 'r', 'e'], self.conf.get('foo'))
3890
conf = self.get_conf('foo=m,o,r,e')
3891
self.assertEquals(['m', 'o', 'r', 'e'], conf.get('foo'))
3457
3893
def test_get_with_list_converter_embedded_spaces_many_items(self):
3458
3894
self.register_list_option('foo', None)
3459
self.conf.store._load_from_string('foo=" bar", "baz "')
3460
self.assertEquals([' bar', 'baz '], self.conf.get('foo'))
3895
conf = self.get_conf('foo=" bar", "baz "')
3896
self.assertEquals([' bar', 'baz '], conf.get('foo'))
3462
3898
def test_get_with_list_converter_stripped_spaces_many_items(self):
3463
3899
self.register_list_option('foo', None)
3464
self.conf.store._load_from_string('foo= bar , baz ')
3465
self.assertEquals(['bar', 'baz'], self.conf.get('foo'))
3900
conf = self.get_conf('foo= bar , baz ')
3901
self.assertEquals(['bar', 'baz'], conf.get('foo'))
3468
3904
class TestIterOptionRefs(tests.TestCase):
4494
4959
self.assertEquals((None, None), (realname, address))
4962
class TestDefaultMailDomain(tests.TestCaseInTempDir):
4963
"""Test retrieving default domain from mailname file"""
4965
def test_default_mail_domain_simple(self):
4966
f = file('simple', 'w')
4968
f.write("domainname.com\n")
4971
r = config._get_default_mail_domain('simple')
4972
self.assertEquals('domainname.com', r)
4974
def test_default_mail_domain_no_eol(self):
4975
f = file('no_eol', 'w')
4977
f.write("domainname.com")
4980
r = config._get_default_mail_domain('no_eol')
4981
self.assertEquals('domainname.com', r)
4983
def test_default_mail_domain_multiple_lines(self):
4984
f = file('multiple_lines', 'w')
4986
f.write("domainname.com\nsome other text\n")
4989
r = config._get_default_mail_domain('multiple_lines')
4990
self.assertEquals('domainname.com', r)
4993
class EmailOptionTests(tests.TestCase):
4995
def test_default_email_uses_BZR_EMAIL(self):
4996
conf = config.MemoryStack('email=jelmer@debian.org')
4997
# BZR_EMAIL takes precedence over EMAIL
4998
self.overrideEnv('BZR_EMAIL', 'jelmer@samba.org')
4999
self.overrideEnv('EMAIL', 'jelmer@apache.org')
5000
self.assertEquals('jelmer@samba.org', conf.get('email'))
5002
def test_default_email_uses_EMAIL(self):
5003
conf = config.MemoryStack('')
5004
self.overrideEnv('BZR_EMAIL', None)
5005
self.overrideEnv('EMAIL', 'jelmer@apache.org')
5006
self.assertEquals('jelmer@apache.org', conf.get('email'))
5008
def test_BZR_EMAIL_overrides(self):
5009
conf = config.MemoryStack('email=jelmer@debian.org')
5010
self.overrideEnv('BZR_EMAIL', 'jelmer@apache.org')
5011
self.assertEquals('jelmer@apache.org', conf.get('email'))
5012
self.overrideEnv('BZR_EMAIL', None)
5013
self.overrideEnv('EMAIL', 'jelmer@samba.org')
5014
self.assertEquals('jelmer@debian.org', conf.get('email'))
5017
class MailClientOptionTests(tests.TestCase):
5019
def test_default(self):
5020
conf = config.MemoryStack('')
5021
client = conf.get('mail_client')
5022
self.assertIs(client, mail_client.DefaultMail)
5024
def test_evolution(self):
5025
conf = config.MemoryStack('mail_client=evolution')
5026
client = conf.get('mail_client')
5027
self.assertIs(client, mail_client.Evolution)
5029
def test_kmail(self):
5030
conf = config.MemoryStack('mail_client=kmail')
5031
client = conf.get('mail_client')
5032
self.assertIs(client, mail_client.KMail)
5034
def test_mutt(self):
5035
conf = config.MemoryStack('mail_client=mutt')
5036
client = conf.get('mail_client')
5037
self.assertIs(client, mail_client.Mutt)
5039
def test_thunderbird(self):
5040
conf = config.MemoryStack('mail_client=thunderbird')
5041
client = conf.get('mail_client')
5042
self.assertIs(client, mail_client.Thunderbird)
5044
def test_explicit_default(self):
5045
conf = config.MemoryStack('mail_client=default')
5046
client = conf.get('mail_client')
5047
self.assertIs(client, mail_client.DefaultMail)
5049
def test_editor(self):
5050
conf = config.MemoryStack('mail_client=editor')
5051
client = conf.get('mail_client')
5052
self.assertIs(client, mail_client.Editor)
5054
def test_mapi(self):
5055
conf = config.MemoryStack('mail_client=mapi')
5056
client = conf.get('mail_client')
5057
self.assertIs(client, mail_client.MAPIClient)
5059
def test_xdg_email(self):
5060
conf = config.MemoryStack('mail_client=xdg-email')
5061
client = conf.get('mail_client')
5062
self.assertIs(client, mail_client.XDGEmail)
5064
def test_unknown(self):
5065
conf = config.MemoryStack('mail_client=firebird')
5066
self.assertRaises(errors.ConfigOptionValueError, conf.get,