diff --git a/automated/linux/kselftest/kselftest.sh b/automated/linux/kselftest/kselftest.sh index 0bccce5c2..54408b852 100755 --- a/automated/linux/kselftest/kselftest.sh +++ b/automated/linux/kselftest/kselftest.sh @@ -135,7 +135,7 @@ install() { dist_name # shellcheck disable=SC2154 case "${dist}" in - debian|ubuntu) install_deps "sed perl wget xz-utils iproute2" "${SKIP_INSTALL}" ;; + debian|ubuntu) install_deps "sed perl wget xz-utils iproute2 python3-tap" "${SKIP_INSTALL}" ;; centos|fedora) install_deps "sed perl wget xz iproute" "${SKIP_INSTALL}" ;; unknown) warn_msg "Unsupported distro: package install skipped" ;; esac diff --git a/automated/linux/kselftest/parse-output.py b/automated/linux/kselftest/parse-output.py index 9708fdeac..976a1d5cd 100755 --- a/automated/linux/kselftest/parse-output.py +++ b/automated/linux/kselftest/parse-output.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 import sys import re +from tap import parser def slugify(line): @@ -11,25 +12,71 @@ def slugify(line): ) -tests = "" -for line in sys.stdin: - if "# selftests: " in line: - tests = slugify(line.replace("\n", "").split("selftests:")[1]) - elif re.search(r"^.*?not ok \d{1,5} ", line): - match = re.match(r"^.*?not ok [0-9]+ (.*?)$", line) - ascii_test_line = slugify(re.sub("# .*$", "", match.group(1))) - output = f"{tests}_{ascii_test_line} fail" - if f"selftests_{tests}" in output: - output = re.sub(r"^.*_selftests_", "", output) - print(f"{output}") - elif re.search(r"^.*?ok \d{1,5} ", line): - match = re.match(r"^.*?ok [0-9]+ (.*?)$", line) - if "# skip" in match.group(1).lower(): - ascii_test_line = slugify(re.sub("# skip", "", match.group(1).lower())) - output = f"{tests}_{ascii_test_line} skip" +def parse_nested_tap(string): + results = [] + + def uncomment(line): + # All of the input lines should be comments and begin with #, but let's + # be cautious; don't do anything if the line doesn't begin with #. + if len(line) > 0 and line[0] == "#": + return line[1:].strip() + return line + + def make_name(name, directive, ok, skip): + # Some of this is to maintain compatibility with the old parser. + if name.startswith("selftests:"): + name = name[10:] + if ok and skip and directive.lower().startswith("skip"): + directive = directive[4:] else: - ascii_test_line = slugify(match.group(1)) - output = f"{tests}_{ascii_test_line} pass" - if f"selftests_{tests}" in output: - output = re.sub(r"^.*_selftests_", "", output) - print(f"{output}") + directive = "" + name = f"{name} {directive}".strip() + if name == "": + name = "" + return slugify(name) + + def make_result(ok, skip): + return ("skip" if skip else "pass") if ok else "fail" + + output = "" + ps = parser.Parser() + for l in ps.parse_text(string): + if l.category == "test": + results.append( + { + "name": make_name(l.description, l.directive.text, l.ok, l.skip), + "result": make_result(l.ok, l.skip), + "children": parse_nested_tap(output), + } + ) + output = "" + elif l.category == "diagnostic": + output += f"{uncomment(l.text)}\n" + + return results + + +def flatten_results(prefix, results): + ret = [] + for r in results: + test = f"{prefix}{r['name']}" + children = flatten_results(f"{test}_", r["children"]) + ret += children + [{"name": test, "result": r["result"]}] + return ret + + +def make_names_unique(results): + namecounts = {} + for r in results: + name = r["name"] + namecounts[name] = namecounts.get(name, 0) + 1 + if namecounts[name] > 1: + r["name"] += f"_dup{namecounts[name]}" + + +if __name__ == "__main__": + results = parse_nested_tap(sys.stdin.read()) + results = flatten_results("", results) + make_names_unique(results) + for r in results: + print(f"{r['name']} {r['result']}")