import pytest

from amcs.canonical_json import CanonicalJSONError, canonical_bytes, canonical_dumps


def test_canonical_dumps_sorts_keys_and_is_stable() -> None:
    obj_a = {"b": 1, "a": 2, "nested": {"z": 3, "x": 4}}
    obj_b = {"nested": {"x": 4, "z": 3}, "a": 2, "b": 1}

    rendered_a = canonical_dumps(obj_a)
    rendered_b = canonical_dumps(obj_b)

    assert rendered_a == rendered_b
    assert rendered_a == '{"a":2,"b":1,"nested":{"x":4,"z":3}}'


def test_canonical_dumps_has_no_whitespace_and_preserves_array_order() -> None:
    obj = {"items": [3, 1, 2]}

    rendered = canonical_dumps(obj)

    assert rendered == '{"items":[3,1,2]}'
    assert " " not in rendered
    assert "\n" not in rendered


def test_canonical_bytes_are_utf8() -> None:
    obj = {"greeting": "naive cafe \u2615"}

    rendered_text = canonical_dumps(obj)
    rendered_bytes = canonical_bytes(obj)

    assert rendered_bytes == rendered_text.encode("utf-8")


def test_canonical_dumps_rejects_floats() -> None:
    with pytest.raises(CanonicalJSONError):
        canonical_dumps({"value": 0.1})

    with pytest.raises(CanonicalJSONError):
        canonical_dumps({"nested": {"value": 0.1}})

    with pytest.raises(CanonicalJSONError):
        canonical_dumps([1, 2, 0.5])
