~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/__init__.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2006-05-23 11:06:22 UTC
  • mfrom: (1704.2.28 bzr.mbp.integration)
  • Revision ID: pqm@pqm.ubuntu.com-20060523110622-5ad5c2bf9dee4fc5
(mbp) use bisect to find revisions by date

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005 by Canonical Ltd
 
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
15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
16
 
17
17
 
 
18
# TODO: Perhaps there should be an API to find out if bzr running under the
 
19
# test suite -- some plugins might want to avoid making intrusive changes if
 
20
# this is the case.  However, we want behaviour under to test to diverge as
 
21
# little as possible, so this should be used rarely if it's added at all.
 
22
# (Suggestion from j-a-meinel, 2005-11-24)
 
23
 
 
24
# NOTE: Some classes in here use camelCaseNaming() rather than
 
25
# underscore_naming().  That's for consistency with unittest; it's not the
 
26
# general style of bzrlib.  Please continue that consistency when adding e.g.
 
27
# new assertFoo() methods.
 
28
 
 
29
import codecs
 
30
from cStringIO import StringIO
 
31
import difflib
 
32
import errno
18
33
import logging
19
 
import unittest
20
 
import tempfile
21
34
import os
 
35
import re
 
36
import stat
22
37
import sys
23
 
import errno
24
 
import subprocess
25
 
import shutil
26
 
 
27
 
import testsweet
 
38
import tempfile
 
39
import unittest
 
40
import time
 
41
 
 
42
 
 
43
import bzrlib.branch
 
44
import bzrlib.bzrdir as bzrdir
28
45
import bzrlib.commands
29
 
 
 
46
import bzrlib.errors as errors
 
47
import bzrlib.inventory
 
48
import bzrlib.iterablefile
 
49
import bzrlib.lockdir
 
50
from bzrlib.merge import merge_inner
 
51
import bzrlib.merge3
 
52
import bzrlib.osutils
 
53
import bzrlib.osutils as osutils
 
54
import bzrlib.plugin
 
55
import bzrlib.progress as progress
 
56
from bzrlib.revision import common_ancestor
 
57
import bzrlib.store
30
58
import bzrlib.trace
31
 
import bzrlib.fetch
 
59
from bzrlib.transport import urlescape, get_transport
 
60
import bzrlib.transport
 
61
from bzrlib.transport.local import LocalRelpathServer
 
62
from bzrlib.transport.readonly import ReadonlyServer
 
63
from bzrlib.trace import mutter
 
64
from bzrlib.tests.TestUtil import TestLoader, TestSuite
 
65
from bzrlib.tests.treeshape import build_tree_contents
 
66
from bzrlib.workingtree import WorkingTree, WorkingTreeFormat2
32
67
 
 
68
default_transport = LocalRelpathServer
33
69
 
34
70
MODULES_TO_TEST = []
35
 
MODULES_TO_DOCTEST = []
36
 
 
37
 
from logging import debug, warning, error
 
71
MODULES_TO_DOCTEST = [
 
72
                      bzrlib.branch,
 
73
                      bzrlib.commands,
 
74
                      bzrlib.errors,
 
75
                      bzrlib.inventory,
 
76
                      bzrlib.iterablefile,
 
77
                      bzrlib.lockdir,
 
78
                      bzrlib.merge3,
 
79
                      bzrlib.option,
 
80
                      bzrlib.osutils,
 
81
                      bzrlib.store
 
82
                      ]
 
83
def packages_to_test():
 
84
    """Return a list of packages to test.
 
85
 
 
86
    The packages are not globally imported so that import failures are
 
87
    triggered when running selftest, not when importing the command.
 
88
    """
 
89
    import bzrlib.doc
 
90
    import bzrlib.tests.blackbox
 
91
    import bzrlib.tests.branch_implementations
 
92
    import bzrlib.tests.bzrdir_implementations
 
93
    import bzrlib.tests.interrepository_implementations
 
94
    import bzrlib.tests.interversionedfile_implementations
 
95
    import bzrlib.tests.repository_implementations
 
96
    import bzrlib.tests.revisionstore_implementations
 
97
    import bzrlib.tests.workingtree_implementations
 
98
    return [
 
99
            bzrlib.doc,
 
100
            bzrlib.tests.blackbox,
 
101
            bzrlib.tests.branch_implementations,
 
102
            bzrlib.tests.bzrdir_implementations,
 
103
            bzrlib.tests.interrepository_implementations,
 
104
            bzrlib.tests.interversionedfile_implementations,
 
105
            bzrlib.tests.repository_implementations,
 
106
            bzrlib.tests.revisionstore_implementations,
 
107
            bzrlib.tests.workingtree_implementations,
 
108
            ]
 
109
 
 
110
 
 
111
class _MyResult(unittest._TextTestResult):
 
112
    """Custom TestResult.
 
113
 
 
114
    Shows output in a different format, including displaying runtime for tests.
 
115
    """
 
116
    stop_early = False
 
117
    
 
118
    def __init__(self, stream, descriptions, verbosity, pb=None):
 
119
        unittest._TextTestResult.__init__(self, stream, descriptions, verbosity)
 
120
        self.pb = pb
 
121
    
 
122
    def extractBenchmarkTime(self, testCase):
 
123
        """Add a benchmark time for the current test case."""
 
124
        self._benchmarkTime = getattr(testCase, "_benchtime", None)
 
125
    
 
126
    def _elapsedTestTimeString(self):
 
127
        """Return a time string for the overall time the current test has taken."""
 
128
        return self._formatTime(time.time() - self._start_time)
 
129
 
 
130
    def _testTimeString(self):
 
131
        if self._benchmarkTime is not None:
 
132
            return "%s/%s" % (
 
133
                self._formatTime(self._benchmarkTime),
 
134
                self._elapsedTestTimeString())
 
135
        else:
 
136
            return "      %s" % self._elapsedTestTimeString()
 
137
 
 
138
    def _formatTime(self, seconds):
 
139
        """Format seconds as milliseconds with leading spaces."""
 
140
        return "%5dms" % (1000 * seconds)
 
141
 
 
142
    def _ellipsise_unimportant_words(self, a_string, final_width,
 
143
                                   keep_start=False):
 
144
        """Add ellipses (sp?) for overly long strings.
 
145
        
 
146
        :param keep_start: If true preserve the start of a_string rather
 
147
                           than the end of it.
 
148
        """
 
149
        if keep_start:
 
150
            if len(a_string) > final_width:
 
151
                result = a_string[:final_width-3] + '...'
 
152
            else:
 
153
                result = a_string
 
154
        else:
 
155
            if len(a_string) > final_width:
 
156
                result = '...' + a_string[3-final_width:]
 
157
            else:
 
158
                result = a_string
 
159
        return result.ljust(final_width)
 
160
 
 
161
    def startTest(self, test):
 
162
        unittest.TestResult.startTest(self, test)
 
163
        # In a short description, the important words are in
 
164
        # the beginning, but in an id, the important words are
 
165
        # at the end
 
166
        SHOW_DESCRIPTIONS = False
 
167
 
 
168
        if not self.showAll and self.dots and self.pb is not None:
 
169
            final_width = 13
 
170
        else:
 
171
            final_width = osutils.terminal_width()
 
172
            final_width = final_width - 15 - 8
 
173
        what = None
 
174
        if SHOW_DESCRIPTIONS:
 
175
            what = test.shortDescription()
 
176
            if what:
 
177
                what = self._ellipsise_unimportant_words(what, final_width, keep_start=True)
 
178
        if what is None:
 
179
            what = test.id()
 
180
            if what.startswith('bzrlib.tests.'):
 
181
                what = what[13:]
 
182
            what = self._ellipsise_unimportant_words(what, final_width)
 
183
        if self.showAll:
 
184
            self.stream.write(what)
 
185
        elif self.dots and self.pb is not None:
 
186
            self.pb.update(what, self.testsRun - 1, None)
 
187
        self.stream.flush()
 
188
        self._recordTestStartTime()
 
189
 
 
190
    def _recordTestStartTime(self):
 
191
        """Record that a test has started."""
 
192
        self._start_time = time.time()
 
193
 
 
194
    def addError(self, test, err):
 
195
        if isinstance(err[1], TestSkipped):
 
196
            return self.addSkipped(test, err)    
 
197
        unittest.TestResult.addError(self, test, err)
 
198
        self.extractBenchmarkTime(test)
 
199
        if self.showAll:
 
200
            self.stream.writeln("ERROR %s" % self._testTimeString())
 
201
        elif self.dots and self.pb is None:
 
202
            self.stream.write('E')
 
203
        elif self.dots:
 
204
            self.pb.update(self._ellipsise_unimportant_words('ERROR', 13), self.testsRun, None)
 
205
        self.stream.flush()
 
206
        if self.stop_early:
 
207
            self.stop()
 
208
 
 
209
    def addFailure(self, test, err):
 
210
        unittest.TestResult.addFailure(self, test, err)
 
211
        self.extractBenchmarkTime(test)
 
212
        if self.showAll:
 
213
            self.stream.writeln(" FAIL %s" % self._testTimeString())
 
214
        elif self.dots and self.pb is None:
 
215
            self.stream.write('F')
 
216
        elif self.dots:
 
217
            self.pb.update(self._ellipsise_unimportant_words('FAIL', 13), self.testsRun, None)
 
218
        self.stream.flush()
 
219
        if self.stop_early:
 
220
            self.stop()
 
221
 
 
222
    def addSuccess(self, test):
 
223
        self.extractBenchmarkTime(test)
 
224
        if self.showAll:
 
225
            self.stream.writeln('   OK %s' % self._testTimeString())
 
226
        elif self.dots and self.pb is None:
 
227
            self.stream.write('~')
 
228
        elif self.dots:
 
229
            self.pb.update(self._ellipsise_unimportant_words('OK', 13), self.testsRun, None)
 
230
        self.stream.flush()
 
231
        unittest.TestResult.addSuccess(self, test)
 
232
 
 
233
    def addSkipped(self, test, skip_excinfo):
 
234
        self.extractBenchmarkTime(test)
 
235
        if self.showAll:
 
236
            print >>self.stream, ' SKIP %s' % self._testTimeString()
 
237
            print >>self.stream, '     %s' % skip_excinfo[1]
 
238
        elif self.dots and self.pb is None:
 
239
            self.stream.write('S')
 
240
        elif self.dots:
 
241
            self.pb.update(self._ellipsise_unimportant_words('SKIP', 13), self.testsRun, None)
 
242
        self.stream.flush()
 
243
        # seems best to treat this as success from point-of-view of unittest
 
244
        # -- it actually does nothing so it barely matters :)
 
245
        unittest.TestResult.addSuccess(self, test)
 
246
 
 
247
    def printErrorList(self, flavour, errors):
 
248
        for test, err in errors:
 
249
            self.stream.writeln(self.separator1)
 
250
            self.stream.writeln("%s: %s" % (flavour, self.getDescription(test)))
 
251
            if getattr(test, '_get_log', None) is not None:
 
252
                print >>self.stream
 
253
                print >>self.stream, \
 
254
                        ('vvvv[log from %s]' % test.id()).ljust(78,'-')
 
255
                print >>self.stream, test._get_log()
 
256
                print >>self.stream, \
 
257
                        ('^^^^[log from %s]' % test.id()).ljust(78,'-')
 
258
            self.stream.writeln(self.separator2)
 
259
            self.stream.writeln("%s" % err)
 
260
 
 
261
 
 
262
class TextTestRunner(object):
 
263
    stop_on_failure = False
 
264
 
 
265
    def __init__(self,
 
266
                 stream=sys.stderr,
 
267
                 descriptions=0,
 
268
                 verbosity=1,
 
269
                 keep_output=False,
 
270
                 pb=None):
 
271
        self.stream = unittest._WritelnDecorator(stream)
 
272
        self.descriptions = descriptions
 
273
        self.verbosity = verbosity
 
274
        self.keep_output = keep_output
 
275
        self.pb = pb
 
276
 
 
277
    def _makeResult(self):
 
278
        result = _MyResult(self.stream,
 
279
                           self.descriptions,
 
280
                           self.verbosity,
 
281
                           pb=self.pb)
 
282
        result.stop_early = self.stop_on_failure
 
283
        return result
 
284
 
 
285
    def run(self, test):
 
286
        "Run the given test case or test suite."
 
287
        result = self._makeResult()
 
288
        startTime = time.time()
 
289
        if self.pb is not None:
 
290
            self.pb.update('Running tests', 0, test.countTestCases())
 
291
        test.run(result)
 
292
        stopTime = time.time()
 
293
        timeTaken = stopTime - startTime
 
294
        result.printErrors()
 
295
        self.stream.writeln(result.separator2)
 
296
        run = result.testsRun
 
297
        self.stream.writeln("Ran %d test%s in %.3fs" %
 
298
                            (run, run != 1 and "s" or "", timeTaken))
 
299
        self.stream.writeln()
 
300
        if not result.wasSuccessful():
 
301
            self.stream.write("FAILED (")
 
302
            failed, errored = map(len, (result.failures, result.errors))
 
303
            if failed:
 
304
                self.stream.write("failures=%d" % failed)
 
305
            if errored:
 
306
                if failed: self.stream.write(", ")
 
307
                self.stream.write("errors=%d" % errored)
 
308
            self.stream.writeln(")")
 
309
        else:
 
310
            self.stream.writeln("OK")
 
311
        if self.pb is not None:
 
312
            self.pb.update('Cleaning up', 0, 1)
 
313
        # This is still a little bogus, 
 
314
        # but only a little. Folk not using our testrunner will
 
315
        # have to delete their temp directories themselves.
 
316
        test_root = TestCaseInTempDir.TEST_ROOT
 
317
        if result.wasSuccessful() or not self.keep_output:
 
318
            if test_root is not None:
 
319
                    osutils.rmtree(test_root)
 
320
        else:
 
321
            if self.pb is not None:
 
322
                self.pb.note("Failed tests working directories are in '%s'\n",
 
323
                             test_root)
 
324
            else:
 
325
                self.stream.writeln(
 
326
                    "Failed tests working directories are in '%s'\n" %
 
327
                    test_root)
 
328
        TestCaseInTempDir.TEST_ROOT = None
 
329
        if self.pb is not None:
 
330
            self.pb.clear()
 
331
        return result
 
332
 
 
333
 
 
334
def iter_suite_tests(suite):
 
