aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArmin Rigo <arigo@tunes.org>2020-08-30 11:24:28 +0200
committerArmin Rigo <arigo@tunes.org>2020-08-30 11:24:28 +0200
commit1422748bb7f0e3e72af0fc96fec8632f0c74539e (patch)
tree601bd3265e4f4f3c3089db01ae68b64ab93c1776
parentmerge heads (diff)
downloadpypy-1422748bb7f0e3e72af0fc96fec8632f0c74539e.tar.gz
pypy-1422748bb7f0e3e72af0fc96fec8632f0c74539e.tar.bz2
pypy-1422748bb7f0e3e72af0fc96fec8632f0c74539e.zip
add the tweaked test_c.py from cffi, which can now be run directly
-rw-r--r--extra_tests/cffi_tests/test_c.py4498
-rwxr-xr-xpypy/tool/import_cffi.py2
2 files changed, 4500 insertions, 0 deletions
diff --git a/extra_tests/cffi_tests/test_c.py b/extra_tests/cffi_tests/test_c.py
new file mode 100644
index 0000000000..e76950f4e5
--- /dev/null
+++ b/extra_tests/cffi_tests/test_c.py
@@ -0,0 +1,4498 @@
+import py
+import pytest
+
+def _setup_path():
+ import os, sys
+ sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))
+_setup_path()
+from _cffi_backend import *
+from _cffi_backend import _get_types, _get_common_types
+try:
+ from _cffi_backend import _testfunc
+except ImportError:
+ def _testfunc(num):
+ pytest.skip("_testunc() not available")
+from _cffi_backend import __version__
+
+# ____________________________________________________________
+
+import sys
+assert __version__ == "1.14.2", ("This test_c.py file is for testing a version"
+ " of cffi that differs from the one that we"
+ " get from 'import _cffi_backend'")
+if sys.version_info < (3,):
+ type_or_class = "type"
+ mandatory_b_prefix = ''
+ mandatory_u_prefix = 'u'
+ bytechr = chr
+ bitem2bchr = lambda x: x
+ class U(object):
+ def __add__(self, other):
+ return eval('u'+repr(other).replace(r'\\u', r'\u')
+ .replace(r'\\U', r'\U'))
+ u = U()
+ str2bytes = str
+ strict_compare = False
+else:
+ type_or_class = "class"
+ long = int
+ unicode = str
+ unichr = chr
+ mandatory_b_prefix = 'b'
+ mandatory_u_prefix = ''
+ bytechr = lambda n: bytes([n])
+ bitem2bchr = bytechr
+ u = ""
+ str2bytes = lambda s: bytes(s, "ascii")
+ strict_compare = True
+
+def size_of_int():
+ BInt = new_primitive_type("int")
+ return sizeof(BInt)
+
+def size_of_long():
+ BLong = new_primitive_type("long")
+ return sizeof(BLong)
+
+def size_of_ptr():
+ BInt = new_primitive_type("int")
+ BPtr = new_pointer_type(BInt)
+ return sizeof(BPtr)
+
+
+def find_and_load_library(name, flags=RTLD_NOW):
+ import ctypes.util
+ if name is None:
+ path = None
+ else:
+ path = ctypes.util.find_library(name)
+ if path is None and name == 'c':
+ assert sys.platform == 'win32'
+ assert (sys.version_info >= (3,) or
+ '__pypy__' in sys.builtin_module_names)
+ py.test.skip("dlopen(None) cannot work on Windows "
+ "with PyPy or Python 3")
+ return load_library(path, flags)
+
+def test_load_library():
+ x = find_and_load_library('c')
+ assert repr(x).startswith("<clibrary '")
+ x = find_and_load_library('c', RTLD_NOW | RTLD_GLOBAL)
+ assert repr(x).startswith("<clibrary '")
+ x = find_and_load_library('c', RTLD_LAZY)
+ assert repr(x).startswith("<clibrary '")
+
+def test_all_rtld_symbols():
+ import sys
+ FFI_DEFAULT_ABI # these symbols must be defined
+ FFI_CDECL
+ RTLD_LAZY
+ RTLD_NOW
+ RTLD_GLOBAL
+ RTLD_LOCAL
+ if sys.platform.startswith("linux"):
+ RTLD_NODELETE
+ RTLD_NOLOAD
+ RTLD_DEEPBIND
+
+def test_new_primitive_type():
+ py.test.raises(KeyError, new_primitive_type, "foo")
+ p = new_primitive_type("signed char")
+ assert repr(p) == "<ctype 'signed char'>"
+
+def check_dir(p, expected):
+ got = [name for name in dir(p) if not name.startswith('_')]
+ assert got == sorted(expected)
+
+def test_inspect_primitive_type():
+ p = new_primitive_type("signed char")
+ assert p.kind == "primitive"
+ assert p.cname == "signed char"
+ check_dir(p, ['cname', 'kind'])
+
+def test_cast_to_signed_char():
+ p = new_primitive_type("signed char")
+ x = cast(p, -65 + 17*256)
+ assert repr(x) == "<cdata 'signed char' -65>"
+ assert repr(type(x)) == "<%s '_cffi_backend._CDataBase'>" % type_or_class
+ assert int(x) == -65
+ x = cast(p, -66 + (1<<199)*256)
+ assert repr(x) == "<cdata 'signed char' -66>"
+ assert int(x) == -66
+ assert (x == cast(p, -66)) is True
+ assert (x != cast(p, -66)) is False
+ q = new_primitive_type("short")
+ assert (x == cast(q, -66)) is True
+ assert (x != cast(q, -66)) is False
+
+def test_sizeof_type():
+ py.test.raises(TypeError, sizeof, 42.5)
+ p = new_primitive_type("short")
+ assert sizeof(p) == 2
+
+def test_integer_types():
+ for name in ['signed char', 'short', 'int', 'long', 'long long']:
+ p = new_primitive_type(name)
+ size = sizeof(p)
+ min = -(1 << (8*size-1))
+ max = (1 << (8*size-1)) - 1
+ assert int(cast(p, min)) == min
+ assert int(cast(p, max)) == max
+ assert int(cast(p, min - 1)) == max
+ assert int(cast(p, max + 1)) == min
+ py.test.raises(TypeError, cast, p, None)
+ assert long(cast(p, min - 1)) == max
+ assert int(cast(p, b'\x08')) == 8
+ assert int(cast(p, u+'\x08')) == 8
+ for name in ['char', 'short', 'int', 'long', 'long long']:
+ p = new_primitive_type('unsigned ' + name)
+ size = sizeof(p)
+ max = (1 << (8*size)) - 1
+ assert int(cast(p, 0)) == 0
+ assert int(cast(p, max)) == max
+ assert int(cast(p, -1)) == max
+ assert int(cast(p, max + 1)) == 0
+ assert long(cast(p, -1)) == max
+ assert int(cast(p, b'\xFE')) == 254
+ assert int(cast(p, u+'\xFE')) == 254
+
+def test_no_float_on_int_types():
+ p = new_primitive_type('long')
+ py.test.raises(TypeError, float, cast(p, 42))
+ py.test.raises(TypeError, complex, cast(p, 42))
+
+def test_float_types():
+ INF = 1E200 * 1E200
+ for name in ["float", "double"]:
+ p = new_primitive_type(name)
+ assert bool(cast(p, 0)) is False # since 1.7
+ assert bool(cast(p, -0.0)) is False # since 1.7
+ assert bool(cast(p, 1e-42)) is True
+ assert bool(cast(p, -1e-42)) is True
+ assert bool(cast(p, INF))
+ assert bool(cast(p, -INF))
+ assert bool(cast(p, float("nan")))
+ assert int(cast(p, -150)) == -150
+ assert int(cast(p, 61.91)) == 61
+ assert long(cast(p, 61.91)) == 61
+ assert type(int(cast(p, 61.91))) is int
+ assert type(int(cast(p, 1E22))) is long
+ assert type(long(cast(p, 61.91))) is long
+ assert type(long(cast(p, 1E22))) is long
+ py.test.raises(OverflowError, int, cast(p, INF))
+ py.test.raises(OverflowError, int, cast(p, -INF))
+ assert float(cast(p, 1.25)) == 1.25
+ assert float(cast(p, INF)) == INF
+ assert float(cast(p, -INF)) == -INF
+ if name == "float":
+ assert float(cast(p, 1.1)) != 1.1 # rounding error
+ assert float(cast(p, 1E200)) == INF # limited range
+
+ assert cast(p, -1.1) == cast(p, -1.1)
+ assert repr(float(cast(p, -0.0))) == '-0.0'
+ assert float(cast(p, b'\x09')) == 9.0
+ assert float(cast(p, u+'\x09')) == 9.0
+ assert float(cast(p, True)) == 1.0
+ py.test.raises(TypeError, cast, p, None)
+
+def test_complex_types():
+ INF = 1E200 * 1E200
+ for name in ["float", "double"]:
+ p = new_primitive_type(name + " _Complex")
+ assert bool(cast(p, 0)) is False
+ assert bool(cast(p, INF))
+ assert bool(cast(p, -INF))
+ assert bool(cast(p, 0j)) is False
+ assert bool(cast(p, INF*1j))
+ assert bool(cast(p, -INF*1j))
+ # "can't convert complex to float", like CPython's "float(0j)"
+ py.test.raises(TypeError, int, cast(p, -150))
+ py.test.raises(TypeError, long, cast(p, -150))
+ py.test.raises(TypeError, float, cast(p, -150))
+ assert complex(cast(p, 1.25)) == 1.25
+ assert complex(cast(p, 1.25j)) == 1.25j
+ assert complex(cast(p, complex(0,INF))) == complex(0,INF)
+ assert complex(cast(p, -INF)) == -INF
+ if name == "float":
+ assert complex(cast(p, 1.1j)) != 1.1j # rounding error
+ assert complex(cast(p, 1E200+3j)) == INF+3j # limited range
+ assert complex(cast(p, complex(3,1E200))) == complex(3,INF) # limited range
+
+ assert cast(p, -1.1j) == cast(p, -1.1j)
+ assert repr(complex(cast(p, -0.0)).real) == '-0.0'
+ #assert repr(complex(cast(p, -0j))) == '-0j' # http://bugs.python.org/issue29602
+ assert complex(cast(p, b'\x09')) == 9.0 + 0j
+ assert complex(cast(p, u+'\x09')) == 9.0 + 0j
+ assert complex(cast(p, True)) == 1.0 + 0j
+ py.test.raises(TypeError, cast, p, None)
+ #
+ py.test.raises(TypeError, cast, new_primitive_type(name), 1+0j)
+ #
+ for basetype in ["char", "int", "uint64_t", "float",
+ "double", "long double"]:
+ baseobj = cast(new_primitive_type(basetype), 65)
+ py.test.raises(TypeError, complex, baseobj)
+ #
+ BArray = new_array_type(new_pointer_type(p), 10)
+ x = newp(BArray, None)
+ x[5] = 12.34 + 56.78j
+ assert type(x[5]) is complex
+ assert abs(x[5] - (12.34 + 56.78j)) < 1e-5
+ assert (x[5] == 12.34 + 56.78j) == (name == "double") # rounding error
+ #
+ class Foo:
+ def __complex__(self):
+ return 2 + 3j
+ assert complex(Foo()) == 2 + 3j
+ assert complex(cast(p, Foo())) == 2 + 3j
+ py.test.raises(TypeError, cast, new_primitive_type("int"), 1+0j)
+
+def test_character_type():
+ p = new_primitive_type("char")
+ assert bool(cast(p, 'A')) is True
+ assert bool(cast(p, '\x00')) is False # since 1.7
+ assert cast(p, '\x00') == cast(p, -17*256)
+ assert int(cast(p, 'A')) == 65
+ assert long(cast(p, 'A')) == 65
+ assert type(int(cast(p, 'A'))) is int
+ assert type(long(cast(p, 'A'))) is long
+ assert str(cast(p, 'A')) == repr(cast(p, 'A'))
+ assert repr(cast(p, 'A')) == "<cdata 'char' %s'A'>" % mandatory_b_prefix
+ assert repr(cast(p, 255)) == r"<cdata 'char' %s'\xff'>" % mandatory_b_prefix
+ assert repr(cast(p, 0)) == r"<cdata 'char' %s'\x00'>" % mandatory_b_prefix
+
+def test_pointer_type():
+ p = new_primitive_type("int")
+ assert repr(p) == "<ctype 'int'>"
+ p = new_pointer_type(p)
+ assert repr(p) == "<ctype 'int *'>"
+ p = new_pointer_type(p)
+ assert repr(p) == "<ctype 'int * *'>"
+ p = new_pointer_type(p)
+ assert repr(p) == "<ctype 'int * * *'>"
+
+def test_inspect_pointer_type():
+ p1 = new_primitive_type("int")
+ p2 = new_pointer_type(p1)
+ assert p2.kind == "pointer"
+ assert p2.cname == "int *"
+ assert p2.item is p1
+ check_dir(p2, ['cname', 'kind', 'item'])
+ p3 = new_pointer_type(p2)
+ assert p3.item is p2
+
+def test_pointer_to_int():
+ BInt = new_primitive_type("int")
+ py.test.raises(TypeError, newp, BInt)
+ py.test.raises(TypeError, newp, BInt, None)
+ BPtr = new_pointer_type(BInt)
+ p = newp(BPtr)
+ assert repr(p) == "<cdata 'int *' owning %d bytes>" % size_of_int()
+ p = newp(BPtr, None)
+ assert repr(p) == "<cdata 'int *' owning %d bytes>" % size_of_int()
+ p = newp(BPtr, 5000)
+ assert repr(p) == "<cdata 'int *' owning %d bytes>" % size_of_int()
+ q = cast(BPtr, p)
+ assert repr(q).startswith("<cdata 'int *' 0x")
+ assert p == q
+ assert hash(p) == hash(q)
+ e = py.test.raises(TypeError, newp, new_array_type(BPtr, None), None)
+ assert str(e.value) == (
+ "expected new array length or list/tuple/str, not NoneType")
+
+def test_pointer_bool():
+ BInt = new_primitive_type("int")
+ BPtr = new_pointer_type(BInt)
+ p = cast(BPtr, 0)
+ assert bool(p) is False
+ p = cast(BPtr, 42)
+ assert bool(p) is True
+
+def test_pointer_to_pointer():
+ BInt = new_primitive_type("int")
+ BPtr = new_pointer_type(BInt)
+ BPtrPtr = new_pointer_type(BPtr)
+ p = newp(BPtrPtr, None)
+ assert repr(p) == "<cdata 'int * *' owning %d bytes>" % size_of_ptr()
+
+def test_reading_pointer_to_int():
+ BInt = new_primitive_type("int")
+ BPtr = new_pointer_type(BInt)
+ p = newp(BPtr, None)
+ assert p[0] == 0
+ p = newp(BPtr, 5000)
+ assert p[0] == 5000
+ with pytest.raises(IndexError):
+ p[1]
+ with pytest.raises(IndexError):
+ p[-1]
+
+def test_reading_pointer_to_float():
+ BFloat = new_primitive_type("float")
+ py.test.raises(TypeError, newp, BFloat, None)
+ BPtr = new_pointer_type(BFloat)
+ p = newp(BPtr, None)
+ assert p[0] == 0.0 and type(p[0]) is float
+ p = newp(BPtr, 1.25)
+ assert p[0] == 1.25 and type(p[0]) is float
+ p = newp(BPtr, 1.1)
+ assert p[0] != 1.1 and abs(p[0] - 1.1) < 1E-5 # rounding errors
+
+def test_cast_float_to_int():
+ for type in ["int", "unsigned int", "long", "unsigned long",
+ "long long", "unsigned long long"]:
+ p = new_primitive_type(type)
+ assert int(cast(p, 4.2)) == 4
+ py.test.raises(TypeError, newp, new_pointer_type(p), 4.2)
+
+def test_newp_integer_types():
+ for name in ['signed char', 'short', 'int', 'long', 'long long']:
+ p = new_primitive_type(name)
+ pp = new_pointer_type(p)
+ size = sizeof(p)
+ min = -(1 << (8*size-1))
+ max = (1 << (8*size-1)) - 1
+ assert newp(pp, min)[0] == min
+ assert newp(pp, max)[0] == max
+ py.test.raises(OverflowError, newp, pp, min - 2 ** 32)
+ py.test.raises(OverflowError, newp, pp, min - 2 ** 64)
+ py.test.raises(OverflowError, newp, pp, max + 2 ** 32)
+ py.test.raises(OverflowError, newp, pp, max + 2 ** 64)
+ py.test.raises(OverflowError, newp, pp, min - 1)
+ py.test.raises(OverflowError, newp, pp, max + 1)
+ py.test.raises(OverflowError, newp, pp, min - 1 - 2 ** 32)
+ py.test.raises(OverflowError, newp, pp, min - 1 - 2 ** 64)
+ py.test.raises(OverflowError, newp, pp, max + 1)
+ py.test.raises(OverflowError, newp, pp, max + 1 + 2 ** 32)
+ py.test.raises(OverflowError, newp, pp, max + 1 + 2 ** 64)
+ py.test.raises(TypeError, newp, pp, 1.0)
+ for name in ['char', 'short', 'int', 'long', 'long long']:
+ p = new_primitive_type('unsigned ' + name)
+ pp = new_pointer_type(p)
+ size = sizeof(p)
+ max = (1 << (8*size)) - 1
+ assert newp(pp, 0)[0] == 0
+ assert newp(pp, max)[0] == max
+ py.test.raises(OverflowError, newp, pp, -1)
+ py.test.raises(OverflowError, newp, pp, max + 1)
+
+def test_reading_pointer_to_char():
+ BChar = new_primitive_type("char")
+ py.test.raises(TypeError, newp, BChar, None)
+ BPtr = new_pointer_type(BChar)
+ p = newp(BPtr, None)
+ assert p[0] == b'\x00'
+ p = newp(BPtr, b'A')
+ assert p[0] == b'A'
+ py.test.raises(TypeError, newp, BPtr, 65)
+ py.test.raises(TypeError, newp, BPtr, b"foo")
+ py.test.raises(TypeError, newp, BPtr, u+"foo")
+ c = cast(BChar, b'A')
+ assert str(c) == repr(c)
+ assert int(c) == ord(b'A')
+ py.test.raises(TypeError, cast, BChar, b'foo')
+ py.test.raises(TypeError, cast, BChar, u+'foo')
+ e = py.test.raises(TypeError, newp, new_array_type(BPtr, None), 12.3)
+ assert str(e.value) == (
+ "expected new array length or list/tuple/str, not float")
+
+def test_reading_pointer_to_pointer():
+ BVoidP = new_pointer_type(new_void_type())
+ BCharP = new_pointer_type(new_primitive_type("char"))
+ BInt = new_primitive_type("int")
+ BIntPtr = new_pointer_type(BInt)
+ BIntPtrPtr = new_pointer_type(BIntPtr)
+ q = newp(BIntPtr, 42)
+ assert q[0] == 42
+ p = newp(BIntPtrPtr, None)
+ assert p[0] is not None
+ assert p[0] == cast(BVoidP, 0)
+ assert p[0] == cast(BCharP, 0)
+ assert p[0] != None
+ assert repr(p[0]) == "<cdata 'int *' NULL>"
+ p[0] = q
+ assert p[0] != cast(BVoidP, 0)
+ assert p[0] != cast(BCharP, 0)
+ assert p[0][0] == 42
+ q[0] += 1
+ assert p[0][0] == 43
+ p = newp(BIntPtrPtr, q)
+ assert p[0][0] == 43
+
+def test_load_standard_library():
+ if sys.platform == "win32":
+ py.test.raises(OSError, find_and_load_library, None)
+ return
+ x = find_and_load_library(None)
+ BVoidP = new_pointer_type(new_void_type())
+ assert x.load_function(BVoidP, 'strcpy')
+ py.test.raises(AttributeError, x.load_function,
+ BVoidP, 'xxx_this_function_does_not_exist')
+ # the next one is from 'libm', not 'libc', but we assume
+ # that it is already loaded too, so it should work
+ assert x.load_function(BVoidP, 'sqrt')
+ #
+ x.close_lib()
+ py.test.raises(ValueError, x.load_function, BVoidP, 'sqrt')
+ x.close_lib()
+
+def test_no_len_on_nonarray():
+ p = new_primitive_type("int")
+ py.test.raises(TypeError, len, cast(p, 42))
+
+def test_cmp_none():
+ p = new_primitive_type("int")
+ x = cast(p, 42)
+ assert (x == None) is False
+ assert (x != None) is True
+ assert (x == ["hello"]) is False
+ assert (x != ["hello"]) is True
+ y = cast(p, 0)
+ assert (y == None) is False
+
+def test_invalid_indexing():
+ p = new_primitive_type("int")
+ x = cast(p, 42)
+ with pytest.raises(TypeError):
+ x[0]
+
+def test_default_str():
+ BChar = new_primitive_type("char")
+ x = cast(BChar, 42)
+ assert str(x) == repr(x)
+ BInt = new_primitive_type("int")
+ x = cast(BInt, 42)
+ assert str(x) == repr(x)
+ BArray = new_array_type(new_pointer_type(BInt), 10)
+ x = newp(BArray, None)
+ assert str(x) == repr(x)
+
+def test_default_unicode():
+ BInt = new_primitive_type("int")
+ x = cast(BInt, 42)
+ assert unicode(x) == unicode(repr(x))
+ BArray = new_array_type(new_pointer_type(BInt), 10)
+ x = newp(BArray, None)
+ assert unicode(x) == unicode(repr(x))
+
+def test_cast_from_cdataint():
+ BInt = new_primitive_type("int")
+ x = cast(BInt, 0)
+ y = cast(new_pointer_type(BInt), x)
+ assert bool(y) is False
+ #
+ x = cast(BInt, 42)
+ y = cast(BInt, x)
+ assert int(y) == 42
+ y = cast(new_primitive_type("char"), x)
+ assert int(y) == 42
+ y = cast(new_primitive_type("float"), x)
+ assert float(y) == 42.0
+ #
+ z = cast(BInt, 42.5)
+ assert int(z) == 42
+ z = cast(BInt, y)
+ assert int(z) == 42
+
+def test_void_type():
+ p = new_void_type()
+ assert p.kind == "void"
+ assert p.cname == "void"
+ check_dir(p, ['kind', 'cname'])
+
+def test_array_type():
+ p = new_primitive_type("int")
+ assert repr(p) == "<ctype 'int'>"
+ #
+ py.test.raises(TypeError, new_array_type, new_pointer_type(p), "foo")
+ py.test.raises(ValueError, new_array_type, new_pointer_type(p), -42)
+ #
+ p1 = new_array_type(new_pointer_type(p), None)
+ assert repr(p1) == "<ctype 'int[]'>"
+ py.test.raises(ValueError, new_array_type, new_pointer_type(p1), 42)
+ #
+ p1 = new_array_type(new_pointer_type(p), 42)
+ p2 = new_array_type(new_pointer_type(p1), 25)
+ assert repr(p2) == "<ctype 'int[25][42]'>"
+ p2 = new_array_type(new_pointer_type(p1), None)
+ assert repr(p2) == "<ctype 'int[][42]'>"
+ #
+ py.test.raises(OverflowError,
+ new_array_type, new_pointer_type(p), sys.maxsize+1)
+ py.test.raises(OverflowError,
+ new_array_type, new_pointer_type(p), sys.maxsize // 3)
+
+def test_inspect_array_type():
+ p = new_primitive_type("int")
+ p1 = new_array_type(new_pointer_type(p), None)
+ assert p1.kind == "array"
+ assert p1.cname == "int[]"
+ assert p1.item is p
+ assert p1.length is None
+ check_dir(p1, ['cname', 'kind', 'item', 'length'])
+ p1 = new_array_type(new_pointer_type(p), 42)
+ assert p1.kind == "array"
+ assert p1.cname == "int[42]"
+ assert p1.item is p
+ assert p1.length == 42
+ check_dir(p1, ['cname', 'kind', 'item', 'length'])
+
+def test_array_instance():
+ LENGTH = 1423
+ p = new_primitive_type("int")
+ p1 = new_array_type(new_pointer_type(p), LENGTH)
+ a = newp(p1, None)
+ assert repr(a) == "<cdata 'int[%d]' owning %d bytes>" % (
+ LENGTH, LENGTH * size_of_int())
+ assert len(a) == LENGTH
+ for i in range(LENGTH):
+ assert a[i] == 0
+ with pytest.raises(IndexError):
+ a[LENGTH]
+ with pytest.raises(IndexError):
+ a[-1]
+ for i in range(LENGTH):
+ a[i] = i * i + 1
+ for i in range(LENGTH):
+ assert a[i] == i * i + 1
+ with pytest.raises(IndexError) as e:
+ a[LENGTH+100] = 500
+ assert ('(expected %d < %d)' % (LENGTH+100, LENGTH)) in str(e.value)
+ py.test.raises(TypeError, int, a)
+
+def test_array_of_unknown_length_instance():
+ p = new_primitive_type("int")
+ p1 = new_array_type(new_pointer_type(p), None)
+ py.test.raises(TypeError, newp, p1, None)
+ py.test.raises(ValueError, newp, p1, -42)
+ a = newp(p1, 42)
+ assert len(a) == 42
+ for i in range(42):
+ a[i] -= i
+ for i in range(42):
+ assert a[i] == -i
+ with pytest.raises(IndexError):
+ a[42]
+ with pytest.raises(IndexError):
+ a[-1]
+ with pytest.raises(IndexError):
+ a[42] = 123
+ with pytest.raises(IndexError):
+ a[-1] = 456
+
+def test_array_of_unknown_length_instance_with_initializer():
+ p = new_primitive_type("int")
+ p1 = new_array_type(new_pointer_type(p), None)
+ a = newp(p1, list(range(42)))
+ assert len(a) == 42
+ a = newp(p1, tuple(range(142)))
+ assert len(a) == 142
+
+def test_array_initializer():
+ p = new_primitive_type("int")
+ p1 = new_array_type(new_pointer_type(p), None)
+ a = newp(p1, list(range(100, 142)))
+ for i in range(42):
+ assert a[i] == 100 + i
+ #
+ p2 = new_array_type(new_pointer_type(p), 43)
+ a = newp(p2, tuple(range(100, 142)))
+ for i in range(42):
+ assert a[i] == 100 + i
+ assert a[42] == 0 # extra uninitialized item
+
+def test_array_add():
+ p = new_primitive_type("int")
+ p1 = new_array_type(new_pointer_type(p), 5) # int[5]
+ p2 = new_array_type(new_pointer_type(p1), 3) # int[3][5]
+ a = newp(p2, [list(range(n, n+5)) for n in [100, 200, 300]])
+ assert repr(a) == "<cdata 'int[3][5]' owning %d bytes>" % (
+ 3*5*size_of_int(),)
+ assert repr(a + 0).startswith("<cdata 'int(*)[5]' 0x")
+ assert 0 + a == a + 0 != 1 + a == a + 1
+ assert repr(a[0]).startswith("<cdata 'int[5]' 0x")
+ assert repr((a + 0)[0]).startswith("<cdata 'int[5]' 0x")
+ assert repr(a[0] + 0).startswith("<cdata 'int *' 0x")
+ assert type(a[0][0]) is int
+ assert type((a[0] + 0)[0]) is int
+
+def test_array_sub():
+ BInt = new_primitive_type("int")
+ BArray = new_array_type(new_pointer_type(BInt), 5) # int[5]
+ a = newp(BArray, None)
+ p = a + 1
+ assert p - a == 1
+ assert p - (a+0) == 1
+ assert a == (p - 1)
+ BPtr = new_pointer_type(new_primitive_type("short"))
+ q = newp(BPtr, None)
+ with pytest.raises(TypeError):
+ p - q
+ with pytest.raises(TypeError):
+ q - p
+ with pytest.raises(TypeError):
+ a - q
+ with pytest.raises(TypeError) as e:
+ q - a
+ assert str(e.value) == "cannot subtract cdata 'short *' and cdata 'int *'"
+
+def test_ptr_sub_unaligned():
+ BInt = new_primitive_type("int")
+ BIntPtr = new_pointer_type(BInt)
+ a = cast(BIntPtr, 1240)
+ for bi in range(1430, 1438):
+ b = cast(BIntPtr, bi)
+ if ((bi - 1240) % size_of_int()) == 0:
+ assert b - a == (bi - 1240) // size_of_int()
+ assert a - b == (1240 - bi) // size_of_int()
+ else:
+ with pytest.raises(ValueError):
+ b - a
+ with pytest.raises(ValueError):
+ a - b
+
+def test_cast_primitive_from_cdata():
+ p = new_primitive_type("int")
+ n = cast(p, cast(p, -42))
+ assert int(n) == -42
+ #
+ p = new_primitive_type("unsigned int")
+ n = cast(p, cast(p, 42))
+ assert int(n) == 42
+ #
+ p = new_primitive_type("long long")
+ n = cast(p, cast(p, -(1<<60)))
+ assert int(n) == -(1<<60)
+ #
+ p = new_primitive_type("unsigned long long")
+ n = cast(p, cast(p, 1<<63))
+ assert int(n) == 1<<63
+ #
+ p = new_primitive_type("float")
+ n = cast(p, cast(p, 42.5))
+ assert float(n) == 42.5
+ #
+ p = new_primitive_type("char")
+ n = cast(p, cast(p, "A"))
+ assert int(n) == ord("A")
+
+def test_new_primitive_from_cdata():
+ p = new_primitive_type("int")
+ p1 = new_pointer_type(p)
+ n = newp(p1, cast(p, -42))
+ assert n[0] == -42
+ #
+ p = new_primitive_type("unsigned int")
+ p1 = new_pointer_type(p)
+ n = newp(p1, cast(p, 42))
+ assert n[0] == 42
+ #
+ p = new_primitive_type("float")
+ p1 = new_pointer_type(p)
+ n = newp(p1, cast(p, 42.5))
+ assert n[0] == 42.5
+ #
+ p = new_primitive_type("char")
+ p1 = new_pointer_type(p)
+ n = newp(p1, cast(p, "A"))
+ assert n[0] == b"A"
+
+def test_cast_between_pointers():
+ BIntP = new_pointer_type(new_primitive_type("int"))
+ BIntA = new_array_type(BIntP, None)
+ a = newp(BIntA, [40, 41, 42, 43, 44])
+ BShortP = new_pointer_type(new_primitive_type("short"))
+ b = cast(BShortP, a)
+ c = cast(BIntP, b)
+ assert c[3] == 43
+ BLongLong = new_primitive_type("long long")
+ d = cast(BLongLong, c)
+ e = cast(BIntP, d)
+ assert e[3] == 43
+ f = cast(BIntP, int(d))
+ assert f[3] == 43
+ #
+ b = cast(BShortP, 0)
+ assert not b
+ c = cast(BIntP, b)
+ assert not c
+ assert int(cast(BLongLong, c)) == 0
+
+def test_alignof():
+ BInt = new_primitive_type("int")
+ assert alignof(BInt) == sizeof(BInt)
+ BPtr = new_pointer_type(BInt)
+ assert alignof(BPtr) == sizeof(BPtr)
+ BArray = new_array_type(BPtr, None)
+ assert alignof(BArray) == alignof(BInt)
+
+def test_new_struct_type():
+ BStruct = new_struct_type("foo")
+ assert repr(BStruct) == "<ctype 'foo'>"
+ BStruct = new_struct_type("struct foo")
+ assert repr(BStruct) == "<ctype 'struct foo'>"
+ BPtr = new_pointer_type(BStruct)
+ assert repr(BPtr) == "<ctype 'struct foo *'>"
+ py.test.raises(ValueError, sizeof, BStruct)
+ py.test.raises(ValueError, alignof, BStruct)
+
+def test_new_union_type():
+ BUnion = new_union_type("union foo")
+ assert repr(BUnion) == "<ctype 'union foo'>"
+ BPtr = new_pointer_type(BUnion)
+ assert repr(BPtr) == "<ctype 'union foo *'>"
+
+def test_complete_struct():
+ BLong = new_primitive_type("long")
+ BChar = new_primitive_type("char")
+ BShort = new_primitive_type("short")
+ BStruct = new_struct_type("struct foo")
+ assert BStruct.kind == "struct"
+ assert BStruct.cname == "struct foo"
+ assert BStruct.fields is None
+ check_dir(BStruct, ['cname', 'kind', 'fields'])
+ #
+ complete_struct_or_union(BStruct, [('a1', BLong, -1),
+ ('a2', BChar, -1),
+ ('a3', BShort, -1)])
+ d = BStruct.fields
+ assert len(d) == 3
+ assert d[0][0] == 'a1'
+ assert d[0][1].type is BLong
+ assert d[0][1].offset == 0
+ assert d[0][1].bitshift == -1
+ assert d[0][1].bitsize == -1
+ assert d[1][0] == 'a2'
+ assert d[1][1].type is BChar
+ assert d[1][1].offset == sizeof(BLong)
+ assert d[1][1].bitshift == -1
+ assert d[1][1].bitsize == -1
+ assert d[2][0] == 'a3'
+ assert d[2][1].type is BShort
+ assert d[2][1].offset == sizeof(BLong) + sizeof(BShort)
+ assert d[2][1].bitshift == -1
+ assert d[2][1].bitsize == -1
+ assert sizeof(BStruct) == 2 * sizeof(BLong)
+ assert alignof(BStruct) == alignof(BLong)
+
+def test_complete_union():
+ BLong = new_primitive_type("long")
+ BChar = new_primitive_type("char")
+ BUnion = new_union_type("union foo")
+ assert BUnion.kind == "union"
+ assert BUnion.cname == "union foo"
+ assert BUnion.fields is None
+ complete_struct_or_union(BUnion, [('a1', BLong, -1),
+ ('a2', BChar, -1)])
+ d = BUnion.fields
+ assert len(d) == 2
+ assert d[0][0] == 'a1'
+ assert d[0][1].type is BLong
+ assert d[0][1].offset == 0
+ assert d[1][0] == 'a2'
+ assert d[1][1].type is BChar
+ assert d[1][1].offset == 0
+ assert sizeof(BUnion) == sizeof(BLong)
+ assert alignof(BUnion) == alignof(BLong)
+
+def test_struct_instance():
+ BInt = new_primitive_type("int")
+ BStruct = new_struct_type("struct foo")
+ BStructPtr = new_pointer_type(BStruct)
+ p = cast(BStructPtr, 42)
+ with pytest.raises(AttributeError) as e:
+ p.a1 # opaque
+ assert str(e.value) == ("cdata 'struct foo *' points to an opaque type: "
+ "cannot read fields")
+ with pytest.raises(AttributeError) as e:
+ p.a1 = 10 # opaque
+ assert str(e.value) == ("cdata 'struct foo *' points to an opaque type: "
+ "cannot write fields")
+
+ complete_struct_or_union(BStruct, [('a1', BInt, -1),
+ ('a2', BInt, -1)])
+ p = newp(BStructPtr, None)
+ s = p[0]
+ assert s.a1 == 0
+ s.a2 = 123
+ assert s.a1 == 0
+ assert s.a2 == 123
+ with pytest.raises(OverflowError):
+ s.a1 = sys.maxsize+1
+ assert s.a1 == 0
+ with pytest.raises(AttributeError) as e:
+ p.foobar
+ assert str(e.value) == "cdata 'struct foo *' has no field 'foobar'"
+ with pytest.raises(AttributeError) as e:
+ p.foobar = 42
+ assert str(e.value) == "cdata 'struct foo *' has no field 'foobar'"
+ with pytest.raises(AttributeError) as e:
+ s.foobar
+ assert str(e.value) == "cdata 'struct foo' has no field 'foobar'"
+ with pytest.raises(AttributeError) as e:
+ s.foobar = 42
+ assert str(e.value) == "cdata 'struct foo' has no field 'foobar'"
+ j = cast(BInt, 42)
+ with pytest.raises(AttributeError) as e:
+ j.foobar
+ assert str(e.value) == "cdata 'int' has no attribute 'foobar'"
+ with pytest.raises(AttributeError) as e:
+ j.foobar = 42
+ assert str(e.value) == "cdata 'int' has no attribute 'foobar'"
+ j = cast(new_pointer_type(BInt), 42)
+ with pytest.raises(AttributeError) as e:
+ j.foobar
+ assert str(e.value) == "cdata 'int *' has no attribute 'foobar'"
+ with pytest.raises(AttributeError) as e:
+ j.foobar = 42
+ assert str(e.value) == "cdata 'int *' has no attribute 'foobar'"
+ pp = newp(new_pointer_type(BStructPtr), p)
+ with pytest.raises(AttributeError) as e:
+ pp.a1
+ assert str(e.value) == "cdata 'struct foo * *' has no attribute 'a1'"
+ with pytest.raises(AttributeError) as e:
+ pp.a1 = 42
+ assert str(e.value) == "cdata 'struct foo * *' has no attribute 'a1'"
+
+def test_union_instance():
+ BInt = new_primitive_type("int")
+ BUInt = new_primitive_type("unsigned int")
+ BUnion = new_union_type("union bar")
+ complete_struct_or_union(BUnion, [('a1', BInt, -1), ('a2', BUInt, -1)])
+ p = newp(new_pointer_type(BUnion), [-42])
+ bigval = -42 + (1 << (8*size_of_int()))
+ assert p.a1 == -42
+ assert p.a2 == bigval
+ p = newp(new_pointer_type(BUnion), {'a2': bigval})
+ assert p.a1 == -42
+ assert p.a2 == bigval
+ py.test.raises(OverflowError, newp, new_pointer_type(BUnion),
+ {'a1': bigval})
+ p = newp(new_pointer_type(BUnion), [])
+ assert p.a1 == p.a2 == 0
+
+def test_struct_pointer():
+ BInt = new_primitive_type("int")
+ BStruct = new_struct_type("struct foo")
+ BStructPtr = new_pointer_type(BStruct)
+ complete_struct_or_union(BStruct, [('a1', BInt, -1),
+ ('a2', BInt, -1)])
+ p = newp(BStructPtr, None)
+ assert p.a1 == 0 # read/write via the pointer (C equivalent: '->')
+ p.a2 = 123
+ assert p.a1 == 0
+ assert p.a2 == 123
+
+def test_struct_init_list():
+ BVoidP = new_pointer_type(new_void_type())
+ BInt = new_primitive_type("int")
+ BIntPtr = new_pointer_type(BInt)
+ BStruct = new_struct_type("struct foo")
+ BStructPtr = new_pointer_type(BStruct)
+ complete_struct_or_union(BStruct, [('a1', BInt, -1),
+ ('a2', BInt, -1),
+ ('a3', BInt, -1),
+ ('p4', BIntPtr, -1)])
+ s = newp(BStructPtr, [123, 456])
+ assert s.a1 == 123
+ assert s.a2 == 456
+ assert s.a3 == 0
+ assert s.p4 == cast(BVoidP, 0)
+ assert s.p4 != 0
+ #
+ s = newp(BStructPtr, {'a2': 41122, 'a3': -123})
+ assert s.a1 == 0
+ assert s.a2 == 41122
+ assert s.a3 == -123
+ assert s.p4 == cast(BVoidP, 0)
+ #
+ py.test.raises(KeyError, newp, BStructPtr, {'foobar': 0})
+ #
+ p = newp(BIntPtr, 14141)
+ s = newp(BStructPtr, [12, 34, 56, p])
+ assert s.p4 == p
+ assert s.p4
+ #
+ s = newp(BStructPtr, [12, 34, 56, cast(BVoidP, 0)])
+ assert s.p4 == cast(BVoidP, 0)
+ assert not s.p4
+ #
+ py.test.raises(TypeError, newp, BStructPtr, [12, 34, 56, None])
+
+def test_array_in_struct():
+ BInt = new_primitive_type("int")
+ BStruct = new_struct_type("struct foo")
+ BArrayInt5 = new_array_type(new_pointer_type(BInt), 5)
+ complete_struct_or_union(BStruct, [('a1', BArrayInt5, -1)])
+ s = newp(new_pointer_type(BStruct), [[20, 24, 27, 29, 30]])
+ assert s.a1[2] == 27
+ assert repr(s.a1).startswith("<cdata 'int[5]' 0x")
+
+def test_offsetof():
+ def offsetof(BType, fieldname):
+ return typeoffsetof(BType, fieldname)[1]
+ BInt = new_primitive_type("int")
+ BStruct = new_struct_type("struct foo")
+ py.test.raises(TypeError, offsetof, BInt, "abc")
+ py.test.raises(TypeError, offsetof, BStruct, "abc")
+ complete_struct_or_union(BStruct, [('abc', BInt, -1), ('def', BInt, -1)])
+ assert offsetof(BStruct, 'abc') == 0
+ assert offsetof(BStruct, 'def') == size_of_int()
+ py.test.raises(KeyError, offsetof, BStruct, "ghi")
+ assert offsetof(new_pointer_type(BStruct), "def") == size_of_int()
+
+def test_function_type():
+ BInt = new_primitive_type("int")
+ BFunc = new_function_type((BInt, BInt), BInt, False)
+ assert repr(BFunc) == "<ctype 'int(*)(int, int)'>"
+ BFunc2 = new_function_type((), BFunc, False)
+ assert repr(BFunc2) == "<ctype 'int(*(*)())(int, int)'>"
+
+def test_inspect_function_type():
+ BInt = new_primitive_type("int")
+ BFunc = new_function_type((BInt, BInt), BInt, False)
+ assert BFunc.kind == "function"
+ assert BFunc.cname == "int(*)(int, int)"
+ assert BFunc.args == (BInt, BInt)
+ assert BFunc.result is BInt
+ assert BFunc.ellipsis is False
+ assert BFunc.abi == FFI_DEFAULT_ABI
+
+def test_function_type_taking_struct():
+ BChar = new_primitive_type("char")
+ BShort = new_primitive_type("short")
+ BStruct = new_struct_type("struct foo")
+ complete_struct_or_union(BStruct, [('a1', BChar, -1),
+ ('a2', BShort, -1)])
+ BFunc = new_function_type((BStruct,), BShort, False)
+ assert repr(BFunc) == "<ctype 'short(*)(struct foo)'>"
+
+def test_function_void_result():
+ BVoid = new_void_type()
+ BInt = new_primitive_type("int")
+ BFunc = new_function_type((BInt, BInt), BVoid, False)
+ assert repr(BFunc) == "<ctype 'void(*)(int, int)'>"
+
+def test_function_void_arg():
+ BVoid = new_void_type()
+ BInt = new_primitive_type("int")
+ py.test.raises(TypeError, new_function_type, (BVoid,), BInt, False)
+
+def test_call_function_0():
+ BSignedChar = new_primitive_type("signed char")
+ BFunc0 = new_function_type((BSignedChar, BSignedChar), BSignedChar, False)
+ f = cast(BFunc0, _testfunc(0))
+ assert f(40, 2) == 42
+ assert f(-100, -100) == -200 + 256
+ py.test.raises(OverflowError, f, 128, 0)
+ py.test.raises(OverflowError, f, 0, 128)
+
+def test_call_function_0_pretend_bool_result():
+ BSignedChar = new_primitive_type("signed char")
+ BBool = new_primitive_type("_Bool")
+ BFunc0 = new_function_type((BSignedChar, BSignedChar), BBool, False)
+ f = cast(BFunc0, _testfunc(0))
+ assert f(40, -39) is True
+ assert f(40, -40) is False
+ py.test.raises(ValueError, f, 40, 2)
+
+def test_call_function_1():
+ BInt = new_primitive_type("int")
+ BLong = new_primitive_type("long")
+ BFunc1 = new_function_type((BInt, BLong), BLong, False)
+ f = cast(BFunc1, _testfunc(1))
+ assert f(40, 2) == 42
+ assert f(-100, -100) == -200
+ int_max = (1 << (8*size_of_int()-1)) - 1
+ long_max = (1 << (8*size_of_long()-1)) - 1
+ if int_max == long_max:
+ assert f(int_max, 1) == - int_max - 1
+ else:
+ assert f(int_max, 1) == int_max + 1
+
+def test_call_function_2():
+ BLongLong = new_primitive_type("long long")
+ BFunc2 = new_function_type((BLongLong, BLongLong), BLongLong, False)
+ f = cast(BFunc2, _testfunc(2))
+ longlong_max = (1 << (8*sizeof(BLongLong)-1)) - 1
+ assert f(longlong_max - 42, 42) == longlong_max
+ assert f(43, longlong_max - 42) == - longlong_max - 1
+
+def test_call_function_3():
+ BFloat = new_primitive_type("float")
+ BDouble = new_primitive_type("double")
+ BFunc3 = new_function_type((BFloat, BDouble), BDouble, False)
+ f = cast(BFunc3, _testfunc(3))
+ assert f(1.25, 5.1) == 1.25 + 5.1 # exact
+ res = f(1.3, 5.1)
+ assert res != 6.4 and abs(res - 6.4) < 1E-5 # inexact
+
+def test_call_function_4():
+ BFloat = new_primitive_type("float")
+ BDouble = new_primitive_type("double")
+ BFunc4 = new_function_type((BFloat, BDouble), BFloat, False)
+ f = cast(BFunc4, _testfunc(4))
+ res = f(1.25, 5.1)
+ assert res != 6.35 and abs(res - 6.35) < 1E-5 # inexact
+
+def test_call_function_5():
+ BVoid = new_void_type()
+ BFunc5 = new_function_type((), BVoid, False)
+ f = cast(BFunc5, _testfunc(5))
+ f() # did not crash
+
+def test_call_function_6():
+ BInt = new_primitive_type("int")
+ BIntPtr = new_pointer_type(BInt)
+ BFunc6 = new_function_type((BIntPtr,), BIntPtr, False)
+ f = cast(BFunc6, _testfunc(6))
+ x = newp(BIntPtr, 42)
+ res = f(x)
+ assert typeof(res) is BIntPtr
+ assert res[0] == 42 - 1000
+ #
+ BIntArray = new_array_type(BIntPtr, None)
+ BFunc6bis = new_function_type((BIntArray,), BIntPtr, False)
+ f = cast(BFunc6bis, _testfunc(6))
+ #
+ res = f([142])
+ assert typeof(res) is BIntPtr
+ assert res[0] == 142 - 1000
+ #
+ res = f((143,))
+ assert typeof(res) is BIntPtr
+ assert res[0] == 143 - 1000
+ #
+ x = newp(BIntArray, [242])
+ res = f(x)
+ assert typeof(res) is BIntPtr
+ assert res[0] == 242 - 1000
+ #
+ py.test.raises(TypeError, f, 123456)
+ py.test.raises(TypeError, f, "foo")
+ py.test.raises(TypeError, f, u+"bar")
+
+def test_call_function_7():
+ BChar = new_primitive_type("char")
+ BShort = new_primitive_type("short")
+ BStruct = new_struct_type("struct foo")
+ BStructPtr = new_pointer_type(BStruct)
+ complete_struct_or_union(BStruct, [('a1', BChar, -1),
+ ('a2', BShort, -1)])
+ BFunc7 = new_function_type((BStruct,), BShort, False)
+ f = cast(BFunc7, _testfunc(7))
+ res = f({'a1': b'A', 'a2': -4042})
+ assert res == -4042 + ord(b'A')
+ #
+ x = newp(BStructPtr, {'a1': b'A', 'a2': -4042})
+ res = f(x[0])
+ assert res == -4042 + ord(b'A')
+
+def test_call_function_20():
+ BChar = new_primitive_type("char")
+ BShort = new_primitive_type("short")
+ BStruct = new_struct_type("struct foo")
+ BStructPtr = new_pointer_type(BStruct)
+ complete_struct_or_union(BStruct, [('a1', BChar, -1),
+ ('a2', BShort, -1)])
+ BFunc20 = new_function_type((BStructPtr,), BShort, False)
+ f = cast(BFunc20, _testfunc(20))
+ x = newp(BStructPtr, {'a1': b'A', 'a2': -4042})
+ # can't pass a 'struct foo'
+ py.test.raises(TypeError, f, x[0])
+
+def test_call_function_21():
+ BInt = new_primitive_type("int")
+ BStruct = new_struct_type("struct foo")
+ complete_struct_or_union(BStruct, [('a', BInt, -1),
+ ('b', BInt, -1),
+ ('c', BInt, -1),
+ ('d', BInt, -1),
+ ('e', BInt, -1),
+ ('f', BInt, -1),
+ ('g', BInt, -1),
+ ('h', BInt, -1),
+ ('i', BInt, -1),
+ ('j', BInt, -1)])
+ BFunc21 = new_function_type((BStruct,), BInt, False)
+ f = cast(BFunc21, _testfunc(21))
+ res = f(list(range(13, 3, -1)))
+ lst = [(n << i) for (i, n) in enumerate(range(13, 3, -1))]
+ assert res == sum(lst)
+
+def test_call_function_22():
+ BInt = new_primitive_type("int")
+ BArray10 = new_array_type(new_pointer_type(BInt), 10)
+ BStruct = new_struct_type("struct foo")
+ BStructP = new_pointer_type(BStruct)
+ complete_struct_or_union(BStruct, [('a', BArray10, -1)])
+ BFunc22 = new_function_type((BStruct, BStruct), BStruct, False)
+ f = cast(BFunc22, _testfunc(22))
+ p1 = newp(BStructP, {'a': list(range(100, 110))})
+ p2 = newp(BStructP, {'a': list(range(1000, 1100, 10))})
+ res = f(p1[0], p2[0])
+ for i in range(10):
+ assert res.a[i] == p1.a[i] - p2.a[i]
+
+def test_call_function_23():
+ BVoid = new_void_type() # declaring the function as int(void*)
+ BVoidP = new_pointer_type(BVoid)
+ BInt = new_primitive_type("int")
+ BFunc23 = new_function_type((BVoidP,), BInt, False)
+ f = cast(BFunc23, _testfunc(23))
+ res = f(b"foo")
+ assert res == 1000 * ord(b'f')
+ res = f(cast(BVoidP, 0)) # NULL
+ assert res == -42
+ py.test.raises(TypeError, f, None)
+ py.test.raises(TypeError, f, 0)
+ py.test.raises(TypeError, f, 0.0)
+
+def test_call_function_23_bis():
+ # declaring the function as int(unsigned char*)
+ BUChar = new_primitive_type("unsigned char")
+ BUCharP = new_pointer_type(BUChar)
+ BInt = new_primitive_type("int")
+ BFunc23 = new_function_type((BUCharP,), BInt, False)
+ f = cast(BFunc23, _testfunc(23))
+ res = f(b"foo")
+ assert res == 1000 * ord(b'f')
+
+def test_call_function_23_bool_array():
+ # declaring the function as int(_Bool*)
+ BBool = new_primitive_type("_Bool")
+ BBoolP = new_pointer_type(BBool)
+ BInt = new_primitive_type("int")
+ BFunc23 = new_function_type((BBoolP,), BInt, False)
+ f = cast(BFunc23, _testfunc(23))
+ res = f(b"\x01\x01")
+ assert res == 1000
+ py.test.raises(ValueError, f, b"\x02\x02")
+
+def test_cannot_pass_struct_with_array_of_length_0():
+ BInt = new_primitive_type("int")
+ BArray0 = new_array_type(new_pointer_type(BInt), 0)
+ BStruct = new_struct_type("struct foo")
+ BStructP = new_pointer_type(BStruct)
+ complete_struct_or_union(BStruct, [('a', BArray0)])
+ BFunc = new_function_type((BStruct,), BInt, False)
+ py.test.raises(NotImplementedError, cast(BFunc, 123), cast(BStructP, 123))
+ BFunc2 = new_function_type((BInt,), BStruct, False)
+ py.test.raises(NotImplementedError, cast(BFunc2, 123), 123)
+
+def test_call_function_9():
+ BInt = new_primitive_type("int")
+ BFunc9 = new_function_type((BInt,), BInt, True) # vararg
+ f = cast(BFunc9, _testfunc(9))
+ assert f(0) == 0
+ assert f(1, cast(BInt, 42)) == 42
+ assert f(2, cast(BInt, 40), cast(BInt, 2)) == 42
+ py.test.raises(TypeError, f, 1, 42)
+ py.test.raises(TypeError, f, 2, None)
+ # promotion of chars and shorts to ints
+ BSChar = new_primitive_type("signed char")
+ BUChar = new_primitive_type("unsigned char")
+ BSShort = new_primitive_type("short")
+ assert f(3, cast(BSChar, -3), cast(BUChar, 200), cast(BSShort, -5)) == 192
+
+def test_call_function_24():
+ BFloat = new_primitive_type("float")
+ BFloatComplex = new_primitive_type("float _Complex")
+ BFunc3 = new_function_type((BFloat, BFloat), BFloatComplex, False)
+ if 0: # libffi returning nonsense silently, so logic disabled for now
+ f = cast(BFunc3, _testfunc(24))
+ result = f(1.25, 5.1)
+ assert type(result) == complex
+ assert result.real == 1.25 # exact
+ assert (result.imag != 2*5.1) and (abs(result.imag - 2*5.1) < 1e-5) # inexact
+ else:
+ f = cast(BFunc3, _testfunc(9))
+ py.test.raises(NotImplementedError, f, 12.3, 34.5)
+
+def test_call_function_25():
+ BDouble = new_primitive_type("double")
+ BDoubleComplex = new_primitive_type("double _Complex")
+ BFunc3 = new_function_type((BDouble, BDouble), BDoubleComplex, False)
+ if 0: # libffi returning nonsense silently, so logic disabled for now
+ f = cast(BFunc3, _testfunc(25))
+ result = f(1.25, 5.1)
+ assert type(result) == complex
+ assert result.real == 1.25 # exact
+ assert (result.imag != 2*5.1) and (abs(result.imag - 2*5.1) < 1e-10) # inexact
+ else:
+ f = cast(BFunc3, _testfunc(9))
+ py.test.raises(NotImplementedError, f, 12.3, 34.5)
+
+def test_cannot_call_with_a_autocompleted_struct():
+ BSChar = new_primitive_type("signed char")
+ BDouble = new_primitive_type("double")
+ BStruct = new_struct_type("struct foo")
+ BStructPtr = new_pointer_type(BStruct)
+ complete_struct_or_union(BStruct, [('c', BDouble, -1, 8),
+ ('a', BSChar, -1, 2),
+ ('b', BSChar, -1, 0)])
+ BFunc = new_function_type((BStruct,), BDouble) # internally not callable
+ dummy_func = cast(BFunc, 42)
+ e = py.test.raises(NotImplementedError, dummy_func, "?")
+ msg = ("ctype 'struct foo' not supported as argument. It is a struct "
+ 'declared with "...;", but the C calling convention may depend '
+ "on the missing fields; or, it contains anonymous struct/unions. "
+ "Such structs are only supported as argument if the function is "
+ "'API mode' and non-variadic (i.e. declared inside ffibuilder."
+ "cdef()+ffibuilder.set_source() and not taking a final '...' "
+ "argument)")
+ assert str(e.value) == msg
+
+def test_new_charp():
+ BChar = new_primitive_type("char")
+ BCharP = new_pointer_type(BChar)
+ BCharA = new_array_type(BCharP, None)
+ x = newp(BCharA, 42)
+ assert len(x) == 42
+ x = newp(BCharA, b"foobar")
+ assert len(x) == 7
+
+def test_load_and_call_function():
+ BChar = new_primitive_type("char")
+ BCharP = new_pointer_type(BChar)
+ BLong = new_primitive_type("long")
+ BFunc = new_function_type((BCharP,), BLong, False)
+ ll = find_and_load_library('c')
+ strlen = ll.load_function(BFunc, "strlen")
+ input = newp(new_array_type(BCharP, None), b"foobar")
+ assert strlen(input) == 6
+ #
+ assert strlen(b"foobarbaz") == 9
+ #
+ BVoidP = new_pointer_type(new_void_type())
+ strlenaddr = ll.load_function(BVoidP, "strlen")
+ assert strlenaddr == cast(BVoidP, strlen)
+
+def test_read_variable():
+ ## FIXME: this test assumes glibc specific behavior, it's not compliant with C standard
+ ## https://bugs.pypy.org/issue1643
+ if not sys.platform.startswith("linux"):
+ py.test.skip("untested")
+ BVoidP = new_pointer_type(new_void_type())
+ ll = find_and_load_library('c')
+ stderr = ll.read_variable(BVoidP, "stderr")
+ assert stderr == cast(BVoidP, _testfunc(8))
+ #
+ ll.close_lib()
+ py.test.raises(ValueError, ll.read_variable, BVoidP, "stderr")
+
+def test_read_variable_as_unknown_length_array():
+ ## FIXME: this test assumes glibc specific behavior, it's not compliant with C standard
+ ## https://bugs.pypy.org/issue1643
+ if not sys.platform.startswith("linux"):
+ py.test.skip("untested")
+ BCharP = new_pointer_type(new_primitive_type("char"))
+ BArray = new_array_type(BCharP, None)
+ ll = find_and_load_library('c')
+ stderr = ll.read_variable(BArray, "stderr")
+ assert repr(stderr).startswith("<cdata 'char *' 0x")
+ # ^^ and not 'char[]', which is basically not allowed and would crash
+
+def test_write_variable():
+ ## FIXME: this test assumes glibc specific behavior, it's not compliant with C standard
+ ## https://bugs.pypy.org/issue1643
+ if not sys.platform.startswith("linux"):
+ py.test.skip("untested")
+ BVoidP = new_pointer_type(new_void_type())
+ ll = find_and_load_library('c')
+ stderr = ll.read_variable(BVoidP, "stderr")
+ ll.write_variable(BVoidP, "stderr", cast(BVoidP, 0))
+ assert ll.read_variable(BVoidP, "stderr") is not None
+ assert not ll.read_variable(BVoidP, "stderr")
+ ll.write_variable(BVoidP, "stderr", stderr)
+ assert ll.read_variable(BVoidP, "stderr") == stderr
+ #
+ ll.close_lib()
+ py.test.raises(ValueError, ll.write_variable, BVoidP, "stderr", stderr)
+
+def test_callback():
+ BInt = new_primitive_type("int")
+ def make_callback():
+ def cb(n):
+ return n + 1
+ BFunc = new_function_type((BInt,), BInt, False)
+ return callback(BFunc, cb, 42) # 'cb' and 'BFunc' go out of scope
+ f = make_callback()
+ assert f(-142) == -141
+ assert repr(f).startswith(
+ "<cdata 'int(*)(int)' calling <function ")
+ assert "cb at 0x" in repr(f)
+ e = py.test.raises(TypeError, f)
+ assert str(e.value) == "'int(*)(int)' expects 1 arguments, got 0"
+
+def test_callback_exception():
+ try:
+ import cStringIO
+ except ImportError:
+ import io as cStringIO # Python 3
+ import linecache
+ def matches(istr, ipattern):
+ str, pattern = istr, ipattern
+ while '$' in pattern:
+ i = pattern.index('$')
+ assert str[:i] == pattern[:i]
+ j = str.find(pattern[i+1], i)
+ assert i + 1 <= j <= str.find('\n', i)
+ str = str[j:]
+ pattern = pattern[i+1:]
+ assert str == pattern
+ return True
+ def check_value(x):
+ if x == 10000:
+ raise ValueError(42)
+ def Zcb1(x):
+ check_value(x)
+ return x * 3
+ BShort = new_primitive_type("short")
+ BFunc = new_function_type((BShort,), BShort, False)
+ f = callback(BFunc, Zcb1, -42)
+ #
+ seen = []
+ oops_result = None
+ def oops(*args):
+ seen.append(args)
+ return oops_result
+ ff = callback(BFunc, Zcb1, -42, oops)
+ #
+ orig_stderr = sys.stderr
+ orig_getline = linecache.getline
+ try:
+ linecache.getline = lambda *args: 'LINE' # hack: speed up PyPy tests
+ sys.stderr = cStringIO.StringIO()
+ assert f(100) == 300
+ assert sys.stderr.getvalue() == ''
+ assert f(10000) == -42
+ assert matches(sys.stderr.getvalue(), """\
+From cffi callback <function$Zcb1 at 0x$>:
+Traceback (most recent call last):
+ File "$", line $, in Zcb1
+ $
+ File "$", line $, in check_value
+ $
+ValueError: 42
+""")
+ sys.stderr = cStringIO.StringIO()
+ bigvalue = 20000
+ assert f(bigvalue) == -42
+ assert matches(sys.stderr.getvalue(), """\
+From cffi callback <function$Zcb1 at 0x$>:
+Trying to convert the result back to C:
+OverflowError: integer 60000 does not fit 'short'
+""")
+ sys.stderr = cStringIO.StringIO()
+ bigvalue = 20000
+ assert len(seen) == 0
+ assert ff(bigvalue) == -42
+ assert sys.stderr.getvalue() == ""
+ assert len(seen) == 1
+ exc, val, tb = seen[0]
+ assert exc is OverflowError
+ assert str(val) == "integer 60000 does not fit 'short'"
+ #
+ sys.stderr = cStringIO.StringIO()
+ bigvalue = 20000
+ del seen[:]
+ oops_result = 81
+ assert ff(bigvalue) == 81
+ oops_result = None
+ assert sys.stderr.getvalue() == ""
+ assert len(seen) == 1
+ exc, val, tb = seen[0]
+ assert exc is OverflowError
+ assert str(val) == "integer 60000 does not fit 'short'"
+ #
+ sys.stderr = cStringIO.StringIO()
+ bigvalue = 20000
+ del seen[:]
+ oops_result = "xy" # not None and not an int!
+ assert ff(bigvalue) == -42
+ oops_result = None
+ assert matches(sys.stderr.getvalue(), """\
+From cffi callback <function$Zcb1 at 0x$>:
+Trying to convert the result back to C:
+OverflowError: integer 60000 does not fit 'short'
+
+During the call to 'onerror', another exception occurred:
+
+TypeError: $integer$
+""")
+ #
+ sys.stderr = cStringIO.StringIO()
+ seen = "not a list" # this makes the oops() function crash
+ assert ff(bigvalue) == -42
+ assert matches(sys.stderr.getvalue(), """\
+From cffi callback <function$Zcb1 at 0x$>:
+Trying to convert the result back to C:
+OverflowError: integer 60000 does not fit 'short'
+
+During the call to 'onerror', another exception occurred:
+
+Traceback (most recent call last):
+ File "$", line $, in oops
+ $
+AttributeError: 'str' object has no attribute 'append'
+""")
+ finally:
+ sys.stderr = orig_stderr
+ linecache.getline = orig_getline
+
+def test_callback_return_type():
+ for rettype in ["signed char", "short", "int", "long", "long long",
+ "unsigned char", "unsigned short", "unsigned int",
+ "unsigned long", "unsigned long long"]:
+ BRet = new_primitive_type(rettype)
+ def cb(n):
+ return n + 1
+ BFunc = new_function_type((BRet,), BRet)
+ f = callback(BFunc, cb, 42)
+ assert f(41) == 42
+ if rettype.startswith("unsigned "):
+ min = 0
+ max = (1 << (8*sizeof(BRet))) - 1
+ else:
+ min = -(1 << (8*sizeof(BRet)-1))
+ max = (1 << (8*sizeof(BRet)-1)) - 1
+ assert f(min) == min + 1
+ assert f(max - 1) == max
+ assert f(max) == 42
+
+def test_a_lot_of_callbacks():
+ BIGNUM = 10000
+ if 'PY_DOT_PY' in globals(): BIGNUM = 100 # tests on py.py
+ #
+ BInt = new_primitive_type("int")
+ BFunc = new_function_type((BInt,), BInt, False)
+ def make_callback(m):
+ def cb(n):
+ return n + m
+ return callback(BFunc, cb, 42) # 'cb' and 'BFunc' go out of scope
+ #
+ flist = [make_callback(i) for i in range(BIGNUM)]
+ for i, f in enumerate(flist):
+ assert f(-142) == -142 + i
+
+def test_callback_receiving_tiny_struct():
+ BSChar = new_primitive_type("signed char")
+ BInt = new_primitive_type("int")
+ BStruct = new_struct_type("struct foo")
+ BStructPtr = new_pointer_type(BStruct)
+ complete_struct_or_union(BStruct, [('a', BSChar, -1),
+ ('b', BSChar, -1)])
+ def cb(s):
+ return s.a + 10 * s.b
+ BFunc = new_function_type((BStruct,), BInt)
+ f = callback(BFunc, cb)
+ p = newp(BStructPtr, [-2, -4])
+ n = f(p[0])
+ assert n == -42
+
+def test_callback_returning_tiny_struct():
+ BSChar = new_primitive_type("signed char")
+ BInt = new_primitive_type("int")
+ BStruct = new_struct_type("struct foo")
+ BStructPtr = new_pointer_type(BStruct)
+ complete_struct_or_union(BStruct, [('a', BSChar, -1),
+ ('b', BSChar, -1)])
+ def cb(n):
+ return newp(BStructPtr, [-n, -3*n])[0]
+ BFunc = new_function_type((BInt,), BStruct)
+ f = callback(BFunc, cb)
+ s = f(10)
+ assert typeof(s) is BStruct
+ assert repr(s) == "<cdata 'struct foo' owning 2 bytes>"
+ assert s.a == -10
+ assert s.b == -30
+
+def test_callback_receiving_struct():
+ BSChar = new_primitive_type("signed char")
+ BInt = new_primitive_type("int")
+ BDouble = new_primitive_type("double")
+ BStruct = new_struct_type("struct foo")
+ BStructPtr = new_pointer_type(BStruct)
+ complete_struct_or_union(BStruct, [('a', BSChar, -1),
+ ('b', BDouble, -1)])
+ def cb(s):
+ return s.a + int(s.b)
+ BFunc = new_function_type((BStruct,), BInt)
+ f = callback(BFunc, cb)
+ p = newp(BStructPtr, [-2, 44.444])
+ n = f(p[0])
+ assert n == 42
+
+def test_callback_returning_struct():
+ BSChar = new_primitive_type("signed char")
+ BInt = new_primitive_type("int")
+ BDouble = new_primitive_type("double")
+ BStruct = new_struct_type("struct foo")
+ BStructPtr = new_pointer_type(BStruct)
+ complete_struct_or_union(BStruct, [('a', BSChar, -1),
+ ('b', BDouble, -1)])
+ def cb(n):
+ return newp(BStructPtr, [-n, 1E-42])[0]
+ BFunc = new_function_type((BInt,), BStruct)
+ f = callback(BFunc, cb)
+ s = f(10)
+ assert typeof(s) is BStruct
+ assert repr(s) in ["<cdata 'struct foo' owning 12 bytes>",
+ "<cdata 'struct foo' owning 16 bytes>"]
+ assert s.a == -10
+ assert s.b == 1E-42
+
+def test_callback_receiving_big_struct():
+ BInt = new_primitive_type("int")
+ BStruct = new_struct_type("struct foo")
+ BStructPtr = new_pointer_type(BStruct)
+ complete_struct_or_union(BStruct, [('a', BInt, -1),
+ ('b', BInt, -1),
+ ('c', BInt, -1),
+ ('d', BInt, -1),
+ ('e', BInt, -1),
+ ('f', BInt, -1),
+ ('g', BInt, -1),
+ ('h', BInt, -1),
+ ('i', BInt, -1),
+ ('j', BInt, -1)])
+ def cb(s):
+ for i, name in enumerate("abcdefghij"):
+ assert getattr(s, name) == 13 - i
+ return 42
+ BFunc = new_function_type((BStruct,), BInt)
+ f = callback(BFunc, cb)
+ p = newp(BStructPtr, list(range(13, 3, -1)))
+ n = f(p[0])
+ assert n == 42
+
+def test_callback_returning_big_struct():
+ BInt = new_primitive_type("int")
+ BStruct = new_struct_type("struct foo")
+ BStructPtr = new_pointer_type(BStruct)
+ complete_struct_or_union(BStruct, [('a', BInt, -1),
+ ('b', BInt, -1),
+ ('c', BInt, -1),
+ ('d', BInt, -1),
+ ('e', BInt, -1),
+ ('f', BInt, -1),
+ ('g', BInt, -1),
+ ('h', BInt, -1),
+ ('i', BInt, -1),
+ ('j', BInt, -1)])
+ def cb():
+ return newp(BStructPtr, list(range(13, 3, -1)))[0]
+ BFunc = new_function_type((), BStruct)
+ f = callback(BFunc, cb)
+ s = f()
+ assert typeof(s) is BStruct
+ assert repr(s) in ["<cdata 'struct foo' owning 40 bytes>",
+ "<cdata 'struct foo' owning 80 bytes>"]
+ for i, name in enumerate("abcdefghij"):
+ assert getattr(s, name) == 13 - i
+
+def test_callback_returning_void():
+ BVoid = new_void_type()
+ BFunc = new_function_type((), BVoid, False)
+ def cb():
+ seen.append(42)
+ f = callback(BFunc, cb)
+ seen = []
+ f()
+ assert seen == [42]
+ py.test.raises(TypeError, callback, BFunc, cb, -42)
+
+def test_enum_type():
+ BUInt = new_primitive_type("unsigned int")
+ BEnum = new_enum_type("foo", (), (), BUInt)
+ assert repr(BEnum) == "<ctype 'foo'>"
+ assert BEnum.kind == "enum"
+ assert BEnum.cname == "foo"
+ assert BEnum.elements == {}
+ #
+ BInt = new_primitive_type("int")
+ BEnum = new_enum_type("enum foo", ('def', 'c', 'ab'), (0, 1, -20), BInt)
+ assert BEnum.kind == "enum"
+ assert BEnum.cname == "enum foo"
+ assert BEnum.elements == {-20: 'ab', 0: 'def', 1: 'c'}
+ # 'elements' is not the real dict, but merely a copy
+ BEnum.elements[2] = '??'
+ assert BEnum.elements == {-20: 'ab', 0: 'def', 1: 'c'}
+ #
+ BEnum = new_enum_type("enum bar", ('ab', 'cd'), (5, 5), BUInt)
+ assert BEnum.elements == {5: 'ab'}
+ assert BEnum.relements == {'ab': 5, 'cd': 5}
+
+def test_cast_to_enum():
+ BInt = new_primitive_type("int")
+ BEnum = new_enum_type("enum foo", ('def', 'c', 'ab'), (0, 1, -20), BInt)
+ assert sizeof(BEnum) == sizeof(BInt)
+ e = cast(BEnum, 0)
+ assert repr(e) == "<cdata 'enum foo' 0: def>"
+ assert repr(cast(BEnum, -42)) == "<cdata 'enum foo' -42>"
+ assert repr(cast(BEnum, -20)) == "<cdata 'enum foo' -20: ab>"
+ assert string(e) == 'def'
+ assert string(cast(BEnum, -20)) == 'ab'
+ assert int(cast(BEnum, 1)) == 1
+ assert int(cast(BEnum, 0)) == 0
+ assert int(cast(BEnum, -242 + 2**128)) == -242
+ assert string(cast(BEnum, -242 + 2**128)) == '-242'
+ #
+ BUInt = new_primitive_type("unsigned int")
+ BEnum = new_enum_type("enum bar", ('def', 'c', 'ab'), (0, 1, 20), BUInt)
+ e = cast(BEnum, -1)
+ assert repr(e) == "<cdata 'enum bar' 4294967295>" # unsigned int
+ #
+ BLong = new_primitive_type("long")
+ BEnum = new_enum_type("enum baz", (), (), BLong)
+ assert sizeof(BEnum) == sizeof(BLong)
+ e = cast(BEnum, -1)
+ assert repr(e) == "<cdata 'enum baz' -1>"
+
+def test_enum_with_non_injective_mapping():
+ BInt = new_primitive_type("int")
+ BEnum = new_enum_type("enum foo", ('ab', 'cd'), (7, 7), BInt)
+ e = cast(BEnum, 7)
+ assert repr(e) == "<cdata 'enum foo' 7: ab>"
+ assert string(e) == 'ab'
+
+def test_enum_in_struct():
+ BInt = new_primitive_type("int")
+ BEnum = new_enum_type("enum foo", ('def', 'c', 'ab'), (0, 1, -20), BInt)
+ BStruct = new_struct_type("struct bar")
+ BStructPtr = new_pointer_type(BStruct)
+ complete_struct_or_union(BStruct, [('a1', BEnum, -1)])
+ p = newp(BStructPtr, [-20])
+ assert p.a1 == -20
+ p = newp(BStructPtr, [12])
+ assert p.a1 == 12
+ e = py.test.raises(TypeError, newp, BStructPtr, [None])
+ msg = str(e.value)
+ assert ("an integer is required" in msg or # CPython
+ "unsupported operand type for int(): 'NoneType'" in msg or # old PyPys
+ "expected integer, got NoneType object" in msg) # newer PyPys
+ with pytest.raises(TypeError):
+ p.a1 = "def"
+ if sys.version_info < (3,):
+ BEnum2 = new_enum_type(unicode("foo"), (unicode('abc'),), (5,), BInt)
+ assert string(cast(BEnum2, 5)) == 'abc'
+ assert type(string(cast(BEnum2, 5))) is str
+
+def test_enum_overflow():
+ max_uint = 2 ** (size_of_int()*8) - 1
+ max_int = max_uint // 2
+ max_ulong = 2 ** (size_of_long()*8) - 1
+ max_long = max_ulong // 2
+ for BPrimitive in [new_primitive_type("int"),
+ new_primitive_type("unsigned int"),
+ new_primitive_type("long"),
+ new_primitive_type("unsigned long")]:
+ for x in [max_uint, max_int, max_ulong, max_long]:
+ for testcase in [x, x+1, -x-1, -x-2]:
+ if int(cast(BPrimitive, testcase)) == testcase:
+ # fits
+ BEnum = new_enum_type("foo", ("AA",), (testcase,),
+ BPrimitive)
+ assert int(cast(BEnum, testcase)) == testcase
+ else:
+ # overflows
+ py.test.raises(OverflowError, new_enum_type,
+ "foo", ("AA",), (testcase,), BPrimitive)
+
+def test_callback_returning_enum():
+ BInt = new_primitive_type("int")
+ BEnum = new_enum_type("foo", ('def', 'c', 'ab'), (0, 1, -20), BInt)
+ def cb(n):
+ if n & 1:
+ return cast(BEnum, n)
+ else:
+ return n
+ BFunc = new_function_type((BInt,), BEnum)
+ f = callback(BFunc, cb)
+ assert f(0) == 0
+ assert f(1) == 1
+ assert f(-20) == -20
+ assert f(20) == 20
+ assert f(21) == 21
+
+def test_callback_returning_enum_unsigned():
+ BInt = new_primitive_type("int")
+ BUInt = new_primitive_type("unsigned int")
+ BEnum = new_enum_type("foo", ('def', 'c', 'ab'), (0, 1, 20), BUInt)
+ def cb(n):
+ if n & 1:
+ return cast(BEnum, n)
+ else:
+ return n
+ BFunc = new_function_type((BInt,), BEnum)
+ f = callback(BFunc, cb)
+ assert f(0) == 0
+ assert f(1) == 1
+ assert f(-21) == 2**32 - 21
+ assert f(20) == 20
+ assert f(21) == 21
+
+def test_callback_returning_char():
+ BInt = new_primitive_type("int")
+ BChar = new_primitive_type("char")
+ def cb(n):
+ return bytechr(n)
+ BFunc = new_function_type((BInt,), BChar)
+ f = callback(BFunc, cb)
+ assert f(0) == b'\x00'
+ assert f(255) == b'\xFF'
+
+def _hacked_pypy_uni4():
+ pyuni4 = {1: True, 2: False}[len(u+'\U00012345')]
+ return 'PY_DOT_PY' in globals() and not pyuni4
+
+def test_callback_returning_wchar_t():
+ BInt = new_primitive_type("int")
+ BWChar = new_primitive_type("wchar_t")
+ def cb(n):
+ if n == -1:
+ return u+'\U00012345'
+ if n == -2:
+ raise ValueError
+ return unichr(n)
+ BFunc = new_function_type((BInt,), BWChar)
+ f = callback(BFunc, cb)
+ assert f(0) == unichr(0)
+ assert f(255) == unichr(255)
+ assert f(0x1234) == u+'\u1234'
+ if sizeof(BWChar) == 4 and not _hacked_pypy_uni4():
+ assert f(-1) == u+'\U00012345'
+ assert f(-2) == u+'\x00' # and an exception printed to stderr
+
+def test_struct_with_bitfields():
+ BLong = new_primitive_type("long")
+ BStruct = new_struct_type("struct foo")
+ LONGBITS = 8 * sizeof(BLong)
+ complete_struct_or_union(BStruct, [('a1', BLong, 1),
+ ('a2', BLong, 2),
+ ('a3', BLong, 3),
+ ('a4', BLong, LONGBITS - 5)])
+ d = BStruct.fields
+ assert d[0][1].offset == d[1][1].offset == d[2][1].offset == 0
+ assert d[3][1].offset == sizeof(BLong)
+ def f(m, r):
+ if sys.byteorder == 'little':
+ return r
+ else:
+ return LONGBITS - m - r
+ assert d[0][1].bitshift == f(1, 0)
+ assert d[0][1].bitsize == 1
+ assert d[1][1].bitshift == f(2, 1)
+ assert d[1][1].bitsize == 2
+ assert d[2][1].bitshift == f(3, 3)
+ assert d[2][1].bitsize == 3
+ assert d[3][1].bitshift == f(LONGBITS - 5, 0)
+ assert d[3][1].bitsize == LONGBITS - 5
+ assert sizeof(BStruct) == 2 * sizeof(BLong)
+ assert alignof(BStruct) == alignof(BLong)
+
+def test_bitfield_instance():
+ BInt = new_primitive_type("int")
+ BUnsignedInt = new_primitive_type("unsigned int")
+ BStruct = new_struct_type("struct foo")
+ complete_struct_or_union(BStruct, [('a1', BInt, 1),
+ ('a2', BUnsignedInt, 2),
+ ('a3', BInt, 3)])
+ p = newp(new_pointer_type(BStruct), None)
+ p.a1 = -1
+ assert p.a1 == -1
+ p.a1 = 0
+ with pytest.raises(OverflowError):
+ p.a1 = 2
+ assert p.a1 == 0
+ #
+ p.a1 = -1
+ p.a2 = 3
+ p.a3 = -4
+ with pytest.raises(OverflowError):
+ p.a3 = 4
+ with pytest.raises(OverflowError) as e:
+ p.a3 = -5
+ assert str(e.value) == ("value -5 outside the range allowed by the "
+ "bit field width: -4 <= x <= 3")
+ assert p.a1 == -1 and p.a2 == 3 and p.a3 == -4
+ #
+ # special case for convenience: "int x:1", while normally signed,
+ # allows also setting the value "1" (it still gets read back as -1)
+ p.a1 = 1
+ assert p.a1 == -1
+ with pytest.raises(OverflowError) as e:
+ p.a1 = -2
+ assert str(e.value) == ("value -2 outside the range allowed by the "
+ "bit field width: -1 <= x <= 1")
+
+def test_bitfield_instance_init():
+ BInt = new_primitive_type("int")
+ BStruct = new_struct_type("struct foo")
+ complete_struct_or_union(BStruct, [('a1', BInt, 1)])
+ p = newp(new_pointer_type(BStruct), [-1])
+ assert p.a1 == -1
+ p = newp(new_pointer_type(BStruct), {'a1': -1})
+ assert p.a1 == -1
+ #
+ BUnion = new_union_type("union bar")
+ complete_struct_or_union(BUnion, [('a1', BInt, 1)])
+ p = newp(new_pointer_type(BUnion), [-1])
+ assert p.a1 == -1
+
+def test_weakref():
+ import _weakref
+ BInt = new_primitive_type("int")
+ BPtr = new_pointer_type(BInt)
+ rlist = [_weakref.ref(BInt),
+ _weakref.ref(newp(BPtr, 42)),
+ _weakref.ref(cast(BPtr, 42)),
+ _weakref.ref(cast(BInt, 42)),
+ _weakref.ref(buffer(newp(BPtr, 42))),
+ ]
+ for i in range(5):
+ import gc; gc.collect()
+ if [r() for r in rlist] == [None for r in rlist]:
+ break
+
+def test_no_inheritance():
+ BInt = new_primitive_type("int")
+ try:
+ class foo(type(BInt)): pass
+ except TypeError:
+ pass
+ else:
+ raise AssertionError
+ x = cast(BInt, 42)
+ try:
+ class foo(type(x)): pass
+ except TypeError:
+ pass
+ else:
+ raise AssertionError
+
+def test_assign_string():
+ BChar = new_primitive_type("char")
+ BArray1 = new_array_type(new_pointer_type(BChar), 5)
+ BArray2 = new_array_type(new_pointer_type(BArray1), 5)
+ a = newp(BArray2, [b"abc", b"de", b"ghij"])
+ assert string(a[1]) == b"de"
+ assert string(a[2]) == b"ghij"
+ a[2] = b"."
+ assert string(a[2]) == b"."
+ a[2] = b"12345"
+ assert string(a[2]) == b"12345"
+ with pytest.raises(IndexError) as e:
+ a[2] = b"123456"
+ assert 'char[5]' in str(e.value)
+ assert 'got 6 characters' in str(e.value)
+
+def test_add_error():
+ x = cast(new_primitive_type("int"), 42)
+ with pytest.raises(TypeError):
+ x + 1
+ with pytest.raises(TypeError):
+ x - 1
+
+def test_void_errors():
+ py.test.raises(ValueError, alignof, new_void_type())
+ py.test.raises(TypeError, newp, new_pointer_type(new_void_type()), None)
+
+def test_too_many_items():
+ BChar = new_primitive_type("char")
+ BArray = new_array_type(new_pointer_type(BChar), 5)
+ py.test.raises(IndexError, newp, BArray, tuple(b'123456'))
+ py.test.raises(IndexError, newp, BArray, list(b'123456'))
+ py.test.raises(IndexError, newp, BArray, b'123456')
+ BStruct = new_struct_type("struct foo")
+ complete_struct_or_union(BStruct, [])
+ py.test.raises(TypeError, newp, new_pointer_type(BStruct), b'')
+ py.test.raises(ValueError, newp, new_pointer_type(BStruct), [b'1'])
+
+def test_more_type_errors():
+ BInt = new_primitive_type("int")
+ BChar = new_primitive_type("char")
+ BArray = new_array_type(new_pointer_type(BChar), 5)
+ py.test.raises(TypeError, newp, BArray, 12.34)
+ BArray = new_array_type(new_pointer_type(BInt), 5)
+ py.test.raises(TypeError, newp, BArray, 12.34)
+ BFloat = new_primitive_type("float")
+ py.test.raises(TypeError, cast, BFloat, newp(BArray, None))
+
+def test_more_overflow_errors():
+ BUInt = new_primitive_type("unsigned int")
+ py.test.raises(OverflowError, newp, new_pointer_type(BUInt), -1)
+ py.test.raises(OverflowError, newp, new_pointer_type(BUInt), 2**32)
+
+def test_newp_copying():
+ """Test that we can do newp(<type>, <cdata of the given type>) for most
+ types, including same-type arrays.
+ """
+ BInt = new_primitive_type("int")
+ p = newp(new_pointer_type(BInt), cast(BInt, 42))
+ assert p[0] == 42
+ #
+ BUInt = new_primitive_type("unsigned int")
+ p = newp(new_pointer_type(BUInt), cast(BUInt, 42))
+ assert p[0] == 42
+ #
+ BChar = new_primitive_type("char")
+ p = newp(new_pointer_type(BChar), cast(BChar, '!'))
+ assert p[0] == b'!'
+ #
+ BFloat = new_primitive_type("float")
+ p = newp(new_pointer_type(BFloat), cast(BFloat, 12.25))
+ assert p[0] == 12.25
+ #
+ BStruct = new_struct_type("struct foo_s")
+ BStructPtr = new_pointer_type(BStruct)
+ complete_struct_or_union(BStruct, [('a1', BInt, -1)])
+ s1 = newp(BStructPtr, [42])
+ p1 = newp(new_pointer_type(BStructPtr), s1)
+ assert p1[0] == s1
+ #
+ BArray = new_array_type(new_pointer_type(BInt), None)
+ a1 = newp(BArray, [1, 2, 3, 4])
+ py.test.raises(TypeError, newp, BArray, a1)
+ BArray6 = new_array_type(new_pointer_type(BInt), 6)
+ a1 = newp(BArray6, [10, 20, 30])
+ a2 = newp(BArray6, a1)
+ assert list(a2) == [10, 20, 30, 0, 0, 0]
+ #
+ s1 = newp(BStructPtr, [42])
+ s2 = newp(BStructPtr, s1[0])
+ assert s2.a1 == 42
+ #
+ BUnion = new_union_type("union foo_u")
+ BUnionPtr = new_pointer_type(BUnion)
+ complete_struct_or_union(BUnion, [('a1', BInt, -1)])
+ u1 = newp(BUnionPtr, [42])
+ u2 = newp(BUnionPtr, u1[0])
+ assert u2.a1 == 42
+ #
+ BFunc = new_function_type((BInt,), BUInt)
+ p1 = cast(BFunc, 42)
+ p2 = newp(new_pointer_type(BFunc), p1)
+ assert p2[0] == p1
+
+def test_string():
+ BChar = new_primitive_type("char")
+ assert string(cast(BChar, 42)) == b'*'
+ assert string(cast(BChar, 0)) == b'\x00'
+ BCharP = new_pointer_type(BChar)
+ BArray = new_array_type(BCharP, 10)
+ a = newp(BArray, b"hello")
+ assert len(a) == 10
+ assert string(a) == b"hello"
+ p = a + 2
+ assert string(p) == b"llo"
+ assert string(newp(new_array_type(BCharP, 4), b"abcd")) == b"abcd"
+ py.test.raises(RuntimeError, string, cast(BCharP, 0))
+ assert string(a, 4) == b"hell"
+ assert string(a, 5) == b"hello"
+ assert string(a, 6) == b"hello"
+
+def test_string_byte():
+ BByte = new_primitive_type("signed char")
+ assert string(cast(BByte, 42)) == b'*'
+ assert string(cast(BByte, 0)) == b'\x00'
+ BArray = new_array_type(new_pointer_type(BByte), None)
+ a = newp(BArray, [65, 66, 67])
+ assert type(string(a)) is bytes and string(a) == b'ABC'
+ #
+ BByte = new_primitive_type("unsigned char")
+ assert string(cast(BByte, 42)) == b'*'
+ assert string(cast(BByte, 0)) == b'\x00'
+ BArray = new_array_type(new_pointer_type(BByte), None)
+ a = newp(BArray, [65, 66, 67])
+ assert type(string(a)) is bytes and string(a) == b'ABC'
+ if 'PY_DOT_PY' not in globals() and sys.version_info < (3,):
+ assert string(a, 8).startswith(b'ABC') # may contain additional garbage
+
+def test_string_wchar():
+ for typename in ["wchar_t", "char16_t", "char32_t"]:
+ _test_string_wchar_variant(typename)
+
+def _test_string_wchar_variant(typename):
+ BWChar = new_primitive_type(typename)
+ assert string(cast(BWChar, 42)) == u+'*'
+ assert string(cast(BWChar, 0x4253)) == u+'\u4253'
+ assert string(cast(BWChar, 0)) == u+'\x00'
+ BArray = new_array_type(new_pointer_type(BWChar), None)
+ a = newp(BArray, [u+'A', u+'B', u+'C'])
+ assert type(string(a)) is unicode and string(a) == u+'ABC'
+ if 'PY_DOT_PY' not in globals() and sys.version_info < (3,):
+ try:
+ # may contain additional garbage
+ assert string(a, 8).startswith(u+'ABC')
+ except ValueError: # garbage contains values > 0x10FFFF
+ assert sizeof(BWChar) == 4
+
+def test_string_typeerror():
+ BShort = new_primitive_type("short")
+ BArray = new_array_type(new_pointer_type(BShort), None)
+ a = newp(BArray, [65, 66, 67])
+ py.test.raises(TypeError, string, a)
+
+def test_bug_convert_to_ptr():
+ BChar = new_primitive_type("char")
+ BCharP = new_pointer_type(BChar)
+ BDouble = new_primitive_type("double")
+ x = cast(BDouble, 42)
+ py.test.raises(TypeError, newp, new_pointer_type(BCharP), x)
+
+def test_set_struct_fields():
+ BChar = new_primitive_type("char")
+ BCharP = new_pointer_type(BChar)
+ BCharArray10 = new_array_type(BCharP, 10)
+ BStruct = new_struct_type("struct foo")
+ BStructPtr = new_pointer_type(BStruct)
+ complete_struct_or_union(BStruct, [('a1', BCharArray10, -1)])
+ p = newp(BStructPtr, None)
+ assert string(p.a1) == b''
+ p.a1 = b'foo'
+ assert string(p.a1) == b'foo'
+ assert list(p.a1) == [b'f', b'o', b'o'] + [b'\x00'] * 7
+ p.a1 = [b'x', b'y']
+ assert string(p.a1) == b'xyo'
+
+def test_invalid_function_result_types():
+ BFunc = new_function_type((), new_void_type())
+ BArray = new_array_type(new_pointer_type(BFunc), 5) # works
+ new_function_type((), BFunc) # works
+ new_function_type((), new_primitive_type("int"))
+ new_function_type((), new_pointer_type(BFunc))
+ BUnion = new_union_type("union foo_u")
+ complete_struct_or_union(BUnion, [])
+ BFunc = new_function_type((), BUnion)
+ py.test.raises(NotImplementedError, cast(BFunc, 123))
+ py.test.raises(TypeError, new_function_type, (), BArray)
+
+def test_struct_return_in_func():
+ BChar = new_primitive_type("char")
+ BShort = new_primitive_type("short")
+ BFloat = new_primitive_type("float")
+ BDouble = new_primitive_type("double")
+ BInt = new_primitive_type("int")
+ BStruct = new_struct_type("struct foo_s")
+ complete_struct_or_union(BStruct, [('a1', BChar, -1),
+ ('a2', BShort, -1)])
+ BFunc10 = new_function_type((BInt,), BStruct)
+ f = cast(BFunc10, _testfunc(10))
+ s = f(40)
+ assert repr(s) == "<cdata 'struct foo_s' owning 4 bytes>"
+ assert s.a1 == bytechr(40)
+ assert s.a2 == 40 * 40
+ #
+ BStruct11 = new_struct_type("struct test11")
+ complete_struct_or_union(BStruct11, [('a1', BInt, -1),
+ ('a2', BInt, -1)])
+ BFunc11 = new_function_type((BInt,), BStruct11)
+ f = cast(BFunc11, _testfunc(11))
+ s = f(40)
+ assert repr(s) == "<cdata 'struct test11' owning 8 bytes>"
+ assert s.a1 == 40
+ assert s.a2 == 40 * 40
+ #
+ BStruct12 = new_struct_type("struct test12")
+ complete_struct_or_union(BStruct12, [('a1', BDouble, -1),
+ ])
+ BFunc12 = new_function_type((BInt,), BStruct12)
+ f = cast(BFunc12, _testfunc(12))
+ s = f(40)
+ assert repr(s) == "<cdata 'struct test12' owning 8 bytes>"
+ assert s.a1 == 40.0
+ #
+ BStruct13 = new_struct_type("struct test13")
+ complete_struct_or_union(BStruct13, [('a1', BInt, -1),
+ ('a2', BInt, -1),
+ ('a3', BInt, -1)])
+ BFunc13 = new_function_type((BInt,), BStruct13)
+ f = cast(BFunc13, _testfunc(13))
+ s = f(40)
+ assert repr(s) == "<cdata 'struct test13' owning 12 bytes>"
+ assert s.a1 == 40
+ assert s.a2 == 40 * 40
+ assert s.a3 == 40 * 40 * 40
+ #
+ BStruct14 = new_struct_type("struct test14")
+ complete_struct_or_union(BStruct14, [('a1', BFloat, -1),
+ ])
+ BFunc14 = new_function_type((BInt,), BStruct14)
+ f = cast(BFunc14, _testfunc(14))
+ s = f(40)
+ assert repr(s) == "<cdata 'struct test14' owning 4 bytes>"
+ assert s.a1 == 40.0
+ #
+ BStruct15 = new_struct_type("struct test15")
+ complete_struct_or_union(BStruct15, [('a1', BFloat, -1),
+ ('a2', BInt, -1)])
+ BFunc15 = new_function_type((BInt,), BStruct15)
+ f = cast(BFunc15, _testfunc(15))
+ s = f(40)
+ assert repr(s) == "<cdata 'struct test15' owning 8 bytes>"
+ assert s.a1 == 40.0
+ assert s.a2 == 40 * 40
+ #
+ BStruct16 = new_struct_type("struct test16")
+ complete_struct_or_union(BStruct16, [('a1', BFloat, -1),
+ ('a2', BFloat, -1)])
+ BFunc16 = new_function_type((BInt,), BStruct16)
+ f = cast(BFunc16, _testfunc(16))
+ s = f(40)
+ assert repr(s) == "<cdata 'struct test16' owning 8 bytes>"
+ assert s.a1 == 40.0
+ assert s.a2 == -40.0
+ #
+ BStruct17 = new_struct_type("struct test17")
+ complete_struct_or_union(BStruct17, [('a1', BInt, -1),
+ ('a2', BFloat, -1)])
+ BFunc17 = new_function_type((BInt,), BStruct17)
+ f = cast(BFunc17, _testfunc(17))
+ s = f(40)
+ assert repr(s) == "<cdata 'struct test17' owning 8 bytes>"
+ assert s.a1 == 40
+ assert s.a2 == 40.0 * 40.0
+ #
+ BStruct17Ptr = new_pointer_type(BStruct17)
+ BFunc18 = new_function_type((BStruct17Ptr,), BInt)
+ f = cast(BFunc18, _testfunc(18))
+ x = f([[40, 2.5]])
+ assert x == 42
+ x = f([{'a2': 43.1}])
+ assert x == 43
+
+def test_cast_with_functionptr():
+ BFunc = new_function_type((), new_void_type())
+ BFunc2 = new_function_type((), new_primitive_type("short"))
+ BCharP = new_pointer_type(new_primitive_type("char"))
+ BIntP = new_pointer_type(new_primitive_type("int"))
+ BStruct = new_struct_type("struct foo")
+ BStructPtr = new_pointer_type(BStruct)
+ complete_struct_or_union(BStruct, [('a1', BFunc, -1)])
+ newp(BStructPtr, [cast(BFunc, 0)])
+ newp(BStructPtr, [cast(BCharP, 0)])
+ py.test.raises(TypeError, newp, BStructPtr, [cast(BIntP, 0)])
+ py.test.raises(TypeError, newp, BStructPtr, [cast(BFunc2, 0)])
+
+def test_wchar():
+ _test_wchar_variant("wchar_t")
+ if sys.platform.startswith("linux"):
+ BWChar = new_primitive_type("wchar_t")
+ assert sizeof(BWChar) == 4
+ # wchar_t is often signed on Linux, but not always (e.g. on ARM)
+ assert int(cast(BWChar, -1)) in (-1, 4294967295)
+
+def test_char16():
+ BChar16 = new_primitive_type("char16_t")
+ assert sizeof(BChar16) == 2
+ _test_wchar_variant("char16_t")
+ assert int(cast(BChar16, -1)) == 0xffff # always unsigned
+
+def test_char32():
+ BChar32 = new_primitive_type("char32_t")
+ assert sizeof(BChar32) == 4
+ _test_wchar_variant("char32_t")
+ assert int(cast(BChar32, -1)) == 0xffffffff # always unsigned
+
+def _test_wchar_variant(typename):
+ BWChar = new_primitive_type(typename)
+ BInt = new_primitive_type("int")
+ pyuni4 = {1: True, 2: False}[len(u+'\U00012345')]
+ wchar4 = {2: False, 4: True}[sizeof(BWChar)]
+ assert str(cast(BWChar, 0x45)) == "<cdata '%s' %s'E'>" % (
+ typename, mandatory_u_prefix)
+ assert str(cast(BWChar, 0x1234)) == "<cdata '%s' %s'\u1234'>" % (
+ typename, mandatory_u_prefix)
+ if not _hacked_pypy_uni4():
+ if wchar4:
+ x = cast(BWChar, 0x12345)
+ assert str(x) == "<cdata '%s' %s'\U00012345'>" % (
+ typename, mandatory_u_prefix)
+ assert int(x) == 0x12345
+ else:
+ x = cast(BWChar, 0x18345)
+ assert str(x) == "<cdata '%s' %s'\u8345'>" % (
+ typename, mandatory_u_prefix)
+ assert int(x) == 0x8345
+ #
+ BWCharP = new_pointer_type(BWChar)
+ BStruct = new_struct_type("struct foo_s")
+ BStructPtr = new_pointer_type(BStruct)
+ complete_struct_or_union(BStruct, [('a1', BWChar, -1),
+ ('a2', BWCharP, -1)])
+ s = newp(BStructPtr)
+ s.a1 = u+'\x00'
+ assert s.a1 == u+'\x00'
+ with pytest.raises(TypeError):
+ s.a1 = b'a'
+ with pytest.raises(TypeError):
+ s.a1 = bytechr(0xFF)
+ s.a1 = u+'\u1234'
+ assert s.a1 == u+'\u1234'
+ if pyuni4:
+ if wchar4:
+ s.a1 = u+'\U00012345'
+ assert s.a1 == u+'\U00012345'
+ elif wchar4:
+ if not _hacked_pypy_uni4():
+ s.a1 = cast(BWChar, 0x12345)
+ assert s.a1 == u+'\ud808\udf45'
+ s.a1 = u+'\ud807\udf44'
+ assert s.a1 == u+'\U00011f44'
+ else:
+ with pytest.raises(TypeError):
+ s.a1 = u+'\U00012345'
+ #
+ BWCharArray = new_array_type(BWCharP, None)
+ a = newp(BWCharArray, u+'hello \u1234 world')
+ assert len(a) == 14 # including the final null
+ assert string(a) == u+'hello \u1234 world'
+ a[13] = u+'!'
+ assert string(a) == u+'hello \u1234 world!'
+ assert str(a) == repr(a)
+ assert a[6] == u+'\u1234'
+ a[6] = u+'-'
+ assert string(a) == u+'hello - world!'
+ assert str(a) == repr(a)
+ #
+ if wchar4 and not _hacked_pypy_uni4():
+ u1 = u+'\U00012345\U00012346\U00012347'
+ a = newp(BWCharArray, u1)
+ assert len(a) == 4
+ assert string(a) == u1
+ assert len(list(a)) == 4
+ expected = [u+'\U00012345', u+'\U00012346', u+'\U00012347', unichr(0)]
+ assert list(a) == expected
+ got = [a[i] for i in range(4)]
+ assert got == expected
+ with pytest.raises(IndexError):
+ a[4]
+ #
+ w = cast(BWChar, 'a')
+ assert repr(w) == "<cdata '%s' %s'a'>" % (typename, mandatory_u_prefix)
+ assert str(w) == repr(w)
+ assert string(w) == u+'a'
+ assert int(w) == ord('a')
+ w = cast(BWChar, 0x1234)
+ assert repr(w) == "<cdata '%s' %s'\u1234'>" % (typename, mandatory_u_prefix)
+ assert str(w) == repr(w)
+ assert string(w) == u+'\u1234'
+ assert int(w) == 0x1234
+ w = cast(BWChar, u+'\u8234')
+ assert repr(w) == "<cdata '%s' %s'\u8234'>" % (typename, mandatory_u_prefix)
+ assert str(w) == repr(w)
+ assert string(w) == u+'\u8234'
+ assert int(w) == 0x8234
+ w = cast(BInt, u+'\u1234')
+ assert repr(w) == "<cdata 'int' 4660>"
+ if wchar4 and not _hacked_pypy_uni4():
+ w = cast(BWChar, u+'\U00012345')
+ assert repr(w) == "<cdata '%s' %s'\U00012345'>" % (
+ typename, mandatory_u_prefix)
+ assert str(w) == repr(w)
+ assert string(w) == u+'\U00012345'
+ assert int(w) == 0x12345
+ w = cast(BInt, u+'\U00012345')
+ assert repr(w) == "<cdata 'int' 74565>"
+ py.test.raises(TypeError, cast, BInt, u+'')
+ py.test.raises(TypeError, cast, BInt, u+'XX')
+ assert int(cast(BInt, u+'a')) == ord('a')
+ #
+ a = newp(BWCharArray, u+'hello - world')
+ p = cast(BWCharP, a)
+ assert string(p) == u+'hello - world'
+ p[6] = u+'\u2345'
+ assert string(p) == u+'hello \u2345 world'
+ #
+ s = newp(BStructPtr, [u+'\u1234', p])
+ assert s.a1 == u+'\u1234'
+ assert s.a2 == p
+ assert str(s.a2) == repr(s.a2)
+ assert string(s.a2) == u+'hello \u2345 world'
+ #
+ q = cast(BWCharP, 0)
+ assert str(q) == repr(q)
+ py.test.raises(RuntimeError, string, q)
+ #
+ def cb(p):
+ assert repr(p).startswith("<cdata '%s *' 0x" % typename)
+ return len(string(p))
+ BFunc = new_function_type((BWCharP,), BInt, False)
+ f = callback(BFunc, cb, -42)
+ assert f(u+'a\u1234b') == 3
+ #
+ if wchar4 and not pyuni4 and not _hacked_pypy_uni4():
+ # try out-of-range wchar_t values
+ x = cast(BWChar, 1114112)
+ py.test.raises(ValueError, string, x)
+ x = cast(BWChar, -1)
+ py.test.raises(ValueError, string, x)
+
+def test_wchar_variants_mix():
+ BWChar = new_primitive_type("wchar_t")
+ BChar16 = new_primitive_type("char16_t")
+ BChar32 = new_primitive_type("char32_t")
+ assert int(cast(BChar32, cast(BChar16, -2))) == 0xfffe
+ assert int(cast(BWChar, cast(BChar16, -2))) == 0xfffe
+ assert int(cast(BChar16, cast(BChar32, 0x0001f345))) == 0xf345
+ assert int(cast(BChar16, cast(BWChar, 0x0001f345))) == 0xf345
+ #
+ BChar16A = new_array_type(new_pointer_type(BChar16), None)
+ BChar32A = new_array_type(new_pointer_type(BChar32), None)
+ x = cast(BChar32, 'A')
+ py.test.raises(TypeError, newp, BChar16A, [x])
+ x = cast(BChar16, 'A')
+ py.test.raises(TypeError, newp, BChar32A, [x])
+ #
+ a = newp(BChar16A, u+'\U00012345')
+ assert len(a) == 3
+ a = newp(BChar32A, u+'\U00012345')
+ assert len(a) == 2 # even if the Python unicode string above is 2 chars
+
+def test_keepalive_struct():
+ # exception to the no-keepalive rule: p=newp(BStructPtr) returns a
+ # pointer owning the memory, and p[0] returns a pointer to the
+ # struct that *also* owns the memory
+ BStruct = new_struct_type("struct foo")
+ BStructPtr = new_pointer_type(BStruct)
+ complete_struct_or_union(BStruct, [('a1', new_primitive_type("int"), -1),
+ ('a2', new_primitive_type("int"), -1),
+ ('a3', new_primitive_type("int"), -1)])
+ p = newp(BStructPtr)
+ assert repr(p) == "<cdata 'struct foo *' owning 12 bytes>"
+ q = p[0]
+ assert repr(q) == "<cdata 'struct foo' owning 12 bytes>"
+ q.a1 = 123456
+ assert p.a1 == 123456
+ r = cast(BStructPtr, p)
+ assert repr(r[0]).startswith("<cdata 'struct foo &' 0x")
+ del p
+ import gc; gc.collect()
+ assert q.a1 == 123456
+ assert repr(q) == "<cdata 'struct foo' owning 12 bytes>"
+ assert q.a1 == 123456
+
+def test_nokeepalive_struct():
+ BStruct = new_struct_type("struct foo")
+ BStructPtr = new_pointer_type(BStruct)
+ BStructPtrPtr = new_pointer_type(BStructPtr)
+ complete_struct_or_union(BStruct, [('a1', new_primitive_type("int"), -1)])
+ p = newp(BStructPtr)
+ pp = newp(BStructPtrPtr)
+ pp[0] = p
+ s = pp[0][0]
+ assert repr(s).startswith("<cdata 'struct foo &' 0x")
+
+def test_owning_repr():
+ BInt = new_primitive_type("int")
+ BArray = new_array_type(new_pointer_type(BInt), None) # int[]
+ p = newp(BArray, 7)
+ assert repr(p) == "<cdata 'int[]' owning 28 bytes>"
+ assert sizeof(p) == 28
+ #
+ BArray = new_array_type(new_pointer_type(BInt), 7) # int[7]
+ p = newp(BArray, None)
+ assert repr(p) == "<cdata 'int[7]' owning 28 bytes>"
+ assert sizeof(p) == 28
+
+def test_cannot_dereference_void():
+ BVoidP = new_pointer_type(new_void_type())
+ p = cast(BVoidP, 123456)
+ with pytest.raises(TypeError):
+ p[0]
+ p = cast(BVoidP, 0)
+ with pytest.raises((TypeError, RuntimeError)):
+ p[0]
+
+def test_iter():
+ BInt = new_primitive_type("int")
+ BIntP = new_pointer_type(BInt)
+ BArray = new_array_type(BIntP, None) # int[]
+ p = newp(BArray, 7)
+ assert list(p) == list(iter(p)) == [0] * 7
+ #
+ py.test.raises(TypeError, iter, cast(BInt, 5))
+ py.test.raises(TypeError, iter, cast(BIntP, 123456))
+
+def test_cmp():
+ BInt = new_primitive_type("int")
+ BIntP = new_pointer_type(BInt)
+ BVoidP = new_pointer_type(new_void_type())
+ p = newp(BIntP, 123)
+ q = cast(BInt, 124)
+ assert (p == q) is False
+ assert (p != q) is True
+ assert (q == p) is False
+ assert (q != p) is True
+ if strict_compare:
+ with pytest.raises(TypeError): p < q
+ with pytest.raises(TypeError): p <= q
+ with pytest.raises(TypeError): q < p
+ with pytest.raises(TypeError): q <= p
+ with pytest.raises(TypeError): p > q
+ with pytest.raises(TypeError): p >= q
+ r = cast(BVoidP, p)
+ assert (p < r) is False
+ assert (p <= r) is True
+ assert (p == r) is True
+ assert (p != r) is False
+ assert (p > r) is False
+ assert (p >= r) is True
+ s = newp(BIntP, 125)
+ assert (p == s) is False
+ assert (p != s) is True
+ assert (p < s) is (p <= s) is (s > p) is (s >= p)
+ assert (p > s) is (p >= s) is (s < p) is (s <= p)
+ assert (p < s) ^ (p > s)
+
+def test_buffer():
+ try:
+ import __builtin__
+ except ImportError:
+ import builtins as __builtin__
+ BShort = new_primitive_type("short")
+ s = newp(new_pointer_type(BShort), 100)
+ assert sizeof(s) == size_of_ptr()
+ assert sizeof(BShort) == 2
+ assert len(buffer(s)) == 2
+ #
+ BChar = new_primitive_type("char")
+ BCharArray = new_array_type(new_pointer_type(BChar), None)
+ c = newp(BCharArray, b"hi there")
+ #
+ buf = buffer(c)
+ assert repr(buf).startswith('<_cffi_backend.buffer object at 0x')
+ assert bytes(buf) == b"hi there\x00"
+ assert type(buf) is buffer
+ if sys.version_info < (3,):
+ assert str(buf) == "hi there\x00"
+ assert unicode(buf) == u+"hi there\x00"
+ else:
+ assert str(buf) == repr(buf)
+ # --mb_length--
+ assert len(buf) == len(b"hi there\x00")
+ # --mb_item--
+ for i in range(-12, 12):
+ try:
+ expected = b"hi there\x00"[i]
+ except IndexError:
+ with pytest.raises(IndexError):
+ buf[i]
+ else:
+ assert buf[i] == bitem2bchr(expected)
+ # --mb_slice--
+ assert buf[:] == b"hi there\x00"
+ for i in range(-12, 12):
+ assert buf[i:] == b"hi there\x00"[i:]
+ assert buf[:i] == b"hi there\x00"[:i]
+ for j in range(-12, 12):
+ assert buf[i:j] == b"hi there\x00"[i:j]
+ # --misc--
+ assert list(buf) == list(map(bitem2bchr, b"hi there\x00"))
+ # --mb_as_buffer--
+ if hasattr(__builtin__, 'buffer'): # Python <= 2.7
+ py.test.raises(TypeError, __builtin__.buffer, c)
+ bf1 = __builtin__.buffer(buf)
+ assert len(bf1) == len(buf) and bf1[3] == "t"
+ if hasattr(__builtin__, 'memoryview'): # Python >= 2.7
+ py.test.raises(TypeError, memoryview, c)
+ mv1 = memoryview(buf)
+ assert len(mv1) == len(buf) and mv1[3] in (b"t", ord(b"t"))
+ # --mb_ass_item--
+ expected = list(map(bitem2bchr, b"hi there\x00"))
+ for i in range(-12, 12):
+ try:
+ expected[i] = bytechr(i & 0xff)
+ except IndexError:
+ with pytest.raises(IndexError):
+ buf[i] = bytechr(i & 0xff)
+ else:
+ buf[i] = bytechr(i & 0xff)
+ assert list(buf) == expected
+ # --mb_ass_slice--
+ buf[:] = b"hi there\x00"
+ assert list(buf) == list(c) == list(map(bitem2bchr, b"hi there\x00"))
+ with pytest.raises(ValueError):
+ buf[:] = b"shorter"
+ with pytest.raises(ValueError):
+ buf[:] = b"this is much too long!"
+ buf[4:2] = b"" # no effect, but should work
+ assert buf[:] == b"hi there\x00"
+ buf[:2] = b"HI"
+ assert buf[:] == b"HI there\x00"
+ buf[:2] = b"hi"
+ expected = list(map(bitem2bchr, b"hi there\x00"))
+ x = 0
+ for i in range(-12, 12):
+ for j in range(-12, 12):
+ start = i if i >= 0 else i + len(buf)
+ stop = j if j >= 0 else j + len(buf)
+ start = max(0, min(len(buf), start))
+ stop = max(0, min(len(buf), stop))
+ sample = bytechr(x & 0xff) * (stop - start)
+ x += 1
+ buf[i:j] = sample
+ expected[i:j] = map(bitem2bchr, sample)
+ assert list(buf) == expected
+
+def test_getcname():
+ BUChar = new_primitive_type("unsigned char")
+ BArray = new_array_type(new_pointer_type(BUChar), 123)
+ assert getcname(BArray, "<-->") == "unsigned char<-->[123]"
+
+def test_errno():
+ BVoid = new_void_type()
+ BFunc5 = new_function_type((), BVoid)
+ f = cast(BFunc5, _testfunc(5))
+ set_errno(50)
+ f()
+ assert get_errno() == 65
+ f(); f()
+ assert get_errno() == 95
+
+def test_errno_callback():
+ if globals().get('PY_DOT_PY') == '2.5':
+ py.test.skip("cannot run this test on py.py with Python 2.5")
+ set_errno(95)
+ def cb():
+ e = get_errno()
+ set_errno(e - 6)
+ BVoid = new_void_type()
+ BFunc5 = new_function_type((), BVoid)
+ f = callback(BFunc5, cb)
+ f()
+ assert get_errno() == 89
+ f(); f()
+ assert get_errno() == 77
+
+def test_cast_to_array():
+ # not valid in C! extension to get a non-owning <cdata 'int[3]'>
+ BInt = new_primitive_type("int")
+ BIntP = new_pointer_type(BInt)
+ BArray = new_array_type(BIntP, 3)
+ x = cast(BArray, 0)
+ assert repr(x) == "<cdata 'int[3]' NULL>"
+
+def test_cast_invalid():
+ BStruct = new_struct_type("struct foo")
+ complete_struct_or_union(BStruct, [])
+ p = cast(new_pointer_type(BStruct), 123456)
+ s = p[0]
+ py.test.raises(TypeError, cast, BStruct, s)
+
+def test_bug_float_convertion():
+ BDouble = new_primitive_type("double")
+ BDoubleP = new_pointer_type(BDouble)
+ py.test.raises(TypeError, newp, BDoubleP, "foobar")
+
+def test_bug_delitem():
+ BChar = new_primitive_type("char")
+ BCharP = new_pointer_type(BChar)
+ x = newp(BCharP)
+ with pytest.raises(TypeError):
+ del x[0]
+
+def test_bug_delattr():
+ BLong = new_primitive_type("long")
+ BStruct = new_struct_type("struct foo")
+ complete_struct_or_union(BStruct, [('a1', BLong, -1)])
+ x = newp(new_pointer_type(BStruct))
+ with pytest.raises(AttributeError):
+ del x.a1
+
+def test_variable_length_struct():
+ py.test.skip("later")
+ BLong = new_primitive_type("long")
+ BArray = new_array_type(new_pointer_type(BLong), None)
+ BStruct = new_struct_type("struct foo")
+ BStructP = new_pointer_type(BStruct)
+ complete_struct_or_union(BStruct, [('a1', BLong, -1),
+ ('a2', BArray, -1)])
+ assert sizeof(BStruct) == size_of_long()
+ assert alignof(BStruct) == alignof(BLong)
+ #
+ py.test.raises(TypeError, newp, BStructP, None)
+ x = newp(BStructP, 5)
+ assert sizeof(x) == 6 * size_of_long()
+ x[4] = 123
+ assert x[4] == 123
+ with pytest.raises(IndexError):
+ x[5]
+ assert len(x.a2) == 5
+ #
+ py.test.raises(TypeError, newp, BStructP, [123])
+ x = newp(BStructP, [123, 5])
+ assert x.a1 == 123
+ assert len(x.a2) == 5
+ assert list(x.a2) == [0] * 5
+ #
+ x = newp(BStructP, {'a2': 5})
+ assert x.a1 == 0
+ assert len(x.a2) == 5
+ assert list(x.a2) == [0] * 5
+ #
+ x = newp(BStructP, [123, (4, 5)])
+ assert x.a1 == 123
+ assert len(x.a2) == 2
+ assert list(x.a2) == [4, 5]
+ #
+ x = newp(BStructP, {'a2': (4, 5)})
+ assert x.a1 == 0
+ assert len(x.a2) == 2
+ assert list(x.a2) == [4, 5]
+
+def test_autocast_int():
+ BInt = new_primitive_type("int")
+ BIntPtr = new_pointer_type(BInt)
+ BLongLong = new_primitive_type("long long")
+ BULongLong = new_primitive_type("unsigned long long")
+ BULongLongPtr = new_pointer_type(BULongLong)
+ x = newp(BIntPtr, cast(BInt, 42))
+ assert x[0] == 42
+ x = newp(BIntPtr, cast(BLongLong, 42))
+ assert x[0] == 42
+ x = newp(BIntPtr, cast(BULongLong, 42))
+ assert x[0] == 42
+ x = newp(BULongLongPtr, cast(BInt, 42))
+ assert x[0] == 42
+ py.test.raises(OverflowError, newp, BULongLongPtr, cast(BInt, -42))
+ x = cast(BInt, cast(BInt, 42))
+ assert int(x) == 42
+ x = cast(BInt, cast(BLongLong, 42))
+ assert int(x) == 42
+ x = cast(BInt, cast(BULongLong, 42))
+ assert int(x) == 42
+ x = cast(BULongLong, cast(BInt, 42))
+ assert int(x) == 42
+ x = cast(BULongLong, cast(BInt, -42))
+ assert int(x) == 2 ** 64 - 42
+ x = cast(BIntPtr, cast(BInt, 42))
+ assert int(cast(BInt, x)) == 42
+
+def test_autocast_float():
+ BFloat = new_primitive_type("float")
+ BDouble = new_primitive_type("float")
+ BFloatPtr = new_pointer_type(BFloat)
+ x = newp(BFloatPtr, cast(BDouble, 12.5))
+ assert x[0] == 12.5
+ x = cast(BFloat, cast(BDouble, 12.5))
+ assert float(x) == 12.5
+
+def test_longdouble():
+ py_py = 'PY_DOT_PY' in globals()
+ BInt = new_primitive_type("int")
+ BLongDouble = new_primitive_type("long double")
+ BLongDoublePtr = new_pointer_type(BLongDouble)
+ BLongDoubleArray = new_array_type(BLongDoublePtr, None)
+ a = newp(BLongDoubleArray, 1)
+ x = a[0]
+ if not py_py:
+ assert repr(x).startswith("<cdata 'long double' 0.0")
+ assert float(x) == 0.0
+ assert int(x) == 0
+ #
+ b = newp(BLongDoubleArray, [1.23])
+ x = b[0]
+ if not py_py:
+ assert repr(x).startswith("<cdata 'long double' 1.23")
+ assert float(x) == 1.23
+ assert int(x) == 1
+ #
+ BFunc19 = new_function_type((BLongDouble, BInt), BLongDouble)
+ f = cast(BFunc19, _testfunc(19))
+ start = lstart = 1.5
+ for i in range(107):
+ start = 4 * start - start * start
+ lstart = f(lstart, 1)
+ lother = f(1.5, 107)
+ if not py_py:
+ assert float(lstart) == float(lother)
+ assert repr(lstart) == repr(lother)
+ if sizeof(BLongDouble) > sizeof(new_primitive_type("double")):
+ assert float(lstart) != start
+ assert repr(lstart).startswith("<cdata 'long double' ")
+ #
+ c = newp(BLongDoubleArray, [lstart])
+ x = c[0]
+ assert float(f(lstart, 107)) == float(f(x, 107))
+
+def test_get_array_of_length_zero():
+ for length in [0, 5, 10]:
+ BLong = new_primitive_type("long")
+ BLongP = new_pointer_type(BLong)
+ BArray0 = new_array_type(BLongP, length)
+ BStruct = new_struct_type("struct foo")
+ BStructPtr = new_pointer_type(BStruct)
+ complete_struct_or_union(BStruct, [('a1', BArray0, -1)])
+ p = newp(BStructPtr, None)
+ if length == 0:
+ assert repr(p.a1).startswith("<cdata 'long *' 0x")
+ else:
+ assert repr(p.a1).startswith("<cdata 'long[%d]' 0x" % length)
+
+def test_nested_anonymous_struct():
+ BInt = new_primitive_type("int")
+ BChar = new_primitive_type("char")
+ BStruct = new_struct_type("struct foo")
+ BInnerStruct = new_struct_type("struct foo")
+ complete_struct_or_union(BInnerStruct, [('a1', BInt, -1),
+ ('a2', BChar, -1)])
+ complete_struct_or_union(BStruct, [('', BInnerStruct, -1),
+ ('a3', BChar, -1)])
+ assert sizeof(BInnerStruct) == sizeof(BInt) * 2 # with alignment
+ assert sizeof(BStruct) == sizeof(BInt) * 3 # 'a3' is placed after
+ d = BStruct.fields
+ assert len(d) == 3
+ assert d[0][0] == 'a1'
+ assert d[0][1].type is BInt
+ assert d[0][1].offset == 0
+ assert d[0][1].bitshift == -1
+ assert d[0][1].bitsize == -1
+ assert d[1][0] == 'a2'
+ assert d[1][1].type is BChar
+ assert d[1][1].offset == sizeof(BInt)
+ assert d[1][1].bitshift == -1
+ assert d[1][1].bitsize == -1
+ assert d[2][0] == 'a3'
+ assert d[2][1].type is BChar
+ assert d[2][1].offset == sizeof(BInt) * 2
+ assert d[2][1].bitshift == -1
+ assert d[2][1].bitsize == -1
+
+def test_nested_anonymous_struct_2():
+ BInt = new_primitive_type("int")
+ BStruct = new_struct_type("struct foo")
+ BInnerUnion = new_union_type("union bar")
+ complete_struct_or_union(BInnerUnion, [('a1', BInt, -1),
+ ('a2', BInt, -1)])
+ complete_struct_or_union(BStruct, [('b1', BInt, -1),
+ ('', BInnerUnion, -1),
+ ('b2', BInt, -1)])
+ assert sizeof(BInnerUnion) == sizeof(BInt)
+ assert sizeof(BStruct) == sizeof(BInt) * 3
+ fields = [(name, fld.offset, fld.flags) for (name, fld) in BStruct.fields]
+ assert fields == [
+ ('b1', 0 * sizeof(BInt), 0),
+ ('a1', 1 * sizeof(BInt), 0),
+ ('a2', 1 * sizeof(BInt), 1),
+ ('b2', 2 * sizeof(BInt), 0),
+ ]
+
+def test_sizeof_union():
+ # a union has the largest alignment of its members, and a total size
+ # that is the largest of its items *possibly further aligned* if
+ # another smaller item has a larger alignment...
+ BChar = new_primitive_type("char")
+ BShort = new_primitive_type("short")
+ assert sizeof(BShort) == alignof(BShort) == 2
+ BStruct = new_struct_type("struct foo")
+ complete_struct_or_union(BStruct, [('a1', BChar),
+ ('a2', BChar),
+ ('a3', BChar)])
+ assert sizeof(BStruct) == 3 and alignof(BStruct) == 1
+ BUnion = new_union_type("union u")
+ complete_struct_or_union(BUnion, [('s', BStruct),
+ ('i', BShort)])
+ assert sizeof(BUnion) == 4
+ assert alignof(BUnion) == 2
+
+def test_unaligned_struct():
+ BInt = new_primitive_type("int")
+ BStruct = new_struct_type("struct foo")
+ complete_struct_or_union(BStruct, [('b', BInt, -1, 1)],
+ None, 5, 1)
+
+def test_CData_CType():
+ CData, CType = _get_types()
+ BChar = new_primitive_type("char")
+ BCharP = new_pointer_type(BChar)
+ nullchr = cast(BChar, 0)
+ chrref = newp(BCharP, None)
+ assert isinstance(nullchr, CData)
+ assert isinstance(chrref, CData)
+ assert not isinstance(BChar, CData)
+ assert not isinstance(nullchr, CType)
+ assert not isinstance(chrref, CType)
+ assert isinstance(BChar, CType)
+
+def test_no_cdata_float():
+ BInt = new_primitive_type("int")
+ BIntP = new_pointer_type(BInt)
+ BUInt = new_primitive_type("unsigned int")
+ BUIntP = new_pointer_type(BUInt)
+ BFloat = new_primitive_type("float")
+ py.test.raises(TypeError, newp, BIntP, cast(BFloat, 0.0))
+ py.test.raises(TypeError, newp, BUIntP, cast(BFloat, 0.0))
+
+def test_bool():
+ BBool = new_primitive_type("_Bool")
+ BBoolP = new_pointer_type(BBool)
+ assert int(cast(BBool, False)) == 0
+ assert int(cast(BBool, True)) == 1
+ assert bool(cast(BBool, False)) is False # since 1.7
+ assert bool(cast(BBool, True)) is True
+ assert int(cast(BBool, 3)) == 1
+ assert int(cast(BBool, long(3))) == 1
+ assert int(cast(BBool, long(10)**4000)) == 1
+ assert int(cast(BBool, -0.1)) == 1
+ assert int(cast(BBool, -0.0)) == 0
+ assert int(cast(BBool, '\x00')) == 0
+ assert int(cast(BBool, '\xff')) == 1
+ assert newp(BBoolP, False)[0] == 0
+ assert newp(BBoolP, True)[0] == 1
+ assert newp(BBoolP, 0)[0] == 0
+ assert newp(BBoolP, 1)[0] == 1
+ py.test.raises(TypeError, newp, BBoolP, 1.0)
+ py.test.raises(TypeError, newp, BBoolP, '\x00')
+ py.test.raises(OverflowError, newp, BBoolP, 2)
+ py.test.raises(OverflowError, newp, BBoolP, -1)
+ BCharP = new_pointer_type(new_primitive_type("char"))
+ p = newp(BCharP, b'\x01')
+ q = cast(BBoolP, p)
+ assert q[0] is True
+ p = newp(BCharP, b'\x00')
+ q = cast(BBoolP, p)
+ assert q[0] is False
+ py.test.raises(TypeError, string, cast(BBool, False))
+ BDouble = new_primitive_type("double")
+ assert int(cast(BBool, cast(BDouble, 0.1))) == 1
+ assert int(cast(BBool, cast(BDouble, 0.0))) == 0
+ BBoolA = new_array_type(BBoolP, None)
+ p = newp(BBoolA, b'\x01\x00')
+ assert p[0] is True
+ assert p[1] is False
+
+def test_bool_forbidden_cases():
+ BBool = new_primitive_type("_Bool")
+ BBoolP = new_pointer_type(BBool)
+ BBoolA = new_array_type(BBoolP, None)
+ BCharP = new_pointer_type(new_primitive_type("char"))
+ p = newp(BCharP, b'X')
+ q = cast(BBoolP, p)
+ with pytest.raises(ValueError):
+ q[0]
+ py.test.raises(TypeError, newp, BBoolP, b'\x00')
+ assert newp(BBoolP, 0)[0] is False
+ assert newp(BBoolP, 1)[0] is True
+ py.test.raises(OverflowError, newp, BBoolP, 2)
+ py.test.raises(OverflowError, newp, BBoolP, -1)
+ py.test.raises(ValueError, newp, BBoolA, b'\x00\x01\x02')
+ py.test.raises(OverflowError, newp, BBoolA, [0, 1, 2])
+ py.test.raises(TypeError, string, newp(BBoolP, 1))
+ py.test.raises(TypeError, string, newp(BBoolA, [1]))
+
+def test_typeoffsetof():
+ BChar = new_primitive_type("char")
+ BStruct = new_struct_type("struct foo")
+ BStructPtr = new_pointer_type(BStruct)
+ complete_struct_or_union(BStruct, [('a1', BChar, -1),
+ ('a2', BChar, -1),
+ ('a3', BChar, -1)])
+ py.test.raises(TypeError, typeoffsetof, BStructPtr, None)
+ py.test.raises(TypeError, typeoffsetof, BStruct, None)
+ assert typeoffsetof(BStructPtr, 'a1') == (BChar, 0)
+ assert typeoffsetof(BStruct, 'a1') == (BChar, 0)
+ assert typeoffsetof(BStructPtr, 'a2') == (BChar, 1)
+ assert typeoffsetof(BStruct, 'a3') == (BChar, 2)
+ assert typeoffsetof(BStructPtr, 'a2', 0) == (BChar, 1)
+ assert typeoffsetof(BStruct, u+'a3') == (BChar, 2)
+ py.test.raises(TypeError, typeoffsetof, BStructPtr, 'a2', 1)
+ py.test.raises(KeyError, typeoffsetof, BStructPtr, 'a4')
+ py.test.raises(KeyError, typeoffsetof, BStruct, 'a5')
+ py.test.raises(TypeError, typeoffsetof, BStruct, 42)
+ py.test.raises(TypeError, typeoffsetof, BChar, 'a1')
+
+def test_typeoffsetof_array():
+ BInt = new_primitive_type("int")
+ BIntP = new_pointer_type(BInt)
+ BArray = new_array_type(BIntP, None)
+ py.test.raises(TypeError, typeoffsetof, BArray, None)
+ py.test.raises(TypeError, typeoffsetof, BArray, 'a1')
+ assert typeoffsetof(BArray, 51) == (BInt, 51 * size_of_int())
+ assert typeoffsetof(BIntP, 51) == (BInt, 51 * size_of_int())
+ assert typeoffsetof(BArray, -51) == (BInt, -51 * size_of_int())
+ MAX = sys.maxsize // size_of_int()
+ assert typeoffsetof(BArray, MAX) == (BInt, MAX * size_of_int())
+ assert typeoffsetof(BIntP, MAX) == (BInt, MAX * size_of_int())
+ py.test.raises(OverflowError, typeoffsetof, BArray, MAX + 1)
+
+def test_typeoffsetof_no_bitfield():
+ BInt = new_primitive_type("int")
+ BStruct = new_struct_type("struct foo")
+ complete_struct_or_union(BStruct, [('a1', BInt, 4)])
+ py.test.raises(TypeError, typeoffsetof, BStruct, 'a1')
+
+def test_rawaddressof():
+ BChar = new_primitive_type("char")
+ BCharP = new_pointer_type(BChar)
+ BStruct = new_struct_type("struct foo")
+ BStructPtr = new_pointer_type(BStruct)
+ complete_struct_or_union(BStruct, [('a1', BChar, -1),
+ ('a2', BChar, -1),
+ ('a3', BChar, -1)])
+ p = newp(BStructPtr)
+ assert repr(p) == "<cdata 'struct foo *' owning 3 bytes>"
+ s = p[0]
+ assert repr(s) == "<cdata 'struct foo' owning 3 bytes>"
+ a = rawaddressof(BStructPtr, s, 0)
+ assert repr(a).startswith("<cdata 'struct foo *' 0x")
+ py.test.raises(TypeError, rawaddressof, BStruct, s, 0)
+ b = rawaddressof(BCharP, s, 0)
+ assert b == cast(BCharP, p)
+ c = rawaddressof(BStructPtr, a, 0)
+ assert c == a
+ py.test.raises(TypeError, rawaddressof, BStructPtr, cast(BChar, '?'), 0)
+ #
+ d = rawaddressof(BCharP, s, 1)
+ assert d == cast(BCharP, p) + 1
+ #
+ e = cast(BCharP, 109238)
+ f = rawaddressof(BCharP, e, 42)
+ assert f == e + 42
+ #
+ BCharA = new_array_type(BCharP, None)
+ e = newp(BCharA, 50)
+ f = rawaddressof(BCharP, e, 42)
+ assert f == e + 42
+
+def test_newp_signed_unsigned_char():
+ BCharArray = new_array_type(
+ new_pointer_type(new_primitive_type("char")), None)
+ p = newp(BCharArray, b"foo")
+ assert len(p) == 4
+ assert list(p) == [b"f", b"o", b"o", b"\x00"]
+ #
+ BUCharArray = new_array_type(
+ new_pointer_type(new_primitive_type("unsigned char")), None)
+ p = newp(BUCharArray, b"fo\xff")
+ assert len(p) == 4
+ assert list(p) == [ord("f"), ord("o"), 0xff, 0]
+ #
+ BSCharArray = new_array_type(
+ new_pointer_type(new_primitive_type("signed char")), None)
+ p = newp(BSCharArray, b"fo\xff")
+ assert len(p) == 4
+ assert list(p) == [ord("f"), ord("o"), -1, 0]
+
+def test_newp_from_bytearray_doesnt_work():
+ BCharArray = new_array_type(
+ new_pointer_type(new_primitive_type("char")), None)
+ py.test.raises(TypeError, newp, BCharArray, bytearray(b"foo"))
+ p = newp(BCharArray, 5)
+ buffer(p)[:] = bytearray(b"foo.\x00")
+ assert len(p) == 5
+ assert list(p) == [b"f", b"o", b"o", b".", b"\x00"]
+ p[1:3] = bytearray(b"XY")
+ assert list(p) == [b"f", b"X", b"Y", b".", b"\x00"]
+
+def test_string_assignment_to_byte_array():
+ BByteArray = new_array_type(
+ new_pointer_type(new_primitive_type("unsigned char")), None)
+ p = newp(BByteArray, 5)
+ p[0:3] = bytearray(b"XYZ")
+ assert list(p) == [ord("X"), ord("Y"), ord("Z"), 0, 0]
+
+# XXX hack
+if sys.version_info >= (3,):
+ try:
+ import posix, io
+ posix.fdopen = io.open
+ except ImportError:
+ pass # win32
+
+def test_FILE():
+ if sys.platform == "win32":
+ py.test.skip("testing FILE not implemented")
+ #
+ BFILE = new_struct_type("struct _IO_FILE")
+ BFILEP = new_pointer_type(BFILE)
+ BChar = new_primitive_type("char")
+ BCharP = new_pointer_type(BChar)
+ BInt = new_primitive_type("int")
+ BFunc = new_function_type((BCharP, BFILEP), BInt, False)
+ BFunc2 = new_function_type((BFILEP, BCharP), BInt, True)
+ ll = find_and_load_library('c')
+ fputs = ll.load_function(BFunc, "fputs")
+ fscanf = ll.load_function(BFunc2, "fscanf")
+ #
+ import posix
+ fdr, fdw = posix.pipe()
+ fr1 = posix.fdopen(fdr, 'rb', 256)
+ fw1 = posix.fdopen(fdw, 'wb', 256)
+ #
+ fw1.write(b"X")
+ res = fputs(b"hello world\n", fw1)
+ assert res >= 0
+ fw1.flush() # should not be needed
+ #
+ p = newp(new_array_type(BCharP, 100), None)
+ res = fscanf(fr1, b"%s\n", p)
+ assert res == 1
+ assert string(p) == b"Xhello"
+ fr1.close()
+ fw1.close()
+
+def test_FILE_only_for_FILE_arg():
+ if sys.platform == "win32":
+ py.test.skip("testing FILE not implemented")
+ #
+ B_NOT_FILE = new_struct_type("struct NOT_FILE")
+ B_NOT_FILEP = new_pointer_type(B_NOT_FILE)
+ BChar = new_primitive_type("char")
+ BCharP = new_pointer_type(BChar)
+ BInt = new_primitive_type("int")
+ BFunc = new_function_type((BCharP, B_NOT_FILEP), BInt, False)
+ ll = find_and_load_library('c')
+ fputs = ll.load_function(BFunc, "fputs")
+ #
+ import posix
+ fdr, fdw = posix.pipe()
+ fr1 = posix.fdopen(fdr, 'r')
+ fw1 = posix.fdopen(fdw, 'w')
+ #
+ e = py.test.raises(TypeError, fputs, b"hello world\n", fw1)
+ assert str(e.value).startswith(
+ "initializer for ctype 'struct NOT_FILE *' must "
+ "be a cdata pointer, not ")
+
+def test_FILE_object():
+ if sys.platform == "win32":
+ py.test.skip("testing FILE not implemented")
+ #
+ BFILE = new_struct_type("FILE")
+ BFILEP = new_pointer_type(BFILE)
+ BChar = new_primitive_type("char")
+ BCharP = new_pointer_type(BChar)
+ BInt = new_primitive_type("int")
+ BFunc = new_function_type((BCharP, BFILEP), BInt, False)
+ BFunc2 = new_function_type((BFILEP,), BInt, False)
+ ll = find_and_load_library('c')
+ fputs = ll.load_function(BFunc, "fputs")
+ fileno = ll.load_function(BFunc2, "fileno")
+ #
+ import posix
+ fdr, fdw = posix.pipe()
+ fw1 = posix.fdopen(fdw, 'wb', 256)
+ #
+ fw1p = cast(BFILEP, fw1)
+ fw1.write(b"X")
+ fw1.flush()
+ res = fputs(b"hello\n", fw1p)
+ assert res >= 0
+ res = fileno(fw1p)
+ assert (res == fdw) == (sys.version_info < (3,))
+ fw1.close()
+ #
+ data = posix.read(fdr, 256)
+ assert data == b"Xhello\n"
+ posix.close(fdr)
+
+def test_errno_saved():
+ set_errno(42)
+ # a random function that will reset errno to 0 (at least on non-windows)
+ import os; os.stat('.')
+ #
+ res = get_errno()
+ assert res == 42
+
+def test_GetLastError():
+ if sys.platform != "win32":
+ py.test.skip("GetLastError(): only for Windows")
+ #
+ lib = find_and_load_library('KERNEL32.DLL')
+ BInt = new_primitive_type("int")
+ BVoid = new_void_type()
+ BFunc1 = new_function_type((BInt,), BVoid, False)
+ BFunc2 = new_function_type((), BInt, False)
+ SetLastError = lib.load_function(BFunc1, "SetLastError")
+ GetLastError = lib.load_function(BFunc2, "GetLastError")
+ #
+ SetLastError(42)
+ # a random function that will reset the real GetLastError() to 0
+ import nt; nt.stat('.')
+ #
+ res = GetLastError()
+ assert res == 42
+ #
+ SetLastError(2)
+ code, message = getwinerror()
+ assert code == 2
+ assert message == "The system cannot find the file specified"
+ #
+ code, message = getwinerror(1155)
+ assert code == 1155
+ assert message == ("No application is associated with the "
+ "specified file for this operation")
+
+def test_nonstandard_integer_types():
+ for typename in ['int8_t', 'uint8_t', 'int16_t', 'uint16_t', 'int32_t',
+ 'uint32_t', 'int64_t', 'uint64_t', 'intptr_t',
+ 'uintptr_t', 'ptrdiff_t', 'size_t', 'ssize_t',
+ 'int_least8_t', 'uint_least8_t',
+ 'int_least16_t', 'uint_least16_t',
+ 'int_least32_t', 'uint_least32_t',
+ 'int_least64_t', 'uint_least64_t',
+ 'int_fast8_t', 'uint_fast8_t',
+ 'int_fast16_t', 'uint_fast16_t',
+ 'int_fast32_t', 'uint_fast32_t',
+ 'int_fast64_t', 'uint_fast64_t',
+ 'intmax_t', 'uintmax_t']:
+ new_primitive_type(typename) # works
+
+def test_cannot_convert_unicode_to_charp():
+ BCharP = new_pointer_type(new_primitive_type("char"))
+ BCharArray = new_array_type(BCharP, None)
+ py.test.raises(TypeError, newp, BCharArray, u+'foobar')
+
+def test_buffer_keepalive():
+ BCharP = new_pointer_type(new_primitive_type("char"))
+ BCharArray = new_array_type(BCharP, None)
+ buflist = []
+ for i in range(20):
+ c = newp(BCharArray, str2bytes("hi there %d" % i))
+ buflist.append(buffer(c))
+ import gc; gc.collect()
+ for i in range(20):
+ buf = buflist[i]
+ assert buf[:] == str2bytes("hi there %d\x00" % i)
+
+def test_slice():
+ BIntP = new_pointer_type(new_primitive_type("int"))
+ BIntArray = new_array_type(BIntP, None)
+ c = newp(BIntArray, 5)
+ assert len(c) == 5
+ assert repr(c) == "<cdata 'int[]' owning 20 bytes>"
+ d = c[1:4]
+ assert len(d) == 3
+ assert repr(d) == "<cdata 'int[]' sliced length 3>"
+ d[0] = 123
+ d[2] = 456
+ assert c[1] == 123
+ assert c[3] == 456
+ assert d[2] == 456
+ with pytest.raises(IndexError):
+ d[3]
+ with pytest.raises(IndexError):
+ d[-1]
+
+def test_slice_ptr():
+ BIntP = new_pointer_type(new_primitive_type("int"))
+ BIntArray = new_array_type(BIntP, None)
+ c = newp(BIntArray, 5)
+ d = (c+1)[0:2]
+ assert len(d) == 2
+ assert repr(d) == "<cdata 'int[]' sliced length 2>"
+ d[1] += 50
+ assert c[2] == 50
+
+def test_slice_array_checkbounds():
+ BIntP = new_pointer_type(new_primitive_type("int"))
+ BIntArray = new_array_type(BIntP, None)
+ c = newp(BIntArray, 5)
+ c[0:5]
+ assert len(c[5:5]) == 0
+ with pytest.raises(IndexError):
+ c[-1:1]
+ cp = c + 0
+ cp[-1:1]
+
+def test_nonstandard_slice():
+ BIntP = new_pointer_type(new_primitive_type("int"))
+ BIntArray = new_array_type(BIntP, None)
+ c = newp(BIntArray, 5)
+ with pytest.raises(IndexError) as e:
+ c[:5]
+ assert str(e.value) == "slice start must be specified"
+ with pytest.raises(IndexError) as e:
+ c[4:]
+ assert str(e.value) == "slice stop must be specified"
+ with pytest.raises(IndexError) as e:
+ c[1:2:3]
+ assert str(e.value) == "slice with step not supported"
+ with pytest.raises(IndexError) as e:
+ c[1:2:1]
+ assert str(e.value) == "slice with step not supported"
+ with pytest.raises(IndexError) as e:
+ c[4:2]
+ assert str(e.value) == "slice start > stop"
+ with pytest.raises(IndexError) as e:
+ c[6:6]
+ assert str(e.value) == "index too large (expected 6 <= 5)"
+
+def test_setslice():
+ BIntP = new_pointer_type(new_primitive_type("int"))
+ BIntArray = new_array_type(BIntP, None)
+ c = newp(BIntArray, 5)
+ c[1:3] = [100, 200]
+ assert list(c) == [0, 100, 200, 0, 0]
+ cp = c + 3
+ cp[-1:1] = [300, 400]
+ assert list(c) == [0, 100, 300, 400, 0]
+ cp[-1:1] = iter([500, 600])
+ assert list(c) == [0, 100, 500, 600, 0]
+ with pytest.raises(ValueError):
+ cp[-1:1] = [1000]
+ assert list(c) == [0, 100, 1000, 600, 0]
+ with pytest.raises(ValueError):
+ cp[-1:1] = (700, 800, 900)
+ assert list(c) == [0, 100, 700, 800, 0]
+
+def test_setslice_array():
+ BIntP = new_pointer_type(new_primitive_type("int"))
+ BIntArray = new_array_type(BIntP, None)
+ c = newp(BIntArray, 5)
+ d = newp(BIntArray, [10, 20, 30])
+ c[1:4] = d
+ assert list(c) == [0, 10, 20, 30, 0]
+ #
+ BShortP = new_pointer_type(new_primitive_type("short"))
+ BShortArray = new_array_type(BShortP, None)
+ d = newp(BShortArray, [40, 50])
+ c[1:3] = d
+ assert list(c) == [0, 40, 50, 30, 0]
+
+def test_cdata_name_module_doc():
+ p = new_primitive_type("signed char")
+ x = cast(p, 17)
+ assert x.__module__ == '_cffi_backend'
+ assert x.__name__ == '<cdata>'
+ assert hasattr(x, '__doc__')
+
+def test_different_types_of_ptr_equality():
+ BVoidP = new_pointer_type(new_void_type())
+ BIntP = new_pointer_type(new_primitive_type("int"))
+ x = cast(BVoidP, 12345)
+ assert x == cast(BIntP, 12345)
+ assert x != cast(BIntP, 12344)
+ assert hash(x) == hash(cast(BIntP, 12345))
+
+def test_new_handle():
+ import _weakref
+ BVoidP = new_pointer_type(new_void_type())
+ BCharP = new_pointer_type(new_primitive_type("char"))
+ class mylist(list):
+ pass
+ o = mylist([2, 3, 4])
+ x = newp_handle(BVoidP, o)
+ assert repr(x) == "<cdata 'void *' handle to [2, 3, 4]>"
+ assert x
+ assert from_handle(x) is o
+ assert from_handle(cast(BCharP, x)) is o
+ wr = _weakref.ref(o)
+ del o
+ import gc; gc.collect()
+ assert wr() is not None
+ assert from_handle(x) == list((2, 3, 4))
+ assert from_handle(cast(BCharP, x)) == list((2, 3, 4))
+ del x
+ for i in range(3):
+ if wr() is not None:
+ import gc; gc.collect()
+ assert wr() is None
+ py.test.raises(RuntimeError, from_handle, cast(BCharP, 0))
+
+def test_new_handle_cycle():
+ import _weakref
+ BVoidP = new_pointer_type(new_void_type())
+ class A(object):
+ pass
+ o = A()
+ o.cycle = newp_handle(BVoidP, o)
+ wr = _weakref.ref(o)
+ del o
+ for i in range(3):
+ if wr() is not None:
+ import gc; gc.collect()
+ assert wr() is None
+
+def _test_bitfield_details(flag):
+ BChar = new_primitive_type("char")
+ BShort = new_primitive_type("short")
+ BInt = new_primitive_type("int")
+ BUInt = new_primitive_type("unsigned int")
+ BStruct = new_struct_type("struct foo1")
+ complete_struct_or_union(BStruct, [('a', BChar, -1),
+ ('b1', BInt, 9),
+ ('b2', BUInt, 7),
+ ('c', BChar, -1)], -1, -1, -1, flag)
+ if not (flag & SF_MSVC_BITFIELDS): # gcc, any variant
+ assert typeoffsetof(BStruct, 'c') == (BChar, 3)
+ assert sizeof(BStruct) == 4
+ else: # msvc
+ assert typeoffsetof(BStruct, 'c') == (BChar, 8)
+ assert sizeof(BStruct) == 12
+ assert alignof(BStruct) == 4
+ #
+ p = newp(new_pointer_type(BStruct), None)
+ p.a = b'A'
+ p.b1 = -201
+ p.b2 = 99
+ p.c = b'\x9D'
+ raw = buffer(p)[:]
+ if sys.byteorder == 'little':
+ if flag & SF_MSVC_BITFIELDS:
+ assert raw == b'A\x00\x00\x007\xC7\x00\x00\x9D\x00\x00\x00'
+ elif flag & SF_GCC_LITTLE_ENDIAN:
+ assert raw == b'A7\xC7\x9D'
+ elif flag & SF_GCC_BIG_ENDIAN:
+ assert raw == b'A\xE3\x9B\x9D'
+ else:
+ raise AssertionError("bad flag")
+ else:
+ if flag & SF_MSVC_BITFIELDS:
+ assert raw == b'A\x00\x00\x00\x00\x00\xC77\x9D\x00\x00\x00'
+ elif flag & SF_GCC_LITTLE_ENDIAN:
+ assert raw == b'A\xC77\x9D'
+ elif flag & SF_GCC_BIG_ENDIAN:
+ assert raw == b'A\x9B\xE3\x9D'
+ else:
+ raise AssertionError("bad flag")
+ #
+ BStruct = new_struct_type("struct foo2")
+ complete_struct_or_union(BStruct, [('a', BChar, -1),
+ ('', BShort, 9),
+ ('c', BChar, -1)], -1, -1, -1, flag)
+ assert typeoffsetof(BStruct, 'c') == (BChar, 4)
+ if flag & SF_MSVC_BITFIELDS:
+ assert sizeof(BStruct) == 6
+ assert alignof(BStruct) == 2
+ elif flag & SF_GCC_X86_BITFIELDS:
+ assert sizeof(BStruct) == 5
+ assert alignof(BStruct) == 1
+ elif flag & SF_GCC_ARM_BITFIELDS:
+ assert sizeof(BStruct) == 6
+ assert alignof(BStruct) == 2
+ else:
+ raise AssertionError("bad flag")
+ #
+ BStruct = new_struct_type("struct foo2")
+ complete_struct_or_union(BStruct, [('a', BChar, -1),
+ ('', BInt, 0),
+ ('', BInt, 0),
+ ('c', BChar, -1)], -1, -1, -1, flag)
+ if flag & SF_MSVC_BITFIELDS:
+ assert typeoffsetof(BStruct, 'c') == (BChar, 1)
+ assert sizeof(BStruct) == 2
+ assert alignof(BStruct) == 1
+ elif flag & SF_GCC_X86_BITFIELDS:
+ assert typeoffsetof(BStruct, 'c') == (BChar, 4)
+ assert sizeof(BStruct) == 5
+ assert alignof(BStruct) == 1
+ elif flag & SF_GCC_ARM_BITFIELDS:
+ assert typeoffsetof(BStruct, 'c') == (BChar, 4)
+ assert sizeof(BStruct) == 8
+ assert alignof(BStruct) == 4
+ else:
+ raise AssertionError("bad flag")
+
+
+SF_MSVC_BITFIELDS = 0x01
+SF_GCC_ARM_BITFIELDS = 0x02
+SF_GCC_X86_BITFIELDS = 0x10
+
+SF_GCC_BIG_ENDIAN = 0x04
+SF_GCC_LITTLE_ENDIAN = 0x40
+
+SF_PACKED = 0x08
+
+def test_bitfield_as_x86_gcc():
+ _test_bitfield_details(flag=SF_GCC_X86_BITFIELDS|SF_GCC_LITTLE_ENDIAN)
+
+def test_bitfield_as_msvc():
+ _test_bitfield_details(flag=SF_MSVC_BITFIELDS|SF_GCC_LITTLE_ENDIAN)
+
+def test_bitfield_as_arm_gcc():
+ _test_bitfield_details(flag=SF_GCC_ARM_BITFIELDS|SF_GCC_LITTLE_ENDIAN)
+
+def test_bitfield_as_ppc_gcc():
+ # PowerPC uses the same format as X86, but is big-endian
+ _test_bitfield_details(flag=SF_GCC_X86_BITFIELDS|SF_GCC_BIG_ENDIAN)
+
+
+def test_struct_array_no_length():
+ BInt = new_primitive_type("int")
+ BIntP = new_pointer_type(BInt)
+ BArray = new_array_type(BIntP, None)
+ BStruct = new_struct_type("foo")
+ py.test.raises(TypeError, complete_struct_or_union,
+ BStruct, [('x', BArray),
+ ('y', BInt)])
+ #
+ BStruct = new_struct_type("foo")
+ complete_struct_or_union(BStruct, [('x', BInt),
+ ('y', BArray)])
+ assert sizeof(BStruct) == size_of_int()
+ d = BStruct.fields
+ assert len(d) == 2
+ assert d[0][0] == 'x'
+ assert d[0][1].type is BInt
+ assert d[0][1].offset == 0
+ assert d[0][1].bitshift == -1
+ assert d[0][1].bitsize == -1
+ assert d[1][0] == 'y'
+ assert d[1][1].type is BArray
+ assert d[1][1].offset == size_of_int()
+ assert d[1][1].bitshift == -2
+ assert d[1][1].bitsize == -1
+ #
+ p = newp(new_pointer_type(BStruct))
+ p.x = 42
+ assert p.x == 42
+ assert typeof(p.y) is BArray
+ assert len(p.y) == 0
+ assert p.y == cast(BIntP, p) + 1
+ #
+ p = newp(new_pointer_type(BStruct), [100])
+ assert p.x == 100
+ assert len(p.y) == 0
+ #
+ # Tests for
+ # ffi.new("struct_with_var_array *", [field.., [the_array_items..]])
+ # ffi.new("struct_with_var_array *", [field.., array_size])
+ plist = []
+ for i in range(20):
+ if i % 2 == 0:
+ p = newp(new_pointer_type(BStruct), [100, [200, i, 400]])
+ else:
+ p = newp(new_pointer_type(BStruct), [100, 3])
+ p.y[1] = i
+ p.y[0] = 200
+ assert p.y[2] == 0
+ p.y[2] = 400
+ assert len(p.y) == 3
+ assert len(p[0].y) == 3
+ assert len(buffer(p)) == sizeof(BInt) * 4
+ assert sizeof(p[0]) == sizeof(BInt) * 4
+ plist.append(p)
+ for i in range(20):
+ p = plist[i]
+ assert p.x == 100
+ assert p.y[0] == 200
+ assert p.y[1] == i
+ assert p.y[2] == 400
+ assert list(p.y) == [200, i, 400]
+ #
+ # the following assignment works, as it normally would, for any array field
+ p.y = [501, 601]
+ assert list(p.y) == [501, 601, 400]
+ p[0].y = [500, 600]
+ assert list(p[0].y) == [500, 600, 400]
+ assert repr(p) == "<cdata 'foo *' owning %d bytes>" % (
+ sizeof(BStruct) + 3 * sizeof(BInt),)
+ assert repr(p[0]) == "<cdata 'foo' owning %d bytes>" % (
+ sizeof(BStruct) + 3 * sizeof(BInt),)
+ assert sizeof(p[0]) == sizeof(BStruct) + 3 * sizeof(BInt)
+ #
+ # from a non-owning pointer, we can't get the length
+ q = cast(new_pointer_type(BStruct), p)
+ assert q.y[0] == 500
+ assert q[0].y[0] == 500
+ py.test.raises(TypeError, len, q.y)
+ py.test.raises(TypeError, len, q[0].y)
+ assert typeof(q.y) is BIntP
+ assert typeof(q[0].y) is BIntP
+ assert sizeof(q[0]) == sizeof(BStruct)
+ #
+ # error cases
+ with pytest.raises(IndexError):
+ p.y[4]
+ with pytest.raises(TypeError):
+ p.y = cast(BIntP, 0)
+ with pytest.raises(TypeError):
+ p.y = 15
+ with pytest.raises(TypeError):
+ p.y = None
+ #
+ # accepting this may be specified by the C99 standard,
+ # or a GCC strangeness...
+ BStruct2 = new_struct_type("bar")
+ complete_struct_or_union(BStruct2, [('f', BStruct),
+ ('n', BInt)])
+ p = newp(new_pointer_type(BStruct2), {'n': 42})
+ assert p.n == 42
+ #
+ # more error cases
+ py.test.raises(TypeError, newp, new_pointer_type(BStruct), [100, None])
+ BArray4 = new_array_type(BIntP, 4)
+ BStruct4 = new_struct_type("test4")
+ complete_struct_or_union(BStruct4, [('a', BArray4)]) # not varsized
+ py.test.raises(TypeError, newp, new_pointer_type(BStruct4), [None])
+ py.test.raises(TypeError, newp, new_pointer_type(BStruct4), [4])
+ p = newp(new_pointer_type(BStruct4), [[10, 20, 30]])
+ assert p.a[0] == 10
+ assert p.a[1] == 20
+ assert p.a[2] == 30
+ assert p.a[3] == 0
+ #
+ # struct of struct of varsized array
+ BStruct2 = new_struct_type("bar")
+ complete_struct_or_union(BStruct2, [('head', BInt),
+ ('tail', BStruct)])
+ for i in range(2): # try to detect heap overwrites
+ p = newp(new_pointer_type(BStruct2), [100, [200, list(range(50))]])
+ assert p.tail.y[49] == 49
+
+
+def test_struct_array_no_length_explicit_position():
+ BInt = new_primitive_type("int")
+ BIntP = new_pointer_type(BInt)
+ BArray = new_array_type(BIntP, None)
+ BStruct = new_struct_type("foo")
+ complete_struct_or_union(BStruct, [('x', BArray, -1, 0), # actually 3 items
+ ('y', BInt, -1, 12)])
+ p = newp(new_pointer_type(BStruct), [[10, 20], 30])
+ assert p.x[0] == 10
+ assert p.x[1] == 20
+ assert p.x[2] == 0
+ assert p.y == 30
+ p = newp(new_pointer_type(BStruct), {'x': [40], 'y': 50})
+ assert p.x[0] == 40
+ assert p.x[1] == 0
+ assert p.x[2] == 0
+ assert p.y == 50
+ p = newp(new_pointer_type(BStruct), {'y': 60})
+ assert p.x[0] == 0
+ assert p.x[1] == 0
+ assert p.x[2] == 0
+ assert p.y == 60
+ #
+ # This "should" work too, allocating a larger structure
+ # (a bit strange in this case, but useful in general)
+ plist = []
+ for i in range(20):
+ p = newp(new_pointer_type(BStruct), [[10, 20, 30, 40, 50, 60, 70]])
+ plist.append(p)
+ for i in range(20):
+ p = plist[i]
+ assert p.x[0] == 10
+ assert p.x[1] == 20
+ assert p.x[2] == 30
+ assert p.x[3] == 40 == p.y
+ assert p.x[4] == 50
+ assert p.x[5] == 60
+ assert p.x[6] == 70
+
+def test_struct_array_not_aligned():
+ # struct a { int x; char y; char z[]; };
+ # ends up of size 8, but 'z' is at offset 5
+ BChar = new_primitive_type("char")
+ BInt = new_primitive_type("int")
+ BCharP = new_pointer_type(BChar)
+ BArray = new_array_type(BCharP, None)
+ BStruct = new_struct_type("foo")
+ complete_struct_or_union(BStruct, [('x', BInt),
+ ('y', BChar),
+ ('z', BArray)])
+ assert sizeof(BStruct) == 2 * size_of_int()
+ def offsetof(BType, fieldname):
+ return typeoffsetof(BType, fieldname)[1]
+ base = offsetof(BStruct, 'z')
+ assert base == size_of_int() + 1
+ #
+ p = newp(new_pointer_type(BStruct), {'z': 3})
+ assert sizeof(p[0]) == base + 3
+ q = newp(new_pointer_type(BStruct), {'z': size_of_int()})
+ assert sizeof(q) == size_of_ptr()
+ assert sizeof(q[0]) == base + size_of_int()
+ assert len(p.z) == 3
+ assert len(p[0].z) == 3
+ assert len(q.z) == size_of_int()
+ assert len(q[0].z) == size_of_int()
+
+def test_ass_slice():
+ BChar = new_primitive_type("char")
+ BArray = new_array_type(new_pointer_type(BChar), None)
+ p = newp(BArray, b"foobar")
+ p[2:5] = [b"*", b"Z", b"T"]
+ p[1:3] = b"XY"
+ assert list(p) == [b"f", b"X", b"Y", b"Z", b"T", b"r", b"\x00"]
+ with pytest.raises(TypeError):
+ p[1:5] = u+'XYZT'
+ with pytest.raises(TypeError):
+ p[1:5] = [1, 2, 3, 4]
+ #
+ for typename in ["wchar_t", "char16_t", "char32_t"]:
+ BUniChar = new_primitive_type(typename)
+ BArray = new_array_type(new_pointer_type(BUniChar), None)
+ p = newp(BArray, u+"foobar")
+ p[2:5] = [u+"*", u+"Z", u+"T"]
+ p[1:3] = u+"XY"
+ assert list(p) == [u+"f", u+"X", u+"Y", u+"Z", u+"T", u+"r", u+"\x00"]
+ with pytest.raises(TypeError):
+ p[1:5] = b'XYZT'
+ with pytest.raises(TypeError):
+ p[1:5] = [1, 2, 3, 4]
+
+def test_void_p_arithmetic():
+ BVoid = new_void_type()
+ BInt = new_primitive_type("intptr_t")
+ p = cast(new_pointer_type(BVoid), 100000)
+ assert int(cast(BInt, p)) == 100000
+ assert int(cast(BInt, p + 42)) == 100042
+ assert int(cast(BInt, p - (-42))) == 100042
+ assert (p + 42) - p == 42
+ q = cast(new_pointer_type(new_primitive_type("char")), 100000)
+ with pytest.raises(TypeError):
+ p - q
+ with pytest.raises(TypeError):
+ q - p
+ with pytest.raises(TypeError):
+ p + cast(new_primitive_type('int'), 42)
+ with pytest.raises(TypeError):
+ p - cast(new_primitive_type('int'), 42)
+
+def test_sizeof_sliced_array():
+ BInt = new_primitive_type("int")
+ BArray = new_array_type(new_pointer_type(BInt), 10)
+ p = newp(BArray, None)
+ assert sizeof(p[2:9]) == 7 * sizeof(BInt)
+
+def test_packed():
+ BLong = new_primitive_type("long")
+ BChar = new_primitive_type("char")
+ BShort = new_primitive_type("short")
+ for extra_args in [(SF_PACKED,), (0, 1)]:
+ BStruct = new_struct_type("struct foo")
+ complete_struct_or_union(BStruct, [('a1', BLong, -1),
+ ('a2', BChar, -1),
+ ('a3', BShort, -1)],
+ None, -1, -1, *extra_args)
+ d = BStruct.fields
+ assert len(d) == 3
+ assert d[0][0] == 'a1'
+ assert d[0][1].type is BLong
+ assert d[0][1].offset == 0
+ assert d[0][1].bitshift == -1
+ assert d[0][1].bitsize == -1
+ assert d[1][0] == 'a2'
+ assert d[1][1].type is BChar
+ assert d[1][1].offset == sizeof(BLong)
+ assert d[1][1].bitshift == -1
+ assert d[1][1].bitsize == -1
+ assert d[2][0] == 'a3'
+ assert d[2][1].type is BShort
+ assert d[2][1].offset == sizeof(BLong) + sizeof(BChar)
+ assert d[2][1].bitshift == -1
+ assert d[2][1].bitsize == -1
+ assert sizeof(BStruct) == sizeof(BLong) + sizeof(BChar) + sizeof(BShort)
+ assert alignof(BStruct) == 1
+ #
+ BStruct2 = new_struct_type("struct foo")
+ complete_struct_or_union(BStruct2, [('b1', BChar, -1),
+ ('b2', BLong, -1)],
+ None, -1, -1, 0, 2)
+ d = BStruct2.fields
+ assert len(d) == 2
+ assert d[0][0] == 'b1'
+ assert d[0][1].type is BChar
+ assert d[0][1].offset == 0
+ assert d[0][1].bitshift == -1
+ assert d[0][1].bitsize == -1
+ assert d[1][0] == 'b2'
+ assert d[1][1].type is BLong
+ assert d[1][1].offset == 2
+ assert d[1][1].bitshift == -1
+ assert d[1][1].bitsize == -1
+ assert sizeof(BStruct2) == 2 + sizeof(BLong)
+ assert alignof(BStruct2) == 2
+
+def test_packed_with_bitfields():
+ if sys.platform == "win32":
+ py.test.skip("testing gcc behavior")
+ BLong = new_primitive_type("long")
+ BChar = new_primitive_type("char")
+ BStruct = new_struct_type("struct foo")
+ py.test.raises(NotImplementedError,
+ complete_struct_or_union,
+ BStruct, [('a1', BLong, 30),
+ ('a2', BChar, 5)],
+ None, -1, -1, SF_PACKED)
+
+def test_from_buffer():
+ import array
+ a = array.array('H', [10000, 20000, 30000])
+ BChar = new_primitive_type("char")
+ BCharP = new_pointer_type(BChar)
+ BCharA = new_array_type(BCharP, None)
+ c = from_buffer(BCharA, a)
+ assert typeof(c) is BCharA
+ assert len(c) == 6
+ assert repr(c) == "<cdata 'char[]' buffer len 6 from 'array.array' object>"
+ p = new_pointer_type(new_primitive_type("unsigned short"))
+ cast(p, c)[1] += 500
+ assert list(a) == [10000, 20500, 30000]
+
+def test_from_buffer_not_str_unicode():
+ BChar = new_primitive_type("char")
+ BCharP = new_pointer_type(BChar)
+ BCharA = new_array_type(BCharP, None)
+ p1 = from_buffer(BCharA, b"foo")
+ assert p1 == from_buffer(BCharA, b"foo")
+ import gc; gc.collect()
+ assert p1 == from_buffer(BCharA, b"foo")
+ py.test.raises(TypeError, from_buffer, BCharA, u+"foo")
+ try:
+ from __builtin__ import buffer
+ except ImportError:
+ pass
+ else:
+ # Python 2 only
+ contents = from_buffer(BCharA, buffer(b"foo"))
+ assert len(contents) == len(p1)
+ for i in range(len(contents)):
+ assert contents[i] == p1[i]
+ p4 = buffer(u+"foo")
+ contents = from_buffer(BCharA, buffer(u+"foo"))
+ assert len(contents) == len(p4)
+ for i in range(len(contents)):
+ assert contents[i] == p4[i]
+ try:
+ from __builtin__ import memoryview
+ except ImportError:
+ pass
+ else:
+ contents = from_buffer(BCharA, memoryview(b"foo"))
+ assert len(contents) == len(p1)
+ for i in range(len(contents)):
+ assert contents[i] == p1[i]
+
+
+def test_from_buffer_bytearray():
+ a = bytearray(b"xyz")
+ BChar = new_primitive_type("char")
+ BCharP = new_pointer_type(BChar)
+ BCharA = new_array_type(BCharP, None)
+ p = from_buffer(BCharA, a)
+ assert typeof(p) is BCharA
+ assert len(p) == 3
+ assert repr(p) == "<cdata 'char[]' buffer len 3 from 'bytearray' object>"
+ assert p[2] == b"z"
+ p[2] = b"."
+ assert a[2] == ord(".")
+ a[2] = ord("?")
+ assert p[2] == b"?"
+
+def test_from_buffer_more_cases():
+ try:
+ from _cffi_backend import _testbuff
+ except ImportError:
+ py.test.skip("not for pypy")
+ BChar = new_primitive_type("char")
+ BCharP = new_pointer_type(BChar)
+ BCharA = new_array_type(BCharP, None)
+ #
+ def check1(bufobj, expected):
+ c = from_buffer(BCharA, bufobj)
+ assert typeof(c) is BCharA
+ if sys.version_info >= (3,):
+ expected = [bytes(c, "ascii") for c in expected]
+ assert list(c) == list(expected)
+ #
+ def check(methods, expected, expected_for_memoryview=None):
+ if sys.version_info >= (3,):
+ if methods <= 7:
+ return
+ if expected_for_memoryview is not None:
+ expected = expected_for_memoryview
+ class X(object):
+ pass
+ _testbuff(X, methods)
+ bufobj = X()
+ check1(bufobj, expected)
+ try:
+ from __builtin__ import buffer
+ bufobjb = buffer(bufobj)
+ except (TypeError, ImportError):
+ pass
+ else:
+ check1(bufobjb, expected)
+ try:
+ bufobjm = memoryview(bufobj)
+ except (TypeError, NameError):
+ pass
+ else:
+ check1(bufobjm, expected_for_memoryview or expected)
+ #
+ check(1, "RDB")
+ check(2, "WRB")
+ check(4, "CHB")
+ check(8, "GTB")
+ check(16, "ROB")
+ #
+ check(1 | 2, "RDB")
+ check(1 | 4, "RDB")
+ check(2 | 4, "CHB")
+ check(1 | 8, "RDB", "GTB")
+ check(1 | 16, "RDB", "ROB")
+ check(2 | 8, "WRB", "GTB")
+ check(2 | 16, "WRB", "ROB")
+ check(4 | 8, "CHB", "GTB")
+ check(4 | 16, "CHB", "ROB")
+
+def test_from_buffer_require_writable():
+ BChar = new_primitive_type("char")
+ BCharP = new_pointer_type(BChar)
+ BCharA = new_array_type(BCharP, None)
+ p1 = from_buffer(BCharA, b"foo", False)
+ assert p1 == from_buffer(BCharA, b"foo", False)
+ py.test.raises((TypeError, BufferError), from_buffer, BCharA, b"foo", True)
+ ba = bytearray(b"foo")
+ p1 = from_buffer(BCharA, ba, True)
+ p1[0] = b"g"
+ assert ba == b"goo"
+
+def test_from_buffer_types():
+ BInt = new_primitive_type("int")
+ BIntP = new_pointer_type(BInt)
+ BIntA = new_array_type(BIntP, None)
+ lst = [-12345678, 87654321, 489148]
+ bytestring = bytearray(buffer(newp(BIntA, lst))[:] + b'XYZ')
+ lst2 = lst + [42, -999999999]
+ bytestring2 = bytearray(buffer(newp(BIntA, lst2))[:] + b'XYZ')
+ #
+ p1 = from_buffer(BIntA, bytestring) # int[]
+ assert typeof(p1) is BIntA
+ assert len(p1) == 3
+ assert p1[0] == lst[0]
+ assert p1[1] == lst[1]
+ assert p1[2] == lst[2]
+ with pytest.raises(IndexError):
+ p1[3]
+ with pytest.raises(IndexError):
+ p1[-1]
+ #
+ py.test.raises(TypeError, from_buffer, BInt, bytestring)
+ #
+ p2 = from_buffer(BIntP, bytestring) # int *
+ assert p2 == p1 or 'PY_DOT_PY' in globals()
+ # note: on py.py ^^^, bytearray buffers are not emulated well enough
+ assert typeof(p2) is BIntP
+ assert p2[0] == lst[0]
+ assert p2[1] == lst[1]
+ assert p2[2] == lst[2]
+ # hopefully does not crash, but doesn't raise an exception:
+ p2[3]
+ p2[-1]
+ # not enough data even for one, but this is not enforced:
+ from_buffer(BIntP, b"")
+ #
+ BIntA2 = new_array_type(BIntP, 2)
+ p2 = from_buffer(BIntA2, bytestring) # int[2]
+ assert typeof(p2) is BIntA2
+ assert len(p2) == 2
+ assert p2[0] == lst[0]
+ assert p2[1] == lst[1]
+ with pytest.raises(IndexError):
+ p2[2]
+ with pytest.raises(IndexError):
+ p2[-1]
+ assert p2 == p1 or 'PY_DOT_PY' in globals()
+ #
+ BIntA4 = new_array_type(BIntP, 4) # int[4]: too big
+ py.test.raises(ValueError, from_buffer, BIntA4, bytestring)
+ #
+ BStruct = new_struct_type("foo")
+ complete_struct_or_union(BStruct, [('a1', BInt, -1),
+ ('a2', BInt, -1)])
+ BStructP = new_pointer_type(BStruct)
+ BStructA = new_array_type(BStructP, None)
+ p1 = from_buffer(BStructA, bytestring2) # struct[]
+ assert len(p1) == 2
+ assert typeof(p1) is BStructA
+ assert p1[0].a1 == lst2[0]
+ assert p1[0].a2 == lst2[1]
+ assert p1[1].a1 == lst2[2]
+ assert p1[1].a2 == lst2[3]
+ with pytest.raises(IndexError):
+ p1[2]
+ with pytest.raises(IndexError):
+ p1[-1]
+ assert repr(p1) == "<cdata 'foo[]' buffer len 2 from 'bytearray' object>"
+ #
+ p2 = from_buffer(BStructP, bytestring2) # 'struct *'
+ assert p2 == p1 or 'PY_DOT_PY' in globals()
+ assert typeof(p2) is BStructP
+ assert p2.a1 == lst2[0]
+ assert p2.a2 == lst2[1]
+ assert p2[0].a1 == lst2[0]
+ assert p2[0].a2 == lst2[1]
+ assert p2[1].a1 == lst2[2]
+ assert p2[1].a2 == lst2[3]
+ # does not crash:
+ p2[2]
+ p2[-1]
+ # not enough data even for one, but this is not enforced:
+ from_buffer(BStructP, b"")
+ from_buffer(BStructP, b"1234567")
+ #
+ release(p1)
+ assert repr(p1) == "<cdata 'foo[]' buffer RELEASED>"
+ #
+ BEmptyStruct = new_struct_type("empty")
+ complete_struct_or_union(BEmptyStruct, [], Ellipsis, 0)
+ assert sizeof(BEmptyStruct) == 0
+ BEmptyStructP = new_pointer_type(BEmptyStruct)
+ BEmptyStructA = new_array_type(BEmptyStructP, None)
+ py.test.raises(ZeroDivisionError, from_buffer, # empty[]
+ BEmptyStructA, bytestring)
+ #
+ BEmptyStructA5 = new_array_type(BEmptyStructP, 5)
+ p1 = from_buffer(BEmptyStructA5, bytestring) # struct empty[5]
+ assert typeof(p1) is BEmptyStructA5
+ assert len(p1) == 5
+ assert (cast(BIntP, p1) == from_buffer(BIntA, bytestring)
+ or 'PY_DOT_PY' in globals())
+ #
+ BVarStruct = new_struct_type("varfoo")
+ BVarStructP = new_pointer_type(BVarStruct)
+ complete_struct_or_union(BVarStruct, [('a1', BInt, -1),
+ ('va', BIntA, -1)])
+ with pytest.raises(TypeError):
+ from_buffer(BVarStruct, bytestring)
+ pv = from_buffer(BVarStructP, bytestring) # varfoo *
+ assert pv.a1 == lst[0]
+ assert pv.va[0] == lst[1]
+ assert pv.va[1] == lst[2]
+ assert sizeof(pv[0]) == 1 * size_of_int()
+ with pytest.raises(TypeError):
+ len(pv.va)
+ # hopefully does not crash, but doesn't raise an exception:
+ pv.va[2]
+ pv.va[-1]
+ # not enough data even for one, but this is not enforced:
+ from_buffer(BVarStructP, b"")
+ assert repr(pv) == "<cdata 'varfoo *' buffer from 'bytearray' object>"
+ assert repr(pv[0]).startswith("<cdata 'varfoo &' ")
+ #
+ release(pv)
+ assert repr(pv) == "<cdata 'varfoo *' buffer RELEASED>"
+ assert repr(pv[0]).startswith("<cdata 'varfoo &' ")
+ #
+ pv = from_buffer(BVarStructP, bytestring) # make a fresh one
+ with pytest.raises(ValueError):
+ release(pv[0])
+
+def test_memmove():
+ Short = new_primitive_type("short")
+ ShortA = new_array_type(new_pointer_type(Short), None)
+ Char = new_primitive_type("char")
+ CharA = new_array_type(new_pointer_type(Char), None)
+ p = newp(ShortA, [-1234, -2345, -3456, -4567, -5678])
+ memmove(p, p + 1, 4)
+ assert list(p) == [-2345, -3456, -3456, -4567, -5678]
+ p[2] = 999
+ memmove(p + 2, p, 6)
+ assert list(p) == [-2345, -3456, -2345, -3456, 999]
+ memmove(p + 4, newp(CharA, b"\x71\x72"), 2)
+ if sys.byteorder == 'little':
+ assert list(p) == [-2345, -3456, -2345, -3456, 0x7271]
+ else:
+ assert list(p) == [-2345, -3456, -2345, -3456, 0x7172]
+
+def test_memmove_buffer():
+ import array
+ Short = new_primitive_type("short")
+ ShortA = new_array_type(new_pointer_type(Short), None)
+ a = array.array('H', [10000, 20000, 30000])
+ p = newp(ShortA, 5)
+ memmove(p, a, 6)
+ assert list(p) == [10000, 20000, 30000, 0, 0]
+ memmove(p + 1, a, 6)
+ assert list(p) == [10000, 10000, 20000, 30000, 0]
+ b = array.array('h', [-1000, -2000, -3000])
+ memmove(b, a, 4)
+ assert b.tolist() == [10000, 20000, -3000]
+ assert a.tolist() == [10000, 20000, 30000]
+ p[0] = 999
+ p[1] = 998
+ p[2] = 997
+ p[3] = 996
+ p[4] = 995
+ memmove(b, p, 2)
+ assert b.tolist() == [999, 20000, -3000]
+ memmove(b, p + 2, 4)
+ assert b.tolist() == [997, 996, -3000]
+ p[2] = -p[2]
+ p[3] = -p[3]
+ memmove(b, p + 2, 6)
+ assert b.tolist() == [-997, -996, 995]
+
+def test_memmove_readonly_readwrite():
+ SignedChar = new_primitive_type("signed char")
+ SignedCharA = new_array_type(new_pointer_type(SignedChar), None)
+ p = newp(SignedCharA, 5)
+ memmove(p, b"abcde", 3)
+ assert list(p) == [ord("a"), ord("b"), ord("c"), 0, 0]
+ memmove(p, bytearray(b"ABCDE"), 2)
+ assert list(p) == [ord("A"), ord("B"), ord("c"), 0, 0]
+ py.test.raises((TypeError, BufferError), memmove, b"abcde", p, 3)
+ ba = bytearray(b"xxxxx")
+ memmove(dest=ba, src=p, n=3)
+ assert ba == bytearray(b"ABcxx")
+ memmove(ba, b"EFGH", 4)
+ assert ba == bytearray(b"EFGHx")
+
+def test_memmove_sign_check():
+ SignedChar = new_primitive_type("signed char")
+ SignedCharA = new_array_type(new_pointer_type(SignedChar), None)
+ p = newp(SignedCharA, 5)
+ py.test.raises(ValueError, memmove, p, p + 1, -1) # not segfault
+
+def test_memmove_bad_cdata():
+ BInt = new_primitive_type("int")
+ p = cast(BInt, 42)
+ py.test.raises(TypeError, memmove, p, bytearray(b'a'), 1)
+ py.test.raises(TypeError, memmove, bytearray(b'a'), p, 1)
+
+def test_dereference_null_ptr():
+ BInt = new_primitive_type("int")
+ BIntPtr = new_pointer_type(BInt)
+ p = cast(BIntPtr, 0)
+ with pytest.raises(RuntimeError):
+ p[0]
+ with pytest.raises(RuntimeError):
+ p[0] = 42
+ with pytest.raises(RuntimeError):
+ p[42]
+ with pytest.raises(RuntimeError):
+ p[42] = -1
+
+def test_mixup():
+ BStruct1 = new_struct_type("foo")
+ BStruct2 = new_struct_type("foo") # <= same name as BStruct1
+ BStruct3 = new_struct_type("bar")
+ BStruct1Ptr = new_pointer_type(BStruct1)
+ BStruct2Ptr = new_pointer_type(BStruct2)
+ BStruct3Ptr = new_pointer_type(BStruct3)
+ BStruct1PtrPtr = new_pointer_type(BStruct1Ptr)
+ BStruct2PtrPtr = new_pointer_type(BStruct2Ptr)
+ BStruct3PtrPtr = new_pointer_type(BStruct3Ptr)
+ pp1 = newp(BStruct1PtrPtr)
+ pp2 = newp(BStruct2PtrPtr)
+ pp3 = newp(BStruct3PtrPtr)
+ pp1[0] = pp1[0]
+ with pytest.raises(TypeError) as e:
+ pp3[0] = pp1[0]
+ assert str(e.value).startswith("initializer for ctype 'bar *' must be a ")
+ assert str(e.value).endswith(", not cdata 'foo *'")
+ with pytest.raises(TypeError) as e:
+ pp2[0] = pp1[0]
+ assert str(e.value) == ("initializer for ctype 'foo *' appears indeed to "
+ "be 'foo *', but the types are different (check "
+ "that you are not e.g. mixing up different ffi "
+ "instances)")
+
+def test_stdcall_function_type():
+ assert FFI_CDECL == FFI_DEFAULT_ABI
+ try:
+ stdcall = FFI_STDCALL
+ except NameError:
+ stdcall = FFI_DEFAULT_ABI
+ BInt = new_primitive_type("int")
+ BFunc = new_function_type((BInt, BInt), BInt, False, stdcall)
+ if stdcall != FFI_DEFAULT_ABI:
+ assert repr(BFunc) == "<ctype 'int(__stdcall *)(int, int)'>"
+ else:
+ assert repr(BFunc) == "<ctype 'int(*)(int, int)'>"
+
+def test_get_common_types():
+ d = {}
+ _get_common_types(d)
+ assert d['bool'] == '_Bool'
+
+def test_unpack():
+ BChar = new_primitive_type("char")
+ BArray = new_array_type(new_pointer_type(BChar), 10) # char[10]
+ p = newp(BArray, b"abc\x00def")
+ p0 = p
+ assert unpack(p, 10) == b"abc\x00def\x00\x00\x00"
+ assert unpack(p+1, 5) == b"bc\x00de"
+
+ for typename in ["wchar_t", "char16_t", "char32_t"]:
+ BWChar = new_primitive_type(typename)
+ BArray = new_array_type(new_pointer_type(BWChar), 10) # wchar_t[10]
+ p = newp(BArray, u"abc\x00def")
+ assert unpack(p, 10) == u"abc\x00def\x00\x00\x00"
+
+ for typename, samples in [
+ ("uint8_t", [0, 2**8-1]),
+ ("uint16_t", [0, 2**16-1]),
+ ("uint32_t", [0, 2**32-1]),
+ ("uint64_t", [0, 2**64-1]),
+ ("int8_t", [-2**7, 2**7-1]),
+ ("int16_t", [-2**15, 2**15-1]),
+ ("int32_t", [-2**31, 2**31-1]),
+ ("int64_t", [-2**63, 2**63-1]),
+ ("_Bool", [False, True]),
+ ("float", [0.0, 10.5]),
+ ("double", [12.34, 56.78]),
+ ]:
+ BItem = new_primitive_type(typename)
+ BArray = new_array_type(new_pointer_type(BItem), 10)
+ p = newp(BArray, samples)
+ result = unpack(p, len(samples))
+ assert result == samples
+ for i in range(len(samples)):
+ assert result[i] == p[i] and type(result[i]) is type(p[i])
+ assert (type(result[i]) is bool) == (type(samples[i]) is bool)
+ #
+ BInt = new_primitive_type("int")
+ py.test.raises(TypeError, unpack, p)
+ py.test.raises(TypeError, unpack, b"foobar", 6)
+ py.test.raises(TypeError, unpack, cast(BInt, 42), 1)
+ #
+ BPtr = new_pointer_type(BInt)
+ random_ptr = cast(BPtr, -424344)
+ other_ptr = cast(BPtr, 54321)
+ BArray = new_array_type(new_pointer_type(BPtr), None)
+ lst = unpack(newp(BArray, [random_ptr, other_ptr]), 2)
+ assert lst == [random_ptr, other_ptr]
+ #
+ BFunc = new_function_type((BInt, BInt), BInt, False)
+ BFuncPtr = new_pointer_type(BFunc)
+ lst = unpack(newp(new_array_type(BFuncPtr, None), 2), 2)
+ assert len(lst) == 2
+ assert not lst[0] and not lst[1]
+ assert typeof(lst[0]) is BFunc
+ #
+ BStruct = new_struct_type("foo")
+ BStructPtr = new_pointer_type(BStruct)
+ e = py.test.raises(ValueError, unpack, cast(BStructPtr, 42), 5)
+ assert str(e.value) == "'foo *' points to items of unknown size"
+ complete_struct_or_union(BStruct, [('a1', BInt, -1),
+ ('a2', BInt, -1)])
+ array_of_structs = newp(new_array_type(BStructPtr, None), [[4,5], [6,7]])
+ lst = unpack(array_of_structs, 2)
+ assert typeof(lst[0]) is BStruct
+ assert lst[0].a1 == 4 and lst[1].a2 == 7
+ #
+ py.test.raises(RuntimeError, unpack, cast(new_pointer_type(BChar), 0), 0)
+ py.test.raises(RuntimeError, unpack, cast(new_pointer_type(BChar), 0), 10)
+ #
+ py.test.raises(ValueError, unpack, p0, -1)
+ py.test.raises(ValueError, unpack, p, -1)
+
+def test_cdata_dir():
+ BInt = new_primitive_type("int")
+ p = cast(BInt, 42)
+ check_dir(p, [])
+ p = newp(new_array_type(new_pointer_type(BInt), None), 5)
+ check_dir(p, [])
+ BStruct = new_struct_type("foo")
+ p = cast(new_pointer_type(BStruct), 0)
+ check_dir(p, []) # opaque
+ complete_struct_or_union(BStruct, [('a2', BInt, -1),
+ ('a1', BInt, -1)])
+ check_dir(p, ['a1', 'a2']) # always sorted
+ p = newp(new_pointer_type(BStruct), None)
+ check_dir(p, ['a1', 'a2'])
+ check_dir(p[0], ['a1', 'a2'])
+ pp = newp(new_pointer_type(new_pointer_type(BStruct)), p)
+ check_dir(pp, [])
+ check_dir(pp[0], ['a1', 'a2'])
+ check_dir(pp[0][0], ['a1', 'a2'])
+
+def test_char_pointer_conversion():
+ import warnings
+ assert __version__.startswith("1."), (
+ "the warning will be an error if we ever release cffi 2.x")
+ BCharP = new_pointer_type(new_primitive_type("char"))
+ BIntP = new_pointer_type(new_primitive_type("int"))
+ BVoidP = new_pointer_type(new_void_type())
+ BUCharP = new_pointer_type(new_primitive_type("unsigned char"))
+ z1 = cast(BCharP, 0)
+ z2 = cast(BIntP, 0)
+ z3 = cast(BVoidP, 0)
+ z4 = cast(BUCharP, 0)
+ with warnings.catch_warnings(record=True) as w:
+ warnings.simplefilter("always")
+ newp(new_pointer_type(BIntP), z1) # warn
+ assert len(w) == 1
+ newp(new_pointer_type(BVoidP), z1) # fine
+ assert len(w) == 1
+ newp(new_pointer_type(BCharP), z2) # warn
+ assert len(w) == 2
+ newp(new_pointer_type(BVoidP), z2) # fine
+ assert len(w) == 2
+ newp(new_pointer_type(BCharP), z3) # fine
+ assert len(w) == 2
+ newp(new_pointer_type(BIntP), z3) # fine
+ assert len(w) == 2
+ newp(new_pointer_type(BCharP), z4) # fine (ignore signedness here)
+ assert len(w) == 2
+ newp(new_pointer_type(BUCharP), z1) # fine (ignore signedness here)
+ assert len(w) == 2
+ newp(new_pointer_type(BUCharP), z3) # fine
+ assert len(w) == 2
+ # check that the warnings are associated with lines in this file
+ assert w[1].lineno == w[0].lineno + 4
+
+def test_primitive_comparison():
+ def assert_eq(a, b):
+ assert (a == b) is True
+ assert (b == a) is True
+ assert (a != b) is False
+ assert (b != a) is False
+ assert (a < b) is False
+ assert (a <= b) is True
+ assert (a > b) is False
+ assert (a >= b) is True
+ assert (b < a) is False
+ assert (b <= a) is True
+ assert (b > a) is False
+ assert (b >= a) is True
+ assert hash(a) == hash(b)
+ def assert_lt(a, b, check_hash=True):
+ assert (a == b) is False
+ assert (b == a) is False
+ assert (a != b) is True
+ assert (b != a) is True
+ assert (a < b) is True
+ assert (a <= b) is True
+ assert (a > b) is False
+ assert (a >= b) is False
+ assert (b < a) is False
+ assert (b <= a) is False
+ assert (b > a) is True
+ assert (b >= a) is True
+ if check_hash:
+ assert hash(a) != hash(b) # (or at least, it is unlikely)
+ def assert_gt(a, b, check_hash=True):
+ assert_lt(b, a, check_hash)
+ def assert_ne(a, b):
+ assert (a == b) is False
+ assert (b == a) is False
+ assert (a != b) is True
+ assert (b != a) is True
+ if strict_compare:
+ with pytest.raises(TypeError): a < b
+ with pytest.raises(TypeError): a <= b
+ with pytest.raises(TypeError): a > b
+ with pytest.raises(TypeError): a >= b
+ with pytest.raises(TypeError): b < a
+ with pytest.raises(TypeError): b <= a
+ with pytest.raises(TypeError): b > a
+ with pytest.raises(TypeError): b >= a
+ elif a < b:
+ assert_lt(a, b)
+ else:
+ assert_lt(b, a)
+ assert_eq(5, 5)
+ assert_lt(3, 5)
+ assert_ne('5', 5)
+ #
+ t1 = new_primitive_type("char")
+ t2 = new_primitive_type("int")
+ t3 = new_primitive_type("unsigned char")
+ t4 = new_primitive_type("unsigned int")
+ t5 = new_primitive_type("float")
+ t6 = new_primitive_type("double")
+ assert_eq(cast(t1, 65), b'A')
+ assert_lt(cast(t1, 64), b'\x99')
+ assert_gt(cast(t1, 200), b'A')
+ assert_ne(cast(t1, 65), 65)
+ assert_eq(cast(t2, -25), -25)
+ assert_lt(cast(t2, -25), -24)
+ assert_gt(cast(t2, -25), -26)
+ assert_eq(cast(t3, 65), 65)
+ assert_ne(cast(t3, 65), b'A')
+ assert_ne(cast(t3, 65), cast(t1, 65))
+ assert_gt(cast(t4, -1), -1, check_hash=False)
+ assert_gt(cast(t4, -1), cast(t2, -1), check_hash=False)
+ assert_gt(cast(t4, -1), 99999)
+ assert_eq(cast(t4, -1), 256 ** size_of_int() - 1)
+ assert_eq(cast(t5, 3.0), 3)
+ assert_eq(cast(t5, 3.5), 3.5)
+ assert_lt(cast(t5, 3.3), 3.3) # imperfect rounding
+ assert_eq(cast(t6, 3.3), 3.3)
+ assert_eq(cast(t5, 3.5), cast(t6, 3.5))
+ assert_lt(cast(t5, 3.1), cast(t6, 3.1)) # imperfect rounding
+ assert_eq(cast(t5, 7.0), cast(t3, 7))
+ assert_lt(cast(t5, 3.1), 3.101)
+ assert_gt(cast(t5, 3.1), 3)
+
+def test_explicit_release_new():
+ # release() on a ffi.new() object has no effect on CPython, but
+ # really releases memory on PyPy. We can't test that effect
+ # though, because a released cdata is not marked.
+ BIntP = new_pointer_type(new_primitive_type("int"))
+ p = newp(BIntP)
+ p[0] = 42
+ with pytest.raises(IndexError):
+ p[1]
+ release(p)
+ # here, reading p[0] might give garbage or segfault...
+ release(p) # no effect
+ #
+ BStruct = new_struct_type("struct foo")
+ BStructP = new_pointer_type(BStruct)
+ complete_struct_or_union(BStruct, [('p', BIntP, -1)])
+ pstruct = newp(BStructP)
+ assert pstruct.p == cast(BIntP, 0)
+ release(pstruct)
+ # here, reading pstruct.p might give garbage or segfault...
+ release(pstruct) # no effect
+
+def test_explicit_release_new_contextmgr():
+ BIntP = new_pointer_type(new_primitive_type("int"))
+ with newp(BIntP) as p:
+ p[0] = 42
+ assert p[0] == 42
+ # here, reading p[0] might give garbage or segfault...
+ release(p) # no effect
+
+def test_explicit_release_badtype():
+ BIntP = new_pointer_type(new_primitive_type("int"))
+ p = cast(BIntP, 12345)
+ py.test.raises(ValueError, release, p)
+ py.test.raises(ValueError, release, p)
+ BStruct = new_struct_type("struct foo")
+ BStructP = new_pointer_type(BStruct)
+ complete_struct_or_union(BStruct, [('p', BIntP, -1)])
+ pstruct = newp(BStructP)
+ py.test.raises(ValueError, release, pstruct[0])
+
+def test_explicit_release_badtype_contextmgr():
+ BIntP = new_pointer_type(new_primitive_type("int"))
+ p = cast(BIntP, 12345)
+ with pytest.raises(ValueError):
+ with p:
+ pass
+ with pytest.raises(ValueError):
+ with p:
+ pass
+
+def test_explicit_release_gc():
+ BIntP = new_pointer_type(new_primitive_type("int"))
+ seen = []
+ intp1 = newp(BIntP, 12345)
+ p1 = cast(BIntP, intp1)
+ p = gcp(p1, seen.append)
+ assert seen == []
+ release(p)
+ assert seen == [p1]
+ assert p1[0] == 12345
+ assert p[0] == 12345 # true so far, but might change to raise RuntimeError
+ release(p) # no effect
+
+def test_explicit_release_gc_contextmgr():
+ BIntP = new_pointer_type(new_primitive_type("int"))
+ seen = []
+ intp1 = newp(BIntP, 12345)
+ p1 = cast(BIntP, intp1)
+ p = gcp(p1, seen.append)
+ with p:
+ assert p[0] == 12345
+ assert seen == []
+ assert seen == [p1]
+ assert p1[0] == 12345
+ assert p[0] == 12345 # true so far, but might change to raise RuntimeError
+ release(p) # no effect
+
+def test_explicit_release_from_buffer():
+ a = bytearray(b"xyz")
+ BChar = new_primitive_type("char")
+ BCharP = new_pointer_type(BChar)
+ BCharA = new_array_type(BCharP, None)
+ p = from_buffer(BCharA, a)
+ assert p[2] == b"z"
+ assert repr(p) == "<cdata 'char[]' buffer len 3 from 'bytearray' object>"
+ release(p)
+ assert p[2] == b"z" # true so far, but might change to raise RuntimeError
+ assert repr(p) == "<cdata 'char[]' buffer RELEASED>"
+ release(p) # no effect
+
+def test_explicit_release_from_buffer_contextmgr():
+ a = bytearray(b"xyz")
+ BChar = new_primitive_type("char")
+ BCharP = new_pointer_type(BChar)
+ BCharA = new_array_type(BCharP, None)
+ p = from_buffer(BCharA, a)
+ with p:
+ assert p[2] == b"z"
+ assert p[2] == b"z" # true so far, but might change to raise RuntimeError
+ assert repr(p) == "<cdata 'char[]' buffer RELEASED>"
+ release(p) # no effect
+
+def test_explicit_release_bytearray_on_cpython():
+ if '__pypy__' in sys.builtin_module_names:
+ py.test.skip("pypy's bytearray are never locked")
+ a = bytearray(b"xyz")
+ BChar = new_primitive_type("char")
+ BCharP = new_pointer_type(BChar)
+ BCharA = new_array_type(BCharP, None)
+ a += b't' * 10
+ p = from_buffer(BCharA, a)
+ with pytest.raises(BufferError):
+ a += b'u' * 100
+ release(p)
+ a += b'v' * 100
+ release(p) # no effect
+ a += b'w' * 1000
+ assert a == bytearray(b"xyz" + b't' * 10 + b'v' * 100 + b'w' * 1000)
+
+def test_int_doesnt_give_bool():
+ BBool = new_primitive_type("_Bool")
+ x = int(cast(BBool, 42))
+ assert type(x) is int and x == 1
+ x = long(cast(BBool, 42))
+ assert type(x) is long and x == 1
+ with pytest.raises(TypeError):
+ float(cast(BBool, 42))
+ with pytest.raises(TypeError):
+ complex(cast(BBool, 42))
+
+def test_cannot_call_null_function_pointer():
+ BInt = new_primitive_type("int")
+ BFunc = new_function_type((BInt, BInt), BInt, False)
+ f = cast(BFunc, 0)
+ with pytest.raises(RuntimeError):
+ f(40, 2)
+
+def test_huge_structure():
+ BChar = new_primitive_type("char")
+ BArray = new_array_type(new_pointer_type(BChar), sys.maxsize)
+ assert sizeof(BArray) == sys.maxsize
+ BStruct = new_struct_type("struct foo")
+ complete_struct_or_union(BStruct, [('a1', BArray, -1)])
+ assert sizeof(BStruct) == sys.maxsize
+
+def test_get_types():
+ import _cffi_backend
+ CData, CType = _get_types()
+ assert CData is _cffi_backend._CDataBase
+ assert CType is _cffi_backend.CType
+
+def test_type_available_with_correct_names():
+ import _cffi_backend
+ check_names = [
+ 'CType',
+ 'CField',
+ 'CLibrary',
+ '_CDataBase',
+ 'FFI',
+ 'Lib',
+ 'buffer',
+ ]
+ if '__pypy__' in sys.builtin_module_names:
+ check_names += [
+ '__CData_iterator',
+ '__FFIGlobSupport',
+ '__FFIAllocator',
+ '__FFIFunctionWrapper',
+ ]
+ else:
+ check_names += [
+ '__CDataOwn',
+ '__CDataOwnGC',
+ '__CDataFromBuf',
+ '__CDataGCP',
+ '__CData_iterator',
+ '__FFIGlobSupport',
+ ]
+ for name in check_names:
+ tp = getattr(_cffi_backend, name)
+ assert isinstance(tp, type)
+ assert (tp.__module__, tp.__name__) == ('_cffi_backend', name)
diff --git a/pypy/tool/import_cffi.py b/pypy/tool/import_cffi.py
index 3e4fe93a00..05b0f4e3bd 100755
--- a/pypy/tool/import_cffi.py
+++ b/pypy/tool/import_cffi.py
@@ -40,6 +40,8 @@ def main(cffi_dir):
path = test_dest.join(p.relto(cffi_dir.join('testing')))
path.join('..').ensure(dir=1)
path.write_binary(fixeol(''.join(mangle(p.readlines(), p.ext))))
+ path = test_dest.join('test_c.py')
+ path.write_binary(fixeol(cffi_dir.join('c', 'test_c.py').read()))
if __name__ == '__main__':
if len(sys.argv) != 2: