You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
374 lines
12 KiB
374 lines
12 KiB
import py, sys, os
|
|
import subprocess, weakref
|
|
from cffi import FFI
|
|
from cffi.backend_ctypes import CTypesBackend
|
|
from testing.support import u
|
|
|
|
|
|
SOURCE = """\
|
|
#include <errno.h>
|
|
|
|
#ifdef _WIN32
|
|
#define EXPORT __declspec(dllexport)
|
|
#else
|
|
#define EXPORT
|
|
#endif
|
|
|
|
EXPORT int test_getting_errno(void) {
|
|
errno = 123;
|
|
return -1;
|
|
}
|
|
|
|
EXPORT int test_setting_errno(void) {
|
|
return errno;
|
|
};
|
|
|
|
typedef struct {
|
|
long x;
|
|
long y;
|
|
} POINT;
|
|
|
|
typedef struct {
|
|
long left;
|
|
long top;
|
|
long right;
|
|
long bottom;
|
|
} RECT;
|
|
|
|
|
|
EXPORT int PointInRect(RECT *prc, POINT pt)
|
|
{
|
|
if (pt.x < prc->left)
|
|
return 0;
|
|
if (pt.x > prc->right)
|
|
return 0;
|
|
if (pt.y < prc->top)
|
|
return 0;
|
|
if (pt.y > prc->bottom)
|
|
return 0;
|
|
return 1;
|
|
};
|
|
|
|
EXPORT long left = 10;
|
|
EXPORT long top = 20;
|
|
EXPORT long right = 30;
|
|
EXPORT long bottom = 40;
|
|
|
|
EXPORT RECT ReturnRect(int i, RECT ar, RECT* br, POINT cp, RECT dr,
|
|
RECT *er, POINT fp, RECT gr)
|
|
{
|
|
/*Check input */
|
|
if (ar.left + br->left + dr.left + er->left + gr.left != left * 5)
|
|
{
|
|
ar.left = 100;
|
|
return ar;
|
|
}
|
|
if (ar.right + br->right + dr.right + er->right + gr.right != right * 5)
|
|
{
|
|
ar.right = 100;
|
|
return ar;
|
|
}
|
|
if (cp.x != fp.x)
|
|
{
|
|
ar.left = -100;
|
|
}
|
|
if (cp.y != fp.y)
|
|
{
|
|
ar.left = -200;
|
|
}
|
|
switch(i)
|
|
{
|
|
case 0:
|
|
return ar;
|
|
break;
|
|
case 1:
|
|
return dr;
|
|
break;
|
|
case 2:
|
|
return gr;
|
|
break;
|
|
|
|
}
|
|
return ar;
|
|
}
|
|
|
|
EXPORT int my_array[7] = {0, 1, 2, 3, 4, 5, 6};
|
|
|
|
EXPORT unsigned short foo_2bytes(unsigned short a)
|
|
{
|
|
return (unsigned short)(a + 42);
|
|
}
|
|
EXPORT unsigned int foo_4bytes(unsigned int a)
|
|
{
|
|
return (unsigned int)(a + 42);
|
|
}
|
|
|
|
EXPORT void modify_struct_value(RECT r)
|
|
{
|
|
r.left = r.right = r.top = r.bottom = 500;
|
|
}
|
|
"""
|
|
|
|
class TestOwnLib(object):
|
|
Backend = CTypesBackend
|
|
|
|
def setup_class(cls):
|
|
cls.module = None
|
|
from testing.udir import udir
|
|
udir.join('testownlib.c').write(SOURCE)
|
|
if sys.platform == 'win32':
|
|
# did we already build it?
|
|
if cls.Backend is CTypesBackend:
|
|
dll_path = str(udir) + '\\testownlib1.dll' # only ascii for the ctypes backend
|
|
else:
|
|
dll_path = str(udir) + '\\' + (u+'testownlib\u03be.dll') # non-ascii char
|
|
if os.path.exists(dll_path):
|
|
cls.module = dll_path
|
|
return
|
|
# try (not too hard) to find the version used to compile this python
|
|
# no mingw
|
|
from distutils.msvc9compiler import get_build_version
|
|
version = get_build_version()
|
|
toolskey = "VS%0.f0COMNTOOLS" % version
|
|
toolsdir = os.environ.get(toolskey, None)
|
|
if toolsdir is None:
|
|
return
|
|
productdir = os.path.join(toolsdir, os.pardir, os.pardir, "VC")
|
|
productdir = os.path.abspath(productdir)
|
|
vcvarsall = os.path.join(productdir, "vcvarsall.bat")
|
|
# 64?
|
|
arch = 'x86'
|
|
if sys.maxsize > 2**32:
|
|
arch = 'amd64'
|
|
if os.path.isfile(vcvarsall):
|
|
cmd = '"%s" %s' % (vcvarsall, arch) + ' & cl.exe testownlib.c ' \
|
|
' /LD /Fetestownlib.dll'
|
|
subprocess.check_call(cmd, cwd = str(udir), shell=True)
|
|
os.rename(str(udir) + '\\testownlib.dll', dll_path)
|
|
cls.module = dll_path
|
|
else:
|
|
encoded = None
|
|
if cls.Backend is not CTypesBackend:
|
|
try:
|
|
unicode_name = u+'testownlibcaf\xe9'
|
|
encoded = unicode_name.encode(sys.getfilesystemencoding())
|
|
if sys.version_info >= (3,):
|
|
encoded = str(unicode_name)
|
|
except UnicodeEncodeError:
|
|
pass
|
|
if encoded is None:
|
|
unicode_name = u+'testownlib'
|
|
encoded = str(unicode_name)
|
|
subprocess.check_call(
|
|
"cc testownlib.c -shared -fPIC -o '%s.so'" % (encoded,),
|
|
cwd=str(udir), shell=True)
|
|
cls.module = os.path.join(str(udir), unicode_name + (u+'.so'))
|
|
print(repr(cls.module))
|
|
|
|
def test_getting_errno(self):
|
|
if self.module is None:
|
|
py.test.skip("fix the auto-generation of the tiny test lib")
|
|
if sys.platform == 'win32':
|
|
py.test.skip("fails, errno at multiple addresses")
|
|
ffi = FFI(backend=self.Backend())
|
|
ffi.cdef("""
|
|
int test_getting_errno(void);
|
|
""")
|
|
ownlib = ffi.dlopen(self.module)
|
|
res = ownlib.test_getting_errno()
|
|
assert res == -1
|
|
assert ffi.errno == 123
|
|
|
|
def test_setting_errno(self):
|
|
if self.module is None:
|
|
py.test.skip("fix the auto-generation of the tiny test lib")
|
|
if sys.platform == 'win32':
|
|
py.test.skip("fails, errno at multiple addresses")
|
|
if self.Backend is CTypesBackend and '__pypy__' in sys.modules:
|
|
py.test.skip("XXX errno issue with ctypes on pypy?")
|
|
ffi = FFI(backend=self.Backend())
|
|
ffi.cdef("""
|
|
int test_setting_errno(void);
|
|
""")
|
|
ownlib = ffi.dlopen(self.module)
|
|
ffi.errno = 42
|
|
res = ownlib.test_setting_errno()
|
|
assert res == 42
|
|
assert ffi.errno == 42
|
|
|
|
def test_my_array_7(self):
|
|
if self.module is None:
|
|
py.test.skip("fix the auto-generation of the tiny test lib")
|
|
ffi = FFI(backend=self.Backend())
|
|
ffi.cdef("""
|
|
int my_array[7];
|
|
""")
|
|
ownlib = ffi.dlopen(self.module)
|
|
for i in range(7):
|
|
assert ownlib.my_array[i] == i
|
|
assert len(ownlib.my_array) == 7
|
|
if self.Backend is CTypesBackend:
|
|
py.test.skip("not supported by the ctypes backend")
|
|
ownlib.my_array = list(range(10, 17))
|
|
for i in range(7):
|
|
assert ownlib.my_array[i] == 10 + i
|
|
ownlib.my_array = list(range(7))
|
|
for i in range(7):
|
|
assert ownlib.my_array[i] == i
|
|
|
|
def test_my_array_no_length(self):
|
|
if self.module is None:
|
|
py.test.skip("fix the auto-generation of the tiny test lib")
|
|
if self.Backend is CTypesBackend:
|
|
py.test.skip("not supported by the ctypes backend")
|
|
ffi = FFI(backend=self.Backend())
|
|
ffi.cdef("""
|
|
int my_array[];
|
|
""")
|
|
ownlib = ffi.dlopen(self.module)
|
|
for i in range(7):
|
|
assert ownlib.my_array[i] == i
|
|
py.test.raises(TypeError, len, ownlib.my_array)
|
|
ownlib.my_array = list(range(10, 17))
|
|
for i in range(7):
|
|
assert ownlib.my_array[i] == 10 + i
|
|
ownlib.my_array = list(range(7))
|
|
for i in range(7):
|
|
assert ownlib.my_array[i] == i
|
|
|
|
def test_keepalive_lib(self):
|
|
if self.module is None:
|
|
py.test.skip("fix the auto-generation of the tiny test lib")
|
|
ffi = FFI(backend=self.Backend())
|
|
ffi.cdef("""
|
|
int test_getting_errno(void);
|
|
""")
|
|
ownlib = ffi.dlopen(self.module)
|
|
ffi_r = weakref.ref(ffi)
|
|
ownlib_r = weakref.ref(ownlib)
|
|
func = ownlib.test_getting_errno
|
|
del ffi
|
|
import gc; gc.collect() # ownlib stays alive
|
|
assert ownlib_r() is not None
|
|
assert ffi_r() is not None # kept alive by ownlib
|
|
res = func()
|
|
assert res == -1
|
|
|
|
def test_keepalive_ffi(self):
|
|
if self.module is None:
|
|
py.test.skip("fix the auto-generation of the tiny test lib")
|
|
ffi = FFI(backend=self.Backend())
|
|
ffi.cdef("""
|
|
int test_getting_errno(void);
|
|
""")
|
|
ownlib = ffi.dlopen(self.module)
|
|
ffi_r = weakref.ref(ffi)
|
|
ownlib_r = weakref.ref(ownlib)
|
|
func = ownlib.test_getting_errno
|
|
del ownlib
|
|
import gc; gc.collect() # ffi stays alive
|
|
assert ffi_r() is not None
|
|
assert ownlib_r() is not None # kept alive by ffi
|
|
res = func()
|
|
assert res == -1
|
|
if sys.platform != 'win32': # else, errno at multiple addresses
|
|
assert ffi.errno == 123
|
|
|
|
def test_struct_by_value(self):
|
|
if self.module is None:
|
|
py.test.skip("fix the auto-generation of the tiny test lib")
|
|
ffi = FFI(backend=self.Backend())
|
|
ffi.cdef("""
|
|
typedef struct {
|
|
long x;
|
|
long y;
|
|
} POINT;
|
|
|
|
typedef struct {
|
|
long left;
|
|
long top;
|
|
long right;
|
|
long bottom;
|
|
} RECT;
|
|
|
|
long left, top, right, bottom;
|
|
|
|
RECT ReturnRect(int i, RECT ar, RECT* br, POINT cp, RECT dr,
|
|
RECT *er, POINT fp, RECT gr);
|
|
""")
|
|
ownlib = ffi.dlopen(self.module)
|
|
|
|
rect = ffi.new('RECT[1]')
|
|
pt = ffi.new('POINT[1]')
|
|
pt[0].x = 15
|
|
pt[0].y = 25
|
|
rect[0].left = ownlib.left
|
|
rect[0].right = ownlib.right
|
|
rect[0].top = ownlib.top
|
|
rect[0].bottom = ownlib.bottom
|
|
|
|
for i in range(4):
|
|
ret = ownlib.ReturnRect(i, rect[0], rect, pt[0], rect[0],
|
|
rect, pt[0], rect[0])
|
|
assert ret.left == ownlib.left
|
|
assert ret.right == ownlib.right
|
|
assert ret.top == ownlib.top
|
|
assert ret.bottom == ownlib.bottom
|
|
|
|
def test_addressof_lib(self):
|
|
if self.module is None:
|
|
py.test.skip("fix the auto-generation of the tiny test lib")
|
|
if self.Backend is CTypesBackend:
|
|
py.test.skip("not implemented with the ctypes backend")
|
|
ffi = FFI(backend=self.Backend())
|
|
ffi.cdef("long left; int test_getting_errno(void);")
|
|
lib = ffi.dlopen(self.module)
|
|
lib.left = 123456
|
|
p = ffi.addressof(lib, "left")
|
|
assert ffi.typeof(p) == ffi.typeof("long *")
|
|
assert p[0] == 123456
|
|
p[0] += 1
|
|
assert lib.left == 123457
|
|
pfn = ffi.addressof(lib, "test_getting_errno")
|
|
assert ffi.typeof(pfn) == ffi.typeof("int(*)(void)")
|
|
assert pfn == lib.test_getting_errno
|
|
|
|
def test_char16_char32_t(self):
|
|
if self.module is None:
|
|
py.test.skip("fix the auto-generation of the tiny test lib")
|
|
if self.Backend is CTypesBackend:
|
|
py.test.skip("not implemented with the ctypes backend")
|
|
ffi = FFI(backend=self.Backend())
|
|
ffi.cdef("""
|
|
char16_t foo_2bytes(char16_t);
|
|
char32_t foo_4bytes(char32_t);
|
|
""")
|
|
lib = ffi.dlopen(self.module)
|
|
assert lib.foo_2bytes(u+'\u1234') == u+'\u125e'
|
|
assert lib.foo_4bytes(u+'\u1234') == u+'\u125e'
|
|
assert lib.foo_4bytes(u+'\U00012345') == u+'\U0001236f'
|
|
|
|
def test_modify_struct_value(self):
|
|
if self.module is None:
|
|
py.test.skip("fix the auto-generation of the tiny test lib")
|
|
if self.Backend is CTypesBackend:
|
|
py.test.skip("fails with the ctypes backend on some architectures")
|
|
ffi = FFI(backend=self.Backend())
|
|
ffi.cdef("""
|
|
typedef struct {
|
|
long left;
|
|
long top;
|
|
long right;
|
|
long bottom;
|
|
} RECT;
|
|
|
|
void modify_struct_value(RECT r);
|
|
""")
|
|
lib = ffi.dlopen(self.module)
|
|
s = ffi.new("RECT *", [11, 22, 33, 44])
|
|
lib.modify_struct_value(s[0])
|
|
assert s.left == 11
|
|
assert s.top == 22
|
|
assert s.right == 33
|
|
assert s.bottom == 44
|