diff options
author | Gary Oberbrunner <garyo@oberbrunner.com> | 2014-03-30 14:53:39 (GMT) |
---|---|---|
committer | Gary Oberbrunner <garyo@oberbrunner.com> | 2014-03-30 14:53:39 (GMT) |
commit | 29b5018f78b8fe161b76b19125eec2a164c58098 (patch) | |
tree | 711940a9fd90bb13ba470dc05e29ab81ff3c2126 | |
parent | 1166292efdcece6306f8545fd6fb3ce44521b77d (diff) | |
parent | 32a609a88ee6d8682840dc9b2ffd31988f91a12a (diff) | |
download | SCons-29b5018f78b8fe161b76b19125eec2a164c58098.zip SCons-29b5018f78b8fe161b76b19125eec2a164c58098.tar.gz SCons-29b5018f78b8fe161b76b19125eec2a164c58098.tar.bz2 |
Merged in techtonik/scons (pull request #124)
New configurable test runner for unittests
48 files changed, 428 insertions, 142 deletions
@@ -157,6 +157,7 @@ Options: --passed Summarize which tests passed. -q --quiet Don't print the test being executed. --quit-on-failure Quit on any test failure + --runner CLASS Alternative test runner class for unit tests -s --short-progress Short progress, prints only the command line and a percentage value, based on the total and current number of tests. @@ -199,6 +200,8 @@ parser.add_option('-a', '--all', action='store_true', help="Run all tests.") parser.add_option('-o', '--output', help="Save the output from a test run to the log file.") +parser.add_option('--runner', metavar='class', + help="Test runner class for unit tests.") parser.add_option('--xml', help="Save results to file in SCons XML format.") (options, args) = parser.parse_args() @@ -280,13 +283,6 @@ for o, a in opts: elif o in ['-x', '--exec']: scons = a -if not args and not options.all and not testlistfile: - sys.stderr.write(usagestr + """ -runtest.py: No tests were specified. - Tests can be specified on the command line, read from file - with -f option, or discovered with -a to run all tests. -""") - sys.exit(1) # --- setup stdout/stderr --- @@ -619,14 +615,17 @@ old_pythonpath = os.environ.get('PYTHONPATH') # FIXME: the following is necessary to pull in half of the testing # harness from $srcdir/etc. Those modules should be transfered -# to QMTest/ once we completely cut over to using that as -# the harness, in which case this manipulation of PYTHONPATH +# to testing/, in which case this manipulation of PYTHONPATH # should be able to go away. pythonpaths = [ pythonpath_dir ] # Add path of the QMTest folder to PYTHONPATH +# [ ] move used parts from QMTest to testing/framework/ scriptpath = os.path.dirname(os.path.realpath(__file__)) pythonpaths.append(os.path.join(scriptpath, 'QMTest')) +# Add path for testing framework to PYTHONPATH +pythonpaths.append(os.path.join(scriptpath, 'testing', 'framework')) + os.environ['PYTHONPATH'] = os.pathsep.join(pythonpaths) @@ -643,6 +642,9 @@ if python3incompatibilities: tests = [] +unittests = [] +endtests = [] + def find_Tests_py(directory): """ Look for unit tests """ result = [] @@ -674,30 +676,20 @@ def find_py(directory): result.append(os.path.join(dirpath, fname)) return sorted(result) -if args: - for a in args: - for path in glob.glob(a): - if os.path.isdir(path): - if path[:3] == 'src': - for p in find_Tests_py(path): - tests.append(p) - elif path[:4] == 'test': - for p in find_py(path): - tests.append(p) - else: - tests.append(path) -elif testlistfile: +if testlistfile: tests = open(testlistfile, 'r').readlines() tests = [x for x in tests if x[0] != '#'] tests = [x[:-1] for x in tests] tests = [x.strip() for x in tests] -elif options.all: - # Find all of the SCons functional tests in the local directory - # tree. This is anything under the 'src' subdirectory that ends - # with 'Tests.py', or any Python script (*.py) under the 'test' - # subdirectory. +else: + testpaths = [] + + # Each test path specifies a test file, or a directory to search for + # SCons tests. SCons code layout assumes that any file under the 'src' + # subdirectory that ends with 'Tests.py' is a unit test, and Python + # script (*.py) under the 'test' subdirectory an end-to-end test. # # Note that there are some tests under 'src' that *begin* with # 'test_', but they're packaging and installation tests, not @@ -705,13 +697,36 @@ elif options.all: # still be executed by hand, though, and are routinely executed # by the Aegis packaging build to make sure that we're building # things correctly.) - tests.extend(find_Tests_py('src')) - tests.extend(find_py('test')) + + if options.all: + testpaths = ['src', 'test'] + elif args: + testpaths = args + + for tp in testpaths: + for path in glob.glob(tp): + if os.path.isdir(path): + if path.startswith('src'): + for p in find_Tests_py(path): + unittests.append(p) + elif path.startswith('test'): + for p in find_py(path): + endtests.append(p) + else: + if path.endswith("Tests.py"): + unittests.append(path) + else: + endtests.append(path) + + tests.extend(unittests) + tests.extend(endtests) tests.sort() if not tests: - sys.stderr.write("""\ + sys.stderr.write(usagestr + """ runtest.py: No tests were found. + Tests can be specified on the command line, read from file + with -f option, or discovered with -a to run all tests. """) sys.exit(1) @@ -725,7 +740,6 @@ if list_only: sys.stdout.write(t.path + "\n") sys.exit(0) -# if not python: if os.name == 'java': python = os.path.join(sys.prefix, 'jython') @@ -760,6 +774,9 @@ def run_test(t, io_lock, async=True): if debug: command_args.append(debug) command_args.append(t.path) + if options.runner and t.path in unittests: + # For example --runner TestUnit.TAPTestRunner + command_args.append('--runner ' + options.runner) t.command_args = [python] + command_args t.command_str = " ".join([escape(python)] + command_args) if printcommand: diff --git a/src/engine/SCons/ActionTests.py b/src/engine/SCons/ActionTests.py index 3e900d7..809e5ce 100644 --- a/src/engine/SCons/ActionTests.py +++ b/src/engine/SCons/ActionTests.py @@ -49,6 +49,7 @@ import SCons.Environment import SCons.Errors import TestCmd +import TestUnit # Initial setup of the common environment for all tests, # a temporary working directory containing a @@ -2108,8 +2109,8 @@ if __name__ == "__main__": for tclass in tclasses: names = unittest.getTestCaseNames(tclass, 'test_') suite.addTests(list(map(tclass, names))) - if not unittest.TextTestRunner().run(suite).wasSuccessful(): - sys.exit(1) + + TestUnit.run(suite) # Local Variables: # tab-width:4 diff --git a/src/engine/SCons/BuilderTests.py b/src/engine/SCons/BuilderTests.py index 766b8fe..70a7a3f 100644 --- a/src/engine/SCons/BuilderTests.py +++ b/src/engine/SCons/BuilderTests.py @@ -40,6 +40,7 @@ import sys import unittest import TestCmd +import TestUnit import SCons.Action import SCons.Builder @@ -1632,8 +1633,8 @@ if __name__ == "__main__": for tclass in tclasses: names = unittest.getTestCaseNames(tclass, 'test_') suite.addTests(list(map(tclass, names))) - if not unittest.TextTestRunner().run(suite).wasSuccessful(): - sys.exit(1) + + TestUnit.run(suite) # Local Variables: # tab-width:4 diff --git a/src/engine/SCons/CacheDirTests.py b/src/engine/SCons/CacheDirTests.py index 21b435a..7ac97ef 100644 --- a/src/engine/SCons/CacheDirTests.py +++ b/src/engine/SCons/CacheDirTests.py @@ -29,6 +29,7 @@ import sys import unittest from TestCmd import TestCmd +import TestUnit import SCons.CacheDir @@ -287,8 +288,7 @@ if __name__ == "__main__": for tclass in tclasses: names = unittest.getTestCaseNames(tclass, 'test_') suite.addTests(list(map(tclass, names))) - if not unittest.TextTestRunner().run(suite).wasSuccessful(): - sys.exit(1) + TestUnit.run(suite) # Local Variables: # tab-width:4 diff --git a/src/engine/SCons/DefaultsTests.py b/src/engine/SCons/DefaultsTests.py index fd10c12..8b9fb4e 100644 --- a/src/engine/SCons/DefaultsTests.py +++ b/src/engine/SCons/DefaultsTests.py @@ -32,6 +32,7 @@ import unittest from collections import UserDict import TestCmd +import TestUnit import SCons.Errors @@ -82,8 +83,7 @@ if __name__ == "__main__": for tclass in tclasses: names = unittest.getTestCaseNames(tclass, 'test_') suite.addTests(list(map(tclass, names))) - if not unittest.TextTestRunner().run(suite).wasSuccessful(): - sys.exit(1) + TestUnit.run(suite) # Local Variables: # tab-width:4 diff --git a/src/engine/SCons/EnvironmentTests.py b/src/engine/SCons/EnvironmentTests.py index 7fa8af4..5235342 100644 --- a/src/engine/SCons/EnvironmentTests.py +++ b/src/engine/SCons/EnvironmentTests.py @@ -29,10 +29,12 @@ import copy import io import os import sys -import TestCmd import unittest from collections import UserDict as UD, UserList as UL +import TestCmd +import TestUnit + from SCons.Environment import * import SCons.Warnings @@ -3999,8 +4001,7 @@ if __name__ == "__main__": for tclass in tclasses: names = unittest.getTestCaseNames(tclass, 'test_') suite.addTests(list(map(tclass, names))) - if not unittest.TextTestRunner().run(suite).wasSuccessful(): - sys.exit(1) + TestUnit.run(suite) # Local Variables: # tab-width:4 diff --git a/src/engine/SCons/ErrorsTests.py b/src/engine/SCons/ErrorsTests.py index 9c8b925..d57faa5 100644 --- a/src/engine/SCons/ErrorsTests.py +++ b/src/engine/SCons/ErrorsTests.py @@ -25,6 +25,9 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import sys import unittest + +import TestUnit + import SCons.Errors @@ -99,8 +102,7 @@ class ErrorsTestCase(unittest.TestCase): if __name__ == "__main__": suite = unittest.makeSuite(ErrorsTestCase, 'test_') - if not unittest.TextTestRunner().run(suite).wasSuccessful(): - sys.exit(1) + TestUnit.run(suite) # Local Variables: # tab-width:4 diff --git a/src/engine/SCons/ExecutorTests.py b/src/engine/SCons/ExecutorTests.py index 6268984..9df0b2d 100644 --- a/src/engine/SCons/ExecutorTests.py +++ b/src/engine/SCons/ExecutorTests.py @@ -26,6 +26,8 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import sys import unittest +import TestUnit + import SCons.Executor @@ -455,8 +457,7 @@ if __name__ == "__main__": for tclass in tclasses: names = unittest.getTestCaseNames(tclass, 'test_') suite.addTests(list(map(tclass, names))) - if not unittest.TextTestRunner().run(suite).wasSuccessful(): - sys.exit(1) + TestUnit.run(suite) # Local Variables: # tab-width:4 diff --git a/src/engine/SCons/JobTests.py b/src/engine/SCons/JobTests.py index e92bdbe..dd2c7aa 100644 --- a/src/engine/SCons/JobTests.py +++ b/src/engine/SCons/JobTests.py @@ -25,10 +25,14 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import unittest import random import math -import SCons.Job import sys import time +import TestUnit + +import SCons.Job + + # a large number num_sines = 10000 @@ -521,8 +525,8 @@ def suite(): return suite if __name__ == "__main__": - runner = unittest.TextTestRunner() - result = runner.run(suite()) + runner = TestUnit.cli.get_runner() + result = runner().run(suite()) if (len(result.failures) == 0 and len(result.errors) == 1 and isinstance(result.errors[0][0], SerialTestCase) diff --git a/src/engine/SCons/MemoizeTests.py b/src/engine/SCons/MemoizeTests.py index 9876c27..3606d57 100644 --- a/src/engine/SCons/MemoizeTests.py +++ b/src/engine/SCons/MemoizeTests.py @@ -26,6 +26,8 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import sys import unittest +import TestUnit + import SCons.Memoize @@ -180,8 +182,7 @@ if __name__ == "__main__": for tclass in tclasses: names = unittest.getTestCaseNames(tclass, 'test_') suite.addTests(list(map(tclass, names))) - if not unittest.TextTestRunner().run(suite).wasSuccessful(): - sys.exit(1) + TestUnit.run(suite) # Local Variables: # tab-width:4 diff --git a/src/engine/SCons/Node/AliasTests.py b/src/engine/SCons/Node/AliasTests.py index b0efea7..2d11bdf 100644 --- a/src/engine/SCons/Node/AliasTests.py +++ b/src/engine/SCons/Node/AliasTests.py @@ -26,6 +26,8 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import sys import unittest +import TestUnit + import SCons.Errors import SCons.Node.Alias @@ -120,8 +122,7 @@ if __name__ == "__main__": for tclass in tclasses: names = unittest.getTestCaseNames(tclass, 'test_') suite.addTests(list(map(tclass, names))) - if not unittest.TextTestRunner().run(suite).wasSuccessful(): - sys.exit(1) + TestUnit.run(suite) # Local Variables: # tab-width:4 diff --git a/src/engine/SCons/Node/FSTests.py b/src/engine/SCons/Node/FSTests.py index a60b8a4..c4dc2ce 100644 --- a/src/engine/SCons/Node/FSTests.py +++ b/src/engine/SCons/Node/FSTests.py @@ -31,10 +31,12 @@ import os.path import sys import time import unittest -from TestCmd import TestCmd import shutil import stat +from TestCmd import TestCmd +import TestUnit + import SCons.Errors import SCons.Node.FS import SCons.Util @@ -3755,8 +3757,7 @@ if __name__ == "__main__": for tclass in tclasses: names = unittest.getTestCaseNames(tclass, 'test_') suite.addTests(list(map(tclass, names))) - if not unittest.TextTestRunner().run(suite).wasSuccessful(): - sys.exit(1) + TestUnit.run(suite) # Local Variables: # tab-width:4 diff --git a/src/engine/SCons/Node/NodeTests.py b/src/engine/SCons/Node/NodeTests.py index 076ca65..da502b0 100644 --- a/src/engine/SCons/Node/NodeTests.py +++ b/src/engine/SCons/Node/NodeTests.py @@ -30,6 +30,8 @@ import re import sys import unittest +import TestUnit + import SCons.Errors import SCons.Node import SCons.Util @@ -1311,8 +1313,7 @@ if __name__ == "__main__": for tclass in tclasses: names = unittest.getTestCaseNames(tclass, 'test_') suite.addTests(list(map(tclass, names))) - if not unittest.TextTestRunner().run(suite).wasSuccessful(): - sys.exit(1) + TestUnit.run(suite) # Local Variables: # tab-width:4 diff --git a/src/engine/SCons/Node/PythonTests.py b/src/engine/SCons/Node/PythonTests.py index 8b08c52..fcdfe77 100644 --- a/src/engine/SCons/Node/PythonTests.py +++ b/src/engine/SCons/Node/PythonTests.py @@ -26,6 +26,8 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import sys import unittest +import TestUnit + import SCons.Errors import SCons.Node.Python @@ -120,8 +122,7 @@ if __name__ == "__main__": for tclass in tclasses: names = unittest.getTestCaseNames(tclass, 'test_') suite.addTests(list(map(tclass, names))) - if not unittest.TextTestRunner().run(suite).wasSuccessful(): - sys.exit(1) + TestUnit.run(suite) # Local Variables: # tab-width:4 diff --git a/src/engine/SCons/PathListTests.py b/src/engine/SCons/PathListTests.py index e83fc50..b5989bb 100644 --- a/src/engine/SCons/PathListTests.py +++ b/src/engine/SCons/PathListTests.py @@ -26,6 +26,8 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import sys import unittest +import TestUnit + import SCons.PathList @@ -196,8 +198,7 @@ if __name__ == "__main__": for tclass in tclasses: names = unittest.getTestCaseNames(tclass, 'test_') suite.addTests(list(map(tclass, names))) - if not unittest.TextTestRunner().run(suite).wasSuccessful(): - sys.exit(1) + TestUnit.run(suite) # Local Variables: # tab-width:4 diff --git a/src/engine/SCons/Platform/PlatformTests.py b/src/engine/SCons/Platform/PlatformTests.py index 6841272..515382a 100644 --- a/src/engine/SCons/Platform/PlatformTests.py +++ b/src/engine/SCons/Platform/PlatformTests.py @@ -29,6 +29,8 @@ import collections import sys import unittest +import TestUnit + import SCons.Errors import SCons.Platform @@ -118,8 +120,7 @@ class PlatformTestCase(unittest.TestCase): if __name__ == "__main__": suite = unittest.makeSuite(PlatformTestCase, 'test_') - if not unittest.TextTestRunner().run(suite).wasSuccessful(): - sys.exit(1) + TestUnit.run(suite) # Local Variables: # tab-width:4 diff --git a/src/engine/SCons/SConfTests.py b/src/engine/SCons/SConfTests.py index 1cfb05b..1c4b401 100644 --- a/src/engine/SCons/SConfTests.py +++ b/src/engine/SCons/SConfTests.py @@ -33,6 +33,8 @@ from types import * import unittest import TestCmd +import TestUnit + sys.stdout = io.StringIO() @@ -752,9 +754,7 @@ int main() { if __name__ == "__main__": suite = unittest.makeSuite(SConfTestCase, 'test_') - res = unittest.TextTestRunner().run(suite) - if not res.wasSuccessful(): - sys.exit(1) + TestUnit.run(suite) # Local Variables: # tab-width:4 diff --git a/src/engine/SCons/SConsignTests.py b/src/engine/SCons/SConsignTests.py index ec063c2..f71e53e 100644 --- a/src/engine/SCons/SConsignTests.py +++ b/src/engine/SCons/SConsignTests.py @@ -25,9 +25,11 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import os import sys -import TestCmd import unittest +import TestCmd +import TestUnit + import SCons.dblite import SCons.SConsign @@ -387,8 +389,7 @@ if __name__ == "__main__": for tclass in tclasses: names = unittest.getTestCaseNames(tclass, 'test_') suite.addTests(list(map(tclass, names))) - if not unittest.TextTestRunner().run(suite).wasSuccessful(): - sys.exit(1) + TestUnit.run(suite) # Local Variables: # tab-width:4 diff --git a/src/engine/SCons/Scanner/CTests.py b/src/engine/SCons/Scanner/CTests.py index 5523f10..6418754 100644 --- a/src/engine/SCons/Scanner/CTests.py +++ b/src/engine/SCons/Scanner/CTests.py @@ -28,9 +28,11 @@ import SCons.compat import collections import os import sys -import TestCmd import unittest +import TestCmd +import TestUnit + import SCons.Node.FS import SCons.Warnings @@ -457,10 +459,7 @@ def suite(): return suite if __name__ == "__main__": - runner = unittest.TextTestRunner() - result = runner.run(suite()) - if not result.wasSuccessful(): - sys.exit(1) + TestUnit.run(suite()) # Local Variables: # tab-width:4 diff --git a/src/engine/SCons/Scanner/DirTests.py b/src/engine/SCons/Scanner/DirTests.py index 968d5d3..9701921 100644 --- a/src/engine/SCons/Scanner/DirTests.py +++ b/src/engine/SCons/Scanner/DirTests.py @@ -28,6 +28,8 @@ import sys import unittest import TestCmd +import TestUnit + import SCons.Node.FS import SCons.Scanner.Dir @@ -126,10 +128,7 @@ def suite(): return suite if __name__ == "__main__": - runner = unittest.TextTestRunner() - result = runner.run(suite()) - if not result.wasSuccessful(): - sys.exit(1) + TestUnit.run(suite()) # Local Variables: # tab-width:4 diff --git a/src/engine/SCons/Scanner/FortranTests.py b/src/engine/SCons/Scanner/FortranTests.py index 3388ffc..252da64 100644 --- a/src/engine/SCons/Scanner/FortranTests.py +++ b/src/engine/SCons/Scanner/FortranTests.py @@ -33,6 +33,7 @@ import SCons.Node.FS import SCons.Warnings import TestCmd +import TestUnit original = os.getcwd() @@ -531,10 +532,7 @@ def suite(): return suite if __name__ == "__main__": - runner = unittest.TextTestRunner() - result = runner.run(suite()) - if not result.wasSuccessful(): - sys.exit(1) + TestUnit.run(suite()) # Local Variables: # tab-width:4 diff --git a/src/engine/SCons/Scanner/IDLTests.py b/src/engine/SCons/Scanner/IDLTests.py index c696722..675c70c 100644 --- a/src/engine/SCons/Scanner/IDLTests.py +++ b/src/engine/SCons/Scanner/IDLTests.py @@ -23,12 +23,15 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import TestCmd -import SCons.Scanner.IDL import unittest import sys import os import os.path + +import TestCmd +import TestUnit + +import SCons.Scanner.IDL import SCons.Node.FS import SCons.Warnings @@ -441,10 +444,7 @@ def suite(): return suite if __name__ == "__main__": - runner = unittest.TextTestRunner() - result = runner.run(suite()) - if not result.wasSuccessful(): - sys.exit(1) + TestUnit.run(suite()) # Local Variables: # tab-width:4 diff --git a/src/engine/SCons/Scanner/LaTeXTests.py b/src/engine/SCons/Scanner/LaTeXTests.py index 8cea63f..49553cf 100644 --- a/src/engine/SCons/Scanner/LaTeXTests.py +++ b/src/engine/SCons/Scanner/LaTeXTests.py @@ -31,6 +31,8 @@ import sys import unittest import TestCmd +import TestUnit + import SCons.Node.FS import SCons.Scanner.LaTeX @@ -150,10 +152,7 @@ def suite(): return suite if __name__ == "__main__": - runner = unittest.TextTestRunner() - result = runner.run(suite()) - if not result.wasSuccessful(): - sys.exit(1) + TestUnit.run(suite()) # Local Variables: # tab-width:4 diff --git a/src/engine/SCons/Scanner/ProgTests.py b/src/engine/SCons/Scanner/ProgTests.py index 411e035..144addb 100644 --- a/src/engine/SCons/Scanner/ProgTests.py +++ b/src/engine/SCons/Scanner/ProgTests.py @@ -28,6 +28,8 @@ import sys import unittest import TestCmd +import TestUnit + import SCons.Node.FS import SCons.Scanner.Prog @@ -249,10 +251,7 @@ def suite(): return suite if __name__ == "__main__": - runner = unittest.TextTestRunner() - result = runner.run(suite()) - if not result.wasSuccessful(): - sys.exit(1) + TestUnit.run(suite()) # Local Variables: # tab-width:4 diff --git a/src/engine/SCons/Scanner/RCTests.py b/src/engine/SCons/Scanner/RCTests.py index 8802885..2864026 100644 --- a/src/engine/SCons/Scanner/RCTests.py +++ b/src/engine/SCons/Scanner/RCTests.py @@ -23,12 +23,15 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import TestCmd -import SCons.Scanner.RC import unittest import sys import collections import os + +import TestCmd +import TestUnit + +import SCons.Scanner.RC import SCons.Node.FS import SCons.Warnings @@ -164,10 +167,7 @@ def suite(): return suite if __name__ == "__main__": - runner = unittest.TextTestRunner() - result = runner.run(suite()) - if not result.wasSuccessful(): - sys.exit(1) + TestUnit.run(suite()) # Local Variables: # tab-width:4 diff --git a/src/engine/SCons/Scanner/ScannerTests.py b/src/engine/SCons/Scanner/ScannerTests.py index ee26922..2496534 100644 --- a/src/engine/SCons/Scanner/ScannerTests.py +++ b/src/engine/SCons/Scanner/ScannerTests.py @@ -28,6 +28,8 @@ import collections import sys import unittest +import TestUnit + import SCons.Scanner class DummyFS(object): @@ -593,10 +595,7 @@ def suite(): return suite if __name__ == "__main__": - runner = unittest.TextTestRunner() - result = runner.run(suite()) - if not result.wasSuccessful(): - sys.exit(1) + TestUnit.run(suite()) # Local Variables: # tab-width:4 diff --git a/src/engine/SCons/Script/MainTests.py b/src/engine/SCons/Script/MainTests.py index c44c426..fd6aaf4 100644 --- a/src/engine/SCons/Script/MainTests.py +++ b/src/engine/SCons/Script/MainTests.py @@ -24,6 +24,9 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import unittest + +import TestUnit + import SCons.Errors import SCons.Script.Main @@ -43,8 +46,7 @@ if __name__ == "__main__": for tclass in tclasses: names = unittest.getTestCaseNames(tclass, 'test_') suite.addTests(list(map(tclass, names))) - if not unittest.TextTestRunner().run(suite).wasSuccessful(): - sys.exit(1) + TestUnit.run(suite) # Local Variables: # tab-width:4 diff --git a/src/engine/SCons/SubstTests.py b/src/engine/SCons/SubstTests.py index ee9f3db..6f2eb3f 100644 --- a/src/engine/SCons/SubstTests.py +++ b/src/engine/SCons/SubstTests.py @@ -31,6 +31,8 @@ import unittest from collections import UserDict +import TestUnit + import SCons.Errors from SCons.Subst import * @@ -1233,8 +1235,7 @@ if __name__ == "__main__": for tclass in tclasses: names = unittest.getTestCaseNames(tclass, 'test_') suite.addTests(list(map(tclass, names))) - if not unittest.TextTestRunner().run(suite).wasSuccessful(): - sys.exit(1) + TestUnit.run(suite) # Local Variables: # tab-width:4 diff --git a/src/engine/SCons/TaskmasterTests.py b/src/engine/SCons/TaskmasterTests.py index e875158..1d81992 100644 --- a/src/engine/SCons/TaskmasterTests.py +++ b/src/engine/SCons/TaskmasterTests.py @@ -30,6 +30,8 @@ import copy import sys import unittest +import TestUnit + import SCons.Taskmaster import SCons.Errors @@ -1223,8 +1225,7 @@ Taskmaster: No candidate anymore. if __name__ == "__main__": suite = unittest.makeSuite(TaskmasterTestCase, 'test_') - if not unittest.TextTestRunner().run(suite).wasSuccessful(): - sys.exit(1) + TestUnit.run(suite) # Local Variables: # tab-width:4 diff --git a/src/engine/SCons/Tool/JavaCommonTests.py b/src/engine/SCons/Tool/JavaCommonTests.py index 76944c1..902030d 100644 --- a/src/engine/SCons/Tool/JavaCommonTests.py +++ b/src/engine/SCons/Tool/JavaCommonTests.py @@ -27,6 +27,9 @@ import os.path import sys import unittest +import TestUnit + +import SCons.Scanner.IDL import SCons.Tool.JavaCommon @@ -570,8 +573,7 @@ if __name__ == "__main__": for tclass in tclasses: names = unittest.getTestCaseNames(tclass, 'test_') suite.addTests(list(map(tclass, names))) - if not unittest.TextTestRunner().run(suite).wasSuccessful(): - sys.exit(1) + TestUnit.run(suite) # Local Variables: # tab-width:4 diff --git a/src/engine/SCons/Tool/PharLapCommonTests.py b/src/engine/SCons/Tool/PharLapCommonTests.py index d1e7f60..e67d426 100644 --- a/src/engine/SCons/Tool/PharLapCommonTests.py +++ b/src/engine/SCons/Tool/PharLapCommonTests.py @@ -28,6 +28,8 @@ import os.path import os import sys +import TestUnit + import SCons.Errors from SCons.Tool.PharLapCommon import * @@ -58,8 +60,7 @@ class PharLapCommonTestCase(unittest.TestCase): if __name__ == "__main__": suite = unittest.makeSuite(PharLapCommonTestCase, 'test_') - if not unittest.TextTestRunner().run(suite).wasSuccessful(): - sys.exit(1) + TestUnit.run(suite) # Local Variables: # tab-width:4 diff --git a/src/engine/SCons/Tool/ToolTests.py b/src/engine/SCons/Tool/ToolTests.py index 9595680..3e6da5b 100644 --- a/src/engine/SCons/Tool/ToolTests.py +++ b/src/engine/SCons/Tool/ToolTests.py @@ -26,6 +26,8 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import sys import unittest +import TestUnit + import SCons.Errors import SCons.Tool @@ -76,8 +78,7 @@ class ToolTestCase(unittest.TestCase): if __name__ == "__main__": suite = unittest.makeSuite(ToolTestCase, 'test_') - if not unittest.TextTestRunner().run(suite).wasSuccessful(): - sys.exit(1) + TestUnit.run(suite) # Local Variables: # tab-width:4 diff --git a/src/engine/SCons/Tool/javacTests.py b/src/engine/SCons/Tool/javacTests.py index 4631c8a..bf75d8a 100644 --- a/src/engine/SCons/Tool/javacTests.py +++ b/src/engine/SCons/Tool/javacTests.py @@ -24,6 +24,8 @@ import os import unittest +import TestUnit + import SCons.Tool.javac class DummyNode(object): @@ -99,4 +101,5 @@ class pathoptTestCase(unittest.TestCase): '') if __name__ == "__main__": - unittest.main() + suite = unittest.makeSuite(pathoptTestCase, 'test_') + TestUnit.run(suite) diff --git a/src/engine/SCons/Tool/msvsTests.py b/src/engine/SCons/Tool/msvsTests.py index 3a9cac7..2f4f302 100644 --- a/src/engine/SCons/Tool/msvsTests.py +++ b/src/engine/SCons/Tool/msvsTests.py @@ -25,10 +25,12 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import os import sys -import TestCmd import unittest import copy +import TestCmd +import TestUnit + from SCons.Tool.msvs import * from SCons.Tool.MSCommon.vs import SupportedVSList import SCons.Util @@ -759,7 +761,7 @@ if __name__ == "__main__": del os.environ[k] suite = unittest.makeSuite(test_class, 'test_') - if not unittest.TextTestRunner().run(suite).wasSuccessful(): + if not TestUnit.cli.get_runner()().run(suite).wasSuccessful(): exit_val = 1 finally: os.env = back_osenv diff --git a/src/engine/SCons/Tool/wixTests.py b/src/engine/SCons/Tool/wixTests.py index c815dd0..c683e98 100644 --- a/src/engine/SCons/Tool/wixTests.py +++ b/src/engine/SCons/Tool/wixTests.py @@ -33,6 +33,8 @@ from SCons.Tool.wix import * from SCons.Environment import Environment import TestCmd +import TestUnit + # create fake candle and light, so the tool's exists() method will succeed test = TestCmd.TestCmd(workdir = '') @@ -52,8 +54,7 @@ class WixTestCase(unittest.TestCase): if __name__ == "__main__": suite = unittest.makeSuite(WixTestCase, 'test_') - if not unittest.TextTestRunner().run(suite).wasSuccessful(): - sys.exit(1) + TestUnit.run(suite) # Local Variables: # tab-width:4 diff --git a/src/engine/SCons/UtilTests.py b/src/engine/SCons/UtilTests.py index a1e6756..b0c15c5 100644 --- a/src/engine/SCons/UtilTests.py +++ b/src/engine/SCons/UtilTests.py @@ -32,6 +32,7 @@ import unittest from collections import UserDict, UserList, UserString import TestCmd +import TestUnit import SCons.Errors @@ -789,8 +790,7 @@ if __name__ == "__main__": for tclass in tclasses: names = unittest.getTestCaseNames(tclass, 'test_') suite.addTests(list(map(tclass, names))) - if not unittest.TextTestRunner().run(suite).wasSuccessful(): - sys.exit(1) + TestUnit.run(suite) # Local Variables: # tab-width:4 diff --git a/src/engine/SCons/Variables/BoolVariableTests.py b/src/engine/SCons/Variables/BoolVariableTests.py index 8ffb079..7110f6f 100644 --- a/src/engine/SCons/Variables/BoolVariableTests.py +++ b/src/engine/SCons/Variables/BoolVariableTests.py @@ -26,6 +26,8 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import sys import unittest +import TestUnit + import SCons.Errors import SCons.Variables @@ -117,8 +119,7 @@ class BoolVariableTestCase(unittest.TestCase): if __name__ == "__main__": suite = unittest.makeSuite(BoolVariableTestCase, 'test_') - if not unittest.TextTestRunner().run(suite).wasSuccessful(): - sys.exit(1) + TestUnit.run(suite) # Local Variables: # tab-width:4 diff --git a/src/engine/SCons/Variables/EnumVariableTests.py b/src/engine/SCons/Variables/EnumVariableTests.py index f4b600d..931dfe2 100644 --- a/src/engine/SCons/Variables/EnumVariableTests.py +++ b/src/engine/SCons/Variables/EnumVariableTests.py @@ -26,6 +26,8 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import sys import unittest +import TestUnit + import SCons.Errors import SCons.Variables @@ -194,8 +196,7 @@ class EnumVariableTestCase(unittest.TestCase): if __name__ == "__main__": suite = unittest.makeSuite(EnumVariableTestCase, 'test_') - if not unittest.TextTestRunner().run(suite).wasSuccessful(): - sys.exit(1) + TestUnit.run(suite) # Local Variables: # tab-width:4 diff --git a/src/engine/SCons/Variables/ListVariableTests.py b/src/engine/SCons/Variables/ListVariableTests.py index 4959f69..adfd353 100644 --- a/src/engine/SCons/Variables/ListVariableTests.py +++ b/src/engine/SCons/Variables/ListVariableTests.py @@ -27,6 +27,8 @@ import copy import sys import unittest +import TestUnit + import SCons.Errors import SCons.Variables @@ -124,8 +126,7 @@ class ListVariableTestCase(unittest.TestCase): if __name__ == "__main__": suite = unittest.makeSuite(ListVariableTestCase, 'test_') - if not unittest.TextTestRunner().run(suite).wasSuccessful(): - sys.exit(1) + TestUnit.run(suite) # Local Variables: # tab-width:4 diff --git a/src/engine/SCons/Variables/PackageVariableTests.py b/src/engine/SCons/Variables/PackageVariableTests.py index 2a93348..3aa411d 100644 --- a/src/engine/SCons/Variables/PackageVariableTests.py +++ b/src/engine/SCons/Variables/PackageVariableTests.py @@ -30,6 +30,8 @@ import SCons.Errors import SCons.Variables import TestCmd +import TestUnit + class PackageVariableTestCase(unittest.TestCase): def test_PackageVariable(self): @@ -114,8 +116,7 @@ class PackageVariableTestCase(unittest.TestCase): if __name__ == "__main__": suite = unittest.makeSuite(PackageVariableTestCase, 'test_') - if not unittest.TextTestRunner().run(suite).wasSuccessful(): - sys.exit(1) + TestUnit.run(suite) # Local Variables: # tab-width:4 diff --git a/src/engine/SCons/Variables/PathVariableTests.py b/src/engine/SCons/Variables/PathVariableTests.py index 084154b..4266759 100644 --- a/src/engine/SCons/Variables/PathVariableTests.py +++ b/src/engine/SCons/Variables/PathVariableTests.py @@ -31,6 +31,8 @@ import SCons.Errors import SCons.Variables import TestCmd +import TestUnit + class PathVariableTestCase(unittest.TestCase): def test_PathVariable(self): @@ -227,8 +229,7 @@ class PathVariableTestCase(unittest.TestCase): if __name__ == "__main__": suite = unittest.makeSuite(PathVariableTestCase, 'test_') - if not unittest.TextTestRunner().run(suite).wasSuccessful(): - sys.exit(1) + TestUnit.run(suite) # Local Variables: # tab-width:4 diff --git a/src/engine/SCons/Variables/VariablesTests.py b/src/engine/SCons/Variables/VariablesTests.py index ad46bd6..d2110c1 100644 --- a/src/engine/SCons/Variables/VariablesTests.py +++ b/src/engine/SCons/Variables/VariablesTests.py @@ -25,7 +25,9 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import sys import unittest + import TestSCons +import TestUnit import SCons.Variables import SCons.Subst @@ -655,8 +657,7 @@ if __name__ == "__main__": for tclass in tclasses: names = unittest.getTestCaseNames(tclass, 'test_') suite.addTests(list(map(tclass, names))) - if not unittest.TextTestRunner().run(suite).wasSuccessful(): - sys.exit(1) + TestUnit.run(suite) # Local Variables: # tab-width:4 diff --git a/src/engine/SCons/WarningsTests.py b/src/engine/SCons/WarningsTests.py index 583b12a..7b8d00d 100644 --- a/src/engine/SCons/WarningsTests.py +++ b/src/engine/SCons/WarningsTests.py @@ -25,6 +25,9 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import sys import unittest + +import TestUnit + import SCons.Warnings class TestOutput(object): @@ -125,8 +128,7 @@ class WarningsTestCase(unittest.TestCase): if __name__ == "__main__": suite = unittest.makeSuite(WarningsTestCase, 'test_') - if not unittest.TextTestRunner().run(suite).wasSuccessful(): - sys.exit(1) + TestUnit.run(suite) # Local Variables: # tab-width:4 diff --git a/src/engine/SCons/cppTests.py b/src/engine/SCons/cppTests.py index 2f2025b..5a06bee 100644 --- a/src/engine/SCons/cppTests.py +++ b/src/engine/SCons/cppTests.py @@ -27,6 +27,8 @@ import atexit import sys import unittest +import TestUnit + import cpp @@ -705,8 +707,7 @@ if __name__ == '__main__': pass names.sort() suite.addTests(list(map(tclass, names))) - if not unittest.TextTestRunner().run(suite).wasSuccessful(): - sys.exit(1) + TestUnit.run(suite) # Local Variables: # tab-width:4 diff --git a/test/runtest/testargv.py b/test/runtest/testargv.py new file mode 100644 index 0000000..62faf51 --- /dev/null +++ b/test/runtest/testargv.py @@ -0,0 +1,75 @@ +#!/usr/bin/env python +# +# __COPYRIGHT__ +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" + +""" +Test subdir args for runtest.py, for example: + + python runtest.py test/subdir + +""" + +import os + +import TestRuntest + +test = TestRuntest.TestRuntest() +test.subdir('test', ['test', 'subdir']) + +files = {} +files['pythonstring'] = TestRuntest.pythonstring + +files['one'] = os.path.join('test/subdir', 'test_one.py') +files['two'] = os.path.join('test/subdir', 'two.py') +files['three'] = os.path.join('test', 'test_three.py') + +test.write_passing_test(files['one']) +test.write_passing_test(files['two']) +test.write_passing_test(files['three']) + +expect_stdout = """\ +%(pythonstring)s -tt %(one)s +PASSING TEST STDOUT +%(pythonstring)s -tt %(two)s +PASSING TEST STDOUT +""" % files + +expect_stderr = """\ +PASSING TEST STDERR +PASSING TEST STDERR +""" + +test.run(arguments = '--no-progress test/subdir', + status = 0, + stdout = expect_stdout, + stderr = expect_stderr) + +test.pass_test() + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: diff --git a/testing/framework/TestUnit/__init__.py b/testing/framework/TestUnit/__init__.py new file mode 100644 index 0000000..51cf972 --- /dev/null +++ b/testing/framework/TestUnit/__init__.py @@ -0,0 +1,5 @@ + +__all__ = ['TAPTestRunner', 'TAPTestResult', 'run'] + +from .taprunner import TAPTestRunner, TAPTestResult +from .cli import run diff --git a/testing/framework/TestUnit/cli.py b/testing/framework/TestUnit/cli.py new file mode 100644 index 0000000..6aec735 --- /dev/null +++ b/testing/framework/TestUnit/cli.py @@ -0,0 +1,35 @@ +""" +Choose test runner class from --runner command line option +and execute test cases. +""" + +import unittest +import optparse +import sys + + +def get_runner(): + parser = optparse.OptionParser() + parser.add_option('--runner', default='unittest.TextTestRunner', + help='name of test runner class to use') + opts, args = parser.parse_args() + + fromsplit = opts.runner.rsplit('.', 1) + if len(fromsplit) < 2: + raise ValueError('Can\'t use module as a runner') + else: + runnermod = __import__(fromsplit[0]) + return getattr(runnermod, fromsplit[1]) + + +def run(suite=None): + runner = get_runner() + if suite: + if not runner().run(suite).wasSuccessful(): + sys.exit(1) + else: + unittest.main(argv=sys.argv[:1], testRunner=runner) + + +if __name__ == '__main__': + run() diff --git a/testing/framework/TestUnit/taprunner.py b/testing/framework/TestUnit/taprunner.py new file mode 100644 index 0000000..01e0e81 --- /dev/null +++ b/testing/framework/TestUnit/taprunner.py @@ -0,0 +1,120 @@ +""" +Format unittest results in Test Anything Protocol (TAP). +http://testanything.org/tap-version-13-specification.html + +Public domain work by: + anatoly techtonik <techtonik@gmail.com> + +""" + +from unittest import suite +from unittest.runner import TextTestRunner, TextTestResult + +__version__ = "0.1" + +class TAPTestResult(TextTestResult): + + def _process(self, test, msg, failtype = None, directive = None): + """ increase the counter, format and output TAP info """ + # counterhack: increase test counter + test.suite.tap_counter += 1 + msg = "%s %d" % (msg, test.suite.tap_counter) + if "not" not in msg: + msg += " " # justify + self.stream.write("%s - " % msg) + if failtype: + self.stream.write("%s - " % failtype) + self.stream.write("%s" % test.__class__.__name__) + self.stream.write(".%s" % test._testMethodName) + if directive: + self.stream.write(directive) + self.stream.write("\n") + # [ ] write test __doc__ (if exists) in comment + self.stream.flush() + + def addSuccess(self, test): + super(TextTestResult, self).addSuccess(test) + self._process(test, "ok") + + def addFailure(self, test, err): + super(TextTestResult, self).addFailure(test, err) + self._process(test, "not ok", "FAIL") + # [ ] add structured data about assertion + + def addError(self, test, err): + super(TextTestResult, self).addError(test, err) + self._process(test, "not ok", "ERROR") + # [ ] add structured data about exception + + def addSkip(self, test, reason): + super(TextTestResult, self).addSkip(test, reason) + self._process(test, "ok", directive=(" # SKIP %s" % reason)) + + def addExpectedFailure(self, test, err): + super(TextTestResult, self).addExpectedFailure(test, err) + self._process(test, "not ok", directive=(" # TODO")) + + def addUnexpectedSuccess(self, test): + super(TextTestResult, self).addUnexpectedSuccess(test) + self._process(test, "not ok", "FAIL (unexpected success)") + + """ + def printErrors(self): + def printErrorList(self, flavour, errors): + """ + + +class TAPTestRunner(TextTestRunner): + resultclass = TAPTestResult + + def run(self, test): + self.stream.write("TAP version 13\n") + # [ ] add commented block with test suite __doc__ + # [ ] check call with a single test + # if isinstance(test, suite.TestSuite): + self.stream.write("1..%s\n" % len(list(test))) + + # counterhack: inject test counter into test suite + test.tap_counter = 0 + # counterhack: inject reference to suite into each test case + for case in test: + case.suite = test + + return super(TAPTestRunner, self).run(test) + + +if __name__ == "__main__": + import sys + import unittest + + class Test(unittest.TestCase): + def test_ok(self): + pass + def test_fail(self): + self.assertTrue(False) + def test_error(self): + bad_symbol + @unittest.skip("skipin'") + def test_skip(self): + pass + @unittest.expectedFailure + def test_not_ready(self): + self.fail() + @unittest.expectedFailure + def test_invalid_fail_mark(self): + pass + def test_another_ok(self): + pass + + + suite = unittest.TestSuite([ + Test('test_ok'), + Test('test_fail'), + Test('test_error'), + Test('test_skip'), + Test('test_not_ready'), + Test('test_invalid_fail_mark'), + Test('test_another_ok') + ]) + if not TAPTestRunner().run(suite).wasSuccessful(): + sys.exit(1) |