diff options
Diffstat (limited to 'testing/cffi1/test_zdist.py')
-rw-r--r-- | testing/cffi1/test_zdist.py | 426 |
1 files changed, 426 insertions, 0 deletions
diff --git a/testing/cffi1/test_zdist.py b/testing/cffi1/test_zdist.py new file mode 100644 index 0000000..efc1d86 --- /dev/null +++ b/testing/cffi1/test_zdist.py @@ -0,0 +1,426 @@ +import sys, os, py +import subprocess +import cffi +from testing.udir import udir +from shutil import rmtree +from tempfile import mkdtemp + + +def chdir_to_tmp(f): + f.chdir_to_tmp = True + return f + +def from_outside(f): + f.chdir_to_tmp = False + return f + + +class TestDist(object): + + def setup_method(self, meth): + self.executable = os.path.abspath(sys.executable) + self.rootdir = os.path.abspath(os.path.dirname(os.path.dirname( + cffi.__file__))) + self.udir = udir.join(meth.__name__) + os.mkdir(str(self.udir)) + if meth.chdir_to_tmp: + self.saved_cwd = os.getcwd() + os.chdir(str(self.udir)) + + def teardown_method(self, meth): + if hasattr(self, 'saved_cwd'): + os.chdir(self.saved_cwd) + + def run(self, args, cwd=None): + env = os.environ.copy() + # a horrible hack to prevent distutils from finding ~/.pydistutils.cfg + # (there is the --no-user-cfg option, but not in Python 2.6...) + # NOTE: pointing $HOME to a nonexistent directory can break certain things + # that look there for configuration (like ccache). + tmp_home = mkdtemp() + assert tmp_home != None, "cannot create temporary homedir" + env['HOME'] = tmp_home + if cwd is None: + newpath = self.rootdir + if 'PYTHONPATH' in env: + newpath += os.pathsep + env['PYTHONPATH'] + env['PYTHONPATH'] = newpath + try: + subprocess.check_call([self.executable] + args, cwd=cwd, env=env) + finally: + rmtree(tmp_home) + + def _prepare_setuptools(self): + if hasattr(TestDist, '_setuptools_ready'): + return + try: + import setuptools + except ImportError: + py.test.skip("setuptools not found") + if os.path.exists(os.path.join(self.rootdir, 'setup.py')): + self.run(['setup.py', 'egg_info'], cwd=self.rootdir) + TestDist._setuptools_ready = True + + def check_produced_files(self, content, curdir=None): + if curdir is None: + curdir = str(self.udir) + found_so = None + for name in os.listdir(curdir): + if (name.endswith('.so') or name.endswith('.pyd') or + name.endswith('.dylib') or name.endswith('.dll')): + found_so = os.path.join(curdir, name) + # foo.so => foo + parts = name.split('.') + del parts[-1] + if len(parts) > 1 and parts[-1] != 'bar': + # foo.cpython-34m.so => foo, but foo.bar.so => foo.bar + del parts[-1] + name = '.'.join(parts) + # foo_d => foo (Python 2 debug builds) + if name.endswith('_d') and hasattr(sys, 'gettotalrefcount'): + name = name[:-2] + name += '.SO' + if name.startswith('pycparser') and name.endswith('.egg'): + continue # no clue why this shows up sometimes and not others + if name == '.eggs': + continue # seems new in 3.5, ignore it + assert name in content, "found unexpected file %r" % ( + os.path.join(curdir, name),) + value = content.pop(name) + if value is None: + assert name.endswith('.SO') or ( + os.path.isfile(os.path.join(curdir, name))) + else: + subdir = os.path.join(curdir, name) + assert os.path.isdir(subdir) + if value == '?': + continue + found_so = self.check_produced_files(value, subdir) or found_so + assert content == {}, "files or dirs not produced in %r: %r" % ( + curdir, content.keys()) + return found_so + + @chdir_to_tmp + def test_empty(self): + self.check_produced_files({}) + + @chdir_to_tmp + def test_abi_emit_python_code_1(self): + ffi = cffi.FFI() + ffi.set_source("package_name_1.mymod", None) + ffi.emit_python_code('xyz.py') + self.check_produced_files({'xyz.py': None}) + + @chdir_to_tmp + def test_abi_emit_python_code_2(self): + ffi = cffi.FFI() + ffi.set_source("package_name_1.mymod", None) + py.test.raises(IOError, ffi.emit_python_code, 'unexisting/xyz.py') + + @from_outside + def test_abi_emit_python_code_3(self): + ffi = cffi.FFI() + ffi.set_source("package_name_1.mymod", None) + ffi.emit_python_code(str(self.udir.join('xyt.py'))) + self.check_produced_files({'xyt.py': None}) + + @chdir_to_tmp + def test_abi_compile_1(self): + ffi = cffi.FFI() + ffi.set_source("mod_name_in_package.mymod", None) + x = ffi.compile() + self.check_produced_files({'mod_name_in_package': {'mymod.py': None}}) + assert x == os.path.join('.', 'mod_name_in_package', 'mymod.py') + + @chdir_to_tmp + def test_abi_compile_2(self): + ffi = cffi.FFI() + ffi.set_source("mod_name_in_package.mymod", None) + x = ffi.compile('build2') + self.check_produced_files({'build2': { + 'mod_name_in_package': {'mymod.py': None}}}) + assert x == os.path.join('build2', 'mod_name_in_package', 'mymod.py') + + @from_outside + def test_abi_compile_3(self): + ffi = cffi.FFI() + ffi.set_source("mod_name_in_package.mymod", None) + tmpdir = str(self.udir.join('build3')) + x = ffi.compile(tmpdir) + self.check_produced_files({'build3': { + 'mod_name_in_package': {'mymod.py': None}}}) + assert x == os.path.join(tmpdir, 'mod_name_in_package', 'mymod.py') + + @chdir_to_tmp + def test_api_emit_c_code_1(self): + ffi = cffi.FFI() + ffi.set_source("package_name_1.mymod", "/*code would be here*/") + ffi.emit_c_code('xyz.c') + self.check_produced_files({'xyz.c': None}) + + @chdir_to_tmp + def test_api_emit_c_code_2(self): + ffi = cffi.FFI() + ffi.set_source("package_name_1.mymod", "/*code would be here*/") + py.test.raises(IOError, ffi.emit_c_code, 'unexisting/xyz.c') + + @from_outside + def test_api_emit_c_code_3(self): + ffi = cffi.FFI() + ffi.set_source("package_name_1.mymod", "/*code would be here*/") + ffi.emit_c_code(str(self.udir.join('xyu.c'))) + self.check_produced_files({'xyu.c': None}) + + @chdir_to_tmp + def test_api_compile_1(self): + ffi = cffi.FFI() + ffi.set_source("mod_name_in_package.mymod", "/*code would be here*/") + x = ffi.compile() + if sys.platform != 'win32': + sofile = self.check_produced_files({ + 'mod_name_in_package': {'mymod.SO': None, + 'mymod.c': None, + 'mymod.o': None}}) + assert os.path.isabs(x) and os.path.samefile(x, sofile) + else: + self.check_produced_files({ + 'mod_name_in_package': {'mymod.SO': None, + 'mymod.c': None}, + 'Release': '?'}) + + @chdir_to_tmp + def test_api_compile_2(self): + ffi = cffi.FFI() + ffi.set_source("mod_name_in_package.mymod", "/*code would be here*/") + x = ffi.compile('output') + if sys.platform != 'win32': + sofile = self.check_produced_files({ + 'output': {'mod_name_in_package': {'mymod.SO': None, + 'mymod.c': None, + 'mymod.o': None}}}) + assert os.path.isabs(x) and os.path.samefile(x, sofile) + else: + self.check_produced_files({ + 'output': {'mod_name_in_package': {'mymod.SO': None, + 'mymod.c': None}, + 'Release': '?'}}) + + @from_outside + def test_api_compile_3(self): + ffi = cffi.FFI() + ffi.set_source("mod_name_in_package.mymod", "/*code would be here*/") + x = ffi.compile(str(self.udir.join('foo'))) + if sys.platform != 'win32': + sofile = self.check_produced_files({ + 'foo': {'mod_name_in_package': {'mymod.SO': None, + 'mymod.c': None, + 'mymod.o': None}}}) + assert os.path.isabs(x) and os.path.samefile(x, sofile) + else: + self.check_produced_files({ + 'foo': {'mod_name_in_package': {'mymod.SO': None, + 'mymod.c': None}, + 'Release': '?'}}) + + @chdir_to_tmp + def test_api_compile_explicit_target_1(self): + ffi = cffi.FFI() + ffi.set_source("mod_name_in_package.mymod", "/*code would be here*/") + x = ffi.compile(target="foo.bar.*") + if sys.platform != 'win32': + sofile = self.check_produced_files({ + 'mod_name_in_package': {'foo.bar.SO': None, + 'mymod.c': None, + 'mymod.o': None}}) + assert os.path.isabs(x) and os.path.samefile(x, sofile) + else: + self.check_produced_files({ + 'mod_name_in_package': {'foo.bar.SO': None, + 'mymod.c': None}, + 'Release': '?'}) + + @chdir_to_tmp + def test_api_compile_explicit_target_3(self): + ffi = cffi.FFI() + ffi.set_source("mod_name_in_package.mymod", "/*code would be here*/") + x = ffi.compile(target="foo.bar.baz") + if sys.platform != 'win32': + self.check_produced_files({ + 'mod_name_in_package': {'foo.bar.baz': None, + 'mymod.c': None, + 'mymod.o': None}}) + sofile = os.path.join(str(self.udir), + 'mod_name_in_package', 'foo.bar.baz') + assert os.path.isabs(x) and os.path.samefile(x, sofile) + else: + self.check_produced_files({ + 'mod_name_in_package': {'foo.bar.baz': None, + 'mymod.c': None}, + 'Release': '?'}) + + @chdir_to_tmp + def test_api_distutils_extension_1(self): + ffi = cffi.FFI() + ffi.set_source("mod_name_in_package.mymod", "/*code would be here*/") + ext = ffi.distutils_extension() + self.check_produced_files({'build': { + 'mod_name_in_package': {'mymod.c': None}}}) + if hasattr(os.path, 'samefile'): + assert os.path.samefile(ext.sources[0], + 'build/mod_name_in_package/mymod.c') + + @from_outside + def test_api_distutils_extension_2(self): + ffi = cffi.FFI() + ffi.set_source("mod_name_in_package.mymod", "/*code would be here*/") + ext = ffi.distutils_extension(str(self.udir.join('foo'))) + self.check_produced_files({'foo': { + 'mod_name_in_package': {'mymod.c': None}}}) + if hasattr(os.path, 'samefile'): + assert os.path.samefile(ext.sources[0], + str(self.udir.join('foo/mod_name_in_package/mymod.c'))) + + + def _make_distutils_api(self): + os.mkdir("src") + os.mkdir(os.path.join("src", "pack1")) + with open(os.path.join("src", "pack1", "__init__.py"), "w") as f: + pass + with open("setup.py", "w") as f: + f.write("""if 1: + # https://bugs.python.org/issue23246 + import sys + if sys.platform == 'win32': + try: + import setuptools + except ImportError: + pass + + import cffi + ffi = cffi.FFI() + ffi.set_source("pack1.mymod", "/*code would be here*/") + + from distutils.core import setup + setup(name='example1', + version='0.1', + packages=['pack1'], + package_dir={'': 'src'}, + ext_modules=[ffi.distutils_extension()]) + """) + + @chdir_to_tmp + def test_distutils_api_1(self): + self._make_distutils_api() + self.run(["setup.py", "build"]) + self.check_produced_files({'setup.py': None, + 'build': '?', + 'src': {'pack1': {'__init__.py': None}}}) + + @chdir_to_tmp + def test_distutils_api_2(self): + self._make_distutils_api() + self.run(["setup.py", "build_ext", "-i"]) + self.check_produced_files({'setup.py': None, + 'build': '?', + 'src': {'pack1': {'__init__.py': None, + 'mymod.SO': None}}}) + + def _make_setuptools_abi(self): + self._prepare_setuptools() + os.mkdir("src0") + os.mkdir(os.path.join("src0", "pack2")) + with open(os.path.join("src0", "pack2", "__init__.py"), "w") as f: + pass + with open(os.path.join("src0", "pack2", "_build.py"), "w") as f: + f.write("""if 1: + import cffi + ffi = cffi.FFI() + ffi.set_source("pack2.mymod", None) + """) + with open("setup.py", "w") as f: + f.write("""if 1: + from setuptools import setup + setup(name='example1', + version='0.1', + packages=['pack2'], + package_dir={'': 'src0'}, + cffi_modules=["src0/pack2/_build.py:ffi"]) + """) + + @chdir_to_tmp + def test_setuptools_abi_1(self): + self._make_setuptools_abi() + self.run(["setup.py", "build"]) + self.check_produced_files({'setup.py': None, + 'build': '?', + 'src0': {'pack2': {'__init__.py': None, + '_build.py': None}}}) + + @chdir_to_tmp + def test_setuptools_abi_2(self): + self._make_setuptools_abi() + self.run(["setup.py", "build_ext", "-i"]) + self.check_produced_files({'setup.py': None, + 'src0': {'pack2': {'__init__.py': None, + '_build.py': None, + 'mymod.py': None}}}) + + def _make_setuptools_api(self): + self._prepare_setuptools() + os.mkdir("src1") + os.mkdir(os.path.join("src1", "pack3")) + with open(os.path.join("src1", "pack3", "__init__.py"), "w") as f: + pass + with open(os.path.join("src1", "pack3", "_build.py"), "w") as f: + f.write("""if 1: + import cffi + ffi = cffi.FFI() + ffi.set_source("pack3.mymod", "/*code would be here*/") + ffi._hi_there = 42 + """) + with open("setup.py", "w") as f: + f.write("from __future__ import print_function\n" + """if 1: + from setuptools import setup + from distutils.command.build_ext import build_ext + import os + + class TestBuildExt(build_ext): + def pre_run(self, ext, ffi): + print('_make_setuptools_api: in pre_run:', end=" ") + assert ffi._hi_there == 42 + assert ext.name == "pack3.mymod" + fn = os.path.join(os.path.dirname(self.build_lib), + '..', 'see_me') + print('creating %r' % (fn,)) + open(fn, 'w').close() + + setup(name='example1', + version='0.1', + packages=['pack3'], + package_dir={'': 'src1'}, + cffi_modules=["src1/pack3/_build.py:ffi"], + cmdclass={'build_ext': TestBuildExt}, + ) + """) + + @chdir_to_tmp + def test_setuptools_api_1(self): + self._make_setuptools_api() + self.run(["setup.py", "build"]) + self.check_produced_files({'setup.py': None, + 'build': '?', + 'see_me': None, + 'src1': {'pack3': {'__init__.py': None, + '_build.py': None}}}) + + @chdir_to_tmp + def test_setuptools_api_2(self): + self._make_setuptools_api() + self.run(["setup.py", "build_ext", "-i"]) + self.check_produced_files({'setup.py': None, + 'build': '?', + 'see_me': None, + 'src1': {'pack3': {'__init__.py': None, + '_build.py': None, + 'mymod.SO': None}}}) |