~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_config.py

  • Committer: Robert Collins
  • Date: 2005-12-02 03:23:47 UTC
  • Revision ID: robertc@robertcollins.net-20051202032347-ba08123207a945a0
Test for Jeff Bailey.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2010 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
 
24
25
#import bzrlib specific imports here
25
 
from bzrlib import (
26
 
    branch,
27
 
    bzrdir,
28
 
    config,
29
 
    diff,
30
 
    errors,
31
 
    osutils,
32
 
    mail_client,
33
 
    ui,
34
 
    urlutils,
35
 
    tests,
36
 
    trace,
37
 
    transport,
38
 
    )
39
 
from bzrlib.tests import features
40
 
from bzrlib.util.configobj import configobj
41
 
 
42
 
 
43
 
def lockable_config_scenarios():
44
 
    return [
45
 
        ('global',
46
 
         {'config_class': config.GlobalConfig,
47
 
          'config_args': [],
48
 
          'config_section': 'DEFAULT'}),
49
 
        ('locations',
50
 
         {'config_class': config.LocationConfig,
51
 
          'config_args': ['.'],
52
 
          'config_section': '.'}),]
53
 
 
54
 
 
55
 
def load_tests(standard_tests, module, loader):
56
 
    suite = loader.suiteClass()
57
 
 
58
 
    lc_tests, remaining_tests = tests.split_suite_by_condition(
59
 
        standard_tests, tests.condition_isinstance((
60
 
                TestLockableConfig,
61
 
                )))
62
 
    tests.multiply_tests(lc_tests, lockable_config_scenarios(), suite)
63
 
    suite.addTest(remaining_tests)
64
 
    return suite
65
 
 
66
 
 
67
 
sample_long_alias="log -r-15..-1 --line"
68
 
sample_config_text = u"""
69
 
[DEFAULT]
70
 
email=Erik B\u00e5gfors <erik@bagfors.nu>
71
 
editor=vim
72
 
change_editor=vimdiff -of @new_path @old_path
73
 
gpg_signing_command=gnome-gpg
74
 
log_format=short
75
 
user_global_option=something
76
 
[ALIASES]
77
 
h=help
78
 
ll=""" + sample_long_alias + "\n"
79
 
 
80
 
 
81
 
sample_always_signatures = """
82
 
[DEFAULT]
83
 
check_signatures=ignore
84
 
create_signatures=always
85
 
"""
86
 
 
87
 
sample_ignore_signatures = """
88
 
[DEFAULT]
89
 
check_signatures=require
90
 
create_signatures=never
91
 
"""
92
 
 
93
 
sample_maybe_signatures = """
94
 
[DEFAULT]
95
 
check_signatures=ignore
96
 
create_signatures=when-required
97
 
"""
98
 
 
99
 
sample_branches_text = """
100
 
[http://www.example.com]
101
 
# Top level policy
102
 
email=Robert Collins <robertc@example.org>
103
 
normal_option = normal
104
 
appendpath_option = append
105
 
appendpath_option:policy = appendpath
106
 
norecurse_option = norecurse
107
 
norecurse_option:policy = norecurse
108
 
[http://www.example.com/ignoreparent]
109
 
# different project: ignore parent dir config
110
 
ignore_parents=true
111
 
[http://www.example.com/norecurse]
112
 
# configuration items that only apply to this dir
113
 
recurse=false
114
 
normal_option = norecurse
115
 
[http://www.example.com/dir]
116
 
appendpath_option = normal
117
 
[/b/]
118
 
check_signatures=require
119
 
# test trailing / matching with no children
120
 
[/a/]
121
 
check_signatures=check-available
122
 
gpg_signing_command=false
123
 
user_local_option=local
124
 
# test trailing / matching
125
 
[/a/*]
126
 
#subdirs will match but not the parent
127
 
[/a/c]
128
 
check_signatures=ignore
129
 
post_commit=bzrlib.tests.test_config.post_commit
130
 
#testing explicit beats globs
131
 
"""
 
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")
132
71
 
133
72
 
134
73
class InstrumentedConfigObj(object):
142
81
        self._calls.append(('__getitem__', key))
143
82
        return self
144
83
 
145
 
    def __init__(self, input, encoding=None):
146
 
        self._calls = [('__init__', input, encoding)]
 
84
    def __init__(self, input):
 
85
        self._calls = [('__init__', input)]
147
86
 
148
87
    def __setitem__(self, key, value):
149
88
        self._calls.append(('__setitem__', key, value))
150
89
 
151
 
    def __delitem__(self, key):
152
 
        self._calls.append(('__delitem__', key))
153
 
 
154
 
    def keys(self):
155
 
        self._calls.append(('keys',))
156
 
        return []
157
 
 
158
 
    def reload(self):
159
 
        self._calls.append(('reload',))
160
 
 
161
 
    def write(self, arg):
 
90
    def write(self):
162
91
        self._calls.append(('write',))
163
92
 
164
 
    def as_bool(self, value):
165
 
        self._calls.append(('as_bool', value))
166
 
        return False
167
 
 
168
 
    def get_value(self, section, name):
169
 
        self._calls.append(('get_value', section, name))
170
 
        return None
171
 
 
172
93
 
173
94
class FakeBranch(object):
174
95
 
175
 
    def __init__(self, base=None, user_id=None):
176
 
        if base is None:
177
 
            self.base = "http://example.com/branches/demo"
178
 
        else:
179
 
            self.base = base
180
 
        self._transport = self.control_files = \
181
 
            FakeControlFilesAndTransport(user_id=user_id)
182
 
 
183
 
    def _get_config(self):
184
 
        return config.TransportConfig(self._transport, 'branch.conf')
185
 
 
186
 
    def lock_write(self):
187
 
        pass
188
 
 
189
 
    def unlock(self):
190
 
        pass
191
 
 
192
 
 
193
 
class FakeControlFilesAndTransport(object):
194
 
 
195
 
    def __init__(self, user_id=None):
196
 
        self.files = {}
197
 
        if user_id:
198
 
            self.files['email'] = user_id
199
 
        self._transport = self
200
 
 
201
 
    def get_utf8(self, filename):
202
 
        # from LockableFiles
203
 
        raise AssertionError("get_utf8 should no longer be used")
204
 
 
205
 
    def get(self, filename):
206
 
        # from Transport
207
 
        try:
208
 
            return StringIO(self.files[filename])
209
 
        except KeyError:
210
 
            raise errors.NoSuchFile(filename)
211
 
 
212
 
    def get_bytes(self, filename):
213
 
        # from Transport
214
 
        try:
215
 
            return self.files[filename]
216
 
        except KeyError:
217
 
            raise errors.NoSuchFile(filename)
218
 
 
219
 
    def put(self, filename, fileobj):
220
 
        self.files[filename] = fileobj.read()
221
 
 
222
 
    def put_file(self, filename, fileobj):
223
 
        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
224
106
 
225
107
 
226
108
class InstrumentedConfig(config.Config):
227
109
    """An instrumented config that supplies stubs for template methods."""
228
 
 
 
110
    
229
111
    def __init__(self):
230
112
        super(InstrumentedConfig, self).__init__()
231
113
        self._calls = []
239
121
        self._calls.append('_get_signature_checking')
240
122
        return self._signatures
241
123
 
242
 
    def _get_change_editor(self):
243
 
        self._calls.append('_get_change_editor')
244
 
        return 'vimdiff -fo @new_path @old_path'
245
 
 
246
 
 
247
 
bool_config = """[DEFAULT]
248
 
active = true
249
 
inactive = false
250
 
[UPPERCASE]
251
 
active = True
252
 
nonactive = False
253
 
"""
254
 
 
255
 
 
256
 
class TestConfigObj(tests.TestCase):
257
 
 
258
 
    def test_get_bool(self):
259
 
        co = config.ConfigObj(StringIO(bool_config))
260
 
        self.assertIs(co.get_bool('DEFAULT', 'active'), True)
261
 
        self.assertIs(co.get_bool('DEFAULT', 'inactive'), False)
262
 
        self.assertIs(co.get_bool('UPPERCASE', 'active'), True)
263
 
        self.assertIs(co.get_bool('UPPERCASE', 'nonactive'), False)
264
 
 
265
 
    def test_hash_sign_in_value(self):
266
 
        """
267
 
        Before 4.5.0, ConfigObj did not quote # signs in values, so they'd be
268
 
        treated as comments when read in again. (#86838)
269
 
        """
270
 
        co = config.ConfigObj()
271
 
        co['test'] = 'foo#bar'
272
 
        lines = co.write()
273
 
        self.assertEqual(lines, ['test = "foo#bar"'])
274
 
        co2 = config.ConfigObj(lines)
275
 
        self.assertEqual(co2['test'], 'foo#bar')
276
 
 
277
 
 
278
 
erroneous_config = """[section] # line 1
279
 
good=good # line 2
280
 
[section] # line 3
281
 
whocares=notme # line 4
282
 
"""
283
 
 
284
 
 
285
 
class TestConfigObjErrors(tests.TestCase):
286
 
 
287
 
    def test_duplicate_section_name_error_line(self):
288
 
        try:
289
 
            co = configobj.ConfigObj(StringIO(erroneous_config),
290
 
                                     raise_errors=True)
291
 
        except config.configobj.DuplicateError, e:
292
 
            self.assertEqual(3, e.line_number)
293
 
        else:
294
 
            self.fail('Error in config file not detected')
295
 
 
296
 
 
297
 
class TestConfig(tests.TestCase):
 
124
 
 
125
class TestConfig(TestCase):
298
126
 
299
127
    def test_constructs(self):
300
128
        config.Config()
301
 
 
 
129
 
302
130
    def test_no_default_editor(self):
303
131
        self.assertRaises(NotImplementedError, config.Config().get_editor)
304
132
 
315
143
 
316
144
    def test_signatures_default(self):
317
145
        my_config = config.Config()
318
 
        self.assertFalse(my_config.signature_needed())
319
146
        self.assertEqual(config.CHECK_IF_POSSIBLE,
320
147
                         my_config.signature_checking())
321
 
        self.assertEqual(config.SIGN_WHEN_REQUIRED,
322
 
                         my_config.signing_policy())
323
148
 
324
149
    def test_signatures_template_method(self):
325
150
        my_config = InstrumentedConfig()
345
170
        my_config = config.Config()
346
171
        self.assertEqual(None, my_config.post_commit())
347
172
 
348
 
    def test_log_format_default(self):
349
 
        my_config = config.Config()
350
 
        self.assertEqual('long', my_config.log_format())
351
 
 
352
 
    def test_get_change_editor(self):
353
 
        my_config = InstrumentedConfig()
354
 
        change_editor = my_config.get_change_editor('old_tree', 'new_tree')
355
 
        self.assertEqual(['_get_change_editor'], my_config._calls)
356
 
        self.assertIs(diff.DiffFromTool, change_editor.__class__)
357
 
        self.assertEqual(['vimdiff', '-fo', '@new_path', '@old_path'],
358
 
                         change_editor.command_template)
359
 
 
360
 
 
361
 
class TestConfigPath(tests.TestCase):
 
173
 
 
174
class TestConfigPath(TestCase):
362
175
 
363
176
    def setUp(self):
364
177
        super(TestConfigPath, self).setUp()
 
178
        self.old_home = os.environ.get('HOME', None)
 
179
        self.old_appdata = os.environ.get('APPDATA', None)
365
180
        os.environ['HOME'] = '/home/bogus'
366
 
        os.environ['XDG_CACHE_DIR'] = ''
