import py import platform, imp import sys, os, ctypes import cffi from testing.udir import udir from testing.support import * from cffi.recompiler import recompile from cffi.cffi_opcode import PRIMITIVE_TO_INDEX SIZE_OF_INT = ctypes.sizeof(ctypes.c_int) SIZE_OF_LONG = ctypes.sizeof(ctypes.c_long) SIZE_OF_SHORT = ctypes.sizeof(ctypes.c_short) SIZE_OF_PTR = ctypes.sizeof(ctypes.c_void_p) SIZE_OF_WCHAR = ctypes.sizeof(ctypes.c_wchar) def setup_module(): global ffi, construction_params ffi1 = cffi.FFI() DEFS = r""" struct repr { short a, b, c; }; struct simple { int a; short b, c; }; struct array { int a[2]; char b[3]; }; struct recursive { int value; struct recursive *next; }; union simple_u { int a; short b, c; }; union init_u { char a; int b; }; struct four_s { int a; short b, c, d; }; union four_u { int a; short b, c, d; }; struct string { const char *name; }; struct ustring { const wchar_t *name; }; struct voidp { void *p; int *q; short *r; }; struct ab { int a, b; }; struct abc { int a, b, c; }; /* don't use A0, B0, CC0, D0 because termios.h might be included and it has its own #defines for these names */ enum foq { cffiA0, cffiB0, cffiCC0, cffiD0 }; enum bar { A1, B1=-2, CC1, D1, E1 }; enum baz { A2=0x1000, B2=0x2000 }; enum foo2 { A3, B3, C3, D3 }; struct bar_with_e { enum foo2 e; }; enum noncont { A4, B4=42, C4 }; enum etypes {A5='!', B5='\'', C5=0x10, D5=010, E5=- 0x10, F5=-010}; typedef enum { Value0 = 0 } e_t, *pe_t; enum e_noninj { AA3=0, BB3=0, CC3=0, DD3=0 }; enum e_prev { AA4, BB4=2, CC4=4, DD4=BB4, EE4, FF4=CC4, GG4=FF4 }; struct nesting { struct abc d, e; }; struct array2 { int a, b; int c[99]; }; struct align { char a; short b; char c; }; struct bitfield { int a:10, b:20, c:3; }; typedef enum { AA2, BB2, CC2 } foo_e_t; typedef struct { foo_e_t f:2; } bfenum_t; typedef struct { int a; } anon_foo_t; typedef struct { char b, c; } anon_bar_t; typedef struct named_foo_s { int a; } named_foo_t, *named_foo_p; typedef struct { int a; } unnamed_foo_t, *unnamed_foo_p; struct nonpacked { char a; int b; }; struct array0 { int len; short data[0]; }; struct array_no_length { int x; int a[]; }; struct nested_anon { struct { int a, b; }; union { int c, d; }; }; struct nested_field_ofs_s { struct { int a; char b; }; union { char c; }; }; union nested_anon_u { struct { int a, b; }; union { int c, d; }; }; struct abc50 { int a, b; int c[50]; }; struct ints_and_bitfield { int a,b,c,d,e; int x:1; }; """ DEFS_PACKED = """ struct is_packed { char a; int b; } /*here*/; """ if sys.platform == "win32": DEFS = DEFS.replace('data[0]', 'data[1]') # not supported CCODE = (DEFS + "\n#pragma pack(push,1)\n" + DEFS_PACKED + "\n#pragma pack(pop)\n") else: CCODE = (DEFS + DEFS_PACKED.replace('/*here*/', '__attribute__((packed))')) ffi1.cdef(DEFS) ffi1.cdef(DEFS_PACKED, packed=True) ffi1.set_source("test_new_ffi_1", CCODE) outputfilename = recompile(ffi1, "test_new_ffi_1", CCODE, tmpdir=str(udir)) module = imp.load_dynamic("test_new_ffi_1", outputfilename) ffi = module.ffi construction_params = (ffi1, CCODE) class TestNewFFI1: def test_integer_ranges(self): for (c_type, size) in [('char', 1), ('short', 2), ('short int', 2), ('', 4), ('int', 4), ('long', SIZE_OF_LONG), ('long int', SIZE_OF_LONG), ('long long', 8), ('long long int', 8), ]: for unsigned in [None, False, True]: c_decl = {None: '', False: 'signed ', True: 'unsigned '}[unsigned] + c_type if c_decl == 'char' or c_decl == '': continue self._test_int_type(ffi, c_decl, size, unsigned) def test_fixedsize_int(self): for size in [1, 2, 4, 8]: self._test_int_type(ffi, 'int%d_t' % (8*size), size, False) self._test_int_type(ffi, 'uint%d_t' % (8*size), size, True) self._test_int_type(ffi, 'intptr_t', SIZE_OF_PTR, False) self._test_int_type(ffi, 'uintptr_t', SIZE_OF_PTR, True) self._test_int_type(ffi, 'ptrdiff_t', SIZE_OF_PTR, False) self._test_int_type(ffi, 'size_t', SIZE_OF_PTR, True) self._test_int_type(ffi, 'ssize_t', SIZE_OF_PTR, False) def _test_int_type(self, ffi, c_decl, size, unsigned): if unsigned: min = 0 max = (1 << (8*size)) - 1 else: min = -(1 << (8*size-1)) max = (1 << (8*size-1)) - 1 min = int(min) max = int(max) p = ffi.cast(c_decl, min) assert p == min assert bool(p) is bool(min) assert int(p) == min p = ffi.cast(c_decl, max) assert int(p) == max p = ffi.cast(c_decl, long(max)) assert int(p) == max q = ffi.cast(c_decl, min - 1) assert ffi.typeof(q) is ffi.typeof(p) and int(q) == max q = ffi.cast(c_decl, long(min - 1)) assert ffi.typeof(q) is ffi.typeof(p) and int(q) == max assert q == p assert int(q) == int(p) assert hash(q) == hash(p) c_decl_ptr = '%s *' % c_decl py.test.raises(OverflowError, ffi.new, c_decl_ptr, min - 1) py.test.raises(OverflowError, ffi.new, c_decl_ptr, max + 1) py.test.raises(OverflowError, ffi.new, c_decl_ptr, long(min - 1)) py.test.raises(OverflowError, ffi.new, c_decl_ptr, long(max + 1)) assert ffi.new(c_decl_ptr, min)[0] == min assert ffi.new(c_decl_ptr, max)[0] == max assert ffi.new(c_decl_ptr, long(min))[0] == min assert ffi.new(c_decl_ptr, long(max))[0] == max def test_new_unsupported_type(self): e = py.test.raises(TypeError, ffi.new, "int") assert str(e.value) == "expected a pointer or array ctype, got 'int'" def test_new_single_integer(self): p = ffi.new("int *") # similar to ffi.new("int[1]") assert p[0] == 0 p[0] = -123 assert p[0] == -123 p = ffi.new("int *", -42) assert p[0] == -42 assert repr(p) == "" % SIZE_OF_INT def test_new_array_no_arg(self): p = ffi.new("int[10]") # the object was zero-initialized: for i in range(10): assert p[i] == 0 def test_array_indexing(self): p = ffi.new("int[10]") p[0] = 42 p[9] = 43 assert p[0] == 42 assert p[9] == 43 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") def test_new_array_args(self): # this tries to be closer to C: where we say "int x[5] = {10, 20, ..}" # then here we must enclose the items in a list p = ffi.new("int[5]", [10, 20, 30, 40, 50]) assert p[0] == 10 assert p[1] == 20 assert p[2] == 30 assert p[3] == 40 assert p[4] == 50 p = ffi.new("int[4]", [25]) assert p[0] == 25 assert p[1] == 0 # follow C convention rather than LuaJIT's assert p[2] == 0 assert p[3] == 0 p = ffi.new("int[4]", [ffi.cast("int", -5)]) assert p[0] == -5 assert repr(p) == "" % (4*SIZE_OF_INT) def test_new_array_varsize(self): p = ffi.new("int[]", 10) # a single integer is the length assert p[9] == 0 py.test.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]") assert repr(p) == "" % (2*SIZE_OF_INT) # p = ffi.new("int[]", 0) py.test.raises(IndexError, "p[0]") py.test.raises(ValueError, ffi.new, "int[]", -1) assert repr(p) == "" def test_pointer_init(self): n = ffi.new("int *", 24) a = ffi.new("int *[10]", [ffi.NULL, ffi.NULL, n, n, ffi.NULL]) for i in range(10): if i not in (2, 3): assert a[i] == ffi.NULL assert a[2] == a[3] == n def test_cannot_cast(self): a = ffi.new("short int[10]") e = py.test.raises(TypeError, ffi.new, "long int **", a) msg = str(e.value) assert "'short[10]'" in msg and "'long *'" in msg def test_new_pointer_to_array(self): a = ffi.new("int[4]", [100, 102, 104, 106]) p = ffi.new("int **", a) assert p[0] == ffi.cast("int *", a) assert p[0][2] == 104 p = ffi.cast("int *", a) assert p[0] == 100 assert p[1] == 102 assert p[2] == 104 assert p[3] == 106 # keepalive: a def test_pointer_direct(self): p = ffi.cast("int*", 0) assert p is not None assert bool(p) is False assert p == ffi.cast("int*", 0) assert p != None assert repr(p) == "" 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 = "" 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 repr *") assert repr(p) == "" % ( 3*SIZE_OF_SHORT) assert repr(ffi.typeof(p)) == typerepr % "struct repr *" # 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: py.test.raises(TypeError, ffi.new, "wchar_t*", u+'\U00012345') assert ffi.new("wchar_t*")[0] == u+'\x00' assert int(ffi.cast("wchar_t", 300)) == 300 assert not bool(ffi.cast("wchar_t", 0)) assert bool(ffi.cast("wchar_t", 1)) assert bool(ffi.cast("wchar_t", 65535)) if SIZE_OF_WCHAR > 2: assert bool(ffi.cast("wchar_t", 65536)) py.test.raises(TypeError, ffi.new, "wchar_t*", 32) py.test.raises(TypeError, ffi.new, "wchar_t*", "foo") # p = ffi.new("wchar_t[]", [u+'a', u+'b', u+'\u1234']) assert len(p) == 3 assert p[0] == u+'a' assert p[1] == u+'b' and type(p[1]) is unicode assert p[2] == u+'\u1234' p[0] = u+'x' assert p[0] == u+'x' and type(p[0]) is unicode p[1] = u+'\u1357' assert p[1] == u+'\u1357' p = ffi.new("wchar_t[]", u+"abcd") assert len(p) == 5 assert p[4] == u+'\x00' p = ffi.new("wchar_t[]", u+"a\u1234b") assert len(p) == 4 assert p[1] == u+'\u1234' # p = ffi.new("wchar_t[]", u+'\U00023456') if SIZE_OF_WCHAR == 2: assert len(p) == 3 assert p[0] == u+'\ud84d' assert p[1] == u+'\udc56' assert p[2] == u+'\x00' else: assert len(p) == 2 assert p[0] == u+'\U00023456' assert p[1] == u+'\x00' # p = ffi.new("wchar_t[4]", u+"ab") assert len(p) == 4 assert [p[i] for i in range(4)] == [u+'a', u+'b', u+'\x00', u+'\x00'] p = ffi.new("wchar_t[2]", u+"ab") assert len(p) == 2 assert [p[i] for i in range(2)] == [u+'a', u+'b'] py.test.raises(IndexError, ffi.new, "wchar_t[2]", u+"abc") def test_none_as_null_doesnt_work(self): p = ffi.new("int*[1]") assert p[0] is not None assert p[0] != None assert p[0] == ffi.NULL assert repr(p[0]) == "" # n = ffi.new("int*", 99) p = ffi.new("int*[]", [n]) assert p[0][0] == 99 py.test.raises(TypeError, "p[0] = None") p[0] = ffi.NULL assert p[0] == ffi.NULL def test_float(self): p = ffi.new("float[]", [-2, -2.5]) assert p[0] == -2.0 assert p[1] == -2.5 p[1] += 17.75 assert p[1] == 15.25 # p = ffi.new("float*", 15.75) assert p[0] == 15.75 py.test.raises(TypeError, int, p) py.test.raises(TypeError, float, p) p[0] = 0.0 assert bool(p) is True # p = ffi.new("float*", 1.1) f = p[0] assert f != 1.1 # because of rounding effect assert abs(f - 1.1) < 1E-7 # INF = 1E200 * 1E200 assert 1E200 != INF p[0] = 1E200 assert p[0] == INF # infinite, not enough precision def test_struct_simple(self): s = ffi.new("struct simple*") assert s.a == s.b == s.c == 0 s.b = -23 assert s.b == -23 py.test.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") assert repr(s) == "" % ( SIZE_OF_INT + 2 * SIZE_OF_SHORT) # py.test.raises(ValueError, ffi.new, "struct simple*", [1, 2, 3, 4]) def test_constructor_struct_from_dict(self): s = ffi.new("struct simple*", {'b': 123, 'c': 456}) assert s.a == 0 assert s.b == 123 assert s.c == 456 py.test.raises(KeyError, ffi.new, "struct simple*", {'d': 456}) def test_struct_pointer(self): s = ffi.new("struct simple*") assert s[0].a == s[0].b == s[0].c == 0 s[0].b = -23 assert s[0].b == s.b == -23 py.test.raises(OverflowError, "s[0].b = -32769") py.test.raises(IndexError, "s[1]") def test_struct_opaque(self): py.test.raises(ffi.error, ffi.new, "struct baz*") # should 'ffi.new("struct baz **") work? it used to, but it was # not particularly useful... py.test.raises(ffi.error, ffi.new, "struct baz**") def test_pointer_to_struct(self): s = ffi.new("struct simple *") s.a = -42 assert s[0].a == -42 p = ffi.new("struct simple **", s) assert p[0].a == -42 assert p[0][0].a == -42 p[0].a = -43 assert s.a == -43 assert s[0].a == -43 p[0][0].a = -44 assert s.a == -44 assert s[0].a == -44 s.a = -45 assert p[0].a == -45 assert p[0][0].a == -45 s[0].a = -46 assert p[0].a == -46 assert p[0][0].a == -46 def test_constructor_struct_of_array(self): s = ffi.new("struct array *", [[10, 11], [b'a', b'b', b'c']]) assert s.a[1] == 11 assert s.b[2] == b'c' s.b[1] = b'X' assert s.b[0] == b'a' assert s.b[1] == b'X' assert s.b[2] == b'c' def test_recursive_struct(self): s = ffi.new("struct recursive*") t = ffi.new("struct recursive*") s.value = 123 s.next = t t.value = 456 assert s.value == 123 assert s.next.value == 456 def test_union_simple(self): u = ffi.new("union simple_u*") assert u.a == u.b == u.c == 0 u.b = -23 assert u.b == -23 assert u.a != 0 py.test.raises(OverflowError, "u.b = 32768") # u = ffi.new("union simple_u*", [-2]) assert u.a == -2 py.test.raises((AttributeError, TypeError), "del u.a") assert repr(u) == "" % ( SIZE_OF_INT,) def test_union_opaque(self): py.test.raises(ffi.error, ffi.new, "union baz*") # should 'ffi.new("union baz **") work? it used to, but it was # not particularly useful... py.test.raises(ffi.error, ffi.new, "union baz**") def test_union_initializer(self): py.test.raises(TypeError, ffi.new, "union init_u*", b'A') py.test.raises(TypeError, ffi.new, "union init_u*", 5) py.test.raises(ValueError, ffi.new, "union init_u*", [b'A', 5]) u = ffi.new("union init_u*", [b'A']) assert u.a == b'A' py.test.raises(TypeError, ffi.new, "union init_u*", [1005]) u = ffi.new("union init_u*", {'b': 12345}) assert u.b == 12345 u = ffi.new("union init_u*", []) assert u.a == b'\x00' assert u.b == 0 def test_sizeof_type(self): for c_type, expected_size in [ ('char', 1), ('unsigned int', 4), ('char *', SIZE_OF_PTR), ('int[5]', 20), ('struct four_s', 12), ('union four_u', 4), ]: size = ffi.sizeof(c_type) assert size == expected_size, (size, expected_size, ctype) def test_sizeof_cdata(self): assert ffi.sizeof(ffi.new("short*")) == SIZE_OF_PTR assert ffi.sizeof(ffi.cast("short", 123)) == SIZE_OF_SHORT # a = ffi.new("int[]", [10, 11, 12, 13, 14]) assert len(a) == 5 assert ffi.sizeof(a) == 5 * SIZE_OF_INT def test_string_from_char_pointer(self): x = ffi.new("char*", b"x") assert str(x) == repr(x) assert ffi.string(x) == b"x" assert ffi.string(ffi.new("char*", b"\x00")) == b"" py.test.raises(TypeError, ffi.new, "char*", unicode("foo")) def test_unicode_from_wchar_pointer(self): self.check_wchar_t(ffi) x = ffi.new("wchar_t*", u+"x") assert unicode(x) == unicode(repr(x)) assert ffi.string(x) == u+"x" assert ffi.string(ffi.new("wchar_t*", u+"\x00")) == u+"" def test_string_from_char_array(self): p = ffi.new("char[]", b"hello.") p[5] = b'!' assert ffi.string(p) == b"hello!" p[6] = b'?' assert ffi.string(p) == b"hello!?" p[3] = b'\x00' assert ffi.string(p) == b"hel" assert ffi.string(p, 2) == b"he" py.test.raises(IndexError, "p[7] = b'X'") # a = ffi.new("char[]", b"hello\x00world") assert len(a) == 12 p = ffi.cast("char *", a) assert ffi.string(p) == b'hello' def test_string_from_wchar_array(self): self.check_wchar_t(ffi) assert ffi.string(ffi.cast("wchar_t", "x")) == u+"x" assert ffi.string(ffi.cast("wchar_t", u+"x")) == u+"x" x = ffi.cast("wchar_t", "x") assert str(x) == repr(x) assert ffi.string(x) == u+"x" # p = ffi.new("wchar_t[]", u+"hello.") p[5] = u+'!' assert ffi.string(p) == u+"hello!" p[6] = u+'\u04d2' assert ffi.string(p) == u+"hello!\u04d2" p[3] = u+'\x00' assert ffi.string(p) == u+"hel" assert ffi.string(p, 123) == u+"hel" py.test.raises(IndexError, "p[7] = u+'X'") # a = ffi.new("wchar_t[]", u+"hello\x00world") assert len(a) == 12 p = ffi.cast("wchar_t *", a) assert ffi.string(p) == u+'hello' assert ffi.string(p, 123) == u+'hello' assert ffi.string(p, 5) == u+'hello' assert ffi.string(p, 2) == u+'he' def test_fetch_const_char_p_field(self): # 'const' is ignored so far, in the declaration of 'struct string' t = ffi.new("const char[]", b"testing") s = ffi.new("struct string*", [t]) assert type(s.name) not in (bytes, str, unicode) assert ffi.string(s.name) == b"testing" py.test.raises(TypeError, "s.name = None") s.name = ffi.NULL assert s.name == ffi.NULL def test_fetch_const_wchar_p_field(self): # 'const' is ignored so far self.check_wchar_t(ffi) t = ffi.new("const wchar_t[]", u+"testing") s = ffi.new("struct ustring*", [t]) assert type(s.name) not in (bytes, str, unicode) assert ffi.string(s.name) == u+"testing" s.name = ffi.NULL assert s.name == ffi.NULL def test_voidp(self): py.test.raises(TypeError, ffi.new, "void*") p = ffi.new("void **") assert p[0] == ffi.NULL a = ffi.new("int[]", [10, 11, 12]) p = ffi.new("void **", a) vp = p[0] py.test.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 b = ffi.cast("int *", a) s.p = b # works s.q = b # works py.test.raises(TypeError, "s.r = b") # fails def test_functionptr_simple(self): py.test.raises(TypeError, ffi.callback, "int(*)(int)", 0) def cb(n): return n + 1 cb.__qualname__ = 'cb' p = ffi.callback("int(*)(int)", cb) res = p(41) # calling an 'int(*)(int)', i.e. a function pointer assert res == 42 and type(res) is int res = p(ffi.cast("int", -41)) assert res == -40 and type(res) is int assert repr(p).startswith( "" % ( SIZE_OF_PTR) py.test.raises(TypeError, "q(43)") res = q[0](43) assert res == 44 q = ffi.cast("int(*)(int)", p) assert repr(q).startswith("" % "int(*(*)(int))(int)" def test_functionptr_voidptr_return(self): def cb(): return ffi.NULL p = ffi.callback("void*(*)()", cb) res = p() assert res is not None assert res == ffi.NULL int_ptr = ffi.new('int*') void_ptr = ffi.cast('void*', int_ptr) def cb(): return void_ptr p = ffi.callback("void*(*)()", cb) res = p() assert res == void_ptr def test_functionptr_intptr_return(self): def cb(): return ffi.NULL p = ffi.callback("int*(*)()", cb) res = p() assert res == ffi.NULL int_ptr = ffi.new('int*') def cb(): return int_ptr p = ffi.callback("int*(*)()", cb) res = p() assert repr(res).startswith("" assert repr(ffi.cast("enum foq", -1)) == ( # enums are unsigned, if "") or ( # they contain no neg value sys.platform == "win32") # (but not on msvc) # enum baz { A2=0x1000, B2=0x2000 }; assert ffi.string(ffi.cast("enum baz", 0x1000)) == "A2" assert ffi.string(ffi.cast("enum baz", 0x2000)) == "B2" def test_enum_in_struct(self): # enum foo2 { A3, B3, C3, D3 }; # struct bar_with_e { enum foo2 e; }; s = ffi.new("struct bar_with_e *") s.e = 0 assert s.e == 0 s.e = 3 assert s.e == 3 assert s[0].e == 3 s[0].e = 2 assert s.e == 2 assert s[0].e == 2 s.e = ffi.cast("enum foo2", -1) assert s.e in (4294967295, -1) # two choices assert s[0].e in (4294967295, -1) s.e = s.e 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'") def test_enum_non_contiguous(self): # enum noncont { A4, B4=42, C4 }; assert ffi.string(ffi.cast("enum noncont", 0)) == "A4" assert ffi.string(ffi.cast("enum noncont", 42)) == "B4" assert ffi.string(ffi.cast("enum noncont", 43)) == "C4" invalid_value = ffi.cast("enum noncont", 2) assert int(invalid_value) == 2 assert ffi.string(invalid_value) == "2" def test_enum_char_hex_oct(self): # enum etypes {A5='!', B5='\'', C5=0x10, D5=010, E5=- 0x10, F5=-010}; assert ffi.string(ffi.cast("enum etypes", ord('!'))) == "A5" assert ffi.string(ffi.cast("enum etypes", ord("'"))) == "B5" assert ffi.string(ffi.cast("enum etypes", 16)) == "C5" assert ffi.string(ffi.cast("enum etypes", 8)) == "D5" assert ffi.string(ffi.cast("enum etypes", -16)) == "E5" assert ffi.string(ffi.cast("enum etypes", -8)) == "F5" def test_array_of_struct(self): s = ffi.new("struct ab[1]") py.test.raises(AttributeError, 's.b') py.test.raises(AttributeError, 's.b = 412') s[0].b = 412 assert s[0].b == 412 py.test.raises(IndexError, 's[1]') def test_pointer_to_array(self): p = ffi.new("int(**)[5]") assert repr(p) == "" % SIZE_OF_PTR def test_iterate_array(self): a = ffi.new("char[]", b"hello") assert list(a) == [b"h", b"e", b"l", b"l", b"o", b"\0"] assert list(iter(a)) == [b"h", b"e", b"l", b"l", b"o", b"\0"] # py.test.raises(TypeError, iter, ffi.cast("char *", a)) py.test.raises(TypeError, list, ffi.cast("char *", a)) py.test.raises(TypeError, iter, ffi.new("int *")) py.test.raises(TypeError, list, ffi.new("int *")) def test_offsetof(self): # struct abc { int a, b, c; }; assert ffi.offsetof("struct abc", "a") == 0 assert ffi.offsetof("struct abc", "b") == 4 assert ffi.offsetof("struct abc", "c") == 8 def test_offsetof_nested(self): # struct nesting { struct abc d, e; }; assert ffi.offsetof("struct nesting", "e") == 12 py.test.raises(KeyError, ffi.offsetof, "struct nesting", "e.a") assert ffi.offsetof("struct nesting", "e", "a") == 12 assert ffi.offsetof("struct nesting", "e", "b") == 16 assert ffi.offsetof("struct nesting", "e", "c") == 20 def test_offsetof_array(self): assert ffi.offsetof("int[]", 51) == 51 * ffi.sizeof("int") assert ffi.offsetof("int *", 51) == 51 * ffi.sizeof("int") # struct array2 { int a, b; int c[99]; }; assert ffi.offsetof("struct array2", "c") == 2 * ffi.sizeof("int") assert ffi.offsetof("struct array2", "c", 0) == 2 * ffi.sizeof("int") assert ffi.offsetof("struct array2", "c", 51) == 53 * ffi.sizeof("int") def test_alignof(self): # struct align { char a; short b; char c; }; assert ffi.alignof("int") == 4 assert ffi.alignof("double") in (4, 8) assert ffi.alignof("struct align") == 2 def test_bitfield(self): # struct bitfield { int a:10, b:20, c:3; }; assert ffi.sizeof("struct bitfield") == 8 s = ffi.new("struct bitfield *") s.a = 511 py.test.raises(OverflowError, "s.a = 512") py.test.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") 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") s.c = -4 assert s.c == -4 def test_bitfield_enum(self): # typedef enum { AA1, BB1, CC1 } foo_e_t; # typedef struct { foo_e_t f:2; } bfenum_t; if sys.platform == "win32": py.test.skip("enums are not unsigned") s = ffi.new("bfenum_t *") s.f = 2 assert s.f == 2 def test_anonymous_struct(self): # typedef struct { int a; } anon_foo_t; # typedef struct { char b, c; } anon_bar_t; f = ffi.new("anon_foo_t *", [12345]) b = ffi.new("anon_bar_t *", [b"B", b"C"]) assert f.a == 12345 assert b.b == b"B" assert b.c == b"C" assert repr(b).startswith(" s) is False assert (p >= s) is True assert (s < p) is False assert (s <= p) is True assert (s == p) is True assert (s != p) is False assert (s > p) is False assert (s >= p) is True q = p + 1 assert (q < s) is False assert (q <= s) is False assert (q == s) is False assert (q != s) is True assert (q > s) is True assert (q >= s) is True assert (s < q) is True assert (s <= q) is True assert (s == q) is False assert (s != q) is True assert (s > q) is False assert (s >= q) is False assert (q < p) is False assert (q <= p) is False assert (q == p) is False assert (q != p) is True assert (q > p) is True assert (q >= p) is True assert (p < q) is True assert (p <= q) is True assert (p == q) is False assert (p != q) is True assert (p > q) is False assert (p >= q) is False # assert (None == s) is False assert (None != s) is True assert (s == None) is False assert (s != None) is True assert (None == q) is False assert (None != q) is True assert (q == None) is False assert (q != None) is True def test_integer_comparison(self): x = ffi.cast("int", 123) y = ffi.cast("int", 456) assert x < y # z = ffi.cast("double", 78.9) assert x > z assert y > z def test_ffi_buffer_ptr(self): a = ffi.new("short *", 100) try: b = ffi.buffer(a) except NotImplementedError as e: py.test.skip(str(e)) content = b[:] assert len(content) == len(b) == 2 if sys.byteorder == 'little': assert content == b'\x64\x00' assert b[0] == b'\x64' b[0] = b'\x65' else: assert content == b'\x00\x64' assert b[1] == b'\x64' b[1] = b'\x65' assert a[0] == 101 def test_ffi_buffer_array(self): a = ffi.new("int[]", list(range(100, 110))) try: b = ffi.buffer(a) except NotImplementedError as e: py.test.skip(str(e)) content = b[:] if sys.byteorder == 'little': assert content.startswith(b'\x64\x00\x00\x00\x65\x00\x00\x00') b[4] = b'\x45' else: assert content.startswith(b'\x00\x00\x00\x64\x00\x00\x00\x65') b[7] = b'\x45' assert len(content) == 4 * 10 assert a[1] == 0x45 def test_ffi_buffer_ptr_size(self): a = ffi.new("short *", 0x4243) try: b = ffi.buffer(a, 1) except NotImplementedError as e: py.test.skip(str(e)) content = b[:] assert len(content) == 1 if sys.byteorder == 'little': assert content == b'\x43' b[0] = b'\x62' assert a[0] == 0x4262 else: assert content == b'\x42' b[0] = b'\x63' assert a[0] == 0x6343 def test_ffi_buffer_array_size(self): a1 = ffi.new("int[]", list(range(100, 110))) a2 = ffi.new("int[]", list(range(100, 115))) try: ffi.buffer(a1) except NotImplementedError as e: py.test.skip(str(e)) assert ffi.buffer(a1)[:] == ffi.buffer(a2, 4*10)[:] def test_ffi_buffer_with_file(self): import tempfile, os, array fd, filename = tempfile.mkstemp() f = os.fdopen(fd, 'r+b') a = ffi.new("int[]", list(range(1005))) try: ffi.buffer(a, 512) except NotImplementedError as e: py.test.skip(str(e)) f.write(ffi.buffer(a, 1000 * ffi.sizeof("int"))) f.seek(0) assert f.read() == array.array('i', range(1000)).tostring() f.seek(0) b = ffi.new("int[]", 1005) f.readinto(ffi.buffer(b, 1000 * ffi.sizeof("int"))) assert list(a)[:1000] + [0] * (len(a)-1000) == list(b) f.close() os.unlink(filename) def test_ffi_buffer_with_io(self): import io, array f = io.BytesIO() a = ffi.new("int[]", list(range(1005))) try: ffi.buffer(a, 512) except NotImplementedError as e: py.test.skip(str(e)) f.write(ffi.buffer(a, 1000 * ffi.sizeof("int"))) f.seek(0) assert f.read() == array.array('i', range(1000)).tostring() f.seek(0) b = ffi.new("int[]", 1005) f.readinto(ffi.buffer(b, 1000 * ffi.sizeof("int"))) assert list(a)[:1000] + [0] * (len(a)-1000) == list(b) f.close() def test_array_in_struct(self): # struct array { int a[2]; char b[3]; }; p = ffi.new("struct array *") p.a[1] = 5 assert p.a[1] == 5 assert repr(p.a).startswith("