home *** CD-ROM | disk | FTP | other *** search
/ Freelog 33 / Freelog033.iso / Progr / Python-2.2.1.exe / TEST_GC.PY < prev    next >
Encoding:
Python Source  |  2002-03-29  |  5.8 KB  |  244 lines

  1. from test_support import verify, verbose, TestFailed
  2. import sys
  3. import gc
  4.  
  5. def expect(actual, expected, name):
  6.     if actual != expected:
  7.         raise TestFailed, "test_%s: actual %d, expected %d" % (
  8.             name, actual, expected)
  9.  
  10. def expect_nonzero(actual, name):
  11.     if actual == 0:
  12.         raise TestFailed, "test_%s: unexpected zero" % name
  13.  
  14. def run_test(name, thunk):
  15.     if verbose:
  16.         print "testing %s..." % name,
  17.     thunk()
  18.     if verbose:
  19.         print "ok"
  20.  
  21. def test_list():
  22.     l = []
  23.     l.append(l)
  24.     gc.collect()
  25.     del l
  26.     expect(gc.collect(), 1, "list")
  27.  
  28. def test_dict():
  29.     d = {}
  30.     d[1] = d
  31.     gc.collect()
  32.     del d
  33.     expect(gc.collect(), 1, "dict")
  34.  
  35. def test_tuple():
  36.     # since tuples are immutable we close the loop with a list
  37.     l = []
  38.     t = (l,)
  39.     l.append(t)
  40.     gc.collect()
  41.     del t
  42.     del l
  43.     expect(gc.collect(), 2, "tuple")
  44.  
  45. def test_class():
  46.     class A:
  47.         pass
  48.     A.a = A
  49.     gc.collect()
  50.     del A
  51.     expect_nonzero(gc.collect(), "class")
  52.  
  53. def test_newstyleclass():
  54.     class A(object):
  55.         pass
  56.     gc.collect()
  57.     del A
  58.     expect_nonzero(gc.collect(), "staticclass")
  59.  
  60. def test_instance():
  61.     class A:
  62.         pass
  63.     a = A()
  64.     a.a = a
  65.     gc.collect()
  66.     del a
  67.     expect_nonzero(gc.collect(), "instance")
  68.  
  69. def test_newinstance():
  70.     class A(object):
  71.         pass
  72.     a = A()
  73.     a.a = a
  74.     gc.collect()
  75.     del a
  76.     expect_nonzero(gc.collect(), "newinstance")
  77.     class B(list):
  78.         pass
  79.     class C(B, A):
  80.         pass
  81.     a = C()
  82.     a.a = a
  83.     gc.collect()
  84.     del a
  85.     expect_nonzero(gc.collect(), "newinstance(2)")
  86.  
  87. def test_method():
  88.     # Tricky: self.__init__ is a bound method, it references the instance.
  89.     class A:
  90.         def __init__(self):
  91.             self.init = self.__init__
  92.     a = A()
  93.     gc.collect()
  94.     del a
  95.     expect_nonzero(gc.collect(), "method")
  96.  
  97. def test_finalizer():
  98.     # A() is uncollectable if it is part of a cycle, make sure it shows up
  99.     # in gc.garbage.
  100.     class A:
  101.         def __del__(self): pass
  102.     class B:
  103.         pass
  104.     a = A()
  105.     a.a = a
  106.     id_a = id(a)
  107.     b = B()
  108.     b.b = b
  109.     gc.collect()
  110.     del a
  111.     del b
  112.     expect_nonzero(gc.collect(), "finalizer")
  113.     for obj in gc.garbage:
  114.         if id(obj) == id_a:
  115.             del obj.a
  116.             break
  117.     else:
  118.         raise TestFailed, "didn't find obj in garbage (finalizer)"
  119.     gc.garbage.remove(obj)
  120.  
  121. def test_function():
  122.     # Tricky: f -> d -> f, code should call d.clear() after the exec to
  123.     # break the cycle.
  124.     d = {}
  125.     exec("def f(): pass\n") in d
  126.     gc.collect()
  127.     del d
  128.     expect(gc.collect(), 2, "function")
  129.  
  130. def test_frame():
  131.     def f():
  132.         frame = sys._getframe()
  133.     gc.collect()
  134.     f()
  135.     expect(gc.collect(), 1, "frame")
  136.  
  137.  
  138. def test_saveall():
  139.     # Verify that cyclic garbage like lists show up in gc.garbage if the
  140.     # SAVEALL option is enabled.
  141.     debug = gc.get_debug()
  142.     gc.set_debug(debug | gc.DEBUG_SAVEALL)
  143.     l = []
  144.     l.append(l)
  145.     id_l = id(l)
  146.     del l
  147.     gc.collect()
  148.     try:
  149.         for obj in gc.garbage:
  150.             if id(obj) == id_l:
  151.                 del obj[:]
  152.                 break
  153.         else:
  154.             raise TestFailed, "didn't find obj in garbage (saveall)"
  155.         gc.garbage.remove(obj)
  156.     finally:
  157.         gc.set_debug(debug)
  158.  
  159. def test_del():
  160.     # __del__ methods can trigger collection, make this to happen
  161.     thresholds = gc.get_threshold()
  162.     gc.enable()
  163.     gc.set_threshold(1)
  164.  
  165.     class A:
  166.         def __del__(self):
  167.             dir(self)
  168.     a = A()
  169.     del a
  170.  
  171.     gc.disable()
  172.     apply(gc.set_threshold, thresholds)
  173.  
  174. class Ouch:
  175.     n = 0
  176.     def __del__(self):
  177.         Ouch.n = Ouch.n + 1
  178.         if Ouch.n % 7 == 0:
  179.             gc.collect()
  180.  
  181. def test_trashcan():
  182.     # "trashcan" is a hack to prevent stack overflow when deallocating
  183.     # very deeply nested tuples etc.  It works in part by abusing the
  184.     # type pointer and refcount fields, and that can yield horrible
  185.     # problems when gc tries to traverse the structures.
  186.     # If this test fails (as it does in 2.0, 2.1 and 2.2), it will
  187.     # most likely die via segfault.
  188.  
  189.     gc.enable()
  190.     N = 200
  191.     for count in range(3):
  192.         t = []
  193.         for i in range(N):
  194.             t = [t, Ouch()]
  195.         u = []
  196.         for i in range(N):
  197.             u = [u, Ouch()]
  198.         v = {}
  199.         for i in range(N):
  200.             v = {1: v, 2: Ouch()}
  201.     gc.disable()
  202.  
  203. def test_all():
  204.     gc.collect() # Delete 2nd generation garbage
  205.     run_test("lists", test_list)
  206.     run_test("dicts", test_dict)
  207.     run_test("tuples", test_tuple)
  208.     run_test("classes", test_class)
  209.     run_test("new style classes", test_newstyleclass)
  210.     run_test("instances", test_instance)
  211.     run_test("new instances", test_newinstance)
  212.     run_test("methods", test_method)
  213.     run_test("functions", test_function)
  214.     run_test("frames", test_frame)
  215.     run_test("finalizers", test_finalizer)
  216.     run_test("__del__", test_del)
  217.     run_test("saveall", test_saveall)
  218.     run_test("trashcan", test_trashcan)
  219.  
  220. def test():
  221.     if verbose:
  222.         print "disabling automatic collection"
  223.     enabled = gc.isenabled()
  224.     gc.disable()
  225.     verify(not gc.isenabled() )
  226.     debug = gc.get_debug()
  227.     gc.set_debug(debug & ~gc.DEBUG_LEAK) # this test is supposed to leak
  228.  
  229.     try:
  230.         test_all()
  231.     finally:
  232.         gc.set_debug(debug)
  233.         # test gc.enable() even if GC is disabled by default
  234.         if verbose:
  235.             print "restoring automatic collection"
  236.         # make sure to always test gc.enable()
  237.         gc.enable()
  238.         verify(gc.isenabled())
  239.         if not enabled:
  240.             gc.disable()
  241.  
  242.  
  243. test()
  244.