~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_config.py

  • Committer: Jelmer Vernooij
  • Date: 2011-11-27 17:42:25 UTC
  • mto: This revision was merged to the branch mainline in revision 6311.
  • Revision ID: jelmer@samba.org-20111127174225-tspfeewl0gwxxumt
Add possible_transports in a couple more places.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2012 Canonical Ltd
 
1
# Copyright (C) 2005-2011 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
35
35
    mail_client,
36
36
    ui,
37
37
    urlutils,
38
 
    registry as _mod_registry,
39
38
    remote,
40
39
    tests,
41
40
    trace,
145
144
config.test_stack_builder_registry.register('branch', build_branch_stack)
146
145
 
147
146
 
148
 
def build_branch_only_stack(test):
 
147
def build_remote_branch_stack(test):
149
148
    # There is only one permutation (but we won't be able to handle more with
150
149
    # this design anyway)
151
150
    (transport_class,
152
151
     server_class) = transport_remote.get_test_permutations()[0]
153
152
    build_backing_branch(test, 'branch', transport_class, server_class)
154
153
    b = branch.Branch.open(test.get_url('branch'))
155
 
    return config.BranchOnlyStack(b)
156
 
config.test_stack_builder_registry.register('branch_only',
157
 
                                            build_branch_only_stack)
 
154
    return config.RemoteBranchStack(b)
 
155
config.test_stack_builder_registry.register('remote_branch',
 
156
                                            build_remote_branch_stack)
158
157
 
159
158
def build_remote_control_stack(test):
160
159
    # There is only one permutation (but we won't be able to handle more with
329
328
 
330
329
class FakeBranch(object):
331
330
 
332
 
    def __init__(self, base=None):
 
331
    def __init__(self, base=None, user_id=None):
333
332
        if base is None:
334
333
            self.base = "http://example.com/branches/demo"
335
334
        else:
336
335
            self.base = base
337
336
        self._transport = self.control_files = \
338
 
            FakeControlFilesAndTransport()
 
337
            FakeControlFilesAndTransport(user_id=user_id)
339
338
 
340
339
    def _get_config(self):
341
340
        return config.TransportConfig(self._transport, 'branch.conf')
349
348
 
350
349
class FakeControlFilesAndTransport(object):
351
350
 
352
 
    def __init__(self):
 
351
    def __init__(self, user_id=None):
353
352
        self.files = {}
 
353
        if user_id:
 
354
            self.files['email'] = user_id
354
355
        self._transport = self
355
356
 
 
357
    def get_utf8(self, filename):
 
358
        # from LockableFiles
 
359
        raise AssertionError("get_utf8 should no longer be used")
 
360
 
356
361
    def get(self, filename):
357
362
        # from Transport
358
363
        try:
495
500
 
496
501
    def test_signatures_default(self):
497
502
        my_config = config.Config()
498
 
        self.assertFalse(
499
 
            self.applyDeprecated(deprecated_in((2, 5, 0)),
500
 
                my_config.signature_needed))
 
503
        self.assertFalse(my_config.signature_needed())
501
504
        self.assertEqual(config.CHECK_IF_POSSIBLE,
502
 
            self.applyDeprecated(deprecated_in((2, 5, 0)),
503
 
                my_config.signature_checking))
 
505
                         my_config.signature_checking())
504
506
        self.assertEqual(config.SIGN_WHEN_REQUIRED,
505
 
                self.applyDeprecated(deprecated_in((2, 5, 0)),
506
 
                    my_config.signing_policy))
 
507
                         my_config.signing_policy())
507
508
 
508
509
    def test_signatures_template_method(self):
509
510
        my_config = InstrumentedConfig()
510
 
        self.assertEqual(config.CHECK_NEVER,
511
 
            self.applyDeprecated(deprecated_in((2, 5, 0)),
512
 
                my_config.signature_checking))
 
511
        self.assertEqual(config.CHECK_NEVER, my_config.signature_checking())
513
512
        self.assertEqual(['_get_signature_checking'], my_config._calls)
514
513
 
515
514
    def test_signatures_template_method_none(self):
516
515
        my_config = InstrumentedConfig()
517
516
        my_config._signatures = None
518
517
        self.assertEqual(config.CHECK_IF_POSSIBLE,
519
 
                         self.applyDeprecated(deprecated_in((2, 5, 0)),
520
 
                             my_config.signature_checking))
 
518
                         my_config.signature_checking())
521
519
        self.assertEqual(['_get_signature_checking'], my_config._calls)
522
520
 
523
521
    def test_gpg_signing_command_default(self):
524
522
        my_config = config.Config()
525
 
        self.assertEqual('gpg',
526
 
            self.applyDeprecated(deprecated_in((2, 5, 0)),
527
 
                my_config.gpg_signing_command))
 
523
        self.assertEqual('gpg', my_config.gpg_signing_command())
528
524
 
529
525
    def test_get_user_option_default(self):
530
526
        my_config = config.Config()
532
528
 
533
529
    def test_post_commit_default(self):
534
530
        my_config = config.Config()
535
 
        self.assertEqual(None, self.applyDeprecated(deprecated_in((2, 5, 0)),
536
 
                                                    my_config.post_commit))
537
 
 
 
531
        self.assertEqual(None, my_config.post_commit())
538
532
 
539
533
    def test_log_format_default(self):
540
534
        my_config = config.Config()
541
 
        self.assertEqual('long',
542
 
                         self.applyDeprecated(deprecated_in((2, 5, 0)),
543
 
                                              my_config.log_format))
 
535
        self.assertEqual('long', my_config.log_format())
544
536
 
545
537
    def test_acceptable_keys_default(self):
546
538
        my_config = config.Config()
547
 
        self.assertEqual(None, self.applyDeprecated(deprecated_in((2, 5, 0)),
548
 
            my_config.acceptable_keys))
 
539
        self.assertEqual(None, my_config.acceptable_keys())
549
540
 
550
541
    def test_validate_signatures_in_log_default(self):
551
542
        my_config = config.Config()
577
568
    def test_config_dir(self):
578
569
        self.assertEqual(config.config_dir(), self.bzr_home)
579
570
 
580
 
    def test_config_dir_is_unicode(self):
581
 
        self.assertIsInstance(config.config_dir(), unicode)
582
 
 
583
571
    def test_config_filename(self):
584
572
        self.assertEqual(config.config_filename(),
585
573
                         self.bzr_home + '/bazaar.conf')
