Author: Armin Rigo <[email protected]>
Branch: ffi-backend
Changeset: r55724:80fd44051daf
Date: 2012-06-19 19:26 +0200
http://bitbucket.org/pypy/pypy/changeset/80fd44051daf/
Log: Starting work on the _ffi_backend module, from the tests of the
CPython version.
diff --git a/pypy/module/_ffi_backend/__init__.py
b/pypy/module/_ffi_backend/__init__.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_ffi_backend/__init__.py
@@ -0,0 +1,9 @@
+from pypy.interpreter.mixedmodule import MixedModule
+
+class Module(MixedModule):
+
+ appleveldefs = {
+ }
+ interpleveldefs = {
+ 'load_library': 'interp_library.load_library',
+ }
diff --git a/pypy/module/_ffi_backend/interp_library.py
b/pypy/module/_ffi_backend/interp_library.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_ffi_backend/interp_library.py
@@ -0,0 +1,44 @@
+from __future__ import with_statement
+from pypy.interpreter.error import OperationError, operationerrfmt
+from pypy.interpreter.baseobjspace import Wrappable
+from pypy.interpreter.gateway import interp2app, unwrap_spec
+from pypy.interpreter.typedef import TypeDef
+from pypy.rpython.lltypesystem import lltype, rffi
+from pypy.rlib.rdynload import DLLHANDLE, dlopen, dlclose, DLOpenError
+
+
+class W_Library(Wrappable):
+ handle = rffi.cast(DLLHANDLE, 0)
+
+ def __init__(self, space, filename):
+ self.space = space
+ with rffi.scoped_str2charp(filename) as ll_libname:
+ try:
+ self.handle = dlopen(ll_libname)
+ except DLOpenError, e:
+ raise operationerrfmt(space.w_OSError,
+ "cannot load '%s': %s",
+ filename, e.msg)
+ self.name = filename
+
+ def __del__(self):
+ h = self.handle
+ if h != rffi.cast(DLLHANDLE, 0):
+ self.handle = rffi.cast(DLLHANDLE, 0)
+ dlclose(h)
+
+ def repr(self):
+ space = self.space
+ return space.wrap("<clibrary '%s'>" % self.name)
+
+
+W_Library.typedef = TypeDef(
+ '_ffi_backend.Library',
+ __repr__ = interp2app(W_Library.repr),
+ )
+
+
+@unwrap_spec(filename=str)
+def load_library(space, filename):
+ lib = W_Library(space, filename)
+ return space.wrap(lib)
diff --git a/pypy/module/_ffi_backend/test/__init__.py
b/pypy/module/_ffi_backend/test/__init__.py
new file mode 100644
diff --git a/pypy/module/_ffi_backend/test/test_c.py
b/pypy/module/_ffi_backend/test/test_c.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_ffi_backend/test/test_c.py
@@ -0,0 +1,777 @@
+import py
+from pypy.conftest import gettestobjspace
+
+
+class AppTestFfiBackend(object):
+
+ def setup_class(cls):
+ cls.space = gettestobjspace(usemodules=('_ffi_backend',))
+ #
+ import ctypes.util
+ path = ctypes.util.find_library('c')
+ #
+ cls.w_b = cls.space.appexec([cls.space.wrap(path)], '''(path):
+ import _ffi_backend
+ def size_of_int():
+ BInt = _ffi_backend.new_primitive_type("int")
+ return _ffi_backend.sizeof(BInt)
+ def size_of_long():
+ BLong = _ffi_backend.new_primitive_type("long")
+ return _ffi_backend.sizeof(BLong)
+ def size_of_ptr():
+ BInt = _ffi_backend.new_primitive_type("int")
+ BPtr = _ffi_backend.new_pointer_type(BInt)
+ return _ffi_backend.sizeof(BPtr)
+ def find_and_load_library():
+ return _ffi_backend.load_library(path)
+ _ffi_backend._size_of_int = size_of_int
+ _ffi_backend._size_of_long = size_of_long
+ _ffi_backend._size_of_ptr = size_of_ptr
+ _ffi_backend._find_and_load_library = find_and_load_library
+ return _ffi_backend
+ ''')
+
+ def test_load_library(self):
+ x = self.b._find_and_load_library()
+ assert repr(x).startswith("<clibrary '")
+
+ def test_nonstandard_integer_types(self):
+ d = nonstandard_integer_types()
+ assert type(d) is dict
+ assert 'char' not in d
+ assert d['size_t'] in (0x1004, 0x1008)
+ assert d['size_t'] == d['ssize_t'] + 0x1000
+
+ def test_new_primitive_type(self):
+ py.test.raises(KeyError, new_primitive_type, "foo")
+ p = new_primitive_type("signed char")
+ assert repr(p) == "<ctype 'signed char'>"
+
+ def test_cast_to_signed_char(self):
+ p = new_primitive_type("signed char")
+ x = cast(p, -65 + 17*256)
+ assert repr(x) == "<cdata 'signed char'>"
+ assert repr(type(x)) == "<type '_ffi_backend.CData'>"
+ assert int(x) == -65
+ x = cast(p, -66 + (1<<199)*256)
+ assert repr(x) == "<cdata 'signed char'>"
+ assert int(x) == -66
+ assert (x == cast(p, -66)) is False
+ assert (x != cast(p, -66)) is True
+ q = new_primitive_type("short")
+ assert (x == cast(q, -66)) is False
+ assert (x != cast(q, -66)) is True
+
+ def test_sizeof_type(self):
+ py.test.raises(TypeError, sizeof, 42.5)
+ p = new_primitive_type("short")
+ assert sizeof(p) == 2
+
+ def test_integer_types(self):
+ for name in ['signed char', 'short', 'int', 'long', 'long long']:
+ p = new_primitive_type(name)
+ size = sizeof(p)
+ min = -(1 << (8*size-1))
+ max = (1 << (8*size-1)) - 1
+ assert int(cast(p, min)) == min
+ assert int(cast(p, max)) == max
+ assert int(cast(p, min - 1)) == max
+ assert int(cast(p, max + 1)) == min
+ assert long(cast(p, min - 1)) == max
+ for name in ['char', 'short', 'int', 'long', 'long long']:
+ p = new_primitive_type('unsigned ' + name)
+ size = sizeof(p)
+ max = (1 << (8*size)) - 1
+ assert int(cast(p, 0)) == 0
+ assert int(cast(p, max)) == max
+ assert int(cast(p, -1)) == max
+ assert int(cast(p, max + 1)) == 0
+ assert long(cast(p, -1)) == max
+
+ def test_no_float_on_int_types(self):
+ p = new_primitive_type('long')
+ py.test.raises(TypeError, float, cast(p, 42))
+
+ def test_float_types(self):
+ INF = 1E200 * 1E200
+ for name in ["float", "double"]:
+ p = new_primitive_type(name)
+ assert bool(cast(p, 0))
+ assert bool(cast(p, INF))
+ assert bool(cast(p, -INF))
+ assert int(cast(p, -150)) == -150
+ assert int(cast(p, 61.91)) == 61
+ assert long(cast(p, 61.91)) == 61L
+ assert type(int(cast(p, 61.91))) is int
+ assert type(int(cast(p, 1E22))) is long
+ assert type(long(cast(p, 61.91))) is long
+ assert type(long(cast(p, 1E22))) is long
+ py.test.raises(OverflowError, int, cast(p, INF))
+ py.test.raises(OverflowError, int, cast(p, -INF))
+ assert float(cast(p, 1.25)) == 1.25
+ assert float(cast(p, INF)) == INF
+ assert float(cast(p, -INF)) == -INF
+ if name == "float":
+ 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 repr(float(cast(p, -0.0))) == '-0.0'
+
+ def test_character_type(self):
+ p = new_primitive_type("char")
+ assert bool(cast(p, '\x00'))
+ assert cast(p, '\x00') != cast(p, -17*256)
+ assert int(cast(p, 'A')) == 65
+ assert long(cast(p, 'A')) == 65L
+ assert type(int(cast(p, 'A'))) is int
+ assert type(long(cast(p, 'A'))) is long
+ assert str(cast(p, 'A')) == 'A'
+
+ def test_pointer_type(self):
+ p = new_primitive_type("int")
+ assert repr(p) == "<ctype 'int'>"
+ p = new_pointer_type(p)
+ assert repr(p) == "<ctype 'int *'>"
+ p = new_pointer_type(p)
+ assert repr(p) == "<ctype 'int * *'>"
+ p = new_pointer_type(p)
+ assert repr(p) == "<ctype 'int * * *'>"
+
+ def test_pointer_to_int(self):
+ BInt = new_primitive_type("int")
+ py.test.raises(TypeError, newp, BInt, None)
+ BPtr = new_pointer_type(BInt)
+ p = newp(BPtr, None)
+ assert repr(p) == "<cdata 'int *' owning %d bytes>" % size_of_int()
+ p = newp(BPtr, 5000)
+ assert repr(p) == "<cdata 'int *' owning %d bytes>" % size_of_int()
+ q = cast(BPtr, p)
+ assert repr(q) == "<cdata 'int *'>"
+ assert p == q
+ assert hash(p) == hash(q)
+
+ def test_pointer_to_pointer(self):
+ BInt = new_primitive_type("int")
+ BPtr = new_pointer_type(BInt)
+ BPtrPtr = new_pointer_type(BPtr)
+ p = newp(BPtrPtr, None)
+ assert repr(p) == "<cdata 'int * *' owning %d bytes>" % size_of_ptr()
+
+ def test_reading_pointer_to_int(self):
+ BInt = new_primitive_type("int")
+ BPtr = new_pointer_type(BInt)
+ p = newp(BPtr, None)
+ assert p[0] == 0
+ p = newp(BPtr, 5000)
+ assert p[0] == 5000
+ py.test.raises(IndexError, "p[1]")
+ py.test.raises(IndexError, "p[-1]")
+
+ def test_reading_pointer_to_float(self):
+ BFloat = new_primitive_type("float")
+ py.test.raises(TypeError, newp, BFloat, None)
+ BPtr = new_pointer_type(BFloat)
+ p = newp(BPtr, None)
+ assert p[0] == 0.0 and type(p[0]) is float
+ p = newp(BPtr, 1.25)
+ assert p[0] == 1.25 and type(p[0]) is float
+ p = newp(BPtr, 1.1)
+ assert p[0] != 1.1 and abs(p[0] - 1.1) < 1E-5 # rounding errors
+
+ def test_reading_pointer_to_char(self):
+ BChar = new_primitive_type("char")
+ py.test.raises(TypeError, newp, BChar, None)
+ BPtr = new_pointer_type(BChar)
+ p = newp(BPtr, None)
+ assert p[0] == '\x00'
+ p = newp(BPtr, 'A')
+ assert p[0] == 'A'
+ py.test.raises(TypeError, newp, BPtr, 65)
+ py.test.raises(TypeError, newp, BPtr, "foo")
+
+ def test_hash_differences(self):
+ BChar = new_primitive_type("char")
+ BInt = new_primitive_type("int")
+ BFloat = new_primitive_type("float")
+ assert (hash(cast(BChar, 'A')) !=
+ hash(cast(BInt, 65)))
+ assert hash(cast(BFloat, 65)) != hash(65.0)
+
+ def test_array_type(self):
+ p = new_primitive_type("int")
+ assert repr(p) == "<ctype 'int'>"
+ #
+ py.test.raises(TypeError, new_array_type, new_pointer_type(p), "foo")
+ py.test.raises(ValueError, new_array_type, new_pointer_type(p), -42)
+ #
+ p1 = new_array_type(new_pointer_type(p), None)
+ assert repr(p1) == "<ctype 'int[]'>"
+ py.test.raises(ValueError, new_array_type, new_pointer_type(p1), 42)
+ #
+ p1 = new_array_type(new_pointer_type(p), 42)
+ p2 = new_array_type(new_pointer_type(p1), 25)
+ assert repr(p2) == "<ctype 'int[25][42]'>"
+ p2 = new_array_type(new_pointer_type(p1), None)
+ assert repr(p2) == "<ctype 'int[][42]'>"
+ #
+ py.test.raises(OverflowError,
+ new_array_type, new_pointer_type(p), sys.maxint+1)
+ py.test.raises(OverflowError,
+ new_array_type, new_pointer_type(p), sys.maxint // 3)
+
+ def test_array_instance(self):
+ LENGTH = 14242
+ p = new_primitive_type("int")
+ p1 = new_array_type(new_pointer_type(p), LENGTH)
+ a = newp(p1, None)
+ assert repr(a) == "<cdata 'int[%d]' owning %d bytes>" % (
+ LENGTH, LENGTH * size_of_int())
+ assert len(a) == LENGTH
+ for i in range(LENGTH):
+ assert a[i] == 0
+ py.test.raises(IndexError, "a[LENGTH]")
+ py.test.raises(IndexError, "a[-1]")
+ for i in range(LENGTH):
+ a[i] = i * i + 1
+ for i in range(LENGTH):
+ assert a[i] == i * i + 1
+ e = py.test.raises(IndexError, "a[LENGTH+100] = 500")
+ assert ('(expected %d < %d)' % (LENGTH+100, LENGTH)) in str(e.value)
+
+ def test_array_of_unknown_length_instance(self):
+ p = new_primitive_type("int")
+ p1 = new_array_type(new_pointer_type(p), None)
+ py.test.raises(TypeError, newp, p1, None)
+ py.test.raises(ValueError, newp, p1, -42)
+ a = newp(p1, 42)
+ assert len(a) == 42
+ for i in range(42):
+ a[i] -= i
+ for i in range(42):
+ assert a[i] == -i
+ py.test.raises(IndexError, "a[42]")
+ py.test.raises(IndexError, "a[-1]")
+ py.test.raises(IndexError, "a[42] = 123")
+ py.test.raises(IndexError, "a[-1] = 456")
+
+ def test_array_of_unknown_length_instance_with_initializer(self):
+ p = new_primitive_type("int")
+ p1 = new_array_type(new_pointer_type(p), None)
+ a = newp(p1, range(42))
+ assert len(a) == 42
+ a = newp(p1, tuple(range(142)))
+ assert len(a) == 142
+
+ def test_array_initializer(self):
+ p = new_primitive_type("int")
+ p1 = new_array_type(new_pointer_type(p), None)
+ a = newp(p1, range(100, 142))
+ for i in range(42):
+ assert a[i] == 100 + i
+ #
+ p2 = new_array_type(new_pointer_type(p), 43)
+ a = newp(p2, tuple(range(100, 142)))
+ for i in range(42):
+ assert a[i] == 100 + i
+ assert a[42] == 0 # extra uninitialized item
+
+ def test_array_add(self):
+ p = new_primitive_type("int")
+ p1 = new_array_type(new_pointer_type(p), 5) # int[5]
+ p2 = new_array_type(new_pointer_type(p1), 3) # int[3][5]
+ a = newp(p2, [range(n, n+5) for n in [100, 200, 300]])
+ assert repr(a) == "<cdata 'int[3][5]' owning %d bytes>" % (
+ 3*5*size_of_int(),)
+ assert repr(a + 0) == "<cdata 'int(*)[5]'>"
+ assert repr(a[0]) == "<cdata 'int[5]'>"
+ assert repr((a + 0)[0]) == "<cdata 'int[5]'>"
+ assert repr(a[0] + 0) == "<cdata 'int *'>"
+ assert type(a[0][0]) is int
+ assert type((a[0] + 0)[0]) is int
+
+ def test_cast_primitive_from_cdata(self):
+ p = new_primitive_type("int")
+ n = cast(p, cast(p, -42))
+ assert int(n) == -42
+ #
+ p = new_primitive_type("unsigned int")
+ n = cast(p, cast(p, 42))
+ assert int(n) == 42
+ #
+ p = new_primitive_type("long long")
+ n = cast(p, cast(p, -(1<<60)))
+ assert int(n) == -(1<<60)
+ #
+ p = new_primitive_type("unsigned long long")
+ n = cast(p, cast(p, 1<<63))
+ assert int(n) == 1<<63
+ #
+ p = new_primitive_type("float")
+ n = cast(p, cast(p, 42.5))
+ assert float(n) == 42.5
+ #
+ p = new_primitive_type("char")
+ n = cast(p, cast(p, "A"))
+ assert str(n) == "A"
+
+ def test_new_primitive_from_cdata(self):
+ p = new_primitive_type("int")
+ p1 = new_pointer_type(p)
+ n = newp(p1, cast(p, -42))
+ assert n[0] == -42
+ #
+ p = new_primitive_type("unsigned int")
+ p1 = new_pointer_type(p)
+ n = newp(p1, cast(p, 42))
+ assert n[0] == 42
+ #
+ p = new_primitive_type("float")
+ p1 = new_pointer_type(p)
+ n = newp(p1, cast(p, 42.5))
+ assert n[0] == 42.5
+ #
+ p = new_primitive_type("char")
+ p1 = new_pointer_type(p)
+ n = newp(p1, cast(p, "A"))
+ assert n[0] == "A"
+
+ def test_cast_between_pointers(self):
+ BIntP = new_pointer_type(new_primitive_type("int"))
+ BIntA = new_array_type(BIntP, None)
+ a = newp(BIntA, [40, 41, 42, 43, 44])
+ BShortP = new_pointer_type(new_primitive_type("short"))
+ b = cast(BShortP, a)
+ c = cast(BIntP, b)
+ assert c[3] == 43
+ BLongLong = new_primitive_type("long long")
+ d = cast(BLongLong, c)
+ e = cast(BIntP, d)
+ assert e[3] == 43
+ f = cast(BIntP, int(d))
+ assert f[3] == 43
+ #
+ for null in [0, None]:
+ b = cast(BShortP, null)
+ assert not b
+ c = cast(BIntP, b)
+ assert not c
+ assert int(cast(BLongLong, c)) == 0
+
+ def test_alignof(self):
+ BInt = new_primitive_type("int")
+ assert alignof(BInt) == sizeof(BInt)
+ BPtr = new_pointer_type(BInt)
+ assert alignof(BPtr) == sizeof(BPtr)
+ BArray = new_array_type(BPtr, None)
+ assert alignof(BArray) == alignof(BInt)
+
+ def test_new_struct_type(self):
+ BStruct = new_struct_type("foo")
+ assert repr(BStruct) == "<ctype 'struct foo'>"
+ BPtr = new_pointer_type(BStruct)
+ assert repr(BPtr) == "<ctype 'struct foo *'>"
+
+ def test_new_union_type(self):
+ BUnion = new_union_type("foo")
+ assert repr(BUnion) == "<ctype 'union foo'>"
+ BPtr = new_pointer_type(BUnion)
+ assert repr(BPtr) == "<ctype 'union foo *'>"
+
+ def test_complete_struct(self):
+ BLong = new_primitive_type("long")
+ BChar = new_primitive_type("char")
+ BShort = new_primitive_type("short")
+ BStruct = new_struct_type("foo")
+ assert _getfields(BStruct) is None
+ complete_struct_or_union(BStruct, [('a1', BLong, -1),
+ ('a2', BChar, -1),
+ ('a3', BShort, -1)])
+ d = _getfields(BStruct)
+ assert len(d) == 3
+ assert d[0][0] == 'a1'
+ assert d[0][1].type is BLong
+ assert d[0][1].offset == 0
+ assert d[0][1].bitshift == -1
+ assert d[0][1].bitsize == -1
+ assert d[1][0] == 'a2'
+ assert d[1][1].type is BChar
+ assert d[1][1].offset == sizeof(BLong)
+ assert d[1][1].bitshift == -1
+ assert d[1][1].bitsize == -1
+ assert d[2][0] == 'a3'
+ assert d[2][1].type is BShort
+ assert d[2][1].offset == sizeof(BLong) + sizeof(BShort)
+ assert d[2][1].bitshift == -1
+ assert d[2][1].bitsize == -1
+ assert sizeof(BStruct) == 2 * sizeof(BLong)
+ assert alignof(BStruct) == alignof(BLong)
+
+ def test_complete_union(self):
+ BLong = new_primitive_type("long")
+ BChar = new_primitive_type("char")
+ BUnion = new_union_type("foo")
+ assert _getfields(BUnion) is None
+ complete_struct_or_union(BUnion, [('a1', BLong, -1),
+ ('a2', BChar, -1)])
+ d = _getfields(BUnion)
+ assert len(d) == 2
+ assert d[0][0] == 'a1'
+ assert d[0][1].type is BLong
+ assert d[0][1].offset == 0
+ assert d[1][0] == 'a2'
+ assert d[1][1].type is BChar
+ assert d[1][1].offset == 0
+ assert sizeof(BUnion) == sizeof(BLong)
+ assert alignof(BUnion) == alignof(BLong)
+
+ def test_struct_instance(self):
+ BInt = new_primitive_type("int")
+ BStruct = new_struct_type("foo")
+ BStructPtr = new_pointer_type(BStruct)
+ p = cast(BStructPtr, None)
+ py.test.raises(AttributeError, "p.a1") # opaque
+ complete_struct_or_union(BStruct, [('a1', BInt, -1),
+ ('a2', BInt, -1)])
+ p = newp(BStructPtr, None)
+ s = p[0]
+ assert s.a1 == 0
+ s.a2 = 123
+ assert s.a1 == 0
+ assert s.a2 == 123
+ py.test.raises(OverflowError, "s.a1 = sys.maxint+1")
+ assert s.a1 == 0
+ py.test.raises(AttributeError, "p.foobar")
+ py.test.raises(AttributeError, "s.foobar")
+
+ def test_struct_pointer(self):
+ BInt = new_primitive_type("int")
+ BStruct = new_struct_type("foo")
+ BStructPtr = new_pointer_type(BStruct)
+ complete_struct_or_union(BStruct, [('a1', BInt, -1),
+ ('a2', BInt, -1)])
+ p = newp(BStructPtr, None)
+ assert p.a1 == 0 # read/write via the pointer (C equivalent: '->')
+ p.a2 = 123
+ assert p.a1 == 0
+ assert p.a2 == 123
+
+ def test_struct_init_list(self):
+ BInt = new_primitive_type("int")
+ BStruct = new_struct_type("foo")
+ BStructPtr = new_pointer_type(BStruct)
+ complete_struct_or_union(BStruct, [('a1', BInt, -1),
+ ('a2', BInt, -1),
+ ('a3', BInt, -1)])
+ s = newp(BStructPtr, [123, 456])
+ assert s.a1 == 123
+ assert s.a2 == 456
+ assert s.a3 == 0
+
+ def test_array_in_struct(self):
+ BInt = new_primitive_type("int")
+ BStruct = new_struct_type("foo")
+ BArrayInt5 = new_array_type(new_pointer_type(BInt), 5)
+ complete_struct_or_union(BStruct, [('a1', BArrayInt5, -1)])
+ s = newp(new_pointer_type(BStruct), [[20, 24, 27, 29, 30]])
+ assert s.a1[2] == 27
+ assert repr(s.a1) == "<cdata 'int[5]'>"
+
+ def test_offsetof(self):
+ BInt = new_primitive_type("int")
+ BStruct = new_struct_type("foo")
+ py.test.raises(TypeError, offsetof, BInt, "abc")
+ py.test.raises(TypeError, offsetof, BStruct, "abc")
+ complete_struct_or_union(BStruct, [('abc', BInt, -1), ('def', BInt,
-1)])
+ assert offsetof(BStruct, 'abc') == 0
+ assert offsetof(BStruct, 'def') == size_of_int()
+ py.test.raises(KeyError, offsetof, BStruct, "ghi")
+
+ def test_function_type(self):
+ BInt = new_primitive_type("int")
+ BFunc = new_function_type((BInt, BInt), BInt, False)
+ assert repr(BFunc) == "<ctype 'int(*)(int, int)'>"
+ BFunc2 = new_function_type((), BFunc, False)
+ assert repr(BFunc2) == "<ctype 'int(*(*)())(int, int)'>"
+
+ def test_function_type_taking_struct(self):
+ BChar = new_primitive_type("char")
+ BShort = new_primitive_type("short")
+ BStruct = new_struct_type("foo")
+ complete_struct_or_union(BStruct, [('a1', BChar, -1),
+ ('a2', BShort, -1)])
+ BFunc = new_function_type((BStruct,), BShort, False)
+ assert repr(BFunc) == "<ctype 'short(*)(struct foo)'>"
+
+ def test_function_void_result(self):
+ BVoid = new_void_type()
+ BInt = new_primitive_type("int")
+ BFunc = new_function_type((BInt, BInt), BVoid, False)
+ assert repr(BFunc) == "<ctype 'void(*)(int, int)'>"
+
+ def test_call_function_0(self):
+ BSignedChar = new_primitive_type("signed char")
+ BFunc0 = new_function_type((BSignedChar, BSignedChar), BSignedChar,
False)
+ f = cast(BFunc0, _testfunc(0))
+ assert f(40, 2) == 42
+ assert f(-100, -100) == -200 + 256
+ py.test.raises(OverflowError, f, 128, 0)
+ py.test.raises(OverflowError, f, 0, 128)
+
+ def test_call_function_1(self):
+ BInt = new_primitive_type("int")
+ BLong = new_primitive_type("long")
+ BFunc1 = new_function_type((BInt, BLong), BLong, False)
+ f = cast(BFunc1, _testfunc(1))
+ assert f(40, 2) == 42
+ assert f(-100, -100) == -200
+ int_max = (1 << (8*size_of_int()-1)) - 1
+ long_max = (1 << (8*size_of_long()-1)) - 1
+ if int_max == long_max:
+ assert f(int_max, 1) == - int_max - 1
+ else:
+ assert f(int_max, 1) == int_max + 1
+
+ def test_call_function_2(self):
+ BLongLong = new_primitive_type("long long")
+ BFunc2 = new_function_type((BLongLong, BLongLong), BLongLong, False)
+ f = cast(BFunc2, _testfunc(2))
+ longlong_max = (1 << (8*sizeof(BLongLong)-1)) - 1
+ assert f(longlong_max - 42, 42) == longlong_max
+ assert f(43, longlong_max - 42) == - longlong_max - 1
+
+ def test_call_function_3(self):
+ BFloat = new_primitive_type("float")
+ BDouble = new_primitive_type("double")
+ BFunc3 = new_function_type((BFloat, BDouble), BDouble, False)
+ f = cast(BFunc3, _testfunc(3))
+ assert f(1.25, 5.1) == 1.25 + 5.1 # exact
+ res = f(1.3, 5.1)
+ assert res != 6.4 and abs(res - 6.4) < 1E-5 # inexact
+
+ def test_call_function_4(self):
+ BFloat = new_primitive_type("float")
+ BDouble = new_primitive_type("double")
+ BFunc4 = new_function_type((BFloat, BDouble), BFloat, False)
+ f = cast(BFunc4, _testfunc(4))
+ res = f(1.25, 5.1)
+ assert res != 6.35 and abs(res - 6.35) < 1E-5 # inexact
+
+ def test_call_function_5(self):
+ BVoid = new_void_type()
+ BFunc5 = new_function_type((), BVoid, False)
+ f = cast(BFunc5, _testfunc(5))
+ f() # did not crash
+
+ def test_call_function_6(self):
+ BInt = new_primitive_type("int")
+ BIntPtr = new_pointer_type(BInt)
+ BFunc6 = new_function_type((BIntPtr,), BIntPtr, False)
+ f = cast(BFunc6, _testfunc(6))
+ x = newp(BIntPtr, 42)
+ res = f(x)
+ assert typeof(res) is BIntPtr
+ assert res[0] == 42 - 1000
+ #
+ BIntArray = new_array_type(BIntPtr, None)
+ BFunc6bis = new_function_type((BIntArray,), BIntPtr, False)
+ f = cast(BFunc6bis, _testfunc(6))
+ #
+ py.test.raises(TypeError, f, [142])
+ #
+ x = newp(BIntArray, [242])
+ res = f(x)
+ assert typeof(res) is BIntPtr
+ assert res[0] == 242 - 1000
+
+ def test_call_function_7(self):
+ BChar = new_primitive_type("char")
+ BShort = new_primitive_type("short")
+ BStruct = new_struct_type("foo")
+ BStructPtr = new_pointer_type(BStruct)
+ complete_struct_or_union(BStruct, [('a1', BChar, -1),
+ ('a2', BShort, -1)])
+ BFunc7 = new_function_type((BStruct,), BShort, False)
+ f = cast(BFunc7, _testfunc(7))
+ res = f({'a1': 'A', 'a2': -4042})
+ assert res == -4042 + ord('A')
+ #
+ x = newp(BStructPtr, {'a1': 'A', 'a2': -4042})
+ res = f(x[0])
+ assert res == -4042 + ord('A')
+
+ def test_call_function_9(self):
+ BInt = new_primitive_type("int")
+ BFunc9 = new_function_type((BInt,), BInt, True) # vararg
+ f = cast(BFunc9, _testfunc(9))
+ assert f(0) == 0
+ assert f(1, cast(BInt, 42)) == 42
+ assert f(2, cast(BInt, 40), cast(BInt, 2)) == 42
+ py.test.raises(TypeError, f, 1, 42)
+
+ def test_new_charp(self):
+ BChar = new_primitive_type("char")
+ BCharP = new_pointer_type(BChar)
+ BCharA = new_array_type(BCharP, None)
+ x = newp(BCharA, 42)
+ assert len(x) == 42
+ x = newp(BCharA, "foobar")
+ assert len(x) == 7
+
+ def test_load_and_call_function(self):
+ BChar = new_primitive_type("char")
+ BCharP = new_pointer_type(BChar)
+ BLong = new_primitive_type("long")
+ BFunc = new_function_type((BCharP,), BLong, False)
+ ll = self.b._find_and_load_library()
+ strlen = ll.load_function(BFunc, "strlen")
+ input = newp(new_array_type(BCharP, None), "foobar")
+ assert strlen(input) == 6
+ #
+ assert strlen("foobarbaz") == 9
+
+ def test_read_variable(self):
+ if sys.platform == 'win32':
+ py.test.skip("untested")
+ BVoidP = new_pointer_type(new_void_type())
+ ll = self.b._find_and_load_library()
+ stderr = ll.read_variable(BVoidP, "stderr")
+ assert stderr == cast(BVoidP, _testfunc(8))
+
+ def test_write_variable(self):
+ if sys.platform == 'win32':
+ py.test.skip("untested")
+ BVoidP = new_pointer_type(new_void_type())
+ ll = self.b._find_and_load_library()
+ stderr = ll.read_variable(BVoidP, "stderr")
+ ll.write_variable(BVoidP, "stderr", None)
+ assert ll.read_variable(BVoidP, "stderr") is None
+ ll.write_variable(BVoidP, "stderr", stderr)
+ assert ll.read_variable(BVoidP, "stderr") == stderr
+
+ def test_callback(self):
+ BInt = new_primitive_type("int")
+ def make_callback(self):
+ def cb(n):
+ return n + 1
+ BFunc = new_function_type((BInt,), BInt, False)
+ return callback(BFunc, cb) # 'cb' and 'BFunc' go out of scope
+ f = make_callback()
+ assert f(-142) == -141
+
+ def test_a_lot_of_callbacks(self):
+ BInt = new_primitive_type("int")
+ def make_callback(m):
+ def cb(n):
+ return n + m
+ BFunc = new_function_type((BInt,), BInt, False)
+ return callback(BFunc, cb) # 'cb' and 'BFunc' go out of scope
+ #
+ flist = [make_callback(i) for i in range(10000)]
+ for i, f in enumerate(flist):
+ assert f(-142) == -142 + i
+
+ def test_enum_type(self):
+ BEnum = new_enum_type("foo", (), ())
+ assert repr(BEnum) == "<ctype 'enum foo'>"
+ assert _getfields(BEnum) == []
+ #
+ BEnum = new_enum_type("foo", ('def', 'c', 'ab'), (0, 1, -20))
+ assert _getfields(BEnum) == [(-20, 'ab'), (0, 'def'), (1, 'c')]
+
+ def test_cast_to_enum(self):
+ BEnum = new_enum_type("foo", ('def', 'c', 'ab'), (0, 1, -20))
+ e = cast(BEnum, 0)
+ assert repr(e) == "<cdata 'enum foo'>"
+ assert str(e) == 'def'
+ assert str(cast(BEnum, -20)) == 'ab'
+ assert str(cast(BEnum, 'c')) == 'c'
+ assert int(cast(BEnum, 'c')) == 1
+ assert int(cast(BEnum, 'def')) == 0
+ assert int(cast(BEnum, -242 + 2**128)) == -242
+ assert str(cast(BEnum, -242 + 2**128)) == '#-242'
+ assert str(cast(BEnum, '#-20')) == 'ab'
+
+ def test_enum_in_struct(self):
+ BEnum = new_enum_type("foo", ('def', 'c', 'ab'), (0, 1, -20))
+ BStruct = new_struct_type("bar")
+ BStructPtr = new_pointer_type(BStruct)
+ complete_struct_or_union(BStruct, [('a1', BEnum, -1)])
+ p = newp(BStructPtr, [-20])
+ assert p.a1 == "ab"
+ p = newp(BStructPtr, ["c"])
+ assert p.a1 == "c"
+ e = py.test.raises(TypeError, newp, BStructPtr, [None])
+ assert "must be a str or int, not NoneType" in str(e.value)
+
+ def test_struct_with_bitfields(self):
+ BLong = new_primitive_type("long")
+ BStruct = new_struct_type("foo")
+ LONGBITS = 8 * sizeof(BLong)
+ complete_struct_or_union(BStruct, [('a1', BLong, 1),
+ ('a2', BLong, 2),
+ ('a3', BLong, 3),
+ ('a4', BLong, LONGBITS - 5)])
+ d = _getfields(BStruct)
+ assert d[0][1].offset == d[1][1].offset == d[2][1].offset == 0
+ assert d[3][1].offset == sizeof(BLong)
+ assert d[0][1].bitshift == 0
+ assert d[0][1].bitsize == 1
+ assert d[1][1].bitshift == 1
+ assert d[1][1].bitsize == 2
+ assert d[2][1].bitshift == 3
+ assert d[2][1].bitsize == 3
+ assert d[3][1].bitshift == 0
+ assert d[3][1].bitsize == LONGBITS - 5
+ assert sizeof(BStruct) == 2 * sizeof(BLong)
+ assert alignof(BStruct) == alignof(BLong)
+
+ def test_bitfield_instance(self):
+ BInt = new_primitive_type("int")
+ BUnsignedInt = new_primitive_type("unsigned int")
+ BStruct = new_struct_type("foo")
+ complete_struct_or_union(BStruct, [('a1', BInt, 1),
+ ('a2', BUnsignedInt, 2),
+ ('a3', BInt, 3)])
+ p = newp(new_pointer_type(BStruct), None)
+ p.a1 = -1
+ assert p.a1 == -1
+ p.a1 = 0
+ py.test.raises(OverflowError, "p.a1 = 2")
+ assert p.a1 == 0
+ #
+ p.a1 = -1
+ p.a2 = 3
+ p.a3 = -4
+ py.test.raises(OverflowError, "p.a3 = 4")
+ e = py.test.raises(OverflowError, "p.a3 = -5")
+ assert str(e.value) == ("value -5 outside the range allowed by the "
+ "bit field width: -4 <= x <= 3")
+ assert p.a1 == -1 and p.a2 == 3 and p.a3 == -4
+ #
+ # special case for convenience: "int x:1", while normally signed,
+ # allows also setting the value "1" (it still gets read back as -1)
+ p.a1 = 1
+ assert p.a1 == -1
+ e = py.test.raises(OverflowError, "p.a1 = -2")
+ assert str(e.value) == ("value -2 outside the range allowed by the "
+ "bit field width: -1 <= x <= 1")
+
+ def test_bitfield_instance_init(self):
+ BInt = new_primitive_type("int")
+ BStruct = new_struct_type("foo")
+ complete_struct_or_union(BStruct, [('a1', BInt, 1)])
+ py.test.raises(NotImplementedError, newp, new_pointer_type(BStruct),
[-1])
+
+ def test_gc(self):
+ from gc import collect
+ BInt = new_primitive_type("int")
+ n = cast(BInt, 123)
+ py.test.raises(TypeError, gc, n, 5)
+ destroyed = []
+ m = gc(n, destroyed.append)
+ assert repr(m) == "<cdata 'int' with destructor>"
+ assert destroyed == []
+ del m; collect()
+ assert len(destroyed) == 1
+ assert int(destroyed[0]) == 123
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit