X-Git-Url: http://git.tremily.us/?a=blobdiff_plain;f=runtest.py;h=7fb505a3872aab9594977417074e2e66ab1c6524;hb=11e8e47454040247b5524a7d00358eb767e7c3c0;hp=b5ffbea744544cddd0ba2eda64987fec18e059b2;hpb=b7a2ffa828c643e0d83bf72d90a285808704cf89;p=scons.git diff --git a/runtest.py b/runtest.py index b5ffbea7..7fb505a3 100644 --- a/runtest.py +++ b/runtest.py @@ -1,12 +1,14 @@ #!/usr/bin/env python # +# __COPYRIGHT__ +# # runtest.py - wrapper script for running SCons tests # # This script mainly exists to set PYTHONPATH to the right list of # directories to test the SCons modules. # # By default, it directly uses the modules in the local tree: -# ./src/ (source files we ship) and ./etc/ (other modules we don't). +# ./src/ (source files we ship) and ./QMTest/ (other modules we don't). # # HOWEVER, now that SCons has Repository support, we don't have # Aegis copy all of the files into the local tree. So if you're @@ -22,72 +24,116 @@ # # Options: # -# -a Run all tests; does a virtual 'find' for -# all SCons tests under the current directory. +# -a Run all tests; does a virtual 'find' for +# all SCons tests under the current directory. +# +# --aegis Print test results to an output file (specified +# by the -o option) in the format expected by +# aetest(5). This is intended for use in the +# batch_test_command field in the Aegis project +# config file. +# +# -d Debug. Runs the script under the Python +# debugger (pdb.py) so you don't have to +# muck with PYTHONPATH yourself. # -# -d Debug. Runs the script under the Python -# debugger (pdb.py) so you don't have to -# muck with PYTHONPATH yourself. +# -f file Only execute the tests listed in the specified +# file. # # -h Print the help and exit. # -# -o file Print test results to the specified file -# in the format expected by aetest(5). This -# is intended for use in the batch_test_command -# field in the Aegis project config file. +# -l List available tests and exit. +# +# -n No execute, just print command lines. +# +# -o file Print test results to the specified file. +# The --aegis and --xml options specify the +# output format. +# +# -P Python Use the specified Python interpreter. +# +# -p package Test against the specified package. +# +# --passed In the final summary, also report which tests +# passed. The default is to only report tests +# which failed or returned NO RESULT. +# +# -q Quiet. By default, runtest.py prints the +# command line it will execute before +# executing it. This suppresses that print. # -# -p package Test against the specified package. +# --sp The Aegis search path. # -# -q Quiet. By default, runtest.py prints the -# command line it will execute before -# executing it. This suppresses that print. +# --spe The Aegis executable search path. # -# -X The scons "script" is an executable; don't -# feed it to Python. +# -t Print the execution time of each test. +# +# -X The scons "script" is an executable; don't +# feed it to Python. # # -x scons The scons script to use for tests. # +# --xml Print test results to an output file (specified +# by the -o option) in an SCons-specific XML format. +# This is (will be) used for reporting results back +# to a central SCons test monitoring infrastructure. +# # (Note: There used to be a -v option that specified the SCons # version to be tested, when we were installing in a version-specific # library directory. If we ever resurrect that as the default, then # you can find the appropriate code in the 0.04 version of this script, # rather than reinventing that wheel.) # +from __future__ import generators ### KEEP FOR COMPATIBILITY FIXERS import getopt import glob import os -import os.path import re import stat -import string import sys +import time + +if not hasattr(os, 'WEXITSTATUS'): + os.WEXITSTATUS = lambda x: x + +cwd = os.getcwd() all = 0 +baseline = 0 +builddir = os.path.join(cwd, 'build') debug = '' -tests = [] -printcmd = 1 +execute_tests = 1 +format = None +list_only = None +printcommand = 1 package = None +print_passed_summary = None scons = None scons_exec = None -output = None - -cwd = os.getcwd() - -if sys.platform == 'win32': - lib_dir = os.path.join(sys.exec_prefix, "lib") -else: - # The hard-coded "python" here is the directory name, - # not an executable, so it's all right. - lib_dir = os.path.join(sys.exec_prefix, "lib", "python" + sys.version[0:3]) +outputfile = None +testlistfile = None +version = '' +print_times = None +python = None +sp = None +spe = None helpstr = """\ Usage: runtest.py [OPTIONS] [TEST ...] Options: -a, --all Run all tests. + --aegis Print results in Aegis format. + -b BASE, --baseline BASE Run test scripts against baseline BASE. + --builddir DIR Directory in which packages were built. -d, --debug Run test scripts under the Python debugger. + -f FILE, --file FILE Run tests in specified FILE. -h, --help Print this message and exit. - -o FILE, --output FILE Print test results to FILE (Aegis format). + -l, --list List available tests and exit. + -n, --no-exec No execute, just print command lines. + --noqmtest Execute tests directly, not using QMTest. + -o FILE, --output FILE Print test results to FILE. + -P Python Use the specified Python interpreter. -p PACKAGE, --package PACKAGE Test against the specified PACKAGE: deb Debian @@ -98,56 +144,199 @@ Options: src-zip .zip source package tar-gz .tar.gz distribution zip .zip distribution + --passed Summarize which tests passed. + --qmtest Run using the QMTest harness. -q, --quiet Don't print the test being executed. + --sp PATH The Aegis search path. + --spe PATH The Aegis executable search path. + -t, --time Print test execution time. + -v version Specify the SCons version. + --verbose=LEVEL Set verbose level: 1 = print executed commands, + 2 = print commands and non-zero output, + 3 = print commands and all output. -X Test script is executable, don't feed to Python. -x SCRIPT, --exec SCRIPT Test SCRIPT. + --xml Print results in SCons XML format. """ -opts, args = getopt.getopt(sys.argv[1:], "adho:p:qXx:", - ['all', 'debug', 'help', 'output=', - 'package=', 'quiet', 'exec=']) +opts, args = getopt.getopt(sys.argv[1:], "ab:df:hlno:P:p:qv:Xx:t", + ['all', 'aegis', 'baseline=', 'builddir=', + 'debug', 'file=', 'help', + 'list', 'no-exec', 'noqmtest', 'output=', + 'package=', 'passed', 'python=', 'qmtest', + 'quiet', 'sp=', 'spe=', 'time', + 'version=', 'exec=', + 'verbose=', 'xml']) for o, a in opts: - if o == '-a' or o == '--all': + if o in ['-a', '--all']: all = 1 - elif o == '-d' or o == '--debug': - debug = os.path.join(lib_dir, "pdb.py") - elif o == '-h' or o == '--help': + elif o in ['-b', '--baseline']: + baseline = a + elif o in ['--builddir']: + builddir = a + if not os.path.isabs(builddir): + builddir = os.path.normpath(os.path.join(cwd, builddir)) + elif o in ['-d', '--debug']: + for dir in sys.path: + pdb = os.path.join(dir, 'pdb.py') + if os.path.exists(pdb): + debug = pdb + break + elif o in ['-f', '--file']: + if not os.path.isabs(a): + a = os.path.join(cwd, a) + testlistfile = a + elif o in ['-h', '--help']: print helpstr sys.exit(0) - elif o == '-o' or o == '--output': - if not os.path.isabs(a): + elif o in ['-l', '--list']: + list_only = 1 + elif o in ['-n', '--no-exec']: + execute_tests = None + elif o in ['--noqmtest']: + qmtest = None + elif o in ['-o', '--output']: + if a != '-' and not os.path.isabs(a): a = os.path.join(cwd, a) - output = a - elif o == '-p' or o == '--package': + outputfile = a + elif o in ['-p', '--package']: package = a - elif o == '-q' or o == '--quiet': - printcmd = 0 - elif o == '-X': + elif o in ['--passed']: + print_passed_summary = 1 + elif o in ['-P', '--python']: + python = a + elif o in ['--qmtest']: + if sys.platform == 'win32': + # typically in c:/PythonXX/Scripts + qmtest = 'qmtest.py' + else: + qmtest = 'qmtest' + elif o in ['-q', '--quiet']: + printcommand = 0 + elif o in ['--sp']: + sp = a.split(os.pathsep) + elif o in ['--spe']: + spe = a.split(os.pathsep) + elif o in ['-t', '--time']: + print_times = 1 + elif o in ['--verbose']: + os.environ['TESTCMD_VERBOSE'] = a + elif o in ['-v', '--version']: + version = a + elif o in ['-X']: scons_exec = 1 - elif o == '-x' or o == '--exec': + elif o in ['-x', '--exec']: scons = a + elif o in ['--aegis', '--xml']: + format = o + +if not args and not all and not testlistfile: + sys.stderr.write("""\ +runtest.py: No tests were specified. + List one or more tests on the command line, use the + -f option to specify a file containing a list of tests, + or use the -a option to find and run all tests. + +""") + sys.exit(1) + +if sys.platform in ('win32', 'cygwin'): + + def whereis(file): + pathext = [''] + os.environ['PATHEXT'].split(os.pathsep) + for dir in os.environ['PATH'].split(os.pathsep): + f = os.path.join(dir, file) + for ext in pathext: + fext = f + ext + if os.path.isfile(fext): + return fext + return None -def whereis(file): - for dir in string.split(os.environ['PATH'], os.pathsep): - f = os.path.join(dir, file) - if os.path.isfile(f): - try: - st = os.stat(f) - except: - continue - if stat.S_IMODE(st[stat.ST_MODE]) & 0111: - return f - return None +else: + + def whereis(file): + for dir in os.environ['PATH'].split(os.pathsep): + f = os.path.join(dir, file) + if os.path.isfile(f): + try: + st = os.stat(f) + except OSError: + continue + if stat.S_IMODE(st[stat.ST_MODE]) & 0111: + return f + return None + +# See if --qmtest or --noqmtest specified +try: + qmtest +except NameError: + qmtest = None + # Old code for using QMTest by default if it's installed. + # We now default to not using QMTest unless explicitly asked for. + #for q in ['qmtest', 'qmtest.py']: + # path = whereis(q) + # if path: + # # The name was found on $PATH; just execute the found name so + # # we don't have to worry about paths containing white space. + # qmtest = q + # break + #if not qmtest: + # msg = ('Warning: found neither qmtest nor qmtest.py on $PATH;\n' + + # '\tassuming --noqmtest option.\n') + # sys.stderr.write(msg) + # sys.stderr.flush() aegis = whereis('aegis') -spe = None -if aegis: - spe = os.popen("aesub '$spe' 2>/dev/null", "r").read()[:-1] - spe = string.split(spe, os.pathsep) +if format == '--aegis' and aegis: + change = os.popen("aesub '$c' 2>/dev/null", "r").read() + if change: + if sp is None: + paths = os.popen("aesub '$sp' 2>/dev/null", "r").read()[:-1] + sp = paths.split(os.pathsep) + if spe is None: + spe = os.popen("aesub '$spe' 2>/dev/null", "r").read()[:-1] + spe = spe.split(os.pathsep) + else: + aegis = None + +if sp is None: + sp = [] +if spe is None: + spe = [] -class Test: +sp.append(builddir) +sp.append(cwd) + +# +_ws = re.compile('\s') + +def escape(s): + if _ws.search(s): + s = '"' + s + '"' + s = s.replace('\\', '\\\\') + return s + +# Set up lowest-common-denominator spawning of a process on both Windows +# and non-Windows systems that works all the way back to Python 1.5.2. +try: + os.spawnv +except AttributeError: + def spawn_it(command_args): + pid = os.fork() + if pid == 0: + os.execv(command_args[0], command_args) + else: + pid, status = os.waitpid(pid, 0) + return status >> 8 +else: + def spawn_it(command_args): + command = command_args[0] + command_args = list(map(escape, command_args)) + return os.spawnv(os.P_WAIT, command, command_args) + +class Base: def __init__(self, path, spe=None): self.path = path self.abspath = os.path.abspath(path) @@ -159,59 +348,84 @@ class Test: break self.status = None -if args: - if spe: - for a in args: - if os.path.isabs(a): - for g in glob.glob(a): - tests.append(Test(g)) - else: - for dir in spe: - x = os.path.join(dir, a) - globs = glob.glob(x) - if globs: - for g in globs: - tests.append(Test(g)) - break +class SystemExecutor(Base): + def execute(self): + s = spawn_it(self.command_args) + self.status = s + if s < 0 or s > 2: + sys.stdout.write("Unexpected exit status %d\n" % s) + +try: + import subprocess +except ImportError: + import popen2 + try: + popen2.Popen3 + except AttributeError: + class PopenExecutor(Base): + def execute(self): + (tochild, fromchild, childerr) = os.popen3(self.command_str) + tochild.close() + self.stderr = childerr.read() + self.stdout = fromchild.read() + fromchild.close() + self.status = childerr.close() + if not self.status: + self.status = 0 + else: + self.status = self.status >> 8 else: - for a in args: - for g in glob.glob(a): - tests.append(Test(g)) -elif all: - tdict = {} - - def find_Test_py(arg, dirname, names, tdict=tdict): - for n in filter(lambda n: n[-8:] == "Tests.py", names): - t = os.path.join(dirname, n) - if not tdict.has_key(t): - tdict[t] = Test(t) - os.path.walk('src', find_Test_py, 0) - - def find_py(arg, dirname, names, tdict=tdict): - for n in filter(lambda n: n[-3:] == ".py", names): - t = os.path.join(dirname, n) - if not tdict.has_key(t): - tdict[t] = Test(t) - os.path.walk('test', find_py, 0) - - if aegis: - cmd = "aegis -list -unf pf 2>/dev/null" - for line in os.popen(cmd, "r").readlines(): - a = string.split(line) - if a[0] == "test" and not tdict.has_key(a[-1]): - tdict[a[-1]] = Test(a[-1], spe) - cmd = "aegis -list -unf cf 2>/dev/null" - for line in os.popen(cmd, "r").readlines(): - a = string.split(line) - if a[0] == "test": - if a[1] == "remove": - del tdict[a[-1]] - elif not tdict.has_key(a[-1]): - tdict[a[-1]] = Test(a[-1], spe) - - keys = tdict.keys() - keys.sort() - tests = map(tdict.get, keys) + class PopenExecutor(Base): + def execute(self): + p = popen2.Popen3(self.command_str, 1) + p.tochild.close() + self.stdout = p.fromchild.read() + self.stderr = p.childerr.read() + self.status = p.wait() + self.status = self.status >> 8 +else: + class PopenExecutor(Base): + def execute(self): + p = subprocess.Popen(self.command_str, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + shell=True) + self.stdout = p.stdout.read() + self.stderr = p.stderr.read() + self.status = p.wait() + +class Aegis(SystemExecutor): + def header(self, f): + f.write('test_result = [\n') + def write(self, f): + f.write(' { file_name = "%s";\n' % self.path) + f.write(' exit_status = %d; },\n' % self.status) + def footer(self, f): + f.write('];\n') + +class XML(PopenExecutor): + def header(self, f): + f.write(' \n') + def write(self, f): + f.write(' \n') + f.write(' %s\n' % self.path) + f.write(' %s\n' % self.command_str) + f.write(' %s\n' % self.status) + f.write(' %s\n' % self.stdout) + f.write(' %s\n' % self.stderr) + f.write(' \n' % self.test_time) + f.write(' \n') + def footer(self, f): + f.write(' \n' % self.total_time) + f.write(' \n') + +format_class = { + None : SystemExecutor, + '--aegis' : Aegis, + '--xml' : XML, +} + +Test = format_class[format] if package: @@ -232,11 +446,11 @@ if package: 'deb' : os.path.join('python2.1', 'site-packages') } - if not dir.has_key(package): + if package not in dir: sys.stderr.write("Unknown package '%s'\n" % package) sys.exit(2) - test_dir = os.path.join(cwd, 'build', 'test-%s' % package) + test_dir = os.path.join(builddir, 'test-%s' % package) if dir[package] is None: scons_script_dir = test_dir @@ -256,6 +470,8 @@ if package: scons_lib_dir = os.path.join(test_dir, dir[package], 'lib', l) pythonpath_dir = scons_lib_dir + scons_runtest_dir = builddir + else: sd = None ld = None @@ -273,11 +489,49 @@ else: # sd = d # scons = f # spe = map(lambda x: os.path.join(x, 'src', 'engine'), spe) - # ld = string.join(spe, os.pathsep) + # ld = os.pathsep.join(spe) + + if not baseline or baseline == '.': + base = cwd + elif baseline == '-': + # Tentative code for fetching information directly from the + # QMTest context file. + # + #import qm.common + #import qm.test.context + #qm.rc.Load("test") + #context = qm.test.context.Context() + #context.Read('context') + + url = None + svn_info = os.popen("svn info 2>&1", "r").read() + match = re.search('URL: (.*)', svn_info) + if match: + url = match.group(1) + if not url: + sys.stderr.write('runtest.py: could not find a URL:\n') + sys.stderr.write(svn_info) + sys.exit(1) + import tempfile + base = tempfile.mkdtemp(prefix='runtest-tmp-') + + command = 'cd %s && svn co -q %s' % (base, url) + + base = os.path.join(base, os.path.split(url)[1]) + if printcommand: + print command + if execute_tests: + os.system(command) + else: + base = baseline + + scons_runtest_dir = base + + scons_script_dir = sd or os.path.join(base, 'src', 'script') - scons_script_dir = sd or os.path.join(cwd, 'src', 'script') + scons_lib_dir = ld or os.path.join(base, 'src', 'engine') - scons_lib_dir = ld or os.path.join(cwd, 'src', 'engine') + pythonpath_dir = scons_lib_dir if scons: # Let the version of SCons that the -x option pointed to find @@ -292,13 +546,179 @@ elif scons_lib_dir: if scons_exec: os.environ['SCONS_EXEC'] = '1' -os.environ['PYTHONPATH'] = pythonpath_dir + \ - os.pathsep + \ - os.path.join(cwd, 'build', 'etc') + \ - os.pathsep + \ - os.path.join(cwd, 'etc') +os.environ['SCONS_RUNTEST_DIR'] = scons_runtest_dir +os.environ['SCONS_SCRIPT_DIR'] = scons_script_dir +os.environ['SCONS_CWD'] = cwd + +os.environ['SCONS_VERSION'] = version + +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 +# should be able to go away. +pythonpaths = [ pythonpath_dir ] + +for dir in sp: + if format == '--aegis': + q = os.path.join(dir, 'build', 'QMTest') + else: + q = os.path.join(dir, 'QMTest') + pythonpaths.append(q) + +os.environ['SCONS_SOURCE_PATH_EXECUTABLE'] = os.pathsep.join(spe) + +os.environ['PYTHONPATH'] = os.pathsep.join(pythonpaths) + +if old_pythonpath: + os.environ['PYTHONPATH'] = os.environ['PYTHONPATH'] + \ + os.pathsep + \ + old_pythonpath + +tests = [] + +def find_Tests_py(tdict, dirname, names): + for n in [n for n in names if n[-8:] == "Tests.py"]: + tdict[os.path.join(dirname, n)] = 1 + +def find_py(tdict, dirname, names): + tests = [n for n in names if n[-3:] == ".py"] + try: + excludes = open(os.path.join(dirname,".exclude_tests")).readlines() + except (OSError, IOError): + pass + else: + for exclude in excludes: + exclude = exclude.split('#' , 1)[0] + exclude = exclude.strip() + if not exclude: continue + tests = [n for n in tests if n != exclude] + for n in tests: + tdict[os.path.join(dirname, n)] = 1 + +if args: + if spe: + for a in args: + if os.path.isabs(a): + tests.extend(glob.glob(a)) + else: + for dir in spe: + x = os.path.join(dir, a) + globs = glob.glob(x) + if globs: + tests.extend(globs) + break + else: + for a in args: + for path in glob.glob(a): + if os.path.isdir(path): + tdict = {} + if path[:3] == 'src': + os.path.walk(path, find_Tests_py, tdict) + elif path[:4] == 'test': + os.path.walk(path, find_py, tdict) + t = tdict.keys() + t.sort() + tests.extend(t) + else: + tests.append(path) +elif testlistfile: + tests = open(testlistfile, 'r').readlines() + tests = [x for x in tests if x[0] != '#'] + tests = [x[:-1] for x in tests] +elif all and not qmtest: + # 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. + # + # Note that there are some tests under 'src' that *begin* with + # 'test_', but they're packaging and installation tests, not + # functional tests, so we don't execute them by default. (They can + # still be executed by hand, though, and are routinely executed + # by the Aegis packaging build to make sure that we're building + # things correctly.) + tdict = {} + os.path.walk('src', find_Tests_py, tdict) + os.path.walk('test', find_py, tdict) + if format == '--aegis' and aegis: + cmd = "aegis -list -unf pf 2>/dev/null" + for line in os.popen(cmd, "r").readlines(): + a = line.split() + if a[0] == "test" and a[-1] not in tdict: + tdict[a[-1]] = Test(a[-1], spe) + cmd = "aegis -list -unf cf 2>/dev/null" + for line in os.popen(cmd, "r").readlines(): + a = line.split() + if a[0] == "test": + if a[1] == "remove": + del tdict[a[-1]] + elif a[-1] not in tdict: + tdict[a[-1]] = Test(a[-1], spe) -os.chdir(scons_script_dir) + tests = tdict.keys() + tests.sort() + +if qmtest: + if baseline: + aegis_result_stream = 'scons_tdb.AegisBaselineStream' + qmr_file = 'baseline.qmr' + else: + aegis_result_stream = 'scons_tdb.AegisChangeStream' + qmr_file = 'results.qmr' + + if print_times: + aegis_result_stream = aegis_result_stream + "(print_time='1')" + + qmtest_args = [ qmtest, ] + + if format == '--aegis': + dir = builddir + if not os.path.isdir(dir): + dir = cwd + qmtest_args.extend(['-D', dir]) + + qmtest_args.extend([ + 'run', + '--output %s' % qmr_file, + '--format none', + '--result-stream="%s"' % aegis_result_stream, + ]) + + if python: + qmtest_args.append('--context python="%s"' % python) + + if outputfile: + if format == '--xml': + rsclass = 'scons_tdb.SConsXMLResultStream' + else: + rsclass = 'scons_tdb.AegisBatchStream' + qof = "r'" + outputfile + "'" + rs = '--result-stream="%s(filename=%s)"' % (rsclass, qof) + qmtest_args.append(rs) + + if format == '--aegis': + tests = [x.replace(cwd+os.sep, '') for x in tests] + else: + os.environ['SCONS'] = os.path.join(cwd, 'src', 'script', 'scons.py') + + cmd = ' '.join(qmtest_args + tests) + if printcommand: + sys.stdout.write(cmd + '\n') + sys.stdout.flush() + status = 0 + if execute_tests: + status = os.WEXITSTATUS(os.system(cmd)) + sys.exit(status) + +#try: +# os.chdir(scons_script_dir) +#except OSError: +# pass + +tests = list(map(Test, tests)) class Unbuffered: def __init__(self, file): @@ -310,50 +730,105 @@ class Unbuffered: return getattr(self.file, attr) sys.stdout = Unbuffered(sys.stdout) +sys.stderr = Unbuffered(sys.stderr) +if list_only: + for t in tests: + sys.stdout.write(t.path + "\n") + sys.exit(0) + +# +if not python: + if os.name == 'java': + python = os.path.join(sys.prefix, 'jython') + else: + python = sys.executable + +# time.clock() is the suggested interface for doing benchmarking timings, +# but time.time() does a better job on Linux systems, so let that be +# the non-Windows default. + +if sys.platform == 'win32': + time_func = time.clock +else: + time_func = time.time + +if print_times: + print_time_func = lambda fmt, time: sys.stdout.write(fmt % time) +else: + print_time_func = lambda fmt, time: None + +total_start_time = time_func() for t in tests: - cmd = string.join([sys.executable, debug, t.abspath], " ") - if printcmd: - sys.stdout.write(cmd + "\n") - s = os.system(cmd) - if s >= 256: - s = s / 256 - t.status = s - if s < 0 or s > 2: - sys.stdout.write("Unexpected exit status %d\n" % s) - -fail = filter(lambda t: t.status == 1, tests) -no_result = filter(lambda t: t.status == 2, tests) - -if len(tests) != 1: + command_args = ['-tt'] + if debug: + command_args.append(debug) + command_args.append(t.path) + t.command_args = [python] + command_args + t.command_str = " ".join([escape(python)] + command_args) + if printcommand: + sys.stdout.write(t.command_str + "\n") + test_start_time = time_func() + if execute_tests: + t.execute() + t.test_time = time_func() - test_start_time + print_time_func("Test execution time: %.1f seconds\n", t.test_time) +if len(tests) > 0: + tests[0].total_time = time_func() - total_start_time + print_time_func("Total execution time for all tests: %.1f seconds\n", tests[0].total_time) + +passed = [t for t in tests if t.status == 0] +fail = [t for t in tests if t.status == 1] +no_result = [t for t in tests if t.status == 2] + +if len(tests) != 1 and execute_tests: + if passed and print_passed_summary: + if len(passed) == 1: + sys.stdout.write("\nPassed the following test:\n") + else: + sys.stdout.write("\nPassed the following %d tests:\n" % len(passed)) + paths = [x.path for x in passed] + sys.stdout.write("\t" + "\n\t".join(paths) + "\n") if fail: if len(fail) == 1: sys.stdout.write("\nFailed the following test:\n") else: sys.stdout.write("\nFailed the following %d tests:\n" % len(fail)) - paths = map(lambda x: x.path, fail) - sys.stdout.write("\t" + string.join(paths, "\n\t") + "\n") + paths = [x.path for x in fail] + sys.stdout.write("\t" + "\n\t".join(paths) + "\n") if no_result: if len(no_result) == 1: sys.stdout.write("\nNO RESULT from the following test:\n") else: sys.stdout.write("\nNO RESULT from the following %d tests:\n" % len(no_result)) - paths = map(lambda x: x.path, no_result) - sys.stdout.write("\t" + string.join(paths, "\n\t") + "\n") + paths = [x.path for x in no_result] + sys.stdout.write("\t" + "\n\t".join(paths) + "\n") -if output: - f = open(output, 'w') - f.write("test_result = [\n") +if outputfile: + if outputfile == '-': + f = sys.stdout + else: + f = open(outputfile, 'w') + tests[0].header(f) + #f.write("test_result = [\n") for t in tests: - f.write(' { file_name = "%s";\n' % t.path) - f.write(' exit_status = %d; },\n' % t.status) - f.write("];\n") - f.close() + t.write(f) + tests[0].footer(f) + #f.write("];\n") + if outputfile != '-': + f.close() + +if format == '--aegis': sys.exit(0) +elif len(fail): + sys.exit(1) +elif len(no_result): + sys.exit(2) else: - if len(fail): - sys.exit(1) - elif len(no_result): - sys.exit(2) - else: - sys.exit(0) + sys.exit(0) + +# Local Variables: +# tab-width:4 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=4 shiftwidth=4: