Commits

Matt McClure committed 33d12fb

Backport 11798-20130803-matthewlmcclure.patch

The patch is attached to http://bugs.python.org/issue11798.

Comments (0)

Files changed (3)

             self.addTest(test)
 
     def run(self, result):
-        for test in self:
+        for index, test in enumerate(self):
             if result.shouldStop:
                 break
             test(result)
+            self._removeTestAtIndex(index)
         return result
+        
+    def _removeTestAtIndex(self, index):
+        """Stop holding a reference to the TestCase at index."""
+        try:
+            self._tests[index] = None
+        except TypeError:
+            # support for suite implementations that have overriden self._test
+            pass
 
     def __call__(self, *args, **kwds):
         return self.run(*args, **kwds)
         if getattr(result, '_testRunEntered', False) is False:
             result._testRunEntered = topLevel = True
 
-        for test in self:
+        for index, test in enumerate(self):
             if result.shouldStop:
                 break
 
                 test(result)
             else:
                 test.debug()
+                
+            self._removeTestAtIndex(index)
 
         if topLevel:
             self._tearDownPreviousClass(None, result)

unittest2/test/test_setups.py

         Test.__module__ = 'Module'
         sys.modules['Module'] = Module
 
-        _suite = unittest2.defaultTestLoader.loadTestsFromTestCase(Test)
-        suite = unittest2.TestSuite()
-
-        # nesting a suite again exposes a bug in the initial implementation
-        suite.addTest(_suite)
         messages = ('setUpModule', 'tearDownModule', 'setUpClass', 'tearDownClass', 'test_something')
         for phase, msg in enumerate(messages):
+            _suite = unittest2.defaultTestLoader.loadTestsFromTestCase(Test)
+            suite = unittest2.TestSuite([_suite])
             self.assertRaisesRegex(Exception, msg, suite.debug)

unittest2/test/test_suite.py

 from unittest2.test.support import EqualityMixin, LoggingResult
 
+import gc
 import sys
 import unittest2
+import weakref
 
 class Test(object):
     class Foo(unittest2.TestCase):
         # when the bug is fixed this line will not crash
         suite.run(unittest2.TestResult())
 
+    def test_remove_test_at_index(self):
+        suite = unittest2.TestSuite()
+        
+        suite._tests = [1, 2, 3]
+        suite._removeTestAtIndex(1)
+        
+        self.assertEqual(suite._tests[1], None)
+
+    def test_remove_test_at_index_not_indexable(self):
+        suite = unittest2.TestSuite()      
+        suite._tests = None
+        
+        # if _removeAtIndex raises for noniterables this next line will break
+        suite._removeTestAtIndex(2)
+        
+    def assert_garbage_collect_test_after_run(self, TestSuiteClass):
+        
+        class Foo(unittest2.TestCase):
+            def test_nothing(self):
+                pass
+        
+        test = Foo('test_nothing')
+        wref = weakref.ref(test)       
+        
+        suite = TestSuiteClass([wref()])
+        suite.run(unittest2.TestResult())
+        
+        del test
+        
+        # for the benefit of non-reference counting implementations
+        gc.collect()
+        
+        self.assertEqual(suite._tests, [None])
+        self.assertIsNone(wref())
+    
+    def test_garbage_collect_test_after_run_BaseTestSuite(self):
+        
+        self.assert_garbage_collect_test_after_run(unittest2.BaseTestSuite)
+        
+    def test_garbage_collect_test_after_run_TestSuite(self):
+        
+        self.assert_garbage_collect_test_after_run(unittest2.TestSuite)
+
 
     def test_basetestsuite(self):
         class Test(unittest2.TestCase):