"""Tests for CLI multi-word message handling (issue #26). This module tests that the chat and route commands properly handle multi-word messages without requiring quotes. """ from unittest.mock import MagicMock, patch from typer.testing import CliRunner from timmy.cli import _CLI_SESSION_ID, app runner = CliRunner() # ----------------------------------------------------------------------------- # chat command — multi-word message handling # ----------------------------------------------------------------------------- def test_chat_joins_multiple_args(): """chat command must join multiple arguments into a single message.""" mock_run_output = MagicMock() mock_run_output.content = "Hello! I am doing well." mock_run_output.status = "COMPLETED" mock_run_output.active_requirements = [] mock_timmy = MagicMock() mock_timmy.run.return_value = mock_run_output with patch("timmy.cli.create_timmy", return_value=mock_timmy): result = runner.invoke(app, ["chat", "hello", "how", "are", "you"]) # Verify the message was joined with spaces mock_timmy.run.assert_called_once_with( "hello how are you", stream=False, session_id=_CLI_SESSION_ID ) assert result.exit_code == 0 assert "Hello! I am doing well." in result.output def test_chat_single_word_still_works(): """chat command must still work with a single word argument.""" mock_run_output = MagicMock() mock_run_output.content = "Hello!" mock_run_output.status = "COMPLETED" mock_run_output.active_requirements = [] mock_timmy = MagicMock() mock_timmy.run.return_value = mock_run_output with patch("timmy.cli.create_timmy", return_value=mock_timmy): result = runner.invoke(app, ["chat", "hello"]) mock_timmy.run.assert_called_once_with("hello", stream=False, session_id=_CLI_SESSION_ID) assert result.exit_code == 0 assert "Hello!" in result.output def test_chat_joins_complex_message(): """chat command must handle complex multi-word messages with punctuation.""" mock_run_output = MagicMock() mock_run_output.content = "The file is located at /path/to/file." mock_run_output.status = "COMPLETED" mock_run_output.active_requirements = [] mock_timmy = MagicMock() mock_timmy.run.return_value = mock_run_output with patch("timmy.cli.create_timmy", return_value=mock_timmy): result = runner.invoke( app, ["chat", "what", "is", "the", "path", "to", "the", "config", "file?"], ) mock_timmy.run.assert_called_once_with( "what is the path to the config file?", stream=False, session_id=_CLI_SESSION_ID ) assert result.exit_code == 0 # ----------------------------------------------------------------------------- # route command — multi-word message handling # ----------------------------------------------------------------------------- def test_route_joins_multiple_args(): """route command must join multiple arguments into a single message.""" with patch("timmy.agents.loader.route_request_with_match") as mock_route: mock_route.return_value = ("orchestrator", None) result = runner.invoke(app, ["route", "hello", "how", "are", "you"]) # Verify the message was joined with spaces mock_route.assert_called_once_with("hello how are you") assert result.exit_code == 0 assert "orchestrator" in result.output def test_route_single_word_still_works(): """route command must still work with a single word argument.""" with patch("timmy.agents.loader.route_request_with_match") as mock_route: mock_route.return_value = ("spark", "test pattern") result = runner.invoke(app, ["route", "test"]) mock_route.assert_called_once_with("test") assert result.exit_code == 0 assert "spark" in result.output def test_route_shows_match_info(): """route command must display matched pattern when there is a match.""" with patch("timmy.agents.loader.route_request_with_match") as mock_route: mock_route.return_value = ("agent_1", "pattern:hello") result = runner.invoke(app, ["route", "hello", "world"]) mock_route.assert_called_once_with("hello world") assert result.exit_code == 0 assert "agent_1" in result.output assert "pattern:hello" in result.output def test_route_no_match(): """route command must show orchestrator when no pattern matches.""" with patch("timmy.agents.loader.route_request_with_match") as mock_route: mock_route.return_value = (None, None) result = runner.invoke(app, ["route", "unknown", "command", "here"]) mock_route.assert_called_once_with("unknown command here") assert result.exit_code == 0 assert "orchestrator (no pattern match)" in result.output