~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_config.py

  • Committer: Martin Pool
  • Date: 2011-03-28 01:28:09 UTC
  • mto: (5425.4.19 220464-stale-locks)
  • mto: This revision was merged to the branch mainline in revision 5970.
  • Revision ID: mbp@canonical.com-20110328012809-frw003r09tcrxkiz
Represent lock held info as an object, not just a dict

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2011 Canonical Ltd
 
1
# Copyright (C) 2005-2010 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
21
21
import sys
22
22
import threading
23
23
 
24
 
 
25
 
from testtools import matchers
26
 
 
27
24
#import bzrlib specific imports here
28
25
from bzrlib import (
29
26
    branch,
33
30
    errors,
34
31
    osutils,
35
32
    mail_client,
36
 
    mergetools,
37
33
    ui,
38
34
    urlutils,
39
 
    registry,
40
35
    tests,
41
36
    trace,
42
37
    transport,
43
38
    )
44
 
from bzrlib.tests import (
45
 
    features,
46
 
    TestSkipped,
47
 
    scenarios,
48
 
    )
 
39
from bzrlib.tests import features
49
40
from bzrlib.util.configobj import configobj
50
41
 
51
42
 
61
52
          'config_section': '.'}),]
62
53
 
63
54
 
64
 
load_tests = scenarios.load_tests_apply_scenarios
65
 
 
66
 
# We need adapters that can build a config store in a test context. Test
67
 
# classes, based on TestCaseWithTransport, can use the registry to parametrize
68
 
# themselves. The builder will receive a test instance and should return a
69
 
# ready-to-use store.  Plugins that defines new stores can also register
70
 
# themselves here to be tested against the tests defined below.
71
 
 
72
 
# FIXME: plugins should *not* need to import test_config to register their
73
 
# helpers (or selftest -s xxx will be broken), the following registry should be
74
 
# moved to bzrlib.config instead so that selftest -s bt.test_config also runs
75
 
# the plugin specific tests (selftest -s bp.xxx won't, that would be against
76
 
# the spirit of '-s') -- vila 20110503
77
 
test_store_builder_registry = registry.Registry()
78
 
test_store_builder_registry.register(
79
 
    'configobj', lambda test: config.IniFileStore(test.get_transport(),
80
 
                                                  'configobj.conf'))
81
 
test_store_builder_registry.register(
82
 
    'bazaar', lambda test: config.GlobalStore())
83
 
test_store_builder_registry.register(
84
 
    'location', lambda test: config.LocationStore())
85
 
test_store_builder_registry.register(
86
 
    'branch', lambda test: config.BranchStore(test.branch))
87
 
 
88
 
# FIXME: Same remark as above for the following registry -- vila 20110503
89
 
test_stack_builder_registry = registry.Registry()
90
 
test_stack_builder_registry.register(
91
 
    'bazaar', lambda test: config.GlobalStack())
92
 
test_stack_builder_registry.register(
93
 
    'location', lambda test: config.LocationStack('.'))
94
 
test_stack_builder_registry.register(
95
 
    'branch', lambda test: config.BranchStack(test.branch))
 
55
def load_tests(standard_tests, module, loader):
 
56
    suite = loader.suiteClass()
 
57
 
 
58
    lc_tests, remaining_tests = tests.split_suite_by_condition(
 
59
        standard_tests, tests.condition_isinstance((
 
60
                TestLockableConfig,
 
61
                )))
 
62
    tests.multiply_tests(lc_tests, lockable_config_scenarios(), suite)
 
63
    suite.addTest(remaining_tests)
 
64
    return suite
96
65
 
97
66
 
98
67
sample_long_alias="log -r-15..-1 --line"
104
73
gpg_signing_command=gnome-gpg
105
74
log_format=short
106
75
user_global_option=something
107
 
bzr.mergetool.sometool=sometool {base} {this} {other} -o {result}
108
 
bzr.mergetool.funkytool=funkytool "arg with spaces" {this_temp}
109
 
bzr.default_mergetool=sometool
110
76
[ALIASES]
111
77
h=help
112
78
ll=""" + sample_long_alias + "\n"
165
131
"""
166
132
 
167
133
 
168
 
def create_configs(test):
169
 
    """Create configuration files for a given test.
170
 
 
171
 
    This requires creating a tree (and populate the ``test.tree`` attribute)
172
 
    and its associated branch and will populate the following attributes:
173
 
 
174
 
    - branch_config: A BranchConfig for the associated branch.
175
 
 
176
 
    - locations_config : A LocationConfig for the associated branch
177
 
 
178
 
    - bazaar_config: A GlobalConfig.
179
 
 
180
 
    The tree and branch are created in a 'tree' subdirectory so the tests can
181
 
    still use the test directory to stay outside of the branch.
182
 
    """
183
 
    tree = test.make_branch_and_tree('tree')
184
 
    test.tree = tree
185
 
    test.branch_config = config.BranchConfig(tree.branch)
186
 
    test.locations_config = config.LocationConfig(tree.basedir)
187
 
    test.bazaar_config = config.GlobalConfig()
188
 
 
189
 
 
190
 
def create_configs_with_file_option(test):
191
 
    """Create configuration files with a ``file`` option set in each.
192
 
 
193
 
    This builds on ``create_configs`` and add one ``file`` option in each
194
 
    configuration with a value which allows identifying the configuration file.
195
 
    """
196
 
    create_configs(test)
197
 
    test.bazaar_config.set_user_option('file', 'bazaar')
198
 
    test.locations_config.set_user_option('file', 'locations')
199
 
    test.branch_config.set_user_option('file', 'branch')
200
 
 
201
 
 
202
 
class TestOptionsMixin:
203
 
 
204
 
    def assertOptions(self, expected, conf):
205
 
        # We don't care about the parser (as it will make tests hard to write
206
 
        # and error-prone anyway)
207
 
        self.assertThat([opt[:4] for opt in conf._get_options()],
208
 
                        matchers.Equals(expected))
209
 
 
210
 
 
211
134
class InstrumentedConfigObj(object):
212
135
    """A config obj look-enough-alike to record calls made to it."""
213
136
 
346
269
        """
347
270
        co = config.ConfigObj()
348
271
        co['test'] = 'foo#bar'
349
 
        outfile = StringIO()
350
 
        co.write(outfile=outfile)
351
 
        lines = outfile.getvalue().splitlines()
 
272
        lines = co.write()
352
273
        self.assertEqual(lines, ['test = "foo#bar"'])
353
274
        co2 = config.ConfigObj(lines)
354
275
        self.assertEqual(co2['test'], 'foo#bar')
355
276
 
356
 
    def test_triple_quotes(self):
357
 
        # Bug #710410: if the value string has triple quotes
358
 
        # then ConfigObj versions up to 4.7.2 will quote them wrong
359
 
        # and won't able to read them back
360
 
        triple_quotes_value = '''spam
361
 
""" that's my spam """
362
 
