/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/tests/__init__.py

Merge bzr.dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
# Copyright (C) 2005, 2006 by 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
5
5
# the Free Software Foundation; either version 2 of the License, or
6
6
# (at your option) any later version.
7
 
 
 
7
#
8
8
# This program is distributed in the hope that it will be useful,
9
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
11
# GNU General Public License for more details.
12
 
 
 
12
#
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
29
29
import codecs
30
30
from cStringIO import StringIO
31
31
import difflib
 
32
import doctest
32
33
import errno
33
34
import logging
34
35
import os
35
36
import re
36
 
import shutil
 
37
import shlex
37
38
import stat
 
39
from subprocess import Popen, PIPE
38
40
import sys
39
41
import tempfile
40
42
import unittest
41
43
import time
42
44
 
43
45
 
 
46
from bzrlib import memorytree
44
47
import bzrlib.branch
45
48
import bzrlib.bzrdir as bzrdir
46
49
import bzrlib.commands
 
50
import bzrlib.bundle.serializer
47
51
import bzrlib.errors as errors
48
52
import bzrlib.inventory
49
53
import bzrlib.iterablefile
50
54
import bzrlib.lockdir
 
55
try:
 
56
    import bzrlib.lsprof
 
57
except ImportError:
 
58
    # lsprof not available
 
59
    pass
51
60
from bzrlib.merge import merge_inner
52
61
import bzrlib.merge3
53
62
import bzrlib.osutils
54
63
import bzrlib.osutils as osutils
55
64
import bzrlib.plugin
 
65
import bzrlib.progress as progress
56
66
from bzrlib.revision import common_ancestor
57
67
import bzrlib.store
 
68
from bzrlib import symbol_versioning
58
69
import bzrlib.trace
59
 
from bzrlib.transport import urlescape, get_transport
 
70
from bzrlib.transport import get_transport
60
71
import bzrlib.transport
61
72
from bzrlib.transport.local import LocalRelpathServer
62
73
from bzrlib.transport.readonly import ReadonlyServer
63
74
from bzrlib.trace import mutter
64
 
from bzrlib.tests.TestUtil import TestLoader, TestSuite
 
75
from bzrlib.tests import TestUtil
 
76
from bzrlib.tests.TestUtil import (
 
77
                          TestSuite,
 
78
                          TestLoader,
 
79
                          )
65
80
from bzrlib.tests.treeshape import build_tree_contents
 
81
import bzrlib.urlutils as urlutils
66
82
from bzrlib.workingtree import WorkingTree, WorkingTreeFormat2
67
83
 
68
84
default_transport = LocalRelpathServer
70
86
MODULES_TO_TEST = []
71
87
MODULES_TO_DOCTEST = [
72
88
                      bzrlib.branch,
 
89
                      bzrlib.bundle.serializer,
73
90
                      bzrlib.commands,
74
91
                      bzrlib.errors,
75
92
                      bzrlib.inventory,
78
95
                      bzrlib.merge3,
79
96
                      bzrlib.option,
80
97
                      bzrlib.osutils,
81
 
                      bzrlib.store
 
98
                      bzrlib.store,
 
99
                      bzrlib.transport,
82
100
                      ]
 
101
 
 
102
 
83
103
def packages_to_test():
84
104
    """Return a list of packages to test.
85
105
 
92
112
    import bzrlib.tests.bzrdir_implementations
93
113
    import bzrlib.tests.interrepository_implementations
94
114
    import bzrlib.tests.interversionedfile_implementations
 
115
    import bzrlib.tests.intertree_implementations
95
116
    import bzrlib.tests.repository_implementations
96
117
    import bzrlib.tests.revisionstore_implementations
 
118
    import bzrlib.tests.tree_implementations
97
119
    import bzrlib.tests.workingtree_implementations
98
120
    return [
99
121
            bzrlib.doc,
102
124
            bzrlib.tests.bzrdir_implementations,
103
125
            bzrlib.tests.interrepository_implementations,
104
126
            bzrlib.tests.interversionedfile_implementations,
 
127
            bzrlib.tests.intertree_implementations,
105
128
            bzrlib.tests.repository_implementations,
106
129
            bzrlib.tests.revisionstore_implementations,
 
130
            bzrlib.tests.tree_implementations,
107
131
            bzrlib.tests.workingtree_implementations,
108
132
            ]
109
133
 
114
138
    Shows output in a different format, including displaying runtime for tests.
115
139
    """
116
140
    stop_early = False
117
 
 
118
 
    def _elapsedTime(self):
119
 
        return "%5dms" % (1000 * (time.time() - self._start_time))
 
141
    
 
142
    def __init__(self, stream, descriptions, verbosity, pb=None,
 
143
                 bench_history=None):
 
144
        """Construct new TestResult.
 
145
 
 
146
        :param bench_history: Optionally, a writable file object to accumulate
 
147
            benchmark results.
 
148
        """
 
149
        unittest._TextTestResult.__init__(self, stream, descriptions, verbosity)
 
150
        self.pb = pb
 
151
        if bench_history is not None:
 
152
            from bzrlib.version import _get_bzr_source_tree
 
153
            src_tree = _get_bzr_source_tree()
 
154
            if src_tree:
 
155
                try:
 
156
                    revision_id = src_tree.get_parent_ids()[0]
 
157
                except IndexError:
 
158
                    # XXX: if this is a brand new tree, do the same as if there
 
159
                    # is no branch.
 
160
                    revision_id = ''
 
161
            else:
 
162
                # XXX: If there's no branch, what should we do?
 
163
                revision_id = ''
 
164
            bench_history.write("--date %s %s\n" % (time.time(), revision_id))
 
165
        self._bench_history = bench_history
 
166
    
 
167
    def extractBenchmarkTime(self, testCase):
 
168
        """Add a benchmark time for the current test case."""
 
169
        self._benchmarkTime = getattr(testCase, "_benchtime", None)
 
170
    
 
171
    def _elapsedTestTimeString(self):
 
172
        """Return a time string for the overall time the current test has taken."""
 
173
        return self._formatTime(time.time() - self._start_time)
 
174
 
 
175
    def _testTimeString(self):
 
176
        if self._benchmarkTime is not None:
 
177
            return "%s/%s" % (
 
178
                self._formatTime(self._benchmarkTime),
 
179
                self._elapsedTestTimeString())
 
180
        else:
 
181
            return "      %s" % self._elapsedTestTimeString()
 
182
 
 
183
    def _formatTime(self, seconds):
 
184
        """Format seconds as milliseconds with leading spaces."""
 
185
        return "%5dms" % (1000 * seconds)
 
186
 
 
187
    def _ellipsise_unimportant_words(self, a_string, final_width,
 
188
                                   keep_start=False):
 
189
        """Add ellipses (sp?) for overly long strings.
 
190
        
 
191
        :param keep_start: If true preserve the start of a_string rather
 
192
                           than the end of it.
 
193
        """
 
194
        if keep_start:
 
195
            if len(a_string) > final_width:
 
196
                result = a_string[:final_width-3] + '...'
 
197
            else:
 
198
                result = a_string
 
199
        else:
 
200
            if len(a_string) > final_width:
 
201
                result = '...' + a_string[3-final_width:]
 
202
            else:
 
203
                result = a_string
 
204
        return result.ljust(final_width)
120
205
 
121
206
    def startTest(self, test):
122
207
        unittest.TestResult.startTest(self, test)
124
209
        # the beginning, but in an id, the important words are
125
210
        # at the end
126
211
        SHOW_DESCRIPTIONS = False
 
212
 
 
213
        if not self.showAll and self.dots and self.pb is not None:
 
214
            final_width = 13
 
215
        else:
 
216
            final_width = osutils.terminal_width()
 
217
            final_width = final_width - 15 - 8
 
218
        what = None
 
219
        if SHOW_DESCRIPTIONS:
 
220
            what = test.shortDescription()
 
221
            if what:
 
222
                what = self._ellipsise_unimportant_words(what, final_width, keep_start=True)
 
223
        if what is None:
 
224
            what = test.id()
 
225
            if what.startswith('bzrlib.tests.'):
 
226
                what = what[13:]
 
227
            what = self._ellipsise_unimportant_words(what, final_width)
127
228
        if self.showAll:
128
 
            width = osutils.terminal_width()
129
 
            name_width = width - 15
130
 
            what = None
131
 
            if SHOW_DESCRIPTIONS:
132
 
                what = test.shortDescription()
133
 
                if what:
134
 
                    if len(what) > name_width:
135
 
                        what = what[:name_width-3] + '...'
136
 
            if what is None:
137
 
                what = test.id()
138
 
                if what.startswith('bzrlib.tests.'):
139
 
                    what = what[13:]
140
 
                if len(what) > name_width:
141
 
                    what = '...' + what[3-name_width:]
142
 
            what = what.ljust(name_width)
143
229
            self.stream.write(what)
 
230
        elif self.dots and self.pb is not None:
 
231
            self.pb.update(what, self.testsRun - 1, None)
144
232
        self.stream.flush()
 
233
        self._recordTestStartTime()
 
234
 
 
235
    def _recordTestStartTime(self):
 
236
        """Record that a test has started."""
145
237
        self._start_time = time.time()
146
238
 
147
239
    def addError(self, test, err):
148
240
        if isinstance(err[1], TestSkipped):
149
241
            return self.addSkipped(test, err)    
150
242
        unittest.TestResult.addError(self, test, err)
 
243
        self.extractBenchmarkTime(test)
151
244
        if self.showAll:
152
 
            self.stream.writeln("ERROR %s" % self._elapsedTime())
153
 
        elif self.dots:
 
245
            self.stream.writeln("ERROR %s" % self._testTimeString())
 
246
        elif self.dots and self.pb is None:
154
247
            self.stream.write('E')
 
248
        elif self.dots:
 
249
            self.pb.update(self._ellipsise_unimportant_words('ERROR', 13), self.testsRun, None)
 
250
            self.pb.note(self._ellipsise_unimportant_words(
 
251
                            test.id() + ': ERROR',
 
252
                            osutils.terminal_width()))
155
253
        self.stream.flush()
156
254
        if self.stop_early:
157
255
            self.stop()
158
256
 
159
257
    def addFailure(self, test, err):
160
258
        unittest.TestResult.addFailure(self, test, err)
 
259
        self.extractBenchmarkTime(test)
161
260
        if self.showAll:
162
 
            self.stream.writeln(" FAIL %s" % self._elapsedTime())
163
 
        elif self.dots:
 
261
            self.stream.writeln(" FAIL %s" % self._testTimeString())
 
262
        elif self.dots and self.pb is None:
164
263
            self.stream.write('F')
 
264
        elif self.dots:
 
265
            self.pb.update(self._ellipsise_unimportant_words('FAIL', 13), self.testsRun, None)
 
266
            self.pb.note(self._ellipsise_unimportant_words(
 
267
                            test.id() + ': FAIL',
 
268
                            osutils.terminal_width()))
165
269
        self.stream.flush()
166
270
        if self.stop_early:
167
271
            self.stop()
168
272
 
169
273
    def addSuccess(self, test):
 
274
        self.extractBenchmarkTime(test)
 
275
        if self._bench_history is not None:
 
276
            if self._benchmarkTime is not None:
 
277
                self._bench_history.write("%s %s\n" % (
 
278
                    self._formatTime(self._benchmarkTime),
 
279
                    test.id()))
170
280
        if self.showAll:
171
 
            self.stream.writeln('   OK %s' % self._elapsedTime())
172
 
        elif self.dots:
 
281
            self.stream.writeln('   OK %s' % self._testTimeString())
 
282
            for bench_called, stats in getattr(test, '_benchcalls', []):
 
283
                self.stream.writeln('LSProf output for %s(%s, %s)' % bench_called)
 
284
                stats.pprint(file=self.stream)
 
285
        elif self.dots and self.pb is None:
173
286
            self.stream.write('~')
 
287
        elif self.dots:
 
288
            self.pb.update(self._ellipsise_unimportant_words('OK', 13), self.testsRun, None)
174
289
        self.stream.flush()
175
290
        unittest.TestResult.addSuccess(self, test)
176
291
 
177
292
    def addSkipped(self, test, skip_excinfo):
 
293
        self.extractBenchmarkTime(test)
178
294
        if self.showAll:
179
 
            print >>self.stream, ' SKIP %s' % self._elapsedTime()
 
295
            print >>self.stream, ' SKIP %s' % self._testTimeString()
180
296
            print >>self.stream, '     %s' % skip_excinfo[1]
181
 
        elif self.dots:
 
297
        elif self.dots and self.pb is None:
182
298
            self.stream.write('S')
 
299
        elif self.dots:
 
300
            self.pb.update(self._ellipsise_unimportant_words('SKIP', 13), self.testsRun, None)
183
301
        self.stream.flush()
184
302
        # seems best to treat this as success from point-of-view of unittest
185
303
        # -- it actually does nothing so it barely matters :)
186
 
        unittest.TestResult.addSuccess(self, test)
 
304
        try:
 
305
            test.tearDown()
 
306
        except KeyboardInterrupt:
 
307
            raise
 
308
        except:
 
309
            self.addError(test, test.__exc_info())
 
310
        else:
 
311
            unittest.TestResult.addSuccess(self, test)
187
312
 
188
313
    def printErrorList(self, flavour, errors):
189
314
        for test, err in errors:
200
325
            self.stream.writeln("%s" % err)
201
326
 
202
327
 
203
 
class TextTestRunner(unittest.TextTestRunner):
 
328
class TextTestRunner(object):
204
329
    stop_on_failure = False
205
330
 
 
331
    def __init__(self,
 
332
                 stream=sys.stderr,
 
333
                 descriptions=0,
 
334
                 verbosity=1,
 
335
                 keep_output=False,
 
336
                 pb=None,
 
337
                 bench_history=None):
 
338
        self.stream = unittest._WritelnDecorator(stream)
 
339
        self.descriptions = descriptions
 
340
        self.verbosity = verbosity
 
341
        self.keep_output = keep_output
 
342
        self.pb = pb
 
343
        self._bench_history = bench_history
 
344
 
206
345
    def _makeResult(self):
207
 
        result = _MyResult(self.stream, self.descriptions, self.verbosity)
 
346
        result = _MyResult(self.stream,
 
347
                           self.descriptions,
 
348
                           self.verbosity,
 
349
                           pb=self.pb,
 
350
                           bench_history=self._bench_history)
208
351
        result.stop_early = self.stop_on_failure
209
352
        return result
210
353
 
 
354
    def run(self, test):
 
355
        "Run the given test case or test suite."
 
356
        result = self._makeResult()
 
357
        startTime = time.time()
 
358
        if self.pb is not None:
 
359
            self.pb.update('Running tests', 0, test.countTestCases())
 
360
        test.run(result)
 
361
        stopTime = time.time()
 
362
        timeTaken = stopTime - startTime
 
363
        result.printErrors()
 
364
        self.stream.writeln(result.separator2)
 
365
        run = result.testsRun
 
366
        self.stream.writeln("Ran %d test%s in %.3fs" %
 
367
                            (run, run != 1 and "s" or "", timeTaken))
 
368
        self.stream.writeln()
 
369
        if not result.wasSuccessful():
 
370
            self.stream.write("FAILED (")
 
371
            failed, errored = map(len, (result.failures, result.errors))
 
372
            if failed:
 
373
                self.stream.write("failures=%d" % failed)
 
374
            if errored:
 
375
                if failed: self.stream.write(", ")
 
376
                self.stream.write("errors=%d" % errored)
 
377
            self.stream.writeln(")")
 
378
        else:
 
379
            self.stream.writeln("OK")
 
380
        if self.pb is not None:
 
381
            self.pb.update('Cleaning up', 0, 1)
 
382
        # This is still a little bogus, 
 
383
        # but only a little. Folk not using our testrunner will
 
384
        # have to delete their temp directories themselves.
 
385
        test_root = TestCaseInTempDir.TEST_ROOT
 
386
        if result.wasSuccessful() or not self.keep_output:
 
387
            if test_root is not None:
 
388
                # If LANG=C we probably have created some bogus paths
 
389
                # which rmtree(unicode) will fail to delete
 
390
                # so make sure we are using rmtree(str) to delete everything
 
391
                # except on win32, where rmtree(str) will fail
 
392
                # since it doesn't have the property of byte-stream paths
 
393
                # (they are either ascii or mbcs)
 
394
                if sys.platform == 'win32':
 
395
                    # make sure we are using the unicode win32 api
 
396
                    test_root = unicode(test_root)
 
397
                else:
 
398
                    test_root = test_root.encode(
 
399
                        sys.getfilesystemencoding())
 
400
                osutils.rmtree(test_root)
 
401
        else:
 
402
            if self.pb is not None:
 
403
                self.pb.note("Failed tests working directories are in '%s'\n",
 
404
                             test_root)
 
405
            else:
 
406
                self.stream.writeln(
 
407
                    "Failed tests working directories are in '%s'\n" %
 
408
                    test_root)
 
409
        TestCaseInTempDir.TEST_ROOT = None
 
410
        if self.pb is not None:
 
411
            self.pb.clear()
 
412
        return result
 
413
 
211
414
 
212
415
def iter_suite_tests(suite):
213
416
    """Return all tests in a suite, recursing through nested suites"""
224
427
 
225
428
class TestSkipped(Exception):
226
429
    """Indicates that a test was intentionally skipped, rather than failing."""
227
 
    # XXX: Not used yet
228
430
 
229
431
 
230
432
class CommandFailed(Exception):
231
433
    pass
232
434
 
 
435
 
 
436
class StringIOWrapper(object):
 
437
    """A wrapper around cStringIO which just adds an encoding attribute.
 
438
    
 
439
    Internally we can check sys.stdout to see what the output encoding
 
440
    should be. However, cStringIO has no encoding attribute that we can
 
441
    set. So we wrap it instead.
 
442
    """
 
443
    encoding='ascii'
 
444
    _cstring = None
 
445
 
 
446
    def __init__(self, s=None):
 
447
        if s is not None:
 
448
            self.__dict__['_cstring'] = StringIO(s)
 
449
        else:
 
450
            self.__dict__['_cstring'] = StringIO()
 
451
 
 
452
    def __getattr__(self, name, getattr=getattr):
 
453
        return getattr(self.__dict__['_cstring'], name)
 
454
 
 
455
    def __setattr__(self, name, val):
 
456
        if name == 'encoding':
 
457
            self.__dict__['encoding'] = val
 
458
        else:
 
459
            return setattr(self._cstring, name, val)
 
460
 
 
461
 
233
462
class TestCase(unittest.TestCase):
234
463
    """Base class for bzr unit tests.
235
464
    
251
480
    accidentally overlooked.
252
481
    """
253
482
 
254
 
    BZRPATH = 'bzr'
255
483
    _log_file_name = None
256
484
    _log_contents = ''
 
485
    # record lsprof data when performing benchmark calls.
 
486
    _gather_lsprof_in_benchmarks = False
257
487
 
258
488
    def __init__(self, methodName='testMethod'):
259
489
        super(TestCase, self).__init__(methodName)
264
494
        self._cleanEnvironment()
265
495
        bzrlib.trace.disable_default_logging()
266
496
        self._startLogFile()
 
497
        self._benchcalls = []
 
498
        self._benchtime = None
267
499
 
268
500
    def _ndiff_strings(self, a, b):
269
501
        """Return ndiff between two strings containing lines.
303
535
            raise AssertionError('string %r does not start with %r' % (s, prefix))
304
536
 
305
537
    def assertEndsWith(self, s, suffix):
306
 
        if not s.endswith(prefix):
 
538
        """Asserts that s ends with suffix."""
 
539
        if not s.endswith(suffix):
307
540
            raise AssertionError('string %r does not end with %r' % (s, suffix))
308
541
 
309
542
    def assertContainsRe(self, haystack, needle_re):
312
545
            raise AssertionError('pattern "%s" not found in "%s"'
313
546
                    % (needle_re, haystack))
314
547
 
 
548
    def assertNotContainsRe(self, haystack, needle_re):
 
549
        """Assert that a does not match a regular expression"""
 
550
        if re.search(needle_re, haystack):
 
551
            raise AssertionError('pattern "%s" found in "%s"'
 
552
                    % (needle_re, haystack))
 
553
 
315
554
    def assertSubset(self, sublist, superlist):
316
555
        """Assert that every entry in sublist is present in superlist."""
317
556
        missing = []
341
580
    def assertIsInstance(self, obj, kls):
342
581
        """Fail if obj is not an instance of kls"""
343
582
        if not isinstance(obj, kls):
344
 
            self.fail("%r is not an instance of %s" % (obj, kls))
 
583
            self.fail("%r is an instance of %s rather than %s" % (
 
584
                obj, obj.__class__, kls))
 
585
 
 
586
    def _capture_warnings(self, a_callable, *args, **kwargs):
 
587
        """A helper for callDeprecated and applyDeprecated.
 
588
 
 
589
        :param a_callable: A callable to call.
 
590
        :param args: The positional arguments for the callable
 
591
        :param kwargs: The keyword arguments for the callable
 
592
        :return: A tuple (warnings, result). result is the result of calling
 
593
            a_callable(*args, **kwargs).
 
594
        """
 
595
        local_warnings = []
 
596
        def capture_warnings(msg, cls, stacklevel=None):
 
597
            # we've hooked into a deprecation specific callpath,
 
598
            # only deprecations should getting sent via it.
 
599
            self.assertEqual(cls, DeprecationWarning)
 
600
            local_warnings.append(msg)
 
601
        original_warning_method = symbol_versioning.warn
 
602
        symbol_versioning.set_warning_method(capture_warnings)
 
603
        try:
 
604
            result = a_callable(*args, **kwargs)
 
605
        finally:
 
606
            symbol_versioning.set_warning_method(original_warning_method)
 
607
        return (local_warnings, result)
 
608
 
 
609
    def applyDeprecated(self, deprecation_format, a_callable, *args, **kwargs):
 
610
        """Call a deprecated callable without warning the user.
 
611
 
 
612
        :param deprecation_format: The deprecation format that the callable
 
613
            should have been deprecated with. This is the same type as the 
 
614
            parameter to deprecated_method/deprecated_function. If the 
 
615
            callable is not deprecated with this format, an assertion error
 
616
            will be raised.
 
617
        :param a_callable: A callable to call. This may be a bound method or
 
618
            a regular function. It will be called with *args and **kwargs.
 
619
        :param args: The positional arguments for the callable
 
620
        :param kwargs: The keyword arguments for the callable
 
621
        :return: The result of a_callable(*args, **kwargs)
 
