~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_config.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2011-06-29 17:19:58 UTC
  • mfrom: (5967.8.4 rm-del-methods)
  • Revision ID: pqm@pqm.ubuntu.com-20110629171958-u8a6lkpw5kdnfm55
(mbp) remove most __del__ methods (Martin Pool)

Show diffs side-by-side

added added

removed removed

Lines of Context:
33
33
    errors,
34
34
    osutils,
35
35
    mail_client,
 
36
    mergetools,
36
37
    ui,
37
38
    urlutils,
 
39
    registry,
38
40
    remote,
39
41
    tests,
40
42
    trace,
 
43
    transport,
41
44
    )
42
45
from bzrlib.symbol_versioning import (
43
46
    deprecated_in,
 
47
    deprecated_method,
44
48
    )
45
49
from bzrlib.transport import remote as transport_remote
46
50
from bzrlib.tests import (
67
71
 
68
72
# Register helpers to build stores
69
73
config.test_store_builder_registry.register(
70
 
    'configobj', lambda test: config.TransportIniFileStore(
71
 
        test.get_transport(), 'configobj.conf'))
 
74
    'configobj', lambda test: config.IniFileStore(test.get_transport(),
 
75
                                                  'configobj.conf'))
72
76
config.test_store_builder_registry.register(
73
77
    'bazaar', lambda test: config.GlobalStore())
74
78
config.test_store_builder_registry.register(
112
116
config.test_store_builder_registry.register('branch', build_branch_store)
113
117
 
114
118
 
115
 
def build_control_store(test):
116
 
    build_backing_branch(test, 'branch')
117
 
    b = bzrdir.BzrDir.open('branch')
118
 
    return config.ControlStore(b)
119
 
config.test_store_builder_registry.register('control', build_control_store)
120
 
 
121
 
 
122
119
def build_remote_branch_store(test):
123
120
    # There is only one permutation (but we won't be able to handle more with
124
121
    # this design anyway)
151
148
     server_class) = transport_remote.get_test_permutations()[0]
152
149
    build_backing_branch(test, 'branch', transport_class, server_class)
153
150
    b = branch.Branch.open(test.get_url('branch'))
154
 
    return config.RemoteBranchStack(b)
 
151
    return config.BranchStack(b)
155
152
config.test_stack_builder_registry.register('remote_branch',
156
153
                                            build_remote_branch_stack)
157
154
 
158
 
def build_remote_control_stack(test):
159
 
    # There is only one permutation (but we won't be able to handle more with
160
 
    # this design anyway)
161
 
    (transport_class,
162
 
     server_class) = transport_remote.get_test_permutations()[0]
163
 
    # We need only a bzrdir for this, not a full branch, but it's not worth
164
 
    # creating a dedicated helper to create only the bzrdir
165
 
    build_backing_branch(test, 'branch', transport_class, server_class)
166
 
    b = branch.Branch.open(test.get_url('branch'))
167
 
    return config.RemoteControlStack(b.bzrdir)
168
 
config.test_stack_builder_registry.register('remote_control',
169
 
                                            build_remote_control_stack)
170
 
 
171
155
 
172
156
sample_long_alias="log -r-15..-1 --line"
173
157
sample_config_text = u"""
176
160
editor=vim
177
161
change_editor=vimdiff -of @new_path @old_path
178
162
gpg_signing_command=gnome-gpg
179
 
gpg_signing_key=DD4D5088
180
163
log_format=short
181
 
validate_signatures_in_log=true
182
 
acceptable_keys=amy
183
164
user_global_option=something
184
165
bzr.mergetool.sometool=sometool {base} {this} {other} -o {result}
185
166
bzr.mergetool.funkytool=funkytool "arg with spaces" {this_temp}
186
 
bzr.mergetool.newtool='"newtool with spaces" {this_temp}'
187
167
bzr.default_mergetool=sometool
188
168
[ALIASES]
189
169
h=help
232
212
[/a/]
233
213
check_signatures=check-available
234
214
gpg_signing_command=false
235
 
gpg_signing_key=default
236
215
user_local_option=local
237
216
# test trailing / matching
238
217
[/a/*]
534
513
        my_config = config.Config()
535
514
        self.assertEqual('long', my_config.log_format())
536
515
 
537
 
    def test_acceptable_keys_default(self):
538
 
        my_config = config.Config()
539
 
        self.assertEqual(None, my_config.acceptable_keys())
540
 
 
541
 
    def test_validate_signatures_in_log_default(self):
542
 
        my_config = config.Config()
543
 
        self.assertEqual(False, my_config.validate_signatures_in_log())
544
 
 
545
516
    def test_get_change_editor(self):
546
517
        my_config = InstrumentedConfig()
547
518
        change_editor = my_config.get_change_editor('old_tree', 'new_tree')
836
807
        self.assertEquals(['{foo', '}', '{', 'bar}'],
837
808
                          conf.get_user_option('hidden', expand=True))
838
809
 
839
 
 
840
810
class TestLocationConfigOptionExpansion(tests.TestCaseInTempDir):
841
811
 
842
812
    def get_config(self, location, string=None):
1053
1023
        # automatically cast to list
1054
1024
        self.assertEqual(['x'], get_list('one_item'))
1055
1025
 
1056
 
    def test_get_user_option_as_int_from_SI(self):
1057
 
        conf, parser = self.make_config_parser("""
1058
 
plain = 100
1059
 
si_k = 5k,
1060
 
si_kb = 5kb,
1061
 
si_m = 5M,
1062
 
si_mb = 5MB,
1063
 
si_g = 5g,
1064
 
si_gb = 5gB,
1065
 
