Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make XML element comparison util more generic #164

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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.
KiLLuuuhh marked this conversation as resolved.
Show resolved Hide resolved
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)
Loading