1 from ctypes import * 2 from ctypes.test import need_symbol 3 import unittest 4 5 # IMPORTANT INFO: 6 # 7 # Consider this call: 8 # func.restype = c_char_p 9 # func(c_char_p("123")) 10 # It returns 11 # "123" 12 # 13 # WHY IS THIS SO? 14 # 15 # argument tuple (c_char_p("123"), ) is destroyed after the function 16 # func is called, but NOT before the result is actually built. 17 # 18 # If the arglist would be destroyed BEFORE the result has been built, 19 # the c_char_p("123") object would already have a zero refcount, 20 # and the pointer passed to (and returned by) the function would 21 # probably point to deallocated space. 22 # 23 # In this case, there would have to be an additional reference to the argument... 24 25 import _ctypes_test 26 testdll = CDLL(_ctypes_test.__file__) 27 28 # Return machine address `a` as a (possibly long) non-negative integer. 29 # Starting with Python 2.5, id(anything) is always non-negative, and 30 # the ctypes addressof() inherits that via PyLong_FromVoidPtr(). 31 def positive_address(a): 32 if a >= 0: 33 return a 34 # View the bits in `a` as unsigned instead. 35 import struct 36 num_bits = struct.calcsize("P") * 8 # num bits in native machine address 37 a += 1 << num_bits 38 assert a >= 0 39 return a 40 41 def c_wbuffer(init): 42 n = len(init) + 1 43 return (c_wchar * n)(*init) 44 45 class CharPointersTestCase(unittest.TestCase): 46 47 def setUp(self): 48 func = testdll._testfunc_p_p 49 func.restype = c_long 50 func.argtypes = None 51 52 def test_paramflags(self): 53 # function returns c_void_p result, 54 # and has a required parameter named 'input' 55 prototype = CFUNCTYPE(c_void_p, c_void_p) 56 func = prototype(("_testfunc_p_p", testdll), 57 ((1, "input"),)) 58 59 try: 60 func() 61 except TypeError as details: 62 self.assertEqual(str(details), "required argument 'input' missing") 63 else: 64 self.fail("TypeError not raised") 65 66 self.assertEqual(func(None), None) 67 self.assertEqual(func(input=None), None) 68 69 70 def test_int_pointer_arg(self): 71 func = testdll._testfunc_p_p 72 if sizeof(c_longlong) == sizeof(c_void_p): 73 func.restype = c_longlong 74 else: 75 func.restype = c_long 76 self.assertEqual(0, func(0)) 77 78 ci = c_int(0) 79 80 func.argtypes = POINTER(c_int), 81 self.assertEqual(positive_address(addressof(ci)), 82 positive_address(func(byref(ci)))) 83 84 func.argtypes = c_char_p, 85 self.assertRaises(ArgumentError, func, byref(ci)) 86 87 func.argtypes = POINTER(c_short), 88 self.assertRaises(ArgumentError, func, byref(ci)) 89 90 func.argtypes = POINTER(c_double), 91 self.assertRaises(ArgumentError, func, byref(ci)) 92 93 def test_POINTER_c_char_arg(self): 94 func = testdll._testfunc_p_p 95 func.restype = c_char_p 96 func.argtypes = POINTER(c_char), 97 98 self.assertEqual(None, func(None)) 99 self.assertEqual(b"123", func(b"123")) 100 self.assertEqual(None, func(c_char_p(None))) 101 self.assertEqual(b"123", func(c_char_p(b"123"))) 102 103 self.assertEqual(b"123", func(c_buffer(b"123"))) 104 ca = c_char(b"a") 105 self.assertEqual(ord(b"a"), func(pointer(ca))[0]) 106 self.assertEqual(ord(b"a"), func(byref(ca))[0]) 107 108 def test_c_char_p_arg(self): 109 func = testdll._testfunc_p_p 110 func.restype = c_char_p 111 func.argtypes = c_char_p, 112 113 self.assertEqual(None, func(None)) 114 self.assertEqual(b"123", func(b"123")) 115 self.assertEqual(None, func(c_char_p(None))) 116 self.assertEqual(b"123", func(c_char_p(b"123"))) 117 118 self.assertEqual(b"123", func(c_buffer(b"123"))) 119 ca = c_char(b"a") 120 self.assertEqual(ord(b"a"), func(pointer(ca))[0]) 121 self.assertEqual(ord(b"a"), func(byref(ca))[0]) 122 123 def test_c_void_p_arg(self): 124 func = testdll._testfunc_p_p 125 func.restype = c_char_p 126 func.argtypes = c_void_p, 127 128 self.assertEqual(None, func(None)) 129 self.assertEqual(b"123", func(b"123")) 130 self.assertEqual(b"123", func(c_char_p(b"123"))) 131 self.assertEqual(None, func(c_char_p(None))) 132 133 self.assertEqual(b"123", func(c_buffer(b"123"))) 134 ca = c_char(b"a") 135 self.assertEqual(ord(b"a"), func(pointer(ca))[0]) 136 self.assertEqual(ord(b"a"), func(byref(ca))[0]) 137 138 func(byref(c_int())) 139 func(pointer(c_int())) 140 func((c_int * 3)()) 141 142 @need_symbol('c_wchar_p') 143 def test_c_void_p_arg_with_c_wchar_p(self): 144 func = testdll._testfunc_p_p 145 func.restype = c_wchar_p 146 func.argtypes = c_void_p, 147 148 self.assertEqual(None, func(c_wchar_p(None))) 149 self.assertEqual("123", func(c_wchar_p("123"))) 150 151 def test_instance(self): 152 func = testdll._testfunc_p_p 153 func.restype = c_void_p 154 155 class X: 156 _as_parameter_ = None 157 158 func.argtypes = c_void_p, 159 self.assertEqual(None, func(X())) 160 161 func.argtypes = None 162 self.assertEqual(None, func(X())) 163 164 @need_symbol('c_wchar') 165 class WCharPointersTestCase(unittest.TestCase): 166 167 def setUp(self): 168 func = testdll._testfunc_p_p 169 func.restype = c_int 170 func.argtypes = None 171 172 173 def test_POINTER_c_wchar_arg(self): 174 func = testdll._testfunc_p_p 175 func.restype = c_wchar_p 176 func.argtypes = POINTER(c_wchar), 177 178 self.assertEqual(None, func(None)) 179 self.assertEqual("123", func("123")) 180 self.assertEqual(None, func(c_wchar_p(None))) 181 self.assertEqual("123", func(c_wchar_p("123"))) 182 183 self.assertEqual("123", func(c_wbuffer("123"))) 184 ca = c_wchar("a") 185 self.assertEqual("a", func(pointer(ca))[0]) 186 self.assertEqual("a", func(byref(ca))[0]) 187 188 def test_c_wchar_p_arg(self): 189 func = testdll._testfunc_p_p 190 func.restype = c_wchar_p 191 func.argtypes = c_wchar_p, 192 193 c_wchar_p.from_param("123") 194 195 self.assertEqual(None, func(None)) 196 self.assertEqual("123", func("123")) 197 self.assertEqual(None, func(c_wchar_p(None))) 198 self.assertEqual("123", func(c_wchar_p("123"))) 199 200 # XXX Currently, these raise TypeErrors, although they shouldn't: 201 self.assertEqual("123", func(c_wbuffer("123"))) 202 ca = c_wchar("a") 203 self.assertEqual("a", func(pointer(ca))[0]) 204 self.assertEqual("a", func(byref(ca))[0]) 205 206 class ArrayTest(unittest.TestCase): 207 def test(self): 208 func = testdll._testfunc_ai8 209 func.restype = POINTER(c_int) 210 func.argtypes = c_int * 8, 211 212 func((c_int * 8)(1, 2, 3, 4, 5, 6, 7, 8)) 213 214 # This did crash before: 215 216 def func(): pass 217 CFUNCTYPE(None, c_int * 3)(func) 218 219 ################################################################ 220 221 if __name__ == '__main__': 222 unittest.main() 223