from ctypes import * import unittest # IMPORTANT INFO: # # Consider this call: # func.restype = c_char_p # func(c_char_p("123")) # It returns # "123" # # WHY IS THIS SO? # # argument tuple (c_char_p("123"), ) is destroyed after the function # func is called, but NOT before the result is actually built. # # If the arglist would be destroyed BEFORE the result has been built, # the c_char_p("123") object would already have a zero refcount, # and the pointer passed to (and returned by) the function would # probably point to deallocated space. # # In this case, there would have to be an additional reference to the argument... import _ctypes_test testdll = CDLL(_ctypes_test.__file__) # Return machine address `a` as a (possibly long) non-negative integer. # Starting with Python 2.5, id(anything) is always non-negative, and # the ctypes addressof() inherits that via PyLong_FromVoidPtr(). def positive_address(a): if a >= 0: return a # View the bits in `a` as unsigned instead. import struct num_bits = struct.calcsize("P") * 8 # num bits in native machine address a += 1L << num_bits assert a >= 0 return a def c_wbuffer(init): n = len(init) + 1 return (c_wchar * n)(*init) class CharPointersTestCase(unittest.TestCase): def setUp(self): func = testdll._testfunc_p_p func.restype = c_long func.argtypes = None def test_int_pointer_arg(self): func = testdll._testfunc_p_p func.restype = c_long self.failUnlessEqual(0, func(0)) ci = c_int(0) func.argtypes = POINTER(c_int), self.failUnlessEqual(positive_address(addressof(ci)), positive_address(func(byref(ci)))) func.argtypes = c_char_p, self.assertRaises(ArgumentError, func, byref(ci)) func.argtypes = POINTER(c_short), self.assertRaises(ArgumentError, func, byref(ci)) func.argtypes = POINTER(c_double), self.assertRaises(ArgumentError, func, byref(ci)) def test_POINTER_c_char_arg(self): func = testdll._testfunc_p_p func.restype = c_char_p func.argtypes = POINTER(c_char), self.failUnlessEqual(None, func(None)) self.failUnlessEqual("123", func("123")) self.failUnlessEqual(None, func(c_char_p(None))) self.failUnlessEqual("123", func(c_char_p("123"))) self.failUnlessEqual("123", func(c_buffer("123"))) ca = c_char("a") self.failUnlessEqual("a", func(pointer(ca))[0]) self.failUnlessEqual("a", func(byref(ca))[0]) def test_c_char_p_arg(self): func = testdll._testfunc_p_p func.restype = c_char_p func.argtypes = c_char_p, self.failUnlessEqual(None, func(None)) self.failUnlessEqual("123", func("123")) self.failUnlessEqual(None, func(c_char_p(None))) self.failUnlessEqual("123", func(c_char_p("123"))) self.failUnlessEqual("123", func(c_buffer("123"))) ca = c_char("a") self.failUnlessEqual("a", func(pointer(ca))[0]) self.failUnlessEqual("a", func(byref(ca))[0]) def test_c_void_p_arg(self): func = testdll._testfunc_p_p func.restype = c_char_p func.argtypes = c_void_p, self.failUnlessEqual(None, func(None)) self.failUnlessEqual("123", func("123")) self.failUnlessEqual("123", func(c_char_p("123"))) self.failUnlessEqual(None, func(c_char_p(None))) self.failUnlessEqual("123", func(c_buffer("123"))) ca = c_char("a") self.failUnlessEqual("a", func(pointer(ca))[0]) self.failUnlessEqual("a", func(byref(ca))[0]) func(byref(c_int())) func(pointer(c_int())) func((c_int * 3)()) try: func.restype = c_wchar_p except NameError: pass else: self.failUnlessEqual(None, func(c_wchar_p(None))) self.failUnlessEqual(u"123", func(c_wchar_p(u"123"))) def test_instance(self): func = testdll._testfunc_p_p func.restype = c_void_p class X: _as_parameter_ = None func.argtypes = c_void_p, self.failUnlessEqual(None, func(X())) func.argtypes = None self.failUnlessEqual(None, func(X())) try: c_wchar except NameError: pass else: class WCharPointersTestCase(unittest.TestCase): def setUp(self): func = testdll._testfunc_p_p func.restype = c_int func.argtypes = None def test_POINTER_c_wchar_arg(self): func = testdll._testfunc_p_p func.restype = c_wchar_p func.argtypes = POINTER(c_wchar), self.failUnlessEqual(None, func(None)) self.failUnlessEqual(u"123", func(u"123")) self.failUnlessEqual(None, func(c_wchar_p(None))) self.failUnlessEqual(u"123", func(c_wchar_p(u"123"))) self.failUnlessEqual(u"123", func(c_wbuffer(u"123"))) ca = c_wchar("a") self.failUnlessEqual(u"a", func(pointer(ca))[0]) self.failUnlessEqual(u"a", func(byref(ca))[0]) def test_c_wchar_p_arg(self): func = testdll._testfunc_p_p func.restype = c_wchar_p func.argtypes = c_wchar_p, c_wchar_p.from_param(u"123") self.failUnlessEqual(None, func(None)) self.failUnlessEqual("123", func(u"123")) self.failUnlessEqual(None, func(c_wchar_p(None))) self.failUnlessEqual("123", func(c_wchar_p("123"))) # XXX Currently, these raise TypeErrors, although they shouldn't: self.failUnlessEqual("123", func(c_wbuffer("123"))) ca = c_wchar("a") self.failUnlessEqual("a", func(pointer(ca))[0]) self.failUnlessEqual("a", func(byref(ca))[0]) class ArrayTest(unittest.TestCase): def test(self): func = testdll._testfunc_ai8 func.restype = POINTER(c_int) func.argtypes = c_int * 8, func((c_int * 8)(1, 2, 3, 4, 5, 6, 7, 8)) # This did crash before: def func(): pass CFUNCTYPE(None, c_int * 3)(func) ################################################################ if __name__ == '__main__': unittest.main()