~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/selftest/__init__.py

  • Committer: Martin Pool
  • Date: 2005-09-23 05:57:06 UTC
  • Revision ID: mbp@sourcefrog.net-20050923055706-afd25ee2a988286d
- update NEWS files

Show diffs side-by-side

added added

removed removed

Lines of Context:
15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
16
 
17
17
 
18
 
from cStringIO import StringIO
19
 
import difflib
20
 
import errno
21
18
import logging
 
19
import unittest
 
20
import tempfile
22
21
import os
23
 
import re
 
22
import sys
 
23
import errno
 
24
import subprocess
24
25
import shutil
25
 
import sys
26
 
import tempfile
27
 
import unittest
28
 
import time
29
26
 
30
 
import bzrlib.branch
 
27
import testsweet
31
28
import bzrlib.commands
32
 
from bzrlib.errors import BzrError
33
 
import bzrlib.inventory
34
 
import bzrlib.merge3
35
 
import bzrlib.osutils
36
 
import bzrlib.plugin
37
 
import bzrlib.store
 
29
 
38
30
import bzrlib.trace
39
 
from bzrlib.trace import mutter
40
 
from bzrlib.tests.TestUtil import TestLoader, TestSuite
41
 
from bzrlib.tests.treeshape import build_tree_contents
 
31
import bzrlib.fetch
 
32
 
42
33
 
43
34
MODULES_TO_TEST = []
44
 
MODULES_TO_DOCTEST = [
45
 
                      bzrlib.branch,
46
 
                      bzrlib.commands,
47
 
                      bzrlib.errors,
48
 
                      bzrlib.inventory,
49
 
                      bzrlib.merge3,
50
 
                      bzrlib.osutils,
51
 
                      bzrlib.store,
52
 
                      ]
53
 
def packages_to_test():
54
 
    import bzrlib.tests.blackbox
55
 
    return [
56
 
            bzrlib.tests.blackbox
57
 
            ]
58
 
 
59
 
 
60
 
class EarlyStoppingTestResultAdapter(object):
61
 
    """An adapter for TestResult to stop at the first first failure or error"""
62
 
 
63
 
    def __init__(self, result):
64
 
        self._result = result
65
 
 
66
 
    def addError(self, test, err):
67
 
        self._result.addError(test, err)
68
 
        self._result.stop()
69
 
 
70
 
    def addFailure(self, test, err):
71
 
        self._result.addFailure(test, err)
72
 
        self._result.stop()
73
 
 
74
 
    def __getattr__(self, name):
75
 
        return getattr(self._result, name)
76
 
 
77
 
    def __setattr__(self, name, value):
78
 
        if name == '_result':
79
 
            object.__setattr__(self, name, value)
80
 
        return setattr(self._result, name, value)
81
 
 
82
 
 
83
 
class _MyResult(unittest._TextTestResult):
84
 
    """Custom TestResult.
85
 
 
86
 
    Shows output in a different format, including displaying runtime for tests.
87
 
    """
88
 
 
89
 
    def _elapsedTime(self):
90
 
        return "%5dms" % (1000 * (time.time() - self._start_time))
91
 
 
92
 
    def startTest(self, test):
93
 
        unittest.TestResult.startTest(self, test)
94
 
        # In a short description, the important words are in
95
 
        # the beginning, but in an id, the important words are
96
 
        # at the end
97
 
        SHOW_DESCRIPTIONS = False
98
 
        if self.showAll:
99
 
            width = bzrlib.osutils.terminal_width()
100
 
            name_width = width - 15
101
 
            what = None
102
 
            if SHOW_DESCRIPTIONS:
103
 
                what = test.shortDescription()
104
 
                if what:
105
 
                    if len(what) > name_width:
106
 
                        what = what[:name_width-3] + '...'
107
 
            if what is None:
108
 
                what = test.id()
109
 
                if what.startswith('bzrlib.tests.'):
110
 
                    what = what[13:]
111
 
                if len(what) > name_width:
112
 
                    what = '...' + what[3-name_width:]
113
 
            what = what.ljust(name_width)
114
 
            self.stream.write(what)
115
 
        self.stream.flush()
116
 
        self._start_time = time.time()
117
 
 
118
 
    def addError(self, test, err):
