1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
|
# Copyright (c) 2017-2026 Juancarlo AƱez (apalala@gmail.com)
# SPDX-License-Identifier: BSD-4-Clause
"""
Unit tests for asjson utility.
# by Gemini (2026-01-26)
# by [apalala@gmail.com](https://github.com/apalala)
"""
from __future__ import annotations
import enum
import weakref
from typing import Any, NamedTuple
from tatsu.util.asjson import asjson
class Color(enum.Enum):
RED = 1
BLUE = "blue"
class Point(NamedTuple):
x: int
y: int
class CustomNode:
def __init__(self, name: str, child: Any = None):
self.name = name
self.child = child
def __json__(self, seen: set[int] | None = None) -> dict[str, Any]:
return {"name": self.name, "child": asjson(self.child, seen=seen)}
def test_primitives():
assert asjson(1) == 1
assert asjson("test") == "test"
assert asjson(True) is True
assert asjson(None) is None
def test_containers():
# Tuples and Sets must become lists
data = {"a": [1, 2], "b": (3, 4), "c": {5, 6}}
result = asjson(data)
assert result["a"] == [1, 2]
assert result["b"] == [3, 4]
assert isinstance(result["b"], list)
assert isinstance(result["c"], list)
assert sorted(result["c"]) == [5, 6]
def test_enum_handling():
assert asjson(Color.RED) == 1
assert asjson(Color.BLUE) == "blue"
def test_namedtuple_handling():
p = Point(10, 20)
assert asjson(p) == {"x": 10, "y": 20}
def test_weakref_proxy():
class Data:
pass
obj = Data()
proxy = weakref.proxy(obj)
result = asjson(proxy)
# Matches type(node).__name__ + hex ID
assert "proxytype@0x" in result.lower()
def test_circular_reference() -> None:
"""Tests that the 'seen' set catches infinite loops."""
node: dict[str, Any] = {}
node["loop"] = node
result = asjson(node)
assert "dict@" in result["loop"]
def test_custom_json_protocol_with_cycle():
"""Tests that __json__ correctly uses the shared 'seen' set."""
parent = CustomNode("parent")
child = CustomNode("child", child=parent)
parent.child = child
result = asjson(parent)
assert result["name"] == "parent"
assert result["child"]["name"] == "child"
assert "CustomNode@" in result["child"]["child"]
def test_mapping_key_conversion():
"""JSON keys must be strings."""
data = {123: "integer_key", (1, 2): "tuple_key"}
result = asjson(data)
assert result["123"] == "integer_key"
assert result["(1, 2)"] == "tuple_key"
|