""")
1066
 
        get_si = conf.get_user_option_as_int_from_SI
1067
 
        self.assertEqual(100, get_si('plain'))
1068
 
        self.assertEqual(5000, get_si('si_k'))
1069
 
        self.assertEqual(5000, get_si('si_kb'))
1070
 
        self.assertEqual(5000000, get_si('si_m'))
1071
 
        self.assertEqual(5000000, get_si('si_mb'))
1072
 
        self.assertEqual(5000000000, get_si('si_g'))
1073
 
        self.assertEqual(5000000000, get_si('si_gb'))
1074
 
        self.assertEqual(None, get_si('non-exist'))
1075
 
        self.assertEqual(42, get_si('non-exist-with-default',  42))
1076
1026
 
1077
1027
class TestSupressWarning(TestIniConfig):
1078
1028
 
1265
1215
        self.assertEqual("gnome-gpg", my_config.gpg_signing_command())
1266
1216
        self.assertEqual(False, my_config.signature_needed())
1267
1217
 
1268
 
    def test_gpg_signing_key(self):
1269
 
        my_config = self._get_sample_config()
1270
 
        self.assertEqual("DD4D5088", my_config.gpg_signing_key())
1271
 
 
1272
1218
    def _get_empty_config(self):
1273
1219
        my_config = config.GlobalConfig()
1274
1220
        return my_config
1294
1240
        my_config = self._get_sample_config()
1295
1241
        self.assertEqual("short", my_config.log_format())
1296
1242
 
1297
 
    def test_configured_acceptable_keys(self):
1298
 
        my_config = self._get_sample_config()
1299
 
        self.assertEqual("amy", my_config.acceptable_keys())
1300
 
 
1301
 
    def test_configured_validate_signatures_in_log(self):
1302
 
        my_config = self._get_sample_config()
1303
 
        self.assertEqual(True, my_config.validate_signatures_in_log())
1304
 
 
1305
1243
    def test_get_alias(self):
1306
1244
        my_config = self._get_sample_config()
1307
1245
        self.assertEqual('help', my_config.get_alias('h'))
1340
1278
        self.log(repr(tools))
1341
1279
        self.assertEqual(
1342
1280
            {u'funkytool' : u'funkytool "arg with spaces" {this_temp}',
1343
 
            u'sometool' : u'sometool {base} {this} {other} -o {result}',
1344
 
            u'newtool' : u'"newtool with spaces" {this_temp}'},
 
1281
            u'sometool' : u'sometool {base} {this} {other} -o {result}'},
1345
1282
            tools)
1346
1283
 
1347
1284
    def test_get_merge_tools_empty(self):
1565
1502
        self.get_branch_config('/a')
1566
1503
        self.assertEqual("false", self.my_config.gpg_signing_command())
1567
1504
 
1568
 
    def test_gpg_signing_key(self):
1569
 
        self.get_branch_config('/b')
1570
 
        self.assertEqual("DD4D5088", self.my_config.gpg_signing_key())
1571
 
 
1572
 
    def test_gpg_signing_key_default(self):
1573
 
        self.get_branch_config('/a')
1574
 
        self.assertEqual("erik@bagfors.nu", self.my_config.gpg_signing_key())
1575
 
 
1576
1505
    def test_get_user_option_global(self):
1577
1506
        self.get_branch_config('/a')
1578
1507
        self.assertEqual('something',
1967
1896
        conf = config.TransportConfig(t, 'foo.conf')
1968
1897
        self.assertRaises(errors.ParseConfigError, conf._get_configobj)
1969
1898
 
1970
 
    def test_load_permission_denied(self):
1971
 
        """Ensure we get an empty config file if the file is inaccessible."""
1972
 
        warnings = []
1973
 
        def warning(*args):
1974
 
            warnings.append(args[0] % args[1:])
1975
 
        self.overrideAttr(trace, 'warning', warning)
1976
 
 
1977
 
        class DenyingTransport(object):
1978
 
 
1979
 
            def __init__(self, base):
1980
 
                self.base = base
1981
 
 
1982
 
            def get_bytes(self, relpath):
1983
 
                raise errors.PermissionDenied(relpath, "")
1984
 
 
1985
 
        cfg = config.TransportConfig(
1986
 
            DenyingTransport("nonexisting://"), 'control.conf')
1987
 
        self.assertIs(None, cfg.get_option('non-existant', 'SECTION'))
1988
 
        self.assertEquals(
1989
 
            warnings,
1990
 
            [u'Permission denied while trying to open configuration file '
1991
 
             u'nonexisting:///control.conf.'])
1992
 
 
1993
1899
    def test_get_value(self):
1994
1900
        """Test that retreiving a value from a section is possible"""
1995
1901
        bzrdir_config = config.TransportConfig(self.get_transport('.'),
2275
2181
        opt = config.Option('foo', default='bar')
2276
2182
        self.assertEquals('bar', opt.get_default())
2277
2183
 
2278
 
    def test_default_value_from_env(self):
2279
 
        opt = config.Option('foo', default='bar', default_from_env=['FOO'])
2280
 
        self.overrideEnv('FOO', 'quux')
2281
 
        # Env variable provides a default taking over the option one
2282
 
        self.assertEquals('quux', opt.get_default())
2283
 
 
2284
 
    def test_first_default_value_from_env_wins(self):
2285
 
        opt = config.Option('foo', default='bar',
2286
 
                            default_from_env=['NO_VALUE', 'FOO', 'BAZ'])
2287
 
        self.overrideEnv('FOO', 'foo')
2288
 
        self.overrideEnv('BAZ', 'baz')
2289
 
        # The first env var set wins
2290
 
        self.assertEquals('foo', opt.get_default())
2291
 
 
2292
 
    def test_not_supported_list_default_value(self):
2293
 
        self.assertRaises(AssertionError, config.Option, 'foo', default=[1])
2294
 
 
2295
 
    def test_not_supported_object_default_value(self):
2296
 
        self.assertRaises(AssertionError, config.Option, 'foo',
2297
 
                          default=object())
2298
 
 
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)
2465
 
 
2466
 
    def test_convert_invalid(self):
2467
 
        opt = self.get_option()
2468
 
        # We don't even try to convert a list into a list, we only expect
2469
 
        # strings
2470
 
        self.assertConvertInvalid(opt, [1])
2471
 
        # No string is invalid as all forms can be converted to a list
2472
 
 
2473
 
    def test_convert_valid(self):
2474
 
        opt = self.get_option()
2475
 
        # An empty string is an empty list
2476
 
        self.assertConverted([], opt, '') # Using a bare str() just in case
2477
 
        self.assertConverted([], opt, u'')
2478
 
        # A boolean
2479
 
        self.assertConverted([u'True'], opt, u'True')
2480
 
        # An integer
2481
 
        self.assertConverted([u'42'], opt, u'42')
2482
 
        # A single string
2483
 
        self.assertConverted([u'bar'], opt, u'bar')
2484
 
 
2485
2184
 
2486
2185
class TestOptionRegistry(tests.TestCase):
2487
2186
 
2488
2187
    def setUp(self):
2489
2188
        super(TestOptionRegistry, self).setUp()
2490
2189
        # Always start with an empty registry
2491
 
        self.overrideAttr(config, 'option_registry', config.OptionRegistry())
 
2190
        self.overrideAttr(config, 'option_registry', registry.Registry())
2492
2191
        self.registry = config.option_registry
2493
2192
 
2494
2193
    def test_register(self):
2495
2194
        opt = config.Option('foo')
2496
 
        self.registry.register(opt)
 
2195
        self.registry.register('foo', opt)
2497
2196
        self.assertIs(opt, self.registry.get('foo'))
2498
2197
 
 
2198
    lazy_option = config.Option('lazy_foo')
 
2199
 
 
2200
    def test_register_lazy(self):
 
2201
        self.registry.register_lazy('foo', self.__module__,
 
2202
                                    'TestOptionRegistry.lazy_option')
 
2203
        self.assertIs(self.lazy_option, self.registry.get('foo'))
 
2204
 
2499
2205
    def test_registered_help(self):
2500
 
        opt = config.Option('foo', help='A simple option')
2501
 
        self.registry.register(opt)
 
2206
        opt = config.Option('foo')
 
2207
        self.registry.register('foo', opt, help='A simple option')
2502
2208
        self.assertEquals('A simple option', self.registry.get_help('foo'))
2503
2209
 
2504
 
    lazy_option = config.Option('lazy_foo', help='Lazy help')
2505
 
 
2506
 
    def test_register_lazy(self):
2507
 
        self.registry.register_lazy('lazy_foo', self.__module__,
2508
 
                                    'TestOptionRegistry.lazy_option')
2509
 
        self.assertIs(self.lazy_option, self.registry.get('lazy_foo'))
2510
 
 
2511
 
    def test_registered_lazy_help(self):
2512
 
        self.registry.register_lazy('lazy_foo', self.__module__,
2513
 
                                    'TestOptionRegistry.lazy_option')
2514
 
        self.assertEquals('Lazy help', self.registry.get_help('lazy_foo'))
2515
 
 
2516
2210
 
2517
2211
class TestRegisteredOptions(tests.TestCase):
2518
2212
    """All registered options should verify some constraints."""
2532
2226
    def test_help_is_set(self):
2533
2227
        option_help = self.registry.get_help(self.option_name)
2534
2228
        self.assertNotEquals(None, option_help)
2535
 
        # Come on, think about the user, he really wants to know what the
 
2229
        # Come on, think about the user, he really wants to know whst the
2536
2230
        # option is about
2537
 
        self.assertIsNot(None, option_help)
2538
2231
        self.assertNotEquals('', option_help)
2539
2232
 
2540
2233
 
2562
2255
 
2563
2256
class TestMutableSection(tests.TestCase):
2564
2257
 
2565
 
    scenarios = [('mutable',
2566
 
                  {'get_section':
2567
 
                       lambda opts: config.MutableSection('myID', opts)},),
2568
 
        ]
 
2258
    # FIXME: Parametrize so that all sections (including os.environ and the
 
2259
    # ones produced by Stores) run these tests -- vila 2011-04-01
2569
2260
 
2570
2261
    def test_set(self):
2571
2262
        a_dict = dict(foo='bar')
2572
 
        section = self.get_section(a_dict)
 
2263
        section = config.MutableSection('myID', a_dict)
2573
2264
        section.set('foo', 'new_value')
2574
2265
        self.assertEquals('new_value', section.get('foo'))
2575
2266
        # The change appears in the shared section
2580
2271
 
2581
2272
    def test_set_preserve_original_once(self):
2582
2273
        a_dict = dict(foo='bar')
2583
 
        section = self.get_section(a_dict)
 
2274
        section = config.MutableSection('myID', a_dict)
2584
2275
        section.set('foo', 'first_value')
2585
2276
        section.set('foo', 'second_value')
2586
2277
        # We keep track of the original value
2589
2280
 
2590
2281
    def test_remove(self):
2591
2282
        a_dict = dict(foo='bar')
2592
 
        section = self.get_section(a_dict)
 
2283
        section = config.MutableSection('myID', a_dict)
2593
2284
        section.remove('foo')
2594
2285
        # We get None for unknown options via the default value
2595
2286
        self.assertEquals(None, section.get('foo'))
2602
2293
 
2603
2294
    def test_remove_new_option(self):
2604
2295
        a_dict = dict()
2605
 
        section = self.get_section(a_dict)
 
2296
        section = config.MutableSection('myID', a_dict)
2606
2297
        section.set('foo', 'bar')
2607
2298
        section.remove('foo')
2608
2299
        self.assertFalse('foo' in section.options)
2612
2303
        self.assertEquals(config._NewlyCreatedOption, section.orig['foo'])
2613
2304
 
2614
2305
 
2615
 
class TestCommandLineStore(tests.TestCase):
2616
 
 
2617
 
    def setUp(self):
2618
 
        super(TestCommandLineStore, self).setUp()
2619
 
        self.store = config.CommandLineStore()
2620
 
 
2621
 
    def get_section(self):
2622
 
        """Get the unique section for the command line overrides."""
2623
 
        sections = list(self.store.get_sections())
2624
 
        self.assertLength(1, sections)
2625
 
        store, section = sections[0]
2626
 
        self.assertEquals(self.store, store)
2627
 
        return section
2628
 
 
2629
 
    def test_no_override(self):
2630
 
        self.store._from_cmdline([])
2631
 
        section = self.get_section()
2632
 
        self.assertLength(0, list(section.iter_option_names()))
2633
 
 
2634
 
    def test_simple_override(self):
2635
 
        self.store._from_cmdline(['a=b'])
2636
 
        section = self.get_section()
2637
 
        self.assertEqual('b', section.get('a'))
2638
 
 
2639
 
    def test_list_override(self):
2640
 
        self.store._from_cmdline(['l=1,2,3'])
2641
 
        val = self.get_section().get('l')
2642
 
        self.assertEqual('1,2,3', val)
2643
 
        # Reminder: lists should be registered as such explicitely, otherwise
2644
 
        # the conversion needs to be done afterwards.
2645
 
        self.assertEqual(['1', '2', '3'], config.list_from_store(val))
2646
 
 
2647
 
    def test_multiple_overrides(self):
2648
 
        self.store._from_cmdline(['a=b', 'x=y'])
2649
 
        section = self.get_section()
2650
 
        self.assertEquals('b', section.get('a'))
2651
 
        self.assertEquals('y', section.get('x'))
2652
 
 
2653
 
    def test_wrong_syntax(self):
2654
 
        self.assertRaises(errors.BzrCommandError,
2655
 
                          self.store._from_cmdline, ['a=b', 'c'])
2656
 
 
2657
 
 
2658
2306
class TestStore(tests.TestCaseWithTransport):
2659
2307
 
2660
 
    def assertSectionContent(self, expected, (store, section)):
 
2308
    def assertSectionContent(self, expected, section):
2661
2309
        """Assert that some options have the proper values in a section."""
2662
2310
        expected_name, expected_options = expected
2663
2311
        self.assertEquals(expected_name, section.id)
2671
2319
    scenarios = [(key, {'get_store': builder}) for key, builder
2672
2320
                 in config.test_store_builder_registry.iteritems()]
2673
2321
 
 
2322
    def setUp(self):
 
2323
        super(TestReadonlyStore, self).setUp()
 
2324
 
2674
2325
    def test_building_delays_load(self):
2675
2326
        store = self.get_store(self)
2676
2327
        self.assertEquals(False, store.is_loaded())
2703
2354
 
2704
2355
 
2705
2356
class TestIniFileStoreContent(tests.TestCaseWithTransport):
2706
 
    """Simulate loading a config store with content of various encodings.
 
