11"""Tests for codebase tools."""
22
3- import subprocess
4-
53import pytest
64
75from codegen .extensions .tools import (
1715 replacement_edit ,
1816 reveal_symbol ,
1917 run_codemod ,
20- search ,
2118 semantic_edit ,
2219 semantic_search ,
2320 view_file ,
@@ -138,10 +135,12 @@ def test_view_file_pagination(large_codebase):
138135 result = view_file (large_codebase , "src/large_file.py" , start_line = 350 )
139136 assert result .status == "success"
140137 assert result .start_line == 350
141- assert result .has_more is True # File has 2010 lines, so there should be more content
138+ # File has 2010 lines, so there should be more content
139+ assert result .has_more is True
142140 assert "def method_69" in result .content # Regular method
143141 assert "def class_method_80" in result .content # Class method at 80
144- assert result .end_line == 599 # Should show 250 lines from start (350 to 599)
142+ # Should show 250 lines from start (350 to 599)
143+ assert result .end_line == 599
145144
146145 # Test custom max_lines
147146 result = view_file (large_codebase , "src/large_file.py" , max_lines = 100 )
@@ -189,7 +188,8 @@ def test_view_file_pagination_edge_cases(large_codebase):
189188 result = view_file (large_codebase , "src/large_file.py" , start_line = 200 , end_line = 2000 )
190189 assert result .status == "success"
191190 assert result .start_line == 200
192- assert result .end_line == min (200 + 250 - 1 , 2010 ) # Should respect max_lines and file length
191+ # Should respect max_lines and file length
192+ assert result .end_line == min (200 + 250 - 1 , 2010 )
193193
194194 # Test negative start_line (should default to 1)
195195 result = view_file (large_codebase , "src/large_file.py" , start_line = - 10 )
@@ -205,7 +205,8 @@ def test_list_directory(codebase):
205205 create_file (codebase , "src/core/models.py" , "" )
206206 create_file (codebase , "src/utils.py" , "" )
207207
208- result = list_directory (codebase , "./" , depth = 2 ) # Ensure we get nested structure
208+ # Ensure we get nested structure
209+ result = list_directory (codebase , "./" , depth = 2 )
209210 assert result .status == "success"
210211
211212 # Check directory structure
@@ -232,126 +233,6 @@ def test_list_directory(codebase):
232233 assert expected_tree in rendered .strip ()
233234
234235
235- def test_search (codebase ):
236- """Test searching the codebase."""
237- result = search (codebase , "hello" )
238- assert result .status == "success"
239- assert len (result .results ) > 0
240-
241- # Check that we found the right content
242- assert any ("hello" in match .match .lower () for file_result in result .results for match in file_result .matches )
243-
244- # Check pagination info
245- assert result .page == 1
246- assert result .total_pages >= 1
247- assert result .files_per_page == 10
248-
249-
250- def test_search_regex (codebase ):
251- """Test searching with regex."""
252- # Search for function definitions
253- result = search (codebase , r"def\s+\w+" , use_regex = True )
254- assert result .status == "success"
255- assert len (result .results ) > 0
256-
257- # Should find both 'def hello' and 'def greet'
258- matches = [match .line for file_result in result .results for match in file_result .matches ]
259- assert any ("def hello" in match for match in matches )
260- assert any ("def greet" in match for match in matches )
261-
262-
263- def test_search_pagination (codebase , tmpdir ):
264- """Test search pagination."""
265- # Create multiple files to test pagination
266- files_dict = {}
267- for i in range (15 ): # Create enough files to span multiple pages
268- content = f"def function_{ i } ():\n print('Hello from function { i } !')"
269- files_dict [f"src/file_{ i } .py" ] = content
270-
271- # Create a new codebase with all the files
272- with get_codebase_session (tmpdir = tmpdir , files = files_dict ) as pagination_codebase :
273- # Search with default pagination (page 1)
274- result_page1 = search (pagination_codebase , "Hello" , files_per_page = 5 )
275- assert result_page1 .status == "success"
276- assert result_page1 .page == 1
277- assert len (result_page1 .results ) <= 5
278-
279- # If we have enough results for multiple pages
280- if result_page1 .total_pages > 1 :
281- # Get page 2
282- result_page2 = search (pagination_codebase , "Hello" , page = 2 , files_per_page = 5 )
283- assert result_page2 .status == "success"
284- assert result_page2 .page == 2
285- assert len (result_page2 .results ) <= 5
286-
287- # Ensure different files on different pages
288- page1_files = {r .filepath for r in result_page1 .results }
289- page2_files = {r .filepath for r in result_page2 .results }
290- assert not page1_files .intersection (page2_files )
291-
292-
293- def test_search_fallback (codebase , monkeypatch ):
294- """Test fallback to Python implementation when ripgrep fails."""
295-
296- # Mock subprocess.run to simulate ripgrep failure
297- def mock_subprocess_run (* args , ** kwargs ):
298- msg = "Simulated ripgrep failure"
299- raise subprocess .SubprocessError (msg )
300-
301- # Apply the mock
302- monkeypatch .setattr (subprocess , "run" , mock_subprocess_run )
303-
304- # Search should still work using Python fallback
305- result = search (codebase , "hello" )
306- assert result .status == "success"
307- assert len (result .results ) > 0
308-
309-
310- def test_search_ripgrep_not_found (codebase , monkeypatch ):
311- """Test fallback to Python implementation when ripgrep is not installed."""
312-
313- # Mock subprocess.run to simulate ripgrep not found
314- def mock_subprocess_run (* args , ** kwargs ):
315- msg = "Simulated ripgrep not found"
316- raise FileNotFoundError (msg )
317-
318- # Apply the mock
319- monkeypatch .setattr (subprocess , "run" , mock_subprocess_run )
320-
321- # Search should still work using Python fallback
322- result = search (codebase , "hello" )
323- assert result .status == "success"
324- assert len (result .results ) > 0
325-
326-
327- def test_search_uses_ripgrep (codebase , monkeypatch ):
328- """Test that ripgrep is used when available."""
329- # Track if ripgrep was called
330- ripgrep_called = False
331-
332- # Store original subprocess.run
333- original_run = subprocess .run
334-
335- # Mock subprocess.run to track calls and then call the original
336- def mock_subprocess_run (* args , ** kwargs ):
337- nonlocal ripgrep_called
338- # Check if this is a ripgrep call
339- if args and args [0 ] and isinstance (args [0 ], list ) and args [0 ][0 ] == "rg" :
340- ripgrep_called = True
341- # Call the original implementation
342- return original_run (* args , ** kwargs )
343-
344- # Apply the mock
345- monkeypatch .setattr (subprocess , "run" , mock_subprocess_run )
346-
347- # Perform a search
348- result = search (codebase , "hello" )
349- assert result .status == "success"
350-
351- # Verify ripgrep was called
352- assert ripgrep_called , "Ripgrep was not used for the search"
353-
354-
355236def test_edit_file (codebase ):
356237 """Test editing a file."""
357238 result = edit_file (codebase , "src/main.py" , "print('edited')" )
0 commit comments