toolplane-python-client 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- toolplane/__init__.py +106 -0
- toolplane/common/__init__.py +93 -0
- toolplane/common/base_config.py +129 -0
- toolplane/common/base_connection_manager.py +171 -0
- toolplane/common/base_session_manager.py +321 -0
- toolplane/common/base_tool_manager.py +347 -0
- toolplane/common/constants.py +47 -0
- toolplane/common/utils.py +310 -0
- toolplane/core/__init__.py +67 -0
- toolplane/core/config.py +107 -0
- toolplane/core/connection.py +285 -0
- toolplane/core/errors.py +298 -0
- toolplane/core/machine.py +480 -0
- toolplane/core/request.py +775 -0
- toolplane/core/session.py +332 -0
- toolplane/core/session_context.py +514 -0
- toolplane/core/task.py +130 -0
- toolplane/core/tool.py +329 -0
- toolplane/http_core/__init__.py +37 -0
- toolplane/http_core/http_config.py +97 -0
- toolplane/http_core/http_connection.py +409 -0
- toolplane/http_core/http_machine.py +298 -0
- toolplane/http_core/http_request.py +748 -0
- toolplane/http_core/http_session.py +348 -0
- toolplane/http_core/http_session_context.py +491 -0
- toolplane/http_core/http_task.py +101 -0
- toolplane/http_core/http_tool.py +400 -0
- toolplane/interfaces/__init__.py +27 -0
- toolplane/interfaces/client_interface.py +122 -0
- toolplane/interfaces/connection_interface.py +193 -0
- toolplane/interfaces/event_interface.py +290 -0
- toolplane/interfaces/request_interface.py +439 -0
- toolplane/interfaces/session_interface.py +288 -0
- toolplane/interfaces/tool_interface.py +441 -0
- toolplane/proto/__init__.py +0 -0
- toolplane/proto/service_pb2.py +315 -0
- toolplane/proto/service_pb2_grpc.py +2240 -0
- toolplane/provider_cli.py +268 -0
- toolplane/provider_registry.py +77 -0
- toolplane/provider_runtime.py +302 -0
- toolplane/toolkits/__init__.py +0 -0
- toolplane/toolkits/standalone_tools/__init__.py +0 -0
- toolplane/toolkits/standalone_tools/create_directory.py +94 -0
- toolplane/toolkits/standalone_tools/create_file.py +124 -0
- toolplane/toolkits/standalone_tools/file_search.py +229 -0
- toolplane/toolkits/standalone_tools/grep_search.py +372 -0
- toolplane/toolkits/standalone_tools/launcher.py +146 -0
- toolplane/toolkits/standalone_tools/list_dir.py +395 -0
- toolplane/toolkits/standalone_tools/read_file.py +346 -0
- toolplane/toolkits/standalone_tools/replace_string_in_file.py +407 -0
- toolplane/toolkits/standalone_tools/run_tests.py +66 -0
- toolplane/toolkits/standalone_tools/semantic_search.py +485 -0
- toolplane/toolkits/standalone_tools/standalone_toolkit.py +979 -0
- toolplane/toolkits/standalone_tools/test_failure_analysis.py +618 -0
- toolplane/toolkits/standalone_tools/test_standalone_toolkit.py +517 -0
- toolplane/toolkits/swe/__init__.py +35 -0
- toolplane/toolkits/swe/create_directory.py +15 -0
- toolplane/toolkits/swe/create_file.py +15 -0
- toolplane/toolkits/swe/descriptions.py +273 -0
- toolplane/toolkits/swe/execute_bash.py +93 -0
- toolplane/toolkits/swe/file_editor.py +775 -0
- toolplane/toolkits/swe/file_search.py +16 -0
- toolplane/toolkits/swe/finish.py +50 -0
- toolplane/toolkits/swe/grep_search.py +19 -0
- toolplane/toolkits/swe/list_dir.py +407 -0
- toolplane/toolkits/swe/read_file.py +18 -0
- toolplane/toolkits/swe/replace_string_in_file.py +17 -0
- toolplane/toolkits/swe/search.py +260 -0
- toolplane/toolkits/swe/semantic_search.py +20 -0
- toolplane/toolkits/swe/str_replace_editor.py +647 -0
- toolplane/toolkits/swe/submit.py +29 -0
- toolplane/toolkits/swe/swe_toolkit.py +1296 -0
- toolplane/toolplane_client.py +686 -0
- toolplane/toolplane_http_client.py +681 -0
- toolplane/utils/__init__.py +3 -0
- toolplane/utils/schema.py +146 -0
- toolplane_python_client-0.1.0.dist-info/METADATA +543 -0
- toolplane_python_client-0.1.0.dist-info/RECORD +81 -0
- toolplane_python_client-0.1.0.dist-info/WHEEL +5 -0
- toolplane_python_client-0.1.0.dist-info/entry_points.txt +2 -0
- toolplane_python_client-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,517 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Comprehensive test suite for standalone tools.
|
|
4
|
+
|
|
5
|
+
This test suite validates all standalone tools functionality including:
|
|
6
|
+
- Basic functionality tests
|
|
7
|
+
- Error handling
|
|
8
|
+
- Edge cases
|
|
9
|
+
- Output format validation
|
|
10
|
+
- Integration tests
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
import json
|
|
14
|
+
import os
|
|
15
|
+
import subprocess
|
|
16
|
+
import sys
|
|
17
|
+
import tempfile
|
|
18
|
+
from pathlib import Path
|
|
19
|
+
from typing import Any, Dict, List
|
|
20
|
+
|
|
21
|
+
import pytest
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class TestStandaloneTools:
|
|
25
|
+
"""Test suite for all standalone tools."""
|
|
26
|
+
|
|
27
|
+
@pytest.fixture(autouse=True)
|
|
28
|
+
def setup(self):
|
|
29
|
+
"""Set up test environment for each test."""
|
|
30
|
+
self.tools_dir = Path(__file__).parent
|
|
31
|
+
self.temp_dir = None
|
|
32
|
+
self.test_files = {}
|
|
33
|
+
|
|
34
|
+
def teardown_method(self):
|
|
35
|
+
"""Clean up after each test."""
|
|
36
|
+
if self.temp_dir and self.temp_dir.exists():
|
|
37
|
+
import shutil
|
|
38
|
+
|
|
39
|
+
shutil.rmtree(self.temp_dir, ignore_errors=True)
|
|
40
|
+
|
|
41
|
+
def create_temp_dir(self) -> Path:
|
|
42
|
+
"""Create a temporary directory for testing."""
|
|
43
|
+
if not self.temp_dir:
|
|
44
|
+
self.temp_dir = Path(tempfile.mkdtemp())
|
|
45
|
+
return self.temp_dir
|
|
46
|
+
|
|
47
|
+
def create_test_file(self, name: str, content: str) -> Path:
|
|
48
|
+
"""Create a test file with given content."""
|
|
49
|
+
temp_dir = self.create_temp_dir()
|
|
50
|
+
file_path = temp_dir / name
|
|
51
|
+
file_path.write_text(content, encoding="utf-8")
|
|
52
|
+
self.test_files[name] = file_path
|
|
53
|
+
return file_path
|
|
54
|
+
|
|
55
|
+
def run_tool(self, tool_name: str, args: List[str]) -> subprocess.CompletedProcess:
|
|
56
|
+
"""Run a standalone tool with given arguments."""
|
|
57
|
+
tool_path = self.tools_dir / tool_name
|
|
58
|
+
cmd = [sys.executable, str(tool_path)] + args
|
|
59
|
+
return subprocess.run(cmd, capture_output=True, text=True)
|
|
60
|
+
|
|
61
|
+
def test_create_directory_basic(self):
|
|
62
|
+
"""Test create_directory.py basic functionality."""
|
|
63
|
+
temp_dir = self.create_temp_dir()
|
|
64
|
+
test_dir = temp_dir / "test_directory"
|
|
65
|
+
|
|
66
|
+
result = self.run_tool("create_directory.py", [str(test_dir)])
|
|
67
|
+
|
|
68
|
+
assert result.returncode == 0
|
|
69
|
+
assert test_dir.exists()
|
|
70
|
+
assert test_dir.is_dir()
|
|
71
|
+
assert "Directory created successfully" in result.stdout
|
|
72
|
+
|
|
73
|
+
def test_create_directory_existing(self):
|
|
74
|
+
"""Test create_directory.py with existing directory."""
|
|
75
|
+
temp_dir = self.create_temp_dir()
|
|
76
|
+
test_dir = temp_dir / "existing_dir"
|
|
77
|
+
test_dir.mkdir()
|
|
78
|
+
|
|
79
|
+
result = self.run_tool("create_directory.py", [str(test_dir)])
|
|
80
|
+
|
|
81
|
+
assert result.returncode == 0
|
|
82
|
+
assert "Directory created successfully" in result.stdout
|
|
83
|
+
|
|
84
|
+
def test_create_directory_nested(self):
|
|
85
|
+
"""Test create_directory.py with nested directories."""
|
|
86
|
+
temp_dir = self.create_temp_dir()
|
|
87
|
+
test_dir = temp_dir / "level1" / "level2" / "level3"
|
|
88
|
+
|
|
89
|
+
result = self.run_tool("create_directory.py", [str(test_dir)])
|
|
90
|
+
|
|
91
|
+
assert result.returncode == 0
|
|
92
|
+
assert test_dir.exists()
|
|
93
|
+
assert test_dir.is_dir()
|
|
94
|
+
|
|
95
|
+
def test_create_file_basic(self):
|
|
96
|
+
"""Test create_file.py basic functionality."""
|
|
97
|
+
temp_dir = self.create_temp_dir()
|
|
98
|
+
test_file = temp_dir / "test.txt"
|
|
99
|
+
content = "Hello, World!"
|
|
100
|
+
|
|
101
|
+
result = self.run_tool("create_file.py", [str(test_file), content])
|
|
102
|
+
|
|
103
|
+
assert result.returncode == 0
|
|
104
|
+
assert test_file.exists()
|
|
105
|
+
assert test_file.read_text() == content
|
|
106
|
+
assert "File created successfully" in result.stdout
|
|
107
|
+
|
|
108
|
+
def test_create_file_with_dirs(self):
|
|
109
|
+
"""Test create_file.py with automatic directory creation."""
|
|
110
|
+
temp_dir = self.create_temp_dir()
|
|
111
|
+
test_file = temp_dir / "subdir" / "test.txt"
|
|
112
|
+
content = "Test content"
|
|
113
|
+
|
|
114
|
+
result = self.run_tool("create_file.py", [str(test_file), content])
|
|
115
|
+
|
|
116
|
+
assert result.returncode == 0
|
|
117
|
+
assert test_file.exists()
|
|
118
|
+
assert test_file.read_text() == content
|
|
119
|
+
|
|
120
|
+
def test_create_file_overwrite(self):
|
|
121
|
+
"""Test create_file.py overwrite functionality."""
|
|
122
|
+
temp_dir = self.create_temp_dir()
|
|
123
|
+
test_file = temp_dir / "test.txt"
|
|
124
|
+
test_file.write_text("Original content")
|
|
125
|
+
|
|
126
|
+
new_content = "New content"
|
|
127
|
+
result = self.run_tool(
|
|
128
|
+
"create_file.py", [str(test_file), new_content, "--overwrite"]
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
assert result.returncode == 0
|
|
132
|
+
assert test_file.read_text() == new_content
|
|
133
|
+
|
|
134
|
+
def test_file_search_basic(self):
|
|
135
|
+
"""Test file_search.py basic functionality."""
|
|
136
|
+
temp_dir = self.create_temp_dir()
|
|
137
|
+
|
|
138
|
+
# Create test files
|
|
139
|
+
(temp_dir / "test1.py").write_text("print('hello')")
|
|
140
|
+
(temp_dir / "test2.py").write_text("print('world')")
|
|
141
|
+
(temp_dir / "test.txt").write_text("text file")
|
|
142
|
+
|
|
143
|
+
result = self.run_tool("file_search.py", ["*.py", "--base_path", str(temp_dir)])
|
|
144
|
+
|
|
145
|
+
assert result.returncode == 0
|
|
146
|
+
assert "test1.py" in result.stdout
|
|
147
|
+
assert "test2.py" in result.stdout
|
|
148
|
+
assert "test.txt" not in result.stdout
|
|
149
|
+
|
|
150
|
+
def test_file_search_json_output(self):
|
|
151
|
+
"""Test file_search.py JSON output format."""
|
|
152
|
+
temp_dir = self.create_temp_dir()
|
|
153
|
+
(temp_dir / "test.py").write_text("test")
|
|
154
|
+
|
|
155
|
+
result = self.run_tool(
|
|
156
|
+
"file_search.py",
|
|
157
|
+
["*.py", "--base_path", str(temp_dir), "--output_format", "json"],
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
assert result.returncode == 0
|
|
161
|
+
data = json.loads(result.stdout)
|
|
162
|
+
assert isinstance(data, list)
|
|
163
|
+
assert len(data) > 0
|
|
164
|
+
assert "test.py" in data[0]["path"]
|
|
165
|
+
|
|
166
|
+
def test_file_search_max_results(self):
|
|
167
|
+
"""Test file_search.py max_results parameter."""
|
|
168
|
+
temp_dir = self.create_temp_dir()
|
|
169
|
+
|
|
170
|
+
# Create multiple test files
|
|
171
|
+
for i in range(5):
|
|
172
|
+
(temp_dir / f"test{i}.py").write_text(f"test {i}")
|
|
173
|
+
|
|
174
|
+
result = self.run_tool(
|
|
175
|
+
"file_search.py",
|
|
176
|
+
["*.py", "--base_path", str(temp_dir), "--max_results", "2"],
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
assert result.returncode == 0
|
|
180
|
+
# Should find exactly 2 files
|
|
181
|
+
lines = [
|
|
182
|
+
line
|
|
183
|
+
for line in result.stdout.split("\n")
|
|
184
|
+
if "test" in line and ".py" in line
|
|
185
|
+
]
|
|
186
|
+
assert len(lines) == 2
|
|
187
|
+
|
|
188
|
+
def test_grep_search_basic(self):
|
|
189
|
+
"""Test grep_search.py basic functionality."""
|
|
190
|
+
temp_dir = self.create_temp_dir()
|
|
191
|
+
test_file = temp_dir / "test.py"
|
|
192
|
+
test_file.write_text(
|
|
193
|
+
"def hello():\n print('Hello, World!')\n return 'hello'"
|
|
194
|
+
)
|
|
195
|
+
|
|
196
|
+
result = self.run_tool(
|
|
197
|
+
"grep_search.py", ["hello", "--base_path", str(temp_dir)]
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
assert result.returncode == 0
|
|
201
|
+
assert "def hello" in result.stdout
|
|
202
|
+
assert "return 'hello'" in result.stdout
|
|
203
|
+
|
|
204
|
+
def test_grep_search_regex(self):
|
|
205
|
+
"""Test grep_search.py regex functionality."""
|
|
206
|
+
temp_dir = self.create_temp_dir()
|
|
207
|
+
test_file = temp_dir / "test.py"
|
|
208
|
+
test_file.write_text("def function1():\n pass\ndef function2():\n pass")
|
|
209
|
+
|
|
210
|
+
result = self.run_tool(
|
|
211
|
+
"grep_search.py",
|
|
212
|
+
["def function\\d", "--is_regexp", "--base_path", str(temp_dir)],
|
|
213
|
+
)
|
|
214
|
+
|
|
215
|
+
assert result.returncode == 0
|
|
216
|
+
assert "function1" in result.stdout
|
|
217
|
+
assert "function2" in result.stdout
|
|
218
|
+
|
|
219
|
+
def test_grep_search_context(self):
|
|
220
|
+
"""Test grep_search.py context lines."""
|
|
221
|
+
temp_dir = self.create_temp_dir()
|
|
222
|
+
test_file = temp_dir / "test.py"
|
|
223
|
+
test_file.write_text("line1\nline2\ntarget_line\nline4\nline5")
|
|
224
|
+
|
|
225
|
+
result = self.run_tool(
|
|
226
|
+
"grep_search.py",
|
|
227
|
+
["target_line", "--context_lines", "1", "--base_path", str(temp_dir)],
|
|
228
|
+
)
|
|
229
|
+
|
|
230
|
+
assert result.returncode == 0
|
|
231
|
+
assert "line2" in result.stdout
|
|
232
|
+
assert "target_line" in result.stdout
|
|
233
|
+
assert "line4" in result.stdout
|
|
234
|
+
|
|
235
|
+
def test_grep_search_json_output(self):
|
|
236
|
+
"""Test grep_search.py JSON output format."""
|
|
237
|
+
temp_dir = self.create_temp_dir()
|
|
238
|
+
test_file = temp_dir / "test.py"
|
|
239
|
+
test_file.write_text("hello world")
|
|
240
|
+
|
|
241
|
+
result = self.run_tool(
|
|
242
|
+
"grep_search.py",
|
|
243
|
+
["hello", "--base_path", str(temp_dir), "--output_format", "json"],
|
|
244
|
+
)
|
|
245
|
+
|
|
246
|
+
assert result.returncode == 0
|
|
247
|
+
data = json.loads(result.stdout)
|
|
248
|
+
assert isinstance(data, list)
|
|
249
|
+
assert len(data) > 0
|
|
250
|
+
assert "matches" in data[0]
|
|
251
|
+
|
|
252
|
+
def test_list_dir_basic(self):
|
|
253
|
+
"""Test list_dir.py basic functionality."""
|
|
254
|
+
temp_dir = self.create_temp_dir()
|
|
255
|
+
|
|
256
|
+
# Create test files and directories
|
|
257
|
+
(temp_dir / "file1.txt").write_text("test")
|
|
258
|
+
(temp_dir / "file2.py").write_text("test")
|
|
259
|
+
(temp_dir / "subdir").mkdir()
|
|
260
|
+
|
|
261
|
+
result = self.run_tool("list_dir.py", [str(temp_dir)])
|
|
262
|
+
|
|
263
|
+
assert result.returncode == 0
|
|
264
|
+
assert "file1.txt" in result.stdout
|
|
265
|
+
assert "file2.py" in result.stdout
|
|
266
|
+
assert "subdir" in result.stdout
|
|
267
|
+
|
|
268
|
+
def test_list_dir_details(self):
|
|
269
|
+
"""Test list_dir.py with details."""
|
|
270
|
+
temp_dir = self.create_temp_dir()
|
|
271
|
+
(temp_dir / "test.txt").write_text("test content")
|
|
272
|
+
|
|
273
|
+
result = self.run_tool("list_dir.py", [str(temp_dir), "--show_details"])
|
|
274
|
+
|
|
275
|
+
assert result.returncode == 0
|
|
276
|
+
assert "test.txt" in result.stdout
|
|
277
|
+
# Since --show_details might not be fully implemented, just check basic functionality
|
|
278
|
+
|
|
279
|
+
def test_read_file_basic(self):
|
|
280
|
+
"""Test read_file.py basic functionality."""
|
|
281
|
+
content = "Line 1\nLine 2\nLine 3\nLine 4\nLine 5"
|
|
282
|
+
test_file = self.create_test_file("test.txt", content)
|
|
283
|
+
|
|
284
|
+
result = self.run_tool("read_file.py", [str(test_file), "2", "4"])
|
|
285
|
+
|
|
286
|
+
assert result.returncode == 0
|
|
287
|
+
assert "Line 2" in result.stdout
|
|
288
|
+
assert "Line 3" in result.stdout
|
|
289
|
+
assert "Line 4" in result.stdout
|
|
290
|
+
assert "Line 1" not in result.stdout
|
|
291
|
+
assert "Line 5" not in result.stdout
|
|
292
|
+
|
|
293
|
+
def test_read_file_all_lines(self):
|
|
294
|
+
"""Test read_file.py reading all lines."""
|
|
295
|
+
content = "Line 1\nLine 2\nLine 3"
|
|
296
|
+
test_file = self.create_test_file("test.txt", content)
|
|
297
|
+
|
|
298
|
+
result = self.run_tool("read_file.py", [str(test_file), "1", "-1"])
|
|
299
|
+
|
|
300
|
+
assert result.returncode == 0
|
|
301
|
+
assert "Line 1" in result.stdout
|
|
302
|
+
assert "Line 2" in result.stdout
|
|
303
|
+
assert "Line 3" in result.stdout
|
|
304
|
+
|
|
305
|
+
def test_read_file_json_output(self):
|
|
306
|
+
"""Test read_file.py JSON output format."""
|
|
307
|
+
content = "Line 1\nLine 2"
|
|
308
|
+
test_file = self.create_test_file("test.txt", content)
|
|
309
|
+
|
|
310
|
+
result = self.run_tool(
|
|
311
|
+
"read_file.py", [str(test_file), "1", "2", "--output_format", "json"]
|
|
312
|
+
)
|
|
313
|
+
|
|
314
|
+
assert result.returncode == 0
|
|
315
|
+
data = json.loads(result.stdout)
|
|
316
|
+
assert data["success"] is True
|
|
317
|
+
assert len(data["content"]) == 2
|
|
318
|
+
assert data["content"][0]["content"] == "Line 1"
|
|
319
|
+
|
|
320
|
+
def test_read_file_nonexistent(self):
|
|
321
|
+
"""Test read_file.py with nonexistent file."""
|
|
322
|
+
result = self.run_tool("read_file.py", ["/nonexistent/file.txt", "1", "5"])
|
|
323
|
+
|
|
324
|
+
assert result.returncode != 0 or "does not exist" in result.stdout
|
|
325
|
+
|
|
326
|
+
def test_replace_string_basic(self):
|
|
327
|
+
"""Test replace_string_in_file.py basic functionality."""
|
|
328
|
+
content = "Hello, World!\nGoodbye, World!"
|
|
329
|
+
test_file = self.create_test_file("test.txt", content)
|
|
330
|
+
|
|
331
|
+
result = self.run_tool(
|
|
332
|
+
"replace_string_in_file.py",
|
|
333
|
+
[str(test_file), "World", "Universe", "--no_backup"],
|
|
334
|
+
)
|
|
335
|
+
|
|
336
|
+
assert result.returncode == 0
|
|
337
|
+
new_content = test_file.read_text()
|
|
338
|
+
assert "Hello, Universe!" in new_content
|
|
339
|
+
assert "Goodbye, Universe!" in new_content
|
|
340
|
+
assert "World" not in new_content
|
|
341
|
+
|
|
342
|
+
def test_replace_string_dry_run(self):
|
|
343
|
+
"""Test replace_string_in_file.py dry run."""
|
|
344
|
+
content = "Hello, World!"
|
|
345
|
+
test_file = self.create_test_file("test.txt", content)
|
|
346
|
+
|
|
347
|
+
result = self.run_tool(
|
|
348
|
+
"replace_string_in_file.py",
|
|
349
|
+
[str(test_file), "World", "Universe", "--dry_run"],
|
|
350
|
+
)
|
|
351
|
+
|
|
352
|
+
assert result.returncode == 0
|
|
353
|
+
assert (
|
|
354
|
+
"would be replaced" in result.stdout.lower()
|
|
355
|
+
or "dry run" in result.stdout.lower()
|
|
356
|
+
)
|
|
357
|
+
# File should remain unchanged
|
|
358
|
+
assert test_file.read_text() == content
|
|
359
|
+
|
|
360
|
+
def test_replace_string_backup(self):
|
|
361
|
+
"""Test replace_string_in_file.py backup creation."""
|
|
362
|
+
content = "Hello, World!"
|
|
363
|
+
test_file = self.create_test_file("test.txt", content)
|
|
364
|
+
|
|
365
|
+
result = self.run_tool(
|
|
366
|
+
"replace_string_in_file.py", [str(test_file), "World", "Universe"]
|
|
367
|
+
)
|
|
368
|
+
|
|
369
|
+
assert result.returncode == 0
|
|
370
|
+
# Check if backup was created (should have backup in name)
|
|
371
|
+
backup_files = list(test_file.parent.glob(f"*backup*"))
|
|
372
|
+
assert len(backup_files) > 0
|
|
373
|
+
|
|
374
|
+
def test_semantic_search_basic(self):
|
|
375
|
+
"""Test semantic_search.py basic functionality."""
|
|
376
|
+
temp_dir = self.create_temp_dir()
|
|
377
|
+
|
|
378
|
+
# Create test files with different content
|
|
379
|
+
(temp_dir / "auth.py").write_text(
|
|
380
|
+
"def authenticate_user(username, password):\n return True"
|
|
381
|
+
)
|
|
382
|
+
(temp_dir / "math.py").write_text("def calculate_sum(a, b):\n return a + b")
|
|
383
|
+
|
|
384
|
+
result = self.run_tool(
|
|
385
|
+
"semantic_search.py",
|
|
386
|
+
[
|
|
387
|
+
"authentication function",
|
|
388
|
+
"--search_path",
|
|
389
|
+
str(temp_dir),
|
|
390
|
+
"--max_results",
|
|
391
|
+
"5",
|
|
392
|
+
],
|
|
393
|
+
)
|
|
394
|
+
|
|
395
|
+
assert result.returncode == 0
|
|
396
|
+
# Should find the authentication-related content
|
|
397
|
+
assert (
|
|
398
|
+
"auth" in result.stdout.lower() or "authenticate" in result.stdout.lower()
|
|
399
|
+
)
|
|
400
|
+
|
|
401
|
+
def test_semantic_search_file_types(self):
|
|
402
|
+
"""Test semantic_search.py file type filtering."""
|
|
403
|
+
temp_dir = self.create_temp_dir()
|
|
404
|
+
|
|
405
|
+
(temp_dir / "test.py").write_text("python code")
|
|
406
|
+
(temp_dir / "test.txt").write_text("text file")
|
|
407
|
+
|
|
408
|
+
result = self.run_tool(
|
|
409
|
+
"semantic_search.py",
|
|
410
|
+
["code", "--search_path", str(temp_dir), "--file_types", ".py"],
|
|
411
|
+
)
|
|
412
|
+
|
|
413
|
+
assert result.returncode == 0
|
|
414
|
+
# Should only search Python files
|
|
415
|
+
|
|
416
|
+
def test_test_failure_analysis_basic(self):
|
|
417
|
+
"""Test test_failure_analysis.py basic functionality."""
|
|
418
|
+
# Create a mock test output
|
|
419
|
+
test_output = """
|
|
420
|
+
FAILED test_example.py::test_function - AssertionError: Expected 5, got 3
|
|
421
|
+
FAILED test_another.py::test_method - ValueError: Invalid input
|
|
422
|
+
"""
|
|
423
|
+
|
|
424
|
+
result = self.run_tool(
|
|
425
|
+
"test_failure_analysis.py", ["--test_output", test_output]
|
|
426
|
+
)
|
|
427
|
+
|
|
428
|
+
assert result.returncode == 0
|
|
429
|
+
assert "AssertionError" in result.stdout or "ValueError" in result.stdout
|
|
430
|
+
|
|
431
|
+
def test_launcher_list(self):
|
|
432
|
+
"""Test launcher.py list functionality."""
|
|
433
|
+
result = self.run_tool("launcher.py", ["list"])
|
|
434
|
+
|
|
435
|
+
assert result.returncode == 0
|
|
436
|
+
assert "create_directory.py" in result.stdout
|
|
437
|
+
assert "create_file.py" in result.stdout
|
|
438
|
+
assert "grep_search.py" in result.stdout
|
|
439
|
+
|
|
440
|
+
def test_launcher_search(self):
|
|
441
|
+
"""Test launcher.py search functionality."""
|
|
442
|
+
result = self.run_tool("launcher.py", ["search", "file"])
|
|
443
|
+
|
|
444
|
+
assert result.returncode == 0
|
|
445
|
+
assert "file_search.py" in result.stdout or "read_file.py" in result.stdout
|
|
446
|
+
|
|
447
|
+
def test_launcher_run_help(self):
|
|
448
|
+
"""Test launcher.py run functionality with help."""
|
|
449
|
+
result = self.run_tool("launcher.py", ["run", "create_directory.py", "--help"])
|
|
450
|
+
|
|
451
|
+
assert result.returncode == 0
|
|
452
|
+
assert "usage:" in result.stdout.lower()
|
|
453
|
+
|
|
454
|
+
def test_all_tools_help(self):
|
|
455
|
+
"""Test that all tools provide help information."""
|
|
456
|
+
tools = [
|
|
457
|
+
"create_directory.py",
|
|
458
|
+
"create_file.py",
|
|
459
|
+
"file_search.py",
|
|
460
|
+
"grep_search.py",
|
|
461
|
+
"list_dir.py",
|
|
462
|
+
"read_file.py",
|
|
463
|
+
"replace_string_in_file.py",
|
|
464
|
+
"semantic_search.py",
|
|
465
|
+
"test_failure_analysis.py",
|
|
466
|
+
"launcher.py",
|
|
467
|
+
]
|
|
468
|
+
|
|
469
|
+
for tool in tools:
|
|
470
|
+
result = self.run_tool(tool, ["--help"])
|
|
471
|
+
assert result.returncode == 0, f"Tool {tool} failed help test"
|
|
472
|
+
assert "usage:" in result.stdout.lower(), f"Tool {tool} doesn't show usage"
|
|
473
|
+
|
|
474
|
+
def test_error_handling(self):
|
|
475
|
+
"""Test error handling for various tools."""
|
|
476
|
+
# Test create_directory with invalid path (if applicable)
|
|
477
|
+
result = self.run_tool("create_directory.py", ["/invalid:/path"])
|
|
478
|
+
# Should handle gracefully (either succeed or fail with proper message)
|
|
479
|
+
|
|
480
|
+
# Test read_file with invalid line numbers
|
|
481
|
+
temp_file = self.create_test_file("small.txt", "line1\nline2")
|
|
482
|
+
result = self.run_tool("read_file.py", [str(temp_file), "10", "20"])
|
|
483
|
+
# Tool handles this gracefully by adjusting range to available lines
|
|
484
|
+
assert result.returncode == 0
|
|
485
|
+
|
|
486
|
+
def test_json_output_validity(self):
|
|
487
|
+
"""Test that all tools produce valid JSON when requested."""
|
|
488
|
+
temp_dir = self.create_temp_dir()
|
|
489
|
+
(temp_dir / "test.py").write_text("test content")
|
|
490
|
+
|
|
491
|
+
tools_with_json = [
|
|
492
|
+
(
|
|
493
|
+
"file_search.py",
|
|
494
|
+
["*.py", "--base_path", str(temp_dir), "--output_format", "json"],
|
|
495
|
+
),
|
|
496
|
+
(
|
|
497
|
+
"grep_search.py",
|
|
498
|
+
["test", "--base_path", str(temp_dir), "--output_format", "json"],
|
|
499
|
+
),
|
|
500
|
+
(
|
|
501
|
+
"read_file.py",
|
|
502
|
+
[str(temp_dir / "test.py"), "1", "1", "--output_format", "json"],
|
|
503
|
+
),
|
|
504
|
+
]
|
|
505
|
+
|
|
506
|
+
for tool, args in tools_with_json:
|
|
507
|
+
result = self.run_tool(tool, args)
|
|
508
|
+
if result.returncode == 0:
|
|
509
|
+
try:
|
|
510
|
+
json.loads(result.stdout)
|
|
511
|
+
except json.JSONDecodeError:
|
|
512
|
+
pytest.fail(f"Tool {tool} produced invalid JSON: {result.stdout}")
|
|
513
|
+
|
|
514
|
+
|
|
515
|
+
if __name__ == "__main__":
|
|
516
|
+
# Run tests directly
|
|
517
|
+
pytest.main([__file__, "-v"])
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
from .swe_toolkit import (
|
|
2
|
+
SWE_TOOL_SELECTION_GUIDE,
|
|
3
|
+
BashInput,
|
|
4
|
+
BashTool,
|
|
5
|
+
FileEditorInput,
|
|
6
|
+
FileEditorTool,
|
|
7
|
+
FinishInput,
|
|
8
|
+
FinishTool,
|
|
9
|
+
SearchDirInput,
|
|
10
|
+
SearchDirTool,
|
|
11
|
+
SearchInput,
|
|
12
|
+
SearchTool,
|
|
13
|
+
SubmitTool,
|
|
14
|
+
get_file_editor_only,
|
|
15
|
+
get_search_tools_only,
|
|
16
|
+
get_swe_toolkit,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
__all__ = [
|
|
20
|
+
"FileEditorInput",
|
|
21
|
+
"SearchInput",
|
|
22
|
+
"SearchDirInput",
|
|
23
|
+
"BashInput",
|
|
24
|
+
"FinishInput",
|
|
25
|
+
"FileEditorTool",
|
|
26
|
+
"SearchTool",
|
|
27
|
+
"SearchDirTool",
|
|
28
|
+
"BashTool",
|
|
29
|
+
"FinishTool",
|
|
30
|
+
"SubmitTool",
|
|
31
|
+
"get_swe_toolkit",
|
|
32
|
+
"get_file_editor_only",
|
|
33
|
+
"get_search_tools_only",
|
|
34
|
+
"SWE_TOOL_SELECTION_GUIDE",
|
|
35
|
+
]
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"""Re-exported from toolplane.toolkits.standalone_tools — the single
|
|
2
|
+
maintained copy of this tool. The SWE toolkit composes these safe
|
|
3
|
+
file tools with its own unsafe ones (execute_bash, file_editor).
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from toolplane.toolkits.standalone_tools.create_directory import ( # noqa: F401
|
|
7
|
+
create_directory,
|
|
8
|
+
main,
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
if __name__ == "__main__":
|
|
12
|
+
main()
|
|
13
|
+
|
|
14
|
+
if __name__ == "__main__":
|
|
15
|
+
main()
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"""Re-exported from toolplane.toolkits.standalone_tools — the single
|
|
2
|
+
maintained copy of this tool. The SWE toolkit composes these safe
|
|
3
|
+
file tools with its own unsafe ones (execute_bash, file_editor).
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from toolplane.toolkits.standalone_tools.create_file import ( # noqa: F401
|
|
7
|
+
create_file,
|
|
8
|
+
main,
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
if __name__ == "__main__":
|
|
12
|
+
main()
|
|
13
|
+
|
|
14
|
+
if __name__ == "__main__":
|
|
15
|
+
main()
|