~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_config.py

  • Committer: Vincent Ladeuil
  • Date: 2011-12-16 16:38:33 UTC
  • mto: This revision was merged to the branch mainline in revision 6387.
  • Revision ID: v.ladeuil+lp@free.fr-20111216163833-4igwmwi1dmxbbebw
Migrate add.maximum_file_size to the new config scheme

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2012 Canonical Ltd
 
1
# Copyright (C) 2005-2011 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
35
35
    mail_client,
36
36
    ui,
37
37
    urlutils,
38
 
    registry as _mod_registry,
39
38
    remote,
40
39
    tests,
41
40
    trace,
145
144
config.test_stack_builder_registry.register('branch', build_branch_stack)
146
145
 
147
146
 
148
 
def build_branch_only_stack(test):
 
147
def build_remote_branch_stack(test):
149
148
    # There is only one permutation (but we won't be able to handle more with
150
149
    # this design anyway)
151
150
    (transport_class,
152
151
     server_class) = transport_remote.get_test_permutations()[0]
153
152
    build_backing_branch(test, 'branch', transport_class, server_class)
154
153
    b = branch.Branch.open(test.get_url('branch'))
155
 
    return config.BranchOnlyStack(b)
156
 
config.test_stack_builder_registry.register('branch_only',
157
 
                                            build_branch_only_stack)
 
154
    return config.RemoteBranchStack(b)
 
155
config.test_stack_builder_registry.register('remote_branch',
 
156
                                            build_remote_branch_stack)
158
157
 
159
158
def build_remote_control_stack(test):
160
159
    # There is only one permutation (but we won't be able to handle more with
538
537
 
539
538
    def test_log_format_default(self):
540
539
        my_config = config.Config()
541
 
        self.assertEqual('long',
542
 
                         self.applyDeprecated(deprecated_in((2, 5, 0)),
543
 
                                              my_config.log_format))
 
540
        self.assertEqual('long', my_config.log_format())
544
541
 
545
542
    def test_acceptable_keys_default(self):
546
543
        my_config = config.Config()
577
574
    def test_config_dir(self):
578
575
        self.assertEqual(config.config_dir(), self.bzr_home)
579
576
 
580
 
    def test_config_dir_is_unicode(self):
581
 
        self.assertIsInstance(config.config_dir(), unicode)
582
 
 
583
577
    def test_config_filename(self):
584
578
        self.assertEqual(config.config_filename(),
585
579
                         self.bzr_home + '/bazaar.conf')
1197
1191
        b = self.make_branch('!repo')
1198
1192
        self.assertEqual('!repo', b.get_config().get_nickname())
1199
1193
 
1200
 
    def test_autonick_uses_branch_name(self):
1201
 
        b = self.make_branch('foo', name='bar')
1202
 
        self.assertEqual('bar', b.get_config().get_nickname())
1203
 
 
1204
1194
    def test_warn_if_masked(self):
1205
1195
        warnings = []
1206
1196
        def warning(*args):
1331
1321
 
1332
1322
    def test_configured_logformat(self):
1333
1323
        my_config = self._get_sample_config()
1334
 
        self.assertEqual("short",
1335
 
                         self.applyDeprecated(deprecated_in((2, 5, 0)),
1336
 
                                              my_config.log_format))
 
1324
        self.assertEqual("short", my_config.log_format())
1337
1325
 
1338
1326
    def test_configured_acceptable_keys(self):
1339
1327
        my_config = self._get_sample_config()
1911
1899
            location='http://example.com/specific')
1912
1900
        self.assertEqual(my_config.get_user_option('option'), 'exact')
1913
1901
 
 
1902
    def test_get_mail_client(self):
 
1903
        config = self.get_branch_config()
 
1904
        client = config.get_mail_client()
 
1905
        self.assertIsInstance(client, mail_client.DefaultMail)
 
1906
 
 
1907
        # Specific clients
 
1908
        config.set_user_option('mail_client', 'evolution')
 
1909
        client = config.get_mail_client()
 
1910
        self.assertIsInstance(client, mail_client.Evolution)
 
1911
 
 
1912
        config.set_user_option('mail_client', 'kmail')
 
1913
        client = config.get_mail_client()
 
1914
        self.assertIsInstance(client, mail_client.KMail)
 
1915
 
 
1916
        config.set_user_option('mail_client', 'mutt')
 
1917
        client = config.get_mail_client()
 
1918
        self.assertIsInstance(client, mail_client.Mutt)
 
1919
 
 
1920
        config.set_user_option('mail_client', 'thunderbird')
 
1921
        client = config.get_mail_client()
 
1922
        self.assertIsInstance(client, mail_client.Thunderbird)
 
1923
 
 
1924
        # Generic options
 
1925
        config.set_user_option('mail_client', 'default')
 
1926
        client = config.get_mail_client()
 
1927
        self.assertIsInstance(client, mail_client.DefaultMail)
 
1928
 
 
1929
        config.set_user_option('mail_client', 'editor')
 
1930
        client = config.get_mail_client()
 
1931
        self.assertIsInstance(client, mail_client.Editor)
 
1932
 
 
1933
        config.set_user_option('mail_client', 'mapi')
 
1934
        client = config.get_mail_client()
 
1935
        self.assertIsInstance(client, mail_client.MAPIClient)
 
1936
 
 
1937
        config.set_user_option('mail_client', 'xdg-email')
 
1938
        client = config.get_mail_client()
 
1939
        self.assertIsInstance(client, mail_client.XDGEmail)
 
1940
 
 
1941
        config.set_user_option('mail_client', 'firebird')
 
1942
        self.assertRaises(errors.UnknownMailClient, config.get_mail_client)
 
1943
 
1914
1944
 
1915
1945
class TestMailAddressExtraction(tests.TestCase):
1916
1946
 
2332
2362
class TestOptionConverterMixin(object):
2333
2363
 
2334
2364
    def assertConverted(self, expected, opt, value):
2335
 
        self.assertEquals(expected, opt.convert_from_unicode(None, value))
 
2365
        self.assertEquals(expected, opt.convert_from_unicode(value),
 
2366
                          'Expecting %s, got %s' % (expected, value,))
2336
2367
 
2337
2368
    def assertWarns(self, opt, value):
2338
2369
        warnings = []
2339
2370
        def warning(*args):
2340
2371
            warnings.append(args[0] % args[1:])
2341
2372
        self.overrideAttr(trace, 'warning', warning)
2342
 
        self.assertEquals(None, opt.convert_from_unicode(None, value))
 
2373
        self.assertEquals(None, opt.convert_from_unicode(value))
2343
2374
        self.assertLength(1, warnings)
2344
2375
        self.assertEquals(
2345
2376
            'Value "%s" is not valid for "%s"' % (value, opt.name),
2347
2378
 
2348
2379
    def assertErrors(self, opt, value):
2349
2380
        self.assertRaises(errors.ConfigOptionValueError,
2350
 
                          opt.convert_from_unicode, None, value)
 
2381
                          opt.convert_from_unicode, value)
2351
2382
 
2352
2383
    def assertConvertInvalid(self, opt, invalid_value):
2353
2384
        opt.invalid = None
2354
 
        self.assertEquals(None, opt.convert_from_unicode(None, invalid_value))
 
2385
        self.assertEquals(None, opt.convert_from_unicode(invalid_value),
 
2386
                          '%s is not None' % (invalid_value,))
2355
2387
        opt.invalid = 'warning'
2356
2388
        self.assertWarns(opt, invalid_value)
2357
2389
        opt.invalid = 'error'
2421
2453
        self.assertConverted(100, opt, u'100')
2422
2454
 
2423
2455
 
2424
 
class TestListOption(tests.TestCase, TestOptionConverterMixin):
2425
 
 
2426
 
    def get_option(self):
2427
 
        return config.ListOption('foo', help='A list.')
 
2456
class TestOptionWithListConverter(tests.TestCase, TestOptionConverterMixin):
 
2457
 
 
2458
    def get_option(self):
 
2459
        return config.Option('foo', help='A list.',
 
2460
                             from_unicode=config.list_from_store)
 
2461
 
 
2462
    def test_convert_invalid(self):
 
2463
        # No string is invalid as all forms can be converted to a list
 
2464
        pass
 
2465
 
 
2466
    def test_convert_valid(self):
 
2467
        opt = self.get_option()
 
2468
        # An empty string is an empty list
 
2469
        self.assertConverted([], opt, '') # Using a bare str() just in case
 
2470
        self.assertConverted([], opt, u'')
 
2471
        # A boolean
 
2472
        self.assertConverted([u'True'], opt, u'True')
 
2473
        # An integer
 
2474
        self.assertConverted([u'42'], opt, u'42')
 
2475
        # A single string
 
2476
        self.assertConverted([u'bar'], opt, u'bar')
 
2477
        # A list remains a list (configObj will turn a string containing commas
 
2478
        # into a list, but that's not what we're testing here)
 
2479
        self.assertConverted([u'foo', u'1', u'True'],
 
2480
                             opt, [u'foo', u'1', u'True'])
 
2481
 
 
2482
 
 
2483
class TestOptionConverterMixin(object):
 
2484
 
 
2485
    def assertConverted(self, expected, opt, value):
 
2486
        self.assertEquals(expected, opt.convert_from_unicode(value))
 
2487
 
 
2488
    def assertWarns(self, opt, value):
 
2489
        warnings = []
 
2490
        def warning(*args):
 
2491
            warnings.append(args[0] % args[1:])
 
2492
        self.overrideAttr(trace, 'warning', warning)
 
2493
        self.assertEquals(None, opt.convert_from_unicode(value))
 
2494
        self.assertLength(1, warnings)
 
2495
        self.assertEquals(
 
2496
            'Value "%s" is not valid for "%s"' % (value, opt.name),
 
2497
            warnings[0])
 
2498
 
 
2499
    def assertErrors(self, opt, value):
 
2500
        self.assertRaises(errors.ConfigOptionValueError,
 
2501
                          opt.convert_from_unicode, value)
 
2502
 
 
2503
    def assertConvertInvalid(self, opt, invalid_value):
 
2504
        opt.invalid = None
 
2505
        self.assertEquals(None, opt.convert_from_unicode(invalid_value))
 
2506
        opt.invalid = 'warning'
 
2507
        self.assertWarns(opt, invalid_value)
 
2508
        opt.invalid = 'error'
 
2509
        self.assertErrors(opt, invalid_value)
 
2510
 
 
2511
 
 
2512
class TestOptionWithBooleanConverter(tests.TestCase, TestOptionConverterMixin):
 
2513
 
 
2514
    def get_option(self):
 
2515
        return config.Option('foo', help='A boolean.',
 
2516
                             from_unicode=config.bool_from_store)
 
2517
 
 
2518
    def test_convert_invalid(self):
 
2519
        opt = self.get_option()
 
2520
        # A string that is not recognized as a boolean
 
2521
        self.assertConvertInvalid(opt, u'invalid-boolean')
 
2522
        # A list of strings is never recognized as a boolean
 
2523
        self.assertConvertInvalid(opt, [u'not', u'a', u'boolean'])
 
2524
 
 
2525
    def test_convert_valid(self):
 
2526
        opt = self.get_option()
 
2527
        self.assertConverted(True, opt, u'True')
 
2528
        self.assertConverted(True, opt, u'1')
 
2529
        self.assertConverted(False, opt, u'False')
 
2530
 
 
2531
 
 
2532
class TestOptionWithIntegerConverter(tests.TestCase, TestOptionConverterMixin):
 
2533
 
 
2534
    def get_option(self):
 
2535
        return config.Option('foo', help='An integer.',
 
2536
                             from_unicode=config.int_from_store)
 
2537
 
 
2538
    def test_convert_invalid(self):
 
2539
        opt = self.get_option()
 
2540
        # A string that is not recognized as an integer
 
2541
        self.assertConvertInvalid(opt, u'forty-two')
 
2542
        # A list of strings is never recognized as an integer
 
2543
        self.assertConvertInvalid(opt, [u'a', u'list'])
 
2544
 
 
2545
    def test_convert_valid(self):
 
2546
        opt = self.get_option()
 
2547
        self.assertConverted(16, opt, u'16')
 
2548
 
 
2549
 
 
2550
class TestOptionWithListConverter(tests.TestCase, TestOptionConverterMixin):
 
2551
 
 
2552
    def get_option(self):
 
2553
        return config.Option('foo', help='A list.',
 
2554
                             from_unicode=config.list_from_store)
2428
2555
 
2429
2556
    def test_convert_invalid(self):
2430
2557
        opt = self.get_option()
2446
2573
        self.assertConverted([u'bar'], opt, u'bar')
2447
2574
 
2448
2575
 
2449
 
class TestRegistryOption(tests.TestCase, TestOptionConverterMixin):
2450
 
 
2451
 
    def get_option(self, registry):
2452
 
        return config.RegistryOption('foo', registry,
2453
 
                help='A registry option.')
2454
 
 
2455
 
    def test_convert_invalid(self):
2456
 
        registry = _mod_registry.Registry()
2457
 
        opt = self.get_option(registry)
2458
 
        self.assertConvertInvalid(opt, [1])
2459
 
        self.assertConvertInvalid(opt, u"notregistered")
2460
 
 
2461
 
    def test_convert_valid(self):
2462
 
        registry = _mod_registry.Registry()
2463
 
        registry.register("someval", 1234)
2464
 
        opt = self.get_option(registry)
2465
 
        # Using a bare str() just in case
2466
 
        self.assertConverted(1234, opt, "someval")
2467
 
        self.assertConverted(1234, opt, u'someval')
2468
 
        self.assertConverted(None, opt, None)
2469
 
 
2470
 
    def test_help(self):
2471
 
        registry = _mod_registry.Registry()
2472
 
        registry.register("someval", 1234, help="some option")
2473
 
        registry.register("dunno", 1234, help="some other option")
2474
 
        opt = self.get_option(registry)
2475
 
        self.assertEquals(
2476
 
            'A registry option.\n'
2477
 
            '\n'
2478
 
            'The following values are supported:\n'
2479
 
            ' dunno - some other option\n'
2480
 
            ' someval - some option\n',
2481
 
            opt.help)
2482
 
 
2483
 
    def test_get_help_text(self):
2484
 
        registry = _mod_registry.Registry()
2485
 
        registry.register("someval", 1234, help="some option")
2486
 
        registry.register("dunno", 1234, help="some other option")
2487
 
        opt = self.get_option(registry)
2488
 
        self.assertEquals(
2489
 
            'A registry option.\n'
2490
 
            '\n'
2491
 
            'The following values are supported:\n'
2492
 
            ' dunno - some other option\n'
2493
 
            ' someval - some option\n',
2494
 
            opt.get_help_text())
