/brz/remove-bazaar

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

« back to all changes in this revision

Viewing changes to bzrlib/selftest/__init__.py

  • Committer: Robey Pointer
  • Date: 2005-11-22 01:41:46 UTC
  • mfrom: (1185.40.1)
  • mto: (1185.33.37 bzr.dev)
  • mto: This revision was merged to the branch mainline in revision 1512.
  • Revision ID: robey@lag.net-20051122014146-5186f5e310a15202
make sftp put faster when using paramiko 1.5.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2005 by Canonical Ltd
 
2
 
 
3
# This program is free software; you can redistribute it and/or modify
 
4
# it under the terms of the GNU General Public License as published by
 
5
# the Free Software Foundation; either version 2 of the License, or
 
6
# (at your option) any later version.
 
7
 
 
8
# This program is distributed in the hope that it will be useful,
 
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
11
# GNU General Public License for more details.
 
12
 
 
13
# You should have received a copy of the GNU General Public License
 
14
# along with this program; if not, write to the Free Software
 
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
16
 
 
17
 
 
18
from cStringIO import StringIO
 
19
import difflib
 
20
import errno
 
21
import logging
 
22
import os
 
23
import re
 
24
import shutil
 
25
import sys
 
26
import tempfile
 
27
import unittest
 
28
import time
 
29
 
 
30
from logging import debug, warning, error
 
31
 
 
32
import bzrlib.commands
 
33
import bzrlib.trace
 
34
import bzrlib.osutils as osutils
 
35
from bzrlib.selftest import TestUtil
 
36
from bzrlib.selftest.TestUtil import TestLoader, TestSuite
 
37
from bzrlib.selftest.treeshape import build_tree_contents
 
38
 
 
39
MODULES_TO_TEST = []
 
40
MODULES_TO_DOCTEST = []
 
41
 
 
42
 
 
43
 
 
44
class EarlyStoppingTestResultAdapter(object):
 
45
    """An adapter for TestResult to stop at the first first failure or error"""
 
46
 
 
47
    def __init__(self, result):
 
48
        self._result = result
 
49
 
 
50
    def addError(self, test, err):
 
51
        self._result.addError(test, err)
 
52
        self._result.stop()
 
53
 
 
54
    def addFailure(self, test, err):
 
55
        self._result.addFailure(test, err)
 
56
        self._result.stop()
 
57
 
 
58
    def __getattr__(self, name):
 
59
        return getattr(self._result, name)
 
60
 
 
61
    def __setattr__(self, name, value):
 
62
        if name == '_result':
 
63
            object.__setattr__(self, name, value)
 
64
        return setattr(self._result, name, value)
 
65
 
 
66
 
 
67
class _MyResult(unittest._TextTestResult):
 
68
    """
 
69
    Custom TestResult.
 
70
 
 
71
    No special behaviour for now.
 
72
    """
 
73
 
 
74
    def _elapsedTime(self):
 
75
        return "(Took %.3fs)" % (time.time() - self._start_time)
 
76
 
 
77
    def startTest(self, test):
 
78
        unittest.TestResult.startTest(self, test)
 
79
        # TODO: Maybe show test.shortDescription somewhere?
 
80
        what = test.shortDescription() or test.id()        
 
81
        if self.showAll:
 
82
            self.stream.write('%-70.70s' % what)
 
83
        self.stream.flush()
 
84
        self._start_time = time.time()
 
85
 
 
86
    def addError(self, test, err):
 
87
        unittest.TestResult.addError(self, test, err)
 
88
        if self.showAll:
 
89
            self.stream.writeln("ERROR %s" % self._elapsedTime())
 
90
        elif self.dots:
 
91
            self.stream.write('E')
 
92
        self.stream.flush()
 
93
 
 
94
    def addFailure(self, test, err):
 
95
        unittest.TestResult.addFailure(self, test, err)
 
96
        if self.showAll:
 
97
            self.stream.writeln("FAIL %s" % self._elapsedTime())
 
98
        elif self.dots:
 
99
            self.stream.write('F')
 
