~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_config.py

  • Committer: Patch Queue Manager
  • Date: 2011-10-14 16:54:26 UTC
  • mfrom: (6216.1.1 remove-this-file)
  • Revision ID: pqm@pqm.ubuntu.com-20111014165426-tjix4e6idryf1r2z
(jelmer) Remove an accidentally committed .THIS file. (Jelmer Vernooij)

Show diffs side-by-side

added added

removed removed

Lines of Context:
33
33
    errors,
34
34
    osutils,
35
35
    mail_client,
36
 
    mergetools,
37
36
    ui,
38
37
    urlutils,
39
 
    registry,
40
38
    remote,
41
39
    tests,
42
40
    trace,
43
 
    transport,
44
41
    )
45
42
from bzrlib.symbol_versioning import (
46
43
    deprecated_in,
47
 
    deprecated_method,
48
44
    )
49
45
from bzrlib.transport import remote as transport_remote
50
46
from bzrlib.tests import (
116
112
config.test_store_builder_registry.register('branch', build_branch_store)
117
113
 
118
114
 
 
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
 
119
122
def build_remote_branch_store(test):
120
123
    # There is only one permutation (but we won't be able to handle more with
121
124
    # this design anyway)
148
151
     server_class) = transport_remote.get_test_permutations()[0]
149
152
    build_backing_branch(test, 'branch', transport_class, server_class)
150
153
    b = branch.Branch.open(test.get_url('branch'))
151
 
    return config.BranchStack(b)
 
154
    return config.RemoteBranchStack(b)
152
155
config.test_stack_builder_registry.register('remote_branch',
153
156
                                            build_remote_branch_stack)
154
157
 
 
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
 
155
171
 
