~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/__init__.py

  • Committer: Andrew Bennetts
  • Date: 2010-09-17 04:32:50 UTC
  • mto: This revision was merged to the branch mainline in revision 5433.
  • Revision ID: andrew.bennetts@canonical.com-20100917043250-4f57ifkg0yu321t7
Reuse self._log_file rather than make new StringIO, and wrap pre-existing long line.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2011 Canonical Ltd
 
1
# Copyright (C) 2005-2010 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
55
55
import testtools
56
56
# nb: check this before importing anything else from within it
57
57
_testtools_version = getattr(testtools, '__version__', ())
58
 
if _testtools_version < (0, 9, 5):
59
 
    raise ImportError("need at least testtools 0.9.5: %s is %r"
 
58
if _testtools_version < (0, 9, 2):
 
59
    raise ImportError("need at least testtools 0.9.2: %s is %r"
60
60
        % (testtools.__file__, _testtools_version))
61
61
from testtools import content
62
62
 
63
 
import bzrlib
64
63
from bzrlib import (
65
64
    branchbuilder,
66
65
    bzrdir,
67
66
    chk_map,
68
 
    commands as _mod_commands,
69
67
    config,
70
68
    debug,
71
69
    errors,
72
70
    hooks,
73
71
    lock as _mod_lock,
74
 
    lockdir,
75
72
    memorytree,
76
73
    osutils,
77
 
    plugin as _mod_plugin,
78
 
    pyutils,
79
74
    ui,
80
75
    urlutils,
81
76
    registry,
82
 
    symbol_versioning,
83
 
    trace,
84
77
    transport as _mod_transport,
85
78
    workingtree,
86
79
    )
 
80
import bzrlib.branch
 
81
import bzrlib.commands
 
82
import bzrlib.timestamp
 
83
import bzrlib.export
 
84
import bzrlib.inventory
 
85
import bzrlib.iterablefile
 
86
import bzrlib.lockdir
87
87
try:
88
88
    import bzrlib.lsprof
89
89
except ImportError:
90
90
    # lsprof not available
91
91
    pass
92
 
from bzrlib.smart import client, request
 
92
from bzrlib.merge import merge_inner
 
93
import bzrlib.merge3
 
94
import bzrlib.plugin
 
95
from bzrlib.smart import client, request, server
 
96
import bzrlib.store
 
97
from bzrlib import symbol_versioning
 
98
from bzrlib.symbol_versioning import (
 
99
    DEPRECATED_PARAMETER,
 
100
    deprecated_function,
 
101
    deprecated_in,
 
102
    deprecated_method,
 
103
    deprecated_passed,
 
104
    )
 
105
import bzrlib.trace
93
106
from bzrlib.transport import (
94
107
    memory,
95
108
    pathfilter,
96
109
    )
 
110
from bzrlib.trace import mutter, note
97
111
from bzrlib.tests import (
98
112
    test_server,
99
113
    TestUtil,
101
115
    )
102
116
from bzrlib.ui import NullProgressView
103
117
from bzrlib.ui.text import TextUIFactory
 
118
import bzrlib.version_info_formats.format_custom
 
119
from bzrlib.workingtree import WorkingTree, WorkingTreeFormat2
104
120
 
105
121
# Mark this python module as being part of the implementation
106
122
# of unittest: this gives us better tracebacks where the last
123
139
TestSuite = TestUtil.TestSuite
124
140
TestLoader = TestUtil.TestLoader
125
141
 
126
 
# Tests should run in a clean and clearly defined environment. The goal is to
127
 
# keep them isolated from the running environment as mush as possible. The test
128
 
# framework ensures the variables defined below are set (or deleted if the
129
 
# value is None) before a test is run and reset to their original value after
130
 
# the test is run. Generally if some code depends on an environment variable,
131
 
# the tests should start without this variable in the environment. There are a
132
 
# few exceptions but you shouldn't violate this rule lightly.
133
 
isolated_environ = {
134
 
    'BZR_HOME': None,
135
 
    'HOME': None,
136
 
    # bzr now uses the Win32 API and doesn't rely on APPDATA, but the
137
 
    # tests do check our impls match APPDATA
138
 
    'BZR_EDITOR': None, # test_msgeditor manipulates this variable
139
 
    'VISUAL': None,
140
 
    'EDITOR': None,
141
 
    'BZR_EMAIL': None,
142
 
    'BZREMAIL': None, # may still be present in the environment
143
 
    'EMAIL': 'jrandom@example.com', # set EMAIL as bzr does not guess
144
 
    'BZR_PROGRESS_BAR': 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',
149
 
    'BZR_PLUGIN_PATH': None,
150
 
    'BZR_DISABLE_PLUGINS': None,
151
 
    'BZR_PLUGINS_AT': None,
152
 
    'BZR_CONCURRENCY': None,
153
 
    # Make sure that any text ui tests are consistent regardless of
154
 
    # the environment the test case is run in; you may want tests that
155
 
    # test other combinations.  'dumb' is a reasonable guess for tests
156
 
    # going to a pipe or a StringIO.
157
 
    'TERM': 'dumb',
158
 
    'LINES': '25',
159
 
    'COLUMNS': '80',
160
 
    'BZR_COLUMNS': '80',
161
 
    # Disable SSH Agent
162
 
    'SSH_AUTH_SOCK': None,
163
 
    # Proxies
164
 
    'http_proxy': None,
165
 
    'HTTP_PROXY': None,
166
 
    'https_proxy': None,
167
 
    'HTTPS_PROXY': None,
168
 
    'no_proxy': None,
169
 
    'NO_PROXY': None,
170
 
    'all_proxy': None,
171
 
    'ALL_PROXY': None,
172
 
    # Nobody cares about ftp_proxy, FTP_PROXY AFAIK. So far at
173
 
    # least. If you do (care), please update this comment
174
 
    # -- vila 20080401
175
 
    'ftp_proxy': None,
176
 
    'FTP_PROXY': None,
177
 
    'BZR_REMOTE_PATH': None,
178
 
    # Generally speaking, we don't want apport reporting on crashes in
179
 
    # the test envirnoment unless we're specifically testing apport,
180
 
    # so that it doesn't leak into the real system environment.  We
181
 
    # use an env var so it propagates to subprocesses.
182
 
    'APPORT_DISABLE': '1',
183
 
    }
184
 
 
185
 
 
186
 
def override_os_environ(test, env=None):
187
 
    """Modify os.environ keeping a copy.
188
 
    
189
 
    :param test: A test instance
190
 
 
191
 
    :param env: A dict containing variable definitions to be installed
192
 
    """
193
 
    if env is None:
194
 
        env = isolated_environ
195
 
    test._original_os_environ = dict([(var, value)
196
 
                                      for var, value in os.environ.iteritems()])
197
 
    for var, value in env.iteritems():
198
 
        osutils.set_or_unset_env(var, value)
199
 
        if var not in test._original_os_environ:
200
 
            # The var is new, add it with a value of None, so
201
 
            # restore_os_environ will delete it
202
 
            test._original_os_environ[var] = None
203
 
 
204
 
 
205
 
def restore_os_environ(test):
206
 
    """Restore os.environ to its original state.
207
 
 
208
 
    :param test: A test instance previously passed to override_os_environ.
209
 
    """
210
 
    for var, value in test._original_os_environ.iteritems():
211
 
        # Restore the original value (or delete it if the value has been set to
212
 
        # None in override_os_environ).
213
 
        osutils.set_or_unset_env(var, value)
214
 
 
215
 
 
216
142
class ExtendedTestResult(testtools.TextTestResult):
217
143
    """Accepts, reports and accumulates the results of running tests.
218
144
 
269
195
        self._strict = strict
270
196
        self._first_thread_leaker_id = None
271
197
        self._tests_leaking_threads_count = 0
272
 
        self._traceback_from_test = None
273
198
 
274
199
    def stopTestRun(self):
275
200
        run = self.testsRun
335
260
 
336
261
    def _elapsedTestTimeString(self):
337
262
        """Return a time string for the overall time the current test has taken."""
338
 
        return self._formatTime(self._delta_to_float(
339
 
            self._now() - self._start_datetime))
 
263
        return self._formatTime(time.time() - self._start_time)
340
264
 
341
265
    def _testTimeString(self, testCase):
342
266
        benchmark_time = self._extractBenchmarkTime(testCase)
356
280
        what = re.sub(r'^bzrlib\.tests\.', '', what)
357
281
        return what
358
282
 
359
 
    # GZ 2010-10-04: Cloned tests may end up harmlessly calling this method
360
 
    #                multiple times in a row, because the handler is added for
361
 
    #                each test but the container list is shared between cases.
362
 
    #                See lp:498869 lp:625574 and lp:637725 for background.
363
 
    def _record_traceback_from_test(self, exc_info):
364
 
        """Store the traceback from passed exc_info tuple till"""
365
 
        self._traceback_from_test = exc_info[2]
366
 
 
367
283
    def startTest(self, test):
368
284
        super(ExtendedTestResult, self).startTest(test)
369
285
        if self.count == 0:
372
288
        self.report_test_start(test)
373
289
        test.number = self.count
374
290
        self._recordTestStartTime()
375
 
        # Make testtools cases give us the real traceback on failure
376
 
        addOnException = getattr(test, "addOnException", None)
377
 
        if addOnException is not None:
378
 
            addOnException(self._record_traceback_from_test)
379
 
        # Only check for thread leaks on bzrlib derived test cases
380
 
        if isinstance(test, TestCase):
381
 
            test.addCleanup(self._check_leaked_threads, test)
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
 
291
        # Only check for thread leaks if the test case supports cleanups
 
292
        addCleanup = getattr(test, "addCleanup", None)
 
293
        if addCleanup is not None:
 
294
            addCleanup(self._check_leaked_threads, test)
393
295
 
394
296
    def startTests(self):
395
297
        self.report_tests_starting()
413
315
 
414
316
    def _recordTestStartTime(self):
415
317
        """Record that a test has started."""
416
 
        self._start_datetime = self._now()
 
318
        self._start_time = time.time()
417
319
 
418
320
    def addError(self, test, err):
419
321
        """Tell result that test finished with an error.
421
323
        Called from the TestCase run() method when the test
422
324
        fails with an unexpected error.
423
325
        """
424
 
        self._post_mortem(self._traceback_from_test)
 
326
        self._post_mortem()
425
327
        super(ExtendedTestResult, self).addError(test, err)
426
328
        self.error_count += 1
427
329
        self.report_error(test, err)
434
336
        Called from the TestCase run() method when the test
435
337
        fails because e.g. an assert() method failed.
436
338
        """
437
 
        self._post_mortem(self._traceback_from_test)
 
339
        self._post_mortem()
438
340
        super(ExtendedTestResult, self).addFailure(test, err)
439
341
        self.failure_count += 1
440
342
        self.report_failure(test, err)
460
362
        self.known_failure_count += 1
461
363
        self.report_known_failure(test, err)
462
364
 
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
 
 
476
365
    def addNotSupported(self, test, feature):
477
366
        """The test will not be run because of a missing feature.
478
367
        """
495
384
        self.not_applicable_count += 1
496
385
        self.report_not_applicable(test, reason)
497
386
 
498
 
    def _post_mortem(self, tb=None):
 
387
    def _post_mortem(self):
499
388
        """Start a PDB post mortem session."""
500
389
        if os.environ.get('BZR_TEST_PDB', None):
501
 
            import pdb
502
 
            pdb.post_mortem(tb)
 
390
            import pdb;pdb.post_mortem()
503
391
 
504
392
    def progress(self, offset, whence):
505
393
        """The test is adjusting the count of tests to run."""
583
471
        self.pb.finished()
584
472
        super(TextTestResult, self).stopTestRun()
585
473
 
586
 
    def report_tests_starting(self):
587
 
        super(TextTestResult, self).report_tests_starting()
 
474
    def startTestRun(self):
 
475
        super(TextTestResult, self).startTestRun()
588
476
        self.pb.update('[test 0/%d] Starting' % (self.num_tests))
589
477
 
590
478
    def _progress_prefix_text(self):
637
525
    def report_known_failure(self, test, err):
638
526
        pass
639
527
 
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
 
 
647
528
    def report_skip(self, test, reason):
648
529
        pass
649
530
 
665
546
            result = a_string
666
547
        return result.ljust(final_width)
667
548
 
668
 
    def report_tests_starting(self):
 
549
    def startTestRun(self):
 
550
        super(VerboseTestResult, self).startTestRun()
669
551
        self.stream.write('running %d tests...\n' % self.num_tests)
670
 
        super(VerboseTestResult, self).report_tests_starting()
671
552
 
672
553
    def report_test_start(self, test):
673
554
        name = self._shortened_test_description(test)
701
582
                % (self._testTimeString(test),
702
583
                   self._error_summary(err)))
703
584
 
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
 
 
710
585
    def report_success(self, test):
711
586
        self.stream.write('   OK %s\n' % self._testTimeString(test))
712
587
        for bench_called, stats in getattr(test, '_benchcalls', []):
759
634
            encode = codec[0]
760
635
        else:
761
636
            encode = codec.encode
762
 
        # GZ 2010-09-08: Really we don't want to be writing arbitrary bytes,
763
 
        #                so should swap to the plain codecs.StreamWriter
764
 
        stream = osutils.UnicodeOrBytesToBytesWriter(encode, stream,
765
 
            "backslashreplace")
 
637
        stream = osutils.UnicodeOrBytesToBytesWriter(encode, stream)
766
638
        stream.encoding = new_encoding
767
639
        self.stream = stream
768
640
        self.descriptions = descriptions
918
790
        return NullProgressView()
919
791
 
920
792
 
921
 
def isolated_doctest_setUp(test):
922
 
    override_os_environ(test)
923
 
 
924
 
 
925
 
def isolated_doctest_tearDown(test):
926
 
    restore_os_environ(test)
927
 
 
928
 
 
929
 
def IsolatedDocTestSuite(*args, **kwargs):
930
 
    """Overrides doctest.DocTestSuite to handle isolation.
931
 
 
932
 
    The method is really a factory and users are expected to use it as such.
933
 
    """
