Restructured serena_agent tests, reifying the cases

Removed some cases (haxe, msl) during cherry pick due to conflicts. We don't need to cover these languages in this test
This commit is contained in:
Michael Panchenko authored and Dominik Jain committed 2026-04-29 23:52:26 +02:00
1 parent c55e0c900e
commit 940bbb31de
5 files changed
+912 -1356

No files matched your search

+1 -1
View File
@@ -370,7 +370,7 @@ def find_identifier_position(file_path: Path, identifier: str) -> tuple[int, int
return None
def find_identifier_occurrence_position(
def find_identifier_pos(
file_path: Path,
identifier: str,
occurrence_index: int = 0,
-230
View File
@@ -1,230 +0,0 @@
import os
from dataclasses import dataclass
from typing import cast
import pytest
from _pytest.mark import Mark, MarkDecorator
from solidlsp.ls_config import Language
from test.conftest import get_pytest_markers
@dataclass(frozen=True)
class DiagnosticCase:
language: Language
relative_path: str
primary_symbol_name_path: str
primary_symbol_identifier: str
reference_symbol_name_path: str
reference_symbol_identifier: str
primary_message_fragment: str
reference_message_fragment: str
def diagnostic_case_param(
case: DiagnosticCase,
*marks: MarkDecorator | Mark,
id: str,
):
return pytest.param(case.language, case, marks=[*get_pytest_markers(case.language), *marks], id=id)
DIAGNOSTIC_CASE_PARAMS = [
diagnostic_case_param(
DiagnosticCase(
language=Language.PYTHON,
relative_path=os.path.join("test_repo", "diagnostics_sample.py"),
primary_symbol_name_path="broken_factory",
primary_symbol_identifier="broken_factory",
reference_symbol_name_path="broken_consumer",
reference_symbol_identifier="broken_consumer",
primary_message_fragment="missing_user",
reference_message_fragment="undefined_name",
),
id="python_missing_user",
),
diagnostic_case_param(
DiagnosticCase(
language=Language.PYTHON_TY,
relative_path=os.path.join("test_repo", "diagnostics_sample.py"),
primary_symbol_name_path="broken_factory",
primary_symbol_identifier="broken_factory",
reference_symbol_name_path="broken_consumer",
reference_symbol_identifier="broken_consumer",
primary_message_fragment="missing_user",
reference_message_fragment="undefined_name",
),
id="python_ty_missing_user",
),
diagnostic_case_param(
DiagnosticCase(
language=Language.GO,
relative_path="diagnostics_sample.go",
primary_symbol_name_path="brokenFactory",
primary_symbol_identifier="brokenFactory",
reference_symbol_name_path="brokenConsumer",
reference_symbol_identifier="brokenConsumer",
primary_message_fragment="missingGreeting",
reference_message_fragment="missingConsumerValue",
),
id="go_missing_greeting",
),
diagnostic_case_param(
DiagnosticCase(
language=Language.JAVA,
relative_path=os.path.join("src", "main", "java", "test_repo", "DiagnosticsSample.java"),
primary_symbol_name_path="DiagnosticsSample/brokenFactory",
primary_symbol_identifier="brokenFactory",
reference_symbol_name_path="DiagnosticsSample/brokenConsumer",
reference_symbol_identifier="brokenConsumer",
primary_message_fragment="missingGreeting",
reference_message_fragment="missingConsumerValue",
),
id="java_missing_greeting",
),
diagnostic_case_param(
DiagnosticCase(
language=Language.KOTLIN,
relative_path=os.path.join("src", "main", "kotlin", "test_repo", "DiagnosticsSample.kt"),
primary_symbol_name_path="brokenFactory",
primary_symbol_identifier="brokenFactory",
reference_symbol_name_path="brokenConsumer",
reference_symbol_identifier="brokenConsumer",
primary_message_fragment="missingGreeting",
reference_message_fragment="missingConsumerValue",
),
id="kotlin_missing_greeting",
),
diagnostic_case_param(
DiagnosticCase(
language=Language.RUST,
relative_path=os.path.join("src", "diagnostics_sample.rs"),
primary_symbol_name_path="broken_factory",
primary_symbol_identifier="broken_factory",
reference_symbol_name_path="broken_consumer",
reference_symbol_identifier="broken_consumer",
primary_message_fragment="missing_greeting",
reference_message_fragment="missing_consumer_value",
),
pytest.mark.xfail(reason="rust-analyzer does not surface diagnostics for this fixture through Serena currently"),
id="rust_missing_greeting",
),
diagnostic_case_param(
DiagnosticCase(
language=Language.PHP,
relative_path="diagnostics_sample.php",
primary_symbol_name_path="brokenFactory",
primary_symbol_identifier="brokenFactory",
reference_symbol_name_path="brokenConsumer",
reference_symbol_identifier="brokenConsumer",
primary_message_fragment="missingGreeting",
reference_message_fragment="missingConsumerValue",
),
pytest.mark.xfail(reason="PHP LS integration does not expose document diagnostics in this environment"),
id="php_missing_greeting",
),
diagnostic_case_param(
DiagnosticCase(
language=Language.CLOJURE,
relative_path=os.path.join("src", "test_app", "diagnostics_sample.clj"),
primary_symbol_name_path="broken-factory",
primary_symbol_identifier="broken-factory",
reference_symbol_name_path="broken-consumer",
reference_symbol_identifier="broken-consumer",
primary_message_fragment="missing-greeting",
reference_message_fragment="missing-consumer-value",
),
id="clojure_missing_greeting",
),
diagnostic_case_param(
DiagnosticCase(
language=Language.CSHARP,
relative_path="DiagnosticsSample.cs",
primary_symbol_name_path="TestProject/DiagnosticsSample/BrokenFactory",
primary_symbol_identifier="BrokenFactory",
reference_symbol_name_path="TestProject/DiagnosticsSample/BrokenConsumer",
reference_symbol_identifier="BrokenConsumer",
primary_message_fragment="missingGreeting",
reference_message_fragment="missingConsumerValue",
),
id="csharp_missing_greeting",
),
diagnostic_case_param(
DiagnosticCase(
language=Language.POWERSHELL,
relative_path="diagnostics_sample.ps1",
primary_symbol_name_path="function Invoke-BrokenFactory ()",
primary_symbol_identifier="Invoke-BrokenFactory",
reference_symbol_name_path="function Invoke-BrokenConsumer ()",
reference_symbol_identifier="Invoke-BrokenConsumer",
primary_message_fragment="MissingGreeting",
reference_message_fragment="MissingConsumerValue",
),
pytest.mark.xfail(reason="PowerShell LS does not surface document diagnostics in this environment"),
id="powershell_missing_greeting",
),
diagnostic_case_param(
DiagnosticCase(
language=Language.CPP_CCLS,
relative_path="diagnostics_sample.cpp",
primary_symbol_name_path="brokenFactory",
primary_symbol_identifier="brokenFactory",
reference_symbol_name_path="brokenConsumer",
reference_symbol_identifier="brokenConsumer",
primary_message_fragment="missingGreeting",
reference_message_fragment="missingConsumerValue",
),
pytest.mark.xfail(reason="ccls does not expose document diagnostics through this integration"),
id="cpp_missing_greeting",
),
diagnostic_case_param(
DiagnosticCase(
language=Language.LEAN4,
relative_path="DiagnosticsSample.lean",
primary_symbol_name_path="brokenFactory",
primary_symbol_identifier="brokenFactory",
reference_symbol_name_path="brokenConsumer",
reference_symbol_identifier="brokenConsumer",
primary_message_fragment="missingGreeting",
reference_message_fragment="missingConsumerValue",
),
pytest.mark.xfail(reason="Lean4 LS does not reliably surface diagnostics in CI"),
id="lean_missing_greeting",
),
diagnostic_case_param(
DiagnosticCase(
language=Language.TYPESCRIPT,
relative_path="diagnostics_sample.ts",
primary_symbol_name_path="brokenFactory",
primary_symbol_identifier="brokenFactory",
reference_symbol_name_path="brokenConsumer",
reference_symbol_identifier="brokenConsumer",
primary_message_fragment="missingGreeting",
reference_message_fragment="missingConsumerValue",
),
pytest.mark.typescript,
pytest.mark.xfail(reason="TypeScript LS does not surface document diagnostics through this integration"),
id="typescript_missing_greeting",
),
diagnostic_case_param(
DiagnosticCase(
language=Language.FSHARP,
relative_path="DiagnosticsSample.fs",
primary_symbol_name_path="brokenFactory",
primary_symbol_identifier="brokenFactory",
reference_symbol_name_path="brokenConsumer",
reference_symbol_identifier="brokenConsumer",
primary_message_fragment="missingGreeting",
reference_message_fragment="missingConsumerValue",
),
pytest.mark.xfail(reason="F# LS does not expose document diagnostics through this integration"),
id="fsharp_missing_greeting",
),
]
WORKING_DIAGNOSTIC_TOOL_CASE_PARAMS = [
case_param
for case_param in DIAGNOSTIC_CASE_PARAMS
if cast(DiagnosticCase, case_param.values[1]).language
in {Language.PYTHON, Language.PYTHON_TY, Language.GO, Language.JAVA, Language.KOTLIN, Language.CSHARP}
]
File diff suppressed because it is too large. Load diff
@@ -1,139 +0,0 @@
import os
import shutil
from pathlib import Path
import pytest
from solidlsp import SolidLanguageServer
from solidlsp.ls_config import Language
from test.conftest import find_identifier_occurrence_position, is_ci
from test.solidlsp import clojure as clj
@pytest.mark.parametrize(
"language_server,relative_path,identifier,occurrence_index,column_offset,expected_name,expected_definition_file",
[
pytest.param(
Language.PYTHON,
os.path.join("test_repo", "services.py"),
"User",
1,
1,
"User",
"models.py",
marks=pytest.mark.python,
),
pytest.param(
Language.PYTHON_TY,
os.path.join("test_repo", "services.py"),
"User",
1,
1,
"User",
"models.py",
marks=pytest.mark.python,
),
pytest.param(Language.GO, "main.go", "Helper", 0, 1, "Helper", "main.go", marks=pytest.mark.go),
pytest.param(
Language.JAVA,
os.path.join("src", "main", "java", "test_repo", "Main.java"),
"Model",
0,
1,
"Model",
"Model.java",
marks=pytest.mark.java,
),
pytest.param(
Language.KOTLIN,
os.path.join("src", "main", "kotlin", "test_repo", "Main.kt"),
"Model",
0,
1,
"Model",
"Model.kt",
marks=[pytest.mark.kotlin] + ([pytest.mark.skip(reason="Kotlin LSP JVM crashes on restart in CI")] if is_ci else []),
),
pytest.param(
Language.RUST,
os.path.join("src", "main.rs"),
"format_greeting",
0,
1,
"format_greeting",
"lib.rs",
marks=pytest.mark.rust,
),
pytest.param(Language.PHP, "index.php", "helperFunction", 0, 5, "helperFunction", "helper.php", marks=pytest.mark.php),
pytest.param(
Language.CLOJURE,
clj.UTILS_PATH,
"multiply",
0,
1,
"multiply",
clj.CORE_PATH,
marks=[
pytest.mark.clojure,
pytest.mark.skipif(not clj.is_clojure_cli_available(), reason="clojure CLI is not installed"),
],
),
pytest.param(Language.CSHARP, "Program.cs", "Add", 0, 1, "Add", "Program.cs", marks=pytest.mark.csharp),
pytest.param(
Language.POWERSHELL,
"main.ps1",
"Convert-ToUpperCase",
0,
1,
"function Convert-ToUpperCase ()",
"utils.ps1",
marks=pytest.mark.powershell,
),
pytest.param(Language.CPP_CCLS, "a.cpp", "add", 0, 1, "add", "b.cpp", marks=pytest.mark.cpp),
pytest.param(
Language.LEAN4,
"Main.lean",
"add",
0,
1,
"add",
"Helper.lean",
marks=[
pytest.mark.lean4,
pytest.mark.skipif(shutil.which("lean") is None, reason="Lean is not installed"),
pytest.mark.xfail(reason="Lean4 LS does not reliably resolve cross-file defining symbols in CI"),
],
),
pytest.param(Language.TYPESCRIPT, "index.ts", "helperFunction", 1, 1, "helperFunction", "index.ts", marks=pytest.mark.typescript),
pytest.param(
Language.FSHARP,
"Program.fs",
"add",
0,
1,
"add",
"Calculator.fs",
marks=[pytest.mark.fsharp, pytest.mark.xfail(reason="F# language server cannot reliably resolve defining symbols")],
),
],
indirect=["language_server"],
)
def test_request_defining_symbol_matrix(
language_server: SolidLanguageServer,
relative_path: str,
identifier: str,
occurrence_index: int,
column_offset: int,
expected_name: str,
expected_definition_file: str,
) -> None:
repo_root = Path(language_server.repository_root_path)
position = find_identifier_occurrence_position(repo_root / relative_path, identifier, occurrence_index, column_offset)
assert position is not None, f"Could not find occurrence {occurrence_index} of {identifier!r} in {relative_path}"
defining_symbol = language_server.request_defining_symbol(relative_path, *position)
assert defining_symbol is not None, f"Expected a defining symbol for {identifier!r} in {relative_path}"
assert defining_symbol.get("name") == expected_name, f"Expected defining symbol name {expected_name!r}, got: {defining_symbol}"
assert expected_definition_file in defining_symbol["location"].get("relativePath", ""), (
f"Expected defining symbol in {expected_definition_file!r}, got: {defining_symbol}"
)
-79
View File
@@ -1,79 +0,0 @@
from pathlib import Path
import pytest
from serena.symbol import LanguageServerSymbolRetriever
from solidlsp import SolidLanguageServer
from test.conftest import find_identifier_position
from test.diagnostics_cases import DIAGNOSTIC_CASE_PARAMS, DiagnosticCase
@pytest.mark.parametrize("language_server,diagnostic_case", DIAGNOSTIC_CASE_PARAMS, indirect=["language_server"])
def test_request_text_document_diagnostics_matrix(
language_server: SolidLanguageServer,
diagnostic_case: DiagnosticCase,
) -> None:
diagnostics = language_server.request_text_document_diagnostics(diagnostic_case.relative_path, min_severity=1)
assert diagnostics, f"Expected diagnostics for {diagnostic_case.language.value}:{diagnostic_case.relative_path}"
diagnostic_messages = [diagnostic["message"] for diagnostic in diagnostics]
assert any(diagnostic_case.primary_message_fragment in message for message in diagnostic_messages), diagnostic_messages
assert any(diagnostic_case.reference_message_fragment in message for message in diagnostic_messages), diagnostic_messages
repo_root = language_server.repository_root_path
primary_symbol_position = find_identifier_position(
Path(repo_root) / diagnostic_case.relative_path, diagnostic_case.primary_symbol_identifier
)
reference_symbol_position = find_identifier_position(
Path(repo_root) / diagnostic_case.relative_path, diagnostic_case.reference_symbol_identifier
)
assert primary_symbol_position is not None
assert reference_symbol_position is not None
primary_diagnostics = language_server.request_text_document_diagnostics(
diagnostic_case.relative_path,
start_line=primary_symbol_position[0],
end_line=reference_symbol_position[0] - 1,
min_severity=1,
)
primary_messages = [diagnostic["message"] for diagnostic in primary_diagnostics]
assert primary_messages, f"Expected range-filtered diagnostics for {diagnostic_case.primary_symbol_identifier}"
assert any(diagnostic_case.primary_message_fragment in message for message in primary_messages), primary_messages
assert all(diagnostic_case.reference_message_fragment not in message for message in primary_messages), primary_messages
@pytest.mark.parametrize("project_with_ls,diagnostic_case", DIAGNOSTIC_CASE_PARAMS, indirect=["project_with_ls"])
def test_get_symbol_diagnostics_matrix(project_with_ls, diagnostic_case: DiagnosticCase) -> None:
symbol_retriever = LanguageServerSymbolRetriever(project_with_ls)
diagnostics_by_symbol = symbol_retriever.get_symbol_diagnostics(
diagnostic_case.primary_symbol_name_path,
reference_file=diagnostic_case.relative_path,
min_severity=1,
)
diagnostic_messages_by_symbol = {
symbol.get_name_path(): [diagnostic["message"] for diagnostic in diagnostics]
for symbol, diagnostics in diagnostics_by_symbol.items()
}
assert diagnostic_case.primary_symbol_name_path in diagnostic_messages_by_symbol, diagnostic_messages_by_symbol
assert any(
diagnostic_case.primary_message_fragment in message
for message in diagnostic_messages_by_symbol[diagnostic_case.primary_symbol_name_path]
), diagnostic_messages_by_symbol
diagnostics_with_references = symbol_retriever.get_symbol_diagnostics(
diagnostic_case.primary_symbol_name_path,
reference_file=diagnostic_case.relative_path,
check_symbol_references=True,
min_severity=1,
)
diagnostic_messages_with_references = {
symbol.get_name_path(): [diagnostic["message"] for diagnostic in diagnostics]
for symbol, diagnostics in diagnostics_with_references.items()
}
assert diagnostic_case.primary_symbol_name_path in diagnostic_messages_with_references, diagnostic_messages_with_references
assert diagnostic_case.reference_symbol_name_path in diagnostic_messages_with_references, diagnostic_messages_with_references
assert any(
diagnostic_case.reference_message_fragment in message
for message in diagnostic_messages_with_references[diagnostic_case.reference_symbol_name_path]
), diagnostic_messages_with_references