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