| 1 | import asyncio |
| 2 | from types import SimpleNamespace |
| 3 | |
| 4 | from plugins._telegram_integration.helpers import command_ui |
| 5 | from plugins._telegram_integration.helpers.constants import ( |
| 6 | CTX_TG_BOT, |
| 7 | CTX_TG_CHAT_ID, |
| 8 | CTX_TG_USER_ID, |
| 9 | CTX_TG_USERNAME, |
| 10 | ) |
| 11 | |
| 12 | |
| 13 | class FakeContext: |
| 14 | def __init__(self, id, name, last_message, *, running=False): |
| 15 | self.id = id |
| 16 | self.name = name |
| 17 | self.data = {} |
| 18 | self._last_message = last_message |
| 19 | self._running = running |
| 20 | |
| 21 | def output(self): |
| 22 | return {"last_message": self._last_message} |
| 23 | |
| 24 | def is_running(self): |
| 25 | return self._running |
| 26 | |
| 27 | |
| 28 | def test_session_picker_shows_four_recent_sessions(monkeypatch): |
| 29 | contexts = [ |
| 30 | FakeContext("ctx-1", "One", "2026-05-01T10:00:00"), |
| 31 | FakeContext("ctx-2", "Two", "2026-05-02T10:00:00"), |
| 32 | FakeContext("ctx-3", "Three", "2026-05-03T10:00:00"), |
| 33 | FakeContext("ctx-4", "Four", "2026-05-04T10:00:00"), |
| 34 | FakeContext("ctx-5", "Five", "2026-05-05T10:00:00"), |
| 35 | ] |
| 36 | current = contexts[4] |
| 37 | monkeypatch.setattr(command_ui, "AgentContext", SimpleNamespace(all=lambda: contexts)) |
| 38 | |
| 39 | text, markup = command_ui._session_view(current, 0) |
| 40 | |
| 41 | assert "Current session: <b>Five</b>" in text |
| 42 | assert "Showing 1-4 of 5." in text |
| 43 | rows = markup["inline_keyboard"] |
| 44 | assert [row[0]["text"] for row in rows[:4]] == ["• Five", "Four", "Three", "Two"] |
| 45 | assert rows[-1] == [{"text": "Next", "callback_data": "tg:session:page:1"}] |
| 46 | |
| 47 | |
| 48 | def test_select_session_remaps_telegram_chat(monkeypatch): |
| 49 | current = FakeContext("ctx-current", "Current", "2026-05-03T10:00:00") |
| 50 | target = FakeContext("ctx-target", "Target", "2026-05-04T10:00:00") |
| 51 | current.data.update( |
| 52 | { |
| 53 | CTX_TG_BOT: "main", |
| 54 | CTX_TG_CHAT_ID: 123, |
| 55 | CTX_TG_USER_ID: 456, |
| 56 | CTX_TG_USERNAME: "anmol", |
| 57 | } |
| 58 | ) |
| 59 | saved = [] |
| 60 | dirty = [] |
| 61 | state_out = {} |
| 62 | |
| 63 | monkeypatch.setattr(command_ui, "AgentContext", SimpleNamespace(all=lambda: [current, target])) |
| 64 | monkeypatch.setattr(command_ui, "save_tmp_chat", lambda context: saved.append(context.id)) |
| 65 | monkeypatch.setattr(command_ui, "mark_dirty_for_context", lambda context_id, *, reason=None: dirty.append((context_id, reason))) |
| 66 | monkeypatch.setattr(command_ui, "_load_telegram_state", lambda: {"chats": {}}) |
| 67 | monkeypatch.setattr(command_ui, "_save_telegram_state", lambda state: state_out.update(state)) |
| 68 | |
| 69 | selected = asyncio.run(command_ui._select_session(current, 0)) |
| 70 | |
| 71 | assert selected is target |
| 72 | assert target.data[CTX_TG_BOT] == "main" |
| 73 | assert target.data[CTX_TG_CHAT_ID] == 123 |
| 74 | assert target.data[CTX_TG_USER_ID] == 456 |
| 75 | assert target.data[CTX_TG_USERNAME] == "anmol" |
| 76 | assert state_out["chats"]["main:456:123"] == "ctx-target" |
| 77 | assert saved == ["ctx-target"] |
| 78 | assert ("ctx-target", "telegram.session_select") in dirty |