100
        self.stream.flush()
 
101
 
 
102
    def addSuccess(self, test):
 
103
        if self.showAll:
 
104
            self.stream.writeln('OK %s' % self._elapsedTime())
 
105
        elif self.dots:
 
106
            self.stream.write('~')
 
107
        self.stream.flush()
 
108
        unittest.TestResult.addSuccess(self, test)
 
109
 
 
110
    def printErrorList(self, flavour, errors):
 
111
        for test, err in errors:
 
112
            self.stream.writeln(self.separator1)
 
113
            self.stream.writeln("%s: %s" % (flavour,self.getDescription(test)))
 
114
            if hasattr(test, '_get_log'):
 
115
                self.stream.writeln()
 
116
                self.stream.writeln('log from this test:')
 
117
                print >>self.stream, test._get_log()
 
118
            self.stream.writeln(self.separator2)
 
119
            self.stream.writeln("%s" % err)
 
120
 
 
121
 
 
122
class TextTestRunner(unittest.TextTestRunner):
 
123
    stop_on_failure = False
 
124
 
 
125
    def _makeResult(self):
 
126
        result = _MyResult(self.stream, self.descriptions, self.verbosity)
 
127
        if self.stop_on_failure:
 
128
            result = EarlyStoppingTestResultAdapter(result)
 
129
        return result
 
130
 
 
131
 
 
132
def iter_suite_tests(suite):
 
133
    """Return all tests in a suite, recursing through nested suites"""
 
134
    for item in suite._tests:
 
135
        if isinstance(item, unittest.TestCase):
 
136
            yield item
 
137
        elif isinstance(item, unittest.TestSuite):
 
138
            for r in iter_suite_tests(item):
 
139
                yield r
 
140
        else:
 
141
            raise Exception('unknown object %r inside test suite %r'
 
142
                            % (item, suite))
 
143
 
 
144
 
 
145
class TestSkipped(Exception):
 
146
    """Indicates that a test was intentionally skipped, rather than failing."""
 
147
    # XXX: Not used yet
 
148
 
 
149
 
 
150
class CommandFailed(Exception):
 
151
    pass
 
152
 
 
153
class TestCase(unittest.TestCase):
 
154
    """Base class for bzr unit tests.
 
155
    
 
156
    Tests that need access to disk resources should subclass 
 
157
    TestCaseInTempDir not TestCase.
 
158
 
 
159
    Error and debug log messages are redirected from their usual
 
160
    location into a temporary file, the contents of which can be
 
161
    retrieved by _get_log().  We use a real OS file, not an in-memory object,
 
162
    so that it can also capture file IO.  When the test completes this file
 
163
    is read into memory and removed from disk.
 
164
       
 
165
    There are also convenience functions to invoke bzr's command-line
 
166
    routine, and to build and check bzr trees.
 
167
   
 
168
    In addition to the usual method of overriding tearDown(), this class also
 
169
    allows subclasses to register functions into the _cleanups list, which is
 
170
    run in order as the object is torn down.  It's less likely this will be
 
171
    accidentally overlooked.
 
172
    """
 
173
 
 
174
    BZRPATH = 'bzr'
 
175
    _log_file_name = None
 
176
    _log_contents = ''
 
177
 
 
178
    def setUp(self):
 
179
        unittest.TestCase.setUp(self)
 
180
        self._cleanups = []
 
181
        self._cleanEnvironment()
 
182
        bzrlib.trace.disable_default_logging()
 
183
        self._startLogFile()
 
184
 
 
185
    def _ndiff_strings(self, a, b):
 
186
        """Return ndiff between two strings containing lines.
 
187
        
 
188
        A trailing newline is added if missing to make the strings
 
189
        print properly."""
 
190
        if b and b[-1] != '\n':
 
191
            b += '\n'
 
192
        if a and a[-1] != '\n':
 
193
            a += '\n'
 
194
        difflines = difflib.ndiff(a.splitlines(True),
 
195
                                  b.splitlines(True),
 
196
                                  linejunk=lambda x: False,
 
197
                                  charjunk=lambda x: False)
 
