~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/__init__.py

  • Committer: John Arbash Meinel
  • Date: 2006-09-20 23:43:18 UTC
  • mto: This revision was merged to the branch mainline in revision 2027.
  • Revision ID: john@arbash-meinel.com-20060920234318-05de23e98f7e7876
Move out export tests from test_too_much, refactor
and re-enable doc tests for export.get_root_name()

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005 by Canonical Ltd
2
 
 
 
1
# Copyright (C) 2005, 2006 by Canonical Ltd
 
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
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 doctest
 
33
import errno
18
34
import logging
19
 
import unittest
20
 
import tempfile
21
35
import os
 
36
import re
 
37
import shlex
 
38
import stat
 
39
from subprocess import Popen, PIPE
22
40
import sys
23
 
import subprocess
24
 
 
25
 
from testsweet import run_suite
 
41
import tempfile
 
42
import unittest
 
43
import time
 
44
 
 
45
 
 
46
from bzrlib import memorytree
 
47
import bzrlib.branch
 
48
import bzrlib.bzrdir as bzrdir
26
49
import bzrlib.commands
27
 
 
 
50
import bzrlib.bundle.serializer
 
51
import bzrlib.errors as errors
 
52
import bzrlib.export
 
53
import bzrlib.inventory
 
54
import bzrlib.iterablefile
 
55
import bzrlib.lockdir
 
56
try:
 
57
    import bzrlib.lsprof
 
58
except ImportError:
 
59
    # lsprof not available
 
60
    pass
 
61
from bzrlib.merge import merge_inner
 
62
import bzrlib.merge3
 
63
import bzrlib.osutils
 
64
import bzrlib.osutils as osutils
 
65
import bzrlib.plugin
 
66
import bzrlib.progress as progress
 
67
from bzrlib.revision import common_ancestor
 
68
import bzrlib.store
 
69
from bzrlib import symbol_versioning
28
70
import bzrlib.trace
29
 
import bzrlib.fetch
 
71
from bzrlib.transport import get_transport
 
72
import bzrlib.transport
 
73
from bzrlib.transport.local import LocalRelpathServer
 
74
from bzrlib.transport.readonly import ReadonlyServer
 
75
from bzrlib.trace import mutter
 
76
from bzrlib.tests import TestUtil
 
77
from bzrlib.tests.TestUtil import (
 
78
                          TestSuite,
 
79
                          TestLoader,
 
80
                          )
 
81
from bzrlib.tests.treeshape import build_tree_contents
 
82
import bzrlib.urlutils as urlutils
 
83
from bzrlib.workingtree import WorkingTree, WorkingTreeFormat2
30
84
 
 
85
default_transport = LocalRelpathServer
31
86
 
32
87
MODULES_TO_TEST = []
33
 
MODULES_TO_DOCTEST = []
34
 
 
35
 
from logging import debug, warning, error
 
88
MODULES_TO_DOCTEST = [
 
89
                      bzrlib.branch,
 
90
                      bzrlib.bundle.serializer,
 
91
                      bzrlib.commands,
 
92
                      bzrlib.errors,
 
93
                      bzrlib.export,
 
94
                      bzrlib.inventory,
 
95
                      bzrlib.iterablefile,
 
96
                      bzrlib.lockdir,
 
97
                      bzrlib.merge3,
 
98
                      bzrlib.option,
 
99
                      bzrlib.osutils,
 
100
                      bzrlib.store,
 
101
                      bzrlib.transport,
 
102
                      ]
 
103
 
 
104
 
 
105
def packages_to_test():
 
106
    """Return a list of packages to test.
 
107
 
 
108
    The packages are not globally imported so that import failures are
 
109
    triggered when running selftest, not when importing the command.
 
110
    """
 
111
    import bzrlib.doc
 
112
    import bzrlib.tests.blackbox
 
113
    import bzrlib.tests.branch_implementations
 
114
    import bzrlib.tests.bzrdir_implementations
 
115
    import bzrlib.tests.interrepository_implementations
 
116
    import bzrlib.tests.interversionedfile_implementations
 
117
    import bzrlib.tests.intertree_implementations
 
118
    import bzrlib.tests.repository_implementations
 
119
    import bzrlib.tests.revisionstore_implementations
 
120
    import bzrlib.tests.tree_implementations
 
121
    import bzrlib.tests.workingtree_implementations
 
122
    return [
 
123
            bzrlib.doc,
 
124
            bzrlib.tests.blackbox,
 
125
            bzrlib.tests.branch_implementations,
 
126
            bzrlib.tests.bzrdir_implementations,
 
127
            bzrlib.tests.interrepository_implementations,
 
128
            bzrlib.tests.interversionedfile_implementations,
 
129
            bzrlib.tests.intertree_implementations,
 
130
            bzrlib.tests.repository_implementations,
 
131
            bzrlib.tests.revisionstore_implementations,
 
132
            bzrlib.tests.tree_implementations,
 
133
            bzrlib.tests.workingtree_implementations,
 
134
            ]
 
135
 
 
136
 
 
137
class _MyResult(unittest._TextTestResult):
 
138
    """Custom TestResult.
 
139
 
 
140
    Shows output in a different format, including displaying runtime for tests.
 
141
    """
 
142
    stop_early = False
 
143
    
 
144
    def __init__(self, stream, descriptions, verbosity, pb=None,
 
145
                 bench_history=None):
 
146
        """Construct new TestResult.
 
147
 
 
148
        :param bench_history: Optionally, a writable file object to accumulate
 
149
            benchmark results.
 
150
        """
 
151
        unittest._TextTestResult.__init__(self, stream, descriptions, verbosity)
 
152
        self.pb = pb
 
153
        if bench_history is not None:
 
154
            from bzrlib.version import _get_bzr_source_tree
 
155
            src_tree = _get_bzr_source_tree()
 
156
            if src_tree:
 
157
                try:
 
158
                    revision_id = src_tree.get_parent_ids()[0]
 
159
                except IndexError:
 
160
                    # XXX: if this is a brand new tree, do the same as if there
 
161
                    # is no branch.
 
162
                    revision_id = ''
 
163
            else:
 
164
                # XXX: If there's no branch, what should we do?
 
165
                revision_id = ''
 
166
            bench_history.write("--date %s %s\n" % (time.time(), revision_id))
 
167
        self._bench_history = bench_history
 
168
    
 
169
    def extractBenchmarkTime(self, testCase):
 
170
        """Add a benchmark time for the current test case."""
 
171
        self._benchmarkTime = getattr(testCase, "_benchtime", None)
 
172
    
 
173
    def _elapsedTestTimeString(self):
 
174
        """Return a time string for the overall time the current test has taken."""
 
175
        return self._formatTime(time.time() - self._start_time)
 
176
 
 
177
    def _testTimeString(self):
 
178
        if self._benchmarkTime is not None:
 
179
            return "%s/%s" % (
 
180
                self._formatTime(self._benchmarkTime),
 
181
                self._elapsedTestTimeString())
 
182
        else:
 
183
            return "      %s" % self._elapsedTestTimeString()
 
184
 
 
185
    def _formatTime(self, seconds):
 
186
        """Format seconds as milliseconds with leading spaces."""
 
187
        return "%5dms" % (1000 * seconds)
 
188
 
 
189
    def _ellipsise_unimportant_words(self, a_string, final_width,
 
190
                                   keep_start=False):
 
191
        """Add ellipses (sp?) for overly long strings.
 
192
        
 
193
        :param keep_start: If true preserve the start of a_string rather
 
194
                           than the end of it.
 
195
        """
 
196
        if keep_start:
 
197
            if len(a_string) > final_width:
 
198
                result = a_string[:final_width-3] + '...'
 
199
            else:
 
200
                result = a_string
 
201
        else:
 
202
            if len(a_string) > final_width:
 
203
                result = '...' + a_string[3-final_width:]
 
204
            else:
 
205
                result = a_string
 
206
        return result.ljust(final_width)
 
207
 
 
208
    def startTest(self, test):
 
209
        unittest.TestResult.startTest(self, test)
 
210
        # In a short description, the important words are in
 
211
        # the beginning, but in an id, the important words are
 
212
        # at the end
 
213
        SHOW_DESCRIPTIONS = False
 
214
 
 
215
        if not self.showAll and self.dots and self.pb is not None:
 
216
            final_width = 13
 
217
        else:
 
218
            final_width = osutils.terminal_width()
 
219
            final_width = final_width - 15 - 8
 
220
        what = None
 
221
        if SHOW_DESCRIPTIONS:
 
222
            what = test.shortDescription()
 
223
            if what:
 
224
                what = self._ellipsise_unimportant_words(what, final_width, keep_start=True)
 
225
        if what is None:
 
226
            what = test.id()
 
227
            if what.startswith('bzrlib.tests.'):
 
228
                what = what[13:]
 
229
            what = self._ellipsise_unimportant_words(what, final_width)
 
230
        if self.showAll:
 
231
            self.stream.write(what)
 
232
        elif self.dots and self.pb is not None:
 
233
            self.pb.update(what, self.testsRun - 1, None)
 
234
        self.stream.flush()
 
235
        self._recordTestStartTime()
 
236
 
 
237
    def _recordTestStartTime(self):
 
238
        """Record that a test has started."""
 
239
        self._start_time = time.time()
 
240
 
 
241
    def addError(self, test, err):
 
242
        if isinstance(err[1], TestSkipped):
 
243
            return self.addSkipped(test, err)    
 
244
        unittest.TestResult.addError(self, test, err)
 
245
        self.extractBenchmarkTime(test)
 
246
        if self.showAll:
 
247
            self.stream.writeln("ERROR %s" % self._testTimeString())
 
248
        elif self.dots and self.pb is None:
 
