From 81127ec451dd221c8f6f7f265925e68a7a86920f Mon Sep 17 00:00:00 2001 From: codegen-bot Date: Thu, 13 Mar 2025 02:01:49 +0000 Subject: [PATCH 1/2] Add integration tests for tools --- .../integration/extension/test_reflection.py | 59 ++++ .../integration/extension/test_relace_edit.py | 151 +++++++++ tests/integration/extension/test_slack.py | 98 ++++++ .../extension/test_workspace_tools.py | 292 ++++++++++++++++++ 4 files changed, 600 insertions(+) create mode 100644 tests/integration/extension/test_reflection.py create mode 100644 tests/integration/extension/test_relace_edit.py create mode 100644 tests/integration/extension/test_slack.py create mode 100644 tests/integration/extension/test_workspace_tools.py diff --git a/tests/integration/extension/test_reflection.py b/tests/integration/extension/test_reflection.py new file mode 100644 index 000000000..87e158a09 --- /dev/null +++ b/tests/integration/extension/test_reflection.py @@ -0,0 +1,59 @@ +"""Integration tests for the reflection tool.""" + +import pytest +from unittest.mock import MagicMock + +from codegen.extensions.tools.reflection import perform_reflection +from codegen.sdk.core.codebase import Codebase + + +@pytest.fixture +def mock_codebase(): + """Create a mock codebase for testing.""" + return MagicMock(spec=Codebase) + + +def test_perform_reflection(mock_codebase): + """Test the reflection tool.""" + # Test with basic inputs + result = perform_reflection( + context_summary="Testing the reflection tool", + findings_so_far="Found some interesting patterns", + current_challenges="Need to improve test coverage", + reflection_focus=None, + codebase=mock_codebase, + ) + + # Verify the result structure + assert result.status == "success" + assert "reflection" in result.content + assert "Testing the reflection tool" in result.content + assert "Found some interesting patterns" in result.content + assert "Need to improve test coverage" in result.content + + # Test with a specific reflection focus + result = perform_reflection( + context_summary="Testing the reflection tool", + findings_so_far="Found some interesting patterns", + current_challenges="Need to improve test coverage", + reflection_focus="architecture", + codebase=mock_codebase, + ) + + # Verify the result includes the focus + assert result.status == "success" + assert "reflection" in result.content + assert "architecture" in result.content + + # Test with minimal inputs + result = perform_reflection( + context_summary="Minimal test", + findings_so_far="Minimal findings", + codebase=mock_codebase, + ) + + # Verify the result with minimal inputs + assert result.status == "success" + assert "reflection" in result.content + assert "Minimal test" in result.content + assert "Minimal findings" in result.content \ No newline at end of file diff --git a/tests/integration/extension/test_relace_edit.py b/tests/integration/extension/test_relace_edit.py new file mode 100644 index 000000000..6c10f4bea --- /dev/null +++ b/tests/integration/extension/test_relace_edit.py @@ -0,0 +1,151 @@ +"""Integration tests for the relace_edit tool.""" + +import os +import tempfile +from pathlib import Path + +import pytest +from unittest.mock import MagicMock, patch + +from codegen.extensions.tools.relace_edit import relace_edit +from codegen.sdk.core.codebase import Codebase + + +@pytest.fixture +def temp_workspace(): + """Create a temporary workspace for testing.""" + with tempfile.TemporaryDirectory() as temp_dir: + # Create a simple file structure for testing + base_dir = Path(temp_dir) + + # Create a simple Python file + test_file = base_dir / "test_file.py" + test_file.write_text(""" +def hello_world(): + return 'Hello, World!' + +def goodbye_world(): + return 'Goodbye, World!' +""") + + # Create a JavaScript file + js_file = base_dir / "test_file.js" + js_file.write_text(""" +function helloWorld() { + return 'Hello, World!'; +} + +function goodbyeWorld() { + return 'Goodbye, World!'; +} +""") + + # Create a codebase from the temp directory + codebase = Codebase.from_directory(str(base_dir)) + + yield codebase + + +@pytest.mark.skipif(not os.getenv("RELACE_API"), reason="RELACE_API environment variable not set") +def test_relace_edit_real_api(temp_workspace): + """Test relace_edit with the real API. + + This test is skipped if the RELACE_API environment variable is not set. + """ + # Test editing a Python file + edit_snippet = """ +# Keep existing imports + +# Modify hello_world function +def hello_world(): + print("Starting greeting") + return 'Hello, Modified World!' + +# Keep goodbye_world function +""" + + result = relace_edit(temp_workspace, "test_file.py", edit_snippet) + assert result.status == "success" + + # Verify the file was modified correctly + from codegen.extensions.tools import view_file + file_content = view_file(temp_workspace, "test_file.py") + assert "print(\"Starting greeting\")" in file_content.content + assert "Hello, Modified World!" in file_content.content + assert "Goodbye, World!" in file_content.content # Should be preserved + + +@patch("codegen.extensions.tools.relace_edit.requests.post") +def test_relace_edit_mock_api(mock_post, temp_workspace): + """Test relace_edit with a mocked API.""" + # Mock the API response + mock_response = MagicMock() + mock_response.status_code = 200 + mock_response.json.return_value = { + "status": "success", + "result": """ +def hello_world(): + print("Mocked greeting") + return 'Hello, Mocked World!' + +def goodbye_world(): + return 'Goodbye, World!' +""" + } + mock_post.return_value = mock_response + + # Test editing a Python file + edit_snippet = """ +# Modify hello_world function +def hello_world(): + print("Mocked greeting") + return 'Hello, Mocked World!' + +# Keep goodbye_world function +""" + + result = relace_edit(temp_workspace, "test_file.py", edit_snippet) + assert result.status == "success" + + # Verify the API was called with the correct parameters + mock_post.assert_called_once() + args, kwargs = mock_post.call_args + assert "content" in kwargs["json"] + assert "edit_snippet" in kwargs["json"] + + # Verify the file was modified correctly + from codegen.extensions.tools import view_file + file_content = view_file(temp_workspace, "test_file.py") + assert "print(\"Mocked greeting\")" in file_content.content + assert "Hello, Mocked World!" in file_content.content + + +@patch("codegen.extensions.tools.relace_edit.requests.post") +def test_relace_edit_api_error(mock_post, temp_workspace): + """Test relace_edit with API errors.""" + # Mock an API error response + mock_response = MagicMock() + mock_response.status_code = 400 + mock_response.json.return_value = { + "status": "error", + "error": "Invalid request" + } + mock_post.return_value = mock_response + + # Test with API error + result = relace_edit(temp_workspace, "test_file.py", "# Invalid edit") + assert result.status == "error" + assert "API error" in result.error + + # Mock a network error + mock_post.side_effect = Exception("Network error") + + # Test with network error + result = relace_edit(temp_workspace, "test_file.py", "# Invalid edit") + assert result.status == "error" + assert "Network error" in result.error + + # Test with non-existent file + result = relace_edit(temp_workspace, "nonexistent_file.py", "# Edit") + assert result.status == "error" + assert "not found" in result.error \ No newline at end of file diff --git a/tests/integration/extension/test_slack.py b/tests/integration/extension/test_slack.py new file mode 100644 index 000000000..4dbc9e269 --- /dev/null +++ b/tests/integration/extension/test_slack.py @@ -0,0 +1,98 @@ +"""Integration tests for Slack tools.""" + +import pytest +from unittest.mock import MagicMock + +from codegen.extensions.tools.link_annotation import add_links_to_message +from codegen.sdk.core.codebase import Codebase + + +@pytest.fixture +def mock_codebase(): + """Create a mock codebase for testing.""" + codebase = MagicMock(spec=Codebase) + + # Mock the symbol lookup functionality + def mock_get_symbol(symbol_name): + if symbol_name in ["test_function", "TestClass"]: + mock_symbol = MagicMock() + mock_symbol.filepath = f"src/{symbol_name.lower()}.py" + return mock_symbol + return None + + codebase.get_symbol.side_effect = mock_get_symbol + + # Mock the file exists functionality + def mock_file_exists(filepath): + return filepath in ["src/file1.py", "src/file2.py", "src/test_function.py", "src/testclass.py"] + + codebase.file_exists.side_effect = mock_file_exists + + return codebase + + +def test_add_links_to_message(mock_codebase): + """Test adding links to a Slack message.""" + # Test with symbol names + message = "Check the `test_function` and `TestClass` implementations." + result = add_links_to_message(message, mock_codebase) + + # Verify links were added for symbols + assert "`test_function`" not in result # Should be replaced with a link + assert "`TestClass`" not in result # Should be replaced with a link + assert "src/test_function.py" in result + assert "src/testclass.py" in result + + # Test with file paths + message = "Look at `src/file1.py` and `src/file2.py`." + result = add_links_to_message(message, mock_codebase) + + # Verify links were added for files + assert "`src/file1.py`" not in result # Should be replaced with a link + assert "`src/file2.py`" not in result # Should be replaced with a link + assert "src/file1.py" in result + assert "src/file2.py" in result + + # Test with non-existent symbols and files + message = "Check `nonexistent_function` and `src/nonexistent.py`." + result = add_links_to_message(message, mock_codebase) + + # Verify no links were added for non-existent items + assert "`nonexistent_function`" in result # Should remain as is + assert "`src/nonexistent.py`" in result # Should remain as is + + # Test with mixed content + message = "Check `test_function` and regular text with `src/file1.py` and *markdown*." + result = add_links_to_message(message, mock_codebase) + + # Verify links were added only for valid symbols and files + assert "`test_function`" not in result + assert "`src/file1.py`" not in result + assert "src/test_function.py" in result + assert "src/file1.py" in result + assert "*markdown*" in result # Markdown should be preserved + + +def test_send_slack_message(): + """Test sending a message to Slack. + + Note: This is a mock test since we can't actually send messages in the test environment. + """ + # Create a mock say function + mock_say = MagicMock() + + # Create a mock codebase + mock_codebase = MagicMock(spec=Codebase) + + # Import the function directly to test + from codegen.extensions.langchain.tools import SlackSendMessageTool + + # Create the tool + tool = SlackSendMessageTool(codebase=mock_codebase, say=mock_say) + + # Test sending a message + result = tool._run("Test message") + + # Verify the message was sent + mock_say.assert_called_once() + assert "✅ Message sent successfully" in result \ No newline at end of file diff --git a/tests/integration/extension/test_workspace_tools.py b/tests/integration/extension/test_workspace_tools.py new file mode 100644 index 000000000..b3b5dda50 --- /dev/null +++ b/tests/integration/extension/test_workspace_tools.py @@ -0,0 +1,292 @@ +"""Integration tests for workspace tools.""" + +import os +import tempfile +from pathlib import Path + +import pytest + +from codegen.extensions.tools import ( + create_file, + delete_file, + edit_file, + list_directory, + rename_file, + view_file, +) +from codegen.extensions.tools.search import search +from codegen.extensions.tools.replacement_edit import replacement_edit +from codegen.sdk.core.codebase import Codebase + + +@pytest.fixture +def temp_workspace(): + """Create a temporary workspace for testing.""" + with tempfile.TemporaryDirectory() as temp_dir: + # Create a simple file structure for testing + base_dir = Path(temp_dir) + + # Create a simple Python file + test_file = base_dir / "test_file.py" + test_file.write_text("def hello_world():\n return 'Hello, World!'\n") + + # Create a directory with files + test_dir = base_dir / "test_dir" + test_dir.mkdir() + (test_dir / "file1.txt").write_text("File 1 content") + (test_dir / "file2.txt").write_text("File 2 content") + + # Create a nested directory + nested_dir = test_dir / "nested" + nested_dir.mkdir() + (nested_dir / "nested_file.txt").write_text("Nested file content") + + # Create a codebase from the temp directory + codebase = Codebase.from_directory(str(base_dir)) + + yield codebase + + +def test_view_file(temp_workspace): + """Test viewing a file.""" + # Test viewing a file that exists + result = view_file(temp_workspace, "test_file.py") + assert result.status == "success" + assert "def hello_world()" in result.content + + # Test viewing a file with line numbers + result = view_file(temp_workspace, "test_file.py", line_numbers=True) + assert result.status == "success" + assert "1|def hello_world()" in result.content + + # Test viewing a file with line range + result = view_file(temp_workspace, "test_file.py", start_line=1, end_line=1) + assert result.status == "success" + assert "def hello_world()" in result.content + assert "return 'Hello, World!'" not in result.content + + # Test viewing a file that doesn't exist + result = view_file(temp_workspace, "nonexistent_file.py") + assert result.status == "error" + assert "not found" in result.error + + +def test_list_directory(temp_workspace): + """Test listing directory contents.""" + # Test listing the root directory + result = list_directory(temp_workspace, "./") + assert result.status == "success" + assert "test_file.py" in result.content + assert "test_dir" in result.content + + # Test listing a subdirectory + result = list_directory(temp_workspace, "test_dir") + assert result.status == "success" + assert "file1.txt" in result.content + assert "file2.txt" in result.content + assert "nested" in result.content + + # Test listing with depth + result = list_directory(temp_workspace, "./", depth=2) + assert result.status == "success" + assert "test_file.py" in result.content + assert "test_dir" in result.content + assert "file1.txt" in result.content + assert "file2.txt" in result.content + assert "nested" in result.content + + # Test listing a directory that doesn't exist + result = list_directory(temp_workspace, "nonexistent_dir") + assert result.status == "error" + assert "not found" in result.error + + +def test_create_file(temp_workspace): + """Test creating a file.""" + # Test creating a new file + result = create_file(temp_workspace, "new_file.py", "print('New file')") + assert result.status == "success" + + # Verify the file was created + result = view_file(temp_workspace, "new_file.py") + assert result.status == "success" + assert "print('New file')" in result.content + + # Test creating a file that already exists + result = create_file(temp_workspace, "test_file.py", "# Overwrite") + assert result.status == "error" + assert "already exists" in result.error + + # Test creating a file in a directory that doesn't exist + result = create_file(temp_workspace, "nonexistent_dir/file.py", "# Content") + assert result.status == "error" + assert "directory does not exist" in result.error + + +def test_edit_file(temp_workspace): + """Test editing a file.""" + # Test editing an existing file + result = edit_file(temp_workspace, "test_file.py", "# Modified file\ndef hello_world():\n return 'Modified!'") + assert result.status == "success" + + # Verify the file was modified + result = view_file(temp_workspace, "test_file.py") + assert result.status == "success" + assert "# Modified file" in result.content + assert "return 'Modified!'" in result.content + + # Test editing a file that doesn't exist + result = edit_file(temp_workspace, "nonexistent_file.py", "# Content") + assert result.status == "error" + assert "not found" in result.error + + +def test_delete_file(temp_workspace): + """Test deleting a file.""" + # Test deleting an existing file + result = delete_file(temp_workspace, "test_dir/file1.txt") + assert result.status == "success" + + # Verify the file was deleted + result = list_directory(temp_workspace, "test_dir") + assert result.status == "success" + assert "file1.txt" not in result.content + assert "file2.txt" in result.content + + # Test deleting a file that doesn't exist + result = delete_file(temp_workspace, "nonexistent_file.py") + assert result.status == "error" + assert "not found" in result.error + + +def test_rename_file(temp_workspace): + """Test renaming a file.""" + # Test renaming an existing file + result = rename_file(temp_workspace, "test_file.py", "renamed_file.py") + assert result.status == "success" + + # Verify the file was renamed + result = list_directory(temp_workspace, "./") + assert result.status == "success" + assert "test_file.py" not in result.content + assert "renamed_file.py" in result.content + + # Test renaming a file that doesn't exist + result = rename_file(temp_workspace, "nonexistent_file.py", "new_name.py") + assert result.status == "error" + assert "not found" in result.error + + # Test renaming to a file that already exists + # First create a file + create_file(temp_workspace, "target_file.py", "# Target file") + result = rename_file(temp_workspace, "renamed_file.py", "target_file.py") + assert result.status == "error" + assert "already exists" in result.error + + +def test_search(temp_workspace): + """Test searching the codebase.""" + # Test searching for text + result = search(temp_workspace, "Hello, World!") + assert result.status == "success" + assert len(result.matches) > 0 + assert "test_file.py" in result.matches[0]["filepath"] + + # Test searching with regex + result = search(temp_workspace, "def.*world", use_regex=True) + assert result.status == "success" + assert len(result.matches) > 0 + + # Test searching with file extensions + result = search(temp_workspace, "content", file_extensions=[".txt"]) + assert result.status == "success" + assert len(result.matches) > 0 + assert all(".txt" in match["filepath"] for match in result.matches) + + # Test searching with no matches + result = search(temp_workspace, "nonexistent_text") + assert result.status == "success" + assert len(result.matches) == 0 + + +def test_replacement_edit(temp_workspace): + """Test replacement edit.""" + # Test replacing text in a file + result = replacement_edit( + temp_workspace, + filepath="test_file.py", + pattern="Hello, World!", + replacement="Goodbye, World!", + ) + assert result.status == "success" + + # Verify the replacement was made + result = view_file(temp_workspace, "test_file.py") + assert result.status == "success" + assert "Goodbye, World!" in result.content + assert "Hello, World!" not in result.content + + # Test replacing with regex groups + result = replacement_edit( + temp_workspace, + filepath="test_file.py", + pattern=r"def (hello_world)\(\):", + replacement=r"def \1_function():", + ) + assert result.status == "success" + + # Verify the regex replacement was made + result = view_file(temp_workspace, "test_file.py") + assert result.status == "success" + assert "def hello_world_function():" in result.content + + # Test replacing with line range + # First create a multi-line file + content = "Line 1\nLine 2\nLine 3\nLine 4\nLine 5" + create_file(temp_workspace, "lines.txt", content) + + result = replacement_edit( + temp_workspace, + filepath="lines.txt", + pattern="Line", + replacement="Modified", + start=2, + end=4, + ) + assert result.status == "success" + + # Verify only lines in the range were modified + result = view_file(temp_workspace, "lines.txt") + assert result.status == "success" + assert "Line 1" in result.content + assert "Modified 2" in result.content + assert "Modified 3" in result.content + assert "Modified 4" in result.content + assert "Line 5" in result.content + + # Test replacing with count + create_file(temp_workspace, "count.txt", "Replace Replace Replace Replace") + + result = replacement_edit( + temp_workspace, + filepath="count.txt", + pattern="Replace", + replacement="Changed", + count=2, + ) + assert result.status == "success" + + # Verify only the specified number of replacements were made + result = view_file(temp_workspace, "count.txt") + assert result.status == "success" + assert "Changed Changed Replace Replace" in result.content + + # Test replacing in a file that doesn't exist + result = replacement_edit( + temp_workspace, + filepath="nonexistent_file.py", + pattern="pattern", + replacement="replacement", + ) + assert result.status == "error" + assert "not found" in result.error \ No newline at end of file From 018c69736a0711dcc6f30fe30ec3beb30fd52cea Mon Sep 17 00:00:00 2001 From: "codegen-sh[bot]" <131295404+codegen-sh[bot]@users.noreply.github.com> Date: Thu, 13 Mar 2025 02:02:36 +0000 Subject: [PATCH 2/2] Automated pre-commit update --- .../integration/extension/test_reflection.py | 15 ++-- .../integration/extension/test_relace_edit.py | 47 ++++++------ tests/integration/extension/test_slack.py | 41 ++++++----- .../extension/test_workspace_tools.py | 73 +++++++++---------- 4 files changed, 88 insertions(+), 88 deletions(-) diff --git a/tests/integration/extension/test_reflection.py b/tests/integration/extension/test_reflection.py index 87e158a09..932e1bda3 100644 --- a/tests/integration/extension/test_reflection.py +++ b/tests/integration/extension/test_reflection.py @@ -1,8 +1,9 @@ """Integration tests for the reflection tool.""" -import pytest from unittest.mock import MagicMock +import pytest + from codegen.extensions.tools.reflection import perform_reflection from codegen.sdk.core.codebase import Codebase @@ -23,14 +24,14 @@ def test_perform_reflection(mock_codebase): reflection_focus=None, codebase=mock_codebase, ) - + # Verify the result structure assert result.status == "success" assert "reflection" in result.content assert "Testing the reflection tool" in result.content assert "Found some interesting patterns" in result.content assert "Need to improve test coverage" in result.content - + # Test with a specific reflection focus result = perform_reflection( context_summary="Testing the reflection tool", @@ -39,21 +40,21 @@ def test_perform_reflection(mock_codebase): reflection_focus="architecture", codebase=mock_codebase, ) - + # Verify the result includes the focus assert result.status == "success" assert "reflection" in result.content assert "architecture" in result.content - + # Test with minimal inputs result = perform_reflection( context_summary="Minimal test", findings_so_far="Minimal findings", codebase=mock_codebase, ) - + # Verify the result with minimal inputs assert result.status == "success" assert "reflection" in result.content assert "Minimal test" in result.content - assert "Minimal findings" in result.content \ No newline at end of file + assert "Minimal findings" in result.content diff --git a/tests/integration/extension/test_relace_edit.py b/tests/integration/extension/test_relace_edit.py index 6c10f4bea..8ee9b7af9 100644 --- a/tests/integration/extension/test_relace_edit.py +++ b/tests/integration/extension/test_relace_edit.py @@ -3,9 +3,9 @@ import os import tempfile from pathlib import Path +from unittest.mock import MagicMock, patch import pytest -from unittest.mock import MagicMock, patch from codegen.extensions.tools.relace_edit import relace_edit from codegen.sdk.core.codebase import Codebase @@ -17,7 +17,7 @@ def temp_workspace(): with tempfile.TemporaryDirectory() as temp_dir: # Create a simple file structure for testing base_dir = Path(temp_dir) - + # Create a simple Python file test_file = base_dir / "test_file.py" test_file.write_text(""" @@ -27,7 +27,7 @@ def hello_world(): def goodbye_world(): return 'Goodbye, World!' """) - + # Create a JavaScript file js_file = base_dir / "test_file.js" js_file.write_text(""" @@ -39,17 +39,17 @@ def goodbye_world(): return 'Goodbye, World!'; } """) - + # Create a codebase from the temp directory codebase = Codebase.from_directory(str(base_dir)) - + yield codebase @pytest.mark.skipif(not os.getenv("RELACE_API"), reason="RELACE_API environment variable not set") def test_relace_edit_real_api(temp_workspace): """Test relace_edit with the real API. - + This test is skipped if the RELACE_API environment variable is not set. """ # Test editing a Python file @@ -63,14 +63,15 @@ def hello_world(): # Keep goodbye_world function """ - + result = relace_edit(temp_workspace, "test_file.py", edit_snippet) assert result.status == "success" - + # Verify the file was modified correctly from codegen.extensions.tools import view_file + file_content = view_file(temp_workspace, "test_file.py") - assert "print(\"Starting greeting\")" in file_content.content + assert 'print("Starting greeting")' in file_content.content assert "Hello, Modified World!" in file_content.content assert "Goodbye, World!" in file_content.content # Should be preserved @@ -90,10 +91,10 @@ def hello_world(): def goodbye_world(): return 'Goodbye, World!' -""" +""", } mock_post.return_value = mock_response - + # Test editing a Python file edit_snippet = """ # Modify hello_world function @@ -103,20 +104,21 @@ def hello_world(): # Keep goodbye_world function """ - + result = relace_edit(temp_workspace, "test_file.py", edit_snippet) assert result.status == "success" - + # Verify the API was called with the correct parameters mock_post.assert_called_once() args, kwargs = mock_post.call_args assert "content" in kwargs["json"] assert "edit_snippet" in kwargs["json"] - + # Verify the file was modified correctly from codegen.extensions.tools import view_file + file_content = view_file(temp_workspace, "test_file.py") - assert "print(\"Mocked greeting\")" in file_content.content + assert 'print("Mocked greeting")' in file_content.content assert "Hello, Mocked World!" in file_content.content @@ -126,26 +128,23 @@ def test_relace_edit_api_error(mock_post, temp_workspace): # Mock an API error response mock_response = MagicMock() mock_response.status_code = 400 - mock_response.json.return_value = { - "status": "error", - "error": "Invalid request" - } + mock_response.json.return_value = {"status": "error", "error": "Invalid request"} mock_post.return_value = mock_response - + # Test with API error result = relace_edit(temp_workspace, "test_file.py", "# Invalid edit") assert result.status == "error" assert "API error" in result.error - + # Mock a network error mock_post.side_effect = Exception("Network error") - + # Test with network error result = relace_edit(temp_workspace, "test_file.py", "# Invalid edit") assert result.status == "error" assert "Network error" in result.error - + # Test with non-existent file result = relace_edit(temp_workspace, "nonexistent_file.py", "# Edit") assert result.status == "error" - assert "not found" in result.error \ No newline at end of file + assert "not found" in result.error diff --git a/tests/integration/extension/test_slack.py b/tests/integration/extension/test_slack.py index 4dbc9e269..470e4d13a 100644 --- a/tests/integration/extension/test_slack.py +++ b/tests/integration/extension/test_slack.py @@ -1,8 +1,9 @@ """Integration tests for Slack tools.""" -import pytest from unittest.mock import MagicMock +import pytest + from codegen.extensions.tools.link_annotation import add_links_to_message from codegen.sdk.core.codebase import Codebase @@ -11,7 +12,7 @@ def mock_codebase(): """Create a mock codebase for testing.""" codebase = MagicMock(spec=Codebase) - + # Mock the symbol lookup functionality def mock_get_symbol(symbol_name): if symbol_name in ["test_function", "TestClass"]: @@ -19,15 +20,15 @@ def mock_get_symbol(symbol_name): mock_symbol.filepath = f"src/{symbol_name.lower()}.py" return mock_symbol return None - + codebase.get_symbol.side_effect = mock_get_symbol - + # Mock the file exists functionality def mock_file_exists(filepath): return filepath in ["src/file1.py", "src/file2.py", "src/test_function.py", "src/testclass.py"] - + codebase.file_exists.side_effect = mock_file_exists - + return codebase @@ -36,35 +37,35 @@ def test_add_links_to_message(mock_codebase): # Test with symbol names message = "Check the `test_function` and `TestClass` implementations." result = add_links_to_message(message, mock_codebase) - + # Verify links were added for symbols assert "`test_function`" not in result # Should be replaced with a link assert "`TestClass`" not in result # Should be replaced with a link assert "src/test_function.py" in result assert "src/testclass.py" in result - + # Test with file paths message = "Look at `src/file1.py` and `src/file2.py`." result = add_links_to_message(message, mock_codebase) - + # Verify links were added for files assert "`src/file1.py`" not in result # Should be replaced with a link assert "`src/file2.py`" not in result # Should be replaced with a link assert "src/file1.py" in result assert "src/file2.py" in result - + # Test with non-existent symbols and files message = "Check `nonexistent_function` and `src/nonexistent.py`." result = add_links_to_message(message, mock_codebase) - + # Verify no links were added for non-existent items assert "`nonexistent_function`" in result # Should remain as is assert "`src/nonexistent.py`" in result # Should remain as is - + # Test with mixed content message = "Check `test_function` and regular text with `src/file1.py` and *markdown*." result = add_links_to_message(message, mock_codebase) - + # Verify links were added only for valid symbols and files assert "`test_function`" not in result assert "`src/file1.py`" not in result @@ -75,24 +76,24 @@ def test_add_links_to_message(mock_codebase): def test_send_slack_message(): """Test sending a message to Slack. - + Note: This is a mock test since we can't actually send messages in the test environment. """ # Create a mock say function mock_say = MagicMock() - + # Create a mock codebase mock_codebase = MagicMock(spec=Codebase) - + # Import the function directly to test from codegen.extensions.langchain.tools import SlackSendMessageTool - + # Create the tool tool = SlackSendMessageTool(codebase=mock_codebase, say=mock_say) - + # Test sending a message result = tool._run("Test message") - + # Verify the message was sent mock_say.assert_called_once() - assert "✅ Message sent successfully" in result \ No newline at end of file + assert "✅ Message sent successfully" in result diff --git a/tests/integration/extension/test_workspace_tools.py b/tests/integration/extension/test_workspace_tools.py index b3b5dda50..1aa99c06e 100644 --- a/tests/integration/extension/test_workspace_tools.py +++ b/tests/integration/extension/test_workspace_tools.py @@ -1,6 +1,5 @@ """Integration tests for workspace tools.""" -import os import tempfile from pathlib import Path @@ -14,8 +13,8 @@ rename_file, view_file, ) -from codegen.extensions.tools.search import search from codegen.extensions.tools.replacement_edit import replacement_edit +from codegen.extensions.tools.search import search from codegen.sdk.core.codebase import Codebase @@ -25,25 +24,25 @@ def temp_workspace(): with tempfile.TemporaryDirectory() as temp_dir: # Create a simple file structure for testing base_dir = Path(temp_dir) - + # Create a simple Python file test_file = base_dir / "test_file.py" test_file.write_text("def hello_world():\n return 'Hello, World!'\n") - + # Create a directory with files test_dir = base_dir / "test_dir" test_dir.mkdir() (test_dir / "file1.txt").write_text("File 1 content") (test_dir / "file2.txt").write_text("File 2 content") - + # Create a nested directory nested_dir = test_dir / "nested" nested_dir.mkdir() (nested_dir / "nested_file.txt").write_text("Nested file content") - + # Create a codebase from the temp directory codebase = Codebase.from_directory(str(base_dir)) - + yield codebase @@ -53,18 +52,18 @@ def test_view_file(temp_workspace): result = view_file(temp_workspace, "test_file.py") assert result.status == "success" assert "def hello_world()" in result.content - + # Test viewing a file with line numbers result = view_file(temp_workspace, "test_file.py", line_numbers=True) assert result.status == "success" assert "1|def hello_world()" in result.content - + # Test viewing a file with line range result = view_file(temp_workspace, "test_file.py", start_line=1, end_line=1) assert result.status == "success" assert "def hello_world()" in result.content assert "return 'Hello, World!'" not in result.content - + # Test viewing a file that doesn't exist result = view_file(temp_workspace, "nonexistent_file.py") assert result.status == "error" @@ -78,14 +77,14 @@ def test_list_directory(temp_workspace): assert result.status == "success" assert "test_file.py" in result.content assert "test_dir" in result.content - + # Test listing a subdirectory result = list_directory(temp_workspace, "test_dir") assert result.status == "success" assert "file1.txt" in result.content assert "file2.txt" in result.content assert "nested" in result.content - + # Test listing with depth result = list_directory(temp_workspace, "./", depth=2) assert result.status == "success" @@ -94,7 +93,7 @@ def test_list_directory(temp_workspace): assert "file1.txt" in result.content assert "file2.txt" in result.content assert "nested" in result.content - + # Test listing a directory that doesn't exist result = list_directory(temp_workspace, "nonexistent_dir") assert result.status == "error" @@ -106,17 +105,17 @@ def test_create_file(temp_workspace): # Test creating a new file result = create_file(temp_workspace, "new_file.py", "print('New file')") assert result.status == "success" - + # Verify the file was created result = view_file(temp_workspace, "new_file.py") assert result.status == "success" assert "print('New file')" in result.content - + # Test creating a file that already exists result = create_file(temp_workspace, "test_file.py", "# Overwrite") assert result.status == "error" assert "already exists" in result.error - + # Test creating a file in a directory that doesn't exist result = create_file(temp_workspace, "nonexistent_dir/file.py", "# Content") assert result.status == "error" @@ -128,13 +127,13 @@ def test_edit_file(temp_workspace): # Test editing an existing file result = edit_file(temp_workspace, "test_file.py", "# Modified file\ndef hello_world():\n return 'Modified!'") assert result.status == "success" - + # Verify the file was modified result = view_file(temp_workspace, "test_file.py") assert result.status == "success" assert "# Modified file" in result.content assert "return 'Modified!'" in result.content - + # Test editing a file that doesn't exist result = edit_file(temp_workspace, "nonexistent_file.py", "# Content") assert result.status == "error" @@ -146,13 +145,13 @@ def test_delete_file(temp_workspace): # Test deleting an existing file result = delete_file(temp_workspace, "test_dir/file1.txt") assert result.status == "success" - + # Verify the file was deleted result = list_directory(temp_workspace, "test_dir") assert result.status == "success" assert "file1.txt" not in result.content assert "file2.txt" in result.content - + # Test deleting a file that doesn't exist result = delete_file(temp_workspace, "nonexistent_file.py") assert result.status == "error" @@ -164,18 +163,18 @@ def test_rename_file(temp_workspace): # Test renaming an existing file result = rename_file(temp_workspace, "test_file.py", "renamed_file.py") assert result.status == "success" - + # Verify the file was renamed result = list_directory(temp_workspace, "./") assert result.status == "success" assert "test_file.py" not in result.content assert "renamed_file.py" in result.content - + # Test renaming a file that doesn't exist result = rename_file(temp_workspace, "nonexistent_file.py", "new_name.py") assert result.status == "error" assert "not found" in result.error - + # Test renaming to a file that already exists # First create a file create_file(temp_workspace, "target_file.py", "# Target file") @@ -191,18 +190,18 @@ def test_search(temp_workspace): assert result.status == "success" assert len(result.matches) > 0 assert "test_file.py" in result.matches[0]["filepath"] - + # Test searching with regex result = search(temp_workspace, "def.*world", use_regex=True) assert result.status == "success" assert len(result.matches) > 0 - + # Test searching with file extensions result = search(temp_workspace, "content", file_extensions=[".txt"]) assert result.status == "success" assert len(result.matches) > 0 assert all(".txt" in match["filepath"] for match in result.matches) - + # Test searching with no matches result = search(temp_workspace, "nonexistent_text") assert result.status == "success" @@ -219,13 +218,13 @@ def test_replacement_edit(temp_workspace): replacement="Goodbye, World!", ) assert result.status == "success" - + # Verify the replacement was made result = view_file(temp_workspace, "test_file.py") assert result.status == "success" assert "Goodbye, World!" in result.content assert "Hello, World!" not in result.content - + # Test replacing with regex groups result = replacement_edit( temp_workspace, @@ -234,17 +233,17 @@ def test_replacement_edit(temp_workspace): replacement=r"def \1_function():", ) assert result.status == "success" - + # Verify the regex replacement was made result = view_file(temp_workspace, "test_file.py") assert result.status == "success" assert "def hello_world_function():" in result.content - + # Test replacing with line range # First create a multi-line file content = "Line 1\nLine 2\nLine 3\nLine 4\nLine 5" create_file(temp_workspace, "lines.txt", content) - + result = replacement_edit( temp_workspace, filepath="lines.txt", @@ -254,7 +253,7 @@ def test_replacement_edit(temp_workspace): end=4, ) assert result.status == "success" - + # Verify only lines in the range were modified result = view_file(temp_workspace, "lines.txt") assert result.status == "success" @@ -263,10 +262,10 @@ def test_replacement_edit(temp_workspace): assert "Modified 3" in result.content assert "Modified 4" in result.content assert "Line 5" in result.content - + # Test replacing with count create_file(temp_workspace, "count.txt", "Replace Replace Replace Replace") - + result = replacement_edit( temp_workspace, filepath="count.txt", @@ -275,12 +274,12 @@ def test_replacement_edit(temp_workspace): count=2, ) assert result.status == "success" - + # Verify only the specified number of replacements were made result = view_file(temp_workspace, "count.txt") assert result.status == "success" assert "Changed Changed Replace Replace" in result.content - + # Test replacing in a file that doesn't exist result = replacement_edit( temp_workspace, @@ -289,4 +288,4 @@ def test_replacement_edit(temp_workspace): replacement="replacement", ) assert result.status == "error" - assert "not found" in result.error \ No newline at end of file + assert "not found" in result.error