Source code for sphinx_reports.Adapter.JUnit

# ==================================================================================================================== #
#            _     _                                           _                                                       #
#  ___ _ __ | |__ (_)_ __ __  __     _ __ ___ _ __   ___  _ __| |_ ___                                                 #
# / __| '_ \| '_ \| | '_ \\ \/ /____| '__/ _ \ '_ \ / _ \| '__| __/ __|                                                #
# \__ \ |_) | | | | | | | |>  <_____| | |  __/ |_) | (_) | |  | |_\__ \                                                #
# |___/ .__/|_| |_|_|_| |_/_/\_\    |_|  \___| .__/ \___/|_|   \__|___/                                                #
#     |_|                                    |_|                                                                       #
# ==================================================================================================================== #
# Authors:                                                                                                             #
#   Patrick Lehmann                                                                                                    #
#                                                                                                                      #
# License:                                                                                                             #
# ==================================================================================================================== #
# Copyright 2023-2024 Patrick Lehmann - Bötzingen, Germany                                                             #
#                                                                                                                      #
# Licensed under the Apache License, Version 2.0 (the "License");                                                      #
# you may not use this file except in compliance with the License.                                                     #
# You may obtain a copy of the License at                                                                              #
#                                                                                                                      #
#   http://www.apache.org/licenses/LICENSE-2.0                                                                         #
#                                                                                                                      #
# Unless required by applicable law or agreed to in writing, software                                                  #
# distributed under the License is distributed on an "AS IS" BASIS,                                                    #
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.                                             #
# See the License for the specific language governing permissions and                                                  #
# limitations under the License.                                                                                       #
#                                                                                                                      #
# SPDX-License-Identifier: Apache-2.0                                                                                  #
# ==================================================================================================================== #
#
"""
**A Sphinx extension providing uni test results embedded in documentation pages.**
"""
from datetime        import datetime, timedelta
from pathlib         import Path
from xml.dom         import minidom, Node
from xml.dom.minidom import Element

from pyTooling.Decorators              import export, readonly

from sphinx_reports.Common             import ReportExtensionError
from sphinx_reports.DataModel.Unittest import Testsuite, Testcase, TestsuiteSummary, Test, TestcaseState


[docs] @export class UnittestError(ReportExtensionError): pass
[docs] @export class Analyzer: _reportFile: Path _documentElement: Element _testsuiteSummary: TestsuiteSummary
[docs] def __init__(self, reportFile: Path): self._reportFile = reportFile if not self._reportFile.exists(): # FIXME: not found vs. does not exist # text in inner exception needed? # FileNotFoundError(f"File '{self._path!s}' not found.") raise UnittestError(f"JUnit unittest report file '{self._reportFile}' not found.") from FileNotFoundError(self._reportFile) try: self._documentElement = minidom.parse(str(self._reportFile)).documentElement except Exception as ex: raise UnittestError(f"Couldn't open '{self._reportFile}'.") from ex
def Convert(self) -> TestsuiteSummary: self._ParseRootElement(self._documentElement) return self._testsuiteSummary def _ParseRootElement(self, root: Element) -> None: name = root.getAttribute("name") if root.hasAttribute("name") else "root" testsuiteRuntime = float(root.getAttribute("time")) if root.hasAttribute("time") else -1.0 timestamp = datetime.fromisoformat(root.getAttribute("timestamp")) if root.hasAttribute("timestamp") else None self._testsuiteSummary = TestsuiteSummary(name, timedelta(seconds=testsuiteRuntime)) tests = root.getAttribute("tests") skipped = root.getAttribute("skipped") errors = root.getAttribute("errors") failures = root.getAttribute("failures") assertions = root.getAttribute("assertions") for rootNode in root.childNodes: if rootNode.nodeName == "testsuite": self._ParseTestsuite(rootNode) def _ParseTestsuite(self, testsuitesNode: Element) -> None: for node in testsuitesNode.childNodes: if node.nodeType == Node.ELEMENT_NODE: if node.tagName == "testsuite": self._ParseTestsuite(node) elif node.tagName == "testcase": self._ParseTestcase(node) def _ParseTestcase(self, testsuiteNode: Element) -> None: className = testsuiteNode.getAttribute("classname") name = testsuiteNode.getAttribute("name") time = float(testsuiteNode.getAttribute("time")) concurrentSuite = self._testsuiteSummary testsuitePath = className.split(".") for testsuiteName in testsuitePath: try: concurrentSuite = concurrentSuite[testsuiteName] except KeyError: new = Testsuite(testsuiteName, timedelta(seconds=time)) concurrentSuite._testsuites[testsuiteName] = new concurrentSuite = new testcase = Testcase(name, timedelta(seconds=time)) concurrentSuite._testcases[name] = testcase for node in testsuiteNode.childNodes: if node.nodeType == Node.ELEMENT_NODE: if node.tagName == "skipped": testcase._state = TestcaseState.Skipped elif node.tagName == "failure": testcase._state = TestcaseState.Failed elif node.tagName == "error": testcase._state = TestcaseState.Error elif node.tagName == "system-out": pass elif node.tagName == "system-err": pass elif node.tagName == "properties": pass else: raise UnittestError(f"Unknown element '{node.tagName}' in junit file.") if testcase._state is TestcaseState.Unknown: testcase._state = TestcaseState.Passed