750
771
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
774
def _time_hello_world_encoding(self):
794
775
"""Profile two sleep calls
835
816
self.assertContainsRe(output,
836
817
r"LSProf output for <type 'unicode'>\(\('world',\), {'errors': 'replace'}\)\n")
819
def test_uses_time_from_testtools(self):
820
"""Test case timings in verbose results should use testtools times"""
822
class TimeAddedVerboseTestResult(tests.VerboseTestResult):
823
def startTest(self, test):
824
self.time(datetime.datetime.utcfromtimestamp(1.145))
825
super(TimeAddedVerboseTestResult, self).startTest(test)
826
def addSuccess(self, test):
827
self.time(datetime.datetime.utcfromtimestamp(51.147))
828
super(TimeAddedVerboseTestResult, self).addSuccess(test)
829
def report_tests_starting(self): pass
831
self.get_passing_test().run(TimeAddedVerboseTestResult(sio, 0, 2))
832
self.assertEndsWith(sio.getvalue(), "OK 50002ms\n")
838
834
def test_known_failure(self):
839
835
"""A KnownFailure being raised should trigger several result actions."""
840
836
class InstrumentedTestResult(tests.ExtendedTestResult):
841
837
def stopTestRun(self): pass
842
def startTests(self): pass
843
def report_test_start(self, test): pass
838
def report_tests_starting(self): pass
844
839
def report_known_failure(self, test, err=None, details=None):
845
840
self._call = test, 'known failure'
846
841
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)
1216
def test_verbose_test_count(self):
1217
"""A verbose test run reports the right test count at the start"""
1218
suite = TestUtil.TestSuite([
1219
unittest.FunctionTestCase(lambda:None),
1220
unittest.FunctionTestCase(lambda:None)])
1221
self.assertEqual(suite.countTestCases(), 2)
1223
runner = tests.TextTestRunner(stream=stream, verbosity=2)
1224
# Need to use the CountingDecorator as that's what sets num_tests
1225
result = self.run_test_runner(runner, tests.CountingDecorator(suite))
1226
self.assertStartsWith(stream.getvalue(), "running 2 tests")
1216
1228
def test_startTestRun(self):
1217
1229
"""run should call result.startTestRun()"""
1219
class LoggingDecorator(tests.ForwardingResult):
1231
class LoggingDecorator(ExtendedToOriginalDecorator):
1220
1232
def startTestRun(self):
1221
tests.ForwardingResult.startTestRun(self)
1233
ExtendedToOriginalDecorator.startTestRun(self)
1222
1234
calls.append('startTestRun')
1223
1235
test = unittest.FunctionTestCase(lambda:None)
1224
1236
stream = StringIO()
1655
1684
self.assertEqual('original', obj.test_attr)
1687
class _MissingFeature(tests.Feature):
1690
missing_feature = _MissingFeature()
1693
def _get_test(name):
1694
"""Get an instance of a specific example test.
1696
We protect this in a function so that they don't auto-run in the test
1700
class ExampleTests(tests.TestCase):
1702
def test_fail(self):
1703
mutter('this was a failing test')
1704
self.fail('this test will fail')
1706
def test_error(self):
1707
mutter('this test errored')
1708
raise RuntimeError('gotcha')
1710
def test_missing_feature(self):
1711
mutter('missing the feature')
1712
self.requireFeature(missing_feature)
1714
def test_skip(self):
1715
mutter('this test will be skipped')
1716
raise tests.TestSkipped('reason')
1718
def test_success(self):
1719
mutter('this test succeeds')
1721
def test_xfail(self):
1722
mutter('test with expected failure')
1723
self.knownFailure('this_fails')
1725
def test_unexpected_success(self):
1726
mutter('test with unexpected success')
1727
self.expectFailure('should_fail', lambda: None)
1729
return ExampleTests(name)
1732
class TestTestCaseLogDetails(tests.TestCase):
1734
def _run_test(self, test_name):
1735
test = _get_test(test_name)
1736
result = testtools.TestResult()
1740
def test_fail_has_log(self):
1741
result = self._run_test('test_fail')
1742
self.assertEqual(1, len(result.failures))
1743
result_content = result.failures[0][1]
1744
self.assertContainsRe(result_content, 'Text attachment: log')
1745
self.assertContainsRe(result_content, 'this was a failing test')
1747
def test_error_has_log(self):
1748
result = self._run_test('test_error')
1749
self.assertEqual(1, len(result.errors))
1750
result_content = result.errors[0][1]
1751
self.assertContainsRe(result_content, 'Text attachment: log')
1752
self.assertContainsRe(result_content, 'this test errored')
1754
def test_skip_has_no_log(self):
1755
result = self._run_test('test_skip')
1756
self.assertEqual(['reason'], result.skip_reasons.keys())
1757
skips = result.skip_reasons['reason']
1758
self.assertEqual(1, len(skips))
1760
self.assertFalse('log' in test.getDetails())
1762
def test_missing_feature_has_no_log(self):
1763
# testtools doesn't know about addNotSupported, so it just gets
1764
# considered as a skip
1765
result = self._run_test('test_missing_feature')
1766
self.assertEqual([missing_feature], result.skip_reasons.keys())
1767
skips = result.skip_reasons[missing_feature]
1768
self.assertEqual(1, len(skips))
1770
self.assertFalse('log' in test.getDetails())
1772
def test_xfail_has_no_log(self):
1773
result = self._run_test('test_xfail')
1774
self.assertEqual(1, len(result.expectedFailures))
1775
result_content = result.expectedFailures[0][1]
1776
self.assertNotContainsRe(result_content, 'Text attachment: log')
1777
self.assertNotContainsRe(result_content, 'test with expected failure')
1779
def test_unexpected_success_has_log(self):
1780
result = self._run_test('test_unexpected_success')
1781
self.assertEqual(1, len(result.unexpectedSuccesses))
1782
# Inconsistency, unexpectedSuccesses is a list of tests,
1783
# expectedFailures is a list of reasons?
1784
test = result.unexpectedSuccesses[0]
1785
details = test.getDetails()
1786
self.assertTrue('log' in details)
1789
class TestTestCloning(tests.TestCase):
1790
"""Tests that test cloning of TestCases (as used by multiply_tests)."""
1792
def test_cloned_testcase_does_not_share_details(self):
1793
"""A TestCase cloned with clone_test does not share mutable attributes
1794
such as details or cleanups.
1796
class Test(tests.TestCase):
1798
self.addDetail('foo', Content('text/plain', lambda: 'foo'))
1799
orig_test = Test('test_foo')
1800
cloned_test = tests.clone_test(orig_test, orig_test.id() + '(cloned)')
1801
orig_test.run(unittest.TestResult())
1802
self.assertEqual('foo', orig_test.getDetails()['foo'].iter_bytes())
1803
self.assertEqual(None, cloned_test.getDetails().get('foo'))
1805
def test_double_apply_scenario_preserves_first_scenario(self):
1806
"""Applying two levels of scenarios to a test preserves the attributes
1807
added by both scenarios.
1809
class Test(tests.TestCase):
1812
test = Test('test_foo')
1813
scenarios_x = [('x=1', {'x': 1}), ('x=2', {'x': 2})]
1814
scenarios_y = [('y=1', {'y': 1}), ('y=2', {'y': 2})]
1815
suite = tests.multiply_tests(test, scenarios_x, unittest.TestSuite())
1816
suite = tests.multiply_tests(suite, scenarios_y, unittest.TestSuite())
1817
all_tests = list(tests.iter_suite_tests(suite))
1818
self.assertLength(4, all_tests)
1819
all_xys = sorted((t.x, t.y) for t in all_tests)
1820
self.assertEqual([(1, 1), (1, 2), (2, 1), (2, 2)], all_xys)
1658
1823
# NB: Don't delete this; it's not actually from 0.11!
1659
1824
@deprecated_function(deprecated_in((0, 11, 0)))
1660
1825
def sample_deprecated_function():
1971
2133
load_list='missing file name', list_only=True)
2136
class TestSubunitLogDetails(tests.TestCase, SelfTestHelper):
2138
_test_needs_features = [features.subunit]
2140
def run_subunit_stream(self, test_name):
2141
from subunit import ProtocolTestCase
2143
return TestUtil.TestSuite([_get_test(test_name)])
2144
stream = self.run_selftest(runner_class=tests.SubUnitBzrRunner,
2145
test_suite_factory=factory)
2146
test = ProtocolTestCase(stream)
2147
result = testtools.TestResult()
2149
content = stream.getvalue()
2150
return content, result
2152
def test_fail_has_log(self):
2153
content, result = self.run_subunit_stream('test_fail')
2154
self.assertEqual(1, len(result.failures))
2155
self.assertContainsRe(content, '(?m)^log$')
2156
self.assertContainsRe(content, 'this test will fail')
2158
def test_error_has_log(self):
2159
content, result = self.run_subunit_stream('test_error')
2160
self.assertContainsRe(content, '(?m)^log$')
2161
self.assertContainsRe(content, 'this test errored')
2163
def test_skip_has_no_log(self):
2164
content, result = self.run_subunit_stream('test_skip')
2165
self.assertNotContainsRe(content, '(?m)^log$')
2166
self.assertNotContainsRe(content, 'this test will be skipped')
2167
self.assertEqual(['reason'], result.skip_reasons.keys())
2168
skips = result.skip_reasons['reason']
2169
self.assertEqual(1, len(skips))
2171
# RemotedTestCase doesn't preserve the "details"
2172
## self.assertFalse('log' in test.getDetails())
2174
def test_missing_feature_has_no_log(self):
2175
content, result = self.run_subunit_stream('test_missing_feature')
2176
self.assertNotContainsRe(content, '(?m)^log$')
2177
self.assertNotContainsRe(content, 'missing the feature')
2178
self.assertEqual(['_MissingFeature\n'], result.skip_reasons.keys())
2179
skips = result.skip_reasons['_MissingFeature\n']
2180
self.assertEqual(1, len(skips))
2182
# RemotedTestCase doesn't preserve the "details"
2183
## self.assertFalse('log' in test.getDetails())
2185
def test_xfail_has_no_log(self):
2186
content, result = self.run_subunit_stream('test_xfail')
2187
self.assertNotContainsRe(content, '(?m)^log$')
2188
self.assertNotContainsRe(content, 'test with expected failure')
2189
self.assertEqual(1, len(result.expectedFailures))
2190
result_content = result.expectedFailures[0][1]
2191
self.assertNotContainsRe(result_content, 'Text attachment: log')
2192
self.assertNotContainsRe(result_content, 'test with expected failure')
2194
def test_unexpected_success_has_log(self):
2195
content, result = self.run_subunit_stream('test_unexpected_success')
2196
self.assertContainsRe(content, '(?m)^log$')
2197
self.assertContainsRe(content, 'test with unexpected success')
2198
# GZ 2011-05-18: Old versions of subunit treat unexpected success as a
2199
# success, if a min version check is added remove this
2200
from subunit import TestProtocolClient as _Client
2201
if _Client.addUnexpectedSuccess.im_func is _Client.addSuccess.im_func:
2202
self.expectFailure('subunit treats "unexpectedSuccess"'
2203
' as a plain success',
2204
self.assertEqual, 1, len(result.unexpectedSuccesses))
2205
self.assertEqual(1, len(result.unexpectedSuccesses))
2206
test = result.unexpectedSuccesses[0]
2207
# RemotedTestCase doesn't preserve the "details"
2208
## self.assertTrue('log' in test.getDetails())
2210
def test_success_has_no_log(self):
2211
content, result = self.run_subunit_stream('test_success')
2212
self.assertEqual(1, result.testsRun)
2213
self.assertNotContainsRe(content, '(?m)^log$')
2214
self.assertNotContainsRe(content, 'this test succeeds')
1974
2217
class TestRunBzr(tests.TestCase):
2960
3209
self.assertEquals('bzrlib.plugins', tpr.resolve_alias('bp'))
3212
class TestThreadLeakDetection(tests.TestCase):
3213
"""Ensure when tests leak threads we detect and report it"""
3215
class LeakRecordingResult(tests.ExtendedTestResult):
3217
tests.ExtendedTestResult.__init__(self, StringIO(), 0, 1)
3219
def _report_thread_leak(self, test, leaks, alive):
3220
self.leaks.append((test, leaks))
3222
def test_testcase_without_addCleanups(self):
3223
"""Check old TestCase instances don't break with leak detection"""
3224
class Test(unittest.TestCase):
3227
result = self.LeakRecordingResult()
3229
result.startTestRun()
3231
result.stopTestRun()
3232
self.assertEqual(result._tests_leaking_threads_count, 0)
3233
self.assertEqual(result.leaks, [])
3235
def test_thread_leak(self):
3236
"""Ensure a thread that outlives the running of a test is reported
3238
Uses a thread that blocks on an event, and is started by the inner
3239
test case. As the thread outlives the inner case's run, it should be
3240
detected as a leak, but the event is then set so that the thread can
3241
be safely joined in cleanup so it's not leaked for real.
3243
event = threading.Event()
3244
thread = threading.Thread(name="Leaker", target=event.wait)
3245
class Test(tests.TestCase):
3246
def test_leak(self):
3248
result = self.LeakRecordingResult()
3249
test = Test("test_leak")
3250
self.addCleanup(thread.join)
3251
self.addCleanup(event.set)
3252
result.startTestRun()
3254
result.stopTestRun()
3255
self.assertEqual(result._tests_leaking_threads_count, 1)
3256
self.assertEqual(result._first_thread_leaker_id, test.id())
3257
self.assertEqual(result.leaks, [(test, set([thread]))])
3258
self.assertContainsString(result.stream.getvalue(), "leaking threads")
3260
def test_multiple_leaks(self):
3261
"""Check multiple leaks are blamed on the test cases at fault
3263
Same concept as the previous test, but has one inner test method that
3264
leaks two threads, and one that doesn't leak at all.
3266
event = threading.Event()
3267
thread_a = threading.Thread(name="LeakerA", target=event.wait)
3268
thread_b = threading.Thread(name="LeakerB", target=event.wait)
3269
thread_c = threading.Thread(name="LeakerC", target=event.wait)
3270
class Test(tests.TestCase):
3271
def test_first_leak(self):
3273
def test_second_no_leak(self):
3275
def test_third_leak(self):
3278
result = self.LeakRecordingResult()
3279
first_test = Test("test_first_leak")
3280
third_test = Test("test_third_leak")
3281
self.addCleanup(thread_a.join)
3282
self.addCleanup(thread_b.join)
3283
self.addCleanup(thread_c.join)
3284
self.addCleanup(event.set)
3285
result.startTestRun()
3287
[first_test, Test("test_second_no_leak"), third_test]
3289
result.stopTestRun()
3290
self.assertEqual(result._tests_leaking_threads_count, 2)
3291
self.assertEqual(result._first_thread_leaker_id, first_test.id())
3292
self.assertEqual(result.leaks, [
3293
(first_test, set([thread_b])),
3294
(third_test, set([thread_a, thread_c]))])
3295
self.assertContainsString(result.stream.getvalue(), "leaking threads")
3298
class TestPostMortemDebugging(tests.TestCase):
3299
"""Check post mortem debugging works when tests fail or error"""
3301
class TracebackRecordingResult(tests.ExtendedTestResult):
3303
tests.ExtendedTestResult.__init__(self, StringIO(), 0, 1)
3304
self.postcode = None
3305
def _post_mortem(self, tb=None):
3306
"""Record the code object at the end of the current traceback"""
3307
tb = tb or sys.exc_info()[2]
3310
while next is not None:
3313
self.postcode = tb.tb_frame.f_code
3314
def report_error(self, test, err):
3316
def report_failure(self, test, err):
3319
def test_location_unittest_error(self):
3320
"""Needs right post mortem traceback with erroring unittest case"""
3321
class Test(unittest.TestCase):
3324
result = self.TracebackRecordingResult()
3326
self.assertEqual(result.postcode, Test.runTest.func_code)
3328
def test_location_unittest_failure(self):
3329
"""Needs right post mortem traceback with failing unittest case"""
3330
class Test(unittest.TestCase):
3332
raise self.failureException
3333
result = self.TracebackRecordingResult()
3335
self.assertEqual(result.postcode, Test.runTest.func_code)
3337
def test_location_bt_error(self):
3338
"""Needs right post mortem traceback with erroring bzrlib.tests case"""
3339
class Test(tests.TestCase):
3340
def test_error(self):
3342
result = self.TracebackRecordingResult()
3343
Test("test_error").run(result)
3344
self.assertEqual(result.postcode, Test.test_error.func_code)
3346
def test_location_bt_failure(self):
3347
"""Needs right post mortem traceback with failing bzrlib.tests case"""
3348
class Test(tests.TestCase):
3349
def test_failure(self):
3350
raise self.failureException
3351
result = self.TracebackRecordingResult()
3352
Test("test_failure").run(result)
3353
self.assertEqual(result.postcode, Test.test_failure.func_code)
3355
def test_env_var_triggers_post_mortem(self):
3356
"""Check pdb.post_mortem is called iff BZR_TEST_PDB is set"""
3358
result = tests.ExtendedTestResult(StringIO(), 0, 1)
3359
post_mortem_calls = []
3360
self.overrideAttr(pdb, "post_mortem", post_mortem_calls.append)
3361
self.overrideEnv('BZR_TEST_PDB', None)
3362
result._post_mortem(1)
3363
self.overrideEnv('BZR_TEST_PDB', 'on')
3364
result._post_mortem(2)
3365
self.assertEqual([2], post_mortem_calls)
2963
3368
class TestRunSuite(tests.TestCase):
2965
3370
def test_runner_class(self):
2976
3381
self.verbosity)
2977
3382
tests.run_suite(suite, runner_class=MyRunner, stream=StringIO())
2978
3383
self.assertLength(1, calls)
3386
class TestEnvironHandling(tests.TestCase):
3388
def test_overrideEnv_None_called_twice_doesnt_leak(self):
3389
self.assertFalse('MYVAR' in os.environ)
3390
self.overrideEnv('MYVAR', '42')
3391
# We use an embedded test to make sure we fix the _captureVar bug
3392
class Test(tests.TestCase):
3394
# The first call save the 42 value
3395
self.overrideEnv('MYVAR', None)
3396
self.assertEquals(None, os.environ.get('MYVAR'))
3397
# Make sure we can call it twice
3398
self.overrideEnv('MYVAR', None)
3399
self.assertEquals(None, os.environ.get('MYVAR'))
3401
result = tests.TextTestResult(output, 0, 1)
3402
Test('test_me').run(result)
3403
if not result.wasStrictlySuccessful():
3404
self.fail(output.getvalue())
3405
# We get our value back
3406
self.assertEquals('42', os.environ.get('MYVAR'))
3409
class TestIsolatedEnv(tests.TestCase):
3410
"""Test isolating tests from os.environ.
3412
Since we use tests that are already isolated from os.environ a bit of care
3413
should be taken when designing the tests to avoid bootstrap side-effects.
3414
The tests start an already clean os.environ which allow doing valid
3415
assertions about which variables are present or not and design tests around
3419
class ScratchMonkey(tests.TestCase):
3424
def test_basics(self):
3425
# Make sure we know the definition of BZR_HOME: not part of os.environ
3426
# for tests.TestCase.
3427
self.assertTrue('BZR_HOME' in tests.isolated_environ)
3428
self.assertEquals(None, tests.isolated_environ['BZR_HOME'])
3429
# Being part of isolated_environ, BZR_HOME should not appear here
3430
self.assertFalse('BZR_HOME' in os.environ)
3431
# Make sure we know the definition of LINES: part of os.environ for
3433
self.assertTrue('LINES' in tests.isolated_environ)
3434
self.assertEquals('25', tests.isolated_environ['LINES'])
3435
self.assertEquals('25', os.environ['LINES'])
3437
def test_injecting_unknown_variable(self):
3438
# BZR_HOME is known to be absent from os.environ
3439
test = self.ScratchMonkey('test_me')
3440
tests.override_os_environ(test, {'BZR_HOME': 'foo'})
3441
self.assertEquals('foo', os.environ['BZR_HOME'])
3442
tests.restore_os_environ(test)
3443
self.assertFalse('BZR_HOME' in os.environ)
3445
def test_injecting_known_variable(self):
3446
test = self.ScratchMonkey('test_me')
3447
# LINES is known to be present in os.environ
3448
tests.override_os_environ(test, {'LINES': '42'})
3449
self.assertEquals('42', os.environ['LINES'])
3450
tests.restore_os_environ(test)
3451
self.assertEquals('25', os.environ['LINES'])
3453
def test_deleting_variable(self):
3454
test = self.ScratchMonkey('test_me')
3455
# LINES is known to be present in os.environ
3456
tests.override_os_environ(test, {'LINES': None})
3457
self.assertTrue('LINES' not in os.environ)
3458
tests.restore_os_environ(test)
3459
self.assertEquals('25', os.environ['LINES'])
3462
class TestDocTestSuiteIsolation(tests.TestCase):
3463
"""Test that `tests.DocTestSuite` isolates doc tests from os.environ.
3465
Since tests.TestCase alreay provides an isolation from os.environ, we use
3466
the clean environment as a base for testing. To precisely capture the
3467
isolation provided by tests.DocTestSuite, we use doctest.DocTestSuite to
3470
We want to make sure `tests.DocTestSuite` respect `tests.isolated_environ`,
3471
not `os.environ` so each test overrides it to suit its needs.
3475
def get_doctest_suite_for_string(self, klass, string):
3476
class Finder(doctest.DocTestFinder):
3478
def find(*args, **kwargs):
3479
test = doctest.DocTestParser().get_doctest(
3480
string, {}, 'foo', 'foo.py', 0)
3483
suite = klass(test_finder=Finder())
3486
def run_doctest_suite_for_string(self, klass, string):
3487
suite = self.get_doctest_suite_for_string(klass, string)
3489
result = tests.TextTestResult(output, 0, 1)
3491
return result, output
3493
def assertDocTestStringSucceds(self, klass, string):
3494
result, output = self.run_doctest_suite_for_string(klass, string)
3495
if not result.wasStrictlySuccessful():
3496
self.fail(output.getvalue())
3498
def assertDocTestStringFails(self, klass, string):
3499
result, output = self.run_doctest_suite_for_string(klass, string)
3500
if result.wasStrictlySuccessful():
3501
self.fail(output.getvalue())
3503
def test_injected_variable(self):
3504
self.overrideAttr(tests, 'isolated_environ', {'LINES': '42'})
3507
>>> os.environ['LINES']
3510
# doctest.DocTestSuite fails as it sees '25'
3511
self.assertDocTestStringFails(doctest.DocTestSuite, test)
3512
# tests.DocTestSuite sees '42'
3513
self.assertDocTestStringSucceds(tests.IsolatedDocTestSuite, test)
3515
def test_deleted_variable(self):
3516
self.overrideAttr(tests, 'isolated_environ', {'LINES': None})
3519
>>> os.environ.get('LINES')
3521
# doctest.DocTestSuite fails as it sees '25'
3522
self.assertDocTestStringFails(doctest.DocTestSuite, test)
3523
# tests.DocTestSuite sees None
3524
self.assertDocTestStringSucceds(tests.IsolatedDocTestSuite, test)
3527
class TestSelftestExcludePatterns(tests.TestCase):
3530
super(TestSelftestExcludePatterns, self).setUp()
3531
self.overrideAttr(tests, 'test_suite', self.suite_factory)
3533
def suite_factory(self, keep_only=None, starting_with=None):
3534
"""A test suite factory with only a few tests."""
3535
class Test(tests.TestCase):
3537
# We don't need the full class path
3538
return self._testMethodName
3545
return TestUtil.TestSuite([Test("a"), Test("b"), Test("c")])
3547
def assertTestList(self, expected, *selftest_args):
3548
# We rely on setUp installing the right test suite factory so we can
3549
# test at the command level without loading the whole test suite
3550
out, err = self.run_bzr(('selftest', '--list') + selftest_args)
3551
actual = out.splitlines()
3552
self.assertEquals(expected, actual)
3554
def test_full_list(self):
3555
self.assertTestList(['a', 'b', 'c'])
3557
def test_single_exclude(self):
3558
self.assertTestList(['b', 'c'], '-x', 'a')
3560
def test_mutiple_excludes(self):
3561
self.assertTestList(['c'], '-x', 'a', '-x', 'b')