~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_config.py

  • Committer: John Arbash Meinel
  • Date: 2011-09-12 18:40:02 UTC
  • mfrom: (6132 +trunk)
  • mto: This revision was merged to the branch mainline in revision 6133.
  • Revision ID: john@arbash-meinel.com-20110912184002-o23eu21fdgp35h2q
Merge bzr.dev, resolve release-notes (aka NEWS) conflicts.

Show diffs side-by-side

added added

removed removed

Lines of Context:
183
183
user_global_option=something
184
184
bzr.mergetool.sometool=sometool {base} {this} {other} -o {result}
185
185
bzr.mergetool.funkytool=funkytool "arg with spaces" {this_temp}
 
186
bzr.mergetool.newtool='"newtool with spaces" {this_temp}'
186
187
bzr.default_mergetool=sometool
187
188
[ALIASES]
188
189
h=help
835
836
        self.assertEquals(['{foo', '}', '{', 'bar}'],
836
837
                          conf.get_user_option('hidden', expand=True))
837
838
 
 
839
 
838
840
class TestLocationConfigOptionExpansion(tests.TestCaseInTempDir):
839
841
 
840
842
    def get_config(self, location, string=None):
1338
1340
        self.log(repr(tools))
1339
1341
        self.assertEqual(
1340
1342
            {u'funkytool' : u'funkytool "arg with spaces" {this_temp}',
1341
 
            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}'},
1342
1345
            tools)
1343
1346
 
1344
1347
    def test_get_merge_tools_empty(self):
2387
2390
                             opt, [u'foo', u'1', u'True'])
2388
2391
 
2389
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
 
2390
2486
class TestOptionRegistry(tests.TestCase):
2391
2487
 
2392
2488
    def setUp(self):
2530
2626
    scenarios = [(key, {'get_store': builder}) for key, builder
2531
2627
                 in config.test_store_builder_registry.iteritems()]
2532
2628
 
2533
 
    def setUp(self):
2534
 
        super(TestReadonlyStore, self).setUp()
2535
 
 
2536
2629
    def test_building_delays_load(self):
2537
2630
        store = self.get_store(self)
2538
2631
        self.assertEquals(False, store.is_loaded())
2565
2658
 
2566
2659
 
2567
2660
class TestIniFileStoreContent(tests.TestCaseWithTransport):
2568
 
    """Simulate loading a config store without content of various encodings.
 
2661
    """Simulate loading a config store with content of various encodings.
2569
2662
 
2570
2663
    All files produced by bzr are in utf8 content.
2571
2664
 
2624
2717
 
2625
2718
 
2626
2719
class TestIniConfigContent(tests.TestCaseWithTransport):
2627
 
    """Simulate loading a IniBasedConfig without content of various encodings.
 
2720
    """Simulate loading a IniBasedConfig with content of various encodings.
2628
2721
 
2629
2722
    All files produced by bzr are in utf8 content.
2630
2723
 
2812
2905
        sections = list(store.get_sections())
2813
2906
        self.assertLength(4, sections)
2814
2907
        # The default section has no name.
2815
 
        # List values are provided as lists
