mirror of
https://github.com/tiennm99/serena.git
synced 2026-10-13 12:15:10 +00:00
remove files
This commit is contained in:
1 parent
061bbbde90
commit
9373d33151
2 files changed
-401
No files matched your search
@@ -1,229 +0,0 @@
|
||||
"""Tests for the GetDiagnosticsTool."""
|
||||
|
||||
import json
|
||||
from unittest.mock import Mock, patch
|
||||
|
||||
import pytest
|
||||
|
||||
from src.serena.agent import SerenaAgent
|
||||
from src.serena.project import Project
|
||||
from src.serena.tools.symbol_tools import GetDiagnosticsTool
|
||||
|
||||
|
||||
class TestGetDiagnosticsTool:
|
||||
"""Unit tests for GetDiagnosticsTool."""
|
||||
|
||||
def setup_method(self):
|
||||
"""Set up test fixtures."""
|
||||
# Mock agent
|
||||
self.mock_agent = Mock(spec=SerenaAgent)
|
||||
self.mock_agent.is_using_language_server.return_value = True
|
||||
|
||||
# Mock language server
|
||||
self.mock_language_server = Mock()
|
||||
self.mock_agent.language_server = self.mock_language_server
|
||||
|
||||
# Mock project
|
||||
self.mock_project = Mock(spec=Project)
|
||||
self.mock_project.project_root = "/test/project"
|
||||
self.mock_agent.get_active_project_or_raise.return_value = self.mock_project
|
||||
|
||||
# Create tool instance
|
||||
self.tool = GetDiagnosticsTool(self.mock_agent)
|
||||
|
||||
def test_get_severity_name(self):
|
||||
"""Test the _get_severity_name helper method."""
|
||||
assert self.tool._get_severity_name(1) == "error"
|
||||
assert self.tool._get_severity_name(2) == "warning"
|
||||
assert self.tool._get_severity_name(3) == "information"
|
||||
assert self.tool._get_severity_name(4) == "hint"
|
||||
assert self.tool._get_severity_name(None) == "unknown"
|
||||
assert self.tool._get_severity_name(999) == "unknown(999)"
|
||||
|
||||
@patch("os.path.exists")
|
||||
@patch("os.path.isdir")
|
||||
def test_apply_success_with_diagnostics(self, mock_isdir, mock_exists):
|
||||
"""Test successful diagnostic retrieval with results."""
|
||||
# Setup mocks
|
||||
mock_exists.return_value = True
|
||||
mock_isdir.return_value = False
|
||||
|
||||
# Mock diagnostic data
|
||||
mock_diagnostics = [
|
||||
{
|
||||
"severity": 1,
|
||||
"message": "Undefined variable 'foo'",
|
||||
"code": "undefined-variable",
|
||||
"source": "pylsp",
|
||||
"range": {"start": {"line": 10, "character": 5}, "end": {"line": 10, "character": 8}},
|
||||
},
|
||||
{
|
||||
"severity": 2,
|
||||
"message": "Line too long",
|
||||
"code": "E501",
|
||||
"source": "flake8",
|
||||
"range": {"start": {"line": 20, "character": 0}, "end": {"line": 20, "character": 100}},
|
||||
},
|
||||
]
|
||||
|
||||
self.mock_language_server.request_text_document_diagnostics.return_value = mock_diagnostics
|
||||
|
||||
# Mock the _limit_length method
|
||||
with patch.object(self.tool, "_limit_length", side_effect=lambda x, _: x):
|
||||
result = self.tool.apply("test_file.py")
|
||||
|
||||
# Verify result
|
||||
result_data = json.loads(result)
|
||||
assert len(result_data) == 2
|
||||
|
||||
# Check first diagnostic
|
||||
diag1 = result_data[0]
|
||||
assert diag1["severity"] == 1
|
||||
assert diag1["severity_name"] == "error"
|
||||
assert diag1["message"] == "Undefined variable 'foo'"
|
||||
assert diag1["code"] == "undefined-variable"
|
||||
assert diag1["source"] == "pylsp"
|
||||
assert diag1["range"]["start"]["line"] == 10
|
||||
assert diag1["range"]["start"]["character"] == 5
|
||||
|
||||
# Check second diagnostic
|
||||
diag2 = result_data[1]
|
||||
assert diag2["severity"] == 2
|
||||
assert diag2["severity_name"] == "warning"
|
||||
assert diag2["message"] == "Line too long"
|
||||
|
||||
# Verify method calls
|
||||
self.mock_language_server.request_text_document_diagnostics.assert_called_once_with("test_file.py")
|
||||
|
||||
@patch("os.path.exists")
|
||||
@patch("os.path.isdir")
|
||||
def test_apply_success_no_diagnostics(self, mock_isdir, mock_exists):
|
||||
"""Test successful diagnostic retrieval with no results."""
|
||||
# Setup mocks
|
||||
mock_exists.return_value = True
|
||||
mock_isdir.return_value = False
|
||||
|
||||
self.mock_language_server.request_text_document_diagnostics.return_value = []
|
||||
|
||||
# Mock the _limit_length method
|
||||
with patch.object(self.tool, "_limit_length", side_effect=lambda x, _: x):
|
||||
result = self.tool.apply("clean_file.py")
|
||||
|
||||
# Verify result
|
||||
result_data = json.loads(result)
|
||||
assert len(result_data) == 0
|
||||
assert result_data == []
|
||||
|
||||
def test_apply_no_language_server(self):
|
||||
"""Test error when language server is not available."""
|
||||
self.mock_agent.is_using_language_server.return_value = False
|
||||
|
||||
with pytest.raises(Exception, match="Cannot get diagnostics; agent is not in language server mode"):
|
||||
self.tool.apply("test_file.py")
|
||||
|
||||
@patch("os.path.exists")
|
||||
def test_apply_file_not_found(self, mock_exists):
|
||||
"""Test error when file does not exist."""
|
||||
mock_exists.return_value = False
|
||||
|
||||
with pytest.raises(FileNotFoundError, match=r"File test_file.py does not exist in the project"):
|
||||
self.tool.apply("test_file.py")
|
||||
|
||||
@patch("os.path.exists")
|
||||
@patch("os.path.isdir")
|
||||
def test_apply_is_directory(self, mock_isdir, mock_exists):
|
||||
"""Test error when path is a directory instead of a file."""
|
||||
mock_exists.return_value = True
|
||||
mock_isdir.return_value = True
|
||||
|
||||
with pytest.raises(ValueError, match="Expected a file path, but got a directory path: test_dir"):
|
||||
self.tool.apply("test_dir")
|
||||
|
||||
@patch("os.path.exists")
|
||||
@patch("os.path.isdir")
|
||||
def test_apply_language_server_error(self, mock_isdir, mock_exists):
|
||||
"""Test handling of language server errors."""
|
||||
mock_exists.return_value = True
|
||||
mock_isdir.return_value = False
|
||||
|
||||
# Mock language server to raise an exception
|
||||
self.mock_language_server.request_text_document_diagnostics.side_effect = Exception("Language server failed")
|
||||
|
||||
with pytest.raises(RuntimeError, match=r"Failed to retrieve diagnostics for test_file.py: Language server failed"):
|
||||
self.tool.apply("test_file.py")
|
||||
|
||||
@patch("os.path.exists")
|
||||
@patch("os.path.isdir")
|
||||
def test_apply_with_missing_fields(self, mock_isdir, mock_exists):
|
||||
"""Test handling of diagnostics with missing optional fields."""
|
||||
# Setup mocks
|
||||
mock_exists.return_value = True
|
||||
mock_isdir.return_value = False
|
||||
|
||||
# Mock diagnostic with missing optional fields
|
||||
mock_diagnostics = [
|
||||
{
|
||||
"message": "Error without optional fields",
|
||||
"range": {"start": {"line": 5, "character": 0}, "end": {"line": 5, "character": 10}},
|
||||
# Missing severity, code, source
|
||||
}
|
||||
]
|
||||
|
||||
self.mock_language_server.request_text_document_diagnostics.return_value = mock_diagnostics
|
||||
|
||||
# Mock the _limit_length method
|
||||
with patch.object(self.tool, "_limit_length", side_effect=lambda x, _: x):
|
||||
result = self.tool.apply("test_file.py")
|
||||
|
||||
# Verify result handles missing fields gracefully
|
||||
result_data = json.loads(result)
|
||||
assert len(result_data) == 1
|
||||
|
||||
diag = result_data[0]
|
||||
assert diag["severity"] == "unknown"
|
||||
assert diag["severity_name"] == "unknown"
|
||||
assert diag["message"] == "Error without optional fields"
|
||||
assert diag["code"] == ""
|
||||
assert diag["source"] == ""
|
||||
|
||||
@patch("os.path.exists")
|
||||
@patch("os.path.isdir")
|
||||
def test_apply_with_max_answer_chars(self, mock_isdir, mock_exists):
|
||||
"""Test limiting output with max_answer_chars parameter."""
|
||||
mock_exists.return_value = True
|
||||
mock_isdir.return_value = False
|
||||
|
||||
mock_diagnostics = [
|
||||
{
|
||||
"severity": 1,
|
||||
"message": "Test error",
|
||||
"code": "test",
|
||||
"source": "test",
|
||||
"range": {"start": {"line": 1, "character": 0}, "end": {"line": 1, "character": 5}},
|
||||
}
|
||||
]
|
||||
|
||||
self.mock_language_server.request_text_document_diagnostics.return_value = mock_diagnostics
|
||||
|
||||
# Mock _limit_length to return truncated result
|
||||
with patch.object(self.tool, "_limit_length", return_value="TRUNCATED"):
|
||||
result = self.tool.apply("test_file.py", max_answer_chars=100)
|
||||
|
||||
assert result == "TRUNCATED"
|
||||
|
||||
def test_path_construction(self):
|
||||
"""Test that file paths are constructed correctly."""
|
||||
relative_path = "src/module/file.py"
|
||||
|
||||
with (
|
||||
patch("os.path.exists", return_value=True),
|
||||
patch("os.path.isdir", return_value=False),
|
||||
patch.object(self.tool, "_limit_length", side_effect=lambda x, _: x),
|
||||
):
|
||||
|
||||
self.mock_language_server.request_text_document_diagnostics.return_value = []
|
||||
self.tool.apply(relative_path)
|
||||
|
||||
# Verify os.path.join was called with correct arguments
|
||||
# The actual path checking happens in the method, we verify the LS call
|
||||
self.mock_language_server.request_text_document_diagnostics.assert_called_once_with(relative_path)
|
||||
@@ -1,172 +0,0 @@
|
||||
"""Integration tests for GetDiagnosticsTool with Go language server."""
|
||||
|
||||
import json
|
||||
import os
|
||||
from unittest.mock import Mock
|
||||
|
||||
import pytest
|
||||
|
||||
from solidlsp.ls_config import Language
|
||||
from src.serena.agent import SerenaAgent
|
||||
from src.serena.project import Project
|
||||
from src.serena.tools.symbol_tools import GetDiagnosticsTool
|
||||
from test.conftest import create_ls
|
||||
|
||||
|
||||
@pytest.mark.go
|
||||
class TestGetDiagnosticsToolGoIntegration:
|
||||
"""Integration tests for GetDiagnosticsTool with Go language server."""
|
||||
|
||||
def setup_method(self):
|
||||
"""Set up test fixtures with real Go language server."""
|
||||
# Path to our diagnostic test repository
|
||||
self.repo_path = os.path.join(os.path.dirname(__file__), "..", "resources", "repos", "go", "diagnostic_test_repo")
|
||||
self.repo_path = os.path.abspath(self.repo_path)
|
||||
|
||||
# Create real language server for Go
|
||||
self.language_server = create_ls(Language.GO, repo_path=self.repo_path)
|
||||
|
||||
# Mock agent with real language server
|
||||
self.mock_agent = Mock(spec=SerenaAgent)
|
||||
self.mock_agent.is_using_language_server.return_value = True
|
||||
self.mock_agent.language_server = self.language_server
|
||||
|
||||
# Mock project
|
||||
self.mock_project = Mock(spec=Project)
|
||||
self.mock_project.project_root = self.repo_path
|
||||
self.mock_agent.get_active_project_or_raise.return_value = self.mock_project
|
||||
|
||||
# Create tool instance
|
||||
self.tool = GetDiagnosticsTool(self.mock_agent)
|
||||
|
||||
def teardown_method(self):
|
||||
"""Clean up language server."""
|
||||
if hasattr(self, "language_server"):
|
||||
self.language_server.stop()
|
||||
|
||||
def test_get_diagnostics_with_go_errors(self):
|
||||
"""Test GetDiagnosticsTool retrieves actual Go diagnostics from language server."""
|
||||
|
||||
# Mock the _limit_length method to avoid character limits in tests
|
||||
def mock_limit_length(content, max_chars):
|
||||
return content
|
||||
|
||||
self.tool._limit_length = mock_limit_length
|
||||
|
||||
try:
|
||||
print(f"Starting Go language server for repo: {self.repo_path}")
|
||||
# Start the language server
|
||||
self.language_server.start()
|
||||
print("Language server started successfully")
|
||||
|
||||
# Get diagnostics for the main.go file with intentional errors
|
||||
result = self.tool.apply("main.go")
|
||||
|
||||
# Parse the JSON result
|
||||
diagnostics = json.loads(result)
|
||||
|
||||
# We should have at least some diagnostics due to the intentional errors
|
||||
assert isinstance(diagnostics, list)
|
||||
assert len(diagnostics) > 0, f"Expected diagnostics but got none. Result: {result}"
|
||||
|
||||
# Check that we have actual diagnostic data
|
||||
for diagnostic in diagnostics:
|
||||
assert "severity" in diagnostic
|
||||
assert "severity_name" in diagnostic
|
||||
assert "message" in diagnostic
|
||||
assert "range" in diagnostic
|
||||
assert "start" in diagnostic["range"]
|
||||
assert "end" in diagnostic["range"]
|
||||
assert "line" in diagnostic["range"]["start"]
|
||||
assert "character" in diagnostic["range"]["start"]
|
||||
|
||||
# Severity should be a known value
|
||||
assert diagnostic["severity_name"] in ["error", "warning", "information", "hint", "unknown"]
|
||||
|
||||
# Message should not be empty for real diagnostics
|
||||
assert len(diagnostic["message"]) > 0
|
||||
|
||||
# Check that we have at least one error (due to undefined variables/functions)
|
||||
error_diagnostics = [d for d in diagnostics if d["severity_name"] == "error"]
|
||||
assert len(error_diagnostics) > 0, f"Expected at least one error diagnostic. Got diagnostics: {diagnostics}"
|
||||
|
||||
print(f"Successfully retrieved {len(diagnostics)} diagnostics:")
|
||||
for i, diag in enumerate(diagnostics[:5]): # Print first 5 diagnostics
|
||||
print(f" {i+1}. [{diag['severity_name']}] {diag['message']} at line {diag['range']['start']['line']}")
|
||||
|
||||
except Exception as e:
|
||||
pytest.skip(f"Go language server not available or failed: {e}")
|
||||
|
||||
def test_get_diagnostics_empty_file(self):
|
||||
"""Test GetDiagnosticsTool with a valid Go file that has no errors."""
|
||||
# Create a valid Go file with no errors
|
||||
valid_go_content = """package utils
|
||||
|
||||
import "fmt"
|
||||
|
||||
func PrintMessage() {
|
||||
fmt.Println("Hello, World!")
|
||||
}
|
||||
"""
|
||||
|
||||
# Create subdirectory for the valid file to avoid package conflicts
|
||||
valid_dir = os.path.join(self.repo_path, "utils")
|
||||
os.makedirs(valid_dir, exist_ok=True)
|
||||
|
||||
# Write the valid content to a test file in subdirectory
|
||||
valid_file_path = os.path.join(valid_dir, "valid.go")
|
||||
try:
|
||||
with open(valid_file_path, "w") as f:
|
||||
f.write(valid_go_content)
|
||||
|
||||
# Mock the _limit_length method
|
||||
def mock_limit_length(content, max_chars):
|
||||
return content
|
||||
|
||||
self.tool._limit_length = mock_limit_length
|
||||
|
||||
# Start the language server
|
||||
self.language_server.start()
|
||||
|
||||
# Get diagnostics for the valid file
|
||||
result = self.tool.apply("utils/valid.go")
|
||||
|
||||
# Parse the JSON result
|
||||
diagnostics = json.loads(result)
|
||||
|
||||
# Should be an empty list or only contain minor warnings
|
||||
assert isinstance(diagnostics, list)
|
||||
|
||||
# If there are any diagnostics, they should not be errors
|
||||
error_diagnostics = [d for d in diagnostics if d["severity_name"] == "error"]
|
||||
assert len(error_diagnostics) == 0, f"Valid Go file should not have errors. Got: {error_diagnostics}"
|
||||
|
||||
print(f"Valid Go file has {len(diagnostics)} diagnostics (expected 0 or only warnings/hints)")
|
||||
|
||||
except Exception as e:
|
||||
pytest.skip(f"Go language server not available or failed: {e}")
|
||||
finally:
|
||||
# Clean up the test file and directory
|
||||
if os.path.exists(valid_file_path):
|
||||
os.remove(valid_file_path)
|
||||
if os.path.exists(valid_dir) and os.path.isdir(valid_dir):
|
||||
os.rmdir(valid_dir)
|
||||
|
||||
def test_get_diagnostics_nonexistent_file(self):
|
||||
"""Test GetDiagnosticsTool error handling with nonexistent file."""
|
||||
with pytest.raises(FileNotFoundError, match=r"File nonexistent.go does not exist in the project"):
|
||||
self.tool.apply("nonexistent.go")
|
||||
|
||||
def test_get_diagnostics_directory_path(self):
|
||||
"""Test GetDiagnosticsTool error handling when given a directory path."""
|
||||
# Create a test directory
|
||||
test_dir = os.path.join(self.repo_path, "test_dir")
|
||||
os.makedirs(test_dir, exist_ok=True)
|
||||
|
||||
try:
|
||||
with pytest.raises(ValueError, match="Expected a file path, but got a directory path"):
|
||||
self.tool.apply("test_dir")
|
||||
finally:
|
||||
# Clean up
|
||||
if os.path.exists(test_dir):
|
||||
os.rmdir(test_dir)
|
||||
Reference in new issue
Block a user