~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_config.py

  • Committer: John Arbash Meinel
  • Date: 2007-02-08 16:28:05 UTC
  • mto: This revision was merged to the branch mainline in revision 2278.
  • Revision ID: john@arbash-meinel.com-20070208162805-dcqiqrwjh9a5lo7n
``GPGStrategy.sign()`` will now raise ``BzrBadParameterUnicode`` if
you pass a Unicode string rather than an 8-bit string. It doesn't 
make sense to sign a Unicode string, and it turns out that some 
versions of python will write out the raw Unicode bytes rather than
encoding automatically. So fail and make callers do the right thing.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2005, 2006 Canonical Ltd
 
2
#   Authors: Robert Collins <robert.collins@canonical.com>
 
3
#
 
4
# This program is free software; you can redistribute it and/or modify
 
5
# it under the terms of the GNU General Public License as published by
 
6
# the Free Software Foundation; either version 2 of the License, or
 
7
# (at your option) any later version.
 
8
#
 
9
# This program is distributed in the hope that it will be useful,
 
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
12
# GNU General Public License for more details.
 
13
#
 
14
# You should have received a copy of the GNU General Public License
 
15
# along with this program; if not, write to the Free Software
 
16
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
17
 
 
18
"""Tests for finding and reading the bzr config file[s]."""
 
19
# import system imports here
 
20
from bzrlib.util.configobj.configobj import ConfigObj, ConfigObjError
 
21
from cStringIO import StringIO
 
22
import os
 
23
import sys
 
24
 
 
25
#import bzrlib specific imports here
 
26
from bzrlib import (
 
27
    config,
 
28
    errors,
 
29
    osutils,
 
30
    urlutils,
 
31
    )
 
32
from bzrlib.branch import Branch
 
33
from bzrlib.bzrdir import BzrDir
 
34
from bzrlib.tests import TestCase, TestCaseInTempDir, TestCaseWithTransport
 
35
 
 
36
 
 
37
sample_long_alias="log -r-15..-1 --line"
 
38
sample_config_text = u"""
 
39
[DEFAULT]
 
40
email=Erik B\u00e5gfors <erik@bagfors.nu>
 
41
editor=vim
 
42
gpg_signing_command=gnome-gpg
 
43
log_format=short
 
44
user_global_option=something
 
45
[ALIASES]
 
46
h=help
 
47
ll=""" + sample_long_alias + "\n"
 
48
 
 
49
 
 
50
sample_always_signatures = """
 
51
[DEFAULT]
 
52
check_signatures=ignore
 
53
create_signatures=always
 
54
"""
 
55
 
 
56
sample_ignore_signatures = """
 
57
[DEFAULT]
 
58
check_signatures=require
 
59
create_signatures=never
 
60
"""
 
61
 
 
62
sample_maybe_signatures = """
 
63
[DEFAULT]
 
64
check_signatures=ignore
 
65
create_signatures=when-required
 
66
"""
 
67
 
 
68
sample_branches_text = """
 
69
[http://www.example.com]
 
70
# Top level policy
 
71
email=Robert Collins <robertc@example.org>
 
72
normal_option = normal
 
73
appendpath_option = append
 
74
appendpath_option:policy = appendpath
 
75
norecurse_option = norecurse
 
76
norecurse_option:policy = norecurse
 
77
[http://www.example.com/ignoreparent]
 
78
# different project: ignore parent dir config
 
79
ignore_parents=true
 
80
[http://www.example.com/norecurse]
 
81
# configuration items that only apply to this dir
 
82
recurse=false
 
83
normal_option = norecurse
 
84
[http://www.example.com/dir]
 
85
appendpath_option = normal
 
86
[/b/]
 
87
check_signatures=require
 
88
# test trailing / matching with no children
 
89
[/a/]
 
90
check_signatures=check-available
 
91
gpg_signing_command=false
 
92
user_local_option=local
 
93
# test trailing / matching
 
94
[/a/*]
 
95
#subdirs will match but not the parent
 
96
[/a/c]
 
97
check_signatures=ignore
 
98
post_commit=bzrlib.tests.test_config.post_commit
 
99
#testing explicit beats globs
 
100
"""
 
101
 
 
102
 
 
103
class InstrumentedConfigObj(object):
 
104
    """A config obj look-enough-alike to record calls made to it."""
 
105
 
 
106
    def __contains__(self, thing):
 
107
        self._calls.append(('__contains__', thing))
 
108
        return False
 
109
 
 
110
    def __getitem__(self, key):
 
111
        self._calls.append(('__getitem__', key))
 
112
        return self
 
113
 
 
114
    def __init__(self, input, encoding=None):
 
115
        self._calls = [('__init__', input, encoding)]
 
116
 
 
117
    def __setitem__(self, key, value):
 
118
        self._calls.append(('__setitem__', key, value))
 
119
 
 
120
    def __delitem__(self, key):
 
121
        self._calls.append(('__delitem__', key))
 
122
 
 
123
    def keys(self):
 
124
        self._calls.append(('keys',))
 
125
        return []
 
126
 
 
127
    def write(self, arg):
 
128
        self._calls.append(('write',))
 
129
 
 
130
    def as_bool(self, value):
 
131
        self._calls.append(('as_bool', value))
 
132
        return False
 
133
 
 
134
    def get_value(self, section, name):
 
135
        self._calls.append(('get_value', section, name))
 
136
        return None
 
137
 
 
138
 
 
139
class FakeBranch(object):
 
140
 
 
141
    def __init__(self, base=None, user_id=None):
 
142
        if base is None:
 
143
            self.base = "http://example.com/branches/demo"
 
144
        else:
 
145
            self.base = base
 
146
        self.control_files = FakeControlFiles(user_id=user_id)
 
147
 
 
148
    def lock_write(self):
 
149
        pass
 
150
 
 
151
    def unlock(self):
 
152
        pass
 