2495
 
 
2496
 
 
2497
2576
class TestOptionRegistry(tests.TestCase):
2498
2577
 
2499
2578
    def setUp(self):
2628
2707
    def setUp(self):
2629
2708
        super(TestCommandLineStore, self).setUp()
2630
2709
        self.store = config.CommandLineStore()
2631
 
        self.overrideAttr(config, 'option_registry', config.OptionRegistry())
2632
2710
 
2633
2711
    def get_section(self):
2634
2712
        """Get the unique section for the command line overrides."""
2649
2727
        self.assertEqual('b', section.get('a'))
2650
2728
 
2651
2729
    def test_list_override(self):
2652
 
        opt = config.ListOption('l')
2653
 
        config.option_registry.register(opt)
2654
2730
        self.store._from_cmdline(['l=1,2,3'])
2655
2731
        val = self.get_section().get('l')
2656
2732
        self.assertEqual('1,2,3', val)
2657
2733
        # Reminder: lists should be registered as such explicitely, otherwise
2658
2734
        # the conversion needs to be done afterwards.
2659
 
        self.assertEqual(['1', '2', '3'],
2660
 
                         opt.convert_from_unicode(self.store, val))
 
2735
        self.assertEqual(['1', '2', '3'], config.list_from_store(val))
2661
2736
 
2662
2737
    def test_multiple_overrides(self):
2663
2738
        self.store._from_cmdline(['a=b', 'x=y'])
2669
2744
        self.assertRaises(errors.BzrCommandError,
2670
2745
                          self.store._from_cmdline, ['a=b', 'c'])
2671
2746
 
2672
 
class TestStoreMinimalAPI(tests.TestCaseWithTransport):
2673
 
 
2674
 
    scenarios = [(key, {'get_store': builder}) for key, builder
2675
 
                 in config.test_store_builder_registry.iteritems()] + [
2676
 
        ('cmdline', {'get_store': lambda test: config.CommandLineStore()})]
2677
 
 
2678
 
    def test_id(self):
2679
 
        store = self.get_store(self)
2680
 
        if type(store) == config.TransportIniFileStore:
2681
 
            raise tests.TestNotApplicable(
2682
 
                "%s is not a concrete Store implementation"
2683
 
                " so it doesn't need an id" % (store.__class__.__name__,))
2684
 
        self.assertIsNot(None, store.id)
2685
 
 
2686
2747
 
2687
2748
class TestStore(tests.TestCaseWithTransport):
2688
2749
 
2731
2792
        self.assertRaises(AssertionError, store._load_from_string, 'bar=baz')
2732
2793
 
2733
2794
 
2734
 
class TestStoreQuoting(TestStore):
2735
 
 
2736
 
    scenarios = [(key, {'get_store': builder}) for key, builder
2737
 
                 in config.test_store_builder_registry.iteritems()]
2738
 
 
2739
 
    def setUp(self):
2740
 
        super(TestStoreQuoting, self).setUp()
2741
 
        self.store = self.get_store(self)
2742
 
        # We need a loaded store but any content will do
2743
 
        self.store._load_from_string('')
2744
 
 
2745
 
    def assertIdempotent(self, s):
2746
 
        """Assert that quoting an unquoted string is a no-op and vice-versa.
2747
 
 
2748
 
        What matters here is that option values, as they appear in a store, can
2749
 
        be safely round-tripped out of the store and back.
2750
 
 
2751
 
        :param s: A string, quoted if required.
2752
 
        """
2753
 
        self.assertEquals(s, self.store.quote(self.store.unquote(s)))
2754
 
        self.assertEquals(s, self.store.unquote(self.store.quote(s)))
2755
 
 
2756
 
    def test_empty_string(self):
2757
 
        if isinstance(self.store, config.IniFileStore):
2758
 
            # configobj._quote doesn't handle empty values
2759
 
            self.assertRaises(AssertionError,
2760
 
                              self.assertIdempotent, '')
2761
 
        else:
2762
 
            self.assertIdempotent('')
2763
 
        # But quoted empty strings are ok
2764
 
        self.assertIdempotent('""')
2765
 
 
2766
 
    def test_embedded_spaces(self):
2767
 
        self.assertIdempotent('" a b c "')
2768
 
 
2769
 
    def test_embedded_commas(self):
2770
 
        self.assertIdempotent('" a , b c "')
2771
 
 
2772
 
    def test_simple_comma(self):
2773
 
        if isinstance(self.store, config.IniFileStore):
2774
 
            # configobj requires that lists are special-cased
2775
 
           self.assertRaises(AssertionError,
2776
 
                             self.assertIdempotent, ',')
2777
 
        else:
2778
 
            self.assertIdempotent(',')
2779
 
        # When a single comma is required, quoting is also required
2780
 
        self.assertIdempotent('","')
2781
 
 
2782
 
    def test_list(self):
2783
 
        if isinstance(self.store, config.IniFileStore):
2784
 
            # configobj requires that lists are special-cased
2785
 
            self.assertRaises(AssertionError,
2786
 
                              self.assertIdempotent, 'a,b')
2787
 
        else:
2788
 
            self.assertIdempotent('a,b')
2789
 
 
2790
 
 
2791
 
class TestDictFromStore(tests.TestCase):
2792
 
 
2793
 
    def test_unquote_not_string(self):
2794
 
        conf = config.MemoryStack('x=2\n[a_section]\na=1\n')
2795
 
        value = conf.get('a_section')
2796
 
        # Urgh, despite 'conf' asking for the no-name section, we get the
2797
 
        # content of another section as a dict o_O
2798
 
        self.assertEquals({'a': '1'}, value)
2799
 
        unquoted = conf.store.unquote(value)
2800
 
        # Which cannot be unquoted but shouldn't crash either (the use cases
2801
 
        # are getting the value or displaying it. In the later case, '%s' will
2802
 
        # do).
2803
 
        self.assertEquals({'a': '1'}, unquoted)
2804
 
        self.assertEquals("{u'a': u'1'}", '%s' % (unquoted,))
