Commit 2e08c791 authored by Stefan Behnel's avatar Stefan Behnel

cleanup in runtests.py, support for testing compiler errors ('tests/errors/' directory)

parent df47628a
#!/usr/bin/python #!/usr/bin/python
import os, sys, unittest, doctest import os, sys, re, shutil, unittest, doctest
from Cython.Distutils.extension import Extension from Cython.Compiler.Main import \
from Cython.Distutils import build_ext CompilationOptions, \
default_options as pyrex_default_options, \
compile as cython_compile
from distutils.dist import Distribution from distutils.dist import Distribution
from distutils.core import Extension
from distutils.command.build_ext import build_ext
distutils_distro = Distribution() distutils_distro = Distribution()
TEST_DIRS = ['compile', 'run'] TEST_DIRS = ['compile', 'errors', 'run']
TEST_RUN_DIRS = ['run'] TEST_RUN_DIRS = ['run']
INCLUDE_DIRS = [ d for d in os.getenv('INCLUDE', '').split(os.pathsep) if d ] INCLUDE_DIRS = [ d for d in os.getenv('INCLUDE', '').split(os.pathsep) if d ]
CFLAGS = os.getenv('CFLAGS', '').split() CFLAGS = os.getenv('CFLAGS', '').split()
class ErrorWriter(object):
match_error = re.compile('(?:.*:)?([-0-9]+):([-0-9]+):(.*)').match
def __init__(self):
self.output = []
self.write = self.output.append
def geterrors(self):
s = ''.join(self.output)
errors = []
for line in s.split('\n'):
match = self.match_error(line)
if match:
line, column, message = match.groups()
errors.append( "%d:%d:%s" % (int(line), int(column), message.strip()) )
return errors
class TestBuilder(object): class TestBuilder(object):
def __init__(self, rootdir, workdir, selectors): def __init__(self, rootdir, workdir, selectors):
self.rootdir = rootdir self.rootdir = rootdir
...@@ -30,6 +51,7 @@ class TestBuilder(object): ...@@ -30,6 +51,7 @@ class TestBuilder(object):
return suite return suite
def handle_directory(self, path, context): def handle_directory(self, path, context):
expect_errors = (context == 'errors')
suite = unittest.TestSuite() suite = unittest.TestSuite()
for filename in os.listdir(path): for filename in os.listdir(path):
if not filename.endswith(".pyx"): if not filename.endswith(".pyx"):
...@@ -39,59 +61,120 @@ class TestBuilder(object): ...@@ -39,59 +61,120 @@ class TestBuilder(object):
if not [ 1 for match in self.selectors if not [ 1 for match in self.selectors
if match(fqmodule) ]: if match(fqmodule) ]:
continue continue
suite.addTest(
CythonCompileTestCase(path, self.workdir, module))
if context in TEST_RUN_DIRS: if context in TEST_RUN_DIRS:
suite.addTest( test = CythonRunTestCase(path, self.workdir, module)
CythonRunTestCase(self.workdir, module)) else:
test = CythonCompileTestCase(
path, self.workdir, module, expect_errors)
suite.addTest(test)
return suite return suite
class CythonCompileTestCase(unittest.TestCase): class CythonCompileTestCase(unittest.TestCase):
def __init__(self, directory, workdir, module): def __init__(self, directory, workdir, module, expect_errors=False):
self.directory = directory self.directory = directory
self.workdir = workdir self.workdir = workdir
self.module = module self.module = module
self.expect_errors = expect_errors
unittest.TestCase.__init__(self) unittest.TestCase.__init__(self)
def shortDescription(self): def shortDescription(self):
return "compiling " + self.module return "compiling " + self.module
def runTest(self): def setUp(self):
self.compile(self.directory, self.module, self.workdir) if os.path.exists(self.workdir):
shutil.rmtree(self.workdir, ignore_errors=True)
os.makedirs(self.workdir)
def compile(self, directory, module, workdir): def runTest(self):
self.compile(self.directory, self.module, self.workdir,
self.directory, self.expect_errors)
def split_source_and_output(self, directory, module, workdir):
source_and_output = open(os.path.join(directory, module + '.pyx'), 'rU')
out = open(os.path.join(workdir, module + '.pyx'), 'w')
for line in source_and_output:
last_line = line
if line.startswith("_ERRORS"):
out.close()
out = ErrorWriter()
else:
out.write(line)
try:
geterrors = out.geterrors
except AttributeError:
return []
else:
return geterrors()
def run_cython(self, directory, module, targetdir, incdir):
include_dirs = INCLUDE_DIRS[:]
if incdir:
include_dirs.append(incdir)
source = os.path.join(directory, module + '.pyx')
target = os.path.join(targetdir, module + '.c')
options = CompilationOptions(
pyrex_default_options,
include_path = include_dirs,
output_file = target,
use_listing_file = False, cplus = False, generate_pxi = False)
cython_compile(source, options=options,
full_module_name=module)
def run_distutils(self, module, workdir, incdir):
build_extension = build_ext(distutils_distro) build_extension = build_ext(distutils_distro)
build_extension.include_dirs = INCLUDE_DIRS[:] build_extension.include_dirs = INCLUDE_DIRS[:]
build_extension.include_dirs.append(directory) if incdir:
build_extension.include_dirs.append(incdir)
build_extension.finalize_options() build_extension.finalize_options()
extension = Extension( extension = Extension(
module, module,
sources = [os.path.join(directory, module + '.pyx')], sources = [os.path.join(workdir, module + '.c')],
extra_compile_args = CFLAGS, extra_compile_args = CFLAGS,
pyrex_c_in_temp = 1
) )
build_extension.extensions = [extension] build_extension.extensions = [extension]
build_extension.build_temp = workdir build_extension.build_temp = workdir
build_extension.build_lib = workdir build_extension.build_lib = workdir
build_extension.pyrex_c_in_temp = 1
build_extension.run() build_extension.run()
class CythonRunTestCase(unittest.TestCase): def compile(self, directory, module, workdir, incdir, expect_errors):
def __init__(self, rootdir, module): expected_errors = errors = ()
self.rootdir, self.module = rootdir, module if expect_errors:
unittest.TestCase.__init__(self) expected_errors = self.split_source_and_output(
directory, module, workdir)
directory = workdir
old_stderr = sys.stderr
try:
sys.stderr = ErrorWriter()
self.run_cython(directory, module, workdir, incdir)
errors = sys.stderr.geterrors()
finally:
sys.stderr = old_stderr
if errors or expected_errors:
for expected, error in zip(expected_errors, errors):
self.assertEquals(expected, error)
if len(errors) < len(expected_errors):
expected_error = expected_errors[len(errors)]
self.assertEquals(expected_error, None)
elif len(errors) > len(expected_errors):
unexpected_error = errors[len(expected_errors)]
self.assertEquals(None, unexpected_error)
else:
self.run_distutils(module, workdir, incdir)
class CythonRunTestCase(CythonCompileTestCase):
def shortDescription(self): def shortDescription(self):
return "running " + self.module return "compiling and running " + self.module
def runTest(self): def runTest(self):
self.run() self.run()
def run(self, result=None): def run(self, result=None):
if not sys.path or sys.path[0] != self.rootdir: if result is None:
sys.path.insert(0, self.rootdir) result = self.defaultTestResult()
if result is None: result = self.defaultTestResult() CythonCompileTestCase.runTest(self)
try: try:
try: try:
doctest.DocTestSuite(self.module).run(result) doctest.DocTestSuite(self.module).run(result)
...@@ -111,6 +194,9 @@ if __name__ == '__main__': ...@@ -111,6 +194,9 @@ if __name__ == '__main__':
if not os.path.exists(WORKDIR): if not os.path.exists(WORKDIR):
os.makedirs(WORKDIR) os.makedirs(WORKDIR)
if not sys.path or sys.path[0] != WORKDIR:
sys.path.insert(0, WORKDIR)
try: try:
sys.argv.remove("-C") sys.argv.remove("-C")
except ValueError: except ValueError:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment