~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_config.py

  • Committer: Andrew Starr-Bochicchio
  • Date: 2014-03-30 17:59:29 UTC
  • mto: This revision was merged to the branch mainline in revision 6592.
  • Revision ID: a.starr.b@gmail.com-20140330175929-rd97jstcbau2j1gy
Use LooseVersion from distutils to check Cython version in order to handle non-integers in the version string.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2011 Canonical Ltd
 
1
# Copyright (C) 2005-2012 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
15
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
17
"""Tests for finding and reading the bzr config file[s]."""
18
 
# import system imports here
 
18
 
19
19
from cStringIO import StringIO
 
20
from textwrap import dedent
20
21
import os
21
22
import sys
22
23
import threading
23
24
 
24
 
 
25
25
from testtools import matchers
26
26
 
27
 
#import bzrlib specific imports here
28
27
from bzrlib import (
29
28
    branch,
30
 
    bzrdir,
31
29
    config,
 
30
    controldir,
32
31
    diff,
33
32
    errors,
34
33
    osutils,
35
34
    mail_client,
36
35
    ui,
37
36
    urlutils,
 
37
    registry as _mod_registry,
38
38
    remote,
39
39
    tests,
40
40
    trace,
114
114
 
115
115
def build_control_store(test):
116
116
    build_backing_branch(test, 'branch')
117
 
    b = bzrdir.BzrDir.open('branch')
 
117
    b = controldir.ControlDir.open('branch')
118
118
    return config.ControlStore(b)
119
119
config.test_store_builder_registry.register('control', build_control_store)
120
120
 
144
144
config.test_stack_builder_registry.register('branch', build_branch_stack)
145
145
 
146
146
 
147
 
def build_remote_branch_stack(test):
 
147
def build_branch_only_stack(test):
148
148
    # There is only one permutation (but we won't be able to handle more with
149
149
    # this design anyway)
150
150
    (transport_class,
151
151
     server_class) = transport_remote.get_test_permutations()[0]
152
152
    build_backing_branch(test, 'branch', transport_class, server_class)
153
153
    b = branch.Branch.open(test.get_url('branch'))
154
 
    return config.RemoteBranchStack(b)
155
 
config.test_stack_builder_registry.register('remote_branch',
156
 
                                            build_remote_branch_stack)
 
154
    return config.BranchOnlyStack(b)
 
155
config.test_stack_builder_registry.register('branch_only',
 
156
                                            build_branch_only_stack)
157
157
 
158
158
def build_remote_control_stack(test):
159
159
    # There is only one permutation (but we won't be able to handle more with
328
328
 
329
329
class FakeBranch(object):
330
330
 
331
 
    def __init__(self, base=None, user_id=None):
 
331
    def __init__(self, base=None):
332
332
        if base is None:
333
333
            self.base = "http://example.com/branches/demo"
334
334
        else:
335
335
            self.base = base
336
336
        self._transport = self.control_files = \
337
 
            FakeControlFilesAndTransport(user_id=user_id)
 
337
            FakeControlFilesAndTransport()
338
338
 
339
339
    def _get_config(self):
340
340
        return config.TransportConfig(self._transport, 'branch.conf')
348
348
 
349
349
class FakeControlFilesAndTransport(object):
350
350
 
351
 
    def __init__(self, user_id=None):
 
351
    def __init__(self):
352
352
        self.files = {}
353
 
        if user_id:
354
 
            self.files['email'] = user_id
355
353
        self._transport = self
356
354
 
357
 
    def get_utf8(self, filename):
358
 
        # from LockableFiles
359
 
        raise AssertionError("get_utf8 should no longer be used")
360
 
 
361
355
    def get(self, filename):
362
356
        # from Transport
363
357
        try:
481
475
    def test_constructs(self):
482
476
        config.Config()
483
477
 
484
 
    def test_no_default_editor(self):
485
 
        self.assertRaises(
486
 
            NotImplementedError,
487
 
            self.applyDeprecated, deprecated_in((2, 4, 0)),
488
 
            config.Config().get_editor)
489
 
 
490
478
    def test_user_email(self):
491
479
        my_config = InstrumentedConfig()
492
480
        self.assertEqual('robert.collins@example.org', my_config.user_email())
500
488
 
501
489
    def test_signatures_default(self):
502
490
        my_config = config.Config()
503
 
        self.assertFalse(my_config.signature_needed())
 
491
        self.assertFalse(
 
492
            self.applyDeprecated(deprecated_in((2, 5, 0)),
 
493
                my_config.signature_needed))
504
494
        self.assertEqual(config.CHECK_IF_POSSIBLE,
505
 
                         my_config.signature_checking())
 
495
            self.applyDeprecated(deprecated_in((2, 5, 0)),
 
496
                my_config.signature_checking))
506
497
        self.assertEqual(config.SIGN_WHEN_REQUIRED,
507
 
                         my_config.signing_policy())
 
498
                self.applyDeprecated(deprecated_in((2, 5, 0)),
 
499
                    my_config.signing_policy))
508
500
 
509
501
    def test_signatures_template_method(self):
510
502
        my_config = InstrumentedConfig()
511
 
        self.assertEqual(config.CHECK_NEVER, my_config.signature_checking())
 
503
        self.assertEqual(config.CHECK_NEVER,
 
504
            self.applyDeprecated(deprecated_in((2, 5, 0)),
 
505
                my_config.signature_checking))
512
506
        self.assertEqual(['_get_signature_checking'], my_config._calls)
513
507
 
514
508
    def test_signatures_template_method_none(self):
515
509
        my_config = InstrumentedConfig()
516
510
        my_config._signatures = None
517
511
        self.assertEqual(config.CHECK_IF_POSSIBLE,
518
 
                         my_config.signature_checking())
 
512
                         self.applyDeprecated(deprecated_in((2, 5, 0)),
 
513
                             my_config.signature_checking))
519
514
        self.assertEqual(['_get_signature_checking'], my_config._calls)
520
515
 
521
516
    def test_gpg_signing_command_default(self):
522
517
        my_config = config.Config()
523
 
        self.assertEqual('gpg', my_config.gpg_signing_command())
 
518
        self.assertEqual('gpg',
 
519
            self.applyDeprecated(deprecated_in((2, 5, 0)),
 
520
                my_config.gpg_signing_command))
524
521
 
525
522
    def test_get_user_option_default(self):
526
523
        my_config = config.Config()
528
525
 
529
526
    def test_post_commit_default(self):
530
527
        my_config = config.Config()
531
 
        self.assertEqual(None, my_config.post_commit())
 
528
        self.assertEqual(None, self.applyDeprecated(deprecated_in((2, 5, 0)),
 
529
                                                    my_config.post_commit))
 
530
 
532
531
 
533
532
    def test_log_format_default(self):
534
533
        my_config = config.Config()
535
 
        self.assertEqual('long', my_config.log_format())
 
534
        self.assertEqual('long',
 
535
                         self.applyDeprecated(deprecated_in((2, 5, 0)),
 
536
                                              my_config.log_format))
536
537
 
537
538
    def test_acceptable_keys_default(self):
538
539
        my_config = config.Config()
539
 
        self.assertEqual(None, my_config.acceptable_keys())
 
540
        self.assertEqual(None, self.applyDeprecated(deprecated_in((2, 5, 0)),
 
541
            my_config.acceptable_keys))
540
542
 
541
543
    def test_validate_signatures_in_log_default(self):
542
544
        my_config = config.Config()
556
558
    def setUp(self):
557
559
        super(TestConfigPath, self).setUp()
558
560
        self.overrideEnv('HOME', '/home/bogus')
559
 
        self.overrideEnv('XDG_CACHE_DIR', '')
 
561
        self.overrideEnv('XDG_CACHE_HOME', '')
560
562
        if sys.platform == 'win32':
561
563
            self.overrideEnv(
562
564
                'BZR_HOME', r'C:\Documents and Settings\bogus\Application Data')
568
570
    def test_config_dir(self):
569
571
        self.assertEqual(config.config_dir(), self.bzr_home)
570
572
 
 
573
    def test_config_dir_is_unicode(self):
 
574
        self.assertIsInstance(config.config_dir(), unicode)
 
575
 
571
576
    def test_config_filename(self):
572
577
        self.assertEqual(config.config_filename(),
573
578
                         self.bzr_home + '/bazaar.conf')
623
628
class TestIniConfigBuilding(TestIniConfig):
624
629
 
625
630
    def test_contructs(self):
626
 
        my_config = config.IniBasedConfig()
 
631
        config.IniBasedConfig()
627
632
 
628
633
    def test_from_fp(self):
629
634
        my_config = config.IniBasedConfig.from_string(sample_config_text)
672
677
 
673
678
    def test_saved_with_content(self):
674
679
        content = 'foo = bar\n'
675
 
        conf = config.IniBasedConfig.from_string(
676
 
            content, file_name='./test.conf', save=True)
 
680
        config.IniBasedConfig.from_string(content, file_name='./test.conf',
 
681
                                          save=True)
677
682
        self.assertFileEqual(content, 'test.conf')
678
683
 
679
684
 
680
 
class TestIniConfigOptionExpansionDefaultValue(tests.TestCaseInTempDir):
681
 
    """What is the default value of expand for config options.
682
 
 
683
 
    This is an opt-in beta feature used to evaluate whether or not option
684
 
    references can appear in dangerous place raising exceptions, disapearing
685
 
    (and as such corrupting data) or if it's safe to activate the option by
686
 
    default.
687
 
 
688
 
    Note that these tests relies on config._expand_default_value being already
689
 
    overwritten in the parent class setUp.
690
 
    """
691
 
 
692
 
    def setUp(self):
693
 
        super(TestIniConfigOptionExpansionDefaultValue, self).setUp()
694
 
        self.config = None
695
 
        self.warnings = []
696
 
        def warning(*args):
697
 
            self.warnings.append(args[0] % args[1:])
698
 
        self.overrideAttr(trace, 'warning', warning)
699
 
 
700
 
    def get_config(self, expand):
701
 
        c = config.GlobalConfig.from_string('bzr.config.expand=%s' % (expand,),
702
 
                                            save=True)
703
 
        return c
704
 
 
705
 
    def assertExpandIs(self, expected):
706
 
        actual = config._get_expand_default_value()
707
 
        #self.config.get_user_option_as_bool('bzr.config.expand')
708
 
        self.assertEquals(expected, actual)
709
 
 
710
 
    def test_default_is_None(self):
711
 
        self.assertEquals(None, config._expand_default_value)
712
 
 
713
 
    def test_default_is_False_even_if_None(self):
714
 
        self.config = self.get_config(None)
715
 
        self.assertExpandIs(False)
716
 
 
717
 
    def test_default_is_False_even_if_invalid(self):
718
 
        self.config = self.get_config('<your choice>')
719
 
        self.assertExpandIs(False)
720
 
        # ...
721
 
        # Huh ? My choice is False ? Thanks, always happy to hear that :D
722
 
        # Wait, you've been warned !
723
 
        self.assertLength(1, self.warnings)
724
 
        self.assertEquals(
725
 
            'Value "<your choice>" is not a boolean for "bzr.config.expand"',
726
 
            self.warnings[0])
727
 
 
728
 
    def test_default_is_True(self):
729
 
        self.config = self.get_config(True)
730
 
        self.assertExpandIs(True)
731
 
 
732
 
    def test_default_is_False(self):
733
 
        self.config = self.get_config(False)
734
 
        self.assertExpandIs(False)
735
 
 
736
 
 
737
685
class TestIniConfigOptionExpansion(tests.TestCase):
738
686
    """Test option expansion from the IniConfig level.
739
687
 
1063
1011
si_g = 5g,
1064
1012
si_gb = 5gB,
1065
1013
""")
1066
 
        get_si = conf.get_user_option_as_int_from_SI
 
1014
        def get_si(s, default=None):
 
1015
            return self.applyDeprecated(
 
1016
                deprecated_in((2, 5, 0)),
 
1017
                conf.get_user_option_as_int_from_SI, s, default)
1067
1018
        self.assertEqual(100, get_si('plain'))
1068
1019
        self.assertEqual(5000, get_si('si_k'))
1069
1020
        self.assertEqual(5000, get_si('si_kb'))
1074
1025
        self.assertEqual(None, get_si('non-exist'))
1075
1026
        self.assertEqual(42, get_si('non-exist-with-default',  42))
1076
1027
 
 
1028
 
1077
1029
class TestSupressWarning(TestIniConfig):
1078
1030
 
1079
1031
    def make_warnings_config(self, s):
1094
1046
class TestGetConfig(tests.TestCase):
1095
1047
 
1096
1048
    def test_constructs(self):
1097
 
        my_config = config.GlobalConfig()
 
1049
        config.GlobalConfig()
1098
1050
 
1099
1051
    def test_calls_read_filenames(self):
1100
1052
        # replace the class that is constructed, to check its parameters
1112
1064
 
1113
1065
class TestBranchConfig(tests.TestCaseWithTransport):
1114
1066
 
1115
 
    def test_constructs(self):
 
1067
    def test_constructs_valid(self):
1116
1068
        branch = FakeBranch()
1117
1069
        my_config = config.BranchConfig(branch)
 
1070
        self.assertIsNot(None, my_config)
 
1071
 
 
1072
    def test_constructs_error(self):
1118
1073
        self.assertRaises(TypeError, config.BranchConfig)
1119
1074
 
1120
1075
    def test_get_location_config(self):
1126
1081
 
1127
1082
    def test_get_config(self):
1128
1083
        """The Branch.get_config method works properly"""
1129
 
        b = bzrdir.BzrDir.create_standalone_workingtree('.').branch
 
1084
        b = controldir.ControlDir.create_standalone_workingtree('.').branch
1130
1085
        my_config = b.get_config()
1131
1086
        self.assertIs(my_config.get_user_option('wacky'), None)