119
 
        unittest.TestResult.addError(self, test, err)
120
 
        if self.showAll:
121
 
            self.stream.writeln("ERROR %s" % self._elapsedTime())
122
 
        elif self.dots:
123
 
            self.stream.write('E')
124
 
        self.stream.flush()
125
 
 
126
 
    def addFailure(self, test, err):
127
 
        unittest.TestResult.addFailure(self, test, err)
128
 
        if self.showAll:
129
 
            self.stream.writeln(" FAIL %s" % self._elapsedTime())
130
 
        elif self.dots:
131
 
            self.stream.write('F')
132
 
        self.stream.flush()
133
 
 
134
 
    def addSuccess(self, test):
135
 
        if self.showAll:
136
 
            self.stream.writeln('   OK %s' % self._elapsedTime())
137
 
        elif self.dots:
138
 
            self.stream.write('~')
139
 
        self.stream.flush()
140
 
        unittest.TestResult.addSuccess(self, test)
141
 
 
142
 
    def printErrorList(self, flavour, errors):
143
 
        for test, err in errors:
144
 
            self.stream.writeln(self.separator1)
145
 
            self.stream.writeln("%s: %s" % (flavour,self.getDescription(test)))
146
 
            if hasattr(test, '_get_log'):
147
 
                self.stream.writeln()
148
 
                self.stream.writeln('log from this test:')
149
 
                print >>self.stream, test._get_log()
150
 
            self.stream.writeln(self.separator2)
151
 
            self.stream.writeln("%s" % err)
152
 
 
153
 
 
154
 
class TextTestRunner(unittest.TextTestRunner):
155
 
    stop_on_failure = False
156
 
 
157
 
    def _makeResult(self):
158
 
        result = _MyResult(self.stream, self.descriptions, self.verbosity)
159
 
        if self.stop_on_failure:
160
 
            result = EarlyStoppingTestResultAdapter(result)
161
 
        return result
162
 
 
163
 
 
164
 
def iter_suite_tests(suite):
165
 
    """Return all tests in a suite, recursing through nested suites"""
166
 
    for item in suite._tests:
167
 
        if isinstance(item, unittest.TestCase):
168
 
            yield item
169
 
        elif isinstance(item, unittest.TestSuite):
170
 
            for r in iter_suite_tests(item):
171
 
                yield r
172
 
        else:
173
 
            raise Exception('unknown object %r inside test suite %r'
174
 
                            % (item, suite))
175
 
 
176
 
 
177
 
class TestSkipped(Exception):
178
 
    """Indicates that a test was intentionally skipped, rather than failing."""
179
 
    # XXX: Not used yet
180
 
 
 
35
MODULES_TO_DOCTEST = []
 
36
 
 
37
from logging import debug, warning, error
181
38
 
182
39
class CommandFailed(Exception):
183
40
    pass
190
47
 
191
48
    Error and debug log messages are redirected from their usual
192
49
    location into a temporary file, the contents of which can be
193
 
    retrieved by _get_log().  We use a real OS file, not an in-memory object,
194
 
    so that it can also capture file IO.  When the test completes this file
195
 
    is read into memory and removed from disk.
 
50
    retrieved by _get_log().
196
51
       
197
52
    There are also convenience functions to invoke bzr's command-line
198
 
    routine, and to build and check bzr trees.
199
 
   
200
 
    In addition to the usual method of overriding tearDown(), this class also
201
 
    allows subclasses to register functions into the _cleanups list, which is
202
 
    run in order as the object is torn down.  It's less likely this will be
203
 
    accidentally overlooked.
204
 
    """
 
53
    routine, and to build and check bzr trees."""
205
54
 
206
55
    BZRPATH = 'bzr'
207
 
    _log_file_name = None
208
 
    _log_contents = ''
209
56
 
210
57
    def setUp(self):
 
58
        # this replaces the default testsweet.TestCase; we don't want logging changed
211
59
        unittest.TestCase.setUp(self)
212
 
        self._cleanups = []
213
 
        self._cleanEnvironment()
214
60
        bzrlib.trace.disable_default_logging()
215
 
        self._startLogFile()
216
 
 
217
 
    def _ndiff_strings(self, a, b):
