~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_config.py

(vila) Provide a config section matcher respecting the file order. (Vincent
 Ladeuil)

Show diffs side-by-side

added added

removed removed

Lines of Context:
2655
2655
        self.assertRaises(errors.BzrCommandError,
2656
2656
                          self.store._from_cmdline, ['a=b', 'c'])
2657
2657
 
 
2658
class TestStoreMinimalAPI(tests.TestCaseWithTransport):
 
2659
 
 
2660
    scenarios = [(key, {'get_store': builder}) for key, builder
 
2661
                 in config.test_store_builder_registry.iteritems()] + [
 
2662
        ('cmdline', {'get_store': lambda test: config.CommandLineStore()})]
 
2663
 
 
2664
    def test_id(self):
 
2665
        store = self.get_store(self)
 
2666
        if type(store) == config.TransportIniFileStore:
 
2667
            raise tests.TestNotApplicable(
 
2668
                "%s is not a concrete Store implementation"
 
2669
                " so it doesn't need an id" % (store.__class__.__name__,))
 
2670
        self.assertIsNot(None, store.id)
 
2671
 
2658
2672
 
2659
2673
class TestStore(tests.TestCaseWithTransport):
2660
2674
 
2760
2774
            self.assertIdempotent('a,b')
2761
2775
 
2762
2776
 
 
2777
class TestDictFromStore(tests.TestCase):
 
2778
 
 
2779
    def test_unquote_not_string(self):
 
2780
        conf = config.MemoryStack('x=2\n[a_section]\na=1\n')
 
2781
        value = conf.get('a_section')
 
2782
        # Urgh, despite 'conf' asking for the no-name section, we get the
 
2783
        # content of another section as a dict o_O
 
2784
        self.assertEquals({'a': '1'}, value)
 
2785
        unquoted = conf.store.unquote(value)
 
2786
        # Which cannot be unquoted but shouldn't crash either (the use cases
 
2787
        # are getting the value or displaying it. In the later case, '%s' will
 
2788
        # do).
 
2789
        self.assertEquals({'a': '1'}, unquoted)
 
2790
        self.assertEquals("{u'a': u'1'}", '%s' % (unquoted,))
 
2791
 
 
2792
 