198
        return ''.join(difflines)
 
199
 
 
200
    def assertEqualDiff(self, a, b):
 
201
        """Assert two texts are equal, if not raise an exception.
 
202
        
 
203
        This is intended for use with multi-line strings where it can 
 
204
        be hard to find the differences by eye.
 
205
        """
 
206
        # TODO: perhaps override assertEquals to call this for strings?
 
207
        if a == b:
 
208
            return
 
209
        raise AssertionError("texts not equal:\n" + 
 
210
                             self._ndiff_strings(a, b))      
 
211
 
 
212
    def assertContainsRe(self, haystack, needle_re):
 
213
        """Assert that a contains something matching a regular expression."""
 
214
        if not re.search(needle_re, haystack):
 
215
            raise AssertionError('pattern "%s" not found in "%s"'
 
216
                    % (needle_re, haystack))
 
217
 
 
218
    def _startLogFile(self):
 
219
        """Send bzr and test log messages to a temporary file.
 
220
 
 
221
        The file is removed as the test is torn down.
 
222
        """
 
223
        fileno, name = tempfile.mkstemp(suffix='.log', prefix='testbzr')
 
224
        self._log_file = os.fdopen(fileno, 'w+')
 
225
        bzrlib.trace.enable_test_log(self._log_file)
 
226
        debug('opened log file %s', name)
 
227
        self._log_file_name = name
 
228
        self.addCleanup(self._finishLogFile)
 
229
 
 
230
    def _finishLogFile(self):
 
231
        """Finished with the log file.
 
232
 
 
233
        Read contents into memory, close, and delete.
 
234
        """
 
235
        bzrlib.trace.disable_test_log()
 
236
        self._log_file.seek(0)
 
237
        self._log_contents = self._log_file.read()
 
238
        self._log_file.close()
 
239
        os.remove(self._log_file_name)
 
240
        self._log_file = self._log_file_name = None
 
241
 
 
242
    def addCleanup(self, callable):
 
243
        """Arrange to run a callable when this case is torn down.
 
244
 
 
245
        Callables are run in the reverse of the order they are registered, 
 
246
        ie last-in first-out.
 
247
        """
 
248
        if callable in self._cleanups:
 
249
            raise ValueError("cleanup function %r already registered on %s" 
 
250
                    % (callable, self))
 
251
        self._cleanups.append(callable)
 
252
 
 
253
    def _cleanEnvironment(self):
 
254
        self.oldenv = os.environ.get('HOME', None)
 
255
        os.environ['HOME'] = os.getcwd()
 
256
        self.bzr_email = os.environ.get('BZREMAIL')
 
257
        if self.bzr_email is not None:
 
258
            del os.environ['BZREMAIL']
 
259
        self.email = os.environ.get('EMAIL')
 
260
        if self.email is not None:
 
261
            del os.environ['EMAIL']
 
262
        self.addCleanup(self._restoreEnvironment)
 
263
 
 
264
    def _restoreEnvironment(self):
 
265
        os.environ['HOME'] = self.oldenv
 
266
        if os.environ.get('BZREMAIL') is not None:
 
267
            del os.environ['BZREMAIL']
 
268
        if self.bzr_email is not None:
 
269
            os.environ['BZREMAIL'] = self.bzr_email
 
270
        if os.environ.get('EMAIL') is not None:
 
271
            del os.environ['EMAIL']
 
272
        if self.email is not None:
 
273
            os.environ['EMAIL'] = self.email
 
274
 
 
275
    def tearDown(self):
 
276
        self._runCleanups()
 
277
        unittest.TestCase.tearDown(self)
 
278
 
 
279
    def _runCleanups(self):
 
280
        """Run registered cleanup functions. 
 
281
 
 
282
        This should only be called from TestCase.tearDown.
 
283
        """
 
284
        for callable in reversed(self._cleanups):
 
285
            callable()
 
286
 
 
287
    def log(self, *args):
 
288
        logging.debug(*args)
 
