~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_config.py

  • Committer: Vincent Ladeuil
  • Date: 2010-07-15 13:05:40 UTC
  • mto: This revision was merged to the branch mainline in revision 5347.
  • Revision ID: v.ladeuil+lp@free.fr-20100715130540-nac9q1yu78870v0e
Delete the after_cleanup_size parameter from the LRUCache constructor.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2011 Canonical Ltd
 
1
# Copyright (C) 2005-2010 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
19
19
from cStringIO import StringIO
20
20
import os
21
21
import sys
22
 
import threading
23
 
 
24
 
 
25
 
from testtools import matchers
26
22
 
27
23
#import bzrlib specific imports here
28
24
from bzrlib import (
33
29
    errors,
34
30
    osutils,
35
31
    mail_client,
36
 
    mergetools,
37
32
    ui,
38
33
    urlutils,
39
34
    tests,
40
35
    trace,
41
36
    transport,
42
37
    )
43
 
from bzrlib.tests import (
44
 
    features,
45
 
    TestSkipped,
46
 
    scenarios,
47
 
    )
48
38
from bzrlib.util.configobj import configobj
49
39
 
50
40
 
51
 
def lockable_config_scenarios():
52
 
    return [
53
 
        ('global',
54
 
         {'config_class': config.GlobalConfig,
55
 
          'config_args': [],
56
 
          'config_section': 'DEFAULT'}),
57
 
        ('locations',
58
 
         {'config_class': config.LocationConfig,
59
 
          'config_args': ['.'],
60
 
          'config_section': '.'}),]
61
 
 
62
 
 
63
 
load_tests = scenarios.load_tests_apply_scenarios
64
 
 
65
 
 
66
41
sample_long_alias="log -r-15..-1 --line"
67
42
sample_config_text = u"""
68
43
[DEFAULT]
72
47
gpg_signing_command=gnome-gpg
73
48
log_format=short
74
49
user_global_option=something
75
 
bzr.mergetool.sometool=sometool {base} {this} {other} -o {result}
76
 
bzr.mergetool.funkytool=funkytool "arg with spaces" {this_temp}
77
 
bzr.default_mergetool=sometool
78
50
[ALIASES]
79
51
h=help
80
52
ll=""" + sample_long_alias + "\n"
133
105
"""
134
106
 
135
107
 
136
 
def create_configs(test):
137
 
    """Create configuration files for a given test.
138
 
 
139
 
    This requires creating a tree (and populate the ``test.tree`` attribute)
140
 
    and its associated branch and will populate the following attributes:
141
 
 
142
 
    - branch_config: A BranchConfig for the associated branch.
143
 
 
144
 
    - locations_config : A LocationConfig for the associated branch
145
 
 
146
 
    - bazaar_config: A GlobalConfig.
147
 
 
148
 
    The tree and branch are created in a 'tree' subdirectory so the tests can
149
 
    still use the test directory to stay outside of the branch.
150
 
    """
151
 
    tree = test.make_branch_and_tree('tree')
152
 
    test.tree = tree
153
 
    test.branch_config = config.BranchConfig(tree.branch)
154
 
    test.locations_config = config.LocationConfig(tree.basedir)
155
 
    test.bazaar_config = config.GlobalConfig()
156
 
 
157
 
 
158
 
def create_configs_with_file_option(test):
159
 
    """Create configuration files with a ``file`` option set in each.
160
 
 
161
 
    This builds on ``create_configs`` and add one ``file`` option in each
162
 
    configuration with a value which allows identifying the configuration file.
163
 
    """
164
 
    create_configs(test)
165
 
    test.bazaar_config.set_user_option('file', 'bazaar')
166
 
    test.locations_config.set_user_option('file', 'locations')
167
 
    test.branch_config.set_user_option('file', 'branch')
168
 
 
169
 
 
170
 
class TestOptionsMixin:
171
 
 
172
 
    def assertOptions(self, expected, conf):
173
 
        # We don't care about the parser (as it will make tests hard to write
174
 
        # and error-prone anyway)
175
 
        self.assertThat([opt[:4] for opt in conf._get_options()],
176
 
                        matchers.Equals(expected))
177
 
 
178
 
 
179
108
class InstrumentedConfigObj(object):
180
109
    """A config obj look-enough-alike to record calls made to it."""
181
110
 
200
129
        self._calls.append(('keys',))
201
130
        return []
202
131
 
203
 
    def reload(self):
204
 
        self._calls.append(('reload',))
205
 
 
206
132
    def write(self, arg):
207
133
        self._calls.append(('write',))
208
134
 
314
240
        """
315
241
        co = config.ConfigObj()
316
242
        co['test'] = 'foo#bar'
317
 
        outfile = StringIO()
318
 
        co.write(outfile=outfile)
319
 
        lines = outfile.getvalue().splitlines()
 
243
        lines = co.write()
320
244
        self.assertEqual(lines, ['test = "foo#bar"'])
321
245
        co2 = config.ConfigObj(lines)
322
246
        self.assertEqual(co2['test'], 'foo#bar')
323
247
 
324
 
    def test_triple_quotes(self):
325
 
        # Bug #710410: if the value string has triple quotes
326
 
        # then ConfigObj versions up to 4.7.2 will quote them wrong
327
 
        # and won't able to read them back
328
 
        triple_quotes_value = '''spam
329
 
""" that's my spam """
330
 
eggs'''
331
 
        co = config.ConfigObj()
332
 
        co['test'] = triple_quotes_value
333
 
        # While writing this test another bug in ConfigObj has been found:
334
 
        # method co.write() without arguments produces list of lines
335
 
        # one option per line, and multiline values are not split
336
 
        # across multiple lines,
337
 
        # and that breaks the parsing these lines back by ConfigObj.
338
 
        # This issue only affects test, but it's better to avoid
339
 
        # `co.write()` construct at all.
340
 
        # [bialix 20110222] bug report sent to ConfigObj's author
341
 
        outfile = StringIO()
342
 
        co.write(outfile=outfile)
343
 
        output = outfile.getvalue()
344
 
        # now we're trying to read it back
345
 
        co2 = config.ConfigObj(StringIO(output))
346
 
        self.assertEquals(triple_quotes_value, co2['test'])
347
 
 
348
248
 