335
    """Return all tests in a suite, recursing through nested suites"""
 
336
    for item in suite._tests:
 
337
        if isinstance(item, unittest.TestCase):
 
338
            yield item
 
339
        elif isinstance(item, unittest.TestSuite):
 
340
            for r in iter_suite_tests(item):
 
341
                yield r
 
342
        else:
 
343
            raise Exception('unknown object %r inside test suite %r'
 
344
                            % (item, suite))
 
345
 
 
346
 
 
347
class TestSkipped(Exception):
 
348
    """Indicates that a test was intentionally skipped, rather than failing."""
 
349
    # XXX: Not used yet
 
350
 
38
351
 
39
352
class CommandFailed(Exception):
40
353
    pass
47
360
 
48
361
    Error and debug log messages are redirected from their usual
49
362
    location into a temporary file, the contents of which can be
50
 
    retrieved by _get_log().
 
363
    retrieved by _get_log().  We use a real OS file, not an in-memory object,
 
364
    so that it can also capture file IO.  When the test completes this file
 
365
    is read into memory and removed from disk.
51
366
       
52
367
    There are also convenience functions to invoke bzr's command-line
53
 
    routine, and to build and check bzr trees."""
54
 
 
55
 
    BZRPATH = 'bzr'
 
368
    routine, and to build and check bzr trees.
 
369
   
 
370
    In addition to the usual method of overriding tearDown(), this class also
 
371
    allows subclasses to register functions into the _cleanups list, which is
 
372
    run in order as the object is torn down.  It's less likely this will be
 
373
    accidentally overlooked.
 
374
    """
 
375
 
 
376
    _log_file_name = None
 
377
    _log_contents = ''
 
378
 
 
379
    def __init__(self, methodName='testMethod'):
 
380
        super(TestCase, self).__init__(methodName)
 
381
        self._cleanups = []
56
382
 
57
383
    def setUp(self):
58
 
        # this replaces the default testsweet.TestCase; we don't want logging changed
59
384
        unittest.TestCase.setUp(self)
 
385
        self._cleanEnvironment()
60
386
        bzrlib.trace.disable_default_logging()
61
 
        self._enable_file_logging()
62
 
 
63
 
 
64
 
    def _enable_file_logging(self):
 
387
        self._startLogFile()
 
388
        self._benchtime = None
 
389
 
 
390
    def _ndiff_strings(self, a, b):
 
391
        """Return ndiff between two strings containing lines.
 
392
        
 
393
        A trailing newline is added if missing to make the strings
 
394
        print properly."""
 
395
        if b and b[-1] != '\n':
 
396
            b += '\n'
 
397
        if a and a[-1] != '\n':
 
398
            a += '\n'
 
399
        difflines = difflib.ndiff(a.splitlines(True),
 
400
                                  b.splitlines(True),
 
401
                                  linejunk=lambda x: False,
 
402
                                  charjunk=lambda x: False)
 
403
        return ''.join(difflines)
 
404
 
 
405
    def assertEqualDiff(self, a, b, message=None):
 
406
        """Assert two texts are equal, if not raise an exception.
 
407
        
 
408
        This is intended for use with multi-line strings where it can 
 
409
        be hard to find the differences by eye.
 
410
        """
 
411
        # TODO: perhaps override assertEquals to call this for strings?
 
412
        if a == b:
 
413
            return
 
414
        if message is None:
 
415
            message = "texts not equal:\n"
 
416
        raise AssertionError(message + 
 
417
                             self._ndiff_strings(a, b))      
 
418
        
 
419
    def assertEqualMode(self, mode, mode_test):
 
420
        self.assertEqual(mode, mode_test,
 
421
                         'mode mismatch %o != %o' % (mode, mode_test))
 
422
 
 
423
    def assertStartsWith(self, s, prefix):
 
424
        if not s.startswith(prefix):
 
425
            raise AssertionError('string %r does not start with %r' % (s, prefix))
 
426
 
 
427
    def assertEndsWith(self, s, suffix):
 
428
        """Asserts that s ends with suffix."""
 
429
        if not s.endswith(suffix):
 
430
            raise AssertionError('string %r does not end with %r' % (s, suffix))
 
431
 
 
432
    def assertContainsRe(self, haystack, needle_re):
 
433
        """Assert that a contains something matching a regular expression."""
 
434
        if not re.search(needle_re, haystack):
 
435
            raise AssertionError('pattern "%s" not found in "%s"'
 
436
                    % (needle_re, haystack))
 
437
 
 
438
    def assertSubset(self, sublist, superlist):
 
439
        """Assert that every entry in sublist is present in superlist."""
 
440
        missing = []
 
441
        for entry in sublist:
 
442
            if entry not in superlist:
 
443
                missing.append(entry)
 
444
        if len(missing) > 0:
 
445
            raise AssertionError("value(s) %r not present in container %r" % 
 
446
                                 (missing, superlist))
 
447
 
 
448
    def assertIs(self, left, right):
 
449
        if not (left is right):
 
450
            raise AssertionError("%r is not %r." % (left, right))
 
451
 
 
452
    def assertTransportMode(self, transport, path, mode):
 
453
        """Fail if a path does not have mode mode.
 
454
        
 
455
        If modes are not supported on this transport, the assertion is ignored.
 
456
        """
 
457
        if not transport._can_roundtrip_unix_modebits():
 
458
            return
 
459
        path_stat = transport.stat(path)
 
460
        actual_mode = stat.S_IMODE(path_stat.st_mode)
 
461
        self.assertEqual(mode, actual_mode,
 
462
            'mode of %r incorrect (%o != %o)' % (path, mode, actual_mode))
 
463
 
 
464
    def assertIsInstance(self, obj, kls):
 
465
        """Fail if obj is not an instance of kls"""
 
466
        if not isinstance(obj, kls):
 
467
            self.fail("%r is an instance of %s rather than %s" % (
 
468
                obj, obj.__class__, kls))
 
469
 
 
470
    def _startLogFile(self):
 
471
        """Send bzr and test log messages to a temporary file.
 
472
 
 
473
        The file is removed as the test is torn down.
 
474
        """
65
475
        fileno, name = tempfile.mkstemp(suffix='.log', prefix='testbzr')
66
 
 
67
 
        self._log_file = os.fdopen(fileno, 'w+')
68
 
 
69
 
        hdlr = logging.StreamHandler(self._log_file)
70
 
        hdlr.setLevel(logging.DEBUG)
71
 
        hdlr.setFormatter(logging.Formatter('%(levelname)8s  %(message)s'))
72
 
        logging.getLogger('').addHandler(hdlr)
73
 
        logging.getLogger('').setLevel(logging.DEBUG)
74
 
        self._log_hdlr = hdlr
75
 
        debug('opened log file %s', name)
76
 
        
 
476
        encoder, decoder, stream_reader, stream_writer = codecs.lookup('UTF-8')
 
477
        self._log_file = stream_writer(os.fdopen(fileno, 'w+'))
 
478
        self._log_nonce = bzrlib.trace.enable_test_log(self._log_file)
77
479
        self._log_file_name = name
78
 
 
79
 
        
80
 
    def tearDown(self):
81
 
        logging.getLogger('').removeHandler(self._log_hdlr)
82
 
        bzrlib.trace.enable_default_logging()
