Files
zig-fetch-py/tests/test_parser.py
crosstyan 81348b1f28 Improve ZON parser tuple handling with configurable empty tuple parsing
- Add `empty_tuple_as_dict` parameter to control parsing of empty tuples
- Enhance tuple and object parsing logic to handle nested and complex structures
- Update test cases to cover various tuple and empty tuple scenarios
- Modify `parse_zon_file` and `zon_to_json` functions to support new parsing option
2025-03-07 17:11:57 +08:00

263 lines
7.7 KiB
Python

"""
Unit tests for the ZON parser.
"""
import json
import pytest
from pathlib import Path
from zig_fetch_py.parser import ZonParser, parse_zon_file, zon_to_json
class TestZonParser:
"""Test cases for the ZonParser class."""
def test_parse_empty_object(self):
"""Test parsing an empty object with empty_tuple_as_dict=True."""
parser = ZonParser(".{}", empty_tuple_as_dict=True)
result = parser.parse()
assert result == {}
def test_parse_empty_tuple_as_list(self):
"""Test parsing an empty tuple as list with empty_tuple_as_dict=False."""
parser = ZonParser(".{}", empty_tuple_as_dict=False)
result = parser.parse()
assert result == []
def test_parse_simple_object(self):
"""Test parsing a simple object with string values."""
parser = ZonParser(
""".{
.name = "test",
.version = "1.0.0",
}"""
)
result = parser.parse()
assert result == {"name": "test", "version": "1.0.0"}
def test_parse_nested_object(self):
"""Test parsing a nested object."""
parser = ZonParser(
""".{
.metadata = .{
.name = "test",
.version = "1.0.0",
},
}"""
)
result = parser.parse()
assert result == {"metadata": {"name": "test", "version": "1.0.0"}}
def test_parse_numbers(self):
"""Test parsing different number formats."""
parser = ZonParser(
""".{
.integer = 42,
.negative = -10,
.float = 3.14,
.hex = 0xDEADBEEF,
}"""
)
result = parser.parse()
assert result == {
"integer": 42,
"negative": -10,
"float": 3.14,
"hex": 0xDEADBEEF,
}
def test_parse_boolean(self):
"""Test parsing boolean values."""
parser = ZonParser(
""".{
.is_true = true,
.is_false = false,
}"""
)
result = parser.parse()
assert result == {"is_true": True, "is_false": False}
def test_parse_null(self):
"""Test parsing null values."""
parser = ZonParser(
""".{
.nothing = null,
}"""
)
result = parser.parse()
assert result == {"nothing": None}
def test_parse_comments(self):
"""Test parsing with comments."""
parser = ZonParser(
""".{
// This is a comment
.name = "test", // Inline comment
// Another comment
.version = "1.0.0",
}"""
)
result = parser.parse()
assert result == {"name": "test", "version": "1.0.0"}
def test_parse_special_identifiers(self):
"""Test parsing special identifiers with @ symbol."""
parser = ZonParser(
""".{
.@"special-name" = "value",
}"""
)
result = parser.parse()
assert result == {"special-name": "value"}
def test_parse_shorthand_notation(self):
"""Test parsing shorthand notation where key is the same as value."""
parser = ZonParser(
""".{
.name,
.version,
}"""
)
result = parser.parse()
assert result == {"name": "name", "version": "version"}
def test_parse_escaped_strings(self):
"""Test parsing strings with escape sequences."""
parser = ZonParser(
""".{
.escaped = "Line 1\\nLine 2\\tTabbed\\r\\n",
}"""
)
result = parser.parse()
assert result == {"escaped": "Line 1\nLine 2\tTabbed\r\n"}
def test_parse_error_invalid_syntax(self):
"""Test that parser raises an error for invalid syntax."""
with pytest.raises(ValueError):
parser = ZonParser(".{,}")
parser.parse()
def test_parse_error_unterminated_string(self):
"""Test that parser raises an error for unterminated strings."""
with pytest.raises(ValueError):
parser = ZonParser(
""".{
.name = "unterminated,
}"""
)
parser.parse()
def test_parse_tuple(self):
"""Test parsing tuples."""
parser = ZonParser(
""".{
.simple_tuple = .{1, 2, 3},
.string_tuple = .{"one", "two", "three"},
.empty_tuple = .{""},
.mixed_tuple = .{1, "two", true},
}"""
)
result = parser.parse()
assert result == {
"simple_tuple": [1, 2, 3],
"string_tuple": ["one", "two", "three"],
"empty_tuple": [""],
"mixed_tuple": [1, "two", True],
}
def test_parse_nested_tuples(self):
"""Test parsing nested tuples."""
parser = ZonParser(
""".{
.nested_tuple = .{ .{1, 2}, .{3, 4} },
}"""
)
result = parser.parse()
assert result == {"nested_tuple": [[1, 2], [3, 4]]}
def test_parse_objects_in_tuple(self):
"""Test parsing objects within tuples."""
parser = ZonParser(
""".{
.object_in_tuple = .{ .{.x = 1, .y = 2}, .{.x = 3, .y = 4} },
}"""
)
result = parser.parse()
assert result == {"object_in_tuple": [{"x": 1, "y": 2}, {"x": 3, "y": 4}]}
def test_parse_complex_nested_structures(self):
"""Test parsing complex nested structures."""
parser = ZonParser(
""".{
.metadata = .{
.name = "example",
.version = "1.0.0",
},
.simple_tuple = .{1, 2, 3},
.nested = .{
.tuple_in_object = .{4, 5, 6},
.object_in_tuple = .{ .{.x = 1, .y = 2}, .{.x = 3, .y = 4} },
},
.nested_tuple = .{ .{1, 2}, .{3, 4} },
.empty = .{},
}"""
)
result = parser.parse()
assert result == {
"metadata": {"name": "example", "version": "1.0.0"},
"simple_tuple": [1, 2, 3],
"nested": {
"tuple_in_object": [4, 5, 6],
"object_in_tuple": [{"x": 1, "y": 2}, {"x": 3, "y": 4}],
},
"nested_tuple": [[1, 2], [3, 4]],
"empty": [],
}
def test_parse_tuple_as_array(self):
"""Test parsing a tuple as an array."""
parser = ZonParser(
""".{
.tags = .{"tag1", "tag2", "tag3"},
}"""
)
result = parser.parse()
assert result == {"tags": ["tag1", "tag2", "tag3"]}
class TestZonFileParser:
"""Test cases for the file parsing functions."""
def test_zon_to_json(self, tmp_path):
"""Test converting ZON to JSON."""
zon_content = """.{
.name = "test",
.version = "1.0.0",
}"""
# Test without indentation
json_str = zon_to_json(zon_content)
parsed_json = json.loads(json_str)
assert parsed_json == {"name": "test", "version": "1.0.0"}
# Test with indentation
json_str_pretty = zon_to_json(zon_content, indent=2)
assert " " in json_str_pretty # Should have indentation
parsed_json = json.loads(json_str_pretty)
assert parsed_json == {"name": "test", "version": "1.0.0"}
def test_parse_zon_file(self, tmp_path):
"""Test parsing a ZON file."""
# Create a temporary ZON file
zon_file = tmp_path / "test.zon"
zon_file.write_text(
""".{
.name = "test",
.version = "1.0.0",
}"""
)
# Parse the file
result = parse_zon_file(str(zon_file))
assert result == {"name": "test", "version": "1.0.0"}