249
            self.stream.write('E')
 
250
        elif self.dots:
 
251
            self.pb.update(self._ellipsise_unimportant_words('ERROR', 13), self.testsRun, None)
 
252
            self.pb.note(self._ellipsise_unimportant_words(
 
253
                            test.id() + ': ERROR',
 
254
                            osutils.terminal_width()))
 
255
        self.stream.flush()
 
256
        if self.stop_early:
 
257
            self.stop()
 
258
 
 
259
    def addFailure(self, test, err):
 
260
        unittest.TestResult.addFailure(self, test, err)
 
261
        self.extractBenchmarkTime(test)
 
262
        if self.showAll:
 
263
            self.stream.writeln(" FAIL %s" % self._testTimeString())
 
264
        elif self.dots and self.pb is None:
 
265
            self.stream.write('F')
 
266
        elif self.dots:
 
267
            self.pb.update(self._ellipsise_unimportant_words('FAIL', 13), self.testsRun, None)
 
268
            self.pb.note(self._ellipsise_unimportant_words(
 
269
                            test.id() + ': FAIL',
 
270
                            osutils.terminal_width()))
 
271
        self.stream.flush()
 
272
        if self.stop_early:
 
273
            self.stop()
 
274
 
 
275
    def addSuccess(self, test):
 
276
        self.extractBenchmarkTime(test)
 
277
        if self._bench_history is not None:
 
278
            if self._benchmarkTime is not None:
 
279
                self._bench_history.write("%s %s\n" % (
 
280
                    self._formatTime(self._benchmarkTime),
 
281
                    test.id()))
 
282
        if self.showAll:
 
283
            self.stream.writeln('   OK %s' % self._testTimeString())
 
284
            for bench_called, stats in getattr(test, '_benchcalls', []):
 
285
                self.stream.writeln('LSProf output for %s(%s, %s)' % bench_called)
 
286
                stats.pprint(file=self.stream)
 
287
        elif self.dots and self.pb is None:
 
288
            self.stream.write('~')
 
289
        elif self.dots:
 
290
            self.pb.update(self._ellipsise_unimportant_words('OK', 13), self.testsRun, None)
 
291
        self.stream.flush()
 
292
        unittest.TestResult.addSuccess(self, test)
 
293
 
 
294
    def addSkipped(self, test, skip_excinfo):
 
295
        self.extractBenchmarkTime(test)
 
296
        if self.showAll:
 
297
            print >>self.stream, ' SKIP %s' % self._testTimeString()
 
298
            print >>self.stream, '     %s' % skip_excinfo[1]
 
299
        elif self.dots and self.pb is None:
 
300
            self.stream.write('S')
 
301
        elif self.dots:
 
302
            self.pb.update(self._ellipsise_unimportant_words('SKIP', 13), self.testsRun, None)
 
303
        self.stream.flush()
 
304
        # seems best to treat this as success from point-of-view of unittest
 
305
        # -- it actually does nothing so it barely matters :)
 
306
        try:
 
307
            test.tearDown()
 
308
        except KeyboardInterrupt:
 
309
            raise
 
310
        except:
 
311
            self.addError(test, test.__exc_info())
 
312
        else:
 
313
            unittest.TestResult.addSuccess(self, test)
 
314
 
 
315
    def printErrorList(self, flavour, errors):
 
316
        for test, err in errors:
 
317
            self.stream.writeln(self.separator1)
 
318
            self.stream.writeln("%s: %s" % (flavour, self.getDescription(test)))
 
319
            if getattr(test, '_get_log', None) is not None:
 
320
                print >>self.stream
 
321
                print >>self.stream, \
 
322
                        ('vvvv[log from %s]' % test.id()).ljust(78,'-')
 
323
                print >>self.stream, test._get_log()
 
324
                print >>self.stream, \
 
325
                        ('^^^^[log from %s]' % test.id()).ljust(78,'-')
 
326
            self.stream.writeln(self.separator2)
 
327
            self.stream.writeln("%s" % err)
 
328
 
 
329
 
 
330
class TextTestRunner(object):
 
331
    stop_on_failure = False
 
332
 
 
333
    def __init__(self,
 
334
                 stream=sys.stderr,
 
335
                 descriptions=0,
 
336
                 verbosity=1,
 
337
                 keep_output=False,
 
338
                 pb=None,
 
339
                 bench_history=None):
 
340
        self.stream = unittest._WritelnDecorator(stream)
 
341
        self.descriptions = descriptions
 
342
        self.verbosity = verbosity
 
343
        self.keep_output = keep_output
 
344
        self.pb = pb
 
345
        self._bench_history = bench_history
 
346
 
 
347
    def _makeResult(self):
 
348
        result = _MyResult(self.stream,
 
349
                           self.descriptions,
 
350
                           self.verbosity,
 
351
                           pb=self.pb,
 
352
                           bench_history=self._bench_history)
 
353
        result.stop_early = self.stop_on_failure
 
354
        return result
 
355
 
 
356
    def run(self, test):
 
357
        "Run the given test case or test suite."
 
358
        result = self._makeResult()
 
359
        startTime = time.time()
 
360
        if self.pb is not None:
 
361
            self.pb.update('Running tests', 0, test.countTestCases())
 
362
        test.run(result)
 
363
        stopTime = time.time()
 
364
        timeTaken = stopTime - startTime
 
365
        result.printErrors()
 
366
        self.stream.writeln(result.separator2)
 
367
        run = result.testsRun
 
368
        self.stream.writeln("Ran %d test%s in %.3fs" %
 
369
                            (run, run != 1 and "s" or "", timeTaken))
 
370
        self.stream.writeln()
 
371
        if not result.wasSuccessful():
 
372
            self.stream.write("FAILED (")
 
373
            failed, errored = map(len, (result.failures, result.errors))
 
374
            if failed:
 
375
                self.stream.write("failures=%d" % failed)
 
376
            if errored:
 
377
                if failed: self.stream.write(", ")
 
378
                self.stream.write("errors=%d" % errored)
 
379
            self.stream.writeln(")")
 
380
        else:
 
381
            self.stream.writeln("OK")
 
382
        if self.pb is not None:
 
383
            self.pb.update('Cleaning up', 0, 1)
 
384
        # This is still a little bogus, 
 
385
        # but only a little. Folk not using our testrunner will
 
386
        # have to delete their temp directories themselves.
 
387
        test_root = TestCaseInTempDir.TEST_ROOT
 
388
        if result.wasSuccessful() or not self.keep_output:
 
389
            if test_root is not None:
 
390
                # If LANG=C we probably have created some bogus paths
 
391
                # which rmtree(unicode) will fail to delete
 
392
                # so make sure we are using rmtree(str) to delete everything
 
393
                # except on win32, where rmtree(str) will fail
 
394
                # since it doesn't have the property of byte-stream paths
 
395
                # (they are either ascii or mbcs)
 
396
                if sys.platform == 'win32':
 
397
                    # make sure we are using the unicode win32 api
 
398
                    test_root = unicode(test_root)
 
399
                else:
 
400
                    test_root = test_root.encode(
 
401
                        sys.getfilesystemencoding())
 
402
                osutils.rmtree(test_root)
 
403
        else:
 
404
            if self.pb is not None:
 
405
                self.pb.note("Failed tests working directories are in '%s'\n",
 
406
                             test_root)
 
407
            else:
 
408
                self.stream.writeln(
 
409
                    "Failed tests working directories are in '%s'\n" %
 
410
                    test_root)
 
411
        TestCaseInTempDir.TEST_ROOT = None
 
412
        if self.pb is not None:
 
413
            self.pb.clear()
 
414
        return result
 
415
 
 
416
 
 
417
def iter_suite_tests(suite):
 
418
    """Return all tests in a suite, recursing through nested suites"""
 
419
    for item in suite._tests:
 
420
        if isinstance(item, unittest.TestCase):
 
421
            yield item
 
422
        elif isinstance(item, unittest.TestSuite):
 
423
            for r in iter_suite_tests(item):
 
424
                yield r
 
425
        else:
 
426
            raise Exception('unknown object %r inside test suite %r'
 
427
                            % (item, suite))
 
428
 
 
429
 
 
430
class TestSkipped(Exception):
 
431
    """Indicates that a test was intentionally skipped, rather than failing."""
 
432
 
36
433
 
37
434
class CommandFailed(Exception):
38
435
    pass
39
436
 
 
437
 
 
438
class StringIOWrapper(object):
 
439
    """A wrapper around cStringIO which just adds an encoding attribute.
 
440
    
 
441
    Internally we can check sys.stdout to see what the output encoding
 
442
    should be. However, cStringIO has no encoding attribute that we can
 
443
    set. So we wrap it instead.
 
444
    """
 
445
    encoding='ascii'
 
446
    _cstring = None
 
447
 
 
448
    def __init__(self, s=None):
 
449
        if s is not None:
 
450
            self.__dict__['_cstring'] = StringIO(s)
 
451
        else:
 
452
            self.__dict__['_cstring'] = StringIO()
 
453
 
 
454
    def __getattr__(self, name, getattr=getattr):
 
455
        return getattr(self.__dict__['_cstring'], name)
 
456
 
 
457
    def __setattr__(self, name, val):
 
458
        if name == 'encoding':
 
459
            self.__dict__['encoding'] = val
 
460
        else:
 
461
            return setattr(self._cstring, name, val)
 
462
 
 
463
 
40
464
class TestCase(unittest.TestCase):
41
465
    """Base class for bzr unit tests.
42
466
    
45
469
 
46
470
    Error and debug log messages are redirected from their usual
47
471
    location into a temporary file, the contents of which can be
48
 
    retrieved by _get_log().
 
472
    retrieved by _get_log().  We use a real OS file, not an in-memory object,
 
473
    so that it can also capture file IO.  When the test completes this file
 
474
    is read into memory and removed from disk.
49
475
       
50
476
    There are also convenience functions to invoke bzr's command-line
51
 
    routine, and to build and check bzr trees."""
