~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_config.py

  • Committer: John Arbash Meinel
  • Date: 2005-11-30 15:43:57 UTC
  • mto: (1185.50.1 jam-integration)
  • mto: This revision was merged to the branch mainline in revision 1518.
  • Revision ID: john@arbash-meinel.com-20051130154357-614206b3a7b83cd0
Refactored bzrlib/ui.py into a module with the possibility for multiple ui forms.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2011 Canonical Ltd
 
1
# Copyright (C) 2005 by Canonical Ltd
 
2
#   Authors: Robert Collins <robert.collins@canonical.com>
2
3
#
3
4
# This program is free software; you can redistribute it and/or modify
4
5
# it under the terms of the GNU General Public License as published by
12
13
#
13
14
# You should have received a copy of the GNU General Public License
14
15
# along with this program; if not, write to the Free Software
15
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
16
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
17
 
17
18
"""Tests for finding and reading the bzr config file[s]."""
18
19
# import system imports here
 
20
from bzrlib.util.configobj.configobj import ConfigObj, ConfigObjError
19
21
from cStringIO import StringIO
20
22
import os
21
23
import sys
22
 
import threading
23
 
 
24
 
 
25
 
from testtools import matchers
26
24
 
27
25
#import bzrlib specific imports here
28
 
from bzrlib import (
29
 
    branch,
30
 
    bzrdir,
31
 
    config,
32
 
    diff,
33
 
    errors,
34
 
    osutils,
35
 
    mail_client,
36
 
    mergetools,
37
 
    ui,
38
 
    urlutils,
39
 
    tests,
40
 
    trace,
41
 
    transport,
42
 
    )
43
 
from bzrlib.tests import (
44
 
    features,
45
 
    TestSkipped,
46
 
    scenarios,
47
 
    )
48
 
from bzrlib.util.configobj import configobj
49
 
 
50
 
 
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
 
sample_long_alias="log -r-15..-1 --line"
67
 
sample_config_text = u"""
68
 
[DEFAULT]
69
 
email=Erik B\u00e5gfors <erik@bagfors.nu>
70
 
editor=vim
71
 
change_editor=vimdiff -of @new_path @old_path
72
 
gpg_signing_command=gnome-gpg
73
 
log_format=short
74
 
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
 
[ALIASES]
79
 
h=help
80
 
ll=""" + sample_long_alias + "\n"
81
 
 
82
 
 
83
 
sample_always_signatures = """
84
 
[DEFAULT]
85
 
check_signatures=ignore
86
 
create_signatures=always
87
 
"""
88
 
 
89
 
sample_ignore_signatures = """
90
 
[DEFAULT]
91
 
check_signatures=require
92
 
create_signatures=never
93
 
"""
94
 
 
95
 
sample_maybe_signatures = """
96
 
[DEFAULT]
97
 
check_signatures=ignore
98
 
create_signatures=when-required
99
 
"""
100
 
 
101
 
sample_branches_text = """
102
 
[http://www.example.com]
103
 
# Top level policy
104
 
email=Robert Collins <robertc@example.org>
105
 
normal_option = normal
106
 
appendpath_option = append
107
 
appendpath_option:policy = appendpath
108
 
norecurse_option = norecurse
109
 
norecurse_option:policy = norecurse
110
 
[http://www.example.com/ignoreparent]
111
 
# different project: ignore parent dir config
112
 
ignore_parents=true
113
 
[http://www.example.com/norecurse]
114
 
# configuration items that only apply to this dir
115
 
recurse=false
116
 
normal_option = norecurse
117
 
[http://www.example.com/dir]
118
 
appendpath_option = normal
119
 
[/b/]
120
 
check_signatures=require
121
 
# test trailing / matching with no children
122
 
[/a/]
123
 
check_signatures=check-available
124
 
gpg_signing_command=false
125
 
user_local_option=local
126
 
# test trailing / matching
127
 
[/a/*]
128
 
#subdirs will match but not the parent
129
 
[/a/c]
130
 
check_signatures=ignore
131
 
post_commit=bzrlib.tests.test_config.post_commit
132
 
#testing explicit beats globs
133
 
"""
134
 
 
135
 
 
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))
 
26
import bzrlib.config as config
 
27
import bzrlib.errors as errors
 
28
from bzrlib.tests import TestCase, TestCaseInTempDir
 
29
 
 
30
 
 
31
sample_config_text = ("[DEFAULT]\n"
 
32
                      "email=Robert Collins <robertc@example.com>\n"
 
33
                      "editor=vim\n"
 
34
                      "gpg_signing_command=gnome-gpg\n"
 
35
                      "user_global_option=something\n")
 
36
 
 
37
 
 
38
sample_always_signatures = ("[DEFAULT]\n"
 
39
                            "check_signatures=require\n")
 
40
 
 
41
 
 
42
sample_ignore_signatures = ("[DEFAULT]\n"
 
43
                            "check_signatures=ignore\n")
 
44
 
 
45
 
 
46
sample_maybe_signatures = ("[DEFAULT]\n"
 
47
                            "check_signatures=check-available\n")
 
48
 
 
49
 
 
50
sample_branches_text = ("[http://www.example.com]\n"
 
51
                        "# Top level policy\n"
 
52
                        "email=Robert Collins <robertc@example.org>\n"
 
53
                        "[http://www.example.com/useglobal]\n"
 
54
                        "# different project, forces global lookup\n"
 
55
                        "recurse=false\n"
 
56
                        "[/b/]\n"
 
57
                        "check_signatures=require\n"
 
58
                        "# test trailing / matching with no children\n"
 
59
                        "[/a/]\n"
 
60
                        "check_signatures=check-available\n"
 
61
                        "gpg_signing_command=false\n"
 
62
                        "user_local_option=local\n"
 
63
                        "# test trailing / matching\n"
 
64
                        "[/a/*]\n"
 
65
                        "#subdirs will match but not the parent\n"
 
66
                        "recurse=False\n"
 
67
                        "[/a/c]\n"
 
68
                        "check_signatures=ignore\n"
 
69
                        "post_commit=bzrlib.tests.test_config.post_commit\n"
 
70
                        "#testing explicit beats globs\n")
177
71
 
178
72
 
179
73
class InstrumentedConfigObj(object):
187
81
        self._calls.append(('__getitem__', key))
188
82
        return self
189
83
 
190
 
    def __init__(self, input, encoding=None):
191
 
        self._calls = [('__init__', input, encoding)]
 
84
    def __init__(self, input):
 
85
        self._calls = [('__init__', input)]
192
86
 
193
87
    def __setitem__(self, key, value):
194
88
        self._calls.append(('__setitem__', key, value))
195
89
 
196
 
    def __delitem__(self, key):
197
 
        self._calls.append(('__delitem__', key))
198
 
 
199
 
    def keys(self):
200
 
        self._calls.append(('keys',))
201
 
        return []
202
 
 
203
 
    def reload(self):
204
 
        self._calls.append(('reload',))
205
 
 
206
 
    def write(self, arg):
 
90
    def write(self):
207
91
        self._calls.append(('write',))
208
92
 
209
 
    def as_bool(self, value):
210
 
        self._calls.append(('as_bool', value))
211
 
        return False
212
 
 
213
 
    def get_value(self, section, name):
214
 
        self._calls.append(('get_value', section, name))
215
 
        return None
216
 
 
217
93
 
218
94
class FakeBranch(object):
219
95
 
220
 
    def __init__(self, base=None, user_id=None):
221
 
        if base is None:
222
 
            self.base = "http://example.com/branches/demo"
223
 
        else:
224
 
            self.base = base
225
 
        self._transport = self.control_files = \
226
 
            FakeControlFilesAndTransport(user_id=user_id)
227
 
 
228
 
    def _get_config(self):
229
 
        return config.TransportConfig(self._transport, 'branch.conf')
230
 
 
231
 
    def lock_write(self):
232
 
        pass
233
 
 
234
 
    def unlock(self):
235
 
        pass
236
 
 
237
 
 
238
 
class FakeControlFilesAndTransport(object):
239
 
 
240
 
    def __init__(self, user_id=None):
241
 
        self.files = {}
242
 
        if user_id:
243
 
            self.files['email'] = user_id
244
 
        self._transport = self
245
 
 
246
 
    def get_utf8(self, filename):
247
 
        # from LockableFiles
248
 
        raise AssertionError("get_utf8 should no longer be used")
249
 
 
250
 
    def get(self, filename):
251
 
        # from Transport
252
 
        try:
253
 
            return StringIO(self.files[filename])
254
 
        except KeyError:
255
 
            raise errors.NoSuchFile(filename)
256
 
 
257
 
    def get_bytes(self, filename):
258
 
        # from Transport
259
 
        try:
260
 
            return self.files[filename]
261
 
        except KeyError:
262
 
            raise errors.NoSuchFile(filename)
263
 
 
264
 
    def put(self, filename, fileobj):
265
 
        self.files[filename] = fileobj.read()
266
 
 
267
 
    def put_file(self, filename, fileobj):
268
 
        return self.put(filename, fileobj)
 
96
    def __init__(self):
 
97
        self.base = "http://example.com/branches/demo"
 
98
        self.email = 'Robert Collins <robertc@example.net>\n'
 
99
 
 
100
    def controlfile(self, filename, mode):
 
101
        if filename != 'email':
 
102
            raise NotImplementedError
 
103
        if self.email is not None:
 
104
            return StringIO(self.email)
 
