summaryrefslogtreecommitdiff
path: root/testing/test_verify.py
diff options
context:
space:
mode:
Diffstat (limited to 'testing/test_verify.py')
-rw-r--r--testing/test_verify.py103
1 files changed, 90 insertions, 13 deletions
diff --git a/testing/test_verify.py b/testing/test_verify.py
index 6027ff4..12266fc 100644
--- a/testing/test_verify.py
+++ b/testing/test_verify.py
@@ -15,10 +15,39 @@ def setup_module():
cffi.verifier.cleanup_tmpdir()
-def test_missing_function():
+def test_module_type():
+ import cffi.verifier
ffi = FFI()
+ lib = ffi.verify()
+ if hasattr(lib, '_cffi_python_module'):
+ print 'verify got a PYTHON module'
+ if hasattr(lib, '_cffi_generic_module'):
+ print 'verify got a GENERIC module'
+ expected_generic = (cffi.verifier._FORCE_GENERIC_ENGINE or
+ '__pypy__' in sys.builtin_module_names)
+ assert hasattr(lib, '_cffi_python_module') == (not expected_generic)
+ assert hasattr(lib, '_cffi_generic_module') == expected_generic
+
+def test_missing_function(ffi=None):
+ # uses the FFI hacked above with '-Werror'
+ if ffi is None:
+ ffi = FFI()
ffi.cdef("void some_completely_unknown_function();")
- py.test.raises(VerificationError, ffi.verify)
+ try:
+ lib = ffi.verify()
+ except VerificationError:
+ pass # expected case: we get a VerificationError
+ else:
+ # but depending on compiler and loader details, maybe
+ # 'lib' could actually be imported but will fail if we
+ # actually try to call the unknown function... Hard
+ # to test anything more.
+ pass
+
+def test_missing_function_import_error():
+ # uses the original FFI that just gives a warning during compilation
+ import cffi
+ test_missing_function(ffi=cffi.FFI())
def test_simple_case():
ffi = FFI()
@@ -102,6 +131,20 @@ def test_all_integer_and_float_types():
else:
assert lib.foo(value) == value + 1
+def test_nonstandard_integer_types():
+ ffi = FFI()
+ lst = ffi._backend.nonstandard_integer_types().items()
+ lst.sort()
+ verify_lines = []
+ for key, value in lst:
+ ffi.cdef("static const int expected_%s;" % key)
+ verify_lines.append("static const int expected_%s =" % key)
+ verify_lines.append(" sizeof(%s) | (((%s)-1) <= 0 ? 0 : 0x1000);"
+ % (key, key))
+ lib = ffi.verify('\n'.join(verify_lines))
+ for key, value in lst:
+ assert getattr(lib, 'expected_%s' % key) == value
+
def test_char_type():
ffi = FFI()
ffi.cdef("char foo(char);")
@@ -339,7 +382,7 @@ def test_global_constants_non_int():
ffi.cdef("static char *const PP;")
lib = ffi.verify('static char *const PP = "testing!";\n')
assert ffi.typeof(lib.PP) == ffi.typeof("char *")
- assert lib.PP.value == b"testing!"
+ assert ffi.string(lib.PP) == b"testing!"
def test_nonfull_enum():
ffi = FFI()
@@ -415,16 +458,26 @@ def test_access_address_of_variable():
assert lib.somenumber == 42
lib.somenumber = 2 # reset for the next run, if any
-def test_access_array_variable():
+def test_access_array_variable(length=5):
ffi = FFI()
ffi.cdef("int foo(int);\n"
- "int somenumber[5];")
+ "int somenumber[%s];" % (length,))
lib = ffi.verify("""
static int somenumber[] = {2, 2, 3, 4, 5};
static int foo(int i) {
return somenumber[i] * 7;
}
""")
+ if length == '':
+ # a global variable of an unknown array length is implicitly
+ # transformed into a global pointer variable, because we can only
+ # work with array instances whose length we know. using a pointer
+ # instead of an array gives the correct effects.
+ assert repr(lib.somenumber).startswith("<cdata 'int *' 0x")
+ py.test.raises(TypeError, len, lib.somenumber)
+ else:
+ assert repr(lib.somenumber).startswith("<cdata 'int[%s]' 0x" % length)
+ assert len(lib.somenumber) == 5
assert lib.somenumber[3] == 4
assert lib.foo(3) == 28
lib.somenumber[3] = -6
@@ -433,6 +486,9 @@ def test_access_array_variable():
assert lib.somenumber[4] == 5
lib.somenumber[3] = 4 # reset for the next run, if any
+def test_access_array_variable_length_hidden():
+ test_access_array_variable(length='')
+
def test_access_struct_variable():
ffi = FFI()
ffi.cdef("struct foo { int x; ...; };\n"
@@ -476,11 +532,32 @@ def test_access_callback():
lib.cb = my_callback
assert lib.foo(4) == 887
-def test_cannot_verify_with_ctypes():
+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);")
+ lib = ffi.verify("""
+ static int g(int x) { return x * 7; }
+ static int (*cb)(int);
+ static int foo(int i) { return cb(i) - 1; }
+ static void reset_cb(void) { cb = g; }
+ """)
+ lib.reset_cb()
+ assert lib.foo(6) == 41
+ my_callback = ffi.callback("int(*)(int)", lambda n: n * 222)
+ lib.cb = my_callback
+ assert lib.foo(4) == 887
+
+def test_ctypes_backend_forces_generic_engine():
from cffi.backend_ctypes import CTypesBackend
ffi = FFI(backend=CTypesBackend())
- ffi.cdef("int a;")
- py.test.raises(NotImplementedError, ffi.verify, "int a;")
+ ffi.cdef("int func(int a);")
+ lib = ffi.verify("int func(int a) { return a * 42; }")
+ assert not hasattr(lib, '_cffi_python_module')
+ assert hasattr(lib, '_cffi_generic_module')
+ assert lib.func(100) == 4200
def test_call_with_struct_ptr():
ffi = FFI()
@@ -635,7 +712,7 @@ def test_func_as_funcptr():
""")
foochar = ffi.cast("char *(*)(void)", lib.fooptr)
s = foochar()
- assert s.value == b"foobar"
+ assert ffi.string(s) == b"foobar"
def test_funcptr_as_argument():
ffi = FFI()
@@ -709,12 +786,12 @@ def test_opaque_integer_as_function_result():
# anyway. XXX think about something better :-(
ffi = FFI()
ffi.cdef("""
- typedef struct { ...; } handle_t;
- handle_t foo(void);
+ typedef struct { ...; } myhandle_t;
+ myhandle_t foo(void);
""")
lib = ffi.verify("""
- typedef short handle_t;
- handle_t foo(void) { return 42; }
+ typedef short myhandle_t;
+ myhandle_t foo(void) { return 42; }
""")
h = lib.foo()
assert ffi.sizeof(h) == ffi.sizeof("short")