52
 
 
53
 
    BZRPATH = 'bzr'
 
477
    routine, and to build and check bzr trees.
 
478
   
 
479
    In addition to the usual method of overriding tearDown(), this class also
 
480
    allows subclasses to register functions into the _cleanups list, which is
 
481
    run in order as the object is torn down.  It's less likely this will be
 
482
    accidentally overlooked.
 
483
    """
 
484
 
 
485
    _log_file_name = None
 
486
    _log_contents = ''
 
487
    # record lsprof data when performing benchmark calls.
 
488
    _gather_lsprof_in_benchmarks = False
 
489
 
 
490
    def __init__(self, methodName='testMethod'):
 
491
        super(TestCase, self).__init__(methodName)
 
492
        self._cleanups = []
54
493
 
55
494
    def setUp(self):
56
 
        # this replaces the default testsweet.TestCase; we don't want logging changed
57
495
        unittest.TestCase.setUp(self)
 
496
        self._cleanEnvironment()
58
497
        bzrlib.trace.disable_default_logging()
59
 
        self._enable_file_logging()
60
 
 
61
 
 
62
 
    def _enable_file_logging(self):
 
498
        self._startLogFile()
 
499
        self._benchcalls = []
 
500
        self._benchtime = None
 
501
 
 
502
    def _ndiff_strings(self, a, b):
 
503
        """Return ndiff between two strings containing lines.
 
504
        
 
505
        A trailing newline is added if missing to make the strings
 
506
        print properly."""
 
507
        if b and b[-1] != '\n':
 
508
            b += '\n'
 
509
        if a and a[-1] != '\n':
 
510
            a += '\n'
 
511
        difflines = difflib.ndiff(a.splitlines(True),
 
512
                                  b.splitlines(True),
 
513
                                  linejunk=lambda x: False,
 
514
                                  charjunk=lambda x: False)
 
515
        return ''.join(difflines)
 
516
 
 
517
    def assertEqualDiff(self, a, b, message=None):
 
518
        """Assert two texts are equal, if not raise an exception.
 
519
        
 
520
        This is intended for use with multi-line strings where it can 
 
521
        be hard to find the differences by eye.
 
522
        """
 
523
        # TODO: perhaps override assertEquals to call this for strings?
 
524
        if a == b:
 
525
            return
 
526
        if message is None:
 
527
            message = "texts not equal:\n"
 
528
        raise AssertionError(message + 
 
529
                             self._ndiff_strings(a, b))      
 
530
        
 
531
    def assertEqualMode(self, mode, mode_test):
 
532
        self.assertEqual(mode, mode_test,
 
533
                         'mode mismatch %o != %o' % (mode, mode_test))
 
534
 
 
535
    def assertStartsWith(self, s, prefix):
 
536
        if not s.startswith(prefix):
 
537
            raise AssertionError('string %r does not start with %r' % (s, prefix))
 
538
 
 
539
    def assertEndsWith(self, s, suffix):
 
540
        """Asserts that s ends with suffix."""
 
541
        if not s.endswith(suffix):
 
542
            raise AssertionError('string %r does not end with %r' % (s, suffix))
 
543
 
 
544
    def assertContainsRe(self, haystack, needle_re):
 
545
        """Assert that a contains something matching a regular expression."""
 
546
        if not re.search(needle_re, haystack):
 
547
            raise AssertionError('pattern "%s" not found in "%s"'
 
548
                    % (needle_re, haystack))
 
549
 
 
550
    def assertNotContainsRe(self, haystack, needle_re):
 
551
        """Assert that a does not match a regular expression"""
 
552
        if re.search(needle_re, haystack):
 
553
            raise AssertionError('pattern "%s" found in "%s"'
 
554
                    % (needle_re, haystack))
 
555
 
 
556
    def assertSubset(self, sublist, superlist):
 
557
        """Assert that every entry in sublist is present in superlist."""
 
558
        missing = []
 
559
        for entry in sublist:
 
560
            if entry not in superlist:
 
561
                missing.append(entry)
 
562
        if len(missing) > 0:
 
563
            raise AssertionError("value(s) %r not present in container %r" % 
 
564
                                 (missing, superlist))
 
565
 
 
566
    def assertIs(self, left, right):
 
567
        if not (left is right):
 
568
            raise AssertionError("%r is not %r." % (left, right))
 
569
 
 
570
    def assertTransportMode(self, transport, path, mode):
 
571
        """Fail if a path does not have mode mode.
 
572
        
 
573
        If modes are not supported on this transport, the assertion is ignored.
 
574
        """
 
575
        if not transport._can_roundtrip_unix_modebits():
 
576
            return
 
577
        path_stat = transport.stat(path)
 
578
        actual_mode = stat.S_IMODE(path_stat.st_mode)
 
579
        self.assertEqual(mode, actual_mode,
 
580
            'mode of %r incorrect (%o != %o)' % (path, mode, actual_mode))
 
581
 
 
582
    def assertIsInstance(self, obj, kls):
 
583
        """Fail if obj is not an instance of kls"""
 
584
        if not isinstance(obj, kls):
 
585
            self.fail("%r is an instance of %s rather than %s" % (
 
586
                obj, obj.__class__, kls))
 
587
 
 
588
    def _capture_warnings(self, a_callable, *args, **kwargs):
 
589
        """A helper for callDeprecated and applyDeprecated.
 
590
 
 
591
        :param a_callable: A callable to call.
 
592
        :param args: The positional arguments for the callable
 
593
        :param kwargs: The keyword arguments for the callable
 
594
        :return: A tuple (warnings, result). result is the result of calling
 
595
            a_callable(*args, **kwargs).
 
596
        """
 
597
        local_warnings = []
 
598
        def capture_warnings(msg, cls, stacklevel=None):
 
599
            # we've hooked into a deprecation specific callpath,
 
600
            # only deprecations should getting sent via it.
 
601
            self.assertEqual(cls, DeprecationWarning)
 
602
            local_warnings.append(msg)
 
603
        original_warning_method = symbol_versioning.warn
 
604
        symbol_versioning.set_warning_method(capture_warnings)
 
605
        try:
 
606
            result = a_callable(*args, **kwargs)
 
607
        finally:
 
608
            symbol_versioning.set_warning_method(original_warning_method)
 
609
        return (local_warnings, result)
 
610
 
 
611
    def applyDeprecated(self, deprecation_format, a_callable, *args, **kwargs):
 
612
        """Call a deprecated callable without warning the user.
 
613
 
 
614
        :param deprecation_format: The deprecation format that the callable
 
615
            should have been deprecated with. This is the same type as the 
 
616
            parameter to deprecated_method/deprecated_function. If the 
 
617
            callable is not deprecated with this format, an assertion error
 
618
            will be raised.
 
619
        :param a_callable: A callable to call. This may be a bound method or
 
620
            a regular function. It will be called with *args and **kwargs.
 
621
        :param args: The positional arguments for the callable
 
622
        :param kwargs: The keyword arguments for the callable
 
623
        :return: The result of a_callable(*args, **kwargs)
 
624
        """
 
625
        call_warnings, result = self._capture_warnings(a_callable,
 
626
            *args, **kwargs)
 
627
        expected_first_warning = symbol_versioning.deprecation_string(
 
628
            a_callable, deprecation_format)
 
629
        if len(call_warnings) == 0:
 
630
            self.fail("No assertion generated by call to %s" %
 
631
                a_callable)
 
632
        self.assertEqual(expected_first_warning, call_warnings[0])
 
633
        return result
 
634
 
 
635
    def callDeprecated(self, expected, callable, *args, **kwargs):
 
636
        """Assert that a callable is deprecated in a particular way.
 
637
 
 
638
        This is a very precise test for unusual requirements. The 
 
639
        applyDeprecated helper function is probably more suited for most tests
 
640
        as it allows you to simply specify the deprecation format being used
 
641
        and will ensure that that is issued for the function being called.
 
642
 
 
643
        :param expected: a list of the deprecation warnings expected, in order
 
644
        :param callable: The callable to call
 
645
        :param args: The positional arguments for the callable
 
646
        :param kwargs: The keyword arguments for the callable
 
647
        """
 
648
        call_warnings, result = self._capture_warnings(callable,
 
649
            *args, **kwargs)
 
650
        self.assertEqual(expected, call_warnings)
 
651
        return result
 
652
 
 
653
    def _startLogFile(self):
 
654
        """Send bzr and test log messages to a temporary file.
 
655
 
 
656
        The file is removed as the test is torn down.
 
657
        """
63
658
        fileno, name = tempfile.mkstemp(suffix='.log', prefix='testbzr')
64
 
 
65
659
        self._log_file = os.fdopen(fileno, 'w+')
66
 
 
67
 
        hdlr = logging.StreamHandler(self._log_file)
68
 
        hdlr.setLevel(logging.DEBUG)
69
 
        hdlr.setFormatter(logging.Formatter('%(levelname)8s  %(message)s'))
70
 
        logging.getLogger('').addHandler(hdlr)
71
 
        logging.getLogger('').setLevel(logging.DEBUG)
72
 
        self._log_hdlr = hdlr
73
 
        debug('opened log file %s', name)
74
 
        
 
660
        self._log_nonce = bzrlib.trace.enable_test_log(self._log_file)
75
661
        self._log_file_name = name
76
 
 
77
 
        
78
 
    def tearDown(self):
79
 
        logging.getLogger('').removeHandler(self._log_hdlr)
80
 
        bzrlib.trace.enable_default_logging()
81
 
        logging.debug('%s teardown', self.id())
 
662
        self.addCleanup(self._finishLogFile)
 
663
 
 
664
    def _finishLogFile(self):
 
665
        """Finished with the log file.
 
