Add basic tap2subunit converter, rather than relying on the one from subunit-tools.
authorJelmer Vernooij <jelmer@samba.org>
Sun, 14 Dec 2014 19:25:12 +0000 (19:25 +0000)
committerAndrew Bartlett <abartlet@samba.org>
Fri, 6 Mar 2015 03:41:47 +0000 (04:41 +0100)
Change-Id: I39ec5ec68c7c3c9d329d8f1a8ce01445b85c7ab8
Signed-Off-By: Jelmer Vernooij <jelmer@samba.org>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
selftest/selftesthelpers.py
selftest/tap2subunit [new file with mode: 0755]

index 3c1e6badef32bce765dd1b5c83d1bc9c6c98f49c..aa1d2b31b5a1ab67355e31a46e3c629cd162f885 100644 (file)
@@ -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 (executable)
index 0000000..e569e7f
--- /dev/null
@@ -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 <robertc@robertcollins.net>
+#
+#  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))