1075
1063
si_g = 5g,
1076
1064
si_gb = 5gB,
1077
1065
""")
1078
 
        def get_si(s, default=None):
1079
 
            return self.applyDeprecated(
1080
 
                deprecated_in((2, 5, 0)),
1081
 
                conf.get_user_option_as_int_from_SI, s, default)
 
1066
        get_si = conf.get_user_option_as_int_from_SI
1082
1067
        self.assertEqual(100, get_si('plain'))
1083
1068
        self.assertEqual(5000, get_si('si_k'))
1084
1069
        self.assertEqual(5000, get_si('si_kb'))
1089
1074
        self.assertEqual(None, get_si('non-exist'))
1090
1075
        self.assertEqual(42, get_si('non-exist-with-default',  42))
1091
1076
 
1092
 
 
1093
1077
class TestSupressWarning(TestIniConfig):
1094
1078
 
1095
1079
    def make_warnings_config(self, s):
1197
1181
        b = self.make_branch('!repo')
1198
1182
        self.assertEqual('!repo', b.get_config().get_nickname())
1199
1183
 
1200
 
    def test_autonick_uses_branch_name(self):
1201
 
        b = self.make_branch('foo', name='bar')
1202
 
        self.assertEqual('bar', b.get_config().get_nickname())
1203
 
 
1204
1184
    def test_warn_if_masked(self):
1205
1185
        warnings = []
1206
1186
        def warning(*args):
1255
1235
    def test_signatures_always(self):
1256
1236
        my_config = config.GlobalConfig.from_string(sample_always_signatures)
1257
1237
        self.assertEqual(config.CHECK_NEVER,
1258
 
                         self.applyDeprecated(deprecated_in((2, 5, 0)),
1259
 
                             my_config.signature_checking))
 
1238
                         my_config.signature_checking())
1260
1239
        self.assertEqual(config.SIGN_ALWAYS,
1261
 
                         self.applyDeprecated(deprecated_in((2, 5, 0)),
1262
 
                             my_config.signing_policy))
1263
 
        self.assertEqual(True,
1264
 
            self.applyDeprecated(deprecated_in((2, 5, 0)),
1265
 
                my_config.signature_needed))
 
1240
                         my_config.signing_policy())
 
1241
        self.assertEqual(True, my_config.signature_needed())
1266
1242
 
1267
1243
    def test_signatures_if_possible(self):
1268
1244
        my_config = config.GlobalConfig.from_string(sample_maybe_signatures)
1269
1245
        self.assertEqual(config.CHECK_NEVER,
1270
 
                         self.applyDeprecated(deprecated_in((2, 5, 0)),
1271
 
                             my_config.signature_checking))
 
1246
                         my_config.signature_checking())
1272
1247
        self.assertEqual(config.SIGN_WHEN_REQUIRED,
1273
 
                         self.applyDeprecated(deprecated_in((2, 5, 0)),
1274
 
                             my_config.signing_policy))
1275
 
        self.assertEqual(False, self.applyDeprecated(deprecated_in((2, 5, 0)),
1276
 
            my_config.signature_needed))
 
1248
                         my_config.signing_policy())
 
1249
        self.assertEqual(False, my_config.signature_needed())
1277
1250
 
1278
1251
    def test_signatures_ignore(self):
1279
1252
        my_config = config.GlobalConfig.from_string(sample_ignore_signatures)
1280
1253
        self.assertEqual(config.CHECK_ALWAYS,
1281
 
                         self.applyDeprecated(deprecated_in((2, 5, 0)),
1282
 
                             my_config.signature_checking))
 
1254
                         my_config.signature_checking())
1283
1255
        self.assertEqual(config.SIGN_NEVER,
1284
 
                         self.applyDeprecated(deprecated_in((2, 5, 0)),
1285
 
                             my_config.signing_policy))
1286
 
        self.assertEqual(False, self.applyDeprecated(deprecated_in((2, 5, 0)),
1287
 
            my_config.signature_needed))
 
1256
                         my_config.signing_policy())
 
1257
        self.assertEqual(False, my_config.signature_needed())
1288
1258
 
1289
1259
    def _get_sample_config(self):
1290
1260
        my_config = config.GlobalConfig.from_string(sample_config_text)
1292
1262
 
1293
1263
    def test_gpg_signing_command(self):
1294
1264
        my_config = self._get_sample_config()
1295
 
        self.assertEqual("gnome-gpg",
1296
 
            self.applyDeprecated(
1297
 
                deprecated_in((2, 5, 0)), my_config.gpg_signing_command))
1298
 
        self.assertEqual(False, self.applyDeprecated(deprecated_in((2, 5, 0)),
1299
 
            my_config.signature_needed))
 
1265
        self.assertEqual("gnome-gpg", my_config.gpg_signing_command())
 
1266
        self.assertEqual(False, my_config.signature_needed())
1300
1267
 
1301
1268
    def test_gpg_signing_key(self):
1302
1269
        my_config = self._get_sample_config()
1303
 
        self.assertEqual("DD4D5088",
1304
 
            self.applyDeprecated(deprecated_in((2, 5, 0)),
1305
 
                my_config.gpg_signing_key))
 
1270
        self.assertEqual("DD4D5088", my_config.gpg_signing_key())
1306
1271
 
1307
1272
    def _get_empty_config(self):
1308
1273
        my_config = config.GlobalConfig()
1310
1275
 
1311
1276
    def test_gpg_signing_command_unset(self):
1312
1277
        my_config = self._get_empty_config()
1313
 
        self.assertEqual("gpg",
1314
 
            self.applyDeprecated(
1315
 
                deprecated_in((2, 5, 0)), my_config.gpg_signing_command))
 
1278
        self.assertEqual("gpg", my_config.gpg_signing_command())
1316
1279
 
1317
1280
    def test_get_user_option_default(self):
1318
1281
        my_config = self._get_empty_config()
1325
1288
 
1326
1289
    def test_post_commit_default(self):
1327
1290
        my_config = self._get_sample_config()
1328
 
        self.assertEqual(None,
1329
 
                         self.applyDeprecated(deprecated_in((2, 5, 0)),
1330
 
                                              my_config.post_commit))
 
1291
        self.assertEqual(None, my_config.post_commit())
1331
1292
 
1332
1293
    def test_configured_logformat(self):
1333
1294
        my_config = self._get_sample_config()
1334
 
        self.assertEqual("short",
1335
 
                         self.applyDeprecated(deprecated_in((2, 5, 0)),
1336
 
                                              my_config.log_format))
 
1295
        self.assertEqual("short", my_config.log_format())
1337
1296
 
1338
1297
    def test_configured_acceptable_keys(self):
1339
1298
        my_config = self._get_sample_config()
1340
 
        self.assertEqual("amy",
1341
 
            self.applyDeprecated(deprecated_in((2, 5, 0)),
1342
 
                my_config.acceptable_keys))
 
1299
        self.assertEqual("amy", my_config.acceptable_keys())
1343
1300
 
1344
1301
    def test_configured_validate_signatures_in_log(self):
1345
1302
        my_config = self._get_sample_config()
1581
1538
        self.get_branch_config('http://www.example.com',
1582
1539
                                 global_config=sample_ignore_signatures)
1583
1540
        self.assertEqual(config.CHECK_ALWAYS,
1584
 
                         self.applyDeprecated(deprecated_in((2, 5, 0)),
1585
 
                             self.my_config.signature_checking))
 
1541
                         self.my_config.signature_checking())
1586
1542
        self.assertEqual(config.SIGN_NEVER,
1587
 
                         self.applyDeprecated(deprecated_in((2, 5, 0)),
1588
 
                             self.my_config.signing_policy))
 
1543
                         self.my_config.signing_policy())
1589
1544
 
1590
1545
    def test_signatures_never(self):
1591
1546
        self.get_branch_config('/a/c')
1592
1547
        self.assertEqual(config.CHECK_NEVER,
1593
 
                         self.applyDeprecated(deprecated_in((2, 5, 0)),
1594
 
                             self.my_config.signature_checking))
 
1548
                         self.my_config.signature_checking())
1595
1549
 
1596
1550
    def test_signatures_when_available(self):
1597
1551
        self.get_branch_config('/a/', global_config=sample_ignore_signatures)
1598
1552
        self.assertEqual(config.CHECK_IF_POSSIBLE,
1599
 
                         self.applyDeprecated(deprecated_in((2, 5, 0)),
1600
 
                             self.my_config.signature_checking))
 
1553
                         self.my_config.signature_checking())
1601
1554
 
1602
1555
    def test_signatures_always(self):
1603
1556
        self.get_branch_config('/b')
1604
1557
        self.assertEqual(config.CHECK_ALWAYS,
1605
 
            self.applyDeprecated(deprecated_in((2, 5, 0)),
1606
 
                         self.my_config.signature_checking))
 
1558
                         self.my_config.signature_checking())
1607
1559
 
1608
1560
    def test_gpg_signing_command(self):
1609
1561
        self.get_branch_config('/b')
1610
 
        self.assertEqual("gnome-gpg",
1611
 
            self.applyDeprecated(deprecated_in((2, 5, 0)),
1612
 
                self.my_config.gpg_signing_command))
 
1562
        self.assertEqual("gnome-gpg", self.my_config.gpg_signing_command())
1613
1563
 
1614
1564
    def test_gpg_signing_command_missing(self):
1615
1565
        self.get_branch_config('/a')
1616
 
        self.assertEqual("false",
1617
 
            self.applyDeprecated(deprecated_in((2, 5, 0)),
1618
 
                self.my_config.gpg_signing_command))
 
1566
        self.assertEqual("false", self.my_config.gpg_signing_command())
1619
1567
 
1620
1568
    def test_gpg_signing_key(self):
1621
1569
        self.get_branch_config('/b')
1622
 
        self.assertEqual("DD4D5088", self.applyDeprecated(deprecated_in((2, 5, 0)),
1623
 
            self.my_config.gpg_signing_key))
 
1570
        self.assertEqual("DD4D5088", self.my_config.gpg_signing_key())
1624
1571
 
1625
1572
    def test_gpg_signing_key_default(self):
1626
1573
        self.get_branch_config('/a')
1627
 
        self.assertEqual("erik@bagfors.nu",
1628
 
            self.applyDeprecated(deprecated_in((2, 5, 0)),
1629
 
                self.my_config.gpg_signing_key))
 
1574
        self.assertEqual("erik@bagfors.nu", self.my_config.gpg_signing_key())
1630
1575
 
1631
1576
    def test_get_user_option_global(self):
1632
1577
        self.get_branch_config('/a')
1720
1665
    def test_post_commit_default(self):
1721
1666
        self.get_branch_config('/a/c')
1722
1667
        self.assertEqual('bzrlib.tests.test_config.post_commit',
1723
 
                         self.applyDeprecated(deprecated_in((2, 5, 0)),
1724
 
                                              self.my_config.post_commit))
 
1668
                         self.my_config.post_commit())
1725
1669
 
1726
1670
    def get_branch_config(self, location, global_config=None,
1727
1671
                          location_config=None):
1817
1761
        return my_config
1818
1762
 
1819
1763
    def test_user_id(self):
1820
 
        branch = FakeBranch()
 
1764
        branch = FakeBranch(user_id='Robert Collins <robertc@example.net>')
1821
1765
        my_config = config.BranchConfig(branch)
1822
 
        self.assertIsNot(None, my_config.username())
 
1766
        self.assertEqual("Robert Collins <robertc@example.net>",
 
1767
                         my_config.username())
1823
1768
        my_config.branch.control_files.files['email'] = "John"
1824
1769
        my_config.set_user_option('email',
1825
1770
                                  "Robert Collins <robertc@example.org>")
 
1771
        self.assertEqual("John", my_config.username())
 
1772
        del my_config.branch.control_files.files['email']
1826
1773
        self.assertEqual("Robert Collins <robertc@example.org>",
1827
 
                        my_config.username())
 
1774
                         my_config.username())
 
1775
 
 
1776
    def test_not_set_in_branch(self):
 
1777
        my_config = self.get_branch_config(global_config=sample_config_text)
 
1778
        self.assertEqual(u"Erik B\u00e5gfors <erik@bagfors.nu>",
 
1779
                         my_config._get_user_id())
 
1780
        my_config.branch.control_files.files['email'] = "John"
 
1781
        self.assertEqual("John", my_config._get_user_id())
1828
1782
 
1829
1783
    def test_BZR_EMAIL_OVERRIDES(self):
1830
1784
        self.overrideEnv('BZR_EMAIL', "Robert Collins <robertc@example.org>")
1836
1790
    def test_signatures_forced(self):
1837
1791
        my_config = self.get_branch_config(
1838
1792
            global_config=sample_always_signatures)
1839
 
        self.assertEqual(config.CHECK_NEVER,
1840
 
            self.applyDeprecated(deprecated_in((2, 5, 0)),
1841
 
                my_config.signature_checking))
1842
 
        self.assertEqual(config.SIGN_ALWAYS,
1843
 
            self.applyDeprecated(deprecated_in((2, 5, 0)),
1844
 
                my_config.signing_policy))
1845
 
        self.assertTrue(self.applyDeprecated(deprecated_in((2, 5, 0)),
1846
 
            my_config.signature_needed))
 
1793
        self.assertEqual(config.CHECK_NEVER, my_config.signature_checking())
 
1794
        self.assertEqual(config.SIGN_ALWAYS, my_config.signing_policy())
 
1795
        self.assertTrue(my_config.signature_needed())
1847
1796
 
1848
1797
    def test_signatures_forced_branch(self):
1849
1798
        my_config = self.get_branch_config(
1850
1799
            global_config=sample_ignore_signatures,
1851
1800
            branch_data_config=sample_always_signatures)
1852
 
        self.assertEqual(config.CHECK_NEVER,
1853
 
            self.applyDeprecated(deprecated_in((2, 5, 0)),
1854
 
                my_config.signature_checking))
1855
 
        self.assertEqual(config.SIGN_ALWAYS,
1856
 
            self.applyDeprecated(deprecated_in((2, 5, 0)),
1857
 
                my_config.signing_policy))
1858
 
        self.assertTrue(self.applyDeprecated(deprecated_in((2, 5, 0)),
1859
 
            my_config.signature_needed))
 
1801
        self.assertEqual(config.CHECK_NEVER, my_config.signature_checking())
 
1802
        self.assertEqual(config.SIGN_ALWAYS, my_config.signing_policy())
 
1803
        self.assertTrue(my_config.signature_needed())
1860
1804
 
1861
1805
    def test_gpg_signing_command(self):
1862
1806
        my_config = self.get_branch_config(
1863
1807
            global_config=sample_config_text,
1864
1808
            # branch data cannot set gpg_signing_command
1865
1809
            branch_data_config="gpg_signing_command=pgp")
1866
 
        self.assertEqual('gnome-gpg',
1867
 
            self.applyDeprecated(deprecated_in((2, 5, 0)),
1868
 
                my_config.gpg_signing_command))
 
1810
        self.assertEqual('gnome-gpg', my_config.gpg_signing_command())
1869
1811
 
1870
1812
    def test_get_user_option_global(self):
1871
1813
        my_config = self.get_branch_config(global_config=sample_config_text)
1878
1820
                                      location_config=sample_branches_text)
1879
1821
        self.assertEqual(my_config.branch.base, '/a/c')
1880
1822
        self.assertEqual('bzrlib.tests.test_config.post_commit',
1881
 
                         self.applyDeprecated(deprecated_in((2, 5, 0)),
1882
 
                                              my_config.post_commit))
 
1823
                         my_config.post_commit())
1883
1824
        my_config.set_user_option('post_commit', 'rmtree_root')
1884
1825
        # post-commit is ignored when present in branch data
1885
1826
        self.assertEqual('bzrlib.tests.test_config.post_commit',
1886
 
                         self.applyDeprecated(deprecated_in((2, 5, 0)),
1887
 
                                              my_config.post_commit))
 
1827
                         my_config.post_commit())
1888
1828
        my_config.set_user_option('post_commit', 'rmtree_root',
1889
1829
                                  store=config.STORE_LOCATION)
1890
 
        self.assertEqual('rmtree_root',
1891
 
                         self.applyDeprecated(deprecated_in((2, 5, 0)),
1892
 
                                              my_config.post_commit))
 
1830
        self.assertEqual('rmtree_root', my_config.post_commit())
1893
1831
 
1894
1832
    def test_config_precedence(self):
1895
1833
        # FIXME: eager test, luckily no persitent config file makes it fail
1911
1849
            location='http://example.com/specific')
1912
1850
        self.assertEqual(my_config.get_user_option('option'), 'exact')
1913
1851
 
 
1852
    def test_get_mail_client(self):
 
1853
        config = self.get_branch_config()
 
1854
        client = config.get_mail_client()
 
1855
        self.assertIsInstance(client, mail_client.DefaultMail)
 
1856
 
 
1857
        # Specific clients
 
1858
        config.set_user_option('mail_client', 'evolution')
 
1859
        client = config.get_mail_client()
 
1860
        self.assertIsInstance(client, mail_client.Evolution)
 
1861
 
 
1862
        config.set_user_option('mail_client', 'kmail')
 
1863
        client = config.get_mail_client()
 
1864
        self.assertIsInstance(client, mail_client.KMail)
 
1865
 
 
1866
        config.set_user_option('mail_client', 'mutt')
 
1867
        client = config.get_mail_client()
 
1868
        self.assertIsInstance(client, mail_client.Mutt)
 
1869
 
 
1870
        config.set_user_option('mail_client', 'thunderbird')
 
1871
        client = config.get_mail_client()
 
1872
        self.assertIsInstance(client, mail_client.Thunderbird)
 
1873
 
 
1874
        # Generic options
 
1875
        config.set_user_option('mail_client', 'default')
 
1876
        client = config.get_mail_client()
 
1877
        self.assertIsInstance(client, mail_client.DefaultMail)
 
1878
 
 
1879
        config.set_user_option('mail_client', 'editor')
 
1880
        client = config.get_mail_client()
 
1881
        self.assertIsInstance(client, mail_client.Editor)
 
1882
 
 
1883
        config.set_user_option('mail_client', 'mapi')
 
1884
        client = config.get_mail_client()
 
1885
        self.assertIsInstance(client, mail_client.MAPIClient)
 
1886
 
 
1887
        config.set_user_option('mail_client', 'xdg-email')
 
1888
        client = config.get_mail_client()
 
1889
        self.assertIsInstance(client, mail_client.XDGEmail)
 
1890
 
 
1891
        config.set_user_option('mail_client', 'firebird')
 
1892
        self.assertRaises(errors.UnknownMailClient, config.get_mail_client)
 
1893
 
1914
1894
 
1915
1895
class TestMailAddressExtraction(tests.TestCase):
1916
1896
 
2295
2275
        opt = config.Option('foo', default='bar')
2296
2276
        self.assertEquals('bar', opt.get_default())
2297
2277
 
2298
 
    def test_callable_default_value(self):
2299
 
        def bar_as_unicode():
2300
 
            return u'bar'
2301
 
        opt = config.Option('foo', default=bar_as_unicode)
2302
 
        self.assertEquals('bar', opt.get_default())
2303
 
 
2304
2278
    def test_default_value_from_env(self):
2305
2279
        opt = config.Option('foo', default='bar', default_from_env=['FOO'])
2306
2280
        self.overrideEnv('FOO', 'quux')
2322
2296
        self.assertRaises(AssertionError, config.Option, 'foo',
2323
2297
                          default=object())
2324
2298
 
2325
 
    def test_not_supported_callable_default_value_not_unicode(self):
2326
 
        def bar_not_unicode():
2327
 
            return 'bar'
2328
 
        opt = config.Option('foo', default=bar_not_unicode)
2329
 
        self.assertRaises(AssertionError, opt.get_default)
2330
 
 
2331
 
 
2332
 
class TestOptionConverterMixin(object):
2333
 
 
2334
 
    def assertConverted(self, expected, opt, value):
2335
 
        self.assertEquals(expected, opt.convert_from_unicode(None, value))
2336
 
 
2337
 
    def assertWarns(self, opt, value):
2338
 
        warnings = []
2339
 
        def warning(*args):
2340
 
            warnings.append(args[0] % args[1:])
2341
 
        self.overrideAttr(trace, 'warning', warning)
2342
 
        self.assertEquals(None, opt.convert_from_unicode(None, value))
2343
 
        self.assertLength(1, warnings)
2344
 
        self.assertEquals(
2345
 
            'Value "%s" is not valid for "%s"' % (value, opt.name),
2346
 
            warnings[0])
2347
 
 
2348
 
    def assertErrors(self, opt, value):
2349
 
        self.assertRaises(errors.ConfigOptionValueError,
2350
 
                          opt.convert_from_unicode, None, value)
2351
 
 
2352
 
    def assertConvertInvalid(self, opt, invalid_value):
2353
 
        opt.invalid = None
2354
 
        self.assertEquals(None, opt.convert_from_unicode(None, invalid_value))
2355
 
        opt.invalid = 'warning'
2356
 
        self.assertWarns(opt, invalid_value)
2357
 
        opt.invalid = 'error'
2358
 
        self.assertErrors(opt, invalid_value)
2359
 
 
2360
 
 
2361
 
class TestOptionWithBooleanConverter(tests.TestCase, TestOptionConverterMixin):
2362
 
 
2363
 
    def get_option(self):
2364
 
        return config.Option('foo', help='A boolean.',
2365
 
                             from_unicode=config.bool_from_store)
2366
 
 
2367
 
    def test_convert_invalid(self):
2368
 
        opt = self.get_option()
2369
 
        # A string that is not recognized as a boolean
2370
 
        self.assertConvertInvalid(opt, u'invalid-boolean')
2371
 
        # A list of strings is never recognized as a boolean
2372
 
        self.assertConvertInvalid(opt, [u'not', u'a', u'boolean'])
2373
 
 
2374
 
    def test_convert_valid(self):
2375
 
        opt = self.get_option()
2376
 
        self.assertConverted(True, opt, u'True')
2377
 
        self.assertConverted(True, opt, u'1')
2378
 
        self.assertConverted(False, opt, u'False')
2379
 
 
2380
 
 
2381
 
class TestOptionWithIntegerConverter(tests.TestCase, TestOptionConverterMixin):
2382
 
 
2383
 
    def get_option(self):
2384
 
        return config.Option('foo', help='An integer.',
2385
 
                             from_unicode=config.int_from_store)
2386
 
 
2387
 
    def test_convert_invalid(self):
2388
 
        opt = self.get_option()
2389
 
        # A string that is not recognized as an integer
2390
 
        self.assertConvertInvalid(opt, u'forty-two')
2391
 
        # A list of strings is never recognized as an integer
2392
 
        self.assertConvertInvalid(opt, [u'a', u'list'])
2393
 
 
2394
 
    def test_convert_valid(self):
2395
 
        opt = self.get_option()
2396
 
        self.assertConverted(16, opt, u'16')
2397
 
 
2398
 
 
2399
 
class TestOptionWithSIUnitConverter(tests.TestCase, TestOptionConverterMixin):
2400
 
 
2401
 
    def get_option(self):
2402
 
        return config.Option('foo', help='An integer in SI units.',
2403
 
                             from_unicode=config.int_SI_from_store)
2404
 
 
2405
 
    def test_convert_invalid(self):
2406
 
        opt = self.get_option()
2407
 
        self.assertConvertInvalid(opt, u'not-a-unit')
2408
 
        self.assertConvertInvalid(opt, u'Gb') # Forgot the int
2409
 
        self.assertConvertInvalid(opt, u'1b') # Forgot the unit
2410
 
        self.assertConvertInvalid(opt, u'1GG')
2411
 
        self.assertConvertInvalid(opt, u'1Mbb')
2412
 
        self.assertConvertInvalid(opt, u'1MM')
2413
 
 
2414
 
    def test_convert_valid(self):
2415
 
        opt = self.get_option()
2416
 
        self.assertConverted(int(5e3), opt, u'5kb')
2417
 
        self.assertConverted(int(5e6), opt, u'5M')
2418
 
        self.assertConverted(int(5e6), opt, u'5MB')
2419
 
        self.assertConverted(int(5e9), opt, u'5g')
2420
 
        self.assertConverted(int(5e9), opt, u'5gB')
2421
 
        self.assertConverted(100, opt, u'100')
2422
 
 
2423
 
 
2424
 
class TestListOption(tests.TestCase, TestOptionConverterMixin):
2425
 
 
2426
 
    def get_option(self):
2427
 
        return config.ListOption('foo', help='A list.')
 
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)
2428
2465
 
2429
2466
    def test_convert_invalid(self):
2430
2467
        opt = self.get_option()
2446
2483
        self.assertConverted([u'bar'], opt, u'bar')
2447
2484
 
2448
2485
 
2449
 
class TestRegistryOption(tests.TestCase, TestOptionConverterMixin):
2450
 
 
2451
 
    def get_option(self, registry):
2452
 
        return config.RegistryOption('foo', registry,
2453
 
                help='A registry option.')
2454
 
 
2455
 
    def test_convert_invalid(self):
2456
 
        registry = _mod_registry.Registry()
2457
 
        opt = self.get_option(registry)
2458
 
        self.assertConvertInvalid(opt, [1])
2459
 
        self.assertConvertInvalid(opt, u"notregistered")
2460
 
 
2461
 
    def test_convert_valid(self):
2462
 
        registry = _mod_registry.Registry()
2463
 
        registry.register("someval", 1234)
2464
 
        opt = self.get_option(registry)
2465
 
        # Using a bare str() just in case
2466
 
        self.assertConverted(1234, opt, "someval")
2467
 
        self.assertConverted(1234, opt, u'someval')
2468
 
        self.assertConverted(None, opt, None)
2469
 
 
2470
 
    def test_help(self):
2471
 
        registry = _mod_registry.Registry()
2472
 
        registry.register("someval", 1234, help="some option")
2473
 
        registry.register("dunno", 1234, help="some other option")
2474
 
        opt = self.get_option(registry)
2475
 
        self.assertEquals(
2476
 
            'A registry option.\n'
2477
 
            '\n'
2478
 
            'The following values are supported:\n'
2479
 
            ' dunno - some other option\n'
2480
 
            ' someval - some option\n',
2481
 
            opt.help)
2482
 
 
2483
 
    def test_get_help_text(self):
2484
 
        registry = _mod_registry.Registry()
2485
 
        registry.register("someval", 1234, help="some option")
2486
 
        registry.register("dunno", 1234, help="some other option")
2487
 
        opt = self.get_option(registry)
2488
 
        self.assertEquals(
2489
 
            'A registry option.\n'
2490
 
            '\n'
2491
 
            'The following values are supported:\n'
2492
 
            ' dunno - some other option\n'
2493
 
            ' someval - some option\n',
2494
 
            opt.get_help_text())
2495
 
 
2496
 
 
2497
2486
class TestOptionRegistry(tests.TestCase):
2498
2487
 
2499
2488
    def setUp(self):
2628
2617
    def setUp(self):
2629
2618
        super(TestCommandLineStore, self).setUp()
2630
2619
        self.store = config.CommandLineStore()
2631
 
        self.overrideAttr(config, 'option_registry', config.OptionRegistry())
2632
2620
 
2633
2621
    def get_section(self):
2634
2622
        """Get the unique section for the command line overrides."""
2649
2637
        self.assertEqual('b', section.get('a'))
2650
2638
 
2651
2639
    def test_list_override(self):
2652
 
        opt = config.ListOption('l')
2653
 
        config.option_registry.register(opt)
2654
2640
        self.store._from_cmdline(['l=1,2,3'])
2655
2641
        val = self.get_section().get('l')
2656
2642
        self.assertEqual('1,2,3', val)
2657
2643
        # Reminder: lists should be registered as such explicitely, otherwise
2658
2644
        # the conversion needs to be done afterwards.
2659
 
        self.assertEqual(['1', '2', '3'],
2660
 
                         opt.convert_from_unicode(self.store, val))
 
2645
        self.assertEqual(['1', '2', '3'], config.list_from_store(val))
2661
2646
 
2662
2647
    def test_multiple_overrides(self):
2663
2648
        self.store._from_cmdline(['a=b', 'x=y'])
2669
2654
        self.assertRaises(errors.BzrCommandError,
2670
2655
                          self.store._from_cmdline, ['a=b', 'c'])
2671
2656
 
2672
 
class TestStoreMinimalAPI(tests.TestCaseWithTransport):
2673
 
 
2674
 
    scenarios = [(key, {'get_store': builder}) for key, builder
2675
 
                 in config.test_store_builder_registry.iteritems()] + [
2676
 
        ('cmdline', {'get_store': lambda test: config.CommandLineStore()})]
2677
 
 
2678
 
    def test_id(self):
2679
 
        store = self.get_store(self)
2680
 
        if type(store) == config.TransportIniFileStore:
2681
 
            raise tests.TestNotApplicable(
2682
 
                "%s is not a concrete Store implementation"
2683
 
                " so it doesn't need an id" % (store.__class__.__name__,))
2684
 
        self.assertIsNot(None, store.id)
2685
 
 
2686
2657
 
2687
2658
class TestStore(tests.TestCaseWithTransport):
2688
2659
 
2731
2702
        self.assertRaises(AssertionError, store._load_from_string, 'bar=baz')
2732
2703
 
2733
2704
 
2734
 
class TestStoreQuoting(TestStore):
2735
 
 
2736
 
    scenarios = [(key, {'get_store': builder}) for key, builder
2737
 
                 in config.test_store_builder_registry.iteritems()]
2738
 
 
2739
 
    def setUp(self):
2740
 
        super(TestStoreQuoting, self).setUp()
2741
 
        self.store = self.get_store(self)
2742
 
        # We need a loaded store but any content will do
2743
 
        self.store._load_from_string('')
2744
 
 
2745
 
    def assertIdempotent(self, s):
2746
 
        """Assert that quoting an unquoted string is a no-op and vice-versa.