666
 
 
667
        Read contents into memory, close, and delete.
 
668
        """
 
669
        if self._log_file is None:
 
670
            return
 
671
        bzrlib.trace.disable_test_log(self._log_nonce)
 
672
        self._log_file.seek(0)
 
673
        self._log_contents = self._log_file.read()
82
674
        self._log_file.close()
 
675
        os.remove(self._log_file_name)
 
676
        self._log_file = self._log_file_name = None
 
677
 
 
678
    def addCleanup(self, callable):
 
679
        """Arrange to run a callable when this case is torn down.
 
680
 
 
681
        Callables are run in the reverse of the order they are registered, 
 
682
        ie last-in first-out.
 
683
        """
 
684
        if callable in self._cleanups:
 
685
            raise ValueError("cleanup function %r already registered on %s" 
 
686
                    % (callable, self))
 
687
        self._cleanups.append(callable)
 
688
 
 
689
    def _cleanEnvironment(self):
 
690
        new_env = {
 
691
            'HOME': os.getcwd(),
 
692
            'APPDATA': os.getcwd(),
 
693
            'BZR_EMAIL': None,
 
694
            'BZREMAIL': None, # may still be present in the environment
 
695
            'EMAIL': None,
 
696
            'BZR_PROGRESS_BAR': None,
 
697
        }
 
698
        self.__old_env = {}
 
699
        self.addCleanup(self._restoreEnvironment)
 
700
        for name, value in new_env.iteritems():
 
701
            self._captureVar(name, value)
 
702
 
 
703
    def _captureVar(self, name, newvalue):
 
704
        """Set an environment variable, and reset it when finished."""
 
705
        self.__old_env[name] = osutils.set_or_unset_env(name, newvalue)
 
706
 
 
707
    def _restoreEnvironment(self):
 
708
        for name, value in self.__old_env.iteritems():
 
709
            osutils.set_or_unset_env(name, value)
 
710
 
 
711
    def tearDown(self):
 
712
        self._runCleanups()
83
713
        unittest.TestCase.tearDown(self)
84
714
 
 
715
    def time(self, callable, *args, **kwargs):
 
716
        """Run callable and accrue the time it takes to the benchmark time.
 
717
        
 
718
        If lsprofiling is enabled (i.e. by --lsprof-time to bzr selftest) then
 
719
        this will cause lsprofile statistics to be gathered and stored in
 
720
        self._benchcalls.
 
721
        """
 
722
        if self._benchtime is None:
 
723
            self._benchtime = 0
 
724
        start = time.time()
 
725
        try:
 
726
            if not self._gather_lsprof_in_benchmarks:
 
727
                return callable(*args, **kwargs)
 
728
            else:
 
729
                # record this benchmark
 
730
                ret, stats = bzrlib.lsprof.profile(callable, *args, **kwargs)
 
731
                stats.sort()
 
732
                self._benchcalls.append(((callable, args, kwargs), stats))
 
733
                return ret
 
734
        finally:
 
735
            self._benchtime += time.time() - start
 
736
 
 
737
    def _runCleanups(self):
 
738
        """Run registered cleanup functions. 
 
739
 
 
740
        This should only be called from TestCase.tearDown.
 
741
        """
 
742
        # TODO: Perhaps this should keep running cleanups even if 
 
743
        # one of them fails?
 
744
        for cleanup_fn in reversed(self._cleanups):
 
745
            cleanup_fn()
85
746
 
86
747
    def log(self, *args):
87
 
        logging.debug(*args)
 
748
        mutter(*args)
88
749
 
89
750
    def _get_log(self):
90
751
        """Return as a string the log for this test"""
91
 
        return open(self._log_file_name).read()
 
752
        if self._log_file_name:
 
753
            return open(self._log_file_name).read()
 
754
        else:
 
755
            return self._log_contents
 
756
        # TODO: Delete the log after it's been read in
 
757
 
 
758
    def capture(self, cmd, retcode=0):
 
759
        """Shortcut that splits cmd into words, runs, and returns stdout"""
 
760
        return self.run_bzr_captured(cmd.split(), retcode=retcode)[0]
 
761
 
 
762
    def run_bzr_captured(self, argv, retcode=0, encoding=None, stdin=None):
 
763
        """Invoke bzr and return (stdout, stderr).
 
764
 
 
765
        Useful for code that wants to check the contents of the
 
766
        output, the way error messages are presented, etc.
 
767
 
 
768
        This should be the main method for tests that want to exercise the
 
769
        overall behavior of the bzr application (rather than a unit test
 
770
        or a functional test of the library.)
 
771
 
 
772
        Much of the old code runs bzr by forking a new copy of Python, but
 
773
        that is slower, harder to debug, and generally not necessary.
 
774
 
 
775
        This runs bzr through the interface that catches and reports
 
776
        errors, and with logging set to something approximating the
 
777
        default, so that error reporting can be checked.
 
778
 
 
779
        :param argv: arguments to invoke bzr
 
780
        :param retcode: expected return code, or None for don't-care.
 
781
        :param encoding: encoding for sys.stdout and sys.stderr
 
782
        :param stdin: A string to be used as stdin for the command.
 
783
        """
 
784
        if encoding is None:
 
785
            encoding = bzrlib.user_encoding
 
786
        if stdin is not None:
 
787
            stdin = StringIO(stdin)
 
788
        stdout = StringIOWrapper()
 
789
        stderr = StringIOWrapper()
 
790
        stdout.encoding = encoding
 
791
        stderr.encoding = encoding
 
792
 
 
793
        self.log('run bzr: %r', argv)
 
794
        # FIXME: don't call into logging here
 
795
        handler = logging.StreamHandler(stderr)
 
796
        handler.setLevel(logging.INFO)
 
797
        logger = logging.getLogger('')
 
798
        logger.addHandler(handler)
 
799
        old_ui_factory = bzrlib.ui.ui_factory
 
800
        bzrlib.ui.ui_factory = bzrlib.tests.blackbox.TestUIFactory(
 
801
            stdout=stdout,
 
802
            stderr=stderr)
 
803
        bzrlib.ui.ui_factory.stdin = stdin
 
804
        try:
 
805
            result = self.apply_redirected(stdin, stdout, stderr,
 
806
                                           bzrlib.commands.run_bzr_catch_errors,
 
807
                                           argv)
 
808
        finally:
 
809
            logger.removeHandler(handler)
 
810
            bzrlib.ui.ui_factory = old_ui_factory
 
811
 
 
812
        out = stdout.getvalue()
 
813
        err = stderr.getvalue()
 
814
        if out:
 
815
            self.log('output:\n%r', out)
 
816
        if err:
 
817
            self.log('errors:\n%r', err)
 
818
        if retcode is not None:
 
819
            self.assertEquals(retcode, result)
 
820
        return out, err
92
821
 
93
822
    def run_bzr(self, *args, **kwargs):
94
823
        """Invoke bzr, as if it were run from the command line.
97
826
        overall behavior of the bzr application (rather than a unit test
98
827
        or a functional test of the library.)
99
828
 
100
 
        Much of the old code runs bzr by forking a new copy of Python, but
101
 
        that is slower, harder to debug, and generally not necessary.
102
 
        """
103
 
        retcode = kwargs.get('retcode', 0)
104
 
        result = self.apply_redirected(None, None, None,
105
 
                                       bzrlib.commands.run_bzr, args)
106
 
        self.assertEquals(result, retcode)
107
 
        
108
 
        
 
829
        This sends the stdout/stderr results into the test's log,
 
830
        where it may be useful for debugging.  See also run_captured.
 
831
 
 
832
        :param stdin: A string to be used as stdin for the command.
 
833
        """
 
834
        retcode = kwargs.pop('retcode', 0)
 
835
        encoding = kwargs.pop('encoding', None)
 
836
        stdin = kwargs.pop('stdin', None)
 
837
        return self.run_bzr_captured(args, retcode=retcode, encoding=encoding, stdin=stdin)
 
838
 
 
839
    def run_bzr_decode(self, *args, **kwargs):
 
840
        if 'encoding' in kwargs:
 
841
            encoding = kwargs['encoding']
 
842
        else:
 
843
            encoding = bzrlib.user_encoding
 
844
        return self.run_bzr(*args, **kwargs)[0].decode(encoding)
 
845
 
 
846
    def run_bzr_error(self, error_regexes, *args, **kwargs):
 
847
        """Run bzr, and check that stderr contains the supplied regexes
 
848
        
 
849
        :param error_regexes: Sequence of regular expressions which 
 
850
            must each be found in the error output. The relative ordering
 
851
            is not enforced.
 
852
        :param args: command-line arguments for bzr
 
853
        :param kwargs: Keyword arguments which are interpreted by run_bzr
 
854
            This function changes the default value of retcode to be 3,
 
855
            since in most cases this is run when you expect bzr to fail.
 
856
        :return: (out, err) The actual output of running the command (in case you
 
857
                 want to do more inspection)
 
858
 
 
859
        Examples of use:
 
860
            # Make sure that commit is failing because there is nothing to do
 
861
            self.run_bzr_error(['no changes to commit'],
 
862
                               'commit', '-m', 'my commit comment')
 
863
            # Make sure --strict is handling an unknown file, rather than
 
864
            # giving us the 'nothing to do' error
 
865
            self.build_tree(['unknown'])
 
866
            self.run_bzr_error(['Commit refused because there are unknown files'],
 
867
                               'commit', '--strict', '-m', 'my commit comment')
 
868
        """
 
