1import unittest 2from test import support 3import ctypes 4import gc 5 6MyCallback = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_int) 7OtherCallback = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_int, ctypes.c_ulonglong) 8 9import _ctypes_test 10dll = ctypes.CDLL(_ctypes_test.__file__) 11 12class RefcountTestCase(unittest.TestCase): 13 14 @support.refcount_test 15 def test_1(self): 16 from sys import getrefcount as grc 17 18 f = dll._testfunc_callback_i_if 19 f.restype = ctypes.c_int 20 f.argtypes = [ctypes.c_int, MyCallback] 21 22 def callback(value): 23 #print "called back with", value 24 return value 25 26 self.assertEqual(grc(callback), 2) 27 cb = MyCallback(callback) 28 29 self.assertGreater(grc(callback), 2) 30 result = f(-10, cb) 31 self.assertEqual(result, -18) 32 cb = None 33 34 gc.collect() 35 36 self.assertEqual(grc(callback), 2) 37 38 39 @support.refcount_test 40 def test_refcount(self): 41 from sys import getrefcount as grc 42 def func(*args): 43 pass 44 # this is the standard refcount for func 45 self.assertEqual(grc(func), 2) 46 47 # the CFuncPtr instance holds at least one refcount on func: 48 f = OtherCallback(func) 49 self.assertGreater(grc(func), 2) 50 51 # and may release it again 52 del f 53 self.assertGreaterEqual(grc(func), 2) 54 55 # but now it must be gone 56 gc.collect() 57 self.assertEqual(grc(func), 2) 58 59 class X(ctypes.Structure): 60 _fields_ = [("a", OtherCallback)] 61 x = X() 62 x.a = OtherCallback(func) 63 64 # the CFuncPtr instance holds at least one refcount on func: 65 self.assertGreater(grc(func), 2) 66 67 # and may release it again 68 del x 69 self.assertGreaterEqual(grc(func), 2) 70 71 # and now it must be gone again 72 gc.collect() 73 self.assertEqual(grc(func), 2) 74 75 f = OtherCallback(func) 76 77 # the CFuncPtr instance holds at least one refcount on func: 78 self.assertGreater(grc(func), 2) 79 80 # create a cycle 81 f.cycle = f 82 83 del f 84 gc.collect() 85 self.assertEqual(grc(func), 2) 86 87class AnotherLeak(unittest.TestCase): 88 def test_callback(self): 89 import sys 90 91 proto = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_int, ctypes.c_int) 92 def func(a, b): 93 return a * b * 2 94 f = proto(func) 95 96 a = sys.getrefcount(ctypes.c_int) 97 f(1, 2) 98 self.assertEqual(sys.getrefcount(ctypes.c_int), a) 99 100if __name__ == '__main__': 101 unittest.main() 102