549
571
tree = self.make_branch_and_memory_tree('dir')
550
572
# Guard against regression into MemoryTransport leaking
551
573
# files to disk instead of keeping them in memory.
552
self.failIf(osutils.lexists('dir'))
574
self.assertFalse(osutils.lexists('dir'))
553
575
self.assertIsInstance(tree, memorytree.MemoryTree)
555
577
def test_make_branch_and_memory_tree_with_format(self):
556
578
"""make_branch_and_memory_tree should accept a format option."""
557
579
format = bzrdir.BzrDirMetaFormat1()
558
format.repository_format = weaverepo.RepositoryFormat7()
580
format.repository_format = repository.format_registry.get_default()
559
581
tree = self.make_branch_and_memory_tree('dir', format=format)
560
582
# Guard against regression into MemoryTransport leaking
561
583
# files to disk instead of keeping them in memory.
562
self.failIf(osutils.lexists('dir'))
584
self.assertFalse(osutils.lexists('dir'))
563
585
self.assertIsInstance(tree, memorytree.MemoryTree)
564
586
self.assertEqual(format.repository_format.__class__,
565
587
tree.branch.repository._format.__class__)
569
591
self.assertIsInstance(builder, branchbuilder.BranchBuilder)
570
592
# Guard against regression into MemoryTransport leaking
571
593
# files to disk instead of keeping them in memory.
572
self.failIf(osutils.lexists('dir'))
594
self.assertFalse(osutils.lexists('dir'))
574
596
def test_make_branch_builder_with_format(self):
575
597
# Use a repo layout that doesn't conform to a 'named' layout, to ensure
576
598
# that the format objects are used.
577
599
format = bzrdir.BzrDirMetaFormat1()
578
repo_format = weaverepo.RepositoryFormat7()
600
repo_format = repository.format_registry.get_default()
579
601
format.repository_format = repo_format
580
602
builder = self.make_branch_builder('dir', format=format)
581
603
the_branch = builder.get_branch()
582
604
# Guard against regression into MemoryTransport leaking
583
605
# files to disk instead of keeping them in memory.
584
self.failIf(osutils.lexists('dir'))
606
self.assertFalse(osutils.lexists('dir'))
585
607
self.assertEqual(format.repository_format.__class__,
586
608
the_branch.repository._format.__class__)
587
609
self.assertEqual(repo_format.get_format_string(),
751
771
self.check_timing(ShortDelayTestCase('test_short_delay'),
754
def _patch_get_bzr_source_tree(self):
755
# Reading from the actual source tree breaks isolation, but we don't
756
# want to assume that thats *all* that would happen.
757
self.overrideAttr(bzrlib.version, '_get_bzr_source_tree', lambda: None)
759
def test_assigned_benchmark_file_stores_date(self):
760
self._patch_get_bzr_source_tree()
762
result = bzrlib.tests.TextTestResult(self._log_file,
767
output_string = output.getvalue()
768
# if you are wondering about the regexp please read the comment in
769
# test_bench_history (bzrlib.tests.test_selftest.TestRunner)
770
# XXX: what comment? -- Andrew Bennetts
771
self.assertContainsRe(output_string, "--date [0-9.]+")
773
def test_benchhistory_records_test_times(self):
774
self._patch_get_bzr_source_tree()
775
result_stream = StringIO()
776
result = bzrlib.tests.TextTestResult(
780
bench_history=result_stream
783
# we want profile a call and check that its test duration is recorded
784
# make a new test instance that when run will generate a benchmark
785
example_test_case = TestTestResult("_time_hello_world_encoding")
786
# execute the test, which should succeed and record times
787
example_test_case.run(result)
788
lines = result_stream.getvalue().splitlines()
789
self.assertEqual(2, len(lines))
790
self.assertContainsRe(lines[1],
791
" *[0-9]+ms bzrlib.tests.test_selftest.TestTestResult"
792
"._time_hello_world_encoding")
794
774
def _time_hello_world_encoding(self):
795
775
"""Profile two sleep calls
836
816
self.assertContainsRe(output,
837
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")
839
834
def test_known_failure(self):
840
835
"""A KnownFailure being raised should trigger several result actions."""
841
836
class InstrumentedTestResult(tests.ExtendedTestResult):
842
837
def stopTestRun(self): pass
843
def startTests(self): pass
844
def report_test_start(self, test): pass
838
def report_tests_starting(self): pass
845
839
def report_known_failure(self, test, err=None, details=None):
846
840
self._call = test, 'known failure'
847
841
result = InstrumentedTestResult(None, None, None, None)
1194
def _patch_get_bzr_source_tree(self):
1195
# Reading from the actual source tree breaks isolation, but we don't
1196
# want to assume that thats *all* that would happen.
1197
self._get_source_tree_calls = []
1199
self._get_source_tree_calls.append("called")
1201
self.overrideAttr(bzrlib.version, '_get_bzr_source_tree', new_get)
1203
def test_bench_history(self):
1204
# tests that the running the benchmark passes bench_history into
1205
# the test result object. We can tell that happens if
1206
# _get_bzr_source_tree is called.
1207
self._patch_get_bzr_source_tree()
1208
test = TestRunner('dummy_test')
1210
runner = tests.TextTestRunner(stream=self._log_file,
1211
bench_history=output)
1212
result = self.run_test_runner(runner, test)
1213
output_string = output.getvalue()
1214
self.assertContainsRe(output_string, "--date [0-9.]+")
1215
self.assertLength(1, self._get_source_tree_calls)
1198
def test_verbose_test_count(self):
1199
"""A verbose test run reports the right test count at the start"""
1200
suite = TestUtil.TestSuite([
1201
unittest.FunctionTestCase(lambda:None),
1202
unittest.FunctionTestCase(lambda:None)])
1203
self.assertEqual(suite.countTestCases(), 2)
1205
runner = tests.TextTestRunner(stream=stream, verbosity=2)
1206
# Need to use the CountingDecorator as that's what sets num_tests
1207
result = self.run_test_runner(runner, tests.CountingDecorator(suite))
1208
self.assertStartsWith(stream.getvalue(), "running 2 tests")
1217
1210
def test_startTestRun(self):
1218
1211
"""run should call result.startTestRun()"""
1220
class LoggingDecorator(tests.ForwardingResult):
1213
class LoggingDecorator(ExtendedToOriginalDecorator):
1221
1214
def startTestRun(self):
1222
tests.ForwardingResult.startTestRun(self)
1215
ExtendedToOriginalDecorator.startTestRun(self)
1223
1216
calls.append('startTestRun')
1224
1217
test = unittest.FunctionTestCase(lambda:None)
1225
1218
stream = StringIO()
1656
1666
self.assertEqual('original', obj.test_attr)
1669
class _MissingFeature(tests.Feature):
1672
missing_feature = _MissingFeature()
1675
def _get_test(name):
1676
"""Get an instance of a specific example test.
1678
We protect this in a function so that they don't auto-run in the test
1682
class ExampleTests(tests.TestCase):
1684
def test_fail(self):
1685
mutter('this was a failing test')
1686
self.fail('this test will fail')
1688
def test_error(self):
1689
mutter('this test errored')
1690
raise RuntimeError('gotcha')
1692
def test_missing_feature(self):
1693
mutter('missing the feature')
1694
self.requireFeature(missing_feature)
1696
def test_skip(self):
1697
mutter('this test will be skipped')
1698
raise tests.TestSkipped('reason')
1700
def test_success(self):
1701
mutter('this test succeeds')
1703
def test_xfail(self):
1704
mutter('test with expected failure')
1705
self.knownFailure('this_fails')
1707
def test_unexpected_success(self):
1708
mutter('test with unexpected success')
1709
self.expectFailure('should_fail', lambda: None)
1711
return ExampleTests(name)
1714
class TestTestCaseLogDetails(tests.TestCase):
1716
def _run_test(self, test_name):
1717
test = _get_test(test_name)
1718
result = testtools.TestResult()
1722
def test_fail_has_log(self):
1723
result = self._run_test('test_fail')
1724
self.assertEqual(1, len(result.failures))
1725
result_content = result.failures[0][1]
1726
self.assertContainsRe(result_content, 'Text attachment: log')
1727
self.assertContainsRe(result_content, 'this was a failing test')
1729
def test_error_has_log(self):
1730
result = self._run_test('test_error')
1731
self.assertEqual(1, len(result.errors))
1732
result_content = result.errors[0][1]
1733
self.assertContainsRe(result_content, 'Text attachment: log')
1734
self.assertContainsRe(result_content, 'this test errored')
1736
def test_skip_has_no_log(self):
1737
result = self._run_test('test_skip')
1738
self.assertEqual(['reason'], result.skip_reasons.keys())
1739
skips = result.skip_reasons['reason']
1740
self.assertEqual(1, len(skips))
1742
self.assertFalse('log' in test.getDetails())
1744
def test_missing_feature_has_no_log(self):
1745
# testtools doesn't know about addNotSupported, so it just gets
1746
# considered as a skip
1747
result = self._run_test('test_missing_feature')
1748
self.assertEqual([missing_feature], result.skip_reasons.keys())
1749
skips = result.skip_reasons[missing_feature]
1750
self.assertEqual(1, len(skips))
1752
self.assertFalse('log' in test.getDetails())
1754
def test_xfail_has_no_log(self):
1755
result = self._run_test('test_xfail')
1756
self.assertEqual(1, len(result.expectedFailures))
1757
result_content = result.expectedFailures[0][1]
1758
self.assertNotContainsRe(result_content, 'Text attachment: log')
1759
self.assertNotContainsRe(result_content, 'test with expected failure')
1761
def test_unexpected_success_has_log(self):
1762
result = self._run_test('test_unexpected_success')
1763
self.assertEqual(1, len(result.unexpectedSuccesses))
1764
# Inconsistency, unexpectedSuccesses is a list of tests,
1765
# expectedFailures is a list of reasons?
1766
test = result.unexpectedSuccesses[0]
1767
details = test.getDetails()
1768
self.assertTrue('log' in details)
1771
class TestTestCloning(tests.TestCase):
1772
"""Tests that test cloning of TestCases (as used by multiply_tests)."""
1774
def test_cloned_testcase_does_not_share_details(self):
1775
"""A TestCase cloned with clone_test does not share mutable attributes
1776
such as details or cleanups.
1778
class Test(tests.TestCase):
1780
self.addDetail('foo', Content('text/plain', lambda: 'foo'))
1781
orig_test = Test('test_foo')
1782
cloned_test = tests.clone_test(orig_test, orig_test.id() + '(cloned)')
1783
orig_test.run(unittest.TestResult())
1784
self.assertEqual('foo', orig_test.getDetails()['foo'].iter_bytes())
1785
self.assertEqual(None, cloned_test.getDetails().get('foo'))
1787
def test_double_apply_scenario_preserves_first_scenario(self):
1788
"""Applying two levels of scenarios to a test preserves the attributes
1789
added by both scenarios.
1791
class Test(tests.TestCase):
1794
test = Test('test_foo')
1795
scenarios_x = [('x=1', {'x': 1}), ('x=2', {'x': 2})]
1796
scenarios_y = [('y=1', {'y': 1}), ('y=2', {'y': 2})]
1797
suite = tests.multiply_tests(test, scenarios_x, unittest.TestSuite())
1798
suite = tests.multiply_tests(suite, scenarios_y, unittest.TestSuite())
1799
all_tests = list(tests.iter_suite_tests(suite))
1800
self.assertLength(4, all_tests)
1801
all_xys = sorted((t.x, t.y) for t in all_tests)
1802
self.assertEqual([(1, 1), (1, 2), (2, 1), (2, 2)], all_xys)
1659
1805
# NB: Don't delete this; it's not actually from 0.11!
1660
1806
@deprecated_function(deprecated_in((0, 11, 0)))
1661
1807
def sample_deprecated_function():
1971
2115
load_list='missing file name', list_only=True)
2118
class TestSubunitLogDetails(tests.TestCase, SelfTestHelper):
2120
_test_needs_features = [features.subunit]
2122
def run_subunit_stream(self, test_name):
2123
from subunit import ProtocolTestCase
2125
return TestUtil.TestSuite([_get_test(test_name)])
2126
stream = self.run_selftest(runner_class=tests.SubUnitBzrRunner,
2127
test_suite_factory=factory)
2128
test = ProtocolTestCase(stream)
2129
result = testtools.TestResult()
2131
content = stream.getvalue()
2132
return content, result
2134
def test_fail_has_log(self):
2135
content, result = self.run_subunit_stream('test_fail')
2136
self.assertEqual(1, len(result.failures))
2137
self.assertContainsRe(content, '(?m)^log$')
2138
self.assertContainsRe(content, 'this test will fail')
2140
def test_error_has_log(self):
2141
content, result = self.run_subunit_stream('test_error')
2142
self.assertContainsRe(content, '(?m)^log$')
2143
self.assertContainsRe(content, 'this test errored')
2145
def test_skip_has_no_log(self):
2146
content, result = self.run_subunit_stream('test_skip')
2147
self.assertNotContainsRe(content, '(?m)^log$')
2148
self.assertNotContainsRe(content, 'this test will be skipped')
2149
self.assertEqual(['reason'], result.skip_reasons.keys())
2150
skips = result.skip_reasons['reason']
2151
self.assertEqual(1, len(skips))
2153
# RemotedTestCase doesn't preserve the "details"
2154
## self.assertFalse('log' in test.getDetails())
2156
def test_missing_feature_has_no_log(self):
2157
content, result = self.run_subunit_stream('test_missing_feature')
2158
self.assertNotContainsRe(content, '(?m)^log$')
2159
self.assertNotContainsRe(content, 'missing the feature')
2160
self.assertEqual(['_MissingFeature\n'], result.skip_reasons.keys())
2161
skips = result.skip_reasons['_MissingFeature\n']
2162
self.assertEqual(1, len(skips))
2164
# RemotedTestCase doesn't preserve the "details"
2165
## self.assertFalse('log' in test.getDetails())
2167
def test_xfail_has_no_log(self):
2168
content, result = self.run_subunit_stream('test_xfail')
2169
self.assertNotContainsRe(content, '(?m)^log$')
2170
self.assertNotContainsRe(content, 'test with expected failure')
2171
self.assertEqual(1, len(result.expectedFailures))
2172
result_content = result.expectedFailures[0][1]
2173
self.assertNotContainsRe(result_content, 'Text attachment: log')
2174
self.assertNotContainsRe(result_content, 'test with expected failure')
2176
def test_unexpected_success_has_log(self):
2177
content, result = self.run_subunit_stream('test_unexpected_success')
2178
self.assertContainsRe(content, '(?m)^log$')
2179
self.assertContainsRe(content, 'test with unexpected success')
2180
self.expectFailure('subunit treats "unexpectedSuccess"'
2181
' as a plain success',
2182
self.assertEqual, 1, len(result.unexpectedSuccesses))
2183
self.assertEqual(1, len(result.unexpectedSuccesses))
2184
test = result.unexpectedSuccesses[0]
2185
# RemotedTestCase doesn't preserve the "details"
2186
## self.assertTrue('log' in test.getDetails())
2188
def test_success_has_no_log(self):
2189
content, result = self.run_subunit_stream('test_success')
2190
self.assertEqual(1, result.testsRun)
2191
self.assertNotContainsRe(content, '(?m)^log$')
2192
self.assertNotContainsRe(content, 'this test succeeds')
1974
2195
class TestRunBzr(tests.TestCase):
2951
3187
self.assertEquals('bzrlib.plugins', tpr.resolve_alias('bp'))
3190
class TestThreadLeakDetection(tests.TestCase):
3191
"""Ensure when tests leak threads we detect and report it"""
3193
class LeakRecordingResult(tests.ExtendedTestResult):
3195
tests.ExtendedTestResult.__init__(self, StringIO(), 0, 1)
3197
def _report_thread_leak(self, test, leaks, alive):
3198
self.leaks.append((test, leaks))
3200
def test_testcase_without_addCleanups(self):
3201
"""Check old TestCase instances don't break with leak detection"""
3202
class Test(unittest.TestCase):
3205
result = self.LeakRecordingResult()
3207
result.startTestRun()
3209
result.stopTestRun()
3210
self.assertEqual(result._tests_leaking_threads_count, 0)
3211
self.assertEqual(result.leaks, [])
3213
def test_thread_leak(self):
3214
"""Ensure a thread that outlives the running of a test is reported
3216
Uses a thread that blocks on an event, and is started by the inner
3217
test case. As the thread outlives the inner case's run, it should be
3218
detected as a leak, but the event is then set so that the thread can
3219
be safely joined in cleanup so it's not leaked for real.
3221
event = threading.Event()
3222
thread = threading.Thread(name="Leaker", target=event.wait)
3223
class Test(tests.TestCase):
3224
def test_leak(self):
3226
result = self.LeakRecordingResult()
3227
test = Test("test_leak")
3228
self.addCleanup(thread.join)
3229
self.addCleanup(event.set)
3230
result.startTestRun()
3232
result.stopTestRun()
3233
self.assertEqual(result._tests_leaking_threads_count, 1)
3234
self.assertEqual(result._first_thread_leaker_id, test.id())
3235
self.assertEqual(result.leaks, [(test, set([thread]))])
3236
self.assertContainsString(result.stream.getvalue(), "leaking threads")
3238
def test_multiple_leaks(self):
3239
"""Check multiple leaks are blamed on the test cases at fault
3241
Same concept as the previous test, but has one inner test method that
3242
leaks two threads, and one that doesn't leak at all.
3244
event = threading.Event()
3245
thread_a = threading.Thread(name="LeakerA", target=event.wait)
3246
thread_b = threading.Thread(name="LeakerB", target=event.wait)
3247
thread_c = threading.Thread(name="LeakerC", target=event.wait)
3248
class Test(tests.TestCase):
3249
def test_first_leak(self):
3251
def test_second_no_leak(self):
3253
def test_third_leak(self):
3256
result = self.LeakRecordingResult()
3257
first_test = Test("test_first_leak")
3258
third_test = Test("test_third_leak")
3259
self.addCleanup(thread_a.join)
3260
self.addCleanup(thread_b.join)
3261
self.addCleanup(thread_c.join)
3262
self.addCleanup(event.set)
3263
result.startTestRun()
3265
[first_test, Test("test_second_no_leak"), third_test]
3267
result.stopTestRun()
3268
self.assertEqual(result._tests_leaking_threads_count, 2)
3269
self.assertEqual(result._first_thread_leaker_id, first_test.id())
3270
self.assertEqual(result.leaks, [
3271
(first_test, set([thread_b])),
3272
(third_test, set([thread_a, thread_c]))])
3273
self.assertContainsString(result.stream.getvalue(), "leaking threads")
3276
class TestPostMortemDebugging(tests.TestCase):
3277
"""Check post mortem debugging works when tests fail or error"""
3279
class TracebackRecordingResult(tests.ExtendedTestResult):
3281
tests.ExtendedTestResult.__init__(self, StringIO(), 0, 1)
3282
self.postcode = None
3283
def _post_mortem(self, tb=None):
3284
"""Record the code object at the end of the current traceback"""
3285
tb = tb or sys.exc_info()[2]
3288
while next is not None:
3291
self.postcode = tb.tb_frame.f_code
3292
def report_error(self, test, err):
3294
def report_failure(self, test, err):
3297
def test_location_unittest_error(self):
3298
"""Needs right post mortem traceback with erroring unittest case"""
3299
class Test(unittest.TestCase):
3302
result = self.TracebackRecordingResult()
3304
self.assertEqual(result.postcode, Test.runTest.func_code)
3306
def test_location_unittest_failure(self):
3307
"""Needs right post mortem traceback with failing unittest case"""
3308
class Test(unittest.TestCase):
3310
raise self.failureException
3311
result = self.TracebackRecordingResult()
3313
self.assertEqual(result.postcode, Test.runTest.func_code)
3315
def test_location_bt_error(self):
3316
"""Needs right post mortem traceback with erroring bzrlib.tests case"""
3317
class Test(tests.TestCase):
3318
def test_error(self):
3320
result = self.TracebackRecordingResult()
3321
Test("test_error").run(result)
3322
self.assertEqual(result.postcode, Test.test_error.func_code)
3324
def test_location_bt_failure(self):
3325
"""Needs right post mortem traceback with failing bzrlib.tests case"""
3326
class Test(tests.TestCase):
3327
def test_failure(self):
3328
raise self.failureException
3329
result = self.TracebackRecordingResult()
3330
Test("test_failure").run(result)
3331
self.assertEqual(result.postcode, Test.test_failure.func_code)
3333
def test_env_var_triggers_post_mortem(self):
3334
"""Check pdb.post_mortem is called iff BZR_TEST_PDB is set"""
3336
result = tests.ExtendedTestResult(StringIO(), 0, 1)
3337
post_mortem_calls = []
3338
self.overrideAttr(pdb, "post_mortem", post_mortem_calls.append)
3339
self.overrideEnv('BZR_TEST_PDB', None)
3340
result._post_mortem(1)
3341
self.overrideEnv('BZR_TEST_PDB', 'on')
3342
result._post_mortem(2)
3343
self.assertEqual([2], post_mortem_calls)
2954
3346
class TestRunSuite(tests.TestCase):
2956
3348
def test_runner_class(self):
2967
3359
self.verbosity)
2968
3360
tests.run_suite(suite, runner_class=MyRunner, stream=StringIO())
2969
3361
self.assertLength(1, calls)
3364
class TestEnvironHandling(tests.TestCase):
3366
def test_overrideEnv_None_called_twice_doesnt_leak(self):
3367
self.assertFalse('MYVAR' in os.environ)
3368
self.overrideEnv('MYVAR', '42')
3369
# We use an embedded test to make sure we fix the _captureVar bug
3370
class Test(tests.TestCase):
3372
# The first call save the 42 value
3373
self.overrideEnv('MYVAR', None)
3374
self.assertEquals(None, os.environ.get('MYVAR'))
3375
# Make sure we can call it twice
3376
self.overrideEnv('MYVAR', None)
3377
self.assertEquals(None, os.environ.get('MYVAR'))
3379
result = tests.TextTestResult(output, 0, 1)
3380
Test('test_me').run(result)
3381
if not result.wasStrictlySuccessful():
3382
self.fail(output.getvalue())
3383
# We get our value back
3384
self.assertEquals('42', os.environ.get('MYVAR'))
3387
class TestIsolatedEnv(tests.TestCase):
3388
"""Test isolating tests from os.environ.
3390
Since we use tests that are already isolated from os.environ a bit of care
3391
should be taken when designing the tests to avoid bootstrap side-effects.
3392
The tests start an already clean os.environ which allow doing valid
3393
assertions about which variables are present or not and design tests around
3397
class ScratchMonkey(tests.TestCase):
3402
def test_basics(self):
3403
# Make sure we know the definition of BZR_HOME: not part of os.environ
3404
# for tests.TestCase.
3405
self.assertTrue('BZR_HOME' in tests.isolated_environ)
3406
self.assertEquals(None, tests.isolated_environ['BZR_HOME'])
3407
# Being part of isolated_environ, BZR_HOME should not appear here
3408
self.assertFalse('BZR_HOME' in os.environ)
3409
# Make sure we know the definition of LINES: part of os.environ for
3411
self.assertTrue('LINES' in tests.isolated_environ)
3412
self.assertEquals('25', tests.isolated_environ['LINES'])
3413
self.assertEquals('25', os.environ['LINES'])
3415
def test_injecting_unknown_variable(self):
3416
# BZR_HOME is known to be absent from os.environ
3417
test = self.ScratchMonkey('test_me')
3418
tests.override_os_environ(test, {'BZR_HOME': 'foo'})
3419
self.assertEquals('foo', os.environ['BZR_HOME'])
3420
tests.restore_os_environ(test)
3421
self.assertFalse('BZR_HOME' in os.environ)
3423
def test_injecting_known_variable(self):
3424
test = self.ScratchMonkey('test_me')
3425
# LINES is known to be present in os.environ
3426
tests.override_os_environ(test, {'LINES': '42'})
3427
self.assertEquals('42', os.environ['LINES'])
3428
tests.restore_os_environ(test)
3429
self.assertEquals('25', os.environ['LINES'])
3431
def test_deleting_variable(self):
3432
test = self.ScratchMonkey('test_me')
3433
# LINES is known to be present in os.environ
3434
tests.override_os_environ(test, {'LINES': None})
3435
self.assertTrue('LINES' not in os.environ)
3436
tests.restore_os_environ(test)
3437
self.assertEquals('25', os.environ['LINES'])
3440
class TestDocTestSuiteIsolation(tests.TestCase):
3441
"""Test that `tests.DocTestSuite` isolates doc tests from os.environ.
3443
Since tests.TestCase alreay provides an isolation from os.environ, we use
3444
the clean environment as a base for testing. To precisely capture the
3445
isolation provided by tests.DocTestSuite, we use doctest.DocTestSuite to
3448
We want to make sure `tests.DocTestSuite` respect `tests.isolated_environ`,
3449
not `os.environ` so each test overrides it to suit its needs.
3453
def get_doctest_suite_for_string(self, klass, string):
3454
class Finder(doctest.DocTestFinder):
3456
def find(*args, **kwargs):
3457
test = doctest.DocTestParser().get_doctest(
3458
string, {}, 'foo', 'foo.py', 0)
3461
suite = klass(test_finder=Finder())
3464
def run_doctest_suite_for_string(self, klass, string):
3465
suite = self.get_doctest_suite_for_string(klass, string)
3467
result = tests.TextTestResult(output, 0, 1)
3469
return result, output
3471
def assertDocTestStringSucceds(self, klass, string):
3472
result, output = self.run_doctest_suite_for_string(klass, string)
3473
if not result.wasStrictlySuccessful():
3474
self.fail(output.getvalue())
3476
def assertDocTestStringFails(self, klass, string):
3477
result, output = self.run_doctest_suite_for_string(klass, string)
3478
if result.wasStrictlySuccessful():
3479
self.fail(output.getvalue())
3481
def test_injected_variable(self):
3482
self.overrideAttr(tests, 'isolated_environ', {'LINES': '42'})
3485
>>> os.environ['LINES']
3488
# doctest.DocTestSuite fails as it sees '25'
3489
self.assertDocTestStringFails(doctest.DocTestSuite, test)
3490
# tests.DocTestSuite sees '42'
3491
self.assertDocTestStringSucceds(tests.IsolatedDocTestSuite, test)
3493
def test_deleted_variable(self):
3494
self.overrideAttr(tests, 'isolated_environ', {'LINES': None})
3497
>>> os.environ.get('LINES')
3499
# doctest.DocTestSuite fails as it sees '25'
3500
self.assertDocTestStringFails(doctest.DocTestSuite, test)
3501
# tests.DocTestSuite sees None
3502
self.assertDocTestStringSucceds(tests.IsolatedDocTestSuite, test)