83
 
        logging.debug('%s teardown', self.id())
 
480
        self.addCleanup(self._finishLogFile)
 
481
 
 
482
    def _finishLogFile(self):
 
483
        """Finished with the log file.
 
484
 
 
485
        Read contents into memory, close, and delete.
 
486
        """
 
487
        bzrlib.trace.disable_test_log(self._log_nonce)
 
488
        self._log_file.seek(0)
 
489
        self._log_contents = self._log_file.read()
84
490
        self._log_file.close()
 
491
        os.remove(self._log_file_name)
 
492
        self._log_file = self._log_file_name = None
 
493
 
 
494
    def addCleanup(self, callable):
 
495
        """Arrange to run a callable when this case is torn down.
 
496
 
 
497
        Callables are run in the reverse of the order they are registered, 
 
498
        ie last-in first-out.
 
499
        """
 
500
        if callable in self._cleanups:
 
501
            raise ValueError("cleanup function %r already registered on %s" 
 
502
                    % (callable, self))
 
503
        self._cleanups.append(callable)
 
504
 
 
505
    def _cleanEnvironment(self):
 
506
        new_env = {
 
507
            'HOME': os.getcwd(),
 
508
            'APPDATA': os.getcwd(),
 
509
            'BZREMAIL': None,
 
510
            'EMAIL': None,
 
511
        }
 
512
        self.__old_env = {}
 
513
        self.addCleanup(self._restoreEnvironment)
 
514
        for name, value in new_env.iteritems():
 
515
            self._captureVar(name, value)
 
516
 
 
517
 
 
518
    def _captureVar(self, name, newvalue):
 
519
        """Set an environment variable, preparing it to be reset when finished."""
 
520
        self.__old_env[name] = os.environ.get(name, None)
 
521
        if newvalue is None:
 
522
            if name in os.environ:
 
523
                del os.environ[name]
 
524
        else:
 
525
            os.environ[name] = newvalue
 
526
 
 
527
    @staticmethod
 
528
    def _restoreVar(name, value):
 
529
        if value is None:
 
530
            if name in os.environ:
 
531
                del os.environ[name]
 
532
        else:
 
533
            os.environ[name] = value
 
534
 
 
535
    def _restoreEnvironment(self):
 
536
        for name, value in self.__old_env.iteritems():
 
537
            self._restoreVar(name, value)
 
538
 
 
539
    def tearDown(self):
 
540
        self._runCleanups()
85
541
        unittest.TestCase.tearDown(self)
86
542
 
 
543
    def time(self, callable, *args, **kwargs):
 
544
        """Run callable and accrue the time it takes to the benchmark time."""
 
545
        if self._benchtime is None:
 
546
            self._benchtime = 0
 
547
        start = time.time()
 
548
        try:
 
549
            callable(*args, **kwargs)
 
550
        finally:
 
551
            self._benchtime += time.time() - start
 
552
 
 
553
    def _runCleanups(self):
 
554
        """Run registered cleanup functions. 
 
555
 
 
556
        This should only be called from TestCase.tearDown.
 
557
        """
 
558
        # TODO: Perhaps this should keep running cleanups even if 
 
559
        # one of them fails?
 
560
        for cleanup_fn in reversed(self._cleanups):
 
561
            cleanup_fn()
87
562
 
88
563
    def log(self, *args):
89
 
        logging.debug(*args)
 
564
        mutter(*args)
90
565
 
91
566
    def _get_log(self):
92
567
        """Return as a string the log for this test"""
93
 
        return open(self._log_file_name).read()
 
568
        if self._log_file_name:
 
569
            return open(self._log_file_name).read()
 
570
        else:
 
571
            return self._log_contents
 
572
        # TODO: Delete the log after it's been read in
 
573
 
 
574
    def capture(self, cmd, retcode=0):
 
575
        """Shortcut that splits cmd into words, runs, and returns stdout"""
 
576
        return self.run_bzr_captured(cmd.split(), retcode=retcode)[0]
 
577
 
 
578
    def run_bzr_captured(self, argv, retcode=0, stdin=None):
 
579
        """Invoke bzr and return (stdout, stderr).
 
580
 
 
581
        Useful for code that wants to check the contents of the
 
582
        output, the way error messages are presented, etc.
 
583
 
 
584
        This should be the main method for tests that want to exercise the
 
585
        overall behavior of the bzr application (rather than a unit test
 
586
        or a functional test of the library.)
 
587
 
 
588
        Much of the old code runs bzr by forking a new copy of Python, but
 
589
        that is slower, harder to debug, and generally not necessary.
 
590
 
 
591
        This runs bzr through the interface that catches and reports
 
592
        errors, and with logging set to something approximating the
 
593
        default, so that error reporting can be checked.
 
594
 
 
595
        argv -- arguments to invoke bzr
 
596
        retcode -- expected return code, or None for don't-care.
 
597
        :param stdin: A string to be used as stdin for the command.
 
598
        """
 
599
        if stdin is not None:
 
600
            stdin = StringIO(stdin)
 
601
        stdout = StringIO()
 
602
        stderr = StringIO()
 
603
        self.log('run bzr: %s', ' '.join(argv))
 
604
        # FIXME: don't call into logging here
 
605
        handler = logging.StreamHandler(stderr)
 
606
        handler.setFormatter(bzrlib.trace.QuietFormatter())
 
607
        handler.setLevel(logging.INFO)
 
608
        logger = logging.getLogger('')
 
609
        logger.addHandler(handler)
 
610
        old_ui_factory = bzrlib.ui.ui_factory
 
611
        bzrlib.ui.ui_factory = bzrlib.tests.blackbox.TestUIFactory(
 
612
            stdout=stdout,
 
613
            stderr=stderr)
 
614
        bzrlib.ui.ui_factory.stdin = stdin
 
615
        try:
 
616
            result = self.apply_redirected(stdin, stdout, stderr,
 
617
                                           bzrlib.commands.run_bzr_catch_errors,
 
618
                                           argv)
 
619
        finally:
 
620
            logger.removeHandler(handler)
 
621
            bzrlib.ui.ui_factory = old_ui_factory
 
622
        out = stdout.getvalue()
 
623
        err = stderr.getvalue()
 
624
        if out:
 
625
            self.log('output:\n%s', out)
 
626
        if err:
 
627
            self.log('errors:\n%s', err)
 
628
        if retcode is not None:
 
629
            self.assertEquals(result, retcode)
 
630
        return out, err
94
631
 
95
632
    def run_bzr(self, *args, **kwargs):
96
633
        """Invoke bzr, as if it were run from the command line.
99
636
        overall behavior of the bzr application (rather than a unit test
100
637
        or a functional test of the library.)
101
638
 
102
 
        Much of the old code runs bzr by forking a new copy of Python, but
103
 
        that is slower, harder to debug, and generally not necessary.
 
639
        This sends the stdout/stderr results into the test's log,
 
640
        where it may be useful for debugging.  See also run_captured.
 
641
 
 
642
        :param stdin: A string to be used as stdin for the command.
104
643
        """
105
 
        retcode = kwargs.get('retcode', 0)
106
 
        result = self.apply_redirected(None, None, None,
107
 
                                       bzrlib.commands.run_bzr, args)
108
 
        self.assertEquals(result, retcode)