869
        kwargs.setdefault('retcode', 3)
 
870
        out, err = self.run_bzr(*args, **kwargs)
 
871
        for regex in error_regexes:
 
872
            self.assertContainsRe(err, regex)
 
873
        return out, err
 
874
 
 
875
    def run_bzr_subprocess(self, *args, **kwargs):
 
876
        """Run bzr in a subprocess for testing.
 
877
 
 
878
        This starts a new Python interpreter and runs bzr in there. 
 
879
        This should only be used for tests that have a justifiable need for
 
880
        this isolation: e.g. they are testing startup time, or signal
 
881
        handling, or early startup code, etc.  Subprocess code can't be 
 
882
        profiled or debugged so easily.
 
883
 
 
884
        :param retcode: The status code that is expected.  Defaults to 0.  If
 
885
            None is supplied, the status code is not checked.
 
886
        :param env_changes: A dictionary which lists changes to environment
 
887
            variables. A value of None will unset the env variable.
 
888
            The values must be strings. The change will only occur in the
 
889
            child, so you don't need to fix the environment after running.
 
890
        :param universal_newlines: Convert CRLF => LF
 
891
        """
 
892
        env_changes = kwargs.get('env_changes', {})
 
893
        process = self.start_bzr_subprocess(args, env_changes=env_changes)
 
894
        # We distinguish between retcode=None and retcode not passed.
 
895
        supplied_retcode = kwargs.get('retcode', 0)
 
896
        return self.finish_bzr_subprocess(process, retcode=supplied_retcode,
 
897
            universal_newlines=kwargs.get('universal_newlines', False),
 
898
            process_args=args)
 
899
 
 
900
    def start_bzr_subprocess(self, process_args, env_changes=None,
 
901
                             skip_if_plan_to_signal=False):
 
902
        """Start bzr in a subprocess for testing.
 
903
 
 
904
        This starts a new Python interpreter and runs bzr in there.
 
905
        This should only be used for tests that have a justifiable need for
 
906
        this isolation: e.g. they are testing startup time, or signal
 
907
        handling, or early startup code, etc.  Subprocess code can't be
 
908
        profiled or debugged so easily.
 
909
 
 
910
        :param process_args: a list of arguments to pass to the bzr executable,
 
911
            for example `['--version']`.
 
912
        :param env_changes: A dictionary which lists changes to environment
 
913
            variables. A value of None will unset the env variable.
 
914
            The values must be strings. The change will only occur in the
 
915
            child, so you don't need to fix the environment after running.
 
916
        :param skip_if_plan_to_signal: raise TestSkipped when true and os.kill
 
917
            is not available.
 
918
 
 
919
        :returns: Popen object for the started process.
 
920
        """
 
921
        if skip_if_plan_to_signal:
 
922
            if not getattr(os, 'kill', None):
 
923
                raise TestSkipped("os.kill not available.")
 
924
 
 
925
        if env_changes is None:
 
926
            env_changes = {}
 
927
        old_env = {}
 
928
 
 
929
        def cleanup_environment():
 
930
            for env_var, value in env_changes.iteritems():
 
931
                old_env[env_var] = osutils.set_or_unset_env(env_var, value)
 
932
 
 
933
        def restore_environment():
 
934
            for env_var, value in old_env.iteritems():
 
935
                osutils.set_or_unset_env(env_var, value)
 
936
 
 
937
        bzr_path = self.get_bzr_path()
 
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
                             stdin=PIPE, stdout=PIPE, stderr=PIPE)
 
946
        finally:
 
947
            restore_environment()
 
948
        return process
 
949
 
 
950
    def get_bzr_path(self):
 
951
        """Return the path of the 'bzr' executable for this test suite."""
 
952
        bzr_path = os.path.dirname(os.path.dirname(bzrlib.__file__))+'/bzr'
 
953
        if not os.path.isfile(bzr_path):
 
954
            # We are probably installed. Assume sys.argv is the right file
 
955
            bzr_path = sys.argv[0]
 
956
        return bzr_path
 
957
 
 
958
    def finish_bzr_subprocess(self, process, retcode=0, send_signal=None,
 
959
                              universal_newlines=False, process_args=None):
 
960
        """Finish the execution of process.
 
961
 
 
962
        :param process: the Popen object returned from start_bzr_subprocess.
 
963
        :param retcode: The status code that is expected.  Defaults to 0.  If
 
964
            None is supplied, the status code is not checked.
 
965
        :param send_signal: an optional signal to send to the process.
 
966
        :param universal_newlines: Convert CRLF => LF
 
967
        :returns: (stdout, stderr)
 
968
        """
 
969
        if send_signal is not None:
 
970
            os.kill(process.pid, send_signal)
 
971
        out, err = process.communicate()
 
972
 
 
973
        if universal_newlines:
 
974
            out = out.replace('\r\n', '\n')
 
975
            err = err.replace('\r\n', '\n')
 
976
 
 
977
        if retcode is not None and retcode != process.returncode:
 
978
            if process_args is None:
 
979
                process_args = "(unknown args)"
 
980
            mutter('Output of bzr %s:\n%s', process_args, out)
 
981
            mutter('Error for bzr %s:\n%s', process_args, err)
 
982
            self.fail('Command bzr %s failed with retcode %s != %s'
 
983
                      % (process_args, retcode, process.returncode))
 
984
        return [out, err]
 
985
 
109
986
    def check_inventory_shape(self, inv, shape):
110
 
        """
111
 
        Compare an inventory to a list of expected names.
 
987
        """Compare an inventory to a list of expected names.
112
988
 
113
989
        Fail if they are not precisely equal.
114
990
        """
132
1008
        """Call callable with redirected std io pipes.
133
1009
 
134
1010
        Returns the return code."""
135
 
        from StringIO import StringIO
136
1011
        if not callable(a_callable):
137
1012
            raise ValueError("a_callable must be callable.")
138
1013
        if stdin is None:
139
1014
            stdin = StringIO("")
140
1015
        if stdout is None:
141
 
            stdout = self._log_file
 
1016
            if getattr(self, "_log_file", None) is not None:
 
1017
                stdout = self._log_file
 
1018
            else:
 
1019
                stdout = StringIO()
142
1020
        if stderr is None:
143
 
            stderr = self._log_file
 
1021
            if getattr(self, "_log_file", None is not None):
 
1022
                stderr = self._log_file
 
1023
            else:
 
1024
                stderr = StringIO()
144
1025
        real_stdin = sys.stdin
145
1026
        real_stdout = sys.stdout
146
1027
        real_stderr = sys.stderr
154
1035
            sys.stderr = real_stderr
155
1036
            sys.stdin = real_stdin
156
1037
 
 
1038
    @symbol_versioning.deprecated_method(symbol_versioning.zero_eleven)
 
1039
    def merge(self, branch_from, wt_to):
 
1040
        """A helper for tests to do a ui-less merge.
 
1041
 
 
1042
        This should move to the main library when someone has time to integrate
 
1043
        it in.
 
1044
        """
 
1045
        # minimal ui-less merge.
 
1046
        wt_to.branch.fetch(branch_from)
 
1047
        base_rev = common_ancestor(branch_from.last_revision(),
 
1048
                                   wt_to.branch.last_revision(),
 
1049
                                   wt_to.branch.repository)
 
1050
        merge_inner(wt_to.branch, branch_from.basis_tree(),
 
1051
                    wt_to.branch.repository.revision_tree(base_rev),
 
1052
                    this_tree=wt_to)
 
1053
        wt_to.add_parent_tree_id(branch_from.last_revision())
 
1054
 
157
1055
 
158
1056
BzrTestBase = TestCase
159
1057
 
181
1079
        if contents != expect:
182
1080
            self.log("expected: %r" % expect)
183
1081
            self.log("actually: %r" % contents)
184
 
            self.fail("contents of %s not as expected")
 
1082
            self.fail("contents of %s not as expected" % filename)
185
1083
 
186
1084
    def _make_test_root(self):
187
 
        import os
188
 
        import shutil
189
 
        import tempfile
190
 
        
191
1085
        if TestCaseInTempDir.TEST_ROOT is not None:
192
1086
            return
193
 
        TestCaseInTempDir.TEST_ROOT = os.path.abspath(
194
 
                                 tempfile.mkdtemp(suffix='.tmp',
195
 
                                                  prefix=self._TEST_NAME + '-',
196
 
                                                  dir=os.curdir))
197
 
    
 
1087
        i = 0
 
1088
        while True:
 
1089
            root = u'test%04d.tmp' % i
 
1090
            try:
 
1091
                os.mkdir(root)
 
1092
            except OSError, e:
 
1093
                if e.errno == errno.EEXIST:
 
1094
                    i += 1
 
1095
                    continue
 
1096
                else:
 
1097
                    raise
 
1098
            # successfully created
 
1099
            TestCaseInTempDir.TEST_ROOT = osutils.abspath(root)
 
1100
            break
198
1101
        # make a fake bzr directory there to prevent any tests propagating
199
1102
        # up onto the source directory's real branch
200
 
        os.mkdir(os.path.join(TestCaseInTempDir.TEST_ROOT, '.bzr'))
 
1103
        bzrdir.BzrDir.create_standalone_workingtree(TestCaseInTempDir.TEST_ROOT)
201
1104
 
202
1105
    def setUp(self):
203
1106
        super(TestCaseInTempDir, self).setUp()
204
 
        import os
205
1107
        self._make_test_root()
206
 
        self._currentdir = os.getcwdu()
207
 
        short_id = self.id().replace('bzrlib.selftest.', '')
208
 
        self.test_dir = os.path.join(self.TEST_ROOT, short_id)
209
 
        os.mkdir(self.test_dir)
210
 
        os.chdir(self.test_dir)
 
1108
        _currentdir = os.getcwdu()
 
1109
        # shorten the name, to avoid test failures due to path length
 
1110
        short_id = self.id().replace('bzrlib.tests.', '') \
 
1111
                   .replace('__main__.', '')[-100:]
 
1112
        # it's possible the same test class is run several times for
 
1113
        # parameterized tests, so make sure the names don't collide.  
 
1114
        i = 0
 
1115
        while True:
 
1116
            if i > 0:
 
1117
                candidate_dir = '%s/%s.%d' % (self.TEST_ROOT, short_id, i)
 
1118
            else:
 
1119
                candidate_dir = '%s/%s' % (self.TEST_ROOT, short_id)
 
1120
            if os.path.exists(candidate_dir):
 
1121
                i = i + 1
 
1122
                continue
 
1123
            else:
 
1124
                os.mkdir(candidate_dir)
 
1125
                self.test_home_dir = candidate_dir + '/home'
 
1126
                os.mkdir(self.test_home_dir)
 
1127
                self.test_dir = candidate_dir + '/work'
 
1128
                os.mkdir(self.test_dir)
 
1129
                os.chdir(self.test_dir)
 
1130
                break
 
1131
        os.environ['HOME'] = self.test_home_dir
 
1132
        os.environ['APPDATA'] = self.test_home_dir
 
1133
        def _leaveDirectory():
 
1134
            os.chdir(_currentdir)
 
1135
        self.addCleanup(_leaveDirectory)
211
1136
        
212
 
    def tearDown(self):
213
 
        import os
214
 
        os.chdir(self._currentdir)
215
 
        super(TestCaseInTempDir, self).tearDown()
216
 
 
217
 
    def _formcmd(self, cmd):
218
 
        if isinstance(cmd, basestring):
219
 
            cmd = cmd.split()
220
 
        if cmd[0] == 'bzr':
221
 
            cmd[0] = self.BZRPATH
222
 
            if self.OVERRIDE_PYTHON:
223
 
                cmd.insert(0, self.OVERRIDE_PYTHON)
224
 
        self.log('$ %r' % cmd)
225
 
        return cmd
226
 
 
227
 
    def runcmd(self, cmd, retcode=0):
228
 
        """Run one command and check the return code.
