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