#!/usr/bin/env python3 """Summarize a CTest Test.xml as markdown. Intended for $GITHUB_STEP_SUMMARY in CI, where only the first few failures are shown inline (pass --link to point at the full Test.xml). Also reusable locally to print every failure from a downloaded Test.xml with --all. """ import argparse import base64 import gzip import xml.etree.ElementTree as ET # Failure output is truncated to this many trailing characters, which is # usually enough to include e.g. an ASan report's summary. OUTPUT_TAIL_CHARS = 3000 def test_output(test): value = test.find("./Results/Measurement/Value") if value is None or value.text is None: return "" text = value.text if value.get("encoding") == "base64": raw = base64.b64decode(text) if value.get("compression") == "gzip": raw = gzip.decompress(raw) text = raw.decode(errors="replace") return text def main(): parser = argparse.ArgumentParser(description=__doc__) parser.add_argument("test_xml", help="path to a ctest Testing/*/Test.xml") parser.add_argument( "--inline", type=int, default=5, help="how many failures to show inline (default 5)", ) parser.add_argument("--all", action="store_true", help="show every failure inline") parser.add_argument( "--link", help="URL of the full Test.xml, linked when failures are elided" ) args = parser.parse_args() testing = ET.parse(args.test_xml).getroot().find("Testing") tests = testing.findall("Test") failed = [t for t in tests if t.get("Status") == "failed"] notrun = sum(1 for t in tests if t.get("Status") == "notrun") if not failed: print(f"✅ All {len(tests) - notrun} tests passed") else: print(f"❌ {len(failed)} of {len(tests)} tests failed\n") shown = failed if args.all else failed[: args.inline] for test in shown: name = test.findtext("Name") output = test_output(test)[-OUTPUT_TAIL_CHARS:].strip() print(f"
{name}\n") print("````") print(output) print("````") print("
\n") remaining = len(failed) - len(shown) if remaining > 0: more = f"… and {remaining} more" if args.link: more += f" — full list in [Test.xml]({args.link})" print(more) if notrun: print(f"\n⚠️ {notrun} tests not run") if __name__ == "__main__": main()