289
 
 
290
    def _get_log(self):
 
291
        """Return as a string the log for this test"""
 
292
        if self._log_file_name:
 
293
            return open(self._log_file_name).read()
 
294
        else:
 
295
            return self._log_contents
 
296
 
 
297
    def capture(self, cmd, retcode=0):
 
298
        """Shortcut that splits cmd into words, runs, and returns stdout"""
 
299
        return self.run_bzr_captured(cmd.split(), retcode=retcode)[0]
 
300
 
 
301
    def run_bzr_captured(self, argv, retcode=0):
 
302
        """Invoke bzr and return (stdout, stderr).
 
303
 
 
304
        Useful for code that wants to check the contents of the
 
305
        output, the way error messages are presented, etc.
 
306
 
 
307
        This should be the main method for tests that want to exercise the
 
308
        overall behavior of the bzr application (rather than a unit test
 
309
        or a functional test of the library.)
 
310
 
 
311
        Much of the old code runs bzr by forking a new copy of Python, but
 
312
        that is slower, harder to debug, and generally not necessary.
 
313
 
 
314
        This runs bzr through the interface that catches and reports
 
315
        errors, and with logging set to something approximating the
 
316
        default, so that error reporting can be checked.
 
317
 
 
318
        argv -- arguments to invoke bzr
 
319
        retcode -- expected return code, or None for don't-care.
 
320
        """
 
321
        stdout = StringIO()
 
322
        stderr = StringIO()
 
323
        self.log('run bzr: %s', ' '.join(argv))
 
324
        handler = logging.StreamHandler(stderr)
 
325
        handler.setFormatter(bzrlib.trace.QuietFormatter())
 
326
        handler.setLevel(logging.INFO)
 
327
        logger = logging.getLogger('')
 
328
        logger.addHandler(handler)
 
329
        try:
 
330
            result = self.apply_redirected(None, stdout, stderr,
 
331
                                           bzrlib.commands.run_bzr_catch_errors,
 
332
                                           argv)
 
333
        finally:
 
334
            logger.removeHandler(handler)
 
335
        out = stdout.getvalue()
 
336
        err = stderr.getvalue()
 
337
        if out:
 
338
            self.log('output:\n%s', out)
 
339
        if err:
 
340
            self.log('errors:\n%s', err)
 
341
        if retcode is not None:
 
342
            self.assertEquals(result, retcode)
 
343
        return out, err
 
344
 
 
345
    def run_bzr(self, *args, **kwargs):
 
346
        """Invoke bzr, as if it were run from the command line.
 
347
 
 
348
        This should be the main method for tests that want to exercise the
 
349
        overall behavior of the bzr application (rather than a unit test
 
350
        or a functional test of the library.)
 
351
 
 
352
        This sends the stdout/stderr results into the test's log,
 
353
        where it may be useful for debugging.  See also run_captured.
 
354
        """
 
355
        retcode = kwargs.pop('retcode', 0)
 
356
        return self.run_bzr_captured(args, retcode)
 
357
 
 
358
    def check_inventory_shape(self, inv, shape):
 
359
        """Compare an inventory to a list of expected names.
 
360
 
 
361
        Fail if they are not precisely equal.
 
362
        """
 
363
        extras = []
 
364
        shape = list(shape)             # copy
 
365
        for path, ie in inv.entries():
 
366
            name = path.replace('\\', '/')
 
367
            if ie.kind == 'dir':
 
368
                name = name + '/'
 
369
            if name in shape:
 
370
                shape.remove(name)
 
371
            else:
 
372
                extras.append(name)
 
373
        if shape:
 
374
            self.fail("expected paths not found in inventory: %r" % shape)
 
375
        if extras:
 
376
            self.fail("unexpected paths found in inventory: %r" % extras)
 
377
 
 
378
    def apply_redirected(self, stdin=None, stdout=None, stderr=None,
 
379
                         a_callable=None, *args, **kwargs):
 
380
        """Call callable with redirected std io pipes.
 
381
 
 
382
        Returns the return code."""
 
