548
570
tree = self.make_branch_and_memory_tree('dir')
549
571
# Guard against regression into MemoryTransport leaking
550
572
# files to disk instead of keeping them in memory.
551
self.failIf(osutils.lexists('dir'))
573
self.assertFalse(osutils.lexists('dir'))
552
574
self.assertIsInstance(tree, memorytree.MemoryTree)
554
576
def test_make_branch_and_memory_tree_with_format(self):
555
577
"""make_branch_and_memory_tree should accept a format option."""
556
578
format = bzrdir.BzrDirMetaFormat1()
557
format.repository_format = weaverepo.RepositoryFormat7()
579
format.repository_format = repository.format_registry.get_default()
558
580
tree = self.make_branch_and_memory_tree('dir', format=format)
559
581
# Guard against regression into MemoryTransport leaking
560
582
# files to disk instead of keeping them in memory.
561
self.failIf(osutils.lexists('dir'))
583
self.assertFalse(osutils.lexists('dir'))
562
584
self.assertIsInstance(tree, memorytree.MemoryTree)
563
585
self.assertEqual(format.repository_format.__class__,
564
586
tree.branch.repository._format.__class__)
568
590
self.assertIsInstance(builder, branchbuilder.BranchBuilder)
569
591
# Guard against regression into MemoryTransport leaking
570
592
# files to disk instead of keeping them in memory.
571
self.failIf(osutils.lexists('dir'))
593
self.assertFalse(osutils.lexists('dir'))
573
595
def test_make_branch_builder_with_format(self):
574
596
# Use a repo layout that doesn't conform to a 'named' layout, to ensure
575
597
# that the format objects are used.
576
598
format = bzrdir.BzrDirMetaFormat1()
577
repo_format = weaverepo.RepositoryFormat7()
599
repo_format = repository.format_registry.get_default()
578
600
format.repository_format = repo_format
579
601
builder = self.make_branch_builder('dir', format=format)
580
602
the_branch = builder.get_branch()
581
603
# Guard against regression into MemoryTransport leaking
582
604
# files to disk instead of keeping them in memory.
583
self.failIf(osutils.lexists('dir'))
605
self.assertFalse(osutils.lexists('dir'))
584
606
self.assertEqual(format.repository_format.__class__,
585
607
the_branch.repository._format.__class__)
586
608
self.assertEqual(repo_format.get_format_string(),
750
770
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
773
def _time_hello_world_encoding(self):
794
774
"""Profile two sleep calls
835
815
self.assertContainsRe(output,
836
816
r"LSProf output for <type 'unicode'>\(\('world',\), {'errors': 'replace'}\)\n")
818
def test_uses_time_from_testtools(self):
819
"""Test case timings in verbose results should use testtools times"""
821
class TimeAddedVerboseTestResult(tests.VerboseTestResult):
822
def startTest(self, test):
823
self.time(datetime.datetime.utcfromtimestamp(1.145))
824
super(TimeAddedVerboseTestResult, self).startTest(test)
825
def addSuccess(self, test):
826
self.time(datetime.datetime.utcfromtimestamp(51.147))
827
super(TimeAddedVerboseTestResult, self).addSuccess(test)
828
def report_tests_starting(self): pass
830
self.get_passing_test().run(TimeAddedVerboseTestResult(sio, 0, 2))
831
self.assertEndsWith(sio.getvalue(), "OK 50002ms\n")
838
833
def test_known_failure(self):
839
834
"""A KnownFailure being raised should trigger several result actions."""
840
835
class InstrumentedTestResult(tests.ExtendedTestResult):
841
836
def stopTestRun(self): pass
842
def startTests(self): pass
843
def report_test_start(self, test): pass
837
def report_tests_starting(self): pass
844
838
def report_known_failure(self, test, err=None, details=None):
845
839
self._call = test, 'known failure'
846
840
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)
1197
def test_verbose_test_count(self):
1198
"""A verbose test run reports the right test count at the start"""
1199
suite = TestUtil.TestSuite([
1200
unittest.FunctionTestCase(lambda:None),
1201
unittest.FunctionTestCase(lambda:None)])
1202
self.assertEqual(suite.countTestCases(), 2)
1204
runner = tests.TextTestRunner(stream=stream, verbosity=2)
1205
# Need to use the CountingDecorator as that's what sets num_tests
1206
result = self.run_test_runner(runner, tests.CountingDecorator(suite))
1207
self.assertStartsWith(stream.getvalue(), "running 2 tests")
1216
1209
def test_startTestRun(self):
1217
1210
"""run should call result.startTestRun()"""
1219
class LoggingDecorator(tests.ForwardingResult):
1212
class LoggingDecorator(ExtendedToOriginalDecorator):
1220
1213
def startTestRun(self):
1221
tests.ForwardingResult.startTestRun(self)
1214
ExtendedToOriginalDecorator.startTestRun(self)
1222
1215
calls.append('startTestRun')
1223
1216
test = unittest.FunctionTestCase(lambda:None)
1224
1217
stream = StringIO()
1655
1665
self.assertEqual('original', obj.test_attr)
1668
class _MissingFeature(tests.Feature):
1671
missing_feature = _MissingFeature()
1674
def _get_test(name):
1675
"""Get an instance of a specific example test.
1677
We protect this in a function so that they don't auto-run in the test
1681
class ExampleTests(tests.TestCase):
1683
def test_fail(self):
1684
mutter('this was a failing test')
1685
self.fail('this test will fail')
1687
def test_error(self):
1688
mutter('this test errored')
1689
raise RuntimeError('gotcha')
1691
def test_missing_feature(self):
1692
mutter('missing the feature')
1693
self.requireFeature(missing_feature)
1695
def test_skip(self):
1696
mutter('this test will be skipped')
1697
raise tests.TestSkipped('reason')
1699
def test_success(self):
1700
mutter('this test succeeds')
1702
def test_xfail(self):
1703
mutter('test with expected failure')
1704
self.knownFailure('this_fails')
1706
def test_unexpected_success(self):
1707
mutter('test with unexpected success')
1708
self.expectFailure('should_fail', lambda: None)
1710
return ExampleTests(name)
1713
class TestTestCaseLogDetails(tests.TestCase):
1715
def _run_test(self, test_name):
1716
test = _get_test(test_name)
1717
result = testtools.TestResult()
1721
def test_fail_has_log(self):
1722
result = self._run_test('test_fail')
1723
self.assertEqual(1, len(result.failures))
1724
result_content = result.failures[0][1]
1725
self.assertContainsRe(result_content, 'Text attachment: log')
1726
self.assertContainsRe(result_content, 'this was a failing test')
1728
def test_error_has_log(self):
1729
result = self._run_test('test_error')
1730
self.assertEqual(1, len(result.errors))
1731
result_content = result.errors[0][1]
1732
self.assertContainsRe(result_content, 'Text attachment: log')
1733
self.assertContainsRe(result_content, 'this test errored')
1735
def test_skip_has_no_log(self):
1736
result = self._run_test('test_skip')
1737
self.assertEqual(['reason'], result.skip_reasons.keys())
1738
skips = result.skip_reasons['reason']
1739
self.assertEqual(1, len(skips))
1741
self.assertFalse('log' in test.getDetails())
1743
def test_missing_feature_has_no_log(self):
1744
# testtools doesn't know about addNotSupported, so it just gets
1745
# considered as a skip
1746
result = self._run_test('test_missing_feature')
1747
self.assertEqual([missing_feature], result.skip_reasons.keys())
1748
skips = result.skip_reasons[missing_feature]
1749
self.assertEqual(1, len(skips))
1751
self.assertFalse('log' in test.getDetails())
1753
def test_xfail_has_no_log(self):
1754
result = self._run_test('test_xfail')
1755
self.assertEqual(1, len(result.expectedFailures))
1756
result_content = result.expectedFailures[0][1]
1757
self.assertNotContainsRe(result_content, 'Text attachment: log')
1758
self.assertNotContainsRe(result_content, 'test with expected failure')
1760
def test_unexpected_success_has_log(self):
1761
result = self._run_test('test_unexpected_success')
1762
self.assertEqual(1, len(result.unexpectedSuccesses))
1763
# Inconsistency, unexpectedSuccesses is a list of tests,
1764
# expectedFailures is a list of reasons?
1765
test = result.unexpectedSuccesses[0]
1766
details = test.getDetails()
1767
self.assertTrue('log' in details)
1770
class TestTestCloning(tests.TestCase):
1771
"""Tests that test cloning of TestCases (as used by multiply_tests)."""
1773
def test_cloned_testcase_does_not_share_details(self):
1774
"""A TestCase cloned with clone_test does not share mutable attributes
1775
such as details or cleanups.
1777
class Test(tests.TestCase):
1779
self.addDetail('foo', Content('text/plain', lambda: 'foo'))
1780
orig_test = Test('test_foo')
1781
cloned_test = tests.clone_test(orig_test, orig_test.id() + '(cloned)')
1782
orig_test.run(unittest.TestResult())
1783
self.assertEqual('foo', orig_test.getDetails()['foo'].iter_bytes())
1784
self.assertEqual(None, cloned_test.getDetails().get('foo'))
1786
def test_double_apply_scenario_preserves_first_scenario(self):
1787
"""Applying two levels of scenarios to a test preserves the attributes
1788
added by both scenarios.
1790
class Test(tests.TestCase):
1793
test = Test('test_foo')
1794
scenarios_x = [('x=1', {'x': 1}), ('x=2', {'x': 2})]
1795
scenarios_y = [('y=1', {'y': 1}), ('y=2', {'y': 2})]
1796
suite = tests.multiply_tests(test, scenarios_x, unittest.TestSuite())
1797
suite = tests.multiply_tests(suite, scenarios_y, unittest.TestSuite())
1798
all_tests = list(tests.iter_suite_tests(suite))
1799
self.assertLength(4, all_tests)
1800
all_xys = sorted((t.x, t.y) for t in all_tests)
1801
self.assertEqual([(1, 1), (1, 2), (2, 1), (2, 2)], all_xys)
1658
1804
# NB: Don't delete this; it's not actually from 0.11!
1659
1805
@deprecated_function(deprecated_in((0, 11, 0)))
1660
1806
def sample_deprecated_function():
1971
2114
load_list='missing file name', list_only=True)
2117
class TestSubunitLogDetails(tests.TestCase, SelfTestHelper):
2119
_test_needs_features = [features.subunit]
2121
def run_subunit_stream(self, test_name):
2122
from subunit import ProtocolTestCase
2124
return TestUtil.TestSuite([_get_test(test_name)])
2125
stream = self.run_selftest(runner_class=tests.SubUnitBzrRunner,
2126
test_suite_factory=factory)
2127
test = ProtocolTestCase(stream)
2128
result = testtools.TestResult()
2130
content = stream.getvalue()
2131
return content, result
2133
def test_fail_has_log(self):
2134
content, result = self.run_subunit_stream('test_fail')
2135
self.assertEqual(1, len(result.failures))
2136
self.assertContainsRe(content, '(?m)^log$')
2137
self.assertContainsRe(content, 'this test will fail')
2139
def test_error_has_log(self):
2140
content, result = self.run_subunit_stream('test_error')
2141
self.assertContainsRe(content, '(?m)^log$')
2142
self.assertContainsRe(content, 'this test errored')
2144
def test_skip_has_no_log(self):
2145
content, result = self.run_subunit_stream('test_skip')
2146
self.assertNotContainsRe(content, '(?m)^log$')
2147
self.assertNotContainsRe(content, 'this test will be skipped')
2148
self.assertEqual(['reason'], result.skip_reasons.keys())
2149
skips = result.skip_reasons['reason']
2150
self.assertEqual(1, len(skips))
2152
# RemotedTestCase doesn't preserve the "details"
2153
## self.assertFalse('log' in test.getDetails())
2155
def test_missing_feature_has_no_log(self):
2156
content, result = self.run_subunit_stream('test_missing_feature')
2157
self.assertNotContainsRe(content, '(?m)^log$')
2158
self.assertNotContainsRe(content, 'missing the feature')
2159
self.assertEqual(['_MissingFeature\n'], result.skip_reasons.keys())
2160
skips = result.skip_reasons['_MissingFeature\n']
2161
self.assertEqual(1, len(skips))
2163
# RemotedTestCase doesn't preserve the "details"
2164
## self.assertFalse('log' in test.getDetails())
2166
def test_xfail_has_no_log(self):
2167
content, result = self.run_subunit_stream('test_xfail')
2168
self.assertNotContainsRe(content, '(?m)^log$')
2169
self.assertNotContainsRe(content, 'test with expected failure')
2170
self.assertEqual(1, len(result.expectedFailures))
2171
result_content = result.expectedFailures[0][1]
2172
self.assertNotContainsRe(result_content, 'Text attachment: log')
2173
self.assertNotContainsRe(result_content, 'test with expected failure')
2175
def test_unexpected_success_has_log(self):
2176
content, result = self.run_subunit_stream('test_unexpected_success')
2177
self.assertContainsRe(content, '(?m)^log$')
2178
self.assertContainsRe(content, 'test with unexpected success')
2179
self.expectFailure('subunit treats "unexpectedSuccess"'
2180
' as a plain success',
2181
self.assertEqual, 1, len(result.unexpectedSuccesses))
2182
self.assertEqual(1, len(result.unexpectedSuccesses))
2183
test = result.unexpectedSuccesses[0]
2184
# RemotedTestCase doesn't preserve the "details"
2185
## self.assertTrue('log' in test.getDetails())
2187
def test_success_has_no_log(self):
2188
content, result = self.run_subunit_stream('test_success')
2189
self.assertEqual(1, result.testsRun)
2190
self.assertNotContainsRe(content, '(?m)^log$')
2191
self.assertNotContainsRe(content, 'this test succeeds')
1974
2194
class TestRunBzr(tests.TestCase):
2960
3186
self.assertEquals('bzrlib.plugins', tpr.resolve_alias('bp'))
3189
class TestThreadLeakDetection(tests.TestCase):
3190
"""Ensure when tests leak threads we detect and report it"""
3192
class LeakRecordingResult(tests.ExtendedTestResult):
3194
tests.ExtendedTestResult.__init__(self, StringIO(), 0, 1)
3196
def _report_thread_leak(self, test, leaks, alive):
3197
self.leaks.append((test, leaks))
3199
def test_testcase_without_addCleanups(self):
3200
"""Check old TestCase instances don't break with leak detection"""
3201
class Test(unittest.TestCase):
3204
result = self.LeakRecordingResult()
3206
result.startTestRun()
3208
result.stopTestRun()
3209
self.assertEqual(result._tests_leaking_threads_count, 0)
3210
self.assertEqual(result.leaks, [])
3212
def test_thread_leak(self):
3213
"""Ensure a thread that outlives the running of a test is reported
3215
Uses a thread that blocks on an event, and is started by the inner
3216
test case. As the thread outlives the inner case's run, it should be
3217
detected as a leak, but the event is then set so that the thread can
3218
be safely joined in cleanup so it's not leaked for real.
3220
event = threading.Event()
3221
thread = threading.Thread(name="Leaker", target=event.wait)
3222
class Test(tests.TestCase):
3223
def test_leak(self):
3225
result = self.LeakRecordingResult()
3226
test = Test("test_leak")
3227
self.addCleanup(thread.join)
3228
self.addCleanup(event.set)
3229
result.startTestRun()
3231
result.stopTestRun()
3232
self.assertEqual(result._tests_leaking_threads_count, 1)
3233
self.assertEqual(result._first_thread_leaker_id, test.id())
3234
self.assertEqual(result.leaks, [(test, set([thread]))])
3235
self.assertContainsString(result.stream.getvalue(), "leaking threads")
3237
def test_multiple_leaks(self):
3238
"""Check multiple leaks are blamed on the test cases at fault
3240
Same concept as the previous test, but has one inner test method that
3241
leaks two threads, and one that doesn't leak at all.
3243
event = threading.Event()
3244
thread_a = threading.Thread(name="LeakerA", target=event.wait)
3245
thread_b = threading.Thread(name="LeakerB", target=event.wait)
3246
thread_c = threading.Thread(name="LeakerC", target=event.wait)
3247
class Test(tests.TestCase):
3248
def test_first_leak(self):
3250
def test_second_no_leak(self):
3252
def test_third_leak(self):
3255
result = self.LeakRecordingResult()
3256
first_test = Test("test_first_leak")
3257
third_test = Test("test_third_leak")
3258
self.addCleanup(thread_a.join)
3259
self.addCleanup(thread_b.join)
3260
self.addCleanup(thread_c.join)
3261
self.addCleanup(event.set)
3262
result.startTestRun()
3264
[first_test, Test("test_second_no_leak"), third_test]
3266
result.stopTestRun()
3267
self.assertEqual(result._tests_leaking_threads_count, 2)
3268
self.assertEqual(result._first_thread_leaker_id, first_test.id())
3269
self.assertEqual(result.leaks, [
3270
(first_test, set([thread_b])),
3271
(third_test, set([thread_a, thread_c]))])
3272
self.assertContainsString(result.stream.getvalue(), "leaking threads")
3275
class TestPostMortemDebugging(tests.TestCase):
3276
"""Check post mortem debugging works when tests fail or error"""
3278
class TracebackRecordingResult(tests.ExtendedTestResult):
3280
tests.ExtendedTestResult.__init__(self, StringIO(), 0, 1)
3281
self.postcode = None
3282
def _post_mortem(self, tb=None):
3283
"""Record the code object at the end of the current traceback"""
3284
tb = tb or sys.exc_info()[2]
3287
while next is not None:
3290
self.postcode = tb.tb_frame.f_code
3291
def report_error(self, test, err):
3293
def report_failure(self, test, err):
3296
def test_location_unittest_error(self):
3297
"""Needs right post mortem traceback with erroring unittest case"""
3298
class Test(unittest.TestCase):
3301
result = self.TracebackRecordingResult()
3303
self.assertEqual(result.postcode, Test.runTest.func_code)
3305
def test_location_unittest_failure(self):
3306
"""Needs right post mortem traceback with failing unittest case"""
3307
class Test(unittest.TestCase):
3309
raise self.failureException
3310
result = self.TracebackRecordingResult()
3312
self.assertEqual(result.postcode, Test.runTest.func_code)
3314
def test_location_bt_error(self):
3315
"""Needs right post mortem traceback with erroring bzrlib.tests case"""
3316
class Test(tests.TestCase):
3317
def test_error(self):
3319
result = self.TracebackRecordingResult()
3320
Test("test_error").run(result)
3321
self.assertEqual(result.postcode, Test.test_error.func_code)
3323
def test_location_bt_failure(self):
3324
"""Needs right post mortem traceback with failing bzrlib.tests case"""
3325
class Test(tests.TestCase):
3326
def test_failure(self):
3327
raise self.failureException
3328
result = self.TracebackRecordingResult()
3329
Test("test_failure").run(result)
3330
self.assertEqual(result.postcode, Test.test_failure.func_code)
3332
def test_env_var_triggers_post_mortem(self):
3333
"""Check pdb.post_mortem is called iff BZR_TEST_PDB is set"""
3335
result = tests.ExtendedTestResult(StringIO(), 0, 1)
3336
post_mortem_calls = []
3337
self.overrideAttr(pdb, "post_mortem", post_mortem_calls.append)
3338
self.overrideEnv('BZR_TEST_PDB', None)
3339
result._post_mortem(1)
3340
self.overrideEnv('BZR_TEST_PDB', 'on')
3341
result._post_mortem(2)
3342
self.assertEqual([2], post_mortem_calls)
2963
3345
class TestRunSuite(tests.TestCase):
2965
3347
def test_runner_class(self):
2976
3358
self.verbosity)
2977
3359
tests.run_suite(suite, runner_class=MyRunner, stream=StringIO())
2978
3360
self.assertLength(1, calls)
3363
class TestEnvironHandling(tests.TestCase):
3365
def test_overrideEnv_None_called_twice_doesnt_leak(self):
3366
self.assertFalse('MYVAR' in os.environ)
3367
self.overrideEnv('MYVAR', '42')
3368
# We use an embedded test to make sure we fix the _captureVar bug
3369
class Test(tests.TestCase):
3371
# The first call save the 42 value
3372
self.overrideEnv('MYVAR', None)
3373
self.assertEquals(None, os.environ.get('MYVAR'))
3374
# Make sure we can call it twice
3375
self.overrideEnv('MYVAR', None)
3376
self.assertEquals(None, os.environ.get('MYVAR'))
3378
result = tests.TextTestResult(output, 0, 1)
3379
Test('test_me').run(result)
3380
if not result.wasStrictlySuccessful():
3381
self.fail(output.getvalue())
3382
# We get our value back
3383
self.assertEquals('42', os.environ.get('MYVAR'))
3386
class TestIsolatedEnv(tests.TestCase):
3387
"""Test isolating tests from os.environ.
3389
Since we use tests that are already isolated from os.environ a bit of care
3390
should be taken when designing the tests to avoid bootstrap side-effects.
3391
The tests start an already clean os.environ which allow doing valid
3392
assertions about which variables are present or not and design tests around
3396
class ScratchMonkey(tests.TestCase):
3401
def test_basics(self):
3402
# Make sure we know the definition of BZR_HOME: not part of os.environ
3403
# for tests.TestCase.
3404
self.assertTrue('BZR_HOME' in tests.isolated_environ)
3405
self.assertEquals(None, tests.isolated_environ['BZR_HOME'])
3406
# Being part of isolated_environ, BZR_HOME should not appear here
3407
self.assertFalse('BZR_HOME' in os.environ)
3408
# Make sure we know the definition of LINES: part of os.environ for
3410
self.assertTrue('LINES' in tests.isolated_environ)
3411
self.assertEquals('25', tests.isolated_environ['LINES'])
3412
self.assertEquals('25', os.environ['LINES'])
3414
def test_injecting_unknown_variable(self):
3415
# BZR_HOME is known to be absent from os.environ
3416
test = self.ScratchMonkey('test_me')
3417
tests.override_os_environ(test, {'BZR_HOME': 'foo'})
3418
self.assertEquals('foo', os.environ['BZR_HOME'])
3419
tests.restore_os_environ(test)
3420
self.assertFalse('BZR_HOME' in os.environ)
3422
def test_injecting_known_variable(self):
3423
test = self.ScratchMonkey('test_me')
3424
# LINES is known to be present in os.environ
3425
tests.override_os_environ(test, {'LINES': '42'})
3426
self.assertEquals('42', os.environ['LINES'])
3427
tests.restore_os_environ(test)
3428
self.assertEquals('25', os.environ['LINES'])
3430
def test_deleting_variable(self):
3431
test = self.ScratchMonkey('test_me')
3432
# LINES is known to be present in os.environ
3433
tests.override_os_environ(test, {'LINES': None})
3434
self.assertTrue('LINES' not in os.environ)
3435
tests.restore_os_environ(test)
3436
self.assertEquals('25', os.environ['LINES'])
3439
class TestDocTestSuiteIsolation(tests.TestCase):
3440
"""Test that `tests.DocTestSuite` isolates doc tests from os.environ.
3442
Since tests.TestCase alreay provides an isolation from os.environ, we use
3443
the clean environment as a base for testing. To precisely capture the
3444
isolation provided by tests.DocTestSuite, we use doctest.DocTestSuite to
3447
We want to make sure `tests.DocTestSuite` respect `tests.isolated_environ`,
3448
not `os.environ` so each test overrides it to suit its needs.
3452
def get_doctest_suite_for_string(self, klass, string):
3453
class Finder(doctest.DocTestFinder):
3455
def find(*args, **kwargs):
3456
test = doctest.DocTestParser().get_doctest(
3457
string, {}, 'foo', 'foo.py', 0)
3460
suite = klass(test_finder=Finder())
3463
def run_doctest_suite_for_string(self, klass, string):
3464
suite = self.get_doctest_suite_for_string(klass, string)
3466
result = tests.TextTestResult(output, 0, 1)
3468
return result, output
3470
def assertDocTestStringSucceds(self, klass, string):
3471
result, output = self.run_doctest_suite_for_string(klass, string)
3472
if not result.wasStrictlySuccessful():
3473
self.fail(output.getvalue())
3475
def assertDocTestStringFails(self, klass, string):
3476
result, output = self.run_doctest_suite_for_string(klass, string)
3477
if result.wasStrictlySuccessful():
3478
self.fail(output.getvalue())
3480
def test_injected_variable(self):
3481
self.overrideAttr(tests, 'isolated_environ', {'LINES': '42'})
3484
>>> os.environ['LINES']
3487
# doctest.DocTestSuite fails as it sees '25'
3488
self.assertDocTestStringFails(doctest.DocTestSuite, test)
3489
# tests.DocTestSuite sees '42'
3490
self.assertDocTestStringSucceds(tests.IsolatedDocTestSuite, test)
3492
def test_deleted_variable(self):
3493
self.overrideAttr(tests, 'isolated_environ', {'LINES': None})
3496
>>> os.environ.get('LINES')
3498
# doctest.DocTestSuite fails as it sees '25'
3499
self.assertDocTestStringFails(doctest.DocTestSuite, test)
3500
# tests.DocTestSuite sees None
3501
self.assertDocTestStringSucceds(tests.IsolatedDocTestSuite, test)