153
 
 
154
 
 
155
class FakeControlFiles(object):
 
156
 
 
157
    def __init__(self, user_id=None):
 
158
        self.email = user_id
 
159
        self.files = {}
 
160
 
 
161
    def get_utf8(self, filename):
 
162
        if filename != 'email':
 
163
            raise NotImplementedError
 
164
        if self.email is not None:
 
165
            return StringIO(self.email)
 
166
        raise errors.NoSuchFile(filename)
 
167
 
 
168
    def get(self, filename):
 
169
        try:
 
170
            return StringIO(self.files[filename])
 
171
        except KeyError:
 
172
            raise errors.NoSuchFile(filename)
 
173
 
 
174
    def put(self, filename, fileobj):
 
175
        self.files[filename] = fileobj.read()
 
176
 
 
177
 
 
178
class InstrumentedConfig(config.Config):
 
179
    """An instrumented config that supplies stubs for template methods."""
 
180
    
 
181
    def __init__(self):
 
182
        super(InstrumentedConfig, self).__init__()
 
183
        self._calls = []
 
184
        self._signatures = config.CHECK_NEVER
 
185
 
 
186
    def _get_user_id(self):
 
187
        self._calls.append('_get_user_id')
 
188
        return "Robert Collins <robert.collins@example.org>"
 
189
 
 
190
    def _get_signature_checking(self):
 
191
        self._calls.append('_get_signature_checking')
 
192
        return self._signatures
 
193
 
 
194
 
 
195
bool_config = """[DEFAULT]
 
196
active = true
 
197
inactive = false
 
198
[UPPERCASE]
 
199
active = True
 
200
nonactive = False
 
201
"""
 
202
class TestConfigObj(TestCase):
 
203
    def test_get_bool(self):
 
204
        from bzrlib.config import ConfigObj
 
205
        co = ConfigObj(StringIO(bool_config))
 
206
        self.assertIs(co.get_bool('DEFAULT', 'active'), True)
 
207
        self.assertIs(co.get_bool('DEFAULT', 'inactive'), False)
 
208
        self.assertIs(co.get_bool('UPPERCASE', 'active'), True)
 
209
        self.assertIs(co.get_bool('UPPERCASE', 'nonactive'), False)
 
210
 
 
211
 
 
212
class TestConfig(TestCase):
 
213
 
 
214
    def test_constructs(self):
 
215
        config.Config()
 
216
 
 
217
    def test_no_default_editor(self):
 
218
        self.assertRaises(NotImplementedError, config.Config().get_editor)
 
219
 
 
220
    def test_user_email(self):
 
221
        my_config = InstrumentedConfig()
 
222
        self.assertEqual('robert.collins@example.org', my_config.user_email())
 
223
        self.assertEqual(['_get_user_id'], my_config._calls)
 
224
 
 
225
    def test_username(self):
 
226
        my_config = InstrumentedConfig()
 
227
        self.assertEqual('Robert Collins <robert.collins@example.org>',
 
228
                         my_config.username())
 
229
        self.assertEqual(['_get_user_id'], my_config._calls)
 
230
 
 
231
    def test_signatures_default(self):
 
232
        my_config = config.Config()
 
233
        self.assertFalse(my_config.signature_needed())
 
234
        self.assertEqual(config.CHECK_IF_POSSIBLE,
 
235
                         my_config.signature_checking())
 
236
        self.assertEqual(config.SIGN_WHEN_REQUIRED,
 
237
                         my_config.signing_policy())
 
238
 
 
239
    def test_signatures_template_method(self):
 
240
        my_config = InstrumentedConfig()
 
241
        self.assertEqual(config.CHECK_NEVER, my_config.signature_checking())
 
242
        self.assertEqual(['_get_signature_checking'], my_config._calls)
 
243
 
 
244
    def test_signatures_template_method_none(self):
 
245
        my_config = InstrumentedConfig()
 
246
        my_config._signatures = None
 
247
        self.assertEqual(config.CHECK_IF_POSSIBLE,
 
248
                         my_config.signature_checking())
 
249
        self.assertEqual(['_get_signature_checking'], my_config._calls)
 
250
 
 
251
    def test_gpg_signing_command_default(self):
 
252
        my_config = config.Config()
 
253
        self.assertEqual('gpg', my_config.gpg_signing_command())
 
254
 
 
255
    def test_get_user_option_default(self):
 
256
        my_config = config.Config()
 
257
        self.assertEqual(None, my_config.get_user_option('no_option'))
 
258
 
 
259
    def test_post_commit_default(self):
 
260
        my_config = config.Config()
 
261
        self.assertEqual(None, my_config.post_commit())
 
262
 
 
263
    def test_log_format_default(self):
 
264
        my_config = config.Config()
 
265
        self.assertEqual('long', my_config.log_format())
 
266
 
 
267
 
 
268
class TestConfigPath(TestCase):
 
269
 
 
270
    def setUp(self):
 
271
        super(TestConfigPath, self).setUp()
 
272
        self.old_home = os.environ.get('HOME', None)
 
273
        self.old_appdata = os.environ.get('APPDATA', None)
 
274
        os.environ['HOME'] = '/home/bogus'
 
275
        os.environ['APPDATA'] = \
 
276
            r'C:\Documents and Settings\bogus\Application Data'
 
277
 
 
278
    def tearDown(self):
 
279
        if self.old_home is None:
 
280
            del os.environ['HOME']
 
281
        else:
 
282
            os.environ['HOME'] = self.old_home
 
283
        if self.old_appdata is None:
 
284
            del os.environ['APPDATA']
 
285
        else:
 
286
            os.environ['APPDATA'] = self.old_appdata
 
287
        super(TestConfigPath, self).tearDown()
 
288
    
 
289
    def test_config_dir(self):
 
290
        if sys.platform == 'win32':
 
291
            self.assertEqual(config.config_dir(), 
 
292
                'C:/Documents and Settings/bogus/Application Data/bazaar/2.0')
 
293
        else:
 
294
            self.assertEqual(config.config_dir(), '/home/bogus/.bazaar')
 
295
 
 
296
    def test_config_filename(self):
 
297
        if sys.platform == 'win32':
 
298
            self.assertEqual(config.config_filename(), 
 
299
                'C:/Documents and Settings/bogus/Application Data/bazaar/2.0/bazaar.conf')
 
300
        else:
 
301
            self.assertEqual(config.config_filename(),
 
302
                             '/home/bogus/.bazaar/bazaar.conf')
 
303
 
 
304
    def test_branches_config_filename(self):
 
305
        if sys.platform == 'win32':
 
306
            self.assertEqual(config.branches_config_filename(), 
 
307
                'C:/Documents and Settings/bogus/Application Data/bazaar/2.0/branches.conf')
 
308
        else:
 
309
            self.assertEqual(config.branches_config_filename(),
 
310
                             '/home/bogus/.bazaar/branches.conf')
 
311
 
 
312
    def test_locations_config_filename(self):
 
313
        if sys.platform == 'win32':
 
314
            self.assertEqual(config.locations_config_filename(), 
 
315
                'C:/Documents and Settings/bogus/Application Data/bazaar/2.0/locations.conf')
 
316
        else:
 
317
            self.assertEqual(config.locations_config_filename(),
 
318
                             '/home/bogus/.bazaar/locations.conf')
 
319
 
 
320
class TestIniConfig(TestCase):
 
321
 
 
322
    def test_contructs(self):
 
323
        my_config = config.IniBasedConfig("nothing")
 
324
 
 
325
    def test_from_fp(self):
 
326
        config_file = StringIO(sample_config_text.encode('utf-8'))
 
327
        my_config = config.IniBasedConfig(None)
 
328
        self.failUnless(
 
329
            isinstance(my_config._get_parser(file=config_file),
 
330
                        ConfigObj))
 
331
 
 
332
    def test_cached(self):
 
333
        config_file = StringIO(sample_config_text.encode('utf-8'))
 
334
        my_config = config.IniBasedConfig(None)
 
335
        parser = my_config._get_parser(file=config_file)
 
336
        self.failUnless(my_config._get_parser() is parser)
 
337
 
 
338
 
 
339
class TestGetConfig(TestCase):
 
340
 
 
341
    def test_constructs(self):
 
342
        my_config = config.GlobalConfig()
 
343
 
 
344
    def test_calls_read_filenames(self):
 
345
        # replace the class that is constructured, to check its parameters
 
346
        oldparserclass = config.ConfigObj
 
347
        config.ConfigObj = InstrumentedConfigObj
 
348
        my_config = config.GlobalConfig()
 
349
        try:
 
350
            parser = my_config._get_parser()
 
351
        finally:
 
352
            config.ConfigObj = oldparserclass
 
353
        self.failUnless(isinstance(parser, InstrumentedConfigObj))
 
354
        self.assertEqual(parser._calls, [('__init__', config.config_filename(),
 
355
                                          'utf-8')])
 
356
 
 
357
 
 
358
class TestBranchConfig(TestCaseWithTransport):
 
359
 
 
360
    def test_constructs(self):
 
361
        branch = FakeBranch()
 
362
        my_config = config.BranchConfig(branch)
 
363
        self.assertRaises(TypeError, config.BranchConfig)
 
364
 
 
365
    def test_get_location_config(self):
 
366
        branch = FakeBranch()
 
367
        my_config = config.BranchConfig(branch)
 
368
        location_config = my_config._get_location_config()
 
369
        self.assertEqual(branch.base, location_config.location)
 
370
        self.failUnless(location_config is my_config._get_location_config())
 
371
 
 
372
    def test_get_config(self):
 
373
        """The Branch.get_config method works properly"""
 
374
        b = BzrDir.create_standalone_workingtree('.').branch
 
375
        my_config = b.get_config()
 
376
        self.assertIs(my_config.get_user_option('wacky'), None)
 
377
        my_config.set_user_option('wacky', 'unlikely')
 
378
        self.assertEqual(my_config.get_user_option('wacky'), 'unlikely')
 
379
 
 
380
        # Ensure we get the same thing if we start again
 
381
        b2 = Branch.open('.')
 
382
        my_config2 = b2.get_config()
 
383
        self.assertEqual(my_config2.get_user_option('wacky'), 'unlikely')
 
384
 
 
385
    def test_has_explicit_nickname(self):
 
386
        b = self.make_branch('.')
 
387
        self.assertFalse(b.get_config().has_explicit_nickname())
 
388
        b.nick = 'foo'
 
389
        self.assertTrue(b.get_config().has_explicit_nickname())
 
390
 
 
391
    def test_config_url(self):
 
392
        """The Branch.get_config will use section that uses a local url"""
 
393
        branch = self.make_branch('branch')
 
394
        self.assertEqual('branch', branch.nick)
 
395
 
 
396
        locations = config.locations_config_filename()
 
397
        config.ensure_config_dir_exists()
 
398
        local_url = urlutils.local_path_to_url('branch')
 
399
        open(locations, 'wb').write('[%s]\nnickname = foobar' 
 
400
                                    % (local_url,))
 
401
        self.assertEqual('foobar', branch.nick)
 
402
 
 
403
    def test_config_local_path(self):
 
404
        """The Branch.get_config will use a local system path"""
 
405
        branch = self.make_branch('branch')
 
406
        self.assertEqual('branch', branch.nick)
 
407
 
 
408
        locations = config.locations_config_filename()
 
409
        config.ensure_config_dir_exists()
 
410
        open(locations, 'wb').write('[%s/branch]\nnickname = barry' 
 
411
                                    % (osutils.getcwd().encode('utf8'),))
 
412
        self.assertEqual('barry', branch.nick)
 
