# Copyright (c) 2026 Krzysztof Rudnicki. MIT licence. """Scoping and tally predicates.""" from __future__ import annotations from typing import TYPE_CHECKING import pytest from signal_bot.counting import media_kind, should_count, watched_group from signal_bot.models import parse_envelope from tests.conftest import OTHER_GROUP, SECOND_GROUP, WATCHED_GROUP, envelope if TYPE_CHECKING: from signal_bot.discovery import GroupDirectory def _message(**kwargs: object) -> object: parsed = parse_envelope(envelope(**kwargs)) assert parsed is not None return parsed @pytest.mark.parametrize("group", [WATCHED_GROUP, SECOND_GROUP]) async def test_every_watched_group_is_accepted_as_itself( directory: GroupDirectory, group: str ) -> None: """Each watched group resolves to itself, never to the first one listed.""" assert watched_group(_message(group_id=group), directory) == group async def test_other_group_is_rejected(directory: GroupDirectory) -> None: assert watched_group(_message(group_id=OTHER_GROUP), directory) is None async def test_direct_message_is_rejected(directory: GroupDirectory) -> None: """The dangerous case: a DM must never reach a handler.""" assert watched_group(_message(group_id=None), directory) is None def test_plain_text_counts() -> None: assert should_count(_message(text="hello")) def test_reactions_do_not_count() -> None: """A reaction annotates somebody else's message; it is not one.""" assert not should_count(_message(extra="reaction")) def test_a_sticker_is_a_message() -> None: assert should_count(_message(text=None, extra="sticker")) @pytest.mark.parametrize("text", [None, ""]) def test_empty_text_with_no_media_does_not_count(text: str | None) -> None: assert not should_count(_message(text=text)) @pytest.mark.parametrize("text", [None, ""]) def test_a_caption_less_photo_counts(text: str | None) -> None: """Until 0.1.0 this was worth zero, which is what the release fixes.""" assert should_count(_message(text=text, attachments=("image/jpeg",))) def test_the_bots_own_messages_never_count() -> None: """Taken from the sync branch, so it holds however the account is spelled.""" assert not should_count(_message(text="hello", sync=True)) @pytest.mark.parametrize( ("attachments", "expected"), [ ((), ""), (("image/jpeg",), "image"), (("image/jpeg", "image/png"), "image"), (("video/mp4",), "video"), (("audio/aac",), "audio"), (("application/pdf",), "file"), (("image/jpeg", "video/mp4"), "mixed"), ], ) def test_media_kind(attachments: tuple[str, ...], expected: str) -> None: assert media_kind(_message(attachments=attachments)) == expected def test_a_sticker_is_its_own_kind() -> None: assert media_kind(_message(text=None, extra="sticker")) == "sticker"