2805
 
 
2806
 
 
2807
2795
class TestIniFileStoreContent(tests.TestCaseWithTransport):
2808
2796
    """Simulate loading a config store with content of various encodings.
2809
2797
 
2928
2916
    def test_save_emptied_succeeds(self):
2929
2917
        store = self.get_store(self)
2930
2918
        store._load_from_string('foo=bar\n')
2931
 
        # FIXME: There should be a better way than relying on the test
2932
 
        # parametrization to identify branch.conf -- vila 2011-0526
2933
 
        if self.store_id in ('branch', 'remote_branch'):
2934
 
            # branch stores requires write locked branches
2935
 
            self.addCleanup(store.branch.lock_write().unlock)
2936
2919
        section = store.get_mutable_section(None)
2937
2920
        section.remove('foo')
2938
2921
        store.save()
2959
2942
 
2960
2943
    def test_set_option_in_empty_store(self):
2961
2944
        store = self.get_store(self)
2962
 
        # FIXME: There should be a better way than relying on the test
2963
 
        # parametrization to identify branch.conf -- vila 2011-0526
2964
 
        if self.store_id in ('branch', 'remote_branch'):
2965
 
            # branch stores requires write locked branches
2966
 
            self.addCleanup(store.branch.lock_write().unlock)
2967
2945
        section = store.get_mutable_section(None)
2968
2946
        section.set('foo', 'bar')
2969
2947
        store.save()
2975
2953
    def test_set_option_in_default_section(self):
2976
2954
        store = self.get_store(self)
2977
2955
        store._load_from_string('')
2978
 
        # FIXME: There should be a better way than relying on the test
2979
 
        # parametrization to identify branch.conf -- vila 2011-0526
2980
 
        if self.store_id in ('branch', 'remote_branch'):
2981
 
            # branch stores requires write locked branches
2982
 
            self.addCleanup(store.branch.lock_write().unlock)
2983
2956
        section = store.get_mutable_section(None)
2984
2957
        section.set('foo', 'bar')
2985
2958
        store.save()
2991
2964
    def test_set_option_in_named_section(self):
2992
2965
        store = self.get_store(self)
2993
2966
        store._load_from_string('')
2994
 
        # FIXME: There should be a better way than relying on the test
2995
 
        # parametrization to identify branch.conf -- vila 2011-0526
2996
 
        if self.store_id in ('branch', 'remote_branch'):
2997
 
            # branch stores requires write locked branches
2998
 
            self.addCleanup(store.branch.lock_write().unlock)
2999
2967
        section = store.get_mutable_section('baz')
3000
2968
        section.set('foo', 'bar')
3001
2969
        store.save()
3005
2973
        self.assertSectionContent(('baz', {'foo': 'bar'}), sections[0])
3006
2974
 
3007
2975
    def test_load_hook(self):
3008
 
        # First, we need to ensure that the store exists
 
2976
        # We first needs to ensure that the store exists
3009
2977
        store = self.get_store(self)
3010
 
        # FIXME: There should be a better way than relying on the test
3011
 
        # parametrization to identify branch.conf -- vila 2011-0526
3012
 
        if self.store_id in ('branch', 'remote_branch'):
3013
 
            # branch stores requires write locked branches
3014
 
            self.addCleanup(store.branch.lock_write().unlock)
3015
2978
        section = store.get_mutable_section('baz')
3016
2979
        section.set('foo', 'bar')
3017
2980
        store.save()
3033
2996
        config.ConfigHooks.install_named_hook('save', hook, None)
3034
2997
        self.assertLength(0, calls)
3035
2998
        store = self.get_store(self)
3036
 
        # FIXME: There should be a better way than relying on the test
3037
 
        # parametrization to identify branch.conf -- vila 2011-0526
3038
 
        if self.store_id in ('branch', 'remote_branch'):
3039
 
            # branch stores requires write locked branches
3040
 
            self.addCleanup(store.branch.lock_write().unlock)
3041
2999
        section = store.get_mutable_section('baz')
3042
3000
        section.set('foo', 'bar')
3043
3001
        store.save()
3044
3002
        self.assertLength(1, calls)
3045
3003
        self.assertEquals((store,), calls[0])
3046
3004
 
3047
 
    def test_set_mark_dirty(self):
3048
 
        stack = config.MemoryStack('')
3049
 
        self.assertLength(0, stack.store.dirty_sections)
3050
 
        stack.set('foo', 'baz')
3051
 
        self.assertLength(1, stack.store.dirty_sections)
3052
 
        self.assertTrue(stack.store._need_saving())
3053
 
 
3054
 
    def test_remove_mark_dirty(self):
3055
 
        stack = config.MemoryStack('foo=bar')
3056
 
        self.assertLength(0, stack.store.dirty_sections)
3057
 
        stack.remove('foo')
3058
 
        self.assertLength(1, stack.store.dirty_sections)
3059
 
        self.assertTrue(stack.store._need_saving())
3060
 
 
3061
 
 
3062
 
class TestStoreSaveChanges(tests.TestCaseWithTransport):
3063
 
    """Tests that config changes are kept in memory and saved on-demand."""
3064
 
 
3065
 
    def setUp(self):
3066
 
        super(TestStoreSaveChanges, self).setUp()
3067
 
        self.transport = self.get_transport()
3068
 
        # Most of the tests involve two stores pointing to the same persistent
3069
 
        # storage to observe the effects of concurrent changes
3070
 
        self.st1 = config.TransportIniFileStore(self.transport, 'foo.conf')
3071
 
        self.st2 = config.TransportIniFileStore(self.transport, 'foo.conf')
3072
 
        self.warnings = []
3073
 
        def warning(*args):
3074
 
            self.warnings.append(args[0] % args[1:])
3075
 
        self.overrideAttr(trace, 'warning', warning)
3076
 
 
3077
 
    def has_store(self, store):
3078
 
        store_basename = urlutils.relative_url(self.transport.external_url(),
3079
 
                                               store.external_url())
3080
 
        return self.transport.has(store_basename)
3081
 
 
3082
 
    def get_stack(self, store):
3083
 
        # Any stack will do as long as it uses the right store, just a single
3084
 
        # no-name section is enough
3085
 
        return config.Stack([store.get_sections], store)
3086
 
 
3087
 
    def test_no_changes_no_save(self):
3088
 
        s = self.get_stack(self.st1)
3089
 
        s.store.save_changes()
3090
 
        self.assertEquals(False, self.has_store(self.st1))
3091
 
 
3092
 
    def test_unrelated_concurrent_update(self):
3093
 
        s1 = self.get_stack(self.st1)
3094
 
        s2 = self.get_stack(self.st2)
3095
 
        s1.set('foo', 'bar')
3096
 
        s2.set('baz', 'quux')
3097
 
        s1.store.save()
3098
 
        # Changes don't propagate magically
3099
 
        self.assertEquals(None, s1.get('baz'))
3100
 
        s2.store.save_changes()
3101
 
        self.assertEquals('quux', s2.get('baz'))
3102
 
        # Changes are acquired when saving
3103
 
        self.assertEquals('bar', s2.get('foo'))
3104
 
        # Since there is no overlap, no warnings are emitted
3105
 
        self.assertLength(0, self.warnings)
3106
 
 
3107
 
    def test_concurrent_update_modified(self):
3108
 
        s1 = self.get_stack(self.st1)
3109
 
        s2 = self.get_stack(self.st2)
3110
 
        s1.set('foo', 'bar')
3111
 
        s2.set('foo', 'baz')
3112
 
        s1.store.save()
3113
 
        # Last speaker wins
3114
 
        s2.store.save_changes()
3115
 
        self.assertEquals('baz', s2.get('foo'))
3116
 
        # But the user get a warning
3117
 
        self.assertLength(1, self.warnings)
3118
 
        warning = self.warnings[0]
3119
 
        self.assertStartsWith(warning, 'Option foo in section None')
3120
 
        self.assertEndsWith(warning, 'was changed from <CREATED> to bar.'
3121
 
                            ' The baz value will be saved.')
3122
 
 
3123
 
    def test_concurrent_deletion(self):
3124
 
        self.st1._load_from_string('foo=bar')
3125
 
        self.st1.save()
3126
 
        s1 = self.get_stack(self.st1)
3127
 
        s2 = self.get_stack(self.st2)
3128
 
        s1.remove('foo')
3129
 
        s2.remove('foo')
3130
 
        s1.store.save_changes()
3131
 
        # No warning yet
3132
 
        self.assertLength(0, self.warnings)
3133
 
        s2.store.save_changes()
3134
 
        # Now we get one
3135
 
        self.assertLength(1, self.warnings)
3136
 
        warning = self.warnings[0]
3137
 
        self.assertStartsWith(warning, 'Option foo in section None')
3138
 
        self.assertEndsWith(warning, 'was changed from bar to <CREATED>.'
3139
 
                            ' The <DELETED> value will be saved.')
3140
 
 
3141
 
 
3142
 
class TestQuotingIniFileStore(tests.TestCaseWithTransport):
3143
 
 
3144
 
    def get_store(self):
3145
 
        return config.TransportIniFileStore(self.get_transport(), 'foo.conf')
3146
 
 
3147
 
    def test_get_quoted_string(self):
3148
 
        store = self.get_store()
3149
 
        store._load_from_string('foo= " abc "')
3150
 
        stack = config.Stack([store.get_sections])
3151
 
        self.assertEquals(' abc ', stack.get('foo'))
3152
 
 
3153
 
    def test_set_quoted_string(self):
3154
 
        store = self.get_store()
3155
 
        stack = config.Stack([store.get_sections], store)
3156
 
        stack.set('foo', ' a b c ')
3157
 
        store.save()
3158
 
        self.assertFileEqual('foo = " a b c "' + os.linesep, 'foo.conf')
3159
 
 
3160
3005
 
3161
3006
class TestTransportIniFileStore(TestStore):
3162
3007
 
3380
3225
 
3381
3226
    def get_section(self, options, extra_path):
3382
3227
        section = config.Section('foo', options)
3383
 
        return config.LocationSection(section, extra_path)
 
3228
        # We don't care about the length so we use '0'
 
3229
        return config.LocationSection(section, 0, extra_path)
3384
3230
 
3385
3231
    def test_simple_option(self):
3386
3232
        section = self.get_section({'foo': 'bar'}, '')
3423
3269
                           '/quux/quux'],
3424
3270
                          [section.id for _, section in store.get_sections()])
3425
3271
        matcher = config.LocationMatcher(store, '/foo/bar/quux')
3426
 
        sections = [section for _, section in matcher.get_sections()]
 
3272
        sections = [section for s, section in matcher.get_sections()]
 
3273
        self.assertEquals([3, 2],
 
3274
                          [section.length for section in sections])
3427
3275
        self.assertEquals(['/foo/bar', '/foo'],
3428
3276
                          [section.id for section in sections])
3429
3277
        self.assertEquals(['quux', 'bar/quux'],
3440
3288
        self.assertEquals(['/foo', '/foo/bar'],
3441
3289
                          [section.id for _, section in store.get_sections()])
3442
3290
        matcher = config.LocationMatcher(store, '/foo/bar/baz')
3443
 
        sections = [section for _, section in matcher.get_sections()]
 
3291
        sections = [section for s, section in matcher.get_sections()]
 
3292
        self.assertEquals([3, 2],
 
3293
                          [section.length for section in sections])
3444
3294
        self.assertEquals(['/foo/bar', '/foo'],
3445
3295
                          [section.id for section in sections])
3446
3296
        self.assertEquals(['baz', 'bar/baz'],
3471
3321
        self.assertEquals(expected_location, matcher.location)
3472
3322
 
3473
3323
 
3474
 
class TestStartingPathMatcher(TestStore):
3475
 
 
3476
 
    def setUp(self):
3477
 
        super(TestStartingPathMatcher, self).setUp()
3478
 
        # Any simple store is good enough
3479
 
        self.store = config.IniFileStore()
3480
 
 
3481
 
    def assertSectionIDs(self, expected, location, content):
3482
 
        self.store._load_from_string(content)
3483
 
        matcher = config.StartingPathMatcher(self.store, location)
3484
 
        sections = list(matcher.get_sections())
3485
 
        self.assertLength(len(expected), sections)
3486
 
        self.assertEqual(expected, [section.id for _, section in sections])
3487
 
        return sections
3488
 
 
3489
 
    def test_empty(self):
3490
 
        self.assertSectionIDs([], self.get_url(), '')
3491
 
 
3492
 
    def test_url_vs_local_paths(self):
3493
 
        # The matcher location is an url and the section names are local paths
3494
 
        sections = self.assertSectionIDs(['/foo/bar', '/foo'],
3495
 
                                         'file:///foo/bar/baz', '''\
3496
 
[/foo]
3497
 
[/foo/bar]
3498
 
''')
3499
 
 
3500
 
    def test_local_path_vs_url(self):
3501
 
        # The matcher location is a local path and the section names are urls
3502
 
        sections = self.assertSectionIDs(['file:///foo/bar', 'file:///foo'],
3503
 
                                         '/foo/bar/baz', '''\
3504
 
[file:///foo]
3505
 
[file:///foo/bar]
3506
 
''')
3507
 
 
3508
 
 
3509
 
    def test_no_name_section_included_when_present(self):
3510
 
        # Note that other tests will cover the case where the no-name section
3511
 
        # is empty and as such, not included.
3512
 
        sections = self.assertSectionIDs(['/foo/bar', '/foo', None],
3513
 
                                         '/foo/bar/baz', '''\
3514
 
option = defined so the no-name section exists
3515
 
[/foo]
3516
 
[/foo/bar]
3517
 
''')
3518
 
        self.assertEquals(['baz', 'bar/baz', '/foo/bar/baz'],
3519
 
                          [s.locals['relpath'] for _, s in sections])
3520
 
 
3521
 
    def test_order_reversed(self):
3522
 
        self.assertSectionIDs(['/foo/bar', '/foo'], '/foo/bar/baz', '''\
3523
 
[/foo]
3524
 
[/foo/bar]
3525
 
''')
3526
 
 
3527
 
    def test_unrelated_section_excluded(self):
3528
 
        self.assertSectionIDs(['/foo/bar', '/foo'], '/foo/bar/baz', '''\
3529
 
[/foo]
3530
 
[/foo/qux]
3531
 
[/foo/bar]
3532
 
''')
3533
 
 
3534
 
    def test_glob_included(self):
3535
 
        sections = self.assertSectionIDs(['/foo/*/baz', '/foo/b*', '/foo'],
3536
 
                                         '/foo/bar/baz', '''\
3537
 
[/foo]
3538
 
[/foo/qux]
3539
 
[/foo/b*]
3540
 
[/foo/*/baz]
3541
 
''')
3542
 
        # Note that 'baz' as a relpath for /foo/b* is not fully correct, but
3543
 
        # nothing really is... as far using {relpath} to append it to something
3544
 
        # else, this seems good enough though.
3545
 
        self.assertEquals(['', 'baz', 'bar/baz'],
3546
 
                          [s.locals['relpath'] for _, s in sections])
3547
 
 
3548
 
    def test_respect_order(self):
3549
 
        self.assertSectionIDs(['/foo', '/foo/b*', '/foo/*/baz'],
3550
 
                              '/foo/bar/baz', '''\
3551
 
[/foo/*/baz]
3552
 
[/foo/qux]
3553
 
[/foo/b*]
3554
 
[/foo]
3555
 
''')
3556
 
 
3557
 
 
3558
3324
class TestNameMatcher(TestStore):
3559
3325
 
3560
3326
    def setUp(self):
3586
3352
        self.assertLength(0, sections)
3587
3353
 
3588
3354
 
3589
 
class TestBaseStackGet(tests.TestCase):
3590
 
 
3591
 
    def setUp(self):
3592
 
        super(TestBaseStackGet, self).setUp()
 
3355
class TestStackGet(tests.TestCase):
 
3356
 
 
3357
    # FIXME: This should be parametrized for all known Stack or dedicated
 
3358
    # paramerized tests created to avoid bloating -- vila 2011-03-31
 
3359
 
 
3360
    def overrideOptionRegistry(self):
3593
3361
        self.overrideAttr(config, 'option_registry', config.OptionRegistry())
3594
3362
 
3595
 
    def test_get_first_definition(self):
3596
 
        store1 = config.IniFileStore()
3597
 
        store1._load_from_string('foo=bar')
3598
 
        store2 = config.IniFileStore()
3599
 
        store2._load_from_string('foo=baz')
3600
 
        conf = config.Stack([store1.get_sections, store2.get_sections])
3601
 
        self.assertEquals('bar', conf.get('foo'))
 
3363
    def test_single_config_get(self):
 
3364
        conf = dict(foo='bar')
 
3365
        conf_stack = config.Stack([conf])
 
3366
        self.assertEquals('bar', conf_stack.get('foo'))
3602
3367
 
3603
3368
    def test_get_with_registered_default_value(self):
3604
 
        config.option_registry.register(config.Option('foo', default='bar'))
3605
 
        conf_stack = config.Stack([])
 
3369
        conf_stack = config.Stack([dict()])
 
3370
        opt = config.Option('foo', default='bar')
 
3371
        self.overrideOptionRegistry()
 
3372
        config.option_registry.register('foo', opt)
3606
3373
        self.assertEquals('bar', conf_stack.get('foo'))
3607
3374
 
3608
3375
    def test_get_without_registered_default_value(self):
3609
 
        config.option_registry.register(config.Option('foo'))
3610
 
        conf_stack = config.Stack([])
 
3376
        conf_stack = config.Stack([dict()])
 
3377
        opt = config.Option('foo')
 
3378
        self.overrideOptionRegistry()
 
3379
        config.option_registry.register('foo', opt)
3611
3380
        self.assertEquals(None, conf_stack.get('foo'))
3612
3381
 
3613
3382
    def test_get_without_default_value_for_not_registered(self):
3614
 
        conf_stack = config.Stack([])
 
3383
        conf_stack = config.Stack([dict()])
 
3384
        opt = config.Option('foo')
 
3385
        self.overrideOptionRegistry()
3615
3386
        self.assertEquals(None, conf_stack.get('foo'))
3616
3387
 
 
3388
    def test_get_first_definition(self):
 
3389
        conf1 = dict(foo='bar')
 
3390
        conf2 = dict(foo='baz')
 
3391
        conf_stack = config.Stack([conf1, conf2])
 
3392
        self.assertEquals('bar', conf_stack.get('foo'))
 
3393
 
 
3394
    def test_get_embedded_definition(self):
 
3395
        conf1 = dict(yy='12')
 
3396
        conf2 = config.Stack([dict(xx='42'), dict(foo='baz')])
 
3397
        conf_stack = config.Stack([conf1, conf2])
 
3398
        self.assertEquals('baz', conf_stack.get('foo'))
 
3399
 
3617
3400
    def test_get_for_empty_section_callable(self):
3618
3401
        conf_stack = config.Stack([lambda : []])
3619
3402
        self.assertEquals(None, conf_stack.get('foo'))
3620
3403
 
3621
3404
    def test_get_for_broken_callable(self):
3622
3405
        # Trying to use and invalid callable raises an exception on first use
3623
 
        conf_stack = config.Stack([object])
 
3406
        conf_stack = config.Stack([lambda : object()])
3624
3407
        self.assertRaises(TypeError, conf_stack.get, 'foo')
3625
3408
 
3626
3409
 
3627
 
class TestStackWithSimpleStore(tests.TestCase):
3628
 
 
3629
 
    def setUp(self):
3630
 
        super(TestStackWithSimpleStore, self).setUp()
3631
 
        self.overrideAttr(config, 'option_registry', config.OptionRegistry())
3632
 
        self.registry = config.option_registry
3633
 
 
3634
 
    def get_conf(self, content=None):
3635
 
        return config.MemoryStack(content)
3636
 
 
3637
 
    def test_override_value_from_env(self):
3638
 
        self.registry.register(
3639
 
            config.Option('foo', default='bar', override_from_env=['FOO']))
3640
 
        self.overrideEnv('FOO', 'quux')
3641
 
        # Env variable provides a default taking over the option one
3642
 
        conf = self.get_conf('foo=store')
3643
 
        self.assertEquals('quux', conf.get('foo'))
3644
 
 
3645
 
    def test_first_override_value_from_env_wins(self):
3646
 
        self.registry.register(
3647
 
            config.Option('foo', default='bar',
3648
 
                          override_from_env=['NO_VALUE', 'FOO', 'BAZ']))
3649
 
        self.overrideEnv('FOO', 'foo')
3650
 
        self.overrideEnv('BAZ', 'baz')
3651
 
        # The first env var set wins
3652
 
        conf = self.get_conf('foo=store')
3653
 
        self.assertEquals('foo', conf.get('foo'))
3654
 
 
3655
 
 
3656
 
class TestMemoryStack(tests.TestCase):
3657
 
 
3658
 
    def test_get(self):
3659
 
        conf = config.MemoryStack('foo=bar')
3660
 
        self.assertEquals('bar', conf.get('foo'))
3661
 
 
3662
 
    def test_set(self):
3663
 
        conf = config.MemoryStack('foo=bar')
3664
 
        conf.set('foo', 'baz')
3665
 
        self.assertEquals('baz', conf.get('foo'))
3666
 
 
3667
 
    def test_no_content(self):
3668
 
        conf = config.MemoryStack()
3669
 
        # No content means no loading
3670
 
        self.assertFalse(conf.store.is_loaded())
3671
 
        self.assertRaises(NotImplementedError, conf.get, 'foo')
3672
 
        # But a content can still be provided
3673
 
        conf.store._load_from_string('foo=bar')
3674
 
        self.assertEquals('bar', conf.get('foo'))
3675
 
 
3676
 
 
3677
 
class TestStackIterSections(tests.TestCase):
3678
 
 
3679
 
    def test_empty_stack(self):
3680
 
        conf = config.Stack([])
3681
 
        sections = list(conf.iter_sections())
3682
 
        self.assertLength(0, sections)
3683
 
 
3684
 
    def test_empty_store(self):
3685
 
        store = config.IniFileStore()
3686
 
        store._load_from_string('')
3687
 
        conf = config.Stack([store.get_sections])
3688
 
        sections = list(conf.iter_sections())
3689
 
        self.assertLength(0, sections)
3690
 
 
3691
 
    def test_simple_store(self):
3692
 
        store = config.IniFileStore()
3693
 
        store._load_from_string('foo=bar')
3694
 
        conf = config.Stack([store.get_sections])
3695
 
        tuples = list(conf.iter_sections())
3696
 
        self.assertLength(1, tuples)
3697
 
        (found_store, found_section) = tuples[0]
3698
 
        self.assertIs(store, found_store)
3699
 
 
3700
 
    def test_two_stores(self):
3701
 
        store1 = config.IniFileStore()
3702
 
        store1._load_from_string('foo=bar')
3703
 
        store2 = config.IniFileStore()
3704
 
        store2._load_from_string('bar=qux')
3705
 
        conf = config.Stack([store1.get_sections, store2.get_sections])
3706
 
        tuples = list(conf.iter_sections())
3707
 
        self.assertLength(2, tuples)
3708
 
        self.assertIs(store1, tuples[0][0])
3709
 
        self.assertIs(store2, tuples[1][0])
3710
 
 
3711
 
 
3712
3410
class TestStackWithTransport(tests.TestCaseWithTransport):
3713
3411
 
3714
3412
    scenarios = [(key, {'get_stack': builder}) for key, builder
3744
3442
        self.assertEquals((self.conf, 'foo', 'bar'), calls[0])
3745
3443
 
3746
3444
 
3747
 
class TestStackGetWithConverter(tests.TestCase):
 
3445
class TestStackGetWithConverter(tests.TestCaseWithTransport):
3748
3446
 
3749
3447
    def setUp(self):
3750
3448
        super(TestStackGetWithConverter, self).setUp()
3751
3449
        self.overrideAttr(config, 'option_registry', config.OptionRegistry())
3752
3450
        self.registry = config.option_registry
3753
 
 
3754
 
    def get_conf(self, content=None):
3755
 
        return config.MemoryStack(content)
 
3451
        # We just want a simple stack with a simple store so we can inject
 
3452
        # whatever content the tests need without caring about what section
 
3453
        # names are valid for a given store/stack.
 
3454
        store = config.TransportIniFileStore(self.get_transport(), 'foo.conf')
 
3455
        self.conf = config.Stack([store.get_sections], store)
3756
3456
 
3757
3457
    def register_bool_option(self, name, default=None, default_from_env=None):
3758
3458
        b = config.Option(name, help='A boolean.',
3762
3462
 
3763
3463
    def test_get_default_bool_None(self):
3764
3464
        self.register_bool_option('foo')
3765
 
        conf = self.get_conf('')
3766
 
        self.assertEquals(None, conf.get('foo'))
 
3465
        self.assertEquals(None, self.conf.get('foo'))
3767
3466
 
3768
3467
    def test_get_default_bool_True(self):
3769
3468
        self.register_bool_option('foo', u'True')
3770
 
        conf = self.get_conf('')
3771
 
        self.assertEquals(True, conf.get('foo'))
 
3469
        self.assertEquals(True, self.conf.get('foo'))
3772
3470
 
3773
3471
    def test_get_default_bool_False(self):
3774
3472
        self.register_bool_option('foo', False)
3775
 
        conf = self.get_conf('')
3776
 
        self.assertEquals(False, conf.get('foo'))
 
3473
        self.assertEquals(False, self.conf.get('foo'))
3777
3474
 
3778
3475
    def test_get_default_bool_False_as_string(self):
3779
3476
        self.register_bool_option('foo', u'False')
3780
 
        conf = self.get_conf('')
3781
 
        self.assertEquals(False, conf.get('foo'))
 
3477
        self.assertEquals(False, self.conf.get('foo'))
3782
3478
 
3783
3479
    def test_get_default_bool_from_env_converted(self):
3784
3480
        self.register_bool_option('foo', u'True', default_from_env=['FOO'])
3785
3481
        self.overrideEnv('FOO', 'False')
3786
 
        conf = self.get_conf('')
3787
 
        self.assertEquals(False, conf.get('foo'))
 
3482
        self.assertEquals(False, self.conf.get('foo'))
3788
3483
 
3789
3484
    def test_get_default_bool_when_conversion_fails(self):
3790
3485
        self.register_bool_option('foo', default='True')
3791
 
        conf = self.get_conf('foo=invalid boolean')
3792
 
        self.assertEquals(True, conf.get('foo'))
 
3486
        self.conf.store._load_from_string('foo=invalid boolean')
 
3487
        self.assertEquals(True, self.conf.get('foo'))
3793
3488
 
3794
3489
    def register_integer_option(self, name,
3795
3490
                                default=None, default_from_env=None):
3800
3495
 
3801
3496
    def test_get_default_integer_None(self):
3802
3497
        self.register_integer_option('foo')
3803
 
        conf = self.get_conf('')
3804
 
        self.assertEquals(None, conf.get('foo'))
 
3498
        self.assertEquals(None, self.conf.get('foo'))
3805
3499
 
3806
3500
    def test_get_default_integer(self):
3807
3501
        self.register_integer_option('foo', 42)
3808
 
        conf = self.get_conf('')
3809
 
        self.assertEquals(42, conf.get('foo'))
 
3502
        self.assertEquals(42, self.conf.get('foo'))
3810
3503
 
3811
3504
    def test_get_default_integer_as_string(self):
3812
3505
        self.register_integer_option('foo', u'42')
3813
 
        conf = self.get_conf('')
3814
 
        self.assertEquals(42, conf.get('foo'))
 
3506
        self.assertEquals(42, self.conf.get('foo'))
3815
3507
 
3816
3508
    def test_get_default_integer_from_env(self):
3817
3509
        self.register_integer_option('foo', default_from_env=['FOO'])
3818
3510
        self.overrideEnv('FOO', '18')
3819
 
        conf = self.get_conf('')
3820
 
        self.assertEquals(18, conf.get('foo'))
 
3511
        self.assertEquals(18, self.conf.get('foo'))
3821
3512
 
3822
3513
    def test_get_default_integer_when_conversion_fails(self):
3823
3514
        self.register_integer_option('foo', default='12')
3824
 
        conf = self.get_conf('foo=invalid integer')
3825
 
        self.assertEquals(12, conf.get('foo'))
 
3515
        self.conf.store._load_from_string('foo=invalid integer')
 
3516
        self.assertEquals(12, self.conf.get('foo'))
3826
3517
 
3827
3518
    def register_list_option(self, name, default=None, default_from_env=None):
3828
 
        l = config.ListOption(name, help='A list.', default=default,
3829
 
                              default_from_env=default_from_env)
 
3519
        l = config.Option(name, help='A list.',
 
3520
                          default=default, default_from_env=default_from_env,
 
3521
                          from_unicode=config.list_from_store)
3830
3522
        self.registry.register(l)
3831
3523
 
3832
3524
    def test_get_default_list_None(self):
3833
3525
        self.register_list_option('foo')
3834
 
        conf = self.get_conf('')
3835
 
        self.assertEquals(None, conf.get('foo'))
 
3526
        self.assertEquals(None, self.conf.get('foo'))
3836
3527
 
3837
3528
    def test_get_default_list_empty(self):
3838
3529
        self.register_list_option('foo', '')
3839
 
        conf = self.get_conf('')
3840
 
        self.assertEquals([], conf.get('foo'))
 
3530
        self.assertEquals([], self.conf.get('foo'))
3841
3531
 
3842
3532
    def test_get_default_list_from_env(self):
3843
3533
        self.register_list_option('foo', default_from_env=['FOO'])
3844
3534
        self.overrideEnv('FOO', '')
3845
 
        conf = self.get_conf('')
3846
 
        self.assertEquals([], conf.get('foo'))
 
3535
        self.assertEquals([], self.conf.get('foo'))
3847
3536
 
3848
3537
    def test_get_with_list_converter_no_item(self):
3849
3538
        self.register_list_option('foo', None)
3850
 
        conf = self.get_conf('foo=,')
3851
 
        self.assertEquals([], conf.get('foo'))
 
3539
        self.conf.store._load_from_string('foo=,')
 
3540
        self.assertEquals([], self.conf.get('foo'))
3852
3541
 
3853
3542
    def test_get_with_list_converter_many_items(self):
3854
3543
        self.register_list_option('foo', None)
3855
 
        conf = self.get_conf('foo=m,o,r,e')
3856
 
        self.assertEquals(['m', 'o', 'r', 'e'], conf.get('foo'))
 
3544
        self.conf.store._load_from_string('foo=m,o,r,e')
 
3545
        self.assertEquals(['m', 'o', 'r', 'e'], self.conf.get('foo'))
3857
3546
 
3858
3547
    def test_get_with_list_converter_embedded_spaces_many_items(self):
3859
3548
        self.register_list_option('foo', None)
3860
 
        conf = self.get_conf('foo=" bar", "baz "')
3861
 
        self.assertEquals([' bar', 'baz '], conf.get('foo'))
 
3549
        self.conf.store._load_from_string('foo=" bar", "baz "')
 
3550
        self.assertEquals([' bar', 'baz '], self.conf.get('foo'))
3862
3551
 
3863
3552
    def test_get_with_list_converter_stripped_spaces_many_items(self):
3864
3553
        self.register_list_option('foo', None)
3865
 
        conf = self.get_conf('foo= bar ,  baz ')
3866
 
        self.assertEquals(['bar', 'baz'], conf.get('foo'))
 
3554
        self.conf.store._load_from_string('foo= bar ,  baz ')
 
3555
        self.assertEquals(['bar', 'baz'], self.conf.get('foo'))
3867
3556
 
3868
3557
 
3869
3558
class TestIterOptionRefs(tests.TestCase):
3904
3593
        super(TestStackExpandOptions, self).setUp()
3905
3594
        self.overrideAttr(config, 'option_registry', config.OptionRegistry())
3906
3595
        self.registry = config.option_registry
3907
 
        store = config.TransportIniFileStore(self.get_transport(), 'foo.conf')
3908
 
        self.conf = config.Stack([store.get_sections], store)
 
3596
        self.conf = build_branch_stack(self)
3909
3597
 
3910
3598
    def assertExpansion(self, expected, string, env=None):
3911
3599
        self.assertEquals(expected, self.conf.expand_options(string, env))
3983
3671
list={foo},{bar},{baz}
3984
3672
''')
3985
3673
        self.registry.register(
3986
 
            config.ListOption('list'))
 
3674
            config.Option('list', from_unicode=config.list_from_store))
3987
3675
        self.assertEquals(['start', 'middle', 'end'],
3988
3676
                           self.conf.get('list', expand=True))
3989
3677
 
3994
3682
baz=end
3995
3683
list={foo}
3996
3684
''')
3997
 
        self.registry.register(config.ListOption('list'))
3998
 
        # Register an intermediate option as a list to ensure no conversion
3999
 
        # happen while expanding. Conversion should only occur for the original
4000
 
        # option ('list' here).
4001
 
        self.registry.register(config.ListOption('baz'))
 
3685
        self.registry.register(
 
3686
            config.Option('list', from_unicode=config.list_from_store))
4002
3687
        self.assertEquals(['start', 'middle', 'end'],
4003
3688
                           self.conf.get('list', expand=True))
4004
3689
 
4013
3698
''')
4014
3699
        # What matters is what the registration says, the conversion happens
4015
3700
        # only after all expansions have been performed
4016
 
        self.registry.register(config.ListOption('hidden'))
 
3701
        self.registry.register(
 
3702
            config.Option('hidden', from_unicode=config.list_from_store))
4017
3703
        self.assertEquals(['bin', 'go'],
4018
3704
                          self.conf.get('hidden', expand=True))
4019
3705
 
4904
4590
class EmailOptionTests(tests.TestCase):
4905
4591
 
4906
4592
    def test_default_email_uses_BZR_EMAIL(self):
4907
 
        conf = config.MemoryStack('email=jelmer@debian.org')
4908
4593
        # BZR_EMAIL takes precedence over EMAIL
4909
4594
        self.overrideEnv('BZR_EMAIL', 'jelmer@samba.org')
4910
4595
        self.overrideEnv('EMAIL', 'jelmer@apache.org')
4911
 
        self.assertEquals('jelmer@samba.org', conf.get('email'))
 
4596
        self.assertEquals('jelmer@samba.org', config.default_email())
4912
4597
 
4913
4598
    def test_default_email_uses_EMAIL(self):
4914
 
        conf = config.MemoryStack('')
4915
4599
        self.overrideEnv('BZR_EMAIL', None)
4916
4600
        self.overrideEnv('EMAIL', 'jelmer@apache.org')
4917
 
        self.assertEquals('jelmer@apache.org', conf.get('email'))
 
4601
        self.assertEquals('jelmer@apache.org', config.default_email())
4918
4602
 
4919
4603
    def test_BZR_EMAIL_overrides(self):
4920
 
        conf = config.MemoryStack('email=jelmer@debian.org')
4921
4604
        self.overrideEnv('BZR_EMAIL', 'jelmer@apache.org')
4922
 
        self.assertEquals('jelmer@apache.org', conf.get('email'))
 
4605
        self.assertEquals('jelmer@apache.org',
 
4606
            config.email_from_store('jelmer@debian.org'))
4923
4607
        self.overrideEnv('BZR_EMAIL', None)
4924
4608
        self.overrideEnv('EMAIL', 'jelmer@samba.org')
4925
 
        self.assertEquals('jelmer@debian.org', conf.get('email'))
4926
 
 
4927
 
 
4928
 
class MailClientOptionTests(tests.TestCase):
4929
 
 
4930
 
    def test_default(self):
4931
 
        conf = config.MemoryStack('')
4932
 
        client = conf.get('mail_client')
4933
 
        self.assertIs(client, mail_client.DefaultMail)
4934
 
 
4935
 
    def test_evolution(self):
4936
 
        conf = config.MemoryStack('mail_client=evolution')
4937
 
        client = conf.get('mail_client')
4938
 
        self.assertIs(client, mail_client.Evolution)
4939
 
 
4940
 
    def test_kmail(self):
4941
 
        conf = config.MemoryStack('mail_client=kmail')
4942
 
        client = conf.get('mail_client')
4943
 
        self.assertIs(client, mail_client.KMail)
4944
 
 
4945
 
    def test_mutt(self):
4946
 
        conf = config.MemoryStack('mail_client=mutt')
4947
 
        client = conf.get('mail_client')
4948
 
        self.assertIs(client, mail_client.Mutt)
4949
 
 
4950
 
    def test_thunderbird(self):
4951
 
        conf = config.MemoryStack('mail_client=thunderbird')
4952
 
        client = conf.get('mail_client')
4953
 
        self.assertIs(client, mail_client.Thunderbird)
4954
 
 
4955
 
    def test_explicit_default(self):
4956
 
        conf = config.MemoryStack('mail_client=default')
4957
 
        client = conf.get('mail_client')
4958
 
        self.assertIs(client, mail_client.DefaultMail)
4959
 
 
4960
 
    def test_editor(self):
4961
 
        conf = config.MemoryStack('mail_client=editor')
4962
 
        client = conf.get('mail_client')
4963
 
        self.assertIs(client, mail_client.Editor)
4964
 
 
4965
 
    def test_mapi(self):
4966
 
        conf = config.MemoryStack('mail_client=mapi')
4967
 
        client = conf.get('mail_client')
4968
 
        self.assertIs(client, mail_client.MAPIClient)
4969
 
 
4970
 
    def test_xdg_email(self):
4971
 
        conf = config.MemoryStack('mail_client=xdg-email')
4972
 
        client = conf.get('mail_client')
4973
 
        self.assertIs(client, mail_client.XDGEmail)
4974
 
 
4975
 
    def test_unknown(self):
4976
 
        conf = config.MemoryStack('mail_client=firebird')
4977
 
        self.assertRaises(errors.ConfigOptionValueError, conf.get,
4978
 
                'mail_client')
 
4609
        self.assertEquals('jelmer@debian.org',
 
4610
            config.email_from_store('jelmer@debian.org'))