Thomas Heller | babddfc | 2006-03-08 19:56:54 +0000 | [diff] [blame] | 1 | import unittest |
| 2 | import ctypes |
| 3 | import gc |
| 4 | |
| 5 | MyCallback = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_int) |
| 6 | OtherCallback = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_int, ctypes.c_ulonglong) |
| 7 | |
| 8 | import _ctypes_test |
Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 9 | dll = ctypes.CDLL(_ctypes_test.__file__) |
Thomas Heller | babddfc | 2006-03-08 19:56:54 +0000 | [diff] [blame] | 10 | |
| 11 | class 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 Peterson | c9c0f20 | 2009-06-30 23:06:06 +0000 | [diff] [blame] | 24 | self.assertEqual(grc(callback), 2) |
Thomas Heller | babddfc | 2006-03-08 19:56:54 +0000 | [diff] [blame] | 25 | cb = MyCallback(callback) |
| 26 | |
Benjamin Peterson | c9c0f20 | 2009-06-30 23:06:06 +0000 | [diff] [blame] | 27 | self.assertTrue(grc(callback) > 2) |
Thomas Heller | babddfc | 2006-03-08 19:56:54 +0000 | [diff] [blame] | 28 | result = f(-10, cb) |
Benjamin Peterson | c9c0f20 | 2009-06-30 23:06:06 +0000 | [diff] [blame] | 29 | self.assertEqual(result, -18) |
Thomas Heller | babddfc | 2006-03-08 19:56:54 +0000 | [diff] [blame] | 30 | cb = None |
| 31 | |
| 32 | gc.collect() |
| 33 | |
Benjamin Peterson | c9c0f20 | 2009-06-30 23:06:06 +0000 | [diff] [blame] | 34 | self.assertEqual(grc(callback), 2) |
Thomas Heller | babddfc | 2006-03-08 19:56:54 +0000 | [diff] [blame] | 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 |
Benjamin Peterson | c9c0f20 | 2009-06-30 23:06:06 +0000 | [diff] [blame] | 42 | self.assertEqual(grc(func), 2) |
Thomas Heller | babddfc | 2006-03-08 19:56:54 +0000 | [diff] [blame] | 43 | |
| 44 | # the CFuncPtr instance holds atr least one refcount on func: |
| 45 | f = OtherCallback(func) |
Benjamin Peterson | c9c0f20 | 2009-06-30 23:06:06 +0000 | [diff] [blame] | 46 | self.assertTrue(grc(func) > 2) |
Thomas Heller | babddfc | 2006-03-08 19:56:54 +0000 | [diff] [blame] | 47 | |
| 48 | # and may release it again |
| 49 | del f |
Benjamin Peterson | c9c0f20 | 2009-06-30 23:06:06 +0000 | [diff] [blame] | 50 | self.assertTrue(grc(func) >= 2) |
Tim Peters | e8d09e5 | 2006-03-09 01:15:05 +0000 | [diff] [blame] | 51 | |
Thomas Heller | babddfc | 2006-03-08 19:56:54 +0000 | [diff] [blame] | 52 | # but now it must be gone |
| 53 | gc.collect() |
Benjamin Peterson | c9c0f20 | 2009-06-30 23:06:06 +0000 | [diff] [blame] | 54 | self.assertTrue(grc(func) == 2) |
Thomas Heller | babddfc | 2006-03-08 19:56:54 +0000 | [diff] [blame] | 55 | |
| 56 | class X(ctypes.Structure): |
| 57 | _fields_ = [("a", OtherCallback)] |
| 58 | x = X() |
| 59 | x.a = OtherCallback(func) |
Tim Peters | e8d09e5 | 2006-03-09 01:15:05 +0000 | [diff] [blame] | 60 | |
Thomas Heller | babddfc | 2006-03-08 19:56:54 +0000 | [diff] [blame] | 61 | # the CFuncPtr instance holds atr least one refcount on func: |
Benjamin Peterson | c9c0f20 | 2009-06-30 23:06:06 +0000 | [diff] [blame] | 62 | self.assertTrue(grc(func) > 2) |
Thomas Heller | babddfc | 2006-03-08 19:56:54 +0000 | [diff] [blame] | 63 | |
| 64 | # and may release it again |
| 65 | del x |
Benjamin Peterson | c9c0f20 | 2009-06-30 23:06:06 +0000 | [diff] [blame] | 66 | self.assertTrue(grc(func) >= 2) |
Tim Peters | e8d09e5 | 2006-03-09 01:15:05 +0000 | [diff] [blame] | 67 | |
Thomas Heller | babddfc | 2006-03-08 19:56:54 +0000 | [diff] [blame] | 68 | # and now it must be gone again |
| 69 | gc.collect() |
Benjamin Peterson | c9c0f20 | 2009-06-30 23:06:06 +0000 | [diff] [blame] | 70 | self.assertEqual(grc(func), 2) |
Thomas Heller | babddfc | 2006-03-08 19:56:54 +0000 | [diff] [blame] | 71 | |
| 72 | f = OtherCallback(func) |
| 73 | |
| 74 | # the CFuncPtr instance holds atr least one refcount on func: |
Benjamin Peterson | c9c0f20 | 2009-06-30 23:06:06 +0000 | [diff] [blame] | 75 | self.assertTrue(grc(func) > 2) |
Thomas Heller | babddfc | 2006-03-08 19:56:54 +0000 | [diff] [blame] | 76 | |
| 77 | # create a cycle |
| 78 | f.cycle = f |
| 79 | |
| 80 | del f |
| 81 | gc.collect() |
Benjamin Peterson | c9c0f20 | 2009-06-30 23:06:06 +0000 | [diff] [blame] | 82 | self.assertEqual(grc(func), 2) |
Tim Peters | e8d09e5 | 2006-03-09 01:15:05 +0000 | [diff] [blame] | 83 | |
Thomas Heller | babddfc | 2006-03-08 19:56:54 +0000 | [diff] [blame] | 84 | class 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 Peters | e8d09e5 | 2006-03-09 01:15:05 +0000 | [diff] [blame] | 92 | |
Thomas Heller | babddfc | 2006-03-08 19:56:54 +0000 | [diff] [blame] | 93 | a = sys.getrefcount(ctypes.c_int) |
| 94 | f(1, 2) |
Benjamin Peterson | c9c0f20 | 2009-06-30 23:06:06 +0000 | [diff] [blame] | 95 | self.assertEqual(sys.getrefcount(ctypes.c_int), a) |
Thomas Heller | babddfc | 2006-03-08 19:56:54 +0000 | [diff] [blame] | 96 | |
| 97 | if __name__ == '__main__': |
| 98 | unittest.main() |