# 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 format_tally, 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")) @pytest.mark.parametrize("kwargs", [{"sticker": True}, {"reaction": True}]) def test_stickers_and_reactions_do_not_count(kwargs: dict[str, bool]) -> None: assert not should_count(_message(**kwargs)) @pytest.mark.parametrize("text", [None, ""]) def test_empty_text_does_not_count(text: str | None) -> None: assert not should_count(_message(text=text)) def test_format_tally_pads_names() -> None: rendered = format_tally([("Alice", 5), ("Bo", 2)]) assert rendered == "Alice 5\nBo 2" def test_format_tally_when_nobody_spoke() -> None: assert format_tally([]) == "Brak wiadomosci dzisiaj."