622
        """
 
623
        call_warnings, result = self._capture_warnings(a_callable,
 
624
            *args, **kwargs)
 
625
        expected_first_warning = symbol_versioning.deprecation_string(
 
626
            a_callable, deprecation_format)
 
627
        if len(call_warnings) == 0:
 
628
            self.fail("No assertion generated by call to %s" %
 
629
                a_callable)
 
630
        self.assertEqual(expected_first_warning, call_warnings[0])
 
631
        return result
 
632
 
 
633
    def callDeprecated(self, expected, callable, *args, **kwargs):
 
634
        """Assert that a callable is deprecated in a particular way.
 
635
 
 
636
        This is a very precise test for unusual requirements. The 
 
637
        applyDeprecated helper function is probably more suited for most tests
 
638
        as it allows you to simply specify the deprecation format being used
 
639
        and will ensure that that is issued for the function being called.
 
640
 
 
641
        :param expected: a list of the deprecation warnings expected, in order
 
642
        :param callable: The callable to call
 
643
        :param args: The positional arguments for the callable
 
644
        :param kwargs: The keyword arguments for the callable
 
645
        """
 
646
        call_warnings, result = self._capture_warnings(callable,
 
647
            *args, **kwargs)
 
648
        self.assertEqual(expected, call_warnings)
 
649
        return result
345
650
 
346
651
    def _startLogFile(self):
347
652
        """Send bzr and test log messages to a temporary file.
349
654
        The file is removed as the test is torn down.
350
655
        """
351
656
        fileno, name = tempfile.mkstemp(suffix='.log', prefix='testbzr')
352
 
        encoder, decoder, stream_reader, stream_writer = codecs.lookup('UTF-8')
353
 
        self._log_file = stream_writer(os.fdopen(fileno, 'w+'))
 
657
        self._log_file = os.fdopen(fileno, 'w+')
354
658
        self._log_nonce = bzrlib.trace.enable_test_log(self._log_file)
355
659
        self._log_file_name = name
356
660
        self.addCleanup(self._finishLogFile)
360
664
 
361
665
        Read contents into memory, close, and delete.
362
666
        """
 
667
        if self._log_file is None:
 
668
            return
363
669
        bzrlib.trace.disable_test_log(self._log_nonce)
364
670
        self._log_file.seek(0)
365
671
        self._log_contents = self._log_file.read()
382
688
        new_env = {
383
689
            'HOME': os.getcwd(),
384
690
            'APPDATA': os.getcwd(),
385
 
            'BZREMAIL': None,
 
691
            'BZR_EMAIL': None,
 
692
            'BZREMAIL': None, # may still be present in the environment
386
693
            'EMAIL': None,
 
694
            'BZR_PROGRESS_BAR': None,
387
695
        }
388
696
        self.__old_env = {}
389
697
        self.addCleanup(self._restoreEnvironment)
390
698
        for name, value in new_env.iteritems():
391
699
            self._captureVar(name, value)
392
700
 
393
 
 
394
701
    def _captureVar(self, name, newvalue):
395
 
        """Set an environment variable, preparing it to be reset when finished."""
396
 
        self.__old_env[name] = os.environ.get(name, None)
397
 
        if newvalue is None:
398
 
            if name in os.environ:
399
 
                del os.environ[name]
400
 
        else:
401
 
            os.environ[name] = newvalue
402
 
 
403
 
    @staticmethod
404
 
    def _restoreVar(name, value):
405
 
        if value is None:
406
 
            if name in os.environ:
407
 
                del os.environ[name]
408
 
        else:
409
 
            os.environ[name] = value
 
702
        """Set an environment variable, and reset it when finished."""
 
703
        self.__old_env[name] = osutils.set_or_unset_env(name, newvalue)
410
704
 
411
705
    def _restoreEnvironment(self):
412
706
        for name, value in self.__old_env.iteritems():
413
 
            self._restoreVar(name, value)
 
707
            osutils.set_or_unset_env(name, value)
414
708
 
415
709
    def tearDown(self):
416
710
        self._runCleanups()
417
711
        unittest.TestCase.tearDown(self)
418
712
 
 
713
    def time(self, callable, *args, **kwargs):
 
714
        """Run callable and accrue the time it takes to the benchmark time.
 
715
        
 
716
        If lsprofiling is enabled (i.e. by --lsprof-time to bzr selftest) then
 
717
        this will cause lsprofile statistics to be gathered and stored in
 
718
        self._benchcalls.
 
719
        """
 
720
        if self._benchtime is None:
 
721
            self._benchtime = 0
 
722
        start = time.time()
 
723
        try:
 
724
            if not self._gather_lsprof_in_benchmarks:
 
725
                return callable(*args, **kwargs)
 
726
            else:
 
727
                # record this benchmark
 
728
                ret, stats = bzrlib.lsprof.profile(callable, *args, **kwargs)
 
729
                stats.sort()
 
730
                self._benchcalls.append(((callable, args, kwargs), stats))
 
731
                return ret
 
732
        finally:
 
733
            self._benchtime += time.time() - start
 
734
 
419
735
    def _runCleanups(self):
420
736
        """Run registered cleanup functions. 
421
737
 
441
757
        """Shortcut that splits cmd into words, runs, and returns stdout"""
442
758
        return self.run_bzr_captured(cmd.split(), retcode=retcode)[0]
443
759
 
444
 
    def run_bzr_captured(self, argv, retcode=0):
 
760
    def run_bzr_captured(self, argv, retcode=0, encoding=None, stdin=None):
445
761
        """Invoke bzr and return (stdout, stderr).
446
762
 
447
763
        Useful for code that wants to check the contents of the
458
774
        errors, and with logging set to something approximating the
459
775
        default, so that error reporting can be checked.
460
776
 
461
 
        argv -- arguments to invoke bzr
462
 
        retcode -- expected return code, or None for don't-care.
 
777
        :param argv: arguments to invoke bzr
 
778
        :param retcode: expected return code, or None for don't-care.
 
779
        :param encoding: encoding for sys.stdout and sys.stderr
 
780
        :param stdin: A string to be used as stdin for the command.
463
781
        """
464
 
        stdout = StringIO()
465
 
        stderr = StringIO()
466
 
        self.log('run bzr: %s', ' '.join(argv))
 
782
        if encoding is None:
 
783
            encoding = bzrlib.user_encoding
 
784
        if stdin is not None:
 
785
            stdin = StringIO(stdin)
 
786
        stdout = StringIOWrapper()
 
787
        stderr = StringIOWrapper()
 
788
        stdout.encoding = encoding
 
789
        stderr.encoding = encoding
 
790
 
 
791
        self.log('run bzr: %r', argv)
467
792
        # FIXME: don't call into logging here
468
793
        handler = logging.StreamHandler(stderr)
469
 
        handler.setFormatter(bzrlib.trace.QuietFormatter())
470
794
        handler.setLevel(logging.INFO)
471
795
        logger = logging.getLogger('')
472
796
        logger.addHandler(handler)
 
797
        old_ui_factory = bzrlib.ui.ui_factory
 
798
        bzrlib.ui.ui_factory = bzrlib.tests.blackbox.TestUIFactory(
 
799
            stdout=stdout,
 
800
            stderr=stderr)
 
801
        bzrlib.ui.ui_factory.stdin = stdin
473
802
        try:
474
 
            result = self.apply_redirected(None, stdout, stderr,
 
803
            result = self.apply_redirected(stdin, stdout, stderr,
475
804
                                           bzrlib.commands.run_bzr_catch_errors,
476
805
                                           argv)
477
806
        finally:
478
807
            logger.removeHandler(handler)
 
808
            bzrlib.ui.ui_factory = old_ui_factory
 
809
 
479
810
        out = stdout.getvalue()
480
811
        err = stderr.getvalue()
481
812
        if out:
482
 
            self.log('output:\n%s', out)
 
813
            self.log('output:\n%r', out)
483
814
        if err:
484
 
            self.log('errors:\n%s', err)
 
815
            self.log('errors:\n%r', err)
485
816
        if retcode is not None:
486
 
            self.assertEquals(result, retcode)
 
817
            self.assertEquals(retcode, result)
487
818
        return out, err
488
819
 
489
820
    def run_bzr(self, *args, **kwargs):
495
826
 
496
827
        This sends the stdout/stderr results into the test's log,
497
828
        where it may be useful for debugging.  See also run_captured.
 
829
 
 
830
        :param stdin: A string to be used as stdin for the command.
498
831
        """