156
172
sample_long_alias="log -r-15..-1 --line"
157
173
sample_config_text = u"""
160
176
editor=vim
161
177
change_editor=vimdiff -of @new_path @old_path
162
178
gpg_signing_command=gnome-gpg
 
179
gpg_signing_key=DD4D5088
163
180
log_format=short
 
181
validate_signatures_in_log=true
 
182
acceptable_keys=amy
164
183
user_global_option=something
165
184
bzr.mergetool.sometool=sometool {base} {this} {other} -o {result}
166
185
bzr.mergetool.funkytool=funkytool "arg with spaces" {this_temp}
 
186
bzr.mergetool.newtool='"newtool with spaces" {this_temp}'
167
187
bzr.default_mergetool=sometool
168
188
[ALIASES]
169
189
h=help
212
232
[/a/]
213
233
check_signatures=check-available
214
234
gpg_signing_command=false
 
235
gpg_signing_key=default
215
236
user_local_option=local
216
237
# test trailing / matching
217
238
[/a/*]
513
534
        my_config = config.Config()
514
535
        self.assertEqual('long', my_config.log_format())
515
536
 
 
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
 
516
545
    def test_get_change_editor(self):
517
546
        my_config = InstrumentedConfig()
518
547
        change_editor = my_config.get_change_editor('old_tree', 'new_tree')
807
836
        self.assertEquals(['{foo', '}', '{', 'bar}'],
808
837
                          conf.get_user_option('hidden', expand=True))
809
838
 
 
839
 
810
840
class TestLocationConfigOptionExpansion(tests.TestCaseInTempDir):
811
841
 
812
842
    def get_config(self, location, string=None):
1023
1053
        # automatically cast to list
1024
1054
        self.assertEqual(['x'], get_list('one_item'))
1025
1055
 
 
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))
1026
1076
 
1027
1077
class TestSupressWarning(TestIniConfig):
1028
1078
 
1215
1265
        self.assertEqual("gnome-gpg", my_config.gpg_signing_command())
1216
1266
        self.assertEqual(False, my_config.signature_needed())
1217
1267
 
 
1268
    def test_gpg_signing_key(self):
 
1269
        my_config = self._get_sample_config()
 
1270
        self.assertEqual("DD4D5088", my_config.gpg_signing_key())
 
1271
 
1218
1272
    def _get_empty_config(self):
1219
1273
        my_config = config.GlobalConfig()
1220
1274
        return my_config
1240
1294
        my_config = self._get_sample_config()
1241
1295
        self.assertEqual("short", my_config.log_format())
1242
1296
 
 
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
 
1243
1305
    def test_get_alias(self):
1244
1306
        my_config = self._get_sample_config()
1245
1307
        self.assertEqual('help', my_config.get_alias('h'))
1278
1340
        self.log(repr(tools))
1279
1341
        self.assertEqual(
1280
1342
            {u'funkytool' : u'funkytool "arg with spaces" {this_temp}',
1281
 
            u'sometool' : u'sometool {base} {this} {other} -o {result}'},
 
1343
            u'sometool' : u'sometool {base} {this} {other} -o {result}',
 
1344
            u'newtool' : u'"newtool with spaces" {this_temp}'},
1282
1345
            tools)
1283
1346
 
1284
1347
    def test_get_merge_tools_empty(self):
1502
1565
        self.get_branch_config('/a')
1503
1566
        self.assertEqual("false", self.my_config.gpg_signing_command())
1504
1567
 
 
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
 
1505
1576
    def test_get_user_option_global(self):
1506
1577
        self.get_branch_config('/a')
1507
1578
        self.assertEqual('something',
1896
1967
        conf = config.TransportConfig(t, 'foo.conf')
1897
1968
        self.assertRaises(errors.ParseConfigError, conf._get_configobj)
1898
1969
 
 
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
 
1899
1993
    def test_get_value(self):
1900
1994
        """Test that retreiving a value from a section is possible"""
1901
1995
        bzrdir_config = config.TransportConfig(self.get_transport('.'),
2181
2275
        opt = config.Option('foo', default='bar')
2182
2276
        self.assertEquals('bar', opt.get_default())
2183
2277
 
 
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
 
2184
2485
 
2185
2486
class TestOptionRegistry(tests.TestCase):
2186
2487
 
2187
2488
    def setUp(self):
2188
2489
        super(TestOptionRegistry, self).setUp()
2189
2490
        # Always start with an empty registry
2190
 
        self.overrideAttr(config, 'option_registry', registry.Registry())
 
2491
        self.overrideAttr(config, 'option_registry', config.OptionRegistry())
2191
2492
        self.registry = config.option_registry
2192
2493
 
2193
2494
    def test_register(self):
2194
2495
        opt = config.Option('foo')
2195
 
        self.registry.register('foo', opt)
 
2496
        self.registry.register(opt)
2196
2497
        self.assertIs(opt, self.registry.get('foo'))
2197
2498
 
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
 
 
2205
2499
    def test_registered_help(self):
2206
 
        opt = config.Option('foo')
2207
 
        self.registry.register('foo', opt, help='A simple option')
 
2500
        opt = config.Option('foo', help='A simple option')
 
2501
        self.registry.register(opt)
2208
2502
        self.assertEquals('A simple option', self.registry.get_help('foo'))
2209
2503
 
 
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
 
2210
2516
 
2211
2517
class TestRegisteredOptions(tests.TestCase):
2212
2518
    """All registered options should verify some constraints."""
2226
2532
    def test_help_is_set(self):
2227
2533
        option_help = self.registry.get_help(self.option_name)
2228
2534
        self.assertNotEquals(None, option_help)
2229
 
        # Come on, think about the user, he really wants to know whst the
 
2535
        # Come on, think about the user, he really wants to know what the
2230
2536
        # option is about
 
2537
        self.assertIsNot(None, option_help)
2231
2538
        self.assertNotEquals('', option_help)
2232
2539
 
2233
2540
 
2255
2562
 
2256
2563
class TestMutableSection(tests.TestCase):
2257
2564
 
2258
 
    # FIXME: Parametrize so that all sections (including os.environ and the
2259
 
    # ones produced by Stores) run these tests -- vila 2011-04-01
 
2565
    scenarios = [('mutable',
 
2566
                  {'get_section':
 
2567
                       lambda opts: config.MutableSection('myID', opts)},),
 
2568
                 ('cmdline',
 
2569
                  {'get_section':
 
2570
                       lambda opts: config.CommandLineSection(opts)},),
 
2571
        ]
2260
2572
 
2261
2573
    def test_set(self):
2262
2574
        a_dict = dict(foo='bar')
2263
 
        section = config.MutableSection('myID', a_dict)
 
2575
        section = self.get_section(a_dict)
2264
2576
        section.set('foo', 'new_value')
2265
2577
        self.assertEquals('new_value', section.get('foo'))
2266
2578
        # The change appears in the shared section
2271
2583
 
2272
2584
    def test_set_preserve_original_once(self):
2273
2585
        a_dict = dict(foo='bar')
2274
 
        section = config.MutableSection('myID', a_dict)
 
2586
        section = self.get_section(a_dict)
2275
2587
        section.set('foo', 'first_value')
2276
2588
        section.set('foo', 'second_value')
2277
2589
        # We keep track of the original value
2280
2592
 
2281
2593
    def test_remove(self):
2282
2594
        a_dict = dict(foo='bar')
2283
 
        section = config.MutableSection('myID', a_dict)
 
2595
        section = self.get_section(a_dict)
2284
2596
        section.remove('foo')
2285
2597
        # We get None for unknown options via the default value
2286
2598
        self.assertEquals(None, section.get('foo'))
2293
2605
 
2294
2606
    def test_remove_new_option(self):
2295
2607
        a_dict = dict()
2296
 
        section = config.MutableSection('myID', a_dict)
 
2608
        section = self.get_section(a_dict)
2297
2609
        section.set('foo', 'bar')
2298
2610
        section.remove('foo')
2299
2611
        self.assertFalse('foo' in section.options)
2303
2615
        self.assertEquals(config._NewlyCreatedOption, section.orig['foo'])
2304
2616
 
2305
2617
 
 
2618
class TestCommandLineSection(tests.TestCase):
 
2619
 
 
2620
    def setUp(self):
 
2621
        super(TestCommandLineSection, self).setUp()
 
2622
        self.section = config.CommandLineSection()
 
2623
 
 
2624
    def test_no_override(self):
 
2625
        self.section._from_cmdline([])
 
2626
        # FIXME: we want some iterator over all options, failing that, we peek
 
2627
        # under the cover -- vila 2011-09026
 
2628
        self.assertLength(0, self.section.options)
 
2629
 
 
2630
    def test_simple_override(self):
 
2631
        self.section._from_cmdline(['a=b'])
 
2632
        self.assertEqual('b', self.section.get('a'))
 
2633
 
 
2634
    def test_list_override(self):
 
2635
        self.section._from_cmdline(['l=1,2,3'])
 
2636
        val = self.section.get('l')
 
2637
        self.assertEqual('1,2,3', val)
 
2638
        # Reminder: lists should registered as such explicitely, otherwise the
 
2639
        # conversion needs to be done afterwards.
 
2640
        self.assertEqual(['1', '2', '3'], config.list_from_store(val))
 
2641
 
 
2642
    def test_multiple_overrides(self):
 
2643
        self.section._from_cmdline(['a=b', 'x=y'])
 
2644
        self.assertEquals('b', self.section.get('a'))
 
2645
        self.assertEquals('y', self.section.get('x'))
 
2646
 
 
2647
    def test_wrong_syntax(self):
 
2648
        self.assertRaises(errors.BzrCommandError,
 
2649
                          self.section._from_cmdline, ['a=b', 'c'])
 
2650
 
 
2651
 
2306
2652
class TestStore(tests.TestCaseWithTransport):
2307
2653
 
2308
2654
    def assertSectionContent(self, expected, section):
2319
2665
    scenarios = [(key, {'get_store': builder}) for key, builder
2320
2666
                 in config.test_store_builder_registry.iteritems()]
2321
2667
 
2322
 
    def setUp(self):
2323
 
        super(TestReadonlyStore, self).setUp()
2324
 
 
2325
2668
    def test_building_delays_load(self):
2326
2669
        store = self.get_store(self)
2327
2670
        self.assertEquals(False, store.is_loaded())
2354
2697
 
2355
2698
 
2356
2699
class TestIniFileStoreContent(tests.TestCaseWithTransport):
2357
 
    """Simulate loading a config store without content of various encodings.
 
