~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/__init__.py

  • Committer: Vincent Ladeuil
  • Date: 2011-07-06 09:22:00 UTC
  • mfrom: (6008 +trunk)
  • mto: (6012.1.1 trunk)
  • mto: This revision was merged to the branch mainline in revision 6013.
  • Revision ID: v.ladeuil+lp@free.fr-20110706092200-7iai2mwzc0sqdsvf
MergingĀ inĀ trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
142
142
    'BZREMAIL': None, # may still be present in the environment
143
143
    'EMAIL': 'jrandom@example.com', # set EMAIL as bzr does not guess
144
144
    'BZR_PROGRESS_BAR': None,
145
 
    'BZR_LOG': None,
 
145
    # This should trap leaks to ~/.bzr.log. This occurs when tests use TestCase
 
146
    # as a base class instead of TestCaseInTempDir. Tests inheriting from
 
147
    # TestCase should not use disk resources, BZR_LOG is one.
 
148
    'BZR_LOG': '/you-should-use-TestCaseInTempDir-if-you-need-a-log-file',
146
149
    'BZR_PLUGIN_PATH': None,
147
150
    'BZR_DISABLE_PLUGINS': None,
148
151
    'BZR_PLUGINS_AT': None,
377
380
        if isinstance(test, TestCase):
378
381
            test.addCleanup(self._check_leaked_threads, test)
379
382
 
 
383
    def stopTest(self, test):
 
384
        super(ExtendedTestResult, self).stopTest(test)
 
385
        # Manually break cycles, means touching various private things but hey
 
386
        getDetails = getattr(test, "getDetails", None)
 
387
        if getDetails is not None:
 
388
            getDetails().clear()
 
389
        type_equality_funcs = getattr(test, "_type_equality_funcs", None)
 
390
        if type_equality_funcs is not None:
 
391
            type_equality_funcs.clear()
 
392
        self._traceback_from_test = None
 
393
 
380
394
    def startTests(self):
381
395
        self.report_tests_starting()
382
396
        self._active_threads = threading.enumerate()
383
397
 
384
 
    def stopTest(self, test):
385
 
        self._traceback_from_test = None
386
 
 
387
398
    def _check_leaked_threads(self, test):
388
399
        """See if any threads have leaked since last call
389
400
 
449
460
        self.known_failure_count += 1
450
461
        self.report_known_failure(test, err)
451
462
 
 
463
    def addUnexpectedSuccess(self, test, details=None):
 
464
        """Tell result the test unexpectedly passed, counting as a failure
 
465
 
 
466
        When the minimum version of testtools required becomes 0.9.8 this
 
467
        can be updated to use the new handling there.
 
468
        """
 
469
        super(ExtendedTestResult, self).addFailure(test, details=details)
 
470
        self.failure_count += 1
 
471
        self.report_unexpected_success(test,
 
472
            "".join(details["reason"].iter_text()))
 
473
        if self.stop_early:
 
474
            self.stop()
 
475
 
452
476
    def addNotSupported(self, test, feature):
453
477
        """The test will not be run because of a missing feature.
454
478
        """
613
637
    def report_known_failure(self, test, err):
614
638
        pass
615
639
 
 
640
    def report_unexpected_success(self, test, reason):
 
641
        self.stream.write('FAIL: %s\n    %s: %s\n' % (
 
642
            self._test_description(test),
 
643
            "Unexpected success. Should have failed",
 
644
            reason,
 
645
            ))
 
646
 
616
647
    def report_skip(self, test, reason):
617
648
        pass
618
649
 
670
701
                % (self._testTimeString(test),
671
702
                   self._error_summary(err)))
672
703
 
 
704
    def report_unexpected_success(self, test, reason):
 
705
        self.stream.write(' FAIL %s\n%s: %s\n'
 
706
                % (self._testTimeString(test),
 
707
                   "Unexpected success. Should have failed",
 
708
                   reason))
 
709
 
673
710
    def report_success(self, test):
674
711
        self.stream.write('   OK %s\n' % self._testTimeString(test))
675
712
        for bench_called, stats in getattr(test, '_benchcalls', []):
894
931
 
895
932
    The method is really a factory and users are expected to use it as such.
896
933
    """