349
249
erroneous_config = """[section] # line 1
350
250
good=good # line 2
433
333
 
434
334
    def setUp(self):
435
335
        super(TestConfigPath, self).setUp()
436
 
        self.overrideEnv('HOME', '/home/bogus')
437
 
        self.overrideEnv('XDG_CACHE_DIR', '')
 
336
        os.environ['HOME'] = '/home/bogus'
 
337
        os.environ['XDG_CACHE_DIR'] = ''
438
338
        if sys.platform == 'win32':
439
 
            self.overrideEnv(
440
 
                'BZR_HOME', r'C:\Documents and Settings\bogus\Application Data')
 
339
            os.environ['BZR_HOME'] = \
 
340
                r'C:\Documents and Settings\bogus\Application Data'
441
341
            self.bzr_home = \
442
342
                'C:/Documents and Settings/bogus/Application Data/bazaar/2.0'
443
343
        else:
450
350
        self.assertEqual(config.config_filename(),
451
351
                         self.bzr_home + '/bazaar.conf')
452
352
 
 
353
    def test_branches_config_filename(self):
 
354
        self.assertEqual(config.branches_config_filename(),
 
355
                         self.bzr_home + '/branches.conf')
 
356
 
453
357
    def test_locations_config_filename(self):
454
358
        self.assertEqual(config.locations_config_filename(),
455
359
                         self.bzr_home + '/locations.conf')
463
367
            '/home/bogus/.cache')
464
368
 
465
369
 
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
469
 
 
470
 
    def setUp(self):
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)
478
 
 
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')
482
 
        os.makedirs(newdir)
483
 
        self.assertEqual(config.config_dir(), newdir)
484
 
 
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')
490
 
        os.makedirs(newdir)
491
 
        self.assertEqual(config.config_dir(), newdir)
492
 
 
493
 
 
494
 
class TestIniConfig(tests.TestCaseInTempDir):
 
370
class TestIniConfig(tests.TestCase):
495
371
 
496
372
    def make_config_parser(self, s):
497
 
        conf = config.IniBasedConfig.from_string(s)
498
 
        return conf, conf._get_parser()
 
373
        conf = config.IniBasedConfig(None)
 
374
        parser = conf._get_parser(file=StringIO(s.encode('utf-8')))
 
375
        return conf, parser
499
376
 
500
377
 
501
378
class TestIniConfigBuilding(TestIniConfig):
502
379
 
503
380
    def test_contructs(self):
504
 
        my_config = config.IniBasedConfig()
 
381
        my_config = config.IniBasedConfig("nothing")
505
382
 
506
383
    def test_from_fp(self):
507
 
        my_config = config.IniBasedConfig.from_string(sample_config_text)
508
 
        self.assertIsInstance(my_config._get_parser(), configobj.ConfigObj)
 
384
        config_file = StringIO(sample_config_text.encode('utf-8'))
 
385
        my_config = config.IniBasedConfig(None)
 
386
        self.failUnless(
 
387
            isinstance(my_config._get_parser(file=config_file),
 
388
                        configobj.ConfigObj))
509
389
 
510
390
    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)
514
 
 
515
 
    def _dummy_chown(self, path, uid, gid):
516
 
        self.path, self.uid, self.gid = path, uid, gid
517
 
 
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))
528
 
 
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)
535
 
 
536
 
    def test_get_parser_file_parameter_is_deprecated_(self):
537
391
        config_file = StringIO(sample_config_text.encode('utf-8'))
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)
543
 
 
544
 
 
545
 
class TestIniConfigSaving(tests.TestCaseInTempDir):
546
 
 
547
 
    def test_cant_save_without_a_file_name(self):
548
 
        conf = config.IniBasedConfig()
549
 
        self.assertRaises(AssertionError, conf._write_config_file)
550
 
 
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')
556
 
 
557
 
 
558
 
class TestIniConfigOptionExpansionDefaultValue(tests.TestCaseInTempDir):
559
 
    """What is the default value of expand for config options.
560
 
 
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
564
 
    default.
565
 
 
566
 
    Note that these tests relies on config._expand_default_value being already
567
 
    overwritten in the parent class setUp.
568
 
    """
569
 
 
570
 
    def setUp(self):
571
 
        super(TestIniConfigOptionExpansionDefaultValue, self).setUp()
572
 
        self.config = None
573
 
        self.warnings = []
574
 
        def warning(*args):
575
 
            self.warnings.append(args[0] % args[1:])
576
 
        self.overrideAttr(trace, 'warning', warning)
577
 
 
578
 
    def get_config(self, expand):
579
 
        c = config.GlobalConfig.from_string('bzr.config.expand=%s' % (expand,),
580
 
                                            save=True)
581
 
        return c
582
 
 
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)
587
 
 
588
 
    def test_default_is_None(self):
589
 
        self.assertEquals(None, config._expand_default_value)
590
 
 
591
 
    def test_default_is_False_even_if_None(self):
592
 
        self.config = self.get_config(None)
593
 
        self.assertExpandIs(False)
594
 
 
595
 
    def test_default_is_False_even_if_invalid(self):
596
 
        self.config = self.get_config('<your choice>')
597
 
        self.assertExpandIs(False)
598
 
        # ...
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)
602
 
        self.assertEquals(
603
 
            'Value "<your choice>" is not a boolean for "bzr.config.expand"',
604
 
            self.warnings[0])
605
 
 
606
 
    def test_default_is_True(self):
607
 
        self.config = self.get_config(True)
608
 
        self.assertExpandIs(True)
609
 
        
610
 
    def test_default_is_False(self):
611
 
        self.config = self.get_config(False)
612
 
        self.assertExpandIs(False)
613
 
        
614
 
 
615
 
class TestIniConfigOptionExpansion(tests.TestCase):
616
 
    """Test option expansion from the IniConfig level.
617
 
 
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
620
 
    properly (yet).