2357
    """Simulate loading a config store without content of various encodings.
2707
2358
 
2708
2359
    All files produced by bzr are in utf8 content.
2709
2360
 
2722
2373
        utf8_content = unicode_content.encode('utf8')
2723
2374
        # Store the raw content in the config file
2724
2375
        t.put_bytes('foo.conf', utf8_content)
2725
 
        store = config.TransportIniFileStore(t, 'foo.conf')
 
2376
        store = config.IniFileStore(t, 'foo.conf')
2726
2377
        store.load()
2727
2378
        stack = config.Stack([store.get_sections], store)
2728
2379
        self.assertEquals(unicode_user, stack.get('user'))
2731
2382
        """Ensure we display a proper error on non-ascii, non utf-8 content."""
2732
2383
        t = self.get_transport()
2733
2384
        t.put_bytes('foo.conf', 'user=foo\n#%s\n' % (self.invalid_utf8_char,))
2734
 
        store = config.TransportIniFileStore(t, 'foo.conf')
 
2385
        store = config.IniFileStore(t, 'foo.conf')
2735
2386
        self.assertRaises(errors.ConfigContentError, store.load)
2736
2387
 
2737
2388
    def test_load_erroneous_content(self):
2738
2389
        """Ensure we display a proper error on content that can't be parsed."""
