367
556
'/home/bogus/.cache')
370
class TestIniConfig(tests.TestCase):
559
class TestXDGConfigDir(tests.TestCaseInTempDir):
560
# must be in temp dir because config tests for the existence of the bazaar
561
# subdirectory of $XDG_CONFIG_HOME
564
if sys.platform in ('darwin', 'win32'):
565
raise tests.TestNotApplicable(
566
'XDG config dir not used on this platform')
567
super(TestXDGConfigDir, self).setUp()
568
self.overrideEnv('HOME', self.test_home_dir)
569
# BZR_HOME overrides everything we want to test so unset it.
570
self.overrideEnv('BZR_HOME', None)
572
def test_xdg_config_dir_exists(self):
573
"""When ~/.config/bazaar exists, use it as the config dir."""
574
newdir = osutils.pathjoin(self.test_home_dir, '.config', 'bazaar')
576
self.assertEqual(config.config_dir(), newdir)
578
def test_xdg_config_home(self):
579
"""When XDG_CONFIG_HOME is set, use it."""
580
xdgconfigdir = osutils.pathjoin(self.test_home_dir, 'xdgconfig')
581
self.overrideEnv('XDG_CONFIG_HOME', xdgconfigdir)
582
newdir = osutils.pathjoin(xdgconfigdir, 'bazaar')
584
self.assertEqual(config.config_dir(), newdir)
587
class TestIniConfig(tests.TestCaseInTempDir):
372
589
def make_config_parser(self, s):
373
conf = config.IniBasedConfig(None)
374
parser = conf._get_parser(file=StringIO(s.encode('utf-8')))
590
conf = config.IniBasedConfig.from_string(s)
591
return conf, conf._get_parser()
378
594
class TestIniConfigBuilding(TestIniConfig):
380
596
def test_contructs(self):
381
my_config = config.IniBasedConfig("nothing")
597
my_config = config.IniBasedConfig()
383
599
def test_from_fp(self):
384
config_file = StringIO(sample_config_text.encode('utf-8'))
385
my_config = config.IniBasedConfig(None)
387
isinstance(my_config._get_parser(file=config_file),
388
configobj.ConfigObj))
600
my_config = config.IniBasedConfig.from_string(sample_config_text)
601
self.assertIsInstance(my_config._get_parser(), configobj.ConfigObj)
390
603
def test_cached(self):
604
my_config = config.IniBasedConfig.from_string(sample_config_text)
605
parser = my_config._get_parser()
606
self.assertTrue(my_config._get_parser() is parser)
608
def _dummy_chown(self, path, uid, gid):
609
self.path, self.uid, self.gid = path, uid, gid
611
def test_ini_config_ownership(self):
612
"""Ensure that chown is happening during _write_config_file"""
613
self.requireFeature(features.chown_feature)
614
self.overrideAttr(os, 'chown', self._dummy_chown)
615
self.path = self.uid = self.gid = None
616
conf = config.IniBasedConfig(file_name='./foo.conf')
617
conf._write_config_file()
618
self.assertEquals(self.path, './foo.conf')
619
self.assertTrue(isinstance(self.uid, int))
620
self.assertTrue(isinstance(self.gid, int))
622
def test_get_filename_parameter_is_deprecated_(self):
623
conf = self.callDeprecated([
624
'IniBasedConfig.__init__(get_filename) was deprecated in 2.3.'
625
' Use file_name instead.'],
626
config.IniBasedConfig, lambda: 'ini.conf')
627
self.assertEqual('ini.conf', conf.file_name)
629
def test_get_parser_file_parameter_is_deprecated_(self):
391
630
config_file = StringIO(sample_config_text.encode('utf-8'))
392
my_config = config.IniBasedConfig(None)
393
parser = my_config._get_parser(file=config_file)
394
self.failUnless(my_config._get_parser() is parser)
631
conf = config.IniBasedConfig.from_string(sample_config_text)
632
conf = self.callDeprecated([
633
'IniBasedConfig._get_parser(file=xxx) was deprecated in 2.3.'
634
' Use IniBasedConfig(_content=xxx) instead.'],
635
conf._get_parser, file=config_file)
638
class TestIniConfigSaving(tests.TestCaseInTempDir):
640
def test_cant_save_without_a_file_name(self):
641
conf = config.IniBasedConfig()
642
self.assertRaises(AssertionError, conf._write_config_file)
644
def test_saved_with_content(self):
645
content = 'foo = bar\n'
646
conf = config.IniBasedConfig.from_string(
647
content, file_name='./test.conf', save=True)
648
self.assertFileEqual(content, 'test.conf')
651
class TestIniConfigOptionExpansionDefaultValue(tests.TestCaseInTempDir):
652
"""What is the default value of expand for config options.
654
This is an opt-in beta feature used to evaluate whether or not option
655
references can appear in dangerous place raising exceptions, disapearing
656
(and as such corrupting data) or if it's safe to activate the option by
659
Note that these tests relies on config._expand_default_value being already
660
overwritten in the parent class setUp.
664
super(TestIniConfigOptionExpansionDefaultValue, self).setUp()
668
self.warnings.append(args[0] % args[1:])
669
self.overrideAttr(trace, 'warning', warning)
671
def get_config(self, expand):
672
c = config.GlobalConfig.from_string('bzr.config.expand=%s' % (expand,),
676
def assertExpandIs(self, expected):
677
actual = config._get_expand_default_value()
678
#self.config.get_user_option_as_bool('bzr.config.expand')
679
self.assertEquals(expected, actual)
681
def test_default_is_None(self):
682
self.assertEquals(None, config._expand_default_value)
684
def test_default_is_False_even_if_None(self):
685
self.config = self.get_config(None)
686
self.assertExpandIs(False)
688
def test_default_is_False_even_if_invalid(self):
689
self.config = self.get_config('<your choice>')
690
self.assertExpandIs(False)
692
# Huh ? My choice is False ? Thanks, always happy to hear that :D
693
# Wait, you've been warned !
694
self.assertLength(1, self.warnings)
696
'Value "<your choice>" is not a boolean for "bzr.config.expand"',
699
def test_default_is_True(self):
700
self.config = self.get_config(True)
701
self.assertExpandIs(True)
703
def test_default_is_False(self):
704
self.config = self.get_config(False)
705
self.assertExpandIs(False)
708
class TestIniConfigOptionExpansion(tests.TestCase):
709
"""Test option expansion from the IniConfig level.
711
What we really want here is to test the Config level, but the class being
712
abstract as far as storing values is concerned, this can't be done
715
# FIXME: This should be rewritten when all configs share a storage
716
# implementation -- vila 2011-02-18
718
def get_config(self, string=None):
721
c = config.IniBasedConfig.from_string(string)
724
def assertExpansion(self, expected, conf, string, env=None):
725
self.assertEquals(expected, conf.expand_options(string, env))
727
def test_no_expansion(self):
728
c = self.get_config('')
729
self.assertExpansion('foo', c, 'foo')
731
def test_env_adding_options(self):
732
c = self.get_config('')
733
self.assertExpansion('bar', c, '{foo}', {'foo': 'bar'})
735
def test_env_overriding_options(self):
736
c = self.get_config('foo=baz')
737
self.assertExpansion('bar', c, '{foo}', {'foo': 'bar'})
739
def test_simple_ref(self):
740
c = self.get_config('foo=xxx')
741
self.assertExpansion('xxx', c, '{foo}')
743
def test_unknown_ref(self):
744
c = self.get_config('')
745
self.assertRaises(errors.ExpandingUnknownOption,
746
c.expand_options, '{foo}')
748
def test_indirect_ref(self):
749
c = self.get_config('''
753
self.assertExpansion('xxx', c, '{bar}')
755
def test_embedded_ref(self):
756
c = self.get_config('''
760
self.assertExpansion('xxx', c, '{{bar}}')
762
def test_simple_loop(self):
763
c = self.get_config('foo={foo}')
764
self.assertRaises(errors.OptionExpansionLoop, c.expand_options, '{foo}')
766
def test_indirect_loop(self):
767
c = self.get_config('''
771
e = self.assertRaises(errors.OptionExpansionLoop,
772
c.expand_options, '{foo}')
773
self.assertEquals('foo->bar->baz', e.refs)
774
self.assertEquals('{foo}', e.string)
777
conf = self.get_config('''
781
list={foo},{bar},{baz}
783
self.assertEquals(['start', 'middle', 'end'],
784
conf.get_user_option('list', expand=True))
786
def test_cascading_list(self):
787
conf = self.get_config('''
793
self.assertEquals(['start', 'middle', 'end'],
794
conf.get_user_option('list', expand=True))
796
def test_pathological_hidden_list(self):
797
conf = self.get_config('''
803
hidden={start}{middle}{end}
805
# Nope, it's either a string or a list, and the list wins as soon as a
806
# ',' appears, so the string concatenation never occur.
807
self.assertEquals(['{foo', '}', '{', 'bar}'],
808
conf.get_user_option('hidden', expand=True))
810
class TestLocationConfigOptionExpansion(tests.TestCaseInTempDir):
812
def get_config(self, location, string=None):
815
# Since we don't save the config we won't strictly require to inherit
816
# from TestCaseInTempDir, but an error occurs so quickly...
817
c = config.LocationConfig.from_string(string, location)
820
def test_dont_cross_unrelated_section(self):
821
c = self.get_config('/another/branch/path','''
826
[/another/branch/path]
829
self.assertRaises(errors.ExpandingUnknownOption,
830
c.get_user_option, 'bar', expand=True)
832
def test_cross_related_sections(self):
833
c = self.get_config('/project/branch/path','''
837
[/project/branch/path]
840
self.assertEquals('quux', c.get_user_option('bar', expand=True))
843
class TestIniBaseConfigOnDisk(tests.TestCaseInTempDir):
845
def test_cannot_reload_without_name(self):
846
conf = config.IniBasedConfig.from_string(sample_config_text)
847
self.assertRaises(AssertionError, conf.reload)
849
def test_reload_see_new_value(self):
850
c1 = config.IniBasedConfig.from_string('editor=vim\n',
851
file_name='./test/conf')
852
c1._write_config_file()
853
c2 = config.IniBasedConfig.from_string('editor=emacs\n',
854
file_name='./test/conf')
855
c2._write_config_file()
856
self.assertEqual('vim', c1.get_user_option('editor'))
857
self.assertEqual('emacs', c2.get_user_option('editor'))
858
# Make sure we get the Right value
860
self.assertEqual('emacs', c1.get_user_option('editor'))
863
class TestLockableConfig(tests.TestCaseInTempDir):
865
scenarios = lockable_config_scenarios()
870
config_section = None
873
super(TestLockableConfig, self).setUp()
874
self._content = '[%s]\none=1\ntwo=2\n' % (self.config_section,)
875
self.config = self.create_config(self._content)
877
def get_existing_config(self):
878
return self.config_class(*self.config_args)
880
def create_config(self, content):
881
kwargs = dict(save=True)
882
c = self.config_class.from_string(content, *self.config_args, **kwargs)
885
def test_simple_read_access(self):
886
self.assertEquals('1', self.config.get_user_option('one'))
888
def test_simple_write_access(self):
889
self.config.set_user_option('one', 'one')
890
self.assertEquals('one', self.config.get_user_option('one'))
892
def test_listen_to_the_last_speaker(self):
894
c2 = self.get_existing_config()
895
c1.set_user_option('one', 'ONE')
896
c2.set_user_option('two', 'TWO')
897
self.assertEquals('ONE', c1.get_user_option('one'))
898
self.assertEquals('TWO', c2.get_user_option('two'))
899
# The second update respect the first one
900
self.assertEquals('ONE', c2.get_user_option('one'))
902
def test_last_speaker_wins(self):
903
# If the same config is not shared, the same variable modified twice
904
# can only see a single result.
906
c2 = self.get_existing_config()
907
c1.set_user_option('one', 'c1')
908
c2.set_user_option('one', 'c2')
909
self.assertEquals('c2', c2._get_user_option('one'))
910
# The first modification is still available until another refresh
912
self.assertEquals('c1', c1._get_user_option('one'))
913
c1.set_user_option('two', 'done')
914
self.assertEquals('c2', c1._get_user_option('one'))
916
def test_writes_are_serialized(self):
918
c2 = self.get_existing_config()
920
# We spawn a thread that will pause *during* the write
921
before_writing = threading.Event()
922
after_writing = threading.Event()
923
writing_done = threading.Event()
924
c1_orig = c1._write_config_file
925
def c1_write_config_file():
928
# The lock is held. We wait for the main thread to decide when to
931
c1._write_config_file = c1_write_config_file
933
c1.set_user_option('one', 'c1')
935
t1 = threading.Thread(target=c1_set_option)
936
# Collect the thread after the test
937
self.addCleanup(t1.join)
938
# Be ready to unblock the thread if the test goes wrong
939
self.addCleanup(after_writing.set)
941
before_writing.wait()
942
self.assertTrue(c1._lock.is_held)
943
self.assertRaises(errors.LockContention,
944
c2.set_user_option, 'one', 'c2')
945
self.assertEquals('c1', c1.get_user_option('one'))
946
# Let the lock be released
949
c2.set_user_option('one', 'c2')
950
self.assertEquals('c2', c2.get_user_option('one'))
952
def test_read_while_writing(self):
954
# We spawn a thread that will pause *during* the write
955
ready_to_write = threading.Event()
956
do_writing = threading.Event()
957
writing_done = threading.Event()
958
c1_orig = c1._write_config_file
959
def c1_write_config_file():
961
# The lock is held. We wait for the main thread to decide when to
966
c1._write_config_file = c1_write_config_file
968
c1.set_user_option('one', 'c1')
969
t1 = threading.Thread(target=c1_set_option)
970
# Collect the thread after the test
971
self.addCleanup(t1.join)
972
# Be ready to unblock the thread if the test goes wrong
973
self.addCleanup(do_writing.set)
975
# Ensure the thread is ready to write
976
ready_to_write.wait()
977
self.assertTrue(c1._lock.is_held)
978
self.assertEquals('c1', c1.get_user_option('one'))
979
# If we read during the write, we get the old value
980
c2 = self.get_existing_config()
981
self.assertEquals('1', c2.get_user_option('one'))
982
# Let the writing occur and ensure it occurred
985
# Now we get the updated value
986
c3 = self.get_existing_config()
987
self.assertEquals('c1', c3.get_user_option('one'))
397
990
class TestGetUserOptionAs(TestIniConfig):
1312
1909
self.assertIs(None, bzrdir_config.get_default_stack_on())
1912
class TestOldConfigHooks(tests.TestCaseWithTransport):
1915
super(TestOldConfigHooks, self).setUp()
1916
create_configs_with_file_option(self)
1918
def assertGetHook(self, conf, name, value):
1922
config.OldConfigHooks.install_named_hook('get', hook, None)
1924
config.OldConfigHooks.uninstall_named_hook, 'get', None)
1925
self.assertLength(0, calls)
1926
actual_value = conf.get_user_option(name)
1927
self.assertEquals(value, actual_value)
1928
self.assertLength(1, calls)
1929
self.assertEquals((conf, name, value), calls[0])
1931
def test_get_hook_bazaar(self):
1932
self.assertGetHook(self.bazaar_config, 'file', 'bazaar')
1934
def test_get_hook_locations(self):
1935
self.assertGetHook(self.locations_config, 'file', 'locations')
1937
def test_get_hook_branch(self):
1938
# Since locations masks branch, we define a different option
1939
self.branch_config.set_user_option('file2', 'branch')
1940
self.assertGetHook(self.branch_config, 'file2', 'branch')
1942
def assertSetHook(self, conf, name, value):
1946
config.OldConfigHooks.install_named_hook('set', hook, None)
1948
config.OldConfigHooks.uninstall_named_hook, 'set', None)
1949
self.assertLength(0, calls)
1950
conf.set_user_option(name, value)
1951
self.assertLength(1, calls)
1952
# We can't assert the conf object below as different configs use
1953
# different means to implement set_user_option and we care only about
1955
self.assertEquals((name, value), calls[0][1:])
1957
def test_set_hook_bazaar(self):
1958
self.assertSetHook(self.bazaar_config, 'foo', 'bazaar')
1960
def test_set_hook_locations(self):
1961
self.assertSetHook(self.locations_config, 'foo', 'locations')
1963
def test_set_hook_branch(self):
1964
self.assertSetHook(self.branch_config, 'foo', 'branch')
1966
def assertRemoveHook(self, conf, name, section_name=None):
1970
config.OldConfigHooks.install_named_hook('remove', hook, None)
1972
config.OldConfigHooks.uninstall_named_hook, 'remove', None)
1973
self.assertLength(0, calls)
1974
conf.remove_user_option(name, section_name)
1975
self.assertLength(1, calls)
1976
# We can't assert the conf object below as different configs use
1977
# different means to implement remove_user_option and we care only about
1979
self.assertEquals((name,), calls[0][1:])
1981
def test_remove_hook_bazaar(self):
1982
self.assertRemoveHook(self.bazaar_config, 'file')
1984
def test_remove_hook_locations(self):
1985
self.assertRemoveHook(self.locations_config, 'file',
1986
self.locations_config.location)
1988
def test_remove_hook_branch(self):
1989
self.assertRemoveHook(self.branch_config, 'file')
1991
def assertLoadHook(self, name, conf_class, *conf_args):
1995
config.OldConfigHooks.install_named_hook('load', hook, None)
1997
config.OldConfigHooks.uninstall_named_hook, 'load', None)
1998
self.assertLength(0, calls)
2000
conf = conf_class(*conf_args)
2001
# Access an option to trigger a load
2002
conf.get_user_option(name)
2003
self.assertLength(1, calls)
2004
# Since we can't assert about conf, we just use the number of calls ;-/
2006
def test_load_hook_bazaar(self):
2007
self.assertLoadHook('file', config.GlobalConfig)
2009
def test_load_hook_locations(self):
2010
self.assertLoadHook('file', config.LocationConfig, self.tree.basedir)
2012
def test_load_hook_branch(self):
2013
self.assertLoadHook('file', config.BranchConfig, self.tree.branch)
2015
def assertSaveHook(self, conf):
2019
config.OldConfigHooks.install_named_hook('save', hook, None)
2021
config.OldConfigHooks.uninstall_named_hook, 'save', None)
2022
self.assertLength(0, calls)
2023
# Setting an option triggers a save
2024
conf.set_user_option('foo', 'bar')
2025
self.assertLength(1, calls)
2026
# Since we can't assert about conf, we just use the number of calls ;-/
2028
def test_save_hook_bazaar(self):
2029
self.assertSaveHook(self.bazaar_config)
2031
def test_save_hook_locations(self):
2032
self.assertSaveHook(self.locations_config)
2034
def test_save_hook_branch(self):
2035
self.assertSaveHook(self.branch_config)
2038
class TestOldConfigHooksForRemote(tests.TestCaseWithTransport):
2039
"""Tests config hooks for remote configs.
2041
No tests for the remove hook as this is not implemented there.
2045
super(TestOldConfigHooksForRemote, self).setUp()
2046
self.transport_server = test_server.SmartTCPServer_for_testing
2047
create_configs_with_file_option(self)
2049
def assertGetHook(self, conf, name, value):
2053
config.OldConfigHooks.install_named_hook('get', hook, None)
2055
config.OldConfigHooks.uninstall_named_hook, 'get', None)
2056
self.assertLength(0, calls)
2057
actual_value = conf.get_option(name)
2058
self.assertEquals(value, actual_value)
2059
self.assertLength(1, calls)
2060
self.assertEquals((conf, name, value), calls[0])
2062
def test_get_hook_remote_branch(self):
2063
remote_branch = branch.Branch.open(self.get_url('tree'))
2064
self.assertGetHook(remote_branch._get_config(), 'file', 'branch')
2066
def test_get_hook_remote_bzrdir(self):
2067
remote_bzrdir = bzrdir.BzrDir.open(self.get_url('tree'))
2068
conf = remote_bzrdir._get_config()
2069
conf.set_option('remotedir', 'file')
2070
self.assertGetHook(conf, 'file', 'remotedir')
2072
def assertSetHook(self, conf, name, value):
2076
config.OldConfigHooks.install_named_hook('set', hook, None)
2078
config.OldConfigHooks.uninstall_named_hook, 'set', None)
2079
self.assertLength(0, calls)
2080
conf.set_option(value, name)
2081
self.assertLength(1, calls)
2082
# We can't assert the conf object below as different configs use
2083
# different means to implement set_user_option and we care only about
2085
self.assertEquals((name, value), calls[0][1:])
2087
def test_set_hook_remote_branch(self):
2088
remote_branch = branch.Branch.open(self.get_url('tree'))
2089
self.addCleanup(remote_branch.lock_write().unlock)
2090
self.assertSetHook(remote_branch._get_config(), 'file', 'remote')
2092
def test_set_hook_remote_bzrdir(self):
2093
remote_branch = branch.Branch.open(self.get_url('tree'))
2094
self.addCleanup(remote_branch.lock_write().unlock)
2095
remote_bzrdir = bzrdir.BzrDir.open(self.get_url('tree'))
2096
self.assertSetHook(remote_bzrdir._get_config(), 'file', 'remotedir')
2098
def assertLoadHook(self, expected_nb_calls, name, conf_class, *conf_args):
2102
config.OldConfigHooks.install_named_hook('load', hook, None)
2104
config.OldConfigHooks.uninstall_named_hook, 'load', None)
2105
self.assertLength(0, calls)
2107
conf = conf_class(*conf_args)
2108
# Access an option to trigger a load
2109
conf.get_option(name)
2110
self.assertLength(expected_nb_calls, calls)
2111
# Since we can't assert about conf, we just use the number of calls ;-/
2113
def test_load_hook_remote_branch(self):
2114
remote_branch = branch.Branch.open(self.get_url('tree'))
2115
self.assertLoadHook(1, 'file', remote.RemoteBranchConfig, remote_branch)
2117
def test_load_hook_remote_bzrdir(self):
2118
remote_bzrdir = bzrdir.BzrDir.open(self.get_url('tree'))
2119
# The config file doesn't exist, set an option to force its creation
2120
conf = remote_bzrdir._get_config()
2121
conf.set_option('remotedir', 'file')
2122
# We get one call for the server and one call for the client, this is
2123
# caused by the differences in implementations betwen
2124
# SmartServerBzrDirRequestConfigFile (in smart/bzrdir.py) and
2125
# SmartServerBranchGetConfigFile (in smart/branch.py)
2126
self.assertLoadHook(2 ,'file', remote.RemoteBzrDirConfig, remote_bzrdir)
2128
def assertSaveHook(self, conf):
2132
config.OldConfigHooks.install_named_hook('save', hook, None)
2134
config.OldConfigHooks.uninstall_named_hook, 'save', None)
2135
self.assertLength(0, calls)
2136
# Setting an option triggers a save
2137
conf.set_option('foo', 'bar')
2138
self.assertLength(1, calls)
2139
# Since we can't assert about conf, we just use the number of calls ;-/
2141
def test_save_hook_remote_branch(self):
2142
remote_branch = branch.Branch.open(self.get_url('tree'))
2143
self.addCleanup(remote_branch.lock_write().unlock)
2144
self.assertSaveHook(remote_branch._get_config())
2146
def test_save_hook_remote_bzrdir(self):
2147
remote_branch = branch.Branch.open(self.get_url('tree'))
2148
self.addCleanup(remote_branch.lock_write().unlock)
2149
remote_bzrdir = bzrdir.BzrDir.open(self.get_url('tree'))
2150
self.assertSaveHook(remote_bzrdir._get_config())
2153
class TestOption(tests.TestCase):
2155
def test_default_value(self):
2156
opt = config.Option('foo', default='bar')
2157
self.assertEquals('bar', opt.get_default())
2160
class TestOptionRegistry(tests.TestCase):
2163
super(TestOptionRegistry, self).setUp()
2164
# Always start with an empty registry
2165
self.overrideAttr(config, 'option_registry', registry.Registry())
2166
self.registry = config.option_registry
2168
def test_register(self):
2169
opt = config.Option('foo')
2170
self.registry.register('foo', opt)
2171
self.assertIs(opt, self.registry.get('foo'))
2173
lazy_option = config.Option('lazy_foo')
2175
def test_register_lazy(self):
2176
self.registry.register_lazy('foo', self.__module__,
2177
'TestOptionRegistry.lazy_option')
2178
self.assertIs(self.lazy_option, self.registry.get('foo'))
2180
def test_registered_help(self):
2181
opt = config.Option('foo')
2182
self.registry.register('foo', opt, help='A simple option')
2183
self.assertEquals('A simple option', self.registry.get_help('foo'))
2186
class TestRegisteredOptions(tests.TestCase):
2187
"""All registered options should verify some constraints."""
2189
scenarios = [(key, {'option_name': key, 'option': option}) for key, option
2190
in config.option_registry.iteritems()]
2193
super(TestRegisteredOptions, self).setUp()
2194
self.registry = config.option_registry
2196
def test_proper_name(self):
2197
# An option should be registered under its own name, this can't be
2198
# checked at registration time for the lazy ones.
2199
self.assertEquals(self.option_name, self.option.name)
2201
def test_help_is_set(self):
2202
option_help = self.registry.get_help(self.option_name)
2203
self.assertNotEquals(None, option_help)
2204
# Come on, think about the user, he really wants to know whst the
2206
self.assertNotEquals('', option_help)
2209
class TestSection(tests.TestCase):
2211
# FIXME: Parametrize so that all sections produced by Stores run these
2212
# tests -- vila 2011-04-01
2214
def test_get_a_value(self):
2215
a_dict = dict(foo='bar')
2216
section = config.Section('myID', a_dict)
2217
self.assertEquals('bar', section.get('foo'))
2219
def test_get_unknown_option(self):
2221
section = config.Section(None, a_dict)
2222
self.assertEquals('out of thin air',
2223
section.get('foo', 'out of thin air'))
2225
def test_options_is_shared(self):
2227
section = config.Section(None, a_dict)
2228
self.assertIs(a_dict, section.options)
2231
class TestMutableSection(tests.TestCase):
2233
# FIXME: Parametrize so that all sections (including os.environ and the
2234
# ones produced by Stores) run these tests -- vila 2011-04-01
2237
a_dict = dict(foo='bar')
2238
section = config.MutableSection('myID', a_dict)
2239
section.set('foo', 'new_value')
2240
self.assertEquals('new_value', section.get('foo'))
2241
# The change appears in the shared section
2242
self.assertEquals('new_value', a_dict.get('foo'))
2243
# We keep track of the change
2244
self.assertTrue('foo' in section.orig)
2245
self.assertEquals('bar', section.orig.get('foo'))
2247
def test_set_preserve_original_once(self):
2248
a_dict = dict(foo='bar')
2249
section = config.MutableSection('myID', a_dict)
2250
section.set('foo', 'first_value')
2251
section.set('foo', 'second_value')
2252
# We keep track of the original value
2253
self.assertTrue('foo' in section.orig)
2254
self.assertEquals('bar', section.orig.get('foo'))
2256
def test_remove(self):
2257
a_dict = dict(foo='bar')
2258
section = config.MutableSection('myID', a_dict)
2259
section.remove('foo')
2260
# We get None for unknown options via the default value
2261
self.assertEquals(None, section.get('foo'))
2262
# Or we just get the default value
2263
self.assertEquals('unknown', section.get('foo', 'unknown'))
2264
self.assertFalse('foo' in section.options)
2265
# We keep track of the deletion
2266
self.assertTrue('foo' in section.orig)
2267
self.assertEquals('bar', section.orig.get('foo'))
2269
def test_remove_new_option(self):
2271
section = config.MutableSection('myID', a_dict)
2272
section.set('foo', 'bar')
2273
section.remove('foo')
2274
self.assertFalse('foo' in section.options)
2275
# The option didn't exist initially so it we need to keep track of it
2276
# with a special value
2277
self.assertTrue('foo' in section.orig)
2278
self.assertEquals(config._NewlyCreatedOption, section.orig['foo'])
2281
class TestStore(tests.TestCaseWithTransport):
2283
def assertSectionContent(self, expected, section):
2284
"""Assert that some options have the proper values in a section."""
2285
expected_name, expected_options = expected
2286
self.assertEquals(expected_name, section.id)
2289
dict([(k, section.get(k)) for k in expected_options.keys()]))
2292
class TestReadonlyStore(TestStore):
2294
scenarios = [(key, {'get_store': builder}) for key, builder
2295
in config.test_store_builder_registry.iteritems()]
2298
super(TestReadonlyStore, self).setUp()
2300
def test_building_delays_load(self):
2301
store = self.get_store(self)
2302
self.assertEquals(False, store.is_loaded())
2303
store._load_from_string('')
2304
self.assertEquals(True, store.is_loaded())
2306
def test_get_no_sections_for_empty(self):
2307
store = self.get_store(self)
2308
store._load_from_string('')
2309
self.assertEquals([], list(store.get_sections()))
2311
def test_get_default_section(self):
2312
store = self.get_store(self)
2313
store._load_from_string('foo=bar')
2314
sections = list(store.get_sections())
2315
self.assertLength(1, sections)
2316
self.assertSectionContent((None, {'foo': 'bar'}), sections[0])
2318
def test_get_named_section(self):
2319
store = self.get_store(self)
2320
store._load_from_string('[baz]\nfoo=bar')
2321
sections = list(store.get_sections())
2322
self.assertLength(1, sections)
2323
self.assertSectionContent(('baz', {'foo': 'bar'}), sections[0])
2325
def test_load_from_string_fails_for_non_empty_store(self):
2326
store = self.get_store(self)
2327
store._load_from_string('foo=bar')
2328
self.assertRaises(AssertionError, store._load_from_string, 'bar=baz')
2331
class TestMutableStore(TestStore):
2333
scenarios = [(key, {'store_id': key, 'get_store': builder}) for key, builder
2334
in config.test_store_builder_registry.iteritems()]
2337
super(TestMutableStore, self).setUp()
2338
self.transport = self.get_transport()
2340
def has_store(self, store):
2341
store_basename = urlutils.relative_url(self.transport.external_url(),
2342
store.external_url())
2343
return self.transport.has(store_basename)
2345
def test_save_empty_creates_no_file(self):
2346
# FIXME: There should be a better way than relying on the test
2347
# parametrization to identify branch.conf -- vila 2011-0526
2348
if self.store_id in ('branch', 'remote_branch'):
2349
raise tests.TestNotApplicable(
2350
'branch.conf is *always* created when a branch is initialized')
2351
store = self.get_store(self)
2353
self.assertEquals(False, self.has_store(store))
2355
def test_save_emptied_succeeds(self):
2356
store = self.get_store(self)
2357
store._load_from_string('foo=bar\n')
2358
section = store.get_mutable_section(None)
2359
section.remove('foo')
2361
self.assertEquals(True, self.has_store(store))
2362
modified_store = self.get_store(self)
2363
sections = list(modified_store.get_sections())
2364
self.assertLength(0, sections)
2366
def test_save_with_content_succeeds(self):
2367
# FIXME: There should be a better way than relying on the test
2368
# parametrization to identify branch.conf -- vila 2011-0526
2369
if self.store_id in ('branch', 'remote_branch'):
2370
raise tests.TestNotApplicable(
2371
'branch.conf is *always* created when a branch is initialized')
2372
store = self.get_store(self)
2373
store._load_from_string('foo=bar\n')
2374
self.assertEquals(False, self.has_store(store))
2376
self.assertEquals(True, self.has_store(store))
2377
modified_store = self.get_store(self)
2378
sections = list(modified_store.get_sections())
2379
self.assertLength(1, sections)
2380
self.assertSectionContent((None, {'foo': 'bar'}), sections[0])
2382
def test_set_option_in_empty_store(self):
2383
store = self.get_store(self)
2384
section = store.get_mutable_section(None)
2385
section.set('foo', 'bar')
2387
modified_store = self.get_store(self)
2388
sections = list(modified_store.get_sections())
2389
self.assertLength(1, sections)
2390
self.assertSectionContent((None, {'foo': 'bar'}), sections[0])
2392
def test_set_option_in_default_section(self):
2393
store = self.get_store(self)
2394
store._load_from_string('')
2395
section = store.get_mutable_section(None)
2396
section.set('foo', 'bar')
2398
modified_store = self.get_store(self)
2399
sections = list(modified_store.get_sections())
2400
self.assertLength(1, sections)
2401
self.assertSectionContent((None, {'foo': 'bar'}), sections[0])
2403
def test_set_option_in_named_section(self):
2404
store = self.get_store(self)
2405
store._load_from_string('')
2406
section = store.get_mutable_section('baz')
2407
section.set('foo', 'bar')
2409
modified_store = self.get_store(self)
2410
sections = list(modified_store.get_sections())
2411
self.assertLength(1, sections)
2412
self.assertSectionContent(('baz', {'foo': 'bar'}), sections[0])
2414
def test_load_hook(self):
2415
# We first needs to ensure that the store exists
2416
store = self.get_store(self)
2417
section = store.get_mutable_section('baz')
2418
section.set('foo', 'bar')
2420
# Now we can try to load it
2421
store = self.get_store(self)
2425
config.ConfigHooks.install_named_hook('load', hook, None)
2426
self.assertLength(0, calls)
2428
self.assertLength(1, calls)
2429
self.assertEquals((store,), calls[0])
2431
def test_save_hook(self):
2435
config.ConfigHooks.install_named_hook('save', hook, None)
2436
self.assertLength(0, calls)
2437
store = self.get_store(self)
2438
section = store.get_mutable_section('baz')
2439
section.set('foo', 'bar')
2441
self.assertLength(1, calls)
2442
self.assertEquals((store,), calls[0])
2445
class TestIniFileStore(TestStore):
2447
def test_loading_unknown_file_fails(self):
2448
store = config.IniFileStore(self.get_transport(), 'I-do-not-exist')
2449
self.assertRaises(errors.NoSuchFile, store.load)
2451
def test_invalid_content(self):
2452
store = config.IniFileStore(self.get_transport(), 'foo.conf', )
2453
self.assertEquals(False, store.is_loaded())
2454
exc = self.assertRaises(
2455
errors.ParseConfigError, store._load_from_string,
2456
'this is invalid !')
2457
self.assertEndsWith(exc.filename, 'foo.conf')
2458
# And the load failed
2459
self.assertEquals(False, store.is_loaded())
2461
def test_get_embedded_sections(self):
2462
# A more complicated example (which also shows that section names and
2463
# option names share the same name space...)
2464
# FIXME: This should be fixed by forbidding dicts as values ?
2465
# -- vila 2011-04-05
2466
store = config.IniFileStore(self.get_transport(), 'foo.conf', )
2467
store._load_from_string('''
2471
foo_in_DEFAULT=foo_DEFAULT
2479
sections = list(store.get_sections())
2480
self.assertLength(4, sections)
2481
# The default section has no name.
2482
# List values are provided as lists
2483
self.assertSectionContent((None, {'foo': 'bar', 'l': ['1', '2']}),
2485
self.assertSectionContent(
2486
('DEFAULT', {'foo_in_DEFAULT': 'foo_DEFAULT'}), sections[1])
2487
self.assertSectionContent(
2488
('bar', {'foo_in_bar': 'barbar'}), sections[2])
2489
# sub sections are provided as embedded dicts.
2490
self.assertSectionContent(
2491
('baz', {'foo_in_baz': 'barbaz', 'qux': {'foo_in_qux': 'quux'}}),
2495
class TestLockableIniFileStore(TestStore):
2497
def test_create_store_in_created_dir(self):
2498
self.assertPathDoesNotExist('dir')
2499
t = self.get_transport('dir/subdir')
2500
store = config.LockableIniFileStore(t, 'foo.conf')
2501
store.get_mutable_section(None).set('foo', 'bar')
2503
self.assertPathExists('dir/subdir')
2506
class TestConcurrentStoreUpdates(TestStore):
2507
"""Test that Stores properly handle conccurent updates.
2509
New Store implementation may fail some of these tests but until such
2510
implementations exist it's hard to properly filter them from the scenarios
2511
applied here. If you encounter such a case, contact the bzr devs.
2514
scenarios = [(key, {'get_stack': builder}) for key, builder
2515
in config.test_stack_builder_registry.iteritems()]
2518
super(TestConcurrentStoreUpdates, self).setUp()
2519
self._content = 'one=1\ntwo=2\n'
2520
self.stack = self.get_stack(self)
2521
if not isinstance(self.stack, config._CompatibleStack):
2522
raise tests.TestNotApplicable(
2523
'%s is not meant to be compatible with the old config design'
2525
self.stack.store._load_from_string(self._content)
2527
self.stack.store.save()
2529
def test_simple_read_access(self):
2530
self.assertEquals('1', self.stack.get('one'))
2532
def test_simple_write_access(self):
2533
self.stack.set('one', 'one')
2534
self.assertEquals('one', self.stack.get('one'))
2536
def test_listen_to_the_last_speaker(self):
2538
c2 = self.get_stack(self)
2539
c1.set('one', 'ONE')
2540
c2.set('two', 'TWO')
2541
self.assertEquals('ONE', c1.get('one'))
2542
self.assertEquals('TWO', c2.get('two'))
2543
# The second update respect the first one
2544
self.assertEquals('ONE', c2.get('one'))
2546
def test_last_speaker_wins(self):
2547
# If the same config is not shared, the same variable modified twice
2548
# can only see a single result.
2550
c2 = self.get_stack(self)
2553
self.assertEquals('c2', c2.get('one'))
2554
# The first modification is still available until another refresh
2556
self.assertEquals('c1', c1.get('one'))
2557
c1.set('two', 'done')
2558
self.assertEquals('c2', c1.get('one'))
2560
def test_writes_are_serialized(self):
2562
c2 = self.get_stack(self)
2564
# We spawn a thread that will pause *during* the config saving.
2565
before_writing = threading.Event()
2566
after_writing = threading.Event()
2567
writing_done = threading.Event()
2568
c1_save_without_locking_orig = c1.store.save_without_locking
2569
def c1_save_without_locking():
2570
before_writing.set()
2571
c1_save_without_locking_orig()
2572
# The lock is held. We wait for the main thread to decide when to
2574
after_writing.wait()
2575
c1.store.save_without_locking = c1_save_without_locking
2579
t1 = threading.Thread(target=c1_set)
2580
# Collect the thread after the test
2581
self.addCleanup(t1.join)
2582
# Be ready to unblock the thread if the test goes wrong
2583
self.addCleanup(after_writing.set)
2585
before_writing.wait()
2586
self.assertRaises(errors.LockContention,
2587
c2.set, 'one', 'c2')
2588
self.assertEquals('c1', c1.get('one'))
2589
# Let the lock be released
2593
self.assertEquals('c2', c2.get('one'))
2595
def test_read_while_writing(self):
2597
# We spawn a thread that will pause *during* the write
2598
ready_to_write = threading.Event()
2599
do_writing = threading.Event()
2600
writing_done = threading.Event()
2601
# We override the _save implementation so we know the store is locked
2602
c1_save_without_locking_orig = c1.store.save_without_locking
2603
def c1_save_without_locking():
2604
ready_to_write.set()
2605
# The lock is held. We wait for the main thread to decide when to
2608
c1_save_without_locking_orig()
2610
c1.store.save_without_locking = c1_save_without_locking
2613
t1 = threading.Thread(target=c1_set)
2614
# Collect the thread after the test
2615
self.addCleanup(t1.join)
2616
# Be ready to unblock the thread if the test goes wrong
2617
self.addCleanup(do_writing.set)
2619
# Ensure the thread is ready to write
2620
ready_to_write.wait()
2621
self.assertEquals('c1', c1.get('one'))
2622
# If we read during the write, we get the old value
2623
c2 = self.get_stack(self)
2624
self.assertEquals('1', c2.get('one'))
2625
# Let the writing occur and ensure it occurred
2628
# Now we get the updated value
2629
c3 = self.get_stack(self)
2630
self.assertEquals('c1', c3.get('one'))
2632
# FIXME: It may be worth looking into removing the lock dir when it's not
2633
# needed anymore and look at possible fallouts for concurrent lockers. This
2634
# will matter if/when we use config files outside of bazaar directories
2635
# (.bazaar or .bzr) -- vila 20110-04-11
2638
class TestSectionMatcher(TestStore):
2640
scenarios = [('location', {'matcher': config.LocationMatcher})]
2642
def get_store(self, file_name):
2643
return config.IniFileStore(self.get_readonly_transport(), file_name)
2645
def test_no_matches_for_empty_stores(self):
2646
store = self.get_store('foo.conf')
2647
store._load_from_string('')
2648
matcher = self.matcher(store, '/bar')
2649
self.assertEquals([], list(matcher.get_sections()))
2651
def test_build_doesnt_load_store(self):
2652
store = self.get_store('foo.conf')
2653
matcher = self.matcher(store, '/bar')
2654
self.assertFalse(store.is_loaded())
2657
class TestLocationSection(tests.TestCase):
2659
def get_section(self, options, extra_path):
2660
section = config.Section('foo', options)
2661
# We don't care about the length so we use '0'
2662
return config.LocationSection(section, 0, extra_path)
2664
def test_simple_option(self):
2665
section = self.get_section({'foo': 'bar'}, '')
2666
self.assertEquals('bar', section.get('foo'))
2668
def test_option_with_extra_path(self):
2669
section = self.get_section({'foo': 'bar', 'foo:policy': 'appendpath'},
2671
self.assertEquals('bar/baz', section.get('foo'))
2673
def test_invalid_policy(self):
2674
section = self.get_section({'foo': 'bar', 'foo:policy': 'die'},
2676
# invalid policies are ignored
2677
self.assertEquals('bar', section.get('foo'))
2680
class TestLocationMatcher(TestStore):
2682
def get_store(self, file_name):
2683
return config.IniFileStore(self.get_readonly_transport(), file_name)
2685
def test_more_specific_sections_first(self):
2686
store = self.get_store('foo.conf')
2687
store._load_from_string('''
2693
self.assertEquals(['/foo', '/foo/bar'],
2694
[section.id for section in store.get_sections()])
2695
matcher = config.LocationMatcher(store, '/foo/bar/baz')
2696
sections = list(matcher.get_sections())
2697
self.assertEquals([3, 2],
2698
[section.length for section in sections])
2699
self.assertEquals(['/foo/bar', '/foo'],
2700
[section.id for section in sections])
2701
self.assertEquals(['baz', 'bar/baz'],
2702
[section.extra_path for section in sections])
2704
def test_appendpath_in_no_name_section(self):
2705
# It's a bit weird to allow appendpath in a no-name section, but
2706
# someone may found a use for it
2707
store = self.get_store('foo.conf')
2708
store._load_from_string('''
2710
foo:policy = appendpath
2712
matcher = config.LocationMatcher(store, 'dir/subdir')
2713
sections = list(matcher.get_sections())
2714
self.assertLength(1, sections)
2715
self.assertEquals('bar/dir/subdir', sections[0].get('foo'))
2717
def test_file_urls_are_normalized(self):
2718
store = self.get_store('foo.conf')
2719
if sys.platform == 'win32':
2720
expected_url = 'file:///C:/dir/subdir'
2721
expected_location = 'C:/dir/subdir'
2723
expected_url = 'file:///dir/subdir'
2724
expected_location = '/dir/subdir'
2725
matcher = config.LocationMatcher(store, expected_url)
2726
self.assertEquals(expected_location, matcher.location)
2729
class TestStackGet(tests.TestCase):
2731
# FIXME: This should be parametrized for all known Stack or dedicated
2732
# paramerized tests created to avoid bloating -- vila 2011-03-31
2734
def test_single_config_get(self):
2735
conf = dict(foo='bar')
2736
conf_stack = config.Stack([conf])
2737
self.assertEquals('bar', conf_stack.get('foo'))
2739
def test_get_with_registered_default_value(self):
2740
conf_stack = config.Stack([dict()])
2741
opt = config.Option('foo', default='bar')
2742
self.overrideAttr(config, 'option_registry', registry.Registry())
2743
config.option_registry.register('foo', opt)
2744
self.assertEquals('bar', conf_stack.get('foo'))
2746
def test_get_without_registered_default_value(self):
2747
conf_stack = config.Stack([dict()])
2748
opt = config.Option('foo')
2749
self.overrideAttr(config, 'option_registry', registry.Registry())
2750
config.option_registry.register('foo', opt)
2751
self.assertEquals(None, conf_stack.get('foo'))
2753
def test_get_without_default_value_for_not_registered(self):
2754
conf_stack = config.Stack([dict()])
2755
opt = config.Option('foo')
2756
self.overrideAttr(config, 'option_registry', registry.Registry())
2757
self.assertEquals(None, conf_stack.get('foo'))
2759
def test_get_first_definition(self):
2760
conf1 = dict(foo='bar')
2761
conf2 = dict(foo='baz')
2762
conf_stack = config.Stack([conf1, conf2])
2763
self.assertEquals('bar', conf_stack.get('foo'))
2765
def test_get_embedded_definition(self):
2766
conf1 = dict(yy='12')
2767
conf2 = config.Stack([dict(xx='42'), dict(foo='baz')])
2768
conf_stack = config.Stack([conf1, conf2])
2769
self.assertEquals('baz', conf_stack.get('foo'))
2771
def test_get_for_empty_section_callable(self):
2772
conf_stack = config.Stack([lambda : []])
2773
self.assertEquals(None, conf_stack.get('foo'))
2775
def test_get_for_broken_callable(self):
2776
# Trying to use and invalid callable raises an exception on first use
2777
conf_stack = config.Stack([lambda : object()])
2778
self.assertRaises(TypeError, conf_stack.get, 'foo')
2781
class TestStackWithTransport(tests.TestCaseWithTransport):
2783
scenarios = [(key, {'get_stack': builder}) for key, builder
2784
in config.test_stack_builder_registry.iteritems()]
2787
class TestConcreteStacks(TestStackWithTransport):
2789
def test_build_stack(self):
2790
# Just a smoke test to help debug builders
2791
stack = self.get_stack(self)
2794
class TestStackGet(TestStackWithTransport):
2796
def test_get_for_empty_stack(self):
2797
conf = self.get_stack(self)
2798
self.assertEquals(None, conf.get('foo'))
2800
def test_get_hook(self):
2801
conf = self.get_stack(self)
2802
conf.store._load_from_string('foo=bar')
2806
config.ConfigHooks.install_named_hook('get', hook, None)
2807
self.assertLength(0, calls)
2808
value = conf.get('foo')
2809
self.assertEquals('bar', value)
2810
self.assertLength(1, calls)
2811
self.assertEquals((conf, 'foo', 'bar'), calls[0])
2814
class TestStackSet(TestStackWithTransport):
2816
def test_simple_set(self):
2817
conf = self.get_stack(self)
2818
conf.store._load_from_string('foo=bar')
2819
self.assertEquals('bar', conf.get('foo'))
2820
conf.set('foo', 'baz')
2821
# Did we get it back ?
2822
self.assertEquals('baz', conf.get('foo'))
2824
def test_set_creates_a_new_section(self):
2825
conf = self.get_stack(self)
2826
conf.set('foo', 'baz')
2827
self.assertEquals, 'baz', conf.get('foo')
2829
def test_set_hook(self):
2833
config.ConfigHooks.install_named_hook('set', hook, None)
2834
self.assertLength(0, calls)
2835
conf = self.get_stack(self)
2836
conf.set('foo', 'bar')
2837
self.assertLength(1, calls)
2838
self.assertEquals((conf, 'foo', 'bar'), calls[0])
2841
class TestStackRemove(TestStackWithTransport):
2843
def test_remove_existing(self):
2844
conf = self.get_stack(self)
2845
conf.store._load_from_string('foo=bar')
2846
self.assertEquals('bar', conf.get('foo'))
2848
# Did we get it back ?
2849
self.assertEquals(None, conf.get('foo'))
2851
def test_remove_unknown(self):
2852
conf = self.get_stack(self)
2853
self.assertRaises(KeyError, conf.remove, 'I_do_not_exist')
2855
def test_remove_hook(self):
2859
config.ConfigHooks.install_named_hook('remove', hook, None)
2860
self.assertLength(0, calls)
2861
conf = self.get_stack(self)
2862
conf.store._load_from_string('foo=bar')
2864
self.assertLength(1, calls)
2865
self.assertEquals((conf, 'foo'), calls[0])
2868
class TestConfigGetOptions(tests.TestCaseWithTransport, TestOptionsMixin):
2871
super(TestConfigGetOptions, self).setUp()
2872
create_configs(self)
2874
def test_no_variable(self):
2875
# Using branch should query branch, locations and bazaar
2876
self.assertOptions([], self.branch_config)
2878
def test_option_in_bazaar(self):
2879
self.bazaar_config.set_user_option('file', 'bazaar')
2880
self.assertOptions([('file', 'bazaar', 'DEFAULT', 'bazaar')],
2883
def test_option_in_locations(self):
2884
self.locations_config.set_user_option('file', 'locations')
2886
[('file', 'locations', self.tree.basedir, 'locations')],
2887
self.locations_config)
2889
def test_option_in_branch(self):
2890
self.branch_config.set_user_option('file', 'branch')
2891
self.assertOptions([('file', 'branch', 'DEFAULT', 'branch')],
2894
def test_option_in_bazaar_and_branch(self):
2895
self.bazaar_config.set_user_option('file', 'bazaar')
2896
self.branch_config.set_user_option('file', 'branch')
2897
self.assertOptions([('file', 'branch', 'DEFAULT', 'branch'),
2898
('file', 'bazaar', 'DEFAULT', 'bazaar'),],
2901
def test_option_in_branch_and_locations(self):
2902
# Hmm, locations override branch :-/
2903
self.locations_config.set_user_option('file', 'locations')
2904
self.branch_config.set_user_option('file', 'branch')
2906
[('file', 'locations', self.tree.basedir, 'locations'),
2907
('file', 'branch', 'DEFAULT', 'branch'),],
2910
def test_option_in_bazaar_locations_and_branch(self):
2911
self.bazaar_config.set_user_option('file', 'bazaar')
2912
self.locations_config.set_user_option('file', 'locations')
2913
self.branch_config.set_user_option('file', 'branch')
2915
[('file', 'locations', self.tree.basedir, 'locations'),
2916
('file', 'branch', 'DEFAULT', 'branch'),
2917
('file', 'bazaar', 'DEFAULT', 'bazaar'),],
2921
class TestConfigRemoveOption(tests.TestCaseWithTransport, TestOptionsMixin):
2924
super(TestConfigRemoveOption, self).setUp()
2925
create_configs_with_file_option(self)
2927
def test_remove_in_locations(self):
2928
self.locations_config.remove_user_option('file', self.tree.basedir)
2930
[('file', 'branch', 'DEFAULT', 'branch'),
2931
('file', 'bazaar', 'DEFAULT', 'bazaar'),],
2934
def test_remove_in_branch(self):
2935
self.branch_config.remove_user_option('file')
2937
[('file', 'locations', self.tree.basedir, 'locations'),
2938
('file', 'bazaar', 'DEFAULT', 'bazaar'),],
2941
def test_remove_in_bazaar(self):
2942
self.bazaar_config.remove_user_option('file')
2944
[('file', 'locations', self.tree.basedir, 'locations'),
2945
('file', 'branch', 'DEFAULT', 'branch'),],
2949
class TestConfigGetSections(tests.TestCaseWithTransport):
2952
super(TestConfigGetSections, self).setUp()
2953
create_configs(self)
2955
def assertSectionNames(self, expected, conf, name=None):
2956
"""Check which sections are returned for a given config.
2958
If fallback configurations exist their sections can be included.
2960
:param expected: A list of section names.
2962
:param conf: The configuration that will be queried.
2964
:param name: An optional section name that will be passed to
2967
sections = list(conf._get_sections(name))
2968
self.assertLength(len(expected), sections)
2969
self.assertEqual(expected, [name for name, _, _ in sections])
2971
def test_bazaar_default_section(self):
2972
self.assertSectionNames(['DEFAULT'], self.bazaar_config)
2974
def test_locations_default_section(self):
2975
# No sections are defined in an empty file
2976
self.assertSectionNames([], self.locations_config)
2978
def test_locations_named_section(self):
2979
self.locations_config.set_user_option('file', 'locations')
2980
self.assertSectionNames([self.tree.basedir], self.locations_config)
2982
def test_locations_matching_sections(self):
2983
loc_config = self.locations_config
2984
loc_config.set_user_option('file', 'locations')
2985
# We need to cheat a bit here to create an option in sections above and
2986
# below the 'location' one.
2987
parser = loc_config._get_parser()
2988
# locations.cong deals with '/' ignoring native os.sep
2989
location_names = self.tree.basedir.split('/')
2990
parent = '/'.join(location_names[:-1])
2991
child = '/'.join(location_names + ['child'])
2993
parser[parent]['file'] = 'parent'
2995
parser[child]['file'] = 'child'
2996
self.assertSectionNames([self.tree.basedir, parent], loc_config)
2998
def test_branch_data_default_section(self):
2999
self.assertSectionNames([None],
3000
self.branch_config._get_branch_data_config())
3002
def test_branch_default_sections(self):
3003
# No sections are defined in an empty locations file
3004
self.assertSectionNames([None, 'DEFAULT'],
3006
# Unless we define an option
3007
self.branch_config._get_location_config().set_user_option(
3008
'file', 'locations')
3009
self.assertSectionNames([self.tree.basedir, None, 'DEFAULT'],
3012
def test_bazaar_named_section(self):
3013
# We need to cheat as the API doesn't give direct access to sections
3014
# other than DEFAULT.
3015
self.bazaar_config.set_alias('bazaar', 'bzr')
3016
self.assertSectionNames(['ALIASES'], self.bazaar_config, 'ALIASES')
1315
3019
class TestAuthenticationConfigFile(tests.TestCase):
1316
3020
"""Test the authentication.conf file matching"""