105
        raise errors.NoSuchFile
269
106
 
270
107
 
271
108
class InstrumentedConfig(config.Config):
272
109
    """An instrumented config that supplies stubs for template methods."""
273
 
 
 
110
    
274
111
    def __init__(self):
275
112
        super(InstrumentedConfig, self).__init__()
276
113
        self._calls = []
284
121
        self._calls.append('_get_signature_checking')
285
122
        return self._signatures
286
123
 
287
 
    def _get_change_editor(self):
288
 
        self._calls.append('_get_change_editor')
289
 
        return 'vimdiff -fo @new_path @old_path'
290
 
 
291
 
 
292
 
bool_config = """[DEFAULT]
293
 
active = true
294
 
inactive = false
295
 
[UPPERCASE]
296
 
active = True
297
 
nonactive = False
298
 
"""
299
 
 
300
 
 
301
 
class TestConfigObj(tests.TestCase):
302
 
 
303
 
    def test_get_bool(self):
304
 
        co = config.ConfigObj(StringIO(bool_config))
305
 
        self.assertIs(co.get_bool('DEFAULT', 'active'), True)
306
 
        self.assertIs(co.get_bool('DEFAULT', 'inactive'), False)
307
 
        self.assertIs(co.get_bool('UPPERCASE', 'active'), True)
308
 
        self.assertIs(co.get_bool('UPPERCASE', 'nonactive'), False)
309
 
 
310
 
    def test_hash_sign_in_value(self):
311
 
        """
312
 
        Before 4.5.0, ConfigObj did not quote # signs in values, so they'd be
313
 
        treated as comments when read in again. (#86838)
314
 
        """
315
 
        co = config.ConfigObj()
316
 
        co['test'] = 'foo#bar'
317
 
        outfile = StringIO()
318
 
        co.write(outfile=outfile)
319
 
        lines = outfile.getvalue().splitlines()
320
 
        self.assertEqual(lines, ['test = "foo#bar"'])
321
 
        co2 = config.ConfigObj(lines)
322
 
        self.assertEqual(co2['test'], 'foo#bar')
323
 
 
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
 
 
349
 
erroneous_config = """[section] # line 1
350
 
good=good # line 2
351
 
[section] # line 3
352
 
whocares=notme # line 4
353
 
"""
354
 
 
355
 
 
356
 
class TestConfigObjErrors(tests.TestCase):
357
 
 
358
 
    def test_duplicate_section_name_error_line(self):
359
 
        try:
360
 
            co = configobj.ConfigObj(StringIO(erroneous_config),
361
 
                                     raise_errors=True)
362
 
        except config.configobj.DuplicateError, e:
363
 
            self.assertEqual(3, e.line_number)
364
 
        else:
365
 
            self.fail('Error in config file not detected')
366
 
 
367
 
 
368
 
class TestConfig(tests.TestCase):
 
124
 
 
125
class TestConfig(TestCase):
369
126
 
370
127
    def test_constructs(self):
371
128
        config.Config()
372
 
 
 
129
 
373
130
    def test_no_default_editor(self):
374
131
        self.assertRaises(NotImplementedError, config.Config().get_editor)
375
132
 
386
143
 
387
144
    def test_signatures_default(self):
388
145
        my_config = config.Config()
389
 
        self.assertFalse(my_config.signature_needed())
390
146
        self.assertEqual(config.CHECK_IF_POSSIBLE,
391
147
                         my_config.signature_checking())
392
 
        self.assertEqual(config.SIGN_WHEN_REQUIRED,
393
 
                         my_config.signing_policy())
394
148
 
395
149
    def test_signatures_template_method(self):
396
150
        my_config = InstrumentedConfig()
416
170
        my_config = config.Config()
417
171
        self.assertEqual(None, my_config.post_commit())
418
172
 
419
 
    def test_log_format_default(self):
420
 
        my_config = config.Config()
421
 
        self.assertEqual('long', my_config.log_format())
422
 
 
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)
430
 
 
431
 
 
432
 
class TestConfigPath(tests.TestCase):
 
173
 
 
174
class TestConfigPath(TestCase):
433
175
 
434
176
    def setUp(self):
435
177
        super(TestConfigPath, self).setUp()
436
 
        self.overrideEnv('HOME', '/home/bogus')
437
 
        self.overrideEnv('XDG_CACHE_DIR', '')
438
 
        if sys.platform == 'win32':
439
 
            self.overrideEnv(
440
 
                'BZR_HOME', r'C:\Documents and Settings\bogus\Application Data')
441
 
            self.bzr_home = \
442
 
                'C:/Documents and Settings/bogus/Application Data/bazaar/2.0'
443
 
        else:
444
 
            self.bzr_home = '/home/bogus/.bazaar'
 
178
        self.old_home = os.environ.get('HOME', None)
 
179
        self.old_appdata = os.environ.get('APPDATA', None)
 
180
        os.environ['HOME'] = '/home/bogus'
 
181
        os.environ['APPDATA'] = \
 
182
            r'C:\Documents and Settings\bogus\Application Data'
445
183
 
 
184
    def tearDown(self):
 
185
        if self.old_home is None:
 
186
            del os.environ['HOME']
 
187
        else:
 
188
            os.environ['HOME'] = self.old_home
 
189
        if self.old_appdata is None:
 
190
            del os.environ['APPDATA']
 
191
        else:
 
192
            os.environ['APPDATA'] = self.old_appdata
 
193
        super(TestConfigPath, self).tearDown()
 
194
    
446
195
    def test_config_dir(self):
447
 
        self.assertEqual(config.config_dir(), self.bzr_home)
 
196
        if sys.platform == 'win32':
 
197
            self.assertEqual(config.config_dir(), 
 
198
                r'C:\Documents and Settings\bogus\Application Data\bazaar\2.0')
 
199
        else:
 
200
            self.assertEqual(config.config_dir(), '/home/bogus/.bazaar')
448
201
 
449
202
    def test_config_filename(self):
450
 
        self.assertEqual(config.config_filename(),
451
 
                         self.bzr_home + '/bazaar.conf')
452
 
 
453
 
    def test_locations_config_filename(self):
454
 
        self.assertEqual(config.locations_config_filename(),
455
 
                         self.bzr_home + '/locations.conf')
456
 
 
457
 
    def test_authentication_config_filename(self):
458
 
        self.assertEqual(config.authentication_config_filename(),
459
 
                         self.bzr_home + '/authentication.conf')
460
 
 
461
 
    def test_xdg_cache_dir(self):
462
 
        self.assertEqual(config.xdg_cache_dir(),
463
 
            '/home/bogus/.cache')
464
 
 
465
 
 
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):
495
 
 
496
 
    def make_config_parser(self, s):
497
 
        conf = config.IniBasedConfig.from_string(s)
498
 
        return conf, conf._get_parser()
499
 
 
500
 
 
501
 
class TestIniConfigBuilding(TestIniConfig):
 
203
        if sys.platform == 'win32':
 
204
            self.assertEqual(config.config_filename(), 
 
205
                r'C:\Documents and Settings\bogus\Application Data\bazaar\2.0\bazaar.conf')
 
206
        else:
 
207
            self.assertEqual(config.config_filename(),
 
208
                             '/home/bogus/.bazaar/bazaar.conf')
 
209
 
 
210
    def test_branches_config_filename(self):
 
211
        if sys.platform == 'win32':
 
212
            self.assertEqual(config.branches_config_filename(), 
 
213
                r'C:\Documents and Settings\bogus\Application Data\bazaar\2.0\branches.conf')
 
214
        else:
 
215
            self.assertEqual(config.branches_config_filename(),
 
216
                             '/home/bogus/.bazaar/branches.conf')
 
217
 
 
218
class TestIniConfig(TestCase):
502
219
 
503
220
    def test_contructs(self):
504
 
        my_config = config.IniBasedConfig()
 
221
        my_config = config.IniBasedConfig("nothing")
505
222
 
506
223
    def test_from_fp(self):
507
 
        my_config = config.IniBasedConfig.from_string(sample_config_text)
508
 
        self.assertIsInstance(my_config._get_parser(), configobj.ConfigObj)
 
224
        config_file = StringIO(sample_config_text)
 
225
        my_config = config.IniBasedConfig(None)
 
226
        self.failUnless(
 
227
            isinstance(my_config._get_parser(file=config_file),
 
228
                        ConfigObj))
509
229
 
510
230
    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
 
        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'))
895
 
 
896
 
 
897
 
class TestGetUserOptionAs(TestIniConfig):
898
 
 
899
 
    def test_get_user_option_as_bool(self):
900
 
        conf, parser = self.make_config_parser("""
901
 
a_true_bool = true
902
 
a_false_bool = 0
903
 
an_invalid_bool = maybe
904
 
a_list = hmm, who knows ? # This is interpreted as a list !
905
 
""")
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'))
909
 
        warnings = []
910
 
        def warning(*args):
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])
916
 
        warnings = []
917
 
        self.assertIs(None, get_bool('not_defined_in_this_config'))
918
 
        self.assertEquals([], warnings)
919
 
 
920
 
    def test_get_user_option_as_list(self):
921
 
        conf, parser = self.make_config_parser("""
922
 
a_list = a,b,c
923
 
length_1 = 1,
924
 
one_item = x
925
 
""")
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'))
932
 
 
933
 
 
934
 
class TestSupressWarning(TestIniConfig):
935
 
 
936
 
    def make_warnings_config(self, s):
