Skip to content

Commit

Permalink
Make XML element comparison util more generic (#164)
Browse files Browse the repository at this point in the history
* Make XML element comparison util more generic

* Add changelog fragment

* Lint

* Add inverse test to xml util

* Lint

* Update some unit test descriptions
  • Loading branch information
DonGiovanni83 authored Dec 6, 2024
1 parent 3564a1a commit 2705319
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 15 deletions.
3 changes: 3 additions & 0 deletions changelogs/fragments/164-fix-xml-element-comparison-util.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
---
minor_changes:
- plugins.module_utils.xml_utils:elements_equal - Fix element content comparison behaviour
20 changes: 6 additions & 14 deletions plugins/module_utils/xml_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -187,17 +187,6 @@ def etree_to_dict(input_etree: Element) -> dict:
return {input_etree.tag: result}


def _is_whitespace_or_none(text) -> bool:
"""
Checks if a given string is a string of whitespace characters or None.
Args:
text: the string to perform the check on.
Returns:
bool: True if the 'text' string is None or a whitespace string.
"""
return text is None or text.strip() == ""


def elements_equal(e1, e2) -> bool:
"""
Compare two XML elements for equality.
Expand All @@ -216,10 +205,13 @@ def elements_equal(e1, e2) -> bool:
if len(e1) == 0 and len(e2) == 0:
# 1. Check if texts are exactly the same (ignoring whitespaces and None)
# 2. or check if one text is '1' and the other is None with no children
e1_text: Optional[str] = "" if e1.text is None else str(e1.text).strip()
e2_text: Optional[str] = "" if e2.text is None else str(e2.text).strip()

return (
(_is_whitespace_or_none(e1.text) == _is_whitespace_or_none(e2.text))
or (e1.text == "1" and not e2.text and not e2)
or (e2.text == "1" and not e1.text and not e1)
e1_text == e2_text
or (e1_text == "1" and e2_text == "")
or (e2_text == "1" and e1_text == "")
)

# Tags have children
Expand Down
42 changes: 41 additions & 1 deletion tests/unit/plugins/module_utils/test_xml_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,21 @@ def test_elements_equal_without_children_whitespace_matches():
assert xml_utils.elements_equal(e1, e2)


def test_elements_equal_str_num_and_int():
"""
Test that elements_equal function considers a string number equal to an integer number
eg:
<test/> == <test> </test>
"""
e1 = Element("test")
e1.text = 1
e2 = Element("test")
e2.text = "1"

assert xml_utils.elements_equal(e1, e2)


def test_elements_equal_without_children_none_and_1():
"""
Tests elements_equal function matches a boolean flag "1" the same as an empty element.
Expand All @@ -433,17 +448,42 @@ def test_elements_equal_without_children_none_and_1():
def test_elements_equal_with_children():
"""
Tests elements_equal function matches recursively equal elements.
Elements having children with the same content should be equal.
"""
e1 = Element("test")
e1c1 = Element("child_1")
e1c1.text = "some_text"
e1c2 = Element("child_2")
e1c2.text = "some_text_as_well"
e1.extend([e1c1, e1c2])

e2 = Element("test")
e2c1 = Element("child_1")
e2c1.text = "some_text \n"
e2c2 = Element("child_2")
e2c2.text = "\n some_text \n"
e2c2.text = "\n some_text_as_well \n"
e2.extend([e2c1, e2c2])

assert xml_utils.elements_equal(e1, e2)


def test_elements_not_equal_with_children():
"""
Tests elements_equal function checks elements recursively.
Elements having children with different content should not be equal.
"""
e1 = Element("test")
e1c1 = Element("child_1")
e1c1.text = "some_text"
e1c2 = Element("child_2")
e1c2.text = "some_text_as_well"
e1.extend([e1c1, e1c2])

e2 = Element("test")
e2c1 = Element("child_1")
e2c1.text = "some_text \n"
e2c2 = Element("child_2")
e2c2.text = "\n wrong_text \n"
e2.extend([e2c1, e2c2])

assert not xml_utils.elements_equal(e1, e2)

0 comments on commit 2705319

Please sign in to comment.