summaryrefslogtreecommitdiff
path: root/run_tests.py
diff options
context:
space:
mode:
Diffstat (limited to 'run_tests.py')
-rwxr-xr-xrun_tests.py175
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