937
 
        conf, parser = self.make_config_parser(s)
938
 
        return conf.suppress_warning
939
 
 
940
 
    def test_suppress_warning_unknown(self):
941
 
        suppress_warning = self.make_warnings_config('')
942
 
        self.assertEqual(False, suppress_warning('unknown_warning'))
943
 
 
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'))
949
 
 
950
 
 
951
 
class TestGetConfig(tests.TestCase):
 
231
        config_file = StringIO(sample_config_text)
 
232
        my_config = config.IniBasedConfig(None)
 
233
        parser = my_config._get_parser(file=config_file)
 
234
        self.failUnless(my_config._get_parser() is parser)
 
235
 
 
236
 
 
237
class TestGetConfig(TestCase):
952
238
 
953
239
    def test_constructs(self):
954
240
        my_config = config.GlobalConfig()
955
241
 
956
242
    def test_calls_read_filenames(self):
957
 
        # replace the class that is constructed, to check its parameters
 
243
        # replace the class that is constructured, to check its parameters
958
244
        oldparserclass = config.ConfigObj
959
245
        config.ConfigObj = InstrumentedConfigObj
960
246
        my_config = config.GlobalConfig()
962
248
            parser = my_config._get_parser()
963
249
        finally:
964
250
            config.ConfigObj = oldparserclass
965
 
        self.assertIsInstance(parser, InstrumentedConfigObj)
966
 
        self.assertEqual(parser._calls, [('__init__', config.config_filename(),
967
 
                                          'utf-8')])
968
 
 
969
 
 
970
 
class TestBranchConfig(tests.TestCaseWithTransport):
 
251
        self.failUnless(isinstance(parser, InstrumentedConfigObj))
 
252
        self.assertEqual(parser._calls, [('__init__', config.config_filename())])
 
253
 
 
254
 
 
255
class TestBranchConfig(TestCaseInTempDir):
971
256
 
972
257
    def test_constructs(self):
973
258
        branch = FakeBranch()
979
264
        my_config = config.BranchConfig(branch)
980
265
        location_config = my_config._get_location_config()
981
266
        self.assertEqual(branch.base, location_config.location)
982
 
        self.assertIs(location_config, my_config._get_location_config())
983
 
 
984
 
    def test_get_config(self):
985
 
        """The Branch.get_config method works properly"""
986
 
        b = bzrdir.BzrDir.create_standalone_workingtree('.').branch
987
 
        my_config = b.get_config()
988
 
        self.assertIs(my_config.get_user_option('wacky'), None)
989
 
        my_config.set_user_option('wacky', 'unlikely')
990
 
        self.assertEqual(my_config.get_user_option('wacky'), 'unlikely')
991
 
 
992
 
        # Ensure we get the same thing if we start again
993
 
        b2 = branch.Branch.open('.')
994
 
        my_config2 = b2.get_config()
995
 
        self.assertEqual(my_config2.get_user_option('wacky'), 'unlikely')
996
 
 
997
 
    def test_has_explicit_nickname(self):
998
 
        b = self.make_branch('.')
999
 
        self.assertFalse(b.get_config().has_explicit_nickname())
1000
 
        b.nick = 'foo'
1001
 
        self.assertTrue(b.get_config().has_explicit_nickname())
1002
 
 
1003
 
    def test_config_url(self):
1004
 
        """The Branch.get_config will use section that uses a local url"""
1005
 
        branch = self.make_branch('branch')
1006
 
        self.assertEqual('branch', branch.nick)
1007
 
 
1008
 
        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)
1012
 
        self.assertEqual('foobar', branch.nick)
1013
 
 
1014
 
    def test_config_local_path(self):
1015
 
        """The Branch.get_config will use a local system path"""
1016
 
        branch = self.make_branch('branch')
1017
 
        self.assertEqual('branch', branch.nick)
1018
 
 
1019
 
        local_path = osutils.getcwd().encode('utf8')
1020
 
        conf = config.LocationConfig.from_string(
1021
 
            '[%s/branch]\nnickname = barry' % (local_path,),
1022
 
            'branch',  save=True)
1023
 
        self.assertEqual('barry', branch.nick)
1024
 
 
1025
 
    def test_config_creates_local(self):
1026
 
        """Creating a new entry in config uses a local path."""
1027
 
        branch = self.make_branch('branch', format='knit')
1028
 
        branch.set_push_location('http://foobar')
1029
 
        local_path = osutils.getcwd().encode('utf8')
1030
 
        # Surprisingly ConfigObj doesn't create a trailing newline
1031
 
        self.check_file_contents(config.locations_config_filename(),
1032
 
                                 '[%s/branch]\n'
1033
 
                                 'push_location = http://foobar\n'
1034
 
                                 'push_location:policy = norecurse\n'
1035
 
                                 % (local_path,))
1036
 
 
1037
 
    def test_autonick_urlencoded(self):
1038
 
        b = self.make_branch('!repo')
1039
 
        self.assertEqual('!repo', b.get_config().get_nickname())
1040
 
 
1041
 
    def test_warn_if_masked(self):
1042
 
        warnings = []
1043
 
        def warning(*args):
1044
 
            warnings.append(args[0] % args[1:])
1045
 
        self.overrideAttr(trace, 'warning', warning)
1046
 
 
1047
 
        def set_option(store, warn_masked=True):
1048
 
            warnings[:] = []
1049
 
            conf.set_user_option('example_option', repr(store), store=store,
1050
 
                                 warn_masked=warn_masked)
1051
 
        def assertWarning(warning):
1052
 
            if warning is None:
1053
 
                self.assertEqual(0, len(warnings))
1054
 
            else:
1055
 
                self.assertEqual(1, len(warnings))
1056
 
                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):
 
267
        self.failUnless(location_config is my_config._get_location_config())
 
268
 
 
269
 
 
270
class TestGlobalConfigItems(TestCase):
1076
271
 
1077
272
    def test_user_id(self):
1078
 
        my_config = config.GlobalConfig.from_string(sample_config_text)
1079
 
        self.assertEqual(u"Erik B\u00e5gfors <erik@bagfors.nu>",
 
273
        config_file = StringIO(sample_config_text)
 
274
        my_config = config.GlobalConfig()
 
275
        my_config._parser = my_config._get_parser(file=config_file)
 
276
        self.assertEqual("Robert Collins <robertc@example.com>",
1080
277
                         my_config._get_user_id())
1081
278
 
1082
279
    def test_absent_user_id(self):
 
280
        config_file = StringIO("")
1083
281
        my_config = config.GlobalConfig()
 
282
        my_config._parser = my_config._get_parser(file=config_file)
1084
283
        self.assertEqual(None, my_config._get_user_id())
1085
284
 
1086
285
    def test_configured_editor(self):
1087
 
        my_config = config.GlobalConfig.from_string(sample_config_text)
 
286
        config_file = StringIO(sample_config_text)
 
287
        my_config = config.GlobalConfig()
 
288
        my_config._parser = my_config._get_parser(file=config_file)
1088
289
        self.assertEqual("vim", my_config.get_editor())
1089
290
 
1090
291
    def test_signatures_always(self):
1091
 
        my_config = config.GlobalConfig.from_string(sample_always_signatures)
1092
 
        self.assertEqual(config.CHECK_NEVER,
 
292
        config_file = StringIO(sample_always_signatures)
 
293
        my_config = config.GlobalConfig()
 
294
        my_config._parser = my_config._get_parser(file=config_file)
 
295
        self.assertEqual(config.CHECK_ALWAYS,
1093
296
                         my_config.signature_checking())
1094
 
        self.assertEqual(config.SIGN_ALWAYS,
1095
 
                         my_config.signing_policy())
1096
297
        self.assertEqual(True, my_config.signature_needed())
1097
298
 
1098
299
    def test_signatures_if_possible(self):
1099
 
        my_config = config.GlobalConfig.from_string(sample_maybe_signatures)
1100
 
        self.assertEqual(config.CHECK_NEVER,
 
300
        config_file = StringIO(sample_maybe_signatures)
 
301
        my_config = config.GlobalConfig()
 
302
        my_config._parser = my_config._get_parser(file=config_file)
 
303
        self.assertEqual(config.CHECK_IF_POSSIBLE,
1101
304
                         my_config.signature_checking())
1102
 
        self.assertEqual(config.SIGN_WHEN_REQUIRED,
1103
 
                         my_config.signing_policy())
1104
305
        self.assertEqual(False, my_config.signature_needed())
1105
306
 
1106
307
    def test_signatures_ignore(self):
1107
 
        my_config = config.GlobalConfig.from_string(sample_ignore_signatures)
1108
 
        self.assertEqual(config.CHECK_ALWAYS,
 
308
        config_file = StringIO(sample_ignore_signatures)
 
309
        my_config = config.GlobalConfig()
 
310
        my_config._parser = my_config._get_parser(file=config_file)
 
311
        self.assertEqual(config.CHECK_NEVER,
1109
312
                         my_config.signature_checking())
1110
 
        self.assertEqual(config.SIGN_NEVER,
1111
 
                         my_config.signing_policy())
1112
313
        self.assertEqual(False, my_config.signature_needed())
1113
314
 
1114
315
    def _get_sample_config(self):
1115
 
        my_config = config.GlobalConfig.from_string(sample_config_text)
 
316
        config_file = StringIO(sample_config_text)
 
317
        my_config = config.GlobalConfig()
 
318
        my_config._parser = my_config._get_parser(file=config_file)
1116
319
        return my_config
1117
320
 
1118
321
    def test_gpg_signing_command(self):
1121
324
        self.assertEqual(False, my_config.signature_needed())
1122
325
 
1123
326
    def _get_empty_config(self):
 
327
        config_file = StringIO("")
1124
328
        my_config = config.GlobalConfig()
 
329
        my_config._parser = my_config._get_parser(file=config_file)
1125
330
        return my_config
1126
331
 
1127
332
    def test_gpg_signing_command_unset(self):
1136
341
        my_config = self._get_sample_config()
1137
342
        self.assertEqual("something",
1138
343
                         my_config.get_user_option('user_global_option'))
1139
 
 
 
344
        
1140
345
    def test_post_commit_default(self):
1141
346
        my_config = self._get_sample_config()
1142
347
        self.assertEqual(None, my_config.post_commit())
1143
348
 
1144
 
    def test_configured_logformat(self):
1145
 
        my_config = self._get_sample_config()
1146
 
        self.assertEqual("short", my_config.log_format())
1147
 
 
1148
 
    def test_get_alias(self):
1149
 
        my_config = self._get_sample_config()
1150
 
        self.assertEqual('help', my_config.get_alias('h'))
1151
 
 
1152
 
    def test_get_aliases(self):
1153
 
        my_config = self._get_sample_config()
1154
 
        aliases = my_config.get_aliases()
1155
 
        self.assertEqual(2, len(aliases))
1156
 
        sorted_keys = sorted(aliases)
1157
 
        self.assertEqual('help', aliases[sorted_keys[0]])
1158
 
        self.assertEqual(sample_long_alias, aliases[sorted_keys[1]])
1159
 
 
1160
 
    def test_get_no_alias(self):
1161
 
        my_config = self._get_sample_config()
1162
 
        self.assertEqual(None, my_config.get_alias('foo'))
1163
 
 
1164
 
    def test_get_long_alias(self):
1165
 
        my_config = self._get_sample_config()
1166
 
        self.assertEqual(sample_long_alias, my_config.get_alias('ll'))
1167
 
 
1168
 
    def test_get_change_editor(self):
1169
 
        my_config = self._get_sample_config()
1170
 
        change_editor = my_config.get_change_editor('old', 'new')
1171
 
        self.assertIs(diff.DiffFromTool, change_editor.__class__)
1172
 
        self.assertEqual('vimdiff -of @new_path @old_path',
1173
 
                         ' '.join(change_editor.command_template))
1174
 
 
1175
 
    def test_get_no_change_editor(self):
1176
 
        my_config = self._get_empty_config()
1177
 
        change_editor = my_config.get_change_editor('old', 'new')
1178
 
        self.assertIs(None, change_editor)
1179
 
 
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
 
 
1216
 
class TestGlobalConfigSavingOptions(tests.TestCaseInTempDir):
1217
 
 
1218
 
    def test_empty(self):
1219
 
        my_config = config.GlobalConfig()
1220
 
        self.assertEqual(0, len(my_config.get_aliases()))
1221
 
 
1222
 
    def test_set_alias(self):
1223
 
        my_config = config.GlobalConfig()
1224
 
        alias_value = 'commit --strict'
1225
 
        my_config.set_alias('commit', alias_value)
1226
 
        new_config = config.GlobalConfig()
1227
 
        self.assertEqual(alias_value, new_config.get_alias('commit'))
1228
 
 
1229
 
    def test_remove_alias(self):
1230
 
        my_config = config.GlobalConfig()
1231
 
        my_config.set_alias('commit', 'commit --strict')
1232
 
        # Now remove the alias again.
1233
 
        my_config.unset_alias('commit')
1234
 
        new_config = config.GlobalConfig()
1235
 
        self.assertIs(None, new_config.get_alias('commit'))
1236
 
 
1237
 
 
1238
 
class TestLocationConfig(tests.TestCaseInTempDir, TestOptionsMixin):
 
349
 
 
350
class TestLocationConfig(TestCase):
1239
351
 
1240
352
    def test_constructs(self):
1241
353
        my_config = config.LocationConfig('http://example.com')
1245
357
        # This is testing the correct file names are provided.
1246
358
        # TODO: consolidate with the test for GlobalConfigs filename checks.
1247
359
        #
1248
 
        # replace the class that is constructed, to check its parameters
 
360
        # replace the class that is constructured, to check its parameters
1249
361
        oldparserclass = config.ConfigObj
1250
362
        config.ConfigObj = InstrumentedConfigObj
 
363
        my_config = config.LocationConfig('http://www.example.com')
1251
364
        try:
1252
 
            my_config = config.LocationConfig('http://www.example.com')
1253
365
            parser = my_config._get_parser()
1254
366
        finally:
1255
367
            config.ConfigObj = oldparserclass
1256
 
        self.assertIsInstance(parser, InstrumentedConfigObj)
 
368
        self.failUnless(isinstance(parser, InstrumentedConfigObj))
1257
369
        self.assertEqual(parser._calls,
1258
 
                         [('__init__', config.locations_config_filename(),
1259
 
                           'utf-8')])
 
370
                         [('__init__', config.branches_config_filename())])
1260
371
 
1261
372
    def test_get_global_config(self):
1262
 
        my_config = config.BranchConfig(FakeBranch('http://example.com'))
 
373
        my_config = config.LocationConfig('http://example.com')
1263
374
        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()))
1270
 
 
1271
 
    def test__get_matching_sections_no_match(self):
1272
 
        self.get_branch_config('/')
1273
 
        self.assertLocationMatching([])
1274
 
 
1275
 
    def test__get_matching_sections_exact(self):
1276
 
        self.get_branch_config('http://www.example.com')
1277
 
        self.assertLocationMatching([('http://www.example.com', '')])
1278
 
 
1279
 
    def test__get_matching_sections_suffix_does_not(self):
1280
 
        self.get_branch_config('http://www.example.com-com')
1281
 
        self.assertLocationMatching([])
1282
 
 
1283
 
    def test__get_matching_sections_subdir_recursive(self):
1284
 
        self.get_branch_config('http://www.example.com/com')
1285
 
        self.assertLocationMatching([('http://www.example.com', 'com')])
1286
 
 
1287
 
    def test__get_matching_sections_ignoreparent(self):
1288
 
        self.get_branch_config('http://www.example.com/ignoreparent')
1289
 
        self.assertLocationMatching([('http://www.example.com/ignoreparent',
1290
 
                                      '')])
1291
 
 
1292
 
    def test__get_matching_sections_ignoreparent_subdir(self):
1293
 
        self.get_branch_config(
1294
 
            'http://www.example.com/ignoreparent/childbranch')
1295
 
        self.assertLocationMatching([('http://www.example.com/ignoreparent',
1296
 
                                      'childbranch')])
1297
 
 
1298
 
    def test__get_matching_sections_subdir_trailing_slash(self):
1299
 
        self.get_branch_config('/b')
1300
 
        self.assertLocationMatching([('/b/', '')])
1301
 
 
1302
 
    def test__get_matching_sections_subdir_child(self):
1303
 
        self.get_branch_config('/a/foo')
1304
 
        self.assertLocationMatching([('/a/*', ''), ('/a/', 'foo')])
1305
 
 
1306
 
    def test__get_matching_sections_subdir_child_child(self):
1307
 
        self.get_branch_config('/a/foo/bar')
1308
 
        self.assertLocationMatching([('/a/*', 'bar'), ('/a/', 'foo/bar')])
1309
 
 
1310
 
    def test__get_matching_sections_trailing_slash_with_children(self):
1311
 
        self.get_branch_config('/a/')
1312
 
        self.assertLocationMatching([('/a/', '')])
1313
 
 
1314
 
    def test__get_matching_sections_explicit_over_glob(self):
1315
 
        # XXX: 2006-09-08 jamesh
1316
 
        # This test only passes because ord('c') > ord('*').  If there
1317
 
        # was a config section for '/a/?', it would get precedence
1318
 
        # over '/a/c'.
1319
 
        self.get_branch_config('/a/c')
1320
 
        self.assertLocationMatching([('/a/c', ''), ('/a/*', ''), ('/a/', 'c')])
1321
 
 
1322
 
    def test__get_option_policy_normal(self):
1323
 
        self.get_branch_config('http://www.example.com')
1324
 
        self.assertEqual(
1325
 
            self.my_location_config._get_config_policy(
1326
 
            'http://www.example.com', 'normal_option'),
1327
 
            config.POLICY_NONE)
1328
 
 
1329
 
    def test__get_option_policy_norecurse(self):
1330
 
        self.get_branch_config('http://www.example.com')
1331
 
        self.assertEqual(
1332
 
            self.my_location_config._get_option_policy(
1333
 
            'http://www.example.com', 'norecurse_option'),
1334
 
            config.POLICY_NORECURSE)
1335
 
        # Test old recurse=False setting:
1336
 
        self.assertEqual(
1337
 
            self.my_location_config._get_option_policy(
1338
 
            'http://www.example.com/norecurse', 'normal_option'),
1339
 
            config.POLICY_NORECURSE)
1340
 
 
1341
 
    def test__get_option_policy_normal(self):
1342
 
        self.get_branch_config('http://www.example.com')
1343
 
        self.assertEqual(
1344
 
            self.my_location_config._get_option_policy(
1345
 
            'http://www.example.com', 'appendpath_option'),
1346
 
            config.POLICY_APPENDPATH)
1347
 
 
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)
 
375
        self.failUnless(isinstance(global_config, config.GlobalConfig))
 
376
        self.failUnless(global_config is my_config._get_global_config())
 
377
 
 
378
    def test__get_section_no_match(self):
 
379
        self.get_location_config('/')
 
380
        self.assertEqual(None, self.my_config._get_section())
 
381
        
 
382
    def test__get_section_exact(self):
 
383
        self.get_location_config('http://www.example.com')
 
384
        self.assertEqual('http://www.example.com',
 
385
                         self.my_config._get_section())
 
386
   
 
387
    def test__get_section_suffix_does_not(self):
 
388
        self.get_location_config('http://www.example.com-com')
 
389
        self.assertEqual(None, self.my_config._get_section())
 
390
 
 
391
    def test__get_section_subdir_recursive(self):
 
392
        self.get_location_config('http://www.example.com/com')
 
393
        self.assertEqual('http://www.example.com',
 
394
                         self.my_config._get_section())
 
395
 
 
396
    def test__get_section_subdir_matches(self):
 
397
        self.get_location_config('http://www.example.com/useglobal')
 
398
        self.assertEqual('http://www.example.com/useglobal',
 
399
                         self.my_config._get_section())
 
400
 
 
401
    def test__get_section_subdir_nonrecursive(self):
 
402
        self.get_location_config(
 
403
            'http://www.example.com/useglobal/childbranch')
 
404
        self.assertEqual('http://www.example.com',
 
405
                         self.my_config._get_section())
 
406
 
 
407
    def test__get_section_subdir_trailing_slash(self):
 
408
        self.get_location_config('/b')
 
409
        self.assertEqual('/b/', self.my_config._get_section())
 
410
 
 
411
    def test__get_section_subdir_child(self):
 
412
        self.get_location_config('/a/foo')
 
413
        self.assertEqual('/a/*', self.my_config._get_section())
 
414
 
 
415
    def test__get_section_subdir_child_child(self):
 
416
        self.get_location_config('/a/foo/bar')
 
417
        self.assertEqual('/a/', self.my_config._get_section())
 
418
 
 
419
    def test__get_section_trailing_slash_with_children(self):
 
420
        self.get_location_config('/a/')
 
421
        self.assertEqual('/a/', self.my_config._get_section())
 
422
 
 
423
    def test__get_section_explicit_over_glob(self):
 
424
        self.get_location_config('/a/c')
 
425
        self.assertEqual('/a/c', self.my_config._get_section())
 
426
 
 
427
    def get_location_config(self, location, global_config=None):
 
428
        if global_config is None:
 
429
            global_file = StringIO(sample_config_text)
 
430
        else:
 
431
            global_file = StringIO(global_config)
 
432
        branches_file = StringIO(sample_branches_text)
 
433
        self.my_config = config.LocationConfig(location)
 
434
        self.my_config._get_parser(branches_file)
 
435
        self.my_config._get_global_config()._get_parser(global_file)
1362
436
 
1363
437
    def test_location_without_username(self):
1364
 
        self.get_branch_config('http://www.example.com/ignoreparent')
1365
 
        self.assertEqual(u'Erik B\u00e5gfors <erik@bagfors.nu>',
 
438
        self.get_location_config('http://www.example.com/useglobal')
 
439
        self.assertEqual('Robert Collins <robertc@example.com>',
1366
440
                         self.my_config.username())
1367
441
 
1368
442
    def test_location_not_listed(self):
1369
 
        """Test that the global username is used when no location matches"""
1370
 
        self.get_branch_config('/home/robertc/sources')
1371
 
        self.assertEqual(u'Erik B\u00e5gfors <erik@bagfors.nu>',
 
443
        self.get_location_config('/home/robertc/sources')
 
444
        self.assertEqual('Robert Collins <robertc@example.com>',
1372
445
                         self.my_config.username())
1373
446
 
1374
447
    def test_overriding_location(self):
1375
 
        self.get_branch_config('http://www.example.com/foo')
 
448
        self.get_location_config('http://www.example.com/foo')
1376
449
        self.assertEqual('Robert Collins <robertc@example.org>',
1377
450
                         self.my_config.username())
1378
451
 
1379
452
    def test_signatures_not_set(self):
1380
 
        self.get_branch_config('http://www.example.com',
 
453
        self.get_location_config('http://www.example.com',
1381
454
                                 global_config=sample_ignore_signatures)
1382
 
        self.assertEqual(config.CHECK_ALWAYS,
 
455
        self.assertEqual(config.CHECK_NEVER,
1383
456
                         self.my_config.signature_checking())
1384
 
        self.assertEqual(config.SIGN_NEVER,
1385
 
                         self.my_config.signing_policy())
1386
457
 
1387
458
    def test_signatures_never(self):
1388
 
        self.get_branch_config('/a/c')
 
459
        self.get_location_config('/a/c')
1389
460
        self.assertEqual(config.CHECK_NEVER,
1390
461
                         self.my_config.signature_checking())
1391
 
 
 
462
        
1392
463
    def test_signatures_when_available(self):
1393
 
        self.get_branch_config('/a/', global_config=sample_ignore_signatures)
 
464
        self.get_location_config('/a/', global_config=sample_ignore_signatures)
1394
465
        self.assertEqual(config.CHECK_IF_POSSIBLE,
1395
466
                         self.my_config.signature_checking())
1396
 
 
 
467
        
1397
468
    def test_signatures_always(self):
1398
 
        self.get_branch_config('/b')
 
469
        self.get_location_config('/b')
1399
470
        self.assertEqual(config.CHECK_ALWAYS,
1400
471
                         self.my_config.signature_checking())
1401
 
 
 
472
        
1402
473
    def test_gpg_signing_command(self):
1403
 
        self.get_branch_config('/b')
 
474
        self.get_location_config('/b')
1404
475
        self.assertEqual("gnome-gpg", self.my_config.gpg_signing_command())
1405
476
 
1406
477
    def test_gpg_signing_command_missing(self):
1407
 
        self.get_branch_config('/a')
 
478
        self.get_location_config('/a')
1408
479
        self.assertEqual("false", self.my_config.gpg_signing_command())
1409
480
 
1410
481
    def test_get_user_option_global(self):
1411
 
        self.get_branch_config('/a')
 
482
        self.get_location_config('/a')
1412
483
        self.assertEqual('something',
1413
484
                         self.my_config.get_user_option('user_global_option'))
1414
485
 
1415
486
    def test_get_user_option_local(self):
1416
 
        self.get_branch_config('/a')
 
487
        self.get_location_config('/a')
1417
488
        self.assertEqual('local',
1418
489
                         self.my_config.get_user_option('user_local_option'))
1419
 
 
1420
 
    def test_get_user_option_appendpath(self):
1421
 
        # returned as is for the base path:
1422
 
        self.get_branch_config('http://www.example.com')
1423
 
        self.assertEqual('append',
1424
 
                         self.my_config.get_user_option('appendpath_option'))
1425
 
        # Extra path components get appended:
1426
 
        self.get_branch_config('http://www.example.com/a/b/c')
1427
 
        self.assertEqual('append/a/b/c',
1428
 
                         self.my_config.get_user_option('appendpath_option'))
1429
 
        # Overriden for http://www.example.com/dir, where it is a
1430
 
        # normal option:
1431
 
        self.get_branch_config('http://www.example.com/dir/a/b/c')
1432
 
        self.assertEqual('normal',
1433
 
                         self.my_config.get_user_option('appendpath_option'))
1434
 
 
1435
 
    def test_get_user_option_norecurse(self):
1436
 
        self.get_branch_config('http://www.example.com')
1437
 
        self.assertEqual('norecurse',
1438
 
                         self.my_config.get_user_option('norecurse_option'))
1439
 
        self.get_branch_config('http://www.example.com/dir')
1440
 
        self.assertEqual(None,
1441
 
                         self.my_config.get_user_option('norecurse_option'))
1442
 
        # http://www.example.com/norecurse is a recurse=False section
1443
 
        # that redefines normal_option.  Subdirectories do not pick up
1444
 
        # this redefinition.
1445
 
        self.get_branch_config('http://www.example.com/norecurse')
1446
 
        self.assertEqual('norecurse',
1447
 
                         self.my_config.get_user_option('normal_option'))
1448
 
        self.get_branch_config('http://www.example.com/norecurse/subdir')
1449
 
        self.assertEqual('normal',
1450
 
                         self.my_config.get_user_option('normal_option'))
1451
 
 
1452
 
    def test_set_user_option_norecurse(self):
1453
 
        self.get_branch_config('http://www.example.com')
1454
 
        self.my_config.set_user_option('foo', 'bar',
1455
 
                                       store=config.STORE_LOCATION_NORECURSE)
1456
 
        self.assertEqual(
1457
 
            self.my_location_config._get_option_policy(
1458
 
            'http://www.example.com', 'foo'),
1459
 
            config.POLICY_NORECURSE)
1460
 
 
1461
 
    def test_set_user_option_appendpath(self):
1462
 
        self.get_branch_config('http://www.example.com')
1463
 
        self.my_config.set_user_option('foo', 'bar',
1464
 
                                       store=config.STORE_LOCATION_APPENDPATH)
1465
 
        self.assertEqual(
1466
 
            self.my_location_config._get_option_policy(
1467
 
            'http://www.example.com', 'foo'),
1468
 
            config.POLICY_APPENDPATH)
1469
 
 
1470
 
    def test_set_user_option_change_policy(self):
1471
 
        self.get_branch_config('http://www.example.com')
1472
 
        self.my_config.set_user_option('norecurse_option', 'normal',
1473
 
                                       store=config.STORE_LOCATION)
1474
 
        self.assertEqual(
1475
 
            self.my_location_config._get_option_policy(
1476
 
            'http://www.example.com', 'norecurse_option'),
1477
 
            config.POLICY_NONE)
1478
 
 
1479
 
    def test_set_user_option_recurse_false_section(self):
1480
 
        # The following section has recurse=False set.  The test is to
1481
 
        # make sure that a normal option can be added to the section,
1482
 
        # converting recurse=False to the norecurse policy.
1483
 
        self.get_branch_config('http://www.example.com/norecurse')
1484
 
        self.callDeprecated(['The recurse option is deprecated as of 0.14.  '
1485
 
                             'The section "http://www.example.com/norecurse" '
1486
 
                             'has been converted to use policies.'],
1487
 
                            self.my_config.set_user_option,
1488
 
                            'foo', 'bar', store=config.STORE_LOCATION)
1489
 
        self.assertEqual(
1490
 
            self.my_location_config._get_option_policy(
1491
 
            'http://www.example.com/norecurse', 'foo'),
1492
 
            config.POLICY_NONE)
1493
 
        # The previously existing option is still norecurse:
1494
 
        self.assertEqual(
1495
 
            self.my_location_config._get_option_policy(
1496
 
            'http://www.example.com/norecurse', 'normal_option'),
1497
 
            config.POLICY_NORECURSE)
1498
 
 
 
490
        
1499
491
    def test_post_commit_default(self):
1500
 
        self.get_branch_config('/a/c')
 
492
        self.get_location_config('/a/c')
1501
493
        self.assertEqual('bzrlib.tests.test_config.post_commit',
1502
494
                         self.my_config.post_commit())
1503
495
 
1504
 
    def get_branch_config(self, location, global_config=None,
1505
 
                          location_config=None):
1506
 
        my_branch = FakeBranch(location)
 
496
 
 
497
class TestLocationConfig(TestCaseInTempDir):
 
498
 
 
499
    def get_location_config(self, location, global_config=None):
1507
500
        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()
 
501
            global_file = StringIO(sample_config_text)
 
502
        else:
 
503
            global_file = StringIO(global_config)
 
504
        branches_file = StringIO(sample_branches_text)
 
505
        self.my_config = config.LocationConfig(location)
 
506
        self.my_config._get_parser(branches_file)
 
507
        self.my_config._get_global_config()._get_parser(global_file)
1519
508
 
1520
509
    def test_set_user_setting_sets_and_saves(self):
1521
 
        self.get_branch_config('/a/c')
 
510
        # TODO RBC 20051029 test hat mkdir ~/.bazaar is called ..
 
511
        self.get_location_config('/a/c')
1522
512
        record = InstrumentedConfigObj("foo")
1523
 
        self.my_location_config._parser = record
1524
 
 
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'),
 
513
        self.my_config._parser = record
 
514
        print ("test_set_user_setting_sets_and_saves broken: creates .bazaar "
 
515
               "in the top-level directory, not inside the test directory")
 
516
        return
 
517
        self.my_config.set_user_option('foo', 'bar')
 
518
        self.assertEqual([('__contains__', '/a/c'),
1532
519
                          ('__contains__', '/a/c/'),
1533
520
                          ('__setitem__', '/a/c', {}),
1534
521
                          ('__getitem__', '/a/c'),
1535
522
                          ('__setitem__', 'foo', 'bar'),
1536
 
                          ('__getitem__', '/a/c'),
1537
 
                          ('as_bool', 'recurse'),
1538
 
                          ('__getitem__', '/a/c'),
1539
 
                          ('__delitem__', 'recurse'),
1540
 
                          ('__getitem__', '/a/c'),
1541
 
                          ('keys',),
1542
 
                          ('__getitem__', '/a/c'),
1543
 
                          ('__contains__', 'foo:policy'),
1544
523
                          ('write',)],
1545
524
                         record._calls[1:])
1546
525
 
1547
 
    def test_set_user_setting_sets_and_saves2(self):
1548
 
        self.get_branch_config('/a/c')
1549
 
        self.assertIs(self.my_config.get_user_option('foo'), None)
1550
 
        self.my_config.set_user_option('foo', 'bar')
1551
 
        self.assertEqual(
1552
 
            self.my_config.branch.control_files.files['branch.conf'].strip(),
1553
 
            'foo = bar')
1554
 
        self.assertEqual(self.my_config.get_user_option('foo'), 'bar')
1555
 
        self.my_config.set_user_option('foo', 'baz',
1556
 
                                       store=config.STORE_LOCATION)
1557
 
        self.assertEqual(self.my_config.get_user_option('foo'), 'baz')
1558
 
        self.my_config.set_user_option('foo', 'qux')
1559
 
        self.assertEqual(self.my_config.get_user_option('foo'), 'baz')
1560
 
 
1561
 
    def test_get_bzr_remote_path(self):
1562
 
        my_config = config.LocationConfig('/a/c')
1563
 
        self.assertEqual('bzr', my_config.get_bzr_remote_path())
1564
 
        my_config.set_user_option('bzr_remote_path', '/path-bzr')
1565
 
        self.assertEqual('/path-bzr', my_config.get_bzr_remote_path())
1566
 
        self.overrideEnv('BZR_REMOTE_PATH', '/environ-bzr')
1567
 
        self.assertEqual('/environ-bzr', my_config.get_bzr_remote_path())
1568
 
 
1569
 
 
1570
 
precedence_global = 'option = global'
1571
 
precedence_branch = 'option = branch'
1572
 
precedence_location = """
1573
 
[http://]
1574
 
recurse = true
1575
 
option = recurse
1576
 
[http://example.com/specific]
1577
 
option = exact
1578
 
"""
1579
 
 
1580
 
class TestBranchConfigItems(tests.TestCaseInTempDir):
1581
 
 
1582
 
    def get_branch_config(self, global_config=None, location=None,
1583
 
                          location_config=None, branch_data_config=None):
1584
 
        my_branch = FakeBranch(location)
1585
 
        if global_config is not None:
1586
 
            my_global_config = config.GlobalConfig.from_string(global_config,
1587
 
                                                               save=True)
1588
 
        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)
1592
 
        if branch_data_config is not None:
1593
 
            my_config.branch.control_files.files['branch.conf'] = \
1594
 
                branch_data_config
1595
 
        return my_config
 
526
 
 
527
class TestBranchConfigItems(TestCase):
1596
528
 
1597
529
    def test_user_id(self):
1598
 
        branch = FakeBranch(user_id='Robert Collins <robertc@example.net>')
 
530
        branch = FakeBranch()
1599
531
        my_config = config.BranchConfig(branch)
1600
532
        self.assertEqual("Robert Collins <robertc@example.net>",
1601
 
                         my_config.username())
1602
 
        my_config.branch.control_files.files['email'] = "John"
1603
 
        my_config.set_user_option('email',
1604
 
                                  "Robert Collins <robertc@example.org>")
1605
 
        self.assertEqual("John", my_config.username())
1606
 
        del my_config.branch.control_files.files['email']
1607
 
        self.assertEqual("Robert Collins <robertc@example.org>",
1608
 
                         my_config.username())
 
533
                         my_config._get_user_id())
 
534
        branch.email = "John"
 
535
        self.assertEqual("John", my_config._get_user_id())
1609
536
 
1610
537
    def test_not_set_in_branch(self):
1611
 
        my_config = self.get_branch_config(global_config=sample_config_text)
1612
 
        self.assertEqual(u"Erik B\u00e5gfors <erik@bagfors.nu>",
 
538
        branch = FakeBranch()
 
539
        my_config = config.BranchConfig(branch)
 
540
        branch.email = None
 
541
        config_file = StringIO(sample_config_text)
 
542
        (my_config._get_location_config().
 
543
            _get_global_config()._get_parser(config_file))
 
544
        self.assertEqual("Robert Collins <robertc@example.com>",
1613
545
                         my_config._get_user_id())
1614
 
        my_config.branch.control_files.files['email'] = "John"
 
546
        branch.email = "John"
1615
547
        self.assertEqual("John", my_config._get_user_id())
1616
548
 
1617
 
    def test_BZR_EMAIL_OVERRIDES(self):
1618
 
        self.overrideEnv('BZR_EMAIL', "Robert Collins <robertc@example.org>")
 
549
    def test_BZREMAIL_OVERRIDES(self):
 
550
        os.environ['BZREMAIL'] = "Robert Collins <robertc@example.org>"
1619
551
        branch = FakeBranch()
1620
552
        my_config = config.BranchConfig(branch)
1621
553
        self.assertEqual("Robert Collins <robertc@example.org>",
1622
554
                         my_config.username())
1623
 
 
 
555
    
1624
556
    def test_signatures_forced(self):
1625
 
        my_config = self.get_branch_config(
1626
 
            global_config=sample_always_signatures)
1627
 
        self.assertEqual(config.CHECK_NEVER, my_config.signature_checking())
1628
 
        self.assertEqual(config.SIGN_ALWAYS, my_config.signing_policy())
1629
 
        self.assertTrue(my_config.signature_needed())
1630
 
 
1631
 
    def test_signatures_forced_branch(self):
1632
 
        my_config = self.get_branch_config(
1633
 
            global_config=sample_ignore_signatures,
1634
 
            branch_data_config=sample_always_signatures)
1635
 
        self.assertEqual(config.CHECK_NEVER, my_config.signature_checking())
1636
 
        self.assertEqual(config.SIGN_ALWAYS, my_config.signing_policy())
1637
 
        self.assertTrue(my_config.signature_needed())
 
557
        branch = FakeBranch()
 
558
        my_config = config.BranchConfig(branch)
 
559
        config_file = StringIO(sample_always_signatures)
 
560
        (my_config._get_location_config().
 
561
            _get_global_config()._get_parser(config_file))
 
562
        self.assertEqual(config.CHECK_ALWAYS, my_config.signature_checking())
1638
563
 
1639
564
    def test_gpg_signing_command(self):
1640
 
        my_config = self.get_branch_config(
1641
 
            global_config=sample_config_text,
1642
 
            # branch data cannot set gpg_signing_command
1643
 
            branch_data_config="gpg_signing_command=pgp")
 
565
        branch = FakeBranch()
 
566
        my_config = config.BranchConfig(branch)
 
567
        config_file = StringIO(sample_config_text)
 
568
        (my_config._get_location_config().
 
569
            _get_global_config()._get_parser(config_file))
1644
570
        self.assertEqual('gnome-gpg', my_config.gpg_signing_command())
1645
571
 
1646
572
    def test_get_user_option_global(self):
1647
 
        my_config = self.get_branch_config(global_config=sample_config_text)
 
573
        branch = FakeBranch()
 
574
        my_config = config.BranchConfig(branch)
 
575
        config_file = StringIO(sample_config_text)
 
576
        (my_config._get_location_config().
 
577
            _get_global_config()._get_parser(config_file))
1648
578
        self.assertEqual('something',
1649
579
                         my_config.get_user_option('user_global_option'))
1650
580
 
1651
581
    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)
1655
 
        self.assertEqual(my_config.branch.base, '/a/c')
1656
 
        self.assertEqual('bzrlib.tests.test_config.post_commit',
1657
 
                         my_config.post_commit())
1658
 
        my_config.set_user_option('post_commit', 'rmtree_root')
1659
 
        # post-commit is ignored when present in branch data
1660
 
        self.assertEqual('bzrlib.tests.test_config.post_commit',
1661
 
                         my_config.post_commit())
1662
 
        my_config.set_user_option('post_commit', 'rmtree_root',
1663
 
                                  store=config.STORE_LOCATION)
1664
 
        self.assertEqual('rmtree_root', my_config.post_commit())
1665
 
 
1666
 
    def test_config_precedence(self):
1667
 
        # FIXME: eager test, luckily no persitent config file makes it fail
1668
 
        # -- vila 20100716
1669
 
        my_config = self.get_branch_config(global_config=precedence_global)
1670
 
        self.assertEqual(my_config.get_user_option('option'), 'global')
1671
 
        my_config = self.get_branch_config(global_config=precedence_global,
1672
 
                                           branch_data_config=precedence_branch)
1673
 
        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)
1678
 
        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')
1684
 
        self.assertEqual(my_config.get_user_option('option'), 'exact')
1685
 
 
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)
1690
 
 
1691
 
        # Specific clients
1692
 
        config.set_user_option('mail_client', 'evolution')
1693
 
        client = config.get_mail_client()
1694
 
        self.assertIsInstance(client, mail_client.Evolution)
1695
 
 
1696
 
        config.set_user_option('mail_client', 'kmail')
1697
 
        client = config.get_mail_client()
1698
 
        self.assertIsInstance(client, mail_client.KMail)
1699
 
 
1700
 
        config.set_user_option('mail_client', 'mutt')
1701
 
        client = config.get_mail_client()
1702
 
        self.assertIsInstance(client, mail_client.Mutt)
1703
 
 
1704
 
        config.set_user_option('mail_client', 'thunderbird')
1705
 
        client = config.get_mail_client()
1706
 
        self.assertIsInstance(client, mail_client.Thunderbird)
1707
 
 
1708
 
        # Generic options
1709
 
        config.set_user_option('mail_client', 'default')
1710
 
        client = config.get_mail_client()
1711
 
        self.assertIsInstance(client, mail_client.DefaultMail)
1712
 
 
1713
 
        config.set_user_option('mail_client', 'editor')
1714
 
        client = config.get_mail_client()
1715
 
        self.assertIsInstance(client, mail_client.Editor)
1716
 
 
1717
 
        config.set_user_option('mail_client', 'mapi')
1718
 
        client = config.get_mail_client()
1719
 
        self.assertIsInstance(client, mail_client.MAPIClient)
1720
 
 
1721
 
        config.set_user_option('mail_client', 'xdg-email')
1722
 
        client = config.get_mail_client()
1723
 
        self.assertIsInstance(client, mail_client.XDGEmail)
1724
 
 
1725
 
        config.set_user_option('mail_client', 'firebird')
1726
 
        self.assertRaises(errors.UnknownMailClient, config.get_mail_client)
1727
 
 
1728
 
 
1729
 
class TestMailAddressExtraction(tests.TestCase):
 
582
        branch = FakeBranch()
 
583
        branch.base='/a/c'
 
584
        my_config = config.BranchConfig(branch)
 
585
        config_file = StringIO(sample_config_text)
 
586
        (my_config._get_location_config().
 
587
            _get_global_config()._get_parser(config_file))
 
588
        branch_file = StringIO(sample_branches_text)
 
589
        my_config._get_location_config()._get_parser(branch_file)
 
590
        self.assertEqual('bzrlib.tests.test_config.post_commit',
 
591
                         my_config.post_commit())
 
592
 
 
593
 
 
594
class TestMailAddressExtraction(TestCase):
1730
595
 
1731
596
    def test_extract_email_address(self):
1732
597
        self.assertEqual('jane@test.com',
1733
598
                         config.extract_email_address('Jane <jane@test.com>'))
1734
 
        self.assertRaises(errors.NoEmailInUsername,
 
599
        self.assertRaises(errors.BzrError,
1735
600
                          config.extract_email_address, 'Jane Tester')
1736
 
 
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'))
1748
 
 
1749
 
class TestTreeConfig(tests.TestCaseWithTransport):
1750
 
 
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')
1775
 
 
1776
 
 
1777
 
class TestTransportConfig(tests.TestCaseWithTransport):
1778
 
 
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('.'),
1782
 
                                               'control.conf')
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',
1798
 
                                         default='default')
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')
1804
 
 
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())
1815
 
 
1816
 
 
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
 
class TestAuthenticationConfigFile(tests.TestCase):
1970
 
    """Test the authentication.conf file matching"""
1971
 
 
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:
1976
 
            user = None
1977
 
            password = None
1978
 
        else:
1979
 
            user = credentials['user']
1980
 
            password = credentials['password']
1981
 
        self.assertEquals(expected_user, user)
1982
 
        self.assertEquals(expected_password, password)
1983
 
 
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')
1988
 
 
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')
1992
 
 
1993
 
    def test_auth_section_header_not_closed(self):
1994
 
        conf = config.AuthenticationConfig(_file=StringIO('[DEF'))
1995
 
        self.assertRaises(errors.ParseConfigError, conf._get_config)
1996
 
 
1997
 
    def test_auth_value_not_boolean(self):
1998
 
        conf = config.AuthenticationConfig(_file=StringIO(
1999
 
                """[broken]
2000
 
scheme=ftp
2001
 
user=joe
2002
 
verify_certificates=askme # Error: Not a boolean
2003
 
"""))
2004
 
        self.assertRaises(ValueError, conf.get_credentials, 'ftp', 'foo.net')
2005
 
 
2006
 
    def test_auth_value_not_int(self):
2007
 
        conf = config.AuthenticationConfig(_file=StringIO(
2008
 
                """[broken]
2009
 
scheme=ftp
2010
 
user=joe
2011
 
port=port # Error: Not an int
2012
 
"""))
2013
 
        self.assertRaises(ValueError, conf.get_credentials, 'ftp', 'foo.net')
2014
 
 
2015
 
    def test_unknown_password_encoding(self):
2016
 
        conf = config.AuthenticationConfig(_file=StringIO(
2017
 
                """[broken]
2018
 
scheme=ftp
2019
 
user=joe
2020
 
password_encoding=unknown
2021
 
"""))
2022
 
        self.assertRaises(ValueError, conf.get_password,
2023
 
                          'ftp', 'foo.net', 'joe')
2024
 
 
2025
 
    def test_credentials_for_scheme_host(self):
2026
 
        conf = config.AuthenticationConfig(_file=StringIO(
2027
 
                """# Identity on foo.net
2028
 
[ftp definition]
2029
 
scheme=ftp
2030
 
host=foo.net
2031
 
user=joe
2032
 
password=secret-pass
2033
 
"""))
2034
 
        # Basic matching
2035
 
        self._got_user_passwd('joe', 'secret-pass', conf, 'ftp', 'foo.net')
2036
 
        # different scheme
2037
 
        self._got_user_passwd(None, None, conf, 'http', 'foo.net')
2038
 
        # different host
2039
 
        self._got_user_passwd(None, None, conf, 'ftp', 'bar.net')
2040
 
 
2041
 
    def test_credentials_for_host_port(self):
