~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_selftest.py

  • Committer: John Arbash Meinel
  • Date: 2011-08-30 10:54:28 UTC
  • mfrom: (5609.48.9 2.3)
  • mto: (6015.28.2 2.4)
  • mto: This revision was merged to the branch mainline in revision 6124.
  • Revision ID: john@arbash-meinel.com-20110830105428-3xu4hkvizhfj5k11
Merge 2.3 into 2.4, and fix up the conflict for resolving bug #835035

Show diffs side-by-side

added added

removed removed

Lines of Context:
17
17
"""Tests for the test framework."""
18
18
 
19
19
from cStringIO import StringIO
20
 
import gc
21
20
import doctest
22
21
import os
23
22
import signal
30
29
from testtools import (
31
30
    ExtendedToOriginalDecorator,
32
31
    MultiTestResult,
33
 
    __version__ as testtools_version,
34
32
    )
35
33
from testtools.content import Content
36
34
from testtools.content_type import ContentType
95
93
            DocTestMatches(u"...a test message\n", doctest.ELLIPSIS))
96
94
 
97
95
 
 
96
class TestUnicodeFilename(tests.TestCase):
 
97
 
 
98
    def test_probe_passes(self):
 
99
        """UnicodeFilename._probe passes."""
 
100
        # We can't test much more than that because the behaviour depends
 
101
        # on the platform.
 
102
        tests.UnicodeFilename._probe()
 
103
 
 
104
 
98
105
class TestTreeShape(tests.TestCaseInTempDir):
99
106
 
100
107
    def test_unicode_paths(self):
101
 
        self.requireFeature(features.UnicodeFilenameFeature)
 
108
        self.requireFeature(tests.UnicodeFilename)
102
109
 
103
110
        filename = u'hell\u00d8'
104
111
        self.build_tree_contents([(filename, 'contents of hello')])
620
627
    def test_dangling_locks_cause_failures(self):
621
628
        class TestDanglingLock(tests.TestCaseWithMemoryTransport):
622
629
            def test_function(self):
623
 
                t = self.get_transport_from_path('.')
 
630
                t = self.get_transport('.')
624
631
                l = lockdir.LockDir(t, 'lock')
625
632
                l.create()
626
633
                l.attempt_lock()
646
653
        # for the server
647
654
        url = self.get_readonly_url()
648
655
        url2 = self.get_readonly_url('foo/bar')
649
 
        t = transport.get_transport_from_url(url)
650
 
        t2 = transport.get_transport_from_url(url2)
 
656
        t = transport.get_transport(url)
 
657
        t2 = transport.get_transport(url2)
651
658
        self.assertIsInstance(t, ReadonlyTransportDecorator)
652
659
        self.assertIsInstance(t2, ReadonlyTransportDecorator)
653
660
        self.assertEqual(t2.base[:-1], t.abspath('foo/bar'))
661
668
        url = self.get_readonly_url()
662
669
        url2 = self.get_readonly_url('foo/bar')
663
670
        # the transport returned may be any HttpTransportBase subclass
664
 
        t = transport.get_transport_from_url(url)
665
 
        t2 = transport.get_transport_from_url(url2)
 
671
        t = transport.get_transport(url)
 
672
        t2 = transport.get_transport(url2)
666
673
        self.assertIsInstance(t, HttpTransportBase)
667
674
        self.assertIsInstance(t2, HttpTransportBase)
668
675
        self.assertEqual(t2.base[:-1], t.abspath('foo/bar'))
706
713
class TestChrootedTest(tests.ChrootedTestCase):
707
714
 
708
715
    def test_root_is_root(self):
709
 
        t = transport.get_transport_from_url(self.get_readonly_url())
 
716
        t = transport.get_transport(self.get_readonly_url())
710
717
        url = t.base
711
718
        self.assertEqual(url, t.clone('..').base)
712
719
 
714
721
class TestProfileResult(tests.TestCase):
715
722
 
716
723
    def test_profiles_tests(self):
717
 
        self.requireFeature(features.lsprof_feature)
 
724
        self.requireFeature(test_lsprof.LSProfFeature)
718
725
        terminal = testtools.testresult.doubles.ExtendedTestResult()
719
726
        result = tests.ProfileResult(terminal)
720
727
        class Sample(tests.TestCase):
775
782
 