eggs'''
363
 
        co = config.ConfigObj()
364
 
        co['test'] = triple_quotes_value
365
 
        # While writing this test another bug in ConfigObj has been found:
366
 
        # method co.write() without arguments produces list of lines
367
 
        # one option per line, and multiline values are not split
368
 
        # across multiple lines,
369
 
        # and that breaks the parsing these lines back by ConfigObj.
370
 
        # This issue only affects test, but it's better to avoid
371
 
        # `co.write()` construct at all.
372
 
        # [bialix 20110222] bug report sent to ConfigObj's author
373
 
        outfile = StringIO()
374
 
        co.write(outfile=outfile)
375
 
        output = outfile.getvalue()
376
 
        # now we're trying to read it back
377
 
        co2 = config.ConfigObj(StringIO(output))
378
 
        self.assertEquals(triple_quotes_value, co2['test'])
379
 
 
380
277
 
381
278
erroneous_config = """[section] # line 1
382
279
good=good # line 2
465
362
 
466
363
    def setUp(self):
467
364
        super(TestConfigPath, self).setUp()
468
 
        self.overrideEnv('HOME', '/home/bogus')
469
 
        self.overrideEnv('XDG_CACHE_DIR', '')
 
365
        os.environ['HOME'] = '/home/bogus'
 
366
        os.environ['XDG_CACHE_DIR'] = ''
470
367
        if sys.platform == 'win32':
471
 
            self.overrideEnv(
472
 
                'BZR_HOME', r'C:\Documents and Settings\bogus\Application Data')
 
368
            os.environ['BZR_HOME'] = \
 
369
                r'C:\Documents and Settings\bogus\Application Data'
473
370
            self.bzr_home = \
474
371
                'C:/Documents and Settings/bogus/Application Data/bazaar/2.0'
475
372
        else:
495
392
            '/home/bogus/.cache')
496
393
 
497
394
 
498
 
class TestXDGConfigDir(tests.TestCaseInTempDir):
499
 
    # must be in temp dir because config tests for the existence of the bazaar
500
 
    # subdirectory of $XDG_CONFIG_HOME
501
 
 
502
 
    def setUp(self):
503
 
        if sys.platform in ('darwin', 'win32'):
504
 
            raise tests.TestNotApplicable(
505
 
                'XDG config dir not used on this platform')
506
 
        super(TestXDGConfigDir, self).setUp()
507
 
        self.overrideEnv('HOME', self.test_home_dir)
508
 
        # BZR_HOME overrides everything we want to test so unset it.
509
 
        self.overrideEnv('BZR_HOME', None)
510
 
 
511
 
    def test_xdg_config_dir_exists(self):
512
 
        """When ~/.config/bazaar exists, use it as the config dir."""
513
 
        newdir = osutils.pathjoin(self.test_home_dir, '.config', 'bazaar')
514
 
        os.makedirs(newdir)
515
 
        self.assertEqual(config.config_dir(), newdir)
516
 
 
517
 
    def test_xdg_config_home(self):
518
 
        """When XDG_CONFIG_HOME is set, use it."""
519
 
        xdgconfigdir = osutils.pathjoin(self.test_home_dir, 'xdgconfig')
520
 
        self.overrideEnv('XDG_CONFIG_HOME', xdgconfigdir)
521
 
        newdir = osutils.pathjoin(xdgconfigdir, 'bazaar')
522
 
        os.makedirs(newdir)
523
 
        self.assertEqual(config.config_dir(), newdir)
524
 
 
525
 
 
526
395
class TestIniConfig(tests.TestCaseInTempDir):
527
396
 
528
397
    def make_config_parser(self, s):
542
411
    def test_cached(self):
543
412
        my_config = config.IniBasedConfig.from_string(sample_config_text)
544
413
        parser = my_config._get_parser()
545
 
        self.assertTrue(my_config._get_parser() is parser)
 
414
        self.failUnless(my_config._get_parser() is parser)
546
415
 
547
416
    def _dummy_chown(self, path, uid, gid):
548
417
        self.path, self.uid, self.gid = path, uid, gid
573
442
            ' Use IniBasedConfig(_content=xxx) instead.'],
574
443
            conf._get_parser, file=config_file)
575
444
 
576
 
 
577
445
class TestIniConfigSaving(tests.TestCaseInTempDir):
578
446
 
579
447
    def test_cant_save_without_a_file_name(self):
587
455
        self.assertFileEqual(content, 'test.conf')
588
456
 
589
457
 
590
 
class TestIniConfigOptionExpansionDefaultValue(tests.TestCaseInTempDir):
591
 
    """What is the default value of expand for config options.
592
 
 
593
 
    This is an opt-in beta feature used to evaluate whether or not option
594
 
    references can appear in dangerous place raising exceptions, disapearing
595
 
    (and as such corrupting data) or if it's safe to activate the option by
596
 
    default.
597
 
 
598
 
    Note that these tests relies on config._expand_default_value being already
599
 
    overwritten in the parent class setUp.
600
 
    """
601
 
 
602
 
    def setUp(self):
603
 
        super(TestIniConfigOptionExpansionDefaultValue, self).setUp()
604
 
        self.config = None
605
 
        self.warnings = []
606
 
        def warning(*args):
607
 
            self.warnings.append(args[0] % args[1:])
608
 
        self.overrideAttr(trace, 'warning', warning)
609
 
 
610
 
    def get_config(self, expand):
611
 
        c = config.GlobalConfig.from_string('bzr.config.expand=%s' % (expand,),
612
 
                                            save=True)
613
 
        return c
614
 
 
615
 
    def assertExpandIs(self, expected):
616
 
        actual = config._get_expand_default_value()
617
 
        #self.config.get_user_option_as_bool('bzr.config.expand')
618
 
        self.assertEquals(expected, actual)
619
 
 
620
 
    def test_default_is_None(self):
621
 
        self.assertEquals(None, config._expand_default_value)
622
 
 
623
 
    def test_default_is_False_even_if_None(self):
624
 
        self.config = self.get_config(None)
625
 
        self.assertExpandIs(False)
626
 
 
627
 
    def test_default_is_False_even_if_invalid(self):
628
 
        self.config = self.get_config('<your choice>')
629
 
        self.assertExpandIs(False)
630
 
        # ...
631
 
        # Huh ? My choice is False ? Thanks, always happy to hear that :D
632
 
        # Wait, you've been warned !
633
 
        self.assertLength(1, self.warnings)
634
 
        self.assertEquals(
635
 
            'Value "<your choice>" is not a boolean for "bzr.config.expand"',
636
 
            self.warnings[0])
637
 
 
638
 
    def test_default_is_True(self):
639
 
        self.config = self.get_config(True)
640
 
        self.assertExpandIs(True)
641
 
        
642
 
    def test_default_is_False(self):
643
 
        self.config = self.get_config(False)
644
 
        self.assertExpandIs(False)
645
 
        
646
 
 
647
 
class TestIniConfigOptionExpansion(tests.TestCase):
648
 
    """Test option expansion from the IniConfig level.
649
 
 
650
 
    What we really want here is to test the Config level, but the class being
651
 
    abstract as far as storing values is concerned, this can't be done
652
 
    properly (yet).
653
 
    """
654
 
    # FIXME: This should be rewritten when all configs share a storage
655
 
    # implementation -- vila 2011-02-18
656
 
 
657
 
    def get_config(self, string=None):
658
 
        if string is None:
659
 
            string = ''
660
 
        c = config.IniBasedConfig.from_string(string)
661
 
        return c
662
 
 
663
 
    def assertExpansion(self, expected, conf, string, env=None):
664
 
        self.assertEquals(expected, conf.expand_options(string, env))
665
 
 
666
 
    def test_no_expansion(self):
667
 
        c = self.get_config('')
668
 
        self.assertExpansion('foo', c, 'foo')
669
 
 
670
 
    def test_env_adding_options(self):
671
 
        c = self.get_config('')
672
 
        self.assertExpansion('bar', c, '{foo}', {'foo': 'bar'})
673
 
 
674
 
    def test_env_overriding_options(self):
675
 
        c = self.get_config('foo=baz')
676
 
        self.assertExpansion('bar', c, '{foo}', {'foo': 'bar'})
677
 
 
678
 
    def test_simple_ref(self):
679
 
        c = self.get_config('foo=xxx')
680
 
        self.assertExpansion('xxx', c, '{foo}')
681
 
 
682
 
    def test_unknown_ref(self):
683
 
        c = self.get_config('')
684
 
        self.assertRaises(errors.ExpandingUnknownOption,
685
 
                          c.expand_options, '{foo}')
686
 
 
687
 
    def test_indirect_ref(self):
688
 
        c = self.get_config('''
689
 
foo=xxx
690
 
bar={foo}
691
 
''')
692
 
        self.assertExpansion('xxx', c, '{bar}')
693
 
 
694
 
    def test_embedded_ref(self):
695
 
        c = self.get_config('''
696
 
foo=xxx
697
 
bar=foo
698
 
