Viewing file: TestSuite.py (11.39 KB) -rw-r--r-- Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
######################################################################## # $Header: /var/local/cvsroot/4Suite/Ft/Lib/TestSuite/TestSuite.py,v 1.12 2002/12/19 20:31:13 jkloth Exp $ """ Provides the TestSuite class, which represents the package(s) to test.
Copyright 2002 Fourthought, Inc. (USA). Detailed license and copyright information: http://4suite.org/COPYRIGHT Project home, documentation, distributions: http://4suite.org/ """
__revision__ = "$Id: TestSuite.py,v 1.12 2002/12/19 20:31:13 jkloth Exp $"
import getopt, sys, os, imp from types import *
import TestModule, Tester from Errors import *
USAGE = """\ Usage: %(script)s [options] [test] [...] %(script)s --help-tests %(script)s --help %(script)s --help [test]
Examples: %(script)s run default set of tests %(script)s directory run all tests in 'directory' %(script)s directory%(sep)sfile run just 'file' from 'directory' """
class TestSuite: """ A command-line program that runs a set of tests; this is primarily for making test modules conveniently executable. """
options = [ ('help', 'h', 'Show detailed help message'), ('help-tests', 't', 'List all available tests'), ('verbose', 'v', 'Increase display verbosity'), ('quiet', 'q', 'Decrease display verbosity'), ('mode=', 'm', 'Add mode to default modes to run'), ('skip=', 'k', 'Remove a mode from the modes to run'), ('full', 'f', 'Use all modes'), ('stop', 's', 'Stop on errors'), ('nocolor', 'n', 'Disable ANSI color sequences'), ('noreport', 'r', 'Disable report generation'), ('outfile=', 'o', 'Specify an output file for all results'), ('offline', 'l', 'Skip tests requiring internet connection') ]
negative_opts = {'quiet' : 'verbose', 'nocolor' : 'color', 'noreport' : 'report', }
# options that can only be true or false boolean_opts = ('full', 'stop', 'nocolor', 'noreport', 'offline', 'help', 'help-tests') def __init__(self, attrs):
# Default values for command-line options self.verbose = 2 # counter self.mode = [] # string list self.skip = [] # string list self.full = 0 # boolean self.stop = 0 # boolean self.color = 1 # boolean self.report = 1 # boolean self.outfile = '' # string self.offline = 0 # boolean self.help = 0 # boolean self.help_tests = 0 # boolean # 'script_name' and 'script_args' are usually set to sys.argv[0] # and sys.argv[1:], but they can be overridden when the caller is # not necessarily a setup script run from the command-line. self.script_name = None self.script_args = None self.name = None self.packages = None
# Now we'll use the attrs dictionary (ultimately, keyword args from # the setup script) to possibly override any or all of these # distribution options. for key, value in attrs.items(): if hasattr(self, key): setattr(self, key, value) else: raise TestSuiteSetupError('invalid test option %r' % key) return
def _grokOptions(self): long_opts = [] short_opts = [] short2long = {} for option in self.options: try: (long, short, help) = option except ValueError: raise TestSuiteInternalError, \ 'invalid option tuple %r' % option
# Type and value check the option names if not isinstance(long, StringType) or len(long) < 2: raise TestSuiteInternalError, \ 'invalid long option %r' % long
if short and not isinstance(short, StringType) and len(short) > 1: raise TestSuiteInternalError, \ 'invalid short option %r' % short
long_opts.append(long)
if short: if long.endswith('='): short = short + ':' long = long[:-1]
short2long[short[0]] = long short_opts.append(short)
return (''.join(short_opts), long_opts, short2long)
def _getopt(self, args): short_opts, long_opts, short2long = self._grokOptions()
parsed_args = [] parsed_opts = []
while args: try: opts, args = getopt.getopt(args, short_opts, long_opts) except getopt.error, error: raise TestSuiteArgumentError(str(error))
# Convert all options to their long form for opt, value in opts: if len(opt) == 2 and opt[0] == '-': # a short option opt = short2long[opt[1]] else: # a long option opt = opt[2:] parsed_opts.append((opt, value)) # Scan the arguments for any remaining options while args and args[0][0] != '-': path = args.pop(0) # If the arg is an existing file/directory, convert it to a # Python package path, otherwise assume a valid package. if os.path.exists(path): # Convert path to pkg.mod notation path = os.path.normpath(path) dirname = os.path.dirname(path) modname = TestModule.GetModuleName(path) if dirname: names = dirname.split(os.sep) names.append(modname) path = '.'.join(names) else: path = modname
# Add Python package path to the parsed arguments parsed_args.append(path)
# Handle the options now for (name, value) in parsed_opts: if name in self.boolean_opts: # If specified it must be true value = 1
alias = self.negative_opts.get(name) if alias: attr = alias.replace('-', '_') else: attr = name.replace('-', '_')
if not hasattr(self, attr): raise TestSuiteInternalError, \ "missing attribute for option %r" % name
current = getattr(self, attr) if name in self.boolean_opts: # boolean if alias: setattr(self, attr, 0) else: setattr(self, attr, 1) elif isinstance(current, IntType): # counter if alias: setattr(self, attr, current - 1) else: setattr(self, attr, current + 1) elif isinstance(current, ListType): # string list if alias: while value in current: current.remove(value) else: current.append(value) elif isinstance(current, StringType): # string setattr(self, attr, value) else: raise TestSuiteInternalError, \ "unknown type for option %r" % name
return parsed_args def addTests(self, packages): for package in packages: testobj = self.test for step in package.split('.'): # See if this step has already been added for test in testobj.tests: if test.name == step: # Found an existing test, reuse it testobj = test break else: # Create a new test testobj = testobj.addTest(step) return
def parseCommandLine(self): """ Parse the test script's command line, taken from the 'script_args' instance attribute (which defaults to 'sys.argv[1:]'). This is first processed for options that set attributes of the TestSuite instance. Then, it is scanned for test arguments. """ packages = self._getopt(self.script_args)
self.test = TestModule.TestModule(self.name, None, self.mode, self.skip, self.full) if self.help_tests: # ignore any supplied arguments print self.generateUsage() print 'Available tests:' self.showTests() return 0 # done
if self.help: # display usage and if there are tests specified info about them self.showHelp(packages) return 0 # done self.addTests(packages or self.packages) # Signal caller that is OK to continue return 1
def showTests(self): indent = ' '*2 self.addTests(self.packages) for test in self.test.getTests(): test.showTests(indent) return
def generateUsage(self): usage = USAGE % {'script' : os.path.basename(self.script_name), 'sep' : os.sep} return usage
def showHelp(self, tests): print self.generateUsage() # Display the options print 'Options:' display_opts = [] max_opt = 0 for opt in self.options: long = opt[0] if long[-1] == '=': long = '%s<%s>' % (long, long[:-1]) display = '-%s, --%s' % (opt[1], long) display_opts.append((display, opt[2])) if len(display) > max_opt: max_opt = len(display) for display, help in display_opts: print ' %-*s %s' % (max_opt, display, help) print
# Display detailed help for the given tests for path in tests: modes = []
testobj = self.test for step in path.split('.'): testobj = testobj.loadTest(step) for mode in testobj.getModes([], [], 1): if mode.name: modes.append((mode.name, testobj.path))
if modes: print 'Modes for %r:' % testobj.path for (name, path) in modes: if path != testobj.path: print " %s (declared in %s)" % (name, path) else: print " %s" % name print
subtests = [ test for test in testobj.getTests() if isinstance(test, TestModule.TestModule) ] if subtests: print 'Sub-tests for %r:' % testobj.path for test in subtests: print " %s" % test.name print return
def runTests(self): tester = Tester.Tester(self.stop, self.color, self.verbose) tester.offline = self.offline try: for test in self.test.getTests(): test.run(tester) except KeyboardInterrupt: sys.stderr.write('\n%s\n' % ('='*72)) sys.stderr.write('\nTesting interrupted\n')
if self.report: tester.report() return
|