776
783
    def test_lsprofiling(self):
777
784
        """Verbose test result prints lsprof statistics from test cases."""
778
 
        self.requireFeature(features.lsprof_feature)
 
785
        self.requireFeature(test_lsprof.LSProfFeature)
779
786
        result_stream = StringIO()
780
787
        result = bzrlib.tests.VerboseTestResult(
781
788
            result_stream,
826
833
        self.assertEndsWith(sio.getvalue(), "OK    50002ms\n")
827
834
 
828
835
    def test_known_failure(self):
829
 
        """Using knownFailure should trigger several result actions."""
 
836
        """A KnownFailure being raised should trigger several result actions."""
830
837
        class InstrumentedTestResult(tests.ExtendedTestResult):
831
838
            def stopTestRun(self): pass
832
839
            def report_tests_starting(self): pass
835
842
        result = InstrumentedTestResult(None, None, None, None)
836
843
        class Test(tests.TestCase):
837
844
            def test_function(self):
838
 
                self.knownFailure('failed!')
 
845
                raise tests.KnownFailure('failed!')
839
846
        test = Test("test_function")
840
847
        test.run(result)
841
848
        # it should invoke 'report_known_failure'.
857
864
            descriptions=0,
858
865
            verbosity=2,
859
866
            )
860
 
        _get_test("test_xfail").run(result)
861
 
        self.assertContainsRe(result_stream.getvalue(),
862
 
            "\n\\S+\\.test_xfail\\s+XFAIL\\s+\\d+ms\n"
863
 
            "\\s*(?:Text attachment: )?reason"
864
 
            "(?:\n-+\n|: {{{)"
865
 
            "this_fails"
866
 
            "(?:\n-+\n|}}}\n)")
 
867
        test = self.get_passing_test()
 
868
        result.startTest(test)
 
869
        prefix = len(result_stream.getvalue())
 
870
        # the err parameter has the shape:
 
871
        # (class, exception object, traceback)
 
872
        # KnownFailures dont get their tracebacks shown though, so we
 
873
        # can skip that.
 
874
        err = (tests.KnownFailure, tests.KnownFailure('foo'), None)
 
875
        result.report_known_failure(test, err)
 
876
        output = result_stream.getvalue()[prefix:]
 
877
        lines = output.splitlines()
 
878
        self.assertContainsRe(lines[0], r'XFAIL *\d+ms$')
 
879
        if sys.version_info > (2, 7):
 
880
            self.expectFailure("_ExpectedFailure on 2.7 loses the message",
 
881
                self.assertNotEqual, lines[1], '    ')
 
882
        self.assertEqual(lines[1], '    foo')
 
883
        self.assertEqual(2, len(lines))
867
884
 
868
885
    def get_passing_test(self):
869
886
        """Return a test object that can't be run usefully."""
880
897
                self._call = test, feature
881
898
        result = InstrumentedTestResult(None, None, None, None)
882
899
        test = SampleTestCase('_test_pass')
883
 
        feature = features.Feature()
 
900
        feature = tests.Feature()
884
901
        result.startTest(test)
885
902
        result.addNotSupported(test, feature)
886
903
        # it should invoke 'report_unsupported'.
905
922
            verbosity=2,
906
923
            )
907
924
        test = self.get_passing_test()
908
 
        feature = features.Feature()
 
925
        feature = tests.Feature()
909
926
        result.startTest(test)
910
927
        prefix = len(result_stream.getvalue())
911
928
        result.report_unsupported(test, feature)
924
941
            def addNotSupported(self, test, feature):
925
942
                self._call = test, feature
926
943
        result = InstrumentedTestResult(None, None, None, None)
927
 
        feature = features.Feature()
 
944
        feature = tests.Feature()
928
945
        class Test(tests.TestCase):
929
946
            def test_function(self):
930
947
                raise tests.UnavailableFeature(feature)
949
966
    def test_strict_with_known_failure(self):
950
967
        result = bzrlib.tests.TextTestResult(self._log_file, descriptions=0,
951
968
                                             verbosity=1)
952
 
        test = _get_test("test_xfail")
953
 
        test.run(result)
 
969
        test = self.get_passing_test()
 
970
        err = (tests.KnownFailure, tests.KnownFailure('foo'), None)
 
971
        result.addExpectedFailure(test, err)