934
 
 
935
 
    kwargs['setUp'] = isolated_doctest_setUp
936
 
    kwargs['tearDown'] = isolated_doctest_tearDown
937
 
    return doctest.DocTestSuite(*args, **kwargs)
938
 
 
939
 
 
940
793
class TestCase(testtools.TestCase):
941
794
    """Base class for bzr unit tests.
942
795
 
974
827
        super(TestCase, self).setUp()
975
828
        for feature in getattr(self, '_test_needs_features', []):
976
829
            self.requireFeature(feature)
 
830
        self._log_contents = None
 
831
        self.addDetail("log", content.Content(content.ContentType("text",
 
832
            "plain", {"charset": "utf8"}),
 
833
            lambda:[self._get_log(keep_log_file=True)]))
977
834
        self._cleanEnvironment()
978
835
        self._silenceUI()
979
836
        self._startLogFile()
983
840
        self._track_transports()
984
841
        self._track_locks()
985
842
        self._clear_debug_flags()
986
 
        # Isolate global verbosity level, to make sure it's reproducible
987
 
        # between tests.  We should get rid of this altogether: bug 656694. --
988
 
        # mbp 20101008
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()
1001
843
 
1002
844
    def debug(self):
1003
845
        # debug a frame up.
1004
846
        import pdb
1005
847
        pdb.Pdb().set_trace(sys._getframe().f_back)
1006
848
 
1007
 
    def discardDetail(self, name):
1008
 
        """Extend the addDetail, getDetails api so we can remove a detail.
1009
 
 
1010
 
        eg. bzr always adds the 'log' detail at startup, but we don't want to
1011
 
        include it for skipped, xfail, etc tests.
1012
 
 
1013
 
        It is safe to call this for a detail that doesn't exist, in case this
1014
 
        gets called multiple times.
1015
 
        """
1016
 
        # We cheat. details is stored in __details which means we shouldn't
1017
 
        # touch it. but getDetails() returns the dict directly, so we can
1018
 
        # mutate it.
1019
 
        details = self.getDetails()
1020
 
        if name in details:
1021
 
            del details[name]
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
 
 
1067
849
    def _clear_debug_flags(self):
1068
850
        """Prevent externally set debug flags affecting tests.
1069
851
 
1079
861
 
1080
862
    def _clear_hooks(self):
1081
863
        # prevent hooks affecting tests
1082
 
        known_hooks = hooks.known_hooks
1083
864
        self._preserved_hooks = {}
1084
 
        for key, (parent, name) in known_hooks.iter_parent_objects():
1085
 
            current_hooks = getattr(parent, name)
 
865
        for key, factory in hooks.known_hooks.items():
 
866
            parent, name = hooks.known_hooks_key_to_parent_and_attribute(key)
 
867
            current_hooks = hooks.known_hooks_key_to_object(key)
1086
868
            self._preserved_hooks[parent] = (name, current_hooks)
1087
 
        self._preserved_lazy_hooks = hooks._lazy_hooks
1088
 
        hooks._lazy_hooks = {}
1089
869
        self.addCleanup(self._restoreHooks)
1090
 
        for key, (parent, name) in known_hooks.iter_parent_objects():
1091
 
            factory = known_hooks.get(key)
 
870
        for key, factory in hooks.known_hooks.items():
 
871
            parent, name = hooks.known_hooks_key_to_parent_and_attribute(key)
1092
872
            setattr(parent, name, factory())
1093
873
        # this hook should always be installed
1094
874
        request._install_hook()
1123
903
        # break some locks on purpose and should be taken into account by
1124
904
        # considering that breaking a lock is just a dirty way of releasing it.
1125
905
        if len(acquired_locks) != (len(released_locks) + len(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))
 
906
            message = ('Different number of acquired and '
 
907
                       'released or broken locks. (%s, %s + %s)' %
 
908
                       (acquired_locks, released_locks, broken_locks))
1133
909
            if not self._lock_check_thorough:
1134
910
                # Rather than fail, just warn
1135
911
                print "Broken test %s: %s" % (self, message)
1192
968
            try:
1193
969
                workingtree.WorkingTree.open(path)
1194
970
            except (errors.NotBranchError, errors.NoWorkingTree):
1195
 
                raise TestSkipped('Needs a working tree of bzr sources')
 
971
                return
1196
972
        finally:
1197
973
            self.enable_directory_isolation()
1198
974
 
1310
1086
        except UnicodeError, e:
1311
1087
            # If we can't compare without getting a UnicodeError, then
1312
1088
            # obviously they are different
1313
 
            trace.mutter('UnicodeError: %s', e)
 
1089
            mutter('UnicodeError: %s', e)
1314
1090
        if message:
1315
1091
            message += '\n'
1316
1092
        raise AssertionError("%snot equal:\na = %s\nb = %s\n"
1355
1131
                         'st_mtime did not match')
1356
1132
        self.assertEqual(expected.st_ctime, actual.st_ctime,
1357
1133
                         'st_ctime did not match')
1358
 
        if sys.platform == 'win32':
 
1134
        if sys.platform != 'win32':
1359
1135
            # On Win32 both 'dev' and 'ino' cannot be trusted. In python2.4 it
1360
1136
            # is 'dev' that varies, in python 2.5 (6?) it is st_ino that is
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:
 
1137
            # odd. Regardless we shouldn't actually try to assert anything
 
1138
            # about their values
1367
1139
            self.assertEqual(expected.st_dev, actual.st_dev,
1368
1140
                             'st_dev did not match')
1369
1141
            self.assertEqual(expected.st_ino, actual.st_ino,
1378
1150
                length, len(obj_with_len), obj_with_len))
1379
1151
 
1380
1152
    def assertLogsError(self, exception_class, func, *args, **kwargs):
1381
 
        """Assert that `func(*args, **kwargs)` quietly logs a specific error.
 
1153
        """Assert that func(*args, **kwargs) quietly logs a specific exception.