499
832
        retcode = kwargs.pop('retcode', 0)
500
 
        return self.run_bzr_captured(args, retcode)
 
833
        encoding = kwargs.pop('encoding', None)
 
834
        stdin = kwargs.pop('stdin', None)
 
835
        return self.run_bzr_captured(args, retcode=retcode, encoding=encoding, stdin=stdin)
 
836
 
 
837
    def run_bzr_decode(self, *args, **kwargs):
 
838
        if 'encoding' in kwargs:
 
839
            encoding = kwargs['encoding']
 
840
        else:
 
841
            encoding = bzrlib.user_encoding
 
842
        return self.run_bzr(*args, **kwargs)[0].decode(encoding)
 
843
 
 
844
    def run_bzr_error(self, error_regexes, *args, **kwargs):
 
845
        """Run bzr, and check that stderr contains the supplied regexes
 
846
        
 
847
        :param error_regexes: Sequence of regular expressions which 
 
848
            must each be found in the error output. The relative ordering
 
849
            is not enforced.
 
850
        :param args: command-line arguments for bzr
 
851
        :param kwargs: Keyword arguments which are interpreted by run_bzr
 
852
            This function changes the default value of retcode to be 3,
 
853
            since in most cases this is run when you expect bzr to fail.
 
854
        :return: (out, err) The actual output of running the command (in case you
 
855
                 want to do more inspection)
 
856
 
 
857
        Examples of use:
 
858
            # Make sure that commit is failing because there is nothing to do
 
859
            self.run_bzr_error(['no changes to commit'],
 
860
                               'commit', '-m', 'my commit comment')
 
861
            # Make sure --strict is handling an unknown file, rather than
 
862
            # giving us the 'nothing to do' error
 
863
            self.build_tree(['unknown'])
 
864
            self.run_bzr_error(['Commit refused because there are unknown files'],
 
865
                               'commit', '--strict', '-m', 'my commit comment')
 
866
        """
 
867
        kwargs.setdefault('retcode', 3)
 
868
        out, err = self.run_bzr(*args, **kwargs)
 
869
        for regex in error_regexes:
 
870
            self.assertContainsRe(err, regex)
 
871
        return out, err
 
872
 
 
873
    def run_bzr_subprocess(self, *args, **kwargs):
 
874
        """Run bzr in a subprocess for testing.
 
875
 
 
876
        This starts a new Python interpreter and runs bzr in there. 
 
877
        This should only be used for tests that have a justifiable need for
 
878
        this isolation: e.g. they are testing startup time, or signal
 
879
        handling, or early startup code, etc.  Subprocess code can't be 
 
880
        profiled or debugged so easily.
 
881
 
 
882
        :param retcode: The status code that is expected.  Defaults to 0.  If
 
883
            None is supplied, the status code is not checked.
 
884
        :param env_changes: A dictionary which lists changes to environment
 
885
            variables. A value of None will unset the env variable.
 
886
            The values must be strings. The change will only occur in the
 
887
            child, so you don't need to fix the environment after running.
 
888
        :param universal_newlines: Convert CRLF => LF
 
889
        """
 
890
        env_changes = kwargs.get('env_changes', {})
 
891
        process = self.start_bzr_subprocess(args, env_changes=env_changes)
 
892
        # We distinguish between retcode=None and retcode not passed.
 
893
        supplied_retcode = kwargs.get('retcode', 0)
 
894
        return self.finish_bzr_subprocess(process, retcode=supplied_retcode,
 
895
            universal_newlines=kwargs.get('universal_newlines', False),
 
896
            process_args=args)
 
897
 
 
898
    def start_bzr_subprocess(self, process_args, env_changes=None,
 
899
                             skip_if_plan_to_signal=False):
 
900
        """Start bzr in a subprocess for testing.
 
901
 
 
902
        This starts a new Python interpreter and runs bzr in there.
 
903
        This should only be used for tests that have a justifiable need for
 
904
        this isolation: e.g. they are testing startup time, or signal
 
905
        handling, or early startup code, etc.  Subprocess code can't be
 
906
        profiled or debugged so easily.
 
907
 
 
908
        :param process_args: a list of arguments to pass to the bzr executable,
 
909
            for example `['--version']`.
 
910
        :param env_changes: A dictionary which lists changes to environment
 
911
            variables. A value of None will unset the env variable.
 
912
            The values must be strings. The change will only occur in the
 
913
            child, so you don't need to fix the environment after running.
 
914
        :param skip_if_plan_to_signal: raise TestSkipped when true and os.kill
 
915
            is not available.
 
916
 
 
917
        :returns: Popen object for the started process.
 
918
        """
 
919
        if skip_if_plan_to_signal:
 
920
            if not getattr(os, 'kill', None):
 
921
                raise TestSkipped("os.kill not available.")
 
922
 
 
923
        if env_changes is None:
 
924
            env_changes = {}
 
925
        old_env = {}
 
926
 
 
927
        def cleanup_environment():
 
928
            for env_var, value in env_changes.iteritems():
 
929
                old_env[env_var] = osutils.set_or_unset_env(env_var, value)
 
930
 
 
931
        def restore_environment():
 
932
            for env_var, value in old_env.iteritems():
 
933
                osutils.set_or_unset_env(env_var, value)
 
934
 
 
935
        bzr_path = self.get_bzr_path()
 
936
 
 
937
        try:
 
938
            # win32 subprocess doesn't support preexec_fn
 
939
            # so we will avoid using it on all platforms, just to
 
940
            # make sure the code path is used, and we don't break on win32
 
941
            cleanup_environment()
 
942
            process = Popen([sys.executable, bzr_path] + list(process_args),
 
943
                             stdin=PIPE, stdout=PIPE, stderr=PIPE)
 
944
        finally:
 
945
            restore_environment()
 
946
        return process
 
947
 
 
948
    def get_bzr_path(self):
 
949
        """Return the path of the 'bzr' executable for this test suite."""
 
950
        bzr_path = os.path.dirname(os.path.dirname(bzrlib.__file__))+'/bzr'
 
951
        if not os.path.isfile(bzr_path):
 
952
            # We are probably installed. Assume sys.argv is the right file
 
953
            bzr_path = sys.argv[0]
 
954
        return bzr_path
 
955
 
 
956
    def finish_bzr_subprocess(self, process, retcode=0, send_signal=None,
 
957
                              universal_newlines=False, process_args=None):
 
958
        """Finish the execution of process.
 
959
 
 
960
        :param process: the Popen object returned from start_bzr_subprocess.
 
961
        :param retcode: The status code that is expected.  Defaults to 0.  If
 
962
            None is supplied, the status code is not checked.
 
963
        :param send_signal: an optional signal to send to the process.
 
964
        :param universal_newlines: Convert CRLF => LF
 
965
        :returns: (stdout, stderr)
 
966
        """
 
967
        if send_signal is not None:
 
968
            os.kill(process.pid, send_signal)
 
969
        out, err = process.communicate()
 
970
 
 
971
        if universal_newlines:
 