109
 
        
110
 
        
 
644
        retcode = kwargs.pop('retcode', 0)
 
645
        stdin = kwargs.pop('stdin', None)
 
646
        return self.run_bzr_captured(args, retcode, stdin)
 
647
 
111
648
    def check_inventory_shape(self, inv, shape):
112
 
        """
113
 
        Compare an inventory to a list of expected names.
 
649
        """Compare an inventory to a list of expected names.
114
650
 
115
651
        Fail if they are not precisely equal.
116
652
        """
134
670
        """Call callable with redirected std io pipes.
135
671
 
136
672
        Returns the return code."""
137
 
        from StringIO import StringIO
138
673
        if not callable(a_callable):
139
674
            raise ValueError("a_callable must be callable.")
140
675
        if stdin is None:
141
676
            stdin = StringIO("")
142
677
        if stdout is None:
143
 
            stdout = self._log_file
 
678
            if getattr(self, "_log_file", None) is not None:
 
679
                stdout = self._log_file
 
680
            else:
 
681
                stdout = StringIO()
144
682
        if stderr is None:
145
 
            stderr = self._log_file
 
683
            if getattr(self, "_log_file", None is not None):
 
684
                stderr = self._log_file
 
685
            else:
 
686
                stderr = StringIO()
146
687
        real_stdin = sys.stdin
147
688
        real_stdout = sys.stdout
148
689
        real_stderr = sys.stderr
156
697
            sys.stderr = real_stderr
157
698
            sys.stdin = real_stdin
158
699
 
 
700
    def merge(self, branch_from, wt_to):
 
701
        """A helper for tests to do a ui-less merge.
 
702
 
 
703
        This should move to the main library when someone has time to integrate
 
704
        it in.
 
705
        """
 
706
        # minimal ui-less merge.
 
707
        wt_to.branch.fetch(branch_from)
 
708
        base_rev = common_ancestor(branch_from.last_revision(),
 
709
                                   wt_to.branch.last_revision(),
 
710
                                   wt_to.branch.repository)
 
711
        merge_inner(wt_to.branch, branch_from.basis_tree(), 
 
712
                    wt_to.branch.repository.revision_tree(base_rev),
 
713
                    this_tree=wt_to)
 
714
        wt_to.add_pending_merge(branch_from.last_revision())
 
715
 
159
716
 
160
717
BzrTestBase = TestCase
161
718
 
183
740
        if contents != expect:
184
741
            self.log("expected: %r" % expect)
185
742
            self.log("actually: %r" % contents)
186
 
            self.fail("contents of %s not as expected")
 
743
            self.fail("contents of %s not as expected" % filename)
187
744
 
188
745
    def _make_test_root(self):
189
746
        if TestCaseInTempDir.TEST_ROOT is not None:
190
747
            return
191
748
        i = 0
192
749
        while True:
193
 
            root = 'test%04d.tmp' % i
 
750
            root = u'test%04d.tmp' % i
194
751
            try:
195
752
                os.mkdir(root)
196
753
            except OSError, e:
200
757
                else:
201
758
                    raise
202
759
            # successfully created
203
 
            TestCaseInTempDir.TEST_ROOT = os.path.abspath(root)
 
760
            TestCaseInTempDir.TEST_ROOT = osutils.abspath(root)
204
761
            break
205
762
        # make a fake bzr directory there to prevent any tests propagating
206
763
        # up onto the source directory's real branch
207
 
        os.mkdir(os.path.join(TestCaseInTempDir.TEST_ROOT, '.bzr'))
 
764
        bzrdir.BzrDir.create_standalone_workingtree(TestCaseInTempDir.TEST_ROOT)
208
765
 
209
766
    def setUp(self):
210
767
        super(TestCaseInTempDir, self).setUp()
211
 
        import os
212
768
        self._make_test_root()
213
 
        self._currentdir = os.getcwdu()
214
 
        short_id = self.id().replace('bzrlib.selftest.', '') \
215
 
                   .replace('__main__.', '')
216
 
        self.test_dir = os.path.join(self.TEST_ROOT, short_id)
217
 
        os.mkdir(self.test_dir)
218
 
        os.chdir(self.test_dir)
 
769
        _currentdir = os.getcwdu()
 
770
        # shorten the name, to avoid test failures due to path length
 
771
        short_id = self.id().replace('bzrlib.tests.', '') \
 
772
                   .replace('__main__.', '')[-100:]
 
773
        # it's possible the same test class is run several times for
 
774
        # parameterized tests, so make sure the names don't collide.  
 
775
        i = 0
 
776
        while True:
 
777
            if i > 0:
 
778
                candidate_dir = '%s/%s.%d' % (self.TEST_ROOT, short_id, i)
 
779
            else:
 
780
                candidate_dir = '%s/%s' % (self.TEST_ROOT, short_id)
 
781
            if os.path.exists(candidate_dir):
 
782
                i = i + 1
 
783
                continue
 
784
            else:
 
785
                self.test_dir = candidate_dir
 
786
                os.mkdir(self.test_dir)
 
787
                os.chdir(self.test_dir)
 
788
                break
 
789
        os.environ['HOME'] = self.test_dir
 
790
        os.environ['APPDATA'] = self.test_dir
 
791
        def _leaveDirectory():
 
792
            os.chdir(_currentdir)
 
793
        self.addCleanup(_leaveDirectory)
219
794
        
220
 
    def tearDown(self):
221
 
        import os
222
 
        os.chdir(self._currentdir)
223
 
        super(TestCaseInTempDir, self).tearDown()
224
 
 
225
 
    def _formcmd(self, cmd):
226
 
        if isinstance(cmd, basestring):
227
 
            cmd = cmd.split()
228
 
        if cmd[0] == 'bzr':
229
 
            cmd[0] = self.BZRPATH
230
 
            if self.OVERRIDE_PYTHON:
231
 
                cmd.insert(0, self.OVERRIDE_PYTHON)
232
 
        self.log('$ %r' % cmd)
233
 
        return cmd
234
 
 
235
 
    def runcmd(self, cmd, retcode=0):
236
 
        """Run one command and check the return code.
237
 
 
238
 
        Returns a tuple of (stdout,stderr) strings.
239
 
 
240
 
        If a single string is based, it is split into words.
241
 
        For commands that are not simple space-separated words, please
242
 
        pass a list instead."""
243
 
        cmd = self._formcmd(cmd)
244
 
        self.log('$ ' + ' '.join(cmd))
245
 
        actual_retcode = subprocess.call(cmd, stdout=self._log_file,
246
 
                                         stderr=self._log_file)
247
 
        if retcode != actual_retcode:
248
 
            raise CommandFailed("test failed: %r returned %d, expected %d"
249
 
                                % (cmd, actual_retcode, retcode))
250
 
 
251
 
    def backtick(self, cmd, retcode=0):
252
 
        """Run a command and return its output"""
253
 
        cmd = self._formcmd(cmd)
254
 
        child = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=self._log_file)
255
 
        outd, errd = child.communicate()
256
 
        self.log(outd)
257
 
        actual_retcode = child.wait()
258
 
 
259
 
        outd = outd.replace('\r', '')
260
 
 
261
 
        if retcode != actual_retcode:
262
 
            raise CommandFailed("test failed: %r returned %d, expected %d"
263
 
                                % (cmd, actual_retcode, retcode))
264
 
 
265
 
        return outd
266
 
 
267
 
 
268
 
 
269
 
    def build_tree(self, shape):
 
795
    def build_tree(self, shape, line_endings='native', transport=None):
270
796
        """Build a test tree according to a pattern.
