| from unittest.mock import MagicMock |
|
|
| import pytest |
|
|
| from api.command_utils import extract_filepaths_from_command |
| from api.detection import ( |
| is_filepath_extraction_request, |
| is_suggestion_mode_request, |
| ) |
| from api.models.anthropic import Message, MessagesRequest |
|
|
|
|
| def _mk_req(messages, tools=None, system=None): |
| req = MagicMock(spec=MessagesRequest) |
| req.messages = messages |
| req.tools = tools |
| req.system = system |
| return req |
|
|
|
|
| def _mk_msg(role: str, content): |
| msg = MagicMock(spec=Message) |
| msg.role = role |
| msg.content = content |
| return msg |
|
|
|
|
| class TestSuggestionMode: |
| def test_detects_suggestion_mode_in_any_user_message(self): |
| req = _mk_req( |
| [ |
| _mk_msg("assistant", "ignore"), |
| _mk_msg("user", "Hello\n[SUGGESTION MODE: on]\nworld"), |
| ] |
| ) |
| assert is_suggestion_mode_request(req) is True |
|
|
| def test_suggestion_mode_ignores_non_user_messages(self): |
| req = _mk_req([_mk_msg("assistant", "[SUGGESTION MODE: on]")]) |
| assert is_suggestion_mode_request(req) is False |
|
|
|
|
| class TestFilepathExtractionDetection: |
| def test_rejects_when_tools_present(self): |
| msg = _mk_msg( |
| "user", |
| "Command: cat foo.txt\nOutput: hi\n\nPlease extract <filepaths>.", |
| ) |
| req = _mk_req([msg], tools=[{"name": "search"}]) |
| ok, cmd, out = is_filepath_extraction_request(req) |
| assert (ok, cmd, out) == (False, "", "") |
|
|
| def test_rejects_when_missing_output_marker(self): |
| msg = _mk_msg( |
| "user", |
| "Command: cat foo.txt\n(no output marker)\n<filepaths>", |
| ) |
| req = _mk_req([msg], tools=None) |
| ok, cmd, out = is_filepath_extraction_request(req) |
| assert (ok, cmd, out) == (False, "", "") |
|
|
| def test_rejects_when_not_asking_for_filepaths(self): |
| msg = _mk_msg("user", "Command: cat foo.txt\nOutput: hi") |
| req = _mk_req([msg], tools=None) |
| ok, cmd, out = is_filepath_extraction_request(req) |
| assert (ok, cmd, out) == (False, "", "") |
|
|
| def test_detects_filepath_extraction_via_system_block(self): |
| """Command: + Output: in user, no filepaths in user; system has extract instructions.""" |
| msg = _mk_msg("user", "Command: ls\nOutput: avazu-ctr\nfree-claude-code") |
| req = _mk_req( |
| [msg], |
| tools=None, |
| system="Extract any file paths that this command reads or modifies.", |
| ) |
| ok, cmd, out = is_filepath_extraction_request(req) |
| assert ok is True |
| assert cmd == "ls" |
| assert "avazu-ctr" in out |
| assert "free-claude-code" in out |
|
|
| def test_extracts_command_and_output_and_cleans_output(self): |
| msg = _mk_msg( |
| "user", |
| "Command: cat foo.txt\n" |
| "Output: line1\nline2\n\n" |
| "Please extract <filepaths>.\n" |
| "<next_section>ignore me</next_section>", |
| ) |
| req = _mk_req([msg], tools=None) |
| ok, cmd, out = is_filepath_extraction_request(req) |
| assert ok is True |
| assert cmd == "cat foo.txt" |
| assert out == "line1\nline2" |
|
|
|
|
| class TestExtractFilepathsFromCommand: |
| @pytest.mark.parametrize( |
| "command,expected_paths", |
| [ |
| ("ls -la", []), |
| ("dir .", []), |
| ("cat foo.txt", ["foo.txt"]), |
| ("cat -n foo.txt bar.md", ["foo.txt", "bar.md"]), |
| ("type C:\\tmp\\a.txt", ["C:\\tmp\\a.txt"]), |
| ("grep pattern file1.txt file2.txt", ["file1.txt", "file2.txt"]), |
| ("grep -n pattern file.txt", ["file.txt"]), |
| ("grep -e pattern file.txt", ["file.txt"]), |
| ("unknowncmd arg1 arg2", []), |
| ("", []), |
| ], |
| ids=[ |
| "listing_ls", |
| "listing_dir", |
| "read_cat", |
| "read_cat_flags", |
| "read_type_windows_path", |
| "grep_simple", |
| "grep_with_flag", |
| "grep_with_e", |
| "unknown", |
| "empty", |
| ], |
| ) |
| def test_extracts_expected_paths(self, command, expected_paths): |
| result = extract_filepaths_from_command(command, output="(ignored)") |
| for p in expected_paths: |
| assert p in result |
| if not expected_paths: |
| assert result.strip() == "<filepaths>\n</filepaths>" |
|
|