summaryrefslogtreecommitdiff
path: root/testing
diff options
context:
space:
mode:
authorArmin Rigo <arigo@tunes.org>2020-07-19 11:35:02 +0200
committerArmin Rigo <arigo@tunes.org>2020-07-19 11:35:02 +0200
commit663ed8ddd7744cd68077141f9b7b0b910c82c09b (patch)
treef56b15a8a609c4c6f179a6d768e348f7bcfbb1c8 /testing
parent63b741f4e24663796b730cbab6a7b25dc6ece004 (diff)
downloadcffi-663ed8ddd7744cd68077141f9b7b0b910c82c09b.tar.gz
Add a hypothesis test. Mostly checks libffi, or our own libffi_msvc on windows
Diffstat (limited to 'testing')
-rw-r--r--testing/cffi0/test_function_args.py89
1 files changed, 89 insertions, 0 deletions
diff --git a/testing/cffi0/test_function_args.py b/testing/cffi0/test_function_args.py
new file mode 100644
index 0000000..ed94c97
--- /dev/null
+++ b/testing/cffi0/test_function_args.py
@@ -0,0 +1,89 @@
+import pytest
+try:
+ from hypothesis import given
+ from hypothesis import strategies as st
+except ImportError as e:
+ def test_types():
+ pytest.skip(str(e))
+else:
+
+ from cffi import FFI
+ import random
+
+ ALL_PRIMITIVES = [
+ 'unsigned char',
+ 'short',
+ 'int',
+ 'long',
+ 'long long',
+ 'float',
+ 'double',
+ 'long double',
+ ]
+ def _make_struct(s):
+ return st.lists(s, min_size=1)
+ types = st.recursive(st.sampled_from(ALL_PRIMITIVES), _make_struct)
+
+ def draw_primitive(ffi, typename):
+ value = random.random() * 2**40
+ if typename != 'long double':
+ return ffi.cast(typename, value)
+ else:
+ return value
+
+
+ @given(st.lists(types), types)
+ def test_types(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)
+
+ ffi = FFI()
+ ffi.cdef("\n".join(cdefs))
+
+ 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)
+ received_arguments = []
+
+ _tp_long_double = ffi.typeof("long double")
+ 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
+
+ def callback(*args):
+ received_arguments.append([expand(arg) for arg in args])
+ return returned_value
+
+ fptr = ffi.callback("%s(*)(%s)" % (result, ','.join(args)), callback)
+ received_return = fptr(*passed_args)
+
+ assert len(received_arguments) == 1
+ assert passed_args == received_arguments[0]
+ assert expand(received_return) == returned_value