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'))
2240
# Don't break bzr-svn for no good reason
2241
self.assertTrue(self.is_valid('guessed-layout'))
2243
def test_invalid_names(self):
2244
self.assertFalse(self.is_valid(' foo'))
2245
self.assertFalse(self.is_valid('foo '))
2246
self.assertFalse(self.is_valid('1'))
2247
self.assertFalse(self.is_valid('1,2'))
2248
self.assertFalse(self.is_valid('foo$'))
2249
self.assertFalse(self.is_valid('!foo'))
2250
self.assertFalse(self.is_valid('foo.'))
2251
self.assertFalse(self.is_valid('foo..bar'))
2252
self.assertFalse(self.is_valid('{}'))
2253
self.assertFalse(self.is_valid('{a}'))
2254
self.assertFalse(self.is_valid('a\n'))
2255
self.assertFalse(self.is_valid('-'))
2256
self.assertFalse(self.is_valid('-a'))
2257
self.assertFalse(self.is_valid('a-'))
2258
self.assertFalse(self.is_valid('a--a'))
2260
def assertSingleGroup(self, reference):
2261
# the regexp is used with split and as such should match the reference
2262
# *only*, if more groups needs to be defined, (?:...) should be used.
2263
m = config._option_ref_re.match('{a}')
2264
self.assertLength(1, m.groups())
2266
def test_valid_references(self):
2267
self.assertSingleGroup('{a}')
2268
self.assertSingleGroup('{{a}}')
2272
2271
class TestOption(tests.TestCase):
2274
2273
def test_default_value(self):
2275
2274
opt = config.Option('foo', default='bar')
2276
self.assertEquals('bar', opt.get_default())
2275
self.assertEqual('bar', opt.get_default())
2277
def test_callable_default_value(self):
2278
def bar_as_unicode():
2280
opt = config.Option('foo', default=bar_as_unicode)
2281
self.assertEqual('bar', opt.get_default())
2278
2283
def test_default_value_from_env(self):
2279
2284
opt = config.Option('foo', default='bar', default_from_env=['FOO'])
2280
2285
self.overrideEnv('FOO', 'quux')
2281
2286
# Env variable provides a default taking over the option one
2282
self.assertEquals('quux', opt.get_default())
2287
self.assertEqual('quux', opt.get_default())
2284
2289
def test_first_default_value_from_env_wins(self):
2285
2290
opt = config.Option('foo', default='bar',
2296
2301
self.assertRaises(AssertionError, config.Option, 'foo',
2297
2302
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)
2304
def test_not_supported_callable_default_value_not_unicode(self):
2305
def bar_not_unicode():
2307
opt = config.Option('foo', default=bar_not_unicode)
2308
self.assertRaises(AssertionError, opt.get_default)
2310
def test_get_help_topic(self):
2311
opt = config.Option('foo')
2312
self.assertEqual('foo', opt.get_help_topic())
2315
class TestOptionConverter(tests.TestCase):
2317
def assertConverted(self, expected, opt, value):
2318
self.assertEqual(expected, opt.convert_from_unicode(None, value))
2320
def assertCallsWarning(self, opt, value):
2324
warnings.append(args[0] % args[1:])
2325
self.overrideAttr(trace, 'warning', warning)
2326
self.assertEqual(None, opt.convert_from_unicode(None, value))
2327
self.assertLength(1, warnings)
2329
'Value "%s" is not valid for "%s"' % (value, opt.name),
2332
def assertCallsError(self, opt, value):
2333
self.assertRaises(errors.ConfigOptionValueError,
2334
opt.convert_from_unicode, None, value)
2336
def assertConvertInvalid(self, opt, invalid_value):
2338
self.assertEqual(None, opt.convert_from_unicode(None, invalid_value))
2339
opt.invalid = 'warning'
2340
self.assertCallsWarning(opt, invalid_value)
2341
opt.invalid = 'error'
2342
self.assertCallsError(opt, invalid_value)
2345
class TestOptionWithBooleanConverter(TestOptionConverter):
2347
def get_option(self):
2348
return config.Option('foo', help='A boolean.',
2349
from_unicode=config.bool_from_store)
2351
def test_convert_invalid(self):
2352
opt = self.get_option()
2353
# A string that is not recognized as a boolean
2354
self.assertConvertInvalid(opt, u'invalid-boolean')
2355
# A list of strings is never recognized as a boolean
2356
self.assertConvertInvalid(opt, [u'not', u'a', u'boolean'])
2358
def test_convert_valid(self):
2359
opt = self.get_option()
2360
self.assertConverted(True, opt, u'True')
2361
self.assertConverted(True, opt, u'1')
2362
self.assertConverted(False, opt, u'False')
2365
class TestOptionWithIntegerConverter(TestOptionConverter):
2367
def get_option(self):
2368
return config.Option('foo', help='An integer.',
2369
from_unicode=config.int_from_store)
2371
def test_convert_invalid(self):
2372
opt = self.get_option()
2373
# A string that is not recognized as an integer
2374
self.assertConvertInvalid(opt, u'forty-two')
2375
# A list of strings is never recognized as an integer
2376
self.assertConvertInvalid(opt, [u'a', u'list'])
2378
def test_convert_valid(self):
2379
opt = self.get_option()
2380
self.assertConverted(16, opt, u'16')
2383
class TestOptionWithSIUnitConverter(TestOptionConverter):
2385
def get_option(self):
2386
return config.Option('foo', help='An integer in SI units.',
2387
from_unicode=config.int_SI_from_store)
2389
def test_convert_invalid(self):
2390
opt = self.get_option()
2391
self.assertConvertInvalid(opt, u'not-a-unit')
2392
self.assertConvertInvalid(opt, u'Gb') # Forgot the value
2393
self.assertConvertInvalid(opt, u'1b') # Forgot the unit
2394
self.assertConvertInvalid(opt, u'1GG')
2395
self.assertConvertInvalid(opt, u'1Mbb')
2396
self.assertConvertInvalid(opt, u'1MM')
2398
def test_convert_valid(self):
2399
opt = self.get_option()
2400
self.assertConverted(int(5e3), opt, u'5kb')
2401
self.assertConverted(int(5e6), opt, u'5M')
2402
self.assertConverted(int(5e6), opt, u'5MB')
2403
self.assertConverted(int(5e9), opt, u'5g')
2404
self.assertConverted(int(5e9), opt, u'5gB')
2405
self.assertConverted(100, opt, u'100')
2408
class TestListOption(TestOptionConverter):
2410
def get_option(self):
2411
return config.ListOption('foo', help='A list.')
2466
2413
def test_convert_invalid(self):
2467
2414
opt = self.get_option()
2563
2576
class TestMutableSection(tests.TestCase):
2565
# FIXME: Parametrize so that all sections (including os.environ and the
2566
# ones produced by Stores) run these tests -- vila 2011-04-01
2578
scenarios = [('mutable',
2580
lambda opts: config.MutableSection('myID', opts)},),
2568
2583
def test_set(self):
2569
2584
a_dict = dict(foo='bar')
2570
section = config.MutableSection('myID', a_dict)
2585
section = self.get_section(a_dict)
2571
2586
section.set('foo', 'new_value')
2572
self.assertEquals('new_value', section.get('foo'))
2587
self.assertEqual('new_value', section.get('foo'))
2573
2588
# The change appears in the shared section
2574
self.assertEquals('new_value', a_dict.get('foo'))
2589
self.assertEqual('new_value', a_dict.get('foo'))
2575
2590
# We keep track of the change
2576
2591
self.assertTrue('foo' in section.orig)
2577
self.assertEquals('bar', section.orig.get('foo'))
2592
self.assertEqual('bar', section.orig.get('foo'))
2579
2594
def test_set_preserve_original_once(self):
2580
2595
a_dict = dict(foo='bar')
2581
section = config.MutableSection('myID', a_dict)
2596
section = self.get_section(a_dict)
2582
2597
section.set('foo', 'first_value')
2583
2598
section.set('foo', 'second_value')
2584
2599
# We keep track of the original value
2585
2600
self.assertTrue('foo' in section.orig)
2586
self.assertEquals('bar', section.orig.get('foo'))
2601
self.assertEqual('bar', section.orig.get('foo'))
2588
2603
def test_remove(self):
2589
2604
a_dict = dict(foo='bar')
2590
section = config.MutableSection('myID', a_dict)
2605
section = self.get_section(a_dict)
2591
2606
section.remove('foo')
2592
2607
# We get None for unknown options via the default value
2593
self.assertEquals(None, section.get('foo'))
2608
self.assertEqual(None, section.get('foo'))
2594
2609
# Or we just get the default value
2595
self.assertEquals('unknown', section.get('foo', 'unknown'))
2610
self.assertEqual('unknown', section.get('foo', 'unknown'))
2596
2611
self.assertFalse('foo' in section.options)
2597
2612
# We keep track of the deletion
2598
2613
self.assertTrue('foo' in section.orig)
2599
self.assertEquals('bar', section.orig.get('foo'))
2614
self.assertEqual('bar', section.orig.get('foo'))
2601
2616
def test_remove_new_option(self):
2602
2617
a_dict = dict()
2603
section = config.MutableSection('myID', a_dict)
2618
section = self.get_section(a_dict)
2604
2619
section.set('foo', 'bar')
2605
2620
section.remove('foo')
2606
2621
self.assertFalse('foo' in section.options)
2607
2622
# The option didn't exist initially so it we need to keep track of it
2608
2623
# with a special value
2609
2624
self.assertTrue('foo' in section.orig)
2610
self.assertEquals(config._NewlyCreatedOption, section.orig['foo'])
2625
self.assertEqual(config._NewlyCreatedOption, section.orig['foo'])
2628
class TestCommandLineStore(tests.TestCase):
2631
super(TestCommandLineStore, self).setUp()
2632
self.store = config.CommandLineStore()
2633
self.overrideAttr(config, 'option_registry', config.OptionRegistry())
2635
def get_section(self):
2636
"""Get the unique section for the command line overrides."""
2637
sections = list(self.store.get_sections())
2638
self.assertLength(1, sections)
2639
store, section = sections[0]
2640
self.assertEqual(self.store, store)
2643
def test_no_override(self):
2644
self.store._from_cmdline([])
2645
section = self.get_section()
2646
self.assertLength(0, list(section.iter_option_names()))
2648
def test_simple_override(self):
2649
self.store._from_cmdline(['a=b'])
2650
section = self.get_section()
2651
self.assertEqual('b', section.get('a'))
2653
def test_list_override(self):
2654
opt = config.ListOption('l')
2655
config.option_registry.register(opt)
2656
self.store._from_cmdline(['l=1,2,3'])
2657
val = self.get_section().get('l')
2658
self.assertEqual('1,2,3', val)
2659
# Reminder: lists should be registered as such explicitely, otherwise
2660
# the conversion needs to be done afterwards.
2661
self.assertEqual(['1', '2', '3'],
2662
opt.convert_from_unicode(self.store, val))
2664
def test_multiple_overrides(self):
2665
self.store._from_cmdline(['a=b', 'x=y'])
2666
section = self.get_section()
2667
self.assertEqual('b', section.get('a'))
2668
self.assertEqual('y', section.get('x'))
2670
def test_wrong_syntax(self):
2671
self.assertRaises(errors.BzrCommandError,
2672
self.store._from_cmdline, ['a=b', 'c'])
2674
class TestStoreMinimalAPI(tests.TestCaseWithTransport):
2676
scenarios = [(key, {'get_store': builder}) for key, builder
2677
in config.test_store_builder_registry.iteritems()] + [
2678
('cmdline', {'get_store': lambda test: config.CommandLineStore()})]
2681
store = self.get_store(self)
2682
if type(store) == config.TransportIniFileStore:
2683
raise tests.TestNotApplicable(
2684
"%s is not a concrete Store implementation"
2685
" so it doesn't need an id" % (store.__class__.__name__,))
2686
self.assertIsNot(None, store.id)
2613
2689
class TestStore(tests.TestCaseWithTransport):
2615
def assertSectionContent(self, expected, section):
2691
def assertSectionContent(self, expected, (store, section)):
2616
2692
"""Assert that some options have the proper values in a section."""
2617
2693
expected_name, expected_options = expected
2618
self.assertEquals(expected_name, section.id)
2694
self.assertEqual(expected_name, section.id)
2620
2696
expected_options,
2621
2697
dict([(k, section.get(k)) for k in expected_options.keys()]))
2657
2733
self.assertRaises(AssertionError, store._load_from_string, 'bar=baz')
2736
class TestStoreQuoting(TestStore):
2738
scenarios = [(key, {'get_store': builder}) for key, builder
2739
in config.test_store_builder_registry.iteritems()]
2742
super(TestStoreQuoting, self).setUp()
2743
self.store = self.get_store(self)
2744
# We need a loaded store but any content will do
2745
self.store._load_from_string('')
2747
def assertIdempotent(self, s):
2748
"""Assert that quoting an unquoted string is a no-op and vice-versa.
2750
What matters here is that option values, as they appear in a store, can
2751
be safely round-tripped out of the store and back.
2753
:param s: A string, quoted if required.
2755
self.assertEqual(s, self.store.quote(self.store.unquote(s)))
2756
self.assertEqual(s, self.store.unquote(self.store.quote(s)))
2758
def test_empty_string(self):
2759
if isinstance(self.store, config.IniFileStore):
2760
# configobj._quote doesn't handle empty values
2761
self.assertRaises(AssertionError,
2762
self.assertIdempotent, '')
2764
self.assertIdempotent('')
2765
# But quoted empty strings are ok
2766
self.assertIdempotent('""')
2768
def test_embedded_spaces(self):
2769
self.assertIdempotent('" a b c "')
2771
def test_embedded_commas(self):
2772
self.assertIdempotent('" a , b c "')
2774
def test_simple_comma(self):
2775
if isinstance(self.store, config.IniFileStore):
2776
# configobj requires that lists are special-cased
2777
self.assertRaises(AssertionError,
2778
self.assertIdempotent, ',')
2780
self.assertIdempotent(',')
2781
# When a single comma is required, quoting is also required
2782
self.assertIdempotent('","')
2784
def test_list(self):
2785
if isinstance(self.store, config.IniFileStore):
2786
# configobj requires that lists are special-cased
2787
self.assertRaises(AssertionError,
2788
self.assertIdempotent, 'a,b')
2790
self.assertIdempotent('a,b')
2793
class TestDictFromStore(tests.TestCase):
2795
def test_unquote_not_string(self):
2796
conf = config.MemoryStack('x=2\n[a_section]\na=1\n')
2797
value = conf.get('a_section')
2798
# Urgh, despite 'conf' asking for the no-name section, we get the
2799
# content of another section as a dict o_O
2800
self.assertEqual({'a': '1'}, value)
2801
unquoted = conf.store.unquote(value)
2802
# Which cannot be unquoted but shouldn't crash either (the use cases
2803
# are getting the value or displaying it. In the later case, '%s' will
2805
self.assertEqual({'a': '1'}, unquoted)
2806
self.assertEqual("{u'a': u'1'}", '%s' % (unquoted,))
2660
2809
class TestIniFileStoreContent(tests.TestCaseWithTransport):
2661
2810
"""Simulate loading a config store with content of various encodings.
2861
3049
config.ConfigHooks.install_named_hook('save', hook, None)
2862
3050
self.assertLength(0, calls)
2863
3051
store = self.get_store(self)
3052
# FIXME: There should be a better way than relying on the test
3053
# parametrization to identify branch.conf -- vila 2011-0526
3054
if self.store_id in ('branch', 'remote_branch'):
3055
# branch stores requires write locked branches
3056
self.addCleanup(store.branch.lock_write().unlock)
2864
3057
section = store.get_mutable_section('baz')
2865
3058
section.set('foo', 'bar')
2867
3060
self.assertLength(1, calls)
2868
self.assertEquals((store,), calls[0])
2871
class TestIniFileStore(TestStore):
3061
self.assertEqual((store,), calls[0])
3063
def test_set_mark_dirty(self):
3064
stack = config.MemoryStack('')
3065
self.assertLength(0, stack.store.dirty_sections)
3066
stack.set('foo', 'baz')
3067
self.assertLength(1, stack.store.dirty_sections)
3068
self.assertTrue(stack.store._need_saving())
3070
def test_remove_mark_dirty(self):
3071
stack = config.MemoryStack('foo=bar')
3072
self.assertLength(0, stack.store.dirty_sections)
3074
self.assertLength(1, stack.store.dirty_sections)
3075
self.assertTrue(stack.store._need_saving())
3078
class TestStoreSaveChanges(tests.TestCaseWithTransport):
3079
"""Tests that config changes are kept in memory and saved on-demand."""
3082
super(TestStoreSaveChanges, self).setUp()
3083
self.transport = self.get_transport()
3084
# Most of the tests involve two stores pointing to the same persistent
3085
# storage to observe the effects of concurrent changes
3086
self.st1 = config.TransportIniFileStore(self.transport, 'foo.conf')
3087
self.st2 = config.TransportIniFileStore(self.transport, 'foo.conf')
3090
self.warnings.append(args[0] % args[1:])
3091
self.overrideAttr(trace, 'warning', warning)
3093
def has_store(self, store):
3094
store_basename = urlutils.relative_url(self.transport.external_url(),
3095
store.external_url())
3096
return self.transport.has(store_basename)
3098
def get_stack(self, store):
3099
# Any stack will do as long as it uses the right store, just a single
3100
# no-name section is enough
3101
return config.Stack([store.get_sections], store)
3103
def test_no_changes_no_save(self):
3104
s = self.get_stack(self.st1)
3105
s.store.save_changes()
3106
self.assertEqual(False, self.has_store(self.st1))
3108
def test_unrelated_concurrent_update(self):
3109
s1 = self.get_stack(self.st1)
3110
s2 = self.get_stack(self.st2)
3111
s1.set('foo', 'bar')
3112
s2.set('baz', 'quux')
3114
# Changes don't propagate magically
3115
self.assertEqual(None, s1.get('baz'))
3116
s2.store.save_changes()
3117
self.assertEqual('quux', s2.get('baz'))
3118
# Changes are acquired when saving
3119
self.assertEqual('bar', s2.get('foo'))
3120
# Since there is no overlap, no warnings are emitted
3121
self.assertLength(0, self.warnings)
3123
def test_concurrent_update_modified(self):
3124
s1 = self.get_stack(self.st1)
3125
s2 = self.get_stack(self.st2)
3126
s1.set('foo', 'bar')
3127
s2.set('foo', 'baz')
3130
s2.store.save_changes()
3131
self.assertEqual('baz', s2.get('foo'))
3132
# But the user get a warning
3133
self.assertLength(1, self.warnings)
3134
warning = self.warnings[0]
3135
self.assertStartsWith(warning, 'Option foo in section None')
3136
self.assertEndsWith(warning, 'was changed from <CREATED> to bar.'
3137
' The baz value will be saved.')
3139
def test_concurrent_deletion(self):
3140
self.st1._load_from_string('foo=bar')
3142
s1 = self.get_stack(self.st1)
3143
s2 = self.get_stack(self.st2)
3146
s1.store.save_changes()
3148
self.assertLength(0, self.warnings)
3149
s2.store.save_changes()
3151
self.assertLength(1, self.warnings)
3152
warning = self.warnings[0]
3153
self.assertStartsWith(warning, 'Option foo in section None')
3154
self.assertEndsWith(warning, 'was changed from bar to <CREATED>.'
3155
' The <DELETED> value will be saved.')
3158
class TestQuotingIniFileStore(tests.TestCaseWithTransport):
3160
def get_store(self):
3161
return config.TransportIniFileStore(self.get_transport(), 'foo.conf')
3163
def test_get_quoted_string(self):
3164
store = self.get_store()
3165
store._load_from_string('foo= " abc "')
3166
stack = config.Stack([store.get_sections])
3167
self.assertEqual(' abc ', stack.get('foo'))
3169
def test_set_quoted_string(self):
3170
store = self.get_store()
3171
stack = config.Stack([store.get_sections], store)
3172
stack.set('foo', ' a b c ')
3174
self.assertFileEqual('foo = " a b c "' + os.linesep, 'foo.conf')
3177
class TestTransportIniFileStore(TestStore):
2873
3179
def test_loading_unknown_file_fails(self):
2874
store = config.IniFileStore(self.get_transport(), 'I-do-not-exist')
3180
store = config.TransportIniFileStore(self.get_transport(),
2875
3182
self.assertRaises(errors.NoSuchFile, store.load)
2877
3184
def test_invalid_content(self):
2878
store = config.IniFileStore(self.get_transport(), 'foo.conf', )
2879
self.assertEquals(False, store.is_loaded())
3185
store = config.TransportIniFileStore(self.get_transport(), 'foo.conf')
3186
self.assertEqual(False, store.is_loaded())
2880
3187
exc = self.assertRaises(
2881
3188
errors.ParseConfigError, store._load_from_string,
2882
3189
'this is invalid !')
2883
3190
self.assertEndsWith(exc.filename, 'foo.conf')
2884
3191
# And the load failed
2885
self.assertEquals(False, store.is_loaded())
3192
self.assertEqual(False, store.is_loaded())
2887
3194
def test_get_embedded_sections(self):
2888
3195
# A more complicated example (which also shows that section names and
2889
3196
# option names share the same name space...)
2890
3197
# FIXME: This should be fixed by forbidding dicts as values ?
2891
3198
# -- vila 2011-04-05
2892
store = config.IniFileStore(self.get_transport(), 'foo.conf', )
3199
store = config.TransportIniFileStore(self.get_transport(), 'foo.conf')
2893
3200
store._load_from_string('''
3126
3436
section=/quux/quux
3128
self.assertEquals(['/foo', '/foo/baz', '/foo/bar', '/foo/bar/baz',
3438
self.assertEqual(['/foo', '/foo/baz', '/foo/bar', '/foo/bar/baz',
3130
[section.id for section in store.get_sections()])
3440
[section.id for _, section in store.get_sections()])
3131
3441
matcher = config.LocationMatcher(store, '/foo/bar/quux')
3132
sections = list(matcher.get_sections())
3133
self.assertEquals([3, 2],
3134
[section.length for section in sections])
3135
self.assertEquals(['/foo/bar', '/foo'],
3442
sections = [section for _, section in matcher.get_sections()]
3443
self.assertEqual(['/foo/bar', '/foo'],
3136
3444
[section.id for section in sections])
3137
self.assertEquals(['quux', 'bar/quux'],
3445
self.assertEqual(['quux', 'bar/quux'],
3138
3446
[section.extra_path for section in sections])
3140
3448
def test_more_specific_sections_first(self):
3141
store = self.get_store('foo.conf')
3449
store = self.get_store(self)
3142
3450
store._load_from_string('''
3146
3454
section=/foo/bar
3148
self.assertEquals(['/foo', '/foo/bar'],
3149
[section.id for section in store.get_sections()])
3456
self.assertEqual(['/foo', '/foo/bar'],
3457
[section.id for _, section in store.get_sections()])
3150
3458
matcher = config.LocationMatcher(store, '/foo/bar/baz')
3151
sections = list(matcher.get_sections())
3152
self.assertEquals([3, 2],
3153
[section.length for section in sections])
3154
self.assertEquals(['/foo/bar', '/foo'],
3459
sections = [section for _, section in matcher.get_sections()]
3460
self.assertEqual(['/foo/bar', '/foo'],
3155
3461
[section.id for section in sections])
3156
self.assertEquals(['baz', 'bar/baz'],
3462
self.assertEqual(['baz', 'bar/baz'],
3157
3463
[section.extra_path for section in sections])
3159
3465
def test_appendpath_in_no_name_section(self):
3160
3466
# It's a bit weird to allow appendpath in a no-name section, but
3161
3467
# someone may found a use for it
3162
store = self.get_store('foo.conf')
3468
store = self.get_store(self)
3163
3469
store._load_from_string('''
3165
3471
foo:policy = appendpath
3178
3484
expected_url = 'file:///dir/subdir'
3179
3485
expected_location = '/dir/subdir'
3180
3486
matcher = config.LocationMatcher(store, expected_url)
3181
self.assertEquals(expected_location, matcher.location)
3487
self.assertEqual(expected_location, matcher.location)
3489
def test_branch_name_colo(self):
3490
store = self.get_store(self)
3491
store._load_from_string(dedent("""\
3493
push_location=my{branchname}
3495
matcher = config.LocationMatcher(store, 'file:///,branch=example%3c')
3496
self.assertEqual('example<', matcher.branch_name)
3497
((_, section),) = matcher.get_sections()
3498
self.assertEqual('example<', section.locals['branchname'])
3500
def test_branch_name_basename(self):
3501
store = self.get_store(self)
3502
store._load_from_string(dedent("""\
3504
push_location=my{branchname}
3506
matcher = config.LocationMatcher(store, 'file:///parent/example%3c')
3507
self.assertEqual('example<', matcher.branch_name)
3508
((_, section),) = matcher.get_sections()
3509
self.assertEqual('example<', section.locals['branchname'])
3512
class TestStartingPathMatcher(TestStore):
3515
super(TestStartingPathMatcher, self).setUp()
3516
# Any simple store is good enough
3517
self.store = config.IniFileStore()
3519
def assertSectionIDs(self, expected, location, content):
3520
self.store._load_from_string(content)
3521
matcher = config.StartingPathMatcher(self.store, location)
3522
sections = list(matcher.get_sections())
3523
self.assertLength(len(expected), sections)
3524
self.assertEqual(expected, [section.id for _, section in sections])
3527
def test_empty(self):
3528
self.assertSectionIDs([], self.get_url(), '')
3530
def test_url_vs_local_paths(self):
3531
# The matcher location is an url and the section names are local paths
3532
self.assertSectionIDs(['/foo/bar', '/foo'],
3533
'file:///foo/bar/baz', '''\
3538
def test_local_path_vs_url(self):
3539
# The matcher location is a local path and the section names are urls
3540
self.assertSectionIDs(['file:///foo/bar', 'file:///foo'],
3541
'/foo/bar/baz', '''\
3547
def test_no_name_section_included_when_present(self):
3548
# Note that other tests will cover the case where the no-name section
3549
# is empty and as such, not included.
3550
sections = self.assertSectionIDs(['/foo/bar', '/foo', None],
3551
'/foo/bar/baz', '''\
3552
option = defined so the no-name section exists
3556
self.assertEqual(['baz', 'bar/baz', '/foo/bar/baz'],
3557
[s.locals['relpath'] for _, s in sections])
3559
def test_order_reversed(self):
3560
self.assertSectionIDs(['/foo/bar', '/foo'], '/foo/bar/baz', '''\
3565
def test_unrelated_section_excluded(self):
3566
self.assertSectionIDs(['/foo/bar', '/foo'], '/foo/bar/baz', '''\
3572
def test_glob_included(self):
3573
sections = self.assertSectionIDs(['/foo/*/baz', '/foo/b*', '/foo'],
3574
'/foo/bar/baz', '''\
3580
# Note that 'baz' as a relpath for /foo/b* is not fully correct, but
3581
# nothing really is... as far using {relpath} to append it to something
3582
# else, this seems good enough though.
3583
self.assertEqual(['', 'baz', 'bar/baz'],
3584
[s.locals['relpath'] for _, s in sections])
3586
def test_respect_order(self):
3587
self.assertSectionIDs(['/foo', '/foo/b*', '/foo/*/baz'],
3588
'/foo/bar/baz', '''\
3184
3596
class TestNameMatcher(TestStore):
3186
3598
def setUp(self):
3187
3599
super(TestNameMatcher, self).setUp()
3188
self.store = config.IniFileStore(self.get_readonly_transport(),
3190
self.store._load_from_string('''
3600
self.matcher = config.NameMatcher
3601
# Any simple store is good enough
3602
self.get_store = config.test_store_builder_registry.get('configobj')
3604
def get_matching_sections(self, name):
3605
store = self.get_store(self)
3606
store._load_from_string('''
3210
3624
self.assertLength(0, sections)
3213
class TestStackGet(tests.TestCase):
3215
# FIXME: This should be parametrized for all known Stack or dedicated
3216
# paramerized tests created to avoid bloating -- vila 2011-03-31
3218
def overrideOptionRegistry(self):
3627
class TestBaseStackGet(tests.TestCase):
3630
super(TestBaseStackGet, self).setUp()
3219
3631
self.overrideAttr(config, 'option_registry', config.OptionRegistry())
3221
def test_single_config_get(self):
3222
conf = dict(foo='bar')
3223
conf_stack = config.Stack([conf])
3224
self.assertEquals('bar', conf_stack.get('foo'))
3633
def test_get_first_definition(self):
3634
store1 = config.IniFileStore()
3635
store1._load_from_string('foo=bar')
3636
store2 = config.IniFileStore()
3637
store2._load_from_string('foo=baz')
3638
conf = config.Stack([store1.get_sections, store2.get_sections])
3639
self.assertEqual('bar', conf.get('foo'))
3226
3641
def test_get_with_registered_default_value(self):
3227
conf_stack = config.Stack([dict()])
3228
opt = config.Option('foo', default='bar')
3229
self.overrideOptionRegistry()
3230
config.option_registry.register('foo', opt)
3231
self.assertEquals('bar', conf_stack.get('foo'))
3642
config.option_registry.register(config.Option('foo', default='bar'))
3643
conf_stack = config.Stack([])
3644
self.assertEqual('bar', conf_stack.get('foo'))
3233
3646
def test_get_without_registered_default_value(self):
3234
conf_stack = config.Stack([dict()])
3235
opt = config.Option('foo')
3236
self.overrideOptionRegistry()
3237
config.option_registry.register('foo', opt)
3238
self.assertEquals(None, conf_stack.get('foo'))
3647
config.option_registry.register(config.Option('foo'))
3648
conf_stack = config.Stack([])
3649
self.assertEqual(None, conf_stack.get('foo'))
3240
3651
def test_get_without_default_value_for_not_registered(self):
3241
conf_stack = config.Stack([dict()])
3242
opt = config.Option('foo')
3243
self.overrideOptionRegistry()
3244
self.assertEquals(None, conf_stack.get('foo'))
3246
def test_get_first_definition(self):
3247
conf1 = dict(foo='bar')
3248
conf2 = dict(foo='baz')
3249
conf_stack = config.Stack([conf1, conf2])
3250
self.assertEquals('bar', conf_stack.get('foo'))
3252
def test_get_embedded_definition(self):
3253
conf1 = dict(yy='12')
3254
conf2 = config.Stack([dict(xx='42'), dict(foo='baz')])
3255
conf_stack = config.Stack([conf1, conf2])
3256
self.assertEquals('baz', conf_stack.get('foo'))
3652
conf_stack = config.Stack([])
3653
self.assertEqual(None, conf_stack.get('foo'))
3258
3655
def test_get_for_empty_section_callable(self):
3259
3656
conf_stack = config.Stack([lambda : []])
3260
self.assertEquals(None, conf_stack.get('foo'))
3657
self.assertEqual(None, conf_stack.get('foo'))
3262
3659
def test_get_for_broken_callable(self):
3263
3660
# Trying to use and invalid callable raises an exception on first use
3264
conf_stack = config.Stack([lambda : object()])
3661
conf_stack = config.Stack([object])
3265
3662
self.assertRaises(TypeError, conf_stack.get, 'foo')
3665
class TestStackWithSimpleStore(tests.TestCase):
3668
super(TestStackWithSimpleStore, self).setUp()
3669
self.overrideAttr(config, 'option_registry', config.OptionRegistry())
3670
self.registry = config.option_registry
3672
def get_conf(self, content=None):
3673
return config.MemoryStack(content)
3675
def test_override_value_from_env(self):
3676
self.overrideEnv('FOO', None)
3677
self.registry.register(
3678
config.Option('foo', default='bar', override_from_env=['FOO']))
3679
self.overrideEnv('FOO', 'quux')
3680
# Env variable provides a default taking over the option one
3681
conf = self.get_conf('foo=store')
3682
self.assertEqual('quux', conf.get('foo'))
3684
def test_first_override_value_from_env_wins(self):
3685
self.overrideEnv('NO_VALUE', None)
3686
self.overrideEnv('FOO', None)
3687
self.overrideEnv('BAZ', None)
3688
self.registry.register(
3689
config.Option('foo', default='bar',
3690
override_from_env=['NO_VALUE', 'FOO', 'BAZ']))
3691
self.overrideEnv('FOO', 'foo')
3692
self.overrideEnv('BAZ', 'baz')
3693
# The first env var set wins
3694
conf = self.get_conf('foo=store')
3695
self.assertEqual('foo', conf.get('foo'))
3698
class TestMemoryStack(tests.TestCase):
3701
conf = config.MemoryStack('foo=bar')
3702
self.assertEqual('bar', conf.get('foo'))
3705
conf = config.MemoryStack('foo=bar')
3706
conf.set('foo', 'baz')
3707
self.assertEqual('baz', conf.get('foo'))
3709
def test_no_content(self):
3710
conf = config.MemoryStack()
3711
# No content means no loading
3712
self.assertFalse(conf.store.is_loaded())
3713
self.assertRaises(NotImplementedError, conf.get, 'foo')
3714
# But a content can still be provided
3715
conf.store._load_from_string('foo=bar')
3716
self.assertEqual('bar', conf.get('foo'))
3719
class TestStackIterSections(tests.TestCase):
3721
def test_empty_stack(self):
3722
conf = config.Stack([])
3723
sections = list(conf.iter_sections())
3724
self.assertLength(0, sections)
3726
def test_empty_store(self):
3727
store = config.IniFileStore()
3728
store._load_from_string('')
3729
conf = config.Stack([store.get_sections])
3730
sections = list(conf.iter_sections())
3731
self.assertLength(0, sections)
3733
def test_simple_store(self):
3734
store = config.IniFileStore()
3735
store._load_from_string('foo=bar')
3736
conf = config.Stack([store.get_sections])
3737
tuples = list(conf.iter_sections())
3738
self.assertLength(1, tuples)
3739
(found_store, found_section) = tuples[0]
3740
self.assertIs(store, found_store)
3742
def test_two_stores(self):
3743
store1 = config.IniFileStore()
3744
store1._load_from_string('foo=bar')
3745
store2 = config.IniFileStore()
3746
store2._load_from_string('bar=qux')
3747
conf = config.Stack([store1.get_sections, store2.get_sections])
3748
tuples = list(conf.iter_sections())
3749
self.assertLength(2, tuples)
3750
self.assertIs(store1, tuples[0][0])
3751
self.assertIs(store2, tuples[1][0])
3268
3754
class TestStackWithTransport(tests.TestCaseWithTransport):
3270
3756
scenarios = [(key, {'get_stack': builder}) for key, builder
3349
3843
def test_get_default_integer_None(self):
3350
3844
self.register_integer_option('foo')
3351
self.assertEquals(None, self.conf.get('foo'))
3845
conf = self.get_conf('')
3846
self.assertEqual(None, conf.get('foo'))
3353
3848
def test_get_default_integer(self):
3354
3849
self.register_integer_option('foo', 42)
3355
self.assertEquals(42, self.conf.get('foo'))
3850
conf = self.get_conf('')
3851
self.assertEqual(42, conf.get('foo'))
3357
3853
def test_get_default_integer_as_string(self):
3358
3854
self.register_integer_option('foo', u'42')
3359
self.assertEquals(42, self.conf.get('foo'))
3855
conf = self.get_conf('')
3856
self.assertEqual(42, conf.get('foo'))
3361
3858
def test_get_default_integer_from_env(self):
3362
3859
self.register_integer_option('foo', default_from_env=['FOO'])
3363
3860
self.overrideEnv('FOO', '18')
3364
self.assertEquals(18, self.conf.get('foo'))
3861
conf = self.get_conf('')
3862
self.assertEqual(18, conf.get('foo'))
3366
3864
def test_get_default_integer_when_conversion_fails(self):
3367
3865
self.register_integer_option('foo', default='12')
3368
self.conf.store._load_from_string('foo=invalid integer')
3369
self.assertEquals(12, self.conf.get('foo'))
3866
conf = self.get_conf('foo=invalid integer')
3867
self.assertEqual(12, conf.get('foo'))
3371
3869
def register_list_option(self, name, default=None, default_from_env=None):
3372
l = config.Option(name, help='A list.',
3373
default=default, default_from_env=default_from_env,
3374
from_unicode=config.list_from_store)
3870
l = config.ListOption(name, help='A list.', default=default,
3871
default_from_env=default_from_env)
3375
3872
self.registry.register(l)
3377
3874
def test_get_default_list_None(self):
3378
3875
self.register_list_option('foo')
3379
self.assertEquals(None, self.conf.get('foo'))
3876
conf = self.get_conf('')
3877
self.assertEqual(None, conf.get('foo'))
3381
3879
def test_get_default_list_empty(self):
3382
3880
self.register_list_option('foo', '')
3383
self.assertEquals([], self.conf.get('foo'))
3881
conf = self.get_conf('')
3882
self.assertEqual([], conf.get('foo'))
3385
3884
def test_get_default_list_from_env(self):
3386
3885
self.register_list_option('foo', default_from_env=['FOO'])
3387
3886
self.overrideEnv('FOO', '')
3388
self.assertEquals([], self.conf.get('foo'))
3887
conf = self.get_conf('')
3888
self.assertEqual([], conf.get('foo'))
3390
3890
def test_get_with_list_converter_no_item(self):
3391
3891
self.register_list_option('foo', None)
3392
self.conf.store._load_from_string('foo=,')
3393
self.assertEquals([], self.conf.get('foo'))
3892
conf = self.get_conf('foo=,')
3893
self.assertEqual([], conf.get('foo'))
3395
3895
def test_get_with_list_converter_many_items(self):
3396
3896
self.register_list_option('foo', None)
3397
self.conf.store._load_from_string('foo=m,o,r,e')
3398
self.assertEquals(['m', 'o', 'r', 'e'], self.conf.get('foo'))
3897
conf = self.get_conf('foo=m,o,r,e')
3898
self.assertEqual(['m', 'o', 'r', 'e'], conf.get('foo'))
3400
3900
def test_get_with_list_converter_embedded_spaces_many_items(self):
3401
3901
self.register_list_option('foo', None)
3402
self.conf.store._load_from_string('foo=" bar", "baz "')
3403
self.assertEquals([' bar', 'baz '], self.conf.get('foo'))
3902
conf = self.get_conf('foo=" bar", "baz "')
3903
self.assertEqual([' bar', 'baz '], conf.get('foo'))
3405
3905
def test_get_with_list_converter_stripped_spaces_many_items(self):
3406
3906
self.register_list_option('foo', None)
3407
self.conf.store._load_from_string('foo= bar , baz ')
3408
self.assertEquals(['bar', 'baz'], self.conf.get('foo'))
3907
conf = self.get_conf('foo= bar , baz ')
3908
self.assertEqual(['bar', 'baz'], conf.get('foo'))
3911
class TestIterOptionRefs(tests.TestCase):
3912
"""iter_option_refs is a bit unusual, document some cases."""
3914
def assertRefs(self, expected, string):
3915
self.assertEqual(expected, list(config.iter_option_refs(string)))
3917
def test_empty(self):
3918
self.assertRefs([(False, '')], '')
3920
def test_no_refs(self):
3921
self.assertRefs([(False, 'foo bar')], 'foo bar')
3923
def test_single_ref(self):
3924
self.assertRefs([(False, ''), (True, '{foo}'), (False, '')], '{foo}')
3926
def test_broken_ref(self):
3927
self.assertRefs([(False, '{foo')], '{foo')
3929
def test_embedded_ref(self):
3930
self.assertRefs([(False, '{'), (True, '{foo}'), (False, '}')],
3933
def test_two_refs(self):
3934
self.assertRefs([(False, ''), (True, '{foo}'),
3935
(False, ''), (True, '{bar}'),
3939
def test_newline_in_refs_are_not_matched(self):
3940
self.assertRefs([(False, '{\nxx}{xx\n}{{\n}}')], '{\nxx}{xx\n}{{\n}}')
3411
3943
class TestStackExpandOptions(tests.TestCaseWithTransport):
3559
4099
[/project/branch/path]
3562
self.assertEquals('quux', c.get('bar', expand=True))
4102
self.assertEqual('quux', c.get('bar', expand=True))
4105
class TestStackCrossStoresExpand(tests.TestCaseWithTransport):
4107
def test_cross_global_locations(self):
4108
l_store = config.LocationStore()
4109
l_store._load_from_string('''
4115
g_store = config.GlobalStore()
4116
g_store._load_from_string('''
4122
stack = config.LocationStack('/branch')
4123
self.assertEqual('glob-bar', stack.get('lbar', expand=True))
4124
self.assertEqual('loc-foo', stack.get('gfoo', expand=True))
4127
class TestStackExpandSectionLocals(tests.TestCaseWithTransport):
4129
def test_expand_locals_empty(self):
4130
l_store = config.LocationStore()
4131
l_store._load_from_string('''
4132
[/home/user/project]
4137
stack = config.LocationStack('/home/user/project/')
4138
self.assertEqual('', stack.get('base', expand=True))
4139
self.assertEqual('', stack.get('rel', expand=True))
4141
def test_expand_basename_locally(self):
4142
l_store = config.LocationStore()
4143
l_store._load_from_string('''
4144
[/home/user/project]
4148
stack = config.LocationStack('/home/user/project/branch')
4149
self.assertEqual('branch', stack.get('bfoo', expand=True))
4151
def test_expand_basename_locally_longer_path(self):
4152
l_store = config.LocationStore()
4153
l_store._load_from_string('''
4158
stack = config.LocationStack('/home/user/project/dir/branch')
4159
self.assertEqual('branch', stack.get('bfoo', expand=True))
4161
def test_expand_relpath_locally(self):
4162
l_store = config.LocationStore()
4163
l_store._load_from_string('''
4164
[/home/user/project]
4165
lfoo = loc-foo/{relpath}
4168
stack = config.LocationStack('/home/user/project/branch')
4169
self.assertEqual('loc-foo/branch', stack.get('lfoo', expand=True))
4171
def test_expand_relpath_unknonw_in_global(self):
4172
g_store = config.GlobalStore()
4173
g_store._load_from_string('''
4178
stack = config.LocationStack('/home/user/project/branch')
4179
self.assertRaises(errors.ExpandingUnknownOption,
4180
stack.get, 'gfoo', expand=True)
4182
def test_expand_local_option_locally(self):
4183
l_store = config.LocationStore()
4184
l_store._load_from_string('''
4185
[/home/user/project]
4186
lfoo = loc-foo/{relpath}
4190
g_store = config.GlobalStore()
4191
g_store._load_from_string('''
4197
stack = config.LocationStack('/home/user/project/branch')
4198
self.assertEqual('glob-bar', stack.get('lbar', expand=True))
4199
self.assertEqual('loc-foo/branch', stack.get('gfoo', expand=True))
4201
def test_locals_dont_leak(self):
4202
"""Make sure we chose the right local in presence of several sections.
4204
l_store = config.LocationStore()
4205
l_store._load_from_string('''
4207
lfoo = loc-foo/{relpath}
4208
[/home/user/project]
4209
lfoo = loc-foo/{relpath}
4212
stack = config.LocationStack('/home/user/project/branch')
4213
self.assertEqual('loc-foo/branch', stack.get('lfoo', expand=True))
4214
stack = config.LocationStack('/home/user/bar/baz')
4215
self.assertEqual('loc-foo/bar/baz', stack.get('lfoo', expand=True))
3565
4219
class TestStackSet(TestStackWithTransport):
3567
4221
def test_simple_set(self):
3568
4222
conf = self.get_stack(self)
3569
conf.store._load_from_string('foo=bar')
3570
self.assertEquals('bar', conf.get('foo'))
4223
self.assertEqual(None, conf.get('foo'))
3571
4224
conf.set('foo', 'baz')
3572
4225
# Did we get it back ?
3573
self.assertEquals('baz', conf.get('foo'))
4226
self.assertEqual('baz', conf.get('foo'))
3575
4228
def test_set_creates_a_new_section(self):
3576
4229
conf = self.get_stack(self)
3577
4230
conf.set('foo', 'baz')
3578
self.assertEquals, 'baz', conf.get('foo')
4231
self.assertEqual, 'baz', conf.get('foo')
3580
4233
def test_set_hook(self):
4292
4963
self.assertIsNot(None, realname)
4293
4964
self.assertIsNot(None, address)
4295
self.assertEquals((None, None), (realname, address))
4966
self.assertEqual((None, None), (realname, address))
4969
class TestDefaultMailDomain(tests.TestCaseInTempDir):
4970
"""Test retrieving default domain from mailname file"""
4972
def test_default_mail_domain_simple(self):
4973
f = file('simple', 'w')
4975
f.write("domainname.com\n")
4978
r = config._get_default_mail_domain('simple')
4979
self.assertEqual('domainname.com', r)
4981
def test_default_mail_domain_no_eol(self):
4982
f = file('no_eol', 'w')
4984
f.write("domainname.com")
4987
r = config._get_default_mail_domain('no_eol')
4988
self.assertEqual('domainname.com', r)
4990
def test_default_mail_domain_multiple_lines(self):
4991
f = file('multiple_lines', 'w')
4993
f.write("domainname.com\nsome other text\n")
4996
r = config._get_default_mail_domain('multiple_lines')
4997
self.assertEqual('domainname.com', r)
5000
class EmailOptionTests(tests.TestCase):
5002
def test_default_email_uses_BZR_EMAIL(self):
5003
conf = config.MemoryStack('email=jelmer@debian.org')
5004
# BZR_EMAIL takes precedence over EMAIL
5005
self.overrideEnv('BZR_EMAIL', 'jelmer@samba.org')
5006
self.overrideEnv('EMAIL', 'jelmer@apache.org')
5007
self.assertEqual('jelmer@samba.org', conf.get('email'))
5009
def test_default_email_uses_EMAIL(self):
5010
conf = config.MemoryStack('')
5011
self.overrideEnv('BZR_EMAIL', None)
5012
self.overrideEnv('EMAIL', 'jelmer@apache.org')
5013
self.assertEqual('jelmer@apache.org', conf.get('email'))
5015
def test_BZR_EMAIL_overrides(self):
5016
conf = config.MemoryStack('email=jelmer@debian.org')
5017
self.overrideEnv('BZR_EMAIL', 'jelmer@apache.org')
5018
self.assertEqual('jelmer@apache.org', conf.get('email'))
5019
self.overrideEnv('BZR_EMAIL', None)
5020
self.overrideEnv('EMAIL', 'jelmer@samba.org')
5021
self.assertEqual('jelmer@debian.org', conf.get('email'))
5024
class MailClientOptionTests(tests.TestCase):
5026
def test_default(self):
5027
conf = config.MemoryStack('')
5028
client = conf.get('mail_client')
5029
self.assertIs(client, mail_client.DefaultMail)
5031
def test_evolution(self):
5032
conf = config.MemoryStack('mail_client=evolution')
5033
client = conf.get('mail_client')
5034
self.assertIs(client, mail_client.Evolution)
5036
def test_kmail(self):
5037
conf = config.MemoryStack('mail_client=kmail')
5038
client = conf.get('mail_client')
5039
self.assertIs(client, mail_client.KMail)
5041
def test_mutt(self):
5042
conf = config.MemoryStack('mail_client=mutt')
5043
client = conf.get('mail_client')
5044
self.assertIs(client, mail_client.Mutt)
5046
def test_thunderbird(self):
5047
conf = config.MemoryStack('mail_client=thunderbird')
5048
client = conf.get('mail_client')
5049
self.assertIs(client, mail_client.Thunderbird)
5051
def test_explicit_default(self):
5052
conf = config.MemoryStack('mail_client=default')
5053
client = conf.get('mail_client')
5054
self.assertIs(client, mail_client.DefaultMail)
5056
def test_editor(self):
5057
conf = config.MemoryStack('mail_client=editor')
5058
client = conf.get('mail_client')
5059
self.assertIs(client, mail_client.Editor)
5061
def test_mapi(self):
5062
conf = config.MemoryStack('mail_client=mapi')
5063
client = conf.get('mail_client')
5064
self.assertIs(client, mail_client.MAPIClient)
5066
def test_xdg_email(self):
5067
conf = config.MemoryStack('mail_client=xdg-email')
5068
client = conf.get('mail_client')
5069
self.assertIs(client, mail_client.XDGEmail)
5071
def test_unknown(self):
5072
conf = config.MemoryStack('mail_client=firebird')
5073
self.assertRaises(errors.ConfigOptionValueError, conf.get,