"""Slack 슬래시 커맨드 파싱 테스트.""" from __future__ import annotations from collections.abc import Callable from lazy_enter.config import Config class FakeClient: def __init__(self) -> None: self.messages: list[dict[str, str | None]] = [] def chat_postMessage( # noqa: N802 self, channel: str, text: str, thread_ts: str | None = None ) -> None: self.messages.append( { "channel": channel, "text": text, "thread_ts": thread_ts, } ) class FakeApp: def __init__(self, token: str) -> None: self.token = token self.client = FakeClient() self.command_handlers: dict[str, Callable[..., None]] = {} self.event_handlers: dict[str, Callable[..., None]] = {} def event(self, name: str) -> Callable[[Callable[..., None]], Callable[..., None]]: def decorator(func: Callable[..., None]) -> Callable[..., None]: self.event_handlers[name] = func return func return decorator def command( self, name: str ) -> Callable[[Callable[..., None]], Callable[..., None]]: def decorator(func: Callable[..., None]) -> Callable[..., None]: self.command_handlers[name] = func return func return decorator class FakeSocketModeHandler: def __init__(self, app: FakeApp, app_token: str) -> None: self.app = app self.app_token = app_token def start(self) -> None: return None def close(self) -> None: return None def _build_handler(monkeypatch): from lazy_enter import slack_handler as slack_handler_module monkeypatch.setattr(slack_handler_module, "App", FakeApp) monkeypatch.setattr( slack_handler_module, "SocketModeHandler", FakeSocketModeHandler ) config = Config() config.allowed_user_id = "U1" config.allowed_channel_id = "C1" return slack_handler_module.SlackHandler(config) def _capture_commands(handler) -> list[tuple[str, str, str]]: called: list[tuple[str, str, str]] = [] def callback(action: str, target: str, channel: str) -> None: called.append((action, target, channel)) handler.on_command(callback) return called def test_start_command_routes_target_from_text(monkeypatch) -> None: handler = _build_handler(monkeypatch) called = _capture_commands(handler) acked: list[bool] = [] start_handler = handler.app.command_handlers["/start"] start_handler( lambda: acked.append(True), {"user_id": "U1", "channel_id": "C1", "text": "codex"}, ) assert acked == [True] assert called == [("start", "codex", "C1")] def test_start_command_normalizes_target(monkeypatch) -> None: handler = _build_handler(monkeypatch) called = _capture_commands(handler) start_handler = handler.app.command_handlers["/start"] start_handler( lambda: None, {"user_id": "U1", "channel_id": "C1", "text": " Claude now "}, ) assert called == [("start", "claude", "C1")] def test_stop_command_ignores_target_text(monkeypatch) -> None: handler = _build_handler(monkeypatch) called = _capture_commands(handler) stop_handler = handler.app.command_handlers["/stop"] stop_handler( lambda: None, {"user_id": "U1", "channel_id": "C1", "text": "claude"}, ) assert called == [("stop", "", "C1")] def test_stop_command_without_target_routes_immediately(monkeypatch) -> None: handler = _build_handler(monkeypatch) called = _capture_commands(handler) stop_handler = handler.app.command_handlers["/stop"] stop_handler( lambda: None, {"user_id": "U1", "channel_id": "C1", "text": ""}, ) assert called == [("stop", "", "C1")] assert handler.app.client.messages == [] def test_invalid_target_sends_warning_message(monkeypatch) -> None: handler = _build_handler(monkeypatch) called = _capture_commands(handler) start_handler = handler.app.command_handlers["/start"] start_handler( lambda: None, {"user_id": "U1", "channel_id": "C1", "text": "gpt"}, ) assert called == [] assert handler.app.client.messages[-1]["channel"] == "C1" assert "claude" in str(handler.app.client.messages[-1]["text"]) assert "codex" in str(handler.app.client.messages[-1]["text"]) def test_unauthorized_command_is_ignored(monkeypatch) -> None: handler = _build_handler(monkeypatch) called = _capture_commands(handler) start_handler = handler.app.command_handlers["/start"] start_handler( lambda: None, {"user_id": "U2", "channel_id": "C1", "text": "codex"}, ) assert called == [] assert handler.app.client.messages == []