''')
699
 
        self.assertExpansion('xxx', c, '{{bar}}')
700
 
 
701
 
    def test_simple_loop(self):
702
 
        c = self.get_config('foo={foo}')
703
 
        self.assertRaises(errors.OptionExpansionLoop, c.expand_options, '{foo}')
704
 
 
705
 
    def test_indirect_loop(self):
706
 
        c = self.get_config('''
707
 
foo={bar}
708
 
bar={baz}
709
 
baz={foo}''')
710
 
        e = self.assertRaises(errors.OptionExpansionLoop,
711
 
                              c.expand_options, '{foo}')
712
 
        self.assertEquals('foo->bar->baz', e.refs)
713
 
        self.assertEquals('{foo}', e.string)
714
 
 
715
 
    def test_list(self):
716
 
        conf = self.get_config('''
717
 
foo=start
718
 
bar=middle
719
 
baz=end
720
 
list={foo},{bar},{baz}
721
 
''')
722
 
        self.assertEquals(['start', 'middle', 'end'],
723
 
                           conf.get_user_option('list', expand=True))
724
 
 
725
 
    def test_cascading_list(self):
726
 
        conf = self.get_config('''
727
 
foo=start,{bar}
728
 
bar=middle,{baz}
729
 
baz=end
730
 
list={foo}
731
 
''')
732
 
        self.assertEquals(['start', 'middle', 'end'],
733
 
                           conf.get_user_option('list', expand=True))
734
 
 
735
 
    def test_pathological_hidden_list(self):
736
 
        conf = self.get_config('''
737
 
foo=bin
738
 
bar=go
739
 
start={foo
740
 
middle=},{
741
 
end=bar}
742
 
hidden={start}{middle}{end}
743
 
''')
744
 
        # Nope, it's either a string or a list, and the list wins as soon as a
745
 
        # ',' appears, so the string concatenation never occur.
746
 
        self.assertEquals(['{foo', '}', '{', 'bar}'],
747
 
                          conf.get_user_option('hidden', expand=True))
748
 
 
749
 
class TestLocationConfigOptionExpansion(tests.TestCaseInTempDir):
750
 
 
751
 
    def get_config(self, location, string=None):
752
 
        if string is None:
753
 
            string = ''
754
 
        # Since we don't save the config we won't strictly require to inherit
755
 
        # from TestCaseInTempDir, but an error occurs so quickly...
756
 
        c = config.LocationConfig.from_string(string, location)
757
 
        return c
758
 
 
759
 
    def test_dont_cross_unrelated_section(self):
760
 
        c = self.get_config('/another/branch/path','''
761
 
[/one/branch/path]
762
 
foo = hello
763
 
bar = {foo}/2
764
 
 
765
 
[/another/branch/path]
766
 
bar = {foo}/2
767
 
''')
768
 
        self.assertRaises(errors.ExpandingUnknownOption,
769
 
                          c.get_user_option, 'bar', expand=True)
770
 
 
771
 
    def test_cross_related_sections(self):
772
 
        c = self.get_config('/project/branch/path','''
773
 
[/project]
774
 
foo = qu
775
 
 
776
 
[/project/branch/path]
777
 
bar = {foo}ux
778
 
