1from ctypes import * 2from ctypes.test import need_symbol 3import 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 25import _ctypes_test 26testdll = 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(). 31def 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 41def c_wbuffer(init): 42 n = len(init) + 1 43 return (c_wchar * n)(*init) 44 45class 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') 165class 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 206class 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 221if __name__ == '__main__': 222 unittest.main() 223