diff options
Diffstat (limited to 'run_tests.py')
-rwxr-xr-x | run_tests.py | 175 |
1 files changed, 109 insertions, 66 deletions
diff --git a/run_tests.py b/run_tests.py index f01ea84..04b0510 100755 --- a/run_tests.py +++ b/run_tests.py @@ -32,7 +32,7 @@ Test coverage dependencies: coverage, lxml. """ __authors__ = ["Jérôme Kieffer", "Thomas Vincent"] -__date__ = "03/08/2017" +__date__ = "29/01/2018" __license__ = "MIT" import distutils.util @@ -42,6 +42,8 @@ import subprocess import sys import time import unittest +import collections +from argparse import ArgumentParser class StreamHandlerUnittestReady(logging.StreamHandler): @@ -90,10 +92,16 @@ except ImportError: try: import importlib -except: - importer = __import__ -else: importer = importlib.import_module +except ImportError: + def importer(name): + module = __import__(name) + # returns the leaf module, instead of the root module + subnames = name.split(".") + subnames.pop(0) + for subname in subnames: + module = getattr(module, subname) + return module try: @@ -126,11 +134,6 @@ def get_project_name(root_dir): return name.split()[-1].decode('ascii') -PROJECT_DIR = os.path.dirname(os.path.abspath(__file__)) -PROJECT_NAME = get_project_name(PROJECT_DIR) -logger.info("Project name: %s", PROJECT_NAME) - - class TextTestResultWithSkipList(unittest.TextTestResult): """Override default TextTestResult to display list of skipped tests at the end @@ -139,7 +142,23 @@ class TextTestResultWithSkipList(unittest.TextTestResult): def printErrors(self): unittest.TextTestResult.printErrors(self) # Print skipped tests at the end - self.printErrorList("SKIPPED", self.skipped) + self.printGroupedList("SKIPPED", self.skipped) + + def printGroupedList(self, flavour, errors): + grouped = collections.OrderedDict() + + for test, err in errors: + if err in grouped: + grouped[err] = grouped[err] + [test] + else: + grouped[err] = [test] + + for err, tests in grouped.items(): + self.stream.writeln(self.separator1) + for test in tests: + self.stream.writeln("%s: %s" % (flavour, self.getDescription(test))) + self.stream.writeln(self.separator2) + self.stream.writeln("%s" % err) class ProfileTextTestResult(unittest.TextTestRunner.resultclass): @@ -170,7 +189,8 @@ class ProfileTextTestResult(unittest.TextTestRunner.resultclass): else: memusage = 0 self.logger.info("Time: %.3fs \t RAM: %.3f Mb\t%s", - time.time() - self.__time_start, memusage, test.id()) + time.time() - self.__time_start, + memusage, test.id()) def report_rst(cov, package, version="0.0.0", base=""): @@ -231,6 +251,20 @@ def report_rst(cov, package, version="0.0.0", base=""): return os.linesep.join(res) +def is_debug_python(): + """Returns true if the Python interpreter is in debug mode.""" + try: + import sysconfig + except ImportError: # pragma nocover + # Python < 2.7 + import distutils.sysconfig as sysconfig + + if sysconfig.get_config_var("Py_DEBUG"): + return True + + return hasattr(sys, "gettotalrefcount") + + def build_project(name, root_dir): """Run python setup.py build for the project. @@ -243,6 +277,8 @@ def build_project(name, root_dir): platform = distutils.util.get_platform() architecture = "lib.%s-%i.%i" % (platform, sys.version_info[0], sys.version_info[1]) + if is_debug_python(): + architecture += "-pydebug" if os.environ.get("PYBUILD_NAME") == name: # we are in the debian packaging way @@ -259,7 +295,55 @@ def build_project(name, root_dir): return home -from argparse import ArgumentParser +def import_project_module(project_name, project_dir): + """Import project module, from the system of from the project directory""" + # Prevent importing from source directory + if (os.path.dirname(os.path.abspath(__file__)) == os.path.abspath(sys.path[0])): + removed_from_sys_path = sys.path.pop(0) + logger.info("Patched sys.path, removed: '%s'", removed_from_sys_path) + + if "--installed" in sys.argv: + try: + module = importer(project_name) + except ImportError: + raise ImportError( + "%s not installed: Cannot run tests on installed version" % + PROJECT_NAME) + else: # Use built source + build_dir = build_project(project_name, project_dir) + + sys.path.insert(0, build_dir) + logger.warning("Patched sys.path, added: '%s'", build_dir) + module = importer(project_name) + return module + + +def get_test_options(project_module): + """Returns the test options if available, else None""" + module_name = project_module.__name__ + '.test.utils' + logger.info('Import %s', module_name) + try: + test_utils = importer(module_name) + except ImportError: + logger.warning("No module named '%s'. No test options available.", module_name) + return None + + test_options = getattr(test_utils, "test_options", None) + return test_options + + +PROJECT_DIR = os.path.dirname(os.path.abspath(__file__)) +PROJECT_NAME = get_project_name(PROJECT_DIR) +logger.info("Project name: %s", PROJECT_NAME) + +project_module = import_project_module(PROJECT_NAME, PROJECT_DIR) +PROJECT_VERSION = getattr(project_module, 'version', '') +PROJECT_PATH = project_module.__path__[0] + +test_options = get_test_options(project_module) +"""Contains extra configuration for the tests.""" + + epilog = """Environment variables: WITH_QT_TEST=False to disable graphical tests SILX_OPENCL=False to disable OpenCL tests @@ -286,20 +370,10 @@ parser.add_argument("-v", "--verbose", default=0, help="Increase verbosity. Option -v prints additional " + "INFO messages. Use -vv for full verbosity, " + "including debug messages and test help strings.") -parser.add_argument("-x", "--no-gui", dest="gui", default=True, - action="store_false", - help="Disable the test of the graphical use interface") -parser.add_argument("-g", "--no-opengl", dest="opengl", default=True, - action="store_false", - help="Disable tests using OpenGL") -parser.add_argument("-o", "--no-opencl", dest="opencl", default=True, - action="store_false", - help="Disable the test of the OpenCL part") -parser.add_argument("-l", "--low-mem", dest="low_mem", default=False, - action="store_true", - help="Disable test with large memory consumption (>100Mbyte") parser.add_argument("--qt-binding", dest="qt_binding", default=None, help="Force using a Qt binding, from 'PyQt4', 'PyQt5', or 'PySide'") +if test_options is not None: + test_options.add_parser_argument(parser) default_test_name = "%s.test.suite" % PROJECT_NAME parser.add_argument("test_name", nargs='*', @@ -322,18 +396,6 @@ elif options.verbose > 1: test_verbosity = 2 use_buffer = False -if not options.gui: - os.environ["WITH_QT_TEST"] = "False" - -if not options.opencl: - os.environ["SILX_OPENCL"] = "False" - -if not options.opengl: - os.environ["WITH_GL_TEST"] = "False" - -if options.low_mem: - os.environ["SILX_TEST_LOW_MEM"] = "True" - if options.coverage: logger.info("Running test-coverage") import coverage @@ -353,10 +415,9 @@ if options.qt_binding: if sys.version < "3.0.0": try: import sip - sip.setapi("QString", 2) sip.setapi("QVariant", 2) - except: + except Exception: logger.warning("Cannot set sip API") import PyQt4.QtCore # noqa elif binding == "pyqt5": @@ -365,36 +426,12 @@ if options.qt_binding: elif binding == "pyside": logger.info("Force using PySide") import PySide.QtCore # noqa + elif binding == "pyside2": + logger.info("Force using PySide2") + import PySide2.QtCore # noqa else: raise ValueError("Qt binding '%s' is unknown" % options.qt_binding) -# Prevent importing from source directory -if (os.path.dirname(os.path.abspath(__file__)) == - os.path.abspath(sys.path[0])): - removed_from_sys_path = sys.path.pop(0) - logger.info("Patched sys.path, removed: '%s'", removed_from_sys_path) - - -# import module -if options.installed: # Use installed version - try: - module = importer(PROJECT_NAME) - except: - raise ImportError( - "%s not installed: Cannot run tests on installed version" % - PROJECT_NAME) -else: # Use built source - build_dir = build_project(PROJECT_NAME, PROJECT_DIR) - - sys.path.insert(0, build_dir) - logger.warning("Patched sys.path, added: '%s'", build_dir) - module = importer(PROJECT_NAME) - - -PROJECT_VERSION = getattr(module, 'version', '') -PROJECT_PATH = module.__path__[0] - - # Run the tests runnerArgs = {} runnerArgs["verbosity"] = test_verbosity @@ -411,9 +448,15 @@ logger.warning("Test %s %s from %s", test_module_name = PROJECT_NAME + '.test' logger.info('Import %s', test_module_name) test_module = importer(test_module_name) - test_suite = unittest.TestSuite() +if test_options is not None: + # Configure the test options according to the command lines and the the environment + test_options.configure(options) +else: + logger.warning("No test options available.") + + if not options.test_name: # Do not use test loader to avoid cryptic exception # when an error occur during import |