import pytest import platform import sys, ctypes, ctypes.util from cffi import FFI, CDefError, FFIError, VerificationMissing from testing.support import * SIZE_OF_INT = ctypes.sizeof(ctypes.c_int) SIZE_OF_LONG = ctypes.sizeof(ctypes.c_long) SIZE_OF_SHORT = ctypes.sizeof(ctypes.c_short) SIZE_OF_PTR = ctypes.sizeof(ctypes.c_void_p) SIZE_OF_WCHAR = ctypes.sizeof(ctypes.c_wchar) def needs_dlopen_none(): if sys.platform == 'win32' and not ctypes.util.find_library('c'): pytest.skip("dlopen(None) cannot work on Windows with this runtime") class BackendTests: def test_integer_ranges(self): ffi = FFI(backend=self.Backend()) for (c_type, size) in [('char', 1), ('short', 2), ('short int', 2), ('', 4), ('int', 4), ('long', SIZE_OF_LONG), ('long int', SIZE_OF_LONG), ('long long', 8), ('long long int', 8), ]: for unsigned in [None, False, True]: c_decl = {None: '', False: 'signed ', True: 'unsigned '}[unsigned] + c_type if c_decl == 'char' or c_decl == '': continue self._test_int_type(ffi, c_decl, size, unsigned) def test_fixedsize_int(self): ffi = FFI(backend=self.Backend()) for size in [1, 2, 4, 8]: self._test_int_type(ffi, 'int%d_t' % (8*size), size, False) self._test_int_type(ffi, 'uint%d_t' % (8*size), size, True) self._test_int_type(ffi, 'intptr_t', SIZE_OF_PTR, False) self._test_int_type(ffi, 'uintptr_t', SIZE_OF_PTR, True) self._test_int_type(ffi, 'ptrdiff_t', SIZE_OF_PTR, False) self._test_int_type(ffi, 'size_t', SIZE_OF_PTR, True) self._test_int_type(ffi, 'ssize_t', SIZE_OF_PTR, False) def _test_int_type(self, ffi, c_decl, size, unsigned): if unsigned: min = 0 max = (1 << (8*size)) - 1 else: min = -(1 << (8*size-1)) max = (1 << (8*size-1)) - 1 min = int(min) max = int(max) p = ffi.cast(c_decl, min) assert p == min assert hash(p) == hash(min) assert bool(p) is bool(min) assert int(p) == min p = ffi.cast(c_decl, max) assert int(p) == max p = ffi.cast(c_decl, long(max)) assert int(p) == max q = ffi.cast(c_decl, min - 1) assert ffi.typeof(q) is ffi.typeof(p) and int(q) == max q = ffi.cast(c_decl, long(min - 1)) assert ffi.typeof(q) is ffi.typeof(p) and int(q) == max assert q == p assert int(q) == int(p) assert hash(q) == hash(p) c_decl_ptr = '%s *' % c_decl pytest.raises(OverflowError, ffi.new, c_decl_ptr, min - 1) pytest.raises(OverflowError, ffi.new, c_decl_ptr, max + 1) pytest.raises(OverflowError, ffi.new, c_decl_ptr, long(min - 1)) pytest.raises(OverflowError, ffi.new, c_decl_ptr, long(max + 1)) assert ffi.new(c_decl_ptr, min)[0] == min assert ffi.new(c_decl_ptr, max)[0] == max assert ffi.new(c_decl_ptr, long(min))[0] == min assert ffi.new(c_decl_ptr, long(max))[0] == max def test_new_unsupported_type(self): ffi = FFI(backend=self.Backend()) e = pytest.raises(TypeError, ffi.new, "int") assert str(e.value) == "expected a pointer or array ctype, got 'int'" def test_new_single_integer(self): ffi = FFI(backend=self.Backend()) p = ffi.new("int *") # similar to ffi.new("int[1]") assert p[0] == 0 p[0] = -123 assert p[0] == -123 p = ffi.new("int *", -42) assert p[0] == -42 assert repr(p) == "" % SIZE_OF_INT def test_new_array_no_arg(self): ffi = FFI(backend=self.Backend()) p = ffi.new("int[10]") # the object was zero-initialized: for i in range(10): assert p[i] == 0 def test_array_indexing(self): ffi = FFI(backend=self.Backend()) p = ffi.new("int[10]") p[0] = 42 p[9] = 43 assert p[0] == 42 assert p[9] == 43 with pytest.raises(IndexError): p[10] with pytest.raises(IndexError): p[10] = 44 with pytest.raises(IndexError): p[-1] with pytest.raises(IndexError): p[-1] = 44 def test_new_array_args(self): ffi = FFI(backend=self.Backend()) # this tries to be closer to C: where we say "int x[5] = {10, 20, ..}" # then here we must enclose the items in a list p = ffi.new("int[5]", [10, 20, 30, 40, 50]) assert p[0] == 10 assert p[1] == 20 assert p[2] == 30 assert p[3] == 40 assert p[4] == 50 p = ffi.new("int[4]", [25]) assert p[0] == 25 assert p[1] == 0 # follow C convention rather than LuaJIT's assert p[2] == 0 assert p[3] == 0 p = ffi.new("int[4]", [ffi.cast("int", -5)]) assert p[0] == -5 assert repr(p) == "" % (4*SIZE_OF_INT) def test_new_array_varsize(self): ffi = FFI(backend=self.Backend()) p = ffi.new("int[]", 10) # a single integer is the length assert p[9] == 0 with pytest.raises(IndexError): p[10] # pytest.raises(TypeError, ffi.new, "int[]") # p = ffi.new("int[]", [-6, -7]) # a list is all the items, like C assert p[0] == -6 assert p[1] == -7 with pytest.raises(IndexError): p[2] assert repr(p) == "" % (2*SIZE_OF_INT) # p = ffi.new("int[]", 0) with pytest.raises(IndexError): p[0] pytest.raises(ValueError, ffi.new, "int[]", -1) assert repr(p) == "" def test_pointer_init(self): ffi = FFI(backend=self.Backend()) n = ffi.new("int *", 24) a = ffi.new("int *[10]", [ffi.NULL, ffi.NULL, n, n, ffi.NULL]) for i in range(10): if i not in (2, 3): assert a[i] == ffi.NULL assert a[2] == a[3] == n def test_cannot_cast(self): ffi = FFI(backend=self.Backend()) a = ffi.new("short int[10]") e = pytest.raises(TypeError, ffi.new, "long int **", a) msg = str(e.value) assert "'short[10]'" in msg and "'long *'" in msg def test_new_pointer_to_array(self): ffi = FFI(backend=self.Backend()) a = ffi.new("int[4]", [100, 102, 104, 106]) p = ffi.new("int **", a) assert p[0] == ffi.cast("int *", a) assert p[0][2] == 104 p = ffi.cast("int *", a) assert p[0] == 100 assert p[1] == 102 assert p[2] == 104 assert p[3] == 106 # keepalive: a def test_pointer_direct(self): ffi = FFI(backend=self.Backend()) p = ffi.cast("int*", 0) assert p is not None assert bool(p) is False assert p == ffi.cast("int*", 0) assert p != None assert repr(p) == "" a = ffi.new("int[]", [123, 456]) p = ffi.cast("int*", a) assert bool(p) is True assert p == ffi.cast("int*", a) assert p != ffi.cast("int*", 0) assert p[0] == 123 assert p[1] == 456 def test_repr(self): typerepr = self.TypeRepr ffi = FFI(backend=self.Backend()) ffi.cdef("struct foo { short a, b, c; };") p = ffi.cast("short unsigned int", 0) assert repr(p) == "" assert repr(ffi.typeof(p)) == typerepr % "unsigned short" p = ffi.cast("unsigned short int", 0) assert repr(p) == "" assert repr(ffi.typeof(p)) == typerepr % "unsigned short" p = ffi.cast("int*", 0) assert repr(p) == "" assert repr(ffi.typeof(p)) == typerepr % "int *" # p = ffi.new("int*") assert repr(p) == "" % SIZE_OF_INT assert repr(ffi.typeof(p)) == typerepr % "int *" p = ffi.new("int**") assert repr(p) == "" % SIZE_OF_PTR assert repr(ffi.typeof(p)) == typerepr % "int * *" p = ffi.new("int [2]") assert repr(p) == "" % (2*SIZE_OF_INT) assert repr(ffi.typeof(p)) == typerepr % "int[2]" p = ffi.new("int*[2][3]") assert repr(p) == "" % ( 6*SIZE_OF_PTR) assert repr(ffi.typeof(p)) == typerepr % "int *[2][3]" p = ffi.new("struct foo *") assert repr(p) == "" % ( 3*SIZE_OF_SHORT) assert repr(ffi.typeof(p)) == typerepr % "struct foo *" # q = ffi.cast("short", -123) assert repr(q) == "" assert repr(ffi.typeof(q)) == typerepr % "short" p = ffi.new("int*") q = ffi.cast("short*", p) assert repr(q).startswith(" 2: assert ffi.new("wchar_t*", u+'\U00012345')[0] == u+'\U00012345' else: pytest.raises(TypeError, ffi.new, "wchar_t*", u+'\U00012345') assert ffi.new("wchar_t*")[0] == u+'\x00' assert int(ffi.cast("wchar_t", 300)) == 300 assert not bool(ffi.cast("wchar_t", 0)) assert bool(ffi.cast("wchar_t", 1)) assert bool(ffi.cast("wchar_t", 65535)) if SIZE_OF_WCHAR > 2: assert bool(ffi.cast("wchar_t", 65536)) pytest.raises(TypeError, ffi.new, "wchar_t*", 32) pytest.raises(TypeError, ffi.new, "wchar_t*", "foo") # p = ffi.new("wchar_t[]", [u+'a', u+'b', u+'\u1234']) assert len(p) == 3 assert p[0] == u+'a' assert p[1] == u+'b' and type(p[1]) is unicode assert p[2] == u+'\u1234' p[0] = u+'x' assert p[0] == u+'x' and type(p[0]) is unicode p[1] = u+'\u1357' assert p[1] == u+'\u1357' p = ffi.new("wchar_t[]", u+"abcd") assert len(p) == 5 assert p[4] == u+'\x00' p = ffi.new("wchar_t[]", u+"a\u1234b") assert len(p) == 4 assert p[1] == u+'\u1234' # p = ffi.new("wchar_t[]", u+'\U00023456') if SIZE_OF_WCHAR == 2: assert len(p) == 3 assert p[0] == u+'\ud84d' assert p[1] == u+'\udc56' assert p[2] == u+'\x00' else: assert len(p) == 2 assert p[0] == u+'\U00023456' assert p[1] == u+'\x00' # p = ffi.new("wchar_t[4]", u+"ab") assert len(p) == 4 assert [p[i] for i in range(4)] == [u+'a', u+'b', u+'\x00', u+'\x00'] p = ffi.new("wchar_t[2]", u+"ab") assert len(p) == 2 assert [p[i] for i in range(2)] == [u+'a', u+'b'] pytest.raises(IndexError, ffi.new, "wchar_t[2]", u+"abc") def test_none_as_null_doesnt_work(self): ffi = FFI(backend=self.Backend()) p = ffi.new("int*[1]") assert p[0] is not None assert p[0] != None assert p[0] == ffi.NULL assert repr(p[0]) == "" # n = ffi.new("int*", 99) p = ffi.new("int*[]", [n]) assert p[0][0] == 99 with pytest.raises(TypeError): p[0] = None p[0] = ffi.NULL assert p[0] == ffi.NULL def test_float(self): ffi = FFI(backend=self.Backend()) p = ffi.new("float[]", [-2, -2.5]) assert p[0] == -2.0 assert p[1] == -2.5 p[1] += 17.75 assert p[1] == 15.25 # p = ffi.new("float*", 15.75) assert p[0] == 15.75 pytest.raises(TypeError, int, p) pytest.raises(TypeError, float, p) p[0] = 0.0 assert bool(p) is True # p = ffi.new("float*", 1.1) f = p[0] assert f != 1.1 # because of rounding effect assert abs(f - 1.1) < 1E-7 # INF = 1E200 * 1E200 assert 1E200 != INF p[0] = 1E200 assert p[0] == INF # infinite, not enough precision def test_struct_simple(self): ffi = FFI(backend=self.Backend()) ffi.cdef("struct foo { int a; short b, c; };") s = ffi.new("struct foo*") assert s.a == s.b == s.c == 0 s.b = -23 assert s.b == -23 with pytest.raises(OverflowError): s.b = 32768 # s = ffi.new("struct foo*", [-2, -3]) assert s.a == -2 assert s.b == -3 assert s.c == 0 with pytest.raises((AttributeError, TypeError)): del s.a assert repr(s) == "" % ( SIZE_OF_INT + 2 * SIZE_OF_SHORT) # pytest.raises(ValueError, ffi.new, "struct foo*", [1, 2, 3, 4]) def test_constructor_struct_from_dict(self): ffi = FFI(backend=self.Backend()) ffi.cdef("struct foo { int a; short b, c; };") s = ffi.new("struct foo*", {'b': 123, 'c': 456}) assert s.a == 0 assert s.b == 123 assert s.c == 456 pytest.raises(KeyError, ffi.new, "struct foo*", {'d': 456}) def test_struct_pointer(self): ffi = FFI(backend=self.Backend()) ffi.cdef("struct foo { int a; short b, c; };") s = ffi.new("struct foo*") assert s[0].a == s[0].b == s[0].c == 0 s[0].b = -23 assert s[0].b == s.b == -23 with pytest.raises(OverflowError): s[0].b = -32769 with pytest.raises(IndexError): s[1] def test_struct_opaque(self): ffi = FFI(backend=self.Backend()) pytest.raises(TypeError, ffi.new, "struct baz*") p = ffi.new("struct baz **") # this works assert p[0] == ffi.NULL def test_pointer_to_struct(self): ffi = FFI(backend=self.Backend()) ffi.cdef("struct foo { int a; short b, c; };") s = ffi.new("struct foo *") s.a = -42 assert s[0].a == -42 p = ffi.new("struct foo **", s) assert p[0].a == -42 assert p[0][0].a == -42 p[0].a = -43 assert s.a == -43 assert s[0].a == -43 p[0][0].a = -44 assert s.a == -44 assert s[0].a == -44 s.a = -45 assert p[0].a == -45 assert p[0][0].a == -45 s[0].a = -46 assert p[0].a == -46 assert p[0][0].a == -46 def test_constructor_struct_of_array(self): ffi = FFI(backend=self.Backend()) ffi.cdef("struct foo { int a[2]; char b[3]; };") s = ffi.new("struct foo *", [[10, 11], [b'a', b'b', b'c']]) assert s.a[1] == 11 assert s.b[2] == b'c' s.b[1] = b'X' assert s.b[0] == b'a' assert s.b[1] == b'X' assert s.b[2] == b'c' def test_recursive_struct(self): ffi = FFI(backend=self.Backend()) ffi.cdef("struct foo { int value; struct foo *next; };") s = ffi.new("struct foo*") t = ffi.new("struct foo*") s.value = 123 s.next = t t.value = 456 assert s.value == 123 assert s.next.value == 456 def test_union_simple(self): ffi = FFI(backend=self.Backend()) ffi.cdef("union foo { int a; short b, c; };") u = ffi.new("union foo*") assert u.a == u.b == u.c == 0 u.b = -23 assert u.b == -23 assert u.a != 0 with pytest.raises(OverflowError): u.b = 32768 # u = ffi.new("union foo*", [-2]) assert u.a == -2 with pytest.raises((AttributeError, TypeError)): del u.a assert repr(u) == "" % SIZE_OF_INT def test_union_opaque(self): ffi = FFI(backend=self.Backend()) pytest.raises(TypeError, ffi.new, "union baz *") u = ffi.new("union baz **") # this works assert u[0] == ffi.NULL def test_union_initializer(self): ffi = FFI(backend=self.Backend()) ffi.cdef("union foo { char a; int b; };") pytest.raises(TypeError, ffi.new, "union foo*", b'A') pytest.raises(TypeError, ffi.new, "union foo*", 5) pytest.raises(ValueError, ffi.new, "union foo*", [b'A', 5]) u = ffi.new("union foo*", [b'A']) assert u.a == b'A' pytest.raises(TypeError, ffi.new, "union foo*", [1005]) u = ffi.new("union foo*", {'b': 12345}) assert u.b == 12345 u = ffi.new("union foo*", []) assert u.a == b'\x00' assert u.b == 0 def test_sizeof_type(self): ffi = FFI(backend=self.Backend()) ffi.cdef(""" struct foo { int a; short b, c, d; }; union foo { int a; short b, c, d; }; """) for c_type, expected_size in [ ('char', 1), ('unsigned int', 4), ('char *', SIZE_OF_PTR), ('int[5]', 20), ('struct foo', 12), ('union foo', 4), ]: size = ffi.sizeof(c_type) assert size == expected_size, (size, expected_size, ctype) def test_sizeof_cdata(self): ffi = FFI(backend=self.Backend()) assert ffi.sizeof(ffi.new("short*")) == SIZE_OF_PTR assert ffi.sizeof(ffi.cast("short", 123)) == SIZE_OF_SHORT # a = ffi.new("int[]", [10, 11, 12, 13, 14]) assert len(a) == 5 assert ffi.sizeof(a) == 5 * SIZE_OF_INT def test_string_from_char_pointer(self): ffi = FFI(backend=self.Backend()) x = ffi.new("char*", b"x") assert str(x) == repr(x) assert ffi.string(x) == b"x" assert ffi.string(ffi.new("char*", b"\x00")) == b"" pytest.raises(TypeError, ffi.new, "char*", unicode("foo")) def test_unicode_from_wchar_pointer(self): ffi = FFI(backend=self.Backend()) self.check_wchar_t(ffi) x = ffi.new("wchar_t*", u+"x") assert unicode(x) == unicode(repr(x)) assert ffi.string(x) == u+"x" assert ffi.string(ffi.new("wchar_t*", u+"\x00")) == u+"" def test_string_from_char_array(self): ffi = FFI(backend=self.Backend()) p = ffi.new("char[]", b"hello.") p[5] = b'!' assert ffi.string(p) == b"hello!" p[6] = b'?' assert ffi.string(p) == b"hello!?" p[3] = b'\x00' assert ffi.string(p) == b"hel" assert ffi.string(p, 2) == b"he" with pytest.raises(IndexError): p[7] = b'X' # a = ffi.new("char[]", b"hello\x00world") assert len(a) == 12 p = ffi.cast("char *", a) assert ffi.string(p) == b'hello' def test_string_from_wchar_array(self): ffi = FFI(backend=self.Backend()) self.check_wchar_t(ffi) assert ffi.string(ffi.cast("wchar_t", "x")) == u+"x" assert ffi.string(ffi.cast("wchar_t", u+"x")) == u+"x" x = ffi.cast("wchar_t", "x") assert str(x) == repr(x) assert ffi.string(x) == u+"x" # p = ffi.new("wchar_t[]", u+"hello.") p[5] = u+'!' assert ffi.string(p) == u+"hello!" p[6] = u+'\u04d2' assert ffi.string(p) == u+"hello!\u04d2" p[3] = u+'\x00' assert ffi.string(p) == u+"hel" assert ffi.string(p, 123) == u+"hel" with pytest.raises(IndexError): p[7] = u+'X' # a = ffi.new("wchar_t[]", u+"hello\x00world") assert len(a) == 12 p = ffi.cast("wchar_t *", a) assert ffi.string(p) == u+'hello' assert ffi.string(p, 123) == u+'hello' assert ffi.string(p, 5) == u+'hello' assert ffi.string(p, 2) == u+'he' def test_fetch_const_char_p_field(self): # 'const' is ignored so far ffi = FFI(backend=self.Backend()) ffi.cdef("struct foo { const char *name; };") t = ffi.new("const char[]", b"testing") s = ffi.new("struct foo*", [t]) assert type(s.name) not in (bytes, str, unicode) assert ffi.string(s.name) == b"testing" with pytest.raises(TypeError): s.name = None s.name = ffi.NULL assert s.name == ffi.NULL def test_fetch_const_wchar_p_field(self): # 'const' is ignored so far ffi = FFI(backend=self.Backend()) self.check_wchar_t(ffi) ffi.cdef("struct foo { const wchar_t *name; };") t = ffi.new("const wchar_t[]", u+"testing") s = ffi.new("struct foo*", [t]) assert type(s.name) not in (bytes, str, unicode) assert ffi.string(s.name) == u+"testing" s.name = ffi.NULL assert s.name == ffi.NULL def test_voidp(self): ffi = FFI(backend=self.Backend()) pytest.raises(TypeError, ffi.new, "void*") p = ffi.new("void **") assert p[0] == ffi.NULL a = ffi.new("int[]", [10, 11, 12]) p = ffi.new("void **", a) vp = p[0] with pytest.raises(TypeError): vp[0] pytest.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 with pytest.raises(TypeError): s.r = a # fails b = ffi.cast("int *", a) s.p = b # works s.q = b # works with pytest.raises(TypeError): s.r = b # fails def test_functionptr_simple(self): ffi = FFI(backend=self.Backend()) pytest.raises(TypeError, ffi.callback, "int(*)(int)", 0) def cb(n): return n + 1 cb.__qualname__ = 'cb' p = ffi.callback("int(*)(int)", cb) res = p(41) # calling an 'int(*)(int)', i.e. a function pointer assert res == 42 and type(res) is int res = p(ffi.cast("int", -41)) assert res == -40 and type(res) is int assert repr(p).startswith( "" % ( SIZE_OF_PTR) with pytest.raises(TypeError): q(43) res = q[0](43) assert res == 44 q = ffi.cast("int(*)(int)", p) assert repr(q).startswith("" assert repr(ffi.cast("enum foo", -1)) == ( # enums are unsigned, if "") # they contain no neg value ffi.cdef("enum baz { A2=0x1000, B2=0x2000 };") assert ffi.string(ffi.cast("enum baz", 0x1000)) == "A2" assert ffi.string(ffi.cast("enum baz", 0x2000)) == "B2" def test_enum_in_struct(self): ffi = FFI(backend=self.Backend()) ffi.cdef("enum foo { A, B, C, D }; struct bar { enum foo e; };") s = ffi.new("struct bar *") s.e = 0 assert s.e == 0 s.e = 3 assert s.e == 3 assert s[0].e == 3 s[0].e = 2 assert s.e == 2 assert s[0].e == 2 s.e = ffi.cast("enum foo", -1) assert s.e == 4294967295 assert s[0].e == 4294967295 s.e = s.e 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()) ffi.cdef("enum foo { A, B=42, C };") assert ffi.string(ffi.cast("enum foo", 0)) == "A" assert ffi.string(ffi.cast("enum foo", 42)) == "B" assert ffi.string(ffi.cast("enum foo", 43)) == "C" invalid_value = ffi.cast("enum foo", 2) assert int(invalid_value) == 2 assert ffi.string(invalid_value) == "2" def test_enum_char_hex_oct(self): ffi = FFI(backend=self.Backend()) ffi.cdef(r"enum foo{A='!', B='\'', C=0x10, D=010, E=- 0x10, F=-010};") assert ffi.string(ffi.cast("enum foo", ord('!'))) == "A" assert ffi.string(ffi.cast("enum foo", ord("'"))) == "B" assert ffi.string(ffi.cast("enum foo", 16)) == "C" assert ffi.string(ffi.cast("enum foo", 8)) == "D" assert ffi.string(ffi.cast("enum foo", -16)) == "E" assert ffi.string(ffi.cast("enum foo", -8)) == "F" def test_enum_partial(self): ffi = FFI(backend=self.Backend()) ffi.cdef(r"enum foo {A, ...}; enum bar { B, C };") needs_dlopen_none() lib = ffi.dlopen(None) assert lib.B == 0 pytest.raises(VerificationMissing, getattr, lib, "A") assert lib.C == 1 def test_array_of_struct(self): ffi = FFI(backend=self.Backend()) ffi.cdef("struct foo { int a, b; };") s = ffi.new("struct foo[1]") with pytest.raises(AttributeError): s.b with pytest.raises(AttributeError): s.b = 412 s[0].b = 412 assert s[0].b == 412 with pytest.raises(IndexError): s[1] def test_pointer_to_array(self): ffi = FFI(backend=self.Backend()) p = ffi.new("int(**)[5]") assert repr(p) == "" % SIZE_OF_PTR def test_iterate_array(self): ffi = FFI(backend=self.Backend()) a = ffi.new("char[]", b"hello") assert list(a) == [b"h", b"e", b"l", b"l", b"o", b"\0"] assert list(iter(a)) == [b"h", b"e", b"l", b"l", b"o", b"\0"] # pytest.raises(TypeError, iter, ffi.cast("char *", a)) pytest.raises(TypeError, list, ffi.cast("char *", a)) pytest.raises(TypeError, iter, ffi.new("int *")) pytest.raises(TypeError, list, ffi.new("int *")) def test_offsetof(self): ffi = FFI(backend=self.Backend()) ffi.cdef("struct foo { int a, b, c; };") assert ffi.offsetof("struct foo", "a") == 0 assert ffi.offsetof("struct foo", "b") == 4 assert ffi.offsetof("struct foo", "c") == 8 def test_offsetof_nested(self): ffi = FFI(backend=self.Backend()) ffi.cdef("struct foo { int a, b, c; };" "struct bar { struct foo d, e; };") assert ffi.offsetof("struct bar", "e") == 12 pytest.raises(KeyError, ffi.offsetof, "struct bar", "e.a") assert ffi.offsetof("struct bar", "e", "a") == 12 assert ffi.offsetof("struct bar", "e", "b") == 16 assert ffi.offsetof("struct bar", "e", "c") == 20 def test_offsetof_array(self): ffi = FFI(backend=self.Backend()) assert ffi.offsetof("int[]", 51) == 51 * ffi.sizeof("int") assert ffi.offsetof("int *", 51) == 51 * ffi.sizeof("int") ffi.cdef("struct bar { int a, b; int c[99]; };") assert ffi.offsetof("struct bar", "c") == 2 * ffi.sizeof("int") assert ffi.offsetof("struct bar", "c", 0) == 2 * ffi.sizeof("int") assert ffi.offsetof("struct bar", "c", 51) == 53 * ffi.sizeof("int") def test_alignof(self): ffi = FFI(backend=self.Backend()) ffi.cdef("struct foo { char a; short b; char c; };") assert ffi.alignof("int") == 4 assert ffi.alignof("double") in (4, 8) assert ffi.alignof("struct foo") == 2 def test_bitfield(self): ffi = FFI(backend=self.Backend()) ffi.cdef("struct foo { int a:10, b:20, c:3; };") assert ffi.sizeof("struct foo") == 8 s = ffi.new("struct foo *") s.a = 511 with pytest.raises(OverflowError): s.a = 512 with pytest.raises(OverflowError): s[0].a = 512 assert s.a == 511 s.a = -512 with pytest.raises(OverflowError): s.a = -513 with pytest.raises(OverflowError): s[0].a = -513 assert s.a == -512 s.c = 3 assert s.c == 3 with pytest.raises(OverflowError): s.c = 4 with pytest.raises(OverflowError): s[0].c = 4 s.c = -4 assert s.c == -4 def test_bitfield_enum(self): ffi = FFI(backend=self.Backend()) ffi.cdef(""" typedef enum { AA, BB, CC } foo_e; typedef struct { foo_e f:2; } foo_s; """) s = ffi.new("foo_s *") s.f = 2 assert s.f == 2 def test_anonymous_struct(self): ffi = FFI(backend=self.Backend()) ffi.cdef("typedef struct { int a; } foo_t;") ffi.cdef("typedef struct { char b, c; } bar_t;") f = ffi.new("foo_t *", [12345]) b = ffi.new("bar_t *", [b"B", b"C"]) assert f.a == 12345 assert b.b == b"B" assert b.c == b"C" assert repr(b).startswith(" s) is False assert (p >= s) is True assert (s < p) is False assert (s <= p) is True assert (s == p) is True assert (s != p) is False assert (s > p) is False assert (s >= p) is True q = p + 1 assert (q < s) is False assert (q <= s) is False assert (q == s) is False assert (q != s) is True assert (q > s) is True assert (q >= s) is True assert (s < q) is True assert (s <= q) is True assert (s == q) is False assert (s != q) is True assert (s > q) is False assert (s >= q) is False assert (q < p) is False assert (q <= p) is False assert (q == p) is False assert (q != p) is True assert (q > p) is True assert (q >= p) is True assert (p < q) is True assert (p <= q) is True assert (p == q) is False assert (p != q) is True assert (p > q) is False assert (p >= q) is False # assert (None == s) is False assert (None != s) is True assert (s == None) is False assert (s != None) is True assert (None == q) is False assert (None != q) is True assert (q == None) is False assert (q != None) is True def test_integer_comparison(self): ffi = FFI(backend=self.Backend()) x = ffi.cast("int", 123) y = ffi.cast("int", 456) assert x < y # z = ffi.cast("double", 78.9) assert x > z assert y > z def test_ffi_buffer_ptr(self): ffi = FFI(backend=self.Backend()) a = ffi.new("short *", 100) try: b = ffi.buffer(a) except NotImplementedError as e: pytest.skip(str(e)) assert type(b) is ffi.buffer content = b[:] assert len(content) == len(b) == 2 if sys.byteorder == 'little': assert content == b'\x64\x00' assert b[0] == b'\x64' b[0] = b'\x65' else: assert content == b'\x00\x64' assert b[1] == b'\x64' b[1] = b'\x65' assert a[0] == 101 def test_ffi_buffer_array(self): ffi = FFI(backend=self.Backend()) a = ffi.new("int[]", list(range(100, 110))) try: b = ffi.buffer(a) except NotImplementedError as e: pytest.skip(str(e)) content = b[:] if sys.byteorder == 'little': assert content.startswith(b'\x64\x00\x00\x00\x65\x00\x00\x00') b[4] = b'\x45' else: assert content.startswith(b'\x00\x00\x00\x64\x00\x00\x00\x65') b[7] = b'\x45' assert len(content) == 4 * 10 assert a[1] == 0x45 def test_ffi_buffer_ptr_size(self): ffi = FFI(backend=self.Backend()) a = ffi.new("short *", 0x4243) try: b = ffi.buffer(a, 1) except NotImplementedError as e: pytest.skip(str(e)) content = b[:] assert len(content) == 1 if sys.byteorder == 'little': assert content == b'\x43' b[0] = b'\x62' assert a[0] == 0x4262 else: assert content == b'\x42' b[0] = b'\x63' assert a[0] == 0x6343 def test_ffi_buffer_array_size(self): ffi = FFI(backend=self.Backend()) a1 = ffi.new("int[]", list(range(100, 110))) a2 = ffi.new("int[]", list(range(100, 115))) try: ffi.buffer(a1) except NotImplementedError as e: pytest.skip(str(e)) assert ffi.buffer(a1)[:] == ffi.buffer(a2, 4*10)[:] def test_ffi_buffer_with_file(self): ffi = FFI(backend=self.Backend()) import tempfile, os, array fd, filename = tempfile.mkstemp() f = os.fdopen(fd, 'r+b') a = ffi.new("int[]", list(range(1005))) try: ffi.buffer(a, 512) except NotImplementedError as e: pytest.skip(str(e)) f.write(ffi.buffer(a, 1000 * ffi.sizeof("int"))) f.seek(0) assert f.read() == arraytostring(array.array('i', range(1000))) f.seek(0) b = ffi.new("int[]", 1005) f.readinto(ffi.buffer(b, 1000 * ffi.sizeof("int"))) assert list(a)[:1000] + [0] * (len(a)-1000) == list(b) f.close() os.unlink(filename) def test_ffi_buffer_with_io(self): ffi = FFI(backend=self.Backend()) import io, array f = io.BytesIO() a = ffi.new("int[]", list(range(1005))) try: ffi.buffer(a, 512) except NotImplementedError as e: pytest.skip(str(e)) f.write(ffi.buffer(a, 1000 * ffi.sizeof("int"))) f.seek(0) assert f.read() == arraytostring(array.array('i', range(1000))) f.seek(0) b = ffi.new("int[]", 1005) f.readinto(ffi.buffer(b, 1000 * ffi.sizeof("int"))) assert list(a)[:1000] + [0] * (len(a)-1000) == list(b) f.close() def test_ffi_buffer_comparisons(self): ffi = FFI(backend=self.Backend()) ba = bytearray(range(100, 110)) if sys.version_info >= (2, 7): assert ba == memoryview(ba) # justification for the following a = ffi.new("uint8_t[]", list(ba)) c = ffi.new("uint8_t[]", [99] + list(ba)) try: b_full = ffi.buffer(a) b_short = ffi.buffer(a, 3) b_mid = ffi.buffer(a, 6) b_other = ffi.buffer(c, 6) except NotImplementedError as e: pytest.skip(str(e)) else: content = b_full[:] assert content == b_full == ba assert b_other < b_short < b_mid < b_full assert ba > b_mid > ba[0:2] assert b_short != ba[1:4] def test_array_in_struct(self): ffi = FFI(backend=self.Backend()) ffi.cdef("struct foo_s { int len; short data[5]; };") p = ffi.new("struct foo_s *") p.data[3] = 5 assert p.data[3] == 5 assert repr(p.data).startswith("