Skip to content

Commit 9e75ca4

Browse files
committed
test(dicttoxml): add targeted tests to cover edge branches and XML name handling
Adds coverage for CDATA edge, numeric and namespaced keys, list header behavior, @Flat handling, Decimal typing, cdata conversion, and id attributes when ids provided.
1 parent 42428f8 commit 9e75ca4

File tree

1 file changed

+101
-0
lines changed

1 file changed

+101
-0
lines changed

tests/test_additional_coverage.py

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
import decimal
2+
from typing import Any
3+
4+
import pytest
5+
6+
from json2xml import dicttoxml
7+
8+
9+
class TestAdditionalCoverage:
10+
def test_wrap_cdata_handles_cdata_end(self) -> None:
11+
# Ensure CDATA splitting works for "]]>" sequence
12+
text = "a]]>b"
13+
wrapped = dicttoxml.wrap_cdata(text)
14+
assert wrapped == "<![CDATA[a]]]]><![CDATA[>b]]>"
15+
16+
def test_make_valid_xml_name_with_int_key(self) -> None:
17+
# Int keys should be converted to n<digits>
18+
key, attr = dicttoxml.make_valid_xml_name(123, {}) # type: ignore[arg-type]
19+
assert key == "n123"
20+
assert attr == {}
21+
22+
def test_make_valid_xml_name_namespace_flat(self) -> None:
23+
# Namespaced key with @flat suffix should be considered valid as-is
24+
key_in = "ns:key@flat"
25+
key_out, attr = dicttoxml.make_valid_xml_name(key_in, {})
26+
assert key_out == key_in
27+
assert attr == {}
28+
29+
def test_dict2xml_str_parent_list_with_attrs_and_no_wrap(self) -> None:
30+
# When inside list context with list_headers=True and item_wrap=False,
31+
# attributes belong to the parent element header
32+
item = {"@attrs": {"a": "b"}, "@val": "X"}
33+
xml = dicttoxml.dict2xml_str(
34+
attr_type=False,
35+
attr={},
36+
item=item,
37+
item_func=lambda _p: "item",
38+
cdata=False,
39+
item_name="ignored",
40+
item_wrap=False,
41+
parentIsList=True,
42+
parent="Parent",
43+
list_headers=True,
44+
)
45+
assert xml == '<Parent a="b">X</Parent>'
46+
47+
def test_dict2xml_str_with_flat_flag_in_item(self) -> None:
48+
# If @flat=True, the subtree should not be wrapped
49+
item = {"@val": "text", "@flat": True}
50+
xml = dicttoxml.dict2xml_str(
51+
attr_type=False,
52+
attr={},
53+
item=item,
54+
item_func=lambda _p: "item",
55+
cdata=False,
56+
item_name="ignored",
57+
item_wrap=True,
58+
parentIsList=False,
59+
)
60+
assert xml == "text"
61+
62+
def test_list2xml_str_returns_subtree_when_list_headers_true(self) -> None:
63+
# list_headers=True should return subtree directly from convert_list
64+
xml = dicttoxml.list2xml_str(
65+
attr_type=False,
66+
attr={},
67+
item=["a"],
68+
item_func=lambda _p: "item",
69+
cdata=False,
70+
item_name="test",
71+
item_wrap=True,
72+
list_headers=True,
73+
)
74+
assert xml == "<item>a</item>"
75+
76+
def test_get_xml_type_with_decimal_number(self) -> None:
77+
# Decimal is a numbers.Number but not int/float
78+
value = decimal.Decimal("5")
79+
assert dicttoxml.get_xml_type(value) == "number"
80+
# And convert_kv should mark it as type="number"
81+
out = dicttoxml.convert_kv("key", value, attr_type=True)
82+
assert out == '<key type="number">5</key>'
83+
84+
def test_dicttoxml_cdata_with_cdata_end_sequence(self) -> None:
85+
data = {"key": "a]]>b"}
86+
out = dicttoxml.dicttoxml(data, root=False, attr_type=False, cdata=True).decode()
87+
assert out == "<key><![CDATA[a]]]]><![CDATA[>b]]></key>"
88+
89+
def test_convert_dict_with_ids_adds_id_attributes(self) -> None:
90+
obj: dict[str, Any] = {"a": 1, "b": 2}
91+
xml = dicttoxml.convert_dict(
92+
obj=obj,
93+
ids=["seed"],
94+
parent="root",
95+
attr_type=False,
96+
item_func=lambda _p: "item",
97+
cdata=False,
98+
item_wrap=True,
99+
)
100+
# Both elements should carry some id attribute
101+
assert xml.count(' id="') == 2

0 commit comments

Comments
 (0)