367
495
'/home/bogus/.cache')
370
class TestIniConfig(tests.TestCase):
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
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)
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')
515
self.assertEqual(config.config_dir(), newdir)
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')
523
self.assertEqual(config.config_dir(), newdir)
526
class TestIniConfig(tests.TestCaseInTempDir):
372
528
def make_config_parser(self, s):
373
conf = config.IniBasedConfig(None)
374
parser = conf._get_parser(file=StringIO(s.encode('utf-8')))
529
conf = config.IniBasedConfig.from_string(s)
530
return conf, conf._get_parser()
378
533
class TestIniConfigBuilding(TestIniConfig):
380
535
def test_contructs(self):
381
my_config = config.IniBasedConfig("nothing")
536
my_config = config.IniBasedConfig()
383
538
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))
539
my_config = config.IniBasedConfig.from_string(sample_config_text)
540
self.assertIsInstance(my_config._get_parser(), configobj.ConfigObj)
390
542
def test_cached(self):
543
my_config = config.IniBasedConfig.from_string(sample_config_text)
544
parser = my_config._get_parser()
545
self.assertTrue(my_config._get_parser() is parser)
547
def _dummy_chown(self, path, uid, gid):
548
self.path, self.uid, self.gid = path, uid, gid
550
def test_ini_config_ownership(self):
551
"""Ensure that chown is happening during _write_config_file"""
552
self.requireFeature(features.chown_feature)
553
self.overrideAttr(os, 'chown', self._dummy_chown)
554
self.path = self.uid = self.gid = None
555
conf = config.IniBasedConfig(file_name='./foo.conf')
556
conf._write_config_file()
557
self.assertEquals(self.path, './foo.conf')
558
self.assertTrue(isinstance(self.uid, int))
559
self.assertTrue(isinstance(self.gid, int))
561
def test_get_filename_parameter_is_deprecated_(self):
562
conf = self.callDeprecated([
563
'IniBasedConfig.__init__(get_filename) was deprecated in 2.3.'
564
' Use file_name instead.'],
565
config.IniBasedConfig, lambda: 'ini.conf')
566
self.assertEqual('ini.conf', conf.file_name)
568
def test_get_parser_file_parameter_is_deprecated_(self):
391
569
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)
570
conf = config.IniBasedConfig.from_string(sample_config_text)
571
conf = self.callDeprecated([
572
'IniBasedConfig._get_parser(file=xxx) was deprecated in 2.3.'
573
' Use IniBasedConfig(_content=xxx) instead.'],
574
conf._get_parser, file=config_file)
577
class TestIniConfigSaving(tests.TestCaseInTempDir):
579
def test_cant_save_without_a_file_name(self):
580
conf = config.IniBasedConfig()
581
self.assertRaises(AssertionError, conf._write_config_file)
583
def test_saved_with_content(self):
584
content = 'foo = bar\n'
585
conf = config.IniBasedConfig.from_string(
586
content, file_name='./test.conf', save=True)
587
self.assertFileEqual(content, 'test.conf')
590
class TestIniConfigOptionExpansionDefaultValue(tests.TestCaseInTempDir):
591
"""What is the default value of expand for config options.
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
598
Note that these tests relies on config._expand_default_value being already
599
overwritten in the parent class setUp.
603
super(TestIniConfigOptionExpansionDefaultValue, self).setUp()
607
self.warnings.append(args[0] % args[1:])
608
self.overrideAttr(trace, 'warning', warning)
610
def get_config(self, expand):
611
c = config.GlobalConfig.from_string('bzr.config.expand=%s' % (expand,),
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)
620
def test_default_is_None(self):
621
self.assertEquals(None, config._expand_default_value)
623
def test_default_is_False_even_if_None(self):
624
self.config = self.get_config(None)
625
self.assertExpandIs(False)
627
def test_default_is_False_even_if_invalid(self):
628
self.config = self.get_config('<your choice>')
629
self.assertExpandIs(False)
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)
635
'Value "<your choice>" is not a boolean for "bzr.config.expand"',
638
def test_default_is_True(self):
639
self.config = self.get_config(True)
640
self.assertExpandIs(True)
642
def test_default_is_False(self):
643
self.config = self.get_config(False)
644
self.assertExpandIs(False)
647
class TestIniConfigOptionExpansion(tests.TestCase):
648
"""Test option expansion from the IniConfig level.
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
654
# FIXME: This should be rewritten when all configs share a storage
655
# implementation -- vila 2011-02-18
657
def get_config(self, string=None):
660
c = config.IniBasedConfig.from_string(string)
663
def assertExpansion(self, expected, conf, string, env=None):
664
self.assertEquals(expected, conf.expand_options(string, env))
666
def test_no_expansion(self):
667
c = self.get_config('')
668
self.assertExpansion('foo', c, 'foo')
670
def test_env_adding_options(self):
671
c = self.get_config('')
672
self.assertExpansion('bar', c, '{foo}', {'foo': 'bar'})
674
def test_env_overriding_options(self):
675
c = self.get_config('foo=baz')
676
self.assertExpansion('bar', c, '{foo}', {'foo': 'bar'})
678
def test_simple_ref(self):
679
c = self.get_config('foo=xxx')
680
self.assertExpansion('xxx', c, '{foo}')
682
def test_unknown_ref(self):
683
c = self.get_config('')
684
self.assertRaises(errors.ExpandingUnknownOption,
685
c.expand_options, '{foo}')
687
def test_indirect_ref(self):
688
c = self.get_config('''
692
self.assertExpansion('xxx', c, '{bar}')
694
def test_embedded_ref(self):
695
c = self.get_config('''
699
self.assertExpansion('xxx', c, '{{bar}}')
701
def test_simple_loop(self):
702
c = self.get_config('foo={foo}')
703
self.assertRaises(errors.OptionExpansionLoop, c.expand_options, '{foo}')
705
def test_indirect_loop(self):
706
c = self.get_config('''
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)
716
conf = self.get_config('''
720
list={foo},{bar},{baz}
722
self.assertEquals(['start', 'middle', 'end'],
723
conf.get_user_option('list', expand=True))
725
def test_cascading_list(self):
726
conf = self.get_config('''
732
self.assertEquals(['start', 'middle', 'end'],
733
conf.get_user_option('list', expand=True))
735
def test_pathological_hidden_list(self):
736
conf = self.get_config('''
742
hidden={start}{middle}{end}
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))
749
class TestLocationConfigOptionExpansion(tests.TestCaseInTempDir):
751
def get_config(self, location, string=None):
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)
759
def test_dont_cross_unrelated_section(self):
760
c = self.get_config('/another/branch/path','''
765
[/another/branch/path]
768
self.assertRaises(errors.ExpandingUnknownOption,
769
c.get_user_option, 'bar', expand=True)
771
def test_cross_related_sections(self):
772
c = self.get_config('/project/branch/path','''
776
[/project/branch/path]
779
self.assertEquals('quux', c.get_user_option('bar', expand=True))
782
class TestIniBaseConfigOnDisk(tests.TestCaseInTempDir):
784
def test_cannot_reload_without_name(self):
785
conf = config.IniBasedConfig.from_string(sample_config_text)
786
self.assertRaises(AssertionError, conf.reload)
788
def test_reload_see_new_value(self):
789
c1 = config.IniBasedConfig.from_string('editor=vim\n',
790
file_name='./test/conf')
791
c1._write_config_file()
792
c2 = config.IniBasedConfig.from_string('editor=emacs\n',
793
file_name='./test/conf')
794
c2._write_config_file()
795
self.assertEqual('vim', c1.get_user_option('editor'))
796
self.assertEqual('emacs', c2.get_user_option('editor'))
797
# Make sure we get the Right value
799
self.assertEqual('emacs', c1.get_user_option('editor'))
802
class TestLockableConfig(tests.TestCaseInTempDir):
804
scenarios = lockable_config_scenarios()
809
config_section = None
812
super(TestLockableConfig, self).setUp()
813
self._content = '[%s]\none=1\ntwo=2\n' % (self.config_section,)
814
self.config = self.create_config(self._content)
816
def get_existing_config(self):
817
return self.config_class(*self.config_args)
819
def create_config(self, content):
820
kwargs = dict(save=True)
821
c = self.config_class.from_string(content, *self.config_args, **kwargs)
824
def test_simple_read_access(self):
825
self.assertEquals('1', self.config.get_user_option('one'))
827
def test_simple_write_access(self):
828
self.config.set_user_option('one', 'one')
829
self.assertEquals('one', self.config.get_user_option('one'))
831
def test_listen_to_the_last_speaker(self):
833
c2 = self.get_existing_config()
834
c1.set_user_option('one', 'ONE')
835
c2.set_user_option('two', 'TWO')
836
self.assertEquals('ONE', c1.get_user_option('one'))
837
self.assertEquals('TWO', c2.get_user_option('two'))
838
# The second update respect the first one
839
self.assertEquals('ONE', c2.get_user_option('one'))
841
def test_last_speaker_wins(self):
842
# If the same config is not shared, the same variable modified twice
843
# can only see a single result.
845
c2 = self.get_existing_config()
846
c1.set_user_option('one', 'c1')
847
c2.set_user_option('one', 'c2')
848
self.assertEquals('c2', c2._get_user_option('one'))
849
# The first modification is still available until another refresh
851
self.assertEquals('c1', c1._get_user_option('one'))
852
c1.set_user_option('two', 'done')
853
self.assertEquals('c2', c1._get_user_option('one'))
855
def test_writes_are_serialized(self):
857
c2 = self.get_existing_config()
859
# We spawn a thread that will pause *during* the write
860
before_writing = threading.Event()
861
after_writing = threading.Event()
862
writing_done = threading.Event()
863
c1_orig = c1._write_config_file
864
def c1_write_config_file():
867
# The lock is held. We wait for the main thread to decide when to
870
c1._write_config_file = c1_write_config_file
872
c1.set_user_option('one', 'c1')
874
t1 = threading.Thread(target=c1_set_option)
875
# Collect the thread after the test
876
self.addCleanup(t1.join)
877
# Be ready to unblock the thread if the test goes wrong
878
self.addCleanup(after_writing.set)
880
before_writing.wait()
881
self.assertTrue(c1._lock.is_held)
882
self.assertRaises(errors.LockContention,
883
c2.set_user_option, 'one', 'c2')
884
self.assertEquals('c1', c1.get_user_option('one'))
885
# Let the lock be released
888
c2.set_user_option('one', 'c2')
889
self.assertEquals('c2', c2.get_user_option('one'))
891
def test_read_while_writing(self):
893
# We spawn a thread that will pause *during* the write
894
ready_to_write = threading.Event()
895
do_writing = threading.Event()
896
writing_done = threading.Event()
897
c1_orig = c1._write_config_file
898
def c1_write_config_file():
900
# The lock is held. We wait for the main thread to decide when to
905
c1._write_config_file = c1_write_config_file
907
c1.set_user_option('one', 'c1')
908
t1 = threading.Thread(target=c1_set_option)
909
# Collect the thread after the test
910
self.addCleanup(t1.join)
911
# Be ready to unblock the thread if the test goes wrong
912
self.addCleanup(do_writing.set)
914
# Ensure the thread is ready to write
915
ready_to_write.wait()
916
self.assertTrue(c1._lock.is_held)
917
self.assertEquals('c1', c1.get_user_option('one'))
918
# If we read during the write, we get the old value
919
c2 = self.get_existing_config()
920
self.assertEquals('1', c2.get_user_option('one'))
921
# Let the writing occur and ensure it occurred
924
# Now we get the updated value
925
c3 = self.get_existing_config()
926
self.assertEquals('c1', c3.get_user_option('one'))
397
929
class TestGetUserOptionAs(TestIniConfig):
1312
1846
self.assertIs(None, bzrdir_config.get_default_stack_on())
1849
class TestSection(tests.TestCase):
1851
# FIXME: Parametrize so that all sections produced by Stores run these
1852
# tests -- vila 2011-04-01
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'))
1859
def test_get_unknown_option(self):
1861
section = config.Section(None, a_dict)
1862
self.assertEquals('out of thin air',
1863
section.get('foo', 'out of thin air'))
1865
def test_options_is_shared(self):
1867
section = config.Section(None, a_dict)
1868
self.assertIs(a_dict, section.options)
1871
class TestMutableSection(tests.TestCase):
1873
# FIXME: Parametrize so that all sections (including os.environ and the
1874
# ones produced by Stores) run these tests -- vila 2011-04-01
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'))
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'))
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'))
1909
def test_remove_new_option(self):
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'])
1921
class TestStore(tests.TestCaseWithTransport):
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)
1929
dict([(k, section.get(k)) for k in expected_options.keys()]))
1932
class TestReadonlyStore(TestStore):
1934
scenarios = [(key, {'get_store': builder})
1935
for key, builder in test_store_builder_registry.iteritems()]
1938
super(TestReadonlyStore, self).setUp()
1939
self.branch = self.make_branch('branch')
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())
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()))
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])
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])
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')
1972
class TestMutableStore(TestStore):
1974
scenarios = [(key, {'store_id': key, 'get_store': builder})
1975
for key, builder in test_store_builder_registry.iteritems()]
1978
super(TestMutableStore, self).setUp()
1979
self.transport = self.get_transport()
1980
self.branch = self.make_branch('branch')
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)
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)
1993
self.assertEquals(False, self.has_store(store))
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')
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)
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))
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])
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')
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])
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')
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])
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')
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])
2053
class TestIniFileStore(TestStore):
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)
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())
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('''
2079
foo_in_DEFAULT=foo_DEFAULT
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']}),
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'}}),
2103
class TestLockableIniFileStore(TestStore):
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')
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
2122
class TestSectionMatcher(TestStore):
2124
scenarios = [('location', {'matcher': config.LocationMatcher})]
2126
def get_store(self, file_name):
2127
return config.IniFileStore(self.get_readonly_transport(), file_name)
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()))
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())
2141
class TestLocationSection(tests.TestCase):
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)
2148
def test_simple_option(self):
2149
section = self.get_section({'foo': 'bar'}, '')
2150
self.assertEquals('bar', section.get('foo'))
2152
def test_option_with_extra_path(self):
2153
section = self.get_section({'foo': 'bar', 'foo:policy': 'appendpath'},
2155
self.assertEquals('bar/baz', section.get('foo'))
2157
def test_invalid_policy(self):
2158
section = self.get_section({'foo': 'bar', 'foo:policy': 'die'},
2160
# invalid policies are ignored
2161
self.assertEquals('bar', section.get('foo'))
2164
class TestLocationMatcher(TestStore):
2166
def get_store(self, file_name):
2167
return config.IniFileStore(self.get_readonly_transport(), file_name)
2169
def test_more_specific_sections_first(self):
2170
store = self.get_store('foo.conf')
2171
store._load_from_string('''
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])
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('''
2194
foo:policy = appendpath
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'))
2201
def test_file_urls_are_normalized(self):
2202
store = self.get_store('foo.conf')
2203
matcher = config.LocationMatcher(store, 'file:///dir/subdir')
2204
self.assertEquals('/dir/subdir', matcher.location)
2207
class TestStackGet(tests.TestCase):
2209
# FIXME: This should be parametrized for all known Stack or dedicated
2210
# paramerized tests created to avoid bloating -- vila 2011-03-31
2212
def test_single_config_get(self):
2213
conf = dict(foo='bar')
2214
conf_stack = config.Stack([conf])
2215
self.assertEquals('bar', conf_stack.get('foo'))
2217
def test_get_first_definition(self):
2218
conf1 = dict(foo='bar')
2219
conf2 = dict(foo='baz')
2220
conf_stack = config.Stack([conf1, conf2])
2221
self.assertEquals('bar', conf_stack.get('foo'))
2223
def test_get_embedded_definition(self):
2224
conf1 = dict(yy='12')
2225
conf2 = config.Stack([dict(xx='42'), dict(foo='baz')])
2226
conf_stack = config.Stack([conf1, conf2])
2227
self.assertEquals('baz', conf_stack.get('foo'))
2229
def test_get_for_empty_stack(self):
2230
conf_stack = config.Stack([])
2231
self.assertEquals(None, conf_stack.get('foo'))
2233
def test_get_for_empty_section_callable(self):
2234
conf_stack = config.Stack([lambda : []])
2235
self.assertEquals(None, conf_stack.get('foo'))
2237
def test_get_for_broken_callable(self):
2238
# Trying to use and invalid callable raises an exception on first use
2239
conf_stack = config.Stack([lambda : object()])
2240
self.assertRaises(TypeError, conf_stack.get, 'foo')
2243
class TestStackWithTransport(tests.TestCaseWithTransport):
2246
super(TestStackWithTransport, self).setUp()
2247
# FIXME: A more elaborate builder for the stack would avoid building a
2248
# branch even for tests that don't need it.
2249
self.branch = self.make_branch('branch')
2252
class TestStackSet(TestStackWithTransport):
2254
scenarios = [(key, {'get_stack': builder})
2255
for key, builder in test_stack_builder_registry.iteritems()]
2257
def test_simple_set(self):
2258
conf = self.get_stack(self)
2259
conf.store._load_from_string('foo=bar')
2260
self.assertEquals('bar', conf.get('foo'))
2261
conf.set('foo', 'baz')
2262
# Did we get it back ?
2263
self.assertEquals('baz', conf.get('foo'))
2265
def test_set_creates_a_new_section(self):
2266
conf = self.get_stack(self)
2267
conf.set('foo', 'baz')
2268
self.assertEquals, 'baz', conf.get('foo')
2271
class TestStackRemove(TestStackWithTransport):
2273
scenarios = [(key, {'get_stack': builder})
2274
for key, builder in test_stack_builder_registry.iteritems()]
2276
def test_remove_existing(self):
2277
conf = self.get_stack(self)
2278
conf.store._load_from_string('foo=bar')
2279
self.assertEquals('bar', conf.get('foo'))
2281
# Did we get it back ?
2282
self.assertEquals(None, conf.get('foo'))
2284
def test_remove_unknown(self):
2285
conf = self.get_stack(self)
2286
self.assertRaises(KeyError, conf.remove, 'I_do_not_exist')
2289
class TestConcreteStacks(TestStackWithTransport):
2291
scenarios = [(key, {'get_stack': builder})
2292
for key, builder in test_stack_builder_registry.iteritems()]
2294
def test_build_stack(self):
2295
stack = self.get_stack(self)
2298
class TestConfigGetOptions(tests.TestCaseWithTransport, TestOptionsMixin):
2301
super(TestConfigGetOptions, self).setUp()
2302
create_configs(self)
2304
def test_no_variable(self):
2305
# Using branch should query branch, locations and bazaar
2306
self.assertOptions([], self.branch_config)
2308
def test_option_in_bazaar(self):
2309
self.bazaar_config.set_user_option('file', 'bazaar')
2310
self.assertOptions([('file', 'bazaar', 'DEFAULT', 'bazaar')],
2313
def test_option_in_locations(self):
2314
self.locations_config.set_user_option('file', 'locations')
2316
[('file', 'locations', self.tree.basedir, 'locations')],
2317
self.locations_config)
2319
def test_option_in_branch(self):
2320
self.branch_config.set_user_option('file', 'branch')
2321
self.assertOptions([('file', 'branch', 'DEFAULT', 'branch')],
2324
def test_option_in_bazaar_and_branch(self):
2325
self.bazaar_config.set_user_option('file', 'bazaar')
2326
self.branch_config.set_user_option('file', 'branch')
2327
self.assertOptions([('file', 'branch', 'DEFAULT', 'branch'),
2328
('file', 'bazaar', 'DEFAULT', 'bazaar'),],
2331
def test_option_in_branch_and_locations(self):
2332
# Hmm, locations override branch :-/
2333
self.locations_config.set_user_option('file', 'locations')
2334
self.branch_config.set_user_option('file', 'branch')
2336
[('file', 'locations', self.tree.basedir, 'locations'),
2337
('file', 'branch', 'DEFAULT', 'branch'),],
2340
def test_option_in_bazaar_locations_and_branch(self):
2341
self.bazaar_config.set_user_option('file', 'bazaar')
2342
self.locations_config.set_user_option('file', 'locations')
2343
self.branch_config.set_user_option('file', 'branch')
2345
[('file', 'locations', self.tree.basedir, 'locations'),
2346
('file', 'branch', 'DEFAULT', 'branch'),
2347
('file', 'bazaar', 'DEFAULT', 'bazaar'),],
2351
class TestConfigRemoveOption(tests.TestCaseWithTransport, TestOptionsMixin):
2354
super(TestConfigRemoveOption, self).setUp()
2355
create_configs_with_file_option(self)
2357
def test_remove_in_locations(self):
2358
self.locations_config.remove_user_option('file', self.tree.basedir)
2360
[('file', 'branch', 'DEFAULT', 'branch'),
2361
('file', 'bazaar', 'DEFAULT', 'bazaar'),],
2364
def test_remove_in_branch(self):
2365
self.branch_config.remove_user_option('file')
2367
[('file', 'locations', self.tree.basedir, 'locations'),
2368
('file', 'bazaar', 'DEFAULT', 'bazaar'),],
2371
def test_remove_in_bazaar(self):
2372
self.bazaar_config.remove_user_option('file')
2374
[('file', 'locations', self.tree.basedir, 'locations'),
2375
('file', 'branch', 'DEFAULT', 'branch'),],
2379
class TestConfigGetSections(tests.TestCaseWithTransport):
2382
super(TestConfigGetSections, self).setUp()
2383
create_configs(self)
2385
def assertSectionNames(self, expected, conf, name=None):
2386
"""Check which sections are returned for a given config.
2388
If fallback configurations exist their sections can be included.
2390
:param expected: A list of section names.
2392
:param conf: The configuration that will be queried.
2394
:param name: An optional section name that will be passed to
2397
sections = list(conf._get_sections(name))
2398
self.assertLength(len(expected), sections)
2399
self.assertEqual(expected, [name for name, _, _ in sections])
2401
def test_bazaar_default_section(self):
2402
self.assertSectionNames(['DEFAULT'], self.bazaar_config)
2404
def test_locations_default_section(self):
2405
# No sections are defined in an empty file
2406
self.assertSectionNames([], self.locations_config)
2408
def test_locations_named_section(self):
2409
self.locations_config.set_user_option('file', 'locations')
2410
self.assertSectionNames([self.tree.basedir], self.locations_config)
2412
def test_locations_matching_sections(self):
2413
loc_config = self.locations_config
2414
loc_config.set_user_option('file', 'locations')
2415
# We need to cheat a bit here to create an option in sections above and
2416
# below the 'location' one.
2417
parser = loc_config._get_parser()
2418
# locations.cong deals with '/' ignoring native os.sep
2419
location_names = self.tree.basedir.split('/')
2420
parent = '/'.join(location_names[:-1])
2421
child = '/'.join(location_names + ['child'])
2423
parser[parent]['file'] = 'parent'
2425
parser[child]['file'] = 'child'
2426
self.assertSectionNames([self.tree.basedir, parent], loc_config)
2428
def test_branch_data_default_section(self):
2429
self.assertSectionNames([None],
2430
self.branch_config._get_branch_data_config())
2432
def test_branch_default_sections(self):
2433
# No sections are defined in an empty locations file
2434
self.assertSectionNames([None, 'DEFAULT'],
2436
# Unless we define an option
2437
self.branch_config._get_location_config().set_user_option(
2438
'file', 'locations')
2439
self.assertSectionNames([self.tree.basedir, None, 'DEFAULT'],
2442
def test_bazaar_named_section(self):
2443
# We need to cheat as the API doesn't give direct access to sections
2444
# other than DEFAULT.
2445
self.bazaar_config.set_alias('bazaar', 'bzr')
2446
self.assertSectionNames(['ALIASES'], self.bazaar_config, 'ALIASES')
1315
2449
class TestAuthenticationConfigFile(tests.TestCase):
1316
2450
"""Test the authentication.conf file matching"""