2189
2220
def test_save_hook_remote_bzrdir(self):
2190
2221
remote_branch = branch.Branch.open(self.get_url('tree'))
2191
2222
self.addCleanup(remote_branch.lock_write().unlock)
2192
remote_bzrdir = bzrdir.BzrDir.open(self.get_url('tree'))
2223
remote_bzrdir = controldir.ControlDir.open(self.get_url('tree'))
2193
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}}')
2196
2265
class TestOption(tests.TestCase):
2198
2267
def test_default_value(self):
2199
2268
opt = config.Option('foo', default='bar')
2200
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())
2277
def test_default_value_from_env(self):
2278
opt = config.Option('foo', default='bar', default_from_env=['FOO'])
2279
self.overrideEnv('FOO', 'quux')
2280
# Env variable provides a default taking over the option one
2281
self.assertEquals('quux', opt.get_default())
2283
def test_first_default_value_from_env_wins(self):
2284
opt = config.Option('foo', default='bar',
2285
default_from_env=['NO_VALUE', 'FOO', 'BAZ'])
2286
self.overrideEnv('FOO', 'foo')
2287
self.overrideEnv('BAZ', 'baz')
2288
# The first env var set wins
2289
self.assertEquals('foo', opt.get_default())
2291
def test_not_supported_list_default_value(self):
2292
self.assertRaises(AssertionError, config.Option, 'foo', default=[1])
2294
def test_not_supported_object_default_value(self):
2295
self.assertRaises(AssertionError, config.Option, 'foo',
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 TestOptionConverter(tests.TestCase):
2311
def assertConverted(self, expected, opt, value):
2312
self.assertEquals(expected, opt.convert_from_unicode(None, value))
2314
def assertCallsWarning(self, opt, value):
2318
warnings.append(args[0] % args[1:])
2319
self.overrideAttr(trace, 'warning', warning)
2320
self.assertEquals(None, opt.convert_from_unicode(None, value))
2321
self.assertLength(1, warnings)
2323
'Value "%s" is not valid for "%s"' % (value, opt.name),
2326
def assertCallsError(self, opt, value):
2327
self.assertRaises(errors.ConfigOptionValueError,
2328
opt.convert_from_unicode, None, value)
2330
def assertConvertInvalid(self, opt, invalid_value):
2332
self.assertEquals(None, opt.convert_from_unicode(None, invalid_value))
2333
opt.invalid = 'warning'
2334
self.assertCallsWarning(opt, invalid_value)
2335
opt.invalid = 'error'
2336
self.assertCallsError(opt, invalid_value)
2339
class TestOptionWithBooleanConverter(TestOptionConverter):
2341
def get_option(self):
2342
return config.Option('foo', help='A boolean.',
2343
from_unicode=config.bool_from_store)
2345
def test_convert_invalid(self):
2346
opt = self.get_option()
2347
# A string that is not recognized as a boolean
2348
self.assertConvertInvalid(opt, u'invalid-boolean')
2349
# A list of strings is never recognized as a boolean
2350
self.assertConvertInvalid(opt, [u'not', u'a', u'boolean'])
2352
def test_convert_valid(self):
2353
opt = self.get_option()
2354
self.assertConverted(True, opt, u'True')
2355
self.assertConverted(True, opt, u'1')
2356
self.assertConverted(False, opt, u'False')
2359
class TestOptionWithIntegerConverter(TestOptionConverter):
2361
def get_option(self):
2362
return config.Option('foo', help='An integer.',
2363
from_unicode=config.int_from_store)
2365
def test_convert_invalid(self):
2366
opt = self.get_option()
2367
# A string that is not recognized as an integer
2368
self.assertConvertInvalid(opt, u'forty-two')
2369
# A list of strings is never recognized as an integer
2370
self.assertConvertInvalid(opt, [u'a', u'list'])
2372
def test_convert_valid(self):
2373
opt = self.get_option()
2374
self.assertConverted(16, opt, u'16')
2377
class TestOptionWithSIUnitConverter(TestOptionConverter):
2379
def get_option(self):
2380
return config.Option('foo', help='An integer in SI units.',
2381
from_unicode=config.int_SI_from_store)
2383
def test_convert_invalid(self):
2384
opt = self.get_option()
2385
self.assertConvertInvalid(opt, u'not-a-unit')
2386
self.assertConvertInvalid(opt, u'Gb') # Forgot the value
2387
self.assertConvertInvalid(opt, u'1b') # Forgot the unit
2388
self.assertConvertInvalid(opt, u'1GG')
2389
self.assertConvertInvalid(opt, u'1Mbb')
2390
self.assertConvertInvalid(opt, u'1MM')
2392
def test_convert_valid(self):
2393
opt = self.get_option()
2394
self.assertConverted(int(5e3), opt, u'5kb')
2395
self.assertConverted(int(5e6), opt, u'5M')
2396
self.assertConverted(int(5e6), opt, u'5MB')
2397
self.assertConverted(int(5e9), opt, u'5g')
2398
self.assertConverted(int(5e9), opt, u'5gB')
2399
self.assertConverted(100, opt, u'100')
2402
class TestListOption(TestOptionConverter):
2404
def get_option(self):
2405
return config.ListOption('foo', help='A list.')
2407
def test_convert_invalid(self):
2408
opt = self.get_option()
2409
# We don't even try to convert a list into a list, we only expect
2411
self.assertConvertInvalid(opt, [1])
2412
# No string is invalid as all forms can be converted to a list
2414
def test_convert_valid(self):
2415
opt = self.get_option()
2416
# An empty string is an empty list
2417
self.assertConverted([], opt, '') # Using a bare str() just in case
2418
self.assertConverted([], opt, u'')
2420
self.assertConverted([u'True'], opt, u'True')
2422
self.assertConverted([u'42'], opt, u'42')
2424
self.assertConverted([u'bar'], opt, u'bar')
2427
class TestRegistryOption(TestOptionConverter):
2429
def get_option(self, registry):
2430
return config.RegistryOption('foo', registry,
2431
help='A registry option.')
2433
def test_convert_invalid(self):
2434
registry = _mod_registry.Registry()
2435
opt = self.get_option(registry)
2436
self.assertConvertInvalid(opt, [1])
2437
self.assertConvertInvalid(opt, u"notregistered")
2439
def test_convert_valid(self):
2440
registry = _mod_registry.Registry()
2441
registry.register("someval", 1234)
2442
opt = self.get_option(registry)
2443
# Using a bare str() just in case
2444
self.assertConverted(1234, opt, "someval")
2445
self.assertConverted(1234, opt, u'someval')
2446
self.assertConverted(None, opt, None)
2448
def test_help(self):
2449
registry = _mod_registry.Registry()
2450
registry.register("someval", 1234, help="some option")
2451
registry.register("dunno", 1234, help="some other option")
2452
opt = self.get_option(registry)
2454
'A registry option.\n'
2456
'The following values are supported:\n'
2457
' dunno - some other option\n'
2458
' someval - some option\n',
2461
def test_get_help_text(self):
2462
registry = _mod_registry.Registry()
2463
registry.register("someval", 1234, help="some option")
2464
registry.register("dunno", 1234, help="some other option")
2465
opt = self.get_option(registry)
2467
'A registry option.\n'
2469
'The following values are supported:\n'
2470
' dunno - some other option\n'
2471
' someval - some option\n',
2472
opt.get_help_text())
2203
2475
class TestOptionRegistry(tests.TestCase):
2205
2477
def setUp(self):
2206
2478
super(TestOptionRegistry, self).setUp()
2207
2479
# Always start with an empty registry
2208
self.overrideAttr(config, 'option_registry', registry.Registry())
2480
self.overrideAttr(config, 'option_registry', config.OptionRegistry())
2209
2481
self.registry = config.option_registry
2211
2483
def test_register(self):
2212
2484
opt = config.Option('foo')
2213
self.registry.register('foo', opt)
2485
self.registry.register(opt)
2214
2486
self.assertIs(opt, self.registry.get('foo'))
2216
lazy_option = config.Option('lazy_foo')
2218
def test_register_lazy(self):
2219
self.registry.register_lazy('foo', self.__module__,
2220
'TestOptionRegistry.lazy_option')
2221
self.assertIs(self.lazy_option, self.registry.get('foo'))
2223
2488
def test_registered_help(self):
2224
opt = config.Option('foo')
2225
self.registry.register('foo', opt, help='A simple option')
2489
opt = config.Option('foo', help='A simple option')
2490
self.registry.register(opt)
2226
2491
self.assertEquals('A simple option', self.registry.get_help('foo'))
2493
def test_dont_register_illegal_name(self):
2494
self.assertRaises(errors.IllegalOptionName,
2495
self.registry.register, config.Option(' foo'))
2496
self.assertRaises(errors.IllegalOptionName,
2497
self.registry.register, config.Option('bar,'))
2499
lazy_option = config.Option('lazy_foo', help='Lazy help')
2501
def test_register_lazy(self):
2502
self.registry.register_lazy('lazy_foo', self.__module__,
2503
'TestOptionRegistry.lazy_option')
2504
self.assertIs(self.lazy_option, self.registry.get('lazy_foo'))
2506
def test_registered_lazy_help(self):
2507
self.registry.register_lazy('lazy_foo', self.__module__,
2508
'TestOptionRegistry.lazy_option')
2509
self.assertEquals('Lazy help', self.registry.get_help('lazy_foo'))
2511
def test_dont_lazy_register_illegal_name(self):
2512
# This is where the root cause of http://pad.lv/1235099 is better
2513
# understood: 'register_lazy' doc string mentions that key should match
2514
# the option name which indirectly requires that the option name is a
2515
# valid python identifier. We violate that rule here (using a key that
2516
# doesn't match the option name) to test the option name checking.
2517
self.assertRaises(errors.IllegalOptionName,
2518
self.registry.register_lazy, ' foo', self.__module__,
2519
'TestOptionRegistry.lazy_option')
2520
self.assertRaises(errors.IllegalOptionName,
2521
self.registry.register_lazy, '1,2', self.__module__,
2522
'TestOptionRegistry.lazy_option')
2229
2525
class TestRegisteredOptions(tests.TestCase):
2230
2526
"""All registered options should verify some constraints."""
2371
2727
self.assertRaises(AssertionError, store._load_from_string, 'bar=baz')
2730
class TestStoreQuoting(TestStore):
2732
scenarios = [(key, {'get_store': builder}) for key, builder
2733
in config.test_store_builder_registry.iteritems()]
2736
super(TestStoreQuoting, self).setUp()
2737
self.store = self.get_store(self)
2738
# We need a loaded store but any content will do
2739
self.store._load_from_string('')
2741
def assertIdempotent(self, s):
2742
"""Assert that quoting an unquoted string is a no-op and vice-versa.
2744
What matters here is that option values, as they appear in a store, can
2745
be safely round-tripped out of the store and back.
2747
:param s: A string, quoted if required.
2749
self.assertEquals(s, self.store.quote(self.store.unquote(s)))
2750
self.assertEquals(s, self.store.unquote(self.store.quote(s)))
2752
def test_empty_string(self):
2753
if isinstance(self.store, config.IniFileStore):
2754
# configobj._quote doesn't handle empty values
2755
self.assertRaises(AssertionError,
2756
self.assertIdempotent, '')
2758
self.assertIdempotent('')
2759
# But quoted empty strings are ok
2760
self.assertIdempotent('""')
2762
def test_embedded_spaces(self):
2763
self.assertIdempotent('" a b c "')
2765
def test_embedded_commas(self):
2766
self.assertIdempotent('" a , b c "')
2768
def test_simple_comma(self):
2769
if isinstance(self.store, config.IniFileStore):
2770
# configobj requires that lists are special-cased
2771
self.assertRaises(AssertionError,
2772
self.assertIdempotent, ',')
2774
self.assertIdempotent(',')
2775
# When a single comma is required, quoting is also required
2776
self.assertIdempotent('","')
2778
def test_list(self):
2779
if isinstance(self.store, config.IniFileStore):
2780
# configobj requires that lists are special-cased
2781
self.assertRaises(AssertionError,
2782
self.assertIdempotent, 'a,b')
2784
self.assertIdempotent('a,b')
2787
class TestDictFromStore(tests.TestCase):
2789
def test_unquote_not_string(self):
2790
conf = config.MemoryStack('x=2\n[a_section]\na=1\n')
2791
value = conf.get('a_section')
2792
# Urgh, despite 'conf' asking for the no-name section, we get the
2793
# content of another section as a dict o_O
2794
self.assertEquals({'a': '1'}, value)
2795
unquoted = conf.store.unquote(value)
2796
# Which cannot be unquoted but shouldn't crash either (the use cases
2797
# are getting the value or displaying it. In the later case, '%s' will
2799
self.assertEquals({'a': '1'}, unquoted)
2800
self.assertEquals("{u'a': u'1'}", '%s' % (unquoted,))
2374
2803
class TestIniFileStoreContent(tests.TestCaseWithTransport):
2375
"""Simulate loading a config store without content of various encodings.
2804
"""Simulate loading a config store with content of various encodings.
2377
2806
All files produced by bzr are in utf8 content.
2556
3043
config.ConfigHooks.install_named_hook('save', hook, None)
2557
3044
self.assertLength(0, calls)
2558
3045
store = self.get_store(self)
3046
# FIXME: There should be a better way than relying on the test
3047
# parametrization to identify branch.conf -- vila 2011-0526
3048
if self.store_id in ('branch', 'remote_branch'):
3049
# branch stores requires write locked branches
3050
self.addCleanup(store.branch.lock_write().unlock)
2559
3051
section = store.get_mutable_section('baz')
2560
3052
section.set('foo', 'bar')
2562
3054
self.assertLength(1, calls)
2563
3055
self.assertEquals((store,), calls[0])
2566
class TestIniFileStore(TestStore):
3057
def test_set_mark_dirty(self):
3058
stack = config.MemoryStack('')
3059
self.assertLength(0, stack.store.dirty_sections)
3060
stack.set('foo', 'baz')
3061
self.assertLength(1, stack.store.dirty_sections)
3062
self.assertTrue(stack.store._need_saving())
3064
def test_remove_mark_dirty(self):
3065
stack = config.MemoryStack('foo=bar')
3066
self.assertLength(0, stack.store.dirty_sections)
3068
self.assertLength(1, stack.store.dirty_sections)
3069
self.assertTrue(stack.store._need_saving())
3072
class TestStoreSaveChanges(tests.TestCaseWithTransport):
3073
"""Tests that config changes are kept in memory and saved on-demand."""
3076
super(TestStoreSaveChanges, self).setUp()
3077
self.transport = self.get_transport()
3078
# Most of the tests involve two stores pointing to the same persistent
3079
# storage to observe the effects of concurrent changes
3080
self.st1 = config.TransportIniFileStore(self.transport, 'foo.conf')
3081
self.st2 = config.TransportIniFileStore(self.transport, 'foo.conf')
3084
self.warnings.append(args[0] % args[1:])
3085
self.overrideAttr(trace, 'warning', warning)
3087
def has_store(self, store):
3088
store_basename = urlutils.relative_url(self.transport.external_url(),
3089
store.external_url())
3090
return self.transport.has(store_basename)
3092
def get_stack(self, store):
3093
# Any stack will do as long as it uses the right store, just a single
3094
# no-name section is enough
3095
return config.Stack([store.get_sections], store)
3097
def test_no_changes_no_save(self):
3098
s = self.get_stack(self.st1)
3099
s.store.save_changes()
3100
self.assertEquals(False, self.has_store(self.st1))
3102
def test_unrelated_concurrent_update(self):
3103
s1 = self.get_stack(self.st1)
3104
s2 = self.get_stack(self.st2)
3105
s1.set('foo', 'bar')
3106
s2.set('baz', 'quux')
3108
# Changes don't propagate magically
3109
self.assertEquals(None, s1.get('baz'))
3110
s2.store.save_changes()
3111
self.assertEquals('quux', s2.get('baz'))
3112
# Changes are acquired when saving
3113
self.assertEquals('bar', s2.get('foo'))
3114
# Since there is no overlap, no warnings are emitted
3115
self.assertLength(0, self.warnings)
3117
def test_concurrent_update_modified(self):
3118
s1 = self.get_stack(self.st1)
3119
s2 = self.get_stack(self.st2)
3120
s1.set('foo', 'bar')
3121
s2.set('foo', 'baz')
3124
s2.store.save_changes()
3125
self.assertEquals('baz', s2.get('foo'))
3126
# But the user get a warning
3127
self.assertLength(1, self.warnings)
3128
warning = self.warnings[0]
3129
self.assertStartsWith(warning, 'Option foo in section None')
3130
self.assertEndsWith(warning, 'was changed from <CREATED> to bar.'
3131
' The baz value will be saved.')
3133
def test_concurrent_deletion(self):
3134
self.st1._load_from_string('foo=bar')
3136
s1 = self.get_stack(self.st1)
3137
s2 = self.get_stack(self.st2)
3140
s1.store.save_changes()
3142
self.assertLength(0, self.warnings)
3143
s2.store.save_changes()
3145
self.assertLength(1, self.warnings)
3146
warning = self.warnings[0]
3147
self.assertStartsWith(warning, 'Option foo in section None')
3148
self.assertEndsWith(warning, 'was changed from bar to <CREATED>.'
3149
' The <DELETED> value will be saved.')
3152
class TestQuotingIniFileStore(tests.TestCaseWithTransport):
3154
def get_store(self):
3155
return config.TransportIniFileStore(self.get_transport(), 'foo.conf')
3157
def test_get_quoted_string(self):
3158
store = self.get_store()
3159
store._load_from_string('foo= " abc "')
3160
stack = config.Stack([store.get_sections])
3161
self.assertEquals(' abc ', stack.get('foo'))
3163
def test_set_quoted_string(self):
3164
store = self.get_store()
3165
stack = config.Stack([store.get_sections], store)
3166
stack.set('foo', ' a b c ')
3168
self.assertFileEqual('foo = " a b c "' + os.linesep, 'foo.conf')
3171
class TestTransportIniFileStore(TestStore):
2568
3173
def test_loading_unknown_file_fails(self):
2569
store = config.IniFileStore(self.get_transport(), 'I-do-not-exist')
3174
store = config.TransportIniFileStore(self.get_transport(),
2570
3176
self.assertRaises(errors.NoSuchFile, store.load)
2572
3178
def test_invalid_content(self):
2573
store = config.IniFileStore(self.get_transport(), 'foo.conf', )
3179
store = config.TransportIniFileStore(self.get_transport(), 'foo.conf')
2574
3180
self.assertEquals(False, store.is_loaded())
2575
3181
exc = self.assertRaises(
2576
3182
errors.ParseConfigError, store._load_from_string,
2846
3480
matcher = config.LocationMatcher(store, expected_url)
2847
3481
self.assertEquals(expected_location, matcher.location)
2850
class TestStackGet(tests.TestCase):
2852
# FIXME: This should be parametrized for all known Stack or dedicated
2853
# paramerized tests created to avoid bloating -- vila 2011-03-31
2855
def test_single_config_get(self):
2856
conf = dict(foo='bar')
2857
conf_stack = config.Stack([conf])
2858
self.assertEquals('bar', conf_stack.get('foo'))
3483
def test_branch_name_colo(self):
3484
store = self.get_store(self)
3485
store._load_from_string(dedent("""\
3487
push_location=my{branchname}
3489
matcher = config.LocationMatcher(store, 'file:///,branch=example%3c')
3490
self.assertEqual('example<', matcher.branch_name)
3491
((_, section),) = matcher.get_sections()
3492
self.assertEqual('example<', section.locals['branchname'])
3494
def test_branch_name_basename(self):
3495
store = self.get_store(self)
3496
store._load_from_string(dedent("""\
3498
push_location=my{branchname}
3500
matcher = config.LocationMatcher(store, 'file:///parent/example%3c')
3501
self.assertEqual('example<', matcher.branch_name)
3502
((_, section),) = matcher.get_sections()
3503
self.assertEqual('example<', section.locals['branchname'])
3506
class TestStartingPathMatcher(TestStore):
3509
super(TestStartingPathMatcher, self).setUp()
3510
# Any simple store is good enough
3511
self.store = config.IniFileStore()
3513
def assertSectionIDs(self, expected, location, content):
3514
self.store._load_from_string(content)
3515
matcher = config.StartingPathMatcher(self.store, location)
3516
sections = list(matcher.get_sections())
3517
self.assertLength(len(expected), sections)
3518
self.assertEqual(expected, [section.id for _, section in sections])
3521
def test_empty(self):
3522
self.assertSectionIDs([], self.get_url(), '')
3524
def test_url_vs_local_paths(self):
3525
# The matcher location is an url and the section names are local paths
3526
self.assertSectionIDs(['/foo/bar', '/foo'],
3527
'file:///foo/bar/baz', '''\
3532
def test_local_path_vs_url(self):
3533
# The matcher location is a local path and the section names are urls
3534
self.assertSectionIDs(['file:///foo/bar', 'file:///foo'],
3535
'/foo/bar/baz', '''\
3541
def test_no_name_section_included_when_present(self):
3542
# Note that other tests will cover the case where the no-name section
3543
# is empty and as such, not included.
3544
sections = self.assertSectionIDs(['/foo/bar', '/foo', None],
3545
'/foo/bar/baz', '''\
3546
option = defined so the no-name section exists
3550
self.assertEquals(['baz', 'bar/baz', '/foo/bar/baz'],
3551
[s.locals['relpath'] for _, s in sections])
3553
def test_order_reversed(self):
3554
self.assertSectionIDs(['/foo/bar', '/foo'], '/foo/bar/baz', '''\
3559
def test_unrelated_section_excluded(self):
3560
self.assertSectionIDs(['/foo/bar', '/foo'], '/foo/bar/baz', '''\
3566
def test_glob_included(self):
3567
sections = self.assertSectionIDs(['/foo/*/baz', '/foo/b*', '/foo'],
3568
'/foo/bar/baz', '''\
3574
# Note that 'baz' as a relpath for /foo/b* is not fully correct, but
3575
# nothing really is... as far using {relpath} to append it to something
3576
# else, this seems good enough though.
3577
self.assertEquals(['', 'baz', 'bar/baz'],
3578
[s.locals['relpath'] for _, s in sections])
3580
def test_respect_order(self):
3581
self.assertSectionIDs(['/foo', '/foo/b*', '/foo/*/baz'],
3582
'/foo/bar/baz', '''\
3590
class TestNameMatcher(TestStore):
3593
super(TestNameMatcher, self).setUp()
3594
self.matcher = config.NameMatcher
3595
# Any simple store is good enough
3596
self.get_store = config.test_store_builder_registry.get('configobj')
3598
def get_matching_sections(self, name):
3599
store = self.get_store(self)
3600
store._load_from_string('''
3608
matcher = self.matcher(store, name)
3609
return list(matcher.get_sections())
3611
def test_matching(self):
3612
sections = self.get_matching_sections('foo')
3613
self.assertLength(1, sections)
3614
self.assertSectionContent(('foo', {'option': 'foo'}), sections[0])
3616
def test_not_matching(self):
3617
sections = self.get_matching_sections('baz')
3618
self.assertLength(0, sections)
3621
class TestBaseStackGet(tests.TestCase):
3624
super(TestBaseStackGet, self).setUp()
3625
self.overrideAttr(config, 'option_registry', config.OptionRegistry())
3627
def test_get_first_definition(self):
3628
store1 = config.IniFileStore()
3629
store1._load_from_string('foo=bar')
3630
store2 = config.IniFileStore()
3631
store2._load_from_string('foo=baz')
3632
conf = config.Stack([store1.get_sections, store2.get_sections])
3633
self.assertEquals('bar', conf.get('foo'))
2860
3635
def test_get_with_registered_default_value(self):
2861
conf_stack = config.Stack([dict()])
2862
opt = config.Option('foo', default='bar')
2863
self.overrideAttr(config, 'option_registry', registry.Registry())
2864
config.option_registry.register('foo', opt)
3636
config.option_registry.register(config.Option('foo', default='bar'))
3637
conf_stack = config.Stack([])
2865
3638
self.assertEquals('bar', conf_stack.get('foo'))
2867
3640
def test_get_without_registered_default_value(self):
2868
conf_stack = config.Stack([dict()])
2869
opt = config.Option('foo')
2870
self.overrideAttr(config, 'option_registry', registry.Registry())
2871
config.option_registry.register('foo', opt)
3641
config.option_registry.register(config.Option('foo'))
3642
conf_stack = config.Stack([])
2872
3643
self.assertEquals(None, conf_stack.get('foo'))
2874
3645
def test_get_without_default_value_for_not_registered(self):
2875
conf_stack = config.Stack([dict()])
2876
opt = config.Option('foo')
2877
self.overrideAttr(config, 'option_registry', registry.Registry())
3646
conf_stack = config.Stack([])
2878
3647
self.assertEquals(None, conf_stack.get('foo'))
2880
def test_get_first_definition(self):
2881
conf1 = dict(foo='bar')
2882
conf2 = dict(foo='baz')
2883
conf_stack = config.Stack([conf1, conf2])
2884
self.assertEquals('bar', conf_stack.get('foo'))
2886
def test_get_embedded_definition(self):
2887
conf1 = dict(yy='12')
2888
conf2 = config.Stack([dict(xx='42'), dict(foo='baz')])
2889
conf_stack = config.Stack([conf1, conf2])
2890
self.assertEquals('baz', conf_stack.get('foo'))
2892
3649
def test_get_for_empty_section_callable(self):
2893
3650
conf_stack = config.Stack([lambda : []])
2894
3651
self.assertEquals(None, conf_stack.get('foo'))
2896
3653
def test_get_for_broken_callable(self):
2897
3654
# Trying to use and invalid callable raises an exception on first use
2898
conf_stack = config.Stack([lambda : object()])
3655
conf_stack = config.Stack([object])
2899
3656
self.assertRaises(TypeError, conf_stack.get, 'foo')
3659
class TestStackWithSimpleStore(tests.TestCase):
3662
super(TestStackWithSimpleStore, self).setUp()
3663
self.overrideAttr(config, 'option_registry', config.OptionRegistry())
3664
self.registry = config.option_registry
3666
def get_conf(self, content=None):
3667
return config.MemoryStack(content)
3669
def test_override_value_from_env(self):
3670
self.overrideEnv('FOO', None)
3671
self.registry.register(
3672
config.Option('foo', default='bar', override_from_env=['FOO']))
3673
self.overrideEnv('FOO', 'quux')
3674
# Env variable provides a default taking over the option one
3675
conf = self.get_conf('foo=store')
3676
self.assertEquals('quux', conf.get('foo'))
3678
def test_first_override_value_from_env_wins(self):
3679
self.overrideEnv('NO_VALUE', None)
3680
self.overrideEnv('FOO', None)
3681
self.overrideEnv('BAZ', None)
3682
self.registry.register(
3683
config.Option('foo', default='bar',
3684
override_from_env=['NO_VALUE', 'FOO', 'BAZ']))
3685
self.overrideEnv('FOO', 'foo')
3686
self.overrideEnv('BAZ', 'baz')
3687
# The first env var set wins
3688
conf = self.get_conf('foo=store')
3689
self.assertEquals('foo', conf.get('foo'))
3692
class TestMemoryStack(tests.TestCase):
3695
conf = config.MemoryStack('foo=bar')
3696
self.assertEquals('bar', conf.get('foo'))
3699
conf = config.MemoryStack('foo=bar')
3700
conf.set('foo', 'baz')
3701
self.assertEquals('baz', conf.get('foo'))
3703
def test_no_content(self):
3704
conf = config.MemoryStack()
3705
# No content means no loading
3706
self.assertFalse(conf.store.is_loaded())
3707
self.assertRaises(NotImplementedError, conf.get, 'foo')
3708
# But a content can still be provided
3709
conf.store._load_from_string('foo=bar')
3710
self.assertEquals('bar', conf.get('foo'))
3713
class TestStackIterSections(tests.TestCase):
3715
def test_empty_stack(self):
3716
conf = config.Stack([])
3717
sections = list(conf.iter_sections())
3718
self.assertLength(0, sections)
3720
def test_empty_store(self):
3721
store = config.IniFileStore()
3722
store._load_from_string('')
3723
conf = config.Stack([store.get_sections])
3724
sections = list(conf.iter_sections())
3725
self.assertLength(0, sections)
3727
def test_simple_store(self):
3728
store = config.IniFileStore()
3729
store._load_from_string('foo=bar')
3730
conf = config.Stack([store.get_sections])
3731
tuples = list(conf.iter_sections())
3732
self.assertLength(1, tuples)
3733
(found_store, found_section) = tuples[0]
3734
self.assertIs(store, found_store)
3736
def test_two_stores(self):
3737
store1 = config.IniFileStore()
3738
store1._load_from_string('foo=bar')
3739
store2 = config.IniFileStore()
3740
store2._load_from_string('bar=qux')
3741
conf = config.Stack([store1.get_sections, store2.get_sections])
3742
tuples = list(conf.iter_sections())
3743
self.assertLength(2, tuples)
3744
self.assertIs(store1, tuples[0][0])
3745
self.assertIs(store2, tuples[1][0])
2902
3748
class TestStackWithTransport(tests.TestCaseWithTransport):
2904
3750
scenarios = [(key, {'get_stack': builder}) for key, builder
2910
3756
def test_build_stack(self):
2911
3757
# Just a smoke test to help debug builders
2912
stack = self.get_stack(self)
3758
self.get_stack(self)
2915
3761
class TestStackGet(TestStackWithTransport):
3764
super(TestStackGet, self).setUp()
3765
self.conf = self.get_stack(self)
2917
3767
def test_get_for_empty_stack(self):
2918
conf = self.get_stack(self)
2919
self.assertEquals(None, conf.get('foo'))
3768
self.assertEquals(None, self.conf.get('foo'))
2921
3770
def test_get_hook(self):
2922
conf = self.get_stack(self)
2923
conf.store._load_from_string('foo=bar')
3771
self.conf.set('foo', 'bar')
2925
3773
def hook(*args):
2926
3774
calls.append(args)
2927
3775
config.ConfigHooks.install_named_hook('get', hook, None)
2928
3776
self.assertLength(0, calls)
2929
value = conf.get('foo')
3777
value = self.conf.get('foo')
2930
3778
self.assertEquals('bar', value)
2931
3779
self.assertLength(1, calls)
2932
self.assertEquals((conf, 'foo', 'bar'), calls[0])
3780
self.assertEquals((self.conf, 'foo', 'bar'), calls[0])
3783
class TestStackGetWithConverter(tests.TestCase):
3786
super(TestStackGetWithConverter, self).setUp()
3787
self.overrideAttr(config, 'option_registry', config.OptionRegistry())
3788
self.registry = config.option_registry
3790
def get_conf(self, content=None):
3791
return config.MemoryStack(content)
3793
def register_bool_option(self, name, default=None, default_from_env=None):
3794
b = config.Option(name, help='A boolean.',
3795
default=default, default_from_env=default_from_env,
3796
from_unicode=config.bool_from_store)
3797
self.registry.register(b)
3799
def test_get_default_bool_None(self):
3800
self.register_bool_option('foo')
3801
conf = self.get_conf('')
3802
self.assertEquals(None, conf.get('foo'))
3804
def test_get_default_bool_True(self):
3805
self.register_bool_option('foo', u'True')
3806
conf = self.get_conf('')
3807
self.assertEquals(True, conf.get('foo'))
3809
def test_get_default_bool_False(self):
3810
self.register_bool_option('foo', False)
3811
conf = self.get_conf('')
3812
self.assertEquals(False, conf.get('foo'))
3814
def test_get_default_bool_False_as_string(self):
3815
self.register_bool_option('foo', u'False')
3816
conf = self.get_conf('')
3817
self.assertEquals(False, conf.get('foo'))
3819
def test_get_default_bool_from_env_converted(self):
3820
self.register_bool_option('foo', u'True', default_from_env=['FOO'])
3821
self.overrideEnv('FOO', 'False')
3822
conf = self.get_conf('')
3823
self.assertEquals(False, conf.get('foo'))
3825
def test_get_default_bool_when_conversion_fails(self):
3826
self.register_bool_option('foo', default='True')
3827
conf = self.get_conf('foo=invalid boolean')
3828
self.assertEquals(True, conf.get('foo'))
3830
def register_integer_option(self, name,
3831
default=None, default_from_env=None):
3832
i = config.Option(name, help='An integer.',
3833
default=default, default_from_env=default_from_env,
3834
from_unicode=config.int_from_store)
3835
self.registry.register(i)
3837
def test_get_default_integer_None(self):
3838
self.register_integer_option('foo')
3839
conf = self.get_conf('')
3840
self.assertEquals(None, conf.get('foo'))
3842
def test_get_default_integer(self):
3843
self.register_integer_option('foo', 42)
3844
conf = self.get_conf('')
3845
self.assertEquals(42, conf.get('foo'))
3847
def test_get_default_integer_as_string(self):
3848
self.register_integer_option('foo', u'42')
3849
conf = self.get_conf('')
3850
self.assertEquals(42, conf.get('foo'))
3852
def test_get_default_integer_from_env(self):
3853
self.register_integer_option('foo', default_from_env=['FOO'])
3854
self.overrideEnv('FOO', '18')
3855
conf = self.get_conf('')
3856
self.assertEquals(18, conf.get('foo'))
3858
def test_get_default_integer_when_conversion_fails(self):
3859
self.register_integer_option('foo', default='12')
3860
conf = self.get_conf('foo=invalid integer')
3861
self.assertEquals(12, conf.get('foo'))
3863
def register_list_option(self, name, default=None, default_from_env=None):
3864
l = config.ListOption(name, help='A list.', default=default,
3865
default_from_env=default_from_env)
3866
self.registry.register(l)
3868
def test_get_default_list_None(self):
3869
self.register_list_option('foo')
3870
conf = self.get_conf('')
3871
self.assertEquals(None, conf.get('foo'))
3873
def test_get_default_list_empty(self):
3874
self.register_list_option('foo', '')
3875
conf = self.get_conf('')
3876
self.assertEquals([], conf.get('foo'))
3878
def test_get_default_list_from_env(self):
3879
self.register_list_option('foo', default_from_env=['FOO'])
3880
self.overrideEnv('FOO', '')
3881
conf = self.get_conf('')
3882
self.assertEquals([], conf.get('foo'))
3884
def test_get_with_list_converter_no_item(self):
3885
self.register_list_option('foo', None)
3886
conf = self.get_conf('foo=,')
3887
self.assertEquals([], conf.get('foo'))
3889
def test_get_with_list_converter_many_items(self):
3890
self.register_list_option('foo', None)
3891
conf = self.get_conf('foo=m,o,r,e')
3892
self.assertEquals(['m', 'o', 'r', 'e'], conf.get('foo'))
3894
def test_get_with_list_converter_embedded_spaces_many_items(self):
3895
self.register_list_option('foo', None)
3896
conf = self.get_conf('foo=" bar", "baz "')
3897
self.assertEquals([' bar', 'baz '], conf.get('foo'))
3899
def test_get_with_list_converter_stripped_spaces_many_items(self):
3900
self.register_list_option('foo', None)
3901
conf = self.get_conf('foo= bar , baz ')
3902
self.assertEquals(['bar', 'baz'], conf.get('foo'))
3905
class TestIterOptionRefs(tests.TestCase):
3906
"""iter_option_refs is a bit unusual, document some cases."""
3908
def assertRefs(self, expected, string):
3909
self.assertEquals(expected, list(config.iter_option_refs(string)))
3911
def test_empty(self):
3912
self.assertRefs([(False, '')], '')
3914
def test_no_refs(self):
3915
self.assertRefs([(False, 'foo bar')], 'foo bar')
3917
def test_single_ref(self):
3918
self.assertRefs([(False, ''), (True, '{foo}'), (False, '')], '{foo}')
3920
def test_broken_ref(self):
3921
self.assertRefs([(False, '{foo')], '{foo')
3923
def test_embedded_ref(self):
3924
self.assertRefs([(False, '{'), (True, '{foo}'), (False, '}')],
3927
def test_two_refs(self):
3928
self.assertRefs([(False, ''), (True, '{foo}'),
3929
(False, ''), (True, '{bar}'),
3933
def test_newline_in_refs_are_not_matched(self):
3934
self.assertRefs([(False, '{\nxx}{xx\n}{{\n}}')], '{\nxx}{xx\n}{{\n}}')
3937
class TestStackExpandOptions(tests.TestCaseWithTransport):
3940
super(TestStackExpandOptions, self).setUp()
3941
self.overrideAttr(config, 'option_registry', config.OptionRegistry())
3942
self.registry = config.option_registry
3943
store = config.TransportIniFileStore(self.get_transport(), 'foo.conf')
3944
self.conf = config.Stack([store.get_sections], store)
3946
def assertExpansion(self, expected, string, env=None):
3947
self.assertEquals(expected, self.conf.expand_options(string, env))
3949
def test_no_expansion(self):
3950
self.assertExpansion('foo', 'foo')
3952
def test_expand_default_value(self):
3953
self.conf.store._load_from_string('bar=baz')
3954
self.registry.register(config.Option('foo', default=u'{bar}'))
3955
self.assertEquals('baz', self.conf.get('foo', expand=True))
3957
def test_expand_default_from_env(self):
3958
self.conf.store._load_from_string('bar=baz')
3959
self.registry.register(config.Option('foo', default_from_env=['FOO']))
3960
self.overrideEnv('FOO', '{bar}')
3961
self.assertEquals('baz', self.conf.get('foo', expand=True))
3963
def test_expand_default_on_failed_conversion(self):
3964
self.conf.store._load_from_string('baz=bogus\nbar=42\nfoo={baz}')
3965
self.registry.register(
3966
config.Option('foo', default=u'{bar}',
3967
from_unicode=config.int_from_store))
3968
self.assertEquals(42, self.conf.get('foo', expand=True))
3970
def test_env_adding_options(self):
3971
self.assertExpansion('bar', '{foo}', {'foo': 'bar'})
3973
def test_env_overriding_options(self):
3974
self.conf.store._load_from_string('foo=baz')
3975
self.assertExpansion('bar', '{foo}', {'foo': 'bar'})
3977
def test_simple_ref(self):
3978
self.conf.store._load_from_string('foo=xxx')
3979
self.assertExpansion('xxx', '{foo}')
3981
def test_unknown_ref(self):
3982
self.assertRaises(errors.ExpandingUnknownOption,
3983
self.conf.expand_options, '{foo}')
3985
def test_illegal_def_is_ignored(self):
3986
self.assertExpansion('{1,2}', '{1,2}')
3987
self.assertExpansion('{ }', '{ }')
3988
self.assertExpansion('${Foo,f}', '${Foo,f}')
3990
def test_indirect_ref(self):
3991
self.conf.store._load_from_string('''
3995
self.assertExpansion('xxx', '{bar}')
3997
def test_embedded_ref(self):
3998
self.conf.store._load_from_string('''
4002
self.assertExpansion('xxx', '{{bar}}')
4004
def test_simple_loop(self):
4005
self.conf.store._load_from_string('foo={foo}')
4006
self.assertRaises(errors.OptionExpansionLoop,
4007
self.conf.expand_options, '{foo}')
4009
def test_indirect_loop(self):
4010
self.conf.store._load_from_string('''
4014
e = self.assertRaises(errors.OptionExpansionLoop,
4015
self.conf.expand_options, '{foo}')
4016
self.assertEquals('foo->bar->baz', e.refs)
4017
self.assertEquals('{foo}', e.string)
4019
def test_list(self):
4020
self.conf.store._load_from_string('''
4024
list={foo},{bar},{baz}
4026
self.registry.register(
4027
config.ListOption('list'))
4028
self.assertEquals(['start', 'middle', 'end'],
4029
self.conf.get('list', expand=True))
4031
def test_cascading_list(self):
4032
self.conf.store._load_from_string('''
4038
self.registry.register(config.ListOption('list'))
4039
# Register an intermediate option as a list to ensure no conversion
4040
# happen while expanding. Conversion should only occur for the original
4041
# option ('list' here).
4042
self.registry.register(config.ListOption('baz'))
4043
self.assertEquals(['start', 'middle', 'end'],
4044
self.conf.get('list', expand=True))
4046
def test_pathologically_hidden_list(self):
4047
self.conf.store._load_from_string('''
4053
hidden={start}{middle}{end}
4055
# What matters is what the registration says, the conversion happens
4056
# only after all expansions have been performed
4057
self.registry.register(config.ListOption('hidden'))
4058
self.assertEquals(['bin', 'go'],
4059
self.conf.get('hidden', expand=True))
4062
class TestStackCrossSectionsExpand(tests.TestCaseWithTransport):
4065
super(TestStackCrossSectionsExpand, self).setUp()
4067
def get_config(self, location, string):
4070
# Since we don't save the config we won't strictly require to inherit
4071
# from TestCaseInTempDir, but an error occurs so quickly...
4072
c = config.LocationStack(location)
4073
c.store._load_from_string(string)
4076
def test_dont_cross_unrelated_section(self):
4077
c = self.get_config('/another/branch/path','''
4082
[/another/branch/path]
4085
self.assertRaises(errors.ExpandingUnknownOption,
4086
c.get, 'bar', expand=True)
4088
def test_cross_related_sections(self):
4089
c = self.get_config('/project/branch/path','''
4093
[/project/branch/path]
4096
self.assertEquals('quux', c.get('bar', expand=True))
4099
class TestStackCrossStoresExpand(tests.TestCaseWithTransport):
4101
def test_cross_global_locations(self):
4102
l_store = config.LocationStore()
4103
l_store._load_from_string('''
4109
g_store = config.GlobalStore()
4110
g_store._load_from_string('''
4116
stack = config.LocationStack('/branch')
4117
self.assertEquals('glob-bar', stack.get('lbar', expand=True))
4118
self.assertEquals('loc-foo', stack.get('gfoo', expand=True))
4121
class TestStackExpandSectionLocals(tests.TestCaseWithTransport):
4123
def test_expand_locals_empty(self):
4124
l_store = config.LocationStore()
4125
l_store._load_from_string('''
4126
[/home/user/project]
4131
stack = config.LocationStack('/home/user/project/')
4132
self.assertEquals('', stack.get('base', expand=True))
4133
self.assertEquals('', stack.get('rel', expand=True))
4135
def test_expand_basename_locally(self):
4136
l_store = config.LocationStore()
4137
l_store._load_from_string('''
4138
[/home/user/project]
4142
stack = config.LocationStack('/home/user/project/branch')
4143
self.assertEquals('branch', stack.get('bfoo', expand=True))
4145
def test_expand_basename_locally_longer_path(self):
4146
l_store = config.LocationStore()
4147
l_store._load_from_string('''
4152
stack = config.LocationStack('/home/user/project/dir/branch')
4153
self.assertEquals('branch', stack.get('bfoo', expand=True))
4155
def test_expand_relpath_locally(self):
4156
l_store = config.LocationStore()
4157
l_store._load_from_string('''
4158
[/home/user/project]
4159
lfoo = loc-foo/{relpath}
4162
stack = config.LocationStack('/home/user/project/branch')
4163
self.assertEquals('loc-foo/branch', stack.get('lfoo', expand=True))
4165
def test_expand_relpath_unknonw_in_global(self):
4166
g_store = config.GlobalStore()
4167
g_store._load_from_string('''
4172
stack = config.LocationStack('/home/user/project/branch')
4173
self.assertRaises(errors.ExpandingUnknownOption,
4174
stack.get, 'gfoo', expand=True)
4176
def test_expand_local_option_locally(self):
4177
l_store = config.LocationStore()
4178
l_store._load_from_string('''
4179
[/home/user/project]
4180
lfoo = loc-foo/{relpath}
4184
g_store = config.GlobalStore()
4185
g_store._load_from_string('''
4191
stack = config.LocationStack('/home/user/project/branch')
4192
self.assertEquals('glob-bar', stack.get('lbar', expand=True))
4193
self.assertEquals('loc-foo/branch', stack.get('gfoo', expand=True))
4195
def test_locals_dont_leak(self):
4196
"""Make sure we chose the right local in presence of several sections.
4198
l_store = config.LocationStore()
4199
l_store._load_from_string('''
4201
lfoo = loc-foo/{relpath}
4202
[/home/user/project]
4203
lfoo = loc-foo/{relpath}
4206
stack = config.LocationStack('/home/user/project/branch')
4207
self.assertEquals('loc-foo/branch', stack.get('lfoo', expand=True))
4208
stack = config.LocationStack('/home/user/bar/baz')
4209
self.assertEquals('loc-foo/bar/baz', stack.get('lfoo', expand=True))
2935
4213
class TestStackSet(TestStackWithTransport):
2937
4215
def test_simple_set(self):
2938
4216
conf = self.get_stack(self)
2939
conf.store._load_from_string('foo=bar')
2940
self.assertEquals('bar', conf.get('foo'))
4217
self.assertEquals(None, conf.get('foo'))
2941
4218
conf.set('foo', 'baz')
2942
4219
# Did we get it back ?
2943
4220
self.assertEquals('baz', conf.get('foo'))
3665
4960
self.assertEquals((None, None), (realname, address))
4963
class TestDefaultMailDomain(tests.TestCaseInTempDir):
4964
"""Test retrieving default domain from mailname file"""
4966
def test_default_mail_domain_simple(self):
4967
f = file('simple', 'w')
4969
f.write("domainname.com\n")
4972
r = config._get_default_mail_domain('simple')
4973
self.assertEquals('domainname.com', r)
4975
def test_default_mail_domain_no_eol(self):
4976
f = file('no_eol', 'w')
4978
f.write("domainname.com")
4981
r = config._get_default_mail_domain('no_eol')
4982
self.assertEquals('domainname.com', r)
4984
def test_default_mail_domain_multiple_lines(self):
4985
f = file('multiple_lines', 'w')
4987
f.write("domainname.com\nsome other text\n")
4990
r = config._get_default_mail_domain('multiple_lines')
4991
self.assertEquals('domainname.com', r)
4994
class EmailOptionTests(tests.TestCase):
4996
def test_default_email_uses_BZR_EMAIL(self):
4997
conf = config.MemoryStack('email=jelmer@debian.org')
4998
# BZR_EMAIL takes precedence over EMAIL
4999
self.overrideEnv('BZR_EMAIL', 'jelmer@samba.org')
5000
self.overrideEnv('EMAIL', 'jelmer@apache.org')
5001
self.assertEquals('jelmer@samba.org', conf.get('email'))
5003
def test_default_email_uses_EMAIL(self):
5004
conf = config.MemoryStack('')
5005
self.overrideEnv('BZR_EMAIL', None)
5006
self.overrideEnv('EMAIL', 'jelmer@apache.org')
5007
self.assertEquals('jelmer@apache.org', conf.get('email'))
5009
def test_BZR_EMAIL_overrides(self):
5010
conf = config.MemoryStack('email=jelmer@debian.org')
5011
self.overrideEnv('BZR_EMAIL', 'jelmer@apache.org')
5012
self.assertEquals('jelmer@apache.org', conf.get('email'))
5013
self.overrideEnv('BZR_EMAIL', None)
5014
self.overrideEnv('EMAIL', 'jelmer@samba.org')
5015
self.assertEquals('jelmer@debian.org', conf.get('email'))
5018
class MailClientOptionTests(tests.TestCase):
5020
def test_default(self):
5021
conf = config.MemoryStack('')
5022
client = conf.get('mail_client')
5023
self.assertIs(client, mail_client.DefaultMail)
5025
def test_evolution(self):
5026
conf = config.MemoryStack('mail_client=evolution')
5027
client = conf.get('mail_client')
5028
self.assertIs(client, mail_client.Evolution)
5030
def test_kmail(self):
5031
conf = config.MemoryStack('mail_client=kmail')
5032
client = conf.get('mail_client')
5033
self.assertIs(client, mail_client.KMail)
5035
def test_mutt(self):
5036
conf = config.MemoryStack('mail_client=mutt')
5037
client = conf.get('mail_client')
5038
self.assertIs(client, mail_client.Mutt)
5040
def test_thunderbird(self):
5041
conf = config.MemoryStack('mail_client=thunderbird')
5042
client = conf.get('mail_client')
5043
self.assertIs(client, mail_client.Thunderbird)
5045
def test_explicit_default(self):
5046
conf = config.MemoryStack('mail_client=default')
5047
client = conf.get('mail_client')
5048
self.assertIs(client, mail_client.DefaultMail)
5050
def test_editor(self):
5051
conf = config.MemoryStack('mail_client=editor')
5052
client = conf.get('mail_client')
5053
self.assertIs(client, mail_client.Editor)
5055
def test_mapi(self):
5056
conf = config.MemoryStack('mail_client=mapi')
5057
client = conf.get('mail_client')
5058
self.assertIs(client, mail_client.MAPIClient)
5060
def test_xdg_email(self):
5061
conf = config.MemoryStack('mail_client=xdg-email')
5062
client = conf.get('mail_client')
5063
self.assertIs(client, mail_client.XDGEmail)
5065
def test_unknown(self):
5066
conf = config.MemoryStack('mail_client=firebird')
5067
self.assertRaises(errors.ConfigOptionValueError, conf.get,