2358
2366
class TestOptionConverterMixin(object):
2360
2368
def assertConverted(self, expected, opt, value):
2361
self.assertEquals(expected, opt.convert_from_unicode(value))
2363
def assertWarns(self, opt, value):
2366
warnings.append(args[0] % args[1:])
2367
self.overrideAttr(trace, 'warning', warning)
2368
self.assertEquals(None, opt.convert_from_unicode(value))
2369
self.assertLength(1, warnings)
2371
'Value "%s" is not valid for "%s"' % (value, opt.name),
2374
def assertErrors(self, opt, value):
2375
self.assertRaises(errors.ConfigOptionValueError,
2376
opt.convert_from_unicode, value)
2378
def assertConvertInvalid(self, opt, invalid_value):
2380
self.assertEquals(None, opt.convert_from_unicode(invalid_value))
2381
opt.invalid = 'warning'
2382
self.assertWarns(opt, invalid_value)
2383
opt.invalid = 'error'
2384
self.assertErrors(opt, invalid_value)
2387
class TestOptionWithBooleanConverter(tests.TestCase, TestOptionConverterMixin):
2389
def get_option(self):
2390
return config.Option('foo', help='A boolean.',
2391
from_unicode=config.bool_from_store)
2393
def test_convert_invalid(self):
2394
opt = self.get_option()
2395
# A string that is not recognized as a boolean
2396
self.assertConvertInvalid(opt, u'invalid-boolean')
2397
# A list of strings is never recognized as a boolean
2398
self.assertConvertInvalid(opt, [u'not', u'a', u'boolean'])
2400
def test_convert_valid(self):
2401
opt = self.get_option()
2402
self.assertConverted(True, opt, u'True')
2403
self.assertConverted(True, opt, u'1')
2404
self.assertConverted(False, opt, u'False')
2407
class TestOptionWithIntegerConverter(tests.TestCase, TestOptionConverterMixin):
2409
def get_option(self):
2410
return config.Option('foo', help='An integer.',
2411
from_unicode=config.int_from_store)
2413
def test_convert_invalid(self):
2414
opt = self.get_option()
2415
# A string that is not recognized as an integer
2416
self.assertConvertInvalid(opt, u'forty-two')
2417
# A list of strings is never recognized as an integer
2418
self.assertConvertInvalid(opt, [u'a', u'list'])
2420
def test_convert_valid(self):
2421
opt = self.get_option()
2422
self.assertConverted(16, opt, u'16')
2425
class TestOptionWithListConverter(tests.TestCase, TestOptionConverterMixin):
2427
def get_option(self):
2428
return config.Option('foo', help='A list.',
2429
from_unicode=config.list_from_store)
2431
def test_convert_invalid(self):
2432
# No string is invalid as all forms can be converted to a list
2435
def test_convert_valid(self):
2436
opt = self.get_option()
2437
# An empty string is an empty list
2438
self.assertConverted([], opt, '') # Using a bare str() just in case
2439
self.assertConverted([], opt, u'')
2441
self.assertConverted([u'True'], opt, u'True')
2443
self.assertConverted([u'42'], opt, u'42')
2445
self.assertConverted([u'bar'], opt, u'bar')
2446
# A list remains a list (configObj will turn a string containing commas
2447
# into a list, but that's not what we're testing here)
2448
self.assertConverted([u'foo', u'1', u'True'],
2449
opt, [u'foo', u'1', u'True'])
2452
class TestOptionConverterMixin(object):
2454
def assertConverted(self, expected, opt, value):
2455
self.assertEquals(expected, opt.convert_from_unicode(value))
2457
def assertWarns(self, opt, value):
2460
warnings.append(args[0] % args[1:])
2461
self.overrideAttr(trace, 'warning', warning)
2462
self.assertEquals(None, opt.convert_from_unicode(value))
2463
self.assertLength(1, warnings)
2465
'Value "%s" is not valid for "%s"' % (value, opt.name),
2468
def assertErrors(self, opt, value):
2469
self.assertRaises(errors.ConfigOptionValueError,
2470
opt.convert_from_unicode, value)
2472
def assertConvertInvalid(self, opt, invalid_value):
2474
self.assertEquals(None, opt.convert_from_unicode(invalid_value))
2475
opt.invalid = 'warning'
2476
self.assertWarns(opt, invalid_value)
2477
opt.invalid = 'error'
2478
self.assertErrors(opt, invalid_value)
2481
class TestOptionWithBooleanConverter(tests.TestCase, TestOptionConverterMixin):
2483
def get_option(self):
2484
return config.Option('foo', help='A boolean.',
2485
from_unicode=config.bool_from_store)
2487
def test_convert_invalid(self):
2488
opt = self.get_option()
2489
# A string that is not recognized as a boolean
2490
self.assertConvertInvalid(opt, u'invalid-boolean')
2491
# A list of strings is never recognized as a boolean
2492
self.assertConvertInvalid(opt, [u'not', u'a', u'boolean'])
2494
def test_convert_valid(self):
2495
opt = self.get_option()
2496
self.assertConverted(True, opt, u'True')
2497
self.assertConverted(True, opt, u'1')
2498
self.assertConverted(False, opt, u'False')
2501
class TestOptionWithIntegerConverter(tests.TestCase, TestOptionConverterMixin):
2503
def get_option(self):
2504
return config.Option('foo', help='An integer.',
2505
from_unicode=config.int_from_store)
2507
def test_convert_invalid(self):
2508
opt = self.get_option()
2509
# A string that is not recognized as an integer
2510
self.assertConvertInvalid(opt, u'forty-two')
2511
# A list of strings is never recognized as an integer
2512
self.assertConvertInvalid(opt, [u'a', u'list'])
2514
def test_convert_valid(self):
2515
opt = self.get_option()
2516
self.assertConverted(16, opt, u'16')
2519
class TestOptionWithListConverter(tests.TestCase, TestOptionConverterMixin):
2521
def get_option(self):
2522
return config.Option('foo', help='A list.',
2523
from_unicode=config.list_from_store)
2369
self.assertEquals(expected, opt.convert_from_unicode(None, value))
2371
def assertWarns(self, opt, value):
2374
warnings.append(args[0] % args[1:])
2375
self.overrideAttr(trace, 'warning', warning)
2376
self.assertEquals(None, opt.convert_from_unicode(None, value))
2377
self.assertLength(1, warnings)
2379
'Value "%s" is not valid for "%s"' % (value, opt.name),
2382
def assertErrors(self, opt, value):
2383
self.assertRaises(errors.ConfigOptionValueError,
2384
opt.convert_from_unicode, None, value)
2386
def assertConvertInvalid(self, opt, invalid_value):
2388
self.assertEquals(None, opt.convert_from_unicode(None, invalid_value))
2389
opt.invalid = 'warning'
2390
self.assertWarns(opt, invalid_value)
2391
opt.invalid = 'error'
2392
self.assertErrors(opt, invalid_value)
2395
class TestOptionWithBooleanConverter(tests.TestCase, TestOptionConverterMixin):
2397
def get_option(self):
2398
return config.Option('foo', help='A boolean.',
2399
from_unicode=config.bool_from_store)
2401
def test_convert_invalid(self):
2402
opt = self.get_option()
2403
# A string that is not recognized as a boolean
2404
self.assertConvertInvalid(opt, u'invalid-boolean')
2405
# A list of strings is never recognized as a boolean
2406
self.assertConvertInvalid(opt, [u'not', u'a', u'boolean'])
2408
def test_convert_valid(self):
2409
opt = self.get_option()
2410
self.assertConverted(True, opt, u'True')
2411
self.assertConverted(True, opt, u'1')
2412
self.assertConverted(False, opt, u'False')
2415
class TestOptionWithIntegerConverter(tests.TestCase, TestOptionConverterMixin):
2417
def get_option(self):
2418
return config.Option('foo', help='An integer.',
2419
from_unicode=config.int_from_store)
2421
def test_convert_invalid(self):
2422
opt = self.get_option()
2423
# A string that is not recognized as an integer
2424
self.assertConvertInvalid(opt, u'forty-two')
2425
# A list of strings is never recognized as an integer
2426
self.assertConvertInvalid(opt, [u'a', u'list'])
2428
def test_convert_valid(self):
2429
opt = self.get_option()
2430
self.assertConverted(16, opt, u'16')
2433
class TestOptionWithSIUnitConverter(tests.TestCase, TestOptionConverterMixin):
2435
def get_option(self):
2436
return config.Option('foo', help='An integer in SI units.',
2437
from_unicode=config.int_SI_from_store)
2439
def test_convert_invalid(self):
2440
opt = self.get_option()
2441
self.assertConvertInvalid(opt, u'not-a-unit')
2442
self.assertConvertInvalid(opt, u'Gb') # Forgot the int
2443
self.assertConvertInvalid(opt, u'1b') # Forgot the unit
2444
self.assertConvertInvalid(opt, u'1GG')
2445
self.assertConvertInvalid(opt, u'1Mbb')
2446
self.assertConvertInvalid(opt, u'1MM')
2448
def test_convert_valid(self):
2449
opt = self.get_option()
2450
self.assertConverted(int(5e3), opt, u'5kb')
2451
self.assertConverted(int(5e6), opt, u'5M')
2452
self.assertConverted(int(5e6), opt, u'5MB')
2453
self.assertConverted(int(5e9), opt, u'5g')
2454
self.assertConverted(int(5e9), opt, u'5gB')
2455
self.assertConverted(100, opt, u'100')
2458
class TestListOption(tests.TestCase, TestOptionConverterMixin):
2460
def get_option(self):
2461
return config.ListOption('foo', help='A list.')
2525
2463
def test_convert_invalid(self):
2526
2464
opt = self.get_option()
2761
2717
self.assertRaises(AssertionError, store._load_from_string, 'bar=baz')
2720
class TestStoreQuoting(TestStore):
2722
scenarios = [(key, {'get_store': builder}) for key, builder
2723
in config.test_store_builder_registry.iteritems()]
2726
super(TestStoreQuoting, self).setUp()
2727
self.store = self.get_store(self)
2728
# We need a loaded store but any content will do
2729
self.store._load_from_string('')
2731
def assertIdempotent(self, s):
2732
"""Assert that quoting an unquoted string is a no-op and vice-versa.
2734
What matters here is that option values, as they appear in a store, can
2735
be safely round-tripped out of the store and back.
2737
:param s: A string, quoted if required.
2739
self.assertEquals(s, self.store.quote(self.store.unquote(s)))
2740
self.assertEquals(s, self.store.unquote(self.store.quote(s)))
2742
def test_empty_string(self):
2743
if isinstance(self.store, config.IniFileStore):
2744
# configobj._quote doesn't handle empty values
2745
self.assertRaises(AssertionError,
2746
self.assertIdempotent, '')
2748
self.assertIdempotent('')
2749
# But quoted empty strings are ok
2750
self.assertIdempotent('""')
2752
def test_embedded_spaces(self):
2753
self.assertIdempotent('" a b c "')
2755
def test_embedded_commas(self):
2756
self.assertIdempotent('" a , b c "')
2758
def test_simple_comma(self):
2759
if isinstance(self.store, config.IniFileStore):
2760
# configobj requires that lists are special-cased
2761
self.assertRaises(AssertionError,
2762
self.assertIdempotent, ',')
2764
self.assertIdempotent(',')
2765
# When a single comma is required, quoting is also required
2766
self.assertIdempotent('","')
2768
def test_list(self):
2769
if isinstance(self.store, config.IniFileStore):
2770
# configobj requires that lists are special-cased
2771
self.assertRaises(AssertionError,
2772
self.assertIdempotent, 'a,b')
2774
self.assertIdempotent('a,b')
2777
class TestDictFromStore(tests.TestCase):
2779
def test_unquote_not_string(self):
2780
conf = config.MemoryStack('x=2\n[a_section]\na=1\n')
2781
value = conf.get('a_section')
2782
# Urgh, despite 'conf' asking for the no-name section, we get the
2783
# content of another section as a dict o_O
2784
self.assertEquals({'a': '1'}, value)
2785
unquoted = conf.store.unquote(value)
2786
# Which cannot be unquoted but shouldn't crash either (the use cases
2787
# are getting the value or displaying it. In the later case, '%s' will
2789
self.assertEquals({'a': '1'}, unquoted)
2790
self.assertEquals("{u'a': u'1'}", '%s' % (unquoted,))
2764
2793
class TestIniFileStoreContent(tests.TestCaseWithTransport):
2765
2794
"""Simulate loading a config store with content of various encodings.
3321
3369
self.assertLength(0, sections)
3324
class TestStackGet(tests.TestCase):
3326
# FIXME: This should be parametrized for all known Stack or dedicated
3327
# paramerized tests created to avoid bloating -- vila 2011-03-31
3329
def overrideOptionRegistry(self):
3372
class TestBaseStackGet(tests.TestCase):
3375
super(TestBaseStackGet, self).setUp()
3330
3376
self.overrideAttr(config, 'option_registry', config.OptionRegistry())
3332
def test_single_config_get(self):
3333
conf = dict(foo='bar')
3334
conf_stack = config.Stack([conf])
3335
self.assertEquals('bar', conf_stack.get('foo'))
3378
def test_get_first_definition(self):
3379
store1 = config.IniFileStore()
3380
store1._load_from_string('foo=bar')
3381
store2 = config.IniFileStore()
3382
store2._load_from_string('foo=baz')
3383
conf = config.Stack([store1.get_sections, store2.get_sections])
3384
self.assertEquals('bar', conf.get('foo'))
3337
3386
def test_get_with_registered_default_value(self):
3338
conf_stack = config.Stack([dict()])
3339
opt = config.Option('foo', default='bar')
3340
self.overrideOptionRegistry()
3341
config.option_registry.register('foo', opt)
3387
config.option_registry.register(config.Option('foo', default='bar'))
3388
conf_stack = config.Stack([])
3342
3389
self.assertEquals('bar', conf_stack.get('foo'))
3344
3391
def test_get_without_registered_default_value(self):
3345
conf_stack = config.Stack([dict()])
3346
opt = config.Option('foo')
3347
self.overrideOptionRegistry()
3348
config.option_registry.register('foo', opt)
3392
config.option_registry.register(config.Option('foo'))
3393
conf_stack = config.Stack([])
3349
3394
self.assertEquals(None, conf_stack.get('foo'))
3351
3396
def test_get_without_default_value_for_not_registered(self):
3352
conf_stack = config.Stack([dict()])
3353
opt = config.Option('foo')
3354
self.overrideOptionRegistry()
3397
conf_stack = config.Stack([])
3355
3398
self.assertEquals(None, conf_stack.get('foo'))
3357
def test_get_first_definition(self):
3358
conf1 = dict(foo='bar')
3359
conf2 = dict(foo='baz')
3360
conf_stack = config.Stack([conf1, conf2])
3361
self.assertEquals('bar', conf_stack.get('foo'))
3363
def test_get_embedded_definition(self):
3364
conf1 = dict(yy='12')
3365
conf2 = config.Stack([dict(xx='42'), dict(foo='baz')])
3366
conf_stack = config.Stack([conf1, conf2])
3367
self.assertEquals('baz', conf_stack.get('foo'))
3369
3400
def test_get_for_empty_section_callable(self):
3370
3401
conf_stack = config.Stack([lambda : []])
3371
3402
self.assertEquals(None, conf_stack.get('foo'))
3373
3404
def test_get_for_broken_callable(self):
3374
3405
# Trying to use and invalid callable raises an exception on first use
3375
conf_stack = config.Stack([lambda : object()])
3406
conf_stack = config.Stack([object])
3376
3407
self.assertRaises(TypeError, conf_stack.get, 'foo')
3410
class TestStackWithSimpleStore(tests.TestCase):
3413
super(TestStackWithSimpleStore, self).setUp()
3414
self.overrideAttr(config, 'option_registry', config.OptionRegistry())
3415
self.registry = config.option_registry
3417
def get_conf(self, content=None):
3418
return config.MemoryStack(content)
3420
def test_override_value_from_env(self):
3421
self.registry.register(
3422
config.Option('foo', default='bar', override_from_env=['FOO']))
3423
self.overrideEnv('FOO', 'quux')
3424
# Env variable provides a default taking over the option one
3425
conf = self.get_conf('foo=store')
3426
self.assertEquals('quux', conf.get('foo'))
3428
def test_first_override_value_from_env_wins(self):
3429
self.registry.register(
3430
config.Option('foo', default='bar',
3431
override_from_env=['NO_VALUE', 'FOO', 'BAZ']))
3432
self.overrideEnv('FOO', 'foo')
3433
self.overrideEnv('BAZ', 'baz')
3434
# The first env var set wins
3435
conf = self.get_conf('foo=store')
3436
self.assertEquals('foo', conf.get('foo'))
3439
class TestMemoryStack(tests.TestCase):
3442
conf = config.MemoryStack('foo=bar')
3443
self.assertEquals('bar', conf.get('foo'))
3446
conf = config.MemoryStack('foo=bar')
3447
conf.set('foo', 'baz')
3448
self.assertEquals('baz', conf.get('foo'))
3450
def test_no_content(self):
3451
conf = config.MemoryStack()
3452
# No content means no loading
3453
self.assertFalse(conf.store.is_loaded())
3454
self.assertRaises(NotImplementedError, conf.get, 'foo')
3455
# But a content can still be provided
3456
conf.store._load_from_string('foo=bar')
3457
self.assertEquals('bar', conf.get('foo'))
3379
3460
class TestStackWithTransport(tests.TestCaseWithTransport):
3381
3462
scenarios = [(key, {'get_stack': builder}) for key, builder
3465
3549
def test_get_default_integer_None(self):
3466
3550
self.register_integer_option('foo')
3467
self.assertEquals(None, self.conf.get('foo'))
3551
conf = self.get_conf('')
3552
self.assertEquals(None, conf.get('foo'))
3469
3554
def test_get_default_integer(self):
3470
3555
self.register_integer_option('foo', 42)
3471
self.assertEquals(42, self.conf.get('foo'))
3556
conf = self.get_conf('')
3557
self.assertEquals(42, conf.get('foo'))
3473
3559
def test_get_default_integer_as_string(self):
3474
3560
self.register_integer_option('foo', u'42')
3475
self.assertEquals(42, self.conf.get('foo'))
3561
conf = self.get_conf('')
3562
self.assertEquals(42, conf.get('foo'))
3477
3564
def test_get_default_integer_from_env(self):
3478
3565
self.register_integer_option('foo', default_from_env=['FOO'])
3479
3566
self.overrideEnv('FOO', '18')
3480
self.assertEquals(18, self.conf.get('foo'))
3567
conf = self.get_conf('')
3568
self.assertEquals(18, conf.get('foo'))
3482
3570
def test_get_default_integer_when_conversion_fails(self):
3483
3571
self.register_integer_option('foo', default='12')
3484
self.conf.store._load_from_string('foo=invalid integer')
3485
self.assertEquals(12, self.conf.get('foo'))
3572
conf = self.get_conf('foo=invalid integer')
3573
self.assertEquals(12, conf.get('foo'))
3487
3575
def register_list_option(self, name, default=None, default_from_env=None):
3488
l = config.Option(name, help='A list.',
3489
default=default, default_from_env=default_from_env,
3490
from_unicode=config.list_from_store)
3576
l = config.ListOption(name, help='A list.', default=default,
3577
default_from_env=default_from_env)
3491
3578
self.registry.register(l)
3493
3580
def test_get_default_list_None(self):
3494
3581
self.register_list_option('foo')
3495
self.assertEquals(None, self.conf.get('foo'))
3582
conf = self.get_conf('')
3583
self.assertEquals(None, conf.get('foo'))
3497
3585
def test_get_default_list_empty(self):
3498
3586
self.register_list_option('foo', '')
3499
self.assertEquals([], self.conf.get('foo'))
3587
conf = self.get_conf('')
3588
self.assertEquals([], conf.get('foo'))
3501
3590
def test_get_default_list_from_env(self):
3502
3591
self.register_list_option('foo', default_from_env=['FOO'])
3503
3592
self.overrideEnv('FOO', '')
3504
self.assertEquals([], self.conf.get('foo'))
3593
conf = self.get_conf('')
3594
self.assertEquals([], conf.get('foo'))
3506
3596
def test_get_with_list_converter_no_item(self):
3507
3597
self.register_list_option('foo', None)
3508
self.conf.store._load_from_string('foo=,')
3509
self.assertEquals([], self.conf.get('foo'))
3598
conf = self.get_conf('foo=,')
3599
self.assertEquals([], conf.get('foo'))
3511
3601
def test_get_with_list_converter_many_items(self):
3512
3602
self.register_list_option('foo', None)
3513
self.conf.store._load_from_string('foo=m,o,r,e')
3514
self.assertEquals(['m', 'o', 'r', 'e'], self.conf.get('foo'))
3603
conf = self.get_conf('foo=m,o,r,e')
3604
self.assertEquals(['m', 'o', 'r', 'e'], conf.get('foo'))
3516
3606
def test_get_with_list_converter_embedded_spaces_many_items(self):
3517
3607
self.register_list_option('foo', None)
3518
self.conf.store._load_from_string('foo=" bar", "baz "')
3519
self.assertEquals([' bar', 'baz '], self.conf.get('foo'))
3608
conf = self.get_conf('foo=" bar", "baz "')
3609
self.assertEquals([' bar', 'baz '], conf.get('foo'))
3521
3611
def test_get_with_list_converter_stripped_spaces_many_items(self):
3522
3612
self.register_list_option('foo', None)
3523
self.conf.store._load_from_string('foo= bar , baz ')
3524
self.assertEquals(['bar', 'baz'], self.conf.get('foo'))
3613
conf = self.get_conf('foo= bar , baz ')
3614
self.assertEquals(['bar', 'baz'], conf.get('foo'))
3527
3617
class TestIterOptionRefs(tests.TestCase):