95
138
def addFailure(self, test, err):
96
139
unittest.TestResult.addFailure(self, test, err)
98
self.stream.writeln("FAIL %s" % self._elapsedTime())
141
self.stream.writeln(" FAIL %s" % self._elapsedTime())
100
143
self.stream.write('F')
101
144
self.stream.flush()
103
146
def addSuccess(self, test):
105
self.stream.writeln('OK %s' % self._elapsedTime())
148
self.stream.writeln(' OK %s' % self._elapsedTime())
107
150
self.stream.write('~')
108
151
self.stream.flush()
109
152
unittest.TestResult.addSuccess(self, test)
154
def addSkipped(self, test, skip_excinfo):
156
print >>self.stream, ' SKIP %s' % self._elapsedTime()
157
print >>self.stream, ' %s' % skip_excinfo[1]
159
self.stream.write('S')
161
# seems best to treat this as success from point-of-view of unittest
162
# -- it actually does nothing so it barely matters :)
163
unittest.TestResult.addSuccess(self, test)
111
165
def printErrorList(self, flavour, errors):
112
166
for test, err in errors:
113
167
self.stream.writeln(self.separator1)
114
self.stream.writeln("%s: %s" % (flavour,self.getDescription(test)))
168
self.stream.writeln("%s: %s" % (flavour, self.getDescription(test)))
115
169
if hasattr(test, '_get_log'):
116
self.stream.writeln()
117
self.stream.writeln('log from this test:')
171
print >>self.stream, \
172
('vvvv[log from %s]' % test.id()).ljust(78,'-')
118
173
print >>self.stream, test._get_log()
174
print >>self.stream, \
175
('^^^^[log from %s]' % test.id()).ljust(78,'-')
119
176
self.stream.writeln(self.separator2)
120
177
self.stream.writeln("%s" % err)
123
180
class TextTestRunner(unittest.TextTestRunner):
181
stop_on_failure = False
125
183
def _makeResult(self):
126
184
result = _MyResult(self.stream, self.descriptions, self.verbosity)
127
return EarlyStoppingTestResultAdapter(result)
185
if self.stop_on_failure:
186
result = EarlyStoppingTestResultAdapter(result)
130
190
def iter_suite_tests(suite):
189
267
raise AssertionError("texts not equal:\n" +
190
268
self._ndiff_strings(a, b))
192
def _enable_file_logging(self):
270
def assertStartsWith(self, s, prefix):
271
if not s.startswith(prefix):
272
raise AssertionError('string %r does not start with %r' % (s, prefix))
274
def assertEndsWith(self, s, suffix):
275
if not s.endswith(prefix):
276
raise AssertionError('string %r does not end with %r' % (s, suffix))
278
def assertContainsRe(self, haystack, needle_re):
279
"""Assert that a contains something matching a regular expression."""
280
if not re.search(needle_re, haystack):
281
raise AssertionError('pattern "%s" not found in "%s"'
282
% (needle_re, haystack))
284
def AssertSubset(self, sublist, superlist):
285
"""Assert that every entry in sublist is present in superlist."""
287
for entry in sublist:
288
if entry not in superlist:
289
missing.append(entry)
291
raise AssertionError("value(s) %r not present in container %r" %
292
(missing, superlist))
294
def assertTransportMode(self, transport, path, mode):
295
"""Fail if a path does not have mode mode.
297
If modes are not supported on this platform, the test is skipped.
299
if sys.platform == 'win32':
301
path_stat = transport.stat(path)
302
actual_mode = stat.S_IMODE(path_stat.st_mode)
303
self.assertEqual(mode, actual_mode,
304
'mode of %r incorrect (%o != %o)' % (path, mode, actual_mode))
306
def _startLogFile(self):
307
"""Send bzr and test log messages to a temporary file.
309
The file is removed as the test is torn down.
193
311
fileno, name = tempfile.mkstemp(suffix='.log', prefix='testbzr')
195
self._log_file = os.fdopen(fileno, 'w+')
197
hdlr = logging.StreamHandler(self._log_file)
198
hdlr.setLevel(logging.DEBUG)
199
hdlr.setFormatter(logging.Formatter('%(levelname)8s %(message)s'))
200
logging.getLogger('').addHandler(hdlr)
201
logging.getLogger('').setLevel(logging.DEBUG)
202
self._log_hdlr = hdlr
203
debug('opened log file %s', name)
312
encoder, decoder, stream_reader, stream_writer = codecs.lookup('UTF-8')
313
self._log_file = stream_writer(os.fdopen(fileno, 'w+'))
314
bzrlib.trace.enable_test_log(self._log_file)
205
315
self._log_file_name = name
208
logging.getLogger('').removeHandler(self._log_hdlr)
209
bzrlib.trace.enable_default_logging()
210
logging.debug('%s teardown', self.id())
316
self.addCleanup(self._finishLogFile)
318
def _finishLogFile(self):
319
"""Finished with the log file.
321
Read contents into memory, close, and delete.
323
bzrlib.trace.disable_test_log()
324
self._log_file.seek(0)
325
self._log_contents = self._log_file.read()
211
326
self._log_file.close()
327
os.remove(self._log_file_name)
328
self._log_file = self._log_file_name = None
330
def addCleanup(self, callable):
331
"""Arrange to run a callable when this case is torn down.
333
Callables are run in the reverse of the order they are registered,
334
ie last-in first-out.
336
if callable in self._cleanups:
337
raise ValueError("cleanup function %r already registered on %s"
339
self._cleanups.append(callable)
341
def _cleanEnvironment(self):
344
'APPDATA': os.getcwd(),
349
self.addCleanup(self._restoreEnvironment)
350
for name, value in new_env.iteritems():
351
self._captureVar(name, value)
354
def _captureVar(self, name, newvalue):
355
"""Set an environment variable, preparing it to be reset when finished."""
356
self.__old_env[name] = os.environ.get(name, None)
358
if name in os.environ:
361
os.environ[name] = newvalue
364
def _restoreVar(name, value):
366
if name in os.environ:
369
os.environ[name] = value
371
def _restoreEnvironment(self):
372
for name, value in self.__old_env.iteritems():
373
self._restoreVar(name, value)
212
377
unittest.TestCase.tearDown(self)
379
def _runCleanups(self):
380
"""Run registered cleanup functions.
382
This should only be called from TestCase.tearDown.
384
# TODO: Perhaps this should keep running cleanups even if
386
for cleanup_fn in reversed(self._cleanups):
214
389
def log(self, *args):
217
392
def _get_log(self):
218
393
"""Return as a string the log for this test"""
219
394
if self._log_file_name:
220
395
return open(self._log_file_name).read()
397
return self._log_contents
398
# TODO: Delete the log after it's been read in
224
def capture(self, cmd):
400
def capture(self, cmd, retcode=0):
225
401
"""Shortcut that splits cmd into words, runs, and returns stdout"""
226
return self.run_bzr_captured(cmd.split())[0]
402
return self.run_bzr_captured(cmd.split(), retcode=retcode)[0]
228
404
def run_bzr_captured(self, argv, retcode=0):
229
"""Invoke bzr and return (result, stdout, stderr).
405
"""Invoke bzr and return (stdout, stderr).
231
407
Useful for code that wants to check the contents of the
232
408
output, the way error messages are presented, etc.
380
557
# successfully created
381
TestCaseInTempDir.TEST_ROOT = os.path.abspath(root)
558
TestCaseInTempDir.TEST_ROOT = osutils.abspath(root)
383
560
# make a fake bzr directory there to prevent any tests propagating
384
561
# up onto the source directory's real branch
385
os.mkdir(os.path.join(TestCaseInTempDir.TEST_ROOT, '.bzr'))
562
os.mkdir(osutils.pathjoin(TestCaseInTempDir.TEST_ROOT, '.bzr'))
388
565
super(TestCaseInTempDir, self).setUp()
389
566
self._make_test_root()
390
self._currentdir = os.getcwdu()
391
short_id = self.id().replace('bzrlib.selftest.', '') \
567
_currentdir = os.getcwdu()
568
short_id = self.id().replace('bzrlib.tests.', '') \
392
569
.replace('__main__.', '')
393
self.test_dir = os.path.join(self.TEST_ROOT, short_id)
570
self.test_dir = osutils.pathjoin(self.TEST_ROOT, short_id)
394
571
os.mkdir(self.test_dir)
395
572
os.chdir(self.test_dir)
573
os.environ['HOME'] = self.test_dir
574
os.environ['APPDATA'] = self.test_dir
575
def _leaveDirectory():
576
os.chdir(_currentdir)
577
self.addCleanup(_leaveDirectory)
398
os.chdir(self._currentdir)
399
super(TestCaseInTempDir, self).tearDown()
401
def build_tree(self, shape):
579
def build_tree(self, shape, line_endings='native', transport=None):
402
580
"""Build a test tree according to a pattern.
404
582
shape is a sequence of file specifications. If the final
405
583
character is '/', a directory is created.
407
585
This doesn't add anything to a branch.
586
:param line_endings: Either 'binary' or 'native'
587
in binary mode, exact contents are written
588
in native mode, the line endings match the
589
default platform endings.
591
:param transport: A transport to write to, for building trees on
592
VFS's. If the transport is readonly or None,
593
"." is opened automatically.
409
595
# XXX: It's OK to just create them using forward slashes on windows?
596
if transport is None or transport.is_readonly():
597
transport = bzrlib.transport.get_transport(".")
410
598
for name in shape:
411
assert isinstance(name, basestring)
599
self.assert_(isinstance(name, basestring))
412
600
if name[-1] == '/':
601
transport.mkdir(urlescape(name[:-1]))
416
print >>f, "contents of", name
603
if line_endings == 'binary':
605
elif line_endings == 'native':
608
raise BzrError('Invalid line ending request %r' % (line_endings,))
609
content = "contents of %s%s" % (name, end)
610
transport.put(urlescape(name), StringIO(content))
612
def build_tree_contents(self, shape):
613
build_tree_contents(shape)
419
615
def failUnlessExists(self, path):
420
616
"""Fail unless path, which may be abs or relative, exists."""
421
617
self.failUnless(osutils.lexists(path))
619
def failIfExists(self, path):
620
"""Fail if path, which may be abs or relative, exists."""
621
self.failIf(osutils.lexists(path))
424
class MetaTestLog(TestCase):
425
def test_logging(self):
426
"""Test logs are captured when a test fails."""
427
logging.info('an info message')
428
warning('something looks dodgy...')
429
logging.debug('hello, test is running')
623
def assertFileEqual(self, content, path):
624
"""Fail if path does not contain 'content'."""
625
self.failUnless(osutils.lexists(path))
626
self.assertEqualDiff(content, open(path, 'r').read())
433
629
def filter_suite_by_re(suite, pattern):
434
result = TestUtil.TestSuite()
435
631
filter_re = re.compile(pattern)
436
632
for test in iter_suite_tests(suite):
437
633
if filter_re.search(test.id()):
462
660
return result.wasSuccessful()
465
def selftest(verbose=False, pattern=".*"):
663
def selftest(verbose=False, pattern=".*", stop_on_failure=True,
466
665
"""Run the whole test suite under the enhanced runner"""
467
return run_suite(test_suite(), 'testbzr', verbose=verbose, pattern=pattern)
666
return run_suite(test_suite(), 'testbzr', verbose=verbose, pattern=pattern,
667
stop_on_failure=stop_on_failure, keep_output=keep_output)
470
670
def test_suite():
471
671
"""Build and return TestSuite for the whole program."""
472
import bzrlib.store, bzrlib.inventory, bzrlib.branch
473
import bzrlib.osutils, bzrlib.merge3, bzrlib.plugin
474
672
from doctest import DocTestSuite
476
global MODULES_TO_TEST, MODULES_TO_DOCTEST
674
global MODULES_TO_DOCTEST
479
['bzrlib.selftest.MetaTestLog',
480
'bzrlib.selftest.testidentitymap',
481
'bzrlib.selftest.testinv',
482
'bzrlib.selftest.test_ancestry',
483
'bzrlib.selftest.test_commit',
484
'bzrlib.selftest.test_commit_merge',
485
'bzrlib.selftest.testconfig',
486
'bzrlib.selftest.versioning',
487
'bzrlib.selftest.testmerge3',
488
'bzrlib.selftest.testmerge',
489
'bzrlib.selftest.testhashcache',
490
'bzrlib.selftest.teststatus',
491
'bzrlib.selftest.testlog',
492
'bzrlib.selftest.testrevisionnamespaces',
493
'bzrlib.selftest.testbranch',
494
'bzrlib.selftest.testrevision',
495
'bzrlib.selftest.test_revision_info',
496
'bzrlib.selftest.test_merge_core',
497
'bzrlib.selftest.test_smart_add',
498
'bzrlib.selftest.test_bad_files',
499
'bzrlib.selftest.testdiff',
500
'bzrlib.selftest.test_parent',
501
'bzrlib.selftest.test_xml',
502
'bzrlib.selftest.test_weave',
503
'bzrlib.selftest.testfetch',
504
'bzrlib.selftest.whitebox',
505
'bzrlib.selftest.teststore',
506
'bzrlib.selftest.blackbox',
507
'bzrlib.selftest.testsampler',
508
'bzrlib.selftest.testtransactions',
509
'bzrlib.selftest.testtransport',
510
'bzrlib.selftest.testgraph',
511
'bzrlib.selftest.testworkingtree',
512
'bzrlib.selftest.test_upgrade',
513
'bzrlib.selftest.test_conflicts',
514
'bzrlib.selftest.testtestament',
515
'bzrlib.selftest.testannotate',
516
'bzrlib.selftest.testrevprops',
677
'bzrlib.tests.test_ancestry',
678
'bzrlib.tests.test_annotate',
679
'bzrlib.tests.test_api',
680
'bzrlib.tests.test_bad_files',
681
'bzrlib.tests.test_basis_inventory',
682
'bzrlib.tests.test_branch',
683
'bzrlib.tests.test_command',
684
'bzrlib.tests.test_commit',
685
'bzrlib.tests.test_commit_merge',
686
'bzrlib.tests.test_config',
687
'bzrlib.tests.test_conflicts',
688
'bzrlib.tests.test_diff',
689
'bzrlib.tests.test_fetch',
690
'bzrlib.tests.test_gpg',
691
'bzrlib.tests.test_graph',
692
'bzrlib.tests.test_hashcache',
693
'bzrlib.tests.test_http',
694
'bzrlib.tests.test_identitymap',
695
'bzrlib.tests.test_inv',
696
'bzrlib.tests.test_log',
697
'bzrlib.tests.test_merge',
698
'bzrlib.tests.test_merge3',
699
'bzrlib.tests.test_merge_core',
700
'bzrlib.tests.test_missing',
701
'bzrlib.tests.test_msgeditor',
702
'bzrlib.tests.test_nonascii',
703
'bzrlib.tests.test_options',
704
'bzrlib.tests.test_osutils',
705
'bzrlib.tests.test_parent',
706
'bzrlib.tests.test_permissions',
707
'bzrlib.tests.test_plugins',
708
'bzrlib.tests.test_remove',
709
'bzrlib.tests.test_revision',
710
'bzrlib.tests.test_revisionnamespaces',
711
'bzrlib.tests.test_revprops',
712
'bzrlib.tests.test_reweave',
713
'bzrlib.tests.test_rio',
714
'bzrlib.tests.test_sampler',
715
'bzrlib.tests.test_selftest',
716
'bzrlib.tests.test_setup',
717
'bzrlib.tests.test_sftp_transport',
718
'bzrlib.tests.test_smart_add',
719
'bzrlib.tests.test_source',
720
'bzrlib.tests.test_status',
721
'bzrlib.tests.test_store',
722
'bzrlib.tests.test_symbol_versioning',
723
'bzrlib.tests.test_testament',
724
'bzrlib.tests.test_trace',
725
'bzrlib.tests.test_transactions',
726
'bzrlib.tests.test_transport',
727
'bzrlib.tests.test_tsort',
728
'bzrlib.tests.test_ui',
729
'bzrlib.tests.test_uncommit',
730
'bzrlib.tests.test_upgrade',
731
'bzrlib.tests.test_weave',
732
'bzrlib.tests.test_whitebox',
733
'bzrlib.tests.test_workingtree',
734
'bzrlib.tests.test_xml',
519
for m in (bzrlib.store, bzrlib.inventory, bzrlib.branch,
520
bzrlib.osutils, bzrlib.commands, bzrlib.merge3):
521
if m not in MODULES_TO_DOCTEST:
522
MODULES_TO_DOCTEST.append(m)
524
TestCase.BZRPATH = os.path.join(os.path.realpath(os.path.dirname(bzrlib.__path__[0])), 'bzr')
525
print '%-30s %s' % ('bzr binary', TestCase.BZRPATH)
736
test_transport_implementations = [
737
'bzrlib.tests.test_transport_implementations']
739
TestCase.BZRPATH = osutils.pathjoin(
740
osutils.realpath(osutils.dirname(bzrlib.__path__[0])), 'bzr')
741
print '%10s: %s' % ('bzr', osutils.realpath(sys.argv[0]))
742
print '%10s: %s' % ('bzrlib', bzrlib.__path__[0])
527
744
suite = TestSuite()
528
suite.addTest(TestLoader().loadTestsFromNames(testmod_names))
745
# python2.4's TestLoader.loadTestsFromNames gives very poor
746
# errors if it fails to load a named module - no indication of what's
747
# actually wrong, just "no such module". We should probably override that
748
# class, but for the moment just load them ourselves. (mbp 20051202)
749
loader = TestLoader()
750
from bzrlib.transport import TransportTestProviderAdapter
751
adapter = TransportTestProviderAdapter()
752
for mod_name in test_transport_implementations:
753
mod = _load_module_by_name(mod_name)
754
for test in iter_suite_tests(loader.loadTestsFromModule(mod)):
755
suite.addTests(adapter.adapt(test))
756
for mod_name in testmod_names:
757
mod = _load_module_by_name(mod_name)
758
suite.addTest(loader.loadTestsFromModule(mod))
759
for package in packages_to_test():
760
suite.addTest(package.test_suite())
529
761
for m in MODULES_TO_TEST:
530
suite.addTest(TestLoader().loadTestsFromModule(m))
762
suite.addTest(loader.loadTestsFromModule(m))
531
763
for m in (MODULES_TO_DOCTEST):
532
764
suite.addTest(DocTestSuite(m))
533
for p in bzrlib.plugin.all_plugins:
534
if hasattr(p, 'test_suite'):
535
suite.addTest(p.test_suite())
765
for name, plugin in bzrlib.plugin.all_plugins().items():
766
if hasattr(plugin, 'test_suite'):
767
suite.addTest(plugin.test_suite())
771
def _load_module_by_name(mod_name):
772
parts = mod_name.split('.')
773
module = __import__(mod_name)
775
# for historical reasons python returns the top-level module even though
776
# it loads the submodule; we need to walk down to get the one we want.
778
module = getattr(module, parts.pop(0))