1import unittest, sys
2
3from ctypes import *
4import _ctypes_test
5
6ctype_types = [c_byte, c_ubyte, c_short, c_ushort, c_int, c_uint,
7                 c_long, c_ulong, c_longlong, c_ulonglong, c_double, c_float]
8python_types = [int, int, int, int, int, int,
9                int, int, int, int, float, float]
10
11class PointersTestCase(unittest.TestCase):
12
13    def test_pointer_crash(self):
14
15        class A(POINTER(c_ulong)):
16            pass
17
18        POINTER(c_ulong)(c_ulong(22))
19        # Pointer can't set contents: has no _type_
20        self.assertRaises(TypeError, A, c_ulong(33))
21
22    def test_pass_pointers(self):
23        dll = CDLL(_ctypes_test.__file__)
24        func = dll._testfunc_p_p
25        if sizeof(c_longlong) == sizeof(c_void_p):
26            func.restype = c_longlong
27        else:
28            func.restype = c_long
29
30        i = c_int(12345678)
31##        func.argtypes = (POINTER(c_int),)
32        address = func(byref(i))
33        self.assertEqual(c_int.from_address(address).value, 12345678)
34
35        func.restype = POINTER(c_int)
36        res = func(pointer(i))
37        self.assertEqual(res.contents.value, 12345678)
38        self.assertEqual(res[0], 12345678)
39
40    def test_change_pointers(self):
41        dll = CDLL(_ctypes_test.__file__)
42        func = dll._testfunc_p_p
43
44        i = c_int(87654)
45        func.restype = POINTER(c_int)
46        func.argtypes = (POINTER(c_int),)
47
48        res = func(pointer(i))
49        self.assertEqual(res[0], 87654)
50        self.assertEqual(res.contents.value, 87654)
51
52        # C code: *res = 54345
53        res[0] = 54345
54        self.assertEqual(i.value, 54345)
55
56        # C code:
57        #   int x = 12321;
58        #   res = &x
59        x = c_int(12321)
60        res.contents = x
61        self.assertEqual(i.value, 54345)
62
63        x.value = -99
64        self.assertEqual(res.contents.value, -99)
65
66    def test_callbacks_with_pointers(self):
67        # a function type receiving a pointer
68        PROTOTYPE = CFUNCTYPE(c_int, POINTER(c_int))
69
70        self.result = []
71
72        def func(arg):
73            for i in range(10):
74##                print arg[i],
75                self.result.append(arg[i])
76##            print
77            return 0
78        callback = PROTOTYPE(func)
79
80        dll = CDLL(_ctypes_test.__file__)
81        # This function expects a function pointer,
82        # and calls this with an integer pointer as parameter.
83        # The int pointer points to a table containing the numbers 1..10
84        doit = dll._testfunc_callback_with_pointer
85
86##        i = c_int(42)
87##        callback(byref(i))
88##        self.assertEqual(i.value, 84)
89
90        doit(callback)
91##        print self.result
92        doit(callback)
93##        print self.result
94
95    def test_basics(self):
96        from operator import delitem
97        for ct, pt in zip(ctype_types, python_types):
98            i = ct(42)
99            p = pointer(i)
100##            print type(p.contents), ct
101            self.assertIs(type(p.contents), ct)
102            # p.contents is the same as p[0]
103##            print p.contents
104##            self.assertEqual(p.contents, 42)
105##            self.assertEqual(p[0], 42)
106
107            self.assertRaises(TypeError, delitem, p, 0)
108
109    def test_from_address(self):
110        from array import array
111        a = array('i', [100, 200, 300, 400, 500])
112        addr = a.buffer_info()[0]
113
114        p = POINTER(POINTER(c_int))
115##        print dir(p)
116##        print p.from_address
117##        print p.from_address(addr)[0][0]
118
119    def test_other(self):
120        class Table(Structure):
121            _fields_ = [("a", c_int),
122                        ("b", c_int),
123                        ("c", c_int)]
124
125        pt = pointer(Table(1, 2, 3))
126
127        self.assertEqual(pt.contents.a, 1)
128        self.assertEqual(pt.contents.b, 2)
129        self.assertEqual(pt.contents.c, 3)
130
131        pt.contents.c = 33
132
133        from ctypes import _pointer_type_cache
134        del _pointer_type_cache[Table]
135
136    def test_basic(self):
137        p = pointer(c_int(42))
138        # Although a pointer can be indexed, it has no length
139        self.assertRaises(TypeError, len, p)
140        self.assertEqual(p[0], 42)
141        self.assertEqual(p[0:1], [42])
142        self.assertEqual(p.contents.value, 42)
143
144    def test_charpp(self):
145        """Test that a character pointer-to-pointer is correctly passed"""
146        dll = CDLL(_ctypes_test.__file__)
147        func = dll._testfunc_c_p_p
148        func.restype = c_char_p
149        argv = (c_char_p * 2)()
150        argc = c_int( 2 )
151        argv[0] = b'hello'
152        argv[1] = b'world'
153        result = func( byref(argc), argv )
154        self.assertEqual(result, b'world')
155
156    def test_bug_1467852(self):
157        # http://sourceforge.net/tracker/?func=detail&atid=532154&aid=1467852&group_id=71702
158        x = c_int(5)
159        dummy = []
160        for i in range(32000):
161            dummy.append(c_int(i))
162        y = c_int(6)
163        p = pointer(x)
164        pp = pointer(p)
165        q = pointer(y)
166        pp[0] = q         # <==
167        self.assertEqual(p[0], 6)
168    def test_c_void_p(self):
169        # http://sourceforge.net/tracker/?func=detail&aid=1518190&group_id=5470&atid=105470
170        if sizeof(c_void_p) == 4:
171            self.assertEqual(c_void_p(0xFFFFFFFF).value,
172                                 c_void_p(-1).value)
173            self.assertEqual(c_void_p(0xFFFFFFFFFFFFFFFF).value,
174                                 c_void_p(-1).value)
175        elif sizeof(c_void_p) == 8:
176            self.assertEqual(c_void_p(0xFFFFFFFF).value,
177                                 0xFFFFFFFF)
178            self.assertEqual(c_void_p(0xFFFFFFFFFFFFFFFF).value,
179                                 c_void_p(-1).value)
180            self.assertEqual(c_void_p(0xFFFFFFFFFFFFFFFFFFFFFFFF).value,
181                                 c_void_p(-1).value)
182
183        self.assertRaises(TypeError, c_void_p, 3.14) # make sure floats are NOT accepted
184        self.assertRaises(TypeError, c_void_p, object()) # nor other objects
185
186    def test_pointers_bool(self):
187        # NULL pointers have a boolean False value, non-NULL pointers True.
188        self.assertEqual(bool(POINTER(c_int)()), False)
189        self.assertEqual(bool(pointer(c_int())), True)
190
191        self.assertEqual(bool(CFUNCTYPE(None)(0)), False)
192        self.assertEqual(bool(CFUNCTYPE(None)(42)), True)
193
194        # COM methods are boolean True:
195        if sys.platform == "win32":
196            mth = WINFUNCTYPE(None)(42, "name", (), None)
197            self.assertEqual(bool(mth), True)
198
199    def test_pointer_type_name(self):
200        LargeNamedType = type('T' * 2 ** 25, (Structure,), {})
201        self.assertTrue(POINTER(LargeNamedType))
202
203        # to not leak references, we must clean _pointer_type_cache
204        from ctypes import _pointer_type_cache
205        del _pointer_type_cache[LargeNamedType]
206
207    def test_pointer_type_str_name(self):
208        large_string = 'T' * 2 ** 25
209        P = POINTER(large_string)
210        self.assertTrue(P)
211
212        # to not leak references, we must clean _pointer_type_cache
213        from ctypes import _pointer_type_cache
214        del _pointer_type_cache[id(P)]
215
216
217if __name__ == '__main__':
218    unittest.main()
219