2747
 
 
2748
 
        What matters here is that option values, as they appear in a store, can
2749
 
        be safely round-tripped out of the store and back.
2750
 
 
2751
 
        :param s: A string, quoted if required.
2752
 
        """
2753
 
        self.assertEquals(s, self.store.quote(self.store.unquote(s)))
2754
 
        self.assertEquals(s, self.store.unquote(self.store.quote(s)))
2755
 
 
2756
 
    def test_empty_string(self):
2757
 
        if isinstance(self.store, config.IniFileStore):
2758
 
            # configobj._quote doesn't handle empty values
2759
 
            self.assertRaises(AssertionError,
2760
 
                              self.assertIdempotent, '')
2761
 
        else:
2762
 
            self.assertIdempotent('')
2763
 
        # But quoted empty strings are ok
2764
 
        self.assertIdempotent('""')
2765
 
 
2766
 
    def test_embedded_spaces(self):
2767
 
        self.assertIdempotent('" a b c "')
2768
 
 
2769
 
    def test_embedded_commas(self):
2770
 
        self.assertIdempotent('" a , b c "')
2771
 
 
2772
 
    def test_simple_comma(self):
2773
 
        if isinstance(self.store, config.IniFileStore):
2774
 
            # configobj requires that lists are special-cased
2775
 
           self.assertRaises(AssertionError,
2776
 
                             self.assertIdempotent, ',')
2777
 
        else:
2778
 
            self.assertIdempotent(',')
2779
 
        # When a single comma is required, quoting is also required
2780
 
        self.assertIdempotent('","')
2781
 
 
2782
 
    def test_list(self):
2783
 
        if isinstance(self.store, config.IniFileStore):
2784
 
            # configobj requires that lists are special-cased
2785
 
            self.assertRaises(AssertionError,
2786
 
                              self.assertIdempotent, 'a,b')
2787
 
        else:
2788
 
            self.assertIdempotent('a,b')
2789
 
 
2790
 
 
2791
 
class TestDictFromStore(tests.TestCase):
2792
 
 
2793
 
    def test_unquote_not_string(self):
2794
 
        conf = config.MemoryStack('x=2\n[a_section]\na=1\n')
2795
 
        value = conf.get('a_section')
2796
 
        # Urgh, despite 'conf' asking for the no-name section, we get the
2797
 
        # content of another section as a dict o_O
2798
 
        self.assertEquals({'a': '1'}, value)
2799
 
        unquoted = conf.store.unquote(value)
2800
 
        # Which cannot be unquoted but shouldn't crash either (the use cases
2801
 
        # are getting the value or displaying it. In the later case, '%s' will
2802
 
        # do).
2803
 
        self.assertEquals({'a': '1'}, unquoted)
2804
 
        self.assertEquals("{u'a': u'1'}", '%s' % (unquoted,))
2805
 
 
2806
 
 
2807
2705
class TestIniFileStoreContent(tests.TestCaseWithTransport):
2808
2706
    """Simulate loading a config store with content of various encodings.