1382
1154
        """
 
1155
        from bzrlib import trace
1383
1156
        captured = []
1384
1157
        orig_log_exception_quietly = trace.log_exception_quietly
1385
1158
        try:
1386
1159
            def capture():
1387
1160
                orig_log_exception_quietly()
1388
 
                captured.append(sys.exc_info()[1])
 
1161
                captured.append(sys.exc_info())
1389
1162
            trace.log_exception_quietly = capture
1390
1163
            func(*args, **kwargs)
1391
1164
        finally:
1392
1165
            trace.log_exception_quietly = orig_log_exception_quietly
1393
1166
        self.assertLength(1, captured)
1394
 
        err = captured[0]
 
1167
        err = captured[0][1]
1395
1168
        self.assertIsInstance(err, exception_class)
1396
1169
        return err
1397
1170
 
1434
1207
        if haystack.find(needle) == -1:
1435
1208
            self.fail("string %r not found in '''%s'''" % (needle, haystack))
1436
1209
 
1437
 
    def assertNotContainsString(self, haystack, needle):
1438
 
        if haystack.find(needle) != -1:
1439
 
            self.fail("string %r found in '''%s'''" % (needle, haystack))
1440
 
 
1441
1210
    def assertSubset(self, sublist, superlist):
1442
1211
        """Assert that every entry in sublist is present in superlist."""
1443
1212
        missing = set(sublist) - set(superlist)
1532
1301
 
1533
1302
    def assertFileEqual(self, content, path):
1534
1303
        """Fail if path does not contain 'content'."""
1535
 
        self.assertPathExists(path)
 
1304
        self.failUnlessExists(path)
1536
1305
        f = file(path, 'rb')
1537
1306
        try:
1538
1307
            s = f.read()
1548
1317
        else:
1549
1318
            self.assertEqual(expected_docstring, obj.__doc__)
1550
1319
 
1551
 
    @symbol_versioning.deprecated_method(symbol_versioning.deprecated_in((2, 4)))
1552
1320
    def failUnlessExists(self, path):
1553
 
        return self.assertPathExists(path)
1554
 
 
1555
 
    def assertPathExists(self, path):
1556
1321
        """Fail unless path or paths, which may be abs or relative, exist."""
1557
1322
        if not isinstance(path, basestring):
1558
1323
            for p in path:
1559
 
                self.assertPathExists(p)
 
1324
                self.failUnlessExists(p)
1560
1325
        else:
1561
 
            self.assertTrue(osutils.lexists(path),
1562
 
                path + " does not exist")
 
1326
            self.failUnless(osutils.lexists(path),path+" does not exist")
1563
1327
 
1564
 
    @symbol_versioning.deprecated_method(symbol_versioning.deprecated_in((2, 4)))
1565
1328
    def failIfExists(self, path):
1566
 
        return self.assertPathDoesNotExist(path)
1567
 
 
1568
 
    def assertPathDoesNotExist(self, path):
1569
1329
        """Fail if path or paths, which may be abs or relative, exist."""
1570
1330
        if not isinstance(path, basestring):
1571
1331
            for p in path:
1572
 
                self.assertPathDoesNotExist(p)
 
1332
                self.failIfExists(p)
1573
1333
        else:
1574
 
            self.assertFalse(osutils.lexists(path),
1575
 
                path + " exists")
 
1334
            self.failIf(osutils.lexists(path),path+" exists")
1576
1335
 
1577
1336
    def _capture_deprecation_warnings(self, a_callable, *args, **kwargs):
1578
1337
        """A helper for callDeprecated and applyDeprecated.
1604
1363
        not other callers that go direct to the warning module.
1605
1364
 
1606
1365
        To test that a deprecated method raises an error, do something like
1607
 
        this (remember that both assertRaises and applyDeprecated delays *args
1608
 
        and **kwargs passing)::
 
1366
        this::
1609
1367
 
