nanobot/tests/tools/test_message_tool.py
Xubin Ren b9b81d9301 test(telegram): pin inline-keyboards flag gate and buttons validation
Two kill-switch tests for the new inline-keyboards path. Neither is
flashy — they just make sure the next unrelated refactor can't quietly
regress two narrow contracts the PR relies on.

  1. TelegramChannel._build_keyboard returns None whenever
     TelegramConfig.inline_keyboards is False, even if buttons are
     supplied. The flag defaults off; if someone ever flips that default
     the change should fail this test before it reaches prod bots.

  2. MessageTool rejects malformed `buttons` payloads (non-list, mixed
     list/str row, non-str label, None label) up front instead of
     letting them slip into the channel layer where Telegram would
     silently 400 the send. Parametrized over four shapes the guard
     needs to reject.

No production code touched.

Made-with: Cursor
2026-04-23 13:26:06 +08:00

32 lines
977 B
Python

import pytest
from nanobot.agent.tools.message import MessageTool
@pytest.mark.asyncio
async def test_message_tool_returns_error_when_no_target_context() -> None:
tool = MessageTool()
result = await tool.execute(content="test")
assert result == "Error: No target channel/chat specified"
@pytest.mark.asyncio
@pytest.mark.parametrize(
"bad",
[
"not a list",
[["ok"], "row-not-a-list"],
[["ok", 42]],
[[None]],
],
)
async def test_message_tool_rejects_malformed_buttons(bad) -> None:
"""``buttons`` must be ``list[list[str]]``; the tool validates the shape
up front so a malformed LLM payload errors visibly instead of slipping
into the channel layer where Telegram would silently reject the frame."""
tool = MessageTool()
result = await tool.execute(
content="hi", channel="telegram", chat_id="1", buttons=bad,
)
assert result == "Error: buttons must be a list of list of strings"