621
 
    """
622
 
    # FIXME: This should be rewritten when all configs share a storage
623
 
    # implementation -- vila 2011-02-18
624
 
 
625
 
    def get_config(self, string=None):
626
 
        if string is None:
627
 
            string = ''
628
 
        c = config.IniBasedConfig.from_string(string)
629
 
        return c
630
 
 
631
 
    def assertExpansion(self, expected, conf, string, env=None):
632
 
        self.assertEquals(expected, conf.expand_options(string, env))
633
 
 
634
 
    def test_no_expansion(self):
635
 
        c = self.get_config('')
636
 
        self.assertExpansion('foo', c, 'foo')
637
 
 
638
 
    def test_env_adding_options(self):
639
 
        c = self.get_config('')
640
 
        self.assertExpansion('bar', c, '{foo}', {'foo': 'bar'})
641
 
 
642
 
    def test_env_overriding_options(self):
643
 
        c = self.get_config('foo=baz')
644
 
        self.assertExpansion('bar', c, '{foo}', {'foo': 'bar'})
645
 
 
646
 
    def test_simple_ref(self):
647
 
        c = self.get_config('foo=xxx')
648
 
        self.assertExpansion('xxx', c, '{foo}')
649
 
 
650
 
    def test_unknown_ref(self):
651
 
        c = self.get_config('')
652
 
        self.assertRaises(errors.ExpandingUnknownOption,
653
 
                          c.expand_options, '{foo}')
654
 
 
655
 
    def test_indirect_ref(self):
656
 
        c = self.get_config('''
657
 
foo=xxx
658
 
bar={foo}
659
 
''')
660
 
        self.assertExpansion('xxx', c, '{bar}')
661
 
 
662
 
    def test_embedded_ref(self):
663
 
        c = self.get_config('''
664
 
foo=xxx
665
 
bar=foo
666
 
''')
667
 
        self.assertExpansion('xxx', c, '{{bar}}')
668
 
 
669
 
    def test_simple_loop(self):
670
 
        c = self.get_config('foo={foo}')
671
 
        self.assertRaises(errors.OptionExpansionLoop, c.expand_options, '{foo}')
672
 
 
673
 
    def test_indirect_loop(self):
674
 
        c = self.get_config('''
675
 
foo={bar}
676
 
bar={baz}
677
 
baz={foo}''')
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)
682
 
 
683
 
    def test_list(self):
684
 
        conf = self.get_config('''
685
 
foo=start
686
 
bar=middle
687
 
baz=end
688
 
list={foo},{bar},{baz}
689
 
''')
690
 
        self.assertEquals(['start', 'middle', 'end'],
691
 
                           conf.get_user_option('list', expand=True))
692
 
 
693
 
    def test_cascading_list(self):
694
 
        conf = self.get_config('''
695
 
foo=start,{bar}
696
 
bar=middle,{baz}
697
 
baz=end
698
 
list={foo}
699
 
''')
700
 
        self.assertEquals(['start', 'middle', 'end'],
701
 
                           conf.get_user_option('list', expand=True))
702
 
 
703
 
    def test_pathological_hidden_list(self):
704
 
        conf = self.get_config('''
705
 
foo=bin
706
 
bar=go
707
 
start={foo
708
 
middle=},{
709
 
end=bar}
710
 
hidden={start}{middle}{end}
711
 
''')
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))
716
 
 
717
 
class TestLocationConfigOptionExpansion(tests.TestCaseInTempDir):
718
 
 
719
 
    def get_config(self, location, string=None):
720
 
        if string is None:
721
 
            string = ''
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)
725
 
        return c
726
 
 
727
 
    def test_dont_cross_unrelated_section(self):
728
 
        c = self.get_config('/another/branch/path','''
729
 
[/one/branch/path]
730
 
foo = hello
731
 
bar = {foo}/2
732
 
 
733
 
[/another/branch/path]
734
 
bar = {foo}/2
735
 
''')
736
 
        self.assertRaises(errors.ExpandingUnknownOption,
737
 
                          c.get_user_option, 'bar', expand=True)
738
 
 
739
 
    def test_cross_related_sections(self):
740
 
        c = self.get_config('/project/branch/path','''
741
 
[/project]
742
 
foo = qu
743
 
 
744
 
[/project/branch/path]
745
 
bar = {foo}ux
746
 
''')
747
 
        self.assertEquals('quux', c.get_user_option('bar', expand=True))
748
 
 
749
 
 
750
 
class TestIniBaseConfigOnDisk(tests.TestCaseInTempDir):
751
 
 
752
 
    def test_cannot_reload_without_name(self):
753
 
        conf = config.IniBasedConfig.from_string(sample_config_text)
754
 
        self.assertRaises(AssertionError, conf.reload)
755
 
 
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
766
 
        c1.reload()
767
 
        self.assertEqual('emacs', c1.get_user_option('editor'))
768
 
 
769
 
 
770
 
class TestLockableConfig(tests.TestCaseInTempDir):
771
 
 
772
 
    scenarios = lockable_config_scenarios()
773
 
 
774
 
    # Set by load_tests
775
 
    config_class = None
776
 
    config_args = None
777
 
    config_section = None
778
 
 
779
 
    def setUp(self):
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)
783
 
 
784
 
    def get_existing_config(self):
785
 
        return self.config_class(*self.config_args)
786
 
 
787
 
    def create_config(self, content):
788
 
        kwargs = dict(save=True)
789
 
        c = self.config_class.from_string(content, *self.config_args, **kwargs)
790
 
        return c
791
 
 
792
 
    def test_simple_read_access(self):
793
 
        self.assertEquals('1', self.config.get_user_option('one'))
794
 
 
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'))
798
 
 
799
 
    def test_listen_to_the_last_speaker(self):
800
 
        c1 = self.config
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'))
808
 
 
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.
812
 
        c1 = self.config
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
818
 
        # occur
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'))
822
 
 
823
 
    def test_writes_are_serialized(self):
824
 
        c1 = self.config
825
 
        c2 = self.get_existing_config()
826
 
 
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():
833
 
            before_writing.set()
834
 
            c1_orig()
835
 
            # The lock is held we wait for the main thread to decide when to
836
 
            # continue
837
 
            after_writing.wait()
838
 
        c1._write_config_file = c1_write_config_file
839
 
        def c1_set_option():
840
 
            c1.set_user_option('one', 'c1')
841
 
            writing_done.set()
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)
847
 
        t1.start()
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
854
 
        after_writing.set()
855
 
        writing_done.wait()
856
 
        c2.set_user_option('one', 'c2')
857
 
        self.assertEquals('c2', c2.get_user_option('one'))
858
 
 
859
 
    def test_read_while_writing(self):
860
 
       c1 = self.config
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():
867
 
           ready_to_write.set()
868
 
           # The lock is held we wait for the main thread to decide when to
869
 
           # continue
870
 
           do_writing.wait()
871
 
           c1_orig()
872
 
           writing_done.set()
873
 
       c1._write_config_file = c1_write_config_file
874
 
       def c1_set_option():
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)
881
 
       t1.start()
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
890
 
       do_writing.set()
891
 
       writing_done.wait()
892
 
       # Now we get the updated value
893
 
       c3 = self.get_existing_config()
894
 
       self.assertEquals('c1', c3.get_user_option('one'))
 
392
        my_config = config.IniBasedConfig(None)
 
393
        parser = my_config._get_parser(file=config_file)
 
394
        self.failUnless(my_config._get_parser() is parser)
895
395
 
896
396
 
897
397
class TestGetUserOptionAs(TestIniConfig):
962
462
            parser = my_config._get_parser()
963
463
        finally:
964
464
            config.ConfigObj = oldparserclass
965
 
        self.assertIsInstance(parser, InstrumentedConfigObj)
 
465
        self.failUnless(isinstance(parser, InstrumentedConfigObj))
966
466
        self.assertEqual(parser._calls, [('__init__', config.config_filename(),
967
467
                                          'utf-8')])
968
468
 
979
479
        my_config = config.BranchConfig(branch)
980
480
        location_config = my_config._get_location_config()
981
481
        self.assertEqual(branch.base, location_config.location)
982
 
        self.assertIs(location_config, my_config._get_location_config())
 
482
        self.failUnless(location_config is my_config._get_location_config())
983
483
 
984
484
    def test_get_config(self):
985
485
        """The Branch.get_config method works properly"""
1005
505
        branch = self.make_branch('branch')
1006
506
        self.assertEqual('branch', branch.nick)
1007
507
 
 
508
        locations = config.locations_config_filename()
 
509
        config.ensure_config_dir_exists()
1008
510
        local_url = urlutils.local_path_to_url('branch')
1009
 
        conf = config.LocationConfig.from_string(
1010
 
            '[%s]\nnickname = foobar' % (local_url,),
1011
 
            local_url, save=True)
 
511
        open(locations, 'wb').write('[%s]\nnickname = foobar'
 
512
                                    % (local_url,))
1012
513
        self.assertEqual('foobar', branch.nick)
1013
514
 
1014
515
    def test_config_local_path(self):
1016
517
        branch = self.make_branch('branch')
1017
518
        self.assertEqual('branch', branch.nick)
1018
519
 
1019
 
        local_path = osutils.getcwd().encode('utf8')
1020
 
        conf = config.LocationConfig.from_string(
1021
 
            '[%s/branch]\nnickname = barry' % (local_path,),
1022
 
            'branch',  save=True)
 
520
        locations = config.locations_config_filename()
 
521
        config.ensure_config_dir_exists()
 
522
        open(locations, 'wb').write('[%s/branch]\nnickname = barry'
 
523
                                    % (osutils.getcwd().encode('utf8'),))
1023
524
        self.assertEqual('barry', branch.nick)
1024
525
 
1025
526
    def test_config_creates_local(self):
1026
527
        """Creating a new entry in config uses a local path."""
1027
528
        branch = self.make_branch('branch', format='knit')
1028
529
        branch.set_push_location('http://foobar')
 
530
        locations = config.locations_config_filename()
1029
531
        local_path = osutils.getcwd().encode('utf8')
1030
532
        # Surprisingly ConfigObj doesn't create a trailing newline
1031
 
        self.check_file_contents(config.locations_config_filename(),
 
533
        self.check_file_contents(locations,
1032
534
                                 '[%s/branch]\n'
1033
535
                                 'push_location = http://foobar\n'
1034
536
                                 'push_location:policy = norecurse\n'
1039
541
        self.assertEqual('!repo', b.get_config().get_nickname())
1040
542
 
1041
543
    def test_warn_if_masked(self):
 
544
        _warning = trace.warning
1042
545
        warnings = []
1043
546
        def warning(*args):
1044
547
            warnings.append(args[0] % args[1:])
1045
 
        self.overrideAttr(trace, 'warning', warning)
1046
548
 
1047
549
        def set_option(store, warn_masked=True):
1048
550
            warnings[:] = []
1054
556
            else:
1055
557
                self.assertEqual(1, len(warnings))
1056
558
                self.assertEqual(warning, warnings[0])
1057
 
        branch = self.make_branch('.')
1058
 
        conf = branch.get_config()
1059
 
        set_option(config.STORE_GLOBAL)
1060
 
        assertWarning(None)
1061
 
        set_option(config.STORE_BRANCH)
1062
 
        assertWarning(None)
1063
 
        set_option(config.STORE_GLOBAL)
1064
 
        assertWarning('Value "4" is masked by "3" from branch.conf')
1065
 
        set_option(config.STORE_GLOBAL, warn_masked=False)
1066
 
        assertWarning(None)
1067
 
        set_option(config.STORE_LOCATION)
1068
 
        assertWarning(None)
1069
 
        set_option(config.STORE_BRANCH)
1070
 
        assertWarning('Value "3" is masked by "0" from locations.conf')
1071
 
        set_option(config.STORE_BRANCH, warn_masked=False)
1072
 
        assertWarning(None)
1073
 
 
1074
 
 
1075
 
class TestGlobalConfigItems(tests.TestCaseInTempDir):
 
559
        trace.warning = warning
 
560
        try:
 
561
            branch = self.make_branch('.')
 
562
            conf = branch.get_config()
 
563
            set_option(config.STORE_GLOBAL)
 
564
            assertWarning(None)
 
565
            set_option(config.STORE_BRANCH)
 
566
            assertWarning(None)
 
567
            set_option(config.STORE_GLOBAL)
 
568
            assertWarning('Value "4" is masked by "3" from branch.conf')
 
569
            set_option(config.STORE_GLOBAL, warn_masked=False)
 
570
            assertWarning(None)
 
571
            set_option(config.STORE_LOCATION)
 
572
            assertWarning(None)
 
573
            set_option(config.STORE_BRANCH)
 
574
            assertWarning('Value "3" is masked by "0" from locations.conf')
 
575
            set_option(config.STORE_BRANCH, warn_masked=False)
 
576
            assertWarning(None)
 
577
        finally:
 
578
            trace.warning = _warning
 
579
 
 
580
 
 
581
class TestGlobalConfigItems(tests.TestCase):
1076
582
 
1077
583
    def test_user_id(self):
1078
 
        my_config = config.GlobalConfig.from_string(sample_config_text)
 
584
        config_file = StringIO(sample_config_text.encode('utf-8'))
 
585
        my_config = config.GlobalConfig()
 
586
        my_config._parser = my_config._get_parser(file=config_file)
1079
587
        self.assertEqual(u"Erik B\u00e5gfors <erik@bagfors.nu>",
1080
588
                         my_config._get_user_id())
1081
589
 
1082
590
    def test_absent_user_id(self):
 
591
        config_file = StringIO("")
1083
592
        my_config = config.GlobalConfig()
 
593
        my_config._parser = my_config._get_parser(file=config_file)
1084
594
        self.assertEqual(None, my_config._get_user_id())
1085
595
 
1086
596
    def test_configured_editor(self):
1087
 
        my_config = config.GlobalConfig.from_string(sample_config_text)
 
597
        config_file = StringIO(sample_config_text.encode('utf-8'))
 
598
        my_config = config.GlobalConfig()
 
599
        my_config._parser = my_config._get_parser(file=config_file)
1088
600
        self.assertEqual("vim", my_config.get_editor())
1089
601
 
1090
602
    def test_signatures_always(self):
1091
 
        my_config = config.GlobalConfig.from_string(sample_always_signatures)
 
603
        config_file = StringIO(sample_always_signatures)
 
604
        my_config = config.GlobalConfig()
 
605
        my_config._parser = my_config._get_parser(file=config_file)
1092
606
        self.assertEqual(config.CHECK_NEVER,
1093
607
                         my_config.signature_checking())
1094
608
        self.assertEqual(config.SIGN_ALWAYS,
1096
610
        self.assertEqual(True, my_config.signature_needed())
1097
611
 
1098
612
    def test_signatures_if_possible(self):
1099
 
        my_config = config.GlobalConfig.from_string(sample_maybe_signatures)
 
613
        config_file = StringIO(sample_maybe_signatures)
 
614
        my_config = config.GlobalConfig()
 
615
        my_config._parser = my_config._get_parser(file=config_file)
1100
616
        self.assertEqual(config.CHECK_NEVER,
1101
617
                         my_config.signature_checking())
1102
618
        self.assertEqual(config.SIGN_WHEN_REQUIRED,
1104
620
        self.assertEqual(False, my_config.signature_needed())
1105
621
 
1106
622
    def test_signatures_ignore(self):
1107
 
        my_config = config.GlobalConfig.from_string(sample_ignore_signatures)
 
623
        config_file = StringIO(sample_ignore_signatures)
 
624
        my_config = config.GlobalConfig()
 
625
        my_config._parser = my_config._get_parser(file=config_file)
1108
626
        self.assertEqual(config.CHECK_ALWAYS,
1109
627
                         my_config.signature_checking())
1110
628
        self.assertEqual(config.SIGN_NEVER,
1112
630
        self.assertEqual(False, my_config.signature_needed())
1113
631
 
1114
632
    def _get_sample_config(self):
1115
 
        my_config = config.GlobalConfig.from_string(sample_config_text)
 
633
        config_file = StringIO(sample_config_text.encode('utf-8'))
 
634
        my_config = config.GlobalConfig()
 
635
        my_config._parser = my_config._get_parser(file=config_file)
1116
636
        return my_config
1117
637
 
1118
638
    def test_gpg_signing_command(self):
1121
641
        self.assertEqual(False, my_config.signature_needed())
1122
642
 
1123
643
    def _get_empty_config(self):
 
644
        config_file = StringIO("")
1124
645
        my_config = config.GlobalConfig()
 
646
        my_config._parser = my_config._get_parser(file=config_file)
1125
647
        return my_config
1126
648
 
1127
649
    def test_gpg_signing_command_unset(self):
1177
699
        change_editor = my_config.get_change_editor('old', 'new')
1178
700
        self.assertIs(None, change_editor)
1179
701
 
1180
 
    def test_get_merge_tools(self):
1181
 
        conf = self._get_sample_config()
1182
 
        tools = conf.get_merge_tools()
1183
 
        self.log(repr(tools))
1184
 
        self.assertEqual(
1185
 
            {u'funkytool' : u'funkytool "arg with spaces" {this_temp}',
1186
 
            u'sometool' : u'sometool {base} {this} {other} -o {result}'},
1187
 
            tools)
1188
 
 
1189
 
    def test_get_merge_tools_empty(self):
1190
 
        conf = self._get_empty_config()
1191
 
        tools = conf.get_merge_tools()
1192
 
        self.assertEqual({}, tools)
1193
 
 
1194
 
    def test_find_merge_tool(self):
1195
 
        conf = self._get_sample_config()
1196
 
        cmdline = conf.find_merge_tool('sometool')
1197
 
        self.assertEqual('sometool {base} {this} {other} -o {result}', cmdline)
1198
 
 
1199
 
    def test_find_merge_tool_not_found(self):
1200
 
        conf = self._get_sample_config()
1201
 
        cmdline = conf.find_merge_tool('DOES NOT EXIST')
1202
 
        self.assertIs(cmdline, None)
1203
 
 
1204
 
    def test_find_merge_tool_known(self):
1205
 
        conf = self._get_empty_config()
1206
 
        cmdline = conf.find_merge_tool('kdiff3')
1207
 
        self.assertEquals('kdiff3 {base} {this} {other} -o {result}', cmdline)
1208
 
 
1209
 
    def test_find_merge_tool_override_known(self):
1210
 
        conf = self._get_empty_config()
1211
 
        conf.set_user_option('bzr.mergetool.kdiff3', 'kdiff3 blah')
1212
 
        cmdline = conf.find_merge_tool('kdiff3')
1213
 
        self.assertEqual('kdiff3 blah', cmdline)
1214
 
 
1215
702
 
1216
703
class TestGlobalConfigSavingOptions(tests.TestCaseInTempDir):
1217
704
 
1235
722
        self.assertIs(None, new_config.get_alias('commit'))
1236
723
 
1237
724
 
1238
 
class TestLocationConfig(tests.TestCaseInTempDir, TestOptionsMixin):
 
725
class TestLocationConfig(tests.TestCaseInTempDir):
1239
726
 
1240
727
    def test_constructs(self):
1241
728
        my_config = config.LocationConfig('http://example.com')
1253
740
            parser = my_config._get_parser()
1254
741
        finally:
1255
742
            config.ConfigObj = oldparserclass
1256
 
        self.assertIsInstance(parser, InstrumentedConfigObj)
 
743
        self.failUnless(isinstance(parser, InstrumentedConfigObj))
1257
744
        self.assertEqual(parser._calls,
1258
745
                         [('__init__', config.locations_config_filename(),
1259
746
                           'utf-8')])
 
747
        config.ensure_config_dir_exists()
 
748
        #os.mkdir(config.config_dir())
 
749
        f = file(config.branches_config_filename(), 'wb')
 
750
        f.write('')
 
751
        f.close()
 
752
        oldparserclass = config.ConfigObj
 
753
        config.ConfigObj = InstrumentedConfigObj
 
754
        try:
 
755
            my_config = config.LocationConfig('http://www.example.com')
 
756
            parser = my_config._get_parser()
 
757
        finally:
 
758
            config.ConfigObj = oldparserclass
1260
759
 
1261
760
    def test_get_global_config(self):
1262
761
        my_config = config.BranchConfig(FakeBranch('http://example.com'))
1263
762
        global_config = my_config._get_global_config()
1264
 
        self.assertIsInstance(global_config, config.GlobalConfig)
1265
 
        self.assertIs(global_config, my_config._get_global_config())
1266
 
 
1267
 
    def assertLocationMatching(self, expected):
1268
 
        self.assertEqual(expected,
1269
 
                         list(self.my_location_config._get_matching_sections()))
 
763
        self.failUnless(isinstance(global_config, config.GlobalConfig))
 
764
        self.failUnless(global_config is my_config._get_global_config())
1270
765
 
1271
766
    def test__get_matching_sections_no_match(self):
1272
767
        self.get_branch_config('/')
1273
 
        self.assertLocationMatching([])
 
768
        self.assertEqual([], self.my_location_config._get_matching_sections())
1274
769
 
1275
770
    def test__get_matching_sections_exact(self):
1276
771
        self.get_branch_config('http://www.example.com')
1277
 
        self.assertLocationMatching([('http://www.example.com', '')])
 
772
        self.assertEqual([('http://www.example.com', '')],
 
773
                         self.my_location_config._get_matching_sections())
1278
774
 
1279
775
    def test__get_matching_sections_suffix_does_not(self):
1280
776
        self.get_branch_config('http://www.example.com-com')
1281
 
        self.assertLocationMatching([])
 
777
        self.assertEqual([], self.my_location_config._get_matching_sections())
1282
778
 
1283
779
    def test__get_matching_sections_subdir_recursive(self):
1284
780
        self.get_branch_config('http://www.example.com/com')
1285
 
        self.assertLocationMatching([('http://www.example.com', 'com')])
 
781
        self.assertEqual([('http://www.example.com', 'com')],
 
782
                         self.my_location_config._get_matching_sections())
1286
783
 
1287
784
    def test__get_matching_sections_ignoreparent(self):
1288
785
        self.get_branch_config('http://www.example.com/ignoreparent')
1289
 
        self.assertLocationMatching([('http://www.example.com/ignoreparent',
1290
 
                                      '')])
 
786
        self.assertEqual([('http://www.example.com/ignoreparent', '')],
 
787
                         self.my_location_config._get_matching_sections())
1291
788
 
1292
789
    def test__get_matching_sections_ignoreparent_subdir(self):
1293
790
        self.get_branch_config(
1294
791
            'http://www.example.com/ignoreparent/childbranch')
1295
 
        self.assertLocationMatching([('http://www.example.com/ignoreparent',
1296
 
                                      'childbranch')])
 
792
        self.assertEqual([('http://www.example.com/ignoreparent',
 
793
                           'childbranch')],
 
794
                         self.my_location_config._get_matching_sections())
1297
795
 
1298
796
    def test__get_matching_sections_subdir_trailing_slash(self):
1299
797
        self.get_branch_config('/b')
1300
 
        self.assertLocationMatching([('/b/', '')])
 
798
        self.assertEqual([('/b/', '')],
 
799
                         self.my_location_config._get_matching_sections())
1301
800
 
1302
801
    def test__get_matching_sections_subdir_child(self):
1303
802
        self.get_branch_config('/a/foo')
1304
 
        self.assertLocationMatching([('/a/*', ''), ('/a/', 'foo')])
 
803
        self.assertEqual([('/a/*', ''), ('/a/', 'foo')],
 
804
                         self.my_location_config._get_matching_sections())
1305
805
 
1306
806
    def test__get_matching_sections_subdir_child_child(self):
1307
807
        self.get_branch_config('/a/foo/bar')
1308
 
        self.assertLocationMatching([('/a/*', 'bar'), ('/a/', 'foo/bar')])
 
808
        self.assertEqual([('/a/*', 'bar'), ('/a/', 'foo/bar')],
 
809
                         self.my_location_config._get_matching_sections())
1309
810
 
1310
811
    def test__get_matching_sections_trailing_slash_with_children(self):
1311
812
        self.get_branch_config('/a/')
1312
 
        self.assertLocationMatching([('/a/', '')])
 
813
        self.assertEqual([('/a/', '')],
 
814
                         self.my_location_config._get_matching_sections())
1313
815
 
1314
816
    def test__get_matching_sections_explicit_over_glob(self):
1315
817
        # XXX: 2006-09-08 jamesh
1317
819
        # was a config section for '/a/?', it would get precedence
1318
820
        # over '/a/c'.
1319
821
        self.get_branch_config('/a/c')
1320
 
        self.assertLocationMatching([('/a/c', ''), ('/a/*', ''), ('/a/', 'c')])
 
822
        self.assertEqual([('/a/c', ''), ('/a/*', ''), ('/a/', 'c')],
 
823
                         self.my_location_config._get_matching_sections())
1321
824
 
1322
825
    def test__get_option_policy_normal(self):
1323
826
        self.get_branch_config('http://www.example.com')
1345
848
            'http://www.example.com', 'appendpath_option'),
1346
849
            config.POLICY_APPENDPATH)
1347
850
 
1348
 
    def test__get_options_with_policy(self):
1349
 
        self.get_branch_config('/dir/subdir',
1350
 
                               location_config="""\
