diff options
Diffstat (limited to 'tests/test_cmdline_tool.py')
-rwxr-xr-x | tests/test_cmdline_tool.py | 163 |
1 files changed, 163 insertions, 0 deletions
diff --git a/tests/test_cmdline_tool.py b/tests/test_cmdline_tool.py new file mode 100755 index 0000000..b8a0d07 --- /dev/null +++ b/tests/test_cmdline_tool.py @@ -0,0 +1,163 @@ +#!/usr/bin/env python + +# +# Regression test driver for cmd-line tools +# +# Usage: test_cmdline_tool.py [<options>] <tool> <arguments> +# +# If the -g option is given or the TEST_GENERATE environment variable is set to 1, +# *-expected.<suffix> files will be generated instead of running the tests. +# +# Any generated output is written to the file `basename <argument`-actual.<suffix> +# Any warning or errors are written to stderr. +# +# Returns 0 on passed test +# 1 on error +# 2 on invalid cmd-line options +# +# Author: Marius Kintel <marius@kintel.net> +# + +import sys +import os +import glob +import subprocess +import re +import getopt + +def initialize_environment(): + if not options.generate: options.generate = bool(os.getenv("TEST_GENERATE")) + return True + +def init_expected_filename(testname, cmd): + global expecteddir, expectedfilename + expecteddir = os.path.join(options.regressiondir, os.path.split(cmd)[1]) + expectedfilename = os.path.join(expecteddir, testname + "-expected." + options.suffix) + +def verify_test(testname, cmd): + global expectedfilename + if not options.generate: + if not os.path.isfile(expectedfilename): + print >> sys.stderr, "Error: test '%s' is missing expected output in %s" % (testname, expectedfilename) + return False + return True + +def execute_and_redirect(cmd, params, outfile): + proc = subprocess.Popen([cmd] + params, stdout=outfile) + retval = proc.wait() + return retval + +def get_normalized_text(filename): + text = open(filename).read() + return text.strip("\r\n").replace("\r\n", "\n") + "\n" + +def compare_text(expected, actual): + return get_normalized_text(expected) == get_normalized_text(actual) + +def compare_default(resultfilename): + if not compare_text(expectedfilename, resultfilename): + execute_and_redirect("diff", [expectedfilename, resultfilename], sys.stderr) + return False + return True + +def compare_png(resultfilename): + if execute_and_redirect("diff", [expectedfilename, resultfilename], sys.stderr) != 0: + return False + return True + +def compare_with_expected(resultfilename): + if not options.generate: + if "compare_" + options.suffix in globals(): return globals()["compare_" + options.suffix](resultfilename) + else: return compare_default(resultfilename) + return True + +def run_test(testname, cmd, args): + cmdname = os.path.split(options.cmd)[1] + + outputdir = os.path.join(os.getcwd(), cmdname + "-output") + actualfilename = os.path.join(outputdir, testname + "-actual." + options.suffix) + + if options.generate: + if not os.path.exists(expecteddir): os.makedirs(expecteddir) + outputname = expectedfilename + else: + if not os.path.exists(outputdir): os.makedirs(outputdir) + outputname = actualfilename + outfile = open(outputname, "wb") + try: + proc = subprocess.Popen([cmd] + args, stdout=outfile, stderr=subprocess.PIPE) + errtext = proc.communicate()[1] + if errtext != None and len(errtext) > 0: + print >> sys.stderr, "Error output: " + errtext + outfile.close() + if proc.returncode != 0: + print >> sys.stderr, "Error: %s failed with return code %d" % (cmdname, proc.returncode) + return None + + return outputname + except OSError, err: + print >> sys.stderr, "Error: %s \"%s\"" % (err.strerror, cmd) + return None + +class Options: + def __init__(self): + self.__dict__['options'] = {} + def __setattr__(self, name, value): + self.options[name] = value + def __getattr__(self, name): + return self.options[name] + +def usage(): + print >> sys.stderr, "Usage: " + sys.argv[0] + " [<options>] <cmdline-tool> <argument>" + print >> sys.stderr, "Options:" + print >> sys.stderr, " -g, --generate Generate expected output for the given tests" + print >> sys.stderr, " -s, --suffix=<suffix> Write -expected and -actual files with the given suffix instead of .txt" + print >> sys.stderr, " -t, --test=<name> Specify test name instead of deducting it from the argument" + +if __name__ == '__main__': + # Handle command-line arguments + try: + opts, args = getopt.getopt(sys.argv[1:], "gs:t:", ["generate", "suffix=", "test="]) + except getopt.GetoptError, err: + usage() + sys.exit(2) + + global options + options = Options() + options.regressiondir = os.path.join(os.path.split(sys.argv[0])[0], "regression") + options.generate = False + options.suffix = "txt" + for o, a in opts: + if o in ("-g", "--generate"): options.generate = True + elif o in ("-s", "--suffix"): + if a[0] == '.': options.suffix = a[1:] + else: options.suffix = a + elif o in ("-t", "--test"): + options.testname = a + + # <cmdline-tool> and <argument> + if len(args) < 2: + usage() + sys.exit(2) + options.cmd = args[0] + + # If only one test file, we can usually deduct the test name from the file + if len(args) == 2: + basename = os.path.splitext(args[1])[0] + path, options.testname = os.path.split(basename) + + if not hasattr(options, "testname"): + print >> sys.stderr, "Test name cannot be deducted from arguments. Specify test name using the -t option" + sys.exit(2) + + # Initialize and verify run-time environment + if not initialize_environment(): sys.exit(1) + + init_expected_filename(options.testname, options.cmd) + + # Verify test environment + verification = verify_test(options.testname, options.cmd) + + resultfile = run_test(options.testname, options.cmd, args[1:]) + + if not verification or not compare_with_expected(resultfile): exit(1) |