229
 
 
230
 
        Returns a tuple of (stdout,stderr) strings.
231
 
 
232
 
        If a single string is based, it is split into words.
233
 
        For commands that are not simple space-separated words, please
234
 
        pass a list instead."""
235
 
        cmd = self._formcmd(cmd)
236
 
        self.log('$ ' + ' '.join(cmd))
237
 
        actual_retcode = subprocess.call(cmd, stdout=self._log_file,
238
 
                                         stderr=self._log_file)
239
 
        if retcode != actual_retcode:
240
 
            raise CommandFailed("test failed: %r returned %d, expected %d"
241
 
                                % (cmd, actual_retcode, retcode))
242
 
 
243
 
    def backtick(self, cmd, retcode=0):
244
 
        """Run a command and return its output"""
245
 
        cmd = self._formcmd(cmd)
246
 
        child = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=self._log_file)
247
 
        outd, errd = child.communicate()
248
 
        self.log(outd)
249
 
        actual_retcode = child.wait()
250
 
 
251
 
        outd = outd.replace('\r', '')
252
 
 
253
 
        if retcode != actual_retcode:
254
 
            raise CommandFailed("test failed: %r returned %d, expected %d"
255
 
                                % (cmd, actual_retcode, retcode))
256
 
 
257
 
        return outd
258
 
 
259
 
 
260
 
 
261
 
    def build_tree(self, shape):
 
1137
    def build_tree(self, shape, line_endings='native', transport=None):
262
1138
        """Build a test tree according to a pattern.
263
1139
 
264
1140
        shape is a sequence of file specifications.  If the final
265
1141
        character is '/', a directory is created.
266
1142
 
 
1143
        This assumes that all the elements in the tree being built are new.
 
1144
 
267
1145
        This doesn't add anything to a branch.
 
1146
        :param line_endings: Either 'binary' or 'native'
 
1147
                             in binary mode, exact contents are written
 
1148
                             in native mode, the line endings match the
 
1149
                             default platform endings.
 
1150
 
 
1151
        :param transport: A transport to write to, for building trees on 
 
1152
                          VFS's. If the transport is readonly or None,
 
1153
                          "." is opened automatically.
268
1154
        """
269
 
        # XXX: It's OK to just create them using forward slashes on windows?
270
 
        import os
 
1155
        # It's OK to just create them using forward slashes on windows.
 
1156
        if transport is None or transport.is_readonly():
 
1157
            transport = get_transport(".")
271
1158
        for name in shape:
272
 
            assert isinstance(name, basestring)
 
1159
            self.assert_(isinstance(name, basestring))
273
1160
            if name[-1] == '/':
274
 
                os.mkdir(name[:-1])
275
 
            else:
276
 
                f = file(name, 'wt')
277
 
                print >>f, "contents of", name
278
 
                f.close()
279
 
                
280
 
 
281
 
 
282
 
class MetaTestLog(TestCase):
283
 
    def test_logging(self):
284
 
        """Test logs are captured when a test fails."""
285
 
        logging.info('an info message')
286
 
        warning('something looks dodgy...')
287
 
        logging.debug('hello, test is running')
288
 
        ##assert 0
289
 
 
290
 
 
291
 
def selftest(verbose=False, pattern=".*"):
 
1161
                transport.mkdir(urlutils.escape(name[:-1]))
 
1162
            else:
 
1163
                if line_endings == 'binary':
 
1164
                    end = '\n'
 
1165
                elif line_endings == 'native':
 
1166
                    end = os.linesep
 
1167
                else:
 
1168
                    raise errors.BzrError('Invalid line ending request %r' % (line_endings,))
 
1169
                content = "contents of %s%s" % (name.encode('utf-8'), end)
 
1170
                # Technically 'put()' is the right command. However, put
 
1171
                # uses an AtomicFile, which requires an extra rename into place
 
1172
                # As long as the files didn't exist in the past, append() will
 
1173
                # do the same thing as put()
 
1174
                # On jam's machine, make_kernel_like_tree is:
 
1175
                #   put:    4.5-7.5s (averaging 6s)
 
1176
                #   append: 2.9-4.5s
 
1177
                #   put_non_atomic: 2.9-4.5s
 
1178
                transport.put_bytes_non_atomic(urlutils.escape(name), content)
 
1179
 
 
1180
    def build_tree_contents(self, shape):
 
1181
        build_tree_contents(shape)
 
1182
 
 
1183
    def failUnlessExists(self, path):
 
1184
        """Fail unless path, which may be abs or relative, exists."""
 
1185
        self.failUnless(osutils.lexists(path))
 
1186
 
 
1187
    def failIfExists(self, path):
 
1188
        """Fail if path, which may be abs or relative, exists."""
 
1189
        self.failIf(osutils.lexists(path))
 
1190
        
 
1191
    def assertFileEqual(self, content, path):
 
1192
        """Fail if path does not contain 'content'."""
 
1193
        self.failUnless(osutils.lexists(path))
 
1194
        # TODO: jam 20060427 Shouldn't this be 'rb'?
 
1195
        self.assertEqualDiff(content, open(path, 'r').read())
 
1196
 
 
1197
 
 
1198
class TestCaseWithTransport(TestCaseInTempDir):
 
1199
    """A test case that provides get_url and get_readonly_url facilities.
 
1200
 
 
1201
    These back onto two transport servers, one for readonly access and one for
 
1202
    read write access.
 
1203
 
 
1204
    If no explicit class is provided for readonly access, a
 
1205
    ReadonlyTransportDecorator is used instead which allows the use of non disk
 
1206
    based read write transports.
 
1207
 
 
1208
    If an explicit class is provided for readonly access, that server and the 
 
1209
    readwrite one must both define get_url() as resolving to os.getcwd().
 
1210
    """
 
1211
 
 
1212
    def __init__(self, methodName='testMethod'):
 
1213
        super(TestCaseWithTransport, self).__init__(methodName)
 
1214
        self.__readonly_server = None
 
1215
        self.__server = None
 
1216
        self.transport_server = default_transport
 
1217
        self.transport_readonly_server = None
 
1218
 
 
1219
    def get_readonly_url(self, relpath=None):
 
1220
        """Get a URL for the readonly transport.
 
1221
 
 
1222
        This will either be backed by '.' or a decorator to the transport 
 
1223
        used by self.get_url()
 
1224
        relpath provides for clients to get a path relative to the base url.
 
1225
        These should only be downwards relative, not upwards.
 
1226
        """
 
1227
        base = self.get_readonly_server().get_url()
 
1228
        if relpath is not None:
 
1229
            if not base.endswith('/'):
 
1230
                base = base + '/'
 
1231
            base = base + relpath
 
1232
        return base
 
1233
 
 
1234
    def get_readonly_server(self):
 
1235
        """Get the server instance for the readonly transport
 
1236
 
 
1237
        This is useful for some tests with specific servers to do diagnostics.
 
1238
        """
 
1239
        if self.__readonly_server is None:
 
1240
            if self.transport_readonly_server is None:
 
1241
                # readonly decorator requested
 
1242
                # bring up the server
 
1243
                self.get_url()
 
1244
                self.__readonly_server = ReadonlyServer()
 
1245
                self.__readonly_server.setUp(self.__server)
 
1246
            else:
 
1247
                self.__readonly_server = self.transport_readonly_server()
 
1248
                self.__readonly_server.setUp()
 
1249
            self.addCleanup(self.__readonly_server.tearDown)
 
1250
        return self.__readonly_server
 
1251
 
 
1252
    def get_server(self):
 
1253
        """Get the read/write server instance.
 