383
        if not callable(a_callable):
 
384
            raise ValueError("a_callable must be callable.")
 
385
        if stdin is None:
 
386
            stdin = StringIO("")
 
387
        if stdout is None:
 
388
            if hasattr(self, "_log_file"):
 
389
                stdout = self._log_file
 
390
            else:
 
391
                stdout = StringIO()
 
392
        if stderr is None:
 
393
            if hasattr(self, "_log_file"):
 
394
                stderr = self._log_file
 
395
            else:
 
396
                stderr = StringIO()
 
397
        real_stdin = sys.stdin
 
398
        real_stdout = sys.stdout
 
399
        real_stderr = sys.stderr
 
400
        try:
 
401
            sys.stdout = stdout
 
402
            sys.stderr = stderr
 
403
            sys.stdin = stdin
 
404
            return a_callable(*args, **kwargs)
 
405
        finally:
 
406
            sys.stdout = real_stdout
 
407
            sys.stderr = real_stderr
 
408
            sys.stdin = real_stdin
 
409
 
 
410
 
 
411
BzrTestBase = TestCase
 
412
 
 
413
     
 
414
class TestCaseInTempDir(TestCase):
 
415
    """Derived class that runs a test within a temporary directory.
 
416
 
 
417
    This is useful for tests that need to create a branch, etc.
 
418
 
 
419
    The directory is created in a slightly complex way: for each
 
420
    Python invocation, a new temporary top-level directory is created.
 
421
    All test cases create their own directory within that.  If the
 
422
    tests complete successfully, the directory is removed.
 
423
 
 
424
    InTempDir is an old alias for FunctionalTestCase.
 
425
    """
 
426
 
 
427
    TEST_ROOT = None
 
428
    _TEST_NAME = 'test'
 
429
    OVERRIDE_PYTHON = 'python'
 
430
 
 
431
    def check_file_contents(self, filename, expect):
 
432
        self.log("check contents of file %s" % filename)
 
433
        contents = file(filename, 'r').read()
 
434
        if contents != expect:
 
435
            self.log("expected: %r" % expect)
 
436
            self.log("actually: %r" % contents)
 
437
            self.fail("contents of %s not as expected" % filename)
 
438
 
 
439
    def _make_test_root(self):
 
440
        if TestCaseInTempDir.TEST_ROOT is not None:
 
441
            return
 
442
        i = 0
 
443
        while True:
 
444
            root = u'test%04d.tmp' % i
 
445
            try:
 
446
                os.mkdir(root)
 
447
            except OSError, e:
 
448
                if e.errno == errno.EEXIST:
 
449
                    i += 1
 
450
                    continue
 
451
                else:
 
452
                    raise
 
453
            # successfully created
 
454
            TestCaseInTempDir.TEST_ROOT = os.path.abspath(root)
 
455
            break
 
456
        # make a fake bzr directory there to prevent any tests propagating
 
457
        # up onto the source directory's real branch
 
458
        os.mkdir(os.path.join(TestCaseInTempDir.TEST_ROOT, '.bzr'))
 
459
 
 
460
    def setUp(self):
 
461
        super(TestCaseInTempDir, self).setUp()
 
462
        self._make_test_root()
 
463
        _currentdir = os.getcwdu()
 
464
        short_id = self.id().replace('bzrlib.selftest.', '') \
 
465
                   .replace('__main__.', '')
 
466
        self.test_dir = os.path.join(self.TEST_ROOT, short_id)
 
467
        os.mkdir(self.test_dir)
 
468
        os.chdir(self.test_dir)
 
469
        os.environ['HOME'] = self.test_dir
 
470
        def _leaveDirectory():
 
471
            os.chdir(_currentdir)
 
472
        self.addCleanup(_leaveDirectory)
 
473
        
 
474
    def build_tree(self, shape):
 
475
        """Build a test tree according to a pattern.
 
476
 
 
477
        shape is a sequence of file specifications.  If the final
 
478
        character is '/', a directory is created.
 
479
 
 
480
        This doesn't add anything to a branch.
 
481
        """
 