2739
2390
        t = self.get_transport()
2740
2391
        t.put_bytes('foo.conf', '[open_section\n')
2741
 
        store = config.TransportIniFileStore(t, 'foo.conf')
 
2392
        store = config.IniFileStore(t, 'foo.conf')
2742
2393
        self.assertRaises(errors.ParseConfigError, store.load)
2743
2394
 
2744
 
    def test_load_permission_denied(self):
2745
 
        """Ensure we get warned when trying to load an inaccessible file."""
2746
 
        warnings = []
2747
 
        def warning(*args):
2748
 
            warnings.append(args[0] % args[1:])
2749
 
        self.overrideAttr(trace, 'warning', warning)
2750
 
 
2751
 
        t = self.get_transport()
2752
 
 
2753
 
        def get_bytes(relpath):
2754
 
            raise errors.PermissionDenied(relpath, "")
2755
 
        t.get_bytes = get_bytes
2756
 
        store = config.TransportIniFileStore(t, 'foo.conf')
2757
 
        self.assertRaises(errors.PermissionDenied, store.load)
2758
 
        self.assertEquals(
2759
 
            warnings,
2760
 
            [u'Permission denied while trying to load configuration store %s.'
2761
 
             % store.external_url()])
2762
 
 
2763
2395
 
2764
2396
class TestIniConfigContent(tests.TestCaseWithTransport):
2765
 
    """Simulate loading a IniBasedConfig with content of various encodings.
 
2397
    """Simulate loading a IniBasedConfig without content of various encodings.
2766
2398
 
2767
2399
    All files produced by bzr are in utf8 content.
2768
2400
 
2913
2545
        self.assertEquals((store,), calls[0])
2914
2546
 
2915
2547
 
2916
 
class TestTransportIniFileStore(TestStore):
 
2548
class TestIniFileStore(TestStore):
2917
2549
 
2918
2550
    def test_loading_unknown_file_fails(self):
2919
 
        store = config.TransportIniFileStore(self.get_transport(),
2920
 
            'I-do-not-exist')
 
2551
        store = config.IniFileStore(self.get_transport(), 'I-do-not-exist')
2921
2552
        self.assertRaises(errors.NoSuchFile, store.load)
2922
2553
 
2923
2554
    def test_invalid_content(self):
2924
 
        store = config.TransportIniFileStore(self.get_transport(), 'foo.conf')
 
2555
        store = config.IniFileStore(self.get_transport(), 'foo.conf', )
2925
2556
        self.assertEquals(False, store.is_loaded())