1254
 
 
1255
        This is useful for some tests with specific servers that need
 
1256
        diagnostics.
 
1257
        """
 
1258
        if self.__server is None:
 
1259
            self.__server = self.transport_server()
 
1260
            self.__server.setUp()
 
1261
            self.addCleanup(self.__server.tearDown)
 
1262
        return self.__server
 
1263
 
 
1264
    def get_url(self, relpath=None):
 
1265
        """Get a URL (or maybe a path) for the readwrite transport.
 
1266
 
 
1267
        This will either be backed by '.' or to an equivalent non-file based
 
1268
        facility.
 
1269
        relpath provides for clients to get a path relative to the base url.
 
1270
        These should only be downwards relative, not upwards.
 
1271
        """
 
1272
        base = self.get_server().get_url()
 
1273
        if relpath is not None and relpath != '.':
 
1274
            if not base.endswith('/'):
 
1275
                base = base + '/'
 
1276
            # XXX: Really base should be a url; we did after all call
 
1277
            # get_url()!  But sometimes it's just a path (from
 
1278
            # LocalAbspathServer), and it'd be wrong to append urlescaped data
 
1279
            # to a non-escaped local path.
 
1280
            if base.startswith('./') or base.startswith('/'):
 
1281
                base += relpath
 
1282
            else:
 
1283
                base += urlutils.escape(relpath)
 
1284
        return base
 
1285
 
 
1286
    def get_transport(self):
 
1287
        """Return a writeable transport for the test scratch space"""
 
1288
        t = get_transport(self.get_url())
 
1289
        self.assertFalse(t.is_readonly())
 
1290
        return t
 
1291
 
 
1292
    def get_readonly_transport(self):
 
1293
        """Return a readonly transport for the test scratch space
 
1294
        
 
1295
        This can be used to test that operations which should only need
 
1296
        readonly access in fact do not try to write.
 
1297
        """
 
1298
        t = get_transport(self.get_readonly_url())
 
1299
        self.assertTrue(t.is_readonly())
 
1300
        return t
 
1301
 
 
1302
    def make_branch(self, relpath, format=None):
 
1303
        """Create a branch on the transport at relpath."""
 
1304
        repo = self.make_repository(relpath, format=format)
 
1305
        return repo.bzrdir.create_branch()
 
1306
 
 
1307
    def make_bzrdir(self, relpath, format=None):
 
1308
        try:
 
1309
            # might be a relative or absolute path
 
1310
            maybe_a_url = self.get_url(relpath)
 
1311
            segments = maybe_a_url.rsplit('/', 1)
 
1312
            t = get_transport(maybe_a_url)
 
1313
            if len(segments) > 1 and segments[-1] not in ('', '.'):
 
1314
                try:
 
1315
                    t.mkdir('.')
 
1316
                except errors.FileExists:
 
1317
                    pass
 
1318
            if format is None:
 
1319
                format = bzrlib.bzrdir.BzrDirFormat.get_default_format()
 
1320
            return format.initialize_on_transport(t)
 
1321
        except errors.UninitializableFormat:
 
1322
            raise TestSkipped("Format %s is not initializable." % format)
 
1323
 
 
1324
    def make_repository(self, relpath, shared=False, format=None):
 
1325
        """Create a repository on our default transport at relpath."""
 
1326
        made_control = self.make_bzrdir(relpath, format=format)
 
1327
        return made_control.create_repository(shared=shared)
 
1328
 
 
1329
    def make_branch_and_memory_tree(self, relpath):
 
1330
        """Create a branch on the default transport and a MemoryTree for it."""
 
1331
        b = self.make_branch(relpath)
 
1332
        return memorytree.MemoryTree.create_on_branch(b)
 
1333
 
 
1334
    def make_branch_and_tree(self, relpath, format=None):
 
1335
        """Create a branch on the transport and a tree locally.
 
1336
 
 
1337
        If the transport is not a LocalTransport, the Tree can't be created on
 
1338
        the transport.  In that case the working tree is created in the local
 
1339
        directory, and the returned tree's branch and repository will also be
 
1340
        accessed locally.
 
1341
 
 
1342
        This will fail if the original default transport for this test
 
1343
        case wasn't backed by the working directory, as the branch won't
 
1344
        be on disk for us to open it.  
 
1345
 
 
1346
        :param format: The BzrDirFormat.
 
1347
        :returns: the WorkingTree.
 
1348
        """
 
1349
        # TODO: always use the local disk path for the working tree,
 
1350
        # this obviously requires a format that supports branch references
 
1351
        # so check for that by checking bzrdir.BzrDirFormat.get_default_format()
 
1352
        # RBC 20060208
 
1353
        b = self.make_branch(relpath, format=format)
 
1354
        try:
 
1355
            return b.bzrdir.create_workingtree()
 
1356
        except errors.NotLocalUrl:
 
1357
            # We can only make working trees locally at the moment.  If the
 
1358
            # transport can't support them, then reopen the branch on a local
 
1359
            # transport, and create the working tree there.  
 
1360
            #
 
1361
            # Possibly we should instead keep
 
1362
            # the non-disk-backed branch and create a local checkout?
 
1363
            bd = bzrdir.BzrDir.open(relpath)
 
1364
            return bd.create_workingtree()
 
1365
 
 
1366
    def assertIsDirectory(self, relpath, transport):
 
1367
        """Assert that relpath within transport is a directory.
 
1368
 
 
1369
        This may not be possible on all transports; in that case it propagates
 
1370
        a TransportNotPossible.
 
1371
        """
 
1372
        try:
 
1373
            mode = transport.stat(relpath).st_mode
 
1374
        except errors.NoSuchFile:
 
1375
            self.fail("path %s is not a directory; no such file"
 
1376
                      % (relpath))
 
1377
        if not stat.S_ISDIR(mode):
 
1378
            self.fail("path %s is not a directory; has mode %#o"
 
1379
                      % (relpath, mode))
 
1380
 
 
1381
 
 
1382
class ChrootedTestCase(TestCaseWithTransport):
 
1383
    """A support class that provides readonly urls outside the local namespace.
 
1384
 
 
1385
    This is done by checking if self.transport_server is a MemoryServer. if it
 
1386
    is then we are chrooted already, if it is not then an HttpServer is used
 
1387
    for readonly urls.
 
1388
 
 
1389
    TODO RBC 20060127: make this an option to TestCaseWithTransport so it can
 
1390
                       be used without needed to redo it when a different 
 
1391
                       subclass is in use ?
 
1392
    """
 
1393
 
 
1394
    def setUp(self):
 
1395
        super(ChrootedTestCase, self).setUp()
 
1396
        if not self.transport_server == bzrlib.transport.memory.MemoryServer:
 
1397
            self.transport_readonly_server = bzrlib.transport.http.HttpServer
 
1398
 
 
1399
 
 
1400
def filter_suite_by_re(suite, pattern):
 
1401
    result = TestUtil.TestSuite()
 
1402
    filter_re = re.compile(pattern)
 
1403
    for test in iter_suite_tests(suite):
 
1404
        if filter_re.search(test.id()):
 
1405
            result.addTest(test)
 
1406
    return result
 
1407
 
 
1408
 
 
1409
def run_suite(suite, name='test', verbose=False, pattern=".*",
 
1410
              stop_on_failure=False, keep_output=False,
 
1411
              transport=None, lsprof_timed=None, bench_history=None):
 
1412
    TestCaseInTempDir._TEST_NAME = name
 
1413
    TestCase._gather_lsprof_in_benchmarks = lsprof_timed
 
1414
    if verbose:
 
1415
        verbosity = 2
 
1416
        pb = None
 
1417
    else:
 
1418
        verbosity = 1
 
1419
        pb = progress.ProgressBar()
 
1420
    runner = TextTestRunner(stream=sys.stdout,
 
1421
                            descriptions=0,
 
1422
                            verbosity=verbosity,
 
1423
                            keep_output=keep_output,
 
1424
                            pb=pb,
 
1425
                            bench_history=bench_history)
 
1426
    runner.stop_on_failure=stop_on_failure
 
1427
    if pattern != '.*':
 
1428
        suite = filter_suite_by_re(suite, pattern)
 
1429
    result = runner.run(suite)
 
1430
    return result.wasSuccessful()
 
1431
 
 
1432
 
 
1433
def selftest(verbose=False, pattern=".*", stop_on_failure=True,
 
1434
             keep_output=False,
 
1435
             transport=None,
 
1436
             test_suite_factory=None,
 
1437
             lsprof_timed=None,
 
1438
             bench_history=None):
292
1439
    """Run the whole test suite under the enhanced runner"""
293
 
    return run_suite(test_suite(), 'testbzr', verbose=verbose, pattern=pattern)
 
1440
    # XXX: Very ugly way to do this...
 
1441
    # Disable warning about old formats because we don't want it to disturb
 
1442
    # any blackbox tests.
 
1443
    from bzrlib import repository
 
1444
    repository._deprecation_warning_done = True
 
1445
 
 
1446
    global default_transport
 
1447
    if transport is None:
 
1448
        transport = default_transport
 
1449
    old_transport = default_transport
 
1450
    default_transport = transport
 
1451
    try:
 
1452
        if test_suite_factory is None:
 
1453
            suite = test_suite()
 
1454
        else:
 
1455
            suite = test_suite_factory()
 
1456
        return run_suite(suite, 'testbzr', verbose=verbose, pattern=pattern,
 
1457
                     stop_on_failure=stop_on_failure, keep_output=keep_output,
 
1458
                     transport=transport,
 
1459
                     lsprof_timed=lsprof_timed,
 
1460
                     bench_history=bench_history)
 
1461
    finally:
 
1462
        default_transport = old_transport
294
1463
 
295
1464
 
296
1465
def test_suite():
297
 
    """Build and return TestSuite for the whole program."""
298
 
    from bzrlib.selftest.TestUtil import TestLoader, TestSuite
299
 
    import bzrlib, bzrlib.store, bzrlib.inventory, bzrlib.branch
300
 
    import bzrlib.osutils, bzrlib.commands, bzrlib.merge3, bzrlib.plugin
301
 
    from doctest import DocTestSuite
302
 
    import os
303
 
    import shutil
304
 
    import time
305
 
    import sys
306
 
 
307
 
    global MODULES_TO_TEST, MODULES_TO_DOCTEST
308
 
 
309
 
    testmod_names = \
310
 
                  ['bzrlib.selftest.MetaTestLog',
311
 
                   'bzrlib.selftest.testinv',
312
 
                   'bzrlib.selftest.versioning',
313
 
                   'bzrlib.selftest.testmerge3',
314
 
                   'bzrlib.selftest.testhashcache',
315
 
                   'bzrlib.selftest.teststatus',
316
 
                   'bzrlib.selftest.testlog',
317
 
                   'bzrlib.selftest.testrevisionnamespaces',
318
 
                   'bzrlib.selftest.testbranch',
319
 
                   'bzrlib.selftest.testrevision',
320
 
                   'bzrlib.selftest.test_merge_core',
321
 
                   'bzrlib.selftest.test_smart_add',
322
 
                   'bzrlib.selftest.testdiff',
323
 
                   'bzrlib.selftest.test_parent',
324
 
                   'bzrlib.selftest.test_xml',
325
 
                   'bzrlib.selftest.testfetch',
326
 
                   'bzrlib.selftest.whitebox',
327
 
                   'bzrlib.selftest.teststore',
328
 
                   'bzrlib.selftest.blackbox',
 
1466
    """Build and return TestSuite for the whole of bzrlib.
 
