98 lines
3.4 KiB
Python
98 lines
3.4 KiB
Python
"""Discord gateway bot: the message-handling logic that decides when to reply and
|
|
with what. No live gateway — we feed MESSAGE_CREATE payloads straight to the pure
|
|
handler and stub the shared /grade lookup so these stay data-independent."""
|
|
import pytest
|
|
|
|
from notifications import discord
|
|
from notifications import discord_bot as bot
|
|
from notifications import discord_interactions as di
|
|
|
|
BOT_ID = "999"
|
|
|
|
|
|
@pytest.fixture(autouse=True)
|
|
def _stub_grade(monkeypatch):
|
|
"""Reply payload for /grade, mirroring the real shape (embeds + an ephemeral
|
|
flag the gateway path must drop)."""
|
|
monkeypatch.setattr(
|
|
di, "_grade_message",
|
|
lambda query: {"embeds": [{"title": f"grade:{query}"}], "flags": 64})
|
|
|
|
|
|
def _msg(content="", *, author_id="1", bot_author=False, mentions=(), guild=True):
|
|
m = {
|
|
"content": content,
|
|
"id": "42",
|
|
"channel_id": "77",
|
|
"author": {"id": author_id, "bot": bot_author},
|
|
"mentions": [{"id": mid} for mid in mentions],
|
|
}
|
|
if guild:
|
|
m["guild_id"] = "5"
|
|
return m
|
|
|
|
|
|
# --- when the bot stays silent ----------------------------------------------
|
|
|
|
def test_ignores_other_bots():
|
|
assert bot._response_for_message(
|
|
_msg("<@999> Phoenix", author_id="8", bot_author=True, mentions=[BOT_ID]), BOT_ID) is None
|
|
|
|
|
|
def test_ignores_its_own_messages():
|
|
assert bot._response_for_message(
|
|
_msg("hello", author_id=BOT_ID, mentions=[BOT_ID]), BOT_ID) is None
|
|
|
|
|
|
def test_ignores_guild_message_without_a_mention():
|
|
assert bot._response_for_message(_msg("just chatting", mentions=[]), BOT_ID) is None
|
|
|
|
|
|
# --- when the bot replies ----------------------------------------------------
|
|
|
|
def test_mention_with_city_returns_grade_without_ephemeral_flag():
|
|
out = bot._response_for_message(_msg("<@999> Phoenix", mentions=[BOT_ID]), BOT_ID)
|
|
assert out == {"embeds": [{"title": "grade:Phoenix"}]} # flags dropped
|
|
assert "flags" not in out
|
|
|
|
|
|
def test_legacy_nickname_mention_is_stripped():
|
|
out = bot._response_for_message(_msg("<@!999> Tokyo", mentions=[BOT_ID]), BOT_ID)
|
|
assert out["embeds"][0]["title"] == "grade:Tokyo"
|
|
|
|
|
|
def test_dm_needs_no_mention():
|
|
out = bot._response_for_message(_msg("Berlin", guild=False, mentions=[]), BOT_ID)
|
|
assert out["embeds"][0]["title"] == "grade:Berlin"
|
|
|
|
|
|
def test_mention_with_no_query_gives_help():
|
|
out = bot._response_for_message(_msg("<@999>", mentions=[BOT_ID]), BOT_ID)
|
|
assert "content" in out and "mention me" in out["content"].lower()
|
|
|
|
|
|
# --- helpers -----------------------------------------------------------------
|
|
|
|
def test_strip_mentions_handles_both_forms():
|
|
assert bot._strip_mentions("<@999> <@!999> Sao Paulo", BOT_ID) == "Sao Paulo"
|
|
|
|
|
|
def test_is_dm_is_true_without_guild_id():
|
|
assert bot._is_dm(_msg("x", guild=False)) is True
|
|
assert bot._is_dm(_msg("x", guild=True)) is False
|
|
|
|
|
|
# --- enabled() gating --------------------------------------------------------
|
|
|
|
def test_enabled_is_off_by_default(monkeypatch):
|
|
monkeypatch.delenv("THERMOGRAPH_DISCORD_BOT", raising=False)
|
|
monkeypatch.setattr(discord, "BOT_TOKEN", "a-token")
|
|
assert bot.enabled() is False
|
|
|
|
|
|
def test_enabled_needs_both_flag_and_token(monkeypatch):
|
|
monkeypatch.setenv("THERMOGRAPH_DISCORD_BOT", "1")
|
|
monkeypatch.setattr(discord, "BOT_TOKEN", "")
|
|
assert bot.enabled() is False
|
|
monkeypatch.setattr(discord, "BOT_TOKEN", "a-token")
|
|
assert bot.enabled() is True
|