1132
1087
        my_config.set_user_option('wacky', 'unlikely')
1152
1107
        conf = config.LocationConfig.from_string(
1153
1108
            '[%s]\nnickname = foobar' % (local_url,),
1154
1109
            local_url, save=True)
 
1110
        self.assertIsNot(None, conf)
1155
1111
        self.assertEqual('foobar', branch.nick)
1156
1112
 
1157
1113
    def test_config_local_path(self):
1160
1116
        self.assertEqual('branch', branch.nick)
1161
1117
 
1162
1118
        local_path = osutils.getcwd().encode('utf8')
1163
 
        conf = config.LocationConfig.from_string(
 
1119
        config.LocationConfig.from_string(
1164
1120
            '[%s/branch]\nnickname = barry' % (local_path,),
1165
1121
            'branch',  save=True)
 
1122
        # Now the branch will find its nick via the location config
1166
1123
        self.assertEqual('barry', branch.nick)
1167
1124
 
1168
1125
    def test_config_creates_local(self):
1181
1138
        b = self.make_branch('!repo')
1182
1139
        self.assertEqual('!repo', b.get_config().get_nickname())
1183
1140
 
 
1141
    def test_autonick_uses_branch_name(self):
 
1142
        b = self.make_branch('foo', name='bar')
 
1143
        self.assertEqual('bar', b.get_config().get_nickname())
 
1144
 
1184
1145
    def test_warn_if_masked(self):
1185
1146
        warnings = []
1186
1147
        def warning(*args):
1226
1187
        my_config = config.GlobalConfig()
1227
1188
        self.assertEqual(None, my_config._get_user_id())
1228
1189
 
1229
 
    def test_configured_editor(self):
1230
 
        my_config = config.GlobalConfig.from_string(sample_config_text)
1231
 
        editor = self.applyDeprecated(
1232
 
            deprecated_in((2, 4, 0)), my_config.get_editor)
1233
 
        self.assertEqual('vim', editor)
1234
 
 
1235
1190
    def test_signatures_always(self):
1236
1191
        my_config = config.GlobalConfig.from_string(sample_always_signatures)
1237
1192
        self.assertEqual(config.CHECK_NEVER,
1238
 
                         my_config.signature_checking())
 
1193
                         self.applyDeprecated(deprecated_in((2, 5, 0)),
 
1194
                             my_config.signature_checking))
1239
1195
        self.assertEqual(config.SIGN_ALWAYS,
1240
 
                         my_config.signing_policy())
1241
 
        self.assertEqual(True, my_config.signature_needed())
 
1196
                         self.applyDeprecated(deprecated_in((2, 5, 0)),
 
1197
                             my_config.signing_policy))
 
1198
        self.assertEqual(True,
 
1199
            self.applyDeprecated(deprecated_in((2, 5, 0)),
 
1200
                my_config.signature_needed))
1242
1201
 
1243
1202
    def test_signatures_if_possible(self):
1244
1203
        my_config = config.GlobalConfig.from_string(sample_maybe_signatures)
1245
1204
        self.assertEqual(config.CHECK_NEVER,
1246
 
                         my_config.signature_checking())
 
1205
                         self.applyDeprecated(deprecated_in((2, 5, 0)),
 
1206
                             my_config.signature_checking))
1247
1207
        self.assertEqual(config.SIGN_WHEN_REQUIRED,
1248
 
                         my_config.signing_policy())
1249
 
        self.assertEqual(False, my_config.signature_needed())
 
1208
                         self.applyDeprecated(deprecated_in((2, 5, 0)),
 
1209
                             my_config.signing_policy))
 
1210
        self.assertEqual(False, self.applyDeprecated(deprecated_in((2, 5, 0)),
 
1211
            my_config.signature_needed))
1250
1212
 
1251
1213
    def test_signatures_ignore(self):
1252
1214
        my_config = config.GlobalConfig.from_string(sample_ignore_signatures)
1253
1215
        self.assertEqual(config.CHECK_ALWAYS,
1254
 
                         my_config.signature_checking())
 
1216
                         self.applyDeprecated(deprecated_in((2, 5, 0)),
 
1217
                             my_config.signature_checking))
1255
1218
        self.assertEqual(config.SIGN_NEVER,
1256
 
                         my_config.signing_policy())
1257
 
        self.assertEqual(False, my_config.signature_needed())
 
1219
                         self.applyDeprecated(deprecated_in((2, 5, 0)),
 
1220
                             my_config.signing_policy))
 
1221
        self.assertEqual(False, self.applyDeprecated(deprecated_in((2, 5, 0)),
 
1222
            my_config.signature_needed))
1258
1223
 
1259
1224
    def _get_sample_config(self):
1260
1225
        my_config = config.GlobalConfig.from_string(sample_config_text)
1262
1227
 
1263
1228
    def test_gpg_signing_command(self):
1264
1229
        my_config = self._get_sample_config()
1265
 
        self.assertEqual("gnome-gpg", my_config.gpg_signing_command())
1266
 
        self.assertEqual(False, my_config.signature_needed())
 
1230
        self.assertEqual("gnome-gpg",
 
1231
            self.applyDeprecated(
 
1232
                deprecated_in((2, 5, 0)), my_config.gpg_signing_command))
 
1233
        self.assertEqual(False, self.applyDeprecated(deprecated_in((2, 5, 0)),
 
1234
            my_config.signature_needed))
1267
1235
 
1268
1236
    def test_gpg_signing_key(self):
1269
1237
        my_config = self._get_sample_config()
1270
 
        self.assertEqual("DD4D5088", my_config.gpg_signing_key())
 
1238
        self.assertEqual("DD4D5088",
 
1239
            self.applyDeprecated(deprecated_in((2, 5, 0)),
 
1240
                my_config.gpg_signing_key))
1271
1241
 
1272
1242
    def _get_empty_config(self):
1273
1243
        my_config = config.GlobalConfig()
1275
1245
 
1276
1246
    def test_gpg_signing_command_unset(self):
1277
1247
        my_config = self._get_empty_config()
1278
 
        self.assertEqual("gpg", my_config.gpg_signing_command())
 
1248
        self.assertEqual("gpg",
 
1249
            self.applyDeprecated(
 
1250
                deprecated_in((2, 5, 0)), my_config.gpg_signing_command))
1279
1251
 
1280
1252
    def test_get_user_option_default(self):
1281
1253
        my_config = self._get_empty_config()
1288
1260
 
1289
1261
    def test_post_commit_default(self):
1290
1262
        my_config = self._get_sample_config()
1291
 
        self.assertEqual(None, my_config.post_commit())
 
1263
        self.assertEqual(None,
 
1264
                         self.applyDeprecated(deprecated_in((2, 5, 0)),
 
1265
                                              my_config.post_commit))
1292
1266
 
1293
1267
    def test_configured_logformat(self):
1294
1268
        my_config = self._get_sample_config()
1295
 
        self.assertEqual("short", my_config.log_format())
 
1269
        self.assertEqual("short",
 
1270
                         self.applyDeprecated(deprecated_in((2, 5, 0)),
 
1271
                                              my_config.log_format))
1296
1272
 
1297
1273
    def test_configured_acceptable_keys(self):
1298
1274
        my_config = self._get_sample_config()
1299
 
        self.assertEqual("amy", my_config.acceptable_keys())
 
1275
        self.assertEqual("amy",
 
1276
            self.applyDeprecated(deprecated_in((2, 5, 0)),
 
1277
                my_config.acceptable_keys))
1300
1278
 
1301
1279
    def test_configured_validate_signatures_in_log(self):
1302
1280
        my_config = self._get_sample_config()
1395
1373
 
1396
1374
class TestLocationConfig(tests.TestCaseInTempDir, TestOptionsMixin):
1397
1375
 
1398
 
    def test_constructs(self):
1399
 
        my_config = config.LocationConfig('http://example.com')
 
1376
    def test_constructs_valid(self):
 
1377
        config.LocationConfig('http://example.com')
 
1378
 
 
1379
    def test_constructs_error(self):
1400
1380
        self.assertRaises(TypeError, config.LocationConfig)
1401
1381
 
1402
1382
    def test_branch_calls_read_filenames(self):
1538
1518
        self.get_branch_config('http://www.example.com',
1539
1519
                                 global_config=sample_ignore_signatures)
1540
1520
        self.assertEqual(config.CHECK_ALWAYS,
1541
 
                         self.my_config.signature_checking())
 
1521
                         self.applyDeprecated(deprecated_in((2, 5, 0)),
 
1522
                             self.my_config.signature_checking))
1542
1523
        self.assertEqual(config.SIGN_NEVER,
1543
 
                         self.my_config.signing_policy())
 
1524
                         self.applyDeprecated(deprecated_in((2, 5, 0)),
 
1525
                             self.my_config.signing_policy))
1544
1526
 
1545
1527
    def test_signatures_never(self):
1546
1528
        self.get_branch_config('/a/c')
1547
1529
        self.assertEqual(config.CHECK_NEVER,
1548
 
                         self.my_config.signature_checking())
 
1530
                         self.applyDeprecated(deprecated_in((2, 5, 0)),
 
1531
                             self.my_config.signature_checking))
1549
1532
 
1550
1533
    def test_signatures_when_available(self):
1551
1534
        self.get_branch_config('/a/', global_config=sample_ignore_signatures)
1552
1535
        self.assertEqual(config.CHECK_IF_POSSIBLE,
1553
 
                         self.my_config.signature_checking())
 
1536
                         self.applyDeprecated(deprecated_in((2, 5, 0)),
 
1537
                             self.my_config.signature_checking))
1554
1538
 
1555
1539
    def test_signatures_always(self):
1556
1540
        self.get_branch_config('/b')
1557
1541
        self.assertEqual(config.CHECK_ALWAYS,
1558
 
                         self.my_config.signature_checking())
 
1542
            self.applyDeprecated(deprecated_in((2, 5, 0)),
 
1543
                         self.my_config.signature_checking))
1559
1544
 
1560
1545
    def test_gpg_signing_command(self):
1561
1546
        self.get_branch_config('/b')
1562
 
        self.assertEqual("gnome-gpg", self.my_config.gpg_signing_command())
 
1547
        self.assertEqual("gnome-gpg",
 
1548
            self.applyDeprecated(deprecated_in((2, 5, 0)),
 
1549
                self.my_config.gpg_signing_command))
1563
1550
 
1564
1551
    def test_gpg_signing_command_missing(self):
1565
1552
        self.get_branch_config('/a')
1566
 
        self.assertEqual("false", self.my_config.gpg_signing_command())
 
1553
        self.assertEqual("false",
 
1554
            self.applyDeprecated(deprecated_in((2, 5, 0)),
 
1555
                self.my_config.gpg_signing_command))
1567
1556
 
1568
1557
    def test_gpg_signing_key(self):
1569
1558
        self.get_branch_config('/b')
1570
 
        self.assertEqual("DD4D5088", self.my_config.gpg_signing_key())
 
1559
        self.assertEqual("DD4D5088", self.applyDeprecated(deprecated_in((2, 5, 0)),
 
1560
            self.my_config.gpg_signing_key))
1571
1561
 
1572
1562
    def test_gpg_signing_key_default(self):
1573
1563
        self.get_branch_config('/a')
1574
 
        self.assertEqual("erik@bagfors.nu", self.my_config.gpg_signing_key())
 
1564
        self.assertEqual("erik@bagfors.nu",
 
1565
            self.applyDeprecated(deprecated_in((2, 5, 0)),
 
1566
                self.my_config.gpg_signing_key))
1575
1567
 
1576
1568
    def test_get_user_option_global(self):
1577
1569
        self.get_branch_config('/a')
1665
1657
    def test_post_commit_default(self):
1666
1658
        self.get_branch_config('/a/c')
1667
1659
        self.assertEqual('bzrlib.tests.test_config.post_commit',
1668
 
                         self.my_config.post_commit())
 
1660
                         self.applyDeprecated(deprecated_in((2, 5, 0)),
 
1661
                                              self.my_config.post_commit))
1669
1662
 
1670
1663
    def get_branch_config(self, location, global_config=None,
1671
1664
                          location_config=None):
1675
1668
        if location_config is None:
1676
1669
            location_config = sample_branches_text
1677
1670
 
1678
 
        my_global_config = config.GlobalConfig.from_string(global_config,
1679
 
                                                           save=True)
1680
 
        my_location_config = config.LocationConfig.from_string(
1681
 
            location_config, my_branch.base, save=True)
 
1671
        config.GlobalConfig.from_string(global_config, save=True)
 
1672
        config.LocationConfig.from_string(location_config, my_branch.base,
 
1673
                                          save=True)
1682
1674
        my_config = config.BranchConfig(my_branch)
1683
1675
        self.my_config = my_config
1684
1676
        self.my_location_config = my_config._get_location_config()
1749
1741
                          location_config=None, branch_data_config=None):
1750
1742
        my_branch = FakeBranch(location)
1751
1743
        if global_config is not None:
1752
 
            my_global_config = config.GlobalConfig.from_string(global_config,
1753
 
                                                               save=True)
 
1744
            config.GlobalConfig.from_string(global_config, save=True)
1754
1745
        if location_config is not None:
1755
 
            my_location_config = config.LocationConfig.from_string(
1756
 
                location_config, my_branch.base, save=True)
 
1746
            config.LocationConfig.from_string(location_config, my_branch.base,
 
1747
                                              save=True)
1757
1748
        my_config = config.BranchConfig(my_branch)
1758
1749
        if branch_data_config is not None:
1759
1750
            my_config.branch.control_files.files['branch.conf'] = \
1761
1752
        return my_config
1762
1753
 
1763
1754
    def test_user_id(self):
1764
 
        branch = FakeBranch(user_id='Robert Collins <robertc@example.net>')
 
1755
        branch = FakeBranch()