271
797
 
272
798
        shape is a sequence of file specifications.  If the final
273
799
        character is '/', a directory is created.
274
800
 
275
801
        This doesn't add anything to a branch.
 
802
        :param line_endings: Either 'binary' or 'native'
 
803
                             in binary mode, exact contents are written
 
804
                             in native mode, the line endings match the
 
805
                             default platform endings.
 
806
 
 
807
        :param transport: A transport to write to, for building trees on 
 
808
                          VFS's. If the transport is readonly or None,
 
809
                          "." is opened automatically.
276
810
        """
277
811
        # XXX: It's OK to just create them using forward slashes on windows?
278
 
        import os
 
812
        if transport is None or transport.is_readonly():
 
813
            transport = get_transport(".")
279
814
        for name in shape:
280
 
            assert isinstance(name, basestring)
 
815
            self.assert_(isinstance(name, basestring))
281
816
            if name[-1] == '/':
282
 
                os.mkdir(name[:-1])
283
 
            else:
284
 
                f = file(name, 'wt')
285
 
                print >>f, "contents of", name
286
 
                f.close()
287
 
                
288
 
 
289
 
 
290
 
class MetaTestLog(TestCase):
291
 
    def test_logging(self):
292
 
        """Test logs are captured when a test fails."""
293
 
        logging.info('an info message')
294
 
        warning('something looks dodgy...')
295
 
        logging.debug('hello, test is running')
296
 
        ##assert 0
297
 
 
298
 
 
299
 
def selftest(verbose=False, pattern=".*"):
 
817
                transport.mkdir(urlescape(name[:-1]))
 
818
            else:
 
819
                if line_endings == 'binary':
 
820
                    end = '\n'
 
821
                elif line_endings == 'native':
 
822
                    end = os.linesep
 
823
                else:
 
824
                    raise errors.BzrError('Invalid line ending request %r' % (line_endings,))
 
825
                content = "contents of %s%s" % (name, end)
 
826
                transport.put(urlescape(name), StringIO(content))
 
827
 
 
828
    def build_tree_contents(self, shape):
 
829
        build_tree_contents(shape)
 
830
 
 
831
    def failUnlessExists(self, path):
 
832
        """Fail unless path, which may be abs or relative, exists."""
 
833
        self.failUnless(osutils.lexists(path))
 
834
 
 
835
    def failIfExists(self, path):
 
836
        """Fail if path, which may be abs or relative, exists."""
 
837
        self.failIf(osutils.lexists(path))
 
838
        
 
839
    def assertFileEqual(self, content, path):
 
840
        """Fail if path does not contain 'content'."""
 
841
        self.failUnless(osutils.lexists(path))
 
842
        self.assertEqualDiff(content, open(path, 'r').read())
 
843
 
 
844
 
 
845
class TestCaseWithTransport(TestCaseInTempDir):
 
846
    """A test case that provides get_url and get_readonly_url facilities.
 
847
 
 
848
    These back onto two transport servers, one for readonly access and one for
 
849
    read write access.
 
850
 
 
851
    If no explicit class is provided for readonly access, a
 
852
    ReadonlyTransportDecorator is used instead which allows the use of non disk
 
853
    based read write transports.
 
854
 
 
855
    If an explicit class is provided for readonly access, that server and the 
 
856
    readwrite one must both define get_url() as resolving to os.getcwd().
 
857
    """
 
858
 
 
859
    def __init__(self, methodName='testMethod'):
 
860
        super(TestCaseWithTransport, self).__init__(methodName)
 
861
        self.__readonly_server = None
 
862
        self.__server = None
 
863
        self.transport_server = default_transport
 
864
        self.transport_readonly_server = None
 
865
 
 
866
    def get_readonly_url(self, relpath=None):
 
867
        """Get a URL for the readonly transport.
 
868
 
 
869
        This will either be backed by '.' or a decorator to the transport 
 
870
        used by self.get_url()
 
871
        relpath provides for clients to get a path relative to the base url.
 
872
        These should only be downwards relative, not upwards.
 
873
        """
 
874
        base = self.get_readonly_server().get_url()
 
875
        if relpath is not None:
 
876
            if not base.endswith('/'):
 
877
                base = base + '/'
 
878
            base = base + relpath
 
879
        return base
 
880
 
 
881
    def get_readonly_server(self):
 
882
        """Get the server instance for the readonly transport
 
883
 
 
884
        This is useful for some tests with specific servers to do diagnostics.
 
885
        """
 
886
        if self.__readonly_server is None:
 
887
            if self.transport_readonly_server is None:
 
888
                # readonly decorator requested
 
889
                # bring up the server
 
890
                self.get_url()
 
891
                self.__readonly_server = ReadonlyServer()
 
892
                self.__readonly_server.setUp(self.__server)
 
893
            else:
 
894
                self.__readonly_server = self.transport_readonly_server()
 
895
                self.__readonly_server.setUp()
 
896
            self.addCleanup(self.__readonly_server.tearDown)
 
897
        return self.__readonly_server
 
898
 
 
899
    def get_server(self):
 
900
        """Get the read/write server instance.
 
901
 
 
902
        This is useful for some tests with specific servers that need
 
903
        diagnostics.
 
904
        """
 
905
        if self.__server is None:
 
906
            self.__server = self.transport_server()
 
907
            self.__server.setUp()
 
908
            self.addCleanup(self.__server.tearDown)
 
909
        return self.__server
 
910
 
 
911
    def get_url(self, relpath=None):
 
912
        """Get a URL for the readwrite transport.
 
913
 
 
914
        This will either be backed by '.' or to an equivalent non-file based
 
915
        facility.
 
916
        relpath provides for clients to get a path relative to the base url.
 
917
        These should only be downwards relative, not upwards.
 
918
        """
 
919
        base = self.get_server().get_url()
 
920
        if relpath is not None and relpath != '.':
 
921
            if not base.endswith('/'):
 
922
                base = base + '/'
 
923
            base = base + relpath
 
924
        return base
 
925
 
 
926
    def get_transport(self):
 
927
        """Return a writeable transport for the test scratch space"""
 
928
        t = get_transport(self.get_url())
 
929
        self.assertFalse(t.is_readonly())
 
930
        return t
 
931
 
 
932
    def get_readonly_transport(self):
 
933
        """Return a readonly transport for the test scratch space
 
934
        
 
935
        This can be used to test that operations which should only need
 
936
        readonly access in fact do not try to write.
 