367
 
        if sys.platform == 'win32':
368
 
            os.environ['BZR_HOME'] = \
369
 
                r'C:\Documents and Settings\bogus\Application Data'
370
 
            self.bzr_home = \
371
 
                'C:/Documents and Settings/bogus/Application Data/bazaar/2.0'
372
 
        else:
373
 
            self.bzr_home = '/home/bogus/.bazaar'
 
181
        os.environ['APPDATA'] = \
 
182
            r'C:\Documents and Settings\bogus\Application Data'
374
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
    
375
195
    def test_config_dir(self):
376
 
        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')
377
201
 
378
202
    def test_config_filename(self):
379
 
        self.assertEqual(config.config_filename(),
380
 
                         self.bzr_home + '/bazaar.conf')
381
 
 
382
 
    def test_locations_config_filename(self):
383
 
        self.assertEqual(config.locations_config_filename(),
384
 
                         self.bzr_home + '/locations.conf')
385
 
 
386
 
    def test_authentication_config_filename(self):
387
 
        self.assertEqual(config.authentication_config_filename(),
388
 
                         self.bzr_home + '/authentication.conf')
389
 
 
390
 
    def test_xdg_cache_dir(self):
391
 
        self.assertEqual(config.xdg_cache_dir(),
392
 
            '/home/bogus/.cache')
393
 
 
394
 
 
395
 
class TestIniConfig(tests.TestCaseInTempDir):
396
 
 
397
 
    def make_config_parser(self, s):
398
 
        conf = config.IniBasedConfig.from_string(s)
399
 
        return conf, conf._get_parser()
400
 
 
401
 
 
402
 
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):
403
219
 
404
220
    def test_contructs(self):
405
 
        my_config = config.IniBasedConfig()
 
221
        my_config = config.IniBasedConfig("nothing")
406
222
 
407
223
    def test_from_fp(self):
408
 
        my_config = config.IniBasedConfig.from_string(sample_config_text)
409
 
        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))
410
229
 
411
230
    def test_cached(self):
412
 
        my_config = config.IniBasedConfig.from_string(sample_config_text)
413
 
        parser = my_config._get_parser()
 
231
        config_file = StringIO(sample_config_text)
 
232
        my_config = config.IniBasedConfig(None)
 
233
        parser = my_config._get_parser(file=config_file)
414
234
        self.failUnless(my_config._get_parser() is parser)
415
235
 
416
 
    def _dummy_chown(self, path, uid, gid):
417
 
        self.path, self.uid, self.gid = path, uid, gid
418
 
 
419
 
    def test_ini_config_ownership(self):
420
 
        """Ensure that chown is happening during _write_config_file"""
421
 
        self.requireFeature(features.chown_feature)
422
 
        self.overrideAttr(os, 'chown', self._dummy_chown)
423
 
        self.path = self.uid = self.gid = None
424
 
        conf = config.IniBasedConfig(file_name='./foo.conf')
425
 
        conf._write_config_file()
426
 
        self.assertEquals(self.path, './foo.conf')
427
 
        self.assertTrue(isinstance(self.uid, int))
428
 
        self.assertTrue(isinstance(self.gid, int))
429
 
 
430
 
    def test_get_filename_parameter_is_deprecated_(self):
431
 
        conf = self.callDeprecated([
432
 
            'IniBasedConfig.__init__(get_filename) was deprecated in 2.3.'
433
 
            ' Use file_name instead.'],
434
 
            config.IniBasedConfig, lambda: 'ini.conf')
435
 
        self.assertEqual('ini.conf', conf.file_name)
436
 
 
437
 
    def test_get_parser_file_parameter_is_deprecated_(self):
438
 
        config_file = StringIO(sample_config_text.encode('utf-8'))
439
 
        conf = config.IniBasedConfig.from_string(sample_config_text)
440
 
        conf = self.callDeprecated([
441
 
            'IniBasedConfig._get_parser(file=xxx) was deprecated in 2.3.'
442
 
            ' Use IniBasedConfig(_content=xxx) instead.'],
443
 
            conf._get_parser, file=config_file)
444
 
 
445
 
class TestIniConfigSaving(tests.TestCaseInTempDir):
446
 
 
447
 
    def test_cant_save_without_a_file_name(self):
448
 
        conf = config.IniBasedConfig()
449
 
        self.assertRaises(AssertionError, conf._write_config_file)
450
 
 
451
 
    def test_saved_with_content(self):
452
 
        content = 'foo = bar\n'
453
 
        conf = config.IniBasedConfig.from_string(
454
 
            content, file_name='./test.conf', save=True)
455
 
        self.assertFileEqual(content, 'test.conf')
456
 
 
457
 
 
458
 
class TestIniBaseConfigOnDisk(tests.TestCaseInTempDir):
459
 
 
460
 
    def test_cannot_reload_without_name(self):
461
 
        conf = config.IniBasedConfig.from_string(sample_config_text)
462
 
        self.assertRaises(AssertionError, conf.reload)
463
 
 
464
 
    def test_reload_see_new_value(self):
465
 
        c1 = config.IniBasedConfig.from_string('editor=vim\n',
466
 
                                               file_name='./test/conf')
467
 
        c1._write_config_file()
468
 
        c2 = config.IniBasedConfig.from_string('editor=emacs\n',
469
 
                                               file_name='./test/conf')
470
 
        c2._write_config_file()
471
 
        self.assertEqual('vim', c1.get_user_option('editor'))
472
 
        self.assertEqual('emacs', c2.get_user_option('editor'))
473
 
        # Make sure we get the Right value
474
 
        c1.reload()
475
 
        self.assertEqual('emacs', c1.get_user_option('editor'))
476
 
 
477
 
 
478
 
class TestLockableConfig(tests.TestCaseInTempDir):
479
 
 
480
 
    # Set by load_tests
481
 
    config_class = None
482
 
    config_args = None
483
 
    config_section = None
484
 
 
485
 
    def setUp(self):
486
 
        super(TestLockableConfig, self).setUp()
487
 
        self._content = '[%s]\none=1\ntwo=2\n' % (self.config_section,)
488
 
        self.config = self.create_config(self._content)
489
 
 
490
 
    def get_existing_config(self):
491
 
        return self.config_class(*self.config_args)
492
 
 
493
 
    def create_config(self, content):
494
 
        kwargs = dict(save=True)
495
 
        c = self.config_class.from_string(content, *self.config_args, **kwargs)
496
 
        return c
497
 
 
498
 
    def test_simple_read_access(self):
499
 
        self.assertEquals('1', self.config.get_user_option('one'))
500
 
 
501
 
    def test_simple_write_access(self):
502
 
        self.config.set_user_option('one', 'one')
503
 
        self.assertEquals('one', self.config.get_user_option('one'))
504
 
 
505
 
    def test_listen_to_the_last_speaker(self):
506
 
        c1 = self.config
507
 
        c2 = self.get_existing_config()
508
 
        c1.set_user_option('one', 'ONE')
509
 
        c2.set_user_option('two', 'TWO')
510
 
        self.assertEquals('ONE', c1.get_user_option('one'))
511
 
        self.assertEquals('TWO', c2.get_user_option('two'))
512
 
        # The second update respect the first one
513
 
        self.assertEquals('ONE', c2.get_user_option('one'))
514
 
 
515
 
    def test_last_speaker_wins(self):
516
 
        # If the same config is not shared, the same variable modified twice
517
 
        # can only see a single result.
518
 
        c1 = self.config
519
 
        c2 = self.get_existing_config()
520
 
        c1.set_user_option('one', 'c1')
521
 
        c2.set_user_option('one', 'c2')
522
 
        self.assertEquals('c2', c2._get_user_option('one'))
523
 
        # The first modification is still available until another refresh
524
 
        # occur
525
 
        self.assertEquals('c1', c1._get_user_option('one'))
526
 
        c1.set_user_option('two', 'done')
527
 
        self.assertEquals('c2', c1._get_user_option('one'))
528
 
 
529
 
    def test_writes_are_serialized(self):
530
 
        c1 = self.config
531
 
        c2 = self.get_existing_config()
532
 
 
533
 
        # We spawn a thread that will pause *during* the write
534
 
        before_writing = threading.Event()
535
 
        after_writing = threading.Event()
536
 
        writing_done = threading.Event()
537
 
        c1_orig = c1._write_config_file
538
 
        def c1_write_config_file():
539
 
            before_writing.set()
540
 
            c1_orig()
541
 
            # The lock is held we wait for the main thread to decide when to
542
 
            # continue
543
 
            after_writing.wait()
544
 
        c1._write_config_file = c1_write_config_file
545
 
        def c1_set_option():
546
 
            c1.set_user_option('one', 'c1')
547
 
            writing_done.set()
548
 
        t1 = threading.Thread(target=c1_set_option)
549
 
        # Collect the thread after the test
550
 
        self.addCleanup(t1.join)
551
 
        # Be ready to unblock the thread if the test goes wrong
552
 
        self.addCleanup(after_writing.set)
553
 
        t1.start()
554
 
        before_writing.wait()
555
 
        self.assertTrue(c1._lock.is_held)
556
 
        self.assertRaises(errors.LockContention,
557
 
                          c2.set_user_option, 'one', 'c2')
558
 
        self.assertEquals('c1', c1.get_user_option('one'))
559
 
        # Let the lock be released
560
 
        after_writing.set()
561
 
        writing_done.wait()
562
 
        c2.set_user_option('one', 'c2')
563
 
        self.assertEquals('c2', c2.get_user_option('one'))
564
 
 
565
 
    def test_read_while_writing(self):
566
 
       c1 = self.config
567
 
       # We spawn a thread that will pause *during* the write
568
 
       ready_to_write = threading.Event()
569
 
       do_writing = threading.Event()
570
 
       writing_done = threading.Event()
571
 
       c1_orig = c1._write_config_file
572
 
       def c1_write_config_file():
573
 
           ready_to_write.set()
574
 
           # The lock is held we wait for the main thread to decide when to
575
 
           # continue
576
 
           do_writing.wait()
577
 
           c1_orig()
578
 
           writing_done.set()
579
 
       c1._write_config_file = c1_write_config_file
580
 
       def c1_set_option():
581
 
           c1.set_user_option('one', 'c1')
582
 
       t1 = threading.Thread(target=c1_set_option)
583
 
       # Collect the thread after the test
584
 
       self.addCleanup(t1.join)
585
 
       # Be ready to unblock the thread if the test goes wrong
586
 
       self.addCleanup(do_writing.set)
587
 
       t1.start()
588
 
       # Ensure the thread is ready to write
589
 
       ready_to_write.wait()
590
 
       self.assertTrue(c1._lock.is_held)
591
 
       self.assertEquals('c1', c1.get_user_option('one'))
592
 
       # If we read during the write, we get the old value
593
 
       c2 = self.get_existing_config()
594
 
       self.assertEquals('1', c2.get_user_option('one'))
595
 
       # Let the writing occur and ensure it occurred
596
 
       do_writing.set()
597
 
       writing_done.wait()
598
 
       # Now we get the updated value
599
 
       c3 = self.get_existing_config()
600
 
       self.assertEquals('c1', c3.get_user_option('one'))
601
 
 
602
 
 
603
 
class TestGetUserOptionAs(TestIniConfig):
604
 
 
605
 
    def test_get_user_option_as_bool(self):
606
 
        conf, parser = self.make_config_parser("""
607
 
a_true_bool = true
608
 
a_false_bool = 0
609
 
an_invalid_bool = maybe
610
 
a_list = hmm, who knows ? # This is interpreted as a list !
611
 
""")
612
 
        get_bool = conf.get_user_option_as_bool
613
 
        self.assertEqual(True, get_bool('a_true_bool'))
614
 
        self.assertEqual(False, get_bool('a_false_bool'))
615
 
        warnings = []
616
 
        def warning(*args):
617
 
            warnings.append(args[0] % args[1:])
618
 
        self.overrideAttr(trace, 'warning', warning)
619
 
        msg = 'Value "%s" is not a boolean for "%s"'
620
 
        self.assertIs(None, get_bool('an_invalid_bool'))
621
 
        self.assertEquals(msg % ('maybe', 'an_invalid_bool'), warnings[0])
622
 
        warnings = []
623
 
        self.assertIs(None, get_bool('not_defined_in_this_config'))
624
 
        self.assertEquals([], warnings)
625
 
 
626
 
    def test_get_user_option_as_list(self):
627
 
        conf, parser = self.make_config_parser("""
628
 
a_list = a,b,c
629
 
length_1 = 1,
630
 
one_item = x
631
 
""")
632
 
        get_list = conf.get_user_option_as_list
633
 
        self.assertEqual(['a', 'b', 'c'], get_list('a_list'))
634
 
        self.assertEqual(['1'], get_list('length_1'))
635
 
        self.assertEqual('x', conf.get_user_option('one_item'))
636
 
        # automatically cast to list
637
 
        self.assertEqual(['x'], get_list('one_item'))
638
 
 
639
 
 
640
 
class TestSupressWarning(TestIniConfig):
641
 
 
642
 
    def make_warnings_config(self, s):
643
 
        conf, parser = self.make_config_parser(s)
644
 
        return conf.suppress_warning
645
 
 
646
 
    def test_suppress_warning_unknown(self):
647
 
        suppress_warning = self.make_warnings_config('')
648
 
        self.assertEqual(False, suppress_warning('unknown_warning'))
649
 
 
650
 
    def test_suppress_warning_known(self):
651
 
        suppress_warning = self.make_warnings_config('suppress_warnings=a,b')
652
 
        self.assertEqual(False, suppress_warning('c'))
653
 
        self.assertEqual(True, suppress_warning('a'))
654
 
        self.assertEqual(True, suppress_warning('b'))
655
 
 
656
 
 
657
 
class TestGetConfig(tests.TestCase):
 
236
 
 
237
class TestGetConfig(TestCase):
658
238
 
659
239
    def test_constructs(self):
660
240
        my_config = config.GlobalConfig()
661
241
 
662
242
    def test_calls_read_filenames(self):
663
 
        # replace the class that is constructed, to check its parameters
 
243
        # replace the class that is constructured, to check its parameters
664
244
        oldparserclass = config.ConfigObj
665
245
        config.ConfigObj = InstrumentedConfigObj
666
246
        my_config = config.GlobalConfig()
669
249
        finally:
670
250
            config.ConfigObj = oldparserclass
671
251
        self.failUnless(isinstance(parser, InstrumentedConfigObj))
672
 
        self.assertEqual(parser._calls, [('__init__', config.config_filename(),
673
 
                                          'utf-8')])
674
 
 
675
 
 
676
 
class TestBranchConfig(tests.TestCaseWithTransport):
 
252
        self.assertEqual(parser._calls, [('__init__', config.config_filename())])
 
253
 
 
254
 
 
255
class TestBranchConfig(TestCaseInTempDir):
677
256
 
678
257
    def test_constructs(self):
679
258
        branch = FakeBranch()
687
266
        self.assertEqual(branch.base, location_config.location)
688
267
        self.failUnless(location_config is my_config._get_location_config())
689
268
 
690
 
    def test_get_config(self):
691
 
        """The Branch.get_config method works properly"""
692
 
        b = bzrdir.BzrDir.create_standalone_workingtree('.').branch
693
 
        my_config = b.get_config()
694
 
        self.assertIs(my_config.get_user_option('wacky'), None)
695
 
        my_config.set_user_option('wacky', 'unlikely')
696
 
        self.assertEqual(my_config.get_user_option('wacky'), 'unlikely')
697
 
 
698
 
        # Ensure we get the same thing if we start again
699
 
        b2 = branch.Branch.open('.')
700
 
        my_config2 = b2.get_config()
701
 
        self.assertEqual(my_config2.get_user_option('wacky'), 'unlikely')
702
 
 
703
 
    def test_has_explicit_nickname(self):
704
 
        b = self.make_branch('.')
705
 
        self.assertFalse(b.get_config().has_explicit_nickname())
706
 
        b.nick = 'foo'
707
 
        self.assertTrue(b.get_config().has_explicit_nickname())
708
 
 
709
 
    def test_config_url(self):
710
 
        """The Branch.get_config will use section that uses a local url"""
711
 
        branch = self.make_branch('branch')
712
 
        self.assertEqual('branch', branch.nick)
713
 
 
714
 
        local_url = urlutils.local_path_to_url('branch')
715
 
        conf = config.LocationConfig.from_string(
716
 
            '[%s]\nnickname = foobar' % (local_url,),
717
 
            local_url, save=True)
718
 
        self.assertEqual('foobar', branch.nick)
719
 
 
720
 
    def test_config_local_path(self):
721
 
        """The Branch.get_config will use a local system path"""
722
 
        branch = self.make_branch('branch')
723
 
        self.assertEqual('branch', branch.nick)
724
 
 
725
 
        local_path = osutils.getcwd().encode('utf8')
726
 
        conf = config.LocationConfig.from_string(
727
 
            '[%s/branch]\nnickname = barry' % (local_path,),
728
 
            'branch',  save=True)
729
 
        self.assertEqual('barry', branch.nick)
730
 
 
731
 
    def test_config_creates_local(self):
732
 
        """Creating a new entry in config uses a local path."""
733
 
        branch = self.make_branch('branch', format='knit')
734
 
        branch.set_push_location('http://foobar')
735
 
        local_path = osutils.getcwd().encode('utf8')
736
 
        # Surprisingly ConfigObj doesn't create a trailing newline
737
 
        self.check_file_contents(config.locations_config_filename(),
738
 
                                 '[%s/branch]\n'
739
 
                                 'push_location = http://foobar\n'
740
 
                                 'push_location:policy = norecurse\n'
741
 
                                 % (local_path,))
742
 
 
743
 
    def test_autonick_urlencoded(self):
744
 
        b = self.make_branch('!repo')
745
 
        self.assertEqual('!repo', b.get_config().get_nickname())
746
 
 
747
 
    def test_warn_if_masked(self):
748
 
        warnings = []
749
 
        def warning(*args):
750
 
            warnings.append(args[0] % args[1:])
751
 
        self.overrideAttr(trace, 'warning', warning)
752
 
 
753
 
        def set_option(store, warn_masked=True):
754
 
            warnings[:] = []
755
 
            conf.set_user_option('example_option', repr(store), store=store,
756
 
                                 warn_masked=warn_masked)
757
 
        def assertWarning(warning):
758
 
            if warning is None:
759
 
                self.assertEqual(0, len(warnings))
760
 
            else:
761
 
                self.assertEqual(1, len(warnings))
762
 
                self.assertEqual(warning, warnings[0])
763
 
        branch = self.make_branch('.')
764
 
        conf = branch.get_config()
765
 
        set_option(config.STORE_GLOBAL)
766
 
        assertWarning(None)
767
 
        set_option(config.STORE_BRANCH)
768
 
        assertWarning(None)
769
 
        set_option(config.STORE_GLOBAL)
770
 
        assertWarning('Value "4" is masked by "3" from branch.conf')
771
 
        set_option(config.STORE_GLOBAL, warn_masked=False)
772
 
        assertWarning(None)
773
 
        set_option(config.STORE_LOCATION)
774
 
        assertWarning(None)
775
 
        set_option(config.STORE_BRANCH)
776
 
        assertWarning('Value "3" is masked by "0" from locations.conf')
777
 
        set_option(config.STORE_BRANCH, warn_masked=False)
778
 
        assertWarning(None)
779
 
 
780
 
 
781
 
class TestGlobalConfigItems(tests.TestCaseInTempDir):
 
269
 
 
270
class TestGlobalConfigItems(TestCase):
782
271
 
783
272
    def test_user_id(self):
784
 
        my_config = config.GlobalConfig.from_string(sample_config_text)
785
 
        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>",
786
277
                         my_config._get_user_id())
787
278
 
788
279
    def test_absent_user_id(self):
 
280
        config_file = StringIO("")
789
281
        my_config = config.GlobalConfig()
 
282
        my_config._parser = my_config._get_parser(file=config_file)
790
283
        self.assertEqual(None, my_config._get_user_id())
791
284
 
792
285
    def test_configured_editor(self):
793
 
        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)
794
289
        self.assertEqual("vim", my_config.get_editor())
795
290
 
796
291
    def test_signatures_always(self):
797
 
        my_config = config.GlobalConfig.from_string(sample_always_signatures)
798
 
        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,
799
296
                         my_config.signature_checking())
800
 
        self.assertEqual(config.SIGN_ALWAYS,
801
 
                         my_config.signing_policy())
802
297
        self.assertEqual(True, my_config.signature_needed())
803
298
 
804
299
    def test_signatures_if_possible(self):
805
 
        my_config = config.GlobalConfig.from_string(sample_maybe_signatures)
806
 
        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,
807
304
                         my_config.signature_checking())
808
 
        self.assertEqual(config.SIGN_WHEN_REQUIRED,
809
 
                         my_config.signing_policy())
810
305
        self.assertEqual(False, my_config.signature_needed())
811
306
 
812
307
    def test_signatures_ignore(self):
813
 
        my_config = config.GlobalConfig.from_string(sample_ignore_signatures)
814
 
        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,
815
312
                         my_config.signature_checking())
816
 
        self.assertEqual(config.SIGN_NEVER,
817
 
                         my_config.signing_policy())
818
313
        self.assertEqual(False, my_config.signature_needed())
819
314
 
820
315
    def _get_sample_config(self):
821
 
        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)
822
319
        return my_config
823
320
 
824
321
    def test_gpg_signing_command(self):
827
324
        self.assertEqual(False, my_config.signature_needed())
828
325
 
829
326
    def _get_empty_config(self):
 
327
        config_file = StringIO("")
830
328
        my_config = config.GlobalConfig()
 
329
        my_config._parser = my_config._get_parser(file=config_file)
831
330
        return my_config
832
331
 
833
332
    def test_gpg_signing_command_unset(self):
842
341
        my_config = self._get_sample_config()
843
342
        self.assertEqual("something",
844
343
                         my_config.get_user_option('user_global_option'))
845
 
 
 
344
        
846
345
    def test_post_commit_default(self):
847
346
        my_config = self._get_sample_config()
848
347
        self.assertEqual(None, my_config.post_commit())
849
348
 
850
 
    def test_configured_logformat(self):
851
 
        my_config = self._get_sample_config()
852
 
        self.assertEqual("short", my_config.log_format())
853
 
 
854
 
    def test_get_alias(self):
855
 
        my_config = self._get_sample_config()
856
 
        self.assertEqual('help', my_config.get_alias('h'))
857
 
 
858
 
    def test_get_aliases(self):
859
 
        my_config = self._get_sample_config()
860
 
        aliases = my_config.get_aliases()
861
 
        self.assertEqual(2, len(aliases))
862
 
        sorted_keys = sorted(aliases)
863
 
        self.assertEqual('help', aliases[sorted_keys[0]])