1765
1756
        my_config = config.BranchConfig(branch)
1766
 
        self.assertEqual("Robert Collins <robertc@example.net>",
1767
 
                         my_config.username())
 
1757
        self.assertIsNot(None, my_config.username())
1768
1758
        my_config.branch.control_files.files['email'] = "John"
1769
1759
        my_config.set_user_option('email',
1770
1760
                                  "Robert Collins <robertc@example.org>")
1771
 
        self.assertEqual("John", my_config.username())
1772
 
        del my_config.branch.control_files.files['email']
1773
1761
        self.assertEqual("Robert Collins <robertc@example.org>",
1774
 
                         my_config.username())
1775
 
 
1776
 
    def test_not_set_in_branch(self):
1777
 
        my_config = self.get_branch_config(global_config=sample_config_text)
1778
 
        self.assertEqual(u"Erik B\u00e5gfors <erik@bagfors.nu>",
1779
 
                         my_config._get_user_id())
1780
 
        my_config.branch.control_files.files['email'] = "John"
1781
 
        self.assertEqual("John", my_config._get_user_id())
 
1762
                        my_config.username())
1782
1763
 
1783
1764
    def test_BZR_EMAIL_OVERRIDES(self):
1784
1765
        self.overrideEnv('BZR_EMAIL', "Robert Collins <robertc@example.org>")
1790
1771
    def test_signatures_forced(self):
1791
1772
        my_config = self.get_branch_config(
1792
1773
            global_config=sample_always_signatures)
1793
 
        self.assertEqual(config.CHECK_NEVER, my_config.signature_checking())
1794
 
        self.assertEqual(config.SIGN_ALWAYS, my_config.signing_policy())
1795
 
        self.assertTrue(my_config.signature_needed())
 
1774
        self.assertEqual(config.CHECK_NEVER,
 
1775
            self.applyDeprecated(deprecated_in((2, 5, 0)),
 
1776
                my_config.signature_checking))
 
1777
        self.assertEqual(config.SIGN_ALWAYS,
 
1778
            self.applyDeprecated(deprecated_in((2, 5, 0)),
 
1779
                my_config.signing_policy))
 
1780
        self.assertTrue(self.applyDeprecated(deprecated_in((2, 5, 0)),
 
1781
            my_config.signature_needed))
1796
1782
 
1797
1783
    def test_signatures_forced_branch(self):
1798
1784
        my_config = self.get_branch_config(
1799
1785
            global_config=sample_ignore_signatures,
1800
1786
            branch_data_config=sample_always_signatures)
1801
 
        self.assertEqual(config.CHECK_NEVER, my_config.signature_checking())
1802
 
        self.assertEqual(config.SIGN_ALWAYS, my_config.signing_policy())
1803
 
        self.assertTrue(my_config.signature_needed())
 
1787
        self.assertEqual(config.CHECK_NEVER,
 
1788
            self.applyDeprecated(deprecated_in((2, 5, 0)),
 
1789
                my_config.signature_checking))
 
1790
        self.assertEqual(config.SIGN_ALWAYS,
 
1791
            self.applyDeprecated(deprecated_in((2, 5, 0)),
 
1792
                my_config.signing_policy))
 
1793
        self.assertTrue(self.applyDeprecated(deprecated_in((2, 5, 0)),
 
1794
            my_config.signature_needed))
1804
1795
 
1805
1796
    def test_gpg_signing_command(self):
1806
1797
        my_config = self.get_branch_config(
1807
1798
            global_config=sample_config_text,
1808
1799
            # branch data cannot set gpg_signing_command
1809
1800
            branch_data_config="gpg_signing_command=pgp")
1810
 
        self.assertEqual('gnome-gpg', my_config.gpg_signing_command())
 
1801
        self.assertEqual('gnome-gpg',
 
1802
            self.applyDeprecated(deprecated_in((2, 5, 0)),
 
1803
                my_config.gpg_signing_command))
1811
1804
 
1812
1805
    def test_get_user_option_global(self):
1813
1806
        my_config = self.get_branch_config(global_config=sample_config_text)
1820
1813
                                      location_config=sample_branches_text)
1821
1814
        self.assertEqual(my_config.branch.base, '/a/c')
1822
1815
        self.assertEqual('bzrlib.tests.test_config.post_commit',
1823
 
                         my_config.post_commit())
 
1816
                         self.applyDeprecated(deprecated_in((2, 5, 0)),
 
1817
                                              my_config.post_commit))
1824
1818
        my_config.set_user_option('post_commit', 'rmtree_root')
1825
1819
        # post-commit is ignored when present in branch data
1826
1820
        self.assertEqual('bzrlib.tests.test_config.post_commit',
1827
 
                         my_config.post_commit())
 
1821
                         self.applyDeprecated(deprecated_in((2, 5, 0)),
 
1822
                                              my_config.post_commit))
1828
1823
        my_config.set_user_option('post_commit', 'rmtree_root',
1829
1824
                                  store=config.STORE_LOCATION)
1830
 
        self.assertEqual('rmtree_root', my_config.post_commit())
 
1825
        self.assertEqual('rmtree_root',
 
1826
                         self.applyDeprecated(deprecated_in((2, 5, 0)),
 
1827
                                              my_config.post_commit))
1831
1828
 
1832
1829
    def test_config_precedence(self):
1833
1830
        # FIXME: eager test, luckily no persitent config file makes it fail
1849
1846
            location='http://example.com/specific')
1850
1847
        self.assertEqual(my_config.get_user_option('option'), 'exact')
1851
1848
 
1852
 
    def test_get_mail_client(self):
1853
 
        config = self.get_branch_config()
1854
 
        client = config.get_mail_client()
1855
 
        self.assertIsInstance(client, mail_client.DefaultMail)
1856
 
 
1857
 
        # Specific clients
1858
 
        config.set_user_option('mail_client', 'evolution')
1859
 
        client = config.get_mail_client()
1860
 
        self.assertIsInstance(client, mail_client.Evolution)
1861
 
 
1862
 
        config.set_user_option('mail_client', 'kmail')
1863
 
        client = config.get_mail_client()
1864
 
        self.assertIsInstance(client, mail_client.KMail)
1865
 
 
1866
 
        config.set_user_option('mail_client', 'mutt')
1867
 
        client = config.get_mail_client()
1868
 
        self.assertIsInstance(client, mail_client.Mutt)
1869
 
 
1870
 
        config.set_user_option('mail_client', 'thunderbird')
1871
 
        client = config.get_mail_client()
1872
 
        self.assertIsInstance(client, mail_client.Thunderbird)
1873
 
 
1874
 
        # Generic options
1875
 
        config.set_user_option('mail_client', 'default')
1876
 
        client = config.get_mail_client()
1877
 
        self.assertIsInstance(client, mail_client.DefaultMail)
1878
 
 
1879
 
        config.set_user_option('mail_client', 'editor')
1880
 
        client = config.get_mail_client()
1881
 
        self.assertIsInstance(client, mail_client.Editor)
1882
 
 
1883
 
        config.set_user_option('mail_client', 'mapi')
1884
 
        client = config.get_mail_client()
1885
 
        self.assertIsInstance(client, mail_client.MAPIClient)
1886
 
 
1887
 
        config.set_user_option('mail_client', 'xdg-email')
1888
 
        client = config.get_mail_client()
1889
 
        self.assertIsInstance(client, mail_client.XDGEmail)
1890
 
 
1891
 
        config.set_user_option('mail_client', 'firebird')
1892
 
        self.assertRaises(errors.UnknownMailClient, config.get_mail_client)
1893
 
 
1894
1849
 
1895
1850
class TestMailAddressExtraction(tests.TestCase):
1896
1851
 
2183
2138
        self.assertGetHook(remote_branch._get_config(), 'file', 'branch')
2184
2139
 
2185
2140
    def test_get_hook_remote_bzrdir(self):
2186
 
        remote_bzrdir = bzrdir.BzrDir.open(self.get_url('tree'))
 
2141
        remote_bzrdir = controldir.ControlDir.open(self.get_url('tree'))
2187
2142
        conf = remote_bzrdir._get_config()
2188
2143
        conf.set_option('remotedir', 'file')
2189
2144
        self.assertGetHook(conf, 'file', 'remotedir')
2211
2166
    def test_set_hook_remote_bzrdir(self):
2212
2167
        remote_branch = branch.Branch.open(self.get_url('tree'))
2213
2168
        self.addCleanup(remote_branch.lock_write().unlock)
2214
 
        remote_bzrdir = bzrdir.BzrDir.open(self.get_url('tree'))
 
2169
        remote_bzrdir = controldir.ControlDir.open(self.get_url('tree'))
2215
2170
        self.assertSetHook(remote_bzrdir._get_config(), 'file', 'remotedir')
2216
2171
 
2217
2172
    def assertLoadHook(self, expected_nb_calls, name, conf_class, *conf_args):
2234
2189
        self.assertLoadHook(1, 'file', remote.RemoteBranchConfig, remote_branch)
2235
2190
 
2236
2191
    def test_load_hook_remote_bzrdir(self):
2237
 
        remote_bzrdir = bzrdir.BzrDir.open(self.get_url('tree'))
 
2192
        remote_bzrdir = controldir.ControlDir.open(self.get_url('tree'))
2238
2193
        # The config file doesn't exist, set an option to force its creation
2239
2194
        conf = remote_bzrdir._get_config()
2240
2195
        conf.set_option('remotedir', 'file')
2265
2220
    def test_save_hook_remote_bzrdir(self):
2266
2221
        remote_branch = branch.Branch.open(self.get_url('tree'))
2267
2222
        self.addCleanup(remote_branch.lock_write().unlock)
2268
 
        remote_bzrdir = bzrdir.BzrDir.open(self.get_url('tree'))
 
2223
        remote_bzrdir = controldir.ControlDir.open(self.get_url('tree'))
2269
2224
        self.assertSaveHook(remote_bzrdir._get_config())
2270
2225
 
2271
2226
 
 
2227
class TestOptionNames(tests.TestCase):
 
2228
 
 
2229
    def is_valid(self, name):
 
2230
        return config._option_ref_re.match('{%s}' % name) is not None
 
2231
 
 
2232
    def test_valid_names(self):
 
2233
        self.assertTrue(self.is_valid('foo'))
 
2234
        self.assertTrue(self.is_valid('foo.bar'))
 
2235
        self.assertTrue(self.is_valid('f1'))
 
2236
        self.assertTrue(self.is_valid('_'))
 
2237
        self.assertTrue(self.is_valid('__bar__'))
 
2238
        self.assertTrue(self.is_valid('a_'))
 
2239
        self.assertTrue(self.is_valid('a1'))
 
2240
 
 
2241
    def test_invalid_names(self):
 
2242
        self.assertFalse(self.is_valid(' foo'))
 
2243
        self.assertFalse(self.is_valid('foo '))
 
2244
        self.assertFalse(self.is_valid('1'))
 
2245
        self.assertFalse(self.is_valid('1,2'))
 
2246
        self.assertFalse(self.is_valid('foo$'))
 
2247
        self.assertFalse(self.is_valid('!foo'))
 
2248
        self.assertFalse(self.is_valid('foo.'))
 
2249
        self.assertFalse(self.is_valid('foo..bar'))
 
2250
        self.assertFalse(self.is_valid('{}'))
 
2251
        self.assertFalse(self.is_valid('{a}'))
 
2252
        self.assertFalse(self.is_valid('a\n'))
 
2253
 
 
2254
    def assertSingleGroup(self, reference):
 
2255
        # the regexp is used with split and as such should match the reference
 
2256
        # *only*, if more groups needs to be defined, (?:...) should be used.
 
2257
        m = config._option_ref_re.match('{a}')
 
2258
        self.assertLength(1, m.groups())
 
2259
 
 
2260
    def test_valid_references(self):
 
2261
        self.assertSingleGroup('{a}')
 
2262
        self.assertSingleGroup('{{a}}')
 
2263
 
 
2264
 
2272
2265
class TestOption(tests.TestCase):
2273
2266
 
2274
2267
    def test_default_value(self):
2275
2268
        opt = config.Option('foo', default='bar')
2276
2269
        self.assertEquals('bar', opt.get_default())
2277
2270
 
 
2271
    def test_callable_default_value(self):
 
2272
        def bar_as_unicode():
 
2273
            return u'bar'
 
2274
        opt = config.Option('foo', default=bar_as_unicode)
 
2275
        self.assertEquals('bar', opt.get_default())
 
2276
 
2278
2277
    def test_default_value_from_env(self):
2279
2278
        opt = config.Option('foo', default='bar', default_from_env=['FOO'])
2280
2279
        self.overrideEnv('FOO', 'quux')
2296
2295
        self.assertRaises(AssertionError, config.Option, 'foo',
2297
2296
                          default=object())
2298
2297
 
2299
 
 
2300
 
class TestOptionConverterMixin(object):
2301
 
 
2302
 
    def assertConverted(self, expected, opt, value):
2303
 
        self.assertEquals(expected, opt.convert_from_unicode(value))
2304
 
 
2305
 
    def assertWarns(self, opt, value):
2306
 
        warnings = []
2307
 
        def warning(*args):
2308
 
            warnings.append(args[0] % args[1:])
2309
 
        self.overrideAttr(trace, 'warning', warning)
2310
 
        self.assertEquals(None, opt.convert_from_unicode(value))
2311
 
        self.assertLength(1, warnings)
2312
 
        self.assertEquals(
2313
 
            'Value "%s" is not valid for "%s"' % (value, opt.name),
2314
 
            warnings[0])
2315
 
 
2316
 
    def assertErrors(self, opt, value):
2317
 
        self.assertRaises(errors.ConfigOptionValueError,
2318
 
                          opt.convert_from_unicode, value)
2319
 
 
2320
 
    def assertConvertInvalid(self, opt, invalid_value):
