/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

(Andrew Bennetts, Robert Collins) Create a new test helper start_bzr_subprocess which is paired with finish_bzr_subprocess, allowing tests that need to interact with the upcoming bzr serve command.

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