-
-
Notifications
You must be signed in to change notification settings - Fork 32
feat: Increase test coverage and strengthen dicttoxml typing #246
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
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,101 @@ | ||||||||||||||||||||||||||||||||||||||||||
import decimal | ||||||||||||||||||||||||||||||||||||||||||
from typing import Any, cast | ||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
import pytest | ||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
from json2xml import dicttoxml | ||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
class TestAdditionalCoverage: | ||||||||||||||||||||||||||||||||||||||||||
def test_wrap_cdata_handles_cdata_end(self) -> None: | ||||||||||||||||||||||||||||||||||||||||||
# Ensure CDATA splitting works for "]]>" sequence | ||||||||||||||||||||||||||||||||||||||||||
text = "a]]>b" | ||||||||||||||||||||||||||||||||||||||||||
wrapped = dicttoxml.wrap_cdata(text) | ||||||||||||||||||||||||||||||||||||||||||
assert wrapped == "<![CDATA[a]]]]><![CDATA[>b]]>" | ||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
def test_make_valid_xml_name_with_int_key(self) -> None: | ||||||||||||||||||||||||||||||||||||||||||
# Int keys should be converted to n<digits> | ||||||||||||||||||||||||||||||||||||||||||
key, attr = dicttoxml.make_valid_xml_name(123, {}) # type: ignore[arg-type] | ||||||||||||||||||||||||||||||||||||||||||
assert key == "n123" | ||||||||||||||||||||||||||||||||||||||||||
assert attr == {} | ||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
def test_make_valid_xml_name_namespace_flat(self) -> None: | ||||||||||||||||||||||||||||||||||||||||||
# Namespaced key with @flat suffix should be considered valid as-is | ||||||||||||||||||||||||||||||||||||||||||
key_in = "ns:key@flat" | ||||||||||||||||||||||||||||||||||||||||||
key_out, attr = dicttoxml.make_valid_xml_name(key_in, {}) | ||||||||||||||||||||||||||||||||||||||||||
assert key_out == key_in | ||||||||||||||||||||||||||||||||||||||||||
assert attr == {} | ||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+22
to
+27
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. suggestion (testing): Consider adding a test for negative integer keys in make_valid_xml_name. Negative integer keys may be handled differently and could cause issues with XML naming. Please add a test for a negative integer key to verify correct behavior.
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
def test_dict2xml_str_parent_list_with_attrs_and_no_wrap(self) -> None: | ||||||||||||||||||||||||||||||||||||||||||
# When inside list context with list_headers=True and item_wrap=False, | ||||||||||||||||||||||||||||||||||||||||||
# attributes belong to the parent element header | ||||||||||||||||||||||||||||||||||||||||||
item = {"@attrs": {"a": "b"}, "@val": "X"} | ||||||||||||||||||||||||||||||||||||||||||
xml = dicttoxml.dict2xml_str( | ||||||||||||||||||||||||||||||||||||||||||
attr_type=False, | ||||||||||||||||||||||||||||||||||||||||||
attr={}, | ||||||||||||||||||||||||||||||||||||||||||
item=item, | ||||||||||||||||||||||||||||||||||||||||||
item_func=lambda _p: "item", | ||||||||||||||||||||||||||||||||||||||||||
cdata=False, | ||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+29
to
+38
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. suggestion (testing): Consider adding a test for multiple attributes in parent list context. Please add a test case with multiple attributes to verify correct serialization in the parent element. |
||||||||||||||||||||||||||||||||||||||||||
item_name="ignored", | ||||||||||||||||||||||||||||||||||||||||||
item_wrap=False, | ||||||||||||||||||||||||||||||||||||||||||
parentIsList=True, | ||||||||||||||||||||||||||||||||||||||||||
parent="Parent", | ||||||||||||||||||||||||||||||||||||||||||
list_headers=True, | ||||||||||||||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||||||||||||||
assert xml == '<Parent a="b">X</Parent>' | ||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
def test_dict2xml_str_with_flat_flag_in_item(self) -> None: | ||||||||||||||||||||||||||||||||||||||||||
# If @flat=True, the subtree should not be wrapped | ||||||||||||||||||||||||||||||||||||||||||
item = {"@val": "text", "@flat": True} | ||||||||||||||||||||||||||||||||||||||||||
xml = dicttoxml.dict2xml_str( | ||||||||||||||||||||||||||||||||||||||||||
attr_type=False, | ||||||||||||||||||||||||||||||||||||||||||
attr={}, | ||||||||||||||||||||||||||||||||||||||||||
item=item, | ||||||||||||||||||||||||||||||||||||||||||
item_func=lambda _p: "item", | ||||||||||||||||||||||||||||||||||||||||||
cdata=False, | ||||||||||||||||||||||||||||||||||||||||||
item_name="ignored", | ||||||||||||||||||||||||||||||||||||||||||
item_wrap=True, | ||||||||||||||||||||||||||||||||||||||||||
parentIsList=False, | ||||||||||||||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||||||||||||||
assert xml == "text" | ||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
def test_list2xml_str_returns_subtree_when_list_headers_true(self) -> None: | ||||||||||||||||||||||||||||||||||||||||||
# list_headers=True should return subtree directly from convert_list | ||||||||||||||||||||||||||||||||||||||||||
xml = dicttoxml.list2xml_str( | ||||||||||||||||||||||||||||||||||||||||||
attr_type=False, | ||||||||||||||||||||||||||||||||||||||||||
attr={}, | ||||||||||||||||||||||||||||||||||||||||||
item=["a"], | ||||||||||||||||||||||||||||||||||||||||||
item_func=lambda _p: "item", | ||||||||||||||||||||||||||||||||||||||||||
cdata=False, | ||||||||||||||||||||||||||||||||||||||||||
item_name="test", | ||||||||||||||||||||||||||||||||||||||||||
item_wrap=True, | ||||||||||||||||||||||||||||||||||||||||||
list_headers=True, | ||||||||||||||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||||||||||||||
assert xml == "<item>a</item>" | ||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
def test_get_xml_type_with_decimal_number(self) -> None: | ||||||||||||||||||||||||||||||||||||||||||
# Decimal is a numbers.Number but not int/float | ||||||||||||||||||||||||||||||||||||||||||
value = decimal.Decimal("5") | ||||||||||||||||||||||||||||||||||||||||||
assert dicttoxml.get_xml_type(cast(Any, value)) == "number" | ||||||||||||||||||||||||||||||||||||||||||
# And convert_kv should mark it as type="number" | ||||||||||||||||||||||||||||||||||||||||||
out = dicttoxml.convert_kv("key", cast(Any, value), attr_type=True) | ||||||||||||||||||||||||||||||||||||||||||
assert out == '<key type="number">5</key>' | ||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
def test_dicttoxml_cdata_with_cdata_end_sequence(self) -> None: | ||||||||||||||||||||||||||||||||||||||||||
data = {"key": "a]]>b"} | ||||||||||||||||||||||||||||||||||||||||||
out = dicttoxml.dicttoxml(data, root=False, attr_type=False, cdata=True).decode() | ||||||||||||||||||||||||||||||||||||||||||
assert out == "<key><![CDATA[a]]]]><![CDATA[>b]]></key>" | ||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
def test_convert_dict_with_ids_adds_id_attributes(self) -> None: | ||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. suggestion (testing): Consider adding a test for multiple CDATA end sequences in a single value. Please include a test case where the value contains more than one ']]>' sequence to verify correct handling in all instances.
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||
obj: dict[str, Any] = {"a": 1, "b": 2} | ||||||||||||||||||||||||||||||||||||||||||
xml = dicttoxml.convert_dict( | ||||||||||||||||||||||||||||||||||||||||||
obj=obj, | ||||||||||||||||||||||||||||||||||||||||||
ids=["seed"], | ||||||||||||||||||||||||||||||||||||||||||
parent="root", | ||||||||||||||||||||||||||||||||||||||||||
attr_type=False, | ||||||||||||||||||||||||||||||||||||||||||
item_func=lambda _p: "item", | ||||||||||||||||||||||||||||||||||||||||||
cdata=False, | ||||||||||||||||||||||||||||||||||||||||||
item_wrap=True, | ||||||||||||||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||||||||||||||
# Both elements should carry some id attribute | ||||||||||||||||||||||||||||||||||||||||||
assert xml.count(' id="') == 2 |
Check notice
Code scanning / CodeQL
Unused import Note test
Copilot Autofix
AI about 1 month ago
To fix the problem, simply remove the unused import statement
import pytest
from line 4 oftests/test_additional_coverage.py
. This will clean up the code by eliminating an unnecessary dependency and improving readability. No other changes are required, as the rest of the code does not referencepytest
directly.