summaryrefslogtreecommitdiff
path: root/testing
diff options
context:
space:
mode:
Diffstat (limited to 'testing')
-rw-r--r--testing/cffi0/backend_tests.py119
-rw-r--r--testing/cffi0/test_ffi_backend.py60
-rw-r--r--testing/cffi0/test_function.py58
-rw-r--r--testing/cffi0/test_ownlib.py66
-rw-r--r--testing/cffi0/test_parsing.py152
-rw-r--r--testing/cffi0/test_verify.py130
-rw-r--r--testing/cffi0/test_version.py8
-rw-r--r--testing/cffi0/test_zdistutils.py2
-rw-r--r--testing/cffi0/test_zintegration.py11
-rw-r--r--testing/cffi1/test_cffi_binary.py2
-rw-r--r--testing/cffi1/test_dlopen.py4
-rw-r--r--testing/cffi1/test_ffi_obj.py10
-rw-r--r--testing/cffi1/test_function_args.py208
-rw-r--r--testing/cffi1/test_new_ffi_1.py118
-rw-r--r--testing/cffi1/test_re_python.py38
-rw-r--r--testing/cffi1/test_recompiler.py323
-rw-r--r--testing/cffi1/test_verify1.py98
-rw-r--r--testing/embedding/add1.py6
-rw-r--r--testing/embedding/add_recursive.py2
-rw-r--r--testing/embedding/test_basic.py13
-rw-r--r--testing/embedding/test_performance.py4
-rw-r--r--testing/embedding/test_thread.py26
-rw-r--r--testing/embedding/withunicode.py26
-rw-r--r--testing/support.py37
-rw-r--r--testing/udir.py131
25 files changed, 1334 insertions, 318 deletions
diff --git a/testing/cffi0/backend_tests.py b/testing/cffi0/backend_tests.py
index 13a4c78..ab013a1 100644
--- a/testing/cffi0/backend_tests.py
+++ b/testing/cffi0/backend_tests.py
@@ -1,6 +1,7 @@
import py
+import pytest
import platform
-import sys, ctypes
+import sys, ctypes, ctypes.util
from cffi import FFI, CDefError, FFIError, VerificationMissing
from testing.support import *
@@ -11,8 +12,8 @@ SIZE_OF_PTR = ctypes.sizeof(ctypes.c_void_p)
SIZE_OF_WCHAR = ctypes.sizeof(ctypes.c_wchar)
def needs_dlopen_none():
- if sys.platform == 'win32' and sys.version_info >= (3,):
- py.test.skip("dlopen(None) cannot work on Windows for Python 3")
+ if sys.platform == 'win32' and not ctypes.util.find_library('c'):
+ py.test.skip("dlopen(None) cannot work on Windows with this runtime")
class BackendTests:
@@ -112,10 +113,14 @@ class BackendTests:
p[9] = 43
assert p[0] == 42
assert p[9] == 43
- py.test.raises(IndexError, "p[10]")
- py.test.raises(IndexError, "p[10] = 44")
- py.test.raises(IndexError, "p[-1]")
- py.test.raises(IndexError, "p[-1] = 44")
+ 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):
ffi = FFI(backend=self.Backend())
@@ -140,18 +145,21 @@ class BackendTests:
ffi = FFI(backend=self.Backend())
p = ffi.new("int[]", 10) # a single integer is the length
assert p[9] == 0
- py.test.raises(IndexError, "p[10]")
+ 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
- py.test.raises(IndexError, "p[2]")
+ with pytest.raises(IndexError):
+ p[2]
assert repr(p) == "<cdata 'int[]' owning %d bytes>" % (2*SIZE_OF_INT)
#
p = ffi.new("int[]", 0)
- py.test.raises(IndexError, "p[0]")
+ with pytest.raises(IndexError):
+ p[0]
py.test.raises(ValueError, ffi.new, "int[]", -1)
assert repr(p) == "<cdata 'int[]' owning 0 bytes>"
@@ -259,7 +267,8 @@ class BackendTests:
p[2][3] = 33
assert p[0][0] == 10
assert p[2][3] == 33
- py.test.raises(IndexError, "p[1][-1]")
+ with pytest.raises(IndexError):
+ p[1][-1]
def test_constructor_array_of_array(self):
ffi = FFI(backend=self.Backend())
@@ -386,7 +395,8 @@ class BackendTests:
n = ffi.new("int*", 99)
p = ffi.new("int*[]", [n])
assert p[0][0] == 99
- py.test.raises(TypeError, "p[0] = None")
+ with pytest.raises(TypeError):
+ p[0] = None
p[0] = ffi.NULL
assert p[0] == ffi.NULL
@@ -422,13 +432,15 @@ class BackendTests:
assert s.a == s.b == s.c == 0
s.b = -23
assert s.b == -23
- py.test.raises(OverflowError, "s.b = 32768")
+ with pytest.raises(OverflowError):
+ s.b = 32768
#
s = ffi.new("struct foo*", [-2, -3])
assert s.a == -2
assert s.b == -3
assert s.c == 0
- py.test.raises((AttributeError, TypeError), "del s.a")
+ with pytest.raises((AttributeError, TypeError)):
+ del s.a
assert repr(s) == "<cdata 'struct foo *' owning %d bytes>" % (
SIZE_OF_INT + 2 * SIZE_OF_SHORT)
#
@@ -450,8 +462,10 @@ class BackendTests:
assert s[0].a == s[0].b == s[0].c == 0
s[0].b = -23
assert s[0].b == s.b == -23
- py.test.raises(OverflowError, "s[0].b = -32769")
- py.test.raises(IndexError, "s[1]")
+ with pytest.raises(OverflowError):
+ s[0].b = -32769
+ with pytest.raises(IndexError):
+ s[1]
def test_struct_opaque(self):
ffi = FFI(backend=self.Backend())
@@ -511,11 +525,13 @@ class BackendTests:
u.b = -23
assert u.b == -23
assert u.a != 0
- py.test.raises(OverflowError, "u.b = 32768")
+ with pytest.raises(OverflowError):
+ u.b = 32768
#
u = ffi.new("union foo*", [-2])
assert u.a == -2
- py.test.raises((AttributeError, TypeError), "del u.a")
+ with pytest.raises((AttributeError, TypeError)):
+ del u.a
assert repr(u) == "<cdata 'union foo *' owning %d bytes>" % SIZE_OF_INT
def test_union_opaque(self):
@@ -591,7 +607,8 @@ class BackendTests:
p[3] = b'\x00'
assert ffi.string(p) == b"hel"
assert ffi.string(p, 2) == b"he"
- py.test.raises(IndexError, "p[7] = b'X'")
+ with pytest.raises(IndexError):
+ p[7] = b'X'
#
a = ffi.new("char[]", b"hello\x00world")
assert len(a) == 12
@@ -615,7 +632,8 @@ class BackendTests:
p[3] = u+'\x00'
assert ffi.string(p) == u+"hel"
assert ffi.string(p, 123) == u+"hel"
- py.test.raises(IndexError, "p[7] = u+'X'")
+ with pytest.raises(IndexError):
+ p[7] = u+'X'
#
a = ffi.new("wchar_t[]", u+"hello\x00world")
assert len(a) == 12
@@ -633,7 +651,8 @@ class BackendTests:
s = ffi.new("struct foo*", [t])
assert type(s.name) not in (bytes, str, unicode)
assert ffi.string(s.name) == b"testing"
- py.test.raises(TypeError, "s.name = None")
+ with pytest.raises(TypeError):
+ s.name = None
s.name = ffi.NULL
assert s.name == ffi.NULL
@@ -657,18 +676,21 @@ class BackendTests:
a = ffi.new("int[]", [10, 11, 12])
p = ffi.new("void **", a)
vp = p[0]
- py.test.raises(TypeError, "vp[0]")
+ with pytest.raises(TypeError):
+ vp[0]
py.test.raises(TypeError, ffi.new, "short **", a)
#
ffi.cdef("struct foo { void *p; int *q; short *r; };")
s = ffi.new("struct foo *")
s.p = a # works
s.q = a # works
- py.test.raises(TypeError, "s.r = a") # fails
+ with pytest.raises(TypeError):
+ s.r = a # fails
b = ffi.cast("int *", a)
s.p = b # works
s.q = b # works
- py.test.raises(TypeError, "s.r = b") # fails
+ with pytest.raises(TypeError):
+ s.r = b # fails
def test_functionptr_simple(self):
ffi = FFI(backend=self.Backend())
@@ -687,7 +709,8 @@ class BackendTests:
q = ffi.new("int(**)(int)", p)
assert repr(q) == "<cdata 'int(* *)(int)' owning %d bytes>" % (
SIZE_OF_PTR)
- py.test.raises(TypeError, "q(43)")
+ with pytest.raises(TypeError):
+ q(43)
res = q[0](43)
assert res == 44
q = ffi.cast("int(*)(int)", p)
@@ -912,10 +935,14 @@ class BackendTests:
assert s.e == 4294967295
assert s[0].e == 4294967295
s.e = s.e
- py.test.raises(TypeError, "s.e = 'B'")
- py.test.raises(TypeError, "s.e = '2'")
- py.test.raises(TypeError, "s.e = '#2'")
- py.test.raises(TypeError, "s.e = '#7'")
+ with pytest.raises(TypeError):
+ s.e = 'B'
+ 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):
ffi = FFI(backend=self.Backend())
@@ -950,11 +977,14 @@ class BackendTests:
ffi = FFI(backend=self.Backend())
ffi.cdef("struct foo { int a, b; };")
s = ffi.new("struct foo[1]")
- py.test.raises(AttributeError, 's.b')
- py.test.raises(AttributeError, 's.b = 412')
+ with pytest.raises(AttributeError):
+ s.b
+ with pytest.raises(AttributeError):
+ s.b = 412
s[0].b = 412
assert s[0].b == 412
- py.test.raises(IndexError, 's[1]')
+ with pytest.raises(IndexError):
+ s[1]
def test_pointer_to_array(self):
ffi = FFI(backend=self.Backend())
@@ -1011,17 +1041,23 @@ class BackendTests:
assert ffi.sizeof("struct foo") == 8
s = ffi.new("struct foo *")
s.a = 511
- py.test.raises(OverflowError, "s.a = 512")
- py.test.raises(OverflowError, "s[0].a = 512")
+ with pytest.raises(OverflowError):
+ s.a = 512
+ with pytest.raises(OverflowError):
+ s[0].a = 512
assert s.a == 511
s.a = -512
- py.test.raises(OverflowError, "s.a = -513")
- py.test.raises(OverflowError, "s[0].a = -513")
+ 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
- py.test.raises(OverflowError, "s.c = 4")
- py.test.raises(OverflowError, "s[0].c = 4")
+ with pytest.raises(OverflowError):
+ s.c = 4
+ with pytest.raises(OverflowError):
+ s[0].c = 4
s.c = -4
assert s.c == -4
@@ -1205,7 +1241,7 @@ class BackendTests:
py.test.skip(str(e))
f.write(ffi.buffer(a, 1000 * ffi.sizeof("int")))
f.seek(0)
- assert f.read() == array.array('i', range(1000)).tostring()
+ 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")))
@@ -1224,7 +1260,7 @@ class BackendTests:
py.test.skip(str(e))
f.write(ffi.buffer(a, 1000 * ffi.sizeof("int")))
f.seek(0)
- assert f.read() == array.array('i', range(1000)).tostring()
+ 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")))
@@ -1279,7 +1315,8 @@ class BackendTests:
p = ffi.new("struct foo_s *", 10) # a single integer is the length
assert p.len == 0
assert p.data[9] == 0
- py.test.raises(IndexError, "p.data[10]")
+ with pytest.raises(IndexError):
+ p.data[10]
def test_ffi_typeof_getcname(self):
ffi = FFI(backend=self.Backend())
diff --git a/testing/cffi0/test_ffi_backend.py b/testing/cffi0/test_ffi_backend.py
index 12ecaee..8e29bc4 100644
--- a/testing/cffi0/test_ffi_backend.py
+++ b/testing/cffi0/test_ffi_backend.py
@@ -129,6 +129,36 @@ class TestFFI(backend_tests.BackendTests,
alloc5 = ffi.new_allocator(myalloc5)
py.test.raises(MemoryError, alloc5, "int[5]")
+ def test_new_struct_containing_struct_containing_array_varsize(self):
+ ffi = FFI(backend=self.Backend())
+ ffi.cdef("""
+ struct foo_s { int len[100]; short data[]; };
+ struct bar_s { int abc[100]; struct foo_s tail; };
+ """)
+ # loop to try to detect heap overwrites, if the size allocated
+ # is too small
+ for i in range(1, 501, 100):
+ p = ffi.new("struct bar_s *", [[10], [[20], [3,4,5,6,7,8,9] * i]])
+ assert p.abc[0] == 10
+ assert p.tail.len[0] == 20
+ assert p.tail.data[0] == 3
+ assert p.tail.data[6] == 9
+ assert p.tail.data[7 * i - 1] == 9
+
+ def test_bogus_struct_containing_struct_containing_array_varsize(self):
+ ffi = FFI(backend=self.Backend())
+ ffi.cdef("""
+ struct foo_s { signed char len; signed char data[]; };
+ struct bar_s { struct foo_s foo; int bcd; };
+ """)
+ p = ffi.new("struct bar_s *", [[123, [45, 56, 67, 78]], 9999999])
+ assert p.foo.len == 123
+ assert p.foo.data[0] == 45
+ assert p.foo.data[1] == 56
+ assert p.foo.data[2] == 67
+ assert p.bcd == 9999999
+ assert p.foo.data[3] != 78 # has been overwritten with 9999999
+
class TestBitfield:
def check(self, source, expected_ofs_y, expected_align, expected_size):
@@ -149,6 +179,7 @@ class TestBitfield:
setters = ['case %d: s.%s = value; break;' % iname
for iname in enumerate(fnames)]
lib = ffi1.verify("""
+ #include <string.h>
struct s1 { %s };
struct sa { char a; struct s1 b; };
#define Gofs_y offsetof(struct s1, y)
@@ -216,7 +247,10 @@ class TestBitfield:
self.check("int a:2; short b:15; char c:2; char y;", 5, 4, 8)
self.check("int a:2; char b:1; char c:1; char y;", 1, 4, 4)
- @pytest.mark.skipif("platform.machine().startswith(('arm', 'aarch64'))")
+ @pytest.mark.skipif(
+ "not (sys.platform == 'darwin' and platform.machine() == 'arm64')"
+ " and "
+ "platform.machine().startswith(('arm', 'aarch64'))")
def test_bitfield_anonymous_no_align(self):
L = FFI().alignof("long long")
self.check("char y; int :1;", 0, 1, 2)
@@ -230,6 +264,8 @@ class TestBitfield:
self.check("char x; long long :57; char y;", L + 8, 1, L + 9)
@pytest.mark.skipif(
+ "(sys.platform == 'darwin' and platform.machine() == 'arm64')"
+ " or "
"not platform.machine().startswith(('arm', 'aarch64'))")
def test_bitfield_anonymous_align_arm(self):
L = FFI().alignof("long long")
@@ -243,7 +279,10 @@ class TestBitfield:
self.check("char x; long long z:57; char y;", L + 8, L, L + 8 + L)
self.check("char x; long long :57; char y;", L + 8, L, L + 8 + L)
- @pytest.mark.skipif("platform.machine().startswith(('arm', 'aarch64'))")
+ @pytest.mark.skipif(
+ "not (sys.platform == 'darwin' and platform.machine() == 'arm64')"
+ " and "
+ "platform.machine().startswith(('arm', 'aarch64'))")
def test_bitfield_zero(self):
L = FFI().alignof("long long")
self.check("char y; int :0;", 0, 1, 4)
@@ -255,6 +294,8 @@ class TestBitfield:
self.check("int a:1; int :0; int b:1; char y;", 5, 4, 8)
@pytest.mark.skipif(
+ "(sys.platform == 'darwin' and platform.machine() == 'arm64')"
+ " or "
"not platform.machine().startswith(('arm', 'aarch64'))")
def test_bitfield_zero_arm(self):
L = FFI().alignof("long long")
@@ -268,12 +309,15 @@ class TestBitfield:
def test_error_cases(self):
ffi = FFI()
- py.test.raises(TypeError,
- 'ffi.cdef("struct s1 { float x:1; };"); ffi.new("struct s1 *")')
- py.test.raises(TypeError,
- 'ffi.cdef("struct s2 { char x:0; };"); ffi.new("struct s2 *")')
- py.test.raises(TypeError,
- 'ffi.cdef("struct s3 { char x:9; };"); ffi.new("struct s3 *")')
+ ffi.cdef("struct s1 { float x:1; };")
+ with pytest.raises(TypeError):
+ ffi.new("struct s1 *")
+ ffi.cdef("struct s2 { char x:0; };")
+ with pytest.raises(TypeError):
+ ffi.new("struct s2 *")
+ ffi.cdef("struct s3 { char x:9; };")
+ with pytest.raises(TypeError):
+ ffi.new("struct s3 *")
def test_struct_with_typedef(self):
ffi = FFI()
diff --git a/testing/cffi0/test_function.py b/testing/cffi0/test_function.py
index ca2353f..b4bb23d 100644
--- a/testing/cffi0/test_function.py
+++ b/testing/cffi0/test_function.py
@@ -1,10 +1,11 @@
import py
+import pytest
from cffi import FFI, CDefError
import math, os, sys
import ctypes.util
from cffi.backend_ctypes import CTypesBackend
from testing.udir import udir
-from testing.support import FdWriteCapture
+from testing.support import FdWriteCapture, StdErrCapture
from .backend_tests import needs_dlopen_none
try:
@@ -90,7 +91,8 @@ class TestFunction(object):
""")
m = ffi.dlopen(lib_m)
assert m.FOOBAR == 42
- py.test.raises(NotImplementedError, "m.baz")
+ with pytest.raises(NotImplementedError):
+ m.baz
def test_tlsalloc(self):
if sys.platform != 'win32':
@@ -111,7 +113,7 @@ class TestFunction(object):
ffi = FFI(backend=self.Backend())
ffi.cdef("""
int fputs(const char *, void *);
- void *stderr;
+ extern void *stderr;
""")
needs_dlopen_none()
ffi.C = ffi.dlopen(None)
@@ -128,7 +130,7 @@ class TestFunction(object):
ffi = FFI(backend=self.Backend())
ffi.cdef("""
int fputs(char *, void *);
- void *stderr;
+ extern void *stderr;
""")
needs_dlopen_none()
ffi.C = ffi.dlopen(None)
@@ -145,7 +147,7 @@ class TestFunction(object):
ffi = FFI(backend=self.Backend())
ffi.cdef("""
int fprintf(void *, const char *format, ...);
- void *stderr;
+ extern void *stderr;
""")
needs_dlopen_none()
ffi.C = ffi.dlopen(None)
@@ -207,7 +209,7 @@ class TestFunction(object):
py.test.skip("probably no symbol 'stderr' in the lib")
ffi.cdef("""
int fputs(const char *, void *);
- void *stderr;
+ extern void *stderr;
""")
needs_dlopen_none()
ffi.C = ffi.dlopen(None)
@@ -225,19 +227,32 @@ class TestFunction(object):
def cb():
return returnvalue
fptr = ffi.callback("void(*)(void)", cb)
- old_stderr = sys.stderr
- try:
- sys.stderr = StringIO()
+ with StdErrCapture() as f:
returned = fptr()
- printed = sys.stderr.getvalue()
- finally:
- sys.stderr = old_stderr
+ printed = f.getvalue()
assert returned is None
if returnvalue is None:
assert printed == ''
else:
assert "None" in printed
+ def test_callback_returning_struct_three_bytes(self):
+ if self.Backend is CTypesBackend:
+ py.test.skip("not supported with the ctypes backend")
+ ffi = FFI(backend=self.Backend())
+ ffi.cdef("""
+ typedef struct {
+ unsigned char a, b, c;
+ } THREEBYTES;
+ """)
+ def cb():
+ return (12, 34, 56)
+ fptr = ffi.callback("THREEBYTES(*)(void)", cb)
+ tb = fptr()
+ assert tb.a == 12
+ assert tb.b == 34
+ assert tb.c == 56
+
def test_passing_array(self):
ffi = FFI(backend=self.Backend())
ffi.cdef("""
@@ -254,7 +269,7 @@ class TestFunction(object):
py.test.skip("probably no symbol 'stdout' in the lib")
ffi = FFI(backend=self.Backend())
ffi.cdef("""
- void *stdout;
+ extern void *stdout;
""")
needs_dlopen_none()
C = ffi.dlopen(None)
@@ -494,7 +509,7 @@ class TestFunction(object):
ffi.cdef("""
typedef enum { MYE1, MYE2 } myenum_t;
double myfunc(double);
- double myvar;
+ extern double myvar;
const double myconst;
#define MYFOO 42
""")
@@ -505,7 +520,7 @@ class TestFunction(object):
if self.Backend is CTypesBackend:
py.test.skip("not with the ctypes backend")
ffi = FFI(backend=self.Backend())
- ffi.cdef("int foobar(void); int foobaz;")
+ ffi.cdef("int foobar(void); extern int foobaz;")
lib = ffi.dlopen(lib_m)
ffi.dlclose(lib)
e = py.test.raises(ValueError, getattr, lib, 'foobar')
@@ -518,3 +533,16 @@ class TestFunction(object):
assert str(e.value).startswith("library '")
assert str(e.value).endswith("' has already been closed")
ffi.dlclose(lib) # does not raise
+
+ def test_passing_large_list(self):
+ if self.Backend is CTypesBackend:
+ py.test.skip("the ctypes backend doesn't support this")
+ ffi = FFI(backend=self.Backend())
+ ffi.cdef("""
+ void getenv(char *);
+ """)
+ needs_dlopen_none()
+ m = ffi.dlopen(None)
+ arg = [b"F", b"O", b"O"] + [b"\x00"] * 20000000
+ x = m.getenv(arg)
+ assert x is None
diff --git a/testing/cffi0/test_ownlib.py b/testing/cffi0/test_ownlib.py
index a06df20..ffad879 100644
--- a/testing/cffi0/test_ownlib.py
+++ b/testing/cffi0/test_ownlib.py
@@ -35,6 +35,10 @@ typedef struct {
long bottom;
} RECT;
+typedef struct {
+ unsigned char a, b, c;
+} THREEBYTES;
+
EXPORT int PointInRect(RECT *prc, POINT pt)
{
@@ -107,6 +111,15 @@ EXPORT void modify_struct_value(RECT r)
{
r.left = r.right = r.top = r.bottom = 500;
}
+
+EXPORT THREEBYTES return_three_bytes(void)
+{
+ THREEBYTES result;
+ result.a = 12;
+ result.b = 34;
+ result.c = 56;
+ return result;
+}
"""
class TestOwnLib(object):
@@ -201,7 +214,7 @@ class TestOwnLib(object):
py.test.skip("fix the auto-generation of the tiny test lib")
ffi = FFI(backend=self.Backend())
ffi.cdef("""
- int my_array[7];
+ extern int my_array[7];
""")
ownlib = ffi.dlopen(self.module)
for i in range(7):
@@ -223,7 +236,7 @@ class TestOwnLib(object):
py.test.skip("not supported by the ctypes backend")
ffi = FFI(backend=self.Backend())
ffi.cdef("""
- int my_array[];
+ extern int my_array[];
""")
ownlib = ffi.dlopen(self.module)
for i in range(7):
@@ -291,7 +304,7 @@ class TestOwnLib(object):
long bottom;
} RECT;
- long left, top, right, bottom;
+ extern long left, top, right, bottom;
RECT ReturnRect(int i, RECT ar, RECT* br, POINT cp, RECT dr,
RECT *er, POINT fp, RECT gr);
@@ -321,7 +334,7 @@ class TestOwnLib(object):
if self.Backend is CTypesBackend:
py.test.skip("not implemented with the ctypes backend")
ffi = FFI(backend=self.Backend())
- ffi.cdef("long left; int test_getting_errno(void);")
+ ffi.cdef("extern long left; int test_getting_errno(void);")
lib = ffi.dlopen(self.module)
lib.left = 123456
p = ffi.addressof(lib, "left")
@@ -371,3 +384,48 @@ class TestOwnLib(object):
assert s.top == 22
assert s.right == 33
assert s.bottom == 44
+
+ def test_dlopen_handle(self):
+ if self.module is None:
+ py.test.skip("fix the auto-generation of the tiny test lib")
+ if sys.platform == 'win32':
+ py.test.skip("uses 'dl' explicitly")
+ if self.__class__.Backend is CTypesBackend:
+ py.test.skip("not for the ctypes backend")
+ backend = self.Backend()
+ ffi1 = FFI(backend=backend)
+ ffi1.cdef("""void *dlopen(const char *filename, int flags);
+ int dlclose(void *handle);""")
+ lib1 = ffi1.dlopen('dl')
+ handle = lib1.dlopen(self.module.encode(sys.getfilesystemencoding()),
+ backend.RTLD_LAZY)
+ assert ffi1.typeof(handle) == ffi1.typeof("void *")
+ assert handle
+
+ ffi = FFI(backend=backend)
+ ffi.cdef("""unsigned short foo_2bytes(unsigned short a);""")
+ lib = ffi.dlopen(handle)
+ x = lib.foo_2bytes(1000)
+ assert x == 1042
+
+ err = lib1.dlclose(handle)
+ assert err == 0
+
+ def test_return_three_bytes(self):
+ if self.module is None:
+ py.test.skip("fix the auto-generation of the tiny test lib")
+ if self.__class__.Backend is CTypesBackend:
+ py.test.skip("not working on win32 on the ctypes backend")
+ ffi = FFI(backend=self.Backend())
+ ffi.cdef("""
+ typedef struct {
+ unsigned char a, b, c;
+ } THREEBYTES;
+
+ THREEBYTES return_three_bytes(void);
+ """)
+ lib = ffi.dlopen(self.module)
+ tb = lib.return_three_bytes()
+ assert tb.a == 12
+ assert tb.b == 34
+ assert tb.c == 56
diff --git a/testing/cffi0/test_parsing.py b/testing/cffi0/test_parsing.py
index 2d75850..a5e4587 100644
--- a/testing/cffi0/test_parsing.py
+++ b/testing/cffi0/test_parsing.py
@@ -174,7 +174,7 @@ def test_remove_line_continuation_comments():
double // blah \\
more comments
x(void);
- double // blah\\\\
+ double // blah // blah\\\\
y(void);
double // blah\\ \
etc
@@ -185,6 +185,93 @@ def test_remove_line_continuation_comments():
m.y
m.z
+def test_dont_remove_comment_in_line_directives():
+ ffi = FFI(backend=FakeBackend())
+ e = py.test.raises(CDefError, ffi.cdef, """
+ \t # \t line \t 8 \t "baz.c" \t
+
+ some syntax error here
+ """)
+ assert str(e.value) == "parse error\nbaz.c:9:14: before: syntax"
+ #
+ e = py.test.raises(CDefError, ffi.cdef, """
+ #line 7 "foo//bar.c"
+
+ some syntax error here
+ """)
+ #
+ assert str(e.value) == "parse error\nfoo//bar.c:8:14: before: syntax"
+ ffi = FFI(backend=FakeBackend())
+ e = py.test.raises(CDefError, ffi.cdef, """
+ \t # \t 8 \t "baz.c" \t
+
+ some syntax error here
+ """)
+ assert str(e.value) == "parse error\nbaz.c:9:14: before: syntax"
+ #
+ e = py.test.raises(CDefError, ffi.cdef, """
+ # 7 "foo//bar.c"
+
+ some syntax error here
+ """)
+ assert str(e.value) == "parse error\nfoo//bar.c:8:14: before: syntax"
+
+def test_multiple_line_directives():
+ ffi = FFI(backend=FakeBackend())
+ e = py.test.raises(CDefError, ffi.cdef,
+ """ #line 5 "foo.c"
+ extern int xx;
+ #line 6 "bar.c"
+ extern int yy;
+ #line 7 "baz.c"
+ some syntax error here
+ #line 8 "yadda.c"
+ extern int zz;
+ """)
+ assert str(e.value) == "parse error\nbaz.c:7:14: before: syntax"
+ #
+ e = py.test.raises(CDefError, ffi.cdef,
+ """ # 5 "foo.c"
+ extern int xx;
+ # 6 "bar.c"
+ extern int yy;
+ # 7 "baz.c"
+ some syntax error here
+ # 8 "yadda.c"
+ extern int zz;
+ """)
+ assert str(e.value) == "parse error\nbaz.c:7:14: before: syntax"
+
+def test_commented_line_directive():
+ ffi = FFI(backend=FakeBackend())
+ e = py.test.raises(CDefError, ffi.cdef, """
+ /*
+ #line 5 "foo.c"
+ */
+ void xx(void);
+
+ #line 6 "bar.c"
+ /*
+ #line 35 "foo.c"
+ */
+ some syntax error
+ """)
+ #
+ assert str(e.value) == "parse error\nbar.c:9:14: before: syntax"
+ e = py.test.raises(CDefError, ffi.cdef, """
+ /*
+ # 5 "foo.c"
+ */
+ void xx(void);
+
+ # 6 "bar.c"
+ /*
+ # 35 "foo.c"
+ */
+ some syntax error
+ """)
+ assert str(e.value) == "parse error\nbar.c:9:14: before: syntax"
+
def test_line_continuation_in_defines():
ffi = FFI(backend=FakeBackend())
ffi.cdef("""
@@ -324,6 +411,7 @@ def test_WPARAM_on_windows():
assert value == sys.maxsize * 2 - 40
def test__is_constant_globalvar():
+ import warnings
for input, expected_output in [
("int a;", False),
("const int a;", True),
@@ -341,10 +429,13 @@ def test__is_constant_globalvar():
("const int a[5][6];", False),
]:
ffi = FFI()
- ffi.cdef(input)
+ with warnings.catch_warnings(record=True) as log:
+ warnings.simplefilter("always")
+ ffi.cdef(input)
declarations = ffi._parser._declarations
assert ('constant a' in declarations) == expected_output
assert ('variable a' in declarations) == (not expected_output)
+ assert len(log) == (1 - expected_output)
def test_restrict():
from cffi import model
@@ -354,7 +445,7 @@ def test_restrict():
("int *a;", False),
]:
ffi = FFI()
- ffi.cdef(input)
+ ffi.cdef("extern " + input)
tp, quals = ffi._parser._declarations['variable a']
assert bool(quals & model.Q_RESTRICT) == expected_output
@@ -409,7 +500,17 @@ def test_const_pointer_to_pointer():
def test_enum():
ffi = FFI()
ffi.cdef("""
- enum Enum { POS = +1, TWO = 2, NIL = 0, NEG = -1, OP = (POS+TWO)-1};
+ enum Enum {
+ POS = +1,
+ TWO = 2,
+ NIL = 0,
+ NEG = -1,
+ ADDSUB = (POS+TWO)-1,
+ DIVMULINT = (3 * 3) / 2,
+ SHIFT = (1 << 3) >> 1,
+ BINOPS = (0x7 & 0x1) | 0x8,
+ XOR = 0xf ^ 0xa
+ };
""")
needs_dlopen_none()
C = ffi.dlopen(None)
@@ -417,7 +518,11 @@ def test_enum():
assert C.TWO == 2
assert C.NIL == 0
assert C.NEG == -1
- assert C.OP == 2
+ assert C.ADDSUB == 2
+ assert C.DIVMULINT == 4
+ assert C.SHIFT == 4
+ assert C.BINOPS == 0b1001
+ assert C.XOR == 0b0101
def test_stdcall():
ffi = FFI()
@@ -466,3 +571,40 @@ def test_error_invalid_syntax_for_cdef():
e = py.test.raises(CDefError, ffi.cdef, 'void foo(void) {}')
assert str(e.value) == ('<cdef source string>:1: unexpected <FuncDef>: '
'this construct is valid C but not valid in cdef()')
+
+def test_unsigned_int_suffix_for_constant():
+ ffi = FFI()
+ ffi.cdef("""enum e {
+ bin_0=0b10,
+ bin_1=0b10u,
+ bin_2=0b10U,
+ bin_3=0b10l,
+ bin_4=0b10L,
+ bin_5=0b10ll,
+ bin_6=0b10LL,
+ oct_0=010,
+ oct_1=010u,
+ oct_2=010U,
+ oct_3=010l,
+ oct_4=010L,
+ oct_5=010ll,
+ oct_6=010LL,
+ dec_0=10,
+ dec_1=10u,
+ dec_2=10U,
+ dec_3=10l,
+ dec_4=10L,
+ dec_5=10ll,
+ dec_6=10LL,
+ hex_0=0x10,
+ hex_1=0x10u,
+ hex_2=0x10U,
+ hex_3=0x10l,
+ hex_4=0x10L,
+ hex_5=0x10ll,
+ hex_6=0x10LL,};""")
+ needs_dlopen_none()
+ C = ffi.dlopen(None)
+ for base, expected_result in (('bin', 2), ('oct', 8), ('dec', 10), ('hex', 16)):
+ for index in range(7):
+ assert getattr(C, '{base}_{index}'.format(base=base, index=index)) == expected_result
diff --git a/testing/cffi0/test_verify.py b/testing/cffi0/test_verify.py
index 79e1c6c..3a1c0b9 100644
--- a/testing/cffi0/test_verify.py
+++ b/testing/cffi0/test_verify.py
@@ -1,7 +1,9 @@
import py, re
+import pytest
import sys, os, math, weakref
from cffi import FFI, VerificationError, VerificationMissing, model, FFIError
from testing.support import *
+from testing.support import extra_compile_args
lib_m = ['m']
@@ -12,16 +14,6 @@ if sys.platform == 'win32':
lib_m = ['msvcrt']
pass # no obvious -Werror equivalent on MSVC
else:
- if (sys.platform == 'darwin' and
- [int(x) for x in os.uname()[2].split('.')] >= [11, 0, 0]):
- # assume a standard clang or gcc
- extra_compile_args = ['-Werror', '-Wall', '-Wextra', '-Wconversion']
- # special things for clang
- extra_compile_args.append('-Qunused-arguments')
- else:
- # assume a standard gcc
- extra_compile_args = ['-Werror', '-Wall', '-Wextra', '-Wconversion']
-
class FFI(FFI):
def verify(self, *args, **kwds):
return super(FFI, self).verify(
@@ -284,7 +276,7 @@ def test_all_integer_and_float_types():
def test_var_signed_integer_types():
ffi = FFI()
lst = all_signed_integer_types(ffi)
- csource = "\n".join(["%s somevar_%s;" % (tp, tp.replace(' ', '_'))
+ csource = "\n".join(["static %s somevar_%s;" % (tp, tp.replace(' ', '_'))
for tp in lst])
ffi.cdef(csource)
lib = ffi.verify(csource)
@@ -303,7 +295,7 @@ def test_var_signed_integer_types():
def test_var_unsigned_integer_types():
ffi = FFI()
lst = all_unsigned_integer_types(ffi)
- csource = "\n".join(["%s somevar_%s;" % (tp, tp.replace(' ', '_'))
+ csource = "\n".join(["static %s somevar_%s;" % (tp, tp.replace(' ', '_'))
for tp in lst])
ffi.cdef(csource)
lib = ffi.verify(csource)
@@ -589,7 +581,8 @@ def test_struct_array_guess_length():
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')
- py.test.raises(IndexError, 's.a[17]')
+ with pytest.raises(IndexError):
+ s.a[17]
def test_struct_array_c99_1():
if sys.platform == 'win32':
@@ -647,7 +640,8 @@ def test_struct_with_bitfield_exact():
ffi.verify("struct foo_s { int a:2, b:3; };")
s = ffi.new("struct foo_s *")
s.b = 3
- py.test.raises(OverflowError, "s.b = 4")
+ with pytest.raises(OverflowError):
+ s.b = 4
assert s.b == 3
def test_struct_with_bitfield_enum():
@@ -813,8 +807,8 @@ def test_define_int():
def test_access_variable():
ffi = FFI()
- ffi.cdef("int foo(void);\n"
- "int somenumber;")
+ ffi.cdef("static int foo(void);\n"
+ "static int somenumber;")
lib = ffi.verify("""
static int somenumber = 2;
static int foo(void) {
@@ -831,7 +825,7 @@ def test_access_variable():
def test_access_address_of_variable():
# access the address of 'somenumber': need a trick
ffi = FFI()
- ffi.cdef("int somenumber; static int *const somenumberptr;")
+ ffi.cdef("static int somenumber; static int *const somenumberptr;")
lib = ffi.verify("""
static int somenumber = 2;
#define somenumberptr (&somenumber)
@@ -844,7 +838,7 @@ def test_access_address_of_variable():
def test_access_array_variable(length=5):
ffi = FFI()
ffi.cdef("int foo(int);\n"
- "int somenumber[%s];" % (length,))
+ "static int somenumber[%s];" % (length,))
lib = ffi.verify("""
static int somenumber[] = {2, 2, 3, 4, 5};
static int foo(int i) {
@@ -876,7 +870,7 @@ def test_access_struct_variable():
ffi = FFI()
ffi.cdef("struct foo { int x; ...; };\n"
"int foo(int);\n"
- "struct foo stuff;")
+ "static struct foo stuff;")
lib = ffi.verify("""
struct foo { int x, y, z; };
static struct foo stuff = {2, 5, 8};
@@ -900,9 +894,9 @@ def test_access_struct_variable():
def test_access_callback():
ffi = FFI()
- ffi.cdef("int (*cb)(int);\n"
- "int foo(int);\n"
- "void reset_cb(void);")
+ 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);
@@ -918,9 +912,9 @@ def test_access_callback():
def test_access_callback_function_typedef():
ffi = FFI()
ffi.cdef("typedef int mycallback_t(int);\n"
- "mycallback_t *cb;\n"
- "int foo(int);\n"
- "void reset_cb(void);")
+ "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);
@@ -1070,7 +1064,7 @@ def test_autofilled_struct_as_argument():
def test_autofilled_struct_as_argument_dynamic():
ffi = FFI()
ffi.cdef("struct foo_s { long a; ...; };\n"
- "int (*foo)(struct foo_s);")
+ "static int (*foo)(struct foo_s);")
lib = ffi.verify("""
struct foo_s {
double b;
@@ -1079,7 +1073,7 @@ def test_autofilled_struct_as_argument_dynamic():
int foo1(struct foo_s s) {
return (int)s.a - (int)s.b;
}
- int (*foo)(struct foo_s s) = &foo1;
+ 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 "
@@ -1449,7 +1443,7 @@ def test_bool():
py.test.skip("_Bool not in MSVC")
ffi = FFI()
ffi.cdef("struct foo_s { _Bool x; };"
- "_Bool foo(_Bool); _Bool (*foop)(_Bool);")
+ "_Bool foo(_Bool); static _Bool (*foop)(_Bool);")
lib = ffi.verify("""
struct foo_s { _Bool x; };
int foo(int arg) {
@@ -1458,13 +1452,15 @@ def test_bool():
_Bool _foofunc(_Bool x) {
return !x;
}
- _Bool (*foop)(_Bool) = _foofunc;
+ static _Bool (*foop)(_Bool) = _foofunc;
""")
p = ffi.new("struct foo_s *")
p.x = 1
assert p.x is True
- py.test.raises(OverflowError, "p.x = -1")
- py.test.raises(TypeError, "p.x = 0.0")
+ 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
@@ -1532,7 +1528,8 @@ def test_cannot_pass_float():
}
""" % (type, type))
p = ffi.new("struct foo_s *")
- py.test.raises(TypeError, "p.x = 0.0")
+ 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)
@@ -1646,7 +1643,7 @@ def test_FILE_stored_in_stdout():
def test_FILE_stored_explicitly():
ffi = FFI()
- ffi.cdef("int myprintf11(const char *, int); FILE *myfile;")
+ ffi.cdef("int myprintf11(const char *, int); extern FILE *myfile;")
lib = ffi.verify("""
#include <stdio.h>
FILE *myfile;
@@ -1672,19 +1669,19 @@ def test_FILE_stored_explicitly():
def test_global_array_with_missing_length():
ffi = FFI()
- ffi.cdef("int fooarray[];")
+ 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("int fooarray[...];")
+ 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():
ffi = FFI()
- ffi.cdef("int fooarray[...];")
+ ffi.cdef("extern int fooarray[...];")
py.test.raises(VerificationError, ffi.verify, "char fooarray[23];")
def test_struct_containing_struct():
@@ -1805,7 +1802,7 @@ def test_string_to_voidp_arg():
def test_callback_indirection():
ffi = FFI()
ffi.cdef("""
- int (*python_callback)(int how_many, int *values);
+ 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,...));
""")
@@ -1939,24 +1936,24 @@ def test_typeof_func_with_struct_argument():
def test_bug_const_char_ptr_array_1():
ffi = FFI()
- ffi.cdef("""const char *a[...];""")
+ 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():
from cffi import FFI # ignore warnings
ffi = FFI()
- ffi.cdef("""const int a[];""")
+ 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 = """
- int xvalue;
- long long ivalue, rvalue;
- float fvalue;
- double dvalue;
- long double Dvalue;
+ 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);
@@ -2098,6 +2095,11 @@ def _run_in_multiple_threads(test1):
raise errors[0][1]
def test_errno_working_even_with_pypys_jit():
+ # NOTE: on some platforms, to work correctly, this test needs to be
+ # compiled with -pthread. Otherwise, the accesses to errno done from f()
+ # are compiled by assuming this small library won't be used from multiple
+ # threads, which is wrong. If you see failures _and_ if you pass your
+ # own CFLAGS environment variable, please make sure "-pthread" is in it.
ffi = FFI()
ffi.cdef("int f(int);")
lib = ffi.verify("""
@@ -2135,7 +2137,7 @@ def test_verify_dlopen_flags():
# exported symbols as well. So we must not export a simple name
# like 'foo'!
ffi1 = FFI()
- ffi1.cdef("int foo_verify_dlopen_flags;")
+ ffi1.cdef("extern int foo_verify_dlopen_flags;")
lib1 = ffi1.verify("int foo_verify_dlopen_flags;",
flags=ffi1.RTLD_GLOBAL | ffi1.RTLD_LAZY)
@@ -2149,7 +2151,7 @@ def test_verify_dlopen_flags():
def get_second_lib():
# Hack, using modulename makes the test fail
ffi2 = FFI()
- ffi2.cdef("int foo_verify_dlopen_flags;")
+ ffi2.cdef("extern int foo_verify_dlopen_flags;")
lib2 = ffi2.verify("int foo_verify_dlopen_flags;",
flags=ffi2.RTLD_GLOBAL | ffi2.RTLD_LAZY)
return lib2
@@ -2522,3 +2524,39 @@ def test_ffi_new_with_cycles():
x.p = p
x.cyclic = x
del p, x
+
+def test_arithmetic_in_cdef():
+ for a in [0, 11, 15]:
+ ffi = FFI()
+ ffi.cdef("""
+ enum FOO {
+ DIVNN = ((-?) / (-3)),
+ DIVNP = ((-?) / (+3)),
+ DIVPN = ((+?) / (-3)),
+ MODNN = ((-?) % (-3)),
+ MODNP = ((-?) % (+3)),
+ MODPN = ((+?) % (-3)),
+ };
+ """.replace('?', str(a)))
+ lib = ffi.verify("""
+ enum FOO {
+ DIVNN = ((-?) / (-3)),
+ DIVNP = ((-?) / (+3)),
+ DIVPN = ((+?) / (-3)),
+ MODNN = ((-?) % (-3)),
+ MODNP = ((-?) % (+3)),
+ MODPN = ((+?) % (-3)),
+ };
+ """.replace('?', str(a)))
+ # the verify() crashes if the values in the enum are different from
+ # the values we computed ourselves from the cdef()
+
+def test_passing_large_list():
+ ffi = FFI()
+ ffi.cdef("""void passing_large_list(long[]);""")
+ lib = ffi.verify("""
+ static void passing_large_list(long a[]) { }
+ """)
+ arg = list(range(20000000))
+ lib.passing_large_list(arg)
+ # assert did not segfault
diff --git a/testing/cffi0/test_version.py b/testing/cffi0/test_version.py
index 9325685..facb84c 100644
--- a/testing/cffi0/test_version.py
+++ b/testing/cffi0/test_version.py
@@ -18,6 +18,7 @@ def test_version():
version_info = '.'.join(str(i) for i in cffi.__version_info__)
version_info = version_info.replace('.beta.', 'b')
version_info = version_info.replace('.plus', '+')
+ version_info = version_info.replace('.rc', 'rc')
assert v == version_info
#v = BACKEND_VERSIONS.get(v, v)
assert v == _cffi_backend.__version__
@@ -36,7 +37,12 @@ def test_doc_version_file():
v = cffi.__version__.replace('+', '')
p = os.path.join(parent, 'doc', 'source', 'installation.rst')
content = open(p).read()
- assert (" package version %s:" % v) in content
+ if " package version %s:" % v not in content:
+ for i in range(5):
+ if " package version %s-%d:" % (v, i) in content:
+ break
+ else:
+ assert 0, "doc/source/installation.rst needs updating"
def test_setup_version():
parent = os.path.dirname(os.path.dirname(cffi.__file__))
diff --git a/testing/cffi0/test_zdistutils.py b/testing/cffi0/test_zdistutils.py
index b67b105..35b3d0c 100644
--- a/testing/cffi0/test_zdistutils.py
+++ b/testing/cffi0/test_zdistutils.py
@@ -89,7 +89,7 @@ class DistUtilsTest(object):
csrc = '/*hi there %s!2*/\n#include <math.h>\n' % self
v = Verifier(ffi, csrc, force_generic_engine=self.generic,
libraries=[self.lib_m])
- basename = self.__class__.__name__ + 'test_compile_module'
+ basename = self.__class__.__name__[:10] + '_test_compile_module'
v.modulefilename = filename = str(udir.join(basename + '.so'))
v.compile_module()
assert filename == v.modulefilename
diff --git a/testing/cffi0/test_zintegration.py b/testing/cffi0/test_zintegration.py
index d56dac2..ce925b8 100644
--- a/testing/cffi0/test_zintegration.py
+++ b/testing/cffi0/test_zintegration.py
@@ -1,11 +1,13 @@
import py, os, sys, shutil
import subprocess
from testing.udir import udir
+import pytest
if sys.platform == 'win32':
- py.test.skip('snippets do not run on win32')
+ pytestmark = pytest.mark.skip('snippets do not run on win32')
if sys.version_info < (2, 7):
- py.test.skip('fails e.g. on a Debian/Ubuntu which patches virtualenv'
+ pytestmark = pytest.mark.skip(
+ 'fails e.g. on a Debian/Ubuntu which patches virtualenv'
' in a non-2.6-friendly way')
def create_venv(name):
@@ -75,7 +77,10 @@ def really_run_setup_and_program(dirname, venv_dir_and_paths, python_snippet):
env = os.environ.copy()
env['PYTHONPATH'] = paths
subprocess.check_call((vp, 'setup.py', 'clean'), env=env)
- subprocess.check_call((vp, 'setup.py', 'install'), env=env)
+ # there's a setuptools/easy_install bug that causes this to fail when the build/install occur together and
+ # we're in the same directory with the build (it tries to look up dependencies for itself on PyPI);
+ # subsequent runs will succeed because this test doesn't properly clean up the build- use pip for now.
+ subprocess.check_call((vp, '-m', 'pip', 'install', '.'), env=env)
subprocess.check_call((vp, str(python_f)), env=env)
finally:
os.chdir(olddir)
diff --git a/testing/cffi1/test_cffi_binary.py b/testing/cffi1/test_cffi_binary.py
index 25953db..7cfbace 100644
--- a/testing/cffi1/test_cffi_binary.py
+++ b/testing/cffi1/test_cffi_binary.py
@@ -10,6 +10,8 @@ def test_no_unknown_exported_symbols():
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]
diff --git a/testing/cffi1/test_dlopen.py b/testing/cffi1/test_dlopen.py
index 1c20550..26a2717 100644
--- a/testing/cffi1/test_dlopen.py
+++ b/testing/cffi1/test_dlopen.py
@@ -6,7 +6,7 @@ from testing.udir import udir
def test_simple():
ffi = FFI()
- ffi.cdef("int close(int); static const int BB = 42; int somevar;")
+ 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
@@ -196,7 +196,7 @@ def test_array_overflow():
def test_global_var():
ffi = FFI()
- ffi.cdef("int myglob;")
+ 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
diff --git a/testing/cffi1/test_ffi_obj.py b/testing/cffi1/test_ffi_obj.py
index e07d6f9..0d29290 100644
--- a/testing/cffi1/test_ffi_obj.py
+++ b/testing/cffi1/test_ffi_obj.py
@@ -1,4 +1,5 @@
import py, sys
+import pytest
import _cffi_backend as _cffi1_backend
@@ -85,9 +86,12 @@ def test_ffi_NULL():
def test_ffi_no_attr():
ffi = _cffi1_backend.FFI()
- py.test.raises(AttributeError, "ffi.no_such_name")
- py.test.raises(AttributeError, "ffi.no_such_name = 42")
- py.test.raises(AttributeError, "del ffi.no_such_name")
+ 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()
diff --git a/testing/cffi1/test_function_args.py b/testing/cffi1/test_function_args.py
new file mode 100644
index 0000000..30c6fed
--- /dev/null
+++ b/testing/cffi1/test_function_args.py
@@ -0,0 +1,208 @@
+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
index 209cb30..640830b 100644
--- a/testing/cffi1/test_new_ffi_1.py
+++ b/testing/cffi1/test_new_ffi_1.py
@@ -1,4 +1,5 @@
import py
+import pytest
import platform, imp
import sys, os, ctypes
import cffi
@@ -186,10 +187,14 @@ class TestNewFFI1:
p[9] = 43
assert p[0] == 42
assert p[9] == 43
- py.test.raises(IndexError, "p[10]")
- py.test.raises(IndexError, "p[10] = 44")
- py.test.raises(IndexError, "p[-1]")
- py.test.raises(IndexError, "p[-1] = 44")
+ 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, ..}"
@@ -212,18 +217,21 @@ class TestNewFFI1:
def test_new_array_varsize(self):
p = ffi.new("int[]", 10) # a single integer is the length
assert p[9] == 0
- py.test.raises(IndexError, "p[10]")
+ 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
- py.test.raises(IndexError, "p[2]")
+ with pytest.raises(IndexError):
+ p[2]
assert repr(p) == "<cdata 'int[]' owning %d bytes>" % (2*SIZE_OF_INT)
#
p = ffi.new("int[]", 0)
- py.test.raises(IndexError, "p[0]")
+ with pytest.raises(IndexError):
+ p[0]
py.test.raises(ValueError, ffi.new, "int[]", -1)
assert repr(p) == "<cdata 'int[]' owning 0 bytes>"
@@ -324,7 +332,8 @@ class TestNewFFI1:
p[2][3] = 33
assert p[0][0] == 10
assert p[2][3] == 33
- py.test.raises(IndexError, "p[1][-1]")
+ 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]])
@@ -445,7 +454,8 @@ class TestNewFFI1:
n = ffi.new("int*", 99)
p = ffi.new("int*[]", [n])
assert p[0][0] == 99
- py.test.raises(TypeError, "p[0] = None")
+ with pytest.raises(TypeError):
+ p[0] = None
p[0] = ffi.NULL
assert p[0] == ffi.NULL
@@ -478,13 +488,15 @@ class TestNewFFI1:
assert s.a == s.b == s.c == 0
s.b = -23
assert s.b == -23
- py.test.raises(OverflowError, "s.b = 32768")
+ 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
- py.test.raises((AttributeError, TypeError), "del s.a")
+ with pytest.raises((AttributeError, TypeError)):
+ del s.a
assert repr(s) == "<cdata 'struct simple *' owning %d bytes>" % (
SIZE_OF_INT + 2 * SIZE_OF_SHORT)
#
@@ -502,8 +514,10 @@ class TestNewFFI1:
assert s[0].a == s[0].b == s[0].c == 0
s[0].b = -23
assert s[0].b == s.b == -23
- py.test.raises(OverflowError, "s[0].b = -32769")
- py.test.raises(IndexError, "s[1]")
+ 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*")
@@ -555,11 +569,13 @@ class TestNewFFI1:
u.b = -23
assert u.b == -23
assert u.a != 0
- py.test.raises(OverflowError, "u.b = 32768")
+ with pytest.raises(OverflowError):
+ u.b = 32768
#
u = ffi.new("union simple_u*", [-2])
assert u.a == -2
- py.test.raises((AttributeError, TypeError), "del u.a")
+ with pytest.raises((AttributeError, TypeError)):
+ del u.a
assert repr(u) == "<cdata 'union simple_u *' owning %d bytes>" % (
SIZE_OF_INT,)
@@ -625,7 +641,8 @@ class TestNewFFI1:
p[3] = b'\x00'
assert ffi.string(p) == b"hel"
assert ffi.string(p, 2) == b"he"
- py.test.raises(IndexError, "p[7] = b'X'")
+ with pytest.raises(IndexError):
+ p[7] = b'X'
#
a = ffi.new("char[]", b"hello\x00world")
assert len(a) == 12
@@ -648,7 +665,8 @@ class TestNewFFI1:
p[3] = u+'\x00'
assert ffi.string(p) == u+"hel"
assert ffi.string(p, 123) == u+"hel"
- py.test.raises(IndexError, "p[7] = u+'X'")
+ with pytest.raises(IndexError):
+ p[7] = u+'X'
#
a = ffi.new("wchar_t[]", u+"hello\x00world")
assert len(a) == 12
@@ -664,7 +682,8 @@ class TestNewFFI1:
s = ffi.new("struct string*", [t])
assert type(s.name) not in (bytes, str, unicode)
assert ffi.string(s.name) == b"testing"
- py.test.raises(TypeError, "s.name = None")
+ with pytest.raises(TypeError):
+ s.name = None
s.name = ffi.NULL
assert s.name == ffi.NULL
@@ -685,17 +704,20 @@ class TestNewFFI1:
a = ffi.new("int[]", [10, 11, 12])
p = ffi.new("void **", a)
vp = p[0]
- py.test.raises(TypeError, "vp[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
- py.test.raises(TypeError, "s.r = a") # fails
+ with pytest.raises(TypeError):
+ s.r = a # fails
b = ffi.cast("int *", a)
s.p = b # works
s.q = b # works
- py.test.raises(TypeError, "s.r = b") # fails
+ with pytest.raises(TypeError):
+ s.r = b # fails
def test_functionptr_simple(self):
py.test.raises(TypeError, ffi.callback, "int(*)(int)", 0)
@@ -713,7 +735,8 @@ class TestNewFFI1:
q = ffi.new("int(**)(int)", p)
assert repr(q) == "<cdata 'int(* *)(int)' owning %d bytes>" % (
SIZE_OF_PTR)
- py.test.raises(TypeError, "q(43)")
+ with pytest.raises(TypeError):
+ q(43)
res = q[0](43)
assert res == 44
q = ffi.cast("int(*)(int)", p)
@@ -922,10 +945,14 @@ class TestNewFFI1:
assert s.e in (4294967295, -1) # two choices
assert s[0].e in (4294967295, -1)
s.e = s.e
- py.test.raises(TypeError, "s.e = 'B3'")
- py.test.raises(TypeError, "s.e = '2'")
- py.test.raises(TypeError, "s.e = '#2'")
- py.test.raises(TypeError, "s.e = '#7'")
+ 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 };
@@ -947,11 +974,14 @@ class TestNewFFI1:
def test_array_of_struct(self):
s = ffi.new("struct ab[1]")
- py.test.raises(AttributeError, 's.b')
- py.test.raises(AttributeError, 's.b = 412')
+ with pytest.raises(AttributeError):
+ s.b
+ with pytest.raises(AttributeError):
+ s.b = 412
s[0].b = 412
assert s[0].b == 412
- py.test.raises(IndexError, 's[1]')
+ with pytest.raises(IndexError):
+ s[1]
def test_pointer_to_array(self):
p = ffi.new("int(**)[5]")
@@ -1000,17 +1030,23 @@ class TestNewFFI1:
assert ffi.sizeof("struct bitfield") == 8
s = ffi.new("struct bitfield *")
s.a = 511
- py.test.raises(OverflowError, "s.a = 512")
- py.test.raises(OverflowError, "s[0].a = 512")
+ with pytest.raises(OverflowError):
+ s.a = 512
+ with pytest.raises(OverflowError):
+ s[0].a = 512
assert s.a == 511
s.a = -512
- py.test.raises(OverflowError, "s.a = -513")
- py.test.raises(OverflowError, "s[0].a = -513")
+ 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
- py.test.raises(OverflowError, "s.c = 4")
- py.test.raises(OverflowError, "s[0].c = 4")
+ with pytest.raises(OverflowError):
+ s.c = 4
+ with pytest.raises(OverflowError):
+ s[0].c = 4
s.c = -4
assert s.c == -4
@@ -1184,7 +1220,7 @@ class TestNewFFI1:
py.test.skip(str(e))
f.write(ffi.buffer(a, 1000 * ffi.sizeof("int")))
f.seek(0)
- assert f.read() == array.array('i', range(1000)).tostring()
+ 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")))
@@ -1202,7 +1238,7 @@ class TestNewFFI1:
py.test.skip(str(e))
f.write(ffi.buffer(a, 1000 * ffi.sizeof("int")))
f.seek(0)
- assert f.read() == array.array('i', range(1000)).tostring()
+ 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")))
@@ -1235,7 +1271,8 @@ class TestNewFFI1:
p = ffi.new("struct foo_s *", 10) # a single integer is the length
assert p.len == 0
assert p.data[9] == 0
- py.test.raises(IndexError, "p.data[10]")
+ with pytest.raises(IndexError):
+ p.data[10]
def test_ffi_typeof_getcname(self):
assert ffi.getctype("int") == "int"
@@ -1742,7 +1779,7 @@ class TestNewFFI1:
def test_import_from_lib(self):
ffi2 = cffi.FFI()
- ffi2.cdef("int myfunc(int); int myvar;\n#define MYFOO ...\n")
+ 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"
@@ -1752,7 +1789,8 @@ class TestNewFFI1:
assert MYFOO == 42
assert myfunc(43) == 44
assert myvar == -5 # but can't be changed, so not very useful
- py.test.raises(ImportError, "from _test_import_from_lib.lib import bar")
+ 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('_')) ==
diff --git a/testing/cffi1/test_re_python.py b/testing/cffi1/test_re_python.py
index 377c29b..2ae0dd1 100644
--- a/testing/cffi1/test_re_python.py
+++ b/testing/cffi1/test_re_python.py
@@ -63,18 +63,20 @@ def setup_module(mod):
#define BIGNEG -420000000000L
int add42(int);
int add43(int, ...);
- int globalvar42;
+ extern int globalvar42;
const int globalconst42;
- const char *const globalconsthello = "hello";
+ const char *const globalconsthello;
int no_such_function(int);
- int no_such_globalvar;
+ 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')))
@@ -247,6 +249,10 @@ def test_anonymous_union_inside_struct():
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
@@ -254,3 +260,29 @@ def test_anonymous_union_inside_struct():
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_recompiler.py b/testing/cffi1/test_recompiler.py
index 6a31110..fdb4d5a 100644
--- a/testing/cffi1/test_recompiler.py
+++ b/testing/cffi1/test_recompiler.py
@@ -1,5 +1,6 @@
import sys, os, py
+import pytest
from cffi import FFI, VerificationError, FFIError, CDefError
from cffi import recompiler
from testing.udir import udir
@@ -25,16 +26,21 @@ def check_type_table(input, expected_output, included=None):
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':
+ 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', []) +
- ['-Werror'])
+ 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():
@@ -82,7 +88,7 @@ def test_type_table_variadic_function():
"(FUNCTION 1)(PRIMITIVE 7)(FUNCTION_END 1)(POINTER 0)")
def test_type_table_array():
- check_type_table("int a[100];",
+ check_type_table("extern int a[100];",
"(PRIMITIVE 7)(ARRAY 0)(None 100)")
def test_type_table_typedef():
@@ -134,7 +140,8 @@ 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>')
+ 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():
@@ -157,7 +164,7 @@ def test_funcres_ptr():
def test_global_var_array():
ffi = FFI()
- ffi.cdef("int a[100];")
+ 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
@@ -181,27 +188,33 @@ def test_verify_typedef_star_dotdotdot():
def test_global_var_int():
ffi = FFI()
- ffi.cdef("int a, b, c;")
+ 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
- py.test.raises(OverflowError, "lib.a = 2147483648")
- py.test.raises(OverflowError, "lib.a = -2147483649")
+ 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
- py.test.raises(AttributeError, "del lib.a")
- py.test.raises(AttributeError, "del lib.c")
- py.test.raises(AttributeError, "del lib.foobarbaz")
+ 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
- py.test.raises(AttributeError, "lib.FOOBAR = 2")
+ with pytest.raises(AttributeError):
+ lib.FOOBAR = 2
def test_macro_check_value():
# the value '-0x80000000' in C sources does not have a clear meaning
@@ -247,7 +260,8 @@ def test_constant():
ffi.cdef("static const int FOOBAR;")
lib = verify(ffi, 'test_constant', "#define FOOBAR (-6912)")
assert lib.FOOBAR == -6912
- py.test.raises(AttributeError, "lib.FOOBAR = 2")
+ with pytest.raises(AttributeError):
+ lib.FOOBAR = 2
def test_check_value_of_static_const():
ffi = FFI()
@@ -263,7 +277,8 @@ def test_constant_nonint():
ffi.cdef("static const double FOOBAR;")
lib = verify(ffi, 'test_constant_nonint', "#define FOOBAR (-6912.5)")
assert lib.FOOBAR == -6912.5
- py.test.raises(AttributeError, "lib.FOOBAR = 2")
+ with pytest.raises(AttributeError):
+ lib.FOOBAR = 2
def test_constant_ptr():
ffi = FFI()
@@ -274,7 +289,7 @@ def test_constant_ptr():
def test_dir():
ffi = FFI()
- ffi.cdef("int ff(int); int aa; static const int my_constant;")
+ ffi.cdef("int ff(int); extern int aa; static const int my_constant;")
lib = verify(ffi, 'test_dir', """
#define my_constant (-45)
int aa;
@@ -315,8 +330,10 @@ def test_verify_struct():
p = ffi.new("struct foo_s *", {'a': -32768, 'b': -2147483648})
assert p.a == -32768
assert p.b == -2147483648
- py.test.raises(OverflowError, "p.a -= 1")
- py.test.raises(OverflowError, "p.b -= 1")
+ 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
#
@@ -336,9 +353,9 @@ def test_verify_exact_field_offset():
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) == ("struct foo_s: wrong offset for field 'b' (cdef "
- 'says 0, but C compiler says 4). fix it or use "...;" '
- "in the cdef for struct foo_s to make it flexible")
+ 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;")
@@ -387,19 +404,23 @@ def test_dotdotdot_length_of_array_field():
assert ffi.sizeof("struct foo_s") == (42 + 11) * 4
p = ffi.new("struct foo_s *")
assert p.a[41] == p.b[10] == 0
- py.test.raises(IndexError, "p.a[42]")
- py.test.raises(IndexError, "p.b[11]")
+ with pytest.raises(IndexError):
+ p.a[42]
+ with pytest.raises(IndexError):
+ p.b[11]
def test_dotdotdot_global_array():
ffi = FFI()
- ffi.cdef("int aa[...]; int bb[...];")
+ 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
- py.test.raises(IndexError, "lib.aa[41]")
- py.test.raises(IndexError, "lib.bb[12]")
+ with pytest.raises(IndexError):
+ lib.aa[41]
+ with pytest.raises(IndexError):
+ lib.bb[12]
def test_misdeclared_field_1():
ffi = FFI()
@@ -545,37 +566,37 @@ def test_module_name_in_package():
def test_bad_size_of_global_1():
ffi = FFI()
- ffi.cdef("short glob;")
+ 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("int glob[10];")
+ 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("int glob[];")
+ 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("int glob[][5];")
+ 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("int glob[][...];")
+ 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("int glob[...][...];")
+ 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]")
@@ -629,7 +650,7 @@ def test_include_3():
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 x + 42; }")
+ "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")
@@ -738,7 +759,7 @@ def test_unicode_libraries():
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)])
+ libraries=[unicode(lib_m)], ignore_warnings=True)
assert lib.cos(1.43) == math.cos(1.43)
def test_incomplete_struct_as_arg():
@@ -798,7 +819,7 @@ def test_name_of_unnamed_struct():
def test_address_of_global_var():
ffi = FFI()
ffi.cdef("""
- long bottom, bottoms[2];
+ extern long bottom, bottoms[2];
long FetchRectBottom(void);
long FetchRectBottoms1(void);
#define FOOBAR 42
@@ -866,15 +887,20 @@ def test_unpack_args():
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)
- assert str(e1.value) == "foo0() takes no arguments (1 given)"
- assert str(e2.value) == "foo0() takes no arguments (2 given)"
- assert str(e3.value) == "foo1() takes exactly one argument (0 given)"
- assert str(e4.value) == "foo1() takes exactly one argument (2 given)"
- assert str(e5.value) in ["foo2 expected 2 arguments, got 0",
+ 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 str(e6.value) in ["foo2 expected 2 arguments, got 1",
+ assert st1(e6.value) in ["foo2 expected 2 arguments, got 1",
"foo2() takes exactly 2 arguments (1 given)"]
- assert str(e7.value) in ["foo2 expected 2 arguments, got 3",
+ assert st1(e7.value) in ["foo2 expected 2 arguments, got 3",
"foo2() takes exactly 2 arguments (3 given)"]
def test_address_of_function():
@@ -882,7 +908,7 @@ def test_address_of_function():
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)
@@ -953,7 +979,7 @@ def test_variable_of_unknown_size():
ffi = FFI()
ffi.cdef("""
typedef ... opaque_t;
- opaque_t globvar;
+ extern opaque_t globvar;
""")
lib = verify(ffi, 'test_variable_of_unknown_size', """
typedef char opaque_t[6];
@@ -998,7 +1024,7 @@ def test_dotdot_in_source_file_names():
def test_call_with_incomplete_structs():
ffi = FFI()
ffi.cdef("typedef struct {...;} foo_t; "
- "foo_t myglob; "
+ "extern foo_t myglob; "
"foo_t increment(foo_t s); "
"double getx(foo_t s);")
lib = verify(ffi, 'test_call_with_incomplete_structs', """
@@ -1020,8 +1046,10 @@ def test_struct_array_guess_length_2():
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
- py.test.raises(IndexError, 's.a[4][8]')
- py.test.raises(IndexError, 's.a[5][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]")
@@ -1034,38 +1062,44 @@ def test_struct_array_guess_length_3():
s = ffi.new("struct foo_s *")
assert ffi.typeof(s.a) == ffi.typeof("int[][7]")
assert s.a[4][6] == 0
- py.test.raises(IndexError, 's.a[4][7]')
+ 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("int a[...][...];")
+ 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
- py.test.raises(IndexError, 'lib.a[0][8]')
- py.test.raises(IndexError, 'lib.a[10][0]')
+ 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("int a[][...];")
+ 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
- py.test.raises(IndexError, 'lib.a[0][8]')
+ 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("int a[10][...];")
+ 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
- py.test.raises(IndexError, 'lib.a[0][8]')
- py.test.raises(IndexError, 'lib.a[10][8]')
+ 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]")
@@ -1147,7 +1181,7 @@ def test_some_float_invalid_3():
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:
@@ -1181,7 +1215,7 @@ def test_alignment_of_longlong():
def test_import_from_lib():
ffi = FFI()
- ffi.cdef("int mybar(int); int myvar;\n#define MYFOO ...")
+ 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"
@@ -1197,7 +1231,7 @@ def test_import_from_lib():
def test_macro_var_callback():
ffi = FFI()
- ffi.cdef("int my_value; int *(*get_my_value)(void);")
+ 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())")
@@ -1312,7 +1346,7 @@ def test_const_function_args():
def test_const_function_type_args():
ffi = FFI()
- ffi.cdef("""int (*foobar)(const int a, const int *b, const int c[]);""")
+ 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[]);
""")
@@ -1338,7 +1372,8 @@ def test_const_via_typedef():
#define aaa 42
""")
assert lib.aaa == 42
- py.test.raises(AttributeError, "lib.aaa = 43")
+ with pytest.raises(AttributeError):
+ lib.aaa = 43
def test_win32_calling_convention_0():
ffi = FFI()
@@ -1601,7 +1636,7 @@ def test_extern_python_1():
def test_extern_python_bogus_name():
ffi = FFI()
- ffi.cdef("int abc;")
+ ffi.cdef("extern int abc;")
lib = verify(ffi, 'test_extern_python_bogus_name', "int abc;")
def fn():
pass
@@ -1634,9 +1669,10 @@ def test_extern_python_bogus_result_type():
with StdErrCapture() as f:
res = lib.bar(321)
assert res is None
- assert f.getvalue() == (
- "From cffi callback %r:\n" % (bar,) +
- "Trying to convert the result back to C:\n"
+ 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():
@@ -1762,8 +1798,8 @@ def test_extern_python_stdcall():
ffi.cdef("""
extern "Python" int __stdcall foo(int);
extern "Python" int WINAPI bar(int);
- int (__stdcall * mycb1)(int);
- int indirect_call(int);
+ static int (__stdcall * mycb1)(int);
+ static int indirect_call(int);
""")
lib = verify(ffi, 'test_extern_python_stdcall', """
#ifndef _MSC_VER
@@ -1820,7 +1856,7 @@ def test_introspect_function():
ffi = FFI()
ffi.cdef("float f1(double);")
lib = verify(ffi, 'test_introspect_function', """
- float f1(double x) { return x; }
+ float f1(double x) { return (float)x; }
""")
assert dir(lib) == ['f1']
FUNC = ffi.typeof(lib.f1)
@@ -1831,7 +1867,7 @@ def test_introspect_function():
def test_introspect_global_var():
ffi = FFI()
- ffi.cdef("float g1;")
+ ffi.cdef("extern float g1;")
lib = verify(ffi, 'test_introspect_global_var', """
float g1;
""")
@@ -1842,7 +1878,7 @@ def test_introspect_global_var():
def test_introspect_global_var_array():
ffi = FFI()
- ffi.cdef("float g1[100];")
+ ffi.cdef("extern float g1[100];")
lib = verify(ffi, 'test_introspect_global_var_array', """
float g1[100];
""")
@@ -2014,7 +2050,7 @@ def test_function_returns_float_complex():
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.0*b; }
+ 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
@@ -2065,7 +2101,7 @@ def test_typedef_array_dotdotdot():
ffi = FFI()
ffi.cdef("""
typedef int foo_t[...], bar_t[...];
- int gv[...];
+ extern int gv[...];
typedef int mat_t[...][...];
typedef int vmat_t[][...];
""")
@@ -2087,6 +2123,40 @@ def test_typedef_array_dotdotdot():
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("""
@@ -2125,7 +2195,8 @@ def test_call_with_nested_anonymous_struct():
lib = verify(ffi, "test_call_with_nested_anonymous_struct", """
struct foo { int a; union { int b, c; }; };
struct foo f(void) {
- struct foo s = { 40 };
+ struct foo s;
+ s.a = 40;
s.b = 200;
return s;
}
@@ -2314,3 +2385,111 @@ def 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_verify1.py b/testing/cffi1/test_verify1.py
index 75f113d..33244cc 100644
--- a/testing/cffi1/test_verify1.py
+++ b/testing/cffi1/test_verify1.py
@@ -1,9 +1,10 @@
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
+from testing.support import _verify, extra_compile_args
import _cffi_backend
lib_m = ['m']
@@ -12,17 +13,6 @@ if sys.platform == 'win32':
import distutils.ccompiler
if distutils.ccompiler.get_default_compiler() == 'msvc':
lib_m = ['msvcrt']
- extra_compile_args = [] # no obvious -Werror equivalent on MSVC
-else:
- if (sys.platform == 'darwin' and
- [int(x) for x in os.uname()[2].split('.')] >= [11, 0, 0]):
- # assume a standard clang or gcc
- extra_compile_args = ['-Werror', '-Wall', '-Wextra', '-Wconversion']
- # special things for clang
- extra_compile_args.append('-Qunused-arguments')
- else:
- # assume a standard gcc
- extra_compile_args = ['-Werror', '-Wall', '-Wextra', '-Wconversion']
class FFI(FFI):
error = _cffi_backend.FFI.error
@@ -265,7 +255,7 @@ def test_all_integer_and_float_types():
def test_var_signed_integer_types():
ffi = FFI()
lst = all_signed_integer_types(ffi)
- csource = "\n".join(["%s somevar_%s;" % (tp, tp.replace(' ', '_'))
+ csource = "\n".join(["static %s somevar_%s;" % (tp, tp.replace(' ', '_'))
for tp in lst])
ffi.cdef(csource)
lib = ffi.verify(csource)
@@ -284,7 +274,7 @@ def test_var_signed_integer_types():
def test_var_unsigned_integer_types():
ffi = FFI()
lst = all_unsigned_integer_types(ffi)
- csource = "\n".join(["%s somevar_%s;" % (tp, tp.replace(' ', '_'))
+ csource = "\n".join(["static %s somevar_%s;" % (tp, tp.replace(' ', '_'))
for tp in lst])
ffi.cdef(csource)
lib = ffi.verify(csource)
@@ -571,7 +561,8 @@ def test_struct_array_guess_length():
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')
- py.test.raises(IndexError, 's.a[17]')
+ with pytest.raises(IndexError):
+ s.a[17]
def test_struct_array_c99_1():
if sys.platform == 'win32':
@@ -629,7 +620,8 @@ def test_struct_with_bitfield_exact():
ffi.verify("struct foo_s { int a:2, b:3; };")
s = ffi.new("struct foo_s *")
s.b = 3
- py.test.raises(OverflowError, "s.b = 4")
+ with pytest.raises(OverflowError):
+ s.b = 4
assert s.b == 3
def test_struct_with_bitfield_enum():
@@ -786,8 +778,8 @@ def test_define_int():
def test_access_variable():
ffi = FFI()
- ffi.cdef("int foo(void);\n"
- "int somenumber;")
+ ffi.cdef("static int foo(void);\n"
+ "static int somenumber;")
lib = ffi.verify("""
static int somenumber = 2;
static int foo(void) {
@@ -804,7 +796,7 @@ def test_access_variable():
def test_access_address_of_variable():
# access the address of 'somenumber': need a trick
ffi = FFI()
- ffi.cdef("int somenumber; static int *const somenumberptr;")
+ ffi.cdef("static int somenumber; static int *const somenumberptr;")
lib = ffi.verify("""
static int somenumber = 2;
#define somenumberptr (&somenumber)
@@ -816,8 +808,8 @@ def test_access_address_of_variable():
def test_access_array_variable(length=5):
ffi = FFI()
- ffi.cdef("int foo(int);\n"
- "int somenumber[%s];" % (length,))
+ 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) {
@@ -848,8 +840,8 @@ def test_access_array_variable_length_hidden():
def test_access_struct_variable():
ffi = FFI()
ffi.cdef("struct foo { int x; ...; };\n"
- "int foo(int);\n"
- "struct foo stuff;")
+ "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};
@@ -873,9 +865,9 @@ def test_access_struct_variable():
def test_access_callback():
ffi = FFI()
- ffi.cdef("int (*cb)(int);\n"
- "int foo(int);\n"
- "void reset_cb(void);")
+ 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);
@@ -891,9 +883,9 @@ def test_access_callback():
def test_access_callback_function_typedef():
ffi = FFI()
ffi.cdef("typedef int mycallback_t(int);\n"
- "mycallback_t *cb;\n"
- "int foo(int);\n"
- "void reset_cb(void);")
+ "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);
@@ -1034,7 +1026,7 @@ def test_autofilled_struct_as_argument():
def test_autofilled_struct_as_argument_dynamic():
ffi = FFI()
ffi.cdef("struct foo_s { long a; ...; };\n"
- "int (*foo)(struct foo_s);")
+ "static int (*foo)(struct foo_s);")
lib = ffi.verify("""
struct foo_s {
double b;
@@ -1043,7 +1035,7 @@ def test_autofilled_struct_as_argument_dynamic():
int foo1(struct foo_s s) {
return (int)s.a - (int)s.b;
}
- int (*foo)(struct foo_s s) = &foo1;
+ 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 "
@@ -1419,7 +1411,7 @@ def test_bool():
py.test.skip("_Bool not in MSVC")
ffi = FFI()
ffi.cdef("struct foo_s { _Bool x; };"
- "_Bool foo(_Bool); _Bool (*foop)(_Bool);")
+ "_Bool foo(_Bool); static _Bool (*foop)(_Bool);")
lib = ffi.verify("""
struct foo_s { _Bool x; };
int foo(int arg) {
@@ -1428,13 +1420,15 @@ def test_bool():
_Bool _foofunc(_Bool x) {
return !x;
}
- _Bool (*foop)(_Bool) = _foofunc;
+ static _Bool (*foop)(_Bool) = _foofunc;
""")
p = ffi.new("struct foo_s *")
p.x = 1
assert p.x is True
- py.test.raises(OverflowError, "p.x = -1")
- py.test.raises(TypeError, "p.x = 0.0")
+ 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
@@ -1502,7 +1496,8 @@ def test_cannot_pass_float():
}
""" % (type, type))
p = ffi.new("struct foo_s *")
- py.test.raises(TypeError, "p.x = 0.0")
+ 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)
@@ -1610,7 +1605,7 @@ def test_FILE_stored_in_stdout():
def test_FILE_stored_explicitly():
ffi = FFI()
- ffi.cdef("int myprintf11(const char *, int); FILE *myfile;")
+ ffi.cdef("int myprintf11(const char *, int); extern FILE *myfile;")
lib = ffi.verify("""
#include <stdio.h>
FILE *myfile;
@@ -1636,13 +1631,13 @@ def test_FILE_stored_explicitly():
def test_global_array_with_missing_length():
ffi = FFI()
- ffi.cdef("int fooarray[];")
+ 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("int fooarray[...];")
+ ffi.cdef("extern int fooarray[...];")
lib = ffi.verify("int fooarray[50];")
assert repr(lib.fooarray).startswith("<cdata 'int[50]'")
@@ -1650,7 +1645,7 @@ 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("int fooarray[...];")
+ ffi.cdef("extern int fooarray[...];")
py.test.raises(VerificationError, ffi.verify, "char fooarray[23];")
def test_struct_containing_struct():
@@ -1771,7 +1766,7 @@ def test_string_to_voidp_arg():
def test_callback_indirection():
ffi = FFI()
ffi.cdef("""
- int (*python_callback)(int how_many, int *values);
+ 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,...));
""")
@@ -1905,23 +1900,23 @@ def test_typeof_func_with_struct_argument():
def test_bug_const_char_ptr_array_1():
ffi = FFI()
- ffi.cdef("""const char *a[...];""")
+ 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("""const int a[];""")
+ 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 = """
- int xvalue;
- long long ivalue, rvalue;
- float fvalue;
- double dvalue;
- long double Dvalue;
+ 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);
@@ -2104,7 +2099,7 @@ def test_verify_dlopen_flags():
old = sys.getdlopenflags()
try:
ffi1 = FFI()
- ffi1.cdef("int foo_verify_dlopen_flags_1;")
+ 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:
@@ -2193,7 +2188,8 @@ def test_define_wrong_value():
ffi = FFI()
ffi.cdef("#define FOO 123")
lib = ffi.verify("#define FOO 124") # used to complain
- e = py.test.raises(ffi.error, "lib.FOO")
+ 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")
@@ -2244,7 +2240,7 @@ def test_windows_dllimport_data():
def test_macro_var():
ffi = FFI()
- ffi.cdef("int myarray[50], my_value;")
+ ffi.cdef("extern int myarray[50], my_value;")
lib = ffi.verify("""
int myarray[50];
int *get_my_value(void) {
diff --git a/testing/embedding/add1.py b/testing/embedding/add1.py
index e5b3de1..6f89ae9 100644
--- a/testing/embedding/add1.py
+++ b/testing/embedding/add1.py
@@ -11,7 +11,11 @@ ffi.embedding_init_code(r"""
sys.stdout.write("preparing")
for i in range(3):
sys.stdout.flush()
- time.sleep(0.2)
+ # Windows: sometimes time.sleep() doesn't sleep at all.
+ # This appears to occur on recent versions of python only.
+ t_end = time.time() + 0.19
+ while time.time() < t_end:
+ time.sleep(0.2)
sys.stdout.write(".")
sys.stdout.write("\n")
diff --git a/testing/embedding/add_recursive.py b/testing/embedding/add_recursive.py
index 9fa463d..a88aa8f 100644
--- a/testing/embedding/add_recursive.py
+++ b/testing/embedding/add_recursive.py
@@ -3,7 +3,7 @@ import cffi
ffi = cffi.FFI()
ffi.embedding_api("""
- int (*my_callback)(int);
+ extern int (*my_callback)(int);
int add_rec(int, int);
""")
diff --git a/testing/embedding/test_basic.py b/testing/embedding/test_basic.py
index 8463c3f..8d2e776 100644
--- a/testing/embedding/test_basic.py
+++ b/testing/embedding/test_basic.py
@@ -63,8 +63,8 @@ class EmbeddingTests:
output = popen.stdout.read()
err = popen.wait()
if err:
- raise OSError("popen failed with exit code %r: %r" % (
- err, args))
+ raise OSError(("popen failed with exit code %r: %r\n\n%s" % (
+ err, args, output)).rstrip())
print(output.rstrip())
return output
@@ -172,7 +172,8 @@ if sys.platform == 'win32':
result = popen.stdout.read()
err = popen.wait()
if err:
- raise OSError("%r failed with exit code %r" % (name, err))
+ raise OSError("%r failed with exit code %r" % (
+ os.path.join(path, executable_name), err))
return result
@@ -205,3 +206,9 @@ class TestBasic(EmbeddingTests):
self.compile('add1-test', [initerror_cffi])
output = self.execute('add1-test')
assert output == "got: 0 0\n" # plus lots of info to stderr
+
+ def test_embedding_with_unicode(self):
+ withunicode_cffi = self.prepare_module('withunicode')
+ self.compile('add1-test', [withunicode_cffi])
+ output = self.execute('add1-test')
+ assert output == "255\n4660\n65244\ngot: 0 0\n"
diff --git a/testing/embedding/test_performance.py b/testing/embedding/test_performance.py
index f9f2605..a0e8458 100644
--- a/testing/embedding/test_performance.py
+++ b/testing/embedding/test_performance.py
@@ -2,8 +2,8 @@ import sys
from testing.embedding.test_basic import EmbeddingTests
if sys.platform == 'win32':
- import py
- py.test.skip("written with POSIX functions")
+ import pytest
+ pytestmark = pytest.mark.skip("written with POSIX functions")
class TestPerformance(EmbeddingTests):
diff --git a/testing/embedding/test_thread.py b/testing/embedding/test_thread.py
index 1895076..9a5936d 100644
--- a/testing/embedding/test_thread.py
+++ b/testing/embedding/test_thread.py
@@ -21,17 +21,21 @@ class TestThread(EmbeddingTests):
add1_cffi = self.prepare_module('add1')
add2_cffi = self.prepare_module('add2')
self.compile('thread2-test', [add1_cffi, add2_cffi], threads=True)
- output = self.execute('thread2-test')
- output = self._take_out(output, "preparing")
- output = self._take_out(output, ".")
- output = self._take_out(output, ".")
- # at least the 3rd dot should be after everything from ADD2
- assert output == ("starting\n"
- "prepADD2\n"
- "adding 1000 and 200 and 30\n"
- ".\n"
- "adding 40 and 2\n"
- "done\n")
+ for i in range(3):
+ output = self.execute('thread2-test')
+ print('='*79)
+ print(output)
+ print('='*79)
+ output = self._take_out(output, "preparing")
+ output = self._take_out(output, ".")
+ output = self._take_out(output, ".")
+ # at least the 3rd dot should be after everything from ADD2
+ assert output == ("starting\n"
+ "prepADD2\n"
+ "adding 1000 and 200 and 30\n"
+ ".\n"
+ "adding 40 and 2\n"
+ "done\n")
def test_alt_issue(self):
add1_cffi = self.prepare_module('add1')
diff --git a/testing/embedding/withunicode.py b/testing/embedding/withunicode.py
new file mode 100644
index 0000000..839c6cd
--- /dev/null
+++ b/testing/embedding/withunicode.py
@@ -0,0 +1,26 @@
+import sys, cffi
+if sys.version_info < (3,):
+ u_prefix = "u"
+else:
+ u_prefix = ""
+ unichr = chr
+
+
+ffi = cffi.FFI()
+
+ffi.embedding_api(u"""
+ int add1(int, int);
+""")
+
+ffi.embedding_init_code(("""
+ import sys, time
+ for c in %s'""" + unichr(0x00ff) + unichr(0x1234) + unichr(0xfedc) + """':
+ sys.stdout.write(str(ord(c)) + '\\n')
+ sys.stdout.flush()
+""") % u_prefix)
+
+ffi.set_source("_withunicode_cffi", """
+""")
+
+fn = ffi.compile(verbose=True)
+print('FILENAME: %s' % (fn,))
diff --git a/testing/support.py b/testing/support.py
index 65f010c..6339a94 100644
--- a/testing/support.py
+++ b/testing/support.py
@@ -1,7 +1,7 @@
-import sys
+import sys, os
if sys.version_info < (3,):
- __all__ = ['u']
+ __all__ = ['u', 'arraytostring']
class U(object):
def __add__(self, other):
@@ -12,12 +12,16 @@ if sys.version_info < (3,):
assert u+'a\x00b' == eval(r"u'a\x00b'")
assert u+'a\u1234b' == eval(r"u'a\u1234b'")
assert u+'a\U00012345b' == eval(r"u'a\U00012345b'")
+ def arraytostring(a):
+ return a.tostring()
else:
- __all__ = ['u', 'unicode', 'long']
+ __all__ = ['u', 'unicode', 'long', 'arraytostring']
u = ""
unicode = str
long = int
+ def arraytostring(a):
+ return a.tobytes()
class StdErrCapture(object):
@@ -29,9 +33,14 @@ class StdErrCapture(object):
from io import StringIO
self.old_stderr = sys.stderr
sys.stderr = f = StringIO()
+ if hasattr(sys, '__unraisablehook__'): # work around pytest
+ self.old_unraisablebook = sys.unraisablehook # on recent CPythons
+ sys.unraisablehook = sys.__unraisablehook__
return f
def __exit__(self, *args):
sys.stderr = self.old_stderr
+ if hasattr(self, 'old_unraisablebook'):
+ sys.unraisablehook = self.old_unraisablebook
class FdWriteCapture(object):
@@ -86,3 +95,25 @@ def _verify(ffi, module_name, preamble, *args, **kwds):
if not name.startswith('_') and not hasattr(module.ffi, name):
setattr(ffi, name, NotImplemented)
return module.lib
+
+
+# For testing, we call gcc with "-Werror". This is fragile because newer
+# versions of gcc are always better at producing warnings, particularly for
+# auto-generated code. We need here to adapt and silence them as needed.
+
+if sys.platform == 'win32':
+ extra_compile_args = [] # no obvious -Werror equivalent on MSVC
+else:
+ if (sys.platform == 'darwin' and
+ [int(x) for x in os.uname()[2].split('.')] >= [11, 0, 0]):
+ # assume a standard clang or gcc
+ extra_compile_args = ['-Werror', '-Wall', '-Wextra', '-Wconversion',
+ '-Wno-unused-parameter',
+ '-Wno-unreachable-code']
+ # special things for clang
+ extra_compile_args.append('-Qunused-arguments')
+ else:
+ # assume a standard gcc
+ extra_compile_args = ['-Werror', '-Wall', '-Wextra', '-Wconversion',
+ '-Wno-unused-parameter',
+ '-Wno-unreachable-code']
diff --git a/testing/udir.py b/testing/udir.py
index 4dd0a11..59db1c4 100644
--- a/testing/udir.py
+++ b/testing/udir.py
@@ -1,7 +1,134 @@
import py
-import sys
+import sys, os, atexit
-udir = py.path.local.make_numbered_dir(prefix = 'ffi-')
+
+# This is copied from PyPy's vendored py lib. The latest py lib release
+# (1.8.1) contains a bug and crashes if it sees another temporary directory
+# in which we don't have write permission (e.g. because it's owned by someone
+# else).
+def make_numbered_dir(prefix='session-', rootdir=None, keep=3,
+ lock_timeout = 172800, # two days
+ min_timeout = 300): # five minutes
+ """ return unique directory with a number greater than the current
+ maximum one. The number is assumed to start directly after prefix.
+ if keep is true directories with a number less than (maxnum-keep)
+ will be removed.
+ """
+ if rootdir is None:
+ rootdir = py.path.local.get_temproot()
+
+ def parse_num(path):
+ """ parse the number out of a path (if it matches the prefix) """
+ bn = path.basename
+ if bn.startswith(prefix):
+ try:
+ return int(bn[len(prefix):])
+ except ValueError:
+ pass
+
+ # compute the maximum number currently in use with the
+ # prefix
+ lastmax = None
+ while True:
+ maxnum = -1
+ for path in rootdir.listdir():
+ num = parse_num(path)
+ if num is not None:
+ maxnum = max(maxnum, num)
+
+ # make the new directory
+ try:
+ udir = rootdir.mkdir(prefix + str(maxnum+1))
+ except py.error.EEXIST:
+ # race condition: another thread/process created the dir
+ # in the meantime. Try counting again
+ if lastmax == maxnum:
+ raise
+ lastmax = maxnum
+ continue
+ break
+
+ # put a .lock file in the new directory that will be removed at
+ # process exit
+ if lock_timeout:
+ lockfile = udir.join('.lock')
+ mypid = os.getpid()
+ if hasattr(lockfile, 'mksymlinkto'):
+ lockfile.mksymlinkto(str(mypid))
+ else:
+ lockfile.write(str(mypid))
+ def try_remove_lockfile():
+ # in a fork() situation, only the last process should
+ # remove the .lock, otherwise the other processes run the
+ # risk of seeing their temporary dir disappear. For now
+ # we remove the .lock in the parent only (i.e. we assume
+ # that the children finish before the parent).
+ if os.getpid() != mypid:
+ return
+ try:
+ lockfile.remove()
+ except py.error.Error:
+ pass
+ atexit.register(try_remove_lockfile)
+
+ # prune old directories
+ if keep:
+ for path in rootdir.listdir():
+ num = parse_num(path)
+ if num is not None and num <= (maxnum - keep):
+ if min_timeout:
+ # NB: doing this is needed to prevent (or reduce
+ # a lot the chance of) the following situation:
+ # 'keep+1' processes call make_numbered_dir() at
+ # the same time, they create dirs, but then the
+ # last process notices the first dir doesn't have
+ # (yet) a .lock in it and kills it.
+ try:
+ t1 = path.lstat().mtime
+ t2 = lockfile.lstat().mtime
+ if abs(t2-t1) < min_timeout:
+ continue # skip directories too recent
+ except py.error.Error:
+ continue # failure to get a time, better skip
+ lf = path.join('.lock')
+ try:
+ t1 = lf.lstat().mtime
+ t2 = lockfile.lstat().mtime
+ if not lock_timeout or abs(t2-t1) < lock_timeout:
+ continue # skip directories still locked
+ except py.error.Error:
+ pass # assume that it means that there is no 'lf'
+ try:
+ path.remove(rec=1)
+ except KeyboardInterrupt:
+ raise
+ except: # this might be py.error.Error, WindowsError ...
+ pass
+
+ # make link...
+ try:
+ username = os.environ['USER'] #linux, et al
+ except KeyError:
+ try:
+ username = os.environ['USERNAME'] #windows
+ except KeyError:
+ username = 'current'
+
+ src = str(udir)
+ dest = src[:src.rfind('-')] + '-' + username
+ try:
+ os.unlink(dest)
+ except OSError:
+ pass
+ try:
+ os.symlink(src, dest)
+ except (OSError, AttributeError, NotImplementedError):
+ pass
+
+ return udir
+
+
+udir = make_numbered_dir(prefix = 'ffi-')
# Windows-only workaround for some configurations: see