972
            out = out.replace('\r\n', '\n')
 
973
            err = err.replace('\r\n', '\n')
 
974
 
 
975
        if retcode is not None and retcode != process.returncode:
 
976
            if process_args is None:
 
977
                process_args = "(unknown args)"
 
978
            mutter('Output of bzr %s:\n%s', process_args, out)
 
979
            mutter('Error for bzr %s:\n%s', process_args, err)
 
980
            self.fail('Command bzr %s failed with retcode %s != %s'
 
981
                      % (process_args, retcode, process.returncode))
 
982
        return [out, err]
501
983
 
502
984
    def check_inventory_shape(self, inv, shape):
503
985
        """Compare an inventory to a list of expected names.
551
1033
            sys.stderr = real_stderr
552
1034
            sys.stdin = real_stdin
553
1035
 
 
1036
    @symbol_versioning.deprecated_method(symbol_versioning.zero_eleven)
554
1037
    def merge(self, branch_from, wt_to):
555
1038
        """A helper for tests to do a ui-less merge.
556
1039
 
562
1045
        base_rev = common_ancestor(branch_from.last_revision(),
563
1046
                                   wt_to.branch.last_revision(),
564
1047
                                   wt_to.branch.repository)
565
 
        merge_inner(wt_to.branch, branch_from.basis_tree(), 
 
1048
        merge_inner(wt_to.branch, branch_from.basis_tree(),
566
1049
                    wt_to.branch.repository.revision_tree(base_rev),
567
1050
                    this_tree=wt_to)
568
 
        wt_to.add_pending_merge(branch_from.last_revision())
 
1051
        wt_to.add_parent_tree_id(branch_from.last_revision())
569
1052
 
570
1053
 
571
1054
BzrTestBase = TestCase
636
1119
                i = i + 1
637
1120
                continue
638
1121
            else:
639
 
                self.test_dir = candidate_dir
 
1122
                os.mkdir(candidate_dir)
 
1123
                self.test_home_dir = candidate_dir + '/home'
 
1124
                os.mkdir(self.test_home_dir)
 
1125
                self.test_dir = candidate_dir + '/work'
640
1126
                os.mkdir(self.test_dir)
641
1127
                os.chdir(self.test_dir)
642
1128
                break
643
 
        os.environ['HOME'] = self.test_dir
644
 
        os.environ['APPDATA'] = self.test_dir
 
1129
        os.environ['HOME'] = self.test_home_dir
 
1130
        os.environ['APPDATA'] = self.test_home_dir
645
1131
        def _leaveDirectory():
646
1132
            os.chdir(_currentdir)
647
1133
        self.addCleanup(_leaveDirectory)
652
1138
        shape is a sequence of file specifications.  If the final
653
1139
        character is '/', a directory is created.
654
1140
 
 
1141
        This assumes that all the elements in the tree being built are new.
 
1142
 
655
1143
        This doesn't add anything to a branch.
656
1144
        :param line_endings: Either 'binary' or 'native'
657
1145
                             in binary mode, exact contents are written
662
1150
                          VFS's. If the transport is readonly or None,
663
1151
                          "." is opened automatically.
664
1152
        """
665
 
        # XXX: It's OK to just create them using forward slashes on windows?
 
1153
        # It's OK to just create them using forward slashes on windows.
666
1154
        if transport is None or transport.is_readonly():
667
1155
            transport = get_transport(".")
668
1156
        for name in shape:
669
1157
            self.assert_(isinstance(name, basestring))
670
1158
            if name[-1] == '/':
671
 
                transport.mkdir(urlescape(name[:-1]))
 
1159
                transport.mkdir(urlutils.escape(name[:-1]))
672
1160
            else:
673
1161
                if line_endings == 'binary':
674
1162
                    end = '\n'
676
1164
                    end = os.linesep
677
1165
                else:
678
1166
                    raise errors.BzrError('Invalid line ending request %r' % (line_endings,))
679
 
                content = "contents of %s%s" % (name, end)
680
 
                transport.put(urlescape(name), StringIO(content))
 
1167
                content = "contents of %s%s" % (name.encode('utf-8'), end)
 
1168
                # Technically 'put()' is the right command. However, put
 
1169
                # uses an AtomicFile, which requires an extra rename into place
 
1170
                # As long as the files didn't exist in the past, append() will
 
1171
                # do the same thing as put()
 
1172
                # On jam's machine, make_kernel_like_tree is:
 
1173
                #   put:    4.5-7.5s (averaging 6s)
 
1174
                #   append: 2.9-4.5s
 
1175
                #   put_non_atomic: 2.9-4.5s
 
1176
                transport.put_bytes_non_atomic(urlutils.escape(name), content)
681
1177
 
682
1178
    def build_tree_contents(self, shape):
683
1179
        build_tree_contents(shape)
693
1189
    def assertFileEqual(self, content, path):
694
1190
        """Fail if path does not contain 'content'."""
695
1191
        self.failUnless(osutils.lexists(path))
 
1192
        # TODO: jam 20060427 Shouldn't this be 'rb'?
696
1193
        self.assertEqualDiff(content, open(path, 'r').read())
697
1194
 
698
1195
 
763
1260
        return self.__server
764
1261
 
765
1262
    def get_url(self, relpath=None):
766
 
        """Get a URL for the readwrite transport.
 
1263
        """Get a URL (or maybe a path) for the readwrite transport.
767
1264
 
768
1265
        This will either be backed by '.' or to an equivalent non-file based
769
1266
        facility.
774
1271
        if relpath is not None and relpath != '.':
775
1272
            if not base.endswith('/'):
776
1273
                base = base + '/'
777
 
            base = base + relpath
 
1274
            # XXX: Really base should be a url; we did after all call
 
1275
            # get_url()!  But sometimes it's just a path (from
 
1276
            # LocalAbspathServer), and it'd be wrong to append urlescaped data
 
1277
            # to a non-escaped local path.
 
1278
            if base.startswith('./') or base.startswith('/'):
 
1279
                base += relpath
 
1280
            else:
 
1281
                base += urlutils.escape(relpath)
778
1282
        return base
779
1283
 
780
1284
    def get_transport(self):
793
1297
        self.assertTrue(t.is_readonly())
794
1298
        return t
795
1299
 
796
 
    def make_branch(self, relpath):
 
1300
    def make_branch(self, relpath, format=None):
797
1301
        """Create a branch on the transport at relpath."""
798
 
        repo = self.make_repository(relpath)
 
1302
        repo = self.make_repository(relpath, format=format)
799
1303
        return repo.bzrdir.create_branch()
800
1304
 
801
 
    def make_bzrdir(self, relpath):
 
1305
    def make_bzrdir(self, relpath, format=None):
802
1306
        try:
803
 
            url = self.get_url(relpath)
804
 
            segments = relpath.split('/')
805
 
            if segments and segments[-1] not in ('', '.'):
806
 
                parent = self.get_url('/'.join(segments[:-1]))
807
 
                t = get_transport(parent)
 
1307
            # might be a relative or absolute path
 
1308
            maybe_a_url = self.get_url(relpath)
 
1309
            segments = maybe_a_url.rsplit('/', 1)
 
1310
            t = get_transport(maybe_a_url)
 
1311
            if len(segments) > 1 and segments[-1] not in ('', '.'):
808
1312
                try:
809
 
                    t.mkdir(segments[-1])
 
1313
                    t.mkdir('.')
810
1314
                except errors.FileExists:
811
1315
                    pass
812
 
            return bzrlib.bzrdir.BzrDir.create(url)
 
1316
            if format is None:
 
1317
                format = bzrlib.bzrdir.BzrDirFormat.get_default_format()
 
1318
            return format.initialize_on_transport(t)
813
1319
        except errors.UninitializableFormat:
814
 
            raise TestSkipped("Format %s is not initializable.")
 
1320
            raise TestSkipped("Format %s is not initializable." % format)
815
1321
 
816
 
    def make_repository(self, relpath, shared=False):
 
1322
    def make_repository(self, relpath, shared=False, format=None):
817
1323
        """Create a repository on our default transport at relpath."""
818
 
        made_control = self.make_bzrdir(relpath)
 
1324
        made_control = self.make_bzrdir(relpath, format=format)
819
1325
        return made_control.create_repository(shared=shared)
820
1326
 
821
 
    def make_branch_and_tree(self, relpath):
 
1327
    def make_branch_and_memory_tree(self, relpath):
 
1328
        """Create a branch on the default transport and a MemoryTree for it."""
 
1329
        b = self.make_branch(relpath)
 
1330
        return memorytree.MemoryTree.create_on_branch(b)
 
1331
 
 
1332
    def make_branch_and_tree(self, relpath, format=None):
822
1333
        """Create a branch on the transport and a tree locally.
823
1334
 
824
 
        Returns the tree.
 
1335
        If the transport is not a LocalTransport, the Tree can't be created on
 
1336
        the transport.  In that case the working tree is created in the local
 
1337
        directory, and the returned tree's branch and repository will also be
 
1338
        accessed locally.
 
1339
 
 
1340
        This will fail if the original default transport for this test
 
1341
        case wasn't backed by the working directory, as the branch won't
 
1342
        be on disk for us to open it.  
 
1343
 
 
1344
        :param format: The BzrDirFormat.
 
1345
        :returns: the WorkingTree.
825
1346
        """
826
1347
        # TODO: always use the local disk path for the working tree,
827
1348
        # this obviously requires a format that supports branch references
828
1349
        # so check for that by checking bzrdir.BzrDirFormat.get_default_format()
829
1350
        # RBC 20060208
830
 
        b = self.make_branch(relpath)
 
1351
        b = self.make_branch(relpath, format=format)
831
1352
        try:
832
1353
            return b.bzrdir.create_workingtree()
833
1354
        except errors.NotLocalUrl:
834
 
            # new formats - catch No tree error and create
835
 
            # a branch reference and a checkout.
836
 
            # old formats at that point - raise TestSkipped.
837
 
            # TODO: rbc 20060208
838
 
            return WorkingTreeFormat2().initialize(bzrdir.BzrDir.open(relpath))
 
1355
            # We can only make working trees locally at the moment.  If the
 
1356
            # transport can't support them, then reopen the branch on a local
 
1357
            # transport, and create the working tree there.  
 
1358
            #
 
1359
            # Possibly we should instead keep
 
1360
            # the non-disk-backed branch and create a local checkout?
 
1361
            bd = bzrdir.BzrDir.open(relpath)
 
1362
            return bd.create_workingtree()
839
1363
 
840
1364
    def assertIsDirectory(self, relpath, transport):
841
1365
        """Assert that relpath within transport is a directory.
872
1396
 
873
1397
 
874
1398
def filter_suite_by_re(suite, pattern):
875
 
    result = TestSuite()
 
1399
    result = TestUtil.TestSuite()
876
1400
    filter_re = re.compile(pattern)
877
1401
    for test in iter_suite_tests(suite):
878
1402
        if filter_re.search(test.id()):
882
1406
 
883
1407
def run_suite(suite, name='test', verbose=False, pattern=".*",
884
1408
              stop_on_failure=False, keep_output=False,
885
 
              transport=None):
 
1409
              transport=None, lsprof_timed=None, bench_history=None):
