548
568
tree = self.make_branch_and_memory_tree('dir')
549
569
# Guard against regression into MemoryTransport leaking
550
570
# files to disk instead of keeping them in memory.
551
self.failIf(osutils.lexists('dir'))
571
self.assertFalse(osutils.lexists('dir'))
552
572
self.assertIsInstance(tree, memorytree.MemoryTree)
554
574
def test_make_branch_and_memory_tree_with_format(self):
555
575
"""make_branch_and_memory_tree should accept a format option."""
556
576
format = bzrdir.BzrDirMetaFormat1()
557
format.repository_format = weaverepo.RepositoryFormat7()
577
format.repository_format = repository.format_registry.get_default()
558
578
tree = self.make_branch_and_memory_tree('dir', format=format)
559
579
# Guard against regression into MemoryTransport leaking
560
580
# files to disk instead of keeping them in memory.
561
self.failIf(osutils.lexists('dir'))
581
self.assertFalse(osutils.lexists('dir'))
562
582
self.assertIsInstance(tree, memorytree.MemoryTree)
563
583
self.assertEqual(format.repository_format.__class__,
564
584
tree.branch.repository._format.__class__)
568
588
self.assertIsInstance(builder, branchbuilder.BranchBuilder)
569
589
# Guard against regression into MemoryTransport leaking
570
590
# files to disk instead of keeping them in memory.
571
self.failIf(osutils.lexists('dir'))
591
self.assertFalse(osutils.lexists('dir'))
573
593
def test_make_branch_builder_with_format(self):
574
594
# Use a repo layout that doesn't conform to a 'named' layout, to ensure
575
595
# that the format objects are used.
576
596
format = bzrdir.BzrDirMetaFormat1()
577
repo_format = weaverepo.RepositoryFormat7()
597
repo_format = repository.format_registry.get_default()
578
598
format.repository_format = repo_format
579
599
builder = self.make_branch_builder('dir', format=format)
580
600
the_branch = builder.get_branch()
581
601
# Guard against regression into MemoryTransport leaking
582
602
# files to disk instead of keeping them in memory.
583
self.failIf(osutils.lexists('dir'))
603
self.assertFalse(osutils.lexists('dir'))
584
604
self.assertEqual(format.repository_format.__class__,
585
605
the_branch.repository._format.__class__)
586
606
self.assertEqual(repo_format.get_format_string(),
750
768
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
771
def _time_hello_world_encoding(self):
794
772
"""Profile two sleep calls
835
813
self.assertContainsRe(output,
836
814
r"LSProf output for <type 'unicode'>\(\('world',\), {'errors': 'replace'}\)\n")
816
def test_uses_time_from_testtools(self):
817
"""Test case timings in verbose results should use testtools times"""
819
class TimeAddedVerboseTestResult(tests.VerboseTestResult):
820
def startTest(self, test):
821
self.time(datetime.datetime.utcfromtimestamp(1.145))
822
super(TimeAddedVerboseTestResult, self).startTest(test)
823
def addSuccess(self, test):
824
self.time(datetime.datetime.utcfromtimestamp(51.147))
825
super(TimeAddedVerboseTestResult, self).addSuccess(test)
826
def report_tests_starting(self): pass
828
self.get_passing_test().run(TimeAddedVerboseTestResult(sio, 0, 2))
829
self.assertEndsWith(sio.getvalue(), "OK 50002ms\n")
838
831
def test_known_failure(self):
839
832
"""A KnownFailure being raised should trigger several result actions."""
840
833
class InstrumentedTestResult(tests.ExtendedTestResult):
841
834
def stopTestRun(self): pass
842
def startTests(self): pass
843
def report_test_start(self, test): pass
835
def report_tests_starting(self): pass
844
836
def report_known_failure(self, test, err=None, details=None):
845
837
self._call = test, 'known failure'
846
838
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)
1195
def test_verbose_test_count(self):
1196
"""A verbose test run reports the right test count at the start"""
1197
suite = TestUtil.TestSuite([
1198
unittest.FunctionTestCase(lambda:None),
1199
unittest.FunctionTestCase(lambda:None)])
1200
self.assertEqual(suite.countTestCases(), 2)
1202
runner = tests.TextTestRunner(stream=stream, verbosity=2)
1203
# Need to use the CountingDecorator as that's what sets num_tests
1204
result = self.run_test_runner(runner, tests.CountingDecorator(suite))
1205
self.assertStartsWith(stream.getvalue(), "running 2 tests")
1216
1207
def test_startTestRun(self):
1217
1208
"""run should call result.startTestRun()"""
1219
class LoggingDecorator(tests.ForwardingResult):
1210
class LoggingDecorator(ExtendedToOriginalDecorator):
1220
1211
def startTestRun(self):
1221
tests.ForwardingResult.startTestRun(self)
1212
ExtendedToOriginalDecorator.startTestRun(self)
1222
1213
calls.append('startTestRun')
1223
1214
test = unittest.FunctionTestCase(lambda:None)
1224
1215
stream = StringIO()
1655
1663
self.assertEqual('original', obj.test_attr)
1666
class _MissingFeature(tests.Feature):
1669
missing_feature = _MissingFeature()
1672
def _get_test(name):
1673
"""Get an instance of a specific example test.
1675
We protect this in a function so that they don't auto-run in the test
1679
class ExampleTests(tests.TestCase):
1681
def test_fail(self):
1682
mutter('this was a failing test')
1683
self.fail('this test will fail')
1685
def test_error(self):
1686
mutter('this test errored')
1687
raise RuntimeError('gotcha')
1689
def test_missing_feature(self):
1690
mutter('missing the feature')
1691
self.requireFeature(missing_feature)
1693
def test_skip(self):
1694
mutter('this test will be skipped')
1695
raise tests.TestSkipped('reason')
1697
def test_success(self):
1698
mutter('this test succeeds')
1700
def test_xfail(self):
1701
mutter('test with expected failure')
1702
self.knownFailure('this_fails')
1704
def test_unexpected_success(self):
1705
mutter('test with unexpected success')
1706
self.expectFailure('should_fail', lambda: None)
1708
return ExampleTests(name)
1711
class TestTestCaseLogDetails(tests.TestCase):
1713
def _run_test(self, test_name):
1714
test = _get_test(test_name)
1715
result = testtools.TestResult()
1719
def test_fail_has_log(self):
1720
result = self._run_test('test_fail')
1721
self.assertEqual(1, len(result.failures))
1722
result_content = result.failures[0][1]
1723
self.assertContainsRe(result_content, 'Text attachment: log')
1724
self.assertContainsRe(result_content, 'this was a failing test')
1726
def test_error_has_log(self):
1727
result = self._run_test('test_error')
1728
self.assertEqual(1, len(result.errors))
1729
result_content = result.errors[0][1]
1730
self.assertContainsRe(result_content, 'Text attachment: log')
1731
self.assertContainsRe(result_content, 'this test errored')
1733
def test_skip_has_no_log(self):
1734
result = self._run_test('test_skip')
1735
self.assertEqual(['reason'], result.skip_reasons.keys())
1736
skips = result.skip_reasons['reason']
1737
self.assertEqual(1, len(skips))
1739
self.assertFalse('log' in test.getDetails())
1741
def test_missing_feature_has_no_log(self):
1742
# testtools doesn't know about addNotSupported, so it just gets
1743
# considered as a skip
1744
result = self._run_test('test_missing_feature')
1745
self.assertEqual([missing_feature], result.skip_reasons.keys())
1746
skips = result.skip_reasons[missing_feature]
1747
self.assertEqual(1, len(skips))
1749
self.assertFalse('log' in test.getDetails())
1751
def test_xfail_has_no_log(self):
1752
result = self._run_test('test_xfail')
1753
self.assertEqual(1, len(result.expectedFailures))
1754
result_content = result.expectedFailures[0][1]
1755
self.assertNotContainsRe(result_content, 'Text attachment: log')
1756
self.assertNotContainsRe(result_content, 'test with expected failure')
1758
def test_unexpected_success_has_log(self):
1759
result = self._run_test('test_unexpected_success')
1760
self.assertEqual(1, len(result.unexpectedSuccesses))
1761
# Inconsistency, unexpectedSuccesses is a list of tests,
1762
# expectedFailures is a list of reasons?
1763
test = result.unexpectedSuccesses[0]
1764
details = test.getDetails()
1765
self.assertTrue('log' in details)
1768
class TestTestCloning(tests.TestCase):
1769
"""Tests that test cloning of TestCases (as used by multiply_tests)."""
1771
def test_cloned_testcase_does_not_share_details(self):
1772
"""A TestCase cloned with clone_test does not share mutable attributes
1773
such as details or cleanups.
1775
class Test(tests.TestCase):
1777
self.addDetail('foo', Content('text/plain', lambda: 'foo'))
1778
orig_test = Test('test_foo')
1779
cloned_test = tests.clone_test(orig_test, orig_test.id() + '(cloned)')
1780
orig_test.run(unittest.TestResult())
1781
self.assertEqual('foo', orig_test.getDetails()['foo'].iter_bytes())
1782
self.assertEqual(None, cloned_test.getDetails().get('foo'))
1784
def test_double_apply_scenario_preserves_first_scenario(self):
1785
"""Applying two levels of scenarios to a test preserves the attributes
1786
added by both scenarios.
1788
class Test(tests.TestCase):
1791
test = Test('test_foo')
1792
scenarios_x = [('x=1', {'x': 1}), ('x=2', {'x': 2})]
1793
scenarios_y = [('y=1', {'y': 1}), ('y=2', {'y': 2})]
1794
suite = tests.multiply_tests(test, scenarios_x, unittest.TestSuite())
1795
suite = tests.multiply_tests(suite, scenarios_y, unittest.TestSuite())
1796
all_tests = list(tests.iter_suite_tests(suite))
1797
self.assertLength(4, all_tests)
1798
all_xys = sorted((t.x, t.y) for t in all_tests)
1799
self.assertEqual([(1, 1), (1, 2), (2, 1), (2, 2)], all_xys)
1658
1802
# NB: Don't delete this; it's not actually from 0.11!
1659
1803
@deprecated_function(deprecated_in((0, 11, 0)))
1660
1804
def sample_deprecated_function():
1971
2112
load_list='missing file name', list_only=True)
2115
class TestSubunitLogDetails(tests.TestCase, SelfTestHelper):
2117
_test_needs_features = [features.subunit]
2119
def run_subunit_stream(self, test_name):
2120
from subunit import ProtocolTestCase
2122
return TestUtil.TestSuite([_get_test(test_name)])
2123
stream = self.run_selftest(runner_class=tests.SubUnitBzrRunner,
2124
test_suite_factory=factory)
2125
test = ProtocolTestCase(stream)
2126
result = testtools.TestResult()
2128
content = stream.getvalue()
2129
return content, result
2131
def test_fail_has_log(self):
2132
content, result = self.run_subunit_stream('test_fail')
2133
self.assertEqual(1, len(result.failures))
2134
self.assertContainsRe(content, '(?m)^log$')
2135
self.assertContainsRe(content, 'this test will fail')
2137
def test_error_has_log(self):
2138
content, result = self.run_subunit_stream('test_error')
2139
self.assertContainsRe(content, '(?m)^log$')
2140
self.assertContainsRe(content, 'this test errored')
2142
def test_skip_has_no_log(self):
2143
content, result = self.run_subunit_stream('test_skip')
2144
self.assertNotContainsRe(content, '(?m)^log$')
2145
self.assertNotContainsRe(content, 'this test will be skipped')
2146
self.assertEqual(['reason'], result.skip_reasons.keys())
2147
skips = result.skip_reasons['reason']
2148
self.assertEqual(1, len(skips))
2150
# RemotedTestCase doesn't preserve the "details"
2151
## self.assertFalse('log' in test.getDetails())
2153
def test_missing_feature_has_no_log(self):
2154
content, result = self.run_subunit_stream('test_missing_feature')
2155
self.assertNotContainsRe(content, '(?m)^log$')
2156
self.assertNotContainsRe(content, 'missing the feature')
2157
self.assertEqual(['_MissingFeature\n'], result.skip_reasons.keys())
2158
skips = result.skip_reasons['_MissingFeature\n']
2159
self.assertEqual(1, len(skips))
2161
# RemotedTestCase doesn't preserve the "details"
2162
## self.assertFalse('log' in test.getDetails())
2164
def test_xfail_has_no_log(self):
2165
content, result = self.run_subunit_stream('test_xfail')
2166
self.assertNotContainsRe(content, '(?m)^log$')
2167
self.assertNotContainsRe(content, 'test with expected failure')
2168
self.assertEqual(1, len(result.expectedFailures))
2169
result_content = result.expectedFailures[0][1]
2170
self.assertNotContainsRe(result_content, 'Text attachment: log')
2171
self.assertNotContainsRe(result_content, 'test with expected failure')
2173
def test_unexpected_success_has_log(self):
2174
content, result = self.run_subunit_stream('test_unexpected_success')
2175
self.assertContainsRe(content, '(?m)^log$')
2176
self.assertContainsRe(content, 'test with unexpected success')
2177
self.expectFailure('subunit treats "unexpectedSuccess"'
2178
' as a plain success',
2179
self.assertEqual, 1, len(result.unexpectedSuccesses))
2180
self.assertEqual(1, len(result.unexpectedSuccesses))
2181
test = result.unexpectedSuccesses[0]
2182
# RemotedTestCase doesn't preserve the "details"
2183
## self.assertTrue('log' in test.getDetails())
2185
def test_success_has_no_log(self):
2186
content, result = self.run_subunit_stream('test_success')
2187
self.assertEqual(1, result.testsRun)
2188
self.assertNotContainsRe(content, '(?m)^log$')
2189
self.assertNotContainsRe(content, 'this test succeeds')
1974
2192
class TestRunBzr(tests.TestCase):
2960
3184
self.assertEquals('bzrlib.plugins', tpr.resolve_alias('bp'))
3187
class TestThreadLeakDetection(tests.TestCase):
3188
"""Ensure when tests leak threads we detect and report it"""
3190
class LeakRecordingResult(tests.ExtendedTestResult):
3192
tests.ExtendedTestResult.__init__(self, StringIO(), 0, 1)
3194
def _report_thread_leak(self, test, leaks, alive):
3195
self.leaks.append((test, leaks))
3197
def test_testcase_without_addCleanups(self):
3198
"""Check old TestCase instances don't break with leak detection"""
3199
class Test(unittest.TestCase):
3202
result = self.LeakRecordingResult()
3204
result.startTestRun()
3206
result.stopTestRun()
3207
self.assertEqual(result._tests_leaking_threads_count, 0)
3208
self.assertEqual(result.leaks, [])
3210
def test_thread_leak(self):
3211
"""Ensure a thread that outlives the running of a test is reported
3213
Uses a thread that blocks on an event, and is started by the inner
3214
test case. As the thread outlives the inner case's run, it should be
3215
detected as a leak, but the event is then set so that the thread can
3216
be safely joined in cleanup so it's not leaked for real.
3218
event = threading.Event()
3219
thread = threading.Thread(name="Leaker", target=event.wait)
3220
class Test(tests.TestCase):
3221
def test_leak(self):
3223
result = self.LeakRecordingResult()
3224
test = Test("test_leak")
3225
self.addCleanup(thread.join)
3226
self.addCleanup(event.set)
3227
result.startTestRun()
3229
result.stopTestRun()
3230
self.assertEqual(result._tests_leaking_threads_count, 1)
3231
self.assertEqual(result._first_thread_leaker_id, test.id())
3232
self.assertEqual(result.leaks, [(test, set([thread]))])
3233
self.assertContainsString(result.stream.getvalue(), "leaking threads")
3235
def test_multiple_leaks(self):
3236
"""Check multiple leaks are blamed on the test cases at fault
3238
Same concept as the previous test, but has one inner test method that
3239
leaks two threads, and one that doesn't leak at all.
3241
event = threading.Event()
3242
thread_a = threading.Thread(name="LeakerA", target=event.wait)
3243
thread_b = threading.Thread(name="LeakerB", target=event.wait)
3244
thread_c = threading.Thread(name="LeakerC", target=event.wait)
3245
class Test(tests.TestCase):
3246
def test_first_leak(self):
3248
def test_second_no_leak(self):
3250
def test_third_leak(self):
3253
result = self.LeakRecordingResult()
3254
first_test = Test("test_first_leak")
3255
third_test = Test("test_third_leak")
3256
self.addCleanup(thread_a.join)
3257
self.addCleanup(thread_b.join)
3258
self.addCleanup(thread_c.join)
3259
self.addCleanup(event.set)
3260
result.startTestRun()
3262
[first_test, Test("test_second_no_leak"), third_test]
3264
result.stopTestRun()
3265
self.assertEqual(result._tests_leaking_threads_count, 2)
3266
self.assertEqual(result._first_thread_leaker_id, first_test.id())
3267
self.assertEqual(result.leaks, [
3268
(first_test, set([thread_b])),
3269
(third_test, set([thread_a, thread_c]))])
3270
self.assertContainsString(result.stream.getvalue(), "leaking threads")
3273
class TestPostMortemDebugging(tests.TestCase):
3274
"""Check post mortem debugging works when tests fail or error"""
3276
class TracebackRecordingResult(tests.ExtendedTestResult):
3278
tests.ExtendedTestResult.__init__(self, StringIO(), 0, 1)
3279
self.postcode = None
3280
def _post_mortem(self, tb=None):
3281
"""Record the code object at the end of the current traceback"""
3282
tb = tb or sys.exc_info()[2]
3285
while next is not None:
3288
self.postcode = tb.tb_frame.f_code
3289
def report_error(self, test, err):
3291
def report_failure(self, test, err):
3294
def test_location_unittest_error(self):
3295
"""Needs right post mortem traceback with erroring unittest case"""
3296
class Test(unittest.TestCase):
3299
result = self.TracebackRecordingResult()
3301
self.assertEqual(result.postcode, Test.runTest.func_code)
3303
def test_location_unittest_failure(self):
3304
"""Needs right post mortem traceback with failing unittest case"""
3305
class Test(unittest.TestCase):
3307
raise self.failureException
3308
result = self.TracebackRecordingResult()
3310
self.assertEqual(result.postcode, Test.runTest.func_code)
3312
def test_location_bt_error(self):
3313
"""Needs right post mortem traceback with erroring bzrlib.tests case"""
3314
class Test(tests.TestCase):
3315
def test_error(self):
3317
result = self.TracebackRecordingResult()
3318
Test("test_error").run(result)
3319
self.assertEqual(result.postcode, Test.test_error.func_code)
3321
def test_location_bt_failure(self):
3322
"""Needs right post mortem traceback with failing bzrlib.tests case"""
3323
class Test(tests.TestCase):
3324
def test_failure(self):
3325
raise self.failureException
3326
result = self.TracebackRecordingResult()
3327
Test("test_failure").run(result)
3328
self.assertEqual(result.postcode, Test.test_failure.func_code)
3330
def test_env_var_triggers_post_mortem(self):
3331
"""Check pdb.post_mortem is called iff BZR_TEST_PDB is set"""
3333
result = tests.ExtendedTestResult(StringIO(), 0, 1)
3334
post_mortem_calls = []
3335
self.overrideAttr(pdb, "post_mortem", post_mortem_calls.append)
3336
self.overrideEnv('BZR_TEST_PDB', None)
3337
result._post_mortem(1)
3338
self.overrideEnv('BZR_TEST_PDB', 'on')
3339
result._post_mortem(2)
3340
self.assertEqual([2], post_mortem_calls)
2963
3343
class TestRunSuite(tests.TestCase):
2965
3345
def test_runner_class(self):
2976
3356
self.verbosity)
2977
3357
tests.run_suite(suite, runner_class=MyRunner, stream=StringIO())
2978
3358
self.assertLength(1, calls)
3361
class TestEnvironHandling(tests.TestCase):
3363
def test_overrideEnv_None_called_twice_doesnt_leak(self):
3364
self.assertFalse('MYVAR' in os.environ)
3365
self.overrideEnv('MYVAR', '42')
3366
# We use an embedded test to make sure we fix the _captureVar bug
3367
class Test(tests.TestCase):
3369
# The first call save the 42 value
3370
self.overrideEnv('MYVAR', None)
3371
self.assertEquals(None, os.environ.get('MYVAR'))
3372
# Make sure we can call it twice
3373
self.overrideEnv('MYVAR', None)
3374
self.assertEquals(None, os.environ.get('MYVAR'))
3376
result = tests.TextTestResult(output, 0, 1)
3377
Test('test_me').run(result)
3378
if not result.wasStrictlySuccessful():
3379
self.fail(output.getvalue())
3380
# We get our value back
3381
self.assertEquals('42', os.environ.get('MYVAR'))
3384
class TestIsolatedEnv(tests.TestCase):
3385
"""Test isolating tests from os.environ.
3387
Since we use tests that are already isolated from os.environ a bit of care
3388
should be taken when designing the tests to avoid bootstrap side-effects.
3389
The tests start an already clean os.environ which allow doing valid
3390
assertions about which variables are present or not and design tests around
3394
class ScratchMonkey(tests.TestCase):
3399
def test_basics(self):
3400
# Make sure we know the definition of BZR_HOME: not part of os.environ
3401
# for tests.TestCase.
3402
self.assertTrue('BZR_HOME' in tests.isolated_environ)
3403
self.assertEquals(None, tests.isolated_environ['BZR_HOME'])
3404
# Being part of isolated_environ, BZR_HOME should not appear here
3405
self.assertFalse('BZR_HOME' in os.environ)
3406
# Make sure we know the definition of LINES: part of os.environ for
3408
self.assertTrue('LINES' in tests.isolated_environ)
3409
self.assertEquals('25', tests.isolated_environ['LINES'])
3410
self.assertEquals('25', os.environ['LINES'])
3412
def test_injecting_unknown_variable(self):
3413
# BZR_HOME is known to be absent from os.environ
3414
test = self.ScratchMonkey('test_me')
3415
tests.override_os_environ(test, {'BZR_HOME': 'foo'})
3416
self.assertEquals('foo', os.environ['BZR_HOME'])
3417
tests.restore_os_environ(test)
3418
self.assertFalse('BZR_HOME' in os.environ)
3420
def test_injecting_known_variable(self):
3421
test = self.ScratchMonkey('test_me')
3422
# LINES is known to be present in os.environ
3423
tests.override_os_environ(test, {'LINES': '42'})
3424
self.assertEquals('42', os.environ['LINES'])
3425
tests.restore_os_environ(test)
3426
self.assertEquals('25', os.environ['LINES'])
3428
def test_deleting_variable(self):
3429
test = self.ScratchMonkey('test_me')
3430
# LINES is known to be present in os.environ
3431
tests.override_os_environ(test, {'LINES': None})
3432
self.assertTrue('LINES' not in os.environ)
3433
tests.restore_os_environ(test)
3434
self.assertEquals('25', os.environ['LINES'])
3437
class TestDocTestSuiteIsolation(tests.TestCase):
3438
"""Test that `tests.DocTestSuite` isolates doc tests from os.environ.
3440
Since tests.TestCase alreay provides an isolation from os.environ, we use
3441
the clean environment as a base for testing. To precisely capture the
3442
isolation provided by tests.DocTestSuite, we use doctest.DocTestSuite to
3445
We want to make sure `tests.DocTestSuite` respect `tests.isolated_environ`,
3446
not `os.environ` so each test overrides it to suit its needs.
3450
def get_doctest_suite_for_string(self, klass, string):
3451
class Finder(doctest.DocTestFinder):
3453
def find(*args, **kwargs):
3454
test = doctest.DocTestParser().get_doctest(
3455
string, {}, 'foo', 'foo.py', 0)
3458
suite = klass(test_finder=Finder())
3461
def run_doctest_suite_for_string(self, klass, string):
3462
suite = self.get_doctest_suite_for_string(klass, string)
3464
result = tests.TextTestResult(output, 0, 1)
3466
return result, output
3468
def assertDocTestStringSucceds(self, klass, string):
3469
result, output = self.run_doctest_suite_for_string(klass, string)
3470
if not result.wasStrictlySuccessful():
3471
self.fail(output.getvalue())
3473
def assertDocTestStringFails(self, klass, string):
3474
result, output = self.run_doctest_suite_for_string(klass, string)
3475
if result.wasStrictlySuccessful():
3476
self.fail(output.getvalue())
3478
def test_injected_variable(self):
3479
self.overrideAttr(tests, 'isolated_environ', {'LINES': '42'})
3482
>>> os.environ['LINES']
3485
# doctest.DocTestSuite fails as it sees '25'
3486
self.assertDocTestStringFails(doctest.DocTestSuite, test)
3487
# tests.DocTestSuite sees '42'
3488
self.assertDocTestStringSucceds(tests.IsolatedDocTestSuite, test)
3490
def test_deleted_variable(self):
3491
self.overrideAttr(tests, 'isolated_environ', {'LINES': None})
3494
>>> os.environ.get('LINES')
3496
# doctest.DocTestSuite fails as it sees '25'
3497
self.assertDocTestStringFails(doctest.DocTestSuite, test)
3498
# tests.DocTestSuite sees None
3499
self.assertDocTestStringSucceds(tests.IsolatedDocTestSuite, test)