# Copyright (c) 2026 Krzysztof Rudnicki. MIT licence. """Describing a frame's shape without logging what anybody wrote.""" from __future__ import annotations import json from signal_bot.envelope_shape import shape_of from tests.conftest import WATCHED_GROUP, envelope PRIVATE_BODY = "the actual message body" def test_values_are_replaced_by_their_types() -> None: """The whole point: a log line that cannot leak a message.""" shape = shape_of(envelope(text=PRIVATE_BODY)) assert PRIVATE_BODY not in shape assert "message: str" in shape def test_names_numbers_and_uuids_do_not_survive() -> None: shape = shape_of(envelope(text="hi", sender=("ffcae71a-dcd1", "kuhy"))) assert "ffcae71a" not in shape assert "kuhy" not in shape assert "+15555550123" not in shape def test_quoted_text_does_not_survive() -> None: shape = shape_of(envelope(text="hi", extra="quote")) assert "..." not in shape assert "quote: {author: str, id: int, text: str}" in shape def test_the_group_id_is_a_type_but_its_kind_is_a_value() -> None: """DELIVER vs UPDATE is wire format; the id identifies a conversation.""" shape = shape_of(envelope(text="hi")) assert WATCHED_GROUP not in shape assert "groupId: str" in shape assert "type: 'DELIVER'" in shape def test_attachment_content_types_are_kept() -> None: """The one thing this exists to answer, so it must survive redaction.""" shape = shape_of(envelope(text=None, attachments=("image/jpeg", "video/mp4"))) assert "contentType: 'image/jpeg'" in shape assert "x2]" in shape def test_an_album_is_summarised_not_repeated() -> None: shape = shape_of(envelope(text=None, attachments=("image/jpeg",) * 20)) assert "x20]" in shape assert shape.count("contentType") == 1 def test_an_empty_list_is_shown_as_empty() -> None: assert shape_of(json.dumps({"envelope": {"members": []}})) == "{envelope: {members: []}}" def test_null_is_distinguished_from_absent() -> None: """A caption-less photo may send message: null rather than omitting it.""" assert "message: null" in shape_of(json.dumps({"envelope": {"message": None}})) def test_numbers_and_booleans_show_their_type() -> None: frame = json.dumps({"envelope": {"timestamp": 1, "urgent": True, "score": 1.5}}) assert shape_of(frame) == "{envelope: {score: float, timestamp: int, urgent: bool}}" def test_an_unparseable_frame_says_so() -> None: assert shape_of("not json") == "" assert shape_of(b"\xff\xfe") == "" def test_keys_are_sorted_so_two_frames_compare() -> None: """Same shape, different key order, identical description.""" first = json.dumps({"envelope": {"b": 1, "a": "x"}}) second = json.dumps({"envelope": {"a": "x", "b": 1}}) assert shape_of(first) == shape_of(second)