def junit_report(
report: EvalReport, resolutions: tuple[PackResolution, ...] = ()
) -> str:
"""Serialize scenarios as JUnit test cases without prompt or response payloads."""
root = Element(
"testsuite",
name="symfonic-evals",
tests=str(len(report.scenarios) + sum(not row.applicable for row in resolutions)),
failures=str(sum(row.status is EvalStatus.FAILED for row in report.scenarios)),
errors=str(sum(row.status is EvalStatus.ERROR for row in report.scenarios)),
skipped=str(
sum(row.status is EvalStatus.UNAVAILABLE for row in report.scenarios)
+ sum(not row.applicable for row in resolutions)
),
)
for scenario in report.scenarios:
case = SubElement(root, "testcase", name=scenario.name, classname="symfonic.evals")
if scenario.status is EvalStatus.FAILED:
SubElement(case, "failure", message="behaviour threshold was not met")
elif scenario.status is EvalStatus.ERROR:
SubElement(case, "error", message="evaluation execution failed")
elif scenario.status is EvalStatus.UNAVAILABLE:
SubElement(case, "skipped", message="evaluation infrastructure unavailable")
for resolution in resolutions:
if resolution.applicable:
continue
case = SubElement(
root,
"testcase",
name=f"pack:{resolution.pack}",
classname="symfonic.evals.applicability",
)
SubElement(case, "skipped", message=resolution.reason)
return tostring(root, encoding="unicode", xml_declaration=True) + "\n"