1610
1368
            self.assertRaises(errors.ReservedId,
1611
1369
                self.applyDeprecated,
1693
1451
 
1694
1452
        The file is removed as the test is torn down.
1695
1453
        """
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
1704
 
        self._log_memento = trace.push_log_file(self._log_file)
 
1454
        self._log_file = StringIO()
 
1455
        self._log_memento = bzrlib.trace.push_log_file(self._log_file)
1705
1456
        self.addCleanup(self._finishLogFile)
1706
1457
 
1707
1458
    def _finishLogFile(self):
1708
1459
        """Finished with the log file.
1709
1460
 
1710
 
        Close the file and delete it.
 
1461
        Close the file and delete it, unless setKeepLogfile was called.
1711
1462
        """
1712
 
        if trace._trace_file:
 
1463
        if bzrlib.trace._trace_file:
1713
1464
            # flush the log file, to get all content
1714
 
            trace._trace_file.flush()
1715
 
        trace.pop_log_file(self._log_memento)
 
1465
            bzrlib.trace._trace_file.flush()
 
1466
        bzrlib.trace.pop_log_file(self._log_memento)
 
1467
        # Cache the log result and delete the file on disk
 
1468
        self._get_log(False)
1716
1469
 
1717
1470
    def thisFailsStrictLockCheck(self):
1718
1471
        """It is known that this test would fail with -Dstrict_locks.
1746
1499
            setattr(obj, attr_name, new)
1747
1500
        return value
1748
1501
 
1749
 
    def overrideEnv(self, name, new):
1750
 
        """Set an environment variable, and reset it after the test.
1751
 
 
1752
 
        :param name: The environment variable name.
1753
 
 
1754
 
        :param new: The value to set the variable to. If None, the 
1755
 
            variable is deleted from the environment.
1756
 
 
1757
 
        :returns: The actual variable value.
1758
 
        """
1759
 
        value = osutils.set_or_unset_env(name, new)
1760
 
        self.addCleanup(osutils.set_or_unset_env, name, value)
1761
 
        return value
1762
 
 
1763
1502
    def _cleanEnvironment(self):
1764
 
        for name, value in isolated_environ.iteritems():
1765
 
            self.overrideEnv(name, value)
 
1503
        new_env = {
 
1504
            'BZR_HOME': None, # Don't inherit BZR_HOME to all the tests.
 
1505
            'HOME': os.getcwd(),
 
1506
            # bzr now uses the Win32 API and doesn't rely on APPDATA, but the
 
1507
            # tests do check our impls match APPDATA
 
1508
            'BZR_EDITOR': None, # test_msgeditor manipulates this variable
 
1509
            'VISUAL': None,
 
1510
            'EDITOR': None,
 
1511
            'BZR_EMAIL': None,
 
1512
            'BZREMAIL': None, # may still be present in the environment
 
1513
            'EMAIL': 'jrandom@example.com', # set EMAIL as bzr does not guess
 
1514
            'BZR_PROGRESS_BAR': None,
 
1515
            'BZR_LOG': None,
 
1516
            'BZR_PLUGIN_PATH': None,
 
1517
            'BZR_DISABLE_PLUGINS': None,
 
1518
            'BZR_PLUGINS_AT': None,
 
1519
            'BZR_CONCURRENCY': None,
 
1520
            # Make sure that any text ui tests are consistent regardless of
 
1521
            # the environment the test case is run in; you may want tests that
 
1522
            # test other combinations.  'dumb' is a reasonable guess for tests
 
1523
            # going to a pipe or a StringIO.
 
1524
            'TERM': 'dumb',
 
1525
            'LINES': '25',
 
1526
            'COLUMNS': '80',
 
1527
            'BZR_COLUMNS': '80',
 
1528
            # SSH Agent
 
1529
            'SSH_AUTH_SOCK': None,
 
1530
            # Proxies
 
1531
            'http_proxy': None,
 
1532
            'HTTP_PROXY': None,
 
1533
            'https_proxy': None,
 
1534
            'HTTPS_PROXY': None,
 
1535
            'no_proxy': None,
 
1536
            'NO_PROXY': None,
 
1537
            'all_proxy': None,
 
1538
            'ALL_PROXY': None,
 
1539
            # Nobody cares about ftp_proxy, FTP_PROXY AFAIK. So far at
 
1540
            # least. If you do (care), please update this comment
 
1541
            # -- vila 20080401
 
1542
            'ftp_proxy': None,
 
1543
            'FTP_PROXY': None,
 
1544
            'BZR_REMOTE_PATH': None,
 
1545
            # Generally speaking, we don't want apport reporting on crashes in
 
1546
            # the test envirnoment unless we're specifically testing apport,
 
1547
            # so that it doesn't leak into the real system environment.  We
 
1548
            # use an env var so it propagates to subprocesses.
 
1549
            'APPORT_DISABLE': '1',
 
1550
        }
 
1551
        self._old_env = {}
 
1552
        self.addCleanup(self._restoreEnvironment)
 
1553
        for name, value in new_env.iteritems():
 
1554
            self._captureVar(name, value)
 
1555
 
 
1556
    def _captureVar(self, name, newvalue):
 
1557
        """Set an environment variable, and reset it when finished."""
 
1558
        self._old_env[name] = osutils.set_or_unset_env(name, newvalue)
 
1559
 
 
1560
    def _restoreEnvironment(self):
 
1561
        for name, value in self._old_env.iteritems():
 
1562
            osutils.set_or_unset_env(name, value)
1766
1563
 
1767
1564
    def _restoreHooks(self):
1768
1565
        for klass, (name, hooks) in self._preserved_hooks.items():
1769
1566
            setattr(klass, name, hooks)
1770
 
        self._preserved_hooks.clear()
1771
 
        bzrlib.hooks._lazy_hooks = self._preserved_lazy_hooks
1772
 
        self._preserved_lazy_hooks.clear()
1773
1567
 
1774
1568
    def knownFailure(self, reason):
1775
1569
        """This test has failed for some known reason."""
1776
1570
        raise KnownFailure(reason)
1777
1571
 
1778
 
    def _suppress_log(self):
1779
 
        """Remove the log info from details."""
1780
 
        self.discardDetail('log')
1781
 
 
1782
1572
    def _do_skip(self, result, reason):
1783
 
        self._suppress_log()
1784
1573
        addSkip = getattr(result, 'addSkip', None)
1785
1574
        if not callable(addSkip):
1786
1575
            result.addSuccess(result)
1789
1578
 
1790
1579
    @staticmethod
1791
1580
    def _do_known_failure(self, result, e):
1792
 
        self._suppress_log()
1793
1581
        err = sys.exc_info()
1794
1582
        addExpectedFailure = getattr(result, 'addExpectedFailure', None)
1795
1583
        if addExpectedFailure is not None:
1803
1591
            reason = 'No reason given'
1804
1592
        else:
1805
1593
            reason = e.args[0]
1806
 
        self._suppress_log ()
1807
1594
        addNotApplicable = getattr(result, 'addNotApplicable', None)
1808
1595
        if addNotApplicable is not None:
1809
1596
            result.addNotApplicable(self, reason)
1811
1598
            self._do_skip(result, reason)
1812
1599
 
1813
1600
    @staticmethod
1814
 
    def _report_skip(self, result, err):
1815
 
        """Override the default _report_skip.
1816
 
 
1817
 
        We want to strip the 'log' detail. If we waint until _do_skip, it has
1818
 
        already been formatted into the 'reason' string, and we can't pull it
1819
 
        out again.
1820
 
        """
1821
 
        self._suppress_log()
1822
 
        super(TestCase, self)._report_skip(self, result, err)
1823
 
 
1824
 
    @staticmethod
1825
 
    def _report_expected_failure(self, result, err):
1826
 
        """Strip the log.
1827
 
 
1828
 
        See _report_skip for motivation.
1829
 
        """
1830
 
        self._suppress_log()
1831
 
        super(TestCase, self)._report_expected_failure(self, result, err)
1832
 
 
1833
 
    @staticmethod
1834
1601
    def _do_unsupported_or_skip(self, result, e):
1835
1602
        reason = e.args[0]
1836
 
        self._suppress_log()
1837
1603
        addNotSupported = getattr(result, 'addNotSupported', None)
1838
1604
        if addNotSupported is not None:
1839
1605
            result.addNotSupported(self, reason)
1865
1631
            self._benchtime += time.time() - start
1866
1632
 
1867
1633
    def log(self, *args):
1868
 
        trace.mutter(*args)
 
1634
        mutter(*args)
 
1635
 
 
1636
    def _get_log(self, keep_log_file=False):
 
1637
        """Internal helper to get the log from bzrlib.trace for this test.
 
1638
 
 
1639
        Please use self.getDetails, or self.get_log to access this in test case
 
1640
        code.
 
1641
 
 
1642
        :param keep_log_file: When True, if the log is still a file on disk
 
1643
            leave it as a file on disk. When False, if the log is still a file
 
1644
            on disk, the log file is deleted and the log preserved as
 
1645
            self._log_contents.
 
1646
        :return: A string containing the log.
 
1647
        """
 
1648
        if self._log_contents is not None:
 
1649
            try:
 
1650
                self._log_contents.decode('utf8')
 
1651
            except UnicodeDecodeError:
 
1652
                unicodestr = self._log_contents.decode('utf8', 'replace')
 
1653
                self._log_contents = unicodestr.encode('utf8')
 
1654
            return self._log_contents
 
1655
        if self._log_file is not None:
 
1656
            log_contents = self._log_file.getvalue()
 
1657
            try:
 
1658
                log_contents.decode('utf8')
 
1659
            except UnicodeDecodeError:
 
1660
                unicodestr = log_contents.decode('utf8', 'replace')
 
1661
                log_contents = unicodestr.encode('utf8')
 
1662
            if not keep_log_file:
 
1663
                self._log_file = None
 
1664
                # Permit multiple calls to get_log until we clean it up in
 
1665
                # finishLogFile
 
1666
                self._log_contents = log_contents
 
1667
            return log_contents
 
1668
        else:
 
1669
            return "No log file content."
1869
1670
 
1870
1671
    def get_log(self):
1871
1672
        """Get a unicode string containing the log from bzrlib.trace.
1921
1722
 
1922
1723
        try:
1923
1724
            try:
1924
 
                result = self.apply_redirected(
1925
 
                    ui.ui_factory.stdin,
 
1725
                result = self.apply_redirected(ui.ui_factory.stdin,
1926
1726
                    stdout, stderr,
1927
 
                    _mod_commands.run_bzr_catch_user_errors,
 
1727
                    bzrlib.commands.run_bzr_catch_user_errors,
1928
1728
                    args)
1929
1729
            except KeyboardInterrupt:
1930
1730
                # Reraise KeyboardInterrupt with contents of redirected stdout
2072
1872
    def start_bzr_subprocess(self, process_args, env_changes=None,
2073
1873
                             skip_if_plan_to_signal=False,
2074
1874
                             working_dir=None,
2075
 
                             allow_plugins=False, stderr=subprocess.PIPE):
 
1875
                             allow_plugins=False):
2076
1876
        """Start bzr in a subprocess for testing.
2077
1877
 
2078
1878
        This starts a new Python interpreter and runs bzr in there.
2090
1890
        :param skip_if_plan_to_signal: raise TestSkipped when true and system
2091
1891
            doesn't support signalling subprocesses.
2092
1892
        :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``.
2096
1893
 
2097
1894
        :returns: Popen object for the started process.
2098
1895
        """
2124
1921
            # so we will avoid using it on all platforms, just to
2125
1922
            # make sure the code path is used, and we don't break on win32
2126
1923
            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())
2130
1924
            command = [sys.executable]
2131
1925
            # frozen executables don't need the path to bzr
2132
1926
            if getattr(sys, "frozen", None) is None:
2136
1930
            command.extend(process_args)
2137
1931
            process = self._popen(command, stdin=subprocess.PIPE,
2138
1932
                                  stdout=subprocess.PIPE,
2139
 
                                  stderr=stderr)
 
1933
                                  stderr=subprocess.PIPE)
2140
1934
        finally:
2141
1935
            restore_environment()
2142
1936
            if cwd is not None:
2144
1938
 
2145
1939
        return process
2146
1940
 
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
 
 
2174
1941
    def _popen(self, *args, **kwargs):
2175
1942
        """Place a call to Popen.
2176
1943
 
2213
1980
        if retcode is not None and retcode != process.returncode:
2214
1981
            if process_args is None:
2215
1982
                process_args = "(unknown args)"
2216
 
            trace.mutter('Output of bzr %s:\n%s', process_args, out)
2217
 
            trace.mutter('Error for bzr %s:\n%s', process_args, err)
 
1983
            mutter('Output of bzr %s:\n%s', process_args, out)
 
1984
            mutter('Error for bzr %s:\n%s', process_args, err)
2218
1985
            self.fail('Command bzr %s failed with retcode %s != %s'
2219
1986
                      % (process_args, retcode, process.returncode))
2220
1987
        return [out, err]
2221
1988
 
2222
 
    def check_tree_shape(self, tree, shape):
2223
 
        """Compare a tree to a list of expected names.
 
1989
    def check_inventory_shape(self, inv, shape):
 
1990
        """Compare an inventory to a list of expected names.
2224
1991
 
2225
1992
        Fail if they are not precisely equal.
2226
1993
        """
2227
1994
        extras = []
2228
1995
        shape = list(shape)             # copy
2229
 
        for path, ie in tree.iter_entries_by_dir():
 
1996
        for path, ie in inv.entries():
2230
1997
            name = path.replace('\\', '/')
2231
1998
            if ie.kind == 'directory':
2232
1999
                name = name + '/'
2233
 
            if name == "/":
2234
 
                pass # ignore root entry
2235
 
            elif name in shape:
 
2000
            if name in shape:
2236
2001
                shape.remove(name)
2237
2002
            else:
2238
2003
                extras.append(name)
2279
2044
 
2280
2045
        Tests that expect to provoke LockContention errors should call this.
2281
2046
        """
2282
 
        self.overrideAttr(lockdir, '_DEFAULT_TIMEOUT_SECONDS', 0)
 
2047
        self.overrideAttr(bzrlib.lockdir, '_DEFAULT_TIMEOUT_SECONDS', 0)
2283
2048
 
2284
2049
    def make_utf8_encoded_stringio(self, encoding_type=None):
2285
2050
        """Return a StringIOWrapper instance, that will encode Unicode
2328
2093
class TestCaseWithMemoryTransport(TestCase):
2329
2094
    """Common test class for tests that do not need disk resources.
2330
2095
 
2331
 
    Tests that need disk resources should derive from TestCaseInTempDir
2332
 
    orTestCaseWithTransport.
 
2096
    Tests that need disk resources should derive from TestCaseWithTransport.
2333
2097
 
2334
2098
    TestCaseWithMemoryTransport sets the TEST_ROOT variable for all bzr tests.
2335
2099
 
2336
 
    For TestCaseWithMemoryTransport the ``test_home_dir`` is set to the name of
 
2100
    For TestCaseWithMemoryTransport the test_home_dir is set to the name of
2337
2101
    a directory which does not exist. This serves to help ensure test isolation
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
 
2102
    is preserved. test_dir is set to the TEST_ROOT, as is cwd, because they
 
2103
    must exist. However, TestCaseWithMemoryTransport does not offer local
 
2104
    file defaults for the transport in tests, nor does it obey the command line
2341
2105
    override, so tests that accidentally write to the common directory should
2342
2106
    be rare.
2343
2107
 
2344
 
    :cvar TEST_ROOT: Directory containing all temporary directories, plus a
2345
 
        ``.bzr`` directory that stops us ascending higher into the filesystem.
 
2108
    :cvar TEST_ROOT: Directory containing all temporary directories, plus
 
2109
    a .bzr directory that stops us ascending higher into the filesystem.
2346
2110
    """
2347
2111
 
2348
2112
    TEST_ROOT = None
2610
2374
        test_home_dir = self.test_home_dir
2611
2375
        if isinstance(test_home_dir, unicode):
2612
2376
            test_home_dir = test_home_dir.encode(sys.getfilesystemencoding())
2613
 
        self.overrideEnv('HOME', test_home_dir)
2614
 
        self.overrideEnv('BZR_HOME', test_home_dir)
 
2377
        os.environ['HOME'] = test_home_dir
 
2378
        os.environ['BZR_HOME'] = test_home_dir
2615
2379
 
2616
2380
    def setUp(self):
2617
2381
        super(TestCaseWithMemoryTransport, self).setUp()
2672
2436
 
2673
2437
    OVERRIDE_PYTHON = 'python'
2674
2438
 
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
 
 
2681
2439
    def check_file_contents(self, filename, expect):
2682
2440
        self.log("check contents of file %s" % filename)
2683
2441
        f = file(filename)
3529
3287
    return result
3530
3288
 
3531
3289
 
3532
 
class ProfileResult(testtools.ExtendedToOriginalDecorator):
 
3290
class ForwardingResult(unittest.TestResult):
 
3291
 
 
3292
    def __init__(self, target):
 
3293
        unittest.TestResult.__init__(self)
 
3294
        self.result = target
 
3295
 
 
3296
    def startTest(self, test):
 
3297
        self.result.startTest(test)
 
3298
 
 
3299
    def stopTest(self, test):
 
3300
        self.result.stopTest(test)
 
3301
 
 
3302
    def startTestRun(self):
 
3303
        self.result.startTestRun()
 
3304
 
 
3305
    def stopTestRun(self):
 
3306
        self.result.stopTestRun()
 
3307
 
 
3308
    def addSkip(self, test, reason):
 
3309
        self.result.addSkip(test, reason)
 
3310
 
 
3311
    def addSuccess(self, test):
 
3312
        self.result.addSuccess(test)
 
3313
 
 
3314
    def addError(self, test, err):
 
3315
        self.result.addError(test, err)
 
3316
 
 
3317
    def addFailure(self, test, err):
 
3318
        self.result.addFailure(test, err)
 
3319
ForwardingResult = testtools.ExtendedToOriginalDecorator
 
3320
 
 
3321
 
 
3322
class ProfileResult(ForwardingResult):
3533
3323
    """Generate profiling data for all activity between start and success.
3534
3324
    
3535
3325
    The profile data is appended to the test's _benchcalls attribute and can
3547
3337
        # unavoidably fail.
3548
3338
        bzrlib.lsprof.BzrProfiler.profiler_block = 0
3549
3339
        self.profiler.start()
3550
 
        testtools.ExtendedToOriginalDecorator.startTest(self, test)
 
3340
        ForwardingResult.startTest(self, test)
3551
3341
 
3552
3342
    def addSuccess(self, test):
3553
3343
        stats = self.profiler.stop()
3557
3347
            test._benchcalls = []
3558
3348
            calls = test._benchcalls
3559
3349
        calls.append(((test.id(), "", ""), stats))
3560
 
        testtools.ExtendedToOriginalDecorator.addSuccess(self, test)
 
3350
        ForwardingResult.addSuccess(self, test)
3561
3351
 
3562
3352
    def stopTest(self, test):
3563
 
        testtools.ExtendedToOriginalDecorator.stopTest(self, test)
 
3353
        ForwardingResult.stopTest(self, test)
3564
3354
        self.profiler = None
3565
3355
 
3566
3356
 
3574
3364
#                           with proper exclusion rules.
3575
3365
#   -Ethreads               Will display thread ident at creation/join time to
3576
3366
#                           help track thread leaks
3577
 
 
3578
 
#   -Econfig_stats          Will collect statistics using addDetail
3579
3367
selftest_debug_flags = set()
3580
3368
 
3581
3369
 
3775
3563
                key, obj, help=help, info=info, override_existing=False)
