import py import sys class TestSimpleTypes: def setup_class(cls): import ctypes try: from _ctypes import set_conversion_mode except ImportError: pass else: cls.prev_conv_mode = set_conversion_mode("ascii", "strict") def teardown_class(cls): try: from _ctypes import set_conversion_mode except ImportError: pass else: set_conversion_mode(*cls.prev_conv_mode) def test_subclasses(self): from ctypes import c_void_p, c_char_p # ctypes 0.9.5 and before did overwrite from_param in SimpleType_new class CVOIDP(c_void_p): def from_param(cls, value): return value * 2 from_param = classmethod(from_param) class CCHARP(c_char_p): def from_param(cls, value): return value * 4 from_param = classmethod(from_param) assert CVOIDP.from_param("abc") == "abcabc" assert CCHARP.from_param("abc") == "abcabcabcabc" try: from ctypes import c_wchar_p except ImportError: return class CWCHARP(c_wchar_p): def from_param(cls, value): return value * 3 from_param = classmethod(from_param) assert CWCHARP.from_param("abc") == "abcabcabc" def test_pointer_subclasses(self): from ctypes import * Void_pp = POINTER(c_void_p) class My_void_p(c_void_p): pass My_void_pp = POINTER(My_void_p) o = My_void_pp() assert Void_pp.from_param(o) is o # XXX Replace by c_char_p tests def test_cstrings(self): py.test.skip("testing implementation internals") from ctypes import c_char_p, byref # c_char_p.from_param on a Python String packs the string # into a cparam object s = "123" assert c_char_p.from_param(s)._obj is s # new in 0.9.1: convert (encode) unicode to ascii assert c_char_p.from_param(u"123")._obj == "123" raises(UnicodeEncodeError, c_char_p.from_param, u"123\377") raises(TypeError, c_char_p.from_param, 42) # calling c_char_p.from_param with a c_char_p instance # returns the argument itself: a = c_char_p("123") assert c_char_p.from_param(a) is a def test_cw_strings(self): py.test.skip("testing implementation internals") from ctypes import byref try: from ctypes import c_wchar_p except ImportError: ## print "(No c_wchar_p)" return s = u"123" if sys.platform == "win32": assert c_wchar_p.from_param(s)._obj is s raises(TypeError, c_wchar_p.from_param, 42) # new in 0.9.1: convert (decode) ascii to unicode assert c_wchar_p.from_param("123")._obj == u"123" raises(UnicodeDecodeError, c_wchar_p.from_param, "123\377") pa = c_wchar_p.from_param(c_wchar_p(u"123")) assert type(pa) == c_wchar_p def test_int_pointers(self): from ctypes import c_short, c_uint, c_int, c_long, POINTER, pointer LPINT = POINTER(c_int) ## p = pointer(c_int(42)) ## x = LPINT.from_param(p) x = LPINT.from_param(pointer(c_int(42))) assert x.contents.value == 42 assert LPINT(c_int(42)).contents.value == 42 assert not LPINT.from_param(None) if c_int != c_long: raises(TypeError, LPINT.from_param, pointer(c_long(42))) raises(TypeError, LPINT.from_param, pointer(c_uint(42))) raises(TypeError, LPINT.from_param, pointer(c_short(42))) def test_byref_pointer(self): # The from_param class method of POINTER(typ) classes accepts what is # returned by byref(obj), it type(obj) == typ from ctypes import c_short, c_uint, c_int, c_long, pointer, POINTER, byref LPINT = POINTER(c_int) LPINT.from_param(byref(c_int(42))) raises(TypeError, LPINT.from_param, byref(c_short(22))) if c_int != c_long: raises(TypeError, LPINT.from_param, byref(c_long(22))) raises(TypeError, LPINT.from_param, byref(c_uint(22))) def test_byref_pointerpointer(self): # See above from ctypes import c_short, c_uint, c_int, c_long, pointer, POINTER, byref LPLPINT = POINTER(POINTER(c_int)) LPLPINT.from_param(byref(pointer(c_int(42)))) raises(TypeError, LPLPINT.from_param, byref(pointer(c_short(22)))) if c_int != c_long: raises(TypeError, LPLPINT.from_param, byref(pointer(c_long(22)))) raises(TypeError, LPLPINT.from_param, byref(pointer(c_uint(22)))) def test_array_pointers(self): from ctypes import c_short, c_uint, c_int, c_long, POINTER INTARRAY = c_int * 3 ia = INTARRAY() assert len(ia) == 3 assert [ia[i] for i in range(3)] == [0, 0, 0] # Pointers are only compatible with arrays containing items of # the same type! LPINT = POINTER(c_int) LPINT.from_param((c_int*3)()) raises(TypeError, LPINT.from_param, c_short*3) raises(TypeError, LPINT.from_param, c_long*3) raises(TypeError, LPINT.from_param, c_uint*3) ## def test_performance(self): ## check_perf() def test_noctypes_argtype(self): py.test.skip("we implement details differently") from ctypes import CDLL, c_void_p, ArgumentError import conftest dll = CDLL(str(conftest.sofile)) func = dll._testfunc_p_p func.restype = c_void_p # TypeError: has no from_param method raises(TypeError, setattr, func, "argtypes", (object,)) class Adapter(object): def from_param(cls, obj): return None func.argtypes = (Adapter(),) assert func(None) == None assert func(object()) == None class Adapter(object): def from_param(cls, obj): return obj func.argtypes = (Adapter(),) # don't know how to convert parameter 1 raises(ArgumentError, func, object()) assert func(c_void_p(42)) == 42 class Adapter(object): def from_param(cls, obj): raise ValueError(obj) func.argtypes = (Adapter(),) # ArgumentError: argument 1: ValueError: 99 raises(ArgumentError, func, 99) def test_multiple_signature(self): # when .argtypes is not set, calling a function with a certain # set of parameters should not prevent another call with # another set. from ctypes import CDLL, byref import conftest dll = CDLL(str(conftest.sofile)) func = dll._testfunc_p_p # This is call has too many arguments assert func(None, 1) == 0 # This one is normal assert func(None) == 0