blob: 0c62bf2daf689aa3e2d711cda236c76b8165be9a [file] [log] [blame]
Thomas Hellerbabddfc2006-03-08 19:56:54 +00001import unittest
2import ctypes
3import gc
4
5MyCallback = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_int)
6OtherCallback = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_int, ctypes.c_ulonglong)
7
8import _ctypes_test
9dll = ctypes.cdll.load(_ctypes_test.__file__)
10
11class RefcountTestCase(unittest.TestCase):
12
13 def test_1(self):
14 from sys import getrefcount as grc
15
16 f = dll._testfunc_callback_i_if
17 f.restype = ctypes.c_int
18 f.argtypes = [ctypes.c_int, MyCallback]
19
20 def callback(value):
21 #print "called back with", value
22 return value
23
24 self.failUnlessEqual(grc(callback), 2)
25 cb = MyCallback(callback)
26
27 self.failUnless(grc(callback) > 2)
28 result = f(-10, cb)
29 self.failUnlessEqual(result, -18)
30 cb = None
31
32 gc.collect()
33
34 self.failUnlessEqual(grc(callback), 2)
35
36
37 def test_refcount(self):
38 from sys import getrefcount as grc
39 def func(*args):
40 pass
41 # this is the standard refcount for func
42 self.failUnlessEqual(grc(func), 2)
43
44 # the CFuncPtr instance holds atr least one refcount on func:
45 f = OtherCallback(func)
46 self.failUnless(grc(func) > 2)
47
48 # and may release it again
49 del f
50 self.failUnless(grc(func) >= 2)
Tim Peterse8d09e52006-03-09 01:15:05 +000051
Thomas Hellerbabddfc2006-03-08 19:56:54 +000052 # but now it must be gone
53 gc.collect()
54 self.failUnless(grc(func) == 2)
55
56 class X(ctypes.Structure):
57 _fields_ = [("a", OtherCallback)]
58 x = X()
59 x.a = OtherCallback(func)
Tim Peterse8d09e52006-03-09 01:15:05 +000060
Thomas Hellerbabddfc2006-03-08 19:56:54 +000061 # the CFuncPtr instance holds atr least one refcount on func:
62 self.failUnless(grc(func) > 2)
63
64 # and may release it again
65 del x
66 self.failUnless(grc(func) >= 2)
Tim Peterse8d09e52006-03-09 01:15:05 +000067
Thomas Hellerbabddfc2006-03-08 19:56:54 +000068 # and now it must be gone again
69 gc.collect()
70 self.failUnlessEqual(grc(func), 2)
71
72 f = OtherCallback(func)
73
74 # the CFuncPtr instance holds atr least one refcount on func:
75 self.failUnless(grc(func) > 2)
76
77 # create a cycle
78 f.cycle = f
79
80 del f
81 gc.collect()
82 self.failUnlessEqual(grc(func), 2)
Tim Peterse8d09e52006-03-09 01:15:05 +000083
Thomas Hellerbabddfc2006-03-08 19:56:54 +000084class AnotherLeak(unittest.TestCase):
85 def test_callback(self):
86 import sys
87
88 proto = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_int, ctypes.c_int)
89 def func(a, b):
90 return a * b * 2
91 f = proto(func)
Tim Peterse8d09e52006-03-09 01:15:05 +000092
Thomas Hellerbabddfc2006-03-08 19:56:54 +000093 a = sys.getrefcount(ctypes.c_int)
94 f(1, 2)
95 self.failUnlessEqual(sys.getrefcount(ctypes.c_int), a)
96
97if __name__ == '__main__':
98 unittest.main()