937
        """
 
938
        t = get_transport(self.get_readonly_url())
 
939
        self.assertTrue(t.is_readonly())
 
940
        return t
 
941
 
 
942
    def make_branch(self, relpath, format=None):
 
943
        """Create a branch on the transport at relpath."""
 
944
        repo = self.make_repository(relpath, format=format)
 
945
        return repo.bzrdir.create_branch()
 
946
 
 
947
    def make_bzrdir(self, relpath, format=None):
 
948
        try:
 
949
            url = self.get_url(relpath)
 
950
            segments = relpath.split('/')
 
951
            if segments and segments[-1] not in ('', '.'):
 
952
                parent = self.get_url('/'.join(segments[:-1]))
 
953
                t = get_transport(parent)
 
954
                try:
 
955
                    t.mkdir(segments[-1])
 
956
                except errors.FileExists:
 
957
                    pass
 
958
            if format is None:
 
959
                format=bzrlib.bzrdir.BzrDirFormat.get_default_format()
 
960
            # FIXME: make this use a single transport someday. RBC 20060418
 
961
            return format.initialize_on_transport(get_transport(relpath))
 
962
        except errors.UninitializableFormat:
 
963
            raise TestSkipped("Format %s is not initializable." % format)
 
964
 
 
965
    def make_repository(self, relpath, shared=False, format=None):
 
966
        """Create a repository on our default transport at relpath."""
 
967
        made_control = self.make_bzrdir(relpath, format=format)
 
968
        return made_control.create_repository(shared=shared)
 
969
 
 
970
    def make_branch_and_tree(self, relpath, format=None):
 
971
        """Create a branch on the transport and a tree locally.
 
972
 
 
973
        Returns the tree.
 
974
        """
 
975
        # TODO: always use the local disk path for the working tree,
 
976
        # this obviously requires a format that supports branch references
 
977
        # so check for that by checking bzrdir.BzrDirFormat.get_default_format()
 
978
        # RBC 20060208
 
979
        b = self.make_branch(relpath, format=format)
 
980
        try:
 
981
            return b.bzrdir.create_workingtree()
 
982
        except errors.NotLocalUrl:
 
983
            # new formats - catch No tree error and create
 
984
            # a branch reference and a checkout.
 
985
            # old formats at that point - raise TestSkipped.
 
986
            # TODO: rbc 20060208
 
987
            return WorkingTreeFormat2().initialize(bzrdir.BzrDir.open(relpath))
 
988
 
 
989
    def assertIsDirectory(self, relpath, transport):
 
990
        """Assert that relpath within transport is a directory.
 
991
 
 
992
        This may not be possible on all transports; in that case it propagates
 
993
        a TransportNotPossible.
 
994
        """
 
995
        try:
 
996
            mode = transport.stat(relpath).st_mode
 
997
        except errors.NoSuchFile:
 
998
            self.fail("path %s is not a directory; no such file"
 
999
                      % (relpath))
 
1000
        if not stat.S_ISDIR(mode):
 
1001
            self.fail("path %s is not a directory; has mode %#o"
 
1002
                      % (relpath, mode))
 
1003
 
 
1004
 
 
1005
class ChrootedTestCase(TestCaseWithTransport):
 
1006
    """A support class that provides readonly urls outside the local namespace.
 
1007
 
 
1008
    This is done by checking if self.transport_server is a MemoryServer. if it
 
1009
    is then we are chrooted already, if it is not then an HttpServer is used
 
1010
    for readonly urls.
 
1011
 
 
1012
    TODO RBC 20060127: make this an option to TestCaseWithTransport so it can
 
1013
                       be used without needed to redo it when a different 
 
1014
                       subclass is in use ?
 
1015
    """
 
1016
 
 
1017
    def setUp(self):
 
1018
        super(ChrootedTestCase, self).setUp()
 
1019
        if not self.transport_server == bzrlib.transport.memory.MemoryServer:
 
1020
            self.transport_readonly_server = bzrlib.transport.http.HttpServer
 
1021
 
 
1022
 
 
1023
def filter_suite_by_re(suite, pattern):
 
1024
    result = TestSuite()
 
1025
    filter_re = re.compile(pattern)
 
1026
    for test in iter_suite_tests(suite):
 
1027
        if filter_re.search(test.id()):
 
1028
            result.addTest(test)
 
1029
    return result
 
1030
 
 
1031
 
 
1032
def run_suite(suite, name='test', verbose=False, pattern=".*",
 
1033
              stop_on_failure=False, keep_output=False,
 
1034
              transport=None):
 
1035
    TestCaseInTempDir._TEST_NAME = name
 
1036
    if verbose:
 
1037
        verbosity = 2
 
1038
        pb = None
 
1039
    else:
 
1040
        verbosity = 1
 
1041
        pb = progress.ProgressBar()
 
1042
    runner = TextTestRunner(stream=sys.stdout,
 
1043
                            descriptions=0,
 
1044
                            verbosity=verbosity,
 
1045
                            keep_output=keep_output,
 
1046
                            pb=pb)
 
1047
    runner.stop_on_failure=stop_on_failure
 
1048
    if pattern != '.*':
 
1049
        suite = filter_suite_by_re(suite, pattern)
 
1050
    result = runner.run(suite)
 
1051
    return result.wasSuccessful()
 
1052
 
 
1053
 
 
1054
def selftest(verbose=False, pattern=".*", stop_on_failure=True,
 
1055
             keep_output=False,
 
1056
             transport=None,
 
1057
             test_suite_factory=None):
300
1058
    """Run the whole test suite under the enhanced runner"""
301
 
    return testsweet.run_suite(test_suite(), 'testbzr', verbose=verbose, pattern=pattern)
 
1059
    global default_transport
 
1060
    if transport is None:
 
1061
        transport = default_transport
 
1062
    old_transport = default_transport
 
1063
    default_transport = transport
 
1064
    try:
 
1065
        if test_suite_factory is None:
 
1066
            suite = test_suite()
 
1067
        else:
 
1068
            suite = test_suite_factory()
 
1069
        return run_suite(suite, 'testbzr', verbose=verbose, pattern=pattern,
 
1070
                     stop_on_failure=stop_on_failure, keep_output=keep_output,
 
1071
                     transport=transport)
 
1072
    finally:
 
1073
        default_transport = old_transport
302
1074
 
303
1075
 
304
1076
def test_suite():
305
 
    """Build and return TestSuite for the whole program."""
306
 
    from bzrlib.selftest.TestUtil import TestLoader, TestSuite
307
 
    import bzrlib, bzrlib.store, bzrlib.inventory, bzrlib.branch
308
 
    import bzrlib.osutils, bzrlib.commands, bzrlib.merge3, bzrlib.plugin
 
1077
    """Build and return TestSuite for the whole of bzrlib.
 
1078
    
 
1079
    This function can be replaced if you need to change the default test
 
1080
    suite on a global basis, but it is not encouraged.
 