413
 
 
414
    def test_config_creates_local(self):
 
415
        """Creating a new entry in config uses a local path."""
 
416
        branch = self.make_branch('branch')
 
417
        branch.set_push_location('http://foobar')
 
418
        locations = config.locations_config_filename()
 
419
        local_path = osutils.getcwd().encode('utf8')
 
420
        # Surprisingly ConfigObj doesn't create a trailing newline
 
421
        self.check_file_contents(locations,
 
422
            '[%s/branch]\npush_location = http://foobar\npush_location:policy = norecurse' % (local_path,))
 
423
 
 
424
    def test_autonick_urlencoded(self):
 
425
        b = self.make_branch('!repo')
 
426
        self.assertEqual('!repo', b.get_config().get_nickname())
 
427
 
 
428
 
 
429
class TestGlobalConfigItems(TestCase):
 
430
 
 
431
    def test_user_id(self):
 
432
        config_file = StringIO(sample_config_text.encode('utf-8'))
 
433
        my_config = config.GlobalConfig()
 
434
        my_config._parser = my_config._get_parser(file=config_file)
 
435
        self.assertEqual(u"Erik B\u00e5gfors <erik@bagfors.nu>",
 
436
                         my_config._get_user_id())
 
437
 
 
438
    def test_absent_user_id(self):
 
439
        config_file = StringIO("")
 
440
        my_config = config.GlobalConfig()
 
441
        my_config._parser = my_config._get_parser(file=config_file)
 
442
        self.assertEqual(None, my_config._get_user_id())
 
443
 
 
444
    def test_configured_editor(self):
 
445
        config_file = StringIO(sample_config_text.encode('utf-8'))
 
446
        my_config = config.GlobalConfig()
 
447
        my_config._parser = my_config._get_parser(file=config_file)
 
448
        self.assertEqual("vim", my_config.get_editor())
 
449
 
 
450
    def test_signatures_always(self):
 
451
        config_file = StringIO(sample_always_signatures)
 
452
        my_config = config.GlobalConfig()
 
453
        my_config._parser = my_config._get_parser(file=config_file)
 
454
        self.assertEqual(config.CHECK_NEVER,
 
455
                         my_config.signature_checking())
 
456
        self.assertEqual(config.SIGN_ALWAYS,
 
457
                         my_config.signing_policy())
 
458
        self.assertEqual(True, my_config.signature_needed())
 
459
 
 
460
    def test_signatures_if_possible(self):
 
461
        config_file = StringIO(sample_maybe_signatures)
 
462
        my_config = config.GlobalConfig()
 
463
        my_config._parser = my_config._get_parser(file=config_file)
 
464
        self.assertEqual(config.CHECK_NEVER,
 
465
                         my_config.signature_checking())
 
466
        self.assertEqual(config.SIGN_WHEN_REQUIRED,
 
467
                         my_config.signing_policy())
 
468
        self.assertEqual(False, my_config.signature_needed())
 
469
 
 
470
    def test_signatures_ignore(self):
 
471
        config_file = StringIO(sample_ignore_signatures)
 
472
        my_config = config.GlobalConfig()
 
473
        my_config._parser = my_config._get_parser(file=config_file)
 
474
        self.assertEqual(config.CHECK_ALWAYS,
 
475
                         my_config.signature_checking())
 
476
        self.assertEqual(config.SIGN_NEVER,
 
477
                         my_config.signing_policy())
 
478
        self.assertEqual(False, my_config.signature_needed())
 
479
 
 
480
    def _get_sample_config(self):
 
481
        config_file = StringIO(sample_config_text.encode('utf-8'))
 
482
        my_config = config.GlobalConfig()
 
483
        my_config._parser = my_config._get_parser(file=config_file)
 
484
        return my_config
 
485
 
 
486
    def test_gpg_signing_command(self):
 
487
        my_config = self._get_sample_config()
 
488
        self.assertEqual("gnome-gpg", my_config.gpg_signing_command())
 
489
        self.assertEqual(False, my_config.signature_needed())
 
490
 
 
491
    def _get_empty_config(self):
 
492
        config_file = StringIO("")
 
493
        my_config = config.GlobalConfig()
 
494
        my_config._parser = my_config._get_parser(file=config_file)
 
495
        return my_config
 
496
 
 
497
    def test_gpg_signing_command_unset(self):
 
498
        my_config = self._get_empty_config()
 
499
        self.assertEqual("gpg", my_config.gpg_signing_command())
 
500
 
 
501
    def test_get_user_option_default(self):
 
502
        my_config = self._get_empty_config()
 
503
        self.assertEqual(None, my_config.get_user_option('no_option'))
 
504
 
 
505
    def test_get_user_option_global(self):
 
506
        my_config = self._get_sample_config()
 
507
        self.assertEqual("something",
 
508
                         my_config.get_user_option('user_global_option'))
 
509
        
 
510
    def test_post_commit_default(self):
 
511
        my_config = self._get_sample_config()
 
512
        self.assertEqual(None, my_config.post_commit())
 
513
 
 
514
    def test_configured_logformat(self):
 
515
        my_config = self._get_sample_config()
 
516
        self.assertEqual("short", my_config.log_format())
 
517
 
 
518
    def test_get_alias(self):
 
519
        my_config = self._get_sample_config()
 
520
        self.assertEqual('help', my_config.get_alias('h'))
 
521
 
 
522
    def test_get_no_alias(self):
 
523
        my_config = self._get_sample_config()
 
524
        self.assertEqual(None, my_config.get_alias('foo'))
 
525
 
 
526
    def test_get_long_alias(self):
 
527
        my_config = self._get_sample_config()
 
528
        self.assertEqual(sample_long_alias, my_config.get_alias('ll'))
 
529
 
 
530
 
 
531
class TestLocationConfig(TestCaseInTempDir):
 
532
 
 
533
    def test_constructs(self):
 
534
        my_config = config.LocationConfig('http://example.com')
 