954
972
        self.assertFalse(result.wasStrictlySuccessful())
955
973
        self.assertEqual(None, result._extractBenchmarkTime(test))
956
974
 
988
1006
        self.assertEquals(2, result.count)
989
1007
 
990
1008
 
 
1009
class TestUnicodeFilenameFeature(tests.TestCase):
 
1010
 
 
1011
    def test_probe_passes(self):
 
1012
        """UnicodeFilenameFeature._probe passes."""
 
1013
        # We can't test much more than that because the behaviour depends
 
1014
        # on the platform.
 
1015
        tests.UnicodeFilenameFeature._probe()
 
1016
 
 
1017
 
991
1018
class TestRunner(tests.TestCase):
992
1019
 
993
1020
    def dummy_test(self):
1063
1090
                self.expectFailure("No absolute truth", self.assertTrue, True)
1064
1091
        runner = tests.TextTestRunner(stream=StringIO())
1065
1092
        result = self.run_test_runner(runner, Test("test_truth"))
1066
 
        if testtools_version[:3] <= (0, 9, 11):
1067
 
            self.assertContainsRe(runner.stream.getvalue(),
1068
 
                "=+\n"
1069
 
                "FAIL: \\S+\.test_truth\n"
1070
 
                "-+\n"
1071
 
                "(?:.*\n)*"
1072
 
                "No absolute truth\n"
1073
 
                "(?:.*\n)*"
1074
 
                "-+\n"
1075
 
                "Ran 1 test in .*\n"
1076
 
                "\n"
1077
 
                "FAILED \\(failures=1\\)\n\\Z")
1078
 
        else:
1079
 
            self.assertContainsRe(runner.stream.getvalue(),
1080
 
                "=+\n"
1081
 
                "FAIL: \\S+\.test_truth\n"
1082
 
                "-+\n"
1083
 
                "Empty attachments:\n"
1084
 
                "  log\n"
1085
 
                "\n"
1086
 
                "reason: {{{No absolute truth}}}\n"
1087
 
                "-+\n"
1088
 
                "Ran 1 test in .*\n"
1089
 
                "\n"
1090
 
                "FAILED \\(failures=1\\)\n\\Z")
 
1093
        self.assertContainsRe(runner.stream.getvalue(),
 
1094
            "=+\n"
 
1095
            "FAIL: \\S+\.test_truth\n"
 
1096
            "-+\n"
 
1097
            "(?:.*\n)*"
 
1098
            "No absolute truth\n"
 
1099
            "(?:.*\n)*"
 
1100
            "-+\n"
 
1101
            "Ran 1 test in .*\n"
 
1102
            "\n"
 
1103
            "FAILED \\(failures=1\\)\n\\Z")
1091
1104
 
1092
1105
    def test_result_decorator(self):
1093
1106
        # decorate results
1178
1191
 
1179
1192
    def test_unsupported_features_listed(self):
1180
1193
        """When unsupported features are encountered they are detailed."""
1181
 
        class Feature1(features.Feature):
 
1194
        class Feature1(tests.Feature):
1182
1195
            def _probe(self): return False
1183
 
        class Feature2(features.Feature):
 
1196
        class Feature2(tests.Feature):
1184
1197
            def _probe(self): return False
1185
1198
        # create sample tests
1186
1199
        test1 = SampleTestCase('_test_pass')
1252
1265
            lambda trace=False: "ascii")
1253
1266
        result = self.run_test_runner(tests.TextTestRunner(stream=out),
1254
1267
            FailureWithUnicode("test_log_unicode"))
1255
 
        if testtools_version[:3] > (0, 9, 11):
1256
 
            self.assertContainsRe(out.getvalue(), "log: {{{\d+\.\d+  \\\\u2606}}}")
1257
 
        else:
1258
 
            self.assertContainsRe(out.getvalue(),
1259
 
                "Text attachment: log\n"
1260
 
                "-+\n"
1261
 
                "\d+\.\d+  \\\\u2606\n"
1262
 
                "-+\n")
 
1268
        self.assertContainsRe(out.getvalue(),
 
1269
            "Text attachment: log\n"
 
1270
            "-+\n"
 
1271
            "\d+\.\d+  \\\\u2606\n"
 
1272
            "-+\n")
1263
1273
 
1264
1274
 
1265
1275
class SampleTestCase(tests.TestCase):
1466
1476
 