3776
3564
        except KeyError:
3777
3565
            actual = self.get(key)
3778
 
            trace.note(
3779
 
                'Test prefix alias %s is already used for %s, ignoring %s'
3780
 
                % (key, actual, obj))
 
3566
            note('Test prefix alias %s is already used for %s, ignoring %s'
 
3567
                 % (key, actual, obj))
3781
3568
 
3782
3569
    def resolve_alias(self, id_start):
3783
3570
        """Replace the alias by the prefix in the given string.
3833
3620
        'bzrlib.tests.per_repository',
3834
3621
        'bzrlib.tests.per_repository_chk',
3835
3622
        'bzrlib.tests.per_repository_reference',
3836
 
        'bzrlib.tests.per_repository_vf',
3837
3623
        'bzrlib.tests.per_uifactory',
3838
3624
        'bzrlib.tests.per_versionedfile',
3839
3625
        'bzrlib.tests.per_workingtree',
3873
3659
        'bzrlib.tests.test_commit_merge',
3874
3660
        'bzrlib.tests.test_config',
3875
3661
        'bzrlib.tests.test_conflicts',
3876
 
        'bzrlib.tests.test_controldir',
3877
3662
        'bzrlib.tests.test_counted_lock',
3878
3663
        'bzrlib.tests.test_crash',
3879
3664
        'bzrlib.tests.test_decorators',
3880
3665
        'bzrlib.tests.test_delta',
3881
3666
        'bzrlib.tests.test_debug',
 
3667
        'bzrlib.tests.test_deprecated_graph',
3882
3668
        'bzrlib.tests.test_diff',
3883
3669
        'bzrlib.tests.test_directory_service',
3884
3670
        'bzrlib.tests.test_dirstate',
3886
3672
        'bzrlib.tests.test_eol_filters',
3887
3673
        'bzrlib.tests.test_errors',
3888
3674
        'bzrlib.tests.test_export',
3889
 
        'bzrlib.tests.test_export_pot',
3890
3675
        'bzrlib.tests.test_extract',
3891
3676
        'bzrlib.tests.test_fetch',
3892
3677
        'bzrlib.tests.test_fixtures',
3906
3691
        'bzrlib.tests.test_http',
3907
3692
        'bzrlib.tests.test_http_response',
3908
3693
        'bzrlib.tests.test_https_ca_bundle',
3909
 
        'bzrlib.tests.test_i18n',
3910
3694
        'bzrlib.tests.test_identitymap',
3911
3695
        'bzrlib.tests.test_ignores',
3912
3696
        'bzrlib.tests.test_index',
3931
3715
        'bzrlib.tests.test_merge3',
3932
3716
        'bzrlib.tests.test_merge_core',
3933
3717
        'bzrlib.tests.test_merge_directive',
3934
 
        'bzrlib.tests.test_mergetools',
3935
3718
        'bzrlib.tests.test_missing',
3936
3719
        'bzrlib.tests.test_msgeditor',
3937
3720
        'bzrlib.tests.test_multiparent',
3946
3729
        'bzrlib.tests.test_permissions',
3947
3730
        'bzrlib.tests.test_plugins',
3948
3731
        'bzrlib.tests.test_progress',
3949
 
        'bzrlib.tests.test_pyutils',
3950
3732
        'bzrlib.tests.test_read_bundle',
3951
3733
        'bzrlib.tests.test_reconcile',
3952
3734
        'bzrlib.tests.test_reconfigure',
3961
3743
        'bzrlib.tests.test_rio',
3962
3744
        'bzrlib.tests.test_rules',
3963
3745
        'bzrlib.tests.test_sampler',
3964
 
        'bzrlib.tests.test_scenarios',
3965
3746
        'bzrlib.tests.test_script',
3966
3747
        'bzrlib.tests.test_selftest',
3967
3748
        'bzrlib.tests.test_serializer',
3987
3768
        'bzrlib.tests.test_testament',
3988
3769
        'bzrlib.tests.test_textfile',
3989
3770
        'bzrlib.tests.test_textmerge',
3990
 
        'bzrlib.tests.test_cethread',
3991
3771
        'bzrlib.tests.test_timestamp',
3992
3772
        'bzrlib.tests.test_trace',
3993
3773
        'bzrlib.tests.test_transactions',
4004
3784
        'bzrlib.tests.test_upgrade',
4005
3785
        'bzrlib.tests.test_upgrade_stacked',
4006
3786
        'bzrlib.tests.test_urlutils',
4007
 
        'bzrlib.tests.test_utextwrap',
4008
3787
        'bzrlib.tests.test_version',
4009
3788
        'bzrlib.tests.test_version_info',
4010
3789
        'bzrlib.tests.test_versionedfile',
4027
3806
        'bzrlib',
4028
3807
        'bzrlib.branchbuilder',
4029
3808
        'bzrlib.decorators',
 
3809
        'bzrlib.export',
4030
3810
        'bzrlib.inventory',
4031
3811
        'bzrlib.iterablefile',
4032
3812
        'bzrlib.lockdir',
4033
3813
        'bzrlib.merge3',
4034
3814
        'bzrlib.option',
4035
 
        'bzrlib.pyutils',
4036
3815
        'bzrlib.symbol_versioning',
4037
3816
        'bzrlib.tests',
4038
3817
        'bzrlib.tests.fixtures',
4039
3818
        'bzrlib.timestamp',
4040
 
        'bzrlib.transport.http',
4041
3819
        'bzrlib.version_info_formats.format_custom',
4042
3820
        ]
4043
3821
 
4096
3874
        try:
4097
3875
            # note that this really does mean "report only" -- doctest
4098
3876
            # still runs the rest of the examples
4099
 
            doc_suite = IsolatedDocTestSuite(
4100
 
                mod, optionflags=doctest.REPORT_ONLY_FIRST_FAILURE)
 
3877
            doc_suite = doctest.DocTestSuite(mod,
 
3878
                optionflags=doctest.REPORT_ONLY_FIRST_FAILURE)
4101
3879
        except ValueError, e:
4102
3880
            print '**failed to get doctest for: %s\n%s' % (mod, e)
4103
3881
            raise
4106
3884
        suite.addTest(doc_suite)
4107
3885
 
4108
3886
    default_encoding = sys.getdefaultencoding()
4109
 
    for name, plugin in _mod_plugin.plugins().items():
 
3887
    for name, plugin in bzrlib.plugin.plugins().items():
4110
3888
        if not interesting_module(plugin.module.__name__):
4111
3889
            continue
4112
3890
        plugin_suite = plugin.test_suite()
4118
3896
        if plugin_suite is not None:
4119
3897
            suite.addTest(plugin_suite)
4120
3898
        if default_encoding != sys.getdefaultencoding():
4121
 
            trace.warning(
 
3899
            bzrlib.trace.warning(
4122
3900
                'Plugin "%s" tried to reset default encoding to: %s', name,
4123
3901
                sys.getdefaultencoding())
4124
3902
            reload(sys)
4139
3917
            # Some tests mentioned in the list are not in the test suite. The
4140
3918
            # list may be out of date, report to the tester.
4141
3919
            for id in not_found:
4142
 
                trace.warning('"%s" not found in the test suite', id)
 
3920
                bzrlib.trace.warning('"%s" not found in the test suite', id)
4143
3921
        for id in duplicates:
4144
 
            trace.warning('"%s" is used as an id by several tests', id)
 
3922
            bzrlib.trace.warning('"%s" is used as an id by several tests', id)
4145
3923
 
4146
3924
    return suite
4147
3925
 
4148
3926
 
4149
 
def multiply_scenarios(*scenarios):
4150
 
    """Multiply two or more iterables of scenarios.
