"""Message-ID and subject normalization (SPEC §7.1, §7.3).""" from __future__ import annotations from app.threading_.normalize import ( is_synthetic, normalize_message_id, normalize_reference_list, normalize_subject, synthesize_message_id, ) def test_normalize_message_id_strips_brackets_and_lowercases_domain() -> None: assert normalize_message_id("") == "Abc.123@example.com" assert normalize_message_id(" ") == "x@y.z" # local part case is preserved, domain lowercased assert normalize_message_id("") == "CaseSensitive@domain.com" def test_normalize_message_id_rejects_invalid() -> None: assert normalize_message_id(None) is None assert normalize_message_id("no-at-sign") is None assert normalize_message_id("<>") is None assert normalize_message_id("@nolocal.com") is None def test_normalize_reference_list_order_and_dedupe() -> None: raw = " " assert normalize_reference_list(raw) == ["a@x.com", "b@y.com"] assert normalize_reference_list("") == [] assert normalize_reference_list(None) == [] def test_normalize_reference_list_whitespace_separated_without_brackets() -> None: assert normalize_reference_list("a@x.com b@y.com") == ["a@x.com", "b@y.com"] def test_synthetic_id() -> None: sid = synthesize_message_id(b"raw bytes here") assert sid.endswith("@synthetic.local") assert is_synthetic(sid) assert not is_synthetic("real@example.com") assert not is_synthetic(None) # deterministic assert synthesize_message_id(b"raw bytes here") == sid def test_normalize_subject_strips_prefixes() -> None: assert normalize_subject("Re: Hello") == "Hello" assert normalize_subject("RE: FW: Fwd: Hello world") == "Hello world" assert normalize_subject("Odp: Cześć") == "Cześć" # Polish reply prefix assert normalize_subject("PD: X") == "X" assert normalize_subject("No prefix") == "No prefix" assert normalize_subject("") == ""