1351
 
[/dir]
1352
 
other_url = /other-dir
1353
 
other_url:policy = appendpath
1354
 
[/dir/subdir]
1355
 
other_url = /other-subdir
1356
 
""")
1357
 
        self.assertOptions(
1358
 
            [(u'other_url', u'/other-subdir', u'/dir/subdir', 'locations'),
1359
 
             (u'other_url', u'/other-dir', u'/dir', 'locations'),
1360
 
             (u'other_url:policy', u'appendpath', u'/dir', 'locations')],
1361
 
            self.my_location_config)
1362
 
 
1363
851
    def test_location_without_username(self):
1364
852
        self.get_branch_config('http://www.example.com/ignoreparent')
1365
853
        self.assertEqual(u'Erik B\u00e5gfors <erik@bagfors.nu>',
1501
989
        self.assertEqual('bzrlib.tests.test_config.post_commit',
1502
990
                         self.my_config.post_commit())
1503
991
 
1504
 
    def get_branch_config(self, location, global_config=None,
1505
 
                          location_config=None):
1506
 
        my_branch = FakeBranch(location)
 
992
    def get_branch_config(self, location, global_config=None):
1507
993
        if global_config is None:
1508
 
            global_config = sample_config_text
1509
 
        if location_config is None:
1510
 
            location_config = sample_branches_text
1511
 
 
1512
 
        my_global_config = config.GlobalConfig.from_string(global_config,
1513
 
                                                           save=True)
1514
 
        my_location_config = config.LocationConfig.from_string(
1515
 
            location_config, my_branch.base, save=True)
1516
 
        my_config = config.BranchConfig(my_branch)
1517
 
        self.my_config = my_config
1518
 
        self.my_location_config = my_config._get_location_config()
 
994
            global_file = StringIO(sample_config_text.encode('utf-8'))
 
995
        else:
 
996
            global_file = StringIO(global_config.encode('utf-8'))
 
997
        branches_file = StringIO(sample_branches_text.encode('utf-8'))
 
998
        self.my_config = config.BranchConfig(FakeBranch(location))
 
999
        # Force location config to use specified file
 
1000
        self.my_location_config = self.my_config._get_location_config()
 
1001
        self.my_location_config._get_parser(branches_file)
 
1002
        # Force global config to use specified file
 
1003
        self.my_config._get_global_config()._get_parser(global_file)
1519
1004
 
1520
1005
    def test_set_user_setting_sets_and_saves(self):
1521
1006
        self.get_branch_config('/a/c')
1522
1007
        record = InstrumentedConfigObj("foo")
1523
1008
        self.my_location_config._parser = record
1524
1009
 
1525
 
        self.callDeprecated(['The recurse option is deprecated as of '
1526
 
                             '0.14.  The section "/a/c" has been '
1527
 
                             'converted to use policies.'],
1528
 
                            self.my_config.set_user_option,
1529
 
                            'foo', 'bar', store=config.STORE_LOCATION)
1530
 
        self.assertEqual([('reload',),
1531
 
                          ('__contains__', '/a/c'),
 
1010
        real_mkdir = os.mkdir
 
1011
        self.created = False
 
1012
        def checked_mkdir(path, mode=0777):
 
1013
            self.log('making directory: %s', path)
 
1014
            real_mkdir(path, mode)
 
1015
            self.created = True
 
1016
 
 
1017
        os.mkdir = checked_mkdir
 
1018
        try:
 
1019
            self.callDeprecated(['The recurse option is deprecated as of '
 
1020
                                 '0.14.  The section "/a/c" has been '
 
1021
                                 'converted to use policies.'],
 
1022
                                self.my_config.set_user_option,
 
1023
                                'foo', 'bar', store=config.STORE_LOCATION)
 
1024
        finally:
 
1025
            os.mkdir = real_mkdir
 
1026
 
 
1027
        self.failUnless(self.created, 'Failed to create ~/.bazaar')
 
1028
        self.assertEqual([('__contains__', '/a/c'),
1532
1029
                          ('__contains__', '/a/c/'),
1533
1030
                          ('__setitem__', '/a/c', {}),
1534
1031
                          ('__getitem__', '/a/c'),
1563
1060
        self.assertEqual('bzr', my_config.get_bzr_remote_path())
1564
1061
        my_config.set_user_option('bzr_remote_path', '/path-bzr')
1565
1062
        self.assertEqual('/path-bzr', my_config.get_bzr_remote_path())
1566
 
        self.overrideEnv('BZR_REMOTE_PATH', '/environ-bzr')
 
1063
        os.environ['BZR_REMOTE_PATH'] = '/environ-bzr'
1567
1064
        self.assertEqual('/environ-bzr', my_config.get_bzr_remote_path())
1568
1065
 
1569
1066
 
1577
1074
option = exact
1578
1075
"""
1579
1076
 
 
1077
 