2926
2557
        exc = self.assertRaises(
2927
2558
            errors.ParseConfigError, store._load_from_string,
2935
2566
        # option names share the same name space...)
2936
2567
        # FIXME: This should be fixed by forbidding dicts as values ?
2937
2568
        # -- vila 2011-04-05
2938
 
        store = config.TransportIniFileStore(self.get_transport(), 'foo.conf')
 
2569
        store = config.IniFileStore(self.get_transport(), 'foo.conf', )
2939
2570
        store._load_from_string('''
2940
2571
foo=bar
2941
2572
l=1,2
2951
2582
        sections = list(store.get_sections())
2952
2583
        self.assertLength(4, sections)
2953
2584
        # The default section has no name.
2954
 
        # List values are provided as strings and need to be explicitly
2955
 
        # converted by specifying from_unicode=list_from_store at option
2956
 
        # registration
2957
 
        self.assertSectionContent((None, {'foo': 'bar', 'l': u'1,2'}),
 
2585
        # List values are provided as lists
 
2586
        self.assertSectionContent((None, {'foo': 'bar', 'l': ['1', '2']}),
2958
2587
                                  sections[0])
2959
2588
        self.assertSectionContent(
2960
2589
            ('DEFAULT', {'foo_in_DEFAULT': 'foo_DEFAULT'}), sections[1])
2990
2619
 
2991
2620
    def setUp(self):
2992
2621
        super(TestConcurrentStoreUpdates, self).setUp()
 
2622
        self._content = 'one=1\ntwo=2\n'
2993
2623
        self.stack = self.get_stack(self)
2994
2624
        if not isinstance(self.stack, config._CompatibleStack):
2995
2625
            raise tests.TestNotApplicable(
2996
2626
                '%s is not meant to be compatible with the old config design'
2997
2627
                % (self.stack,))
2998
 
        self.stack.set('one', '1')
2999
 
        self.stack.set('two', '2')
 
2628
        self.stack.store._load_from_string(self._content)
3000
2629
        # Flush the store
3001
2630
        self.stack.store.save()
3002
2631
 
3106
2735
    # FIXME: It may be worth looking into removing the lock dir when it's not
3107
2736
    # needed anymore and look at possible fallouts for concurrent lockers. This
3108
2737
    # will matter if/when we use config files outside of bazaar directories
3109
 
    # (.bazaar or .bzr) -- vila 20110-04-111
 
2738
    # (.bazaar or .bzr) -- vila 20110-04-11
3110
2739
 
3111
2740
 
3112
2741
class TestSectionMatcher(TestStore):
3113
2742
 
3114
 
    scenarios = [('location', {'matcher': config.LocationMatcher}),
3115
 
                 ('id', {'matcher': config.NameMatcher}),]
 
2743
    scenarios = [('location', {'matcher': config.LocationMatcher})]
3116
2744
 
3117
 
    def setUp(self):
3118
 
        super(TestSectionMatcher, self).setUp()
3119
 
        # Any simple store is good enough
3120
 
        self.get_store = config.test_store_builder_registry.get('configobj')
 
2745
    def get_store(self, file_name):
 
2746
        return config.IniFileStore(self.get_readonly_transport(), file_name)
3121
2747
 
3122
2748
    def test_no_matches_for_empty_stores(self):
3123
 
        store = self.get_store(self)
 
2749
        store = self.get_store('foo.conf')
3124
2750
        store._load_from_string('')
3125
2751
        matcher = self.matcher(store, '/bar')
3126
2752
        self.assertEquals([], list(matcher.get_sections()))
3127
2753
 
3128
2754
    def test_build_doesnt_load_store(self):
3129
 
        store = self.get_store(self)
 
2755
        store = self.get_store('foo.conf')
3130
2756
        matcher = self.matcher(store, '/bar')
3131
2757
        self.assertFalse(store.is_loaded())
3132
2758
 
3156
2782
 
3157
2783
class TestLocationMatcher(TestStore):
3158
2784
 
3159
 
    def setUp(self):
3160
 
        super(TestLocationMatcher, self).setUp()
3161
 
        # Any simple store is good enough
3162
 
        self.get_store = config.test_store_builder_registry.get('configobj')
3163
 
 
3164
 
    def test_unrelated_section_excluded(self):
3165
 
        store = self.get_store(self)
3166
 
        store._load_from_string('''
3167
 
[/foo]
3168
 
section=/foo
3169
 
[/foo/baz]
3170
 
section=/foo/baz
3171
 
[/foo/bar]
3172
 
section=/foo/bar
3173
 
[/foo/bar/baz]
3174
 
section=/foo/bar/baz
3175
 
[/quux/quux]
3176
 
section=/quux/quux
3177
 
''')
3178
 
        self.assertEquals(['/foo', '/foo/baz', '/foo/bar', '/foo/bar/baz',
3179
 
                           '/quux/quux'],
3180
 
                          [section.id for _, section in store.get_sections()])
3181
 
        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])
3185
 
        self.assertEquals(['/foo/bar', '/foo'],
3186
 
                          [section.id for section in sections])
3187
 
        self.assertEquals(['quux', 'bar/quux'],
3188
 
                          [section.extra_path for section in sections])
 
2785
    def get_store(self, file_name):
 
2786
        return config.IniFileStore(self.get_readonly_transport(), file_name)
3189
2787
 
3190
2788
    def test_more_specific_sections_first(self):
3191
 
        store = self.get_store(self)
 
2789
        store = self.get_store('foo.conf')
3192
2790
        store._load_from_string('''
3193
2791
[/foo]
3194
2792
section=/foo
3196
2794
section=/foo/bar
3197
2795
''')
3198
2796
        self.assertEquals(['/foo', '/foo/bar'],
3199
 
                          [section.id for _, section in store.get_sections()])
 
2797
                          [section.id for section in store.get_sections()])
3200
2798
        matcher = config.LocationMatcher(store, '/foo/bar/baz')
3201
 
        sections = [section for s, section in matcher.get_sections()]
 
2799
        sections = list(matcher.get_sections())
3202
2800
        self.assertEquals([3, 2],
3203
2801
                          [section.length for section in sections])
3204
2802
        self.assertEquals(['/foo/bar', '/foo'],
3209
2807
    def test_appendpath_in_no_name_section(self):
3210
2808
        # It's a bit weird to allow appendpath in a no-name section, but
3211
2809
        # someone may found a use for it
3212
 
        store = self.get_store(self)
 
2810
        store = self.get_store('foo.conf')
3213
2811
        store._load_from_string('''
3214
2812
foo=bar
3215
2813
foo:policy = appendpath
3217
2815
        matcher = config.LocationMatcher(store, 'dir/subdir')
3218
2816
        sections = list(matcher.get_sections())
3219
2817
        self.assertLength(1, sections)
3220
 
        self.assertEquals('bar/dir/subdir', sections[0][1].get('foo'))
 
2818
        self.assertEquals('bar/dir/subdir', sections[0].get('foo'))
3221
2819
 
3222
2820
    def test_file_urls_are_normalized(self):
3223
 
        store = self.get_store(self)
 
2821
        store = self.get_store('foo.conf')
3224
2822
        if sys.platform == 'win32':
3225
2823
            expected_url = 'file:///C:/dir/subdir'
3226
2824
            expected_location = 'C:/dir/subdir'
3231
2829
        self.assertEquals(expected_location, matcher.location)
3232
2830
 
3233
2831
 
3234
 
class TestNameMatcher(TestStore):
3235
 
 
3236
 
    def setUp(self):
3237
 
        super(TestNameMatcher, self).setUp()
3238
 
        self.matcher = config.NameMatcher
3239
 
        # Any simple store is good enough
3240
 
        self.get_store = config.test_store_builder_registry.get('configobj')
3241
 
 
3242
 
    def get_matching_sections(self, name):
3243
 
        store = self.get_store(self)
3244
 
        store._load_from_string('''
3245
 
[foo]
3246
 
option=foo
3247
 
[foo/baz]
3248
 
option=foo/baz
3249
 
[bar]
3250
 
option=bar
3251
 
''')
3252
 
        matcher = self.matcher(store, name)
3253
 
        return list(matcher.get_sections())
3254
 
 
3255
 
    def test_matching(self):
3256
 
        sections = self.get_matching_sections('foo')
3257
 
        self.assertLength(1, sections)
3258
 
        self.assertSectionContent(('foo', {'option': 'foo'}), sections[0])
3259
 
 
3260
 
    def test_not_matching(self):
3261
 
        sections = self.get_matching_sections('baz')
3262
 
        self.assertLength(0, sections)
3263
 
 
3264
 
 
3265
2832
class TestStackGet(tests.TestCase):
3266
2833
 
3267
2834
    # FIXME: This should be parametrized for all known Stack or dedicated
3268
2835
    # paramerized tests created to avoid bloating -- vila 2011-03-31
3269
2836
 
3270
 
    def overrideOptionRegistry(self):
3271
 
        self.overrideAttr(config, 'option_registry', config.OptionRegistry())
3272
 
 
3273
2837
    def test_single_config_get(self):
3274
2838
        conf = dict(foo='bar')
3275
2839
        conf_stack = config.Stack([conf])
3278
2842
    def test_get_with_registered_default_value(self):
3279
2843
        conf_stack = config.Stack([dict()])
3280
2844
        opt = config.Option('foo', default='bar')
3281
 
        self.overrideOptionRegistry()
 
2845
        self.overrideAttr(config, 'option_registry', registry.Registry())
3282
2846
        config.option_registry.register('foo', opt)
3283
2847
        self.assertEquals('bar', conf_stack.get('foo'))
3284
2848
 
3285
2849
    def test_get_without_registered_default_value(self):
3286
2850
        conf_stack = config.Stack([dict()])
3287
2851
        opt = config.Option('foo')
3288
 
        self.overrideOptionRegistry()
 
2852
        self.overrideAttr(config, 'option_registry', registry.Registry())
3289
2853
        config.option_registry.register('foo', opt)
3290
2854
        self.assertEquals(None, conf_stack.get('foo'))
3291
2855
 
3292
2856
    def test_get_without_default_value_for_not_registered(self):
3293
2857
        conf_stack = config.Stack([dict()])
3294
2858
        opt = config.Option('foo')
3295
 
        self.overrideOptionRegistry()
 
2859
        self.overrideAttr(config, 'option_registry', registry.Registry())
3296
2860
        self.assertEquals(None, conf_stack.get('foo'))
3297
2861
 
3298
2862
    def test_get_first_definition(self):
3332
2896
 
3333
2897
class TestStackGet(TestStackWithTransport):
3334
2898
 
3335
 
    def setUp(self):
3336
 
        super(TestStackGet, self).setUp()
3337
 
        self.conf = self.get_stack(self)
3338
 
 
3339
2899
    def test_get_for_empty_stack(self):
3340
 
        self.assertEquals(None, self.conf.get('foo'))
 
2900
        conf = self.get_stack(self)
 
2901
        self.assertEquals(None, conf.get('foo'))
3341
2902
 
3342
2903
    def test_get_hook(self):
3343
 
        self.conf.set('foo', 'bar')
 
2904
        conf = self.get_stack(self)
 
2905
        conf.store._load_from_string('foo=bar')
3344
2906
        calls = []
3345
2907
        def hook(*args):
3346
2908
            calls.append(args)
3347
2909
        config.ConfigHooks.install_named_hook('get', hook, None)
3348
2910
        self.assertLength(0, calls)
3349
 
        value = self.conf.get('foo')
 
2911
        value = conf.get('foo')
3350
2912
        self.assertEquals('bar', value)
3351
2913
        self.assertLength(1, calls)
3352
 
        self.assertEquals((self.conf, 'foo', 'bar'), calls[0])
3353
 
 
3354
 
 
3355
 
class TestStackGetWithConverter(tests.TestCaseWithTransport):
3356
 
 
3357
 
    def setUp(self):
3358
 
        super(TestStackGetWithConverter, self).setUp()
3359
 
        self.overrideAttr(config, 'option_registry', config.OptionRegistry())
3360
 
        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)
3366
 
 
3367
 
    def register_bool_option(self, name, default=None, default_from_env=None):
3368
 
        b = config.Option(name, help='A boolean.',
3369
 
                          default=default, default_from_env=default_from_env,
3370
 
                          from_unicode=config.bool_from_store)
3371
 
        self.registry.register(b)
3372
 
 
3373
 
    def test_get_default_bool_None(self):
3374
 
        self.register_bool_option('foo')
3375
 
        self.assertEquals(None, self.conf.get('foo'))
3376
 
 
3377
 
    def test_get_default_bool_True(self):
3378
 
        self.register_bool_option('foo', u'True')
3379
 
        self.assertEquals(True, self.conf.get('foo'))
3380
 
 
3381
 
    def test_get_default_bool_False(self):
3382
 
        self.register_bool_option('foo', False)
3383
 
        self.assertEquals(False, self.conf.get('foo'))
3384
 
 
3385
 
    def test_get_default_bool_False_as_string(self):
3386
 
        self.register_bool_option('foo', u'False')
3387
 
        self.assertEquals(False, self.conf.get('foo'))
3388
 
 
3389
 
    def test_get_default_bool_from_env_converted(self):
3390
 
        self.register_bool_option('foo', u'True', default_from_env=['FOO'])
3391
 
        self.overrideEnv('FOO', 'False')
3392
 
        self.assertEquals(False, self.conf.get('foo'))
3393
 
 
3394
 
    def test_get_default_bool_when_conversion_fails(self):
3395
 
        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'))
3398
 
 
3399
 
    def register_integer_option(self, name,
3400
 
                                default=None, default_from_env=None):
3401
 
        i = config.Option(name, help='An integer.',
3402
 
                          default=default, default_from_env=default_from_env,
3403
 
                          from_unicode=config.int_from_store)
3404
 
        self.registry.register(i)
3405
 
 
3406
 
    def test_get_default_integer_None(self):
3407
 
        self.register_integer_option('foo')
3408
 
        self.assertEquals(None, self.conf.get('foo'))
3409
 
 
3410
 
    def test_get_default_integer(self):
3411
 
        self.register_integer_option('foo', 42)
3412
 
        self.assertEquals(42, self.conf.get('foo'))
3413
 
 
3414
 
    def test_get_default_integer_as_string(self):
3415
 
        self.register_integer_option('foo', u'42')
3416
 
        self.assertEquals(42, self.conf.get('foo'))
3417
 
 
3418
 
    def test_get_default_integer_from_env(self):
3419
 
        self.register_integer_option('foo', default_from_env=['FOO'])
3420
 
        self.overrideEnv('FOO', '18')
3421
 
        self.assertEquals(18, self.conf.get('foo'))
3422
 
 
3423
 
    def test_get_default_integer_when_conversion_fails(self):
3424
 
        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'))
3427
 
 
3428
 
    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)
