blob: fa1c02606e45d6014f794d2f69c9a100196b5508 [file] [log] [blame]
Anders Roxell65be7682022-12-08 12:02:43 +01001#!/usr/bin/env python3
2import sys
3import re
Ryan Roberts6e2cfcd2024-02-10 11:45:59 +00004from tap import parser
Anders Roxell65be7682022-12-08 12:02:43 +01005
6
7def slugify(line):
8 non_ascii_pattern = r"[^A-Za-z0-9_-]+"
9 line = re.sub(r"\[\d{1,5}\]", "", line)
10 return re.sub(
11 r"_-", "_", re.sub(r"(^_|_$)", "", re.sub(non_ascii_pattern, "_", line))
12 )
13
14
Ryan Roberts6e2cfcd2024-02-10 11:45:59 +000015def parse_nested_tap(string):
16 results = []
17
18 def uncomment(line):
19 # All of the input lines should be comments and begin with #, but let's
20 # be cautious; don't do anything if the line doesn't begin with #.
21 if len(line) > 0 and line[0] == "#":
22 return line[1:].strip()
23 return line
24
25 def make_name(name, directive, ok, skip):
26 # Some of this is to maintain compatibility with the old parser.
27 if name.startswith("selftests:"):
28 name = name[10:]
29 if ok and skip and directive.lower().startswith("skip"):
30 directive = directive[4:]
Anders Roxell65be7682022-12-08 12:02:43 +010031 else:
Ryan Roberts6e2cfcd2024-02-10 11:45:59 +000032 directive = ""
33 name = f"{name} {directive}".strip()
34 if name == "":
35 name = "<unknown>"
36 return slugify(name)
37
38 def make_result(ok, skip):
39 return ("skip" if skip else "pass") if ok else "fail"
40
41 output = ""
42 ps = parser.Parser()
Theodore Grey9d6d8c72025-03-24 18:16:57 -040043 test_name = None
Ryan Roberts6e2cfcd2024-02-10 11:45:59 +000044 for l in ps.parse_text(string):
45 if l.category == "test":
Theodore Grey9d6d8c72025-03-24 18:16:57 -040046 test_name = make_name(l.description, l.directive.text, l.ok, l.skip)
Ryan Roberts6e2cfcd2024-02-10 11:45:59 +000047 results.append(
48 {
49 "name": make_name(l.description, l.directive.text, l.ok, l.skip),
50 "result": make_result(l.ok, l.skip),
51 "children": parse_nested_tap(output),
Theodore Grey9d6d8c72025-03-24 18:16:57 -040052 "logs": f"{l.directive.text}",
Ryan Roberts6e2cfcd2024-02-10 11:45:59 +000053 }
54 )
55 output = ""
56 elif l.category == "diagnostic":
57 output += f"{uncomment(l.text)}\n"
Theodore Grey9d6d8c72025-03-24 18:16:57 -040058 for r in results:
59 if r["name"] == test_name and not None:
60 r["logs"] += f"{uncomment(l.text)}\n"
Ryan Roberts6e2cfcd2024-02-10 11:45:59 +000061
62 return results
63
64
65def flatten_results(prefix, results):
66 ret = []
67 for r in results:
68 test = f"{prefix}{r['name']}"
69 children = flatten_results(f"{test}_", r["children"])
Theodore Grey9d6d8c72025-03-24 18:16:57 -040070 output = r["logs"]
71 ret += children + [{"name": test, "result": r["result"], "logs": output}]
Ryan Roberts6e2cfcd2024-02-10 11:45:59 +000072 return ret
73
74
75def make_names_unique(results):
76 namecounts = {}
77 for r in results:
78 name = r["name"]
79 namecounts[name] = namecounts.get(name, 0) + 1
80 if namecounts[name] > 1:
81 r["name"] += f"_dup{namecounts[name]}"
82
83
Theodore Grey9d6d8c72025-03-24 18:16:57 -040084def make_log_files(results):
85 for r in results:
86 name = r["name"]
87 if r["result"] == "fail":
88 try:
TheodoreGrey9c158162025-04-08 10:30:10 -040089 log_file = open(f"output/{name}.log", "w")
Theodore Grey9d6d8c72025-03-24 18:16:57 -040090 log_file.writelines(r["logs"])
91 log_file.close()
92 except OSError as e:
93 print(f"Error writing to file output/{name}.log: {e}")
94
95
Ryan Roberts6e2cfcd2024-02-10 11:45:59 +000096if __name__ == "__main__":
97 results = parse_nested_tap(sys.stdin.read())
98 results = flatten_results("", results)
99 make_names_unique(results)
Theodore Grey9d6d8c72025-03-24 18:16:57 -0400100 make_log_files(results)
Ryan Roberts6e2cfcd2024-02-10 11:45:59 +0000101 for r in results:
102 print(f"{r['name']} {r['result']}")