1467
    
 
1468
    This function can be replaced if you need to change the default test
 
1469
    suite on a global basis, but it is not encouraged.
 
1470
    """
 
1471
    testmod_names = [
 
1472
                   'bzrlib.tests.test_ancestry',
 
1473
                   'bzrlib.tests.test_api',
 
1474
                   'bzrlib.tests.test_atomicfile',
 
1475
                   'bzrlib.tests.test_bad_files',
 
1476
                   'bzrlib.tests.test_branch',
 
1477
                   'bzrlib.tests.test_bundle',
 
1478
                   'bzrlib.tests.test_bzrdir',
 
1479
                   'bzrlib.tests.test_cache_utf8',
 
1480
                   'bzrlib.tests.test_command',
 
1481
                   'bzrlib.tests.test_commit',
 
1482
                   'bzrlib.tests.test_commit_merge',
 
1483
                   'bzrlib.tests.test_config',
 
1484
                   'bzrlib.tests.test_conflicts',
 
1485
                   'bzrlib.tests.test_decorators',
 
1486
                   'bzrlib.tests.test_diff',
 
1487
                   'bzrlib.tests.test_doc_generate',
 
1488
                   'bzrlib.tests.test_errors',
 
1489
                   'bzrlib.tests.test_escaped_store',
 
1490
                   'bzrlib.tests.test_fetch',
 
1491
                   'bzrlib.tests.test_ftp_transport',
 
1492
                   'bzrlib.tests.test_gpg',
 
1493
                   'bzrlib.tests.test_graph',
 
1494
                   'bzrlib.tests.test_hashcache',
 
1495
                   'bzrlib.tests.test_http',
 
1496
                   'bzrlib.tests.test_http_response',
 
1497
                   'bzrlib.tests.test_identitymap',
 
1498
                   'bzrlib.tests.test_ignores',
 
1499
                   'bzrlib.tests.test_inv',
 
1500
                   'bzrlib.tests.test_knit',
 
1501
                   'bzrlib.tests.test_lazy_import',
 
1502
                   'bzrlib.tests.test_lockdir',
 
1503
                   'bzrlib.tests.test_lockable_files',
 
1504
                   'bzrlib.tests.test_log',
 
1505
                   'bzrlib.tests.test_memorytree',
 
1506
                   'bzrlib.tests.test_merge',
 
1507
                   'bzrlib.tests.test_merge3',
 
1508
                   'bzrlib.tests.test_merge_core',
 
1509
                   'bzrlib.tests.test_missing',
 
1510
                   'bzrlib.tests.test_msgeditor',
 
1511
                   'bzrlib.tests.test_nonascii',
 
1512
                   'bzrlib.tests.test_options',
 
1513
                   'bzrlib.tests.test_osutils',
 
1514
                   'bzrlib.tests.test_patch',
 
1515
                   'bzrlib.tests.test_patches',
 
1516
                   'bzrlib.tests.test_permissions',
 
1517
                   'bzrlib.tests.test_plugins',
 
1518
                   'bzrlib.tests.test_progress',
 
1519
                   'bzrlib.tests.test_reconcile',
 
1520
                   'bzrlib.tests.test_repository',
 
1521
                   'bzrlib.tests.test_revert',
 
1522
                   'bzrlib.tests.test_revision',
 
1523
                   'bzrlib.tests.test_revisionnamespaces',
 
1524
                   'bzrlib.tests.test_revisiontree',
 
1525
                   'bzrlib.tests.test_rio',
 
1526
                   'bzrlib.tests.test_sampler',
 
1527
                   'bzrlib.tests.test_selftest',
 
1528
                   'bzrlib.tests.test_setup',
 
1529
                   'bzrlib.tests.test_sftp_transport',
 
1530
                   'bzrlib.tests.test_smart_add',
 
1531
                   'bzrlib.tests.test_smart_transport',
 
1532
                   'bzrlib.tests.test_source',
 
1533
                   'bzrlib.tests.test_status',
 
1534
                   'bzrlib.tests.test_store',
 
1535
                   'bzrlib.tests.test_symbol_versioning',
 
1536
                   'bzrlib.tests.test_testament',
 
1537
                   'bzrlib.tests.test_textfile',
 
1538
                   'bzrlib.tests.test_textmerge',
 
1539
                   'bzrlib.tests.test_trace',
 
1540
                   'bzrlib.tests.test_transactions',
 
1541
                   'bzrlib.tests.test_transform',
 
1542
                   'bzrlib.tests.test_transport',
 
1543
                   'bzrlib.tests.test_tree',
 
1544
                   'bzrlib.tests.test_treebuilder',
 
1545
                   'bzrlib.tests.test_tsort',
 
1546
                   'bzrlib.tests.test_tuned_gzip',
 
1547
                   'bzrlib.tests.test_ui',
 
1548
                   'bzrlib.tests.test_upgrade',
 
1549
                   'bzrlib.tests.test_urlutils',
 
1550
                   'bzrlib.tests.test_versionedfile',
 
1551
                   'bzrlib.tests.test_version',
 
1552
                   'bzrlib.tests.test_weave',
 
1553
                   'bzrlib.tests.test_whitebox',
 
1554
                   'bzrlib.tests.test_workingtree',
 
1555
                   'bzrlib.tests.test_xml',
329
1556
                   ]
330
 
 
331
 
    for m in (bzrlib.store, bzrlib.inventory, bzrlib.branch,
332
 
              bzrlib.osutils, bzrlib.commands, bzrlib.merge3):
333
 
        if m not in MODULES_TO_DOCTEST:
334
 
            MODULES_TO_DOCTEST.append(m)
335
 
 
336
 
    TestCase.BZRPATH = os.path.join(os.path.realpath(os.path.dirname(bzrlib.__path__[0])), 'bzr')
337
 
    print '%-30s %s' % ('bzr binary', TestCase.BZRPATH)
338
 
    print
339
 
    suite = TestSuite()
340
 
    suite.addTest(TestLoader().loadTestsFromNames(testmod_names))
 
1557
    test_transport_implementations = [
 
1558
        'bzrlib.tests.test_transport_implementations',
 
1559
        'bzrlib.tests.test_read_bundle',
 
1560
        ]
 
1561
    suite = TestUtil.TestSuite()
 
1562
    loader = TestUtil.TestLoader()
 
1563
    suite.addTest(loader.loadTestsFromModuleNames(testmod_names))
 
1564
    from bzrlib.transport import TransportTestProviderAdapter
 
1565
    adapter = TransportTestProviderAdapter()
 
1566
    adapt_modules(test_transport_implementations, adapter, loader, suite)
 
1567
    for package in packages_to_test():
 
1568
        suite.addTest(package.test_suite())
341
1569
    for m in MODULES_TO_TEST:
342
 
         suite.addTest(TestLoader().loadTestsFromModule(m))
343
 
    for m in (MODULES_TO_DOCTEST):
344
 
        suite.addTest(DocTestSuite(m))
345
 
    for p in bzrlib.plugin.all_plugins:
346
 
        if hasattr(p, 'test_suite'):
347
 
            suite.addTest(p.test_suite())
 
1570
        suite.addTest(loader.loadTestsFromModule(m))
 
1571
    for m in MODULES_TO_DOCTEST:
 
1572
        suite.addTest(doctest.DocTestSuite(m))
 
1573
    for name, plugin in bzrlib.plugin.all_plugins().items():
 
1574
        if getattr(plugin, 'test_suite', None) is not None:
 
1575
            suite.addTest(plugin.test_suite())
348
1576
    return suite
349
1577
 
 
1578
 
 
1579
def adapt_modules(mods_list, adapter, loader, suite):
 
1580
    """Adapt the modules in mods_list using adapter and add to suite."""
 
1581
    for test in iter_suite_tests(loader.loadTestsFromModuleNames(mods_list)):
 
1582
        suite.addTests(adapter.adapt(test))