1081
    """
309
1082
    from doctest import DocTestSuite
310
 
    import os
311
 
    import shutil
312
 
    import time
313
 
    import sys
314
 
 
315
 
    global MODULES_TO_TEST, MODULES_TO_DOCTEST
316
 
 
317
 
    testmod_names = \
318
 
                  ['bzrlib.selftest.MetaTestLog',
319
 
                   'bzrlib.selftest.testinv',
320
 
                   'bzrlib.selftest.test_commit',
321
 
                   'bzrlib.selftest.versioning',
322
 
                   'bzrlib.selftest.testmerge3',
323
 
                   'bzrlib.selftest.testhashcache',
324
 
                   'bzrlib.selftest.teststatus',
325
 
                   'bzrlib.selftest.testlog',
326
 
                   'bzrlib.selftest.testrevisionnamespaces',
327
 
                   'bzrlib.selftest.testbranch',
328
 
                   'bzrlib.selftest.testrevision',
329
 
                   'bzrlib.selftest.test_merge_core',
330
 
                   'bzrlib.selftest.test_smart_add',
331
 
                   'bzrlib.selftest.testdiff',
332
 
                   'bzrlib.selftest.test_parent',
333
 
                   'bzrlib.selftest.test_xml',
334
 
                   'bzrlib.selftest.test_weave',
335
 
                   'bzrlib.selftest.testfetch',
336
 
                   'bzrlib.selftest.whitebox',
337
 
                   'bzrlib.selftest.teststore',
338
 
                   'bzrlib.selftest.blackbox',
 
1083
 
 
1084
    global MODULES_TO_DOCTEST
 
1085
 
 
1086
    testmod_names = [ \
 
1087
                   'bzrlib.tests.test_ancestry',
 
1088
                   'bzrlib.tests.test_api',
 
1089
                   'bzrlib.tests.test_bad_files',
 
1090
                   'bzrlib.tests.test_branch',
 
1091
                   'bzrlib.tests.test_bzrdir',
 
1092
                   'bzrlib.tests.test_command',
 
1093
                   'bzrlib.tests.test_commit',
 
1094
                   'bzrlib.tests.test_commit_merge',
 
1095
                   'bzrlib.tests.test_config',
 
1096
                   'bzrlib.tests.test_conflicts',
 
1097
                   'bzrlib.tests.test_decorators',
 
1098
                   'bzrlib.tests.test_diff',
 
1099
                   'bzrlib.tests.test_doc_generate',
 
1100
                   'bzrlib.tests.test_errors',
 
1101
                   'bzrlib.tests.test_escaped_store',
 
1102
                   'bzrlib.tests.test_fetch',
 
1103
                   'bzrlib.tests.test_gpg',
 
1104
                   'bzrlib.tests.test_graph',
 
1105
                   'bzrlib.tests.test_hashcache',
 
1106
                   'bzrlib.tests.test_http',
 
1107
                   'bzrlib.tests.test_identitymap',
 
1108
                   'bzrlib.tests.test_inv',
 
1109
                   'bzrlib.tests.test_knit',
 
1110
                   'bzrlib.tests.test_lockdir',
 
1111
                   'bzrlib.tests.test_lockable_files',
 
1112
                   'bzrlib.tests.test_log',
 
1113
                   'bzrlib.tests.test_merge',
 
1114
                   'bzrlib.tests.test_merge3',
 
1115
                   'bzrlib.tests.test_merge_core',
 
1116
                   'bzrlib.tests.test_missing',
 
1117
                   'bzrlib.tests.test_msgeditor',
 
1118
                   'bzrlib.tests.test_nonascii',
 
1119
                   'bzrlib.tests.test_options',
 
1120
                   'bzrlib.tests.test_osutils',
 
1121
                   'bzrlib.tests.test_patch',
 
1122
                   'bzrlib.tests.test_permissions',
 
1123
                   'bzrlib.tests.test_plugins',
 
1124
                   'bzrlib.tests.test_progress',
 
1125
                   'bzrlib.tests.test_reconcile',
 
1126
                   'bzrlib.tests.test_repository',
 
1127
                   'bzrlib.tests.test_revision',
 
1128
                   'bzrlib.tests.test_revisionnamespaces',
 
1129
                   'bzrlib.tests.test_revprops',
 
1130
                   'bzrlib.tests.test_rio',
 
1131
                   'bzrlib.tests.test_sampler',
 
1132
                   'bzrlib.tests.test_selftest',
 
1133
                   'bzrlib.tests.test_setup',
 
1134
                   'bzrlib.tests.test_sftp_transport',
 
1135
                   'bzrlib.tests.test_smart_add',
 
1136
                   'bzrlib.tests.test_source',
 
1137
                   'bzrlib.tests.test_status',
 
1138
                   'bzrlib.tests.test_store',
 
1139
                   'bzrlib.tests.test_symbol_versioning',
 
1140
                   'bzrlib.tests.test_testament',
 
1141
                   'bzrlib.tests.test_textfile',
 
1142
                   'bzrlib.tests.test_textmerge',
 
1143
                   'bzrlib.tests.test_trace',
 
1144
                   'bzrlib.tests.test_transactions',
 
1145
                   'bzrlib.tests.test_transform',
 
1146
                   'bzrlib.tests.test_transport',
 
1147
                   'bzrlib.tests.test_tsort',
 
1148
                   'bzrlib.tests.test_tuned_gzip',
 
1149
                   'bzrlib.tests.test_ui',
 
1150
                   'bzrlib.tests.test_upgrade',
 
1151
                   'bzrlib.tests.test_versionedfile',
 
1152
                   'bzrlib.tests.test_weave',
 
1153
                   'bzrlib.tests.test_whitebox',
 
1154
                   'bzrlib.tests.test_workingtree',
 
1155
                   'bzrlib.tests.test_xml',
339
1156
                   ]
340
 
 
341
 
    for m in (bzrlib.store, bzrlib.inventory, bzrlib.branch,
342
 
              bzrlib.osutils, bzrlib.commands, bzrlib.merge3):
343
 
        if m not in MODULES_TO_DOCTEST:
344
 
            MODULES_TO_DOCTEST.append(m)
345
 
 
346
 
    TestCase.BZRPATH = os.path.join(os.path.realpath(os.path.dirname(bzrlib.__path__[0])), 'bzr')
347
 
    print '%-30s %s' % ('bzr binary', TestCase.BZRPATH)
348
 
    print
 
1157
    test_transport_implementations = [
 
1158
        'bzrlib.tests.test_transport_implementations']
 
1159
 
349
1160
    suite = TestSuite()
350
 
    suite.addTest(TestLoader().loadTestsFromNames(testmod_names))
 
1161
    loader = TestUtil.TestLoader()
 
1162
    from bzrlib.transport import TransportTestProviderAdapter
 
1163
    adapter = TransportTestProviderAdapter()
 
1164
    adapt_modules(test_transport_implementations, adapter, loader, suite)
 
1165
    suite.addTest(loader.loadTestsFromModuleNames(testmod_names))
 
1166
    for package in packages_to_test():
 
1167
        suite.addTest(package.test_suite())
351
1168
    for m in MODULES_TO_TEST:
352
 
         suite.addTest(TestLoader().loadTestsFromModule(m))
 
1169
        suite.addTest(loader.loadTestsFromModule(m))
353
1170
    for m in (MODULES_TO_DOCTEST):
354
1171
        suite.addTest(DocTestSuite(m))
355
 
    for p in bzrlib.plugin.all_plugins:
356
 
        if hasattr(p, 'test_suite'):
357
 
            suite.addTest(p.test_suite())
 
1172
    for name, plugin in bzrlib.plugin.all_plugins().items():
 
1173
        if getattr(plugin, 'test_suite', None) is not None:
 
1174
            suite.addTest(plugin.test_suite())
358
1175
    return suite
359
1176
 
 
1177
 
 
1178
def adapt_modules(mods_list, adapter, loader, suite):
 
1179
    """Adapt the modules in mods_list using adapter and add to suite."""
 
1180
    for test in iter_suite_tests(loader.loadTestsFromModuleNames(mods_list)):
 
1181
        suite.addTests(adapter.adapt(test))