864
 
        self.assertEqual(sample_long_alias, aliases[sorted_keys[1]])
865
 
 
866
 
    def test_get_no_alias(self):
867
 
        my_config = self._get_sample_config()
868
 
        self.assertEqual(None, my_config.get_alias('foo'))
869
 
 
870
 
    def test_get_long_alias(self):
871
 
        my_config = self._get_sample_config()
872
 
        self.assertEqual(sample_long_alias, my_config.get_alias('ll'))
873
 
 
874
 
    def test_get_change_editor(self):
875
 
        my_config = self._get_sample_config()
876
 
        change_editor = my_config.get_change_editor('old', 'new')
877
 
        self.assertIs(diff.DiffFromTool, change_editor.__class__)
878
 
        self.assertEqual('vimdiff -of @new_path @old_path',
879
 
                         ' '.join(change_editor.command_template))
880
 
 
881
 
    def test_get_no_change_editor(self):
882
 
        my_config = self._get_empty_config()
883
 
        change_editor = my_config.get_change_editor('old', 'new')
884
 
        self.assertIs(None, change_editor)
885
 
 
886
 
 
887
 
class TestGlobalConfigSavingOptions(tests.TestCaseInTempDir):
888
 
 
889
 
    def test_empty(self):
890
 
        my_config = config.GlobalConfig()
891
 
        self.assertEqual(0, len(my_config.get_aliases()))
892
 
 
893
 
    def test_set_alias(self):
894
 
        my_config = config.GlobalConfig()
895
 
        alias_value = 'commit --strict'
896
 
        my_config.set_alias('commit', alias_value)
897
 
        new_config = config.GlobalConfig()
898
 
        self.assertEqual(alias_value, new_config.get_alias('commit'))
899
 
 
900
 
    def test_remove_alias(self):
901
 
        my_config = config.GlobalConfig()
902
 
        my_config.set_alias('commit', 'commit --strict')
903
 
        # Now remove the alias again.
904
 
        my_config.unset_alias('commit')
905
 
        new_config = config.GlobalConfig()
906
 
        self.assertIs(None, new_config.get_alias('commit'))
907
 
 
908
 
 
909
 
class TestLocationConfig(tests.TestCaseInTempDir):
 
349
 
 
350
class TestLocationConfig(TestCase):
910
351
 
911
352
    def test_constructs(self):
912
353
        my_config = config.LocationConfig('http://example.com')
916
357
        # This is testing the correct file names are provided.
917
358
        # TODO: consolidate with the test for GlobalConfigs filename checks.
918
359
        #
919
 
        # replace the class that is constructed, to check its parameters
 
360
        # replace the class that is constructured, to check its parameters
920
361
        oldparserclass = config.ConfigObj
921
362
        config.ConfigObj = InstrumentedConfigObj
 
363
        my_config = config.LocationConfig('http://www.example.com')
922
364
        try:
923
 
            my_config = config.LocationConfig('http://www.example.com')
924
365
            parser = my_config._get_parser()
925
366
        finally:
926
367
            config.ConfigObj = oldparserclass
927
368
        self.failUnless(isinstance(parser, InstrumentedConfigObj))
928
369
        self.assertEqual(parser._calls,
929
 
                         [('__init__', config.locations_config_filename(),
930
 
                           'utf-8')])
 
370
                         [('__init__', config.branches_config_filename())])
931
371
 
932
372
    def test_get_global_config(self):
933
 
        my_config = config.BranchConfig(FakeBranch('http://example.com'))
 
373
        my_config = config.LocationConfig('http://example.com')
934
374
        global_config = my_config._get_global_config()
935
375
        self.failUnless(isinstance(global_config, config.GlobalConfig))
936
376
        self.failUnless(global_config is my_config._get_global_config())
937
377
 
938
 
    def test__get_matching_sections_no_match(self):
939
 
        self.get_branch_config('/')
940
 
        self.assertEqual([], self.my_location_config._get_matching_sections())
941
 
 
942
 
    def test__get_matching_sections_exact(self):
943
 
        self.get_branch_config('http://www.example.com')
944
 
        self.assertEqual([('http://www.example.com', '')],
945
 
                         self.my_location_config._get_matching_sections())
946
 
 
947
 
    def test__get_matching_sections_suffix_does_not(self):
948
 
        self.get_branch_config('http://www.example.com-com')
949
 
        self.assertEqual([], self.my_location_config._get_matching_sections())
950
 
 
951
 
    def test__get_matching_sections_subdir_recursive(self):
952
 
        self.get_branch_config('http://www.example.com/com')
953
 
        self.assertEqual([('http://www.example.com', 'com')],
954
 
                         self.my_location_config._get_matching_sections())
955
 
 
956
 
    def test__get_matching_sections_ignoreparent(self):
957
 
        self.get_branch_config('http://www.example.com/ignoreparent')
958
 
        self.assertEqual([('http://www.example.com/ignoreparent', '')],
959
 
                         self.my_location_config._get_matching_sections())
960
 
 
961
 
    def test__get_matching_sections_ignoreparent_subdir(self):
962
 
        self.get_branch_config(
963
 
            'http://www.example.com/ignoreparent/childbranch')
964
 
        self.assertEqual([('http://www.example.com/ignoreparent',
965
 
                           'childbranch')],
966
 
                         self.my_location_config._get_matching_sections())
967
 
 
968
 
    def test__get_matching_sections_subdir_trailing_slash(self):
969
 
        self.get_branch_config('/b')
970
 
        self.assertEqual([('/b/', '')],
971
 
                         self.my_location_config._get_matching_sections())
972
 
 
973
 
    def test__get_matching_sections_subdir_child(self):
974
 
        self.get_branch_config('/a/foo')
975
 
        self.assertEqual([('/a/*', ''), ('/a/', 'foo')],
976
 
                         self.my_location_config._get_matching_sections())
977
 
 
978
 
    def test__get_matching_sections_subdir_child_child(self):
979
 
        self.get_branch_config('/a/foo/bar')
980
 
        self.assertEqual([('/a/*', 'bar'), ('/a/', 'foo/bar')],
981
 
                         self.my_location_config._get_matching_sections())
982
 
 
983
 
    def test__get_matching_sections_trailing_slash_with_children(self):
984
 
        self.get_branch_config('/a/')
985
 
        self.assertEqual([('/a/', '')],
986
 
                         self.my_location_config._get_matching_sections())
987
 
 
988
 
    def test__get_matching_sections_explicit_over_glob(self):
989
 
        # XXX: 2006-09-08 jamesh
990
 
        # This test only passes because ord('c') > ord('*').  If there
991
 
        # was a config section for '/a/?', it would get precedence
992
 
        # over '/a/c'.
993
 
        self.get_branch_config('/a/c')
994
 
        self.assertEqual([('/a/c', ''), ('/a/*', ''), ('/a/', 'c')],
995
 
                         self.my_location_config._get_matching_sections())
996
 
 
997
 
    def test__get_option_policy_normal(self):
998
 
        self.get_branch_config('http://www.example.com')
999
 
        self.assertEqual(
1000
 
            self.my_location_config._get_config_policy(
1001
 
            'http://www.example.com', 'normal_option'),
1002
 
            config.POLICY_NONE)
1003
 
 
1004
 
    def test__get_option_policy_norecurse(self):
1005
 
        self.get_branch_config('http://www.example.com')
1006
 
        self.assertEqual(
1007
 
            self.my_location_config._get_option_policy(
1008
 
            'http://www.example.com', 'norecurse_option'),
1009
 
            config.POLICY_NORECURSE)
1010
 
        # Test old recurse=False setting:
1011
 
        self.assertEqual(
1012
 
            self.my_location_config._get_option_policy(
1013
 
            'http://www.example.com/norecurse', 'normal_option'),
1014
 
            config.POLICY_NORECURSE)
1015
 
 
1016
 
    def test__get_option_policy_normal(self):
1017
 
        self.get_branch_config('http://www.example.com')
1018
 
        self.assertEqual(
1019
 
            self.my_location_config._get_option_policy(
1020
 
            'http://www.example.com', 'appendpath_option'),
1021
 
            config.POLICY_APPENDPATH)
 
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)
1022
436
 
1023
437
    def test_location_without_username(self):
1024
 
        self.get_branch_config('http://www.example.com/ignoreparent')
1025
 
        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>',
1026
440
                         self.my_config.username())
1027
441
 
1028
442
    def test_location_not_listed(self):
1029
 
        """Test that the global username is used when no location matches"""
1030
 
        self.get_branch_config('/home/robertc/sources')
1031
 
        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>',
1032
445
                         self.my_config.username())
1033
446
 
1034
447
    def test_overriding_location(self):
1035
 
        self.get_branch_config('http://www.example.com/foo')
 
448
        self.get_location_config('http://www.example.com/foo')
1036
449
        self.assertEqual('Robert Collins <robertc@example.org>',
1037
450
                         self.my_config.username())
1038
451
 
1039
452
    def test_signatures_not_set(self):
1040
 
        self.get_branch_config('http://www.example.com',
 
453
        self.get_location_config('http://www.example.com',
1041
454
                                 global_config=sample_ignore_signatures)
1042
 
        self.assertEqual(config.CHECK_ALWAYS,
 
455
        self.assertEqual(config.CHECK_NEVER,
1043
456
                         self.my_config.signature_checking())
1044
 
        self.assertEqual(config.SIGN_NEVER,
1045
 
                         self.my_config.signing_policy())
1046
457
 
1047
458
    def test_signatures_never(self):
1048
 
        self.get_branch_config('/a/c')
 
459
        self.get_location_config('/a/c')
1049
460
        self.assertEqual(config.CHECK_NEVER,
1050
461
                         self.my_config.signature_checking())
1051
 
 
 
462
        
1052
463
    def test_signatures_when_available(self):
1053
 
        self.get_branch_config('/a/', global_config=sample_ignore_signatures)
 
464
        self.get_location_config('/a/', global_config=sample_ignore_signatures)
1054
465
        self.assertEqual(config.CHECK_IF_POSSIBLE,
1055
466
                         self.my_config.signature_checking())
1056
 
 
 
467
        
1057
468
    def test_signatures_always(self):
1058
 
        self.get_branch_config('/b')
 
469
        self.get_location_config('/b')
1059
470
        self.assertEqual(config.CHECK_ALWAYS,
1060
471
                         self.my_config.signature_checking())
1061
 
 
 
472
        
1062
473
    def test_gpg_signing_command(self):
1063
 
        self.get_branch_config('/b')
 
474
        self.get_location_config('/b')
1064
475
        self.assertEqual("gnome-gpg", self.my_config.gpg_signing_command())
1065
476
 
1066
477
    def test_gpg_signing_command_missing(self):
1067
 
        self.get_branch_config('/a')
 
478
        self.get_location_config('/a')
1068
479
        self.assertEqual("false", self.my_config.gpg_signing_command())
1069
480
 
1070
481
    def test_get_user_option_global(self):
1071
 
        self.get_branch_config('/a')
 
482
        self.get_location_config('/a')
1072
483
        self.assertEqual('something',
1073
484
                         self.my_config.get_user_option('user_global_option'))
1074
485
 
1075
486
    def test_get_user_option_local(self):
1076
 
        self.get_branch_config('/a')
 
487
        self.get_location_config('/a')
1077
488
        self.assertEqual('local',
1078
489
                         self.my_config.get_user_option('user_local_option'))
1079
 
 
1080
 
    def test_get_user_option_appendpath(self):
1081
 
        # returned as is for the base path:
1082
 
        self.get_branch_config('http://www.example.com')
1083
 
        self.assertEqual('append',
1084
 
                         self.my_config.get_user_option('appendpath_option'))
1085
 
        # Extra path components get appended:
1086
 
        self.get_branch_config('http://www.example.com/a/b/c')
1087
 
        self.assertEqual('append/a/b/c',
1088
 
                         self.my_config.get_user_option('appendpath_option'))
1089
 
        # Overriden for http://www.example.com/dir, where it is a
1090
 
        # normal option:
1091
 
        self.get_branch_config('http://www.example.com/dir/a/b/c')
1092
 
        self.assertEqual('normal',
1093
 
                         self.my_config.get_user_option('appendpath_option'))
1094
 
 
1095
 
    def test_get_user_option_norecurse(self):
1096
 
        self.get_branch_config('http://www.example.com')
1097
 
        self.assertEqual('norecurse',
1098
 
                         self.my_config.get_user_option('norecurse_option'))
1099
 
        self.get_branch_config('http://www.example.com/dir')
1100
 
        self.assertEqual(None,
1101
 
                         self.my_config.get_user_option('norecurse_option'))
1102
 
        # http://www.example.com/norecurse is a recurse=False section
1103
 
        # that redefines normal_option.  Subdirectories do not pick up
1104
 
        # this redefinition.
1105
 
        self.get_branch_config('http://www.example.com/norecurse')
1106
 
        self.assertEqual('norecurse',
1107
 
                         self.my_config.get_user_option('normal_option'))
1108
 
        self.get_branch_config('http://www.example.com/norecurse/subdir')
1109
 
        self.assertEqual('normal',
1110
 
                         self.my_config.get_user_option('normal_option'))
1111
 
 
1112
 
    def test_set_user_option_norecurse(self):
1113
 
        self.get_branch_config('http://www.example.com')
1114
 
        self.my_config.set_user_option('foo', 'bar',
1115
 
                                       store=config.STORE_LOCATION_NORECURSE)
1116
 
        self.assertEqual(
1117
 
            self.my_location_config._get_option_policy(
1118
 
            'http://www.example.com', 'foo'),
1119
 
            config.POLICY_NORECURSE)
1120
 
 
1121
 
    def test_set_user_option_appendpath(self):
1122
 
        self.get_branch_config('http://www.example.com')
1123
 
        self.my_config.set_user_option('foo', 'bar',
1124
 
                                       store=config.STORE_LOCATION_APPENDPATH)
1125
 
        self.assertEqual(
1126
 
            self.my_location_config._get_option_policy(
1127
 
            'http://www.example.com', 'foo'),
1128
 
            config.POLICY_APPENDPATH)
1129
 
 
1130
 
    def test_set_user_option_change_policy(self):
1131
 
        self.get_branch_config('http://www.example.com')
1132
 
        self.my_config.set_user_option('norecurse_option', 'normal',
1133
 
                                       store=config.STORE_LOCATION)
1134
 
        self.assertEqual(
1135
 
            self.my_location_config._get_option_policy(
1136
 
            'http://www.example.com', 'norecurse_option'),
1137
 
            config.POLICY_NONE)
1138
 
 
1139
 
    def test_set_user_option_recurse_false_section(self):
1140
 
        # The following section has recurse=False set.  The test is to
1141
 
        # make sure that a normal option can be added to the section,
1142
 
        # converting recurse=False to the norecurse policy.
1143
 
        self.get_branch_config('http://www.example.com/norecurse')
1144
 
        self.callDeprecated(['The recurse option is deprecated as of 0.14.  '
1145
 
                             'The section "http://www.example.com/norecurse" '
1146
 
                             'has been converted to use policies.'],
1147
 
                            self.my_config.set_user_option,
1148
 
                            'foo', 'bar', store=config.STORE_LOCATION)
1149
 
        self.assertEqual(
1150
 
            self.my_location_config._get_option_policy(
1151
 
            'http://www.example.com/norecurse', 'foo'),
1152
 
            config.POLICY_NONE)
1153
 
        # The previously existing option is still norecurse:
1154
 
        self.assertEqual(
1155
 
            self.my_location_config._get_option_policy(
1156
 
            'http://www.example.com/norecurse', 'normal_option'),
1157
 
            config.POLICY_NORECURSE)
1158
 
 
 
490
        
1159
491
    def test_post_commit_default(self):
1160
 
        self.get_branch_config('/a/c')
 
492
        self.get_location_config('/a/c')
1161
493
        self.assertEqual('bzrlib.tests.test_config.post_commit',
1162
494
                         self.my_config.post_commit())
1163
495
 
1164
 
    def get_branch_config(self, location, global_config=None):
1165
 
        my_branch = FakeBranch(location)
 
496
 
 
497
class TestLocationConfig(TestCaseInTempDir):
 
498
 
 
499
    def get_location_config(self, location, global_config=None):
1166
500
        if global_config is None:
1167
 
            global_config = sample_config_text
1168
 
 
1169
 
        my_global_config = config.GlobalConfig.from_string(global_config,
1170
 
                                                           save=True)
1171
 
        my_location_config = config.LocationConfig.from_string(
1172
 
            sample_branches_text, my_branch.base, save=True)
1173
 
        my_config = config.BranchConfig(my_branch)
1174
 
        self.my_config = my_config
1175
 
        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)
1176
508
 
1177
509
    def test_set_user_setting_sets_and_saves(self):
1178
 
        self.get_branch_config('/a/c')
 
510
        # TODO RBC 20051029 test hat mkdir ~/.bazaar is called ..
 
511
        self.get_location_config('/a/c')
1179
512
        record = InstrumentedConfigObj("foo")
1180
 
        self.my_location_config._parser = record
1181
 
 
1182
 
        self.callDeprecated(['The recurse option is deprecated as of '
1183
 
                             '0.14.  The section "/a/c" has been '
1184
 
                             'converted to use policies.'],
1185
 
                            self.my_config.set_user_option,
1186
 
                            'foo', 'bar', store=config.STORE_LOCATION)
1187
 
        self.assertEqual([('reload',),
1188
 
                          ('__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'),
1189
519
                          ('__contains__', '/a/c/'),
1190
520
                          ('__setitem__', '/a/c', {}),
1191
521
                          ('__getitem__', '/a/c'),
1192
522
                          ('__setitem__', 'foo', 'bar'),
1193
 
                          ('__getitem__', '/a/c'),
1194
 
                          ('as_bool', 'recurse'),
1195
 
                          ('__getitem__', '/a/c'),
1196
 
                          ('__delitem__', 'recurse'),
1197
 
                          ('__getitem__', '/a/c'),
1198
 
                          ('keys',),
1199
 
                          ('__getitem__', '/a/c'),
1200
 
                          ('__contains__', 'foo:policy'),
1201
523
                          ('write',)],
1202
524
                         record._calls[1:])
1203
525
 
1204
 
    def test_set_user_setting_sets_and_saves2(self):
1205
 
        self.get_branch_config('/a/c')
1206
 
        self.assertIs(self.my_config.get_user_option('foo'), None)
1207
 
        self.my_config.set_user_option('foo', 'bar')
1208
 
        self.assertEqual(
1209
 
            self.my_config.branch.control_files.files['branch.conf'].strip(),
1210
 
            'foo = bar')
1211
 
        self.assertEqual(self.my_config.get_user_option('foo'), 'bar')
1212
 
        self.my_config.set_user_option('foo', 'baz',
1213
 
                                       store=config.STORE_LOCATION)
1214
 
        self.assertEqual(self.my_config.get_user_option('foo'), 'baz')
1215
 
        self.my_config.set_user_option('foo', 'qux')
1216
 
        self.assertEqual(self.my_config.get_user_option('foo'), 'baz')
1217
 
 
1218
 
    def test_get_bzr_remote_path(self):
1219
 
        my_config = config.LocationConfig('/a/c')
1220
 
        self.assertEqual('bzr', my_config.get_bzr_remote_path())
1221
 
        my_config.set_user_option('bzr_remote_path', '/path-bzr')
1222
 
        self.assertEqual('/path-bzr', my_config.get_bzr_remote_path())
1223
 
        os.environ['BZR_REMOTE_PATH'] = '/environ-bzr'
1224
 
        self.assertEqual('/environ-bzr', my_config.get_bzr_remote_path())
1225
 
 
1226
 
 
1227
 
precedence_global = 'option = global'
1228
 
precedence_branch = 'option = branch'
1229
 
precedence_location = """
1230
 
[http://]
1231
 
recurse = true
1232
 
option = recurse
1233
 
[http://example.com/specific]
1234
 
option = exact
1235
 
"""
1236
 
 
1237
 
class TestBranchConfigItems(tests.TestCaseInTempDir):
1238
 
 
1239
 
    def get_branch_config(self, global_config=None, location=None,
1240
 
                          location_config=None, branch_data_config=None):
1241
 
        my_branch = FakeBranch(location)
1242
 
        if global_config is not None:
1243
 
            my_global_config = config.GlobalConfig.from_string(global_config,
1244
 
                                                               save=True)
1245
 
        if location_config is not None:
1246
 
            my_location_config = config.LocationConfig.from_string(
1247
 
                location_config, my_branch.base, save=True)
1248
 
        my_config = config.BranchConfig(my_branch)
1249
 
        if branch_data_config is not None:
1250
 
            my_config.branch.control_files.files['branch.conf'] = \
1251
 
                branch_data_config
1252
 
        return my_config
 
526
 
 
527
class TestBranchConfigItems(TestCase):
1253
528
 
1254
529
    def test_user_id(self):
1255
 
        branch = FakeBranch(user_id='Robert Collins <robertc@example.net>')
 
530
        branch = FakeBranch()
1256
531
        my_config = config.BranchConfig(branch)
1257
532
        self.assertEqual("Robert Collins <robertc@example.net>",
1258
 
                         my_config.username())
1259
 
        my_config.branch.control_files.files['email'] = "John"
1260
 
        my_config.set_user_option('email',
1261
 
                                  "Robert Collins <robertc@example.org>")
1262
 
        self.assertEqual("John", my_config.username())
1263
 
        del my_config.branch.control_files.files['email']
1264
 
        self.assertEqual("Robert Collins <robertc@example.org>",
1265
 
                         my_config.username())
 
533
                         my_config._get_user_id())
 
534
        branch.email = "John"
 
535
        self.assertEqual("John", my_config._get_user_id())
1266
536
 
1267
537
    def test_not_set_in_branch(self):
1268
 
        my_config = self.get_branch_config(global_config=sample_config_text)
1269
 
        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>",
1270
545
                         my_config._get_user_id())
1271
 
        my_config.branch.control_files.files['email'] = "John"
 
546
        branch.email = "John"
1272
547
        self.assertEqual("John", my_config._get_user_id())
1273
548
 
1274
 
    def test_BZR_EMAIL_OVERRIDES(self):
1275
 
        os.environ['BZR_EMAIL'] = "Robert Collins <robertc@example.org>"
 
549
    def test_BZREMAIL_OVERRIDES(self):
 
550
        os.environ['BZREMAIL'] = "Robert Collins <robertc@example.org>"
1276
551
        branch = FakeBranch()
1277
552
        my_config = config.BranchConfig(branch)
1278
553
        self.assertEqual("Robert Collins <robertc@example.org>",
1279
554
                         my_config.username())
1280
 
 
 
555
    
1281
556
    def test_signatures_forced(self):
1282
 
        my_config = self.get_branch_config(
1283
 
            global_config=sample_always_signatures)