1580
1078
class TestBranchConfigItems(tests.TestCaseInTempDir):
1581
1079
 
1582
1080
    def get_branch_config(self, global_config=None, location=None,
1583
1081
                          location_config=None, branch_data_config=None):
1584
 
        my_branch = FakeBranch(location)
 
1082
        my_config = config.BranchConfig(FakeBranch(location))
1585
1083
        if global_config is not None:
1586
 
            my_global_config = config.GlobalConfig.from_string(global_config,
1587
 
                                                               save=True)
 
1084
            global_file = StringIO(global_config.encode('utf-8'))
 
1085
            my_config._get_global_config()._get_parser(global_file)
 
1086
        self.my_location_config = my_config._get_location_config()
1588
1087
        if location_config is not None:
1589
 
            my_location_config = config.LocationConfig.from_string(
1590
 
                location_config, my_branch.base, save=True)
1591
 
        my_config = config.BranchConfig(my_branch)
 
1088
            location_file = StringIO(location_config.encode('utf-8'))
 
1089
            self.my_location_config._get_parser(location_file)
1592
1090
        if branch_data_config is not None:
1593
1091
            my_config.branch.control_files.files['branch.conf'] = \
1594
1092
                branch_data_config
1608
1106
                         my_config.username())
1609
1107
 
