diff options
| author | Steven Knight <knight@baldmt.com> | 2006-07-25 02:30:45 (GMT) |
|---|---|---|
| committer | Steven Knight <knight@baldmt.com> | 2006-07-25 02:30:45 (GMT) |
| commit | dd9bbc79353ae90b2402c16b1613dad4e502d250 (patch) | |
| tree | 42f857f72bb4dcab6d876d1f9c73e0a1dd70d8c2 /etc/unittest.py | |
| parent | 57fcbbc5d24fb16f988e4fe3294d5d49abef8e2a (diff) | |
| download | SCons-dd9bbc79353ae90b2402c16b1613dad4e502d250.zip SCons-dd9bbc79353ae90b2402c16b1613dad4e502d250.tar.gz SCons-dd9bbc79353ae90b2402c16b1613dad4e502d250.tar.bz2 | |
Merged revisions 1441-1539 via svnmerge from
http://scons.tigris.org/svn/scons/branches/core
........
r1441 | stevenknight | 2006-04-22 23:06:53 -0400 (Sat, 22 Apr 2006) | 1 line
0.96.D397 - The scons command, branch 0.96.91.
........
r1442 | stevenknight | 2006-04-27 00:45:12 -0400 (Thu, 27 Apr 2006) | 1 line
0.96.D398 - The scons command, branch 0.96.92.
........
r1443 | stevenknight | 2006-04-27 00:49:25 -0400 (Thu, 27 Apr 2006) | 1 line
0.96.D399 - Taskmaster clean-ups in anticipation of refactoring speedups.
........
r1450 | stevenknight | 2006-05-02 00:04:55 -0400 (Tue, 02 May 2006) | 1 line
0.96.D400 - Fix VC+++ 2005 Express detection. (Atul Varma) Fix parsing Intel C compiler Li
........
r1451 | stevenknight | 2006-05-02 01:14:24 -0400 (Tue, 02 May 2006) | 1 line
0.96.D401 - Enhance ParseConfig() to understand -arch and -isysroot options. (Gary Oberbrun
........
r1458 | stevenknight | 2006-05-02 23:21:04 -0400 (Tue, 02 May 2006) | 1 line
0.96.D402 - Make strfunction handling consistent. (David Gruener)
........
r1459 | stevenknight | 2006-05-02 23:37:08 -0400 (Tue, 02 May 2006) | 1 line
0.96.D403 - Comment out the test of CVS checkout from the old tigris.org repository.
........
r1460 | stevenknight | 2006-05-03 23:47:54 -0400 (Wed, 03 May 2006) | 1 line
0.96.D404 - Preserve white space in display Action string. (David Gruener)
........
r1461 | stevenknight | 2006-05-04 09:16:15 -0400 (Thu, 04 May 2006) | 1 line
0.96.D405 - Add MergeFlags() and AddFlags() methods. (Greg Noel) Support recognizing compi
........
r1462 | stevenknight | 2006-05-04 23:46:53 -0400 (Thu, 04 May 2006) | 1 line
0.96.D406 - Fix stack trace when ParseFlags has a null string.
........
r1464 | stevenknight | 2006-05-05 17:21:27 -0400 (Fri, 05 May 2006) | 1 line
0.96.D408 - Fix the string displayed by InstallAs() when called through the default construc
........
r1465 | stevenknight | 2006-05-05 18:30:28 -0400 (Fri, 05 May 2006) | 1 line
0.96.D409 - Fix test/ParseConfig.py, broken in the previous checkin by ParseFlags() changes.
........
r1466 | stevenknight | 2006-05-05 20:42:35 -0400 (Fri, 05 May 2006) | 1 line
0.96.D407 - Avoid recursive calls to main() in SConf test programs. (Karol Pietrzak)
........
r1467 | stevenknight | 2006-05-06 00:27:21 -0400 (Sat, 06 May 2006) | 1 line
0.96.D410 - Catch errors from commands that ParseConfig() calls. (John Pye)
........
r1468 | stevenknight | 2006-05-06 10:55:38 -0400 (Sat, 06 May 2006) | 1 line
0.96.D411 - Significant taskmaster speedup by using reference counts, not list manipulation.
........
r1469 | stevenknight | 2006-05-06 18:38:02 -0400 (Sat, 06 May 2006) | 1 line
0.96.D413 - TeX improvements.
........
r1471 | stevenknight | 2006-05-07 09:07:58 -0400 (Sun, 07 May 2006) | 2 lines
Delete properties interfering with clean .jpg checkout.
........
r1472 | stevenknight | 2006-05-07 09:23:54 -0400 (Sun, 07 May 2006) | 1 line
0.96.D412 - Windows portability fixes for two tests and ParseConfig() execution.
........
r1473 | stevenknight | 2006-05-07 09:30:11 -0400 (Sun, 07 May 2006) | 1 line
0.96.D414 - Various man page and documentation updates.
........
r1474 | stevenknight | 2006-05-07 23:53:12 -0400 (Sun, 07 May 2006) | 1 line
0.96.D415 - Initial infrastructure for executing tests under QMTest. (Stefan Seefeld)
........
r1476 | stevenknight | 2006-05-09 00:03:47 -0400 (Tue, 09 May 2006) | 1 line
0.96.D416 - Fix QMTest infrastructure to avoid listing directories with no tests and to find
........
r1477 | stevenknight | 2006-05-16 06:47:51 -0400 (Tue, 16 May 2006) | 1 line
0.96.D417 - Fix Alias turning Entries into Nodes or Dirs too soon.
........
r1478 | stevenknight | 2006-05-17 08:32:58 -0400 (Wed, 17 May 2006) | 1 line
0.96.D418 - Next QMTest changes (including fixing copyrights).
........
r1479 | stevenknight | 2006-05-18 05:07:06 -0400 (Thu, 18 May 2006) | 1 line
0.96.D419 - Fix DVIPDF tests after recent changes.
........
r1497 | stevenknight | 2006-05-23 08:47:01 -0400 (Tue, 23 May 2006) | 1 line
0.96.D420 - Better error message when trying to build a file from an unknown sufix. (Gary O
........
r1498 | stevenknight | 2006-05-23 09:38:52 -0400 (Tue, 23 May 2006) | 1 line
0.96.D421 - Suppress duplicate entries in latest TeX patch. (Joel B. Mohler)
........
r1499 | stevenknight | 2006-05-23 22:00:06 -0400 (Tue, 23 May 2006) | 1 line
0.96.D422 - Add tests for tuple variable expansion. (Gary Oberbrunner)
........
r1515 | stevenknight | 2006-06-12 06:44:24 -0400 (Mon, 12 Jun 2006) | 1 line
0.96.D423 - More QMTest work: start giving runtest.py its own tests, more functionality for
........
r1517 | stevenknight | 2006-06-21 07:34:30 -0400 (Wed, 21 Jun 2006) | 1 line
0.96.D424 - Move test/Configure.py and test/Options.py to avoid confusion with similarly-nam
........
r1518 | stevenknight | 2006-06-21 12:40:37 -0400 (Wed, 21 Jun 2006) | 1 line
0.96.D425 - Change the QMTest infrastructure to use File naming, not Python. Rename tests w
........
r1533 | stevenknight | 2006-07-23 20:10:08 -0400 (Sun, 23 Jul 2006) | 1 line
0.96.D426 - Fix ramifications of changing when Node disambiguation happens.
........
r1535 | stevenknight | 2006-07-24 06:40:43 -0400 (Mon, 24 Jul 2006) | 3 lines
Initialized merge tracking via "svnmerge" with revisions "1-1534" from
http://scons.tigris.org/svn/scons/trunk
........
r1536 | stevenknight | 2006-07-24 21:45:40 -0400 (Mon, 24 Jul 2006) | 2 lines
Remove svnmerge-integrated property to start over.
........
r1538 | stevenknight | 2006-07-24 21:51:32 -0400 (Mon, 24 Jul 2006) | 3 lines
Initialized merge tracking via "svnmerge" with revisions "1-1440" from
http://scons.tigris.org/svn/scons/trunk
........
Diffstat (limited to 'etc/unittest.py')
| -rw-r--r-- | etc/unittest.py | 693 |
1 files changed, 0 insertions, 693 deletions
diff --git a/etc/unittest.py b/etc/unittest.py deleted file mode 100644 index f0540a5..0000000 --- a/etc/unittest.py +++ /dev/null @@ -1,693 +0,0 @@ -#!/usr/bin/env python -""" -Python unit testing framework, based on Erich Gamma's JUnit and Kent Beck's -Smalltalk testing framework. - -Further information is available in the bundled documentation, and from - - http://pyunit.sourceforge.net/ - -This module contains the core framework classes that form the basis of -specific test cases and suites (TestCase, TestSuite etc.), and also a -text-based utility class for running the tests and reporting the results -(TextTestRunner). - -Copyright (c) 1999, 2000, 2001 Steve Purcell -This module is free software, and you may redistribute it and/or modify -it under the same terms as Python itself, so long as this copyright message -and disclaimer are retained in their original form. - -IN NO EVENT SHALL THE AUTHOR BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, -SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF -THIS CODE, EVEN IF THE AUTHOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGE. - -THE AUTHOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -PARTICULAR PURPOSE. THE CODE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, -AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, -SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. -""" - -__author__ = "Steve Purcell (stephen_purcell@yahoo.com)" -__version__ = "$ Revision: 1.23 $"[11:-2] - -import time -import sys -import traceback -import string -import os - -############################################################################## -# A platform-specific concession to help the code work for JPython users -############################################################################## - -plat = string.lower(sys.platform) -_isJPython = string.find(plat, 'java') >= 0 or string.find(plat, 'jdk') >= 0 -del plat - - -############################################################################## -# Test framework core -############################################################################## - -class TestResult: - """Holder for test result information. - - Test results are automatically managed by the TestCase and TestSuite - classes, and do not need to be explicitly manipulated by writers of tests. - - Each instance holds the total number of tests run, and collections of - failures and errors that occurred among those test runs. The collections - contain tuples of (testcase, exceptioninfo), where exceptioninfo is a - tuple of values as returned by sys.exc_info(). - """ - def __init__(self): - self.failures = [] - self.errors = [] - self.testsRun = 0 - self.shouldStop = 0 - - def startTest(self, test): - "Called when the given test is about to be run" - self.testsRun = self.testsRun + 1 - - def stopTest(self, test): - "Called when the given test has been run" - pass - - def addError(self, test, err): - "Called when an error has occurred" - self.errors.append((test, err)) - - def addFailure(self, test, err): - "Called when a failure has occurred" - self.failures.append((test, err)) - - def wasSuccessful(self): - "Tells whether or not this result was a success" - return len(self.failures) == len(self.errors) == 0 - - def stop(self): - "Indicates that the tests should be aborted" - self.shouldStop = 1 - - def __repr__(self): - return "<%s run=%i errors=%i failures=%i>" % \ - (self.__class__, self.testsRun, len(self.errors), - len(self.failures)) - - -class TestCase: - """A class whose instances are single test cases. - - Test authors should subclass TestCase for their own tests. Construction - and deconstruction of the test's environment ('fixture') can be - implemented by overriding the 'setUp' and 'tearDown' methods respectively. - - By default, the test code itself should be placed in a method named - 'runTest'. - - If the fixture may be used for many test cases, create as - many test methods as are needed. When instantiating such a TestCase - subclass, specify in the constructor arguments the name of the test method - that the instance is to execute. - - If it is necessary to override the __init__ method, the base class - __init__ method must always be called. - """ - def __init__(self, methodName='runTest'): - """Create an instance of the class that will use the named test - method when executed. Raises a ValueError if the instance does - not have a method with the specified name. - """ - try: - self.__testMethod = getattr(self,methodName) - except AttributeError: - raise ValueError, "no such test method in %s: %s" % \ - (self.__class__, methodName) - - def setUp(self): - "Hook method for setting up the test fixture before exercising it." - pass - - def tearDown(self): - "Hook method for deconstructing the test fixture after testing it." - pass - - def countTestCases(self): - return 1 - - def defaultTestResult(self): - return TestResult() - - def shortDescription(self): - """Returns a one-line description of the test, or None if no - description has been provided. - - The default implementation of this method returns the first line of - the specified test method's docstring. - """ - doc = self.__testMethod.__doc__ - return doc and string.strip(string.split(doc, "\n")[0]) or None - - def id(self): - return "%s.%s" % (self.__class__, self.__testMethod.__name__) - - def __str__(self): - return "%s (%s)" % (self.__testMethod.__name__, self.__class__) - - def __repr__(self): - return "<%s testMethod=%s>" % \ - (self.__class__, self.__testMethod.__name__) - - def run(self, result=None): - return self(result) - - def __call__(self, result=None): - if result is None: result = self.defaultTestResult() - result.startTest(self) - try: - try: - self.setUp() - except: - result.addError(self,self.__exc_info()) - return - - try: - self.__testMethod() - except AssertionError, e: - result.addFailure(self,self.__exc_info()) - except: - result.addError(self,self.__exc_info()) - - try: - self.tearDown() - except: - result.addError(self,self.__exc_info()) - finally: - result.stopTest(self) - - def debug(self): - """Run the test without collecting errors in a TestResult""" - self.setUp() - self.__testMethod() - self.tearDown() - - def assert_(self, expr, msg=None): - """Equivalent of built-in 'assert', but is not optimised out when - __debug__ is false. - """ - if not expr: - raise AssertionError, msg - - failUnless = assert_ - - def failIf(self, expr, msg=None): - "Fail the test if the expression is true." - apply(self.assert_,(not expr,msg)) - - def assertRaises(self, excClass, callableObj, *args, **kwargs): - """Assert that an exception of class excClass is thrown - by callableObj when invoked with arguments args and keyword - arguments kwargs. If a different type of exception is - thrown, it will not be caught, and the test case will be - deemed to have suffered an error, exactly as for an - unexpected exception. - """ - try: - apply(callableObj, args, kwargs) - except excClass: - return - else: - if hasattr(excClass,'__name__'): excName = excClass.__name__ - else: excName = str(excClass) - raise AssertionError, excName - - def fail(self, msg=None): - """Fail immediately, with the given message.""" - raise AssertionError, msg - - def __exc_info(self): - """Return a version of sys.exc_info() with the traceback frame - minimised; usually the top level of the traceback frame is not - needed. - """ - exctype, excvalue, tb = sys.exc_info() - newtb = tb.tb_next - if newtb is None: - return (exctype, excvalue, tb) - return (exctype, excvalue, newtb) - - -class TestSuite: - """A test suite is a composite test consisting of a number of TestCases. - - For use, create an instance of TestSuite, then add test case instances. - When all tests have been added, the suite can be passed to a test - runner, such as TextTestRunner. It will run the individual test cases - in the order in which they were added, aggregating the results. When - subclassing, do not forget to call the base class constructor. - """ - def __init__(self, tests=()): - self._tests = [] - self.addTests(tests) - - def __repr__(self): - return "<%s tests=%s>" % (self.__class__, self._tests) - - __str__ = __repr__ - - def countTestCases(self): - cases = 0 - for test in self._tests: - cases = cases + test.countTestCases() - return cases - - def addTest(self, test): - self._tests.append(test) - - def addTests(self, tests): - for test in tests: - self.addTest(test) - - def run(self, result): - return self(result) - - def __call__(self, result): - for test in self._tests: - if result.shouldStop: - break - test(result) - return result - - def debug(self): - """Run the tests without collecting errors in a TestResult""" - for test in self._tests: test.debug() - - -class FunctionTestCase(TestCase): - """A test case that wraps a test function. - - This is useful for slipping pre-existing test functions into the - PyUnit framework. Optionally, set-up and tidy-up functions can be - supplied. As with TestCase, the tidy-up ('tearDown') function will - always be called if the set-up ('setUp') function ran successfully. - """ - - def __init__(self, testFunc, setUp=None, tearDown=None, - description=None): - TestCase.__init__(self) - self.__setUpFunc = setUp - self.__tearDownFunc = tearDown - self.__testFunc = testFunc - self.__description = description - - def setUp(self): - if self.__setUpFunc is not None: - self.__setUpFunc() - - def tearDown(self): - if self.__tearDownFunc is not None: - self.__tearDownFunc() - - def runTest(self): - self.__testFunc() - - def id(self): - return self.__testFunc.__name__ - - def __str__(self): - return "%s (%s)" % (self.__class__, self.__testFunc.__name__) - - def __repr__(self): - return "<%s testFunc=%s>" % (self.__class__, self.__testFunc) - - def shortDescription(self): - if self.__description is not None: return self.__description - doc = self.__testFunc.__doc__ - return doc and string.strip(string.split(doc, "\n")[0]) or None - - - -############################################################################## -# Convenience functions -############################################################################## - -def getTestCaseNames(testCaseClass, prefix, sortUsing=cmp): - """Extracts all the names of functions in the given test case class - and its base classes that start with the given prefix. This is used - by makeSuite(). - """ - testFnNames = filter(lambda n,p=prefix: n[:len(p)] == p, - dir(testCaseClass)) - for baseclass in testCaseClass.__bases__: - testFnNames = testFnNames + \ - getTestCaseNames(baseclass, prefix, sortUsing=None) - if sortUsing: - testFnNames.sort(sortUsing) - return testFnNames - - -def makeSuite(testCaseClass, prefix='test', sortUsing=cmp): - """Returns a TestSuite instance built from all of the test functions - in the given test case class whose names begin with the given - prefix. The cases are sorted by their function names - using the supplied comparison function, which defaults to 'cmp'. - """ - cases = map(testCaseClass, - getTestCaseNames(testCaseClass, prefix, sortUsing)) - return TestSuite(cases) - - -def createTestInstance(name, module=None): - """Finds tests by their name, optionally only within the given module. - - Return the newly-constructed test, ready to run. If the name contains a ':' - then the portion of the name after the colon is used to find a specific - test case within the test case class named before the colon. - - Examples: - findTest('examples.listtests.suite') - -- returns result of calling 'suite' - findTest('examples.listtests.ListTestCase:checkAppend') - -- returns result of calling ListTestCase('checkAppend') - findTest('examples.listtests.ListTestCase:check-') - -- returns result of calling makeSuite(ListTestCase, prefix="check") - """ - - spec = string.split(name, ':') - if len(spec) > 2: raise ValueError, "illegal test name: %s" % name - if len(spec) == 1: - testName = spec[0] - caseName = None - else: - testName, caseName = spec - parts = string.split(testName, '.') - if module is None: - if len(parts) < 2: - raise ValueError, "incomplete test name: %s" % name - constructor = __import__(string.join(parts[:-1],'.')) - parts = parts[1:] - else: - constructor = module - for part in parts: - constructor = getattr(constructor, part) - if not callable(constructor): - raise ValueError, "%s is not a callable object" % constructor - if caseName: - if caseName[-1] == '-': - prefix = caseName[:-1] - if not prefix: - raise ValueError, "prefix too short: %s" % name - test = makeSuite(constructor, prefix=prefix) - else: - test = constructor(caseName) - else: - test = constructor() - if not hasattr(test,"countTestCases"): - raise TypeError, \ - "object %s found with spec %s is not a test" % (test, name) - return test - - -############################################################################## -# Text UI -############################################################################## - -class _WritelnDecorator: - """Used to decorate file-like objects with a handy 'writeln' method""" - def __init__(self,stream): - self.stream = stream - if _isJPython: - import java.lang.System - self.linesep = java.lang.System.getProperty("line.separator") - else: - self.linesep = os.linesep - - def __getattr__(self, attr): - return getattr(self.stream,attr) - - def writeln(self, *args): - if args: apply(self.write, args) - self.write(self.linesep) - - -class _JUnitTextTestResult(TestResult): - """A test result class that can print formatted text results to a stream. - - Used by JUnitTextTestRunner. - """ - def __init__(self, stream): - self.stream = stream - TestResult.__init__(self) - - def addError(self, test, error): - TestResult.addError(self,test,error) - self.stream.write('E') - self.stream.flush() - if error[0] is KeyboardInterrupt: - self.shouldStop = 1 - - def addFailure(self, test, error): - TestResult.addFailure(self,test,error) - self.stream.write('F') - self.stream.flush() - - def startTest(self, test): - TestResult.startTest(self,test) - self.stream.write('.') - self.stream.flush() - - def printNumberedErrors(self,errFlavour,errors): - if not errors: return - if len(errors) == 1: - self.stream.writeln("There was 1 %s:" % errFlavour) - else: - self.stream.writeln("There were %i %ss:" % - (len(errors), errFlavour)) - i = 1 - for test,error in errors: - errString = string.join(apply(traceback.format_exception,error),"") - self.stream.writeln("%i) %s" % (i, test)) - self.stream.writeln(errString) - i = i + 1 - - def printErrors(self): - self.printNumberedErrors("error",self.errors) - - def printFailures(self): - self.printNumberedErrors("failure",self.failures) - - def printHeader(self): - self.stream.writeln() - if self.wasSuccessful(): - self.stream.writeln("OK (%i tests)" % self.testsRun) - else: - self.stream.writeln("!!!FAILURES!!!") - self.stream.writeln("Test Results") - self.stream.writeln() - self.stream.writeln("Run: %i ; Failures: %i ; Errors: %i" % - (self.testsRun, len(self.failures), - len(self.errors))) - - def printResult(self): - self.printHeader() - self.printErrors() - self.printFailures() - - -class JUnitTextTestRunner: - """A test runner class that displays results in textual form. - - The display format approximates that of JUnit's 'textui' test runner. - This test runner may be removed in a future version of PyUnit. - """ - def __init__(self, stream=sys.stderr): - self.stream = _WritelnDecorator(stream) - - def run(self, test): - "Run the given test case or test suite." - result = _JUnitTextTestResult(self.stream) - startTime = time.time() - test(result) - stopTime = time.time() - self.stream.writeln() - self.stream.writeln("Time: %.3fs" % float(stopTime - startTime)) - result.printResult() - return result - - -############################################################################## -# Verbose text UI -############################################################################## - -class _VerboseTextTestResult(TestResult): - """A test result class that can print formatted text results to a stream. - - Used by VerboseTextTestRunner. - """ - def __init__(self, stream, descriptions): - TestResult.__init__(self) - self.stream = stream - self.lastFailure = None - self.descriptions = descriptions - - def startTest(self, test): - TestResult.startTest(self, test) - if self.descriptions: - self.stream.write(test.shortDescription() or str(test)) - else: - self.stream.write(str(test)) - self.stream.write(" ... ") - - def stopTest(self, test): - TestResult.stopTest(self, test) - if self.lastFailure is not test: - self.stream.writeln("ok") - - def addError(self, test, err): - TestResult.addError(self, test, err) - self._printError("ERROR", test, err) - self.lastFailure = test - if err[0] is KeyboardInterrupt: - self.shouldStop = 1 - - def addFailure(self, test, err): - TestResult.addFailure(self, test, err) - self._printError("FAIL", test, err) - self.lastFailure = test - - def _printError(self, flavour, test, err): - errLines = [] - separator1 = "\t" + '=' * 70 - separator2 = "\t" + '-' * 70 - if not self.lastFailure is test: - self.stream.writeln() - self.stream.writeln(separator1) - self.stream.writeln("\t%s" % flavour) - self.stream.writeln(separator2) - for line in apply(traceback.format_exception, err): - for l in string.split(line,"\n")[:-1]: - self.stream.writeln("\t%s" % l) - self.stream.writeln(separator1) - - -class VerboseTextTestRunner: - """A test runner class that displays results in textual form. - - It prints out the names of tests as they are run, errors as they - occur, and a summary of the results at the end of the test run. - """ - def __init__(self, stream=sys.stderr, descriptions=1): - self.stream = _WritelnDecorator(stream) - self.descriptions = descriptions - - def run(self, test): - "Run the given test case or test suite." - result = _VerboseTextTestResult(self.stream, self.descriptions) - startTime = time.time() - test(result) - stopTime = time.time() - timeTaken = float(stopTime - startTime) - self.stream.writeln("-" * 78) - run = result.testsRun - self.stream.writeln("Ran %d test%s in %.3fs" % - (run, run > 1 and "s" or "", timeTaken)) - self.stream.writeln() - if not result.wasSuccessful(): - self.stream.write("FAILED (") - failed, errored = map(len, (result.failures, result.errors)) - if failed: - self.stream.write("failures=%d" % failed) - if errored: - if failed: self.stream.write(", ") - self.stream.write("errors=%d" % errored) - self.stream.writeln(")") - else: - self.stream.writeln("OK") - return result - - -# Which flavour of TextTestRunner is the default? -TextTestRunner = VerboseTextTestRunner - - -############################################################################## -# Facilities for running tests from the command line -############################################################################## - -class TestProgram: - """A command-line program that runs a set of tests; this is primarily - for making test modules conveniently executable. - """ - USAGE = """\ -Usage: %(progName)s [-h|--help] [test[:(casename|prefix-)]] [...] - -Examples: - %(progName)s - run default set of tests - %(progName)s MyTestSuite - run suite 'MyTestSuite' - %(progName)s MyTestCase:checkSomething - run MyTestCase.checkSomething - %(progName)s MyTestCase:check- - run all 'check*' test methods - in MyTestCase -""" - def __init__(self, module='__main__', defaultTest=None, - argv=None, testRunner=None): - if type(module) == type(''): - self.module = __import__(module) - for part in string.split(module,'.')[1:]: - self.module = getattr(self.module, part) - else: - self.module = module - if argv is None: - argv = sys.argv - self.defaultTest = defaultTest - self.testRunner = testRunner - self.progName = os.path.basename(argv[0]) - self.parseArgs(argv) - self.createTests() - self.runTests() - - def usageExit(self, msg=None): - if msg: print msg - print self.USAGE % self.__dict__ - sys.exit(2) - - def parseArgs(self, argv): - import getopt - try: - options, args = getopt.getopt(argv[1:], 'hH', ['help']) - opts = {} - for opt, value in options: - if opt in ('-h','-H','--help'): - self.usageExit() - if len(args) == 0 and self.defaultTest is None: - raise getopt.error, "No default test is defined." - if len(args) > 0: - self.testNames = args - else: - self.testNames = (self.defaultTest,) - except getopt.error, msg: - self.usageExit(msg) - - def createTests(self): - tests = [] - for testName in self.testNames: - tests.append(createTestInstance(testName, self.module)) - self.test = TestSuite(tests) - - def runTests(self): - if self.testRunner is None: - self.testRunner = TextTestRunner() - result = self.testRunner.run(self.test) - sys.exit(not result.wasSuccessful()) - -main = TestProgram - - -############################################################################## -# Executing this module from the command line -############################################################################## - -if __name__ == "__main__": - main(module=None) |
