176
163
# creating a dedicated helper to create only the bzrdir
177
164
build_backing_branch(test, 'branch', transport_class, server_class)
178
165
b = branch.Branch.open(test.get_url('branch'))
179
return config.RemoteControlStack(b.controldir)
166
return config.RemoteControlStack(b.bzrdir)
182
167
config.test_stack_builder_registry.register('remote_control',
183
168
build_remote_control_stack)
186
sample_long_alias = "log -r-15..-1 --line"
171
sample_long_alias="log -r-15..-1 --line"
187
172
sample_config_text = u"""
189
174
email=Erik B\u00e5gfors <erik@bagfors.nu>
191
change_editor=vimdiff -of {new_path} {old_path}
176
change_editor=vimdiff -of @new_path @old_path
177
gpg_signing_command=gnome-gpg
192
178
gpg_signing_key=DD4D5088
194
180
validate_signatures_in_log=true
512
498
change_editor = my_config.get_change_editor('old_tree', 'new_tree')
513
499
self.assertEqual(['_get_change_editor'], my_config._calls)
514
500
self.assertIs(diff.DiffFromTool, change_editor.__class__)
515
self.assertEqual(['vimdiff', '-fo', '{new_path}', '{old_path}'],
516
change_editor.command_template)
518
def test_get_change_editor_implicit_args(self):
519
# If there are no substitution variables, then assume the
520
# old and new path are the last arguments.
521
my_config = InstrumentedConfig()
522
my_config._change_editor = 'vimdiff -o'
523
change_editor = my_config.get_change_editor('old_tree', 'new_tree')
524
self.assertEqual(['_get_change_editor'], my_config._calls)
525
self.assertIs(diff.DiffFromTool, change_editor.__class__)
526
self.assertEqual(['vimdiff', '-o', '{old_path}', '{new_path}'],
527
change_editor.command_template)
529
def test_get_change_editor_old_style(self):
530
# Test the old style format for the change_editor setting.
531
my_config = InstrumentedConfig()
532
my_config._change_editor = 'vimdiff -o @old_path @new_path'
533
change_editor = my_config.get_change_editor('old_tree', 'new_tree')
534
self.assertEqual(['_get_change_editor'], my_config._calls)
535
self.assertIs(diff.DiffFromTool, change_editor.__class__)
536
self.assertEqual(['vimdiff', '-o', '{old_path}', '{new_path}'],
537
change_editor.command_template)
501
self.assertEqual(['vimdiff', '-fo', '@new_path', '@old_path'],
502
change_editor.command_template)
505
class TestConfigPath(tests.TestCase):
508
super(TestConfigPath, self).setUp()
509
self.overrideEnv('HOME', '/home/bogus')
510
self.overrideEnv('XDG_CACHE_HOME', '')
511
if sys.platform == 'win32':
514
r'C:\Documents and Settings\bogus\Application Data')
516
'C:/Documents and Settings/bogus/Application Data/breezy'
518
self.brz_home = '/home/bogus/.config/breezy'
520
def test_config_dir(self):
521
self.assertEqual(config.config_dir(), self.brz_home)
523
def test_config_dir_is_unicode(self):
524
self.assertIsInstance(config.config_dir(), unicode)
526
def test_config_filename(self):
527
self.assertEqual(config.config_filename(),
528
self.brz_home + '/bazaar.conf')
530
def test_locations_config_filename(self):
531
self.assertEqual(config.locations_config_filename(),
532
self.brz_home + '/locations.conf')
534
def test_authentication_config_filename(self):
535
self.assertEqual(config.authentication_config_filename(),
536
self.brz_home + '/authentication.conf')
538
def test_xdg_cache_dir(self):
539
self.assertEqual(config.xdg_cache_dir(),
540
'/home/bogus/.cache')
543
class TestXDGConfigDir(tests.TestCaseInTempDir):
544
# must be in temp dir because config tests for the existence of the bazaar
545
# subdirectory of $XDG_CONFIG_HOME
548
if sys.platform == 'win32':
549
raise tests.TestNotApplicable(
550
'XDG config dir not used on this platform')
551
super(TestXDGConfigDir, self).setUp()
552
self.overrideEnv('HOME', self.test_home_dir)
553
# BRZ_HOME overrides everything we want to test so unset it.
554
self.overrideEnv('BRZ_HOME', None)
556
def test_xdg_config_dir_exists(self):
557
"""When ~/.config/bazaar exists, use it as the config dir."""
558
newdir = osutils.pathjoin(self.test_home_dir, '.config', 'bazaar')
560
self.assertEqual(config.config_dir(), newdir)
562
def test_xdg_config_home(self):
563
"""When XDG_CONFIG_HOME is set, use it."""
564
xdgconfigdir = osutils.pathjoin(self.test_home_dir, 'xdgconfig')
565
self.overrideEnv('XDG_CONFIG_HOME', xdgconfigdir)
566
newdir = osutils.pathjoin(xdgconfigdir, 'bazaar')
568
self.assertEqual(config.config_dir(), newdir)
540
571
class TestIniConfig(tests.TestCaseInTempDir):
835
863
self.assertEqual('c2', c2.get_user_option('one'))
837
865
def test_read_while_writing(self):
839
# We spawn a thread that will pause *during* the write
840
ready_to_write = threading.Event()
841
do_writing = threading.Event()
842
writing_done = threading.Event()
843
c1_orig = c1._write_config_file
845
def c1_write_config_file():
847
# The lock is held. We wait for the main thread to decide when to
852
c1._write_config_file = c1_write_config_file
855
c1.set_user_option('one', 'c1')
856
t1 = threading.Thread(target=c1_set_option)
857
# Collect the thread after the test
858
self.addCleanup(t1.join)
859
# Be ready to unblock the thread if the test goes wrong
860
self.addCleanup(do_writing.set)
862
# Ensure the thread is ready to write
863
ready_to_write.wait()
864
self.assertTrue(c1._lock.is_held)
865
self.assertEqual('c1', c1.get_user_option('one'))
866
# If we read during the write, we get the old value
867
c2 = self.get_existing_config()
868
self.assertEqual('1', c2.get_user_option('one'))
869
# Let the writing occur and ensure it occurred
872
# Now we get the updated value
873
c3 = self.get_existing_config()
874
self.assertEqual('c1', c3.get_user_option('one'))
867
# We spawn a thread that will pause *during* the write
868
ready_to_write = threading.Event()
869
do_writing = threading.Event()
870
writing_done = threading.Event()
871
c1_orig = c1._write_config_file
872
def c1_write_config_file():
874
# The lock is held. We wait for the main thread to decide when to
879
c1._write_config_file = c1_write_config_file
881
c1.set_user_option('one', 'c1')
882
t1 = threading.Thread(target=c1_set_option)
883
# Collect the thread after the test
884
self.addCleanup(t1.join)
885
# Be ready to unblock the thread if the test goes wrong
886
self.addCleanup(do_writing.set)
888
# Ensure the thread is ready to write
889
ready_to_write.wait()
890
self.assertTrue(c1._lock.is_held)
891
self.assertEqual('c1', c1.get_user_option('one'))
892
# If we read during the write, we get the old value
893
c2 = self.get_existing_config()
894
self.assertEqual('1', c2.get_user_option('one'))
895
# Let the writing occur and ensure it occurred
898
# Now we get the updated value
899
c3 = self.get_existing_config()
900
self.assertEqual('c1', c3.get_user_option('one'))
877
903
class TestGetUserOptionAs(TestIniConfig):
1277
1300
self.get_branch_config('http://www.example.com')
1278
1301
self.assertEqual(
1279
1302
self.my_location_config._get_config_policy(
1280
'http://www.example.com', 'normal_option'),
1303
'http://www.example.com', 'normal_option'),
1281
1304
config.POLICY_NONE)
1283
1306
def test__get_option_policy_norecurse(self):
1284
1307
self.get_branch_config('http://www.example.com')
1285
1308
self.assertEqual(
1286
1309
self.my_location_config._get_option_policy(
1287
'http://www.example.com', 'norecurse_option'),
1310
'http://www.example.com', 'norecurse_option'),
1288
1311
config.POLICY_NORECURSE)
1289
1312
# Test old recurse=False setting:
1290
1313
self.assertEqual(
1291
1314
self.my_location_config._get_option_policy(
1292
'http://www.example.com/norecurse', 'normal_option'),
1315
'http://www.example.com/norecurse', 'normal_option'),
1293
1316
config.POLICY_NORECURSE)
1295
1318
def test__get_option_policy_normal(self):
1296
1319
self.get_branch_config('http://www.example.com')
1297
1320
self.assertEqual(
1298
1321
self.my_location_config._get_option_policy(
1299
'http://www.example.com', 'appendpath_option'),
1322
'http://www.example.com', 'appendpath_option'),
1300
1323
config.POLICY_APPENDPATH)
1302
1325
def test__get_options_with_policy(self):
1579
1593
def test_load_non_ascii(self):
1580
1594
"""Ensure we display a proper error on non-ascii, non utf-8 content."""
1581
1595
t = self.get_transport()
1582
t.put_bytes('foo.conf', b'user=foo\n#\xff\n')
1596
t.put_bytes('foo.conf', 'user=foo\n#\xff\n')
1583
1597
conf = config.TransportConfig(t, 'foo.conf')
1584
self.assertRaises(config.ConfigContentError, conf._get_configobj)
1598
self.assertRaises(errors.ConfigContentError, conf._get_configobj)
1586
1600
def test_load_erroneous_content(self):
1587
1601
"""Ensure we display a proper error on content that can't be parsed."""
1588
1602
t = self.get_transport()
1589
t.put_bytes('foo.conf', b'[open_section\n')
1603
t.put_bytes('foo.conf', '[open_section\n')
1590
1604
conf = config.TransportConfig(t, 'foo.conf')
1591
self.assertRaises(config.ParseConfigError, conf._get_configobj)
1605
self.assertRaises(errors.ParseConfigError, conf._get_configobj)
1593
1607
def test_load_permission_denied(self):
1594
1608
"""Ensure we get an empty config file if the file is inaccessible."""
1597
1610
def warning(*args):
1598
1611
warnings.append(args[0] % args[1:])
1599
1612
self.overrideAttr(trace, 'warning', warning)
2200
2202
# the option name which indirectly requires that the option name is a
2201
2203
# valid python identifier. We violate that rule here (using a key that
2202
2204
# doesn't match the option name) to test the option name checking.
2203
self.assertRaises(config.IllegalOptionName,
2205
self.assertRaises(errors.IllegalOptionName,
2204
2206
self.registry.register_lazy, ' foo', self.__module__,
2205
2207
'TestOptionRegistry.lazy_option')
2206
self.assertRaises(config.IllegalOptionName,
2208
self.assertRaises(errors.IllegalOptionName,
2207
2209
self.registry.register_lazy, '1,2', self.__module__,
2208
2210
'TestOptionRegistry.lazy_option')
2387
2388
def test_building_delays_load(self):
2388
2389
store = self.get_store(self)
2389
2390
self.assertEqual(False, store.is_loaded())
2390
store._load_from_string(b'')
2391
store._load_from_string('')
2391
2392
self.assertEqual(True, store.is_loaded())
2393
2394
def test_get_no_sections_for_empty(self):
2394
2395
store = self.get_store(self)
2395
store._load_from_string(b'')
2396
store._load_from_string('')
2396
2397
self.assertEqual([], list(store.get_sections()))
2398
2399
def test_get_default_section(self):
2399
2400
store = self.get_store(self)
2400
store._load_from_string(b'foo=bar')
2401
store._load_from_string('foo=bar')
2401
2402
sections = list(store.get_sections())
2402
2403
self.assertLength(1, sections)
2403
2404
self.assertSectionContent((None, {'foo': 'bar'}), sections[0])
2405
2406
def test_get_named_section(self):
2406
2407
store = self.get_store(self)
2407
store._load_from_string(b'[baz]\nfoo=bar')
2408
store._load_from_string('[baz]\nfoo=bar')
2408
2409
sections = list(store.get_sections())
2409
2410
self.assertLength(1, sections)
2410
2411
self.assertSectionContent(('baz', {'foo': 'bar'}), sections[0])
2412
2413
def test_load_from_string_fails_for_non_empty_store(self):
2413
2414
store = self.get_store(self)
2414
store._load_from_string(b'foo=bar')
2415
self.assertRaises(AssertionError, store._load_from_string, b'bar=baz')
2415
store._load_from_string('foo=bar')
2416
self.assertRaises(AssertionError, store._load_from_string, 'bar=baz')
2418
2419
class TestStoreQuoting(TestStore):
2516
2517
def test_load_non_ascii(self):
2517
2518
"""Ensure we display a proper error on non-ascii, non utf-8 content."""
2518
2519
t = self.get_transport()
2519
t.put_bytes('foo.conf', b'user=foo\n#%s\n' % (self.invalid_utf8_char,))
2520
t.put_bytes('foo.conf', 'user=foo\n#%s\n' % (self.invalid_utf8_char,))
2520
2521
store = config.TransportIniFileStore(t, 'foo.conf')
2521
self.assertRaises(config.ConfigContentError, store.load)
2522
self.assertRaises(errors.ConfigContentError, store.load)
2523
2524
def test_load_erroneous_content(self):
2524
2525
"""Ensure we display a proper error on content that can't be parsed."""
2525
2526
t = self.get_transport()
2526
t.put_bytes('foo.conf', b'[open_section\n')
2527
t.put_bytes('foo.conf', '[open_section\n')
2527
2528
store = config.TransportIniFileStore(t, 'foo.conf')
2528
self.assertRaises(config.ParseConfigError, store.load)
2529
self.assertRaises(errors.ParseConfigError, store.load)
2530
2531
def test_load_permission_denied(self):
2531
2532
"""Ensure we get warned when trying to load an inaccessible file."""
2534
2534
def warning(*args):
2535
2535
warnings.append(args[0] % args[1:])
2536
2536
self.overrideAttr(trace, 'warning', warning)
2574
2574
def test_load_badly_encoded_content(self):
2575
2575
"""Ensure we display a proper error on non-ascii, non utf-8 content."""
2576
2576
with open('foo.conf', 'wb') as f:
2577
f.write(b'user=foo\n#%s\n' % (self.invalid_utf8_char,))
2577
f.write('user=foo\n#%s\n' % (self.invalid_utf8_char,))
2578
2578
conf = config.IniBasedConfig(file_name='foo.conf')
2579
self.assertRaises(config.ConfigContentError, conf._get_parser)
2579
self.assertRaises(errors.ConfigContentError, conf._get_parser)
2581
2581
def test_load_erroneous_content(self):
2582
2582
"""Ensure we display a proper error on content that can't be parsed."""
2583
2583
with open('foo.conf', 'wb') as f:
2584
f.write(b'[open_section\n')
2584
f.write('[open_section\n')
2585
2585
conf = config.IniBasedConfig(file_name='foo.conf')
2586
self.assertRaises(config.ParseConfigError, conf._get_parser)
2586
self.assertRaises(errors.ParseConfigError, conf._get_parser)
2589
2589
class TestMutableStore(TestStore):
2857
2854
stack = config.Stack([store.get_sections], store)
2858
2855
stack.set('foo', ' a b c ')
2860
self.assertFileEqual(b'foo = " a b c "' +
2861
os.linesep.encode('ascii'), 'foo.conf')
2857
self.assertFileEqual('foo = " a b c "' + os.linesep, 'foo.conf')
2864
2860
class TestTransportIniFileStore(TestStore):
2866
2862
def test_loading_unknown_file_fails(self):
2867
2863
store = config.TransportIniFileStore(self.get_transport(),
2869
2865
self.assertRaises(errors.NoSuchFile, store.load)
2871
2867
def test_invalid_content(self):
2872
2868
store = config.TransportIniFileStore(self.get_transport(), 'foo.conf')
2873
2869
self.assertEqual(False, store.is_loaded())
2874
2870
exc = self.assertRaises(
2875
config.ParseConfigError, store._load_from_string,
2876
b'this is invalid !')
2871
errors.ParseConfigError, store._load_from_string,
2872
'this is invalid !')
2877
2873
self.assertEndsWith(exc.filename, 'foo.conf')
2878
2874
# And the load failed
2879
2875
self.assertEqual(False, store.is_loaded())
3017
3011
self.assertEqual('c2', c2.get('one'))
3019
3013
def test_read_while_writing(self):
3021
# We spawn a thread that will pause *during* the write
3022
ready_to_write = threading.Event()
3023
do_writing = threading.Event()
3024
writing_done = threading.Event()
3025
# We override the _save implementation so we know the store is locked
3026
c1_save_without_locking_orig = c1.store.save_without_locking
3028
def c1_save_without_locking():
3029
ready_to_write.set()
3030
# The lock is held. We wait for the main thread to decide when to
3033
c1_save_without_locking_orig()
3035
c1.store.save_without_locking = c1_save_without_locking
3039
t1 = threading.Thread(target=c1_set)
3040
# Collect the thread after the test
3041
self.addCleanup(t1.join)
3042
# Be ready to unblock the thread if the test goes wrong
3043
self.addCleanup(do_writing.set)
3045
# Ensure the thread is ready to write
3046
ready_to_write.wait()
3047
self.assertEqual('c1', c1.get('one'))
3048
# If we read during the write, we get the old value
3049
c2 = self.get_stack(self)
3050
self.assertEqual('1', c2.get('one'))
3051
# Let the writing occur and ensure it occurred
3054
# Now we get the updated value
3055
c3 = self.get_stack(self)
3056
self.assertEqual('c1', c3.get('one'))
3015
# We spawn a thread that will pause *during* the write
3016
ready_to_write = threading.Event()
3017
do_writing = threading.Event()
3018
writing_done = threading.Event()
3019
# We override the _save implementation so we know the store is locked
3020
c1_save_without_locking_orig = c1.store.save_without_locking
3021
def c1_save_without_locking():
3022
ready_to_write.set()
3023
# The lock is held. We wait for the main thread to decide when to
3026
c1_save_without_locking_orig()
3028
c1.store.save_without_locking = c1_save_without_locking
3031
t1 = threading.Thread(target=c1_set)
3032
# Collect the thread after the test
3033
self.addCleanup(t1.join)
3034
# Be ready to unblock the thread if the test goes wrong
3035
self.addCleanup(do_writing.set)
3037
# Ensure the thread is ready to write
3038
ready_to_write.wait()
3039
self.assertEqual('c1', c1.get('one'))
3040
# If we read during the write, we get the old value
3041
c2 = self.get_stack(self)
3042
self.assertEqual('1', c2.get('one'))
3043
# Let the writing occur and ensure it occurred
3046
# Now we get the updated value
3047
c3 = self.get_stack(self)
3048
self.assertEqual('c1', c3.get('one'))
3058
3050
# FIXME: It may be worth looking into removing the lock dir when it's not
3059
3051
# needed anymore and look at possible fallouts for concurrent lockers. This
3060
# will matter if/when we use config files outside of breezy directories
3061
# (.config/breezy or .bzr) -- vila 20110-04-111
3052
# will matter if/when we use config files outside of bazaar directories
3053
# (.bazaar or .bzr) -- vila 20110-04-111
3064
3056
class TestSectionMatcher(TestStore):
3066
3058
scenarios = [('location', {'matcher': config.LocationMatcher}),
3067
('id', {'matcher': config.NameMatcher}), ]
3059
('id', {'matcher': config.NameMatcher}),]
3069
3061
def setUp(self):
3070
3062
super(TestSectionMatcher, self).setUp()
3127
3119
section=/quux/quux
3129
3121
self.assertEqual(['/foo', '/foo/baz', '/foo/bar', '/foo/bar/baz',
3131
[section.id for _, section in store.get_sections()])
3123
[section.id for _, section in store.get_sections()])
3132
3124
matcher = config.LocationMatcher(store, '/foo/bar/quux')
3133
3125
sections = [section for _, section in matcher.get_sections()]
3134
3126
self.assertEqual(['/foo/bar', '/foo'],
3135
[section.id for section in sections])
3127
[section.id for section in sections])
3136
3128
self.assertEqual(['quux', 'bar/quux'],
3137
[section.extra_path for section in sections])
3129
[section.extra_path for section in sections])
3139
3131
def test_more_specific_sections_first(self):
3140
3132
store = self.get_store(self)
3141
store._load_from_string(b'''
3133
store._load_from_string('''
3145
3137
section=/foo/bar
3147
3139
self.assertEqual(['/foo', '/foo/bar'],
3148
[section.id for _, section in store.get_sections()])
3140
[section.id for _, section in store.get_sections()])
3149
3141
matcher = config.LocationMatcher(store, '/foo/bar/baz')
3150
3142
sections = [section for _, section in matcher.get_sections()]
3151
3143
self.assertEqual(['/foo/bar', '/foo'],
3152
[section.id for section in sections])
3144
[section.id for section in sections])
3153
3145
self.assertEqual(['baz', 'bar/baz'],
3154
[section.extra_path for section in sections])
3146
[section.extra_path for section in sections])
3156
3148
def test_appendpath_in_no_name_section(self):
3157
3149
# It's a bit weird to allow appendpath in a no-name section, but
3158
3150
# someone may found a use for it
3159
3151
store = self.get_store(self)
3160
store._load_from_string(b'''
3152
store._load_from_string('''
3162
3154
foo:policy = appendpath
3229
3221
def test_local_path_vs_url(self):
3230
3222
# The matcher location is a local path and the section names are urls
3231
3223
self.assertSectionIDs(['file:///foo/bar', 'file:///foo'],
3232
'/foo/bar/baz', b'''\
3224
'/foo/bar/baz', '''\
3234
3226
[file:///foo/bar]
3237
3230
def test_no_name_section_included_when_present(self):
3238
3231
# Note that other tests will cover the case where the no-name section
3239
3232
# is empty and as such, not included.
3240
3233
sections = self.assertSectionIDs(['/foo/bar', '/foo', None],
3241
'/foo/bar/baz', b'''\
3234
'/foo/bar/baz', '''\
3242
3235
option = defined so the no-name section exists
3246
3239
self.assertEqual(['baz', 'bar/baz', '/foo/bar/baz'],
3247
[s.locals['relpath'] for _, s in sections])
3240
[s.locals['relpath'] for _, s in sections])
3249
3242
def test_order_reversed(self):
3250
self.assertSectionIDs(['/foo/bar', '/foo'], '/foo/bar/baz', b'''\
3243
self.assertSectionIDs(['/foo/bar', '/foo'], '/foo/bar/baz', '''\
3255
3248
def test_unrelated_section_excluded(self):
3256
self.assertSectionIDs(['/foo/bar', '/foo'], '/foo/bar/baz', b'''\
3249
self.assertSectionIDs(['/foo/bar', '/foo'], '/foo/bar/baz', '''\
3496
3488
def test_get_default_bool_None(self):
3497
3489
self.register_bool_option('foo')
3498
conf = self.get_conf(b'')
3490
conf = self.get_conf('')
3499
3491
self.assertEqual(None, conf.get('foo'))
3501
3493
def test_get_default_bool_True(self):
3502
3494
self.register_bool_option('foo', u'True')
3503
conf = self.get_conf(b'')
3495
conf = self.get_conf('')
3504
3496
self.assertEqual(True, conf.get('foo'))
3506
3498
def test_get_default_bool_False(self):
3507
3499
self.register_bool_option('foo', False)
3508
conf = self.get_conf(b'')
3500
conf = self.get_conf('')
3509
3501
self.assertEqual(False, conf.get('foo'))
3511
3503
def test_get_default_bool_False_as_string(self):
3512
3504
self.register_bool_option('foo', u'False')
3513
conf = self.get_conf(b'')
3505
conf = self.get_conf('')
3514
3506
self.assertEqual(False, conf.get('foo'))
3516
3508
def test_get_default_bool_from_env_converted(self):
3517
3509
self.register_bool_option('foo', u'True', default_from_env=['FOO'])
3518
3510
self.overrideEnv('FOO', 'False')
3519
conf = self.get_conf(b'')
3511
conf = self.get_conf('')
3520
3512
self.assertEqual(False, conf.get('foo'))
3522
3514
def test_get_default_bool_when_conversion_fails(self):
3523
3515
self.register_bool_option('foo', default='True')
3524
conf = self.get_conf(b'foo=invalid boolean')
3516
conf = self.get_conf('foo=invalid boolean')
3525
3517
self.assertEqual(True, conf.get('foo'))
3527
3519
def register_integer_option(self, name,
3534
3526
def test_get_default_integer_None(self):
3535
3527
self.register_integer_option('foo')
3536
conf = self.get_conf(b'')
3528
conf = self.get_conf('')
3537
3529
self.assertEqual(None, conf.get('foo'))
3539
3531
def test_get_default_integer(self):
3540
3532
self.register_integer_option('foo', 42)
3541
conf = self.get_conf(b'')
3533
conf = self.get_conf('')
3542
3534
self.assertEqual(42, conf.get('foo'))
3544
3536
def test_get_default_integer_as_string(self):
3545
3537
self.register_integer_option('foo', u'42')
3546
conf = self.get_conf(b'')
3538
conf = self.get_conf('')
3547
3539
self.assertEqual(42, conf.get('foo'))
3549
3541
def test_get_default_integer_from_env(self):
3550
3542
self.register_integer_option('foo', default_from_env=['FOO'])
3551
3543
self.overrideEnv('FOO', '18')
3552
conf = self.get_conf(b'')
3544
conf = self.get_conf('')
3553
3545
self.assertEqual(18, conf.get('foo'))
3555
3547
def test_get_default_integer_when_conversion_fails(self):
3556
3548
self.register_integer_option('foo', default='12')
3557
conf = self.get_conf(b'foo=invalid integer')
3549
conf = self.get_conf('foo=invalid integer')
3558
3550
self.assertEqual(12, conf.get('foo'))
3560
3552
def register_list_option(self, name, default=None, default_from_env=None):
3565
3557
def test_get_default_list_None(self):
3566
3558
self.register_list_option('foo')
3567
conf = self.get_conf(b'')
3559
conf = self.get_conf('')
3568
3560
self.assertEqual(None, conf.get('foo'))
3570
3562
def test_get_default_list_empty(self):
3571
3563
self.register_list_option('foo', '')
3572
conf = self.get_conf(b'')
3564
conf = self.get_conf('')
3573
3565
self.assertEqual([], conf.get('foo'))
3575
3567
def test_get_default_list_from_env(self):
3576
3568
self.register_list_option('foo', default_from_env=['FOO'])
3577
3569
self.overrideEnv('FOO', '')
3578
conf = self.get_conf(b'')
3570
conf = self.get_conf('')
3579
3571
self.assertEqual([], conf.get('foo'))
3581
3573
def test_get_with_list_converter_no_item(self):
3582
3574
self.register_list_option('foo', None)
3583
conf = self.get_conf(b'foo=,')
3575
conf = self.get_conf('foo=,')
3584
3576
self.assertEqual([], conf.get('foo'))
3586
3578
def test_get_with_list_converter_many_items(self):
3587
3579
self.register_list_option('foo', None)
3588
conf = self.get_conf(b'foo=m,o,r,e')
3580
conf = self.get_conf('foo=m,o,r,e')
3589
3581
self.assertEqual(['m', 'o', 'r', 'e'], conf.get('foo'))
3591
3583
def test_get_with_list_converter_embedded_spaces_many_items(self):
3592
3584
self.register_list_option('foo', None)
3593
conf = self.get_conf(b'foo=" bar", "baz "')
3585
conf = self.get_conf('foo=" bar", "baz "')
3594
3586
self.assertEqual([' bar', 'baz '], conf.get('foo'))
3596
3588
def test_get_with_list_converter_stripped_spaces_many_items(self):
3597
3589
self.register_list_option('foo', None)
3598
conf = self.get_conf(b'foo= bar , baz ')
3590
conf = self.get_conf('foo= bar , baz ')
3599
3591
self.assertEqual(['bar', 'baz'], conf.get('foo'))
3647
3639
self.assertExpansion('foo', 'foo')
3649
3641
def test_expand_default_value(self):
3650
self.conf.store._load_from_string(b'bar=baz')
3642
self.conf.store._load_from_string('bar=baz')
3651
3643
self.registry.register(config.Option('foo', default=u'{bar}'))
3652
3644
self.assertEqual('baz', self.conf.get('foo', expand=True))
3654
3646
def test_expand_default_from_env(self):
3655
self.conf.store._load_from_string(b'bar=baz')
3647
self.conf.store._load_from_string('bar=baz')
3656
3648
self.registry.register(config.Option('foo', default_from_env=['FOO']))
3657
3649
self.overrideEnv('FOO', '{bar}')
3658
3650
self.assertEqual('baz', self.conf.get('foo', expand=True))
3660
3652
def test_expand_default_on_failed_conversion(self):
3661
self.conf.store._load_from_string(b'baz=bogus\nbar=42\nfoo={baz}')
3653
self.conf.store._load_from_string('baz=bogus\nbar=42\nfoo={baz}')
3662
3654
self.registry.register(
3663
3655
config.Option('foo', default=u'{bar}',
3664
3656
from_unicode=config.int_from_store))
3668
3660
self.assertExpansion('bar', '{foo}', {'foo': 'bar'})
3670
3662
def test_env_overriding_options(self):
3671
self.conf.store._load_from_string(b'foo=baz')
3663
self.conf.store._load_from_string('foo=baz')
3672
3664
self.assertExpansion('bar', '{foo}', {'foo': 'bar'})
3674
3666
def test_simple_ref(self):
3675
self.conf.store._load_from_string(b'foo=xxx')
3667
self.conf.store._load_from_string('foo=xxx')
3676
3668
self.assertExpansion('xxx', '{foo}')
3678
3670
def test_unknown_ref(self):
3679
self.assertRaises(config.ExpandingUnknownOption,
3671
self.assertRaises(errors.ExpandingUnknownOption,
3680
3672
self.conf.expand_options, '{foo}')
3682
3674
def test_illegal_def_is_ignored(self):
3685
3677
self.assertExpansion('${Foo,f}', '${Foo,f}')
3687
3679
def test_indirect_ref(self):
3688
self.conf.store._load_from_string(b'''
3680
self.conf.store._load_from_string('''
3692
3684
self.assertExpansion('xxx', '{bar}')
3694
3686
def test_embedded_ref(self):
3695
self.conf.store._load_from_string(b'''
3687
self.conf.store._load_from_string('''
3699
3691
self.assertExpansion('xxx', '{{bar}}')
3701
3693
def test_simple_loop(self):
3702
self.conf.store._load_from_string(b'foo={foo}')
3703
self.assertRaises(config.OptionExpansionLoop,
3694
self.conf.store._load_from_string('foo={foo}')
3695
self.assertRaises(errors.OptionExpansionLoop,
3704
3696
self.conf.expand_options, '{foo}')
3706
3698
def test_indirect_loop(self):
3707
self.conf.store._load_from_string(b'''
3699
self.conf.store._load_from_string('''
3711
e = self.assertRaises(config.OptionExpansionLoop,
3703
e = self.assertRaises(errors.OptionExpansionLoop,
3712
3704
self.conf.expand_options, '{foo}')
3713
3705
self.assertEqual('foo->bar->baz', e.refs)
3714
3706
self.assertEqual('{foo}', e.string)
3716
3708
def test_list(self):
3717
self.conf.store._load_from_string(b'''
3709
self.conf.store._load_from_string('''
3862
3854
def test_expand_relpath_unknonw_in_global(self):
3863
3855
g_store = config.GlobalStore()
3864
g_store._load_from_string(b'''
3856
g_store._load_from_string('''
3866
3858
gfoo = {relpath}
3869
3861
stack = config.LocationStack('/home/user/project/branch')
3870
self.assertRaises(config.ExpandingUnknownOption,
3862
self.assertRaises(errors.ExpandingUnknownOption,
3871
3863
stack.get, 'gfoo', expand=True)
3873
3865
def test_expand_local_option_locally(self):
3874
3866
l_store = config.LocationStore()
3875
l_store._load_from_string(b'''
3867
l_store._load_from_string('''
3876
3868
[/home/user/project]
3877
3869
lfoo = loc-foo/{relpath}
3881
3873
g_store = config.GlobalStore()
3882
g_store._load_from_string(b'''
3874
g_store._load_from_string('''
3885
3877
gbar = glob-bar
3968
3959
create_configs(self)
3970
3961
def test_no_variable(self):
3971
# Using branch should query branch, locations and breezy
3962
# Using branch should query branch, locations and bazaar
3972
3963
self.assertOptions([], self.branch_config)
3974
def test_option_in_breezy(self):
3975
self.breezy_config.set_user_option('file', 'breezy')
3976
self.assertOptions([('file', 'breezy', 'DEFAULT', 'breezy')],
3965
def test_option_in_bazaar(self):
3966
self.bazaar_config.set_user_option('file', 'bazaar')
3967
self.assertOptions([('file', 'bazaar', 'DEFAULT', 'bazaar')],
3979
3970
def test_option_in_locations(self):
3980
3971
self.locations_config.set_user_option('file', 'locations')
3987
3978
self.assertOptions([('file', 'branch', 'DEFAULT', 'branch')],
3988
3979
self.branch_config)
3990
def test_option_in_breezy_and_branch(self):
3991
self.breezy_config.set_user_option('file', 'breezy')
3981
def test_option_in_bazaar_and_branch(self):
3982
self.bazaar_config.set_user_option('file', 'bazaar')
3992
3983
self.branch_config.set_user_option('file', 'branch')
3993
3984
self.assertOptions([('file', 'branch', 'DEFAULT', 'branch'),
3994
('file', 'breezy', 'DEFAULT', 'breezy'), ],
3985
('file', 'bazaar', 'DEFAULT', 'bazaar'),],
3995
3986
self.branch_config)
3997
3988
def test_option_in_branch_and_locations(self):
4000
3991
self.branch_config.set_user_option('file', 'branch')
4001
3992
self.assertOptions(
4002
3993
[('file', 'locations', self.tree.basedir, 'locations'),
4003
('file', 'branch', 'DEFAULT', 'branch'), ],
3994
('file', 'branch', 'DEFAULT', 'branch'),],
4004
3995
self.branch_config)
4006
def test_option_in_breezy_locations_and_branch(self):
4007
self.breezy_config.set_user_option('file', 'breezy')
3997
def test_option_in_bazaar_locations_and_branch(self):
3998
self.bazaar_config.set_user_option('file', 'bazaar')
4008
3999
self.locations_config.set_user_option('file', 'locations')
4009
4000
self.branch_config.set_user_option('file', 'branch')
4010
4001
self.assertOptions(
4011
4002
[('file', 'locations', self.tree.basedir, 'locations'),
4012
4003
('file', 'branch', 'DEFAULT', 'branch'),
4013
('file', 'breezy', 'DEFAULT', 'breezy'), ],
4004
('file', 'bazaar', 'DEFAULT', 'bazaar'),],
4014
4005
self.branch_config)
4024
4015
self.locations_config.remove_user_option('file', self.tree.basedir)
4025
4016
self.assertOptions(
4026
4017
[('file', 'branch', 'DEFAULT', 'branch'),
4027
('file', 'breezy', 'DEFAULT', 'breezy'), ],
4018
('file', 'bazaar', 'DEFAULT', 'bazaar'),],
4028
4019
self.branch_config)
4030
4021
def test_remove_in_branch(self):
4031
4022
self.branch_config.remove_user_option('file')
4032
4023
self.assertOptions(
4033
4024
[('file', 'locations', self.tree.basedir, 'locations'),
4034
('file', 'breezy', 'DEFAULT', 'breezy'), ],
4025
('file', 'bazaar', 'DEFAULT', 'bazaar'),],
4035
4026
self.branch_config)
4037
def test_remove_in_breezy(self):
4038
self.breezy_config.remove_user_option('file')
4028
def test_remove_in_bazaar(self):
4029
self.bazaar_config.remove_user_option('file')
4039
4030
self.assertOptions(
4040
4031
[('file', 'locations', self.tree.basedir, 'locations'),
4041
('file', 'branch', 'DEFAULT', 'branch'), ],
4032
('file', 'branch', 'DEFAULT', 'branch'),],
4042
4033
self.branch_config)
4105
4096
self.assertSectionNames([self.tree.basedir, None, 'DEFAULT'],
4106
4097
self.branch_config)
4108
def test_breezy_named_section(self):
4099
def test_bazaar_named_section(self):
4109
4100
# We need to cheat as the API doesn't give direct access to sections
4110
4101
# other than DEFAULT.
4111
self.breezy_config.set_alias('breezy', 'bzr')
4112
self.assertSectionNames(['ALIASES'], self.breezy_config, 'ALIASES')
4102
self.bazaar_config.set_alias('bazaar', 'bzr')
4103
self.assertSectionNames(['ALIASES'], self.bazaar_config, 'ALIASES')
4115
4106
class TestSharedStores(tests.TestCaseInTempDir):
4117
def test_breezy_conf_shared(self):
4108
def test_bazaar_conf_shared(self):
4118
4109
g1 = config.GlobalStack()
4119
4110
g2 = config.GlobalStack()
4120
4111
# The two stacks share the same store
4121
4112
self.assertIs(g1.store, g2.store)
4124
class TestAuthenticationConfigFilePermissions(tests.TestCaseInTempDir):
4125
"""Test warning for permissions of authentication.conf."""
4128
super(TestAuthenticationConfigFilePermissions, self).setUp()
4129
self.path = osutils.pathjoin(self.test_dir, 'authentication.conf')
4130
with open(self.path, 'wb') as f:
4131
f.write(b"""[broken]
4134
port=port # Error: Not an int
4136
self.overrideAttr(bedding, 'authentication_config_path',
4138
osutils.chmod_if_possible(self.path, 0o755)
4140
def test_check_warning(self):
4141
conf = config.AuthenticationConfig()
4142
self.assertEqual(conf._filename, self.path)
4143
self.assertContainsRe(self.get_log(),
4144
'Saved passwords may be accessible by other users.')
4146
def test_check_suppressed_warning(self):
4147
global_config = config.GlobalConfig()
4148
global_config.set_user_option('suppress_warnings',
4149
'insecure_permissions')
4150
conf = config.AuthenticationConfig()
4151
self.assertEqual(conf._filename, self.path)
4152
self.assertNotContainsRe(self.get_log(),
4153
'Saved passwords may be accessible by other users.')
4156
4115
class TestAuthenticationConfigFile(tests.TestCase):
4157
4116
"""Test the authentication.conf file matching"""
4420
4379
expected_prompt = expected_prompt_format % {
4421
4380
'scheme': scheme, 'host': host, 'port': port,
4422
4381
'realm': realm}
4423
ui.ui_factory = tests.TestUIFactory(stdin=username + '\n')
4382
ui.ui_factory = tests.TestUIFactory(stdin=username+ '\n')
4424
4383
# We use an empty conf so that the user is always prompted
4425
4384
conf = config.AuthenticationConfig()
4426
4385
self.assertEqual(username, conf.get_user(scheme, host, port=port,
4427
realm=realm, path=path, ask=True))
4386
realm=realm, path=path, ask=True))
4428
4387
self.assertEqual(expected_prompt, ui.ui_factory.stderr.getvalue())
4429
4388
self.assertEqual('', ui.ui_factory.stdout.getvalue())
4610
class TestAutoUserId(tests.TestCase):
4611
"""Test inferring an automatic user name."""
4613
def test_auto_user_id(self):
4614
"""Automatic inference of user name.
4616
This is a bit hard to test in an isolated way, because it depends on
4617
system functions that go direct to /etc or perhaps somewhere else.
4618
But it's reasonable to say that on Unix, with an /etc/mailname, we ought
4619
to be able to choose a user name with no configuration.
4621
if sys.platform == 'win32':
4622
raise tests.TestSkipped(
4623
"User name inference not implemented on win32")
4624
realname, address = config._auto_user_id()
4625
if os.path.exists('/etc/mailname'):
4626
self.assertIsNot(None, realname)
4627
self.assertIsNot(None, address)
4629
self.assertEqual((None, None), (realname, address))
4632
class TestDefaultMailDomain(tests.TestCaseInTempDir):
4633
"""Test retrieving default domain from mailname file"""
4635
def test_default_mail_domain_simple(self):
4636
f = file('simple', 'w')
4638
f.write("domainname.com\n")
4641
r = config._get_default_mail_domain('simple')
4642
self.assertEqual('domainname.com', r)
4644
def test_default_mail_domain_no_eol(self):
4645
f = file('no_eol', 'w')
4647
f.write("domainname.com")
4650
r = config._get_default_mail_domain('no_eol')
4651
self.assertEqual('domainname.com', r)
4653
def test_default_mail_domain_multiple_lines(self):
4654
f = file('multiple_lines', 'w')
4656
f.write("domainname.com\nsome other text\n")
4659
r = config._get_default_mail_domain('multiple_lines')
4660
self.assertEqual('domainname.com', r)
4651
4663
class EmailOptionTests(tests.TestCase):
4653
4665
def test_default_email_uses_BRZ_EMAIL(self):
4654
conf = config.MemoryStack(b'email=jelmer@debian.org')
4655
# BRZ_EMAIL takes precedence over BZR_EMAIL and EMAIL
4666
conf = config.MemoryStack('email=jelmer@debian.org')
4667
# BRZ_EMAIL takes precedence over EMAIL
4656
4668
self.overrideEnv('BRZ_EMAIL', 'jelmer@samba.org')
4657
self.overrideEnv('BZR_EMAIL', 'jelmer@jelmer.uk')
4658
self.overrideEnv('EMAIL', 'jelmer@apache.org')
4659
self.assertEqual('jelmer@samba.org', conf.get('email'))
4661
def test_default_email_uses_BZR_EMAIL(self):
4662
conf = config.MemoryStack(b'email=jelmer@debian.org')
4663
# BZR_EMAIL takes precedence over EMAIL
4664
self.overrideEnv('BZR_EMAIL', 'jelmer@samba.org')
4665
4669
self.overrideEnv('EMAIL', 'jelmer@apache.org')
4666
4670
self.assertEqual('jelmer@samba.org', conf.get('email'))
4668
4672
def test_default_email_uses_EMAIL(self):
4669
conf = config.MemoryStack(b'')
4673
conf = config.MemoryStack('')
4670
4674
self.overrideEnv('BRZ_EMAIL', None)
4671
4675
self.overrideEnv('EMAIL', 'jelmer@apache.org')
4672
4676
self.assertEqual('jelmer@apache.org', conf.get('email'))
4674
4678
def test_BRZ_EMAIL_overrides(self):
4675
conf = config.MemoryStack(b'email=jelmer@debian.org')
4679
conf = config.MemoryStack('email=jelmer@debian.org')
4676
4680
self.overrideEnv('BRZ_EMAIL', 'jelmer@apache.org')
4677
4681
self.assertEqual('jelmer@apache.org', conf.get('email'))
4678
4682
self.overrideEnv('BRZ_EMAIL', None)
4683
4687
class MailClientOptionTests(tests.TestCase):
4685
4689
def test_default(self):
4686
conf = config.MemoryStack(b'')
4690
conf = config.MemoryStack('')
4687
4691
client = conf.get('mail_client')
4688
4692
self.assertIs(client, mail_client.DefaultMail)
4690
4694
def test_evolution(self):
4691
conf = config.MemoryStack(b'mail_client=evolution')
4695
conf = config.MemoryStack('mail_client=evolution')
4692
4696
client = conf.get('mail_client')
4693
4697
self.assertIs(client, mail_client.Evolution)
4695
4699
def test_kmail(self):
4696
conf = config.MemoryStack(b'mail_client=kmail')
4700
conf = config.MemoryStack('mail_client=kmail')
4697
4701
client = conf.get('mail_client')
4698
4702
self.assertIs(client, mail_client.KMail)
4700
4704
def test_mutt(self):
4701
conf = config.MemoryStack(b'mail_client=mutt')
4705
conf = config.MemoryStack('mail_client=mutt')
4702
4706
client = conf.get('mail_client')
4703
4707
self.assertIs(client, mail_client.Mutt)
4705
4709
def test_thunderbird(self):
4706
conf = config.MemoryStack(b'mail_client=thunderbird')
4710
conf = config.MemoryStack('mail_client=thunderbird')
4707
4711
client = conf.get('mail_client')
4708
4712
self.assertIs(client, mail_client.Thunderbird)
4710
4714
def test_explicit_default(self):
4711
conf = config.MemoryStack(b'mail_client=default')
4715
conf = config.MemoryStack('mail_client=default')
4712
4716
client = conf.get('mail_client')
4713
4717
self.assertIs(client, mail_client.DefaultMail)
4715
4719
def test_editor(self):
4716
conf = config.MemoryStack(b'mail_client=editor')
4720
conf = config.MemoryStack('mail_client=editor')
4717
4721
client = conf.get('mail_client')
4718
4722
self.assertIs(client, mail_client.Editor)
4720
4724
def test_mapi(self):
4721
conf = config.MemoryStack(b'mail_client=mapi')
4725
conf = config.MemoryStack('mail_client=mapi')
4722
4726
client = conf.get('mail_client')
4723
4727
self.assertIs(client, mail_client.MAPIClient)
4725
4729
def test_xdg_email(self):
4726
conf = config.MemoryStack(b'mail_client=xdg-email')
4730
conf = config.MemoryStack('mail_client=xdg-email')
4727
4731
client = conf.get('mail_client')
4728
4732
self.assertIs(client, mail_client.XDGEmail)
4730
4734
def test_unknown(self):
4731
conf = config.MemoryStack(b'mail_client=firebird')
4732
self.assertRaises(config.ConfigOptionValueError, conf.get,
4735
conf = config.MemoryStack('mail_client=firebird')
4736
self.assertRaises(errors.ConfigOptionValueError, conf.get,