2700
    """Simulate loading a config store with content of various encodings.
2358
2701
 
2359
2702
    All files produced by bzr are in utf8 content.
2360
2703
 
2392
2735
        store = config.IniFileStore(t, 'foo.conf')
2393
2736
        self.assertRaises(errors.ParseConfigError, store.load)
2394
2737
 
 
2738
    def test_load_permission_denied(self):
 
2739
        """Ensure we get warned when trying to load an inaccessible file."""
 
2740
        warnings = []
 
2741
        def warning(*args):
 
2742
            warnings.append(args[0] % args[1:])
 
2743
        self.overrideAttr(trace, 'warning', warning)
 
2744
 
 
2745
        t = self.get_transport()
 
2746
 
 
2747
        def get_bytes(relpath):
 
2748
            raise errors.PermissionDenied(relpath, "")
 
2749
        t.get_bytes = get_bytes
 
2750
        store = config.IniFileStore(t, 'foo.conf')
 
2751
        self.assertRaises(errors.PermissionDenied, store.load)
 
2752
        self.assertEquals(
 
2753
            warnings,
 
2754
            [u'Permission denied while trying to load configuration store %s.'
 
2755
             % store.external_url()])
 
2756
 
2395
2757
 
2396
2758
class TestIniConfigContent(tests.TestCaseWithTransport):
2397
 
    """Simulate loading a IniBasedConfig without content of various encodings.
 
