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 @need_symbol('c_longdouble') 132 def test_longdoubleresult(self): 133 f = dll._testfunc_D_bhilfD 134 f.argtypes = [c_byte, c_short, c_int, c_long, c_float, c_longdouble] 135 f.restype = c_longdouble 136 result = f(1, 2, 3, 4, 5.0, 6.0) 137 self.assertEqual(result, 21) 138 self.assertEqual(type(result), float) 139 140 result = f(-1, -2, -3, -4, -5.0, -6.0) 141 self.assertEqual(result, -21) 142 self.assertEqual(type(result), float) 143 144 @need_symbol('c_longlong') 145 def test_longlongresult(self): 146 f = dll._testfunc_q_bhilfd 147 f.restype = c_longlong 148 f.argtypes = [c_byte, c_short, c_int, c_long, c_float, c_double] 149 result = f(1, 2, 3, 4, 5.0, 6.0) 150 self.assertEqual(result, 21) 151 152 f = dll._testfunc_q_bhilfdq 153 f.restype = c_longlong 154 f.argtypes = [c_byte, c_short, c_int, c_long, c_float, c_double, c_longlong] 155 result = f(1, 2, 3, 4, 5.0, 6.0, 21) 156 self.assertEqual(result, 42) 157 158 def test_stringresult(self): 159 f = dll._testfunc_p_p 160 f.argtypes = None 161 f.restype = c_char_p 162 result = f(b"123") 163 self.assertEqual(result, b"123") 164 165 result = f(None) 166 self.assertEqual(result, None) 167 168 def test_pointers(self): 169 f = dll._testfunc_p_p 170 f.restype = POINTER(c_int) 171 f.argtypes = [POINTER(c_int)] 172 173 # This only works if the value c_int(42) passed to the 174 # function is still alive while the pointer (the result) is 175 # used. 176 177 v = c_int(42) 178 179 self.assertEqual(pointer(v).contents.value, 42) 180 result = f(pointer(v)) 181 self.assertEqual(type(result), POINTER(c_int)) 182 self.assertEqual(result.contents.value, 42) 183 184 # This on works... 185 result = f(pointer(v)) 186 self.assertEqual(result.contents.value, v.value) 187 188 p = pointer(c_int(99)) 189 result = f(p) 190 self.assertEqual(result.contents.value, 99) 191 192 arg = byref(v) 193 result = f(arg) 194 self.assertNotEqual(result.contents, v.value) 195 196 self.assertRaises(ArgumentError, f, byref(c_short(22))) 197 198 # It is dangerous, however, because you don't control the lifetime 199 # of the pointer: 200 result = f(byref(c_int(99))) 201 self.assertNotEqual(result.contents, 99) 202 203 ################################################################ 204 def test_shorts(self): 205 f = dll._testfunc_callback_i_if 206 207 args = [] 208 expected = [262144, 131072, 65536, 32768, 16384, 8192, 4096, 2048, 209 1024, 512, 256, 128, 64, 32, 16, 8, 4, 2, 1] 210 211 def callback(v): 212 args.append(v) 213 return v 214 215 CallBack = CFUNCTYPE(c_int, c_int) 216 217 cb = CallBack(callback) 218 f(2**18, cb) 219 self.assertEqual(args, expected) 220 221 ################################################################ 222 223 224 def test_callbacks(self): 225 f = dll._testfunc_callback_i_if 226 f.restype = c_int 227 f.argtypes = None 228 229 MyCallback = CFUNCTYPE(c_int, c_int) 230 231 def callback(value): 232 #print "called back with", value 233 return value 234 235 cb = MyCallback(callback) 236 result = f(-10, cb) 237 self.assertEqual(result, -18) 238 239 # test with prototype 240 f.argtypes = [c_int, MyCallback] 241 cb = MyCallback(callback) 242 result = f(-10, cb) 243 self.assertEqual(result, -18) 244 245 AnotherCallback = WINFUNCTYPE(c_int, c_int, c_int, c_int, c_int) 246 247 # check that the prototype works: we call f with wrong 248 # argument types 249 cb = AnotherCallback(callback) 250 self.assertRaises(ArgumentError, f, -10, cb) 251 252 253 def test_callbacks_2(self): 254 # Can also use simple datatypes as argument type specifiers 255 # for the callback function. 256 # In this case the call receives an instance of that type 257 f = dll._testfunc_callback_i_if 258 f.restype = c_int 259 260 MyCallback = CFUNCTYPE(c_int, c_int) 261 262 f.argtypes = [c_int, MyCallback] 263 264 def callback(value): 265 #print "called back with", value 266 self.assertEqual(type(value), int) 267 return value 268 269 cb = MyCallback(callback) 270 result = f(-10, cb) 271 self.assertEqual(result, -18) 272 273 @need_symbol('c_longlong') 274 def test_longlong_callbacks(self): 275 276 f = dll._testfunc_callback_q_qf 277 f.restype = c_longlong 278 279 MyCallback = CFUNCTYPE(c_longlong, c_longlong) 280 281 f.argtypes = [c_longlong, MyCallback] 282 283 def callback(value): 284 self.assertIsInstance(value, int) 285 return value & 0x7FFFFFFF 286 287 cb = MyCallback(callback) 288 289 self.assertEqual(13577625587, f(1000000000000, cb)) 290 291 def test_errors(self): 292 self.assertRaises(AttributeError, getattr, dll, "_xxx_yyy") 293 self.assertRaises(ValueError, c_int.in_dll, dll, "_xxx_yyy") 294 295 def test_byval(self): 296 297 # without prototype 298 ptin = POINT(1, 2) 299 ptout = POINT() 300 # EXPORT int _testfunc_byval(point in, point *pout) 301 result = dll._testfunc_byval(ptin, byref(ptout)) 302 got = result, ptout.x, ptout.y 303 expected = 3, 1, 2 304 self.assertEqual(got, expected) 305 306 # with prototype 307 ptin = POINT(101, 102) 308 ptout = POINT() 309 dll._testfunc_byval.argtypes = (POINT, POINTER(POINT)) 310 dll._testfunc_byval.restype = c_int 311 result = dll._testfunc_byval(ptin, byref(ptout)) 312 got = result, ptout.x, ptout.y 313 expected = 203, 101, 102 314 self.assertEqual(got, expected) 315 316 def test_struct_return_2H(self): 317 class S2H(Structure): 318 _fields_ = [("x", c_short), 319 ("y", c_short)] 320 dll.ret_2h_func.restype = S2H 321 dll.ret_2h_func.argtypes = [S2H] 322 inp = S2H(99, 88) 323 s2h = dll.ret_2h_func(inp) 324 self.assertEqual((s2h.x, s2h.y), (99*2, 88*3)) 325 326 @unittest.skipUnless(sys.platform == "win32", 'Windows-specific test') 327 def test_struct_return_2H_stdcall(self): 328 class S2H(Structure): 329 _fields_ = [("x", c_short), 330 ("y", c_short)] 331 332 windll.s_ret_2h_func.restype = S2H 333 windll.s_ret_2h_func.argtypes = [S2H] 334 s2h = windll.s_ret_2h_func(S2H(99, 88)) 335 self.assertEqual((s2h.x, s2h.y), (99*2, 88*3)) 336 337 def test_struct_return_8H(self): 338 class S8I(Structure): 339 _fields_ = [("a", c_int), 340 ("b", c_int), 341 ("c", c_int), 342 ("d", c_int), 343 ("e", c_int), 344 ("f", c_int), 345 ("g", c_int), 346 ("h", c_int)] 347 dll.ret_8i_func.restype = S8I 348 dll.ret_8i_func.argtypes = [S8I] 349 inp = S8I(9, 8, 7, 6, 5, 4, 3, 2) 350 s8i = dll.ret_8i_func(inp) 351 self.assertEqual((s8i.a, s8i.b, s8i.c, s8i.d, s8i.e, s8i.f, s8i.g, s8i.h), 352 (9*2, 8*3, 7*4, 6*5, 5*6, 4*7, 3*8, 2*9)) 353 354 @unittest.skipUnless(sys.platform == "win32", 'Windows-specific test') 355 def test_struct_return_8H_stdcall(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 windll.s_ret_8i_func.restype = S8I 366 windll.s_ret_8i_func.argtypes = [S8I] 367 inp = S8I(9, 8, 7, 6, 5, 4, 3, 2) 368 s8i = windll.s_ret_8i_func(inp) 369 self.assertEqual( 370 (s8i.a, s8i.b, s8i.c, s8i.d, s8i.e, s8i.f, s8i.g, s8i.h), 371 (9*2, 8*3, 7*4, 6*5, 5*6, 4*7, 3*8, 2*9)) 372 373 def test_sf1651235(self): 374 # see https://www.python.org/sf/1651235 375 376 proto = CFUNCTYPE(c_int, RECT, POINT) 377 def callback(*args): 378 return 0 379 380 callback = proto(callback) 381 self.assertRaises(ArgumentError, lambda: callback((1, 2, 3, 4), POINT())) 382 383if __name__ == '__main__': 384 unittest.main() 385