1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
|
from __future__ import with_statement
"""
This file is OBSCURE. Really. The purpose is to avoid copying and changing
'test_c.py' from cffi/c/ in the original CFFI repository:
https://foss.heptapod.net/pypy/cffi/
Adding a test here involves:
1. add a test to cffi/c/test.py
- if you need a C function to call, add it into _cffi_backend.c
as a testfuncNN().
2. have it pass when you run 'py.test test_c.py' in cffi
3. check in and (if you can) push the changes
4. copy test_c.py into _backend_test.py here, killing the few lines of header
- if you added a C function, it goes into _test_lib.c here
- if you could complete step 3, try running 'python2 pytest.py test_file.py' here
5. make the test pass in pypy ('python2 pytest.py test_c.py')
"""
import py, sys, ctypes
from rpython.tool.udir import udir
from pypy.interpreter import gateway
from pypy.module._cffi_backend.moduledef import Module
from pypy.module._cffi_backend.newtype import _clean_cache, UniqueCache
from rpython.translator import cdir
from rpython.translator.platform import host
from rpython.translator.tool.cbuild import ExternalCompilationInfo
from .. import VERSION as TEST_VERSION
class AppTestC(object):
"""Populated below, hack hack hack."""
spaceconfig = dict(usemodules=('_cffi_backend', '_io', 'array'))
def setup_class(cls):
if cls.runappdirect:
_cffi_backend = py.test.importorskip('_cffi_backend')
if _cffi_backend.__version__ != TEST_VERSION:
py.test.skip(
"These tests are for cffi version %s, this Python "
"has version %s installed" %
(TEST_VERSION, _cffi_backend.__version__))
testfuncs_w = []
keepalive_funcs = []
UniqueCache.for_testing = True
test_lib_c = tmpdir.join('_test_lib.c')
src_test_lib_c = py.path.local(__file__).dirpath().join('_test_lib.c')
src_test_lib_c.copy(test_lib_c)
eci = ExternalCompilationInfo(include_dirs=[cdir])
test_lib = str(host.compile([test_lib_c], eci, standalone=False))
cdll = ctypes.CDLL(test_lib)
cdll.gettestfunc.restype = ctypes.c_void_p
space = cls.space
if cls.runappdirect:
def find_and_load_library_for_test(name, is_global=False):
if name is None:
path = None
else:
import ctypes.util
path = ctypes.util.find_library(name)
if path is None and name == 'c' and sys.platform == 'win32':
skip("dlopen(None) cannot work on Windows")
import _cffi_backend
return _cffi_backend.load_library(path, is_global)
def w_testfunc_for_test(num):
import ctypes
cdll = ctypes.CDLL(str(self.test_lib))
cdll.gettestfunc.restype = ctypes.c_void_p
return cdll.gettestfunc(num)
cls.w_test_lib = space.wrap(test_lib)
cls.w_func = find_and_load_library_for_test
cls.w_testfunc = w_testfunc_for_test
else:
def find_and_load_library_for_test(space, w_name, w_is_global=None):
if w_is_global is None:
w_is_global = space.wrap(0)
if space.is_w(w_name, space.w_None):
path = None
w_name = space.newtext('None')
else:
import ctypes.util
path = ctypes.util.find_library(space.text_w(w_name))
if path is None and sys.platform == 'win32':
py.test.skip("cannot find library '%s'" % (space.text_w(w_name),))
return space.appexec([space.wrap(path), w_is_global],
"""(path, is_global):
import _cffi_backend
return _cffi_backend.load_library(path, is_global)""")
def testfunc_for_test(space, w_num):
if hasattr(space, 'int_w'):
w_num = space.int_w(w_num)
addr = cdll.gettestfunc(w_num)
return space.wrap(addr)
cls.w_func = space.wrap(gateway.interp2app(find_and_load_library_for_test))
cls.w_testfunc = space.wrap(gateway.interp2app(testfunc_for_test))
cls.w_zz_init = space.appexec(
[space.wrap(str(tmpdir)), cls.w_func, cls.w_testfunc,
space.wrap(sys.version[:3])],
"""(path, func, testfunc, underlying_version):
import sys
sys.path.append(path)
is_musl = False
import _all_test_c
_all_test_c.PY_DOT_PY = underlying_version
_all_test_c.find_and_load_library = func
_all_test_c._testfunc = testfunc
""")
def teardown_method(self, method):
_clean_cache(self.space)
def teardown_class(cls):
UniqueCache.for_testing = False
all_names = ', '.join(Module.interpleveldefs.keys())
backend_test_c = py.path.local(__file__).join('..', '_backend_test_c.py')
lst = []
with backend_test_c.open('r') as f:
for line in f:
if line.startswith('def test_'):
line = line[4:]
line = line[:line.index('():')]
lst.append(line)
tmpdir = udir.join('test_c').ensure(dir=1)
tmpname = tmpdir.join('_test_c.py')
with tmpname.open('w') as f:
print >> f, "import pytest"
for func in lst:
print >> f, 'def %s(self):' % (func,)
print >> f, ' import _all_test_c'
print >> f, ' try:'
print >> f, ' _all_test_c.%s()' % (func,)
print >> f, ' except BaseException as e:'
print >> f, ' if "Skipped" in str(type(e)):'
print >> f, ' skip(e.msg)'
print >> f, ' raise'
tmpname2 = tmpdir.join('_all_test_c.py')
with tmpname2.open('w') as f:
print >> f, 'import sys'
print >> f, 'from _cffi_backend import %s' % all_names
print >> f, 'is_musl = False'
print >> f, 'class py:'
print >> f, ' class test:'
print >> f, ' raises = staticmethod(raises)'
print >> f, ' skip = staticmethod(skip)'
print >> f, 'pytest = py.test'
print >> f, backend_test_c.read()
mod = tmpname.pyimport()
for key, value in mod.__dict__.items():
if key.startswith('test_'):
setattr(AppTestC, key, value)
|