897
 
    
 
934
 
898
935
    kwargs['setUp'] = isolated_doctest_setUp
899
936
    kwargs['tearDown'] = isolated_doctest_tearDown
900
937
    return doctest.DocTestSuite(*args, **kwargs)
937
974
        super(TestCase, self).setUp()
938
975
        for feature in getattr(self, '_test_needs_features', []):
939
976
            self.requireFeature(feature)
940
 
        self._log_contents = None
941
 
        self.addDetail("log", content.Content(content.ContentType("text",
942
 
            "plain", {"charset": "utf8"}),
943
 
            lambda:[self._get_log(keep_log_file=True)]))
944
977
        self._cleanEnvironment()
945
978
        self._silenceUI()
946
979
        self._startLogFile()
954
987
        # between tests.  We should get rid of this altogether: bug 656694. --
955
988
        # mbp 20101008
956
989
        self.overrideAttr(bzrlib.trace, '_verbosity_level', 0)
 
990
        # Isolate config option expansion until its default value for bzrlib is
 
991
        # settled on or a the FIXME associated with _get_expand_default_value
 
992
        # is addressed -- vila 20110219
 
993
        self.overrideAttr(config, '_expand_default_value', None)
 
994
        self._log_files = set()
 
995
        # Each key in the ``_counters`` dict holds a value for a different
 
996
        # counter. When the test ends, addDetail() should be used to output the
 
997
        # counter values. This happens in install_counter_hook().
 
998
        self._counters = {}
 
999
        if 'config_stats' in selftest_debug_flags:
 
1000
            self._install_config_stats_hooks()
957
1001
 
958
1002
    def debug(self):
959
1003
        # debug a frame up.
976
1020
        if name in details:
977
1021
            del details[name]
978
1022
 
 
1023
    def install_counter_hook(self, hooks, name, counter_name=None):
 
1024
        """Install a counting hook.
 
1025
 
 
1026
        Any hook can be counted as long as it doesn't need to return a value.
 
1027
 
 
1028
        :param hooks: Where the hook should be installed.
 
1029
 
 
1030
        :param name: The hook name that will be counted.
 
1031
 
 
1032
        :param counter_name: The counter identifier in ``_counters``, defaults
 
1033
            to ``name``.
 
1034
        """
 
1035
        _counters = self._counters # Avoid closing over self
 
1036
        if counter_name is None:
 
1037
            counter_name = name
 
1038
        if _counters.has_key(counter_name):
 
1039
            raise AssertionError('%s is already used as a counter name'
 
1040
                                  % (counter_name,))
 
1041
        _counters[counter_name] = 0
 
1042
        self.addDetail(counter_name, content.Content(content.UTF8_TEXT,
 
1043
            lambda: ['%d' % (_counters[counter_name],)]))
 
1044
        def increment_counter(*args, **kwargs):
 
1045
            _counters[counter_name] += 1
 
1046
        label = 'count %s calls' % (counter_name,)
 
1047
        hooks.install_named_hook(name, increment_counter, label)
 
1048
        self.addCleanup(hooks.uninstall_named_hook, name, label)
 
1049
 
 
1050
    def _install_config_stats_hooks(self):
 
1051
        """Install config hooks to count hook calls.
 
1052
 
 
1053
        """
 
1054
        for hook_name in ('get', 'set', 'remove', 'load', 'save'):
 
1055
            self.install_counter_hook(config.ConfigHooks, hook_name,
 
1056
                                       'config.%s' % (hook_name,))
 
1057
 
 
1058
        # The OldConfigHooks are private and need special handling to protect
 
1059
        # against recursive tests (tests that run other tests), so we just do
 
1060
        # manually what registering them into _builtin_known_hooks will provide
 
1061
        # us.
 
1062
        self.overrideAttr(config, 'OldConfigHooks', config._OldConfigHooks())
 
1063
        for hook_name in ('get', 'set', 'remove', 'load', 'save'):
 
1064
            self.install_counter_hook(config.OldConfigHooks, hook_name,
 
1065
                                      'old_config.%s' % (hook_name,))
 
1066
 
979
1067
    def _clear_debug_flags(self):
980
1068
        """Prevent externally set debug flags affecting tests.
981
1069
 
996
1084
        for key, (parent, name) in known_hooks.iter_parent_objects():
997
1085
            current_hooks = getattr(parent, name)
998
1086
            self._preserved_hooks[parent] = (name, current_hooks)
 
1087
        self._preserved_lazy_hooks = hooks._lazy_hooks
 
1088
        hooks._lazy_hooks = {}
999
1089
        self.addCleanup(self._restoreHooks)
1000
1090
        for key, (parent, name) in known_hooks.iter_parent_objects():
1001
1091
            factory = known_hooks.get(key)
1033
1123
        # break some locks on purpose and should be taken into account by
1034
1124
        # considering that breaking a lock is just a dirty way of releasing it.
1035
1125
        if len(acquired_locks) != (len(released_locks) + len(broken_locks)):
1036
 
            message = ('Different number of acquired and '
1037
 
                       'released or broken locks. (%s, %s + %s)' %
1038
 
                       (acquired_locks, released_locks, broken_locks))
 
1126
            message = (
 
1127
                'Different number of acquired and '
 
1128
                'released or broken locks.\n'
 
1129
                'acquired=%s\n'
 
1130
                'released=%s\n'
 
1131
                'broken=%s\n' %
 
1132
                (acquired_locks, released_locks, broken_locks))
1039
1133
            if not self._lock_check_thorough:
1040
1134
                # Rather than fail, just warn
1041
1135
                print "Broken test %s: %s" % (self, message)
1261
1355
                         'st_mtime did not match')
1262
1356
        self.assertEqual(expected.st_ctime, actual.st_ctime,
1263
1357
                         'st_ctime did not match')
1264
 
        if sys.platform != 'win32':
 
1358
        if sys.platform == 'win32':
1265
1359
            # On Win32 both 'dev' and 'ino' cannot be trusted. In python2.4 it
1266
1360
            # is 'dev' that varies, in python 2.5 (6?) it is st_ino that is
1267
 
            # odd. Regardless we shouldn't actually try to assert anything
1268
 
            # about their values
 
1361
            # odd. We just force it to always be 0 to avoid any problems.
 
1362
            self.assertEqual(0, expected.st_dev)
 
1363
            self.assertEqual(0, actual.st_dev)
 
1364
            self.assertEqual(0, expected.st_ino)
 
1365
            self.assertEqual(0, actual.st_ino)
 
1366
        else:
1269
1367
            self.assertEqual(expected.st_dev, actual.st_dev,
1270
1368
                             'st_dev did not match')
1271
1369
            self.assertEqual(expected.st_ino, actual.st_ino,
1280
1378
                length, len(obj_with_len), obj_with_len))
1281
1379
 
1282
1380
    def assertLogsError(self, exception_class, func, *args, **kwargs):
1283
 
        """Assert that func(*args, **kwargs) quietly logs a specific exception.
 
1381
        """Assert that `func(*args, **kwargs)` quietly logs a specific error.
1284
1382
        """
1285
1383
        captured = []
1286
1384
        orig_log_exception_quietly = trace.log_exception_quietly
1287
1385
        try:
1288
1386
            def capture():
1289
1387
                orig_log_exception_quietly()
1290
 
                captured.append(sys.exc_info())
 
1388
                captured.append(sys.exc_info()[1])
1291
1389
            trace.log_exception_quietly = capture
1292
1390
            func(*args, **kwargs)
1293
1391
        finally:
1294
1392
            trace.log_exception_quietly = orig_log_exception_quietly
1295
1393
        self.assertLength(1, captured)
1296
 
        err = captured[0][1]
 
1394
        err = captured[0]
1297
1395
        self.assertIsInstance(err, exception_class)
1298
1396
        return err
1299
1397
 
