548
571
tree = self.make_branch_and_memory_tree('dir')
549
572
# Guard against regression into MemoryTransport leaking
550
573
# files to disk instead of keeping them in memory.
551
self.failIf(osutils.lexists('dir'))
574
self.assertFalse(osutils.lexists('dir'))
552
575
self.assertIsInstance(tree, memorytree.MemoryTree)
554
577
def test_make_branch_and_memory_tree_with_format(self):
555
578
"""make_branch_and_memory_tree should accept a format option."""
556
579
format = bzrdir.BzrDirMetaFormat1()
557
format.repository_format = weaverepo.RepositoryFormat7()
580
format.repository_format = repository.format_registry.get_default()
558
581
tree = self.make_branch_and_memory_tree('dir', format=format)
559
582
# Guard against regression into MemoryTransport leaking
560
583
# files to disk instead of keeping them in memory.
561
self.failIf(osutils.lexists('dir'))
584
self.assertFalse(osutils.lexists('dir'))
562
585
self.assertIsInstance(tree, memorytree.MemoryTree)
563
586
self.assertEqual(format.repository_format.__class__,
564
587
tree.branch.repository._format.__class__)
568
591
self.assertIsInstance(builder, branchbuilder.BranchBuilder)
569
592
# Guard against regression into MemoryTransport leaking
570
593
# files to disk instead of keeping them in memory.
571
self.failIf(osutils.lexists('dir'))
594
self.assertFalse(osutils.lexists('dir'))
573
596
def test_make_branch_builder_with_format(self):
574
597
# Use a repo layout that doesn't conform to a 'named' layout, to ensure
575
598
# that the format objects are used.
576
599
format = bzrdir.BzrDirMetaFormat1()
577
repo_format = weaverepo.RepositoryFormat7()
600
repo_format = repository.format_registry.get_default()
578
601
format.repository_format = repo_format
579
602
builder = self.make_branch_builder('dir', format=format)
580
603
the_branch = builder.get_branch()
581
604
# Guard against regression into MemoryTransport leaking
582
605
# files to disk instead of keeping them in memory.
583
self.failIf(osutils.lexists('dir'))
606
self.assertFalse(osutils.lexists('dir'))
584
607
self.assertEqual(format.repository_format.__class__,
585
608
the_branch.repository._format.__class__)
586
609
self.assertEqual(repo_format.get_format_string(),
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
self.expectFailure('subunit treats "unexpectedSuccess"'
2199
' as a plain success',
2200
self.assertEqual, 1, len(result.unexpectedSuccesses))
2201
self.assertEqual(1, len(result.unexpectedSuccesses))
2202
test = result.unexpectedSuccesses[0]
2203
# RemotedTestCase doesn't preserve the "details"
2204
## self.assertTrue('log' in test.getDetails())
2206
def test_success_has_no_log(self):
2207
content, result = self.run_subunit_stream('test_success')
2208
self.assertEqual(1, result.testsRun)
2209
self.assertNotContainsRe(content, '(?m)^log$')
2210
self.assertNotContainsRe(content, 'this test succeeds')
1974
2213
class TestRunBzr(tests.TestCase):
2960
3205
self.assertEquals('bzrlib.plugins', tpr.resolve_alias('bp'))
3208
class TestThreadLeakDetection(tests.TestCase):
3209
"""Ensure when tests leak threads we detect and report it"""
3211
class LeakRecordingResult(tests.ExtendedTestResult):
3213
tests.ExtendedTestResult.__init__(self, StringIO(), 0, 1)
3215
def _report_thread_leak(self, test, leaks, alive):
3216
self.leaks.append((test, leaks))
3218
def test_testcase_without_addCleanups(self):
3219
"""Check old TestCase instances don't break with leak detection"""
3220
class Test(unittest.TestCase):
3223
result = self.LeakRecordingResult()
3225
result.startTestRun()
3227
result.stopTestRun()
3228
self.assertEqual(result._tests_leaking_threads_count, 0)
3229
self.assertEqual(result.leaks, [])
3231
def test_thread_leak(self):
3232
"""Ensure a thread that outlives the running of a test is reported
3234
Uses a thread that blocks on an event, and is started by the inner
3235
test case. As the thread outlives the inner case's run, it should be
3236
detected as a leak, but the event is then set so that the thread can
3237
be safely joined in cleanup so it's not leaked for real.
3239
event = threading.Event()
3240
thread = threading.Thread(name="Leaker", target=event.wait)
3241
class Test(tests.TestCase):
3242
def test_leak(self):
3244
result = self.LeakRecordingResult()
3245
test = Test("test_leak")
3246
self.addCleanup(thread.join)
3247
self.addCleanup(event.set)
3248
result.startTestRun()
3250
result.stopTestRun()
3251
self.assertEqual(result._tests_leaking_threads_count, 1)
3252
self.assertEqual(result._first_thread_leaker_id, test.id())
3253
self.assertEqual(result.leaks, [(test, set([thread]))])
3254
self.assertContainsString(result.stream.getvalue(), "leaking threads")
3256
def test_multiple_leaks(self):
3257
"""Check multiple leaks are blamed on the test cases at fault
3259
Same concept as the previous test, but has one inner test method that
3260
leaks two threads, and one that doesn't leak at all.
3262
event = threading.Event()
3263
thread_a = threading.Thread(name="LeakerA", target=event.wait)
3264
thread_b = threading.Thread(name="LeakerB", target=event.wait)
3265
thread_c = threading.Thread(name="LeakerC", target=event.wait)
3266
class Test(tests.TestCase):
3267
def test_first_leak(self):
3269
def test_second_no_leak(self):
3271
def test_third_leak(self):
3274
result = self.LeakRecordingResult()
3275
first_test = Test("test_first_leak")
3276
third_test = Test("test_third_leak")
3277
self.addCleanup(thread_a.join)
3278
self.addCleanup(thread_b.join)
3279
self.addCleanup(thread_c.join)
3280
self.addCleanup(event.set)
3281
result.startTestRun()
3283
[first_test, Test("test_second_no_leak"), third_test]
3285
result.stopTestRun()
3286
self.assertEqual(result._tests_leaking_threads_count, 2)
3287
self.assertEqual(result._first_thread_leaker_id, first_test.id())
3288
self.assertEqual(result.leaks, [
3289
(first_test, set([thread_b])),
3290
(third_test, set([thread_a, thread_c]))])
3291
self.assertContainsString(result.stream.getvalue(), "leaking threads")
3294
class TestPostMortemDebugging(tests.TestCase):
3295
"""Check post mortem debugging works when tests fail or error"""
3297
class TracebackRecordingResult(tests.ExtendedTestResult):
3299
tests.ExtendedTestResult.__init__(self, StringIO(), 0, 1)
3300
self.postcode = None
3301
def _post_mortem(self, tb=None):
3302
"""Record the code object at the end of the current traceback"""
3303
tb = tb or sys.exc_info()[2]
3306
while next is not None:
3309
self.postcode = tb.tb_frame.f_code
3310
def report_error(self, test, err):
3312
def report_failure(self, test, err):
3315
def test_location_unittest_error(self):
3316
"""Needs right post mortem traceback with erroring unittest case"""
3317
class Test(unittest.TestCase):
3320
result = self.TracebackRecordingResult()
3322
self.assertEqual(result.postcode, Test.runTest.func_code)
3324
def test_location_unittest_failure(self):
3325
"""Needs right post mortem traceback with failing unittest case"""
3326
class Test(unittest.TestCase):
3328
raise self.failureException
3329
result = self.TracebackRecordingResult()
3331
self.assertEqual(result.postcode, Test.runTest.func_code)
3333
def test_location_bt_error(self):
3334
"""Needs right post mortem traceback with erroring bzrlib.tests case"""
3335
class Test(tests.TestCase):
3336
def test_error(self):
3338
result = self.TracebackRecordingResult()
3339
Test("test_error").run(result)
3340
self.assertEqual(result.postcode, Test.test_error.func_code)
3342
def test_location_bt_failure(self):
3343
"""Needs right post mortem traceback with failing bzrlib.tests case"""
3344
class Test(tests.TestCase):
3345
def test_failure(self):
3346
raise self.failureException
3347
result = self.TracebackRecordingResult()
3348
Test("test_failure").run(result)
3349
self.assertEqual(result.postcode, Test.test_failure.func_code)
3351
def test_env_var_triggers_post_mortem(self):
3352
"""Check pdb.post_mortem is called iff BZR_TEST_PDB is set"""
3354
result = tests.ExtendedTestResult(StringIO(), 0, 1)
3355
post_mortem_calls = []
3356
self.overrideAttr(pdb, "post_mortem", post_mortem_calls.append)
3357
self.overrideEnv('BZR_TEST_PDB', None)
3358
result._post_mortem(1)
3359
self.overrideEnv('BZR_TEST_PDB', 'on')
3360
result._post_mortem(2)
3361
self.assertEqual([2], post_mortem_calls)
2963
3364
class TestRunSuite(tests.TestCase):
2965
3366
def test_runner_class(self):
2976
3377
self.verbosity)
2977
3378
tests.run_suite(suite, runner_class=MyRunner, stream=StringIO())
2978
3379
self.assertLength(1, calls)
3382
class TestEnvironHandling(tests.TestCase):
3384
def test_overrideEnv_None_called_twice_doesnt_leak(self):
3385
self.assertFalse('MYVAR' in os.environ)
3386
self.overrideEnv('MYVAR', '42')
3387
# We use an embedded test to make sure we fix the _captureVar bug
3388
class Test(tests.TestCase):
3390
# The first call save the 42 value
3391
self.overrideEnv('MYVAR', None)
3392
self.assertEquals(None, os.environ.get('MYVAR'))
3393
# Make sure we can call it twice
3394
self.overrideEnv('MYVAR', None)
3395
self.assertEquals(None, os.environ.get('MYVAR'))
3397
result = tests.TextTestResult(output, 0, 1)
3398
Test('test_me').run(result)
3399
if not result.wasStrictlySuccessful():
3400
self.fail(output.getvalue())
3401
# We get our value back
3402
self.assertEquals('42', os.environ.get('MYVAR'))
3405
class TestIsolatedEnv(tests.TestCase):
3406
"""Test isolating tests from os.environ.
3408
Since we use tests that are already isolated from os.environ a bit of care
3409
should be taken when designing the tests to avoid bootstrap side-effects.
3410
The tests start an already clean os.environ which allow doing valid
3411
assertions about which variables are present or not and design tests around
3415
class ScratchMonkey(tests.TestCase):
3420
def test_basics(self):
3421
# Make sure we know the definition of BZR_HOME: not part of os.environ
3422
# for tests.TestCase.
3423
self.assertTrue('BZR_HOME' in tests.isolated_environ)
3424
self.assertEquals(None, tests.isolated_environ['BZR_HOME'])
3425
# Being part of isolated_environ, BZR_HOME should not appear here
3426
self.assertFalse('BZR_HOME' in os.environ)
3427
# Make sure we know the definition of LINES: part of os.environ for
3429
self.assertTrue('LINES' in tests.isolated_environ)
3430
self.assertEquals('25', tests.isolated_environ['LINES'])
3431
self.assertEquals('25', os.environ['LINES'])
3433
def test_injecting_unknown_variable(self):
3434
# BZR_HOME is known to be absent from os.environ
3435
test = self.ScratchMonkey('test_me')
3436
tests.override_os_environ(test, {'BZR_HOME': 'foo'})
3437
self.assertEquals('foo', os.environ['BZR_HOME'])
3438
tests.restore_os_environ(test)
3439
self.assertFalse('BZR_HOME' in os.environ)
3441
def test_injecting_known_variable(self):
3442
test = self.ScratchMonkey('test_me')
3443
# LINES is known to be present in os.environ
3444
tests.override_os_environ(test, {'LINES': '42'})
3445
self.assertEquals('42', os.environ['LINES'])
3446
tests.restore_os_environ(test)
3447
self.assertEquals('25', os.environ['LINES'])
3449
def test_deleting_variable(self):
3450
test = self.ScratchMonkey('test_me')
3451
# LINES is known to be present in os.environ
3452
tests.override_os_environ(test, {'LINES': None})
3453
self.assertTrue('LINES' not in os.environ)
3454
tests.restore_os_environ(test)
3455
self.assertEquals('25', os.environ['LINES'])
3458
class TestDocTestSuiteIsolation(tests.TestCase):
3459
"""Test that `tests.DocTestSuite` isolates doc tests from os.environ.
3461
Since tests.TestCase alreay provides an isolation from os.environ, we use
3462
the clean environment as a base for testing. To precisely capture the
3463
isolation provided by tests.DocTestSuite, we use doctest.DocTestSuite to
3466
We want to make sure `tests.DocTestSuite` respect `tests.isolated_environ`,
3467
not `os.environ` so each test overrides it to suit its needs.
3471
def get_doctest_suite_for_string(self, klass, string):
3472
class Finder(doctest.DocTestFinder):
3474
def find(*args, **kwargs):
3475
test = doctest.DocTestParser().get_doctest(
3476
string, {}, 'foo', 'foo.py', 0)
3479
suite = klass(test_finder=Finder())
3482
def run_doctest_suite_for_string(self, klass, string):
3483
suite = self.get_doctest_suite_for_string(klass, string)
3485
result = tests.TextTestResult(output, 0, 1)
3487
return result, output
3489
def assertDocTestStringSucceds(self, klass, string):
3490
result, output = self.run_doctest_suite_for_string(klass, string)
3491
if not result.wasStrictlySuccessful():
3492
self.fail(output.getvalue())
3494
def assertDocTestStringFails(self, klass, string):
3495
result, output = self.run_doctest_suite_for_string(klass, string)
3496
if result.wasStrictlySuccessful():
3497
self.fail(output.getvalue())
3499
def test_injected_variable(self):
3500
self.overrideAttr(tests, 'isolated_environ', {'LINES': '42'})
3503
>>> os.environ['LINES']
3506
# doctest.DocTestSuite fails as it sees '25'
3507
self.assertDocTestStringFails(doctest.DocTestSuite, test)
3508
# tests.DocTestSuite sees '42'
3509
self.assertDocTestStringSucceds(tests.IsolatedDocTestSuite, test)
3511
def test_deleted_variable(self):
3512
self.overrideAttr(tests, 'isolated_environ', {'LINES': None})
3515
>>> os.environ.get('LINES')
3517
# doctest.DocTestSuite fails as it sees '25'
3518
self.assertDocTestStringFails(doctest.DocTestSuite, test)
3519
# tests.DocTestSuite sees None
3520
self.assertDocTestStringSucceds(tests.IsolatedDocTestSuite, test)