''')
779
 
        self.assertEquals('quux', c.get_user_option('bar', expand=True))
780
 
 
781
 
 
782
458
class TestIniBaseConfigOnDisk(tests.TestCaseInTempDir):
783
459
 
784
460
    def test_cannot_reload_without_name(self):
801
477
 
802
478
class TestLockableConfig(tests.TestCaseInTempDir):
803
479
 
804
 
    scenarios = lockable_config_scenarios()
805
 
 
806
480
    # Set by load_tests
807
481
    config_class = None
808
482
    config_args = None
864
538
        def c1_write_config_file():
865
539
            before_writing.set()
866
540
            c1_orig()
867
 
            # The lock is held. We wait for the main thread to decide when to
 
541
            # The lock is held we wait for the main thread to decide when to
868
542
            # continue
869
543
            after_writing.wait()
870
544
        c1._write_config_file = c1_write_config_file
897
571
       c1_orig = c1._write_config_file
898
572
       def c1_write_config_file():
899
573
           ready_to_write.set()
900
 
           # The lock is held. We wait for the main thread to decide when to
 
574
           # The lock is held we wait for the main thread to decide when to
901
575
           # continue
902
576
           do_writing.wait()
903
577
           c1_orig()
994
668
            parser = my_config._get_parser()
995
669
        finally:
996
670
            config.ConfigObj = oldparserclass
997
 
        self.assertIsInstance(parser, InstrumentedConfigObj)
 
671
        self.failUnless(isinstance(parser, InstrumentedConfigObj))
998
672
        self.assertEqual(parser._calls, [('__init__', config.config_filename(),
999
673
                                          'utf-8')])
1000
674
 
1011
685
        my_config = config.BranchConfig(branch)
1012
686
        location_config = my_config._get_location_config()
1013
687
        self.assertEqual(branch.base, location_config.location)
1014
 
        self.assertIs(location_config, my_config._get_location_config())
 
688
        self.failUnless(location_config is my_config._get_location_config())
1015
689
 
1016
690
    def test_get_config(self):
1017
691
        """The Branch.get_config method works properly"""
1104
778
        assertWarning(None)
1105
779
 
1106
780
 
1107
 
class TestGlobalConfigItems(tests.TestCaseInTempDir):
 
781
class TestGlobalConfigItems(tests.TestCase):
1108
782
 
1109
783
    def test_user_id(self):
1110
784
        my_config = config.GlobalConfig.from_string(sample_config_text)
1209
883
        change_editor = my_config.get_change_editor('old', 'new')
1210
884
        self.assertIs(None, change_editor)
1211
885
 
1212
 
    def test_get_merge_tools(self):
1213
 
        conf = self._get_sample_config()
1214
 
        tools = conf.get_merge_tools()
1215
 
        self.log(repr(tools))
1216
 
        self.assertEqual(
1217
 
            {u'funkytool' : u'funkytool "arg with spaces" {this_temp}',
1218
 
            u'sometool' : u'sometool {base} {this} {other} -o {result}'},
1219
 
            tools)
1220
 
 
1221
 
    def test_get_merge_tools_empty(self):
1222
 
        conf = self._get_empty_config()
1223
 
        tools = conf.get_merge_tools()
1224
 
        self.assertEqual({}, tools)
1225
 
 
1226
 
    def test_find_merge_tool(self):
1227
 
        conf = self._get_sample_config()
1228
 
        cmdline = conf.find_merge_tool('sometool')
1229
 
        self.assertEqual('sometool {base} {this} {other} -o {result}', cmdline)
1230
 
 
1231
 
    def test_find_merge_tool_not_found(self):
1232
 
        conf = self._get_sample_config()
1233
 
        cmdline = conf.find_merge_tool('DOES NOT EXIST')
1234
 
        self.assertIs(cmdline, None)
1235
 
 
1236
 
    def test_find_merge_tool_known(self):
1237
 
        conf = self._get_empty_config()
1238
 
        cmdline = conf.find_merge_tool('kdiff3')
1239
 
        self.assertEquals('kdiff3 {base} {this} {other} -o {result}', cmdline)
1240
 
 
1241
 
    def test_find_merge_tool_override_known(self):
1242
 
        conf = self._get_empty_config()
1243
 
        conf.set_user_option('bzr.mergetool.kdiff3', 'kdiff3 blah')
1244
 
        cmdline = conf.find_merge_tool('kdiff3')
1245
 
        self.assertEqual('kdiff3 blah', cmdline)
1246
 
 
1247
886
 
1248
887
class TestGlobalConfigSavingOptions(tests.TestCaseInTempDir):
1249
888
 
1267
906
        self.assertIs(None, new_config.get_alias('commit'))
1268
907
 
1269
908
 
1270
 
class TestLocationConfig(tests.TestCaseInTempDir, TestOptionsMixin):
 
909
class TestLocationConfig(tests.TestCaseInTempDir):
1271
910
 
1272
911
    def test_constructs(self):
1273
912
        my_config = config.LocationConfig('http://example.com')
1285
924
            parser = my_config._get_parser()
1286
925
        finally:
1287
926
            config.ConfigObj = oldparserclass
1288
 
        self.assertIsInstance(parser, InstrumentedConfigObj)
 
927
        self.failUnless(isinstance(parser, InstrumentedConfigObj))
1289
928
        self.assertEqual(parser._calls,
1290
929
                         [('__init__', config.locations_config_filename(),
1291
930
                           'utf-8')])
1293
932
    def test_get_global_config(self):
1294
933
        my_config = config.BranchConfig(FakeBranch('http://example.com'))
1295
934
        global_config = my_config._get_global_config()
1296
 
        self.assertIsInstance(global_config, config.GlobalConfig)
1297
 
        self.assertIs(global_config, my_config._get_global_config())
1298
 
 
1299
 
    def assertLocationMatching(self, expected):
1300
 
        self.assertEqual(expected,
1301
 
                         list(self.my_location_config._get_matching_sections()))
 
935
        self.failUnless(isinstance(global_config, config.GlobalConfig))
 
936
        self.failUnless(global_config is my_config._get_global_config())
1302
937
 
1303
938
    def test__get_matching_sections_no_match(self):
1304
939
        self.get_branch_config('/')
1305
 
        self.assertLocationMatching([])
 
940
        self.assertEqual([], self.my_location_config._get_matching_sections())
1306
941
 
1307
942
    def test__get_matching_sections_exact(self):
1308
943
        self.get_branch_config('http://www.example.com')
1309
 
        self.assertLocationMatching([('http://www.example.com', '')])
 
944
        self.assertEqual([('http://www.example.com', '')],
 
945
                         self.my_location_config._get_matching_sections())
1310
946
 
1311
947
    def test__get_matching_sections_suffix_does_not(self):
1312
948
        self.get_branch_config('http://www.example.com-com')
1313
 
        self.assertLocationMatching([])
 
949
        self.assertEqual([], self.my_location_config._get_matching_sections())
1314
950
 
1315
951
    def test__get_matching_sections_subdir_recursive(self):
1316
952
        self.get_branch_config('http://www.example.com/com')
1317
 
        self.assertLocationMatching([('http://www.example.com', 'com')])
 
953
        self.assertEqual([('http://www.example.com', 'com')],
 
954
                         self.my_location_config._get_matching_sections())
1318
955
 
1319
956
    def test__get_matching_sections_ignoreparent(self):
1320
957
        self.get_branch_config('http://www.example.com/ignoreparent')
1321
 
        self.assertLocationMatching([('http://www.example.com/ignoreparent',
1322
 
                                      '')])
 
958
        self.assertEqual([('http://www.example.com/ignoreparent', '')],
 
959
                         self.my_location_config._get_matching_sections())
1323
960
 
1324
961
    def test__get_matching_sections_ignoreparent_subdir(self):
1325
962
        self.get_branch_config(
1326
963
            'http://www.example.com/ignoreparent/childbranch')
1327
 
        self.assertLocationMatching([('http://www.example.com/ignoreparent',
1328
 
                                      'childbranch')])
 
964
        self.assertEqual([('http://www.example.com/ignoreparent',
 
965
                           'childbranch')],
 
966
                         self.my_location_config._get_matching_sections())
1329
967
 
1330
968
    def test__get_matching_sections_subdir_trailing_slash(self):
1331
969
        self.get_branch_config('/b')
1332
 
        self.assertLocationMatching([('/b/', '')])
 
970
        self.assertEqual([('/b/', '')],
 
971
                         self.my_location_config._get_matching_sections())
1333
972
 
1334
973
    def test__get_matching_sections_subdir_child(self):
1335
974
        self.get_branch_config('/a/foo')
1336
 
        self.assertLocationMatching([('/a/*', ''), ('/a/', 'foo')])
 
975
        self.assertEqual([('/a/*', ''), ('/a/', 'foo')],
 
976
                         self.my_location_config._get_matching_sections())
1337
977
 
1338
978
    def test__get_matching_sections_subdir_child_child(self):
1339
979
        self.get_branch_config('/a/foo/bar')
1340
 
        self.assertLocationMatching([('/a/*', 'bar'), ('/a/', 'foo/bar')])
 
980
        self.assertEqual([('/a/*', 'bar'), ('/a/', 'foo/bar')],
 
981
                         self.my_location_config._get_matching_sections())
1341
982
 
1342
983
    def test__get_matching_sections_trailing_slash_with_children(self):
1343
984
        self.get_branch_config('/a/')
1344
 
        self.assertLocationMatching([('/a/', '')])
 
985
        self.assertEqual([('/a/', '')],
 
986
                         self.my_location_config._get_matching_sections())
1345
987
 
1346
988
    def test__get_matching_sections_explicit_over_glob(self):
1347
989
        # XXX: 2006-09-08 jamesh
1349
991
        # was a config section for '/a/?', it would get precedence
1350
992
        # over '/a/c'.
1351
993
        self.get_branch_config('/a/c')
1352
 
        self.assertLocationMatching([('/a/c', ''), ('/a/*', ''), ('/a/', 'c')])
 
994
        self.assertEqual([('/a/c', ''), ('/a/*', ''), ('/a/', 'c')],
 
995
                         self.my_location_config._get_matching_sections())
1353
996
 
1354
997
    def test__get_option_policy_normal(self):
1355
998
        self.get_branch_config('http://www.example.com')
1377
1020
            'http://www.example.com', 'appendpath_option'),
1378
1021
            config.POLICY_APPENDPATH)
1379
1022
 
1380
 
    def test__get_options_with_policy(self):
1381
 
        self.get_branch_config('/dir/subdir',
1382
 
                               location_config="""\
1383
 
[/dir]
1384
 
other_url = /other-dir
1385
 
other_url:policy = appendpath
1386
 
[/dir/subdir]
1387
 
other_url = /other-subdir
1388
 
""")
1389
 
        self.assertOptions(
1390
 
            [(u'other_url', u'/other-subdir', u'/dir/subdir', 'locations'),
1391
 
             (u'other_url', u'/other-dir', u'/dir', 'locations'),
1392
 
             (u'other_url:policy', u'appendpath', u'/dir', 'locations')],
1393
 
            self.my_location_config)
1394
 
 
1395
1023
    def test_location_without_username(self):
1396
1024
        self.get_branch_config('http://www.example.com/ignoreparent')
1397
1025
        self.assertEqual(u'Erik B\u00e5gfors <erik@bagfors.nu>',
1533
1161
        self.assertEqual('bzrlib.tests.test_config.post_commit',
1534
1162
                         self.my_config.post_commit())
1535
1163
 
1536
 
    def get_branch_config(self, location, global_config=None,
1537
 
                          location_config=None):
 
1164
    def get_branch_config(self, location, global_config=None):
1538
1165
        my_branch = FakeBranch(location)
1539
1166
        if global_config is None:
1540
1167
            global_config = sample_config_text
1541
 
        if location_config is None:
1542
 
            location_config = sample_branches_text
1543
1168
 
1544
1169
        my_global_config = config.GlobalConfig.from_string(global_config,
1545
1170
                                                           save=True)
1546
1171
        my_location_config = config.LocationConfig.from_string(
1547
 
            location_config, my_branch.base, save=True)
 
1172
            sample_branches_text, my_branch.base, save=True)
1548
1173
        my_config = config.BranchConfig(my_branch)
1549
1174
        self.my_config = my_config
1550
1175
        self.my_location_config = my_config._get_location_config()
1595
1220
        self.assertEqual('bzr', my_config.get_bzr_remote_path())
1596
1221
        my_config.set_user_option('bzr_remote_path', '/path-bzr')
1597
1222
        self.assertEqual('/path-bzr', my_config.get_bzr_remote_path())
1598
 
        self.overrideEnv('BZR_REMOTE_PATH', '/environ-bzr')
 
1223
        os.environ['BZR_REMOTE_PATH'] = '/environ-bzr'
1599
1224
        self.assertEqual('/environ-bzr', my_config.get_bzr_remote_path())
1600
1225
 
1601
1226
 
1647
1272
        self.assertEqual("John", my_config._get_user_id())
1648
1273
 
1649
1274
    def test_BZR_EMAIL_OVERRIDES(self):
1650
 
        self.overrideEnv('BZR_EMAIL', "Robert Collins <robertc@example.org>")
 
1275
        os.environ['BZR_EMAIL'] = "Robert Collins <robertc@example.org>"
1651
1276
        branch = FakeBranch()
1652
1277
        my_config = config.BranchConfig(branch)
1653
1278
        self.assertEqual("Robert Collins <robertc@example.org>",
1846
1471
        self.assertIs(None, bzrdir_config.get_default_stack_on())
1847
1472
 
1848
1473
 
1849
 
class TestSection(tests.TestCase):
1850
 
 
1851
 
    # FIXME: Parametrize so that all sections produced by Stores run these
1852
 
    # tests -- vila 2011-04-01
1853
 
 
1854
 
    def test_get_a_value(self):
1855
 
        a_dict = dict(foo='bar')
1856
 
        section = config.Section('myID', a_dict)
1857
 
        self.assertEquals('bar', section.get('foo'))
1858
 
 
1859
 
    def test_get_unknown_option(self):
1860
 
        a_dict = dict()
1861
 
        section = config.Section(None, a_dict)
1862
 
        self.assertEquals('out of thin air',
1863
 
                          section.get('foo', 'out of thin air'))
1864
 
 
1865
 
    def test_options_is_shared(self):
1866
 
        a_dict = dict()
1867
 
        section = config.Section(None, a_dict)
1868
 
        self.assertIs(a_dict, section.options)
1869
 
 
1870
 
 
1871
 
class TestMutableSection(tests.TestCase):
1872
 
 
1873
 
    # FIXME: Parametrize so that all sections (including os.environ and the
1874
 
    # ones produced by Stores) run these tests -- vila 2011-04-01
1875
 
 
1876
 
    def test_set(self):
1877
 
        a_dict = dict(foo='bar')
1878
 
        section = config.MutableSection('myID', a_dict)
1879
 
        section.set('foo', 'new_value')
1880
 
        self.assertEquals('new_value', section.get('foo'))
1881
 
        # The change appears in the shared section
1882
 
        self.assertEquals('new_value', a_dict.get('foo'))
1883
 
        # We keep track of the change
1884
 
        self.assertTrue('foo' in section.orig)
1885
 
        self.assertEquals('bar', section.orig.get('foo'))
1886
 
 
1887
 
    def test_set_preserve_original_once(self):
1888
 
        a_dict = dict(foo='bar')
1889
 
        section = config.MutableSection('myID', a_dict)
1890
 
        section.set('foo', 'first_value')
1891
 
        section.set('foo', 'second_value')
1892
 
        # We keep track of the original value
1893
 
        self.assertTrue('foo' in section.orig)
1894
 
        self.assertEquals('bar', section.orig.get('foo'))
1895
 
 
1896
 
    def test_remove(self):
1897
 
        a_dict = dict(foo='bar')
1898
 
        section = config.MutableSection('myID', a_dict)
1899
 
        section.remove('foo')
1900
 
        # We get None for unknown options via the default value
1901
 
        self.assertEquals(None, section.get('foo'))
1902
 
        # Or we just get the default value
1903
 
        self.assertEquals('unknown', section.get('foo', 'unknown'))
1904
 
        self.assertFalse('foo' in section.options)
1905
 
        # We keep track of the deletion
1906
 
        self.assertTrue('foo' in section.orig)
1907
 
        self.assertEquals('bar', section.orig.get('foo'))
1908
 
 
1909
 
    def test_remove_new_option(self):
1910
 
        a_dict = dict()
1911
 
        section = config.MutableSection('myID', a_dict)
1912
 
        section.set('foo', 'bar')
1913
 
        section.remove('foo')
1914
 
        self.assertFalse('foo' in section.options)
1915
 
        # The option didn't exist initially so it we need to keep track of it
1916
 
        # with a special value
1917
 
        self.assertTrue('foo' in section.orig)
1918
 
        self.assertEquals(config._NewlyCreatedOption, section.orig['foo'])
1919
 
 
1920
 
 
1921
 
class TestStore(tests.TestCaseWithTransport):
1922
 
 
1923
 
    def assertSectionContent(self, expected, section):
1924
 
        """Assert that some options have the proper values in a section."""
1925
 
        expected_name, expected_options = expected
1926
 
        self.assertEquals(expected_name, section.id)
1927
 
        self.assertEquals(
1928
 
            expected_options,
1929
 
            dict([(k, section.get(k)) for k in expected_options.keys()]))
1930
 
 
1931
 
 
1932
 
class TestReadonlyStore(TestStore):
1933
 
 
1934
 
    scenarios = [(key, {'get_store': builder})
1935
 
                 for key, builder in test_store_builder_registry.iteritems()]
1936
 
 
1937
 
    def setUp(self):
1938
 
        super(TestReadonlyStore, self).setUp()
1939
 
        self.branch = self.make_branch('branch')
1940
 
 
1941
 
    def test_building_delays_load(self):
1942
 
        store = self.get_store(self)
1943
 
        self.assertEquals(False, store.is_loaded())
1944
 
        store._load_from_string('')
1945
 
        self.assertEquals(True, store.is_loaded())
1946
 
 
1947
 
    def test_get_no_sections_for_empty(self):
1948
 
        store = self.get_store(self)
1949
 
        store._load_from_string('')
1950
 
        self.assertEquals([], list(store.get_sections()))
1951
 
 
1952
 
    def test_get_default_section(self):
1953
 
        store = self.get_store(self)
1954
 
        store._load_from_string('foo=bar')
1955
 
        sections = list(store.get_sections())
1956
 
        self.assertLength(1, sections)
1957
 
        self.assertSectionContent((None, {'foo': 'bar'}), sections[0])
1958
 
 
1959
 
    def test_get_named_section(self):
1960
 
        store = self.get_store(self)
1961
 
        store._load_from_string('[baz]\nfoo=bar')
1962
 
        sections = list(store.get_sections())
1963
 
        self.assertLength(1, sections)
1964
 
        self.assertSectionContent(('baz', {'foo': 'bar'}), sections[0])
1965
 
 
1966
 
    def test_load_from_string_fails_for_non_empty_store(self):
1967
 
        store = self.get_store(self)
1968
 
        store._load_from_string('foo=bar')
1969
 
        self.assertRaises(AssertionError, store._load_from_string, 'bar=baz')
1970
 
 
1971
 
 
1972
 
class TestMutableStore(TestStore):
1973
 
 
1974
 
    scenarios = [(key, {'store_id': key, 'get_store': builder})
1975
 
                 for key, builder in test_store_builder_registry.iteritems()]
1976
 
 
1977
 
    def setUp(self):
1978
 
        super(TestMutableStore, self).setUp()
1979
 
        self.transport = self.get_transport()
1980
 
        self.branch = self.make_branch('branch')
1981
 
 
1982
 
    def has_store(self, store):
1983
 
        store_basename = urlutils.relative_url(self.transport.external_url(),
1984
 
                                               store.external_url())
1985
 
        return self.transport.has(store_basename)
1986
 
 
1987
 
    def test_save_empty_creates_no_file(self):
1988
 
        if self.store_id == 'branch':
1989
 
            raise tests.TestNotApplicable(
1990
 
                'branch.conf is *always* created when a branch is initialized')
1991
 
        store = self.get_store(self)
1992
 
        store.save()
1993
 
        self.assertEquals(False, self.has_store(store))
1994
 
 
1995
 
    def test_save_emptied_succeeds(self):
1996
 
        store = self.get_store(self)
1997
 
        store._load_from_string('foo=bar\n')
1998
 
        section = store.get_mutable_section(None)
1999
 
        section.remove('foo')
2000
 
        store.save()
2001
 
        self.assertEquals(True, self.has_store(store))
2002
 
        modified_store = self.get_store(self)
2003
 
        sections = list(modified_store.get_sections())
2004
 
        self.assertLength(0, sections)
2005
 
 
2006
 
    def test_save_with_content_succeeds(self):
2007
 
        if self.store_id == 'branch':
2008
 
            raise tests.TestNotApplicable(
2009
 
                'branch.conf is *always* created when a branch is initialized')
2010
 
        store = self.get_store(self)
2011
 
        store._load_from_string('foo=bar\n')
2012
 
        self.assertEquals(False, self.has_store(store))
2013
 
        store.save()
2014
 
        self.assertEquals(True, self.has_store(store))
2015
 
        modified_store = self.get_store(self)
2016
 
        sections = list(modified_store.get_sections())
2017
 
        self.assertLength(1, sections)
2018
 
        self.assertSectionContent((None, {'foo': 'bar'}), sections[0])
2019
 
 
2020
 
    def test_set_option_in_empty_store(self):
2021
 
        store = self.get_store(self)
2022
 
        section = store.get_mutable_section(None)
2023
 
        section.set('foo', 'bar')
2024
 
        store.save()
2025
 
        modified_store = self.get_store(self)
2026
 
        sections = list(modified_store.get_sections())
2027
 
        self.assertLength(1, sections)
2028
 
        self.assertSectionContent((None, {'foo': 'bar'}), sections[0])
2029
 
 
2030
 
    def test_set_option_in_default_section(self):
2031
 
        store = self.get_store(self)
2032
 
        store._load_from_string('')
2033
 
        section = store.get_mutable_section(None)
2034
 
        section.set('foo', 'bar')
2035
 
        store.save()
2036
 
        modified_store = self.get_store(self)
2037
 
        sections = list(modified_store.get_sections())
2038
 
        self.assertLength(1, sections)
2039
 
        self.assertSectionContent((None, {'foo': 'bar'}), sections[0])
2040
 
 
2041
 
    def test_set_option_in_named_section(self):
2042
 
        store = self.get_store(self)
2043
 
        store._load_from_string('')
2044
 
        section = store.get_mutable_section('baz')
2045
 
        section.set('foo', 'bar')
2046
 
        store.save()
2047
 
        modified_store = self.get_store(self)
2048
 
        sections = list(modified_store.get_sections())
2049
 
        self.assertLength(1, sections)
2050
 
        self.assertSectionContent(('baz', {'foo': 'bar'}), sections[0])
2051
 
 
2052
 
 
2053
 
class TestIniFileStore(TestStore):
2054
 
 
2055
 
    def test_loading_unknown_file_fails(self):
2056
 
        store = config.IniFileStore(self.get_transport(), 'I-do-not-exist')
2057
 
        self.assertRaises(errors.NoSuchFile, store.load)
2058
 
 
2059
 
    def test_invalid_content(self):
2060
 
        store = config.IniFileStore(self.get_transport(), 'foo.conf', )
2061
 
        self.assertEquals(False, store.is_loaded())
2062
 
        exc = self.assertRaises(
2063
 
            errors.ParseConfigError, store._load_from_string,
2064
 
            'this is invalid !')
2065
 
        self.assertEndsWith(exc.filename, 'foo.conf')
2066
 
        # And the load failed
2067
 
        self.assertEquals(False, store.is_loaded())
2068
 
 
2069
 
    def test_get_embedded_sections(self):
2070
 
        # A more complicated example (which also shows that section names and
2071
 
        # option names share the same name space...)
2072
 
        # FIXME: This should be fixed by forbidding dicts as values ?
2073
 
        # -- vila 2011-04-05
2074
 
        store = config.IniFileStore(self.get_transport(), 'foo.conf', )
2075
 
        store._load_from_string('''
