18
18
"""Tests for finding and reading the bzr config file[s]."""
19
19
# import system imports here
20
from ConfigParser import ConfigParser
20
from bzrlib.util.configobj.configobj import ConfigObj, ConfigObjError
21
21
from cStringIO import StringIO
25
25
#import bzrlib specific imports here
26
26
import bzrlib.config as config
27
from bzrlib.selftest import TestCase, TestCaseInTempDir
27
import bzrlib.errors as errors
28
from bzrlib.tests import TestCase, TestCaseInTempDir
30
31
sample_config_text = ("[DEFAULT]\n"
31
32
"email=Robert Collins <robertc@example.com>\n"
33
"gpg_signing_command=gnome-gpg\n")
35
class InstrumentedConfigParser(object):
36
"""A config parser look-enough-alike to record calls made to it."""
34
"gpg_signing_command=gnome-gpg\n"
36
"user_global_option=something\n")
39
sample_always_signatures = ("[DEFAULT]\n"
40
"check_signatures=require\n")
43
sample_ignore_signatures = ("[DEFAULT]\n"
44
"check_signatures=ignore\n")
47
sample_maybe_signatures = ("[DEFAULT]\n"
48
"check_signatures=check-available\n")
51
sample_branches_text = ("[http://www.example.com]\n"
52
"# Top level policy\n"
53
"email=Robert Collins <robertc@example.org>\n"
54
"[http://www.example.com/useglobal]\n"
55
"# different project, forces global lookup\n"
58
"check_signatures=require\n"
59
"# test trailing / matching with no children\n"
61
"check_signatures=check-available\n"
62
"gpg_signing_command=false\n"
63
"user_local_option=local\n"
64
"# test trailing / matching\n"
66
"#subdirs will match but not the parent\n"
69
"check_signatures=ignore\n"
70
"post_commit=bzrlib.tests.test_config.post_commit\n"
71
"#testing explicit beats globs\n")
74
class InstrumentedConfigObj(object):
75
"""A config obj look-enough-alike to record calls made to it."""
77
def __contains__(self, thing):
78
self._calls.append(('__contains__', thing))
81
def __getitem__(self, key):
82
self._calls.append(('__getitem__', key))
85
def __init__(self, input):
86
self._calls = [('__init__', input)]
88
def __setitem__(self, key, value):
89
self._calls.append(('__setitem__', key, value))
92
self._calls.append(('write',))
95
class FakeBranch(object):
98
self.base = "http://example.com/branches/demo"
99
self.control_files = FakeControlFiles()
102
class FakeControlFiles(object):
105
self.email = 'Robert Collins <robertc@example.net>\n'
107
def get_utf8(self, filename):
108
if filename != 'email':
109
raise NotImplementedError
110
if self.email is not None:
111
return StringIO(self.email)
112
raise errors.NoSuchFile(filename)
115
class InstrumentedConfig(config.Config):
116
"""An instrumented config that supplies stubs for template methods."""
119
super(InstrumentedConfig, self).__init__()
41
def read(self, filenames):
42
self._calls.append(('read', filenames))
121
self._signatures = config.CHECK_NEVER
123
def _get_user_id(self):
124
self._calls.append('_get_user_id')
125
return "Robert Collins <robert.collins@example.org>"
127
def _get_signature_checking(self):
128
self._calls.append('_get_signature_checking')
129
return self._signatures
132
bool_config = """[DEFAULT]
139
class TestConfigObj(TestCase):
140
def test_get_bool(self):
141
from bzrlib.config import ConfigObj
142
co = ConfigObj(StringIO(bool_config))
143
self.assertIs(co.get_bool('DEFAULT', 'active'), True)
144
self.assertIs(co.get_bool('DEFAULT', 'inactive'), False)
145
self.assertIs(co.get_bool('UPPERCASE', 'active'), True)
146
self.assertIs(co.get_bool('UPPERCASE', 'nonactive'), False)
149
class TestConfig(TestCase):
151
def test_constructs(self):
154
def test_no_default_editor(self):
155
self.assertRaises(NotImplementedError, config.Config().get_editor)
157
def test_user_email(self):
158
my_config = InstrumentedConfig()
159
self.assertEqual('robert.collins@example.org', my_config.user_email())
160
self.assertEqual(['_get_user_id'], my_config._calls)
162
def test_username(self):
163
my_config = InstrumentedConfig()
164
self.assertEqual('Robert Collins <robert.collins@example.org>',
165
my_config.username())
166
self.assertEqual(['_get_user_id'], my_config._calls)
168
def test_signatures_default(self):
169
my_config = config.Config()
170
self.assertEqual(config.CHECK_IF_POSSIBLE,
171
my_config.signature_checking())
173
def test_signatures_template_method(self):
174
my_config = InstrumentedConfig()
175
self.assertEqual(config.CHECK_NEVER, my_config.signature_checking())
176
self.assertEqual(['_get_signature_checking'], my_config._calls)
178
def test_signatures_template_method_none(self):
179
my_config = InstrumentedConfig()
180
my_config._signatures = None
181
self.assertEqual(config.CHECK_IF_POSSIBLE,
182
my_config.signature_checking())
183
self.assertEqual(['_get_signature_checking'], my_config._calls)
185
def test_gpg_signing_command_default(self):
186
my_config = config.Config()
187
self.assertEqual('gpg', my_config.gpg_signing_command())
189
def test_get_user_option_default(self):
190
my_config = config.Config()
191
self.assertEqual(None, my_config.get_user_option('no_option'))
193
def test_post_commit_default(self):
194
my_config = config.Config()
195
self.assertEqual(None, my_config.post_commit())
197
def test_log_format_default(self):
198
my_config = config.Config()
199
self.assertEqual('long', my_config.log_format())
45
202
class TestConfigPath(TestCase):
48
205
super(TestConfigPath, self).setUp()
49
self.oldenv = os.environ.get('HOME', None)
206
self.old_home = os.environ.get('HOME', None)
207
self.old_appdata = os.environ.get('APPDATA', None)
50
208
os.environ['HOME'] = '/home/bogus'
209
os.environ['APPDATA'] = \
210
r'C:\Documents and Settings\bogus\Application Data'
52
212
def tearDown(self):
53
os.environ['HOME'] = self.oldenv
213
if self.old_home is None:
214
del os.environ['HOME']
216
os.environ['HOME'] = self.old_home
217
if self.old_appdata is None:
218
del os.environ['APPDATA']
220
os.environ['APPDATA'] = self.old_appdata
221
super(TestConfigPath, self).tearDown()
55
223
def test_config_dir(self):
56
self.assertEqual(config.config_dir(), '/home/bogus/.bazaar')
224
if sys.platform == 'win32':
225
self.assertEqual(config.config_dir(),
226
'C:/Documents and Settings/bogus/Application Data/bazaar/2.0')
228
self.assertEqual(config.config_dir(), '/home/bogus/.bazaar')
58
230
def test_config_filename(self):
59
self.assertEqual(config.config_filename(),
60
'/home/bogus/.bazaar/bazaar.conf')
231
if sys.platform == 'win32':
232
self.assertEqual(config.config_filename(),
233
'C:/Documents and Settings/bogus/Application Data/bazaar/2.0/bazaar.conf')
235
self.assertEqual(config.config_filename(),
236
'/home/bogus/.bazaar/bazaar.conf')
238
def test_branches_config_filename(self):
239
if sys.platform == 'win32':
240
self.assertEqual(config.branches_config_filename(),
241
'C:/Documents and Settings/bogus/Application Data/bazaar/2.0/branches.conf')
243
self.assertEqual(config.branches_config_filename(),
244
'/home/bogus/.bazaar/branches.conf')
246
class TestIniConfig(TestCase):
248
def test_contructs(self):
249
my_config = config.IniBasedConfig("nothing")
251
def test_from_fp(self):
252
config_file = StringIO(sample_config_text)
253
my_config = config.IniBasedConfig(None)
255
isinstance(my_config._get_parser(file=config_file),
258
def test_cached(self):
259
config_file = StringIO(sample_config_text)
260
my_config = config.IniBasedConfig(None)
261
parser = my_config._get_parser(file=config_file)
262
self.failUnless(my_config._get_parser() is parser)
63
265
class TestGetConfig(TestCase):
65
def test_from_fp(self):
66
config_file = StringIO(sample_config_text)
67
self.failUnless(isinstance(config._get_config_parser(file=config_file),
267
def test_constructs(self):
268
my_config = config.GlobalConfig()
70
270
def test_calls_read_filenames(self):
71
# note the monkey patching. if config access was via a class instance,
72
# we would not have to - if this changes in future, be sure to stop
73
# monkey patching RBC 20051011
74
oldparserclass = config.ConfigParser
75
config.ConfigParser = InstrumentedConfigParser
271
# replace the class that is constructured, to check its parameters
272
oldparserclass = config.ConfigObj
273
config.ConfigObj = InstrumentedConfigObj
274
my_config = config.GlobalConfig()
77
parser = config._get_config_parser()
276
parser = my_config._get_parser()
79
config.ConfigParser = oldparserclass
80
self.failUnless(isinstance(parser, InstrumentedConfigParser))
81
self.assertEqual(parser._calls, [('read', [config.config_filename()])])
84
class TestConfigItems(TestCase):
87
super(TestConfigItems, self).setUp()
88
self.bzr_email = os.environ.get('BZREMAIL')
89
if self.bzr_email is not None:
90
del os.environ['BZREMAIL']
91
self.email = os.environ.get('EMAIL')
92
if self.email is not None:
93
del os.environ['EMAIL']
94
self.oldenv = os.environ.get('HOME', None)
95
os.environ['HOME'] = os.getcwd()
98
os.environ['HOME'] = self.oldenv
99
if self.bzr_email is not None:
100
os.environ['BZREMAIL'] = self.bzr_email
101
if self.email is not None:
102
os.environ['EMAIL'] = self.email
103
super(TestConfigItems, self).tearDown()
278
config.ConfigObj = oldparserclass
279
self.failUnless(isinstance(parser, InstrumentedConfigObj))
280
self.assertEqual(parser._calls, [('__init__', config.config_filename())])
283
class TestBranchConfig(TestCaseInTempDir):
285
def test_constructs(self):
286
branch = FakeBranch()
287
my_config = config.BranchConfig(branch)
288
self.assertRaises(TypeError, config.BranchConfig)
290
def test_get_location_config(self):
291
branch = FakeBranch()
292
my_config = config.BranchConfig(branch)
293
location_config = my_config._get_location_config()
294
self.assertEqual(branch.base, location_config.location)
295
self.failUnless(location_config is my_config._get_location_config())
298
class TestGlobalConfigItems(TestCase):
105
300
def test_user_id(self):
106
301
config_file = StringIO(sample_config_text)
107
parser = config._get_config_parser(file=config_file)
302
my_config = config.GlobalConfig()
303
my_config._parser = my_config._get_parser(file=config_file)
108
304
self.assertEqual("Robert Collins <robertc@example.com>",
109
config._get_user_id(parser = parser))
305
my_config._get_user_id())
111
307
def test_absent_user_id(self):
112
308
config_file = StringIO("")
113
parser = config._get_config_parser(file=config_file)
114
self.assertEqual(None,
115
config._get_user_id(parser = parser))
117
def test_configured_edit(self):
118
config_file = StringIO(sample_config_text)
119
parser = config._get_config_parser(file=config_file)
120
self.assertEqual("vim", config.get_editor(parser = parser))
309
my_config = config.GlobalConfig()
310
my_config._parser = my_config._get_parser(file=config_file)
311
self.assertEqual(None, my_config._get_user_id())
313
def test_configured_editor(self):
314
config_file = StringIO(sample_config_text)
315
my_config = config.GlobalConfig()
316
my_config._parser = my_config._get_parser(file=config_file)
317
self.assertEqual("vim", my_config.get_editor())
319
def test_signatures_always(self):
320
config_file = StringIO(sample_always_signatures)
321
my_config = config.GlobalConfig()
322
my_config._parser = my_config._get_parser(file=config_file)
323
self.assertEqual(config.CHECK_ALWAYS,
324
my_config.signature_checking())
325
self.assertEqual(True, my_config.signature_needed())
327
def test_signatures_if_possible(self):
328
config_file = StringIO(sample_maybe_signatures)
329
my_config = config.GlobalConfig()
330
my_config._parser = my_config._get_parser(file=config_file)
331
self.assertEqual(config.CHECK_IF_POSSIBLE,
332
my_config.signature_checking())
333
self.assertEqual(False, my_config.signature_needed())
335
def test_signatures_ignore(self):
336
config_file = StringIO(sample_ignore_signatures)
337
my_config = config.GlobalConfig()
338
my_config._parser = my_config._get_parser(file=config_file)
339
self.assertEqual(config.CHECK_NEVER,
340
my_config.signature_checking())
341
self.assertEqual(False, my_config.signature_needed())
343
def _get_sample_config(self):
344
config_file = StringIO(sample_config_text)
345
my_config = config.GlobalConfig()
346
my_config._parser = my_config._get_parser(file=config_file)
349
def test_gpg_signing_command(self):
350
my_config = self._get_sample_config()
351
self.assertEqual("gnome-gpg", my_config.gpg_signing_command())
352
self.assertEqual(False, my_config.signature_needed())
354
def _get_empty_config(self):
355
config_file = StringIO("")
356
my_config = config.GlobalConfig()
357
my_config._parser = my_config._get_parser(file=config_file)
360
def test_gpg_signing_command_unset(self):
361
my_config = self._get_empty_config()
362
self.assertEqual("gpg", my_config.gpg_signing_command())
364
def test_get_user_option_default(self):
365
my_config = self._get_empty_config()
366
self.assertEqual(None, my_config.get_user_option('no_option'))
368
def test_get_user_option_global(self):
369
my_config = self._get_sample_config()
370
self.assertEqual("something",
371
my_config.get_user_option('user_global_option'))
373
def test_post_commit_default(self):
374
my_config = self._get_sample_config()
375
self.assertEqual(None, my_config.post_commit())
377
def test_configured_logformat(self):
378
my_config = self._get_sample_config()
379
self.assertEqual("short", my_config.log_format())
382
class TestLocationConfig(TestCase):
384
def test_constructs(self):
385
my_config = config.LocationConfig('http://example.com')
386
self.assertRaises(TypeError, config.LocationConfig)
388
def test_branch_calls_read_filenames(self):
389
# This is testing the correct file names are provided.
390
# TODO: consolidate with the test for GlobalConfigs filename checks.
392
# replace the class that is constructured, to check its parameters
393
oldparserclass = config.ConfigObj
394
config.ConfigObj = InstrumentedConfigObj
395
my_config = config.LocationConfig('http://www.example.com')
397
parser = my_config._get_parser()
399
config.ConfigObj = oldparserclass
400
self.failUnless(isinstance(parser, InstrumentedConfigObj))
401
self.assertEqual(parser._calls,
402
[('__init__', config.branches_config_filename())])
404
def test_get_global_config(self):
405
my_config = config.LocationConfig('http://example.com')
406
global_config = my_config._get_global_config()
407
self.failUnless(isinstance(global_config, config.GlobalConfig))
408
self.failUnless(global_config is my_config._get_global_config())
410
def test__get_section_no_match(self):
411
self.get_location_config('/')
412
self.assertEqual(None, self.my_config._get_section())
414
def test__get_section_exact(self):
415
self.get_location_config('http://www.example.com')
416
self.assertEqual('http://www.example.com',
417
self.my_config._get_section())
419
def test__get_section_suffix_does_not(self):
420
self.get_location_config('http://www.example.com-com')
421
self.assertEqual(None, self.my_config._get_section())
423
def test__get_section_subdir_recursive(self):
424
self.get_location_config('http://www.example.com/com')
425
self.assertEqual('http://www.example.com',
426
self.my_config._get_section())
428
def test__get_section_subdir_matches(self):
429
self.get_location_config('http://www.example.com/useglobal')
430
self.assertEqual('http://www.example.com/useglobal',
431
self.my_config._get_section())
433
def test__get_section_subdir_nonrecursive(self):
434
self.get_location_config(
435
'http://www.example.com/useglobal/childbranch')
436
self.assertEqual('http://www.example.com',
437
self.my_config._get_section())
439
def test__get_section_subdir_trailing_slash(self):
440
self.get_location_config('/b')
441
self.assertEqual('/b/', self.my_config._get_section())
443
def test__get_section_subdir_child(self):
444
self.get_location_config('/a/foo')
445
self.assertEqual('/a/*', self.my_config._get_section())
447
def test__get_section_subdir_child_child(self):
448
self.get_location_config('/a/foo/bar')
449
self.assertEqual('/a/', self.my_config._get_section())
451
def test__get_section_trailing_slash_with_children(self):
452
self.get_location_config('/a/')
453
self.assertEqual('/a/', self.my_config._get_section())
455
def test__get_section_explicit_over_glob(self):
456
self.get_location_config('/a/c')
457
self.assertEqual('/a/c', self.my_config._get_section())
459
def get_location_config(self, location, global_config=None):
460
if global_config is None:
461
global_file = StringIO(sample_config_text)
463
global_file = StringIO(global_config)
464
branches_file = StringIO(sample_branches_text)
465
self.my_config = config.LocationConfig(location)
466
self.my_config._get_parser(branches_file)
467
self.my_config._get_global_config()._get_parser(global_file)
469
def test_location_without_username(self):
470
self.get_location_config('http://www.example.com/useglobal')
471
self.assertEqual('Robert Collins <robertc@example.com>',
472
self.my_config.username())
474
def test_location_not_listed(self):
475
self.get_location_config('/home/robertc/sources')
476
self.assertEqual('Robert Collins <robertc@example.com>',
477
self.my_config.username())
479
def test_overriding_location(self):
480
self.get_location_config('http://www.example.com/foo')
481
self.assertEqual('Robert Collins <robertc@example.org>',
482
self.my_config.username())
484
def test_signatures_not_set(self):
485
self.get_location_config('http://www.example.com',
486
global_config=sample_ignore_signatures)
487
self.assertEqual(config.CHECK_NEVER,
488
self.my_config.signature_checking())
490
def test_signatures_never(self):
491
self.get_location_config('/a/c')
492
self.assertEqual(config.CHECK_NEVER,
493
self.my_config.signature_checking())
495
def test_signatures_when_available(self):
496
self.get_location_config('/a/', global_config=sample_ignore_signatures)
497
self.assertEqual(config.CHECK_IF_POSSIBLE,
498
self.my_config.signature_checking())
500
def test_signatures_always(self):
501
self.get_location_config('/b')
502
self.assertEqual(config.CHECK_ALWAYS,
503
self.my_config.signature_checking())
505
def test_gpg_signing_command(self):
506
self.get_location_config('/b')
507
self.assertEqual("gnome-gpg", self.my_config.gpg_signing_command())
509
def test_gpg_signing_command_missing(self):
510
self.get_location_config('/a')
511
self.assertEqual("false", self.my_config.gpg_signing_command())
513
def test_get_user_option_global(self):
514
self.get_location_config('/a')
515
self.assertEqual('something',
516
self.my_config.get_user_option('user_global_option'))
518
def test_get_user_option_local(self):
519
self.get_location_config('/a')
520
self.assertEqual('local',
521
self.my_config.get_user_option('user_local_option'))
523
def test_post_commit_default(self):
524
self.get_location_config('/a/c')
525
self.assertEqual('bzrlib.tests.test_config.post_commit',
526
self.my_config.post_commit())
529
class TestLocationConfig(TestCaseInTempDir):
531
def get_location_config(self, location, global_config=None):
532
if global_config is None:
533
global_file = StringIO(sample_config_text)
535
global_file = StringIO(global_config)
536
branches_file = StringIO(sample_branches_text)
537
self.my_config = config.LocationConfig(location)
538
self.my_config._get_parser(branches_file)
539
self.my_config._get_global_config()._get_parser(global_file)
541
def test_set_user_setting_sets_and_saves(self):
542
self.get_location_config('/a/c')
543
record = InstrumentedConfigObj("foo")
544
self.my_config._parser = record
546
real_mkdir = os.mkdir
548
def checked_mkdir(path, mode=0777):
549
self.log('making directory: %s', path)
550
real_mkdir(path, mode)
553
os.mkdir = checked_mkdir
555
self.my_config.set_user_option('foo', 'bar')
557
os.mkdir = real_mkdir
559
self.failUnless(self.created, 'Failed to create ~/.bazaar')
560
self.assertEqual([('__contains__', '/a/c'),
561
('__contains__', '/a/c/'),
562
('__setitem__', '/a/c', {}),
563
('__getitem__', '/a/c'),
564
('__setitem__', 'foo', 'bar'),
569
class TestBranchConfigItems(TestCase):
571
def test_user_id(self):
572
branch = FakeBranch()
573
my_config = config.BranchConfig(branch)
574
self.assertEqual("Robert Collins <robertc@example.net>",
575
my_config._get_user_id())
576
branch.control_files.email = "John"
577
self.assertEqual("John", my_config._get_user_id())
579
def test_not_set_in_branch(self):
580
branch = FakeBranch()
581
my_config = config.BranchConfig(branch)
582
branch.control_files.email = None
583
config_file = StringIO(sample_config_text)
584
(my_config._get_location_config().
585
_get_global_config()._get_parser(config_file))
586
self.assertEqual("Robert Collins <robertc@example.com>",
587
my_config._get_user_id())
588
branch.control_files.email = "John"
589
self.assertEqual("John", my_config._get_user_id())
591
def test_BZREMAIL_OVERRIDES(self):
592
os.environ['BZREMAIL'] = "Robert Collins <robertc@example.org>"
593
branch = FakeBranch()
594
my_config = config.BranchConfig(branch)
595
self.assertEqual("Robert Collins <robertc@example.org>",
596
my_config.username())
598
def test_signatures_forced(self):
599
branch = FakeBranch()
600
my_config = config.BranchConfig(branch)
601
config_file = StringIO(sample_always_signatures)
602
(my_config._get_location_config().
603
_get_global_config()._get_parser(config_file))
604
self.assertEqual(config.CHECK_ALWAYS, my_config.signature_checking())
606
def test_gpg_signing_command(self):
607
branch = FakeBranch()
608
my_config = config.BranchConfig(branch)
609
config_file = StringIO(sample_config_text)
610
(my_config._get_location_config().
611
_get_global_config()._get_parser(config_file))
612
self.assertEqual('gnome-gpg', my_config.gpg_signing_command())
614
def test_get_user_option_global(self):
615
branch = FakeBranch()
616
my_config = config.BranchConfig(branch)
617
config_file = StringIO(sample_config_text)
618
(my_config._get_location_config().
619
_get_global_config()._get_parser(config_file))
620
self.assertEqual('something',
621
my_config.get_user_option('user_global_option'))
623
def test_post_commit_default(self):
624
branch = FakeBranch()
626
my_config = config.BranchConfig(branch)
627
config_file = StringIO(sample_config_text)
628
(my_config._get_location_config().
629
_get_global_config()._get_parser(config_file))
630
branch_file = StringIO(sample_branches_text)
631
my_config._get_location_config()._get_parser(branch_file)
632
self.assertEqual('bzrlib.tests.test_config.post_commit',
633
my_config.post_commit())
636
class TestMailAddressExtraction(TestCase):
638
def test_extract_email_address(self):
639
self.assertEqual('jane@test.com',
640
config.extract_email_address('Jane <jane@test.com>'))
641
self.assertRaises(errors.BzrError,
642
config.extract_email_address, 'Jane Tester')