886
1410
    TestCaseInTempDir._TEST_NAME = name
 
1411
    TestCase._gather_lsprof_in_benchmarks = lsprof_timed
887
1412
    if verbose:
888
1413
        verbosity = 2
 
1414
        pb = None
889
1415
    else:
890
1416
        verbosity = 1
 
1417
        pb = progress.ProgressBar()
891
1418
    runner = TextTestRunner(stream=sys.stdout,
892
1419
                            descriptions=0,
893
 
                            verbosity=verbosity)
 
1420
                            verbosity=verbosity,
 
1421
                            keep_output=keep_output,
 
1422
                            pb=pb,
 
1423
                            bench_history=bench_history)
894
1424
    runner.stop_on_failure=stop_on_failure
895
1425
    if pattern != '.*':
896
1426
        suite = filter_suite_by_re(suite, pattern)
897
1427
    result = runner.run(suite)
898
 
    # This is still a little bogus, 
899
 
    # but only a little. Folk not using our testrunner will
900
 
    # have to delete their temp directories themselves.
901
 
    test_root = TestCaseInTempDir.TEST_ROOT
902
 
    if result.wasSuccessful() or not keep_output:
903
 
        if test_root is not None:
904
 
            print 'Deleting test root %s...' % test_root
905
 
            try:
906
 
                shutil.rmtree(test_root)
907
 
            finally:
908
 
                print
909
 
    else:
910
 
        print "Failed tests working directories are in '%s'\n" % TestCaseInTempDir.TEST_ROOT
911
1428
    return result.wasSuccessful()
912
1429
 
913
1430
 
914
1431
def selftest(verbose=False, pattern=".*", stop_on_failure=True,
915
1432
             keep_output=False,
916
 
             transport=None):
 
1433
             transport=None,
 
1434
             test_suite_factory=None,
 
1435
             lsprof_timed=None,
 
1436
             bench_history=None):
917
1437
    """Run the whole test suite under the enhanced runner"""
 
1438
    # XXX: Very ugly way to do this...
 
1439
    # Disable warning about old formats because we don't want it to disturb
 
1440
    # any blackbox tests.
 
1441
    from bzrlib import repository
 
1442
    repository._deprecation_warning_done = True
 
1443
 
918
1444
    global default_transport
919
1445
    if transport is None:
920
1446
        transport = default_transport
921
1447
    old_transport = default_transport
922
1448
    default_transport = transport
923
 
    suite = test_suite()
924
1449
    try:
 
1450
        if test_suite_factory is None:
 
1451
            suite = test_suite()
 
1452
        else:
 
1453
            suite = test_suite_factory()
925
1454
        return run_suite(suite, 'testbzr', verbose=verbose, pattern=pattern,
926
1455
                     stop_on_failure=stop_on_failure, keep_output=keep_output,
927
 
                     transport=transport)
 
1456
                     transport=transport,
 
1457
                     lsprof_timed=lsprof_timed,
 
1458
                     bench_history=bench_history)
928
1459
    finally:
929
1460
        default_transport = old_transport
930
1461
 
931
1462
 
932
 
 
933
1463
def test_suite():
934
 
    """Build and return TestSuite for the whole program."""
935
 
    from doctest import DocTestSuite
936
 
 
937
 
    global MODULES_TO_DOCTEST
