Skip to content

Commit

Permalink
Fix XML comparison, compare time within 1e-6 seconds
Browse files Browse the repository at this point in the history
There appears to be a difference in how 'time' is generated in the XML
output, possibly different in different systems/configurations.

Possible culprit is how the 'time' attribute is for 'testsuite' elements.
https://github.com/kyrus/python-junit-xml/blob/4bd08a272f059998cedf9b7779f944d49eba13a6/junit_xml/__init__.py#L135

Test case attributes appear to be formatted using `'%f' % time`, which
is 6 decimal places by default.

For the testsuite, it looks like it's just a `str` call and maybe this
is causing different systems to generate time of different precision.

Due to this small differences in how time is encoded in the XML, the
test suite may fail due to differences in the amount of precision is
encoded on the system.

Add a new function to the test suite that compares the XML document
recursively and assert that tags, text and attributes match.

For 'time' attributes, we compare using `math.isclose()` with a
tolerance of 1e-6.
  • Loading branch information
CervEdin committed Sep 25, 2024
1 parent 0601e2d commit fc89270
Showing 1 changed file with 46 additions and 1 deletion.
47 changes: 46 additions & 1 deletion test/test_outputs.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,55 @@
import glob
import math
import os
import subprocess
import xml.etree.ElementTree as ET
from pathlib import Path

import pytest
from _common import normalize_output


def compare_xml_elements(elem1, elem2):
"""
Recursively assert the equality of two XML elements and their children.
"""
# Compare tags
assert elem1.tag == elem2.tag, f"Tag mismatch: {elem1.tag} != {elem2.tag}"

# Compare text
assert (
elem1.text == elem2.text
), f"Text mismatch in tag {elem1.tag}: {elem1.text} != {elem2.text}"

# Compare attributes
for attr in elem1.attrib:
assert attr in elem2.attrib, f"Attribute '{attr}' missing in tag {elem2.tag}"
# 'time' is sensitive to precision
if attr == "time":
assert math.isclose(
float(elem1.attrib[attr]), float(elem2.attrib[attr]), abs_tol=1e-6
), (
f"Floating-point mismatch in attribute '{attr}'"
f" in tag {elem1.tag}:"
f" {elem1.attrib[attr]} != {elem2.attrib[attr]}"
)
else:
assert elem1.attrib[attr] == elem2.attrib[attr], (
f"Attribute mismatch in tag {elem1.tag}: {attr}:"
f" {elem1.attrib[attr]} != {elem2.attrib[attr]}"
)

# Compare number of children
assert len(elem1) == len(elem2), (
f"Number of children mismatch in tag {elem1.tag}: "
f"{len(elem1)} != {len(elem2)}"
)

# Recursively compare child elements
for child1, child2 in zip(elem1, elem2):
compare_xml_elements(child1, child2)


class TestOutputs:
filelist = glob.glob("test/fixtures/*.tap")
print(filelist)
Expand All @@ -17,4 +60,6 @@ def test_file(self, tmp_path, file):
original = f"./test/output/{name}.xml"
output = f"{tmp_path}/out.xml"
subprocess.run(["python", "-m", "tap2junit", "-i", file, "-o", output])
assert Path(original).read_text() == normalize_output(Path(output).read_text())
original_xml = ET.parse(original)

Check failure on line 63 in test/test_outputs.py

View workflow job for this annotation

GitHub Actions / lint_python

Ruff (S314)

test/test_outputs.py:63:24: S314 Using `xml` to parse untrusted data is known to be vulnerable to XML attacks; use `defusedxml` equivalents
output_xml = ET.fromstring(normalize_output(Path(output).read_text()))

Check failure on line 64 in test/test_outputs.py

View workflow job for this annotation

GitHub Actions / lint_python

Ruff (S314)

test/test_outputs.py:64:22: S314 Using `xml` to parse untrusted data is known to be vulnerable to XML attacks; use `defusedxml` equivalents
compare_xml_elements(original_xml.getroot(), output_xml)

0 comments on commit fc89270

Please sign in to comment.