2321
 
        opt.invalid = None
2322
 
        self.assertEquals(None, opt.convert_from_unicode(invalid_value))
2323
 
        opt.invalid = 'warning'
2324
 
        self.assertWarns(opt, invalid_value)
2325
 
        opt.invalid = 'error'
2326
 
        self.assertErrors(opt, invalid_value)
2327
 
 
2328
 
 
2329
 
class TestOptionWithBooleanConverter(tests.TestCase, TestOptionConverterMixin):
2330
 
 
2331
 
    def get_option(self):
2332
 
        return config.Option('foo', help='A boolean.',
2333
 
                             from_unicode=config.bool_from_store)
2334
 
 
2335
 
    def test_convert_invalid(self):
2336
 
        opt = self.get_option()
2337
 
        # A string that is not recognized as a boolean
2338
 
        self.assertConvertInvalid(opt, u'invalid-boolean')
2339
 
        # A list of strings is never recognized as a boolean
2340
 
        self.assertConvertInvalid(opt, [u'not', u'a', u'boolean'])
2341
 
 
2342
 
    def test_convert_valid(self):
2343
 
        opt = self.get_option()
2344
 
        self.assertConverted(True, opt, u'True')
2345
 
        self.assertConverted(True, opt, u'1')
2346
 
        self.assertConverted(False, opt, u'False')
2347
 
 
2348
 
 
2349
 
class TestOptionWithIntegerConverter(tests.TestCase, TestOptionConverterMixin):
2350
 
 
2351
 
    def get_option(self):
2352
 
        return config.Option('foo', help='An integer.',
2353
 
                             from_unicode=config.int_from_store)
2354
 
 
2355
 
    def test_convert_invalid(self):
2356
 
        opt = self.get_option()
2357
 
        # A string that is not recognized as an integer
2358
 
        self.assertConvertInvalid(opt, u'forty-two')
2359
 
        # A list of strings is never recognized as an integer
2360
 
        self.assertConvertInvalid(opt, [u'a', u'list'])
2361
 
 
2362
 
    def test_convert_valid(self):
2363
 
        opt = self.get_option()
2364
 
        self.assertConverted(16, opt, u'16')
2365
 
 
2366
 
class TestOptionWithListConverter(tests.TestCase, TestOptionConverterMixin):
2367
 
 
2368
 
    def get_option(self):
2369
 
        return config.Option('foo', help='A list.',
2370
 
                             from_unicode=config.list_from_store)
2371
 
 
2372
 
    def test_convert_invalid(self):
2373
 
        # No string is invalid as all forms can be converted to a list
2374
 
        pass
2375
 
 
2376
 
    def test_convert_valid(self):
2377
 
        opt = self.get_option()
2378
 
        # An empty string is an empty list
2379
 
        self.assertConverted([], opt, '') # Using a bare str() just in case
2380
 
        self.assertConverted([], opt, u'')
2381
 
        # A boolean
2382
 
        self.assertConverted([u'True'], opt, u'True')
2383
 
        # An integer
2384
 
        self.assertConverted([u'42'], opt, u'42')
2385
 
        # A single string
2386
 
        self.assertConverted([u'bar'], opt, u'bar')
2387
 
        # A list remains a list (configObj will turn a string containing commas
2388
 
        # into a list, but that's not what we're testing here)
2389
 
        self.assertConverted([u'foo', u'1', u'True'],
2390
 
                             opt, [u'foo', u'1', u'True'])
2391
 
 
2392
 
 
2393
 
class TestOptionConverterMixin(object):
2394
 
 
2395
 
    def assertConverted(self, expected, opt, value):
2396
 
        self.assertEquals(expected, opt.convert_from_unicode(value))
2397
 
 
2398
 
    def assertWarns(self, opt, value):
2399
 
        warnings = []
2400
 
        def warning(*args):
2401
 
            warnings.append(args[0] % args[1:])
2402
 
        self.overrideAttr(trace, 'warning', warning)
2403
 
        self.assertEquals(None, opt.convert_from_unicode(value))
2404
 
        self.assertLength(1, warnings)
2405
 
        self.assertEquals(
2406
 
            'Value "%s" is not valid for "%s"' % (value, opt.name),
2407
 
            warnings[0])
2408
 
 
2409
 
    def assertErrors(self, opt, value):
2410
 
        self.assertRaises(errors.ConfigOptionValueError,
2411
 
                          opt.convert_from_unicode, value)
2412
 
 
2413
 
    def assertConvertInvalid(self, opt, invalid_value):
2414
 
        opt.invalid = None
2415
 
        self.assertEquals(None, opt.convert_from_unicode(invalid_value))
2416
 
        opt.invalid = 'warning'
2417
 
        self.assertWarns(opt, invalid_value)
2418
 
        opt.invalid = 'error'
2419
 
        self.assertErrors(opt, invalid_value)
2420
 
 
2421
 
 
2422
 
class TestOptionWithBooleanConverter(tests.TestCase, TestOptionConverterMixin):
2423
 
 
2424
 
    def get_option(self):
2425
 
        return config.Option('foo', help='A boolean.',
2426
 
                             from_unicode=config.bool_from_store)
2427
 
 
2428
 
    def test_convert_invalid(self):
2429
 
        opt = self.get_option()
2430
 
        # A string that is not recognized as a boolean
2431
 
        self.assertConvertInvalid(opt, u'invalid-boolean')
2432
 
        # A list of strings is never recognized as a boolean
2433
 
        self.assertConvertInvalid(opt, [u'not', u'a', u'boolean'])
2434
 
 
2435
 
    def test_convert_valid(self):
2436
 
        opt = self.get_option()
2437
 
        self.assertConverted(True, opt, u'True')
2438
 
        self.assertConverted(True, opt, u'1')
2439
 
        self.assertConverted(False, opt, u'False')
2440
 
 
2441
 
 
2442
 
class TestOptionWithIntegerConverter(tests.TestCase, TestOptionConverterMixin):
2443
 
 
2444
 
    def get_option(self):
2445
 
        return config.Option('foo', help='An integer.',
2446
 
                             from_unicode=config.int_from_store)
2447
 
 
2448
 
    def test_convert_invalid(self):
2449
 
        opt = self.get_option()
2450
 
        # A string that is not recognized as an integer
2451
 
        self.assertConvertInvalid(opt, u'forty-two')
2452
 
        # A list of strings is never recognized as an integer
2453
 
        self.assertConvertInvalid(opt, [u'a', u'list'])
2454
 
 
2455
 
    def test_convert_valid(self):
2456
 
        opt = self.get_option()
2457
 
        self.assertConverted(16, opt, u'16')
2458
 
 
2459
 
 
2460
 
class TestOptionWithListConverter(tests.TestCase, TestOptionConverterMixin):
2461
 
 
2462
 
    def get_option(self):
2463
 
        return config.Option('foo', help='A list.',
2464
 
                             from_unicode=config.list_from_store)
 
2298
    def test_not_supported_callable_default_value_not_unicode(self):
 
2299
        def bar_not_unicode():
 
2300
            return 'bar'
 
2301
        opt = config.Option('foo', default=bar_not_unicode)
 
2302
        self.assertRaises(AssertionError, opt.get_default)
 
2303
 
 
2304
    def test_get_help_topic(self):
 
2305
        opt = config.Option('foo')
 
2306
        self.assertEquals('foo', opt.get_help_topic())
 
2307
 
 
2308
 
 
2309
class TestOptionConverterMixin(object):
 
2310
 
 
2311
    def assertConverted(self, expected, opt, value):
 
2312
        self.assertEquals(expected, opt.convert_from_unicode(None, value))
 
2313
 
 
2314
    def assertWarns(self, opt, value):
 
2315
        warnings = []
 
2316
        def warning(*args):
 
2317
            warnings.append(args[0] % args[1:])
 
2318
        self.overrideAttr(trace, 'warning', warning)
 
2319
        self.assertEquals(None, opt.convert_from_unicode(None, value))
 
2320
        self.assertLength(1, warnings)
 
2321
        self.assertEquals(
 
2322
            'Value "%s" is not valid for "%s"' % (value, opt.name),
 
2323
            warnings[0])
 
2324
 
 
2325
    def assertErrors(self, opt, value):
 
2326
        self.assertRaises(errors.ConfigOptionValueError,
 
2327
                          opt.convert_from_unicode, None, value)
 
2328
 
 
2329
    def assertConvertInvalid(self, opt, invalid_value):
 
2330
        opt.invalid = None
 
2331
        self.assertEquals(None, opt.convert_from_unicode(None, invalid_value))
 
2332
        opt.invalid = 'warning'
 
2333
        self.assertWarns(opt, invalid_value)
 
2334
        opt.invalid = 'error'
 
2335
        self.assertErrors(opt, invalid_value)
 
2336
 
 
2337
 
 
2338
class TestOptionWithBooleanConverter(tests.TestCase, TestOptionConverterMixin):
 
2339
 
 
2340
    def get_option(self):
 
2341
        return config.Option('foo', help='A boolean.',
 
2342
                             from_unicode=config.bool_from_store)
 
2343
 
 
2344
    def test_convert_invalid(self):
 
2345
        opt = self.get_option()
 
2346
        # A string that is not recognized as a boolean
 
2347
        self.assertConvertInvalid(opt, u'invalid-boolean')
 
2348
        # A list of strings is never recognized as a boolean
 
2349
        self.assertConvertInvalid(opt, [u'not', u'a', u'boolean'])
 
2350
 
 
2351
    def test_convert_valid(self):
 
2352
        opt = self.get_option()
 
2353
        self.assertConverted(True, opt, u'True')
 
2354
        self.assertConverted(True, opt, u'1')
 
2355
        self.assertConverted(False, opt, u'False')
 
2356
 
 
2357
 
 
2358
class TestOptionWithIntegerConverter(tests.TestCase, TestOptionConverterMixin):
 
2359
 
 
2360
    def get_option(self):
 
2361
        return config.Option('foo', help='An integer.',
 
2362
                             from_unicode=config.int_from_store)
 
2363
 
 
2364
    def test_convert_invalid(self):
 
2365
        opt = self.get_option()
 
2366
        # A string that is not recognized as an integer
 
2367
        self.assertConvertInvalid(opt, u'forty-two')
 
2368
        # A list of strings is never recognized as an integer
 
2369
        self.assertConvertInvalid(opt, [u'a', u'list'])
 
2370
 
 
2371
    def test_convert_valid(self):
 
2372
        opt = self.get_option()
 
2373
        self.assertConverted(16, opt, u'16')
 
2374
 
 
2375
 
 
2376
class TestOptionWithSIUnitConverter(tests.TestCase, TestOptionConverterMixin):
 
2377
 
 
2378
    def get_option(self):
 
2379
        return config.Option('foo', help='An integer in SI units.',
 
2380
                             from_unicode=config.int_SI_from_store)
 
2381
 
 
2382
    def test_convert_invalid(self):
 
2383
        opt = self.get_option()
 
2384
        self.assertConvertInvalid(opt, u'not-a-unit')
 
2385
        self.assertConvertInvalid(opt, u'Gb') # Forgot the int
 
2386
        self.assertConvertInvalid(opt, u'1b') # Forgot the unit
 
2387
        self.assertConvertInvalid(opt, u'1GG')
 
2388
        self.assertConvertInvalid(opt, u'1Mbb')
 
2389
        self.assertConvertInvalid(opt, u'1MM')
 
2390
 
 
2391
    def test_convert_valid(self):
 
2392
        opt = self.get_option()
 
2393
        self.assertConverted(int(5e3), opt, u'5kb')
 
2394
        self.assertConverted(int(5e6), opt, u'5M')
 
2395
        self.assertConverted(int(5e6), opt, u'5MB')
 
2396
        self.assertConverted(int(5e9), opt, u'5g')
 
2397
        self.assertConverted(int(5e9), opt, u'5gB')
 
2398
        self.assertConverted(100, opt, u'100')
 
2399
 
 
2400
 
 
2401
class TestListOption(tests.TestCase, TestOptionConverterMixin):
 
2402
 
 
2403
    def get_option(self):
 
2404
        return config.ListOption('foo', help='A list.')
2465
2405
 
2466
2406
    def test_convert_invalid(self):
2467
2407
        opt = self.get_option()
2483
2423
        self.assertConverted([u'bar'], opt, u'bar')
2484
2424
 
2485
2425
 
 
2426
class TestRegistryOption(tests.TestCase, TestOptionConverterMixin):
 
2427
 
 
2428
    def get_option(self, registry):
 
2429
        return config.RegistryOption('foo', registry,
 
2430
                help='A registry option.')
 
2431
 
 
2432
    def test_convert_invalid(self):
 
2433
        registry = _mod_registry.Registry()
 
2434
        opt = self.get_option(registry)
 
2435
        self.assertConvertInvalid(opt, [1])
 
2436
        self.assertConvertInvalid(opt, u"notregistered")
 
2437
 
 
2438
    def test_convert_valid(self):
 
2439
        registry = _mod_registry.Registry()
 
2440
        registry.register("someval", 1234)
 
2441
        opt = self.get_option(registry)
 
2442
        # Using a bare str() just in case
 
2443
        self.assertConverted(1234, opt, "someval")
 
2444
        self.assertConverted(1234, opt, u'someval')
 
2445
        self.assertConverted(None, opt, None)
 
2446
 
 
2447
    def test_help(self):
 
2448
        registry = _mod_registry.Registry()
 
2449
        registry.register("someval", 1234, help="some option")
 
2450
        registry.register("dunno", 1234, help="some other option")
 
2451
        opt = self.get_option(registry)
 
2452
        self.assertEquals(
 
2453
            'A registry option.\n'
 
2454
            '\n'
 
2455
            'The following values are supported:\n'
 
2456
            ' dunno - some other option\n'
 
2457
            ' someval - some option\n',
 
2458
            opt.help)
 