2076
 
foo=bar
2077
 
l=1,2
2078
 
[DEFAULT]
2079
 
foo_in_DEFAULT=foo_DEFAULT
2080
 
[bar]
2081
 
foo_in_bar=barbar
2082
 
[baz]
2083
 
foo_in_baz=barbaz
2084
 
[[qux]]
2085
 
foo_in_qux=quux
2086
 
''')
2087
 
        sections = list(store.get_sections())
2088
 
        self.assertLength(4, sections)
2089
 
        # The default section has no name.
2090
 
        # List values are provided as lists
2091
 
        self.assertSectionContent((None, {'foo': 'bar', 'l': ['1', '2']}),
2092
 
                                  sections[0])
2093
 
        self.assertSectionContent(
2094
 
            ('DEFAULT', {'foo_in_DEFAULT': 'foo_DEFAULT'}), sections[1])
2095
 
        self.assertSectionContent(
2096
 
            ('bar', {'foo_in_bar': 'barbar'}), sections[2])
2097
 
        # sub sections are provided as embedded dicts.
2098
 
        self.assertSectionContent(
2099
 
            ('baz', {'foo_in_baz': 'barbaz', 'qux': {'foo_in_qux': 'quux'}}),
2100
 
            sections[3])
2101
 
 
2102
 
 
2103
 
class TestLockableIniFileStore(TestStore):
2104
 
 
2105
 
    def test_create_store_in_created_dir(self):
2106
 
        t = self.get_transport('dir/subdir')
2107
 
        store = config.LockableIniFileStore(t, 'foo.conf')
2108
 
        store.get_mutable_section(None).set('foo', 'bar')
2109
 
        store.save()
2110
 
 
2111
 
    # FIXME: We should adapt the tests in TestLockableConfig about concurrent
2112
 
    # writes. Since this requires a clearer rewrite, I'll just rely on using
2113
 
    # the same code in LockableIniFileStore (copied from LockableConfig, but
2114
 
    # trivial enough, the main difference is that we add @needs_write_lock on
2115
 
    # save() instead of set_user_option() and remove_user_option()). The intent
2116
 
    # is to ensure that we always get a valid content for the store even when
2117
 
    # concurrent accesses occur, read/write, write/write. It may be worth
2118
 
    # looking into removing the lock dir when it;s not needed anymore and look
2119
 
    # at possible fallouts for concurrent lockers -- vila 20110-04-06
2120
 
 
2121
 
 
2122
 
class TestSectionMatcher(TestStore):
2123
 
 
2124
 
    scenarios = [('location', {'matcher': config.LocationMatcher})]
2125
 
 
2126
 
    def get_store(self, file_name):
2127
 
        return config.IniFileStore(self.get_readonly_transport(), file_name)
2128
 
 
2129
 
    def test_no_matches_for_empty_stores(self):
2130
 
        store = self.get_store('foo.conf')
2131
 
        store._load_from_string('')
2132
 
        matcher = self.matcher(store, '/bar')
2133
 
        self.assertEquals([], list(matcher.get_sections()))
2134
 
 
2135
 
    def test_build_doesnt_load_store(self):
2136
 
        store = self.get_store('foo.conf')
2137
 
        matcher = self.matcher(store, '/bar')
2138
 
        self.assertFalse(store.is_loaded())
2139
 
 
2140
 
 
2141
 
class TestLocationSection(tests.TestCase):
2142
 
 
2143
 
    def get_section(self, options, extra_path):
2144
 
        section = config.Section('foo', options)
2145
 
        # We don't care about the length so we use '0'
2146
 
        return config.LocationSection(section, 0, extra_path)
2147
 
 
2148
 
    def test_simple_option(self):
2149
 
        section = self.get_section({'foo': 'bar'}, '')
2150
 
        self.assertEquals('bar', section.get('foo'))
2151
 
 
2152
 
    def test_option_with_extra_path(self):
2153
 
        section = self.get_section({'foo': 'bar', 'foo:policy': 'appendpath'},
2154
 
                                   'baz')
2155
 
        self.assertEquals('bar/baz', section.get('foo'))
2156
 
 
2157
 
    def test_invalid_policy(self):
2158
 
        section = self.get_section({'foo': 'bar', 'foo:policy': 'die'},
2159
 
                                   'baz')
2160
 
        # invalid policies are ignored
2161
 
        self.assertEquals('bar', section.get('foo'))
2162
 
 
2163
 
 
2164
 
class TestLocationMatcher(TestStore):
2165
 
 
2166
 
    def get_store(self, file_name):
2167
 
        return config.IniFileStore(self.get_readonly_transport(), file_name)
2168
 
 
2169
 
    def test_more_specific_sections_first(self):
2170
 
        store = self.get_store('foo.conf')
2171
 
        store._load_from_string('''