1284
 
        self.assertEqual(config.CHECK_NEVER, my_config.signature_checking())
1285
 
        self.assertEqual(config.SIGN_ALWAYS, my_config.signing_policy())
1286
 
        self.assertTrue(my_config.signature_needed())
1287
 
 
1288
 
    def test_signatures_forced_branch(self):
1289
 
        my_config = self.get_branch_config(
1290
 
            global_config=sample_ignore_signatures,
1291
 
            branch_data_config=sample_always_signatures)
1292
 
        self.assertEqual(config.CHECK_NEVER, my_config.signature_checking())
1293
 
        self.assertEqual(config.SIGN_ALWAYS, my_config.signing_policy())
1294
 
        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())
1295
563
 
1296
564
    def test_gpg_signing_command(self):
1297
 
        my_config = self.get_branch_config(
1298
 
            global_config=sample_config_text,
1299
 
            # branch data cannot set gpg_signing_command
1300
 
            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))
1301
570
        self.assertEqual('gnome-gpg', my_config.gpg_signing_command())
1302
571
 
1303
572
    def test_get_user_option_global(self):
1304
 
        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))
1305
578
        self.assertEqual('something',
1306
579
                         my_config.get_user_option('user_global_option'))
1307
580
 
1308
581
    def test_post_commit_default(self):
1309
 
        my_config = self.get_branch_config(global_config=sample_config_text,
1310
 
                                      location='/a/c',
1311
 
                                      location_config=sample_branches_text)
1312
 
        self.assertEqual(my_config.branch.base, '/a/c')
1313
 
        self.assertEqual('bzrlib.tests.test_config.post_commit',
1314
 
                         my_config.post_commit())
1315
 
        my_config.set_user_option('post_commit', 'rmtree_root')
1316
 
        # post-commit is ignored when present in branch data
1317
 
        self.assertEqual('bzrlib.tests.test_config.post_commit',
1318
 
                         my_config.post_commit())
1319
 
        my_config.set_user_option('post_commit', 'rmtree_root',
1320
 
                                  store=config.STORE_LOCATION)
1321
 
        self.assertEqual('rmtree_root', my_config.post_commit())
1322
 
 
1323
 
    def test_config_precedence(self):
1324
 
        # FIXME: eager test, luckily no persitent config file makes it fail
1325
 
        # -- vila 20100716
1326
 
        my_config = self.get_branch_config(global_config=precedence_global)
1327
 
        self.assertEqual(my_config.get_user_option('option'), 'global')
1328
 
        my_config = self.get_branch_config(global_config=precedence_global,
1329
 
                                           branch_data_config=precedence_branch)
1330
 
        self.assertEqual(my_config.get_user_option('option'), 'branch')
1331
 
        my_config = self.get_branch_config(
1332
 
            global_config=precedence_global,
1333
 
            branch_data_config=precedence_branch,
1334
 
            location_config=precedence_location)
1335
 
        self.assertEqual(my_config.get_user_option('option'), 'recurse')
1336
 
        my_config = self.get_branch_config(
1337
 
            global_config=precedence_global,
1338
 
            branch_data_config=precedence_branch,
1339
 
            location_config=precedence_location,
1340
 
            location='http://example.com/specific')
1341
 
        self.assertEqual(my_config.get_user_option('option'), 'exact')
1342
 
 
1343
 
    def test_get_mail_client(self):
1344
 
        config = self.get_branch_config()
1345
 
        client = config.get_mail_client()
1346
 
        self.assertIsInstance(client, mail_client.DefaultMail)
1347
 
 
1348
 
        # Specific clients
1349
 
        config.set_user_option('mail_client', 'evolution')
1350
 
        client = config.get_mail_client()
1351
 
        self.assertIsInstance(client, mail_client.Evolution)
1352
 
 
1353
 
        config.set_user_option('mail_client', 'kmail')
1354
 
        client = config.get_mail_client()
1355
 
        self.assertIsInstance(client, mail_client.KMail)
1356
 
 
1357
 
        config.set_user_option('mail_client', 'mutt')
1358
 
        client = config.get_mail_client()
1359
 
        self.assertIsInstance(client, mail_client.Mutt)
1360
 
 
1361
 
        config.set_user_option('mail_client', 'thunderbird')
1362
 
        client = config.get_mail_client()
1363
 
        self.assertIsInstance(client, mail_client.Thunderbird)
1364
 
 
1365
 
        # Generic options
1366
 
        config.set_user_option('mail_client', 'default')
1367
 
        client = config.get_mail_client()
1368
 
        self.assertIsInstance(client, mail_client.DefaultMail)
1369
 
 
1370
 
        config.set_user_option('mail_client', 'editor')
1371
 
        client = config.get_mail_client()
1372
 
        self.assertIsInstance(client, mail_client.Editor)
1373
 
 
1374
 
        config.set_user_option('mail_client', 'mapi')
1375
 
        client = config.get_mail_client()
1376
 
        self.assertIsInstance(client, mail_client.MAPIClient)
1377
 
 
1378
 
        config.set_user_option('mail_client', 'xdg-email')
1379
 
        client = config.get_mail_client()
1380
 
        self.assertIsInstance(client, mail_client.XDGEmail)
1381
 
 
1382
 
        config.set_user_option('mail_client', 'firebird')
1383
 
        self.assertRaises(errors.UnknownMailClient, config.get_mail_client)
1384
 
 
1385
 
 
1386
 
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):
1387
595
 
1388
596
    def test_extract_email_address(self):
1389
597
        self.assertEqual('jane@test.com',
1390
598
                         config.extract_email_address('Jane <jane@test.com>'))