3432
 
        self.registry.register(l)
3433
 
 
3434
 
    def test_get_default_list_None(self):
3435
 
        self.register_list_option('foo')
3436
 
        self.assertEquals(None, self.conf.get('foo'))
3437
 
 
3438
 
    def test_get_default_list_empty(self):
3439
 
        self.register_list_option('foo', '')
3440
 
        self.assertEquals([], self.conf.get('foo'))
3441
 
 
3442
 
    def test_get_default_list_from_env(self):
3443
 
        self.register_list_option('foo', default_from_env=['FOO'])
3444
 
        self.overrideEnv('FOO', '')
3445
 
        self.assertEquals([], self.conf.get('foo'))
3446
 
 
3447
 
    def test_get_with_list_converter_no_item(self):
3448
 
        self.register_list_option('foo', None)
3449
 
        self.conf.store._load_from_string('foo=,')
3450
 
        self.assertEquals([], self.conf.get('foo'))
3451
 
 
3452
 
    def test_get_with_list_converter_many_items(self):
3453
 
        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'))
3456
 
 
3457
 
    def test_get_with_list_converter_embedded_spaces_many_items(self):
3458
 
        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'))
3461
 
 
3462
 
    def test_get_with_list_converter_stripped_spaces_many_items(self):
3463
 
        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'))
3466
 
 
3467
 
 
3468
 
class TestIterOptionRefs(tests.TestCase):
3469
 
    """iter_option_refs is a bit unusual, document some cases."""
3470
 
 
3471
 
    def assertRefs(self, expected, string):
3472
 
        self.assertEquals(expected, list(config.iter_option_refs(string)))
3473
 
 
3474
 
    def test_empty(self):
3475
 
        self.assertRefs([(False, '')], '')
3476
 
 
3477
 
    def test_no_refs(self):
3478
 
        self.assertRefs([(False, 'foo bar')], 'foo bar')
3479
 
 
3480
 
    def test_single_ref(self):
3481
 
        self.assertRefs([(False, ''), (True, '{foo}'), (False, '')], '{foo}')
3482
 
 
3483
 
    def test_broken_ref(self):
3484
 
        self.assertRefs([(False, '{foo')], '{foo')
3485
 
 
3486
 
    def test_embedded_ref(self):
3487
 
        self.assertRefs([(False, '{'), (True, '{foo}'), (False, '}')],
3488
 
                        '{{foo}}')
3489
 
 
3490
 
    def test_two_refs(self):
3491
 
        self.assertRefs([(False, ''), (True, '{foo}'),
3492
 
                         (False, ''), (True, '{bar}'),
3493
 
                         (False, ''),],
3494
 
                        '{foo}{bar}')
3495
 
 
3496
 
 
3497
 