2172
 
[/foo]
2173
 
section=/foo
2174
 
[/foo/bar]
2175
 
section=/foo/bar
2176
 
''')
2177
 
        self.assertEquals(['/foo', '/foo/bar'],
2178
 
                          [section.id for section in store.get_sections()])
2179
 
        matcher = config.LocationMatcher(store, '/foo/bar/baz')
2180
 
        sections = list(matcher.get_sections())
2181
 
        self.assertEquals([3, 2],
2182
 
                          [section.length for section in sections])
2183
 
        self.assertEquals(['/foo/bar', '/foo'],
2184
 
                          [section.id for section in sections])
2185
 
        self.assertEquals(['baz', 'bar/baz'],
2186
 
                          [section.extra_path for section in sections])
2187
 
 
2188
 
    def test_appendpath_in_no_name_section(self):
2189
 
        # It's a bit weird to allow appendpath in a no-name section, but
2190
 
        # someone may found a use for it
2191
 
        store = self.get_store('foo.conf')
2192
 
        store._load_from_string('''
2193
 
foo=bar
2194
 
foo:policy = appendpath
2195
 
''')
2196
 
        matcher = config.LocationMatcher(store, 'dir/subdir')
2197
 
        sections = list(matcher.get_sections())
2198
 
        self.assertLength(1, sections)
2199
 
        self.assertEquals('bar/dir/subdir', sections[0].get('foo'))
2200
 
 
2201
 
    def test_file_urls_are_normalized(self):
2202
 
        store = self.get_store('foo.conf')
2203
 
        if sys.platform == 'win32':
2204
 
            expected_url = 'file:///C:/dir/subdir'
2205
 
            expected_location = 'C:/dir/subdir'
2206
 
        else:
2207
 
            expected_url = 'file:///dir/subdir'
2208
 
            expected_location = '/dir/subdir'
2209
 
        matcher = config.LocationMatcher(store, expected_url)
2210
 
        self.assertEquals(expected_location, matcher.location)
2211
 
 
2212
 
 
2213
 
class TestStackGet(tests.TestCase):
2214
 
 
2215
 
    # FIXME: This should be parametrized for all known Stack or dedicated
2216
 
    # paramerized tests created to avoid bloating -- vila 2011-03-31
2217
 
 
2218
 
    def test_single_config_get(self):
2219
 
        conf = dict(foo='bar')
2220
 
        conf_stack = config.Stack([conf])
2221
 
        self.assertEquals('bar', conf_stack.get('foo'))
2222
 
 
2223
 
    def test_get_first_definition(self):
2224
 
        conf1 = dict(foo='bar')
2225
 
        conf2 = dict(foo='baz')
2226
 
        conf_stack = config.Stack([conf1, conf2])
2227
 
        self.assertEquals('bar', conf_stack.get('foo'))
2228
 
 
2229
 
    def test_get_embedded_definition(self):
2230
 
        conf1 = dict(yy='12')
2231
 
        conf2 = config.Stack([dict(xx='42'), dict(foo='baz')])
2232
 
        conf_stack = config.Stack([conf1, conf2])
2233
 
        self.assertEquals('baz', conf_stack.get('foo'))
2234
 
 
2235
 
    def test_get_for_empty_stack(self):
2236
 
        conf_stack = config.Stack([])
2237
 
        self.assertEquals(None, conf_stack.get('foo'))
2238
 
 
2239
 
    def test_get_for_empty_section_callable(self):
2240
 
        conf_stack = config.Stack([lambda : []])
2241
 
        self.assertEquals(None, conf_stack.get('foo'))
2242
 
 
2243
 
    def test_get_for_broken_callable(self):
2244
 
        # Trying to use and invalid callable raises an exception on first use
2245
 
        conf_stack = config.Stack([lambda : object()])
2246
 
        self.assertRaises(TypeError, conf_stack.get, 'foo')
2247
 
 
2248
 
 
2249
 
class TestStackWithTransport(tests.TestCaseWithTransport):
2250
 
 
2251
 
    def setUp(self):
2252
 
        super(TestStackWithTransport, self).setUp()
2253
 
        # FIXME: A more elaborate builder for the stack would avoid building a
2254
 
        # branch even for tests that don't need it.
2255
 
        self.branch = self.make_branch('branch')
2256
 
 
2257
 
 
2258
 
class TestStackSet(TestStackWithTransport):
2259
 
 
2260
 
    scenarios = [(key, {'get_stack': builder})
2261
 
                 for key, builder in test_stack_builder_registry.iteritems()]
2262
 
 
2263
 
    def test_simple_set(self):
2264
 
        conf = self.get_stack(self)
2265
 
        conf.store._load_from_string('foo=bar')
2266
 
        self.assertEquals('bar', conf.get('foo'))
2267
 
        conf.set('foo', 'baz')
2268
 
        # Did we get it back ?
2269
 
        self.assertEquals('baz', conf.get('foo'))
2270
 
 
2271
 
    def test_set_creates_a_new_section(self):
2272
 
        conf = self.get_stack(self)
2273
 
        conf.set('foo', 'baz')
2274
 
        self.assertEquals, 'baz', conf.get('foo')
2275
 
 
2276
 
 
2277
 
class TestStackRemove(TestStackWithTransport):
2278
 
 
2279
 
    scenarios = [(key, {'get_stack': builder})
2280
 
                 for key, builder in test_stack_builder_registry.iteritems()]
2281
 
 
2282
 
    def test_remove_existing(self):
2283
 
        conf = self.get_stack(self)
2284
 
        conf.store._load_from_string('foo=bar')
2285
 
        self.assertEquals('bar', conf.get('foo'))
2286
 
        conf.remove('foo')
2287
 
        # Did we get it back ?
2288
 
        self.assertEquals(None, conf.get('foo'))
2289
 
 
2290
 
    def test_remove_unknown(self):
2291
 
        conf = self.get_stack(self)
2292
 
        self.assertRaises(KeyError, conf.remove, 'I_do_not_exist')
2293
 
 
2294
 
 
2295
 
class TestConcreteStacks(TestStackWithTransport):
2296
 
 
2297
 
    scenarios = [(key, {'get_stack': builder})
2298
 
                 for key, builder in test_stack_builder_registry.iteritems()]
2299
 
 
2300
 
    def test_build_stack(self):
2301
 
        stack = self.get_stack(self)
2302
 
 
2303
 
 
2304
 
class TestConfigGetOptions(tests.TestCaseWithTransport, TestOptionsMixin):
2305
 
 
2306
 
    def setUp(self):
2307
 
        super(TestConfigGetOptions, self).setUp()
2308
 
        create_configs(self)
2309
 
 
2310
 
    def test_no_variable(self):
2311
 
        # Using branch should query branch, locations and bazaar
2312
 
        self.assertOptions([], self.branch_config)
2313
 
 
2314
 
    def test_option_in_bazaar(self):
2315
 
        self.bazaar_config.set_user_option('file', 'bazaar')
2316
 
        self.assertOptions([('file', 'bazaar', 'DEFAULT', 'bazaar')],
2317
 
                           self.bazaar_config)
2318
 
 
2319
 
    def test_option_in_locations(self):
2320
 
        self.locations_config.set_user_option('file', 'locations')
2321
 
        self.assertOptions(
2322
 
            [('file', 'locations', self.tree.basedir, 'locations')],
2323
 
            self.locations_config)
2324
 
 
2325
 
    def test_option_in_branch(self):
2326
 
        self.branch_config.set_user_option('file', 'branch')
2327
 
        self.assertOptions([('file', 'branch', 'DEFAULT', 'branch')],
2328
 
                           self.branch_config)
2329
 
 
2330
 
    def test_option_in_bazaar_and_branch(self):
2331
 
        self.bazaar_config.set_user_option('file', 'bazaar')
2332
 
        self.branch_config.set_user_option('file', 'branch')
2333
 
        self.assertOptions([('file', 'branch', 'DEFAULT', 'branch'),
2334
 
                            ('file', 'bazaar', 'DEFAULT', 'bazaar'),],
2335
 
                           self.branch_config)
2336
 
 
2337
 
    def test_option_in_branch_and_locations(self):
2338
 
        # Hmm, locations override branch :-/
2339
 
        self.locations_config.set_user_option('file', 'locations')
2340
 
        self.branch_config.set_user_option('file', 'branch')
2341
 
        self.assertOptions(
2342
 
            [('file', 'locations', self.tree.basedir, 'locations'),
2343
 
             ('file', 'branch', 'DEFAULT', 'branch'),],
2344
 
            self.branch_config)
2345
 
 
2346
 
    def test_option_in_bazaar_locations_and_branch(self):
2347
 
        self.bazaar_config.set_user_option('file', 'bazaar')
2348
 
        self.locations_config.set_user_option('file', 'locations')
2349
 
        self.branch_config.set_user_option('file', 'branch')
2350
 
        self.assertOptions(
2351
 
            [('file', 'locations', self.tree.basedir, 'locations'),
2352
 
             ('file', 'branch', 'DEFAULT', 'branch'),
2353
 
             ('file', 'bazaar', 'DEFAULT', 'bazaar'),],
2354
 
            self.branch_config)
2355
 
 
2356
 
 
2357
 
class TestConfigRemoveOption(tests.TestCaseWithTransport, TestOptionsMixin):
2358
 
 
2359
 
    def setUp(self):
2360
 
        super(TestConfigRemoveOption, self).setUp()
2361
 
        create_configs_with_file_option(self)
2362
 
 
2363
 
    def test_remove_in_locations(self):
2364
 
        self.locations_config.remove_user_option('file', self.tree.basedir)
2365
 
        self.assertOptions(
2366
 
            [('file', 'branch', 'DEFAULT', 'branch'),
2367
 
             ('file', 'bazaar', 'DEFAULT', 'bazaar'),],
2368
 
            self.branch_config)
2369
 
 
2370
 
    def test_remove_in_branch(self):
2371
 
        self.branch_config.remove_user_option('file')
2372
 
        self.assertOptions(
2373
 
            [('file', 'locations', self.tree.basedir, 'locations'),
2374
 
             ('file', 'bazaar', 'DEFAULT', 'bazaar'),],
2375
 
            self.branch_config)
2376
 
 
2377
 
    def test_remove_in_bazaar(self):
2378
 
        self.bazaar_config.remove_user_option('file')
2379
 
        self.assertOptions(
2380
 
            [('file', 'locations', self.tree.basedir, 'locations'),
2381
 
             ('file', 'branch', 'DEFAULT', 'branch'),],
2382
 
            self.branch_config)
2383
 
 
2384
 
 
2385
 
class TestConfigGetSections(tests.TestCaseWithTransport):
2386
 
 
2387
 
    def setUp(self):
2388
 
        super(TestConfigGetSections, self).setUp()
2389
 
        create_configs(self)
2390
 
 
2391
 
    def assertSectionNames(self, expected, conf, name=None):
2392
 
        """Check which sections are returned for a given config.
2393
 
 
2394
 
        If fallback configurations exist their sections can be included.
2395
 
 
2396
 
        :param expected: A list of section names.
2397
 
 
2398
 
        :param conf: The configuration that will be queried.
2399
 
 
2400
 
        :param name: An optional section name that will be passed to
2401
 
            get_sections().
2402
 
        """
2403
 
        sections = list(conf._get_sections(name))
2404
 
        self.assertLength(len(expected), sections)
2405
 
        self.assertEqual(expected, [name for name, _, _ in sections])
2406
 
 
2407
 
    def test_bazaar_default_section(self):
2408
 
        self.assertSectionNames(['DEFAULT'], self.bazaar_config)
2409
 
 
2410
 
    def test_locations_default_section(self):
2411
 
        # No sections are defined in an empty file
2412
 
        self.assertSectionNames([], self.locations_config)
2413
 
 
2414
 
    def test_locations_named_section(self):
2415
 
        self.locations_config.set_user_option('file', 'locations')
2416
 
        self.assertSectionNames([self.tree.basedir], self.locations_config)
2417
 
 
2418
 
    def test_locations_matching_sections(self):
2419
 
        loc_config = self.locations_config
2420
 
        loc_config.set_user_option('file', 'locations')
2421
 
        # We need to cheat a bit here to create an option in sections above and
2422
 
        # below the 'location' one.
2423
 
        parser = loc_config._get_parser()
2424
 
        # locations.cong deals with '/' ignoring native os.sep
2425
 
        location_names = self.tree.basedir.split('/')
2426
 
        parent = '/'.join(location_names[:-1])
2427
 
        child = '/'.join(location_names + ['child'])
2428
 
        parser[parent] = {}
2429
 
        parser[parent]['file'] = 'parent'
2430
 
        parser[child] = {}
2431
 
        parser[child]['file'] = 'child'
2432
 
        self.assertSectionNames([self.tree.basedir, parent], loc_config)
2433
 
 
2434
 
    def test_branch_data_default_section(self):
2435
 
        self.assertSectionNames([None],
2436
 
                                self.branch_config._get_branch_data_config())
2437
 
 
2438
 
    def test_branch_default_sections(self):
2439
 
        # No sections are defined in an empty locations file
2440
 
        self.assertSectionNames([None, 'DEFAULT'],
2441
 
                                self.branch_config)
2442
 
        # Unless we define an option
2443
 
        self.branch_config._get_location_config().set_user_option(
2444
 
            'file', 'locations')
2445
 
        self.assertSectionNames([self.tree.basedir, None, 'DEFAULT'],
2446
 
                                self.branch_config)
2447
 
 
2448
 
    def test_bazaar_named_section(self):
2449
 
        # We need to cheat as the API doesn't give direct access to sections
2450
 
        # other than DEFAULT.
2451
 
        self.bazaar_config.set_alias('bazaar', 'bzr')
2452
 
        self.assertSectionNames(['ALIASES'], self.bazaar_config, 'ALIASES')
2453
 
 
2454
 
 
2455
1474
class TestAuthenticationConfigFile(tests.TestCase):
2456
1475
    """Test the authentication.conf file matching"""
2457
1476
 
2952
1971
# test_user_prompted ?
2953
1972
class TestAuthenticationRing(tests.TestCaseWithTransport):
2954
1973
    pass
2955
 
 
2956
 
 
2957
 
class TestAutoUserId(tests.TestCase):
2958
 
    """Test inferring an automatic user name."""
2959
 
 
2960
 
    def test_auto_user_id(self):
2961
 
        """Automatic inference of user name.
2962
 
        
2963
 
        This is a bit hard to test in an isolated way, because it depends on
2964
 
        system functions that go direct to /etc or perhaps somewhere else.
2965
 
        But it's reasonable to say that on Unix, with an /etc/mailname, we ought
2966
 
        to be able to choose a user name with no configuration.
2967
 
        """
2968
 
        if sys.platform == 'win32':
2969
 
            raise TestSkipped("User name inference not implemented on win32")
2970
 
        realname, address = config._auto_user_id()
2971
 
        if os.path.exists('/etc/mailname'):
2972
 
            self.assertIsNot(None, realname)
2973
 
            self.assertIsNot(None, address)
2974
 
        else:
2975
 
            self.assertEquals((None, None), (realname, address))
2976