# Copyright (c) 2026 Krzysztof Rudnicki. MIT licence. """Trigger resolution.""" from __future__ import annotations from typing import TYPE_CHECKING import pytest from signal_bot.models import parse_envelope from signal_bot.registry import CommandContext, CommandRegistry, DuplicateTriggerError from signal_bot.transport_fake import FakeTransport from tests.conftest import WATCHED_GROUP, envelope if TYPE_CHECKING: from signal_bot.config import Config from signal_bot.store import Store async def _noop(ctx: CommandContext) -> None: return None def test_resolves_a_registered_trigger() -> None: registry = CommandRegistry() registry.register("cat", ["!cat", "!kot"], _noop) assert registry.resolve("!kot") is not None assert registry.resolve("!cat").name == "cat" def test_resolution_is_case_insensitive_and_trims() -> None: registry = CommandRegistry() registry.register("cat", ["!cat"], _noop) assert registry.resolve(" !CAT ") is not None def test_unknown_and_prefixless_text_resolves_to_nothing() -> None: registry = CommandRegistry() registry.register("cat", ["!cat"], _noop) assert registry.resolve("!nope") is None assert registry.resolve("cat") is None @pytest.mark.parametrize("text", [None, ""]) def test_empty_text_resolves_to_nothing(text: str | None) -> None: assert CommandRegistry().resolve(text) is None def test_duplicate_trigger_is_rejected() -> None: registry = CommandRegistry() registry.register("cat", ["!cat"], _noop) with pytest.raises(DuplicateTriggerError, match="!cat"): registry.register("feline", ["!cat"], _noop) def test_commands_lists_in_registration_order() -> None: registry = CommandRegistry() registry.register("cat", ["!cat"], _noop) registry.register("dog", ["!dog"], _noop) assert [c.name for c in registry.commands] == ["cat", "dog"] def _ctx(transport: FakeTransport, store: Store, config: Config) -> CommandContext: message = parse_envelope(envelope(text="!papiez")) assert message is not None return CommandContext( message=message, group_id=WATCHED_GROUP, transport=transport, store=store, config=config, command_name="pope", now=100.0, day="2026-08-30", ) async def test_reply_image_defaults_to_no_caption(store: Store, config: Config) -> None: transport = FakeTransport() await _ctx(transport, store, config).reply_image("Zm9v") assert transport.sent[0].caption == "" async def test_reply_image_passes_the_caption_through(store: Store, config: Config) -> None: """The caption rides in the same payload, so Signal shows one message.""" transport = FakeTransport() await _ctx(transport, store, config).reply_image("Zm9v", "8. Telesfor") sent = transport.sent[0] assert sent.caption == "8. Telesfor" assert sent.image_base64 == "Zm9v" assert sent.quote is not None