mirror of
https://github.com/tiennm99/serena.git
synced 2026-10-03 09:13:49 +00:00
Fixed diagnostics files uri handling, added low-level tests
This commit is contained in:
1 parent
d198d67a9f
commit
bd7e64e85a
91 files changed
+958
-72
No files matched your search
+3
-1
@@ -79,6 +79,8 @@ downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
!test/resources/repos/dart/test_repo/lib/
|
||||
!test/resources/repos/dart/test_repo/lib/diagnostics_sample.dart
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
@@ -271,4 +273,4 @@ cabal.project.local*
|
||||
zz-misc/
|
||||
vue-implementation/
|
||||
|
||||
news/news.json
|
||||
news/news.json
|
||||
@@ -28,6 +28,7 @@ project_name: "serena"
|
||||
languages:
|
||||
- python
|
||||
- typescript
|
||||
- clojure
|
||||
|
||||
# whether to use project's .gitignore files to ignore files
|
||||
ignore_all_files_in_gitignore: true
|
||||
|
||||
@@ -16,6 +16,7 @@ from serena.tools import (
|
||||
JetBrainsFindSymbolTool,
|
||||
JetBrainsGetSymbolsOverviewTool,
|
||||
JetBrainsInlineSymbol,
|
||||
JetBrainsRunInspectionsTool,
|
||||
JetBrainsSafeDeleteTool,
|
||||
SearchForPatternTool,
|
||||
)
|
||||
@@ -35,12 +36,13 @@ if __name__ == "__main__":
|
||||
overview_tool = agent.get_tool(JetBrainsGetSymbolsOverviewTool)
|
||||
safe_delete_tool = agent.get_tool(JetBrainsSafeDeleteTool)
|
||||
inline_symbol = agent.get_tool(JetBrainsInlineSymbol)
|
||||
diagnostics_in_file_tool = agent.get_tool(GetDiagnosticsForFileTool)
|
||||
jb_inspections_tool = agent.get_tool(JetBrainsRunInspectionsTool)
|
||||
|
||||
result = agent.execute_task(
|
||||
lambda: overview_tool.apply(
|
||||
# name_path_pattern="SerenaAgent",
|
||||
relative_path="src/serena/agent.py",
|
||||
depth=2,
|
||||
relative_path="test/resources/repos/clojure/test_repo/src/test_app/diagnostics_sample.clj",
|
||||
# keep_definition=True,
|
||||
)
|
||||
)
|
||||
|
||||
@@ -689,7 +689,7 @@ class JetBrainsPluginClient(ToStringMixin):
|
||||
request_data["startLine"] = start_line
|
||||
if end_line is not None:
|
||||
request_data["endLine"] = end_line
|
||||
return cast(jb.RunInspectionsResponse, self._make_request("POST", "/runInspections", request_data))
|
||||
return cast(jb.RunInspectionsResponse, self._make_request("POST", "/runInspectionsOnFile", request_data))
|
||||
|
||||
def list_inspections(
|
||||
self,
|
||||
|
||||
@@ -32,9 +32,10 @@ class ElmLanguageServer(SolidLanguageServer):
|
||||
Creates an ElmLanguageServer instance. This class is not meant to be instantiated directly. Use LanguageServer.create() instead.
|
||||
"""
|
||||
elm_lsp_executable_path = self._setup_runtime_dependencies(config, solidlsp_settings)
|
||||
managed_bin_dir = os.path.join(self.ls_resources_dir(solidlsp_settings), "elm-lsp", "node_modules", ".bin")
|
||||
|
||||
# Resolve ELM_HOME to absolute path if it's set to a relative path
|
||||
env = {}
|
||||
env = {"PATH": managed_bin_dir + os.pathsep + os.environ.get("PATH", "")}
|
||||
elm_home = os.environ.get("ELM_HOME")
|
||||
if elm_home:
|
||||
if not os.path.isabs(elm_home):
|
||||
@@ -65,9 +66,15 @@ class ElmLanguageServer(SolidLanguageServer):
|
||||
"""
|
||||
Setup runtime dependencies for Elm Language Server and return the command to start the server.
|
||||
"""
|
||||
# Check if elm-language-server is already installed globally
|
||||
elm_config = solidlsp_settings.get_ls_specific_settings(Language.ELM)
|
||||
elm_language_server_version = elm_config.get("elm_language_server_version", "2.8.0")
|
||||
elm_compiler_version = elm_config.get("elm_compiler_version", "0.19.1-6")
|
||||
npm_registry = elm_config.get("npm_registry")
|
||||
|
||||
# Check if elm-language-server and elm are already installed globally
|
||||
system_elm_ls = shutil.which("elm-language-server")
|
||||
if system_elm_ls:
|
||||
system_elm = shutil.which("elm")
|
||||
if system_elm_ls and system_elm:
|
||||
log.info(f"Found system-installed elm-language-server at {system_elm_ls}")
|
||||
return [system_elm_ls, "--stdio"]
|
||||
|
||||
@@ -76,10 +83,6 @@ class ElmLanguageServer(SolidLanguageServer):
|
||||
assert is_node_installed, "node is not installed or isn't in PATH. Please install NodeJS and try again."
|
||||
is_npm_installed = shutil.which("npm") is not None
|
||||
assert is_npm_installed, "npm is not installed or isn't in PATH. Please install npm and try again."
|
||||
elm_config = solidlsp_settings.get_ls_specific_settings(Language.ELM)
|
||||
elm_language_server_version = elm_config.get("elm_language_server_version", "2.8.0")
|
||||
npm_registry = elm_config.get("npm_registry")
|
||||
|
||||
deps = RuntimeDependencyCollection(
|
||||
[
|
||||
RuntimeDependency(
|
||||
@@ -88,6 +91,12 @@ class ElmLanguageServer(SolidLanguageServer):
|
||||
command=build_npm_install_command("@elm-tooling/elm-language-server", elm_language_server_version, npm_registry),
|
||||
platform_id="any",
|
||||
),
|
||||
RuntimeDependency(
|
||||
id="elm",
|
||||
description="Elm compiler package",
|
||||
command=build_npm_install_command("elm", elm_compiler_version, npm_registry),
|
||||
platform_id="any",
|
||||
),
|
||||
]
|
||||
)
|
||||
|
||||
@@ -98,6 +107,10 @@ class ElmLanguageServer(SolidLanguageServer):
|
||||
log.info(f"Elm Language Server executable not found at {elm_ls_executable_path}. Installing...")
|
||||
with LogTime("Installation of Elm language server dependencies", logger=log):
|
||||
deps.install(elm_ls_dir)
|
||||
elif not system_elm:
|
||||
log.info("Elm compiler not found on PATH. Installing a managed Elm compiler...")
|
||||
with LogTime("Installation of Elm compiler dependency", logger=log):
|
||||
deps.install(elm_ls_dir)
|
||||
|
||||
if not os.path.exists(elm_ls_executable_path):
|
||||
raise FileNotFoundError(
|
||||
@@ -128,6 +141,7 @@ class ElmLanguageServer(SolidLanguageServer):
|
||||
"hover": {"dynamicRegistration": True, "contentFormat": ["markdown", "plaintext"]},
|
||||
"codeAction": {"dynamicRegistration": True},
|
||||
"rename": {"dynamicRegistration": True},
|
||||
"publishDiagnostics": {"relatedInformation": True},
|
||||
},
|
||||
"workspace": {
|
||||
"workspaceFolders": True,
|
||||
|
||||
@@ -220,6 +220,7 @@ class FortranLanguageServer(SolidLanguageServer):
|
||||
"formatting": {"dynamicRegistration": True},
|
||||
"rangeFormatting": {"dynamicRegistration": True},
|
||||
"codeAction": {"dynamicRegistration": True},
|
||||
"publishDiagnostics": {"relatedInformation": True},
|
||||
},
|
||||
"workspace": {
|
||||
"workspaceFolders": True,
|
||||
|
||||
@@ -124,6 +124,7 @@ class Lean4LanguageServer(SolidLanguageServer):
|
||||
"documentationFormat": ["markdown", "plaintext"],
|
||||
},
|
||||
},
|
||||
"publishDiagnostics": {"relatedInformation": True},
|
||||
},
|
||||
"workspace": {
|
||||
"workspaceFolders": True,
|
||||
|
||||
@@ -777,6 +777,14 @@ class PascalLanguageServer(SolidLanguageServer):
|
||||
if value:
|
||||
initialization_options[var] = value
|
||||
|
||||
initialization_options.update(
|
||||
{
|
||||
"checkSyntax": True,
|
||||
"publishDiagnostics": True,
|
||||
"showSyntaxErrors": True,
|
||||
}
|
||||
)
|
||||
|
||||
initialize_params = {
|
||||
"locale": "en",
|
||||
"capabilities": {
|
||||
@@ -831,6 +839,7 @@ class PascalLanguageServer(SolidLanguageServer):
|
||||
},
|
||||
"formatting": {"dynamicRegistration": True},
|
||||
"rangeFormatting": {"dynamicRegistration": True},
|
||||
"publishDiagnostics": {"relatedInformation": True},
|
||||
},
|
||||
"workspace": {
|
||||
"workspaceFolders": True,
|
||||
|
||||
@@ -148,6 +148,7 @@ class SolidityLanguageServer(SolidLanguageServer):
|
||||
"dynamicRegistration": True,
|
||||
"contentFormat": ["markdown", "plaintext"], # type: ignore[list-item]
|
||||
},
|
||||
"publishDiagnostics": {"relatedInformation": True},
|
||||
},
|
||||
"workspace": {
|
||||
"workspaceFolders": True,
|
||||
|
||||
@@ -89,7 +89,10 @@ class TypeScriptLanguageServer(SolidLanguageServer):
|
||||
self.server_ready = threading.Event()
|
||||
self.initialize_searcher_command_available = threading.Event()
|
||||
|
||||
# Progress tracking for $/progress notifications (project indexing, etc.)
|
||||
# tracking asynchronous diagnostics publication
|
||||
self._published_diagnostics_timeout = 5.0
|
||||
|
||||
# tracking project indexing progress
|
||||
self._progress_lock = threading.Lock()
|
||||
self._active_progress_tokens: set[str] = set()
|
||||
self._indexing_complete = threading.Event()
|
||||
@@ -243,9 +246,11 @@ class TypeScriptLanguageServer(SolidLanguageServer):
|
||||
"signatureHelp": {"dynamicRegistration": True},
|
||||
"codeAction": {"dynamicRegistration": True},
|
||||
"rename": {"dynamicRegistration": True, "prepareSupport": True},
|
||||
"publishDiagnostics": {"relatedInformation": True},
|
||||
},
|
||||
"workspace": {
|
||||
"workspaceFolders": True,
|
||||
"configuration": True,
|
||||
"didChangeConfiguration": {"dynamicRegistration": True},
|
||||
"symbol": {"dynamicRegistration": True},
|
||||
},
|
||||
@@ -293,6 +298,10 @@ class TypeScriptLanguageServer(SolidLanguageServer):
|
||||
def execute_client_command_handler(params: dict) -> list:
|
||||
return []
|
||||
|
||||
def configuration_handler(params: dict) -> list:
|
||||
items = params.get("items", [])
|
||||
return [{} for _ in items]
|
||||
|
||||
def do_nothing(params: dict) -> None:
|
||||
return
|
||||
|
||||
@@ -352,6 +361,7 @@ class TypeScriptLanguageServer(SolidLanguageServer):
|
||||
self._indexing_complete.set()
|
||||
|
||||
self.server.on_request("client/registerCapability", register_capability_handler)
|
||||
self.server.on_request("workspace/configuration", configuration_handler)
|
||||
self.server.on_notification("window/logMessage", window_log_message)
|
||||
self.server.on_request("workspace/executeClientCommand", execute_client_command_handler)
|
||||
self.server.on_request("window/workDoneProgress/create", work_done_progress_create)
|
||||
@@ -397,6 +407,20 @@ class TypeScriptLanguageServer(SolidLanguageServer):
|
||||
self.INDEXING_PROGRESS_TIMEOUT,
|
||||
)
|
||||
|
||||
@override
|
||||
def _get_published_diagnostics_uri(self, request_uri: str) -> str:
|
||||
if os.name != "nt" or not request_uri.startswith("file:///"):
|
||||
return request_uri
|
||||
|
||||
path_part = request_uri[len("file:///") :]
|
||||
if len(path_part) >= 2 and path_part[0].isalpha() and path_part[1] == ":":
|
||||
return f"file:///{path_part[0].lower()}%3A{path_part[2:]}"
|
||||
return request_uri
|
||||
|
||||
@override
|
||||
def _get_published_diagnostics_wait_timeout(self, pull_diagnostics_failed: bool) -> float:
|
||||
return self._published_diagnostics_timeout
|
||||
|
||||
@override
|
||||
def _get_wait_time_for_cross_file_referencing(self) -> float:
|
||||
return 2
|
||||
|
||||
@@ -426,6 +426,18 @@ class VueLanguageServer(SolidLanguageServer):
|
||||
with self._ts_server.open_file(relative_file_path):
|
||||
return self._ts_server.request_rename_symbol_edit(relative_file_path, line, column, new_name)
|
||||
|
||||
@override
|
||||
def request_text_document_diagnostics(
|
||||
self,
|
||||
relative_file_path: str,
|
||||
start_line: int = 0,
|
||||
end_line: int = -1,
|
||||
min_severity: int = 4,
|
||||
) -> list[ls_types.Diagnostic]:
|
||||
self._ensure_ls_operational()
|
||||
assert self._ts_server is not None
|
||||
return self._ts_server.request_text_document_diagnostics(relative_file_path, start_line, end_line, min_severity)
|
||||
|
||||
def _forward_edit_to_ts_server_if_needed(self, relative_file_path: str, edit_fn: Callable[[], object]) -> None:
|
||||
"""
|
||||
Calls ``edit_fn`` on the TypeScript server if the file is open there.
|
||||
@@ -598,6 +610,7 @@ class VueLanguageServer(SolidLanguageServer):
|
||||
"signatureHelp": {"dynamicRegistration": True},
|
||||
"codeAction": {"dynamicRegistration": True},
|
||||
"rename": {"dynamicRegistration": True, "prepareSupport": True},
|
||||
"publishDiagnostics": {"relatedInformation": True},
|
||||
},
|
||||
"workspace": {
|
||||
"workspaceFolders": True,
|
||||
|
||||
@@ -132,6 +132,7 @@ class ZigLanguageServer(SolidLanguageServer):
|
||||
"dynamicRegistration": True,
|
||||
"contentFormat": ["markdown", "plaintext"],
|
||||
},
|
||||
"publishDiagnostics": {"relatedInformation": True},
|
||||
},
|
||||
"workspace": {
|
||||
"workspaceFolders": True,
|
||||
|
||||
+67
-12
@@ -13,7 +13,7 @@ from collections.abc import Hashable, Iterator
|
||||
from contextlib import contextmanager
|
||||
from copy import copy
|
||||
from pathlib import Path, PurePath
|
||||
from time import perf_counter, sleep
|
||||
from time import monotonic, perf_counter, sleep
|
||||
from typing import Any, Self, Union, cast
|
||||
|
||||
import pathspec
|
||||
@@ -754,21 +754,77 @@ class SolidLanguageServer(ABC):
|
||||
:return: the published diagnostics, or ``None`` if no diagnostics are available.
|
||||
"""
|
||||
uri = self._validate_text_document_diagnostics_request(relative_file_path, start_line, end_line, min_severity)
|
||||
published_uri = self._get_published_diagnostics_uri(uri)
|
||||
diagnostics: list[ls_types.Diagnostic] | None = None
|
||||
|
||||
# keeping the document open
|
||||
with self.open_file(relative_file_path):
|
||||
diagnostics = self._wait_for_published_diagnostics(uri=uri, after_generation=after_generation, timeout=timeout)
|
||||
|
||||
# falling back to cached diagnostics
|
||||
if diagnostics is None and allow_cached:
|
||||
diagnostics = self._get_cached_published_diagnostics(uri)
|
||||
diagnostics = self._wait_for_relevant_published_diagnostics(
|
||||
uri=published_uri,
|
||||
after_generation=after_generation,
|
||||
timeout=timeout,
|
||||
allow_cached=allow_cached,
|
||||
)
|
||||
|
||||
if diagnostics is None:
|
||||
return None
|
||||
|
||||
return self._filter_diagnostics(diagnostics, start_line, end_line, min_severity)
|
||||
|
||||
def _get_published_diagnostics_uri(self, request_uri: str) -> str:
|
||||
"""
|
||||
Gets the URI under which published diagnostics should be looked up.
|
||||
"""
|
||||
return request_uri
|
||||
|
||||
def _get_published_diagnostics_wait_timeout(self, pull_diagnostics_failed: bool) -> float:
|
||||
"""
|
||||
Gets the timeout for waiting on published diagnostics after a diagnostics request.
|
||||
"""
|
||||
return 2.5
|
||||
|
||||
def _accept_published_diagnostics(self, diagnostics: list[ls_types.Diagnostic]) -> bool:
|
||||
"""
|
||||
Determines whether a published diagnostics payload should satisfy the current wait.
|
||||
"""
|
||||
return bool(diagnostics)
|
||||
|
||||
def _wait_for_relevant_published_diagnostics(
|
||||
self,
|
||||
uri: str,
|
||||
after_generation: int,
|
||||
timeout: float,
|
||||
allow_cached: bool = True,
|
||||
) -> list[ls_types.Diagnostic] | None:
|
||||
"""
|
||||
Waits for a published diagnostics payload that is relevant for the current request.
|
||||
"""
|
||||
deadline = monotonic() + timeout
|
||||
current_after_generation = after_generation
|
||||
|
||||
while True:
|
||||
remaining_timeout = deadline - monotonic()
|
||||
if remaining_timeout <= 0:
|
||||
break
|
||||
|
||||
diagnostics = self._wait_for_published_diagnostics(
|
||||
uri=uri,
|
||||
after_generation=current_after_generation,
|
||||
timeout=remaining_timeout,
|
||||
)
|
||||
if diagnostics is None:
|
||||
break
|
||||
if self._accept_published_diagnostics(diagnostics):
|
||||
return diagnostics
|
||||
current_after_generation = self._get_published_diagnostics_generation(uri)
|
||||
|
||||
if allow_cached:
|
||||
diagnostics = self._get_cached_published_diagnostics(uri)
|
||||
if diagnostics is not None and self._accept_published_diagnostics(diagnostics):
|
||||
return diagnostics
|
||||
|
||||
return None
|
||||
|
||||
def request_text_document_diagnostics(
|
||||
self,
|
||||
relative_file_path: str,
|
||||
@@ -789,7 +845,8 @@ class SolidLanguageServer(ABC):
|
||||
:return: A list of diagnostics for the file
|
||||
"""
|
||||
uri = self._validate_text_document_diagnostics_request(relative_file_path, start_line, end_line, min_severity)
|
||||
diagnostics_before_request = self._get_published_diagnostics_generation(uri)
|
||||
published_uri = self._get_published_diagnostics_uri(uri)
|
||||
diagnostics_before_request = self._get_published_diagnostics_generation(published_uri)
|
||||
ret: list[ls_types.Diagnostic] | None = None
|
||||
pull_diagnostics_failed = False
|
||||
|
||||
@@ -825,13 +882,11 @@ class SolidLanguageServer(ABC):
|
||||
ret.append(ls_types.Diagnostic(**new_item))
|
||||
|
||||
if not ret:
|
||||
published_diagnostics = self._wait_for_published_diagnostics(
|
||||
uri=uri,
|
||||
published_diagnostics = self._wait_for_relevant_published_diagnostics(
|
||||
uri=published_uri,
|
||||
after_generation=diagnostics_before_request,
|
||||
timeout=2.5 if pull_diagnostics_failed else 0.5,
|
||||
timeout=self._get_published_diagnostics_wait_timeout(pull_diagnostics_failed),
|
||||
)
|
||||
if published_diagnostics is None:
|
||||
published_diagnostics = self._get_cached_published_diagnostics(uri)
|
||||
if published_diagnostics is not None:
|
||||
ret = published_diagnostics
|
||||
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
#!/usr/bin/env bash
|
||||
if then
|
||||
echo "$missingGreeting"
|
||||
fi
|
||||
@@ -0,0 +1,5 @@
|
||||
def broken_factory : String
|
||||
missingGreeting
|
||||
end
|
||||
|
||||
broken_consumer = missingConsumerValue
|
||||
@@ -0,0 +1,3 @@
|
||||
String brokenFactory() {
|
||||
return 'broken'
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
defmodule DiagnosticsSample do
|
||||
def broken_factory do
|
||||
missing_greeting
|
||||
end
|
||||
|
||||
def broken_consumer do
|
||||
value = broken_factory()
|
||||
{value, missing_consumer_value}
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,5 @@
|
||||
module DiagnosticsSample exposing (brokenFactory)
|
||||
|
||||
brokenFactory : String
|
||||
brokenFactory =
|
||||
"unterminated
|
||||
@@ -0,0 +1,5 @@
|
||||
-module(diagnostics_sample).
|
||||
-export([broken_factory/0, broken_consumer/0]).
|
||||
|
||||
broken_factory() -> MissingGreeting.
|
||||
broken_consumer() -> MissingConsumerValue.
|
||||
@@ -0,0 +1,5 @@
|
||||
program diagnostics_sample
|
||||
implicit none
|
||||
integer :: duplicated_value
|
||||
real :: duplicated_value
|
||||
end program diagnostics_sample
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
package com.example
|
||||
|
||||
class DiagnosticsSample {
|
||||
static String brokenFactory() {
|
||||
missingGreeting
|
||||
}
|
||||
|
||||
static void brokenConsumer() {
|
||||
def value = brokenFactory()
|
||||
println(value)
|
||||
println(missingConsumerValue)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
module DiagnosticsSample where
|
||||
|
||||
brokenFactory :: String
|
||||
brokenFactory = missingGreeting
|
||||
|
||||
brokenConsumer :: String
|
||||
brokenConsumer = missingConsumerValue
|
||||
@@ -0,0 +1,10 @@
|
||||
class DiagnosticsSample {
|
||||
static function brokenFactory():String {
|
||||
return missingGreeting;
|
||||
}
|
||||
|
||||
static function brokenConsumer():Void {
|
||||
trace(brokenFactory());
|
||||
trace(missingConsumerValue);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
float4 main() : SV_Target {
|
||||
return missingGreeting;
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"name": "diagnostics",
|
||||
"value":
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
function broken_factory(
|
||||
value = 1
|
||||
end
|
||||
@@ -1,6 +1 @@
|
||||
def brokenFactory : Nat :=
|
||||
missingGreeting
|
||||
|
||||
def brokenConsumer : Nat :=
|
||||
let value := brokenFactory
|
||||
value + missingConsumerValue
|
||||
@@ -0,0 +1,3 @@
|
||||
function value = diagnostics_sample()
|
||||
value = missingGreeting;
|
||||
end
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
greeting = missingGreeting;
|
||||
consumer = missingConsumerValue;
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
let broken_factory (
|
||||
@@ -1,3 +1,4 @@
|
||||
(library
|
||||
(public_name test_repo)
|
||||
(name test_repo))
|
||||
(name test_repo)
|
||||
(modules test_repo))
|
||||
@@ -0,0 +1,4 @@
|
||||
program DiagnosticsSample;
|
||||
begin
|
||||
writeln(
|
||||
end.
|
||||
@@ -0,0 +1,5 @@
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
print $missingGreeting;
|
||||
print $missingConsumerValue;
|
||||
@@ -1,9 +1,4 @@
|
||||
function Invoke-BrokenFactory {
|
||||
Invoke-MissingGreeting
|
||||
}
|
||||
|
||||
function Invoke-BrokenConsumer {
|
||||
$value = Invoke-BrokenFactory
|
||||
Write-Output $value
|
||||
Invoke-MissingConsumerValue
|
||||
if ($true) {
|
||||
Write-Output "broken"
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
package com.example
|
||||
|
||||
object DiagnosticsSample {
|
||||
def brokenFactory(): String = missingGreeting
|
||||
def brokenConsumer(): Unit = {
|
||||
println(brokenFactory())
|
||||
println(missingConsumerValue)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
contract DiagnosticsSample {
|
||||
function brokenFactory() pure returns (string memory) {
|
||||
return "broken";
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,7 @@ let package = Package(
|
||||
targets: [
|
||||
.target(
|
||||
name: "test_repo",
|
||||
dependencies: []),
|
||||
dependencies: [],
|
||||
path: "src"),
|
||||
]
|
||||
)
|
||||
)
|
||||
@@ -0,0 +1,3 @@
|
||||
func brokenFactory() -> String {
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
module diagnostics_sample;
|
||||
initial begin
|
||||
if (
|
||||
end
|
||||
endmodule
|
||||
@@ -0,0 +1,4 @@
|
||||
resource "aws_instance" "broken" {
|
||||
ami =
|
||||
instance_type = "t2.micro"
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
[diagnostics]
|
||||
value =
|
||||
@@ -0,0 +1,3 @@
|
||||
<script setup lang="ts">
|
||||
const value: string =
|
||||
</script>
|
||||
@@ -0,0 +1,5 @@
|
||||
name: diagnostics
|
||||
value:
|
||||
- good
|
||||
-
|
||||
broken: [
|
||||
@@ -28,4 +28,4 @@ pub fn build(b: *std.Build) void {
|
||||
const run_lib_tests = b.addRunArtifact(lib_tests);
|
||||
const test_step = b.step("test", "Run unit tests");
|
||||
test_step.dependOn(&run_lib_tests.step);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
pub fn brokenFactory() void {
|
||||
const value =
|
||||
}
|
||||
@@ -29,4 +29,4 @@ pub fn main() !void {
|
||||
|
||||
pub fn greeting(name: []const u8) []const u8 {
|
||||
return std.fmt.allocPrint(std.heap.page_allocator, "Hello, {s}!", .{name}) catch "Hello!";
|
||||
}
|
||||
}
|
||||
@@ -68,13 +68,13 @@
|
||||
# name: test_delete_symbol[test_case1]
|
||||
'''
|
||||
import { ConsoleGreeter, Greeter } from "./formatters";
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
export function helperFunction() {
|
||||
const demo = new DemoClass(42);
|
||||
demo.printValue();
|
||||
|
||||
|
||||
const greeter: Greeter = new ConsoleGreeter();
|
||||
console.log(greeter.formatGreeting("World"));
|
||||
}
|
||||
@@ -521,7 +521,7 @@
|
||||
# name: test_insert_in_rel_to_symbol[test_case1-after]
|
||||
'''
|
||||
import { ConsoleGreeter, Greeter } from "./formatters";
|
||||
|
||||
|
||||
export class DemoClass {
|
||||
value: number;
|
||||
constructor(value: number) {
|
||||
@@ -539,7 +539,7 @@
|
||||
export function helperFunction() {
|
||||
const demo = new DemoClass(42);
|
||||
demo.printValue();
|
||||
|
||||
|
||||
const greeter: Greeter = new ConsoleGreeter();
|
||||
console.log(greeter.formatGreeting("World"));
|
||||
}
|
||||
@@ -555,7 +555,7 @@
|
||||
# name: test_insert_in_rel_to_symbol[test_case1-before]
|
||||
'''
|
||||
import { ConsoleGreeter, Greeter } from "./formatters";
|
||||
|
||||
|
||||
function newFunctionAfterClass(): void {
|
||||
console.log("This function is after DemoClass.");
|
||||
}
|
||||
@@ -573,7 +573,7 @@
|
||||
export function helperFunction() {
|
||||
const demo = new DemoClass(42);
|
||||
demo.printValue();
|
||||
|
||||
|
||||
const greeter: Greeter = new ConsoleGreeter();
|
||||
console.log(greeter.formatGreeting("World"));
|
||||
}
|
||||
@@ -589,7 +589,7 @@
|
||||
# name: test_insert_in_rel_to_symbol[test_case2-after]
|
||||
'''
|
||||
import { ConsoleGreeter, Greeter } from "./formatters";
|
||||
|
||||
|
||||
export class DemoClass {
|
||||
value: number;
|
||||
constructor(value: number) {
|
||||
@@ -603,7 +603,7 @@
|
||||
export function helperFunction() {
|
||||
const demo = new DemoClass(42);
|
||||
demo.printValue();
|
||||
|
||||
|
||||
const greeter: Greeter = new ConsoleGreeter();
|
||||
console.log(greeter.formatGreeting("World"));
|
||||
}
|
||||
@@ -623,7 +623,7 @@
|
||||
# name: test_insert_in_rel_to_symbol[test_case2-before]
|
||||
'''
|
||||
import { ConsoleGreeter, Greeter } from "./formatters";
|
||||
|
||||
|
||||
export class DemoClass {
|
||||
value: number;
|
||||
constructor(value: number) {
|
||||
@@ -641,7 +641,7 @@
|
||||
export function helperFunction() {
|
||||
const demo = new DemoClass(42);
|
||||
demo.printValue();
|
||||
|
||||
|
||||
const greeter: Greeter = new ConsoleGreeter();
|
||||
console.log(greeter.formatGreeting("World"));
|
||||
}
|
||||
@@ -1712,7 +1712,7 @@
|
||||
# name: test_replace_body[test_case1]
|
||||
'''
|
||||
import { ConsoleGreeter, Greeter } from "./formatters";
|
||||
|
||||
|
||||
export class DemoClass {
|
||||
value: number;
|
||||
constructor(value: number) {
|
||||
@@ -1727,7 +1727,7 @@
|
||||
export function helperFunction() {
|
||||
const demo = new DemoClass(42);
|
||||
demo.printValue();
|
||||
|
||||
|
||||
const greeter: Greeter = new ConsoleGreeter();
|
||||
console.log(greeter.formatGreeting("World"));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
import pytest
|
||||
|
||||
from solidlsp import SolidLanguageServer
|
||||
from solidlsp.ls_config import Language
|
||||
from test.solidlsp.util.diagnostics import assert_file_diagnostics
|
||||
|
||||
|
||||
@pytest.mark.bash
|
||||
class TestBashDiagnostics:
|
||||
@pytest.mark.parametrize("language_server", [Language.BASH], indirect=True)
|
||||
def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None:
|
||||
assert_file_diagnostics(
|
||||
language_server,
|
||||
"diagnostics_sample.sh",
|
||||
(),
|
||||
min_count=1,
|
||||
)
|
||||
@@ -13,8 +13,8 @@ def _test_clojure_cli() -> bool:
|
||||
|
||||
CLI_FAIL = _test_clojure_cli()
|
||||
TEST_APP_PATH = Path("src") / "test_app"
|
||||
CORE_PATH = str(TEST_APP_PATH / "core.clj").replace("\\", "/")
|
||||
UTILS_PATH = str(TEST_APP_PATH / "utils.clj").replace("\\", "/")
|
||||
CORE_PATH = str(TEST_APP_PATH / "core.clj")
|
||||
UTILS_PATH = str(TEST_APP_PATH / "utils.clj")
|
||||
|
||||
|
||||
def is_clojure_cli_available() -> bool:
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
import os
|
||||
|
||||
import pytest
|
||||
|
||||
from solidlsp import SolidLanguageServer
|
||||
from solidlsp.ls_config import Language
|
||||
from test.solidlsp.util.diagnostics import assert_file_diagnostics
|
||||
|
||||
|
||||
@pytest.mark.clojure
|
||||
class TestClojureDiagnostics:
|
||||
@pytest.mark.parametrize("language_server", [Language.CLOJURE], indirect=True)
|
||||
def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None:
|
||||
assert_file_diagnostics(
|
||||
language_server,
|
||||
os.path.join("src", "test_app", "diagnostics_sample.clj"),
|
||||
("missing-greeting", "missing-consumer-value"),
|
||||
min_count=2,
|
||||
)
|
||||
@@ -5,6 +5,12 @@ from solidlsp.ls_types import SymbolKind, UnifiedSymbolInformation
|
||||
PYTHON_BACKEND_LANGUAGES = [Language.PYTHON, Language.PYTHON_TY]
|
||||
|
||||
|
||||
def is_diagnostics_test_file(relative_path: str) -> bool:
|
||||
normalized_path = relative_path.replace("\\", "/")
|
||||
filename = normalized_path.rsplit("/", 1)[-1].lower()
|
||||
return filename.startswith(("diagnosticssample.", "diagnostics_sample."))
|
||||
|
||||
|
||||
def has_malformed_name(
|
||||
symbol: UnifiedSymbolInformation,
|
||||
whitespace_allowed: bool = False,
|
||||
@@ -36,6 +42,9 @@ def request_all_symbols(language_server: SolidLanguageServer) -> list[UnifiedSym
|
||||
result: list[UnifiedSymbolInformation] = []
|
||||
|
||||
def visit(symbol: UnifiedSymbolInformation) -> None:
|
||||
relative_path = symbol.get("location", {}).get("relativePath", "")
|
||||
if relative_path and is_diagnostics_test_file(relative_path):
|
||||
return
|
||||
result.append(symbol)
|
||||
for child in symbol.get("children", []):
|
||||
visit(child)
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
import pytest
|
||||
|
||||
from solidlsp import SolidLanguageServer
|
||||
from solidlsp.ls_config import Language
|
||||
from test.solidlsp.util.diagnostics import assert_file_diagnostics
|
||||
|
||||
|
||||
@pytest.mark.cpp
|
||||
class TestCppDiagnostics:
|
||||
@pytest.mark.parametrize("language_server", [Language.CPP], indirect=True)
|
||||
def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None:
|
||||
assert_file_diagnostics(
|
||||
language_server,
|
||||
"diagnostics_sample.cpp",
|
||||
(),
|
||||
min_count=1,
|
||||
)
|
||||
@@ -0,0 +1,23 @@
|
||||
import shutil
|
||||
|
||||
import pytest
|
||||
|
||||
from solidlsp import SolidLanguageServer
|
||||
from solidlsp.ls_config import Language
|
||||
from test.solidlsp.util.diagnostics import assert_file_diagnostics
|
||||
|
||||
pytestmark = [
|
||||
pytest.mark.crystal,
|
||||
pytest.mark.skipif(shutil.which("crystalline") is None, reason="Crystalline is not installed"),
|
||||
]
|
||||
|
||||
|
||||
class TestCrystalDiagnostics:
|
||||
@pytest.mark.parametrize("language_server", [Language.CRYSTAL], indirect=True)
|
||||
def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None:
|
||||
assert_file_diagnostics(
|
||||
language_server,
|
||||
"src/diagnostics_sample.cr",
|
||||
(),
|
||||
min_count=1,
|
||||
)
|
||||
@@ -0,0 +1,17 @@
|
||||
import pytest
|
||||
|
||||
from solidlsp import SolidLanguageServer
|
||||
from solidlsp.ls_config import Language
|
||||
from test.solidlsp.util.diagnostics import assert_file_diagnostics
|
||||
|
||||
|
||||
@pytest.mark.csharp
|
||||
class TestCsharpDiagnostics:
|
||||
@pytest.mark.parametrize("language_server", [Language.CSHARP], indirect=True)
|
||||
def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None:
|
||||
assert_file_diagnostics(
|
||||
language_server,
|
||||
"DiagnosticsSample.cs",
|
||||
(),
|
||||
min_count=1,
|
||||
)
|
||||
@@ -0,0 +1,17 @@
|
||||
import pytest
|
||||
|
||||
from solidlsp import SolidLanguageServer
|
||||
from solidlsp.ls_config import Language
|
||||
from test.solidlsp.util.diagnostics import assert_file_diagnostics
|
||||
|
||||
|
||||
@pytest.mark.dart
|
||||
class TestDartDiagnostics:
|
||||
@pytest.mark.parametrize("language_server", [Language.DART], indirect=True)
|
||||
def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None:
|
||||
assert_file_diagnostics(
|
||||
language_server,
|
||||
"lib/diagnostics_sample.dart",
|
||||
(),
|
||||
min_count=1,
|
||||
)
|
||||
@@ -13,6 +13,7 @@ from solidlsp import SolidLanguageServer
|
||||
from solidlsp.ls_config import Language
|
||||
from solidlsp.ls_types import SymbolKind
|
||||
from test.solidlsp.conftest import format_symbol_for_assert, has_malformed_name, request_all_symbols
|
||||
from test.solidlsp.util.diagnostics import assert_file_diagnostics
|
||||
|
||||
from . import EXPERT_UNAVAILABLE, EXPERT_UNAVAILABLE_REASON
|
||||
|
||||
@@ -138,3 +139,12 @@ class TestElixirBasic:
|
||||
f"Found malformed symbols: {[format_symbol_for_assert(sym) for sym in malformed_symbols]}",
|
||||
pytrace=False,
|
||||
)
|
||||
|
||||
@pytest.mark.parametrize("language_server", [Language.ELIXIR], indirect=True)
|
||||
def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None:
|
||||
assert_file_diagnostics(
|
||||
language_server,
|
||||
"lib/diagnostics_sample.ex",
|
||||
(),
|
||||
min_count=1,
|
||||
)
|
||||
@@ -0,0 +1,20 @@
|
||||
import shutil
|
||||
|
||||
import pytest
|
||||
|
||||
from solidlsp import SolidLanguageServer
|
||||
from solidlsp.ls_config import Language
|
||||
from test.solidlsp.util.diagnostics import assert_file_diagnostics
|
||||
|
||||
|
||||
@pytest.mark.elm
|
||||
@pytest.mark.skipif(shutil.which("node") is None or shutil.which("npm") is None, reason="Elm diagnostics require Node.js and npm")
|
||||
class TestElmDiagnostics:
|
||||
@pytest.mark.parametrize("language_server", [Language.ELM], indirect=True)
|
||||
def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None:
|
||||
assert_file_diagnostics(
|
||||
language_server,
|
||||
"DiagnosticsSample.elm",
|
||||
(),
|
||||
min_count=1,
|
||||
)
|
||||
@@ -10,6 +10,7 @@ import pytest
|
||||
from solidlsp import SolidLanguageServer
|
||||
from solidlsp.ls_config import Language
|
||||
from test.solidlsp.conftest import format_symbol_for_assert, has_malformed_name, request_all_symbols
|
||||
from test.solidlsp.util.diagnostics import assert_file_diagnostics
|
||||
|
||||
from . import ERLANG_LS_UNAVAILABLE, ERLANG_LS_UNAVAILABLE_REASON
|
||||
|
||||
@@ -55,3 +56,12 @@ class TestErlangLanguageServerBasics:
|
||||
f"Found malformed symbols: {[format_symbol_for_assert(sym) for sym in malformed_symbols]}",
|
||||
pytrace=False,
|
||||
)
|
||||
|
||||
@pytest.mark.parametrize("language_server", [Language.ERLANG], indirect=True)
|
||||
def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None:
|
||||
assert_file_diagnostics(
|
||||
language_server,
|
||||
"src/diagnostics_sample.erl",
|
||||
(),
|
||||
min_count=1,
|
||||
)
|
||||
@@ -0,0 +1,17 @@
|
||||
import pytest
|
||||
|
||||
from solidlsp import SolidLanguageServer
|
||||
from solidlsp.ls_config import Language
|
||||
from test.solidlsp.util.diagnostics import assert_file_diagnostics
|
||||
|
||||
|
||||
@pytest.mark.fortran
|
||||
class TestFortranDiagnostics:
|
||||
@pytest.mark.parametrize("language_server", [Language.FORTRAN], indirect=True)
|
||||
def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None:
|
||||
assert_file_diagnostics(
|
||||
language_server,
|
||||
"diagnostics_sample.f90",
|
||||
(),
|
||||
min_count=1,
|
||||
)
|
||||
@@ -9,6 +9,7 @@ from solidlsp.ls_config import Language
|
||||
from solidlsp.ls_utils import SymbolUtils
|
||||
from test.conftest import find_identifier_position, get_repo_path, is_ci, language_has_verified_implementation_support
|
||||
from test.solidlsp.conftest import format_symbol_for_assert, has_malformed_name, request_all_symbols
|
||||
from test.solidlsp.util.diagnostics import assert_file_diagnostics
|
||||
|
||||
|
||||
# Currently, most F# tests fail, there seems to be a regression or instability.
|
||||
@@ -196,21 +197,13 @@ class TestFSharpLanguageServer:
|
||||
assert isinstance(result["value"], list), "Completions should be a list"
|
||||
|
||||
@pytest.mark.parametrize("language_server", [Language.FSHARP], indirect=True)
|
||||
def test_diagnostics(self, language_server: SolidLanguageServer) -> None:
|
||||
"""Test getting diagnostics (errors, warnings) from F# files."""
|
||||
file_path = os.path.join("Program.fs")
|
||||
|
||||
# FsAutoComplete uses publishDiagnostics notifications instead of textDocument/diagnostic requests
|
||||
# So we'll test that the language server can handle files without crashing
|
||||
# In real usage, diagnostics would come through the publishDiagnostics notification handler
|
||||
|
||||
# Test that we can at least work with the file (open/close cycle)
|
||||
with language_server.open_file(file_path) as _:
|
||||
# If we can open and close the file without errors, basic diagnostics support is working
|
||||
pass
|
||||
|
||||
# This is a successful test - FsAutoComplete is working with F# files
|
||||
assert True, "F# language server can handle files successfully"
|
||||
def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None:
|
||||
assert_file_diagnostics(
|
||||
language_server,
|
||||
"DiagnosticsSample.fs",
|
||||
(),
|
||||
min_count=1,
|
||||
)
|
||||
|
||||
@pytest.mark.parametrize("language_server", [Language.FSHARP], indirect=True)
|
||||
def test_bare_symbol_names(self, language_server) -> None:
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
import pytest
|
||||
|
||||
from solidlsp import SolidLanguageServer
|
||||
from solidlsp.ls_config import Language
|
||||
from test.solidlsp.util.diagnostics import assert_file_diagnostics
|
||||
|
||||
|
||||
@pytest.mark.go
|
||||
class TestGoDiagnostics:
|
||||
@pytest.mark.parametrize("language_server", [Language.GO], indirect=True)
|
||||
def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None:
|
||||
assert_file_diagnostics(
|
||||
language_server,
|
||||
"diagnostics_sample.go",
|
||||
("missingGreeting", "missingConsumerValue"),
|
||||
min_count=2,
|
||||
)
|
||||
@@ -9,6 +9,7 @@ from solidlsp.ls_config import Language, LanguageServerConfig
|
||||
from solidlsp.ls_utils import SymbolUtils
|
||||
from solidlsp.settings import SolidLSPSettings
|
||||
from test.solidlsp.conftest import format_symbol_for_assert, has_malformed_name, request_all_symbols
|
||||
from test.solidlsp.util.diagnostics import assert_file_diagnostics
|
||||
|
||||
|
||||
@pytest.mark.groovy
|
||||
@@ -117,3 +118,12 @@ class TestGroovyLanguageServer:
|
||||
f"Found malformed symbols: {[format_symbol_for_assert(sym) for sym in malformed_symbols]}",
|
||||
pytrace=False,
|
||||
)
|
||||
|
||||
def test_file_diagnostics(self) -> None:
|
||||
assert self.language_server is not None
|
||||
assert_file_diagnostics(
|
||||
self.language_server,
|
||||
"src/main/groovy/com/example/DiagnosticsSample.groovy",
|
||||
(),
|
||||
min_count=1,
|
||||
)
|
||||
@@ -21,6 +21,7 @@ from solidlsp.ls import SolidLanguageServer
|
||||
from solidlsp.ls_config import Language
|
||||
from solidlsp.ls_types import SymbolKind
|
||||
from test.solidlsp.conftest import format_symbol_for_assert, has_malformed_name, request_all_symbols
|
||||
from test.solidlsp.util.diagnostics import assert_file_diagnostics
|
||||
|
||||
|
||||
@pytest.mark.haskell
|
||||
@@ -240,3 +241,12 @@ class TestHaskellLanguageServer:
|
||||
for sym in malformed_symbols
|
||||
]
|
||||
pytest.fail(f"Found malformed symbols: {diagnostics}", pytrace=False)
|
||||
|
||||
@pytest.mark.parametrize("language_server", [Language.HASKELL], indirect=True)
|
||||
def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None:
|
||||
assert_file_diagnostics(
|
||||
language_server,
|
||||
"src/DiagnosticsSample.hs",
|
||||
(),
|
||||
min_count=1,
|
||||
)
|
||||
@@ -0,0 +1,17 @@
|
||||
import pytest
|
||||
|
||||
from solidlsp import SolidLanguageServer
|
||||
from solidlsp.ls_config import Language
|
||||
from test.solidlsp.util.diagnostics import assert_file_diagnostics
|
||||
|
||||
|
||||
@pytest.mark.haxe
|
||||
class TestHaxeDiagnostics:
|
||||
@pytest.mark.parametrize("language_server", [Language.HAXE], indirect=True)
|
||||
def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None:
|
||||
assert_file_diagnostics(
|
||||
language_server,
|
||||
"src/DiagnosticsSample.hx",
|
||||
(),
|
||||
min_count=1,
|
||||
)
|
||||
@@ -0,0 +1,17 @@
|
||||
import pytest
|
||||
|
||||
from solidlsp import SolidLanguageServer
|
||||
from solidlsp.ls_config import Language
|
||||
from test.solidlsp.util.diagnostics import assert_file_diagnostics
|
||||
|
||||
|
||||
@pytest.mark.hlsl
|
||||
class TestHlslDiagnostics:
|
||||
@pytest.mark.parametrize("language_server", [Language.HLSL], indirect=True)
|
||||
def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None:
|
||||
assert_file_diagnostics(
|
||||
language_server,
|
||||
"diagnostics_sample.hlsl",
|
||||
(),
|
||||
min_count=1,
|
||||
)
|
||||
@@ -0,0 +1,17 @@
|
||||
import pytest
|
||||
|
||||
from solidlsp import SolidLanguageServer
|
||||
from solidlsp.ls_config import Language
|
||||
from test.solidlsp.util.diagnostics import assert_file_diagnostics
|
||||
|
||||
|
||||
@pytest.mark.java
|
||||
class TestJavaDiagnostics:
|
||||
@pytest.mark.parametrize("language_server", [Language.JAVA], indirect=True)
|
||||
def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None:
|
||||
assert_file_diagnostics(
|
||||
language_server,
|
||||
"src/main/java/test_repo/DiagnosticsSample.java",
|
||||
(),
|
||||
min_count=1,
|
||||
)
|
||||
@@ -0,0 +1,17 @@
|
||||
import pytest
|
||||
|
||||
from solidlsp import SolidLanguageServer
|
||||
from solidlsp.ls_config import Language
|
||||
from test.solidlsp.util.diagnostics import assert_file_diagnostics
|
||||
|
||||
|
||||
@pytest.mark.json
|
||||
class TestJsonDiagnostics:
|
||||
@pytest.mark.parametrize("language_server", [Language.JSON], indirect=True)
|
||||
def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None:
|
||||
assert_file_diagnostics(
|
||||
language_server,
|
||||
"diagnostics_sample.json",
|
||||
(),
|
||||
min_count=1,
|
||||
)
|
||||
@@ -6,6 +6,7 @@ from solidlsp.ls import SolidLanguageServer
|
||||
from solidlsp.ls_config import Language
|
||||
from test.conftest import is_ci
|
||||
from test.solidlsp.conftest import format_symbol_for_assert, has_malformed_name, request_all_symbols
|
||||
from test.solidlsp.util.diagnostics import assert_file_diagnostics
|
||||
|
||||
|
||||
@pytest.mark.skipif(shutil.which("julia") is None and not is_ci, reason="Julia is not available")
|
||||
@@ -66,3 +67,12 @@ class TestJuliaLanguageServer:
|
||||
f"Found malformed symbols: {[format_symbol_for_assert(sym) for sym in malformed_symbols]}",
|
||||
pytrace=False,
|
||||
)
|
||||
|
||||
@pytest.mark.parametrize("language_server", [Language.JULIA], indirect=True)
|
||||
def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None:
|
||||
assert_file_diagnostics(
|
||||
language_server,
|
||||
"diagnostics_sample.jl",
|
||||
(),
|
||||
min_count=1,
|
||||
)
|
||||
@@ -0,0 +1,17 @@
|
||||
import pytest
|
||||
|
||||
from solidlsp import SolidLanguageServer
|
||||
from solidlsp.ls_config import Language
|
||||
from test.solidlsp.util.diagnostics import assert_file_diagnostics
|
||||
|
||||
|
||||
@pytest.mark.kotlin
|
||||
class TestKotlinDiagnostics:
|
||||
@pytest.mark.parametrize("language_server", [Language.KOTLIN], indirect=True)
|
||||
def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None:
|
||||
assert_file_diagnostics(
|
||||
language_server,
|
||||
"src/main/kotlin/test_repo/DiagnosticsSample.kt",
|
||||
(),
|
||||
min_count=1,
|
||||
)
|
||||
@@ -0,0 +1,17 @@
|
||||
import pytest
|
||||
|
||||
from solidlsp import SolidLanguageServer
|
||||
from solidlsp.ls_config import Language
|
||||
from test.solidlsp.util.diagnostics import assert_file_diagnostics
|
||||
|
||||
|
||||
@pytest.mark.lean4
|
||||
class TestLean4Diagnostics:
|
||||
@pytest.mark.parametrize("language_server", [Language.LEAN4], indirect=True)
|
||||
def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None:
|
||||
assert_file_diagnostics(
|
||||
language_server,
|
||||
"DiagnosticsSample.lean",
|
||||
(),
|
||||
min_count=1,
|
||||
)
|
||||
@@ -17,6 +17,7 @@ import pytest
|
||||
from solidlsp import SolidLanguageServer
|
||||
from solidlsp.ls_config import Language
|
||||
from test.solidlsp.conftest import format_symbol_for_assert, has_malformed_name, request_all_symbols
|
||||
from test.solidlsp.util.diagnostics import assert_file_diagnostics
|
||||
|
||||
# Skip all tests if MATLAB is not available
|
||||
pytestmark = pytest.mark.matlab
|
||||
@@ -129,3 +130,12 @@ class TestMatlabLanguageServerReferences:
|
||||
f"Found malformed symbols: {[format_symbol_for_assert(sym) for sym in malformed_symbols]}",
|
||||
pytrace=False,
|
||||
)
|
||||
|
||||
@pytest.mark.parametrize("language_server", [Language.MATLAB], indirect=True)
|
||||
def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None:
|
||||
assert_file_diagnostics(
|
||||
language_server,
|
||||
"diagnostics_sample.m",
|
||||
(),
|
||||
min_count=1,
|
||||
)
|
||||
@@ -13,6 +13,7 @@ from solidlsp.ls_config import Language
|
||||
from solidlsp.ls_types import SymbolKind
|
||||
from test.conftest import is_ci
|
||||
from test.solidlsp.conftest import format_symbol_for_assert, has_malformed_name, request_all_symbols
|
||||
from test.solidlsp.util.diagnostics import assert_file_diagnostics
|
||||
|
||||
# Skip all Nix tests on Windows as Nix doesn't support Windows
|
||||
pytestmark = pytest.mark.skipif(platform.system() == "Windows", reason="Nix and nil are not available on Windows")
|
||||
@@ -250,3 +251,12 @@ class TestNixLanguageServer:
|
||||
f"Found malformed symbols: {[format_symbol_for_assert(sym) for sym in malformed_symbols]}",
|
||||
pytrace=False,
|
||||
)
|
||||
|
||||
@pytest.mark.parametrize("language_server", [Language.NIX], indirect=True)
|
||||
def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None:
|
||||
assert_file_diagnostics(
|
||||
language_server,
|
||||
"diagnostics_sample.nix",
|
||||
(),
|
||||
min_count=1,
|
||||
)
|
||||
@@ -0,0 +1,17 @@
|
||||
import pytest
|
||||
|
||||
from solidlsp import SolidLanguageServer
|
||||
from solidlsp.ls_config import Language
|
||||
from test.solidlsp.util.diagnostics import assert_file_diagnostics
|
||||
|
||||
|
||||
@pytest.mark.ocaml
|
||||
class TestOcamlDiagnostics:
|
||||
@pytest.mark.parametrize("language_server", [Language.OCAML], indirect=True)
|
||||
def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None:
|
||||
assert_file_diagnostics(
|
||||
language_server,
|
||||
"lib/diagnostics_sample.ml",
|
||||
(),
|
||||
min_count=1,
|
||||
)
|
||||
@@ -0,0 +1,25 @@
|
||||
import shutil
|
||||
|
||||
import pytest
|
||||
|
||||
from solidlsp import SolidLanguageServer
|
||||
from solidlsp.ls_config import Language
|
||||
from test.conftest import language_tests_enabled
|
||||
from test.solidlsp.util.diagnostics import assert_file_diagnostics
|
||||
|
||||
pytestmark = [
|
||||
pytest.mark.pascal,
|
||||
pytest.mark.skipif(not language_tests_enabled(Language.PASCAL), reason="Pascal tests are disabled"),
|
||||
pytest.mark.skipif(shutil.which("fpc") is None, reason="Pascal diagnostics require the Free Pascal compiler"),
|
||||
]
|
||||
|
||||
|
||||
class TestPascalDiagnostics:
|
||||
@pytest.mark.parametrize("language_server", [Language.PASCAL], indirect=True)
|
||||
def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None:
|
||||
assert_file_diagnostics(
|
||||
language_server,
|
||||
"diagnostics_sample.pas",
|
||||
(),
|
||||
min_count=1,
|
||||
)
|
||||
@@ -6,6 +6,7 @@ import pytest
|
||||
from solidlsp import SolidLanguageServer
|
||||
from solidlsp.ls_config import Language
|
||||
from test.solidlsp.conftest import format_symbol_for_assert, has_malformed_name, request_all_symbols
|
||||
from test.solidlsp.util.diagnostics import assert_file_diagnostics
|
||||
|
||||
|
||||
@pytest.mark.perl
|
||||
@@ -88,3 +89,12 @@ class TestPerlLanguageServer:
|
||||
f"Found malformed symbols: {[format_symbol_for_assert(sym) for sym in malformed_symbols]}",
|
||||
pytrace=False,
|
||||
)
|
||||
|
||||
@pytest.mark.parametrize("language_server", [Language.PERL], indirect=True)
|
||||
def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None:
|
||||
assert_file_diagnostics(
|
||||
language_server,
|
||||
"diagnostics_sample.pl",
|
||||
(),
|
||||
min_count=1,
|
||||
)
|
||||
@@ -0,0 +1,17 @@
|
||||
import pytest
|
||||
|
||||
from solidlsp import SolidLanguageServer
|
||||
from solidlsp.ls_config import Language
|
||||
from test.solidlsp.util.diagnostics import assert_file_diagnostics
|
||||
|
||||
|
||||
@pytest.mark.php
|
||||
class TestPhpDiagnostics:
|
||||
@pytest.mark.parametrize("language_server", [Language.PHP], indirect=True)
|
||||
def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None:
|
||||
assert_file_diagnostics(
|
||||
language_server,
|
||||
"diagnostics_sample.php",
|
||||
(),
|
||||
min_count=1,
|
||||
)
|
||||
@@ -0,0 +1,17 @@
|
||||
import pytest
|
||||
|
||||
from solidlsp import SolidLanguageServer
|
||||
from solidlsp.ls_config import Language
|
||||
from test.solidlsp.util.diagnostics import assert_file_diagnostics
|
||||
|
||||
|
||||
@pytest.mark.powershell
|
||||
class TestPowershellDiagnostics:
|
||||
@pytest.mark.parametrize("language_server", [Language.POWERSHELL], indirect=True)
|
||||
def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None:
|
||||
assert_file_diagnostics(
|
||||
language_server,
|
||||
"diagnostics_sample.ps1",
|
||||
(),
|
||||
min_count=1,
|
||||
)
|
||||
@@ -0,0 +1,19 @@
|
||||
import os
|
||||
|
||||
import pytest
|
||||
|
||||
from solidlsp import SolidLanguageServer
|
||||
from test.conftest import PYTHON_LANGUAGE_BACKENDS
|
||||
from test.solidlsp.util.diagnostics import assert_file_diagnostics
|
||||
|
||||
|
||||
@pytest.mark.python
|
||||
class TestPythonDiagnostics:
|
||||
@pytest.mark.parametrize("language_server", PYTHON_LANGUAGE_BACKENDS, indirect=True)
|
||||
def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None:
|
||||
assert_file_diagnostics(
|
||||
language_server,
|
||||
os.path.join("test_repo", "diagnostics_sample.py"),
|
||||
("missing_user", "undefined_name"),
|
||||
min_count=2,
|
||||
)
|
||||
@@ -90,7 +90,7 @@ class TestRustLanguageServer:
|
||||
all_symbols = request_all_symbols(language_server)
|
||||
malformed_symbols = []
|
||||
for s in all_symbols:
|
||||
if has_malformed_name(s):
|
||||
if has_malformed_name(s, whitespace_allowed=True):
|
||||
malformed_symbols.append(s)
|
||||
if malformed_symbols:
|
||||
pytest.fail(
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
import pytest
|
||||
|
||||
from solidlsp import SolidLanguageServer
|
||||
from solidlsp.ls_config import Language
|
||||
from test.solidlsp.util.diagnostics import assert_file_diagnostics
|
||||
|
||||
|
||||
@pytest.mark.rust
|
||||
class TestRustDiagnostics:
|
||||
@pytest.mark.parametrize("language_server", [Language.RUST], indirect=True)
|
||||
def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None:
|
||||
assert_file_diagnostics(
|
||||
language_server,
|
||||
"src/diagnostics_sample.rs",
|
||||
(),
|
||||
min_count=1,
|
||||
)
|
||||
@@ -6,6 +6,7 @@ import pytest
|
||||
from solidlsp.language_servers.scala_language_server import ScalaLanguageServer
|
||||
from solidlsp.ls_config import Language, LanguageServerConfig
|
||||
from solidlsp.settings import SolidLSPSettings
|
||||
from test.solidlsp.util.diagnostics import assert_file_diagnostics
|
||||
|
||||
pytest.skip("Scala must be compiled for these tests to run through, which is a huge hassle", allow_module_level=True)
|
||||
|
||||
@@ -62,3 +63,12 @@ def test_scala_find_definition_and_references_across_files(scala_ls):
|
||||
assert first_def["range"]["start"]["character"] == 6
|
||||
assert first_def["range"]["end"]["line"] == 7
|
||||
assert first_def["range"]["end"]["character"] == 14
|
||||
|
||||
|
||||
def test_file_diagnostics(scala_ls) -> None:
|
||||
assert_file_diagnostics(
|
||||
scala_ls,
|
||||
"src/main/scala/com/example/DiagnosticsSample.scala",
|
||||
(),
|
||||
min_count=1,
|
||||
)
|
||||
@@ -0,0 +1,24 @@
|
||||
import sys
|
||||
|
||||
import pytest
|
||||
|
||||
from solidlsp import SolidLanguageServer
|
||||
from solidlsp.ls_config import Language
|
||||
from test.solidlsp.util.diagnostics import assert_file_diagnostics
|
||||
|
||||
|
||||
@pytest.mark.solidity
|
||||
class TestSolidityDiagnostics:
|
||||
@pytest.mark.xfail(
|
||||
sys.platform == "darwin",
|
||||
reason="Unknown — passes on Ubuntu but consistently fails on macOS CI; root cause not yet identified.",
|
||||
strict=False,
|
||||
)
|
||||
@pytest.mark.parametrize("language_server", [Language.SOLIDITY], indirect=True)
|
||||
def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None:
|
||||
assert_file_diagnostics(
|
||||
language_server,
|
||||
"contracts/DiagnosticsSample.sol",
|
||||
(),
|
||||
min_count=1,
|
||||
)
|
||||
@@ -16,6 +16,7 @@ from solidlsp import SolidLanguageServer
|
||||
from solidlsp.ls_config import Language
|
||||
from test.conftest import is_ci
|
||||
from test.solidlsp.conftest import format_symbol_for_assert, has_malformed_name, request_all_symbols
|
||||
from test.solidlsp.util.diagnostics import assert_file_diagnostics
|
||||
|
||||
# Skip Swift tests on Windows due to complex GitHub Actions configuration
|
||||
WINDOWS_SKIP = platform.system() == "Windows"
|
||||
@@ -238,3 +239,12 @@ class TestSwiftProjectBasics:
|
||||
f"Found malformed symbols: {[format_symbol_for_assert(sym) for sym in malformed_symbols]}",
|
||||
pytrace=False,
|
||||
)
|
||||
|
||||
@pytest.mark.parametrize("language_server", [Language.SWIFT], indirect=True)
|
||||
def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None:
|
||||
assert_file_diagnostics(
|
||||
language_server,
|
||||
"src/diagnostics_sample.swift",
|
||||
(),
|
||||
min_count=1,
|
||||
)
|
||||
@@ -0,0 +1,17 @@
|
||||
import pytest
|
||||
|
||||
from solidlsp import SolidLanguageServer
|
||||
from solidlsp.ls_config import Language
|
||||
from test.solidlsp.util.diagnostics import assert_file_diagnostics
|
||||
|
||||
|
||||
@pytest.mark.systemverilog
|
||||
class TestSystemverilogDiagnostics:
|
||||
@pytest.mark.parametrize("language_server", [Language.SYSTEMVERILOG], indirect=True)
|
||||
def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None:
|
||||
assert_file_diagnostics(
|
||||
language_server,
|
||||
"diagnostics_sample.sv",
|
||||
(),
|
||||
min_count=1,
|
||||
)
|
||||
@@ -0,0 +1,17 @@
|
||||
import pytest
|
||||
|
||||
from solidlsp import SolidLanguageServer
|
||||
from solidlsp.ls_config import Language
|
||||
from test.solidlsp.util.diagnostics import assert_file_diagnostics
|
||||
|
||||
|
||||
@pytest.mark.terraform
|
||||
class TestTerraformDiagnostics:
|
||||
@pytest.mark.parametrize("language_server", [Language.TERRAFORM], indirect=True)
|
||||
def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None:
|
||||
assert_file_diagnostics(
|
||||
language_server,
|
||||
"diagnostics_sample.tf",
|
||||
(),
|
||||
min_count=1,
|
||||
)
|
||||
@@ -0,0 +1,17 @@
|
||||
import pytest
|
||||
|
||||
from solidlsp import SolidLanguageServer
|
||||
from solidlsp.ls_config import Language
|
||||
from test.solidlsp.util.diagnostics import assert_file_diagnostics
|
||||
|
||||
|
||||
@pytest.mark.toml
|
||||
class TestTomlDiagnostics:
|
||||
@pytest.mark.parametrize("language_server", [Language.TOML], indirect=True)
|
||||
def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None:
|
||||
assert_file_diagnostics(
|
||||
language_server,
|
||||
"diagnostics_sample.toml",
|
||||
(),
|
||||
min_count=1,
|
||||
)
|
||||
@@ -0,0 +1,17 @@
|
||||
import pytest
|
||||
|
||||
from solidlsp import SolidLanguageServer
|
||||
from solidlsp.ls_config import Language
|
||||
from test.solidlsp.util.diagnostics import assert_file_diagnostics
|
||||
|
||||
|
||||
@pytest.mark.typescript
|
||||
class TestTypeScriptDiagnostics:
|
||||
@pytest.mark.parametrize("language_server", [Language.TYPESCRIPT], indirect=True)
|
||||
def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None:
|
||||
assert_file_diagnostics(
|
||||
language_server,
|
||||
"diagnostics_sample.ts",
|
||||
("missingGreeting", "missingConsumerValue"),
|
||||
min_count=2,
|
||||
)
|
||||
@@ -0,0 +1,19 @@
|
||||
from collections.abc import Sequence
|
||||
|
||||
from solidlsp import SolidLanguageServer
|
||||
|
||||
|
||||
def assert_file_diagnostics(
|
||||
language_server: SolidLanguageServer,
|
||||
relative_file_path: str,
|
||||
expected_message_fragments: Sequence[str],
|
||||
min_count: int = 1,
|
||||
) -> None:
|
||||
diagnostics = language_server.request_text_document_diagnostics(relative_file_path, min_severity=1)
|
||||
|
||||
assert isinstance(diagnostics, list), diagnostics
|
||||
assert len(diagnostics) >= min_count, diagnostics
|
||||
|
||||
diagnostic_messages = [diagnostic["message"] for diagnostic in diagnostics]
|
||||
for fragment in expected_message_fragments:
|
||||
assert any(fragment in message for message in diagnostic_messages), diagnostic_messages
|
||||
@@ -0,0 +1,17 @@
|
||||
import pytest
|
||||
|
||||
from solidlsp import SolidLanguageServer
|
||||
from solidlsp.ls_config import Language
|
||||
from test.solidlsp.util.diagnostics import assert_file_diagnostics
|
||||
|
||||
|
||||
@pytest.mark.vue
|
||||
class TestVueDiagnostics:
|
||||
@pytest.mark.parametrize("language_server", [Language.VUE], indirect=True)
|
||||
def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None:
|
||||
assert_file_diagnostics(
|
||||
language_server,
|
||||
"src/DiagnosticsSample.vue",
|
||||
(),
|
||||
min_count=1,
|
||||
)
|
||||
@@ -0,0 +1,17 @@
|
||||
import pytest
|
||||
|
||||
from solidlsp import SolidLanguageServer
|
||||
from solidlsp.ls_config import Language
|
||||
from test.solidlsp.util.diagnostics import assert_file_diagnostics
|
||||
|
||||
|
||||
@pytest.mark.yaml
|
||||
class TestYamlDiagnostics:
|
||||
@pytest.mark.parametrize("language_server", [Language.YAML], indirect=True)
|
||||
def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None:
|
||||
assert_file_diagnostics(
|
||||
language_server,
|
||||
"diagnostics_sample.yaml",
|
||||
(),
|
||||
min_count=1,
|
||||
)
|
||||
@@ -14,6 +14,7 @@ from solidlsp import SolidLanguageServer
|
||||
from solidlsp.ls_config import Language
|
||||
from solidlsp.ls_types import SymbolKind
|
||||
from test.solidlsp.conftest import format_symbol_for_assert, has_malformed_name, request_all_symbols
|
||||
from test.solidlsp.util.diagnostics import assert_file_diagnostics
|
||||
|
||||
|
||||
@pytest.mark.zig
|
||||
@@ -355,3 +356,12 @@ class TestZigLanguageServer:
|
||||
f"Found malformed symbols: {[format_symbol_for_assert(sym) for sym in malformed_symbols]}",
|
||||
pytrace=False,
|
||||
)
|
||||
|
||||
@pytest.mark.parametrize("language_server", [Language.ZIG], indirect=True)
|
||||
def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None:
|
||||
assert_file_diagnostics(
|
||||
language_server,
|
||||
"src/diagnostics_sample.zig",
|
||||
(),
|
||||
min_count=1,
|
||||
)
|
||||
Reference in new issue
Block a user