750
763
self.check_timing(ShortDelayTestCase('test_short_delay'),
753
def _patch_get_bzr_source_tree(self):
754
# Reading from the actual source tree breaks isolation, but we don't
755
# want to assume that thats *all* that would happen.
756
self.overrideAttr(bzrlib.version, '_get_bzr_source_tree', lambda: None)
758
def test_assigned_benchmark_file_stores_date(self):
759
self._patch_get_bzr_source_tree()
761
result = bzrlib.tests.TextTestResult(self._log_file,
766
output_string = output.getvalue()
767
# if you are wondering about the regexp please read the comment in
768
# test_bench_history (bzrlib.tests.test_selftest.TestRunner)
769
# XXX: what comment? -- Andrew Bennetts
770
self.assertContainsRe(output_string, "--date [0-9.]+")
772
def test_benchhistory_records_test_times(self):
773
self._patch_get_bzr_source_tree()
774
result_stream = StringIO()
775
result = bzrlib.tests.TextTestResult(
779
bench_history=result_stream
782
# we want profile a call and check that its test duration is recorded
783
# make a new test instance that when run will generate a benchmark
784
example_test_case = TestTestResult("_time_hello_world_encoding")
785
# execute the test, which should succeed and record times
786
example_test_case.run(result)
787
lines = result_stream.getvalue().splitlines()
788
self.assertEqual(2, len(lines))
789
self.assertContainsRe(lines[1],
790
" *[0-9]+ms bzrlib.tests.test_selftest.TestTestResult"
791
"._time_hello_world_encoding")
793
766
def _time_hello_world_encoding(self):
794
767
"""Profile two sleep calls
835
808
self.assertContainsRe(output,
836
809
r"LSProf output for <type 'unicode'>\(\('world',\), {'errors': 'replace'}\)\n")
811
def test_uses_time_from_testtools(self):
812
"""Test case timings in verbose results should use testtools times"""
814
class TimeAddedVerboseTestResult(tests.VerboseTestResult):
815
def startTest(self, test):
816
self.time(datetime.datetime.utcfromtimestamp(1.145))
817
super(TimeAddedVerboseTestResult, self).startTest(test)
818
def addSuccess(self, test):
819
self.time(datetime.datetime.utcfromtimestamp(51.147))
820
super(TimeAddedVerboseTestResult, self).addSuccess(test)
821
def report_tests_starting(self): pass
823
self.get_passing_test().run(TimeAddedVerboseTestResult(sio, 0, 2))
824
self.assertEndsWith(sio.getvalue(), "OK 50002ms\n")
838
826
def test_known_failure(self):
839
827
"""A KnownFailure being raised should trigger several result actions."""
840
828
class InstrumentedTestResult(tests.ExtendedTestResult):
841
829
def stopTestRun(self): pass
842
def startTests(self): pass
843
def report_test_start(self, test): pass
830
def report_tests_starting(self): pass
844
831
def report_known_failure(self, test, err=None, details=None):
845
832
self._call = test, 'known failure'
846
833
result = InstrumentedTestResult(None, None, None, None)
1193
def _patch_get_bzr_source_tree(self):
1194
# Reading from the actual source tree breaks isolation, but we don't
1195
# want to assume that thats *all* that would happen.
1196
self._get_source_tree_calls = []
1198
self._get_source_tree_calls.append("called")
1200
self.overrideAttr(bzrlib.version, '_get_bzr_source_tree', new_get)
1202
def test_bench_history(self):
1203
# tests that the running the benchmark passes bench_history into
1204
# the test result object. We can tell that happens if
1205
# _get_bzr_source_tree is called.
1206
self._patch_get_bzr_source_tree()
1207
test = TestRunner('dummy_test')
1209
runner = tests.TextTestRunner(stream=self._log_file,
1210
bench_history=output)
1211
result = self.run_test_runner(runner, test)
1212
output_string = output.getvalue()
1213
self.assertContainsRe(output_string, "--date [0-9.]+")
1214
self.assertLength(1, self._get_source_tree_calls)
1199
def test_verbose_test_count(self):
1200
"""A verbose test run reports the right test count at the start"""
1201
suite = TestUtil.TestSuite([
1202
unittest.FunctionTestCase(lambda:None),
1203
unittest.FunctionTestCase(lambda:None)])
1204
self.assertEqual(suite.countTestCases(), 2)
1206
runner = tests.TextTestRunner(stream=stream, verbosity=2)
1207
# Need to use the CountingDecorator as that's what sets num_tests
1208
result = self.run_test_runner(runner, tests.CountingDecorator(suite))
1209
self.assertStartsWith(stream.getvalue(), "running 2 tests")
1216
1211
def test_startTestRun(self):
1217
1212
"""run should call result.startTestRun()"""
1219
class LoggingDecorator(tests.ForwardingResult):
1214
class LoggingDecorator(ExtendedToOriginalDecorator):
1220
1215
def startTestRun(self):
1221
tests.ForwardingResult.startTestRun(self)
1216
ExtendedToOriginalDecorator.startTestRun(self)
1222
1217
calls.append('startTestRun')
1223
1218
test = unittest.FunctionTestCase(lambda:None)
1224
1219
stream = StringIO()
1655
1667
self.assertEqual('original', obj.test_attr)
1670
class _MissingFeature(features.Feature):
1673
missing_feature = _MissingFeature()
1676
def _get_test(name):
1677
"""Get an instance of a specific example test.
1679
We protect this in a function so that they don't auto-run in the test
1683
class ExampleTests(tests.TestCase):
1685
def test_fail(self):
1686
mutter('this was a failing test')
1687
self.fail('this test will fail')
1689
def test_error(self):
1690
mutter('this test errored')
1691
raise RuntimeError('gotcha')
1693
def test_missing_feature(self):
1694
mutter('missing the feature')
1695
self.requireFeature(missing_feature)
1697
def test_skip(self):
1698
mutter('this test will be skipped')
1699
raise tests.TestSkipped('reason')
1701
def test_success(self):
1702
mutter('this test succeeds')
1704
def test_xfail(self):
1705
mutter('test with expected failure')
1706
self.knownFailure('this_fails')
1708
def test_unexpected_success(self):
1709
mutter('test with unexpected success')
1710
self.expectFailure('should_fail', lambda: None)
1712
return ExampleTests(name)
1715
class TestTestCaseLogDetails(tests.TestCase):
1717
def _run_test(self, test_name):
1718
test = _get_test(test_name)
1719
result = testtools.TestResult()
1723
def test_fail_has_log(self):
1724
result = self._run_test('test_fail')
1725
self.assertEqual(1, len(result.failures))
1726
result_content = result.failures[0][1]
1727
self.assertContainsRe(result_content, 'Text attachment: log')
1728
self.assertContainsRe(result_content, 'this was a failing test')
1730
def test_error_has_log(self):
1731
result = self._run_test('test_error')
1732
self.assertEqual(1, len(result.errors))
1733
result_content = result.errors[0][1]
1734
self.assertContainsRe(result_content, 'Text attachment: log')
1735
self.assertContainsRe(result_content, 'this test errored')
1737
def test_skip_has_no_log(self):
1738
result = self._run_test('test_skip')
1739
self.assertEqual(['reason'], result.skip_reasons.keys())
1740
skips = result.skip_reasons['reason']
1741
self.assertEqual(1, len(skips))
1743
self.assertFalse('log' in test.getDetails())
1745
def test_missing_feature_has_no_log(self):
1746
# testtools doesn't know about addNotSupported, so it just gets
1747
# considered as a skip
1748
result = self._run_test('test_missing_feature')
1749
self.assertEqual([missing_feature], result.skip_reasons.keys())
1750
skips = result.skip_reasons[missing_feature]
1751
self.assertEqual(1, len(skips))
1753
self.assertFalse('log' in test.getDetails())
1755
def test_xfail_has_no_log(self):
1756
result = self._run_test('test_xfail')
1757
self.assertEqual(1, len(result.expectedFailures))
1758
result_content = result.expectedFailures[0][1]
1759
self.assertNotContainsRe(result_content, 'Text attachment: log')
1760
self.assertNotContainsRe(result_content, 'test with expected failure')
1762
def test_unexpected_success_has_log(self):
1763
result = self._run_test('test_unexpected_success')
1764
self.assertEqual(1, len(result.unexpectedSuccesses))
1765
# Inconsistency, unexpectedSuccesses is a list of tests,
1766
# expectedFailures is a list of reasons?
1767
test = result.unexpectedSuccesses[0]
1768
details = test.getDetails()
1769
self.assertTrue('log' in details)
1772
class TestTestCloning(tests.TestCase):
1773
"""Tests that test cloning of TestCases (as used by multiply_tests)."""
1775
def test_cloned_testcase_does_not_share_details(self):
1776
"""A TestCase cloned with clone_test does not share mutable attributes
1777
such as details or cleanups.
1779
class Test(tests.TestCase):
1781
self.addDetail('foo', Content('text/plain', lambda: 'foo'))
1782
orig_test = Test('test_foo')
1783
cloned_test = tests.clone_test(orig_test, orig_test.id() + '(cloned)')
1784
orig_test.run(unittest.TestResult())
1785
self.assertEqual('foo', orig_test.getDetails()['foo'].iter_bytes())
1786
self.assertEqual(None, cloned_test.getDetails().get('foo'))
1788
def test_double_apply_scenario_preserves_first_scenario(self):
1789
"""Applying two levels of scenarios to a test preserves the attributes
1790
added by both scenarios.
1792
class Test(tests.TestCase):
1795
test = Test('test_foo')
1796
scenarios_x = [('x=1', {'x': 1}), ('x=2', {'x': 2})]
1797
scenarios_y = [('y=1', {'y': 1}), ('y=2', {'y': 2})]
1798
suite = tests.multiply_tests(test, scenarios_x, unittest.TestSuite())
1799
suite = tests.multiply_tests(suite, scenarios_y, unittest.TestSuite())
1800
all_tests = list(tests.iter_suite_tests(suite))
1801
self.assertLength(4, all_tests)
1802
all_xys = sorted((t.x, t.y) for t in all_tests)
1803
self.assertEqual([(1, 1), (1, 2), (2, 1), (2, 2)], all_xys)
1658
1806
# NB: Don't delete this; it's not actually from 0.11!
1659
1807
@deprecated_function(deprecated_in((0, 11, 0)))
1660
1808
def sample_deprecated_function():
1971
2116
load_list='missing file name', list_only=True)
2119
class TestSubunitLogDetails(tests.TestCase, SelfTestHelper):
2121
_test_needs_features = [features.subunit]
2123
def run_subunit_stream(self, test_name):
2124
from subunit import ProtocolTestCase
2126
return TestUtil.TestSuite([_get_test(test_name)])
2127
stream = self.run_selftest(runner_class=tests.SubUnitBzrRunner,
2128
test_suite_factory=factory)
2129
test = ProtocolTestCase(stream)
2130
result = testtools.TestResult()
2132
content = stream.getvalue()
2133
return content, result
2135
def test_fail_has_log(self):
2136
content, result = self.run_subunit_stream('test_fail')
2137
self.assertEqual(1, len(result.failures))
2138
self.assertContainsRe(content, '(?m)^log$')
2139
self.assertContainsRe(content, 'this test will fail')
2141
def test_error_has_log(self):
2142
content, result = self.run_subunit_stream('test_error')
2143
self.assertContainsRe(content, '(?m)^log$')
2144
self.assertContainsRe(content, 'this test errored')
2146
def test_skip_has_no_log(self):
2147
content, result = self.run_subunit_stream('test_skip')
2148
self.assertNotContainsRe(content, '(?m)^log$')
2149
self.assertNotContainsRe(content, 'this test will be skipped')
2150
self.assertEqual(['reason'], result.skip_reasons.keys())
2151
skips = result.skip_reasons['reason']
2152
self.assertEqual(1, len(skips))
2154
# RemotedTestCase doesn't preserve the "details"
2155
## self.assertFalse('log' in test.getDetails())
2157
def test_missing_feature_has_no_log(self):
2158
content, result = self.run_subunit_stream('test_missing_feature')
2159
self.assertNotContainsRe(content, '(?m)^log$')
2160
self.assertNotContainsRe(content, 'missing the feature')
2161
self.assertEqual(['_MissingFeature\n'], result.skip_reasons.keys())
2162
skips = result.skip_reasons['_MissingFeature\n']
2163
self.assertEqual(1, len(skips))
2165
# RemotedTestCase doesn't preserve the "details"
2166
## self.assertFalse('log' in test.getDetails())
2168
def test_xfail_has_no_log(self):
2169
content, result = self.run_subunit_stream('test_xfail')
2170
self.assertNotContainsRe(content, '(?m)^log$')
2171
self.assertNotContainsRe(content, 'test with expected failure')
2172
self.assertEqual(1, len(result.expectedFailures))
2173
result_content = result.expectedFailures[0][1]
2174
self.assertNotContainsRe(result_content, 'Text attachment: log')
2175
self.assertNotContainsRe(result_content, 'test with expected failure')
2177
def test_unexpected_success_has_log(self):
2178
content, result = self.run_subunit_stream('test_unexpected_success')
2179
self.assertContainsRe(content, '(?m)^log$')
2180
self.assertContainsRe(content, 'test with unexpected success')
2181
# GZ 2011-05-18: Old versions of subunit treat unexpected success as a
2182
# success, if a min version check is added remove this
2183
from subunit import TestProtocolClient as _Client
2184
if _Client.addUnexpectedSuccess.im_func is _Client.addSuccess.im_func:
2185
self.expectFailure('subunit treats "unexpectedSuccess"'
2186
' as a plain success',
2187
self.assertEqual, 1, len(result.unexpectedSuccesses))
2188
self.assertEqual(1, len(result.unexpectedSuccesses))
2189
test = result.unexpectedSuccesses[0]
2190
# RemotedTestCase doesn't preserve the "details"
2191
## self.assertTrue('log' in test.getDetails())
2193
def test_success_has_no_log(self):
2194
content, result = self.run_subunit_stream('test_success')
2195
self.assertEqual(1, result.testsRun)
2196
self.assertNotContainsRe(content, '(?m)^log$')
2197
self.assertNotContainsRe(content, 'this test succeeds')
1974
2200
class TestRunBzr(tests.TestCase):
2283
2516
def test_allow_plugins(self):
2284
2517
self.assertRaises(_DontSpawnProcess, self.start_bzr_subprocess, [],
2286
2519
command = self._popen_args[0]
2287
2520
self.assertEqual([], command[2:])
2289
2522
def test_set_env(self):
2290
self.failIf('EXISTANT_ENV_VAR' in os.environ)
2523
self.assertFalse('EXISTANT_ENV_VAR' in os.environ)
2291
2524
# set in the child
2292
2525
def check_environment():
2293
2526
self.assertEqual('set variable', os.environ['EXISTANT_ENV_VAR'])
2294
2527
self.check_popen_state = check_environment
2295
2528
self.assertRaises(_DontSpawnProcess, self.start_bzr_subprocess, [],
2296
env_changes={'EXISTANT_ENV_VAR':'set variable'})
2529
env_changes={'EXISTANT_ENV_VAR':'set variable'})
2297
2530
# not set in theparent
2298
2531
self.assertFalse('EXISTANT_ENV_VAR' in os.environ)
2300
2533
def test_run_bzr_subprocess_env_del(self):
2301
2534
"""run_bzr_subprocess can remove environment variables too."""
2302
self.failIf('EXISTANT_ENV_VAR' in os.environ)
2535
self.assertFalse('EXISTANT_ENV_VAR' in os.environ)
2303
2536
def check_environment():
2304
2537
self.assertFalse('EXISTANT_ENV_VAR' in os.environ)
2305
2538
os.environ['EXISTANT_ENV_VAR'] = 'set variable'
2306
2539
self.check_popen_state = check_environment
2307
2540
self.assertRaises(_DontSpawnProcess, self.start_bzr_subprocess, [],
2308
env_changes={'EXISTANT_ENV_VAR':None})
2541
env_changes={'EXISTANT_ENV_VAR':None})
2309
2542
# Still set in parent
2310
2543
self.assertEqual('set variable', os.environ['EXISTANT_ENV_VAR'])
2311
2544
del os.environ['EXISTANT_ENV_VAR']
2313
2546
def test_env_del_missing(self):
2314
self.failIf('NON_EXISTANT_ENV_VAR' in os.environ)
2547
self.assertFalse('NON_EXISTANT_ENV_VAR' in os.environ)
2315
2548
def check_environment():
2316
2549
self.assertFalse('NON_EXISTANT_ENV_VAR' in os.environ)
2317
2550
self.check_popen_state = check_environment
2318
2551
self.assertRaises(_DontSpawnProcess, self.start_bzr_subprocess, [],
2319
env_changes={'NON_EXISTANT_ENV_VAR':None})
2552
env_changes={'NON_EXISTANT_ENV_VAR':None})
2321
2554
def test_working_dir(self):
2322
2555
"""Test that we can specify the working dir for the child"""
2357
2589
self.assertEqual('bzr: interrupted\n', result[1])
2360
class TestFeature(tests.TestCase):
2362
def test_caching(self):
2363
"""Feature._probe is called by the feature at most once."""
2364
class InstrumentedFeature(tests.Feature):
2366
super(InstrumentedFeature, self).__init__()
2369
self.calls.append('_probe')
2371
feature = InstrumentedFeature()
2373
self.assertEqual(['_probe'], feature.calls)
2375
self.assertEqual(['_probe'], feature.calls)
2377
def test_named_str(self):
2378
"""Feature.__str__ should thunk to feature_name()."""
2379
class NamedFeature(tests.Feature):
2380
def feature_name(self):
2382
feature = NamedFeature()
2383
self.assertEqual('symlinks', str(feature))
2385
def test_default_str(self):
2386
"""Feature.__str__ should default to __class__.__name__."""
2387
class NamedFeature(tests.Feature):
2389
feature = NamedFeature()
2390
self.assertEqual('NamedFeature', str(feature))
2393
class TestUnavailableFeature(tests.TestCase):
2395
def test_access_feature(self):
2396
feature = tests.Feature()
2397
exception = tests.UnavailableFeature(feature)
2398
self.assertIs(feature, exception.args[0])
2401
simple_thunk_feature = tests._CompatabilityThunkFeature(
2402
deprecated_in((2, 1, 0)),
2403
'bzrlib.tests.test_selftest',
2404
'simple_thunk_feature','UnicodeFilename',
2405
replacement_module='bzrlib.tests'
2408
class Test_CompatibilityFeature(tests.TestCase):
2410
def test_does_thunk(self):
2411
res = self.callDeprecated(
2412
['bzrlib.tests.test_selftest.simple_thunk_feature was deprecated'
2413
' in version 2.1.0. Use bzrlib.tests.UnicodeFilename instead.'],
2414
simple_thunk_feature.available)
2415
self.assertEqual(tests.UnicodeFilename.available(), res)
2418
class TestModuleAvailableFeature(tests.TestCase):
2420
def test_available_module(self):
2421
feature = tests.ModuleAvailableFeature('bzrlib.tests')
2422
self.assertEqual('bzrlib.tests', feature.module_name)
2423
self.assertEqual('bzrlib.tests', str(feature))
2424
self.assertTrue(feature.available())
2425
self.assertIs(tests, feature.module)
2427
def test_unavailable_module(self):
2428
feature = tests.ModuleAvailableFeature('bzrlib.no_such_module_exists')
2429
self.assertEqual('bzrlib.no_such_module_exists', str(feature))
2430
self.assertFalse(feature.available())
2431
self.assertIs(None, feature.module)
2434
2592
class TestSelftestFiltering(tests.TestCase):
2436
2594
def setUp(self):
2960
3119
self.assertEquals('bzrlib.plugins', tpr.resolve_alias('bp'))
3122
class TestThreadLeakDetection(tests.TestCase):
3123
"""Ensure when tests leak threads we detect and report it"""
3125
class LeakRecordingResult(tests.ExtendedTestResult):
3127
tests.ExtendedTestResult.__init__(self, StringIO(), 0, 1)
3129
def _report_thread_leak(self, test, leaks, alive):
3130
self.leaks.append((test, leaks))
3132
def test_testcase_without_addCleanups(self):
3133
"""Check old TestCase instances don't break with leak detection"""
3134
class Test(unittest.TestCase):
3137
result = self.LeakRecordingResult()
3139
result.startTestRun()
3141
result.stopTestRun()
3142
self.assertEqual(result._tests_leaking_threads_count, 0)
3143
self.assertEqual(result.leaks, [])
3145
def test_thread_leak(self):
3146
"""Ensure a thread that outlives the running of a test is reported
3148
Uses a thread that blocks on an event, and is started by the inner
3149
test case. As the thread outlives the inner case's run, it should be
3150
detected as a leak, but the event is then set so that the thread can
3151
be safely joined in cleanup so it's not leaked for real.
3153
event = threading.Event()
3154
thread = threading.Thread(name="Leaker", target=event.wait)
3155
class Test(tests.TestCase):
3156
def test_leak(self):
3158
result = self.LeakRecordingResult()
3159
test = Test("test_leak")
3160
self.addCleanup(thread.join)
3161
self.addCleanup(event.set)
3162
result.startTestRun()
3164
result.stopTestRun()
3165
self.assertEqual(result._tests_leaking_threads_count, 1)
3166
self.assertEqual(result._first_thread_leaker_id, test.id())
3167
self.assertEqual(result.leaks, [(test, set([thread]))])
3168
self.assertContainsString(result.stream.getvalue(), "leaking threads")
3170
def test_multiple_leaks(self):
3171
"""Check multiple leaks are blamed on the test cases at fault
3173
Same concept as the previous test, but has one inner test method that
3174
leaks two threads, and one that doesn't leak at all.
3176
event = threading.Event()
3177
thread_a = threading.Thread(name="LeakerA", target=event.wait)
3178
thread_b = threading.Thread(name="LeakerB", target=event.wait)
3179
thread_c = threading.Thread(name="LeakerC", target=event.wait)
3180
class Test(tests.TestCase):
3181
def test_first_leak(self):
3183
def test_second_no_leak(self):
3185
def test_third_leak(self):
3188
result = self.LeakRecordingResult()
3189
first_test = Test("test_first_leak")
3190
third_test = Test("test_third_leak")
3191
self.addCleanup(thread_a.join)
3192
self.addCleanup(thread_b.join)
3193
self.addCleanup(thread_c.join)
3194
self.addCleanup(event.set)
3195
result.startTestRun()
3197
[first_test, Test("test_second_no_leak"), third_test]
3199
result.stopTestRun()
3200
self.assertEqual(result._tests_leaking_threads_count, 2)
3201
self.assertEqual(result._first_thread_leaker_id, first_test.id())
3202
self.assertEqual(result.leaks, [
3203
(first_test, set([thread_b])),
3204
(third_test, set([thread_a, thread_c]))])
3205
self.assertContainsString(result.stream.getvalue(), "leaking threads")
3208
class TestPostMortemDebugging(tests.TestCase):
3209
"""Check post mortem debugging works when tests fail or error"""
3211
class TracebackRecordingResult(tests.ExtendedTestResult):
3213
tests.ExtendedTestResult.__init__(self, StringIO(), 0, 1)
3214
self.postcode = None
3215
def _post_mortem(self, tb=None):
3216
"""Record the code object at the end of the current traceback"""
3217
tb = tb or sys.exc_info()[2]
3220
while next is not None:
3223
self.postcode = tb.tb_frame.f_code
3224
def report_error(self, test, err):
3226
def report_failure(self, test, err):
3229
def test_location_unittest_error(self):
3230
"""Needs right post mortem traceback with erroring unittest case"""
3231
class Test(unittest.TestCase):
3234
result = self.TracebackRecordingResult()
3236
self.assertEqual(result.postcode, Test.runTest.func_code)
3238
def test_location_unittest_failure(self):
3239
"""Needs right post mortem traceback with failing unittest case"""
3240
class Test(unittest.TestCase):
3242
raise self.failureException
3243
result = self.TracebackRecordingResult()
3245
self.assertEqual(result.postcode, Test.runTest.func_code)
3247
def test_location_bt_error(self):
3248
"""Needs right post mortem traceback with erroring bzrlib.tests case"""
3249
class Test(tests.TestCase):
3250
def test_error(self):
3252
result = self.TracebackRecordingResult()
3253
Test("test_error").run(result)
3254
self.assertEqual(result.postcode, Test.test_error.func_code)
3256
def test_location_bt_failure(self):
3257
"""Needs right post mortem traceback with failing bzrlib.tests case"""
3258
class Test(tests.TestCase):
3259
def test_failure(self):
3260
raise self.failureException
3261
result = self.TracebackRecordingResult()
3262
Test("test_failure").run(result)
3263
self.assertEqual(result.postcode, Test.test_failure.func_code)
3265
def test_env_var_triggers_post_mortem(self):
3266
"""Check pdb.post_mortem is called iff BZR_TEST_PDB is set"""
3268
result = tests.ExtendedTestResult(StringIO(), 0, 1)
3269
post_mortem_calls = []
3270
self.overrideAttr(pdb, "post_mortem", post_mortem_calls.append)
3271
self.overrideEnv('BZR_TEST_PDB', None)
3272
result._post_mortem(1)
3273
self.overrideEnv('BZR_TEST_PDB', 'on')
3274
result._post_mortem(2)
3275
self.assertEqual([2], post_mortem_calls)
2963
3278
class TestRunSuite(tests.TestCase):
2965
3280
def test_runner_class(self):
2976
3291
self.verbosity)
2977
3292
tests.run_suite(suite, runner_class=MyRunner, stream=StringIO())
2978
3293
self.assertLength(1, calls)
3296
class TestEnvironHandling(tests.TestCase):
3298
def test_overrideEnv_None_called_twice_doesnt_leak(self):
3299
self.assertFalse('MYVAR' in os.environ)
3300
self.overrideEnv('MYVAR', '42')
3301
# We use an embedded test to make sure we fix the _captureVar bug
3302
class Test(tests.TestCase):
3304
# The first call save the 42 value
3305
self.overrideEnv('MYVAR', None)
3306
self.assertEquals(None, os.environ.get('MYVAR'))
3307
# Make sure we can call it twice
3308
self.overrideEnv('MYVAR', None)
3309
self.assertEquals(None, os.environ.get('MYVAR'))
3311
result = tests.TextTestResult(output, 0, 1)
3312
Test('test_me').run(result)
3313
if not result.wasStrictlySuccessful():
3314
self.fail(output.getvalue())
3315
# We get our value back
3316
self.assertEquals('42', os.environ.get('MYVAR'))
3319
class TestIsolatedEnv(tests.TestCase):
3320
"""Test isolating tests from os.environ.
3322
Since we use tests that are already isolated from os.environ a bit of care
3323
should be taken when designing the tests to avoid bootstrap side-effects.
3324
The tests start an already clean os.environ which allow doing valid
3325
assertions about which variables are present or not and design tests around
3329
class ScratchMonkey(tests.TestCase):
3334
def test_basics(self):
3335
# Make sure we know the definition of BZR_HOME: not part of os.environ
3336
# for tests.TestCase.
3337
self.assertTrue('BZR_HOME' in tests.isolated_environ)
3338
self.assertEquals(None, tests.isolated_environ['BZR_HOME'])
3339
# Being part of isolated_environ, BZR_HOME should not appear here
3340
self.assertFalse('BZR_HOME' in os.environ)
3341
# Make sure we know the definition of LINES: part of os.environ for
3343
self.assertTrue('LINES' in tests.isolated_environ)
3344
self.assertEquals('25', tests.isolated_environ['LINES'])
3345
self.assertEquals('25', os.environ['LINES'])
3347
def test_injecting_unknown_variable(self):
3348
# BZR_HOME is known to be absent from os.environ
3349
test = self.ScratchMonkey('test_me')
3350
tests.override_os_environ(test, {'BZR_HOME': 'foo'})
3351
self.assertEquals('foo', os.environ['BZR_HOME'])
3352
tests.restore_os_environ(test)
3353
self.assertFalse('BZR_HOME' in os.environ)
3355
def test_injecting_known_variable(self):
3356
test = self.ScratchMonkey('test_me')
3357
# LINES is known to be present in os.environ
3358
tests.override_os_environ(test, {'LINES': '42'})
3359
self.assertEquals('42', os.environ['LINES'])
3360
tests.restore_os_environ(test)
3361
self.assertEquals('25', os.environ['LINES'])
3363
def test_deleting_variable(self):
3364
test = self.ScratchMonkey('test_me')
3365
# LINES is known to be present in os.environ
3366
tests.override_os_environ(test, {'LINES': None})
3367
self.assertTrue('LINES' not in os.environ)
3368
tests.restore_os_environ(test)
3369
self.assertEquals('25', os.environ['LINES'])
3372
class TestDocTestSuiteIsolation(tests.TestCase):
3373
"""Test that `tests.DocTestSuite` isolates doc tests from os.environ.
3375
Since tests.TestCase alreay provides an isolation from os.environ, we use
3376
the clean environment as a base for testing. To precisely capture the
3377
isolation provided by tests.DocTestSuite, we use doctest.DocTestSuite to
3380
We want to make sure `tests.DocTestSuite` respect `tests.isolated_environ`,
3381
not `os.environ` so each test overrides it to suit its needs.
3385
def get_doctest_suite_for_string(self, klass, string):
3386
class Finder(doctest.DocTestFinder):
3388
def find(*args, **kwargs):
3389
test = doctest.DocTestParser().get_doctest(
3390
string, {}, 'foo', 'foo.py', 0)
3393
suite = klass(test_finder=Finder())
3396
def run_doctest_suite_for_string(self, klass, string):
3397
suite = self.get_doctest_suite_for_string(klass, string)
3399
result = tests.TextTestResult(output, 0, 1)
3401
return result, output
3403
def assertDocTestStringSucceds(self, klass, string):
3404
result, output = self.run_doctest_suite_for_string(klass, string)
3405
if not result.wasStrictlySuccessful():
3406
self.fail(output.getvalue())
3408
def assertDocTestStringFails(self, klass, string):
3409
result, output = self.run_doctest_suite_for_string(klass, string)
3410
if result.wasStrictlySuccessful():
3411
self.fail(output.getvalue())
3413
def test_injected_variable(self):
3414
self.overrideAttr(tests, 'isolated_environ', {'LINES': '42'})
3417
>>> os.environ['LINES']
3420
# doctest.DocTestSuite fails as it sees '25'
3421
self.assertDocTestStringFails(doctest.DocTestSuite, test)
3422
# tests.DocTestSuite sees '42'
3423
self.assertDocTestStringSucceds(tests.IsolatedDocTestSuite, test)
3425
def test_deleted_variable(self):
3426
self.overrideAttr(tests, 'isolated_environ', {'LINES': None})
3429
>>> os.environ.get('LINES')
3431
# doctest.DocTestSuite fails as it sees '25'
3432
self.assertDocTestStringFails(doctest.DocTestSuite, test)
3433
# tests.DocTestSuite sees None
3434
self.assertDocTestStringSucceds(tests.IsolatedDocTestSuite, test)
3437
class TestSelftestExcludePatterns(tests.TestCase):
3440
super(TestSelftestExcludePatterns, self).setUp()
3441
self.overrideAttr(tests, 'test_suite', self.suite_factory)
3443
def suite_factory(self, keep_only=None, starting_with=None):
3444
"""A test suite factory with only a few tests."""
3445
class Test(tests.TestCase):
3447
# We don't need the full class path
3448
return self._testMethodName
3455
return TestUtil.TestSuite([Test("a"), Test("b"), Test("c")])
3457
def assertTestList(self, expected, *selftest_args):
3458
# We rely on setUp installing the right test suite factory so we can
3459
# test at the command level without loading the whole test suite
3460
out, err = self.run_bzr(('selftest', '--list') + selftest_args)
3461
actual = out.splitlines()
3462
self.assertEquals(expected, actual)
3464
def test_full_list(self):
3465
self.assertTestList(['a', 'b', 'c'])
3467
def test_single_exclude(self):
3468
self.assertTestList(['b', 'c'], '-x', 'a')
3470
def test_mutiple_excludes(self):
3471
self.assertTestList(['c'], '-x', 'a', '-x', 'b')
3474
class TestCounterHooks(tests.TestCase, SelfTestHelper):
3476
_test_needs_features = [features.subunit]
3479
super(TestCounterHooks, self).setUp()
3480
class Test(tests.TestCase):
3483
super(Test, self).setUp()
3484
self.hooks = hooks.Hooks()
3485
self.hooks.add_hook('myhook', 'Foo bar blah', (2,4))
3486
self.install_counter_hook(self.hooks, 'myhook')
3491
def run_hook_once(self):
3492
for hook in self.hooks['myhook']:
3495
self.test_class = Test
3497
def assertHookCalls(self, expected_calls, test_name):
3498
test = self.test_class(test_name)
3499
result = unittest.TestResult()
3501
self.assertTrue(hasattr(test, '_counters'))
3502
self.assertTrue(test._counters.has_key('myhook'))
3503
self.assertEquals(expected_calls, test._counters['myhook'])
3505
def test_no_hook(self):
3506
self.assertHookCalls(0, 'no_hook')
3508
def test_run_hook_once(self):
3509
tt = features.testtools
3510
if tt.module.__version__ < (0, 9, 8):
3511
raise tests.TestSkipped('testtools-0.9.8 required for addDetail')
3512
self.assertHookCalls(1, 'run_hook_once')