535
        self.assertRaises(TypeError, config.LocationConfig)
 
536
 
 
537
    def test_branch_calls_read_filenames(self):
 
538
        # This is testing the correct file names are provided.
 
539
        # TODO: consolidate with the test for GlobalConfigs filename checks.
 
540
        #
 
541
        # replace the class that is constructured, to check its parameters
 
542
        oldparserclass = config.ConfigObj
 
543
        config.ConfigObj = InstrumentedConfigObj
 
544
        try:
 
545
            my_config = config.LocationConfig('http://www.example.com')
 
546
            parser = my_config._get_parser()
 
547
        finally:
 
548
            config.ConfigObj = oldparserclass
 
549
        self.failUnless(isinstance(parser, InstrumentedConfigObj))
 
550
        self.assertEqual(parser._calls,
 
551
                         [('__init__', config.locations_config_filename(),
 
552
                           'utf-8')])
 
553
        config.ensure_config_dir_exists()
 
554
        #os.mkdir(config.config_dir())
 
555
        f = file(config.branches_config_filename(), 'wb')
 
556
        f.write('')
 
557
        f.close()
 
558
        oldparserclass = config.ConfigObj
 
559
        config.ConfigObj = InstrumentedConfigObj
 
560
        try:
 
561
            my_config = config.LocationConfig('http://www.example.com')
 
562
            parser = my_config._get_parser()
 
563
        finally:
 
564
            config.ConfigObj = oldparserclass
 
565
 
 
566
    def test_get_global_config(self):
 
567
        my_config = config.BranchConfig(FakeBranch('http://example.com'))
 
568
        global_config = my_config._get_global_config()
 
569
        self.failUnless(isinstance(global_config, config.GlobalConfig))
 
570
        self.failUnless(global_config is my_config._get_global_config())
 
571
 
 
572
    def test__get_matching_sections_no_match(self):
 
573
        self.get_branch_config('/')
 
574
        self.assertEqual([], self.my_location_config._get_matching_sections())
 
575
        
 
576
    def test__get_matching_sections_exact(self):
 
577
        self.get_branch_config('http://www.example.com')
 
578
        self.assertEqual([('http://www.example.com', '')],
 
579
                         self.my_location_config._get_matching_sections())
 
580
   
 
581
    def test__get_matching_sections_suffix_does_not(self):
 
582
        self.get_branch_config('http://www.example.com-com')
 
583
        self.assertEqual([], self.my_location_config._get_matching_sections())
 
584
 
 
585
    def test__get_matching_sections_subdir_recursive(self):
 
586
        self.get_branch_config('http://www.example.com/com')
 
587
        self.assertEqual([('http://www.example.com', 'com')],
 
588
                         self.my_location_config._get_matching_sections())
 
589
 
 
590
    def test__get_matching_sections_ignoreparent(self):
 
591
        self.get_branch_config('http://www.example.com/ignoreparent')
 
592
        self.assertEqual([('http://www.example.com/ignoreparent', '')],
 
593
                         self.my_location_config._get_matching_sections())
 
594
 
 
595
    def test__get_matching_sections_ignoreparent_subdir(self):
 
596
        self.get_branch_config(
 
597
            'http://www.example.com/ignoreparent/childbranch')
 
598
        self.assertEqual([('http://www.example.com/ignoreparent', 'childbranch')],
 
599
                         self.my_location_config._get_matching_sections())
 
600
 
 
601
    def test__get_matching_sections_subdir_trailing_slash(self):
 
602
        self.get_branch_config('/b')
 
603
        self.assertEqual([('/b/', '')],
 
604
                         self.my_location_config._get_matching_sections())
 
605
 
 
606
    def test__get_matching_sections_subdir_child(self):
 
607
        self.get_branch_config('/a/foo')
 
608
        self.assertEqual([('/a/*', ''), ('/a/', 'foo')],
 
609
                         self.my_location_config._get_matching_sections())
 
610
 
 
611
    def test__get_matching_sections_subdir_child_child(self):
 
612
        self.get_branch_config('/a/foo/bar')
 
613
        self.assertEqual([('/a/*', 'bar'), ('/a/', 'foo/bar')],
 
614
                         self.my_location_config._get_matching_sections())
 
615
 
 
616
    def test__get_matching_sections_trailing_slash_with_children(self):
 
617
        self.get_branch_config('/a/')
 
618
        self.assertEqual([('/a/', '')],
 
619
                         self.my_location_config._get_matching_sections())
 
620
 
 
621
    def test__get_matching_sections_explicit_over_glob(self):
 
622
        # XXX: 2006-09-08 jamesh
 
623
        # This test only passes because ord('c') > ord('*').  If there
 
624
        # was a config section for '/a/?', it would get precedence
 
625
        # over '/a/c'.
 
626
        self.get_branch_config('/a/c')
 
627
        self.assertEqual([('/a/c', ''), ('/a/*', ''), ('/a/', 'c')],
 
628
                         self.my_location_config._get_matching_sections())
 
629
 
 
630
    def test__get_option_policy_normal(self):
 
631
        self.get_branch_config('http://www.example.com')
 
632
        self.assertEqual(
 
633
            self.my_location_config._get_config_policy(
 
634
            'http://www.example.com', 'normal_option'),
 
635
            config.POLICY_NONE)
 
636
 
 
637
    def test__get_option_policy_norecurse(self):
 
638
        self.get_branch_config('http://www.example.com')
 
639
        self.assertEqual(
 
640
            self.my_location_config._get_option_policy(
 
641
            'http://www.example.com', 'norecurse_option'),
 
642
            config.POLICY_NORECURSE)
 
643
        # Test old recurse=False setting:
 
644
        self.assertEqual(
 
645
            self.my_location_config._get_option_policy(
 
646
            'http://www.example.com/norecurse', 'normal_option'),
 
647
            config.POLICY_NORECURSE)
 