class TestStackExpandOptions(tests.TestCaseWithTransport):
3498
 
 
3499
 
    def setUp(self):
3500
 
        super(TestStackExpandOptions, self).setUp()
3501
 
        self.overrideAttr(config, 'option_registry', config.OptionRegistry())
3502
 
        self.registry = config.option_registry
3503
 
        self.conf = build_branch_stack(self)
3504
 
 
3505
 
    def assertExpansion(self, expected, string, env=None):
3506
 
        self.assertEquals(expected, self.conf.expand_options(string, env))
3507
 
 
3508
 
    def test_no_expansion(self):
3509
 
        self.assertExpansion('foo', 'foo')
3510
 
 
3511
 
    def test_expand_default_value(self):
3512
 
        self.conf.store._load_from_string('bar=baz')
3513
 
        self.registry.register(config.Option('foo', default=u'{bar}'))
3514
 
        self.assertEquals('baz', self.conf.get('foo', expand=True))
3515
 
 
3516
 
    def test_expand_default_from_env(self):
3517
 
        self.conf.store._load_from_string('bar=baz')
3518
 
        self.registry.register(config.Option('foo', default_from_env=['FOO']))
3519
 
        self.overrideEnv('FOO', '{bar}')
3520
 
        self.assertEquals('baz', self.conf.get('foo', expand=True))
3521
 
 
3522
 
    def test_expand_default_on_failed_conversion(self):
3523
 
        self.conf.store._load_from_string('baz=bogus\nbar=42\nfoo={baz}')
3524
 
        self.registry.register(
3525
 
            config.Option('foo', default=u'{bar}',
3526
 
                          from_unicode=config.int_from_store))
3527
 
        self.assertEquals(42, self.conf.get('foo', expand=True))
3528
 
 
3529
 
    def test_env_adding_options(self):
3530
 
        self.assertExpansion('bar', '{foo}', {'foo': 'bar'})
3531
 
 
3532
 
    def test_env_overriding_options(self):
3533
 
        self.conf.store._load_from_string('foo=baz')
3534
 
        self.assertExpansion('bar', '{foo}', {'foo': 'bar'})
3535
 
 
3536
 
    def test_simple_ref(self):
3537
 
        self.conf.store._load_from_string('foo=xxx')
3538
 
        self.assertExpansion('xxx', '{foo}')
3539
 
 
3540
 
    def test_unknown_ref(self):
3541
 
        self.assertRaises(errors.ExpandingUnknownOption,
3542
 
                          self.conf.expand_options, '{foo}')
3543
 
 
3544
 
    def test_indirect_ref(self):
3545
 
        self.conf.store._load_from_string('''
3546
 
foo=xxx
3547
 
bar={foo}
3548
 
''')
3549
 
        self.assertExpansion('xxx', '{bar}')
3550
 
 
3551
 
    def test_embedded_ref(self):
3552
 
        self.conf.store._load_from_string('''
3553
 
foo=xxx
3554
 
bar=foo
3555
 
''')
3556
 
        self.assertExpansion('xxx', '{{bar}}')
3557
 
 
3558
 
    def test_simple_loop(self):
3559
 
        self.conf.store._load_from_string('foo={foo}')
3560
 
        self.assertRaises(errors.OptionExpansionLoop,
3561
 
                          self.conf.expand_options, '{foo}')
3562
 
 
3563
 
    def test_indirect_loop(self):
3564
 
        self.conf.store._load_from_string('''
3565
 
foo={bar}
3566
 
bar={baz}
3567
 
baz={foo}''')
3568
 
        e = self.assertRaises(errors.OptionExpansionLoop,
3569
 
                              self.conf.expand_options, '{foo}')
3570
 
        self.assertEquals('foo->bar->baz', e.refs)
3571
 
        self.assertEquals('{foo}', e.string)
3572
 
 
3573
 
    def test_list(self):
3574
 
        self.conf.store._load_from_string('''
3575
 
foo=start
3576
 
bar=middle
3577
 
baz=end
3578
 
list={foo},{bar},{baz}
3579
 
''')
3580
 
        self.registry.register(
3581
 
            config.Option('list', from_unicode=config.list_from_store))
3582
 
        self.assertEquals(['start', 'middle', 'end'],
3583
 
                           self.conf.get('list', expand=True))
3584
 
 
3585
 
    def test_cascading_list(self):
3586
 
        self.conf.store._load_from_string('''
3587
 
foo=start,{bar}
3588
 
bar=middle,{baz}
3589
 
baz=end
3590
 
list={foo}
3591
 
''')
3592
 
        self.registry.register(
3593
 
            config.Option('list', from_unicode=config.list_from_store))
3594
 
        self.assertEquals(['start', 'middle', 'end'],
3595
 
                           self.conf.get('list', expand=True))
3596
 
 
3597
 
    def test_pathologically_hidden_list(self):
3598
 
        self.conf.store._load_from_string('''
3599
 
foo=bin
3600
 
bar=go
3601
 
start={foo
3602
 
middle=},{
3603
 
end=bar}
3604
 
hidden={start}{middle}{end}
3605
 
''')
3606
 
        # What matters is what the registration says, the conversion happens
3607
 
        # only after all expansions have been performed
3608
 
        self.registry.register(
3609
 
            config.Option('hidden', from_unicode=config.list_from_store))
3610
 
        self.assertEquals(['bin', 'go'],
3611
 
                          self.conf.get('hidden', expand=True))
3612
 
 
3613
 
 
3614
 
class TestStackCrossSectionsExpand(tests.TestCaseWithTransport):
3615
 
 
3616
 
    def setUp(self):
3617
 
        super(TestStackCrossSectionsExpand, self).setUp()
3618
 
 
3619
 
    def get_config(self, location, string):
3620
 
        if string is None:
3621
 
            string = ''
3622
 
        # Since we don't save the config we won't strictly require to inherit
3623
 
        # from TestCaseInTempDir, but an error occurs so quickly...
3624
 
        c = config.LocationStack(location)
3625
 
        c.store._load_from_string(string)
3626
 
        return c
3627
 
 
3628
 
    def test_dont_cross_unrelated_section(self):
3629
 
        c = self.get_config('/another/branch/path','''
3630
 
[/one/branch/path]
3631
 
foo = hello
3632
 
bar = {foo}/2
3633
 
 
3634
 
[/another/branch/path]
3635
 
bar = {foo}/2
3636
 
''')
3637
 
        self.assertRaises(errors.ExpandingUnknownOption,
3638
 
                          c.get, 'bar', expand=True)
3639
 
 
3640
 
    def test_cross_related_sections(self):
3641
 
        c = self.get_config('/project/branch/path','''
3642
 
[/project]
3643
 
foo = qu
3644
 
 
3645
 
[/project/branch/path]
3646
 
bar = {foo}ux
3647
 
''')
3648
 
        self.assertEquals('quux', c.get('bar', expand=True))
3649
 
 
3650
 
 
3651
 
class TestStackCrossStoresExpand(tests.TestCaseWithTransport):
3652
 
 
3653
 
    def test_cross_global_locations(self):