2459
 
 
2460
    def test_get_help_text(self):
 
2461
        registry = _mod_registry.Registry()
 
2462
        registry.register("someval", 1234, help="some option")
 
2463
        registry.register("dunno", 1234, help="some other option")
 
2464
        opt = self.get_option(registry)
 
2465
        self.assertEquals(
 
2466
            'A registry option.\n'
 
2467
            '\n'
 
2468
            'The following values are supported:\n'
 
2469
            ' dunno - some other option\n'
 
2470
            ' someval - some option\n',
 
2471
            opt.get_help_text())
 
2472
 
 
2473
 
2486
2474
class TestOptionRegistry(tests.TestCase):
2487
2475
 
2488
2476
    def setUp(self):
2501
2489
        self.registry.register(opt)
2502
2490
        self.assertEquals('A simple option', self.registry.get_help('foo'))
2503
2491
 
 
2492
    def test_dont_register_illegal_name(self):
 
2493
        self.assertRaises(errors.IllegalOptionName,
 
2494
                          self.registry.register, config.Option(' foo'))
 
2495
        self.assertRaises(errors.IllegalOptionName,
 
2496
                          self.registry.register, config.Option('bar,'))
 
2497
 
2504
2498
    lazy_option = config.Option('lazy_foo', help='Lazy help')
2505
2499
 
2506
2500
    def test_register_lazy(self):
2513
2507
                                    'TestOptionRegistry.lazy_option')
2514
2508
        self.assertEquals('Lazy help', self.registry.get_help('lazy_foo'))
2515
2509
 
 
2510
    def test_dont_lazy_register_illegal_name(self):
 
2511
        # This is where the root cause of http://pad.lv/1235099 is better
 
2512
        # understood: 'register_lazy' doc string mentions that key should match
 
2513
        # the option name which indirectly requires that the option name is a
 
2514
        # valid python identifier. We violate that rule here (using a key that
 
2515
        # doesn't match the option name) to test the option name checking.
 
2516
        self.assertRaises(errors.IllegalOptionName,
 
2517
                          self.registry.register_lazy, ' foo', self.__module__,
 
2518
                          'TestOptionRegistry.lazy_option')
 
2519
        self.assertRaises(errors.IllegalOptionName,
 
2520
                          self.registry.register_lazy, '1,2', self.__module__,
 
2521
                          'TestOptionRegistry.lazy_option')
 
2522
 
2516
2523
 
2517
2524
class TestRegisteredOptions(tests.TestCase):
2518
2525
    """All registered options should verify some constraints."""
2531
2538
 
2532
2539
    def test_help_is_set(self):
2533
2540
        option_help = self.registry.get_help(self.option_name)
2534
 
        self.assertNotEquals(None, option_help)
2535
2541
        # Come on, think about the user, he really wants to know what the
2536
2542
        # option is about
2537
2543
        self.assertIsNot(None, option_help)
2617
2623
    def setUp(self):
2618
2624
        super(TestCommandLineStore, self).setUp()
2619
2625
        self.store = config.CommandLineStore()
 
2626
        self.overrideAttr(config, 'option_registry', config.OptionRegistry())
2620
2627
 
2621
2628
    def get_section(self):
2622
2629
        """Get the unique section for the command line overrides."""
2637
2644
        self.assertEqual('b', section.get('a'))
2638
2645
 
2639
2646
    def test_list_override(self):
 
2647
        opt = config.ListOption('l')
 
2648
        config.option_registry.register(opt)
2640
2649
        self.store._from_cmdline(['l=1,2,3'])
2641
2650
        val = self.get_section().get('l')
2642
2651
        self.assertEqual('1,2,3', val)
2643
2652
        # Reminder: lists should be registered as such explicitely, otherwise
2644
2653
        # the conversion needs to be done afterwards.
2645
 
        self.assertEqual(['1', '2', '3'], config.list_from_store(val))
 
2654
        self.assertEqual(['1', '2', '3'],
 
2655
                         opt.convert_from_unicode(self.store, val))
2646
2656
 
2647
2657
    def test_multiple_overrides(self):
2648
2658
        self.store._from_cmdline(['a=b', 'x=y'])
2654
2664
        self.assertRaises(errors.BzrCommandError,
2655
2665
                          self.store._from_cmdline, ['a=b', 'c'])
2656
2666
 
 
2667
class TestStoreMinimalAPI(tests.TestCaseWithTransport):
 
2668
 
 
2669
    scenarios = [(key, {'get_store': builder}) for key, builder
 
2670
                 in config.test_store_builder_registry.iteritems()] + [
 
2671
        ('cmdline', {'get_store': lambda test: config.CommandLineStore()})]
 
2672
 
 
2673
    def test_id(self):
 
2674
        store = self.get_store(self)
 
2675
        if type(store) == config.TransportIniFileStore:
 
2676
            raise tests.TestNotApplicable(
 
2677
                "%s is not a concrete Store implementation"
 
2678
                " so it doesn't need an id" % (store.__class__.__name__,))
 
2679
        self.assertIsNot(None, store.id)
 
2680
 
2657
2681
 
2658
2682
class TestStore(tests.TestCaseWithTransport):
2659
2683
 
2702
2726
        self.assertRaises(AssertionError, store._load_from_string, 'bar=baz')
2703
2727
 
2704
2728
 
 
2729
class TestStoreQuoting(TestStore):
 
2730
 
 
2731
    scenarios = [(key, {'get_store': builder}) for key, builder
 
2732
                 in config.test_store_builder_registry.iteritems()]
 
2733
 
 
2734
    def setUp(self):
 
2735
        super(TestStoreQuoting, self).setUp()
 
2736
        self.store = self.get_store(self)
 
2737
        # We need a loaded store but any content will do
 
2738
        self.store._load_from_string('')
 
2739
 
 
2740
    def assertIdempotent(self, s):
 
2741
        """Assert that quoting an unquoted string is a no-op and vice-versa.
 
2742
 
 
2743
        What matters here is that option values, as they appear in a store, can
 
2744
        be safely round-tripped out of the store and back.
 
2745
 
 
2746
        :param s: A string, quoted if required.
 
2747
        """
 
2748
        self.assertEquals(s, self.store.quote(self.store.unquote(s)))
 
2749
        self.assertEquals(s, self.store.unquote(self.store.quote(s)))
 
2750
 
 
2751
    def test_empty_string(self):
 
2752
        if isinstance(self.store, config.IniFileStore):
 
2753
            # configobj._quote doesn't handle empty values
 
2754
            self.assertRaises(AssertionError,
 
2755
                              self.assertIdempotent, '')
 
2756
        else:
 
2757
            self.assertIdempotent('')
 
2758
        # But quoted empty strings are ok
 
2759
        self.assertIdempotent('""')
 
2760
 
 
2761
    def test_embedded_spaces(self):
 
2762
        self.assertIdempotent('" a b c "')
 
2763
 
 
2764
    def test_embedded_commas(self):
 
2765
        self.assertIdempotent('" a , b c "')
 
2766
 
 
2767
    def test_simple_comma(self):
 
2768
        if isinstance(self.store, config.IniFileStore):
 
2769
            # configobj requires that lists are special-cased
 
2770
           self.assertRaises(AssertionError,
 
2771
                             self.assertIdempotent, ',')
 
2772
        else:
 
2773
            self.assertIdempotent(',')
 
2774
        # When a single comma is required, quoting is also required
 
2775
        self.assertIdempotent('","')
 
2776
 
 
2777
    def test_list(self):
 
2778
        if isinstance(self.store, config.IniFileStore):
 
2779
            # configobj requires that lists are special-cased
 
2780
            self.assertRaises(AssertionError,
 
2781
                              self.assertIdempotent, 'a,b')
 
2782
        else:
 
2783
            self.assertIdempotent('a,b')
 
2784
 
 
2785
 
 
2786
class TestDictFromStore(tests.TestCase):
 
2787
 
 
2788
    def test_unquote_not_string(self):
 
2789
        conf = config.MemoryStack('x=2\n[a_section]\na=1\n')
 
2790
        value = conf.get('a_section')
 
2791
        # Urgh, despite 'conf' asking for the no-name section, we get the
 
2792
        # content of another section as a dict o_O
 
2793
        self.assertEquals({'a': '1'}, value)
 
2794
        unquoted = conf.store.unquote(value)
 
2795
        # Which cannot be unquoted but shouldn't crash either (the use cases
 
2796
        # are getting the value or displaying it. In the later case, '%s' will
 
2797
        # do).
 
2798
        self.assertEquals({'a': '1'}, unquoted)
 
2799
        self.assertEquals("{u'a': u'1'}", '%s' % (unquoted,))
 
2800
 
 
2801
 