1467
1477
        Each self.time() call is individually and separately profiled.
1468
1478
        """
1469
 
        self.requireFeature(features.lsprof_feature)
 
1479
        self.requireFeature(test_lsprof.LSProfFeature)
1470
1480
        # overrides the class member with an instance member so no cleanup
1471
1481
        # needed.
1472
1482
        self._gather_lsprof_in_benchmarks = True
1491
1501
        transport_server = memory.MemoryServer()
1492
1502
        transport_server.start_server()
1493
1503
        self.addCleanup(transport_server.stop_server)
1494
 
        t = transport.get_transport_from_url(transport_server.get_url())
 
1504
        t = transport.get_transport(transport_server.get_url())
1495
1505
        bzrdir.BzrDir.create(t.base)
1496
1506
        self.assertRaises(errors.BzrError,
1497
1507
            bzrdir.BzrDir.open_from_transport, t)
1502
1512
 
1503
1513
    def test_requireFeature_available(self):
1504
1514
        """self.requireFeature(available) is a no-op."""
1505
 
        class Available(features.Feature):
 
1515
        class Available(tests.Feature):
1506
1516
            def _probe(self):return True
1507
1517
        feature = Available()
1508
1518
        self.requireFeature(feature)
1509
1519
 
1510
1520
    def test_requireFeature_unavailable(self):
1511
1521
        """self.requireFeature(unavailable) raises UnavailableFeature."""
1512
 
        class Unavailable(features.Feature):
 
1522
        class Unavailable(tests.Feature):
1513
1523
            def _probe(self):return False
1514
1524
        feature = Unavailable()
1515
1525
        self.assertRaises(tests.UnavailableFeature,
1687
1697
    return a + b
1688
1698
 
1689
1699
 
1690
 
class _MissingFeature(features.Feature):
 
1700
class _MissingFeature(tests.Feature):
1691
1701
    def _probe(self):
1692
1702
        return False
1693
1703
missing_feature = _MissingFeature()
1744
1754
        result = self._run_test('test_fail')
1745
1755
        self.assertEqual(1, len(result.failures))
1746
1756
        result_content = result.failures[0][1]
1747
 
        if testtools_version < (0, 9, 12):
1748
 
            self.assertContainsRe(result_content, 'Text attachment: log')
 
1757
        self.assertContainsRe(result_content, 'Text attachment: log')
1749
1758
        self.assertContainsRe(result_content, 'this was a failing test')
1750
1759
 
1751
1760
    def test_error_has_log(self):
1752
1761
        result = self._run_test('test_error')
1753
1762
        self.assertEqual(1, len(result.errors))
1754
1763
        result_content = result.errors[0][1]
1755
 
        if testtools_version < (0, 9, 12):
1756
 
            self.assertContainsRe(result_content, 'Text attachment: log')
 
1764
        self.assertContainsRe(result_content, 'Text attachment: log')
1757
1765
        self.assertContainsRe(result_content, 'this test errored')
1758
1766
 
1759
1767
    def test_skip_has_no_log(self):
2041
2049
        self.assertLength(2, output.readlines())
2042
2050
 
2043
2051
    def test_lsprof_tests(self):
2044
 
        self.requireFeature(features.lsprof_feature)
 
2052
        self.requireFeature(test_lsprof.LSProfFeature)
2045
2053
        results = []
2046
2054
        class Test(object):
2047
2055
            def __call__(test, result):
2611
2619
        self.assertEqual('bzr: interrupted\n', result[1])
2612
2620
 
2613
2621
 
 
2622
class TestFeature(tests.TestCase):
 
2623
 
 
2624
    def test_caching(self):
 
2625
        """Feature._probe is called by the feature at most once."""
 
2626
        class InstrumentedFeature(tests.Feature):
 
2627
            def __init__(self):
 
2628
                super(InstrumentedFeature, self).__init__()
 
2629
                self.calls = []
 
2630
            def _probe(self):
 
2631
                self.calls.append('_probe')
 
2632
                return False
 
2633
        feature = InstrumentedFeature()
 
2634
        feature.available()
 
2635
        self.assertEqual(['_probe'], feature.calls)
 
2636
        feature.available()
 
2637
        self.assertEqual(['_probe'], feature.calls)
 
2638
 
 
2639
    def test_named_str(self):
 
2640
        """Feature.__str__ should thunk to feature_name()."""
 
2641
        class NamedFeature(tests.Feature):
 
2642
            def feature_name(self):
 
2643
                return 'symlinks'
 
2644
        feature = NamedFeature()
 
2645
        self.assertEqual('symlinks', str(feature))
 
2646
 
 
2647
    def test_default_str(self):
 
2648
        """Feature.__str__ should default to __class__.__name__."""
 
2649
        class NamedFeature(tests.Feature):
 
2650
            pass
 
2651
        feature = NamedFeature()
 
2652
        self.assertEqual('NamedFeature', str(feature))
 
2653
 
 
2654
 
 
2655
class TestUnavailableFeature(tests.TestCase):
 
2656
 
 
2657
    def test_access_feature(self):
 
2658
        feature = tests.Feature()
 
2659
        exception = tests.UnavailableFeature(feature)
 
2660
        self.assertIs(feature, exception.args[0])
 
2661
 
 
2662
 
 
2663
simple_thunk_feature = tests._CompatabilityThunkFeature(
 
2664
    deprecated_in((2, 1, 0)),
 
2665
    'bzrlib.tests.test_selftest',
 
2666
    'simple_thunk_feature','UnicodeFilename',
 
2667
    replacement_module='bzrlib.tests'
 
2668
    )
 
2669
 
 
2670
class Test_CompatibilityFeature(tests.TestCase):
 
2671
 
 
2672
    def test_does_thunk(self):
 
2673
        res = self.callDeprecated(
 
2674
            ['bzrlib.tests.test_selftest.simple_thunk_feature was deprecated'
 
2675
             ' in version 2.1.0. Use bzrlib.tests.UnicodeFilename instead.'],
 
2676
            simple_thunk_feature.available)
 
2677
        self.assertEqual(tests.UnicodeFilename.available(), res)
 
2678
 
 
2679
 
 
2680
class TestModuleAvailableFeature(tests.TestCase):
 
2681
 
 
2682
    def test_available_module(self):
 
2683
        feature = tests.ModuleAvailableFeature('bzrlib.tests')
 
2684
        self.assertEqual('bzrlib.tests', feature.module_name)
 
2685
        self.assertEqual('bzrlib.tests', str(feature))
 
2686
        self.assertTrue(feature.available())
 
2687
        self.assertIs(tests, feature.module)
 
2688
 
 
2689
    def test_unavailable_module(self):
 
2690
        feature = tests.ModuleAvailableFeature('bzrlib.no_such_module_exists')
 
2691
        self.assertEqual('bzrlib.no_such_module_exists', str(feature))
 
2692
        self.assertFalse(feature.available())
 
2693
        self.assertIs(None, feature.module)
 
2694
 
 
2695
 
2614
2696
class TestSelftestFiltering(tests.TestCase):
2615
2697
 
2616
2698
    def setUp(self):
3315
3397
        self.assertLength(1, calls)
3316
3398
 
3317
3399
 
3318
 
class TestUncollectedWarnings(tests.TestCase):
3319
 
    """Check a test case still alive after being run emits a warning"""
3320
 
 
3321
 
    class Test(tests.TestCase):
3322
 
        def test_pass(self):
3323
 
            pass
3324
 
        def test_self_ref(self):
3325
 
            self.also_self = self.test_self_ref
3326
 
        def test_skip(self):
3327
 
            self.skip("Don't need")
3328
 
 
3329
 
    def _get_suite(self):
3330
 
        return TestUtil.TestSuite([
3331
 
            self.Test("test_pass"),
3332
 
            self.Test("test_self_ref"),
3333
 
            self.Test("test_skip"),
3334
 
            ])
3335
 
 
3336
 
    def _inject_stream_into_subunit(self, stream):
3337
 
        """To be overridden by subclasses that run tests out of process"""
3338
 
 
3339
 
    def _run_selftest_with_suite(self, **kwargs):
3340
 
        sio = StringIO()
3341
 
        self._inject_stream_into_subunit(sio)
3342
 
        old_flags = tests.selftest_debug_flags
3343
 
        tests.selftest_debug_flags = old_flags.union(["uncollected_cases"])
3344
 
        gc_on = gc.isenabled()
3345
 
        if gc_on:
3346
 
            gc.disable()
3347
 
        try:
3348
 
            tests.selftest(test_suite_factory=self._get_suite, stream=sio,
3349
 
                stop_on_failure=False, **kwargs)
3350
 
        finally:
3351
 
            if gc_on:
3352
 
                gc.enable()
3353
 
            tests.selftest_debug_flags = old_flags
3354
 
        output = sio.getvalue()
3355
 
        self.assertNotContainsRe(output, "Uncollected test case.*test_pass")
3356
 
        self.assertContainsRe(output, "Uncollected test case.*test_self_ref")
3357
 
        return output
3358
 
 
3359
 
    def test_testsuite(self):
3360
 
        self._run_selftest_with_suite()
3361
 
 
3362
 
    def test_pattern(self):
3363
 
        out = self._run_selftest_with_suite(pattern="test_(?:pass|self_ref)$")
3364
 
        self.assertNotContainsRe(out, "test_skip")
3365
 
 
3366
 
    def test_exclude_pattern(self):
3367
 
        out = self._run_selftest_with_suite(exclude_pattern="test_skip$")
3368
 
        self.assertNotContainsRe(out, "test_skip")
3369
 
 
3370
 
    def test_random_seed(self):
3371
 
        self._run_selftest_with_suite(random_seed="now")
3372
 
 
3373
 
    def test_matching_tests_first(self):
3374
 
        self._run_selftest_with_suite(matching_tests_first=True,
3375
 
            pattern="test_self_ref$")
3376
 
 
3377
 
    def test_starting_with_and_exclude(self):
3378
 
        out = self._run_selftest_with_suite(starting_with=["bt."],
3379
 
            exclude_pattern="test_skip$")
3380
 
        self.assertNotContainsRe(out, "test_skip")
3381
 
 
3382
 
    def test_additonal_decorator(self):
3383
 
        out = self._run_selftest_with_suite(
3384
 
            suite_decorators=[tests.TestDecorator])
3385
 
 
3386
 
 
3387
 
class TestUncollectedWarningsSubunit(TestUncollectedWarnings):
3388
 
    """Check warnings from tests staying alive are emitted with subunit"""
3389
 
 
3390
 
    _test_needs_features = [features.subunit]
3391
 
 
3392
 
    def _run_selftest_with_suite(self, **kwargs):
3393
 
        return TestUncollectedWarnings._run_selftest_with_suite(self,
3394
 
            runner_class=tests.SubUnitBzrRunner, **kwargs)
3395
 
 
3396
 
 
3397
 
class TestUncollectedWarningsForking(TestUncollectedWarnings):
3398
 
    """Check warnings from tests staying alive are emitted when forking"""
3399
 
 
3400
 
    _test_needs_features = [features.subunit]
3401
 
 
3402
 
    def _inject_stream_into_subunit(self, stream):
3403
 
        """Monkey-patch subunit so the extra output goes to stream not stdout