3654
 
        l_store = config.LocationStore()
3655
 
        l_store._load_from_string('''
3656
 
[/branch]
3657
 
lfoo = loc-foo
3658
 
lbar = {gbar}
3659
 
''')
3660
 
        l_store.save()
3661
 
        g_store = config.GlobalStore()
3662
 
        g_store._load_from_string('''
3663
 
[DEFAULT]
3664
 
gfoo = {lfoo}
3665
 
gbar = glob-bar
3666
 
''')
3667
 
        g_store.save()
3668
 
        stack = config.LocationStack('/branch')
3669
 
        self.assertEquals('glob-bar', stack.get('lbar', expand=True))
3670
 
        self.assertEquals('loc-foo', stack.get('gfoo', expand=True))
3671
 
 
3672
 
 
3673
 
class TestStackExpandSectionLocals(tests.TestCaseWithTransport):
3674
 
 
3675
 
    def test_expand_locals_empty(self):
3676
 
        l_store = config.LocationStore()
3677
 
        l_store._load_from_string('''
3678
 
[/home/user/project]
3679
 
base = {basename}
3680
 
rel = {relpath}
3681
 
''')
3682
 
        l_store.save()
3683
 
        stack = config.LocationStack('/home/user/project/')
3684
 
        self.assertEquals('', stack.get('base', expand=True))
3685
 
        self.assertEquals('', stack.get('rel', expand=True))
3686
 
 
3687
 
    def test_expand_basename_locally(self):
3688
 
        l_store = config.LocationStore()
3689
 
        l_store._load_from_string('''
3690
 
[/home/user/project]
3691
 
bfoo = {basename}
3692
 
''')
3693
 
        l_store.save()
3694
 
        stack = config.LocationStack('/home/user/project/branch')
3695
 
        self.assertEquals('branch', stack.get('bfoo', expand=True))
3696
 
 
3697
 
    def test_expand_basename_locally_longer_path(self):
3698
 
        l_store = config.LocationStore()
3699
 
        l_store._load_from_string('''
3700
 
[/home/user]
3701
 
bfoo = {basename}
3702
 
''')
3703
 
        l_store.save()
3704
 
        stack = config.LocationStack('/home/user/project/dir/branch')
3705
 
        self.assertEquals('branch', stack.get('bfoo', expand=True))
3706
 
 
3707
 
    def test_expand_relpath_locally(self):
3708
 
        l_store = config.LocationStore()
3709
 
        l_store._load_from_string('''
3710
 
[/home/user/project]
3711
 
lfoo = loc-foo/{relpath}
3712
 
''')
3713
 
        l_store.save()
3714
 
        stack = config.LocationStack('/home/user/project/branch')
3715
 
        self.assertEquals('loc-foo/branch', stack.get('lfoo', expand=True))
3716
 
 
3717
 
    def test_expand_relpath_unknonw_in_global(self):
3718
 
        g_store = config.GlobalStore()
3719
 
        g_store._load_from_string('''
3720
 
[DEFAULT]
3721
 
gfoo = {relpath}
3722
 
''')
3723
 
        g_store.save()
3724
 
        stack = config.LocationStack('/home/user/project/branch')
3725
 
        self.assertRaises(errors.ExpandingUnknownOption,
3726
 
                          stack.get, 'gfoo', expand=True)
3727
 
 
3728
 
    def test_expand_local_option_locally(self):
3729
 
        l_store = config.LocationStore()
3730
 
        l_store._load_from_string('''
3731
 
[/home/user/project]
3732
 
lfoo = loc-foo/{relpath}
3733
 
lbar = {gbar}
3734
 
''')
3735
 
        l_store.save()
3736
 
        g_store = config.GlobalStore()
3737
 
        g_store._load_from_string('''
3738
 
[DEFAULT]
3739
 
gfoo = {lfoo}
3740
 
gbar = glob-bar
3741
 
''')
3742
 
        g_store.save()
3743
 
        stack = config.LocationStack('/home/user/project/branch')
3744
 
        self.assertEquals('glob-bar', stack.get('lbar', expand=True))
3745
 
        self.assertEquals('loc-foo/branch', stack.get('gfoo', expand=True))
3746
 
 
3747
 
    def test_locals_dont_leak(self):
3748
 
        """Make sure we chose the right local in presence of several sections.
3749
 
        """
3750
 
        l_store = config.LocationStore()
3751
 
        l_store._load_from_string('''
3752
 
[/home/user]
3753
 
lfoo = loc-foo/{relpath}
3754
 
[/home/user/project]
3755
 
lfoo = loc-foo/{relpath}
3756
 
''')
3757
 
        l_store.save()
3758
 
        stack = config.LocationStack('/home/user/project/branch')
3759
 
        self.assertEquals('loc-foo/branch', stack.get('lfoo', expand=True))
3760
 
        stack = config.LocationStack('/home/user/bar/baz')
3761
 
        self.assertEquals('loc-foo/bar/baz', stack.get('lfoo', expand=True))
3762
 
 
 
2914
        self.assertEquals((conf, 'foo', 'bar'), calls[0])
3763
2915
 
3764
2916
 
3765
2917
class TestStackSet(TestStackWithTransport):
3766
2918
 
3767
2919
    def test_simple_set(self):
3768
2920
        conf = self.get_stack(self)
3769
 
        self.assertEquals(None, conf.get('foo'))
 
2921
        conf.store._load_from_string('foo=bar')
 
2922
        self.assertEquals('bar', conf.get('foo'))
3770
2923
        conf.set('foo', 'baz')
3771
2924
        # Did we get it back ?
3772
2925
        self.assertEquals('baz', conf.get('foo'))
3792
2945
 
3793
2946
    def test_remove_existing(self):
3794
2947
        conf = self.get_stack(self)
3795
 
        conf.set('foo', 'bar')
 
2948
        conf.store._load_from_string('foo=bar')
3796
2949
        self.assertEquals('bar', conf.get('foo'))
3797
2950
        conf.remove('foo')
3798
2951
        # Did we get it back ?
3809
2962
        config.ConfigHooks.install_named_hook('remove', hook, None)
3810
2963
        self.assertLength(0, calls)
3811
2964
        conf = self.get_stack(self)
3812
 
        conf.set('foo', 'bar')
 
2965
        conf.store._load_from_string('foo=bar')
3813
2966
        conf.remove('foo')
3814
2967
        self.assertLength(1, calls)
3815
2968
        self.assertEquals((conf, 'foo'), calls[0])
3990
3143
        conf = config.AuthenticationConfig(_file=StringIO(
3991
3144
                'foo = bar\xff'))
3992
3145
        self.assertRaises(errors.ConfigContentError, conf._get_config)
3993
 
 
 
3146
        
3994
3147
    def test_missing_auth_section_header(self):
3995
3148
        conf = config.AuthenticationConfig(_file=StringIO('foo = bar'))
3996
3149
        self.assertRaises(ValueError, conf.get_credentials, 'ftp', 'foo.net')