diff --git a/src/extensions/score_source_code_linker/tests/test_xml_parser.py b/src/extensions/score_source_code_linker/tests/test_xml_parser.py index 00c802e50..bd1d1e5e5 100644 --- a/src/extensions/score_source_code_linker/tests/test_xml_parser.py +++ b/src/extensions/score_source_code_linker/tests/test_xml_parser.py @@ -247,6 +247,17 @@ def test_parse_testcase_result(): ET.SubElement(tc4, "skipped", {"message": "skp"}) assert xml_parser.parse_testcase_result(tc4) == ("skipped", "skp") + # An '' (e.g. uncaught exception) must not be reported as 'passed'. + tc5 = ET.Element("testcase", {"name": "e"}) + ET.SubElement(tc5, "error", {"message": "boom"}) + assert xml_parser.parse_testcase_result(tc5) == ("failed", "boom") + + # A '' takes precedence over an additional ''. + tc6 = ET.Element("testcase", {"name": "f"}) + ET.SubElement(tc6, "failure", {"message": "err"}) + ET.SubElement(tc6, "error", {"message": "boom"}) + assert xml_parser.parse_testcase_result(tc6) == ("failed", "err") + @add_test_properties( partially_verifies=["tool_req__docs_test_link_testcase"], diff --git a/src/extensions/score_source_code_linker/xml_parser.py b/src/extensions/score_source_code_linker/xml_parser.py index 131014889..97a5bc044 100644 --- a/src/extensions/score_source_code_linker/xml_parser.py +++ b/src/extensions/score_source_code_linker/xml_parser.py @@ -169,14 +169,20 @@ def parse_testcase_result(testcase: ET.Element) -> tuple[str, str]: """ skipped = testcase.find("skipped") failed = testcase.find("failure") + # An '' means the testcase did not complete, e.g. an uncaught + # exception in Python's unittest or a crashing binary. It must not be + # reported as 'passed', so it is treated like a failure. + errored = testcase.find("error") status = testcase.get("status") # NOTE: Special CPP case of 'disabled' if status is not None and status == "notrun": return "disabled", "" - if skipped is None and failed is None: + if skipped is None and failed is None and errored is None: return "passed", "" if failed is not None: return "failed", failed.get("message", "") + if errored is not None: + return "failed", errored.get("message", "") if skipped is not None: return "skipped", skipped.get("message", "") # TODO: Test all possible permuations of this to find if this is unreachable