Files
tbamud/tests/unity_to_junit.py
Copilot ac94839eb5 Add Unity-based unit test infrastructure (Phase 1 — 117 tests) (#177)
Introduced new system for unit tests based on the Unity framework.

Added tests for some of the simple functions in four different files.
2026-04-23 01:17:48 +02:00

81 lines
2.6 KiB
Python

#!/usr/bin/env python3
"""Convert Unity test-runner output to JUnit XML.
Usage:
./test_binary | python3 unity_to_junit.py <suite_name> <output.xml> [elapsed_seconds]
Unity emits one result line per test:
path/to/file.c:LINE:TEST_NAME:PASS
path/to/file.c:LINE:TEST_NAME:FAIL:message
path/to/file.c:LINE:TEST_NAME:IGNORE:message
followed by a summary line:
N Tests N Failures N Ignored
"""
import re
import sys
import xml.etree.ElementTree as ET
def parse_unity(lines):
tests = []
total = failures = ignored = 0
for line in lines:
line = line.rstrip("\n")
m = re.match(
r"^.+:\d+:([^:]+):(PASS|FAIL|IGNORE)(?::(.*))?$", line
)
if m:
name, result, message = m.group(1), m.group(2), m.group(3) or ""
tests.append((name, result, message))
continue
m2 = re.match(r"^(\d+) Tests (\d+) Failures (\d+) Ignored", line)
if m2:
total, failures, ignored = int(m2.group(1)), int(m2.group(2)), int(m2.group(3))
if not total:
total = len(tests)
failures = sum(1 for _, r, _ in tests if r == "FAIL")
ignored = sum(1 for _, r, _ in tests if r == "IGNORE")
return tests, total, failures, ignored
def build_xml(suite_name, tests, total, failures, ignored, elapsed):
# Distribute total time evenly across tests for per-testcase timing.
per_test = round(elapsed / total, 6) if total else 0.0
suite = ET.Element(
"testsuite",
name=suite_name,
tests=str(total),
failures=str(failures),
errors="0",
skipped=str(ignored),
time=f"{elapsed:.6f}",
)
for name, result, message in tests:
case = ET.SubElement(
suite, "testcase",
name=name, classname=suite_name, time=f"{per_test:.6f}",
)
if result == "FAIL":
f = ET.SubElement(case, "failure", message=message)
f.text = message
elif result == "IGNORE":
ET.SubElement(case, "skipped", message=message)
return ET.ElementTree(suite)
def main():
if len(sys.argv) < 3 or len(sys.argv) > 4:
print(f"usage: {sys.argv[0]} <suite_name> <output.xml> [elapsed_seconds]", file=sys.stderr)
sys.exit(1)
suite_name, output_file = sys.argv[1], sys.argv[2]
elapsed = float(sys.argv[3]) if len(sys.argv) == 4 else 0.0
tests, total, failures, ignored = parse_unity(sys.stdin.readlines())
tree = build_xml(suite_name, tests, total, failures, ignored, elapsed)
ET.indent(tree, space=" ")
tree.write(output_file, encoding="unicode", xml_declaration=True)
if __name__ == "__main__":
main()