4151
 
 
4152
 
    It is safe to pass scenario generators or iterators.
4153
 
 
4154
 
    :returns: A list of compound scenarios: the cross-product of all 
4155
 
        scenarios, with the names concatenated and the parameters
4156
 
        merged together.
4157
 
    """
4158
 
    return reduce(_multiply_two_scenarios, map(list, scenarios))
4159
 
 
4160
 
 
4161
 
def _multiply_two_scenarios(scenarios_left, scenarios_right):
 
3927
def multiply_scenarios(scenarios_left, scenarios_right):
4162
3928
    """Multiply two sets of scenarios.
4163
3929
 
4164
3930
    :returns: the cartesian product of the two sets of scenarios, that is
4250
4016
    """
4251
4017
    new_test = copy.copy(test)
4252
4018
    new_test.id = lambda: new_id
4253
 
    # XXX: Workaround <https://bugs.launchpad.net/testtools/+bug/637725>, which
4254
 
    # causes cloned tests to share the 'details' dict.  This makes it hard to
4255
 
    # read the test output for parameterized tests, because tracebacks will be
4256
 
    # associated with irrelevant tests.
4257
 
    try:
4258
 
        details = new_test._TestCase__details
4259
 
    except AttributeError:
4260
 
        # must be a different version of testtools than expected.  Do nothing.
4261
 
        pass
4262
 
    else:
4263
 
        # Reset the '__details' dict.
4264
 
        new_test._TestCase__details = {}
4265
4019
    return new_test
4266
4020
 
4267
4021
 
4288
4042
        the module is available.
4289
4043
    """
