• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1"""
2Here is probably the place to write the docs, since the test-cases
3show how the type behave.
4
5Later...
6"""
7
8from ctypes import *
9from ctypes.test import need_symbol
10import sys, unittest
11
12try:
13    WINFUNCTYPE
14except NameError:
15    # fake to enable this test on Linux
16    WINFUNCTYPE = CFUNCTYPE
17
18import _ctypes_test
19dll = CDLL(_ctypes_test.__file__)
20if sys.platform == "win32":
21    windll = WinDLL(_ctypes_test.__file__)
22
23class POINT(Structure):
24    _fields_ = [("x", c_int), ("y", c_int)]
25class RECT(Structure):
26    _fields_ = [("left", c_int), ("top", c_int),
27                ("right", c_int), ("bottom", c_int)]
28class FunctionTestCase(unittest.TestCase):
29
30    def test_mro(self):
31        # in Python 2.3, this raises TypeError: MRO conflict among bases classes,
32        # in Python 2.2 it works.
33        #
34        # But in early versions of _ctypes.c, the result of tp_new
35        # wasn't checked, and it even crashed Python.
36        # Found by Greg Chapman.
37
38        try:
39            class X(object, Array):
40                _length_ = 5
41                _type_ = "i"
42        except TypeError:
43            pass
44
45
46        from _ctypes import _Pointer
47        try:
48            class X(object, _Pointer):
49                pass
50        except TypeError:
51            pass
52
53        from _ctypes import _SimpleCData
54        try:
55            class X(object, _SimpleCData):
56                _type_ = "i"
57        except TypeError:
58            pass
59
60        try:
61            class X(object, Structure):
62                _fields_ = []
63        except TypeError:
64            pass
65
66
67    @need_symbol('c_wchar')
68    def test_wchar_parm(self):
69        f = dll._testfunc_i_bhilfd
70        f.argtypes = [c_byte, c_wchar, c_int, c_long, c_float, c_double]
71        result = f(1, u"x", 3, 4, 5.0, 6.0)
72        self.assertEqual(result, 139)
73        self.assertEqual(type(result), int)
74
75    @need_symbol('c_wchar')
76    def test_wchar_result(self):
77        f = dll._testfunc_i_bhilfd
78        f.argtypes = [c_byte, c_short, c_int, c_long, c_float, c_double]
79        f.restype = c_wchar
80        result = f(0, 0, 0, 0, 0, 0)
81        self.assertEqual(result, u'\x00')
82
83    def test_voidresult(self):
84        f = dll._testfunc_v
85        f.restype = None
86        f.argtypes = [c_int, c_int, POINTER(c_int)]
87        result = c_int()
88        self.assertEqual(None, f(1, 2, byref(result)))
89        self.assertEqual(result.value, 3)
90
91    def test_intresult(self):
92        f = dll._testfunc_i_bhilfd
93        f.argtypes = [c_byte, c_short, c_int, c_long, c_float, c_double]
94        f.restype = c_int
95        result = f(1, 2, 3, 4, 5.0, 6.0)
96        self.assertEqual(result, 21)
97        self.assertEqual(type(result), int)
98
99        result = f(-1, -2, -3, -4, -5.0, -6.0)
100        self.assertEqual(result, -21)
101        self.assertEqual(type(result), int)
102
103        # If we declare the function to return a short,
104        # is the high part split off?
105        f.restype = c_short
106        result = f(1, 2, 3, 4, 5.0, 6.0)
107        self.assertEqual(result, 21)
108        self.assertEqual(type(result), int)
109
110        result = f(1, 2, 3, 0x10004, 5.0, 6.0)
111        self.assertEqual(result, 21)
112        self.assertEqual(type(result), int)
113
114        # You cannot assign character format codes as restype any longer
115        self.assertRaises(TypeError, setattr, f, "restype", "i")
116
117    def test_floatresult(self):
118        f = dll._testfunc_f_bhilfd
119        f.argtypes = [c_byte, c_short, c_int, c_long, c_float, c_double]
120        f.restype = c_float
121        result = f(1, 2, 3, 4, 5.0, 6.0)
122        self.assertEqual(result, 21)
123        self.assertEqual(type(result), float)
124
125        result = f(-1, -2, -3, -4, -5.0, -6.0)
126        self.assertEqual(result, -21)
127        self.assertEqual(type(result), float)
128
129    def test_doubleresult(self):
130        f = dll._testfunc_d_bhilfd
131        f.argtypes = [c_byte, c_short, c_int, c_long, c_float, c_double]
132        f.restype = c_double
133        result = f(1, 2, 3, 4, 5.0, 6.0)
134        self.assertEqual(result, 21)
135        self.assertEqual(type(result), float)
136
137        result = f(-1, -2, -3, -4, -5.0, -6.0)
138        self.assertEqual(result, -21)
139        self.assertEqual(type(result), float)
140
141    def test_longdoubleresult(self):
142        f = dll._testfunc_D_bhilfD
143        f.argtypes = [c_byte, c_short, c_int, c_long, c_float, c_longdouble]
144        f.restype = c_longdouble
145        result = f(1, 2, 3, 4, 5.0, 6.0)
146        self.assertEqual(result, 21)
147        self.assertEqual(type(result), float)
148
149        result = f(-1, -2, -3, -4, -5.0, -6.0)
150        self.assertEqual(result, -21)
151        self.assertEqual(type(result), float)
152
153    @need_symbol('c_longlong')
154    def test_longlongresult(self):
155        f = dll._testfunc_q_bhilfd
156        f.restype = c_longlong
157        f.argtypes = [c_byte, c_short, c_int, c_long, c_float, c_double]
158        result = f(1, 2, 3, 4, 5.0, 6.0)
159        self.assertEqual(result, 21)
160
161        f = dll._testfunc_q_bhilfdq
162        f.restype = c_longlong
163        f.argtypes = [c_byte, c_short, c_int, c_long, c_float, c_double, c_longlong]
164        result = f(1, 2, 3, 4, 5.0, 6.0, 21)
165        self.assertEqual(result, 42)
166
167    def test_stringresult(self):
168        f = dll._testfunc_p_p
169        f.argtypes = None
170        f.restype = c_char_p
171        result = f("123")
172        self.assertEqual(result, "123")
173
174        result = f(None)
175        self.assertEqual(result, None)
176
177    def test_pointers(self):
178        f = dll._testfunc_p_p
179        f.restype = POINTER(c_int)
180        f.argtypes = [POINTER(c_int)]
181
182        # This only works if the value c_int(42) passed to the
183        # function is still alive while the pointer (the result) is
184        # used.
185
186        v = c_int(42)
187
188        self.assertEqual(pointer(v).contents.value, 42)
189        result = f(pointer(v))
190        self.assertEqual(type(result), POINTER(c_int))
191        self.assertEqual(result.contents.value, 42)
192
193        # This on works...
194        result = f(pointer(v))
195        self.assertEqual(result.contents.value, v.value)
196
197        p = pointer(c_int(99))
198        result = f(p)
199        self.assertEqual(result.contents.value, 99)
200
201        arg = byref(v)
202        result = f(arg)
203        self.assertNotEqual(result.contents, v.value)
204
205        self.assertRaises(ArgumentError, f, byref(c_short(22)))
206
207        # It is dangerous, however, because you don't control the lifetime
208        # of the pointer:
209        result = f(byref(c_int(99)))
210        self.assertNotEqual(result.contents, 99)
211
212    def test_errors(self):
213        f = dll._testfunc_p_p
214        f.restype = c_int
215
216        class X(Structure):
217            _fields_ = [("y", c_int)]
218
219        self.assertRaises(TypeError, f, X()) #cannot convert parameter
220
221    ################################################################
222    def test_shorts(self):
223        f = dll._testfunc_callback_i_if
224
225        args = []
226        expected = [262144, 131072, 65536, 32768, 16384, 8192, 4096, 2048,
227                    1024, 512, 256, 128, 64, 32, 16, 8, 4, 2, 1]
228
229        def callback(v):
230            args.append(v)
231            return v
232
233        CallBack = CFUNCTYPE(c_int, c_int)
234
235        cb = CallBack(callback)
236        f(2**18, cb)
237        self.assertEqual(args, expected)
238
239    ################################################################
240
241
242    def test_callbacks(self):
243        f = dll._testfunc_callback_i_if
244        f.restype = c_int
245        f.argtypes = None
246
247        MyCallback = CFUNCTYPE(c_int, c_int)
248
249        def callback(value):
250            #print "called back with", value
251            return value
252
253        cb = MyCallback(callback)
254        result = f(-10, cb)
255        self.assertEqual(result, -18)
256
257        # test with prototype
258        f.argtypes = [c_int, MyCallback]
259        cb = MyCallback(callback)
260        result = f(-10, cb)
261        self.assertEqual(result, -18)
262
263        AnotherCallback = WINFUNCTYPE(c_int, c_int, c_int, c_int, c_int)
264
265        # check that the prototype works: we call f with wrong
266        # argument types
267        cb = AnotherCallback(callback)
268        self.assertRaises(ArgumentError, f, -10, cb)
269
270
271    def test_callbacks_2(self):
272        # Can also use simple datatypes as argument type specifiers
273        # for the callback function.
274        # In this case the call receives an instance of that type
275        f = dll._testfunc_callback_i_if
276        f.restype = c_int
277
278        MyCallback = CFUNCTYPE(c_int, c_int)
279
280        f.argtypes = [c_int, MyCallback]
281
282        def callback(value):
283            #print "called back with", value
284            self.assertEqual(type(value), int)
285            return value
286
287        cb = MyCallback(callback)
288        result = f(-10, cb)
289        self.assertEqual(result, -18)
290
291    @need_symbol('c_longlong')
292    def test_longlong_callbacks(self):
293
294        f = dll._testfunc_callback_q_qf
295        f.restype = c_longlong
296
297        MyCallback = CFUNCTYPE(c_longlong, c_longlong)
298
299        f.argtypes = [c_longlong, MyCallback]
300
301        def callback(value):
302            self.assertIsInstance(value, (int, long))
303            return value & 0x7FFFFFFF
304
305        cb = MyCallback(callback)
306
307        self.assertEqual(13577625587, f(1000000000000, cb))
308
309    def test_errors(self):
310        self.assertRaises(AttributeError, getattr, dll, "_xxx_yyy")
311        self.assertRaises(ValueError, c_int.in_dll, dll, "_xxx_yyy")
312
313    def test_byval(self):
314
315        # without prototype
316        ptin = POINT(1, 2)
317        ptout = POINT()
318        # EXPORT int _testfunc_byval(point in, point *pout)
319        result = dll._testfunc_byval(ptin, byref(ptout))
320        got = result, ptout.x, ptout.y
321        expected = 3, 1, 2
322        self.assertEqual(got, expected)
323
324        # with prototype
325        ptin = POINT(101, 102)
326        ptout = POINT()
327        dll._testfunc_byval.argtypes = (POINT, POINTER(POINT))
328        dll._testfunc_byval.restype = c_int
329        result = dll._testfunc_byval(ptin, byref(ptout))
330        got = result, ptout.x, ptout.y
331        expected = 203, 101, 102
332        self.assertEqual(got, expected)
333
334    def test_struct_return_2H(self):
335        class S2H(Structure):
336            _fields_ = [("x", c_short),
337                        ("y", c_short)]
338        dll.ret_2h_func.restype = S2H
339        dll.ret_2h_func.argtypes = [S2H]
340        inp = S2H(99, 88)
341        s2h = dll.ret_2h_func(inp)
342        self.assertEqual((s2h.x, s2h.y), (99*2, 88*3))
343
344    @unittest.skipUnless(sys.platform == "win32", 'Windows-specific test')
345    def test_struct_return_2H_stdcall(self):
346        class S2H(Structure):
347            _fields_ = [("x", c_short),
348                        ("y", c_short)]
349
350        windll.s_ret_2h_func.restype = S2H
351        windll.s_ret_2h_func.argtypes = [S2H]
352        s2h = windll.s_ret_2h_func(S2H(99, 88))
353        self.assertEqual((s2h.x, s2h.y), (99*2, 88*3))
354
355    def test_struct_return_8H(self):
356        class S8I(Structure):
357            _fields_ = [("a", c_int),
358                        ("b", c_int),
359                        ("c", c_int),
360                        ("d", c_int),
361                        ("e", c_int),
362                        ("f", c_int),
363                        ("g", c_int),
364                        ("h", c_int)]
365        dll.ret_8i_func.restype = S8I
366        dll.ret_8i_func.argtypes = [S8I]
367        inp = S8I(9, 8, 7, 6, 5, 4, 3, 2)
368        s8i = dll.ret_8i_func(inp)
369        self.assertEqual((s8i.a, s8i.b, s8i.c, s8i.d, s8i.e, s8i.f, s8i.g, s8i.h),
370                             (9*2, 8*3, 7*4, 6*5, 5*6, 4*7, 3*8, 2*9))
371
372    @unittest.skipUnless(sys.platform == "win32", 'Windows-specific test')
373    def test_struct_return_8H_stdcall(self):
374        class S8I(Structure):
375            _fields_ = [("a", c_int),
376                        ("b", c_int),
377                        ("c", c_int),
378                        ("d", c_int),
379                        ("e", c_int),
380                        ("f", c_int),
381                        ("g", c_int),
382                        ("h", c_int)]
383        windll.s_ret_8i_func.restype = S8I
384        windll.s_ret_8i_func.argtypes = [S8I]
385        inp = S8I(9, 8, 7, 6, 5, 4, 3, 2)
386        s8i = windll.s_ret_8i_func(inp)
387        self.assertEqual(
388                (s8i.a, s8i.b, s8i.c, s8i.d, s8i.e, s8i.f, s8i.g, s8i.h),
389                (9*2, 8*3, 7*4, 6*5, 5*6, 4*7, 3*8, 2*9))
390
391    def test_sf1651235(self):
392        # see http://www.python.org/sf/1651235
393
394        proto = CFUNCTYPE(c_int, RECT, POINT)
395        def callback(*args):
396            return 0
397
398        callback = proto(callback)
399        self.assertRaises(ArgumentError, lambda: callback((1, 2, 3, 4), POINT()))
400
401if __name__ == '__main__':
402    unittest.main()
403