2809
2707
 
2928
2826
    def test_save_emptied_succeeds(self):
2929
2827
        store = self.get_store(self)
2930
2828
        store._load_from_string('foo=bar\n')
2931
 
        # FIXME: There should be a better way than relying on the test
2932
 
        # parametrization to identify branch.conf -- vila 2011-0526
2933
 
        if self.store_id in ('branch', 'remote_branch'):
2934
 
            # branch stores requires write locked branches
2935
 
            self.addCleanup(store.branch.lock_write().unlock)
2936
2829
        section = store.get_mutable_section(None)
2937
2830
        section.remove('foo')
2938
2831
        store.save()
2959
2852
 
2960
2853
    def test_set_option_in_empty_store(self):
2961
2854
        store = self.get_store(self)
2962
 
        # FIXME: There should be a better way than relying on the test
2963
 
        # parametrization to identify branch.conf -- vila 2011-0526
2964
 
        if self.store_id in ('branch', 'remote_branch'):
2965
 
            # branch stores requires write locked branches
2966
 
            self.addCleanup(store.branch.lock_write().unlock)
2967
2855
        section = store.get_mutable_section(None)
2968
2856
        section.set('foo', 'bar')
2969
2857
        store.save()
2975
2863
    def test_set_option_in_default_section(self):
2976
2864
        store = self.get_store(self)
2977
2865
        store._load_from_string('')
2978
 
        # FIXME: There should be a better way than relying on the test
2979
 
        # parametrization to identify branch.conf -- vila 2011-0526
2980
 
        if self.store_id in ('branch', 'remote_branch'):
2981
 
            # branch stores requires write locked branches
2982
 
            self.addCleanup(store.branch.lock_write().unlock)
2983
2866
        section = store.get_mutable_section(None)
2984
2867
        section.set('foo', 'bar')
2985
2868
        store.save()
2991
2874
    def test_set_option_in_named_section(self):
2992
2875
        store = self.get_store(self)
2993
2876
        store._load_from_string('')
2994
 
        # FIXME: There should be a better way than relying on the test
2995
 
        # parametrization to identify branch.conf -- vila 2011-0526
2996
 
        if self.store_id in ('branch', 'remote_branch'):
2997
 
            # branch stores requires write locked branches
2998
 
            self.addCleanup(store.branch.lock_write().unlock)
2999
2877
        section = store.get_mutable_section('baz')
3000
2878
        section.set('foo', 'bar')
3001
2879
        store.save()
3005
2883
        self.assertSectionContent(('baz', {'foo': 'bar'}), sections[0])
3006
2884
 
3007
2885
    def test_load_hook(self):
3008
 
        # First, we need to ensure that the store exists
 
2886
        # We first needs to ensure that the store exists
3009
2887
        store = self.get_store(self)
3010
 
        # FIXME: There should be a better way than relying on the test
3011
 
        # parametrization to identify branch.conf -- vila 2011-0526
3012
 
        if self.store_id in ('branch', 'remote_branch'):
3013
 
            # branch stores requires write locked branches
3014
 
            self.addCleanup(store.branch.lock_write().unlock)
3015
2888
        section = store.get_mutable_section('baz')
3016
2889
        section.set('foo', 'bar')
3017
2890
        store.save()
3033
2906
        config.ConfigHooks.install_named_hook('save', hook, None)
3034
2907
        self.assertLength(0, calls)
3035
2908
        store = self.get_store(self)
3036
 
        # FIXME: There should be a better way than relying on the test
3037
 
        # parametrization to identify branch.conf -- vila 2011-0526
3038
 
        if self.store_id in ('branch', 'remote_branch'):
3039
 
            # branch stores requires write locked branches
3040
 
            self.addCleanup(store.branch.lock_write().unlock)
3041
2909
        section = store.get_mutable_section('baz')
3042
2910
        section.set('foo', 'bar')
3043
2911
        store.save()
3044
2912
        self.assertLength(1, calls)
3045
2913
        self.assertEquals((store,), calls[0])
3046
2914
 
3047
 
    def test_set_mark_dirty(self):
3048
 
        stack = config.MemoryStack('')
3049
 
        self.assertLength(0, stack.store.dirty_sections)
3050
 
        stack.set('foo', 'baz')
3051
 
        self.assertLength(1, stack.store.dirty_sections)
3052
 
        self.assertTrue(stack.store._need_saving())
3053
 
 
3054
 
    def test_remove_mark_dirty(self):
3055
 
        stack = config.MemoryStack('foo=bar')
3056
 
        self.assertLength(0, stack.store.dirty_sections)
3057
 
        stack.remove('foo')
3058
 
        self.assertLength(1, stack.store.dirty_sections)
3059
 
        self.assertTrue(stack.store._need_saving())
3060
 
 
3061
 
 
3062
 
class TestStoreSaveChanges(tests.TestCaseWithTransport):
3063
 
    """Tests that config changes are kept in memory and saved on-demand."""
3064
 
 
3065
 
    def setUp(self):
3066
 
        super(TestStoreSaveChanges, self).setUp()
3067
 
        self.transport = self.get_transport()
3068
 
        # Most of the tests involve two stores pointing to the same persistent
3069
 
        # storage to observe the effects of concurrent changes
3070
 
        self.st1 = config.TransportIniFileStore(self.transport, 'foo.conf')
3071
 
        self.st2 = config.TransportIniFileStore(self.transport, 'foo.conf')
3072
 
        self.warnings = []
3073
 
        def warning(*args):
3074
 
            self.warnings.append(args[0] % args[1:])
3075
 
        self.overrideAttr(trace, 'warning', warning)
3076
 
 
3077
 
    def has_store(self, store):
3078
 
        store_basename = urlutils.relative_url(self.transport.external_url(),
3079
 
                                               store.external_url())
3080
 
        return self.transport.has(store_basename)
3081
 
 
3082
 
    def get_stack(self, store):
3083
 
        # Any stack will do as long as it uses the right store, just a single
3084
 
        # no-name section is enough
3085
 
        return config.Stack([store.get_sections], store)
3086
 
 
3087
 
    def test_no_changes_no_save(self):
3088
 
        s = self.get_stack(self.st1)
3089
 
        s.store.save_changes()
3090
 
        self.assertEquals(False, self.has_store(self.st1))
3091
 
 
3092
 
    def test_unrelated_concurrent_update(self):
3093
 
        s1 = self.get_stack(self.st1)
3094
 
        s2 = self.get_stack(self.st2)
3095
 
        s1.set('foo', 'bar')
3096
 
        s2.set('baz', 'quux')
3097
 
        s1.store.save()
3098
 
        # Changes don't propagate magically
3099
 
        self.assertEquals(None, s1.get('baz'))
3100
 
        s2.store.save_changes()
3101
 
        self.assertEquals('quux', s2.get('baz'))
3102
 
        # Changes are acquired when saving
3103
 
        self.assertEquals('bar', s2.get('foo'))
3104
 
        # Since there is no overlap, no warnings are emitted
3105
 
        self.assertLength(0, self.warnings)
3106
 
 
3107
 
    def test_concurrent_update_modified(self):
3108
 
        s1 = self.get_stack(self.st1)
3109
 
        s2 = self.get_stack(self.st2)
3110
 
        s1.set('foo', 'bar')
3111
 
        s2.set('foo', 'baz')
3112
 
        s1.store.save()
3113
 
        # Last speaker wins
3114
 
        s2.store.save_changes()
3115
 
        self.assertEquals('baz', s2.get('foo'))
3116
 
        # But the user get a warning
3117
 
        self.assertLength(1, self.warnings)
3118
 
        warning = self.warnings[0]
3119
 
        self.assertStartsWith(warning, 'Option foo in section None')
3120
 
        self.assertEndsWith(warning, 'was changed from <CREATED> to bar.'
3121
 
                            ' The baz value will be saved.')
3122
 
 
3123
 
    def test_concurrent_deletion(self):
3124
 
        self.st1._load_from_string('foo=bar')
3125
 
        self.st1.save()
3126
 
        s1 = self.get_stack(self.st1)
3127
 
        s2 = self.get_stack(self.st2)
3128
 
        s1.remove('foo')
3129
 
        s2.remove('foo')
3130
 
        s1.store.save_changes()
3131
 
        # No warning yet
3132
 
        self.assertLength(0, self.warnings)
3133
 
        s2.store.save_changes()
3134
 
        # Now we get one
3135
 
        self.assertLength(1, self.warnings)
3136
 
        warning = self.warnings[0]
3137
 
        self.assertStartsWith(warning, 'Option foo in section None')
3138
 
        self.assertEndsWith(warning, 'was changed from bar to <CREATED>.'
3139
 
                            ' The <DELETED> value will be saved.')
3140
 
 
3141
 
 
3142
 
class TestQuotingIniFileStore(tests.TestCaseWithTransport):
3143
 
 
3144
 
    def get_store(self):
3145
 
        return config.TransportIniFileStore(self.get_transport(), 'foo.conf')
3146
 
 
3147
 
    def test_get_quoted_string(self):
3148
 
        store = self.get_store()
3149
 
        store._load_from_string('foo= " abc "')
3150
 
        stack = config.Stack([store.get_sections])
3151
 
        self.assertEquals(' abc ', stack.get('foo'))
3152
 
 
3153
 
    def test_set_quoted_string(self):
3154
 
        store = self.get_store()
3155
 
        stack = config.Stack([store.get_sections], store)
3156
 
        stack.set('foo', ' a b c ')
3157
 
        store.save()
3158
 
        self.assertFileEqual('foo = " a b c "' + os.linesep, 'foo.conf')
3159
 
 
3160
2915
 
3161
2916
class TestTransportIniFileStore(TestStore):
3162
2917
 
3380
3135
 
3381
3136
    def get_section(self, options, extra_path):
3382
3137
        section = config.Section('foo', options)
3383
 
        return config.LocationSection(section, extra_path)
 
3138
        # We don't care about the length so we use '0'
 
3139
        return config.LocationSection(section, 0, extra_path)
3384
3140
 
3385
3141
    def test_simple_option(self):
3386
3142
        section = self.get_section({'foo': 'bar'}, '')
3423
3179
                           '/quux/quux'],
3424
3180
                          [section.id for _, section in store.get_sections()])
3425
3181
        matcher = config.LocationMatcher(store, '/foo/bar/quux')
3426
 
        sections = [section for _, section in matcher.get_sections()]
 
3182
        sections = [section for s, section in matcher.get_sections()]
 
3183
        self.assertEquals([3, 2],
 
3184
                          [section.length for section in sections])
3427
3185
        self.assertEquals(['/foo/bar', '/foo'],
3428
3186
                          [section.id for section in sections])
3429
3187
        self.assertEquals(['quux', 'bar/quux'],
3440
3198
        self.assertEquals(['/foo', '/foo/bar'],
3441
3199
                          [section.id for _, section in store.get_sections()])
3442
3200
        matcher = config.LocationMatcher(store, '/foo/bar/baz')
3443
 
        sections = [section for _, section in matcher.get_sections()]
 
3201
        sections = [section for s, section in matcher.get_sections()]
 
3202
        self.assertEquals([3, 2],
 
3203
                          [section.length for section in sections])
3444
3204
        self.assertEquals(['/foo/bar', '/foo'],
3445
3205
                          [section.id for section in sections])
3446
3206
        self.assertEquals(['baz', 'bar/baz'],
3471
3231
        self.assertEquals(expected_location, matcher.location)
3472
3232
 
3473
3233
 
3474
 
class TestStartingPathMatcher(TestStore):
3475
 
 
3476
 
    def setUp(self):
3477
 
        super(TestStartingPathMatcher, self).setUp()
3478
 
        # Any simple store is good enough
3479
 
        self.store = config.IniFileStore()
3480
 
 
3481
 
    def assertSectionIDs(self, expected, location, content):
3482
 
        self.store._load_from_string(content)
3483
 
        matcher = config.StartingPathMatcher(self.store, location)
3484
 
        sections = list(matcher.get_sections())
3485
 
        self.assertLength(len(expected), sections)
3486
 
        self.assertEqual(expected, [section.id for _, section in sections])
3487
 
        return sections
3488
 
 
3489
 
    def test_empty(self):
3490
 
        self.assertSectionIDs([], self.get_url(), '')
3491
 
 
3492
 
    def test_url_vs_local_paths(self):
3493
 
        # The matcher location is an url and the section names are local paths
3494
 
        sections = self.assertSectionIDs(['/foo/bar', '/foo'],
3495
 
                                         'file:///foo/bar/baz', '''\
3496
 
[/foo]
3497
 
[/foo/bar]
3498
 
''')
3499
 
 
3500
 
    def test_local_path_vs_url(self):
3501
 
        # The matcher location is a local path and the section names are urls
3502
 
        sections = self.assertSectionIDs(['file:///foo/bar', 'file:///foo'],
3503
 
                                         '/foo/bar/baz', '''\
3504
 
[file:///foo]
3505
 
[file:///foo/bar]
3506
 
''')
3507
 
 
3508
 
 
3509
 
    def test_no_name_section_included_when_present(self):
3510
 
        # Note that other tests will cover the case where the no-name section
3511
 
        # is empty and as such, not included.
3512
 
        sections = self.assertSectionIDs(['/foo/bar', '/foo', None],
3513
 
                                         '/foo/bar/baz', '''\
3514
 
option = defined so the no-name section exists
3515
 
[/foo]
3516
 
[/foo/bar]
3517
 
''')
3518
 
        self.assertEquals(['baz', 'bar/baz', '/foo/bar/baz'],
3519
 
                          [s.locals['relpath'] for _, s in sections])
3520
 
 
3521
 
    def test_order_reversed(self):
3522
 
        self.assertSectionIDs(['/foo/bar', '/foo'], '/foo/bar/baz', '''\
3523
 
[/foo]
3524
 
[/foo/bar]
3525
 
''')
3526
 
 
3527
 
    def test_unrelated_section_excluded(self):
3528
 
        self.assertSectionIDs(['/foo/bar', '/foo'], '/foo/bar/baz', '''\
3529
 
[/foo]
3530
 
[/foo/qux]
3531
 
[/foo/bar]
3532
 
''')
3533
 
 
3534
 
    def test_glob_included(self):
3535
 
        sections = self.assertSectionIDs(['/foo/*/baz', '/foo/b*', '/foo'],
3536
 
                                         '/foo/bar/baz', '''\
3537
 
[/foo]
3538
 
[/foo/qux]
3539
 
[/foo/b*]
3540
 
[/foo/*/baz]
3541
 
''')
3542
 
        # Note that 'baz' as a relpath for /foo/b* is not fully correct, but
3543
 
        # nothing really is... as far using {relpath} to append it to something
3544
 
        # else, this seems good enough though.
3545
 
        self.assertEquals(['', 'baz', 'bar/baz'],
3546
 
                          [s.locals['relpath'] for _, s in sections])
3547
 
 
3548
 
    def test_respect_order(self):
3549
 
        self.assertSectionIDs(['/foo', '/foo/b*', '/foo/*/baz'],
3550
 
                              '/foo/bar/baz', '''\
3551
 
[/foo/*/baz]
3552
 
[/foo/qux]
3553
 
[/foo/b*]
3554
 
[/foo]
3555
 
''')
3556
 
 
3557
 
 
3558
3234
class TestNameMatcher(TestStore):
3559
3235
 
3560
3236
    def setUp(self):
3586
3262
        self.assertLength(0, sections)
3587
3263
 
3588
3264
 
3589
 
class TestBaseStackGet(tests.TestCase):
3590
 
 
3591
 
    def setUp(self):
3592
 
        super(TestBaseStackGet, self).setUp()
 
3265
class TestStackGet(tests.TestCase):
 
3266
 
 
3267
    # FIXME: This should be parametrized for all known Stack or dedicated
 
3268
    # paramerized tests created to avoid bloating -- vila 2011-03-31
 
3269
 
 
3270
    def overrideOptionRegistry(self):
3593
3271
        self.overrideAttr(config, 'option_registry', config.OptionRegistry())
3594
3272
 
3595
 
    def test_get_first_definition(self):
3596
 
        store1 = config.IniFileStore()
3597
 
        store1._load_from_string('foo=bar')
3598
 
        store2 = config.IniFileStore()
3599
 
        store2._load_from_string('foo=baz')
3600
 
        conf = config.Stack([store1.get_sections, store2.get_sections])
3601
 
        self.assertEquals('bar', conf.get('foo'))
 
3273
    def test_single_config_get(self):
 
3274
        conf = dict(foo='bar')
 
3275
        conf_stack = config.Stack([conf])
 
3276
        self.assertEquals('bar', conf_stack.get('foo'))
3602
3277
 
3603
3278
    def test_get_with_registered_default_value(self):
3604
 
        config.option_registry.register(config.Option('foo', default='bar'))
3605
 
        conf_stack = config.Stack([])
 
3279
        conf_stack = config.Stack([dict()])
 
3280
        opt = config.Option('foo', default='bar')
 
3281
        self.overrideOptionRegistry()
 
3282
        config.option_registry.register('foo', opt)
3606
3283
        self.assertEquals('bar', conf_stack.get('foo'))
3607
3284
 
3608
3285
    def test_get_without_registered_default_value(self):
3609
 
        config.option_registry.register(config.Option('foo'))
3610
 
        conf_stack = config.Stack([])
 
3286
        conf_stack = config.Stack([dict()])
 
3287
        opt = config.Option('foo')
 
3288
        self.overrideOptionRegistry()
 
3289
        config.option_registry.register('foo', opt)
3611
3290
        self.assertEquals(None, conf_stack.get('foo'))
3612
3291
 
3613
3292
    def test_get_without_default_value_for_not_registered(self):
3614
 
        conf_stack = config.Stack([])
 
3293
        conf_stack = config.Stack([dict()])
 
3294
        opt = config.Option('foo')
 
3295
        self.overrideOptionRegistry()
3615
3296
        self.assertEquals(None, conf_stack.get('foo'))
3616
3297
 
 
3298
    def test_get_first_definition(self):
 
3299
        conf1 = dict(foo='bar')
 
3300
        conf2 = dict(foo='baz')
 
3301
        conf_stack = config.Stack([conf1, conf2])
 
3302
        self.assertEquals('bar', conf_stack.get('foo'))
 
3303
 
 
3304
    def test_get_embedded_definition(self):
 
3305
        conf1 = dict(yy='12')
 
3306
        conf2 = config.Stack([dict(xx='42'), dict(foo='baz')])
 
3307
        conf_stack = config.Stack([conf1, conf2])
 
3308
        self.assertEquals('baz', conf_stack.get('foo'))
 
3309
 
3617
3310
    def test_get_for_empty_section_callable(self):
3618
3311
        conf_stack = config.Stack([lambda : []])
3619
3312
        self.assertEquals(None, conf_stack.get('foo'))
3620
3313
 
3621
3314
    def test_get_for_broken_callable(self):
3622
3315
        # Trying to use and invalid callable raises an exception on first use
3623
 
        conf_stack = config.Stack([object])
 
3316
        conf_stack = config.Stack([lambda : object()])
3624
3317
        self.assertRaises(TypeError, conf_stack.get, 'foo')
3625
3318
 
3626
3319
 
3627
 
class TestStackWithSimpleStore(tests.TestCase):
3628
 
 
3629
 
    def setUp(self):
3630
 
        super(TestStackWithSimpleStore, self).setUp()
3631
 
        self.overrideAttr(config, 'option_registry', config.OptionRegistry())
3632
 
        self.registry = config.option_registry
3633
 
 
3634
 
    def get_conf(self, content=None):
3635
 
        return config.MemoryStack(content)
3636
 
 
3637
 
    def test_override_value_from_env(self):
3638
 
        self.registry.register(
3639
 
            config.Option('foo', default='bar', override_from_env=['FOO']))
3640
 
        self.overrideEnv('FOO', 'quux')
3641
 
        # Env variable provides a default taking over the option one
3642
 
        conf = self.get_conf('foo=store')
3643
 
        self.assertEquals('quux', conf.get('foo'))
3644
 
 
3645
 
    def test_first_override_value_from_env_wins(self):
3646
 
        self.registry.register(
3647
 
            config.Option('foo', default='bar',
3648
 
                          override_from_env=['NO_VALUE', 'FOO', 'BAZ']))
3649
 
        self.overrideEnv('FOO', 'foo')
3650
 
        self.overrideEnv('BAZ', 'baz')
3651
 
        # The first env var set wins
3652
 
        conf = self.get_conf('foo=store')
3653
 
        self.assertEquals('foo', conf.get('foo'))
3654
 
 
3655
 
 
3656
 
class TestMemoryStack(tests.TestCase):
3657
 
 
3658
 
    def test_get(self):
3659
 
        conf = config.MemoryStack('foo=bar')
3660
 
        self.assertEquals('bar', conf.get('foo'))
3661
 
 
3662
 
    def test_set(self):
3663
 
        conf = config.MemoryStack('foo=bar')
3664
 
        conf.set('foo', 'baz')
3665
 
        self.assertEquals('baz', conf.get('foo'))
3666
 
 
3667
 
    def test_no_content(self):
3668
 
        conf = config.MemoryStack()
3669
 
        # No content means no loading
3670
 
        self.assertFalse(conf.store.is_loaded())
3671
 
        self.assertRaises(NotImplementedError, conf.get, 'foo')
3672
 
        # But a content can still be provided
3673
 
        conf.store._load_from_string('foo=bar')
3674
 
        self.assertEquals('bar', conf.get('foo'))
3675
 
 
3676
 
 
3677
 
class TestStackIterSections(tests.TestCase):
3678
 
 
3679
 
    def test_empty_stack(self):
3680
 
        conf = config.Stack([])
3681
 
        sections = list(conf.iter_sections())
3682
 
        self.assertLength(0, sections)
3683
 
 
3684
 
    def test_empty_store(self):
3685
 
        store = config.IniFileStore()
3686
 
        store._load_from_string('')
3687
 
        conf = config.Stack([store.get_sections])
3688
 
        sections = list(conf.iter_sections())
3689
 
        self.assertLength(0, sections)
3690
 
 
3691
 
    def test_simple_store(self):
3692
 
        store = config.IniFileStore()
3693
 
        store._load_from_string('foo=bar')
3694
 
        conf = config.Stack([store.get_sections])
3695
 
        tuples = list(conf.iter_sections())
3696
 
        self.assertLength(1, tuples)
3697
 
        (found_store, found_section) = tuples[0]
3698
 
        self.assertIs(store, found_store)
3699
 
 
3700
 
    def test_two_stores(self):
3701
 
        store1 = config.IniFileStore()
3702
 
        store1._load_from_string('foo=bar')
3703
 
        store2 = config.IniFileStore()
3704
 
        store2._load_from_string('bar=qux')
3705
 
        conf = config.Stack([store1.get_sections, store2.get_sections])
3706
 
        tuples = list(conf.iter_sections())
3707
 
        self.assertLength(2, tuples)
3708
 
        self.assertIs(store1, tuples[0][0])
3709
 
        self.assertIs(store2, tuples[1][0])
3710
 
 
3711
 
 
3712
3320
class TestStackWithTransport(tests.TestCaseWithTransport):
3713
3321
 
3714
3322
    scenarios = [(key, {'get_stack': builder}) for key, builder
3744
3352
        self.assertEquals((self.conf, 'foo', 'bar'), calls[0])
3745
3353
 
3746
3354
 
3747
 
class TestStackGetWithConverter(tests.TestCase):
 
3355
class TestStackGetWithConverter(tests.TestCaseWithTransport):
3748
3356
 
3749
3357
    def setUp(self):
3750
3358
        super(TestStackGetWithConverter, self).setUp()
3751
3359
        self.overrideAttr(config, 'option_registry', config.OptionRegistry())
3752
3360
        self.registry = config.option_registry
3753
 
 
3754
 
    def get_conf(self, content=None):
3755
 
        return config.MemoryStack(content)
 
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)
3756
3366
 
3757
3367
    def register_bool_option(self, name, default=None, default_from_env=None):
3758
3368
        b = config.Option(name, help='A boolean.',
3762
3372
 
3763
3373
    def test_get_default_bool_None(self):
3764
3374
        self.register_bool_option('foo')
3765
 
        conf = self.get_conf('')
3766
 
        self.assertEquals(None, conf.get('foo'))
 
3375
        self.assertEquals(None, self.conf.get('foo'))
3767
3376
 
3768
3377
    def test_get_default_bool_True(self):
3769
3378
        self.register_bool_option('foo', u'True')
3770
 
        conf = self.get_conf('')
3771
 
        self.assertEquals(True, conf.get('foo'))
 
3379
        self.assertEquals(True, self.conf.get('foo'))
3772
3380
 
3773
3381
    def test_get_default_bool_False(self):
3774
3382
        self.register_bool_option('foo', False)
3775
 
        conf = self.get_conf('')
3776
 
        self.assertEquals(False, conf.get('foo'))
 
3383
        self.assertEquals(False, self.conf.get('foo'))
3777
3384
 
3778
3385
    def test_get_default_bool_False_as_string(self):
3779
3386
        self.register_bool_option('foo', u'False')
3780
 
        conf = self.get_conf('')
3781
 
        self.assertEquals(False, conf.get('foo'))
 
3387
        self.assertEquals(False, self.conf.get('foo'))
3782
3388
 
3783
3389
    def test_get_default_bool_from_env_converted(self):
3784
3390
        self.register_bool_option('foo', u'True', default_from_env=['FOO'])
3785
3391
        self.overrideEnv('FOO', 'False')
3786
 
        conf = self.get_conf('')
3787
 
        self.assertEquals(False, conf.get('foo'))
 
3392
        self.assertEquals(False, self.conf.get('foo'))
3788
3393
 
3789
3394
    def test_get_default_bool_when_conversion_fails(self):
3790
3395
        self.register_bool_option('foo', default='True')
3791
 
        conf = self.get_conf('foo=invalid boolean')
3792
 
        self.assertEquals(True, conf.get('foo'))
 
3396
        self.conf.store._load_from_string('foo=invalid boolean')
 
3397
        self.assertEquals(True, self.conf.get('foo'))
3793
3398
 
3794
3399
    def register_integer_option(self, name,
3795
3400
                                default=None, default_from_env=None):
3800
3405
 
3801
3406
    def test_get_default_integer_None(self):
3802
3407
        self.register_integer_option('foo')
3803
 
        conf = self.get_conf('')
3804
 
        self.assertEquals(None, conf.get('foo'))
 
3408
        self.assertEquals(None, self.conf.get('foo'))
3805
3409
 
3806
3410
    def test_get_default_integer(self):
3807
3411
        self.register_integer_option('foo', 42)
3808
 
        conf = self.get_conf('')
3809
 
        self.assertEquals(42, conf.get('foo'))
 
3412
        self.assertEquals(42, self.conf.get('foo'))
3810
3413
 
3811
3414
    def test_get_default_integer_as_string(self):
3812
3415
        self.register_integer_option('foo', u'42')
3813
 
        conf = self.get_conf('')
3814
 
        self.assertEquals(42, conf.get('foo'))
 
3416
        self.assertEquals(42, self.conf.get('foo'))
3815
3417
 
3816
3418
    def test_get_default_integer_from_env(self):
3817
3419
        self.register_integer_option('foo', default_from_env=['FOO'])
3818
3420
        self.overrideEnv('FOO', '18')
3819
 
        conf = self.get_conf('')
3820
 
        self.assertEquals(18, conf.get('foo'))
 
3421
        self.assertEquals(18, self.conf.get('foo'))
3821
3422
 
3822
3423
    def test_get_default_integer_when_conversion_fails(self):
3823
3424
        self.register_integer_option('foo', default='12')
3824
 
        conf = self.get_conf('foo=invalid integer')
3825
 
        self.assertEquals(12, conf.get('foo'))
 
3425
        self.conf.store._load_from_string('foo=invalid integer')
 
3426
        self.assertEquals(12, self.conf.get('foo'))
3826
3427
 
3827
3428
    def register_list_option(self, name, default=None, default_from_env=None):
3828
 
        l = config.ListOption(name, help='A list.', default=default,
3829
 
                              default_from_env=default_from_env)
 
3429
        l = config.Option(name, help='A list.',
 
3430
                          default=default, default_from_env=default_from_env,
 
3431
                          from_unicode=config.list_from_store)
3830
3432
        self.registry.register(l)
3831
3433
 
3832
3434
    def test_get_default_list_None(self):
3833
3435
        self.register_list_option('foo')
3834
 
        conf = self.get_conf('')
3835
 
        self.assertEquals(None, conf.get('foo'))
 
3436
        self.assertEquals(None, self.conf.get('foo'))
3836
3437
 
3837
3438
    def test_get_default_list_empty(self):
3838
3439
        self.register_list_option('foo', '')
3839
 
        conf = self.get_conf('')
3840
 
        self.assertEquals([], conf.get('foo'))
 
3440
        self.assertEquals([], self.conf.get('foo'))
3841
3441
 
3842
3442
    def test_get_default_list_from_env(self):
3843
3443
        self.register_list_option('foo', default_from_env=['FOO'])
3844
3444
        self.overrideEnv('FOO', '')
3845
 
        conf = self.get_conf('')
3846
 
        self.assertEquals([], conf.get('foo'))
 
3445
        self.assertEquals([], self.conf.get('foo'))
3847
3446
 
3848
3447
    def test_get_with_list_converter_no_item(self):
3849
3448
        self.register_list_option('foo', None)
3850
 
        conf = self.get_conf('foo=,')
3851
 
        self.assertEquals([], conf.get('foo'))
 
3449
        self.conf.store._load_from_string('foo=,')
 
3450
        self.assertEquals([], self.conf.get('foo'))
3852
3451
 
3853
3452
    def test_get_with_list_converter_many_items(self):
3854
3453
        self.register_list_option('foo', None)
3855
 
        conf = self.get_conf('foo=m,o,r,e')
3856
 
        self.assertEquals(['m', 'o', 'r', 'e'], conf.get('foo'))
 
3454
        self.conf.store._load_from_string('foo=m,o,r,e')
 
3455
        self.assertEquals(['m', 'o', 'r', 'e'], self.conf.get('foo'))
3857
3456
 
3858
3457
    def test_get_with_list_converter_embedded_spaces_many_items(self):
3859
3458
        self.register_list_option('foo', None)
3860
 
        conf = self.get_conf('foo=" bar", "baz "')
3861
 
        self.assertEquals([' bar', 'baz '], conf.get('foo'))
 
3459
        self.conf.store._load_from_string('foo=" bar", "baz "')
 
3460
        self.assertEquals([' bar', 'baz '], self.conf.get('foo'))
3862
3461
 
3863
3462
    def test_get_with_list_converter_stripped_spaces_many_items(self):
3864
3463
        self.register_list_option('foo', None)
3865
 
        conf = self.get_conf('foo= bar ,  baz ')
3866
 
        self.assertEquals(['bar', 'baz'], conf.get('foo'))
 
3464
        self.conf.store._load_from_string('foo= bar ,  baz ')
 
3465
        self.assertEquals(['bar', 'baz'], self.conf.get('foo'))
3867
3466
 
3868
3467
 
3869
3468
class TestIterOptionRefs(tests.TestCase):
3894
3493
                         (False, ''),],
3895
3494
                        '{foo}{bar}')
3896
3495
 
3897
 
    def test_newline_in_refs_are_not_matched(self):
3898
 
        self.assertRefs([(False, '{\nxx}{xx\n}{{\n}}')], '{\nxx}{xx\n}{{\n}}')
3899
 
 
3900
3496
 
3901
3497
class TestStackExpandOptions(tests.TestCaseWithTransport):
3902
3498
 
3904
3500
        super(TestStackExpandOptions, self).setUp()
3905
3501
        self.overrideAttr(config, 'option_registry', config.OptionRegistry())
3906
3502
        self.registry = config.option_registry
3907
 
        store = config.TransportIniFileStore(self.get_transport(), 'foo.conf')
3908
 
        self.conf = config.Stack([store.get_sections], store)
 
3503
        self.conf = build_branch_stack(self)
3909
3504
 
3910
3505
    def assertExpansion(self, expected, string, env=None):
3911
3506
        self.assertEquals(expected, self.conf.expand_options(string, env))
3983
3578
list={foo},{bar},{baz}
3984
3579
''')
3985
3580
        self.registry.register(
3986
 
            config.ListOption('list'))
 
3581
            config.Option('list', from_unicode=config.list_from_store))
3987
3582
        self.assertEquals(['start', 'middle', 'end'],
3988
3583
                           self.conf.get('list', expand=True))
3989
3584
 
3994
3589
baz=end
3995
3590
list={foo}
3996
3591
''')
3997
 
        self.registry.register(config.ListOption('list'))
