diff --git a/codecov_cli/parsers/junit.py b/codecov_cli/parsers/junit.py new file mode 100644 index 00000000..16c4a101 --- /dev/null +++ b/codecov_cli/parsers/junit.py @@ -0,0 +1,51 @@ +import logging +from datetime import datetime, timedelta +from typing import List + +from lxml import etree + +from codecov_cli.parsers.base import ParsingError, Testcase, Testsuite + +logger = logging.getLogger("codecovcli") + + +class JUnitXMLParser: + def __init__(self): + self._parser = etree.XMLParser(recover=True, resolve_entities=False) + + def parse(self, file_content) -> List[Testsuite]: + processed = self._parse_xml(file_content) + if processed is None or len(processed) == 0: + raise ParsingError("Error parsing XML file") + + testsuites = [ + self._create_testsuite(testsuite_xml) + for testsuite_xml in processed.iter("testsuite") + ] + + return testsuites + + def _create_testcase(self, testcase_xml: etree.Element): + return Testcase( + f"{testcase_xml.get('classname')}.{testcase_xml.get('name')}", + len(testcase_xml) == 0, + timedelta(seconds=float(testcase_xml.get("time"))), + ) + + def _create_testsuite(self, testsuite_xml: etree.Element): + return Testsuite( + testsuite_xml.get("name"), + datetime.fromisoformat(testsuite_xml.get("timestamp")), + timedelta(seconds=float(testsuite_xml.get("time"))), + [ + self._create_testcase(testcase_xml) + for testcase_xml in testsuite_xml.iter("testcase") + ], + int(testsuite_xml.get("failures")), + int(testsuite_xml.get("errors")), + int(testsuite_xml.get("skipped")), + int(testsuite_xml.get("tests")), + ) + + def _parse_xml(self, file_content): + return etree.fromstring(file_content, parser=self._parser) diff --git a/tests/parsers/test_junit.py b/tests/parsers/test_junit.py new file mode 100644 index 00000000..d1386781 --- /dev/null +++ b/tests/parsers/test_junit.py @@ -0,0 +1,27 @@ +from datetime import datetime, timedelta + +from codecov_cli.parsers.base import Testcase, Testsuite +from codecov_cli.parsers.junit import JUnitXMLParser + + +def test_parse_junit(): + parser = JUnitXMLParser() + testsuites = parser.parse( + bytes( + """""", + encoding="utf-8", + ) + ) + + result = testsuites[0] + + assert result.name == "pytest" + assert result.timestamp == datetime.fromisoformat("2023-10-20T12:56:19.831266") + assert result.time == timedelta(seconds=0.016) + assert result.testcases[0].name == "tests.parsers.test_base.test_testsuite" + assert result.testcases[0].status == True + assert result.testcases[0].duration == timedelta(seconds=0.0) + assert result.errors == 0 + assert result.failures == 0 + assert result.skipped == 0 + assert result.total == 1