from __future__ import annotations from uuid import UUID import pytest from app.contracts import TextCheck from app.fingerprint import canonical_json, fingerprint from app.normalization import normalize_text def test_jcs_field_order_and_unicode_are_deterministic() -> None: left = {"z": None, "а": "е\u0301", "a": 1} right = {"a": 1, "z": None, "а": "е\u0301"} assert canonical_json(left) == canonical_json(right) assert fingerprint(left) == fingerprint(right) assert canonical_json(left).decode() == '{"a":1,"z":null,"а":"е́"}' def test_dto_fingerprint_contains_explicit_null() -> None: dto = TextCheck( message_id=UUID("00000000-0000-4000-8000-000000000001"), content_kind="text", text="hello", attachment=None, ) assert b'"attachment":null' in canonical_json(dto) assert len(fingerprint(dto)) == 32 def test_normalization_nfkc_whitespace_and_flags() -> None: result = normalize_text("A\r\nB\u200b\u202e C") assert result.display.startswith("A\nB") assert result.analysis == "A\nB C" assert result.flags == ("bidi_control", "default_ignorable", "zero_width") def test_normalization_hard_limit() -> None: with pytest.raises(ValueError): normalize_text("x" * 10_001)