From 2e08c7915f56870331fce23583754ff8c1d6172f Mon Sep 17 00:00:00 2001 From: Stefan Behnel Date: Mon, 28 Apr 2008 10:33:38 +0200 Subject: [PATCH] cleanup in runtests.py, support for testing compiler errors ('tests/errors/' directory) --- runtests.py | 134 ++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 110 insertions(+), 24 deletions(-) diff --git a/runtests.py b/runtests.py index 1c3441bb..85d9e997 100644 --- a/runtests.py +++ b/runtests.py @@ -1,19 +1,40 @@ #!/usr/bin/python -import os, sys, unittest, doctest +import os, sys, re, shutil, unittest, doctest -from Cython.Distutils.extension import Extension -from Cython.Distutils import build_ext +from Cython.Compiler.Main import \ + CompilationOptions, \ + default_options as pyrex_default_options, \ + compile as cython_compile from distutils.dist import Distribution +from distutils.core import Extension +from distutils.command.build_ext import build_ext distutils_distro = Distribution() -TEST_DIRS = ['compile', 'run'] +TEST_DIRS = ['compile', 'errors', 'run'] TEST_RUN_DIRS = ['run'] INCLUDE_DIRS = [ d for d in os.getenv('INCLUDE', '').split(os.pathsep) if d ] 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): def __init__(self, rootdir, workdir, selectors): self.rootdir = rootdir @@ -30,6 +51,7 @@ class TestBuilder(object): return suite def handle_directory(self, path, context): + expect_errors = (context == 'errors') suite = unittest.TestSuite() for filename in os.listdir(path): if not filename.endswith(".pyx"): @@ -39,59 +61,120 @@ class TestBuilder(object): if not [ 1 for match in self.selectors if match(fqmodule) ]: continue - suite.addTest( - CythonCompileTestCase(path, self.workdir, module)) if context in TEST_RUN_DIRS: - suite.addTest( - CythonRunTestCase(self.workdir, module)) + test = CythonRunTestCase(path, self.workdir, module) + else: + test = CythonCompileTestCase( + path, self.workdir, module, expect_errors) + suite.addTest(test) return suite class CythonCompileTestCase(unittest.TestCase): - def __init__(self, directory, workdir, module): + def __init__(self, directory, workdir, module, expect_errors=False): self.directory = directory self.workdir = workdir self.module = module + self.expect_errors = expect_errors unittest.TestCase.__init__(self) def shortDescription(self): return "compiling " + self.module - def runTest(self): - self.compile(self.directory, self.module, self.workdir) + def setUp(self): + 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.include_dirs = INCLUDE_DIRS[:] - build_extension.include_dirs.append(directory) + if incdir: + build_extension.include_dirs.append(incdir) build_extension.finalize_options() extension = Extension( module, - sources = [os.path.join(directory, module + '.pyx')], + sources = [os.path.join(workdir, module + '.c')], extra_compile_args = CFLAGS, - pyrex_c_in_temp = 1 ) build_extension.extensions = [extension] build_extension.build_temp = workdir build_extension.build_lib = workdir - build_extension.pyrex_c_in_temp = 1 build_extension.run() -class CythonRunTestCase(unittest.TestCase): - def __init__(self, rootdir, module): - self.rootdir, self.module = rootdir, module - unittest.TestCase.__init__(self) + def compile(self, directory, module, workdir, incdir, expect_errors): + expected_errors = errors = () + if expect_errors: + 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): - return "running " + self.module + return "compiling and running " + self.module def runTest(self): self.run() def run(self, result=None): - if not sys.path or sys.path[0] != self.rootdir: - sys.path.insert(0, self.rootdir) - if result is None: result = self.defaultTestResult() + if result is None: + result = self.defaultTestResult() + CythonCompileTestCase.runTest(self) try: try: doctest.DocTestSuite(self.module).run(result) @@ -111,6 +194,9 @@ if __name__ == '__main__': if not os.path.exists(WORKDIR): os.makedirs(WORKDIR) + if not sys.path or sys.path[0] != WORKDIR: + sys.path.insert(0, WORKDIR) + try: sys.argv.remove("-C") except ValueError: -- 2.26.2