This commit is contained in:
Miguel de Benito Delgado committed 2025-06-28 14:00:21 +02:00
1 parent 5cedba39e3
commit f24ee42592
2 files changed
+48 -54

No files matched your search

@@ -2,20 +2,19 @@
Provides Clojure specific instantiation of the LanguageServer class. Contains various configurations and settings specific to Clojure.
"""
import threading
import json
import logging
import os
import stat
import pathlib
import stat
import threading
from solidlsp.ls_logger import LanguageServerLogger
from solidlsp.ls import SolidLanguageServer
from solidlsp.lsp_protocol_handler.server import ProcessLaunchInfo
from solidlsp.lsp_protocol_handler.lsp_types import InitializeParams
from solidlsp.ls_config import LanguageServerConfig
from solidlsp.ls_utils import FileUtils
from solidlsp.ls_utils import PlatformUtils
from solidlsp.ls_logger import LanguageServerLogger
from solidlsp.ls_utils import FileUtils, PlatformUtils
from solidlsp.lsp_protocol_handler.lsp_types import InitializeParams
from solidlsp.lsp_protocol_handler.server import ProcessLaunchInfo
class ClojureLSP(SolidLanguageServer):
@@ -46,7 +45,7 @@ class ClojureLSP(SolidLanguageServer):
"""
platform_id = PlatformUtils.get_platform_id()
with open(os.path.join(os.path.dirname(__file__), "runtime_dependencies.json"), "r", encoding="utf-8") as f:
with open(os.path.join(os.path.dirname(__file__), "runtime_dependencies.json"), encoding="utf-8") as f:
d = json.load(f)
del d["_description"]
@@ -73,7 +72,7 @@ class ClojureLSP(SolidLanguageServer):
"""
Returns the init params for clojure-lsp.
"""
with open(os.path.join(os.path.dirname(__file__), "initialize_params.json"), "r", encoding="utf-8") as f:
with open(os.path.join(os.path.dirname(__file__), "initialize_params.json"), encoding="utf-8") as f:
d = json.load(f)
del d["_description"]
+40 -45
View File
@@ -1,13 +1,12 @@
import pytest
from solidlsp.ls import SolidLanguageServer
from solidlsp.ls import SolidLanguageServer
from solidlsp.ls_config import Language
from solidlsp.ls_types import UnifiedSymbolInformation
@pytest.mark.clojure
class TestLanguageServerBasics:
@pytest.mark.parametrize("language_server", [Language.CLOJURE], indirect=True)
def test_basic_definition(self, language_server: SolidLanguageServer):
"""
@@ -18,7 +17,7 @@ class TestLanguageServerBasics:
assert isinstance(result, list)
assert len(result) >= 1
definition = result[0]
assert definition["relativePath"] == "src/test_app/core.clj"
assert definition["range"]["start"]["line"] == 2, \
@@ -43,7 +42,6 @@ class TestLanguageServerBasics:
)
assert usage_found, "Should find multiply usage in utils.clj"
@pytest.mark.parametrize("language_server", [Language.CLOJURE], indirect=True)
def test_completions(self, language_server: SolidLanguageServer):
filepath = "src/test_app/utils.clj"
@@ -58,7 +56,6 @@ class TestLanguageServerBasics:
completion_texts = [item["completionText"] for item in result]
assert any("multiply" in text for text in completion_texts)
@pytest.mark.parametrize("language_server", [Language.CLOJURE], indirect=True)
def test_document_symbols(self, language_server: SolidLanguageServer):
filepath = "src/test_app/core.clj"
@@ -70,15 +67,14 @@ class TestLanguageServerBasics:
# Check that we find the expected function symbols
symbol_names = [symbol["name"] for symbol in symbols]
expected_functions = ["greet", "add", "multiply", "-main"]
for func_name in expected_functions:
assert func_name in symbol_names, f"Should find {func_name} function in symbols"
@pytest.mark.parametrize("language_server", [Language.CLOJURE], indirect=True)
def test_hover(self, language_server: SolidLanguageServer):
# Test hover on greet function
filepath = "src/test_app/core.clj"
filepath = "src/test_app/core.clj"
result = language_server.request_hover(filepath, 2, 7) # Position on 'greet' function name
assert result is not None, "Hover should return information for greet function"
@@ -92,7 +88,6 @@ class TestLanguageServerBasics:
else:
assert False, f"Unexpected contents format: {type(contents)}"
@pytest.mark.parametrize("language_server", [Language.CLOJURE], indirect=True)
def test_workspace_symbols(self, language_server: SolidLanguageServer):
# Search for functions containing "add"
@@ -111,18 +106,18 @@ class TestLanguageServerBasics:
def test_retrieve_content_around_line(self, language_server: SolidLanguageServer):
"""Test retrieving content around specific lines"""
filepath = "src/test_app/core.clj"
# Test retrieving content around the greet function definition (line 2)
result = language_server.retrieve_content_around_line(filepath, 2, 2)
assert result is not None, "Should retrieve content around line 2"
content_str = result.to_display_string()
assert "greet" in content_str, "Should contain the greet function definition"
assert "defn" in content_str, "Should contain defn keyword"
# Test retrieving content around multiply function (around line 13)
# Test retrieving content around multiply function (around line 13)
result = language_server.retrieve_content_around_line(filepath, 13, 1)
assert result is not None, "Should retrieve content around line 13"
content_str = result.to_display_string()
assert "multiply" in content_str, "Should contain multiply function"
@@ -131,12 +126,12 @@ class TestLanguageServerBasics:
def test_namespace_functions(self, language_server: SolidLanguageServer):
"""Test definition lookup for core/greet usage in utils.clj"""
filepath = "src/test_app/utils.clj"
# Position of 'greet' in core/greet call
# Position of 'greet' in core/greet call
result = language_server.request_definition(filepath, 11, 25)
assert isinstance(result, list)
assert len(result) >= 1
definition = result[0]
assert definition["relativePath"] == "src/test_app/core.clj",\
"Should find the definition of greet in core.clj"
@@ -144,38 +139,38 @@ class TestLanguageServerBasics:
@pytest.mark.parametrize("language_server", [Language.CLOJURE], indirect=True)
def test_search_files_for_pattern(self, language_server: SolidLanguageServer):
result = language_server.search_files_for_pattern("defn.*greet")
assert result is not None, "Pattern search should return results"
assert len(result) > 0, "Should find at least one match for 'defn.*greet'"
core_matches = [match for match in result if match.source_file_path and "core.clj" in match.source_file_path]
assert len(core_matches) > 0, "Should find greet function in core.clj"
result = language_server.search_files_for_pattern(":require")
assert result is not None, "Should find require statements"
utils_matches = [match for match in result if match.source_file_path and "utils.clj" in match.source_file_path]
assert len(utils_matches) > 0, "Should find require statement in utils.clj"
@pytest.mark.parametrize("language_server", [Language.CLOJURE], indirect=True)
def test_request_references_with_content(self, language_server: SolidLanguageServer):
"""Test references to multiply function with content"""
filepath = "src/test_app/core.clj"
result = language_server.request_references_with_content(filepath, 12, 6, 3)
assert result is not None, "Should find references with content"
assert isinstance(result, list)
assert len(result) >= 2, "Should find definition + usage in utils.clj"
for ref in result:
assert ref.source_file_path is not None, "Each reference should have a source file path"
content_str = ref.to_display_string()
assert len(content_str) > 0, "Content should not be empty"
# Verify we find the reference in utils.clj with context
utils_refs = [ref for ref in result if ref.source_file_path and "utils.clj" in ref.source_file_path]
assert len(utils_refs) > 0, "Should find reference in utils.clj"
# The context should contain the calculate-area function
utils_content = utils_refs[0].to_display_string()
assert "calculate-area" in utils_content
@@ -186,55 +181,55 @@ class TestLanguageServerBasics:
We just check that we find some expected symbols.
"""
result = language_server.request_full_symbol_tree()
assert result is not None, "Should return symbol tree"
assert isinstance(result, list), "Symbol tree should be a list"
assert len(result) > 0, "Should find symbols in the project"
def traverse_symbols(symbols, indent=0):
"""Recursively traverse symbols to print their structure"""
info = []
for s in symbols:
name = getattr(s, 'name', 'NO_NAME')
kind = getattr(s, 'kind', 'NO_KIND')
info.append(f'{" " * indent}Symbol: {name}, Kind: {kind}')
if hasattr(s, 'children') and s.children:
name = getattr(s, "name", "NO_NAME")
kind = getattr(s, "kind", "NO_KIND")
info.append(f"{' ' * indent}Symbol: {name}, Kind: {kind}")
if hasattr(s, "children") and s.children:
info.append(" " * indent + "Children:")
info.extend(traverse_symbols(s.children, indent + 2))
return info
def list_all_symbols(symbols: list[UnifiedSymbolInformation]):
found = []
for symbol in symbols:
found.append(symbol["name"])
found.extend(list_all_symbols(symbol["children"]))
return found
all_symbol_names = list_all_symbols(result)
expected_symbols = ["greet", "add", "multiply", "-main", "calculate-area", "format-greeting", "sum-list"]
found_expected = [name for name in expected_symbols if any(name in symbol_name for symbol_name in all_symbol_names)]
if len(found_expected) < 7:
pytest.fail(f"Expected to find at least 3 symbols from {expected_symbols}, but found: {found_expected}.\n"
f"All symbol names: {all_symbol_names}\n"
f"Symbol tree structure:\n{traverse_symbols(result)}")
if len(found_expected) < 7:
pytest.fail(
f"Expected to find at least 3 symbols from {expected_symbols}, but found: {found_expected}.\n"
f"All symbol names: {all_symbol_names}\n"
f"Symbol tree structure:\n{traverse_symbols(result)}"
)
@pytest.mark.parametrize("language_server", [Language.CLOJURE], indirect=True)
def test_request_referencing_symbols(self, language_server: SolidLanguageServer):
"""Test finding symbols that reference a given symbol
Finds references to the 'multiply' function.
"""
filepath = "src/test_app/core.clj"
result = language_server.request_referencing_symbols(filepath, 12, 6)
"""
filepath = "src/test_app/core.clj"
result = language_server.request_referencing_symbols(filepath, 12, 6)
assert isinstance(result, list) and len(result) > 0, \
"Should find at least one referencing symbol"
found_relevant_references = False
for ref in result:
if hasattr(ref, 'symbol') and "calculate-area" in ref.symbol["name"]:
if hasattr(ref, "symbol") and "calculate-area" in ref.symbol["name"]:
found_relevant_references = True
break
assert found_relevant_references, f"Should have found calculate-area referencing multiply, but got: {result}"