2759
    """Simulate loading a IniBasedConfig with content of various encodings.
2398
2760
 
2399
2761
    All files produced by bzr are in utf8 content.
2400
2762
 
2582
2944
        sections = list(store.get_sections())
2583
2945
        self.assertLength(4, sections)
2584
2946
        # The default section has no name.
2585
 
        # List values are provided as lists
2586
 
        self.assertSectionContent((None, {'foo': 'bar', 'l': ['1', '2']}),
 
2947
        # List values are provided as strings and need to be explicitly
 
2948
        # converted by specifying from_unicode=list_from_store at option
 
2949
        # registration
 
2950
        self.assertSectionContent((None, {'foo': 'bar', 'l': u'1,2'}),
2587
2951
                                  sections[0])
2588
2952
        self.assertSectionContent(
2589
2953
            ('DEFAULT', {'foo_in_DEFAULT': 'foo_DEFAULT'}), sections[1])
2735
3099
    # FIXME: It may be worth looking into removing the lock dir when it's not
2736
3100
    # needed anymore and look at possible fallouts for concurrent lockers. This
2737
3101
    # will matter if/when we use config files outside of bazaar directories
2738
 
    # (.bazaar or .bzr) -- vila 20110-04-11
 
3102
    # (.bazaar or .bzr) -- vila 20110-04-111
2739
3103
 
2740
3104
 
2741
3105
class TestSectionMatcher(TestStore):
2742
3106
 
2743
 
    scenarios = [('location', {'matcher': config.LocationMatcher})]
 
3107
    scenarios = [('location', {'matcher': config.LocationMatcher}),
 
3108
                 ('id', {'matcher': config.NameMatcher}),]
2744
3109
 
2745
 
    def get_store(self, file_name):
2746
 
        return config.IniFileStore(self.get_readonly_transport(), file_name)
 
3110
    def setUp(self):
 
3111
        super(TestSectionMatcher, self).setUp()
 
3112
        # Any simple store is good enough
 
3113
        self.get_store = config.test_store_builder_registry.get('configobj')
2747
3114
 
2748
3115
    def test_no_matches_for_empty_stores(self):
2749
 
        store = self.get_store('foo.conf')
 
3116
        store = self.get_store(self)
2750
3117
        store._load_from_string('')
2751
3118
        matcher = self.matcher(store, '/bar')
2752
3119
        self.assertEquals([], list(matcher.get_sections()))
2753
3120
 
2754
3121
    def test_build_doesnt_load_store(self):
2755
 
        store = self.get_store('foo.conf')
 
3122
        store = self.get_store(self)
2756
3123
        matcher = self.matcher(store, '/bar')
2757
3124
        self.assertFalse(store.is_loaded())
2758
3125
 
2782
3149
 
2783
3150
class TestLocationMatcher(TestStore):
2784
3151
 
2785
 
    def get_store(self, file_name):
2786
 
        return config.IniFileStore(self.get_readonly_transport(), file_name)
 
3152
    def setUp(self):
 
3153
        super(TestLocationMatcher, self).setUp()
 
3154
        # Any simple store is good enough
 
3155
        self.get_store = config.test_store_builder_registry.get('configobj')
 
3156
 
 
3157
    def test_unrelated_section_excluded(self):
 
3158
        store = self.get_store(self)
 
3159
        store._load_from_string('''
 
3160
[/foo]
 
3161
section=/foo
 
3162
[/foo/baz]
 
3163
section=/foo/baz
 
3164
[/foo/bar]
 
3165
section=/foo/bar
 
3166
[/foo/bar/baz]
 
3167
section=/foo/bar/baz
 
3168
[/quux/quux]
 
3169
section=/quux/quux
 
3170
''')
 
3171
        self.assertEquals(['/foo', '/foo/baz', '/foo/bar', '/foo/bar/baz',
 
3172
                           '/quux/quux'],
 
3173
                          [section.id for section in store.get_sections()])
 
3174
        matcher = config.LocationMatcher(store, '/foo/bar/quux')
 
3175
        sections = list(matcher.get_sections())
 
3176
        self.assertEquals([3, 2],
 
3177
                          [section.length for section in sections])
 
3178
        self.assertEquals(['/foo/bar', '/foo'],
 
3179
                          [section.id for section in sections])
 
3180
        self.assertEquals(['quux', 'bar/quux'],
 
3181
                          [section.extra_path for section in sections])
2787
3182
 
2788
3183
    def test_more_specific_sections_first(self):
2789
 
        store = self.get_store('foo.conf')
 
3184
        store = self.get_store(self)
2790
3185
        store._load_from_string('''
2791
3186
[/foo]
2792
3187
section=/foo
2807
3202
    def test_appendpath_in_no_name_section(self):
2808
3203
        # It's a bit weird to allow appendpath in a no-name section, but
2809
3204
        # someone may found a use for it
2810
 
        store = self.get_store('foo.conf')
 
3205
        store = self.get_store(self)
2811
3206
        store._load_from_string('''
2812
3207
foo=bar
2813
3208
foo:policy = appendpath
2818
3213
        self.assertEquals('bar/dir/subdir', sections[0].get('foo'))
2819
3214
 
2820
3215
    def test_file_urls_are_normalized(self):
2821
 
        store = self.get_store('foo.conf')
 
3216
        store = self.get_store(self)
2822
3217
        if sys.platform == 'win32':
2823
3218
            expected_url = 'file:///C:/dir/subdir'
2824
3219
            expected_location = 'C:/dir/subdir'
2829
3224
        self.assertEquals(expected_location, matcher.location)
2830
3225
 
2831
3226
 
 
3227
class TestNameMatcher(TestStore):
 
3228
 
 
3229
    def setUp(self):
 
3230
        super(TestNameMatcher, self).setUp()
 
3231
        self.matcher = config.NameMatcher
 
3232
        # Any simple store is good enough
 
3233
        self.get_store = config.test_store_builder_registry.get('configobj')
 
3234
 
 
3235
    def get_matching_sections(self, name):
 
3236
        store = self.get_store(self)
 
3237
        store._load_from_string('''
 
3238
[foo]
 
3239
option=foo
 
3240
[foo/baz]
 
3241
option=foo/baz
 
3242
[bar]
 
3243
option=bar
 
3244
''')
 
3245
        matcher = self.matcher(store, name)
 
3246
        return list(matcher.get_sections())
 
3247
 
 
3248
    def test_matching(self):
 
3249
        sections = self.get_matching_sections('foo')
 
3250
        self.assertLength(1, sections)
 
3251
        self.assertSectionContent(('foo', {'option': 'foo'}), sections[0])
 
3252
 
 
3253
    def test_not_matching(self):
 
3254
        sections = self.get_matching_sections('baz')
 
3255
        self.assertLength(0, sections)
 
3256
 
 
3257
 
2832
3258
class TestStackGet(tests.TestCase):
2833
3259
 
2834
3260
    # FIXME: This should be parametrized for all known Stack or dedicated
2835
3261
    # paramerized tests created to avoid bloating -- vila 2011-03-31
2836
3262
 
 
3263
    def overrideOptionRegistry(self):
 
3264
        self.overrideAttr(config, 'option_registry', config.OptionRegistry())
 
3265
 
2837
3266
    def test_single_config_get(self):
2838
3267
        conf = dict(foo='bar')
2839
3268
        conf_stack = config.Stack([conf])
2842
3271
    def test_get_with_registered_default_value(self):
2843
3272
        conf_stack = config.Stack([dict()])
2844
3273
        opt = config.Option('foo', default='bar')
2845
 
        self.overrideAttr(config, 'option_registry', registry.Registry())
 
3274
        self.overrideOptionRegistry()
2846
3275
        config.option_registry.register('foo', opt)
2847
3276
        self.assertEquals('bar', conf_stack.get('foo'))
2848
3277
 
2849
3278
    def test_get_without_registered_default_value(self):
2850
3279
        conf_stack = config.Stack([dict()])
2851
3280
        opt = config.Option('foo')
2852
 
        self.overrideAttr(config, 'option_registry', registry.Registry())
 
3281
        self.overrideOptionRegistry()
2853
3282
        config.option_registry.register('foo', opt)
2854
3283
        self.assertEquals(None, conf_stack.get('foo'))
2855
3284
 
2856
3285
    def test_get_without_default_value_for_not_registered(self):
2857
3286
        conf_stack = config.Stack([dict()])
2858
3287
        opt = config.Option('foo')
2859
 
        self.overrideAttr(config, 'option_registry', registry.Registry())
 
3288
        self.overrideOptionRegistry()
2860
3289
        self.assertEquals(None, conf_stack.get('foo'))
2861
3290
 
2862
3291
    def test_get_first_definition(self):
2896
3325
 
2897
3326
class TestStackGet(TestStackWithTransport):
2898
3327
 
 
3328
    def setUp(self):
 
3329
        super(TestStackGet, self).setUp()
 
3330
        self.conf = self.get_stack(self)
 
3331
 
2899
3332
    def test_get_for_empty_stack(self):
2900
 
        conf = self.get_stack(self)
2901
 
        self.assertEquals(None, conf.get('foo'))
 
3333
        self.assertEquals(None, self.conf.get('foo'))
2902
3334
 
2903
3335
    def test_get_hook(self):
2904
 
        conf = self.get_stack(self)
2905
 
        conf.store._load_from_string('foo=bar')
 
3336
        self.conf.store._load_from_string('foo=bar')
2906
3337
        calls = []
2907
3338
        def hook(*args):
2908
3339
            calls.append(args)
2909
3340
        config.ConfigHooks.install_named_hook('get', hook, None)
2910
3341
        self.assertLength(0, calls)
2911
 
        value = conf.get('foo')
 
3342
        value = self.conf.get('foo')
2912
3343
        self.assertEquals('bar', value)
2913
3344
        self.assertLength(1, calls)
2914
 
        self.assertEquals((conf, 'foo', 'bar'), calls[0])
 
3345
        self.assertEquals((self.conf, 'foo', 'bar'), calls[0])
 
3346
 
 
3347
 
 
3348
class TestStackGetWithConverter(TestStackGet):
 
3349
 
 
3350
    def setUp(self):
 
3351
        super(TestStackGetWithConverter, self).setUp()
 
3352
        self.overrideAttr(config, 'option_registry', config.OptionRegistry())
 
3353
        self.registry = config.option_registry
 
3354
 
 
3355
    def register_bool_option(self, name, default=None, default_from_env=None):
 
3356
        b = config.Option(name, help='A boolean.',
 
3357
                          default=default, default_from_env=default_from_env,
 
3358
                          from_unicode=config.bool_from_store)
 
3359
        self.registry.register(b)
 
3360
 
 
3361
    def test_get_default_bool_None(self):
 
3362
        self.register_bool_option('foo')
 
3363
        self.assertEquals(None, self.conf.get('foo'))
 
3364
 
 
3365
    def test_get_default_bool_True(self):
 
3366
        self.register_bool_option('foo', u'True')
 
3367
        self.assertEquals(True, self.conf.get('foo'))
 
3368
 
 
3369
    def test_get_default_bool_False(self):
 
3370
        self.register_bool_option('foo', False)
 
3371
        self.assertEquals(False, self.conf.get('foo'))
 
3372
 
 
3373
    def test_get_default_bool_False_as_string(self):
 
3374
        self.register_bool_option('foo', u'False')
 
3375
        self.assertEquals(False, self.conf.get('foo'))
 
3376
 
 
3377
    def test_get_default_bool_from_env_converted(self):
 
3378
        self.register_bool_option('foo', u'True', default_from_env=['FOO'])
 
3379
        self.overrideEnv('FOO', 'False')
 
3380
        self.assertEquals(False, self.conf.get('foo'))
 
3381
 
 
3382
    def test_get_default_bool_when_conversion_fails(self):
 
3383
        self.register_bool_option('foo', default='True')
 
3384
        self.conf.store._load_from_string('foo=invalid boolean')
 
3385
        self.assertEquals(True, self.conf.get('foo'))
 
3386
 
 
3387
    def register_integer_option(self, name,
 
3388
                                default=None, default_from_env=None):
 
3389
        i = config.Option(name, help='An integer.',
 
3390
                          default=default, default_from_env=default_from_env,
 
3391
                          from_unicode=config.int_from_store)
 
3392
        self.registry.register(i)
 
3393
 
 
3394
    def test_get_default_integer_None(self):
 
3395
        self.register_integer_option('foo')
 
3396
        self.assertEquals(None, self.conf.get('foo'))
 
3397
 
 
3398
    def test_get_default_integer(self):
 
3399
        self.register_integer_option('foo', 42)
 
3400
        self.assertEquals(42, self.conf.get('foo'))
 
3401
 
 
3402
    def test_get_default_integer_as_string(self):
 
3403
        self.register_integer_option('foo', u'42')
 
3404
        self.assertEquals(42, self.conf.get('foo'))
 
3405
 
 
3406
    def test_get_default_integer_from_env(self):
 
3407
        self.register_integer_option('foo', default_from_env=['FOO'])
 
3408
        self.overrideEnv('FOO', '18')
 
3409
        self.assertEquals(18, self.conf.get('foo'))
 
3410
 
 
3411
    def test_get_default_integer_when_conversion_fails(self):
 
3412
        self.register_integer_option('foo', default='12')
 
3413
        self.conf.store._load_from_string('foo=invalid integer')
 
3414
        self.assertEquals(12, self.conf.get('foo'))
 
3415
 
 
3416
    def register_list_option(self, name, default=None, default_from_env=None):
 
3417
        l = config.Option(name, help='A list.',
 
3418
                          default=default, default_from_env=default_from_env,
 
3419
                          from_unicode=config.list_from_store)
 
3420
        self.registry.register(l)
 
3421
 
 
3422
    def test_get_default_list_None(self):
 
3423
        self.register_list_option('foo')
 
3424
        self.assertEquals(None, self.conf.get('foo'))
 
3425
 
 
3426
    def test_get_default_list_empty(self):
 
3427
        self.register_list_option('foo', '')
 
3428
        self.assertEquals([], self.conf.get('foo'))
 
3429
 
 
3430
    def test_get_default_list_from_env(self):
 
3431
        self.register_list_option('foo', default_from_env=['FOO'])
 
3432
        self.overrideEnv('FOO', '')
 
3433
        self.assertEquals([], self.conf.get('foo'))
 
3434
 
 
3435
    def test_get_with_list_converter_no_item(self):
 
3436
        self.register_list_option('foo', None)
 
3437
        self.conf.store._load_from_string('foo=,')
 
3438
        self.assertEquals([], self.conf.get('foo'))
 
3439
 
 
3440
    def test_get_with_list_converter_many_items(self):
 
3441
        self.register_list_option('foo', None)
 
3442
        self.conf.store._load_from_string('foo=m,o,r,e')
 
3443
        self.assertEquals(['m', 'o', 'r', 'e'], self.conf.get('foo'))
 
3444
 
 
3445
    def test_get_with_list_converter_embedded_spaces_many_items(self):
 
3446
        self.register_list_option('foo', None)
 
3447
        self.conf.store._load_from_string('foo=" bar", "baz "')
 
3448
        self.assertEquals([' bar', 'baz '], self.conf.get('foo'))
 
3449
 
 
3450
    def test_get_with_list_converter_stripped_spaces_many_items(self):
 
3451
        self.register_list_option('foo', None)
 
3452
        self.conf.store._load_from_string('foo= bar ,  baz ')
 
3453
        self.assertEquals(['bar', 'baz'], self.conf.get('foo'))
 
3454
 
 
3455
 
 
3456
class TestStackExpandOptions(tests.TestCaseWithTransport):
 
3457
 
 
3458
    def setUp(self):
 
3459
        super(TestStackExpandOptions, self).setUp()
 
3460
        self.overrideAttr(config, 'option_registry', config.OptionRegistry())
 
3461
        self.registry = config.option_registry
 
3462
        self.conf = build_branch_stack(self)
 
3463
 
 
3464
    def assertExpansion(self, expected, string, env=None):
 
3465
        self.assertEquals(expected, self.conf.expand_options(string, env))
 
3466
 
 
3467
    def test_no_expansion(self):
 
3468
        self.assertExpansion('foo', 'foo')
 
3469
 
 
3470
    def test_expand_default_value(self):
 
3471
        self.conf.store._load_from_string('bar=baz')
 
3472
        self.registry.register(config.Option('foo', default=u'{bar}'))
 
3473
        self.assertEquals('baz', self.conf.get('foo', expand=True))
 
3474
 
 
3475
    def test_expand_default_from_env(self):
 
3476
        self.conf.store._load_from_string('bar=baz')
 
3477
        self.registry.register(config.Option('foo', default_from_env=['FOO']))
 
3478
        self.overrideEnv('FOO', '{bar}')
 
3479
        self.assertEquals('baz', self.conf.get('foo', expand=True))
 
3480
 
 
3481
    def test_expand_default_on_failed_conversion(self):
 
3482
        self.conf.store._load_from_string('baz=bogus\nbar=42\nfoo={baz}')
 
3483
        self.registry.register(
 
3484
            config.Option('foo', default=u'{bar}',
 
3485
                          from_unicode=config.int_from_store))
 
3486
        self.assertEquals(42, self.conf.get('foo', expand=True))
 
3487
 
 
3488
    def test_env_adding_options(self):
 
3489
        self.assertExpansion('bar', '{foo}', {'foo': 'bar'})
 
3490
 
 
3491
    def test_env_overriding_options(self):
 
3492
        self.conf.store._load_from_string('foo=baz')
 
3493
        self.assertExpansion('bar', '{foo}', {'foo': 'bar'})
 
3494
 
 
3495
    def test_simple_ref(self):
 
3496
        self.conf.store._load_from_string('foo=xxx')
 
3497
        self.assertExpansion('xxx', '{foo}')
 
3498
 
 
3499
    def test_unknown_ref(self):
 
3500
        self.assertRaises(errors.ExpandingUnknownOption,
 
3501
                          self.conf.expand_options, '{foo}')
 
3502
 
 
3503
    def test_indirect_ref(self):
 
3504
        self.conf.store._load_from_string('''
 
3505
foo=xxx
 
3506
bar={foo}
 
3507
''')
 
3508
        self.assertExpansion('xxx', '{bar}')
 
3509
 
 
3510
    def test_embedded_ref(self):
 
3511
        self.conf.store._load_from_string('''
 
3512
foo=xxx
 
3513
bar=foo
 
3514
''')
 
3515
        self.assertExpansion('xxx', '{{bar}}')
 
3516
 
 
3517
    def test_simple_loop(self):
 
3518
        self.conf.store._load_from_string('foo={foo}')
 
3519
        self.assertRaises(errors.OptionExpansionLoop,
 
3520
                          self.conf.expand_options, '{foo}')
 
3521
 
 
3522
    def test_indirect_loop(self):
 
3523
        self.conf.store._load_from_string('''
 
3524
foo={bar}
 
3525
bar={baz}
 
3526
baz={foo}''')
 
3527
        e = self.assertRaises(errors.OptionExpansionLoop,
 
3528
                              self.conf.expand_options, '{foo}')
 
3529
        self.assertEquals('foo->bar->baz', e.refs)
 
3530
        self.assertEquals('{foo}', e.string)
 
3531
 
 
3532
    def test_list(self):
 
3533
        self.conf.store._load_from_string('''
 
3534
foo=start
 
3535
bar=middle
 
3536
baz=end
 
3537
list={foo},{bar},{baz}
 
3538
''')
 
3539
        self.registry.register(
 
3540
            config.Option('list', from_unicode=config.list_from_store))
 
3541
        self.assertEquals(['start', 'middle', 'end'],
 
3542
                           self.conf.get('list', expand=True))
 
3543
 
 
3544
    def test_cascading_list(self):
 
3545
        self.conf.store._load_from_string('''
 
3546
foo=start,{bar}
 
3547
bar=middle,{baz}
 
3548
baz=end
 
3549
list={foo}
 
3550
''')
 
3551
        self.registry.register(
 
3552
            config.Option('list', from_unicode=config.list_from_store))
 
3553
        self.assertEquals(['start', 'middle', 'end'],
 
3554
                           self.conf.get('list', expand=True))
 
3555
 
 
3556
    def test_pathologically_hidden_list(self):
 
3557
        self.conf.store._load_from_string('''
 
3558
foo=bin
 
3559
bar=go
 
3560
start={foo
 
3561
middle=},{
 
3562
end=bar}
 
3563
hidden={start}{middle}{end}
 
3564
''')
 
3565
        # What matters is what the registration says, the conversion happens
 
3566
        # only after all expansions have been performed
 
3567
        self.registry.register(
 
3568
            config.Option('hidden', from_unicode=config.list_from_store))
 
3569
        self.assertEquals(['bin', 'go'],
 
3570
                          self.conf.get('hidden', expand=True))
 
3571
 
 
3572
 
 
3573
class TestStackCrossSectionsExpand(tests.TestCaseWithTransport):
 
3574
 
 
3575
    def setUp(self):
 
3576
        super(TestStackCrossSectionsExpand, self).setUp()
 
3577
 
 
3578
    def get_config(self, location, string):
 
3579
        if string is None:
 
3580
            string = ''
 
3581
        # Since we don't save the config we won't strictly require to inherit
 
3582
        # from TestCaseInTempDir, but an error occurs so quickly...
 
3583
        c = config.LocationStack(location)
 
3584
        c.store._load_from_string(string)
 
3585
        return c
 
3586
 
 
3587
    def test_dont_cross_unrelated_section(self):
 
3588
        c = self.get_config('/another/branch/path','''
 
3589
[/one/branch/path]
 
3590
foo = hello
 
3591
bar = {foo}/2
 
3592
 
 
3593
[/another/branch/path]
 
3594
bar = {foo}/2
 
3595
''')
 
3596
        self.assertRaises(errors.ExpandingUnknownOption,
 
3597
                          c.get, 'bar', expand=True)
 
3598
 
 
3599
    def test_cross_related_sections(self):
 
3600
        c = self.get_config('/project/branch/path','''
 
3601
[/project]
 
3602
foo = qu
 
3603
 
 
3604
[/project/branch/path]
 
3605
bar = {foo}ux
 
3606
''')
 
3607
        self.assertEquals('quux', c.get('bar', expand=True))
2915
3608
 
2916
3609
 
2917
3610
class TestStackSet(TestStackWithTransport):
2945
3638
 
2946
3639
    def test_remove_existing(self):
2947
3640
        conf = self.get_stack(self)
2948
 
        conf.store._load_from_string('foo=bar')
 
3641
        conf.set('foo', 'bar')
2949
3642
        self.assertEquals('bar', conf.get('foo'))
2950
3643
        conf.remove('foo')
2951
3644
        # Did we get it back ?
2962
3655
        config.ConfigHooks.install_named_hook('remove', hook, None)
2963
3656
        self.assertLength(0, calls)
2964
3657
        conf = self.get_stack(self)
2965
 
        conf.store._load_from_string('foo=bar')
 
3658
        conf.set('foo', 'bar')
2966
3659
        conf.remove('foo')
2967
3660
        self.assertLength(1, calls)
2968
3661
        self.assertEquals((conf, 'foo'), calls[0])
3143
3836
        conf = config.AuthenticationConfig(_file=StringIO(
3144
3837
                'foo = bar\xff'))
3145
3838
        self.assertRaises(errors.ConfigContentError, conf._get_config)
3146
 
        
 
3839
 
3147
3840
    def test_missing_auth_section_header(self):
3148
3841
        conf = config.AuthenticationConfig(_file=StringIO('foo = bar'))
3149
3842
        self.assertRaises(ValueError, conf.get_credentials, 'ftp', 'foo.net')