218
 
        """Return ndiff between two strings containing lines.
219
 
        
220
 
        A trailing newline is added if missing to make the strings
221
 
        print properly."""
222
 
        if b and b[-1] != '\n':
223
 
            b += '\n'
224
 
        if a and a[-1] != '\n':
225
 
            a += '\n'
226
 
        difflines = difflib.ndiff(a.splitlines(True),
227
 
                                  b.splitlines(True),
228
 
                                  linejunk=lambda x: False,
229
 
                                  charjunk=lambda x: False)
230
 
        return ''.join(difflines)
231
 
 
232
 
    def assertEqualDiff(self, a, b):
233
 
        """Assert two texts are equal, if not raise an exception.
234
 
        
235
 
        This is intended for use with multi-line strings where it can 
236
 
        be hard to find the differences by eye.
237
 
        """
238
 
        # TODO: perhaps override assertEquals to call this for strings?
239
 
        if a == b:
240
 
            return
241
 
        raise AssertionError("texts not equal:\n" + 
242
 
                             self._ndiff_strings(a, b))      
243
 
 
244
 
    def assertContainsRe(self, haystack, needle_re):
245
 
        """Assert that a contains something matching a regular expression."""
246
 
        if not re.search(needle_re, haystack):
247
 
            raise AssertionError('pattern "%s" not found in "%s"'
248
 
                    % (needle_re, haystack))
249
 
 
250
 
    def _startLogFile(self):
251
 
        """Send bzr and test log messages to a temporary file.
252
 
 
253
 
        The file is removed as the test is torn down.
254
 
        """
 
61
        self._enable_file_logging()
 
62
 
 
63
 
 
64
    def _enable_file_logging(self):
255
65
        fileno, name = tempfile.mkstemp(suffix='.log', prefix='testbzr')
 
66
 
256
67
        self._log_file = os.fdopen(fileno, 'w+')
257
 
        bzrlib.trace.enable_test_log(self._log_file)
 
68
 
 
69
        hdlr = logging.StreamHandler(self._log_file)
 
70
        hdlr.setLevel(logging.DEBUG)
 
71
        hdlr.setFormatter(logging.Formatter('%(levelname)8s  %(message)s'))
 
72
        logging.getLogger('').addHandler(hdlr)
 
73
        logging.getLogger('').setLevel(logging.DEBUG)
 
74
        self._log_hdlr = hdlr
 
75
        debug('opened log file %s', name)
 
76
        
258
77
        self._log_file_name = name
259
 
        self.addCleanup(self._finishLogFile)
260
 
 
261
 
    def _finishLogFile(self):
262
 
        """Finished with the log file.
263
 
 
264
 
        Read contents into memory, close, and delete.
265
 
        """
266
 
        bzrlib.trace.disable_test_log()
267
 
        self._log_file.seek(0)
268
 
        self._log_contents = self._log_file.read()
 
78
 
 
79
        
 
80
    def tearDown(self):
 
81
        logging.getLogger('').removeHandler(self._log_hdlr)
 
82
        bzrlib.trace.enable_default_logging()
 
83
        logging.debug('%s teardown', self.id())
269
84
        self._log_file.close()
270
 
        os.remove(self._log_file_name)
271
 
        self._log_file = self._log_file_name = None
272
 
 
273
 
    def addCleanup(self, callable):
274
 
        """Arrange to run a callable when this case is torn down.
275
 
 
276
 
        Callables are run in the reverse of the order they are registered, 
277
 
        ie last-in first-out.
278
 
        """
279
 
        if callable in self._cleanups:
280
 
            raise ValueError("cleanup function %r already registered on %s" 
281
 
                    % (callable, self))
282
 
        self._cleanups.append(callable)
283
 
 
284
 
    def _cleanEnvironment(self):
285
 
        new_env = {
286
 
            'HOME': os.getcwd(),
287
 
            'APPDATA': os.getcwd(),
288
 
            'BZREMAIL': None,
289
 
            'EMAIL': None,
290
 
        }
291
 
        self.__old_env = {}
292
 
        self.addCleanup(self._restoreEnvironment)
293
 
        for name, value in new_env.iteritems():
294
 
            self._captureVar(name, value)
295
 
 
296
 
 
297
 
    def _captureVar(self, name, newvalue):