648
 
 
649
    def test__get_option_policy_normal(self):
 
650
        self.get_branch_config('http://www.example.com')
 
651
        self.assertEqual(
 
652
            self.my_location_config._get_option_policy(
 
653
            'http://www.example.com', 'appendpath_option'),
 
654
            config.POLICY_APPENDPATH)
 
655
 
 
656
    def test_location_without_username(self):
 
657
        self.get_branch_config('http://www.example.com/ignoreparent')
 
658
        self.assertEqual(u'Erik B\u00e5gfors <erik@bagfors.nu>',
 
659
                         self.my_config.username())
 
660
 
 
661
    def test_location_not_listed(self):
 
662
        """Test that the global username is used when no location matches"""
 
663
        self.get_branch_config('/home/robertc/sources')
 
664
        self.assertEqual(u'Erik B\u00e5gfors <erik@bagfors.nu>',
 
665
                         self.my_config.username())
 
666
 
 
667
    def test_overriding_location(self):
 
668
        self.get_branch_config('http://www.example.com/foo')
 
669
        self.assertEqual('Robert Collins <robertc@example.org>',
 
670
                         self.my_config.username())
 
671
 
 
672
    def test_signatures_not_set(self):
 
673
        self.get_branch_config('http://www.example.com',
 
674
                                 global_config=sample_ignore_signatures)
 
675
        self.assertEqual(config.CHECK_ALWAYS,
 
676
                         self.my_config.signature_checking())
 
677
        self.assertEqual(config.SIGN_NEVER,
 
678
                         self.my_config.signing_policy())
 
679
 
 
680
    def test_signatures_never(self):
 
681
        self.get_branch_config('/a/c')
 
682
        self.assertEqual(config.CHECK_NEVER,
 
683
                         self.my_config.signature_checking())
 
684
        
 
685
    def test_signatures_when_available(self):
 
686
        self.get_branch_config('/a/', global_config=sample_ignore_signatures)
 
687
        self.assertEqual(config.CHECK_IF_POSSIBLE,
 
688
                         self.my_config.signature_checking())
 
689
        
 
690
    def test_signatures_always(self):
 
691
        self.get_branch_config('/b')
 
692
        self.assertEqual(config.CHECK_ALWAYS,
 
693
                         self.my_config.signature_checking())
 
694
        
 
695
    def test_gpg_signing_command(self):
 
696
        self.get_branch_config('/b')
 
697
        self.assertEqual("gnome-gpg", self.my_config.gpg_signing_command())
 
698
 
 
699
    def test_gpg_signing_command_missing(self):
 
700
        self.get_branch_config('/a')
 
701
        self.assertEqual("false", self.my_config.gpg_signing_command())
 
702
 
 
703
    def test_get_user_option_global(self):
 
704
        self.get_branch_config('/a')
 
705
        self.assertEqual('something',
 
706
                         self.my_config.get_user_option('user_global_option'))
 
707
 
 
708
    def test_get_user_option_local(self):
 
709
        self.get_branch_config('/a')
 
710
        self.assertEqual('local',
 
711
                         self.my_config.get_user_option('user_local_option'))
 
712
 
 
713
    def test_get_user_option_appendpath(self):
 
714
        # returned as is for the base path:
 
715
        self.get_branch_config('http://www.example.com')
 
716
        self.assertEqual('append',
 
717
                         self.my_config.get_user_option('appendpath_option'))
 
718
        # Extra path components get appended:
 
719
        self.get_branch_config('http://www.example.com/a/b/c')
 
720
        self.assertEqual('append/a/b/c',
 
721
                         self.my_config.get_user_option('appendpath_option'))
 
722
        # Overriden for http://www.example.com/dir, where it is a
 
723
        # normal option:
 
724
        self.get_branch_config('http://www.example.com/dir/a/b/c')
 
725
        self.assertEqual('normal',
 
726
                         self.my_config.get_user_option('appendpath_option'))
 
727
 
 
728
    def test_get_user_option_norecurse(self):
 
729
        self.get_branch_config('http://www.example.com')
 
730
        self.assertEqual('norecurse',
 
731
                         self.my_config.get_user_option('norecurse_option'))
 
732
        self.get_branch_config('http://www.example.com/dir')
 
733
        self.assertEqual(None,
 
734
                         self.my_config.get_user_option('norecurse_option'))
 
735
        # http://www.example.com/norecurse is a recurse=False section
 
736
        # that redefines normal_option.  Subdirectories do not pick up
 
737
        # this redefinition.
 
738
        self.get_branch_config('http://www.example.com/norecurse')
 
739
        self.assertEqual('norecurse',
 
740
                         self.my_config.get_user_option('normal_option'))
 
741
        self.get_branch_config('http://www.example.com/norecurse/subdir')
 
742
        self.assertEqual('normal',
 
743
                         self.my_config.get_user_option('normal_option'))
 
744
 
 
745
    def test_set_user_option_norecurse(self):
 
746
        self.get_branch_config('http://www.example.com')
 
747
        self.my_config.set_user_option('foo', 'bar',
 
748
                                       store=config.STORE_LOCATION_NORECURSE)
 
749
        self.assertEqual(
 
750
            self.my_location_config._get_option_policy(
 
751
            'http://www.example.com', 'foo'),
 
752
            config.POLICY_NORECURSE)
 
753
 
 
754
    def test_set_user_option_appendpath(self):
 
755
        self.get_branch_config('http://www.example.com')
 
756
        self.my_config.set_user_option('foo', 'bar',
 
757
                                       store=config.STORE_LOCATION_APPENDPATH)
 
758
        self.assertEqual(
 
759
            self.my_location_config._get_option_policy(
 
760
            'http://www.example.com', 'foo'),
 
761
            config.POLICY_APPENDPATH)
 
762
 
 
763
    def test_set_user_option_change_policy(self):
 
764
        self.get_branch_config('http://www.example.com')
 