3404
 
 
3405
 
        Some APIs need rewriting so this kind of bogus hackery can be replaced
3406
 
        by passing the stream param from run_tests down into ProtocolTestCase.
3407
 
        """
3408
 
        from subunit import ProtocolTestCase
3409
 
        _original_init = ProtocolTestCase.__init__
3410
 
        def _init_with_passthrough(self, *args, **kwargs):
3411
 
            _original_init(self, *args, **kwargs)
3412
 
            self._passthrough = stream
3413
 
        self.overrideAttr(ProtocolTestCase, "__init__", _init_with_passthrough)
3414
 
 
3415
 
    def _run_selftest_with_suite(self, **kwargs):
3416
 
        # GZ 2011-05-26: Add a PosixSystem feature so this check can go away
3417
 
        if getattr(os, "fork", None) is None:
3418
 
            raise tests.TestNotApplicable("Platform doesn't support forking")
3419
 
        # Make sure the fork code is actually invoked by claiming two cores
3420
 
        self.overrideAttr(osutils, "local_concurrency", lambda: 2)
3421
 
        kwargs.setdefault("suite_decorators", []).append(tests.fork_decorator)
3422
 
        return TestUncollectedWarnings._run_selftest_with_suite(self, **kwargs)
3423
 
 
3424
 
 
3425
3400
class TestEnvironHandling(tests.TestCase):
3426
3401
 
3427
3402
    def test_overrideEnv_None_called_twice_doesnt_leak(self):