1450
1548
        else:
1451
1549
            self.assertEqual(expected_docstring, obj.__doc__)
1452
1550
 
 
1551
    @symbol_versioning.deprecated_method(symbol_versioning.deprecated_in((2, 4)))
1453
1552
    def failUnlessExists(self, path):
1454
1553
        return self.assertPathExists(path)
1455
1554
 
1462
1561
            self.assertTrue(osutils.lexists(path),
1463
1562
                path + " does not exist")
1464
1563
 
 
1564
    @symbol_versioning.deprecated_method(symbol_versioning.deprecated_in((2, 4)))
1465
1565
    def failIfExists(self, path):
1466
1566
        return self.assertPathDoesNotExist(path)
1467
1567
 
1504
1604
        not other callers that go direct to the warning module.
1505
1605
 
1506
1606
        To test that a deprecated method raises an error, do something like
1507
 
        this::
 
1607
        this (remember that both assertRaises and applyDeprecated delays *args
 
1608
        and **kwargs passing)::
1508
1609
 
1509
1610
            self.assertRaises(errors.ReservedId,
1510
1611
                self.applyDeprecated,
1592
1693
 
1593
1694
        The file is removed as the test is torn down.
1594
1695
        """
1595
 
        self._log_file = StringIO()
 
1696
        pseudo_log_file = StringIO()
 
1697
        def _get_log_contents_for_weird_testtools_api():
 
1698
            return [pseudo_log_file.getvalue().decode(
 
1699
                "utf-8", "replace").encode("utf-8")]
 
1700
        self.addDetail("log", content.Content(content.ContentType("text",
 
1701
            "plain", {"charset": "utf8"}),
 
1702
            _get_log_contents_for_weird_testtools_api))
 
1703
        self._log_file = pseudo_log_file
1596
1704
        self._log_memento = trace.push_log_file(self._log_file)
1597
1705
        self.addCleanup(self._finishLogFile)
1598
1706
 
1599
1707
    def _finishLogFile(self):
1600
1708
        """Finished with the log file.
1601
1709
 
1602
 
        Close the file and delete it, unless setKeepLogfile was called.
 
1710
        Close the file and delete it.
1603
1711
        """
1604
1712
        if trace._trace_file:
1605
1713
            # flush the log file, to get all content
1606
1714
            trace._trace_file.flush()
1607
1715
        trace.pop_log_file(self._log_memento)
1608
 
        # Cache the log result and delete the file on disk
1609
 
        self._get_log(False)
1610
1716
 
1611
1717
    def thisFailsStrictLockCheck(self):
1612
1718
        """It is known that this test would fail with -Dstrict_locks.
1661
1767
    def _restoreHooks(self):
1662
1768
        for klass, (name, hooks) in self._preserved_hooks.items():
1663
1769
            setattr(klass, name, hooks)
 
1770
        self._preserved_hooks.clear()
 
1771
        bzrlib.hooks._lazy_hooks = self._preserved_lazy_hooks
 
1772
        self._preserved_lazy_hooks.clear()
1664
1773
 
1665
1774
    def knownFailure(self, reason):
1666
1775
        """This test has failed for some known reason."""
1758
1867
    def log(self, *args):
1759
1868
        trace.mutter(*args)
1760
1869
 
1761
 
    def _get_log(self, keep_log_file=False):
1762
 
        """Internal helper to get the log from bzrlib.trace for this test.
1763
 
 
1764
 
        Please use self.getDetails, or self.get_log to access this in test case
1765
 
        code.
1766
 
 
1767
 
        :param keep_log_file: When True, if the log is still a file on disk
1768
 
            leave it as a file on disk. When False, if the log is still a file
1769
 
            on disk, the log file is deleted and the log preserved as
1770
 
            self._log_contents.
1771
 
        :return: A string containing the log.
1772
 
        """
1773
 
        if self._log_contents is not None:
1774
 
            try:
1775
 
                self._log_contents.decode('utf8')
1776
 
            except UnicodeDecodeError:
1777
 
                unicodestr = self._log_contents.decode('utf8', 'replace')
1778
 
                self._log_contents = unicodestr.encode('utf8')
1779
 
            return self._log_contents
1780
 
        if self._log_file is not None:
1781
 
            log_contents = self._log_file.getvalue()
1782
 
            try:
1783
 
                log_contents.decode('utf8')
1784
 
            except UnicodeDecodeError:
1785
 
                unicodestr = log_contents.decode('utf8', 'replace')
1786
 
                log_contents = unicodestr.encode('utf8')
1787
 
            if not keep_log_file:
1788
 
                self._log_file = None
1789
 
                # Permit multiple calls to get_log until we clean it up in
1790
 
                # finishLogFile
1791
 
                self._log_contents = log_contents
1792
 
            return log_contents
1793
 
        else:
1794
 
            return "No log file content."
1795
 
 
1796
1870
    def get_log(self):
1797
1871
        """Get a unicode string containing the log from bzrlib.trace.
1798
1872
 
1998
2072
    def start_bzr_subprocess(self, process_args, env_changes=None,
1999
2073
                             skip_if_plan_to_signal=False,
2000
2074
                             working_dir=None,
2001
 
                             allow_plugins=False):
 
2075
                             allow_plugins=False, stderr=subprocess.PIPE):
2002
2076
        """Start bzr in a subprocess for testing.
2003
2077
 
2004
2078
        This starts a new Python interpreter and runs bzr in there.
2016
2090
        :param skip_if_plan_to_signal: raise TestSkipped when true and system
2017
2091
            doesn't support signalling subprocesses.
2018
2092
        :param allow_plugins: If False (default) pass --no-plugins to bzr.
 
2093
        :param stderr: file to use for the subprocess's stderr.  Valid values
 
2094
            are those valid for the stderr argument of `subprocess.Popen`.
 
2095
            Default value is ``subprocess.PIPE``.
2019
2096
 
2020
2097
        :returns: Popen object for the started process.
2021
2098
        """
2047
2124
            # so we will avoid using it on all platforms, just to
2048
2125
            # make sure the code path is used, and we don't break on win32
2049
2126
            cleanup_environment()
 
2127
            # Include the subprocess's log file in the test details, in case
 
2128
            # the test fails due to an error in the subprocess.
 
2129
            self._add_subprocess_log(trace._get_bzr_log_filename())
2050
2130
            command = [sys.executable]
2051
2131
            # frozen executables don't need the path to bzr
2052
2132
            if getattr(sys, "frozen", None) is None:
2056
2136
            command.extend(process_args)
2057
2137
            process = self._popen(command, stdin=subprocess.PIPE,
2058
2138
                                  stdout=subprocess.PIPE,
2059
 
                                  stderr=subprocess.PIPE)
 
2139
                                  stderr=stderr)
2060
2140
        finally:
2061
2141
            restore_environment()
2062
2142
            if cwd is not None:
2064
2144
 
2065
2145
        return process
2066
2146
 
 
2147
    def _add_subprocess_log(self, log_file_path):
 
2148
        if len(self._log_files) == 0:
 
2149
            # Register an addCleanup func.  We do this on the first call to
 
2150
            # _add_subprocess_log rather than in TestCase.setUp so that this
 
2151
            # addCleanup is registered after any cleanups for tempdirs that
 
2152
            # subclasses might create, which will probably remove the log file
 
2153
            # we want to read.
 
2154
            self.addCleanup(self._subprocess_log_cleanup)
 
2155
        # self._log_files is a set, so if a log file is reused we won't grab it
 
2156
        # twice.
 
2157
        self._log_files.add(log_file_path)
 
2158
 
 
2159
    def _subprocess_log_cleanup(self):
 
2160
        for count, log_file_path in enumerate(self._log_files):
 
2161
            # We use buffer_now=True to avoid holding the file open beyond
 
2162
            # the life of this function, which might interfere with e.g.
 
2163
            # cleaning tempdirs on Windows.
 
2164
            # XXX: Testtools 0.9.5 doesn't have the content_from_file helper
 
2165
            #detail_content = content.content_from_file(
 
2166
            #    log_file_path, buffer_now=True)
 
2167
            with open(log_file_path, 'rb') as log_file:
 
2168
                log_file_bytes = log_file.read()
 
2169
            detail_content = content.Content(content.ContentType("text",
 
2170
                "plain", {"charset": "utf8"}), lambda: [log_file_bytes])
 
2171
            self.addDetail("start_bzr_subprocess-log-%d" % (count,),
 
2172
                detail_content)
 
2173
 
2067
2174
    def _popen(self, *args, **kwargs):
2068
2175
        """Place a call to Popen.
2069
2176
 
2112
2219
                      % (process_args, retcode, process.returncode))
