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