blob: da5f751f3d6637bf4b9972db096376ed54e01479 [file] [log] [blame]
import py
def _setup_path():
import os, sys
if '__pypy__' in sys.builtin_module_names:
py.test.skip("_cffi_backend.c: not tested on top of pypy, "
"use pypy/module/_cffi_backend/test/ instead.")
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))
_setup_path()
from _cffi_backend import *
from _cffi_backend import _testfunc, _get_types, _get_common_types, __version__
# ____________________________________________________________
import sys
assert __version__ == "1.12.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,)
py.test.skip("dlopen(None) cannot work on Windows with 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.CData'>" % 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
py.test.raises(IndexError, "p[1]")
py.test.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)
py.test.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
py.test.raises(IndexError, "a[LENGTH]")
py.test.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
e = py.test.raises(IndexError, "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
py.test.raises(IndexError, "a[42]")
py.test.raises(IndexError, "a[-1]")
py.test.raises(IndexError, "a[42] = 123")
py.test.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)
py.test.raises(TypeError, "p - q")
py.test.raises(TypeError, "q - p")
py.test.raises(TypeError, "a - q")
e = py.test.raises(TypeError, "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:
py.test.raises(ValueError, "b - a")
py.test.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)
e = py.test.raises(AttributeError, "p.a1") # opaque
assert str(e.value) == ("cdata 'struct foo *' points to an opaque type: "
"cannot read fields")
e = py.test.raises(AttributeError, "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
py.test.raises(OverflowError, "s.a1 = sys.maxsize+1")
assert s.a1 == 0
e = py.test.raises(AttributeError, "p.foobar")
assert str(e.value) == "cdata 'struct foo *' has no field 'foobar'"
e = py.test.raises(AttributeError, "p.foobar = 42")
assert str(e.value) == "cdata 'struct foo *' has no field 'foobar'"
e = py.test.raises(AttributeError, "s.foobar")
assert str(e.value) == "cdata 'struct foo' has no field 'foobar'"
e = py.test.raises(AttributeError, "s.foobar = 42")
assert str(e.value) == "cdata 'struct foo' has no field 'foobar'"
j = cast(BInt, 42)
e = py.test.raises(AttributeError, "j.foobar")
assert str(e.value) == "cdata 'int' has no attribute 'foobar'"
e = py.test.raises(AttributeError, "j.foobar = 42")
assert str(e.value) == "cdata 'int' has no attribute 'foobar'"
j = cast(new_pointer_type(BInt), 42)
e = py.test.raises(AttributeError, "j.foobar")
assert str(e.value) == "cdata 'int *' has no attribute 'foobar'"
e = py.test.raises(AttributeError, "j.foobar = 42")
assert str(e.value) == "cdata 'int *' has no attribute 'foobar'"
pp = newp(new_pointer_type(BStructPtr), p)
e = py.test.raises(AttributeError, "pp.a1")
assert str(e.value) == "cdata 'struct foo * *' has no attribute 'a1'"
e = py.test.raises(AttributeError, "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
py.test.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
py.test.raises(OverflowError, "p.a1 = 2")
assert p.a1 == 0
#
p.a1 = -1
p.a2 = 3
p.a3 = -4
py.test.raises(OverflowError, "p.a3 = 4")
e = py.test.raises(OverflowError, "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
e = py.test.raises(OverflowError, "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"
e = py.test.raises(IndexError, '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)
py.test.raises(TypeError, "x + 1")
py.test.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'
py.test.raises(TypeError, "s.a1 = b'a'")
py.test.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:
py.test.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
py.test.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)
py.test.raises(TypeError, "p[0]")
p = cast(BVoidP, 0)
py.test.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:
py.test.raises(TypeError, "p < q")
py.test.raises(TypeError, "p <= q")
py.test.raises(TypeError, "q < p")
py.test.raises(TypeError, "q <= p")
py.test.raises(TypeError, "p > q")
py.test.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:
py.test.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:
py.test.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"))
py.test.raises(ValueError, 'buf[:] = b"shorter"')
py.test.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)
py.test.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))
py.test.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
py.test.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)
py.test.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
py.test.raises(IndexError, "d[3]")
py.test.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
py.test.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)
e = py.test.raises(IndexError, "c[:5]")
assert str(e.value) == "slice start must be specified"
e = py.test.raises(IndexError, "c[4:]")
assert str(e.value) == "slice stop must be specified"
e = py.test.raises(IndexError, "c[1:2:3]")
assert str(e.value) == "slice with step not supported"
e = py.test.raises(IndexError, "c[1:2:1]")
assert str(e.value) == "slice with step not supported"
e = py.test.raises(IndexError, "c[4:2]")
assert str(e.value) == "slice start > stop"
e = py.test.raises(IndexError, "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]
py.test.raises(ValueError, "cp[-1:1] = [1000]")
assert list(c) == [0, 100, 1000, 600, 0]
py.test.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
py.test.raises(IndexError, "p.y[4]")
py.test.raises(TypeError, "p.y = cast(BIntP, 0)")
py.test.raises(TypeError, "p.y = 15")
py.test.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
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"]
py.test.raises(TypeError, "p[1:5] = u+'XYZT'")
py.test.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"]
py.test.raises(TypeError, "p[1:5] = b'XYZT'")
py.test.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)
py.test.raises(TypeError, "p - q")
py.test.raises(TypeError, "q - p")
py.test.raises(TypeError, "p + cast(new_primitive_type('int'), 42)")
py.test.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 = buffer(newp(BIntA, lst))[:] + 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]
py.test.raises(IndexError, "p1[3]")
py.test.raises(IndexError, "p1[-1]")
#
py.test.raises(TypeError, from_buffer, BInt, bytestring)
py.test.raises(TypeError, from_buffer, BIntP, bytestring)
#
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]
py.test.raises(IndexError, "p2[2]")
py.test.raises(IndexError, "p2[-1]")
assert p2 == p1
#
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, bytestring) # struct[]
assert len(p1) == 1
assert typeof(p1) is BStructA
assert p1[0].a1 == lst[0]
assert p1[0].a2 == lst[1]
py.test.raises(IndexError, "p1[1]")
#
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)
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)
py.test.raises(RuntimeError, "p[0]")
py.test.raises(RuntimeError, "p[0] = 42")
py.test.raises(RuntimeError, "p[42]")
py.test.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]
e = py.test.raises(TypeError, "pp3[0] = pp1[0]")
assert str(e.value).startswith("initializer for ctype 'bar *' must be a ")
assert str(e.value).endswith(", not cdata 'foo *'")
e = py.test.raises(TypeError, "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:
py.test.raises(TypeError, "a < b")
py.test.raises(TypeError, "a <= b")
py.test.raises(TypeError, "a > b")
py.test.raises(TypeError, "a >= b")
py.test.raises(TypeError, "b < a")
py.test.raises(TypeError, "b <= a")
py.test.raises(TypeError, "b > a")
py.test.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
py.test.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)
py.test.raises(ValueError, "with p: pass")
py.test.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"
release(p)
assert p[2] == b"z" # true so far, but might change to raise RuntimeError
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
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)
py.test.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)