2705
2802
class TestIniFileStoreContent(tests.TestCaseWithTransport):
2706
2803
    """Simulate loading a config store with content of various encodings.
2707
2804
 
2823
2920
        store.save()
2824
2921
        self.assertEquals(False, self.has_store(store))
2825
2922
 
 
2923
    def test_mutable_section_shared(self):
 
2924
        store = self.get_store(self)
 
2925
        store._load_from_string('foo=bar\n')
 
2926
        # FIXME: There should be a better way than relying on the test
 
2927
        # parametrization to identify branch.conf -- vila 2011-0526
 
2928
        if self.store_id in ('branch', 'remote_branch'):
 
2929
            # branch stores requires write locked branches
 
2930
            self.addCleanup(store.branch.lock_write().unlock)
 
2931
        section1 = store.get_mutable_section(None)
 
2932
        section2 = store.get_mutable_section(None)
 
2933
        # If we get different sections, different callers won't share the
 
2934
        # modification
 
2935
        self.assertIs(section1, section2)
 
2936
 
2826
2937
    def test_save_emptied_succeeds(self):
2827
2938
        store = self.get_store(self)
2828
2939
        store._load_from_string('foo=bar\n')
 
2940
        # FIXME: There should be a better way than relying on the test
 
2941
        # parametrization to identify branch.conf -- vila 2011-0526
 
2942
        if self.store_id in ('branch', 'remote_branch'):
 
2943
            # branch stores requires write locked branches
 
2944
            self.addCleanup(store.branch.lock_write().unlock)
2829
2945
        section = store.get_mutable_section(None)
2830
2946
        section.remove('foo')
2831
2947
        store.save()
2852
2968
 
2853
2969
    def test_set_option_in_empty_store(self):
2854
2970
        store = self.get_store(self)
 
2971
        # FIXME: There should be a better way than relying on the test
 
2972
        # parametrization to identify branch.conf -- vila 2011-0526
 
2973
        if self.store_id in ('branch', 'remote_branch'):
 
2974
            # branch stores requires write locked branches
 
2975
            self.addCleanup(store.branch.lock_write().unlock)
2855
2976
        section = store.get_mutable_section(None)
2856
2977
        section.set('foo', 'bar')
2857
2978
        store.save()
2863
2984
    def test_set_option_in_default_section(self):
2864
2985
        store = self.get_store(self)
2865
2986
        store._load_from_string('')
 
2987
        # FIXME: There should be a better way than relying on the test
 
2988
        # parametrization to identify branch.conf -- vila 2011-0526
 
2989
        if self.store_id in ('branch', 'remote_branch'):
 
2990
            # branch stores requires write locked branches
 
2991
            self.addCleanup(store.branch.lock_write().unlock)
2866
2992
        section = store.get_mutable_section(None)
2867
2993
        section.set('foo', 'bar')
2868
2994
        store.save()
2874
3000
    def test_set_option_in_named_section(self):
2875
3001
        store = self.get_store(self)
2876
3002
        store._load_from_string('')
 
3003
        # FIXME: There should be a better way than relying on the test
 
3004
        # parametrization to identify branch.conf -- vila 2011-0526
 
3005
        if self.store_id in ('branch', 'remote_branch'):
 
3006
            # branch stores requires write locked branches
 
3007
            self.addCleanup(store.branch.lock_write().unlock)
2877
3008
        section = store.get_mutable_section('baz')
2878
3009
        section.set('foo', 'bar')
2879
3010
        store.save()
2883
3014
        self.assertSectionContent(('baz', {'foo': 'bar'}), sections[0])
2884
3015
 
2885
3016
    def test_load_hook(self):
2886
 
        # We first needs to ensure that the store exists
 
3017
        # First, we need to ensure that the store exists
2887
3018
        store = self.get_store(self)
 
3019
        # FIXME: There should be a better way than relying on the test
 
3020
        # parametrization to identify branch.conf -- vila 2011-0526
 
3021
        if self.store_id in ('branch', 'remote_branch'):
 
3022
            # branch stores requires write locked branches
 
3023
            self.addCleanup(store.branch.lock_write().unlock)
2888
3024
        section = store.get_mutable_section('baz')
2889
3025
        section.set('foo', 'bar')
2890
3026
        store.save()
2906
3042
        config.ConfigHooks.install_named_hook('save', hook, None)
2907
3043
        self.assertLength(0, calls)
2908
3044
        store = self.get_store(self)
 
3045
        # FIXME: There should be a better way than relying on the test
 
3046
        # parametrization to identify branch.conf -- vila 2011-0526
 
3047
        if self.store_id in ('branch', 'remote_branch'):
 
3048
            # branch stores requires write locked branches
 
3049
            self.addCleanup(store.branch.lock_write().unlock)
2909
3050
        section = store.get_mutable_section('baz')
2910
3051
        section.set('foo', 'bar')
2911
3052
        store.save()
2912
3053
        self.assertLength(1, calls)
2913
3054
        self.assertEquals((store,), calls[0])
2914
3055
 
 
3056
    def test_set_mark_dirty(self):
 
3057
        stack = config.MemoryStack('')
 
3058
        self.assertLength(0, stack.store.dirty_sections)
 
3059
        stack.set('foo', 'baz')
 
3060
        self.assertLength(1, stack.store.dirty_sections)
 
3061
        self.assertTrue(stack.store._need_saving())
 
3062
 
 
3063
    def test_remove_mark_dirty(self):
 
3064
        stack = config.MemoryStack('foo=bar')
 
3065
        self.assertLength(0, stack.store.dirty_sections)
 
3066
        stack.remove('foo')
 
3067
        self.assertLength(1, stack.store.dirty_sections)
 
3068
        self.assertTrue(stack.store._need_saving())
 
3069
 
 
3070
 
 
3071
class TestStoreSaveChanges(tests.TestCaseWithTransport):
 
3072
    """Tests that config changes are kept in memory and saved on-demand."""
 
3073
 
 
3074
    def setUp(self):
 
3075
        super(TestStoreSaveChanges, self).setUp()
 
3076
        self.transport = self.get_transport()
 
3077
        # Most of the tests involve two stores pointing to the same persistent
 
3078
        # storage to observe the effects of concurrent changes
 
3079
        self.st1 = config.TransportIniFileStore(self.transport, 'foo.conf')
 
3080
        self.st2 = config.TransportIniFileStore(self.transport, 'foo.conf')
 
3081
        self.warnings = []
 
3082
        def warning(*args):
 
3083
            self.warnings.append(args[0] % args[1:])
 
3084
        self.overrideAttr(trace, 'warning', warning)
 
3085
 
 
3086
    def has_store(self, store):
 
3087
        store_basename = urlutils.relative_url(self.transport.external_url(),
 
3088
                                               store.external_url())
 
3089
        return self.transport.has(store_basename)
 
3090
 
 
3091
    def get_stack(self, store):
 
3092
        # Any stack will do as long as it uses the right store, just a single
 
3093
        # no-name section is enough
 
3094
        return config.Stack([store.get_sections], store)
 
3095
 
 
3096
    def test_no_changes_no_save(self):
 
3097
        s = self.get_stack(self.st1)
 
3098
        s.store.save_changes()
 
3099
        self.assertEquals(False, self.has_store(self.st1))
 
3100
 
 
3101
    def test_unrelated_concurrent_update(self):
 
3102
        s1 = self.get_stack(self.st1)
 
3103
        s2 = self.get_stack(self.st2)
 
3104
        s1.set('foo', 'bar')
 
3105
        s2.set('baz', 'quux')
 
3106
        s1.store.save()
 
3107
        # Changes don't propagate magically
 
3108
        self.assertEquals(None, s1.get('baz'))
 
3109
        s2.store.save_changes()
 
3110
        self.assertEquals('quux', s2.get('baz'))
 
3111
        # Changes are acquired when saving
 
3112
        self.assertEquals('bar', s2.get('foo'))
 
3113
        # Since there is no overlap, no warnings are emitted
 
3114
        self.assertLength(0, self.warnings)
 
3115
 
 
3116
    def test_concurrent_update_modified(self):
 
3117
        s1 = self.get_stack(self.st1)
 
3118
        s2 = self.get_stack(self.st2)
 
3119
        s1.set('foo', 'bar')
 
3120
        s2.set('foo', 'baz')
 
3121
        s1.store.save()
 
3122
        # Last speaker wins
 
3123
        s2.store.save_changes()
 
3124
        self.assertEquals('baz', s2.get('foo'))
 
3125
        # But the user get a warning
 
3126
        self.assertLength(1, self.warnings)
 
3127
        warning = self.warnings[0]
 
3128
        self.assertStartsWith(warning, 'Option foo in section None')
 
3129
        self.assertEndsWith(warning, 'was changed from <CREATED> to bar.'
 
3130
                            ' The baz value will be saved.')
 
3131
 
 
3132
    def test_concurrent_deletion(self):
 
3133
        self.st1._load_from_string('foo=bar')
 
3134
        self.st1.save()
 
3135
        s1 = self.get_stack(self.st1)
 
3136
        s2 = self.get_stack(self.st2)
 
3137
        s1.remove('foo')
 
3138
        s2.remove('foo')
 
3139
        s1.store.save_changes()
 
3140
        # No warning yet
 
3141
        self.assertLength(0, self.warnings)
 
3142
        s2.store.save_changes()
 
3143
        # Now we get one
 
3144
        self.assertLength(1, self.warnings)
 
3145
        warning = self.warnings[0]
 
3146
        self.assertStartsWith(warning, 'Option foo in section None')
 
3147
        self.assertEndsWith(warning, 'was changed from bar to <CREATED>.'
 
3148
                            ' The <DELETED> value will be saved.')
 
3149
 
 
3150
 
 
3151
class TestQuotingIniFileStore(tests.TestCaseWithTransport):
 
3152
 
 
3153
    def get_store(self):
 
3154
        return config.TransportIniFileStore(self.get_transport(), 'foo.conf')
 
3155
 
 
3156
    def test_get_quoted_string(self):
 
3157
        store = self.get_store()
 
3158
        store._load_from_string('foo= " abc "')
 
3159
        stack = config.Stack([store.get_sections])
 
3160
        self.assertEquals(' abc ', stack.get('foo'))
 
3161
 
 
3162
    def test_set_quoted_string(self):
 
3163
        store = self.get_store()
 
3164
        stack = config.Stack([store.get_sections], store)
 
3165
        stack.set('foo', ' a b c ')
 
3166
        store.save()
 
3167
        self.assertFileEqual('foo = " a b c "' + os.linesep, 'foo.conf')
 
3168
 
2915
3169
 
2916
3170
class TestTransportIniFileStore(TestStore):
2917
3171
 
3127
3381
 
3128
3382
    def test_build_doesnt_load_store(self):
3129
3383
        store = self.get_store(self)
3130
 
        matcher = self.matcher(store, '/bar')
 
3384
        self.matcher(store, '/bar')
3131
3385
        self.assertFalse(store.is_loaded())
3132
3386
 
3133
3387
 
3135
3389
 
3136
3390
    def get_section(self, options, extra_path):
3137
3391
        section = config.Section('foo', options)
3138
 
        # We don't care about the length so we use '0'
3139
 
        return config.LocationSection(section, 0, extra_path)
 
3392
        return config.LocationSection(section, extra_path)
3140
3393
 
3141
3394
    def test_simple_option(self):
3142
3395
        section = self.get_section({'foo': 'bar'}, '')
3179
3432
                           '/quux/quux'],
3180
3433
                          [section.id for _, section in store.get_sections()])
3181
3434
        matcher = config.LocationMatcher(store, '/foo/bar/quux')
3182
 
        sections = [section for s, section in matcher.get_sections()]
3183
 
        self.assertEquals([3, 2],
3184
 
                          [section.length for section in sections])
 
3435
        sections = [section for _, section in matcher.get_sections()]
3185
3436
        self.assertEquals(['/foo/bar', '/foo'],
3186
3437
                          [section.id for section in sections])
3187
3438
        self.assertEquals(['quux', 'bar/quux'],
3198
3449
        self.assertEquals(['/foo', '/foo/bar'],
3199
3450
                          [section.id for _, section in store.get_sections()])
3200
3451
        matcher = config.LocationMatcher(store, '/foo/bar/baz')
3201
 
        sections = [section for s, section in matcher.get_sections()]
3202
 
        self.assertEquals([3, 2],
3203
 
                          [section.length for section in sections])
 
3452
        sections = [section for _, section in matcher.get_sections()]
3204
3453
        self.assertEquals(['/foo/bar', '/foo'],
3205
3454
                          [section.id for section in sections])
3206
3455
        self.assertEquals(['baz', 'bar/baz'],
3230
3479
        matcher = config.LocationMatcher(store, expected_url)
3231
3480
        self.assertEquals(expected_location, matcher.location)
3232
3481
 
 
3482
    def test_branch_name_colo(self):
 
3483
        store = self.get_store(self)
 
3484
        store._load_from_string(dedent("""\
 
3485
            [/]
 
3486
            push_location=my{branchname}
 
3487
        """))
 
3488
        matcher = config.LocationMatcher(store, 'file:///,branch=example%3c')
 
3489
        self.assertEqual('example<', matcher.branch_name)
 
3490
        ((_, section),) = matcher.get_sections()
 
3491
        self.assertEqual('example<', section.locals['branchname'])
 
3492
 
 
3493
    def test_branch_name_basename(self):
 
3494
        store = self.get_store(self)
 
3495
        store._load_from_string(dedent("""\
 
3496
            [/]
 
3497
            push_location=my{branchname}
 