938
 
 
939
 
    testmod_names = [ \
 
1464
    """Build and return TestSuite for the whole of bzrlib.
 
1465
    
 
1466
    This function can be replaced if you need to change the default test
 
1467
    suite on a global basis, but it is not encouraged.
 
1468
    """
 
1469
    testmod_names = [
940
1470
                   'bzrlib.tests.test_ancestry',
941
 
                   'bzrlib.tests.test_annotate',
942
1471
                   'bzrlib.tests.test_api',
 
1472
                   'bzrlib.tests.test_atomicfile',
943
1473
                   'bzrlib.tests.test_bad_files',
944
 
                   'bzrlib.tests.test_basis_inventory',
945
1474
                   'bzrlib.tests.test_branch',
 
1475
                   'bzrlib.tests.test_bundle',
946
1476
                   'bzrlib.tests.test_bzrdir',
 
1477
                   'bzrlib.tests.test_cache_utf8',
947
1478
                   'bzrlib.tests.test_command',
948
1479
                   'bzrlib.tests.test_commit',
949
1480
                   'bzrlib.tests.test_commit_merge',
955
1486
                   'bzrlib.tests.test_errors',
956
1487
                   'bzrlib.tests.test_escaped_store',
957
1488
                   'bzrlib.tests.test_fetch',
 
1489
                   'bzrlib.tests.test_ftp_transport',
958
1490
                   'bzrlib.tests.test_gpg',
959
1491
                   'bzrlib.tests.test_graph',
960
1492
                   'bzrlib.tests.test_hashcache',
961
1493
                   'bzrlib.tests.test_http',
 
1494
                   'bzrlib.tests.test_http_response',
962
1495
                   'bzrlib.tests.test_identitymap',
 
1496
                   'bzrlib.tests.test_ignores',
963
1497
                   'bzrlib.tests.test_inv',
964
1498
                   'bzrlib.tests.test_knit',
 
1499
                   'bzrlib.tests.test_lazy_import',
965
1500
                   'bzrlib.tests.test_lockdir',
966
1501
                   'bzrlib.tests.test_lockable_files',
967
1502
                   'bzrlib.tests.test_log',
 
1503
                   'bzrlib.tests.test_memorytree',
968
1504
                   'bzrlib.tests.test_merge',
969
1505
                   'bzrlib.tests.test_merge3',
970
1506
                   'bzrlib.tests.test_merge_core',
973
1509
                   'bzrlib.tests.test_nonascii',
974
1510
                   'bzrlib.tests.test_options',
975
1511
                   'bzrlib.tests.test_osutils',
 
1512
                   'bzrlib.tests.test_patch',
 
1513
                   'bzrlib.tests.test_patches',
976
1514
                   'bzrlib.tests.test_permissions',
977
1515
                   'bzrlib.tests.test_plugins',
978
1516
                   'bzrlib.tests.test_progress',
979
1517
                   'bzrlib.tests.test_reconcile',
980
1518
                   'bzrlib.tests.test_repository',
 
1519
                   'bzrlib.tests.test_revert',
981
1520
                   'bzrlib.tests.test_revision',
982
1521
                   'bzrlib.tests.test_revisionnamespaces',
983
 
                   'bzrlib.tests.test_revprops',
 
1522
                   'bzrlib.tests.test_revisiontree',
984
1523
                   'bzrlib.tests.test_rio',
985
1524
                   'bzrlib.tests.test_sampler',
986
1525
                   'bzrlib.tests.test_selftest',
987
1526
                   'bzrlib.tests.test_setup',
988
1527
                   'bzrlib.tests.test_sftp_transport',
989
1528
                   'bzrlib.tests.test_smart_add',
 
1529
                   'bzrlib.tests.test_smart_transport',
990
1530
                   'bzrlib.tests.test_source',
 
1531
                   'bzrlib.tests.test_status',
991
1532
                   'bzrlib.tests.test_store',
992
1533
                   'bzrlib.tests.test_symbol_versioning',
993
1534
                   'bzrlib.tests.test_testament',
 
1535
                   'bzrlib.tests.test_textfile',
 
1536
                   'bzrlib.tests.test_textmerge',
994
1537
                   'bzrlib.tests.test_trace',
995
1538
                   'bzrlib.tests.test_transactions',
996
1539
                   'bzrlib.tests.test_transform',
997
1540
                   'bzrlib.tests.test_transport',
 
1541
                   'bzrlib.tests.test_tree',
 
1542
                   'bzrlib.tests.test_treebuilder',
998
1543
                   'bzrlib.tests.test_tsort',
 
1544
                   'bzrlib.tests.test_tuned_gzip',
999
1545
                   'bzrlib.tests.test_ui',
1000
1546
                   'bzrlib.tests.test_upgrade',
 
1547
                   'bzrlib.tests.test_urlutils',
1001
1548
                   'bzrlib.tests.test_versionedfile',
 
1549
                   'bzrlib.tests.test_version',
1002
1550
                   'bzrlib.tests.test_weave',
1003
1551
                   'bzrlib.tests.test_whitebox',
1004
1552
                   'bzrlib.tests.test_workingtree',
1005
1553
                   'bzrlib.tests.test_xml',
1006
1554
                   ]
1007
1555
    test_transport_implementations = [
1008
 
        'bzrlib.tests.test_transport_implementations']
1009
 
 
1010
 
    TestCase.BZRPATH = osutils.pathjoin(
1011
 
            osutils.realpath(osutils.dirname(bzrlib.__path__[0])), 'bzr')
1012
 
    print '%10s: %s' % ('bzr', osutils.realpath(sys.argv[0]))
1013
 
    print '%10s: %s' % ('bzrlib', bzrlib.__path__[0])
1014
 
    print
1015
 
    suite = TestSuite()
1016
 
    # python2.4's TestLoader.loadTestsFromNames gives very poor 
1017
 
    # errors if it fails to load a named module - no indication of what's
1018
 
    # actually wrong, just "no such module".  We should probably override that
1019
 
    # class, but for the moment just load them ourselves. (mbp 20051202)
1020
 
    loader = TestLoader()
 
1556
        'bzrlib.tests.test_transport_implementations',
 
1557
        'bzrlib.tests.test_read_bundle',
 
1558
        ]
 
1559
    suite = TestUtil.TestSuite()
 
1560
    loader = TestUtil.TestLoader()
 
1561
    suite.addTest(loader.loadTestsFromModuleNames(testmod_names))
1021
1562
    from bzrlib.transport import TransportTestProviderAdapter
1022
1563
    adapter = TransportTestProviderAdapter()
1023
1564
    adapt_modules(test_transport_implementations, adapter, loader, suite)
1024
 
    for mod_name in testmod_names:
1025
 
        mod = _load_module_by_name(mod_name)
1026
 
        suite.addTest(loader.loadTestsFromModule(mod))
1027
1565
    for package in packages_to_test():
1028
1566
        suite.addTest(package.test_suite())
1029
1567
    for m in MODULES_TO_TEST:
1030
1568
        suite.addTest(loader.loadTestsFromModule(m))
1031
 
    for m in (MODULES_TO_DOCTEST):
1032
 
        suite.addTest(DocTestSuite(m))
 
1569
    for m in MODULES_TO_DOCTEST:
 
1570
        suite.addTest(doctest.DocTestSuite(m))
1033
1571
    for name, plugin in bzrlib.plugin.all_plugins().items():
1034
1572
        if getattr(plugin, 'test_suite', None) is not None:
1035
1573
            suite.addTest(plugin.test_suite())
1038
1576
 
1039
1577
def adapt_modules(mods_list, adapter, loader, suite):
1040
1578
    """Adapt the modules in mods_list using adapter and add to suite."""
1041
 
    for mod_name in mods_list:
1042
 
        mod = _load_module_by_name(mod_name)
1043
 
        for test in iter_suite_tests(loader.loadTestsFromModule(mod)):
1044
 
            suite.addTests(adapter.adapt(test))
1045
 
 
1046
 
 
1047
 
def _load_module_by_name(mod_name):
1048
 
    parts = mod_name.split('.')
1049
 
    module = __import__(mod_name)
1050
 
    del parts[0]
1051
 
    # for historical reasons python returns the top-level module even though
1052
 
    # it loads the submodule; we need to walk down to get the one we want.
1053
 
    while parts:
1054
 
        module = getattr(module, parts.pop(0))
1055
 
    return module
 
1579
    for test in iter_suite_tests(loader.loadTestsFromModuleNames(mods_list)):
 
1580
        suite.addTests(adapter.adapt(test))