2113
2220
        return [out, err]
2114
2221
 
2115
 
    def check_inventory_shape(self, inv, shape):
2116
 
        """Compare an inventory to a list of expected names.
 
2222
    def check_tree_shape(self, tree, shape):
 
2223
        """Compare a tree to a list of expected names.
2117
2224
 
2118
2225
        Fail if they are not precisely equal.
2119
2226
        """
2120
2227
        extras = []
2121
2228
        shape = list(shape)             # copy
2122
 
        for path, ie in inv.entries():
 
2229
        for path, ie in tree.iter_entries_by_dir():
2123
2230
            name = path.replace('\\', '/')
2124
2231
            if ie.kind == 'directory':
2125
2232
                name = name + '/'
2126
 
            if name in shape:
 
2233
            if name == "/":
 
2234
                pass # ignore root entry
 
2235
            elif name in shape:
2127
2236
                shape.remove(name)
2128
2237
            else:
2129
2238
                extras.append(name)
2219
2328
class TestCaseWithMemoryTransport(TestCase):
2220
2329
    """Common test class for tests that do not need disk resources.
2221
2330
 
2222
 
    Tests that need disk resources should derive from TestCaseWithTransport.
 
2331
    Tests that need disk resources should derive from TestCaseInTempDir
 
2332
    orTestCaseWithTransport.
2223
2333
 
2224
2334
    TestCaseWithMemoryTransport sets the TEST_ROOT variable for all bzr tests.
2225
2335
 
2226
 
    For TestCaseWithMemoryTransport the test_home_dir is set to the name of
 
2336
    For TestCaseWithMemoryTransport the ``test_home_dir`` is set to the name of
2227
2337
    a directory which does not exist. This serves to help ensure test isolation
2228
 
    is preserved. test_dir is set to the TEST_ROOT, as is cwd, because they
2229
 
    must exist. However, TestCaseWithMemoryTransport does not offer local
2230
 
    file defaults for the transport in tests, nor does it obey the command line
 
2338
    is preserved. ``test_dir`` is set to the TEST_ROOT, as is cwd, because they
 
2339
    must exist. However, TestCaseWithMemoryTransport does not offer local file
 
2340
    defaults for the transport in tests, nor does it obey the command line
2231
2341
    override, so tests that accidentally write to the common directory should
2232
2342
    be rare.
2233
2343
 
2234
 
    :cvar TEST_ROOT: Directory containing all temporary directories, plus
2235
 
    a .bzr directory that stops us ascending higher into the filesystem.
 
2344
    :cvar TEST_ROOT: Directory containing all temporary directories, plus a
 
2345
        ``.bzr`` directory that stops us ascending higher into the filesystem.
