1 import unittest 2 from ctypes import * 3 import _ctypes_test 4 import sys 5 6 dll = CDLL(_ctypes_test.__file__) 7 8 try: 9 CALLBACK_FUNCTYPE = WINFUNCTYPE 10 except NameError: 11 # fake to enable this test on Linux 12 CALLBACK_FUNCTYPE = CFUNCTYPE 13 14 class POINT(Structure): 15 _fields_ = [("x", c_int), ("y", c_int)] 16 17 class BasicWrapTestCase(unittest.TestCase): 18 def wrap(self, param): 19 return param 20 21 def test_wchar_parm(self): 22 try: 23 c_wchar 24 except NameError: 25 return 26 f = dll._testfunc_i_bhilfd 27 f.argtypes = [c_byte, c_wchar, c_int, c_long, c_float, c_double] 28 result = f(self.wrap(1), self.wrap(u"x"), self.wrap(3), self.wrap(4), self.wrap(5.0), self.wrap(6.0)) 29 self.assertEqual(result, 139) 30 self.assertTrue(type(result), int) 31 32 def test_pointers(self): 33 f = dll._testfunc_p_p 34 f.restype = POINTER(c_int) 35 f.argtypes = [POINTER(c_int)] 36 37 # This only works if the value c_int(42) passed to the 38 # function is still alive while the pointer (the result) is 39 # used. 40 41 v = c_int(42) 42 43 self.assertEqual(pointer(v).contents.value, 42) 44 result = f(self.wrap(pointer(v))) 45 self.assertEqual(type(result), POINTER(c_int)) 46 self.assertEqual(result.contents.value, 42) 47 48 # This on works... 49 result = f(self.wrap(pointer(v))) 50 self.assertEqual(result.contents.value, v.value) 51 52 p = pointer(c_int(99)) 53 result = f(self.wrap(p)) 54 self.assertEqual(result.contents.value, 99) 55 56 def test_shorts(self): 57 f = dll._testfunc_callback_i_if 58 59 args = [] 60 expected = [262144, 131072, 65536, 32768, 16384, 8192, 4096, 2048, 61 1024, 512, 256, 128, 64, 32, 16, 8, 4, 2, 1] 62 63 def callback(v): 64 args.append(v) 65 return v 66 67 CallBack = CFUNCTYPE(c_int, c_int) 68 69 cb = CallBack(callback) 70 f(self.wrap(2**18), self.wrap(cb)) 71 self.assertEqual(args, expected) 72 73 ################################################################ 74 75 def test_callbacks(self): 76 f = dll._testfunc_callback_i_if 77 f.restype = c_int 78 f.argtypes = None 79 80 MyCallback = CFUNCTYPE(c_int, c_int) 81 82 def callback(value): 83 #print "called back with", value 84 return value 85 86 cb = MyCallback(callback) 87 88 result = f(self.wrap(-10), self.wrap(cb)) 89 self.assertEqual(result, -18) 90 91 # test with prototype 92 f.argtypes = [c_int, MyCallback] 93 cb = MyCallback(callback) 94 95 result = f(self.wrap(-10), self.wrap(cb)) 96 self.assertEqual(result, -18) 97 98 result = f(self.wrap(-10), self.wrap(cb)) 99 self.assertEqual(result, -18) 100 101 AnotherCallback = CALLBACK_FUNCTYPE(c_int, c_int, c_int, c_int, c_int) 102 103 # check that the prototype works: we call f with wrong 104 # argument types 105 cb = AnotherCallback(callback) 106 self.assertRaises(ArgumentError, f, self.wrap(-10), self.wrap(cb)) 107 108 def test_callbacks_2(self): 109 # Can also use simple datatypes as argument type specifiers 110 # for the callback function. 111 # In this case the call receives an instance of that type 112 f = dll._testfunc_callback_i_if 113 f.restype = c_int 114 115 MyCallback = CFUNCTYPE(c_int, c_int) 116 117 f.argtypes = [c_int, MyCallback] 118 119 def callback(value): 120 #print "called back with", value 121 self.assertEqual(type(value), int) 122 return value 123 124 cb = MyCallback(callback) 125 result = f(self.wrap(-10), self.wrap(cb)) 126 self.assertEqual(result, -18) 127 128 def test_longlong_callbacks(self): 129 130 f = dll._testfunc_callback_q_qf 131 f.restype = c_longlong 132 133 MyCallback = CFUNCTYPE(c_longlong, c_longlong) 134 135 f.argtypes = [c_longlong, MyCallback] 136 137 def callback(value): 138 self.assertTrue(isinstance(value, (int, long))) 139 return value & 0x7FFFFFFF 140 141 cb = MyCallback(callback) 142 143 self.assertEqual(13577625587, int(f(self.wrap(1000000000000), self.wrap(cb)))) 144 145 def test_byval(self): 146 # without prototype 147 ptin = POINT(1, 2) 148 ptout = POINT() 149 # EXPORT int _testfunc_byval(point in, point *pout) 150 result = dll._testfunc_byval(ptin, byref(ptout)) 151 got = result, ptout.x, ptout.y 152 expected = 3, 1, 2 153 self.assertEqual(got, expected) 154 155 # with prototype 156 ptin = POINT(101, 102) 157 ptout = POINT() 158 dll._testfunc_byval.argtypes = (POINT, POINTER(POINT)) 159 dll._testfunc_byval.restype = c_int 160 result = dll._testfunc_byval(self.wrap(ptin), byref(ptout)) 161 got = result, ptout.x, ptout.y 162 expected = 203, 101, 102 163 self.assertEqual(got, expected) 164 165 def test_struct_return_2H(self): 166 class S2H(Structure): 167 _fields_ = [("x", c_short), 168 ("y", c_short)] 169 dll.ret_2h_func.restype = S2H 170 dll.ret_2h_func.argtypes = [S2H] 171 inp = S2H(99, 88) 172 s2h = dll.ret_2h_func(self.wrap(inp)) 173 self.assertEqual((s2h.x, s2h.y), (99*2, 88*3)) 174 175 # This is known cdecl incompatibility between GCC 176 # and MSVC. It is addressed in GCC issue #36834. 177 # Python libffi detect it and complain. 178 @unittest.skipIf(sys.platform == "win32" and sys.version.find("GCC") >= 0, 'XFAIL GCC(mingw)') 179 def test_struct_return_8H(self): 180 class S8I(Structure): 181 _fields_ = [("a", c_int), 182 ("b", c_int), 183 ("c", c_int), 184 ("d", c_int), 185 ("e", c_int), 186 ("f", c_int), 187 ("g", c_int), 188 ("h", c_int)] 189 dll.ret_8i_func.restype = S8I 190 dll.ret_8i_func.argtypes = [S8I] 191 inp = S8I(9, 8, 7, 6, 5, 4, 3, 2) 192 s8i = dll.ret_8i_func(self.wrap(inp)) 193 self.assertEqual((s8i.a, s8i.b, s8i.c, s8i.d, s8i.e, s8i.f, s8i.g, s8i.h), 194 (9*2, 8*3, 7*4, 6*5, 5*6, 4*7, 3*8, 2*9)) 195 196 def test_recursive_as_param(self): 197 from ctypes import c_int 198 199 class A(object): 200 pass 201 202 a = A() 203 a._as_parameter_ = a 204 with self.assertRaises(RuntimeError): 205 c_int.from_param(a) 206 207 208 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 209 210 class AsParamWrapper(object): 211 def __init__(self, param): 212 self._as_parameter_ = param 213 214 class AsParamWrapperTestCase(BasicWrapTestCase): 215 wrap = AsParamWrapper 216 217 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 218 219 class AsParamPropertyWrapper(object): 220 def __init__(self, param): 221 self._param = param 222 223 def getParameter(self): 224 return self._param 225 _as_parameter_ = property(getParameter) 226 227 class AsParamPropertyWrapperTestCase(BasicWrapTestCase): 228 wrap = AsParamPropertyWrapper 229 230 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 231 232 if __name__ == '__main__': 233 unittest.main() 234