Skip to content

Commit ec80bef

Browse files
committed
test: improve coverage for dicttoxml_fast module
- Add tests for escape_xml and wrap_cdata functions via Rust backend - Add tests for Python fallback paths using mock - Add tests for special keys detection in nested list structures - Coverage for dicttoxml_fast.py improved from 74% to 92% - Total coverage improved from 97% to 99%
1 parent 937978b commit ec80bef

File tree

1 file changed

+117
-0
lines changed

1 file changed

+117
-0
lines changed

tests/test_rust_dicttoxml.py

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,16 @@
2020
from json2xml.dicttoxml_fast import (
2121
dicttoxml as fast_dicttoxml,
2222
)
23+
from json2xml.dicttoxml_fast import (
24+
escape_xml as fast_escape_xml,
25+
)
2326
from json2xml.dicttoxml_fast import (
2427
get_backend,
2528
is_rust_available,
2629
)
30+
from json2xml.dicttoxml_fast import (
31+
wrap_cdata as fast_wrap_cdata,
32+
)
2733

2834
# Skip all tests if Rust is not available
2935
pytestmark = pytest.mark.skipif(not RUST_AVAILABLE, reason="Rust extension not installed")
@@ -453,3 +459,114 @@ def test_deeply_nested_structure(self):
453459
current = current["level"]
454460
result = rust_dicttoxml(data)
455461
assert b"<level" in result
462+
463+
464+
class TestFastDicttoxmlHelpers:
465+
"""Test helper functions in dicttoxml_fast module."""
466+
467+
def test_escape_xml_via_rust(self):
468+
"""Test escape_xml uses Rust backend when available."""
469+
result = fast_escape_xml("Hello <World> & 'Friends'")
470+
assert "&lt;" in result
471+
assert "&gt;" in result
472+
assert "&amp;" in result
473+
assert "&apos;" in result
474+
475+
def test_escape_xml_empty_string(self):
476+
"""Test escape_xml with empty string."""
477+
result = fast_escape_xml("")
478+
assert result == ""
479+
480+
def test_escape_xml_no_special_chars(self):
481+
"""Test escape_xml with no special characters."""
482+
result = fast_escape_xml("Hello World")
483+
assert result == "Hello World"
484+
485+
def test_wrap_cdata_via_rust(self):
486+
"""Test wrap_cdata uses Rust backend when available."""
487+
result = fast_wrap_cdata("Hello <World>")
488+
assert result == "<![CDATA[Hello <World>]]>"
489+
490+
def test_wrap_cdata_empty_string(self):
491+
"""Test wrap_cdata with empty string."""
492+
result = fast_wrap_cdata("")
493+
assert result == "<![CDATA[]]>"
494+
495+
def test_wrap_cdata_with_cdata_end_sequence(self):
496+
"""Test wrap_cdata handles ]]> in content."""
497+
result = fast_wrap_cdata("Content with ]]> inside")
498+
assert "]]>" in result
499+
assert result.startswith("<![CDATA[")
500+
501+
def test_special_keys_in_nested_list(self):
502+
"""Test that special keys in lists trigger Python fallback."""
503+
# List containing dicts with special keys
504+
data = {"items": [{"@attrs": {"id": "1"}, "@val": "value"}]}
505+
result = fast_dicttoxml(data)
506+
# Should use Python fallback and handle @attrs correctly
507+
assert b'id="1"' in result
508+
509+
def test_special_keys_deep_in_list(self):
510+
"""Test special keys detection in deeply nested list structures."""
511+
data = {
512+
"outer": [
513+
{"normal": "value"},
514+
{"nested": {"@attrs": {"class": "test"}, "@val": "content"}}
515+
]
516+
}
517+
result = fast_dicttoxml(data)
518+
assert b'class="test"' in result
519+
520+
def test_list_with_flat_key(self):
521+
"""Test @flat key handling in lists."""
522+
data = {"items": [{"name@flat": "John"}]}
523+
result = fast_dicttoxml(data)
524+
# Should use Python fallback for @flat handling
525+
assert b"John" in result
526+
527+
528+
class TestFastDicttoxmlPythonFallback:
529+
"""Test Python fallback paths in dicttoxml_fast module."""
530+
531+
def test_escape_xml_python_fallback(self):
532+
"""Test escape_xml falls back to Python when Rust unavailable."""
533+
from unittest.mock import patch
534+
535+
import json2xml.dicttoxml_fast as fast_module
536+
537+
# Temporarily mock _USE_RUST to False
538+
with patch.object(fast_module, '_USE_RUST', False):
539+
result = fast_module.escape_xml("Hello <World>")
540+
assert "&lt;" in result
541+
assert "&gt;" in result
542+
543+
def test_wrap_cdata_python_fallback(self):
544+
"""Test wrap_cdata falls back to Python when Rust unavailable."""
545+
from unittest.mock import patch
546+
547+
import json2xml.dicttoxml_fast as fast_module
548+
549+
# Temporarily mock _USE_RUST to False
550+
with patch.object(fast_module, '_USE_RUST', False):
551+
result = fast_module.wrap_cdata("Hello World")
552+
assert result == "<![CDATA[Hello World]]>"
553+
554+
def test_escape_xml_fallback_when_rust_func_none(self):
555+
"""Test escape_xml falls back when rust_escape_xml is None."""
556+
from unittest.mock import patch
557+
558+
import json2xml.dicttoxml_fast as fast_module
559+
560+
with patch.object(fast_module, 'rust_escape_xml', None):
561+
result = fast_module.escape_xml("Test & Value")
562+
assert "&amp;" in result
563+
564+
def test_wrap_cdata_fallback_when_rust_func_none(self):
565+
"""Test wrap_cdata falls back when rust_wrap_cdata is None."""
566+
from unittest.mock import patch
567+
568+
import json2xml.dicttoxml_fast as fast_module
569+
570+
with patch.object(fast_module, 'rust_wrap_cdata', None):
571+
result = fast_module.wrap_cdata("Test Content")
572+
assert result == "<![CDATA[Test Content]]>"

0 commit comments

Comments
 (0)