/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
5557.1.7 by John Arbash Meinel
Merge in the bzr.dev 5582
1
# Copyright (C) 2005-2011 Canonical Ltd
1442.1.1 by Robert Collins
move config_dir into bzrlib.config
2
#
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
7
#
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
12
#
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
4183.7.1 by Sabin Iacob
update FSF mailing address
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
1442.1.1 by Robert Collins
move config_dir into bzrlib.config
16
17
"""Tests for finding and reading the bzr config file[s]."""
18
# import system imports here
1442.1.2 by Robert Collins
create a config module - there is enough config logic to make this worthwhile, and start testing config processing.
19
from cStringIO import StringIO
1442.1.1 by Robert Collins
move config_dir into bzrlib.config
20
import os
21
import sys
5345.5.4 by Vincent Ladeuil
Start implementing config files locking.
22
import threading
1442.1.1 by Robert Collins
move config_dir into bzrlib.config
23
5533.2.1 by Vincent Ladeuil
``bzr config`` properly displays list values
24
25
from testtools import matchers
26
1442.1.1 by Robert Collins
move config_dir into bzrlib.config
27
#import bzrlib specific imports here
1878.1.3 by John Arbash Meinel
some test cleanups
28
from bzrlib import (
2900.2.4 by Vincent Ladeuil
Cosmetic changes.
29
    branch,
30
    bzrdir,
1878.1.3 by John Arbash Meinel
some test cleanups
31
    config,
4603.1.10 by Aaron Bentley
Provide change editor via config.
32
    diff,
1878.1.3 by John Arbash Meinel
some test cleanups
33
    errors,
34
    osutils,
2681.1.8 by Aaron Bentley
Add Thunderbird support to bzr send
35
    mail_client,
5321.1.89 by Gordon Tyler
Moved mergetools config tests to bzrlib.tests.test_config.
36
    mergetools,
2900.2.14 by Vincent Ladeuil
More tests.
37
    ui,
1878.1.3 by John Arbash Meinel
some test cleanups
38
    urlutils,
5743.5.10 by Vincent Ladeuil
Parametrize the generic tests against the concrete stores.
39
    registry,
5743.8.21 by Vincent Ladeuil
Add test for config load hook for remote configs.
40
    remote,
2900.2.4 by Vincent Ladeuil
Cosmetic changes.
41
    tests,
1551.15.35 by Aaron Bentley
Warn when setting config values that will be masked (#122286)
42
    trace,
3242.1.2 by Aaron Bentley
Turn BzrDirConfig into TransportConfig, reduce code duplication
43
    transport,
1878.1.3 by John Arbash Meinel
some test cleanups
44
    )
5743.13.1 by Vincent Ladeuil
Deprecate _get_editor to identify its usages.
45
from bzrlib.symbol_versioning import (
46
    deprecated_in,
47
    deprecated_method,
48
    )
5743.8.21 by Vincent Ladeuil
Add test for config load hook for remote configs.
49
from bzrlib.transport import remote as transport_remote
5050.72.1 by Martin Pool
Set email address from /etc/mailname if possible
50
from bzrlib.tests import (
51
    features,
5506.2.1 by Vincent Ladeuil
Implements ``bzr config --active option`` displaying only the value.
52
    scenarios,
5743.8.17 by Vincent Ladeuil
Add config old_get hook for remote config.
53
    test_server,
5050.72.1 by Martin Pool
Set email address from /etc/mailname if possible
54
    )
2991.2.4 by Vincent Ladeuil
Various fixes following local testing environment rebuild.
55
from bzrlib.util.configobj import configobj
1442.1.1 by Robert Collins
move config_dir into bzrlib.config
56
57
5345.5.7 by Vincent Ladeuil
Make LocationConfig use a lock too.
58
def lockable_config_scenarios():
59
    return [
60
        ('global',
61
         {'config_class': config.GlobalConfig,
62
          'config_args': [],
63
          'config_section': 'DEFAULT'}),
64
        ('locations',
65
         {'config_class': config.LocationConfig,
66
          'config_args': ['.'],
67
          'config_section': '.'}),]
68
69
5506.2.1 by Vincent Ladeuil
Implements ``bzr config --active option`` displaying only the value.
70
load_tests = scenarios.load_tests_apply_scenarios
5345.5.7 by Vincent Ladeuil
Make LocationConfig use a lock too.
71
5743.6.27 by Vincent Ladeuil
Move the test registries to bzrlib.config so plugins will be able to use
72
# Register helpers to build stores
73
config.test_store_builder_registry.register(
5743.5.13 by Vincent Ladeuil
Merge config-abstract-store into config-concrete-stores resolving conflicts
74
    'configobj', lambda test: config.IniFileStore(test.get_transport(),
75
                                                  'configobj.conf'))
5743.6.27 by Vincent Ladeuil
Move the test registries to bzrlib.config so plugins will be able to use
76
config.test_store_builder_registry.register(
5743.5.10 by Vincent Ladeuil
Parametrize the generic tests against the concrete stores.
77
    'bazaar', lambda test: config.GlobalStore())
5743.6.27 by Vincent Ladeuil
Move the test registries to bzrlib.config so plugins will be able to use
78
config.test_store_builder_registry.register(
5743.5.10 by Vincent Ladeuil
Parametrize the generic tests against the concrete stores.
79
    'location', lambda test: config.LocationStore())
5743.6.27 by Vincent Ladeuil
Move the test registries to bzrlib.config so plugins will be able to use
80
5743.10.2 by Vincent Ladeuil
Make sure RemoteBranch are supported as well, relying on the vfs API.
81
82
def build_backing_branch(test, relpath,
83
                         transport_class=None, server_class=None):
84
    """Test helper to create a backing branch only once.
85
86
    Some tests needs multiple stores/stacks to check concurrent update
87
    behaviours. As such, they need to build different branch *objects* even if
88
    they share the branch on disk.
89
90
    :param relpath: The relative path to the branch. (Note that the helper
91
        should always specify the same relpath).
92
93
    :param transport_class: The Transport class the test needs to use.
94
95
    :param server_class: The server associated with the ``transport_class``
96
        above.
97
5743.10.9 by Vincent Ladeuil
Fix use of none where neither is required.
98
    Either both or neither of ``transport_class`` and ``server_class`` should
99
    be specified.
5743.10.2 by Vincent Ladeuil
Make sure RemoteBranch are supported as well, relying on the vfs API.
100
    """
101
    if transport_class is not None and server_class is not None:
102
        test.transport_class = transport_class
103
        test.transport_server = server_class
104
    elif not (transport_class is None and server_class is None):
105
        raise AssertionError('Specify both ``transport_class`` and '
5743.10.9 by Vincent Ladeuil
Fix use of none where neither is required.
106
                             '``server_class`` or neither of them')
5743.10.2 by Vincent Ladeuil
Make sure RemoteBranch are supported as well, relying on the vfs API.
107
    if getattr(test, 'backing_branch', None) is None:
108
        # First call, let's build the branch on disk
109
        test.backing_branch = test.make_branch(relpath)
110
111
5743.6.27 by Vincent Ladeuil
Move the test registries to bzrlib.config so plugins will be able to use
112
def build_branch_store(test):
5743.10.2 by Vincent Ladeuil
Make sure RemoteBranch are supported as well, relying on the vfs API.
113
    build_backing_branch(test, 'branch')
114
    b = branch.Branch.open('branch')
115
    return config.BranchStore(b)
5743.6.27 by Vincent Ladeuil
Move the test registries to bzrlib.config so plugins will be able to use
116
config.test_store_builder_registry.register('branch', build_branch_store)
117
118
5743.10.2 by Vincent Ladeuil
Make sure RemoteBranch are supported as well, relying on the vfs API.
119
def build_remote_branch_store(test):
120
    # There is only one permutation (but we won't be able to handle more with
121
    # this design anyway)
5743.8.21 by Vincent Ladeuil
Add test for config load hook for remote configs.
122
    (transport_class,
123
     server_class) = transport_remote.get_test_permutations()[0]
5743.10.2 by Vincent Ladeuil
Make sure RemoteBranch are supported as well, relying on the vfs API.
124
    build_backing_branch(test, 'branch', transport_class, server_class)
125
    b = branch.Branch.open(test.get_url('branch'))
126
    return config.BranchStore(b)
127
config.test_store_builder_registry.register('remote_branch',
128
                                            build_remote_branch_store)
129
130
5743.6.27 by Vincent Ladeuil
Move the test registries to bzrlib.config so plugins will be able to use
131
config.test_stack_builder_registry.register(
132
    'bazaar', lambda test: config.GlobalStack())
133
config.test_stack_builder_registry.register(
134
    'location', lambda test: config.LocationStack('.'))
135
5743.10.2 by Vincent Ladeuil
Make sure RemoteBranch are supported as well, relying on the vfs API.
136
5743.6.27 by Vincent Ladeuil
Move the test registries to bzrlib.config so plugins will be able to use
137
def build_branch_stack(test):
5743.10.2 by Vincent Ladeuil
Make sure RemoteBranch are supported as well, relying on the vfs API.
138
    build_backing_branch(test, 'branch')
139
    b = branch.Branch.open('branch')
140
    return config.BranchStack(b)
5743.6.27 by Vincent Ladeuil
Move the test registries to bzrlib.config so plugins will be able to use
141
config.test_stack_builder_registry.register('branch', build_branch_stack)
142
5345.5.7 by Vincent Ladeuil
Make LocationConfig use a lock too.
143
5743.10.2 by Vincent Ladeuil
Make sure RemoteBranch are supported as well, relying on the vfs API.
144
def build_remote_branch_stack(test):
145
    # There is only one permutation (but we won't be able to handle more with
146
    # this design anyway)
5743.8.21 by Vincent Ladeuil
Add test for config load hook for remote configs.
147
    (transport_class,
148
     server_class) = transport_remote.get_test_permutations()[0]
5743.10.2 by Vincent Ladeuil
Make sure RemoteBranch are supported as well, relying on the vfs API.
149
    build_backing_branch(test, 'branch', transport_class, server_class)
150
    b = branch.Branch.open(test.get_url('branch'))
151
    return config.BranchStack(b)
152
config.test_stack_builder_registry.register('remote_branch',
153
                                            build_remote_branch_stack)
154
155
1553.6.12 by Erik Bågfors
remove AliasConfig, based on input from abentley
156
sample_long_alias="log -r-15..-1 --line"
2120.6.2 by James Henstridge
remove get_matching_sections() norecurse tests, since that feature is handled in the config policy code now
157
sample_config_text = u"""
158
[DEFAULT]
159
email=Erik B\u00e5gfors <erik@bagfors.nu>
160
editor=vim
4603.1.20 by Aaron Bentley
Use string.Template substitution with @ as delimiter.
161
change_editor=vimdiff -of @new_path @old_path
2120.6.2 by James Henstridge
remove get_matching_sections() norecurse tests, since that feature is handled in the config policy code now
162
gpg_signing_command=gnome-gpg
163
log_format=short
164
user_global_option=something
5321.1.108 by Gordon Tyler
Changed known merge tools into a default set of merge tools that are always defined but can be overridden by user-defined merge tools.
165
bzr.mergetool.sometool=sometool {base} {this} {other} -o {result}
5321.2.3 by Vincent Ladeuil
Prefix mergetools option names with 'bzr.'.
166
bzr.mergetool.funkytool=funkytool "arg with spaces" {this_temp}
5321.1.108 by Gordon Tyler
Changed known merge tools into a default set of merge tools that are always defined but can be overridden by user-defined merge tools.
167
bzr.default_mergetool=sometool
2120.6.2 by James Henstridge
remove get_matching_sections() norecurse tests, since that feature is handled in the config policy code now
168
[ALIASES]
169
h=help
170
ll=""" + sample_long_alias + "\n"
171
172
173
sample_always_signatures = """
174
[DEFAULT]
175
check_signatures=ignore
176
create_signatures=always
177
"""
178
179
sample_ignore_signatures = """
180
[DEFAULT]
181
check_signatures=require
182
create_signatures=never
183
"""
184
185
sample_maybe_signatures = """
186
[DEFAULT]
187
check_signatures=ignore
188
create_signatures=when-required
189
"""
190
191
sample_branches_text = """
192
[http://www.example.com]
193
# Top level policy
194
email=Robert Collins <robertc@example.org>
2120.6.3 by James Henstridge
add some more tests for getting policy options, and behaviour of get_user_option in the presence of config policies
195
normal_option = normal
196
appendpath_option = append
2120.6.8 by James Henstridge
Change syntax for setting config option policies. Rather than
197
appendpath_option:policy = appendpath
2120.6.3 by James Henstridge
add some more tests for getting policy options, and behaviour of get_user_option in the presence of config policies
198
norecurse_option = norecurse
2120.6.8 by James Henstridge
Change syntax for setting config option policies. Rather than
199
norecurse_option:policy = norecurse
2120.6.2 by James Henstridge
remove get_matching_sections() norecurse tests, since that feature is handled in the config policy code now
200
[http://www.example.com/ignoreparent]
201
# different project: ignore parent dir config
202
ignore_parents=true
203
[http://www.example.com/norecurse]
204
# configuration items that only apply to this dir
205
recurse=false
2120.6.3 by James Henstridge
add some more tests for getting policy options, and behaviour of get_user_option in the presence of config policies
206
normal_option = norecurse
207
[http://www.example.com/dir]
208
appendpath_option = normal
2120.6.2 by James Henstridge
remove get_matching_sections() norecurse tests, since that feature is handled in the config policy code now
209
[/b/]
210
check_signatures=require
211
# test trailing / matching with no children
212
[/a/]
213
check_signatures=check-available
214
gpg_signing_command=false
215
user_local_option=local
216
# test trailing / matching
217
[/a/*]
218
#subdirs will match but not the parent
219
[/a/c]
220
check_signatures=ignore
221
post_commit=bzrlib.tests.test_config.post_commit
222
#testing explicit beats globs
223
"""
1553.6.3 by Erik Bågfors
tests for AliasesConfig
224
1442.1.8 by Robert Collins
preparing some tests for LocationConfig
225
5533.2.1 by Vincent Ladeuil
``bzr config`` properly displays list values
226
def create_configs(test):
227
    """Create configuration files for a given test.
228
229
    This requires creating a tree (and populate the ``test.tree`` attribute)
230
    and its associated branch and will populate the following attributes:
231
232
    - branch_config: A BranchConfig for the associated branch.
233
234
    - locations_config : A LocationConfig for the associated branch
235
236
    - bazaar_config: A GlobalConfig.
237
238
    The tree and branch are created in a 'tree' subdirectory so the tests can
239
    still use the test directory to stay outside of the branch.
240
    """
241
    tree = test.make_branch_and_tree('tree')
242
    test.tree = tree
243
    test.branch_config = config.BranchConfig(tree.branch)
244
    test.locations_config = config.LocationConfig(tree.basedir)
245
    test.bazaar_config = config.GlobalConfig()
246
5533.2.4 by Vincent Ladeuil
Fix whitespace issue.
247
5533.2.1 by Vincent Ladeuil
``bzr config`` properly displays list values
248
def create_configs_with_file_option(test):
249
    """Create configuration files with a ``file`` option set in each.
250
251
    This builds on ``create_configs`` and add one ``file`` option in each
252
    configuration with a value which allows identifying the configuration file.
253
    """
254
    create_configs(test)
255
    test.bazaar_config.set_user_option('file', 'bazaar')
256
    test.locations_config.set_user_option('file', 'locations')
257
    test.branch_config.set_user_option('file', 'branch')
258
259
260
class TestOptionsMixin:
261
262
    def assertOptions(self, expected, conf):
263
        # We don't care about the parser (as it will make tests hard to write
264
        # and error-prone anyway)
265
        self.assertThat([opt[:4] for opt in conf._get_options()],
266
                        matchers.Equals(expected))
267
268
1474 by Robert Collins
Merge from Aaron Bentley.
269
class InstrumentedConfigObj(object):
270
    """A config obj look-enough-alike to record calls made to it."""
271
1490 by Robert Collins
Implement a 'bzr push' command, with saved locations; update diff to return 1.
272
    def __contains__(self, thing):
273
        self._calls.append(('__contains__', thing))
274
        return False
275
276
    def __getitem__(self, key):
277
        self._calls.append(('__getitem__', key))
278
        return self
279
1551.2.20 by Aaron Bentley
Treated config files as utf-8
280
    def __init__(self, input, encoding=None):
281
        self._calls = [('__init__', input, encoding)]
1442.1.2 by Robert Collins
create a config module - there is enough config logic to make this worthwhile, and start testing config processing.
282
1490 by Robert Collins
Implement a 'bzr push' command, with saved locations; update diff to return 1.
283
    def __setitem__(self, key, value):
284
        self._calls.append(('__setitem__', key, value))
285
2120.6.4 by James Henstridge
add support for specifying policy when storing options
286
    def __delitem__(self, key):
287
        self._calls.append(('__delitem__', key))
288
289
    def keys(self):
290
        self._calls.append(('keys',))
291
        return []
292
5345.1.8 by Vincent Ladeuil
Make the test_listen_to_the_last_speaker pass and fix fallouts.
293
    def reload(self):
294
        self._calls.append(('reload',))
295
1551.2.49 by abentley
Made ConfigObj output binary-identical files on win32 and *nix
296
    def write(self, arg):
1490 by Robert Collins
Implement a 'bzr push' command, with saved locations; update diff to return 1.
297
        self._calls.append(('write',))
298
2120.6.4 by James Henstridge
add support for specifying policy when storing options
299
    def as_bool(self, value):
300
        self._calls.append(('as_bool', value))
301
        return False
302
303
    def get_value(self, section, name):
304
        self._calls.append(('get_value', section, name))
305
        return None
306
1442.1.2 by Robert Collins
create a config module - there is enough config logic to make this worthwhile, and start testing config processing.
307
1442.1.6 by Robert Collins
first stage major overhaul of configs, giving use BranchConfigs, LocationConfigs and GlobalConfigs
308
class FakeBranch(object):
309
1770.2.5 by Aaron Bentley
Integrate branch.conf into BranchConfig
310
    def __init__(self, base=None, user_id=None):
311
        if base is None:
312
            self.base = "http://example.com/branches/demo"
313
        else:
314
            self.base = base
3407.2.13 by Martin Pool
Remove indirection through control_files to get transports
315
        self._transport = self.control_files = \
316
            FakeControlFilesAndTransport(user_id=user_id)
1770.2.5 by Aaron Bentley
Integrate branch.conf into BranchConfig
317
4226.1.7 by Robert Collins
Alter test_config.FakeBranch in accordance with the Branch change to have a _get_config.
318
    def _get_config(self):
319
        return config.TransportConfig(self._transport, 'branch.conf')
320
1770.2.5 by Aaron Bentley
Integrate branch.conf into BranchConfig
321
    def lock_write(self):
322
        pass
323
324
    def unlock(self):
325
        pass
1185.65.11 by Robert Collins
Disable inheritance for getting at LockableFiles, rather use composition.
326
327
3407.2.13 by Martin Pool
Remove indirection through control_files to get transports
328
class FakeControlFilesAndTransport(object):
1185.65.11 by Robert Collins
Disable inheritance for getting at LockableFiles, rather use composition.
329
1770.2.5 by Aaron Bentley
Integrate branch.conf into BranchConfig
330
    def __init__(self, user_id=None):
331
        self.files = {}
3388.2.3 by Martin Pool
Fix up more uses of LockableFiles.get_utf8 in tests
332
        if user_id:
333
            self.files['email'] = user_id
3242.1.2 by Aaron Bentley
Turn BzrDirConfig into TransportConfig, reduce code duplication
334
        self._transport = self
1442.1.6 by Robert Collins
first stage major overhaul of configs, giving use BranchConfigs, LocationConfigs and GlobalConfigs
335
1185.65.29 by Robert Collins
Implement final review suggestions.
336
    def get_utf8(self, filename):
3388.2.3 by Martin Pool
Fix up more uses of LockableFiles.get_utf8 in tests
337
        # from LockableFiles
338
        raise AssertionError("get_utf8 should no longer be used")
1442.1.6 by Robert Collins
first stage major overhaul of configs, giving use BranchConfigs, LocationConfigs and GlobalConfigs
339
1770.2.5 by Aaron Bentley
Integrate branch.conf into BranchConfig
340
    def get(self, filename):
3388.2.3 by Martin Pool
Fix up more uses of LockableFiles.get_utf8 in tests
341
        # from Transport
1770.2.6 by Aaron Bentley
Ensure branch.conf works properly
342
        try:
343
            return StringIO(self.files[filename])
344
        except KeyError:
345
            raise errors.NoSuchFile(filename)
1770.2.5 by Aaron Bentley
Integrate branch.conf into BranchConfig
346
3388.2.3 by Martin Pool
Fix up more uses of LockableFiles.get_utf8 in tests
347
    def get_bytes(self, filename):
348
        # from Transport
349
        try:
350
            return self.files[filename]
351
        except KeyError:
352
            raise errors.NoSuchFile(filename)
353
1770.2.5 by Aaron Bentley
Integrate branch.conf into BranchConfig
354
    def put(self, filename, fileobj):
1770.2.6 by Aaron Bentley
Ensure branch.conf works properly
355
        self.files[filename] = fileobj.read()
1770.2.5 by Aaron Bentley
Integrate branch.conf into BranchConfig
356
3242.1.2 by Aaron Bentley
Turn BzrDirConfig into TransportConfig, reduce code duplication
357
    def put_file(self, filename, fileobj):
358
        return self.put(filename, fileobj)
359
1442.1.6 by Robert Collins
first stage major overhaul of configs, giving use BranchConfigs, LocationConfigs and GlobalConfigs
360
361
class InstrumentedConfig(config.Config):
362
    """An instrumented config that supplies stubs for template methods."""
2991.2.2 by Vincent Ladeuil
No tests worth adding after upgrading to configobj-4.4.0.
363
1442.1.6 by Robert Collins
first stage major overhaul of configs, giving use BranchConfigs, LocationConfigs and GlobalConfigs
364
    def __init__(self):
365
        super(InstrumentedConfig, self).__init__()
366
        self._calls = []
1442.1.15 by Robert Collins
make getting the signature checking policy a template method
367
        self._signatures = config.CHECK_NEVER
1442.1.6 by Robert Collins
first stage major overhaul of configs, giving use BranchConfigs, LocationConfigs and GlobalConfigs
368
369
    def _get_user_id(self):
370
        self._calls.append('_get_user_id')
371
        return "Robert Collins <robert.collins@example.org>"
372
1442.1.15 by Robert Collins
make getting the signature checking policy a template method
373
    def _get_signature_checking(self):
374
        self._calls.append('_get_signature_checking')
375
        return self._signatures
376
4603.1.10 by Aaron Bentley
Provide change editor via config.
377
    def _get_change_editor(self):
378
        self._calls.append('_get_change_editor')
4603.1.20 by Aaron Bentley
Use string.Template substitution with @ as delimiter.
379
        return 'vimdiff -fo @new_path @old_path'
4603.1.10 by Aaron Bentley
Provide change editor via config.
380
1442.1.6 by Robert Collins
first stage major overhaul of configs, giving use BranchConfigs, LocationConfigs and GlobalConfigs
381
1556.2.2 by Aaron Bentley
Fixed get_bool
382
bool_config = """[DEFAULT]
383
active = true
384
inactive = false
385
[UPPERCASE]
386
active = True
387
nonactive = False
388
"""
2991.2.2 by Vincent Ladeuil
No tests worth adding after upgrading to configobj-4.4.0.
389
390
2900.2.4 by Vincent Ladeuil
Cosmetic changes.
391
class TestConfigObj(tests.TestCase):
3221.7.4 by Matt Nordhoff
Add test for bug #86838.
392
1556.2.2 by Aaron Bentley
Fixed get_bool
393
    def test_get_bool(self):
2991.2.2 by Vincent Ladeuil
No tests worth adding after upgrading to configobj-4.4.0.
394
        co = config.ConfigObj(StringIO(bool_config))
1556.2.2 by Aaron Bentley
Fixed get_bool
395
        self.assertIs(co.get_bool('DEFAULT', 'active'), True)
396
        self.assertIs(co.get_bool('DEFAULT', 'inactive'), False)
397
        self.assertIs(co.get_bool('UPPERCASE', 'active'), True)
398
        self.assertIs(co.get_bool('UPPERCASE', 'nonactive'), False)
399
3221.7.4 by Matt Nordhoff
Add test for bug #86838.
400
    def test_hash_sign_in_value(self):
401
        """
402
        Before 4.5.0, ConfigObj did not quote # signs in values, so they'd be
403
        treated as comments when read in again. (#86838)
404
        """
405
        co = config.ConfigObj()
406
        co['test'] = 'foo#bar'
5050.62.14 by Alexander Belchenko
don't use lines in the tests, and better comment about the corresponding bug in configobj; avoid using write() method without outfile parameter.
407
        outfile = StringIO()
408
        co.write(outfile=outfile)
409
        lines = outfile.getvalue().splitlines()
3221.7.4 by Matt Nordhoff
Add test for bug #86838.
410
        self.assertEqual(lines, ['test = "foo#bar"'])
411
        co2 = config.ConfigObj(lines)
412
        self.assertEqual(co2['test'], 'foo#bar')
413
5050.62.10 by Alexander Belchenko
test to illustrate the problem
414
    def test_triple_quotes(self):
415
        # Bug #710410: if the value string has triple quotes
416
        # then ConfigObj versions up to 4.7.2 will quote them wrong
5050.62.12 by Alexander Belchenko
added NEWS entry
417
        # and won't able to read them back
5050.62.10 by Alexander Belchenko
test to illustrate the problem
418
        triple_quotes_value = '''spam
419
""" that's my spam """
420
eggs'''
421
        co = config.ConfigObj()
422
        co['test'] = triple_quotes_value
5050.62.14 by Alexander Belchenko
don't use lines in the tests, and better comment about the corresponding bug in configobj; avoid using write() method without outfile parameter.
423
        # While writing this test another bug in ConfigObj has been found:
5050.62.10 by Alexander Belchenko
test to illustrate the problem
424
        # method co.write() without arguments produces list of lines
425
        # one option per line, and multiline values are not split
426
        # across multiple lines,
5050.62.14 by Alexander Belchenko
don't use lines in the tests, and better comment about the corresponding bug in configobj; avoid using write() method without outfile parameter.
427
        # and that breaks the parsing these lines back by ConfigObj.
428
        # This issue only affects test, but it's better to avoid
429
        # `co.write()` construct at all.
430
        # [bialix 20110222] bug report sent to ConfigObj's author
5050.62.10 by Alexander Belchenko
test to illustrate the problem
431
        outfile = StringIO()
432
        co.write(outfile=outfile)
5050.62.14 by Alexander Belchenko
don't use lines in the tests, and better comment about the corresponding bug in configobj; avoid using write() method without outfile parameter.
433
        output = outfile.getvalue()
5050.62.10 by Alexander Belchenko
test to illustrate the problem
434
        # now we're trying to read it back
5050.62.14 by Alexander Belchenko
don't use lines in the tests, and better comment about the corresponding bug in configobj; avoid using write() method without outfile parameter.
435
        co2 = config.ConfigObj(StringIO(output))
5050.62.10 by Alexander Belchenko
test to illustrate the problem
436
        self.assertEquals(triple_quotes_value, co2['test'])
437
1556.2.2 by Aaron Bentley
Fixed get_bool
438
2900.1.1 by Vincent Ladeuil
439
erroneous_config = """[section] # line 1
440
good=good # line 2
441
[section] # line 3
442
whocares=notme # line 4
443
"""
2991.2.2 by Vincent Ladeuil
No tests worth adding after upgrading to configobj-4.4.0.
444
445
2900.2.4 by Vincent Ladeuil
Cosmetic changes.
446
class TestConfigObjErrors(tests.TestCase):
2900.1.1 by Vincent Ladeuil
447
448
    def test_duplicate_section_name_error_line(self):
449
        try:
2991.2.2 by Vincent Ladeuil
No tests worth adding after upgrading to configobj-4.4.0.
450
            co = configobj.ConfigObj(StringIO(erroneous_config),
451
                                     raise_errors=True)
2900.1.1 by Vincent Ladeuil
452
        except config.configobj.DuplicateError, e:
453
            self.assertEqual(3, e.line_number)
454
        else:
455
            self.fail('Error in config file not detected')
456
2991.2.2 by Vincent Ladeuil
No tests worth adding after upgrading to configobj-4.4.0.
457
2900.2.4 by Vincent Ladeuil
Cosmetic changes.
458
class TestConfig(tests.TestCase):
1442.1.6 by Robert Collins
first stage major overhaul of configs, giving use BranchConfigs, LocationConfigs and GlobalConfigs
459
460
    def test_constructs(self):
461
        config.Config()
2991.2.2 by Vincent Ladeuil
No tests worth adding after upgrading to configobj-4.4.0.
462
1442.1.6 by Robert Collins
first stage major overhaul of configs, giving use BranchConfigs, LocationConfigs and GlobalConfigs
463
    def test_no_default_editor(self):
5743.13.1 by Vincent Ladeuil
Deprecate _get_editor to identify its usages.
464
        self.assertRaises(
465
            NotImplementedError,
466
            self.applyDeprecated, deprecated_in((2, 4, 0)),
467
            config.Config().get_editor)
1442.1.6 by Robert Collins
first stage major overhaul of configs, giving use BranchConfigs, LocationConfigs and GlobalConfigs
468
469
    def test_user_email(self):
470
        my_config = InstrumentedConfig()
471
        self.assertEqual('robert.collins@example.org', my_config.user_email())
472
        self.assertEqual(['_get_user_id'], my_config._calls)
473
474
    def test_username(self):
475
        my_config = InstrumentedConfig()
476
        self.assertEqual('Robert Collins <robert.collins@example.org>',
477
                         my_config.username())
478
        self.assertEqual(['_get_user_id'], my_config._calls)
1442.1.14 by Robert Collins
Create a default signature checking policy of CHECK_IF_POSSIBLE
479
480
    def test_signatures_default(self):
481
        my_config = config.Config()
1770.2.1 by Aaron Bentley
Use create_signature for signing policy, deprecate check_signatures for this
482
        self.assertFalse(my_config.signature_needed())
1442.1.14 by Robert Collins
Create a default signature checking policy of CHECK_IF_POSSIBLE
483
        self.assertEqual(config.CHECK_IF_POSSIBLE,
484
                         my_config.signature_checking())
1770.2.1 by Aaron Bentley
Use create_signature for signing policy, deprecate check_signatures for this
485
        self.assertEqual(config.SIGN_WHEN_REQUIRED,
486
                         my_config.signing_policy())
1442.1.14 by Robert Collins
Create a default signature checking policy of CHECK_IF_POSSIBLE
487
1442.1.15 by Robert Collins
make getting the signature checking policy a template method
488
    def test_signatures_template_method(self):
489
        my_config = InstrumentedConfig()
490
        self.assertEqual(config.CHECK_NEVER, my_config.signature_checking())
491
        self.assertEqual(['_get_signature_checking'], my_config._calls)
492
493
    def test_signatures_template_method_none(self):
494
        my_config = InstrumentedConfig()
495
        my_config._signatures = None
496
        self.assertEqual(config.CHECK_IF_POSSIBLE,
497
                         my_config.signature_checking())
498
        self.assertEqual(['_get_signature_checking'], my_config._calls)
499
1442.1.56 by Robert Collins
gpg_signing_command configuration item
500
    def test_gpg_signing_command_default(self):
501
        my_config = config.Config()
502
        self.assertEqual('gpg', my_config.gpg_signing_command())
503
1442.1.69 by Robert Collins
config.Config has a 'get_user_option' call that accepts an option name.
504
    def test_get_user_option_default(self):
505
        my_config = config.Config()
506
        self.assertEqual(None, my_config.get_user_option('no_option'))
507
1472 by Robert Collins
post commit hook, first pass implementation
508
    def test_post_commit_default(self):
509
        my_config = config.Config()
510
        self.assertEqual(None, my_config.post_commit())
511
1553.2.9 by Erik Bågfors
log_formatter => log_format for "named" formatters
512
    def test_log_format_default(self):
1553.2.8 by Erik Bågfors
tests for config log_formatter
513
        my_config = config.Config()
1553.2.9 by Erik Bågfors
log_formatter => log_format for "named" formatters
514
        self.assertEqual('long', my_config.log_format())
1553.2.8 by Erik Bågfors
tests for config log_formatter
515
4603.1.10 by Aaron Bentley
Provide change editor via config.
516
    def test_get_change_editor(self):
517
        my_config = InstrumentedConfig()
518
        change_editor = my_config.get_change_editor('old_tree', 'new_tree')
519
        self.assertEqual(['_get_change_editor'], my_config._calls)
520
        self.assertIs(diff.DiffFromTool, change_editor.__class__)
4603.1.20 by Aaron Bentley
Use string.Template substitution with @ as delimiter.
521
        self.assertEqual(['vimdiff', '-fo', '@new_path', '@old_path'],
4603.1.10 by Aaron Bentley
Provide change editor via config.
522
                         change_editor.command_template)
523
1442.1.6 by Robert Collins
first stage major overhaul of configs, giving use BranchConfigs, LocationConfigs and GlobalConfigs
524
2900.2.4 by Vincent Ladeuil
Cosmetic changes.
525
class TestConfigPath(tests.TestCase):
1442.1.1 by Robert Collins
move config_dir into bzrlib.config
526
1442.1.2 by Robert Collins
create a config module - there is enough config logic to make this worthwhile, and start testing config processing.
527
    def setUp(self):
528
        super(TestConfigPath, self).setUp()
5570.3.9 by Vincent Ladeuil
More use cases for overrideEnv, _cleanEnvironment *may* contain too much variables now.
529
        self.overrideEnv('HOME', '/home/bogus')
530
        self.overrideEnv('XDG_CACHE_DIR', '')
2309.2.6 by Alexander Belchenko
bzr now use Win32 API to determine Application Data location, and don't rely solely on $APPDATA
531
        if sys.platform == 'win32':
5570.3.8 by Vincent Ladeuil
More use cases for overrideEnv.
532
            self.overrideEnv(
533
                'BZR_HOME', r'C:\Documents and Settings\bogus\Application Data')
2991.2.2 by Vincent Ladeuil
No tests worth adding after upgrading to configobj-4.4.0.
534
            self.bzr_home = \
535
                'C:/Documents and Settings/bogus/Application Data/bazaar/2.0'
5519.4.3 by Neil Martinsen-Burrell
be permissive about using $XDG_CONFIG_HOME/bazaar, but dont complain
536
        else:
2991.2.2 by Vincent Ladeuil
No tests worth adding after upgrading to configobj-4.4.0.
537
            self.bzr_home = '/home/bogus/.bazaar'
1442.1.2 by Robert Collins
create a config module - there is enough config logic to make this worthwhile, and start testing config processing.
538
1442.1.1 by Robert Collins
move config_dir into bzrlib.config
539
    def test_config_dir(self):
2991.2.2 by Vincent Ladeuil
No tests worth adding after upgrading to configobj-4.4.0.
540
        self.assertEqual(config.config_dir(), self.bzr_home)
1442.1.2 by Robert Collins
create a config module - there is enough config logic to make this worthwhile, and start testing config processing.
541
542
    def test_config_filename(self):
2991.2.2 by Vincent Ladeuil
No tests worth adding after upgrading to configobj-4.4.0.
543
        self.assertEqual(config.config_filename(),
544
                         self.bzr_home + '/bazaar.conf')
1442.1.2 by Robert Collins
create a config module - there is enough config logic to make this worthwhile, and start testing config processing.
545
1770.2.2 by Aaron Bentley
Rename branches.conf to locations.conf
546
    def test_locations_config_filename(self):
2991.2.4 by Vincent Ladeuil
Various fixes following local testing environment rebuild.
547
        self.assertEqual(config.locations_config_filename(),
2991.2.2 by Vincent Ladeuil
No tests worth adding after upgrading to configobj-4.4.0.
548
                         self.bzr_home + '/locations.conf')
1770.2.2 by Aaron Bentley
Rename branches.conf to locations.conf
549
2900.2.5 by Vincent Ladeuil
ake ftp aware of authentication config.
550
    def test_authentication_config_filename(self):
2991.2.4 by Vincent Ladeuil
Various fixes following local testing environment rebuild.
551
        self.assertEqual(config.authentication_config_filename(),
2991.2.2 by Vincent Ladeuil
No tests worth adding after upgrading to configobj-4.4.0.
552
                         self.bzr_home + '/authentication.conf')
553
4584.3.23 by Martin Pool
Correction to xdg_cache_dir and add a simple test
554
    def test_xdg_cache_dir(self):
555
        self.assertEqual(config.xdg_cache_dir(),
556
            '/home/bogus/.cache')
557
2900.2.5 by Vincent Ladeuil
ake ftp aware of authentication config.
558
5519.4.8 by Neil Martinsen-Burrell
some tests and mention in Whats New
559
class TestXDGConfigDir(tests.TestCaseInTempDir):
560
    # must be in temp dir because config tests for the existence of the bazaar
561
    # subdirectory of $XDG_CONFIG_HOME
562
5519.4.9 by Neil Martinsen-Burrell
working tests
563
    def setUp(self):
5519.4.10 by Andrew Bennetts
Cosmetic tweaks to TestXDGConfigDir.
564
        if sys.platform in ('darwin', 'win32'):
565
            raise tests.TestNotApplicable(
566
                'XDG config dir not used on this platform')
5519.4.9 by Neil Martinsen-Burrell
working tests
567
        super(TestXDGConfigDir, self).setUp()
5570.3.8 by Vincent Ladeuil
More use cases for overrideEnv.
568
        self.overrideEnv('HOME', self.test_home_dir)
5519.4.10 by Andrew Bennetts
Cosmetic tweaks to TestXDGConfigDir.
569
        # BZR_HOME overrides everything we want to test so unset it.
5570.3.8 by Vincent Ladeuil
More use cases for overrideEnv.
570
        self.overrideEnv('BZR_HOME', None)
5519.4.9 by Neil Martinsen-Burrell
working tests
571
5519.4.8 by Neil Martinsen-Burrell
some tests and mention in Whats New
572
    def test_xdg_config_dir_exists(self):
5519.4.10 by Andrew Bennetts
Cosmetic tweaks to TestXDGConfigDir.
573
        """When ~/.config/bazaar exists, use it as the config dir."""
5519.4.8 by Neil Martinsen-Burrell
some tests and mention in Whats New
574
        newdir = osutils.pathjoin(self.test_home_dir, '.config', 'bazaar')
575
        os.makedirs(newdir)
576
        self.assertEqual(config.config_dir(), newdir)
577
578
    def test_xdg_config_home(self):
5519.4.10 by Andrew Bennetts
Cosmetic tweaks to TestXDGConfigDir.
579
        """When XDG_CONFIG_HOME is set, use it."""
5519.4.8 by Neil Martinsen-Burrell
some tests and mention in Whats New
580
        xdgconfigdir = osutils.pathjoin(self.test_home_dir, 'xdgconfig')
5570.3.8 by Vincent Ladeuil
More use cases for overrideEnv.
581
        self.overrideEnv('XDG_CONFIG_HOME', xdgconfigdir)
5519.4.8 by Neil Martinsen-Burrell
some tests and mention in Whats New
582
        newdir = osutils.pathjoin(xdgconfigdir, 'bazaar')
583
        os.makedirs(newdir)
584
        self.assertEqual(config.config_dir(), newdir)
585
586
5050.13.2 by Parth Malwankar
copy config file ownership only if a new file is created
587
class TestIniConfig(tests.TestCaseInTempDir):
1442.1.18 by Robert Collins
permit per branch location overriding of signature checking policy
588
4840.2.6 by Vincent Ladeuil
Implement config.suppress_warning.
589
    def make_config_parser(self, s):
5345.2.9 by Vincent Ladeuil
Rename IniBaseConfig.from_bytes to from_string.
590
        conf = config.IniBasedConfig.from_string(s)
5345.1.4 by Vincent Ladeuil
Deprecate the ``file`` parameter of the ``config._get_parser()`` method.
591
        return conf, conf._get_parser()
4840.2.6 by Vincent Ladeuil
Implement config.suppress_warning.
592
5050.13.2 by Parth Malwankar
copy config file ownership only if a new file is created
593
4840.2.6 by Vincent Ladeuil
Implement config.suppress_warning.
594
class TestIniConfigBuilding(TestIniConfig):
595
1442.1.18 by Robert Collins
permit per branch location overriding of signature checking policy
596
    def test_contructs(self):
5345.1.1 by Vincent Ladeuil
Deprecate the get_filename parameter in IniBasedConfig.
597
        my_config = config.IniBasedConfig()
1442.1.6 by Robert Collins
first stage major overhaul of configs, giving use BranchConfigs, LocationConfigs and GlobalConfigs
598
1442.1.2 by Robert Collins
create a config module - there is enough config logic to make this worthwhile, and start testing config processing.
599
    def test_from_fp(self):
5345.2.9 by Vincent Ladeuil
Rename IniBaseConfig.from_bytes to from_string.
600
        my_config = config.IniBasedConfig.from_string(sample_config_text)
5345.1.4 by Vincent Ladeuil
Deprecate the ``file`` parameter of the ``config._get_parser()`` method.
601
        self.assertIsInstance(my_config._get_parser(), configobj.ConfigObj)
1442.1.2 by Robert Collins
create a config module - there is enough config logic to make this worthwhile, and start testing config processing.
602
1442.1.6 by Robert Collins
first stage major overhaul of configs, giving use BranchConfigs, LocationConfigs and GlobalConfigs
603
    def test_cached(self):
5345.2.9 by Vincent Ladeuil
Rename IniBaseConfig.from_bytes to from_string.
604
        my_config = config.IniBasedConfig.from_string(sample_config_text)
5345.1.4 by Vincent Ladeuil
Deprecate the ``file`` parameter of the ``config._get_parser()`` method.
605
        parser = my_config._get_parser()
5784.1.1 by Martin Pool
Stop using failIf, failUnless, etc
606
        self.assertTrue(my_config._get_parser() is parser)
1442.1.18 by Robert Collins
permit per branch location overriding of signature checking policy
607
5050.13.1 by Parth Malwankar
fixed .bazaar ownership regression
608
    def _dummy_chown(self, path, uid, gid):
609
        self.path, self.uid, self.gid = path, uid, gid
610
611
    def test_ini_config_ownership(self):
5345.5.8 by Vincent Ladeuil
More doc and ensure that the config is locked when _write_config_file is called.
612
        """Ensure that chown is happening during _write_config_file"""
5050.13.1 by Parth Malwankar
fixed .bazaar ownership regression
613
        self.requireFeature(features.chown_feature)
614
        self.overrideAttr(os, 'chown', self._dummy_chown)
615
        self.path = self.uid = self.gid = None
5345.5.7 by Vincent Ladeuil
Make LocationConfig use a lock too.
616
        conf = config.IniBasedConfig(file_name='./foo.conf')
5050.13.1 by Parth Malwankar
fixed .bazaar ownership regression
617
        conf._write_config_file()
5345.5.7 by Vincent Ladeuil
Make LocationConfig use a lock too.
618
        self.assertEquals(self.path, './foo.conf')
5050.13.1 by Parth Malwankar
fixed .bazaar ownership regression
619
        self.assertTrue(isinstance(self.uid, int))
620
        self.assertTrue(isinstance(self.gid, int))
4840.2.5 by Vincent Ladeuil
Refactor get_user_option_as_* tests.
621
5345.1.1 by Vincent Ladeuil
Deprecate the get_filename parameter in IniBasedConfig.
622
    def test_get_filename_parameter_is_deprecated_(self):
623
        conf = self.callDeprecated([
624
            'IniBasedConfig.__init__(get_filename) was deprecated in 2.3.'
625
            ' Use file_name instead.'],
626
            config.IniBasedConfig, lambda: 'ini.conf')
5345.3.1 by Vincent Ladeuil
Check that _get_filename() is called and produces the desired side effect.
627
        self.assertEqual('ini.conf', conf.file_name)
5345.1.1 by Vincent Ladeuil
Deprecate the get_filename parameter in IniBasedConfig.
628
5345.1.4 by Vincent Ladeuil
Deprecate the ``file`` parameter of the ``config._get_parser()`` method.
629
    def test_get_parser_file_parameter_is_deprecated_(self):
630
        config_file = StringIO(sample_config_text.encode('utf-8'))
5345.2.9 by Vincent Ladeuil
Rename IniBaseConfig.from_bytes to from_string.
631
        conf = config.IniBasedConfig.from_string(sample_config_text)
5345.1.4 by Vincent Ladeuil
Deprecate the ``file`` parameter of the ``config._get_parser()`` method.
632
        conf = self.callDeprecated([
5345.1.5 by Vincent Ladeuil
Fix fallouts by slightly editing the tests. More refactoring avoided to keep the review light.
633
            'IniBasedConfig._get_parser(file=xxx) was deprecated in 2.3.'
634
            ' Use IniBasedConfig(_content=xxx) instead.'],
635
            conf._get_parser, file=config_file)
5345.1.4 by Vincent Ladeuil
Deprecate the ``file`` parameter of the ``config._get_parser()`` method.
636
5676.1.4 by Jelmer Vernooij
merge bzr.dev.
637
5345.1.16 by Vincent Ladeuil
Allows tests to save the config file at build time.
638
class TestIniConfigSaving(tests.TestCaseInTempDir):
639
5345.1.1 by Vincent Ladeuil
Deprecate the get_filename parameter in IniBasedConfig.
640
    def test_cant_save_without_a_file_name(self):
641
        conf = config.IniBasedConfig()
642
        self.assertRaises(AssertionError, conf._write_config_file)
643
5345.1.16 by Vincent Ladeuil
Allows tests to save the config file at build time.
644
    def test_saved_with_content(self):
645
        content = 'foo = bar\n'
5345.1.26 by Vincent Ladeuil
Merge lockable-config-files into remove-gratuitous-ensure-config-dir-exist-calls resolving conflicts
646
        conf = config.IniBasedConfig.from_string(
5345.1.25 by Vincent Ladeuil
Move the '_save' parameter from '__init__' to 'from_bytes', fix fallouts.
647
            content, file_name='./test.conf', save=True)
5345.1.16 by Vincent Ladeuil
Allows tests to save the config file at build time.
648
        self.assertFileEqual(content, 'test.conf')
649
4840.2.5 by Vincent Ladeuil
Refactor get_user_option_as_* tests.
650
5676.1.4 by Jelmer Vernooij
merge bzr.dev.
651
class TestIniConfigOptionExpansionDefaultValue(tests.TestCaseInTempDir):
652
    """What is the default value of expand for config options.
653
654
    This is an opt-in beta feature used to evaluate whether or not option
655
    references can appear in dangerous place raising exceptions, disapearing
656
    (and as such corrupting data) or if it's safe to activate the option by
657
    default.
658
659
    Note that these tests relies on config._expand_default_value being already
660
    overwritten in the parent class setUp.
661
    """
662
663
    def setUp(self):
664
        super(TestIniConfigOptionExpansionDefaultValue, self).setUp()
665
        self.config = None
666
        self.warnings = []
667
        def warning(*args):
668
            self.warnings.append(args[0] % args[1:])
669
        self.overrideAttr(trace, 'warning', warning)
670
671
    def get_config(self, expand):
672
        c = config.GlobalConfig.from_string('bzr.config.expand=%s' % (expand,),
673
                                            save=True)
674
        return c
675
676
    def assertExpandIs(self, expected):
677
        actual = config._get_expand_default_value()
678
        #self.config.get_user_option_as_bool('bzr.config.expand')
679
        self.assertEquals(expected, actual)
680
681
    def test_default_is_None(self):
682
        self.assertEquals(None, config._expand_default_value)
683
684
    def test_default_is_False_even_if_None(self):
685
        self.config = self.get_config(None)
686
        self.assertExpandIs(False)
687
688
    def test_default_is_False_even_if_invalid(self):
689
        self.config = self.get_config('<your choice>')
690
        self.assertExpandIs(False)
691
        # ...
692
        # Huh ? My choice is False ? Thanks, always happy to hear that :D
693
        # Wait, you've been warned !
694
        self.assertLength(1, self.warnings)
695
        self.assertEquals(
696
            'Value "<your choice>" is not a boolean for "bzr.config.expand"',
697
            self.warnings[0])
698
699
    def test_default_is_True(self):
700
        self.config = self.get_config(True)
701
        self.assertExpandIs(True)
5743.10.10 by Vincent Ladeuil
Remove spurious space
702
5676.1.4 by Jelmer Vernooij
merge bzr.dev.
703
    def test_default_is_False(self):
704
        self.config = self.get_config(False)
705
        self.assertExpandIs(False)
5743.10.10 by Vincent Ladeuil
Remove spurious space
706
5676.1.4 by Jelmer Vernooij
merge bzr.dev.
707
708
class TestIniConfigOptionExpansion(tests.TestCase):
709
    """Test option expansion from the IniConfig level.
710
711
    What we really want here is to test the Config level, but the class being
712
    abstract as far as storing values is concerned, this can't be done
713
    properly (yet).
714
    """
715
    # FIXME: This should be rewritten when all configs share a storage
716
    # implementation -- vila 2011-02-18
717
718
    def get_config(self, string=None):
719
        if string is None:
720
            string = ''
721
        c = config.IniBasedConfig.from_string(string)
722
        return c
723
724
    def assertExpansion(self, expected, conf, string, env=None):
725
        self.assertEquals(expected, conf.expand_options(string, env))
726
727
    def test_no_expansion(self):
728
        c = self.get_config('')
729
        self.assertExpansion('foo', c, 'foo')
730
731
    def test_env_adding_options(self):
732
        c = self.get_config('')
733
        self.assertExpansion('bar', c, '{foo}', {'foo': 'bar'})
734
735
    def test_env_overriding_options(self):
736
        c = self.get_config('foo=baz')
737
        self.assertExpansion('bar', c, '{foo}', {'foo': 'bar'})
738
739
    def test_simple_ref(self):
740
        c = self.get_config('foo=xxx')
741
        self.assertExpansion('xxx', c, '{foo}')
742
743
    def test_unknown_ref(self):
744
        c = self.get_config('')
745
        self.assertRaises(errors.ExpandingUnknownOption,
746
                          c.expand_options, '{foo}')
747
748
    def test_indirect_ref(self):
749
        c = self.get_config('''
750
foo=xxx
751
bar={foo}
752
''')
753
        self.assertExpansion('xxx', c, '{bar}')
754
755
    def test_embedded_ref(self):
756
        c = self.get_config('''
757
foo=xxx
758
bar=foo
759
''')
760
        self.assertExpansion('xxx', c, '{{bar}}')
761
762
    def test_simple_loop(self):
763
        c = self.get_config('foo={foo}')
764
        self.assertRaises(errors.OptionExpansionLoop, c.expand_options, '{foo}')
765
766
    def test_indirect_loop(self):
767
        c = self.get_config('''
768
foo={bar}
769
bar={baz}
770
baz={foo}''')
771
        e = self.assertRaises(errors.OptionExpansionLoop,
772
                              c.expand_options, '{foo}')
773
        self.assertEquals('foo->bar->baz', e.refs)
774
        self.assertEquals('{foo}', e.string)
775
776
    def test_list(self):
777
        conf = self.get_config('''
778
foo=start
779
bar=middle
780
baz=end
781
list={foo},{bar},{baz}
782
''')
783
        self.assertEquals(['start', 'middle', 'end'],
784
                           conf.get_user_option('list', expand=True))
785
786
    def test_cascading_list(self):
787
        conf = self.get_config('''
788
foo=start,{bar}
789
bar=middle,{baz}
790
baz=end
791
list={foo}
792
''')
793
        self.assertEquals(['start', 'middle', 'end'],
794
                           conf.get_user_option('list', expand=True))
795
796
    def test_pathological_hidden_list(self):
797
        conf = self.get_config('''
798
foo=bin
799
bar=go
800
start={foo
801
middle=},{
802
end=bar}
803
hidden={start}{middle}{end}
804
''')
805
        # Nope, it's either a string or a list, and the list wins as soon as a
806
        # ',' appears, so the string concatenation never occur.
807
        self.assertEquals(['{foo', '}', '{', 'bar}'],
808
                          conf.get_user_option('hidden', expand=True))
809
810
class TestLocationConfigOptionExpansion(tests.TestCaseInTempDir):
811
812
    def get_config(self, location, string=None):
813
        if string is None:
814
            string = ''
815
        # Since we don't save the config we won't strictly require to inherit
816
        # from TestCaseInTempDir, but an error occurs so quickly...
817
        c = config.LocationConfig.from_string(string, location)
818
        return c
819
820
    def test_dont_cross_unrelated_section(self):
821
        c = self.get_config('/another/branch/path','''
822
[/one/branch/path]
823
foo = hello
824
bar = {foo}/2
825
826
[/another/branch/path]
827
bar = {foo}/2
828
''')
829
        self.assertRaises(errors.ExpandingUnknownOption,
830
                          c.get_user_option, 'bar', expand=True)
831
832
    def test_cross_related_sections(self):
833
        c = self.get_config('/project/branch/path','''
834
[/project]
835
foo = qu
836
837
[/project/branch/path]
838
bar = {foo}ux
839
''')
840
        self.assertEquals('quux', c.get_user_option('bar', expand=True))
841
842
5345.5.1 by Vincent Ladeuil
Implement config.reload and make sure we have a file name when using it.
843
class TestIniBaseConfigOnDisk(tests.TestCaseInTempDir):
844
845
    def test_cannot_reload_without_name(self):
5345.5.13 by Vincent Ladeuil
Merge simplify-test-config-building into lockable-config-files resolving conflicts
846
        conf = config.IniBasedConfig.from_string(sample_config_text)
5345.5.1 by Vincent Ladeuil
Implement config.reload and make sure we have a file name when using it.
847
        self.assertRaises(AssertionError, conf.reload)
848
849
    def test_reload_see_new_value(self):
5345.5.13 by Vincent Ladeuil
Merge simplify-test-config-building into lockable-config-files resolving conflicts
850
        c1 = config.IniBasedConfig.from_string('editor=vim\n',
851
                                               file_name='./test/conf')
5345.5.1 by Vincent Ladeuil
Implement config.reload and make sure we have a file name when using it.
852
        c1._write_config_file()
5345.5.13 by Vincent Ladeuil
Merge simplify-test-config-building into lockable-config-files resolving conflicts
853
        c2 = config.IniBasedConfig.from_string('editor=emacs\n',
854
                                               file_name='./test/conf')
5345.5.1 by Vincent Ladeuil
Implement config.reload and make sure we have a file name when using it.
855
        c2._write_config_file()
856
        self.assertEqual('vim', c1.get_user_option('editor'))
857
        self.assertEqual('emacs', c2.get_user_option('editor'))
858
        # Make sure we get the Right value
859
        c1.reload()
860
        self.assertEqual('emacs', c1.get_user_option('editor'))
861
862
5345.1.7 by Vincent Ladeuil
Start LockableConfig tests.
863
class TestLockableConfig(tests.TestCaseInTempDir):
864
5506.2.1 by Vincent Ladeuil
Implements ``bzr config --active option`` displaying only the value.
865
    scenarios = lockable_config_scenarios()
866
5345.5.7 by Vincent Ladeuil
Make LocationConfig use a lock too.
867
    # Set by load_tests
868
    config_class = None
869
    config_args = None
870
    config_section = None
5345.1.7 by Vincent Ladeuil
Start LockableConfig tests.
871
872
    def setUp(self):
873
        super(TestLockableConfig, self).setUp()
5345.5.7 by Vincent Ladeuil
Make LocationConfig use a lock too.
874
        self._content = '[%s]\none=1\ntwo=2\n' % (self.config_section,)
5345.1.7 by Vincent Ladeuil
Start LockableConfig tests.
875
        self.config = self.create_config(self._content)
876
5345.5.7 by Vincent Ladeuil
Make LocationConfig use a lock too.
877
    def get_existing_config(self):
878
        return self.config_class(*self.config_args)
879
5345.1.7 by Vincent Ladeuil
Start LockableConfig tests.
880
    def create_config(self, content):
5396.1.1 by Vincent Ladeuil
Fix python-2.6-ism.
881
        kwargs = dict(save=True)
882
        c = self.config_class.from_string(content, *self.config_args, **kwargs)
5345.1.7 by Vincent Ladeuil
Start LockableConfig tests.
883
        return c
884
885
    def test_simple_read_access(self):
886
        self.assertEquals('1', self.config.get_user_option('one'))
887
888
    def test_simple_write_access(self):
889
        self.config.set_user_option('one', 'one')
890
        self.assertEquals('one', self.config.get_user_option('one'))
891
5345.1.8 by Vincent Ladeuil
Make the test_listen_to_the_last_speaker pass and fix fallouts.
892
    def test_listen_to_the_last_speaker(self):
893
        c1 = self.config
5345.5.7 by Vincent Ladeuil
Make LocationConfig use a lock too.
894
        c2 = self.get_existing_config()
5345.1.8 by Vincent Ladeuil
Make the test_listen_to_the_last_speaker pass and fix fallouts.
895
        c1.set_user_option('one', 'ONE')
896
        c2.set_user_option('two', 'TWO')
897
        self.assertEquals('ONE', c1.get_user_option('one'))
898
        self.assertEquals('TWO', c2.get_user_option('two'))
899
        # The second update respect the first one
900
        self.assertEquals('ONE', c2.get_user_option('one'))
901
5345.5.3 by Vincent Ladeuil
Add a test for concurrent writers ensuring the values propagate.
902
    def test_last_speaker_wins(self):
903
        # If the same config is not shared, the same variable modified twice
904
        # can only see a single result.
905
        c1 = self.config
5345.5.7 by Vincent Ladeuil
Make LocationConfig use a lock too.
906
        c2 = self.get_existing_config()
5345.5.3 by Vincent Ladeuil
Add a test for concurrent writers ensuring the values propagate.
907
        c1.set_user_option('one', 'c1')
908
        c2.set_user_option('one', 'c2')
909
        self.assertEquals('c2', c2._get_user_option('one'))
910
        # The first modification is still available until another refresh
911
        # occur
912
        self.assertEquals('c1', c1._get_user_option('one'))
913
        c1.set_user_option('two', 'done')
914
        self.assertEquals('c2', c1._get_user_option('one'))
915
5345.5.4 by Vincent Ladeuil
Start implementing config files locking.
916
    def test_writes_are_serialized(self):
5345.5.7 by Vincent Ladeuil
Make LocationConfig use a lock too.
917
        c1 = self.config
918
        c2 = self.get_existing_config()
5345.5.4 by Vincent Ladeuil
Start implementing config files locking.
919
920
        # We spawn a thread that will pause *during* the write
921
        before_writing = threading.Event()
922
        after_writing = threading.Event()
923
        writing_done = threading.Event()
924
        c1_orig = c1._write_config_file
925
        def c1_write_config_file():
926
            before_writing.set()
927
            c1_orig()
5743.4.9 by Vincent Ladeuil
Implement a LockableConfigObjStore to be able to mimick the actual behaviour.
928
            # The lock is held. We wait for the main thread to decide when to
5345.5.4 by Vincent Ladeuil
Start implementing config files locking.
929
            # continue
930
            after_writing.wait()
931
        c1._write_config_file = c1_write_config_file
932
        def c1_set_option():
933
            c1.set_user_option('one', 'c1')
934
            writing_done.set()
935
        t1 = threading.Thread(target=c1_set_option)
936
        # Collect the thread after the test
937
        self.addCleanup(t1.join)
938
        # Be ready to unblock the thread if the test goes wrong
939
        self.addCleanup(after_writing.set)
940
        t1.start()
941
        before_writing.wait()
942
        self.assertTrue(c1._lock.is_held)
943
        self.assertRaises(errors.LockContention,
944
                          c2.set_user_option, 'one', 'c2')
945
        self.assertEquals('c1', c1.get_user_option('one'))
946
        # Let the lock be released
947
        after_writing.set()
948
        writing_done.wait()
949
        c2.set_user_option('one', 'c2')
950
        self.assertEquals('c2', c2.get_user_option('one'))
951
5345.5.7 by Vincent Ladeuil
Make LocationConfig use a lock too.
952
    def test_read_while_writing(self):
953
       c1 = self.config
954
       # We spawn a thread that will pause *during* the write
955
       ready_to_write = threading.Event()
956
       do_writing = threading.Event()
957
       writing_done = threading.Event()
958
       c1_orig = c1._write_config_file
959
       def c1_write_config_file():
960
           ready_to_write.set()
5743.4.9 by Vincent Ladeuil
Implement a LockableConfigObjStore to be able to mimick the actual behaviour.
961
           # The lock is held. We wait for the main thread to decide when to
5345.5.7 by Vincent Ladeuil
Make LocationConfig use a lock too.
962
           # continue
963
           do_writing.wait()
964
           c1_orig()
965
           writing_done.set()
966
       c1._write_config_file = c1_write_config_file
967
       def c1_set_option():
968
           c1.set_user_option('one', 'c1')
969
       t1 = threading.Thread(target=c1_set_option)
970
       # Collect the thread after the test
971
       self.addCleanup(t1.join)
972
       # Be ready to unblock the thread if the test goes wrong
973
       self.addCleanup(do_writing.set)
974
       t1.start()
975
       # Ensure the thread is ready to write
976
       ready_to_write.wait()
977
       self.assertTrue(c1._lock.is_held)
978
       self.assertEquals('c1', c1.get_user_option('one'))
979
       # If we read during the write, we get the old value
980
       c2 = self.get_existing_config()
981
       self.assertEquals('1', c2.get_user_option('one'))
982
       # Let the writing occur and ensure it occurred
983
       do_writing.set()
984
       writing_done.wait()
985
       # Now we get the updated value
986
       c3 = self.get_existing_config()
987
       self.assertEquals('c1', c3.get_user_option('one'))
988
5345.1.7 by Vincent Ladeuil
Start LockableConfig tests.
989
4840.2.6 by Vincent Ladeuil
Implement config.suppress_warning.
990
class TestGetUserOptionAs(TestIniConfig):
4840.2.5 by Vincent Ladeuil
Refactor get_user_option_as_* tests.
991
4503.2.2 by Vincent Ladeuil
Get a bool or none from a config file.
992
    def test_get_user_option_as_bool(self):
4840.2.6 by Vincent Ladeuil
Implement config.suppress_warning.
993
        conf, parser = self.make_config_parser("""
4503.2.2 by Vincent Ladeuil
Get a bool or none from a config file.
994
a_true_bool = true
995
a_false_bool = 0
996
an_invalid_bool = maybe
4840.2.4 by Vincent Ladeuil
Implement config.get_user_option_as_list.
997
a_list = hmm, who knows ? # This is interpreted as a list !
4840.2.5 by Vincent Ladeuil
Refactor get_user_option_as_* tests.
998
""")
4840.2.6 by Vincent Ladeuil
Implement config.suppress_warning.
999
        get_bool = conf.get_user_option_as_bool
1000
        self.assertEqual(True, get_bool('a_true_bool'))
1001
        self.assertEqual(False, get_bool('a_false_bool'))
4989.2.12 by Vincent Ladeuil
Display a warning if an option value is not boolean.
1002
        warnings = []
1003
        def warning(*args):
1004
            warnings.append(args[0] % args[1:])
1005
        self.overrideAttr(trace, 'warning', warning)
1006
        msg = 'Value "%s" is not a boolean for "%s"'
4840.2.6 by Vincent Ladeuil
Implement config.suppress_warning.
1007
        self.assertIs(None, get_bool('an_invalid_bool'))
4989.2.12 by Vincent Ladeuil
Display a warning if an option value is not boolean.
1008
        self.assertEquals(msg % ('maybe', 'an_invalid_bool'), warnings[0])
1009
        warnings = []
4840.2.6 by Vincent Ladeuil
Implement config.suppress_warning.
1010
        self.assertIs(None, get_bool('not_defined_in_this_config'))
4989.2.12 by Vincent Ladeuil
Display a warning if an option value is not boolean.
1011
        self.assertEquals([], warnings)
4840.2.4 by Vincent Ladeuil
Implement config.get_user_option_as_list.
1012
1013
    def test_get_user_option_as_list(self):
4840.2.6 by Vincent Ladeuil
Implement config.suppress_warning.
1014
        conf, parser = self.make_config_parser("""
4840.2.4 by Vincent Ladeuil
Implement config.get_user_option_as_list.
1015
a_list = a,b,c
1016
length_1 = 1,
1017
one_item = x
4840.2.6 by Vincent Ladeuil
Implement config.suppress_warning.
1018
""")
1019
        get_list = conf.get_user_option_as_list
4840.2.4 by Vincent Ladeuil
Implement config.get_user_option_as_list.
1020
        self.assertEqual(['a', 'b', 'c'], get_list('a_list'))
1021
        self.assertEqual(['1'], get_list('length_1'))
4840.2.6 by Vincent Ladeuil
Implement config.suppress_warning.
1022
        self.assertEqual('x', conf.get_user_option('one_item'))
4840.2.4 by Vincent Ladeuil
Implement config.get_user_option_as_list.
1023
        # automatically cast to list
1024
        self.assertEqual(['x'], get_list('one_item'))
1025
1026
4840.2.6 by Vincent Ladeuil
Implement config.suppress_warning.
1027
class TestSupressWarning(TestIniConfig):
1028
1029
    def make_warnings_config(self, s):
1030
        conf, parser = self.make_config_parser(s)
1031
        return conf.suppress_warning
1032
1033
    def test_suppress_warning_unknown(self):
1034
        suppress_warning = self.make_warnings_config('')
1035
        self.assertEqual(False, suppress_warning('unknown_warning'))
1036
1037
    def test_suppress_warning_known(self):
1038
        suppress_warning = self.make_warnings_config('suppress_warnings=a,b')
1039
        self.assertEqual(False, suppress_warning('c'))
1040
        self.assertEqual(True, suppress_warning('a'))
1041
        self.assertEqual(True, suppress_warning('b'))
1042
1043
2900.2.4 by Vincent Ladeuil
Cosmetic changes.
1044
class TestGetConfig(tests.TestCase):
1442.1.18 by Robert Collins
permit per branch location overriding of signature checking policy
1045
1046
    def test_constructs(self):
1442.1.6 by Robert Collins
first stage major overhaul of configs, giving use BranchConfigs, LocationConfigs and GlobalConfigs
1047
        my_config = config.GlobalConfig()
1048
1442.1.2 by Robert Collins
create a config module - there is enough config logic to make this worthwhile, and start testing config processing.
1049
    def test_calls_read_filenames(self):
2991.2.2 by Vincent Ladeuil
No tests worth adding after upgrading to configobj-4.4.0.
1050
        # replace the class that is constructed, to check its parameters
1474 by Robert Collins
Merge from Aaron Bentley.
1051
        oldparserclass = config.ConfigObj
1052
        config.ConfigObj = InstrumentedConfigObj
1442.1.6 by Robert Collins
first stage major overhaul of configs, giving use BranchConfigs, LocationConfigs and GlobalConfigs
1053
        my_config = config.GlobalConfig()
1442.1.2 by Robert Collins
create a config module - there is enough config logic to make this worthwhile, and start testing config processing.
1054
        try:
1442.1.18 by Robert Collins
permit per branch location overriding of signature checking policy
1055
            parser = my_config._get_parser()
1442.1.2 by Robert Collins
create a config module - there is enough config logic to make this worthwhile, and start testing config processing.
1056
        finally:
1474 by Robert Collins
Merge from Aaron Bentley.
1057
            config.ConfigObj = oldparserclass
5784.1.1 by Martin Pool
Stop using failIf, failUnless, etc
1058
        self.assertIsInstance(parser, InstrumentedConfigObj)
1551.2.20 by Aaron Bentley
Treated config files as utf-8
1059
        self.assertEqual(parser._calls, [('__init__', config.config_filename(),
1060
                                          'utf-8')])
1442.1.2 by Robert Collins
create a config module - there is enough config logic to make this worthwhile, and start testing config processing.
1061
1062
2900.2.4 by Vincent Ladeuil
Cosmetic changes.
1063
class TestBranchConfig(tests.TestCaseWithTransport):
1442.1.6 by Robert Collins
first stage major overhaul of configs, giving use BranchConfigs, LocationConfigs and GlobalConfigs
1064
1065
    def test_constructs(self):
1066
        branch = FakeBranch()
1067
        my_config = config.BranchConfig(branch)
1068
        self.assertRaises(TypeError, config.BranchConfig)
1069
1070
    def test_get_location_config(self):
1071
        branch = FakeBranch()
1072
        my_config = config.BranchConfig(branch)
1073
        location_config = my_config._get_location_config()
1074
        self.assertEqual(branch.base, location_config.location)
5784.1.1 by Martin Pool
Stop using failIf, failUnless, etc
1075
        self.assertIs(location_config, my_config._get_location_config())
1442.1.6 by Robert Collins
first stage major overhaul of configs, giving use BranchConfigs, LocationConfigs and GlobalConfigs
1076
1770.2.9 by Aaron Bentley
Add Branch.get_config, update BranchConfig() callers
1077
    def test_get_config(self):
1078
        """The Branch.get_config method works properly"""
2900.2.4 by Vincent Ladeuil
Cosmetic changes.
1079
        b = bzrdir.BzrDir.create_standalone_workingtree('.').branch
1770.2.9 by Aaron Bentley
Add Branch.get_config, update BranchConfig() callers
1080
        my_config = b.get_config()
1081
        self.assertIs(my_config.get_user_option('wacky'), None)
1082
        my_config.set_user_option('wacky', 'unlikely')
1083
        self.assertEqual(my_config.get_user_option('wacky'), 'unlikely')
1084
1085
        # Ensure we get the same thing if we start again
2900.2.4 by Vincent Ladeuil
Cosmetic changes.
1086
        b2 = branch.Branch.open('.')
1770.2.9 by Aaron Bentley
Add Branch.get_config, update BranchConfig() callers
1087
        my_config2 = b2.get_config()
1088
        self.assertEqual(my_config2.get_user_option('wacky'), 'unlikely')
1089
1824.1.1 by Robert Collins
Add BranchConfig.has_explicit_nickname call.
1090
    def test_has_explicit_nickname(self):
1091
        b = self.make_branch('.')
1092
        self.assertFalse(b.get_config().has_explicit_nickname())
1093
        b.nick = 'foo'
1094
        self.assertTrue(b.get_config().has_explicit_nickname())
1095
1878.1.1 by John Arbash Meinel
Entries in locations.conf should prefer local paths if available (bug #53653)
1096
    def test_config_url(self):
1097
        """The Branch.get_config will use section that uses a local url"""
1098
        branch = self.make_branch('branch')
1099
        self.assertEqual('branch', branch.nick)
1100
1101
        local_url = urlutils.local_path_to_url('branch')
5345.1.26 by Vincent Ladeuil
Merge lockable-config-files into remove-gratuitous-ensure-config-dir-exist-calls resolving conflicts
1102
        conf = config.LocationConfig.from_string(
5345.1.25 by Vincent Ladeuil
Move the '_save' parameter from '__init__' to 'from_bytes', fix fallouts.
1103
            '[%s]\nnickname = foobar' % (local_url,),
1104
            local_url, save=True)
1878.1.1 by John Arbash Meinel
Entries in locations.conf should prefer local paths if available (bug #53653)
1105
        self.assertEqual('foobar', branch.nick)
1106
1107
    def test_config_local_path(self):
1108
        """The Branch.get_config will use a local system path"""
1109
        branch = self.make_branch('branch')
1110
        self.assertEqual('branch', branch.nick)
1111
5345.1.12 by Vincent Ladeuil
Cleanup test_config some more.
1112
        local_path = osutils.getcwd().encode('utf8')
5345.1.26 by Vincent Ladeuil
Merge lockable-config-files into remove-gratuitous-ensure-config-dir-exist-calls resolving conflicts
1113
        conf = config.LocationConfig.from_string(
5345.1.25 by Vincent Ladeuil
Move the '_save' parameter from '__init__' to 'from_bytes', fix fallouts.
1114
            '[%s/branch]\nnickname = barry' % (local_path,),
1115
            'branch',  save=True)
1878.1.1 by John Arbash Meinel
Entries in locations.conf should prefer local paths if available (bug #53653)
1116
        self.assertEqual('barry', branch.nick)
1117
1878.1.2 by John Arbash Meinel
Add a test that new locations.conf entries are created with a local path, rather than a URL
1118
    def test_config_creates_local(self):
1119
        """Creating a new entry in config uses a local path."""
2230.3.6 by Aaron Bentley
work in progress bind stuff
1120
        branch = self.make_branch('branch', format='knit')
1878.1.2 by John Arbash Meinel
Add a test that new locations.conf entries are created with a local path, rather than a URL
1121
        branch.set_push_location('http://foobar')
1122
        local_path = osutils.getcwd().encode('utf8')
1123
        # Surprisingly ConfigObj doesn't create a trailing newline
5345.1.12 by Vincent Ladeuil
Cleanup test_config some more.
1124
        self.check_file_contents(config.locations_config_filename(),
2991.2.2 by Vincent Ladeuil
No tests worth adding after upgrading to configobj-4.4.0.
1125
                                 '[%s/branch]\n'
1126
                                 'push_location = http://foobar\n'
3221.7.1 by Matt Nordhoff
Upgrade ConfigObj to version 4.5.1.
1127
                                 'push_location:policy = norecurse\n'
2991.2.2 by Vincent Ladeuil
No tests worth adding after upgrading to configobj-4.4.0.
1128
                                 % (local_path,))
1878.1.2 by John Arbash Meinel
Add a test that new locations.conf entries are created with a local path, rather than a URL
1129
2120.5.4 by Alexander Belchenko
Whitebox test for Config.get_nickname (req. by Aaron Bentley)
1130
    def test_autonick_urlencoded(self):
1131
        b = self.make_branch('!repo')
1132
        self.assertEqual('!repo', b.get_config().get_nickname())
1133
1551.15.35 by Aaron Bentley
Warn when setting config values that will be masked (#122286)
1134
    def test_warn_if_masked(self):
1135
        warnings = []
1136
        def warning(*args):
1137
            warnings.append(args[0] % args[1:])
5345.1.12 by Vincent Ladeuil
Cleanup test_config some more.
1138
        self.overrideAttr(trace, 'warning', warning)
1551.15.35 by Aaron Bentley
Warn when setting config values that will be masked (#122286)
1139
1140
        def set_option(store, warn_masked=True):
1141
            warnings[:] = []
1142
            conf.set_user_option('example_option', repr(store), store=store,
1143
                                 warn_masked=warn_masked)
1144
        def assertWarning(warning):
1145
            if warning is None:
1146
                self.assertEqual(0, len(warnings))
1147
            else:
1148
                self.assertEqual(1, len(warnings))
1149
                self.assertEqual(warning, warnings[0])
5345.1.12 by Vincent Ladeuil
Cleanup test_config some more.
1150
        branch = self.make_branch('.')
1151
        conf = branch.get_config()
1152
        set_option(config.STORE_GLOBAL)
1153
        assertWarning(None)
1154
        set_option(config.STORE_BRANCH)
1155
        assertWarning(None)
1156
        set_option(config.STORE_GLOBAL)
1157
        assertWarning('Value "4" is masked by "3" from branch.conf')
1158
        set_option(config.STORE_GLOBAL, warn_masked=False)
1159
        assertWarning(None)
1160
        set_option(config.STORE_LOCATION)
1161
        assertWarning(None)
1162
        set_option(config.STORE_BRANCH)
1163
        assertWarning('Value "3" is masked by "0" from locations.conf')
1164
        set_option(config.STORE_BRANCH, warn_masked=False)
1165
        assertWarning(None)
1551.15.35 by Aaron Bentley
Warn when setting config values that will be masked (#122286)
1166
1442.1.6 by Robert Collins
first stage major overhaul of configs, giving use BranchConfigs, LocationConfigs and GlobalConfigs
1167
5448.1.1 by Vincent Ladeuil
Use TestCaseInTempDir for tests requiring disk resources
1168
class TestGlobalConfigItems(tests.TestCaseInTempDir):
1442.1.6 by Robert Collins
first stage major overhaul of configs, giving use BranchConfigs, LocationConfigs and GlobalConfigs
1169
1442.1.2 by Robert Collins
create a config module - there is enough config logic to make this worthwhile, and start testing config processing.
1170
    def test_user_id(self):
5345.2.9 by Vincent Ladeuil
Rename IniBaseConfig.from_bytes to from_string.
1171
        my_config = config.GlobalConfig.from_string(sample_config_text)
1551.2.21 by Aaron Bentley
Formatted unicode config tests as ASCII
1172
        self.assertEqual(u"Erik B\u00e5gfors <erik@bagfors.nu>",
1442.1.6 by Robert Collins
first stage major overhaul of configs, giving use BranchConfigs, LocationConfigs and GlobalConfigs
1173
                         my_config._get_user_id())
1442.1.2 by Robert Collins
create a config module - there is enough config logic to make this worthwhile, and start testing config processing.
1174
1175
    def test_absent_user_id(self):
5345.2.2 by Vincent Ladeuil
Simplify test config building.
1176
        my_config = config.GlobalConfig()
1442.1.6 by Robert Collins
first stage major overhaul of configs, giving use BranchConfigs, LocationConfigs and GlobalConfigs
1177
        self.assertEqual(None, my_config._get_user_id())
1178
1179
    def test_configured_editor(self):
5345.2.9 by Vincent Ladeuil
Rename IniBaseConfig.from_bytes to from_string.
1180
        my_config = config.GlobalConfig.from_string(sample_config_text)
5743.13.1 by Vincent Ladeuil
Deprecate _get_editor to identify its usages.
1181
        editor = self.applyDeprecated(
1182
            deprecated_in((2, 4, 0)), my_config.get_editor)
1183
        self.assertEqual('vim', editor)
1442.1.6 by Robert Collins
first stage major overhaul of configs, giving use BranchConfigs, LocationConfigs and GlobalConfigs
1184
1442.1.17 by Robert Collins
allow global overriding of signature policy to force checking, or (pointless but allowed) to set auto checking
1185
    def test_signatures_always(self):
5345.2.9 by Vincent Ladeuil
Rename IniBaseConfig.from_bytes to from_string.
1186
        my_config = config.GlobalConfig.from_string(sample_always_signatures)
1770.2.1 by Aaron Bentley
Use create_signature for signing policy, deprecate check_signatures for this
1187
        self.assertEqual(config.CHECK_NEVER,
1442.1.17 by Robert Collins
allow global overriding of signature policy to force checking, or (pointless but allowed) to set auto checking
1188
                         my_config.signature_checking())
1770.2.1 by Aaron Bentley
Use create_signature for signing policy, deprecate check_signatures for this
1189
        self.assertEqual(config.SIGN_ALWAYS,
1190
                         my_config.signing_policy())
1442.1.21 by Robert Collins
create signature_needed() call for commit to trigger creating signatures
1191
        self.assertEqual(True, my_config.signature_needed())
1442.1.17 by Robert Collins
allow global overriding of signature policy to force checking, or (pointless but allowed) to set auto checking
1192
1193
    def test_signatures_if_possible(self):
5345.2.9 by Vincent Ladeuil
Rename IniBaseConfig.from_bytes to from_string.
1194
        my_config = config.GlobalConfig.from_string(sample_maybe_signatures)
1770.2.1 by Aaron Bentley
Use create_signature for signing policy, deprecate check_signatures for this
1195
        self.assertEqual(config.CHECK_NEVER,
1442.1.17 by Robert Collins
allow global overriding of signature policy to force checking, or (pointless but allowed) to set auto checking
1196
                         my_config.signature_checking())
1770.2.1 by Aaron Bentley
Use create_signature for signing policy, deprecate check_signatures for this
1197
        self.assertEqual(config.SIGN_WHEN_REQUIRED,
1198
                         my_config.signing_policy())
1442.1.21 by Robert Collins
create signature_needed() call for commit to trigger creating signatures
1199
        self.assertEqual(False, my_config.signature_needed())
1442.1.17 by Robert Collins
allow global overriding of signature policy to force checking, or (pointless but allowed) to set auto checking
1200
1442.1.16 by Robert Collins
allow global overriding of signature policy to never check
1201
    def test_signatures_ignore(self):
5345.2.9 by Vincent Ladeuil
Rename IniBaseConfig.from_bytes to from_string.
1202
        my_config = config.GlobalConfig.from_string(sample_ignore_signatures)
1770.2.1 by Aaron Bentley
Use create_signature for signing policy, deprecate check_signatures for this
1203
        self.assertEqual(config.CHECK_ALWAYS,
1442.1.16 by Robert Collins
allow global overriding of signature policy to never check
1204
                         my_config.signature_checking())
1770.2.1 by Aaron Bentley
Use create_signature for signing policy, deprecate check_signatures for this
1205
        self.assertEqual(config.SIGN_NEVER,
1206
                         my_config.signing_policy())
1442.1.21 by Robert Collins
create signature_needed() call for commit to trigger creating signatures
1207
        self.assertEqual(False, my_config.signature_needed())
1442.1.16 by Robert Collins
allow global overriding of signature policy to never check
1208
1442.1.69 by Robert Collins
config.Config has a 'get_user_option' call that accepts an option name.
1209
    def _get_sample_config(self):
5345.2.9 by Vincent Ladeuil
Rename IniBaseConfig.from_bytes to from_string.
1210
        my_config = config.GlobalConfig.from_string(sample_config_text)
1534.7.154 by Aaron Bentley
Removed changes from bzr.ab 1529..1536
1211
        return my_config
1442.1.69 by Robert Collins
config.Config has a 'get_user_option' call that accepts an option name.
1212
1442.1.56 by Robert Collins
gpg_signing_command configuration item
1213
    def test_gpg_signing_command(self):
1442.1.69 by Robert Collins
config.Config has a 'get_user_option' call that accepts an option name.
1214
        my_config = self._get_sample_config()
1442.1.56 by Robert Collins
gpg_signing_command configuration item
1215
        self.assertEqual("gnome-gpg", my_config.gpg_signing_command())
1216
        self.assertEqual(False, my_config.signature_needed())
1217
1442.1.69 by Robert Collins
config.Config has a 'get_user_option' call that accepts an option name.
1218
    def _get_empty_config(self):
5345.2.2 by Vincent Ladeuil
Simplify test config building.
1219
        my_config = config.GlobalConfig()
1442.1.69 by Robert Collins
config.Config has a 'get_user_option' call that accepts an option name.
1220
        return my_config
1221
1442.1.59 by Robert Collins
Add re-sign command to generate a digital signature on a single revision.
1222
    def test_gpg_signing_command_unset(self):
1442.1.69 by Robert Collins
config.Config has a 'get_user_option' call that accepts an option name.
1223
        my_config = self._get_empty_config()
1442.1.59 by Robert Collins
Add re-sign command to generate a digital signature on a single revision.
1224
        self.assertEqual("gpg", my_config.gpg_signing_command())
1225
1442.1.69 by Robert Collins
config.Config has a 'get_user_option' call that accepts an option name.
1226
    def test_get_user_option_default(self):
1227
        my_config = self._get_empty_config()
1228
        self.assertEqual(None, my_config.get_user_option('no_option'))
1229
1230
    def test_get_user_option_global(self):
1231
        my_config = self._get_sample_config()
1232
        self.assertEqual("something",
1233
                         my_config.get_user_option('user_global_option'))
2991.2.2 by Vincent Ladeuil
No tests worth adding after upgrading to configobj-4.4.0.
1234
1472 by Robert Collins
post commit hook, first pass implementation
1235
    def test_post_commit_default(self):
1236
        my_config = self._get_sample_config()
1237
        self.assertEqual(None, my_config.post_commit())
1238
1553.2.9 by Erik Bågfors
log_formatter => log_format for "named" formatters
1239
    def test_configured_logformat(self):
1553.2.8 by Erik Bågfors
tests for config log_formatter
1240
        my_config = self._get_sample_config()
1553.2.9 by Erik Bågfors
log_formatter => log_format for "named" formatters
1241
        self.assertEqual("short", my_config.log_format())
1553.2.8 by Erik Bågfors
tests for config log_formatter
1242
1553.6.12 by Erik Bågfors
remove AliasConfig, based on input from abentley
1243
    def test_get_alias(self):
1244
        my_config = self._get_sample_config()
1245
        self.assertEqual('help', my_config.get_alias('h'))
1246
2900.3.6 by Tim Penhey
Added tests.
1247
    def test_get_aliases(self):
1248
        my_config = self._get_sample_config()
1249
        aliases = my_config.get_aliases()
1250
        self.assertEqual(2, len(aliases))
1251
        sorted_keys = sorted(aliases)
1252
        self.assertEqual('help', aliases[sorted_keys[0]])
1253
        self.assertEqual(sample_long_alias, aliases[sorted_keys[1]])
1254
1553.6.12 by Erik Bågfors
remove AliasConfig, based on input from abentley
1255
    def test_get_no_alias(self):
1256
        my_config = self._get_sample_config()
1257
        self.assertEqual(None, my_config.get_alias('foo'))
1258
1259
    def test_get_long_alias(self):
1260
        my_config = self._get_sample_config()
1261
        self.assertEqual(sample_long_alias, my_config.get_alias('ll'))
1442.1.69 by Robert Collins
config.Config has a 'get_user_option' call that accepts an option name.
1262
4603.1.10 by Aaron Bentley
Provide change editor via config.
1263
    def test_get_change_editor(self):
1264
        my_config = self._get_sample_config()
1265
        change_editor = my_config.get_change_editor('old', 'new')
1266
        self.assertIs(diff.DiffFromTool, change_editor.__class__)
4603.1.20 by Aaron Bentley
Use string.Template substitution with @ as delimiter.
1267
        self.assertEqual('vimdiff -of @new_path @old_path',
4603.1.10 by Aaron Bentley
Provide change editor via config.
1268
                         ' '.join(change_editor.command_template))
1269
1270
    def test_get_no_change_editor(self):
1271
        my_config = self._get_empty_config()
1272
        change_editor = my_config.get_change_editor('old', 'new')
1273
        self.assertIs(None, change_editor)
1274
5321.1.89 by Gordon Tyler
Moved mergetools config tests to bzrlib.tests.test_config.
1275
    def test_get_merge_tools(self):
1276
        conf = self._get_sample_config()
5321.1.116 by Gordon Tyler
Simplified mergetools module down to functions which deal with command lines -- no MergeTool class.
1277
        tools = conf.get_merge_tools()
5321.1.108 by Gordon Tyler
Changed known merge tools into a default set of merge tools that are always defined but can be overridden by user-defined merge tools.
1278
        self.log(repr(tools))
5321.1.116 by Gordon Tyler
Simplified mergetools module down to functions which deal with command lines -- no MergeTool class.
1279
        self.assertEqual(
1280
            {u'funkytool' : u'funkytool "arg with spaces" {this_temp}',
1281
            u'sometool' : u'sometool {base} {this} {other} -o {result}'},
5321.1.108 by Gordon Tyler
Changed known merge tools into a default set of merge tools that are always defined but can be overridden by user-defined merge tools.
1282
            tools)
5321.1.89 by Gordon Tyler
Moved mergetools config tests to bzrlib.tests.test_config.
1283
5321.1.116 by Gordon Tyler
Simplified mergetools module down to functions which deal with command lines -- no MergeTool class.
1284
    def test_get_merge_tools_empty(self):
5321.1.93 by Gordon Tyler
Added tests for get_default_merge_tool.
1285
        conf = self._get_empty_config()
5321.1.116 by Gordon Tyler
Simplified mergetools module down to functions which deal with command lines -- no MergeTool class.
1286
        tools = conf.get_merge_tools()
1287
        self.assertEqual({}, tools)
5321.1.103 by Gordon Tyler
Renamed _find_merge_tool back to find_merge_tool since it must be public for UI code to lookup merge tools by name, and added tests for it.
1288
1289
    def test_find_merge_tool(self):
1290
        conf = self._get_sample_config()
5321.1.116 by Gordon Tyler
Simplified mergetools module down to functions which deal with command lines -- no MergeTool class.
1291
        cmdline = conf.find_merge_tool('sometool')
1292
        self.assertEqual('sometool {base} {this} {other} -o {result}', cmdline)
5321.1.103 by Gordon Tyler
Renamed _find_merge_tool back to find_merge_tool since it must be public for UI code to lookup merge tools by name, and added tests for it.
1293
1294
    def test_find_merge_tool_not_found(self):
1295
        conf = self._get_sample_config()
5321.1.116 by Gordon Tyler
Simplified mergetools module down to functions which deal with command lines -- no MergeTool class.
1296
        cmdline = conf.find_merge_tool('DOES NOT EXIST')
1297
        self.assertIs(cmdline, None)
5321.1.93 by Gordon Tyler
Added tests for get_default_merge_tool.
1298
5321.1.108 by Gordon Tyler
Changed known merge tools into a default set of merge tools that are always defined but can be overridden by user-defined merge tools.
1299
    def test_find_merge_tool_known(self):
1300
        conf = self._get_empty_config()
5321.1.116 by Gordon Tyler
Simplified mergetools module down to functions which deal with command lines -- no MergeTool class.
1301
        cmdline = conf.find_merge_tool('kdiff3')
1302
        self.assertEquals('kdiff3 {base} {this} {other} -o {result}', cmdline)
5676.1.4 by Jelmer Vernooij
merge bzr.dev.
1303
5321.1.108 by Gordon Tyler
Changed known merge tools into a default set of merge tools that are always defined but can be overridden by user-defined merge tools.
1304
    def test_find_merge_tool_override_known(self):
1305
        conf = self._get_empty_config()
5321.1.112 by Gordon Tyler
Removed set_merge_tool, remove_merge_tool and set_default_merge_tool from Config.
1306
        conf.set_user_option('bzr.mergetool.kdiff3', 'kdiff3 blah')
5321.1.116 by Gordon Tyler
Simplified mergetools module down to functions which deal with command lines -- no MergeTool class.
1307
        cmdline = conf.find_merge_tool('kdiff3')
1308
        self.assertEqual('kdiff3 blah', cmdline)
5321.1.108 by Gordon Tyler
Changed known merge tools into a default set of merge tools that are always defined but can be overridden by user-defined merge tools.
1309
1704.2.18 by Martin Pool
Remove duplicated TestLocationConfig and update previously hidden tests. (#32587)
1310
2900.3.6 by Tim Penhey
Added tests.
1311
class TestGlobalConfigSavingOptions(tests.TestCaseInTempDir):
1312
1313
    def test_empty(self):
1314
        my_config = config.GlobalConfig()
1315
        self.assertEqual(0, len(my_config.get_aliases()))
1316
1317
    def test_set_alias(self):
1318
        my_config = config.GlobalConfig()
1319
        alias_value = 'commit --strict'
1320
        my_config.set_alias('commit', alias_value)
1321
        new_config = config.GlobalConfig()
1322
        self.assertEqual(alias_value, new_config.get_alias('commit'))
1323
1324
    def test_remove_alias(self):
1325
        my_config = config.GlobalConfig()
1326
        my_config.set_alias('commit', 'commit --strict')
1327
        # Now remove the alias again.
1328
        my_config.unset_alias('commit')
1329
        new_config = config.GlobalConfig()
1330
        self.assertIs(None, new_config.get_alias('commit'))
1331
1332
5533.2.1 by Vincent Ladeuil
``bzr config`` properly displays list values
1333
class TestLocationConfig(tests.TestCaseInTempDir, TestOptionsMixin):
1442.1.8 by Robert Collins
preparing some tests for LocationConfig
1334
1335
    def test_constructs(self):
1336
        my_config = config.LocationConfig('http://example.com')
1337
        self.assertRaises(TypeError, config.LocationConfig)
1338
1339
    def test_branch_calls_read_filenames(self):
1474 by Robert Collins
Merge from Aaron Bentley.
1340
        # This is testing the correct file names are provided.
1341
        # TODO: consolidate with the test for GlobalConfigs filename checks.
1342
        #
2991.2.2 by Vincent Ladeuil
No tests worth adding after upgrading to configobj-4.4.0.
1343
        # replace the class that is constructed, to check its parameters
1474 by Robert Collins
Merge from Aaron Bentley.
1344
        oldparserclass = config.ConfigObj
1345
        config.ConfigObj = InstrumentedConfigObj
1442.1.8 by Robert Collins
preparing some tests for LocationConfig
1346
        try:
1770.2.2 by Aaron Bentley
Rename branches.conf to locations.conf
1347
            my_config = config.LocationConfig('http://www.example.com')
1442.1.18 by Robert Collins
permit per branch location overriding of signature checking policy
1348
            parser = my_config._get_parser()
1442.1.8 by Robert Collins
preparing some tests for LocationConfig
1349
        finally:
1474 by Robert Collins
Merge from Aaron Bentley.
1350
            config.ConfigObj = oldparserclass
5784.1.1 by Martin Pool
Stop using failIf, failUnless, etc
1351
        self.assertIsInstance(parser, InstrumentedConfigObj)
1474 by Robert Collins
Merge from Aaron Bentley.
1352
        self.assertEqual(parser._calls,
1770.2.2 by Aaron Bentley
Rename branches.conf to locations.conf
1353
                         [('__init__', config.locations_config_filename(),
1704.2.18 by Martin Pool
Remove duplicated TestLocationConfig and update previously hidden tests. (#32587)
1354
                           'utf-8')])
1442.1.8 by Robert Collins
preparing some tests for LocationConfig
1355
1356
    def test_get_global_config(self):
1770.2.5 by Aaron Bentley
Integrate branch.conf into BranchConfig
1357
        my_config = config.BranchConfig(FakeBranch('http://example.com'))
1442.1.8 by Robert Collins
preparing some tests for LocationConfig
1358
        global_config = my_config._get_global_config()
5784.1.1 by Martin Pool
Stop using failIf, failUnless, etc
1359
        self.assertIsInstance(global_config, config.GlobalConfig)
1360
        self.assertIs(global_config, my_config._get_global_config())
1442.1.8 by Robert Collins
preparing some tests for LocationConfig
1361
5764.1.4 by Vincent Ladeuil
Using iterators is even clearer.
1362
    def assertLocationMatching(self, expected):
1363
        self.assertEqual(expected,
1364
                         list(self.my_location_config._get_matching_sections()))
1365
1993.3.1 by James Henstridge
first go at making location config lookup recursive
1366
    def test__get_matching_sections_no_match(self):
1770.2.5 by Aaron Bentley
Integrate branch.conf into BranchConfig
1367
        self.get_branch_config('/')
5764.1.4 by Vincent Ladeuil
Using iterators is even clearer.
1368
        self.assertLocationMatching([])
2991.2.2 by Vincent Ladeuil
No tests worth adding after upgrading to configobj-4.4.0.
1369
1993.3.1 by James Henstridge
first go at making location config lookup recursive
1370
    def test__get_matching_sections_exact(self):
1770.2.5 by Aaron Bentley
Integrate branch.conf into BranchConfig
1371
        self.get_branch_config('http://www.example.com')
5764.1.4 by Vincent Ladeuil
Using iterators is even clearer.
1372
        self.assertLocationMatching([('http://www.example.com', '')])
2991.2.2 by Vincent Ladeuil
No tests worth adding after upgrading to configobj-4.4.0.
1373
1993.3.1 by James Henstridge
first go at making location config lookup recursive
1374
    def test__get_matching_sections_suffix_does_not(self):
1770.2.5 by Aaron Bentley
Integrate branch.conf into BranchConfig
1375
        self.get_branch_config('http://www.example.com-com')
5764.1.4 by Vincent Ladeuil
Using iterators is even clearer.
1376
        self.assertLocationMatching([])
1442.1.8 by Robert Collins
preparing some tests for LocationConfig
1377
1993.3.1 by James Henstridge
first go at making location config lookup recursive
1378
    def test__get_matching_sections_subdir_recursive(self):
1770.2.5 by Aaron Bentley
Integrate branch.conf into BranchConfig
1379
        self.get_branch_config('http://www.example.com/com')
5764.1.4 by Vincent Ladeuil
Using iterators is even clearer.
1380
        self.assertLocationMatching([('http://www.example.com', 'com')])
1442.1.8 by Robert Collins
preparing some tests for LocationConfig
1381
1993.3.5 by James Henstridge
add back recurse=False option to config file
1382
    def test__get_matching_sections_ignoreparent(self):
1993.3.3 by James Henstridge
make _get_matching_sections() return (section, extra_path) tuples, and adjust other code to match
1383
        self.get_branch_config('http://www.example.com/ignoreparent')
5764.1.4 by Vincent Ladeuil
Using iterators is even clearer.
1384
        self.assertLocationMatching([('http://www.example.com/ignoreparent',
1385
                                      '')])
1442.1.8 by Robert Collins
preparing some tests for LocationConfig
1386
1993.3.5 by James Henstridge
add back recurse=False option to config file
1387
    def test__get_matching_sections_ignoreparent_subdir(self):
1770.2.5 by Aaron Bentley
Integrate branch.conf into BranchConfig
1388
        self.get_branch_config(
1993.3.3 by James Henstridge
make _get_matching_sections() return (section, extra_path) tuples, and adjust other code to match
1389
            'http://www.example.com/ignoreparent/childbranch')
5764.1.4 by Vincent Ladeuil
Using iterators is even clearer.
1390
        self.assertLocationMatching([('http://www.example.com/ignoreparent',
1391
                                      'childbranch')])
1442.1.8 by Robert Collins
preparing some tests for LocationConfig
1392
1993.3.1 by James Henstridge
first go at making location config lookup recursive
1393
    def test__get_matching_sections_subdir_trailing_slash(self):
1770.2.5 by Aaron Bentley
Integrate branch.conf into BranchConfig
1394
        self.get_branch_config('/b')
5764.1.4 by Vincent Ladeuil
Using iterators is even clearer.
1395
        self.assertLocationMatching([('/b/', '')])
1442.1.8 by Robert Collins
preparing some tests for LocationConfig
1396
1993.3.1 by James Henstridge
first go at making location config lookup recursive
1397
    def test__get_matching_sections_subdir_child(self):
1770.2.5 by Aaron Bentley
Integrate branch.conf into BranchConfig
1398
        self.get_branch_config('/a/foo')
5764.1.4 by Vincent Ladeuil
Using iterators is even clearer.
1399
        self.assertLocationMatching([('/a/*', ''), ('/a/', 'foo')])
1442.1.8 by Robert Collins
preparing some tests for LocationConfig
1400
1993.3.1 by James Henstridge
first go at making location config lookup recursive
1401
    def test__get_matching_sections_subdir_child_child(self):
1770.2.5 by Aaron Bentley
Integrate branch.conf into BranchConfig
1402
        self.get_branch_config('/a/foo/bar')
5764.1.4 by Vincent Ladeuil
Using iterators is even clearer.
1403
        self.assertLocationMatching([('/a/*', 'bar'), ('/a/', 'foo/bar')])
1442.1.8 by Robert Collins
preparing some tests for LocationConfig
1404
1993.3.1 by James Henstridge
first go at making location config lookup recursive
1405
    def test__get_matching_sections_trailing_slash_with_children(self):
1770.2.5 by Aaron Bentley
Integrate branch.conf into BranchConfig
1406
        self.get_branch_config('/a/')
5764.1.4 by Vincent Ladeuil
Using iterators is even clearer.
1407
        self.assertLocationMatching([('/a/', '')])
1442.1.18 by Robert Collins
permit per branch location overriding of signature checking policy
1408
1993.3.1 by James Henstridge
first go at making location config lookup recursive
1409
    def test__get_matching_sections_explicit_over_glob(self):
1410
        # XXX: 2006-09-08 jamesh
1411
        # This test only passes because ord('c') > ord('*').  If there
1412
        # was a config section for '/a/?', it would get precedence
1413
        # over '/a/c'.
1770.2.5 by Aaron Bentley
Integrate branch.conf into BranchConfig
1414
        self.get_branch_config('/a/c')
5764.1.4 by Vincent Ladeuil
Using iterators is even clearer.
1415
        self.assertLocationMatching([('/a/c', ''), ('/a/*', ''), ('/a/', 'c')])
1442.1.8 by Robert Collins
preparing some tests for LocationConfig
1416
2120.6.3 by James Henstridge
add some more tests for getting policy options, and behaviour of get_user_option in the presence of config policies
1417
    def test__get_option_policy_normal(self):
1418
        self.get_branch_config('http://www.example.com')
1419
        self.assertEqual(
1420
            self.my_location_config._get_config_policy(
1421
            'http://www.example.com', 'normal_option'),
1422
            config.POLICY_NONE)
1423
1424
    def test__get_option_policy_norecurse(self):
1425
        self.get_branch_config('http://www.example.com')
1426
        self.assertEqual(
1427
            self.my_location_config._get_option_policy(
1428
            'http://www.example.com', 'norecurse_option'),
1429
            config.POLICY_NORECURSE)
1430
        # Test old recurse=False setting:
1431
        self.assertEqual(
1432
            self.my_location_config._get_option_policy(
1433
            'http://www.example.com/norecurse', 'normal_option'),
1434
            config.POLICY_NORECURSE)
1435
1436
    def test__get_option_policy_normal(self):
1437
        self.get_branch_config('http://www.example.com')
1438
        self.assertEqual(
1439
            self.my_location_config._get_option_policy(
1440
            'http://www.example.com', 'appendpath_option'),
1441
            config.POLICY_APPENDPATH)
1442
5533.1.1 by Vincent Ladeuil
Fix ``bzr config`` to respect policies when displaying values and also display sections when appropriate.
1443
    def test__get_options_with_policy(self):
1444
        self.get_branch_config('/dir/subdir',
1445
                               location_config="""\
1446
[/dir]
1447
other_url = /other-dir
1448
other_url:policy = appendpath
1449
[/dir/subdir]
1450
other_url = /other-subdir
1451
""")
5533.2.1 by Vincent Ladeuil
``bzr config`` properly displays list values
1452
        self.assertOptions(
5533.1.1 by Vincent Ladeuil
Fix ``bzr config`` to respect policies when displaying values and also display sections when appropriate.
1453
            [(u'other_url', u'/other-subdir', u'/dir/subdir', 'locations'),
1454
             (u'other_url', u'/other-dir', u'/dir', 'locations'),
1455
             (u'other_url:policy', u'appendpath', u'/dir', 'locations')],
5533.2.1 by Vincent Ladeuil
``bzr config`` properly displays list values
1456
            self.my_location_config)
5533.1.1 by Vincent Ladeuil
Fix ``bzr config`` to respect policies when displaying values and also display sections when appropriate.
1457
1442.1.8 by Robert Collins
preparing some tests for LocationConfig
1458
    def test_location_without_username(self):
1993.3.3 by James Henstridge
make _get_matching_sections() return (section, extra_path) tuples, and adjust other code to match
1459
        self.get_branch_config('http://www.example.com/ignoreparent')
1704.2.18 by Martin Pool
Remove duplicated TestLocationConfig and update previously hidden tests. (#32587)
1460
        self.assertEqual(u'Erik B\u00e5gfors <erik@bagfors.nu>',
1442.1.8 by Robert Collins
preparing some tests for LocationConfig
1461
                         self.my_config.username())
1462
1463
    def test_location_not_listed(self):
1704.2.18 by Martin Pool
Remove duplicated TestLocationConfig and update previously hidden tests. (#32587)
1464
        """Test that the global username is used when no location matches"""
1770.2.5 by Aaron Bentley
Integrate branch.conf into BranchConfig
1465
        self.get_branch_config('/home/robertc/sources')
1704.2.18 by Martin Pool
Remove duplicated TestLocationConfig and update previously hidden tests. (#32587)
1466
        self.assertEqual(u'Erik B\u00e5gfors <erik@bagfors.nu>',
1442.1.8 by Robert Collins
preparing some tests for LocationConfig
1467
                         self.my_config.username())
1468
1442.1.13 by Robert Collins
branches.conf is now able to override the users email
1469
    def test_overriding_location(self):
1770.2.5 by Aaron Bentley
Integrate branch.conf into BranchConfig
1470
        self.get_branch_config('http://www.example.com/foo')
1442.1.13 by Robert Collins
branches.conf is now able to override the users email
1471
        self.assertEqual('Robert Collins <robertc@example.org>',
1472
                         self.my_config.username())
1442.1.16 by Robert Collins
allow global overriding of signature policy to never check
1473
1442.1.18 by Robert Collins
permit per branch location overriding of signature checking policy
1474
    def test_signatures_not_set(self):
1770.2.5 by Aaron Bentley
Integrate branch.conf into BranchConfig
1475
        self.get_branch_config('http://www.example.com',
1442.1.18 by Robert Collins
permit per branch location overriding of signature checking policy
1476
                                 global_config=sample_ignore_signatures)
1770.2.1 by Aaron Bentley
Use create_signature for signing policy, deprecate check_signatures for this
1477
        self.assertEqual(config.CHECK_ALWAYS,
1442.1.18 by Robert Collins
permit per branch location overriding of signature checking policy
1478
                         self.my_config.signature_checking())
1770.2.1 by Aaron Bentley
Use create_signature for signing policy, deprecate check_signatures for this
1479
        self.assertEqual(config.SIGN_NEVER,
1480
                         self.my_config.signing_policy())
1442.1.18 by Robert Collins
permit per branch location overriding of signature checking policy
1481
1482
    def test_signatures_never(self):
1770.2.5 by Aaron Bentley
Integrate branch.conf into BranchConfig
1483
        self.get_branch_config('/a/c')
1442.1.18 by Robert Collins
permit per branch location overriding of signature checking policy
1484
        self.assertEqual(config.CHECK_NEVER,
1485
                         self.my_config.signature_checking())
2991.2.2 by Vincent Ladeuil
No tests worth adding after upgrading to configobj-4.4.0.
1486
1442.1.16 by Robert Collins
allow global overriding of signature policy to never check
1487
    def test_signatures_when_available(self):
1770.2.5 by Aaron Bentley
Integrate branch.conf into BranchConfig
1488
        self.get_branch_config('/a/', global_config=sample_ignore_signatures)
1442.1.16 by Robert Collins
allow global overriding of signature policy to never check
1489
        self.assertEqual(config.CHECK_IF_POSSIBLE,
1490
                         self.my_config.signature_checking())
2991.2.2 by Vincent Ladeuil
No tests worth adding after upgrading to configobj-4.4.0.
1491
1442.1.18 by Robert Collins
permit per branch location overriding of signature checking policy
1492
    def test_signatures_always(self):
1770.2.5 by Aaron Bentley
Integrate branch.conf into BranchConfig
1493
        self.get_branch_config('/b')
1442.1.18 by Robert Collins
permit per branch location overriding of signature checking policy
1494
        self.assertEqual(config.CHECK_ALWAYS,
1495
                         self.my_config.signature_checking())
2991.2.2 by Vincent Ladeuil
No tests worth adding after upgrading to configobj-4.4.0.
1496
1442.1.56 by Robert Collins
gpg_signing_command configuration item
1497
    def test_gpg_signing_command(self):
1770.2.5 by Aaron Bentley
Integrate branch.conf into BranchConfig
1498
        self.get_branch_config('/b')
1442.1.56 by Robert Collins
gpg_signing_command configuration item
1499
        self.assertEqual("gnome-gpg", self.my_config.gpg_signing_command())
1500
1501
    def test_gpg_signing_command_missing(self):
1770.2.5 by Aaron Bentley
Integrate branch.conf into BranchConfig
1502
        self.get_branch_config('/a')
1442.1.56 by Robert Collins
gpg_signing_command configuration item
1503
        self.assertEqual("false", self.my_config.gpg_signing_command())
1504
1442.1.69 by Robert Collins
config.Config has a 'get_user_option' call that accepts an option name.
1505
    def test_get_user_option_global(self):
1770.2.5 by Aaron Bentley
Integrate branch.conf into BranchConfig
1506
        self.get_branch_config('/a')
1442.1.69 by Robert Collins
config.Config has a 'get_user_option' call that accepts an option name.
1507
        self.assertEqual('something',
1508
                         self.my_config.get_user_option('user_global_option'))
1509
1510
    def test_get_user_option_local(self):
1770.2.5 by Aaron Bentley
Integrate branch.conf into BranchConfig
1511
        self.get_branch_config('/a')
1442.1.69 by Robert Collins
config.Config has a 'get_user_option' call that accepts an option name.
1512
        self.assertEqual('local',
1513
                         self.my_config.get_user_option('user_local_option'))
1993.3.3 by James Henstridge
make _get_matching_sections() return (section, extra_path) tuples, and adjust other code to match
1514
2120.6.3 by James Henstridge
add some more tests for getting policy options, and behaviour of get_user_option in the presence of config policies
1515
    def test_get_user_option_appendpath(self):
1516
        # returned as is for the base path:
1517
        self.get_branch_config('http://www.example.com')
1518
        self.assertEqual('append',
1519
                         self.my_config.get_user_option('appendpath_option'))
1520
        # Extra path components get appended:
1521
        self.get_branch_config('http://www.example.com/a/b/c')
1522
        self.assertEqual('append/a/b/c',
1523
                         self.my_config.get_user_option('appendpath_option'))
1524
        # Overriden for http://www.example.com/dir, where it is a
1525
        # normal option:
1526
        self.get_branch_config('http://www.example.com/dir/a/b/c')
1527
        self.assertEqual('normal',
1528
                         self.my_config.get_user_option('appendpath_option'))
1529
1530
    def test_get_user_option_norecurse(self):
1531
        self.get_branch_config('http://www.example.com')
1532
        self.assertEqual('norecurse',
1533
                         self.my_config.get_user_option('norecurse_option'))
1534
        self.get_branch_config('http://www.example.com/dir')
1535
        self.assertEqual(None,
1536
                         self.my_config.get_user_option('norecurse_option'))
1537
        # http://www.example.com/norecurse is a recurse=False section
1538
        # that redefines normal_option.  Subdirectories do not pick up
1539
        # this redefinition.
1540
        self.get_branch_config('http://www.example.com/norecurse')
1541
        self.assertEqual('norecurse',
1542
                         self.my_config.get_user_option('normal_option'))
1543
        self.get_branch_config('http://www.example.com/norecurse/subdir')
1544
        self.assertEqual('normal',
1545
                         self.my_config.get_user_option('normal_option'))
1546
2120.6.4 by James Henstridge
add support for specifying policy when storing options
1547
    def test_set_user_option_norecurse(self):
1548
        self.get_branch_config('http://www.example.com')
1549
        self.my_config.set_user_option('foo', 'bar',
1550
                                       store=config.STORE_LOCATION_NORECURSE)
1551
        self.assertEqual(
1552
            self.my_location_config._get_option_policy(
1553
            'http://www.example.com', 'foo'),
1554
            config.POLICY_NORECURSE)
1555
1556
    def test_set_user_option_appendpath(self):
1557
        self.get_branch_config('http://www.example.com')
1558
        self.my_config.set_user_option('foo', 'bar',
1559
                                       store=config.STORE_LOCATION_APPENDPATH)
1560
        self.assertEqual(
1561
            self.my_location_config._get_option_policy(
1562
            'http://www.example.com', 'foo'),
1563
            config.POLICY_APPENDPATH)
1564
1565
    def test_set_user_option_change_policy(self):
1566
        self.get_branch_config('http://www.example.com')
1567
        self.my_config.set_user_option('norecurse_option', 'normal',
1568
                                       store=config.STORE_LOCATION)
1569
        self.assertEqual(
1570
            self.my_location_config._get_option_policy(
1571
            'http://www.example.com', 'norecurse_option'),
1572
            config.POLICY_NONE)
1573
1574
    def test_set_user_option_recurse_false_section(self):
2120.6.9 by James Henstridge
Fixes for issues brought up in John's review
1575
        # The following section has recurse=False set.  The test is to
1576
        # make sure that a normal option can be added to the section,
1577
        # converting recurse=False to the norecurse policy.
2120.6.4 by James Henstridge
add support for specifying policy when storing options
1578
        self.get_branch_config('http://www.example.com/norecurse')
2120.6.11 by James Henstridge
s/0.13/0.14/ in deprecation warning
1579
        self.callDeprecated(['The recurse option is deprecated as of 0.14.  '
2120.6.9 by James Henstridge
Fixes for issues brought up in John's review
1580
                             'The section "http://www.example.com/norecurse" '
1581
                             'has been converted to use policies.'],
1582
                            self.my_config.set_user_option,
1583
                            'foo', 'bar', store=config.STORE_LOCATION)
2120.6.4 by James Henstridge
add support for specifying policy when storing options
1584
        self.assertEqual(
1585
            self.my_location_config._get_option_policy(
1586
            'http://www.example.com/norecurse', 'foo'),
1587
            config.POLICY_NONE)
1588
        # The previously existing option is still norecurse:
1589
        self.assertEqual(
1590
            self.my_location_config._get_option_policy(
1591
            'http://www.example.com/norecurse', 'normal_option'),
1592
            config.POLICY_NORECURSE)
1593
1472 by Robert Collins
post commit hook, first pass implementation
1594
    def test_post_commit_default(self):
1770.2.5 by Aaron Bentley
Integrate branch.conf into BranchConfig
1595
        self.get_branch_config('/a/c')
1185.31.25 by John Arbash Meinel
Renamed all of the tests from selftest/foo.py to tests/test_foo.py
1596
        self.assertEqual('bzrlib.tests.test_config.post_commit',
1472 by Robert Collins
post commit hook, first pass implementation
1597
                         self.my_config.post_commit())
1442.1.69 by Robert Collins
config.Config has a 'get_user_option' call that accepts an option name.
1598
5533.1.1 by Vincent Ladeuil
Fix ``bzr config`` to respect policies when displaying values and also display sections when appropriate.
1599
    def get_branch_config(self, location, global_config=None,
1600
                          location_config=None):
5345.1.5 by Vincent Ladeuil
Fix fallouts by slightly editing the tests. More refactoring avoided to keep the review light.
1601
        my_branch = FakeBranch(location)
1502 by Robert Collins
Bugfix the config test suite to not create .bazaar in the dir where it is run.
1602
        if global_config is None:
5345.2.2 by Vincent Ladeuil
Simplify test config building.
1603
            global_config = sample_config_text
5533.1.1 by Vincent Ladeuil
Fix ``bzr config`` to respect policies when displaying values and also display sections when appropriate.
1604
        if location_config is None:
1605
            location_config = sample_branches_text
5345.1.5 by Vincent Ladeuil
Fix fallouts by slightly editing the tests. More refactoring avoided to keep the review light.
1606
5345.1.26 by Vincent Ladeuil
Merge lockable-config-files into remove-gratuitous-ensure-config-dir-exist-calls resolving conflicts
1607
        my_global_config = config.GlobalConfig.from_string(global_config,
1608
                                                           save=True)
5345.2.9 by Vincent Ladeuil
Rename IniBaseConfig.from_bytes to from_string.
1609
        my_location_config = config.LocationConfig.from_string(
5533.1.1 by Vincent Ladeuil
Fix ``bzr config`` to respect policies when displaying values and also display sections when appropriate.
1610
            location_config, my_branch.base, save=True)
5345.1.5 by Vincent Ladeuil
Fix fallouts by slightly editing the tests. More refactoring avoided to keep the review light.
1611
        my_config = config.BranchConfig(my_branch)
1612
        self.my_config = my_config
1613
        self.my_location_config = my_config._get_location_config()
1502 by Robert Collins
Bugfix the config test suite to not create .bazaar in the dir where it is run.
1614
1490 by Robert Collins
Implement a 'bzr push' command, with saved locations; update diff to return 1.
1615
    def test_set_user_setting_sets_and_saves(self):
1770.2.5 by Aaron Bentley
Integrate branch.conf into BranchConfig
1616
        self.get_branch_config('/a/c')
1490 by Robert Collins
Implement a 'bzr push' command, with saved locations; update diff to return 1.
1617
        record = InstrumentedConfigObj("foo")
1770.2.5 by Aaron Bentley
Integrate branch.conf into BranchConfig
1618
        self.my_location_config._parser = record
1185.62.6 by John Arbash Meinel
Updated test_set_user_setting_sets_and_saves to remove the print statement, and make sure it is doing the right thing
1619
5345.1.5 by Vincent Ladeuil
Fix fallouts by slightly editing the tests. More refactoring avoided to keep the review light.
1620
        self.callDeprecated(['The recurse option is deprecated as of '
1621
                             '0.14.  The section "/a/c" has been '
1622
                             'converted to use policies.'],
1623
                            self.my_config.set_user_option,
1624
                            'foo', 'bar', store=config.STORE_LOCATION)
5345.1.8 by Vincent Ladeuil
Make the test_listen_to_the_last_speaker pass and fix fallouts.
1625
        self.assertEqual([('reload',),
1626
                          ('__contains__', '/a/c'),
1490 by Robert Collins
Implement a 'bzr push' command, with saved locations; update diff to return 1.
1627
                          ('__contains__', '/a/c/'),
1628
                          ('__setitem__', '/a/c', {}),
1629
                          ('__getitem__', '/a/c'),
1630
                          ('__setitem__', 'foo', 'bar'),
2120.6.4 by James Henstridge
add support for specifying policy when storing options
1631
                          ('__getitem__', '/a/c'),
1632
                          ('as_bool', 'recurse'),
1633
                          ('__getitem__', '/a/c'),
1634
                          ('__delitem__', 'recurse'),
1635
                          ('__getitem__', '/a/c'),
1636
                          ('keys',),
2120.6.8 by James Henstridge
Change syntax for setting config option policies. Rather than
1637
                          ('__getitem__', '/a/c'),
1638
                          ('__contains__', 'foo:policy'),
1490 by Robert Collins
Implement a 'bzr push' command, with saved locations; update diff to return 1.
1639
                          ('write',)],
1640
                         record._calls[1:])
1641
1770.2.6 by Aaron Bentley
Ensure branch.conf works properly
1642
    def test_set_user_setting_sets_and_saves2(self):
1643
        self.get_branch_config('/a/c')
1644
        self.assertIs(self.my_config.get_user_option('foo'), None)
1645
        self.my_config.set_user_option('foo', 'bar')
1646
        self.assertEqual(
3616.2.6 by Mark Hammond
Fix test_set_user_setting_sets_and_saves2 on windows by stripping EOL
1647
            self.my_config.branch.control_files.files['branch.conf'].strip(),
1648
            'foo = bar')
1770.2.6 by Aaron Bentley
Ensure branch.conf works properly
1649
        self.assertEqual(self.my_config.get_user_option('foo'), 'bar')
2120.6.4 by James Henstridge
add support for specifying policy when storing options
1650
        self.my_config.set_user_option('foo', 'baz',
1651
                                       store=config.STORE_LOCATION)
1770.2.6 by Aaron Bentley
Ensure branch.conf works properly
1652
        self.assertEqual(self.my_config.get_user_option('foo'), 'baz')
1653
        self.my_config.set_user_option('foo', 'qux')
1654
        self.assertEqual(self.my_config.get_user_option('foo'), 'baz')
2991.2.2 by Vincent Ladeuil
No tests worth adding after upgrading to configobj-4.4.0.
1655
1551.18.17 by Aaron Bentley
Introduce bzr_remote_path configuration variable
1656
    def test_get_bzr_remote_path(self):
1657
        my_config = config.LocationConfig('/a/c')
1658
        self.assertEqual('bzr', my_config.get_bzr_remote_path())
1659
        my_config.set_user_option('bzr_remote_path', '/path-bzr')
1660
        self.assertEqual('/path-bzr', my_config.get_bzr_remote_path())
5570.3.9 by Vincent Ladeuil
More use cases for overrideEnv, _cleanEnvironment *may* contain too much variables now.
1661
        self.overrideEnv('BZR_REMOTE_PATH', '/environ-bzr')
1551.18.17 by Aaron Bentley
Introduce bzr_remote_path configuration variable
1662
        self.assertEqual('/environ-bzr', my_config.get_bzr_remote_path())
1663
1185.62.7 by John Arbash Meinel
Whitespace cleanup.
1664
1770.2.8 by Aaron Bentley
Add precedence test
1665
precedence_global = 'option = global'
1666
precedence_branch = 'option = branch'
1667
precedence_location = """
1668
[http://]
1669
recurse = true
1670
option = recurse
1671
[http://example.com/specific]
1672
option = exact
1673
"""
1674
2900.2.4 by Vincent Ladeuil
Cosmetic changes.
1675
class TestBranchConfigItems(tests.TestCaseInTempDir):
1442.1.6 by Robert Collins
first stage major overhaul of configs, giving use BranchConfigs, LocationConfigs and GlobalConfigs
1676
2991.2.2 by Vincent Ladeuil
No tests worth adding after upgrading to configobj-4.4.0.
1677
    def get_branch_config(self, global_config=None, location=None,
1770.2.6 by Aaron Bentley
Ensure branch.conf works properly
1678
                          location_config=None, branch_data_config=None):
5345.1.5 by Vincent Ladeuil
Fix fallouts by slightly editing the tests. More refactoring avoided to keep the review light.
1679
        my_branch = FakeBranch(location)
1770.2.5 by Aaron Bentley
Integrate branch.conf into BranchConfig
1680
        if global_config is not None:
5345.1.26 by Vincent Ladeuil
Merge lockable-config-files into remove-gratuitous-ensure-config-dir-exist-calls resolving conflicts
1681
            my_global_config = config.GlobalConfig.from_string(global_config,
1682
                                                               save=True)
1770.2.5 by Aaron Bentley
Integrate branch.conf into BranchConfig
1683
        if location_config is not None:
5345.2.9 by Vincent Ladeuil
Rename IniBaseConfig.from_bytes to from_string.
1684
            my_location_config = config.LocationConfig.from_string(
5345.1.25 by Vincent Ladeuil
Move the '_save' parameter from '__init__' to 'from_bytes', fix fallouts.
1685
                location_config, my_branch.base, save=True)
5345.1.5 by Vincent Ladeuil
Fix fallouts by slightly editing the tests. More refactoring avoided to keep the review light.
1686
        my_config = config.BranchConfig(my_branch)
1770.2.6 by Aaron Bentley
Ensure branch.conf works properly
1687
        if branch_data_config is not None:
1688
            my_config.branch.control_files.files['branch.conf'] = \
1689
                branch_data_config
1770.2.5 by Aaron Bentley
Integrate branch.conf into BranchConfig
1690
        return my_config
1691
1442.1.6 by Robert Collins
first stage major overhaul of configs, giving use BranchConfigs, LocationConfigs and GlobalConfigs
1692
    def test_user_id(self):
1770.2.5 by Aaron Bentley
Integrate branch.conf into BranchConfig
1693
        branch = FakeBranch(user_id='Robert Collins <robertc@example.net>')
1442.1.6 by Robert Collins
first stage major overhaul of configs, giving use BranchConfigs, LocationConfigs and GlobalConfigs
1694
        my_config = config.BranchConfig(branch)
1695
        self.assertEqual("Robert Collins <robertc@example.net>",
1770.2.6 by Aaron Bentley
Ensure branch.conf works properly
1696
                         my_config.username())
3388.2.3 by Martin Pool
Fix up more uses of LockableFiles.get_utf8 in tests
1697
        my_config.branch.control_files.files['email'] = "John"
2991.2.2 by Vincent Ladeuil
No tests worth adding after upgrading to configobj-4.4.0.
1698
        my_config.set_user_option('email',
1770.2.6 by Aaron Bentley
Ensure branch.conf works properly
1699
                                  "Robert Collins <robertc@example.org>")
1700
        self.assertEqual("John", my_config.username())
3388.2.3 by Martin Pool
Fix up more uses of LockableFiles.get_utf8 in tests
1701
        del my_config.branch.control_files.files['email']
1770.2.6 by Aaron Bentley
Ensure branch.conf works properly
1702
        self.assertEqual("Robert Collins <robertc@example.org>",
1703
                         my_config.username())
1442.1.6 by Robert Collins
first stage major overhaul of configs, giving use BranchConfigs, LocationConfigs and GlobalConfigs
1704
1705
    def test_not_set_in_branch(self):
5345.1.5 by Vincent Ladeuil
Fix fallouts by slightly editing the tests. More refactoring avoided to keep the review light.
1706
        my_config = self.get_branch_config(global_config=sample_config_text)
1551.2.21 by Aaron Bentley
Formatted unicode config tests as ASCII
1707
        self.assertEqual(u"Erik B\u00e5gfors <erik@bagfors.nu>",
1442.1.6 by Robert Collins
first stage major overhaul of configs, giving use BranchConfigs, LocationConfigs and GlobalConfigs
1708
                         my_config._get_user_id())
3388.2.3 by Martin Pool
Fix up more uses of LockableFiles.get_utf8 in tests
1709
        my_config.branch.control_files.files['email'] = "John"
1442.1.6 by Robert Collins
first stage major overhaul of configs, giving use BranchConfigs, LocationConfigs and GlobalConfigs
1710
        self.assertEqual("John", my_config._get_user_id())
1711
1861.4.1 by Matthieu Moy
BZREMAIL renamed to BZR_EMAIL.
1712
    def test_BZR_EMAIL_OVERRIDES(self):
5570.3.9 by Vincent Ladeuil
More use cases for overrideEnv, _cleanEnvironment *may* contain too much variables now.
1713
        self.overrideEnv('BZR_EMAIL', "Robert Collins <robertc@example.org>")
1442.1.6 by Robert Collins
first stage major overhaul of configs, giving use BranchConfigs, LocationConfigs and GlobalConfigs
1714
        branch = FakeBranch()
1715
        my_config = config.BranchConfig(branch)
1716
        self.assertEqual("Robert Collins <robertc@example.org>",
1717
                         my_config.username())
2991.2.2 by Vincent Ladeuil
No tests worth adding after upgrading to configobj-4.4.0.
1718
1442.1.19 by Robert Collins
BranchConfigs inherit signature_checking policy from their LocationConfig.
1719
    def test_signatures_forced(self):
1770.2.5 by Aaron Bentley
Integrate branch.conf into BranchConfig
1720
        my_config = self.get_branch_config(
1721
            global_config=sample_always_signatures)
1770.2.1 by Aaron Bentley
Use create_signature for signing policy, deprecate check_signatures for this
1722
        self.assertEqual(config.CHECK_NEVER, my_config.signature_checking())
1723
        self.assertEqual(config.SIGN_ALWAYS, my_config.signing_policy())
1724
        self.assertTrue(my_config.signature_needed())
1442.1.56 by Robert Collins
gpg_signing_command configuration item
1725
1770.2.6 by Aaron Bentley
Ensure branch.conf works properly
1726
    def test_signatures_forced_branch(self):
1727
        my_config = self.get_branch_config(
1728
            global_config=sample_ignore_signatures,
1729
            branch_data_config=sample_always_signatures)
1730
        self.assertEqual(config.CHECK_NEVER, my_config.signature_checking())
1731
        self.assertEqual(config.SIGN_ALWAYS, my_config.signing_policy())
1732
        self.assertTrue(my_config.signature_needed())
1733
1442.1.56 by Robert Collins
gpg_signing_command configuration item
1734
    def test_gpg_signing_command(self):
1770.2.10 by Aaron Bentley
Added test that branch_config can't influence gpg_signing_command
1735
        my_config = self.get_branch_config(
5345.1.5 by Vincent Ladeuil
Fix fallouts by slightly editing the tests. More refactoring avoided to keep the review light.
1736
            global_config=sample_config_text,
1770.2.10 by Aaron Bentley
Added test that branch_config can't influence gpg_signing_command
1737
            # branch data cannot set gpg_signing_command
1738
            branch_data_config="gpg_signing_command=pgp")
1442.1.56 by Robert Collins
gpg_signing_command configuration item
1739
        self.assertEqual('gnome-gpg', my_config.gpg_signing_command())
1442.1.69 by Robert Collins
config.Config has a 'get_user_option' call that accepts an option name.
1740
1741
    def test_get_user_option_global(self):
5345.1.5 by Vincent Ladeuil
Fix fallouts by slightly editing the tests. More refactoring avoided to keep the review light.
1742
        my_config = self.get_branch_config(global_config=sample_config_text)
1442.1.69 by Robert Collins
config.Config has a 'get_user_option' call that accepts an option name.
1743
        self.assertEqual('something',
1744
                         my_config.get_user_option('user_global_option'))
1472 by Robert Collins
post commit hook, first pass implementation
1745
1746
    def test_post_commit_default(self):
5345.1.5 by Vincent Ladeuil
Fix fallouts by slightly editing the tests. More refactoring avoided to keep the review light.
1747
        my_config = self.get_branch_config(global_config=sample_config_text,
1748
                                      location='/a/c',
1749
                                      location_config=sample_branches_text)
1770.2.5 by Aaron Bentley
Integrate branch.conf into BranchConfig
1750
        self.assertEqual(my_config.branch.base, '/a/c')
1185.31.25 by John Arbash Meinel
Renamed all of the tests from selftest/foo.py to tests/test_foo.py
1751
        self.assertEqual('bzrlib.tests.test_config.post_commit',
1472 by Robert Collins
post commit hook, first pass implementation
1752
                         my_config.post_commit())
1770.2.6 by Aaron Bentley
Ensure branch.conf works properly
1753
        my_config.set_user_option('post_commit', 'rmtree_root')
5345.1.5 by Vincent Ladeuil
Fix fallouts by slightly editing the tests. More refactoring avoided to keep the review light.
1754
        # post-commit is ignored when present in branch data
1770.2.6 by Aaron Bentley
Ensure branch.conf works properly
1755
        self.assertEqual('bzrlib.tests.test_config.post_commit',
1756
                         my_config.post_commit())
2120.6.4 by James Henstridge
add support for specifying policy when storing options
1757
        my_config.set_user_option('post_commit', 'rmtree_root',
1758
                                  store=config.STORE_LOCATION)
1770.2.6 by Aaron Bentley
Ensure branch.conf works properly
1759
        self.assertEqual('rmtree_root', my_config.post_commit())
1185.33.31 by Martin Pool
Make annotate cope better with revisions committed without a valid
1760
1770.2.8 by Aaron Bentley
Add precedence test
1761
    def test_config_precedence(self):
5345.1.5 by Vincent Ladeuil
Fix fallouts by slightly editing the tests. More refactoring avoided to keep the review light.
1762
        # FIXME: eager test, luckily no persitent config file makes it fail
1763
        # -- vila 20100716
1770.2.8 by Aaron Bentley
Add precedence test
1764
        my_config = self.get_branch_config(global_config=precedence_global)
1765
        self.assertEqual(my_config.get_user_option('option'), 'global')
2991.2.2 by Vincent Ladeuil
No tests worth adding after upgrading to configobj-4.4.0.
1766
        my_config = self.get_branch_config(global_config=precedence_global,
5345.1.5 by Vincent Ladeuil
Fix fallouts by slightly editing the tests. More refactoring avoided to keep the review light.
1767
                                           branch_data_config=precedence_branch)
1770.2.8 by Aaron Bentley
Add precedence test
1768
        self.assertEqual(my_config.get_user_option('option'), 'branch')
5345.1.5 by Vincent Ladeuil
Fix fallouts by slightly editing the tests. More refactoring avoided to keep the review light.
1769
        my_config = self.get_branch_config(
1770
            global_config=precedence_global,
1771
            branch_data_config=precedence_branch,
1772
            location_config=precedence_location)
1770.2.8 by Aaron Bentley
Add precedence test
1773
        self.assertEqual(my_config.get_user_option('option'), 'recurse')
5345.1.5 by Vincent Ladeuil
Fix fallouts by slightly editing the tests. More refactoring avoided to keep the review light.
1774
        my_config = self.get_branch_config(
1775
            global_config=precedence_global,
1776
            branch_data_config=precedence_branch,
1777
            location_config=precedence_location,
1778
            location='http://example.com/specific')
1770.2.8 by Aaron Bentley
Add precedence test
1779
        self.assertEqual(my_config.get_user_option('option'), 'exact')
1780
2681.1.8 by Aaron Bentley
Add Thunderbird support to bzr send
1781
    def test_get_mail_client(self):
1782
        config = self.get_branch_config()
1783
        client = config.get_mail_client()
2681.1.24 by Aaron Bentley
Handle default mail client by trying xdg-email, falling back to editor
1784
        self.assertIsInstance(client, mail_client.DefaultMail)
1785
2790.2.2 by Keir Mierle
Change alphabetic ordering into two categories; one for specific clients the other for generic options.
1786
        # Specific clients
2681.1.21 by Aaron Bentley
Refactor prompt generation to make it testable, test it with unicode
1787
        config.set_user_option('mail_client', 'evolution')
1788
        client = config.get_mail_client()
1789
        self.assertIsInstance(client, mail_client.Evolution)
1790
2681.5.1 by ghigo
Add KMail support to bzr send
1791
        config.set_user_option('mail_client', 'kmail')
1792
        client = config.get_mail_client()
1793
        self.assertIsInstance(client, mail_client.KMail)
1794
2790.2.1 by Keir Mierle
Add Mutt as a supported client email program. Also rearranges various listings
1795
        config.set_user_option('mail_client', 'mutt')
1796
        client = config.get_mail_client()
1797
        self.assertIsInstance(client, mail_client.Mutt)
1798
1799
        config.set_user_option('mail_client', 'thunderbird')
1800
        client = config.get_mail_client()
1801
        self.assertIsInstance(client, mail_client.Thunderbird)
1802
2790.2.2 by Keir Mierle
Change alphabetic ordering into two categories; one for specific clients the other for generic options.
1803
        # Generic options
1804
        config.set_user_option('mail_client', 'default')
1805
        client = config.get_mail_client()
1806
        self.assertIsInstance(client, mail_client.DefaultMail)
1807
1808
        config.set_user_option('mail_client', 'editor')
1809
        client = config.get_mail_client()
1810
        self.assertIsInstance(client, mail_client.Editor)
1811
1812
        config.set_user_option('mail_client', 'mapi')
1813
        client = config.get_mail_client()
1814
        self.assertIsInstance(client, mail_client.MAPIClient)
1815
2681.1.23 by Aaron Bentley
Add support for xdg-email
1816
        config.set_user_option('mail_client', 'xdg-email')
1817
        client = config.get_mail_client()
1818
        self.assertIsInstance(client, mail_client.XDGEmail)
1819
2681.1.10 by Aaron Bentley
Clean up handling of unknown mail clients
1820
        config.set_user_option('mail_client', 'firebird')
1821
        self.assertRaises(errors.UnknownMailClient, config.get_mail_client)
1822
1185.33.31 by Martin Pool
Make annotate cope better with revisions committed without a valid
1823
2900.2.4 by Vincent Ladeuil
Cosmetic changes.
1824
class TestMailAddressExtraction(tests.TestCase):
1185.33.31 by Martin Pool
Make annotate cope better with revisions committed without a valid
1825
1826
    def test_extract_email_address(self):
1827
        self.assertEqual('jane@test.com',
1828
                         config.extract_email_address('Jane <jane@test.com>'))
2055.2.2 by John Arbash Meinel
Switch extract_email_address() to use a more specific exception
1829
        self.assertRaises(errors.NoEmailInUsername,
1185.33.31 by Martin Pool
Make annotate cope better with revisions committed without a valid
1830
                          config.extract_email_address, 'Jane Tester')
2533.1.1 by James Westby
Fix TreeConfig to return values from sections.
1831
3063.3.2 by Lukáš Lalinský
Move the name and e-mail address extraction logic to config.parse_username.
1832
    def test_parse_username(self):
1833
        self.assertEqual(('', 'jdoe@example.com'),
1834
                         config.parse_username('jdoe@example.com'))
1835
        self.assertEqual(('', 'jdoe@example.com'),
1836
                         config.parse_username('<jdoe@example.com>'))
1837
        self.assertEqual(('John Doe', 'jdoe@example.com'),
1838
                         config.parse_username('John Doe <jdoe@example.com>'))
1839
        self.assertEqual(('John Doe', ''),
1840
                         config.parse_username('John Doe'))
3063.3.3 by Lukáš Lalinský
Add one more test for config.parse_username().
1841
        self.assertEqual(('John Doe', 'jdoe@example.com'),
1842
                         config.parse_username('John Doe jdoe@example.com'))
2562.1.2 by John Arbash Meinel
Clean up whitespace
1843
2900.2.4 by Vincent Ladeuil
Cosmetic changes.
1844
class TestTreeConfig(tests.TestCaseWithTransport):
2533.1.1 by James Westby
Fix TreeConfig to return values from sections.
1845
1846
    def test_get_value(self):
1847
        """Test that retreiving a value from a section is possible"""
1848
        branch = self.make_branch('.')
1849
        tree_config = config.TreeConfig(branch)
1850
        tree_config.set_option('value', 'key', 'SECTION')
1851
        tree_config.set_option('value2', 'key2')
1852
        tree_config.set_option('value3-top', 'key3')
1853
        tree_config.set_option('value3-section', 'key3', 'SECTION')
1854
        value = tree_config.get_option('key', 'SECTION')
1855
        self.assertEqual(value, 'value')
1856
        value = tree_config.get_option('key2')
1857
        self.assertEqual(value, 'value2')
1858
        self.assertEqual(tree_config.get_option('non-existant'), None)
1859
        value = tree_config.get_option('non-existant', 'SECTION')
1860
        self.assertEqual(value, None)
1861
        value = tree_config.get_option('non-existant', default='default')
1862
        self.assertEqual(value, 'default')
1863
        self.assertEqual(tree_config.get_option('key2', 'NOSECTION'), None)
1864
        value = tree_config.get_option('key2', 'NOSECTION', default='default')
1865
        self.assertEqual(value, 'default')
1866
        value = tree_config.get_option('key3')
1867
        self.assertEqual(value, 'value3-top')
1868
        value = tree_config.get_option('key3', 'SECTION')
1869
        self.assertEqual(value, 'value3-section')
2900.2.3 by Vincent Ladeuil
Credentials matching implementation.
1870
1871
3242.1.2 by Aaron Bentley
Turn BzrDirConfig into TransportConfig, reduce code duplication
1872
class TestTransportConfig(tests.TestCaseWithTransport):
3242.1.1 by Aaron Bentley
Implement BzrDir configuration
1873
5987.1.4 by Vincent Ladeuil
Proper error messages for config files with content in non-utf encoding or that cannot be parsed
1874
    def test_load_utf8(self):
1875
        """Ensure we can load an utf8-encoded file."""
1876
        t = self.get_transport()
1877
        unicode_user = u'b\N{Euro Sign}ar'
1878
        unicode_content = u'user=%s' % (unicode_user,)
1879
        utf8_content = unicode_content.encode('utf8')
1880
        # Store the raw content in the config file
1881
        t.put_bytes('foo.conf', utf8_content)
1882
        conf = config.TransportConfig(t, 'foo.conf')
1883
        self.assertEquals(unicode_user, conf.get_option('user'))
1884
1885
    def test_load_non_ascii(self):
1886
        """Ensure we display a proper error on non-ascii, non utf-8 content."""
1887
        t = self.get_transport()
1888
        t.put_bytes('foo.conf', 'user=foo\n#\xff\n')
1889
        conf = config.TransportConfig(t, 'foo.conf')
1890
        self.assertRaises(errors.ConfigContentError, conf._get_configobj)
1891
1892
    def test_load_erroneous_content(self):
1893
        """Ensure we display a proper error on content that can't be parsed."""
1894
        t = self.get_transport()
1895
        t.put_bytes('foo.conf', '[open_section\n')
1896
        conf = config.TransportConfig(t, 'foo.conf')
1897
        self.assertRaises(errors.ParseConfigError, conf._get_configobj)
1898
3242.1.1 by Aaron Bentley
Implement BzrDir configuration
1899
    def test_get_value(self):
1900
        """Test that retreiving a value from a section is possible"""
5987.1.4 by Vincent Ladeuil
Proper error messages for config files with content in non-utf encoding or that cannot be parsed
1901
        bzrdir_config = config.TransportConfig(self.get_transport('.'),
3242.1.2 by Aaron Bentley
Turn BzrDirConfig into TransportConfig, reduce code duplication
1902
                                               'control.conf')
3242.1.1 by Aaron Bentley
Implement BzrDir configuration
1903
        bzrdir_config.set_option('value', 'key', 'SECTION')
1904
        bzrdir_config.set_option('value2', 'key2')
1905
        bzrdir_config.set_option('value3-top', 'key3')
1906
        bzrdir_config.set_option('value3-section', 'key3', 'SECTION')
1907
        value = bzrdir_config.get_option('key', 'SECTION')
1908
        self.assertEqual(value, 'value')
1909
        value = bzrdir_config.get_option('key2')
1910
        self.assertEqual(value, 'value2')
1911
        self.assertEqual(bzrdir_config.get_option('non-existant'), None)
1912
        value = bzrdir_config.get_option('non-existant', 'SECTION')
1913
        self.assertEqual(value, None)
1914
        value = bzrdir_config.get_option('non-existant', default='default')
1915
        self.assertEqual(value, 'default')
1916
        self.assertEqual(bzrdir_config.get_option('key2', 'NOSECTION'), None)
1917
        value = bzrdir_config.get_option('key2', 'NOSECTION',
1918
                                         default='default')
1919
        self.assertEqual(value, 'default')
1920
        value = bzrdir_config.get_option('key3')
1921
        self.assertEqual(value, 'value3-top')
1922
        value = bzrdir_config.get_option('key3', 'SECTION')
1923
        self.assertEqual(value, 'value3-section')
1924
3242.3.11 by Aaron Bentley
Clean up BzrDirConfig usage
1925
    def test_set_unset_default_stack_on(self):
1926
        my_dir = self.make_bzrdir('.')
4288.1.3 by Robert Collins
Fix BzrDirConfig tests.
1927
        bzrdir_config = config.BzrDirConfig(my_dir)
3242.3.11 by Aaron Bentley
Clean up BzrDirConfig usage
1928
        self.assertIs(None, bzrdir_config.get_default_stack_on())
1929
        bzrdir_config.set_default_stack_on('Foo')
3242.3.14 by Aaron Bentley
Make BzrDirConfig use TransportConfig
1930
        self.assertEqual('Foo', bzrdir_config._config.get_option(
1931
                         'default_stack_on'))
3242.3.11 by Aaron Bentley
Clean up BzrDirConfig usage
1932
        self.assertEqual('Foo', bzrdir_config.get_default_stack_on())
1933
        bzrdir_config.set_default_stack_on(None)
1934
        self.assertIs(None, bzrdir_config.get_default_stack_on())
1935
3242.1.1 by Aaron Bentley
Implement BzrDir configuration
1936
5743.8.19 by Vincent Ladeuil
Revert the mixin addition, no way to share with remote configs which implements a different API.
1937
class TestOldConfigHooks(tests.TestCaseWithTransport):
1938
1939
    def setUp(self):
1940
        super(TestOldConfigHooks, self).setUp()
1941
        create_configs_with_file_option(self)
5743.8.15 by Vincent Ladeuil
Add tests for old config hooks covering bazaar.conf, locations.conf and branch.conf.
1942
1943
    def assertGetHook(self, conf, name, value):
1944
        calls = []
1945
        def hook(*args):
1946
            calls.append(args)
5743.8.24 by Vincent Ladeuil
Clearly seaparate both sets of hooks for the old and new config implementations.
1947
        config.OldConfigHooks.install_named_hook('get', hook, None)
5743.8.23 by Vincent Ladeuil
Don't publicize the hooks yet and add proper cleanups to avoid hook leaks (or hooks triggering during tests cleanup).
1948
        self.addCleanup(
5743.8.24 by Vincent Ladeuil
Clearly seaparate both sets of hooks for the old and new config implementations.
1949
            config.OldConfigHooks.uninstall_named_hook, 'get', None)
5743.8.15 by Vincent Ladeuil
Add tests for old config hooks covering bazaar.conf, locations.conf and branch.conf.
1950
        self.assertLength(0, calls)
1951
        actual_value = conf.get_user_option(name)
1952
        self.assertEquals(value, actual_value)
1953
        self.assertLength(1, calls)
1954
        self.assertEquals((conf, name, value), calls[0])
1955
1956
    def test_get_hook_bazaar(self):
1957
        self.assertGetHook(self.bazaar_config, 'file', 'bazaar')
1958
1959
    def test_get_hook_locations(self):
1960
        self.assertGetHook(self.locations_config, 'file', 'locations')
1961
1962
    def test_get_hook_branch(self):
1963
        # Since locations masks branch, we define a different option
1964
        self.branch_config.set_user_option('file2', 'branch')
1965
        self.assertGetHook(self.branch_config, 'file2', 'branch')
1966
5743.8.19 by Vincent Ladeuil
Revert the mixin addition, no way to share with remote configs which implements a different API.
1967
    def assertSetHook(self, conf, name, value):
1968
        calls = []
1969
        def hook(*args):
1970
            calls.append(args)
5743.8.24 by Vincent Ladeuil
Clearly seaparate both sets of hooks for the old and new config implementations.
1971
        config.OldConfigHooks.install_named_hook('set', hook, None)
5743.8.23 by Vincent Ladeuil
Don't publicize the hooks yet and add proper cleanups to avoid hook leaks (or hooks triggering during tests cleanup).
1972
        self.addCleanup(
5743.8.24 by Vincent Ladeuil
Clearly seaparate both sets of hooks for the old and new config implementations.
1973
            config.OldConfigHooks.uninstall_named_hook, 'set', None)
5743.8.19 by Vincent Ladeuil
Revert the mixin addition, no way to share with remote configs which implements a different API.
1974
        self.assertLength(0, calls)
1975
        conf.set_user_option(name, value)
1976
        self.assertLength(1, calls)
1977
        # We can't assert the conf object below as different configs use
1978
        # different means to implement set_user_option and we care only about
1979
        # coverage here.
1980
        self.assertEquals((name, value), calls[0][1:])
1981
5743.8.15 by Vincent Ladeuil
Add tests for old config hooks covering bazaar.conf, locations.conf and branch.conf.
1982
    def test_set_hook_bazaar(self):
1983
        self.assertSetHook(self.bazaar_config, 'foo', 'bazaar')
1984
1985
    def test_set_hook_locations(self):
1986
        self.assertSetHook(self.locations_config, 'foo', 'locations')
1987
1988
    def test_set_hook_branch(self):
1989
        self.assertSetHook(self.branch_config, 'foo', 'branch')
1990
5743.8.19 by Vincent Ladeuil
Revert the mixin addition, no way to share with remote configs which implements a different API.
1991
    def assertRemoveHook(self, conf, name, section_name=None):
1992
        calls = []
1993
        def hook(*args):
1994
            calls.append(args)
5743.8.24 by Vincent Ladeuil
Clearly seaparate both sets of hooks for the old and new config implementations.
1995
        config.OldConfigHooks.install_named_hook('remove', hook, None)
5743.8.23 by Vincent Ladeuil
Don't publicize the hooks yet and add proper cleanups to avoid hook leaks (or hooks triggering during tests cleanup).
1996
        self.addCleanup(
5743.8.24 by Vincent Ladeuil
Clearly seaparate both sets of hooks for the old and new config implementations.
1997
            config.OldConfigHooks.uninstall_named_hook, 'remove', None)
5743.8.19 by Vincent Ladeuil
Revert the mixin addition, no way to share with remote configs which implements a different API.
1998
        self.assertLength(0, calls)
1999
        conf.remove_user_option(name, section_name)
2000
        self.assertLength(1, calls)
2001
        # We can't assert the conf object below as different configs use
2002
        # different means to implement remove_user_option and we care only about
2003
        # coverage here.
2004
        self.assertEquals((name,), calls[0][1:])
2005
5743.8.15 by Vincent Ladeuil
Add tests for old config hooks covering bazaar.conf, locations.conf and branch.conf.
2006
    def test_remove_hook_bazaar(self):
2007
        self.assertRemoveHook(self.bazaar_config, 'file')
2008
2009
    def test_remove_hook_locations(self):
2010
        self.assertRemoveHook(self.locations_config, 'file',
2011
                              self.locations_config.location)
2012
2013
    def test_remove_hook_branch(self):
2014
        self.assertRemoveHook(self.branch_config, 'file')
2015
5743.8.19 by Vincent Ladeuil
Revert the mixin addition, no way to share with remote configs which implements a different API.
2016
    def assertLoadHook(self, name, conf_class, *conf_args):
2017
        calls = []
2018
        def hook(*args):
2019
            calls.append(args)
5743.8.24 by Vincent Ladeuil
Clearly seaparate both sets of hooks for the old and new config implementations.
2020
        config.OldConfigHooks.install_named_hook('load', hook, None)
5743.8.23 by Vincent Ladeuil
Don't publicize the hooks yet and add proper cleanups to avoid hook leaks (or hooks triggering during tests cleanup).
2021
        self.addCleanup(
5743.8.24 by Vincent Ladeuil
Clearly seaparate both sets of hooks for the old and new config implementations.
2022
            config.OldConfigHooks.uninstall_named_hook, 'load', None)
5743.8.19 by Vincent Ladeuil
Revert the mixin addition, no way to share with remote configs which implements a different API.
2023
        self.assertLength(0, calls)
2024
        # Build a config
2025
        conf = conf_class(*conf_args)
2026
        # Access an option to trigger a load
2027
        conf.get_user_option(name)
2028
        self.assertLength(1, calls)
2029
        # Since we can't assert about conf, we just use the number of calls ;-/
2030
5743.8.15 by Vincent Ladeuil
Add tests for old config hooks covering bazaar.conf, locations.conf and branch.conf.
2031
    def test_load_hook_bazaar(self):
2032
        self.assertLoadHook('file', config.GlobalConfig)
2033
2034
    def test_load_hook_locations(self):
2035
        self.assertLoadHook('file', config.LocationConfig, self.tree.basedir)
2036
2037
    def test_load_hook_branch(self):
2038
        self.assertLoadHook('file', config.BranchConfig, self.tree.branch)
2039
5743.8.19 by Vincent Ladeuil
Revert the mixin addition, no way to share with remote configs which implements a different API.
2040
    def assertSaveHook(self, conf):
2041
        calls = []
2042
        def hook(*args):
2043
            calls.append(args)
5743.8.24 by Vincent Ladeuil
Clearly seaparate both sets of hooks for the old and new config implementations.
2044
        config.OldConfigHooks.install_named_hook('save', hook, None)
5743.8.23 by Vincent Ladeuil
Don't publicize the hooks yet and add proper cleanups to avoid hook leaks (or hooks triggering during tests cleanup).
2045
        self.addCleanup(
5743.8.24 by Vincent Ladeuil
Clearly seaparate both sets of hooks for the old and new config implementations.
2046
            config.OldConfigHooks.uninstall_named_hook, 'save', None)
5743.8.19 by Vincent Ladeuil
Revert the mixin addition, no way to share with remote configs which implements a different API.
2047
        self.assertLength(0, calls)
2048
        # Setting an option triggers a save
2049
        conf.set_user_option('foo', 'bar')
2050
        self.assertLength(1, calls)
2051
        # Since we can't assert about conf, we just use the number of calls ;-/
2052
5743.8.15 by Vincent Ladeuil
Add tests for old config hooks covering bazaar.conf, locations.conf and branch.conf.
2053
    def test_save_hook_bazaar(self):
2054
        self.assertSaveHook(self.bazaar_config)
2055
2056
    def test_save_hook_locations(self):
2057
        self.assertSaveHook(self.locations_config)
2058
2059
    def test_save_hook_branch(self):
2060
        self.assertSaveHook(self.branch_config)
2061
2062
5743.8.20 by Vincent Ladeuil
Add tests for set hook.
2063
class TestOldConfigHooksForRemote(tests.TestCaseWithTransport):
2064
    """Tests config hooks for remote configs.
2065
2066
    No tests for the remove hook as this is not implemented there.
2067
    """
5743.8.17 by Vincent Ladeuil
Add config old_get hook for remote config.
2068
2069
    def setUp(self):
2070
        super(TestOldConfigHooksForRemote, self).setUp()
2071
        self.transport_server = test_server.SmartTCPServer_for_testing
2072
        create_configs_with_file_option(self)
2073
5743.8.18 by Vincent Ladeuil
Add a test for remote bzr dir.
2074
    def assertGetHook(self, conf, name, value):
2075
        calls = []
2076
        def hook(*args):
2077
            calls.append(args)
5743.8.24 by Vincent Ladeuil
Clearly seaparate both sets of hooks for the old and new config implementations.
2078
        config.OldConfigHooks.install_named_hook('get', hook, None)
5743.8.21 by Vincent Ladeuil
Add test for config load hook for remote configs.
2079
        self.addCleanup(
5743.8.24 by Vincent Ladeuil
Clearly seaparate both sets of hooks for the old and new config implementations.
2080
            config.OldConfigHooks.uninstall_named_hook, 'get', None)
5743.8.18 by Vincent Ladeuil
Add a test for remote bzr dir.
2081
        self.assertLength(0, calls)
2082
        actual_value = conf.get_option(name)
2083
        self.assertEquals(value, actual_value)
2084
        self.assertLength(1, calls)
2085
        self.assertEquals((conf, name, value), calls[0])
2086
2087
    def test_get_hook_remote_branch(self):
5743.8.17 by Vincent Ladeuil
Add config old_get hook for remote config.
2088
        remote_branch = branch.Branch.open(self.get_url('tree'))
5743.8.18 by Vincent Ladeuil
Add a test for remote bzr dir.
2089
        self.assertGetHook(remote_branch._get_config(), 'file', 'branch')
5743.8.17 by Vincent Ladeuil
Add config old_get hook for remote config.
2090
5743.8.18 by Vincent Ladeuil
Add a test for remote bzr dir.
2091
    def test_get_hook_remote_bzrdir(self):
2092
        remote_bzrdir = bzrdir.BzrDir.open(self.get_url('tree'))
2093
        conf = remote_bzrdir._get_config()
2094
        conf.set_option('remotedir', 'file')
2095
        self.assertGetHook(conf, 'file', 'remotedir')
5743.8.17 by Vincent Ladeuil
Add config old_get hook for remote config.
2096
5743.8.20 by Vincent Ladeuil
Add tests for set hook.
2097
    def assertSetHook(self, conf, name, value):
2098
        calls = []
2099
        def hook(*args):
2100
            calls.append(args)
5743.8.24 by Vincent Ladeuil
Clearly seaparate both sets of hooks for the old and new config implementations.
2101
        config.OldConfigHooks.install_named_hook('set', hook, None)
5743.8.21 by Vincent Ladeuil
Add test for config load hook for remote configs.
2102
        self.addCleanup(
5743.8.24 by Vincent Ladeuil
Clearly seaparate both sets of hooks for the old and new config implementations.
2103
            config.OldConfigHooks.uninstall_named_hook, 'set', None)
5743.8.20 by Vincent Ladeuil
Add tests for set hook.
2104
        self.assertLength(0, calls)
2105
        conf.set_option(value, name)
2106
        self.assertLength(1, calls)
2107
        # We can't assert the conf object below as different configs use
2108
        # different means to implement set_user_option and we care only about
2109
        # coverage here.
2110
        self.assertEquals((name, value), calls[0][1:])
2111
2112
    def test_set_hook_remote_branch(self):
2113
        remote_branch = branch.Branch.open(self.get_url('tree'))
2114
        self.addCleanup(remote_branch.lock_write().unlock)
2115
        self.assertSetHook(remote_branch._get_config(), 'file', 'remote')
2116
2117
    def test_set_hook_remote_bzrdir(self):
2118
        remote_branch = branch.Branch.open(self.get_url('tree'))
2119
        self.addCleanup(remote_branch.lock_write().unlock)
2120
        remote_bzrdir = bzrdir.BzrDir.open(self.get_url('tree'))
2121
        self.assertSetHook(remote_bzrdir._get_config(), 'file', 'remotedir')
2122
5743.8.21 by Vincent Ladeuil
Add test for config load hook for remote configs.
2123
    def assertLoadHook(self, expected_nb_calls, name, conf_class, *conf_args):
2124
        calls = []
2125
        def hook(*args):
2126
            calls.append(args)
5743.8.24 by Vincent Ladeuil
Clearly seaparate both sets of hooks for the old and new config implementations.
2127
        config.OldConfigHooks.install_named_hook('load', hook, None)
5743.8.21 by Vincent Ladeuil
Add test for config load hook for remote configs.
2128
        self.addCleanup(
5743.8.24 by Vincent Ladeuil
Clearly seaparate both sets of hooks for the old and new config implementations.
2129
            config.OldConfigHooks.uninstall_named_hook, 'load', None)
5743.8.21 by Vincent Ladeuil
Add test for config load hook for remote configs.
2130
        self.assertLength(0, calls)
2131
        # Build a config
2132
        conf = conf_class(*conf_args)
2133
        # Access an option to trigger a load
2134
        conf.get_option(name)
2135
        self.assertLength(expected_nb_calls, calls)
2136
        # Since we can't assert about conf, we just use the number of calls ;-/
2137
2138
    def test_load_hook_remote_branch(self):
2139
        remote_branch = branch.Branch.open(self.get_url('tree'))
2140
        self.assertLoadHook(1, 'file', remote.RemoteBranchConfig, remote_branch)
2141
2142
    def test_load_hook_remote_bzrdir(self):
2143
        remote_bzrdir = bzrdir.BzrDir.open(self.get_url('tree'))
2144
        # The config file doesn't exist, set an option to force its creation
2145
        conf = remote_bzrdir._get_config()
2146
        conf.set_option('remotedir', 'file')
2147
        # We get one call for the server and one call for the client, this is
2148
        # caused by the differences in implementations betwen
2149
        # SmartServerBzrDirRequestConfigFile (in smart/bzrdir.py) and
2150
        # SmartServerBranchGetConfigFile (in smart/branch.py)
2151
        self.assertLoadHook(2 ,'file', remote.RemoteBzrDirConfig, remote_bzrdir)
2152
5743.8.22 by Vincent Ladeuil
Add tests for config save hook for remote configs.
2153
    def assertSaveHook(self, conf):
2154
        calls = []
2155
        def hook(*args):
2156
            calls.append(args)
5743.8.24 by Vincent Ladeuil
Clearly seaparate both sets of hooks for the old and new config implementations.
2157
        config.OldConfigHooks.install_named_hook('save', hook, None)
5743.8.22 by Vincent Ladeuil
Add tests for config save hook for remote configs.
2158
        self.addCleanup(
5743.8.24 by Vincent Ladeuil
Clearly seaparate both sets of hooks for the old and new config implementations.
2159
            config.OldConfigHooks.uninstall_named_hook, 'save', None)
5743.8.22 by Vincent Ladeuil
Add tests for config save hook for remote configs.
2160
        self.assertLength(0, calls)
2161
        # Setting an option triggers a save
2162
        conf.set_option('foo', 'bar')
2163
        self.assertLength(1, calls)
2164
        # Since we can't assert about conf, we just use the number of calls ;-/
2165
2166
    def test_save_hook_remote_branch(self):
2167
        remote_branch = branch.Branch.open(self.get_url('tree'))
2168
        self.addCleanup(remote_branch.lock_write().unlock)
2169
        self.assertSaveHook(remote_branch._get_config())
2170
2171
    def test_save_hook_remote_bzrdir(self):
2172
        remote_branch = branch.Branch.open(self.get_url('tree'))
2173
        self.addCleanup(remote_branch.lock_write().unlock)
2174
        remote_bzrdir = bzrdir.BzrDir.open(self.get_url('tree'))
2175
        self.assertSaveHook(remote_bzrdir._get_config())
2176
5743.8.17 by Vincent Ladeuil
Add config old_get hook for remote config.
2177
5743.12.4 by Vincent Ladeuil
An option can provide a default value.
2178
class TestOption(tests.TestCase):
2179
2180
    def test_default_value(self):
2181
        opt = config.Option('foo', default='bar')
2182
        self.assertEquals('bar', opt.get_default())
5743.12.5 by Vincent Ladeuil
Remove spurious spaces.
2183
5743.12.4 by Vincent Ladeuil
An option can provide a default value.
2184
5743.12.2 by Vincent Ladeuil
Basic registry for options.
2185
class TestOptionRegistry(tests.TestCase):
5743.12.5 by Vincent Ladeuil
Remove spurious spaces.
2186
5743.12.2 by Vincent Ladeuil
Basic registry for options.
2187
    def setUp(self):
2188
        super(TestOptionRegistry, self).setUp()
2189
        # Always start with an empty registry
2190
        self.overrideAttr(config, 'option_registry', registry.Registry())
2191
        self.registry = config.option_registry
2192
2193
    def test_register(self):
2194
        opt = config.Option('foo')
2195
        self.registry.register('foo', opt)
2196
        self.assertIs(opt, self.registry.get('foo'))
2197
2198
    lazy_option = config.Option('lazy_foo')
2199
2200
    def test_register_lazy(self):
2201
        self.registry.register_lazy('foo', self.__module__,
2202
                                    'TestOptionRegistry.lazy_option')
2203
        self.assertIs(self.lazy_option, self.registry.get('foo'))
2204
5743.12.3 by Vincent Ladeuil
More basic tests for options. Start tests for all registered options.
2205
    def test_registered_help(self):
2206
        opt = config.Option('foo')
2207
        self.registry.register('foo', opt, help='A simple option')
2208
        self.assertEquals('A simple option', self.registry.get_help('foo'))
2209
2210
2211
class TestRegisteredOptions(tests.TestCase):
2212
    """All registered options should verify some constraints."""
2213
2214
    scenarios = [(key, {'option_name': key, 'option': option}) for key, option
2215
                 in config.option_registry.iteritems()]
2216
2217
    def setUp(self):
2218
        super(TestRegisteredOptions, self).setUp()
2219
        self.registry = config.option_registry
2220
2221
    def test_proper_name(self):
2222
        # An option should be registered under its own name, this can't be
2223
        # checked at registration time for the lazy ones.
2224
        self.assertEquals(self.option_name, self.option.name)
2225
2226
    def test_help_is_set(self):
2227
        option_help = self.registry.get_help(self.option_name)
2228
        self.assertNotEquals(None, option_help)
2229
        # Come on, think about the user, he really wants to know whst the
2230
        # option is about
2231
        self.assertNotEquals('', option_help)
2232
5743.12.2 by Vincent Ladeuil
Basic registry for options.
2233
5743.3.12 by Vincent Ladeuil
Add an ad-hoc __repr__.
2234
class TestSection(tests.TestCase):
5743.2.1 by Vincent Ladeuil
Basic tests and implementations for read-only and mutable sections.
2235
2236
    # FIXME: Parametrize so that all sections produced by Stores run these
5743.3.1 by Vincent Ladeuil
Add a docstring and dates to FIXMEs.
2237
    # tests -- vila 2011-04-01
5743.2.1 by Vincent Ladeuil
Basic tests and implementations for read-only and mutable sections.
2238
2239
    def test_get_a_value(self):
2240
        a_dict = dict(foo='bar')
5743.3.11 by Vincent Ladeuil
Config sections only implement read access.
2241
        section = config.Section('myID', a_dict)
5743.2.1 by Vincent Ladeuil
Basic tests and implementations for read-only and mutable sections.
2242
        self.assertEquals('bar', section.get('foo'))
2243
5743.3.10 by Vincent Ladeuil
Fix typos mentioned in reviews.
2244
    def test_get_unknown_option(self):
5743.2.2 by Vincent Ladeuil
Add tests for remove.
2245
        a_dict = dict()
5743.5.13 by Vincent Ladeuil
Merge config-abstract-store into config-concrete-stores resolving conflicts
2246
        section = config.Section(None, a_dict)
5743.2.2 by Vincent Ladeuil
Add tests for remove.
2247
        self.assertEquals('out of thin air',
2248
                          section.get('foo', 'out of thin air'))
2249
5743.2.1 by Vincent Ladeuil
Basic tests and implementations for read-only and mutable sections.
2250
    def test_options_is_shared(self):
2251
        a_dict = dict()
5743.5.13 by Vincent Ladeuil
Merge config-abstract-store into config-concrete-stores resolving conflicts
2252
        section = config.Section(None, a_dict)
5743.2.1 by Vincent Ladeuil
Basic tests and implementations for read-only and mutable sections.
2253
        self.assertIs(a_dict, section.options)
2254
2255
5743.3.12 by Vincent Ladeuil
Add an ad-hoc __repr__.
2256
class TestMutableSection(tests.TestCase):
5743.2.1 by Vincent Ladeuil
Basic tests and implementations for read-only and mutable sections.
2257
5743.4.20 by Vincent Ladeuil
Fix typo.
2258
    # FIXME: Parametrize so that all sections (including os.environ and the
5743.3.1 by Vincent Ladeuil
Add a docstring and dates to FIXMEs.
2259
    # ones produced by Stores) run these tests -- vila 2011-04-01
5743.2.1 by Vincent Ladeuil
Basic tests and implementations for read-only and mutable sections.
2260
2261
    def test_set(self):
2262
        a_dict = dict(foo='bar')
2263
        section = config.MutableSection('myID', a_dict)
2264
        section.set('foo', 'new_value')
2265
        self.assertEquals('new_value', section.get('foo'))
2266
        # The change appears in the shared section
2267
        self.assertEquals('new_value', a_dict.get('foo'))
2268
        # We keep track of the change
2269
        self.assertTrue('foo' in section.orig)
2270
        self.assertEquals('bar', section.orig.get('foo'))
2271
2272
    def test_set_preserve_original_once(self):
2273
        a_dict = dict(foo='bar')
2274
        section = config.MutableSection('myID', a_dict)
2275
        section.set('foo', 'first_value')
2276
        section.set('foo', 'second_value')
2277
        # We keep track of the original value
2278
        self.assertTrue('foo' in section.orig)
2279
        self.assertEquals('bar', section.orig.get('foo'))
2280
5743.2.2 by Vincent Ladeuil
Add tests for remove.
2281
    def test_remove(self):
2282
        a_dict = dict(foo='bar')
2283
        section = config.MutableSection('myID', a_dict)
2284
        section.remove('foo')
2285
        # We get None for unknown options via the default value
2286
        self.assertEquals(None, section.get('foo'))
2287
        # Or we just get the default value
2288
        self.assertEquals('unknown', section.get('foo', 'unknown'))
2289
        self.assertFalse('foo' in section.options)
2290
        # We keep track of the deletion
2291
        self.assertTrue('foo' in section.orig)
2292
        self.assertEquals('bar', section.orig.get('foo'))
2293
2294
    def test_remove_new_option(self):
2295
        a_dict = dict()
2296
        section = config.MutableSection('myID', a_dict)
2297
        section.set('foo', 'bar')
2298
        section.remove('foo')
2299
        self.assertFalse('foo' in section.options)
2300
        # The option didn't exist initially so it we need to keep track of it
2301
        # with a special value
2302
        self.assertTrue('foo' in section.orig)
5743.3.6 by Vincent Ladeuil
Use a name less likely to be reused.
2303
        self.assertEquals(config._NewlyCreatedOption, section.orig['foo'])
5743.2.2 by Vincent Ladeuil
Add tests for remove.
2304
5743.2.1 by Vincent Ladeuil
Basic tests and implementations for read-only and mutable sections.
2305
5743.4.6 by Vincent Ladeuil
Parametrize Store tests and isolate the ConfigObjStore specific ones.
2306
class TestStore(tests.TestCaseWithTransport):
2307
2308
    def assertSectionContent(self, expected, section):
2309
        """Assert that some options have the proper values in a section."""
2310
        expected_name, expected_options = expected
2311
        self.assertEquals(expected_name, section.id)
2312
        self.assertEquals(
2313
            expected_options,
2314
            dict([(k, section.get(k)) for k in expected_options.keys()]))
2315
2316
2317
class TestReadonlyStore(TestStore):
2318
5743.6.27 by Vincent Ladeuil
Move the test registries to bzrlib.config so plugins will be able to use
2319
    scenarios = [(key, {'get_store': builder}) for key, builder
2320
                 in config.test_store_builder_registry.iteritems()]
5743.5.10 by Vincent Ladeuil
Parametrize the generic tests against the concrete stores.
2321
2322
    def setUp(self):
2323
        super(TestReadonlyStore, self).setUp()
2324
2325
    def test_building_delays_load(self):
2326
        store = self.get_store(self)
5743.4.25 by Vincent Ladeuil
Address review comments by jelmer and poolie.
2327
        self.assertEquals(False, store.is_loaded())
5743.5.10 by Vincent Ladeuil
Parametrize the generic tests against the concrete stores.
2328
        store._load_from_string('')
5743.4.25 by Vincent Ladeuil
Address review comments by jelmer and poolie.
2329
        self.assertEquals(True, store.is_loaded())
5743.2.7 by Vincent Ladeuil
Implement loading a config store from a string or a file.
2330
5743.4.6 by Vincent Ladeuil
Parametrize Store tests and isolate the ConfigObjStore specific ones.
2331
    def test_get_no_sections_for_empty(self):
5743.5.10 by Vincent Ladeuil
Parametrize the generic tests against the concrete stores.
2332
        store = self.get_store(self)
2333
        store._load_from_string('')
5743.4.6 by Vincent Ladeuil
Parametrize Store tests and isolate the ConfigObjStore specific ones.
2334
        self.assertEquals([], list(store.get_sections()))
2335
2336
    def test_get_default_section(self):
5743.5.10 by Vincent Ladeuil
Parametrize the generic tests against the concrete stores.
2337
        store = self.get_store(self)
2338
        store._load_from_string('foo=bar')
5743.4.6 by Vincent Ladeuil
Parametrize Store tests and isolate the ConfigObjStore specific ones.
2339
        sections = list(store.get_sections())
2340
        self.assertLength(1, sections)
2341
        self.assertSectionContent((None, {'foo': 'bar'}), sections[0])
2342
2343
    def test_get_named_section(self):
5743.5.10 by Vincent Ladeuil
Parametrize the generic tests against the concrete stores.
2344
        store = self.get_store(self)
2345
        store._load_from_string('[baz]\nfoo=bar')
5743.4.6 by Vincent Ladeuil
Parametrize Store tests and isolate the ConfigObjStore specific ones.
2346
        sections = list(store.get_sections())
2347
        self.assertLength(1, sections)
2348
        self.assertSectionContent(('baz', {'foo': 'bar'}), sections[0])
2349
5743.4.21 by Vincent Ladeuil
All stores should provide _load_from_string to reuse the existing tests.
2350
    def test_load_from_string_fails_for_non_empty_store(self):
5743.5.10 by Vincent Ladeuil
Parametrize the generic tests against the concrete stores.
2351
        store = self.get_store(self)
2352
        store._load_from_string('foo=bar')
5743.4.21 by Vincent Ladeuil
All stores should provide _load_from_string to reuse the existing tests.
2353
        self.assertRaises(AssertionError, store._load_from_string, 'bar=baz')
2354
5743.4.6 by Vincent Ladeuil
Parametrize Store tests and isolate the ConfigObjStore specific ones.
2355
5987.1.2 by Vincent Ladeuil
Reproduce bug #502060, bug #688677 and bug #792246.
2356
class TestIniFileStoreContent(tests.TestCaseWithTransport):
2357
    """Simulate loading a config store without content of various encodings.
2358
2359
    All files produced by bzr are in utf8 content.
2360
2361
    Users may modify them manually and end up with a file that can't be
2362
    loaded. We need to issue proper error messages in this case.
2363
    """
2364
2365
    invalid_utf8_char = '\xff'
2366
2367
    def test_load_utf8(self):
2368
        """Ensure we can load an utf8-encoded file."""
5987.1.1 by Vincent Ladeuil
Properly load utf8-encoded config files
2369
        t = self.get_transport()
2370
        # From http://pad.lv/799212
5987.1.2 by Vincent Ladeuil
Reproduce bug #502060, bug #688677 and bug #792246.
2371
        unicode_user = u'b\N{Euro Sign}ar'
5987.1.1 by Vincent Ladeuil
Properly load utf8-encoded config files
2372
        unicode_content = u'user=%s' % (unicode_user,)
2373
        utf8_content = unicode_content.encode('utf8')
2374
        # Store the raw content in the config file
2375
        t.put_bytes('foo.conf', utf8_content)
2376
        store = config.IniFileStore(t, 'foo.conf')
2377
        store.load()
2378
        stack = config.Stack([store.get_sections], store)
2379
        self.assertEquals(unicode_user, stack.get('user'))
2380
5987.1.2 by Vincent Ladeuil
Reproduce bug #502060, bug #688677 and bug #792246.
2381
    def test_load_non_ascii(self):
2382
        """Ensure we display a proper error on non-ascii, non utf-8 content."""
2383
        t = self.get_transport()
2384
        t.put_bytes('foo.conf', 'user=foo\n#%s\n' % (self.invalid_utf8_char,))
2385
        store = config.IniFileStore(t, 'foo.conf')
5987.1.4 by Vincent Ladeuil
Proper error messages for config files with content in non-utf encoding or that cannot be parsed
2386
        self.assertRaises(errors.ConfigContentError, store.load)
5987.1.2 by Vincent Ladeuil
Reproduce bug #502060, bug #688677 and bug #792246.
2387
2388
    def test_load_erroneous_content(self):
2389
        """Ensure we display a proper error on content that can't be parsed."""
2390
        t = self.get_transport()
2391
        t.put_bytes('foo.conf', '[open_section\n')
2392
        store = config.IniFileStore(t, 'foo.conf')
2393
        self.assertRaises(errors.ParseConfigError, store.load)
2394
2395
2396
class TestIniConfigContent(tests.TestCaseWithTransport):
2397
    """Simulate loading a IniBasedConfig without content of various encodings.
2398
2399
    All files produced by bzr are in utf8 content.
2400
2401
    Users may modify them manually and end up with a file that can't be
2402
    loaded. We need to issue proper error messages in this case.
2403
    """
2404
2405
    invalid_utf8_char = '\xff'
2406
2407
    def test_load_utf8(self):
2408
        """Ensure we can load an utf8-encoded file."""
2409
        # From http://pad.lv/799212
2410
        unicode_user = u'b\N{Euro Sign}ar'
2411
        unicode_content = u'user=%s' % (unicode_user,)
2412
        utf8_content = unicode_content.encode('utf8')
2413
        # Store the raw content in the config file
2414
        with open('foo.conf', 'wb') as f:
2415
            f.write(utf8_content)
2416
        conf = config.IniBasedConfig(file_name='foo.conf')
2417
        self.assertEquals(unicode_user, conf.get_user_option('user'))
2418
2419
    def test_load_badly_encoded_content(self):
2420
        """Ensure we display a proper error on non-ascii, non utf-8 content."""
2421
        with open('foo.conf', 'wb') as f:
2422
            f.write('user=foo\n#%s\n' % (self.invalid_utf8_char,))
2423
        conf = config.IniBasedConfig(file_name='foo.conf')
5987.1.4 by Vincent Ladeuil
Proper error messages for config files with content in non-utf encoding or that cannot be parsed
2424
        self.assertRaises(errors.ConfigContentError, conf._get_parser)
5987.1.2 by Vincent Ladeuil
Reproduce bug #502060, bug #688677 and bug #792246.
2425
2426
    def test_load_erroneous_content(self):
2427
        """Ensure we display a proper error on content that can't be parsed."""
2428
        with open('foo.conf', 'wb') as f:
2429
            f.write('[open_section\n')
2430
        conf = config.IniBasedConfig(file_name='foo.conf')
2431
        self.assertRaises(errors.ParseConfigError, conf._get_parser)
2432
5987.1.1 by Vincent Ladeuil
Properly load utf8-encoded config files
2433
5743.4.6 by Vincent Ladeuil
Parametrize Store tests and isolate the ConfigObjStore specific ones.
2434
class TestMutableStore(TestStore):
2435
5743.6.27 by Vincent Ladeuil
Move the test registries to bzrlib.config so plugins will be able to use
2436
    scenarios = [(key, {'store_id': key, 'get_store': builder}) for key, builder
2437
                 in config.test_store_builder_registry.iteritems()]
5743.5.10 by Vincent Ladeuil
Parametrize the generic tests against the concrete stores.
2438
2439
    def setUp(self):
2440
        super(TestMutableStore, self).setUp()
2441
        self.transport = self.get_transport()
2442
2443
    def has_store(self, store):
2444
        store_basename = urlutils.relative_url(self.transport.external_url(),
2445
                                               store.external_url())
2446
        return self.transport.has(store_basename)
5743.4.6 by Vincent Ladeuil
Parametrize Store tests and isolate the ConfigObjStore specific ones.
2447
5743.4.19 by Vincent Ladeuil
Clarify that only Store.get_mutable_section() can accept an empty file.
2448
    def test_save_empty_creates_no_file(self):
5743.10.4 by Vincent Ladeuil
Add FIXME.
2449
        # FIXME: There should be a better way than relying on the test
2450
        # parametrization to identify branch.conf -- vila 2011-0526
5743.10.2 by Vincent Ladeuil
Make sure RemoteBranch are supported as well, relying on the vfs API.
2451
        if self.store_id in ('branch', 'remote_branch'):
5743.5.10 by Vincent Ladeuil
Parametrize the generic tests against the concrete stores.
2452
            raise tests.TestNotApplicable(
2453
                'branch.conf is *always* created when a branch is initialized')
2454
        store = self.get_store(self)
5743.4.19 by Vincent Ladeuil
Clarify that only Store.get_mutable_section() can accept an empty file.
2455
        store.save()
5743.5.10 by Vincent Ladeuil
Parametrize the generic tests against the concrete stores.
2456
        self.assertEquals(False, self.has_store(store))
5743.4.19 by Vincent Ladeuil
Clarify that only Store.get_mutable_section() can accept an empty file.
2457
2458
    def test_save_emptied_succeeds(self):
5743.5.10 by Vincent Ladeuil
Parametrize the generic tests against the concrete stores.
2459
        store = self.get_store(self)
2460
        store._load_from_string('foo=bar\n')
5743.4.19 by Vincent Ladeuil
Clarify that only Store.get_mutable_section() can accept an empty file.
2461
        section = store.get_mutable_section(None)
2462
        section.remove('foo')
5743.4.6 by Vincent Ladeuil
Parametrize Store tests and isolate the ConfigObjStore specific ones.
2463
        store.save()
5743.5.10 by Vincent Ladeuil
Parametrize the generic tests against the concrete stores.
2464
        self.assertEquals(True, self.has_store(store))
2465
        modified_store = self.get_store(self)
5743.4.19 by Vincent Ladeuil
Clarify that only Store.get_mutable_section() can accept an empty file.
2466
        sections = list(modified_store.get_sections())
2467
        self.assertLength(0, sections)
5743.4.6 by Vincent Ladeuil
Parametrize Store tests and isolate the ConfigObjStore specific ones.
2468
2469
    def test_save_with_content_succeeds(self):
5743.10.4 by Vincent Ladeuil
Add FIXME.
2470
        # FIXME: There should be a better way than relying on the test
2471
        # parametrization to identify branch.conf -- vila 2011-0526
5743.10.2 by Vincent Ladeuil
Make sure RemoteBranch are supported as well, relying on the vfs API.
2472
        if self.store_id in ('branch', 'remote_branch'):
5743.5.10 by Vincent Ladeuil
Parametrize the generic tests against the concrete stores.
2473
            raise tests.TestNotApplicable(
2474
                'branch.conf is *always* created when a branch is initialized')
2475
        store = self.get_store(self)
2476
        store._load_from_string('foo=bar\n')
2477
        self.assertEquals(False, self.has_store(store))
5743.4.6 by Vincent Ladeuil
Parametrize Store tests and isolate the ConfigObjStore specific ones.
2478
        store.save()
5743.5.10 by Vincent Ladeuil
Parametrize the generic tests against the concrete stores.
2479
        self.assertEquals(True, self.has_store(store))
2480
        modified_store = self.get_store(self)
5743.4.6 by Vincent Ladeuil
Parametrize Store tests and isolate the ConfigObjStore specific ones.
2481
        sections = list(modified_store.get_sections())
2482
        self.assertLength(1, sections)
2483
        self.assertSectionContent((None, {'foo': 'bar'}), sections[0])
2484
2485
    def test_set_option_in_empty_store(self):
5743.5.10 by Vincent Ladeuil
Parametrize the generic tests against the concrete stores.
2486
        store = self.get_store(self)
5743.4.6 by Vincent Ladeuil
Parametrize Store tests and isolate the ConfigObjStore specific ones.
2487
        section = store.get_mutable_section(None)
2488
        section.set('foo', 'bar')
2489
        store.save()
5743.5.10 by Vincent Ladeuil
Parametrize the generic tests against the concrete stores.
2490
        modified_store = self.get_store(self)
5743.4.6 by Vincent Ladeuil
Parametrize Store tests and isolate the ConfigObjStore specific ones.
2491
        sections = list(modified_store.get_sections())
2492
        self.assertLength(1, sections)
2493
        self.assertSectionContent((None, {'foo': 'bar'}), sections[0])
2494
2495
    def test_set_option_in_default_section(self):
5743.5.10 by Vincent Ladeuil
Parametrize the generic tests against the concrete stores.
2496
        store = self.get_store(self)
2497
        store._load_from_string('')
5743.4.6 by Vincent Ladeuil
Parametrize Store tests and isolate the ConfigObjStore specific ones.
2498
        section = store.get_mutable_section(None)
2499
        section.set('foo', 'bar')
2500
        store.save()
5743.5.10 by Vincent Ladeuil
Parametrize the generic tests against the concrete stores.
2501
        modified_store = self.get_store(self)
5743.4.6 by Vincent Ladeuil
Parametrize Store tests and isolate the ConfigObjStore specific ones.
2502
        sections = list(modified_store.get_sections())
2503
        self.assertLength(1, sections)
2504
        self.assertSectionContent((None, {'foo': 'bar'}), sections[0])
2505
2506
    def test_set_option_in_named_section(self):
5743.5.10 by Vincent Ladeuil
Parametrize the generic tests against the concrete stores.
2507
        store = self.get_store(self)
2508
        store._load_from_string('')
5743.4.6 by Vincent Ladeuil
Parametrize Store tests and isolate the ConfigObjStore specific ones.
2509
        section = store.get_mutable_section('baz')
2510
        section.set('foo', 'bar')
2511
        store.save()
5743.5.10 by Vincent Ladeuil
Parametrize the generic tests against the concrete stores.
2512
        modified_store = self.get_store(self)
5743.4.6 by Vincent Ladeuil
Parametrize Store tests and isolate the ConfigObjStore specific ones.
2513
        sections = list(modified_store.get_sections())
2514
        self.assertLength(1, sections)
2515
        self.assertSectionContent(('baz', {'foo': 'bar'}), sections[0])
2516
5743.8.8 by Vincent Ladeuil
Puth the load hook in the right place.
2517
    def test_load_hook(self):
2518
        # We first needs to ensure that the store exists
2519
        store = self.get_store(self)
2520
        section = store.get_mutable_section('baz')
2521
        section.set('foo', 'bar')
2522
        store.save()
2523
        # Now we can try to load it
5743.8.11 by Vincent Ladeuil
Restrict the scope when testing hooks to avoid spurious failures.
2524
        store = self.get_store(self)
5743.8.8 by Vincent Ladeuil
Puth the load hook in the right place.
2525
        calls = []
2526
        def hook(*args):
2527
            calls.append(args)
5743.8.10 by Vincent Ladeuil
We don't need (nor want) to tie the config hooks to a particular class. Especially when we want to use the same hooks on both implementations.
2528
        config.ConfigHooks.install_named_hook('load', hook, None)
5743.8.8 by Vincent Ladeuil
Puth the load hook in the right place.
2529
        self.assertLength(0, calls)
2530
        store.load()
2531
        self.assertLength(1, calls)
2532
        self.assertEquals((store,), calls[0])
2533
5743.8.7 by Vincent Ladeuil
Add hooks for config stores (but the load one is not in the right place).
2534
    def test_save_hook(self):
2535
        calls = []
2536
        def hook(*args):
2537
            calls.append(args)
5743.8.10 by Vincent Ladeuil
We don't need (nor want) to tie the config hooks to a particular class. Especially when we want to use the same hooks on both implementations.
2538
        config.ConfigHooks.install_named_hook('save', hook, None)
5743.8.7 by Vincent Ladeuil
Add hooks for config stores (but the load one is not in the right place).
2539
        self.assertLength(0, calls)
2540
        store = self.get_store(self)
2541
        section = store.get_mutable_section('baz')
2542
        section.set('foo', 'bar')
2543
        store.save()
2544
        self.assertLength(1, calls)
2545
        self.assertEquals((store,), calls[0])
2546
5743.4.6 by Vincent Ladeuil
Parametrize Store tests and isolate the ConfigObjStore specific ones.
2547
5743.4.25 by Vincent Ladeuil
Address review comments by jelmer and poolie.
2548
class TestIniFileStore(TestStore):
5743.4.6 by Vincent Ladeuil
Parametrize Store tests and isolate the ConfigObjStore specific ones.
2549
5743.4.3 by Vincent Ladeuil
Implement get_mutable_section.
2550
    def test_loading_unknown_file_fails(self):
5743.4.25 by Vincent Ladeuil
Address review comments by jelmer and poolie.
2551
        store = config.IniFileStore(self.get_transport(), 'I-do-not-exist')
5743.4.3 by Vincent Ladeuil
Implement get_mutable_section.
2552
        self.assertRaises(errors.NoSuchFile, store.load)
2553
5743.2.7 by Vincent Ladeuil
Implement loading a config store from a string or a file.
2554
    def test_invalid_content(self):
5743.4.25 by Vincent Ladeuil
Address review comments by jelmer and poolie.
2555
        store = config.IniFileStore(self.get_transport(), 'foo.conf', )
2556
        self.assertEquals(False, store.is_loaded())
5743.4.18 by Vincent Ladeuil
Replace class.from_string with self._load_from_string to all stores can use it.
2557
        exc = self.assertRaises(
2558
            errors.ParseConfigError, store._load_from_string,
2559
            'this is invalid !')
5743.2.7 by Vincent Ladeuil
Implement loading a config store from a string or a file.
2560
        self.assertEndsWith(exc.filename, 'foo.conf')
2561
        # And the load failed
5743.4.25 by Vincent Ladeuil
Address review comments by jelmer and poolie.
2562
        self.assertEquals(False, store.is_loaded())
5743.2.7 by Vincent Ladeuil
Implement loading a config store from a string or a file.
2563
5743.2.10 by Vincent Ladeuil
Implement store.get_sections() as an iterator and provides the configobj implementation.
2564
    def test_get_embedded_sections(self):
5743.2.11 by Vincent Ladeuil
Basic store.set implementation.
2565
        # A more complicated example (which also shows that section names and
2566
        # option names share the same name space...)
5743.4.7 by Vincent Ladeuil
The test is now specific to ConfigObjStore and highlight a pending problem there.
2567
        # FIXME: This should be fixed by forbidding dicts as values ?
2568
        # -- vila 2011-04-05
5743.4.25 by Vincent Ladeuil
Address review comments by jelmer and poolie.
2569
        store = config.IniFileStore(self.get_transport(), 'foo.conf', )
5743.4.18 by Vincent Ladeuil
Replace class.from_string with self._load_from_string to all stores can use it.
2570
        store._load_from_string('''
5743.2.10 by Vincent Ladeuil
Implement store.get_sections() as an iterator and provides the configobj implementation.
2571
foo=bar
2572
l=1,2
2573
[DEFAULT]
2574
foo_in_DEFAULT=foo_DEFAULT
2575
[bar]
2576
foo_in_bar=barbar
2577
[baz]
2578
foo_in_baz=barbaz
2579
[[qux]]
2580
foo_in_qux=quux
5743.4.18 by Vincent Ladeuil
Replace class.from_string with self._load_from_string to all stores can use it.
2581
''')
5743.2.10 by Vincent Ladeuil
Implement store.get_sections() as an iterator and provides the configobj implementation.
2582
        sections = list(store.get_sections())
2583
        self.assertLength(4, sections)
2584
        # The default section has no name.
2585
        # List values are provided as lists
5743.4.1 by Vincent Ladeuil
Use proper ReadOnly sections in ConfigObjStore.get_sections().
2586
        self.assertSectionContent((None, {'foo': 'bar', 'l': ['1', '2']}),
2587
                                  sections[0])
2588
        self.assertSectionContent(
2589
            ('DEFAULT', {'foo_in_DEFAULT': 'foo_DEFAULT'}), sections[1])
2590
        self.assertSectionContent(
2591
            ('bar', {'foo_in_bar': 'barbar'}), sections[2])
5743.2.10 by Vincent Ladeuil
Implement store.get_sections() as an iterator and provides the configobj implementation.
2592
        # sub sections are provided as embedded dicts.
5743.4.1 by Vincent Ladeuil
Use proper ReadOnly sections in ConfigObjStore.get_sections().
2593
        self.assertSectionContent(
2594
            ('baz', {'foo_in_baz': 'barbaz', 'qux': {'foo_in_qux': 'quux'}}),
2595
            sections[3])
5743.2.10 by Vincent Ladeuil
Implement store.get_sections() as an iterator and provides the configobj implementation.
2596
5743.4.5 by Vincent Ladeuil
Split store tests between readonly and mutable ones.
2597
5743.4.25 by Vincent Ladeuil
Address review comments by jelmer and poolie.
2598
class TestLockableIniFileStore(TestStore):
5743.4.9 by Vincent Ladeuil
Implement a LockableConfigObjStore to be able to mimick the actual behaviour.
2599
2600
    def test_create_store_in_created_dir(self):
5743.6.21 by Vincent Ladeuil
Tighten the test.
2601
        self.assertPathDoesNotExist('dir')
5743.4.9 by Vincent Ladeuil
Implement a LockableConfigObjStore to be able to mimick the actual behaviour.
2602
        t = self.get_transport('dir/subdir')
5743.4.25 by Vincent Ladeuil
Address review comments by jelmer and poolie.
2603
        store = config.LockableIniFileStore(t, 'foo.conf')
5743.4.9 by Vincent Ladeuil
Implement a LockableConfigObjStore to be able to mimick the actual behaviour.
2604
        store.get_mutable_section(None).set('foo', 'bar')
2605
        store.save()
5743.6.21 by Vincent Ladeuil
Tighten the test.
2606
        self.assertPathExists('dir/subdir')
5743.4.9 by Vincent Ladeuil
Implement a LockableConfigObjStore to be able to mimick the actual behaviour.
2607
5743.6.23 by Vincent Ladeuil
More config concurrent updates tests.
2608
5743.6.22 by Vincent Ladeuil
Start writing tests for lockable stores.
2609
class TestConcurrentStoreUpdates(TestStore):
5743.10.13 by Vincent Ladeuil
Mention that the the concurrent update tests are not targeted at *all* Store implementations.
2610
    """Test that Stores properly handle conccurent updates.
2611
2612
    New Store implementation may fail some of these tests but until such
2613
    implementations exist it's hard to properly filter them from the scenarios
2614
    applied here. If you encounter such a case, contact the bzr devs.
2615
    """
5743.6.22 by Vincent Ladeuil
Start writing tests for lockable stores.
2616
5743.6.27 by Vincent Ladeuil
Move the test registries to bzrlib.config so plugins will be able to use
2617
    scenarios = [(key, {'get_stack': builder}) for key, builder
2618
                 in config.test_stack_builder_registry.iteritems()]
5743.6.22 by Vincent Ladeuil
Start writing tests for lockable stores.
2619
2620
    def setUp(self):
2621
        super(TestConcurrentStoreUpdates, self).setUp()
2622
        self._content = 'one=1\ntwo=2\n'
5743.6.23 by Vincent Ladeuil
More config concurrent updates tests.
2623
        self.stack = self.get_stack(self)
5743.6.27 by Vincent Ladeuil
Move the test registries to bzrlib.config so plugins will be able to use
2624
        if not isinstance(self.stack, config._CompatibleStack):
2625
            raise tests.TestNotApplicable(
2626
                '%s is not meant to be compatible with the old config design'
2627
                % (self.stack,))
5743.6.23 by Vincent Ladeuil
More config concurrent updates tests.
2628
        self.stack.store._load_from_string(self._content)
2629
        # Flush the store
2630
        self.stack.store.save()
5743.6.22 by Vincent Ladeuil
Start writing tests for lockable stores.
2631
2632
    def test_simple_read_access(self):
2633
        self.assertEquals('1', self.stack.get('one'))
5743.6.27 by Vincent Ladeuil
Move the test registries to bzrlib.config so plugins will be able to use
2634
5743.6.22 by Vincent Ladeuil
Start writing tests for lockable stores.
2635
    def test_simple_write_access(self):
2636
        self.stack.set('one', 'one')
2637
        self.assertEquals('one', self.stack.get('one'))
2638
5743.6.23 by Vincent Ladeuil
More config concurrent updates tests.
2639
    def test_listen_to_the_last_speaker(self):
2640
        c1 = self.stack
2641
        c2 = self.get_stack(self)
2642
        c1.set('one', 'ONE')
2643
        c2.set('two', 'TWO')
2644
        self.assertEquals('ONE', c1.get('one'))
2645
        self.assertEquals('TWO', c2.get('two'))
2646
        # The second update respect the first one
2647
        self.assertEquals('ONE', c2.get('one'))
2648
2649
    def test_last_speaker_wins(self):
2650
        # If the same config is not shared, the same variable modified twice
2651
        # can only see a single result.
2652
        c1 = self.stack
2653
        c2 = self.get_stack(self)
2654
        c1.set('one', 'c1')
2655
        c2.set('one', 'c2')
2656
        self.assertEquals('c2', c2.get('one'))
2657
        # The first modification is still available until another refresh
2658
        # occur
2659
        self.assertEquals('c1', c1.get('one'))
2660
        c1.set('two', 'done')
2661
        self.assertEquals('c2', c1.get('one'))
2662
5743.6.24 by Vincent Ladeuil
One more test with a ugly hack to allow the test to stop in the right place.
2663
    def test_writes_are_serialized(self):
2664
        c1 = self.stack
2665
        c2 = self.get_stack(self)
2666
5743.6.25 by Vincent Ladeuil
Last test rewritten.
2667
        # We spawn a thread that will pause *during* the config saving.
5743.6.24 by Vincent Ladeuil
One more test with a ugly hack to allow the test to stop in the right place.
2668
        before_writing = threading.Event()
2669
        after_writing = threading.Event()
2670
        writing_done = threading.Event()
5743.6.32 by Vincent Ladeuil
Address poolie's review comments.
2671
        c1_save_without_locking_orig = c1.store.save_without_locking
2672
        def c1_save_without_locking():
5743.6.24 by Vincent Ladeuil
One more test with a ugly hack to allow the test to stop in the right place.
2673
            before_writing.set()
5743.6.32 by Vincent Ladeuil
Address poolie's review comments.
2674
            c1_save_without_locking_orig()
5743.6.24 by Vincent Ladeuil
One more test with a ugly hack to allow the test to stop in the right place.
2675
            # The lock is held. We wait for the main thread to decide when to
2676
            # continue
2677
            after_writing.wait()
5743.6.32 by Vincent Ladeuil
Address poolie's review comments.
2678
        c1.store.save_without_locking = c1_save_without_locking
5743.6.24 by Vincent Ladeuil
One more test with a ugly hack to allow the test to stop in the right place.
2679
        def c1_set():
2680
            c1.set('one', 'c1')
2681
            writing_done.set()
2682
        t1 = threading.Thread(target=c1_set)
2683
        # Collect the thread after the test
2684
        self.addCleanup(t1.join)
2685
        # Be ready to unblock the thread if the test goes wrong
2686
        self.addCleanup(after_writing.set)
2687
        t1.start()
2688
        before_writing.wait()
2689
        self.assertRaises(errors.LockContention,
2690
                          c2.set, 'one', 'c2')
2691
        self.assertEquals('c1', c1.get('one'))
2692
        # Let the lock be released
2693
        after_writing.set()
2694
        writing_done.wait()
2695
        c2.set('one', 'c2')
2696
        self.assertEquals('c2', c2.get('one'))
2697
5743.6.25 by Vincent Ladeuil
Last test rewritten.
2698
    def test_read_while_writing(self):
2699
       c1 = self.stack
2700
       # We spawn a thread that will pause *during* the write
2701
       ready_to_write = threading.Event()
2702
       do_writing = threading.Event()
2703
       writing_done = threading.Event()
2704
       # We override the _save implementation so we know the store is locked
5743.6.32 by Vincent Ladeuil
Address poolie's review comments.
2705
       c1_save_without_locking_orig = c1.store.save_without_locking
2706
       def c1_save_without_locking():
5743.6.25 by Vincent Ladeuil
Last test rewritten.
2707
           ready_to_write.set()
2708
           # The lock is held. We wait for the main thread to decide when to
2709
           # continue
2710
           do_writing.wait()
5743.6.32 by Vincent Ladeuil
Address poolie's review comments.
2711
           c1_save_without_locking_orig()
5743.6.25 by Vincent Ladeuil
Last test rewritten.
2712
           writing_done.set()
5743.6.32 by Vincent Ladeuil
Address poolie's review comments.
2713
       c1.store.save_without_locking = c1_save_without_locking
5743.6.25 by Vincent Ladeuil
Last test rewritten.
2714
       def c1_set():
2715
           c1.set('one', 'c1')
2716
       t1 = threading.Thread(target=c1_set)
2717
       # Collect the thread after the test
2718
       self.addCleanup(t1.join)
2719
       # Be ready to unblock the thread if the test goes wrong
2720
       self.addCleanup(do_writing.set)
2721
       t1.start()
2722
       # Ensure the thread is ready to write
2723
       ready_to_write.wait()
2724
       self.assertEquals('c1', c1.get('one'))
2725
       # If we read during the write, we get the old value
2726
       c2 = self.get_stack(self)
2727
       self.assertEquals('1', c2.get('one'))
2728
       # Let the writing occur and ensure it occurred
2729
       do_writing.set()
2730
       writing_done.wait()
2731
       # Now we get the updated value
2732
       c3 = self.get_stack(self)
2733
       self.assertEquals('c1', c3.get('one'))
2734
2735
    # FIXME: It may be worth looking into removing the lock dir when it's not
2736
    # needed anymore and look at possible fallouts for concurrent lockers. This
2737
    # will matter if/when we use config files outside of bazaar directories
2738
    # (.bazaar or .bzr) -- vila 20110-04-11
5743.4.9 by Vincent Ladeuil
Implement a LockableConfigObjStore to be able to mimick the actual behaviour.
2739
2740
5743.2.22 by Vincent Ladeuil
Some minimal SectionMatcher implementation to setup the test infrastucture.
2741
class TestSectionMatcher(TestStore):
2742
2743
    scenarios = [('location', {'matcher': config.LocationMatcher})]
2744
5743.2.33 by Vincent Ladeuil
Stop using get_ConfigObjStore.
2745
    def get_store(self, file_name):
5743.2.37 by Vincent Ladeuil
Merge config-concrete-stores into config-section-matchers resolving conflicts
2746
        return config.IniFileStore(self.get_readonly_transport(), file_name)
5743.2.22 by Vincent Ladeuil
Some minimal SectionMatcher implementation to setup the test infrastucture.
2747
2748
    def test_no_matches_for_empty_stores(self):
5743.2.33 by Vincent Ladeuil
Stop using get_ConfigObjStore.
2749
        store = self.get_store('foo.conf')
2750
        store._load_from_string('')
5743.2.24 by Vincent Ladeuil
Complete location config helpers with basic tests.
2751
        matcher = self.matcher(store, '/bar')
5743.2.22 by Vincent Ladeuil
Some minimal SectionMatcher implementation to setup the test infrastucture.
2752
        self.assertEquals([], list(matcher.get_sections()))
2753
5743.2.24 by Vincent Ladeuil
Complete location config helpers with basic tests.
2754
    def test_build_doesnt_load_store(self):
5743.2.33 by Vincent Ladeuil
Stop using get_ConfigObjStore.
2755
        store = self.get_store('foo.conf')
5743.2.24 by Vincent Ladeuil
Complete location config helpers with basic tests.
2756
        matcher = self.matcher(store, '/bar')
5743.2.37 by Vincent Ladeuil
Merge config-concrete-stores into config-section-matchers resolving conflicts
2757
        self.assertFalse(store.is_loaded())
5743.2.24 by Vincent Ladeuil
Complete location config helpers with basic tests.
2758
2759
2760
class TestLocationSection(tests.TestCase):
2761
2762
    def get_section(self, options, extra_path):
5743.2.37 by Vincent Ladeuil
Merge config-concrete-stores into config-section-matchers resolving conflicts
2763
        section = config.Section('foo', options)
5743.2.24 by Vincent Ladeuil
Complete location config helpers with basic tests.
2764
        # We don't care about the length so we use '0'
2765
        return config.LocationSection(section, 0, extra_path)
2766
2767
    def test_simple_option(self):
2768
        section = self.get_section({'foo': 'bar'}, '')
2769
        self.assertEquals('bar', section.get('foo'))
2770
2771
    def test_option_with_extra_path(self):
2772
        section = self.get_section({'foo': 'bar', 'foo:policy': 'appendpath'},
2773
                                   'baz')
2774
        self.assertEquals('bar/baz', section.get('foo'))
2775
2776
    def test_invalid_policy(self):
2777
        section = self.get_section({'foo': 'bar', 'foo:policy': 'die'},
2778
                                   'baz')
2779
        # invalid policies are ignored
2780
        self.assertEquals('bar', section.get('foo'))
2781
2782
2783
class TestLocationMatcher(TestStore):
2784
5743.2.33 by Vincent Ladeuil
Stop using get_ConfigObjStore.
2785
    def get_store(self, file_name):
5743.2.37 by Vincent Ladeuil
Merge config-concrete-stores into config-section-matchers resolving conflicts
2786
        return config.IniFileStore(self.get_readonly_transport(), file_name)
5743.2.33 by Vincent Ladeuil
Stop using get_ConfigObjStore.
2787
5743.2.24 by Vincent Ladeuil
Complete location config helpers with basic tests.
2788
    def test_more_specific_sections_first(self):
5743.2.33 by Vincent Ladeuil
Stop using get_ConfigObjStore.
2789
        store = self.get_store('foo.conf')
2790
        store._load_from_string('''
5743.2.24 by Vincent Ladeuil
Complete location config helpers with basic tests.
2791
[/foo]
2792
section=/foo
2793
[/foo/bar]
2794
section=/foo/bar
5743.2.33 by Vincent Ladeuil
Stop using get_ConfigObjStore.
2795
''')
5743.2.24 by Vincent Ladeuil
Complete location config helpers with basic tests.
2796
        self.assertEquals(['/foo', '/foo/bar'],
2797
                          [section.id for section in store.get_sections()])
2798
        matcher = config.LocationMatcher(store, '/foo/bar/baz')
2799
        sections = list(matcher.get_sections())
2800
        self.assertEquals([3, 2],
2801
                          [section.length for section in sections])
2802
        self.assertEquals(['/foo/bar', '/foo'],
2803
                          [section.id for section in sections])
2804
        self.assertEquals(['baz', 'bar/baz'],
2805
                          [section.extra_path for section in sections])
2806
5743.6.18 by Vincent Ladeuil
Add a test for appendpath support in no-name section.
2807
    def test_appendpath_in_no_name_section(self):
2808
        # It's a bit weird to allow appendpath in a no-name section, but
2809
        # someone may found a use for it
2810
        store = self.get_store('foo.conf')
2811
        store._load_from_string('''
2812
foo=bar
2813
foo:policy = appendpath
2814
''')
2815
        matcher = config.LocationMatcher(store, 'dir/subdir')
2816
        sections = list(matcher.get_sections())
2817
        self.assertLength(1, sections)
2818
        self.assertEquals('bar/dir/subdir', sections[0].get('foo'))
2819
5743.6.19 by Vincent Ladeuil
Clarify comments about section names for Location-related objects (also fix LocationMatcher and add tests).
2820
    def test_file_urls_are_normalized(self):
2821
        store = self.get_store('foo.conf')
5912.3.1 by Vincent Ladeuil
Fix spurious windows-specific test failure
2822
        if sys.platform == 'win32':
2823
            expected_url = 'file:///C:/dir/subdir'
2824
            expected_location = 'C:/dir/subdir'
2825
        else:
2826
            expected_url = 'file:///dir/subdir'
2827
            expected_location = '/dir/subdir'
2828
        matcher = config.LocationMatcher(store, expected_url)
2829
        self.assertEquals(expected_location, matcher.location)
5743.6.19 by Vincent Ladeuil
Clarify comments about section names for Location-related objects (also fix LocationMatcher and add tests).
2830
5743.1.20 by Vincent Ladeuil
Merge config-section-matchers into config-stack resolving conflicts
2831
5743.1.35 by Vincent Ladeuil
Address some review comments from jelmer and poolie.
2832
class TestStackGet(tests.TestCase):
5743.1.1 by Vincent Ladeuil
Start implementing a config stack.
2833
5743.1.35 by Vincent Ladeuil
Address some review comments from jelmer and poolie.
2834
    # FIXME: This should be parametrized for all known Stack or dedicated
5743.1.3 by Vincent Ladeuil
Don't forget to parametrized for people *providing* new stacks.
2835
    # paramerized tests created to avoid bloating -- vila 2011-03-31
2836
5743.1.1 by Vincent Ladeuil
Start implementing a config stack.
2837
    def test_single_config_get(self):
2838
        conf = dict(foo='bar')
5743.1.34 by Vincent Ladeuil
Merge config-section-matchers into config-stack resolving conflicts
2839
        conf_stack = config.Stack([conf])
5743.1.1 by Vincent Ladeuil
Start implementing a config stack.
2840
        self.assertEquals('bar', conf_stack.get('foo'))
2841
5743.12.7 by Vincent Ladeuil
Test that providing a default value doesn't break for non-registered options.
2842
    def test_get_with_registered_default_value(self):
5743.12.6 by Vincent Ladeuil
Stack.get() provides the registered option default value.
2843
        conf_stack = config.Stack([dict()])
2844
        opt = config.Option('foo', default='bar')
2845
        self.overrideAttr(config, 'option_registry', registry.Registry())
2846
        config.option_registry.register('foo', opt)
2847
        self.assertEquals('bar', conf_stack.get('foo'))
2848
5743.12.7 by Vincent Ladeuil
Test that providing a default value doesn't break for non-registered options.
2849
    def test_get_without_registered_default_value(self):
2850
        conf_stack = config.Stack([dict()])
2851
        opt = config.Option('foo')
2852
        self.overrideAttr(config, 'option_registry', registry.Registry())
2853
        config.option_registry.register('foo', opt)
2854
        self.assertEquals(None, conf_stack.get('foo'))
2855
2856
    def test_get_without_default_value_for_not_registered(self):
2857
        conf_stack = config.Stack([dict()])
2858
        opt = config.Option('foo')
2859
        self.overrideAttr(config, 'option_registry', registry.Registry())
2860
        self.assertEquals(None, conf_stack.get('foo'))
2861
5743.1.1 by Vincent Ladeuil
Start implementing a config stack.
2862
    def test_get_first_definition(self):
2863
        conf1 = dict(foo='bar')
2864
        conf2 = dict(foo='baz')
5743.1.34 by Vincent Ladeuil
Merge config-section-matchers into config-stack resolving conflicts
2865
        conf_stack = config.Stack([conf1, conf2])
5743.1.1 by Vincent Ladeuil
Start implementing a config stack.
2866
        self.assertEquals('bar', conf_stack.get('foo'))
2867
5743.1.2 by Vincent Ladeuil
Stacks can be used as read-only sections.
2868
    def test_get_embedded_definition(self):
2869
        conf1 = dict(yy='12')
5743.1.34 by Vincent Ladeuil
Merge config-section-matchers into config-stack resolving conflicts
2870
        conf2 = config.Stack([dict(xx='42'), dict(foo='baz')])
2871
        conf_stack = config.Stack([conf1, conf2])
5743.1.2 by Vincent Ladeuil
Stacks can be used as read-only sections.
2872
        self.assertEquals('baz', conf_stack.get('foo'))
2873
5743.1.16 by Vincent Ladeuil
Allows empty sections and empty section callables.
2874
    def test_get_for_empty_section_callable(self):
5743.1.34 by Vincent Ladeuil
Merge config-section-matchers into config-stack resolving conflicts
2875
        conf_stack = config.Stack([lambda : []])
5743.1.16 by Vincent Ladeuil
Allows empty sections and empty section callables.
2876
        self.assertEquals(None, conf_stack.get('foo'))
2877
5743.1.35 by Vincent Ladeuil
Address some review comments from jelmer and poolie.
2878
    def test_get_for_broken_callable(self):
2879
        # Trying to use and invalid callable raises an exception on first use
2880
        conf_stack = config.Stack([lambda : object()])
2881
        self.assertRaises(TypeError, conf_stack.get, 'foo')
2882
2883
5743.6.14 by Vincent Ladeuil
Parametrize the Stack tests.
2884
class TestStackWithTransport(tests.TestCaseWithTransport):
2885
5743.6.27 by Vincent Ladeuil
Move the test registries to bzrlib.config so plugins will be able to use
2886
    scenarios = [(key, {'get_stack': builder}) for key, builder
2887
                 in config.test_stack_builder_registry.iteritems()]
5743.6.14 by Vincent Ladeuil
Parametrize the Stack tests.
2888
2889
5743.11.1 by Vincent Ladeuil
Add a note about config store builders being called several times by some tests.
2890
class TestConcreteStacks(TestStackWithTransport):
2891
2892
    def test_build_stack(self):
2893
        # Just a smoke test to help debug builders
2894
        stack = self.get_stack(self)
2895
2896
5743.8.6 by Vincent Ladeuil
Add hooks for config stacks.
2897
class TestStackGet(TestStackWithTransport):
2898
2899
    def test_get_for_empty_stack(self):
2900
        conf = self.get_stack(self)
2901
        self.assertEquals(None, conf.get('foo'))
2902
2903
    def test_get_hook(self):
5743.8.11 by Vincent Ladeuil
Restrict the scope when testing hooks to avoid spurious failures.
2904
        conf = self.get_stack(self)
2905
        conf.store._load_from_string('foo=bar')
5743.8.6 by Vincent Ladeuil
Add hooks for config stacks.
2906
        calls = []
2907
        def hook(*args):
2908
            calls.append(args)
5743.8.10 by Vincent Ladeuil
We don't need (nor want) to tie the config hooks to a particular class. Especially when we want to use the same hooks on both implementations.
2909
        config.ConfigHooks.install_named_hook('get', hook, None)
5743.8.6 by Vincent Ladeuil
Add hooks for config stacks.
2910
        self.assertLength(0, calls)
2911
        value = conf.get('foo')
2912
        self.assertEquals('bar', value)
2913
        self.assertLength(1, calls)
2914
        self.assertEquals((conf, 'foo', 'bar'), calls[0])
2915
2916
5743.6.14 by Vincent Ladeuil
Parametrize the Stack tests.
2917
class TestStackSet(TestStackWithTransport):
2918
5743.1.7 by Vincent Ladeuil
Simple set implementation.
2919
    def test_simple_set(self):
5743.6.14 by Vincent Ladeuil
Parametrize the Stack tests.
2920
        conf = self.get_stack(self)
2921
        conf.store._load_from_string('foo=bar')
5743.1.7 by Vincent Ladeuil
Simple set implementation.
2922
        self.assertEquals('bar', conf.get('foo'))
2923
        conf.set('foo', 'baz')
2924
        # Did we get it back ?
2925
        self.assertEquals('baz', conf.get('foo'))
2926
5743.1.8 by Vincent Ladeuil
Damn, the sections can't be pre-loaded or need to be reloaded on modifications or even better lazily iterated instead.
2927
    def test_set_creates_a_new_section(self):
5743.6.14 by Vincent Ladeuil
Parametrize the Stack tests.
2928
        conf = self.get_stack(self)
5743.1.8 by Vincent Ladeuil
Damn, the sections can't be pre-loaded or need to be reloaded on modifications or even better lazily iterated instead.
2929
        conf.set('foo', 'baz')
5743.1.9 by Vincent Ladeuil
Fix the issue by allowing delayed section acquisition.
2930
        self.assertEquals, 'baz', conf.get('foo')
5743.1.8 by Vincent Ladeuil
Damn, the sections can't be pre-loaded or need to be reloaded on modifications or even better lazily iterated instead.
2931
5743.8.6 by Vincent Ladeuil
Add hooks for config stacks.
2932
    def test_set_hook(self):
2933
        calls = []
2934
        def hook(*args):
2935
            calls.append(args)
5743.8.10 by Vincent Ladeuil
We don't need (nor want) to tie the config hooks to a particular class. Especially when we want to use the same hooks on both implementations.
2936
        config.ConfigHooks.install_named_hook('set', hook, None)
5743.8.6 by Vincent Ladeuil
Add hooks for config stacks.
2937
        self.assertLength(0, calls)
2938
        conf = self.get_stack(self)
2939
        conf.set('foo', 'bar')
2940
        self.assertLength(1, calls)
2941
        self.assertEquals((conf, 'foo', 'bar'), calls[0])
2942
5743.1.7 by Vincent Ladeuil
Simple set implementation.
2943
5743.6.14 by Vincent Ladeuil
Parametrize the Stack tests.
2944
class TestStackRemove(TestStackWithTransport):
5743.1.15 by Vincent Ladeuil
Test and implement ConfigStack.remove.
2945
2946
    def test_remove_existing(self):
5743.6.14 by Vincent Ladeuil
Parametrize the Stack tests.
2947
        conf = self.get_stack(self)
2948
        conf.store._load_from_string('foo=bar')
5743.1.15 by Vincent Ladeuil
Test and implement ConfigStack.remove.
2949
        self.assertEquals('bar', conf.get('foo'))
2950
        conf.remove('foo')
2951
        # Did we get it back ?
2952
        self.assertEquals(None, conf.get('foo'))
2953
2954
    def test_remove_unknown(self):
5743.6.14 by Vincent Ladeuil
Parametrize the Stack tests.
2955
        conf = self.get_stack(self)
5743.1.15 by Vincent Ladeuil
Test and implement ConfigStack.remove.
2956
        self.assertRaises(KeyError, conf.remove, 'I_do_not_exist')
2957
5743.8.6 by Vincent Ladeuil
Add hooks for config stacks.
2958
    def test_remove_hook(self):
2959
        calls = []
2960
        def hook(*args):
2961
            calls.append(args)
5743.8.10 by Vincent Ladeuil
We don't need (nor want) to tie the config hooks to a particular class. Especially when we want to use the same hooks on both implementations.
2962
        config.ConfigHooks.install_named_hook('remove', hook, None)
5743.8.6 by Vincent Ladeuil
Add hooks for config stacks.
2963
        self.assertLength(0, calls)
2964
        conf = self.get_stack(self)
2965
        conf.store._load_from_string('foo=bar')
2966
        conf.remove('foo')
2967
        self.assertLength(1, calls)
2968
        self.assertEquals((conf, 'foo'), calls[0])
2969
5743.1.15 by Vincent Ladeuil
Test and implement ConfigStack.remove.
2970
5533.2.1 by Vincent Ladeuil
``bzr config`` properly displays list values
2971
class TestConfigGetOptions(tests.TestCaseWithTransport, TestOptionsMixin):
5447.4.1 by Vincent Ladeuil
Implement config.get_options_matching_regexp.
2972
2973
    def setUp(self):
5447.4.6 by Vincent Ladeuil
Start defining fixtures but we still have an unexpected sucessful test.
2974
        super(TestConfigGetOptions, self).setUp()
2975
        create_configs(self)
5447.4.4 by Vincent Ladeuil
Implement config.get_sections() to clarify how sections can be used.
2976
5447.4.1 by Vincent Ladeuil
Implement config.get_options_matching_regexp.
2977
    def test_no_variable(self):
2978
        # Using branch should query branch, locations and bazaar
5447.4.3 by Vincent Ladeuil
Simplify code and design by only defining get_options() where relevant.
2979
        self.assertOptions([], self.branch_config)
2980
2981
    def test_option_in_bazaar(self):
5447.4.6 by Vincent Ladeuil
Start defining fixtures but we still have an unexpected sucessful test.
2982
        self.bazaar_config.set_user_option('file', 'bazaar')
5447.4.3 by Vincent Ladeuil
Simplify code and design by only defining get_options() where relevant.
2983
        self.assertOptions([('file', 'bazaar', 'DEFAULT', 'bazaar')],
5447.4.6 by Vincent Ladeuil
Start defining fixtures but we still have an unexpected sucessful test.
2984
                           self.bazaar_config)
5447.4.3 by Vincent Ladeuil
Simplify code and design by only defining get_options() where relevant.
2985
2986
    def test_option_in_locations(self):
2987
        self.locations_config.set_user_option('file', 'locations')
2988
        self.assertOptions(
2989
            [('file', 'locations', self.tree.basedir, 'locations')],
2990
            self.locations_config)
2991
2992
    def test_option_in_branch(self):
2993
        self.branch_config.set_user_option('file', 'branch')
2994
        self.assertOptions([('file', 'branch', 'DEFAULT', 'branch')],
2995
                           self.branch_config)
2996
2997
    def test_option_in_bazaar_and_branch(self):
5447.4.6 by Vincent Ladeuil
Start defining fixtures but we still have an unexpected sucessful test.
2998
        self.bazaar_config.set_user_option('file', 'bazaar')
5447.4.3 by Vincent Ladeuil
Simplify code and design by only defining get_options() where relevant.
2999
        self.branch_config.set_user_option('file', 'branch')
3000
        self.assertOptions([('file', 'branch', 'DEFAULT', 'branch'),
3001
                            ('file', 'bazaar', 'DEFAULT', 'bazaar'),],
3002
                           self.branch_config)
3003
3004
    def test_option_in_branch_and_locations(self):
5447.4.1 by Vincent Ladeuil
Implement config.get_options_matching_regexp.
3005
        # Hmm, locations override branch :-/
3006
        self.locations_config.set_user_option('file', 'locations')
3007
        self.branch_config.set_user_option('file', 'branch')
5447.4.3 by Vincent Ladeuil
Simplify code and design by only defining get_options() where relevant.
3008
        self.assertOptions(
3009
            [('file', 'locations', self.tree.basedir, 'locations'),
3010
             ('file', 'branch', 'DEFAULT', 'branch'),],
3011
            self.branch_config)
5447.4.1 by Vincent Ladeuil
Implement config.get_options_matching_regexp.
3012
5447.4.3 by Vincent Ladeuil
Simplify code and design by only defining get_options() where relevant.
3013
    def test_option_in_bazaar_locations_and_branch(self):
5447.4.6 by Vincent Ladeuil
Start defining fixtures but we still have an unexpected sucessful test.
3014
        self.bazaar_config.set_user_option('file', 'bazaar')
5447.4.1 by Vincent Ladeuil
Implement config.get_options_matching_regexp.
3015
        self.locations_config.set_user_option('file', 'locations')
3016
        self.branch_config.set_user_option('file', 'branch')
5447.4.3 by Vincent Ladeuil
Simplify code and design by only defining get_options() where relevant.
3017
        self.assertOptions(
3018
            [('file', 'locations', self.tree.basedir, 'locations'),
3019
             ('file', 'branch', 'DEFAULT', 'branch'),
3020
             ('file', 'bazaar', 'DEFAULT', 'bazaar'),],
3021
            self.branch_config)
5447.4.1 by Vincent Ladeuil
Implement config.get_options_matching_regexp.
3022
3023
5533.2.1 by Vincent Ladeuil
``bzr config`` properly displays list values
3024
class TestConfigRemoveOption(tests.TestCaseWithTransport, TestOptionsMixin):
5447.4.6 by Vincent Ladeuil
Start defining fixtures but we still have an unexpected sucessful test.
3025
3026
    def setUp(self):
3027
        super(TestConfigRemoveOption, self).setUp()
3028
        create_configs_with_file_option(self)
3029
5447.4.11 by Vincent Ladeuil
Implement ``bzr config --remove <option>``.
3030
    def test_remove_in_locations(self):
3031
        self.locations_config.remove_user_option('file', self.tree.basedir)
3032
        self.assertOptions(
3033
            [('file', 'branch', 'DEFAULT', 'branch'),
3034
             ('file', 'bazaar', 'DEFAULT', 'bazaar'),],
3035
            self.branch_config)
3036
3037
    def test_remove_in_branch(self):
3038
        self.branch_config.remove_user_option('file')
3039
        self.assertOptions(
3040
            [('file', 'locations', self.tree.basedir, 'locations'),
3041
             ('file', 'bazaar', 'DEFAULT', 'bazaar'),],
3042
            self.branch_config)
3043
3044
    def test_remove_in_bazaar(self):
3045
        self.bazaar_config.remove_user_option('file')
3046
        self.assertOptions(
3047
            [('file', 'locations', self.tree.basedir, 'locations'),
3048
             ('file', 'branch', 'DEFAULT', 'branch'),],
3049
            self.branch_config)
3050
5447.4.7 by Vincent Ladeuil
Check error message if the test is checking for errors or we have unexpected success for wrong errors.
3051
5447.4.6 by Vincent Ladeuil
Start defining fixtures but we still have an unexpected sucessful test.
3052
class TestConfigGetSections(tests.TestCaseWithTransport):
3053
3054
    def setUp(self):
3055
        super(TestConfigGetSections, self).setUp()
3056
        create_configs(self)
5447.4.4 by Vincent Ladeuil
Implement config.get_sections() to clarify how sections can be used.
3057
3058
    def assertSectionNames(self, expected, conf, name=None):
3059
        """Check which sections are returned for a given config.
3060
3061
        If fallback configurations exist their sections can be included.
3062
3063
        :param expected: A list of section names.
3064
3065
        :param conf: The configuration that will be queried.
3066
3067
        :param name: An optional section name that will be passed to
3068
            get_sections().
3069
        """
5447.4.12 by Vincent Ladeuil
Turn get_options() and get_sections() into private methods because section handling is too messy and needs to be discussed and settled.
3070
        sections = list(conf._get_sections(name))
5447.4.4 by Vincent Ladeuil
Implement config.get_sections() to clarify how sections can be used.
3071
        self.assertLength(len(expected), sections)
5447.4.12 by Vincent Ladeuil
Turn get_options() and get_sections() into private methods because section handling is too messy and needs to be discussed and settled.
3072
        self.assertEqual(expected, [name for name, _, _ in sections])
5447.4.4 by Vincent Ladeuil
Implement config.get_sections() to clarify how sections can be used.
3073
5447.4.6 by Vincent Ladeuil
Start defining fixtures but we still have an unexpected sucessful test.
3074
    def test_bazaar_default_section(self):
3075
        self.assertSectionNames(['DEFAULT'], self.bazaar_config)
5447.4.4 by Vincent Ladeuil
Implement config.get_sections() to clarify how sections can be used.
3076
3077
    def test_locations_default_section(self):
3078
        # No sections are defined in an empty file
3079
        self.assertSectionNames([], self.locations_config)
3080
3081
    def test_locations_named_section(self):
3082
        self.locations_config.set_user_option('file', 'locations')
3083
        self.assertSectionNames([self.tree.basedir], self.locations_config)
3084
3085
    def test_locations_matching_sections(self):
3086
        loc_config = self.locations_config
3087
        loc_config.set_user_option('file', 'locations')
3088
        # We need to cheat a bit here to create an option in sections above and
3089
        # below the 'location' one.
3090
        parser = loc_config._get_parser()
3091
        # locations.cong deals with '/' ignoring native os.sep
3092
        location_names = self.tree.basedir.split('/')
3093
        parent = '/'.join(location_names[:-1])
3094
        child = '/'.join(location_names + ['child'])
3095
        parser[parent] = {}
3096
        parser[parent]['file'] = 'parent'
3097
        parser[child] = {}
3098
        parser[child]['file'] = 'child'
3099
        self.assertSectionNames([self.tree.basedir, parent], loc_config)
3100
3101
    def test_branch_data_default_section(self):
3102
        self.assertSectionNames([None],
3103
                                self.branch_config._get_branch_data_config())
3104
3105
    def test_branch_default_sections(self):
3106
        # No sections are defined in an empty locations file
3107
        self.assertSectionNames([None, 'DEFAULT'],
3108
                                self.branch_config)
3109
        # Unless we define an option
3110
        self.branch_config._get_location_config().set_user_option(
3111
            'file', 'locations')
3112
        self.assertSectionNames([self.tree.basedir, None, 'DEFAULT'],
3113
                                self.branch_config)
3114
5447.4.6 by Vincent Ladeuil
Start defining fixtures but we still have an unexpected sucessful test.
3115
    def test_bazaar_named_section(self):
5447.4.4 by Vincent Ladeuil
Implement config.get_sections() to clarify how sections can be used.
3116
        # We need to cheat as the API doesn't give direct access to sections
3117
        # other than DEFAULT.
5447.4.6 by Vincent Ladeuil
Start defining fixtures but we still have an unexpected sucessful test.
3118
        self.bazaar_config.set_alias('bazaar', 'bzr')
3119
        self.assertSectionNames(['ALIASES'], self.bazaar_config, 'ALIASES')
5447.4.4 by Vincent Ladeuil
Implement config.get_sections() to clarify how sections can be used.
3120
3121
2900.2.5 by Vincent Ladeuil
ake ftp aware of authentication config.
3122
class TestAuthenticationConfigFile(tests.TestCase):
2900.2.14 by Vincent Ladeuil
More tests.
3123
    """Test the authentication.conf file matching"""
2900.2.3 by Vincent Ladeuil
Credentials matching implementation.
3124
3125
    def _got_user_passwd(self, expected_user, expected_password,
3126
                         config, *args, **kwargs):
3127
        credentials = config.get_credentials(*args, **kwargs)
3128
        if credentials is None:
3129
            user = None
3130
            password = None
3131
        else:
3132
            user = credentials['user']
3133
            password = credentials['password']
3134
        self.assertEquals(expected_user, user)
3135
        self.assertEquals(expected_password, password)
3136
2978.5.1 by John Arbash Meinel
Fix bug #162494, 'bzr register-branch' needs proper auth handling.
3137
    def test_empty_config(self):
2900.2.3 by Vincent Ladeuil
Credentials matching implementation.
3138
        conf = config.AuthenticationConfig(_file=StringIO())
3139
        self.assertEquals({}, conf._get_config())
3140
        self._got_user_passwd(None, None, conf, 'http', 'foo.net')
3141
5987.1.2 by Vincent Ladeuil
Reproduce bug #502060, bug #688677 and bug #792246.
3142
    def test_non_utf8_config(self):
3143
        conf = config.AuthenticationConfig(_file=StringIO(
3144
                'foo = bar\xff'))
5987.1.3 by Vincent Ladeuil
Proper message when authentication.conf has non-utf8 content
3145
        self.assertRaises(errors.ConfigContentError, conf._get_config)
5987.1.2 by Vincent Ladeuil
Reproduce bug #502060, bug #688677 and bug #792246.
3146
        
3418.2.1 by Vincent Ladeuil
Fix #217650 by catching declarations outside sections.
3147
    def test_missing_auth_section_header(self):
3148
        conf = config.AuthenticationConfig(_file=StringIO('foo = bar'))
3149
        self.assertRaises(ValueError, conf.get_credentials, 'ftp', 'foo.net')
3150
3151
    def test_auth_section_header_not_closed(self):
2900.2.3 by Vincent Ladeuil
Credentials matching implementation.
3152
        conf = config.AuthenticationConfig(_file=StringIO('[DEF'))
3153
        self.assertRaises(errors.ParseConfigError, conf._get_config)
2900.2.15 by Vincent Ladeuil
AuthenticationConfig can be queried for logins too (first step).
3154
3418.2.1 by Vincent Ladeuil
Fix #217650 by catching declarations outside sections.
3155
    def test_auth_value_not_boolean(self):
2900.2.4 by Vincent Ladeuil
Cosmetic changes.
3156
        conf = config.AuthenticationConfig(_file=StringIO(
3157
                """[broken]
3158
scheme=ftp
3159
user=joe
2900.2.15 by Vincent Ladeuil
AuthenticationConfig can be queried for logins too (first step).
3160
verify_certificates=askme # Error: Not a boolean
2900.2.4 by Vincent Ladeuil
Cosmetic changes.
3161
"""))
3162
        self.assertRaises(ValueError, conf.get_credentials, 'ftp', 'foo.net')
3418.2.1 by Vincent Ladeuil
Fix #217650 by catching declarations outside sections.
3163
3164
    def test_auth_value_not_int(self):
2900.2.22 by Vincent Ladeuil
Polishing.
3165
        conf = config.AuthenticationConfig(_file=StringIO(
3166
                """[broken]
3167
scheme=ftp
3168
user=joe
3169
port=port # Error: Not an int
3170
"""))
3171
        self.assertRaises(ValueError, conf.get_credentials, 'ftp', 'foo.net')
2900.2.3 by Vincent Ladeuil
Credentials matching implementation.
3172
3757.3.1 by Vincent Ladeuil
Add credential stores plugging.
3173
    def test_unknown_password_encoding(self):
3174
        conf = config.AuthenticationConfig(_file=StringIO(
3175
                """[broken]
3176
scheme=ftp
3177
user=joe
3178
password_encoding=unknown
3179
"""))
3180
        self.assertRaises(ValueError, conf.get_password,
3181
                          'ftp', 'foo.net', 'joe')
3182
2900.2.3 by Vincent Ladeuil
Credentials matching implementation.
3183
    def test_credentials_for_scheme_host(self):
3184
        conf = config.AuthenticationConfig(_file=StringIO(
3185
                """# Identity on foo.net
3186
[ftp definition]
3187
scheme=ftp
3188
host=foo.net
3189
user=joe
3190
password=secret-pass
3191
"""))
3192
        # Basic matching
3193
        self._got_user_passwd('joe', 'secret-pass', conf, 'ftp', 'foo.net')
3194
        # different scheme
3195
        self._got_user_passwd(None, None, conf, 'http', 'foo.net')
3196
        # different host
3197
        self._got_user_passwd(None, None, conf, 'ftp', 'bar.net')
3198
3199
    def test_credentials_for_host_port(self):
3200
        conf = config.AuthenticationConfig(_file=StringIO(
3201
                """# Identity on foo.net
3202
[ftp definition]
3203
scheme=ftp
3204
port=10021
3205
host=foo.net
3206
user=joe
3207
password=secret-pass
3208
"""))
3209
        # No port
3210
        self._got_user_passwd('joe', 'secret-pass',
3211
                              conf, 'ftp', 'foo.net', port=10021)
3212
        # different port
3213
        self._got_user_passwd(None, None, conf, 'ftp', 'foo.net')
3214
3215
    def test_for_matching_host(self):
3216
        conf = config.AuthenticationConfig(_file=StringIO(
3217
                """# Identity on foo.net
3218
[sourceforge]
3219
scheme=bzr
3220
host=bzr.sf.net
3221
user=joe
3222
password=joepass
3223
[sourceforge domain]
3224
scheme=bzr
3225
host=.bzr.sf.net
3226
user=georges
3227
password=bendover
3228
"""))
3229
        # matching domain
3230
        self._got_user_passwd('georges', 'bendover',
3231
                              conf, 'bzr', 'foo.bzr.sf.net')
3232
        # phishing attempt
3233
        self._got_user_passwd(None, None,
3234
                              conf, 'bzr', 'bbzr.sf.net')
3235
3236
    def test_for_matching_host_None(self):
3237
        conf = config.AuthenticationConfig(_file=StringIO(
3238
                """# Identity on foo.net
3239
[catchup bzr]
3240
scheme=bzr
3241
user=joe
3242
password=joepass
3243
[DEFAULT]
3244
user=georges
3245
password=bendover
3246
"""))
3247
        # match no host
3248
        self._got_user_passwd('joe', 'joepass',
3249
                              conf, 'bzr', 'quux.net')
3250
        # no host but different scheme
3251
        self._got_user_passwd('georges', 'bendover',
3252
                              conf, 'ftp', 'quux.net')
3253
3254
    def test_credentials_for_path(self):
3255
        conf = config.AuthenticationConfig(_file=StringIO(
3256
                """
3257
[http dir1]
3258
scheme=http
3259
host=bar.org
3260
path=/dir1
3261
user=jim
3262
password=jimpass
3263
[http dir2]
3264
scheme=http
3265
host=bar.org
3266
path=/dir2
3267
user=georges
3268
password=bendover
3269
"""))
3270
        # no path no dice
3271
        self._got_user_passwd(None, None,
3272
                              conf, 'http', host='bar.org', path='/dir3')
3273
        # matching path
3274
        self._got_user_passwd('georges', 'bendover',
3275
                              conf, 'http', host='bar.org', path='/dir2')
3276
        # matching subdir
3277
        self._got_user_passwd('jim', 'jimpass',
3278
                              conf, 'http', host='bar.org',path='/dir1/subdir')
3279
3280
    def test_credentials_for_user(self):
3281
        conf = config.AuthenticationConfig(_file=StringIO(
3282
                """
3283
[with user]
3284
scheme=http
3285
host=bar.org
3286
user=jim
3287
password=jimpass
3288
"""))
3289
        # Get user
3290
        self._got_user_passwd('jim', 'jimpass',
3291
                              conf, 'http', 'bar.org')
3292
        # Get same user
3293
        self._got_user_passwd('jim', 'jimpass',
3294
                              conf, 'http', 'bar.org', user='jim')
3295
        # Don't get a different user if one is specified
3296
        self._got_user_passwd(None, None,
3297
                              conf, 'http', 'bar.org', user='georges')
3298
3418.4.1 by Vincent Ladeuil
Reproduce bug 199440.
3299
    def test_credentials_for_user_without_password(self):
3300
        conf = config.AuthenticationConfig(_file=StringIO(
3301
                """
3302
[without password]
3303
scheme=http
3304
host=bar.org
3305
user=jim
3306
"""))
3307
        # Get user but no password
3308
        self._got_user_passwd('jim', None,
3309
                              conf, 'http', 'bar.org')
3310
2900.2.3 by Vincent Ladeuil
Credentials matching implementation.
3311
    def test_verify_certificates(self):
3312
        conf = config.AuthenticationConfig(_file=StringIO(
3313
                """
3314
[self-signed]
3315
scheme=https
3316
host=bar.org
3317
user=jim
3318
password=jimpass
3319
verify_certificates=False
3320
[normal]
3321
scheme=https
3322
host=foo.net
3323
user=georges
3324
password=bendover
3325
"""))
3326
        credentials = conf.get_credentials('https', 'bar.org')
3327
        self.assertEquals(False, credentials.get('verify_certificates'))
3328
        credentials = conf.get_credentials('https', 'foo.net')
3329
        self.assertEquals(True, credentials.get('verify_certificates'))
2900.2.4 by Vincent Ladeuil
Cosmetic changes.
3330
3777.1.10 by Aaron Bentley
Ensure credentials are stored
3331
3332
class TestAuthenticationStorage(tests.TestCaseInTempDir):
3333
3777.1.8 by Aaron Bentley
Commit work-in-progress
3334
    def test_set_credentials(self):
3777.1.10 by Aaron Bentley
Ensure credentials are stored
3335
        conf = config.AuthenticationConfig()
3777.3.2 by Aaron Bentley
Reverse order of scheme and password
3336
        conf.set_credentials('name', 'host', 'user', 'scheme', 'password',
4081.1.1 by Jean-Francois Roy
A 'realm' optional argument was added to the get_credentials and set_credentials
3337
        99, path='/foo', verify_certificates=False, realm='realm')
3777.1.8 by Aaron Bentley
Commit work-in-progress
3338
        credentials = conf.get_credentials(host='host', scheme='scheme',
4081.1.1 by Jean-Francois Roy
A 'realm' optional argument was added to the get_credentials and set_credentials
3339
                                           port=99, path='/foo',
3340
                                           realm='realm')
3777.1.10 by Aaron Bentley
Ensure credentials are stored
3341
        CREDENTIALS = {'name': 'name', 'user': 'user', 'password': 'password',
4107.1.8 by Jean-Francois Roy
Updated test_config to account for the new credentials keys.
3342
                       'verify_certificates': False, 'scheme': 'scheme', 
3343
                       'host': 'host', 'port': 99, 'path': '/foo', 
3344
                       'realm': 'realm'}
3777.1.10 by Aaron Bentley
Ensure credentials are stored
3345
        self.assertEqual(CREDENTIALS, credentials)
3346
        credentials_from_disk = config.AuthenticationConfig().get_credentials(
4081.1.1 by Jean-Francois Roy
A 'realm' optional argument was added to the get_credentials and set_credentials
3347
            host='host', scheme='scheme', port=99, path='/foo', realm='realm')
3777.1.10 by Aaron Bentley
Ensure credentials are stored
3348
        self.assertEqual(CREDENTIALS, credentials_from_disk)
3777.1.8 by Aaron Bentley
Commit work-in-progress
3349
3777.1.11 by Aaron Bentley
Ensure changed-name updates clear old values
3350
    def test_reset_credentials_different_name(self):
3351
        conf = config.AuthenticationConfig()
3777.3.2 by Aaron Bentley
Reverse order of scheme and password
3352
        conf.set_credentials('name', 'host', 'user', 'scheme', 'password'),
3353
        conf.set_credentials('name2', 'host', 'user2', 'scheme', 'password'),
3777.1.11 by Aaron Bentley
Ensure changed-name updates clear old values
3354
        self.assertIs(None, conf._get_config().get('name'))
3355
        credentials = conf.get_credentials(host='host', scheme='scheme')
3356
        CREDENTIALS = {'name': 'name2', 'user': 'user2', 'password':
4107.1.8 by Jean-Francois Roy
Updated test_config to account for the new credentials keys.
3357
                       'password', 'verify_certificates': True, 
3358
                       'scheme': 'scheme', 'host': 'host', 'port': None, 
3359
                       'path': None, 'realm': None}
3777.1.11 by Aaron Bentley
Ensure changed-name updates clear old values
3360
        self.assertEqual(CREDENTIALS, credentials)
3361
2900.2.5 by Vincent Ladeuil
ake ftp aware of authentication config.
3362
2900.2.14 by Vincent Ladeuil
More tests.
3363
class TestAuthenticationConfig(tests.TestCase):
3364
    """Test AuthenticationConfig behaviour"""
3365
4222.3.1 by Jelmer Vernooij
Mention password when checking default prompt.
3366
    def _check_default_password_prompt(self, expected_prompt_format, scheme,
4368.3.1 by Vincent Ladeuil
Use stderr for UI prompt to address bug #376582.
3367
                                       host=None, port=None, realm=None,
3368
                                       path=None):
2900.2.14 by Vincent Ladeuil
More tests.
3369
        if host is None:
3370
            host = 'bar.org'
3371
        user, password = 'jim', 'precious'
3372
        expected_prompt = expected_prompt_format % {
3373
            'scheme': scheme, 'host': host, 'port': port,
3374
            'user': user, 'realm': realm}
3375
3376
        stdout = tests.StringIOWrapper()
4368.3.1 by Vincent Ladeuil
Use stderr for UI prompt to address bug #376582.
3377
        stderr = tests.StringIOWrapper()
2900.2.14 by Vincent Ladeuil
More tests.
3378
        ui.ui_factory = tests.TestUIFactory(stdin=password + '\n',
4368.3.1 by Vincent Ladeuil
Use stderr for UI prompt to address bug #376582.
3379
                                            stdout=stdout, stderr=stderr)
2900.2.14 by Vincent Ladeuil
More tests.
3380
        # We use an empty conf so that the user is always prompted
3381
        conf = config.AuthenticationConfig()
3382
        self.assertEquals(password,
3383
                          conf.get_password(scheme, host, user, port=port,
3384
                                            realm=realm, path=path))
4368.3.1 by Vincent Ladeuil
Use stderr for UI prompt to address bug #376582.
3385
        self.assertEquals(expected_prompt, stderr.getvalue())
3386
        self.assertEquals('', stdout.getvalue())
2900.2.14 by Vincent Ladeuil
More tests.
3387
4222.3.2 by Jelmer Vernooij
Prompt for user names if they are not in the configuration.
3388
    def _check_default_username_prompt(self, expected_prompt_format, scheme,
4368.3.1 by Vincent Ladeuil
Use stderr for UI prompt to address bug #376582.
3389
                                       host=None, port=None, realm=None,
3390
                                       path=None):
4222.3.2 by Jelmer Vernooij
Prompt for user names if they are not in the configuration.
3391
        if host is None:
3392
            host = 'bar.org'
3393
        username = 'jim'
3394
        expected_prompt = expected_prompt_format % {
3395
            'scheme': scheme, 'host': host, 'port': port,
3396
            'realm': realm}
3397
        stdout = tests.StringIOWrapper()
4368.3.1 by Vincent Ladeuil
Use stderr for UI prompt to address bug #376582.
3398
        stderr = tests.StringIOWrapper()
4222.3.2 by Jelmer Vernooij
Prompt for user names if they are not in the configuration.
3399
        ui.ui_factory = tests.TestUIFactory(stdin=username+ '\n',
4368.3.1 by Vincent Ladeuil
Use stderr for UI prompt to address bug #376582.
3400
                                            stdout=stdout, stderr=stderr)
4222.3.2 by Jelmer Vernooij
Prompt for user names if they are not in the configuration.
3401
        # We use an empty conf so that the user is always prompted
3402
        conf = config.AuthenticationConfig()
4222.3.5 by Jelmer Vernooij
Fix test.
3403
        self.assertEquals(username, conf.get_user(scheme, host, port=port,
3404
                          realm=realm, path=path, ask=True))
4368.3.1 by Vincent Ladeuil
Use stderr for UI prompt to address bug #376582.
3405
        self.assertEquals(expected_prompt, stderr.getvalue())
3406
        self.assertEquals('', stdout.getvalue())
4222.3.2 by Jelmer Vernooij
Prompt for user names if they are not in the configuration.
3407
3408
    def test_username_defaults_prompts(self):
3409
        # HTTP prompts can't be tested here, see test_http.py
5923.1.3 by Vincent Ladeuil
Even more unicode prompts fixes revealed by pqm.
3410
        self._check_default_username_prompt(u'FTP %(host)s username: ', 'ftp')
3411
        self._check_default_username_prompt(
3412
            u'FTP %(host)s:%(port)d username: ', 'ftp', port=10020)
3413
        self._check_default_username_prompt(
3414
            u'SSH %(host)s:%(port)d username: ', 'ssh', port=12345)
4222.3.2 by Jelmer Vernooij
Prompt for user names if they are not in the configuration.
3415
4222.3.11 by Jelmer Vernooij
Add test to make sure the default= parameter works.
3416
    def test_username_default_no_prompt(self):
3417
        conf = config.AuthenticationConfig()
4304.2.1 by Vincent Ladeuil
Fix bug #367726 by reverting some default user handling introduced
3418
        self.assertEquals(None,
4222.3.11 by Jelmer Vernooij
Add test to make sure the default= parameter works.
3419
            conf.get_user('ftp', 'example.com'))
4304.2.1 by Vincent Ladeuil
Fix bug #367726 by reverting some default user handling introduced
3420
        self.assertEquals("explicitdefault",
4222.3.11 by Jelmer Vernooij
Add test to make sure the default= parameter works.
3421
            conf.get_user('ftp', 'example.com', default="explicitdefault"))
3422
4222.3.1 by Jelmer Vernooij
Mention password when checking default prompt.
3423
    def test_password_default_prompts(self):
2900.2.19 by Vincent Ladeuil
Mention proxy and https in the password prompts, with tests.
3424
        # HTTP prompts can't be tested here, see test_http.py
4222.3.1 by Jelmer Vernooij
Mention password when checking default prompt.
3425
        self._check_default_password_prompt(
5923.1.3 by Vincent Ladeuil
Even more unicode prompts fixes revealed by pqm.
3426
            u'FTP %(user)s@%(host)s password: ', 'ftp')
3427
        self._check_default_password_prompt(
3428
            u'FTP %(user)s@%(host)s:%(port)d password: ', 'ftp', port=10020)
3429
        self._check_default_password_prompt(
3430
            u'SSH %(user)s@%(host)s:%(port)d password: ', 'ssh', port=12345)
2900.2.14 by Vincent Ladeuil
More tests.
3431
        # SMTP port handling is a bit special (it's handled if embedded in the
3432
        # host too)
2900.2.22 by Vincent Ladeuil
Polishing.
3433
        # FIXME: should we: forbid that, extend it to other schemes, leave
3434
        # things as they are that's fine thank you ?
5923.1.3 by Vincent Ladeuil
Even more unicode prompts fixes revealed by pqm.
3435
        self._check_default_password_prompt(
3436
            u'SMTP %(user)s@%(host)s password: ', 'smtp')
3437
        self._check_default_password_prompt(
3438
            u'SMTP %(user)s@%(host)s password: ', 'smtp', host='bar.org:10025')
3439
        self._check_default_password_prompt(
3440
            u'SMTP %(user)s@%(host)s:%(port)d password: ', 'smtp', port=10025)
2900.2.14 by Vincent Ladeuil
More tests.
3441
3420.1.2 by Vincent Ladeuil
Fix bug #203186 by ignoring passwords for ssh and warning user.
3442
    def test_ssh_password_emits_warning(self):
3443
        conf = config.AuthenticationConfig(_file=StringIO(
3444
                """
3445
[ssh with password]
3446
scheme=ssh
3447
host=bar.org
3448
user=jim
3449
password=jimpass
3450
"""))
3451
        entered_password = 'typed-by-hand'
3452
        stdout = tests.StringIOWrapper()
4449.3.30 by Martin Pool
Tweaks to test_config ui factory use
3453
        stderr = tests.StringIOWrapper()
3420.1.2 by Vincent Ladeuil
Fix bug #203186 by ignoring passwords for ssh and warning user.
3454
        ui.ui_factory = tests.TestUIFactory(stdin=entered_password + '\n',
4449.3.30 by Martin Pool
Tweaks to test_config ui factory use
3455
                                            stdout=stdout, stderr=stderr)
3420.1.2 by Vincent Ladeuil
Fix bug #203186 by ignoring passwords for ssh and warning user.
3456
3457
        # Since the password defined in the authentication config is ignored,
3458
        # the user is prompted
3459
        self.assertEquals(entered_password,
3460
                          conf.get_password('ssh', 'bar.org', user='jim'))
3461
        self.assertContainsRe(
4794.1.17 by Robert Collins
Fix from vila for type log_log.
3462
            self.get_log(),
3420.1.2 by Vincent Ladeuil
Fix bug #203186 by ignoring passwords for ssh and warning user.
3463
            'password ignored in section \[ssh with password\]')
3464
3420.1.3 by Vincent Ladeuil
John's review feedback.
3465
    def test_ssh_without_password_doesnt_emit_warning(self):
3466
        conf = config.AuthenticationConfig(_file=StringIO(
3467
                """
3468
[ssh with password]
3469
scheme=ssh
3470
host=bar.org
3471
user=jim
3472
"""))
3473
        entered_password = 'typed-by-hand'
3474
        stdout = tests.StringIOWrapper()
4449.3.30 by Martin Pool
Tweaks to test_config ui factory use
3475
        stderr = tests.StringIOWrapper()
3420.1.3 by Vincent Ladeuil
John's review feedback.
3476
        ui.ui_factory = tests.TestUIFactory(stdin=entered_password + '\n',
4449.3.30 by Martin Pool
Tweaks to test_config ui factory use
3477
                                            stdout=stdout,
3478
                                            stderr=stderr)
3420.1.3 by Vincent Ladeuil
John's review feedback.
3479
3480
        # Since the password defined in the authentication config is ignored,
3481
        # the user is prompted
3482
        self.assertEquals(entered_password,
3483
                          conf.get_password('ssh', 'bar.org', user='jim'))
3420.1.4 by Vincent Ladeuil
Fix comment.
3484
        # No warning shoud be emitted since there is no password. We are only
3485
        # providing "user".
3420.1.3 by Vincent Ladeuil
John's review feedback.
3486
        self.assertNotContainsRe(
4794.1.15 by Robert Collins
Review feedback.
3487
            self.get_log(),
3420.1.3 by Vincent Ladeuil
John's review feedback.
3488
            'password ignored in section \[ssh with password\]')
3489
4283.1.3 by Jelmer Vernooij
Add test to make sure AuthenticationConfig queries for fallback credentials.
3490
    def test_uses_fallback_stores(self):
4985.1.5 by Vincent Ladeuil
Deploying the new overrideAttr facility further reduces the complexity
3491
        self.overrideAttr(config, 'credential_store_registry',
3492
                          config.CredentialStoreRegistry())
4283.1.3 by Jelmer Vernooij
Add test to make sure AuthenticationConfig queries for fallback credentials.
3493
        store = StubCredentialStore()
3494
        store.add_credentials("http", "example.com", "joe", "secret")
3495
        config.credential_store_registry.register("stub", store, fallback=True)
3496
        conf = config.AuthenticationConfig(_file=StringIO())
3497
        creds = conf.get_credentials("http", "example.com")
3498
        self.assertEquals("joe", creds["user"])
3499
        self.assertEquals("secret", creds["password"])
3500
2900.2.14 by Vincent Ladeuil
More tests.
3501
4283.1.2 by Jelmer Vernooij
Add tests, NEWS item.
3502
class StubCredentialStore(config.CredentialStore):
3503
3504
    def __init__(self):
3505
        self._username = {}
3506
        self._password = {}
3507
3508
    def add_credentials(self, scheme, host, user, password=None):
3509
        self._username[(scheme, host)] = user
3510
        self._password[(scheme, host)] = password
3511
3512
    def get_credentials(self, scheme, host, port=None, user=None,
3513
        path=None, realm=None):
4283.2.1 by Vincent Ladeuil
Add a test and cleanup some PEP8 issues.
3514
        key = (scheme, host)
4283.1.2 by Jelmer Vernooij
Add tests, NEWS item.
3515
        if not key in self._username:
3516
            return None
4283.2.1 by Vincent Ladeuil
Add a test and cleanup some PEP8 issues.
3517
        return { "scheme": scheme, "host": host, "port": port,
4283.1.2 by Jelmer Vernooij
Add tests, NEWS item.
3518
                "user": self._username[key], "password": self._password[key]}
3519
3520
3521
class CountingCredentialStore(config.CredentialStore):
3522
3523
    def __init__(self):
3524
        self._calls = 0
3525
3526
    def get_credentials(self, scheme, host, port=None, user=None,
3527
        path=None, realm=None):
3528
        self._calls += 1
3529
        return None
3530
3531
3757.3.1 by Vincent Ladeuil
Add credential stores plugging.
3532
class TestCredentialStoreRegistry(tests.TestCase):
3533
3534
    def _get_cs_registry(self):
3535
        return config.credential_store_registry
3536
3537
    def test_default_credential_store(self):
3538
        r = self._get_cs_registry()
3539
        default = r.get_credential_store(None)
3540
        self.assertIsInstance(default, config.PlainTextCredentialStore)
3541
3542
    def test_unknown_credential_store(self):
3543
        r = self._get_cs_registry()
3544
        # It's hard to imagine someone creating a credential store named
3545
        # 'unknown' so we use that as an never registered key.
3546
        self.assertRaises(KeyError, r.get_credential_store, 'unknown')
3547
4283.1.2 by Jelmer Vernooij
Add tests, NEWS item.
3548
    def test_fallback_none_registered(self):
3549
        r = config.CredentialStoreRegistry()
4283.2.1 by Vincent Ladeuil
Add a test and cleanup some PEP8 issues.
3550
        self.assertEquals(None,
3551
                          r.get_fallback_credentials("http", "example.com"))
4283.1.2 by Jelmer Vernooij
Add tests, NEWS item.
3552
3553
    def test_register(self):
3554
        r = config.CredentialStoreRegistry()
3555
        r.register("stub", StubCredentialStore(), fallback=False)
3556
        r.register("another", StubCredentialStore(), fallback=True)
3557
        self.assertEquals(["another", "stub"], r.keys())
3558
3559
    def test_register_lazy(self):
3560
        r = config.CredentialStoreRegistry()
4283.2.1 by Vincent Ladeuil
Add a test and cleanup some PEP8 issues.
3561
        r.register_lazy("stub", "bzrlib.tests.test_config",
3562
                        "StubCredentialStore", fallback=False)
4283.1.2 by Jelmer Vernooij
Add tests, NEWS item.
3563
        self.assertEquals(["stub"], r.keys())
4283.2.1 by Vincent Ladeuil
Add a test and cleanup some PEP8 issues.
3564
        self.assertIsInstance(r.get_credential_store("stub"),
3565
                              StubCredentialStore)
4283.1.2 by Jelmer Vernooij
Add tests, NEWS item.
3566
3567
    def test_is_fallback(self):
3568
        r = config.CredentialStoreRegistry()
3569
        r.register("stub1", None, fallback=False)
3570
        r.register("stub2", None, fallback=True)
3571
        self.assertEquals(False, r.is_fallback("stub1"))
3572
        self.assertEquals(True, r.is_fallback("stub2"))
3573
3574
    def test_no_fallback(self):
3575
        r = config.CredentialStoreRegistry()
3576
        store = CountingCredentialStore()
3577
        r.register("count", store, fallback=False)
4283.2.1 by Vincent Ladeuil
Add a test and cleanup some PEP8 issues.
3578
        self.assertEquals(None,
3579
                          r.get_fallback_credentials("http", "example.com"))
4283.1.2 by Jelmer Vernooij
Add tests, NEWS item.
3580
        self.assertEquals(0, store._calls)
3581
3582
    def test_fallback_credentials(self):
3583
        r = config.CredentialStoreRegistry()
3584
        store = StubCredentialStore()
4283.2.1 by Vincent Ladeuil
Add a test and cleanup some PEP8 issues.
3585
        store.add_credentials("http", "example.com",
3586
                              "somebody", "geheim")
4283.1.2 by Jelmer Vernooij
Add tests, NEWS item.
3587
        r.register("stub", store, fallback=True)
3588
        creds = r.get_fallback_credentials("http", "example.com")
3589
        self.assertEquals("somebody", creds["user"])
3590
        self.assertEquals("geheim", creds["password"])
3591
4283.2.1 by Vincent Ladeuil
Add a test and cleanup some PEP8 issues.
3592
    def test_fallback_first_wins(self):
3593
        r = config.CredentialStoreRegistry()
3594
        stub1 = StubCredentialStore()
3595
        stub1.add_credentials("http", "example.com",
3596
                              "somebody", "stub1")
3597
        r.register("stub1", stub1, fallback=True)
3598
        stub2 = StubCredentialStore()
3599
        stub2.add_credentials("http", "example.com",
3600
                              "somebody", "stub2")
3601
        r.register("stub2", stub1, fallback=True)
3602
        creds = r.get_fallback_credentials("http", "example.com")
3603
        self.assertEquals("somebody", creds["user"])
3604
        self.assertEquals("stub1", creds["password"])
3605
3757.3.1 by Vincent Ladeuil
Add credential stores plugging.
3606
3607
class TestPlainTextCredentialStore(tests.TestCase):
3608
3609
    def test_decode_password(self):
3610
        r = config.credential_store_registry
3611
        plain_text = r.get_credential_store()
3612
        decoded = plain_text.decode_password(dict(password='secret'))
3613
        self.assertEquals('secret', decoded)
3614
3615
2900.2.14 by Vincent Ladeuil
More tests.
3616
# FIXME: Once we have a way to declare authentication to all test servers, we
2900.2.5 by Vincent Ladeuil
ake ftp aware of authentication config.
3617
# can implement generic tests.
2900.2.15 by Vincent Ladeuil
AuthenticationConfig can be queried for logins too (first step).
3618
# test_user_password_in_url
3619
# test_user_in_url_password_from_config
3620
# test_user_in_url_password_prompted
3621
# test_user_in_config
3622
# test_user_getpass.getuser
3623
# test_user_prompted ?
2900.2.5 by Vincent Ladeuil
ake ftp aware of authentication config.
3624
class TestAuthenticationRing(tests.TestCaseWithTransport):
3625
    pass
5050.72.1 by Martin Pool
Set email address from /etc/mailname if possible
3626
3627
3628
class TestAutoUserId(tests.TestCase):
3629
    """Test inferring an automatic user name."""
3630
3631
    def test_auto_user_id(self):
3632
        """Automatic inference of user name.
3633
        
3634
        This is a bit hard to test in an isolated way, because it depends on
3635
        system functions that go direct to /etc or perhaps somewhere else.
3636
        But it's reasonable to say that on Unix, with an /etc/mailname, we ought
3637
        to be able to choose a user name with no configuration.
3638
        """
3639
        if sys.platform == 'win32':
5743.8.17 by Vincent Ladeuil
Add config old_get hook for remote config.
3640
            raise tests.TestSkipped(
3641
                "User name inference not implemented on win32")
5050.72.1 by Martin Pool
Set email address from /etc/mailname if possible
3642
        realname, address = config._auto_user_id()
3643
        if os.path.exists('/etc/mailname'):
5813.1.1 by Jelmer Vernooij
Allow realname to be empty in tests.
3644
            self.assertIsNot(None, realname)
3645
            self.assertIsNot(None, address)
5050.72.1 by Martin Pool
Set email address from /etc/mailname if possible
3646
        else:
3647
            self.assertEquals((None, None), (realname, address))
3648