import types import pytest from huesoporro.bot import SaveMessagesCog class DummyDB: def __init__(self, *args, **kwargs): pass class FakeChannel: def __init__(self): self.sent: list[str] = [] async def send(self, content: str): self.sent.append(content) class FakeAuthor: def __init__(self, name: str): self.name = name class FakeMessage: def __init__(self, content: str | None, author_name: str = "alice"): self.content = content self.author = FakeAuthor(author_name) self.channel = FakeChannel() class FakeBot: def __init__(self, nick: str = "Junie", channel: str = "testchan"): self.nick = nick self.channel = channel @pytest.fixture(autouse=True) def patch_markov_and_svcs(monkeypatch): monkeypatch.setattr("huesoporro.bot.MarkovDatabase", DummyDB) class _DummyStoreSvc: def __init__(self, db): self.db = db async def run(self, content: str | None): return None class _DummyGenSvc: def __init__(self, db): self.db = db async def run(self, seed: str): return None monkeypatch.setattr("huesoporro.bot.SentenceStorerSvc", _DummyStoreSvc) monkeypatch.setattr("huesoporro.bot.SentenceGeneratorSvc", _DummyGenSvc) @pytest.fixture def cog(monkeypatch) -> SaveMessagesCog: bot = FakeBot() return SaveMessagesCog(bot) # type: ignore[arg-type] def make_async_fn(result=None, exc: Exception | None = None): async def _fn(*args, **kwargs): if exc: raise exc return result return _fn @pytest.mark.asyncio async def test_handle_bot_mention_returns_none_on_empty_content(cog: SaveMessagesCog): msg = FakeMessage(content=None) res = await cog._handle_bot_mention(msg) # type: ignore[attr-defined] assert res is None assert msg.channel.sent == [] @pytest.mark.asyncio async def test_handle_bot_mention_returns_none_when_no_mention(cog: SaveMessagesCog): msg = FakeMessage(content="hello world") res = await cog._handle_bot_mention(msg) # type: ignore[attr-defined] assert res is None assert msg.channel.sent == [] @pytest.mark.asyncio async def test_handle_bot_mention_returns_none_when_only_mention( cog: SaveMessagesCog, monkeypatch ): msg = FakeMessage(content=cog.bot.nick) # type: ignore[attr-defined] res = await cog._handle_bot_mention(msg) # type: ignore[attr-defined] assert res is None assert msg.channel.sent == [] @pytest.mark.asyncio async def test_handle_bot_mention_generates_and_sends_reply( cog: SaveMessagesCog, monkeypatch ): msg = FakeMessage(content="juNie hello there") monkeypatch.setattr( cog, "generate_svc", types.SimpleNamespace(run=make_async_fn("foo bar")) ) res = await cog._handle_bot_mention(msg) # type: ignore[attr-defined] assert res == "foo bar" assert len(msg.channel.sent) == 1 assert msg.channel.sent[0].startswith(f"@{msg.author.name} ") assert msg.channel.sent[0].endswith("foo bar") @pytest.mark.asyncio async def test_handle_bot_mention_no_send_when_generator_returns_none( cog: SaveMessagesCog, monkeypatch ): msg = FakeMessage(content=f"{cog.bot.nick} hello") # type: ignore[attr-defined] monkeypatch.setattr( cog, "generate_svc", types.SimpleNamespace(run=make_async_fn(None)) ) res = await cog._handle_bot_mention(msg) # type: ignore[attr-defined] assert res is None assert msg.channel.sent == [] @pytest.mark.asyncio async def test_handle_bot_mention_swallows_exceptions_and_returns_none( cog: SaveMessagesCog, monkeypatch ): msg = FakeMessage(content=f"{cog.bot.nick} hello") # type: ignore[attr-defined] monkeypatch.setattr( cog, "generate_svc", types.SimpleNamespace(run=make_async_fn(exc=RuntimeError("boom"))), ) res = await cog._handle_bot_mention(msg) # type: ignore[attr-defined] assert res is None assert msg.channel.sent == []