"""Tests for canonical JSON serialization and hashing."""
from abi_spec.canonical import canonical_hash, canonical_json, sha256_bytes


class TestCanonicalJson:
    def test_sorted_keys(self):
        assert canonical_json({"b": 1, "a": 2}) == '{"a":2,"b":1}'

    def test_nested_sorted_keys(self):
        obj = {"z": {"b": 1, "a": 2}, "a": 0}
        result = canonical_json(obj)
        assert result == '{"a":0,"z":{"a":2,"b":1}}'

    def test_compact_separators(self):
        result = canonical_json({"a": [1, 2, 3]})
        assert " " not in result
        assert result == '{"a":[1,2,3]}'

    def test_no_trailing_newline(self):
        result = canonical_json({"a": 1})
        assert not result.endswith("\n")

    def test_unicode_preserved(self):
        result = canonical_json({"name": "cafe\u0301"})
        assert "caf\u00e9" in result or "cafe\u0301" in result


class TestCanonicalHash:
    def test_deterministic(self):
        obj = {"hello": "world"}
        h1 = canonical_hash(obj)
        h2 = canonical_hash(obj)
        assert h1 == h2

    def test_hex_64_chars(self):
        h = canonical_hash({"a": 1})
        assert len(h) == 64
        assert all(c in "0123456789abcdef" for c in h)

    def test_different_objects_different_hash(self):
        h1 = canonical_hash({"a": 1})
        h2 = canonical_hash({"a": 2})
        assert h1 != h2

    def test_key_order_insensitive(self):
        h1 = canonical_hash({"a": 1, "b": 2})
        h2 = canonical_hash({"b": 2, "a": 1})
        assert h1 == h2


class TestSha256Bytes:
    def test_deterministic(self):
        data = b"hello world"
        h1 = sha256_bytes(data)
        h2 = sha256_bytes(data)
        assert h1 == h2

    def test_hex_64_chars(self):
        h = sha256_bytes(b"test")
        assert len(h) == 64
