|
|
@@ -12,9 +12,9 @@ from _cffi_backend import _testfunc, _get_types, _get_common_types, __version__
|
|
|
# ____________________________________________________________
|
|
|
|
|
|
import sys
|
|
|
-assert __version__ == "1.5.2", ("This test_c.py file is for testing a version"
|
|
|
- " of cffi that differs from the one that we"
|
|
|
- " get from 'import _cffi_backend'")
|
|
|
+assert __version__ == "1.11.5", ("This test_c.py file is for testing a version"
|
|
|
+ " of cffi that differs from the one that we"
|
|
|
+ " get from 'import _cffi_backend'")
|
|
|
if sys.version_info < (3,):
|
|
|
type_or_class = "type"
|
|
|
mandatory_b_prefix = ''
|
|
|
@@ -27,6 +27,7 @@ if sys.version_info < (3,):
|
|
|
.replace(r'\\U', r'\U'))
|
|
|
u = U()
|
|
|
str2bytes = str
|
|
|
+ strict_compare = False
|
|
|
else:
|
|
|
type_or_class = "class"
|
|
|
long = int
|
|
|
@@ -38,6 +39,7 @@ else:
|
|
|
bitem2bchr = bytechr
|
|
|
u = ""
|
|
|
str2bytes = lambda s: bytes(s, "ascii")
|
|
|
+ strict_compare = True
|
|
|
|
|
|
def size_of_int():
|
|
|
BInt = new_primitive_type("int")
|
|
|
@@ -59,6 +61,10 @@ def find_and_load_library(name, flags=RTLD_NOW):
|
|
|
path = None
|
|
|
else:
|
|
|
path = ctypes.util.find_library(name)
|
|
|
+ if path is None and name == 'c':
|
|
|
+ assert sys.platform == 'win32'
|
|
|
+ assert sys.version_info >= (3,)
|
|
|
+ py.test.skip("dlopen(None) cannot work on Windows with Python 3")
|
|
|
return load_library(path, flags)
|
|
|
|
|
|
def test_load_library():
|
|
|
@@ -88,8 +94,8 @@ def test_new_primitive_type():
|
|
|
assert repr(p) == "<ctype 'signed char'>"
|
|
|
|
|
|
def check_dir(p, expected):
|
|
|
- got = set(name for name in dir(p) if not name.startswith('_'))
|
|
|
- assert got == set(expected)
|
|
|
+ got = [name for name in dir(p) if not name.startswith('_')]
|
|
|
+ assert got == sorted(expected)
|
|
|
|
|
|
def test_inspect_primitive_type():
|
|
|
p = new_primitive_type("signed char")
|
|
|
@@ -106,11 +112,11 @@ def test_cast_to_signed_char():
|
|
|
x = cast(p, -66 + (1<<199)*256)
|
|
|
assert repr(x) == "<cdata 'signed char' -66>"
|
|
|
assert int(x) == -66
|
|
|
- assert (x == cast(p, -66)) is False
|
|
|
- assert (x != cast(p, -66)) is True
|
|
|
+ assert (x == cast(p, -66)) is True
|
|
|
+ assert (x != cast(p, -66)) is False
|
|
|
q = new_primitive_type("short")
|
|
|
- assert (x == cast(q, -66)) is False
|
|
|
- assert (x != cast(q, -66)) is True
|
|
|
+ assert (x == cast(q, -66)) is True
|
|
|
+ assert (x != cast(q, -66)) is False
|
|
|
|
|
|
def test_sizeof_type():
|
|
|
py.test.raises(TypeError, sizeof, 42.5)
|
|
|
@@ -152,9 +158,13 @@ def test_float_types():
|
|
|
INF = 1E200 * 1E200
|
|
|
for name in ["float", "double"]:
|
|
|
p = new_primitive_type(name)
|
|
|
- assert bool(cast(p, 0))
|
|
|
+ assert bool(cast(p, 0)) is False # since 1.7
|
|
|
+ assert bool(cast(p, -0.0)) is False # since 1.7
|
|
|
+ assert bool(cast(p, 1e-42)) is True
|
|
|
+ assert bool(cast(p, -1e-42)) is True
|
|
|
assert bool(cast(p, INF))
|
|
|
assert bool(cast(p, -INF))
|
|
|
+ assert bool(cast(p, float("nan")))
|
|
|
assert int(cast(p, -150)) == -150
|
|
|
assert int(cast(p, 61.91)) == 61
|
|
|
assert long(cast(p, 61.91)) == 61
|
|
|
@@ -171,7 +181,7 @@ def test_float_types():
|
|
|
assert float(cast(p, 1.1)) != 1.1 # rounding error
|
|
|
assert float(cast(p, 1E200)) == INF # limited range
|
|
|
|
|
|
- assert cast(p, -1.1) != cast(p, -1.1)
|
|
|
+ assert cast(p, -1.1) == cast(p, -1.1)
|
|
|
assert repr(float(cast(p, -0.0))) == '-0.0'
|
|
|
assert float(cast(p, b'\x09')) == 9.0
|
|
|
assert float(cast(p, u+'\x09')) == 9.0
|
|
|
@@ -179,42 +189,62 @@ def test_float_types():
|
|
|
py.test.raises(TypeError, cast, p, None)
|
|
|
|
|
|
def test_complex_types():
|
|
|
- py.test.skip("later")
|
|
|
INF = 1E200 * 1E200
|
|
|
for name in ["float", "double"]:
|
|
|
- p = new_primitive_type("_Complex " + name)
|
|
|
- assert bool(cast(p, 0))
|
|
|
+ p = new_primitive_type(name + " _Complex")
|
|
|
+ assert bool(cast(p, 0)) is False
|
|
|
assert bool(cast(p, INF))
|
|
|
assert bool(cast(p, -INF))
|
|
|
- assert bool(cast(p, 0j))
|
|
|
+ assert bool(cast(p, 0j)) is False
|
|
|
assert bool(cast(p, INF*1j))
|
|
|
assert bool(cast(p, -INF*1j))
|
|
|
+ # "can't convert complex to float", like CPython's "float(0j)"
|
|
|
py.test.raises(TypeError, int, cast(p, -150))
|
|
|
py.test.raises(TypeError, long, cast(p, -150))
|
|
|
py.test.raises(TypeError, float, cast(p, -150))
|
|
|
assert complex(cast(p, 1.25)) == 1.25
|
|
|
assert complex(cast(p, 1.25j)) == 1.25j
|
|
|
- assert float(cast(p, INF*1j)) == INF*1j
|
|
|
- assert float(cast(p, -INF)) == -INF
|
|
|
+ assert complex(cast(p, complex(0,INF))) == complex(0,INF)
|
|
|
+ assert complex(cast(p, -INF)) == -INF
|
|
|
if name == "float":
|
|
|
assert complex(cast(p, 1.1j)) != 1.1j # rounding error
|
|
|
assert complex(cast(p, 1E200+3j)) == INF+3j # limited range
|
|
|
- assert complex(cast(p, 3+1E200j)) == 3+INF*1j # limited range
|
|
|
+ assert complex(cast(p, complex(3,1E200))) == complex(3,INF) # limited range
|
|
|
|
|
|
- assert cast(p, -1.1j) != cast(p, -1.1j)
|
|
|
+ assert cast(p, -1.1j) == cast(p, -1.1j)
|
|
|
assert repr(complex(cast(p, -0.0)).real) == '-0.0'
|
|
|
- assert repr(complex(cast(p, -0j))) == '-0j'
|
|
|
- assert complex(cast(p, '\x09')) == 9.0
|
|
|
- assert complex(cast(p, True)) == 1.0
|
|
|
+ #assert repr(complex(cast(p, -0j))) == '-0j' # http://bugs.python.org/issue29602
|
|
|
+ assert complex(cast(p, b'\x09')) == 9.0 + 0j
|
|
|
+ assert complex(cast(p, u+'\x09')) == 9.0 + 0j
|
|
|
+ assert complex(cast(p, True)) == 1.0 + 0j
|
|
|
py.test.raises(TypeError, cast, p, None)
|
|
|
#
|
|
|
- py.test.raises(cast, new_primitive_type(name), 1+2j)
|
|
|
- py.test.raises(cast, new_primitive_type("int"), 1+2j)
|
|
|
+ py.test.raises(TypeError, cast, new_primitive_type(name), 1+0j)
|
|
|
+ #
|
|
|
+ for basetype in ["char", "int", "uint64_t", "float",
|
|
|
+ "double", "long double"]:
|
|
|
+ baseobj = cast(new_primitive_type(basetype), 65)
|
|
|
+ py.test.raises(TypeError, complex, baseobj)
|
|
|
+ #
|
|
|
+ BArray = new_array_type(new_pointer_type(p), 10)
|
|
|
+ x = newp(BArray, None)
|
|
|
+ x[5] = 12.34 + 56.78j
|
|
|
+ assert type(x[5]) is complex
|
|
|
+ assert abs(x[5] - (12.34 + 56.78j)) < 1e-5
|
|
|
+ assert (x[5] == 12.34 + 56.78j) == (name == "double") # rounding error
|
|
|
+ #
|
|
|
+ class Foo:
|
|
|
+ def __complex__(self):
|
|
|
+ return 2 + 3j
|
|
|
+ assert complex(Foo()) == 2 + 3j
|
|
|
+ assert complex(cast(p, Foo())) == 2 + 3j
|
|
|
+ py.test.raises(TypeError, cast, new_primitive_type("int"), 1+0j)
|
|
|
|
|
|
def test_character_type():
|
|
|
p = new_primitive_type("char")
|
|
|
- assert bool(cast(p, '\x00'))
|
|
|
- assert cast(p, '\x00') != cast(p, -17*256)
|
|
|
+ assert bool(cast(p, 'A')) is True
|
|
|
+ assert bool(cast(p, '\x00')) is False # since 1.7
|
|
|
+ assert cast(p, '\x00') == cast(p, -17*256)
|
|
|
assert int(cast(p, 'A')) == 65
|
|
|
assert long(cast(p, 'A')) == 65
|
|
|
assert type(int(cast(p, 'A'))) is int
|
|
|
@@ -371,29 +401,12 @@ def test_load_standard_library():
|
|
|
x = find_and_load_library(None)
|
|
|
BVoidP = new_pointer_type(new_void_type())
|
|
|
assert x.load_function(BVoidP, 'strcpy')
|
|
|
- py.test.raises(KeyError, x.load_function,
|
|
|
+ py.test.raises(AttributeError, x.load_function,
|
|
|
BVoidP, 'xxx_this_function_does_not_exist')
|
|
|
# the next one is from 'libm', not 'libc', but we assume
|
|
|
# that it is already loaded too, so it should work
|
|
|
assert x.load_function(BVoidP, 'sqrt')
|
|
|
|
|
|
-def test_hash_differences():
|
|
|
- BChar = new_primitive_type("char")
|
|
|
- BInt = new_primitive_type("int")
|
|
|
- BFloat = new_primitive_type("float")
|
|
|
- for i in range(1, 20):
|
|
|
- x1 = cast(BChar, chr(i))
|
|
|
- x2 = cast(BInt, i)
|
|
|
- if hash(x1) != hash(x2):
|
|
|
- break
|
|
|
- else:
|
|
|
- raise AssertionError("hashes are equal")
|
|
|
- for i in range(1, 20):
|
|
|
- if hash(cast(BFloat, i)) != hash(float(i)):
|
|
|
- break
|
|
|
- else:
|
|
|
- raise AssertionError("hashes are equal")
|
|
|
-
|
|
|
def test_no_len_on_nonarray():
|
|
|
p = new_primitive_type("int")
|
|
|
py.test.raises(TypeError, len, cast(p, 42))
|
|
|
@@ -582,6 +595,19 @@ def test_array_sub():
|
|
|
e = py.test.raises(TypeError, "q - a")
|
|
|
assert str(e.value) == "cannot subtract cdata 'short *' and cdata 'int *'"
|
|
|
|
|
|
+def test_ptr_sub_unaligned():
|
|
|
+ BInt = new_primitive_type("int")
|
|
|
+ BIntPtr = new_pointer_type(BInt)
|
|
|
+ a = cast(BIntPtr, 1240)
|
|
|
+ for bi in range(1430, 1438):
|
|
|
+ b = cast(BIntPtr, bi)
|
|
|
+ if ((bi - 1240) % size_of_int()) == 0:
|
|
|
+ assert b - a == (bi - 1240) // size_of_int()
|
|
|
+ assert a - b == (1240 - bi) // size_of_int()
|
|
|
+ else:
|
|
|
+ py.test.raises(ValueError, "b - a")
|
|
|
+ py.test.raises(ValueError, "a - b")
|
|
|
+
|
|
|
def test_cast_primitive_from_cdata():
|
|
|
p = new_primitive_type("int")
|
|
|
n = cast(p, cast(p, -42))
|
|
|
@@ -730,8 +756,14 @@ def test_struct_instance():
|
|
|
BInt = new_primitive_type("int")
|
|
|
BStruct = new_struct_type("struct foo")
|
|
|
BStructPtr = new_pointer_type(BStruct)
|
|
|
- p = cast(BStructPtr, 0)
|
|
|
- py.test.raises(AttributeError, "p.a1") # opaque
|
|
|
+ p = cast(BStructPtr, 42)
|
|
|
+ e = py.test.raises(AttributeError, "p.a1") # opaque
|
|
|
+ assert str(e.value) == ("cdata 'struct foo *' points to an opaque type: "
|
|
|
+ "cannot read fields")
|
|
|
+ e = py.test.raises(AttributeError, "p.a1 = 10") # opaque
|
|
|
+ assert str(e.value) == ("cdata 'struct foo *' points to an opaque type: "
|
|
|
+ "cannot write fields")
|
|
|
+
|
|
|
complete_struct_or_union(BStruct, [('a1', BInt, -1),
|
|
|
('a2', BInt, -1)])
|
|
|
p = newp(BStructPtr, None)
|
|
|
@@ -742,8 +774,29 @@ def test_struct_instance():
|
|
|
assert s.a2 == 123
|
|
|
py.test.raises(OverflowError, "s.a1 = sys.maxsize+1")
|
|
|
assert s.a1 == 0
|
|
|
- py.test.raises(AttributeError, "p.foobar")
|
|
|
- py.test.raises(AttributeError, "s.foobar")
|
|
|
+ e = py.test.raises(AttributeError, "p.foobar")
|
|
|
+ assert str(e.value) == "cdata 'struct foo *' has no field 'foobar'"
|
|
|
+ e = py.test.raises(AttributeError, "p.foobar = 42")
|
|
|
+ assert str(e.value) == "cdata 'struct foo *' has no field 'foobar'"
|
|
|
+ e = py.test.raises(AttributeError, "s.foobar")
|
|
|
+ assert str(e.value) == "cdata 'struct foo' has no field 'foobar'"
|
|
|
+ e = py.test.raises(AttributeError, "s.foobar = 42")
|
|
|
+ assert str(e.value) == "cdata 'struct foo' has no field 'foobar'"
|
|
|
+ j = cast(BInt, 42)
|
|
|
+ e = py.test.raises(AttributeError, "j.foobar")
|
|
|
+ assert str(e.value) == "cdata 'int' has no attribute 'foobar'"
|
|
|
+ e = py.test.raises(AttributeError, "j.foobar = 42")
|
|
|
+ assert str(e.value) == "cdata 'int' has no attribute 'foobar'"
|
|
|
+ j = cast(new_pointer_type(BInt), 42)
|
|
|
+ e = py.test.raises(AttributeError, "j.foobar")
|
|
|
+ assert str(e.value) == "cdata 'int *' has no attribute 'foobar'"
|
|
|
+ e = py.test.raises(AttributeError, "j.foobar = 42")
|
|
|
+ assert str(e.value) == "cdata 'int *' has no attribute 'foobar'"
|
|
|
+ pp = newp(new_pointer_type(BStructPtr), p)
|
|
|
+ e = py.test.raises(AttributeError, "pp.a1")
|
|
|
+ assert str(e.value) == "cdata 'struct foo * *' has no attribute 'a1'"
|
|
|
+ e = py.test.raises(AttributeError, "pp.a1 = 42")
|
|
|
+ assert str(e.value) == "cdata 'struct foo * *' has no attribute 'a1'"
|
|
|
|
|
|
def test_union_instance():
|
|
|
BInt = new_primitive_type("int")
|
|
|
@@ -878,6 +931,15 @@ def test_call_function_0():
|
|
|
py.test.raises(OverflowError, f, 128, 0)
|
|
|
py.test.raises(OverflowError, f, 0, 128)
|
|
|
|
|
|
+def test_call_function_0_pretend_bool_result():
|
|
|
+ BSignedChar = new_primitive_type("signed char")
|
|
|
+ BBool = new_primitive_type("_Bool")
|
|
|
+ BFunc0 = new_function_type((BSignedChar, BSignedChar), BBool, False)
|
|
|
+ f = cast(BFunc0, _testfunc(0))
|
|
|
+ assert f(40, -39) is True
|
|
|
+ assert f(40, -40) is False
|
|
|
+ py.test.raises(ValueError, f, 40, 2)
|
|
|
+
|
|
|
def test_call_function_1():
|
|
|
BInt = new_primitive_type("int")
|
|
|
BLong = new_primitive_type("long")
|
|
|
@@ -1040,6 +1102,17 @@ def test_call_function_23_bis():
|
|
|
res = f(b"foo")
|
|
|
assert res == 1000 * ord(b'f')
|
|
|
|
|
|
+def test_call_function_23_bool_array():
|
|
|
+ # declaring the function as int(_Bool*)
|
|
|
+ BBool = new_primitive_type("_Bool")
|
|
|
+ BBoolP = new_pointer_type(BBool)
|
|
|
+ BInt = new_primitive_type("int")
|
|
|
+ BFunc23 = new_function_type((BBoolP,), BInt, False)
|
|
|
+ f = cast(BFunc23, _testfunc(23))
|
|
|
+ res = f(b"\x01\x01")
|
|
|
+ assert res == 1000
|
|
|
+ py.test.raises(ValueError, f, b"\x02\x02")
|
|
|
+
|
|
|
def test_cannot_pass_struct_with_array_of_length_0():
|
|
|
BInt = new_primitive_type("int")
|
|
|
BArray0 = new_array_type(new_pointer_type(BInt), 0)
|
|
|
@@ -1066,6 +1139,34 @@ def test_call_function_9():
|
|
|
BSShort = new_primitive_type("short")
|
|
|
assert f(3, cast(BSChar, -3), cast(BUChar, 200), cast(BSShort, -5)) == 192
|
|
|
|
|
|
+def test_call_function_24():
|
|
|
+ BFloat = new_primitive_type("float")
|
|
|
+ BFloatComplex = new_primitive_type("float _Complex")
|
|
|
+ BFunc3 = new_function_type((BFloat, BFloat), BFloatComplex, False)
|
|
|
+ if 0: # libffi returning nonsense silently, so logic disabled for now
|
|
|
+ f = cast(BFunc3, _testfunc(24))
|
|
|
+ result = f(1.25, 5.1)
|
|
|
+ assert type(result) == complex
|
|
|
+ assert result.real == 1.25 # exact
|
|
|
+ assert (result.imag != 2*5.1) and (abs(result.imag - 2*5.1) < 1e-5) # inexact
|
|
|
+ else:
|
|
|
+ f = cast(BFunc3, _testfunc(9))
|
|
|
+ py.test.raises(NotImplementedError, f, 12.3, 34.5)
|
|
|
+
|
|
|
+def test_call_function_25():
|
|
|
+ BDouble = new_primitive_type("double")
|
|
|
+ BDoubleComplex = new_primitive_type("double _Complex")
|
|
|
+ BFunc3 = new_function_type((BDouble, BDouble), BDoubleComplex, False)
|
|
|
+ if 0: # libffi returning nonsense silently, so logic disabled for now
|
|
|
+ f = cast(BFunc3, _testfunc(25))
|
|
|
+ result = f(1.25, 5.1)
|
|
|
+ assert type(result) == complex
|
|
|
+ assert result.real == 1.25 # exact
|
|
|
+ assert (result.imag != 2*5.1) and (abs(result.imag - 2*5.1) < 1e-10) # inexact
|
|
|
+ else:
|
|
|
+ f = cast(BFunc3, _testfunc(9))
|
|
|
+ py.test.raises(NotImplementedError, f, 12.3, 34.5)
|
|
|
+
|
|
|
def test_cannot_call_with_a_autocompleted_struct():
|
|
|
BSChar = new_primitive_type("signed char")
|
|
|
BDouble = new_primitive_type("double")
|
|
|
@@ -1077,9 +1178,13 @@ def test_cannot_call_with_a_autocompleted_struct():
|
|
|
BFunc = new_function_type((BStruct,), BDouble) # internally not callable
|
|
|
dummy_func = cast(BFunc, 42)
|
|
|
e = py.test.raises(NotImplementedError, dummy_func, "?")
|
|
|
- msg = ("ctype \'struct foo\' not supported as argument (it is a struct "
|
|
|
- 'declared with "...;", but the C calling convention may depend on '
|
|
|
- 'the missing fields)')
|
|
|
+ msg = ("ctype 'struct foo' not supported as argument. It is a struct "
|
|
|
+ 'declared with "...;", but the C calling convention may depend '
|
|
|
+ "on the missing fields; or, it contains anonymous struct/unions. "
|
|
|
+ "Such structs are only supported as argument if the function is "
|
|
|
+ "'API mode' and non-variadic (i.e. declared inside ffibuilder."
|
|
|
+ "cdef()+ffibuilder.set_source() and not taking a final '...' "
|
|
|
+ "argument)")
|
|
|
assert str(e.value) == msg
|
|
|
|
|
|
def test_new_charp():
|
|
|
@@ -1835,7 +1940,11 @@ def test_string_byte():
|
|
|
assert string(a, 8).startswith(b'ABC') # may contain additional garbage
|
|
|
|
|
|
def test_string_wchar():
|
|
|
- BWChar = new_primitive_type("wchar_t")
|
|
|
+ for typename in ["wchar_t", "char16_t", "char32_t"]:
|
|
|
+ _test_string_wchar_variant(typename)
|
|
|
+
|
|
|
+def _test_string_wchar_variant(typename):
|
|
|
+ BWChar = new_primitive_type(typename)
|
|
|
assert string(cast(BWChar, 42)) == u+'*'
|
|
|
assert string(cast(BWChar, 0x4253)) == u+'\u4253'
|
|
|
assert string(cast(BWChar, 0)) == u+'\x00'
|
|
|
@@ -1997,22 +2106,45 @@ def test_cast_with_functionptr():
|
|
|
py.test.raises(TypeError, newp, BStructPtr, [cast(BFunc2, 0)])
|
|
|
|
|
|
def test_wchar():
|
|
|
- BWChar = new_primitive_type("wchar_t")
|
|
|
+ _test_wchar_variant("wchar_t")
|
|
|
+ if sys.platform.startswith("linux"):
|
|
|
+ BWChar = new_primitive_type("wchar_t")
|
|
|
+ assert sizeof(BWChar) == 4
|
|
|
+ # wchar_t is often signed on Linux, but not always (e.g. on ARM)
|
|
|
+ assert int(cast(BWChar, -1)) in (-1, 4294967295)
|
|
|
+
|
|
|
+def test_char16():
|
|
|
+ BChar16 = new_primitive_type("char16_t")
|
|
|
+ assert sizeof(BChar16) == 2
|
|
|
+ _test_wchar_variant("char16_t")
|
|
|
+ assert int(cast(BChar16, -1)) == 0xffff # always unsigned
|
|
|
+
|
|
|
+def test_char32():
|
|
|
+ BChar32 = new_primitive_type("char32_t")
|
|
|
+ assert sizeof(BChar32) == 4
|
|
|
+ _test_wchar_variant("char32_t")
|
|
|
+ assert int(cast(BChar32, -1)) == 0xffffffff # always unsigned
|
|
|
+
|
|
|
+def _test_wchar_variant(typename):
|
|
|
+ BWChar = new_primitive_type(typename)
|
|
|
BInt = new_primitive_type("int")
|
|
|
pyuni4 = {1: True, 2: False}[len(u+'\U00012345')]
|
|
|
wchar4 = {2: False, 4: True}[sizeof(BWChar)]
|
|
|
- assert str(cast(BWChar, 0x45)) == "<cdata 'wchar_t' %s'E'>" % (
|
|
|
- mandatory_u_prefix,)
|
|
|
- assert str(cast(BWChar, 0x1234)) == "<cdata 'wchar_t' %s'\u1234'>" % (
|
|
|
- mandatory_u_prefix,)
|
|
|
- if wchar4:
|
|
|
- if not _hacked_pypy_uni4():
|
|
|
+ assert str(cast(BWChar, 0x45)) == "<cdata '%s' %s'E'>" % (
|
|
|
+ typename, mandatory_u_prefix)
|
|
|
+ assert str(cast(BWChar, 0x1234)) == "<cdata '%s' %s'\u1234'>" % (
|
|
|
+ typename, mandatory_u_prefix)
|
|
|
+ if not _hacked_pypy_uni4():
|
|
|
+ if wchar4:
|
|
|
x = cast(BWChar, 0x12345)
|
|
|
- assert str(x) == "<cdata 'wchar_t' %s'\U00012345'>" % (
|
|
|
- mandatory_u_prefix,)
|
|
|
+ assert str(x) == "<cdata '%s' %s'\U00012345'>" % (
|
|
|
+ typename, mandatory_u_prefix)
|
|
|
assert int(x) == 0x12345
|
|
|
- else:
|
|
|
- assert not pyuni4
|
|
|
+ else:
|
|
|
+ x = cast(BWChar, 0x18345)
|
|
|
+ assert str(x) == "<cdata '%s' %s'\u8345'>" % (
|
|
|
+ typename, mandatory_u_prefix)
|
|
|
+ assert int(x) == 0x8345
|
|
|
#
|
|
|
BWCharP = new_pointer_type(BWChar)
|
|
|
BStruct = new_struct_type("struct foo_s")
|
|
|
@@ -2027,9 +2159,9 @@ def test_wchar():
|
|
|
s.a1 = u+'\u1234'
|
|
|
assert s.a1 == u+'\u1234'
|
|
|
if pyuni4:
|
|
|
- assert wchar4
|
|
|
- s.a1 = u+'\U00012345'
|
|
|
- assert s.a1 == u+'\U00012345'
|
|
|
+ if wchar4:
|
|
|
+ s.a1 = u+'\U00012345'
|
|
|
+ assert s.a1 == u+'\U00012345'
|
|
|
elif wchar4:
|
|
|
if not _hacked_pypy_uni4():
|
|
|
s.a1 = cast(BWChar, 0x12345)
|
|
|
@@ -2064,17 +2196,17 @@ def test_wchar():
|
|
|
py.test.raises(IndexError, 'a[4]')
|
|
|
#
|
|
|
w = cast(BWChar, 'a')
|
|
|
- assert repr(w) == "<cdata 'wchar_t' %s'a'>" % mandatory_u_prefix
|
|
|
+ assert repr(w) == "<cdata '%s' %s'a'>" % (typename, mandatory_u_prefix)
|
|
|
assert str(w) == repr(w)
|
|
|
assert string(w) == u+'a'
|
|
|
assert int(w) == ord('a')
|
|
|
w = cast(BWChar, 0x1234)
|
|
|
- assert repr(w) == "<cdata 'wchar_t' %s'\u1234'>" % mandatory_u_prefix
|
|
|
+ assert repr(w) == "<cdata '%s' %s'\u1234'>" % (typename, mandatory_u_prefix)
|
|
|
assert str(w) == repr(w)
|
|
|
assert string(w) == u+'\u1234'
|
|
|
assert int(w) == 0x1234
|
|
|
w = cast(BWChar, u+'\u8234')
|
|
|
- assert repr(w) == "<cdata 'wchar_t' %s'\u8234'>" % mandatory_u_prefix
|
|
|
+ assert repr(w) == "<cdata '%s' %s'\u8234'>" % (typename, mandatory_u_prefix)
|
|
|
assert str(w) == repr(w)
|
|
|
assert string(w) == u+'\u8234'
|
|
|
assert int(w) == 0x8234
|
|
|
@@ -2082,8 +2214,8 @@ def test_wchar():
|
|
|
assert repr(w) == "<cdata 'int' 4660>"
|
|
|
if wchar4 and not _hacked_pypy_uni4():
|
|
|
w = cast(BWChar, u+'\U00012345')
|
|
|
- assert repr(w) == "<cdata 'wchar_t' %s'\U00012345'>" % (
|
|
|
- mandatory_u_prefix,)
|
|
|
+ assert repr(w) == "<cdata '%s' %s'\U00012345'>" % (
|
|
|
+ typename, mandatory_u_prefix)
|
|
|
assert str(w) == repr(w)
|
|
|
assert string(w) == u+'\U00012345'
|
|
|
assert int(w) == 0x12345
|
|
|
@@ -2110,7 +2242,7 @@ def test_wchar():
|
|
|
py.test.raises(RuntimeError, string, q)
|
|
|
#
|
|
|
def cb(p):
|
|
|
- assert repr(p).startswith("<cdata 'wchar_t *' 0x")
|
|
|
+ assert repr(p).startswith("<cdata '%s *' 0x" % typename)
|
|
|
return len(string(p))
|
|
|
BFunc = new_function_type((BWCharP,), BInt, False)
|
|
|
f = callback(BFunc, cb, -42)
|
|
|
@@ -2123,6 +2255,27 @@ def test_wchar():
|
|
|
x = cast(BWChar, -1)
|
|
|
py.test.raises(ValueError, string, x)
|
|
|
|
|
|
+def test_wchar_variants_mix():
|
|
|
+ BWChar = new_primitive_type("wchar_t")
|
|
|
+ BChar16 = new_primitive_type("char16_t")
|
|
|
+ BChar32 = new_primitive_type("char32_t")
|
|
|
+ assert int(cast(BChar32, cast(BChar16, -2))) == 0xfffe
|
|
|
+ assert int(cast(BWChar, cast(BChar16, -2))) == 0xfffe
|
|
|
+ assert int(cast(BChar16, cast(BChar32, 0x0001f345))) == 0xf345
|
|
|
+ assert int(cast(BChar16, cast(BWChar, 0x0001f345))) == 0xf345
|
|
|
+ #
|
|
|
+ BChar16A = new_array_type(new_pointer_type(BChar16), None)
|
|
|
+ BChar32A = new_array_type(new_pointer_type(BChar32), None)
|
|
|
+ x = cast(BChar32, 'A')
|
|
|
+ py.test.raises(TypeError, newp, BChar16A, [x])
|
|
|
+ x = cast(BChar16, 'A')
|
|
|
+ py.test.raises(TypeError, newp, BChar32A, [x])
|
|
|
+ #
|
|
|
+ a = newp(BChar16A, u+'\U00012345')
|
|
|
+ assert len(a) == 3
|
|
|
+ a = newp(BChar32A, u+'\U00012345')
|
|
|
+ assert len(a) == 2 # even if the Python unicode string above is 2 chars
|
|
|
+
|
|
|
def test_keepalive_struct():
|
|
|
# exception to the no-keepalive rule: p=newp(BStructPtr) returns a
|
|
|
# pointer owning the memory, and p[0] returns a pointer to the
|
|
|
@@ -2192,12 +2345,17 @@ def test_cmp():
|
|
|
BVoidP = new_pointer_type(new_void_type())
|
|
|
p = newp(BIntP, 123)
|
|
|
q = cast(BInt, 124)
|
|
|
- py.test.raises(TypeError, "p < q")
|
|
|
- py.test.raises(TypeError, "p <= q")
|
|
|
assert (p == q) is False
|
|
|
assert (p != q) is True
|
|
|
- py.test.raises(TypeError, "p > q")
|
|
|
- py.test.raises(TypeError, "p >= q")
|
|
|
+ assert (q == p) is False
|
|
|
+ assert (q != p) is True
|
|
|
+ if strict_compare:
|
|
|
+ py.test.raises(TypeError, "p < q")
|
|
|
+ py.test.raises(TypeError, "p <= q")
|
|
|
+ py.test.raises(TypeError, "q < p")
|
|
|
+ py.test.raises(TypeError, "q <= p")
|
|
|
+ py.test.raises(TypeError, "p > q")
|
|
|
+ py.test.raises(TypeError, "p >= q")
|
|
|
r = cast(BVoidP, p)
|
|
|
assert (p < r) is False
|
|
|
assert (p <= r) is True
|
|
|
@@ -2230,6 +2388,7 @@ def test_buffer():
|
|
|
buf = buffer(c)
|
|
|
assert repr(buf).startswith('<_cffi_backend.buffer object at 0x')
|
|
|
assert bytes(buf) == b"hi there\x00"
|
|
|
+ assert type(buf) is buffer
|
|
|
if sys.version_info < (3,):
|
|
|
assert str(buf) == "hi there\x00"
|
|
|
assert unicode(buf) == u+"hi there\x00"
|
|
|
@@ -2518,6 +2677,25 @@ def test_nested_anonymous_struct():
|
|
|
assert d[2][1].bitshift == -1
|
|
|
assert d[2][1].bitsize == -1
|
|
|
|
|
|
+def test_nested_anonymous_struct_2():
|
|
|
+ BInt = new_primitive_type("int")
|
|
|
+ BStruct = new_struct_type("struct foo")
|
|
|
+ BInnerUnion = new_union_type("union bar")
|
|
|
+ complete_struct_or_union(BInnerUnion, [('a1', BInt, -1),
|
|
|
+ ('a2', BInt, -1)])
|
|
|
+ complete_struct_or_union(BStruct, [('b1', BInt, -1),
|
|
|
+ ('', BInnerUnion, -1),
|
|
|
+ ('b2', BInt, -1)])
|
|
|
+ assert sizeof(BInnerUnion) == sizeof(BInt)
|
|
|
+ assert sizeof(BStruct) == sizeof(BInt) * 3
|
|
|
+ fields = [(name, fld.offset, fld.flags) for (name, fld) in BStruct.fields]
|
|
|
+ assert fields == [
|
|
|
+ ('b1', 0 * sizeof(BInt), 0),
|
|
|
+ ('a1', 1 * sizeof(BInt), 0),
|
|
|
+ ('a2', 1 * sizeof(BInt), 1),
|
|
|
+ ('b2', 2 * sizeof(BInt), 0),
|
|
|
+ ]
|
|
|
+
|
|
|
def test_sizeof_union():
|
|
|
# a union has the largest alignment of its members, and a total size
|
|
|
# that is the largest of its items *possibly further aligned* if
|
|
|
@@ -2569,7 +2747,8 @@ def test_bool():
|
|
|
BBoolP = new_pointer_type(BBool)
|
|
|
assert int(cast(BBool, False)) == 0
|
|
|
assert int(cast(BBool, True)) == 1
|
|
|
- assert bool(cast(BBool, False)) is True # warning!
|
|
|
+ assert bool(cast(BBool, False)) is False # since 1.7
|
|
|
+ assert bool(cast(BBool, True)) is True
|
|
|
assert int(cast(BBool, 3)) == 1
|
|
|
assert int(cast(BBool, long(3))) == 1
|
|
|
assert int(cast(BBool, long(10)**4000)) == 1
|
|
|
@@ -2586,13 +2765,38 @@ def test_bool():
|
|
|
py.test.raises(OverflowError, newp, BBoolP, 2)
|
|
|
py.test.raises(OverflowError, newp, BBoolP, -1)
|
|
|
BCharP = new_pointer_type(new_primitive_type("char"))
|
|
|
- p = newp(BCharP, b'X')
|
|
|
+ p = newp(BCharP, b'\x01')
|
|
|
q = cast(BBoolP, p)
|
|
|
- assert q[0] == ord(b'X')
|
|
|
+ assert q[0] is True
|
|
|
+ p = newp(BCharP, b'\x00')
|
|
|
+ q = cast(BBoolP, p)
|
|
|
+ assert q[0] is False
|
|
|
py.test.raises(TypeError, string, cast(BBool, False))
|
|
|
BDouble = new_primitive_type("double")
|
|
|
assert int(cast(BBool, cast(BDouble, 0.1))) == 1
|
|
|
assert int(cast(BBool, cast(BDouble, 0.0))) == 0
|
|
|
+ BBoolA = new_array_type(BBoolP, None)
|
|
|
+ p = newp(BBoolA, b'\x01\x00')
|
|
|
+ assert p[0] is True
|
|
|
+ assert p[1] is False
|
|
|
+
|
|
|
+def test_bool_forbidden_cases():
|
|
|
+ BBool = new_primitive_type("_Bool")
|
|
|
+ BBoolP = new_pointer_type(BBool)
|
|
|
+ BBoolA = new_array_type(BBoolP, None)
|
|
|
+ BCharP = new_pointer_type(new_primitive_type("char"))
|
|
|
+ p = newp(BCharP, b'X')
|
|
|
+ q = cast(BBoolP, p)
|
|
|
+ py.test.raises(ValueError, "q[0]")
|
|
|
+ py.test.raises(TypeError, newp, BBoolP, b'\x00')
|
|
|
+ assert newp(BBoolP, 0)[0] is False
|
|
|
+ assert newp(BBoolP, 1)[0] is True
|
|
|
+ py.test.raises(OverflowError, newp, BBoolP, 2)
|
|
|
+ py.test.raises(OverflowError, newp, BBoolP, -1)
|
|
|
+ py.test.raises(ValueError, newp, BBoolA, b'\x00\x01\x02')
|
|
|
+ py.test.raises(OverflowError, newp, BBoolA, [0, 1, 2])
|
|
|
+ py.test.raises(TypeError, string, newp(BBoolP, 1))
|
|
|
+ py.test.raises(TypeError, string, newp(BBoolA, [1]))
|
|
|
|
|
|
def test_typeoffsetof():
|
|
|
BChar = new_primitive_type("char")
|
|
|
@@ -2691,10 +2895,19 @@ def test_newp_from_bytearray_doesnt_work():
|
|
|
BCharArray = new_array_type(
|
|
|
new_pointer_type(new_primitive_type("char")), None)
|
|
|
py.test.raises(TypeError, newp, BCharArray, bytearray(b"foo"))
|
|
|
- p = newp(BCharArray, 4)
|
|
|
- buffer(p)[:] = bytearray(b"foo\x00")
|
|
|
- assert len(p) == 4
|
|
|
- assert list(p) == [b"f", b"o", b"o", b"\x00"]
|
|
|
+ p = newp(BCharArray, 5)
|
|
|
+ buffer(p)[:] = bytearray(b"foo.\x00")
|
|
|
+ assert len(p) == 5
|
|
|
+ assert list(p) == [b"f", b"o", b"o", b".", b"\x00"]
|
|
|
+ p[1:3] = bytearray(b"XY")
|
|
|
+ assert list(p) == [b"f", b"X", b"Y", b".", b"\x00"]
|
|
|
+
|
|
|
+def test_string_assignment_to_byte_array():
|
|
|
+ BByteArray = new_array_type(
|
|
|
+ new_pointer_type(new_primitive_type("unsigned char")), None)
|
|
|
+ p = newp(BByteArray, 5)
|
|
|
+ p[0:3] = bytearray(b"XYZ")
|
|
|
+ assert list(p) == [ord("X"), ord("Y"), ord("Z"), 0, 0]
|
|
|
|
|
|
# XXX hack
|
|
|
if sys.version_info >= (3,):
|
|
|
@@ -3125,17 +3338,19 @@ def test_struct_array_no_length():
|
|
|
assert d[1][0] == 'y'
|
|
|
assert d[1][1].type is BArray
|
|
|
assert d[1][1].offset == size_of_int()
|
|
|
- assert d[1][1].bitshift == -1
|
|
|
+ assert d[1][1].bitshift == -2
|
|
|
assert d[1][1].bitsize == -1
|
|
|
#
|
|
|
p = newp(new_pointer_type(BStruct))
|
|
|
p.x = 42
|
|
|
assert p.x == 42
|
|
|
- assert typeof(p.y) is BIntP
|
|
|
+ assert typeof(p.y) is BArray
|
|
|
+ assert len(p.y) == 0
|
|
|
assert p.y == cast(BIntP, p) + 1
|
|
|
#
|
|
|
p = newp(new_pointer_type(BStruct), [100])
|
|
|
assert p.x == 100
|
|
|
+ assert len(p.y) == 0
|
|
|
#
|
|
|
# Tests for
|
|
|
# ffi.new("struct_with_var_array *", [field.., [the_array_items..]])
|
|
|
@@ -3150,6 +3365,10 @@ def test_struct_array_no_length():
|
|
|
p.y[0] = 200
|
|
|
assert p.y[2] == 0
|
|
|
p.y[2] = 400
|
|
|
+ assert len(p.y) == 3
|
|
|
+ assert len(p[0].y) == 3
|
|
|
+ assert len(buffer(p)) == sizeof(BInt) * 4
|
|
|
+ assert sizeof(p[0]) == sizeof(BInt) * 4
|
|
|
plist.append(p)
|
|
|
for i in range(20):
|
|
|
p = plist[i]
|
|
|
@@ -3157,13 +3376,31 @@ def test_struct_array_no_length():
|
|
|
assert p.y[0] == 200
|
|
|
assert p.y[1] == i
|
|
|
assert p.y[2] == 400
|
|
|
- assert list(p.y[0:3]) == [200, i, 400]
|
|
|
+ assert list(p.y) == [200, i, 400]
|
|
|
#
|
|
|
# the following assignment works, as it normally would, for any array field
|
|
|
- p.y = [500, 600]
|
|
|
- assert list(p.y[0:3]) == [500, 600, 400]
|
|
|
+ p.y = [501, 601]
|
|
|
+ assert list(p.y) == [501, 601, 400]
|
|
|
+ p[0].y = [500, 600]
|
|
|
+ assert list(p[0].y) == [500, 600, 400]
|
|
|
+ assert repr(p) == "<cdata 'foo *' owning %d bytes>" % (
|
|
|
+ sizeof(BStruct) + 3 * sizeof(BInt),)
|
|
|
+ assert repr(p[0]) == "<cdata 'foo' owning %d bytes>" % (
|
|
|
+ sizeof(BStruct) + 3 * sizeof(BInt),)
|
|
|
+ assert sizeof(p[0]) == sizeof(BStruct) + 3 * sizeof(BInt)
|
|
|
+ #
|
|
|
+ # from a non-owning pointer, we can't get the length
|
|
|
+ q = cast(new_pointer_type(BStruct), p)
|
|
|
+ assert q.y[0] == 500
|
|
|
+ assert q[0].y[0] == 500
|
|
|
+ py.test.raises(TypeError, len, q.y)
|
|
|
+ py.test.raises(TypeError, len, q[0].y)
|
|
|
+ assert typeof(q.y) is BIntP
|
|
|
+ assert typeof(q[0].y) is BIntP
|
|
|
+ assert sizeof(q[0]) == sizeof(BStruct)
|
|
|
#
|
|
|
# error cases
|
|
|
+ py.test.raises(IndexError, "p.y[4]")
|
|
|
py.test.raises(TypeError, "p.y = cast(BIntP, 0)")
|
|
|
py.test.raises(TypeError, "p.y = 15")
|
|
|
py.test.raises(TypeError, "p.y = None")
|
|
|
@@ -3228,6 +3465,33 @@ def test_struct_array_no_length_explicit_position():
|
|
|
assert p.x[5] == 60
|
|
|
assert p.x[6] == 70
|
|
|
|
|
|
+def test_struct_array_not_aligned():
|
|
|
+ # struct a { int x; char y; char z[]; };
|
|
|
+ # ends up of size 8, but 'z' is at offset 5
|
|
|
+ BChar = new_primitive_type("char")
|
|
|
+ BInt = new_primitive_type("int")
|
|
|
+ BCharP = new_pointer_type(BChar)
|
|
|
+ BArray = new_array_type(BCharP, None)
|
|
|
+ BStruct = new_struct_type("foo")
|
|
|
+ complete_struct_or_union(BStruct, [('x', BInt),
|
|
|
+ ('y', BChar),
|
|
|
+ ('z', BArray)])
|
|
|
+ assert sizeof(BStruct) == 2 * size_of_int()
|
|
|
+ def offsetof(BType, fieldname):
|
|
|
+ return typeoffsetof(BType, fieldname)[1]
|
|
|
+ base = offsetof(BStruct, 'z')
|
|
|
+ assert base == size_of_int() + 1
|
|
|
+ #
|
|
|
+ p = newp(new_pointer_type(BStruct), {'z': 3})
|
|
|
+ assert sizeof(p[0]) == base + 3
|
|
|
+ q = newp(new_pointer_type(BStruct), {'z': size_of_int()})
|
|
|
+ assert sizeof(q) == size_of_ptr()
|
|
|
+ assert sizeof(q[0]) == base + size_of_int()
|
|
|
+ assert len(p.z) == 3
|
|
|
+ assert len(p[0].z) == 3
|
|
|
+ assert len(q.z) == size_of_int()
|
|
|
+ assert len(q[0].z) == size_of_int()
|
|
|
+
|
|
|
def test_ass_slice():
|
|
|
BChar = new_primitive_type("char")
|
|
|
BArray = new_array_type(new_pointer_type(BChar), None)
|
|
|
@@ -3238,14 +3502,15 @@ def test_ass_slice():
|
|
|
py.test.raises(TypeError, "p[1:5] = u+'XYZT'")
|
|
|
py.test.raises(TypeError, "p[1:5] = [1, 2, 3, 4]")
|
|
|
#
|
|
|
- BUniChar = new_primitive_type("wchar_t")
|
|
|
- BArray = new_array_type(new_pointer_type(BUniChar), None)
|
|
|
- p = newp(BArray, u+"foobar")
|
|
|
- p[2:5] = [u+"*", u+"Z", u+"T"]
|
|
|
- p[1:3] = u+"XY"
|
|
|
- assert list(p) == [u+"f", u+"X", u+"Y", u+"Z", u+"T", u+"r", u+"\x00"]
|
|
|
- py.test.raises(TypeError, "p[1:5] = b'XYZT'")
|
|
|
- py.test.raises(TypeError, "p[1:5] = [1, 2, 3, 4]")
|
|
|
+ for typename in ["wchar_t", "char16_t", "char32_t"]:
|
|
|
+ BUniChar = new_primitive_type(typename)
|
|
|
+ BArray = new_array_type(new_pointer_type(BUniChar), None)
|
|
|
+ p = newp(BArray, u+"foobar")
|
|
|
+ p[2:5] = [u+"*", u+"Z", u+"T"]
|
|
|
+ p[1:3] = u+"XY"
|
|
|
+ assert list(p) == [u+"f", u+"X", u+"Y", u+"Z", u+"T", u+"r", u+"\x00"]
|
|
|
+ py.test.raises(TypeError, "p[1:5] = b'XYZT'")
|
|
|
+ py.test.raises(TypeError, "p[1:5] = [1, 2, 3, 4]")
|
|
|
|
|
|
def test_void_p_arithmetic():
|
|
|
BVoid = new_void_type()
|
|
|
@@ -3322,30 +3587,55 @@ def test_from_buffer():
|
|
|
cast(p, c)[1] += 500
|
|
|
assert list(a) == [10000, 20500, 30000]
|
|
|
|
|
|
-def test_from_buffer_not_str_unicode_bytearray():
|
|
|
+def test_from_buffer_not_str_unicode():
|
|
|
BChar = new_primitive_type("char")
|
|
|
BCharP = new_pointer_type(BChar)
|
|
|
BCharA = new_array_type(BCharP, None)
|
|
|
- py.test.raises(TypeError, from_buffer, BCharA, b"foo")
|
|
|
+ p1 = from_buffer(BCharA, b"foo")
|
|
|
+ assert p1 == from_buffer(BCharA, b"foo")
|
|
|
+ import gc; gc.collect()
|
|
|
+ assert p1 == from_buffer(BCharA, b"foo")
|
|
|
py.test.raises(TypeError, from_buffer, BCharA, u+"foo")
|
|
|
- py.test.raises(TypeError, from_buffer, BCharA, bytearray(b"foo"))
|
|
|
try:
|
|
|
from __builtin__ import buffer
|
|
|
except ImportError:
|
|
|
pass
|
|
|
else:
|
|
|
- py.test.raises(TypeError, from_buffer, BCharA, buffer(b"foo"))
|
|
|
- py.test.raises(TypeError, from_buffer, BCharA, buffer(u+"foo"))
|
|
|
- py.test.raises(TypeError, from_buffer, BCharA,
|
|
|
- buffer(bytearray(b"foo")))
|
|
|
+ # Python 2 only
|
|
|
+ contents = from_buffer(BCharA, buffer(b"foo"))
|
|
|
+ assert len(contents) == len(p1)
|
|
|
+ for i in range(len(contents)):
|
|
|
+ assert contents[i] == p1[i]
|
|
|
+ p4 = buffer(u+"foo")
|
|
|
+ contents = from_buffer(BCharA, buffer(u+"foo"))
|
|
|
+ assert len(contents) == len(p4)
|
|
|
+ for i in range(len(contents)):
|
|
|
+ assert contents[i] == p4[i]
|
|
|
try:
|
|
|
from __builtin__ import memoryview
|
|
|
except ImportError:
|
|
|
pass
|
|
|
else:
|
|
|
- py.test.raises(TypeError, from_buffer, BCharA, memoryview(b"foo"))
|
|
|
- py.test.raises(TypeError, from_buffer, BCharA,
|
|
|
- memoryview(bytearray(b"foo")))
|
|
|
+ contents = from_buffer(BCharA, memoryview(b"foo"))
|
|
|
+ assert len(contents) == len(p1)
|
|
|
+ for i in range(len(contents)):
|
|
|
+ assert contents[i] == p1[i]
|
|
|
+
|
|
|
+
|
|
|
+def test_from_buffer_bytearray():
|
|
|
+ a = bytearray(b"xyz")
|
|
|
+ BChar = new_primitive_type("char")
|
|
|
+ BCharP = new_pointer_type(BChar)
|
|
|
+ BCharA = new_array_type(BCharP, None)
|
|
|
+ p = from_buffer(BCharA, a)
|
|
|
+ assert typeof(p) is BCharA
|
|
|
+ assert len(p) == 3
|
|
|
+ assert repr(p) == "<cdata 'char[]' buffer len 3 from 'bytearray' object>"
|
|
|
+ assert p[2] == b"z"
|
|
|
+ p[2] = b"."
|
|
|
+ assert a[2] == ord(".")
|
|
|
+ a[2] = ord("?")
|
|
|
+ assert p[2] == b"?"
|
|
|
|
|
|
def test_from_buffer_more_cases():
|
|
|
try:
|
|
|
@@ -3525,3 +3815,213 @@ def test_get_common_types():
|
|
|
d = {}
|
|
|
_get_common_types(d)
|
|
|
assert d['bool'] == '_Bool'
|
|
|
+
|
|
|
+def test_unpack():
|
|
|
+ BChar = new_primitive_type("char")
|
|
|
+ BArray = new_array_type(new_pointer_type(BChar), 10) # char[10]
|
|
|
+ p = newp(BArray, b"abc\x00def")
|
|
|
+ p0 = p
|
|
|
+ assert unpack(p, 10) == b"abc\x00def\x00\x00\x00"
|
|
|
+ assert unpack(p+1, 5) == b"bc\x00de"
|
|
|
+
|
|
|
+ for typename in ["wchar_t", "char16_t", "char32_t"]:
|
|
|
+ BWChar = new_primitive_type(typename)
|
|
|
+ BArray = new_array_type(new_pointer_type(BWChar), 10) # wchar_t[10]
|
|
|
+ p = newp(BArray, u"abc\x00def")
|
|
|
+ assert unpack(p, 10) == u"abc\x00def\x00\x00\x00"
|
|
|
+
|
|
|
+ for typename, samples in [
|
|
|
+ ("uint8_t", [0, 2**8-1]),
|
|
|
+ ("uint16_t", [0, 2**16-1]),
|
|
|
+ ("uint32_t", [0, 2**32-1]),
|
|
|
+ ("uint64_t", [0, 2**64-1]),
|
|
|
+ ("int8_t", [-2**7, 2**7-1]),
|
|
|
+ ("int16_t", [-2**15, 2**15-1]),
|
|
|
+ ("int32_t", [-2**31, 2**31-1]),
|
|
|
+ ("int64_t", [-2**63, 2**63-1]),
|
|
|
+ ("_Bool", [False, True]),
|
|
|
+ ("float", [0.0, 10.5]),
|
|
|
+ ("double", [12.34, 56.78]),
|
|
|
+ ]:
|
|
|
+ BItem = new_primitive_type(typename)
|
|
|
+ BArray = new_array_type(new_pointer_type(BItem), 10)
|
|
|
+ p = newp(BArray, samples)
|
|
|
+ result = unpack(p, len(samples))
|
|
|
+ assert result == samples
|
|
|
+ for i in range(len(samples)):
|
|
|
+ assert result[i] == p[i] and type(result[i]) is type(p[i])
|
|
|
+ assert (type(result[i]) is bool) == (type(samples[i]) is bool)
|
|
|
+ #
|
|
|
+ BInt = new_primitive_type("int")
|
|
|
+ py.test.raises(TypeError, unpack, p)
|
|
|
+ py.test.raises(TypeError, unpack, b"foobar", 6)
|
|
|
+ py.test.raises(TypeError, unpack, cast(BInt, 42), 1)
|
|
|
+ #
|
|
|
+ BPtr = new_pointer_type(BInt)
|
|
|
+ random_ptr = cast(BPtr, -424344)
|
|
|
+ other_ptr = cast(BPtr, 54321)
|
|
|
+ BArray = new_array_type(new_pointer_type(BPtr), None)
|
|
|
+ lst = unpack(newp(BArray, [random_ptr, other_ptr]), 2)
|
|
|
+ assert lst == [random_ptr, other_ptr]
|
|
|
+ #
|
|
|
+ BFunc = new_function_type((BInt, BInt), BInt, False)
|
|
|
+ BFuncPtr = new_pointer_type(BFunc)
|
|
|
+ lst = unpack(newp(new_array_type(BFuncPtr, None), 2), 2)
|
|
|
+ assert len(lst) == 2
|
|
|
+ assert not lst[0] and not lst[1]
|
|
|
+ assert typeof(lst[0]) is BFunc
|
|
|
+ #
|
|
|
+ BStruct = new_struct_type("foo")
|
|
|
+ BStructPtr = new_pointer_type(BStruct)
|
|
|
+ e = py.test.raises(ValueError, unpack, cast(BStructPtr, 42), 5)
|
|
|
+ assert str(e.value) == "'foo *' points to items of unknown size"
|
|
|
+ complete_struct_or_union(BStruct, [('a1', BInt, -1),
|
|
|
+ ('a2', BInt, -1)])
|
|
|
+ array_of_structs = newp(new_array_type(BStructPtr, None), [[4,5], [6,7]])
|
|
|
+ lst = unpack(array_of_structs, 2)
|
|
|
+ assert typeof(lst[0]) is BStruct
|
|
|
+ assert lst[0].a1 == 4 and lst[1].a2 == 7
|
|
|
+ #
|
|
|
+ py.test.raises(RuntimeError, unpack, cast(new_pointer_type(BChar), 0), 0)
|
|
|
+ py.test.raises(RuntimeError, unpack, cast(new_pointer_type(BChar), 0), 10)
|
|
|
+ #
|
|
|
+ py.test.raises(ValueError, unpack, p0, -1)
|
|
|
+ py.test.raises(ValueError, unpack, p, -1)
|
|
|
+
|
|
|
+def test_cdata_dir():
|
|
|
+ BInt = new_primitive_type("int")
|
|
|
+ p = cast(BInt, 42)
|
|
|
+ check_dir(p, [])
|
|
|
+ p = newp(new_array_type(new_pointer_type(BInt), None), 5)
|
|
|
+ check_dir(p, [])
|
|
|
+ BStruct = new_struct_type("foo")
|
|
|
+ p = cast(new_pointer_type(BStruct), 0)
|
|
|
+ check_dir(p, []) # opaque
|
|
|
+ complete_struct_or_union(BStruct, [('a2', BInt, -1),
|
|
|
+ ('a1', BInt, -1)])
|
|
|
+ check_dir(p, ['a1', 'a2']) # always sorted
|
|
|
+ p = newp(new_pointer_type(BStruct), None)
|
|
|
+ check_dir(p, ['a1', 'a2'])
|
|
|
+ check_dir(p[0], ['a1', 'a2'])
|
|
|
+ pp = newp(new_pointer_type(new_pointer_type(BStruct)), p)
|
|
|
+ check_dir(pp, [])
|
|
|
+ check_dir(pp[0], ['a1', 'a2'])
|
|
|
+ check_dir(pp[0][0], ['a1', 'a2'])
|
|
|
+
|
|
|
+def test_char_pointer_conversion():
|
|
|
+ import warnings
|
|
|
+ assert __version__.startswith(("1.8", "1.9", "1.10", "1.11")), (
|
|
|
+ "consider turning the warning into an error")
|
|
|
+ BCharP = new_pointer_type(new_primitive_type("char"))
|
|
|
+ BIntP = new_pointer_type(new_primitive_type("int"))
|
|
|
+ BVoidP = new_pointer_type(new_void_type())
|
|
|
+ BUCharP = new_pointer_type(new_primitive_type("unsigned char"))
|
|
|
+ z1 = cast(BCharP, 0)
|
|
|
+ z2 = cast(BIntP, 0)
|
|
|
+ z3 = cast(BVoidP, 0)
|
|
|
+ z4 = cast(BUCharP, 0)
|
|
|
+ with warnings.catch_warnings(record=True) as w:
|
|
|
+ newp(new_pointer_type(BIntP), z1) # warn
|
|
|
+ assert len(w) == 1
|
|
|
+ newp(new_pointer_type(BVoidP), z1) # fine
|
|
|
+ assert len(w) == 1
|
|
|
+ newp(new_pointer_type(BCharP), z2) # warn
|
|
|
+ assert len(w) == 2
|
|
|
+ newp(new_pointer_type(BVoidP), z2) # fine
|
|
|
+ assert len(w) == 2
|
|
|
+ newp(new_pointer_type(BCharP), z3) # fine
|
|
|
+ assert len(w) == 2
|
|
|
+ newp(new_pointer_type(BIntP), z3) # fine
|
|
|
+ assert len(w) == 2
|
|
|
+ newp(new_pointer_type(BCharP), z4) # fine (ignore signedness here)
|
|
|
+ assert len(w) == 2
|
|
|
+ newp(new_pointer_type(BUCharP), z1) # fine (ignore signedness here)
|
|
|
+ assert len(w) == 2
|
|
|
+ newp(new_pointer_type(BUCharP), z3) # fine
|
|
|
+ assert len(w) == 2
|
|
|
+ # check that the warnings are associated with lines in this file
|
|
|
+ assert w[1].lineno == w[0].lineno + 4
|
|
|
+
|
|
|
+def test_primitive_comparison():
|
|
|
+ def assert_eq(a, b):
|
|
|
+ assert (a == b) is True
|
|
|
+ assert (b == a) is True
|
|
|
+ assert (a != b) is False
|
|
|
+ assert (b != a) is False
|
|
|
+ assert (a < b) is False
|
|
|
+ assert (a <= b) is True
|
|
|
+ assert (a > b) is False
|
|
|
+ assert (a >= b) is True
|
|
|
+ assert (b < a) is False
|
|
|
+ assert (b <= a) is True
|
|
|
+ assert (b > a) is False
|
|
|
+ assert (b >= a) is True
|
|
|
+ assert hash(a) == hash(b)
|
|
|
+ def assert_lt(a, b, check_hash=True):
|
|
|
+ assert (a == b) is False
|
|
|
+ assert (b == a) is False
|
|
|
+ assert (a != b) is True
|
|
|
+ assert (b != a) is True
|
|
|
+ assert (a < b) is True
|
|
|
+ assert (a <= b) is True
|
|
|
+ assert (a > b) is False
|
|
|
+ assert (a >= b) is False
|
|
|
+ assert (b < a) is False
|
|
|
+ assert (b <= a) is False
|
|
|
+ assert (b > a) is True
|
|
|
+ assert (b >= a) is True
|
|
|
+ if check_hash:
|
|
|
+ assert hash(a) != hash(b) # (or at least, it is unlikely)
|
|
|
+ def assert_gt(a, b, check_hash=True):
|
|
|
+ assert_lt(b, a, check_hash)
|
|
|
+ def assert_ne(a, b):
|
|
|
+ assert (a == b) is False
|
|
|
+ assert (b == a) is False
|
|
|
+ assert (a != b) is True
|
|
|
+ assert (b != a) is True
|
|
|
+ if strict_compare:
|
|
|
+ py.test.raises(TypeError, "a < b")
|
|
|
+ py.test.raises(TypeError, "a <= b")
|
|
|
+ py.test.raises(TypeError, "a > b")
|
|
|
+ py.test.raises(TypeError, "a >= b")
|
|
|
+ py.test.raises(TypeError, "b < a")
|
|
|
+ py.test.raises(TypeError, "b <= a")
|
|
|
+ py.test.raises(TypeError, "b > a")
|
|
|
+ py.test.raises(TypeError, "b >= a")
|
|
|
+ elif a < b:
|
|
|
+ assert_lt(a, b)
|
|
|
+ else:
|
|
|
+ assert_lt(b, a)
|
|
|
+ assert_eq(5, 5)
|
|
|
+ assert_lt(3, 5)
|
|
|
+ assert_ne('5', 5)
|
|
|
+ #
|
|
|
+ t1 = new_primitive_type("char")
|
|
|
+ t2 = new_primitive_type("int")
|
|
|
+ t3 = new_primitive_type("unsigned char")
|
|
|
+ t4 = new_primitive_type("unsigned int")
|
|
|
+ t5 = new_primitive_type("float")
|
|
|
+ t6 = new_primitive_type("double")
|
|
|
+ assert_eq(cast(t1, 65), b'A')
|
|
|
+ assert_lt(cast(t1, 64), b'\x99')
|
|
|
+ assert_gt(cast(t1, 200), b'A')
|
|
|
+ assert_ne(cast(t1, 65), 65)
|
|
|
+ assert_eq(cast(t2, -25), -25)
|
|
|
+ assert_lt(cast(t2, -25), -24)
|
|
|
+ assert_gt(cast(t2, -25), -26)
|
|
|
+ assert_eq(cast(t3, 65), 65)
|
|
|
+ assert_ne(cast(t3, 65), b'A')
|
|
|
+ assert_ne(cast(t3, 65), cast(t1, 65))
|
|
|
+ assert_gt(cast(t4, -1), -1, check_hash=False)
|
|
|
+ assert_gt(cast(t4, -1), cast(t2, -1), check_hash=False)
|
|
|
+ assert_gt(cast(t4, -1), 99999)
|
|
|
+ assert_eq(cast(t4, -1), 256 ** size_of_int() - 1)
|
|
|
+ assert_eq(cast(t5, 3.0), 3)
|
|
|
+ assert_eq(cast(t5, 3.5), 3.5)
|
|
|
+ assert_lt(cast(t5, 3.3), 3.3) # imperfect rounding
|
|
|
+ assert_eq(cast(t6, 3.3), 3.3)
|
|
|
+ assert_eq(cast(t5, 3.5), cast(t6, 3.5))
|
|
|
+ assert_lt(cast(t5, 3.1), cast(t6, 3.1)) # imperfect rounding
|
|
|
+ assert_eq(cast(t5, 7.0), cast(t3, 7))
|
|
|
+ assert_lt(cast(t5, 3.1), 3.101)
|
|
|
+ assert_gt(cast(t5, 3.1), 3)
|