2042
 
        conf = config.AuthenticationConfig(_file=StringIO(
2043
 
                """# Identity on foo.net
2044
 
[ftp definition]
2045
 
scheme=ftp
2046
 
port=10021
2047
 
host=foo.net
2048
 
user=joe
2049
 
password=secret-pass
2050
 
"""))
2051
 
        # No port
2052
 
        self._got_user_passwd('joe', 'secret-pass',
2053
 
                              conf, 'ftp', 'foo.net', port=10021)
2054
 
        # different port
2055
 
        self._got_user_passwd(None, None, conf, 'ftp', 'foo.net')
2056
 
 
2057
 
    def test_for_matching_host(self):
2058
 
        conf = config.AuthenticationConfig(_file=StringIO(
2059
 
                """# Identity on foo.net
2060
 
[sourceforge]
2061
 
scheme=bzr
2062
 
host=bzr.sf.net
2063
 
user=joe
2064
 
password=joepass
2065
 
[sourceforge domain]
2066
 
scheme=bzr
2067
 
host=.bzr.sf.net
2068
 
user=georges
2069
 
password=bendover
2070
 
"""))
2071
 
        # matching domain
2072
 
        self._got_user_passwd('georges', 'bendover',
2073
 
                              conf, 'bzr', 'foo.bzr.sf.net')
2074
 
        # phishing attempt
2075
 
        self._got_user_passwd(None, None,
2076
 
                              conf, 'bzr', 'bbzr.sf.net')
2077
 
 
2078
 
    def test_for_matching_host_None(self):
2079
 
        conf = config.AuthenticationConfig(_file=StringIO(
2080
 
                """# Identity on foo.net
2081
 
[catchup bzr]
2082
 
scheme=bzr
2083
 
user=joe
2084
 
password=joepass
2085
 
[DEFAULT]
2086
 
user=georges
2087
 
password=bendover
2088
 
"""))
2089
 
        # match no host
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')
2095
 
 
2096
 
    def test_credentials_for_path(self):
2097
 
        conf = config.AuthenticationConfig(_file=StringIO(
2098
 
                """
2099
 
[http dir1]
2100
 
scheme=http
2101
 
host=bar.org
2102
 
path=/dir1
2103
 
user=jim
2104
 
password=jimpass
2105
 
[http dir2]
2106
 
scheme=http
2107
 
host=bar.org
2108
 
path=/dir2
2109
 
user=georges
2110
 
password=bendover
2111
 
"""))
2112
 
        # no path no dice
2113
 
        self._got_user_passwd(None, None,
2114
 
                              conf, 'http', host='bar.org', path='/dir3')
2115
 
        # matching path
2116
 
        self._got_user_passwd('georges', 'bendover',
2117
 
                              conf, 'http', host='bar.org', path='/dir2')
2118
 
        # matching subdir
2119
 
        self._got_user_passwd('jim', 'jimpass',
2120
 
                              conf, 'http', host='bar.org',path='/dir1/subdir')
2121
 
 
2122
 
    def test_credentials_for_user(self):
2123
 
        conf = config.AuthenticationConfig(_file=StringIO(
2124
 
                """
2125
 
[with user]
2126
 
scheme=http
2127
 
host=bar.org
2128
 
user=jim
2129
 
password=jimpass
2130
 
"""))
2131
 
        # Get user
2132
 
        self._got_user_passwd('jim', 'jimpass',
2133
 
                              conf, 'http', 'bar.org')
2134
 
        # Get same user
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')
2140
 
 
2141
 
    def test_credentials_for_user_without_password(self):
2142
 
        conf = config.AuthenticationConfig(_file=StringIO(
2143
 
                """
2144
 
[without password]
2145
 
scheme=http
2146
 
host=bar.org
2147
 
user=jim
2148
 
"""))
2149
 
        # Get user but no password
2150
 
        self._got_user_passwd('jim', None,
2151
 
                              conf, 'http', 'bar.org')
2152
 
 
2153
 
    def test_verify_certificates(self):
2154
 
        conf = config.AuthenticationConfig(_file=StringIO(
2155
 
                """
2156
 
[self-signed]
2157
 
scheme=https
2158
 
host=bar.org
2159
 
user=jim
2160
 
password=jimpass
2161
 
verify_certificates=False
2162
 
[normal]
2163
 
scheme=https
2164
 
host=foo.net
2165
 
user=georges
2166
 
password=bendover
2167
 
"""))
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'))
2172
 
 
2173
 
 
2174
 
class TestAuthenticationStorage(tests.TestCaseInTempDir):
2175
 
 
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',
2182
 
                                           realm='realm')
2183
 
        CREDENTIALS = {'name': 'name', 'user': 'user', 'password': 'password',
2184
 
                       'verify_certificates': False, 'scheme': 'scheme', 
2185
 
                       'host': 'host', 'port': 99, 'path': '/foo', 
2186
 
                       'realm': 'realm'}
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)
2191
 
 
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)
2203
 
 
2204
 
 
2205
 
class TestAuthenticationConfig(tests.TestCase):
2206
 
    """Test AuthenticationConfig behaviour"""
2207
 
 
2208
 
    def _check_default_password_prompt(self, expected_prompt_format, scheme,
2209
 
                                       host=None, port=None, realm=None,
2210
 
                                       path=None):
2211
 
        if host is None:
2212
 
            host = 'bar.org'
2213
 
        user, password = 'jim', 'precious'
2214
 
        expected_prompt = expected_prompt_format % {
2215
 
            'scheme': scheme, 'host': host, 'port': port,
2216
 
            'user': user, 'realm': realm}
2217
 
 
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())
2229
 
 
2230
 
    def _check_default_username_prompt(self, expected_prompt_format, scheme,
2231
 
                                       host=None, port=None, realm=None,
2232
 
                                       path=None):
2233
 
        if host is None:
2234
 
            host = 'bar.org'
2235
 
        username = 'jim'
2236
 
        expected_prompt = expected_prompt_format % {
2237
 
            'scheme': scheme, 'host': host, 'port': port,
2238
 
            'realm': realm}
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())
2249
 
 
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)
2257
 
 
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"))
2264
 
 
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
2274
 
        # host too)
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: ',
2278
 
                                            'smtp')
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: ',
2283
 
            'smtp', port=10025)
2284
 
 
2285
 
    def test_ssh_password_emits_warning(self):
2286
 
        conf = config.AuthenticationConfig(_file=StringIO(
2287
 
                """
2288
 
[ssh with password]
2289
 
scheme=ssh
2290
 
host=bar.org
2291
 
user=jim
2292
 
password=jimpass
2293
 
"""))
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)
2299
 
 
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(
2305
 
            self.get_log(),
2306
 
            'password ignored in section \[ssh with password\]')
2307
 
 
2308
 
    def test_ssh_without_password_doesnt_emit_warning(self):
2309
 
        conf = config.AuthenticationConfig(_file=StringIO(
2310
 
                """
2311
 
[ssh with password]
2312
 
scheme=ssh
2313
 
host=bar.org
2314
 
user=jim
2315
 
"""))
2316
 
        entered_password = 'typed-by-hand'
2317
 
        stdout = tests.StringIOWrapper()
2318
 
        stderr = tests.StringIOWrapper()
2319
 
        ui.ui_factory = tests.TestUIFactory(stdin=entered_password + '\n',
2320
 
                                            stdout=stdout,
2321
 
                                            stderr=stderr)
2322
 
 
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
2328
 
        # providing "user".
2329
 
        self.assertNotContainsRe(
2330
 
            self.get_log(),
2331
 
            'password ignored in section \[ssh with password\]')
2332
 
 
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"])
2343
 
 
2344
 
 
2345
 
class StubCredentialStore(config.CredentialStore):
2346
 
 
2347
 
    def __init__(self):
2348
 
        self._username = {}
2349
 
        self._password = {}
2350
 
 
2351
 
    def add_credentials(self, scheme, host, user, password=None):
2352
 
        self._username[(scheme, host)] = user
2353
 
        self._password[(scheme, host)] = password
2354
 
 
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:
2359
 
            return None
2360
 
        return { "scheme": scheme, "host": host, "port": port,
2361
 
                "user": self._username[key], "password": self._password[key]}
2362
 
 
2363
 
 
2364
 
class CountingCredentialStore(config.CredentialStore):
2365
 
 
2366
 
    def __init__(self):
2367
 
        self._calls = 0
2368
 
 
2369
 
    def get_credentials(self, scheme, host, port=None, user=None,
2370
 
        path=None, realm=None):
2371
 
        self._calls += 1
2372
 
        return None
2373
 
 
2374
 
 
2375
 
class TestCredentialStoreRegistry(tests.TestCase):
2376
 
 
2377
 
    def _get_cs_registry(self):
2378
 
        return config.credential_store_registry
2379
 
 
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)
2384
 
 
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')
2390
 
 
2391
 
    def test_fallback_none_registered(self):
2392
 
        r = config.CredentialStoreRegistry()
2393
 
        self.assertEquals(None,
2394
 
                          r.get_fallback_credentials("http", "example.com"))
2395
 
 
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())
2401
 
 
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)
2409
 
 
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"))
2416
 
 
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)
2424
 
 
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"])
2434
 
 
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"])
2448
 
 
2449
 
 
2450
 
class TestPlainTextCredentialStore(tests.TestCase):
2451
 
 
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)
2457
 
 
2458
 
 
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):
2468
 
    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