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