Files
wehub-resource-sync c6af9e284a
Tests / catch-all (windows-latest) (push) Has been cancelled
Tests / jvm (macos-latest) (push) Has been cancelled
Tests / jvm (ubuntu-latest) (push) Has been cancelled
Tests / jvm (windows-latest) (push) Has been cancelled
Tests / native (macos-latest) (push) Has been cancelled
Tests / native (ubuntu-latest) (push) Has been cancelled
Tests / native (windows-latest) (push) Has been cancelled
Tests / niche (ubuntu-latest) (push) Has been cancelled
Tests / other-langs (macos-latest) (push) Has been cancelled
Tests / other-langs (ubuntu-latest) (push) Has been cancelled
Tests / other-langs (windows-latest) (push) Has been cancelled
Tests / catch-all (macos-latest) (push) Has been cancelled
Tests / catch-all (ubuntu-latest) (push) Has been cancelled
Docs Build / build (push) Has been cancelled
Docs Build / deploy (push) Has been cancelled
CodeQL Advanced / Analyze (actions) (push) Has been cancelled
CodeQL Advanced / Analyze (javascript-typescript) (push) Has been cancelled
CodeQL Advanced / Analyze (python) (push) Has been cancelled
Codespell / Check for spelling errors (push) Has been cancelled
Build and Push Docker Images / build-and-push (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:39:38 +08:00

146 lines
8.4 KiB
Python

"""Basic integration tests for the CUE language server (``cue lsp``)."""
from pathlib import Path
import pytest
from solidlsp import SolidLanguageServer
from solidlsp.ls_config import Language
from solidlsp.ls_utils import SymbolUtils
from test.solidlsp.conftest import format_symbol_for_assert, has_malformed_name, request_all_symbols
@pytest.mark.cue
class TestCueLanguageServer:
"""Verifies that ``cue lsp`` drives the symbol and reference APIs Serena depends on.
The test repo (``test/resources/repos/cue/test_repo``) defines three CUE files that
share package ``testrepo`` and cross-reference each other's definitions:
- ``schema.cue`` defines ``#Person``, ``#Greeting``, ``defaultLocale``.
- ``lib.cue`` defines ``#BuildGreeting`` (which uses ``#Person`` and ``#Greeting``) and
``locales``.
- ``main.cue`` defines ``alice: #Person & {...}``, ``greetingForAlice: (#BuildGreeting & {...})``,
and ``locale: defaultLocale``.
Line/character positions below are 0-indexed (LSP convention) and were captured from
``cue lsp v0.16.1`` responses against this repository.
"""
@pytest.mark.parametrize("language_server", [Language.CUE], indirect=True)
@pytest.mark.parametrize("repo_path", [Language.CUE], indirect=True)
def test_ls_is_running(self, language_server: SolidLanguageServer, repo_path: Path) -> None:
"""The server starts and reports the expected repository root."""
assert language_server.is_running()
assert Path(language_server.language_server.repository_root_path).resolve() == repo_path.resolve()
@pytest.mark.parametrize("language_server", [Language.CUE], indirect=True)
def test_document_symbols_schema(self, language_server: SolidLanguageServer) -> None:
"""``schema.cue`` exposes its top-level definitions with the expected hierarchy."""
# request hierarchical document symbols for schema.cue
all_symbols, root_symbols = language_server.request_document_symbols("schema.cue").get_all_symbols_and_roots()
# schema.cue's three top-level definitions must appear as roots
root_names = [s.get("name") for s in root_symbols]
for expected in ("#Person", "#Greeting", "defaultLocale"):
assert expected in root_names, f"{expected} missing from schema.cue roots: {root_names}"
# #Person's field children must be nested under it (hierarchical response, not flat)
person = next(s for s in root_symbols if s.get("name") == "#Person")
person_children = [c.get("name") for c in person.get("children", [])]
for expected_field in ("name", "age", "email"):
assert expected_field in person_children, f"{expected_field} missing under #Person: {person_children}"
# fields must not also appear at root level (that would be the flat fallback)
assert "name" not in root_names, f"name should be a child of #Person, not a root. Roots: {root_names}"
@pytest.mark.parametrize("language_server", [Language.CUE], indirect=True)
def test_full_symbol_tree_contains_cross_file_names(self, language_server: SolidLanguageServer) -> None:
"""The repository-wide symbol tree contains definitions from all three CUE files."""
symbols = language_server.request_full_symbol_tree()
for expected in (
"#Person", # schema.cue
"#Greeting", # schema.cue
"defaultLocale", # schema.cue
"#BuildGreeting", # lib.cue
"locales", # lib.cue
"alice", # main.cue
"greetingForAlice", # main.cue
"locale", # main.cue
):
assert SymbolUtils.symbol_tree_contains_name(symbols, expected), f"{expected} missing from full symbol tree"
@pytest.mark.parametrize("language_server", [Language.CUE], indirect=True)
@pytest.mark.parametrize("repo_path", [Language.CUE], indirect=True)
def test_find_definition_across_files(self, language_server: SolidLanguageServer, repo_path: Path) -> None:
"""``#Person`` used in ``main.cue`` resolves to its definition in ``schema.cue``."""
# main.cue line 3 (0-indexed): "alice: #Person & {"
# ^ char 7 — cursor on '#Person'
definitions = language_server.request_definition(str(repo_path / "main.cue"), 3, 8)
assert definitions, f"Expected a definition for #Person, got {definitions=}"
# definition must live in schema.cue at line 3 (0-indexed), char 0
target = definitions[0]
assert target["uri"].endswith("schema.cue")
assert target["range"]["start"] == {"line": 3, "character": 0}
@pytest.mark.parametrize("language_server", [Language.CUE], indirect=True)
@pytest.mark.parametrize("repo_path", [Language.CUE], indirect=True)
def test_find_references_across_files_person(self, language_server: SolidLanguageServer, repo_path: Path) -> None:
"""``#Person`` has references in ``lib.cue`` and ``main.cue`` beyond its declaration."""
schema_path = str(repo_path / "schema.cue")
# schema.cue line 3 (0-indexed): "#Person: {" — cursor on the identifier
references = language_server.request_references(schema_path, 3, 1)
assert references, f"Expected references for #Person, got {references=}"
# collapse to (filename, start_line) tuples for set-based assertions
ref_pairs = {(ref["uri"].split("/")[-1], ref["range"]["start"]["line"]) for ref in references}
# must include use sites in lib.cue (line 5, in `for_: #Person`) and
# main.cue (line 3, in `alice: #Person & {`)
assert ("lib.cue", 5) in ref_pairs, f"Expected lib.cue:5 reference, got {sorted(ref_pairs)}"
assert ("main.cue", 3) in ref_pairs, f"Expected main.cue:3 reference, got {sorted(ref_pairs)}"
@pytest.mark.parametrize("language_server", [Language.CUE], indirect=True)
@pytest.mark.parametrize("repo_path", [Language.CUE], indirect=True)
def test_find_references_within_file_build_greeting(self, language_server: SolidLanguageServer, repo_path: Path) -> None:
"""``#BuildGreeting`` (defined in lib.cue) is referenced from main.cue."""
lib_path = str(repo_path / "lib.cue")
# lib.cue line 4 (0-indexed): "#BuildGreeting: {"
references = language_server.request_references(lib_path, 4, 1)
assert references, f"Expected references for #BuildGreeting, got {references=}"
ref_pairs = {(ref["uri"].split("/")[-1], ref["range"]["start"]["line"]) for ref in references}
# use site in main.cue is line 10: "greetingForAlice: (#BuildGreeting & {for_: alice}).result"
assert ("main.cue", 10) in ref_pairs, f"Expected main.cue:10 reference, got {sorted(ref_pairs)}"
@pytest.mark.parametrize("language_server", [Language.CUE], indirect=True)
@pytest.mark.parametrize("repo_path", [Language.CUE], indirect=True)
def test_find_references_default_locale(self, language_server: SolidLanguageServer, repo_path: Path) -> None:
"""``defaultLocale`` (schema.cue) is used in main.cue."""
schema_path = str(repo_path / "schema.cue")
# schema.cue line 16 (0-indexed): 'defaultLocale: "en-US"'
references = language_server.request_references(schema_path, 16, 1)
assert references, f"Expected references for defaultLocale, got {references=}"
ref_pairs = {(ref["uri"].split("/")[-1], ref["range"]["start"]["line"]) for ref in references}
# use site in main.cue is line 13: "locale: defaultLocale"
assert ("main.cue", 13) in ref_pairs, f"Expected main.cue:13 reference, got {sorted(ref_pairs)}"
@pytest.mark.parametrize("language_server", [Language.CUE], indirect=True)
def test_bare_symbol_names(self, language_server: SolidLanguageServer) -> None:
"""CUE symbols must have bare names (no whitespace/bracket/paren/comma/colon pollution)."""
# `.` is allowed because the synthetic directory symbol for `cue.mod/` contains a literal
# period — CUE modules are always anchored under a directory named `cue.mod`.
# `#` in names like `#Person` is part of the identifier in CUE's grammar and is not
# in the forbidden-char set.
malformed_symbols = [s for s in request_all_symbols(language_server) if has_malformed_name(s, period_allowed=True)]
if malformed_symbols:
pytest.fail(
f"Found malformed symbols: {[format_symbol_for_assert(sym) for sym in malformed_symbols]}",
pytrace=False,
)