482
        # XXX: It's OK to just create them using forward slashes on windows?
 
483
        for name in shape:
 
484
            self.assert_(isinstance(name, basestring))
 
485
            if name[-1] == '/':
 
486
                os.mkdir(name[:-1])
 
487
            else:
 
488
                f = file(name, 'wt')
 
489
                print >>f, "contents of", name
 
490
                f.close()
 
491
 
 
492
    def build_tree_contents(self, shape):
 
493
        bzrlib.selftest.build_tree_contents(shape)
 
494
 
 
495
    def failUnlessExists(self, path):
 
496
        """Fail unless path, which may be abs or relative, exists."""
 
497
        self.failUnless(osutils.lexists(path))
 
498
        
 
499
    def assertFileEqual(self, content, path):
 
500
        """Fail if path does not contain 'content'."""
 
501
        self.failUnless(osutils.lexists(path))
 
502
        self.assertEqualDiff(content, open(path, 'r').read())
 
503
        
 
504
 
 
505
class MetaTestLog(TestCase):
 
506
    def test_logging(self):
 
507
        """Test logs are captured when a test fails."""
 
508
        self.log('a test message')
 
509
        self.assertContainsRe(self._get_log(), 'a test message\n')
 
510
 
 
511
 
 
512
def filter_suite_by_re(suite, pattern):
 
513
    result = TestUtil.TestSuite()
 
514
    filter_re = re.compile(pattern)
 
515
    for test in iter_suite_tests(suite):
 
516
        if filter_re.search(test.id()):
 
517
            result.addTest(test)
 
518
    return result
 
519
 
 
520
 
 
521
def run_suite(suite, name='test', verbose=False, pattern=".*",
 
522
              stop_on_failure=False, keep_output=False):
 
523
    TestCaseInTempDir._TEST_NAME = name
 
524
    if verbose:
 
525
        verbosity = 2
 
526
    else:
 
527
        verbosity = 1
 
528
    runner = TextTestRunner(stream=sys.stdout,
 
529
                            descriptions=0,
 
530
                            verbosity=verbosity)
 
531
    runner.stop_on_failure=stop_on_failure
 
532
    if pattern != '.*':
 
533
        suite = filter_suite_by_re(suite, pattern)
 
534
    result = runner.run(suite)
 
535
    # This is still a little bogus, 
 
536
    # but only a little. Folk not using our testrunner will
 
537
    # have to delete their temp directories themselves.
 
538
    if result.wasSuccessful() or not keep_output:
 
539
        if TestCaseInTempDir.TEST_ROOT is not None:
 
540
            shutil.rmtree(TestCaseInTempDir.TEST_ROOT) 
 
541
    else:
 
542
        print "Failed tests working directories are in '%s'\n" % TestCaseInTempDir.TEST_ROOT
 
543
    return result.wasSuccessful()
 
544
 
 
545
 
 
546
def selftest(verbose=False, pattern=".*", stop_on_failure=True,
 
547
             keep_output=False):
 
548
    """Run the whole test suite under the enhanced runner"""
 
549
    return run_suite(test_suite(), 'testbzr', verbose=verbose, pattern=pattern,
 
550
                     stop_on_failure=stop_on_failure, keep_output=keep_output)
 
551
 
 
552
 
 
553
def test_suite():
 
554
    """Build and return TestSuite for the whole program."""
 
555
    import bzrlib.store, bzrlib.inventory, bzrlib.branch
 
556
    import bzrlib.osutils, bzrlib.merge3, bzrlib.plugin
 
557
    from doctest import DocTestSuite
 
558
 
 
559
    global MODULES_TO_TEST, MODULES_TO_DOCTEST
 
560
 
 
561
    # FIXME: If these fail to load, e.g. because of a syntax error, the
 
562
    # exception is hidden by unittest.  Sucks.  Should either fix that or
 
563
    # perhaps import them and pass them to unittest as modules.
 
564
    testmod_names = \
 