2763
2793
class TestIniFileStoreContent(tests.TestCaseWithTransport):
2764
2794
    """Simulate loading a config store with content of various encodings.
2765
2795
 
2970
3000
        self.assertLength(1, calls)
2971
3001
        self.assertEquals((store,), calls[0])
2972
3002
 
 
3003
    def test_set_mark_dirty(self):
 
3004
        stack = config.MemoryStack('')
 
3005
        self.assertLength(0, stack.store.dirty_sections)
 
3006
        stack.set('foo', 'baz')
 
3007
        self.assertLength(1, stack.store.dirty_sections)
 
3008
        self.assertTrue(stack.store._need_saving())
 
3009
 
 
3010
    def test_remove_mark_dirty(self):
 
3011
        stack = config.MemoryStack('foo=bar')
 
3012
        self.assertLength(0, stack.store.dirty_sections)
 
3013
        stack.remove('foo')
 
3014
        self.assertLength(1, stack.store.dirty_sections)
 
3015
        self.assertTrue(stack.store._need_saving())
 
3016
 
 
3017
 
 
3018
class TestStoreSaveChanges(tests.TestCaseWithTransport):
 
3019
    """Tests that config changes are kept in memory and saved on-demand."""
 
3020
 
 
3021
    def setUp(self):
 
3022
        super(TestStoreSaveChanges, self).setUp()
 
3023
        self.transport = self.get_transport()
 
3024
        # Most of the tests involve two stores pointing to the same persistent
 
3025
        # storage to observe the effects of concurrent changes
 
3026
        self.st1 = config.TransportIniFileStore(self.transport, 'foo.conf')
 
3027
        self.st2 = config.TransportIniFileStore(self.transport, 'foo.conf')
 
3028
        self.warnings = []
 
3029
        def warning(*args):
 
3030
            self.warnings.append(args[0] % args[1:])
 
3031
        self.overrideAttr(trace, 'warning', warning)
 
3032
 
 
3033
    def has_store(self, store):
 
3034
        store_basename = urlutils.relative_url(self.transport.external_url(),
 
3035
                                               store.external_url())
 
3036
        return self.transport.has(store_basename)
 
3037
 
 
3038
    def get_stack(self, store):
 
3039
        # Any stack will do as long as it uses the right store, just a single
 
3040
        # no-name section is enough
 
3041
        return config.Stack([store.get_sections], store)
 
3042
 
 
3043
    def test_no_changes_no_save(self):
 
3044
        s = self.get_stack(self.st1)
 
3045
        s.store.save_changes()
 
3046
        self.assertEquals(False, self.has_store(self.st1))
 
3047
 
 
3048
    def test_unrelated_concurrent_update(self):
 
3049
        s1 = self.get_stack(self.st1)
 
3050
        s2 = self.get_stack(self.st2)
 
3051
        s1.set('foo', 'bar')
 
3052
        s2.set('baz', 'quux')
 
3053
        s1.store.save()
 
3054
        # Changes don't propagate magically
 
3055
        self.assertEquals(None, s1.get('baz'))
 
3056
        s2.store.save_changes()
 
3057
        self.assertEquals('quux', s2.get('baz'))
 
3058
        # Changes are acquired when saving
 
3059
        self.assertEquals('bar', s2.get('foo'))
 
3060
        # Since there is no overlap, no warnings are emitted
 
3061
        self.assertLength(0, self.warnings)
 
3062
 
 
3063
    def test_concurrent_update_modified(self):
 
3064
        s1 = self.get_stack(self.st1)
 
3065
        s2 = self.get_stack(self.st2)
 
3066
        s1.set('foo', 'bar')
 
3067
        s2.set('foo', 'baz')
 
3068
        s1.store.save()
 
3069
        # Last speaker wins
 
3070
        s2.store.save_changes()
 
3071
        self.assertEquals('baz', s2.get('foo'))
 
3072
        # But the user get a warning
 
3073
        self.assertLength(1, self.warnings)
 
3074
        warning = self.warnings[0]
 
3075
        self.assertStartsWith(warning, 'Option foo in section None')
 
3076
        self.assertEndsWith(warning, 'was changed from <CREATED> to bar.'
 
3077
                            ' The baz value will be saved.')
 
3078
 
 
3079
    def test_concurrent_deletion(self):
 
3080
        self.st1._load_from_string('foo=bar')
 
3081
        self.st1.save()
 
3082
        s1 = self.get_stack(self.st1)
 
3083
        s2 = self.get_stack(self.st2)
 
3084
        s1.remove('foo')
 
3085
        s2.remove('foo')
 
3086
        s1.store.save_changes()
 
3087
        # No warning yet
 
3088
        self.assertLength(0, self.warnings)
 
3089
        s2.store.save_changes()
 
3090
        # Now we get one
 
3091
        self.assertLength(1, self.warnings)
 
3092
        warning = self.warnings[0]
 
3093
        self.assertStartsWith(warning, 'Option foo in section None')
 
3094
        self.assertEndsWith(warning, 'was changed from bar to <CREATED>.'
 
3095
                            ' The <DELETED> value will be saved.')
 
3096
 
2973
3097
 
2974
3098
class TestQuotingIniFileStore(tests.TestCaseWithTransport):
2975
3099
 
2987
3111
        stack = config.Stack([store.get_sections], store)
2988
3112
        stack.set('foo', ' a b c ')
2989
3113
        store.save()
2990
 
        self.assertFileEqual('foo = " a b c "\n', 'foo.conf')
 
3114
        self.assertFileEqual('foo = " a b c "' + os.linesep, 'foo.conf')
2991
3115
 
2992
3116
 
2993
3117
class TestTransportIniFileStore(TestStore):
3456
3580
        self.assertRaises(TypeError, conf_stack.get, 'foo')
3457
3581
 
3458
3582
 
 
3583
class TestStackWithSimpleStore(tests.TestCase):
 
3584
 
 
3585
    def setUp(self):
 
3586
        super(TestStackWithSimpleStore, self).setUp()
 
3587
        self.overrideAttr(config, 'option_registry', config.OptionRegistry())
 
3588
        self.registry = config.option_registry
 
3589
 
 
3590
    def get_conf(self, content=None):
 
3591
        return config.MemoryStack(content)
 
3592
 
 
3593
    def test_override_value_from_env(self):
 
3594
        self.registry.register(
 
3595
            config.Option('foo', default='bar', override_from_env=['FOO']))
 
3596
        self.overrideEnv('FOO', 'quux')
 
3597
        # Env variable provides a default taking over the option one
 
3598
        conf = self.get_conf('foo=store')
 
3599
        self.assertEquals('quux', conf.get('foo'))
 
3600
 
 
3601
    def test_first_override_value_from_env_wins(self):
 
3602
        self.registry.register(
 
3603
            config.Option('foo', default='bar',
 
3604
                          override_from_env=['NO_VALUE', 'FOO', 'BAZ']))
 
3605
        self.overrideEnv('FOO', 'foo')
 
3606
        self.overrideEnv('BAZ', 'baz')
 
3607
        # The first env var set wins
 
3608
        conf = self.get_conf('foo=store')
 
3609
        self.assertEquals('foo', conf.get('foo'))
 
3610
 
 
3611
 
3459
3612
class TestMemoryStack(tests.TestCase):
3460
3613
 
3461
3614
    def test_get(self):
4668
4821
class EmailOptionTests(tests.TestCase):
4669
4822
 
4670
4823
    def test_default_email_uses_BZR_EMAIL(self):
 
4824
        conf = config.MemoryStack('email=jelmer@debian.org')
4671
4825
        # BZR_EMAIL takes precedence over EMAIL
4672
4826
        self.overrideEnv('BZR_EMAIL', 'jelmer@samba.org')
4673
4827
        self.overrideEnv('EMAIL', 'jelmer@apache.org')
4674
 
        self.assertEquals('jelmer@samba.org', config.default_email())
 
4828
        self.assertEquals('jelmer@samba.org', conf.get('email'))
4675
4829
 
4676
4830
    def test_default_email_uses_EMAIL(self):
 
4831
        conf = config.MemoryStack('')
4677
4832
        self.overrideEnv('BZR_EMAIL', None)
4678
4833
        self.overrideEnv('EMAIL', 'jelmer@apache.org')
4679
 
        self.assertEquals('jelmer@apache.org', config.default_email())
 
4834
        self.assertEquals('jelmer@apache.org', conf.get('email'))
4680
4835
 
4681
4836
    def test_BZR_EMAIL_overrides(self):
 
4837
        conf = config.MemoryStack('email=jelmer@debian.org')
4682
4838
        self.overrideEnv('BZR_EMAIL', 'jelmer@apache.org')
4683
 
        self.assertEquals('jelmer@apache.org',
4684
 
            config.email_from_store('jelmer@debian.org'))
 
4839
        self.assertEquals('jelmer@apache.org', conf.get('email'))
4685
4840
        self.overrideEnv('BZR_EMAIL', None)
4686
4841
        self.overrideEnv('EMAIL', 'jelmer@samba.org')
4687
 
        self.assertEquals('jelmer@debian.org',
4688
 
            config.email_from_store('jelmer@debian.org'))
 
4842
        self.assertEquals('jelmer@debian.org', conf.get('email'))