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