2236
2346
    """
2237
2347
 
2238
2348
    TEST_ROOT = None
2562
2672
 
2563
2673
    OVERRIDE_PYTHON = 'python'
2564
2674
 
 
2675
    def setUp(self):
 
2676
        super(TestCaseInTempDir, self).setUp()
 
2677
        # Remove the protection set in isolated_environ, we have a proper
 
2678
        # access to disk resources now.
 
2679
        self.overrideEnv('BZR_LOG', None)
 
2680
 
2565
2681
    def check_file_contents(self, filename, expect):
2566
2682
        self.log("check contents of file %s" % filename)
2567
2683
        f = file(filename)
3458
3574
#                           with proper exclusion rules.
3459
3575
#   -Ethreads               Will display thread ident at creation/join time to
3460
3576
#                           help track thread leaks
 
3577
 
 
3578
#   -Econfig_stats          Will collect statistics using addDetail
3461
3579
selftest_debug_flags = set()
3462
3580
 
3463
3581
 
3715
3833
        'bzrlib.tests.per_repository',
3716
3834
        'bzrlib.tests.per_repository_chk',
3717
3835
        'bzrlib.tests.per_repository_reference',
 
3836
        'bzrlib.tests.per_repository_vf',
3718
3837
        'bzrlib.tests.per_uifactory',
3719
3838
        'bzrlib.tests.per_versionedfile',
3720
3839
        'bzrlib.tests.per_workingtree',
3754
3873
        'bzrlib.tests.test_commit_merge',
3755
3874
        'bzrlib.tests.test_config',
3756
3875
        'bzrlib.tests.test_conflicts',
 
3876
        'bzrlib.tests.test_controldir',
3757
3877
        'bzrlib.tests.test_counted_lock',
3758
3878
        'bzrlib.tests.test_crash',
3759
3879
        'bzrlib.tests.test_decorators',
3760
3880
        'bzrlib.tests.test_delta',
3761
3881
        'bzrlib.tests.test_debug',
3762
 
        'bzrlib.tests.test_deprecated_graph',
3763
3882
        'bzrlib.tests.test_diff',
3764
3883
        'bzrlib.tests.test_directory_service',
3765
3884
        'bzrlib.tests.test_dirstate',
3767
3886
        'bzrlib.tests.test_eol_filters',
3768
3887
        'bzrlib.tests.test_errors',
3769
3888
        'bzrlib.tests.test_export',
 
3889
        'bzrlib.tests.test_export_pot',
3770
3890
        'bzrlib.tests.test_extract',
3771
3891
        'bzrlib.tests.test_fetch',
3772
3892
        'bzrlib.tests.test_fixtures',
3786
3906
        'bzrlib.tests.test_http',
3787
3907
        'bzrlib.tests.test_http_response',
3788
3908
        'bzrlib.tests.test_https_ca_bundle',
 
3909
        'bzrlib.tests.test_i18n',
3789
3910
        'bzrlib.tests.test_identitymap',
3790
3911
        'bzrlib.tests.test_ignores',
3791
3912
        'bzrlib.tests.test_index',
3810
3931
        'bzrlib.tests.test_merge3',
3811
3932
        'bzrlib.tests.test_merge_core',
3812
3933
        'bzrlib.tests.test_merge_directive',
 
3934
        'bzrlib.tests.test_mergetools',
3813
3935
        'bzrlib.tests.test_missing',
3814
3936
        'bzrlib.tests.test_msgeditor',
3815
3937
        'bzrlib.tests.test_multiparent',
3865
3987
        'bzrlib.tests.test_testament',
3866
3988
        'bzrlib.tests.test_textfile',
3867
3989
        'bzrlib.tests.test_textmerge',
 
3990
        'bzrlib.tests.test_cethread',
3868
3991
        'bzrlib.tests.test_timestamp',
3869
3992
        'bzrlib.tests.test_trace',
3870
3993
        'bzrlib.tests.test_transactions',
3881
4004
        'bzrlib.tests.test_upgrade',
3882
4005
        'bzrlib.tests.test_upgrade_stacked',
3883
4006
        'bzrlib.tests.test_urlutils',
 
4007
        'bzrlib.tests.test_utextwrap',
3884
4008
        'bzrlib.tests.test_version',
3885
4009
        'bzrlib.tests.test_version_info',
3886
4010
        'bzrlib.tests.test_versionedfile',
3903
4027
        'bzrlib',
3904
4028
        'bzrlib.branchbuilder',
3905
4029
        'bzrlib.decorators',
3906
 
        'bzrlib.export',
3907
4030
        'bzrlib.inventory',
3908
4031
        'bzrlib.iterablefile',
3909
4032
        'bzrlib.lockdir',