565
                  ['bzrlib.selftest.MetaTestLog',
 
566
                   'bzrlib.selftest.testapi',
 
567
                   'bzrlib.selftest.testgpg',
 
568
                   'bzrlib.selftest.testidentitymap',
 
569
                   'bzrlib.selftest.testinv',
 
570
                   'bzrlib.selftest.test_ancestry',
 
571
                   'bzrlib.selftest.test_commit',
 
572
                   'bzrlib.selftest.test_command',
 
573
                   'bzrlib.selftest.test_commit_merge',
 
574
                   'bzrlib.selftest.testconfig',
 
575
                   'bzrlib.selftest.versioning',
 
576
                   'bzrlib.selftest.testmerge3',
 
577
                   'bzrlib.selftest.testmerge',
 
578
                   'bzrlib.selftest.testhashcache',
 
579
                   'bzrlib.selftest.teststatus',
 
580
                   'bzrlib.selftest.testlog',
 
581
                   'bzrlib.selftest.testrevisionnamespaces',
 
582
                   'bzrlib.selftest.testbranch',
 
583
                   'bzrlib.selftest.testrevision',
 
584
                   'bzrlib.selftest.test_revision_info',
 
585
                   'bzrlib.selftest.test_merge_core',
 
586
                   'bzrlib.selftest.test_smart_add',
 
587
                   'bzrlib.selftest.test_bad_files',
 
588
                   'bzrlib.selftest.testdiff',
 
589
                   'bzrlib.selftest.test_parent',
 
590
                   'bzrlib.selftest.test_xml',
 
591
                   'bzrlib.selftest.test_weave',
 
592
                   'bzrlib.selftest.testfetch',
 
593
                   'bzrlib.selftest.whitebox',
 
594
                   'bzrlib.selftest.teststore',
 
595
                   'bzrlib.selftest.blackbox',
 
596
                   'bzrlib.selftest.testsampler',
 
597
                   'bzrlib.selftest.testtransactions',
 
598
                   'bzrlib.selftest.testtransport',
 
599
                   'bzrlib.selftest.testsftp',
 
600
                   'bzrlib.selftest.testgraph',
 
601
                   'bzrlib.selftest.testworkingtree',
 
602
                   'bzrlib.selftest.test_upgrade',
 
603
                   'bzrlib.selftest.test_conflicts',
 
604
                   'bzrlib.selftest.testtestament',
 
605
                   'bzrlib.selftest.testannotate',
 
606
                   'bzrlib.selftest.testrevprops',
 
607
                   'bzrlib.selftest.testoptions',
 
608
                   'bzrlib.selftest.testhttp',
 
609
                   'bzrlib.selftest.testnonascii',
 
610
                   'bzrlib.selftest.testreweave',
 
611
                   'bzrlib.selftest.testtsort',
 
612
                   'bzrlib.selftest.testtrace',
 
613
                   ]
 
614
 
 
615
    for m in (bzrlib.store, bzrlib.inventory, bzrlib.branch,
 
616
              bzrlib.osutils, bzrlib.commands, bzrlib.merge3,
 
617
              bzrlib.errors,
 
618
              ):
 
619
        if m not in MODULES_TO_DOCTEST:
 
620
            MODULES_TO_DOCTEST.append(m)
 
621
 
 
622
    TestCase.BZRPATH = os.path.join(os.path.realpath(os.path.dirname(bzrlib.__path__[0])), 'bzr')
 
623
    print '%-30s %s' % ('bzr binary', TestCase.BZRPATH)
 
624
    print
 
625
    suite = TestSuite()
 
626
    suite.addTest(TestLoader().loadTestsFromNames(testmod_names))
 
627
    for m in MODULES_TO_TEST:
 
628
         suite.addTest(TestLoader().loadTestsFromModule(m))
 
629
    for m in (MODULES_TO_DOCTEST):
 
630
        suite.addTest(DocTestSuite(m))
 
631
    for p in bzrlib.plugin.all_plugins:
 
632
        if hasattr(p, 'test_suite'):
 
633
            suite.addTest(p.test_suite())
 
634
    return suite
 
635