2816
 
        self.assertSectionContent((None, {'foo': 'bar', 'l': ['1', '2']}),
 
2908
        # List values are provided as strings and need to be explicitly
 
2909
        # converted by specifying from_unicode=list_from_store at option
 
2910
        # registration
 
2911
        self.assertSectionContent((None, {'foo': 'bar', 'l': u'1,2'}),
2817
2912
                                  sections[0])
2818
2913
        self.assertSectionContent(
2819
2914
            ('DEFAULT', {'foo_in_DEFAULT': 'foo_DEFAULT'}), sections[1])
2965
3060
    # FIXME: It may be worth looking into removing the lock dir when it's not
2966
3061
    # needed anymore and look at possible fallouts for concurrent lockers. This
2967
3062
    # will matter if/when we use config files outside of bazaar directories
2968
 
    # (.bazaar or .bzr) -- vila 20110-04-11
 
3063
    # (.bazaar or .bzr) -- vila 20110-04-111
2969
3064
 
2970
3065
 
2971
3066
class TestSectionMatcher(TestStore):
2972
3067
 
2973
 
    scenarios = [('location', {'matcher': config.LocationMatcher})]
 
3068
    scenarios = [('location', {'matcher': config.LocationMatcher}),
 
3069
                 ('id', {'matcher': config.NameMatcher}),]
2974
3070
 
2975
3071
    def get_store(self, file_name):
2976
3072
        return config.IniFileStore(self.get_readonly_transport(), file_name)
3085
3181
        self.assertEquals(expected_location, matcher.location)
3086
3182
 
3087
3183
 
 
3184
class TestNameMatcher(TestStore):
 
3185
 
 
3186
    def setUp(self):
 
3187
        super(TestNameMatcher, self).setUp()
 
3188
        self.store = config.IniFileStore(self.get_readonly_transport(),
 
3189
                                         'foo.conf')
 
3190
        self.store._load_from_string('''
 
3191
[foo]
 
3192
option=foo
 
3193
[foo/baz]
 
3194
option=foo/baz
 
3195
[bar]
 
3196
option=bar
 
3197
''')
 
3198
 
 
3199
    def get_matching_sections(self, name):
 
3200
        matcher = config.NameMatcher(self.store, name)
 
3201
        return list(matcher.get_sections())
 
3202
 
 
3203
    def test_matching(self):
 
3204
        sections = self.get_matching_sections('foo')
 
3205
        self.assertLength(1, sections)
 
3206
        self.assertSectionContent(('foo', {'option': 'foo'}), sections[0])
 
3207
 
 
3208
    def test_not_matching(self):
 
3209
        sections = self.get_matching_sections('baz')
 
3210
        self.assertLength(0, sections)
 
3211
 
 
3212
 
3088
3213
class TestStackGet(tests.TestCase):
3089
3214
 
3090
3215
    # FIXME: This should be parametrized for all known Stack or dedicated
3272
3397
        self.conf.store._load_from_string('foo=m,o,r,e')
3273
3398
        self.assertEquals(['m', 'o', 'r', 'e'], self.conf.get('foo'))
3274
3399
 
 
3400
    def test_get_with_list_converter_embedded_spaces_many_items(self):
 
3401
        self.register_list_option('foo', None)
 
3402
        self.conf.store._load_from_string('foo=" bar", "baz "')
 
3403
        self.assertEquals([' bar', 'baz '], self.conf.get('foo'))
 
3404
 
 
3405
    def test_get_with_list_converter_stripped_spaces_many_items(self):
 
3406
        self.register_list_option('foo', None)
 
3407
        self.conf.store._load_from_string('foo= bar ,  baz ')
 
3408
        self.assertEquals(['bar', 'baz'], self.conf.get('foo'))
 
3409
 
 
3410
 
 
3411
class TestStackExpandOptions(tests.TestCaseWithTransport):
 
3412
 
 
3413
    def setUp(self):
 
3414
        super(TestStackExpandOptions, self).setUp()
 
3415
        self.overrideAttr(config, 'option_registry', config.OptionRegistry())
 
3416
        self.registry = config.option_registry
 
3417
        self.conf = build_branch_stack(self)
 
3418
 
 
3419
    def assertExpansion(self, expected, string, env=None):
 
3420
        self.assertEquals(expected, self.conf.expand_options(string, env))
 
3421
 
 
3422
    def test_no_expansion(self):
 
3423
        self.assertExpansion('foo', 'foo')
 
3424
 
 
3425
    def test_expand_default_value(self):
 
3426
        self.conf.store._load_from_string('bar=baz')
 
3427
        self.registry.register(config.Option('foo', default=u'{bar}'))
 
3428
        self.assertEquals('baz', self.conf.get('foo', expand=True))
 
3429
 
 
3430
    def test_expand_default_from_env(self):
 
3431
        self.conf.store._load_from_string('bar=baz')
 
3432
        self.registry.register(config.Option('foo', default_from_env=['FOO']))
 
3433
        self.overrideEnv('FOO', '{bar}')
 
3434
        self.assertEquals('baz', self.conf.get('foo', expand=True))
 
3435
 
 
3436
    def test_expand_default_on_failed_conversion(self):
 
3437
        self.conf.store._load_from_string('baz=bogus\nbar=42\nfoo={baz}')
 
3438
        self.registry.register(
 
3439
            config.Option('foo', default=u'{bar}',
 
3440
                          from_unicode=config.int_from_store))
 
3441
        self.assertEquals(42, self.conf.get('foo', expand=True))
 
3442
 
 
3443
    def test_env_adding_options(self):
 
3444
        self.assertExpansion('bar', '{foo}', {'foo': 'bar'})
 
3445
 
 
3446
    def test_env_overriding_options(self):
 
3447
        self.conf.store._load_from_string('foo=baz')
 
3448
        self.assertExpansion('bar', '{foo}', {'foo': 'bar'})
 
3449
 
 
3450
    def test_simple_ref(self):
 
3451
        self.conf.store._load_from_string('foo=xxx')
 
3452
        self.assertExpansion('xxx', '{foo}')
 
3453
 
 
3454
    def test_unknown_ref(self):
 
3455
        self.assertRaises(errors.ExpandingUnknownOption,
 
3456
                          self.conf.expand_options, '{foo}')
 
3457
 
 
3458
    def test_indirect_ref(self):
 
3459
        self.conf.store._load_from_string('''
 
3460
foo=xxx
 
3461
bar={foo}
 
3462
''')
 
3463
        self.assertExpansion('xxx', '{bar}')
 
3464
 
 
3465
    def test_embedded_ref(self):
 
3466
        self.conf.store._load_from_string('''
 
3467
foo=xxx
 
3468
bar=foo
 
3469
''')
 
3470
        self.assertExpansion('xxx', '{{bar}}')
 
3471
 
 
3472
    def test_simple_loop(self):
 
3473
        self.conf.store._load_from_string('foo={foo}')
 
3474
        self.assertRaises(errors.OptionExpansionLoop,
 
3475
                          self.conf.expand_options, '{foo}')
 
3476
 
 
3477
    def test_indirect_loop(self):
 
3478
        self.conf.store._load_from_string('''
 
3479
foo={bar}
 
3480
bar={baz}
 
3481
baz={foo}''')
 
3482
        e = self.assertRaises(errors.OptionExpansionLoop,
 
3483
                              self.conf.expand_options, '{foo}')
 
3484
        self.assertEquals('foo->bar->baz', e.refs)
 
3485
        self.assertEquals('{foo}', e.string)
 
3486
 
 
3487
    def test_list(self):
 
3488
        self.conf.store._load_from_string('''
 
3489
foo=start
 
3490
bar=middle
 
3491
baz=end
 
3492
list={foo},{bar},{baz}
 
3493
''')
 
3494
        self.registry.register(
 
3495
            config.Option('list', from_unicode=config.list_from_store))
 
3496
        self.assertEquals(['start', 'middle', 'end'],
 
3497
                           self.conf.get('list', expand=True))
 
3498
 
 
3499
    def test_cascading_list(self):
 
3500
        self.conf.store._load_from_string('''
 
3501
foo=start,{bar}
 
3502
bar=middle,{baz}
 
3503
baz=end
 
3504
list={foo}
 
3505
''')
 
3506
        self.registry.register(
 
3507
            config.Option('list', from_unicode=config.list_from_store))
 
3508
        self.assertEquals(['start', 'middle', 'end'],
 
3509
                           self.conf.get('list', expand=True))
 
3510
 
 
3511
    def test_pathologically_hidden_list(self):
 
3512
        self.conf.store._load_from_string('''
 
3513
foo=bin
 
3514
bar=go
 
3515
start={foo
 
3516
middle=},{
 
3517
end=bar}
 
3518
hidden={start}{middle}{end}
 
3519
''')
 
3520
        # What matters is what the registration says, the conversion happens
 
3521
        # only after all expansions have been performed
 
3522
        self.registry.register(
 
3523
            config.Option('hidden', from_unicode=config.list_from_store))
 
3524
        self.assertEquals(['bin', 'go'],
 
3525
                          self.conf.get('hidden', expand=True))
 
3526
 
 
3527
 
 
3528
class TestStackCrossSectionsExpand(tests.TestCaseWithTransport):
 
3529
 
 
3530
    def setUp(self):
 
3531
        super(TestStackCrossSectionsExpand, self).setUp()
 
3532
 
 
3533
    def get_config(self, location, string):
 
3534
        if string is None:
 
3535
            string = ''
 
3536
        # Since we don't save the config we won't strictly require to inherit
 
3537
        # from TestCaseInTempDir, but an error occurs so quickly...
 
3538
        c = config.LocationStack(location)
 
3539
        c.store._load_from_string(string)
 
3540
        return c
 
3541
 
 
3542
    def test_dont_cross_unrelated_section(self):
 
3543
        c = self.get_config('/another/branch/path','''
 
3544
[/one/branch/path]
 
3545
foo = hello
 
3546
bar = {foo}/2
 
3547
 
 
3548
[/another/branch/path]
 
3549
bar = {foo}/2
 
3550
''')
 
3551
        self.assertRaises(errors.ExpandingUnknownOption,
 
3552
                          c.get, 'bar', expand=True)
 
3553
 
 
3554
    def test_cross_related_sections(self):
 
3555
        c = self.get_config('/project/branch/path','''
 
3556
[/project]
 
3557
foo = qu
 
3558
 
 
3559
[/project/branch/path]
 
3560
bar = {foo}ux
 
3561
''')
 
3562
        self.assertEquals('quux', c.get('bar', expand=True))
 
3563
 
3275
3564
 
3276
3565
class TestStackSet(TestStackWithTransport):
3277
3566