3498
        """))
 
3499
        matcher = config.LocationMatcher(store, 'file:///parent/example%3c')
 
3500
        self.assertEqual('example<', matcher.branch_name)
 
3501
        ((_, section),) = matcher.get_sections()
 
3502
        self.assertEqual('example<', section.locals['branchname'])
 
3503
 
 
3504
 
 
3505
class TestStartingPathMatcher(TestStore):
 
3506
 
 
3507
    def setUp(self):
 
3508
        super(TestStartingPathMatcher, self).setUp()
 
3509
        # Any simple store is good enough
 
3510
        self.store = config.IniFileStore()
 
3511
 
 
3512
    def assertSectionIDs(self, expected, location, content):
 
3513
        self.store._load_from_string(content)
 
3514
        matcher = config.StartingPathMatcher(self.store, location)
 
3515
        sections = list(matcher.get_sections())
 
3516
        self.assertLength(len(expected), sections)
 
3517
        self.assertEqual(expected, [section.id for _, section in sections])
 
3518
        return sections
 
3519
 
 
3520
    def test_empty(self):
 
3521
        self.assertSectionIDs([], self.get_url(), '')
 
3522
 
 
3523
    def test_url_vs_local_paths(self):
 
3524
        # The matcher location is an url and the section names are local paths
 
3525
        self.assertSectionIDs(['/foo/bar', '/foo'],
 
3526
                              'file:///foo/bar/baz', '''\
 
3527
[/foo]
 
3528
[/foo/bar]
 
3529
''')
 
3530
 
 
3531
    def test_local_path_vs_url(self):
 
3532
        # The matcher location is a local path and the section names are urls
 
3533
        self.assertSectionIDs(['file:///foo/bar', 'file:///foo'],
 
3534
                              '/foo/bar/baz', '''\
 
3535
[file:///foo]
 
3536
[file:///foo/bar]
 
3537
''')
 
3538
 
 
3539
 
 
3540
    def test_no_name_section_included_when_present(self):
 
3541
        # Note that other tests will cover the case where the no-name section
 
3542
        # is empty and as such, not included.
 
3543
        sections = self.assertSectionIDs(['/foo/bar', '/foo', None],
 
3544
                                         '/foo/bar/baz', '''\
 
3545
option = defined so the no-name section exists
 
3546
[/foo]
 
3547
[/foo/bar]
 
3548
''')
 
3549
        self.assertEquals(['baz', 'bar/baz', '/foo/bar/baz'],
 
3550
                          [s.locals['relpath'] for _, s in sections])
 
3551
 
 
3552
    def test_order_reversed(self):
 
3553
        self.assertSectionIDs(['/foo/bar', '/foo'], '/foo/bar/baz', '''\
 
3554
[/foo]
 
3555
[/foo/bar]
 
3556
''')
 
3557
 
 
3558
    def test_unrelated_section_excluded(self):
 
3559
        self.assertSectionIDs(['/foo/bar', '/foo'], '/foo/bar/baz', '''\
 
3560
[/foo]
 
3561
[/foo/qux]
 
3562
[/foo/bar]
 
3563
''')
 
3564
 
 
3565
    def test_glob_included(self):
 
3566
        sections = self.assertSectionIDs(['/foo/*/baz', '/foo/b*', '/foo'],
 
3567
                                         '/foo/bar/baz', '''\
 
3568
[/foo]
 
3569
[/foo/qux]
 
3570
[/foo/b*]
 
3571
[/foo/*/baz]
 
3572
''')
 
3573
        # Note that 'baz' as a relpath for /foo/b* is not fully correct, but
 
3574
        # nothing really is... as far using {relpath} to append it to something
 
3575
        # else, this seems good enough though.
 
3576
        self.assertEquals(['', 'baz', 'bar/baz'],
 
3577
                          [s.locals['relpath'] for _, s in sections])
 
3578
 
 
3579
    def test_respect_order(self):
 
3580
        self.assertSectionIDs(['/foo', '/foo/b*', '/foo/*/baz'],
 
3581
                              '/foo/bar/baz', '''\
 
3582
[/foo/*/baz]
 
3583
[/foo/qux]
 
3584
[/foo/b*]
 
3585
[/foo]
 
3586
''')
 
3587
 
3233
3588
 
3234
3589
class TestNameMatcher(TestStore):
3235
3590
 
3262
3617
        self.assertLength(0, sections)
3263
3618
 
3264
3619
 
3265
 
class TestStackGet(tests.TestCase):
3266
 
 
3267
 
    # FIXME: This should be parametrized for all known Stack or dedicated
3268
 
    # paramerized tests created to avoid bloating -- vila 2011-03-31
3269
 
 
3270
 
    def overrideOptionRegistry(self):
 
3620
class TestBaseStackGet(tests.TestCase):
 
3621
 
 
3622
    def setUp(self):
 
3623
        super(TestBaseStackGet, self).setUp()
3271
3624
        self.overrideAttr(config, 'option_registry', config.OptionRegistry())
3272
3625
 
3273
 
    def test_single_config_get(self):
3274
 
        conf = dict(foo='bar')
3275
 
        conf_stack = config.Stack([conf])
3276
 
        self.assertEquals('bar', conf_stack.get('foo'))
 
3626
    def test_get_first_definition(self):
 
3627
        store1 = config.IniFileStore()
 
3628
        store1._load_from_string('foo=bar')
 
3629
        store2 = config.IniFileStore()
 
3630
        store2._load_from_string('foo=baz')
 
3631
        conf = config.Stack([store1.get_sections, store2.get_sections])
 
3632
        self.assertEquals('bar', conf.get('foo'))
3277
3633
 
3278
3634
    def test_get_with_registered_default_value(self):
3279
 
        conf_stack = config.Stack([dict()])
3280
 
        opt = config.Option('foo', default='bar')
3281
 
        self.overrideOptionRegistry()
3282
 
        config.option_registry.register('foo', opt)
 
3635
        config.option_registry.register(config.Option('foo', default='bar'))
 
3636
        conf_stack = config.Stack([])
3283
3637
        self.assertEquals('bar', conf_stack.get('foo'))
3284
3638
 
3285
3639
    def test_get_without_registered_default_value(self):
3286
 
        conf_stack = config.Stack([dict()])
3287
 
        opt = config.Option('foo')
3288
 
        self.overrideOptionRegistry()
3289
 
        config.option_registry.register('foo', opt)
 
3640
        config.option_registry.register(config.Option('foo'))
 
3641
        conf_stack = config.Stack([])
3290
3642
        self.assertEquals(None, conf_stack.get('foo'))
3291
3643
 
3292
3644
    def test_get_without_default_value_for_not_registered(self):
3293
 
        conf_stack = config.Stack([dict()])
3294
 
        opt = config.Option('foo')
3295
 
        self.overrideOptionRegistry()
 
3645
        conf_stack = config.Stack([])
3296
3646
        self.assertEquals(None, conf_stack.get('foo'))
3297
3647
 
3298
 
    def test_get_first_definition(self):
3299
 
        conf1 = dict(foo='bar')
3300
 
        conf2 = dict(foo='baz')
3301
 
        conf_stack = config.Stack([conf1, conf2])
3302
 
        self.assertEquals('bar', conf_stack.get('foo'))
3303
 
 
3304
 
    def test_get_embedded_definition(self):
3305
 
        conf1 = dict(yy='12')
3306
 
        conf2 = config.Stack([dict(xx='42'), dict(foo='baz')])
3307
 
        conf_stack = config.Stack([conf1, conf2])
3308
 
        self.assertEquals('baz', conf_stack.get('foo'))
3309
 
 
3310
3648
    def test_get_for_empty_section_callable(self):
3311
3649
        conf_stack = config.Stack([lambda : []])
3312
3650
        self.assertEquals(None, conf_stack.get('foo'))
3313
3651
 
3314
3652
    def test_get_for_broken_callable(self):
3315
3653
        # Trying to use and invalid callable raises an exception on first use
3316
 
        conf_stack = config.Stack([lambda : object()])
 
3654
        conf_stack = config.Stack([object])
3317
3655
        self.assertRaises(TypeError, conf_stack.get, 'foo')
3318
3656
 
3319
3657
 
 
3658
class TestStackWithSimpleStore(tests.TestCase):
 
3659
 
 
3660
    def setUp(self):
 
3661
        super(TestStackWithSimpleStore, self).setUp()
 
3662
        self.overrideAttr(config, 'option_registry', config.OptionRegistry())
 
3663
        self.registry = config.option_registry
 
3664
 
 
3665
    def get_conf(self, content=None):
 
3666
        return config.MemoryStack(content)
 
3667
 
 
3668
    def test_override_value_from_env(self):
 
3669
        self.overrideEnv('FOO', None)
 
3670
        self.registry.register(
 
3671
            config.Option('foo', default='bar', override_from_env=['FOO']))
 
3672
        self.overrideEnv('FOO', 'quux')
 
3673
        # Env variable provides a default taking over the option one
 
3674
        conf = self.get_conf('foo=store')
 
3675
        self.assertEquals('quux', conf.get('foo'))
 
3676
 
 
3677
    def test_first_override_value_from_env_wins(self):
 
3678
        self.overrideEnv('NO_VALUE', None)
 
3679
        self.overrideEnv('FOO', None)
 
3680
        self.overrideEnv('BAZ', None)
 
3681
        self.registry.register(
 
3682
            config.Option('foo', default='bar',
 
3683
                          override_from_env=['NO_VALUE', 'FOO', 'BAZ']))
 
3684
        self.overrideEnv('FOO', 'foo')
 
3685
        self.overrideEnv('BAZ', 'baz')
 
3686
        # The first env var set wins
 
3687
        conf = self.get_conf('foo=store')
 
3688
        self.assertEquals('foo', conf.get('foo'))
 
3689
 
 
3690
 
 
3691
class TestMemoryStack(tests.TestCase):
 
3692
 
 
3693
    def test_get(self):
 
3694
        conf = config.MemoryStack('foo=bar')
 
3695
        self.assertEquals('bar', conf.get('foo'))
 
3696
 
 
3697
    def test_set(self):
 
3698
        conf = config.MemoryStack('foo=bar')
 
3699
        conf.set('foo', 'baz')
 
3700
        self.assertEquals('baz', conf.get('foo'))
 
3701
 
 
3702
    def test_no_content(self):
 
3703
        conf = config.MemoryStack()
 
3704
        # No content means no loading
 
3705
        self.assertFalse(conf.store.is_loaded())
 
3706
        self.assertRaises(NotImplementedError, conf.get, 'foo')
 
3707
        # But a content can still be provided
 
3708
        conf.store._load_from_string('foo=bar')
 
3709
        self.assertEquals('bar', conf.get('foo'))
 
3710
 
 
3711
 
 
3712
class TestStackIterSections(tests.TestCase):
 
3713
 
 
3714
    def test_empty_stack(self):
 
3715
        conf = config.Stack([])
 
3716
        sections = list(conf.iter_sections())
 
3717
        self.assertLength(0, sections)
 
3718
 
 
3719
    def test_empty_store(self):
 
3720
        store = config.IniFileStore()
 
3721
        store._load_from_string('')
 
3722
        conf = config.Stack([store.get_sections])
 
3723
        sections = list(conf.iter_sections())
 
3724
        self.assertLength(0, sections)
 
3725
 
 
3726
    def test_simple_store(self):
 
3727
        store = config.IniFileStore()
 
3728
        store._load_from_string('foo=bar')
 
3729
        conf = config.Stack([store.get_sections])
 
3730
        tuples = list(conf.iter_sections())
 
3731
        self.assertLength(1, tuples)
 
3732
        (found_store, found_section) = tuples[0]
 
3733
        self.assertIs(store, found_store)
 
3734
 
 
3735
    def test_two_stores(self):
 
3736
        store1 = config.IniFileStore()
 
3737
        store1._load_from_string('foo=bar')
 
3738
        store2 = config.IniFileStore()
 
3739
        store2._load_from_string('bar=qux')
 
3740
        conf = config.Stack([store1.get_sections, store2.get_sections])
 
3741
        tuples = list(conf.iter_sections())
 
3742
        self.assertLength(2, tuples)
 
3743
        self.assertIs(store1, tuples[0][0])
 
3744
        self.assertIs(store2, tuples[1][0])
 
3745
 
 
3746
 
3320
3747
class TestStackWithTransport(tests.TestCaseWithTransport):
3321
3748
 
3322
3749
    scenarios = [(key, {'get_stack': builder}) for key, builder
3327
3754
 
3328
3755
    def test_build_stack(self):
3329
3756
        # Just a smoke test to help debug builders
3330
 
        stack = self.get_stack(self)
 
3757
        self.get_stack(self)
3331
3758
 
3332
3759
 
3333
3760
class TestStackGet(TestStackWithTransport):
3352
3779
        self.assertEquals((self.conf, 'foo', 'bar'), calls[0])
3353
3780
 
3354
3781
 
3355
 
class TestStackGetWithConverter(tests.TestCaseWithTransport):
 
3782
class TestStackGetWithConverter(tests.TestCase):
3356
3783
 
3357
3784
    def setUp(self):
3358
3785
        super(TestStackGetWithConverter, self).setUp()
3359
3786
        self.overrideAttr(config, 'option_registry', config.OptionRegistry())
3360
3787
        self.registry = config.option_registry
3361
 
        # We just want a simple stack with a simple store so we can inject
3362
 
        # whatever content the tests need without caring about what section
3363
 
        # names are valid for a given store/stack.
3364
 
        store = config.TransportIniFileStore(self.get_transport(), 'foo.conf')
3365
 
        self.conf = config.Stack([store.get_sections], store)
 
3788
 
 
3789
    def get_conf(self, content=None):
 
3790
        return config.MemoryStack(content)
3366
3791
 
3367
3792
    def register_bool_option(self, name, default=None, default_from_env=None):
3368
3793
        b = config.Option(name, help='A boolean.',
3372
3797
 
3373
3798
    def test_get_default_bool_None(self):
3374
3799
        self.register_bool_option('foo')
3375
 
        self.assertEquals(None, self.conf.get('foo'))
 
3800
        conf = self.get_conf('')
 
3801
        self.assertEquals(None, conf.get('foo'))
3376
3802
 
3377
3803
    def test_get_default_bool_True(self):
3378
3804
        self.register_bool_option('foo', u'True')
3379
 
        self.assertEquals(True, self.conf.get('foo'))
 
3805
        conf = self.get_conf('')
 
3806
        self.assertEquals(True, conf.get('foo'))
3380
3807
 
3381
3808
    def test_get_default_bool_False(self):
3382
3809
        self.register_bool_option('foo', False)
3383
 
        self.assertEquals(False, self.conf.get('foo'))
 
3810
        conf = self.get_conf('')
 
3811
        self.assertEquals(False, conf.get('foo'))
3384
3812
 
3385
3813
    def test_get_default_bool_False_as_string(self):
3386
3814
        self.register_bool_option('foo', u'False')
3387
 
        self.assertEquals(False, self.conf.get('foo'))
 
3815
        conf = self.get_conf('')
 
3816
        self.assertEquals(False, conf.get('foo'))
3388
3817
 
3389
3818
    def test_get_default_bool_from_env_converted(self):
3390
3819
        self.register_bool_option('foo', u'True', default_from_env=['FOO'])
3391
3820
        self.overrideEnv('FOO', 'False')
3392
 
        self.assertEquals(False, self.conf.get('foo'))
 
3821
        conf = self.get_conf('')
 
3822
        self.assertEquals(False, conf.get('foo'))
3393
3823
 
3394
3824
    def test_get_default_bool_when_conversion_fails(self):
3395
3825
        self.register_bool_option('foo', default='True')
3396
 
        self.conf.store._load_from_string('foo=invalid boolean')
3397
 
        self.assertEquals(True, self.conf.get('foo'))
 
3826
        conf = self.get_conf('foo=invalid boolean')
 
3827
        self.assertEquals(True, conf.get('foo'))
3398
3828
 
3399
3829
    def register_integer_option(self, name,
3400
3830
                                default=None, default_from_env=None):
3405
3835
 
3406
3836
    def test_get_default_integer_None(self):
3407
3837
        self.register_integer_option('foo')
3408
 
        self.assertEquals(None, self.conf.get('foo'))
 
3838
        conf = self.get_conf('')
 
3839
        self.assertEquals(None, conf.get('foo'))
3409
3840
 
3410
3841
    def test_get_default_integer(self):
3411
3842
        self.register_integer_option('foo', 42)
3412
 
        self.assertEquals(42, self.conf.get('foo'))
 
3843
        conf = self.get_conf('')
 
3844
        self.assertEquals(42, conf.get('foo'))
3413
3845
 
3414
3846
    def test_get_default_integer_as_string(self):
3415
3847
        self.register_integer_option('foo', u'42')
3416
 
        self.assertEquals(42, self.conf.get('foo'))
 
3848
        conf = self.get_conf('')
 
3849
        self.assertEquals(42, conf.get('foo'))
3417
3850
 
3418
3851
    def test_get_default_integer_from_env(self):
3419
3852
        self.register_integer_option('foo', default_from_env=['FOO'])
3420
3853
        self.overrideEnv('FOO', '18')
3421
 
        self.assertEquals(18, self.conf.get('foo'))
 
3854
        conf = self.get_conf('')
 
3855
        self.assertEquals(18, conf.get('foo'))
3422
3856
 
3423
3857
    def test_get_default_integer_when_conversion_fails(self):
3424
3858
        self.register_integer_option('foo', default='12')
3425
 
        self.conf.store._load_from_string('foo=invalid integer')
3426
 
        self.assertEquals(12, self.conf.get('foo'))
 
3859
        conf = self.get_conf('foo=invalid integer')
 
3860
        self.assertEquals(12, conf.get('foo'))
3427
3861
 
3428
3862
    def register_list_option(self, name, default=None, default_from_env=None):
3429
 
        l = config.Option(name, help='A list.',
3430
 
                          default=default, default_from_env=default_from_env,
3431
 
                          from_unicode=config.list_from_store)
 
3863
        l = config.ListOption(name, help='A list.', default=default,
 
3864
                              default_from_env=default_from_env)
3432
3865
        self.registry.register(l)
3433
3866
 
3434
3867
    def test_get_default_list_None(self):
3435
3868
        self.register_list_option('foo')
3436
 
        self.assertEquals(None, self.conf.get('foo'))
 
3869
        conf = self.get_conf('')
 
3870
        self.assertEquals(None, conf.get('foo'))
3437
3871
 
3438
3872
    def test_get_default_list_empty(self):
3439
3873
        self.register_list_option('foo', '')
3440
 
        self.assertEquals([], self.conf.get('foo'))
 
3874
        conf = self.get_conf('')
 
3875
        self.assertEquals([], conf.get('foo'))
3441
3876
 
3442
3877
    def test_get_default_list_from_env(self):
3443
3878
        self.register_list_option('foo', default_from_env=['FOO'])
3444
3879
        self.overrideEnv('FOO', '')
3445
 
        self.assertEquals([], self.conf.get('foo'))
 
3880
        conf = self.get_conf('')
 
3881
        self.assertEquals([], conf.get('foo'))
3446
3882
 
3447
3883
    def test_get_with_list_converter_no_item(self):
3448
3884
        self.register_list_option('foo', None)
3449
 
        self.conf.store._load_from_string('foo=,')
3450
 
        self.assertEquals([], self.conf.get('foo'))
 
3885
        conf = self.get_conf('foo=,')
 
3886
        self.assertEquals([], conf.get('foo'))
3451
3887
 
3452
3888
    def test_get_with_list_converter_many_items(self):
3453
3889
        self.register_list_option('foo', None)
3454
 
        self.conf.store._load_from_string('foo=m,o,r,e')
3455
 
        self.assertEquals(['m', 'o', 'r', 'e'], self.conf.get('foo'))
 
3890
        conf = self.get_conf('foo=m,o,r,e')
 
3891
        self.assertEquals(['m', 'o', 'r', 'e'], conf.get('foo'))
3456
3892
 
3457
3893
    def test_get_with_list_converter_embedded_spaces_many_items(self):
3458
3894
        self.register_list_option('foo', None)
3459
 
        self.conf.store._load_from_string('foo=" bar", "baz "')
3460
 
        self.assertEquals([' bar', 'baz '], self.conf.get('foo'))
 
3895
        conf = self.get_conf('foo=" bar", "baz "')
 
3896
        self.assertEquals([' bar', 'baz '], conf.get('foo'))
3461
3897
 
3462
3898
    def test_get_with_list_converter_stripped_spaces_many_items(self):
3463
3899
        self.register_list_option('foo', None)
3464
 
        self.conf.store._load_from_string('foo= bar ,  baz ')
3465
 
        self.assertEquals(['bar', 'baz'], self.conf.get('foo'))
 
3900
        conf = self.get_conf('foo= bar ,  baz ')
 
3901
        self.assertEquals(['bar', 'baz'], conf.get('foo'))
3466
3902
 
3467
3903
 
3468
3904
class TestIterOptionRefs(tests.TestCase):
3493
3929
                         (False, ''),],
3494
3930
                        '{foo}{bar}')
3495
3931
 
 
3932
    def test_newline_in_refs_are_not_matched(self):
 
3933
        self.assertRefs([(False, '{\nxx}{xx\n}{{\n}}')], '{\nxx}{xx\n}{{\n}}')
 
3934
 
3496
3935
 
3497
3936
class TestStackExpandOptions(tests.TestCaseWithTransport):
3498
3937
 
3500
3939
        super(TestStackExpandOptions, self).setUp()
3501
3940
        self.overrideAttr(config, 'option_registry', config.OptionRegistry())
3502
3941
        self.registry = config.option_registry
3503
 
        self.conf = build_branch_stack(self)
 
3942
        store = config.TransportIniFileStore(self.get_transport(), 'foo.conf')
 
3943
        self.conf = config.Stack([store.get_sections], store)
3504
3944
 
3505
3945
    def assertExpansion(self, expected, string, env=None):
3506
3946
        self.assertEquals(expected, self.conf.expand_options(string, env))
3541
3981
        self.assertRaises(errors.ExpandingUnknownOption,
3542
3982
                          self.conf.expand_options, '{foo}')
3543
3983
 
 
3984
    def test_illegal_def_is_ignored(self):
 
3985
        self.assertExpansion('{1,2}', '{1,2}')
 
3986
        self.assertExpansion('{ }', '{ }')
 
3987
        self.assertExpansion('${Foo,f}', '${Foo,f}')
 
3988
 
3544
3989
    def test_indirect_ref(self):
3545
3990
        self.conf.store._load_from_string('''
3546
3991
foo=xxx
3578
4023
list={foo},{bar},{baz}
3579
4024
''')
3580
4025
        self.registry.register(
3581
 
            config.Option('list', from_unicode=config.list_from_store))
 
4026
            config.ListOption('list'))
3582
4027
        self.assertEquals(['start', 'middle', 'end'],
3583
4028
                           self.conf.get('list', expand=True))
3584
4029
 
3589
4034
baz=end
3590
4035
list={foo}
3591
4036
''')
3592
 
        self.registry.register(
3593
 
            config.Option('list', from_unicode=config.list_from_store))
 
4037
        self.registry.register(config.ListOption('list'))
 
4038
        # Register an intermediate option as a list to ensure no conversion
 
4039
        # happen while expanding. Conversion should only occur for the original
 
4040
        # option ('list' here).
 
4041
        self.registry.register(config.ListOption('baz'))
3594
4042
        self.assertEquals(['start', 'middle', 'end'],
3595
4043
                           self.conf.get('list', expand=True))
3596
4044
 
3605
4053
''')
3606
4054
        # What matters is what the registration says, the conversion happens
3607
4055
        # only after all expansions have been performed
3608
 
        self.registry.register(
3609
 
            config.Option('hidden', from_unicode=config.list_from_store))
 
4056
        self.registry.register(config.ListOption('hidden'))
3610
4057
        self.assertEquals(['bin', 'go'],
3611
4058
                          self.conf.get('hidden', expand=True))
3612
4059
 
3916
4363
        """
