chore: junitxml tests: add more type annotations

This commit is contained in:
Ronny Pfannschmidt 2024-02-21 16:24:54 +01:00
parent 812ce76298
commit e133932b7b
1 changed files with 35 additions and 32 deletions

View File

@ -5,6 +5,7 @@ from datetime import datetime
import os import os
from pathlib import Path from pathlib import Path
import platform import platform
from typing import Any
from typing import cast from typing import cast
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from xml.dom import minidom from xml.dom import minidom
@ -20,6 +21,7 @@ from _pytest.pytester import RunResult
from _pytest.reports import BaseReport from _pytest.reports import BaseReport
from _pytest.reports import TestReport from _pytest.reports import TestReport
from _pytest.stash import Stash from _pytest.stash import Stash
import _pytest.timing
import pytest import pytest
@ -61,13 +63,12 @@ def run_and_parse(pytester: Pytester, schema: xmlschema.XMLSchema) -> RunAndPars
return RunAndParse(pytester, schema) return RunAndParse(pytester, schema)
def assert_attr(node, **kwargs): def assert_attr(node: minidom.Element, **kwargs: object) -> None:
__tracebackhide__ = True __tracebackhide__ = True
def nodeval(node, name): def nodeval(node: minidom.Element, name: str) -> str | None:
anode = node.getAttributeNode(name) anode = node.getAttributeNode(name)
if anode is not None: return anode.value if anode is not None else None
return anode.value
expected = {name: str(value) for name, value in kwargs.items()} expected = {name: str(value) for name, value in kwargs.items()}
on_node = {name: nodeval(node, name) for name in expected} on_node = {name: nodeval(node, name) for name in expected}
@ -75,38 +76,35 @@ def assert_attr(node, **kwargs):
class DomNode: class DomNode:
def __init__(self, dom): def __init__(self, dom: minidom.Element | minidom.Document):
self.__node = dom self.__node = dom
def __repr__(self): def __repr__(self) -> str:
return self.__node.toxml() return self.__node.toxml()
def find_first_by_tag(self, tag): def find_first_by_tag(self, tag: str) -> DomNode | None:
return self.find_nth_by_tag(tag, 0) return self.find_nth_by_tag(tag, 0)
def _by_tag(self, tag):
return self.__node.getElementsByTagName(tag)
@property @property
def children(self): def children(self) -> list[DomNode]:
return [type(self)(x) for x in self.__node.childNodes] return [type(self)(x) for x in self.__node.childNodes]
@property @property
def get_unique_child(self): def get_unique_child(self) -> DomNode:
children = self.children children = self.children
assert len(children) == 1 assert len(children) == 1
return children[0] return children[0]
def find_nth_by_tag(self, tag, n): def find_nth_by_tag(self, tag: str, n: int) -> DomNode | None:
items = self._by_tag(tag) items = self.__node.getElementsByTagName(tag)
try: try:
nth = items[n] nth = items[n]
except IndexError: except IndexError:
pass return None
else: else:
return type(self)(nth) return type(self)(nth)
def find_by_tag(self, tag): def find_by_tag(self, tag: str) -> list[DomNode]:
t = type(self) t = type(self)
return [t(x) for x in self.__node.getElementsByTagName(tag)] return [t(x) for x in self.__node.getElementsByTagName(tag)]
@ -115,23 +113,25 @@ class DomNode:
if node is not None: if node is not None:
return node.value return node.value
def assert_attr(self, **kwargs): def assert_attr(self, **kwargs: object) -> None:
__tracebackhide__ = True __tracebackhide__ = True
assert isinstance(self.__node, minidom.Element)
return assert_attr(self.__node, **kwargs) return assert_attr(self.__node, **kwargs)
def toxml(self): def toxml(self) -> str:
return self.__node.toxml() return self.__node.toxml()
@property @property
def text(self): def text(self) -> str:
return self.__node.childNodes[0].wholeText return cast(str, self.__node.childNodes[0].wholeText)
@property @property
def tag(self): def tag(self) -> str:
assert isinstance(self.__node, minidom.Element)
return self.__node.tagName return self.__node.tagName
@property @property
def next_sibling(self): def next_sibling(self) -> DomNode:
return type(self)(self.__node.nextSibling) return type(self)(self.__node.nextSibling)
@ -225,7 +225,10 @@ class TestPython:
assert start_time <= timestamp < datetime.now() assert start_time <= timestamp < datetime.now()
def test_timing_function( def test_timing_function(
self, pytester: Pytester, run_and_parse: RunAndParse, mock_timing self,
pytester: Pytester,
run_and_parse: RunAndParse,
mock_timing: _pytest.timing.MockTiming,
) -> None: ) -> None:
pytester.makepyfile( pytester.makepyfile(
""" """
@ -255,7 +258,7 @@ class TestPython:
# mock LogXML.node_reporter so it always sets a known duration to each test report object # mock LogXML.node_reporter so it always sets a known duration to each test report object
original_node_reporter = LogXML.node_reporter original_node_reporter = LogXML.node_reporter
def node_reporter_wrapper(s, report): def node_reporter_wrapper(s: Any, report: TestReport) -> Any:
report.duration = 1.0 report.duration = 1.0
reporter = original_node_reporter(s, report) reporter = original_node_reporter(s, report)
return reporter return reporter
@ -499,9 +502,9 @@ class TestPython:
def test_failure_function( def test_failure_function(
self, self,
pytester: Pytester, pytester: Pytester,
junit_logging, junit_logging: str,
run_and_parse: RunAndParse, run_and_parse: RunAndParse,
xunit_family, xunit_family: str,
) -> None: ) -> None:
pytester.makepyfile( pytester.makepyfile(
""" """
@ -599,9 +602,9 @@ class TestPython:
assert result.ret assert result.ret
node = dom.find_first_by_tag("testsuite") node = dom.find_first_by_tag("testsuite")
node.assert_attr(failures=3, tests=3) node.assert_attr(failures=3, tests=3)
tnodes = node.find_by_tag("testcase")
for index, char in enumerate("<&'"): assert len(tnodes) == 3
tnode = node.find_nth_by_tag("testcase", index) for tnode, char in zip(tnodes, "<&'"):
tnode.assert_attr( tnode.assert_attr(
classname="test_failure_escape", name=f"test_func[{char}]" classname="test_failure_escape", name=f"test_func[{char}]"
) )
@ -944,12 +947,12 @@ def test_dont_configure_on_workers(tmp_path: Path) -> None:
if TYPE_CHECKING: if TYPE_CHECKING:
workerinput = None workerinput = None
def __init__(self): def __init__(self) -> None:
self.pluginmanager = self self.pluginmanager = self
self.option = self self.option = self
self.stash = Stash() self.stash = Stash()
def getini(self, name): def getini(self, name: object) -> str:
return "pytest" return "pytest"
junitprefix = None junitprefix = None
@ -1468,7 +1471,7 @@ def test_fancy_items_regression(pytester: Pytester, run_and_parse: RunAndParse)
result.stdout.no_fnmatch_line("*INTERNALERROR*") result.stdout.no_fnmatch_line("*INTERNALERROR*")
items = sorted( items = sorted(
"%(classname)s %(name)s" % x # noqa: UP031 f"{x['classname']} {x['name']}"
# dom is a DomNode not a mapping, it's not possible to ** it. # dom is a DomNode not a mapping, it's not possible to ** it.
for x in dom.find_by_tag("testcase") for x in dom.find_by_tag("testcase")
) )