765
        self.my_config.set_user_option('norecurse_option', 'normal',
 
766
                                       store=config.STORE_LOCATION)
 
767
        self.assertEqual(
 
768
            self.my_location_config._get_option_policy(
 
769
            'http://www.example.com', 'norecurse_option'),
 
770
            config.POLICY_NONE)
 
771
 
 
772
    def test_set_user_option_recurse_false_section(self):
 
773
        # The following section has recurse=False set.  The test is to
 
774
        # make sure that a normal option can be added to the section,
 
775
        # converting recurse=False to the norecurse policy.
 
776
        self.get_branch_config('http://www.example.com/norecurse')
 
777
        self.callDeprecated(['The recurse option is deprecated as of 0.14.  '
 
778
                             'The section "http://www.example.com/norecurse" '
 
779
                             'has been converted to use policies.'],
 
780
                            self.my_config.set_user_option,
 
781
                            'foo', 'bar', store=config.STORE_LOCATION)
 
782
        self.assertEqual(
 
783
            self.my_location_config._get_option_policy(
 
784
            'http://www.example.com/norecurse', 'foo'),
 
785
            config.POLICY_NONE)
 
786
        # The previously existing option is still norecurse:
 
787
        self.assertEqual(
 
788
            self.my_location_config._get_option_policy(
 
789
            'http://www.example.com/norecurse', 'normal_option'),
 
790
            config.POLICY_NORECURSE)
 
791
        
 
792
 
 
793
    def test_post_commit_default(self):
 
794
        self.get_branch_config('/a/c')
 
795
        self.assertEqual('bzrlib.tests.test_config.post_commit',
 
796
                         self.my_config.post_commit())
 
797
 
 
798
    def get_branch_config(self, location, global_config=None):
 
799
        if global_config is None:
 
800
            global_file = StringIO(sample_config_text.encode('utf-8'))
 
801
        else:
 
802
            global_file = StringIO(global_config.encode('utf-8'))
 
803
        branches_file = StringIO(sample_branches_text.encode('utf-8'))
 
804
        self.my_config = config.BranchConfig(FakeBranch(location))
 
805
        # Force location config to use specified file
 
806
        self.my_location_config = self.my_config._get_location_config()
 
807
        self.my_location_config._get_parser(branches_file)
 
808
        # Force global config to use specified file
 
809
        self.my_config._get_global_config()._get_parser(global_file)
 
810
 
 
811
    def test_set_user_setting_sets_and_saves(self):
 
812
        self.get_branch_config('/a/c')
 
813
        record = InstrumentedConfigObj("foo")
 
814
        self.my_location_config._parser = record
 
815
 
 
816
        real_mkdir = os.mkdir
 
817
        self.created = False
 
818
        def checked_mkdir(path, mode=0777):
 
819
            self.log('making directory: %s', path)
 
820
            real_mkdir(path, mode)
 
821
            self.created = True
 
822
 
 
823
        os.mkdir = checked_mkdir
 
824
        try:
 
825
            self.callDeprecated(['The recurse option is deprecated as of '
 
826
                                 '0.14.  The section "/a/c" has been '
 
827
                                 'converted to use policies.'],
 
828
                                self.my_config.set_user_option,
 
829
                                'foo', 'bar', store=config.STORE_LOCATION)
 
830
        finally:
 
831
            os.mkdir = real_mkdir
 
832
 
 
833
        self.failUnless(self.created, 'Failed to create ~/.bazaar')
 
834
        self.assertEqual([('__contains__', '/a/c'),
 
835
                          ('__contains__', '/a/c/'),
 
836
                          ('__setitem__', '/a/c', {}),
 
837
                          ('__getitem__', '/a/c'),
 
838
                          ('__setitem__', 'foo', 'bar'),
 
839
                          ('__getitem__', '/a/c'),
 
840
                          ('as_bool', 'recurse'),
 
841
                          ('__getitem__', '/a/c'),
 
842
                          ('__delitem__', 'recurse'),
 
843
                          ('__getitem__', '/a/c'),
 
844
                          ('keys',),
 
845
                          ('__getitem__', '/a/c'),
 
846
                          ('__contains__', 'foo:policy'),
 
847
                          ('write',)],
 
848
                         record._calls[1:])
 
849
 
 
850
    def test_set_user_setting_sets_and_saves2(self):
 
851
        self.get_branch_config('/a/c')
 
852
        self.assertIs(self.my_config.get_user_option('foo'), None)
 
853
        self.my_config.set_user_option('foo', 'bar')
 
854
        self.assertEqual(
 
855
            self.my_config.branch.control_files.files['branch.conf'], 
 
856
            'foo = bar')
 
857
        self.assertEqual(self.my_config.get_user_option('foo'), 'bar')
 
858
        self.my_config.set_user_option('foo', 'baz',
 
859
                                       store=config.STORE_LOCATION)
 
860
        self.assertEqual(self.my_config.get_user_option('foo'), 'baz')
 
861
        self.my_config.set_user_option('foo', 'qux')
 
862
        self.assertEqual(self.my_config.get_user_option('foo'), 'baz')
 
863
        
 
864
 
 
865
precedence_global = 'option = global'
 
866
precedence_branch = 'option = branch'
 
867
precedence_location = """
 
868
[http://]
 
869
recurse = true
 
870
option = recurse
 
871
[http://example.com/specific]
 
872
option = exact
 
873
"""
 
874
 
 
875
 
 
876
class TestBranchConfigItems(TestCaseInTempDir):
 
877
 
 
878
    def get_branch_config(self, global_config=None, location=None, 
 
879
                          location_config=None, branch_data_config=None):
 
880
        my_config = config.BranchConfig(FakeBranch(location))
 
881
        if global_config is not None:
 
882
            global_file = StringIO(global_config.encode('utf-8'))
 
883
            my_config._get_global_config()._get_parser(global_file)
 
