"""Canonical encoding: the byte layer every other guarantee depends on.""" from fablepool.canonical import canonical_encode, sha256_hex def test_returns_bytes(): assert isinstance(canonical_encode({}), (bytes, bytearray)) def test_empty_containers(): assert bytes(canonical_encode({})) == b"{}" assert bytes(canonical_encode([])) == b"[]" def test_key_order_independence(): a = canonical_encode({"a": 1, "b": 2, "c": [1, 2]}) b = canonical_encode({"c": [1, 2], "b": 2, "a": 1}) assert bytes(a) == bytes(b) def test_keys_sorted_in_output(): assert bytes(canonical_encode({"b": 2, "a": 1})) == b'{"a":1,"b":2}' def test_keys_sorted_by_code_point(): # "Z" (0x5A) sorts before "a" (0x61): byte order, not locale order. assert bytes(canonical_encode({"a": 1, "Z": 2})) == b'{"Z":2,"a":1}' def test_nested_objects_sorted(): out = bytes(canonical_encode({"outer": {"b": [3, 2, 1], "a": "x"}})) assert out == b'{"outer":{"a":"x","b":[3,2,1]}}' def test_array_order_preserved(): out = bytes(canonical_encode(["b", "a", 2, 1])) assert out == b'["b","a",2,1]' def test_no_insignificant_whitespace(): out = bytes(canonical_encode({"a": [1, 2], "b": {"c": 3}})) assert b" " not in out assert b"\n" not in out def test_unicode_emitted_raw_not_escaped(): out = bytes(canonical_encode({"k": "é"})) assert out == '{"k":"é"}'.encode("utf-8") assert b"\\u" not in out def test_deterministic_across_calls(): value = {"z": None, "a": True, "nested": {"k": ["v", 1]}} assert bytes(canonical_encode(value)) == bytes(canonical_encode(value)) def test_sha256_known_vectors(): # FIPS 180-4 reference digests. assert ( sha256_hex(b"") == "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" ) assert ( sha256_hex(b"abc") == "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad" )