10c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiimport unittest
20c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yifrom test.test_support import verbose, run_unittest
30c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiimport sys
40c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiimport time
50c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiimport gc
60c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiimport weakref
70c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
80c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yitry:
90c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    import threading
100c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiexcept ImportError:
110c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    threading = None
120c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
130c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi### Support code
140c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi###############################################################################
150c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
160c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# Bug 1055820 has several tests of longstanding bugs involving weakrefs and
170c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# cyclic gc.
180c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
190c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# An instance of C1055820 has a self-loop, so becomes cyclic trash when
200c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi# unreachable.
210c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiclass C1055820(object):
220c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def __init__(self, i):
230c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.i = i
240c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.loop = self
250c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
260c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiclass GC_Detector(object):
270c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # Create an instance I.  Then gc hasn't happened again so long as
280c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # I.gc_happened is false.
290c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
300c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def __init__(self):
310c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.gc_happened = False
320c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
330c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        def it_happened(ignored):
340c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            self.gc_happened = True
350c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
360c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # Create a piece of cyclic trash that triggers it_happened when
370c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # gc collects it.
380c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.wr = weakref.ref(C1055820(666), it_happened)
390c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
400c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
410c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi### Tests
420c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi###############################################################################
430c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
440c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiclass GCTests(unittest.TestCase):
450c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_list(self):
460c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        l = []
470c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        l.append(l)
480c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        gc.collect()
490c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        del l
500c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(gc.collect(), 1)
510c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
520c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_dict(self):
530c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        d = {}
540c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        d[1] = d
550c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        gc.collect()
560c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        del d
570c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(gc.collect(), 1)
580c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
590c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_tuple(self):
600c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # since tuples are immutable we close the loop with a list
610c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        l = []
620c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        t = (l,)
630c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        l.append(t)
640c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        gc.collect()
650c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        del t
660c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        del l
670c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(gc.collect(), 2)
680c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
690c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_class(self):
700c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        class A:
710c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            pass
720c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        A.a = A
730c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        gc.collect()
740c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        del A
750c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertNotEqual(gc.collect(), 0)
760c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
770c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_newstyleclass(self):
780c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        class A(object):
790c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            pass
800c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        gc.collect()
810c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        del A
820c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertNotEqual(gc.collect(), 0)
830c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
840c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_instance(self):
850c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        class A:
860c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            pass
870c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        a = A()
880c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        a.a = a
890c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        gc.collect()
900c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        del a
910c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertNotEqual(gc.collect(), 0)
920c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
930c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_newinstance(self):
940c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        class A(object):
950c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            pass
960c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        a = A()
970c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        a.a = a
980c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        gc.collect()
990c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        del a
1000c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertNotEqual(gc.collect(), 0)
1010c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        class B(list):
1020c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            pass
1030c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        class C(B, A):
1040c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            pass
1050c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        a = C()
1060c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        a.a = a
1070c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        gc.collect()
1080c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        del a
1090c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertNotEqual(gc.collect(), 0)
1100c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        del B, C
1110c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertNotEqual(gc.collect(), 0)
1120c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        A.a = A()
1130c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        del A
1140c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertNotEqual(gc.collect(), 0)
1150c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(gc.collect(), 0)
1160c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
1170c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_method(self):
1180c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # Tricky: self.__init__ is a bound method, it references the instance.
1190c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        class A:
1200c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            def __init__(self):
1210c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                self.init = self.__init__
1220c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        a = A()
1230c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        gc.collect()
1240c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        del a
1250c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertNotEqual(gc.collect(), 0)
1260c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
1270c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_finalizer(self):
1280c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # A() is uncollectable if it is part of a cycle, make sure it shows up
1290c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # in gc.garbage.
1300c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        class A:
1310c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            def __del__(self): pass
1320c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        class B:
1330c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            pass
1340c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        a = A()
1350c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        a.a = a
1360c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        id_a = id(a)
1370c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        b = B()
1380c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        b.b = b
1390c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        gc.collect()
1400c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        del a
1410c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        del b
1420c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertNotEqual(gc.collect(), 0)
1430c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        for obj in gc.garbage:
1440c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            if id(obj) == id_a:
1450c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                del obj.a
1460c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                break
1470c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        else:
1480c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            self.fail("didn't find obj in garbage (finalizer)")
1490c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        gc.garbage.remove(obj)
1500c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
1510c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_finalizer_newclass(self):
1520c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # A() is uncollectable if it is part of a cycle, make sure it shows up
1530c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # in gc.garbage.
1540c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        class A(object):
1550c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            def __del__(self): pass
1560c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        class B(object):
1570c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            pass
1580c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        a = A()
1590c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        a.a = a
1600c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        id_a = id(a)
1610c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        b = B()
1620c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        b.b = b
1630c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        gc.collect()
1640c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        del a
1650c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        del b
1660c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertNotEqual(gc.collect(), 0)
1670c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        for obj in gc.garbage:
1680c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            if id(obj) == id_a:
1690c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                del obj.a
1700c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                break
1710c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        else:
1720c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            self.fail("didn't find obj in garbage (finalizer)")
1730c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        gc.garbage.remove(obj)
1740c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
1750c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_function(self):
1760c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # Tricky: f -> d -> f, code should call d.clear() after the exec to
1770c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # break the cycle.
1780c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        d = {}
1790c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        exec("def f(): pass\n") in d
1800c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        gc.collect()
1810c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        del d
1820c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(gc.collect(), 2)
1830c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
1840c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_frame(self):
1850c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        def f():
1860c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            frame = sys._getframe()
1870c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        gc.collect()
1880c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        f()
1890c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(gc.collect(), 1)
1900c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
1910c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_saveall(self):
1920c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # Verify that cyclic garbage like lists show up in gc.garbage if the
1930c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # SAVEALL option is enabled.
1940c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
1950c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # First make sure we don't save away other stuff that just happens to
1960c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # be waiting for collection.
1970c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        gc.collect()
1980c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # if this fails, someone else created immortal trash
1990c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(gc.garbage, [])
2000c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
2010c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        L = []
2020c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        L.append(L)
2030c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        id_L = id(L)
2040c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
2050c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        debug = gc.get_debug()
2060c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        gc.set_debug(debug | gc.DEBUG_SAVEALL)
2070c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        del L
2080c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        gc.collect()
2090c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        gc.set_debug(debug)
2100c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
2110c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(len(gc.garbage), 1)
2120c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        obj = gc.garbage.pop()
2130c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(id(obj), id_L)
2140c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
2150c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_del(self):
2160c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # __del__ methods can trigger collection, make this to happen
2170c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        thresholds = gc.get_threshold()
2180c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        gc.enable()
2190c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        gc.set_threshold(1)
2200c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
2210c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        class A:
2220c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            def __del__(self):
2230c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                dir(self)
2240c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        a = A()
2250c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        del a
2260c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
2270c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        gc.disable()
2280c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        gc.set_threshold(*thresholds)
2290c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
2300c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_del_newclass(self):
2310c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # __del__ methods can trigger collection, make this to happen
2320c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        thresholds = gc.get_threshold()
2330c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        gc.enable()
2340c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        gc.set_threshold(1)
2350c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
2360c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        class A(object):
2370c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            def __del__(self):
2380c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                dir(self)
2390c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        a = A()
2400c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        del a
2410c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
2420c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        gc.disable()
2430c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        gc.set_threshold(*thresholds)
2440c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
2450c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # The following two tests are fragile:
2460c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # They precisely count the number of allocations,
2470c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # which is highly implementation-dependent.
2480c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # For example:
2490c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # - disposed tuples are not freed, but reused
2500c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    # - the call to assertEqual somehow avoids building its args tuple
2510c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_get_count(self):
2520c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # Avoid future allocation of method object
2530c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        assertEqual = self._baseAssertEqual
2540c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        gc.collect()
2550c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        assertEqual(gc.get_count(), (0, 0, 0))
2560c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        a = dict()
2570c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # since gc.collect(), we created two objects:
2580c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # the dict, and the tuple returned by get_count()
2590c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        assertEqual(gc.get_count(), (2, 0, 0))
2600c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
2610c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_collect_generations(self):
2620c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # Avoid future allocation of method object
2630c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        assertEqual = self.assertEqual
2640c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        gc.collect()
2650c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        a = dict()
2660c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        gc.collect(0)
2670c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        assertEqual(gc.get_count(), (0, 1, 0))
2680c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        gc.collect(1)
2690c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        assertEqual(gc.get_count(), (0, 0, 1))
2700c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        gc.collect(2)
2710c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        assertEqual(gc.get_count(), (0, 0, 0))
2720c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
2730c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_trashcan(self):
2740c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        class Ouch:
2750c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            n = 0
2760c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            def __del__(self):
2770c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                Ouch.n = Ouch.n + 1
2780c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                if Ouch.n % 17 == 0:
2790c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                    gc.collect()
2800c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
2810c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # "trashcan" is a hack to prevent stack overflow when deallocating
2820c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # very deeply nested tuples etc.  It works in part by abusing the
2830c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # type pointer and refcount fields, and that can yield horrible
2840c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # problems when gc tries to traverse the structures.
2850c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # If this test fails (as it does in 2.0, 2.1 and 2.2), it will
2860c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # most likely die via segfault.
2870c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
2880c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # Note:  In 2.3 the possibility for compiling without cyclic gc was
2890c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # removed, and that in turn allows the trashcan mechanism to work
2900c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # via much simpler means (e.g., it never abuses the type pointer or
2910c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # refcount fields anymore).  Since it's much less likely to cause a
2920c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # problem now, the various constants in this expensive (we force a lot
2930c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # of full collections) test are cut back from the 2.2 version.
2940c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        gc.enable()
2950c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        N = 150
2960c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        for count in range(2):
2970c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            t = []
2980c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            for i in range(N):
2990c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                t = [t, Ouch()]
3000c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            u = []
3010c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            for i in range(N):
3020c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                u = [u, Ouch()]
3030c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            v = {}
3040c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            for i in range(N):
3050c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                v = {1: v, 2: Ouch()}
3060c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        gc.disable()
3070c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
3080c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    @unittest.skipUnless(threading, "test meaningless on builds without threads")
3090c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_trashcan_threads(self):
3100c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # Issue #13992: trashcan mechanism should be thread-safe
3110c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        NESTING = 60
3120c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        N_THREADS = 2
3130c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
3140c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        def sleeper_gen():
3150c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            """A generator that releases the GIL when closed or dealloc'ed."""
3160c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            try:
3170c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                yield
3180c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            finally:
3190c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                time.sleep(0.000001)
3200c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
3210c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        class C(list):
3220c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            # Appending to a list is atomic, which avoids the use of a lock.
3230c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            inits = []
3240c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            dels = []
3250c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            def __init__(self, alist):
3260c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                self[:] = alist
3270c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                C.inits.append(None)
3280c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            def __del__(self):
3290c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                # This __del__ is called by subtype_dealloc().
3300c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                C.dels.append(None)
3310c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                # `g` will release the GIL when garbage-collected.  This
3320c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                # helps assert subtype_dealloc's behaviour when threads
3330c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                # switch in the middle of it.
3340c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                g = sleeper_gen()
3350c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                next(g)
3360c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                # Now that __del__ is finished, subtype_dealloc will proceed
3370c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                # to call list_dealloc, which also uses the trashcan mechanism.
3380c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
3390c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        def make_nested():
3400c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            """Create a sufficiently nested container object so that the
3410c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            trashcan mechanism is invoked when deallocating it."""
3420c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            x = C([])
3430c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            for i in range(NESTING):
3440c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                x = [C([x])]
3450c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            del x
3460c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
3470c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        def run_thread():
3480c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            """Exercise make_nested() in a loop."""
3490c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            while not exit:
3500c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                make_nested()
3510c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
3520c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        old_checkinterval = sys.getcheckinterval()
3530c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        sys.setcheckinterval(3)
3540c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        try:
3550c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            exit = False
3560c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            threads = []
3570c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            for i in range(N_THREADS):
3580c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                t = threading.Thread(target=run_thread)
3590c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                threads.append(t)
3600c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            for t in threads:
3610c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                t.start()
3620c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            time.sleep(1.0)
3630c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            exit = True
3640c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            for t in threads:
3650c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                t.join()
3660c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        finally:
3670c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            sys.setcheckinterval(old_checkinterval)
3680c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        gc.collect()
3690c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(len(C.inits), len(C.dels))
3700c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
3710c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_boom(self):
3720c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        class Boom:
3730c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            def __getattr__(self, someattribute):
3740c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                del self.attr
3750c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                raise AttributeError
3760c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
3770c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        a = Boom()
3780c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        b = Boom()
3790c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        a.attr = b
3800c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        b.attr = a
3810c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
3820c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        gc.collect()
3830c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        garbagelen = len(gc.garbage)
3840c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        del a, b
3850c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # a<->b are in a trash cycle now.  Collection will invoke
3860c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # Boom.__getattr__ (to see whether a and b have __del__ methods), and
3870c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # __getattr__ deletes the internal "attr" attributes as a side effect.
3880c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # That causes the trash cycle to get reclaimed via refcounts falling to
3890c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # 0, thus mutating the trash graph as a side effect of merely asking
3900c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # whether __del__ exists.  This used to (before 2.3b1) crash Python.
3910c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # Now __getattr__ isn't called.
3920c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(gc.collect(), 4)
3930c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(len(gc.garbage), garbagelen)
3940c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
3950c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_boom2(self):
3960c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        class Boom2:
3970c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            def __init__(self):
3980c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                self.x = 0
3990c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
4000c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            def __getattr__(self, someattribute):
4010c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                self.x += 1
4020c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                if self.x > 1:
4030c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                    del self.attr
4040c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                raise AttributeError
4050c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
4060c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        a = Boom2()
4070c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        b = Boom2()
4080c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        a.attr = b
4090c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        b.attr = a
4100c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
4110c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        gc.collect()
4120c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        garbagelen = len(gc.garbage)
4130c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        del a, b
4140c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # Much like test_boom(), except that __getattr__ doesn't break the
4150c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # cycle until the second time gc checks for __del__.  As of 2.3b1,
4160c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # there isn't a second time, so this simply cleans up the trash cycle.
4170c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # We expect a, b, a.__dict__ and b.__dict__ (4 objects) to get
4180c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # reclaimed this way.
4190c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(gc.collect(), 4)
4200c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(len(gc.garbage), garbagelen)
4210c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
4220c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_boom_new(self):
4230c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # boom__new and boom2_new are exactly like boom and boom2, except use
4240c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # new-style classes.
4250c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
4260c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        class Boom_New(object):
4270c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            def __getattr__(self, someattribute):
4280c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                del self.attr
4290c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                raise AttributeError
4300c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
4310c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        a = Boom_New()
4320c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        b = Boom_New()
4330c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        a.attr = b
4340c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        b.attr = a
4350c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
4360c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        gc.collect()
4370c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        garbagelen = len(gc.garbage)
4380c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        del a, b
4390c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(gc.collect(), 4)
4400c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(len(gc.garbage), garbagelen)
4410c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
4420c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_boom2_new(self):
4430c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        class Boom2_New(object):
4440c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            def __init__(self):
4450c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                self.x = 0
4460c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
4470c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            def __getattr__(self, someattribute):
4480c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                self.x += 1
4490c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                if self.x > 1:
4500c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                    del self.attr
4510c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                raise AttributeError
4520c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
4530c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        a = Boom2_New()
4540c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        b = Boom2_New()
4550c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        a.attr = b
4560c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        b.attr = a
4570c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
4580c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        gc.collect()
4590c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        garbagelen = len(gc.garbage)
4600c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        del a, b
4610c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(gc.collect(), 4)
4620c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(len(gc.garbage), garbagelen)
4630c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
4640c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_get_referents(self):
4650c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        alist = [1, 3, 5]
4660c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        got = gc.get_referents(alist)
4670c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        got.sort()
4680c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(got, alist)
4690c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
4700c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        atuple = tuple(alist)
4710c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        got = gc.get_referents(atuple)
4720c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        got.sort()
4730c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(got, alist)
4740c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
4750c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        adict = {1: 3, 5: 7}
4760c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        expected = [1, 3, 5, 7]
4770c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        got = gc.get_referents(adict)
4780c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        got.sort()
4790c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(got, expected)
4800c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
4810c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        got = gc.get_referents([1, 2], {3: 4}, (0, 0, 0))
4820c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        got.sort()
4830c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(got, [0, 0] + range(5))
4840c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
4850c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(gc.get_referents(1, 'a', 4j), [])
4860c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
4870c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_is_tracked(self):
4880c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # Atomic built-in types are not tracked, user-defined objects and
4890c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # mutable containers are.
4900c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # NOTE: types with special optimizations (e.g. tuple) have tests
4910c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # in their own test files instead.
4920c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertFalse(gc.is_tracked(None))
4930c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertFalse(gc.is_tracked(1))
4940c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertFalse(gc.is_tracked(1.0))
4950c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertFalse(gc.is_tracked(1.0 + 5.0j))
4960c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertFalse(gc.is_tracked(True))
4970c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertFalse(gc.is_tracked(False))
4980c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertFalse(gc.is_tracked("a"))
4990c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertFalse(gc.is_tracked(u"a"))
5000c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertFalse(gc.is_tracked(bytearray("a")))
5010c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertFalse(gc.is_tracked(type))
5020c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertFalse(gc.is_tracked(int))
5030c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertFalse(gc.is_tracked(object))
5040c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertFalse(gc.is_tracked(object()))
5050c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
5060c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        class OldStyle:
5070c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            pass
5080c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        class NewStyle(object):
5090c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            pass
5100c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertTrue(gc.is_tracked(gc))
5110c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertTrue(gc.is_tracked(OldStyle))
5120c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertTrue(gc.is_tracked(OldStyle()))
5130c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertTrue(gc.is_tracked(NewStyle))
5140c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertTrue(gc.is_tracked(NewStyle()))
5150c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertTrue(gc.is_tracked([]))
5160c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertTrue(gc.is_tracked(set()))
5170c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
5180c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_bug1055820b(self):
5190c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # Corresponds to temp2b.py in the bug report.
5200c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
5210c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        ouch = []
5220c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        def callback(ignored):
5230c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            ouch[:] = [wr() for wr in WRs]
5240c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
5250c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        Cs = [C1055820(i) for i in range(2)]
5260c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        WRs = [weakref.ref(c, callback) for c in Cs]
5270c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        c = None
5280c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
5290c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        gc.collect()
5300c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(len(ouch), 0)
5310c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # Make the two instances trash, and collect again.  The bug was that
5320c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # the callback materialized a strong reference to an instance, but gc
5330c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # cleared the instance's dict anyway.
5340c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        Cs = None
5350c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        gc.collect()
5360c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(len(ouch), 2)  # else the callbacks didn't run
5370c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        for x in ouch:
5380c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            # If the callback resurrected one of these guys, the instance
5390c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            # would be damaged, with an empty __dict__.
5400c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            self.assertEqual(x, None)
5410c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
5420c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiclass GCTogglingTests(unittest.TestCase):
5430c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def setUp(self):
5440c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        gc.enable()
5450c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
5460c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def tearDown(self):
5470c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        gc.disable()
5480c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
5490c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_bug1055820c(self):
5500c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # Corresponds to temp2c.py in the bug report.  This is pretty
5510c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # elaborate.
5520c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
5530c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        c0 = C1055820(0)
5540c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # Move c0 into generation 2.
5550c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        gc.collect()
5560c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
5570c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        c1 = C1055820(1)
5580c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        c1.keep_c0_alive = c0
5590c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        del c0.loop # now only c1 keeps c0 alive
5600c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
5610c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        c2 = C1055820(2)
5620c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        c2wr = weakref.ref(c2) # no callback!
5630c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
5640c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        ouch = []
5650c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        def callback(ignored):
5660c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            ouch[:] = [c2wr()]
5670c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
5680c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # The callback gets associated with a wr on an object in generation 2.
5690c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        c0wr = weakref.ref(c0, callback)
5700c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
5710c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        c0 = c1 = c2 = None
5720c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
5730c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # What we've set up:  c0, c1, and c2 are all trash now.  c0 is in
5740c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # generation 2.  The only thing keeping it alive is that c1 points to
5750c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # it. c1 and c2 are in generation 0, and are in self-loops.  There's a
5760c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # global weakref to c2 (c2wr), but that weakref has no callback.
5770c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # There's also a global weakref to c0 (c0wr), and that does have a
5780c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # callback, and that callback references c2 via c2wr().
5790c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        #
5800c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        #               c0 has a wr with callback, which references c2wr
5810c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        #               ^
5820c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        #               |
5830c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        #               |     Generation 2 above dots
5840c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        #. . . . . . . .|. . . . . . . . . . . . . . . . . . . . . . . .
5850c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        #               |     Generation 0 below dots
5860c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        #               |
5870c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        #               |
5880c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        #            ^->c1   ^->c2 has a wr but no callback
5890c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        #            |  |    |  |
5900c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        #            <--v    <--v
5910c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        #
5920c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # So this is the nightmare:  when generation 0 gets collected, we see
5930c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # that c2 has a callback-free weakref, and c1 doesn't even have a
5940c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # weakref.  Collecting generation 0 doesn't see c0 at all, and c0 is
5950c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # the only object that has a weakref with a callback.  gc clears c1
5960c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # and c2.  Clearing c1 has the side effect of dropping the refcount on
5970c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # c0 to 0, so c0 goes away (despite that it's in an older generation)
5980c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # and c0's wr callback triggers.  That in turn materializes a reference
5990c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # to c2 via c2wr(), but c2 gets cleared anyway by gc.
6000c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
6010c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # We want to let gc happen "naturally", to preserve the distinction
6020c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # between generations.
6030c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        junk = []
6040c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        i = 0
6050c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        detector = GC_Detector()
6060c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        while not detector.gc_happened:
6070c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            i += 1
6080c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            if i > 10000:
6090c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                self.fail("gc didn't happen after 10000 iterations")
6100c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            self.assertEqual(len(ouch), 0)
6110c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            junk.append([])  # this will eventually trigger gc
6120c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
6130c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(len(ouch), 1)  # else the callback wasn't invoked
6140c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        for x in ouch:
6150c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            # If the callback resurrected c2, the instance would be damaged,
6160c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            # with an empty __dict__.
6170c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            self.assertEqual(x, None)
6180c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
6190c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    def test_bug1055820d(self):
6200c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # Corresponds to temp2d.py in the bug report.  This is very much like
6210c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # test_bug1055820c, but uses a __del__ method instead of a weakref
6220c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # callback to sneak in a resurrection of cyclic trash.
6230c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
6240c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        ouch = []
6250c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        class D(C1055820):
6260c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            def __del__(self):
6270c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                ouch[:] = [c2wr()]
6280c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
6290c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        d0 = D(0)
6300c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # Move all the above into generation 2.
6310c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        gc.collect()
6320c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
6330c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        c1 = C1055820(1)
6340c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        c1.keep_d0_alive = d0
6350c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        del d0.loop # now only c1 keeps d0 alive
6360c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
6370c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        c2 = C1055820(2)
6380c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        c2wr = weakref.ref(c2) # no callback!
6390c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
6400c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        d0 = c1 = c2 = None
6410c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
6420c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # What we've set up:  d0, c1, and c2 are all trash now.  d0 is in
6430c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # generation 2.  The only thing keeping it alive is that c1 points to
6440c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # it.  c1 and c2 are in generation 0, and are in self-loops.  There's
6450c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # a global weakref to c2 (c2wr), but that weakref has no callback.
6460c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # There are no other weakrefs.
6470c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        #
6480c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        #               d0 has a __del__ method that references c2wr
6490c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        #               ^
6500c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        #               |
6510c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        #               |     Generation 2 above dots
6520c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        #. . . . . . . .|. . . . . . . . . . . . . . . . . . . . . . . .
6530c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        #               |     Generation 0 below dots
6540c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        #               |
6550c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        #               |
6560c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        #            ^->c1   ^->c2 has a wr but no callback
6570c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        #            |  |    |  |
6580c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        #            <--v    <--v
6590c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        #
6600c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # So this is the nightmare:  when generation 0 gets collected, we see
6610c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # that c2 has a callback-free weakref, and c1 doesn't even have a
6620c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # weakref.  Collecting generation 0 doesn't see d0 at all.  gc clears
6630c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # c1 and c2.  Clearing c1 has the side effect of dropping the refcount
6640c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # on d0 to 0, so d0 goes away (despite that it's in an older
6650c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # generation) and d0's __del__ triggers.  That in turn materializes
6660c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # a reference to c2 via c2wr(), but c2 gets cleared anyway by gc.
6670c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
6680c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # We want to let gc happen "naturally", to preserve the distinction
6690c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # between generations.
6700c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        detector = GC_Detector()
6710c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        junk = []
6720c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        i = 0
6730c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        while not detector.gc_happened:
6740c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            i += 1
6750c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            if i > 10000:
6760c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi                self.fail("gc didn't happen after 10000 iterations")
6770c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            self.assertEqual(len(ouch), 0)
6780c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            junk.append([])  # this will eventually trigger gc
6790c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
6800c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        self.assertEqual(len(ouch), 1)  # else __del__ wasn't invoked
6810c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        for x in ouch:
6820c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            # If __del__ resurrected c2, the instance would be damaged, with an
6830c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            # empty __dict__.
6840c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            self.assertEqual(x, None)
6850c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
6860c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yidef test_main():
6870c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    enabled = gc.isenabled()
6880c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    gc.disable()
6890c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    assert not gc.isenabled()
6900c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    debug = gc.get_debug()
6910c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    gc.set_debug(debug & ~gc.DEBUG_LEAK) # this test is supposed to leak
6920c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
6930c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    try:
6940c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        gc.collect() # Delete 2nd generation garbage
6950c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        run_unittest(GCTests, GCTogglingTests)
6960c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    finally:
6970c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        gc.set_debug(debug)
6980c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # test gc.enable() even if GC is disabled by default
6990c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        if verbose:
7000c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            print "restoring automatic collection"
7010c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        # make sure to always test gc.enable()
7020c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        gc.enable()
7030c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        assert gc.isenabled()
7040c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi        if not enabled:
7050c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi            gc.disable()
7060c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi
7070c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yiif __name__ == "__main__":
7080c5958b1636c47ed7c284f859c8e805fd06a0e6Bill Yi    test_main()
709