298
 
        """Set an environment variable, preparing it to be reset when finished."""
299
 
        self.__old_env[name] = os.environ.get(name, None)
300
 
        if newvalue is None:
301
 
            if name in os.environ:
302
 
                del os.environ[name]
303
 
        else:
304
 
            os.environ[name] = newvalue
305
 
 
306
 
    @staticmethod
307
 
    def _restoreVar(name, value):
308
 
        if value is None:
309
 
            if name in os.environ:
310
 
                del os.environ[name]
311
 
        else:
312
 
            os.environ[name] = value
313
 
 
314
 
    def _restoreEnvironment(self):
315
 
        for name, value in self.__old_env.iteritems():
316
 
            self._restoreVar(name, value)
317
 
 
318
 
    def tearDown(self):
319
 
        self._runCleanups()
320
85
        unittest.TestCase.tearDown(self)
321
86
 
322
 
    def _runCleanups(self):
323
 
        """Run registered cleanup functions. 
324
 
 
325
 
        This should only be called from TestCase.tearDown.
326
 
        """
327
 
        for cleanup_fn in reversed(self._cleanups):
328
 
            cleanup_fn()
329
87
 
330
88
    def log(self, *args):
331
 
        mutter(*args)
 
89
        logging.debug(*args)
332
90
 
333
91
    def _get_log(self):
334
92
        """Return as a string the log for this test"""
335
 
        if self._log_file_name:
336
 
            return open(self._log_file_name).read()
337
 
        else:
338
 
            return self._log_contents
339
 
        # TODO: Delete the log after it's been read in
340
 
 
341
 
    def capture(self, cmd, retcode=0):
342
 
        """Shortcut that splits cmd into words, runs, and returns stdout"""
343
 
        return self.run_bzr_captured(cmd.split(), retcode=retcode)[0]
344
 
 
345
 
    def run_bzr_captured(self, argv, retcode=0):
346
 
        """Invoke bzr and return (stdout, stderr).
347
 
 
348
 
        Useful for code that wants to check the contents of the
349
 
        output, the way error messages are presented, etc.
 
93
        return open(self._log_file_name).read()
 
94
 
 
95
    def run_bzr(self, *args, **kwargs):
 
96
        """Invoke bzr, as if it were run from the command line.
350
97
 
351
98
        This should be the main method for tests that want to exercise the
352
99
        overall behavior of the bzr application (rather than a unit test
354
101
 
355
102
        Much of the old code runs bzr by forking a new copy of Python, but
356
103
        that is slower, harder to debug, and generally not necessary.
357
 
 
358
 
        This runs bzr through the interface that catches and reports
359
 
        errors, and with logging set to something approximating the
360
 
        default, so that error reporting can be checked.
361
 
 
362
 
        argv -- arguments to invoke bzr
363
 
        retcode -- expected return code, or None for don't-care.
364
 
        """
365
 
        stdout = StringIO()
366
 
        stderr = StringIO()
367
 
        self.log('run bzr: %s', ' '.join(argv))
368
 
        # FIXME: don't call into logging here
369
 
        handler = logging.StreamHandler(stderr)
370
 
        handler.setFormatter(bzrlib.trace.QuietFormatter())
371
 
        handler.setLevel(logging.INFO)
372
 
        logger = logging.getLogger('')
373
 
        logger.addHandler(handler)
374
 
        try:
375
 
            result = self.apply_redirected(None, stdout, stderr,
376
 
                                           bzrlib.commands.run_bzr_catch_errors,
377
 
                                           argv)
378
 
        finally:
379
 
            logger.removeHandler(handler)
380
 
        out = stdout.getvalue()
381
 
        err = stderr.getvalue()
382
 
        if out:
383
 
            self.log('output:\n%s', out)
384
 
        if err:
385
 
            self.log('errors:\n%s', err)
386
 
        if retcode is not None:
387
 
            self.assertEquals(result, retcode)
388
 
        return out, err
389
 
 
390
 
    def run_bzr(self, *args, **kwargs):
391
 
        """Invoke bzr, as if it were run from the command line.
392
 
 
393
 
        This should be the main method for tests that want to exercise the
394
 
        overall behavior of the bzr application (rather than a unit test
395
 
        or a functional test of the library.)
396
 
 
397
 
        This sends the stdout/stderr results into the test's log,
398
 
        where it may be useful for debugging.  See also run_captured.
399
 
        """
400
 
        retcode = kwargs.pop('retcode', 0)
401
 
        return self.run_bzr_captured(args, retcode)
402
 
 
 
104
        """
 
105
        retcode = kwargs.get('retcode', 0)
 
106
        result = self.apply_redirected(None, None, None,
 
107
                                       bzrlib.commands.run_bzr, args)
 
108
        self.assertEquals(result, retcode)
 
109
        
 
110
        
403
111
    def check_inventory_shape(self, inv, shape):
404
112
        """Compare an inventory to a list of expected names.
405
113
 
425
133
        """Call callable with redirected std io pipes.
426
134
 
427
135
        Returns the return code."""
 
136
        from StringIO import StringIO
428
137
        if not callable(a_callable):
429
138
            raise ValueError("a_callable must be callable.")
430
139
        if stdin is None:
431
140
            stdin = StringIO("")
432
141
        if stdout is None:
433
 
            if hasattr(self, "_log_file"):
434
 
                stdout = self._log_file
435
 
            else:
436
 
                stdout = StringIO()
 
142
            stdout = self._log_file
437
143
        if stderr is None:
438
 
            if hasattr(self, "_log_file"):
439
 
                stderr = self._log_file
440
 
            else:
441
 
                stderr = StringIO()
 
144
            stderr = self._log_file
442
145
        real_stdin = sys.stdin
443
146
        real_stdout = sys.stdout
444
147
        real_stderr = sys.stderr
479
182
        if contents != expect:
480
183
            self.log("expected: %r" % expect)
481
184
            self.log("actually: %r" % contents)
482
 
            self.fail("contents of %s not as expected" % filename)
 
185
            self.fail("contents of %s not as expected")
483
186
 
484
187
    def _make_test_root(self):
485
188
        if TestCaseInTempDir.TEST_ROOT is not None:
486
189
            return
487
190
        i = 0
488
191
        while True:
489
 
            root = u'test%04d.tmp' % i
 
192
            root = 'test%04d.tmp' % i
490
193
            try:
491
194
                os.mkdir(root)
492
195
            except OSError, e:
504
207
 
505
208
    def setUp(self):
506
209
        super(TestCaseInTempDir, self).setUp()
 
210
        import os
507
211
        self._make_test_root()
508
 
        _currentdir = os.getcwdu()
509
 
        short_id = self.id().replace('bzrlib.tests.', '') \
 
212
        self._currentdir = os.getcwdu()
 
213
        short_id = self.id().replace('bzrlib.selftest.', '') \
510
214
                   .replace('__main__.', '')
511
215
        self.test_dir = os.path.join(self.TEST_ROOT, short_id)
512
216
        os.mkdir(self.test_dir)
513
217
        os.chdir(self.test_dir)
514
 
        os.environ['HOME'] = self.test_dir
515
 
        def _leaveDirectory():
516
 
            os.chdir(_currentdir)
517
 
        self.addCleanup(_leaveDirectory)
518
218
        
519
 
    def build_tree(self, shape, line_endings='native'):
 
219
    def tearDown(self):
 
220
        import os
 
221
        os.chdir(self._currentdir)
 
222
        super(TestCaseInTempDir, self).tearDown()
 
223
 
 
224
    def _formcmd(self, cmd):
 
225
        if isinstance(cmd, basestring):
 
226
            cmd = cmd.split()
 
227
        if cmd[0] == 'bzr':
 
228
            cmd[0] = self.BZRPATH
 
229
            if self.OVERRIDE_PYTHON:
 
230
                cmd.insert(0, self.OVERRIDE_PYTHON)
 
231
        self.log('$ %r' % cmd)
 
232
        return cmd
 
233
 
 
234
    def runcmd(self, cmd, retcode=0):
 
235
        """Run one command and check the return code.
 
236
 
 
237
        Returns a tuple of (stdout,stderr) strings.
 
238
 
 
239
        If a single string is based, it is split into words.
 
240
        For commands that are not simple space-separated words, please
 
241
        pass a list instead."""
 
242
        cmd = self._formcmd(cmd)
 
243
        self.log('$ ' + ' '.join(cmd))
 
244
        actual_retcode = subprocess.call(cmd, stdout=self._log_file,
 
245
                                         stderr=self._log_file)
 
246
        if retcode != actual_retcode:
 
247
            raise CommandFailed("test failed: %r returned %d, expected %d"
 
248
                                % (cmd, actual_retcode, retcode))
 
249
 
 
250
    def backtick(self, cmd, retcode=0):
 
251
        """Run a command and return its output"""
 
252
        cmd = self._formcmd(cmd)
 
253
        child = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=self._log_file)
 
254
        outd, errd = child.communicate()
 
255
        self.log(outd)
 
256
        actual_retcode = child.wait()
 
257
 
 
258
        outd = outd.replace('\r', '')
 
259
 
 
260
        if retcode != actual_retcode:
 
261
            raise CommandFailed("test failed: %r returned %d, expected %d"
 
262
                                % (cmd, actual_retcode, retcode))
 
263
 
 
264
        return outd
 
265
 
 
266
 
 
267
 
 
268
    def build_tree(self, shape):
520
269
        """Build a test tree according to a pattern.
521
270
 
522
271
        shape is a sequence of file specifications.  If the final
523
272
        character is '/', a directory is created.
524
273
 
525
274
        This doesn't add anything to a branch.
526
 
        :param line_endings: Either 'binary' or 'native'
527
 
                             in binary mode, exact contents are written
528
 
                             in native mode, the line endings match the
529
 
                             default platform endings.
530
275
        """
531
276
        # XXX: It's OK to just create them using forward slashes on windows?
 
277
        import os
532
278
        for name in shape:
533
 
            self.assert_(isinstance(name, basestring))
 
279
            assert isinstance(name, basestring)
534
280
            if name[-1] == '/':
535
281
                os.mkdir(name[:-1])
536
282
            else:
537
 
                if line_endings == 'binary':
538
 
                    f = file(name, 'wb')
539
 
                elif line_endings == 'native':
540
 
                    f = file(name, 'wt')
541
 
                else:
542
 
                    raise BzrError('Invalid line ending request %r' % (line_endings,))
 
283
                f = file(name, 'wt')
543
284
                print >>f, "contents of", name
544
285
                f.close()
545
 
 
546
 
    def build_tree_contents(self, shape):
547
 
        build_tree_contents(shape)
548
 
 
549
 
    def failUnlessExists(self, path):
550
 
        """Fail unless path, which may be abs or relative, exists."""
551
 
        self.failUnless(bzrlib.osutils.lexists(path))
552
 
        
553
 
    def assertFileEqual(self, content, path):
554
 
        """Fail if path does not contain 'content'."""
555
 
        self.failUnless(bzrlib.osutils.lexists(path))
556
 
        self.assertEqualDiff(content, open(path, 'r').read())
557
 
        
558
 
 
559
 
def filter_suite_by_re(suite, pattern):
560
 
    result = TestSuite()
561
 
    filter_re = re.compile(pattern)
562
 
    for test in iter_suite_tests(suite):
563
 
        if filter_re.search(test.id()):
564
 
            result.addTest(test)
565
 
    return result
566
 
 
567
 
 
568
 
def run_suite(suite, name='test', verbose=False, pattern=".*",
569
 
              stop_on_failure=False, keep_output=False):
570
 
    TestCaseInTempDir._TEST_NAME = name
571
 
    if verbose:
572
 
        verbosity = 2
573
 
    else:
574
 
        verbosity = 1
575
 
    runner = TextTestRunner(stream=sys.stdout,
576
 
                            descriptions=0,
577
 
                            verbosity=verbosity)
578
 
    runner.stop_on_failure=stop_on_failure
579
 
    if pattern != '.*':
580
 
        suite = filter_suite_by_re(suite, pattern)
581
 
    result = runner.run(suite)
582
 
    # This is still a little bogus, 
583
 
    # but only a little. Folk not using our testrunner will
584
 
    # have to delete their temp directories themselves.
585
 
    if result.wasSuccessful() or not keep_output:
586
 
        if TestCaseInTempDir.TEST_ROOT is not None:
587
 
            shutil.rmtree(TestCaseInTempDir.TEST_ROOT) 
588
 
    else:
589
 
        print "Failed tests working directories are in '%s'\n" % TestCaseInTempDir.TEST_ROOT
590
 
    return result.wasSuccessful()
591
 
 
592
 
 
593
 
def selftest(verbose=False, pattern=".*", stop_on_failure=True,
594
 
             keep_output=False):
 
286
                
 
287
 
 
288
 
 
289
class MetaTestLog(TestCase):
 
290
    def test_logging(self):
 
291
        """Test logs are captured when a test fails."""
 
292
        logging.info('an info message')
 
293
        warning('something looks dodgy...')
 
294
        logging.debug('hello, test is running')
 
295
        ##assert 0
 
296
 
 
297
 
 
298
def selftest(verbose=False, pattern=".*"):
595
299
    """Run the whole test suite under the enhanced runner"""
596
 
    return run_suite(test_suite(), 'testbzr', verbose=verbose, pattern=pattern,
597
 
                     stop_on_failure=stop_on_failure, keep_output=keep_output)
 
300
    return testsweet.run_suite(test_suite(), 'testbzr', verbose=verbose, pattern=pattern)
598
301
 
599
302
 
600
303
def test_suite():
601
304
    """Build and return TestSuite for the whole program."""
 
305
    from bzrlib.selftest.TestUtil import TestLoader, TestSuite
 
306
    import bzrlib, bzrlib.store, bzrlib.inventory, bzrlib.branch
 
307
    import bzrlib.osutils, bzrlib.commands, bzrlib.merge3, bzrlib.plugin
602
308
    from doctest import DocTestSuite
603
 
 
604
 
    global MODULES_TO_DOCTEST
605
 
 
606
 
    testmod_names = [ \
607
 
                   'bzrlib.tests.test_api',
608
 
                   'bzrlib.tests.test_gpg',
609
 
                   'bzrlib.tests.test_identitymap',
610
 
                   'bzrlib.tests.test_inv',
611
 
                   'bzrlib.tests.test_ancestry',
612
 
                   'bzrlib.tests.test_commit',
613
 
                   'bzrlib.tests.test_command',
614
 
                   'bzrlib.tests.test_commit_merge',
615
 
                   'bzrlib.tests.test_config',
616
 
                   'bzrlib.tests.test_merge3',
617
 
                   'bzrlib.tests.test_merge',
618
 
                   'bzrlib.tests.test_hashcache',
619
 
                   'bzrlib.tests.test_status',
620
 
                   'bzrlib.tests.test_log',
621
 
                   'bzrlib.tests.test_revisionnamespaces',
622
 
                   'bzrlib.tests.test_branch',
623
 
                   'bzrlib.tests.test_revision',
624
 
                   'bzrlib.tests.test_revision_info',
625
 
                   'bzrlib.tests.test_merge_core',
626
 
                   'bzrlib.tests.test_smart_add',
627
 
                   'bzrlib.tests.test_bad_files',
628
 
                   'bzrlib.tests.test_diff',
629
 
                   'bzrlib.tests.test_parent',
630
 
                   'bzrlib.tests.test_xml',
631
 
                   'bzrlib.tests.test_weave',
632
 
                   'bzrlib.tests.test_fetch',
633
 
                   'bzrlib.tests.test_whitebox',
634
 
                   'bzrlib.tests.test_store',
635
 
                   'bzrlib.tests.test_sampler',
636
 
                   'bzrlib.tests.test_transactions',
637
 
                   'bzrlib.tests.test_transport',
638
 
                   'bzrlib.tests.test_sftp',
639
 
                   'bzrlib.tests.test_graph',
640
 
                   'bzrlib.tests.test_workingtree',
641
 
                   'bzrlib.tests.test_upgrade',
642
 
                   'bzrlib.tests.test_uncommit',
643
 
                   'bzrlib.tests.test_ui',
644
 
                   'bzrlib.tests.test_conflicts',
645
 
                   'bzrlib.tests.test_testament',
646
 
                   'bzrlib.tests.test_annotate',
647
 
                   'bzrlib.tests.test_revprops',
648
 
                   'bzrlib.tests.test_options',
649
 
                   'bzrlib.tests.test_http',
650
 
                   'bzrlib.tests.test_nonascii',
651
 
                   'bzrlib.tests.test_reweave',
652
 
                   'bzrlib.tests.test_tsort',
653
 
                   'bzrlib.tests.test_trace',
654
 
                   'bzrlib.tests.test_rio',
655
 
                   'bzrlib.tests.test_msgeditor',
656
 
                   'bzrlib.tests.test_selftest',
 
309
    import os
 
310
    import shutil
 
311
    import time
 
312
    import sys
 
313
 
 
314
    global MODULES_TO_TEST, MODULES_TO_DOCTEST
 
315
 
 
316
    testmod_names = \
 
317
                  ['bzrlib.selftest.MetaTestLog',
 
318
                   'bzrlib.selftest.testinv',
 
319
                   'bzrlib.selftest.test_commit',
 
320
                   'bzrlib.selftest.test_commit_merge',
 
321
                   'bzrlib.selftest.versioning',
 
322
                   'bzrlib.selftest.testmerge3',
 
323
                   'bzrlib.selftest.testhashcache',
 
324
                   'bzrlib.selftest.teststatus',
 
325
                   'bzrlib.selftest.testlog',
 
326
                   'bzrlib.selftest.testrevisionnamespaces',
 
327
                   'bzrlib.selftest.testbranch',
 
328
                   'bzrlib.selftest.testrevision',
 
329
                   'bzrlib.selftest.test_merge_core',
 
330
                   'bzrlib.selftest.test_smart_add',
 
331
                   'bzrlib.selftest.testdiff',
 
332
                   'bzrlib.selftest.test_parent',
 
333
                   'bzrlib.selftest.test_xml',
 
334
                   'bzrlib.selftest.test_weave',
 
335
                   'bzrlib.selftest.testfetch',
 
336
                   'bzrlib.selftest.whitebox',
 
337
                   'bzrlib.selftest.teststore',
 
338
                   'bzrlib.selftest.blackbox',
657
339
                   ]
658
340
 
659
 
    print '%10s: %s' % ('bzr', os.path.realpath(sys.argv[0]))
660
 
    print '%10s: %s' % ('bzrlib', bzrlib.__path__[0])
 
341
    for m in (bzrlib.store, bzrlib.inventory, bzrlib.branch,
 
342
              bzrlib.osutils, bzrlib.commands, bzrlib.merge3):
 
343
        if m not in MODULES_TO_DOCTEST:
 
344
            MODULES_TO_DOCTEST.append(m)
 
345
 
 
346
    TestCase.BZRPATH = os.path.join(os.path.realpath(os.path.dirname(bzrlib.__path__[0])), 'bzr')
 
347
    print '%-30s %s' % ('bzr binary', TestCase.BZRPATH)
661
348
    print
662
349
    suite = TestSuite()
663
 
    # python2.4's TestLoader.loadTestsFromNames gives very poor 
664
 
    # errors if it fails to load a named module - no indication of what's
665
 
    # actually wrong, just "no such module".  We should probably override that
666
 
    # class, but for the moment just load them ourselves. (mbp 20051202)
667
 
    loader = TestLoader()
668
 
    for mod_name in testmod_names:
669
 
        mod = _load_module_by_name(mod_name)
670
 
        suite.addTest(loader.loadTestsFromModule(mod))
671
 
    for package in packages_to_test():
672
 
        suite.addTest(package.test_suite())
 
350
    suite.addTest(TestLoader().loadTestsFromNames(testmod_names))
673
351
    for m in MODULES_TO_TEST:
674
 
        suite.addTest(loader.loadTestsFromModule(m))
 
352
         suite.addTest(TestLoader().loadTestsFromModule(m))
675
353
    for m in (MODULES_TO_DOCTEST):
676
354
        suite.addTest(DocTestSuite(m))
677
355
    for p in bzrlib.plugin.all_plugins:
679
357
            suite.addTest(p.test_suite())
680
358
    return suite
681
359
 
682
 
 
683
 
def _load_module_by_name(mod_name):
684
 
    parts = mod_name.split('.')
685
 
    module = __import__(mod_name)
686
 
    del parts[0]
687
 
    # for historical reasons python returns the top-level module even though
688
 
    # it loads the submodule; we need to walk down to get the one we want.
689
 
    while parts:
690
 
        module = getattr(module, parts.pop(0))
691
 
    return module