3998
 
        # Register an intermediate option as a list to ensure no conversion
3999
 
        # happen while expanding. Conversion should only occur for the original
4000
 
        # option ('list' here).
4001
 
        self.registry.register(config.ListOption('baz'))
 
3592
        self.registry.register(
 
3593
            config.Option('list', from_unicode=config.list_from_store))
4002
3594
        self.assertEquals(['start', 'middle', 'end'],
4003
3595
                           self.conf.get('list', expand=True))
4004
3596
 
4013
3605
''')
4014
3606
        # What matters is what the registration says, the conversion happens
4015
3607
        # only after all expansions have been performed
4016
 
        self.registry.register(config.ListOption('hidden'))
 
3608
        self.registry.register(
 
3609
            config.Option('hidden', from_unicode=config.list_from_store))
4017
3610
        self.assertEquals(['bin', 'go'],
4018
3611
                          self.conf.get('hidden', expand=True))
4019
3612
 
4884
4477
 
4885
4478
    def test_auto_user_id(self):
4886
4479
        """Automatic inference of user name.
4887
 
 
 
4480
        
4888
4481
        This is a bit hard to test in an isolated way, because it depends on
4889
4482
        system functions that go direct to /etc or perhaps somewhere else.
4890
4483
        But it's reasonable to say that on Unix, with an /etc/mailname, we ought
4900
4493
        else:
4901
4494
            self.assertEquals((None, None), (realname, address))
4902
4495
 
4903
 
 
4904
 
class EmailOptionTests(tests.TestCase):
4905
 
 
4906
 
    def test_default_email_uses_BZR_EMAIL(self):
4907
 
        conf = config.MemoryStack('email=jelmer@debian.org')
4908
 
        # BZR_EMAIL takes precedence over EMAIL
4909
 
        self.overrideEnv('BZR_EMAIL', 'jelmer@samba.org')
4910
 
        self.overrideEnv('EMAIL', 'jelmer@apache.org')
4911
 
        self.assertEquals('jelmer@samba.org', conf.get('email'))
4912
 
 
4913
 
    def test_default_email_uses_EMAIL(self):
4914
 
        conf = config.MemoryStack('')
4915
 
        self.overrideEnv('BZR_EMAIL', None)
4916
 
        self.overrideEnv('EMAIL', 'jelmer@apache.org')
4917
 
        self.assertEquals('jelmer@apache.org', conf.get('email'))
4918
 
 
4919
 
    def test_BZR_EMAIL_overrides(self):
4920
 
        conf = config.MemoryStack('email=jelmer@debian.org')
4921
 
        self.overrideEnv('BZR_EMAIL', 'jelmer@apache.org')
4922
 
        self.assertEquals('jelmer@apache.org', conf.get('email'))
4923
 
        self.overrideEnv('BZR_EMAIL', None)
4924
 
        self.overrideEnv('EMAIL', 'jelmer@samba.org')
4925
 
        self.assertEquals('jelmer@debian.org', conf.get('email'))
4926
 
 
4927
 
 
4928
 
class MailClientOptionTests(tests.TestCase):
4929
 
 
4930
 
    def test_default(self):
4931
 
        conf = config.MemoryStack('')
4932
 
        client = conf.get('mail_client')
4933
 
        self.assertIs(client, mail_client.DefaultMail)
4934
 
 
4935
 
    def test_evolution(self):
4936
 
        conf = config.MemoryStack('mail_client=evolution')
4937
 
        client = conf.get('mail_client')
4938
 
        self.assertIs(client, mail_client.Evolution)
4939
 
 
4940
 
    def test_kmail(self):
4941
 
        conf = config.MemoryStack('mail_client=kmail')
4942
 
        client = conf.get('mail_client')
4943
 
        self.assertIs(client, mail_client.KMail)
4944
 
 
4945
 
    def test_mutt(self):
4946
 
        conf = config.MemoryStack('mail_client=mutt')
4947
 
        client = conf.get('mail_client')
4948
 
        self.assertIs(client, mail_client.Mutt)
4949
 
 
4950
 
    def test_thunderbird(self):
4951
 
        conf = config.MemoryStack('mail_client=thunderbird')
4952
 
        client = conf.get('mail_client')
4953
 
        self.assertIs(client, mail_client.Thunderbird)
4954
 
 
4955
 
    def test_explicit_default(self):
4956
 
        conf = config.MemoryStack('mail_client=default')
4957
 
        client = conf.get('mail_client')
4958
 
        self.assertIs(client, mail_client.DefaultMail)
4959
 
 
4960
 
    def test_editor(self):
4961
 
        conf = config.MemoryStack('mail_client=editor')
4962
 
        client = conf.get('mail_client')
4963
 
        self.assertIs(client, mail_client.Editor)
4964
 
 
4965
 
    def test_mapi(self):
4966
 
        conf = config.MemoryStack('mail_client=mapi')
4967
 
        client = conf.get('mail_client')
4968
 
        self.assertIs(client, mail_client.MAPIClient)
4969
 
 
4970
 
    def test_xdg_email(self):
4971
 
        conf = config.MemoryStack('mail_client=xdg-email')
4972
 
        client = conf.get('mail_client')
4973
 
        self.assertIs(client, mail_client.XDGEmail)
4974
 
 
4975
 
    def test_unknown(self):
4976
 
        conf = config.MemoryStack('mail_client=firebird')
4977
 
        self.assertRaises(errors.ConfigOptionValueError, conf.get,
4978
 
                'mail_client')