162
161
class ExtendedTestResult(unittest._TextTestResult):
163
162
"""Accepts, reports and accumulates the results of running tests.
165
Compared to this unittest version this class adds support for
164
Compared to the unittest version this class adds support for
166
165
profiling, benchmarking, stopping as soon as a test fails, and
167
166
skipping tests. There are further-specialized subclasses for
168
167
different types of display.
343
342
except KeyboardInterrupt:
346
self.addError(test, test.__exc_info())
345
self.addError(test, test._exc_info())
348
347
# seems best to treat this as success from point-of-view of unittest
349
348
# -- it actually does nothing so it barely matters :)
355
354
self.stream.write("%s: " % flavour)
356
355
self.stream.writeln(self.getDescription(test))
357
356
if getattr(test, '_get_log', None) is not None:
359
print >>self.stream, \
360
('vvvv[log from %s]' % test.id()).ljust(78,'-')
361
print >>self.stream, test._get_log()
362
print >>self.stream, \
363
('^^^^[log from %s]' % test.id()).ljust(78,'-')
357
self.stream.write('\n')
359
('vvvv[log from %s]' % test.id()).ljust(78,'-'))
360
self.stream.write('\n')
361
self.stream.write(test._get_log())
362
self.stream.write('\n')
364
('^^^^[log from %s]' % test.id()).ljust(78,'-'))
365
self.stream.write('\n')
364
366
self.stream.writeln(self.separator2)
365
367
self.stream.writeln("%s" % err)
983
985
self.assertEqual(mode, actual_mode,
984
986
'mode of %r incorrect (%o != %o)' % (path, mode, actual_mode))
988
def assertIsSameRealPath(self, path1, path2):
989
"""Fail if path1 and path2 points to different files"""
990
self.assertEqual(osutils.realpath(path1),
991
osutils.realpath(path2),
992
"apparent paths:\na = %s\nb = %s\n," % (path1, path2))
986
994
def assertIsInstance(self, obj, kls):
987
995
"""Fail if obj is not an instance of kls"""
988
996
if not isinstance(obj, kls):
1025
1033
self.fail('Unexpected success. Should have failed: %s' % reason)
1027
def _capture_warnings(self, a_callable, *args, **kwargs):
1035
def _capture_deprecation_warnings(self, a_callable, *args, **kwargs):
1028
1036
"""A helper for callDeprecated and applyDeprecated.
1030
1038
:param a_callable: A callable to call.
1072
1080
:param kwargs: The keyword arguments for the callable
1073
1081
:return: The result of a_callable(``*args``, ``**kwargs``)
1075
call_warnings, result = self._capture_warnings(a_callable,
1083
call_warnings, result = self._capture_deprecation_warnings(a_callable,
1076
1084
*args, **kwargs)
1077
1085
expected_first_warning = symbol_versioning.deprecation_string(
1078
1086
a_callable, deprecation_format)
1082
1090
self.assertEqual(expected_first_warning, call_warnings[0])
1093
def callCatchWarnings(self, fn, *args, **kw):
1094
"""Call a callable that raises python warnings.
1096
The caller's responsible for examining the returned warnings.
1098
If the callable raises an exception, the exception is not
1099
caught and propagates up to the caller. In that case, the list
1100
of warnings is not available.
1102
:returns: ([warning_object, ...], fn_result)
1104
# XXX: This is not perfect, because it completely overrides the
1105
# warnings filters, and some code may depend on suppressing particular
1106
# warnings. It's the easiest way to insulate ourselves from -Werror,
1107
# though. -- Andrew, 20071062
1109
def _catcher(message, category, filename, lineno, file=None):
1110
# despite the name, 'message' is normally(?) a Warning subclass
1112
wlist.append(message)
1113
saved_showwarning = warnings.showwarning
1114
saved_filters = warnings.filters
1116
warnings.showwarning = _catcher
1117
warnings.filters = []
1118
result = fn(*args, **kw)
1120
warnings.showwarning = saved_showwarning
1121
warnings.filters = saved_filters
1122
return wlist, result
1085
1124
def callDeprecated(self, expected, callable, *args, **kwargs):
1086
1125
"""Assert that a callable is deprecated in a particular way.
1091
1130
and will ensure that that is issued for the function being called.
1093
1132
Note that this only captures warnings raised by symbol_versioning.warn,
1094
not other callers that go direct to the warning module.
1133
not other callers that go direct to the warning module. To catch
1134
general warnings, use callCatchWarnings.
1096
1136
:param expected: a list of the deprecation warnings expected, in order
1097
1137
:param callable: The callable to call
1098
1138
:param args: The positional arguments for the callable
1099
1139
:param kwargs: The keyword arguments for the callable
1101
call_warnings, result = self._capture_warnings(callable,
1141
call_warnings, result = self._capture_deprecation_warnings(callable,
1102
1142
*args, **kwargs)
1103
1143
self.assertEqual(expected, call_warnings)
1148
1188
'BZR_HOME': None, # Don't inherit BZR_HOME to all the tests.
1149
1189
'HOME': os.getcwd(),
1150
1190
'APPDATA': None, # bzr now use Win32 API and don't rely on APPDATA
1191
'BZR_EDITOR': None, # test_msgeditor manipulates this variable
1151
1192
'BZR_EMAIL': None,
1152
1193
'BZREMAIL': None, # may still be present in the environment
1276
1317
os.remove(self._log_file_name)
1277
1318
except OSError, e:
1278
1319
if sys.platform == 'win32' and e.errno == errno.EACCES:
1279
print >>sys.stderr, ('Unable to delete log file '
1280
' %r' % self._log_file_name)
1320
sys.stderr.write(('Unable to delete log file '
1321
' %r\n' % self._log_file_name))
1283
1324
return log_contents
1285
1326
return "DELETED log file to reduce memory footprint"
1287
@deprecated_method(zero_eighteen)
1288
def capture(self, cmd, retcode=0):
1289
"""Shortcut that splits cmd into words, runs, and returns stdout"""
1290
return self.run_bzr_captured(cmd.split(), retcode=retcode)[0]
1292
1328
def requireFeature(self, feature):
1293
1329
"""This test requires a specific feature is available.
1297
1333
if not feature.available():
1298
1334
raise UnavailableFeature(feature)
1300
@deprecated_method(zero_eighteen)
1301
def run_bzr_captured(self, argv, retcode=0, encoding=None, stdin=None,
1303
"""Invoke bzr and return (stdout, stderr).
1305
Don't call this method, just use run_bzr() which is equivalent.
1307
:param argv: Arguments to invoke bzr. This may be either a
1308
single string, in which case it is split by shlex into words,
1309
or a list of arguments.
1310
:param retcode: Expected return code, or None for don't-care.
1311
:param encoding: Encoding for sys.stdout and sys.stderr
1312
:param stdin: A string to be used as stdin for the command.
1313
:param working_dir: Change to this directory before running
1315
return self._run_bzr_autosplit(argv, retcode=retcode,
1316
encoding=encoding, stdin=stdin, working_dir=working_dir,
1319
1336
def _run_bzr_autosplit(self, args, retcode, encoding, stdin,
1321
1338
"""Run bazaar command line, splitting up a string command line."""
1322
1339
if isinstance(args, basestring):
1323
args = list(shlex.split(args))
1340
# shlex don't understand unicode strings,
1341
# so args should be plain string (bialix 20070906)
1342
args = list(shlex.split(str(args)))
1324
1343
return self._run_bzr_core(args, retcode=retcode,
1325
1344
encoding=encoding, stdin=stdin, working_dir=working_dir,
1370
1389
message='Unexpected return code')
1371
1390
return out, err
1373
def run_bzr(self, *args, **kwargs):
1392
def run_bzr(self, args, retcode=0, encoding=None, stdin=None,
1393
working_dir=None, error_regexes=[], output_encoding=None):
1374
1394
"""Invoke bzr, as if it were run from the command line.
1376
1396
The argument list should not include the bzr program name - the
1384
1404
2- A single string, eg "add a". This is the most convenient
1385
1405
for hardcoded commands.
1387
3- Several varargs parameters, eg run_bzr("add", "a").
1388
This is not recommended for new code.
1390
1407
This runs bzr through the interface that catches and reports
1391
1408
errors, and with logging set to something approximating the
1392
1409
default, so that error reporting can be checked.
1405
1422
:keyword error_regexes: A list of expected error messages. If
1406
1423
specified they must be seen in the error output of the command.
1408
retcode = kwargs.pop('retcode', 0)
1409
encoding = kwargs.pop('encoding', None)
1410
stdin = kwargs.pop('stdin', None)
1411
working_dir = kwargs.pop('working_dir', None)
1412
error_regexes = kwargs.pop('error_regexes', [])
1415
raise TypeError("run_bzr() got unexpected keyword arguments '%s'"
1419
if isinstance(args[0], (list, basestring)):
1422
symbol_versioning.warn(zero_eighteen % "passing varargs to run_bzr",
1423
DeprecationWarning, stacklevel=3)
1425
out, err = self._run_bzr_autosplit(args=args,
1425
out, err = self._run_bzr_autosplit(
1426
1427
retcode=retcode,
1427
encoding=encoding, stdin=stdin, working_dir=working_dir,
1430
working_dir=working_dir,
1430
1432
for regex in error_regexes:
1431
1433
self.assertContainsRe(err, regex)
1432
1434
return out, err
1434
def run_bzr_decode(self, *args, **kwargs):
1435
if 'encoding' in kwargs:
1436
encoding = kwargs['encoding']
1438
encoding = bzrlib.user_encoding
1439
return self.run_bzr(*args, **kwargs)[0].decode(encoding)
1441
1436
def run_bzr_error(self, error_regexes, *args, **kwargs):
1442
1437
"""Run bzr, and check that stderr contains the supplied regexes
1875
1870
base = self.get_vfs_only_server().get_url()
1876
1871
return self._adjust_url(base, relpath)
1873
def _create_safety_net(self):
1874
"""Make a fake bzr directory.
1876
This prevents any tests propagating up onto the TEST_ROOT directory's
1879
root = TestCaseWithMemoryTransport.TEST_ROOT
1880
bzrdir.BzrDir.create_standalone_workingtree(root)
1882
def _check_safety_net(self):
1883
"""Check that the safety .bzr directory have not been touched.
1885
_make_test_root have created a .bzr directory to prevent tests from
1886
propagating. This method ensures than a test did not leaked.
1888
root = TestCaseWithMemoryTransport.TEST_ROOT
1889
wt = workingtree.WorkingTree.open(root)
1890
last_rev = wt.last_revision()
1891
if last_rev != 'null:':
1892
# The current test have modified the /bzr directory, we need to
1893
# recreate a new one or all the followng tests will fail.
1894
# If you need to inspect its content uncomment the following line
1895
# import pdb; pdb.set_trace()
1896
_rmtree_temp_dir(root + '/.bzr')
1897
self._create_safety_net()
1898
raise AssertionError('%s/.bzr should not be modified' % root)
1878
1900
def _make_test_root(self):
1879
if TestCaseWithMemoryTransport.TEST_ROOT is not None:
1881
root = tempfile.mkdtemp(prefix='testbzr-', suffix='.tmp')
1882
TestCaseWithMemoryTransport.TEST_ROOT = root
1884
# make a fake bzr directory there to prevent any tests propagating
1885
# up onto the source directory's real branch
1886
bzrdir.BzrDir.create_standalone_workingtree(root)
1888
# The same directory is used by all tests, and we're not specifically
1889
# told when all tests are finished. This will do.
1890
atexit.register(_rmtree_temp_dir, root)
1901
if TestCaseWithMemoryTransport.TEST_ROOT is None:
1902
root = osutils.mkdtemp(prefix='testbzr-', suffix='.tmp')
1903
TestCaseWithMemoryTransport.TEST_ROOT = root
1905
self._create_safety_net()
1907
# The same directory is used by all tests, and we're not
1908
# specifically told when all tests are finished. This will do.
1909
atexit.register(_rmtree_temp_dir, root)
1911
self.addCleanup(self._check_safety_net)
1892
1913
def makeAndChdirToTestDir(self):
1893
1914
"""Create a temporary directories for this one test.
1994
2015
name and then create two subdirs - test and home under it.
1996
2017
# create a directory within the top level test directory
1997
candidate_dir = tempfile.mkdtemp(dir=self.TEST_ROOT)
2018
candidate_dir = osutils.mkdtemp(dir=self.TEST_ROOT)
1998
2019
# now create test and home directories within this dir
1999
2020
self.test_base_dir = candidate_dir
2000
2021
self.test_home_dir = self.test_base_dir + '/home'
2361
2382
'bzrlib.tests.test_api',
2362
2383
'bzrlib.tests.test_atomicfile',
2363
2384
'bzrlib.tests.test_bad_files',
2385
'bzrlib.tests.test_bisect_multi',
2364
2386
'bzrlib.tests.test_branch',
2365
2387
'bzrlib.tests.test_branchbuilder',
2366
2388
'bzrlib.tests.test_bugtracker',
2426
2448
'bzrlib.tests.test_permissions',
2427
2449
'bzrlib.tests.test_plugins',
2428
2450
'bzrlib.tests.test_progress',
2451
'bzrlib.tests.test_reconfigure',
2429
2452
'bzrlib.tests.test_reconcile',
2430
2453
'bzrlib.tests.test_registry',
2431
2454
'bzrlib.tests.test_remote',
2583
def multiply_scenarios(scenarios_left, scenarios_right):
2584
"""Multiply two sets of scenarios.
2586
:returns: the cartesian product of the two sets of scenarios, that is
2587
a scenario for every possible combination of a left scenario and a
2591
('%s,%s' % (left_name, right_name),
2592
dict(left_dict.items() + right_dict.items()))
2593
for left_name, left_dict in scenarios_left
2594
for right_name, right_dict in scenarios_right]
2560
2598
def adapt_modules(mods_list, adapter, loader, suite):
2561
2599
"""Adapt the modules in mods_list using adapter and add to suite."""
2562
2600
for test in iter_suite_tests(loader.loadTestsFromModuleNames(mods_list)):
2579
2617
osutils.rmtree(dirname)
2580
2618
except OSError, e:
2581
2619
if sys.platform == 'win32' and e.errno == errno.EACCES:
2582
print >>sys.stderr, ('Permission denied: '
2620
sys.stderr.write(('Permission denied: '
2583
2621
'unable to remove testing dir '
2584
'%s' % os.path.basename(dirname))
2622
'%s\n' % os.path.basename(dirname)))
2625
2663
SymlinkFeature = _SymlinkFeature()
2666
class _OsFifoFeature(Feature):
2669
return getattr(os, 'mkfifo', None)
2671
def feature_name(self):
2672
return 'filesystem fifos'
2674
OsFifoFeature = _OsFifoFeature()
2628
2677
class TestScenarioApplier(object):
2629
2678
"""A tool to apply scenarios to tests."""
2671
2720
return uni_val, str_val
2672
2721
return None, None
2724
def probe_bad_non_ascii(encoding):
2725
"""Try to find [bad] character with code [128..255]
2726
that cannot be decoded to unicode in some encoding.
2727
Return None if all non-ascii characters is valid
2730
for i in xrange(128, 256):
2733
char.decode(encoding)
2734
except UnicodeDecodeError:
2739
class _FTPServerFeature(Feature):
2740
"""Some tests want an FTP Server, check if one is available.
2742
Right now, the only way this is available is if 'medusa' is installed.
2743
http://www.amk.ca/python/code/medusa.html
2748
import bzrlib.tests.ftp_server
2753
def feature_name(self):
2756
FTPServerFeature = _FTPServerFeature()