18
18
from cStringIO import StringIO
30
29
import bzrlib.commands
31
30
import bzrlib.trace
32
31
import bzrlib.fetch
33
import bzrlib.osutils as osutils
34
from bzrlib.selftest import TestUtil
35
from bzrlib.selftest.TestUtil import TestLoader, TestSuite
36
from bzrlib.selftest.treeshape import build_tree_contents
38
34
MODULES_TO_TEST = []
39
35
MODULES_TO_DOCTEST = []
41
37
from logging import debug, warning, error
45
class EarlyStoppingTestResultAdapter(object):
46
"""An adapter for TestResult to stop at the first first failure or error"""
48
def __init__(self, result):
51
def addError(self, test, err):
52
self._result.addError(test, err)
55
def addFailure(self, test, err):
56
self._result.addFailure(test, err)
59
def __getattr__(self, name):
60
return getattr(self._result, name)
62
def __setattr__(self, name, value):
64
object.__setattr__(self, name, value)
65
return setattr(self._result, name, value)
68
class _MyResult(unittest._TextTestResult):
72
No special behaviour for now.
75
def _elapsedTime(self):
76
return "(Took %.3fs)" % (time.time() - self._start_time)
78
def startTest(self, test):
79
unittest.TestResult.startTest(self, test)
80
# TODO: Maybe show test.shortDescription somewhere?
81
what = test.shortDescription() or test.id()
83
self.stream.write('%-70.70s' % what)
85
self._start_time = time.time()
87
def addError(self, test, err):
88
unittest.TestResult.addError(self, test, err)
90
self.stream.writeln("ERROR %s" % self._elapsedTime())
92
self.stream.write('E')
95
def addFailure(self, test, err):
96
unittest.TestResult.addFailure(self, test, err)
98
self.stream.writeln("FAIL %s" % self._elapsedTime())
100
self.stream.write('F')
103
def addSuccess(self, test):
105
self.stream.writeln('OK %s' % self._elapsedTime())
107
self.stream.write('~')
109
unittest.TestResult.addSuccess(self, test)
111
def printErrorList(self, flavour, errors):
112
for test, err in errors:
113
self.stream.writeln(self.separator1)
114
self.stream.writeln("%s: %s" % (flavour,self.getDescription(test)))
115
if hasattr(test, '_get_log'):
116
self.stream.writeln()
117
self.stream.writeln('log from this test:')
118
print >>self.stream, test._get_log()
119
self.stream.writeln(self.separator2)
120
self.stream.writeln("%s" % err)
123
class TextTestRunner(unittest.TextTestRunner):
124
stop_on_failure = False
126
def _makeResult(self):
127
result = _MyResult(self.stream, self.descriptions, self.verbosity)
128
if self.stop_on_failure:
129
result = EarlyStoppingTestResultAdapter(result)
133
def iter_suite_tests(suite):
134
"""Return all tests in a suite, recursing through nested suites"""
135
for item in suite._tests:
136
if isinstance(item, unittest.TestCase):
138
elif isinstance(item, unittest.TestSuite):
139
for r in iter_suite_tests(item):
142
raise Exception('unknown object %r inside test suite %r'
146
class TestSkipped(Exception):
147
"""Indicates that a test was intentionally skipped, rather than failing."""
151
39
class CommandFailed(Exception):
165
53
routine, and to build and check bzr trees."""
168
_log_file_name = None
58
# this replaces the default testsweet.TestCase; we don't want logging changed
171
59
unittest.TestCase.setUp(self)
172
self.oldenv = os.environ.get('HOME', None)
173
os.environ['HOME'] = os.getcwd()
174
self.bzr_email = os.environ.get('BZREMAIL')
175
if self.bzr_email is not None:
176
del os.environ['BZREMAIL']
177
self.email = os.environ.get('EMAIL')
178
if self.email is not None:
179
del os.environ['EMAIL']
180
60
bzrlib.trace.disable_default_logging()
181
61
self._enable_file_logging()
183
def _ndiff_strings(self, a, b):
184
"""Return ndiff between two strings containing lines.
186
A trailing newline is added if missing to make the strings
188
if b and b[-1] != '\n':
190
if a and a[-1] != '\n':
192
difflines = difflib.ndiff(a.splitlines(True),
194
linejunk=lambda x: False,
195
charjunk=lambda x: False)
196
return ''.join(difflines)
198
def assertEqualDiff(self, a, b):
199
"""Assert two texts are equal, if not raise an exception.
201
This is intended for use with multi-line strings where it can
202
be hard to find the differences by eye.
204
# TODO: perhaps override assertEquals to call this for strings?
207
raise AssertionError("texts not equal:\n" +
208
self._ndiff_strings(a, b))
210
def assertContainsRe(self, haystack, needle_re):
211
"""Assert that a contains something matching a regular expression."""
212
if not re.search(needle_re, haystack):
213
raise AssertionError('pattern "%s" not found in "%s"'
214
% (needle_re, haystack))
216
64
def _enable_file_logging(self):
217
65
fileno, name = tempfile.mkstemp(suffix='.log', prefix='testbzr')
229
77
self._log_file_name = name
231
79
def tearDown(self):
232
os.environ['HOME'] = self.oldenv
233
if os.environ.get('BZREMAIL') is not None:
234
del os.environ['BZREMAIL']
235
if self.bzr_email is not None:
236
os.environ['BZREMAIL'] = self.bzr_email
237
if os.environ.get('EMAIL') is not None:
238
del os.environ['EMAIL']
239
if self.email is not None:
240
os.environ['EMAIL'] = self.email
241
80
logging.getLogger('').removeHandler(self._log_hdlr)
242
81
bzrlib.trace.enable_default_logging()
243
82
logging.debug('%s teardown', self.id())
449
286
print >>f, "contents of", name
452
def build_tree_contents(self, shape):
453
bzrlib.selftest.build_tree_contents(shape)
455
def failUnlessExists(self, path):
456
"""Fail unless path, which may be abs or relative, exists."""
457
self.failUnless(osutils.lexists(path))
459
def assertFileEqual(self, content, path):
460
"""Fail if path does not contain 'content'."""
461
self.failUnless(osutils.lexists(path))
462
self.assertEqualDiff(content, open(path, 'r').read())
465
290
class MetaTestLog(TestCase):
466
291
def test_logging(self):
468
293
logging.info('an info message')
469
294
warning('something looks dodgy...')
470
295
logging.debug('hello, test is running')
474
def filter_suite_by_re(suite, pattern):
475
result = TestUtil.TestSuite()
476
filter_re = re.compile(pattern)
477
for test in iter_suite_tests(suite):
478
if filter_re.search(test.id()):
483
def run_suite(suite, name='test', verbose=False, pattern=".*",
484
stop_on_failure=False):
485
TestCaseInTempDir._TEST_NAME = name
490
runner = TextTestRunner(stream=sys.stdout,
493
runner.stop_on_failure=stop_on_failure
495
suite = filter_suite_by_re(suite, pattern)
496
result = runner.run(suite)
497
# This is still a little bogus,
498
# but only a little. Folk not using our testrunner will
499
# have to delete their temp directories themselves.
500
if result.wasSuccessful():
501
if TestCaseInTempDir.TEST_ROOT is not None:
502
shutil.rmtree(TestCaseInTempDir.TEST_ROOT)
504
print "Failed tests working directories are in '%s'\n" % TestCaseInTempDir.TEST_ROOT
505
return result.wasSuccessful()
508
def selftest(verbose=False, pattern=".*", stop_on_failure=True):
299
def selftest(verbose=False, pattern=".*"):
509
300
"""Run the whole test suite under the enhanced runner"""
510
return run_suite(test_suite(), 'testbzr', verbose=verbose, pattern=pattern,
511
stop_on_failure=stop_on_failure)
301
return testsweet.run_suite(test_suite(), 'testbzr', verbose=verbose, pattern=pattern)
514
304
def test_suite():
515
305
"""Build and return TestSuite for the whole program."""
516
import bzrlib.store, bzrlib.inventory, bzrlib.branch
517
import bzrlib.osutils, bzrlib.merge3, bzrlib.plugin
306
from bzrlib.selftest.TestUtil import TestLoader, TestSuite
307
import bzrlib, bzrlib.store, bzrlib.inventory, bzrlib.branch
308
import bzrlib.osutils, bzrlib.commands, bzrlib.merge3, bzrlib.plugin
518
309
from doctest import DocTestSuite
520
311
global MODULES_TO_TEST, MODULES_TO_DOCTEST
522
313
testmod_names = \
523
314
['bzrlib.selftest.MetaTestLog',
524
'bzrlib.selftest.testgpg',
525
'bzrlib.selftest.testidentitymap',
526
315
'bzrlib.selftest.testinv',
527
316
'bzrlib.selftest.test_ancestry',
528
317
'bzrlib.selftest.test_commit',
529
318
'bzrlib.selftest.test_commit_merge',
530
'bzrlib.selftest.testconfig',
531
319
'bzrlib.selftest.versioning',
532
320
'bzrlib.selftest.testmerge3',
533
321
'bzrlib.selftest.testmerge',
549
338
'bzrlib.selftest.whitebox',
550
339
'bzrlib.selftest.teststore',
551
340
'bzrlib.selftest.blackbox',
552
'bzrlib.selftest.testsampler',
553
'bzrlib.selftest.testtransactions',
554
'bzrlib.selftest.testtransport',
555
341
'bzrlib.selftest.testgraph',
556
'bzrlib.selftest.testworkingtree',
557
'bzrlib.selftest.test_upgrade',
558
'bzrlib.selftest.test_conflicts',
559
'bzrlib.selftest.testtestament',
560
'bzrlib.selftest.testannotate',
561
'bzrlib.selftest.testrevprops',
562
'bzrlib.selftest.testoptions',
563
'bzrlib.selftest.testhttp',
564
'bzrlib.selftest.testnonascii',
567
344
for m in (bzrlib.store, bzrlib.inventory, bzrlib.branch,
568
bzrlib.osutils, bzrlib.commands, bzrlib.merge3,
345
bzrlib.osutils, bzrlib.commands, bzrlib.merge3):
571
346
if m not in MODULES_TO_DOCTEST:
572
347
MODULES_TO_DOCTEST.append(m)