4290
4044
 
4291
 
    py_module = pyutils.get_named_object(py_module_name)
 
4045
    py_module = __import__(py_module_name, {}, {}, ['NO_SUCH_ATTRIB'])
4292
4046
    scenarios = [
4293
4047
        ('python', {'module': py_module}),
4294
4048
    ]
4447
4201
            symbol_versioning.warn(depr_msg + use_msg, DeprecationWarning)
4448
4202
            # Import the new feature and use it as a replacement for the
4449
4203
            # deprecated one.
4450
 
            self._feature = pyutils.get_named_object(
4451
 
                self._replacement_module, self._replacement_name)
 
4204
            mod = __import__(self._replacement_module, {}, {},
 
4205
                             [self._replacement_name])
 
4206
            self._feature = getattr(mod, self._replacement_name)
4452
4207
 
4453
4208
    def _probe(self):
4454
4209
        self._ensure()
4485
4240
        return self.module_name
4486
4241
 
4487
4242
 
 
4243
# This is kept here for compatibility, it is recommended to use
 
4244
# 'bzrlib.tests.feature.paramiko' instead
 
4245
ParamikoFeature = _CompatabilityThunkFeature(
 
4246
    deprecated_in((2,1,0)),
 
4247
    'bzrlib.tests.features', 'ParamikoFeature', 'paramiko')
 
4248
 
 
4249
 
4488
4250
def probe_unicode_in_user_encoding():
4489
4251
    """Try to encode several unicode strings to use in unicode-aware tests.
4490
4252
    Return first successfull match.
4677
4439
case_sensitive_filesystem_feature = _CaseSensitiveFilesystemFeature()
4678
4440
 
4679
4441
 
 
4442
# Kept for compatibility, use bzrlib.tests.features.subunit instead
 
4443
SubUnitFeature = _CompatabilityThunkFeature(
 
4444
    deprecated_in((2,1,0)),
 
4445
    'bzrlib.tests.features', 'SubUnitFeature', 'subunit')
4680
4446
# Only define SubUnitBzrRunner if subunit is available.
4681
4447
try:
4682
4448
    from subunit import TestProtocolClient
4683
4449
    from subunit.test_results import AutoTimingTestResultDecorator
4684
 
    class SubUnitBzrProtocolClient(TestProtocolClient):
4685
 
 
4686
 
        def addSuccess(self, test, details=None):
4687
 
            # The subunit client always includes the details in the subunit
4688
 
            # stream, but we don't want to include it in ours.
4689
 
            if details is not None and 'log' in details:
4690
 
                del details['log']
4691
 
            return super(SubUnitBzrProtocolClient, self).addSuccess(
4692
 
                test, details)
4693
 
 
4694
4450
    class SubUnitBzrRunner(TextTestRunner):
4695
4451
        def run(self, test):
4696
4452
            result = AutoTimingTestResultDecorator(
4697
 
                SubUnitBzrProtocolClient(self.stream))
 
4453
                TestProtocolClient(self.stream))
4698
4454
            test.run(result)
4699
4455
            return result
4700
4456
except ImportError: