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