1391
 
        self.assertRaises(errors.NoEmailInUsername,
 
599
        self.assertRaises(errors.BzrError,
1392
600
                          config.extract_email_address, 'Jane Tester')
1393
 
 
1394
 
    def test_parse_username(self):
1395
 
        self.assertEqual(('', 'jdoe@example.com'),
1396
 
                         config.parse_username('jdoe@example.com'))
1397
 
        self.assertEqual(('', 'jdoe@example.com'),
1398
 
                         config.parse_username('<jdoe@example.com>'))
1399
 
        self.assertEqual(('John Doe', 'jdoe@example.com'),
1400
 
                         config.parse_username('John Doe <jdoe@example.com>'))
1401
 
        self.assertEqual(('John Doe', ''),
1402
 
                         config.parse_username('John Doe'))
1403
 
        self.assertEqual(('John Doe', 'jdoe@example.com'),
1404
 
                         config.parse_username('John Doe jdoe@example.com'))
1405
 
 
1406
 
class TestTreeConfig(tests.TestCaseWithTransport):
1407
 
 
1408
 
    def test_get_value(self):
1409
 
        """Test that retreiving a value from a section is possible"""
1410
 
        branch = self.make_branch('.')
1411
 
        tree_config = config.TreeConfig(branch)
1412
 
        tree_config.set_option('value', 'key', 'SECTION')
1413
 
        tree_config.set_option('value2', 'key2')
1414
 
        tree_config.set_option('value3-top', 'key3')
1415
 
        tree_config.set_option('value3-section', 'key3', 'SECTION')
1416
 
        value = tree_config.get_option('key', 'SECTION')
1417
 
        self.assertEqual(value, 'value')
1418
 
        value = tree_config.get_option('key2')
1419
 
        self.assertEqual(value, 'value2')
1420
 
        self.assertEqual(tree_config.get_option('non-existant'), None)
1421
 
        value = tree_config.get_option('non-existant', 'SECTION')
1422
 
        self.assertEqual(value, None)
1423
 
        value = tree_config.get_option('non-existant', default='default')
1424
 
        self.assertEqual(value, 'default')
1425
 
        self.assertEqual(tree_config.get_option('key2', 'NOSECTION'), None)
1426
 
        value = tree_config.get_option('key2', 'NOSECTION', default='default')
1427
 
        self.assertEqual(value, 'default')
1428
 
        value = tree_config.get_option('key3')
1429
 
        self.assertEqual(value, 'value3-top')
1430
 
        value = tree_config.get_option('key3', 'SECTION')
1431
 
        self.assertEqual(value, 'value3-section')
1432
 
 
1433
 
 
1434
 
class TestTransportConfig(tests.TestCaseWithTransport):
1435
 
 
1436
 
    def test_get_value(self):
1437
 
        """Test that retreiving a value from a section is possible"""
1438
 
        bzrdir_config = config.TransportConfig(transport.get_transport('.'),
1439
 
                                               'control.conf')
1440
 
        bzrdir_config.set_option('value', 'key', 'SECTION')
1441
 
        bzrdir_config.set_option('value2', 'key2')
1442
 
        bzrdir_config.set_option('value3-top', 'key3')
1443
 
        bzrdir_config.set_option('value3-section', 'key3', 'SECTION')
1444
 
        value = bzrdir_config.get_option('key', 'SECTION')
1445
 
        self.assertEqual(value, 'value')
1446
 
        value = bzrdir_config.get_option('key2')
1447
 
        self.assertEqual(value, 'value2')
1448
 
        self.assertEqual(bzrdir_config.get_option('non-existant'), None)
1449
 
        value = bzrdir_config.get_option('non-existant', 'SECTION')
1450
 
        self.assertEqual(value, None)
1451
 
        value = bzrdir_config.get_option('non-existant', default='default')
1452
 
        self.assertEqual(value, 'default')
1453
 
        self.assertEqual(bzrdir_config.get_option('key2', 'NOSECTION'), None)
1454
 
        value = bzrdir_config.get_option('key2', 'NOSECTION',
1455
 
                                         default='default')
1456
 
        self.assertEqual(value, 'default')
1457
 
        value = bzrdir_config.get_option('key3')
1458
 
        self.assertEqual(value, 'value3-top')
1459
 
        value = bzrdir_config.get_option('key3', 'SECTION')
1460
 
        self.assertEqual(value, 'value3-section')
1461
 
 
1462
 
    def test_set_unset_default_stack_on(self):
1463
 
        my_dir = self.make_bzrdir('.')
1464
 
        bzrdir_config = config.BzrDirConfig(my_dir)
1465
 
        self.assertIs(None, bzrdir_config.get_default_stack_on())
1466
 
        bzrdir_config.set_default_stack_on('Foo')
1467
 
        self.assertEqual('Foo', bzrdir_config._config.get_option(
1468
 
                         'default_stack_on'))
1469
 
        self.assertEqual('Foo', bzrdir_config.get_default_stack_on())
1470
 
        bzrdir_config.set_default_stack_on(None)
1471
 
        self.assertIs(None, bzrdir_config.get_default_stack_on())
1472
 
 
1473
 
 
1474
 
class TestAuthenticationConfigFile(tests.TestCase):
1475
 
    """Test the authentication.conf file matching"""
1476
 
 
1477
 
    def _got_user_passwd(self, expected_user, expected_password,
1478
 
                         config, *args, **kwargs):
1479
 
        credentials = config.get_credentials(*args, **kwargs)
1480
 
        if credentials is None:
1481
 
            user = None
1482
 
            password = None
1483
 
        else:
1484
 
            user = credentials['user']
1485
 
            password = credentials['password']
1486
 
        self.assertEquals(expected_user, user)
1487
 
        self.assertEquals(expected_password, password)
1488
 
 
1489
 
    def test_empty_config(self):
1490
 
        conf = config.AuthenticationConfig(_file=StringIO())
1491
 
        self.assertEquals({}, conf._get_config())
1492
 
        self._got_user_passwd(None, None, conf, 'http', 'foo.net')
1493
 
 
1494
 
    def test_missing_auth_section_header(self):
1495
 
        conf = config.AuthenticationConfig(_file=StringIO('foo = bar'))
1496
 
        self.assertRaises(ValueError, conf.get_credentials, 'ftp', 'foo.net')
1497
 
 
1498
 
    def test_auth_section_header_not_closed(self):
1499
 
        conf = config.AuthenticationConfig(_file=StringIO('[DEF'))
1500
 
        self.assertRaises(errors.ParseConfigError, conf._get_config)
1501
 
 
1502
 
    def test_auth_value_not_boolean(self):
1503
 
        conf = config.AuthenticationConfig(_file=StringIO(
1504
 
                """[broken]
1505
 
scheme=ftp
1506
 
user=joe
1507
 
verify_certificates=askme # Error: Not a boolean
1508
 
"""))
1509
 
        self.assertRaises(ValueError, conf.get_credentials, 'ftp', 'foo.net')
1510
 
 
1511
 
    def test_auth_value_not_int(self):
1512
 
        conf = config.AuthenticationConfig(_file=StringIO(
1513
 
                """[broken]
1514
 
scheme=ftp
1515
 
user=joe
1516
 
port=port # Error: Not an int
1517
 
"""))
1518
 
        self.assertRaises(ValueError, conf.get_credentials, 'ftp', 'foo.net')
1519
 
 
1520
 
    def test_unknown_password_encoding(self):
1521
 
        conf = config.AuthenticationConfig(_file=StringIO(
1522
 
                """[broken]
1523
 
scheme=ftp
1524
 
user=joe
1525
 
password_encoding=unknown
1526
 
"""))
1527
 
        self.assertRaises(ValueError, conf.get_password,
1528
 
                          'ftp', 'foo.net', 'joe')
1529
 
 
1530
 
    def test_credentials_for_scheme_host(self):
1531
 
        conf = config.AuthenticationConfig(_file=StringIO(
1532
 
                """# Identity on foo.net
1533
 
[ftp definition]
1534
 
scheme=ftp
1535
 
host=foo.net
1536
 
user=joe
1537
 
password=secret-pass
1538
 
"""))
1539
 
        # Basic matching
1540
 
        self._got_user_passwd('joe', 'secret-pass', conf, 'ftp', 'foo.net')
1541
 
        # different scheme
1542
 
        self._got_user_passwd(None, None, conf, 'http', 'foo.net')
1543
 
        # different host
1544
 
        self._got_user_passwd(None, None, conf, 'ftp', 'bar.net')
1545
 
 
1546
 
    def test_credentials_for_host_port(self):
1547
 
        conf = config.AuthenticationConfig(_file=StringIO(
1548
 
                """# Identity on foo.net
1549
 
[ftp definition]
1550
 
scheme=ftp
1551
 
port=10021
1552
 
host=foo.net
1553
 
user=joe
1554
 
password=secret-pass
1555
 
"""))
1556
 
        # No port
1557
 
        self._got_user_passwd('joe', 'secret-pass',
1558
 
                              conf, 'ftp', 'foo.net', port=10021)
1559
 
        # different port
1560
 
        self._got_user_passwd(None, None, conf, 'ftp', 'foo.net')
1561
 
 
1562
 
    def test_for_matching_host(self):
1563
 
        conf = config.AuthenticationConfig(_file=StringIO(
1564
 
                """# Identity on foo.net
1565
 
[sourceforge]
1566
 
scheme=bzr
1567
 
host=bzr.sf.net
1568
 
user=joe
1569
 
password=joepass
1570
 
[sourceforge domain]
1571
 
scheme=bzr
1572
 
host=.bzr.sf.net
1573
 
user=georges
1574
 
password=bendover
1575
 
"""))
1576
 
        # matching domain
1577
 
        self._got_user_passwd('georges', 'bendover',
1578
 
                              conf, 'bzr', 'foo.bzr.sf.net')
1579
 
        # phishing attempt
1580
 
        self._got_user_passwd(None, None,
1581
 
                              conf, 'bzr', 'bbzr.sf.net')
1582
 
 
1583
 
    def test_for_matching_host_None(self):
1584
 
        conf = config.AuthenticationConfig(_file=StringIO(
1585
 
                """# Identity on foo.net
1586
 
[catchup bzr]
1587
 
scheme=bzr
1588
 
user=joe
1589
 
password=joepass
1590
 
[DEFAULT]
1591
 
user=georges
1592
 
password=bendover
1593
 
"""))
1594
 
        # match no host
1595
 
        self._got_user_passwd('joe', 'joepass',
1596
 
                              conf, 'bzr', 'quux.net')
1597
 
        # no host but different scheme
1598
 
        self._got_user_passwd('georges', 'bendover',
1599
 
                              conf, 'ftp', 'quux.net')
1600
 
 
1601
 
    def test_credentials_for_path(self):
1602
 
        conf = config.AuthenticationConfig(_file=StringIO(
1603
 
                """
1604
 
[http dir1]
1605
 
scheme=http
1606
 
host=bar.org
1607
 
path=/dir1
1608
 
user=jim
1609
 
password=jimpass
1610
 
[http dir2]
1611
 
scheme=http
1612
 
host=bar.org
1613
 
path=/dir2
1614
 
user=georges
1615
 
password=bendover
1616
 
"""))
1617
 
        # no path no dice
1618
 
        self._got_user_passwd(None, None,
1619
 
                              conf, 'http', host='bar.org', path='/dir3')
1620
 
        # matching path
1621
 
        self._got_user_passwd('georges', 'bendover',
1622
 
                              conf, 'http', host='bar.org', path='/dir2')
1623
 
        # matching subdir
1624
 
        self._got_user_passwd('jim', 'jimpass',
1625
 
                              conf, 'http', host='bar.org',path='/dir1/subdir')
1626
 
 
1627
 
    def test_credentials_for_user(self):
1628
 
        conf = config.AuthenticationConfig(_file=StringIO(
1629
 
                """
1630
 
[with user]
1631
 
scheme=http
1632
 
host=bar.org
1633
 
user=jim
1634
 
password=jimpass
1635
 
"""))
1636
 
        # Get user
1637
 
        self._got_user_passwd('jim', 'jimpass',
1638
 
                              conf, 'http', 'bar.org')
1639
 
        # Get same user
1640
 
        self._got_user_passwd('jim', 'jimpass',
1641
 
                              conf, 'http', 'bar.org', user='jim')
1642
 
        # Don't get a different user if one is specified
1643
 
        self._got_user_passwd(None, None,
1644
 
                              conf, 'http', 'bar.org', user='georges')
1645
 
 
1646
 
    def test_credentials_for_user_without_password(self):
1647
 
        conf = config.AuthenticationConfig(_file=StringIO(
1648
 
                """
1649
 
[without password]
1650
 
scheme=http
1651
 
host=bar.org
1652
 
user=jim
1653
 
"""))
1654
 
        # Get user but no password
1655
 
        self._got_user_passwd('jim', None,
1656
 
                              conf, 'http', 'bar.org')
1657
 
 
1658
 
    def test_verify_certificates(self):
1659
 
        conf = config.AuthenticationConfig(_file=StringIO(
1660
 
                """
1661
 
[self-signed]
1662
 
scheme=https
1663
 
host=bar.org
1664
 
user=jim
1665
 
password=jimpass
1666
 
verify_certificates=False
1667
 
[normal]
1668
 
scheme=https
1669
 
host=foo.net
1670
 
user=georges
1671
 
password=bendover
1672
 
"""))
1673
 
        credentials = conf.get_credentials('https', 'bar.org')
1674
 
        self.assertEquals(False, credentials.get('verify_certificates'))
1675
 
        credentials = conf.get_credentials('https', 'foo.net')
1676
 
        self.assertEquals(True, credentials.get('verify_certificates'))
1677
 
 
1678
 
 
1679
 
class TestAuthenticationStorage(tests.TestCaseInTempDir):
1680
 
 
1681
 
    def test_set_credentials(self):
1682
 
        conf = config.AuthenticationConfig()
1683
 
        conf.set_credentials('name', 'host', 'user', 'scheme', 'password',
1684
 
        99, path='/foo', verify_certificates=False, realm='realm')
1685
 
        credentials = conf.get_credentials(host='host', scheme='scheme',
1686
 
                                           port=99, path='/foo',
1687
 
                                           realm='realm')
1688
 
        CREDENTIALS = {'name': 'name', 'user': 'user', 'password': 'password',
1689
 
                       'verify_certificates': False, 'scheme': 'scheme', 
1690
 
                       'host': 'host', 'port': 99, 'path': '/foo', 
1691
 
                       'realm': 'realm'}
1692
 
        self.assertEqual(CREDENTIALS, credentials)
1693
 
        credentials_from_disk = config.AuthenticationConfig().get_credentials(
1694
 
            host='host', scheme='scheme', port=99, path='/foo', realm='realm')
1695
 
        self.assertEqual(CREDENTIALS, credentials_from_disk)
1696
 
 
1697
 
    def test_reset_credentials_different_name(self):
1698
 
        conf = config.AuthenticationConfig()
1699
 
        conf.set_credentials('name', 'host', 'user', 'scheme', 'password'),
1700
 
        conf.set_credentials('name2', 'host', 'user2', 'scheme', 'password'),
1701
 
        self.assertIs(None, conf._get_config().get('name'))
1702
 
        credentials = conf.get_credentials(host='host', scheme='scheme')
1703
 
        CREDENTIALS = {'name': 'name2', 'user': 'user2', 'password':
1704
 
                       'password', 'verify_certificates': True, 
1705
 
                       'scheme': 'scheme', 'host': 'host', 'port': None, 
1706
 
                       'path': None, 'realm': None}
1707
 
        self.assertEqual(CREDENTIALS, credentials)
1708
 
 
1709
 
 
1710
 
class TestAuthenticationConfig(tests.TestCase):
1711
 
    """Test AuthenticationConfig behaviour"""
1712
 
 
1713
 
    def _check_default_password_prompt(self, expected_prompt_format, scheme,
1714
 
                                       host=None, port=None, realm=None,
1715
 
                                       path=None):
1716
 
        if host is None:
1717
 
            host = 'bar.org'
1718
 
        user, password = 'jim', 'precious'
1719
 
        expected_prompt = expected_prompt_format % {
1720
 
            'scheme': scheme, 'host': host, 'port': port,
1721
 
            'user': user, 'realm': realm}
1722
 
 
1723
 
        stdout = tests.StringIOWrapper()
1724
 
        stderr = tests.StringIOWrapper()
1725
 
        ui.ui_factory = tests.TestUIFactory(stdin=password + '\n',
1726
 
                                            stdout=stdout, stderr=stderr)
1727
 
        # We use an empty conf so that the user is always prompted
1728
 
        conf = config.AuthenticationConfig()
1729
 
        self.assertEquals(password,
1730
 
                          conf.get_password(scheme, host, user, port=port,
1731
 
                                            realm=realm, path=path))
1732
 
        self.assertEquals(expected_prompt, stderr.getvalue())
1733
 
        self.assertEquals('', stdout.getvalue())
1734
 
 
1735
 
    def _check_default_username_prompt(self, expected_prompt_format, scheme,
1736
 
                                       host=None, port=None, realm=None,
1737
 
                                       path=None):
1738
 
        if host is None:
1739
 
            host = 'bar.org'
1740
 
        username = 'jim'
1741
 
        expected_prompt = expected_prompt_format % {
1742
 
            'scheme': scheme, 'host': host, 'port': port,
1743
 
            'realm': realm}
1744
 
        stdout = tests.StringIOWrapper()
1745
 
        stderr = tests.StringIOWrapper()
1746
 
        ui.ui_factory = tests.TestUIFactory(stdin=username+ '\n',
1747
 
                                            stdout=stdout, stderr=stderr)
1748
 
        # We use an empty conf so that the user is always prompted
1749
 
        conf = config.AuthenticationConfig()
1750
 
        self.assertEquals(username, conf.get_user(scheme, host, port=port,
1751
 
                          realm=realm, path=path, ask=True))
1752
 
        self.assertEquals(expected_prompt, stderr.getvalue())
1753
 
        self.assertEquals('', stdout.getvalue())
1754
 
 
1755
 
    def test_username_defaults_prompts(self):
1756
 
        # HTTP prompts can't be tested here, see test_http.py
1757
 
        self._check_default_username_prompt('FTP %(host)s username: ', 'ftp')
1758
 
        self._check_default_username_prompt(
1759
 
            'FTP %(host)s:%(port)d username: ', 'ftp', port=10020)
1760
 
        self._check_default_username_prompt(
1761
 
            'SSH %(host)s:%(port)d username: ', 'ssh', port=12345)
1762
 
 
1763
 
    def test_username_default_no_prompt(self):
1764
 
        conf = config.AuthenticationConfig()
1765
 
        self.assertEquals(None,
1766
 
            conf.get_user('ftp', 'example.com'))
1767
 
        self.assertEquals("explicitdefault",
1768
 
            conf.get_user('ftp', 'example.com', default="explicitdefault"))
1769
 
 
1770
 
    def test_password_default_prompts(self):
1771
 
        # HTTP prompts can't be tested here, see test_http.py
1772
 
        self._check_default_password_prompt(
1773
 
            'FTP %(user)s@%(host)s password: ', 'ftp')
1774
 
        self._check_default_password_prompt(
1775
 
            'FTP %(user)s@%(host)s:%(port)d password: ', 'ftp', port=10020)
1776
 
        self._check_default_password_prompt(
1777
 
            'SSH %(user)s@%(host)s:%(port)d password: ', 'ssh', port=12345)
1778
 
        # SMTP port handling is a bit special (it's handled if embedded in the
1779
 
        # host too)
1780
 
        # FIXME: should we: forbid that, extend it to other schemes, leave
1781
 
        # things as they are that's fine thank you ?
1782
 
        self._check_default_password_prompt('SMTP %(user)s@%(host)s password: ',
1783
 
                                            'smtp')
1784
 
        self._check_default_password_prompt('SMTP %(user)s@%(host)s password: ',
1785
 
                                            'smtp', host='bar.org:10025')
1786
 
        self._check_default_password_prompt(
1787
 
            'SMTP %(user)s@%(host)s:%(port)d password: ',
1788
 
            'smtp', port=10025)
1789
 
 
1790
 
    def test_ssh_password_emits_warning(self):
1791
 
        conf = config.AuthenticationConfig(_file=StringIO(
1792
 
                """
1793
 
[ssh with password]
1794
 
scheme=ssh
1795
 
host=bar.org
1796
 
user=jim
1797
 
password=jimpass
1798
 
"""))
1799
 
        entered_password = 'typed-by-hand'
1800
 
        stdout = tests.StringIOWrapper()
1801
 
        stderr = tests.StringIOWrapper()
1802
 
        ui.ui_factory = tests.TestUIFactory(stdin=entered_password + '\n',
1803
 
                                            stdout=stdout, stderr=stderr)
1804
 
 
1805
 
        # Since the password defined in the authentication config is ignored,
1806
 
        # the user is prompted
1807
 
        self.assertEquals(entered_password,
1808
 
                          conf.get_password('ssh', 'bar.org', user='jim'))
1809
 
        self.assertContainsRe(
1810
 
            self.get_log(),
1811
 
            'password ignored in section \[ssh with password\]')
1812
 
 
1813
 
    def test_ssh_without_password_doesnt_emit_warning(self):
1814
 
        conf = config.AuthenticationConfig(_file=StringIO(
1815
 
                """
1816
 
[ssh with password]
1817
 
scheme=ssh
1818
 
host=bar.org
1819
 
user=jim
1820
 
"""))
1821
 
        entered_password = 'typed-by-hand'
1822
 
        stdout = tests.StringIOWrapper()
1823
 
        stderr = tests.StringIOWrapper()
1824
 
        ui.ui_factory = tests.TestUIFactory(stdin=entered_password + '\n',
1825
 
                                            stdout=stdout,
1826
 
                                            stderr=stderr)
1827
 
 
1828
 
        # Since the password defined in the authentication config is ignored,
1829
 
        # the user is prompted
1830
 
        self.assertEquals(entered_password,
1831
 
                          conf.get_password('ssh', 'bar.org', user='jim'))
1832
 
        # No warning shoud be emitted since there is no password. We are only
1833
 
        # providing "user".
1834
 
        self.assertNotContainsRe(
1835
 
            self.get_log(),
1836
 
            'password ignored in section \[ssh with password\]')
1837
 
 
1838
 
    def test_uses_fallback_stores(self):
1839
 
        self.overrideAttr(config, 'credential_store_registry',
1840
 
                          config.CredentialStoreRegistry())
1841
 
        store = StubCredentialStore()
1842
 
        store.add_credentials("http", "example.com", "joe", "secret")
1843
 
        config.credential_store_registry.register("stub", store, fallback=True)
1844
 
        conf = config.AuthenticationConfig(_file=StringIO())
1845
 
        creds = conf.get_credentials("http", "example.com")
1846
 
        self.assertEquals("joe", creds["user"])
1847
 
        self.assertEquals("secret", creds["password"])
1848
 
 
1849
 
 
1850
 
class StubCredentialStore(config.CredentialStore):
1851
 
 
1852
 
    def __init__(self):
1853
 
        self._username = {}
1854
 
        self._password = {}
1855
 
 
1856
 
    def add_credentials(self, scheme, host, user, password=None):
1857
 
        self._username[(scheme, host)] = user
1858
 
        self._password[(scheme, host)] = password
1859
 
 
1860
 
    def get_credentials(self, scheme, host, port=None, user=None,
1861
 
        path=None, realm=None):
1862
 
        key = (scheme, host)
1863
 
        if not key in self._username:
1864
 
            return None
1865
 
        return { "scheme": scheme, "host": host, "port": port,
1866
 
                "user": self._username[key], "password": self._password[key]}
1867
 
 
1868
 
 
1869
 
class CountingCredentialStore(config.CredentialStore):
1870
 
 
1871
 
    def __init__(self):
1872
 
        self._calls = 0
1873
 
 
1874
 
    def get_credentials(self, scheme, host, port=None, user=None,
1875
 
        path=None, realm=None):
1876
 
        self._calls += 1
1877
 
        return None
1878
 
 
1879
 
 
1880
 
class TestCredentialStoreRegistry(tests.TestCase):
1881
 
 
1882
 
    def _get_cs_registry(self):
1883
 
        return config.credential_store_registry
1884
 
 
1885
 
    def test_default_credential_store(self):
1886
 
        r = self._get_cs_registry()
1887
 
        default = r.get_credential_store(None)
1888
 
        self.assertIsInstance(default, config.PlainTextCredentialStore)
1889
 
 
1890
 
    def test_unknown_credential_store(self):
1891
 
        r = self._get_cs_registry()
1892
 
        # It's hard to imagine someone creating a credential store named
1893
 
        # 'unknown' so we use that as an never registered key.
1894
 
        self.assertRaises(KeyError, r.get_credential_store, 'unknown')
1895
 
 
1896
 
    def test_fallback_none_registered(self):
1897
 
        r = config.CredentialStoreRegistry()
1898
 
        self.assertEquals(None,
1899
 
                          r.get_fallback_credentials("http", "example.com"))
1900
 
 
1901
 
    def test_register(self):
1902
 
        r = config.CredentialStoreRegistry()
1903
 
        r.register("stub", StubCredentialStore(), fallback=False)
1904
 
        r.register("another", StubCredentialStore(), fallback=True)
1905
 
        self.assertEquals(["another", "stub"], r.keys())
1906
 
 
1907
 
    def test_register_lazy(self):
1908
 
        r = config.CredentialStoreRegistry()
1909
 
        r.register_lazy("stub", "bzrlib.tests.test_config",
1910
 
                        "StubCredentialStore", fallback=False)
1911
 
        self.assertEquals(["stub"], r.keys())
1912
 
        self.assertIsInstance(r.get_credential_store("stub"),
1913
 
                              StubCredentialStore)
1914
 
 
1915
 
    def test_is_fallback(self):
1916
 
        r = config.CredentialStoreRegistry()
1917
 
        r.register("stub1", None, fallback=False)
1918
 
        r.register("stub2", None, fallback=True)
1919
 
        self.assertEquals(False, r.is_fallback("stub1"))
1920
 
        self.assertEquals(True, r.is_fallback("stub2"))
1921
 
 
1922
 
    def test_no_fallback(self):
1923
 
        r = config.CredentialStoreRegistry()
1924
 
        store = CountingCredentialStore()
1925
 
        r.register("count", store, fallback=False)
1926
 
        self.assertEquals(None,
1927
 
                          r.get_fallback_credentials("http", "example.com"))
1928
 
        self.assertEquals(0, store._calls)
1929
 
 
1930
 
    def test_fallback_credentials(self):
1931
 
        r = config.CredentialStoreRegistry()
1932
 
        store = StubCredentialStore()
1933
 
        store.add_credentials("http", "example.com",
1934
 
                              "somebody", "geheim")
1935
 
        r.register("stub", store, fallback=True)
1936
 
        creds = r.get_fallback_credentials("http", "example.com")
1937
 
        self.assertEquals("somebody", creds["user"])
1938
 
        self.assertEquals("geheim", creds["password"])
1939
 
 
1940
 
    def test_fallback_first_wins(self):
1941
 
        r = config.CredentialStoreRegistry()
1942
 
        stub1 = StubCredentialStore()
1943
 
        stub1.add_credentials("http", "example.com",
1944
 
                              "somebody", "stub1")
1945
 
        r.register("stub1", stub1, fallback=True)
1946
 
        stub2 = StubCredentialStore()
1947
 
        stub2.add_credentials("http", "example.com",
1948
 
                              "somebody", "stub2")
1949
 
        r.register("stub2", stub1, fallback=True)
1950
 
        creds = r.get_fallback_credentials("http", "example.com")
1951
 
        self.assertEquals("somebody", creds["user"])
1952
 
        self.assertEquals("stub1", creds["password"])
1953
 
 
1954
 
 
1955
 
class TestPlainTextCredentialStore(tests.TestCase):
1956
 
 
1957
 
    def test_decode_password(self):
1958
 
        r = config.credential_store_registry
1959
 
        plain_text = r.get_credential_store()
1960
 
        decoded = plain_text.decode_password(dict(password='secret'))
1961
 
        self.assertEquals('secret', decoded)
1962
 
 
1963
 
 
1964
 
# FIXME: Once we have a way to declare authentication to all test servers, we
1965
 
# can implement generic tests.
1966
 
# test_user_password_in_url
1967
 
# test_user_in_url_password_from_config
1968
 
# test_user_in_url_password_prompted
1969
 
# test_user_in_config
1970
 
# test_user_getpass.getuser
1971
 
# test_user_prompted ?
1972
 
class TestAuthenticationRing(tests.TestCaseWithTransport):
1973
 
    pass