884
        self.my_location_config = my_config._get_location_config()
 
885
        if location_config is not None:
 
886
            location_file = StringIO(location_config.encode('utf-8'))
 
887
            self.my_location_config._get_parser(location_file)
 
888
        if branch_data_config is not None:
 
889
            my_config.branch.control_files.files['branch.conf'] = \
 
890
                branch_data_config
 
891
        return my_config
 
892
 
 
893
    def test_user_id(self):
 
894
        branch = FakeBranch(user_id='Robert Collins <robertc@example.net>')
 
895
        my_config = config.BranchConfig(branch)
 
896
        self.assertEqual("Robert Collins <robertc@example.net>",
 
897
                         my_config.username())
 
898
        branch.control_files.email = "John"
 
899
        my_config.set_user_option('email', 
 
900
                                  "Robert Collins <robertc@example.org>")
 
901
        self.assertEqual("John", my_config.username())
 
902
        branch.control_files.email = None
 
903
        self.assertEqual("Robert Collins <robertc@example.org>",
 
904
                         my_config.username())
 
905
 
 
906
    def test_not_set_in_branch(self):
 
907
        my_config = self.get_branch_config(sample_config_text)
 
908
        my_config.branch.control_files.email = None
 
909
        self.assertEqual(u"Erik B\u00e5gfors <erik@bagfors.nu>",
 
910
                         my_config._get_user_id())
 
911
        my_config.branch.control_files.email = "John"
 
912
        self.assertEqual("John", my_config._get_user_id())
 
913
 
 
914
    def test_BZR_EMAIL_OVERRIDES(self):
 
915
        os.environ['BZR_EMAIL'] = "Robert Collins <robertc@example.org>"
 
916
        branch = FakeBranch()
 
917
        my_config = config.BranchConfig(branch)
 
918
        self.assertEqual("Robert Collins <robertc@example.org>",
 
919
                         my_config.username())
 
920
    
 
921
    def test_signatures_forced(self):
 
922
        my_config = self.get_branch_config(
 
923
            global_config=sample_always_signatures)
 
924
        self.assertEqual(config.CHECK_NEVER, my_config.signature_checking())
 
925
        self.assertEqual(config.SIGN_ALWAYS, my_config.signing_policy())
 
926
        self.assertTrue(my_config.signature_needed())
 
927
 
 
928
    def test_signatures_forced_branch(self):
 
929
        my_config = self.get_branch_config(
 
930
            global_config=sample_ignore_signatures,
 
931
            branch_data_config=sample_always_signatures)
 
932
        self.assertEqual(config.CHECK_NEVER, my_config.signature_checking())
 
933
        self.assertEqual(config.SIGN_ALWAYS, my_config.signing_policy())
 
934
        self.assertTrue(my_config.signature_needed())
 
935
 
 
936
    def test_gpg_signing_command(self):
 
937
        my_config = self.get_branch_config(
 
938
            # branch data cannot set gpg_signing_command
 
939
            branch_data_config="gpg_signing_command=pgp")
 
940
        config_file = StringIO(sample_config_text.encode('utf-8'))
 
941
        my_config._get_global_config()._get_parser(config_file)
 
942
        self.assertEqual('gnome-gpg', my_config.gpg_signing_command())
 
943
 
 
944
    def test_get_user_option_global(self):
 
945
        branch = FakeBranch()
 
946
        my_config = config.BranchConfig(branch)
 
947
        config_file = StringIO(sample_config_text.encode('utf-8'))
 
948
        (my_config._get_global_config()._get_parser(config_file))
 
949
        self.assertEqual('something',
 
950
                         my_config.get_user_option('user_global_option'))
 
951
 
 
952
    def test_post_commit_default(self):
 
953
        branch = FakeBranch()
 
954
        my_config = self.get_branch_config(sample_config_text, '/a/c',
 
955
                                           sample_branches_text)
 
956
        self.assertEqual(my_config.branch.base, '/a/c')
 
957
        self.assertEqual('bzrlib.tests.test_config.post_commit',
 
958
                         my_config.post_commit())
 
959
        my_config.set_user_option('post_commit', 'rmtree_root')
 
960
        # post-commit is ignored when bresent in branch data
 
961
        self.assertEqual('bzrlib.tests.test_config.post_commit',
 
962
                         my_config.post_commit())
 
963
        my_config.set_user_option('post_commit', 'rmtree_root',
 
964
                                  store=config.STORE_LOCATION)
 
965
        self.assertEqual('rmtree_root', my_config.post_commit())
 
966
 
 
967
    def test_config_precedence(self):
 
968
        my_config = self.get_branch_config(global_config=precedence_global)
 
969
        self.assertEqual(my_config.get_user_option('option'), 'global')
 
970
        my_config = self.get_branch_config(global_config=precedence_global, 
 
971
                                      branch_data_config=precedence_branch)
 
972
        self.assertEqual(my_config.get_user_option('option'), 'branch')
 
973
        my_config = self.get_branch_config(global_config=precedence_global, 
 
974
                                      branch_data_config=precedence_branch,
 
975
                                      location_config=precedence_location)
 
976
        self.assertEqual(my_config.get_user_option('option'), 'recurse')
 
977
        my_config = self.get_branch_config(global_config=precedence_global, 
 
978
                                      branch_data_config=precedence_branch,
 
979
                                      location_config=precedence_location,
 
980
                                      location='http://example.com/specific')
 
981
        self.assertEqual(my_config.get_user_option('option'), 'exact')
 
982
 
 
983
 
 
984
class TestMailAddressExtraction(TestCase):
 
985
 
 
986
    def test_extract_email_address(self):
 
987
        self.assertEqual('jane@test.com',
 
988
                         config.extract_email_address('Jane <jane@test.com>'))
 
989
        self.assertRaises(errors.NoEmailInUsername,
 
990
                          config.extract_email_address, 'Jane Tester')