feat(tg): forum-first adapter complete — handlers, bot.py, 46 tests pass
This commit is contained in:
parent
82dc840544
commit
24c61468d7
9 changed files with 675 additions and 0 deletions
76
tests/adapter/telegram/test_commands.py
Normal file
76
tests/adapter/telegram/test_commands.py
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import importlib
|
||||
from types import SimpleNamespace
|
||||
from unittest.mock import AsyncMock, MagicMock
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def fresh_db(tmp_path, monkeypatch):
|
||||
monkeypatch.setenv("DB_PATH", str(tmp_path / "test.db"))
|
||||
import adapter.telegram.db as db_mod
|
||||
importlib.reload(db_mod)
|
||||
db_mod.init_db()
|
||||
return db_mod
|
||||
|
||||
|
||||
def make_message(*, user_id=1, thread_id=42, chat_id=100, text="/new"):
|
||||
m = SimpleNamespace()
|
||||
m.from_user = SimpleNamespace(id=user_id, full_name="Alice")
|
||||
m.message_thread_id = thread_id
|
||||
m.chat = SimpleNamespace(id=chat_id)
|
||||
m.text = text
|
||||
m.answer = AsyncMock()
|
||||
m.reply = AsyncMock()
|
||||
m.bot = MagicMock()
|
||||
m.bot.create_forum_topic = AsyncMock(
|
||||
return_value=SimpleNamespace(message_thread_id=200)
|
||||
)
|
||||
m.bot.close_forum_topic = AsyncMock()
|
||||
m.bot.edit_forum_topic = AsyncMock()
|
||||
m.bot.send_message = AsyncMock()
|
||||
return m
|
||||
|
||||
|
||||
async def test_cmd_new_creates_topic(fresh_db, monkeypatch):
|
||||
import adapter.telegram.handlers.commands as mod
|
||||
importlib.reload(mod)
|
||||
fresh_db.create_chat(1, 42, "Чат #1")
|
||||
msg = make_message(user_id=1, thread_id=42, chat_id=100)
|
||||
await mod.cmd_new(msg)
|
||||
msg.bot.create_forum_topic.assert_called_once()
|
||||
call_kwargs = str(msg.bot.create_forum_topic.call_args)
|
||||
assert "Чат #2" in call_kwargs
|
||||
assert fresh_db.get_chat(1, 200) is not None
|
||||
|
||||
|
||||
async def test_cmd_archive_closes_and_archives(fresh_db, monkeypatch):
|
||||
import adapter.telegram.handlers.commands as mod
|
||||
importlib.reload(mod)
|
||||
fresh_db.create_chat(1, 42, "Чат #1")
|
||||
msg = make_message(user_id=1, thread_id=42, chat_id=100)
|
||||
await mod.cmd_archive(msg)
|
||||
msg.bot.close_forum_topic.assert_called_once_with(chat_id=100, message_thread_id=42)
|
||||
assert fresh_db.get_chat(1, 42)["archived_at"] is not None
|
||||
|
||||
|
||||
async def test_cmd_archive_unknown_topic_replies_error(fresh_db, monkeypatch):
|
||||
import adapter.telegram.handlers.commands as mod
|
||||
importlib.reload(mod)
|
||||
msg = make_message(user_id=1, thread_id=999, chat_id=100)
|
||||
await mod.cmd_archive(msg)
|
||||
msg.answer.assert_called_once()
|
||||
|
||||
|
||||
async def test_cmd_rename_updates_db_and_topic(fresh_db, monkeypatch):
|
||||
import adapter.telegram.handlers.commands as mod
|
||||
importlib.reload(mod)
|
||||
fresh_db.create_chat(1, 42, "Чат #1")
|
||||
msg = make_message(user_id=1, thread_id=42, chat_id=100, text="/rename Работа")
|
||||
await mod.cmd_rename(msg)
|
||||
msg.bot.edit_forum_topic.assert_called_once_with(
|
||||
chat_id=100, message_thread_id=42, name="Работа"
|
||||
)
|
||||
assert fresh_db.get_chat(1, 42)["chat_name"] == "Работа"
|
||||
70
tests/adapter/telegram/test_topic_events.py
Normal file
70
tests/adapter/telegram/test_topic_events.py
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import importlib
|
||||
from types import SimpleNamespace
|
||||
from unittest.mock import AsyncMock
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def fresh_db(tmp_path, monkeypatch):
|
||||
monkeypatch.setenv("DB_PATH", str(tmp_path / "test.db"))
|
||||
import adapter.telegram.db as db_mod
|
||||
importlib.reload(db_mod)
|
||||
db_mod.init_db()
|
||||
return db_mod
|
||||
|
||||
|
||||
def make_service_message(*, user_id=1, thread_id=42, topic_name="Мой чат"):
|
||||
m = SimpleNamespace()
|
||||
m.message_thread_id = thread_id
|
||||
m.from_user = SimpleNamespace(id=user_id, full_name="Alice")
|
||||
m.chat = SimpleNamespace(id=user_id)
|
||||
m.forum_topic_created = SimpleNamespace(name=topic_name)
|
||||
m.forum_topic_edited = SimpleNamespace(name="Новое имя")
|
||||
m.forum_topic_closed = SimpleNamespace()
|
||||
m.answer = AsyncMock()
|
||||
return m
|
||||
|
||||
|
||||
async def test_on_topic_created_registers_chat(fresh_db, monkeypatch):
|
||||
import adapter.telegram.handlers.topic_events as mod
|
||||
importlib.reload(mod)
|
||||
msg = make_service_message(user_id=5, thread_id=99, topic_name="Мой чат")
|
||||
await mod.on_topic_created(msg)
|
||||
chat = fresh_db.get_chat(5, 99)
|
||||
assert chat is not None
|
||||
assert chat["chat_name"] == "Мой чат"
|
||||
|
||||
|
||||
async def test_on_topic_edited_renames_chat(fresh_db, monkeypatch):
|
||||
import adapter.telegram.handlers.topic_events as mod
|
||||
importlib.reload(mod)
|
||||
fresh_db.create_chat(5, 99, "Старое имя")
|
||||
msg = make_service_message(user_id=5, thread_id=99)
|
||||
await mod.on_topic_edited(msg)
|
||||
assert fresh_db.get_chat(5, 99)["chat_name"] == "Новое имя"
|
||||
|
||||
|
||||
async def test_on_topic_edited_unknown_chat_is_noop(fresh_db):
|
||||
import adapter.telegram.handlers.topic_events as mod
|
||||
importlib.reload(mod)
|
||||
msg = make_service_message(user_id=5, thread_id=999)
|
||||
await mod.on_topic_edited(msg) # should not raise
|
||||
|
||||
|
||||
async def test_on_topic_closed_archives_chat(fresh_db):
|
||||
import adapter.telegram.handlers.topic_events as mod
|
||||
importlib.reload(mod)
|
||||
fresh_db.create_chat(5, 99, "Чат #1")
|
||||
msg = make_service_message(user_id=5, thread_id=99)
|
||||
await mod.on_topic_closed(msg)
|
||||
assert fresh_db.get_chat(5, 99)["archived_at"] is not None
|
||||
|
||||
|
||||
async def test_on_topic_closed_unknown_chat_is_noop(fresh_db):
|
||||
import adapter.telegram.handlers.topic_events as mod
|
||||
importlib.reload(mod)
|
||||
msg = make_service_message(user_id=5, thread_id=999)
|
||||
await mod.on_topic_closed(msg) # should not raise
|
||||
Loading…
Add table
Add a link
Reference in a new issue