PageRenderTime 38ms CodeModel.GetById 15ms app.highlight 9ms RepoModel.GetById 13ms app.codeStats 0ms

/Lib/ctypes/test/test_refcounts.py

http://unladen-swallow.googlecode.com/
Python | 98 lines | 61 code | 27 blank | 10 comment | 1 complexity | d412f5fef54ee53209c7f9103c0f46df MD5 | raw file
 1import 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(_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)
51
52        # 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)
60
61        # 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)
67
68        # 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)
83
84class 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)
92
93        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()