264
420
my_config = config.Config()
265
421
self.assertEqual('long', my_config.log_format())
268
class TestConfigPath(TestCase):
423
def test_get_change_editor(self):
424
my_config = InstrumentedConfig()
425
change_editor = my_config.get_change_editor('old_tree', 'new_tree')
426
self.assertEqual(['_get_change_editor'], my_config._calls)
427
self.assertIs(diff.DiffFromTool, change_editor.__class__)
428
self.assertEqual(['vimdiff', '-fo', '@new_path', '@old_path'],
429
change_editor.command_template)
432
class TestConfigPath(tests.TestCase):
271
435
super(TestConfigPath, self).setUp()
272
self.old_home = os.environ.get('HOME', None)
273
self.old_appdata = os.environ.get('APPDATA', None)
274
os.environ['HOME'] = '/home/bogus'
275
os.environ['APPDATA'] = \
276
r'C:\Documents and Settings\bogus\Application Data'
436
self.overrideEnv('HOME', '/home/bogus')
437
self.overrideEnv('XDG_CACHE_DIR', '')
438
if sys.platform == 'win32':
440
'BZR_HOME', r'C:\Documents and Settings\bogus\Application Data')
442
'C:/Documents and Settings/bogus/Application Data/bazaar/2.0'
444
self.bzr_home = '/home/bogus/.bazaar'
279
if self.old_home is None:
280
del os.environ['HOME']
282
os.environ['HOME'] = self.old_home
283
if self.old_appdata is None:
284
del os.environ['APPDATA']
286
os.environ['APPDATA'] = self.old_appdata
287
super(TestConfigPath, self).tearDown()
289
446
def test_config_dir(self):
290
if sys.platform == 'win32':
291
self.assertEqual(config.config_dir(),
292
'C:/Documents and Settings/bogus/Application Data/bazaar/2.0')
294
self.assertEqual(config.config_dir(), '/home/bogus/.bazaar')
447
self.assertEqual(config.config_dir(), self.bzr_home)
296
449
def test_config_filename(self):
297
if sys.platform == 'win32':
298
self.assertEqual(config.config_filename(),
299
'C:/Documents and Settings/bogus/Application Data/bazaar/2.0/bazaar.conf')
301
self.assertEqual(config.config_filename(),
302
'/home/bogus/.bazaar/bazaar.conf')
304
def test_branches_config_filename(self):
305
if sys.platform == 'win32':
306
self.assertEqual(config.branches_config_filename(),
307
'C:/Documents and Settings/bogus/Application Data/bazaar/2.0/branches.conf')
309
self.assertEqual(config.branches_config_filename(),
310
'/home/bogus/.bazaar/branches.conf')
450
self.assertEqual(config.config_filename(),
451
self.bzr_home + '/bazaar.conf')
312
453
def test_locations_config_filename(self):
313
if sys.platform == 'win32':
314
self.assertEqual(config.locations_config_filename(),
315
'C:/Documents and Settings/bogus/Application Data/bazaar/2.0/locations.conf')
317
self.assertEqual(config.locations_config_filename(),
318
'/home/bogus/.bazaar/locations.conf')
320
class TestIniConfig(TestCase):
454
self.assertEqual(config.locations_config_filename(),
455
self.bzr_home + '/locations.conf')
457
def test_authentication_config_filename(self):
458
self.assertEqual(config.authentication_config_filename(),
459
self.bzr_home + '/authentication.conf')
461
def test_xdg_cache_dir(self):
462
self.assertEqual(config.xdg_cache_dir(),
463
'/home/bogus/.cache')
466
class TestXDGConfigDir(tests.TestCaseInTempDir):
467
# must be in temp dir because config tests for the existence of the bazaar
468
# subdirectory of $XDG_CONFIG_HOME
471
if sys.platform in ('darwin', 'win32'):
472
raise tests.TestNotApplicable(
473
'XDG config dir not used on this platform')
474
super(TestXDGConfigDir, self).setUp()
475
self.overrideEnv('HOME', self.test_home_dir)
476
# BZR_HOME overrides everything we want to test so unset it.
477
self.overrideEnv('BZR_HOME', None)
479
def test_xdg_config_dir_exists(self):
480
"""When ~/.config/bazaar exists, use it as the config dir."""
481
newdir = osutils.pathjoin(self.test_home_dir, '.config', 'bazaar')
483
self.assertEqual(config.config_dir(), newdir)
485
def test_xdg_config_home(self):
486
"""When XDG_CONFIG_HOME is set, use it."""
487
xdgconfigdir = osutils.pathjoin(self.test_home_dir, 'xdgconfig')
488
self.overrideEnv('XDG_CONFIG_HOME', xdgconfigdir)
489
newdir = osutils.pathjoin(xdgconfigdir, 'bazaar')
491
self.assertEqual(config.config_dir(), newdir)
494
class TestIniConfig(tests.TestCaseInTempDir):
496
def make_config_parser(self, s):
497
conf = config.IniBasedConfig.from_string(s)
498
return conf, conf._get_parser()
501
class TestIniConfigBuilding(TestIniConfig):
322
503
def test_contructs(self):
323
my_config = config.IniBasedConfig("nothing")
504
my_config = config.IniBasedConfig()
325
506
def test_from_fp(self):
326
config_file = StringIO(sample_config_text.encode('utf-8'))
327
my_config = config.IniBasedConfig(None)
329
isinstance(my_config._get_parser(file=config_file),
507
my_config = config.IniBasedConfig.from_string(sample_config_text)
508
self.assertIsInstance(my_config._get_parser(), configobj.ConfigObj)
332
510
def test_cached(self):
511
my_config = config.IniBasedConfig.from_string(sample_config_text)
512
parser = my_config._get_parser()
513
self.assertTrue(my_config._get_parser() is parser)
515
def _dummy_chown(self, path, uid, gid):
516
self.path, self.uid, self.gid = path, uid, gid
518
def test_ini_config_ownership(self):
519
"""Ensure that chown is happening during _write_config_file"""
520
self.requireFeature(features.chown_feature)
521
self.overrideAttr(os, 'chown', self._dummy_chown)
522
self.path = self.uid = self.gid = None
523
conf = config.IniBasedConfig(file_name='./foo.conf')
524
conf._write_config_file()
525
self.assertEquals(self.path, './foo.conf')
526
self.assertTrue(isinstance(self.uid, int))
527
self.assertTrue(isinstance(self.gid, int))
529
def test_get_filename_parameter_is_deprecated_(self):
530
conf = self.callDeprecated([
531
'IniBasedConfig.__init__(get_filename) was deprecated in 2.3.'
532
' Use file_name instead.'],
533
config.IniBasedConfig, lambda: 'ini.conf')
534
self.assertEqual('ini.conf', conf.file_name)
536
def test_get_parser_file_parameter_is_deprecated_(self):
333
537
config_file = StringIO(sample_config_text.encode('utf-8'))
334
my_config = config.IniBasedConfig(None)
335
parser = my_config._get_parser(file=config_file)
336
self.failUnless(my_config._get_parser() is parser)
339
class TestGetConfig(TestCase):
538
conf = config.IniBasedConfig.from_string(sample_config_text)
539
conf = self.callDeprecated([
540
'IniBasedConfig._get_parser(file=xxx) was deprecated in 2.3.'
541
' Use IniBasedConfig(_content=xxx) instead.'],
542
conf._get_parser, file=config_file)
545
class TestIniConfigSaving(tests.TestCaseInTempDir):
547
def test_cant_save_without_a_file_name(self):
548
conf = config.IniBasedConfig()
549
self.assertRaises(AssertionError, conf._write_config_file)
551
def test_saved_with_content(self):
552
content = 'foo = bar\n'
553
conf = config.IniBasedConfig.from_string(
554
content, file_name='./test.conf', save=True)
555
self.assertFileEqual(content, 'test.conf')
558
class TestIniConfigOptionExpansionDefaultValue(tests.TestCaseInTempDir):
559
"""What is the default value of expand for config options.
561
This is an opt-in beta feature used to evaluate whether or not option
562
references can appear in dangerous place raising exceptions, disapearing
563
(and as such corrupting data) or if it's safe to activate the option by
566
Note that these tests relies on config._expand_default_value being already
567
overwritten in the parent class setUp.
571
super(TestIniConfigOptionExpansionDefaultValue, self).setUp()
575
self.warnings.append(args[0] % args[1:])
576
self.overrideAttr(trace, 'warning', warning)
578
def get_config(self, expand):
579
c = config.GlobalConfig.from_string('bzr.config.expand=%s' % (expand,),
583
def assertExpandIs(self, expected):
584
actual = config._get_expand_default_value()
585
#self.config.get_user_option_as_bool('bzr.config.expand')
586
self.assertEquals(expected, actual)
588
def test_default_is_None(self):
589
self.assertEquals(None, config._expand_default_value)
591
def test_default_is_False_even_if_None(self):
592
self.config = self.get_config(None)
593
self.assertExpandIs(False)
595
def test_default_is_False_even_if_invalid(self):
596
self.config = self.get_config('<your choice>')
597
self.assertExpandIs(False)
599
# Huh ? My choice is False ? Thanks, always happy to hear that :D
600
# Wait, you've been warned !
601
self.assertLength(1, self.warnings)
603
'Value "<your choice>" is not a boolean for "bzr.config.expand"',
606
def test_default_is_True(self):
607
self.config = self.get_config(True)
608
self.assertExpandIs(True)
610
def test_default_is_False(self):
611
self.config = self.get_config(False)
612
self.assertExpandIs(False)
615
class TestIniConfigOptionExpansion(tests.TestCase):
616
"""Test option expansion from the IniConfig level.
618
What we really want here is to test the Config level, but the class being
619
abstract as far as storing values is concerned, this can't be done
622
# FIXME: This should be rewritten when all configs share a storage
623
# implementation -- vila 2011-02-18
625
def get_config(self, string=None):
628
c = config.IniBasedConfig.from_string(string)
631
def assertExpansion(self, expected, conf, string, env=None):
632
self.assertEquals(expected, conf.expand_options(string, env))
634
def test_no_expansion(self):
635
c = self.get_config('')
636
self.assertExpansion('foo', c, 'foo')
638
def test_env_adding_options(self):
639
c = self.get_config('')
640
self.assertExpansion('bar', c, '{foo}', {'foo': 'bar'})
642
def test_env_overriding_options(self):
643
c = self.get_config('foo=baz')
644
self.assertExpansion('bar', c, '{foo}', {'foo': 'bar'})
646
def test_simple_ref(self):
647
c = self.get_config('foo=xxx')
648
self.assertExpansion('xxx', c, '{foo}')
650
def test_unknown_ref(self):
651
c = self.get_config('')
652
self.assertRaises(errors.ExpandingUnknownOption,
653
c.expand_options, '{foo}')
655
def test_indirect_ref(self):
656
c = self.get_config('''
660
self.assertExpansion('xxx', c, '{bar}')
662
def test_embedded_ref(self):
663
c = self.get_config('''
667
self.assertExpansion('xxx', c, '{{bar}}')
669
def test_simple_loop(self):
670
c = self.get_config('foo={foo}')
671
self.assertRaises(errors.OptionExpansionLoop, c.expand_options, '{foo}')
673
def test_indirect_loop(self):
674
c = self.get_config('''
678
e = self.assertRaises(errors.OptionExpansionLoop,
679
c.expand_options, '{foo}')
680
self.assertEquals('foo->bar->baz', e.refs)
681
self.assertEquals('{foo}', e.string)
684
conf = self.get_config('''
688
list={foo},{bar},{baz}
690
self.assertEquals(['start', 'middle', 'end'],
691
conf.get_user_option('list', expand=True))
693
def test_cascading_list(self):
694
conf = self.get_config('''
700
self.assertEquals(['start', 'middle', 'end'],
701
conf.get_user_option('list', expand=True))
703
def test_pathological_hidden_list(self):
704
conf = self.get_config('''
710
hidden={start}{middle}{end}
712
# Nope, it's either a string or a list, and the list wins as soon as a
713
# ',' appears, so the string concatenation never occur.
714
self.assertEquals(['{foo', '}', '{', 'bar}'],
715
conf.get_user_option('hidden', expand=True))
717
class TestLocationConfigOptionExpansion(tests.TestCaseInTempDir):
719
def get_config(self, location, string=None):
722
# Since we don't save the config we won't strictly require to inherit
723
# from TestCaseInTempDir, but an error occurs so quickly...
724
c = config.LocationConfig.from_string(string, location)
727
def test_dont_cross_unrelated_section(self):
728
c = self.get_config('/another/branch/path','''
733
[/another/branch/path]
736
self.assertRaises(errors.ExpandingUnknownOption,
737
c.get_user_option, 'bar', expand=True)
739
def test_cross_related_sections(self):
740
c = self.get_config('/project/branch/path','''
744
[/project/branch/path]
747
self.assertEquals('quux', c.get_user_option('bar', expand=True))
750
class TestIniBaseConfigOnDisk(tests.TestCaseInTempDir):
752
def test_cannot_reload_without_name(self):
753
conf = config.IniBasedConfig.from_string(sample_config_text)
754
self.assertRaises(AssertionError, conf.reload)
756
def test_reload_see_new_value(self):
757
c1 = config.IniBasedConfig.from_string('editor=vim\n',
758
file_name='./test/conf')
759
c1._write_config_file()
760
c2 = config.IniBasedConfig.from_string('editor=emacs\n',
761
file_name='./test/conf')
762
c2._write_config_file()
763
self.assertEqual('vim', c1.get_user_option('editor'))
764
self.assertEqual('emacs', c2.get_user_option('editor'))
765
# Make sure we get the Right value
767
self.assertEqual('emacs', c1.get_user_option('editor'))
770
class TestLockableConfig(tests.TestCaseInTempDir):
772
scenarios = lockable_config_scenarios()
777
config_section = None
780
super(TestLockableConfig, self).setUp()
781
self._content = '[%s]\none=1\ntwo=2\n' % (self.config_section,)
782
self.config = self.create_config(self._content)
784
def get_existing_config(self):
785
return self.config_class(*self.config_args)
787
def create_config(self, content):
788
kwargs = dict(save=True)
789
c = self.config_class.from_string(content, *self.config_args, **kwargs)
792
def test_simple_read_access(self):
793
self.assertEquals('1', self.config.get_user_option('one'))
795
def test_simple_write_access(self):
796
self.config.set_user_option('one', 'one')
797
self.assertEquals('one', self.config.get_user_option('one'))
799
def test_listen_to_the_last_speaker(self):
801
c2 = self.get_existing_config()
802
c1.set_user_option('one', 'ONE')
803
c2.set_user_option('two', 'TWO')
804
self.assertEquals('ONE', c1.get_user_option('one'))
805
self.assertEquals('TWO', c2.get_user_option('two'))
806
# The second update respect the first one
807
self.assertEquals('ONE', c2.get_user_option('one'))
809
def test_last_speaker_wins(self):
810
# If the same config is not shared, the same variable modified twice
811
# can only see a single result.
813
c2 = self.get_existing_config()
814
c1.set_user_option('one', 'c1')
815
c2.set_user_option('one', 'c2')
816
self.assertEquals('c2', c2._get_user_option('one'))
817
# The first modification is still available until another refresh
819
self.assertEquals('c1', c1._get_user_option('one'))
820
c1.set_user_option('two', 'done')
821
self.assertEquals('c2', c1._get_user_option('one'))
823
def test_writes_are_serialized(self):
825
c2 = self.get_existing_config()
827
# We spawn a thread that will pause *during* the write
828
before_writing = threading.Event()
829
after_writing = threading.Event()
830
writing_done = threading.Event()
831
c1_orig = c1._write_config_file
832
def c1_write_config_file():
835
# The lock is held we wait for the main thread to decide when to
838
c1._write_config_file = c1_write_config_file
840
c1.set_user_option('one', 'c1')
842
t1 = threading.Thread(target=c1_set_option)
843
# Collect the thread after the test
844
self.addCleanup(t1.join)
845
# Be ready to unblock the thread if the test goes wrong
846
self.addCleanup(after_writing.set)
848
before_writing.wait()
849
self.assertTrue(c1._lock.is_held)
850
self.assertRaises(errors.LockContention,
851
c2.set_user_option, 'one', 'c2')
852
self.assertEquals('c1', c1.get_user_option('one'))
853
# Let the lock be released
856
c2.set_user_option('one', 'c2')
857
self.assertEquals('c2', c2.get_user_option('one'))
859
def test_read_while_writing(self):
861
# We spawn a thread that will pause *during* the write
862
ready_to_write = threading.Event()
863
do_writing = threading.Event()
864
writing_done = threading.Event()
865
c1_orig = c1._write_config_file
866
def c1_write_config_file():
868
# The lock is held we wait for the main thread to decide when to
873
c1._write_config_file = c1_write_config_file
875
c1.set_user_option('one', 'c1')
876
t1 = threading.Thread(target=c1_set_option)
877
# Collect the thread after the test
878
self.addCleanup(t1.join)
879
# Be ready to unblock the thread if the test goes wrong
880
self.addCleanup(do_writing.set)
882
# Ensure the thread is ready to write
883
ready_to_write.wait()
884
self.assertTrue(c1._lock.is_held)
885
self.assertEquals('c1', c1.get_user_option('one'))
886
# If we read during the write, we get the old value
887
c2 = self.get_existing_config()
888
self.assertEquals('1', c2.get_user_option('one'))
889
# Let the writing occur and ensure it occurred
892
# Now we get the updated value
893
c3 = self.get_existing_config()
894
self.assertEquals('c1', c3.get_user_option('one'))
897
class TestGetUserOptionAs(TestIniConfig):
899
def test_get_user_option_as_bool(self):
900
conf, parser = self.make_config_parser("""
903
an_invalid_bool = maybe
904
a_list = hmm, who knows ? # This is interpreted as a list !
906
get_bool = conf.get_user_option_as_bool
907
self.assertEqual(True, get_bool('a_true_bool'))
908
self.assertEqual(False, get_bool('a_false_bool'))
911
warnings.append(args[0] % args[1:])
912
self.overrideAttr(trace, 'warning', warning)
913
msg = 'Value "%s" is not a boolean for "%s"'
914
self.assertIs(None, get_bool('an_invalid_bool'))
915
self.assertEquals(msg % ('maybe', 'an_invalid_bool'), warnings[0])
917
self.assertIs(None, get_bool('not_defined_in_this_config'))
918
self.assertEquals([], warnings)
920
def test_get_user_option_as_list(self):
921
conf, parser = self.make_config_parser("""
926
get_list = conf.get_user_option_as_list
927
self.assertEqual(['a', 'b', 'c'], get_list('a_list'))
928
self.assertEqual(['1'], get_list('length_1'))
929
self.assertEqual('x', conf.get_user_option('one_item'))
930
# automatically cast to list
931
self.assertEqual(['x'], get_list('one_item'))
934
class TestSupressWarning(TestIniConfig):
936
def make_warnings_config(self, s):
937
conf, parser = self.make_config_parser(s)
938
return conf.suppress_warning
940
def test_suppress_warning_unknown(self):
941
suppress_warning = self.make_warnings_config('')
942
self.assertEqual(False, suppress_warning('unknown_warning'))
944
def test_suppress_warning_known(self):
945
suppress_warning = self.make_warnings_config('suppress_warnings=a,b')
946
self.assertEqual(False, suppress_warning('c'))
947
self.assertEqual(True, suppress_warning('a'))
948
self.assertEqual(True, suppress_warning('b'))
951
class TestGetConfig(tests.TestCase):
341
953
def test_constructs(self):
342
954
my_config = config.GlobalConfig()
344
956
def test_calls_read_filenames(self):
345
# replace the class that is constructured, to check its parameters
957
# replace the class that is constructed, to check its parameters
346
958
oldparserclass = config.ConfigObj
347
959
config.ConfigObj = InstrumentedConfigObj
348
960
my_config = config.GlobalConfig()
965
1664
self.assertEqual('rmtree_root', my_config.post_commit())
967
1666
def test_config_precedence(self):
1667
# FIXME: eager test, luckily no persitent config file makes it fail
968
1669
my_config = self.get_branch_config(global_config=precedence_global)
969
1670
self.assertEqual(my_config.get_user_option('option'), 'global')
970
my_config = self.get_branch_config(global_config=precedence_global,
971
branch_data_config=precedence_branch)
1671
my_config = self.get_branch_config(global_config=precedence_global,
1672
branch_data_config=precedence_branch)
972
1673
self.assertEqual(my_config.get_user_option('option'), 'branch')
973
my_config = self.get_branch_config(global_config=precedence_global,
974
branch_data_config=precedence_branch,
975
location_config=precedence_location)
1674
my_config = self.get_branch_config(
1675
global_config=precedence_global,
1676
branch_data_config=precedence_branch,
1677
location_config=precedence_location)
976
1678
self.assertEqual(my_config.get_user_option('option'), 'recurse')
977
my_config = self.get_branch_config(global_config=precedence_global,
978
branch_data_config=precedence_branch,
979
location_config=precedence_location,
980
location='http://example.com/specific')
1679
my_config = self.get_branch_config(
1680
global_config=precedence_global,
1681
branch_data_config=precedence_branch,
1682
location_config=precedence_location,
1683
location='http://example.com/specific')
981
1684
self.assertEqual(my_config.get_user_option('option'), 'exact')
984
class TestMailAddressExtraction(TestCase):
1686
def test_get_mail_client(self):
1687
config = self.get_branch_config()
1688
client = config.get_mail_client()
1689
self.assertIsInstance(client, mail_client.DefaultMail)
1692
config.set_user_option('mail_client', 'evolution')
1693
client = config.get_mail_client()
1694
self.assertIsInstance(client, mail_client.Evolution)
1696
config.set_user_option('mail_client', 'kmail')
1697
client = config.get_mail_client()
1698
self.assertIsInstance(client, mail_client.KMail)
1700
config.set_user_option('mail_client', 'mutt')
1701
client = config.get_mail_client()
1702
self.assertIsInstance(client, mail_client.Mutt)
1704
config.set_user_option('mail_client', 'thunderbird')
1705
client = config.get_mail_client()
1706
self.assertIsInstance(client, mail_client.Thunderbird)
1709
config.set_user_option('mail_client', 'default')
1710
client = config.get_mail_client()
1711
self.assertIsInstance(client, mail_client.DefaultMail)
1713
config.set_user_option('mail_client', 'editor')
1714
client = config.get_mail_client()
1715
self.assertIsInstance(client, mail_client.Editor)
1717
config.set_user_option('mail_client', 'mapi')
1718
client = config.get_mail_client()
1719
self.assertIsInstance(client, mail_client.MAPIClient)
1721
config.set_user_option('mail_client', 'xdg-email')
1722
client = config.get_mail_client()
1723
self.assertIsInstance(client, mail_client.XDGEmail)
1725
config.set_user_option('mail_client', 'firebird')
1726
self.assertRaises(errors.UnknownMailClient, config.get_mail_client)
1729
class TestMailAddressExtraction(tests.TestCase):
986
1731
def test_extract_email_address(self):
987
1732
self.assertEqual('jane@test.com',
988
1733
config.extract_email_address('Jane <jane@test.com>'))
989
1734
self.assertRaises(errors.NoEmailInUsername,
990
1735
config.extract_email_address, 'Jane Tester')
1737
def test_parse_username(self):
1738
self.assertEqual(('', 'jdoe@example.com'),
1739
config.parse_username('jdoe@example.com'))
1740
self.assertEqual(('', 'jdoe@example.com'),
1741
config.parse_username('<jdoe@example.com>'))
1742
self.assertEqual(('John Doe', 'jdoe@example.com'),
1743
config.parse_username('John Doe <jdoe@example.com>'))
1744
self.assertEqual(('John Doe', ''),
1745
config.parse_username('John Doe'))
1746
self.assertEqual(('John Doe', 'jdoe@example.com'),
1747
config.parse_username('John Doe jdoe@example.com'))
1749
class TestTreeConfig(tests.TestCaseWithTransport):
1751
def test_get_value(self):
1752
"""Test that retreiving a value from a section is possible"""
1753
branch = self.make_branch('.')
1754
tree_config = config.TreeConfig(branch)
1755
tree_config.set_option('value', 'key', 'SECTION')
1756
tree_config.set_option('value2', 'key2')
1757
tree_config.set_option('value3-top', 'key3')
1758
tree_config.set_option('value3-section', 'key3', 'SECTION')
1759
value = tree_config.get_option('key', 'SECTION')
1760
self.assertEqual(value, 'value')
1761
value = tree_config.get_option('key2')
1762
self.assertEqual(value, 'value2')
1763
self.assertEqual(tree_config.get_option('non-existant'), None)
1764
value = tree_config.get_option('non-existant', 'SECTION')
1765
self.assertEqual(value, None)
1766
value = tree_config.get_option('non-existant', default='default')
1767
self.assertEqual(value, 'default')
1768
self.assertEqual(tree_config.get_option('key2', 'NOSECTION'), None)
1769
value = tree_config.get_option('key2', 'NOSECTION', default='default')
1770
self.assertEqual(value, 'default')
1771
value = tree_config.get_option('key3')
1772
self.assertEqual(value, 'value3-top')
1773
value = tree_config.get_option('key3', 'SECTION')
1774
self.assertEqual(value, 'value3-section')
1777
class TestTransportConfig(tests.TestCaseWithTransport):
1779
def test_get_value(self):
1780
"""Test that retreiving a value from a section is possible"""
1781
bzrdir_config = config.TransportConfig(transport.get_transport('.'),
1783
bzrdir_config.set_option('value', 'key', 'SECTION')
1784
bzrdir_config.set_option('value2', 'key2')
1785
bzrdir_config.set_option('value3-top', 'key3')
1786
bzrdir_config.set_option('value3-section', 'key3', 'SECTION')
1787
value = bzrdir_config.get_option('key', 'SECTION')
1788
self.assertEqual(value, 'value')
1789
value = bzrdir_config.get_option('key2')
1790
self.assertEqual(value, 'value2')
1791
self.assertEqual(bzrdir_config.get_option('non-existant'), None)
1792
value = bzrdir_config.get_option('non-existant', 'SECTION')
1793
self.assertEqual(value, None)
1794
value = bzrdir_config.get_option('non-existant', default='default')
1795
self.assertEqual(value, 'default')
1796
self.assertEqual(bzrdir_config.get_option('key2', 'NOSECTION'), None)
1797
value = bzrdir_config.get_option('key2', 'NOSECTION',
1799
self.assertEqual(value, 'default')
1800
value = bzrdir_config.get_option('key3')
1801
self.assertEqual(value, 'value3-top')
1802
value = bzrdir_config.get_option('key3', 'SECTION')
1803
self.assertEqual(value, 'value3-section')
1805
def test_set_unset_default_stack_on(self):
1806
my_dir = self.make_bzrdir('.')
1807
bzrdir_config = config.BzrDirConfig(my_dir)
1808
self.assertIs(None, bzrdir_config.get_default_stack_on())
1809
bzrdir_config.set_default_stack_on('Foo')
1810
self.assertEqual('Foo', bzrdir_config._config.get_option(
1811
'default_stack_on'))
1812
self.assertEqual('Foo', bzrdir_config.get_default_stack_on())
1813
bzrdir_config.set_default_stack_on(None)
1814
self.assertIs(None, bzrdir_config.get_default_stack_on())
1817
class TestConfigGetOptions(tests.TestCaseWithTransport, TestOptionsMixin):
1820
super(TestConfigGetOptions, self).setUp()
1821
create_configs(self)
1823
# One variable in none of the above
1824
def test_no_variable(self):
1825
# Using branch should query branch, locations and bazaar
1826
self.assertOptions([], self.branch_config)
1828
def test_option_in_bazaar(self):
1829
self.bazaar_config.set_user_option('file', 'bazaar')
1830
self.assertOptions([('file', 'bazaar', 'DEFAULT', 'bazaar')],
1833
def test_option_in_locations(self):
1834
self.locations_config.set_user_option('file', 'locations')
1836
[('file', 'locations', self.tree.basedir, 'locations')],
1837
self.locations_config)
1839
def test_option_in_branch(self):
1840
self.branch_config.set_user_option('file', 'branch')
1841
self.assertOptions([('file', 'branch', 'DEFAULT', 'branch')],
1844
def test_option_in_bazaar_and_branch(self):
1845
self.bazaar_config.set_user_option('file', 'bazaar')
1846
self.branch_config.set_user_option('file', 'branch')
1847
self.assertOptions([('file', 'branch', 'DEFAULT', 'branch'),
1848
('file', 'bazaar', 'DEFAULT', 'bazaar'),],
1851
def test_option_in_branch_and_locations(self):
1852
# Hmm, locations override branch :-/
1853
self.locations_config.set_user_option('file', 'locations')
1854
self.branch_config.set_user_option('file', 'branch')
1856
[('file', 'locations', self.tree.basedir, 'locations'),
1857
('file', 'branch', 'DEFAULT', 'branch'),],
1860
def test_option_in_bazaar_locations_and_branch(self):
1861
self.bazaar_config.set_user_option('file', 'bazaar')
1862
self.locations_config.set_user_option('file', 'locations')
1863
self.branch_config.set_user_option('file', 'branch')
1865
[('file', 'locations', self.tree.basedir, 'locations'),
1866
('file', 'branch', 'DEFAULT', 'branch'),
1867
('file', 'bazaar', 'DEFAULT', 'bazaar'),],
1871
class TestConfigRemoveOption(tests.TestCaseWithTransport, TestOptionsMixin):
1874
super(TestConfigRemoveOption, self).setUp()
1875
create_configs_with_file_option(self)
1877
def test_remove_in_locations(self):
1878
self.locations_config.remove_user_option('file', self.tree.basedir)
1880
[('file', 'branch', 'DEFAULT', 'branch'),
1881
('file', 'bazaar', 'DEFAULT', 'bazaar'),],
1884
def test_remove_in_branch(self):
1885
self.branch_config.remove_user_option('file')
1887
[('file', 'locations', self.tree.basedir, 'locations'),
1888
('file', 'bazaar', 'DEFAULT', 'bazaar'),],
1891
def test_remove_in_bazaar(self):
1892
self.bazaar_config.remove_user_option('file')
1894
[('file', 'locations', self.tree.basedir, 'locations'),
1895
('file', 'branch', 'DEFAULT', 'branch'),],
1899
class TestConfigGetSections(tests.TestCaseWithTransport):
1902
super(TestConfigGetSections, self).setUp()
1903
create_configs(self)
1905
def assertSectionNames(self, expected, conf, name=None):
1906
"""Check which sections are returned for a given config.
1908
If fallback configurations exist their sections can be included.
1910
:param expected: A list of section names.
1912
:param conf: The configuration that will be queried.
1914
:param name: An optional section name that will be passed to
1917
sections = list(conf._get_sections(name))
1918
self.assertLength(len(expected), sections)
1919
self.assertEqual(expected, [name for name, _, _ in sections])
1921
def test_bazaar_default_section(self):
1922
self.assertSectionNames(['DEFAULT'], self.bazaar_config)
1924
def test_locations_default_section(self):
1925
# No sections are defined in an empty file
1926
self.assertSectionNames([], self.locations_config)
1928
def test_locations_named_section(self):
1929
self.locations_config.set_user_option('file', 'locations')
1930
self.assertSectionNames([self.tree.basedir], self.locations_config)
1932
def test_locations_matching_sections(self):
1933
loc_config = self.locations_config
1934
loc_config.set_user_option('file', 'locations')
1935
# We need to cheat a bit here to create an option in sections above and
1936
# below the 'location' one.
1937
parser = loc_config._get_parser()
1938
# locations.cong deals with '/' ignoring native os.sep
1939
location_names = self.tree.basedir.split('/')
1940
parent = '/'.join(location_names[:-1])
1941
child = '/'.join(location_names + ['child'])
1943
parser[parent]['file'] = 'parent'
1945
parser[child]['file'] = 'child'
1946
self.assertSectionNames([self.tree.basedir, parent], loc_config)
1948
def test_branch_data_default_section(self):
1949
self.assertSectionNames([None],
1950
self.branch_config._get_branch_data_config())
1952
def test_branch_default_sections(self):
1953
# No sections are defined in an empty locations file
1954
self.assertSectionNames([None, 'DEFAULT'],
1956
# Unless we define an option
1957
self.branch_config._get_location_config().set_user_option(
1958
'file', 'locations')
1959
self.assertSectionNames([self.tree.basedir, None, 'DEFAULT'],
1962
def test_bazaar_named_section(self):
1963
# We need to cheat as the API doesn't give direct access to sections
1964
# other than DEFAULT.
1965
self.bazaar_config.set_alias('bazaar', 'bzr')
1966
self.assertSectionNames(['ALIASES'], self.bazaar_config, 'ALIASES')
1969
class TestAuthenticationConfigFile(tests.TestCase):
1970
"""Test the authentication.conf file matching"""
1972
def _got_user_passwd(self, expected_user, expected_password,
1973
config, *args, **kwargs):
1974
credentials = config.get_credentials(*args, **kwargs)
1975
if credentials is None:
1979
user = credentials['user']
1980
password = credentials['password']
1981
self.assertEquals(expected_user, user)
1982
self.assertEquals(expected_password, password)
1984
def test_empty_config(self):
1985
conf = config.AuthenticationConfig(_file=StringIO())
1986
self.assertEquals({}, conf._get_config())
1987
self._got_user_passwd(None, None, conf, 'http', 'foo.net')
1989
def test_missing_auth_section_header(self):
1990
conf = config.AuthenticationConfig(_file=StringIO('foo = bar'))
1991
self.assertRaises(ValueError, conf.get_credentials, 'ftp', 'foo.net')
1993
def test_auth_section_header_not_closed(self):
1994
conf = config.AuthenticationConfig(_file=StringIO('[DEF'))
1995
self.assertRaises(errors.ParseConfigError, conf._get_config)
1997
def test_auth_value_not_boolean(self):
1998
conf = config.AuthenticationConfig(_file=StringIO(
2002
verify_certificates=askme # Error: Not a boolean
2004
self.assertRaises(ValueError, conf.get_credentials, 'ftp', 'foo.net')
2006
def test_auth_value_not_int(self):
2007
conf = config.AuthenticationConfig(_file=StringIO(
2011
port=port # Error: Not an int
2013
self.assertRaises(ValueError, conf.get_credentials, 'ftp', 'foo.net')
2015
def test_unknown_password_encoding(self):
2016
conf = config.AuthenticationConfig(_file=StringIO(
2020
password_encoding=unknown
2022
self.assertRaises(ValueError, conf.get_password,
2023
'ftp', 'foo.net', 'joe')
2025
def test_credentials_for_scheme_host(self):
2026
conf = config.AuthenticationConfig(_file=StringIO(
2027
"""# Identity on foo.net
2032
password=secret-pass
2035
self._got_user_passwd('joe', 'secret-pass', conf, 'ftp', 'foo.net')
2037
self._got_user_passwd(None, None, conf, 'http', 'foo.net')
2039
self._got_user_passwd(None, None, conf, 'ftp', 'bar.net')
2041
def test_credentials_for_host_port(self):
2042
conf = config.AuthenticationConfig(_file=StringIO(
2043
"""# Identity on foo.net
2049
password=secret-pass
2052
self._got_user_passwd('joe', 'secret-pass',
2053
conf, 'ftp', 'foo.net', port=10021)
2055
self._got_user_passwd(None, None, conf, 'ftp', 'foo.net')
2057
def test_for_matching_host(self):
2058
conf = config.AuthenticationConfig(_file=StringIO(
2059
"""# Identity on foo.net
2065
[sourceforge domain]
2072
self._got_user_passwd('georges', 'bendover',
2073
conf, 'bzr', 'foo.bzr.sf.net')
2075
self._got_user_passwd(None, None,
2076
conf, 'bzr', 'bbzr.sf.net')
2078
def test_for_matching_host_None(self):
2079
conf = config.AuthenticationConfig(_file=StringIO(
2080
"""# Identity on foo.net
2090
self._got_user_passwd('joe', 'joepass',
2091
conf, 'bzr', 'quux.net')
2092
# no host but different scheme
2093
self._got_user_passwd('georges', 'bendover',
2094
conf, 'ftp', 'quux.net')
2096
def test_credentials_for_path(self):
2097
conf = config.AuthenticationConfig(_file=StringIO(
2113
self._got_user_passwd(None, None,
2114
conf, 'http', host='bar.org', path='/dir3')
2116
self._got_user_passwd('georges', 'bendover',
2117
conf, 'http', host='bar.org', path='/dir2')
2119
self._got_user_passwd('jim', 'jimpass',
2120
conf, 'http', host='bar.org',path='/dir1/subdir')
2122
def test_credentials_for_user(self):
2123
conf = config.AuthenticationConfig(_file=StringIO(
2132
self._got_user_passwd('jim', 'jimpass',
2133
conf, 'http', 'bar.org')
2135
self._got_user_passwd('jim', 'jimpass',
2136
conf, 'http', 'bar.org', user='jim')
2137
# Don't get a different user if one is specified
2138
self._got_user_passwd(None, None,
2139
conf, 'http', 'bar.org', user='georges')
2141
def test_credentials_for_user_without_password(self):
2142
conf = config.AuthenticationConfig(_file=StringIO(
2149
# Get user but no password
2150
self._got_user_passwd('jim', None,
2151
conf, 'http', 'bar.org')
2153
def test_verify_certificates(self):
2154
conf = config.AuthenticationConfig(_file=StringIO(
2161
verify_certificates=False
2168
credentials = conf.get_credentials('https', 'bar.org')
2169
self.assertEquals(False, credentials.get('verify_certificates'))
2170
credentials = conf.get_credentials('https', 'foo.net')
2171
self.assertEquals(True, credentials.get('verify_certificates'))
2174
class TestAuthenticationStorage(tests.TestCaseInTempDir):
2176
def test_set_credentials(self):
2177
conf = config.AuthenticationConfig()
2178
conf.set_credentials('name', 'host', 'user', 'scheme', 'password',
2179
99, path='/foo', verify_certificates=False, realm='realm')
2180
credentials = conf.get_credentials(host='host', scheme='scheme',
2181
port=99, path='/foo',
2183
CREDENTIALS = {'name': 'name', 'user': 'user', 'password': 'password',
2184
'verify_certificates': False, 'scheme': 'scheme',
2185
'host': 'host', 'port': 99, 'path': '/foo',
2187
self.assertEqual(CREDENTIALS, credentials)
2188
credentials_from_disk = config.AuthenticationConfig().get_credentials(
2189
host='host', scheme='scheme', port=99, path='/foo', realm='realm')
2190
self.assertEqual(CREDENTIALS, credentials_from_disk)
2192
def test_reset_credentials_different_name(self):
2193
conf = config.AuthenticationConfig()
2194
conf.set_credentials('name', 'host', 'user', 'scheme', 'password'),
2195
conf.set_credentials('name2', 'host', 'user2', 'scheme', 'password'),
2196
self.assertIs(None, conf._get_config().get('name'))
2197
credentials = conf.get_credentials(host='host', scheme='scheme')
2198
CREDENTIALS = {'name': 'name2', 'user': 'user2', 'password':
2199
'password', 'verify_certificates': True,
2200
'scheme': 'scheme', 'host': 'host', 'port': None,
2201
'path': None, 'realm': None}
2202
self.assertEqual(CREDENTIALS, credentials)
2205
class TestAuthenticationConfig(tests.TestCase):
2206
"""Test AuthenticationConfig behaviour"""
2208
def _check_default_password_prompt(self, expected_prompt_format, scheme,
2209
host=None, port=None, realm=None,
2213
user, password = 'jim', 'precious'
2214
expected_prompt = expected_prompt_format % {
2215
'scheme': scheme, 'host': host, 'port': port,
2216
'user': user, 'realm': realm}
2218
stdout = tests.StringIOWrapper()
2219
stderr = tests.StringIOWrapper()
2220
ui.ui_factory = tests.TestUIFactory(stdin=password + '\n',
2221
stdout=stdout, stderr=stderr)
2222
# We use an empty conf so that the user is always prompted
2223
conf = config.AuthenticationConfig()
2224
self.assertEquals(password,
2225
conf.get_password(scheme, host, user, port=port,
2226
realm=realm, path=path))
2227
self.assertEquals(expected_prompt, stderr.getvalue())
2228
self.assertEquals('', stdout.getvalue())
2230
def _check_default_username_prompt(self, expected_prompt_format, scheme,
2231
host=None, port=None, realm=None,
2236
expected_prompt = expected_prompt_format % {
2237
'scheme': scheme, 'host': host, 'port': port,
2239
stdout = tests.StringIOWrapper()
2240
stderr = tests.StringIOWrapper()
2241
ui.ui_factory = tests.TestUIFactory(stdin=username+ '\n',
2242
stdout=stdout, stderr=stderr)
2243
# We use an empty conf so that the user is always prompted
2244
conf = config.AuthenticationConfig()
2245
self.assertEquals(username, conf.get_user(scheme, host, port=port,
2246
realm=realm, path=path, ask=True))
2247
self.assertEquals(expected_prompt, stderr.getvalue())
2248
self.assertEquals('', stdout.getvalue())
2250
def test_username_defaults_prompts(self):
2251
# HTTP prompts can't be tested here, see test_http.py
2252
self._check_default_username_prompt('FTP %(host)s username: ', 'ftp')
2253
self._check_default_username_prompt(
2254
'FTP %(host)s:%(port)d username: ', 'ftp', port=10020)
2255
self._check_default_username_prompt(
2256
'SSH %(host)s:%(port)d username: ', 'ssh', port=12345)
2258
def test_username_default_no_prompt(self):
2259
conf = config.AuthenticationConfig()
2260
self.assertEquals(None,
2261
conf.get_user('ftp', 'example.com'))
2262
self.assertEquals("explicitdefault",
2263
conf.get_user('ftp', 'example.com', default="explicitdefault"))
2265
def test_password_default_prompts(self):
2266
# HTTP prompts can't be tested here, see test_http.py
2267
self._check_default_password_prompt(
2268
'FTP %(user)s@%(host)s password: ', 'ftp')
2269
self._check_default_password_prompt(
2270
'FTP %(user)s@%(host)s:%(port)d password: ', 'ftp', port=10020)
2271
self._check_default_password_prompt(
2272
'SSH %(user)s@%(host)s:%(port)d password: ', 'ssh', port=12345)
2273
# SMTP port handling is a bit special (it's handled if embedded in the
2275
# FIXME: should we: forbid that, extend it to other schemes, leave
2276
# things as they are that's fine thank you ?
2277
self._check_default_password_prompt('SMTP %(user)s@%(host)s password: ',
2279
self._check_default_password_prompt('SMTP %(user)s@%(host)s password: ',
2280
'smtp', host='bar.org:10025')
2281
self._check_default_password_prompt(
2282
'SMTP %(user)s@%(host)s:%(port)d password: ',
2285
def test_ssh_password_emits_warning(self):
2286
conf = config.AuthenticationConfig(_file=StringIO(
2294
entered_password = 'typed-by-hand'
2295
stdout = tests.StringIOWrapper()
2296
stderr = tests.StringIOWrapper()
2297
ui.ui_factory = tests.TestUIFactory(stdin=entered_password + '\n',
2298
stdout=stdout, stderr=stderr)
2300
# Since the password defined in the authentication config is ignored,
2301
# the user is prompted
2302
self.assertEquals(entered_password,
2303
conf.get_password('ssh', 'bar.org', user='jim'))
2304
self.assertContainsRe(
2306
'password ignored in section \[ssh with password\]')
2308
def test_ssh_without_password_doesnt_emit_warning(self):
2309
conf = config.AuthenticationConfig(_file=StringIO(
2316
entered_password = 'typed-by-hand'
2317
stdout = tests.StringIOWrapper()
2318
stderr = tests.StringIOWrapper()
2319
ui.ui_factory = tests.TestUIFactory(stdin=entered_password + '\n',
2323
# Since the password defined in the authentication config is ignored,
2324
# the user is prompted
2325
self.assertEquals(entered_password,
2326
conf.get_password('ssh', 'bar.org', user='jim'))
2327
# No warning shoud be emitted since there is no password. We are only
2329
self.assertNotContainsRe(
2331
'password ignored in section \[ssh with password\]')
2333
def test_uses_fallback_stores(self):
2334
self.overrideAttr(config, 'credential_store_registry',
2335
config.CredentialStoreRegistry())
2336
store = StubCredentialStore()
2337
store.add_credentials("http", "example.com", "joe", "secret")
2338
config.credential_store_registry.register("stub", store, fallback=True)
2339
conf = config.AuthenticationConfig(_file=StringIO())
2340
creds = conf.get_credentials("http", "example.com")
2341
self.assertEquals("joe", creds["user"])
2342
self.assertEquals("secret", creds["password"])
2345
class StubCredentialStore(config.CredentialStore):
2351
def add_credentials(self, scheme, host, user, password=None):
2352
self._username[(scheme, host)] = user
2353
self._password[(scheme, host)] = password
2355
def get_credentials(self, scheme, host, port=None, user=None,
2356
path=None, realm=None):
2357
key = (scheme, host)
2358
if not key in self._username:
2360
return { "scheme": scheme, "host": host, "port": port,
2361
"user": self._username[key], "password": self._password[key]}
2364
class CountingCredentialStore(config.CredentialStore):
2369
def get_credentials(self, scheme, host, port=None, user=None,
2370
path=None, realm=None):
2375
class TestCredentialStoreRegistry(tests.TestCase):
2377
def _get_cs_registry(self):
2378
return config.credential_store_registry
2380
def test_default_credential_store(self):
2381
r = self._get_cs_registry()
2382
default = r.get_credential_store(None)
2383
self.assertIsInstance(default, config.PlainTextCredentialStore)
2385
def test_unknown_credential_store(self):
2386
r = self._get_cs_registry()
2387
# It's hard to imagine someone creating a credential store named
2388
# 'unknown' so we use that as an never registered key.
2389
self.assertRaises(KeyError, r.get_credential_store, 'unknown')
2391
def test_fallback_none_registered(self):
2392
r = config.CredentialStoreRegistry()
2393
self.assertEquals(None,
2394
r.get_fallback_credentials("http", "example.com"))
2396
def test_register(self):
2397
r = config.CredentialStoreRegistry()
2398
r.register("stub", StubCredentialStore(), fallback=False)
2399
r.register("another", StubCredentialStore(), fallback=True)
2400
self.assertEquals(["another", "stub"], r.keys())
2402
def test_register_lazy(self):
2403
r = config.CredentialStoreRegistry()
2404
r.register_lazy("stub", "bzrlib.tests.test_config",
2405
"StubCredentialStore", fallback=False)
2406
self.assertEquals(["stub"], r.keys())
2407
self.assertIsInstance(r.get_credential_store("stub"),
2408
StubCredentialStore)
2410
def test_is_fallback(self):
2411
r = config.CredentialStoreRegistry()
2412
r.register("stub1", None, fallback=False)
2413
r.register("stub2", None, fallback=True)
2414
self.assertEquals(False, r.is_fallback("stub1"))
2415
self.assertEquals(True, r.is_fallback("stub2"))
2417
def test_no_fallback(self):
2418
r = config.CredentialStoreRegistry()
2419
store = CountingCredentialStore()
2420
r.register("count", store, fallback=False)
2421
self.assertEquals(None,
2422
r.get_fallback_credentials("http", "example.com"))
2423
self.assertEquals(0, store._calls)
2425
def test_fallback_credentials(self):
2426
r = config.CredentialStoreRegistry()
2427
store = StubCredentialStore()
2428
store.add_credentials("http", "example.com",
2429
"somebody", "geheim")
2430
r.register("stub", store, fallback=True)
2431
creds = r.get_fallback_credentials("http", "example.com")
2432
self.assertEquals("somebody", creds["user"])
2433
self.assertEquals("geheim", creds["password"])
2435
def test_fallback_first_wins(self):
2436
r = config.CredentialStoreRegistry()
2437
stub1 = StubCredentialStore()
2438
stub1.add_credentials("http", "example.com",
2439
"somebody", "stub1")
2440
r.register("stub1", stub1, fallback=True)
2441
stub2 = StubCredentialStore()
2442
stub2.add_credentials("http", "example.com",
2443
"somebody", "stub2")
2444
r.register("stub2", stub1, fallback=True)
2445
creds = r.get_fallback_credentials("http", "example.com")
2446
self.assertEquals("somebody", creds["user"])
2447
self.assertEquals("stub1", creds["password"])
2450
class TestPlainTextCredentialStore(tests.TestCase):
2452
def test_decode_password(self):
2453
r = config.credential_store_registry
2454
plain_text = r.get_credential_store()
2455
decoded = plain_text.decode_password(dict(password='secret'))
2456
self.assertEquals('secret', decoded)
2459
# FIXME: Once we have a way to declare authentication to all test servers, we
2460
# can implement generic tests.
2461
# test_user_password_in_url
2462
# test_user_in_url_password_from_config
2463
# test_user_in_url_password_prompted
2464
# test_user_in_config
2465
# test_user_getpass.getuser
2466
# test_user_prompted ?
2467
class TestAuthenticationRing(tests.TestCaseWithTransport):
2471
class TestAutoUserId(tests.TestCase):
2472
"""Test inferring an automatic user name."""
2474
def test_auto_user_id(self):
2475
"""Automatic inference of user name.
2477
This is a bit hard to test in an isolated way, because it depends on
2478
system functions that go direct to /etc or perhaps somewhere else.
2479
But it's reasonable to say that on Unix, with an /etc/mailname, we ought
2480
to be able to choose a user name with no configuration.
2482
if sys.platform == 'win32':
2483
raise TestSkipped("User name inference not implemented on win32")
2484
realname, address = config._auto_user_id()
2485
if os.path.exists('/etc/mailname'):
2486
self.assertIsNot(None, realname)
2487
self.assertIsNot(None, address)
2489
self.assertEquals((None, None), (realname, address))