From cc4f5372af80577cf7026438ebefc3ae8e5e030f Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Sun, 14 Dec 2014 19:25:12 +0000 Subject: [PATCH] Add basic tap2subunit converter, rather than relying on the one from subunit-tools. Change-Id: I39ec5ec68c7c3c9d329d8f1a8ce01445b85c7ab8 Signed-Off-By: Jelmer Vernooij Reviewed-by: Andrew Bartlett --- selftest/selftesthelpers.py | 28 ++------ selftest/tap2subunit | 128 ++++++++++++++++++++++++++++++++++++ 2 files changed, 133 insertions(+), 23 deletions(-) create mode 100755 selftest/tap2subunit diff --git a/selftest/selftesthelpers.py b/selftest/selftesthelpers.py index 3c1e6badef3..aa1d2b31b5a 100644 --- a/selftest/selftesthelpers.py +++ b/selftest/selftesthelpers.py @@ -60,25 +60,7 @@ else: python = os.getenv("PYTHON", "python") -# Set a default value, overridden if we find a working one on the system -tap2subunit = "PYTHONPATH=%s/lib/subunit/python:%s/lib/testtools:%s/lib/extras:%s/lib/mimeparse %s %s/lib/subunit/filters/tap2subunit" % (srcdir(), srcdir(), srcdir(), srcdir(), python, srcdir()) -subunit2to1 = "PYTHONPATH=%s/lib/subunit/python:%s/lib/testtools:%s/lib/extras:%s/lib/mimeparse %s %s/lib/subunit/filters/subunit-2to1" % (srcdir(), srcdir(), srcdir(), srcdir(), python, srcdir()) - -sub = subprocess.Popen("tap2subunit", stdin=subprocess.PIPE, - stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) -sub.communicate("") - -if sub.returncode == 0: - cmd = "echo -ne \"1..1\nok 1 # skip doesn't seem to work yet\n\" | tap2subunit | grep skip" - sub = subprocess.Popen(cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE, - stderr=subprocess.PIPE, shell=True) - if sub.returncode == 0: - tap2subunit = "tap2subunit" - -def to_subunit1(subunit_version): - if subunit_version == 1: - return "" - return " | " + subunit2to1 +tap2subunit = python + " " + os.path.join(srcdir(), "selftest", "tap2subunit") def valgrindify(cmdline): @@ -89,7 +71,7 @@ def valgrindify(cmdline): return valgrind + " " + cmdline -def plantestsuite(name, env, cmdline, subunit_version=1): +def plantestsuite(name, env, cmdline): """Plan a test suite. :param name: Testsuite name @@ -103,7 +85,7 @@ def plantestsuite(name, env, cmdline, subunit_version=1): cmdline = " ".join(cmdline) if "$LISTOPT" in cmdline: raise AssertionError("test %s supports --list, but not --load-list" % name) - print cmdline + " 2>&1 " + to_subunit1(subunit_version) + " | " + add_prefix(name, env) + print cmdline + " 2>&1 " + " | " + add_prefix(name, env) def add_prefix(prefix, env, support_list=False): @@ -114,7 +96,7 @@ def add_prefix(prefix, env, support_list=False): return "%s/selftest/filter-subunit %s--fail-on-empty --prefix=\"%s.\" --suffix=\"(%s)\"" % (srcdir(), listopt, prefix, env) -def plantestsuite_loadlist(name, env, cmdline, subunit_version=1): +def plantestsuite_loadlist(name, env, cmdline): print "-- TEST-LOADLIST --" if env == "none": fullname = name @@ -130,7 +112,7 @@ def plantestsuite_loadlist(name, env, cmdline, subunit_version=1): if not "$LOADLIST" in cmdline: raise AssertionError("loadlist test %s does not support --load-list" % name) print ("%s | %s" % (cmdline.replace("$LOADLIST", ""), add_prefix(name, env, support_list))).replace("$LISTOPT", "--list") - print cmdline.replace("$LISTOPT", "") + " 2>&1 " + to_subunit1(subunit_version) + " | " + add_prefix(name, env, False) + print cmdline.replace("$LISTOPT", "") + " 2>&1 " + " | " + add_prefix(name, env, False) def skiptestsuite(name, reason): diff --git a/selftest/tap2subunit b/selftest/tap2subunit new file mode 100755 index 00000000000..e569e7f8d14 --- /dev/null +++ b/selftest/tap2subunit @@ -0,0 +1,128 @@ +#!/usr/bin/python +# +# tap2subunit: convert a tap stream to a subunit stream. +# Extract from the subunit source: +# Copyright (C) 2005 Robert Collins +# +# Licensed under either the Apache License, Version 2.0 or the BSD 3-clause +# license at the users choice. A copy of both licenses are available in the +# project source as Apache-2.0 and BSD. You may not use this file except in +# compliance with one of these two licences. +# +# Unless required by applicable law or agreed to in writing, software +# distributed under these licenses is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# license you chose for the specific language governing permissions and +# limitations under that license. +# + + +import re +import sys + +def TAP2SubUnit(tap, subunit): + """Filter a TAP pipe into a subunit pipe. + + :param tap: A tap pipe/stream/file object. + :param subunit: A pipe/stream/file object to write subunit results to. + :return: The exit code to exit with. + """ + BEFORE_PLAN = 0 + AFTER_PLAN = 1 + SKIP_STREAM = 2 + state = BEFORE_PLAN + plan_start = 1 + plan_stop = 0 + def _skipped_test(subunit, plan_start): + # Some tests were skipped. + subunit.write('test: test %d\n' % plan_start) + subunit.write('error: test %d [\n' % plan_start) + subunit.write('test missing from TAP output\n') + subunit.write(']\n') + return plan_start + 1 + # Test data for the next test to emit + test_name = None + log = [] + result = None + def _emit_test(): + "write out a test" + if test_name is None: + return + subunit.write("test: %s\n" % test_name) + if not log: + subunit.write("%s: %s\n" % (result, test_name)) + else: + subunit.write("%s: %s [\n" % (result, test_name)) + if log: + for line in log: + subunit.write("%s\n" % line) + subunit.write("]\n") + del log[:] + for line in tap: + if state == BEFORE_PLAN: + match = re.match("(\d+)\.\.(\d+)\s*(?:\#\s+(.*))?\n", line) + if match: + state = AFTER_PLAN + _, plan_stop, comment = match.groups() + plan_stop = int(plan_stop) + if plan_start > plan_stop and plan_stop == 0: + # skipped file + state = SKIP_STREAM + subunit.write("test: file skip\n") + subunit.write("skip: file skip [\n") + subunit.write("%s\n" % comment) + subunit.write("]\n") + continue + # not a plan line, or have seen one before + match = re.match("(ok|not ok)(?:\s+(\d+)?)?(?:\s+([^#]*[^#\s]+)\s*)?(?:\s+#\s+(TODO|SKIP|skip|todo)(?:\s+(.*))?)?\n", line) + if match: + # new test, emit current one. + _emit_test() + status, number, description, directive, directive_comment = match.groups() + if status == 'ok': + result = 'success' + else: + result = "failure" + if description is None: + description = '' + else: + description = ' ' + description + if directive is not None: + if directive.upper() == 'TODO': + result = 'xfail' + elif directive.upper() == 'SKIP': + result = 'skip' + if directive_comment is not None: + log.append(directive_comment) + if number is not None: + number = int(number) + while plan_start < number: + plan_start = _skipped_test(subunit, plan_start) + test_name = "test %d%s" % (plan_start, description) + plan_start += 1 + continue + match = re.match("Bail out\!(?:\s*(.*))?\n", line) + if match: + reason, = match.groups() + if reason is None: + extra = '' + else: + extra = ' %s' % reason + _emit_test() + test_name = "Bail out!%s" % extra + result = "error" + state = SKIP_STREAM + continue + match = re.match("\#.*\n", line) + if match: + log.append(line[:-1]) + continue + subunit.write(line) + _emit_test() + while plan_start <= plan_stop: + # record missed tests + plan_start = _skipped_test(subunit, plan_start) + return 0 + + +sys.exit(TAP2SubUnit(sys.stdin, sys.stdout))