1610
1108
    def test_not_set_in_branch(self):
1611
 
        my_config = self.get_branch_config(global_config=sample_config_text)
 
1109
        my_config = self.get_branch_config(sample_config_text)
1612
1110
        self.assertEqual(u"Erik B\u00e5gfors <erik@bagfors.nu>",
1613
1111
                         my_config._get_user_id())
1614
1112
        my_config.branch.control_files.files['email'] = "John"
1615
1113
        self.assertEqual("John", my_config._get_user_id())
1616
1114
 
1617
1115
    def test_BZR_EMAIL_OVERRIDES(self):
1618
 
        self.overrideEnv('BZR_EMAIL', "Robert Collins <robertc@example.org>")
 
1116
        os.environ['BZR_EMAIL'] = "Robert Collins <robertc@example.org>"
1619
1117
        branch = FakeBranch()
1620
1118
        my_config = config.BranchConfig(branch)
1621
1119
        self.assertEqual("Robert Collins <robertc@example.org>",
1638
1136
 
1639
1137
    def test_gpg_signing_command(self):
1640
1138
        my_config = self.get_branch_config(
1641
 
            global_config=sample_config_text,
1642
1139
            # branch data cannot set gpg_signing_command
1643
1140
            branch_data_config="gpg_signing_command=pgp")
 
1141
        config_file = StringIO(sample_config_text.encode('utf-8'))
 
1142
        my_config._get_global_config()._get_parser(config_file)
1644
1143
        self.assertEqual('gnome-gpg', my_config.gpg_signing_command())
1645
1144
 
1646
1145
    def test_get_user_option_global(self):
1647
 
        my_config = self.get_branch_config(global_config=sample_config_text)
 
1146
        branch = FakeBranch()
 
1147
        my_config = config.BranchConfig(branch)
 
1148
        config_file = StringIO(sample_config_text.encode('utf-8'))
 
1149
        (my_config._get_global_config()._get_parser(config_file))
1648
1150
        self.assertEqual('something',
1649
1151
                         my_config.get_user_option('user_global_option'))
1650
1152
 
1651
1153
    def test_post_commit_default(self):
1652
 
        my_config = self.get_branch_config(global_config=sample_config_text,
1653
 
                                      location='/a/c',
1654
 
                                      location_config=sample_branches_text)
 
1154
        branch = FakeBranch()
 
1155
        my_config = self.get_branch_config(sample_config_text, '/a/c',
 
1156
                                           sample_branches_text)
1655
1157
        self.assertEqual(my_config.branch.base, '/a/c')
1656
1158
        self.assertEqual('bzrlib.tests.test_config.post_commit',
1657
1159
                         my_config.post_commit())
1658
1160
        my_config.set_user_option('post_commit', 'rmtree_root')
1659
 
        # post-commit is ignored when present in branch data
 
1161
        # post-commit is ignored when bresent in branch data
1660
1162
        self.assertEqual('bzrlib.tests.test_config.post_commit',
1661
1163
                         my_config.post_commit())
1662
1164
        my_config.set_user_option('post_commit', 'rmtree_root',
1664
1166
        self.assertEqual('rmtree_root', my_config.post_commit())
1665
1167
 
1666
1168
    def test_config_precedence(self):
1667
 
        # FIXME: eager test, luckily no persitent config file makes it fail
1668
 
        # -- vila 20100716
1669
1169
        my_config = self.get_branch_config(global_config=precedence_global)
1670
1170
        self.assertEqual(my_config.get_user_option('option'), 'global')
1671
1171
        my_config = self.get_branch_config(global_config=precedence_global,
1672
 
                                           branch_data_config=precedence_branch)
 
1172
                                      branch_data_config=precedence_branch)
1673
1173
        self.assertEqual(my_config.get_user_option('option'), 'branch')
1674
 
        my_config = self.get_branch_config(
1675
 
            global_config=precedence_global,
1676
 
            branch_data_config=precedence_branch,
1677
 
            location_config=precedence_location)
 
1174
        my_config = self.get_branch_config(global_config=precedence_global,
 
1175
                                      branch_data_config=precedence_branch,
 
1176
                                      location_config=precedence_location)
1678
1177
        self.assertEqual(my_config.get_user_option('option'), 'recurse')
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')
 
1178
        my_config = self.get_branch_config(global_config=precedence_global,
 
1179
                                      branch_data_config=precedence_branch,
 
1180
                                      location_config=precedence_location,
 
1181
                                      location='http://example.com/specific')
1684
1182
        self.assertEqual(my_config.get_user_option('option'), 'exact')
1685
1183
 
1686
1184
    def test_get_mail_client(self):
1814
1312
        self.assertIs(None, bzrdir_config.get_default_stack_on())
1815
1313
 
1816
1314
 
1817
 
class TestConfigGetOptions(tests.TestCaseWithTransport, TestOptionsMixin):
1818
 
 
1819
 
    def setUp(self):
1820
 
        super(TestConfigGetOptions, self).setUp()
1821
 
        create_configs(self)
1822
 
 
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)
1827
 
 
1828
 
    def test_option_in_bazaar(self):
1829
 
        self.bazaar_config.set_user_option('file', 'bazaar')
1830
 
        self.assertOptions([('file', 'bazaar', 'DEFAULT', 'bazaar')],
1831
 
                           self.bazaar_config)
1832
 
 
1833
 
    def test_option_in_locations(self):
1834
 
        self.locations_config.set_user_option('file', 'locations')
1835
 
        self.assertOptions(
1836
 
            [('file', 'locations', self.tree.basedir, 'locations')],
1837
 
            self.locations_config)
1838
 
 
1839
 
    def test_option_in_branch(self):
1840
 
        self.branch_config.set_user_option('file', 'branch')
1841
 
        self.assertOptions([('file', 'branch', 'DEFAULT', 'branch')],
1842
 
                           self.branch_config)
1843
 
 
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'),],
1849
 
                           self.branch_config)
1850
 
 
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')
1855
 
        self.assertOptions(
1856
 
            [('file', 'locations', self.tree.basedir, 'locations'),
1857
 
             ('file', 'branch', 'DEFAULT', 'branch'),],
1858
 
            self.branch_config)
1859
 
 
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')
1864
 
        self.assertOptions(
1865
 
            [('file', 'locations', self.tree.basedir, 'locations'),
1866
 
             ('file', 'branch', 'DEFAULT', 'branch'),
1867
 
             ('file', 'bazaar', 'DEFAULT', 'bazaar'),],
1868
 
            self.branch_config)
1869
 
 
1870
 
 
1871
 
class TestConfigRemoveOption(tests.TestCaseWithTransport, TestOptionsMixin):
1872
 
 
1873
 
    def setUp(self):
1874
 
        super(TestConfigRemoveOption, self).setUp()
1875
 
        create_configs_with_file_option(self)
1876
 
 
1877
 
    def test_remove_in_locations(self):
1878
 
        self.locations_config.remove_user_option('file', self.tree.basedir)
1879
 
        self.assertOptions(
1880
 
            [('file', 'branch', 'DEFAULT', 'branch'),
1881
 
             ('file', 'bazaar', 'DEFAULT', 'bazaar'),],
1882
 
            self.branch_config)
1883
 
 
1884
 
    def test_remove_in_branch(self):
1885
 
        self.branch_config.remove_user_option('file')
1886
 
        self.assertOptions(
1887
 
            [('file', 'locations', self.tree.basedir, 'locations'),
1888
 
             ('file', 'bazaar', 'DEFAULT', 'bazaar'),],
1889
 
            self.branch_config)
1890
 
 
1891
 
    def test_remove_in_bazaar(self):
1892
 
        self.bazaar_config.remove_user_option('file')
1893
 
        self.assertOptions(
1894
 
            [('file', 'locations', self.tree.basedir, 'locations'),
1895
 
             ('file', 'branch', 'DEFAULT', 'branch'),],
1896
 
            self.branch_config)
1897
 
 
1898
 
 
1899
 
class TestConfigGetSections(tests.TestCaseWithTransport):
1900
 
 
1901
 
    def setUp(self):
1902
 
        super(TestConfigGetSections, self).setUp()
1903
 
        create_configs(self)
1904
 
 
1905
 
    def assertSectionNames(self, expected, conf, name=None):
1906
 
        """Check which sections are returned for a given config.
1907
 
 
1908
 
        If fallback configurations exist their sections can be included.
1909
 
 
1910
 
        :param expected: A list of section names.
1911
 
 
1912
 
        :param conf: The configuration that will be queried.
1913
 
 
1914
 
        :param name: An optional section name that will be passed to
1915
 
            get_sections().
1916
 
        """
1917
 
        sections = list(conf._get_sections(name))
1918
 
        self.assertLength(len(expected), sections)
1919
 
        self.assertEqual(expected, [name for name, _, _ in sections])
1920
 
 
1921
 
    def test_bazaar_default_section(self):
1922
 
        self.assertSectionNames(['DEFAULT'], self.bazaar_config)
1923
 
 
1924
 
    def test_locations_default_section(self):
1925
 
        # No sections are defined in an empty file
1926
 
        self.assertSectionNames([], self.locations_config)
1927
 
 
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)
1931
 
 
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'])
1942
 
        parser[parent] = {}
1943
 
        parser[parent]['file'] = 'parent'
1944
 
        parser[child] = {}
1945
 
        parser[child]['file'] = 'child'
1946
 
        self.assertSectionNames([self.tree.basedir, parent], loc_config)
1947
 
 
1948
 
    def test_branch_data_default_section(self):
1949
 
        self.assertSectionNames([None],
1950
 
                                self.branch_config._get_branch_data_config())
1951
 
 
1952
 
    def test_branch_default_sections(self):
1953
 
        # No sections are defined in an empty locations file
1954
 
        self.assertSectionNames([None, 'DEFAULT'],
1955
 
                                self.branch_config)
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'],
1960
 
                                self.branch_config)
1961
 
 
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')
1967
 
 
1968
 
 
1969
1315
class TestAuthenticationConfigFile(tests.TestCase):
1970
1316
    """Test the authentication.conf file matching"""
1971
1317
 
2466
1812
# test_user_prompted ?
2467
1813
class TestAuthenticationRing(tests.TestCaseWithTransport):
2468
1814
    pass
2469
 
 
2470
 
 
2471
 
class TestAutoUserId(tests.TestCase):
2472
 
    """Test inferring an automatic user name."""
2473
 
 
2474
 
    def test_auto_user_id(self):
2475
 
        """Automatic inference of user name.
2476
 
        
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.
2481
 
        """
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)
2488
 
        else:
2489
 
            self.assertEquals((None, None), (realname, address))
2490