3917
4364
        sections = list(conf._get_sections(name))
3918
4365
        self.assertLength(len(expected), sections)
3919
 
        self.assertEqual(expected, [name for name, _, _ in sections])
 
4366
        self.assertEqual(expected, [n for n, _, _ in sections])
3920
4367
 
3921
4368
    def test_bazaar_default_section(self):
3922
4369
        self.assertSectionNames(['DEFAULT'], self.bazaar_config)
3966
4413
        self.assertSectionNames(['ALIASES'], self.bazaar_config, 'ALIASES')
3967
4414
 
3968
4415
 
 
4416
class TestSharedStores(tests.TestCaseInTempDir):
 
4417
 
 
4418
    def test_bazaar_conf_shared(self):
 
4419
        g1 = config.GlobalStack()
 
4420
        g2 = config.GlobalStack()
 
4421
        # The two stacks share the same store
 
4422
        self.assertIs(g1.store, g2.store)
 
4423
 
 
4424
 
3969
4425
class TestAuthenticationConfigFile(tests.TestCase):
3970
4426
    """Test the authentication.conf file matching"""
3971
4427
 
4186
4642
                                           port=99, path='/foo',
4187
4643
                                           realm='realm')
4188
4644
        CREDENTIALS = {'name': 'name', 'user': 'user', 'password': 'password',
4189
 
                       'verify_certificates': False, 'scheme': 'scheme', 
4190
 
                       'host': 'host', 'port': 99, 'path': '/foo', 
 
4645
                       'verify_certificates': False, 'scheme': 'scheme',
 
4646
                       'host': 'host', 'port': 99, 'path': '/foo',
4191
4647
                       'realm': 'realm'}
4192
4648
        self.assertEqual(CREDENTIALS, credentials)
4193
4649
        credentials_from_disk = config.AuthenticationConfig().get_credentials(
4201
4657
        self.assertIs(None, conf._get_config().get('name'))
4202
4658
        credentials = conf.get_credentials(host='host', scheme='scheme')
4203
4659
        CREDENTIALS = {'name': 'name2', 'user': 'user2', 'password':
4204
 
                       'password', 'verify_certificates': True, 
4205
 
                       'scheme': 'scheme', 'host': 'host', 'port': None, 
 
4660
                       'password', 'verify_certificates': True,
 
4661
                       'scheme': 'scheme', 'host': 'host', 'port': None,
4206
4662
                       'path': None, 'realm': None}
4207
4663
        self.assertEqual(CREDENTIALS, credentials)
4208
4664
 
4460
4916
        self.assertEquals('secret', decoded)
4461
4917
 
4462
4918
 
 
4919
class TestBase64CredentialStore(tests.TestCase):
 
4920
 
 
4921
    def test_decode_password(self):
 
4922
        r = config.credential_store_registry
 
4923
        plain_text = r.get_credential_store('base64')
 
4924
        decoded = plain_text.decode_password(dict(password='c2VjcmV0'))
 
4925
        self.assertEquals('secret', decoded)
 
4926
 
 
4927
 
4463
4928
# FIXME: Once we have a way to declare authentication to all test servers, we
4464
4929
# can implement generic tests.
4465
4930
# test_user_password_in_url
4477
4942
 
4478
4943
    def test_auto_user_id(self):
4479
4944
        """Automatic inference of user name.
4480
 
        
 
4945
 
4481
4946
        This is a bit hard to test in an isolated way, because it depends on
4482
4947
        system functions that go direct to /etc or perhaps somewhere else.
4483
4948
        But it's reasonable to say that on Unix, with an /etc/mailname, we ought
4493
4958
        else:
4494
4959
            self.assertEquals((None, None), (realname, address))
4495
4960
 
 
4961
 
 
4962
class TestDefaultMailDomain(tests.TestCaseInTempDir):
 
4963
    """Test retrieving default domain from mailname file"""
 
4964
 
 
4965
    def test_default_mail_domain_simple(self):
 
4966
        f = file('simple', 'w')
 
4967
        try:
 
4968
            f.write("domainname.com\n")
 
4969
        finally:
 
4970
            f.close()
 
4971
        r = config._get_default_mail_domain('simple')
 
4972
        self.assertEquals('domainname.com', r)
 
4973
 
 
4974
    def test_default_mail_domain_no_eol(self):
 
4975
        f = file('no_eol', 'w')
 
4976
        try:
 
4977
            f.write("domainname.com")
 
4978
        finally:
 
4979
            f.close()
 
4980
        r = config._get_default_mail_domain('no_eol')
 
4981
        self.assertEquals('domainname.com', r)
 
4982
 
 
4983
    def test_default_mail_domain_multiple_lines(self):
 
4984
        f = file('multiple_lines', 'w')
 
4985
        try:
 
4986
            f.write("domainname.com\nsome other text\n")
 
4987
        finally:
 
4988
            f.close()
 
4989
        r = config._get_default_mail_domain('multiple_lines')
 
4990
        self.assertEquals('domainname.com', r)
 
4991
 
 
4992
 
 
4993
class EmailOptionTests(tests.TestCase):
 
4994
 
 
4995
    def test_default_email_uses_BZR_EMAIL(self):
 
4996
        conf = config.MemoryStack('email=jelmer@debian.org')
 
4997
        # BZR_EMAIL takes precedence over EMAIL
 
4998
        self.overrideEnv('BZR_EMAIL', 'jelmer@samba.org')
 
4999
        self.overrideEnv('EMAIL', 'jelmer@apache.org')
 
5000
        self.assertEquals('jelmer@samba.org', conf.get('email'))
 
5001
 
 
5002
    def test_default_email_uses_EMAIL(self):
 
5003
        conf = config.MemoryStack('')
 
5004
        self.overrideEnv('BZR_EMAIL', None)
 
5005
        self.overrideEnv('EMAIL', 'jelmer@apache.org')
 
5006
        self.assertEquals('jelmer@apache.org', conf.get('email'))
 
5007
 
 
5008
    def test_BZR_EMAIL_overrides(self):
 
5009
        conf = config.MemoryStack('email=jelmer@debian.org')
 
5010
        self.overrideEnv('BZR_EMAIL', 'jelmer@apache.org')
 
5011
        self.assertEquals('jelmer@apache.org', conf.get('email'))
 
5012
        self.overrideEnv('BZR_EMAIL', None)
 
5013
        self.overrideEnv('EMAIL', 'jelmer@samba.org')
 
5014
        self.assertEquals('jelmer@debian.org', conf.get('email'))
 
5015
 
 
5016
 
 
5017
class MailClientOptionTests(tests.TestCase):
 
5018
 
 
5019
    def test_default(self):
 
5020
        conf = config.MemoryStack('')
 
5021
        client = conf.get('mail_client')
 
5022
        self.assertIs(client, mail_client.DefaultMail)
 
5023
 
 
5024
    def test_evolution(self):
 
5025
        conf = config.MemoryStack('mail_client=evolution')
 
5026
        client = conf.get('mail_client')
 
5027
        self.assertIs(client, mail_client.Evolution)
 
5028
 
 
5029
    def test_kmail(self):
 
5030
        conf = config.MemoryStack('mail_client=kmail')
 
5031
        client = conf.get('mail_client')
 
5032
        self.assertIs(client, mail_client.KMail)
 
5033
 
 
5034
    def test_mutt(self):
 
5035
        conf = config.MemoryStack('mail_client=mutt')
 
5036
        client = conf.get('mail_client')
 
5037
        self.assertIs(client, mail_client.Mutt)
 
5038
 
 
5039
    def test_thunderbird(self):
 
5040
        conf = config.MemoryStack('mail_client=thunderbird')
 
5041
        client = conf.get('mail_client')
 
5042
        self.assertIs(client, mail_client.Thunderbird)
 
5043
 
 
5044
    def test_explicit_default(self):
 
5045
        conf = config.MemoryStack('mail_client=default')
 
5046
        client = conf.get('mail_client')
 
5047
        self.assertIs(client, mail_client.DefaultMail)
 
5048
 
 
5049
    def test_editor(self):
 
5050
        conf = config.MemoryStack('mail_client=editor')
 
5051
        client = conf.get('mail_client')
 
5052
        self.assertIs(client, mail_client.Editor)
 
5053
 
 
5054
    def test_mapi(self):
 
5055
        conf = config.MemoryStack('mail_client=mapi')
 
5056
        client = conf.get('mail_client')
 
5057
        self.assertIs(client, mail_client.MAPIClient)
 
5058
 
 
5059
    def test_xdg_email(self):
 
5060
        conf = config.MemoryStack('mail_client=xdg-email')
 
5061
        client = conf.get('mail_client')
 
5062
        self.assertIs(client, mail_client.XDGEmail)
 
5063
 
 
5064
    def test_unknown(self):
 
5065
        conf = config.MemoryStack('mail_client=firebird')
 
5066
        self.assertRaises(errors.ConfigOptionValueError, conf.get,
 
5067
                'mail_client')