diff options
Diffstat (limited to 'testing/cffi1')
-rw-r--r-- | testing/cffi1/__init__.py | 0 | ||||
-rw-r--r-- | testing/cffi1/test_cffi_binary.py | 22 | ||||
-rw-r--r-- | testing/cffi1/test_commontypes.py | 34 | ||||
-rw-r--r-- | testing/cffi1/test_dlopen.py | 225 | ||||
-rw-r--r-- | testing/cffi1/test_dlopen_unicode_literals.py | 9 | ||||
-rw-r--r-- | testing/cffi1/test_ffi_obj.py | 536 | ||||
-rw-r--r-- | testing/cffi1/test_function_args.py | 208 | ||||
-rw-r--r-- | testing/cffi1/test_new_ffi_1.py | 1831 | ||||
-rw-r--r-- | testing/cffi1/test_parse_c_type.py | 372 | ||||
-rw-r--r-- | testing/cffi1/test_pkgconfig.py | 94 | ||||
-rw-r--r-- | testing/cffi1/test_re_python.py | 288 | ||||
-rw-r--r-- | testing/cffi1/test_realize_c_type.py | 73 | ||||
-rw-r--r-- | testing/cffi1/test_recompiler.py | 2495 | ||||
-rw-r--r-- | testing/cffi1/test_unicode_literals.py | 43 | ||||
-rw-r--r-- | testing/cffi1/test_verify1.py | 2359 | ||||
-rw-r--r-- | testing/cffi1/test_zdist.py | 426 |
16 files changed, 0 insertions, 9015 deletions
diff --git a/testing/cffi1/__init__.py b/testing/cffi1/__init__.py deleted file mode 100644 index e69de29..0000000 --- a/testing/cffi1/__init__.py +++ /dev/null diff --git a/testing/cffi1/test_cffi_binary.py b/testing/cffi1/test_cffi_binary.py deleted file mode 100644 index 7cfbace..0000000 --- a/testing/cffi1/test_cffi_binary.py +++ /dev/null @@ -1,22 +0,0 @@ -import py, sys, os -import _cffi_backend - -def test_no_unknown_exported_symbols(): - if not hasattr(_cffi_backend, '__file__'): - py.test.skip("_cffi_backend module is built-in") - if not sys.platform.startswith('linux'): - py.test.skip("linux-only") - g = os.popen("objdump -T '%s'" % _cffi_backend.__file__, 'r') - for line in g: - if not line.startswith('0'): - continue - if line[line.find(' ') + 1] == 'l': - continue - if '*UND*' in line: - continue - name = line.split()[-1] - if name.startswith('_') or name.startswith('.'): - continue - if name not in ('init_cffi_backend', 'PyInit__cffi_backend'): - raise Exception("Unexpected exported name %r" % (name,)) - g.close() diff --git a/testing/cffi1/test_commontypes.py b/testing/cffi1/test_commontypes.py deleted file mode 100644 index ea7ffde..0000000 --- a/testing/cffi1/test_commontypes.py +++ /dev/null @@ -1,34 +0,0 @@ -import py, os, cffi, re -import _cffi_backend - - -def getlines(): - try: - f = open(os.path.join(os.path.dirname(cffi.__file__), - '..', 'c', 'commontypes.c')) - except IOError: - py.test.skip("cannot find ../c/commontypes.c") - lines = [line for line in f.readlines() if line.strip().startswith('EQ(')] - f.close() - return lines - -def test_alphabetical_order(): - lines = getlines() - assert lines == sorted(lines) - -def test_dependencies(): - r = re.compile(r'EQ[(]"([^"]+)",(?:\s*"([A-Z0-9_]+)\s*[*]*"[)])?') - lines = getlines() - d = {} - for line in lines: - match = r.search(line) - if match is not None: - d[match.group(1)] = match.group(2) - for value in d.values(): - if value: - assert value in d - -def test_get_common_types(): - d = {} - _cffi_backend._get_common_types(d) - assert d["bool"] == "_Bool" diff --git a/testing/cffi1/test_dlopen.py b/testing/cffi1/test_dlopen.py deleted file mode 100644 index 26a2717..0000000 --- a/testing/cffi1/test_dlopen.py +++ /dev/null @@ -1,225 +0,0 @@ -import py -from cffi import FFI, VerificationError, CDefError -from cffi.recompiler import make_py_source -from testing.udir import udir - - -def test_simple(): - ffi = FFI() - ffi.cdef("int close(int); static const int BB = 42; extern int somevar;") - target = udir.join('test_simple.py') - make_py_source(ffi, 'test_simple', str(target)) - assert target.read() == r"""# auto-generated file -import _cffi_backend - -ffi = _cffi_backend.FFI('test_simple', - _version = 0x2601, - _types = b'\x00\x00\x01\x0D\x00\x00\x07\x01\x00\x00\x00\x0F', - _globals = (b'\xFF\xFF\xFF\x1FBB',42,b'\x00\x00\x00\x23close',0,b'\x00\x00\x01\x21somevar',0), -) -""" - -def test_global_constant(): - ffi = FFI() - ffi.cdef("static const long BB; static const float BF = 12;") - target = udir.join('test_valid_global_constant.py') - make_py_source(ffi, 'test_valid_global_constant', str(target)) - assert target.read() == r"""# auto-generated file -import _cffi_backend - -ffi = _cffi_backend.FFI('test_valid_global_constant', - _version = 0x2601, - _types = b'\x00\x00\x0D\x01\x00\x00\x09\x01', - _globals = (b'\x00\x00\x01\x25BB',0,b'\x00\x00\x00\x25BF',0), -) -""" - -def test_invalid_global_constant_3(): - ffi = FFI() - e = py.test.raises(CDefError, ffi.cdef, "#define BB 12.34") - assert str(e.value).startswith( - "only supports one of the following syntax:") - -def test_invalid_dotdotdot_in_macro(): - ffi = FFI() - ffi.cdef("#define FOO ...") - target = udir.join('test_invalid_dotdotdot_in_macro.py') - e = py.test.raises(VerificationError, make_py_source, ffi, - 'test_invalid_dotdotdot_in_macro', str(target)) - assert str(e.value) == ("macro FOO: cannot use the syntax '...' in " - "'#define FOO ...' when using the ABI mode") - -def test_typename(): - ffi = FFI() - ffi.cdef("typedef int foobar_t;") - target = udir.join('test_typename.py') - make_py_source(ffi, 'test_typename', str(target)) - assert target.read() == r"""# auto-generated file -import _cffi_backend - -ffi = _cffi_backend.FFI('test_typename', - _version = 0x2601, - _types = b'\x00\x00\x07\x01', - _typenames = (b'\x00\x00\x00\x00foobar_t',), -) -""" - -def test_enum(): - ffi = FFI() - ffi.cdef("enum myenum_e { AA, BB, CC=-42 };") - target = udir.join('test_enum.py') - make_py_source(ffi, 'test_enum', str(target)) - assert target.read() == r"""# auto-generated file -import _cffi_backend - -ffi = _cffi_backend.FFI('test_enum', - _version = 0x2601, - _types = b'\x00\x00\x00\x0B', - _globals = (b'\xFF\xFF\xFF\x0BAA',0,b'\xFF\xFF\xFF\x0BBB',1,b'\xFF\xFF\xFF\x0BCC',-42), - _enums = (b'\x00\x00\x00\x00\x00\x00\x00\x15myenum_e\x00AA,BB,CC',), -) -""" - -def test_struct(): - ffi = FFI() - ffi.cdef("struct foo_s { int a; signed char b[]; }; struct bar_s;") - target = udir.join('test_struct.py') - make_py_source(ffi, 'test_struct', str(target)) - assert target.read() == r"""# auto-generated file -import _cffi_backend - -ffi = _cffi_backend.FFI('test_struct', - _version = 0x2601, - _types = b'\x00\x00\x07\x01\x00\x00\x03\x01\x00\x00\x01\x07\x00\x00\x00\x09\x00\x00\x01\x09', - _struct_unions = ((b'\x00\x00\x00\x03\x00\x00\x00\x10bar_s',),(b'\x00\x00\x00\x04\x00\x00\x00\x02foo_s',b'\x00\x00\x00\x11a',b'\x00\x00\x02\x11b')), -) -""" - -def test_include(): - ffi = FFI() - ffi.cdef("#define ABC 123") - ffi.set_source('test_include', None) - target = udir.join('test_include.py') - make_py_source(ffi, 'test_include', str(target)) - assert target.read() == r"""# auto-generated file -import _cffi_backend - -ffi = _cffi_backend.FFI('test_include', - _version = 0x2601, - _types = b'', - _globals = (b'\xFF\xFF\xFF\x1FABC',123,), -) -""" - # - ffi2 = FFI() - ffi2.include(ffi) - target2 = udir.join('test2_include.py') - make_py_source(ffi2, 'test2_include', str(target2)) - assert target2.read() == r"""# auto-generated file -import _cffi_backend -from test_include import ffi as _ffi0 - -ffi = _cffi_backend.FFI('test2_include', - _version = 0x2601, - _types = b'', - _includes = (_ffi0,), -) -""" - -def test_negative_constant(): - ffi = FFI() - ffi.cdef("static const int BB = -42;") - target = udir.join('test_negative_constant.py') - make_py_source(ffi, 'test_negative_constant', str(target)) - assert target.read() == r"""# auto-generated file -import _cffi_backend - -ffi = _cffi_backend.FFI('test_negative_constant', - _version = 0x2601, - _types = b'', - _globals = (b'\xFF\xFF\xFF\x1FBB',-42,), -) -""" - -def test_struct_included(): - baseffi = FFI() - baseffi.cdef("struct foo_s { int x; };") - baseffi.set_source('test_struct_included_base', None) - # - ffi = FFI() - ffi.include(baseffi) - target = udir.join('test_struct_included.py') - make_py_source(ffi, 'test_struct_included', str(target)) - assert target.read() == r"""# auto-generated file -import _cffi_backend -from test_struct_included_base import ffi as _ffi0 - -ffi = _cffi_backend.FFI('test_struct_included', - _version = 0x2601, - _types = b'\x00\x00\x00\x09', - _struct_unions = ((b'\x00\x00\x00\x00\x00\x00\x00\x08foo_s',),), - _includes = (_ffi0,), -) -""" - -def test_no_cross_include(): - baseffi = FFI() - baseffi.set_source('test_no_cross_include_base', "..source..") - # - ffi = FFI() - ffi.include(baseffi) - target = udir.join('test_no_cross_include.py') - py.test.raises(VerificationError, make_py_source, - ffi, 'test_no_cross_include', str(target)) - -def test_array(): - ffi = FFI() - ffi.cdef("typedef int32_t my_array_t[42];") - target = udir.join('test_array.py') - make_py_source(ffi, 'test_array', str(target)) - assert target.read() == r"""# auto-generated file -import _cffi_backend - -ffi = _cffi_backend.FFI('test_array', - _version = 0x2601, - _types = b'\x00\x00\x15\x01\x00\x00\x00\x05\x00\x00\x00\x2A', - _typenames = (b'\x00\x00\x00\x01my_array_t',), -) -""" - -def test_array_overflow(): - ffi = FFI() - ffi.cdef("typedef int32_t my_array_t[3000000000];") - target = udir.join('test_array_overflow.py') - py.test.raises(OverflowError, make_py_source, - ffi, 'test_array_overflow', str(target)) - -def test_global_var(): - ffi = FFI() - ffi.cdef("extern int myglob;") - target = udir.join('test_global_var.py') - make_py_source(ffi, 'test_global_var', str(target)) - assert target.read() == r"""# auto-generated file -import _cffi_backend - -ffi = _cffi_backend.FFI('test_global_var', - _version = 0x2601, - _types = b'\x00\x00\x07\x01', - _globals = (b'\x00\x00\x00\x21myglob',0,), -) -""" - -def test_bitfield(): - ffi = FFI() - ffi.cdef("struct foo_s { int y:10; short x:5; };") - target = udir.join('test_bitfield.py') - make_py_source(ffi, 'test_bitfield', str(target)) - assert target.read() == r"""# auto-generated file -import _cffi_backend - -ffi = _cffi_backend.FFI('test_bitfield', - _version = 0x2601, - _types = b'\x00\x00\x07\x01\x00\x00\x05\x01\x00\x00\x00\x09', - _struct_unions = ((b'\x00\x00\x00\x02\x00\x00\x00\x02foo_s',b'\x00\x00\x00\x13\x00\x00\x00\x0Ay',b'\x00\x00\x01\x13\x00\x00\x00\x05x'),), -) -""" diff --git a/testing/cffi1/test_dlopen_unicode_literals.py b/testing/cffi1/test_dlopen_unicode_literals.py deleted file mode 100644 index e792866..0000000 --- a/testing/cffi1/test_dlopen_unicode_literals.py +++ /dev/null @@ -1,9 +0,0 @@ -import py, os - -s = """from __future__ import unicode_literals -""" - -with open(os.path.join(os.path.dirname(__file__), 'test_dlopen.py')) as f: - s += f.read() - -exec(py.code.compile(s)) diff --git a/testing/cffi1/test_ffi_obj.py b/testing/cffi1/test_ffi_obj.py deleted file mode 100644 index 0d29290..0000000 --- a/testing/cffi1/test_ffi_obj.py +++ /dev/null @@ -1,536 +0,0 @@ -import py, sys -import pytest -import _cffi_backend as _cffi1_backend - - -def test_ffi_new(): - ffi = _cffi1_backend.FFI() - p = ffi.new("int *") - p[0] = -42 - assert p[0] == -42 - assert type(ffi) is ffi.__class__ is _cffi1_backend.FFI - -def test_ffi_subclass(): - class FOO(_cffi1_backend.FFI): - def __init__(self, x): - self.x = x - foo = FOO(42) - assert foo.x == 42 - p = foo.new("int *") - assert p[0] == 0 - assert type(foo) is foo.__class__ is FOO - -def test_ffi_no_argument(): - py.test.raises(TypeError, _cffi1_backend.FFI, 42) - -def test_ffi_cache_type(): - ffi = _cffi1_backend.FFI() - t1 = ffi.typeof("int **") - t2 = ffi.typeof("int *") - assert t2.item is t1.item.item - assert t2 is t1.item - assert ffi.typeof("int[][10]") is ffi.typeof("int[][10]") - assert ffi.typeof("int(*)()") is ffi.typeof("int(*)()") - -def test_ffi_type_not_immortal(): - import weakref, gc - ffi = _cffi1_backend.FFI() - t1 = ffi.typeof("int **") - t2 = ffi.typeof("int *") - w1 = weakref.ref(t1) - w2 = weakref.ref(t2) - del t1, ffi - gc.collect() - assert w1() is None - assert w2() is t2 - ffi = _cffi1_backend.FFI() - assert ffi.typeof(ffi.new("int **")[0]) is t2 - # - ffi = _cffi1_backend.FFI() - t1 = ffi.typeof("int ***") - t2 = ffi.typeof("int **") - w1 = weakref.ref(t1) - w2 = weakref.ref(t2) - del t2, ffi - gc.collect() - assert w1() is t1 - assert w2() is not None # kept alive by t1 - ffi = _cffi1_backend.FFI() - assert ffi.typeof("int * *") is t1.item - -def test_ffi_cache_type_globally(): - ffi1 = _cffi1_backend.FFI() - ffi2 = _cffi1_backend.FFI() - t1 = ffi1.typeof("int *") - t2 = ffi2.typeof("int *") - assert t1 is t2 - -def test_ffi_invalid(): - ffi = _cffi1_backend.FFI() - # array of 10 times an "int[]" is invalid - py.test.raises(ValueError, ffi.typeof, "int[10][]") - -def test_ffi_docstrings(): - # check that all methods of the FFI class have a docstring. - check_type = type(_cffi1_backend.FFI.new) - for methname in dir(_cffi1_backend.FFI): - if not methname.startswith('_'): - method = getattr(_cffi1_backend.FFI, methname) - if isinstance(method, check_type): - assert method.__doc__, "method FFI.%s() has no docstring" % ( - methname,) - -def test_ffi_NULL(): - NULL = _cffi1_backend.FFI.NULL - assert _cffi1_backend.FFI().typeof(NULL).cname == "void *" - -def test_ffi_no_attr(): - ffi = _cffi1_backend.FFI() - with pytest.raises(AttributeError): - ffi.no_such_name - with pytest.raises(AttributeError): - ffi.no_such_name = 42 - with pytest.raises(AttributeError): - del ffi.no_such_name - -def test_ffi_string(): - ffi = _cffi1_backend.FFI() - p = ffi.new("char[]", init=b"foobar\x00baz") - assert ffi.string(p) == b"foobar" - assert ffi.string(cdata=p, maxlen=3) == b"foo" - -def test_ffi_errno(): - # xxx not really checking errno, just checking that we can read/write it - ffi = _cffi1_backend.FFI() - ffi.errno = 42 - assert ffi.errno == 42 - -def test_ffi_alignof(): - ffi = _cffi1_backend.FFI() - assert ffi.alignof("int") == 4 - assert ffi.alignof("int[]") == 4 - assert ffi.alignof("int[41]") == 4 - assert ffi.alignof("short[41]") == 2 - assert ffi.alignof(ffi.new("int[41]")) == 4 - assert ffi.alignof(ffi.new("int[]", 41)) == 4 - -def test_ffi_sizeof(): - ffi = _cffi1_backend.FFI() - assert ffi.sizeof("int") == 4 - py.test.raises(ffi.error, ffi.sizeof, "int[]") - assert ffi.sizeof("int[41]") == 41 * 4 - assert ffi.sizeof(ffi.new("int[41]")) == 41 * 4 - assert ffi.sizeof(ffi.new("int[]", 41)) == 41 * 4 - -def test_ffi_callback(): - ffi = _cffi1_backend.FFI() - assert ffi.callback("int(int)", lambda x: x + 42)(10) == 52 - assert ffi.callback("int(*)(int)", lambda x: x + 42)(10) == 52 - assert ffi.callback("int(int)", lambda x: x + "", -66)(10) == -66 - assert ffi.callback("int(int)", lambda x: x + "", error=-66)(10) == -66 - -def test_ffi_callback_decorator(): - ffi = _cffi1_backend.FFI() - assert ffi.callback(ffi.typeof("int(*)(int)"))(lambda x: x + 42)(10) == 52 - deco = ffi.callback("int(int)", error=-66) - assert deco(lambda x: x + "")(10) == -66 - assert deco(lambda x: x + 42)(10) == 52 - -def test_ffi_callback_onerror(): - ffi = _cffi1_backend.FFI() - seen = [] - def oops(*args): - seen.append(args) - - @ffi.callback("int(int)", onerror=oops) - def fn1(x): - return x + "" - assert fn1(10) == 0 - - @ffi.callback("int(int)", onerror=oops, error=-66) - def fn2(x): - return x + "" - assert fn2(10) == -66 - - assert len(seen) == 2 - exc, val, tb = seen[0] - assert exc is TypeError - assert isinstance(val, TypeError) - assert tb.tb_frame.f_code.co_name == "fn1" - exc, val, tb = seen[1] - assert exc is TypeError - assert isinstance(val, TypeError) - assert tb.tb_frame.f_code.co_name == "fn2" - # - py.test.raises(TypeError, ffi.callback, "int(int)", - lambda x: x, onerror=42) # <- not callable - -def test_ffi_getctype(): - ffi = _cffi1_backend.FFI() - assert ffi.getctype("int") == "int" - assert ffi.getctype("int", 'x') == "int x" - assert ffi.getctype("int*") == "int *" - assert ffi.getctype("int*", '') == "int *" - assert ffi.getctype("int*", 'x') == "int * x" - assert ffi.getctype("int", '*') == "int *" - assert ffi.getctype("int", replace_with=' * x ') == "int * x" - assert ffi.getctype(ffi.typeof("int*"), '*') == "int * *" - assert ffi.getctype("int", '[5]') == "int[5]" - assert ffi.getctype("int[5]", '[6]') == "int[6][5]" - assert ffi.getctype("int[5]", '(*)') == "int(*)[5]" - # special-case for convenience: automatically put '()' around '*' - assert ffi.getctype("int[5]", '*') == "int(*)[5]" - assert ffi.getctype("int[5]", '*foo') == "int(*foo)[5]" - assert ffi.getctype("int[5]", ' ** foo ') == "int(** foo)[5]" - -def test_addressof(): - ffi = _cffi1_backend.FFI() - a = ffi.new("int[10]") - b = ffi.addressof(a, 5) - b[2] = -123 - assert a[7] == -123 - -def test_handle(): - ffi = _cffi1_backend.FFI() - x = [2, 4, 6] - xp = ffi.new_handle(x) - assert ffi.typeof(xp) == ffi.typeof("void *") - assert ffi.from_handle(xp) is x - yp = ffi.new_handle([6, 4, 2]) - assert ffi.from_handle(yp) == [6, 4, 2] - -def test_handle_unique(): - ffi = _cffi1_backend.FFI() - assert ffi.new_handle(None) is not ffi.new_handle(None) - assert ffi.new_handle(None) != ffi.new_handle(None) - -def test_ffi_cast(): - ffi = _cffi1_backend.FFI() - assert ffi.cast("int(*)(int)", 0) == ffi.NULL - ffi.callback("int(int)") # side-effect of registering this string - py.test.raises(ffi.error, ffi.cast, "int(int)", 0) - -def test_ffi_invalid_type(): - ffi = _cffi1_backend.FFI() - e = py.test.raises(ffi.error, ffi.cast, "", 0) - assert str(e.value) == ("identifier expected\n" - "\n" - "^") - e = py.test.raises(ffi.error, ffi.cast, "struct struct", 0) - assert str(e.value) == ("struct or union name expected\n" - "struct struct\n" - " ^") - e = py.test.raises(ffi.error, ffi.cast, "struct never_heard_of_s", 0) - assert str(e.value) == ("undefined struct/union name\n" - "struct never_heard_of_s\n" - " ^") - e = py.test.raises(ffi.error, ffi.cast, "\t\n\x01\x1f~\x7f\x80\xff", 0) - marks = "?" if sys.version_info < (3,) else "??" - assert str(e.value) == ("identifier expected\n" - " ??~?%s%s\n" - " ^" % (marks, marks)) - e = py.test.raises(ffi.error, ffi.cast, "X" * 600, 0) - assert str(e.value) == ("undefined type name") - -def test_ffi_buffer(): - ffi = _cffi1_backend.FFI() - a = ffi.new("signed char[]", [5, 6, 7]) - assert ffi.buffer(a)[:] == b'\x05\x06\x07' - assert ffi.buffer(cdata=a, size=2)[:] == b'\x05\x06' - assert type(ffi.buffer(a)) is ffi.buffer - -def test_ffi_from_buffer(): - import array - ffi = _cffi1_backend.FFI() - a = array.array('H', [10000, 20000, 30000, 40000]) - c = ffi.from_buffer(a) - assert ffi.typeof(c) is ffi.typeof("char[]") - assert len(c) == 8 - ffi.cast("unsigned short *", c)[1] += 500 - assert list(a) == [10000, 20500, 30000, 40000] - py.test.raises(TypeError, ffi.from_buffer, a, True) - assert c == ffi.from_buffer("char[]", a, True) - assert c == ffi.from_buffer(a, require_writable=True) - # - c = ffi.from_buffer("unsigned short[]", a) - assert len(c) == 4 - assert c[1] == 20500 - # - c = ffi.from_buffer("unsigned short[2][2]", a) - assert len(c) == 2 - assert len(c[0]) == 2 - assert c[0][1] == 20500 - # - p = ffi.from_buffer(b"abcd") - assert p[2] == b"c" - # - assert p == ffi.from_buffer(b"abcd", require_writable=False) - py.test.raises((TypeError, BufferError), ffi.from_buffer, - "char[]", b"abcd", True) - py.test.raises((TypeError, BufferError), ffi.from_buffer, b"abcd", - require_writable=True) - -def test_memmove(): - ffi = _cffi1_backend.FFI() - p = ffi.new("short[]", [-1234, -2345, -3456, -4567, -5678]) - ffi.memmove(p, p + 1, 4) - assert list(p) == [-2345, -3456, -3456, -4567, -5678] - p[2] = 999 - ffi.memmove(p + 2, p, 6) - assert list(p) == [-2345, -3456, -2345, -3456, 999] - ffi.memmove(p + 4, ffi.new("char[]", 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 - ffi = _cffi1_backend.FFI() - a = array.array('H', [10000, 20000, 30000]) - p = ffi.new("short[]", 5) - ffi.memmove(p, a, 6) - assert list(p) == [10000, 20000, 30000, 0, 0] - ffi.memmove(p + 1, a, 6) - assert list(p) == [10000, 10000, 20000, 30000, 0] - b = array.array('h', [-1000, -2000, -3000]) - ffi.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 - ffi.memmove(b, p, 2) - assert b.tolist() == [999, 20000, -3000] - ffi.memmove(b, p + 2, 4) - assert b.tolist() == [997, 996, -3000] - p[2] = -p[2] - p[3] = -p[3] - ffi.memmove(b, p + 2, 6) - assert b.tolist() == [-997, -996, 995] - -def test_memmove_readonly_readwrite(): - ffi = _cffi1_backend.FFI() - p = ffi.new("signed char[]", 5) - ffi.memmove(p, b"abcde", 3) - assert list(p) == [ord("a"), ord("b"), ord("c"), 0, 0] - ffi.memmove(p, bytearray(b"ABCDE"), 2) - assert list(p) == [ord("A"), ord("B"), ord("c"), 0, 0] - py.test.raises((TypeError, BufferError), ffi.memmove, b"abcde", p, 3) - ba = bytearray(b"xxxxx") - ffi.memmove(dest=ba, src=p, n=3) - assert ba == bytearray(b"ABcxx") - -def test_ffi_types(): - CData = _cffi1_backend.FFI.CData - CType = _cffi1_backend.FFI.CType - ffi = _cffi1_backend.FFI() - assert isinstance(ffi.cast("int", 42), CData) - assert isinstance(ffi.typeof("int"), CType) - -def test_ffi_getwinerror(): - if sys.platform != "win32": - py.test.skip("for windows") - ffi = _cffi1_backend.FFI() - n = (1 << 29) + 42 - code, message = ffi.getwinerror(code=n) - assert code == n - -def test_ffi_new_allocator_1(): - ffi = _cffi1_backend.FFI() - alloc1 = ffi.new_allocator() - alloc2 = ffi.new_allocator(should_clear_after_alloc=False) - for retry in range(100): - p1 = alloc1("int[10]") - p2 = alloc2("int[10]") - combination = 0 - for i in range(10): - assert p1[i] == 0 - combination |= p2[i] - p1[i] = -42 - p2[i] = -43 - if combination != 0: - break - del p1, p2 - import gc; gc.collect() - else: - raise AssertionError("cannot seem to get an int[10] not " - "completely cleared") - -def test_ffi_new_allocator_2(): - ffi = _cffi1_backend.FFI() - seen = [] - def myalloc(size): - seen.append(size) - return ffi.new("char[]", b"X" * size) - def myfree(raw): - seen.append(raw) - alloc1 = ffi.new_allocator(myalloc, myfree) - alloc2 = ffi.new_allocator(alloc=myalloc, free=myfree, - should_clear_after_alloc=False) - p1 = alloc1("int[10]") - p2 = alloc2("int[]", 10) - assert seen == [40, 40] - assert ffi.typeof(p1) == ffi.typeof("int[10]") - assert ffi.sizeof(p1) == 40 - assert ffi.typeof(p2) == ffi.typeof("int[]") - assert ffi.sizeof(p2) == 40 - assert p1[5] == 0 - assert p2[6] == ord('X') * 0x01010101 - raw1 = ffi.cast("char *", p1) - raw2 = ffi.cast("char *", p2) - del p1, p2 - retries = 0 - while len(seen) != 4: - retries += 1 - assert retries <= 5 - import gc; gc.collect() - assert (seen == [40, 40, raw1, raw2] or - seen == [40, 40, raw2, raw1]) - assert repr(seen[2]) == "<cdata 'char[]' owning 41 bytes>" - assert repr(seen[3]) == "<cdata 'char[]' owning 41 bytes>" - -def test_ffi_new_allocator_3(): - ffi = _cffi1_backend.FFI() - seen = [] - def myalloc(size): - seen.append(size) - return ffi.new("char[]", b"X" * size) - alloc1 = ffi.new_allocator(myalloc) # no 'free' - p1 = alloc1("int[10]") - assert seen == [40] - assert ffi.typeof(p1) == ffi.typeof("int[10]") - assert ffi.sizeof(p1) == 40 - assert p1[5] == 0 - -def test_ffi_new_allocator_4(): - ffi = _cffi1_backend.FFI() - py.test.raises(TypeError, ffi.new_allocator, free=lambda x: None) - # - def myalloc2(size): - raise LookupError - alloc2 = ffi.new_allocator(myalloc2) - py.test.raises(LookupError, alloc2, "int[5]") - # - def myalloc3(size): - return 42 - alloc3 = ffi.new_allocator(myalloc3) - e = py.test.raises(TypeError, alloc3, "int[5]") - assert str(e.value) == "alloc() must return a cdata object (got int)" - # - def myalloc4(size): - return ffi.cast("int", 42) - alloc4 = ffi.new_allocator(myalloc4) - e = py.test.raises(TypeError, alloc4, "int[5]") - assert str(e.value) == "alloc() must return a cdata pointer, not 'int'" - # - def myalloc5(size): - return ffi.NULL - alloc5 = ffi.new_allocator(myalloc5) - py.test.raises(MemoryError, alloc5, "int[5]") - -def test_bool_issue228(): - ffi = _cffi1_backend.FFI() - fntype = ffi.typeof("int(*callback)(bool is_valid)") - assert repr(fntype.args[0]) == "<ctype '_Bool'>" - -def test_FILE_issue228(): - fntype1 = _cffi1_backend.FFI().typeof("FILE *") - fntype2 = _cffi1_backend.FFI().typeof("FILE *") - assert repr(fntype1) == "<ctype 'FILE *'>" - assert fntype1 is fntype2 - -def test_cast_from_int_type_to_bool(): - ffi = _cffi1_backend.FFI() - for basetype in ['char', 'short', 'int', 'long', 'long long']: - for sign in ['signed', 'unsigned']: - type = '%s %s' % (sign, basetype) - assert int(ffi.cast("_Bool", ffi.cast(type, 42))) == 1 - assert int(ffi.cast("bool", ffi.cast(type, 42))) == 1 - assert int(ffi.cast("_Bool", ffi.cast(type, 0))) == 0 - -def test_init_once(): - def do_init(): - seen.append(1) - return 42 - ffi = _cffi1_backend.FFI() - seen = [] - for i in range(3): - res = ffi.init_once(do_init, "tag1") - assert res == 42 - assert seen == [1] - for i in range(3): - res = ffi.init_once(do_init, "tag2") - assert res == 42 - assert seen == [1, 1] - -def test_init_once_multithread(): - if sys.version_info < (3,): - import thread - else: - import _thread as thread - import time - # - def do_init(): - print('init!') - seen.append('init!') - time.sleep(1) - seen.append('init done') - print('init done') - return 7 - ffi = _cffi1_backend.FFI() - seen = [] - for i in range(6): - def f(): - res = ffi.init_once(do_init, "tag") - seen.append(res) - thread.start_new_thread(f, ()) - time.sleep(1.5) - assert seen == ['init!', 'init done'] + 6 * [7] - -def test_init_once_failure(): - def do_init(): - seen.append(1) - raise ValueError - ffi = _cffi1_backend.FFI() - seen = [] - for i in range(5): - py.test.raises(ValueError, ffi.init_once, do_init, "tag") - assert seen == [1] * (i + 1) - -def test_init_once_multithread_failure(): - if sys.version_info < (3,): - import thread - else: - import _thread as thread - import time - def do_init(): - seen.append('init!') - time.sleep(1) - seen.append('oops') - raise ValueError - ffi = _cffi1_backend.FFI() - seen = [] - for i in range(3): - def f(): - py.test.raises(ValueError, ffi.init_once, do_init, "tag") - thread.start_new_thread(f, ()) - i = 0 - while len(seen) < 6: - i += 1 - assert i < 20 - time.sleep(0.51) - assert seen == ['init!', 'oops'] * 3 - -def test_unpack(): - ffi = _cffi1_backend.FFI() - p = ffi.new("char[]", b"abc\x00def") - assert ffi.unpack(p+1, 7) == b"bc\x00def\x00" - p = ffi.new("int[]", [-123456789]) - assert ffi.unpack(p, 1) == [-123456789] - -def test_negative_array_size(): - ffi = _cffi1_backend.FFI() - py.test.raises(ffi.error, ffi.cast, "int[-5]", 0) diff --git a/testing/cffi1/test_function_args.py b/testing/cffi1/test_function_args.py deleted file mode 100644 index 30c6fed..0000000 --- a/testing/cffi1/test_function_args.py +++ /dev/null @@ -1,208 +0,0 @@ -import pytest, sys -try: - # comment out the following line to run this test. - # the latest on x86-64 linux: https://github.com/libffi/libffi/issues/574 - if sys.platform != 'win32': - raise ImportError("this test is skipped because it keeps finding " - "failures in libffi, instead of cffi") - - from hypothesis import given, settings, example - from hypothesis import strategies as st -except ImportError as e: - e1 = e - def test_types(): - pytest.skip(str(e1)) -else: - - from cffi import FFI - import sys, random - from .test_recompiler import verify - - ALL_PRIMITIVES = [ - 'unsigned char', - 'short', - 'int', - 'long', - 'long long', - 'float', - 'double', - #'long double', --- on x86 it can give libffi crashes - ] - def _make_struct(s): - return st.lists(s, min_size=1) - types = st.one_of(st.sampled_from(ALL_PRIMITIVES), - st.lists(st.sampled_from(ALL_PRIMITIVES), min_size=1)) - # NB. 'types' could be st.recursive instead, but it doesn't - # really seem useful - - def draw_primitive(ffi, typename): - value = random.random() * 2**40 - if typename != 'long double': - return ffi.cast(typename, value) - else: - return value - - TEST_RUN_COUNTER = 0 - - - @given(st.lists(types), types) - @settings(max_examples=100, deadline=5000) # 5000ms - def test_types(tp_args, tp_result): - global TEST_RUN_COUNTER - print(tp_args, tp_result) - cdefs = [] - structs = {} - - def build_type(tp): - if type(tp) is list: - field_types = [build_type(tp1) for tp1 in tp] - fields = ['%s f%d;' % (ftp, j) - for (j, ftp) in enumerate(field_types)] - fields = '\n '.join(fields) - name = 's%d' % len(cdefs) - cdefs.append("typedef struct {\n %s\n} %s;" % (fields, name)) - structs[name] = field_types - return name - else: - return tp - - args = [build_type(tp) for tp in tp_args] - result = build_type(tp_result) - - TEST_RUN_COUNTER += 1 - signature = "%s testfargs(%s)" % (result, - ', '.join(['%s a%d' % (arg, i) for (i, arg) in enumerate(args)]) - or 'void') - - source = list(cdefs) - - cdefs.append("%s;" % signature) - cdefs.append("extern %s testfargs_result;" % result) - for i, arg in enumerate(args): - cdefs.append("extern %s testfargs_arg%d;" % (arg, i)) - source.append("%s testfargs_result;" % result) - for i, arg in enumerate(args): - source.append("%s testfargs_arg%d;" % (arg, i)) - source.append(signature) - source.append("{") - for i, arg in enumerate(args): - source.append(" testfargs_arg%d = a%d;" % (i, i)) - source.append(" return testfargs_result;") - source.append("}") - - typedef_line = "typedef %s;" % (signature.replace('testfargs', - '(*mycallback_t)'),) - assert signature.endswith(')') - sig_callback = "%s testfcallback(mycallback_t callback)" % result - cdefs.append(typedef_line) - cdefs.append("%s;" % sig_callback) - source.append(typedef_line) - source.append(sig_callback) - source.append("{") - source.append(" return callback(%s);" % - ', '.join(["testfargs_arg%d" % i for i in range(len(args))])) - source.append("}") - - ffi = FFI() - ffi.cdef("\n".join(cdefs)) - lib = verify(ffi, 'test_function_args_%d' % TEST_RUN_COUNTER, - "\n".join(source), no_cpp=True) - - # when getting segfaults, enable this: - if False: - from testing.udir import udir - import subprocess - f = open(str(udir.join('run1.py')), 'w') - f.write('import sys; sys.path = %r\n' % (sys.path,)) - f.write('from _CFFI_test_function_args_%d import ffi, lib\n' % - TEST_RUN_COUNTER) - for i in range(len(args)): - f.write('a%d = ffi.new("%s *")\n' % (i, args[i])) - aliststr = ', '.join(['a%d[0]' % i for i in range(len(args))]) - f.write('lib.testfargs(%s)\n' % aliststr) - f.write('ffi.addressof(lib, "testfargs")(%s)\n' % aliststr) - f.close() - print("checking for segfault for direct call...") - rc = subprocess.call([sys.executable, 'run1.py'], cwd=str(udir)) - assert rc == 0, rc - - def make_arg(tp): - if tp in structs: - return [make_arg(tp1) for tp1 in structs[tp]] - else: - return draw_primitive(ffi, tp) - - passed_args = [make_arg(arg) for arg in args] - returned_value = make_arg(result) - - def write(p, v): - if type(v) is list: - for i, v1 in enumerate(v): - write(ffi.addressof(p, 'f%d' % i), v1) - else: - p[0] = v - - write(ffi.addressof(lib, 'testfargs_result'), returned_value) - - ## CALL forcing libffi - print("CALL forcing libffi") - received_return = ffi.addressof(lib, 'testfargs')(*passed_args) - ## - - _tp_long_double = ffi.typeof("long double") - def check(p, v): - if type(v) is list: - for i, v1 in enumerate(v): - check(ffi.addressof(p, 'f%d' % i), v1) - else: - if ffi.typeof(p).item is _tp_long_double: - assert ffi.cast("double", p[0]) == v - else: - assert p[0] == v - - for i, arg in enumerate(passed_args): - check(ffi.addressof(lib, 'testfargs_arg%d' % i), arg) - ret = ffi.new(result + "*", received_return) - check(ret, returned_value) - - ## CALLBACK - def expand(value): - if isinstance(value, ffi.CData): - t = ffi.typeof(value) - if t is _tp_long_double: - return float(ffi.cast("double", value)) - return [expand(getattr(value, 'f%d' % i)) - for i in range(len(t.fields))] - else: - return value - - # when getting segfaults, enable this: - if False: - from testing.udir import udir - import subprocess - f = open(str(udir.join('run1.py')), 'w') - f.write('import sys; sys.path = %r\n' % (sys.path,)) - f.write('from _CFFI_test_function_args_%d import ffi, lib\n' % - TEST_RUN_COUNTER) - f.write('def callback(*args): return ffi.new("%s *")[0]\n' % result) - f.write('fptr = ffi.callback("%s(%s)", callback)\n' % (result, - ','.join(args))) - f.write('print(lib.testfcallback(fptr))\n') - f.close() - print("checking for segfault for callback...") - rc = subprocess.call([sys.executable, 'run1.py'], cwd=str(udir)) - assert rc == 0, rc - - seen_args = [] - def callback(*args): - seen_args.append([expand(arg) for arg in args]) - return returned_value - - fptr = ffi.callback("%s(%s)" % (result, ','.join(args)), callback) - print("CALL with callback") - received_return = lib.testfcallback(fptr) - - assert len(seen_args) == 1 - assert passed_args == seen_args[0] - ret = ffi.new(result + "*", received_return) - check(ret, returned_value) diff --git a/testing/cffi1/test_new_ffi_1.py b/testing/cffi1/test_new_ffi_1.py deleted file mode 100644 index 640830b..0000000 --- a/testing/cffi1/test_new_ffi_1.py +++ /dev/null @@ -1,1831 +0,0 @@ -import py -import pytest -import platform, imp -import sys, os, ctypes -import cffi -from testing.udir import udir -from testing.support import * -from cffi.recompiler import recompile -from cffi.cffi_opcode import PRIMITIVE_TO_INDEX - -SIZE_OF_INT = ctypes.sizeof(ctypes.c_int) -SIZE_OF_LONG = ctypes.sizeof(ctypes.c_long) -SIZE_OF_SHORT = ctypes.sizeof(ctypes.c_short) -SIZE_OF_PTR = ctypes.sizeof(ctypes.c_void_p) -SIZE_OF_WCHAR = ctypes.sizeof(ctypes.c_wchar) - - -def setup_module(): - global ffi, construction_params - ffi1 = cffi.FFI() - DEFS = r""" - struct repr { short a, b, c; }; - struct simple { int a; short b, c; }; - struct array { int a[2]; char b[3]; }; - struct recursive { int value; struct recursive *next; }; - union simple_u { int a; short b, c; }; - union init_u { char a; int b; }; - struct four_s { int a; short b, c, d; }; - union four_u { int a; short b, c, d; }; - struct string { const char *name; }; - struct ustring { const wchar_t *name; }; - struct voidp { void *p; int *q; short *r; }; - struct ab { int a, b; }; - struct abc { int a, b, c; }; - - /* don't use A0, B0, CC0, D0 because termios.h might be included - and it has its own #defines for these names */ - enum foq { cffiA0, cffiB0, cffiCC0, cffiD0 }; - enum bar { A1, B1=-2, CC1, D1, E1 }; - enum baz { A2=0x1000, B2=0x2000 }; - enum foo2 { A3, B3, C3, D3 }; - struct bar_with_e { enum foo2 e; }; - enum noncont { A4, B4=42, C4 }; - enum etypes {A5='!', B5='\'', C5=0x10, D5=010, E5=- 0x10, F5=-010}; - typedef enum { Value0 = 0 } e_t, *pe_t; - enum e_noninj { AA3=0, BB3=0, CC3=0, DD3=0 }; - enum e_prev { AA4, BB4=2, CC4=4, DD4=BB4, EE4, FF4=CC4, GG4=FF4 }; - - struct nesting { struct abc d, e; }; - struct array2 { int a, b; int c[99]; }; - struct align { char a; short b; char c; }; - struct bitfield { int a:10, b:20, c:3; }; - typedef enum { AA2, BB2, CC2 } foo_e_t; - typedef struct { foo_e_t f:2; } bfenum_t; - typedef struct { int a; } anon_foo_t; - typedef struct { char b, c; } anon_bar_t; - typedef struct named_foo_s { int a; } named_foo_t, *named_foo_p; - typedef struct { int a; } unnamed_foo_t, *unnamed_foo_p; - struct nonpacked { char a; int b; }; - struct array0 { int len; short data[0]; }; - struct array_no_length { int x; int a[]; }; - - struct nested_anon { - struct { int a, b; }; - union { int c, d; }; - }; - struct nested_field_ofs_s { - struct { int a; char b; }; - union { char c; }; - }; - union nested_anon_u { - struct { int a, b; }; - union { int c, d; }; - }; - struct abc50 { int a, b; int c[50]; }; - struct ints_and_bitfield { int a,b,c,d,e; int x:1; }; - """ - DEFS_PACKED = """ - struct is_packed { char a; int b; } /*here*/; - """ - if sys.platform == "win32": - DEFS = DEFS.replace('data[0]', 'data[1]') # not supported - CCODE = (DEFS + "\n#pragma pack(push,1)\n" + DEFS_PACKED + - "\n#pragma pack(pop)\n") - else: - CCODE = (DEFS + - DEFS_PACKED.replace('/*here*/', '__attribute__((packed))')) - - ffi1.cdef(DEFS) - ffi1.cdef(DEFS_PACKED, packed=True) - ffi1.set_source("test_new_ffi_1", CCODE) - - outputfilename = recompile(ffi1, "test_new_ffi_1", CCODE, - tmpdir=str(udir)) - module = imp.load_dynamic("test_new_ffi_1", outputfilename) - ffi = module.ffi - construction_params = (ffi1, CCODE) - - -class TestNewFFI1: - - def test_integer_ranges(self): - for (c_type, size) in [('char', 1), - ('short', 2), - ('short int', 2), - ('', 4), - ('int', 4), - ('long', SIZE_OF_LONG), - ('long int', SIZE_OF_LONG), - ('long long', 8), - ('long long int', 8), - ]: - for unsigned in [None, False, True]: - c_decl = {None: '', - False: 'signed ', - True: 'unsigned '}[unsigned] + c_type - if c_decl == 'char' or c_decl == '': - continue - self._test_int_type(ffi, c_decl, size, unsigned) - - def test_fixedsize_int(self): - for size in [1, 2, 4, 8]: - self._test_int_type(ffi, 'int%d_t' % (8*size), size, False) - self._test_int_type(ffi, 'uint%d_t' % (8*size), size, True) - self._test_int_type(ffi, 'intptr_t', SIZE_OF_PTR, False) - self._test_int_type(ffi, 'uintptr_t', SIZE_OF_PTR, True) - self._test_int_type(ffi, 'ptrdiff_t', SIZE_OF_PTR, False) - self._test_int_type(ffi, 'size_t', SIZE_OF_PTR, True) - self._test_int_type(ffi, 'ssize_t', SIZE_OF_PTR, False) - - def _test_int_type(self, ffi, c_decl, size, unsigned): - if unsigned: - min = 0 - max = (1 << (8*size)) - 1 - else: - min = -(1 << (8*size-1)) - max = (1 << (8*size-1)) - 1 - min = int(min) - max = int(max) - p = ffi.cast(c_decl, min) - assert p == min - assert bool(p) is bool(min) - assert int(p) == min - p = ffi.cast(c_decl, max) - assert int(p) == max - p = ffi.cast(c_decl, long(max)) - assert int(p) == max - q = ffi.cast(c_decl, min - 1) - assert ffi.typeof(q) is ffi.typeof(p) and int(q) == max - q = ffi.cast(c_decl, long(min - 1)) - assert ffi.typeof(q) is ffi.typeof(p) and int(q) == max - assert q == p - assert int(q) == int(p) - assert hash(q) == hash(p) - c_decl_ptr = '%s *' % c_decl - py.test.raises(OverflowError, ffi.new, c_decl_ptr, min - 1) - py.test.raises(OverflowError, ffi.new, c_decl_ptr, max + 1) - py.test.raises(OverflowError, ffi.new, c_decl_ptr, long(min - 1)) - py.test.raises(OverflowError, ffi.new, c_decl_ptr, long(max + 1)) - assert ffi.new(c_decl_ptr, min)[0] == min - assert ffi.new(c_decl_ptr, max)[0] == max - assert ffi.new(c_decl_ptr, long(min))[0] == min - assert ffi.new(c_decl_ptr, long(max))[0] == max - - def test_new_unsupported_type(self): - e = py.test.raises(TypeError, ffi.new, "int") - assert str(e.value) == "expected a pointer or array ctype, got 'int'" - - def test_new_single_integer(self): - p = ffi.new("int *") # similar to ffi.new("int[1]") - assert p[0] == 0 - p[0] = -123 - assert p[0] == -123 - p = ffi.new("int *", -42) - assert p[0] == -42 - assert repr(p) == "<cdata 'int *' owning %d bytes>" % SIZE_OF_INT - - def test_new_array_no_arg(self): - p = ffi.new("int[10]") - # the object was zero-initialized: - for i in range(10): - assert p[i] == 0 - - def test_array_indexing(self): - p = ffi.new("int[10]") - p[0] = 42 - p[9] = 43 - assert p[0] == 42 - assert p[9] == 43 - with pytest.raises(IndexError): - p[10] - with pytest.raises(IndexError): - p[10] = 44 - with pytest.raises(IndexError): - p[-1] - with pytest.raises(IndexError): - p[-1] = 44 - - def test_new_array_args(self): - # this tries to be closer to C: where we say "int x[5] = {10, 20, ..}" - # then here we must enclose the items in a list - p = ffi.new("int[5]", [10, 20, 30, 40, 50]) - assert p[0] == 10 - assert p[1] == 20 - assert p[2] == 30 - assert p[3] == 40 - assert p[4] == 50 - p = ffi.new("int[4]", [25]) - assert p[0] == 25 - assert p[1] == 0 # follow C convention rather than LuaJIT's - assert p[2] == 0 - assert p[3] == 0 - p = ffi.new("int[4]", [ffi.cast("int", -5)]) - assert p[0] == -5 - assert repr(p) == "<cdata 'int[4]' owning %d bytes>" % (4*SIZE_OF_INT) - - def test_new_array_varsize(self): - p = ffi.new("int[]", 10) # a single integer is the length - assert p[9] == 0 - with pytest.raises(IndexError): - p[10] - # - py.test.raises(TypeError, ffi.new, "int[]") - # - p = ffi.new("int[]", [-6, -7]) # a list is all the items, like C - assert p[0] == -6 - assert p[1] == -7 - with pytest.raises(IndexError): - p[2] - assert repr(p) == "<cdata 'int[]' owning %d bytes>" % (2*SIZE_OF_INT) - # - p = ffi.new("int[]", 0) - with pytest.raises(IndexError): - p[0] - py.test.raises(ValueError, ffi.new, "int[]", -1) - assert repr(p) == "<cdata 'int[]' owning 0 bytes>" - - def test_pointer_init(self): - n = ffi.new("int *", 24) - a = ffi.new("int *[10]", [ffi.NULL, ffi.NULL, n, n, ffi.NULL]) - for i in range(10): - if i not in (2, 3): - assert a[i] == ffi.NULL - assert a[2] == a[3] == n - - def test_cannot_cast(self): - a = ffi.new("short int[10]") - e = py.test.raises(TypeError, ffi.new, "long int **", a) - msg = str(e.value) - assert "'short[10]'" in msg and "'long *'" in msg - - def test_new_pointer_to_array(self): - a = ffi.new("int[4]", [100, 102, 104, 106]) - p = ffi.new("int **", a) - assert p[0] == ffi.cast("int *", a) - assert p[0][2] == 104 - p = ffi.cast("int *", a) - assert p[0] == 100 - assert p[1] == 102 - assert p[2] == 104 - assert p[3] == 106 - # keepalive: a - - def test_pointer_direct(self): - p = ffi.cast("int*", 0) - assert p is not None - assert bool(p) is False - assert p == ffi.cast("int*", 0) - assert p != None - assert repr(p) == "<cdata 'int *' NULL>" - a = ffi.new("int[]", [123, 456]) - p = ffi.cast("int*", a) - assert bool(p) is True - assert p == ffi.cast("int*", a) - assert p != ffi.cast("int*", 0) - assert p[0] == 123 - assert p[1] == 456 - - def test_repr(self): - typerepr = "<ctype '%s'>" - p = ffi.cast("short unsigned int", 0) - assert repr(p) == "<cdata 'unsigned short' 0>" - assert repr(ffi.typeof(p)) == typerepr % "unsigned short" - p = ffi.cast("unsigned short int", 0) - assert repr(p) == "<cdata 'unsigned short' 0>" - assert repr(ffi.typeof(p)) == typerepr % "unsigned short" - p = ffi.cast("int*", 0) - assert repr(p) == "<cdata 'int *' NULL>" - assert repr(ffi.typeof(p)) == typerepr % "int *" - # - p = ffi.new("int*") - assert repr(p) == "<cdata 'int *' owning %d bytes>" % SIZE_OF_INT - assert repr(ffi.typeof(p)) == typerepr % "int *" - p = ffi.new("int**") - assert repr(p) == "<cdata 'int * *' owning %d bytes>" % SIZE_OF_PTR - assert repr(ffi.typeof(p)) == typerepr % "int * *" - p = ffi.new("int [2]") - assert repr(p) == "<cdata 'int[2]' owning %d bytes>" % (2*SIZE_OF_INT) - assert repr(ffi.typeof(p)) == typerepr % "int[2]" - p = ffi.new("int*[2][3]") - assert repr(p) == "<cdata 'int *[2][3]' owning %d bytes>" % ( - 6*SIZE_OF_PTR) - assert repr(ffi.typeof(p)) == typerepr % "int *[2][3]" - p = ffi.new("struct repr *") - assert repr(p) == "<cdata 'struct repr *' owning %d bytes>" % ( - 3*SIZE_OF_SHORT) - assert repr(ffi.typeof(p)) == typerepr % "struct repr *" - # - q = ffi.cast("short", -123) - assert repr(q) == "<cdata 'short' -123>" - assert repr(ffi.typeof(q)) == typerepr % "short" - p = ffi.new("int*") - q = ffi.cast("short*", p) - assert repr(q).startswith("<cdata 'short *' 0x") - assert repr(ffi.typeof(q)) == typerepr % "short *" - p = ffi.new("int [2]") - q = ffi.cast("int*", p) - assert repr(q).startswith("<cdata 'int *' 0x") - assert repr(ffi.typeof(q)) == typerepr % "int *" - p = ffi.new("struct repr*") - q = ffi.cast("struct repr *", p) - assert repr(q).startswith("<cdata 'struct repr *' 0x") - assert repr(ffi.typeof(q)) == typerepr % "struct repr *" - prevrepr = repr(q) - q = q[0] - assert repr(q) == prevrepr.replace(' *', ' &') - assert repr(ffi.typeof(q)) == typerepr % "struct repr" - - def test_new_array_of_array(self): - p = ffi.new("int[3][4]") - p[0][0] = 10 - p[2][3] = 33 - assert p[0][0] == 10 - assert p[2][3] == 33 - with pytest.raises(IndexError): - p[1][-1] - - def test_constructor_array_of_array(self): - p = ffi.new("int[3][2]", [[10, 11], [12, 13], [14, 15]]) - assert p[2][1] == 15 - - def test_new_array_of_pointer_1(self): - n = ffi.new("int*", 99) - p = ffi.new("int*[4]") - p[3] = n - a = p[3] - assert repr(a).startswith("<cdata 'int *' 0x") - assert a[0] == 99 - - def test_new_array_of_pointer_2(self): - n = ffi.new("int[1]", [99]) - p = ffi.new("int*[4]") - p[3] = n - a = p[3] - assert repr(a).startswith("<cdata 'int *' 0x") - assert a[0] == 99 - - def test_char(self): - assert ffi.new("char*", b"\xff")[0] == b'\xff' - assert ffi.new("char*")[0] == b'\x00' - assert int(ffi.cast("char", 300)) == 300 - 256 - assert not bool(ffi.cast("char", 0)) - assert bool(ffi.cast("char", 1)) - assert bool(ffi.cast("char", 255)) - py.test.raises(TypeError, ffi.new, "char*", 32) - py.test.raises(TypeError, ffi.new, "char*", u+"x") - py.test.raises(TypeError, ffi.new, "char*", b"foo") - # - p = ffi.new("char[]", [b'a', b'b', b'\x9c']) - assert len(p) == 3 - assert p[0] == b'a' - assert p[1] == b'b' - assert p[2] == b'\x9c' - p[0] = b'\xff' - assert p[0] == b'\xff' - p = ffi.new("char[]", b"abcd") - assert len(p) == 5 - assert p[4] == b'\x00' # like in C, with: char[] p = "abcd"; - # - p = ffi.new("char[4]", b"ab") - assert len(p) == 4 - assert [p[i] for i in range(4)] == [b'a', b'b', b'\x00', b'\x00'] - p = ffi.new("char[2]", b"ab") - assert len(p) == 2 - assert [p[i] for i in range(2)] == [b'a', b'b'] - py.test.raises(IndexError, ffi.new, "char[2]", b"abc") - - def check_wchar_t(self, ffi): - try: - ffi.cast("wchar_t", 0) - except NotImplementedError: - py.test.skip("NotImplementedError: wchar_t") - - def test_wchar_t(self): - self.check_wchar_t(ffi) - assert ffi.new("wchar_t*", u+'x')[0] == u+'x' - assert ffi.new("wchar_t*", u+'\u1234')[0] == u+'\u1234' - if SIZE_OF_WCHAR > 2: - assert ffi.new("wchar_t*", u+'\U00012345')[0] == u+'\U00012345' - else: - py.test.raises(TypeError, ffi.new, "wchar_t*", u+'\U00012345') - assert ffi.new("wchar_t*")[0] == u+'\x00' - assert int(ffi.cast("wchar_t", 300)) == 300 - assert not bool(ffi.cast("wchar_t", 0)) - assert bool(ffi.cast("wchar_t", 1)) - assert bool(ffi.cast("wchar_t", 65535)) - if SIZE_OF_WCHAR > 2: - assert bool(ffi.cast("wchar_t", 65536)) - py.test.raises(TypeError, ffi.new, "wchar_t*", 32) - py.test.raises(TypeError, ffi.new, "wchar_t*", "foo") - # - p = ffi.new("wchar_t[]", [u+'a', u+'b', u+'\u1234']) - assert len(p) == 3 - assert p[0] == u+'a' - assert p[1] == u+'b' and type(p[1]) is unicode - assert p[2] == u+'\u1234' - p[0] = u+'x' - assert p[0] == u+'x' and type(p[0]) is unicode - p[1] = u+'\u1357' - assert p[1] == u+'\u1357' - p = ffi.new("wchar_t[]", u+"abcd") - assert len(p) == 5 - assert p[4] == u+'\x00' - p = ffi.new("wchar_t[]", u+"a\u1234b") - assert len(p) == 4 - assert p[1] == u+'\u1234' - # - p = ffi.new("wchar_t[]", u+'\U00023456') - if SIZE_OF_WCHAR == 2: - assert len(p) == 3 - assert p[0] == u+'\ud84d' - assert p[1] == u+'\udc56' - assert p[2] == u+'\x00' - else: - assert len(p) == 2 - assert p[0] == u+'\U00023456' - assert p[1] == u+'\x00' - # - p = ffi.new("wchar_t[4]", u+"ab") - assert len(p) == 4 - assert [p[i] for i in range(4)] == [u+'a', u+'b', u+'\x00', u+'\x00'] - p = ffi.new("wchar_t[2]", u+"ab") - assert len(p) == 2 - assert [p[i] for i in range(2)] == [u+'a', u+'b'] - py.test.raises(IndexError, ffi.new, "wchar_t[2]", u+"abc") - - def test_none_as_null_doesnt_work(self): - p = ffi.new("int*[1]") - assert p[0] is not None - assert p[0] != None - assert p[0] == ffi.NULL - assert repr(p[0]) == "<cdata 'int *' NULL>" - # - n = ffi.new("int*", 99) - p = ffi.new("int*[]", [n]) - assert p[0][0] == 99 - with pytest.raises(TypeError): - p[0] = None - p[0] = ffi.NULL - assert p[0] == ffi.NULL - - def test_float(self): - p = ffi.new("float[]", [-2, -2.5]) - assert p[0] == -2.0 - assert p[1] == -2.5 - p[1] += 17.75 - assert p[1] == 15.25 - # - p = ffi.new("float*", 15.75) - assert p[0] == 15.75 - py.test.raises(TypeError, int, p) - py.test.raises(TypeError, float, p) - p[0] = 0.0 - assert bool(p) is True - # - p = ffi.new("float*", 1.1) - f = p[0] - assert f != 1.1 # because of rounding effect - assert abs(f - 1.1) < 1E-7 - # - INF = 1E200 * 1E200 - assert 1E200 != INF - p[0] = 1E200 - assert p[0] == INF # infinite, not enough precision - - def test_struct_simple(self): - s = ffi.new("struct simple*") - assert s.a == s.b == s.c == 0 - s.b = -23 - assert s.b == -23 - with pytest.raises(OverflowError): - s.b = 32768 - # - s = ffi.new("struct simple*", [-2, -3]) - assert s.a == -2 - assert s.b == -3 - assert s.c == 0 - with pytest.raises((AttributeError, TypeError)): - del s.a - assert repr(s) == "<cdata 'struct simple *' owning %d bytes>" % ( - SIZE_OF_INT + 2 * SIZE_OF_SHORT) - # - py.test.raises(ValueError, ffi.new, "struct simple*", [1, 2, 3, 4]) - - def test_constructor_struct_from_dict(self): - s = ffi.new("struct simple*", {'b': 123, 'c': 456}) - assert s.a == 0 - assert s.b == 123 - assert s.c == 456 - py.test.raises(KeyError, ffi.new, "struct simple*", {'d': 456}) - - def test_struct_pointer(self): - s = ffi.new("struct simple*") - assert s[0].a == s[0].b == s[0].c == 0 - s[0].b = -23 - assert s[0].b == s.b == -23 - with pytest.raises(OverflowError): - s[0].b = -32769 - with pytest.raises(IndexError): - s[1] - - def test_struct_opaque(self): - py.test.raises(ffi.error, ffi.new, "struct baz*") - # should 'ffi.new("struct baz **") work? it used to, but it was - # not particularly useful... - py.test.raises(ffi.error, ffi.new, "struct baz**") - - def test_pointer_to_struct(self): - s = ffi.new("struct simple *") - s.a = -42 - assert s[0].a == -42 - p = ffi.new("struct simple **", s) - assert p[0].a == -42 - assert p[0][0].a == -42 - p[0].a = -43 - assert s.a == -43 - assert s[0].a == -43 - p[0][0].a = -44 - assert s.a == -44 - assert s[0].a == -44 - s.a = -45 - assert p[0].a == -45 - assert p[0][0].a == -45 - s[0].a = -46 - assert p[0].a == -46 - assert p[0][0].a == -46 - - def test_constructor_struct_of_array(self): - s = ffi.new("struct array *", [[10, 11], [b'a', b'b', b'c']]) - assert s.a[1] == 11 - assert s.b[2] == b'c' - s.b[1] = b'X' - assert s.b[0] == b'a' - assert s.b[1] == b'X' - assert s.b[2] == b'c' - - def test_recursive_struct(self): - s = ffi.new("struct recursive*") - t = ffi.new("struct recursive*") - s.value = 123 - s.next = t - t.value = 456 - assert s.value == 123 - assert s.next.value == 456 - - def test_union_simple(self): - u = ffi.new("union simple_u*") - assert u.a == u.b == u.c == 0 - u.b = -23 - assert u.b == -23 - assert u.a != 0 - with pytest.raises(OverflowError): - u.b = 32768 - # - u = ffi.new("union simple_u*", [-2]) - assert u.a == -2 - with pytest.raises((AttributeError, TypeError)): - del u.a - assert repr(u) == "<cdata 'union simple_u *' owning %d bytes>" % ( - SIZE_OF_INT,) - - def test_union_opaque(self): - py.test.raises(ffi.error, ffi.new, "union baz*") - # should 'ffi.new("union baz **") work? it used to, but it was - # not particularly useful... - py.test.raises(ffi.error, ffi.new, "union baz**") - - def test_union_initializer(self): - py.test.raises(TypeError, ffi.new, "union init_u*", b'A') - py.test.raises(TypeError, ffi.new, "union init_u*", 5) - py.test.raises(ValueError, ffi.new, "union init_u*", [b'A', 5]) - u = ffi.new("union init_u*", [b'A']) - assert u.a == b'A' - py.test.raises(TypeError, ffi.new, "union init_u*", [1005]) - u = ffi.new("union init_u*", {'b': 12345}) - assert u.b == 12345 - u = ffi.new("union init_u*", []) - assert u.a == b'\x00' - assert u.b == 0 - - def test_sizeof_type(self): - for c_type, expected_size in [ - ('char', 1), - ('unsigned int', 4), - ('char *', SIZE_OF_PTR), - ('int[5]', 20), - ('struct four_s', 12), - ('union four_u', 4), - ]: - size = ffi.sizeof(c_type) - assert size == expected_size, (size, expected_size, ctype) - - def test_sizeof_cdata(self): - assert ffi.sizeof(ffi.new("short*")) == SIZE_OF_PTR - assert ffi.sizeof(ffi.cast("short", 123)) == SIZE_OF_SHORT - # - a = ffi.new("int[]", [10, 11, 12, 13, 14]) - assert len(a) == 5 - assert ffi.sizeof(a) == 5 * SIZE_OF_INT - - def test_string_from_char_pointer(self): - x = ffi.new("char*", b"x") - assert str(x) == repr(x) - assert ffi.string(x) == b"x" - assert ffi.string(ffi.new("char*", b"\x00")) == b"" - py.test.raises(TypeError, ffi.new, "char*", unicode("foo")) - - def test_unicode_from_wchar_pointer(self): - self.check_wchar_t(ffi) - x = ffi.new("wchar_t*", u+"x") - assert unicode(x) == unicode(repr(x)) - assert ffi.string(x) == u+"x" - assert ffi.string(ffi.new("wchar_t*", u+"\x00")) == u+"" - - def test_string_from_char_array(self): - p = ffi.new("char[]", b"hello.") - p[5] = b'!' - assert ffi.string(p) == b"hello!" - p[6] = b'?' - assert ffi.string(p) == b"hello!?" - p[3] = b'\x00' - assert ffi.string(p) == b"hel" - assert ffi.string(p, 2) == b"he" - with pytest.raises(IndexError): - p[7] = b'X' - # - a = ffi.new("char[]", b"hello\x00world") - assert len(a) == 12 - p = ffi.cast("char *", a) - assert ffi.string(p) == b'hello' - - def test_string_from_wchar_array(self): - self.check_wchar_t(ffi) - assert ffi.string(ffi.cast("wchar_t", "x")) == u+"x" - assert ffi.string(ffi.cast("wchar_t", u+"x")) == u+"x" - x = ffi.cast("wchar_t", "x") - assert str(x) == repr(x) - assert ffi.string(x) == u+"x" - # - p = ffi.new("wchar_t[]", u+"hello.") - p[5] = u+'!' - assert ffi.string(p) == u+"hello!" - p[6] = u+'\u04d2' - assert ffi.string(p) == u+"hello!\u04d2" - p[3] = u+'\x00' - assert ffi.string(p) == u+"hel" - assert ffi.string(p, 123) == u+"hel" - with pytest.raises(IndexError): - p[7] = u+'X' - # - a = ffi.new("wchar_t[]", u+"hello\x00world") - assert len(a) == 12 - p = ffi.cast("wchar_t *", a) - assert ffi.string(p) == u+'hello' - assert ffi.string(p, 123) == u+'hello' - assert ffi.string(p, 5) == u+'hello' - assert ffi.string(p, 2) == u+'he' - - def test_fetch_const_char_p_field(self): - # 'const' is ignored so far, in the declaration of 'struct string' - t = ffi.new("const char[]", b"testing") - s = ffi.new("struct string*", [t]) - assert type(s.name) not in (bytes, str, unicode) - assert ffi.string(s.name) == b"testing" - with pytest.raises(TypeError): - s.name = None - s.name = ffi.NULL - assert s.name == ffi.NULL - - def test_fetch_const_wchar_p_field(self): - # 'const' is ignored so far - self.check_wchar_t(ffi) - t = ffi.new("const wchar_t[]", u+"testing") - s = ffi.new("struct ustring*", [t]) - assert type(s.name) not in (bytes, str, unicode) - assert ffi.string(s.name) == u+"testing" - s.name = ffi.NULL - assert s.name == ffi.NULL - - def test_voidp(self): - py.test.raises(TypeError, ffi.new, "void*") - p = ffi.new("void **") - assert p[0] == ffi.NULL - a = ffi.new("int[]", [10, 11, 12]) - p = ffi.new("void **", a) - vp = p[0] - with pytest.raises(TypeError): - vp[0] - py.test.raises(TypeError, ffi.new, "short **", a) - # - s = ffi.new("struct voidp *") - s.p = a # works - s.q = a # works - with pytest.raises(TypeError): - s.r = a # fails - b = ffi.cast("int *", a) - s.p = b # works - s.q = b # works - with pytest.raises(TypeError): - s.r = b # fails - - def test_functionptr_simple(self): - py.test.raises(TypeError, ffi.callback, "int(*)(int)", 0) - def cb(n): - return n + 1 - cb.__qualname__ = 'cb' - p = ffi.callback("int(*)(int)", cb) - res = p(41) # calling an 'int(*)(int)', i.e. a function pointer - assert res == 42 and type(res) is int - res = p(ffi.cast("int", -41)) - assert res == -40 and type(res) is int - assert repr(p).startswith( - "<cdata 'int(*)(int)' calling <function cb at 0x") - assert ffi.typeof(p) is ffi.typeof("int(*)(int)") - q = ffi.new("int(**)(int)", p) - assert repr(q) == "<cdata 'int(* *)(int)' owning %d bytes>" % ( - SIZE_OF_PTR) - with pytest.raises(TypeError): - q(43) - res = q[0](43) - assert res == 44 - q = ffi.cast("int(*)(int)", p) - assert repr(q).startswith("<cdata 'int(*)(int)' 0x") - res = q(45) - assert res == 46 - - def test_functionptr_advanced(self): - t = ffi.typeof("int(*(*)(int))(int)") - assert repr(t) == "<ctype '%s'>" % "int(*(*)(int))(int)" - - def test_functionptr_voidptr_return(self): - def cb(): - return ffi.NULL - p = ffi.callback("void*(*)()", cb) - res = p() - assert res is not None - assert res == ffi.NULL - int_ptr = ffi.new('int*') - void_ptr = ffi.cast('void*', int_ptr) - def cb(): - return void_ptr - p = ffi.callback("void*(*)()", cb) - res = p() - assert res == void_ptr - - def test_functionptr_intptr_return(self): - def cb(): - return ffi.NULL - p = ffi.callback("int*(*)()", cb) - res = p() - assert res == ffi.NULL - int_ptr = ffi.new('int*') - def cb(): - return int_ptr - p = ffi.callback("int*(*)()", cb) - res = p() - assert repr(res).startswith("<cdata 'int *' 0x") - assert res == int_ptr - int_array_ptr = ffi.new('int[1]') - def cb(): - return int_array_ptr - p = ffi.callback("int*(*)()", cb) - res = p() - assert repr(res).startswith("<cdata 'int *' 0x") - assert res == int_array_ptr - - def test_functionptr_void_return(self): - def foo(): - pass - foo_cb = ffi.callback("void foo()", foo) - result = foo_cb() - assert result is None - - def test_char_cast(self): - p = ffi.cast("int", b'\x01') - assert ffi.typeof(p) is ffi.typeof("int") - assert int(p) == 1 - p = ffi.cast("int", ffi.cast("char", b"a")) - assert int(p) == ord("a") - p = ffi.cast("int", ffi.cast("char", b"\x80")) - assert int(p) == 0x80 # "char" is considered unsigned in this case - p = ffi.cast("int", b"\x81") - assert int(p) == 0x81 - - def test_wchar_cast(self): - self.check_wchar_t(ffi) - p = ffi.cast("int", ffi.cast("wchar_t", u+'\u1234')) - assert int(p) == 0x1234 - p = ffi.cast("long long", ffi.cast("wchar_t", -1)) - if SIZE_OF_WCHAR == 2: # 2 bytes, unsigned - assert int(p) == 0xffff - elif (sys.platform.startswith('linux') and - platform.machine().startswith('x86')): # known to be signed - assert int(p) == -1 - else: # in general, it can be either signed or not - assert int(p) in [-1, 0xffffffff] # e.g. on arm, both cases occur - p = ffi.cast("int", u+'\u1234') - assert int(p) == 0x1234 - - def test_cast_array_to_charp(self): - a = ffi.new("short int[]", [0x1234, 0x5678]) - p = ffi.cast("char*", a) - data = b''.join([p[i] for i in range(4)]) - if sys.byteorder == 'little': - assert data == b'\x34\x12\x78\x56' - else: - assert data == b'\x12\x34\x56\x78' - - def test_cast_between_pointers(self): - a = ffi.new("short int[]", [0x1234, 0x5678]) - p = ffi.cast("short*", a) - p2 = ffi.cast("int*", p) - q = ffi.cast("char*", p2) - data = b''.join([q[i] for i in range(4)]) - if sys.byteorder == 'little': - assert data == b'\x34\x12\x78\x56' - else: - assert data == b'\x12\x34\x56\x78' - - def test_cast_pointer_and_int(self): - a = ffi.new("short int[]", [0x1234, 0x5678]) - l1 = ffi.cast("intptr_t", a) - p = ffi.cast("short*", a) - l2 = ffi.cast("intptr_t", p) - assert int(l1) == int(l2) != 0 - q = ffi.cast("short*", l1) - assert q == ffi.cast("short*", int(l1)) - assert q[0] == 0x1234 - assert int(ffi.cast("intptr_t", ffi.NULL)) == 0 - - def test_cast_functionptr_and_int(self): - def cb(n): - return n + 1 - a = ffi.callback("int(*)(int)", cb) - p = ffi.cast("void *", a) - assert p - b = ffi.cast("int(*)(int)", p) - assert b(41) == 42 - assert a == b - assert hash(a) == hash(b) - - def test_callback_crash(self): - def cb(n): - raise Exception - a = ffi.callback("int(*)(int)", cb, error=42) - res = a(1) # and the error reported to stderr - assert res == 42 - - def test_structptr_argument(self): - def cb(p): - return p[0].a * 1000 + p[0].b * 100 + p[1].a * 10 + p[1].b - a = ffi.callback("int(*)(struct ab[])", cb) - res = a([[5, 6], {'a': 7, 'b': 8}]) - assert res == 5678 - res = a([[5], {'b': 8}]) - assert res == 5008 - - def test_array_argument_as_list(self): - seen = [] - def cb(argv): - seen.append(ffi.string(argv[0])) - seen.append(ffi.string(argv[1])) - a = ffi.callback("void(*)(char *[])", cb) - a([ffi.new("char[]", b"foobar"), ffi.new("char[]", b"baz")]) - assert seen == [b"foobar", b"baz"] - - def test_cast_float(self): - a = ffi.cast("float", 12) - assert float(a) == 12.0 - a = ffi.cast("float", 12.5) - assert float(a) == 12.5 - a = ffi.cast("float", b"A") - assert float(a) == ord("A") - a = ffi.cast("int", 12.9) - assert int(a) == 12 - a = ffi.cast("char", 66.9 + 256) - assert ffi.string(a) == b"B" - # - a = ffi.cast("float", ffi.cast("int", 12)) - assert float(a) == 12.0 - a = ffi.cast("float", ffi.cast("double", 12.5)) - assert float(a) == 12.5 - a = ffi.cast("float", ffi.cast("char", b"A")) - assert float(a) == ord("A") - a = ffi.cast("int", ffi.cast("double", 12.9)) - assert int(a) == 12 - a = ffi.cast("char", ffi.cast("double", 66.9 + 256)) - assert ffi.string(a) == b"B" - - def test_enum(self): - # enum foq { A0, B0, CC0, D0 }; - assert ffi.string(ffi.cast("enum foq", 0)) == "cffiA0" - assert ffi.string(ffi.cast("enum foq", 2)) == "cffiCC0" - assert ffi.string(ffi.cast("enum foq", 3)) == "cffiD0" - assert ffi.string(ffi.cast("enum foq", 4)) == "4" - # enum bar { A1, B1=-2, CC1, D1, E1 }; - assert ffi.string(ffi.cast("enum bar", 0)) == "A1" - assert ffi.string(ffi.cast("enum bar", -2)) == "B1" - assert ffi.string(ffi.cast("enum bar", -1)) == "CC1" - assert ffi.string(ffi.cast("enum bar", 1)) == "E1" - assert ffi.cast("enum bar", -2) == ffi.cast("enum bar", -2) - assert ffi.cast("enum foq", 0) == ffi.cast("enum bar", 0) - assert ffi.cast("enum bar", 0) == ffi.cast("int", 0) - assert repr(ffi.cast("enum bar", -1)) == "<cdata 'enum bar' -1: CC1>" - assert repr(ffi.cast("enum foq", -1)) == ( # enums are unsigned, if - "<cdata 'enum foq' 4294967295>") or ( # they contain no neg value - sys.platform == "win32") # (but not on msvc) - # enum baz { A2=0x1000, B2=0x2000 }; - assert ffi.string(ffi.cast("enum baz", 0x1000)) == "A2" - assert ffi.string(ffi.cast("enum baz", 0x2000)) == "B2" - - def test_enum_in_struct(self): - # enum foo2 { A3, B3, C3, D3 }; - # struct bar_with_e { enum foo2 e; }; - s = ffi.new("struct bar_with_e *") - s.e = 0 - assert s.e == 0 - s.e = 3 - assert s.e == 3 - assert s[0].e == 3 - s[0].e = 2 - assert s.e == 2 - assert s[0].e == 2 - s.e = ffi.cast("enum foo2", -1) - assert s.e in (4294967295, -1) # two choices - assert s[0].e in (4294967295, -1) - s.e = s.e - with pytest.raises(TypeError): - s.e = 'B3' - with pytest.raises(TypeError): - s.e = '2' - with pytest.raises(TypeError): - s.e = '#2' - with pytest.raises(TypeError): - s.e = '#7' - - def test_enum_non_contiguous(self): - # enum noncont { A4, B4=42, C4 }; - assert ffi.string(ffi.cast("enum noncont", 0)) == "A4" - assert ffi.string(ffi.cast("enum noncont", 42)) == "B4" - assert ffi.string(ffi.cast("enum noncont", 43)) == "C4" - invalid_value = ffi.cast("enum noncont", 2) - assert int(invalid_value) == 2 - assert ffi.string(invalid_value) == "2" - - def test_enum_char_hex_oct(self): - # enum etypes {A5='!', B5='\'', C5=0x10, D5=010, E5=- 0x10, F5=-010}; - assert ffi.string(ffi.cast("enum etypes", ord('!'))) == "A5" - assert ffi.string(ffi.cast("enum etypes", ord("'"))) == "B5" - assert ffi.string(ffi.cast("enum etypes", 16)) == "C5" - assert ffi.string(ffi.cast("enum etypes", 8)) == "D5" - assert ffi.string(ffi.cast("enum etypes", -16)) == "E5" - assert ffi.string(ffi.cast("enum etypes", -8)) == "F5" - - def test_array_of_struct(self): - s = ffi.new("struct ab[1]") - with pytest.raises(AttributeError): - s.b - with pytest.raises(AttributeError): - s.b = 412 - s[0].b = 412 - assert s[0].b == 412 - with pytest.raises(IndexError): - s[1] - - def test_pointer_to_array(self): - p = ffi.new("int(**)[5]") - assert repr(p) == "<cdata 'int(* *)[5]' owning %d bytes>" % SIZE_OF_PTR - - def test_iterate_array(self): - a = ffi.new("char[]", b"hello") - assert list(a) == [b"h", b"e", b"l", b"l", b"o", b"\0"] - assert list(iter(a)) == [b"h", b"e", b"l", b"l", b"o", b"\0"] - # - py.test.raises(TypeError, iter, ffi.cast("char *", a)) - py.test.raises(TypeError, list, ffi.cast("char *", a)) - py.test.raises(TypeError, iter, ffi.new("int *")) - py.test.raises(TypeError, list, ffi.new("int *")) - - def test_offsetof(self): - # struct abc { int a, b, c; }; - assert ffi.offsetof("struct abc", "a") == 0 - assert ffi.offsetof("struct abc", "b") == 4 - assert ffi.offsetof("struct abc", "c") == 8 - - def test_offsetof_nested(self): - # struct nesting { struct abc d, e; }; - assert ffi.offsetof("struct nesting", "e") == 12 - py.test.raises(KeyError, ffi.offsetof, "struct nesting", "e.a") - assert ffi.offsetof("struct nesting", "e", "a") == 12 - assert ffi.offsetof("struct nesting", "e", "b") == 16 - assert ffi.offsetof("struct nesting", "e", "c") == 20 - - def test_offsetof_array(self): - assert ffi.offsetof("int[]", 51) == 51 * ffi.sizeof("int") - assert ffi.offsetof("int *", 51) == 51 * ffi.sizeof("int") - # struct array2 { int a, b; int c[99]; }; - assert ffi.offsetof("struct array2", "c") == 2 * ffi.sizeof("int") - assert ffi.offsetof("struct array2", "c", 0) == 2 * ffi.sizeof("int") - assert ffi.offsetof("struct array2", "c", 51) == 53 * ffi.sizeof("int") - - def test_alignof(self): - # struct align { char a; short b; char c; }; - assert ffi.alignof("int") == 4 - assert ffi.alignof("double") in (4, 8) - assert ffi.alignof("struct align") == 2 - - def test_bitfield(self): - # struct bitfield { int a:10, b:20, c:3; }; - assert ffi.sizeof("struct bitfield") == 8 - s = ffi.new("struct bitfield *") - s.a = 511 - with pytest.raises(OverflowError): - s.a = 512 - with pytest.raises(OverflowError): - s[0].a = 512 - assert s.a == 511 - s.a = -512 - with pytest.raises(OverflowError): - s.a = -513 - with pytest.raises(OverflowError): - s[0].a = -513 - assert s.a == -512 - s.c = 3 - assert s.c == 3 - with pytest.raises(OverflowError): - s.c = 4 - with pytest.raises(OverflowError): - s[0].c = 4 - s.c = -4 - assert s.c == -4 - - def test_bitfield_enum(self): - # typedef enum { AA1, BB1, CC1 } foo_e_t; - # typedef struct { foo_e_t f:2; } bfenum_t; - if sys.platform == "win32": - py.test.skip("enums are not unsigned") - s = ffi.new("bfenum_t *") - s.f = 2 - assert s.f == 2 - - def test_anonymous_struct(self): - # typedef struct { int a; } anon_foo_t; - # typedef struct { char b, c; } anon_bar_t; - f = ffi.new("anon_foo_t *", [12345]) - b = ffi.new("anon_bar_t *", [b"B", b"C"]) - assert f.a == 12345 - assert b.b == b"B" - assert b.c == b"C" - assert repr(b).startswith("<cdata 'anon_bar_t *'") - - def test_struct_with_two_usages(self): - # typedef struct named_foo_s { int a; } named_foo_t, *named_foo_p; - # typedef struct { int a; } unnamed_foo_t, *unnamed_foo_p; - f = ffi.new("named_foo_t *", [12345]) - ps = ffi.new("named_foo_p[]", [f]) - f = ffi.new("unnamed_foo_t *", [12345]) - ps = ffi.new("unnamed_foo_p[]", [f]) - - def test_pointer_arithmetic(self): - s = ffi.new("short[]", list(range(100, 110))) - p = ffi.cast("short *", s) - assert p[2] == 102 - assert p+1 == p+1 - assert p+1 != p+0 - assert p == p+0 == p-0 - assert (p+1)[0] == 101 - assert (p+19)[-10] == 109 - assert (p+5) - (p+1) == 4 - assert p == s+0 - assert p+1 == s+1 - - def test_pointer_comparison(self): - s = ffi.new("short[]", list(range(100))) - p = ffi.cast("short *", s) - assert (p < s) is False - assert (p <= s) is True - assert (p == s) is True - assert (p != s) is False - assert (p > s) is False - assert (p >= s) is True - assert (s < p) is False - assert (s <= p) is True - assert (s == p) is True - assert (s != p) is False - assert (s > p) is False - assert (s >= p) is True - q = p + 1 - assert (q < s) is False - assert (q <= s) is False - assert (q == s) is False - assert (q != s) is True - assert (q > s) is True - assert (q >= s) is True - assert (s < q) is True - assert (s <= q) is True - assert (s == q) is False - assert (s != q) is True - assert (s > q) is False - assert (s >= q) is False - assert (q < p) is False - assert (q <= p) is False - assert (q == p) is False - assert (q != p) is True - assert (q > p) is True - assert (q >= p) is True - assert (p < q) is True - assert (p <= q) is True - assert (p == q) is False - assert (p != q) is True - assert (p > q) is False - assert (p >= q) is False - # - assert (None == s) is False - assert (None != s) is True - assert (s == None) is False - assert (s != None) is True - assert (None == q) is False - assert (None != q) is True - assert (q == None) is False - assert (q != None) is True - - def test_integer_comparison(self): - x = ffi.cast("int", 123) - y = ffi.cast("int", 456) - assert x < y - # - z = ffi.cast("double", 78.9) - assert x > z - assert y > z - - def test_ffi_buffer_ptr(self): - a = ffi.new("short *", 100) - try: - b = ffi.buffer(a) - except NotImplementedError as e: - py.test.skip(str(e)) - content = b[:] - assert len(content) == len(b) == 2 - if sys.byteorder == 'little': - assert content == b'\x64\x00' - assert b[0] == b'\x64' - b[0] = b'\x65' - else: - assert content == b'\x00\x64' - assert b[1] == b'\x64' - b[1] = b'\x65' - assert a[0] == 101 - - def test_ffi_buffer_array(self): - a = ffi.new("int[]", list(range(100, 110))) - try: - b = ffi.buffer(a) - except NotImplementedError as e: - py.test.skip(str(e)) - content = b[:] - if sys.byteorder == 'little': - assert content.startswith(b'\x64\x00\x00\x00\x65\x00\x00\x00') - b[4] = b'\x45' - else: - assert content.startswith(b'\x00\x00\x00\x64\x00\x00\x00\x65') - b[7] = b'\x45' - assert len(content) == 4 * 10 - assert a[1] == 0x45 - - def test_ffi_buffer_ptr_size(self): - a = ffi.new("short *", 0x4243) - try: - b = ffi.buffer(a, 1) - except NotImplementedError as e: - py.test.skip(str(e)) - content = b[:] - assert len(content) == 1 - if sys.byteorder == 'little': - assert content == b'\x43' - b[0] = b'\x62' - assert a[0] == 0x4262 - else: - assert content == b'\x42' - b[0] = b'\x63' - assert a[0] == 0x6343 - - def test_ffi_buffer_array_size(self): - a1 = ffi.new("int[]", list(range(100, 110))) - a2 = ffi.new("int[]", list(range(100, 115))) - try: - ffi.buffer(a1) - except NotImplementedError as e: - py.test.skip(str(e)) - assert ffi.buffer(a1)[:] == ffi.buffer(a2, 4*10)[:] - - def test_ffi_buffer_with_file(self): - import tempfile, os, array - fd, filename = tempfile.mkstemp() - f = os.fdopen(fd, 'r+b') - a = ffi.new("int[]", list(range(1005))) - try: - ffi.buffer(a, 512) - except NotImplementedError as e: - py.test.skip(str(e)) - f.write(ffi.buffer(a, 1000 * ffi.sizeof("int"))) - f.seek(0) - assert f.read() == arraytostring(array.array('i', range(1000))) - f.seek(0) - b = ffi.new("int[]", 1005) - f.readinto(ffi.buffer(b, 1000 * ffi.sizeof("int"))) - assert list(a)[:1000] + [0] * (len(a)-1000) == list(b) - f.close() - os.unlink(filename) - - def test_ffi_buffer_with_io(self): - import io, array - f = io.BytesIO() - a = ffi.new("int[]", list(range(1005))) - try: - ffi.buffer(a, 512) - except NotImplementedError as e: - py.test.skip(str(e)) - f.write(ffi.buffer(a, 1000 * ffi.sizeof("int"))) - f.seek(0) - assert f.read() == arraytostring(array.array('i', range(1000))) - f.seek(0) - b = ffi.new("int[]", 1005) - f.readinto(ffi.buffer(b, 1000 * ffi.sizeof("int"))) - assert list(a)[:1000] + [0] * (len(a)-1000) == list(b) - f.close() - - def test_array_in_struct(self): - # struct array { int a[2]; char b[3]; }; - p = ffi.new("struct array *") - p.a[1] = 5 - assert p.a[1] == 5 - assert repr(p.a).startswith("<cdata 'int[2]' 0x") - - def test_struct_containing_array_varsize_workaround(self): - if sys.platform == "win32": - py.test.skip("array of length 0 not supported") - # struct array0 { int len; short data[0]; }; - p = ffi.new("char[]", ffi.sizeof("struct array0") + 7 * SIZE_OF_SHORT) - q = ffi.cast("struct array0 *", p) - assert q.len == 0 - # 'q.data' gets not a 'short[0]', but just a 'short *' instead - assert repr(q.data).startswith("<cdata 'short *' 0x") - assert q.data[6] == 0 - q.data[6] = 15 - assert q.data[6] == 15 - - def test_new_struct_containing_array_varsize(self): - py.test.skip("later?") - ffi.cdef("struct foo_s { int len; short data[]; };") - p = ffi.new("struct foo_s *", 10) # a single integer is the length - assert p.len == 0 - assert p.data[9] == 0 - with pytest.raises(IndexError): - p.data[10] - - def test_ffi_typeof_getcname(self): - assert ffi.getctype("int") == "int" - assert ffi.getctype("int", 'x') == "int x" - assert ffi.getctype("int*") == "int *" - assert ffi.getctype("int*", '') == "int *" - assert ffi.getctype("int*", 'x') == "int * x" - assert ffi.getctype("int", '*') == "int *" - assert ffi.getctype("int", ' * x ') == "int * x" - assert ffi.getctype(ffi.typeof("int*"), '*') == "int * *" - assert ffi.getctype("int", '[5]') == "int[5]" - assert ffi.getctype("int[5]", '[6]') == "int[6][5]" - assert ffi.getctype("int[5]", '(*)') == "int(*)[5]" - # special-case for convenience: automatically put '()' around '*' - assert ffi.getctype("int[5]", '*') == "int(*)[5]" - assert ffi.getctype("int[5]", '*foo') == "int(*foo)[5]" - assert ffi.getctype("int[5]", ' ** foo ') == "int(** foo)[5]" - - def test_array_of_func_ptr(self): - f = ffi.cast("int(*)(int)", 42) - assert f != ffi.NULL - py.test.raises(ffi.error, ffi.cast, "int(int)", 42) - py.test.raises(ffi.error, ffi.new, "int([5])(int)") - a = ffi.new("int(*[5])(int)", [f]) - assert ffi.getctype(ffi.typeof(a)) == "int(*[5])(int)" - assert len(a) == 5 - assert a[0] == f - assert a[1] == ffi.NULL - py.test.raises(TypeError, ffi.cast, "int(*)(int)[5]", 0) - # - def cb(n): - return n + 1 - f = ffi.callback("int(*)(int)", cb) - a = ffi.new("int(*[5])(int)", [f, f]) - assert a[1](42) == 43 - - def test_callback_as_function_argument(self): - # In C, function arguments can be declared with a function type, - # which is automatically replaced with the ptr-to-function type. - def cb(a, b): - return chr(ord(a) + ord(b)).encode() - f = ffi.callback("char cb(char, char)", cb) - assert f(b'A', b'\x01') == b'B' - def g(callback): - return callback(b'A', b'\x01') - g = ffi.callback("char g(char cb(char, char))", g) - assert g(f) == b'B' - - def test_vararg_callback(self): - py.test.skip("callback with '...'") - def cb(i, va_list): - j = ffi.va_arg(va_list, "int") - k = ffi.va_arg(va_list, "long long") - return i * 2 + j * 3 + k * 5 - f = ffi.callback("long long cb(long i, ...)", cb) - res = f(10, ffi.cast("int", 100), ffi.cast("long long", 1000)) - assert res == 20 + 300 + 5000 - - def test_callback_decorator(self): - # - @ffi.callback("long(long, long)", error=42) - def cb(a, b): - return a - b - # - assert cb(-100, -10) == -90 - sz = ffi.sizeof("long") - assert cb((1 << (sz*8-1)) - 1, -10) == 42 - - def test_anonymous_enum(self): - # typedef enum { Value0 = 0 } e_t, *pe_t; - assert ffi.getctype("e_t*") == 'e_t *' - assert ffi.getctype("pe_t") == 'e_t *' - assert ffi.getctype("foo_e_t*") == 'foo_e_t *' - - def test_new_ctype(self): - p = ffi.new("int *") - py.test.raises(TypeError, ffi.new, p) - p = ffi.new(ffi.typeof("int *"), 42) - assert p[0] == 42 - - def test_enum_with_non_injective_mapping(self): - # enum e_noninj { AA3=0, BB3=0, CC3=0, DD3=0 }; - e = ffi.cast("enum e_noninj", 0) - assert ffi.string(e) == "AA3" # pick the first one arbitrarily - - def test_enum_refer_previous_enum_value(self): - # enum e_prev { AA4, BB4=2, CC4=4, DD4=BB4, EE4, FF4=CC4, GG4=FF4 }; - assert ffi.string(ffi.cast("enum e_prev", 2)) == "BB4" - assert ffi.string(ffi.cast("enum e_prev", 3)) == "EE4" - assert ffi.sizeof("char[DD4]") == 2 - assert ffi.sizeof("char[EE4]") == 3 - assert ffi.sizeof("char[FF4]") == 4 - assert ffi.sizeof("char[GG4]") == 4 - - def test_nested_anonymous_struct(self): - # struct nested_anon { - # struct { int a, b; }; - # union { int c, d; }; - # }; - assert ffi.sizeof("struct nested_anon") == 3 * SIZE_OF_INT - p = ffi.new("struct nested_anon *", [1, 2, 3]) - assert p.a == 1 - assert p.b == 2 - assert p.c == 3 - assert p.d == 3 - p.d = 17 - assert p.c == 17 - p.b = 19 - assert p.a == 1 - assert p.b == 19 - assert p.c == 17 - assert p.d == 17 - p = ffi.new("struct nested_anon *", {'b': 12, 'd': 14}) - assert p.a == 0 - assert p.b == 12 - assert p.c == 14 - assert p.d == 14 - - def test_nested_field_offset_align(self): - # struct nested_field_ofs_s { - # struct { int a; char b; }; - # union { char c; }; - # }; - assert ffi.offsetof("struct nested_field_ofs_s", "c") == 2 * SIZE_OF_INT - assert ffi.sizeof("struct nested_field_ofs_s") == 3 * SIZE_OF_INT - - def test_nested_anonymous_union(self): - # union nested_anon_u { - # struct { int a, b; }; - # union { int c, d; }; - # }; - assert ffi.sizeof("union nested_anon_u") == 2 * SIZE_OF_INT - p = ffi.new("union nested_anon_u *", [5]) - assert p.a == 5 - assert p.b == 0 - assert p.c == 5 - assert p.d == 5 - p.d = 17 - assert p.c == 17 - assert p.a == 17 - p.b = 19 - assert p.a == 17 - assert p.b == 19 - assert p.c == 17 - assert p.d == 17 - p = ffi.new("union nested_anon_u *", {'d': 14}) - assert p.a == 14 - assert p.b == 0 - assert p.c == 14 - assert p.d == 14 - p = ffi.new("union nested_anon_u *", {'b': 12}) - assert p.a == 0 - assert p.b == 12 - assert p.c == 0 - assert p.d == 0 - # we cannot specify several items in the dict, even though - # in theory in this particular case it would make sense - # to give both 'a' and 'b' - - def test_cast_to_array_type(self): - p = ffi.new("int[4]", [-5]) - q = ffi.cast("int[3]", p) - assert q[0] == -5 - assert repr(q).startswith("<cdata 'int[3]' 0x") - - def test_gc(self): - p = ffi.new("int *", 123) - seen = [] - def destructor(p1): - assert p1 is p - assert p1[0] == 123 - seen.append(1) - q = ffi.gc(p, destructor=destructor) - import gc; gc.collect() - assert seen == [] - del q - import gc; gc.collect(); gc.collect(); gc.collect() - assert seen == [1] - - def test_gc_2(self): - p = ffi.new("int *", 123) - seen = [] - q1 = ffi.gc(p, lambda p: seen.append(1)) - q2 = ffi.gc(q1, lambda p: seen.append(2)) - import gc; gc.collect() - assert seen == [] - del q1, q2 - import gc; gc.collect(); gc.collect(); gc.collect(); gc.collect() - assert seen == [2, 1] - - def test_gc_3(self): - p = ffi.new("int *", 123) - r = ffi.new("int *", 123) - seen = [] - seen_r = [] - q1 = ffi.gc(p, lambda p: seen.append(1)) - s1 = ffi.gc(r, lambda r: seen_r.append(4)) - q2 = ffi.gc(q1, lambda p: seen.append(2)) - s2 = ffi.gc(s1, lambda r: seen_r.append(5)) - q3 = ffi.gc(q2, lambda p: seen.append(3)) - import gc; gc.collect() - assert seen == [] - assert seen_r == [] - del q1, q2, q3, s2, s1 - import gc; gc.collect(); gc.collect(); gc.collect(); gc.collect() - assert seen == [3, 2, 1] - assert seen_r == [5, 4] - - def test_gc_4(self): - p = ffi.new("int *", 123) - seen = [] - q1 = ffi.gc(p, lambda p: seen.append(1)) - q2 = ffi.gc(q1, lambda p: seen.append(2)) - q3 = ffi.gc(q2, lambda p: seen.append(3)) - import gc; gc.collect() - assert seen == [] - del q1, q3 # q2 remains, and has a hard ref to q1 - import gc; gc.collect(); gc.collect(); gc.collect() - assert seen == [3] - - def test_release(self): - p = ffi.new("int[]", 123) - ffi.release(p) - # here, reading p[0] might give garbage or segfault... - ffi.release(p) # no effect - - def test_release_new_allocator(self): - seen = [] - def myalloc(size): - seen.append(size) - return ffi.new("char[]", b"X" * size) - def myfree(raw): - seen.append(raw) - alloc2 = ffi.new_allocator(alloc=myalloc, free=myfree) - p = alloc2("int[]", 15) - assert seen == [15 * 4] - ffi.release(p) - assert seen == [15 * 4, p] - ffi.release(p) # no effect - assert seen == [15 * 4, p] - # - del seen[:] - p = alloc2("struct ab *") - assert seen == [2 * 4] - ffi.release(p) - assert seen == [2 * 4, p] - ffi.release(p) # no effect - assert seen == [2 * 4, p] - - def test_CData_CType(self): - assert isinstance(ffi.cast("int", 0), ffi.CData) - assert isinstance(ffi.new("int *"), ffi.CData) - assert not isinstance(ffi.typeof("int"), ffi.CData) - assert not isinstance(ffi.cast("int", 0), ffi.CType) - assert not isinstance(ffi.new("int *"), ffi.CType) - - def test_CData_CType_2(self): - assert isinstance(ffi.typeof("int"), ffi.CType) - - def test_bool(self): - assert int(ffi.cast("_Bool", 0.1)) == 1 - assert int(ffi.cast("_Bool", -0.0)) == 0 - assert int(ffi.cast("_Bool", b'\x02')) == 1 - assert int(ffi.cast("_Bool", b'\x00')) == 0 - assert int(ffi.cast("_Bool", b'\x80')) == 1 - assert ffi.new("_Bool *", False)[0] == 0 - assert ffi.new("_Bool *", 1)[0] == 1 - py.test.raises(OverflowError, ffi.new, "_Bool *", 2) - py.test.raises(TypeError, ffi.string, ffi.cast("_Bool", 2)) - - def test_addressof(self): - p = ffi.new("struct ab *") - a = ffi.addressof(p[0]) - assert repr(a).startswith("<cdata 'struct ab *' 0x") - assert a == p - py.test.raises(TypeError, ffi.addressof, p) - py.test.raises((AttributeError, TypeError), ffi.addressof, 5) - py.test.raises(TypeError, ffi.addressof, ffi.cast("int", 5)) - - def test_addressof_field(self): - p = ffi.new("struct ab *") - b = ffi.addressof(p[0], 'b') - assert repr(b).startswith("<cdata 'int *' 0x") - assert int(ffi.cast("uintptr_t", b)) == ( - int(ffi.cast("uintptr_t", p)) + ffi.sizeof("int")) - assert b == ffi.addressof(p, 'b') - assert b != ffi.addressof(p, 'a') - - def test_addressof_field_nested(self): - # struct nesting { struct abc d, e; }; - p = ffi.new("struct nesting *") - py.test.raises(KeyError, ffi.addressof, p[0], 'e.b') - a = ffi.addressof(p[0], 'e', 'b') - assert int(ffi.cast("uintptr_t", a)) == ( - int(ffi.cast("uintptr_t", p)) + - ffi.sizeof("struct abc") + ffi.sizeof("int")) - - def test_addressof_anonymous_struct(self): - # typedef struct { int a; } anon_foo_t; - p = ffi.new("anon_foo_t *") - a = ffi.addressof(p[0]) - assert a == p - - def test_addressof_array(self): - p = ffi.new("int[52]") - p0 = ffi.addressof(p) - assert p0 == p - assert ffi.typeof(p0) is ffi.typeof("int(*)[52]") - py.test.raises(TypeError, ffi.addressof, p0) - # - p1 = ffi.addressof(p, 25) - assert ffi.typeof(p1) is ffi.typeof("int *") - assert (p1 - p) == 25 - assert ffi.addressof(p, 0) == p - - def test_addressof_pointer(self): - array = ffi.new("int[50]") - p = ffi.cast("int *", array) - py.test.raises(TypeError, ffi.addressof, p) - assert ffi.addressof(p, 0) == p - assert ffi.addressof(p, 25) == p + 25 - assert ffi.typeof(ffi.addressof(p, 25)) == ffi.typeof(p) - # - array = ffi.new("struct ab[50]") - p = ffi.cast("int *", array) - py.test.raises(TypeError, ffi.addressof, p) - assert ffi.addressof(p, 0) == p - assert ffi.addressof(p, 25) == p + 25 - assert ffi.typeof(ffi.addressof(p, 25)) == ffi.typeof(p) - - def test_addressof_array_in_struct(self): - # struct abc50 { int a, b; int c[50]; }; - p = ffi.new("struct abc50 *") - p1 = ffi.addressof(p, "c", 25) - assert ffi.typeof(p1) is ffi.typeof("int *") - assert p1 == ffi.cast("int *", p) + 27 - assert ffi.addressof(p, "c") == ffi.cast("int *", p) + 2 - assert ffi.addressof(p, "c", 0) == ffi.cast("int *", p) + 2 - p2 = ffi.addressof(p, 1) - assert ffi.typeof(p2) is ffi.typeof("struct abc50 *") - assert p2 == p + 1 - - def test_multiple_independent_structs(self): - CDEF2 = "struct ab { int x; };" - ffi2 = cffi.FFI(); ffi2.cdef(CDEF2) - outputfilename = recompile(ffi2, "test_multiple_independent_structs", - CDEF2, tmpdir=str(udir)) - module = imp.load_dynamic("test_multiple_independent_structs", - outputfilename) - ffi1 = module.ffi - foo1 = ffi1.new("struct ab *", [10]) - foo2 = ffi .new("struct ab *", [20, 30]) - assert foo1.x == 10 - assert foo2.a == 20 - assert foo2.b == 30 - - def test_include_struct_union_enum_typedef(self): - ffi1, CCODE = construction_params - ffi2 = cffi.FFI() - ffi2.include(ffi1) - outputfilename = recompile(ffi2, - "test_include_struct_union_enum_typedef", - CCODE, tmpdir=str(udir)) - module = imp.load_dynamic("test_include_struct_union_enum_typedef", - outputfilename) - ffi2 = module.ffi - # - p = ffi2.new("struct nonpacked *", [b'A', -43141]) - assert p.a == b'A' - assert p.b == -43141 - # - p = ffi.new("union simple_u *", [-52525]) - assert p.a == -52525 - # - p = ffi.cast("enum foq", 2) - assert ffi.string(p) == "cffiCC0" - assert ffi2.sizeof("char[cffiCC0]") == 2 - # - p = ffi.new("anon_foo_t *", [-52526]) - assert p.a == -52526 - p = ffi.new("named_foo_p", [-52527]) - assert p.a == -52527 - - def test_struct_packed(self): - # struct nonpacked { char a; int b; }; - # struct is_packed { char a; int b; } __attribute__((packed)); - assert ffi.sizeof("struct nonpacked") == 8 - assert ffi.sizeof("struct is_packed") == 5 - assert ffi.alignof("struct nonpacked") == 4 - assert ffi.alignof("struct is_packed") == 1 - s = ffi.new("struct is_packed[2]") - s[0].b = 42623381 - s[0].a = b'X' - s[1].b = -4892220 - s[1].a = b'Y' - assert s[0].b == 42623381 - assert s[0].a == b'X' - assert s[1].b == -4892220 - assert s[1].a == b'Y' - - def test_not_supported_bitfield_in_result(self): - # struct ints_and_bitfield { int a,b,c,d,e; int x:1; }; - e = py.test.raises(NotImplementedError, ffi.callback, - "struct ints_and_bitfield foo(void)", lambda: 42) - assert str(e.value) == ("struct ints_and_bitfield(*)(): " - "callback with unsupported argument or return type or with '...'") - - def test_inspecttype(self): - assert ffi.typeof("long").kind == "primitive" - assert ffi.typeof("long(*)(long, long**, ...)").cname == ( - "long(*)(long, long * *, ...)") - assert ffi.typeof("long(*)(long, long**, ...)").ellipsis is True - - def test_new_handle(self): - o = [2, 3, 4] - p = ffi.new_handle(o) - assert ffi.typeof(p) == ffi.typeof("void *") - assert ffi.from_handle(p) is o - assert ffi.from_handle(ffi.cast("char *", p)) is o - py.test.raises(RuntimeError, ffi.from_handle, ffi.NULL) - - def test_struct_array_no_length(self): - # struct array_no_length { int x; int a[]; }; - p = ffi.new("struct array_no_length *", [100, [200, 300, 400]]) - assert p.x == 100 - assert ffi.typeof(p.a) is ffi.typeof("int[]") # length available - assert p.a[0] == 200 - assert p.a[1] == 300 - assert p.a[2] == 400 - assert len(p.a) == 3 - assert list(p.a) == [200, 300, 400] - q = ffi.cast("struct array_no_length *", p) - assert ffi.typeof(q.a) is ffi.typeof("int *") # no length available - assert q.a[0] == 200 - assert q.a[1] == 300 - assert q.a[2] == 400 - py.test.raises(TypeError, len, q.a) - py.test.raises(TypeError, list, q.a) - - def test_all_primitives(self): - assert set(PRIMITIVE_TO_INDEX) == set([ - "char", - "short", - "int", - "long", - "long long", - "signed char", - "unsigned char", - "unsigned short", - "unsigned int", - "unsigned long", - "unsigned long long", - "float", - "double", - "long double", - "wchar_t", - "char16_t", - "char32_t", - "_Bool", - "int8_t", - "uint8_t", - "int16_t", - "uint16_t", - "int32_t", - "uint32_t", - "int64_t", - "uint64_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", - "intptr_t", - "uintptr_t", - "intmax_t", - "uintmax_t", - "ptrdiff_t", - "size_t", - "ssize_t", - 'float _Complex', - 'double _Complex', - ]) - for name in PRIMITIVE_TO_INDEX: - x = ffi.sizeof(name) - assert 1 <= x <= 16 - - def test_emit_c_code(self): - ffi = cffi.FFI() - ffi.set_source("foobar", "??") - c_file = str(udir.join('test_emit_c_code')) - ffi.emit_c_code(c_file) - assert os.path.isfile(c_file) - - def test_import_from_lib(self): - ffi2 = cffi.FFI() - ffi2.cdef("int myfunc(int); extern int myvar;\n#define MYFOO ...\n") - outputfilename = recompile(ffi2, "_test_import_from_lib", - "int myfunc(int x) { return x + 1; }\n" - "int myvar = -5;\n" - "#define MYFOO 42", tmpdir=str(udir)) - imp.load_dynamic("_test_import_from_lib", outputfilename) - from _test_import_from_lib.lib import myfunc, myvar, MYFOO - assert MYFOO == 42 - assert myfunc(43) == 44 - assert myvar == -5 # but can't be changed, so not very useful - with pytest.raises(ImportError): - from _test_import_from_lib.lib import bar - d = {} - exec("from _test_import_from_lib.lib import *", d) - assert (set(key for key in d if not key.startswith('_')) == - set(['myfunc', 'MYFOO'])) - # - # also test "import *" on the module itself, which should be - # equivalent to "import ffi, lib" - d = {} - exec("from _test_import_from_lib import *", d) - assert (sorted([x for x in d.keys() if not x.startswith('__')]) == - ['ffi', 'lib']) - - def test_char16_t(self): - x = ffi.new("char16_t[]", 5) - assert len(x) == 5 and ffi.sizeof(x) == 10 - x[2] = u+'\u1324' - assert x[2] == u+'\u1324' - y = ffi.new("char16_t[]", u+'\u1234\u5678') - assert len(y) == 3 - assert list(y) == [u+'\u1234', u+'\u5678', u+'\x00'] - assert ffi.string(y) == u+'\u1234\u5678' - z = ffi.new("char16_t[]", u+'\U00012345') - assert len(z) == 3 - assert list(z) == [u+'\ud808', u+'\udf45', u+'\x00'] - assert ffi.string(z) == u+'\U00012345' - - def test_char32_t(self): - x = ffi.new("char32_t[]", 5) - assert len(x) == 5 and ffi.sizeof(x) == 20 - x[3] = u+'\U00013245' - assert x[3] == u+'\U00013245' - y = ffi.new("char32_t[]", u+'\u1234\u5678') - assert len(y) == 3 - assert list(y) == [u+'\u1234', u+'\u5678', u+'\x00'] - z = ffi.new("char32_t[]", u+'\U00012345') - assert len(z) == 2 - assert list(z) == [u+'\U00012345', u+'\x00'] # maybe a 2-unichars strin - assert ffi.string(z) == u+'\U00012345' diff --git a/testing/cffi1/test_parse_c_type.py b/testing/cffi1/test_parse_c_type.py deleted file mode 100644 index a9f5fcb..0000000 --- a/testing/cffi1/test_parse_c_type.py +++ /dev/null @@ -1,372 +0,0 @@ -import sys, re, os, py -import cffi -from cffi import cffi_opcode - -if '__pypy__' in sys.builtin_module_names: - try: - # pytest >= 4.0 - py.test.skip("not available on pypy", allow_module_level=True) - except TypeError: - # older pytest - py.test.skip("not available on pypy") - -cffi_dir = os.path.dirname(cffi_opcode.__file__) - -r_macro = re.compile(r"#define \w+[(][^\n]*|#include [^\n]*") -r_define = re.compile(r"(#define \w+) [^\n]*") -r_ifdefs = re.compile(r"(#ifdef |#endif)[^\n]*") -header = open(os.path.join(cffi_dir, 'parse_c_type.h')).read() -header = r_macro.sub(r"", header) -header = r_define.sub(r"\1 ...", header) -header = r_ifdefs.sub(r"", header) - -ffi = cffi.FFI() -ffi.cdef(header) - -lib = ffi.verify( - open(os.path.join(cffi_dir, '..', 'c', 'parse_c_type.c')).read() + """ -static const char *get_common_type(const char *search, size_t search_len) { - return NULL; -} -""", include_dirs=[cffi_dir]) - -class ParseError(Exception): - pass - -struct_names = ["bar_s", "foo", "foo_", "foo_s", "foo_s1", "foo_s12"] -assert struct_names == sorted(struct_names) - -enum_names = ["ebar_s", "efoo", "efoo_", "efoo_s", "efoo_s1", "efoo_s12"] -assert enum_names == sorted(enum_names) - -identifier_names = ["id", "id0", "id05", "id05b", "tail"] -assert identifier_names == sorted(identifier_names) - -global_names = ["FIVE", "NEG", "ZERO"] -assert global_names == sorted(global_names) - -ctx = ffi.new("struct _cffi_type_context_s *") -c_struct_names = [ffi.new("char[]", _n.encode('ascii')) for _n in struct_names] -ctx_structs = ffi.new("struct _cffi_struct_union_s[]", len(struct_names)) -for _i in range(len(struct_names)): - ctx_structs[_i].name = c_struct_names[_i] -ctx_structs[3].flags = lib._CFFI_F_UNION -ctx.struct_unions = ctx_structs -ctx.num_struct_unions = len(struct_names) - -c_enum_names = [ffi.new("char[]", _n.encode('ascii')) for _n in enum_names] -ctx_enums = ffi.new("struct _cffi_enum_s[]", len(enum_names)) -for _i in range(len(enum_names)): - ctx_enums[_i].name = c_enum_names[_i] -ctx.enums = ctx_enums -ctx.num_enums = len(enum_names) - -c_identifier_names = [ffi.new("char[]", _n.encode('ascii')) - for _n in identifier_names] -ctx_identifiers = ffi.new("struct _cffi_typename_s[]", len(identifier_names)) -for _i in range(len(identifier_names)): - ctx_identifiers[_i].name = c_identifier_names[_i] - ctx_identifiers[_i].type_index = 100 + _i -ctx.typenames = ctx_identifiers -ctx.num_typenames = len(identifier_names) - -@ffi.callback("int(unsigned long long *)") -def fetch_constant_five(p): - p[0] = 5 - return 0 -@ffi.callback("int(unsigned long long *)") -def fetch_constant_zero(p): - p[0] = 0 - return 1 -@ffi.callback("int(unsigned long long *)") -def fetch_constant_neg(p): - p[0] = 123321 - return 1 - -ctx_globals = ffi.new("struct _cffi_global_s[]", len(global_names)) -c_glob_names = [ffi.new("char[]", _n.encode('ascii')) for _n in global_names] -for _i, _fn in enumerate([fetch_constant_five, - fetch_constant_neg, - fetch_constant_zero]): - ctx_globals[_i].name = c_glob_names[_i] - ctx_globals[_i].address = _fn - ctx_globals[_i].type_op = ffi.cast("_cffi_opcode_t", - cffi_opcode.OP_CONSTANT_INT if _i != 1 - else cffi_opcode.OP_ENUM) -ctx.globals = ctx_globals -ctx.num_globals = len(global_names) - - -def parse(input): - out = ffi.new("_cffi_opcode_t[]", 100) - info = ffi.new("struct _cffi_parse_info_s *") - info.ctx = ctx - info.output = out - info.output_size = len(out) - for j in range(len(out)): - out[j] = ffi.cast("void *", -424242) - res = lib.parse_c_type(info, input.encode('ascii')) - if res < 0: - raise ParseError(ffi.string(info.error_message).decode('ascii'), - info.error_location) - assert 0 <= res < len(out) - result = [] - for j in range(len(out)): - if out[j] == ffi.cast("void *", -424242): - assert res < j - break - i = int(ffi.cast("intptr_t", out[j])) - if j == res: - result.append('->') - result.append(i) - return result - -def parsex(input): - result = parse(input) - def str_if_int(x): - if isinstance(x, str): - return x - return '%d,%d' % (x & 255, x >> 8) - return ' '.join(map(str_if_int, result)) - -def parse_error(input, expected_msg, expected_location): - e = py.test.raises(ParseError, parse, input) - assert e.value.args[0] == expected_msg - assert e.value.args[1] == expected_location - -def make_getter(name): - opcode = getattr(lib, '_CFFI_OP_' + name) - def getter(value): - return opcode | (value << 8) - return getter - -Prim = make_getter('PRIMITIVE') -Pointer = make_getter('POINTER') -Array = make_getter('ARRAY') -OpenArray = make_getter('OPEN_ARRAY') -NoOp = make_getter('NOOP') -Func = make_getter('FUNCTION') -FuncEnd = make_getter('FUNCTION_END') -Struct = make_getter('STRUCT_UNION') -Enum = make_getter('ENUM') -Typename = make_getter('TYPENAME') - - -def test_simple(): - for simple_type, expected in [ - ("int", lib._CFFI_PRIM_INT), - ("signed int", lib._CFFI_PRIM_INT), - (" long ", lib._CFFI_PRIM_LONG), - ("long int", lib._CFFI_PRIM_LONG), - ("unsigned short", lib._CFFI_PRIM_USHORT), - ("long double", lib._CFFI_PRIM_LONGDOUBLE), - (" float _Complex", lib._CFFI_PRIM_FLOATCOMPLEX), - ("double _Complex ", lib._CFFI_PRIM_DOUBLECOMPLEX), - ]: - assert parse(simple_type) == ['->', Prim(expected)] - -def test_array(): - assert parse("int[5]") == [Prim(lib._CFFI_PRIM_INT), '->', Array(0), 5] - assert parse("int[]") == [Prim(lib._CFFI_PRIM_INT), '->', OpenArray(0)] - assert parse("int[5][8]") == [Prim(lib._CFFI_PRIM_INT), - '->', Array(3), - 5, - Array(0), - 8] - assert parse("int[][8]") == [Prim(lib._CFFI_PRIM_INT), - '->', OpenArray(2), - Array(0), - 8] - -def test_pointer(): - assert parse("int*") == [Prim(lib._CFFI_PRIM_INT), '->', Pointer(0)] - assert parse("int***") == [Prim(lib._CFFI_PRIM_INT), - Pointer(0), Pointer(1), '->', Pointer(2)] - -def test_grouping(): - assert parse("int*[]") == [Prim(lib._CFFI_PRIM_INT), - Pointer(0), '->', OpenArray(1)] - assert parse("int**[][8]") == [Prim(lib._CFFI_PRIM_INT), - Pointer(0), Pointer(1), - '->', OpenArray(4), Array(2), 8] - assert parse("int(*)[]") == [Prim(lib._CFFI_PRIM_INT), - NoOp(3), '->', Pointer(1), OpenArray(0)] - assert parse("int(*)[][8]") == [Prim(lib._CFFI_PRIM_INT), - NoOp(3), '->', Pointer(1), - OpenArray(4), Array(0), 8] - assert parse("int**(**)") == [Prim(lib._CFFI_PRIM_INT), - Pointer(0), Pointer(1), - NoOp(2), Pointer(3), '->', Pointer(4)] - assert parse("int**(**)[]") == [Prim(lib._CFFI_PRIM_INT), - Pointer(0), Pointer(1), - NoOp(6), Pointer(3), '->', Pointer(4), - OpenArray(2)] - -def test_simple_function(): - assert parse("int()") == [Prim(lib._CFFI_PRIM_INT), - '->', Func(0), FuncEnd(0), 0] - assert parse("int(int)") == [Prim(lib._CFFI_PRIM_INT), - '->', Func(0), NoOp(4), FuncEnd(0), - Prim(lib._CFFI_PRIM_INT)] - assert parse("int(long, char)") == [ - Prim(lib._CFFI_PRIM_INT), - '->', Func(0), NoOp(5), NoOp(6), FuncEnd(0), - Prim(lib._CFFI_PRIM_LONG), - Prim(lib._CFFI_PRIM_CHAR)] - assert parse("int(int*)") == [Prim(lib._CFFI_PRIM_INT), - '->', Func(0), NoOp(5), FuncEnd(0), - Prim(lib._CFFI_PRIM_INT), - Pointer(4)] - assert parse("int*(void)") == [Prim(lib._CFFI_PRIM_INT), - Pointer(0), - '->', Func(1), FuncEnd(0), 0] - assert parse("int(int, ...)") == [Prim(lib._CFFI_PRIM_INT), - '->', Func(0), NoOp(5), FuncEnd(1), 0, - Prim(lib._CFFI_PRIM_INT)] - -def test_internal_function(): - assert parse("int(*)()") == [Prim(lib._CFFI_PRIM_INT), - NoOp(3), '->', Pointer(1), - Func(0), FuncEnd(0), 0] - assert parse("int(*())[]") == [Prim(lib._CFFI_PRIM_INT), - NoOp(6), Pointer(1), - '->', Func(2), FuncEnd(0), 0, - OpenArray(0)] - assert parse("int(char(*)(long, short))") == [ - Prim(lib._CFFI_PRIM_INT), - '->', Func(0), NoOp(6), FuncEnd(0), - Prim(lib._CFFI_PRIM_CHAR), - NoOp(7), Pointer(5), - Func(4), NoOp(11), NoOp(12), FuncEnd(0), - Prim(lib._CFFI_PRIM_LONG), - Prim(lib._CFFI_PRIM_SHORT)] - -def test_fix_arg_types(): - assert parse("int(char(long, short))") == [ - Prim(lib._CFFI_PRIM_INT), - '->', Func(0), Pointer(5), FuncEnd(0), - Prim(lib._CFFI_PRIM_CHAR), - Func(4), NoOp(9), NoOp(10), FuncEnd(0), - Prim(lib._CFFI_PRIM_LONG), - Prim(lib._CFFI_PRIM_SHORT)] - assert parse("int(char[])") == [ - Prim(lib._CFFI_PRIM_INT), - '->', Func(0), Pointer(4), FuncEnd(0), - Prim(lib._CFFI_PRIM_CHAR), - OpenArray(4)] - -def test_enum(): - for i in range(len(enum_names)): - assert parse("enum %s" % (enum_names[i],)) == ['->', Enum(i)] - assert parse("enum %s*" % (enum_names[i],)) == [Enum(i), - '->', Pointer(0)] - -def test_error(): - parse_error("short short int", "'short' after another 'short' or 'long'", 6) - parse_error("long long long", "'long long long' is too long", 10) - parse_error("short long", "'long' after 'short'", 6) - parse_error("signed unsigned int", "multiple 'signed' or 'unsigned'", 7) - parse_error("unsigned signed int", "multiple 'signed' or 'unsigned'", 9) - parse_error("long char", "invalid combination of types", 5) - parse_error("short char", "invalid combination of types", 6) - parse_error("signed void", "invalid combination of types", 7) - parse_error("unsigned struct", "invalid combination of types", 9) - # - parse_error("", "identifier expected", 0) - parse_error("]", "identifier expected", 0) - parse_error("*", "identifier expected", 0) - parse_error("int ]**", "unexpected symbol", 4) - parse_error("char char", "unexpected symbol", 5) - parse_error("int(int]", "expected ')'", 7) - parse_error("int(*]", "expected ')'", 5) - parse_error("int(]", "identifier expected", 4) - parse_error("int[?]", "expected a positive integer constant", 4) - parse_error("int[24)", "expected ']'", 6) - parse_error("struct", "struct or union name expected", 6) - parse_error("struct 24", "struct or union name expected", 7) - parse_error("int[5](*)", "unexpected symbol", 6) - parse_error("int a(*)", "identifier expected", 6) - parse_error("int[123456789012345678901234567890]", "number too large", 4) - # - parse_error("_Complex", "identifier expected", 0) - parse_error("int _Complex", "_Complex type combination unsupported", 4) - parse_error("long double _Complex", "_Complex type combination unsupported", - 12) - -def test_number_too_large(): - num_max = sys.maxsize - assert parse("char[%d]" % num_max) == [Prim(lib._CFFI_PRIM_CHAR), - '->', Array(0), num_max] - parse_error("char[%d]" % (num_max + 1), "number too large", 5) - -def test_complexity_limit(): - parse_error("int" + "[]" * 2500, "internal type complexity limit reached", - 202) - -def test_struct(): - for i in range(len(struct_names)): - if i == 3: - tag = "union" - else: - tag = "struct" - assert parse("%s %s" % (tag, struct_names[i])) == ['->', Struct(i)] - assert parse("%s %s*" % (tag, struct_names[i])) == [Struct(i), - '->', Pointer(0)] - -def test_exchanging_struct_union(): - parse_error("union %s" % (struct_names[0],), - "wrong kind of tag: struct vs union", 6) - parse_error("struct %s" % (struct_names[3],), - "wrong kind of tag: struct vs union", 7) - -def test_identifier(): - for i in range(len(identifier_names)): - assert parse("%s" % (identifier_names[i])) == ['->', Typename(i)] - assert parse("%s*" % (identifier_names[i])) == [Typename(i), - '->', Pointer(0)] - -def test_cffi_opcode_sync(): - import cffi.model - for name in dir(lib): - if name.startswith('_CFFI_'): - assert getattr(cffi_opcode, name[6:]) == getattr(lib, name) - assert sorted(cffi_opcode.PRIMITIVE_TO_INDEX.keys()) == ( - sorted(cffi.model.PrimitiveType.ALL_PRIMITIVE_TYPES.keys())) - -def test_array_length_from_constant(): - parse_error("int[UNKNOWN]", "expected a positive integer constant", 4) - assert parse("int[FIVE]") == [Prim(lib._CFFI_PRIM_INT), '->', Array(0), 5] - assert parse("int[ZERO]") == [Prim(lib._CFFI_PRIM_INT), '->', Array(0), 0] - parse_error("int[NEG]", "expected a positive integer constant", 4) - -def test_various_constant_exprs(): - def array(n): - return [Prim(lib._CFFI_PRIM_CHAR), '->', Array(0), n] - assert parse("char[21]") == array(21) - assert parse("char[0x10]") == array(16) - assert parse("char[0X21]") == array(33) - assert parse("char[0Xb]") == array(11) - assert parse("char[0x1C]") == array(0x1C) - assert parse("char[0xc6]") == array(0xC6) - assert parse("char[010]") == array(8) - assert parse("char[021]") == array(17) - parse_error("char[08]", "invalid number", 5) - parse_error("char[1C]", "invalid number", 5) - parse_error("char[0C]", "invalid number", 5) - # not supported (really obscure): - # "char[+5]" - # "char['A']" - -def test_stdcall_cdecl(): - assert parse("int __stdcall(int)") == [Prim(lib._CFFI_PRIM_INT), - '->', Func(0), NoOp(4), FuncEnd(2), - Prim(lib._CFFI_PRIM_INT)] - assert parse("int __stdcall func(int)") == parse("int __stdcall(int)") - assert parse("int (__stdcall *)()") == [Prim(lib._CFFI_PRIM_INT), - NoOp(3), '->', Pointer(1), - Func(0), FuncEnd(2), 0] - assert parse("int (__stdcall *p)()") == parse("int (__stdcall*)()") - parse_error("__stdcall int", "identifier expected", 0) - parse_error("__cdecl int", "identifier expected", 0) - parse_error("int __stdcall", "expected '('", 13) - parse_error("int __cdecl", "expected '('", 11) diff --git a/testing/cffi1/test_pkgconfig.py b/testing/cffi1/test_pkgconfig.py deleted file mode 100644 index c725cca..0000000 --- a/testing/cffi1/test_pkgconfig.py +++ /dev/null @@ -1,94 +0,0 @@ -import sys -import subprocess -import py -import cffi.pkgconfig as pkgconfig -from cffi import PkgConfigError - - -def mock_call(libname, flag): - assert libname=="foobarbaz" - flags = { - "--cflags": "-I/usr/include/python3.6m -DABCD -DCFFI_TEST=1 -O42\n", - "--libs": "-L/usr/lib64 -lpython3.6 -shared\n", - } - return flags[flag] - - -def test_merge_flags(): - d1 = {"ham": [1, 2, 3], "spam" : ["a", "b", "c"], "foo" : []} - d2 = {"spam" : ["spam", "spam", "spam"], "bar" : ["b", "a", "z"]} - - pkgconfig.merge_flags(d1, d2) - assert d1 == { - "ham": [1, 2, 3], - "spam" : ["a", "b", "c", "spam", "spam", "spam"], - "bar" : ["b", "a", "z"], - "foo" : []} - - -def test_pkgconfig(): - assert pkgconfig.flags_from_pkgconfig([]) == {} - - saved = pkgconfig.call - try: - pkgconfig.call = mock_call - flags = pkgconfig.flags_from_pkgconfig(["foobarbaz"]) - finally: - pkgconfig.call = saved - assert flags == { - 'include_dirs': ['/usr/include/python3.6m'], - 'library_dirs': ['/usr/lib64'], - 'libraries': ['python3.6'], - 'define_macros': [('ABCD', None), ('CFFI_TEST', '1')], - 'extra_compile_args': ['-O42'], - 'extra_link_args': ['-shared'] - } - -class mock_subprocess: - PIPE = Ellipsis - class Popen: - def __init__(self, cmd, stdout, stderr): - if mock_subprocess.RESULT is None: - raise OSError("oops can't run") - assert cmd == ['pkg-config', '--print-errors', '--cflags', 'libfoo'] - def communicate(self): - bout, berr, rc = mock_subprocess.RESULT - self.returncode = rc - return bout, berr - -def test_call(): - saved = pkgconfig.subprocess - try: - pkgconfig.subprocess = mock_subprocess - - mock_subprocess.RESULT = None - e = py.test.raises(PkgConfigError, pkgconfig.call, "libfoo", "--cflags") - assert str(e.value) == "cannot run pkg-config: oops can't run" - - mock_subprocess.RESULT = b"", "Foo error!\n", 1 - e = py.test.raises(PkgConfigError, pkgconfig.call, "libfoo", "--cflags") - assert str(e.value) == "Foo error!" - - mock_subprocess.RESULT = b"abc\\def\n", "", 0 - e = py.test.raises(PkgConfigError, pkgconfig.call, "libfoo", "--cflags") - assert str(e.value).startswith("pkg-config --cflags libfoo returned an " - "unsupported backslash-escaped output:") - - mock_subprocess.RESULT = b"abc def\n", "", 0 - result = pkgconfig.call("libfoo", "--cflags") - assert result == "abc def\n" - - mock_subprocess.RESULT = b"abc def\n", "", 0 - result = pkgconfig.call("libfoo", "--cflags") - assert result == "abc def\n" - - if sys.version_info >= (3,): - mock_subprocess.RESULT = b"\xff\n", "", 0 - e = py.test.raises(PkgConfigError, pkgconfig.call, - "libfoo", "--cflags", encoding="utf-8") - assert str(e.value) == ( - "pkg-config --cflags libfoo returned bytes that cannot be " - "decoded with encoding 'utf-8':\nb'\\xff\\n'") - - finally: - pkgconfig.subprocess = saved diff --git a/testing/cffi1/test_re_python.py b/testing/cffi1/test_re_python.py deleted file mode 100644 index 2ae0dd1..0000000 --- a/testing/cffi1/test_re_python.py +++ /dev/null @@ -1,288 +0,0 @@ -import sys, os -import py -from cffi import FFI -from cffi import recompiler, ffiplatform, VerificationMissing -from testing.udir import udir -from testing.support import u - - -def setup_module(mod): - SRC = """ - #include <string.h> - #define FOOBAR (-42) - static const int FOOBAZ = -43; - #define BIGPOS 420000000000L - #define BIGNEG -420000000000L - int add42(int x) { return x + 42; } - int add43(int x, ...) { return x; } - int globalvar42 = 1234; - const int globalconst42 = 4321; - const char *const globalconsthello = "hello"; - struct foo_s; - typedef struct bar_s { int x; signed char a[]; } bar_t; - enum foo_e { AA, BB, CC }; - - void init_test_re_python(void) { } /* windows hack */ - void PyInit__test_re_python(void) { } /* windows hack */ - """ - tmpdir = udir.join('test_re_python') - tmpdir.ensure(dir=1) - c_file = tmpdir.join('_test_re_python.c') - c_file.write(SRC) - ext = ffiplatform.get_extension( - str(c_file), - '_test_re_python', - export_symbols=['add42', 'add43', 'globalvar42', - 'globalconst42', 'globalconsthello'] - ) - outputfilename = ffiplatform.compile(str(tmpdir), ext) - - # test with a non-ascii char - ofn, oext = os.path.splitext(outputfilename) - if sys.platform == "win32": - unicode_name = ofn + (u+'\u03be') + oext - else: - unicode_name = ofn + (u+'\xe9') + oext - try: - unicode_name.encode(sys.getfilesystemencoding()) - except UnicodeEncodeError: - unicode_name = None - if unicode_name is not None: - print(repr(outputfilename) + ' ==> ' + repr(unicode_name)) - os.rename(outputfilename, unicode_name) - outputfilename = unicode_name - - mod.extmod = outputfilename - mod.tmpdir = tmpdir - # - ffi = FFI() - ffi.cdef(""" - #define FOOBAR -42 - static const int FOOBAZ = -43; - #define BIGPOS 420000000000L - #define BIGNEG -420000000000L - int add42(int); - int add43(int, ...); - extern int globalvar42; - const int globalconst42; - const char *const globalconsthello; - int no_such_function(int); - extern int no_such_globalvar; - struct foo_s; - typedef struct bar_s { int x; signed char a[]; } bar_t; - enum foo_e { AA, BB, CC }; - int strlen(const char *); - struct with_union { union { int a; char b; }; }; - union with_struct { struct { int a; char b; }; }; - struct with_struct_with_union { struct { union { int x; }; } cp; }; - struct NVGcolor { union { float rgba[4]; struct { float r,g,b,a; }; }; }; - typedef struct selfref { struct selfref *next; } *selfref_ptr_t; - """) - ffi.set_source('re_python_pysrc', None) - ffi.emit_python_code(str(tmpdir.join('re_python_pysrc.py'))) - mod.original_ffi = ffi - # - sys.path.insert(0, str(tmpdir)) - - -def test_constant(): - from re_python_pysrc import ffi - assert ffi.integer_const('FOOBAR') == -42 - assert ffi.integer_const('FOOBAZ') == -43 - -def test_large_constant(): - from re_python_pysrc import ffi - assert ffi.integer_const('BIGPOS') == 420000000000 - assert ffi.integer_const('BIGNEG') == -420000000000 - -def test_function(): - import _cffi_backend - from re_python_pysrc import ffi - lib = ffi.dlopen(extmod) - assert lib.add42(-10) == 32 - assert type(lib.add42) is _cffi_backend.FFI.CData - -def test_function_with_varargs(): - import _cffi_backend - from re_python_pysrc import ffi - lib = ffi.dlopen(extmod, 0) - assert lib.add43(45, ffi.cast("int", -5)) == 45 - assert type(lib.add43) is _cffi_backend.FFI.CData - -def test_dlopen_none(): - import _cffi_backend - from re_python_pysrc import ffi - name = None - if sys.platform == 'win32': - import ctypes.util - name = ctypes.util.find_msvcrt() - if name is None: - py.test.skip("dlopen(None) cannot work on Windows with Python 3") - lib = ffi.dlopen(name) - assert lib.strlen(b"hello") == 5 - -def test_dlclose(): - import _cffi_backend - from re_python_pysrc import ffi - lib = ffi.dlopen(extmod) - ffi.dlclose(lib) - if type(extmod) is not str: # unicode, on python 2 - str_extmod = extmod.encode('utf-8') - else: - str_extmod = extmod - e = py.test.raises(ffi.error, getattr, lib, 'add42') - assert str(e.value) == ( - "library '%s' has been closed" % (str_extmod,)) - ffi.dlclose(lib) # does not raise - -def test_constant_via_lib(): - from re_python_pysrc import ffi - lib = ffi.dlopen(extmod) - assert lib.FOOBAR == -42 - assert lib.FOOBAZ == -43 - -def test_opaque_struct(): - from re_python_pysrc import ffi - ffi.cast("struct foo_s *", 0) - py.test.raises(TypeError, ffi.new, "struct foo_s *") - -def test_nonopaque_struct(): - from re_python_pysrc import ffi - for p in [ffi.new("struct bar_s *", [5, b"foobar"]), - ffi.new("bar_t *", [5, b"foobar"])]: - assert p.x == 5 - assert p.a[0] == ord('f') - assert p.a[5] == ord('r') - -def test_enum(): - from re_python_pysrc import ffi - assert ffi.integer_const("BB") == 1 - e = ffi.cast("enum foo_e", 2) - assert ffi.string(e) == "CC" - -def test_include_1(): - sub_ffi = FFI() - sub_ffi.cdef("static const int k2 = 121212;") - sub_ffi.include(original_ffi) - assert 'macro FOOBAR' in original_ffi._parser._declarations - assert 'macro FOOBAZ' in original_ffi._parser._declarations - sub_ffi.set_source('re_python_pysrc', None) - sub_ffi.emit_python_code(str(tmpdir.join('_re_include_1.py'))) - # - if sys.version_info[:2] >= (3, 3): - import importlib - importlib.invalidate_caches() # issue 197 (but can't reproduce myself) - # - from _re_include_1 import ffi - assert ffi.integer_const('FOOBAR') == -42 - assert ffi.integer_const('FOOBAZ') == -43 - assert ffi.integer_const('k2') == 121212 - lib = ffi.dlopen(extmod) # <- a random unrelated library would be fine - assert lib.FOOBAR == -42 - assert lib.FOOBAZ == -43 - assert lib.k2 == 121212 - # - p = ffi.new("bar_t *", [5, b"foobar"]) - assert p.a[4] == ord('a') - -def test_global_var(): - from re_python_pysrc import ffi - lib = ffi.dlopen(extmod) - assert lib.globalvar42 == 1234 - p = ffi.addressof(lib, 'globalvar42') - lib.globalvar42 += 5 - assert p[0] == 1239 - p[0] -= 1 - assert lib.globalvar42 == 1238 - -def test_global_const_int(): - from re_python_pysrc import ffi - lib = ffi.dlopen(extmod) - assert lib.globalconst42 == 4321 - py.test.raises(AttributeError, ffi.addressof, lib, 'globalconst42') - -def test_global_const_nonint(): - from re_python_pysrc import ffi - lib = ffi.dlopen(extmod) - assert ffi.string(lib.globalconsthello, 8) == b"hello" - py.test.raises(AttributeError, ffi.addressof, lib, 'globalconsthello') - -def test_rtld_constants(): - from re_python_pysrc import ffi - ffi.RTLD_NOW # check that we have the attributes - ffi.RTLD_LAZY - ffi.RTLD_GLOBAL - -def test_no_such_function_or_global_var(): - from re_python_pysrc import ffi - lib = ffi.dlopen(extmod) - e = py.test.raises(ffi.error, getattr, lib, 'no_such_function') - assert str(e.value).startswith( - "symbol 'no_such_function' not found in library '") - e = py.test.raises(ffi.error, getattr, lib, 'no_such_globalvar') - assert str(e.value).startswith( - "symbol 'no_such_globalvar' not found in library '") - -def test_check_version(): - import _cffi_backend - e = py.test.raises(ImportError, _cffi_backend.FFI, - "foobar", _version=0x2594) - assert str(e.value).startswith( - "cffi out-of-line Python module 'foobar' has unknown version") - -def test_partial_enum(): - ffi = FFI() - ffi.cdef("enum foo { A, B, ... };") - ffi.set_source('test_partial_enum', None) - py.test.raises(VerificationMissing, ffi.emit_python_code, - str(tmpdir.join('test_partial_enum.py'))) - -def test_anonymous_union_inside_struct(): - # based on issue #357 - from re_python_pysrc import ffi - INT = ffi.sizeof("int") - assert ffi.offsetof("struct with_union", "a") == 0 - assert ffi.offsetof("struct with_union", "b") == 0 - assert ffi.sizeof("struct with_union") == INT - # - assert ffi.offsetof("union with_struct", "a") == 0 - assert ffi.offsetof("union with_struct", "b") == INT - assert ffi.sizeof("union with_struct") >= INT + 1 - # - assert ffi.sizeof("struct with_struct_with_union") == INT - p = ffi.new("struct with_struct_with_union *") - assert p.cp.x == 0 - # - FLOAT = ffi.sizeof("float") - assert ffi.sizeof("struct NVGcolor") == FLOAT * 4 - assert ffi.offsetof("struct NVGcolor", "rgba") == 0 - assert ffi.offsetof("struct NVGcolor", "r") == 0 - assert ffi.offsetof("struct NVGcolor", "g") == FLOAT - assert ffi.offsetof("struct NVGcolor", "b") == FLOAT * 2 - assert ffi.offsetof("struct NVGcolor", "a") == FLOAT * 3 - -def test_selfref(): - # based on issue #429 - from re_python_pysrc import ffi - ffi.new("selfref_ptr_t") - -def test_dlopen_handle(): - import _cffi_backend - from re_python_pysrc import ffi - if sys.platform == 'win32': - py.test.skip("uses 'dl' explicitly") - ffi1 = FFI() - ffi1.cdef("""void *dlopen(const char *filename, int flags); - int dlclose(void *handle);""") - lib1 = ffi1.dlopen('dl') - handle = lib1.dlopen(extmod.encode(sys.getfilesystemencoding()), - _cffi_backend.RTLD_LAZY) - assert ffi1.typeof(handle) == ffi1.typeof("void *") - assert handle - - lib = ffi.dlopen(handle) - assert lib.add42(-10) == 32 - assert type(lib.add42) is _cffi_backend.FFI.CData - - err = lib1.dlclose(handle) - assert err == 0 diff --git a/testing/cffi1/test_realize_c_type.py b/testing/cffi1/test_realize_c_type.py deleted file mode 100644 index a1f31e6..0000000 --- a/testing/cffi1/test_realize_c_type.py +++ /dev/null @@ -1,73 +0,0 @@ -import py, sys -from cffi import cffi_opcode - - -def check(input, expected_output=None, expected_ffi_error=False): - import _cffi_backend - ffi = _cffi_backend.FFI() - if not expected_ffi_error: - ct = ffi.typeof(input) - assert isinstance(ct, ffi.CType) - assert ct.cname == (expected_output or input) - else: - e = py.test.raises(ffi.error, ffi.typeof, input) - if isinstance(expected_ffi_error, str): - assert str(e.value) == expected_ffi_error - -def test_void(): - check("void", "void") - check(" void ", "void") - -def test_int_star(): - check("int") - check("int *") - check("int*", "int *") - check("long int", "long") - check("long") - -def test_noop(): - check("int(*)", "int *") - -def test_array(): - check("int[6]") - -def test_funcptr(): - check("int(*)(long)") - check("int(long)", expected_ffi_error="the type 'int(long)' is a" - " function type, not a pointer-to-function type") - check("int(void)", expected_ffi_error="the type 'int()' is a" - " function type, not a pointer-to-function type") - -def test_funcptr_rewrite_args(): - check("int(*)(int(int))", "int(*)(int(*)(int))") - check("int(*)(long[])", "int(*)(long *)") - check("int(*)(long[5])", "int(*)(long *)") - -def test_all_primitives(): - for name in cffi_opcode.PRIMITIVE_TO_INDEX: - check(name, name) - -def check_func(input, expected_output=None): - import _cffi_backend - ffi = _cffi_backend.FFI() - ct = ffi.typeof(ffi.callback(input, lambda: None)) - assert isinstance(ct, ffi.CType) - if sys.platform != 'win32' or sys.maxsize > 2**32: - expected_output = expected_output.replace('__stdcall *', '*') - assert ct.cname == expected_output - -def test_funcptr_stdcall(): - check_func("int(int)", "int(*)(int)") - check_func("int foobar(int)", "int(*)(int)") - check_func("int __stdcall(int)", "int(__stdcall *)(int)") - check_func("int __stdcall foobar(int)", "int(__stdcall *)(int)") - check_func("void __cdecl(void)", "void(*)()") - check_func("void __cdecl foobar(void)", "void(*)()") - check_func("void __stdcall(void)", "void(__stdcall *)()") - check_func("void __stdcall foobar(long, short)", - "void(__stdcall *)(long, short)") - check_func("void(void __cdecl(void), void __stdcall(void))", - "void(*)(void(*)(), void(__stdcall *)())") - -def test_variadic_overrides_stdcall(): - check("void (__stdcall*)(int, ...)", "void(*)(int, ...)") diff --git a/testing/cffi1/test_recompiler.py b/testing/cffi1/test_recompiler.py deleted file mode 100644 index fdb4d5a..0000000 --- a/testing/cffi1/test_recompiler.py +++ /dev/null @@ -1,2495 +0,0 @@ - -import sys, os, py -import pytest -from cffi import FFI, VerificationError, FFIError, CDefError -from cffi import recompiler -from testing.udir import udir -from testing.support import u, long -from testing.support import FdWriteCapture, StdErrCapture, _verify - -try: - import importlib -except ImportError: - importlib = None - - -def check_type_table(input, expected_output, included=None): - ffi = FFI() - if included: - ffi1 = FFI() - ffi1.cdef(included) - ffi.include(ffi1) - ffi.cdef(input) - recomp = recompiler.Recompiler(ffi, 'testmod') - recomp.collect_type_table() - assert ''.join(map(str, recomp.cffi_types)) == expected_output - -def verify(ffi, module_name, source, *args, **kwds): - no_cpp = kwds.pop('no_cpp', False) - ignore_warnings = kwds.pop('ignore_warnings', False) - kwds.setdefault('undef_macros', ['NDEBUG']) - module_name = '_CFFI_' + module_name - ffi.set_source(module_name, source) - if not os.environ.get('NO_CPP') and not no_cpp: # test the .cpp mode too - kwds.setdefault('source_extension', '.cpp') - source = 'extern "C" {\n%s\n}' % (source,) - elif sys.platform != 'win32' and not ignore_warnings: - # add '-Werror' to the existing 'extra_compile_args' flags - from testing.support import extra_compile_args - kwds['extra_compile_args'] = (kwds.get('extra_compile_args', []) + - extra_compile_args) - if sys.platform == 'darwin': - kwds['extra_link_args'] = (kwds.get('extra_link_args', []) + - ['-stdlib=libc++']) - return _verify(ffi, module_name, source, *args, **kwds) - -def test_set_source_no_slashes(): - ffi = FFI() - py.test.raises(ValueError, ffi.set_source, "abc/def", None) - py.test.raises(ValueError, ffi.set_source, "abc/def", "C code") - - -def test_type_table_func(): - check_type_table("double sin(double);", - "(FUNCTION 1)(PRIMITIVE 14)(FUNCTION_END 0)") - check_type_table("float sin(double);", - "(FUNCTION 3)(PRIMITIVE 14)(FUNCTION_END 0)(PRIMITIVE 13)") - check_type_table("float sin(void);", - "(FUNCTION 2)(FUNCTION_END 0)(PRIMITIVE 13)") - check_type_table("double sin(float); double cos(float);", - "(FUNCTION 3)(PRIMITIVE 13)(FUNCTION_END 0)(PRIMITIVE 14)") - check_type_table("double sin(float); double cos(double);", - "(FUNCTION 1)(PRIMITIVE 14)(FUNCTION_END 0)" # cos - "(FUNCTION 1)(PRIMITIVE 13)(FUNCTION_END 0)") # sin - check_type_table("float sin(double); float cos(float);", - "(FUNCTION 4)(PRIMITIVE 14)(FUNCTION_END 0)" # sin - "(FUNCTION 4)(PRIMITIVE 13)(FUNCTION_END 0)") # cos - -def test_type_table_use_noop_for_repeated_args(): - check_type_table("double sin(double *, double *);", - "(FUNCTION 4)(POINTER 4)(NOOP 1)(FUNCTION_END 0)" - "(PRIMITIVE 14)") - check_type_table("double sin(double *, double *, double);", - "(FUNCTION 3)(POINTER 3)(NOOP 1)(PRIMITIVE 14)" - "(FUNCTION_END 0)") - -def test_type_table_dont_use_noop_for_primitives(): - check_type_table("double sin(double, double);", - "(FUNCTION 1)(PRIMITIVE 14)(PRIMITIVE 14)(FUNCTION_END 0)") - -def test_type_table_funcptr_as_argument(): - check_type_table("int sin(double(float));", - "(FUNCTION 6)(PRIMITIVE 13)(FUNCTION_END 0)" - "(FUNCTION 7)(POINTER 0)(FUNCTION_END 0)" - "(PRIMITIVE 14)(PRIMITIVE 7)") - -def test_type_table_variadic_function(): - check_type_table("int sin(int, ...);", - "(FUNCTION 1)(PRIMITIVE 7)(FUNCTION_END 1)(POINTER 0)") - -def test_type_table_array(): - check_type_table("extern int a[100];", - "(PRIMITIVE 7)(ARRAY 0)(None 100)") - -def test_type_table_typedef(): - check_type_table("typedef int foo_t;", - "(PRIMITIVE 7)") - -def test_type_table_prebuilt_type(): - check_type_table("int32_t f(void);", - "(FUNCTION 2)(FUNCTION_END 0)(PRIMITIVE 21)") - -def test_type_table_struct_opaque(): - check_type_table("struct foo_s;", - "(STRUCT_UNION 0)") - -def test_type_table_struct(): - check_type_table("struct foo_s { int a; long b; };", - "(PRIMITIVE 7)(PRIMITIVE 9)(STRUCT_UNION 0)") - -def test_type_table_union(): - check_type_table("union foo_u { int a; long b; };", - "(PRIMITIVE 7)(PRIMITIVE 9)(STRUCT_UNION 0)") - -def test_type_table_struct_used(): - check_type_table("struct foo_s { int a; long b; }; int f(struct foo_s*);", - "(FUNCTION 3)(POINTER 5)(FUNCTION_END 0)" - "(PRIMITIVE 7)(PRIMITIVE 9)" - "(STRUCT_UNION 0)") - -def test_type_table_anonymous_struct_with_typedef(): - check_type_table("typedef struct { int a; long b; } foo_t;", - "(STRUCT_UNION 0)(PRIMITIVE 7)(PRIMITIVE 9)") - -def test_type_table_enum(): - check_type_table("enum foo_e { AA, BB, ... };", - "(ENUM 0)") - -def test_type_table_include_1(): - check_type_table("foo_t sin(foo_t);", - "(FUNCTION 1)(PRIMITIVE 14)(FUNCTION_END 0)", - included="typedef double foo_t;") - -def test_type_table_include_2(): - check_type_table("struct foo_s *sin(struct foo_s *);", - "(FUNCTION 1)(POINTER 3)(FUNCTION_END 0)(STRUCT_UNION 0)", - included="struct foo_s { int x, y; };") - - -def test_math_sin(): - import math - ffi = FFI() - ffi.cdef("float sin(double); double cos(double);") - lib = verify(ffi, 'test_math_sin', '#include <math.h>', - ignore_warnings=True) - assert lib.cos(1.43) == math.cos(1.43) - -def test_repr_lib(): - ffi = FFI() - lib = verify(ffi, 'test_repr_lib', '') - assert repr(lib) == "<Lib object for '_CFFI_test_repr_lib'>" - -def test_funcarg_ptr(): - ffi = FFI() - ffi.cdef("int foo(int *);") - lib = verify(ffi, 'test_funcarg_ptr', 'int foo(int *p) { return *p; }') - assert lib.foo([-12345]) == -12345 - -def test_funcres_ptr(): - ffi = FFI() - ffi.cdef("int *foo(void);") - lib = verify(ffi, 'test_funcres_ptr', - 'int *foo(void) { static int x=-12345; return &x; }') - assert lib.foo()[0] == -12345 - -def test_global_var_array(): - ffi = FFI() - ffi.cdef("extern int a[100];") - lib = verify(ffi, 'test_global_var_array', 'int a[100] = { 9999 };') - lib.a[42] = 123456 - assert lib.a[42] == 123456 - assert lib.a[0] == 9999 - -def test_verify_typedef(): - ffi = FFI() - ffi.cdef("typedef int **foo_t;") - lib = verify(ffi, 'test_verify_typedef', 'typedef int **foo_t;') - assert ffi.sizeof("foo_t") == ffi.sizeof("void *") - -def test_verify_typedef_dotdotdot(): - ffi = FFI() - ffi.cdef("typedef ... foo_t;") - verify(ffi, 'test_verify_typedef_dotdotdot', 'typedef int **foo_t;') - -def test_verify_typedef_star_dotdotdot(): - ffi = FFI() - ffi.cdef("typedef ... *foo_t;") - verify(ffi, 'test_verify_typedef_star_dotdotdot', 'typedef int **foo_t;') - -def test_global_var_int(): - ffi = FFI() - ffi.cdef("extern int a, b, c;") - lib = verify(ffi, 'test_global_var_int', 'int a = 999, b, c;') - assert lib.a == 999 - lib.a -= 1001 - assert lib.a == -2 - lib.a = -2147483648 - assert lib.a == -2147483648 - with pytest.raises(OverflowError): - lib.a = 2147483648 - with pytest.raises(OverflowError): - lib.a = -2147483649 - lib.b = 525 # try with the first access being in setattr, too - assert lib.b == 525 - with pytest.raises(AttributeError): - del lib.a - with pytest.raises(AttributeError): - del lib.c - with pytest.raises(AttributeError): - del lib.foobarbaz - -def test_macro(): - ffi = FFI() - ffi.cdef("#define FOOBAR ...") - lib = verify(ffi, 'test_macro', "#define FOOBAR (-6912)") - assert lib.FOOBAR == -6912 - with pytest.raises(AttributeError): - lib.FOOBAR = 2 - -def test_macro_check_value(): - # the value '-0x80000000' in C sources does not have a clear meaning - # to me; it appears to have a different effect than '-2147483648'... - # Moreover, on 32-bits, -2147483648 is actually equal to - # -2147483648U, which in turn is equal to 2147483648U and so positive. - vals = ['42', '-42', '0x80000000', '-2147483648', - '0', '9223372036854775809ULL', - '-9223372036854775807LL'] - if sys.maxsize <= 2**32 or sys.platform == 'win32': - vals.remove('-2147483648') - ffi = FFI() - cdef_lines = ['#define FOO_%d_%d %s' % (i, j, vals[i]) - for i in range(len(vals)) - for j in range(len(vals))] - ffi.cdef('\n'.join(cdef_lines)) - - verify_lines = ['#define FOO_%d_%d %s' % (i, j, vals[j]) # [j], not [i] - for i in range(len(vals)) - for j in range(len(vals))] - lib = verify(ffi, 'test_macro_check_value_ok', - '\n'.join(verify_lines)) - # - for j in range(len(vals)): - c_got = int(vals[j].replace('U', '').replace('L', ''), 0) - c_compiler_msg = str(c_got) - if c_got > 0: - c_compiler_msg += ' (0x%x)' % (c_got,) - # - for i in range(len(vals)): - attrname = 'FOO_%d_%d' % (i, j) - if i == j: - x = getattr(lib, attrname) - assert x == c_got - else: - e = py.test.raises(ffi.error, getattr, lib, attrname) - assert str(e.value) == ( - "the C compiler says '%s' is equal to " - "%s, but the cdef disagrees" % (attrname, c_compiler_msg)) - -def test_constant(): - ffi = FFI() - ffi.cdef("static const int FOOBAR;") - lib = verify(ffi, 'test_constant', "#define FOOBAR (-6912)") - assert lib.FOOBAR == -6912 - with pytest.raises(AttributeError): - lib.FOOBAR = 2 - -def test_check_value_of_static_const(): - ffi = FFI() - ffi.cdef("static const int FOOBAR = 042;") - lib = verify(ffi, 'test_check_value_of_static_const', - "#define FOOBAR (-6912)") - e = py.test.raises(ffi.error, getattr, lib, 'FOOBAR') - assert str(e.value) == ( - "the C compiler says 'FOOBAR' is equal to -6912, but the cdef disagrees") - -def test_constant_nonint(): - ffi = FFI() - ffi.cdef("static const double FOOBAR;") - lib = verify(ffi, 'test_constant_nonint', "#define FOOBAR (-6912.5)") - assert lib.FOOBAR == -6912.5 - with pytest.raises(AttributeError): - lib.FOOBAR = 2 - -def test_constant_ptr(): - ffi = FFI() - ffi.cdef("static double *const FOOBAR;") - lib = verify(ffi, 'test_constant_ptr', "#define FOOBAR NULL") - assert lib.FOOBAR == ffi.NULL - assert ffi.typeof(lib.FOOBAR) == ffi.typeof("double *") - -def test_dir(): - ffi = FFI() - ffi.cdef("int ff(int); extern int aa; static const int my_constant;") - lib = verify(ffi, 'test_dir', """ - #define my_constant (-45) - int aa; - int ff(int x) { return x+aa; } - """) - lib.aa = 5 - assert dir(lib) == ['aa', 'ff', 'my_constant'] - # - aaobj = lib.__dict__['aa'] - assert not isinstance(aaobj, int) # some internal object instead - assert lib.__dict__ == { - 'ff': lib.ff, - 'aa': aaobj, - 'my_constant': -45} - lib.__dict__['ff'] = "??" - assert lib.ff(10) == 15 - -def test_verify_opaque_struct(): - ffi = FFI() - ffi.cdef("struct foo_s;") - lib = verify(ffi, 'test_verify_opaque_struct', "struct foo_s;") - assert ffi.typeof("struct foo_s").cname == "struct foo_s" - -def test_verify_opaque_union(): - ffi = FFI() - ffi.cdef("union foo_s;") - lib = verify(ffi, 'test_verify_opaque_union', "union foo_s;") - assert ffi.typeof("union foo_s").cname == "union foo_s" - -def test_verify_struct(): - ffi = FFI() - ffi.cdef("""struct foo_s { int b; short a; ...; }; - struct bar_s { struct foo_s *f; };""") - lib = verify(ffi, 'test_verify_struct', - """struct foo_s { short a; int b; }; - struct bar_s { struct foo_s *f; };""") - ffi.typeof("struct bar_s *") - p = ffi.new("struct foo_s *", {'a': -32768, 'b': -2147483648}) - assert p.a == -32768 - assert p.b == -2147483648 - with pytest.raises(OverflowError): - p.a -= 1 - with pytest.raises(OverflowError): - p.b -= 1 - q = ffi.new("struct bar_s *", {'f': p}) - assert q.f == p - # - assert ffi.offsetof("struct foo_s", "a") == 0 - assert ffi.offsetof("struct foo_s", "b") == 4 - assert ffi.offsetof(u+"struct foo_s", u+"b") == 4 - # - py.test.raises(TypeError, ffi.addressof, p) - assert ffi.addressof(p[0]) == p - assert ffi.typeof(ffi.addressof(p[0])) is ffi.typeof("struct foo_s *") - assert ffi.typeof(ffi.addressof(p, "b")) is ffi.typeof("int *") - assert ffi.addressof(p, "b")[0] == p.b - -def test_verify_exact_field_offset(): - ffi = FFI() - ffi.cdef("""struct foo_s { int b; short a; };""") - lib = verify(ffi, 'test_verify_exact_field_offset', - """struct foo_s { short a; int b; };""") - e = py.test.raises(ffi.error, ffi.new, "struct foo_s *", []) # lazily - assert str(e.value).startswith( - "struct foo_s: wrong offset for field 'b' (cdef " - 'says 0, but C compiler says 4). fix it or use "...;" ') - -def test_type_caching(): - ffi1 = FFI(); ffi1.cdef("struct foo_s;") - ffi2 = FFI(); ffi2.cdef("struct foo_s;") # different one! - lib1 = verify(ffi1, 'test_type_caching_1', 'struct foo_s;') - lib2 = verify(ffi2, 'test_type_caching_2', 'struct foo_s;') - # shared types - assert ffi1.typeof("long") is ffi2.typeof("long") - assert ffi1.typeof("long**") is ffi2.typeof("long * *") - assert ffi1.typeof("long(*)(int, ...)") is ffi2.typeof("long(*)(int, ...)") - # non-shared types - assert ffi1.typeof("struct foo_s") is not ffi2.typeof("struct foo_s") - assert ffi1.typeof("struct foo_s *") is not ffi2.typeof("struct foo_s *") - assert ffi1.typeof("struct foo_s*(*)()") is not ( - ffi2.typeof("struct foo_s*(*)()")) - assert ffi1.typeof("void(*)(struct foo_s*)") is not ( - ffi2.typeof("void(*)(struct foo_s*)")) - -def test_verify_enum(): - ffi = FFI() - ffi.cdef("""enum e1 { B1, A1, ... }; enum e2 { B2, A2, ... };""") - lib = verify(ffi, 'test_verify_enum', - "enum e1 { A1, B1, C1=%d };" % sys.maxsize + - "enum e2 { A2, B2, C2 };") - ffi.typeof("enum e1") - ffi.typeof("enum e2") - assert lib.A1 == 0 - assert lib.B1 == 1 - assert lib.A2 == 0 - assert lib.B2 == 1 - assert ffi.sizeof("enum e1") == ffi.sizeof("long") - assert ffi.sizeof("enum e2") == ffi.sizeof("int") - assert repr(ffi.cast("enum e1", 0)) == "<cdata 'enum e1' 0: A1>" - -def test_duplicate_enum(): - ffi = FFI() - ffi.cdef("enum e1 { A1, ... }; enum e2 { A1, ... };") - py.test.raises(VerificationError, verify, ffi, 'test_duplicate_enum', - "enum e1 { A1 }; enum e2 { B1 };") - -def test_dotdotdot_length_of_array_field(): - ffi = FFI() - ffi.cdef("struct foo_s { int a[...]; int b[...]; };") - verify(ffi, 'test_dotdotdot_length_of_array_field', - "struct foo_s { int a[42]; int b[11]; };") - assert ffi.sizeof("struct foo_s") == (42 + 11) * 4 - p = ffi.new("struct foo_s *") - assert p.a[41] == p.b[10] == 0 - with pytest.raises(IndexError): - p.a[42] - with pytest.raises(IndexError): - p.b[11] - -def test_dotdotdot_global_array(): - ffi = FFI() - ffi.cdef("extern int aa[...]; extern int bb[...];") - lib = verify(ffi, 'test_dotdotdot_global_array', - "int aa[41]; int bb[12];") - assert ffi.sizeof(lib.aa) == 41 * 4 - assert ffi.sizeof(lib.bb) == 12 * 4 - assert lib.aa[40] == lib.bb[11] == 0 - with pytest.raises(IndexError): - lib.aa[41] - with pytest.raises(IndexError): - lib.bb[12] - -def test_misdeclared_field_1(): - ffi = FFI() - ffi.cdef("struct foo_s { int a[5]; };") - try: - verify(ffi, 'test_misdeclared_field_1', - "struct foo_s { int a[6]; };") - except VerificationError: - pass # ok, fail during compilation already (e.g. C++) - else: - assert ffi.sizeof("struct foo_s") == 24 # found by the actual C code - try: - # lazily build the fields and boom: - p = ffi.new("struct foo_s *") - p.a - assert False, "should have raised" - except ffi.error as e: - assert str(e).startswith("struct foo_s: wrong size for field 'a' " - "(cdef says 20, but C compiler says 24)") - -def test_open_array_in_struct(): - ffi = FFI() - ffi.cdef("struct foo_s { int b; int a[]; };") - verify(ffi, 'test_open_array_in_struct', - "struct foo_s { int b; int a[]; };") - assert ffi.sizeof("struct foo_s") == 4 - p = ffi.new("struct foo_s *", [5, [10, 20, 30, 40]]) - assert p.a[2] == 30 - assert ffi.sizeof(p) == ffi.sizeof("void *") - assert ffi.sizeof(p[0]) == 5 * ffi.sizeof("int") - -def test_math_sin_type(): - ffi = FFI() - ffi.cdef("double sin(double); void *xxtestfunc();") - lib = verify(ffi, 'test_math_sin_type', """ - #include <math.h> - void *xxtestfunc(void) { return 0; } - """) - # 'lib.sin' is typed as a <built-in method> object on lib - assert ffi.typeof(lib.sin).cname == "double(*)(double)" - # 'x' is another <built-in method> object on lib, made very indirectly - x = type(lib).__dir__.__get__(lib) - py.test.raises(TypeError, ffi.typeof, x) - # - # present on built-in functions on CPython; must be emulated on PyPy: - assert lib.sin.__name__ == 'sin' - assert lib.sin.__module__ == '_CFFI_test_math_sin_type' - assert lib.sin.__doc__ == ( - "double sin(double);\n" - "\n" - "CFFI C function from _CFFI_test_math_sin_type.lib") - - assert ffi.typeof(lib.xxtestfunc).cname == "void *(*)()" - assert lib.xxtestfunc.__doc__ == ( - "void *xxtestfunc();\n" - "\n" - "CFFI C function from _CFFI_test_math_sin_type.lib") - -def test_verify_anonymous_struct_with_typedef(): - ffi = FFI() - ffi.cdef("typedef struct { int a; long b; ...; } foo_t;") - verify(ffi, 'test_verify_anonymous_struct_with_typedef', - "typedef struct { long b; int hidden, a; } foo_t;") - p = ffi.new("foo_t *", {'b': 42}) - assert p.b == 42 - assert repr(p).startswith("<cdata 'foo_t *' ") - -def test_verify_anonymous_struct_with_star_typedef(): - ffi = FFI() - ffi.cdef("typedef struct { int a; long b; } *foo_t;") - verify(ffi, 'test_verify_anonymous_struct_with_star_typedef', - "typedef struct { int a; long b; } *foo_t;") - p = ffi.new("foo_t", {'b': 42}) - assert p.b == 42 - -def test_verify_anonymous_enum_with_typedef(): - ffi = FFI() - ffi.cdef("typedef enum { AA, ... } e1;") - lib = verify(ffi, 'test_verify_anonymous_enum_with_typedef1', - "typedef enum { BB, CC, AA } e1;") - assert lib.AA == 2 - assert ffi.sizeof("e1") == ffi.sizeof("int") - assert repr(ffi.cast("e1", 2)) == "<cdata 'e1' 2: AA>" - # - ffi = FFI() - ffi.cdef("typedef enum { AA=%d } e1;" % sys.maxsize) - lib = verify(ffi, 'test_verify_anonymous_enum_with_typedef2', - "typedef enum { AA=%d } e1;" % sys.maxsize) - assert lib.AA == int(ffi.cast("long", sys.maxsize)) - assert ffi.sizeof("e1") == ffi.sizeof("long") - -def test_unique_types(): - CDEF = "struct foo_s; union foo_u; enum foo_e { AA };" - ffi1 = FFI(); ffi1.cdef(CDEF); verify(ffi1, "test_unique_types_1", CDEF) - ffi2 = FFI(); ffi2.cdef(CDEF); verify(ffi2, "test_unique_types_2", CDEF) - # - assert ffi1.typeof("char") is ffi2.typeof("char ") - assert ffi1.typeof("long") is ffi2.typeof("signed long int") - assert ffi1.typeof("double *") is ffi2.typeof("double*") - assert ffi1.typeof("int ***") is ffi2.typeof(" int * * *") - assert ffi1.typeof("int[]") is ffi2.typeof("signed int[]") - assert ffi1.typeof("signed int*[17]") is ffi2.typeof("int *[17]") - assert ffi1.typeof("void") is ffi2.typeof("void") - assert ffi1.typeof("int(*)(int,int)") is ffi2.typeof("int(*)(int,int)") - # - # these depend on user-defined data, so should not be shared - for name in ["struct foo_s", - "union foo_u *", - "enum foo_e", - "struct foo_s *(*)()", - "void(*)(struct foo_s *)", - "struct foo_s *(*[5])[8]", - ]: - assert ffi1.typeof(name) is not ffi2.typeof(name) - # sanity check: twice 'ffi1' - assert ffi1.typeof("struct foo_s*") is ffi1.typeof("struct foo_s *") - -def test_module_name_in_package(): - ffi = FFI() - ffi.cdef("int foo(int);") - recompiler.recompile(ffi, "test_module_name_in_package.mymod", - "int foo(int x) { return x + 32; }", - tmpdir=str(udir)) - old_sys_path = sys.path[:] - try: - package_dir = udir.join('test_module_name_in_package') - for name in os.listdir(str(udir)): - assert not name.startswith('test_module_name_in_package.') - assert os.path.isdir(str(package_dir)) - assert len(os.listdir(str(package_dir))) > 0 - assert os.path.exists(str(package_dir.join('mymod.c'))) - package_dir.join('__init__.py').write('') - # - getattr(importlib, 'invalidate_caches', object)() - # - sys.path.insert(0, str(udir)) - import test_module_name_in_package.mymod - assert test_module_name_in_package.mymod.lib.foo(10) == 42 - assert test_module_name_in_package.mymod.__name__ == ( - 'test_module_name_in_package.mymod') - finally: - sys.path[:] = old_sys_path - -def test_bad_size_of_global_1(): - ffi = FFI() - ffi.cdef("extern short glob;") - py.test.raises(VerificationError, verify, ffi, - "test_bad_size_of_global_1", "long glob;") - -def test_bad_size_of_global_2(): - ffi = FFI() - ffi.cdef("extern int glob[10];") - py.test.raises(VerificationError, verify, ffi, - "test_bad_size_of_global_2", "int glob[9];") - -def test_unspecified_size_of_global_1(): - ffi = FFI() - ffi.cdef("extern int glob[];") - lib = verify(ffi, "test_unspecified_size_of_global_1", "int glob[10];") - assert ffi.typeof(lib.glob) == ffi.typeof("int *") - -def test_unspecified_size_of_global_2(): - ffi = FFI() - ffi.cdef("extern int glob[][5];") - lib = verify(ffi, "test_unspecified_size_of_global_2", "int glob[10][5];") - assert ffi.typeof(lib.glob) == ffi.typeof("int(*)[5]") - -def test_unspecified_size_of_global_3(): - ffi = FFI() - ffi.cdef("extern int glob[][...];") - lib = verify(ffi, "test_unspecified_size_of_global_3", "int glob[10][5];") - assert ffi.typeof(lib.glob) == ffi.typeof("int(*)[5]") - -def test_unspecified_size_of_global_4(): - ffi = FFI() - ffi.cdef("extern int glob[...][...];") - lib = verify(ffi, "test_unspecified_size_of_global_4", "int glob[10][5];") - assert ffi.typeof(lib.glob) == ffi.typeof("int[10][5]") - -def test_include_1(): - ffi1 = FFI() - ffi1.cdef("typedef double foo_t;") - verify(ffi1, "test_include_1_parent", "typedef double foo_t;") - ffi = FFI() - ffi.include(ffi1) - ffi.cdef("foo_t ff1(foo_t);") - lib = verify(ffi, "test_include_1", "double ff1(double x) { return 42.5; }") - assert lib.ff1(0) == 42.5 - assert ffi1.typeof("foo_t") is ffi.typeof("foo_t") is ffi.typeof("double") - -def test_include_1b(): - ffi1 = FFI() - ffi1.cdef("int foo1(int);") - lib1 = verify(ffi1, "test_include_1b_parent", - "int foo1(int x) { return x + 10; }") - ffi = FFI() - ffi.include(ffi1) - ffi.cdef("int foo2(int);") - lib = verify(ffi, "test_include_1b", "int foo2(int x) { return x - 5; }") - assert lib.foo2(42) == 37 - assert lib.foo1(42) == 52 - assert lib.foo1 is lib1.foo1 - -def test_include_2(): - ffi1 = FFI() - ffi1.cdef("struct foo_s { int x, y; };") - verify(ffi1, "test_include_2_parent", "struct foo_s { int x, y; };") - ffi = FFI() - ffi.include(ffi1) - ffi.cdef("struct foo_s *ff2(struct foo_s *);") - lib = verify(ffi, "test_include_2", - "struct foo_s { int x, y; }; //usually from a #include\n" - "struct foo_s *ff2(struct foo_s *p) { p->y++; return p; }") - p = ffi.new("struct foo_s *") - p.y = 41 - q = lib.ff2(p) - assert q == p - assert p.y == 42 - assert ffi1.typeof("struct foo_s") is ffi.typeof("struct foo_s") - -def test_include_3(): - ffi1 = FFI() - ffi1.cdef("typedef short sshort_t;") - verify(ffi1, "test_include_3_parent", "typedef short sshort_t;") - ffi = FFI() - ffi.include(ffi1) - ffi.cdef("sshort_t ff3(sshort_t);") - lib = verify(ffi, "test_include_3", - "typedef short sshort_t; //usually from a #include\n" - "sshort_t ff3(sshort_t x) { return (sshort_t)(x + 42); }") - assert lib.ff3(10) == 52 - assert ffi.typeof(ffi.cast("sshort_t", 42)) is ffi.typeof("short") - assert ffi1.typeof("sshort_t") is ffi.typeof("sshort_t") - -def test_include_4(): - ffi1 = FFI() - ffi1.cdef("typedef struct { int x; } mystruct_t;") - verify(ffi1, "test_include_4_parent", - "typedef struct { int x; } mystruct_t;") - ffi = FFI() - ffi.include(ffi1) - ffi.cdef("mystruct_t *ff4(mystruct_t *);") - lib = verify(ffi, "test_include_4", - "typedef struct {int x; } mystruct_t; //usually from a #include\n" - "mystruct_t *ff4(mystruct_t *p) { p->x += 42; return p; }") - p = ffi.new("mystruct_t *", [10]) - q = lib.ff4(p) - assert q == p - assert p.x == 52 - assert ffi1.typeof("mystruct_t") is ffi.typeof("mystruct_t") - -def test_include_5(): - ffi1 = FFI() - ffi1.cdef("typedef struct { int x[2]; int y; } *mystruct_p;") - verify(ffi1, "test_include_5_parent", - "typedef struct { int x[2]; int y; } *mystruct_p;") - ffi = FFI() - ffi.include(ffi1) - ffi.cdef("mystruct_p ff5(mystruct_p);") - lib = verify(ffi, "test_include_5", - "typedef struct {int x[2]; int y; } *mystruct_p; //usually #include\n" - "mystruct_p ff5(mystruct_p p) { p->x[1] += 42; return p; }") - assert ffi.alignof(ffi.typeof("mystruct_p").item) == 4 - assert ffi1.typeof("mystruct_p") is ffi.typeof("mystruct_p") - p = ffi.new("mystruct_p", [[5, 10], -17]) - q = lib.ff5(p) - assert q == p - assert p.x[0] == 5 - assert p.x[1] == 52 - assert p.y == -17 - assert ffi.alignof(ffi.typeof(p[0])) == 4 - -def test_include_6(): - ffi1 = FFI() - ffi1.cdef("typedef ... mystruct_t;") - verify(ffi1, "test_include_6_parent", - "typedef struct _mystruct_s mystruct_t;") - ffi = FFI() - ffi.include(ffi1) - ffi.cdef("mystruct_t *ff6(void); int ff6b(mystruct_t *);") - lib = verify(ffi, "test_include_6", - "typedef struct _mystruct_s mystruct_t; //usually from a #include\n" - "struct _mystruct_s { int x; };\n" - "static mystruct_t result_struct = { 42 };\n" - "mystruct_t *ff6(void) { return &result_struct; }\n" - "int ff6b(mystruct_t *p) { return p->x; }") - p = lib.ff6() - assert ffi.cast("int *", p)[0] == 42 - assert lib.ff6b(p) == 42 - -def test_include_7(): - ffi1 = FFI() - ffi1.cdef("typedef ... mystruct_t;\n" - "int ff7b(mystruct_t *);") - verify(ffi1, "test_include_7_parent", - "typedef struct { int x; } mystruct_t;\n" - "int ff7b(mystruct_t *p) { return p->x; }") - ffi = FFI() - ffi.include(ffi1) - ffi.cdef("mystruct_t *ff7(void);") - lib = verify(ffi, "test_include_7", - "typedef struct { int x; } mystruct_t; //usually from a #include\n" - "static mystruct_t result_struct = { 42 };" - "mystruct_t *ff7(void) { return &result_struct; }") - p = lib.ff7() - assert ffi.cast("int *", p)[0] == 42 - assert lib.ff7b(p) == 42 - -def test_include_8(): - ffi1 = FFI() - ffi1.cdef("struct foo_s;") - verify(ffi1, "test_include_8_parent", "struct foo_s;") - ffi = FFI() - ffi.include(ffi1) - ffi.cdef("struct foo_s { int x, y; };") - verify(ffi, "test_include_8", "struct foo_s { int x, y; };") - e = py.test.raises(NotImplementedError, ffi.new, "struct foo_s *") - assert str(e.value) == ( - "'struct foo_s' is opaque in the ffi.include(), but no longer in " - "the ffi doing the include (workaround: don't use ffi.include() but" - " duplicate the declarations of everything using struct foo_s)") - -def test_unicode_libraries(): - try: - unicode - except NameError: - py.test.skip("for python 2.x") - # - import math - lib_m = "m" - if sys.platform == 'win32': - #there is a small chance this fails on Mingw via environ $CC - import distutils.ccompiler - if distutils.ccompiler.get_default_compiler() == 'msvc': - lib_m = 'msvcrt' - ffi = FFI() - ffi.cdef(unicode("float sin(double); double cos(double);")) - lib = verify(ffi, 'test_math_sin_unicode', unicode('#include <math.h>'), - libraries=[unicode(lib_m)], ignore_warnings=True) - assert lib.cos(1.43) == math.cos(1.43) - -def test_incomplete_struct_as_arg(): - ffi = FFI() - ffi.cdef("struct foo_s { int x; ...; }; int f(int, struct foo_s);") - lib = verify(ffi, "test_incomplete_struct_as_arg", - "struct foo_s { int a, x, z; };\n" - "int f(int b, struct foo_s s) { return s.x * b; }") - s = ffi.new("struct foo_s *", [21]) - assert s.x == 21 - assert ffi.sizeof(s[0]) == 12 - assert ffi.offsetof(ffi.typeof(s), 'x') == 4 - assert lib.f(2, s[0]) == 42 - assert ffi.typeof(lib.f) == ffi.typeof("int(*)(int, struct foo_s)") - -def test_incomplete_struct_as_result(): - ffi = FFI() - ffi.cdef("struct foo_s { int x; ...; }; struct foo_s f(int);") - lib = verify(ffi, "test_incomplete_struct_as_result", - "struct foo_s { int a, x, z; };\n" - "struct foo_s f(int x) { struct foo_s r; r.x = x * 2; return r; }") - s = lib.f(21) - assert s.x == 42 - assert ffi.typeof(lib.f) == ffi.typeof("struct foo_s(*)(int)") - -def test_incomplete_struct_as_both(): - ffi = FFI() - ffi.cdef("struct foo_s { int x; ...; }; struct bar_s { int y; ...; };\n" - "struct foo_s f(int, struct bar_s);") - lib = verify(ffi, "test_incomplete_struct_as_both", - "struct foo_s { int a, x, z; };\n" - "struct bar_s { int b, c, y, d; };\n" - "struct foo_s f(int x, struct bar_s b) {\n" - " struct foo_s r; r.x = x * b.y; return r;\n" - "}") - b = ffi.new("struct bar_s *", [7]) - s = lib.f(6, b[0]) - assert s.x == 42 - assert ffi.typeof(lib.f) == ffi.typeof( - "struct foo_s(*)(int, struct bar_s)") - s = lib.f(14, {'y': -3}) - assert s.x == -42 - -def test_name_of_unnamed_struct(): - ffi = FFI() - ffi.cdef("typedef struct { int x; } foo_t;\n" - "typedef struct { int y; } *bar_p;\n" - "typedef struct { int y; } **baz_pp;\n") - verify(ffi, "test_name_of_unnamed_struct", - "typedef struct { int x; } foo_t;\n" - "typedef struct { int y; } *bar_p;\n" - "typedef struct { int y; } **baz_pp;\n") - assert repr(ffi.typeof("foo_t")) == "<ctype 'foo_t'>" - assert repr(ffi.typeof("bar_p")) == "<ctype 'struct $1 *'>" - assert repr(ffi.typeof("baz_pp")) == "<ctype 'struct $2 * *'>" - -def test_address_of_global_var(): - ffi = FFI() - ffi.cdef(""" - extern long bottom, bottoms[2]; - long FetchRectBottom(void); - long FetchRectBottoms1(void); - #define FOOBAR 42 - """) - lib = verify(ffi, "test_address_of_global_var", """ - long bottom, bottoms[2]; - long FetchRectBottom(void) { return bottom; } - long FetchRectBottoms1(void) { return bottoms[1]; } - #define FOOBAR 42 - """) - lib.bottom = 300 - assert lib.FetchRectBottom() == 300 - lib.bottom += 1 - assert lib.FetchRectBottom() == 301 - lib.bottoms[1] = 500 - assert lib.FetchRectBottoms1() == 500 - lib.bottoms[1] += 2 - assert lib.FetchRectBottoms1() == 502 - # - p = ffi.addressof(lib, 'bottom') - assert ffi.typeof(p) == ffi.typeof("long *") - assert p[0] == 301 - p[0] += 1 - assert lib.FetchRectBottom() == 302 - p = ffi.addressof(lib, 'bottoms') - assert ffi.typeof(p) == ffi.typeof("long(*)[2]") - assert p[0] == lib.bottoms - # - py.test.raises(AttributeError, ffi.addressof, lib, 'unknown_var') - py.test.raises(AttributeError, ffi.addressof, lib, "FOOBAR") - -def test_defines__CFFI_(): - # Check that we define the macro _CFFI_ automatically. - # It should be done before including Python.h, so that PyPy's Python.h - # can check for it. - ffi = FFI() - ffi.cdef(""" - #define CORRECT 1 - """) - lib = verify(ffi, "test_defines__CFFI_", """ - #ifdef _CFFI_ - # define CORRECT 1 - #endif - """) - assert lib.CORRECT == 1 - -def test_unpack_args(): - ffi = FFI() - ffi.cdef("void foo0(void); void foo1(int); void foo2(int, int);") - lib = verify(ffi, "test_unpack_args", """ - void foo0(void) { } - void foo1(int x) { } - void foo2(int x, int y) { } - """) - assert 'foo0' in repr(lib.foo0) - assert 'foo1' in repr(lib.foo1) - assert 'foo2' in repr(lib.foo2) - lib.foo0() - lib.foo1(42) - lib.foo2(43, 44) - e1 = py.test.raises(TypeError, lib.foo0, 42) - e2 = py.test.raises(TypeError, lib.foo0, 43, 44) - e3 = py.test.raises(TypeError, lib.foo1) - e4 = py.test.raises(TypeError, lib.foo1, 43, 44) - e5 = py.test.raises(TypeError, lib.foo2) - e6 = py.test.raises(TypeError, lib.foo2, 42) - e7 = py.test.raises(TypeError, lib.foo2, 45, 46, 47) - def st1(s): - s = str(s) - if s.startswith("_CFFI_test_unpack_args.Lib."): - s = s[len("_CFFI_test_unpack_args.Lib."):] - return s - assert st1(e1.value) == "foo0() takes no arguments (1 given)" - assert st1(e2.value) == "foo0() takes no arguments (2 given)" - assert st1(e3.value) == "foo1() takes exactly one argument (0 given)" - assert st1(e4.value) == "foo1() takes exactly one argument (2 given)" - assert st1(e5.value) in ["foo2 expected 2 arguments, got 0", - "foo2() takes exactly 2 arguments (0 given)"] - assert st1(e6.value) in ["foo2 expected 2 arguments, got 1", - "foo2() takes exactly 2 arguments (1 given)"] - assert st1(e7.value) in ["foo2 expected 2 arguments, got 3", - "foo2() takes exactly 2 arguments (3 given)"] - -def test_address_of_function(): - ffi = FFI() - ffi.cdef("long myfunc(long x);") - lib = verify(ffi, "test_addressof_function", """ - char myfunc(char x) { return (char)(x + 42); } - """, ignore_warnings=True) - assert lib.myfunc(5) == 47 - assert lib.myfunc(0xABC05) == 47 - assert not isinstance(lib.myfunc, ffi.CData) - assert ffi.typeof(lib.myfunc) == ffi.typeof("long(*)(long)") - addr = ffi.addressof(lib, 'myfunc') - assert addr(5) == 47 - assert addr(0xABC05) == 47 - assert isinstance(addr, ffi.CData) - assert ffi.typeof(addr) == ffi.typeof("long(*)(long)") - -def test_address_of_function_with_struct(): - ffi = FFI() - ffi.cdef("struct foo_s { int x; }; long myfunc(struct foo_s);") - lib = verify(ffi, "test_addressof_function_with_struct", """ - struct foo_s { int x; }; - char myfunc(struct foo_s input) { return (char)(input.x + 42); } - """) - s = ffi.new("struct foo_s *", [5])[0] - assert lib.myfunc(s) == 47 - assert not isinstance(lib.myfunc, ffi.CData) - assert ffi.typeof(lib.myfunc) == ffi.typeof("long(*)(struct foo_s)") - addr = ffi.addressof(lib, 'myfunc') - assert addr(s) == 47 - assert isinstance(addr, ffi.CData) - assert ffi.typeof(addr) == ffi.typeof("long(*)(struct foo_s)") - -def test_issue198(): - ffi = FFI() - ffi.cdef(""" - typedef struct{...;} opaque_t; - const opaque_t CONSTANT; - int toint(opaque_t); - """) - lib = verify(ffi, 'test_issue198', """ - typedef int opaque_t; - #define CONSTANT ((opaque_t)42) - static int toint(opaque_t o) { return o; } - """) - def random_stuff(): - pass - assert lib.toint(lib.CONSTANT) == 42 - random_stuff() - assert lib.toint(lib.CONSTANT) == 42 - -def test_constant_is_not_a_compiler_constant(): - ffi = FFI() - ffi.cdef("static const float almost_forty_two;") - lib = verify(ffi, 'test_constant_is_not_a_compiler_constant', """ - static float f(void) { return 42.25; } - #define almost_forty_two (f()) - """) - assert lib.almost_forty_two == 42.25 - -def test_constant_of_unknown_size(): - ffi = FFI() - ffi.cdef(""" - typedef ... opaque_t; - const opaque_t CONSTANT; - """) - lib = verify(ffi, 'test_constant_of_unknown_size', - "typedef int opaque_t;" - "const int CONSTANT = 42;") - e = py.test.raises(ffi.error, getattr, lib, 'CONSTANT') - assert str(e.value) == ("constant 'CONSTANT' is of " - "type 'opaque_t', whose size is not known") - -def test_variable_of_unknown_size(): - ffi = FFI() - ffi.cdef(""" - typedef ... opaque_t; - extern opaque_t globvar; - """) - lib = verify(ffi, 'test_variable_of_unknown_size', """ - typedef char opaque_t[6]; - opaque_t globvar = "hello"; - """) - # can't read or write it at all - e = py.test.raises(TypeError, getattr, lib, 'globvar') - assert str(e.value) in ["cdata 'opaque_t' is opaque", - "'opaque_t' is opaque or not completed yet"] #pypy - e = py.test.raises(TypeError, setattr, lib, 'globvar', []) - assert str(e.value) in ["'opaque_t' is opaque", - "'opaque_t' is opaque or not completed yet"] #pypy - # but we can get its address - p = ffi.addressof(lib, 'globvar') - assert ffi.typeof(p) == ffi.typeof('opaque_t *') - assert ffi.string(ffi.cast("char *", p), 8) == b"hello" - -def test_constant_of_value_unknown_to_the_compiler(): - extra_c_source = udir.join( - 'extra_test_constant_of_value_unknown_to_the_compiler.c') - extra_c_source.write('const int external_foo = 42;\n') - ffi = FFI() - ffi.cdef("const int external_foo;") - lib = verify(ffi, 'test_constant_of_value_unknown_to_the_compiler', """ - extern const int external_foo; - """, sources=[str(extra_c_source)]) - assert lib.external_foo == 42 - -def test_dotdot_in_source_file_names(): - extra_c_source = udir.join( - 'extra_test_dotdot_in_source_file_names.c') - extra_c_source.write('const int external_foo = 42;\n') - ffi = FFI() - ffi.cdef("const int external_foo;") - lib = verify(ffi, 'test_dotdot_in_source_file_names', """ - extern const int external_foo; - """, sources=[os.path.join(os.path.dirname(str(extra_c_source)), - 'foobar', '..', - os.path.basename(str(extra_c_source)))]) - assert lib.external_foo == 42 - -def test_call_with_incomplete_structs(): - ffi = FFI() - ffi.cdef("typedef struct {...;} foo_t; " - "extern foo_t myglob; " - "foo_t increment(foo_t s); " - "double getx(foo_t s);") - lib = verify(ffi, 'test_call_with_incomplete_structs', """ - typedef double foo_t; - double myglob = 42.5; - double getx(double x) { return x; } - double increment(double x) { return x + 1; } - """) - assert lib.getx(lib.myglob) == 42.5 - assert lib.getx(lib.increment(lib.myglob)) == 43.5 - -def test_struct_array_guess_length_2(): - ffi = FFI() - ffi.cdef("struct foo_s { int a[...][...]; };") - lib = verify(ffi, 'test_struct_array_guess_length_2', - "struct foo_s { int x; int a[5][8]; int y; };") - assert ffi.sizeof('struct foo_s') == 42 * ffi.sizeof('int') - s = ffi.new("struct foo_s *") - assert ffi.typeof(s.a) == ffi.typeof("int[5][8]") - assert ffi.sizeof(s.a) == 40 * ffi.sizeof('int') - assert s.a[4][7] == 0 - with pytest.raises(IndexError): - s.a[4][8] - with pytest.raises(IndexError): - s.a[5][0] - assert ffi.typeof(s.a) == ffi.typeof("int[5][8]") - assert ffi.typeof(s.a[0]) == ffi.typeof("int[8]") - -def test_struct_array_guess_length_3(): - ffi = FFI() - ffi.cdef("struct foo_s { int a[][...]; };") - lib = verify(ffi, 'test_struct_array_guess_length_3', - "struct foo_s { int x; int a[5][7]; int y; };") - assert ffi.sizeof('struct foo_s') == 37 * ffi.sizeof('int') - s = ffi.new("struct foo_s *") - assert ffi.typeof(s.a) == ffi.typeof("int[][7]") - assert s.a[4][6] == 0 - with pytest.raises(IndexError): - s.a[4][7] - assert ffi.typeof(s.a[0]) == ffi.typeof("int[7]") - -def test_global_var_array_2(): - ffi = FFI() - ffi.cdef("extern int a[...][...];") - lib = verify(ffi, 'test_global_var_array_2', 'int a[10][8];') - lib.a[9][7] = 123456 - assert lib.a[9][7] == 123456 - with pytest.raises(IndexError): - lib.a[0][8] - with pytest.raises(IndexError): - lib.a[10][0] - assert ffi.typeof(lib.a) == ffi.typeof("int[10][8]") - assert ffi.typeof(lib.a[0]) == ffi.typeof("int[8]") - -def test_global_var_array_3(): - ffi = FFI() - ffi.cdef("extern int a[][...];") - lib = verify(ffi, 'test_global_var_array_3', 'int a[10][8];') - lib.a[9][7] = 123456 - assert lib.a[9][7] == 123456 - with pytest.raises(IndexError): - lib.a[0][8] - assert ffi.typeof(lib.a) == ffi.typeof("int(*)[8]") - assert ffi.typeof(lib.a[0]) == ffi.typeof("int[8]") - -def test_global_var_array_4(): - ffi = FFI() - ffi.cdef("extern int a[10][...];") - lib = verify(ffi, 'test_global_var_array_4', 'int a[10][8];') - lib.a[9][7] = 123456 - assert lib.a[9][7] == 123456 - with pytest.raises(IndexError): - lib.a[0][8] - with pytest.raises(IndexError): - lib.a[10][8] - assert ffi.typeof(lib.a) == ffi.typeof("int[10][8]") - assert ffi.typeof(lib.a[0]) == ffi.typeof("int[8]") - -def test_some_integer_type(): - ffi = FFI() - ffi.cdef(""" - typedef int... foo_t; - typedef unsigned long... bar_t; - typedef struct { foo_t a, b; } mystruct_t; - foo_t foobar(bar_t, mystruct_t); - static const bar_t mu = -20; - static const foo_t nu = 20; - """) - lib = verify(ffi, 'test_some_integer_type', """ - typedef unsigned long long foo_t; - typedef short bar_t; - typedef struct { foo_t a, b; } mystruct_t; - static foo_t foobar(bar_t x, mystruct_t s) { - return (foo_t)x + s.a + s.b; - } - static const bar_t mu = -20; - static const foo_t nu = 20; - """) - assert ffi.sizeof("foo_t") == ffi.sizeof("unsigned long long") - assert ffi.sizeof("bar_t") == ffi.sizeof("short") - maxulonglong = 2 ** 64 - 1 - assert int(ffi.cast("foo_t", -1)) == maxulonglong - assert int(ffi.cast("bar_t", -1)) == -1 - assert lib.foobar(-1, [0, 0]) == maxulonglong - assert lib.foobar(2 ** 15 - 1, [0, 0]) == 2 ** 15 - 1 - assert lib.foobar(10, [20, 31]) == 61 - assert lib.foobar(0, [0, maxulonglong]) == maxulonglong - py.test.raises(OverflowError, lib.foobar, 2 ** 15, [0, 0]) - py.test.raises(OverflowError, lib.foobar, -(2 ** 15) - 1, [0, 0]) - py.test.raises(OverflowError, ffi.new, "mystruct_t *", [0, -1]) - assert lib.mu == -20 - assert lib.nu == 20 - -def test_some_float_type(): - ffi = FFI() - ffi.cdef(""" - typedef double... foo_t; - typedef float... bar_t; - foo_t sum(foo_t[]); - bar_t neg(bar_t); - """) - lib = verify(ffi, 'test_some_float_type', """ - typedef float foo_t; - static foo_t sum(foo_t x[]) { return x[0] + x[1]; } - typedef double bar_t; - static double neg(double x) { return -x; } - """) - assert lib.sum([40.0, 2.25]) == 42.25 - assert lib.sum([12.3, 45.6]) != 12.3 + 45.6 # precision loss - assert lib.neg(12.3) == -12.3 # no precision loss - assert ffi.sizeof("foo_t") == ffi.sizeof("float") - assert ffi.sizeof("bar_t") == ffi.sizeof("double") - -def test_some_float_invalid_1(): - ffi = FFI() - py.test.raises((FFIError, # with pycparser <= 2.17 - CDefError), # with pycparser >= 2.18 - ffi.cdef, "typedef long double... foo_t;") - -def test_some_float_invalid_2(): - ffi = FFI() - ffi.cdef("typedef double... foo_t; foo_t neg(foo_t);") - lib = verify(ffi, 'test_some_float_invalid_2', """ - typedef unsigned long foo_t; - foo_t neg(foo_t x) { return -x; } - """) - e = py.test.raises(ffi.error, getattr, lib, 'neg') - assert str(e.value) == ("primitive floating-point type with an unexpected " - "size (or not a float type at all)") - -def test_some_float_invalid_3(): - ffi = FFI() - ffi.cdef("typedef double... foo_t; foo_t neg(foo_t);") - lib = verify(ffi, 'test_some_float_invalid_3', """ - typedef long double foo_t; - foo_t neg(foo_t x) { return -x; } - """, ignore_warnings=True) - if ffi.sizeof("long double") == ffi.sizeof("double"): - assert lib.neg(12.3) == -12.3 - else: - e = py.test.raises(ffi.error, getattr, lib, 'neg') - assert str(e.value) == ("primitive floating-point type is " - "'long double', not supported for now with " - "the syntax 'typedef double... xxx;'") - -def test_issue200(): - ffi = FFI() - ffi.cdef(""" - typedef void (function_t)(void*); - void function(void *); - """) - lib = verify(ffi, 'test_issue200', """ - static void function(void *p) { (void)p; } - """) - ffi.typeof('function_t*') - lib.function(ffi.NULL) - # assert did not crash - -def test_alignment_of_longlong(): - ffi = FFI() - x1 = ffi.alignof('unsigned long long') - assert x1 in [4, 8] - ffi.cdef("struct foo_s { unsigned long long x; };") - lib = verify(ffi, 'test_alignment_of_longlong', - "struct foo_s { unsigned long long x; };") - assert ffi.alignof('unsigned long long') == x1 - assert ffi.alignof('struct foo_s') == x1 - -def test_import_from_lib(): - ffi = FFI() - ffi.cdef("int mybar(int); static int myvar;\n#define MYFOO ...") - lib = verify(ffi, 'test_import_from_lib', - "#define MYFOO 42\n" - "static int mybar(int x) { return x + 1; }\n" - "static int myvar = -5;") - assert sys.modules['_CFFI_test_import_from_lib'].lib is lib - assert sys.modules['_CFFI_test_import_from_lib.lib'] is lib - from _CFFI_test_import_from_lib.lib import MYFOO - assert MYFOO == 42 - assert hasattr(lib, '__dict__') - assert lib.__all__ == ['MYFOO', 'mybar'] # but not 'myvar' - assert lib.__name__ == '_CFFI_test_import_from_lib.lib' - assert lib.__class__ is type(sys) # !! hack for help() - -def test_macro_var_callback(): - ffi = FFI() - ffi.cdef("extern int my_value; extern int *(*get_my_value)(void);") - lib = verify(ffi, 'test_macro_var_callback', - "int *(*get_my_value)(void);\n" - "#define my_value (*get_my_value())") - # - values = ffi.new("int[50]") - def it(): - for i in range(50): - yield i - it = it() - # - @ffi.callback("int *(*)(void)") - def get_my_value(): - for nextvalue in it: - return values + nextvalue - lib.get_my_value = get_my_value - # - values[0] = 41 - assert lib.my_value == 41 # [0] - p = ffi.addressof(lib, 'my_value') # [1] - assert p == values + 1 - assert p[-1] == 41 - assert p[+1] == 0 - lib.my_value = 42 # [2] - assert values[2] == 42 - assert p[-1] == 41 - assert p[+1] == 42 - # - # if get_my_value raises or returns nonsense, the exception is printed - # to stderr like with any callback, but then the C expression 'my_value' - # expand to '*NULL'. We assume here that '&my_value' will return NULL - # without segfaulting, and check for NULL when accessing the variable. - @ffi.callback("int *(*)(void)") - def get_my_value(): - raise LookupError - lib.get_my_value = get_my_value - py.test.raises(ffi.error, getattr, lib, 'my_value') - py.test.raises(ffi.error, setattr, lib, 'my_value', 50) - py.test.raises(ffi.error, ffi.addressof, lib, 'my_value') - @ffi.callback("int *(*)(void)") - def get_my_value(): - return "hello" - lib.get_my_value = get_my_value - py.test.raises(ffi.error, getattr, lib, 'my_value') - e = py.test.raises(ffi.error, setattr, lib, 'my_value', 50) - assert str(e.value) == "global variable 'my_value' is at address NULL" - -def test_const_fields(): - ffi = FFI() - ffi.cdef("""struct foo_s { const int a; void *const b; };""") - lib = verify(ffi, 'test_const_fields', """ - struct foo_s { const int a; void *const b; };""") - foo_s = ffi.typeof("struct foo_s") - assert foo_s.fields[0][0] == 'a' - assert foo_s.fields[0][1].type is ffi.typeof("int") - assert foo_s.fields[1][0] == 'b' - assert foo_s.fields[1][1].type is ffi.typeof("void *") - -def test_restrict_fields(): - ffi = FFI() - ffi.cdef("""struct foo_s { void * restrict b; };""") - lib = verify(ffi, 'test_restrict_fields', """ - struct foo_s { void * __restrict b; };""") - foo_s = ffi.typeof("struct foo_s") - assert foo_s.fields[0][0] == 'b' - assert foo_s.fields[0][1].type is ffi.typeof("void *") - -def test_volatile_fields(): - ffi = FFI() - ffi.cdef("""struct foo_s { void * volatile b; };""") - lib = verify(ffi, 'test_volatile_fields', """ - struct foo_s { void * volatile b; };""") - foo_s = ffi.typeof("struct foo_s") - assert foo_s.fields[0][0] == 'b' - assert foo_s.fields[0][1].type is ffi.typeof("void *") - -def test_const_array_fields(): - ffi = FFI() - ffi.cdef("""struct foo_s { const int a[4]; };""") - lib = verify(ffi, 'test_const_array_fields', """ - struct foo_s { const int a[4]; };""") - foo_s = ffi.typeof("struct foo_s") - assert foo_s.fields[0][0] == 'a' - assert foo_s.fields[0][1].type is ffi.typeof("int[4]") - -def test_const_array_fields_varlength(): - ffi = FFI() - ffi.cdef("""struct foo_s { const int a[]; ...; };""") - lib = verify(ffi, 'test_const_array_fields_varlength', """ - struct foo_s { const int a[4]; };""") - foo_s = ffi.typeof("struct foo_s") - assert foo_s.fields[0][0] == 'a' - assert foo_s.fields[0][1].type is ffi.typeof("int[]") - -def test_const_array_fields_unknownlength(): - ffi = FFI() - ffi.cdef("""struct foo_s { const int a[...]; ...; };""") - lib = verify(ffi, 'test_const_array_fields_unknownlength', """ - struct foo_s { const int a[4]; };""") - foo_s = ffi.typeof("struct foo_s") - assert foo_s.fields[0][0] == 'a' - assert foo_s.fields[0][1].type is ffi.typeof("int[4]") - -def test_const_function_args(): - ffi = FFI() - ffi.cdef("""int foobar(const int a, const int *b, const int c[]);""") - lib = verify(ffi, 'test_const_function_args', """ - int foobar(const int a, const int *b, const int c[]) { - return a + *b + *c; - } - """) - assert lib.foobar(100, ffi.new("int *", 40), ffi.new("int *", 2)) == 142 - -def test_const_function_type_args(): - ffi = FFI() - ffi.cdef("""extern int(*foobar)(const int a,const int*b,const int c[]);""") - lib = verify(ffi, 'test_const_function_type_args', """ - int (*foobar)(const int a, const int *b, const int c[]); - """) - t = ffi.typeof(lib.foobar) - assert t.args[0] is ffi.typeof("int") - assert t.args[1] is ffi.typeof("int *") - assert t.args[2] is ffi.typeof("int *") - -def test_const_constant(): - ffi = FFI() - ffi.cdef("""struct foo_s { int x,y; }; const struct foo_s myfoo;""") - lib = verify(ffi, 'test_const_constant', """ - struct foo_s { int x,y; }; const struct foo_s myfoo = { 40, 2 }; - """) - assert lib.myfoo.x == 40 - assert lib.myfoo.y == 2 - -def test_const_via_typedef(): - ffi = FFI() - ffi.cdef("""typedef const int const_t; const_t aaa;""") - lib = verify(ffi, 'test_const_via_typedef', """ - typedef const int const_t; - #define aaa 42 - """) - assert lib.aaa == 42 - with pytest.raises(AttributeError): - lib.aaa = 43 - -def test_win32_calling_convention_0(): - ffi = FFI() - ffi.cdef(""" - int call1(int(__cdecl *cb)(int)); - int (*const call2)(int(__stdcall *cb)(int)); - """) - lib = verify(ffi, 'test_win32_calling_convention_0', r""" - #ifndef _MSC_VER - # define __stdcall /* nothing */ - #endif - int call1(int(*cb)(int)) { - int i, result = 0; - //printf("call1: cb = %p\n", cb); - for (i = 0; i < 1000; i++) - result += cb(i); - //printf("result = %d\n", result); - return result; - } - int call2(int(__stdcall *cb)(int)) { - int i, result = 0; - //printf("call2: cb = %p\n", cb); - for (i = 0; i < 1000; i++) - result += cb(-i); - //printf("result = %d\n", result); - return result; - } - """) - @ffi.callback("int(int)") - def cb1(x): - return x * 2 - @ffi.callback("int __stdcall(int)") - def cb2(x): - return x * 3 - res = lib.call1(cb1) - assert res == 500*999*2 - assert res == ffi.addressof(lib, 'call1')(cb1) - res = lib.call2(cb2) - assert res == -500*999*3 - assert res == ffi.addressof(lib, 'call2')(cb2) - if sys.platform == 'win32' and not sys.maxsize > 2**32: - assert '__stdcall' in str(ffi.typeof(cb2)) - assert '__stdcall' not in str(ffi.typeof(cb1)) - py.test.raises(TypeError, lib.call1, cb2) - py.test.raises(TypeError, lib.call2, cb1) - else: - assert '__stdcall' not in str(ffi.typeof(cb2)) - assert ffi.typeof(cb2) is ffi.typeof(cb1) - -def test_win32_calling_convention_1(): - ffi = FFI() - ffi.cdef(""" - int __cdecl call1(int(__cdecl *cb)(int)); - int __stdcall call2(int(__stdcall *cb)(int)); - int (__cdecl *const cb1)(int); - int (__stdcall *const cb2)(int); - """) - lib = verify(ffi, 'test_win32_calling_convention_1', r""" - #ifndef _MSC_VER - # define __cdecl - # define __stdcall - #endif - int __cdecl cb1(int x) { return x * 2; } - int __stdcall cb2(int x) { return x * 3; } - - int __cdecl call1(int(__cdecl *cb)(int)) { - int i, result = 0; - //printf("here1\n"); - //printf("cb = %p, cb1 = %p\n", cb, (void *)cb1); - for (i = 0; i < 1000; i++) - result += cb(i); - //printf("result = %d\n", result); - return result; - } - int __stdcall call2(int(__stdcall *cb)(int)) { - int i, result = 0; - //printf("here1\n"); - //printf("cb = %p, cb2 = %p\n", cb, (void *)cb2); - for (i = 0; i < 1000; i++) - result += cb(-i); - //printf("result = %d\n", result); - return result; - } - """) - #print '<<< cb1 =', ffi.addressof(lib, 'cb1') - ptr_call1 = ffi.addressof(lib, 'call1') - assert lib.call1(ffi.addressof(lib, 'cb1')) == 500*999*2 - assert ptr_call1(ffi.addressof(lib, 'cb1')) == 500*999*2 - #print '<<< cb2 =', ffi.addressof(lib, 'cb2') - ptr_call2 = ffi.addressof(lib, 'call2') - assert lib.call2(ffi.addressof(lib, 'cb2')) == -500*999*3 - assert ptr_call2(ffi.addressof(lib, 'cb2')) == -500*999*3 - #print '<<< done' - -def test_win32_calling_convention_2(): - # any mistake in the declaration of plain function (including the - # precise argument types and, here, the calling convention) are - # automatically corrected. But this does not apply to the 'cb' - # function pointer argument. - ffi = FFI() - ffi.cdef(""" - int __stdcall call1(int(__cdecl *cb)(int)); - int __cdecl call2(int(__stdcall *cb)(int)); - int (__cdecl *const cb1)(int); - int (__stdcall *const cb2)(int); - """) - lib = verify(ffi, 'test_win32_calling_convention_2', """ - #ifndef _MSC_VER - # define __cdecl - # define __stdcall - #endif - int __cdecl call1(int(__cdecl *cb)(int)) { - int i, result = 0; - for (i = 0; i < 1000; i++) - result += cb(i); - return result; - } - int __stdcall call2(int(__stdcall *cb)(int)) { - int i, result = 0; - for (i = 0; i < 1000; i++) - result += cb(-i); - return result; - } - int __cdecl cb1(int x) { return x * 2; } - int __stdcall cb2(int x) { return x * 3; } - """) - ptr_call1 = ffi.addressof(lib, 'call1') - ptr_call2 = ffi.addressof(lib, 'call2') - if sys.platform == 'win32' and not sys.maxsize > 2**32: - py.test.raises(TypeError, lib.call1, ffi.addressof(lib, 'cb2')) - py.test.raises(TypeError, ptr_call1, ffi.addressof(lib, 'cb2')) - py.test.raises(TypeError, lib.call2, ffi.addressof(lib, 'cb1')) - py.test.raises(TypeError, ptr_call2, ffi.addressof(lib, 'cb1')) - assert lib.call1(ffi.addressof(lib, 'cb1')) == 500*999*2 - assert ptr_call1(ffi.addressof(lib, 'cb1')) == 500*999*2 - assert lib.call2(ffi.addressof(lib, 'cb2')) == -500*999*3 - assert ptr_call2(ffi.addressof(lib, 'cb2')) == -500*999*3 - -def test_win32_calling_convention_3(): - ffi = FFI() - ffi.cdef(""" - struct point { int x, y; }; - - int (*const cb1)(struct point); - int (__stdcall *const cb2)(struct point); - - struct point __stdcall call1(int(*cb)(struct point)); - struct point call2(int(__stdcall *cb)(struct point)); - """) - lib = verify(ffi, 'test_win32_calling_convention_3', r""" - #ifndef _MSC_VER - # define __cdecl - # define __stdcall - #endif - struct point { int x, y; }; - int cb1(struct point pt) { return pt.x + 10 * pt.y; } - int __stdcall cb2(struct point pt) { return pt.x + 100 * pt.y; } - struct point __stdcall call1(int(__cdecl *cb)(struct point)) { - int i; - struct point result = { 0, 0 }; - //printf("here1\n"); - //printf("cb = %p, cb1 = %p\n", cb, (void *)cb1); - for (i = 0; i < 1000; i++) { - struct point p = { i, -i }; - int r = cb(p); - result.x += r; - result.y -= r; - } - return result; - } - struct point __cdecl call2(int(__stdcall *cb)(struct point)) { - int i; - struct point result = { 0, 0 }; - for (i = 0; i < 1000; i++) { - struct point p = { -i, i }; - int r = cb(p); - result.x += r; - result.y -= r; - } - return result; - } - """) - ptr_call1 = ffi.addressof(lib, 'call1') - ptr_call2 = ffi.addressof(lib, 'call2') - if sys.platform == 'win32' and not sys.maxsize > 2**32: - py.test.raises(TypeError, lib.call1, ffi.addressof(lib, 'cb2')) - py.test.raises(TypeError, ptr_call1, ffi.addressof(lib, 'cb2')) - py.test.raises(TypeError, lib.call2, ffi.addressof(lib, 'cb1')) - py.test.raises(TypeError, ptr_call2, ffi.addressof(lib, 'cb1')) - pt = lib.call1(ffi.addressof(lib, 'cb1')) - assert (pt.x, pt.y) == (-9*500*999, 9*500*999) - pt = ptr_call1(ffi.addressof(lib, 'cb1')) - assert (pt.x, pt.y) == (-9*500*999, 9*500*999) - pt = lib.call2(ffi.addressof(lib, 'cb2')) - assert (pt.x, pt.y) == (99*500*999, -99*500*999) - pt = ptr_call2(ffi.addressof(lib, 'cb2')) - assert (pt.x, pt.y) == (99*500*999, -99*500*999) - -def test_extern_python_1(): - import warnings - ffi = FFI() - with warnings.catch_warnings(record=True) as log: - ffi.cdef(""" - extern "Python" { - int bar(int, int); - void baz(int, int); - int bok(void); - void boz(void); - } - """) - assert len(log) == 0, "got a warning: %r" % (log,) - lib = verify(ffi, 'test_extern_python_1', """ - static void baz(int, int); /* forward */ - """) - assert ffi.typeof(lib.bar) == ffi.typeof("int(*)(int, int)") - with FdWriteCapture() as f: - res = lib.bar(4, 5) - assert res == 0 - assert f.getvalue() == ( - b"extern \"Python\": function _CFFI_test_extern_python_1.bar() called, " - b"but no code was attached " - b"to it yet with @ffi.def_extern(). Returning 0.\n") - - @ffi.def_extern("bar") - def my_bar(x, y): - seen.append(("Bar", x, y)) - return x * y - assert my_bar != lib.bar - seen = [] - res = lib.bar(6, 7) - assert seen == [("Bar", 6, 7)] - assert res == 42 - - def baz(x, y): - seen.append(("Baz", x, y)) - baz1 = ffi.def_extern()(baz) - assert baz1 is baz - seen = [] - baz(long(40), long(4)) - res = lib.baz(long(50), long(8)) - assert res is None - assert seen == [("Baz", 40, 4), ("Baz", 50, 8)] - assert type(seen[0][1]) is type(seen[0][2]) is long - assert type(seen[1][1]) is type(seen[1][2]) is int - - @ffi.def_extern(name="bok") - def bokk(): - seen.append("Bok") - return 42 - seen = [] - assert lib.bok() == 42 - assert seen == ["Bok"] - - @ffi.def_extern() - def boz(): - seen.append("Boz") - seen = [] - assert lib.boz() is None - assert seen == ["Boz"] - -def test_extern_python_bogus_name(): - ffi = FFI() - ffi.cdef("extern int abc;") - lib = verify(ffi, 'test_extern_python_bogus_name', "int abc;") - def fn(): - pass - py.test.raises(ffi.error, ffi.def_extern("unknown_name"), fn) - py.test.raises(ffi.error, ffi.def_extern("abc"), fn) - assert lib.abc == 0 - e = py.test.raises(ffi.error, ffi.def_extern("abc"), fn) - assert str(e.value) == ("ffi.def_extern('abc'): no 'extern \"Python\"' " - "function with this name") - e = py.test.raises(ffi.error, ffi.def_extern(), fn) - assert str(e.value) == ("ffi.def_extern('fn'): no 'extern \"Python\"' " - "function with this name") - # - py.test.raises(TypeError, ffi.def_extern(42), fn) - py.test.raises((TypeError, AttributeError), ffi.def_extern(), "foo") - class X: - pass - x = X() - x.__name__ = x - py.test.raises(TypeError, ffi.def_extern(), x) - -def test_extern_python_bogus_result_type(): - ffi = FFI() - ffi.cdef("""extern "Python" void bar(int);""") - lib = verify(ffi, 'test_extern_python_bogus_result_type', "") - # - @ffi.def_extern() - def bar(n): - return n * 10 - with StdErrCapture() as f: - res = lib.bar(321) - assert res is None - msg = f.getvalue() - assert "rom cffi callback %r" % (bar,) in msg - assert "rying to convert the result back to C:\n" in msg - assert msg.endswith( - "TypeError: callback with the return type 'void' must return None\n") - -def test_extern_python_redefine(): - ffi = FFI() - ffi.cdef("""extern "Python" int bar(int);""") - lib = verify(ffi, 'test_extern_python_redefine', "") - # - @ffi.def_extern() - def bar(n): - return n * 10 - assert lib.bar(42) == 420 - # - @ffi.def_extern() - def bar(n): - return -n - assert lib.bar(42) == -42 - -def test_extern_python_struct(): - ffi = FFI() - ffi.cdef(""" - struct foo_s { int a, b, c; }; - extern "Python" int bar(int, struct foo_s, int); - extern "Python" { struct foo_s baz(int, int); - struct foo_s bok(void); } - """) - lib = verify(ffi, 'test_extern_python_struct', - "struct foo_s { int a, b, c; };") - # - @ffi.def_extern() - def bar(x, s, z): - return x + s.a + s.b + s.c + z - res = lib.bar(1000, [1001, 1002, 1004], 1008) - assert res == 5015 - # - @ffi.def_extern() - def baz(x, y): - return [x + y, x - y, x * y] - res = lib.baz(1000, 42) - assert res.a == 1042 - assert res.b == 958 - assert res.c == 42000 - # - @ffi.def_extern() - def bok(): - return [10, 20, 30] - res = lib.bok() - assert [res.a, res.b, res.c] == [10, 20, 30] - -def test_extern_python_long_double(): - ffi = FFI() - ffi.cdef(""" - extern "Python" int bar(int, long double, int); - extern "Python" long double baz(int, int); - extern "Python" long double bok(void); - """) - lib = verify(ffi, 'test_extern_python_long_double', "") - # - @ffi.def_extern() - def bar(x, l, z): - seen.append((x, l, z)) - return 6 - seen = [] - lib.bar(10, 3.5, 20) - expected = ffi.cast("long double", 3.5) - assert repr(seen) == repr([(10, expected, 20)]) - # - @ffi.def_extern() - def baz(x, z): - assert x == 10 and z == 20 - return expected - res = lib.baz(10, 20) - assert repr(res) == repr(expected) - # - @ffi.def_extern() - def bok(): - return expected - res = lib.bok() - assert repr(res) == repr(expected) - -def test_extern_python_signature(): - ffi = FFI() - lib = verify(ffi, 'test_extern_python_signature', "") - py.test.raises(TypeError, ffi.def_extern(425), None) - py.test.raises(TypeError, ffi.def_extern, 'a', 'b', 'c', 'd') - -def test_extern_python_errors(): - ffi = FFI() - ffi.cdef(""" - extern "Python" int bar(int); - """) - lib = verify(ffi, 'test_extern_python_errors', "") - - seen = [] - def oops(*args): - seen.append(args) - - @ffi.def_extern(onerror=oops) - def bar(x): - return x + "" - assert lib.bar(10) == 0 - - @ffi.def_extern(name="bar", onerror=oops, error=-66) - def bar2(x): - return x + "" - assert lib.bar(10) == -66 - - assert len(seen) == 2 - exc, val, tb = seen[0] - assert exc is TypeError - assert isinstance(val, TypeError) - assert tb.tb_frame.f_code.co_name == "bar" - exc, val, tb = seen[1] - assert exc is TypeError - assert isinstance(val, TypeError) - assert tb.tb_frame.f_code.co_name == "bar2" - # - # a case where 'onerror' is not callable - py.test.raises(TypeError, ffi.def_extern(name='bar', onerror=42), - lambda x: x) - -def test_extern_python_stdcall(): - ffi = FFI() - ffi.cdef(""" - extern "Python" int __stdcall foo(int); - extern "Python" int WINAPI bar(int); - static int (__stdcall * mycb1)(int); - static int indirect_call(int); - """) - lib = verify(ffi, 'test_extern_python_stdcall', """ - #ifndef _MSC_VER - # define __stdcall - #endif - static int (__stdcall * mycb1)(int); - static int indirect_call(int x) { - return mycb1(x); - } - """) - # - @ffi.def_extern() - def foo(x): - return x + 42 - @ffi.def_extern() - def bar(x): - return x + 43 - assert lib.foo(100) == 142 - assert lib.bar(100) == 143 - lib.mycb1 = lib.foo - assert lib.mycb1(200) == 242 - assert lib.indirect_call(300) == 342 - -def test_extern_python_plus_c(): - ffi = FFI() - ffi.cdef(""" - extern "Python+C" int foo(int); - extern "C +\tPython" int bar(int); - int call_me(int); - """) - lib = verify(ffi, 'test_extern_python_plus_c', """ - int foo(int); - #ifdef __GNUC__ - __attribute__((visibility("hidden"))) - #endif - int bar(int); - - static int call_me(int x) { - return foo(x) - bar(x); - } - """) - # - @ffi.def_extern() - def foo(x): - return x * 42 - @ffi.def_extern() - def bar(x): - return x * 63 - assert lib.foo(100) == 4200 - assert lib.bar(100) == 6300 - assert lib.call_me(100) == -2100 - -def test_introspect_function(): - ffi = FFI() - ffi.cdef("float f1(double);") - lib = verify(ffi, 'test_introspect_function', """ - float f1(double x) { return (float)x; } - """) - assert dir(lib) == ['f1'] - FUNC = ffi.typeof(lib.f1) - assert FUNC.kind == 'function' - assert FUNC.args[0].cname == 'double' - assert FUNC.result.cname == 'float' - assert ffi.typeof(ffi.addressof(lib, 'f1')) is FUNC - -def test_introspect_global_var(): - ffi = FFI() - ffi.cdef("extern float g1;") - lib = verify(ffi, 'test_introspect_global_var', """ - float g1; - """) - assert dir(lib) == ['g1'] - FLOATPTR = ffi.typeof(ffi.addressof(lib, 'g1')) - assert FLOATPTR.kind == 'pointer' - assert FLOATPTR.item.cname == 'float' - -def test_introspect_global_var_array(): - ffi = FFI() - ffi.cdef("extern float g1[100];") - lib = verify(ffi, 'test_introspect_global_var_array', """ - float g1[100]; - """) - assert dir(lib) == ['g1'] - FLOATARRAYPTR = ffi.typeof(ffi.addressof(lib, 'g1')) - assert FLOATARRAYPTR.kind == 'pointer' - assert FLOATARRAYPTR.item.kind == 'array' - assert FLOATARRAYPTR.item.length == 100 - assert ffi.typeof(lib.g1) is FLOATARRAYPTR.item - -def test_introspect_integer_const(): - ffi = FFI() - ffi.cdef("#define FOO 42") - lib = verify(ffi, 'test_introspect_integer_const', """ - #define FOO 42 - """) - assert dir(lib) == ['FOO'] - assert lib.FOO == ffi.integer_const('FOO') == 42 - -def test_introspect_typedef(): - ffi = FFI() - ffi.cdef("typedef int foo_t;") - lib = verify(ffi, 'test_introspect_typedef', """ - typedef int foo_t; - """) - assert ffi.list_types() == (['foo_t'], [], []) - assert ffi.typeof('foo_t').kind == 'primitive' - assert ffi.typeof('foo_t').cname == 'int' - -def test_introspect_typedef_multiple(): - ffi = FFI() - ffi.cdef("typedef signed char a_t, c_t, g_t, b_t;") - lib = verify(ffi, 'test_introspect_typedef_multiple', """ - typedef signed char a_t, c_t, g_t, b_t; - """) - assert ffi.list_types() == (['a_t', 'b_t', 'c_t', 'g_t'], [], []) - -def test_introspect_struct(): - ffi = FFI() - ffi.cdef("struct foo_s { int a; };") - lib = verify(ffi, 'test_introspect_struct', """ - struct foo_s { int a; }; - """) - assert ffi.list_types() == ([], ['foo_s'], []) - assert ffi.typeof('struct foo_s').kind == 'struct' - assert ffi.typeof('struct foo_s').cname == 'struct foo_s' - -def test_introspect_union(): - ffi = FFI() - ffi.cdef("union foo_s { int a; };") - lib = verify(ffi, 'test_introspect_union', """ - union foo_s { int a; }; - """) - assert ffi.list_types() == ([], [], ['foo_s']) - assert ffi.typeof('union foo_s').kind == 'union' - assert ffi.typeof('union foo_s').cname == 'union foo_s' - -def test_introspect_struct_and_typedef(): - ffi = FFI() - ffi.cdef("typedef struct { int a; } foo_t;") - lib = verify(ffi, 'test_introspect_struct_and_typedef', """ - typedef struct { int a; } foo_t; - """) - assert ffi.list_types() == (['foo_t'], [], []) - assert ffi.typeof('foo_t').kind == 'struct' - assert ffi.typeof('foo_t').cname == 'foo_t' - -def test_introspect_included_type(): - SOURCE = """ - typedef signed char schar_t; - struct sint_t { int x; }; - """ - ffi1 = FFI() - ffi1.cdef(SOURCE) - ffi2 = FFI() - ffi2.include(ffi1) - verify(ffi1, "test_introspect_included_type_parent", SOURCE) - verify(ffi2, "test_introspect_included_type", SOURCE) - assert ffi1.list_types() == ffi2.list_types() == ( - ['schar_t'], ['sint_t'], []) - -def test_introspect_order(): - ffi = FFI() - ffi.cdef("union CFFIaaa { int a; }; typedef struct CFFIccc { int a; } CFFIb;") - ffi.cdef("union CFFIg { int a; }; typedef struct CFFIcc { int a; } CFFIbbb;") - ffi.cdef("union CFFIaa { int a; }; typedef struct CFFIa { int a; } CFFIbb;") - verify(ffi, "test_introspect_order", """ - union CFFIaaa { int a; }; typedef struct CFFIccc { int a; } CFFIb; - union CFFIg { int a; }; typedef struct CFFIcc { int a; } CFFIbbb; - union CFFIaa { int a; }; typedef struct CFFIa { int a; } CFFIbb; - """) - assert ffi.list_types() == (['CFFIb', 'CFFIbb', 'CFFIbbb'], - ['CFFIa', 'CFFIcc', 'CFFIccc'], - ['CFFIaa', 'CFFIaaa', 'CFFIg']) - -def test_bool_in_cpp(): - # this works when compiled as C, but in cffi < 1.7 it fails as C++ - ffi = FFI() - ffi.cdef("bool f(void);") - lib = verify(ffi, "test_bool_in_cpp", "char f(void) { return 2; }") - assert lib.f() is True - -def test_bool_in_cpp_2(): - ffi = FFI() - ffi.cdef('int add(int a, int b);') - lib = verify(ffi, "test_bool_bug_cpp", ''' - typedef bool _Bool; /* there is a Windows header with this line */ - int add(int a, int b) - { - return a + b; - }''', source_extension='.cpp') - c = lib.add(2, 3) - assert c == 5 - -def test_struct_field_opaque(): - ffi = FFI() - ffi.cdef("struct a { struct b b; };") - e = py.test.raises(TypeError, verify, - ffi, "test_struct_field_opaque", "?") - assert str(e.value) == ("struct a: field 'a.b' is of an opaque" - " type (not declared in cdef())") - ffi = FFI() - ffi.cdef("struct a { struct b b[2]; };") - e = py.test.raises(TypeError, verify, - ffi, "test_struct_field_opaque", "?") - assert str(e.value) == ("struct a: field 'a.b' is of an opaque" - " type (not declared in cdef())") - ffi = FFI() - ffi.cdef("struct a { struct b b[]; };") - e = py.test.raises(TypeError, verify, - ffi, "test_struct_field_opaque", "?") - assert str(e.value) == ("struct a: field 'a.b' is of an opaque" - " type (not declared in cdef())") - -def test_function_arg_opaque(): - py.test.skip("can currently declare a function with an opaque struct " - "as argument, but AFAICT it's impossible to call it later") - -def test_function_returns_opaque(): - ffi = FFI() - ffi.cdef("struct a foo(int);") - e = py.test.raises(TypeError, verify, - ffi, "test_function_returns_opaque", "?") - assert str(e.value) == ("function foo: 'struct a' is used as result type," - " but is opaque") - -def test_function_returns_union(): - ffi = FFI() - ffi.cdef("union u1 { int a, b; }; union u1 f1(int);") - lib = verify(ffi, "test_function_returns_union", """ - union u1 { int a, b; }; - static union u1 f1(int x) { union u1 u; u.b = x; return u; } - """) - assert lib.f1(51).a == 51 - -def test_function_returns_partial_struct(): - ffi = FFI() - ffi.cdef("struct aaa { int a; ...; }; struct aaa f1(int);") - lib = verify(ffi, "test_function_returns_partial_struct", """ - struct aaa { int b, a, c; }; - static struct aaa f1(int x) { struct aaa s = {0}; s.a = x; return s; } - """) - assert lib.f1(52).a == 52 - -def test_function_returns_float_complex(): - if sys.platform == 'win32': - py.test.skip("MSVC may not support _Complex") - ffi = FFI() - ffi.cdef("float _Complex f1(float a, float b);"); - lib = verify(ffi, "test_function_returns_float_complex", """ - #include <complex.h> - static float _Complex f1(float a, float b) { return a + I*2.0f*b; } - """, no_cpp=True) # <complex.h> fails on some systems with C++ - result = lib.f1(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 - -def test_function_returns_double_complex(): - if sys.platform == 'win32': - py.test.skip("MSVC may not support _Complex") - ffi = FFI() - ffi.cdef("double _Complex f1(double a, double b);"); - lib = verify(ffi, "test_function_returns_double_complex", """ - #include <complex.h> - static double _Complex f1(double a, double b) { return a + I*2.0*b; } - """, no_cpp=True) # <complex.h> fails on some systems with C++ - result = lib.f1(1.25, 5.1) - assert type(result) == complex - assert result.real == 1.25 # exact - assert result.imag == 2*5.1 # exact - -def test_function_argument_float_complex(): - if sys.platform == 'win32': - py.test.skip("MSVC may not support _Complex") - ffi = FFI() - ffi.cdef("float f1(float _Complex x);"); - lib = verify(ffi, "test_function_argument_float_complex", """ - #include <complex.h> - static float f1(float _Complex x) { return cabsf(x); } - """, no_cpp=True) # <complex.h> fails on some systems with C++ - x = complex(12.34, 56.78) - result = lib.f1(x) - assert abs(result - abs(x)) < 1e-5 - -def test_function_argument_double_complex(): - if sys.platform == 'win32': - py.test.skip("MSVC may not support _Complex") - ffi = FFI() - ffi.cdef("double f1(double _Complex);"); - lib = verify(ffi, "test_function_argument_double_complex", """ - #include <complex.h> - static double f1(double _Complex x) { return cabs(x); } - """, no_cpp=True) # <complex.h> fails on some systems with C++ - x = complex(12.34, 56.78) - result = lib.f1(x) - assert abs(result - abs(x)) < 1e-11 - -def test_typedef_array_dotdotdot(): - ffi = FFI() - ffi.cdef(""" - typedef int foo_t[...], bar_t[...]; - extern int gv[...]; - typedef int mat_t[...][...]; - typedef int vmat_t[][...]; - """) - lib = verify(ffi, "test_typedef_array_dotdotdot", """ - typedef int foo_t[50], bar_t[50]; - int gv[23]; - typedef int mat_t[6][7]; - typedef int vmat_t[][8]; - """) - assert ffi.sizeof("foo_t") == 50 * ffi.sizeof("int") - assert ffi.sizeof("bar_t") == 50 * ffi.sizeof("int") - assert len(ffi.new("foo_t")) == 50 - assert len(ffi.new("bar_t")) == 50 - assert ffi.sizeof(lib.gv) == 23 * ffi.sizeof("int") - assert ffi.sizeof("mat_t") == 6 * 7 * ffi.sizeof("int") - assert len(ffi.new("mat_t")) == 6 - assert len(ffi.new("mat_t")[3]) == 7 - py.test.raises(ffi.error, ffi.sizeof, "vmat_t") - p = ffi.new("vmat_t", 4) - assert ffi.sizeof(p[3]) == 8 * ffi.sizeof("int") - -def test_typedef_array_dotdotdot_usage(): - ffi = FFI() - ffi.cdef(""" - typedef int foo_t[...]; - typedef int mat_t[...][...]; - struct s { foo_t a; foo_t *b; foo_t **c; }; - int myfunc(foo_t a, foo_t *b, foo_t **c); - struct sm { mat_t a; mat_t *b; mat_t **c; }; - int myfuncm(mat_t a, mat_t *b, mat_t **c); - """) - lib = verify(ffi, "test_typedef_array_dotdotdot_usage", """ - typedef int foo_t[50]; - typedef int mat_t[6][7]; - struct s { foo_t a; foo_t *b; foo_t **c; }; - static int myfunc(foo_t a, foo_t *b, foo_t **c) { return (**c)[49]; } - struct sm { mat_t a; mat_t *b; mat_t **c; }; - static int myfuncm(mat_t a, mat_t *b, mat_t **c) { return (**c)[5][6]; } - """) - assert ffi.sizeof("foo_t") == 50 * ffi.sizeof("int") - p = ffi.new("struct s *") - assert ffi.sizeof(p[0]) == 50 * ffi.sizeof("int") + 2 * ffi.sizeof("void *") - p.a[49] = 321 - p.b = ffi.addressof(p, 'a') - p.c = ffi.addressof(p, 'b') - assert lib.myfunc(ffi.NULL, ffi.NULL, p.c) == 321 - # - assert ffi.sizeof("mat_t") == 42 * ffi.sizeof("int") - p = ffi.new("struct sm *") - assert ffi.sizeof(p[0]) == 42 * ffi.sizeof("int") + 2 * ffi.sizeof("void *") - p.a[5][6] = -321 - p.b = ffi.addressof(p, 'a') - p.c = ffi.addressof(p, 'b') - assert lib.myfuncm(ffi.NULL, ffi.NULL, p.c) == -321 - -def test_call_with_custom_field_pos(): - ffi = FFI() - ffi.cdef(""" - struct foo { int x; ...; }; - struct foo f(void); - struct foo g(int, ...); - """) - lib = verify(ffi, "test_call_with_custom_field_pos", """ - struct foo { int y, x; }; - struct foo f(void) { - struct foo s = { 40, 200 }; - return s; - } - struct foo g(int a, ...) { return f(); } - """) - assert lib.f().x == 200 - e = py.test.raises(NotImplementedError, lib.g, 0) - assert str(e.value) == ( - 'ctype \'struct foo\' not supported as return value. 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 return value if the function is \'API mode\' and non-variadic ' - '(i.e. declared inside ffibuilder.cdef()+ffibuilder.set_source() ' - 'and not taking a final \'...\' argument)') - -def test_call_with_nested_anonymous_struct(): - if sys.platform == 'win32': - py.test.skip("needs a GCC extension") - ffi = FFI() - ffi.cdef(""" - struct foo { int a; union { int b, c; }; }; - struct foo f(void); - struct foo g(int, ...); - """) - lib = verify(ffi, "test_call_with_nested_anonymous_struct", """ - struct foo { int a; union { int b, c; }; }; - struct foo f(void) { - struct foo s; - s.a = 40; - s.b = 200; - return s; - } - struct foo g(int a, ...) { return f(); } - """) - assert lib.f().b == 200 - e = py.test.raises(NotImplementedError, lib.g, 0) - assert str(e.value) == ( - 'ctype \'struct foo\' not supported as return value. 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 return value if the function is \'API mode\' and non-variadic ' - '(i.e. declared inside ffibuilder.cdef()+ffibuilder.set_source() ' - 'and not taking a final \'...\' argument)') - -def test_call_with_bitfield(): - ffi = FFI() - ffi.cdef(""" - struct foo { int x:5; }; - struct foo f(void); - struct foo g(int, ...); - """) - lib = verify(ffi, "test_call_with_bitfield", """ - struct foo { int x:5; }; - struct foo f(void) { - struct foo s = { 11 }; - return s; - } - struct foo g(int a, ...) { return f(); } - """) - assert lib.f().x == 11 - e = py.test.raises(NotImplementedError, lib.g, 0) - assert str(e.value) == ( - "ctype 'struct foo' not supported as return value. It is a struct " - "with bit fields, which libffi does not support. Such structs are " - "only supported as return value if the function is 'API mode' and " - "non-variadic (i.e. declared inside ffibuilder.cdef()+ffibuilder." - "set_source() and not taking a final '...' argument)") - -def test_call_with_zero_length_field(): - if sys.platform == 'win32': - py.test.skip("zero-length field not supported by MSVC") - ffi = FFI() - ffi.cdef(""" - struct foo { int a; int x[0]; }; - struct foo f(void); - struct foo g(int, ...); - """) - lib = verify(ffi, "test_call_with_zero_length_field", """ - struct foo { int a; int x[0]; }; - struct foo f(void) { - struct foo s = { 42 }; - return s; - } - struct foo g(int a, ...) { return f(); } - """) - assert lib.f().a == 42 - e = py.test.raises(NotImplementedError, lib.g, 0) - assert str(e.value) == ( - "ctype 'struct foo' not supported as return value. It is a " - "struct with a zero-length array, which libffi does not support." - " Such structs are only supported as return value if the function is " - "'API mode' and non-variadic (i.e. declared inside ffibuilder.cdef()" - "+ffibuilder.set_source() and not taking a final '...' argument)") - -def test_call_with_union(): - ffi = FFI() - ffi.cdef(""" - union foo { int a; char b; }; - union foo f(void); - union foo g(int, ...); - """) - lib = verify(ffi, "test_call_with_union", """ - union foo { int a; char b; }; - union foo f(void) { - union foo s = { 42 }; - return s; - } - union foo g(int a, ...) { return f(); } - """) - assert lib.f().a == 42 - e = py.test.raises(NotImplementedError, lib.g, 0) - assert str(e.value) == ( - "ctype 'union foo' not supported as return value by libffi. " - "Unions are only supported as return value if the function is " - "'API mode' and non-variadic (i.e. declared inside ffibuilder.cdef()" - "+ffibuilder.set_source() and not taking a final '...' argument)") - -def test_call_with_packed_struct(): - if sys.platform == 'win32': - py.test.skip("needs a GCC extension") - ffi = FFI() - ffi.cdef(""" - struct foo { char y; int x; }; - struct foo f(void); - struct foo g(int, ...); - """, packed=True) - lib = verify(ffi, "test_call_with_packed_struct", """ - struct foo { char y; int x; } __attribute__((packed)); - struct foo f(void) { - struct foo s = { 40, 200 }; - return s; - } - struct foo g(int a, ...) { - struct foo s = { 41, 201 }; - return s; - } - """) - assert ord(lib.f().y) == 40 - assert lib.f().x == 200 - e = py.test.raises(NotImplementedError, lib.g, 0) - assert str(e.value) == ( - "ctype 'struct foo' not supported as return value. It is a " - "'packed' structure, with a different layout than expected by libffi." - " Such structs are only supported as return value if the function is " - "'API mode' and non-variadic (i.e. declared inside ffibuilder.cdef()" - "+ffibuilder.set_source() and not taking a final '...' argument)") - -def test_pack_not_supported(): - ffi = FFI() - ffi.cdef("""struct foo { char y; int x; };""", pack=2) - py.test.raises(NotImplementedError, verify, - ffi, "test_pack_not_supported", "") - -def test_gcc_visibility_hidden(): - if sys.platform == 'win32': - py.test.skip("test for gcc/clang") - ffi = FFI() - ffi.cdef(""" - int f(int); - """) - lib = verify(ffi, "test_gcc_visibility_hidden", """ - int f(int a) { return a + 40; } - """, extra_compile_args=['-fvisibility=hidden']) - assert lib.f(2) == 42 - -def test_override_default_definition(): - ffi = FFI() - ffi.cdef("typedef long int16_t, char16_t;") - lib = verify(ffi, "test_override_default_definition", "") - assert ffi.typeof("int16_t") is ffi.typeof("char16_t") is ffi.typeof("long") - -def test_char16_char32_type(no_cpp=False): - if no_cpp is False and sys.platform == "win32": - py.test.skip("aaaaaaa why do modern MSVC compilers still define " - "a very old __cplusplus value") - ffi = FFI() - ffi.cdef(""" - char16_t foo_2bytes(char16_t); - char32_t foo_4bytes(char32_t); - """) - lib = verify(ffi, "test_char16_char32_type" + no_cpp * "_nocpp", """ - #if !defined(__cplusplus) || (!defined(_LIBCPP_VERSION) && __cplusplus < 201103L) - typedef uint_least16_t char16_t; - typedef uint_least32_t char32_t; - #endif - - char16_t foo_2bytes(char16_t a) { return (char16_t)(a + 42); } - char32_t foo_4bytes(char32_t a) { return (char32_t)(a + 42); } - """, no_cpp=no_cpp) - assert lib.foo_2bytes(u+'\u1234') == u+'\u125e' - assert lib.foo_4bytes(u+'\u1234') == u+'\u125e' - assert lib.foo_4bytes(u+'\U00012345') == u+'\U0001236f' - py.test.raises(TypeError, lib.foo_2bytes, u+'\U00012345') - py.test.raises(TypeError, lib.foo_2bytes, 1234) - py.test.raises(TypeError, lib.foo_4bytes, 1234) - -def test_char16_char32_plain_c(): - test_char16_char32_type(no_cpp=True) - -def test_loader_spec(): - ffi = FFI() - lib = verify(ffi, "test_loader_spec", "") - if sys.version_info < (3,): - assert not hasattr(lib, '__loader__') - assert not hasattr(lib, '__spec__') - else: - assert lib.__loader__ is None - assert lib.__spec__ is None - -def test_realize_struct_error(): - ffi = FFI() - ffi.cdef("""typedef ... foo_t; struct foo_s { void (*x)(foo_t); };""") - lib = verify(ffi, "test_realize_struct_error", """ - typedef int foo_t; struct foo_s { void (*x)(foo_t); }; - """) - py.test.raises(TypeError, ffi.new, "struct foo_s *") - -def test_from_buffer_struct(): - ffi = FFI() - ffi.cdef("""struct foo_s { int a, b; };""") - lib = verify(ffi, "test_from_buffer_struct_p", """ - struct foo_s { int a, b; }; - """) - p = ffi.new("struct foo_s *", [-219239, 58974983]) - q = ffi.from_buffer("struct foo_s[]", ffi.buffer(p)) - assert ffi.typeof(q) == ffi.typeof("struct foo_s[]") - assert len(q) == 1 - assert q[0].a == p.a - assert q[0].b == p.b - assert q == p - q = ffi.from_buffer("struct foo_s *", ffi.buffer(p)) - assert ffi.typeof(q) == ffi.typeof("struct foo_s *") - assert q.a == p.a - assert q.b == p.b - assert q[0].a == p.a - assert q[0].b == p.b - assert q == p - -def test_unnamed_bitfield_1(): - ffi = FFI() - ffi.cdef("""struct A { char : 1; };""") - lib = verify(ffi, "test_unnamed_bitfield_1", """ - struct A { char : 1; }; - """) - p = ffi.new("struct A *") - assert ffi.sizeof(p[0]) == 1 - # Note: on gcc, the type name is ignored for anonymous bitfields - # and that's why the result is 1. On MSVC, the result is - # sizeof("char") which is also 1. - -def test_unnamed_bitfield_2(): - ffi = FFI() - ffi.cdef("""struct A { - short c : 1; short : 1; short d : 1; short : 1; };""") - lib = verify(ffi, "test_unnamed_bitfield_2", """ - struct A { - short c : 1; short : 1; short d : 1; short : 1; - }; - """) - p = ffi.new("struct A *") - assert ffi.sizeof(p[0]) == ffi.sizeof("short") - -def test_unnamed_bitfield_3(): - ffi = FFI() - ffi.cdef("""struct A { struct { char : 1; char : 1; } b; };""") - lib = verify(ffi, "test_unnamed_bitfield_3", """ - struct A { struct { char : 1; char : 1; } b; }; - """) - p = ffi.new("struct A *") - assert ffi.sizeof(p[0]) == 1 - # Note: on gcc, the type name is ignored for anonymous bitfields - # and that's why the result is 1. On MSVC, the result is - # sizeof("char") which is also 1. - -def test_unnamed_bitfield_4(): - ffi = FFI() - ffi.cdef("""struct A { struct { - unsigned c : 1; unsigned : 1; unsigned d : 1; unsigned : 1; } a; - }; - struct B { struct A a; };""") - lib = verify(ffi, "test_unnamed_bitfield_4", """ - struct A { struct { - unsigned c : 1; unsigned : 1; unsigned d : 1; unsigned : 1; } a; - }; - struct B { struct A a; }; - """) - b = ffi.new("struct B *") - a = ffi.new("struct A *") - assert ffi.sizeof(a[0]) == ffi.sizeof("unsigned") - assert ffi.sizeof(b[0]) == ffi.sizeof(a[0]) - -def test_struct_with_func_with_struct_pointer_arg(): - ffi = FFI() - ffi.cdef("""struct BinaryTree { - int (* CompareKey)(struct BinaryTree *tree); - };""") - lib = verify(ffi, "test_struct_with_func_with_struct_pointer_arg", """ - struct BinaryTree { - int (* CompareKey)(struct BinaryTree *tree); - }; - """) - ffi.new("struct BinaryTree *") - -def test_struct_with_func_with_struct_arg(): - ffi = FFI() - ffi.cdef("""struct BinaryTree { - int (* CompareKey)(struct BinaryTree tree); - };""") - lib = verify(ffi, "test_struct_with_func_with_struct_arg", """ - struct BinaryTree { - int (* CompareKey)(struct BinaryTree tree); - }; - """) - py.test.raises(RuntimeError, ffi.new, "struct BinaryTree *") - -def test_passing_large_list(): - ffi = FFI() - ffi.cdef("""void passing_large_list(long[]);""") - lib = verify(ffi, "test_passing_large_list", """ - static void passing_large_list(long a[]) { } - """) - arg = list(range(20000000)) - lib.passing_large_list(arg) - # assert did not segfault diff --git a/testing/cffi1/test_unicode_literals.py b/testing/cffi1/test_unicode_literals.py deleted file mode 100644 index e9825db..0000000 --- a/testing/cffi1/test_unicode_literals.py +++ /dev/null @@ -1,43 +0,0 @@ -# -# ---------------------------------------------- -# WARNING, ALL LITERALS IN THIS FILE ARE UNICODE -# ---------------------------------------------- -# -from __future__ import unicode_literals -# -# -# -from _cffi_backend import FFI - - -def test_cast(): - ffi = FFI() - assert int(ffi.cast("int", 3.14)) == 3 # unicode literal - -def test_new(): - ffi = FFI() - assert ffi.new("int[]", [3, 4, 5])[2] == 5 # unicode literal - -def test_typeof(): - ffi = FFI() - tp = ffi.typeof("int[51]") # unicode literal - assert tp.length == 51 - -def test_sizeof(): - ffi = FFI() - assert ffi.sizeof("int[51]") == 51 * 4 # unicode literal - -def test_alignof(): - ffi = FFI() - assert ffi.alignof("int[51]") == 4 # unicode literal - -def test_getctype(): - ffi = FFI() - assert ffi.getctype("int**") == "int * *" # unicode literal - assert type(ffi.getctype("int**")) is str - -def test_callback(): - ffi = FFI() - cb = ffi.callback("int(int)", # unicode literal - lambda x: x + 42) - assert cb(5) == 47 diff --git a/testing/cffi1/test_verify1.py b/testing/cffi1/test_verify1.py deleted file mode 100644 index 33244cc..0000000 --- a/testing/cffi1/test_verify1.py +++ /dev/null @@ -1,2359 +0,0 @@ -import os, sys, math, py -import pytest -from cffi import FFI, FFIError, VerificationError, VerificationMissing, model -from cffi import CDefError -from cffi import recompiler -from testing.support import * -from testing.support import _verify, extra_compile_args -import _cffi_backend - -lib_m = ['m'] -if sys.platform == 'win32': - #there is a small chance this fails on Mingw via environ $CC - import distutils.ccompiler - if distutils.ccompiler.get_default_compiler() == 'msvc': - lib_m = ['msvcrt'] - -class FFI(FFI): - error = _cffi_backend.FFI.error - _extra_compile_args = extra_compile_args - _verify_counter = 0 - - def verify(self, preamble='', *args, **kwds): - # HACK to reuse the tests from ../cffi0/test_verify.py - FFI._verify_counter += 1 - module_name = 'verify%d' % FFI._verify_counter - try: - del self._assigned_source - except AttributeError: - pass - self.set_source(module_name, preamble) - return _verify(self, module_name, preamble, *args, - extra_compile_args=self._extra_compile_args, **kwds) - -class FFI_warnings_not_error(FFI): - _extra_compile_args = [] - - -def test_missing_function(ffi=None): - # uses the FFI hacked above with '-Werror' - if ffi is None: - ffi = FFI() - ffi.cdef("void some_completely_unknown_function();") - try: - lib = ffi.verify() - except (VerificationError, OSError, ImportError): - pass # expected case: we get a VerificationError - else: - # but depending on compiler and loader details, maybe - # 'lib' could actually be imported but will fail if we - # actually try to call the unknown function... Hard - # to test anything more. - pass - -def test_missing_function_import_error(): - # uses the original FFI that just gives a warning during compilation - test_missing_function(ffi=FFI_warnings_not_error()) - -def test_simple_case(): - ffi = FFI() - ffi.cdef("double sin(double x);") - lib = ffi.verify('#include <math.h>', libraries=lib_m) - assert lib.sin(1.23) == math.sin(1.23) - -def _Wconversion(cdef, source, **kargs): - if sys.platform in ('win32', 'darwin'): - py.test.skip("needs GCC") - ffi = FFI() - ffi.cdef(cdef) - py.test.raises(VerificationError, ffi.verify, source, **kargs) - extra_compile_args_orig = extra_compile_args[:] - extra_compile_args.remove('-Wconversion') - try: - lib = ffi.verify(source, **kargs) - finally: - extra_compile_args[:] = extra_compile_args_orig - return lib - -def test_Wconversion_unsigned(): - _Wconversion("unsigned foo(void);", - "int foo(void) { return -1;}") - -def test_Wconversion_integer(): - _Wconversion("short foo(void);", - "long long foo(void) { return 1<<sizeof(short);}") - -def test_Wconversion_floating(): - lib = _Wconversion("float sin(double);", - "#include <math.h>", libraries=lib_m) - res = lib.sin(1.23) - assert res != math.sin(1.23) # not exact, because of double->float - assert abs(res - math.sin(1.23)) < 1E-5 - -def test_Wconversion_float2int(): - _Wconversion("int sinf(float);", - "#include <math.h>", libraries=lib_m) - -def test_Wconversion_double2int(): - _Wconversion("int sin(double);", - "#include <math.h>", libraries=lib_m) - -def test_rounding_1(): - ffi = FFI() - ffi.cdef("double sinf(float x);") - lib = ffi.verify('#include <math.h>', libraries=lib_m) - res = lib.sinf(1.23) - assert res != math.sin(1.23) # not exact, because of double->float - assert abs(res - math.sin(1.23)) < 1E-5 - -def test_rounding_2(): - ffi = FFI() - ffi.cdef("double sin(float x);") - lib = ffi.verify('#include <math.h>', libraries=lib_m) - res = lib.sin(1.23) - assert res != math.sin(1.23) # not exact, because of double->float - assert abs(res - math.sin(1.23)) < 1E-5 - -def test_strlen_exact(): - ffi = FFI() - ffi.cdef("size_t strlen(const char *s);") - lib = ffi.verify("#include <string.h>") - assert lib.strlen(b"hi there!") == 9 - -def test_strlen_approximate(): - lib = _Wconversion("int strlen(char *s);", - "#include <string.h>") - assert lib.strlen(b"hi there!") == 9 - -def test_return_approximate(): - for typename in ['short', 'int', 'long', 'long long']: - ffi = FFI() - ffi.cdef("%s foo(signed char x);" % typename) - lib = ffi.verify("signed char foo(signed char x) { return x;}") - assert lib.foo(-128) == -128 - assert lib.foo(+127) == +127 - -def test_strlen_array_of_char(): - ffi = FFI() - ffi.cdef("size_t strlen(char[]);") - lib = ffi.verify("#include <string.h>") - assert lib.strlen(b"hello") == 5 - -def test_longdouble(): - ffi = FFI() - ffi.cdef("long double sinl(long double x);") - lib = ffi.verify('#include <math.h>', libraries=lib_m) - for input in [1.23, - ffi.cast("double", 1.23), - ffi.cast("long double", 1.23)]: - x = lib.sinl(input) - assert repr(x).startswith("<cdata 'long double'") - assert (float(x) - math.sin(1.23)) < 1E-10 - -def test_longdouble_precision(): - # Test that we don't loose any precision of 'long double' when - # passing through Python and CFFI. - ffi = FFI() - ffi.cdef("long double step1(long double x);") - SAME_SIZE = ffi.sizeof("long double") == ffi.sizeof("double") - lib = ffi.verify(""" - long double step1(long double x) - { - return 4*x-x*x; - } - """) - def do(cast_to_double): - x = 0.9789 - for i in range(10000): - x = lib.step1(x) - if cast_to_double: - x = float(x) - return float(x) - - more_precise = do(False) - less_precise = do(True) - if SAME_SIZE: - assert more_precise == less_precise - else: - assert abs(more_precise - less_precise) > 0.1 - # Check the particular results on Intel - import platform - if (platform.machine().startswith('i386') or - platform.machine().startswith('i486') or - platform.machine().startswith('i586') or - platform.machine().startswith('i686') or - platform.machine().startswith('x86')): - assert abs(more_precise - 0.656769) < 0.001 - assert abs(less_precise - 3.99091) < 0.001 - else: - py.test.skip("don't know the very exact precision of 'long double'") - - -all_primitive_types = model.PrimitiveType.ALL_PRIMITIVE_TYPES -if sys.platform == 'win32': - all_primitive_types = all_primitive_types.copy() - del all_primitive_types['ssize_t'] -all_integer_types = sorted(tp for tp in all_primitive_types - if all_primitive_types[tp] == 'i') -all_float_types = sorted(tp for tp in all_primitive_types - if all_primitive_types[tp] == 'f') - -def all_signed_integer_types(ffi): - return [x for x in all_integer_types if int(ffi.cast(x, -1)) < 0] - -def all_unsigned_integer_types(ffi): - return [x for x in all_integer_types if int(ffi.cast(x, -1)) > 0] - - -def test_primitive_category(): - for typename in all_primitive_types: - tp = model.PrimitiveType(typename) - C = tp.is_char_type() - F = tp.is_float_type() - X = tp.is_complex_type() - I = tp.is_integer_type() - assert C == (typename in ('char', 'wchar_t', 'char16_t', 'char32_t')) - assert F == (typename in ('float', 'double', 'long double')) - assert X == (typename in ('float _Complex', 'double _Complex')) - assert I + F + C + X == 1 # one and only one of them is true - -def test_all_integer_and_float_types(): - typenames = [] - for typename in all_primitive_types: - if (all_primitive_types[typename] == 'c' or - all_primitive_types[typename] == 'j' or # complex - typename == '_Bool' or typename == 'long double'): - pass - else: - typenames.append(typename) - # - ffi = FFI() - ffi.cdef('\n'.join(["%s foo_%s(%s);" % (tp, tp.replace(' ', '_'), tp) - for tp in typenames])) - lib = ffi.verify('\n'.join(["%s foo_%s(%s x) { return (%s)(x+1); }" % - (tp, tp.replace(' ', '_'), tp, tp) - for tp in typenames])) - for typename in typenames: - foo = getattr(lib, 'foo_%s' % typename.replace(' ', '_')) - assert foo(42) == 43 - if sys.version < '3': - assert foo(long(44)) == 45 - assert foo(ffi.cast(typename, 46)) == 47 - py.test.raises(TypeError, foo, ffi.NULL) - # - # check for overflow cases - if all_primitive_types[typename] == 'f': - continue - for value in [-2**80, -2**40, -2**20, -2**10, -2**5, -1, - 2**5, 2**10, 2**20, 2**40, 2**80]: - overflows = int(ffi.cast(typename, value)) != value - if overflows: - py.test.raises(OverflowError, foo, value) - else: - assert foo(value) == value + 1 - -def test_var_signed_integer_types(): - ffi = FFI() - lst = all_signed_integer_types(ffi) - csource = "\n".join(["static %s somevar_%s;" % (tp, tp.replace(' ', '_')) - for tp in lst]) - ffi.cdef(csource) - lib = ffi.verify(csource) - for tp in lst: - varname = 'somevar_%s' % tp.replace(' ', '_') - sz = ffi.sizeof(tp) - max = (1 << (8*sz-1)) - 1 - min = -(1 << (8*sz-1)) - setattr(lib, varname, max) - assert getattr(lib, varname) == max - setattr(lib, varname, min) - assert getattr(lib, varname) == min - py.test.raises(OverflowError, setattr, lib, varname, max+1) - py.test.raises(OverflowError, setattr, lib, varname, min-1) - -def test_var_unsigned_integer_types(): - ffi = FFI() - lst = all_unsigned_integer_types(ffi) - csource = "\n".join(["static %s somevar_%s;" % (tp, tp.replace(' ', '_')) - for tp in lst]) - ffi.cdef(csource) - lib = ffi.verify(csource) - for tp in lst: - varname = 'somevar_%s' % tp.replace(' ', '_') - sz = ffi.sizeof(tp) - if tp != '_Bool': - max = (1 << (8*sz)) - 1 - else: - max = 1 - setattr(lib, varname, max) - assert getattr(lib, varname) == max - setattr(lib, varname, 0) - assert getattr(lib, varname) == 0 - py.test.raises(OverflowError, setattr, lib, varname, max+1) - py.test.raises(OverflowError, setattr, lib, varname, -1) - -def test_fn_signed_integer_types(): - ffi = FFI() - lst = all_signed_integer_types(ffi) - cdefsrc = "\n".join(["%s somefn_%s(%s);" % (tp, tp.replace(' ', '_'), tp) - for tp in lst]) - ffi.cdef(cdefsrc) - verifysrc = "\n".join(["%s somefn_%s(%s x) { return x; }" % - (tp, tp.replace(' ', '_'), tp) for tp in lst]) - lib = ffi.verify(verifysrc) - for tp in lst: - fnname = 'somefn_%s' % tp.replace(' ', '_') - sz = ffi.sizeof(tp) - max = (1 << (8*sz-1)) - 1 - min = -(1 << (8*sz-1)) - fn = getattr(lib, fnname) - assert fn(max) == max - assert fn(min) == min - py.test.raises(OverflowError, fn, max + 1) - py.test.raises(OverflowError, fn, min - 1) - -def test_fn_unsigned_integer_types(): - ffi = FFI() - lst = all_unsigned_integer_types(ffi) - cdefsrc = "\n".join(["%s somefn_%s(%s);" % (tp, tp.replace(' ', '_'), tp) - for tp in lst]) - ffi.cdef(cdefsrc) - verifysrc = "\n".join(["%s somefn_%s(%s x) { return x; }" % - (tp, tp.replace(' ', '_'), tp) for tp in lst]) - lib = ffi.verify(verifysrc) - for tp in lst: - fnname = 'somefn_%s' % tp.replace(' ', '_') - sz = ffi.sizeof(tp) - if tp != '_Bool': - max = (1 << (8*sz)) - 1 - else: - max = 1 - fn = getattr(lib, fnname) - assert fn(max) == max - assert fn(0) == 0 - py.test.raises(OverflowError, fn, max + 1) - py.test.raises(OverflowError, fn, -1) - -def test_char_type(): - ffi = FFI() - ffi.cdef("char foo(char);") - lib = ffi.verify("char foo(char x) { return ++x; }") - assert lib.foo(b"A") == b"B" - py.test.raises(TypeError, lib.foo, b"bar") - py.test.raises(TypeError, lib.foo, "bar") - -def test_wchar_type(): - ffi = FFI() - if ffi.sizeof('wchar_t') == 2: - uniexample1 = u+'\u1234' - uniexample2 = u+'\u1235' - else: - uniexample1 = u+'\U00012345' - uniexample2 = u+'\U00012346' - # - ffi.cdef("wchar_t foo(wchar_t);") - lib = ffi.verify("wchar_t foo(wchar_t x) { return x+1; }") - assert lib.foo(uniexample1) == uniexample2 - -def test_no_argument(): - ffi = FFI() - ffi.cdef("int foo(void);") - lib = ffi.verify("int foo(void) { return 42; }") - assert lib.foo() == 42 - -def test_two_arguments(): - ffi = FFI() - ffi.cdef("int foo(int, int);") - lib = ffi.verify("int foo(int a, int b) { return a - b; }") - assert lib.foo(40, -2) == 42 - -def test_macro(): - ffi = FFI() - ffi.cdef("int foo(int, int);") - lib = ffi.verify("#define foo(a, b) ((a) * (b))") - assert lib.foo(-6, -7) == 42 - -def test_ptr(): - ffi = FFI() - ffi.cdef("int *foo(int *);") - lib = ffi.verify("int *foo(int *a) { return a; }") - assert lib.foo(ffi.NULL) == ffi.NULL - p = ffi.new("int *", 42) - q = ffi.new("int *", 42) - assert lib.foo(p) == p - assert lib.foo(q) != p - -def test_bogus_ptr(): - ffi = FFI() - ffi.cdef("int *foo(int *);") - lib = ffi.verify("int *foo(int *a) { return a; }") - py.test.raises(TypeError, lib.foo, ffi.new("short *", 42)) - - -def test_verify_typedefs(): - py.test.skip("ignored so far") - types = ['signed char', 'unsigned char', 'int', 'long'] - for cdefed in types: - for real in types: - ffi = FFI() - ffi.cdef("typedef %s foo_t;" % cdefed) - if cdefed == real: - ffi.verify("typedef %s foo_t;" % real) - else: - py.test.raises(VerificationError, ffi.verify, - "typedef %s foo_t;" % real) - -def test_nondecl_struct(): - ffi = FFI() - ffi.cdef("typedef struct foo_s foo_t; int bar(foo_t *);") - lib = ffi.verify("typedef struct foo_s foo_t;\n" - "int bar(foo_t *f) { (void)f; return 42; }\n") - assert lib.bar(ffi.NULL) == 42 - -def test_ffi_full_struct(): - def check(verified_code): - ffi = FFI() - ffi.cdef("struct foo_s { char x; int y; long *z; };") - ffi.verify(verified_code) - ffi.new("struct foo_s *", {}) - - check("struct foo_s { char x; int y; long *z; };") - # - if sys.platform != 'win32': # XXX fixme: only gives warnings - py.test.raises(VerificationError, check, - "struct foo_s { char x; int y; int *z; };") - # - py.test.raises(VerificationError, check, - "struct foo_s { int y; long *z; };") # cdef'ed field x is missing - # - e = py.test.raises(FFI.error, check, - "struct foo_s { int y; char x; long *z; };") - assert str(e.value).startswith( - "struct foo_s: wrong offset for field 'x'" - " (cdef says 0, but C compiler says 4)") - # - e = py.test.raises(FFI.error, check, - "struct foo_s { char x; int y; long *z; char extra; };") - assert str(e.value).startswith( - "struct foo_s: wrong total size" - " (cdef says %d, but C compiler says %d)" % ( - 8 + FFI().sizeof('long *'), - 8 + FFI().sizeof('long *') * 2)) - # - # a corner case that we cannot really detect, but where it has no - # bad consequences: the size is the same, but there is an extra field - # that replaces what is just padding in our declaration above - check("struct foo_s { char x, extra; int y; long *z; };") - # - e = py.test.raises(FFI.error, check, - "struct foo_s { char x; short pad; short y; long *z; };") - assert str(e.value).startswith( - "struct foo_s: wrong size for field 'y'" - " (cdef says 4, but C compiler says 2)") - -def test_ffi_nonfull_struct(): - ffi = FFI() - ffi.cdef(""" - struct foo_s { - int x; - ...; - }; - """) - py.test.raises(VerificationMissing, ffi.sizeof, 'struct foo_s') - py.test.raises(VerificationMissing, ffi.offsetof, 'struct foo_s', 'x') - py.test.raises(VerificationMissing, ffi.new, 'struct foo_s *') - ffi.verify(""" - struct foo_s { - int a, b, x, c, d, e; - }; - """) - assert ffi.sizeof('struct foo_s') == 6 * ffi.sizeof('int') - assert ffi.offsetof('struct foo_s', 'x') == 2 * ffi.sizeof('int') - -def test_ffi_nonfull_alignment(): - ffi = FFI() - ffi.cdef("struct foo_s { char x; ...; };") - ffi.verify("struct foo_s { int a, b; char x; };") - assert ffi.sizeof('struct foo_s') == 3 * ffi.sizeof('int') - assert ffi.alignof('struct foo_s') == ffi.sizeof('int') - -def _check_field_match(typename, real, expect_mismatch): - ffi = FFI() - testing_by_size = (expect_mismatch == 'by_size') - if testing_by_size: - expect_mismatch = ffi.sizeof(typename) != ffi.sizeof(real) - ffi.cdef("struct foo_s { %s x; ...; };" % typename) - try: - ffi.verify("struct foo_s { %s x; };" % real) - ffi.new("struct foo_s *", []) # because some mismatches show up lazily - except (VerificationError, ffi.error): - if not expect_mismatch: - if testing_by_size and typename != real: - print("ignoring mismatch between %s* and %s* even though " - "they have the same size" % (typename, real)) - return - raise AssertionError("unexpected mismatch: %s should be accepted " - "as equal to %s" % (typename, real)) - else: - if expect_mismatch: - raise AssertionError("mismatch not detected: " - "%s != %s" % (typename, real)) - -def test_struct_bad_sized_integer(): - for typename in ['int8_t', 'int16_t', 'int32_t', 'int64_t']: - for real in ['int8_t', 'int16_t', 'int32_t', 'int64_t']: - _check_field_match(typename, real, "by_size") - -def test_struct_bad_sized_float(): - for typename in all_float_types: - for real in all_float_types: - _check_field_match(typename, real, "by_size") - -def test_struct_signedness_ignored(): - _check_field_match("int", "unsigned int", expect_mismatch=False) - _check_field_match("unsigned short", "signed short", expect_mismatch=False) - -def test_struct_float_vs_int(): - if sys.platform == 'win32': - py.test.skip("XXX fixme: only gives warnings") - ffi = FFI() - for typename in all_signed_integer_types(ffi): - for real in all_float_types: - _check_field_match(typename, real, expect_mismatch=True) - for typename in all_float_types: - for real in all_signed_integer_types(ffi): - _check_field_match(typename, real, expect_mismatch=True) - -def test_struct_array_field(): - ffi = FFI() - ffi.cdef("struct foo_s { int a[17]; ...; };") - ffi.verify("struct foo_s { int x; int a[17]; int y; };") - assert ffi.sizeof('struct foo_s') == 19 * ffi.sizeof('int') - s = ffi.new("struct foo_s *") - assert ffi.sizeof(s.a) == 17 * ffi.sizeof('int') - -def test_struct_array_no_length(): - ffi = FFI() - ffi.cdef("struct foo_s { int a[]; int y; ...; };\n" - "int bar(struct foo_s *);\n") - lib = ffi.verify("struct foo_s { int x; int a[17]; int y; };\n" - "int bar(struct foo_s *f) { return f->a[14]; }\n") - assert ffi.sizeof('struct foo_s') == 19 * ffi.sizeof('int') - s = ffi.new("struct foo_s *") - assert ffi.typeof(s.a) is ffi.typeof('int[]') # implicit max length - assert len(s.a) == 18 # max length, computed from the size and start offset - s.a[14] = 4242 - assert lib.bar(s) == 4242 - # with no declared length, out-of-bound accesses are not detected - s.a[17] = -521 - assert s.y == s.a[17] == -521 - # - s = ffi.new("struct foo_s *", {'a': list(range(17))}) - assert s.a[16] == 16 - # overflows at construction time not detected either - s = ffi.new("struct foo_s *", {'a': list(range(18))}) - assert s.y == s.a[17] == 17 - -def test_struct_array_guess_length(): - ffi = FFI() - ffi.cdef("struct foo_s { int a[...]; };") - ffi.verify("struct foo_s { int x; int a[17]; int y; };") - assert ffi.sizeof('struct foo_s') == 19 * ffi.sizeof('int') - s = ffi.new("struct foo_s *") - assert ffi.sizeof(s.a) == 17 * ffi.sizeof('int') - with pytest.raises(IndexError): - s.a[17] - -def test_struct_array_c99_1(): - if sys.platform == 'win32': - py.test.skip("requires C99") - ffi = FFI() - ffi.cdef("struct foo_s { int x; int a[]; };") - ffi.verify("struct foo_s { int x; int a[]; };") - assert ffi.sizeof('struct foo_s') == 1 * ffi.sizeof('int') - s = ffi.new("struct foo_s *", [424242, 4]) - assert ffi.sizeof(ffi.typeof(s[0])) == 1 * ffi.sizeof('int') - assert ffi.sizeof(s[0]) == 5 * ffi.sizeof('int') - # ^^^ explanation: if you write in C: "char x[5];", then - # "sizeof(x)" will evaluate to 5. The behavior above is - # a generalization of that to "struct foo_s[len(a)=5] x;" - # if you could do that in C. - assert s.a[3] == 0 - s = ffi.new("struct foo_s *", [424242, [-40, -30, -20, -10]]) - assert ffi.sizeof(s[0]) == 5 * ffi.sizeof('int') - assert s.a[3] == -10 - s = ffi.new("struct foo_s *") - assert ffi.sizeof(s[0]) == 1 * ffi.sizeof('int') - s = ffi.new("struct foo_s *", [424242]) - assert ffi.sizeof(s[0]) == 1 * ffi.sizeof('int') - -def test_struct_array_c99_2(): - if sys.platform == 'win32': - py.test.skip("requires C99") - ffi = FFI() - ffi.cdef("struct foo_s { int x; int a[]; ...; };") - ffi.verify("struct foo_s { int x, y; int a[]; };") - assert ffi.sizeof('struct foo_s') == 2 * ffi.sizeof('int') - s = ffi.new("struct foo_s *", [424242, 4]) - assert ffi.sizeof(s[0]) == 6 * ffi.sizeof('int') - assert s.a[3] == 0 - s = ffi.new("struct foo_s *", [424242, [-40, -30, -20, -10]]) - assert ffi.sizeof(s[0]) == 6 * ffi.sizeof('int') - assert s.a[3] == -10 - s = ffi.new("struct foo_s *") - assert ffi.sizeof(s[0]) == 2 * ffi.sizeof('int') - s = ffi.new("struct foo_s *", [424242]) - assert ffi.sizeof(s[0]) == 2 * ffi.sizeof('int') - -def test_struct_ptr_to_array_field(): - ffi = FFI() - ffi.cdef("struct foo_s { int (*a)[17]; ...; }; struct bar_s { ...; };") - ffi.verify("struct foo_s { int x; int (*a)[17]; int y; };\n" - "struct bar_s { int x; int *a; int y; };") - assert ffi.sizeof('struct foo_s') == ffi.sizeof("struct bar_s") - s = ffi.new("struct foo_s *") - assert ffi.sizeof(s.a) == ffi.sizeof('int(*)[17]') == ffi.sizeof("int *") - -def test_struct_with_bitfield_exact(): - ffi = FFI() - ffi.cdef("struct foo_s { int a:2, b:3; };") - ffi.verify("struct foo_s { int a:2, b:3; };") - s = ffi.new("struct foo_s *") - s.b = 3 - with pytest.raises(OverflowError): - s.b = 4 - assert s.b == 3 - -def test_struct_with_bitfield_enum(): - ffi = FFI() - code = """ - typedef enum { AA, BB, CC } foo_e; - typedef struct { foo_e f:2; } foo_s; - """ - ffi.cdef(code) - ffi.verify(code) - s = ffi.new("foo_s *") - s.f = 1 - assert s.f == 1 - if int(ffi.cast("foo_e", -1)) < 0: - two = -2 - else: - two = 2 - s.f = two - assert s.f == two - -def test_unsupported_struct_with_bitfield_ellipsis(): - ffi = FFI() - py.test.raises(NotImplementedError, ffi.cdef, - "struct foo_s { int a:2, b:3; ...; };") - -def test_global_constants(): - ffi = FFI() - # use 'static const int', as generally documented, although in this - # case the 'static' is completely ignored. - ffi.cdef("static const int AA, BB, CC, DD;") - lib = ffi.verify("#define AA 42\n" - "#define BB (-43) // blah\n" - "#define CC (22*2) /* foobar */\n" - "#define DD ((unsigned int)142) /* foo\nbar */\n") - assert lib.AA == 42 - assert lib.BB == -43 - assert lib.CC == 44 - assert lib.DD == 142 - -def test_global_const_int_size(): - # integer constants: ignore the declared type, always just use the value - for value in [-2**63, -2**31, -2**15, - 2**15-1, 2**15, 2**31-1, 2**31, 2**32-1, 2**32, - 2**63-1, 2**63, 2**64-1]: - ffi = FFI() - if value == int(ffi.cast("long long", value)): - if value < 0: - vstr = '(-%dLL-1)' % (~value,) - else: - vstr = '%dLL' % value - elif value == int(ffi.cast("unsigned long long", value)): - vstr = '%dULL' % value - else: - raise AssertionError(value) - ffi.cdef("static const unsigned short AA;") - lib = ffi.verify("#define AA %s\n" % vstr) - assert lib.AA == value - assert type(lib.AA) is type(int(lib.AA)) - -def test_global_constants_non_int(): - ffi = FFI() - ffi.cdef("static char *const PP;") - lib = ffi.verify('static char *const PP = "testing!";\n') - assert ffi.typeof(lib.PP) == ffi.typeof("char *") - assert ffi.string(lib.PP) == b"testing!" - -def test_nonfull_enum(): - ffi = FFI() - ffi.cdef("enum ee { EE1, EE2, EE3, ... \n \t };") - py.test.raises(VerificationMissing, ffi.cast, 'enum ee', 'EE2') - ffi.verify("enum ee { EE1=10, EE2, EE3=-10, EE4 };") - assert ffi.string(ffi.cast('enum ee', 11)) == "EE2" - assert ffi.string(ffi.cast('enum ee', -10)) == "EE3" - # - assert ffi.typeof("enum ee").relements == {'EE1': 10, 'EE2': 11, 'EE3': -10} - assert ffi.typeof("enum ee").elements == {10: 'EE1', 11: 'EE2', -10: 'EE3'} - -def test_full_enum(): - ffi = FFI() - ffi.cdef("enum ee { EE1, EE2, EE3 };") - lib = ffi.verify("enum ee { EE1, EE2, EE3 };") - assert [lib.EE1, lib.EE2, lib.EE3] == [0, 1, 2] - -def test_enum_usage(): - ffi = FFI() - ffi.cdef("enum ee { EE1,EE2 }; typedef struct { enum ee x; } *sp;") - lib = ffi.verify("enum ee { EE1,EE2 }; typedef struct { enum ee x; } *sp;") - assert lib.EE2 == 1 - s = ffi.new("sp", [lib.EE2]) - assert s.x == 1 - s.x = 17 - assert s.x == 17 - -def test_anonymous_enum(): - ffi = FFI() - ffi.cdef("enum { EE1 }; enum { EE2, EE3 };") - lib = ffi.verify("enum { EE1 }; enum { EE2, EE3 };") - assert lib.EE1 == 0 - assert lib.EE2 == 0 - assert lib.EE3 == 1 - -def test_nonfull_anonymous_enum(): - ffi = FFI() - ffi.cdef("enum { EE1, ... }; enum { EE3, ... };") - lib = ffi.verify("enum { EE2, EE1 }; enum { EE3 };") - assert lib.EE1 == 1 - assert lib.EE3 == 0 - -def test_nonfull_enum_syntax2(): - ffi = FFI() - ffi.cdef("enum ee { EE1, EE2=\t..., EE3 };") - py.test.raises(VerificationMissing, ffi.cast, 'enum ee', 'EE1') - ffi.verify("enum ee { EE1=10, EE2, EE3=-10, EE4 };") - assert ffi.string(ffi.cast('enum ee', 11)) == 'EE2' - assert ffi.string(ffi.cast('enum ee', -10)) == 'EE3' - # - ffi = FFI() - ffi.cdef("enum ee { EE1, EE2=\t... };") - py.test.raises(VerificationMissing, ffi.cast, 'enum ee', 'EE1') - ffi.verify("enum ee { EE1=10, EE2, EE3=-10, EE4 };") - assert ffi.string(ffi.cast('enum ee', 11)) == 'EE2' - # - ffi = FFI() - ffi.cdef("enum ee2 { EE4=..., EE5=..., ... };") - ffi.verify("enum ee2 { EE4=-1234-5, EE5 }; ") - assert ffi.string(ffi.cast('enum ee2', -1239)) == 'EE4' - assert ffi.string(ffi.cast('enum ee2', -1238)) == 'EE5' - -def test_get_set_errno(): - ffi = FFI() - ffi.cdef("int foo(int);") - lib = ffi.verify(""" - static int foo(int x) - { - errno += 1; - return x * 7; - } - """) - ffi.errno = 15 - assert lib.foo(6) == 42 - assert ffi.errno == 16 - -def test_define_int(): - ffi = FFI() - ffi.cdef("#define FOO ...\n" - "\t#\tdefine\tBAR\t...\t\n" - "#define BAZ ...\n") - lib = ffi.verify("#define FOO 42\n" - "#define BAR (-44)\n" - "#define BAZ 0xffffffffffffffffULL\n") - assert lib.FOO == 42 - assert lib.BAR == -44 - assert lib.BAZ == 0xffffffffffffffff - -def test_access_variable(): - ffi = FFI() - ffi.cdef("static int foo(void);\n" - "static int somenumber;") - lib = ffi.verify(""" - static int somenumber = 2; - static int foo(void) { - return somenumber * 7; - } - """) - assert lib.somenumber == 2 - assert lib.foo() == 14 - lib.somenumber = -6 - assert lib.foo() == -42 - assert lib.somenumber == -6 - lib.somenumber = 2 # reset for the next run, if any - -def test_access_address_of_variable(): - # access the address of 'somenumber': need a trick - ffi = FFI() - ffi.cdef("static int somenumber; static int *const somenumberptr;") - lib = ffi.verify(""" - static int somenumber = 2; - #define somenumberptr (&somenumber) - """) - assert lib.somenumber == 2 - lib.somenumberptr[0] = 42 - assert lib.somenumber == 42 - lib.somenumber = 2 # reset for the next run, if any - -def test_access_array_variable(length=5): - ffi = FFI() - ffi.cdef("static int foo(int);\n" - "static int somenumber[%s];" % (length,)) - lib = ffi.verify(""" - static int somenumber[] = {2, 2, 3, 4, 5}; - static int foo(int i) { - return somenumber[i] * 7; - } - """) - if length == '': - # a global variable of an unknown array length is implicitly - # transformed into a global pointer variable, because we can only - # work with array instances whose length we know. using a pointer - # instead of an array gives the correct effects. - assert repr(lib.somenumber).startswith("<cdata 'int *' 0x") - py.test.raises(TypeError, len, lib.somenumber) - else: - assert repr(lib.somenumber).startswith("<cdata 'int[%s]' 0x" % length) - assert len(lib.somenumber) == 5 - assert lib.somenumber[3] == 4 - assert lib.foo(3) == 28 - lib.somenumber[3] = -6 - assert lib.foo(3) == -42 - assert lib.somenumber[3] == -6 - assert lib.somenumber[4] == 5 - lib.somenumber[3] = 4 # reset for the next run, if any - -def test_access_array_variable_length_hidden(): - test_access_array_variable(length='') - -def test_access_struct_variable(): - ffi = FFI() - ffi.cdef("struct foo { int x; ...; };\n" - "static int foo(int);\n" - "static struct foo stuff;") - lib = ffi.verify(""" - struct foo { int x, y, z; }; - static struct foo stuff = {2, 5, 8}; - static int foo(int i) { - switch (i) { - case 0: return stuff.x * 7; - case 1: return stuff.y * 7; - case 2: return stuff.z * 7; - } - return -1; - } - """) - assert lib.stuff.x == 2 - assert lib.foo(0) == 14 - assert lib.foo(1) == 35 - assert lib.foo(2) == 56 - lib.stuff.x = -6 - assert lib.foo(0) == -42 - assert lib.foo(1) == 35 - lib.stuff.x = 2 # reset for the next run, if any - -def test_access_callback(): - ffi = FFI() - ffi.cdef("static int (*cb)(int);\n" - "static int foo(int);\n" - "static void reset_cb(void);") - lib = ffi.verify(""" - static int g(int x) { return x * 7; } - static int (*cb)(int); - static int foo(int i) { return cb(i) - 1; } - static void reset_cb(void) { cb = g; } - """) - lib.reset_cb() - assert lib.foo(6) == 41 - my_callback = ffi.callback("int(*)(int)", lambda n: n * 222) - lib.cb = my_callback - assert lib.foo(4) == 887 - -def test_access_callback_function_typedef(): - ffi = FFI() - ffi.cdef("typedef int mycallback_t(int);\n" - "static mycallback_t *cb;\n" - "static int foo(int);\n" - "static void reset_cb(void);") - lib = ffi.verify(""" - static int g(int x) { return x * 7; } - static int (*cb)(int); - static int foo(int i) { return cb(i) - 1; } - static void reset_cb(void) { cb = g; } - """) - lib.reset_cb() - assert lib.foo(6) == 41 - my_callback = ffi.callback("int(*)(int)", lambda n: n * 222) - lib.cb = my_callback - assert lib.foo(4) == 887 - -def test_call_with_struct_ptr(): - ffi = FFI() - ffi.cdef("typedef struct { int x; ...; } foo_t; int foo(foo_t *);") - lib = ffi.verify(""" - typedef struct { int y, x; } foo_t; - static int foo(foo_t *f) { return f->x * 7; } - """) - f = ffi.new("foo_t *") - f.x = 6 - assert lib.foo(f) == 42 - -def test_unknown_type(): - ffi = FFI() - ffi.cdef(""" - typedef ... token_t; - int foo(token_t *); - #define TOKEN_SIZE ... - """) - lib = ffi.verify(""" - typedef float token_t; - static int foo(token_t *tk) { - if (!tk) - return -42; - *tk += 1.601f; - return (int)*tk; - } - #define TOKEN_SIZE sizeof(token_t) - """) - # we cannot let ffi.new("token_t *") work, because we don't know ahead of - # time if it's ok to ask 'sizeof(token_t)' in the C code or not. - # See test_unknown_type_2. Workaround. - tkmem = ffi.new("char[]", lib.TOKEN_SIZE) # zero-initialized - tk = ffi.cast("token_t *", tkmem) - results = [lib.foo(tk) for i in range(6)] - assert results == [1, 3, 4, 6, 8, 9] - assert lib.foo(ffi.NULL) == -42 - -def test_unknown_type_2(): - ffi = FFI() - ffi.cdef("typedef ... token_t;") - lib = ffi.verify("typedef struct token_s token_t;") - # assert did not crash, even though 'sizeof(token_t)' is not valid in C. - -def test_unknown_type_3(): - ffi = FFI() - ffi.cdef(""" - typedef ... *token_p; - token_p foo(token_p); - """) - lib = ffi.verify(""" - typedef struct _token_s *token_p; - token_p foo(token_p arg) { - if (arg) - return (token_p)0x12347; - else - return (token_p)0x12345; - } - """) - p = lib.foo(ffi.NULL) - assert int(ffi.cast("intptr_t", p)) == 0x12345 - q = lib.foo(p) - assert int(ffi.cast("intptr_t", q)) == 0x12347 - -def test_varargs(): - ffi = FFI() - ffi.cdef("int foo(int x, ...);") - lib = ffi.verify(""" - int foo(int x, ...) { - va_list vargs; - va_start(vargs, x); - x -= va_arg(vargs, int); - x -= va_arg(vargs, int); - va_end(vargs); - return x; - } - """) - assert lib.foo(50, ffi.cast("int", 5), ffi.cast("int", 3)) == 42 - -def test_varargs_exact(): - if sys.platform == 'win32': - py.test.skip("XXX fixme: only gives warnings") - ffi = FFI() - ffi.cdef("int foo(int x, ...);") - py.test.raises(VerificationError, ffi.verify, """ - int foo(long long x, ...) { - return x; - } - """) - -def test_varargs_struct(): - ffi = FFI() - ffi.cdef("struct foo_s { char a; int b; }; int foo(int x, ...);") - lib = ffi.verify(""" - struct foo_s { - char a; int b; - }; - int foo(int x, ...) { - va_list vargs; - struct foo_s s; - va_start(vargs, x); - s = va_arg(vargs, struct foo_s); - va_end(vargs); - return s.a - s.b; - } - """) - s = ffi.new("struct foo_s *", [b'B', 1]) - assert lib.foo(50, s[0]) == ord('A') - -def test_autofilled_struct_as_argument(): - ffi = FFI() - ffi.cdef("struct foo_s { long a; double b; ...; };\n" - "int foo(struct foo_s);") - lib = ffi.verify(""" - struct foo_s { - double b; - long a; - }; - int foo(struct foo_s s) { - return (int)s.a - (int)s.b; - } - """) - s = ffi.new("struct foo_s *", [100, 1]) - assert lib.foo(s[0]) == 99 - assert lib.foo([100, 1]) == 99 - -def test_autofilled_struct_as_argument_dynamic(): - ffi = FFI() - ffi.cdef("struct foo_s { long a; ...; };\n" - "static int (*foo)(struct foo_s);") - lib = ffi.verify(""" - struct foo_s { - double b; - long a; - }; - int foo1(struct foo_s s) { - return (int)s.a - (int)s.b; - } - static int (*foo)(struct foo_s s) = &foo1; - """) - e = py.test.raises(NotImplementedError, lib.foo, "?") - msg = ("ctype 'struct foo_s' 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_func_returns_struct(): - ffi = FFI() - ffi.cdef(""" - struct foo_s { int aa, bb; }; - struct foo_s foo(int a, int b); - """) - lib = ffi.verify(""" - struct foo_s { int aa, bb; }; - struct foo_s foo(int a, int b) { - struct foo_s r; - r.aa = a*a; - r.bb = b*b; - return r; - } - """) - s = lib.foo(6, 7) - assert repr(s) == "<cdata 'struct foo_s' owning 8 bytes>" - assert s.aa == 36 - assert s.bb == 49 - -def test_func_as_funcptr(): - ffi = FFI() - ffi.cdef("int *(*const fooptr)(void);") - lib = ffi.verify(""" - int *foo(void) { - return (int*)"foobar"; - } - int *(*fooptr)(void) = foo; - """) - foochar = ffi.cast("char *(*)(void)", lib.fooptr) - s = foochar() - assert ffi.string(s) == b"foobar" - -def test_funcptr_as_argument(): - ffi = FFI() - ffi.cdef(""" - void qsort(void *base, size_t nel, size_t width, - int (*compar)(const void *, const void *)); - """) - ffi.verify("#include <stdlib.h>") - -def test_func_as_argument(): - ffi = FFI() - ffi.cdef(""" - void qsort(void *base, size_t nel, size_t width, - int compar(const void *, const void *)); - """) - ffi.verify("#include <stdlib.h>") - -def test_array_as_argument(): - ffi = FFI() - ffi.cdef(""" - size_t strlen(char string[]); - """) - ffi.verify("#include <string.h>") - -def test_enum_as_argument(): - ffi = FFI() - ffi.cdef(""" - enum foo_e { AA, BB, ... }; - int foo_func(enum foo_e); - """) - lib = ffi.verify(""" - enum foo_e { AA, CC, BB }; - int foo_func(enum foo_e e) { return (int)e; } - """) - assert lib.foo_func(lib.BB) == 2 - py.test.raises(TypeError, lib.foo_func, "BB") - -def test_enum_as_function_result(): - ffi = FFI() - ffi.cdef(""" - enum foo_e { AA, BB, ... }; - enum foo_e foo_func(int x); - """) - lib = ffi.verify(""" - enum foo_e { AA, CC, BB }; - enum foo_e foo_func(int x) { return (enum foo_e)x; } - """) - assert lib.foo_func(lib.BB) == lib.BB == 2 - -def test_enum_values(): - ffi = FFI() - ffi.cdef("enum enum1_e { AA, BB };") - lib = ffi.verify("enum enum1_e { AA, BB };") - assert lib.AA == 0 - assert lib.BB == 1 - assert ffi.string(ffi.cast("enum enum1_e", 1)) == 'BB' - -def test_typedef_complete_enum(): - ffi = FFI() - ffi.cdef("typedef enum { AA, BB } enum1_t;") - lib = ffi.verify("typedef enum { AA, BB } enum1_t;") - assert ffi.string(ffi.cast("enum1_t", 1)) == 'BB' - assert lib.AA == 0 - assert lib.BB == 1 - -def test_typedef_broken_complete_enum(): - # xxx this is broken in old cffis, but works with recompiler.py - ffi = FFI() - ffi.cdef("typedef enum { AA, BB } enum1_t;") - lib = ffi.verify("typedef enum { AA, CC, BB } enum1_t;") - assert lib.AA == 0 - assert lib.BB == 2 - -def test_typedef_incomplete_enum(): - ffi = FFI() - ffi.cdef("typedef enum { AA, BB, ... } enum1_t;") - lib = ffi.verify("typedef enum { AA, CC, BB } enum1_t;") - assert ffi.string(ffi.cast("enum1_t", 1)) == '1' - assert ffi.string(ffi.cast("enum1_t", 2)) == 'BB' - assert lib.AA == 0 - assert lib.BB == 2 - -def test_typedef_enum_as_argument(): - ffi = FFI() - ffi.cdef(""" - typedef enum { AA, BB, ... } foo_t; - int foo_func(foo_t); - """) - lib = ffi.verify(""" - typedef enum { AA, CC, BB } foo_t; - int foo_func(foo_t e) { return (int)e; } - """) - assert lib.foo_func(lib.BB) == lib.BB == 2 - py.test.raises(TypeError, lib.foo_func, "BB") - -def test_typedef_enum_as_function_result(): - ffi = FFI() - ffi.cdef(""" - typedef enum { AA, BB, ... } foo_t; - foo_t foo_func(int x); - """) - lib = ffi.verify(""" - typedef enum { AA, CC, BB } foo_t; - foo_t foo_func(int x) { return (foo_t)x; } - """) - assert lib.foo_func(lib.BB) == lib.BB == 2 - -def test_function_typedef(): - ffi = FFI() - ffi.cdef(""" - typedef double func_t(double); - func_t sin; - """) - lib = ffi.verify('#include <math.h>', libraries=lib_m) - assert lib.sin(1.23) == math.sin(1.23) - -def test_opaque_integer_as_function_result(): - #import platform - #if platform.machine().startswith('sparc'): - # py.test.skip('Breaks horribly on sparc (SIGILL + corrupted stack)') - #elif platform.machine() == 'mips64' and sys.maxsize > 2**32: - # py.test.skip('Segfaults on mips64el') - # XXX bad abuse of "struct { ...; }". It only works a bit by chance - # anyway. XXX think about something better :-( - ffi = FFI() - ffi.cdef(""" - typedef struct { ...; } myhandle_t; - myhandle_t foo(void); - """) - lib = ffi.verify(""" - typedef short myhandle_t; - myhandle_t foo(void) { return 42; } - """) - h = lib.foo() - assert ffi.sizeof(h) == ffi.sizeof("short") - -def test_return_partial_struct(): - ffi = FFI() - ffi.cdef(""" - typedef struct { int x; ...; } foo_t; - foo_t foo(void); - """) - lib = ffi.verify(""" - typedef struct { int y, x; } foo_t; - foo_t foo(void) { foo_t r = { 45, 81 }; return r; } - """) - h = lib.foo() - assert ffi.sizeof(h) == 2 * ffi.sizeof("int") - assert h.x == 81 - -def test_take_and_return_partial_structs(): - ffi = FFI() - ffi.cdef(""" - typedef struct { int x; ...; } foo_t; - foo_t foo(foo_t, foo_t); - """) - lib = ffi.verify(""" - typedef struct { int y, x; } foo_t; - foo_t foo(foo_t a, foo_t b) { - foo_t r = { 100, a.x * 5 + b.x * 7 }; - return r; - } - """) - args = ffi.new("foo_t[3]") - args[0].x = 1000 - args[2].x = -498 - h = lib.foo(args[0], args[2]) - assert ffi.sizeof(h) == 2 * ffi.sizeof("int") - assert h.x == 1000 * 5 - 498 * 7 - -def test_cannot_name_struct_type(): - ffi = FFI() - ffi.cdef("typedef struct { int x; } **sp; void foo(sp);") - e = py.test.raises(VerificationError, ffi.verify, - "typedef struct { int x; } **sp; void foo(sp x) { }") - assert 'in argument of foo: unknown type name' in str(e.value) - -def test_dont_check_unnamable_fields(): - ffi = FFI() - ffi.cdef("struct foo_s { struct { int x; } someone; };") - ffi.verify("struct foo_s { struct { int x; } someone; };") - # assert did not crash - -def test_nested_anonymous_struct_exact(): - if sys.platform == 'win32': - py.test.skip("nested anonymous struct/union") - ffi = FFI() - ffi.cdef(""" - struct foo_s { struct { int a; char b; }; union { char c, d; }; }; - """) - assert ffi.offsetof("struct foo_s", "c") == 2 * ffi.sizeof("int") - assert ffi.sizeof("struct foo_s") == 3 * ffi.sizeof("int") - ffi.verify(""" - struct foo_s { struct { int a; char b; }; union { char c, d; }; }; - """) - p = ffi.new("struct foo_s *") - assert ffi.sizeof(p[0]) == 3 * ffi.sizeof("int") # with alignment - p.a = 1234567 - p.b = b'X' - p.c = b'Y' - assert p.a == 1234567 - assert p.b == b'X' - assert p.c == b'Y' - assert p.d == b'Y' - -def test_nested_anonymous_struct_exact_error(): - if sys.platform == 'win32': - py.test.skip("nested anonymous struct/union") - ffi = FFI() - ffi.cdef(""" - struct foo_s { struct { int a; char b; }; union { char c, d; }; }; - """) - py.test.raises(VerificationError, ffi.verify, """ - struct foo_s { struct { int a; short b; }; union { char c, d; }; }; - """) - # works fine now - #py.test.raises(VerificationError, ffi.verify, """ - # struct foo_s { struct { int a; char e, b; }; union { char c, d; }; }; - #""") - -def test_nested_anonymous_struct_inexact_1(): - ffi = FFI() - ffi.cdef(""" - struct foo_s { struct { char b; ...; }; union { char c, d; }; }; - """) - ffi.verify(""" - struct foo_s { int a, padding; char c, d, b; }; - """) - assert ffi.sizeof("struct foo_s") == 3 * ffi.sizeof("int") - -def test_nested_anonymous_struct_inexact_2(): - ffi = FFI() - ffi.cdef(""" - struct foo_s { union { char c, d; }; struct { int a; char b; }; ...; }; - """) - ffi.verify(""" - struct foo_s { int a, padding; char c, d, b; }; - """) - assert ffi.sizeof("struct foo_s") == 3 * ffi.sizeof("int") - -def test_ffi_union(): - ffi = FFI() - ffi.cdef("union foo_u { char x; long *z; };") - ffi.verify("union foo_u { char x; int y; long *z; };") - -def test_ffi_union_partial(): - ffi = FFI() - ffi.cdef("union foo_u { char x; ...; };") - ffi.verify("union foo_u { char x; int y; };") - assert ffi.sizeof("union foo_u") == 4 - -def test_ffi_union_with_partial_struct(): - ffi = FFI() - ffi.cdef("struct foo_s { int x; ...; }; union foo_u { struct foo_s s; };") - ffi.verify("struct foo_s { int a; int x; }; " - "union foo_u { char b[32]; struct foo_s s; };") - assert ffi.sizeof("struct foo_s") == 8 - assert ffi.sizeof("union foo_u") == 32 - -def test_ffi_union_partial_2(): - ffi = FFI() - ffi.cdef("typedef union { char x; ...; } u1;") - ffi.verify("typedef union { char x; int y; } u1;") - assert ffi.sizeof("u1") == 4 - -def test_ffi_union_with_partial_struct_2(): - ffi = FFI() - ffi.cdef("typedef struct { int x; ...; } s1;" - "typedef union { s1 s; } u1;") - ffi.verify("typedef struct { int a; int x; } s1; " - "typedef union { char b[32]; s1 s; } u1;") - assert ffi.sizeof("s1") == 8 - assert ffi.sizeof("u1") == 32 - assert ffi.offsetof("u1", "s") == 0 - -def test_ffi_struct_packed(): - if sys.platform == 'win32': - py.test.skip("needs a GCC extension") - ffi = FFI() - ffi.cdef("struct foo_s { int b; ...; };") - ffi.verify(""" - struct foo_s { - char a; - int b; - } __attribute__((packed)); - """) - -def test_tmpdir(): - import tempfile, os - from testing.udir import udir - tmpdir = tempfile.mkdtemp(dir=str(udir)) - ffi = FFI() - ffi.cdef("int foo(int);") - lib = ffi.verify("int foo(int a) { return a + 42; }", tmpdir=tmpdir) - assert os.listdir(tmpdir) - assert lib.foo(100) == 142 - -def test_relative_to(): - py.test.skip("not available") - import tempfile, os - from testing.udir import udir - tmpdir = tempfile.mkdtemp(dir=str(udir)) - ffi = FFI() - ffi.cdef("int foo(int);") - f = open(os.path.join(tmpdir, 'foo.h'), 'w') - f.write("int foo(int a) { return a + 42; }\n") - f.close() - lib = ffi.verify('#include "foo.h"', - include_dirs=['.'], - relative_to=os.path.join(tmpdir, 'x')) - assert lib.foo(100) == 142 - -def test_bug1(): - ffi = FFI() - ffi.cdef(""" - typedef struct tdlhandle_s { ...; } *tdl_handle_t; - typedef struct my_error_code_ { - tdl_handle_t *rh; - } my_error_code_t; - """) - ffi.verify(""" - typedef struct tdlhandle_s { int foo; } *tdl_handle_t; - typedef struct my_error_code_ { - tdl_handle_t *rh; - } my_error_code_t; - """) - -def test_bool(): - if sys.platform == 'win32': - py.test.skip("_Bool not in MSVC") - ffi = FFI() - ffi.cdef("struct foo_s { _Bool x; };" - "_Bool foo(_Bool); static _Bool (*foop)(_Bool);") - lib = ffi.verify(""" - struct foo_s { _Bool x; }; - int foo(int arg) { - return !arg; - } - _Bool _foofunc(_Bool x) { - return !x; - } - static _Bool (*foop)(_Bool) = _foofunc; - """) - p = ffi.new("struct foo_s *") - p.x = 1 - assert p.x is True - with pytest.raises(OverflowError): - p.x = -1 - with pytest.raises(TypeError): - p.x = 0.0 - assert lib.foop(1) is False - assert lib.foop(True) is False - assert lib.foop(0) is True - py.test.raises(OverflowError, lib.foop, 42) - py.test.raises(TypeError, lib.foop, 0.0) - assert lib.foo(1) is False - assert lib.foo(True) is False - assert lib.foo(0) is True - py.test.raises(OverflowError, lib.foo, 42) - py.test.raises(TypeError, lib.foo, 0.0) - assert int(ffi.cast("_Bool", long(1))) == 1 - assert int(ffi.cast("_Bool", long(0))) == 0 - assert int(ffi.cast("_Bool", long(-1))) == 1 - assert int(ffi.cast("_Bool", 10**200)) == 1 - assert int(ffi.cast("_Bool", 10**40000)) == 1 - # - class Foo(object): - def __int__(self): - self.seen = 1 - return result - f = Foo() - f.seen = 0 - result = 42 - assert int(ffi.cast("_Bool", f)) == 1 - assert f.seen - f.seen = 0 - result = 0 - assert int(ffi.cast("_Bool", f)) == 0 - assert f.seen - # - py.test.raises(TypeError, ffi.cast, "_Bool", []) - -def test_bool_on_long_double(): - if sys.platform == 'win32': - py.test.skip("_Bool not in MSVC") - f = 1E-250 - if f == 0.0 or f*f != 0.0: - py.test.skip("unexpected precision") - ffi = FFI() - ffi.cdef("long double square(long double f); _Bool opposite(_Bool);") - lib = ffi.verify("long double square(long double f) { return f*f; }\n" - "_Bool opposite(_Bool x) { return !x; }") - f0 = lib.square(0.0) - f2 = lib.square(f) - f3 = lib.square(f * 2.0) - if repr(f2) == repr(f3): - py.test.skip("long double doesn't have enough precision") - assert float(f0) == float(f2) == float(f3) == 0.0 # too tiny for 'double' - assert int(ffi.cast("_Bool", f2)) == 1 - assert int(ffi.cast("_Bool", f3)) == 1 - assert int(ffi.cast("_Bool", f0)) == 0 - py.test.raises(TypeError, lib.opposite, f2) - -def test_cannot_pass_float(): - for basetype in ['char', 'short', 'int', 'long', 'long long']: - for sign in ['signed', 'unsigned']: - type = '%s %s' % (sign, basetype) - ffi = FFI() - ffi.cdef("struct foo_s { %s x; };\n" - "int foo(%s);" % (type, type)) - lib = ffi.verify(""" - struct foo_s { %s x; }; - int foo(%s arg) { - return !arg; - } - """ % (type, type)) - p = ffi.new("struct foo_s *") - with pytest.raises(TypeError): - p.x = 0.0 - assert lib.foo(42) == 0 - assert lib.foo(0) == 1 - py.test.raises(TypeError, lib.foo, 0.0) - -def test_addressof(): - ffi = FFI() - ffi.cdef(""" - struct point_s { int x, y; }; - struct foo_s { int z; struct point_s point; }; - struct point_s sum_coord(struct point_s *); - """) - lib = ffi.verify(""" - struct point_s { int x, y; }; - struct foo_s { int z; struct point_s point; }; - struct point_s sum_coord(struct point_s *point) { - struct point_s r; - r.x = point->x + point->y; - r.y = point->x - point->y; - return r; - } - """) - p = ffi.new("struct foo_s *") - p.point.x = 16 - p.point.y = 9 - py.test.raises(TypeError, lib.sum_coord, p.point) - res = lib.sum_coord(ffi.addressof(p.point)) - assert res.x == 25 - assert res.y == 7 - res2 = lib.sum_coord(ffi.addressof(res)) - assert res2.x == 32 - assert res2.y == 18 - py.test.raises(TypeError, lib.sum_coord, res2) - -def test_callback_in_thread(): - py.test.xfail("adapt or remove") - if sys.platform == 'win32': - py.test.skip("pthread only") - import os, subprocess, imp - arg = os.path.join(os.path.dirname(__file__), 'callback_in_thread.py') - g = subprocess.Popen([sys.executable, arg, - os.path.dirname(imp.find_module('cffi')[1])]) - result = g.wait() - assert result == 0 - -def test_keepalive_lib(): - py.test.xfail("adapt or remove") - ffi = FFI() - ffi.cdef("int foobar(void);") - lib = ffi.verify("int foobar(void) { return 42; }") - func = lib.foobar - ffi_r = weakref.ref(ffi) - lib_r = weakref.ref(lib) - del ffi - import gc; gc.collect() # lib stays alive - assert lib_r() is not None - assert ffi_r() is not None - assert func() == 42 - -def test_keepalive_ffi(): - py.test.xfail("adapt or remove") - ffi = FFI() - ffi.cdef("int foobar(void);") - lib = ffi.verify("int foobar(void) { return 42; }") - func = lib.foobar - ffi_r = weakref.ref(ffi) - lib_r = weakref.ref(lib) - del lib - import gc; gc.collect() # ffi stays alive - assert ffi_r() is not None - assert lib_r() is not None - assert func() == 42 - -def test_FILE_stored_in_stdout(): - if not sys.platform.startswith('linux'): - py.test.skip("likely, we cannot assign to stdout") - ffi = FFI() - ffi.cdef("int printf(const char *, ...); FILE *setstdout(FILE *);") - lib = ffi.verify(""" - #include <stdio.h> - FILE *setstdout(FILE *f) { - FILE *result = stdout; - stdout = f; - return result; - } - """) - import os - fdr, fdw = os.pipe() - fw1 = os.fdopen(fdw, 'wb', 256) - old_stdout = lib.setstdout(fw1) - try: - # - fw1.write(b"X") - r = lib.printf(b"hello, %d!\n", ffi.cast("int", 42)) - fw1.close() - assert r == len("hello, 42!\n") - # - finally: - lib.setstdout(old_stdout) - # - result = os.read(fdr, 256) - os.close(fdr) - # the 'X' might remain in the user-level buffer of 'fw1' and - # end up showing up after the 'hello, 42!\n' - assert result == b"Xhello, 42!\n" or result == b"hello, 42!\nX" - -def test_FILE_stored_explicitly(): - ffi = FFI() - ffi.cdef("int myprintf11(const char *, int); extern FILE *myfile;") - lib = ffi.verify(""" - #include <stdio.h> - FILE *myfile; - int myprintf11(const char *out, int value) { - return fprintf(myfile, out, value); - } - """) - import os - fdr, fdw = os.pipe() - fw1 = os.fdopen(fdw, 'wb', 256) - lib.myfile = ffi.cast("FILE *", fw1) - # - fw1.write(b"X") - r = lib.myprintf11(b"hello, %d!\n", ffi.cast("int", 42)) - fw1.close() - assert r == len("hello, 42!\n") - # - result = os.read(fdr, 256) - os.close(fdr) - # the 'X' might remain in the user-level buffer of 'fw1' and - # end up showing up after the 'hello, 42!\n' - assert result == b"Xhello, 42!\n" or result == b"hello, 42!\nX" - -def test_global_array_with_missing_length(): - ffi = FFI() - ffi.cdef("extern int fooarray[];") - lib = ffi.verify("int fooarray[50];") - assert repr(lib.fooarray).startswith("<cdata 'int *'") - -def test_global_array_with_dotdotdot_length(): - ffi = FFI() - ffi.cdef("extern int fooarray[...];") - lib = ffi.verify("int fooarray[50];") - assert repr(lib.fooarray).startswith("<cdata 'int[50]'") - -def test_bad_global_array_with_dotdotdot_length(): - py.test.xfail("was detected only because 23 bytes cannot be divided by 4; " - "redo more generally") - ffi = FFI() - ffi.cdef("extern int fooarray[...];") - py.test.raises(VerificationError, ffi.verify, "char fooarray[23];") - -def test_struct_containing_struct(): - ffi = FFI() - ffi.cdef("struct foo_s { ...; }; struct bar_s { struct foo_s f; ...; };") - ffi.verify("struct foo_s { int x; }; struct bar_s { struct foo_s f; };") - # - ffi = FFI() - ffi.cdef("struct foo_s { struct bar_s f; ...; }; struct bar_s { ...; };") - ffi.verify("struct bar_s { int x; }; struct foo_s { struct bar_s f; };") - -def test_struct_returned_by_func(): - ffi = FFI() - ffi.cdef("typedef ... foo_t; foo_t myfunc(void);") - e = py.test.raises(TypeError, ffi.verify, - "typedef struct { int x; } foo_t; " - "foo_t myfunc(void) { foo_t x = { 42 }; return x; }") - assert str(e.value) == ( - "function myfunc: 'foo_t' is used as result type, but is opaque") - -def test_include(): - ffi1 = FFI() - ffi1.cdef("typedef struct { int x; ...; } foo_t;") - ffi1.verify("typedef struct { int y, x; } foo_t;") - ffi2 = FFI() - ffi2.include(ffi1) - ffi2.cdef("int myfunc(foo_t *);") - lib = ffi2.verify("typedef struct { int y, x; } foo_t;" - "int myfunc(foo_t *p) { return 42 * p->x; }") - res = lib.myfunc(ffi2.new("foo_t *", {'x': 10})) - assert res == 420 - res = lib.myfunc(ffi1.new("foo_t *", {'x': -10})) - assert res == -420 - -def test_include_enum(): - ffi1 = FFI() - ffi1.cdef("enum foo_e { AA, ... };") - lib1 = ffi1.verify("enum foo_e { CC, BB, AA };") - ffi2 = FFI() - ffi2.include(ffi1) - ffi2.cdef("int myfunc(enum foo_e);") - lib2 = ffi2.verify("enum foo_e { CC, BB, AA };" - "int myfunc(enum foo_e x) { return (int)x; }") - res = lib2.myfunc(lib2.AA) - assert res == 2 - -def test_named_pointer_as_argument(): - ffi = FFI() - ffi.cdef("typedef struct { int x; } *mystruct_p;\n" - "mystruct_p ff5a(mystruct_p);") - lib = ffi.verify("typedef struct { int x; } *mystruct_p;\n" - "mystruct_p ff5a(mystruct_p p) { p->x += 40; return p; }") - p = ffi.new("mystruct_p", [-2]) - q = lib.ff5a(p) - assert q == p - assert p.x == 38 - -def test_enum_size(): - cases = [('123', 4, 4294967295), - ('4294967295U', 4, 4294967295), - ('-123', 4, -1), - ('-2147483647-1', 4, -1), - ] - if FFI().sizeof("long") == 8: - cases += [('4294967296L', 8, 2**64-1), - ('%dUL' % (2**64-1), 8, 2**64-1), - ('-2147483649L', 8, -1), - ('%dL-1L' % (1-2**63), 8, -1)] - for hidden_value, expected_size, expected_minus1 in cases: - if sys.platform == 'win32' and 'U' in hidden_value: - continue # skipped on Windows - ffi = FFI() - ffi.cdef("enum foo_e { AA, BB, ... };") - lib = ffi.verify("enum foo_e { AA, BB=%s };" % hidden_value) - assert lib.AA == 0 - assert lib.BB == eval(hidden_value.replace('U', '').replace('L', '')) - assert ffi.sizeof("enum foo_e") == expected_size - if sys.platform != 'win32': - assert int(ffi.cast("enum foo_e", -1)) == expected_minus1 - # test with the large value hidden: - # disabled so far, doesn't work -## for hidden_value, expected_size, expected_minus1 in cases: -## ffi = FFI() -## ffi.cdef("enum foo_e { AA, BB, ... };") -## lib = ffi.verify("enum foo_e { AA, BB=%s };" % hidden_value) -## assert lib.AA == 0 -## assert ffi.sizeof("enum foo_e") == expected_size -## assert int(ffi.cast("enum foo_e", -1)) == expected_minus1 - -def test_enum_bug118(): - maxulong = 256 ** FFI().sizeof("unsigned long") - 1 - for c2, c2c in [(-1, ''), - (-1, ''), - (0xffffffff, 'U'), - (maxulong, 'UL'), - (-int(maxulong / 3), 'L')]: - if c2c and sys.platform == 'win32': - continue # enums may always be signed with MSVC - ffi = FFI() - ffi.cdef("enum foo_e { AA };") - lib = ffi.verify("enum foo_e { AA=%s%s };" % (c2, c2c)) - assert lib.AA == c2 - -def test_string_to_voidp_arg(): - ffi = FFI() - ffi.cdef("int myfunc(void *);") - lib = ffi.verify("int myfunc(void *p) { return ((signed char *)p)[0]; }") - res = lib.myfunc(b"hi!") - assert res == ord(b"h") - p = ffi.new("char[]", b"gah") - res = lib.myfunc(p) - assert res == ord(b"g") - res = lib.myfunc(ffi.cast("void *", p)) - assert res == ord(b"g") - res = lib.myfunc(ffi.cast("int *", p)) - assert res == ord(b"g") - -def test_callback_indirection(): - ffi = FFI() - ffi.cdef(""" - static int (*python_callback)(int how_many, int *values); - int (*const c_callback)(int,...); /* pass this ptr to C routines */ - int some_c_function(int(*cb)(int,...)); - """) - lib = ffi.verify(""" - #include <stdarg.h> - #ifdef _WIN32 - #include <malloc.h> - #define alloca _alloca - #else - # ifdef __FreeBSD__ - # include <stdlib.h> - # else - # include <alloca.h> - # endif - #endif - static int (*python_callback)(int how_many, int *values); - static int c_callback(int how_many, ...) { - va_list ap; - /* collect the "..." arguments into the values[] array */ - int i, *values = alloca((size_t)how_many * sizeof(int)); - va_start(ap, how_many); - for (i=0; i<how_many; i++) - values[i] = va_arg(ap, int); - va_end(ap); - return python_callback(how_many, values); - } - int some_c_function(int(*cb)(int,...)) { - int result = cb(2, 10, 20); - result += cb(3, 30, 40, 50); - return result; - } - """) - seen = [] - @ffi.callback("int(int, int*)") - def python_callback(how_many, values): - seen.append([values[i] for i in range(how_many)]) - return 42 - lib.python_callback = python_callback - - res = lib.some_c_function(lib.c_callback) - assert res == 84 - assert seen == [[10, 20], [30, 40, 50]] - -def test_floatstar_argument(): - ffi = FFI() - ffi.cdef("float sum3floats(float *);") - lib = ffi.verify(""" - float sum3floats(float *f) { - return f[0] + f[1] + f[2]; - } - """) - assert lib.sum3floats((1.5, 2.5, 3.5)) == 7.5 - p = ffi.new("float[]", (1.5, 2.5, 3.5)) - assert lib.sum3floats(p) == 7.5 - -def test_charstar_argument(): - ffi = FFI() - ffi.cdef("char sum3chars(char *);") - lib = ffi.verify(""" - char sum3chars(char *f) { - return (char)(f[0] + f[1] + f[2]); - } - """) - assert lib.sum3chars((b'\x10', b'\x20', b'\x30')) == b'\x60' - p = ffi.new("char[]", b'\x10\x20\x30') - assert lib.sum3chars(p) == b'\x60' - -def test_passing_string_or_NULL(): - ffi = FFI() - ffi.cdef("int seeme1(char *); int seeme2(int *);") - lib = ffi.verify(""" - int seeme1(char *x) { - return (x == NULL); - } - int seeme2(int *x) { - return (x == NULL); - } - """) - assert lib.seeme1(b"foo") == 0 - assert lib.seeme1(ffi.NULL) == 1 - assert lib.seeme2([42, 43]) == 0 - assert lib.seeme2(ffi.NULL) == 1 - py.test.raises(TypeError, lib.seeme1, None) - py.test.raises(TypeError, lib.seeme2, None) - py.test.raises(TypeError, lib.seeme1, 0.0) - py.test.raises(TypeError, lib.seeme2, 0.0) - py.test.raises(TypeError, lib.seeme1, 0) - py.test.raises(TypeError, lib.seeme2, 0) - zeroL = 99999999999999999999 - zeroL -= 99999999999999999999 - py.test.raises(TypeError, lib.seeme2, zeroL) - -def test_typeof_function(): - ffi = FFI() - ffi.cdef("int foo(int, char);") - lib = ffi.verify("int foo(int x, char y) { (void)x; (void)y; return 42; }") - ctype = ffi.typeof(lib.foo) - assert len(ctype.args) == 2 - assert ctype.result == ffi.typeof("int") - -def test_call_with_voidstar_arg(): - ffi = FFI() - ffi.cdef("int f(void *);") - lib = ffi.verify("int f(void *x) { return ((char*)x)[0]; }") - assert lib.f(b"foobar") == ord(b"f") - -def test_dir(): - ffi = FFI() - ffi.cdef("""void somefunc(void); - extern int somevar, somearray[2]; - static char *const sv2; - enum my_e { AA, BB, ... }; - #define FOO ...""") - lib = ffi.verify("""void somefunc(void) { } - int somevar, somearray[2]; - #define sv2 "text" - enum my_e { AA, BB }; - #define FOO 42""") - assert dir(lib) == ['AA', 'BB', 'FOO', 'somearray', - 'somefunc', 'somevar', 'sv2'] - -def test_typeof_func_with_struct_argument(): - ffi = FFI() - ffi.cdef("""struct s { int a; }; int foo(struct s);""") - lib = ffi.verify("""struct s { int a; }; - int foo(struct s x) { return x.a; }""") - s = ffi.new("struct s *", [-1234]) - m = lib.foo(s[0]) - assert m == -1234 - assert repr(ffi.typeof(lib.foo)) == "<ctype 'int(*)(struct s)'>" - -def test_bug_const_char_ptr_array_1(): - ffi = FFI() - ffi.cdef("""extern const char *a[...];""") - lib = ffi.verify("""const char *a[5];""") - assert repr(ffi.typeof(lib.a)) == "<ctype 'char *[5]'>" - -def test_bug_const_char_ptr_array_2(): - ffi = FFI() - ffi.cdef("""extern const int a[];""") - lib = ffi.verify("""const int a[5];""") - assert repr(ffi.typeof(lib.a)) == "<ctype 'int *'>" - -def _test_various_calls(force_libffi): - cdef_source = """ - extern int xvalue; - extern long long ivalue, rvalue; - extern float fvalue; - extern double dvalue; - extern long double Dvalue; - signed char tf_bb(signed char x, signed char c); - unsigned char tf_bB(signed char x, unsigned char c); - short tf_bh(signed char x, short c); - unsigned short tf_bH(signed char x, unsigned short c); - int tf_bi(signed char x, int c); - unsigned int tf_bI(signed char x, unsigned int c); - long tf_bl(signed char x, long c); - unsigned long tf_bL(signed char x, unsigned long c); - long long tf_bq(signed char x, long long c); - unsigned long long tf_bQ(signed char x, unsigned long long c); - float tf_bf(signed char x, float c); - double tf_bd(signed char x, double c); - long double tf_bD(signed char x, long double c); - """ - if force_libffi: - cdef_source = (cdef_source - .replace('tf_', '(*const tf_') - .replace('(signed char x', ')(signed char x')) - ffi = FFI() - ffi.cdef(cdef_source) - lib = ffi.verify(""" - int xvalue; - long long ivalue, rvalue; - float fvalue; - double dvalue; - long double Dvalue; - - typedef signed char b_t; - typedef unsigned char B_t; - typedef short h_t; - typedef unsigned short H_t; - typedef int i_t; - typedef unsigned int I_t; - typedef long l_t; - typedef unsigned long L_t; - typedef long long q_t; - typedef unsigned long long Q_t; - typedef float f_t; - typedef double d_t; - typedef long double D_t; - #define S(letter) xvalue = (int)x; letter##value = (letter##_t)c; - #define R(letter) return (letter##_t)rvalue; - - signed char tf_bb(signed char x, signed char c) { S(i) R(b) } - unsigned char tf_bB(signed char x, unsigned char c) { S(i) R(B) } - short tf_bh(signed char x, short c) { S(i) R(h) } - unsigned short tf_bH(signed char x, unsigned short c) { S(i) R(H) } - int tf_bi(signed char x, int c) { S(i) R(i) } - unsigned int tf_bI(signed char x, unsigned int c) { S(i) R(I) } - long tf_bl(signed char x, long c) { S(i) R(l) } - unsigned long tf_bL(signed char x, unsigned long c) { S(i) R(L) } - long long tf_bq(signed char x, long long c) { S(i) R(q) } - unsigned long long tf_bQ(signed char x, unsigned long long c) { S(i) R(Q) } - float tf_bf(signed char x, float c) { S(f) R(f) } - double tf_bd(signed char x, double c) { S(d) R(d) } - long double tf_bD(signed char x, long double c) { S(D) R(D) } - """) - lib.rvalue = 0x7182838485868788 - for kind, cname in [('b', 'signed char'), - ('B', 'unsigned char'), - ('h', 'short'), - ('H', 'unsigned short'), - ('i', 'int'), - ('I', 'unsigned int'), - ('l', 'long'), - ('L', 'unsigned long'), - ('q', 'long long'), - ('Q', 'unsigned long long'), - ('f', 'float'), - ('d', 'double'), - ('D', 'long double')]: - sign = +1 if 'unsigned' in cname else -1 - lib.xvalue = 0 - lib.ivalue = 0 - lib.fvalue = 0 - lib.dvalue = 0 - lib.Dvalue = 0 - fun = getattr(lib, 'tf_b' + kind) - res = fun(-42, sign * 99) - if kind == 'D': - res = float(res) - assert res == int(ffi.cast(cname, 0x7182838485868788)) - assert lib.xvalue == -42 - if kind in 'fdD': - assert float(getattr(lib, kind + 'value')) == -99.0 - else: - assert lib.ivalue == sign * 99 - -def test_various_calls_direct(): - _test_various_calls(force_libffi=False) - -def test_various_calls_libffi(): - _test_various_calls(force_libffi=True) - -def test_ptr_to_opaque(): - ffi = FFI() - ffi.cdef("typedef ... foo_t; int f1(foo_t*); foo_t *f2(int);") - lib = ffi.verify(""" - #include <stdlib.h> - typedef struct { int x; } foo_t; - int f1(foo_t* p) { - int x = p->x; - free(p); - return x; - } - foo_t *f2(int x) { - foo_t *p = malloc(sizeof(foo_t)); - p->x = x; - return p; - } - """) - p = lib.f2(42) - x = lib.f1(p) - assert x == 42 - -def _run_in_multiple_threads(test1): - test1() - import sys - try: - import thread - except ImportError: - import _thread as thread - errors = [] - def wrapper(lock): - try: - test1() - except: - errors.append(sys.exc_info()) - lock.release() - locks = [] - for i in range(10): - _lock = thread.allocate_lock() - _lock.acquire() - thread.start_new_thread(wrapper, (_lock,)) - locks.append(_lock) - for _lock in locks: - _lock.acquire() - if errors: - raise errors[0][1] - -def test_errno_working_even_with_pypys_jit(): - ffi = FFI() - ffi.cdef("int f(int);") - lib = ffi.verify(""" - #include <errno.h> - int f(int x) { return (errno = errno + x); } - """) - @_run_in_multiple_threads - def test1(): - ffi.errno = 0 - for i in range(10000): - e = lib.f(1) - assert e == i + 1 - assert ffi.errno == e - for i in range(10000): - ffi.errno = i - e = lib.f(42) - assert e == i + 42 - -def test_getlasterror_working_even_with_pypys_jit(): - if sys.platform != 'win32': - py.test.skip("win32-only test") - ffi = FFI() - ffi.cdef("void SetLastError(DWORD);") - lib = ffi.dlopen("Kernel32.dll") - @_run_in_multiple_threads - def test1(): - for i in range(10000): - n = (1 << 29) + i - lib.SetLastError(n) - assert ffi.getwinerror()[0] == n - -def test_verify_dlopen_flags(): - if not hasattr(sys, 'setdlopenflags'): - py.test.skip("requires sys.setdlopenflags()") - # Careful with RTLD_GLOBAL. If by chance the FFI is not deleted - # promptly, like on PyPy, then other tests may see the same - # exported symbols as well. So we must not export a simple name - # like 'foo'! - old = sys.getdlopenflags() - try: - ffi1 = FFI() - ffi1.cdef("extern int foo_verify_dlopen_flags_1;") - sys.setdlopenflags(ffi1.RTLD_GLOBAL | ffi1.RTLD_NOW) - lib1 = ffi1.verify("int foo_verify_dlopen_flags_1;") - finally: - sys.setdlopenflags(old) - - ffi2 = FFI() - ffi2.cdef("int *getptr(void);") - lib2 = ffi2.verify(""" - extern int foo_verify_dlopen_flags_1; - static int *getptr(void) { return &foo_verify_dlopen_flags_1; } - """) - p = lib2.getptr() - assert ffi1.addressof(lib1, 'foo_verify_dlopen_flags_1') == p - -def test_consider_not_implemented_function_type(): - ffi = FFI() - ffi.cdef("typedef union { int a; float b; } Data;" - "typedef struct { int a:2; } MyStr;" - "typedef void (*foofunc_t)(Data);" - "typedef Data (*bazfunc_t)(void);" - "typedef MyStr (*barfunc_t)(void);") - fooptr = ffi.cast("foofunc_t", 123) - bazptr = ffi.cast("bazfunc_t", 123) - barptr = ffi.cast("barfunc_t", 123) - # assert did not crash so far - e = py.test.raises(NotImplementedError, fooptr, ffi.new("Data *")) - assert str(e.value) == ( - "ctype 'Data' not supported as argument by libffi. Unions 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)") - e = py.test.raises(NotImplementedError, bazptr) - assert str(e.value) == ( - "ctype 'Data' not supported as return value by libffi. Unions are " - "only supported as return value if the function is 'API mode' and " - "non-variadic (i.e. declared inside ffibuilder.cdef()+" - "ffibuilder.set_source() and not taking a final '...' argument)") - e = py.test.raises(NotImplementedError, barptr) - assert str(e.value) == ( - "ctype 'MyStr' not supported as return value. It is a struct with " - "bit fields, which libffi does not support. Such structs are only " - "supported as return value if the function is 'API mode' and non-" - "variadic (i.e. declared inside ffibuilder.cdef()+ffibuilder." - "set_source() and not taking a final '...' argument)") - -def test_verify_extra_arguments(): - ffi = FFI() - ffi.cdef("#define ABA ...") - lib = ffi.verify("", define_macros=[('ABA', '42')]) - assert lib.ABA == 42 - -def test_implicit_unicode_on_windows(): - from cffi import FFIError - if sys.platform != 'win32': - py.test.skip("win32-only test") - ffi = FFI() - e = py.test.raises(FFIError, ffi.cdef, "int foo(LPTSTR);") - assert str(e.value) == ("The Windows type 'LPTSTR' is only available after" - " you call ffi.set_unicode()") - for with_unicode in [True, False]: - ffi = FFI() - ffi.set_unicode(with_unicode) - ffi.cdef(""" - DWORD GetModuleFileName(HMODULE hModule, LPTSTR lpFilename, - DWORD nSize); - """) - lib = ffi.verify(""" - #include <windows.h> - """, libraries=['Kernel32']) - outbuf = ffi.new("TCHAR[]", 200) - n = lib.GetModuleFileName(ffi.NULL, outbuf, 500) - assert 0 < n < 500 - for i in range(n): - #print repr(outbuf[i]) - assert ord(outbuf[i]) != 0 - assert ord(outbuf[n]) == 0 - assert ord(outbuf[0]) < 128 # should be a letter, or '\' - -def test_define_known_value(): - ffi = FFI() - ffi.cdef("#define FOO 0x123") - lib = ffi.verify("#define FOO 0x123") - assert lib.FOO == 0x123 - -def test_define_wrong_value(): - ffi = FFI() - ffi.cdef("#define FOO 123") - lib = ffi.verify("#define FOO 124") # used to complain - with pytest.raises(ffi.error) as e: - lib.FOO - assert str(e.value) == ("the C compiler says 'FOO' is equal to 124 (0x7c)," - " but the cdef disagrees") - -def test_some_integer_type_for_issue73(): - ffi = FFI() - ffi.cdef(""" - typedef int... AnIntegerWith32Bits; - typedef AnIntegerWith32Bits (*AFunctionReturningInteger) (void); - AnIntegerWith32Bits InvokeFunction(AFunctionReturningInteger); - """) - lib = ffi.verify(""" - #ifdef __LP64__ - typedef int AnIntegerWith32Bits; - #else - typedef long AnIntegerWith32Bits; - #endif - typedef AnIntegerWith32Bits (*AFunctionReturningInteger) (void); - AnIntegerWith32Bits InvokeFunction(AFunctionReturningInteger f) { - return f(); - } - """) - @ffi.callback("AFunctionReturningInteger") - def add(): - return 3 + 4 - x = lib.InvokeFunction(add) - assert x == 7 - -def test_unsupported_some_primitive_types(): - ffi = FFI() - py.test.raises((FFIError, # with pycparser <= 2.17 - CDefError), # with pycparser >= 2.18 - ffi.cdef, """typedef void... foo_t;""") - # - ffi.cdef("typedef int... foo_t;") - py.test.raises(VerificationError, ffi.verify, "typedef float foo_t;") - -def test_windows_dllimport_data(): - if sys.platform != 'win32': - py.test.skip("Windows only") - from testing.udir import udir - tmpfile = udir.join('dllimport_data.c') - tmpfile.write('int my_value = 42;\n') - ffi = FFI() - ffi.cdef("int my_value;") - lib = ffi.verify("extern __declspec(dllimport) int my_value;", - sources = [str(tmpfile)]) - assert lib.my_value == 42 - -def test_macro_var(): - ffi = FFI() - ffi.cdef("extern int myarray[50], my_value;") - lib = ffi.verify(""" - int myarray[50]; - int *get_my_value(void) { - static int index = 0; - return &myarray[index++]; - } - #define my_value (*get_my_value()) - """) - assert lib.my_value == 0 # [0] - lib.my_value = 42 # [1] - assert lib.myarray[1] == 42 - assert lib.my_value == 0 # [2] - lib.myarray[3] = 63 - assert lib.my_value == 63 # [3] - p = ffi.addressof(lib, 'my_value') # [4] - assert p[-1] == 63 - assert p[0] == 0 - assert p == lib.myarray + 4 - p[1] = 82 - assert lib.my_value == 82 # [5] - -def test_const_pointer_to_pointer(): - ffi = FFI() - ffi.cdef("struct s { char *const *a; };") - ffi.verify("struct s { char *const *a; };") - -def test_share_FILE(): - ffi1 = FFI() - ffi1.cdef("void do_stuff(FILE *);") - lib1 = ffi1.verify("void do_stuff(FILE *f) { (void)f; }") - ffi2 = FFI() - ffi2.cdef("FILE *barize(void);") - lib2 = ffi2.verify("FILE *barize(void) { return NULL; }") - lib1.do_stuff(lib2.barize()) - -def test_win_common_types(): - if sys.platform != 'win32': - py.test.skip("Windows only") - ffi = FFI() - ffi.set_unicode(True) - ffi.verify("") - assert ffi.typeof("PBYTE") is ffi.typeof("unsigned char *") - if sys.maxsize > 2**32: - expected = "unsigned long long" - else: - expected = "unsigned int" - assert ffi.typeof("UINT_PTR") is ffi.typeof(expected) - assert ffi.typeof("PTSTR") is ffi.typeof("wchar_t *") - -def _only_test_on_linux_intel(): - if not sys.platform.startswith('linux'): - py.test.skip('only running the memory-intensive test on Linux') - import platform - machine = platform.machine() - if 'x86' not in machine and 'x64' not in machine: - py.test.skip('only running the memory-intensive test on x86/x64') - -def test_ffi_gc_size_arg(): - _only_test_on_linux_intel() - ffi = FFI() - ffi.cdef("void *malloc(size_t); void free(void *);") - lib = ffi.verify(r""" - #include <stdlib.h> - """) - for i in range(2000): - p = lib.malloc(20*1024*1024) # 20 MB - p1 = ffi.cast("char *", p) - for j in range(0, 20*1024*1024, 4096): - p1[j] = b'!' - p = ffi.gc(p, lib.free, 20*1024*1024) - del p - # with PyPy's GC, the above would rapidly consume 40 GB of RAM - # without the third argument to ffi.gc() - -def test_ffi_gc_size_arg_2(): - # a variant of the above: this "attack" works on cpython's cyclic gc too - # and I found no obvious way to prevent that. So for now, this test - # is skipped on CPython, where it eats all the memory. - if '__pypy__' not in sys.builtin_module_names: - py.test.skip("find a way to tweak the cyclic GC of CPython") - _only_test_on_linux_intel() - ffi = FFI() - ffi.cdef("void *malloc(size_t); void free(void *);") - lib = ffi.verify(r""" - #include <stdlib.h> - """) - class X(object): - pass - for i in range(2000): - p = lib.malloc(50*1024*1024) # 50 MB - p1 = ffi.cast("char *", p) - for j in range(0, 50*1024*1024, 4096): - p1[j] = b'!' - p = ffi.gc(p, lib.free, 50*1024*1024) - x = X() - x.p = p - x.cyclic = x - del p, x - -def test_ffi_new_with_cycles(): - # still another variant, with ffi.new() - if '__pypy__' not in sys.builtin_module_names: - py.test.skip("find a way to tweak the cyclic GC of CPython") - ffi = FFI() - ffi.cdef("") - lib = ffi.verify("") - class X(object): - pass - for i in range(2000): - p = ffi.new("char[]", 50*1024*1024) # 50 MB - for j in range(0, 50*1024*1024, 4096): - p[j] = b'!' - x = X() - x.p = p - x.cyclic = x - del p, x diff --git a/testing/cffi1/test_zdist.py b/testing/cffi1/test_zdist.py deleted file mode 100644 index efc1d86..0000000 --- a/testing/cffi1/test_zdist.py +++ /dev/null @@ -1,426 +0,0 @@ -import sys, os, py -import subprocess -import cffi -from testing.udir import udir -from shutil import rmtree -from tempfile import mkdtemp - - -def chdir_to_tmp(f): - f.chdir_to_tmp = True - return f - -def from_outside(f): - f.chdir_to_tmp = False - return f - - -class TestDist(object): - - def setup_method(self, meth): - self.executable = os.path.abspath(sys.executable) - self.rootdir = os.path.abspath(os.path.dirname(os.path.dirname( - cffi.__file__))) - self.udir = udir.join(meth.__name__) - os.mkdir(str(self.udir)) - if meth.chdir_to_tmp: - self.saved_cwd = os.getcwd() - os.chdir(str(self.udir)) - - def teardown_method(self, meth): - if hasattr(self, 'saved_cwd'): - os.chdir(self.saved_cwd) - - def run(self, args, cwd=None): - env = os.environ.copy() - # a horrible hack to prevent distutils from finding ~/.pydistutils.cfg - # (there is the --no-user-cfg option, but not in Python 2.6...) - # NOTE: pointing $HOME to a nonexistent directory can break certain things - # that look there for configuration (like ccache). - tmp_home = mkdtemp() - assert tmp_home != None, "cannot create temporary homedir" - env['HOME'] = tmp_home - if cwd is None: - newpath = self.rootdir - if 'PYTHONPATH' in env: - newpath += os.pathsep + env['PYTHONPATH'] - env['PYTHONPATH'] = newpath - try: - subprocess.check_call([self.executable] + args, cwd=cwd, env=env) - finally: - rmtree(tmp_home) - - def _prepare_setuptools(self): - if hasattr(TestDist, '_setuptools_ready'): - return - try: - import setuptools - except ImportError: - py.test.skip("setuptools not found") - if os.path.exists(os.path.join(self.rootdir, 'setup.py')): - self.run(['setup.py', 'egg_info'], cwd=self.rootdir) - TestDist._setuptools_ready = True - - def check_produced_files(self, content, curdir=None): - if curdir is None: - curdir = str(self.udir) - found_so = None - for name in os.listdir(curdir): - if (name.endswith('.so') or name.endswith('.pyd') or - name.endswith('.dylib') or name.endswith('.dll')): - found_so = os.path.join(curdir, name) - # foo.so => foo - parts = name.split('.') - del parts[-1] - if len(parts) > 1 and parts[-1] != 'bar': - # foo.cpython-34m.so => foo, but foo.bar.so => foo.bar - del parts[-1] - name = '.'.join(parts) - # foo_d => foo (Python 2 debug builds) - if name.endswith('_d') and hasattr(sys, 'gettotalrefcount'): - name = name[:-2] - name += '.SO' - if name.startswith('pycparser') and name.endswith('.egg'): - continue # no clue why this shows up sometimes and not others - if name == '.eggs': - continue # seems new in 3.5, ignore it - assert name in content, "found unexpected file %r" % ( - os.path.join(curdir, name),) - value = content.pop(name) - if value is None: - assert name.endswith('.SO') or ( - os.path.isfile(os.path.join(curdir, name))) - else: - subdir = os.path.join(curdir, name) - assert os.path.isdir(subdir) - if value == '?': - continue - found_so = self.check_produced_files(value, subdir) or found_so - assert content == {}, "files or dirs not produced in %r: %r" % ( - curdir, content.keys()) - return found_so - - @chdir_to_tmp - def test_empty(self): - self.check_produced_files({}) - - @chdir_to_tmp - def test_abi_emit_python_code_1(self): - ffi = cffi.FFI() - ffi.set_source("package_name_1.mymod", None) - ffi.emit_python_code('xyz.py') - self.check_produced_files({'xyz.py': None}) - - @chdir_to_tmp - def test_abi_emit_python_code_2(self): - ffi = cffi.FFI() - ffi.set_source("package_name_1.mymod", None) - py.test.raises(IOError, ffi.emit_python_code, 'unexisting/xyz.py') - - @from_outside - def test_abi_emit_python_code_3(self): - ffi = cffi.FFI() - ffi.set_source("package_name_1.mymod", None) - ffi.emit_python_code(str(self.udir.join('xyt.py'))) - self.check_produced_files({'xyt.py': None}) - - @chdir_to_tmp - def test_abi_compile_1(self): - ffi = cffi.FFI() - ffi.set_source("mod_name_in_package.mymod", None) - x = ffi.compile() - self.check_produced_files({'mod_name_in_package': {'mymod.py': None}}) - assert x == os.path.join('.', 'mod_name_in_package', 'mymod.py') - - @chdir_to_tmp - def test_abi_compile_2(self): - ffi = cffi.FFI() - ffi.set_source("mod_name_in_package.mymod", None) - x = ffi.compile('build2') - self.check_produced_files({'build2': { - 'mod_name_in_package': {'mymod.py': None}}}) - assert x == os.path.join('build2', 'mod_name_in_package', 'mymod.py') - - @from_outside - def test_abi_compile_3(self): - ffi = cffi.FFI() - ffi.set_source("mod_name_in_package.mymod", None) - tmpdir = str(self.udir.join('build3')) - x = ffi.compile(tmpdir) - self.check_produced_files({'build3': { - 'mod_name_in_package': {'mymod.py': None}}}) - assert x == os.path.join(tmpdir, 'mod_name_in_package', 'mymod.py') - - @chdir_to_tmp - def test_api_emit_c_code_1(self): - ffi = cffi.FFI() - ffi.set_source("package_name_1.mymod", "/*code would be here*/") - ffi.emit_c_code('xyz.c') - self.check_produced_files({'xyz.c': None}) - - @chdir_to_tmp - def test_api_emit_c_code_2(self): - ffi = cffi.FFI() - ffi.set_source("package_name_1.mymod", "/*code would be here*/") - py.test.raises(IOError, ffi.emit_c_code, 'unexisting/xyz.c') - - @from_outside - def test_api_emit_c_code_3(self): - ffi = cffi.FFI() - ffi.set_source("package_name_1.mymod", "/*code would be here*/") - ffi.emit_c_code(str(self.udir.join('xyu.c'))) - self.check_produced_files({'xyu.c': None}) - - @chdir_to_tmp - def test_api_compile_1(self): - ffi = cffi.FFI() - ffi.set_source("mod_name_in_package.mymod", "/*code would be here*/") - x = ffi.compile() - if sys.platform != 'win32': - sofile = self.check_produced_files({ - 'mod_name_in_package': {'mymod.SO': None, - 'mymod.c': None, - 'mymod.o': None}}) - assert os.path.isabs(x) and os.path.samefile(x, sofile) - else: - self.check_produced_files({ - 'mod_name_in_package': {'mymod.SO': None, - 'mymod.c': None}, - 'Release': '?'}) - - @chdir_to_tmp - def test_api_compile_2(self): - ffi = cffi.FFI() - ffi.set_source("mod_name_in_package.mymod", "/*code would be here*/") - x = ffi.compile('output') - if sys.platform != 'win32': - sofile = self.check_produced_files({ - 'output': {'mod_name_in_package': {'mymod.SO': None, - 'mymod.c': None, - 'mymod.o': None}}}) - assert os.path.isabs(x) and os.path.samefile(x, sofile) - else: - self.check_produced_files({ - 'output': {'mod_name_in_package': {'mymod.SO': None, - 'mymod.c': None}, - 'Release': '?'}}) - - @from_outside - def test_api_compile_3(self): - ffi = cffi.FFI() - ffi.set_source("mod_name_in_package.mymod", "/*code would be here*/") - x = ffi.compile(str(self.udir.join('foo'))) - if sys.platform != 'win32': - sofile = self.check_produced_files({ - 'foo': {'mod_name_in_package': {'mymod.SO': None, - 'mymod.c': None, - 'mymod.o': None}}}) - assert os.path.isabs(x) and os.path.samefile(x, sofile) - else: - self.check_produced_files({ - 'foo': {'mod_name_in_package': {'mymod.SO': None, - 'mymod.c': None}, - 'Release': '?'}}) - - @chdir_to_tmp - def test_api_compile_explicit_target_1(self): - ffi = cffi.FFI() - ffi.set_source("mod_name_in_package.mymod", "/*code would be here*/") - x = ffi.compile(target="foo.bar.*") - if sys.platform != 'win32': - sofile = self.check_produced_files({ - 'mod_name_in_package': {'foo.bar.SO': None, - 'mymod.c': None, - 'mymod.o': None}}) - assert os.path.isabs(x) and os.path.samefile(x, sofile) - else: - self.check_produced_files({ - 'mod_name_in_package': {'foo.bar.SO': None, - 'mymod.c': None}, - 'Release': '?'}) - - @chdir_to_tmp - def test_api_compile_explicit_target_3(self): - ffi = cffi.FFI() - ffi.set_source("mod_name_in_package.mymod", "/*code would be here*/") - x = ffi.compile(target="foo.bar.baz") - if sys.platform != 'win32': - self.check_produced_files({ - 'mod_name_in_package': {'foo.bar.baz': None, - 'mymod.c': None, - 'mymod.o': None}}) - sofile = os.path.join(str(self.udir), - 'mod_name_in_package', 'foo.bar.baz') - assert os.path.isabs(x) and os.path.samefile(x, sofile) - else: - self.check_produced_files({ - 'mod_name_in_package': {'foo.bar.baz': None, - 'mymod.c': None}, - 'Release': '?'}) - - @chdir_to_tmp - def test_api_distutils_extension_1(self): - ffi = cffi.FFI() - ffi.set_source("mod_name_in_package.mymod", "/*code would be here*/") - ext = ffi.distutils_extension() - self.check_produced_files({'build': { - 'mod_name_in_package': {'mymod.c': None}}}) - if hasattr(os.path, 'samefile'): - assert os.path.samefile(ext.sources[0], - 'build/mod_name_in_package/mymod.c') - - @from_outside - def test_api_distutils_extension_2(self): - ffi = cffi.FFI() - ffi.set_source("mod_name_in_package.mymod", "/*code would be here*/") - ext = ffi.distutils_extension(str(self.udir.join('foo'))) - self.check_produced_files({'foo': { - 'mod_name_in_package': {'mymod.c': None}}}) - if hasattr(os.path, 'samefile'): - assert os.path.samefile(ext.sources[0], - str(self.udir.join('foo/mod_name_in_package/mymod.c'))) - - - def _make_distutils_api(self): - os.mkdir("src") - os.mkdir(os.path.join("src", "pack1")) - with open(os.path.join("src", "pack1", "__init__.py"), "w") as f: - pass - with open("setup.py", "w") as f: - f.write("""if 1: - # https://bugs.python.org/issue23246 - import sys - if sys.platform == 'win32': - try: - import setuptools - except ImportError: - pass - - import cffi - ffi = cffi.FFI() - ffi.set_source("pack1.mymod", "/*code would be here*/") - - from distutils.core import setup - setup(name='example1', - version='0.1', - packages=['pack1'], - package_dir={'': 'src'}, - ext_modules=[ffi.distutils_extension()]) - """) - - @chdir_to_tmp - def test_distutils_api_1(self): - self._make_distutils_api() - self.run(["setup.py", "build"]) - self.check_produced_files({'setup.py': None, - 'build': '?', - 'src': {'pack1': {'__init__.py': None}}}) - - @chdir_to_tmp - def test_distutils_api_2(self): - self._make_distutils_api() - self.run(["setup.py", "build_ext", "-i"]) - self.check_produced_files({'setup.py': None, - 'build': '?', - 'src': {'pack1': {'__init__.py': None, - 'mymod.SO': None}}}) - - def _make_setuptools_abi(self): - self._prepare_setuptools() - os.mkdir("src0") - os.mkdir(os.path.join("src0", "pack2")) - with open(os.path.join("src0", "pack2", "__init__.py"), "w") as f: - pass - with open(os.path.join("src0", "pack2", "_build.py"), "w") as f: - f.write("""if 1: - import cffi - ffi = cffi.FFI() - ffi.set_source("pack2.mymod", None) - """) - with open("setup.py", "w") as f: - f.write("""if 1: - from setuptools import setup - setup(name='example1', - version='0.1', - packages=['pack2'], - package_dir={'': 'src0'}, - cffi_modules=["src0/pack2/_build.py:ffi"]) - """) - - @chdir_to_tmp - def test_setuptools_abi_1(self): - self._make_setuptools_abi() - self.run(["setup.py", "build"]) - self.check_produced_files({'setup.py': None, - 'build': '?', - 'src0': {'pack2': {'__init__.py': None, - '_build.py': None}}}) - - @chdir_to_tmp - def test_setuptools_abi_2(self): - self._make_setuptools_abi() - self.run(["setup.py", "build_ext", "-i"]) - self.check_produced_files({'setup.py': None, - 'src0': {'pack2': {'__init__.py': None, - '_build.py': None, - 'mymod.py': None}}}) - - def _make_setuptools_api(self): - self._prepare_setuptools() - os.mkdir("src1") - os.mkdir(os.path.join("src1", "pack3")) - with open(os.path.join("src1", "pack3", "__init__.py"), "w") as f: - pass - with open(os.path.join("src1", "pack3", "_build.py"), "w") as f: - f.write("""if 1: - import cffi - ffi = cffi.FFI() - ffi.set_source("pack3.mymod", "/*code would be here*/") - ffi._hi_there = 42 - """) - with open("setup.py", "w") as f: - f.write("from __future__ import print_function\n" - """if 1: - from setuptools import setup - from distutils.command.build_ext import build_ext - import os - - class TestBuildExt(build_ext): - def pre_run(self, ext, ffi): - print('_make_setuptools_api: in pre_run:', end=" ") - assert ffi._hi_there == 42 - assert ext.name == "pack3.mymod" - fn = os.path.join(os.path.dirname(self.build_lib), - '..', 'see_me') - print('creating %r' % (fn,)) - open(fn, 'w').close() - - setup(name='example1', - version='0.1', - packages=['pack3'], - package_dir={'': 'src1'}, - cffi_modules=["src1/pack3/_build.py:ffi"], - cmdclass={'build_ext': TestBuildExt}, - ) - """) - - @chdir_to_tmp - def test_setuptools_api_1(self): - self._make_setuptools_api() - self.run(["setup.py", "build"]) - self.check_produced_files({'setup.py': None, - 'build': '?', - 'see_me': None, - 'src1': {'pack3': {'__init__.py': None, - '_build.py': None}}}) - - @chdir_to_tmp - def test_setuptools_api_2(self): - self._make_setuptools_api() - self.run(["setup.py", "build_ext", "-i"]) - self.check_produced_files({'setup.py': None, - 'build': '?', - 'see_me': None, - 'src1': {'pack3': {'__init__.py': None, - '_build.py': None, - 'mymod.SO': None}}}) |