227
237
'%d non-main threads were left active in the end.\n'
228
238
% (TestCase._active_threads - 1))
230
def _extractBenchmarkTime(self, testCase):
240
def getDescription(self, test):
243
def _extractBenchmarkTime(self, testCase, details=None):
231
244
"""Add a benchmark time for the current test case."""
245
if details and 'benchtime' in details:
246
return float(''.join(details['benchtime'].iter_bytes()))
232
247
return getattr(testCase, "_benchtime", None)
234
249
def _elapsedTestTimeString(self):
297
312
Called from the TestCase run() method when the test
298
313
fails with an unexpected error.
300
self._testConcluded(test)
301
if isinstance(err[1], TestNotApplicable):
302
return self._addNotApplicable(test, err)
303
elif isinstance(err[1], UnavailableFeature):
304
return self.addNotSupported(test, err[1].args[0])
307
unittest.TestResult.addError(self, test, err)
308
self.error_count += 1
309
self.report_error(test, err)
312
self._cleanupLogFile(test)
316
unittest.TestResult.addError(self, test, err)
317
self.error_count += 1
318
self.report_error(test, err)
321
self._cleanupLogFile(test)
314
323
def addFailure(self, test, err):
315
324
"""Tell result that test failed.
317
326
Called from the TestCase run() method when the test
318
327
fails because e.g. an assert() method failed.
320
self._testConcluded(test)
321
if isinstance(err[1], KnownFailure):
322
return self._addKnownFailure(test, err)
325
unittest.TestResult.addFailure(self, test, err)
326
self.failure_count += 1
327
self.report_failure(test, err)
330
self._cleanupLogFile(test)
330
unittest.TestResult.addFailure(self, test, err)
331
self.failure_count += 1
332
self.report_failure(test, err)
335
self._cleanupLogFile(test)
332
def addSuccess(self, test):
337
def addSuccess(self, test, details=None):
333
338
"""Tell result that test completed successfully.
335
340
Called from the TestCase run()
337
self._testConcluded(test)
338
342
if self._bench_history is not None:
339
benchmark_time = self._extractBenchmarkTime(test)
343
benchmark_time = self._extractBenchmarkTime(test, details)
340
344
if benchmark_time is not None:
341
345
self._bench_history.write("%s %s\n" % (
342
346
self._formatTime(benchmark_time),
346
350
unittest.TestResult.addSuccess(self, test)
347
351
test._log_contents = ''
349
def _testConcluded(self, test):
350
"""Common code when a test has finished.
352
Called regardless of whether it succeded, failed, etc.
356
def _addKnownFailure(self, test, err):
353
def addExpectedFailure(self, test, err):
357
354
self.known_failure_count += 1
358
355
self.report_known_failure(test, err)
361
358
"""The test will not be run because of a missing feature.
363
360
# this can be called in two different ways: it may be that the
364
# test started running, and then raised (through addError)
361
# test started running, and then raised (through requireFeature)
365
362
# UnavailableFeature. Alternatively this method can be called
366
# while probing for features before running the tests; in that
367
# case we will see startTest and stopTest, but the test will never
363
# while probing for features before running the test code proper; in
364
# that case we will see startTest and stopTest, but the test will
365
# never actually run.
369
366
self.unsupported.setdefault(str(feature), 0)
370
367
self.unsupported[str(feature)] += 1
371
368
self.report_unsupported(test, feature)
375
372
self.skip_count += 1
376
373
self.report_skip(test, reason)
378
def _addNotApplicable(self, test, skip_excinfo):
379
if isinstance(skip_excinfo[1], TestNotApplicable):
380
self.not_applicable_count += 1
381
self.report_not_applicable(test, skip_excinfo)
384
except KeyboardInterrupt:
387
self.addError(test, test.exc_info())
389
# seems best to treat this as success from point-of-view of unittest
390
# -- it actually does nothing so it barely matters :)
391
unittest.TestResult.addSuccess(self, test)
392
test._log_contents = ''
394
def printErrorList(self, flavour, errors):
395
for test, err in errors:
396
self.stream.writeln(self.separator1)
397
self.stream.write("%s: " % flavour)
398
self.stream.writeln(self.getDescription(test))
399
if getattr(test, '_get_log', None) is not None:
400
log_contents = test._get_log()
402
self.stream.write('\n')
404
('vvvv[log from %s]' % test.id()).ljust(78,'-'))
405
self.stream.write('\n')
406
self.stream.write(log_contents)
407
self.stream.write('\n')
409
('^^^^[log from %s]' % test.id()).ljust(78,'-'))
410
self.stream.write('\n')
411
self.stream.writeln(self.separator2)
412
self.stream.writeln("%s" % err)
375
def addNotApplicable(self, test, reason):
376
self.not_applicable_count += 1
377
self.report_not_applicable(test, reason)
414
379
def _post_mortem(self):
415
380
"""Start a PDB post mortem session."""
562
525
def report_test_start(self, test):
564
527
name = self._shortened_test_description(test)
565
# width needs space for 6 char status, plus 1 for slash, plus an
566
# 11-char time string, plus a trailing blank
567
# when NUMBERED_DIRS: plus 5 chars on test number, plus 1 char on space
568
self.stream.write(self._ellipsize_to_right(name,
569
osutils.terminal_width()-18))
528
width = osutils.terminal_width()
529
if width is not None:
530
# width needs space for 6 char status, plus 1 for slash, plus an
531
# 11-char time string, plus a trailing blank
532
# when NUMBERED_DIRS: plus 5 chars on test number, plus 1 char on
534
self.stream.write(self._ellipsize_to_right(name, width-18))
536
self.stream.write(name)
570
537
self.stream.flush()
572
539
def _error_summary(self, err):
601
568
self.stream.writeln(' SKIP %s\n%s'
602
569
% (self._testTimeString(test), reason))
604
def report_not_applicable(self, test, skip_excinfo):
605
self.stream.writeln(' N/A %s\n%s'
606
% (self._testTimeString(test),
607
self._error_summary(skip_excinfo)))
571
def report_not_applicable(self, test, reason):
572
self.stream.writeln(' N/A %s\n %s'
573
% (self._testTimeString(test), reason))
609
575
def report_unsupported(self, test, feature):
610
576
"""test cannot be run because feature is missing."""
630
596
applied left to right - the first element in the list is the
631
597
innermost decorator.
599
# stream may know claim to know to write unicode strings, but in older
600
# pythons this goes sufficiently wrong that it is a bad idea. (
601
# specifically a built in file with encoding 'UTF-8' will still try
602
# to encode using ascii.
603
new_encoding = osutils.get_terminal_encoding()
604
codec = codecs.lookup(new_encoding)
605
if type(codec) is tuple:
609
encode = codec.encode
610
stream = osutils.UnicodeOrBytesToBytesWriter(encode, stream)
611
stream.encoding = new_encoding
633
612
self.stream = unittest._WritelnDecorator(stream)
634
613
self.descriptions = descriptions
635
614
self.verbosity = verbosity
702
class KnownFailure(AssertionError):
703
"""Indicates that a test failed in a precisely expected manner.
705
Such failures dont block the whole test suite from passing because they are
706
indicators of partially completed code or of future work. We have an
707
explicit error for them so that we can ensure that they are always visible:
708
KnownFailures are always shown in the output of bzr selftest.
672
# traceback._some_str fails to format exceptions that have the default
673
# __str__ which does an implicit ascii conversion. However, repr() on those
674
# objects works, for all that its not quite what the doctor may have ordered.
675
def _clever_some_str(value):
680
return repr(value).replace('\\n', '\n')
682
return '<unprintable %s object>' % type(value).__name__
684
traceback._some_str = _clever_some_str
687
# deprecated - use self.knownFailure(), or self.expectFailure.
688
KnownFailure = testtools.testcase._ExpectedFailure
712
691
class UnavailableFeature(Exception):
713
692
"""A feature required for this test was not available.
694
This can be considered a specialised form of SkippedTest.
715
696
The feature should be used to construct the exception.
811
792
_leaking_threads_tests = 0
812
793
_first_thread_leaker_id = None
813
794
_log_file_name = None
815
_keep_log_file = False
816
795
# record lsprof data when performing benchmark calls.
817
796
_gather_lsprof_in_benchmarks = False
818
attrs_to_keep = ('id', '_testMethodName', '_testMethodDoc',
819
'_log_contents', '_log_file_name', '_benchtime',
820
'_TestCase__testMethodName', '_TestCase__testMethodDoc',)
822
798
def __init__(self, methodName='testMethod'):
823
799
super(TestCase, self).__init__(methodName)
824
800
self._cleanups = []
825
self._bzr_test_setUp_run = False
826
self._bzr_test_tearDown_run = False
827
801
self._directory_isolation = True
802
self.exception_handlers.insert(0,
803
(UnavailableFeature, self._do_unsupported_or_skip))
804
self.exception_handlers.insert(0,
805
(TestNotApplicable, self._do_not_applicable))
830
unittest.TestCase.setUp(self)
831
self._bzr_test_setUp_run = True
808
super(TestCase, self).setUp()
809
for feature in getattr(self, '_test_needs_features', []):
810
self.requireFeature(feature)
811
self._log_contents = None
812
self.addDetail("log", content.Content(content.ContentType("text",
813
"plain", {"charset": "utf8"}),
814
lambda:[self._get_log(keep_log_file=True)]))
832
815
self._cleanEnvironment()
833
816
self._silenceUI()
834
817
self._startLogFile()
1143
1126
:raises AssertionError: If the expected and actual stat values differ
1144
1127
other than by atime.
1146
self.assertEqual(expected.st_size, actual.st_size)
1147
self.assertEqual(expected.st_mtime, actual.st_mtime)
1148
self.assertEqual(expected.st_ctime, actual.st_ctime)
1149
self.assertEqual(expected.st_dev, actual.st_dev)
1150
self.assertEqual(expected.st_ino, actual.st_ino)
1151
self.assertEqual(expected.st_mode, actual.st_mode)
1129
self.assertEqual(expected.st_size, actual.st_size,
1130
'st_size did not match')
1131
self.assertEqual(expected.st_mtime, actual.st_mtime,
1132
'st_mtime did not match')
1133
self.assertEqual(expected.st_ctime, actual.st_ctime,
1134
'st_ctime did not match')
1135
if sys.platform != 'win32':
1136
# On Win32 both 'dev' and 'ino' cannot be trusted. In python2.4 it
1137
# is 'dev' that varies, in python 2.5 (6?) it is st_ino that is
1138
# odd. Regardless we shouldn't actually try to assert anything
1139
# about their values
1140
self.assertEqual(expected.st_dev, actual.st_dev,
1141
'st_dev did not match')
1142
self.assertEqual(expected.st_ino, actual.st_ino,
1143
'st_ino did not match')
1144
self.assertEqual(expected.st_mode, actual.st_mode,
1145
'st_mode did not match')
1153
1147
def assertLength(self, length, obj_with_len):
1154
1148
"""Assert that obj_with_len is of length length."""
1302
1296
m += ": " + msg
1305
def expectFailure(self, reason, assertion, *args, **kwargs):
1306
"""Invoke a test, expecting it to fail for the given reason.
1308
This is for assertions that ought to succeed, but currently fail.
1309
(The failure is *expected* but not *wanted*.) Please be very precise
1310
about the failure you're expecting. If a new bug is introduced,
1311
AssertionError should be raised, not KnownFailure.
1313
Frequently, expectFailure should be followed by an opposite assertion.
1316
Intended to be used with a callable that raises AssertionError as the
1317
'assertion' parameter. args and kwargs are passed to the 'assertion'.
1319
Raises KnownFailure if the test fails. Raises AssertionError if the
1324
self.expectFailure('Math is broken', self.assertNotEqual, 54,
1326
self.assertEqual(42, dynamic_val)
1328
This means that a dynamic_val of 54 will cause the test to raise
1329
a KnownFailure. Once math is fixed and the expectFailure is removed,
1330
only a dynamic_val of 42 will allow the test to pass. Anything other
1331
than 54 or 42 will cause an AssertionError.
1334
assertion(*args, **kwargs)
1335
except AssertionError:
1336
raise KnownFailure(reason)
1338
self.fail('Unexpected success. Should have failed: %s' % reason)
1340
1299
def assertFileEqual(self, content, path):
1341
1300
"""Fail if path does not contain 'content'."""
1342
1301
self.failUnlessExists(path)
1493
1452
Close the file and delete it, unless setKeepLogfile was called.
1495
if self._log_file is None:
1454
if bzrlib.trace._trace_file:
1455
# flush the log file, to get all content
1456
bzrlib.trace._trace_file.flush()
1497
1457
bzrlib.trace.pop_log_file(self._log_memento)
1498
self._log_file.close()
1499
self._log_file = None
1500
if not self._keep_log_file:
1501
os.remove(self._log_file_name)
1502
self._log_file_name = None
1504
def setKeepLogfile(self):
1505
"""Make the logfile not be deleted when _finishLogFile is called."""
1506
self._keep_log_file = True
1458
# Cache the log result and delete the file on disk
1459
self._get_log(False)
1508
1461
def thisFailsStrictLockCheck(self):
1509
1462
"""It is known that this test would fail with -Dstrict_locks.
1594
1549
def _do_skip(self, result, reason):
1595
1550
addSkip = getattr(result, 'addSkip', None)
1596
1551
if not callable(addSkip):
1597
result.addError(self, sys.exc_info())
1552
result.addSuccess(result)
1599
1554
addSkip(self, reason)
1601
def run(self, result=None):
1602
if result is None: result = self.defaultTestResult()
1603
for feature in getattr(self, '_test_needs_features', []):
1604
if not feature.available():
1605
result.startTest(self)
1606
if getattr(result, 'addNotSupported', None):
1607
result.addNotSupported(self, feature)
1609
result.addSuccess(self)
1610
result.stopTest(self)
1614
result.startTest(self)
1615
absent_attr = object()
1617
method_name = getattr(self, '_testMethodName', absent_attr)
1618
if method_name is absent_attr:
1620
method_name = getattr(self, '_TestCase__testMethodName')
1621
testMethod = getattr(self, method_name)
1625
if not self._bzr_test_setUp_run:
1627
"test setUp did not invoke "
1628
"bzrlib.tests.TestCase's setUp")
1629
except KeyboardInterrupt:
1632
except TestSkipped, e:
1633
self._do_skip(result, e.args[0])
1637
result.addError(self, sys.exc_info())
1645
except self.failureException:
1646
result.addFailure(self, sys.exc_info())
1647
except TestSkipped, e:
1649
reason = "No reason given."
1652
self._do_skip(result, reason)
1653
except KeyboardInterrupt:
1657
result.addError(self, sys.exc_info())
1661
if not self._bzr_test_tearDown_run:
1663
"test tearDown did not invoke "
1664
"bzrlib.tests.TestCase's tearDown")
1665
except KeyboardInterrupt:
1669
result.addError(self, sys.exc_info())
1672
if ok: result.addSuccess(self)
1674
result.stopTest(self)
1676
except TestNotApplicable:
1677
# Not moved from the result [yet].
1680
except KeyboardInterrupt:
1685
for attr_name in self.attrs_to_keep:
1686
if attr_name in self.__dict__:
1687
saved_attrs[attr_name] = self.__dict__[attr_name]
1688
self.__dict__ = saved_attrs
1692
self._log_contents = ''
1693
self._bzr_test_tearDown_run = True
1694
unittest.TestCase.tearDown(self)
1557
def _do_known_failure(self, result, e):
1558
err = sys.exc_info()
1559
addExpectedFailure = getattr(result, 'addExpectedFailure', None)
1560
if addExpectedFailure is not None:
1561
addExpectedFailure(self, err)
1563
result.addSuccess(self)
1566
def _do_not_applicable(self, result, e):
1568
reason = 'No reason given'
1571
addNotApplicable = getattr(result, 'addNotApplicable', None)
1572
if addNotApplicable is not None:
1573
result.addNotApplicable(self, reason)
1575
self._do_skip(result, reason)
1578
def _do_unsupported_or_skip(self, result, e):
1580
addNotSupported = getattr(result, 'addNotSupported', None)
1581
if addNotSupported is not None:
1582
result.addNotSupported(self, reason)
1584
self._do_skip(result, reason)
1696
1586
def time(self, callable, *args, **kwargs):
1697
1587
"""Run callable and accrue the time it takes to the benchmark time.
1716
1608
self._benchtime += time.time() - start
1718
def _runCleanups(self):
1719
"""Run registered cleanup functions.
1721
This should only be called from TestCase.tearDown.
1723
# TODO: Perhaps this should keep running cleanups even if
1724
# one of them fails?
1726
# Actually pop the cleanups from the list so tearDown running
1727
# twice is safe (this happens for skipped tests).
1728
while self._cleanups:
1729
cleanup, args, kwargs = self._cleanups.pop()
1730
cleanup(*args, **kwargs)
1732
1610
def log(self, *args):
1735
1613
def _get_log(self, keep_log_file=False):
1736
"""Get the log from bzrlib.trace calls from this test.
1614
"""Internal helper to get the log from bzrlib.trace for this test.
1616
Please use self.getDetails, or self.get_log to access this in test case
1738
1619
:param keep_log_file: When True, if the log is still a file on disk
1739
1620
leave it as a file on disk. When False, if the log is still a file
1741
1622
self._log_contents.
1742
1623
:return: A string containing the log.
1744
# flush the log file, to get all content
1625
if self._log_contents is not None:
1627
self._log_contents.decode('utf8')
1628
except UnicodeDecodeError:
1629
unicodestr = self._log_contents.decode('utf8', 'replace')
1630
self._log_contents = unicodestr.encode('utf8')
1631
return self._log_contents
1745
1632
import bzrlib.trace
1746
1633
if bzrlib.trace._trace_file:
1634
# flush the log file, to get all content
1747
1635
bzrlib.trace._trace_file.flush()
1748
if self._log_contents:
1749
# XXX: this can hardly contain the content flushed above --vila
1751
return self._log_contents
1752
1636
if self._log_file_name is not None:
1753
1637
logfile = open(self._log_file_name)
1755
1639
log_contents = logfile.read()
1757
1641
logfile.close()
1643
log_contents.decode('utf8')
1644
except UnicodeDecodeError:
1645
unicodestr = log_contents.decode('utf8', 'replace')
1646
log_contents = unicodestr.encode('utf8')
1758
1647
if not keep_log_file:
1648
self._log_file.close()
1649
self._log_file = None
1650
# Permit multiple calls to get_log until we clean it up in
1759
1652
self._log_contents = log_contents
1761
1654
os.remove(self._log_file_name)
1812
1716
os.chdir(working_dir)
1815
result = self.apply_redirected(ui.ui_factory.stdin,
1817
bzrlib.commands.run_bzr_catch_user_errors,
1720
result = self.apply_redirected(ui.ui_factory.stdin,
1722
bzrlib.commands.run_bzr_catch_user_errors,
1724
except KeyboardInterrupt:
1725
# Reraise KeyboardInterrupt with contents of redirected stdout
1726
# and stderr as arguments, for tests which are interested in
1727
# stdout and stderr and are expecting the exception.
1728
out = stdout.getvalue()
1729
err = stderr.getvalue()
1731
self.log('output:\n%r', out)
1733
self.log('errors:\n%r', err)
1734
raise KeyboardInterrupt(out, err)
1820
1736
logger.removeHandler(handler)
1821
1737
ui.ui_factory = old_ui_factory
3312
3228
if not os.path.isfile(bzr_path):
3313
3229
# We are probably installed. Assume sys.argv is the right file
3314
3230
bzr_path = sys.argv[0]
3231
bzr_path = [bzr_path]
3232
if sys.platform == "win32":
3233
# if we're on windows, we can't execute the bzr script directly
3234
bzr_path = [sys.executable] + bzr_path
3315
3235
fd, test_list_file_name = tempfile.mkstemp()
3316
3236
test_list_file = os.fdopen(fd, 'wb', 1)
3317
3237
for test in process_tests:
3318
3238
test_list_file.write(test.id() + '\n')
3319
3239
test_list_file.close()
3321
argv = [bzr_path, 'selftest', '--load-list', test_list_file_name,
3241
argv = bzr_path + ['selftest', '--load-list', test_list_file_name,
3323
3243
if '--no-plugins' in sys.argv:
3324
3244
argv.append('--no-plugins')
3364
3284
def addFailure(self, test, err):
3365
3285
self.result.addFailure(test, err)
3368
class BZRTransformingResult(ForwardingResult):
3370
def addError(self, test, err):
3371
feature = self._error_looks_like('UnavailableFeature: ', err)
3372
if feature is not None:
3373
self.result.addNotSupported(test, feature)
3375
self.result.addError(test, err)
3377
def addFailure(self, test, err):
3378
known = self._error_looks_like('KnownFailure: ', err)
3379
if known is not None:
3380
self.result._addKnownFailure(test, [KnownFailure,
3381
KnownFailure(known), None])
3383
self.result.addFailure(test, err)
3385
def _error_looks_like(self, prefix, err):
3386
"""Deserialize exception and returns the stringify value."""
3390
if isinstance(exc, subunit.RemoteException):
3391
# stringify the exception gives access to the remote traceback
3392
# We search the last line for 'prefix'
3393
lines = str(exc).split('\n')
3394
while lines and not lines[-1]:
3397
if lines[-1].startswith(prefix):
3398
value = lines[-1][len(prefix):]
3286
ForwardingResult = testtools.ExtendedToOriginalDecorator
3402
3289
class ProfileResult(ForwardingResult):
4075
3965
return new_test
4078
def _rmtree_temp_dir(dirname):
3968
def permute_tests_for_extension(standard_tests, loader, py_module_name,
3970
"""Helper for permutating tests against an extension module.
3972
This is meant to be used inside a modules 'load_tests()' function. It will
3973
create 2 scenarios, and cause all tests in the 'standard_tests' to be run
3974
against both implementations. Setting 'test.module' to the appropriate
3975
module. See bzrlib.tests.test__chk_map.load_tests as an example.
3977
:param standard_tests: A test suite to permute
3978
:param loader: A TestLoader
3979
:param py_module_name: The python path to a python module that can always
3980
be loaded, and will be considered the 'python' implementation. (eg
3981
'bzrlib._chk_map_py')
3982
:param ext_module_name: The python path to an extension module. If the
3983
module cannot be loaded, a single test will be added, which notes that
3984
the module is not available. If it can be loaded, all standard_tests
3985
will be run against that module.
3986
:return: (suite, feature) suite is a test-suite that has all the permuted
3987
tests. feature is the Feature object that can be used to determine if
3988
the module is available.
3991
py_module = __import__(py_module_name, {}, {}, ['NO_SUCH_ATTRIB'])
3993
('python', {'module': py_module}),
3995
suite = loader.suiteClass()
3996
feature = ModuleAvailableFeature(ext_module_name)
3997
if feature.available():
3998
scenarios.append(('C', {'module': feature.module}))
4000
# the compiled module isn't available, so we add a failing test
4001
class FailWithoutFeature(TestCase):
4002
def test_fail(self):
4003
self.requireFeature(feature)
4004
suite.addTest(loader.loadTestsFromTestCase(FailWithoutFeature))
4005
result = multiply_tests(standard_tests, scenarios, suite)
4006
return result, feature
4009
def _rmtree_temp_dir(dirname, test_id=None):
4079
4010
# If LANG=C we probably have created some bogus paths
4080
4011
# which rmtree(unicode) will fail to delete
4081
4012
# so make sure we are using rmtree(str) to delete everything
4182
4116
UnicodeFilenameFeature = _UnicodeFilenameFeature()
4119
class _CompatabilityThunkFeature(Feature):
4120
"""This feature is just a thunk to another feature.
4122
It issues a deprecation warning if it is accessed, to let you know that you
4123
should really use a different feature.
4126
def __init__(self, module, name, this_name, dep_version):
4127
super(_CompatabilityThunkFeature, self).__init__()
4128
self._module = module
4130
self._this_name = this_name
4131
self._dep_version = dep_version
4132
self._feature = None
4135
if self._feature is None:
4136
msg = (self._dep_version % self._this_name) + (
4137
' Use %s.%s instead.' % (self._module, self._name))
4138
symbol_versioning.warn(msg, DeprecationWarning)
4139
mod = __import__(self._module, {}, {}, [self._name])
4140
self._feature = getattr(mod, self._name)
4144
return self._feature._probe()
4147
class ModuleAvailableFeature(Feature):
4148
"""This is a feature than describes a module we want to be available.
4150
Declare the name of the module in __init__(), and then after probing, the
4151
module will be available as 'self.module'.
4153
:ivar module: The module if it is available, else None.
4156
def __init__(self, module_name):
4157
super(ModuleAvailableFeature, self).__init__()
4158
self.module_name = module_name
4162
self._module = __import__(self.module_name, {}, {}, [''])
4169
if self.available(): # Make sure the probe has been done
4173
def feature_name(self):
4174
return self.module_name
4177
# This is kept here for compatibility, it is recommended to use
4178
# 'bzrlib.tests.feature.paramiko' instead
4179
ParamikoFeature = _CompatabilityThunkFeature('bzrlib.tests.features',
4180
'paramiko', 'bzrlib.tests.ParamikoFeature', deprecated_in((2,1,0)))
4185
4183
def probe_unicode_in_user_encoding():
4186
4184
"""Try to encode several unicode strings to use in unicode-aware tests.
4187
4185
Return first successfull match.
4361
4344
CaseInsensitiveFilesystemFeature = _CaseInsensitiveFilesystemFeature()
4364
class _SubUnitFeature(Feature):
4365
"""Check if subunit is available."""
4347
class _CaseSensitiveFilesystemFeature(Feature):
4367
4349
def _probe(self):
4350
if CaseInsCasePresFilenameFeature.available():
4352
elif CaseInsensitiveFilesystemFeature.available():
4374
4357
def feature_name(self):
4377
SubUnitFeature = _SubUnitFeature()
4358
return 'case-sensitive filesystem'
4360
# new coding style is for feature instances to be lowercase
4361
case_sensitive_filesystem_feature = _CaseSensitiveFilesystemFeature()
4364
# Kept for compatibility, use bzrlib.tests.features.subunit instead
4365
SubUnitFeature = _CompatabilityThunkFeature('bzrlib.tests.features', 'subunit',
4366
'bzrlib.tests.SubUnitFeature', deprecated_in((2,1,0)))
4378
4367
# Only define SubUnitBzrRunner if subunit is available.
4380
4369
from subunit import TestProtocolClient
4382
from subunit.test_results import AutoTimingTestResultDecorator
4384
AutoTimingTestResultDecorator = lambda x:x
4370
from subunit.test_results import AutoTimingTestResultDecorator
4385
4371
class SubUnitBzrRunner(TextTestRunner):
4386
4372
def run(self, test):
4387
4373
result = AutoTimingTestResultDecorator(