blob: 35a81aa40be0c100c8463f114cfe7853d0972517 [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
Thomas Wouters477c8d52006-05-27 19:21:47 +00009dll = ctypes.CDLL(_ctypes_test.__file__)
Thomas Hellerbabddfc2006-03-08 19:56:54 +000010
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
Benjamin Petersonc9c0f202009-06-30 23:06:06 +000024 self.assertEqual(grc(callback), 2)
Thomas Hellerbabddfc2006-03-08 19:56:54 +000025 cb = MyCallback(callback)
26
Benjamin Petersonc9c0f202009-06-30 23:06:06 +000027 self.assertTrue(grc(callback) > 2)
Thomas Hellerbabddfc2006-03-08 19:56:54 +000028 result = f(-10, cb)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +000029 self.assertEqual(result, -18)
Thomas Hellerbabddfc2006-03-08 19:56:54 +000030 cb = None
31
32 gc.collect()
33
Benjamin Petersonc9c0f202009-06-30 23:06:06 +000034 self.assertEqual(grc(callback), 2)
Thomas Hellerbabddfc2006-03-08 19:56:54 +000035
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
Benjamin Petersonc9c0f202009-06-30 23:06:06 +000042 self.assertEqual(grc(func), 2)
Thomas Hellerbabddfc2006-03-08 19:56:54 +000043
44 # the CFuncPtr instance holds atr least one refcount on func:
45 f = OtherCallback(func)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +000046 self.assertTrue(grc(func) > 2)
Thomas Hellerbabddfc2006-03-08 19:56:54 +000047
48 # and may release it again
49 del f
Benjamin Petersonc9c0f202009-06-30 23:06:06 +000050 self.assertTrue(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()
Benjamin Petersonc9c0f202009-06-30 23:06:06 +000054 self.assertTrue(grc(func) == 2)
Thomas Hellerbabddfc2006-03-08 19:56:54 +000055
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:
Benjamin Petersonc9c0f202009-06-30 23:06:06 +000062 self.assertTrue(grc(func) > 2)
Thomas Hellerbabddfc2006-03-08 19:56:54 +000063
64 # and may release it again
65 del x
Benjamin Petersonc9c0f202009-06-30 23:06:06 +000066 self.assertTrue(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()
Benjamin Petersonc9c0f202009-06-30 23:06:06 +000070 self.assertEqual(grc(func), 2)
Thomas Hellerbabddfc2006-03-08 19:56:54 +000071
72 f = OtherCallback(func)
73
74 # the CFuncPtr instance holds atr least one refcount on func:
Benjamin Petersonc9c0f202009-06-30 23:06:06 +000075 self.assertTrue(grc(func) > 2)
Thomas Hellerbabddfc2006-03-08 19:56:54 +000076
77 # create a cycle
78 f.cycle = f
79
80 del f
81 gc.collect()
Benjamin Petersonc9c0f202009-06-30 23:06:06 +000082 self.assertEqual(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)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +000095 self.assertEqual(sys.getrefcount(ctypes.c_int), a)
Thomas Hellerbabddfc2006-03-08 19:56:54 +000096
97if __name__ == '__main__':
98 unittest.main()