diff -r 9f939fae8ff3 -r c7a471b49819 tests/run-tests.py --- a/tests/run-tests.py Mon Jul 26 12:32:45 2010 +0200 +++ b/tests/run-tests.py Sat Aug 14 09:47:41 2010 +0100 @@ -52,6 +52,7 @@ import sys import tempfile import time +import re closefds = os.name == 'posix' def Popen4(cmd, bufsize=-1): @@ -441,6 +442,94 @@ def alarmed(signum, frame): raise Timeout +def pytest(test, options): + py3kswitch = options.py3k_warnings and ' -3' or '' + cmd = '%s%s "%s"' % (PYTHON, py3kswitch, test) + vlog("# Running", cmd) + return run(cmd, options) + +def shtest(test, options): + cmd = '"%s"' % test + vlog("# Running", cmd) + return run(cmd, options) + +def battest(test, options): + # To reliably get the error code from batch files on WinXP, + # the "cmd /c call" prefix is needed. Grrr + cmd = 'cmd /c call "%s"' % testpath + vlog("# Running", cmd) + return run(cmd, options) + +def tsttest(test, options): + t = open(test) + out = [] + script = [] + salt = "SALT" + str(time.time()) + + pos = prepos = -1 + after = {} + expected = {} + for n, l in enumerate(t): + if l.startswith(' $ '): # commands + after.setdefault(pos, []).append(l) + prepos = pos + pos = n + script.append('echo %s %s\n' % (salt, n)) + script.append(l[4:]) + elif l.startswith(' > '): # continuations + after.setdefault(prepos, []).append(l) + script.append(l[4:]) + elif l.startswith(' '): # results + # queue up a list of expected results + expected.setdefault(pos, []).append(l[2:]) + else: + # non-command/result - queue up for merged output + after.setdefault(pos, []).append(l) + + fd, name = tempfile.mkstemp(suffix='hg-tst') + + try: + for l in script: + os.write(fd, l) + os.close(fd) + + cmd = '/bin/sh "%s"' % name + vlog("# Running", cmd) + exitcode, output = run(cmd, options) + finally: + os.remove(name) + + def rematch(el, l): + try: + return re.match(el, l) + except re.error: + # el is an invalid regex + return False + + pos = -1 + postout = [] + for n, l in enumerate(output): + if l.startswith(salt): + if pos in after: + postout += after.pop(pos) + pos = int(l.split()[1]) + else: + el = None + if pos in expected and expected[pos]: + el = expected[pos].pop(0) + + if el == l: # perfect match (fast) + postout.append(" " + l) + elif el and rematch(el, l): # fallback regex match + postout.append(" " + el) + else: # mismatch - let diff deal with it + postout.append(" " + l) + + if pos in after: + postout += after.pop(pos) + + return exitcode, postout + def run(cmd, options): """Run command in a sub-process, capturing the output (stdout and stderr). Return a tuple (exitcode, output). output is None in debug mode.""" @@ -537,15 +626,15 @@ lctest = test.lower() if lctest.endswith('.py') or firstline == '#!/usr/bin/env python': - py3kswitch = options.py3k_warnings and ' -3' or '' - cmd = '%s%s "%s"' % (PYTHON, py3kswitch, testpath) + runner = pytest elif lctest.endswith('.bat'): # do not run batch scripts on non-windows if os.name != 'nt': return skip("batch script") - # To reliably get the error code from batch files on WinXP, - # the "cmd /c call" prefix is needed. Grrr - cmd = 'cmd /c call "%s"' % testpath + runner = battest + elif lctest.endswith('.t'): + runner = tsttest + ref = testpath else: # do not run shell scripts on windows if os.name == 'nt': @@ -555,7 +644,7 @@ return fail("does not exist") elif not os.access(testpath, os.X_OK): return skip("not executable") - cmd = '"%s"' % testpath + runner = shtest # Make a tmp subdirectory to work in tmpd = os.path.join(HGTMP, test) @@ -565,8 +654,7 @@ if options.timeout > 0: signal.alarm(options.timeout) - vlog("# Running", cmd) - ret, out = run(cmd, options) + ret, out = runner(testpath, options) vlog("# Ret was:", ret) if options.timeout > 0: @@ -807,7 +895,10 @@ print "Accept this change? [n] ", answer = sys.stdin.readline().strip() if answer.lower() in "y yes".split(): - rename(test + ".err", test + ".out") + if test.endswith(".t"): + rename(test + ".err", test) + else: + rename(test + ".err", test + ".out") tested += 1 fails.pop() continue @@ -944,7 +1035,7 @@ for test in args: if (test.startswith("test-") and '~' not in test and ('.' not in test or test.endswith('.py') or - test.endswith('.bat'))): + test.endswith('.bat') or test.endswith('.t'))): tests.append(test) if not tests: print "# Ran 0 tests, 0 skipped, 0 failed."