diff --git a/.serena/memories/adding_new_language_support_guide.md b/.serena/memories/adding_new_language_support_guide.md index db470b94..e80f1cf8 100644 --- a/.serena/memories/adding_new_language_support_guide.md +++ b/.serena/memories/adding_new_language_support_guide.md @@ -111,12 +111,12 @@ For an example, see `EclipseJDTLS._start_server`. ## Step 2: Language Registration -### 2.1 Add to Language Enum +### 2.1 Add to LanguageServerId Enum -In `src/solidlsp/ls_config.py`, add your language to the `Language` enum: +In `src/solidlsp/ls_config.py`, add your language to the enum: ```python -class Language(str, Enum): +class LanguageServerId(str, Enum): # Existing languages... NEW_LANGUAGE = "new_language" @@ -125,20 +125,15 @@ class Language(str, Enum): # Existing cases... case self.NEW_LANGUAGE: return FilenameMatcher(".newlang", ".nl") # File extensions -``` -### 2.2 Update Language Server Factory - -In `src/solidlsp/ls.py`, add your language to the `create` method: - -```python -@classmethod -def create(cls, config: LanguageServerConfig, repository_root_path: str) -> "SolidLanguageServer": - match config.code_language: - # Existing cases... - case Language.NEW_LANGUAGE: - from solidlsp.language_servers.new_language_server import NewLanguageServer - return NewLanguageServer(config, repository_root_path) + ... + + def get_ls_class(self) -> type["SolidLanguageServer"]: + match self: + # Existing cases... + case self.NEW_LANGUAGE: + from solidlsp.language_servers.new_language_server import NewLanguageServer + return NewLanguageServer ``` ## Step 3: Test Repository @@ -214,10 +209,6 @@ You should at least test: Have a look at `test/solidlsp/php/test_php_basic.py` as an example for what should be tested. Don't forget to add a new language marker to `pytest.ini`. -### 4.2 Integration Tests - -Consider adding new cases to the parametrized tests in `test_serena_agent.py` for the new language. - ### 5 Documentation diff --git a/scripts/demo_diagnostics.py b/scripts/demo_diagnostics.py index 2e5cd30e..e5c73603 100644 --- a/scripts/demo_diagnostics.py +++ b/scripts/demo_diagnostics.py @@ -23,7 +23,7 @@ from serena.tools import ( GetDiagnosticsForSymbolTool, ReplaceContentTool, ) -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId SEPARATOR = "=" * 80 REPO_PATH = Path(REPO_ROOT) @@ -40,7 +40,7 @@ def make_agent() -> SerenaAgent: project_root=str(REPO_PATH), project_config=ProjectConfig( project_name="demo_serena_repo", - languages=[Language.PYTHON], + languages=[LanguageServerId.PYTHON], ignored_paths=[], excluded_tools=[], read_only=False, diff --git a/scripts/demo_find_defining_symbol.py b/scripts/demo_find_defining_symbol.py index 63bde56c..339a6502 100644 --- a/scripts/demo_find_defining_symbol.py +++ b/scripts/demo_find_defining_symbol.py @@ -12,14 +12,14 @@ from serena.config.serena_config import LanguageBackend, ProjectConfig, Register from serena.constants import REPO_ROOT from serena.project import Project from serena.tools import FindDeclarationTool -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId SEPARATOR = "=" * 80 PYTHON_TEST_REPO = Path(REPO_ROOT) / "test" / "resources" / "repos" / "python" / "test_repo" SERVICES_FILE = Path("test_repo") / "services.py" -def make_agent(project_root: Path, language: Language, project_name: str) -> SerenaAgent: +def make_agent(project_root: Path, language: LanguageServerId, project_name: str) -> SerenaAgent: """Create an LSP-backed Serena agent for a single explicit project.""" serena_config = SerenaConfig.from_config_file() serena_config.web_dashboard = False @@ -64,7 +64,7 @@ def find_identifier_occurrence_position(file_path: Path, identifier: str, occurr if __name__ == "__main__": - agent = make_agent(PYTHON_TEST_REPO, Language.PYTHON, "demo_python_test_repo") + agent = make_agent(PYTHON_TEST_REPO, LanguageServerId.PYTHON, "demo_python_test_repo") try: # letting the language server finish startup diff --git a/scripts/demo_find_implementing_symbol.py b/scripts/demo_find_implementing_symbol.py index a19d4b94..4bce7915 100644 --- a/scripts/demo_find_implementing_symbol.py +++ b/scripts/demo_find_implementing_symbol.py @@ -11,13 +11,13 @@ from serena.config.serena_config import LanguageBackend, ProjectConfig, Register from serena.constants import REPO_ROOT from serena.project import Project from serena.tools import FindImplementationsTool -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId SEPARATOR = "=" * 80 GO_TEST_REPO = Path(REPO_ROOT) / "test" / "resources" / "repos" / "go" / "test_repo" -def make_agent(project_root: Path, language: Language, project_name: str) -> SerenaAgent: +def make_agent(project_root: Path, language: LanguageServerId, project_name: str) -> SerenaAgent: """Create an LSP-backed Serena agent for a single explicit project.""" serena_config = SerenaConfig.from_config_file() serena_config.web_dashboard = False @@ -49,7 +49,7 @@ def print_section(title: str) -> None: if __name__ == "__main__": - agent = make_agent(GO_TEST_REPO, Language.GO, "demo_go_test_repo") + agent = make_agent(GO_TEST_REPO, LanguageServerId.GO, "demo_go_test_repo") try: # letting the language server finish startup diff --git a/scripts/print_language_list.py b/scripts/print_language_list.py index 6a156731..bf43a34e 100644 --- a/scripts/print_language_list.py +++ b/scripts/print_language_list.py @@ -2,10 +2,10 @@ Prints the list of supported languages, for use in the project.yml template """ -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId if __name__ == "__main__": - lang_strings = sorted([l.value for l in Language]) + lang_strings = sorted([l.value for l in LanguageServerId]) max_len = max(len(s) for s in lang_strings) fmt = f"%-{max_len + 2}s" for i, l in enumerate(lang_strings): diff --git a/src/serena/agent.py b/src/serena/agent.py index f21d6b03..30aebb35 100644 --- a/src/serena/agent.py +++ b/src/serena/agent.py @@ -61,7 +61,7 @@ from serena.tools import ( from serena.util.gui import system_has_usable_display from serena.util.inspection import iter_subclasses from serena.util.logging import MemoryLogHandler -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from solidlsp.util import subprocess_util from solidlsp.util.subprocess_util import terminate_process_tree_with_kill_fallback @@ -1385,24 +1385,24 @@ class SerenaAgent: """ self.get_active_project_or_raise().create_language_server_manager() - def add_language(self, language: Language) -> None: + def add_language_server(self, ls_id: LanguageServerId) -> None: """ - Adds a new language to the active project, spawning the respective language server and updating the project configuration. + Adds a new language server to the active project, spawning the respective language server and updating the project configuration. The addition is scheduled via the agent's task executor and executed synchronously, i.e. the method returns when the addition is complete. - :param language: the language to add + :param ls_id: the language server to add """ - self.execute_task(lambda: self.get_active_project_or_raise().add_language(language), name=f"AddLanguage:{language.value}") + self.execute_task(lambda: self.get_active_project_or_raise().add_language_server(ls_id), name=f"AddLanguage:{ls_id.value}") - def remove_language(self, language: Language) -> None: + def remove_language_server(self, ls_id: LanguageServerId) -> None: """ - Removes a language from the active project, shutting down the respective language server and updating the project configuration. + Removes a language server from the active project, shutting down the respective server and updating the project configuration. The removal is scheduled via the agent's task executor and executed asynchronously. - :param language: the language to remove + :param ls_id: the language to remove """ - self.issue_task(lambda: self.get_active_project_or_raise().remove_language(language), name=f"RemoveLanguage:{language.value}") + self.issue_task(lambda: self.get_active_project_or_raise().remove_language_server(ls_id), name=f"RemoveLanguage:{ls_id.value}") def get_tool(self, tool_class: type[TTool]) -> TTool: return self._all_tools[tool_class] @@ -1444,11 +1444,11 @@ class SerenaAgent: tool_class = ToolRegistry().get_tool_class_by_name(tool_name) return self.get_tool(tool_class) - def get_active_lsp_languages(self) -> list[Language]: + def get_active_language_server_ids(self) -> list[LanguageServerId]: ls_manager = self.get_language_server_manager() if ls_manager is None: return [] - return ls_manager.get_active_languages() + return ls_manager.get_active_language_server_ids() @contextmanager def active_project_context(self, project: Project) -> Iterator[None]: diff --git a/src/serena/cli.py b/src/serena/cli.py index 77d84180..797930c6 100644 --- a/src/serena/cli.py +++ b/src/serena/cli.py @@ -39,7 +39,7 @@ from serena.constants import ( from serena.prompt_factory import SerenaPromptFactory from serena.util.cli_util import AutoRegisteringGroup from serena.util.logging import MemoryLogHandler -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from solidlsp.ls_types import SymbolKind from solidlsp.util.subprocess_util import subprocess_kwargs @@ -701,13 +701,13 @@ class ProjectCommands(AutoRegisteringGroup): if os.path.exists(yml_path): raise FileExistsError(f"Project file {yml_path} already exists.") - languages: list[Language] = [] + languages: list[LanguageServerId] = [] if language: for lang in language: try: - languages.append(Language(lang.lower())) + languages.append(LanguageServerId(lang.lower())) except ValueError: - all_langs = [l.value for l in Language] + all_langs = [l.value for l in LanguageServerId] raise ValueError(f"Unknown language '{lang}'. Supported: {all_langs}") generated_conf = ProjectConfig.autogenerate( @@ -801,13 +801,13 @@ class ProjectCommands(AutoRegisteringGroup): collected_exceptions: list[Exception] = [] files_failed = [] - language_file_counts: dict[Language, int] = collections.defaultdict(lambda: 0) + language_file_counts: dict[LanguageServerId, int] = collections.defaultdict(lambda: 0) last_save_time = time.monotonic() for i, f in enumerate(tqdm(files, desc="Indexing")): try: ls = ls_mgr.get_language_server(f) ls.request_document_symbols(f) - language_file_counts[ls.language] += 1 + language_file_counts[ls.ls_id] += 1 except Exception as e: log.error(f"Failed to index {f}, continuing.") collected_exceptions.append(e) @@ -882,7 +882,7 @@ class ProjectCommands(AutoRegisteringGroup): ls_mgr = proj.create_language_server_manager() try: for ls in ls_mgr.iter_language_servers(): - click.echo(f"Indexing for language {ls.language.value} …") + click.echo(f"Indexing for language {ls.ls_id.value} …") document_symbols = ls.request_document_symbols(file) symbols, _ = document_symbols.get_all_symbols_and_roots() if verbose: diff --git a/src/serena/config/serena_config.py b/src/serena/config/serena_config.py index 8fa343dd..bf2898a1 100644 --- a/src/serena/config/serena_config.py +++ b/src/serena/config/serena_config.py @@ -32,10 +32,10 @@ from serena.constants import ( SERENA_FILE_ENCODING, SERENA_MANAGED_DIR_NAME, ) -from serena.util.inspection import determine_programming_language_composition +from serena.util.inspection import compute_language_server_support_composition from serena.util.text_utils import glob_match from serena.util.yaml import YamlCommentNormalisation, load_yaml, normalise_yaml_comments, save_yaml, transfer_yaml_comments -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from ..analytics import RegisteredTokenCountEstimator from ..util.class_decorators import singleton @@ -321,7 +321,7 @@ class ProjectConfigAutoGenerationMode(Enum): @dataclass(kw_only=True) class ProjectConfig(SharedConfig, ModeSelectionDefinitionWithAddedModes): project_name: str - languages: list[Language] + languages: list[LanguageServerId] ignored_paths: list[str] = field(default_factory=list) ls_workspace_folders: list[str] = field(default_factory=lambda: ["."]) ls_additional_workspace_folders: list[str] = field(default_factory=list) @@ -356,57 +356,58 @@ class ProjectConfig(SharedConfig, ModeSelectionDefinitionWithAddedModes): return ["project_name"] @classmethod - def _determine_project_languages(cls, project_root: str, interactive: bool, serena_config: "SerenaConfig") -> list[Language]: - log.info("Determining programming languages used in the project") + def _determine_project_language_servers( + cls, project_root: str, interactive: bool, serena_config: "SerenaConfig" + ) -> list[LanguageServerId]: + log.info("Determining suitable language servers for the project") - # determine languages to be considered and their priorities - language_priorities = {} - for language in Language: + # determine language servers to be considered and their priorities + ls_priorities = {} + for language in LanguageServerId: priority = serena_config.get_ls_priority(language) if priority > 0: - language_priorities[language] = priority + ls_priorities[language] = priority - log.debug("Language priorities: %s", language_priorities) - language_composition = determine_programming_language_composition(project_root, list(language_priorities.keys())) - log.info("Project language composition: %s", language_composition) + log.debug("Language server priorities: %s", ls_priorities) + ls_composition = compute_language_server_support_composition(project_root, list(ls_priorities.keys())) + log.info("Project composition: %s", ls_composition) - if len(language_composition) == 0: + if len(ls_composition) == 0: log.warning( "No source files for supported language servers were found in %s. " - "Creating project with no configured languages. " + "Creating project with no configured language servers. " "Symbol-related tools (e.g. find_symbol, get_symbols_overview) will not work " "when using the LSP backend. You can add languages later via the Serena dashboard " "or by manually editing the project configuration.", project_root, ) - languages_to_use = [] + language_servers_to_use = [] else: # sort languages by number of files found - languages_and_percentages = sorted( - language_composition.items(), key=lambda item: (item[1], language_priorities[item[0]]), reverse=True - ) + languages_and_percentages = sorted(ls_composition.items(), key=lambda item: (item[1], ls_priorities[item[0]]), reverse=True) # find the language with the highest percentage and enable it top_language_pair = languages_and_percentages[0] other_language_pairs = languages_and_percentages[1:] - languages_to_use = [top_language_pair[0]] + language_servers_to_use = [top_language_pair[0]] # if in interactive mode, ask the user which other languages to enable if len(other_language_pairs) > 0 and interactive: print( - "Detected and enabled main language '%s' (%.2f%% of source files)." % (top_language_pair[0].value, top_language_pair[1]) + "Detected and enabled main language server '%s' (%.2f%% of source files)." + % (top_language_pair[0].value, top_language_pair[1]) ) - print(f"Additionally detected {len(other_language_pairs)} other language(s).\n") - print("Note: Enable only languages you need symbolic retrieval/editing capabilities for.") - print(" Additional language servers use resources and some languages may require additional") + print(f"Additionally detected {len(other_language_pairs)} other applicable language servers.\n") + print("Note: Enable only servers for languages you need symbolic retrieval/editing capabilities for.") + print(" Additional language servers use resources and some may require additional") print(" system-level installations/configuration (see Serena documentation).") - print("\nWhich additional languages do you want to enable?") - for lang, perc in other_language_pairs: - enable = ask_yes_no("Enable %s (%.2f%% of source files)?" % (lang.value, perc), default=False) + print("\nWhich additional language servers do you want to enable?") + for ls_id, perc in other_language_pairs: + enable = ask_yes_no("Enable %s (%.2f%% of source files)?" % (ls_id.value, perc), default=False) if enable: - languages_to_use.append(lang) + language_servers_to_use.append(ls_id) print() - log.info("Using languages: %s", languages_to_use) - return languages_to_use + log.info("Using language servers: %s", language_servers_to_use) + return language_servers_to_use @classmethod def autogenerate( @@ -414,7 +415,7 @@ class ProjectConfig(SharedConfig, ModeSelectionDefinitionWithAddedModes): project_root: str | Path, serena_config: "SerenaConfig", project_name: str | None = None, - languages: list[Language] | None = None, + languages: list[LanguageServerId] | None = None, save_to_disk: bool = True, interactive: bool = False, asynchronous: bool = False, @@ -448,7 +449,7 @@ class ProjectConfig(SharedConfig, ModeSelectionDefinitionWithAddedModes): use_asynchronous_language_determination = True languages_to_use = [] # temporarily empty, will be determined in background thread else: - determined_languages = cls._determine_project_languages( + determined_languages = cls._determine_project_language_servers( str(project_root), interactive=interactive, serena_config=serena_config ) languages_to_use = [l.value for l in determined_languages] @@ -477,7 +478,7 @@ class ProjectConfig(SharedConfig, ModeSelectionDefinitionWithAddedModes): def async_language_determination(): try: with LogTime("Asynchronous language determination", logger=log): - project_config.languages = cls._determine_project_languages( + project_config.languages = cls._determine_project_language_servers( str(project_root), interactive=False, serena_config=serena_config ) if save_to_disk: @@ -579,18 +580,18 @@ class ProjectConfig(SharedConfig, ModeSelectionDefinitionWithAddedModes): """ # map languages to list of enum items, checking for errors lang_name_mapping = {"javascript": "typescript"} - languages: list[Language] = [] + languages: list[LanguageServerId] = [] for language_str in data["languages"]: orig_language_str = language_str try: language_str = language_str.lower() if language_str in lang_name_mapping: language_str = lang_name_mapping[language_str] - language = Language(language_str) + language = LanguageServerId(language_str) languages.append(language) except ValueError as e: raise ValueError( - f"Invalid language: {orig_language_str}.\nValid language_strings are: {[l.value for l in Language]}" + f"Invalid language: {orig_language_str}.\nValid language_strings are: {[l.value for l in LanguageServerId]}" ) from e # Validate activation_command_timeout @@ -1451,18 +1452,18 @@ class SerenaConfig(SharedConfig, ModeSelectionDefinitionWithBaseModes): log.info(f"Using language backend from global configuration: {language_backend.name}") return language_backend - def get_ls_priority(self, language: Language) -> int: + def get_ls_priority(self, ls_id: LanguageServerId) -> int: """ Gets the priority value associated with a language server - :param language: identifies the language server + :param ls_id: identifies the language server :return: the integer priority """ if self.ls_priorities is not None: try: - configured_value = self.ls_priorities.get(language.value) + configured_value = self.ls_priorities.get(ls_id.value) if configured_value is not None: return int(configured_value) except Exception as e: - log.error("Error reading language priority for %s: %s. Using default priority.", language.value, e) - return language.get_priority() + log.error("Error reading language priority for %s: %s. Using default priority.", ls_id.value, e) + return ls_id.get_priority() diff --git a/src/serena/dashboard.py b/src/serena/dashboard.py index 80415b45..4b6637b6 100644 --- a/src/serena/dashboard.py +++ b/src/serena/dashboard.py @@ -638,10 +638,10 @@ class SerenaDashboardAPI: self._current_config_overview = self._compute_config_overview().model_dump() def _get_available_languages(self) -> ResponseAvailableLanguages: - from solidlsp.ls_config import Language + from solidlsp.ls_config import LanguageServerId def run() -> ResponseAvailableLanguages: - all_languages = [lang.value for lang in Language.iter_all(include_experimental=True)] + all_languages = [lang.value for lang in LanguageServerId.iter_all(include_experimental=True)] # Filter out already added languages for the active project project = self._agent.get_active_project() @@ -776,24 +776,24 @@ class SerenaDashboardAPI: return {} def _add_language(self, request_add_language: RequestAddLanguage) -> None: - from solidlsp.ls_config import Language + from solidlsp.ls_config import LanguageServerId try: - language = Language(request_add_language.language) + language = LanguageServerId(request_add_language.language) except ValueError: - raise ValueError(f"Invalid language: {request_add_language.language}") + raise ValueError(f"Invalid language server identifier: {request_add_language.language}") # add_language is already thread-safe - self._agent.add_language(language) + self._agent.add_language_server(language) def _remove_language(self, request_remove_language: RequestRemoveLanguage) -> None: - from solidlsp.ls_config import Language + from solidlsp.ls_config import LanguageServerId try: - language = Language(request_remove_language.language) + language = LanguageServerId(request_remove_language.language) except ValueError: - raise ValueError(f"Invalid language: {request_remove_language.language}") + raise ValueError(f"Invalid language server identifier: {request_remove_language.language}") # remove_language is already thread-safe - self._agent.remove_language(language) + self._agent.remove_language_server(language) @staticmethod def _find_first_free_port(start_port: int, host: str) -> int: diff --git a/src/serena/ls_manager.py b/src/serena/ls_manager.py index 45405962..2dd3aaf4 100644 --- a/src/serena/ls_manager.py +++ b/src/serena/ls_manager.py @@ -9,7 +9,7 @@ from sensai.util.logging import LogTime from serena.config.serena_config import ProjectConfig, SerenaPaths from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language, LanguageServerConfig +from solidlsp.ls_config import LanguageServerConfig, LanguageServerId from solidlsp.lsp_protocol_handler.lsp_types import DidChangeWatchedFilesParams, FileChangeType, FileEvent from solidlsp.settings import SolidLSPSettings @@ -45,17 +45,17 @@ class LanguageServerFactory: self.ls_specific_settings = ls_specific_settings self.trace_lsp_communication = trace_lsp_communication - def create_language_server(self, language: Language) -> SolidLanguageServer: + def create_language_server(self, ls_id: LanguageServerId) -> SolidLanguageServer: ls_config = LanguageServerConfig( workspace_folders=self.project_config.ls_workspace_folders, additional_workspace_folders=self.project_config.ls_additional_workspace_folders, - code_language=language, + ls_id=ls_id, ignored_paths=self.ignored_patterns, trace_lsp_communication=self.trace_lsp_communication, encoding=self.encoding, ) - log.info(f"Creating language server instance for {self.project_root}, language={language}.") + log.info(f"Creating language server instance for {self.project_root}, language={ls_id}.") return SolidLanguageServer.create( ls_config, self.project_root, @@ -74,7 +74,10 @@ class LanguageServerManager: """ def __init__( - self, language_servers: dict[Language, SolidLanguageServer], language_server_factory: LanguageServerFactory, project: "Project" + self, + language_servers: dict[LanguageServerId, SolidLanguageServer], + language_server_factory: LanguageServerFactory, + project: "Project", ) -> None: """ :param language_servers: a mapping from language to language server; the servers are assumed to be already started. @@ -94,7 +97,7 @@ class LanguageServerManager: return next(iter(self._language_servers.values())) @staticmethod - def from_languages(languages: list[Language], factory: LanguageServerFactory, project: "Project") -> "LanguageServerManager": + def from_languages(languages: list[LanguageServerId], factory: LanguageServerFactory, project: "Project") -> "LanguageServerManager": """ Creates a manager with language servers for the given languages using the given factory. The language servers are started in parallel threads. @@ -106,21 +109,21 @@ class LanguageServerManager: """ class StartLSThread(threading.Thread): - def __init__(self, language: Language): - super().__init__(target=self._start_language_server, name="StartLS:" + language.value) - self.language = language + def __init__(self, ls_id: LanguageServerId): + super().__init__(target=self._start_language_server, name="StartLS:" + ls_id.value) + self.ls_id = ls_id self.language_server: SolidLanguageServer | None = None self.exception: Exception | None = None def _start_language_server(self) -> None: try: - with LogTime(f"Language server startup (language={self.language.value})"): - self.language_server = factory.create_language_server(self.language) + with LogTime(f"Language server startup (language={self.ls_id.value})"): + self.language_server = factory.create_language_server(self.ls_id) self.language_server.start() if not self.language_server.is_running(): - raise RuntimeError(f"Failed to start the language server for language {self.language.value}") + raise RuntimeError(f"Failed to start the language server for language {self.ls_id.value}") except Exception as e: - log.error(f"Error starting language server for language {self.language.value}: {e}", exc_info=e) + log.error(f"Error starting language server for language {self.ls_id.value}: {e}", exc_info=e) self.exception = e # start language servers in parallel threads @@ -131,14 +134,14 @@ class LanguageServerManager: threads.append(thread) # collect language servers and exceptions - language_servers: dict[Language, SolidLanguageServer] = {} - exceptions: dict[Language, Exception] = {} + language_servers: dict[LanguageServerId, SolidLanguageServer] = {} + exceptions: dict[LanguageServerId, Exception] = {} for thread in threads: thread.join() if thread.exception is not None: - exceptions[thread.language] = thread.exception + exceptions[thread.ls_id] = thread.exception elif thread.language_server is not None: - language_servers[thread.language] = thread.language_server + language_servers[thread.ls_id] = thread.language_server # If any server failed to start up, raise an exception and stop all started language servers. # We intentionally fail fast here. The user's intention is to work with all the specified languages, @@ -155,8 +158,8 @@ class LanguageServerManager: def _ensure_functional_ls(self, ls: SolidLanguageServer) -> SolidLanguageServer: if not ls.is_running(): - log.warning(f"Language server for language {ls.language} is not running; restarting ...") - ls = self.restart_language_server(ls.language) + log.warning(f"Language server for language {ls.ls_id} is not running; restarting ...") + ls = self.restart_language_server(ls.ls_id) return ls def _get_suitable_language_server(self, relative_path: str) -> SolidLanguageServer | None: @@ -177,15 +180,15 @@ class LanguageServerManager: ls = self._default_language_server return self._ensure_functional_ls(ls) - def _create_and_start_language_server(self, language: Language) -> SolidLanguageServer: + def _create_and_start_language_server(self, ls_id: LanguageServerId) -> SolidLanguageServer: if self._language_server_factory is None: - raise ValueError(f"No language server factory available to create language server for {language}") - language_server = self._language_server_factory.create_language_server(language) + raise ValueError(f"No language server factory available to create language server for {ls_id}") + language_server = self._language_server_factory.create_language_server(ls_id) language_server.start() - self._language_servers[language] = language_server + self._language_servers[ls_id] = language_server return language_server - def restart_language_server(self, language: Language) -> SolidLanguageServer: + def restart_language_server(self, language: LanguageServerId) -> SolidLanguageServer: """ Forces recreation and restart of the language server for the given language. It is assumed that the language server for the given language is no longer running. @@ -197,19 +200,18 @@ class LanguageServerManager: raise ValueError(f"No language server for language {language.value} present; cannot restart") return self._create_and_start_language_server(language) - def add_language_server(self, language: Language) -> SolidLanguageServer: + def add_language_server(self, ls_id: LanguageServerId) -> SolidLanguageServer: """ Dynamically adds a new language server for the given language. - :param language: the language - :param factory: the factory to create the language server + :param ls_id: the language server to add :return: the newly created language server """ - if language in self._language_servers: - raise ValueError(f"Language server for language {language.value} already present") - return self._create_and_start_language_server(language) + if ls_id in self._language_servers: + raise ValueError(f"Language server for language {ls_id.value} already present") + return self._create_and_start_language_server(ls_id) - def remove_language_server(self, language: Language, save_cache: bool = False) -> None: + def remove_language_server(self, language: LanguageServerId, save_cache: bool = False) -> None: """ Removes the language server for the given language, stopping it if it is running. @@ -220,7 +222,7 @@ class LanguageServerManager: ls = self._language_servers.pop(language) self._stop_language_server(ls, save_cache=save_cache) - def get_active_languages(self) -> list[Language]: + def get_active_language_server_ids(self) -> list[LanguageServerId]: """ Returns the list of languages for which language servers are currently managed. @@ -233,7 +235,7 @@ class LanguageServerManager: if ls.is_running(): if save_cache: ls.save_cache() - log.info(f"Stopping language server for language {ls.language} ...") + log.info(f"Stopping language server for language {ls.ls_id} ...") ls.stop(shutdown_timeout=timeout) def iter_language_servers(self) -> Iterator[SolidLanguageServer]: diff --git a/src/serena/project.py b/src/serena/project.py index e316f7a2..0323eebd 100644 --- a/src/serena/project.py +++ b/src/serena/project.py @@ -20,7 +20,7 @@ from serena.util.file_proxy import FileCollection, FileProxy from serena.util.file_system import GitignoreParser, match_path, scan_directory from serena.util.text_utils import MatchedConsecutiveLines, search_files from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId if TYPE_CHECKING: from serena.agent import SerenaAgent @@ -493,7 +493,7 @@ class Project(ToStringMixin): ls_specific_settings=ls_specific_settings, trace_lsp_communication=self.serena_config.trace_lsp_communication, ) - self.language_server_manager = LanguageServerManager.from_languages(self.project_config.languages, factory, self) + self.language_server_manager = LanguageServerManager.from_languages(self.project_config.language_servers, factory, self) return self.language_server_manager except Exception as e: self._language_server_manager_init_error = e @@ -512,50 +512,50 @@ class Project(ToStringMixin): raise Exception(msg.build()) return self.language_server_manager - def add_language(self, language: Language) -> None: + def add_language_server(self, ls_id: LanguageServerId) -> None: """ - Adds a new programming language to the project configuration, starting the corresponding - language server instance if the LS manager is active. + Adds a new language server to the project configuration, starting the corresponding + server instance if the LS manager is active. The project configuration is saved to disk after adding the language. - :param language: the programming language to add + :param ls_id: the language server to add """ - if language in self.project_config.languages: - log.info(f"Language {language.value} is already present in the project configuration.") + if ls_id in self.project_config.language_servers: + log.info(f"Language server {ls_id.value} is already present in the project configuration.") return # start the language server (if the LS manager is active) if self.language_server_manager is None: log.info("Language server manager is not active; skipping language server startup for the new language.") else: - log.info("Adding and starting the language server for new language %s ...", language.value) - self.language_server_manager.add_language_server(language) + log.info("Adding and starting the language server '%s' ...", ls_id.value) + self.language_server_manager.add_language_server(ls_id) # update the project configuration - self.project_config.languages.append(language) + self.project_config.language_servers.append(ls_id) self.save_config() - def remove_language(self, language: Language) -> None: + def remove_language_server(self, ls_id: LanguageServerId) -> None: """ - Removes a programming language from the project configuration, stopping the corresponding - language server instance if the LS manager is active. + Removes a language server from the project configuration, stopping the corresponding + server instance if the LS manager is active. The project configuration is saved to disk after removing the language. - :param language: the programming language to remove + :param ls_id: the language server to remove """ - if language not in self.project_config.languages: - log.info(f"Language {language.value} is not present in the project configuration.") + if ls_id not in self.project_config.language_servers: + log.info(f"Language {ls_id.value} is not present in the project configuration.") return # update the project configuration - self.project_config.languages.remove(language) + self.project_config.language_servers.remove(ls_id) self.save_config() # stop the language server (if the LS manager is active) if self.language_server_manager is None: log.info("Language server manager is not active; skipping language server shutdown for the removed language.") else: - log.info("Removing and stopping the language server for language %s ...", language.value) - self.language_server_manager.remove_language_server(language) + log.info("Removing and stopping the language server for language %s ...", ls_id.value) + self.language_server_manager.remove_language_server(ls_id) def ls_sync_file_system_changes(self) -> int: """ diff --git a/src/serena/tools/symbol_tools.py b/src/serena/tools/symbol_tools.py index c4ed5bfc..d4d27785 100644 --- a/src/serena/tools/symbol_tools.py +++ b/src/serena/tools/symbol_tools.py @@ -107,7 +107,7 @@ class GetSymbolsOverviewTool(Tool, ToolMarkerSymbolicRead): raise ValueError(f"Expected a file path, but got a directory path: {relative_path}. ") if not symbol_retriever.can_analyze_file(relative_path): raise ValueError( - f"Cannot extract symbols from file {relative_path}. Active languages: {[l.value for l in self.agent.get_active_lsp_languages()]}" + f"Cannot extract symbols from file {relative_path}. Active language servers: {[l.value for l in self.agent.get_active_language_server_ids()]}" ) symbols = symbol_retriever.get_symbol_overview(relative_path)[relative_path] diff --git a/src/serena/util/inspection.py b/src/serena/util/inspection.py index 04c3c33d..0f2ebcf2 100644 --- a/src/serena/util/inspection.py +++ b/src/serena/util/inspection.py @@ -4,7 +4,7 @@ from collections.abc import Callable, Iterator from typing import TypeVar from serena.util.file_system import find_all_non_ignored_files -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId T = TypeVar("T") @@ -27,40 +27,42 @@ def iter_subclasses( yield from iter_subclasses(subclass, recursive, inclusion_predicate) -def determine_programming_language_composition(repo_path: str, languages: list[Language] | None = None) -> dict[Language, float]: +def compute_language_server_support_composition( + repo_path: str, ls_ids: list[LanguageServerId] | None = None +) -> dict[LanguageServerId, float]: """ - Determine the programming language composition of a repository. + Determine the composition of a repository in terms of the language servers that can be used to analyze it. Percentages are computed relative to the number of files that match at least - one supported language, not the total file count. This prevents files that + one supported language server, not the total file count. This prevents files that belong to no supported language (images, plain text, licenses, lock files, etc.) from diluting language percentages in repositories where such files dominate. :param repo_path: path to the repository to analyze - :param languages: the list of languages to consider; if None, use default languages - :return: dictionary mapping languages to percentages of recognised source files - matching the respective language (denominator = files matched by at least one language) + :param ls_ids: the list of language servers to consider; if None, use default (non-experimental ones) + :return: dictionary mapping language servers to percentages of recognised source files + (denominator = files matched by at least one language server) """ - if languages is None: - languages = list(Language.iter_all(include_experimental=False)) + if ls_ids is None: + ls_ids = list(LanguageServerId.iter_all(include_experimental=False)) all_files = find_all_non_ignored_files(repo_path) if not all_files: return {} - matchers = {lang: lang.get_source_fn_matcher() for lang in languages} + matchers = {lang: lang.get_source_fn_matcher() for lang in ls_ids} # count files per language in a single pass over the files - language_counts: dict[Language, int] = {} + ls_file_counts: dict[LanguageServerId, int] = {} recognised_files = 0 for file_path in all_files: # Use just the filename for matching, not the full path filename = os.path.basename(file_path) matched_any = False - for lang, matcher in matchers.items(): + for ls_id, matcher in matchers.items(): if matcher.is_relevant_filename(filename): - language_counts[lang] = language_counts.get(lang, 0) + 1 + ls_file_counts[ls_id] = ls_file_counts.get(ls_id, 0) + 1 matched_any = True if matched_any: recognised_files += 1 @@ -69,4 +71,4 @@ def determine_programming_language_composition(repo_path: str, languages: list[L return {} # convert to percentages relative to recognised source files only - return {lang: round(count / recognised_files * 100, 2) for lang, count in language_counts.items()} + return {ls_id: round(count / recognised_files * 100, 2) for ls_id, count in ls_file_counts.items()} diff --git a/src/solidlsp/language_servers/al_language_server.py b/src/solidlsp/language_servers/al_language_server.py index f67ee2ba..f3b72500 100644 --- a/src/solidlsp/language_servers/al_language_server.py +++ b/src/solidlsp/language_servers/al_language_server.py @@ -18,7 +18,7 @@ from overrides import override from solidlsp import ls_types from solidlsp.language_servers.common import quote_windows_path from solidlsp.ls import DocumentSymbols, LSPFileBuffer, RawDocumentSymbol, SolidLanguageServer -from solidlsp.ls_config import Language, LanguageServerConfig +from solidlsp.ls_config import LanguageServerConfig, LanguageServerId from solidlsp.ls_types import SymbolKind, UnifiedSymbolInformation from solidlsp.ls_utils import FileUtils from solidlsp.lsp_protocol_handler.lsp_types import Definition, DefinitionParams, LocationLink @@ -240,7 +240,7 @@ class ALLanguageServer(SolidLanguageServer): log.warning(f"AL_EXTENSION_PATH set but directory not found: {env_path}") # Check the resolved-version download location (versioned for non-INITIAL, legacy "al-extension" for INITIAL) - al_settings = solidlsp_settings.get_ls_specific_settings(Language.AL) + al_settings = solidlsp_settings.get_ls_specific_settings(LanguageServerId.AL) al_extension_version = al_settings.get("al_extension_version", DEFAULT_AL_EXTENSION_VERSION) default_path = os.path.join(cls.ls_resources_dir(solidlsp_settings), _al_extension_dirname(al_extension_version), "extension") if os.path.exists(default_path): @@ -265,7 +265,7 @@ class ALLanguageServer(SolidLanguageServer): Path to installed extension or None if download failed """ - al_settings = solidlsp_settings.get_ls_specific_settings(Language.AL) + al_settings = solidlsp_settings.get_ls_specific_settings(LanguageServerId.AL) al_extension_version = al_settings.get("al_extension_version", DEFAULT_AL_EXTENSION_VERSION) al_extension_dir = os.path.join(cls.ls_resources_dir(solidlsp_settings), _al_extension_dirname(al_extension_version)) al_extension_url = ( diff --git a/src/solidlsp/language_servers/angular_language_server.py b/src/solidlsp/language_servers/angular_language_server.py index e7bf231d..c25ed837 100644 --- a/src/solidlsp/language_servers/angular_language_server.py +++ b/src/solidlsp/language_servers/angular_language_server.py @@ -69,7 +69,7 @@ from solidlsp.language_servers.typescript_language_server import ( ) from solidlsp.language_servers.vscode_html_language_server import VsCodeHtmlLanguageServer from solidlsp.ls import LanguageServerDependencyProvider, LSPFileBuffer, SolidLanguageServer -from solidlsp.ls_config import FilenameMatcher, Language, LanguageServerConfig +from solidlsp.ls_config import FilenameMatcher, LanguageServerConfig, LanguageServerId from solidlsp.lsp_protocol_handler.lsp_types import DocumentSymbol, SymbolInformation from solidlsp.lsp_protocol_handler.server import ProcessLaunchInfo from solidlsp.settings import SolidLSPSettings @@ -97,13 +97,13 @@ class AngularTypeScriptServer(TypeScriptLanguageServer): @classmethod @override - def get_language_enum_instance(cls) -> Language: - return Language.TYPESCRIPT + def get_language_server_id(cls) -> LanguageServerId: + return LanguageServerId.TYPESCRIPT def get_source_fn_matcher(self) -> FilenameMatcher: # Use the Angular matcher so .html template files aren't filtered out of # reference / search results when the companion is asked about them. - return Language.ANGULAR.get_source_fn_matcher() + return LanguageServerId.ANGULAR.get_source_fn_matcher() class DependencyProvider(TypeScriptLanguageServer.DependencyProvider): """Dependency provider that returns a pre-resolved executable path. @@ -293,8 +293,8 @@ class AngularLanguageServer(SolidLanguageServer): assert shutil.which("node") is not None, "node is not installed or isn't in PATH. Please install NodeJS and try again." assert shutil.which("npm") is not None, "npm is not installed or isn't in PATH. Please install npm and try again." - ng_settings = solidlsp_settings.get_ls_specific_settings(Language.ANGULAR) - ts_settings = solidlsp_settings.get_ls_specific_settings(Language.TYPESCRIPT) + ng_settings = solidlsp_settings.get_ls_specific_settings(LanguageServerId.ANGULAR) + ts_settings = solidlsp_settings.get_ls_specific_settings(LanguageServerId.TYPESCRIPT) ls_version = ng_settings.get("angular_language_server_version", DEFAULT_ANGULAR_LANGUAGE_SERVER_VERSION) svc_version = ng_settings.get("angular_language_service_version", DEFAULT_ANGULAR_LANGUAGE_SERVICE_VERSION) ts_version = ng_settings.get("typescript_version", ts_settings.get("typescript_version", DEFAULT_TYPESCRIPT_VERSION)) @@ -368,7 +368,7 @@ class AngularLanguageServer(SolidLanguageServer): def _start_typescript_server(self) -> None: try: - ts_config = LanguageServerConfig(code_language=Language.TYPESCRIPT, trace_lsp_communication=False) + ts_config = LanguageServerConfig(ls_id=LanguageServerId.TYPESCRIPT, trace_lsp_communication=False) log.info("Creating companion AngularTypeScriptServer") self._ts_server = AngularTypeScriptServer( config=ts_config, @@ -413,7 +413,7 @@ class AngularLanguageServer(SolidLanguageServer): non-fatal: we log and fall back to returning an empty list. """ try: - html_config = LanguageServerConfig(code_language=Language.HTML, trace_lsp_communication=False) + html_config = LanguageServerConfig(ls_id=LanguageServerId.HTML, trace_lsp_communication=False) log.info("Creating companion VsCodeHtmlLanguageServer") self._html_server = VsCodeHtmlLanguageServer( config=html_config, diff --git a/src/solidlsp/language_servers/basedpyright_server.py b/src/solidlsp/language_servers/basedpyright_server.py index 28e4ca13..4c87f01d 100644 --- a/src/solidlsp/language_servers/basedpyright_server.py +++ b/src/solidlsp/language_servers/basedpyright_server.py @@ -32,7 +32,7 @@ class BasedPyrightLanguageServer(SolidLanguageServer): config, repository_root_path, None, - str(config.code_language), + str(config.ls_id), solidlsp_settings, ) diff --git a/src/solidlsp/language_servers/dart_language_server.py b/src/solidlsp/language_servers/dart_language_server.py index 59fd4327..553d753b 100644 --- a/src/solidlsp/language_servers/dart_language_server.py +++ b/src/solidlsp/language_servers/dart_language_server.py @@ -8,7 +8,7 @@ from solidlsp.ls import RawDocumentSymbol, SolidLanguageServer from solidlsp.lsp_protocol_handler.server import ProcessLaunchInfo from solidlsp.settings import SolidLSPSettings -from ..ls_config import Language, LanguageServerConfig +from ..ls_config import LanguageServerConfig, LanguageServerId from .common import RuntimeDependency, RuntimeDependencyCollection log = logging.getLogger(__name__) @@ -73,7 +73,7 @@ class DartLanguageServer(SolidLanguageServer): @classmethod def _setup_runtime_dependencies(cls, solidlsp_settings: SolidLSPSettings) -> str: - dart_settings = solidlsp_settings.get_ls_specific_settings(Language.DART) + dart_settings = solidlsp_settings.get_ls_specific_settings(LanguageServerId.DART) dart_sdk_version = dart_settings.get("dart_sdk_version", DEFAULT_DART_SDK_VERSION) deps = RuntimeDependencyCollection( [ diff --git a/src/solidlsp/language_servers/elixir_tools/elixir_tools.py b/src/solidlsp/language_servers/elixir_tools/elixir_tools.py index d80e43e3..01e64513 100644 --- a/src/solidlsp/language_servers/elixir_tools/elixir_tools.py +++ b/src/solidlsp/language_servers/elixir_tools/elixir_tools.py @@ -10,7 +10,7 @@ from typing import Any from overrides import override from solidlsp.ls import RawDocumentSymbol, SolidLanguageServer -from solidlsp.ls_config import Language, LanguageServerConfig +from solidlsp.ls_config import LanguageServerConfig, LanguageServerId from solidlsp.ls_utils import FileUtils, PlatformId, PlatformUtils from solidlsp.lsp_protocol_handler.server import ProcessLaunchInfo from solidlsp.settings import SolidLSPSettings @@ -77,7 +77,7 @@ class ElixirTools(SolidLanguageServer): Setup runtime dependencies for Expert. Downloads the Expert binary for the current platform and returns the path to the executable. """ - elixir_settings = solidlsp_settings.get_ls_specific_settings(Language.ELIXIR) + elixir_settings = solidlsp_settings.get_ls_specific_settings(LanguageServerId.ELIXIR) expert_version = elixir_settings.get("expert_version", EXPERT_VERSION) # Check if Elixir is available first elixir_version = cls._get_elixir_version() diff --git a/src/solidlsp/language_servers/elm_language_server.py b/src/solidlsp/language_servers/elm_language_server.py index bd488500..e3fe7790 100644 --- a/src/solidlsp/language_servers/elm_language_server.py +++ b/src/solidlsp/language_servers/elm_language_server.py @@ -12,7 +12,7 @@ from sensai.util.logging import LogTime from solidlsp import ls_types from solidlsp.ls import SolidLanguageServer -from solidlsp.ls_config import Language, LanguageServerConfig +from solidlsp.ls_config import LanguageServerConfig, LanguageServerId from solidlsp.lsp_protocol_handler.server import ProcessLaunchInfo from solidlsp.settings import SolidLSPSettings @@ -73,7 +73,7 @@ class ElmLanguageServer(SolidLanguageServer): """ Setup runtime dependencies for Elm Language Server and return the command to start the server. """ - elm_config = solidlsp_settings.get_ls_specific_settings(Language.ELM) + elm_config = solidlsp_settings.get_ls_specific_settings(LanguageServerId.ELM) elm_language_server_version = elm_config.get("elm_language_server_version", DEFAULT_ELM_LANGUAGE_SERVER_VERSION) elm_compiler_version = elm_config.get("elm_compiler_version", DEFAULT_ELM_COMPILER_VERSION) npm_registry = elm_config.get("npm_registry") diff --git a/src/solidlsp/language_servers/fsharp_language_server.py b/src/solidlsp/language_servers/fsharp_language_server.py index 4b4fc820..7a07bfdc 100644 --- a/src/solidlsp/language_servers/fsharp_language_server.py +++ b/src/solidlsp/language_servers/fsharp_language_server.py @@ -13,7 +13,7 @@ from overrides import override from serena.util.dotnet import DotNETUtil from solidlsp.language_servers.common import RuntimeDependency, RuntimeDependencyCollection from solidlsp.ls import SolidLanguageServer -from solidlsp.ls_config import Language, LanguageServerConfig +from solidlsp.ls_config import LanguageServerConfig, LanguageServerId from solidlsp.ls_exceptions import SolidLSPException from solidlsp.lsp_protocol_handler.server import ProcessLaunchInfo from solidlsp.settings import SolidLSPSettings @@ -71,7 +71,7 @@ class FSharpLanguageServer(SolidLanguageServer): """ Setup runtime dependencies for F# Language Server and return the command to start the server. """ - fsharp_settings = solidlsp_settings.get_ls_specific_settings(Language.FSHARP) + fsharp_settings = solidlsp_settings.get_ls_specific_settings(LanguageServerId.FSHARP) fsautocomplete_version = fsharp_settings.get("fsautocomplete_version", DEFAULT_FSAUTOCOMPLETE_VERSION) dotnet_exe = DotNETUtil("8.0", allow_higher_version=True).get_dotnet_path_or_raise() diff --git a/src/solidlsp/language_servers/godot_language_server.py b/src/solidlsp/language_servers/godot_language_server.py index fe3df8b5..59302693 100644 --- a/src/solidlsp/language_servers/godot_language_server.py +++ b/src/solidlsp/language_servers/godot_language_server.py @@ -81,7 +81,7 @@ class GodotLanguageServer(SolidLanguageServer): self._conn_info = TCPConnectionInfo(host="127.0.0.1", port=port) return TCPLanguageServer( connection_info=self._conn_info, - language=self.language, + ls_id=self.ls_id, determine_log_level=self._determine_log_level, logger=logging_fn, request_timeout=request_timeout, diff --git a/src/solidlsp/language_servers/groovy_language_server.py b/src/solidlsp/language_servers/groovy_language_server.py index f6530733..2d801656 100644 --- a/src/solidlsp/language_servers/groovy_language_server.py +++ b/src/solidlsp/language_servers/groovy_language_server.py @@ -8,7 +8,7 @@ import os import shlex from solidlsp.ls import SolidLanguageServer -from solidlsp.ls_config import Language, LanguageServerConfig +from solidlsp.ls_config import LanguageServerConfig, LanguageServerId from solidlsp.ls_utils import FileUtils, PlatformUtils from solidlsp.lsp_protocol_handler.server import ProcessLaunchInfo from solidlsp.settings import SolidLSPSettings @@ -82,7 +82,7 @@ class GroovyLanguageServer(SolidLanguageServer): ls_jar_options = [] if solidlsp_settings.ls_specific_settings: - groovy_settings = solidlsp_settings.get_ls_specific_settings(Language.GROOVY) + groovy_settings = solidlsp_settings.get_ls_specific_settings(LanguageServerId.GROOVY) jar_options_str = groovy_settings.get("ls_jar_options", "") if jar_options_str: ls_jar_options = shlex.split(jar_options_str) @@ -111,7 +111,7 @@ class GroovyLanguageServer(SolidLanguageServer): Setup runtime dependencies for Groovy Language Server and return paths. """ platform_id = PlatformUtils.get_platform_id() - groovy_settings = solidlsp_settings.get_ls_specific_settings(Language.GROOVY) + groovy_settings = solidlsp_settings.get_ls_specific_settings(LanguageServerId.GROOVY) vscode_java_version = groovy_settings.get("vscode_java_version", DEFAULT_VSCODE_JAVA_VERSION) vscode_java_tag = f"v{vscode_java_version.rsplit('-', 1)[0]}" @@ -125,7 +125,7 @@ class GroovyLanguageServer(SolidLanguageServer): java_path = None if solidlsp_settings and solidlsp_settings.ls_specific_settings: - groovy_settings = solidlsp_settings.get_ls_specific_settings(Language.GROOVY) + groovy_settings = solidlsp_settings.get_ls_specific_settings(LanguageServerId.GROOVY) custom_java_home = groovy_settings.get("ls_java_home_path") if custom_java_home: log.info(f"Using custom Java home path from configuration: {custom_java_home}") @@ -226,7 +226,7 @@ class GroovyLanguageServer(SolidLanguageServer): Find Groovy Language Server JAR file """ if solidlsp_settings and solidlsp_settings.ls_specific_settings: - groovy_settings = solidlsp_settings.get_ls_specific_settings(Language.GROOVY) + groovy_settings = solidlsp_settings.get_ls_specific_settings(LanguageServerId.GROOVY) config_jar_path = groovy_settings.get("ls_jar_path") if config_jar_path and os.path.exists(config_jar_path): log.info(f"Using Groovy LS JAR from configuration: {config_jar_path}") diff --git a/src/solidlsp/language_servers/intelephense.py b/src/solidlsp/language_servers/intelephense.py index 1f937da3..b84f6a3b 100644 --- a/src/solidlsp/language_servers/intelephense.py +++ b/src/solidlsp/language_servers/intelephense.py @@ -115,7 +115,7 @@ class Intelephense(SolidLanguageServer): # such that Serena's symbol tools treat the added extensions as PHP sources as well (#1710) file_filter = self._custom_settings.get("file_filter") if file_filter: - self.language.get_source_fn_matcher().add_extensions(*file_filter) + self.ls_id.get_source_fn_matcher().add_extensions(*file_filter) def _create_dependency_provider(self) -> LanguageServerDependencyProvider: return self.DependencyProvider(self._custom_settings, self._ls_resources_dir) @@ -201,7 +201,7 @@ class Intelephense(SolidLanguageServer): # the initialize request: Intelephense reads configuration exclusively from # workspace/didChangeConfiguration (its initializationOptions only cover storagePath, # globalStoragePath, clearCache and licenceKey). - associations = [f"*{ext}" for ext in self.language.get_source_fn_matcher().file_extensions] + associations = [f"*{ext}" for ext in self.ls_id.get_source_fn_matcher().file_extensions] intelephense_config: DidChangeConfigurationParams = {"settings": {"intelephense": {"files": {"associations": associations}}}} log.info(f"Sending workspace/didChangeConfiguration with file associations: {associations}") self.server.notify.workspace_did_change_configuration(intelephense_config) diff --git a/src/solidlsp/language_servers/lua_ls.py b/src/solidlsp/language_servers/lua_ls.py index 7b31cc71..36c8b362 100644 --- a/src/solidlsp/language_servers/lua_ls.py +++ b/src/solidlsp/language_servers/lua_ls.py @@ -15,7 +15,7 @@ from pathlib import Path from overrides import override from solidlsp.ls import RawDocumentSymbol, SolidLanguageServer -from solidlsp.ls_config import Language, LanguageServerConfig +from solidlsp.ls_config import LanguageServerConfig, LanguageServerId from solidlsp.ls_types import SymbolKind from solidlsp.ls_utils import FileUtils from solidlsp.lsp_protocol_handler.server import ProcessLaunchInfo @@ -91,7 +91,7 @@ class LuaLanguageServer(SolidLanguageServer): ] if solidlsp_settings is not None: - lua_settings = solidlsp_settings.get_ls_specific_settings(Language.LUA) + lua_settings = solidlsp_settings.get_ls_specific_settings(LanguageServerId.LUA) lua_ls_version = lua_settings.get("lua_language_server_version", DEFAULT_LUA_LS_VERSION) ls_resource_dir = _lua_ls_install_dir(LuaLanguageServer.ls_resources_dir(solidlsp_settings), lua_ls_version) possible_paths.extend( @@ -118,7 +118,7 @@ class LuaLanguageServer(SolidLanguageServer): @staticmethod def _download_lua_ls(solidlsp_settings: SolidLSPSettings) -> str: """Download and install lua-language-server if not present.""" - lua_settings = solidlsp_settings.get_ls_specific_settings(Language.LUA) + lua_settings = solidlsp_settings.get_ls_specific_settings(LanguageServerId.LUA) lua_ls_version = lua_settings.get("lua_language_server_version", DEFAULT_LUA_LS_VERSION) system = platform.system() machine = platform.machine().lower() diff --git a/src/solidlsp/language_servers/omnisharp.py b/src/solidlsp/language_servers/omnisharp.py index e64746e5..8a089f2d 100644 --- a/src/solidlsp/language_servers/omnisharp.py +++ b/src/solidlsp/language_servers/omnisharp.py @@ -11,7 +11,7 @@ from collections.abc import Iterable from overrides import override from solidlsp.ls import SolidLanguageServer -from solidlsp.ls_config import Language, LanguageServerConfig +from solidlsp.ls_config import LanguageServerConfig, LanguageServerId from solidlsp.ls_exceptions import SolidLSPException from solidlsp.ls_utils import DotnetVersion, FileUtils, PlatformId, PlatformUtils from solidlsp.lsp_protocol_handler.server import ProcessLaunchInfo @@ -152,7 +152,7 @@ class OmniSharp(SolidLanguageServer): with open(os.path.join(os.path.dirname(__file__), "omnisharp", "runtime_dependencies.json"), encoding="utf-8") as f: d = json.load(f) del d["_description"] - omnisharp_settings = solidlsp_settings.get_ls_specific_settings(Language.CSHARP_OMNISHARP) + omnisharp_settings = solidlsp_settings.get_ls_specific_settings(LanguageServerId.CSHARP_OMNISHARP) omnisharp_version = omnisharp_settings.get("omnisharp_version", DEFAULT_OMNISHARP_VERSION) razor_omnisharp_version = omnisharp_settings.get("razor_omnisharp_version", DEFAULT_RAZOR_OMNISHARP_VERSION) for dependency in d["runtimeDependencies"]: diff --git a/src/solidlsp/language_servers/pascal_server.py b/src/solidlsp/language_servers/pascal_server.py index e27831fd..4b1ab282 100644 --- a/src/solidlsp/language_servers/pascal_server.py +++ b/src/solidlsp/language_servers/pascal_server.py @@ -62,7 +62,7 @@ import zipfile from solidlsp.language_servers.common import RuntimeDependency, RuntimeDependencyCollection, quote_windows_path from solidlsp.ls import SolidLanguageServer -from solidlsp.ls_config import Language, LanguageServerConfig +from solidlsp.ls_config import LanguageServerConfig, LanguageServerId from solidlsp.lsp_protocol_handler.server import ProcessLaunchInfo from solidlsp.settings import SolidLSPSettings @@ -131,9 +131,9 @@ class PascalLanguageServer(SolidLanguageServer): proc_env: dict[str, str] = {} # Read from ls_specific_settings["pascal"] - from solidlsp.ls_config import Language + from solidlsp.ls_config import LanguageServerId - pascal_settings = solidlsp_settings.get_ls_specific_settings(Language.PASCAL) + pascal_settings = solidlsp_settings.get_ls_specific_settings(LanguageServerId.PASCAL) # pp: Path to FPC compiler driver (must be fpc.exe, NOT ppc386.exe/ppcx64.exe) # CodeTools queries fpc.exe for configuration via "fpc -iV", "fpc -iTO", etc. @@ -638,7 +638,7 @@ class PascalLanguageServer(SolidLanguageServer): str: The command to start the pasls server """ - pascal_settings = solidlsp_settings.get_ls_specific_settings(Language.PASCAL) + pascal_settings = solidlsp_settings.get_ls_specific_settings(LanguageServerId.PASCAL) pasls_version = pascal_settings.get("pasls_version", PASLS_VERSION) cls.PASLS_VERSION = pasls_version cls.PASLS_RELEASES_URL = f"https://github.com/zen010101/pascal-language-server/releases/download/{pasls_version}" diff --git a/src/solidlsp/language_servers/perl_language_server.py b/src/solidlsp/language_servers/perl_language_server.py index 7e3744b6..54496f60 100644 --- a/src/solidlsp/language_servers/perl_language_server.py +++ b/src/solidlsp/language_servers/perl_language_server.py @@ -12,7 +12,7 @@ from typing import Any from overrides import override from solidlsp.ls import SolidLanguageServer -from solidlsp.ls_config import Language, LanguageServerConfig +from solidlsp.ls_config import LanguageServerConfig, LanguageServerId from solidlsp.ls_utils import PlatformId, PlatformUtils from solidlsp.lsp_protocol_handler.lsp_types import DidChangeConfigurationParams from solidlsp.lsp_protocol_handler.server import ProcessLaunchInfo @@ -120,7 +120,7 @@ class PerlLanguageServer(SolidLanguageServer): ``ignore_dirs``); falls back to the defaults otherwise. Extracted as a pure function so the configuration plumbing can be unit-tested without starting the language server. """ - perl_settings = solidlsp_settings.get_ls_specific_settings(Language.PERL) + perl_settings = solidlsp_settings.get_ls_specific_settings(LanguageServerId.PERL) file_filter = perl_settings.get("file_filter", list(_DEFAULT_FILE_FILTER)) ignore_dirs = perl_settings.get("ignore_dirs", list(_DEFAULT_IGNORE_DIRS)) return file_filter, ignore_dirs @@ -135,7 +135,7 @@ class PerlLanguageServer(SolidLanguageServer): language composition detection. Without this, ``find_symbol`` would not surface symbols in files whose extensions were added to ``file_filter`` (#1449). """ - Language.PERL.get_source_fn_matcher().add_extensions(*file_filter) + LanguageServerId.PERL.get_source_fn_matcher().add_extensions(*file_filter) def __init__(self, config: LanguageServerConfig, repository_root_path: str, solidlsp_settings: SolidLSPSettings): # Setup runtime dependencies before initializing diff --git a/src/solidlsp/language_servers/phpactor.py b/src/solidlsp/language_servers/phpactor.py index 306374d9..7104baa6 100644 --- a/src/solidlsp/language_servers/phpactor.py +++ b/src/solidlsp/language_servers/phpactor.py @@ -12,7 +12,7 @@ import subprocess from overrides import override from solidlsp.ls import LanguageServerDependencyProvider, LanguageServerDependencyProviderSinglePath, SolidLanguageServer -from solidlsp.ls_config import Language, LanguageServerConfig +from solidlsp.ls_config import LanguageServerConfig from solidlsp.ls_utils import FileUtils from solidlsp.settings import SolidLSPSettings @@ -109,8 +109,6 @@ class PhpactorServer(SolidLanguageServer): def __init__(self, config: LanguageServerConfig, repository_root_path: str, solidlsp_settings: SolidLSPSettings): super().__init__(config, repository_root_path, None, "php", solidlsp_settings) - # Override internal language enum for correct file matching - self.language = Language.PHP_PHPACTOR self._ignored_dirnames = {"node_modules", "cache"} if self._custom_settings.get("ignore_vendor", True): diff --git a/src/solidlsp/language_servers/phpantom.py b/src/solidlsp/language_servers/phpantom.py index f0f11dd1..b461981c 100644 --- a/src/solidlsp/language_servers/phpantom.py +++ b/src/solidlsp/language_servers/phpantom.py @@ -17,7 +17,7 @@ from solidlsp.ls import ( LSPFileBuffer, SolidLanguageServer, ) -from solidlsp.ls_config import Language, LanguageServerConfig +from solidlsp.ls_config import LanguageServerConfig from solidlsp.ls_utils import PlatformId, PlatformUtils from solidlsp.lsp_protocol_handler import lsp_types as protocol_lsp_types from solidlsp.lsp_protocol_handler.lsp_types import Definition, DefinitionParams, LocationLink @@ -165,9 +165,6 @@ class PHPantomServer(SolidLanguageServer): def __init__(self, config: LanguageServerConfig, repository_root_path: str, solidlsp_settings: SolidLSPSettings): super().__init__(config, repository_root_path, None, "php", solidlsp_settings) - self.request_id = 0 - self.language = Language.PHP_PHPANTOM - self._ignored_dirnames = {"node_modules", "cache"} if self._custom_settings.get("ignore_vendor", True): self._ignored_dirnames.add("vendor") diff --git a/src/solidlsp/language_servers/powershell_language_server.py b/src/solidlsp/language_servers/powershell_language_server.py index 99bac570..7927a6ff 100644 --- a/src/solidlsp/language_servers/powershell_language_server.py +++ b/src/solidlsp/language_servers/powershell_language_server.py @@ -23,7 +23,7 @@ from overrides import override from solidlsp import ls_types from solidlsp.ls import LSPConstants, RawDocumentSymbol, SolidLanguageServer -from solidlsp.ls_config import Language, LanguageServerConfig +from solidlsp.ls_config import LanguageServerConfig, LanguageServerId from solidlsp.ls_types import SymbolKind from solidlsp.ls_utils import FileUtils from solidlsp.lsp_protocol_handler.server import ProcessLaunchInfo @@ -119,7 +119,7 @@ class PowerShellLanguageServer(SolidLanguageServer): @classmethod def _get_pses_path(cls, solidlsp_settings: SolidLSPSettings) -> str | None: """Get the path to PowerShell Editor Services installation.""" - ps_settings = solidlsp_settings.get_ls_specific_settings(Language.POWERSHELL) + ps_settings = solidlsp_settings.get_ls_specific_settings(LanguageServerId.POWERSHELL) pses_version = ps_settings.get("pses_version", DEFAULT_PSES_VERSION) install_dir = _pses_install_dir(cls.ls_resources_dir(solidlsp_settings), pses_version) start_script = install_dir / "PowerShellEditorServices" / "Start-EditorServices.ps1" @@ -132,7 +132,7 @@ class PowerShellLanguageServer(SolidLanguageServer): @classmethod def _download_pses(cls, solidlsp_settings: SolidLSPSettings) -> str: """Download and install PowerShell Editor Services.""" - ps_settings = solidlsp_settings.get_ls_specific_settings(Language.POWERSHELL) + ps_settings = solidlsp_settings.get_ls_specific_settings(LanguageServerId.POWERSHELL) pses_version = ps_settings.get("pses_version", DEFAULT_PSES_VERSION) download_url = ( f"https://github.com/PowerShell/PowerShellEditorServices/releases/download/v{pses_version}/PowerShellEditorServices.zip" @@ -184,7 +184,7 @@ class PowerShellLanguageServer(SolidLanguageServer): # The bundled modules path is the directory containing PowerShellEditorServices bundled_modules_path = str(Path(pses_path).parent) - psscriptanalyzer_version = solidlsp_settings.get_ls_specific_settings(Language.POWERSHELL).get( + psscriptanalyzer_version = solidlsp_settings.get_ls_specific_settings(LanguageServerId.POWERSHELL).get( "psscriptanalyzer_version", PSSCRIPTANALYZER_VERSION ) psscriptanalyzer_path = Path(bundled_modules_path) / "PSScriptAnalyzer" / psscriptanalyzer_version diff --git a/src/solidlsp/language_servers/pyrefly_server.py b/src/solidlsp/language_servers/pyrefly_server.py index b657895b..ce6899e6 100644 --- a/src/solidlsp/language_servers/pyrefly_server.py +++ b/src/solidlsp/language_servers/pyrefly_server.py @@ -51,7 +51,7 @@ class PyreflyLanguageServer(SolidLanguageServer): config, repository_root_path, None, - str(config.code_language), + str(config.ls_id), solidlsp_settings, ) self._ensure_workspace_pyrefly_config() diff --git a/src/solidlsp/language_servers/ruby_lsp.py b/src/solidlsp/language_servers/ruby_lsp.py index 0e66b16b..008637b5 100644 --- a/src/solidlsp/language_servers/ruby_lsp.py +++ b/src/solidlsp/language_servers/ruby_lsp.py @@ -18,7 +18,7 @@ import threading from overrides import override from solidlsp.ls import SolidLanguageServer -from solidlsp.ls_config import Language, LanguageServerConfig +from solidlsp.ls_config import LanguageServerConfig, LanguageServerId from solidlsp.lsp_protocol_handler.lsp_types import InitializeResult from solidlsp.lsp_protocol_handler.server import ProcessLaunchInfo from solidlsp.settings import SolidLSPSettings @@ -107,7 +107,7 @@ class RubyLsp(SolidLanguageServer): Setup runtime dependencies for ruby-lsp and return the command list to start the server. Installation strategy: Bundler project > global ruby-lsp > gem install ruby-lsp at the pinned version """ - ls_specific_settings = solidlsp_settings.get_ls_specific_settings(Language.RUBY) + ls_specific_settings = solidlsp_settings.get_ls_specific_settings(LanguageServerId.RUBY) ruby_lsp_version = ls_specific_settings.get("ruby_lsp_version", RUBY_LSP_VERSION) # Detect Ruby version manager environment # Using the version manager's exec wrapper ensures commands run with the correct Ruby version diff --git a/src/solidlsp/language_servers/scala_language_server.py b/src/solidlsp/language_servers/scala_language_server.py index f360d1ce..e9b03ace 100644 --- a/src/solidlsp/language_servers/scala_language_server.py +++ b/src/solidlsp/language_servers/scala_language_server.py @@ -52,7 +52,7 @@ def _get_scala_settings(solidlsp_settings: SolidLSPSettings) -> dict[str, object - on_stale_lock: StaleLockMode - log_multi_instance_notice: bool """ - from solidlsp.ls_config import Language + from solidlsp.ls_config import LanguageServerId defaults: dict[str, object] = { "metals_version": DEFAULT_METALS_VERSION, @@ -64,7 +64,7 @@ def _get_scala_settings(solidlsp_settings: SolidLSPSettings) -> dict[str, object if not solidlsp_settings.ls_specific_settings: return defaults - scala_settings = solidlsp_settings.get_ls_specific_settings(Language.SCALA) + scala_settings = solidlsp_settings.get_ls_specific_settings(LanguageServerId.SCALA) # Parse stale lock mode with validation on_stale_lock_str = scala_settings.get("on_stale_lock", DEFAULT_ON_STALE_LOCK) @@ -120,7 +120,7 @@ class ScalaLanguageServer(SolidLanguageServer): config, repository_root_path, ProcessLaunchInfo(cmd=scala_lsp_executable_path, cwd=repository_root_path), - config.code_language.value, + config.ls_id.value, solidlsp_settings, ) diff --git a/src/solidlsp/language_servers/solargraph.py b/src/solidlsp/language_servers/solargraph.py index b0ae3b00..969123a4 100644 --- a/src/solidlsp/language_servers/solargraph.py +++ b/src/solidlsp/language_servers/solargraph.py @@ -40,11 +40,6 @@ class Solargraph(SolidLanguageServer): "ruby", solidlsp_settings, ) - # Override internal language enum for file matching (excludes .erb files) - # while keeping LSP languageId as "ruby" for protocol compliance - from solidlsp.ls_config import Language - - self.language = Language.RUBY_SOLARGRAPH self.analysis_complete = threading.Event() self.service_ready_event = threading.Event() self.initialize_searcher_command_available = threading.Event() diff --git a/src/solidlsp/language_servers/svelte_language_server.py b/src/solidlsp/language_servers/svelte_language_server.py index ad82617e..b18e32e5 100644 --- a/src/solidlsp/language_servers/svelte_language_server.py +++ b/src/solidlsp/language_servers/svelte_language_server.py @@ -27,7 +27,7 @@ from solidlsp.ls import ( LSPFileBuffer, SolidLanguageServer, ) -from solidlsp.ls_config import FilenameMatcher, Language, LanguageServerConfig +from solidlsp.ls_config import FilenameMatcher, LanguageServerConfig, LanguageServerId from solidlsp.settings import SolidLSPSettings log = logging.getLogger(__name__) @@ -100,14 +100,14 @@ class SvelteTypeScriptServer(TypeScriptLanguageServer): @classmethod @override - def get_language_enum_instance(cls) -> Language: + def get_language_server_id(cls) -> LanguageServerId: """Return TYPESCRIPT; companion uses the TypeScript LS infrastructure.""" - return Language.TYPESCRIPT + return LanguageServerId.TYPESCRIPT @override def get_source_fn_matcher(self) -> FilenameMatcher: # include .svelte so references returned by the plugin are not filtered out - return Language.SVELTE.get_source_fn_matcher() + return LanguageServerId.SVELTE.get_source_fn_matcher() @override def _create_dependency_provider(self) -> LanguageServerDependencyProvider: @@ -273,7 +273,7 @@ class SvelteLanguageServer(SolidLanguageServer): @override def _create_dependency_provider(self) -> LanguageServerDependencyProvider: - ts_settings = self._solidlsp_settings.get_ls_specific_settings(Language.TYPESCRIPT) + ts_settings = self._solidlsp_settings.get_ls_specific_settings(LanguageServerId.TYPESCRIPT) return self.DependencyProvider(self._custom_settings, self._ls_resources_dir, ts_settings) def __init__(self, config: LanguageServerConfig, repo_path: str, solidlsp_settings: SolidLSPSettings): @@ -337,7 +337,7 @@ class SvelteLanguageServer(SolidLanguageServer): def _get_companion_indexing_timeout(self) -> float: """:return: maximum seconds to wait for companion TS indexing after opening Svelte files.""" - ts_settings = self._solidlsp_settings.get_ls_specific_settings(Language.TYPESCRIPT) + ts_settings = self._solidlsp_settings.get_ls_specific_settings(LanguageServerId.TYPESCRIPT) timeout = self._custom_settings.get( "indexing_timeout", ts_settings.get("indexing_timeout", SvelteTypeScriptServer.INDEXING_PROGRESS_TIMEOUT), @@ -417,7 +417,7 @@ class SvelteLanguageServer(SolidLanguageServer): """Spawn the companion :class:`SvelteTypeScriptServer`, wait for ready, then index .svelte files.""" try: ts_config = LanguageServerConfig( - code_language=Language.TYPESCRIPT, + ls_id=LanguageServerId.TYPESCRIPT, trace_lsp_communication=False, ) log.info("Creating companion SvelteTypeScriptServer") diff --git a/src/solidlsp/language_servers/terraform_ls.py b/src/solidlsp/language_servers/terraform_ls.py index a298fee1..d9b0531c 100644 --- a/src/solidlsp/language_servers/terraform_ls.py +++ b/src/solidlsp/language_servers/terraform_ls.py @@ -5,7 +5,7 @@ import shutil from overrides import override from solidlsp.ls import SolidLanguageServer -from solidlsp.ls_config import Language, LanguageServerConfig +from solidlsp.ls_config import LanguageServerConfig, LanguageServerId from solidlsp.ls_utils import PlatformUtils from solidlsp.lsp_protocol_handler.server import ProcessLaunchInfo from solidlsp.settings import SolidLSPSettings @@ -124,7 +124,7 @@ class TerraformLS(SolidLanguageServer): Downloads and installs terraform-ls if not already present. """ cls._ensure_tf_command_available() - terraform_settings = solidlsp_settings.get_ls_specific_settings(Language.TERRAFORM) + terraform_settings = solidlsp_settings.get_ls_specific_settings(LanguageServerId.TERRAFORM) terraform_ls_version = terraform_settings.get("terraform_ls_version", DEFAULT_TERRAFORM_LS_VERSION) platform_id = PlatformUtils.get_platform_id() deps = RuntimeDependencyCollection( diff --git a/src/solidlsp/language_servers/ty_server.py b/src/solidlsp/language_servers/ty_server.py index 4ce67355..ea20f54a 100644 --- a/src/solidlsp/language_servers/ty_server.py +++ b/src/solidlsp/language_servers/ty_server.py @@ -34,7 +34,7 @@ class TyLanguageServer(SolidLanguageServer): config, repository_root_path, None, - str(config.code_language), + str(config.ls_id), solidlsp_settings, ) diff --git a/src/solidlsp/language_servers/vts_language_server.py b/src/solidlsp/language_servers/vts_language_server.py index 84a80c4c..1f2cf1ae 100644 --- a/src/solidlsp/language_servers/vts_language_server.py +++ b/src/solidlsp/language_servers/vts_language_server.py @@ -12,7 +12,7 @@ import threading from overrides import override from solidlsp.ls import SolidLanguageServer -from solidlsp.ls_config import Language, LanguageServerConfig +from solidlsp.ls_config import LanguageServerConfig, LanguageServerId from solidlsp.ls_utils import PlatformId, PlatformUtils from solidlsp.lsp_protocol_handler.server import ProcessLaunchInfo from solidlsp.settings import SolidLSPSettings @@ -87,7 +87,7 @@ class VtsLanguageServer(SolidLanguageServer): PlatformId.WIN_arm64, ] assert platform_id in valid_platforms, f"Platform {platform_id} is not supported for vtsls at the moment" - vts_config = solidlsp_settings.get_ls_specific_settings(Language.TYPESCRIPT_VTS) + vts_config = solidlsp_settings.get_ls_specific_settings(LanguageServerId.TYPESCRIPT_VTS) vtsls_version = vts_config.get("vtsls_version", DEFAULT_VTSLS_VERSION) npm_registry = vts_config.get("npm_registry") diff --git a/src/solidlsp/language_servers/vue_language_server.py b/src/solidlsp/language_servers/vue_language_server.py index b4d79297..74519276 100644 --- a/src/solidlsp/language_servers/vue_language_server.py +++ b/src/solidlsp/language_servers/vue_language_server.py @@ -22,7 +22,7 @@ from solidlsp.language_servers.typescript_language_server import ( prefer_non_node_modules_definition, ) from solidlsp.ls import LanguageServerDependencyProvider, LSPFileBuffer, SolidLanguageServer -from solidlsp.ls_config import FilenameMatcher, Language, LanguageServerConfig +from solidlsp.ls_config import FilenameMatcher, LanguageServerConfig, LanguageServerId from solidlsp.ls_exceptions import SolidLSPException from solidlsp.ls_types import Location from solidlsp.ls_utils import PathUtils @@ -39,19 +39,19 @@ class VueTypeScriptServer(TypeScriptLanguageServer): @classmethod @override - def get_language_enum_instance(cls) -> Language: + def get_language_server_id(cls) -> LanguageServerId: """Return TYPESCRIPT since this is a TypeScript language server variant. Note: VueTypeScriptServer is a companion server that uses TypeScript's language server with the Vue TypeScript plugin. It reports as TYPESCRIPT to maintain compatibility with the TypeScript language server infrastructure. """ - return Language.TYPESCRIPT + return LanguageServerId.TYPESCRIPT def get_source_fn_matcher(self) -> FilenameMatcher: # must override with Vue-specific matcher to ensure .vue files are included (as they can be discovered via references, # for instance; otherwise, we may find references in .vue files but then filter the results out, because .vue files are ignored.) - return Language.VUE.get_source_fn_matcher() + return LanguageServerId.VUE.get_source_fn_matcher() class DependencyProvider(TypeScriptLanguageServer.DependencyProvider): """Dependency provider that returns a pre-resolved executable path. @@ -536,10 +536,10 @@ class VueLanguageServer(SolidLanguageServer): assert is_npm_installed, "npm is not installed or isn't in PATH. Please install npm and try again." # Get TypeScript version settings from TypeScript language server settings - typescript_config = solidlsp_settings.get_ls_specific_settings(Language.TYPESCRIPT) + typescript_config = solidlsp_settings.get_ls_specific_settings(LanguageServerId.TYPESCRIPT) typescript_version = typescript_config.get("typescript_version", "5.9.3") typescript_language_server_version = typescript_config.get("typescript_language_server_version", "5.1.3") - vue_config = solidlsp_settings.get_ls_specific_settings(Language.VUE) + vue_config = solidlsp_settings.get_ls_specific_settings(LanguageServerId.VUE) vue_language_server_version = vue_config.get("vue_language_server_version", "3.1.5") npm_registry = vue_config.get("npm_registry", typescript_config.get("npm_registry")) @@ -659,7 +659,7 @@ class VueLanguageServer(SolidLanguageServer): vue_ts_plugin_path = os.path.join(self._vue_ls_dir, "node_modules", "@vue", "typescript-plugin") ts_config = LanguageServerConfig( - code_language=Language.TYPESCRIPT, + ls_id=LanguageServerId.TYPESCRIPT, trace_lsp_communication=False, ) diff --git a/src/solidlsp/ls.py b/src/solidlsp/ls.py index 56767490..f76bb5fe 100644 --- a/src/solidlsp/ls.py +++ b/src/solidlsp/ls.py @@ -31,7 +31,7 @@ from solidlsp.dependency_provider import ( LanguageServerDependencyProviderUvx, ) from solidlsp.initialize_params import DefaultInitializeParamsBuilder, InitializeParamsBuilder -from solidlsp.ls_config import FilenameMatcher, Language, LanguageServerConfig +from solidlsp.ls_config import FilenameMatcher, LanguageServerConfig, LanguageServerId from solidlsp.ls_exceptions import InvalidTextLocationError, SolidLSPException from solidlsp.ls_process import LanguageServerInterface, StdioLanguageServer from solidlsp.ls_types import UnifiedSymbolInformation @@ -383,8 +383,8 @@ class SolidLanguageServer(ABC): return logging.INFO @classmethod - def get_language_enum_instance(cls) -> Language: - return Language.from_ls_class(cls) + def get_language_server_id(cls) -> LanguageServerId: + return LanguageServerId.from_ls_class(cls) @classmethod def supports_implementation_request(cls) -> bool: @@ -442,7 +442,7 @@ class SolidLanguageServer(ABC): # Ensure repository_root_path is absolute to avoid issues with file URIs repository_root_path = os.path.abspath(repository_root_path) - ls_class = config.code_language.get_ls_class() + ls_class = config.ls_id.get_ls_class() # All language server implementations are required to use the same signature of the constructor # (which differs from the signature of the base class constructor). ls = ls_class(config, repository_root_path, solidlsp_settings) @@ -481,13 +481,13 @@ class SolidLanguageServer(ABC): """ self.config = config self._solidlsp_settings = solidlsp_settings - lang = self.get_language_enum_instance() - self._custom_settings = solidlsp_settings.get_ls_specific_settings(lang) + ls_id = self.get_language_server_id() + self._custom_settings = solidlsp_settings.get_ls_specific_settings(ls_id) """ the (user-provided) language server-specific settings """ self._ls_resources_dir = self.ls_resources_dir(solidlsp_settings) - log.debug(f"Custom config (LS-specific settings) for {lang}: {self._custom_settings}") + log.debug(f"Custom config (LS-specific settings) for {ls_id}: {self._custom_settings}") self._encoding = config.encoding self.repository_root_path: str = repository_root_path @@ -500,15 +500,15 @@ class SolidLanguageServer(ABC): default language identifier to be passed to the language server in `textDocument/didOpen` notifications. """ self.open_file_buffers: dict[str, LSPFileBuffer] = {} - self.language = self.get_language_enum_instance() + self.ls_id = self.get_language_server_id() """ - identifies the language server (not to be confused with the language id passed to the language server) + identifies the language server (not to be confused with the language_id passed to the language server) """ # The source filename matcher is a @cache'd per-language singleton. A previous project may # have extended it (e.g. Perl's file_filter adding .cgi); reset it here so every activation # starts from the language's default extensions, then language-server subclasses re-apply # their own settings during the rest of __init__. - self.language.get_source_fn_matcher().reset() + self.ls_id.get_source_fn_matcher().reset() self._published_diagnostics: dict[str, list[ls_types.Diagnostic]] = {} self._published_diagnostics_generation_by_uri: dict[str, int] = {} self._published_diagnostics_generation = 0 @@ -611,7 +611,7 @@ class SolidLanguageServer(ABC): log.debug(f"Creating language server instance with {language_id=} and {process_launch_info}") return StdioLanguageServer( process_launch_info, - language=self.language, + ls_id=self.ls_id, determine_log_level=self._determine_log_level, logger=logging_fn, start_independent_lsp_process=self.config.start_independent_lsp_process, @@ -1167,7 +1167,7 @@ class SolidLanguageServer(ABC): are understood by this language server or are discovered as containing sources indirectly, e.g. via references """ # By default, use the matcher of the language - return self.language.get_source_fn_matcher() + return self.ls_id.get_source_fn_matcher() def is_ignored_path(self, relative_path: str, ignore_unsupported_files: bool = True) -> bool: """ @@ -3131,7 +3131,7 @@ class SolidLanguageServer(ABC): :return: self for method chaining """ - log.info(f"Starting language server with language {self.language_server.language} for {self.language_server.repository_root_path}") + log.info(f"Starting language server {self.language_server.ls_id} for {self.language_server.repository_root_path}") self.server_started = True self._start_server() return self diff --git a/src/solidlsp/ls_config.py b/src/solidlsp/ls_config.py index 398988ce..2db41106 100644 --- a/src/solidlsp/ls_config.py +++ b/src/solidlsp/ls_config.py @@ -87,7 +87,7 @@ class FilenameMatcher: return False -class Language(str, Enum): +class LanguageServerId(str, Enum): """ Enumeration of language servers supported by SolidLSP. """ @@ -895,7 +895,7 @@ class LanguageServerConfig: Configuration parameters for a language server instance """ - code_language: Language + ls_id: LanguageServerId """ defines the language server to use """ diff --git a/src/solidlsp/ls_exceptions.py b/src/solidlsp/ls_exceptions.py index 214b890b..5b34c406 100644 --- a/src/solidlsp/ls_exceptions.py +++ b/src/solidlsp/ls_exceptions.py @@ -2,7 +2,7 @@ This module contains the exceptions raised by the framework. """ -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId class SolidLSPException(Exception): @@ -28,14 +28,14 @@ class SolidLSPException(Exception): return isinstance(self.cause, LanguageServerTerminatedException) - def get_affected_language(self) -> Language | None: + def get_affected_language(self) -> LanguageServerId | None: """ :return: the affected language for the case where the exception is caused by the language server having terminated """ from .ls_process import LanguageServerTerminatedException if isinstance(self.cause, LanguageServerTerminatedException): - return self.cause.language + return self.cause.ls_id return None def __str__(self) -> str: diff --git a/src/solidlsp/ls_process.py b/src/solidlsp/ls_process.py index b7f1a3d8..b369ff11 100644 --- a/src/solidlsp/ls_process.py +++ b/src/solidlsp/ls_process.py @@ -14,7 +14,7 @@ from typing import IO, Any, AnyStr, cast from sensai.util.string import ToStringMixin -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from solidlsp.ls_exceptions import SolidLSPException from solidlsp.ls_request import LanguageServerRequest from solidlsp.lsp_protocol_handler.lsp_requests import LspNotification @@ -53,10 +53,10 @@ class LanguageServerTerminatedException(Exception): Exception raised when the language server process has terminated unexpectedly. """ - def __init__(self, message: str, language: Language, cause: Exception | None = None) -> None: + def __init__(self, message: str, ls_id: LanguageServerId, cause: Exception | None = None) -> None: super().__init__(message) self.message = message - self.language = language + self.ls_id = ls_id self.cause = cause def __str__(self) -> str: @@ -116,18 +116,18 @@ class LanguageServerInterface(ABC): def __init__( self, - language: Language, + ls_id: LanguageServerId, determine_log_level: Callable[[str], int], logger: Callable[[str, str, StringDict | str], None] | None = None, request_timeout: float | None = None, ) -> None: """ - :param language: the language + :param ls_id: the language server identifier :param determine_log_level: a function for log lines read from stderr, which determines the log level :param logger: the trace logger function :param request_timeout: the timeout, in seconds, for all requests sent to the language server. If None, no timeout will be applied. """ - self.language = language + self.ls_id = ls_id self._determine_log_level = determine_log_level self.send = LanguageServerRequest(self) """ @@ -486,7 +486,7 @@ class StdioLanguageServer(LanguageServerInterface): def __init__( self, process_launch_info: ProcessLaunchInfo, - language: Language, + ls_id: LanguageServerId, determine_log_level: Callable[[str], int], logger: Callable[[str, str, StringDict | str], None] | None = None, start_independent_lsp_process: bool = True, @@ -494,13 +494,13 @@ class StdioLanguageServer(LanguageServerInterface): ) -> None: """ :param process_launch_info: the information required to launch the language server process - :param language: the language + :param ls_id: the language :param determine_log_level: a function for log lines read from stderr, which determines the log level :param logger: the trace logger function :param start_independent_lsp_process: whether to start the language server process in an independent process group :param request_timeout: the timeout, in seconds, for all requests sent to the language server. If None, no timeout will be applied. """ - super().__init__(language, determine_log_level, logger, request_timeout) + super().__init__(ls_id, determine_log_level, logger, request_timeout) self.process_launch_info = process_launch_info self.process: subprocess.Popen[bytes] | None = None @@ -547,12 +547,12 @@ class StdioLanguageServer(LanguageServerInterface): # start threads to read stdout and stderr of the process threading.Thread( target=self._read_ls_process_stdout, - name=f"LSP-stdout-reader:{self.language.value}", + name=f"LSP-stdout-reader:{self.ls_id.value}", daemon=True, ).start() threading.Thread( target=self._read_ls_process_stderr, - name=f"LSP-stderr-reader:{self.language.value}", + name=f"LSP-stderr-reader:{self.ls_id.value}", daemon=True, ).start() @@ -571,7 +571,7 @@ class StdioLanguageServer(LanguageServerInterface): # Ignore errors here, we are proceeding to terminate anyway. # terminate the process subprocess_util.terminate_process_tree_with_kill_fallback( - self.process, terminate_timeout=timeout, process_name=f"LS[{self.language.value}]" + self.process, terminate_timeout=timeout, process_name=f"LS[{self.ls_id.value}]" ) finally: self.process = None @@ -594,7 +594,7 @@ class StdioLanguageServer(LanguageServerInterface): if process.poll() is not None: raise LanguageServerTerminatedException( f"Process terminated while trying to read response (read {len(data)} of {num_bytes} bytes before termination)", - language=self.language, + ls_id=self.ls_id, ) # Process still running but no data available yet, retry after a short delay time.sleep(0.01) @@ -631,15 +631,15 @@ class StdioLanguageServer(LanguageServerInterface): except LanguageServerTerminatedException as e: exception = e except (BrokenPipeError, ConnectionResetError) as e: - exception = LanguageServerTerminatedException("Language server process terminated while reading stdout", self.language, cause=e) + exception = LanguageServerTerminatedException("Language server process terminated while reading stdout", self.ls_id, cause=e) except Exception as e: exception = LanguageServerTerminatedException( - "Unexpected error while reading stdout from language server process", self.language, cause=e + "Unexpected error while reading stdout from language server process", self.ls_id, cause=e ) log.info("Language server stdout reader thread has terminated") if not self._is_stopping: if exception is None: - exception = LanguageServerTerminatedException("Language server stdout read process terminated unexpectedly", self.language) + exception = LanguageServerTerminatedException("Language server stdout read process terminated unexpectedly", self.ls_id) log.error(str(exception)) self._cancel_pending_requests(exception) @@ -704,12 +704,12 @@ class TCPLanguageServer(LanguageServerInterface): def __init__( self, connection_info: TCPConnectionInfo, - language: Language, + ls_id: LanguageServerId, determine_log_level: Callable[[str], int], logger: Callable[[str, str, StringDict | str], None] | None = None, request_timeout: float | None = None, ) -> None: - super().__init__(language, determine_log_level, logger, request_timeout) + super().__init__(ls_id, determine_log_level, logger, request_timeout) self._connection_info = connection_info self._sock: socket.socket | None = None self._file: Any = None # socket.makefile("rb") - buffered reader @@ -747,7 +747,7 @@ class TCPLanguageServer(LanguageServerInterface): threading.Thread( target=self._read_loop, - name=f"LSP-tcp-reader:{self.language.value}", + name=f"LSP-tcp-reader:{self.ls_id.value}", daemon=True, ).start() @@ -788,7 +788,7 @@ class TCPLanguageServer(LanguageServerInterface): log.error("Failed to write to TCP language server: %s", e) self._sock = None self._file = None - self._cancel_pending_requests(LanguageServerTerminatedException("TCP send error", self.language, cause=e)) + self._cancel_pending_requests(LanguageServerTerminatedException("TCP send error", self.ls_id, cause=e)) def _read_loop(self) -> None: """Read Content-Length-framed LSP messages from the TCP socket and dispatch them.""" @@ -802,7 +802,7 @@ class TCPLanguageServer(LanguageServerInterface): line = f.readline() except OSError as exc: if not self._is_stopping: - exception = LanguageServerTerminatedException("TCP read error", self.language, cause=exc) + exception = LanguageServerTerminatedException("TCP read error", self.ls_id, cause=exc) break if not line: break @@ -824,17 +824,17 @@ class TCPLanguageServer(LanguageServerInterface): body = f.read(num_bytes) except OSError as exc: if not self._is_stopping: - exception = LanguageServerTerminatedException("TCP read error", self.language, cause=exc) + exception = LanguageServerTerminatedException("TCP read error", self.ls_id, cause=exc) break if len(body) < num_bytes: break self._handle_body(body) except Exception as exc: - exception = LanguageServerTerminatedException("Unexpected error in TCP language server read loop", self.language, cause=exc) + exception = LanguageServerTerminatedException("Unexpected error in TCP language server read loop", self.ls_id, cause=exc) log.info("TCP language server read loop has terminated") if not self._is_stopping: if exception is None: - exception = LanguageServerTerminatedException("TCP language server read loop terminated unexpectedly", self.language) + exception = LanguageServerTerminatedException("TCP language server read loop terminated unexpectedly", self.ls_id) log.error(str(exception)) self._cancel_pending_requests(exception) # Clear the socket so is_running() returns False, allowing _ensure_functional_ls diff --git a/src/solidlsp/settings.py b/src/solidlsp/settings.py index 373f5d2f..a5ee4ace 100644 --- a/src/solidlsp/settings.py +++ b/src/solidlsp/settings.py @@ -11,7 +11,7 @@ from typing import TYPE_CHECKING, Any from sensai.util.string import ToStringMixin if TYPE_CHECKING: - from solidlsp.ls_config import Language + from solidlsp.ls_config import LanguageServerId log = logging.getLogger(__name__) @@ -34,7 +34,7 @@ class SolidLSPSettings: For instance, if this is "/home/user/myproject/.solidlsp", then Solid-LSP will store project-specific data (e.g. caches) in that directory. """ - ls_specific_settings: dict["Language", dict[str, Any]] = field(default_factory=dict) + ls_specific_settings: dict["LanguageServerId", dict[str, Any]] = field(default_factory=dict) """ Advanced configuration option allowing to configure language server implementation specific options. Have a look at the docstring of the constructors of the corresponding LS implementations within solidlsp to see which options are available. @@ -50,6 +50,10 @@ class SolidLSPSettings: return os.path.join(str(self.solidlsp_dir), "language_servers", "static") class CustomLSSettings(ToStringMixin): + """ + Represents custom (user-specified) settings for a specific language server. + """ + def __init__(self, settings: dict[str, Any] | None) -> None: self.settings = settings or {} @@ -69,11 +73,11 @@ class SolidLSPSettings: value = default_value return value - def get_ls_specific_settings(self, language: "Language") -> CustomLSSettings: + def get_ls_specific_settings(self, ls_id: "LanguageServerId") -> CustomLSSettings: """ - Get the language server specific settings for the given language. + Gets the custom settings for the given language server - :param language: The programming language. - :return: A dictionary of settings for the language server. + :param ls_id: the language server identifier for which to retrieve settings + :return: a dictionary of settings for the language server """ - return self.CustomLSSettings(self.ls_specific_settings.get(language)) + return self.CustomLSSettings(self.ls_specific_settings.get(ls_id)) diff --git a/test/conftest.py b/test/conftest.py index e1a11dbc..9110b68e 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -19,7 +19,7 @@ from serena.constants import SERENA_MANAGED_DIR_NAME from serena.project import Project from serena.util.file_system import GitignoreParser from solidlsp.ls import SolidLanguageServer -from solidlsp.ls_config import Language, LanguageServerConfig +from solidlsp.ls_config import LanguageServerConfig, LanguageServerId from solidlsp.settings import SolidLSPSettings from .solidlsp.clojure import is_clojure_cli_available @@ -39,47 +39,47 @@ def resources_dir() -> Path: class LanguageParamRequest: - param: Language + param: LanguageServerId -_LANGUAGE_REPO_ALIASES: dict[Language, Language] = { - Language.CPP_CCLS: Language.CPP, - Language.PHP_PHPACTOR: Language.PHP, - Language.PHP_PHPANTOM: Language.PHP, - Language.PYTHON_JEDI: Language.PYTHON, - Language.PYTHON_BASEDPYRIGHT: Language.PYTHON, - Language.PYTHON_TY: Language.PYTHON, - Language.RUBY_SOLARGRAPH: Language.RUBY, - Language.PYTHON_TY: Language.PYTHON, - Language.PYTHON_PYREFLY: Language.PYTHON, +_LANGUAGE_REPO_ALIASES: dict[LanguageServerId, LanguageServerId] = { + LanguageServerId.CPP_CCLS: LanguageServerId.CPP, + LanguageServerId.PHP_PHPACTOR: LanguageServerId.PHP, + LanguageServerId.PHP_PHPANTOM: LanguageServerId.PHP, + LanguageServerId.PYTHON_JEDI: LanguageServerId.PYTHON, + LanguageServerId.PYTHON_BASEDPYRIGHT: LanguageServerId.PYTHON, + LanguageServerId.PYTHON_TY: LanguageServerId.PYTHON, + LanguageServerId.RUBY_SOLARGRAPH: LanguageServerId.RUBY, + LanguageServerId.PYTHON_TY: LanguageServerId.PYTHON, + LanguageServerId.PYTHON_PYREFLY: LanguageServerId.PYTHON, } -PYTHON_LANGUAGE_BACKENDS = [Language.PYTHON, Language.PYTHON_TY, Language.PYTHON_BASEDPYRIGHT] +PYTHON_LANGUAGE_BACKENDS = [LanguageServerId.PYTHON, LanguageServerId.PYTHON_TY, LanguageServerId.PYTHON_BASEDPYRIGHT] -def get_repo_path(language: Language) -> Path: +def get_repo_path(language: LanguageServerId) -> Path: repo_language = _LANGUAGE_REPO_ALIASES.get(language, language) return Path(__file__).parent / "resources" / "repos" / repo_language / "test_repo" def _create_ls( - language: Language, + ls_id: LanguageServerId, repo_path: str | None = None, ignored_paths: list[str] | None = None, trace_lsp_communication: bool = False, - ls_specific_settings: dict[Language, dict[str, Any]] | None = None, + ls_specific_settings: dict[LanguageServerId, dict[str, Any]] | None = None, workspace_folders: list[str] | None = None, additional_workspace_folders: list[str] | None = None, solidlsp_dir: Path | None = None, ) -> SolidLanguageServer: ignored_paths = ignored_paths or [] if repo_path is None: - repo_path = str(get_repo_path(language)) + repo_path = str(get_repo_path(ls_id)) gitignore_parser = GitignoreParser(str(repo_path)) for spec in gitignore_parser.get_ignore_specs(): ignored_paths.extend(spec.patterns) config = LanguageServerConfig( - code_language=language, + ls_id=ls_id, ignored_paths=ignored_paths, trace_lsp_communication=trace_lsp_communication, workspace_folders=workspace_folders or ["."], @@ -100,17 +100,17 @@ def _create_ls( @contextmanager def start_ls_context( - language: Language, + ls_id: LanguageServerId, repo_path: str | None = None, ignored_paths: list[str] | None = None, trace_lsp_communication: bool = False, - ls_specific_settings: dict[Language, dict[str, Any]] | None = None, + ls_specific_settings: dict[LanguageServerId, dict[str, Any]] | None = None, workspace_folders: list[str] | None = None, additional_workspace_folders: list[str] | None = None, solidlsp_dir: Path | None = None, ) -> Iterator[SolidLanguageServer]: ls = _create_ls( - language, + ls_id, repo_path, ignored_paths, trace_lsp_communication, @@ -119,14 +119,14 @@ def start_ls_context( additional_workspace_folders, solidlsp_dir, ) - log.info(f"Starting language server for {language} {repo_path}") + log.info(f"Starting language server for {ls_id} {repo_path}") with ls.start_server_context(): yield ls @contextmanager -def start_default_ls_context(language: Language) -> Iterator[SolidLanguageServer]: - with start_ls_context(language) as ls: +def start_default_ls_context(ls_id: LanguageServerId) -> Iterator[SolidLanguageServer]: + with start_ls_context(ls_id) as ls: yield ls @@ -134,8 +134,8 @@ def create_default_serena_config(): return SerenaConfig().with_headless_mode_overrides() -def _create_default_project(language: Language, repo_root_override: str | None = None) -> Project: - repo_path = str(get_repo_path(language)) if repo_root_override is None else repo_root_override +def _create_default_project(ls_id: LanguageServerId, repo_root_override: str | None = None) -> Project: + repo_path = str(get_repo_path(ls_id)) if repo_root_override is None else repo_root_override return Project.load(repo_path, serena_config=create_default_serena_config()) @@ -193,9 +193,9 @@ def language_server(request: LanguageParamRequest): @contextmanager -def project_context(language: Language, repo_root_override: str | None = None) -> Iterator[Project]: +def project_context(ls_id: LanguageServerId, repo_root_override: str | None = None) -> Iterator[Project]: """Context manager that creates a Project for the specified language and ensures proper cleanup.""" - project = _create_default_project(language, repo_root_override) + project = _create_default_project(ls_id, repo_root_override) try: yield project finally: @@ -233,16 +233,16 @@ def project(request: LanguageParamRequest, repo_root_override: str | None = None @contextmanager -def project_with_ls_context(language: Language, repo_root_override: str | None = None) -> Iterator[Project]: +def project_with_ls_context(ls_id: LanguageServerId, repo_root_override: str | None = None) -> Iterator[Project]: """Context manager that creates a Project with an active language server for the specified language.""" - with project_context(language, repo_root_override) as project: + with project_context(ls_id, repo_root_override) as project: project.create_language_server_manager() yield project @contextmanager -def agent_for_project_context(language: Language, repo_root_override: str | None = None) -> Iterator[SerenaAgent]: - project_root = str(get_repo_path(language)) if repo_root_override is None else repo_root_override +def agent_for_project_context(ls_id: LanguageServerId, repo_root_override: str | None = None) -> Iterator[SerenaAgent]: + project_root = str(get_repo_path(ls_id)) if repo_root_override is None else repo_root_override agent = SerenaAgent(project=project_root, serena_config=create_default_serena_config()) # wait for agent to be ready @@ -273,50 +273,50 @@ is_macos = platform.system() == "Darwin" is_linux = platform.system() == "Linux" -_LANGUAGE_PYTEST_MARKERS: dict[Language, list[MarkDecorator | Mark]] = { - Language.ADA: [pytest.mark.ada], - Language.CLOJURE: [pytest.mark.clojure], - Language.CPP: [pytest.mark.cpp], - Language.CPP_CCLS: [pytest.mark.cpp], - Language.CUE: [pytest.mark.cue], - Language.CSHARP: [pytest.mark.csharp], - Language.FSHARP: [pytest.mark.fsharp], - Language.GO: [pytest.mark.go], - Language.HAXE: [pytest.mark.haxe], - Language.JAVA: [pytest.mark.java], - Language.KOTLIN: [pytest.mark.kotlin], - Language.LEAN4: [pytest.mark.lean4], - Language.LATEX: [pytest.mark.latex], - Language.MSL: [pytest.mark.msl], - Language.PHP: [pytest.mark.php], - Language.PHP_PHPACTOR: [pytest.mark.php], - Language.PHP_PHPANTOM: [pytest.mark.php], - Language.POWERSHELL: [pytest.mark.powershell], - Language.PYTHON: [pytest.mark.python], - Language.PYTHON_JEDI: [pytest.mark.python], - Language.PYTHON_TY: [pytest.mark.python], - Language.PYTHON_PYREFLY: [pytest.mark.python], - Language.PYTHON_BASEDPYRIGHT: [pytest.mark.python], - Language.RUST: [pytest.mark.rust], - Language.TYPESCRIPT: [pytest.mark.typescript], - Language.BSL: [pytest.mark.bsl], - Language.SVELTE: [pytest.mark.svelte], - Language.ANGULAR: [pytest.mark.angular], - Language.HTML: [pytest.mark.html], - Language.SCSS: [pytest.mark.scss], +_LANGUAGE_PYTEST_MARKERS: dict[LanguageServerId, list[MarkDecorator | Mark]] = { + LanguageServerId.ADA: [pytest.mark.ada], + LanguageServerId.CLOJURE: [pytest.mark.clojure], + LanguageServerId.CPP: [pytest.mark.cpp], + LanguageServerId.CPP_CCLS: [pytest.mark.cpp], + LanguageServerId.CUE: [pytest.mark.cue], + LanguageServerId.CSHARP: [pytest.mark.csharp], + LanguageServerId.FSHARP: [pytest.mark.fsharp], + LanguageServerId.GO: [pytest.mark.go], + LanguageServerId.HAXE: [pytest.mark.haxe], + LanguageServerId.JAVA: [pytest.mark.java], + LanguageServerId.KOTLIN: [pytest.mark.kotlin], + LanguageServerId.LEAN4: [pytest.mark.lean4], + LanguageServerId.LATEX: [pytest.mark.latex], + LanguageServerId.MSL: [pytest.mark.msl], + LanguageServerId.PHP: [pytest.mark.php], + LanguageServerId.PHP_PHPACTOR: [pytest.mark.php], + LanguageServerId.PHP_PHPANTOM: [pytest.mark.php], + LanguageServerId.POWERSHELL: [pytest.mark.powershell], + LanguageServerId.PYTHON: [pytest.mark.python], + LanguageServerId.PYTHON_JEDI: [pytest.mark.python], + LanguageServerId.PYTHON_TY: [pytest.mark.python], + LanguageServerId.PYTHON_PYREFLY: [pytest.mark.python], + LanguageServerId.PYTHON_BASEDPYRIGHT: [pytest.mark.python], + LanguageServerId.RUST: [pytest.mark.rust], + LanguageServerId.TYPESCRIPT: [pytest.mark.typescript], + LanguageServerId.BSL: [pytest.mark.bsl], + LanguageServerId.SVELTE: [pytest.mark.svelte], + LanguageServerId.ANGULAR: [pytest.mark.angular], + LanguageServerId.HTML: [pytest.mark.html], + LanguageServerId.SCSS: [pytest.mark.scss], } -def get_pytest_markers(language: Language) -> list[MarkDecorator | Mark]: - """Pytest markers for a language. +def get_pytest_markers(ls_id: LanguageServerId) -> list[MarkDecorator | Mark]: + """Pytest markers for a language server. - Returns the primary language marker plus the central enablement skip derived from + Returns the primary language server marker plus the central enablement skip derived from ``language_tests_enabled()`` -- so per-language availability/reliability lives in exactly one place (``_determine_disabled_languages``) instead of being duplicated per marker or per test file. """ return [ - *_LANGUAGE_PYTEST_MARKERS[language], - pytest.mark.skipif(not language_tests_enabled(language), reason=f"{language.value} tests are disabled in this environment"), + *_LANGUAGE_PYTEST_MARKERS[ls_id], + pytest.mark.skipif(not language_server_tests_enabled(ls_id), reason=f"{ls_id.value} tests are disabled in this environment"), ] @@ -395,9 +395,9 @@ def _is_ocaml_lsp_available() -> bool: return False -def _determine_disabled_languages() -> list[Language]: +def _determine_disabled_language_servers() -> list[LanguageServerId]: """ - Determine which language tests are disabled in the current environment. + Determine which language server tests are disabled in the current environment. Every language falls into exactly ONE of the categories below; a language that is not appended here is **category 4 (enabled everywhere)**, e.g. python, typescript, go, java, kotlin-locally. @@ -412,112 +412,112 @@ def _determine_disabled_languages() -> list[Language]: 4. ENABLED EVERYWHERE -- not listed in this function at all. 5. DISABLED ONLY ON CI (resource/stability reasons) even though the precondition holds locally. """ - result: list[Language] = [] + result: list[LanguageServerId] = [] # === 1. Always disabled (flaky / broken everywhere) === - result.append(Language.BSL) # 1C:Enterprise; niche and the tests are slow and flaky - result.append(Language.FSHARP) # F# language server is currently unreliable + result.append(LanguageServerId.BSL) # 1C:Enterprise; niche and the tests are slow and flaky + result.append(LanguageServerId.FSHARP) # F# language server is currently unreliable # === 2. Disabled off-CI if the precondition is missing; expected to be present on CI === if _sh.which("terraform") is None and not is_ci: - result.append(Language.TERRAFORM) + result.append(LanguageServerId.TERRAFORM) if _sh.which("regal") is None and not is_ci: - result.append(Language.REGO) + result.append(LanguageServerId.REGO) if _sh.which("elm") is None and not is_ci: - result.append(Language.ELM) + result.append(LanguageServerId.ELM) # qmlls is installed (standalone build; see pytest.yml) only on the Ubuntu other-langs CI batch. It is # expected there, so a missing binary on Linux CI is NOT skipped here -- the test runs and fails loudly, # catching a CI setup regression. On Windows/macOS CI (never installed) and off-CI without the binary it skips. if (_sh.which("qmlls6") is None and _sh.which("qmlls") is None) and not (is_ci and is_linux): - result.append(Language.QML) + result.append(LanguageServerId.QML) # === 3. Disabled wherever the precondition is missing (including on CI) === # 3a. Platform precondition: these language servers have no native Windows support. if is_windows: - result.append(Language.ANSIBLE) # ansible-language-server has no native Windows support + result.append(LanguageServerId.ANSIBLE) # ansible-language-server has no native Windows support if not is_macos: - result.append(Language.SWIFT) # swiftly toolchain is only set up on the macOS native batch + result.append(LanguageServerId.SWIFT) # swiftly toolchain is only set up on the macOS native batch # 3b. Toolchain / language-server availability (the LS/compiler must be on PATH or installed). if _sh.which("clangd") is None: - result.append(Language.CPP) + result.append(LanguageServerId.CPP) if _sh.which("ccls") is None or is_windows: # no recent ccls binary is available for Windows - result.append(Language.CPP_CCLS) + result.append(LanguageServerId.CPP_CCLS) if _sh.which("php") is None: - result.append(Language.PHP_PHPACTOR) - result.append(Language.PHP_PHPANTOM) + result.append(LanguageServerId.PHP_PHPACTOR) + result.append(LanguageServerId.PHP_PHPANTOM) if not is_clojure_cli_available(): - result.append(Language.CLOJURE) + result.append(LanguageServerId.CLOJURE) if _sh.which("verible-verilog-ls") is None: - result.append(Language.SYSTEMVERILOG) + result.append(LanguageServerId.SYSTEMVERILOG) if not _is_matlab_available(): - result.append(Language.MATLAB) + result.append(LanguageServerId.MATLAB) if ERLANG_LS_UNAVAILABLE: # no Erlang-OTP / no rebar3 / Windows -- see test/solidlsp/erlang - result.append(Language.ERLANG) + result.append(LanguageServerId.ERLANG) if EXPERT_UNAVAILABLE: # Elixir not installed -- see test/solidlsp/elixir - result.append(Language.ELIXIR) + result.append(LanguageServerId.ELIXIR) if _sh.which("lean") is None: - result.append(Language.LEAN4) + result.append(LanguageServerId.LEAN4) if _sh.which("crystalline") is None: - result.append(Language.CRYSTAL) + result.append(LanguageServerId.CRYSTAL) if _sh.which("julia") is None: # LanguageServer.jl is auto-installed by the LS when julia is present - result.append(Language.JULIA) + result.append(LanguageServerId.JULIA) if _sh.which("nixd") is None: - result.append(Language.NIX) + result.append(LanguageServerId.NIX) if _sh.which("haskell-language-server-wrapper") is None: - result.append(Language.HASKELL) + result.append(LanguageServerId.HASKELL) if not _is_r_language_server_available(): # `which("R")` isn't enough -- needs the languageserver package - result.append(Language.R) + result.append(LanguageServerId.R) if not _is_ocaml_lsp_available(): # opam alone isn't enough -- needs the ocaml-lsp-server package - result.append(Language.OCAML) + result.append(LanguageServerId.OCAML) if not _is_perl_language_server_available(): # perl ships with the OS; the LS module is the real signal - result.append(Language.PERL) + result.append(LanguageServerId.PERL) # === 4. Enabled everywhere: every language NOT listed in this function (python, go, java, ...) === # === 5. Disabled only on CI (works locally; too unstable/costly on the CI runners) === if is_ci: - result.append(Language.KOTLIN) # IntelliJ-based Kotlin LSP crashes on JVM restart under CI memory limits + result.append(LanguageServerId.KOTLIN) # IntelliJ-based Kotlin LSP crashes on JVM restart under CI memory limits return result -_disabled_languages = _determine_disabled_languages() +_disabled_language_servers = _determine_disabled_language_servers() -def language_tests_enabled(language: Language) -> bool: +def language_server_tests_enabled(ls_id: LanguageServerId) -> bool: """ - Check if tests for the given language are enabled in the current environment. + Check if tests for the given language server are enabled in the current environment. - :param language: the language to check + :param ls_id: the language server to check :return: True if tests for the language are enabled, False otherwise """ - return language not in _disabled_languages + return ls_id not in _disabled_language_servers -def language_supports_implementation(language: Language) -> bool: +def ls_supports_implementation(language: LanguageServerId) -> bool: return language.supports_implementation_request() -def languages_supporting_implementation(*languages: Language) -> list[Language]: - return [language for language in languages if language_supports_implementation(language)] +def language_servers_supporting_implementation(*languages: LanguageServerId) -> list[LanguageServerId]: + return [language for language in languages if ls_supports_implementation(language)] _VERIFIED_IMPLEMENTATION_LANGUAGES = { - Language.ANGULAR, - Language.CSHARP, - Language.GO, - Language.JAVA, - Language.RUST, - Language.TYPESCRIPT, + LanguageServerId.ANGULAR, + LanguageServerId.CSHARP, + LanguageServerId.GO, + LanguageServerId.JAVA, + LanguageServerId.RUST, + LanguageServerId.TYPESCRIPT, } -def language_has_verified_implementation_support(language: Language) -> bool: +def ls_has_verified_implementation_support(language: LanguageServerId) -> bool: """ True only for languages where the server advertises implementation support and the repo fixtures contain a verified working go-to-implementation scenario. """ - return language in _VERIFIED_IMPLEMENTATION_LANGUAGES and language_supports_implementation(language) + return language in _VERIFIED_IMPLEMENTATION_LANGUAGES and ls_supports_implementation(language) def find_identifier_position(file_path: Path, identifier: str) -> tuple[int, int] | None: diff --git a/test/serena/config/test_global_ignored_paths.py b/test/serena/config/test_global_ignored_paths.py index 862ac2f2..4bee1e4b 100644 --- a/test/serena/config/test_global_ignored_paths.py +++ b/test/serena/config/test_global_ignored_paths.py @@ -5,7 +5,7 @@ from pathlib import Path from serena.config.serena_config import ProjectConfig, RegisteredProject, SerenaConfig from serena.project import Project -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId def _create_test_project( @@ -16,7 +16,7 @@ def _create_test_project( """Helper to create a Project with the given ignored paths configuration.""" config = ProjectConfig( project_name="test_project", - languages=[Language.PYTHON], + languages=[LanguageServerId.PYTHON], ignored_paths=project_ignored_paths or [], ignore_all_files_in_gitignore=False, ) @@ -145,7 +145,7 @@ class TestRegisteredProjectGlobalIgnoredPaths: """RegisteredProject.get_project_instance() passes global_ignored_paths to Project.""" config = ProjectConfig( project_name="test_project", - languages=[Language.PYTHON], + languages=[LanguageServerId.PYTHON], ignored_paths=[], ignore_all_files_in_gitignore=False, ) @@ -161,7 +161,7 @@ class TestRegisteredProjectGlobalIgnoredPaths: """RegisteredProject without global_ignored_paths defaults to empty.""" config = ProjectConfig( project_name="test_project", - languages=[Language.PYTHON], + languages=[LanguageServerId.PYTHON], ignored_paths=[], ignore_all_files_in_gitignore=False, ) @@ -193,7 +193,7 @@ class TestRegisteredProjectGlobalIgnoredPaths: """RegisteredProject.from_project_instance() threads global_ignored_paths to Project.""" config = ProjectConfig( project_name="test_project", - languages=[Language.PYTHON], + languages=[LanguageServerId.PYTHON], ignored_paths=[], ignore_all_files_in_gitignore=False, ) @@ -233,7 +233,7 @@ class TestGlobalIgnoredPathsWithGitignore: """Global patterns, project patterns, and .gitignore patterns are all applied together.""" config = ProjectConfig( project_name="test_project", - languages=[Language.PYTHON], + languages=[LanguageServerId.PYTHON], ignored_paths=["build"], ignore_all_files_in_gitignore=True, ) diff --git a/test/serena/config/test_serena_config.py b/test/serena/config/test_serena_config.py index e1d7cffa..d6372205 100644 --- a/test/serena/config/test_serena_config.py +++ b/test/serena/config/test_serena_config.py @@ -18,7 +18,7 @@ from serena.config.serena_config import ( ) from serena.constants import PROJECT_TEMPLATE_FILE, SERENA_MANAGED_DIR_NAME from serena.project import MemoryManager, Project -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from test.conftest import create_default_serena_config @@ -62,7 +62,7 @@ class TestProjectConfigAutogenerate: # Verify the configuration assert config.project_name == self.project_path.name - assert config.languages == [Language.PYTHON] + assert config.languages == [LanguageServerId.PYTHON] def test_autogenerate_with_python_files_and_custom_ls_priorities(self): """Test successful autogeneration with Python source files, using custom language server priorities.""" @@ -71,14 +71,14 @@ class TestProjectConfigAutogenerate: python_file.write_text("def hello():\n print('Hello, world!')\n") serena_config = deepcopy(self.serena_config) - serena_config.ls_priorities = {Language.PYTHON_TY.value: 3} + serena_config.ls_priorities = {LanguageServerId.PYTHON_TY.value: 3} # Run autogenerate config = ProjectConfig.autogenerate(self.project_path, serena_config, save_to_disk=False) # Verify the configuration assert config.project_name == self.project_path.name - assert config.languages == [Language.PYTHON_TY] + assert config.languages == [LanguageServerId.PYTHON_TY] def test_autogenerate_with_js_files(self): """Test successful autogeneration with JavaScript source files.""" @@ -88,7 +88,7 @@ class TestProjectConfigAutogenerate: # Run autogenerate - should pick Python as dominant config = ProjectConfig.autogenerate(self.project_path, self.serena_config, save_to_disk=False) - assert config.languages == [Language.TYPESCRIPT] + assert config.languages == [LanguageServerId.TYPESCRIPT] def test_autogenerate_with_multiple_languages(self): """Test autogeneration picks dominant language when multiple are present.""" @@ -100,7 +100,7 @@ class TestProjectConfigAutogenerate: # Run autogenerate - should pick Python as dominant config = ProjectConfig.autogenerate(self.project_path, self.serena_config, save_to_disk=False) - assert config.languages == [Language.PYTHON] + assert config.languages == [LanguageServerId.PYTHON] def test_autogenerate_saves_to_disk(self): """Test that autogenerate can save the configuration to disk.""" @@ -116,7 +116,7 @@ class TestProjectConfigAutogenerate: assert config_path.exists() # Verify the content - assert config.languages == [Language.GO] + assert config.languages == [LanguageServerId.GO] def test_autogenerate_nonexistent_path(self): """Test that autogenerate raises FileNotFoundError for non-existent path.""" @@ -153,7 +153,7 @@ class TestProjectConfigAutogenerate: config = ProjectConfig.autogenerate(self.project_path, self.serena_config, project_name=custom_name, save_to_disk=False) assert config.project_name == custom_name - assert config.languages == [Language.TYPESCRIPT] + assert config.languages == [LanguageServerId.TYPESCRIPT] class TestProjectConfig: @@ -168,14 +168,14 @@ class TestProjectConfigLanguageBackend: def test_language_backend_defaults_to_none(self): config = ProjectConfig( project_name="test", - languages=[Language.PYTHON], + languages=[LanguageServerId.PYTHON], ) assert config.language_backend is None def test_language_backend_can_be_set(self): config = ProjectConfig( project_name="test", - languages=[Language.PYTHON], + languages=[LanguageServerId.PYTHON], language_backend=LanguageBackend.JETBRAINS, ) assert config.language_backend == LanguageBackend.JETBRAINS @@ -183,7 +183,7 @@ class TestProjectConfigLanguageBackend: def test_language_backend_roundtrips_through_yaml(self): config = ProjectConfig( project_name="test", - languages=[Language.PYTHON], + languages=[LanguageServerId.PYTHON], language_backend=LanguageBackend.JETBRAINS, ) d = config._to_yaml_dict() @@ -192,7 +192,7 @@ class TestProjectConfigLanguageBackend: def test_language_backend_none_roundtrips_through_yaml(self): config = ProjectConfig( project_name="test", - languages=[Language.PYTHON], + languages=[LanguageServerId.PYTHON], ) d = config._to_yaml_dict() assert d["language_backend"] is None @@ -232,7 +232,7 @@ def _make_config_with_project( project_root=str(Path(__file__).parent.parent / "resources" / "repos" / "python" / "test_repo"), project_config=ProjectConfig( project_name=project_name, - languages=[Language.PYTHON], + languages=[LanguageServerId.PYTHON], language_backend=language_backend, ), serena_config=config, @@ -286,7 +286,7 @@ class TestEffectiveLanguageBackend: project_root=str(Path(__file__).parent.parent / "resources" / "repos" / "java" / "test_repo"), project_config=ProjectConfig( project_name="jb_proj", - languages=[Language.JAVA], + languages=[LanguageServerId.JAVA], language_backend=LanguageBackend.JETBRAINS, ), serena_config=config, @@ -309,7 +309,7 @@ class TestEffectiveLanguageBackend: project_root=str(Path(__file__).parent.parent / "resources" / "repos" / "python" / "test_repo"), project_config=ProjectConfig( project_name="lsp_proj2", - languages=[Language.PYTHON], + languages=[LanguageServerId.PYTHON], language_backend=LanguageBackend.LSP, ), serena_config=config, @@ -332,7 +332,7 @@ class TestEffectiveLanguageBackend: project_root=str(Path(__file__).parent.parent / "resources" / "repos" / "python" / "test_repo"), project_config=ProjectConfig( project_name="proj2", - languages=[Language.PYTHON], + languages=[LanguageServerId.PYTHON], language_backend=None, ), serena_config=config, @@ -432,7 +432,7 @@ class TestProjectSerenaDataFolder: def _make_project(self, serena_config: "SerenaConfig | None" = None) -> Project: project_config = ProjectConfig( project_name="myproject", - languages=[Language.PYTHON], + languages=[LanguageServerId.PYTHON], ) project = Project( project_root=str(self.project_path), @@ -679,11 +679,11 @@ class TestProjectConfigActivationCommand: return data def test_activation_command_defaults_to_none(self): - config = ProjectConfig(project_name="test", languages=[Language.PYTHON]) + config = ProjectConfig(project_name="test", languages=[LanguageServerId.PYTHON]) assert config.activation_command is None def test_activation_command_timeout_default(self): - config = ProjectConfig(project_name="test", languages=[Language.PYTHON]) + config = ProjectConfig(project_name="test", languages=[LanguageServerId.PYTHON]) assert config.activation_command_timeout == 180.0 def test_activation_command_parsed_from_dict(self): diff --git a/test/serena/test_activation_command.py b/test/serena/test_activation_command.py index 39bca274..58f33e21 100644 --- a/test/serena/test_activation_command.py +++ b/test/serena/test_activation_command.py @@ -8,7 +8,7 @@ import pytest from serena.config.serena_config import ProjectConfig, SerenaConfig from serena.project import Project -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId def _make_project( @@ -25,7 +25,7 @@ def _make_project( ) project_config = ProjectConfig( project_name="test-activation", - languages=[Language.PYTHON], + languages=[LanguageServerId.PYTHON], activation_command=activation_command, activation_command_timeout=activation_command_timeout, ) diff --git a/test/serena/test_dashboard.py b/test/serena/test_dashboard.py index a4355e87..fb553a0a 100644 --- a/test/serena/test_dashboard.py +++ b/test/serena/test_dashboard.py @@ -2,7 +2,7 @@ from collections.abc import Callable from types import SimpleNamespace from serena.dashboard import SerenaDashboardAPI -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId class _DummyMemoryLogHandler: @@ -28,7 +28,7 @@ class _DummyAgent: return self._project -def _make_dashboard(project_languages: list[Language] | None) -> SerenaDashboardAPI: +def _make_dashboard(project_languages: list[LanguageServerId] | None) -> SerenaDashboardAPI: project = None if project_languages is not None: project = SimpleNamespace(project_config=SimpleNamespace(languages=project_languages)) @@ -39,15 +39,15 @@ def _make_dashboard(project_languages: list[Language] | None) -> SerenaDashboard def test_available_languages_include_experimental_when_no_active_project(): dashboard = _make_dashboard(project_languages=None) response = dashboard._get_available_languages() - expected = sorted(lang.value for lang in Language.iter_all(include_experimental=True)) + expected = sorted(lang.value for lang in LanguageServerId.iter_all(include_experimental=True)) assert response.languages == expected def test_available_languages_exclude_project_languages(): - dashboard = _make_dashboard(project_languages=[Language.PYTHON, Language.MARKDOWN]) + dashboard = _make_dashboard(project_languages=[LanguageServerId.PYTHON, LanguageServerId.MARKDOWN]) response = dashboard._get_available_languages() available = set(response.languages) - assert Language.PYTHON.value not in available - assert Language.MARKDOWN.value not in available + assert LanguageServerId.PYTHON.value not in available + assert LanguageServerId.MARKDOWN.value not in available # ensure experimental languages remain available for selection - assert Language.ANSIBLE.value in available + assert LanguageServerId.ANSIBLE.value in available diff --git a/test/serena/test_ls_file_sync.py b/test/serena/test_ls_file_sync.py index 874dbcc7..4902ffa7 100644 --- a/test/serena/test_ls_file_sync.py +++ b/test/serena/test_ls_file_sync.py @@ -14,7 +14,7 @@ import pytest from serena.agent import SerenaAgent from serena.project import Project from serena.tools import FindReferencingSymbolsTool -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from test.conftest import agent_for_project_context, get_repo_path pytestmark = pytest.mark.python @@ -73,10 +73,10 @@ class FileSystemSyncTestCase: def run(self, tmp_path): # Work on an isolated copy so we can freely create/edit/delete files under the project root. repo_root = tmp_path / "repo" - shutil.copytree(get_repo_path(Language.PYTHON), repo_root) + shutil.copytree(get_repo_path(LanguageServerId.PYTHON), repo_root) caller_abs = repo_root / self._CALLER_REL_PATH - with agent_for_project_context(Language.PYTHON, str(repo_root)) as agent: + with agent_for_project_context(LanguageServerId.PYTHON, str(repo_root)) as agent: project = agent.get_active_project_or_raise() # Warm the reference index, then establish the freshness baseline (first poll never notifies). diff --git a/test/serena/test_serena_agent.py b/test/serena/test_serena_agent.py index e373fb8a..b6a65dd3 100644 --- a/test/serena/test_serena_agent.py +++ b/test/serena/test_serena_agent.py @@ -32,24 +32,24 @@ from serena.tools import ( SafeDeleteSymbol, Tool, ) -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from solidlsp.ls_types import SymbolKind from test.conftest import ( find_identifier_pos, get_pytest_markers, get_repo_path, - language_tests_enabled, + language_server_tests_enabled, ) from test.serena.config.test_context_mode import GROK_EXCLUDED_TOOLS @dataclass class BaseCase: - language: Language + ls_id: LanguageServerId id: str def to_pytest_param(self, *marks: MarkDecorator | Mark) -> ParameterSet: - return pytest.param(self.language, self, marks=[*get_pytest_markers(self.language), *marks], id=self.id) + return pytest.param(self.ls_id, self, marks=[*get_pytest_markers(self.ls_id), *marks], id=self.id) @dataclass @@ -139,7 +139,6 @@ class SafeDeleteCase(BaseCase): @dataclass class DiagnosticCase(BaseCase): - language: Language relative_path: str name_path1: str name_path2: str | None @@ -189,8 +188,8 @@ class DiagnosticCase(BaseCase): DIAGNOSTIC_CASES = [ DiagnosticCase( - language=Language.PYTHON, - id=f"{Language.PYTHON.value}_missing_user", + ls_id=LanguageServerId.PYTHON, + id=f"{LanguageServerId.PYTHON.value}_missing_user", relative_path=os.path.join("test_repo", "diagnostics_sample.py"), name_path1="broken_factory", name_path2="broken_consumer", @@ -198,8 +197,8 @@ DIAGNOSTIC_CASES = [ message_fragment2="undefined_name", ).to_pytest_param(), DiagnosticCase( - language=Language.CLOJURE, - id=f"{Language.CLOJURE.value}_missing-greeting", + ls_id=LanguageServerId.CLOJURE, + id=f"{LanguageServerId.CLOJURE.value}_missing-greeting", relative_path=os.path.join("src", "test_app", "diagnostics_sample.clj"), name_path1="broken-factory", name_path2="broken-consumer", @@ -207,8 +206,8 @@ DIAGNOSTIC_CASES = [ message_fragment2="missing-consumer-value", ).to_pytest_param(), DiagnosticCase( - language=Language.GO, - id=f"{Language.GO.value}_missingGreeting", + ls_id=LanguageServerId.GO, + id=f"{LanguageServerId.GO.value}_missingGreeting", relative_path="diagnostics_sample.go", name_path1="brokenFactory", name_path2="brokenConsumer", @@ -216,8 +215,8 @@ DIAGNOSTIC_CASES = [ message_fragment2="missingConsumerValue", ).to_pytest_param(), DiagnosticCase( - language=Language.TYPESCRIPT, - id=f"{Language.TYPESCRIPT.value}_missingGreeting", + ls_id=LanguageServerId.TYPESCRIPT, + id=f"{LanguageServerId.TYPESCRIPT.value}_missingGreeting", relative_path="diagnostics_sample.ts", name_path1="brokenFactory", name_path2="brokenConsumer", @@ -229,7 +228,7 @@ DIAGNOSTIC_CASES = [ FIND_DEFINING_SYMBOL_CASES = [ FindDefiningSymbolCase( - language=Language.PYTHON, + ls_id=LanguageServerId.PYTHON, id="python_user_in_services", relative_path=os.path.join("test_repo", "services.py"), identifier="User", @@ -239,7 +238,7 @@ FIND_DEFINING_SYMBOL_CASES = [ expected_definition_file="models.py", ).to_pytest_param(), FindDefiningSymbolCase( - language=Language.PYTHON_TY, + ls_id=LanguageServerId.PYTHON_TY, id="python_ty_user_in_services", relative_path=os.path.join("test_repo", "services.py"), identifier="User", @@ -249,7 +248,7 @@ FIND_DEFINING_SYMBOL_CASES = [ expected_definition_file="models.py", ).to_pytest_param(), FindDefiningSymbolCase( - language=Language.GO, + ls_id=LanguageServerId.GO, id="go_helper_in_main", relative_path="main.go", identifier="Helper", @@ -259,7 +258,7 @@ FIND_DEFINING_SYMBOL_CASES = [ expected_definition_file="main.go", ).to_pytest_param(), FindDefiningSymbolCase( - language=Language.JAVA, + ls_id=LanguageServerId.JAVA, id="java_model_in_main", relative_path=os.path.join("src", "main", "java", "test_repo", "Main.java"), identifier="Model", @@ -269,7 +268,7 @@ FIND_DEFINING_SYMBOL_CASES = [ expected_definition_file="Model.java", ).to_pytest_param(), FindDefiningSymbolCase( - language=Language.KOTLIN, + ls_id=LanguageServerId.KOTLIN, id="kotlin_model_in_main", relative_path=os.path.join("src", "main", "kotlin", "test_repo", "Main.kt"), identifier="Model", @@ -279,7 +278,7 @@ FIND_DEFINING_SYMBOL_CASES = [ expected_definition_file="Model.kt", ).to_pytest_param(), FindDefiningSymbolCase( - language=Language.RUST, + ls_id=LanguageServerId.RUST, id="rust_format_greeting", relative_path=os.path.join("src", "main.rs"), identifier="format_greeting", @@ -289,7 +288,7 @@ FIND_DEFINING_SYMBOL_CASES = [ expected_definition_file="lib.rs", ).to_pytest_param(), FindDefiningSymbolCase( - language=Language.PHP, + ls_id=LanguageServerId.PHP, id="php_helper_function", relative_path="index.php", identifier="helperFunction", @@ -299,7 +298,7 @@ FIND_DEFINING_SYMBOL_CASES = [ expected_definition_file="helper.php", ).to_pytest_param(), FindDefiningSymbolCase( - language=Language.CLOJURE, + ls_id=LanguageServerId.CLOJURE, id="clojure_multiply_in_utils", relative_path=os.path.join("src", "test_app", "utils.clj"), identifier="multiply", @@ -309,7 +308,7 @@ FIND_DEFINING_SYMBOL_CASES = [ expected_definition_file=os.path.join("src", "test_app", "core.clj"), ).to_pytest_param(), FindDefiningSymbolCase( - language=Language.CSHARP, + ls_id=LanguageServerId.CSHARP, id="csharp_add_in_program", relative_path="Program.cs", identifier="Add", @@ -319,7 +318,7 @@ FIND_DEFINING_SYMBOL_CASES = [ expected_definition_file="Program.cs", ).to_pytest_param(), FindDefiningSymbolCase( - language=Language.POWERSHELL, + ls_id=LanguageServerId.POWERSHELL, id="powershell_convert_to_uppercase", relative_path="main.ps1", identifier="Convert-ToUpperCase", @@ -329,7 +328,7 @@ FIND_DEFINING_SYMBOL_CASES = [ expected_definition_file="utils.ps1", ).to_pytest_param(), FindDefiningSymbolCase( - language=Language.CPP, + ls_id=LanguageServerId.CPP, id="cpp_add_in_a", relative_path="a.cpp", identifier="add", @@ -339,7 +338,7 @@ FIND_DEFINING_SYMBOL_CASES = [ expected_definition_file="b.cpp", ).to_pytest_param(), FindDefiningSymbolCase( - language=Language.LEAN4, + ls_id=LanguageServerId.LEAN4, id="lean_add_in_main", relative_path="Main.lean", identifier="add", @@ -349,7 +348,7 @@ FIND_DEFINING_SYMBOL_CASES = [ expected_definition_file="Helper.lean", ).to_pytest_param(), FindDefiningSymbolCase( - language=Language.TYPESCRIPT, + ls_id=LanguageServerId.TYPESCRIPT, id="typescript_helper_function", relative_path="index.ts", identifier="helperFunction", @@ -359,7 +358,7 @@ FIND_DEFINING_SYMBOL_CASES = [ expected_definition_file="index.ts", ).to_pytest_param(), FindDefiningSymbolCase( - language=Language.FSHARP, + ls_id=LanguageServerId.FSHARP, id="fsharp_add_in_program", relative_path="Program.fs", identifier="add", @@ -374,7 +373,7 @@ FIND_DEFINING_SYMBOL_CASES = [ FIND_DEFINING_SYMBOL_REGEX_CASES = [ RegexDefiningSymbolCase( - language=Language.PYTHON, + ls_id=LanguageServerId.PYTHON, id="python_import_user", relative_path=os.path.join("test_repo", "services.py"), regex=r"from \.models import Item, (User)", @@ -383,7 +382,7 @@ FIND_DEFINING_SYMBOL_REGEX_CASES = [ expected_definition_file="models.py", ).to_pytest_param(), RegexDefiningSymbolCase( - language=Language.PYTHON, + ls_id=LanguageServerId.PYTHON, id="python_create_user_call", relative_path=os.path.join("test_repo", "services.py"), regex=r"=\s+(User)\(", @@ -392,7 +391,7 @@ FIND_DEFINING_SYMBOL_REGEX_CASES = [ expected_definition_file="models.py", ).to_pytest_param(), RegexDefiningSymbolCase( - language=Language.PYTHON_TY, + ls_id=LanguageServerId.PYTHON_TY, id="python_ty_create_user_call", relative_path=os.path.join("test_repo", "services.py"), regex=r"=\s+(User)\(", @@ -401,7 +400,7 @@ FIND_DEFINING_SYMBOL_REGEX_CASES = [ expected_definition_file="models.py", ).to_pytest_param(), RegexDefiningSymbolCase( - language=Language.GO, + ls_id=LanguageServerId.GO, id="go_greeter_var", relative_path="main.go", regex=r"var greeter (Greeter) =", @@ -413,7 +412,7 @@ FIND_DEFINING_SYMBOL_REGEX_CASES = [ FIND_IMPLEMENTATION_CASES = [ FindImplementationCase( - language=Language.CSHARP, + ls_id=LanguageServerId.CSHARP, id="csharp_greeter_format", symbol_name="IGreeter/FormatGreeting", definition_file=os.path.join("Services", "IGreeter.cs"), @@ -421,7 +420,7 @@ FIND_IMPLEMENTATION_CASES = [ expected_symbol_name="FormatGreeting", ).to_pytest_param(), FindImplementationCase( - language=Language.GO, + ls_id=LanguageServerId.GO, id="go_greeter_format", symbol_name="Greeter/FormatGreeting", definition_file="main.go", @@ -429,7 +428,7 @@ FIND_IMPLEMENTATION_CASES = [ expected_symbol_name="FormatGreeting", ).to_pytest_param(), FindImplementationCase( - language=Language.JAVA, + ls_id=LanguageServerId.JAVA, id="java_greeter_format", symbol_name="Greeter/formatGreeting", definition_file=os.path.join("src", "main", "java", "test_repo", "Greeter.java"), @@ -437,7 +436,7 @@ FIND_IMPLEMENTATION_CASES = [ expected_symbol_name="formatGreeting", ).to_pytest_param(), FindImplementationCase( - language=Language.RUST, + ls_id=LanguageServerId.RUST, id="rust_greeter_format", symbol_name="Greeter/format_greeting", definition_file=os.path.join("src", "lib.rs"), @@ -445,7 +444,7 @@ FIND_IMPLEMENTATION_CASES = [ expected_symbol_name="format_greeting", ).to_pytest_param(), FindImplementationCase( - language=Language.TYPESCRIPT, + ls_id=LanguageServerId.TYPESCRIPT, id="typescript_greeter_format", symbol_name="Greeter/formatGreeting", definition_file="formatters.ts", @@ -457,153 +456,157 @@ FIND_IMPLEMENTATION_CASES = [ FIND_SYMBOL_REFERENCES_CASES = [ FindSymbolCase( - language=Language.PYTHON, id="python_user_class", symbol_name="User", expected_kind="Class", expected_file="models.py" + ls_id=LanguageServerId.PYTHON, id="python_user_class", symbol_name="User", expected_kind="Class", expected_file="models.py" ).to_pytest_param(), FindSymbolCase( - language=Language.GO, id="go_helper_function", symbol_name="Helper", expected_kind="Function", expected_file="main.go" + ls_id=LanguageServerId.GO, id="go_helper_function", symbol_name="Helper", expected_kind="Function", expected_file="main.go" ).to_pytest_param(), FindSymbolCase( - language=Language.JAVA, id="java_model_class", symbol_name="Model", expected_kind="Class", expected_file="Model.java" + ls_id=LanguageServerId.JAVA, id="java_model_class", symbol_name="Model", expected_kind="Class", expected_file="Model.java" ).to_pytest_param(), FindSymbolCase( - language=Language.KOTLIN, id="kotlin_model_struct", symbol_name="Model", expected_kind="Struct", expected_file="Model.kt" + ls_id=LanguageServerId.KOTLIN, id="kotlin_model_struct", symbol_name="Model", expected_kind="Struct", expected_file="Model.kt" ).to_pytest_param(), FindSymbolCase( - language=Language.TYPESCRIPT, + ls_id=LanguageServerId.TYPESCRIPT, id="typescript_demo_class", symbol_name="DemoClass", expected_kind="Class", expected_file="index.ts", ).to_pytest_param(), FindSymbolCase( - language=Language.PHP, + ls_id=LanguageServerId.PHP, id="php_helper_function", symbol_name="helperFunction", expected_kind="Function", expected_file="helper.php", ).to_pytest_param(), FindSymbolCase( - language=Language.CLOJURE, + ls_id=LanguageServerId.CLOJURE, id="clojure_greet_function", symbol_name="greet", expected_kind="Function", expected_file=os.path.join("src", "test_app", "core.clj"), ).to_pytest_param(), FindSymbolCase( - language=Language.CSHARP, + ls_id=LanguageServerId.CSHARP, id="csharp_calculator_class", symbol_name="Calculator", expected_kind="Class", expected_file="Program.cs", ).to_pytest_param(), FindSymbolCase( - language=Language.POWERSHELL, + ls_id=LanguageServerId.POWERSHELL, id="powershell_greet_user", symbol_name="Greet-User", expected_kind="Function", expected_file="main.ps1", ).to_pytest_param(), FindSymbolCase( - language=Language.CPP, id="cpp_add_function", symbol_name="add", expected_kind="Function", expected_file="b.cpp" + ls_id=LanguageServerId.CPP, id="cpp_add_function", symbol_name="add", expected_kind="Function", expected_file="b.cpp" ).to_pytest_param(), FindSymbolCase( - language=Language.LEAN4, id="lean_add_method", symbol_name="add", expected_kind="Method", expected_file="Helper.lean" + ls_id=LanguageServerId.LEAN4, id="lean_add_method", symbol_name="add", expected_kind="Method", expected_file="Helper.lean" ).to_pytest_param(), FindSymbolCase( - language=Language.FSHARP, + ls_id=LanguageServerId.FSHARP, id="fsharp_calculator_module", symbol_name="Calculator", expected_kind="Module", expected_file="Calculator.fs", ).to_pytest_param(pytest.mark.xfail(reason="F# language server is unreliable")), FindSymbolCase( - language=Language.RUST, id="rust_add_function", symbol_name="add", expected_kind="Function", expected_file="lib.rs" + ls_id=LanguageServerId.RUST, id="rust_add_function", symbol_name="add", expected_kind="Function", expected_file="lib.rs" ).to_pytest_param(), FindSymbolCase( - language=Language.LATEX, id="latex_methods_section", symbol_name="Methods", expected_kind="Module", expected_file="main.tex" + ls_id=LanguageServerId.LATEX, id="latex_methods_section", symbol_name="Methods", expected_kind="Module", expected_file="main.tex" ).to_pytest_param(), ] FIND_REFERENCE_CASES = [ FindReferenceCase( - language=Language.PYTHON, + ls_id=LanguageServerId.PYTHON, id="python_user_refs", symbol_name="User", definition_file=os.path.join("test_repo", "models.py"), reference_file=os.path.join("test_repo", "services.py"), ).to_pytest_param(), FindReferenceCase( - language=Language.GO, id="go_helper_refs", symbol_name="Helper", definition_file="main.go", reference_file="main.go" + ls_id=LanguageServerId.GO, id="go_helper_refs", symbol_name="Helper", definition_file="main.go", reference_file="main.go" ).to_pytest_param(), FindReferenceCase( - language=Language.JAVA, + ls_id=LanguageServerId.JAVA, id="java_model_refs", symbol_name="Model", definition_file=os.path.join("src", "main", "java", "test_repo", "Model.java"), reference_file=os.path.join("src", "main", "java", "test_repo", "Main.java"), ).to_pytest_param(), FindReferenceCase( - language=Language.KOTLIN, + ls_id=LanguageServerId.KOTLIN, id="kotlin_model_refs", symbol_name="Model", definition_file=os.path.join("src", "main", "kotlin", "test_repo", "Model.kt"), reference_file=os.path.join("src", "main", "kotlin", "test_repo", "Main.kt"), ).to_pytest_param(), FindReferenceCase( - language=Language.RUST, + ls_id=LanguageServerId.RUST, id="rust_add_refs", symbol_name="add", definition_file=os.path.join("src", "lib.rs"), reference_file=os.path.join("src", "main.rs"), ).to_pytest_param(), FindReferenceCase( - language=Language.PHP, + ls_id=LanguageServerId.PHP, id="php_helper_refs", symbol_name="helperFunction", definition_file="helper.php", reference_file="index.php", ).to_pytest_param(), FindReferenceCase( - language=Language.CLOJURE, + ls_id=LanguageServerId.CLOJURE, id="clojure_multiply_refs", symbol_name="multiply", definition_file=os.path.join("src", "test_app", "core.clj"), reference_file=os.path.join("src", "test_app", "utils.clj"), ).to_pytest_param(), FindReferenceCase( - language=Language.CSHARP, + ls_id=LanguageServerId.CSHARP, id="csharp_calculator_refs", symbol_name="Calculator", definition_file="Program.cs", reference_file="Program.cs", ).to_pytest_param(), FindReferenceCase( - language=Language.POWERSHELL, + ls_id=LanguageServerId.POWERSHELL, id="powershell_greet_user_refs", symbol_name="Greet-User", definition_file="main.ps1", reference_file="main.ps1", ).to_pytest_param(), FindReferenceCase( - language=Language.CPP, id="cpp_add_refs", symbol_name="add", definition_file="b.cpp", reference_file="a.cpp" + ls_id=LanguageServerId.CPP, id="cpp_add_refs", symbol_name="add", definition_file="b.cpp", reference_file="a.cpp" ).to_pytest_param(), FindReferenceCase( - language=Language.LEAN4, id="lean_add_refs", symbol_name="add", definition_file="Helper.lean", reference_file="Main.lean" + ls_id=LanguageServerId.LEAN4, id="lean_add_refs", symbol_name="add", definition_file="Helper.lean", reference_file="Main.lean" ).to_pytest_param(), FindReferenceCase( - language=Language.TYPESCRIPT, + ls_id=LanguageServerId.TYPESCRIPT, id="typescript_helper_refs", symbol_name="helperFunction", definition_file="index.ts", reference_file="use_helper.ts", ).to_pytest_param(pytest.mark.xfail(False, reason="TypeScript language server is unreliable")), FindReferenceCase( - language=Language.FSHARP, id="fsharp_add_refs", symbol_name="add", definition_file="Calculator.fs", reference_file="Program.fs" + ls_id=LanguageServerId.FSHARP, + id="fsharp_add_refs", + symbol_name="add", + definition_file="Calculator.fs", + reference_file="Program.fs", ).to_pytest_param( pytest.mark.xfail(reason="F# language server is unreliable"), # See issue #1040 ), FindReferenceCase( - language=Language.LATEX, + ls_id=LanguageServerId.LATEX, id="latex_background_refs", symbol_name="Background", definition_file="sections/background.tex", @@ -613,7 +616,7 @@ FIND_REFERENCE_CASES = [ FIND_DEFINING_SYMBOL_REGEX_ERROR_CASES = [ RegexDefiningSymbolErrorCase( - language=Language.PYTHON, + ls_id=LanguageServerId.PYTHON, id="python_regex_multiple_matches", relative_path=os.path.join("test_repo", "services.py"), regex=r"(User)", @@ -621,7 +624,7 @@ FIND_DEFINING_SYMBOL_REGEX_ERROR_CASES = [ error_fragment="Match must be unique", ).to_pytest_param(), RegexDefiningSymbolErrorCase( - language=Language.PYTHON, + ls_id=LanguageServerId.PYTHON, id="python_regex_missing_group", relative_path=os.path.join("test_repo", "services.py"), regex=r"self.users.get\(id\)", @@ -632,7 +635,7 @@ FIND_DEFINING_SYMBOL_REGEX_ERROR_CASES = [ FIND_SYMBOL_NAME_PATH_CASES = [ FindSymbolNamePathCase( - language=Language.PYTHON, + ls_id=LanguageServerId.PYTHON, id="nested_class_exact", name_path="OuterClass/NestedClass", substring_matching=False, @@ -641,7 +644,7 @@ FIND_SYMBOL_NAME_PATH_CASES = [ expected_file=os.path.join("test_repo", "nested.py"), ).to_pytest_param(), FindSymbolNamePathCase( - language=Language.PYTHON, + ls_id=LanguageServerId.PYTHON, id="nested_method_exact", name_path="OuterClass/NestedClass/find_me", substring_matching=False, @@ -650,7 +653,7 @@ FIND_SYMBOL_NAME_PATH_CASES = [ expected_file=os.path.join("test_repo", "nested.py"), ).to_pytest_param(), FindSymbolNamePathCase( - language=Language.PYTHON, + ls_id=LanguageServerId.PYTHON, id="nested_class_substring", name_path="OuterClass/NestedCl", substring_matching=True, @@ -659,7 +662,7 @@ FIND_SYMBOL_NAME_PATH_CASES = [ expected_file=os.path.join("test_repo", "nested.py"), ).to_pytest_param(), FindSymbolNamePathCase( - language=Language.PYTHON, + ls_id=LanguageServerId.PYTHON, id="nested_method_substring", name_path="OuterClass/NestedClass/find_m", substring_matching=True, @@ -668,7 +671,7 @@ FIND_SYMBOL_NAME_PATH_CASES = [ expected_file=os.path.join("test_repo", "nested.py"), ).to_pytest_param(), FindSymbolNamePathCase( - language=Language.PYTHON, + ls_id=LanguageServerId.PYTHON, id="outer_class_absolute", name_path="/OuterClass", substring_matching=False, @@ -677,7 +680,7 @@ FIND_SYMBOL_NAME_PATH_CASES = [ expected_file=os.path.join("test_repo", "nested.py"), ).to_pytest_param(), FindSymbolNamePathCase( - language=Language.PYTHON, + ls_id=LanguageServerId.PYTHON, id="nested_method_absolute_substring", name_path="/OuterClass/NestedClass/find_m", substring_matching=True, @@ -688,21 +691,21 @@ FIND_SYMBOL_NAME_PATH_CASES = [ ] FIND_SYMBOL_NAME_PATH_NO_MATCH_CASES = [ - FindSymbolNoMatchCase(language=Language.PYTHON, id="nested_class_not_top_level", name_path="/NestedClass").to_pytest_param(), + FindSymbolNoMatchCase(ls_id=LanguageServerId.PYTHON, id="nested_class_not_top_level", name_path="/NestedClass").to_pytest_param(), FindSymbolNoMatchCase( - language=Language.PYTHON, id="nested_class_missing_parent", name_path="/NoSuchParent/NestedClass" + ls_id=LanguageServerId.PYTHON, id="nested_class_missing_parent", name_path="/NoSuchParent/NestedClass" ).to_pytest_param(), ] FIND_SYMBOL_OVERLOADED_FUNCTION_CASES = [ FindSymbolOverloadedCase( - language=Language.JAVA, id="java_overloaded_get_name", name_path="Model/getName", num_expected=2 + ls_id=LanguageServerId.JAVA, id="java_overloaded_get_name", name_path="Model/getName", num_expected=2 ).to_pytest_param(), ] NON_UNIQUE_SYMBOL_REFERENCE_ERROR_CASES = [ NonUniqueSymbolReferenceCase( - language=Language.JAVA, + ls_id=LanguageServerId.JAVA, id="java_overloaded_get_name", name_path="Model/getName", relative_path=os.path.join("src", "main", "java", "test_repo", "Model.java"), @@ -711,25 +714,25 @@ NON_UNIQUE_SYMBOL_REFERENCE_ERROR_CASES = [ SAFE_DELETE_BLOCKED_CASES = [ SafeDeleteCase( - language=Language.PYTHON, + ls_id=LanguageServerId.PYTHON, id="python_user", name_path="User", relative_path=os.path.join("test_repo", "models.py"), ).to_pytest_param(), SafeDeleteCase( - language=Language.JAVA, + ls_id=LanguageServerId.JAVA, id="java_model", name_path="Model", relative_path=os.path.join("src", "main", "java", "test_repo", "Model.java"), ).to_pytest_param(), SafeDeleteCase( - language=Language.KOTLIN, + ls_id=LanguageServerId.KOTLIN, id="kotlin_model", name_path="Model", relative_path=os.path.join("src", "main", "kotlin", "test_repo", "Model.kt"), ).to_pytest_param(), SafeDeleteCase( - language=Language.TYPESCRIPT, + ls_id=LanguageServerId.TYPESCRIPT, id="typescript_helper_function", name_path="helperFunction", relative_path="index.ts", @@ -738,25 +741,25 @@ SAFE_DELETE_BLOCKED_CASES = [ SAFE_DELETE_SUCCEEDS_CASES = [ SafeDeleteCase( - language=Language.PYTHON, + ls_id=LanguageServerId.PYTHON, id="python_timer", name_path="Timer", relative_path=os.path.join("test_repo", "utils.py"), ).to_pytest_param(), SafeDeleteCase( - language=Language.JAVA, + ls_id=LanguageServerId.JAVA, id="java_model_user", name_path="ModelUser", relative_path=os.path.join("src", "main", "java", "test_repo", "ModelUser.java"), ).to_pytest_param(), SafeDeleteCase( - language=Language.KOTLIN, + ls_id=LanguageServerId.KOTLIN, id="kotlin_model_user", name_path="ModelUser", relative_path=os.path.join("src", "main", "kotlin", "test_repo", "ModelUser.kt"), ).to_pytest_param(), SafeDeleteCase( - language=Language.TYPESCRIPT, + ls_id=LanguageServerId.TYPESCRIPT, id="typescript_unused_standalone_function", name_path="unusedStandaloneFunction", relative_path="index.ts", @@ -771,23 +774,23 @@ def serena_config(): # Create test projects for all supported languages test_projects = [] for language in [ - Language.PYTHON, - Language.PYTHON_TY, - Language.GO, - Language.JAVA, - Language.KOTLIN, - Language.RUST, - Language.TYPESCRIPT, - Language.PHP, - Language.CSHARP, - Language.CLOJURE, - Language.FSHARP, - Language.POWERSHELL, - Language.CPP, - Language.HAXE, - Language.LEAN4, - Language.MSL, - Language.LATEX, + LanguageServerId.PYTHON, + LanguageServerId.PYTHON_TY, + LanguageServerId.GO, + LanguageServerId.JAVA, + LanguageServerId.KOTLIN, + LanguageServerId.RUST, + LanguageServerId.TYPESCRIPT, + LanguageServerId.PHP, + LanguageServerId.CSHARP, + LanguageServerId.CLOJURE, + LanguageServerId.FSHARP, + LanguageServerId.POWERSHELL, + LanguageServerId.CPP, + LanguageServerId.HAXE, + LanguageServerId.LEAN4, + LanguageServerId.MSL, + LanguageServerId.LATEX, ]: repo_path = get_repo_path(language) if repo_path.exists(): @@ -845,8 +848,8 @@ def project_file_modification_context(serena_agent: SerenaAgent, relative_path: @pytest.fixture def serena_agent(request: pytest.FixtureRequest, serena_config) -> Iterator[SerenaAgent]: - language = Language(request.param) - if not language_tests_enabled(language): + language = LanguageServerId(request.param) + if not language_server_tests_enabled(language): pytest.skip(f"Tests for language {language} are not enabled.") project_name = f"test_repo_{language}" @@ -865,7 +868,7 @@ def serena_agent(request: pytest.FixtureRequest, serena_config) -> Iterator[Sere class TestSerenaAgent: @pytest.mark.parametrize( "project", - [None, str(get_repo_path(Language.PYTHON)), "non_existent_path"], + [None, str(get_repo_path(LanguageServerId.PYTHON)), "non_existent_path"], ids=["no_project", "python_project_path", "invalid_project_path"], ) def test_agent_instantiation(self, project: str | None): @@ -880,7 +883,7 @@ class TestSerenaAgent: SerenaAgent(project=project, serena_config=serena_config) @pytest.mark.python - @pytest.mark.skipif(not language_tests_enabled(Language.PYTHON), reason="python tests are disabled in this environment") + @pytest.mark.skipif(not language_server_tests_enabled(LanguageServerId.PYTHON), reason="python tests are disabled in this environment") def test_grok_context_restricts_toolset_and_prompt(self, serena_config): agent = SerenaAgent( project="test_repo_python", @@ -911,7 +914,7 @@ class TestSerenaAgent: symbol: dict, expected_name: str | None = None, ) -> None: - if serena_agent.get_active_lsp_languages() == [Language.KOTLIN]: + if serena_agent.get_active_language_server_ids() == [LanguageServerId.KOTLIN]: # kotlin LS doesn't seem to provide hover info right now, at least for the struct we test this on return @@ -924,12 +927,12 @@ class TestSerenaAgent: if expected_name is not None: assert expected_name in symbol_info, ( - f"[{serena_agent.get_active_lsp_languages()[0]}] Expected symbol info to contain symbol name " + f"[{serena_agent.get_active_language_server_ids()[0]}] Expected symbol info to contain symbol name " f"{expected_name}. Info: {symbol_info}" ) # special additional test for Java, since Eclipse returns hover in a complex format and we want to make sure to get it right - if symbol["kind"] == SymbolKind.Class.name and serena_agent.get_active_lsp_languages() == [Language.JAVA]: + if symbol["kind"] == SymbolKind.Class.name and serena_agent.get_active_language_server_ids() == [LanguageServerId.JAVA]: assert "A simple model class" in symbol_info, f"Java class docstring not found in symbol info: {symbol}" @pytest.mark.parametrize("serena_agent,case", FIND_SYMBOL_REFERENCES_CASES, indirect=["serena_agent"]) @@ -1030,7 +1033,7 @@ class TestSerenaAgent: diagnostic_case.assert_matches(full_file_diagnostics) # testing diagnostics in range by removing second symbol - project_root = get_repo_path(diagnostic_case.language) + project_root = get_repo_path(diagnostic_case.ls_id) pos1 = find_identifier_pos(project_root / diagnostic_case.relative_path, diagnostic_case.symbol1_id_str) pos2 = find_identifier_pos(project_root / diagnostic_case.relative_path, cast(str, diagnostic_case.symbol2_id_str)) assert pos1 is not None @@ -1141,7 +1144,7 @@ class TestSerenaAgent: @pytest.mark.parametrize( "serena_agent", [ - pytest.param(Language.TYPESCRIPT, marks=get_pytest_markers(Language.TYPESCRIPT), id="typescript_unique_regex"), + pytest.param(LanguageServerId.TYPESCRIPT, marks=get_pytest_markers(LanguageServerId.TYPESCRIPT), id="typescript_unique_regex"), ], indirect=["serena_agent"], ) @@ -1163,7 +1166,7 @@ class TestSerenaAgent: @pytest.mark.parametrize( "serena_agent", [ - pytest.param(Language.TYPESCRIPT, marks=get_pytest_markers(Language.TYPESCRIPT), id="typescript_backslashes"), + pytest.param(LanguageServerId.TYPESCRIPT, marks=get_pytest_markers(LanguageServerId.TYPESCRIPT), id="typescript_backslashes"), ], indirect=["serena_agent"], ) @@ -1191,7 +1194,7 @@ class TestSerenaAgent: @pytest.mark.parametrize( "serena_agent", [ - pytest.param(Language.PYTHON, marks=get_pytest_markers(Language.PYTHON), id="python_replace_in_files"), + pytest.param(LanguageServerId.PYTHON, marks=get_pytest_markers(LanguageServerId.PYTHON), id="python_replace_in_files"), ], indirect=["serena_agent"], ) @@ -1221,7 +1224,7 @@ class TestSerenaAgent: @pytest.mark.parametrize( "serena_agent", [ - pytest.param(Language.PYTHON, marks=get_pytest_markers(Language.PYTHON), id="python_replace_in_files_guard"), + pytest.param(LanguageServerId.PYTHON, marks=get_pytest_markers(LanguageServerId.PYTHON), id="python_replace_in_files_guard"), ], indirect=["serena_agent"], ) @@ -1242,8 +1245,8 @@ class TestSerenaAgent: @pytest.mark.parametrize( "serena_agent", [ - pytest.param(Language.PYTHON, marks=get_pytest_markers(Language.PYTHON), id="python_services"), - pytest.param(Language.PYTHON_TY, marks=get_pytest_markers(Language.PYTHON_TY), id="python_ty_services"), + pytest.param(LanguageServerId.PYTHON, marks=get_pytest_markers(LanguageServerId.PYTHON), id="python_services"), + pytest.param(LanguageServerId.PYTHON_TY, marks=get_pytest_markers(LanguageServerId.PYTHON_TY), id="python_ty_services"), ], indirect=["serena_agent"], ) @@ -1273,8 +1276,8 @@ class TestSerenaAgent: @pytest.mark.parametrize( "serena_agent", [ - pytest.param(Language.PYTHON, marks=get_pytest_markers(Language.PYTHON), id="python_container_body"), - pytest.param(Language.PYTHON_TY, marks=get_pytest_markers(Language.PYTHON_TY), id="python_ty_container_body"), + pytest.param(LanguageServerId.PYTHON, marks=get_pytest_markers(LanguageServerId.PYTHON), id="python_container_body"), + pytest.param(LanguageServerId.PYTHON_TY, marks=get_pytest_markers(LanguageServerId.PYTHON_TY), id="python_ty_container_body"), ], indirect=["serena_agent"], ) @@ -1306,7 +1309,9 @@ class TestSerenaAgent: @pytest.mark.parametrize( "serena_agent", [ - pytest.param(Language.TYPESCRIPT, marks=get_pytest_markers(Language.TYPESCRIPT), id="typescript_ambiguous_regex"), + pytest.param( + LanguageServerId.TYPESCRIPT, marks=get_pytest_markers(LanguageServerId.TYPESCRIPT), id="typescript_ambiguous_regex" + ), ], indirect=["serena_agent"], ) @@ -1375,7 +1380,7 @@ class TestPromptProvision: else: assert match is None, f"Expected no project activation message in result:\n{result}" - @pytest.mark.parametrize("serena_agent", [Language.PYTHON], indirect=True) + @pytest.mark.parametrize("serena_agent", [LanguageServerId.PYTHON], indirect=True) def test_initial_instructions_provide_project_activation_message_once_per_session(self, serena_agent: SerenaAgent) -> None: """ Tests that the project activation message is provided on the first call to InitialInstructionsTool for a session, @@ -1394,7 +1399,7 @@ class TestPromptProvision: result3 = self._call_tool(serena_agent, InitialInstructionsTool, session_id=session1) self._assert_activation_message(result3, project_name, present=False) - @pytest.mark.parametrize("serena_agent", [Language.PYTHON], indirect=True) + @pytest.mark.parametrize("serena_agent", [LanguageServerId.PYTHON], indirect=True) def test_dynamically_activated_mode_is_provided_once_per_session(self, serena_agent: SerenaAgent) -> None: """ Tests that when a new project is activated within a session that has a different mode configuration (e.g. no-onboarding), @@ -1437,7 +1442,7 @@ class TestPromptProvision: # the initial instructions for the new session must also include the activation message for the project self._assert_activation_message(result4, project_name2, present=True) - @pytest.mark.parametrize("serena_agent", [Language.PYTHON], indirect=True) + @pytest.mark.parametrize("serena_agent", [LanguageServerId.PYTHON], indirect=True) def test_activate_project_tool_always_returns_activation_message(self, serena_agent: SerenaAgent) -> None: project_name = "test_repo_python" session = "session1" diff --git a/test/serena/test_symbol_editing.py b/test/serena/test_symbol_editing.py index 030321e2..bef06e77 100644 --- a/test/serena/test_symbol_editing.py +++ b/test/serena/test_symbol_editing.py @@ -22,9 +22,9 @@ from overrides import overrides from syrupy import SnapshotAssertion from serena.code_editor import CodeEditor, LanguageServerCodeEditor -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from src.serena.symbol import LanguageServerSymbolRetriever -from test.conftest import get_repo_path, language_tests_enabled, project_with_ls_context +from test.conftest import get_repo_path, language_server_tests_enabled, project_with_ls_context pytestmark = pytest.mark.snapshot @@ -177,14 +177,14 @@ class CodeDiff: class EditingTest(ABC): - def __init__(self, language: Language, rel_path: str): + def __init__(self, ls_id: LanguageServerId, rel_path: str): """ - :param language: the language + :param ls_id: the language server to use :param rel_path: the relative path of the edited file """ self.rel_path = rel_path - self.language = language - self.original_repo_path = get_repo_path(language) + self.ls_id = ls_id + self.original_repo_path = get_repo_path(ls_id) self.repo_path: Path | None = None @contextmanager @@ -199,8 +199,8 @@ class EditingTest(ABC): # wait for a long time here if os.name == "nt": time.sleep(0.1) - log.info(f"Creating language server for {self.language} {self.rel_path}") - with project_with_ls_context(self.language, str(self.repo_path)) as project: + log.info(f"Creating language server for {self.ls_id} {self.rel_path}") + with project_with_ls_context(self.ls_id, str(self.repo_path)) as project: yield LanguageServerSymbolRetriever(project) finally: # prevent deadlock on Windows due to lingering file locks @@ -244,8 +244,8 @@ TYPESCRIPT_TEST_FILE = "index.ts" class DeleteSymbolTest(EditingTest): - def __init__(self, language: Language, rel_path: str, deleted_symbol: str): - super().__init__(language, rel_path) + def __init__(self, ls_id: LanguageServerId, rel_path: str, deleted_symbol: str): + super().__init__(ls_id, rel_path) self.deleted_symbol = deleted_symbol self.rel_path = rel_path @@ -258,7 +258,7 @@ class DeleteSymbolTest(EditingTest): [ pytest.param( DeleteSymbolTest( - Language.PYTHON, + LanguageServerId.PYTHON, PYTHON_TEST_REL_FILE_PATH, "VariableContainer", ), @@ -266,7 +266,7 @@ class DeleteSymbolTest(EditingTest): ), pytest.param( DeleteSymbolTest( - Language.TYPESCRIPT, + LanguageServerId.TYPESCRIPT, TYPESCRIPT_TEST_FILE, "DemoClass", ), @@ -307,9 +307,9 @@ NEW_TYPESCRIPT_FUNCTION_AFTER = """function newFunctionAfterClass(): void { class InsertInRelToSymbolTest(EditingTest): def __init__( - self, language: Language, rel_path: str, symbol_name: str, new_content: str, mode: Literal["before", "after"] | None = None + self, ls_id: LanguageServerId, rel_path: str, symbol_name: str, new_content: str, mode: Literal["before", "after"] | None = None ): - super().__init__(language, rel_path) + super().__init__(ls_id, rel_path) self.symbol_name = symbol_name self.new_content = new_content self.mode: Literal["before", "after"] | None = mode @@ -331,7 +331,7 @@ class InsertInRelToSymbolTest(EditingTest): [ pytest.param( InsertInRelToSymbolTest( - Language.PYTHON, + LanguageServerId.PYTHON, PYTHON_TEST_REL_FILE_PATH, "use_module_variables", NEW_PYTHON_FUNCTION, @@ -340,7 +340,7 @@ class InsertInRelToSymbolTest(EditingTest): ), pytest.param( InsertInRelToSymbolTest( - Language.TYPESCRIPT, + LanguageServerId.TYPESCRIPT, TYPESCRIPT_TEST_FILE, "DemoClass", NEW_TYPESCRIPT_FUNCTION_AFTER, @@ -349,7 +349,7 @@ class InsertInRelToSymbolTest(EditingTest): ), pytest.param( InsertInRelToSymbolTest( - Language.TYPESCRIPT, + LanguageServerId.TYPESCRIPT, TYPESCRIPT_TEST_FILE, "helperFunction", NEW_TYPESCRIPT_FUNCTION, @@ -366,7 +366,7 @@ def test_insert_in_rel_to_symbol(test_case: InsertInRelToSymbolTest, mode: Liter @pytest.mark.python def test_insert_python_class_before(snapshot: SnapshotAssertion): InsertInRelToSymbolTest( - Language.PYTHON, + LanguageServerId.PYTHON, PYTHON_TEST_REL_FILE_PATH, "VariableDataclass", NEW_PYTHON_CLASS_WITH_TRAILING_NEWLINES, @@ -377,7 +377,7 @@ def test_insert_python_class_before(snapshot: SnapshotAssertion): @pytest.mark.python def test_insert_python_class_after(snapshot: SnapshotAssertion): InsertInRelToSymbolTest( - Language.PYTHON, + LanguageServerId.PYTHON, PYTHON_TEST_REL_FILE_PATH, "VariableDataclass", NEW_PYTHON_CLASS_WITH_LEADING_NEWLINES, @@ -399,8 +399,8 @@ TYPESCRIPT_REPLACED_BODY = """function printValue() { class ReplaceBodyTest(EditingTest): - def __init__(self, language: Language, rel_path: str, symbol_name: str, new_body: str): - super().__init__(language, rel_path) + def __init__(self, ls_id: LanguageServerId, rel_path: str, symbol_name: str, new_body: str): + super().__init__(ls_id, rel_path) self.symbol_name = symbol_name self.new_body = new_body @@ -413,7 +413,7 @@ class ReplaceBodyTest(EditingTest): [ pytest.param( ReplaceBodyTest( - Language.PYTHON, + LanguageServerId.PYTHON, PYTHON_TEST_REL_FILE_PATH, "VariableContainer/modify_instance_var", PYTHON_REPLACED_BODY, @@ -422,7 +422,7 @@ class ReplaceBodyTest(EditingTest): ), pytest.param( ReplaceBodyTest( - Language.TYPESCRIPT, + LanguageServerId.TYPESCRIPT, TYPESCRIPT_TEST_FILE, "DemoClass/printValue", TYPESCRIPT_REPLACED_BODY, @@ -442,8 +442,8 @@ NIX_ATTR_REPLACEMENT = """c = 3;""" class NixAttrReplacementTest(EditingTest): """Test for replacing individual attributes in Nix that should NOT result in double semicolons.""" - def __init__(self, language: Language, rel_path: str, symbol_name: str, new_body: str): - super().__init__(language, rel_path) + def __init__(self, ls_id: LanguageServerId, rel_path: str, symbol_name: str, new_body: str): + super().__init__(ls_id, rel_path) self.symbol_name = symbol_name self.new_body = new_body @@ -452,7 +452,7 @@ class NixAttrReplacementTest(EditingTest): @pytest.mark.nix -@pytest.mark.skipif(not language_tests_enabled(Language.NIX), reason="Nix tests are disabled (nixd not available)") +@pytest.mark.skipif(not language_server_tests_enabled(LanguageServerId.NIX), reason="Nix tests are disabled (nixd not available)") def test_nix_symbol_replacement_no_double_semicolon(snapshot: SnapshotAssertion): """ Test that replacing a Nix attribute does not result in double semicolons. @@ -467,7 +467,7 @@ def test_nix_symbol_replacement_no_double_semicolon(snapshot: SnapshotAssertion) logic should prevent double semicolons. """ test_case = NixAttrReplacementTest( - Language.NIX, + LanguageServerId.NIX, "default.nix", "testUser", # Simple attrset with multiple key-value pairs NIX_ATTR_REPLACEMENT, @@ -486,8 +486,8 @@ class GoDeclReplacementTest(EditingTest): in a duplicated leading keyword (e.g. ``type type NamedInt``). """ - def __init__(self, language: Language, rel_path: str, symbol_name: str, new_body: str): - super().__init__(language, rel_path) + def __init__(self, ls_id: LanguageServerId, rel_path: str, symbol_name: str, new_body: str): + super().__init__(ls_id, rel_path) self.symbol_name = symbol_name self.new_body = new_body @@ -523,7 +523,7 @@ def test_go_symbol_replacement_no_double_keyword(snapshot: SnapshotAssertion): range extension prevents the duplicated keyword. """ test_case = GoDeclReplacementTest( - Language.GO, + LanguageServerId.GO, "symbol_body.go", "NamedInt", GO_DECL_REPLACEMENT, @@ -532,8 +532,8 @@ def test_go_symbol_replacement_no_double_keyword(snapshot: SnapshotAssertion): class RenameSymbolTest(EditingTest): - def __init__(self, language: Language, rel_path: str, symbol_name: str, new_name: str): - super().__init__(language, rel_path) + def __init__(self, ls_id: LanguageServerId, rel_path: str, symbol_name: str, new_name: str): + super().__init__(ls_id, rel_path) self.symbol_name = symbol_name self.new_name = new_name @@ -550,7 +550,7 @@ class RenameSymbolTest(EditingTest): @pytest.mark.python def test_rename_symbol(snapshot: SnapshotAssertion): test_case = RenameSymbolTest( - Language.PYTHON, + LanguageServerId.PYTHON, PYTHON_TEST_REL_FILE_PATH, "typed_module_var", "renamed_typed_module_var", @@ -564,15 +564,15 @@ class InsertAndDeleteSymbolTest(EditingTest): in no change to the file content. """ - def __init__(self, language: Language, rel_path: str, rel_symbol: str, deleted_symbol: str, insertion: str): + def __init__(self, ls_id: LanguageServerId, rel_path: str, rel_symbol: str, deleted_symbol: str, insertion: str): """ - :param language: specifies the language server to use + :param ls_id: specifies the language server to use :param rel_path: relative path of the file :param rel_symbol: symbol after which the insertion is made :param deleted_symbol: the symbol to be deleted after the insertion :param insertion: text which inserts the symbol `deleted_symbol` """ - super().__init__(language, rel_path) + super().__init__(ls_id, rel_path) self.rel_symbol = rel_symbol self.deleted_symbol = deleted_symbol self.rel_path = rel_path @@ -592,7 +592,7 @@ def test_insert_and_delete_no_change(): """ insertion = " def inserted_function():\n pass" test_case = InsertAndDeleteSymbolTest( - Language.PYTHON, + LanguageServerId.PYTHON, PYTHON_TEST_REL_FILE_PATH, "VariableContainer/modify_instance_var", "VariableContainer/inserted_function", @@ -617,7 +617,7 @@ NEW_VUE_HANDLER = """const handleDoubleClick = () => { [ pytest.param( DeleteSymbolTest( - Language.VUE, + LanguageServerId.VUE, VUE_TEST_FILE, "handleMouseEnter", ), @@ -635,7 +635,7 @@ def test_delete_symbol_vue(test_case: DeleteSymbolTest, snapshot: SnapshotAssert [ pytest.param( InsertInRelToSymbolTest( - Language.VUE, + LanguageServerId.VUE, VUE_TEST_FILE, "handleClick", NEW_VUE_HANDLER, @@ -666,7 +666,7 @@ VUE_REPLACED_HANDLECLICK_BODY = """const handleClick = () => { [ pytest.param( ReplaceBodyTest( - Language.VUE, + LanguageServerId.VUE, VUE_TEST_FILE, "handleClick", VUE_REPLACED_HANDLECLICK_BODY, @@ -687,7 +687,7 @@ VUE_REPLACED_PRESSCOUNT_BODY = """const pressCount = ref(100)""" [ pytest.param( ReplaceBodyTest( - Language.VUE, + LanguageServerId.VUE, VUE_TEST_FILE, "pressCount", VUE_REPLACED_PRESSCOUNT_BODY, @@ -726,7 +726,7 @@ VUE_STORE_REPLACED_CLEAR_BODY = """function clear() { [ pytest.param( ReplaceBodyTest( - Language.VUE, + LanguageServerId.VUE, VUE_STORE_FILE, "clear", VUE_STORE_REPLACED_CLEAR_BODY, diff --git a/test/serena/util/test_inspection.py b/test/serena/util/test_inspection.py index 90378aac..f508d5c4 100644 --- a/test/serena/util/test_inspection.py +++ b/test/serena/util/test_inspection.py @@ -1,9 +1,7 @@ -"""Unit tests for :func:`serena.util.inspection.determine_programming_language_composition`.""" - from pathlib import Path -from serena.util.inspection import determine_programming_language_composition -from solidlsp.ls_config import Language +from serena.util.inspection import compute_language_server_support_composition +from solidlsp.ls_config import LanguageServerId def _touch(directory: Path, *names: str) -> None: @@ -11,11 +9,11 @@ def _touch(directory: Path, *names: str) -> None: (directory / name).write_text("content", encoding="utf-8") -class TestDetermineProgrammingLanguageComposition: +class TestComputeLanguageServerSupportComposition: def test_single_language_repo(self, tmp_path: Path) -> None: _touch(tmp_path, "a.py", "b.py", "c.py") - composition = determine_programming_language_composition(str(tmp_path)) - assert composition[Language.PYTHON] == 100.0 + composition = compute_language_server_support_composition(str(tmp_path)) + assert composition[LanguageServerId.PYTHON] == 100.0 def test_unrecognised_files_do_not_dilute_percentages(self, tmp_path: Path) -> None: # 2 source files vs many files that belong to no supported language @@ -23,23 +21,23 @@ class TestDetermineProgrammingLanguageComposition: _touch(tmp_path, *[f"note_{i}.txt" for i in range(20)]) _touch(tmp_path, "logo.png", "LICENSE", "data.csv") - composition = determine_programming_language_composition(str(tmp_path)) + composition = compute_language_server_support_composition(str(tmp_path)) # previously: 2 / 25 files = 8% — now the denominator is recognised source files only - assert composition[Language.PYTHON] == 100.0 + assert composition[LanguageServerId.PYTHON] == 100.0 def test_mixed_language_percentages_relative_to_recognised_files(self, tmp_path: Path) -> None: _touch(tmp_path, "a.py", "b.py", "c.py", "d.go") _touch(tmp_path, *[f"asset_{i}.dat" for i in range(50)]) - composition = determine_programming_language_composition(str(tmp_path)) + composition = compute_language_server_support_composition(str(tmp_path)) - assert composition[Language.PYTHON] == 75.0 - assert composition[Language.GO] == 25.0 + assert composition[LanguageServerId.PYTHON] == 75.0 + assert composition[LanguageServerId.GO] == 25.0 def test_repo_without_recognised_files(self, tmp_path: Path) -> None: _touch(tmp_path, "readme.txt", "logo.png") - assert determine_programming_language_composition(str(tmp_path)) == {} + assert compute_language_server_support_composition(str(tmp_path)) == {} def test_empty_repo(self, tmp_path: Path) -> None: - assert determine_programming_language_composition(str(tmp_path)) == {} + assert compute_language_server_support_composition(str(tmp_path)) == {} diff --git a/test/solidlsp/ada/test_ada_basic.py b/test/solidlsp/ada/test_ada_basic.py index 18919a49..32b31de8 100644 --- a/test/solidlsp/ada/test_ada_basic.py +++ b/test/solidlsp/ada/test_ada_basic.py @@ -3,7 +3,7 @@ from pathlib import Path import pytest from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from test.solidlsp.conftest import format_symbol_for_assert, has_malformed_name, request_all_symbols @@ -24,14 +24,14 @@ class TestAdaLanguageServer: obviously test-affecting. """ - @pytest.mark.parametrize("language_server", [Language.ADA], indirect=True) - @pytest.mark.parametrize("repo_path", [Language.ADA], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ADA], indirect=True) + @pytest.mark.parametrize("repo_path", [LanguageServerId.ADA], indirect=True) def test_ls_is_running(self, language_server: SolidLanguageServer, repo_path: Path) -> None: assert language_server.is_running() assert Path(language_server.language_server.repository_root_path).resolve() == repo_path.resolve() - @pytest.mark.parametrize("language_server", [Language.ADA], indirect=True) - @pytest.mark.parametrize("repo_path", [Language.ADA], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ADA], indirect=True) + @pytest.mark.parametrize("repo_path", [LanguageServerId.ADA], indirect=True) def test_find_definition_within_file(self, language_server: SolidLanguageServer, repo_path: Path) -> None: # main.adb (1-indexed source / 0-indexed LSP): # 5/4: Greeting : constant String := Helper.Greet ("Ada"); @@ -47,8 +47,8 @@ class TestAdaLanguageServer: # `Greeting` is declared on LSP line 4; ALS points at the identifier (column 3). assert loc["range"]["start"]["line"] == 4 - @pytest.mark.parametrize("language_server", [Language.ADA], indirect=True) - @pytest.mark.parametrize("repo_path", [Language.ADA], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ADA], indirect=True) + @pytest.mark.parametrize("repo_path", [LanguageServerId.ADA], indirect=True) def test_find_definition_across_files(self, language_server: SolidLanguageServer, repo_path: Path) -> None: # main.adb LSP line 4 / column 40 sits on the `G` of `Helper.Greet`: # ` Greeting : constant String := Helper.Greet ("Ada");` @@ -65,8 +65,8 @@ class TestAdaLanguageServer: assert loc["range"]["start"]["line"] == 4 assert loc["range"]["start"]["character"] == 12 - @pytest.mark.parametrize("language_server", [Language.ADA], indirect=True) - @pytest.mark.parametrize("repo_path", [Language.ADA], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ADA], indirect=True) + @pytest.mark.parametrize("repo_path", [LanguageServerId.ADA], indirect=True) def test_find_references_within_file(self, language_server: SolidLanguageServer, repo_path: Path) -> None: # Click on `Helper` in `with Helper;` (main.adb LSP line 1, column 5). # Serena's request_references uses includeDeclaration=False, so we need a symbol with @@ -80,8 +80,8 @@ class TestAdaLanguageServer: # The qualifier usage on LSP line 4 of main.adb must appear among the references. assert 4 in ref_lines_in_main, f"Expected reference on line 4 of main.adb, got {ref_lines_in_main}" - @pytest.mark.parametrize("language_server", [Language.ADA], indirect=True) - @pytest.mark.parametrize("repo_path", [Language.ADA], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ADA], indirect=True) + @pytest.mark.parametrize("repo_path", [LanguageServerId.ADA], indirect=True) def test_find_references_across_files(self, language_server: SolidLanguageServer, repo_path: Path) -> None: # Click on the `G` of `Greet` in the spec: # helper.ads LSP line 4: ` function Greet (Name : String) return String;` @@ -94,7 +94,7 @@ class TestAdaLanguageServer: # The call site in main.adb must appear in the references. assert "main.adb" in ref_files, f"Expected reference in main.adb, got {ref_files}" - @pytest.mark.parametrize("language_server", [Language.ADA], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ADA], indirect=True) def test_find_symbol(self, language_server: SolidLanguageServer) -> None: from solidlsp.ls_utils import SymbolUtils @@ -103,7 +103,7 @@ class TestAdaLanguageServer: assert SymbolUtils.symbol_tree_contains_name(symbols, "Greet"), "Greet subprogram not found in symbol tree" assert SymbolUtils.symbol_tree_contains_name(symbols, "Main"), "Main procedure not found in symbol tree" - @pytest.mark.parametrize("language_server", [Language.ADA], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ADA], indirect=True) def test_document_symbols_helper(self, language_server: SolidLanguageServer) -> None: doc_symbols = language_server.request_document_symbols(str(Path("src") / "helper.ads")) all_symbols, _ = doc_symbols.get_all_symbols_and_roots() @@ -111,7 +111,7 @@ class TestAdaLanguageServer: assert "Helper" in names, f"Helper package not found in helper.ads document symbols. Found: {names}" assert "Greet" in names, f"Greet not found in helper.ads document symbols. Found: {names}" - @pytest.mark.parametrize("language_server", [Language.ADA], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ADA], indirect=True) def test_document_symbols_hierarchical_structure(self, language_server: SolidLanguageServer) -> None: """ALS must return hierarchical DocumentSymbol[] with subprograms nested under their package.""" all_symbols, root_symbols = language_server.request_document_symbols(str(Path("src") / "helper.ads")).get_all_symbols_and_roots() @@ -129,7 +129,7 @@ class TestAdaLanguageServer: # Greet must NOT appear at root level — that would indicate the flat fallback format. assert "Greet" not in root_names, f"Greet should be a child of Helper, not at root level. Roots: {root_names}" - @pytest.mark.parametrize("language_server", [Language.ADA], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ADA], indirect=True) def test_bare_symbol_names(self, language_server: SolidLanguageServer) -> None: # ALS surfaces a few Ada-specific synthetic groupings as symbols: # - "With clauses" — namespace-kind group containing all `with` statements in a unit diff --git a/test/solidlsp/ada/test_ada_diagnostics.py b/test/solidlsp/ada/test_ada_diagnostics.py index cac0baa1..6d317af4 100644 --- a/test/solidlsp/ada/test_ada_diagnostics.py +++ b/test/solidlsp/ada/test_ada_diagnostics.py @@ -1,13 +1,13 @@ import pytest from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from test.solidlsp.util.diagnostics import assert_file_diagnostics @pytest.mark.ada class TestAdaDiagnostics: - @pytest.mark.parametrize("language_server", [Language.ADA], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ADA], indirect=True) def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None: assert_file_diagnostics( language_server, diff --git a/test/solidlsp/al/test_al_basic.py b/test/solidlsp/al/test_al_basic.py index a52e2f14..62e129e5 100644 --- a/test/solidlsp/al/test_al_basic.py +++ b/test/solidlsp/al/test_al_basic.py @@ -5,13 +5,13 @@ import pytest from serena.symbol import LanguageServerSymbol from solidlsp import SolidLanguageServer from solidlsp.language_servers.al_language_server import ALLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from solidlsp.ls_types import SymbolKind from solidlsp.ls_utils import SymbolUtils -from test.conftest import language_tests_enabled +from test.conftest import language_server_tests_enabled from test.solidlsp.conftest import format_symbol_for_assert, has_malformed_name, request_all_symbols -pytestmark = [pytest.mark.al, pytest.mark.skipif(not language_tests_enabled(Language.AL), reason="AL tests are disabled")] +pytestmark = [pytest.mark.al, pytest.mark.skipif(not language_server_tests_enabled(LanguageServerId.AL), reason="AL tests are disabled")] class TestExtractALDisplayName: @@ -62,7 +62,7 @@ class TestExtractALDisplayName: @pytest.mark.al class TestALLanguageServer: - @pytest.mark.parametrize("language_server", [Language.AL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.AL], indirect=True) def test_symbol_names_are_normalized(self, language_server: SolidLanguageServer) -> None: """Test that AL symbol names are normalized (metadata stripped).""" file_path = os.path.join("src", "Tables", "Customer.Table.al") @@ -79,7 +79,7 @@ class TestALLanguageServer: # Name should be just "TEST Customer", not "Table 50000 'TEST Customer'" assert customer_table["name"] == "TEST Customer", f"Expected normalized name 'TEST Customer', got '{customer_table['name']}'" - @pytest.mark.parametrize("language_server", [Language.AL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.AL], indirect=True) def test_find_symbol_exact_match(self, language_server: SolidLanguageServer) -> None: """Test that find_symbol can match AL symbols by normalized name without substring_matching.""" file_path = os.path.join("src", "Tables", "Customer.Table.al") @@ -96,7 +96,7 @@ class TestALLanguageServer: pytest.fail("Could not find 'TEST Customer' symbol by exact name match") - @pytest.mark.parametrize("language_server", [Language.AL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.AL], indirect=True) def test_find_codeunit_exact_match(self, language_server: SolidLanguageServer) -> None: """Test finding a codeunit by its normalized name.""" file_path = os.path.join("src", "Codeunits", "CustomerMgt.Codeunit.al") @@ -112,7 +112,7 @@ class TestALLanguageServer: pytest.fail("Could not find 'CustomerMgt' symbol by exact name match") - @pytest.mark.parametrize("language_server", [Language.AL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.AL], indirect=True) def test_find_symbol(self, language_server: SolidLanguageServer) -> None: """Test that AL Language Server can find symbols in the test repository with normalized names.""" symbols = language_server.request_full_symbol_tree() @@ -136,7 +136,7 @@ class TestALLanguageServer: # Check for interface symbol assert SymbolUtils.symbol_tree_contains_name(symbols, "IPaymentProcessor"), "IPaymentProcessor interface not found in symbol tree" - @pytest.mark.parametrize("language_server", [Language.AL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.AL], indirect=True) def test_find_table_fields(self, language_server: SolidLanguageServer) -> None: """Test that AL Language Server can find fields within a table.""" file_path = os.path.join("src", "Tables", "Customer.Table.al") @@ -169,7 +169,7 @@ class TestALLanguageServer: assert any("Name" in name for name in field_names), f"Name field not found. Fields: {field_names}" assert any("Balance" in name for name in field_names), f"Balance field not found. Fields: {field_names}" - @pytest.mark.parametrize("language_server", [Language.AL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.AL], indirect=True) def test_find_procedures(self, language_server: SolidLanguageServer) -> None: """Test that AL Language Server can find procedures in codeunits.""" file_path = os.path.join("src", "Codeunits", "CustomerMgt.Codeunit.al") @@ -191,7 +191,7 @@ class TestALLanguageServer: assert any("CreateCustomer" in name for name in procedure_names), "CreateCustomer procedure not found" assert any("TestNoSeries" in name for name in procedure_names), "TestNoSeries procedure not found" - @pytest.mark.parametrize("language_server", [Language.AL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.AL], indirect=True) def test_find_referencing_symbols(self, language_server: SolidLanguageServer) -> None: """Test that AL Language Server can find references to symbols.""" # Find references to the Customer table from the CustomerMgt codeunit @@ -220,7 +220,7 @@ class TestALLanguageServer: "Customer table should be referenced in CustomerCard.Page.al" ) - @pytest.mark.parametrize("language_server", [Language.AL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.AL], indirect=True) def test_cross_file_symbols(self, language_server: SolidLanguageServer) -> None: """Test that AL Language Server can handle cross-file symbol relationships.""" # Get all symbols to verify cross-file visibility @@ -290,7 +290,7 @@ class TestALHoverInjection: return hover, None return None, None - @pytest.mark.parametrize("language_server", [Language.AL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.AL], indirect=True) def test_hover_table_injects_full_name(self, language_server: SolidLanguageServer) -> None: """Test that hovering over a Table symbol shows the full object name with ID.""" file_path = os.path.join("src", "Tables", "Customer.Table.al") @@ -300,7 +300,7 @@ class TestALHoverInjection: assert value is not None, "Hover should have content" assert '**Table 50000 "TEST Customer"**' in value, f"Hover should contain full Table name with ID. Got: {value[:200]}" - @pytest.mark.parametrize("language_server", [Language.AL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.AL], indirect=True) def test_hover_page_injects_full_name(self, language_server: SolidLanguageServer) -> None: """Test that hovering over a Page symbol shows the full object name with ID.""" file_path = os.path.join("src", "Pages", "CustomerCard.Page.al") @@ -310,7 +310,7 @@ class TestALHoverInjection: assert value is not None, "Hover should have content" assert '**Page 50001 "TEST Customer Card"**' in value, f"Hover should contain full Page name with ID. Got: {value[:200]}" - @pytest.mark.parametrize("language_server", [Language.AL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.AL], indirect=True) def test_hover_codeunit_injects_full_name(self, language_server: SolidLanguageServer) -> None: """Test that hovering over a Codeunit symbol shows the full object name with ID.""" file_path = os.path.join("src", "Codeunits", "CustomerMgt.Codeunit.al") @@ -320,7 +320,7 @@ class TestALHoverInjection: assert value is not None, "Hover should have content" assert "**Codeunit 50000 CustomerMgt**" in value, f"Hover should contain full Codeunit name with ID. Got: {value[:200]}" - @pytest.mark.parametrize("language_server", [Language.AL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.AL], indirect=True) def test_hover_enum_injects_full_name(self, language_server: SolidLanguageServer) -> None: """Test that hovering over an Enum symbol shows the full object name with ID.""" file_path = os.path.join("src", "Enums", "CustomerType.Enum.al") @@ -330,7 +330,7 @@ class TestALHoverInjection: assert value is not None, "Hover should have content" assert "**Enum 50000 CustomerType**" in value, f"Hover should contain full Enum name with ID. Got: {value[:200]}" - @pytest.mark.parametrize("language_server", [Language.AL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.AL], indirect=True) def test_hover_interface_injects_full_name(self, language_server: SolidLanguageServer) -> None: """Test that hovering over an Interface symbol shows the full object name (no ID for interfaces).""" file_path = os.path.join("src", "Interfaces", "IPaymentProcessor.Interface.al") @@ -340,7 +340,7 @@ class TestALHoverInjection: assert value is not None, "Hover should have content" assert "**Interface IPaymentProcessor**" in value, f"Hover should contain full Interface name. Got: {value[:200]}" - @pytest.mark.parametrize("language_server", [Language.AL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.AL], indirect=True) def test_hover_procedure_no_injection(self, language_server: SolidLanguageServer) -> None: """Test that hovering over a procedure does NOT inject object name (procedures are not normalized).""" file_path = os.path.join("src", "Codeunits", "CustomerMgt.Codeunit.al") @@ -353,7 +353,7 @@ class TestALHoverInjection: # But should contain procedure info assert "CreateCustomer" in value, f"Hover should contain procedure name. Got: {value[:200]}" - @pytest.mark.parametrize("language_server", [Language.AL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.AL], indirect=True) def test_hover_field_no_injection(self, language_server: SolidLanguageServer) -> None: """Test that hovering over a field does NOT inject object name (fields are not normalized).""" file_path = os.path.join("src", "Tables", "Customer.Table.al") @@ -380,7 +380,7 @@ class TestALHoverInjection: pytest.fail("Could not find a field to test hover on") - @pytest.mark.parametrize("language_server", [Language.AL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.AL], indirect=True) def test_hover_multiple_objects_correct_injection(self, language_server: SolidLanguageServer) -> None: """Test that multiple AL objects each get their correct full name injected.""" test_cases = [ @@ -398,7 +398,7 @@ class TestALHoverInjection: f"Hover for {symbol_name} should contain '{expected_full_name}'. Got: {value[:200]}" ) - @pytest.mark.parametrize("language_server", [Language.AL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.AL], indirect=True) def test_hover_contains_separator_after_injection(self, language_server: SolidLanguageServer) -> None: """Test that injected hover has a separator between injected name and original content.""" file_path = os.path.join("src", "Tables", "Customer.Table.al") @@ -413,7 +413,7 @@ class TestALHoverInjection: separator_pos = value.find("---") assert separator_pos > bold_end, "Separator should come after the injected name" - @pytest.mark.parametrize("language_server", [Language.AL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.AL], indirect=True) def test_hover_preserves_original_content(self, language_server: SolidLanguageServer) -> None: """Test that the original hover content is preserved after the injected name.""" file_path = os.path.join("src", "Tables", "Customer.Table.al") @@ -430,7 +430,7 @@ class TestALHoverInjection: class TestALPathNormalization: """Tests for path normalization in hover injection cache.""" - @pytest.mark.parametrize("language_server", [Language.AL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.AL], indirect=True) def test_hover_with_forward_slash_path(self, language_server: SolidLanguageServer) -> None: """Test that hover injection works with forward slash paths.""" file_path = "src/Tables/Customer.Table.al" @@ -451,7 +451,7 @@ class TestALPathNormalization: pytest.fail("Could not find TEST Customer symbol") - @pytest.mark.parametrize("language_server", [Language.AL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.AL], indirect=True) def test_hover_with_backslash_path(self, language_server: SolidLanguageServer) -> None: """Test that hover injection works with backslash paths (Windows style).""" file_path = "src\\Tables\\Customer.Table.al" @@ -472,7 +472,7 @@ class TestALPathNormalization: pytest.fail("Could not find TEST Customer symbol") - @pytest.mark.parametrize("language_server", [Language.AL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.AL], indirect=True) def test_hover_with_mixed_path_formats_symbols_backslash_hover_forward(self, language_server: SolidLanguageServer) -> None: """Test hover works when symbols requested with backslash but hover with forward slash.""" file_path_backslash = "src\\Tables\\Customer.Table.al" @@ -499,7 +499,7 @@ class TestALPathNormalization: pytest.fail("Could not find TEST Customer symbol") - @pytest.mark.parametrize("language_server", [Language.AL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.AL], indirect=True) def test_hover_with_mixed_path_formats_symbols_forward_hover_backslash(self, language_server: SolidLanguageServer) -> None: """Test hover works when symbols requested with forward slash but hover with backslash.""" file_path_forward = "src/Tables/Customer.Table.al" @@ -526,7 +526,7 @@ class TestALPathNormalization: pytest.fail("Could not find TEST Customer symbol") - @pytest.mark.parametrize("language_server", [Language.AL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.AL], indirect=True) def test_hover_caching_multiple_files_different_path_formats(self, language_server: SolidLanguageServer) -> None: """Test that hover injection cache works correctly across multiple files with different path formats.""" test_cases = [ @@ -559,7 +559,7 @@ class TestALPathNormalization: ) break - @pytest.mark.parametrize("language_server", [Language.AL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.AL], indirect=True) def test_bare_symbol_names(self, language_server) -> None: all_symbols = request_all_symbols(language_server) malformed_symbols = [] diff --git a/test/solidlsp/angular/test_angular_basic.py b/test/solidlsp/angular/test_angular_basic.py index 9d2054b5..8b377d5c 100644 --- a/test/solidlsp/angular/test_angular_basic.py +++ b/test/solidlsp/angular/test_angular_basic.py @@ -17,19 +17,19 @@ import pytest from serena.util.text_utils import find_text_coordinates from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from test.solidlsp.conftest import read_repo_file, request_all_symbols @pytest.mark.angular class TestAngularLanguageServerBasics: - @pytest.mark.parametrize("language_server", [Language.ANGULAR], indirect=True) - @pytest.mark.parametrize("repo_path", [Language.ANGULAR], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ANGULAR], indirect=True) + @pytest.mark.parametrize("repo_path", [LanguageServerId.ANGULAR], indirect=True) def test_ls_is_running(self, language_server: SolidLanguageServer, repo_path: Path) -> None: assert language_server.is_running() assert Path(language_server.language_server.repository_root_path).resolve() == repo_path.resolve() - @pytest.mark.parametrize("language_server", [Language.ANGULAR], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ANGULAR], indirect=True) def test_component_class_symbols(self, language_server: SolidLanguageServer) -> None: """The Angular LS exposes the component class methods/fields via tsserver.""" all_symbols, _ = language_server.request_document_symbols("src/app/app.component.ts").get_all_symbols_and_roots() @@ -37,14 +37,14 @@ class TestAngularLanguageServerBasics: for expected in ("AppComponent", "title", "userName", "items", "greeting", "setName"): assert expected in names, f"Expected '{expected}' in component symbols: {names}" - @pytest.mark.parametrize("language_server", [Language.ANGULAR], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ANGULAR], indirect=True) def test_service_class_symbols(self, language_server: SolidLanguageServer) -> None: all_symbols, _ = language_server.request_document_symbols("src/app/greeting.service.ts").get_all_symbols_and_roots() names = [s["name"] for s in all_symbols] for expected in ("GreetingService", "greet", "defaultName"): assert expected in names, f"Expected '{expected}' in service symbols: {names}" - @pytest.mark.parametrize("language_server", [Language.ANGULAR], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ANGULAR], indirect=True) def test_full_symbol_tree_includes_all_files(self, language_server: SolidLanguageServer) -> None: all_symbols = request_all_symbols(language_server) relative_paths = {s.get("location", {}).get("relativePath") for s in all_symbols} @@ -59,7 +59,7 @@ class TestAngularLanguageServerBasics: ): assert f in relative_paths, f"Expected {f} to appear in symbol tree, got {relative_paths}" - @pytest.mark.parametrize("language_server", [Language.ANGULAR], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ANGULAR], indirect=True) def test_template_definition_to_component_method(self, language_server: SolidLanguageServer) -> None: """Resolve `greeting()` interpolation in the template to its component method. @@ -79,7 +79,7 @@ class TestAngularLanguageServerBasics: f"Expected definition to resolve into app.component.ts, got URIs: {target_uris}" ) - @pytest.mark.parametrize("language_server", [Language.ANGULAR], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ANGULAR], indirect=True) def test_plain_html_document_symbols(self, language_server: SolidLanguageServer) -> None: """DocumentSymbol on plain index.html should come back from the HTML companion. @@ -94,7 +94,7 @@ class TestAngularLanguageServerBasics: for expected in ("html", "head", "body", "app-root"): assert expected in names, f"Expected '{expected}' in plain-HTML symbol list, got: {names}" - @pytest.mark.parametrize("language_server", [Language.ANGULAR], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ANGULAR], indirect=True) def test_template_html_document_symbols(self, language_server: SolidLanguageServer) -> None: """DocumentSymbol on an Angular template must return the HTML element tree. @@ -108,7 +108,7 @@ class TestAngularLanguageServerBasics: for expected in ("section", "h1", "p", "input", "ul", "app-item-card"): assert expected in names, f"Expected '{expected}' in template HTML symbol list, got: {names}" - @pytest.mark.parametrize("language_server", [Language.ANGULAR], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ANGULAR], indirect=True) def test_ts_method_references_include_template_usage(self, language_server: SolidLanguageServer) -> None: """References on a .ts component method must include its template callers. @@ -134,7 +134,7 @@ class TestAngularLanguageServerBasics: class TestAngularHover: """Hover routing — .ts goes to the companion tsserver, .html goes to ngserver.""" - @pytest.mark.parametrize("language_server", [Language.ANGULAR], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ANGULAR], indirect=True) def test_hover_on_ts_method(self, language_server: SolidLanguageServer) -> None: """Hover on a .ts method declaration is routed through the companion TS server and must yield a non-empty MarkupContent describing the method signature. @@ -153,7 +153,7 @@ class TestAngularHover: text = contents["value"] if isinstance(contents, dict) else str(contents) assert "setName" in text, f"Expected setName in hover text, got: {text}" - @pytest.mark.parametrize("language_server", [Language.ANGULAR], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ANGULAR], indirect=True) def test_hover_on_template_method_call(self, language_server: SolidLanguageServer) -> None: """Hover on a method call inside an Angular template ({{ greeting() }}) goes through ngserver and must yield Angular-aware type info. @@ -174,7 +174,7 @@ class TestAngularHover: class TestAngularDefinitionRouting: """Cross-file definition for the binding flavours not covered by basic tests.""" - @pytest.mark.parametrize("language_server", [Language.ANGULAR], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ANGULAR], indirect=True) def test_definition_from_property_binding(self, language_server: SolidLanguageServer) -> None: """Property binding ``[value]="userName()"`` must resolve to the component's ``userName`` signal field declaration in app.component.ts. @@ -193,7 +193,7 @@ class TestAngularDefinitionRouting: f"Expected definition to resolve into app.component.ts, got URIs: {target_uris}" ) - @pytest.mark.parametrize("language_server", [Language.ANGULAR], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ANGULAR], indirect=True) def test_definition_from_event_binding(self, language_server: SolidLanguageServer) -> None: """Event binding ``(input)="setName(...)"`` must resolve to the component's ``setName`` method declaration in app.component.ts. @@ -211,7 +211,7 @@ class TestAngularDefinitionRouting: f"Expected definition to resolve into app.component.ts, got URIs: {target_uris}" ) - @pytest.mark.parametrize("language_server", [Language.ANGULAR], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ANGULAR], indirect=True) def test_definition_service_import_in_component(self, language_server: SolidLanguageServer) -> None: """The ``GreetingService`` symbol used in the constructor parameter list of AppComponent must resolve to greeting.service.ts via the companion TS server. @@ -231,7 +231,7 @@ class TestAngularDefinitionRouting: f"Expected definition to resolve into greeting.service.ts, got URIs: {target_uris}" ) - @pytest.mark.parametrize("language_server", [Language.ANGULAR], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ANGULAR], indirect=True) def test_definition_from_child_component_selector(self, language_server: SolidLanguageServer) -> None: """The ```` element in the parent template must resolve to the ItemCardComponent class declaration in item-card.component.ts. @@ -258,7 +258,7 @@ class TestAngularDefinitionRouting: class TestAngularRename: """Rename routing returns a WorkspaceEdit without applying it (safe for fixtures).""" - @pytest.mark.parametrize("language_server", [Language.ANGULAR], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ANGULAR], indirect=True) def test_rename_method_returns_edits_for_ts_and_template(self, language_server: SolidLanguageServer) -> None: """Renaming the ``setName`` method from its .ts declaration must return a WorkspaceEdit that touches both app.component.ts (declaration + any TS calls) @@ -289,7 +289,7 @@ class TestAngularRename: class TestAngularSymbolStructure: """Hierarchical symbol structure — class symbols must contain method/field children.""" - @pytest.mark.parametrize("language_server", [Language.ANGULAR], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ANGULAR], indirect=True) def test_component_class_has_methods_and_fields_as_children(self, language_server: SolidLanguageServer) -> None: """``request_document_symbols`` should return AppComponent as a class symbol whose children include its methods (``greeting``, ``setName``) and signal @@ -306,7 +306,7 @@ class TestAngularSymbolStructure: for expected in ("greeting", "setName", "title", "userName", "items"): assert expected in child_names, f"Expected '{expected}' as child of AppComponent, got: {child_names}" - @pytest.mark.parametrize("language_server", [Language.ANGULAR], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ANGULAR], indirect=True) def test_pipe_class_in_symbol_tree(self, language_server: SolidLanguageServer) -> None: """A custom pipe (``ExclaimPipe``) declared in exclaim.pipe.ts must appear in the workspace symbol tree alongside the components and the service. @@ -321,7 +321,7 @@ class TestAngularSymbolStructure: class TestAngularImplementations: """``textDocument/implementation`` is routed through tsserver via the Angular plugin.""" - @pytest.mark.parametrize("language_server", [Language.ANGULAR], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ANGULAR], indirect=True) def test_find_implementations_of_interface_method(self, language_server: SolidLanguageServer) -> None: """``Greeter.greet`` is implemented by ``GreetingService``; ``request_implementation`` invoked at the interface declaration must point at the service. diff --git a/test/solidlsp/angular/test_angular_diagnostics.py b/test/solidlsp/angular/test_angular_diagnostics.py index d1f02bdb..7df9757f 100644 --- a/test/solidlsp/angular/test_angular_diagnostics.py +++ b/test/solidlsp/angular/test_angular_diagnostics.py @@ -12,13 +12,13 @@ Two paths are exercised: import pytest from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from test.solidlsp.util.diagnostics import assert_file_diagnostics @pytest.mark.angular class TestAngularDiagnostics: - @pytest.mark.parametrize("language_server", [Language.ANGULAR], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ANGULAR], indirect=True) def test_component_class_diagnostics(self, language_server: SolidLanguageServer) -> None: """The component's ``count: number = 'not-a-number'`` must be flagged by tsserver.""" assert_file_diagnostics( @@ -28,7 +28,7 @@ class TestAngularDiagnostics: min_count=1, ) - @pytest.mark.parametrize("language_server", [Language.ANGULAR], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ANGULAR], indirect=True) def test_template_diagnostics(self, language_server: SolidLanguageServer) -> None: """The template's ``{{ undefinedSignal() }}`` must be flagged by ngserver. diff --git a/test/solidlsp/angular/test_angular_error_cases.py b/test/solidlsp/angular/test_angular_error_cases.py index 85e9375e..6ce05e8c 100644 --- a/test/solidlsp/angular/test_angular_error_cases.py +++ b/test/solidlsp/angular/test_angular_error_cases.py @@ -21,7 +21,7 @@ import time import pytest from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from solidlsp.ls_exceptions import SolidLSPException from test.conftest import _create_ls @@ -37,7 +37,7 @@ TEMPLATE_FILE = os.path.join("src", "app", "app.component.html") class TestAngularInvalidPositionsOnTs: """Negative / out-of-bounds line and column on .ts files (TS-companion route).""" - @pytest.mark.parametrize("language_server", [Language.ANGULAR], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ANGULAR], indirect=True) def test_negative_line_number_containing_symbol(self, language_server: SolidLanguageServer) -> None: """``request_containing_symbol`` short-circuits before reaching the LS: a negative line returns None. @@ -45,19 +45,19 @@ class TestAngularInvalidPositionsOnTs: result = language_server.request_containing_symbol(TS_FILE, -1, 0) assert result is None, f"Expected None for negative line, got: {result!r}" - @pytest.mark.parametrize("language_server", [Language.ANGULAR], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ANGULAR], indirect=True) def test_negative_character_number_containing_symbol(self, language_server: SolidLanguageServer) -> None: result = language_server.request_containing_symbol(TS_FILE, 5, -1) assert result is None, f"Expected None for negative character, got: {result!r}" - @pytest.mark.parametrize("language_server", [Language.ANGULAR], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ANGULAR], indirect=True) def test_line_number_beyond_file_length(self, language_server: SolidLanguageServer) -> None: """The wrapper code raises ``IndexError`` before reaching the LS.""" with pytest.raises(IndexError) as exc_info: language_server.request_containing_symbol(TS_FILE, 99999, 0) assert "list index out of range" in str(exc_info.value), f"Expected 'list index out of range' error, got: {exc_info.value}" - @pytest.mark.parametrize("language_server", [Language.ANGULAR], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ANGULAR], indirect=True) def test_character_beyond_line_length_returns_enclosing_class(self, language_server: SolidLanguageServer) -> None: """Character far beyond end-of-line is clamped by the LSP. Line 5 of app.component.ts is inside ``export class AppComponent { ... }``, so the @@ -69,7 +69,7 @@ class TestAngularInvalidPositionsOnTs: assert isinstance(result, dict), f"Expected dict (containing class), got: {result!r}" assert result.get("name") == "AppComponent", f"Expected containing symbol 'AppComponent', got: {result.get('name')!r}" - @pytest.mark.parametrize("language_server", [Language.ANGULAR], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ANGULAR], indirect=True) def test_references_at_negative_line_returns_empty(self, language_server: SolidLanguageServer) -> None: """The Angular LS's TS companion returns ``[]`` for negative-line ``request_references`` — it does **not** raise. (Plain Vue tests @@ -79,7 +79,7 @@ class TestAngularInvalidPositionsOnTs: result = language_server.request_references(TS_FILE, -1, 0) assert result == [], f"Expected [], got: {result!r}" - @pytest.mark.parametrize("language_server", [Language.ANGULAR], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ANGULAR], indirect=True) def test_definition_at_negative_position_returns_empty(self, language_server: SolidLanguageServer) -> None: """Same as references: TS companion returns ``[]``, does not raise.""" result = language_server.request_definition(TS_FILE, -1, 0) @@ -93,7 +93,7 @@ class TestAngularInvalidPositionsOnTs: class TestAngularInvalidPositionsOnTemplate: """Negative / out-of-bounds positions on .html files (ngserver route).""" - @pytest.mark.parametrize("language_server", [Language.ANGULAR], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ANGULAR], indirect=True) def test_negative_line_definition_raises(self, language_server: SolidLanguageServer) -> None: """Ngserver does **not** swallow malformed positions: it surfaces a ``Debug Failure. False expression.`` error from its underlying @@ -105,7 +105,7 @@ class TestAngularInvalidPositionsOnTemplate: f"Unexpected exception message: {exc_info.value}" ) - @pytest.mark.parametrize("language_server", [Language.ANGULAR], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ANGULAR], indirect=True) def test_character_beyond_line_definition_raises(self, language_server: SolidLanguageServer) -> None: """Same path as negative line — ngserver raises Debug Failure.""" with pytest.raises(SolidLSPException) as exc_info: @@ -118,7 +118,7 @@ class TestAngularInvalidPositionsOnTemplate: class TestAngularNonExistentFiles: """Requests against files that don't exist must raise FileNotFoundError consistently.""" - @pytest.mark.parametrize("language_server", [Language.ANGULAR], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ANGULAR], indirect=True) def test_nonexistent_ts_file_raises(self, language_server: SolidLanguageServer) -> None: nonexistent = os.path.join("src", "app", "does-not-exist.component.ts") with pytest.raises(FileNotFoundError): @@ -128,7 +128,7 @@ class TestAngularNonExistentFiles: with pytest.raises(FileNotFoundError): language_server.request_document_symbols(nonexistent) - @pytest.mark.parametrize("language_server", [Language.ANGULAR], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ANGULAR], indirect=True) def test_nonexistent_html_file_raises(self, language_server: SolidLanguageServer) -> None: nonexistent = os.path.join("src", "app", "does-not-exist.component.html") with pytest.raises(FileNotFoundError): @@ -140,7 +140,7 @@ class TestAngularNonExistentFiles: class TestAngularUndefinedSymbols: """Symbols that have no callers / definitions / referencing positions.""" - @pytest.mark.parametrize("language_server", [Language.ANGULAR], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ANGULAR], indirect=True) def test_definition_at_keyword_position_returns_empty(self, language_server: SolidLanguageServer) -> None: """Cursor on the ``import`` keyword (line 0, col 0 of app.component.ts) has no definition target — the TS companion returns ``[]``. @@ -148,7 +148,7 @@ class TestAngularUndefinedSymbols: result = language_server.request_definition(TS_FILE, 0, 0) assert result == [], f"Expected [] for keyword position, got: {result!r}" - @pytest.mark.parametrize("language_server", [Language.ANGULAR], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ANGULAR], indirect=True) def test_references_for_local_const_have_few_callers(self, language_server: SolidLanguageServer) -> None: """A locally-scoped private field has at most its declaration plus its in-method use as references. ``defaultName`` on GreetingService is @@ -168,7 +168,7 @@ class TestAngularUndefinedSymbols: class TestAngularEdgeCasePositions: """Position (0,0), whitespace lines, and other boundary conditions.""" - @pytest.mark.parametrize("language_server", [Language.ANGULAR], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ANGULAR], indirect=True) def test_containing_symbol_at_file_start_is_none(self, language_server: SolidLanguageServer) -> None: """Line 0 of app.component.ts is an ``import`` statement, outside any class or function — the TS companion returns ``None`` for containing @@ -177,19 +177,19 @@ class TestAngularEdgeCasePositions: result = language_server.request_containing_symbol(TS_FILE, 0, 0) assert result is None, f"Expected None at (0,0), got: {result!r}" - @pytest.mark.parametrize("language_server", [Language.ANGULAR], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ANGULAR], indirect=True) def test_references_at_file_start_returns_empty(self, language_server: SolidLanguageServer) -> None: """Position (0, 0) is on the ``import`` keyword — no references.""" result = language_server.request_references(TS_FILE, 0, 0) assert result == [], f"Expected [] at (0,0), got: {result!r}" - @pytest.mark.parametrize("language_server", [Language.ANGULAR], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ANGULAR], indirect=True) def test_definition_at_file_start_returns_empty(self, language_server: SolidLanguageServer) -> None: """Position (0, 0) is on the ``import`` keyword — no definition.""" result = language_server.request_definition(TS_FILE, 0, 0) assert result == [], f"Expected [] at (0,0), got: {result!r}" - @pytest.mark.parametrize("language_server", [Language.ANGULAR], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ANGULAR], indirect=True) def test_template_position_no_containing_symbol(self, language_server: SolidLanguageServer) -> None: """An Angular template has no class/function containers; the HTML companion's documentSymbol provides element symbols only. @@ -198,7 +198,7 @@ class TestAngularEdgeCasePositions: result = language_server.request_containing_symbol(TEMPLATE_FILE, 1, 4) assert result is None, f"Expected None inside template, got: {result!r}" - @pytest.mark.parametrize("language_server", [Language.ANGULAR], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ANGULAR], indirect=True) def test_containing_symbol_inside_class_body_returns_class(self, language_server: SolidLanguageServer) -> None: """Lines 5 and 10 of app.component.ts are inside the AppComponent class body. The TS companion correctly reports AppComponent as the @@ -209,7 +209,7 @@ class TestAngularEdgeCasePositions: assert isinstance(result, dict), f"Line {line}: expected dict, got {result!r}" assert result.get("name") == "AppComponent", f"Line {line}: expected 'AppComponent', got {result.get('name')!r}" - @pytest.mark.parametrize("language_server", [Language.ANGULAR], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ANGULAR], indirect=True) def test_containing_symbol_outside_class_body_is_none(self, language_server: SolidLanguageServer) -> None: """Line 0 (import) and line 15 (blank/whitespace inside file but outside any symbol's range, depending on file structure) report no @@ -223,7 +223,7 @@ class TestAngularEdgeCasePositions: class TestAngularReferenceEdgeCases: """Edge cases for the SolidLanguageServer reference helpers (built on top of LSP).""" - @pytest.mark.parametrize("language_server", [Language.ANGULAR], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ANGULAR], indirect=True) def test_referencing_symbols_at_invalid_position_raises(self, language_server: SolidLanguageServer) -> None: """Unlike ``request_references`` (which returns ``[]``), ``request_referencing_symbols`` validates more strictly and surfaces @@ -241,7 +241,7 @@ class TestAngularReferenceEdgeCases: f"Unexpected exception message: {exc_info.value}" ) - @pytest.mark.parametrize("language_server", [Language.ANGULAR], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ANGULAR], indirect=True) def test_defining_symbol_at_invalid_position_returns_none(self, language_server: SolidLanguageServer) -> None: """``request_defining_symbol`` short-circuits when no definition is found and returns None — no exception, even for negative positions. @@ -328,7 +328,7 @@ class TestAngularStartupCleanup: import psutil - ls = _create_ls(Language.ANGULAR) + ls = _create_ls(LanguageServerId.ANGULAR) my_proc = psutil.Process(os.getpid()) children_before = {p.pid for p in my_proc.children(recursive=True)} diff --git a/test/solidlsp/ansible/test_ansible_basic.py b/test/solidlsp/ansible/test_ansible_basic.py index 666a3f0b..00db128f 100644 --- a/test/solidlsp/ansible/test_ansible_basic.py +++ b/test/solidlsp/ansible/test_ansible_basic.py @@ -11,24 +11,26 @@ from pathlib import Path import pytest from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language -from test.conftest import language_tests_enabled +from solidlsp.ls_config import LanguageServerId +from test.conftest import language_server_tests_enabled from test.solidlsp.conftest import format_symbol_for_assert, has_malformed_name, request_all_symbols -@pytest.mark.skipif(not language_tests_enabled(Language.ANSIBLE), reason="Ansible tests are disabled (no native Windows support)") +@pytest.mark.skipif( + not language_server_tests_enabled(LanguageServerId.ANSIBLE), reason="Ansible tests are disabled (no native Windows support)" +) @pytest.mark.ansible class TestAnsibleLanguageServerBasics: """Test basic Ansible language server functionality.""" - @pytest.mark.parametrize("language_server", [Language.ANSIBLE], indirect=True) - @pytest.mark.parametrize("repo_path", [Language.ANSIBLE], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ANSIBLE], indirect=True) + @pytest.mark.parametrize("repo_path", [LanguageServerId.ANSIBLE], indirect=True) def test_ls_is_running(self, language_server: SolidLanguageServer, repo_path: Path) -> None: """Language server starts and points to the correct repo.""" assert language_server.is_running() assert Path(language_server.language_server.repository_root_path).resolve() == repo_path.resolve() - @pytest.mark.parametrize("language_server", [Language.ANSIBLE], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ANSIBLE], indirect=True) def test_hover_on_module_contains_documentation(self, language_server: SolidLanguageServer) -> None: """Hover on ansible.builtin.package returns module documentation.""" # playbook.yml line 10 (0-indexed): "ansible.builtin.package:" @@ -43,7 +45,7 @@ class TestAnsibleLanguageServerBasics: hover_text = str(hover_value) assert "package" in hover_text.lower(), f"Hover should mention 'package', got: {hover_text[:300]}" - @pytest.mark.parametrize("language_server", [Language.ANSIBLE], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ANSIBLE], indirect=True) def test_completions_contain_module_names(self, language_server: SolidLanguageServer) -> None: """Completions at a task keyword position return Ansible module names.""" # playbook.yml line 10 (0-indexed), col 6: inside a task block @@ -54,7 +56,7 @@ class TestAnsibleLanguageServerBasics: assert labels, f"Expected completions with completionText, got: {result[:3]}" @pytest.mark.xfail(reason="Seems like ansible LS lacks basic functionality at the moment, textDocument/documentSymbol doesn't work") - @pytest.mark.parametrize("language_server", [Language.ANSIBLE], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ANSIBLE], indirect=True) def test_bare_symbol_names(self, language_server) -> None: all_symbols = request_all_symbols(language_server) malformed_symbols = [] diff --git a/test/solidlsp/bash/test_bash_basic.py b/test/solidlsp/bash/test_bash_basic.py index c7715a29..bef97709 100644 --- a/test/solidlsp/bash/test_bash_basic.py +++ b/test/solidlsp/bash/test_bash_basic.py @@ -8,7 +8,7 @@ like request_document_symbols using the bash test repository. import pytest from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from test.solidlsp.conftest import format_symbol_for_assert, has_malformed_name, request_all_symbols @@ -16,13 +16,13 @@ from test.solidlsp.conftest import format_symbol_for_assert, has_malformed_name, class TestBashLanguageServerBasics: """Test basic functionality of the bash language server.""" - @pytest.mark.parametrize("language_server", [Language.BASH], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.BASH], indirect=True) def test_bash_language_server_initialization(self, language_server: SolidLanguageServer) -> None: """Test that bash language server can be initialized successfully.""" assert language_server is not None - assert language_server.language == Language.BASH + assert language_server.ls_id == LanguageServerId.BASH - @pytest.mark.parametrize("language_server", [Language.BASH], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.BASH], indirect=True) def test_bash_request_document_symbols(self, language_server: SolidLanguageServer) -> None: """Test request_document_symbols for bash files.""" # Test getting symbols from main.sh @@ -38,7 +38,7 @@ class TestBashLanguageServerBasics: assert "main" in function_names, "Should find main function" assert len(function_symbols) >= 3, f"Should find at least 3 functions, found {len(function_symbols)}" - @pytest.mark.parametrize("language_server", [Language.BASH], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.BASH], indirect=True) def test_bash_request_document_symbols_with_body(self, language_server: SolidLanguageServer) -> None: """Test request_document_symbols with body extraction.""" # Test with include_body=True @@ -55,7 +55,7 @@ class TestBashLanguageServerBasics: assert "function greet_user()" in body, "Function body should contain function definition" assert "case" in body.lower(), "Function body should contain case statement" - @pytest.mark.parametrize("language_server", [Language.BASH], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.BASH], indirect=True) def test_bash_utils_functions(self, language_server: SolidLanguageServer) -> None: """Test function detection in utils.sh file.""" # Test with utils.sh as well @@ -81,7 +81,7 @@ class TestBashLanguageServerBasics: assert len(utils_function_symbols) >= 8, f"Should find at least 8 functions in utils.sh, found {len(utils_function_symbols)}" - @pytest.mark.parametrize("language_server", [Language.BASH], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.BASH], indirect=True) def test_bash_function_syntax_patterns(self, language_server: SolidLanguageServer) -> None: """Test that LSP detects different bash function syntax patterns correctly.""" # Test main.sh (has both 'function' keyword and traditional syntax) @@ -121,7 +121,7 @@ class TestBashLanguageServerBasics: assert len(main_functions) >= 3, f"Should find at least 3 functions in main.sh, found {len(main_functions)}" assert len(utils_functions) >= 8, f"Should find at least 8 functions in utils.sh, found {len(utils_functions)}" - @pytest.mark.parametrize("language_server", [Language.BASH], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.BASH], indirect=True) def test_bare_symbol_names(self, language_server) -> None: all_symbols = request_all_symbols(language_server) malformed_symbols = [] diff --git a/test/solidlsp/bash/test_bash_diagnostics.py b/test/solidlsp/bash/test_bash_diagnostics.py index bd1cc494..66e30fe2 100644 --- a/test/solidlsp/bash/test_bash_diagnostics.py +++ b/test/solidlsp/bash/test_bash_diagnostics.py @@ -1,13 +1,13 @@ import pytest from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from test.solidlsp.util.diagnostics import assert_file_diagnostics @pytest.mark.bash class TestBashDiagnostics: - @pytest.mark.parametrize("language_server", [Language.BASH], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.BASH], indirect=True) def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None: assert_file_diagnostics( language_server, diff --git a/test/solidlsp/bsl/test_bsl_basic.py b/test/solidlsp/bsl/test_bsl_basic.py index 4e093749..314b7d5a 100644 --- a/test/solidlsp/bsl/test_bsl_basic.py +++ b/test/solidlsp/bsl/test_bsl_basic.py @@ -5,32 +5,34 @@ from unittest import mock import pytest from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from solidlsp.ls_utils import SymbolUtils from solidlsp.settings import SolidLSPSettings -from test.conftest import language_tests_enabled +from test.conftest import language_server_tests_enabled from test.solidlsp.conftest import format_symbol_for_assert, has_malformed_name, request_all_symbols -pytestmark = pytest.mark.skipif(not language_tests_enabled(Language.BSL), reason="BSL tests are disabled (niche, slow and flaky)") +pytestmark = pytest.mark.skipif( + not language_server_tests_enabled(LanguageServerId.BSL), reason="BSL tests are disabled (niche, slow and flaky)" +) @pytest.mark.bsl class TestBSLLanguageServer: - @pytest.mark.parametrize("language_server", [Language.BSL], indirect=True) - @pytest.mark.parametrize("repo_path", [Language.BSL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.BSL], indirect=True) + @pytest.mark.parametrize("repo_path", [LanguageServerId.BSL], indirect=True) def test_ls_is_running(self, language_server: SolidLanguageServer, repo_path: Path) -> None: """Language server starts and attaches to the test repository.""" assert language_server.is_running() assert Path(language_server.language_server.repository_root_path).resolve() == repo_path.resolve() - @pytest.mark.parametrize("language_server", [Language.BSL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.BSL], indirect=True) def test_find_symbol(self, language_server: SolidLanguageServer) -> None: symbols = language_server.request_full_symbol_tree() assert SymbolUtils.symbol_tree_contains_name(symbols, "ВывестиСообщение"), "ВывестиСообщение not found in symbol tree" assert SymbolUtils.symbol_tree_contains_name(symbols, "ПолучитьПриветствие"), "ПолучитьПриветствие not found in symbol tree" assert SymbolUtils.symbol_tree_contains_name(symbols, "Инициализировать"), "Инициализировать not found in symbol tree" - @pytest.mark.parametrize("language_server", [Language.BSL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.BSL], indirect=True) def test_document_symbols(self, language_server: SolidLanguageServer) -> None: doc_symbols = language_server.request_document_symbols("CommonModule.bsl") all_symbols, _ = doc_symbols.get_all_symbols_and_roots() @@ -39,7 +41,7 @@ class TestBSLLanguageServer: assert "ПолучитьПриветствие" in names, f"ПолучитьПриветствие not found in CommonModule.bsl symbols. Found: {names}" assert "ВызватьПриветствие" in names, f"ВызватьПриветствие not found in CommonModule.bsl symbols. Found: {names}" - @pytest.mark.parametrize("language_server", [Language.BSL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.BSL], indirect=True) def test_full_symbol_tree_within_file(self, language_server: SolidLanguageServer) -> None: """Scoping the full-tree request to a single file returns that file's symbols.""" symbols = language_server.request_full_symbol_tree(within_relative_path="ObjectModule.bsl") @@ -50,7 +52,7 @@ class TestBSLLanguageServer: "ПолучитьСостояние not found in ObjectModule.bsl symbol tree" ) - @pytest.mark.parametrize("language_server", [Language.BSL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.BSL], indirect=True) def test_find_references_within_file(self, language_server: SolidLanguageServer) -> None: # CommonModule.bsl (0-indexed): # line 2: Процедура ВывестиСообщение(Текст) Экспорт <- declaration (name starts at col 10) @@ -66,7 +68,7 @@ class TestBSLLanguageServer: matching_lines = [ref["range"]["start"]["line"] for ref in refs if "CommonModule.bsl" in ref.get("relativePath", "")] assert 12 in matching_lines, f"Expected a reference on line 12 (0-indexed), got lines: {matching_lines}" - @pytest.mark.parametrize("language_server", [Language.BSL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.BSL], indirect=True) def test_find_references_to_function_within_file(self, language_server: SolidLanguageServer) -> None: # CommonModule.bsl (0-indexed): # line 6: Функция ПолучитьПриветствие(Имя) Экспорт <- declaration (name starts at col 8) @@ -88,7 +90,7 @@ class TestBSLLanguageServer: _CROSS_REF_MODULE1 = os.path.join("src", "CommonModules", "ОбщийМодуль1", "Ext", "Module.bsl") _CROSS_REF_MODULE2 = os.path.join("src", "CommonModules", "ОбщийМодуль2", "Ext", "Module.bsl") - @pytest.mark.parametrize("language_server", [Language.BSL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.BSL], indirect=True) def test_find_references_across_files(self, language_server: SolidLanguageServer) -> None: """``request_references`` from the declaration must include the cross-module call-site.""" # ОбщийМодуль1 / Ext / Module.bsl (0-indexed): @@ -104,7 +106,7 @@ class TestBSLLanguageServer: call_site_lines = [ref["range"]["start"]["line"] for ref in refs if "ОбщийМодуль2" in ref.get("relativePath", "")] assert 3 in call_site_lines, f"Expected a reference at ОбщийМодуль2/Module.bsl line 3, got lines: {call_site_lines}" - @pytest.mark.parametrize("language_server", [Language.BSL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.BSL], indirect=True) def test_find_definition_across_files(self, language_server: SolidLanguageServer) -> None: """``request_definition`` from a cross-module call-site must resolve to the other module.""" # cursor on "ВывестиСообщение" inside @@ -116,7 +118,7 @@ class TestBSLLanguageServer: target_lines = [d["range"]["start"]["line"] for d in definitions if "ОбщийМодуль1" in d.get("relativePath", "")] assert 2 in target_lines, f"Expected the definition to point at ОбщийМодуль1/Module.bsl line 2, got: {target_lines}" - @pytest.mark.parametrize("language_server", [Language.BSL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.BSL], indirect=True) def test_bare_symbol_names(self, language_server: SolidLanguageServer) -> None: all_symbols = request_all_symbols(language_server) malformed = [s for s in all_symbols if has_malformed_name(s)] @@ -133,15 +135,15 @@ class TestBSLLanguageServer: def test_bsl_filename_matcher() -> None: - matcher = Language.BSL.get_source_fn_matcher() + matcher = LanguageServerId.BSL.get_source_fn_matcher() assert matcher.is_relevant_filename("module.bsl") assert matcher.is_relevant_filename("script.os") assert not matcher.is_relevant_filename("module.py") def test_bsl_enum_registration() -> None: - assert Language.BSL.value == "bsl" - assert Language.BSL.get_ls_class().__name__ == "BSLLanguageServer" + assert LanguageServerId.BSL.value == "bsl" + assert LanguageServerId.BSL.get_ls_class().__name__ == "BSLLanguageServer" def test_bsl_dependency_provider_default_version() -> None: @@ -153,7 +155,7 @@ def test_bsl_dependency_provider_default_version() -> None: settings = SolidLSPSettings() provider = BSLLanguageServer.DependencyProvider( - settings.get_ls_specific_settings(Language.BSL), + settings.get_ls_specific_settings(LanguageServerId.BSL), "/tmp/ls_resources", ) @@ -174,9 +176,9 @@ def test_bsl_dependency_provider_custom_version_no_sha() -> None: from solidlsp.language_servers.common import RuntimeDependencyCollection settings = SolidLSPSettings() - settings.ls_specific_settings[Language.BSL] = {"bsl_ls_version": "0.28.0"} + settings.ls_specific_settings[LanguageServerId.BSL] = {"bsl_ls_version": "0.28.0"} provider = BSLLanguageServer.DependencyProvider( - settings.get_ls_specific_settings(Language.BSL), + settings.get_ls_specific_settings(LanguageServerId.BSL), "/tmp/ls_resources", ) @@ -214,9 +216,9 @@ def test_bsl_launch_command_uses_ls_path_without_download() -> None: from solidlsp.language_servers.bsl_language_server import BSLLanguageServer settings = SolidLSPSettings() - settings.ls_specific_settings[Language.BSL] = {"ls_path": "/custom/path/bsl-language-server.jar"} + settings.ls_specific_settings[LanguageServerId.BSL] = {"ls_path": "/custom/path/bsl-language-server.jar"} provider = BSLLanguageServer.DependencyProvider( - settings.get_ls_specific_settings(Language.BSL), + settings.get_ls_specific_settings(LanguageServerId.BSL), "/tmp/ls_resources", ) @@ -241,9 +243,9 @@ def test_bsl_launch_command_requires_java() -> None: from solidlsp.language_servers.bsl_language_server import BSLLanguageServer settings = SolidLSPSettings() - settings.ls_specific_settings[Language.BSL] = {"ls_path": "/custom/path/bsl-language-server.jar"} + settings.ls_specific_settings[LanguageServerId.BSL] = {"ls_path": "/custom/path/bsl-language-server.jar"} provider = BSLLanguageServer.DependencyProvider( - settings.get_ls_specific_settings(Language.BSL), + settings.get_ls_specific_settings(LanguageServerId.BSL), "/tmp/ls_resources", ) @@ -258,9 +260,9 @@ def test_bsl_launch_command_rejects_old_java() -> None: from solidlsp.language_servers.bsl_language_server import BSL_LS_MIN_JAVA_VERSION, BSLLanguageServer settings = SolidLSPSettings() - settings.ls_specific_settings[Language.BSL] = {"ls_path": "/custom/path/bsl-language-server.jar"} + settings.ls_specific_settings[LanguageServerId.BSL] = {"ls_path": "/custom/path/bsl-language-server.jar"} provider = BSLLanguageServer.DependencyProvider( - settings.get_ls_specific_settings(Language.BSL), + settings.get_ls_specific_settings(LanguageServerId.BSL), "/tmp/ls_resources", ) diff --git a/test/solidlsp/bsl/test_bsl_diagnostics.py b/test/solidlsp/bsl/test_bsl_diagnostics.py index e5dfe69e..3c63642a 100644 --- a/test/solidlsp/bsl/test_bsl_diagnostics.py +++ b/test/solidlsp/bsl/test_bsl_diagnostics.py @@ -1,15 +1,15 @@ import pytest from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language -from test.conftest import language_tests_enabled +from solidlsp.ls_config import LanguageServerId +from test.conftest import language_server_tests_enabled from test.solidlsp.util.diagnostics import assert_file_diagnostics @pytest.mark.bsl -@pytest.mark.skipif(not language_tests_enabled(Language.BSL), reason="BSL tests are disabled") +@pytest.mark.skipif(not language_server_tests_enabled(LanguageServerId.BSL), reason="BSL tests are disabled") class TestBSLDiagnostics: - @pytest.mark.parametrize("language_server", [Language.BSL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.BSL], indirect=True) def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None: """bsl-language-server must flag the unterminated string literal in the fixture.""" assert_file_diagnostics( diff --git a/test/solidlsp/clojure/test_clojure_basic.py b/test/solidlsp/clojure/test_clojure_basic.py index 3dd06d8e..7c4f442b 100644 --- a/test/solidlsp/clojure/test_clojure_basic.py +++ b/test/solidlsp/clojure/test_clojure_basic.py @@ -2,18 +2,18 @@ import pytest from serena.project import Project from solidlsp.ls import SolidLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from solidlsp.ls_types import SymbolKind, UnifiedSymbolInformation -from test.conftest import language_tests_enabled +from test.conftest import language_server_tests_enabled from test.solidlsp.conftest import format_symbol_for_assert, has_malformed_name, request_all_symbols from . import CORE_PATH, UTILS_PATH -@pytest.mark.skipif(not language_tests_enabled(Language.CLOJURE), reason="Clojure tests are disabled") +@pytest.mark.skipif(not language_server_tests_enabled(LanguageServerId.CLOJURE), reason="Clojure tests are disabled") @pytest.mark.clojure class TestLanguageServerBasics: - @pytest.mark.parametrize("language_server", [Language.CLOJURE], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.CLOJURE], indirect=True) def test_basic_definition(self, language_server: SolidLanguageServer): """ Test finding definition of 'greet' function call in core.clj @@ -27,7 +27,7 @@ class TestLanguageServerBasics: assert definition["relativePath"] == CORE_PATH assert definition["range"]["start"]["line"] == 2, "Should find the definition of greet function at line 2" - @pytest.mark.parametrize("language_server", [Language.CLOJURE], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.CLOJURE], indirect=True) def test_cross_file_references(self, language_server: SolidLanguageServer): """ Test finding references to 'multiply' function from core.clj @@ -42,7 +42,7 @@ class TestLanguageServerBasics: ) assert usage_found, "Should find multiply usage in utils.clj" - @pytest.mark.parametrize("language_server", [Language.CLOJURE], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.CLOJURE], indirect=True) def test_completions(self, language_server: SolidLanguageServer): with language_server.open_file(UTILS_PATH): # After "core/" in calculate-area @@ -53,7 +53,7 @@ class TestLanguageServerBasics: completion_texts = [item["completionText"] for item in result] assert any("multiply" in text for text in completion_texts), "Should find 'multiply' function in completions after 'core/'" - @pytest.mark.parametrize("language_server", [Language.CLOJURE], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.CLOJURE], indirect=True) def test_document_symbols(self, language_server: SolidLanguageServer): symbols, _ = language_server.request_document_symbols(CORE_PATH).get_all_symbols_and_roots() @@ -66,7 +66,7 @@ class TestLanguageServerBasics: 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) + @pytest.mark.parametrize("language_server", [LanguageServerId.CLOJURE], indirect=True) def test_hover(self, language_server: SolidLanguageServer): """Test hover on greet function""" result = language_server.request_hover(CORE_PATH, 2, 7) @@ -82,7 +82,7 @@ class TestLanguageServerBasics: else: assert False, f"Unexpected contents format: {type(contents)}" - @pytest.mark.parametrize("language_server", [Language.CLOJURE], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.CLOJURE], indirect=True) def test_workspace_symbols(self, language_server: SolidLanguageServer): # Search for functions containing "add" result = language_server.request_workspace_symbol("add") @@ -93,7 +93,7 @@ class TestLanguageServerBasics: symbol_names = [symbol["name"] for symbol in result] assert any("add" in name.lower() for name in symbol_names), f"Should find 'add' function in symbols: {symbol_names}" - @pytest.mark.parametrize("language_server", [Language.CLOJURE], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.CLOJURE], indirect=True) def test_namespace_functions(self, language_server: SolidLanguageServer): """Test definition lookup for core/greet usage in utils.clj""" # Position of 'greet' in core/greet call @@ -105,7 +105,7 @@ class TestLanguageServerBasics: definition = result[0] assert definition["relativePath"] == CORE_PATH, "Should find the definition of greet in core.clj" - @pytest.mark.parametrize("language_server", [Language.CLOJURE], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.CLOJURE], indirect=True) def test_request_references_with_content(self, language_server: SolidLanguageServer): """Test references to multiply function with content""" references = language_server.request_references(CORE_PATH, 12, 6) @@ -130,7 +130,7 @@ class TestLanguageServerBasics: utils_content = utils_refs[0].to_display_string() assert "calculate-area" in utils_content - @pytest.mark.parametrize("language_server", [Language.CLOJURE], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.CLOJURE], indirect=True) def test_request_full_symbol_tree(self, language_server: SolidLanguageServer): """Test retrieving the full symbol tree for project overview We just check that we find some expected symbols. @@ -172,7 +172,7 @@ class TestLanguageServerBasics: f"Symbol tree structure:\n{traverse_symbols(result)}" ) - @pytest.mark.parametrize("language_server", [Language.CLOJURE], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.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. @@ -188,10 +188,10 @@ class TestLanguageServerBasics: assert found_relevant_references, f"Should have found calculate-area referencing multiply, but got: {result}" -@pytest.mark.skipif(not language_tests_enabled(Language.CLOJURE), reason="Clojure tests are disabled") +@pytest.mark.skipif(not language_server_tests_enabled(LanguageServerId.CLOJURE), reason="Clojure tests are disabled") @pytest.mark.clojure class TestProjectBasics: - @pytest.mark.parametrize("project", [Language.CLOJURE], indirect=True) + @pytest.mark.parametrize("project", [LanguageServerId.CLOJURE], indirect=True) def test_retrieve_content_around_line(self, project: Project): """Test retrieving content around specific lines""" # Test retrieving content around the greet function definition (line 2) @@ -209,7 +209,7 @@ class TestProjectBasics: content_str = result.to_display_string() assert "multiply" in content_str, "Should contain multiply function" - @pytest.mark.parametrize("project", [Language.CLOJURE], indirect=True) + @pytest.mark.parametrize("project", [LanguageServerId.CLOJURE], indirect=True) def test_search_files_for_pattern(self, project: Project) -> None: result = project.search_project_files_for_pattern("defn.*greet") @@ -225,7 +225,7 @@ class TestProjectBasics: 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) + @pytest.mark.parametrize("language_server", [LanguageServerId.CLOJURE], indirect=True) def test_bare_symbol_names(self, language_server) -> None: all_symbols = request_all_symbols(language_server) malformed_symbols = [] diff --git a/test/solidlsp/clojure/test_clojure_diagnostics.py b/test/solidlsp/clojure/test_clojure_diagnostics.py index a7bff96b..15d62497 100644 --- a/test/solidlsp/clojure/test_clojure_diagnostics.py +++ b/test/solidlsp/clojure/test_clojure_diagnostics.py @@ -3,13 +3,13 @@ import os import pytest from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from test.solidlsp.util.diagnostics import assert_file_diagnostics @pytest.mark.clojure class TestClojureDiagnostics: - @pytest.mark.parametrize("language_server", [Language.CLOJURE], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.CLOJURE], indirect=True) def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None: assert_file_diagnostics( language_server, diff --git a/test/solidlsp/clojure/test_clojure_indexing.py b/test/solidlsp/clojure/test_clojure_indexing.py index 93354990..da5121b0 100644 --- a/test/solidlsp/clojure/test_clojure_indexing.py +++ b/test/solidlsp/clojure/test_clojure_indexing.py @@ -19,8 +19,8 @@ import pytest from serena.util.text_utils import find_text_coordinates from solidlsp.ls import SolidLanguageServer -from solidlsp.ls_config import Language -from test.conftest import language_tests_enabled +from solidlsp.ls_config import LanguageServerId +from test.conftest import language_server_tests_enabled from test.solidlsp.conftest import read_repo_file from . import CORE_PATH, TEST_APP_PATH @@ -29,7 +29,7 @@ EXTRA_PATH = str(TEST_APP_PATH / "extra.clj") SUBMODULE_CONSUMER_PATH = str(Path("sub_module") / "src" / "sub_module_app" / "consumer.clj") -@pytest.mark.skipif(not language_tests_enabled(Language.CLOJURE), reason="Clojure tests are disabled") +@pytest.mark.skipif(not language_server_tests_enabled(LanguageServerId.CLOJURE), reason="Clojure tests are disabled") @pytest.mark.clojure class TestClojureProjectIndexing: """Covers the "indexing leaks through results" bug for clojure-lsp. @@ -41,7 +41,7 @@ class TestClojureProjectIndexing: indexing of those calls. """ - @pytest.mark.parametrize("language_server", [Language.CLOJURE], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.CLOJURE], indirect=True) def test_request_references_includes_unopened_file(self, language_server: SolidLanguageServer) -> None: # locate the definition of `multiply` in core.clj without hardcoding coords core_content = read_repo_file(language_server, CORE_PATH) @@ -65,7 +65,7 @@ class TestClojureProjectIndexing: f"Expected at least 2 references in extra.clj (double-product and triple-product), got {len(extra_refs)}: {extra_refs}" ) - @pytest.mark.parametrize("language_server", [Language.CLOJURE], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.CLOJURE], indirect=True) def test_request_references_includes_unopened_sibling_module_file(self, language_server: SolidLanguageServer) -> None: """Mirrors the real-world penpot bug repro: ``multiply`` is defined in one module (root ``src/``) and consumed from a sibling module that has its @@ -92,7 +92,7 @@ class TestClojureProjectIndexing: "get_symbols_overview, so reference search returns silently incomplete results." ) - @pytest.mark.parametrize("language_server", [Language.CLOJURE], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.CLOJURE], indirect=True) def test_request_referencing_symbols_includes_unopened_file(self, language_server: SolidLanguageServer) -> None: core_content = read_repo_file(language_server, CORE_PATH) coords = find_text_coordinates(core_content, r"\(defn (multiply)\b", require_unique=True) diff --git a/test/solidlsp/conftest.py b/test/solidlsp/conftest.py index b74a246c..1777668d 100644 --- a/test/solidlsp/conftest.py +++ b/test/solidlsp/conftest.py @@ -1,14 +1,14 @@ from pathlib import Path from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from solidlsp.ls_types import SymbolKind, UnifiedSymbolInformation PYTHON_BACKEND_LANGUAGES = [ - Language.PYTHON, - Language.PYTHON_TY, - Language.PYTHON_PYREFLY, - Language.PYTHON_BASEDPYRIGHT, + LanguageServerId.PYTHON, + LanguageServerId.PYTHON_TY, + LanguageServerId.PYTHON_PYREFLY, + LanguageServerId.PYTHON_BASEDPYRIGHT, ] diff --git a/test/solidlsp/cpp/test_ccls_languages.py b/test/solidlsp/cpp/test_ccls_languages.py index 70cfac6a..c4839c9f 100644 --- a/test/solidlsp/cpp/test_ccls_languages.py +++ b/test/solidlsp/cpp/test_ccls_languages.py @@ -2,7 +2,7 @@ import os import pytest -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from test.conftest import start_ls_context @@ -16,7 +16,7 @@ class TestCCLSLanguages: ], ) def test_get_document_symbols(self, lang: str, unit: str, names: set[str]) -> None: - with start_ls_context(Language.CPP) as ccls: + with start_ls_context(LanguageServerId.CPP) as ccls: path = os.path.join(lang, unit) symbols = ccls.request_document_symbols(path).get_all_symbols_and_roots() symbols = symbols[0] if symbols and isinstance(symbols[0], list) else symbols diff --git a/test/solidlsp/cpp/test_clangd_languages.py b/test/solidlsp/cpp/test_clangd_languages.py index 8bf3a30f..69a52297 100644 --- a/test/solidlsp/cpp/test_clangd_languages.py +++ b/test/solidlsp/cpp/test_clangd_languages.py @@ -2,7 +2,7 @@ import os import pytest -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from test.conftest import start_ls_context @@ -22,7 +22,7 @@ class TestClangdLanguages: ], ) def test_get_document_symbols(self, lang: str, unit: str, names: set[str]) -> None: - with start_ls_context(Language.CPP) as clangd: + with start_ls_context(LanguageServerId.CPP) as clangd: path = os.path.join(lang, unit) symbols = clangd.request_document_symbols(path).get_all_symbols_and_roots() symbols = symbols[0] if symbols and isinstance(symbols[0], list) else symbols diff --git a/test/solidlsp/cpp/test_cpp_basic.py b/test/solidlsp/cpp/test_cpp_basic.py index 749efcac..6e73e8dc 100644 --- a/test/solidlsp/cpp/test_cpp_basic.py +++ b/test/solidlsp/cpp/test_cpp_basic.py @@ -14,18 +14,18 @@ from pathlib import Path import pytest from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from solidlsp.ls_utils import SymbolUtils -from test.conftest import get_repo_path, language_tests_enabled, start_ls_context +from test.conftest import get_repo_path, language_server_tests_enabled, start_ls_context from test.solidlsp.conftest import format_symbol_for_assert, has_malformed_name, request_all_symbols -_cpp_servers: list[Language] = [Language.CPP] -if language_tests_enabled(Language.CPP_CCLS): - _cpp_servers.append(Language.CPP_CCLS) +_cpp_servers: list[LanguageServerId] = [LanguageServerId.CPP] +if language_server_tests_enabled(LanguageServerId.CPP_CCLS): + _cpp_servers.append(LanguageServerId.CPP_CCLS) -@pytest.mark.parametrize("language", [Language.CPP, Language.CPP_CCLS]) -def test_source_fn_matcher_includes_ino(language: Language) -> None: +@pytest.mark.parametrize("language", [LanguageServerId.CPP, LanguageServerId.CPP_CCLS]) +def test_source_fn_matcher_includes_ino(language: LanguageServerId) -> None: """Arduino .ino sketches are C++ and must route to the C++ language server. This is a pure matcher check; it needs no running language server. @@ -172,7 +172,7 @@ int use_add() { @pytest.mark.cpp class TestCppDocumentSymbolCache: def _copy_cpp_fixture(self, tmp_path: Path) -> Path: - fixture_path = get_repo_path(Language.CPP) + fixture_path = get_repo_path(LanguageServerId.CPP) target_path = tmp_path / "test_repo" shutil.copytree(fixture_path, target_path) return target_path @@ -180,7 +180,7 @@ class TestCppDocumentSymbolCache: def test_cache_invalidates_when_clangd_context_changes(self, tmp_path: Path) -> None: repo_path = self._copy_cpp_fixture(tmp_path) ls_settings_alt = { - Language.CPP: { + LanguageServerId.CPP: { "compile_commands_dir": ".serena-alt", } } @@ -201,7 +201,7 @@ class TestCppDocumentSymbolCache: assert ls._raw_document_symbols_cache_is_modified assert ls._document_symbols_cache_is_modified - with start_ls_context(Language.CPP, repo_path=str(repo_path), solidlsp_dir=tmp_path) as ls_default: + with start_ls_context(LanguageServerId.CPP, repo_path=str(repo_path), solidlsp_dir=tmp_path) as ls_default: _ = ls_default.request_document_symbols(main_cpp) default_raw_cache_version = ls_default._raw_document_symbols_cache_version() @@ -212,7 +212,7 @@ class TestCppDocumentSymbolCache: cache_files = [p for p in cache_dir.rglob("*") if p.is_file()] assert cache_files, f"Expected SolidLSP to create cache artifacts under {cache_dir}" - with start_ls_context(Language.CPP, repo_path=str(repo_path), solidlsp_dir=tmp_path) as ls_default_again: + with start_ls_context(LanguageServerId.CPP, repo_path=str(repo_path), solidlsp_dir=tmp_path) as ls_default_again: assert ls_default_again.cache_dir == cache_dir _assert_caches_loaded_and_clean(ls_default_again) _ = ls_default_again.request_document_symbols(main_cpp) @@ -220,7 +220,7 @@ class TestCppDocumentSymbolCache: assert not ls_default_again._document_symbols_cache_is_modified with start_ls_context( - Language.CPP, + LanguageServerId.CPP, repo_path=str(repo_path), ls_specific_settings=ls_settings_alt, solidlsp_dir=tmp_path, diff --git a/test/solidlsp/cpp/test_cpp_diagnostics.py b/test/solidlsp/cpp/test_cpp_diagnostics.py index 20a58368..0f09f2af 100644 --- a/test/solidlsp/cpp/test_cpp_diagnostics.py +++ b/test/solidlsp/cpp/test_cpp_diagnostics.py @@ -1,13 +1,13 @@ import pytest from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from test.solidlsp.util.diagnostics import assert_file_diagnostics @pytest.mark.cpp class TestCppDiagnostics: - @pytest.mark.parametrize("language_server", [Language.CPP], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.CPP], indirect=True) def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None: assert_file_diagnostics( language_server, diff --git a/test/solidlsp/cpp/test_cpp_unreal.py b/test/solidlsp/cpp/test_cpp_unreal.py index 540becd0..888f25cd 100644 --- a/test/solidlsp/cpp/test_cpp_unreal.py +++ b/test/solidlsp/cpp/test_cpp_unreal.py @@ -23,12 +23,12 @@ from collections.abc import Iterator import pytest from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from solidlsp.ls_utils import SymbolUtils from test.conftest import find_identifier_position, get_repo_path, start_ls_context from test.solidlsp.conftest import document_symbol_names, find_document_symbol -UE_REPO_PATH = get_repo_path(Language.CPP).parent / "ue_test_repo" +UE_REPO_PATH = get_repo_path(LanguageServerId.CPP).parent / "ue_test_repo" ABILITY_COMPONENT_H = os.path.join("Source", "TestGame", "AbilityComponent.h") ABILITY_ACTOR_H = os.path.join("Source", "TestGame", "AbilityActor.h") ABILITY_ACTOR_CPP = os.path.join("Source", "TestGame", "AbilityActor.cpp") @@ -37,7 +37,7 @@ ABILITY_ACTOR_CPP = os.path.join("Source", "TestGame", "AbilityActor.cpp") @pytest.fixture(scope="module") def language_server() -> Iterator[SolidLanguageServer]: """Clangd over ue_test_repo; overrides the shared fixture for this module.""" - with start_ls_context(Language.CPP, repo_path=str(UE_REPO_PATH)) as ls: + with start_ls_context(LanguageServerId.CPP, repo_path=str(UE_REPO_PATH)) as ls: yield ls diff --git a/test/solidlsp/crystal/test_crystal_basic.py b/test/solidlsp/crystal/test_crystal_basic.py index 7af66129..ae5d618d 100644 --- a/test/solidlsp/crystal/test_crystal_basic.py +++ b/test/solidlsp/crystal/test_crystal_basic.py @@ -14,25 +14,27 @@ import os import pytest from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language -from test.conftest import language_tests_enabled +from solidlsp.ls_config import LanguageServerId +from test.conftest import language_server_tests_enabled from test.solidlsp.conftest import format_symbol_for_assert, has_malformed_name, request_all_symbols pytestmark = [ pytest.mark.crystal, - pytest.mark.skipif(not language_tests_enabled(Language.CRYSTAL), reason="Crystal tests are disabled (crystalline not available)"), + pytest.mark.skipif( + not language_server_tests_enabled(LanguageServerId.CRYSTAL), reason="Crystal tests are disabled (crystalline not available)" + ), ] class TestCrystalDocumentSymbols: """Test document symbol retrieval, which works reliably in Crystalline.""" - @pytest.mark.parametrize("language_server", [Language.CRYSTAL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.CRYSTAL], indirect=True) def test_ls_is_running(self, language_server: SolidLanguageServer) -> None: """Test that the language server starts successfully.""" assert language_server.is_running() - @pytest.mark.parametrize("language_server", [Language.CRYSTAL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.CRYSTAL], indirect=True) def test_document_symbols_main(self, language_server: SolidLanguageServer) -> None: """Test that document symbols are returned for the main file.""" file_path = os.path.join("src", "main.cr") @@ -43,7 +45,7 @@ class TestCrystalDocumentSymbols: assert "Calculator" in symbol_names, f"Calculator not found in symbols. Found: {symbol_names}" assert "User" in symbol_names, f"User not found in symbols. Found: {symbol_names}" - @pytest.mark.parametrize("language_server", [Language.CRYSTAL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.CRYSTAL], indirect=True) def test_document_symbols_utils(self, language_server: SolidLanguageServer) -> None: """Test that document symbols are returned for the utils file.""" file_path = os.path.join("src", "utils.cr") @@ -53,7 +55,7 @@ class TestCrystalDocumentSymbols: symbol_names = [s.get("name") for s in all_symbols if s.get("name")] assert "Utils" in symbol_names, f"Utils not found in symbols. Found: {symbol_names}" - @pytest.mark.parametrize("language_server", [Language.CRYSTAL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.CRYSTAL], indirect=True) def test_find_symbol(self, language_server: SolidLanguageServer) -> None: """Test that the full symbol tree contains expected symbols.""" from solidlsp.ls_utils import SymbolUtils @@ -63,7 +65,7 @@ class TestCrystalDocumentSymbols: assert SymbolUtils.symbol_tree_contains_name(symbols, "User"), "User not found in symbol tree" assert SymbolUtils.symbol_tree_contains_name(symbols, "Utils"), "Utils not found in symbol tree" - @pytest.mark.parametrize("language_server", [Language.CRYSTAL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.CRYSTAL], indirect=True) def test_bare_symbol_names(self, language_server: SolidLanguageServer) -> None: """Test that symbol names do not contain unexpected formatting characters.""" all_symbols = request_all_symbols(language_server) @@ -86,7 +88,7 @@ class TestCrystalDefinition: module-scoped ``language_server`` fixture ensures we get a fresh server. """ - @pytest.mark.parametrize("language_server", [Language.CRYSTAL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.CRYSTAL], indirect=True) def test_goto_definition_within_file(self, language_server: SolidLanguageServer) -> None: """Test goto_definition for a symbol defined within the same file.""" file_path = os.path.join("src", "main.cr") diff --git a/test/solidlsp/crystal/test_crystal_diagnostics.py b/test/solidlsp/crystal/test_crystal_diagnostics.py index b593b147..53313bca 100644 --- a/test/solidlsp/crystal/test_crystal_diagnostics.py +++ b/test/solidlsp/crystal/test_crystal_diagnostics.py @@ -1,18 +1,20 @@ import pytest from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language -from test.conftest import language_tests_enabled +from solidlsp.ls_config import LanguageServerId +from test.conftest import language_server_tests_enabled from test.solidlsp.util.diagnostics import assert_file_diagnostics pytestmark = [ pytest.mark.crystal, - pytest.mark.skipif(not language_tests_enabled(Language.CRYSTAL), reason="Crystal tests are disabled (crystalline not available)"), + pytest.mark.skipif( + not language_server_tests_enabled(LanguageServerId.CRYSTAL), reason="Crystal tests are disabled (crystalline not available)" + ), ] class TestCrystalDiagnostics: - @pytest.mark.parametrize("language_server", [Language.CRYSTAL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.CRYSTAL], indirect=True) def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None: assert_file_diagnostics( language_server, diff --git a/test/solidlsp/csharp/test_csharp_basic.py b/test/solidlsp/csharp/test_csharp_basic.py index 932f73d3..5f0a0107 100644 --- a/test/solidlsp/csharp/test_csharp_basic.py +++ b/test/solidlsp/csharp/test_csharp_basic.py @@ -10,16 +10,16 @@ from solidlsp.language_servers.csharp_language_server import ( breadth_first_file_scan, find_solution_or_project_file, ) -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from solidlsp.ls_types import SymbolKind from solidlsp.ls_utils import SymbolUtils -from test.conftest import find_identifier_position, get_repo_path, language_has_verified_implementation_support +from test.conftest import find_identifier_position, get_repo_path, ls_has_verified_implementation_support from test.solidlsp.conftest import format_symbol_for_assert, has_malformed_name, request_all_symbols @pytest.mark.csharp class TestCSharpLanguageServer: - @pytest.mark.parametrize("language_server", [Language.CSHARP], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.CSHARP], indirect=True) def test_find_symbol(self, language_server: SolidLanguageServer) -> None: """Test finding symbols in the full symbol tree.""" symbols = language_server.request_full_symbol_tree() @@ -27,7 +27,7 @@ class TestCSharpLanguageServer: assert SymbolUtils.symbol_tree_contains_name(symbols, "Calculator"), "Calculator class not found in symbol tree" assert SymbolUtils.symbol_tree_contains_name(symbols, "Add"), "Add method not found in symbol tree" - @pytest.mark.parametrize("language_server", [Language.CSHARP], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.CSHARP], indirect=True) def test_get_document_symbols(self, language_server: SolidLanguageServer) -> None: """Test getting document symbols from a C# file.""" file_path = os.path.join("Program.cs") @@ -45,7 +45,7 @@ class TestCSharpLanguageServer: assert "Program" in class_names assert "Calculator" in class_names - @pytest.mark.parametrize("language_server", [Language.CSHARP], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.CSHARP], indirect=True) def test_find_referencing_symbols(self, language_server: SolidLanguageServer) -> None: """Test finding references using symbol selection range.""" file_path = os.path.join("Program.cs") @@ -65,7 +65,7 @@ class TestCSharpLanguageServer: "Program.cs should reference Add method (tried all positions in selectionRange)" ) - @pytest.mark.parametrize("language_server", [Language.CSHARP], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.CSHARP], indirect=True) def test_nested_namespace_symbols(self, language_server: SolidLanguageServer) -> None: """Test getting symbols from nested namespace.""" file_path = os.path.join("Models", "Person.cs") @@ -89,7 +89,7 @@ class TestCSharpLanguageServer: assert "ToString" in symbol_names, "ToString method not found" assert "IsAdult" in symbol_names, "IsAdult method not found" - @pytest.mark.parametrize("language_server", [Language.CSHARP], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.CSHARP], indirect=True) def test_find_referencing_symbols_across_files(self, language_server: SolidLanguageServer) -> None: """Test finding references to Calculator.Subtract method across files.""" # First, find the Subtract method in Program.cs @@ -128,7 +128,7 @@ class TestCSharpLanguageServer: refs_second_call = language_server.request_references(file_path, sel_start["line"], sel_start["character"] + 1) assert refs_second_call == refs, "Second call to request_references should return the same results" - @pytest.mark.parametrize("language_server", [Language.CSHARP], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.CSHARP], indirect=True) def test_hover_includes_type_information(self, language_server: SolidLanguageServer) -> None: """Test that hover information is available and includes type information.""" file_path = os.path.join("Models", "Person.cs") @@ -172,11 +172,11 @@ class TestCSharpLanguageServer: assert "bool" in method_hover_text, f"Hover should include 'bool' return type, got: {method_hover_text}" assert "IsAdult" in method_hover_text, f"Hover should include 'IsAdult' method name, got: {method_hover_text}" - if language_has_verified_implementation_support(Language.CSHARP): + if ls_has_verified_implementation_support(LanguageServerId.CSHARP): - @pytest.mark.parametrize("language_server", [Language.CSHARP], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.CSHARP], indirect=True) def test_find_implementations(self, language_server: SolidLanguageServer) -> None: - repo_path = get_repo_path(Language.CSHARP) + repo_path = get_repo_path(LanguageServerId.CSHARP) pos = find_identifier_position(repo_path / "Services" / "IGreeter.cs", "FormatGreeting") assert pos is not None, "Could not find IGreeter.FormatGreeting in fixture" @@ -186,9 +186,9 @@ class TestCSharpLanguageServer: f"Expected ConsoleGreeter.FormatGreeting in implementations, got: {implementations}" ) - @pytest.mark.parametrize("language_server", [Language.CSHARP], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.CSHARP], indirect=True) def test_request_implementing_symbols(self, language_server: SolidLanguageServer) -> None: - repo_path = get_repo_path(Language.CSHARP) + repo_path = get_repo_path(LanguageServerId.CSHARP) pos = find_identifier_position(repo_path / "Services" / "IGreeter.cs", "FormatGreeting") assert pos is not None, "Could not find IGreeter.FormatGreeting in fixture" @@ -327,7 +327,7 @@ class TestCSharpSolutionProjectOpening: # Verify the file actually exists assert os.path.exists(result) - @pytest.mark.parametrize("language_server", [Language.CSHARP], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.CSHARP], indirect=True) def test_bare_symbol_names(self, language_server) -> None: all_symbols = request_all_symbols(language_server) malformed_symbols = [] diff --git a/test/solidlsp/csharp/test_csharp_diagnostics.py b/test/solidlsp/csharp/test_csharp_diagnostics.py index de32fd1d..7e9b9543 100644 --- a/test/solidlsp/csharp/test_csharp_diagnostics.py +++ b/test/solidlsp/csharp/test_csharp_diagnostics.py @@ -1,13 +1,13 @@ import pytest from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from test.solidlsp.util.diagnostics import assert_file_diagnostics @pytest.mark.csharp class TestCsharpDiagnostics: - @pytest.mark.parametrize("language_server", [Language.CSHARP], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.CSHARP], indirect=True) def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None: assert_file_diagnostics( language_server, diff --git a/test/solidlsp/cue/test_cue_basic.py b/test/solidlsp/cue/test_cue_basic.py index f2a580b0..7f2c1f78 100644 --- a/test/solidlsp/cue/test_cue_basic.py +++ b/test/solidlsp/cue/test_cue_basic.py @@ -5,7 +5,7 @@ from pathlib import Path import pytest from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from solidlsp.ls_utils import SymbolUtils from test.solidlsp.conftest import format_symbol_for_assert, has_malformed_name, request_all_symbols @@ -27,14 +27,14 @@ class TestCueLanguageServer: ``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) + @pytest.mark.parametrize("language_server", [LanguageServerId.CUE], indirect=True) + @pytest.mark.parametrize("repo_path", [LanguageServerId.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) + @pytest.mark.parametrize("language_server", [LanguageServerId.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 @@ -54,7 +54,7 @@ class TestCueLanguageServer: # 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) + @pytest.mark.parametrize("language_server", [LanguageServerId.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() @@ -71,8 +71,8 @@ class TestCueLanguageServer: ): 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) + @pytest.mark.parametrize("language_server", [LanguageServerId.CUE], indirect=True) + @pytest.mark.parametrize("repo_path", [LanguageServerId.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 & {" @@ -85,8 +85,8 @@ class TestCueLanguageServer: 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) + @pytest.mark.parametrize("language_server", [LanguageServerId.CUE], indirect=True) + @pytest.mark.parametrize("repo_path", [LanguageServerId.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") @@ -103,8 +103,8 @@ class TestCueLanguageServer: 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) + @pytest.mark.parametrize("language_server", [LanguageServerId.CUE], indirect=True) + @pytest.mark.parametrize("repo_path", [LanguageServerId.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") @@ -117,8 +117,8 @@ class TestCueLanguageServer: # 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) + @pytest.mark.parametrize("language_server", [LanguageServerId.CUE], indirect=True) + @pytest.mark.parametrize("repo_path", [LanguageServerId.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") @@ -130,7 +130,7 @@ class TestCueLanguageServer: # 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) + @pytest.mark.parametrize("language_server", [LanguageServerId.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 diff --git a/test/solidlsp/dart/test_dart_basic.py b/test/solidlsp/dart/test_dart_basic.py index 7dab1fe9..96f93b7e 100644 --- a/test/solidlsp/dart/test_dart_basic.py +++ b/test/solidlsp/dart/test_dart_basic.py @@ -5,7 +5,7 @@ import pytest from serena.util.text_utils import find_text_coordinates from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from solidlsp.ls_types import SymbolKind from solidlsp.ls_utils import SymbolUtils from test.solidlsp.conftest import format_symbol_for_assert, has_malformed_name, request_all_symbols @@ -13,16 +13,16 @@ from test.solidlsp.conftest import format_symbol_for_assert, has_malformed_name, @pytest.mark.dart class TestDartLanguageServer: - @pytest.mark.parametrize("language_server", [Language.DART], indirect=True) - @pytest.mark.parametrize("repo_path", [Language.DART], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.DART], indirect=True) + @pytest.mark.parametrize("repo_path", [LanguageServerId.DART], indirect=True) def test_ls_is_running(self, language_server: SolidLanguageServer, repo_path: Path) -> None: """Test that the language server starts and stops successfully.""" # The fixture already handles start and stop assert language_server.is_running() assert Path(language_server.language_server.repository_root_path).resolve() == repo_path.resolve() - @pytest.mark.parametrize("language_server", [Language.DART], indirect=True) - @pytest.mark.parametrize("repo_path", [Language.DART], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.DART], indirect=True) + @pytest.mark.parametrize("repo_path", [LanguageServerId.DART], indirect=True) def test_find_definition_within_file(self, language_server: SolidLanguageServer, repo_path: Path) -> None: """Test finding definition of a method within the same file.""" # In lib/main.dart: @@ -43,8 +43,8 @@ class TestDartLanguageServer: # But language server may return different positions assert definition_location["range"]["start"]["line"] >= 0 - @pytest.mark.parametrize("language_server", [Language.DART], indirect=True) - @pytest.mark.parametrize("repo_path", [Language.DART], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.DART], indirect=True) + @pytest.mark.parametrize("repo_path", [LanguageServerId.DART], indirect=True) def test_find_definition_across_files(self, language_server: SolidLanguageServer, repo_path: Path) -> None: """Test finding definition across different files.""" # Test finding definition of MathHelper class which is in helper.dart @@ -65,8 +65,8 @@ class TestDartLanguageServer: assert definition_location["uri"].endswith("helper.dart") assert definition_location["range"]["start"]["line"] >= 0 - @pytest.mark.parametrize("language_server", [Language.DART], indirect=True) - @pytest.mark.parametrize("repo_path", [Language.DART], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.DART], indirect=True) + @pytest.mark.parametrize("repo_path", [LanguageServerId.DART], indirect=True) def test_find_definition_class_method(self, language_server: SolidLanguageServer, repo_path: Path) -> None: """Test finding definition of a class method.""" # In lib/main.dart: @@ -86,8 +86,8 @@ class TestDartLanguageServer: # Definition of power method should be around line 13 (0-indexed) assert 12 <= definition_location["range"]["start"]["line"] <= 16 - @pytest.mark.parametrize("language_server", [Language.DART], indirect=True) - @pytest.mark.parametrize("repo_path", [Language.DART], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.DART], indirect=True) + @pytest.mark.parametrize("repo_path", [LanguageServerId.DART], indirect=True) def test_find_references_within_file(self, language_server: SolidLanguageServer, repo_path: Path) -> None: """Test finding references to a method within the same file.""" main_dart_path = str(repo_path / "lib" / "main.dart") @@ -105,8 +105,8 @@ class TestDartLanguageServer: main_dart_references = [ref for ref in references if ref["uri"].endswith("main.dart")] assert len(main_dart_references) >= 1 - @pytest.mark.parametrize("language_server", [Language.DART], indirect=True) - @pytest.mark.parametrize("repo_path", [Language.DART], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.DART], indirect=True) + @pytest.mark.parametrize("repo_path", [LanguageServerId.DART], indirect=True) def test_find_references_across_files(self, language_server: SolidLanguageServer, repo_path: Path) -> None: """Test finding references across different files.""" helper_dart_path = str(repo_path / "lib" / "helper.dart") @@ -121,8 +121,8 @@ class TestDartLanguageServer: main_dart_references = [ref for ref in references if ref["uri"].endswith("main.dart")] assert len(main_dart_references) >= 1 - @pytest.mark.parametrize("language_server", [Language.DART], indirect=True) - @pytest.mark.parametrize("repo_path", [Language.DART], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.DART], indirect=True) + @pytest.mark.parametrize("repo_path", [LanguageServerId.DART], indirect=True) def test_find_definition_constructor(self, language_server: SolidLanguageServer, repo_path: Path) -> None: """Test finding definition of a constructor call.""" main_dart_path = str(repo_path / "lib" / "main.dart") @@ -139,8 +139,8 @@ class TestDartLanguageServer: # Definition of Calculator class should be around line 3 (0-indexed) assert 3 <= definition_location["range"]["start"]["line"] <= 7 - @pytest.mark.parametrize("language_server", [Language.DART], indirect=True) - @pytest.mark.parametrize("repo_path", [Language.DART], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.DART], indirect=True) + @pytest.mark.parametrize("repo_path", [LanguageServerId.DART], indirect=True) def test_find_definition_import(self, language_server: SolidLanguageServer, repo_path: Path) -> None: """Test finding definition through imports.""" models_dart_path = str(repo_path / "lib" / "models.dart") @@ -159,7 +159,7 @@ class TestDartLanguageServer: # This is acceptable behavior - the important thing is that it found a definition assert "dart" in definition_location["uri"].lower() - @pytest.mark.parametrize("language_server", [Language.DART], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.DART], indirect=True) def test_find_symbol(self, language_server: SolidLanguageServer) -> None: """Test finding symbols in the full symbol tree.""" symbols = language_server.request_full_symbol_tree() @@ -169,7 +169,7 @@ class TestDartLanguageServer: assert SymbolUtils.symbol_tree_contains_name(symbols, "MathHelper"), "MathHelper class not found in symbol tree" assert SymbolUtils.symbol_tree_contains_name(symbols, "User"), "User class not found in symbol tree" - @pytest.mark.parametrize("language_server", [Language.DART], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.DART], indirect=True) def test_find_referencing_symbols(self, language_server: SolidLanguageServer) -> None: """Test finding references using symbol selection range.""" file_path = os.path.join("lib", "main.dart") @@ -202,7 +202,7 @@ class TestDartLanguageServer: "main.dart should reference add method (tried all positions in selectionRange)" ) - @pytest.mark.parametrize("language_server", [Language.DART], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.DART], indirect=True) def test_request_containing_symbol_method(self, language_server: SolidLanguageServer) -> None: """Test request_containing_symbol for a method.""" file_path = os.path.join("lib", "main.dart") @@ -217,7 +217,7 @@ class TestDartLanguageServer: body = containing_symbol["body"].get_text() assert "add" in body or "final result" in body - @pytest.mark.parametrize("language_server", [Language.DART], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.DART], indirect=True) def test_request_containing_symbol_class(self, language_server: SolidLanguageServer) -> None: """Test request_containing_symbol for a class.""" file_path = os.path.join("lib", "main.dart") @@ -229,7 +229,7 @@ class TestDartLanguageServer: assert containing_symbol["name"] == "Calculator" assert containing_symbol["kind"] == SymbolKind.Class - @pytest.mark.parametrize("language_server", [Language.DART], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.DART], indirect=True) def test_request_containing_symbol_nested(self, language_server: SolidLanguageServer) -> None: """Test request_containing_symbol with nested scopes.""" file_path = os.path.join("lib", "main.dart") @@ -241,7 +241,7 @@ class TestDartLanguageServer: assert containing_symbol["name"] == "add" assert containing_symbol["kind"] == SymbolKind.Method - @pytest.mark.parametrize("language_server", [Language.DART], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.DART], indirect=True) def test_request_defining_symbol_variable(self, language_server: SolidLanguageServer) -> None: """Test request_defining_symbol for a variable usage.""" file_path = os.path.join("lib", "main.dart") @@ -259,7 +259,7 @@ class TestDartLanguageServer: if defining_symbol.get("name") == "add": assert defining_symbol.get("kind") == SymbolKind.Method.value - @pytest.mark.parametrize("language_server", [Language.DART], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.DART], indirect=True) def test_request_defining_symbol_imported_class(self, language_server: SolidLanguageServer) -> None: """Test request_defining_symbol for an imported class/function.""" file_path = os.path.join("lib", "main.dart") @@ -272,7 +272,7 @@ class TestDartLanguageServer: # Could be Function or Method depending on language server interpretation assert defining_symbol.get("kind") in [SymbolKind.Function.value, SymbolKind.Method.value] - @pytest.mark.parametrize("language_server", [Language.DART], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.DART], indirect=True) def test_request_defining_symbol_class_method(self, language_server: SolidLanguageServer) -> None: """Test request_defining_symbol for a static class method.""" file_path = os.path.join("lib", "main.dart") @@ -284,7 +284,7 @@ class TestDartLanguageServer: assert defining_symbol.get("name") == "power" assert defining_symbol.get("kind") == SymbolKind.Method.value - @pytest.mark.parametrize("language_server", [Language.DART], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.DART], indirect=True) def test_request_document_symbols(self, language_server: SolidLanguageServer) -> None: """Test getting document symbols from a Dart file.""" file_path = os.path.join("lib", "main.dart") @@ -311,7 +311,7 @@ class TestDartLanguageServer: # This is acceptable behavior - the important thing is we found the class pass - @pytest.mark.parametrize("language_server", [Language.DART], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.DART], indirect=True) def test_request_referencing_symbols_comprehensive(self, language_server: SolidLanguageServer) -> None: """Test comprehensive referencing symbols functionality.""" file_path = os.path.join("lib", "main.dart") @@ -340,7 +340,7 @@ class TestDartLanguageServer: assert "start" in ref["range"] assert "end" in ref["range"] - @pytest.mark.parametrize("language_server", [Language.DART], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.DART], indirect=True) def test_cross_file_symbol_resolution(self, language_server: SolidLanguageServer) -> None: """Test symbol resolution across multiple files.""" helper_file_path = os.path.join("lib", "helper.dart") @@ -363,7 +363,7 @@ class TestDartLanguageServer: for ref in main_dart_refs: assert "range" in ref or "location" in ref - @pytest.mark.parametrize("language_server", [Language.DART], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.DART], indirect=True) def test_bare_symbol_names(self, language_server) -> None: all_symbols = request_all_symbols(language_server) malformed_symbols = [] @@ -376,7 +376,7 @@ class TestDartLanguageServer: pytrace=False, ) - @pytest.mark.parametrize("language_server", [Language.DART], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.DART], indirect=True) def test_symbol_body_contains_full_method(self, language_server: SolidLanguageServer) -> None: """Test that document symbols return the full method body range, not just the identifier. diff --git a/test/solidlsp/dart/test_dart_diagnostics.py b/test/solidlsp/dart/test_dart_diagnostics.py index ddc5e398..8626ecaf 100644 --- a/test/solidlsp/dart/test_dart_diagnostics.py +++ b/test/solidlsp/dart/test_dart_diagnostics.py @@ -1,13 +1,13 @@ import pytest from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from test.solidlsp.util.diagnostics import assert_file_diagnostics @pytest.mark.dart class TestDartDiagnostics: - @pytest.mark.parametrize("language_server", [Language.DART], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.DART], indirect=True) def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None: assert_file_diagnostics( language_server, diff --git a/test/solidlsp/elixir/test_elixir_basic.py b/test/solidlsp/elixir/test_elixir_basic.py index ac32edd5..8d51dc63 100644 --- a/test/solidlsp/elixir/test_elixir_basic.py +++ b/test/solidlsp/elixir/test_elixir_basic.py @@ -10,20 +10,23 @@ import os import pytest from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from solidlsp.ls_types import SymbolKind -from test.conftest import language_tests_enabled +from test.conftest import language_server_tests_enabled from test.solidlsp.conftest import format_symbol_for_assert, has_malformed_name, request_all_symbols from test.solidlsp.util.diagnostics import assert_file_diagnostics # These marks will be applied to all tests in this module -pytestmark = [pytest.mark.elixir, pytest.mark.skipif(not language_tests_enabled(Language.ELIXIR), reason="Elixir tests are disabled")] +pytestmark = [ + pytest.mark.elixir, + pytest.mark.skipif(not language_server_tests_enabled(LanguageServerId.ELIXIR), reason="Elixir tests are disabled"), +] class TestElixirBasic: """Basic Elixir language server functionality tests.""" - @pytest.mark.parametrize("language_server", [Language.ELIXIR], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ELIXIR], indirect=True) def test_request_references_function_definition(self, language_server: SolidLanguageServer): """Test finding references to a function definition.""" file_path = os.path.join("lib", "models.ex") @@ -52,7 +55,7 @@ class TestElixirBasic: found_definition = any(ref["uri"].endswith("models.ex") for ref in references) assert found_definition, "Should find the function definition" - @pytest.mark.parametrize("language_server", [Language.ELIXIR], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ELIXIR], indirect=True) def test_request_references_create_user_function(self, language_server: SolidLanguageServer): """Test finding references to create_user function.""" file_path = os.path.join("lib", "services.ex") @@ -77,7 +80,7 @@ class TestElixirBasic: assert references is not None assert len(references) > 0 - @pytest.mark.parametrize("language_server", [Language.ELIXIR], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ELIXIR], indirect=True) def test_request_referencing_symbols_function(self, language_server: SolidLanguageServer): """Test finding symbols that reference a specific function.""" file_path = os.path.join("lib", "models.ex") @@ -101,7 +104,7 @@ class TestElixirBasic: assert referencing_symbols is not None - @pytest.mark.parametrize("language_server", [Language.ELIXIR], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ELIXIR], indirect=True) def test_timeout_enumeration_bug(self, language_server: SolidLanguageServer): """Test that enumeration doesn't timeout (regression test).""" # This should complete without timing out @@ -113,7 +116,7 @@ class TestElixirBasic: symbols = language_server.request_document_symbols("lib/services.ex").get_all_symbols_and_roots() assert symbols is not None - @pytest.mark.parametrize("language_server", [Language.ELIXIR], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ELIXIR], indirect=True) def test_bare_symbol_names(self, language_server) -> None: all_symbols = request_all_symbols(language_server) malformed_symbols = [] @@ -139,7 +142,7 @@ class TestElixirBasic: pytrace=False, ) - @pytest.mark.parametrize("language_server", [Language.ELIXIR], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ELIXIR], indirect=True) def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None: assert_file_diagnostics( language_server, diff --git a/test/solidlsp/elixir/test_elixir_ignored_dirs.py b/test/solidlsp/elixir/test_elixir_ignored_dirs.py index 75f4870b..dd2305a8 100644 --- a/test/solidlsp/elixir/test_elixir_ignored_dirs.py +++ b/test/solidlsp/elixir/test_elixir_ignored_dirs.py @@ -5,11 +5,14 @@ from pathlib import Path import pytest from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language -from test.conftest import language_tests_enabled, start_ls_context +from solidlsp.ls_config import LanguageServerId +from test.conftest import language_server_tests_enabled, start_ls_context # These marks will be applied to all tests in this module -pytestmark = [pytest.mark.elixir, pytest.mark.skipif(not language_tests_enabled(Language.ELIXIR), reason="Elixir tests are disabled")] +pytestmark = [ + pytest.mark.elixir, + pytest.mark.skipif(not language_server_tests_enabled(LanguageServerId.ELIXIR), reason="Elixir tests are disabled"), +] # Skip slow tests in CI - they require multiple Expert instances which is too slow IN_CI = bool(os.environ.get("CI") or os.environ.get("GITHUB_ACTIONS")) @@ -26,7 +29,7 @@ def ls_with_ignored_dirs() -> Generator[SolidLanguageServer, None, None]: Uses session scope to avoid restarting Expert for each test. """ ignored_paths = ["scripts", "ignored_dir"] - with start_ls_context(language=Language.ELIXIR, ignored_paths=ignored_paths) as ls: + with start_ls_context(ls_id=LanguageServerId.ELIXIR, ignored_paths=ignored_paths) as ls: yield ls @@ -81,7 +84,7 @@ def test_find_references_ignores_dir(ls_with_ignored_dirs: SolidLanguageServer): @pytest.mark.slow @SKIP_SLOW_IN_CI -@pytest.mark.parametrize("repo_path", [Language.ELIXIR], indirect=True) +@pytest.mark.parametrize("repo_path", [LanguageServerId.ELIXIR], indirect=True) def test_refs_and_symbols_with_glob_patterns(repo_path: Path) -> None: """Tests that refs and symbols with glob patterns are ignored. @@ -89,7 +92,7 @@ def test_refs_and_symbols_with_glob_patterns(repo_path: Path) -> None: which adds ~60-90s startup time. """ ignored_paths = ["*cripts", "ignored_*"] # codespell:ignore cripts - with start_ls_context(language=Language.ELIXIR, repo_path=str(repo_path), ignored_paths=ignored_paths) as ls: + with start_ls_context(ls_id=LanguageServerId.ELIXIR, repo_path=str(repo_path), ignored_paths=ignored_paths) as ls: # Same as in the above tests root = ls.request_full_symbol_tree()[0] root_children = root["children"] @@ -121,7 +124,7 @@ def test_refs_and_symbols_with_glob_patterns(repo_path: Path) -> None: assert not any("ignored_dir" in ref["relativePath"] for ref in references), "ignored_dir should be ignored (glob)" -@pytest.mark.parametrize("language_server", [Language.ELIXIR], indirect=True) +@pytest.mark.parametrize("language_server", [LanguageServerId.ELIXIR], indirect=True) def test_default_ignored_directories(language_server: SolidLanguageServer): """Test that default Elixir directories are ignored.""" # Test that Elixir-specific directories are ignored by default @@ -142,7 +145,7 @@ def test_default_ignored_directories(language_server: SolidLanguageServer): reason="Expert 0.1.0 bug: document_symbols may return nil for some files (flaky)", raises=Exception, ) -@pytest.mark.parametrize("language_server", [Language.ELIXIR], indirect=True) +@pytest.mark.parametrize("language_server", [LanguageServerId.ELIXIR], indirect=True) def test_symbol_tree_excludes_build_dirs(language_server: SolidLanguageServer): """Test that symbol tree excludes build and dependency directories.""" symbol_tree = language_server.request_full_symbol_tree() diff --git a/test/solidlsp/elixir/test_elixir_integration.py b/test/solidlsp/elixir/test_elixir_integration.py index 1658993f..8637b7d6 100644 --- a/test/solidlsp/elixir/test_elixir_integration.py +++ b/test/solidlsp/elixir/test_elixir_integration.py @@ -12,11 +12,14 @@ import pytest from serena.project import Project from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language -from test.conftest import language_tests_enabled +from solidlsp.ls_config import LanguageServerId +from test.conftest import language_server_tests_enabled # These marks will be applied to all tests in this module -pytestmark = [pytest.mark.elixir, pytest.mark.skipif(not language_tests_enabled(Language.ELIXIR), reason="Elixir tests are disabled")] +pytestmark = [ + pytest.mark.elixir, + pytest.mark.skipif(not language_server_tests_enabled(LanguageServerId.ELIXIR), reason="Elixir tests are disabled"), +] class TestElixirIntegration: @@ -42,7 +45,7 @@ class TestElixirIntegration: assert (repo_path / "test" / "test_repo_test.exs").exists(), "test file should exist" assert (repo_path / "test" / "models_test.exs").exists(), "models test should exist" - @pytest.mark.parametrize("language_server", [Language.ELIXIR], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ELIXIR], indirect=True) def test_cross_file_symbol_resolution(self, language_server: SolidLanguageServer): """Test that symbols can be resolved across different files.""" # Test that User struct from models.ex can be found when referenced in services.ex @@ -67,7 +70,7 @@ class TestElixirIntegration: # Should point to models.ex assert "models.ex" in defining_symbol["location"]["uri"] - @pytest.mark.parametrize("language_server", [Language.ELIXIR], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ELIXIR], indirect=True) def test_module_hierarchy_understanding(self, language_server: SolidLanguageServer): """Test that the language server understands Elixir module hierarchy.""" models_file = os.path.join("lib", "models.ex") @@ -91,7 +94,7 @@ class TestElixirIntegration: def test_file_extension_matching(self): """Test that the Elixir language recognizes the correct file extensions.""" - language = Language.ELIXIR + language = LanguageServerId.ELIXIR matcher = language.get_source_fn_matcher() # Test Elixir file extensions @@ -110,7 +113,7 @@ class TestElixirIntegration: class TestElixirProject: - @pytest.mark.parametrize("project", [Language.ELIXIR], indirect=True) + @pytest.mark.parametrize("project", [LanguageServerId.ELIXIR], indirect=True) def test_comprehensive_symbol_search(self, project: Project): """Test comprehensive symbol search across the entire project.""" # Search for all function definitions @@ -138,7 +141,7 @@ class TestElixirProject: models_structs = [m for m in struct_matches if m.source_file_path and "models.ex" in m.source_file_path] assert len(models_structs) > 0, "Should find struct definitions in models.ex" - @pytest.mark.parametrize("project", [Language.ELIXIR], indirect=True) + @pytest.mark.parametrize("project", [LanguageServerId.ELIXIR], indirect=True) def test_protocol_and_implementation_understanding(self, project: Project): """Test that the language server understands Elixir protocols and implementations.""" # Search for protocol definitions diff --git a/test/solidlsp/elixir/test_elixir_symbol_retrieval.py b/test/solidlsp/elixir/test_elixir_symbol_retrieval.py index 219cfe15..45ce5aa4 100644 --- a/test/solidlsp/elixir/test_elixir_symbol_retrieval.py +++ b/test/solidlsp/elixir/test_elixir_symbol_retrieval.py @@ -12,12 +12,15 @@ import os import pytest from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from solidlsp.ls_types import SymbolKind -from test.conftest import language_tests_enabled +from test.conftest import language_server_tests_enabled # These marks will be applied to all tests in this module -pytestmark = [pytest.mark.elixir, pytest.mark.skipif(not language_tests_enabled(Language.ELIXIR), reason="Elixir tests are disabled")] +pytestmark = [ + pytest.mark.elixir, + pytest.mark.skipif(not language_server_tests_enabled(LanguageServerId.ELIXIR), reason="Elixir tests are disabled"), +] class TestElixirLanguageServerSymbols: @@ -26,7 +29,7 @@ class TestElixirLanguageServerSymbols: @pytest.mark.xfail( reason="Expert 0.1.0 bug: document_symbols returns nil for some files (FunctionClauseError in XPExpert.EngineApi.document_symbols/2)" ) - @pytest.mark.parametrize("language_server", [Language.ELIXIR], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ELIXIR], indirect=True) def test_request_containing_symbol_function(self, language_server: SolidLanguageServer) -> None: """Test request_containing_symbol for a function.""" # Test for a position inside the create_user function @@ -54,7 +57,7 @@ class TestElixirLanguageServerSymbols: if "body" in containing_symbol: assert "def create_user" in containing_symbol["body"].get_text() - @pytest.mark.parametrize("language_server", [Language.ELIXIR], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ELIXIR], indirect=True) def test_request_containing_symbol_module(self, language_server: SolidLanguageServer) -> None: """Test request_containing_symbol for a module.""" # Test for a position inside the UserService module but outside any function @@ -79,7 +82,7 @@ class TestElixirLanguageServerSymbols: assert "UserService" in containing_symbol["name"] assert containing_symbol["kind"] == SymbolKind.Module or containing_symbol["kind"] == SymbolKind.Class - @pytest.mark.parametrize("language_server", [Language.ELIXIR], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ELIXIR], indirect=True) def test_request_containing_symbol_nested(self, language_server: SolidLanguageServer) -> None: """Test request_containing_symbol with nested scopes.""" # Test for a position inside a function which is inside a module @@ -104,7 +107,7 @@ class TestElixirLanguageServerSymbols: expected_names = ["create_user", "UserService"] assert any(name in containing_symbol["name"] for name in expected_names) - @pytest.mark.parametrize("language_server", [Language.ELIXIR], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ELIXIR], indirect=True) def test_request_containing_symbol_none(self, language_server: SolidLanguageServer) -> None: """Test request_containing_symbol for a position with no containing symbol.""" # Test for a position outside any function/module (e.g., in module doc) @@ -116,7 +119,7 @@ class TestElixirLanguageServerSymbols: # This is acceptable behavior for module-level positions assert containing_symbol is None or containing_symbol == {} or "TestRepo.Services" in str(containing_symbol) - @pytest.mark.parametrize("language_server", [Language.ELIXIR], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ELIXIR], indirect=True) def test_request_referencing_symbols_struct(self, language_server: SolidLanguageServer) -> None: """Test request_referencing_symbols for a struct.""" # Test referencing symbols for User struct @@ -146,7 +149,7 @@ class TestElixirLanguageServerSymbols: # We expect some references from services.ex assert len(services_references) >= 0 # At least attempt to find references - @pytest.mark.parametrize("language_server", [Language.ELIXIR], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ELIXIR], indirect=True) def test_request_referencing_symbols_none(self, language_server: SolidLanguageServer) -> None: """Test request_referencing_symbols for a position with no symbol.""" file_path = os.path.join("lib", "services.ex") @@ -164,7 +167,7 @@ class TestElixirLanguageServerSymbols: @pytest.mark.xfail( reason="Expert 0.1.0 bug: definition request crashes (FunctionClauseError in XPExpert.Protocol.Conversions.to_elixir/2)" ) - @pytest.mark.parametrize("language_server", [Language.ELIXIR], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ELIXIR], indirect=True) def test_request_defining_symbol_function_call(self, language_server: SolidLanguageServer) -> None: """Test request_defining_symbol for a function call.""" # Find a place where User.new is called in services.ex @@ -191,7 +194,7 @@ class TestElixirLanguageServerSymbols: @pytest.mark.xfail( reason="Expert 0.1.0 bug: definition request crashes (FunctionClauseError in XPExpert.Protocol.Conversions.to_elixir/2)" ) - @pytest.mark.parametrize("language_server", [Language.ELIXIR], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ELIXIR], indirect=True) def test_request_defining_symbol_struct_usage(self, language_server: SolidLanguageServer) -> None: """Test request_defining_symbol for a struct usage.""" # Find a place where User struct is used in services.ex @@ -215,7 +218,7 @@ class TestElixirLanguageServerSymbols: @pytest.mark.xfail( reason="Expert 0.1.0 bug: definition request crashes (FunctionClauseError in XPExpert.Protocol.Conversions.to_elixir/2)" ) - @pytest.mark.parametrize("language_server", [Language.ELIXIR], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ELIXIR], indirect=True) def test_request_defining_symbol_none(self, language_server: SolidLanguageServer) -> None: """Test request_defining_symbol for a position with no symbol.""" # Test for a position with no symbol (e.g., whitespace or comment) @@ -226,7 +229,7 @@ class TestElixirLanguageServerSymbols: # Should return None or empty assert defining_symbol is None or defining_symbol == {} - @pytest.mark.parametrize("language_server", [Language.ELIXIR], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ELIXIR], indirect=True) def test_symbol_methods_integration(self, language_server: SolidLanguageServer) -> None: """Test integration between different symbol methods.""" file_path = os.path.join("lib", "models.ex") @@ -257,7 +260,7 @@ class TestElixirLanguageServerSymbols: assert isinstance(refs, list) @pytest.mark.xfail(reason="Flaky test, sometimes fails with an Expert-internal error") - @pytest.mark.parametrize("language_server", [Language.ELIXIR], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ELIXIR], indirect=True) def test_symbol_tree_structure(self, language_server: SolidLanguageServer) -> None: """Test that symbol tree structure is correctly built.""" symbol_tree = language_server.request_full_symbol_tree() @@ -283,7 +286,7 @@ class TestElixirLanguageServerSymbols: found_modules = [name for name in expected_modules if name in file_names] assert len(found_modules) > 0, f"Expected to find some modules from {expected_modules}, but got {file_names}" - @pytest.mark.parametrize("language_server", [Language.ELIXIR], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ELIXIR], indirect=True) def test_request_dir_overview(self, language_server: SolidLanguageServer) -> None: """Test request_dir_overview functionality.""" lib_overview = language_server.request_dir_overview("lib") @@ -321,7 +324,7 @@ class TestElixirLanguageServerSymbols: # found_terms = [term for term in expected_terms if term in overview_text] # assert len(found_terms) > 0, f"Expected to find some terms from {expected_terms} in overview" - @pytest.mark.parametrize("language_server", [Language.ELIXIR], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ELIXIR], indirect=True) def test_containing_symbol_of_module_attribute(self, language_server: SolidLanguageServer) -> None: """Test containing symbol for module attributes.""" file_path = os.path.join("lib", "models.ex") diff --git a/test/solidlsp/elm/test_elm_basic.py b/test/solidlsp/elm/test_elm_basic.py index a886ede9..7144091c 100644 --- a/test/solidlsp/elm/test_elm_basic.py +++ b/test/solidlsp/elm/test_elm_basic.py @@ -3,16 +3,16 @@ import os import pytest from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from solidlsp.ls_utils import SymbolUtils -from test.conftest import language_tests_enabled +from test.conftest import language_server_tests_enabled from test.solidlsp.conftest import format_symbol_for_assert, has_malformed_name, request_all_symbols -@pytest.mark.skipif(not language_tests_enabled(Language.ELM), reason="Elm tests are disabled (elm compiler not available)") +@pytest.mark.skipif(not language_server_tests_enabled(LanguageServerId.ELM), reason="Elm tests are disabled (elm compiler not available)") @pytest.mark.elm class TestElmLanguageServer: - @pytest.mark.parametrize("language_server", [Language.ELM], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ELM], indirect=True) def test_find_symbol(self, language_server: SolidLanguageServer) -> None: symbols = language_server.request_full_symbol_tree() assert SymbolUtils.symbol_tree_contains_name(symbols, "greet"), "greet function not found in symbol tree" @@ -20,7 +20,7 @@ class TestElmLanguageServer: assert SymbolUtils.symbol_tree_contains_name(symbols, "formatMessage"), "formatMessage function not found in symbol tree" assert SymbolUtils.symbol_tree_contains_name(symbols, "addNumbers"), "addNumbers function not found in symbol tree" - @pytest.mark.parametrize("language_server", [Language.ELM], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ELM], indirect=True) def test_find_references_within_file(self, language_server: SolidLanguageServer) -> None: file_path = os.path.join("Main.elm") symbols = language_server.request_document_symbols(file_path).get_all_symbols_and_roots() @@ -34,7 +34,7 @@ class TestElmLanguageServer: refs = language_server.request_references(file_path, sel_start["line"], sel_start["character"]) assert any("Main.elm" in ref.get("relativePath", "") for ref in refs), "Main.elm should reference greet function" - @pytest.mark.parametrize("language_server", [Language.ELM], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ELM], indirect=True) def test_find_references_across_files(self, language_server: SolidLanguageServer) -> None: # Test formatMessage function which is defined in Utils.elm and used in Main.elm utils_path = os.path.join("Utils.elm") @@ -56,7 +56,7 @@ class TestElmLanguageServer: # Verify that at least one reference is in Main.elm (where formatMessage is used) assert any("Main.elm" in ref.get("relativePath", "") for ref in refs), "Expected to find usage of formatMessage in Main.elm" - @pytest.mark.parametrize("language_server", [Language.ELM], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ELM], indirect=True) def test_bare_symbol_names(self, language_server) -> None: all_symbols = request_all_symbols(language_server) malformed_symbols = [] diff --git a/test/solidlsp/elm/test_elm_diagnostics.py b/test/solidlsp/elm/test_elm_diagnostics.py index 744201a2..64475880 100644 --- a/test/solidlsp/elm/test_elm_diagnostics.py +++ b/test/solidlsp/elm/test_elm_diagnostics.py @@ -3,14 +3,14 @@ import shutil import pytest from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId 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) + @pytest.mark.parametrize("language_server", [LanguageServerId.ELM], indirect=True) def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None: assert_file_diagnostics( language_server, diff --git a/test/solidlsp/erlang/test_erlang_basic.py b/test/solidlsp/erlang/test_erlang_basic.py index 491c71a7..66e284e0 100644 --- a/test/solidlsp/erlang/test_erlang_basic.py +++ b/test/solidlsp/erlang/test_erlang_basic.py @@ -8,24 +8,24 @@ like request_references using the test repository. import pytest from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language -from test.conftest import language_tests_enabled +from solidlsp.ls_config import LanguageServerId +from test.conftest import language_server_tests_enabled 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.erlang -@pytest.mark.skipif(not language_tests_enabled(Language.ERLANG), reason="Erlang tests are disabled") +@pytest.mark.skipif(not language_server_tests_enabled(LanguageServerId.ERLANG), reason="Erlang tests are disabled") class TestErlangLanguageServerBasics: """Test basic functionality of the Erlang language server.""" - @pytest.mark.parametrize("language_server", [Language.ERLANG], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ERLANG], indirect=True) def test_language_server_initialization(self, language_server: SolidLanguageServer) -> None: """Test that the Erlang language server initializes properly.""" assert language_server is not None - assert language_server.language == Language.ERLANG + assert language_server.ls_id == LanguageServerId.ERLANG - @pytest.mark.parametrize("language_server", [Language.ERLANG], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ERLANG], indirect=True) def test_document_symbols(self, language_server: SolidLanguageServer) -> None: """Test document symbols retrieval for Erlang files.""" try: @@ -43,7 +43,7 @@ class TestErlangLanguageServerBasics: else: raise - @pytest.mark.parametrize("language_server", [Language.ERLANG], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ERLANG], indirect=True) def test_bare_symbol_names(self, language_server) -> None: all_symbols = request_all_symbols(language_server) malformed_symbols = [] @@ -56,7 +56,7 @@ class TestErlangLanguageServerBasics: pytrace=False, ) - @pytest.mark.parametrize("language_server", [Language.ERLANG], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ERLANG], indirect=True) def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None: assert_file_diagnostics( language_server, diff --git a/test/solidlsp/erlang/test_erlang_ignored_dirs.py b/test/solidlsp/erlang/test_erlang_ignored_dirs.py index d6fdb0ab..38013a6d 100644 --- a/test/solidlsp/erlang/test_erlang_ignored_dirs.py +++ b/test/solidlsp/erlang/test_erlang_ignored_dirs.py @@ -4,13 +4,13 @@ from pathlib import Path import pytest from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language -from test.conftest import language_tests_enabled, start_ls_context +from solidlsp.ls_config import LanguageServerId +from test.conftest import language_server_tests_enabled, start_ls_context # These marks will be applied to all tests in this module pytestmark = [ pytest.mark.erlang, - pytest.mark.skipif(not language_tests_enabled(Language.ERLANG), reason="Erlang tests are disabled"), + pytest.mark.skipif(not language_server_tests_enabled(LanguageServerId.ERLANG), reason="Erlang tests are disabled"), ] @@ -18,13 +18,13 @@ pytestmark = [ def ls_with_ignored_dirs() -> Generator[SolidLanguageServer, None, None]: """Fixture to set up an LS for the erlang test repo with the 'ignored_dir' directory ignored.""" ignored_paths = ["_build", "ignored_dir"] - with start_ls_context(language=Language.ERLANG, ignored_paths=ignored_paths) as ls: + with start_ls_context(ls_id=LanguageServerId.ERLANG, ignored_paths=ignored_paths) as ls: yield ls @pytest.mark.timeout(60) # Add 60 second timeout @pytest.mark.xfail(reason="Known timeout issue on Ubuntu CI with Erlang LS server startup", strict=False) -@pytest.mark.parametrize("ls_with_ignored_dirs", [Language.ERLANG], indirect=True) +@pytest.mark.parametrize("ls_with_ignored_dirs", [LanguageServerId.ERLANG], indirect=True) def test_symbol_tree_ignores_dir(ls_with_ignored_dirs: SolidLanguageServer): """Tests that request_full_symbol_tree ignores the configured directory.""" root = ls_with_ignored_dirs.request_full_symbol_tree()[0] @@ -41,7 +41,7 @@ def test_symbol_tree_ignores_dir(ls_with_ignored_dirs: SolidLanguageServer): @pytest.mark.timeout(60) # Add 60 second timeout @pytest.mark.xfail(reason="Known timeout issue on Ubuntu CI with Erlang LS server startup", strict=False) -@pytest.mark.parametrize("ls_with_ignored_dirs", [Language.ERLANG], indirect=True) +@pytest.mark.parametrize("ls_with_ignored_dirs", [LanguageServerId.ERLANG], indirect=True) def test_find_references_ignores_dir(ls_with_ignored_dirs: SolidLanguageServer): """Tests that find_references ignores the configured directory.""" # Location of user record, which might be referenced in ignored_dir @@ -68,11 +68,11 @@ def test_find_references_ignores_dir(ls_with_ignored_dirs: SolidLanguageServer): @pytest.mark.timeout(60) # Add 60 second timeout @pytest.mark.xfail(reason="Known timeout issue on Ubuntu CI with Erlang LS server startup", strict=False) -@pytest.mark.parametrize("repo_path", [Language.ERLANG], indirect=True) +@pytest.mark.parametrize("repo_path", [LanguageServerId.ERLANG], indirect=True) def test_refs_and_symbols_with_glob_patterns(repo_path: Path) -> None: """Tests that refs and symbols with glob patterns are ignored.""" ignored_paths = ["_build*", "ignored_*", "*.tmp"] - with start_ls_context(language=Language.ERLANG, repo_path=str(repo_path), ignored_paths=ignored_paths) as ls: + with start_ls_context(ls_id=LanguageServerId.ERLANG, repo_path=str(repo_path), ignored_paths=ignored_paths) as ls: # Same as in the above tests root = ls.request_full_symbol_tree()[0] root_children = root["children"] @@ -105,7 +105,7 @@ def test_refs_and_symbols_with_glob_patterns(repo_path: Path) -> None: assert not any("ignored_dir" in ref["relativePath"] for ref in references), "ignored_dir should be ignored (glob)" -@pytest.mark.parametrize("language_server", [Language.ERLANG], indirect=True) +@pytest.mark.parametrize("language_server", [LanguageServerId.ERLANG], indirect=True) def test_default_ignored_directories(language_server: SolidLanguageServer): """Test that default Erlang directories are ignored.""" # Test that Erlang-specific directories are ignored by default @@ -123,7 +123,7 @@ def test_default_ignored_directories(language_server: SolidLanguageServer): assert not language_server.is_ignored_dirname("priv"), "priv should not be ignored" -@pytest.mark.parametrize("language_server", [Language.ERLANG], indirect=True) +@pytest.mark.parametrize("language_server", [LanguageServerId.ERLANG], indirect=True) def test_symbol_tree_excludes_build_dirs(language_server: SolidLanguageServer): """Test that symbol tree excludes build and dependency directories.""" symbol_tree = language_server.request_full_symbol_tree() @@ -143,7 +143,7 @@ def test_symbol_tree_excludes_build_dirs(language_server: SolidLanguageServer): assert len(found_important) > 0, f"Expected to find important directories: {important_dirs}, got: {children_names}" -@pytest.mark.parametrize("language_server", [Language.ERLANG], indirect=True) +@pytest.mark.parametrize("language_server", [LanguageServerId.ERLANG], indirect=True) def test_ignore_compiled_files(language_server: SolidLanguageServer): """Test that compiled Erlang files are ignored.""" # Test that beam files are ignored @@ -155,7 +155,7 @@ def test_ignore_compiled_files(language_server: SolidLanguageServer): assert not language_server.is_ignored_filename("records.hrl"), "Header files should not be ignored" -@pytest.mark.parametrize("language_server", [Language.ERLANG], indirect=True) +@pytest.mark.parametrize("language_server", [LanguageServerId.ERLANG], indirect=True) def test_rebar_directories_ignored(language_server: SolidLanguageServer): """Test that rebar-specific directories are ignored.""" # Test rebar3-specific directories @@ -168,7 +168,7 @@ def test_rebar_directories_ignored(language_server: SolidLanguageServer): assert not language_server.is_ignored_filename("rebar.lock"), "rebar.lock should not be ignored" -@pytest.mark.parametrize("ls_with_ignored_dirs", [Language.ERLANG], indirect=True) +@pytest.mark.parametrize("ls_with_ignored_dirs", [LanguageServerId.ERLANG], indirect=True) def test_document_symbols_ignores_dirs(ls_with_ignored_dirs: SolidLanguageServer): """Test that document symbols from ignored directories are not included.""" # Try to get symbols from a file in ignored directory (should not find it) @@ -183,7 +183,7 @@ def test_document_symbols_ignores_dirs(ls_with_ignored_dirs: SolidLanguageServer pass -@pytest.mark.parametrize("language_server", [Language.ERLANG], indirect=True) +@pytest.mark.parametrize("language_server", [LanguageServerId.ERLANG], indirect=True) def test_erlang_specific_ignore_patterns(language_server: SolidLanguageServer): """Test Erlang-specific ignore patterns work correctly.""" erlang_ignored_dirs = ["_build", "ebin", ".rebar3", "_checkouts", "cover"] diff --git a/test/solidlsp/erlang/test_erlang_symbol_retrieval.py b/test/solidlsp/erlang/test_erlang_symbol_retrieval.py index 918237c5..b833971b 100644 --- a/test/solidlsp/erlang/test_erlang_symbol_retrieval.py +++ b/test/solidlsp/erlang/test_erlang_symbol_retrieval.py @@ -12,21 +12,21 @@ import os import pytest from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from solidlsp.ls_types import SymbolKind -from test.conftest import language_tests_enabled +from test.conftest import language_server_tests_enabled # These marks will be applied to all tests in this module pytestmark = [ pytest.mark.erlang, - pytest.mark.skipif(not language_tests_enabled(Language.ERLANG), reason="Erlang tests are disabled"), + pytest.mark.skipif(not language_server_tests_enabled(LanguageServerId.ERLANG), reason="Erlang tests are disabled"), ] class TestErlangLanguageServerSymbols: """Test the Erlang language server's symbol-related functionality.""" - @pytest.mark.parametrize("language_server", [Language.ERLANG], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ERLANG], indirect=True) def test_request_containing_symbol_function(self, language_server: SolidLanguageServer) -> None: """Test request_containing_symbol for a function.""" # Test for a position inside the create_user function @@ -53,7 +53,7 @@ class TestErlangLanguageServerSymbols: if "body" in containing_symbol: assert "create_user" in containing_symbol["body"].get_text() - @pytest.mark.parametrize("language_server", [Language.ERLANG], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ERLANG], indirect=True) def test_request_containing_symbol_module(self, language_server: SolidLanguageServer) -> None: """Test request_containing_symbol for a module.""" # Test for a position inside the models module but outside any function @@ -78,7 +78,7 @@ class TestErlangLanguageServerSymbols: assert "models" in containing_symbol["name"] or "module" in containing_symbol["name"].lower() assert containing_symbol["kind"] == SymbolKind.Module or containing_symbol["kind"] == SymbolKind.Class - @pytest.mark.parametrize("language_server", [Language.ERLANG], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ERLANG], indirect=True) def test_request_containing_symbol_nested(self, language_server: SolidLanguageServer) -> None: """Test request_containing_symbol with nested scopes.""" # Test for a position inside a function which is inside a module @@ -107,7 +107,7 @@ class TestErlangLanguageServerSymbols: expected_names = ["create_user", "models"] assert any(name in containing_symbol["name"] for name in expected_names) - @pytest.mark.parametrize("language_server", [Language.ERLANG], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ERLANG], indirect=True) def test_request_containing_symbol_none(self, language_server: SolidLanguageServer) -> None: """Test request_containing_symbol for a position with no containing symbol.""" # Test for a position outside any function/module (e.g., in comments) @@ -119,7 +119,7 @@ class TestErlangLanguageServerSymbols: # This is acceptable behavior for module-level positions assert containing_symbol is None or containing_symbol == {} or "models" in str(containing_symbol) - @pytest.mark.parametrize("language_server", [Language.ERLANG], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ERLANG], indirect=True) def test_request_referencing_symbols_record(self, language_server: SolidLanguageServer) -> None: """Test request_referencing_symbols for a record.""" # Test referencing symbols for user record @@ -149,7 +149,7 @@ class TestErlangLanguageServerSymbols: # We expect some references from models.erl assert len(models_references) >= 0 # At least attempt to find references - @pytest.mark.parametrize("language_server", [Language.ERLANG], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ERLANG], indirect=True) def test_request_referencing_symbols_function(self, language_server: SolidLanguageServer) -> None: """Test request_referencing_symbols for a function.""" # Test referencing symbols for create_user function @@ -181,7 +181,7 @@ class TestErlangLanguageServerSymbols: ] assert len(service_references) >= 0 # At least attempt to find references - @pytest.mark.parametrize("language_server", [Language.ERLANG], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ERLANG], indirect=True) def test_request_referencing_symbols_none(self, language_server: SolidLanguageServer) -> None: """Test request_referencing_symbols for a position with no symbol.""" file_path = os.path.join("src", "models.erl") @@ -196,7 +196,7 @@ class TestErlangLanguageServerSymbols: pass # Tests for request_defining_symbol - @pytest.mark.parametrize("language_server", [Language.ERLANG], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ERLANG], indirect=True) def test_request_defining_symbol_function_call(self, language_server: SolidLanguageServer) -> None: """Test request_defining_symbol for a function call.""" # Find a place where models:create_user is called in services.erl @@ -220,7 +220,7 @@ class TestErlangLanguageServerSymbols: if "location" in defining_symbol and "uri" in defining_symbol["location"]: assert "models.erl" in defining_symbol["location"]["uri"] - @pytest.mark.parametrize("language_server", [Language.ERLANG], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ERLANG], indirect=True) def test_request_defining_symbol_record_usage(self, language_server: SolidLanguageServer) -> None: """Test request_defining_symbol for a record usage.""" # Find a place where #user{} record is used in models.erl @@ -243,7 +243,7 @@ class TestErlangLanguageServerSymbols: if "location" in defining_symbol and "uri" in defining_symbol["location"]: assert "records.hrl" in defining_symbol["location"]["uri"] - @pytest.mark.parametrize("language_server", [Language.ERLANG], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ERLANG], indirect=True) def test_request_defining_symbol_module_call(self, language_server: SolidLanguageServer) -> None: """Test request_defining_symbol for a module function call.""" # Find a place where utils:validate_input is called @@ -264,7 +264,7 @@ class TestErlangLanguageServerSymbols: if defining_symbol: assert "validate" in defining_symbol.get("name", "") or "email" in defining_symbol.get("name", "") - @pytest.mark.parametrize("language_server", [Language.ERLANG], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ERLANG], indirect=True) def test_request_defining_symbol_none(self, language_server: SolidLanguageServer) -> None: """Test request_defining_symbol for a position with no symbol.""" # Test for a position with no symbol (e.g., whitespace or comment) @@ -275,7 +275,7 @@ class TestErlangLanguageServerSymbols: # Should return None or empty assert defining_symbol is None or defining_symbol == {} - @pytest.mark.parametrize("language_server", [Language.ERLANG], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ERLANG], indirect=True) def test_symbol_methods_integration(self, language_server: SolidLanguageServer) -> None: """Test integration between different symbol methods.""" file_path = os.path.join("src", "models.erl") @@ -310,7 +310,7 @@ class TestErlangLanguageServerSymbols: reason="Known intermittent timeout issue in Erlang LS in CI environments. May pass locally but can timeout on slower CI systems.", strict=False, ) - @pytest.mark.parametrize("language_server", [Language.ERLANG], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ERLANG], indirect=True) def test_symbol_tree_structure(self, language_server: SolidLanguageServer) -> None: """Test that symbol tree structure is correctly built.""" symbol_tree = language_server.request_full_symbol_tree() @@ -336,7 +336,7 @@ class TestErlangLanguageServerSymbols: found_modules = [name for name in expected_modules if any(name in fname for fname in file_names)] assert len(found_modules) > 0, f"Expected to find some modules from {expected_modules}, but got {file_names}" - @pytest.mark.parametrize("language_server", [Language.ERLANG], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ERLANG], indirect=True) def test_request_dir_overview(self, language_server: SolidLanguageServer) -> None: """Test request_dir_overview functionality.""" src_overview = language_server.request_dir_overview("src") @@ -353,7 +353,7 @@ class TestErlangLanguageServerSymbols: found_terms = [term for term in expected_terms if term in overview_text] assert len(found_terms) > 0, f"Expected to find some terms from {expected_terms} in overview" - @pytest.mark.parametrize("language_server", [Language.ERLANG], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ERLANG], indirect=True) def test_containing_symbol_of_record_field(self, language_server: SolidLanguageServer) -> None: """Test containing symbol for record field access.""" file_path = os.path.join("src", "models.erl") @@ -378,7 +378,7 @@ class TestErlangLanguageServerSymbols: expected_names = ["create_user", "update_user", "format_user_info"] assert any(name in containing_symbol["name"] for name in expected_names) - @pytest.mark.parametrize("language_server", [Language.ERLANG], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ERLANG], indirect=True) def test_containing_symbol_of_spec(self, language_server: SolidLanguageServer) -> None: """Test containing symbol for function specs.""" file_path = os.path.join("src", "models.erl") @@ -410,7 +410,7 @@ class TestErlangLanguageServerSymbols: "Similar to known Next LS timeout issues.", strict=False, ) - @pytest.mark.parametrize("language_server", [Language.ERLANG], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ERLANG], indirect=True) def test_referencing_symbols_across_files(self, language_server: SolidLanguageServer) -> None: """Test finding references across different files.""" # Test that we can find references to models module functions in services.erl diff --git a/test/solidlsp/fortran/test_fortran_basic.py b/test/solidlsp/fortran/test_fortran_basic.py index 9a73ece1..7f43eb4d 100644 --- a/test/solidlsp/fortran/test_fortran_basic.py +++ b/test/solidlsp/fortran/test_fortran_basic.py @@ -8,10 +8,10 @@ Note: These tests require fortls to be installed: pip install fortls import pytest from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from solidlsp.ls_types import SymbolKind from solidlsp.ls_utils import SymbolUtils -from test.conftest import find_identifier_position, get_repo_path, language_has_verified_implementation_support +from test.conftest import find_identifier_position, get_repo_path, ls_has_verified_implementation_support from test.solidlsp.conftest import format_symbol_for_assert, has_malformed_name, request_all_symbols # Mark all tests in this module as fortran tests @@ -21,7 +21,7 @@ pytestmark = pytest.mark.fortran class TestFortranLanguageServer: """Test Fortran language server functionality.""" - @pytest.mark.parametrize("language_server", [Language.FORTRAN], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.FORTRAN], indirect=True) def test_find_symbol(self, language_server: SolidLanguageServer) -> None: """Test finding symbols using request_full_symbol_tree.""" symbols = language_server.request_full_symbol_tree() @@ -39,11 +39,11 @@ class TestFortranLanguageServer: # Verify subroutine symbol assert SymbolUtils.symbol_tree_contains_name(symbols, "print_result"), "print_result subroutine not found in symbol tree" - if language_has_verified_implementation_support(Language.FORTRAN): + if ls_has_verified_implementation_support(LanguageServerId.FORTRAN): - @pytest.mark.parametrize("language_server", [Language.FORTRAN], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.FORTRAN], indirect=True) def test_find_implementations(self, language_server: SolidLanguageServer) -> None: - repo_path = get_repo_path(Language.FORTRAN) + repo_path = get_repo_path(LanguageServerId.FORTRAN) pos = find_identifier_position(repo_path / "modules" / "geometry.f90", "distance") assert pos is not None, "Could not find interface distance in geometry.f90" @@ -53,9 +53,9 @@ class TestFortranLanguageServer: assert implementation_files == {"modules/geometry.f90"}, f"Unexpected implementation locations: {implementations}" assert len(implementations) >= 2, f"Expected module procedure implementations, got: {implementations}" - @pytest.mark.parametrize("language_server", [Language.FORTRAN], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.FORTRAN], indirect=True) def test_request_implementing_symbols(self, language_server: SolidLanguageServer) -> None: - repo_path = get_repo_path(Language.FORTRAN) + repo_path = get_repo_path(LanguageServerId.FORTRAN) pos = find_identifier_position(repo_path / "modules" / "geometry.f90", "distance") assert pos is not None, "Could not find interface distance in geometry.f90" @@ -66,7 +66,7 @@ class TestFortranLanguageServer: f"Expected distance_2d and distance_3d, got: {implementing_symbols}" ) - @pytest.mark.parametrize("language_server", [Language.FORTRAN], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.FORTRAN], indirect=True) def test_request_document_symbols(self, language_server: SolidLanguageServer) -> None: """Test that document symbols can be retrieved from Fortran files.""" # Test main.f90 - should have a program symbol @@ -82,7 +82,7 @@ class TestFortranLanguageServer: assert "multiply_numbers" in all_names, f"Function 'multiply_numbers' not found. Found: {all_names}" assert "print_result" in all_names, f"Subroutine 'print_result' not found. Found: {all_names}" - @pytest.mark.parametrize("language_server", [Language.FORTRAN], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.FORTRAN], indirect=True) def test_find_references_cross_file(self, language_server: SolidLanguageServer) -> None: """Test finding references across files using low-level request_references. @@ -116,7 +116,7 @@ class TestFortranLanguageServer: f"Expected to find reference in main.f90, but found references in: {[ref.get('relativePath') for ref in refs]}" ) - @pytest.mark.parametrize("language_server", [Language.FORTRAN], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.FORTRAN], indirect=True) def test_find_definition_cross_file(self, language_server: SolidLanguageServer) -> None: """Test finding definition across files using request_definition.""" # In main.f90, line 7 (0-indexed: line 6) contains: result = add_numbers(5.0, 3.0) @@ -142,7 +142,7 @@ class TestFortranLanguageServer: f"Expected definition at line 4, but found at line {definition_location['range']['start']['line']}" ) - @pytest.mark.parametrize("language_server", [Language.FORTRAN], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.FORTRAN], indirect=True) def test_request_referencing_symbols(self, language_server: SolidLanguageServer) -> None: """Test finding symbols that reference a function - Serena's high-level API. @@ -189,7 +189,7 @@ class TestFortranLanguageServer: # because it depends on finding containing symbols for each reference. We verify that # the API works and returns valid symbols with proper structure. - @pytest.mark.parametrize("language_server", [Language.FORTRAN], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.FORTRAN], indirect=True) def test_request_defining_symbol(self, language_server: SolidLanguageServer) -> None: """Test finding the defining symbol - Serena's high-level API. @@ -218,7 +218,7 @@ class TestFortranLanguageServer: defining_path = defining_symbol["location"]["relativePath"] assert "math_utils.f90" in defining_path, f"Expected definition to be in math_utils.f90, but found in: {defining_path}" - @pytest.mark.parametrize("language_server", [Language.FORTRAN], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.FORTRAN], indirect=True) def test_request_containing_symbol(self, language_server: SolidLanguageServer) -> None: """Test finding the containing symbol for a position in the code.""" # Test finding the containing symbol for a position inside the add_numbers function @@ -246,7 +246,7 @@ class TestFortranLanguageServer: assert "range" in location, "Location should contain range information" assert "start" in location["range"] and "end" in location["range"], "Range should have start and end positions" - @pytest.mark.parametrize("language_server", [Language.FORTRAN], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.FORTRAN], indirect=True) def test_type_and_interface_symbols(self, language_server: SolidLanguageServer) -> None: """Test that type definitions and interfaces are properly recognized with corrected selectionRange. @@ -302,7 +302,7 @@ class TestFortranLanguageServer: # refs might be empty if Point3D isn't used elsewhere, but the call should not fail # The important thing is that it doesn't error due to wrong character position - @pytest.mark.parametrize("language_server", [Language.FORTRAN], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.FORTRAN], indirect=True) def test_bare_symbol_names(self, language_server) -> None: all_symbols = request_all_symbols(language_server) malformed_symbols = [] diff --git a/test/solidlsp/fortran/test_fortran_diagnostics.py b/test/solidlsp/fortran/test_fortran_diagnostics.py index f607cd0b..0fb34d4b 100644 --- a/test/solidlsp/fortran/test_fortran_diagnostics.py +++ b/test/solidlsp/fortran/test_fortran_diagnostics.py @@ -1,13 +1,13 @@ import pytest from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from test.solidlsp.util.diagnostics import assert_file_diagnostics @pytest.mark.fortran class TestFortranDiagnostics: - @pytest.mark.parametrize("language_server", [Language.FORTRAN], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.FORTRAN], indirect=True) def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None: assert_file_diagnostics( language_server, diff --git a/test/solidlsp/fsharp/test_fsharp_basic.py b/test/solidlsp/fsharp/test_fsharp_basic.py index 37ed0bb5..524bbe2f 100644 --- a/test/solidlsp/fsharp/test_fsharp_basic.py +++ b/test/solidlsp/fsharp/test_fsharp_basic.py @@ -5,23 +5,26 @@ from typing import Any import pytest from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from solidlsp.ls_utils import SymbolUtils from test.conftest import ( find_identifier_position, get_repo_path, - language_has_verified_implementation_support, - language_tests_enabled, + language_server_tests_enabled, + ls_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 (regression/instability), so the suite is disabled on CI. -pytestmark = [pytest.mark.fsharp, pytest.mark.skipif(not language_tests_enabled(Language.FSHARP), reason="F# tests are disabled")] +pytestmark = [ + pytest.mark.fsharp, + pytest.mark.skipif(not language_server_tests_enabled(LanguageServerId.FSHARP), reason="F# tests are disabled"), +] class TestFSharpLanguageServer: - @pytest.mark.parametrize("language_server", [Language.FSHARP], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.FSHARP], indirect=True) def test_find_symbol(self, language_server: SolidLanguageServer) -> None: """Test finding symbols in the full symbol tree.""" symbols = language_server.request_full_symbol_tree() @@ -35,7 +38,7 @@ class TestFSharpLanguageServer: assert SymbolUtils.symbol_tree_contains_name(symbols, "add"), "add function not found in symbol tree" assert SymbolUtils.symbol_tree_contains_name(symbols, "CalculatorClass"), "CalculatorClass not found in symbol tree" - @pytest.mark.parametrize("language_server", [Language.FSHARP], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.FSHARP], indirect=True) def test_get_document_symbols_program(self, language_server: SolidLanguageServer) -> None: """Test getting document symbols from the main Program.fs file.""" file_path = os.path.join("Program.fs") @@ -45,11 +48,11 @@ class TestFSharpLanguageServer: symbol_names = [s.get("name") for s in symbols] assert "main" in symbol_names, "main function not found in Program.fs symbols" - if language_has_verified_implementation_support(Language.FSHARP): + if ls_has_verified_implementation_support(LanguageServerId.FSHARP): - @pytest.mark.parametrize("language_server", [Language.FSHARP], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.FSHARP], indirect=True) def test_find_implementations(self, language_server: SolidLanguageServer) -> None: - repo_path = get_repo_path(Language.FSHARP) + repo_path = get_repo_path(LanguageServerId.FSHARP) pos = find_identifier_position(repo_path / "Formatter.fs", "FormatGreeting") assert pos is not None, "Could not find IGreeter.FormatGreeting in fixture" @@ -59,9 +62,9 @@ class TestFSharpLanguageServer: f"Expected ConsoleGreeter.FormatGreeting in implementations, got: {implementations}" ) - @pytest.mark.parametrize("language_server", [Language.FSHARP], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.FSHARP], indirect=True) def test_request_implementing_symbols(self, language_server: SolidLanguageServer) -> None: - repo_path = get_repo_path(Language.FSHARP) + repo_path = get_repo_path(LanguageServerId.FSHARP) pos = find_identifier_position(repo_path / "Formatter.fs", "FormatGreeting") assert pos is not None, "Could not find IGreeter.FormatGreeting in fixture" @@ -72,7 +75,7 @@ class TestFSharpLanguageServer: for symbol in implementing_symbols ), f"Expected ConsoleGreeter.FormatGreeting symbol, got: {implementing_symbols}" - @pytest.mark.parametrize("language_server", [Language.FSHARP], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.FSHARP], indirect=True) def test_get_document_symbols_calculator(self, language_server: SolidLanguageServer) -> None: """Test getting document symbols from Calculator.fs file.""" file_path = os.path.join("Calculator.fs") @@ -85,7 +88,7 @@ class TestFSharpLanguageServer: for expected in expected_symbols: assert expected in symbol_names, f"{expected} function not found in Calculator.fs symbols" - @pytest.mark.parametrize("language_server", [Language.FSHARP], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.FSHARP], indirect=True) def test_find_referencing_symbols(self, language_server: SolidLanguageServer) -> None: """Test finding references using symbol selection range.""" file_path = os.path.join("Calculator.fs") @@ -108,7 +111,7 @@ class TestFSharpLanguageServer: # The add function should be referenced in Program.fs assert any("Program.fs" in ref.get("relativePath", "") for ref in refs), "Program.fs should reference add function" - @pytest.mark.parametrize("language_server", [Language.FSHARP], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.FSHARP], indirect=True) def test_nested_module_symbols(self, language_server: SolidLanguageServer) -> None: """Test getting symbols from nested Models namespace.""" file_path = os.path.join("Models", "Person.fs") @@ -121,7 +124,7 @@ class TestFSharpLanguageServer: for expected in expected_symbols: assert expected in symbol_names, f"{expected} not found in Person.fs symbols" - @pytest.mark.parametrize("language_server", [Language.FSHARP], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.FSHARP], indirect=True) def test_find_referencing_symbols_across_files(self, language_server: SolidLanguageServer) -> None: """Test finding references to Calculator functions across files.""" # Find the subtract function in Calculator.fs @@ -143,7 +146,7 @@ class TestFSharpLanguageServer: # The subtract function should be referenced in Program.fs assert any("Program.fs" in ref.get("relativePath", "") for ref in refs), "Program.fs should reference subtract function" - @pytest.mark.parametrize("language_server", [Language.FSHARP], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.FSHARP], indirect=True) def test_go_to_definition(self, language_server: SolidLanguageServer) -> None: """Test go-to-definition functionality.""" # Test going to definition of 'add' function from Program.fs @@ -156,7 +159,7 @@ class TestFSharpLanguageServer: # We should get at least some definitions assert len(definitions) >= 0, "Should get definitions (even if empty for complex cases)" - @pytest.mark.parametrize("language_server", [Language.FSHARP], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.FSHARP], indirect=True) def test_hover_information(self, language_server: SolidLanguageServer) -> None: """Test hover information functionality.""" file_path = os.path.join("Calculator.fs") @@ -168,7 +171,7 @@ class TestFSharpLanguageServer: # This is acceptable as it depends on the LSP server's capabilities and timing assert hover_info is None or isinstance(hover_info, dict), "Hover info should be None or dict" - @pytest.mark.parametrize("language_server", [Language.FSHARP], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.FSHARP], indirect=True) def test_completion(self, language_server: SolidLanguageServer) -> None: """Test code completion functionality.""" file_path = os.path.join("Program.fs") @@ -197,7 +200,7 @@ class TestFSharpLanguageServer: assert isinstance(result["value"], list), "Completions should be a list" - @pytest.mark.parametrize("language_server", [Language.FSHARP], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.FSHARP], indirect=True) def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None: assert_file_diagnostics( language_server, @@ -206,7 +209,7 @@ class TestFSharpLanguageServer: min_count=1, ) - @pytest.mark.parametrize("language_server", [Language.FSHARP], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.FSHARP], indirect=True) def test_bare_symbol_names(self, language_server) -> None: all_symbols = request_all_symbols(language_server) malformed_symbols = [] diff --git a/test/solidlsp/go/test_go_basic.py b/test/solidlsp/go/test_go_basic.py index 2388b78c..d623eb87 100644 --- a/test/solidlsp/go/test_go_basic.py +++ b/test/solidlsp/go/test_go_basic.py @@ -5,22 +5,22 @@ import pytest from serena.symbol import LanguageServerSymbol from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from solidlsp.ls_utils import SymbolUtils -from test.conftest import find_identifier_position, get_repo_path, language_has_verified_implementation_support +from test.conftest import find_identifier_position, get_repo_path, ls_has_verified_implementation_support from test.solidlsp.conftest import format_symbol_for_assert, has_malformed_name, request_all_symbols @pytest.mark.go class TestGoLanguageServer: - @pytest.mark.parametrize("language_server", [Language.GO], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.GO], indirect=True) def test_find_symbol(self, language_server: SolidLanguageServer) -> None: symbols = language_server.request_full_symbol_tree() assert SymbolUtils.symbol_tree_contains_name(symbols, "main"), "main function not found in symbol tree" assert SymbolUtils.symbol_tree_contains_name(symbols, "Helper"), "Helper function not found in symbol tree" assert SymbolUtils.symbol_tree_contains_name(symbols, "DemoStruct"), "DemoStruct not found in symbol tree" - @pytest.mark.parametrize("language_server", [Language.GO], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.GO], indirect=True) def test_find_symbol_matches_go_method_by_bare_name(self, language_server: SolidLanguageServer) -> None: symbols = language_server.request_full_symbol_tree(within_relative_path="main.go") @@ -34,7 +34,7 @@ class TestGoLanguageServer: assert bare_name_matches, "Expected a Go method to match by bare name" assert all(match.name == "Value" for match in bare_name_matches) - @pytest.mark.parametrize("language_server", [Language.GO], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.GO], indirect=True) def test_find_referencing_symbols(self, language_server: SolidLanguageServer) -> None: file_path = os.path.join("main.go") symbols = language_server.request_document_symbols(file_path).get_all_symbols_and_roots() @@ -48,7 +48,7 @@ class TestGoLanguageServer: refs = language_server.request_references(file_path, sel_start["line"], sel_start["character"]) assert any("main.go" in ref.get("uri", "") for ref in refs), "Expected at least one reference result to point at main.go" - @pytest.mark.parametrize("language_server", [Language.GO], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.GO], indirect=True) def test_type_var_const_body_includes_leading_keyword(self, language_server: SolidLanguageServer) -> None: """ Single ``type``/``var``/``const`` declarations must expose a body and replacement range that @@ -88,11 +88,11 @@ class TestGoLanguageServer: assert body.startswith(name), f"Expected grouped var {name} body to start with the identifier, got {body[:24]!r}" assert not body.startswith("var"), f"Grouped var {name} body must not include the 'var' keyword" - if language_has_verified_implementation_support(Language.GO): + if ls_has_verified_implementation_support(LanguageServerId.GO): - @pytest.mark.parametrize("language_server", [Language.GO], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.GO], indirect=True) def test_find_implementations(self, language_server: SolidLanguageServer) -> None: - repo_path = get_repo_path(Language.GO) + repo_path = get_repo_path(LanguageServerId.GO) pos = find_identifier_position(repo_path / "main.go", "FormatGreeting") assert pos is not None, "Could not find Greeter.FormatGreeting in fixture" @@ -102,9 +102,9 @@ class TestGoLanguageServer: f"Expected ConsoleGreeter.FormatGreeting in implementations, got: {implementations}" ) - @pytest.mark.parametrize("language_server", [Language.GO], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.GO], indirect=True) def test_request_implementing_symbols(self, language_server: SolidLanguageServer) -> None: - repo_path = get_repo_path(Language.GO) + repo_path = get_repo_path(LanguageServerId.GO) pos = find_identifier_position(repo_path / "main.go", "FormatGreeting") assert pos is not None, "Could not find Greeter.FormatGreeting in fixture" @@ -133,7 +133,7 @@ class TestGoBuildTags: from test.conftest import get_repo_path - fixture_path = get_repo_path(Language.GO) + fixture_path = get_repo_path(LanguageServerId.GO) target_path = tmp_path / "test_repo" shutil.copytree(fixture_path, target_path) @@ -145,7 +145,7 @@ class TestGoBuildTags: repo_path = self._copy_go_fixture(tmp_path) - with start_ls_context(Language.GO, repo_path=str(repo_path), solidlsp_dir=tmp_path) as ls: + with start_ls_context(LanguageServerId.GO, repo_path=str(repo_path), solidlsp_dir=tmp_path) as ls: xnotfoo_symbols = ls.request_workspace_symbol("XNotFoo") xfoo_symbols = ls.request_workspace_symbol("XFoo") @@ -162,14 +162,14 @@ class TestGoBuildTags: repo_path = self._copy_go_fixture(tmp_path) ls_settings = { - Language.GO: { + LanguageServerId.GO: { "gopls_settings": { "buildFlags": ["-tags=foo"], }, }, } - with start_ls_context(Language.GO, repo_path=str(repo_path), ls_specific_settings=ls_settings, solidlsp_dir=tmp_path) as ls: + with start_ls_context(LanguageServerId.GO, repo_path=str(repo_path), ls_specific_settings=ls_settings, solidlsp_dir=tmp_path) as ls: xfoo_symbols = ls.request_workspace_symbol("XFoo") xnotfoo_symbols = ls.request_workspace_symbol("XNotFoo") @@ -188,7 +188,7 @@ class TestGoBuildTags: repo_path = self._copy_go_fixture(tmp_path) ls_settings_foo = { - Language.GO: { + LanguageServerId.GO: { "gopls_settings": { "buildFlags": ["-tags=foo"], }, @@ -214,7 +214,7 @@ class TestGoBuildTags: assert ls._document_symbols_cache_is_modified # Run 1 (default context): populate caches and persist them to disk. - with start_ls_context(Language.GO, repo_path=str(repo_path), solidlsp_dir=tmp_path) as ls_default: + with start_ls_context(LanguageServerId.GO, repo_path=str(repo_path), solidlsp_dir=tmp_path) as ls_default: _ = ls_default.request_document_symbols(main_go) default_raw_cache_version = ls_default._raw_document_symbols_cache_version() @@ -243,7 +243,7 @@ class TestGoBuildTags: ) # Run 2 (default context again): prove that persisted caches are actually loaded and used. - with start_ls_context(Language.GO, repo_path=str(repo_path), solidlsp_dir=tmp_path) as ls_default_again: + with start_ls_context(LanguageServerId.GO, repo_path=str(repo_path), solidlsp_dir=tmp_path) as ls_default_again: assert ls_default_again.cache_dir == cache_dir _assert_caches_loaded_and_clean(ls_default_again) @@ -256,7 +256,7 @@ class TestGoBuildTags: # Run 3 (foo context): the same on-disk cache directory exists, but MUST be treated as stale. with start_ls_context( - Language.GO, + LanguageServerId.GO, repo_path=str(repo_path), ls_specific_settings=ls_settings_foo, solidlsp_dir=tmp_path, @@ -277,7 +277,7 @@ class TestGoBuildTags: # A cache miss should repopulate and mark caches modified. _assert_caches_modified(ls_foo) - @pytest.mark.parametrize("language_server", [Language.GO], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.GO], indirect=True) def test_bare_symbol_names(self, language_server) -> None: all_symbols = request_all_symbols(language_server) malformed_symbols = [] diff --git a/test/solidlsp/go/test_go_diagnostics.py b/test/solidlsp/go/test_go_diagnostics.py index 00b4cc48..0a5b50ec 100644 --- a/test/solidlsp/go/test_go_diagnostics.py +++ b/test/solidlsp/go/test_go_diagnostics.py @@ -1,13 +1,13 @@ import pytest from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from test.solidlsp.util.diagnostics import assert_file_diagnostics @pytest.mark.go class TestGoDiagnostics: - @pytest.mark.parametrize("language_server", [Language.GO], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.GO], indirect=True) def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None: assert_file_diagnostics( language_server, diff --git a/test/solidlsp/groovy/test_groovy_basic.py b/test/solidlsp/groovy/test_groovy_basic.py index 0637e3de..7568d80d 100644 --- a/test/solidlsp/groovy/test_groovy_basic.py +++ b/test/solidlsp/groovy/test_groovy_basic.py @@ -5,7 +5,7 @@ import pytest from serena.constants import SERENA_MANAGED_DIR_NAME from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language, LanguageServerConfig +from solidlsp.ls_config import LanguageServerConfig, LanguageServerId 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 @@ -43,13 +43,13 @@ class TestGroovyLanguageServer: # Create language server directly with Groovy-specific settings repo_path = str(cls.test_repo_path) - config = LanguageServerConfig(code_language=Language.GROOVY, ignored_paths=[], trace_lsp_communication=False) + config = LanguageServerConfig(ls_id=LanguageServerId.GROOVY, ignored_paths=[], trace_lsp_communication=False) project_data_path = os.path.join(repo_path, SERENA_MANAGED_DIR_NAME) solidlsp_settings = SolidLSPSettings( solidlsp_dir=str(Path.home() / ".serena"), project_data_path=project_data_path, - ls_specific_settings={Language.GROOVY: groovy_settings}, + ls_specific_settings={LanguageServerId.GROOVY: groovy_settings}, ) cls.language_server = SolidLanguageServer.create(config, repo_path, solidlsp_settings=solidlsp_settings) diff --git a/test/solidlsp/haskell/test_haskell_basic.py b/test/solidlsp/haskell/test_haskell_basic.py index cf4bba3b..cfd104c7 100644 --- a/test/solidlsp/haskell/test_haskell_basic.py +++ b/test/solidlsp/haskell/test_haskell_basic.py @@ -16,18 +16,20 @@ Test Repository Structure: import pytest from solidlsp.ls import SolidLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from solidlsp.ls_types import SymbolKind -from test.conftest import language_tests_enabled +from test.conftest import language_server_tests_enabled from test.solidlsp.conftest import format_symbol_for_assert, has_malformed_name, request_all_symbols from test.solidlsp.util.diagnostics import assert_file_diagnostics -pytestmark = pytest.mark.skipif(not language_tests_enabled(Language.HASKELL), reason="Haskell tests are disabled (HLS not available)") +pytestmark = pytest.mark.skipif( + not language_server_tests_enabled(LanguageServerId.HASKELL), reason="Haskell tests are disabled (HLS not available)" +) @pytest.mark.haskell class TestHaskellLanguageServer: - @pytest.mark.parametrize("language_server", [Language.HASKELL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.HASKELL], indirect=True) def test_calculator_module_symbols(self, language_server: SolidLanguageServer): """ Test precise symbol discovery in Calculator.hs. @@ -66,7 +68,7 @@ class TestHaskellLanguageServer: 23, ], f"Calculator should be a data type (kind 1, 5, or 23), got kind {calculator_symbol['kind']}" - @pytest.mark.parametrize("language_server", [Language.HASKELL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.HASKELL], indirect=True) def test_helper_module_symbols(self, language_server: SolidLanguageServer): """ Test precise symbol discovery in Helper.hs. @@ -93,7 +95,7 @@ class TestHaskellLanguageServer: extra = symbol_names - expected_symbols - {"Helper"} assert not extra, f"Unexpected symbols in Helper.hs: {extra}" - @pytest.mark.parametrize("language_server", [Language.HASKELL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.HASKELL], indirect=True) def test_main_module_imports(self, language_server: SolidLanguageServer): """ Test that Main.hs properly references both Calculator and Helper modules. @@ -106,7 +108,7 @@ class TestHaskellLanguageServer: # Main.hs should have the main function assert "main" in symbol_names, "Main.hs should contain 'main' function" - @pytest.mark.parametrize("language_server", [Language.HASKELL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.HASKELL], indirect=True) def test_cross_file_references_validateNumber(self, language_server: SolidLanguageServer): """ Test cross-file reference tracking for validateNumber function. @@ -132,7 +134,7 @@ class TestHaskellLanguageServer: f"got {len(calculator_refs)} references in Calculator.hs" ) - @pytest.mark.parametrize("language_server", [Language.HASKELL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.HASKELL], indirect=True) def test_within_file_references_isNegative(self, language_server: SolidLanguageServer): """ Test within-file reference tracking for isNegative function. @@ -152,7 +154,7 @@ class TestHaskellLanguageServer: f"All isNegative references should be in Helper.hs, got: {reference_paths}" ) - @pytest.mark.parametrize("language_server", [Language.HASKELL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.HASKELL], indirect=True) def test_function_references_from_main(self, language_server: SolidLanguageServer): """ Test that functions used in Main.hs can be traced back to their definitions. @@ -175,7 +177,7 @@ class TestHaskellLanguageServer: f"Expected 'add' to be referenced in Main.hs or Calculator.hs, got: {add_ref_paths}" ) - @pytest.mark.parametrize("language_server", [Language.HASKELL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.HASKELL], indirect=True) def test_multiply_function_usage_in_calculate(self, language_server: SolidLanguageServer): """ Test that multiply function usage is tracked within Calculator module. @@ -198,7 +200,7 @@ class TestHaskellLanguageServer: f"Expected 'multiply' to be referenced in Calculator.hs, got: {multiply_ref_paths}" ) - @pytest.mark.parametrize("language_server", [Language.HASKELL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.HASKELL], indirect=True) def test_data_type_constructor_references(self, language_server: SolidLanguageServer): """ Test that Calculator data type constructor usage is tracked. @@ -221,7 +223,7 @@ class TestHaskellLanguageServer: f"Expected Calculator to be referenced in Main.hs or Calculator.hs, got: {calc_ref_paths}" ) - @pytest.mark.parametrize("language_server", [Language.HASKELL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.HASKELL], indirect=True) def test_bare_symbol_names(self, language_server) -> None: all_symbols = request_all_symbols(language_server) malformed_symbols = [] @@ -242,7 +244,7 @@ class TestHaskellLanguageServer: ] pytest.fail(f"Found malformed symbols: {diagnostics}", pytrace=False) - @pytest.mark.parametrize("language_server", [Language.HASKELL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.HASKELL], indirect=True) def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None: assert_file_diagnostics( language_server, diff --git a/test/solidlsp/haxe/test_haxe_basic.py b/test/solidlsp/haxe/test_haxe_basic.py index 1662090e..eefe2c6d 100644 --- a/test/solidlsp/haxe/test_haxe_basic.py +++ b/test/solidlsp/haxe/test_haxe_basic.py @@ -3,7 +3,7 @@ import os import pytest from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from solidlsp.ls_types import SymbolKind from solidlsp.ls_utils import SymbolUtils from test.solidlsp.conftest import format_symbol_for_assert, has_malformed_name, request_all_symbols @@ -11,12 +11,12 @@ from test.solidlsp.conftest import format_symbol_for_assert, has_malformed_name, @pytest.mark.haxe class TestHaxeLanguageServer: - @pytest.mark.parametrize("language_server", [Language.HAXE], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.HAXE], indirect=True) def test_ls_is_running(self, language_server: SolidLanguageServer) -> None: """Test that the Haxe language server starts successfully.""" assert language_server.is_running() - @pytest.mark.parametrize("language_server", [Language.HAXE], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.HAXE], indirect=True) def test_find_symbol(self, language_server: SolidLanguageServer) -> None: symbols = language_server.request_full_symbol_tree() assert SymbolUtils.symbol_tree_contains_name(symbols, "Main"), "Main class not found in symbol tree" @@ -26,7 +26,7 @@ class TestHaxeLanguageServer: assert SymbolUtils.symbol_tree_contains_name(symbols, "addNumbers"), "addNumbers method not found in symbol tree" assert SymbolUtils.symbol_tree_contains_name(symbols, "formatMessage"), "formatMessage method not found in symbol tree" - @pytest.mark.parametrize("language_server", [Language.HAXE], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.HAXE], indirect=True) def test_bare_symbol_names(self, language_server: SolidLanguageServer) -> None: """Test that symbol names do not contain unexpected formatting characters.""" all_symbols = request_all_symbols(language_server) @@ -40,7 +40,7 @@ class TestHaxeLanguageServer: pytrace=False, ) - @pytest.mark.parametrize("language_server", [Language.HAXE], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.HAXE], indirect=True) def test_find_references_within_file(self, language_server: SolidLanguageServer) -> None: file_path = os.path.join("src", "Main.hx") all_symbols, _ = language_server.request_document_symbols(file_path).get_all_symbols_and_roots() @@ -69,7 +69,7 @@ class TestHaxeLanguageServer: f"Expected all greet references in Main.hx, got {actual_locations}" ) - @pytest.mark.parametrize("language_server", [Language.HAXE], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.HAXE], indirect=True) def test_find_references_across_files(self, language_server: SolidLanguageServer) -> None: # Test addNumbers which is defined in Helper.hx and used in Main.hx helper_path = os.path.join("src", "utils", "Helper.hx") @@ -103,7 +103,7 @@ class TestHaxeLanguageServer: main_refs = [loc for loc in actual_locations if loc["uri_suffix"] == "Main.hx"] assert len(main_refs) >= 2, f"Expected at least 2 references in Main.hx (lines 16 and 30), got {main_refs}" - @pytest.mark.parametrize("language_server", [Language.HAXE], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.HAXE], indirect=True) def test_document_symbols_structure(self, language_server: SolidLanguageServer) -> None: file_path = os.path.join("src", "Main.hx") result = language_server.request_document_symbols(file_path) @@ -139,14 +139,14 @@ class TestHaxeLanguageServer: SymbolKind.Property, ), f"Expected message to be Field/Variable, got {sym.get('kind')}" - @pytest.mark.parametrize("language_server", [Language.HAXE], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.HAXE], indirect=True) def test_workspace_symbol(self, language_server: SolidLanguageServer) -> None: result = language_server.request_workspace_symbol("Helper") assert result is not None, "Workspace symbol search returned None" assert len(result) > 0, "Workspace symbol search returned no results" assert any("Helper" in str(s.get("name", "")) for s in result), f"Expected at least one result containing 'Helper', got {result}" - @pytest.mark.parametrize("language_server", [Language.HAXE], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.HAXE], indirect=True) def test_go_to_definition_within_file(self, language_server: SolidLanguageServer) -> None: """Go to definition of greet from its call site in Main.hx -- should resolve within the same file.""" main_path = os.path.join("src", "Main.hx") @@ -161,7 +161,7 @@ class TestHaxeLanguageServer: definition_lines = [d["range"]["start"]["line"] for d in definitions if "Main.hx" in d.get("uri", d.get("relativePath", ""))] assert 22 in definition_lines, f"Expected definition of greet at line 22 in Main.hx, got lines {definition_lines}" - @pytest.mark.parametrize("language_server", [Language.HAXE], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.HAXE], indirect=True) def test_go_to_definition(self, language_server: SolidLanguageServer) -> None: """Go to definition of addNumbers from a call site in Main.hx -- should resolve to Helper.hx.""" main_path = os.path.join("src", "Main.hx") @@ -176,7 +176,7 @@ class TestHaxeLanguageServer: definition_lines = [d["range"]["start"]["line"] for d in definitions if "Helper.hx" in d.get("uri", d.get("relativePath", ""))] assert 18 in definition_lines, f"Expected definition of addNumbers at line 18 in Helper.hx, got lines {definition_lines}" - @pytest.mark.parametrize("language_server", [Language.HAXE], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.HAXE], indirect=True) def test_hover(self, language_server: SolidLanguageServer) -> None: file_path = os.path.join("src", "Main.hx") result = language_server.request_document_symbols(file_path) @@ -190,7 +190,7 @@ class TestHaxeLanguageServer: hover_str = str(hover) assert "String" in hover_str or "greet" in hover_str, f"Expected hover to contain type info, got {hover_str}" - @pytest.mark.parametrize("language_server", [Language.HAXE], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.HAXE], indirect=True) def test_hover_on_class_declaration(self, language_server: SolidLanguageServer) -> None: """Hovering on a class name should return hover info.""" file_path = os.path.join("src", "Main.hx") @@ -206,7 +206,7 @@ class TestHaxeLanguageServer: hover_str = str(hover) assert "Main" in hover_str, f"Expected hover to contain 'Main', got {hover_str}" - @pytest.mark.parametrize("language_server", [Language.HAXE], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.HAXE], indirect=True) def test_rename_symbol(self, language_server: SolidLanguageServer) -> None: file_path = os.path.join("src", "Main.hx") result = language_server.request_document_symbols(file_path) @@ -222,7 +222,7 @@ class TestHaxeLanguageServer: assert "Main.hx" in edits_str, f"Expected rename edits for Main.hx, got {edits}" assert "sayHello" in edits_str, f"Expected new name 'sayHello' in rename edits, got {edits}" - @pytest.mark.parametrize("language_server", [Language.HAXE], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.HAXE], indirect=True) def test_completions(self, language_server: SolidLanguageServer) -> None: """Request completions after Helper. in calculateResult — should return Helper's static methods.""" file_path = os.path.join("src", "Main.hx") @@ -233,7 +233,7 @@ class TestHaxeLanguageServer: completion_texts = [c.get("completionText", c.get("label", "")) for c in completions] assert "addNumbers" in completion_texts, f"Expected 'addNumbers' in completions after Helper., got {completion_texts[:10]}" - @pytest.mark.parametrize("language_server", [Language.HAXE], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.HAXE], indirect=True) def test_document_overview(self, language_server: SolidLanguageServer) -> None: overview = language_server.request_document_overview(os.path.join("src", "Main.hx")) assert overview, "Document overview returned empty list" @@ -248,7 +248,7 @@ class TestHaxeLanguageServer: assert s.get("name"), "Symbol missing 'name' field" assert s.get("kind"), "Symbol missing 'kind' field" - @pytest.mark.parametrize("language_server", [Language.HAXE], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.HAXE], indirect=True) def test_rapid_successive_requests(self, language_server: SolidLanguageServer) -> None: """Verify that rapid successive requests don't return empty results. diff --git a/test/solidlsp/haxe/test_haxe_diagnostics.py b/test/solidlsp/haxe/test_haxe_diagnostics.py index 2f789b60..0da34728 100644 --- a/test/solidlsp/haxe/test_haxe_diagnostics.py +++ b/test/solidlsp/haxe/test_haxe_diagnostics.py @@ -1,13 +1,13 @@ import pytest from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from test.solidlsp.util.diagnostics import assert_file_diagnostics @pytest.mark.haxe class TestHaxeDiagnostics: - @pytest.mark.parametrize("language_server", [Language.HAXE], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.HAXE], indirect=True) def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None: assert_file_diagnostics( language_server, diff --git a/test/solidlsp/hlsl/test_hlsl_basic.py b/test/solidlsp/hlsl/test_hlsl_basic.py index 90d1c864..9280a1a2 100644 --- a/test/solidlsp/hlsl/test_hlsl_basic.py +++ b/test/solidlsp/hlsl/test_hlsl_basic.py @@ -10,7 +10,7 @@ from typing import Any import pytest from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from solidlsp.ls_exceptions import SolidLSPException from solidlsp.ls_types import SymbolKind from solidlsp.ls_utils import SymbolUtils @@ -30,19 +30,19 @@ def _find_symbol_by_name(language_server: SolidLanguageServer, file_path: str, n class TestHlslSymbols: """Tests for document symbol extraction.""" - @pytest.mark.parametrize("language_server", [Language.HLSL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.HLSL], indirect=True) def test_find_struct(self, language_server: SolidLanguageServer) -> None: """VertexInput struct should appear in common.hlsl symbols.""" symbol = _find_symbol_by_name(language_server, "common.hlsl", "VertexInput") assert symbol is not None, "Expected 'VertexInput' struct in document symbols" - @pytest.mark.parametrize("language_server", [Language.HLSL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.HLSL], indirect=True) def test_find_function(self, language_server: SolidLanguageServer) -> None: """SafeNormalize function should appear in common.hlsl.""" symbol = _find_symbol_by_name(language_server, "common.hlsl", "SafeNormalize") assert symbol is not None, "Expected 'SafeNormalize' function in document symbols" - @pytest.mark.parametrize("language_server", [Language.HLSL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.HLSL], indirect=True) def test_find_cbuffer_members(self, language_server: SolidLanguageServer) -> None: """Cbuffer members should appear as variables in compute_test.hlsl. @@ -52,13 +52,13 @@ class TestHlslSymbols: symbol = _find_symbol_by_name(language_server, "compute_test.hlsl", "TextureSize") assert symbol is not None, "Expected 'TextureSize' cbuffer member in document symbols" - @pytest.mark.parametrize("language_server", [Language.HLSL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.HLSL], indirect=True) def test_find_compute_kernel(self, language_server: SolidLanguageServer) -> None: """CSMain kernel should appear in compute_test.hlsl.""" symbol = _find_symbol_by_name(language_server, "compute_test.hlsl", "CSMain") assert symbol is not None, "Expected 'CSMain' compute kernel in document symbols" - @pytest.mark.parametrize("language_server", [Language.HLSL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.HLSL], indirect=True) def test_full_symbol_tree(self, language_server: SolidLanguageServer) -> None: """Full symbol tree should contain symbols from multiple files.""" symbols = language_server.request_full_symbol_tree() @@ -73,7 +73,7 @@ class TestHlslSymbols: class TestHlslDefinition: """Tests for go-to-definition capability.""" - @pytest.mark.parametrize("language_server", [Language.HLSL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.HLSL], indirect=True) def test_goto_definition_cross_file(self, language_server: SolidLanguageServer) -> None: """Navigating to SafeNormalize call in lighting.hlsl should resolve to common.hlsl. @@ -85,7 +85,7 @@ class TestHlslDefinition: def_paths = [d.get("relativePath", d.get("uri", "")) for d in definitions] assert any("common.hlsl" in p for p in def_paths), f"Expected definition in common.hlsl, got: {def_paths}" - @pytest.mark.parametrize("language_server", [Language.HLSL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.HLSL], indirect=True) def test_goto_definition_cross_file_remap(self, language_server: SolidLanguageServer) -> None: """Navigating to Remap call in compute_test.hlsl should resolve to common.hlsl. @@ -109,7 +109,7 @@ class TestHlslReferences: request_references is expected to return an empty list. """ - @pytest.mark.parametrize("language_server", [Language.HLSL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.HLSL], indirect=True) def test_references_not_supported(self, language_server: SolidLanguageServer) -> None: """References request should raise because shader-language-server does not support it. @@ -137,7 +137,7 @@ def _extract_hover_text(hover_info: dict[str, Any]) -> str: class TestHlslHover: """Tests for hover information.""" - @pytest.mark.parametrize("language_server", [Language.HLSL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.HLSL], indirect=True) def test_hover_on_function(self, language_server: SolidLanguageServer) -> None: """Hovering over SafeNormalize definition should return info. @@ -150,7 +150,7 @@ class TestHlslHover: hover_text = _extract_hover_text(hover_info) assert len(hover_text) > 0, "Hover text should not be empty" - @pytest.mark.parametrize("language_server", [Language.HLSL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.HLSL], indirect=True) def test_hover_on_struct(self, language_server: SolidLanguageServer) -> None: """Hovering over VertexInput should return struct info. @@ -161,7 +161,7 @@ class TestHlslHover: assert hover_info is not None, "Hover should return information for VertexInput" assert "contents" in hover_info, "Hover should have contents" - @pytest.mark.parametrize("language_server", [Language.HLSL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.HLSL], indirect=True) def test_bare_symbol_names(self, language_server) -> None: all_symbols = request_all_symbols(language_server) malformed_symbols = [] diff --git a/test/solidlsp/hlsl/test_hlsl_diagnostics.py b/test/solidlsp/hlsl/test_hlsl_diagnostics.py index e356d2da..bb25b349 100644 --- a/test/solidlsp/hlsl/test_hlsl_diagnostics.py +++ b/test/solidlsp/hlsl/test_hlsl_diagnostics.py @@ -1,13 +1,13 @@ import pytest from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from test.solidlsp.util.diagnostics import assert_file_diagnostics @pytest.mark.hlsl class TestHlslDiagnostics: - @pytest.mark.parametrize("language_server", [Language.HLSL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.HLSL], indirect=True) def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None: assert_file_diagnostics( language_server, diff --git a/test/solidlsp/hlsl/test_hlsl_full_index.py b/test/solidlsp/hlsl/test_hlsl_full_index.py index 70df1a61..391d1fbb 100644 --- a/test/solidlsp/hlsl/test_hlsl_full_index.py +++ b/test/solidlsp/hlsl/test_hlsl_full_index.py @@ -11,7 +11,7 @@ from typing import Any import pytest from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from solidlsp.ls_types import SymbolKind from solidlsp.ls_utils import SymbolUtils @@ -36,7 +36,7 @@ TERRAIN_SDF_UNIQUE_SYMBOLS = {"SampleSDF", "CalculateGradient", "SDFBrickData"} class TestHlslFullIndex: """Tests for full symbol tree indexing completeness.""" - @pytest.mark.parametrize("language_server", [Language.HLSL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.HLSL], indirect=True) def test_all_files_indexed_in_symbol_tree(self, language_server: SolidLanguageServer) -> None: """Every .hlsl file in the test repo must appear as a File symbol in the tree.""" symbols = language_server.request_full_symbol_tree() @@ -44,7 +44,7 @@ class TestHlslFullIndex: missing = EXPECTED_FILES - file_names assert not missing, f"Files missing from full symbol tree: {missing}. Found: {file_names}" - @pytest.mark.parametrize("language_server", [Language.HLSL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.HLSL], indirect=True) def test_subdirectory_file_symbols_present(self, language_server: SolidLanguageServer) -> None: """Symbols unique to terrain/terrain_sdf.hlsl must appear in the full tree.""" symbols = language_server.request_full_symbol_tree() @@ -53,7 +53,7 @@ class TestHlslFullIndex: f"Expected '{name}' from terrain/terrain_sdf.hlsl in full symbol tree" ) - @pytest.mark.parametrize("language_server", [Language.HLSL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.HLSL], indirect=True) def test_include_file_document_symbols_directly(self, language_server: SolidLanguageServer) -> None: """request_document_symbols on terrain/terrain_sdf.hlsl should return its symbols.""" doc_symbols = language_server.request_document_symbols("terrain/terrain_sdf.hlsl") diff --git a/test/solidlsp/html_ls/test_html_basic.py b/test/solidlsp/html_ls/test_html_basic.py index 1a3444ef..d83a2d26 100644 --- a/test/solidlsp/html_ls/test_html_basic.py +++ b/test/solidlsp/html_ls/test_html_basic.py @@ -11,7 +11,7 @@ from pathlib import Path import pytest from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from test.solidlsp.conftest import request_all_symbols @@ -19,13 +19,13 @@ from test.solidlsp.conftest import request_all_symbols class TestHtmlLanguageServerBasics: """Smoke + symbol tests for the HTML language server.""" - @pytest.mark.parametrize("language_server", [Language.HTML], indirect=True) - @pytest.mark.parametrize("repo_path", [Language.HTML], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.HTML], indirect=True) + @pytest.mark.parametrize("repo_path", [LanguageServerId.HTML], indirect=True) def test_ls_is_running(self, language_server: SolidLanguageServer, repo_path: Path) -> None: assert language_server.is_running() assert Path(language_server.language_server.repository_root_path).resolve() == repo_path.resolve() - @pytest.mark.parametrize("language_server", [Language.HTML], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.HTML], indirect=True) def test_index_document_symbols(self, language_server: SolidLanguageServer) -> None: """The HTML LSP exposes elements/IDs as document symbols.""" all_symbols, _ = language_server.request_document_symbols("index.html").get_all_symbols_and_roots() @@ -38,7 +38,7 @@ class TestHtmlLanguageServerBasics: for expected_id in ("page-header", "site-title", "main-nav", "section-features", "feature-list", "page-footer"): assert expected_id in joined, f"Expected id '{expected_id}' to appear in HTML symbols: {names}" - @pytest.mark.parametrize("language_server", [Language.HTML], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.HTML], indirect=True) def test_about_document_symbols(self, language_server: SolidLanguageServer) -> None: all_symbols, _ = language_server.request_document_symbols("about.html").get_all_symbols_and_roots() names = [s["name"] for s in all_symbols] @@ -46,7 +46,7 @@ class TestHtmlLanguageServerBasics: for expected_id in ("page-header", "about-title", "main-nav", "about-article"): assert expected_id in joined, f"Expected id '{expected_id}' to appear in HTML symbols: {names}" - @pytest.mark.parametrize("language_server", [Language.HTML], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.HTML], indirect=True) def test_full_symbol_tree_includes_both_files(self, language_server: SolidLanguageServer) -> None: all_symbols = request_all_symbols(language_server) relative_paths = {s.get("location", {}).get("relativePath") for s in all_symbols} diff --git a/test/solidlsp/html_ls/test_html_diagnostics.py b/test/solidlsp/html_ls/test_html_diagnostics.py index 7fb7df26..5affa597 100644 --- a/test/solidlsp/html_ls/test_html_diagnostics.py +++ b/test/solidlsp/html_ls/test_html_diagnostics.py @@ -16,12 +16,12 @@ diagnostic request, which is the practical purpose for this LS. import pytest from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId @pytest.mark.html class TestHtmlDiagnostics: - @pytest.mark.parametrize("language_server", [Language.HTML], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.HTML], indirect=True) def test_diagnostics_endpoint_returns_list(self, language_server: SolidLanguageServer) -> None: diagnostics = language_server.request_text_document_diagnostics("diagnostics_sample.html", min_severity=1) assert isinstance(diagnostics, list), diagnostics diff --git a/test/solidlsp/java/test_java_basic.py b/test/solidlsp/java/test_java_basic.py index b9b78d84..6517a47e 100644 --- a/test/solidlsp/java/test_java_basic.py +++ b/test/solidlsp/java/test_java_basic.py @@ -3,28 +3,28 @@ import os import pytest from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from solidlsp.ls_utils import SymbolUtils from test.conftest import ( find_identifier_position, get_repo_path, - language_has_verified_implementation_support, - language_tests_enabled, + language_server_tests_enabled, + ls_has_verified_implementation_support, ) from test.solidlsp.conftest import format_symbol_for_assert, has_malformed_name, request_all_symbols -pytestmark = [pytest.mark.java, pytest.mark.skipif(not language_tests_enabled(Language.JAVA), reason="Java tests disabled")] +pytestmark = [pytest.mark.java, pytest.mark.skipif(not language_server_tests_enabled(LanguageServerId.JAVA), reason="Java tests disabled")] class TestJavaLanguageServer: - @pytest.mark.parametrize("language_server", [Language.JAVA], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.JAVA], indirect=True) def test_find_symbol(self, language_server: SolidLanguageServer) -> None: symbols = language_server.request_full_symbol_tree() assert SymbolUtils.symbol_tree_contains_name(symbols, "Main"), "Main class not found in symbol tree" assert SymbolUtils.symbol_tree_contains_name(symbols, "Utils"), "Utils class not found in symbol tree" assert SymbolUtils.symbol_tree_contains_name(symbols, "Model"), "Model class not found in symbol tree" - @pytest.mark.parametrize("language_server", [Language.JAVA], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.JAVA], indirect=True) def test_find_referencing_symbols(self, language_server: SolidLanguageServer) -> None: # Use correct Maven/Java file paths file_path = os.path.join("src", "main", "java", "test_repo", "Utils.java") @@ -50,18 +50,18 @@ class TestJavaLanguageServer: "Main should reference Model (tried all positions in selectionRange)" ) - @pytest.mark.parametrize("language_server", [Language.JAVA], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.JAVA], indirect=True) def test_overview_methods(self, language_server: SolidLanguageServer) -> None: symbols = language_server.request_full_symbol_tree() assert SymbolUtils.symbol_tree_contains_name(symbols, "Main"), "Main missing from overview" assert SymbolUtils.symbol_tree_contains_name(symbols, "Utils"), "Utils missing from overview" assert SymbolUtils.symbol_tree_contains_name(symbols, "Model"), "Model missing from overview" - if language_has_verified_implementation_support(Language.JAVA): + if ls_has_verified_implementation_support(LanguageServerId.JAVA): - @pytest.mark.parametrize("language_server", [Language.JAVA], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.JAVA], indirect=True) def test_find_implementations(self, language_server: SolidLanguageServer) -> None: - repo_path = get_repo_path(Language.JAVA) + repo_path = get_repo_path(LanguageServerId.JAVA) pos = find_identifier_position(repo_path / "src/main/java/test_repo/Greeter.java", "formatGreeting") assert pos is not None, "Could not find Greeter.formatGreeting in fixture" @@ -71,9 +71,9 @@ class TestJavaLanguageServer: f"Expected ConsoleGreeter.formatGreeting in implementations, got: {implementations}" ) - @pytest.mark.parametrize("language_server", [Language.JAVA], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.JAVA], indirect=True) def test_request_implementing_symbols(self, language_server: SolidLanguageServer) -> None: - repo_path = get_repo_path(Language.JAVA) + repo_path = get_repo_path(LanguageServerId.JAVA) pos = find_identifier_position(repo_path / "src/main/java/test_repo/Greeter.java", "formatGreeting") assert pos is not None, "Could not find Greeter.formatGreeting in fixture" @@ -84,7 +84,7 @@ class TestJavaLanguageServer: for symbol in implementing_symbols ), f"Expected ConsoleGreeter.formatGreeting symbol, got: {implementing_symbols}" - @pytest.mark.parametrize("language_server", [Language.JAVA], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.JAVA], indirect=True) def test_bare_symbol_names(self, language_server) -> None: all_symbols = request_all_symbols(language_server) malformed_symbols = [] @@ -97,7 +97,7 @@ class TestJavaLanguageServer: pytrace=False, ) - @pytest.mark.parametrize("language_server", [Language.JAVA], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.JAVA], indirect=True) def test_lombok_generated_methods_visible_by_default(self, language_server: SolidLanguageServer) -> None: """Generated Lombok methods must appear in document symbols across the common annotations. diff --git a/test/solidlsp/java/test_java_diagnostics.py b/test/solidlsp/java/test_java_diagnostics.py index ebd59457..c79de2dc 100644 --- a/test/solidlsp/java/test_java_diagnostics.py +++ b/test/solidlsp/java/test_java_diagnostics.py @@ -1,13 +1,13 @@ import pytest from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from test.solidlsp.util.diagnostics import assert_file_diagnostics @pytest.mark.java class TestJavaDiagnostics: - @pytest.mark.parametrize("language_server", [Language.JAVA], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.JAVA], indirect=True) def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None: assert_file_diagnostics( language_server, diff --git a/test/solidlsp/json_ls/test_json_basic.py b/test/solidlsp/json_ls/test_json_basic.py index c2e8031a..b2753f9b 100644 --- a/test/solidlsp/json_ls/test_json_basic.py +++ b/test/solidlsp/json_ls/test_json_basic.py @@ -10,7 +10,7 @@ from pathlib import Path import pytest from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from test.solidlsp.conftest import format_symbol_for_assert, has_malformed_name, request_all_symbols @@ -18,17 +18,17 @@ from test.solidlsp.conftest import format_symbol_for_assert, has_malformed_name, class TestJsonLanguageServerBasics: """Test basic functionality of the JSON language server.""" - @pytest.mark.parametrize("language_server", [Language.JSON], indirect=True) - @pytest.mark.parametrize("repo_path", [Language.JSON], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.JSON], indirect=True) + @pytest.mark.parametrize("repo_path", [LanguageServerId.JSON], indirect=True) def test_json_language_server_initialization(self, language_server: SolidLanguageServer, repo_path: Path) -> None: """Test that JSON language server can be initialized successfully.""" assert language_server is not None - assert language_server.language == Language.JSON + assert language_server.ls_id == LanguageServerId.JSON assert language_server.is_running() assert Path(language_server.language_server.repository_root_path).resolve() == repo_path.resolve() - @pytest.mark.parametrize("language_server", [Language.JSON], indirect=True) - @pytest.mark.parametrize("repo_path", [Language.JSON], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.JSON], indirect=True) + @pytest.mark.parametrize("repo_path", [LanguageServerId.JSON], indirect=True) def test_json_config_file_symbols(self, language_server: SolidLanguageServer, repo_path: Path) -> None: """Test document symbols detection in config.json with specific symbol verification.""" all_symbols, root_symbols = language_server.request_document_symbols("config.json").get_all_symbols_and_roots() @@ -47,8 +47,8 @@ class TestJsonLanguageServerBasics: assert "port" in symbol_names, "Should detect nested 'port' key" assert "debug" in symbol_names, "Should detect nested 'debug' key" - @pytest.mark.parametrize("language_server", [Language.JSON], indirect=True) - @pytest.mark.parametrize("repo_path", [Language.JSON], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.JSON], indirect=True) + @pytest.mark.parametrize("repo_path", [LanguageServerId.JSON], indirect=True) def test_json_data_file_symbols(self, language_server: SolidLanguageServer, repo_path: Path) -> None: """Test symbol detection in data.json with array structures.""" all_symbols, root_symbols = language_server.request_document_symbols("data.json").get_all_symbols_and_roots() @@ -63,7 +63,7 @@ class TestJsonLanguageServerBasics: assert "email" in symbol_names, "Should detect 'email' fields" assert "id" in symbol_names, "Should detect 'id' fields" - @pytest.mark.parametrize("language_server", [Language.JSON], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.JSON], indirect=True) def test_bare_symbol_names(self, language_server: SolidLanguageServer) -> None: """Test that symbol names do not contain malformed characters.""" all_symbols = request_all_symbols(language_server) diff --git a/test/solidlsp/json_ls/test_json_diagnostics.py b/test/solidlsp/json_ls/test_json_diagnostics.py index 7850083a..d3e3c40e 100644 --- a/test/solidlsp/json_ls/test_json_diagnostics.py +++ b/test/solidlsp/json_ls/test_json_diagnostics.py @@ -1,13 +1,13 @@ import pytest from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from test.solidlsp.util.diagnostics import assert_file_diagnostics @pytest.mark.json class TestJsonDiagnostics: - @pytest.mark.parametrize("language_server", [Language.JSON], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.JSON], indirect=True) def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None: assert_file_diagnostics( language_server, diff --git a/test/solidlsp/julia/test_julia_basic.py b/test/solidlsp/julia/test_julia_basic.py index 75b81abf..acd5375b 100644 --- a/test/solidlsp/julia/test_julia_basic.py +++ b/test/solidlsp/julia/test_julia_basic.py @@ -1,16 +1,16 @@ import pytest from solidlsp.ls import SolidLanguageServer -from solidlsp.ls_config import Language -from test.conftest import language_tests_enabled +from solidlsp.ls_config import LanguageServerId +from test.conftest import language_server_tests_enabled 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(not language_tests_enabled(Language.JULIA), reason="Julia tests are disabled (julia not available)") +@pytest.mark.skipif(not language_server_tests_enabled(LanguageServerId.JULIA), reason="Julia tests are disabled (julia not available)") @pytest.mark.julia class TestJuliaLanguageServer: - @pytest.mark.parametrize("language_server", [Language.JULIA], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.JULIA], indirect=True) def test_julia_symbols(self, language_server: SolidLanguageServer): """ Test if we can find the top-level symbols in the main.jl file. @@ -20,7 +20,7 @@ class TestJuliaLanguageServer: assert "calculate_sum" in symbol_names assert "main" in symbol_names - @pytest.mark.parametrize("language_server", [Language.JULIA], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.JULIA], indirect=True) def test_julia_within_file_references(self, language_server: SolidLanguageServer): """ Test finding references to a function within the same file. @@ -36,7 +36,7 @@ class TestJuliaLanguageServer: reference_paths = [ref["relativePath"] for ref in references] assert "main.jl" in reference_paths - @pytest.mark.parametrize("language_server", [Language.JULIA], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.JULIA], indirect=True) def test_julia_cross_file_references(self, language_server: SolidLanguageServer): """ Test finding references to a function defined in another file. @@ -53,7 +53,7 @@ class TestJuliaLanguageServer: # The reference might be in either file (definition or usage) assert "main.jl" in reference_paths or "lib/helper.jl" in reference_paths - @pytest.mark.parametrize("language_server", [Language.JULIA], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.JULIA], indirect=True) def test_bare_symbol_names(self, language_server) -> None: all_symbols = request_all_symbols(language_server) malformed_symbols = [] @@ -66,7 +66,7 @@ class TestJuliaLanguageServer: pytrace=False, ) - @pytest.mark.parametrize("language_server", [Language.JULIA], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.JULIA], indirect=True) def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None: assert_file_diagnostics( language_server, diff --git a/test/solidlsp/kotlin/test_kotlin_basic.py b/test/solidlsp/kotlin/test_kotlin_basic.py index 0ce7a61f..d903a06d 100644 --- a/test/solidlsp/kotlin/test_kotlin_basic.py +++ b/test/solidlsp/kotlin/test_kotlin_basic.py @@ -3,10 +3,10 @@ import os import pytest from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from solidlsp.ls_types import SymbolKind from solidlsp.ls_utils import SymbolUtils -from test.conftest import language_tests_enabled +from test.conftest import language_server_tests_enabled from test.solidlsp.conftest import format_symbol_for_assert, has_malformed_name, request_all_symbols @@ -14,17 +14,17 @@ from test.solidlsp.conftest import format_symbol_for_assert, has_malformed_name, # (2 CPUs, 7GB RAM). First start succeeds but subsequent starts fail with cancelled (-32800). # Tests pass reliably on developer machines. See PR #1061 for investigation details. # (The CI quarantine lives centrally in test/conftest.py::_determine_disabled_languages.) -@pytest.mark.skipif(not language_tests_enabled(Language.KOTLIN), reason="Kotlin tests are disabled") +@pytest.mark.skipif(not language_server_tests_enabled(LanguageServerId.KOTLIN), reason="Kotlin tests are disabled") @pytest.mark.kotlin class TestKotlinLanguageServer: - @pytest.mark.parametrize("language_server", [Language.KOTLIN], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.KOTLIN], indirect=True) def test_find_symbol(self, language_server: SolidLanguageServer) -> None: symbols = language_server.request_full_symbol_tree() assert SymbolUtils.symbol_tree_contains_name(symbols, "Main"), "Main class not found in symbol tree" assert SymbolUtils.symbol_tree_contains_name(symbols, "Utils"), "Utils class not found in symbol tree" assert SymbolUtils.symbol_tree_contains_name(symbols, "Model"), "Model class not found in symbol tree" - @pytest.mark.parametrize("language_server", [Language.KOTLIN], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.KOTLIN], indirect=True) def test_find_referencing_symbols(self, language_server: SolidLanguageServer) -> None: # Use correct Kotlin file paths file_path = os.path.join("src", "main", "kotlin", "test_repo", "Utils.kt") @@ -52,14 +52,14 @@ class TestKotlinLanguageServer: "Main should reference Model (tried all positions in selectionRange)" ) - @pytest.mark.parametrize("language_server", [Language.KOTLIN], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.KOTLIN], indirect=True) def test_overview_methods(self, language_server: SolidLanguageServer) -> None: symbols = language_server.request_full_symbol_tree() assert SymbolUtils.symbol_tree_contains_name(symbols, "Main"), "Main missing from overview" assert SymbolUtils.symbol_tree_contains_name(symbols, "Utils"), "Utils missing from overview" assert SymbolUtils.symbol_tree_contains_name(symbols, "Model"), "Model missing from overview" - @pytest.mark.parametrize("language_server", [Language.KOTLIN], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.KOTLIN], indirect=True) def test_bare_symbol_names(self, language_server) -> None: all_symbols = request_all_symbols(language_server) malformed_symbols = [] diff --git a/test/solidlsp/kotlin/test_kotlin_diagnostics.py b/test/solidlsp/kotlin/test_kotlin_diagnostics.py index c189825f..c981add4 100644 --- a/test/solidlsp/kotlin/test_kotlin_diagnostics.py +++ b/test/solidlsp/kotlin/test_kotlin_diagnostics.py @@ -1,13 +1,13 @@ import pytest from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from test.solidlsp.util.diagnostics import assert_file_diagnostics @pytest.mark.kotlin class TestKotlinDiagnostics: - @pytest.mark.parametrize("language_server", [Language.KOTLIN], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.KOTLIN], indirect=True) def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None: assert_file_diagnostics( language_server, diff --git a/test/solidlsp/latex/test_latex_basic.py b/test/solidlsp/latex/test_latex_basic.py index 36cc67df..d8734e73 100644 --- a/test/solidlsp/latex/test_latex_basic.py +++ b/test/solidlsp/latex/test_latex_basic.py @@ -4,14 +4,14 @@ import pytest from serena.symbol import LanguageServerSymbol from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId @pytest.mark.latex class TestLatexLanguageServerBasics: """Basic functionality of the LaTeX (texlab) language server.""" - @pytest.mark.parametrize("language_server", [Language.LATEX], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.LATEX], indirect=True) def test_document_symbols_are_sections(self, language_server: SolidLanguageServer) -> None: """Sectioning commands should surface as document symbols.""" symbols, _roots = language_server.request_document_symbols("main.tex").get_all_symbols_and_roots() @@ -21,14 +21,14 @@ class TestLatexLanguageServerBasics: for expected in ("Introduction", "Methods", "Conclusion"): assert expected in names, f"Expected section '{expected}' among document symbols, got: {sorted(names)}" - @pytest.mark.parametrize("language_server", [Language.LATEX], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.LATEX], indirect=True) def test_subsection_symbol_present(self, language_server: SolidLanguageServer) -> None: """A nested subsection should also be exposed as a symbol.""" symbols, _roots = language_server.request_document_symbols("main.tex").get_all_symbols_and_roots() names = {s.get("name", "") for s in symbols} assert "Implementation Details" in names, f"Expected the subsection symbol, got: {sorted(names)}" - @pytest.mark.parametrize("language_server", [Language.LATEX], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.LATEX], indirect=True) def test_subsection_name_path_nests_under_section(self, language_server: SolidLanguageServer) -> None: """A subsection's name path nests under its parent section ("section/subsection").""" _symbols, roots = language_server.request_document_symbols("main.tex").get_all_symbols_and_roots() diff --git a/test/solidlsp/latex/test_latex_beamer.py b/test/solidlsp/latex/test_latex_beamer.py index adc6daea..54819e78 100644 --- a/test/solidlsp/latex/test_latex_beamer.py +++ b/test/solidlsp/latex/test_latex_beamer.py @@ -8,7 +8,7 @@ import pytest from serena.util.text_utils import find_text_coordinates from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from solidlsp.ls_types import Location from test.solidlsp.conftest import read_repo_file @@ -25,7 +25,7 @@ def _rel(location: Location) -> str: class TestLatexBeamer: """texlab handling of a beamer presentation (sections and frames).""" - @pytest.mark.parametrize("language_server", [Language.LATEX], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.LATEX], indirect=True) def test_beamer_sections_and_frames_are_symbols(self, language_server: SolidLanguageServer) -> None: r"""Beamer sections and ``\frametitle`` frames both surface as document symbols.""" symbols, _roots = language_server.request_document_symbols(SLIDES).get_all_symbols_and_roots() @@ -33,7 +33,7 @@ class TestLatexBeamer: for expected in ("Overview", "Results", "Frame: Introduction", "Frame: Methodology", "Frame: Findings"): assert expected in names, f"Expected beamer symbol {expected!r}, got: {sorted(names)}" - @pytest.mark.parametrize("language_server", [Language.LATEX], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.LATEX], indirect=True) def test_beamer_frames_nest_under_sections(self, language_server: SolidLanguageServer) -> None: r"""Frames are children of the section they appear in.""" _symbols, roots = language_server.request_document_symbols(SLIDES).get_all_symbols_and_roots() @@ -44,7 +44,7 @@ class TestLatexBeamer: overview_children = {child.get("name") for child in overview.get("children", [])} assert overview_children == {"Frame: Introduction", "Frame: Methodology"}, overview_children - @pytest.mark.parametrize("language_server", [Language.LATEX], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.LATEX], indirect=True) def test_beamer_frame_ref_resolves_to_section(self, language_server: SolidLanguageServer) -> None: r"""A ``\ref`` inside a beamer frame resolves to the section it targets.""" content = read_repo_file(language_server, SLIDES) diff --git a/test/solidlsp/latex/test_latex_references.py b/test/solidlsp/latex/test_latex_references.py index 0cfd1865..83012af5 100644 --- a/test/solidlsp/latex/test_latex_references.py +++ b/test/solidlsp/latex/test_latex_references.py @@ -10,7 +10,7 @@ import pytest from serena.util.text_utils import find_text_coordinates from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from solidlsp.ls_types import Location from test.solidlsp.conftest import read_repo_file @@ -35,7 +35,7 @@ def _rel(location: Location) -> str: class TestLatexReferences: """texlab reference/definition resolution within and across files.""" - @pytest.mark.parametrize("language_server", [Language.LATEX], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.LATEX], indirect=True) def test_within_file_ref_resolves_to_section(self, language_server: SolidLanguageServer) -> None: r"""A ``\ref`` resolves to the sectioning command labelled in the same file.""" ref = _coords(language_server, MAIN, r"forward to Section~\\ref\{(sec:methods)\}") @@ -47,7 +47,7 @@ class TestLatexReferences: assert _rel(definitions[0]) == "main.tex" assert definitions[0]["range"]["start"]["line"] == section.line - @pytest.mark.parametrize("language_server", [Language.LATEX], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.LATEX], indirect=True) def test_within_file_references_list_all_uses(self, language_server: SolidLanguageServer) -> None: r"""Requesting references on a within-file label returns both ``\ref`` uses.""" label = _coords(language_server, MAIN, r"\\label\{(sec:methods)\}") @@ -57,7 +57,7 @@ class TestLatexReferences: assert {_rel(ref) for ref in references} == {"main.tex"} assert len(references) == 2, references - @pytest.mark.parametrize("language_server", [Language.LATEX], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.LATEX], indirect=True) def test_cross_file_ref_resolves_across_files(self, language_server: SolidLanguageServer) -> None: r"""A ``\ref`` in main.tex resolves to a ``\label`` defined in another file.""" ref = _coords(language_server, MAIN, r"see Section~\\ref\{(sec:background)\}") @@ -69,7 +69,7 @@ class TestLatexReferences: assert _rel(definitions[0]) == "sections/background.tex" assert definitions[0]["range"]["start"]["line"] == section.line - @pytest.mark.parametrize("language_server", [Language.LATEX], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.LATEX], indirect=True) def test_cross_file_references_point_back_to_main(self, language_server: SolidLanguageServer) -> None: r"""References on a cross-file label include the ``\ref`` site in main.tex.""" label = _coords(language_server, BACKGROUND, r"\\label\{(sec:background)\}") @@ -79,7 +79,7 @@ class TestLatexReferences: assert any(_rel(ref) == "main.tex" and ref["range"]["start"]["line"] == ref_in_main.line for ref in references), references - @pytest.mark.parametrize("language_server", [Language.LATEX], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.LATEX], indirect=True) def test_citation_resolves_to_bib_entry(self, language_server: SolidLanguageServer) -> None: r"""A ``\cite`` resolves to its entry in the BibTeX file.""" cite = _coords(language_server, MAIN, r"Knuth~\\cite\{(knuth1984)\}") diff --git a/test/solidlsp/lean4/test_lean4_basic.py b/test/solidlsp/lean4/test_lean4_basic.py index bb4883cf..aff011a6 100644 --- a/test/solidlsp/lean4/test_lean4_basic.py +++ b/test/solidlsp/lean4/test_lean4_basic.py @@ -15,20 +15,22 @@ Test Repository Structure: import pytest from solidlsp.ls import SolidLanguageServer -from solidlsp.ls_config import Language -from test.conftest import language_tests_enabled +from solidlsp.ls_config import LanguageServerId +from test.conftest import language_server_tests_enabled -pytestmark = pytest.mark.skipif(not language_tests_enabled(Language.LEAN4), reason="Lean4 tests are disabled (lean not available)") +pytestmark = pytest.mark.skipif( + not language_server_tests_enabled(LanguageServerId.LEAN4), reason="Lean4 tests are disabled (lean not available)" +) @pytest.mark.lean4 class TestLean4LanguageServer: - @pytest.mark.parametrize("language_server", [Language.LEAN4], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.LEAN4], indirect=True) def test_ls_is_running(self, language_server: SolidLanguageServer) -> None: """Test that the Lean 4 language server starts successfully.""" assert language_server.is_running() - @pytest.mark.parametrize("language_server", [Language.LEAN4], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.LEAN4], indirect=True) def test_helper_symbols(self, language_server: SolidLanguageServer) -> None: """ Test symbol discovery in Helper.lean. @@ -51,7 +53,7 @@ class TestLean4LanguageServer: missing = expected_symbols - symbol_names assert not missing, f"Missing expected symbols in Helper.lean: {missing}" - @pytest.mark.parametrize("language_server", [Language.LEAN4], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.LEAN4], indirect=True) def test_main_symbols(self, language_server: SolidLanguageServer) -> None: """ Test symbol discovery in Main.lean. @@ -70,7 +72,7 @@ class TestLean4LanguageServer: missing = expected_symbols - symbol_names assert not missing, f"Missing expected symbols in Main.lean: {missing}" - @pytest.mark.parametrize("language_server", [Language.LEAN4], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.LEAN4], indirect=True) def test_within_file_references(self, language_server: SolidLanguageServer) -> None: """ Test within-file reference tracking for isPositive. @@ -89,7 +91,7 @@ class TestLean4LanguageServer: f"Expected isPositive reference at Helper.lean:15 (in absolute), got: {ref_locations}" ) - @pytest.mark.parametrize("language_server", [Language.LEAN4], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.LEAN4], indirect=True) def test_cross_file_references_add(self, language_server: SolidLanguageServer) -> None: """ Test cross-file reference tracking for add function. @@ -111,7 +113,7 @@ class TestLean4LanguageServer: f"Expected add references at Main.lean lines 7 or 15, got lines: {main_ref_lines}" ) - @pytest.mark.parametrize("language_server", [Language.LEAN4], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.LEAN4], indirect=True) def test_cross_file_references_calculator(self, language_server: SolidLanguageServer) -> None: """ Test cross-file reference tracking for Calculator structure. @@ -132,7 +134,7 @@ class TestLean4LanguageServer: f"Expected Calculator references at Main.lean lines 5 or 13, got lines: {main_ref_lines}" ) - @pytest.mark.parametrize("language_server", [Language.LEAN4], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.LEAN4], indirect=True) def test_go_to_definition_within_file(self, language_server: SolidLanguageServer) -> None: """ Test go-to-definition within a file. @@ -149,7 +151,7 @@ class TestLean4LanguageServer: assert def_location["uri"].endswith("Main.lean"), f"Expected definition in Main.lean, got: {def_location['uri']}" assert def_location["range"]["start"]["line"] == 5, f"Expected definition at line 5, got: {def_location['range']['start']['line']}" - @pytest.mark.parametrize("language_server", [Language.LEAN4], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.LEAN4], indirect=True) def test_go_to_definition_across_files(self, language_server: SolidLanguageServer) -> None: """ Test go-to-definition across files. diff --git a/test/solidlsp/lean4/test_lean4_diagnostics.py b/test/solidlsp/lean4/test_lean4_diagnostics.py index 11eac570..dcc19ac3 100644 --- a/test/solidlsp/lean4/test_lean4_diagnostics.py +++ b/test/solidlsp/lean4/test_lean4_diagnostics.py @@ -1,16 +1,18 @@ import pytest from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language -from test.conftest import language_tests_enabled +from solidlsp.ls_config import LanguageServerId +from test.conftest import language_server_tests_enabled from test.solidlsp.util.diagnostics import assert_file_diagnostics -pytestmark = pytest.mark.skipif(not language_tests_enabled(Language.LEAN4), reason="Lean4 tests are disabled (lean not available)") +pytestmark = pytest.mark.skipif( + not language_server_tests_enabled(LanguageServerId.LEAN4), reason="Lean4 tests are disabled (lean not available)" +) @pytest.mark.lean4 class TestLean4Diagnostics: - @pytest.mark.parametrize("language_server", [Language.LEAN4], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.LEAN4], indirect=True) def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None: assert_file_diagnostics( language_server, diff --git a/test/solidlsp/lua/test_lua_basic.py b/test/solidlsp/lua/test_lua_basic.py index 5465fda1..c70431af 100644 --- a/test/solidlsp/lua/test_lua_basic.py +++ b/test/solidlsp/lua/test_lua_basic.py @@ -8,9 +8,9 @@ for Lua modules and functions. import pytest from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from solidlsp.ls_types import SymbolKind -from test.conftest import find_identifier_position, get_repo_path, language_has_verified_implementation_support +from test.conftest import find_identifier_position, get_repo_path, ls_has_verified_implementation_support from test.solidlsp.conftest import format_symbol_for_assert, has_malformed_name, request_all_symbols @@ -18,7 +18,7 @@ from test.solidlsp.conftest import format_symbol_for_assert, has_malformed_name, class TestLuaLanguageServer: """Test Lua language server symbol finding and cross-file references.""" - @pytest.mark.parametrize("language_server", [Language.LUA], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.LUA], indirect=True) def test_find_symbols_in_calculator(self, language_server: SolidLanguageServer) -> None: """Test finding specific functions in calculator.lua.""" symbols = language_server.request_document_symbols("src/calculator.lua").get_all_symbols_and_roots() @@ -48,7 +48,7 @@ class TestLuaLanguageServer: assert "multiply" in function_names, "multiply function not found" assert "factorial" in function_names, "factorial function not found" - @pytest.mark.parametrize("language_server", [Language.LUA], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.LUA], indirect=True) def test_find_symbols_in_utils(self, language_server: SolidLanguageServer) -> None: """Test finding specific functions in utils.lua.""" symbols = language_server.request_document_symbols("src/utils.lua").get_all_symbols_and_roots() @@ -83,11 +83,11 @@ class TestLuaLanguageServer: # Check for Logger class/table assert "Logger" in all_symbols or any("Logger" in s for s in all_symbols), "Logger not found in symbols" - if language_has_verified_implementation_support(Language.LUA): + if ls_has_verified_implementation_support(LanguageServerId.LUA): - @pytest.mark.parametrize("language_server", [Language.LUA], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.LUA], indirect=True) def test_find_implementations(self, language_server: SolidLanguageServer) -> None: - repo_path = get_repo_path(Language.LUA) + repo_path = get_repo_path(LanguageServerId.LUA) pos = find_identifier_position(repo_path / "src" / "animals.lua", "speak") assert pos is not None, "Could not find Animal:speak in fixture" @@ -97,9 +97,9 @@ class TestLuaLanguageServer: f"Expected Dog:speak in implementations, got: {implementations}" ) - @pytest.mark.parametrize("language_server", [Language.LUA], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.LUA], indirect=True) def test_request_implementing_symbols(self, language_server: SolidLanguageServer) -> None: - repo_path = get_repo_path(Language.LUA) + repo_path = get_repo_path(LanguageServerId.LUA) pos = find_identifier_position(repo_path / "src" / "animals.lua", "speak") assert pos is not None, "Could not find Animal:speak in fixture" @@ -110,7 +110,7 @@ class TestLuaLanguageServer: for symbol in implementing_symbols ), f"Expected Dog:speak symbol, got: {implementing_symbols}" - @pytest.mark.parametrize("language_server", [Language.LUA], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.LUA], indirect=True) def test_find_symbols_in_main(self, language_server: SolidLanguageServer) -> None: """Test finding functions in main.lua.""" symbols = language_server.request_document_symbols("main.lua").get_all_symbols_and_roots() @@ -133,7 +133,7 @@ class TestLuaLanguageServer: assert "test_calculator" in function_names, "test_calculator function not found" assert "test_utils" in function_names, "test_utils function not found" - @pytest.mark.parametrize("language_server", [Language.LUA], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.LUA], indirect=True) def test_cross_file_references_calculator_add(self, language_server: SolidLanguageServer) -> None: """Test finding cross-file references to calculator.add function.""" symbols = language_server.request_document_symbols("src/calculator.lua").get_all_symbols_and_roots() @@ -189,7 +189,7 @@ class TestLuaLanguageServer: main_refs = [ref for ref in refs if "main.lua" in ref.get("uri", "")] assert len(main_refs) > 0, "calculator.add should be called in main.lua" - @pytest.mark.parametrize("language_server", [Language.LUA], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.LUA], indirect=True) def test_cross_file_references_utils_trim(self, language_server: SolidLanguageServer) -> None: """Test finding cross-file references to utils.trim function.""" symbols = language_server.request_document_symbols("src/utils.lua").get_all_symbols_and_roots() @@ -245,7 +245,7 @@ class TestLuaLanguageServer: main_refs = [ref for ref in refs if "main.lua" in ref.get("uri", "")] assert len(main_refs) > 0, "utils.trim should be called in main.lua" - @pytest.mark.parametrize("language_server", [Language.LUA], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.LUA], indirect=True) def test_hover_information(self, language_server: SolidLanguageServer) -> None: """Test hover information for symbols.""" # Get hover info for a function @@ -257,7 +257,7 @@ class TestLuaLanguageServer: if isinstance(hover_info, dict): assert "contents" in hover_info or "value" in hover_info, "Hover should have contents" - @pytest.mark.parametrize("language_server", [Language.LUA], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.LUA], indirect=True) def test_full_symbol_tree(self, language_server: SolidLanguageServer) -> None: """Test that full symbol tree is not empty.""" symbols = language_server.request_full_symbol_tree() @@ -270,7 +270,7 @@ class TestLuaLanguageServer: assert isinstance(root, dict), "Root should be a dict" assert "name" in root, "Root should have a name" - @pytest.mark.parametrize("language_server", [Language.LUA], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.LUA], indirect=True) def test_references_between_test_and_source(self, language_server: SolidLanguageServer) -> None: """Test finding references from test files to source files.""" # Check if test_calculator.lua references calculator module @@ -283,7 +283,7 @@ class TestLuaLanguageServer: symbol_list = test_symbols[0] if isinstance(test_symbols, tuple) else test_symbols assert len(symbol_list) > 0, "test_calculator.lua should have symbols" - @pytest.mark.parametrize("language_server", [Language.LUA], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.LUA], indirect=True) def test_bare_symbol_names(self, language_server) -> None: all_symbols = request_all_symbols(language_server) malformed_symbols = [] diff --git a/test/solidlsp/luau/test_luau_basic.py b/test/solidlsp/luau/test_luau_basic.py index 4564e257..2710c002 100644 --- a/test/solidlsp/luau/test_luau_basic.py +++ b/test/solidlsp/luau/test_luau_basic.py @@ -8,7 +8,7 @@ and cross-file reference capabilities for Luau modules and functions. import pytest from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from test.solidlsp.conftest import format_symbol_for_assert, has_malformed_name, request_all_symbols @@ -16,7 +16,7 @@ from test.solidlsp.conftest import format_symbol_for_assert, has_malformed_name, class TestLuauLanguageServer: """Test Luau language server symbol finding and cross-file references.""" - @pytest.mark.parametrize("language_server", [Language.LUAU], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.LUAU], indirect=True) def test_find_symbols_in_init(self, language_server: SolidLanguageServer) -> None: """Test finding specific functions in init.luau.""" symbols = language_server.request_document_symbols("src/init.luau").get_all_symbols_and_roots() @@ -34,7 +34,7 @@ class TestLuauLanguageServer: assert "createConfig" in symbol_names, f"createConfig not found in symbols: {symbol_names}" assert "main" in symbol_names, f"main not found in symbols: {symbol_names}" - @pytest.mark.parametrize("language_server", [Language.LUAU], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.LUAU], indirect=True) def test_find_symbols_in_module(self, language_server: SolidLanguageServer) -> None: """Test finding specific functions in module.luau.""" symbols = language_server.request_document_symbols("src/module.luau").get_all_symbols_and_roots() @@ -52,7 +52,7 @@ class TestLuauLanguageServer: assert "process" in symbol_names, f"process not found in symbols: {symbol_names}" assert "helper" in symbol_names, f"helper not found in symbols: {symbol_names}" - @pytest.mark.parametrize("language_server", [Language.LUAU], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.LUAU], indirect=True) def test_find_references_within_file(self, language_server: SolidLanguageServer) -> None: """Test finding within-file references to createConfig in init.luau. @@ -92,7 +92,7 @@ class TestLuauLanguageServer: assert "init.luau" in ref_files, f"Expected references in init.luau, found in: {ref_files}" - @pytest.mark.parametrize("language_server", [Language.LUAU], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.LUAU], indirect=True) def test_find_references_across_files(self, language_server: SolidLanguageServer) -> None: """Test finding cross-file references to process function. @@ -134,7 +134,7 @@ class TestLuauLanguageServer: # We expect at least the reference in module.luau return table (line 9) assert "module.luau" in ref_info, f"Expected references in module.luau, found in: {set(ref_info.keys())}" - @pytest.mark.parametrize("language_server", [Language.LUAU], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.LUAU], indirect=True) def test_find_definition(self, language_server: SolidLanguageServer) -> None: """Test finding definition of createConfig from its usage in main(). @@ -153,7 +153,7 @@ class TestLuauLanguageServer: # createConfig is defined at line 8 (0-indexed): `local function createConfig(...)` assert definition["range"]["start"]["line"] == 8, f"Definition should be at line 8, got line {definition['range']['start']['line']}" - @pytest.mark.parametrize("language_server", [Language.LUAU], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.LUAU], indirect=True) def test_bare_symbol_names(self, language_server) -> None: all_symbols = request_all_symbols(language_server) malformed_symbols = [] diff --git a/test/solidlsp/markdown/test_markdown_basic.py b/test/solidlsp/markdown/test_markdown_basic.py index 34f57533..337cf0c5 100644 --- a/test/solidlsp/markdown/test_markdown_basic.py +++ b/test/solidlsp/markdown/test_markdown_basic.py @@ -9,7 +9,7 @@ import pytest from serena.symbol import LanguageServerSymbol from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from solidlsp.ls_types import SymbolKind from test.solidlsp.conftest import format_symbol_for_assert, has_malformed_name, request_all_symbols @@ -18,13 +18,13 @@ from test.solidlsp.conftest import format_symbol_for_assert, has_malformed_name, class TestMarkdownLanguageServerBasics: """Test basic functionality of the markdown language server.""" - @pytest.mark.parametrize("language_server", [Language.MARKDOWN], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.MARKDOWN], indirect=True) def test_markdown_language_server_initialization(self, language_server: SolidLanguageServer) -> None: """Test that markdown language server can be initialized successfully.""" assert language_server is not None - assert language_server.language == Language.MARKDOWN + assert language_server.ls_id == LanguageServerId.MARKDOWN - @pytest.mark.parametrize("language_server", [Language.MARKDOWN], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.MARKDOWN], indirect=True) def test_markdown_request_document_symbols(self, language_server: SolidLanguageServer) -> None: """Test request_document_symbols for markdown files.""" all_symbols, _root_symbols = language_server.request_document_symbols("README.md").get_all_symbols_and_roots() @@ -40,7 +40,7 @@ class TestMarkdownLanguageServerBasics: f"Heading '{symbol['name']}' should have kind Namespace, got {SymbolKind(symbol['kind']).name}" ) - @pytest.mark.parametrize("language_server", [Language.MARKDOWN], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.MARKDOWN], indirect=True) def test_markdown_request_symbols_from_guide(self, language_server: SolidLanguageServer) -> None: """Test symbol detection in guide.md file.""" all_symbols, _root_symbols = language_server.request_document_symbols("guide.md").get_all_symbols_and_roots() @@ -48,7 +48,7 @@ class TestMarkdownLanguageServerBasics: # At least some headings should be found assert len(all_symbols) > 0, f"Should find headings in guide.md, found {len(all_symbols)}" - @pytest.mark.parametrize("language_server", [Language.MARKDOWN], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.MARKDOWN], indirect=True) def test_markdown_request_symbols_from_api(self, language_server: SolidLanguageServer) -> None: """Test symbol detection in api.md file.""" all_symbols, _root_symbols = language_server.request_document_symbols("api.md").get_all_symbols_and_roots() @@ -56,7 +56,7 @@ class TestMarkdownLanguageServerBasics: # Should detect headings from api.md assert len(all_symbols) > 0, f"Should find headings in api.md, found {len(all_symbols)}" - @pytest.mark.parametrize("language_server", [Language.MARKDOWN], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.MARKDOWN], indirect=True) def test_markdown_request_document_symbols_with_body(self, language_server: SolidLanguageServer) -> None: """Test request_document_symbols with body extraction.""" all_symbols, _root_symbols = language_server.request_document_symbols("README.md").get_all_symbols_and_roots() @@ -68,7 +68,7 @@ class TestMarkdownLanguageServerBasics: # This test is more lenient and just verifies the API works assert all_symbols is not None, "Should return symbols even if body extraction is limited" - @pytest.mark.parametrize("language_server", [Language.MARKDOWN], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.MARKDOWN], indirect=True) def test_markdown_headings_not_low_level(self, language_server: SolidLanguageServer) -> None: """Test that markdown headings are not classified as low-level symbols. @@ -84,7 +84,7 @@ class TestMarkdownLanguageServerBasics: f"Heading '{symbol['name']}' should not be low-level (kind={SymbolKind(symbol['kind']).name})" ) - @pytest.mark.parametrize("language_server", [Language.MARKDOWN], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.MARKDOWN], indirect=True) def test_markdown_nested_headings_remapped(self, language_server: SolidLanguageServer) -> None: """Test that nested headings (h1-h5) are all remapped from String to Namespace.""" all_symbols, _root_symbols = language_server.request_document_symbols("api.md").get_all_symbols_and_roots() @@ -95,7 +95,7 @@ class TestMarkdownLanguageServerBasics: for symbol in all_symbols: assert symbol["kind"] == SymbolKind.Namespace, f"Nested heading '{symbol['name']}' should be remapped to Namespace" - @pytest.mark.parametrize("language_server", [Language.MARKDOWN], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.MARKDOWN], indirect=True) def test_bare_symbol_names(self, language_server) -> None: all_symbols = request_all_symbols(language_server) malformed_symbols = [] diff --git a/test/solidlsp/matlab/test_matlab_basic.py b/test/solidlsp/matlab/test_matlab_basic.py index 4857a447..a019c6ca 100644 --- a/test/solidlsp/matlab/test_matlab_basic.py +++ b/test/solidlsp/matlab/test_matlab_basic.py @@ -13,8 +13,8 @@ Requirements: import pytest from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language -from test.conftest import language_tests_enabled +from solidlsp.ls_config import LanguageServerId +from test.conftest import language_server_tests_enabled from test.solidlsp.conftest import format_symbol_for_assert, has_malformed_name, request_all_symbols from test.solidlsp.util.diagnostics import assert_file_diagnostics @@ -22,17 +22,19 @@ from test.solidlsp.util.diagnostics import assert_file_diagnostics pytestmark = pytest.mark.matlab -@pytest.mark.skipif(not language_tests_enabled(Language.MATLAB), reason="MATLAB tests are disabled (MATLAB installation not found)") +@pytest.mark.skipif( + not language_server_tests_enabled(LanguageServerId.MATLAB), reason="MATLAB tests are disabled (MATLAB installation not found)" +) class TestMatlabLanguageServerBasics: """Test basic functionality of the MATLAB language server.""" - @pytest.mark.parametrize("language_server", [Language.MATLAB], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.MATLAB], indirect=True) def test_matlab_language_server_initialization(self, language_server: SolidLanguageServer) -> None: """Test that MATLAB language server can be initialized successfully.""" assert language_server is not None - assert language_server.language == Language.MATLAB + assert language_server.ls_id == LanguageServerId.MATLAB - @pytest.mark.parametrize("language_server", [Language.MATLAB], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.MATLAB], indirect=True) def test_matlab_request_document_symbols_class(self, language_server: SolidLanguageServer) -> None: """Test request_document_symbols for MATLAB class file.""" # Test getting symbols from Calculator.m (class file) @@ -54,7 +56,7 @@ class TestMatlabLanguageServerBasics: for method in expected_methods: assert method in method_names, f"Should find {method} method in Calculator class" - @pytest.mark.parametrize("language_server", [Language.MATLAB], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.MATLAB], indirect=True) def test_matlab_request_document_symbols_function(self, language_server: SolidLanguageServer) -> None: """Test request_document_symbols for MATLAB function file.""" # Test getting symbols from lib/mathUtils.m (function file) @@ -72,7 +74,7 @@ class TestMatlabLanguageServerBasics: for func in expected_local_functions: assert func in function_names, f"Should find {func} local function" - @pytest.mark.parametrize("language_server", [Language.MATLAB], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.MATLAB], indirect=True) def test_matlab_request_document_symbols_script(self, language_server: SolidLanguageServer) -> None: """Test request_document_symbols for MATLAB script file.""" # Test getting symbols from main.m (script file) @@ -83,11 +85,13 @@ class TestMatlabLanguageServerBasics: assert all_symbols is not None -@pytest.mark.skipif(not language_tests_enabled(Language.MATLAB), reason="MATLAB tests are disabled (MATLAB installation not found)") +@pytest.mark.skipif( + not language_server_tests_enabled(LanguageServerId.MATLAB), reason="MATLAB tests are disabled (MATLAB installation not found)" +) class TestMatlabLanguageServerReferences: """Test find references functionality of the MATLAB language server.""" - @pytest.mark.parametrize("language_server", [Language.MATLAB], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.MATLAB], indirect=True) def test_matlab_find_references_within_file(self, language_server: SolidLanguageServer) -> None: """Test finding references within a single MATLAB file.""" # Find references to 'result' variable in Calculator.m @@ -97,7 +101,7 @@ class TestMatlabLanguageServerReferences: # Should find at least the definition assert references is not None - @pytest.mark.parametrize("language_server", [Language.MATLAB], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.MATLAB], indirect=True) def test_matlab_find_references_cross_file(self, language_server: SolidLanguageServer) -> None: """Test finding references across MATLAB files.""" # Find references to Calculator class used in main.m @@ -106,7 +110,7 @@ class TestMatlabLanguageServerReferences: # Should find references in both main.m and Calculator.m assert references is not None - @pytest.mark.parametrize("language_server", [Language.MATLAB], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.MATLAB], indirect=True) def test_bare_symbol_names(self, language_server) -> None: all_symbols = request_all_symbols(language_server) malformed_symbols = [] @@ -119,7 +123,7 @@ class TestMatlabLanguageServerReferences: pytrace=False, ) - @pytest.mark.parametrize("language_server", [Language.MATLAB], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.MATLAB], indirect=True) def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None: assert_file_diagnostics( language_server, diff --git a/test/solidlsp/msl/test_msl_basic.py b/test/solidlsp/msl/test_msl_basic.py index 92a4cd41..be27ba9e 100644 --- a/test/solidlsp/msl/test_msl_basic.py +++ b/test/solidlsp/msl/test_msl_basic.py @@ -10,7 +10,7 @@ import os import pytest from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from test.solidlsp.conftest import format_symbol_for_assert, has_malformed_name, request_all_symbols pytestmark = [pytest.mark.msl] @@ -19,12 +19,12 @@ pytestmark = [pytest.mark.msl] class TestMslDocumentSymbols: """Test document symbol retrieval for mSL constructs.""" - @pytest.mark.parametrize("language_server", [Language.MSL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.MSL], indirect=True) def test_ls_is_running(self, language_server: SolidLanguageServer) -> None: """Test that the language server starts successfully.""" assert language_server.is_running() - @pytest.mark.parametrize("language_server", [Language.MSL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.MSL], indirect=True) def test_document_symbols_main(self, language_server: SolidLanguageServer) -> None: """Test that document symbols are returned for the main file.""" doc_symbols = language_server.request_document_symbols("main.mrc") @@ -35,7 +35,7 @@ class TestMslDocumentSymbols: assert "calculate.doubloons" in symbol_names, f"calculate.doubloons alias not found. Found: {symbol_names}" assert "show.player.info" in symbol_names, f"show.player.info alias not found. Found: {symbol_names}" - @pytest.mark.parametrize("language_server", [Language.MSL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.MSL], indirect=True) def test_document_symbols_events(self, language_server: SolidLanguageServer) -> None: """Test that event handlers, raw events, and menus are detected in the main file.""" doc_symbols = language_server.request_document_symbols("main.mrc") @@ -52,7 +52,7 @@ class TestMslDocumentSymbols: menus = [n for n in symbol_names if n.startswith("menu ")] assert len(menus) >= 1, f"Expected at least 1 menu. Found: {menus}" - @pytest.mark.parametrize("language_server", [Language.MSL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.MSL], indirect=True) def test_document_symbols_utils(self, language_server: SolidLanguageServer) -> None: """Test that document symbols are returned for the utils file.""" doc_symbols = language_server.request_document_symbols("utils.mrc") @@ -63,7 +63,7 @@ class TestMslDocumentSymbols: assert "is.admin" in symbol_names, f"is.admin alias not found. Found: {symbol_names}" assert "welcome.message" in symbol_names, f"welcome.message alias not found. Found: {symbol_names}" - @pytest.mark.parametrize("language_server", [Language.MSL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.MSL], indirect=True) def test_document_symbols_dialog_and_ctcp(self, language_server: SolidLanguageServer) -> None: """Test that dialog and CTCP handler definitions are detected.""" doc_symbols = language_server.request_document_symbols("utils.mrc") @@ -75,7 +75,7 @@ class TestMslDocumentSymbols: ctcp_events = [n for n in symbol_names if n.startswith("ctcp ")] assert len(ctcp_events) >= 1, f"Expected at least 1 ctcp handler. Found: {ctcp_events}" - @pytest.mark.parametrize("language_server", [Language.MSL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.MSL], indirect=True) def test_find_symbol(self, language_server: SolidLanguageServer) -> None: """Test that the full symbol tree contains expected symbols from both files.""" from solidlsp.ls_utils import SymbolUtils @@ -85,7 +85,7 @@ class TestMslDocumentSymbols: assert SymbolUtils.symbol_tree_contains_name(symbols, "format.coins"), "format.coins not found in symbol tree" assert SymbolUtils.symbol_tree_contains_name(symbols, "show.player.info"), "show.player.info not found in symbol tree" - @pytest.mark.parametrize("language_server", [Language.MSL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.MSL], indirect=True) def test_bare_symbol_names(self, language_server: SolidLanguageServer) -> None: """Test that symbol names do not contain unexpected formatting characters.""" all_symbols = request_all_symbols(language_server) @@ -101,7 +101,7 @@ class TestMslDocumentSymbols: pytrace=False, ) - @pytest.mark.parametrize("language_server", [Language.MSL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.MSL], indirect=True) def test_find_references_within_file(self, language_server: SolidLanguageServer) -> None: """Test that references to 'greet' are found within main.mrc.""" file_path = "main.mrc" @@ -126,7 +126,7 @@ class TestMslDocumentSymbols: call_site = {"uri_suffix": "main.mrc", "line": 13} assert call_site in actual_locations, f"Expected reference to greet at line 13 in main.mrc, got {actual_locations}" - @pytest.mark.parametrize("language_server", [Language.MSL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.MSL], indirect=True) def test_find_references_across_files(self, language_server: SolidLanguageServer) -> None: """Test that references to 'format.coins' are found across main.mrc and utils.mrc.""" # format.coins is defined in utils.mrc but called in both main.mrc and utils.mrc @@ -152,7 +152,7 @@ class TestMslDocumentSymbols: main_refs = [loc for loc in actual_locations if loc["uri_suffix"] == "main.mrc"] assert len(main_refs) >= 1, f"Expected at least 1 reference in main.mrc, got {main_refs}" - @pytest.mark.parametrize("language_server", [Language.MSL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.MSL], indirect=True) def test_workspace_symbol(self, language_server: SolidLanguageServer) -> None: """Test that workspace symbol search returns results.""" result = language_server.request_workspace_symbol("greet") diff --git a/test/solidlsp/nix/test_nix_basic.py b/test/solidlsp/nix/test_nix_basic.py index 789d047b..003a0e71 100644 --- a/test/solidlsp/nix/test_nix_basic.py +++ b/test/solidlsp/nix/test_nix_basic.py @@ -7,20 +7,22 @@ These tests validate symbol finding and cross-file reference capabilities for Ni import pytest from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from solidlsp.ls_types import SymbolKind -from test.conftest import is_ci, language_tests_enabled +from test.conftest import is_ci, language_server_tests_enabled from test.solidlsp.conftest import format_symbol_for_assert, has_malformed_name, request_all_symbols from test.solidlsp.util.diagnostics import assert_file_diagnostics -pytestmark = pytest.mark.skipif(not language_tests_enabled(Language.NIX), reason="Nix tests are disabled (nixd not available)") +pytestmark = pytest.mark.skipif( + not language_server_tests_enabled(LanguageServerId.NIX), reason="Nix tests are disabled (nixd not available)" +) @pytest.mark.nix class TestNixLanguageServer: """Test Nix language server symbol finding capabilities.""" - @pytest.mark.parametrize("language_server", [Language.NIX], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.NIX], indirect=True) def test_find_symbols_in_default_nix(self, language_server: SolidLanguageServer) -> None: """Test finding specific symbols in default.nix.""" symbols = language_server.request_document_symbols("default.nix").get_all_symbols_and_roots() @@ -40,7 +42,7 @@ class TestNixLanguageServer: found_attrs = symbol_names & expected_attrs assert found_attrs == expected_attrs, f"Expected exactly {expected_attrs}, found {found_attrs}" - @pytest.mark.parametrize("language_server", [Language.NIX], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.NIX], indirect=True) def test_find_symbols_in_utils(self, language_server: SolidLanguageServer) -> None: """Test finding symbols in lib/utils.nix.""" symbols = language_server.request_document_symbols("lib/utils.nix").get_all_symbols_and_roots() @@ -56,7 +58,7 @@ class TestNixLanguageServer: found_modules = symbol_names & expected_modules assert found_modules == expected_modules, f"Expected exactly {expected_modules}, found {found_modules}" - @pytest.mark.parametrize("language_server", [Language.NIX], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.NIX], indirect=True) def test_find_symbols_in_flake(self, language_server: SolidLanguageServer) -> None: """Test finding symbols in flake.nix.""" symbols = language_server.request_document_symbols("flake.nix").get_all_symbols_and_roots() @@ -70,7 +72,7 @@ class TestNixLanguageServer: # Flakes must have either inputs or outputs assert "inputs" in symbol_names or "outputs" in symbol_names, "Flake must have inputs or outputs" - @pytest.mark.parametrize("language_server", [Language.NIX], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.NIX], indirect=True) def test_find_symbols_in_module(self, language_server: SolidLanguageServer) -> None: """Test finding symbols in a NixOS module.""" symbols = language_server.request_document_symbols("modules/example.nix").get_all_symbols_and_roots() @@ -84,7 +86,7 @@ class TestNixLanguageServer: # NixOS modules must have either options or config assert "options" in symbol_names or "config" in symbol_names, "Module must have options or config" - @pytest.mark.parametrize("language_server", [Language.NIX], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.NIX], indirect=True) def test_find_references_within_file(self, language_server: SolidLanguageServer) -> None: """Test finding references within the same file.""" symbols = language_server.request_document_symbols("default.nix").get_all_symbols_and_roots() @@ -117,7 +119,7 @@ class TestNixLanguageServer: assert 66 in ref_lines, f"Should find makeGreeting inherit at line 67, found at lines {[l + 1 for l in ref_lines]}" @pytest.mark.xfail(is_ci, reason="Test is flaky") # TODO: Re-enable if the hover test becomes more stable (#1040) - @pytest.mark.parametrize("language_server", [Language.NIX], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.NIX], indirect=True) def test_hover_information(self, language_server: SolidLanguageServer) -> None: """Test hover information for symbols.""" # Get hover info for makeGreeting function @@ -129,7 +131,7 @@ class TestNixLanguageServer: # If hover info is provided, it should have proper structure assert "contents" in hover_info or "value" in hover_info, "Hover should have contents or value" - @pytest.mark.parametrize("language_server", [Language.NIX], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.NIX], indirect=True) def test_cross_file_references_utils_import(self, language_server: SolidLanguageServer) -> None: """Test finding cross-file references for imported utils.""" # Find references to 'utils' which is imported in default.nix from lib/utils.nix @@ -152,7 +154,7 @@ class TestNixLanguageServer: f"Should find utils import or usage, found references at lines {[l + 1 for l in ref_lines]}" ) - @pytest.mark.parametrize("language_server", [Language.NIX], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.NIX], indirect=True) def test_verify_imports_exist(self, language_server: SolidLanguageServer) -> None: """Verify that our test files have proper imports set up.""" # Verify that default.nix imports utils from lib/utils.nix @@ -175,7 +177,7 @@ class TestNixLanguageServer: assert "math" in utils_names, "math should be found in lib/utils.nix" assert "strings" in utils_names, "strings should be found in lib/utils.nix" - @pytest.mark.parametrize("language_server", [Language.NIX], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.NIX], indirect=True) def test_go_to_definition_cross_file(self, language_server: SolidLanguageServer) -> None: """Test go-to-definition from default.nix to lib/utils.nix.""" # Line 24 in default.nix: unique = utils.lists.unique; @@ -191,7 +193,7 @@ class TestNixLanguageServer: "Definition should relate to utils import or utils.nix file" ) - @pytest.mark.parametrize("language_server", [Language.NIX], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.NIX], indirect=True) def test_definition_navigation_in_flake(self, language_server: SolidLanguageServer) -> None: """Test definition navigation in flake.nix.""" # Test that we can navigate to definitions within flake.nix @@ -206,7 +208,7 @@ class TestNixLanguageServer: "Should find hello-custom definition in flake.nix" ) - @pytest.mark.parametrize("language_server", [Language.NIX], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.NIX], indirect=True) def test_full_symbol_tree(self, language_server: SolidLanguageServer) -> None: """Test that full symbol tree is not empty.""" symbols = language_server.request_full_symbol_tree() @@ -219,7 +221,7 @@ class TestNixLanguageServer: assert isinstance(root, dict), "Root should be a dict" assert "name" in root, "Root should have a name" - @pytest.mark.parametrize("language_server", [Language.NIX], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.NIX], indirect=True) def test_bare_symbol_names(self, language_server) -> None: all_symbols = request_all_symbols(language_server) malformed_symbols = [] @@ -249,7 +251,7 @@ class TestNixLanguageServer: pytrace=False, ) - @pytest.mark.parametrize("language_server", [Language.NIX], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.NIX], indirect=True) def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None: assert_file_diagnostics( language_server, diff --git a/test/solidlsp/ocaml/test_cross_file_refs.py b/test/solidlsp/ocaml/test_cross_file_refs.py index 44c72e49..056790db 100644 --- a/test/solidlsp/ocaml/test_cross_file_refs.py +++ b/test/solidlsp/ocaml/test_cross_file_refs.py @@ -13,16 +13,16 @@ import pytest from solidlsp import SolidLanguageServer from solidlsp.language_servers.ocaml_lsp_server import OcamlLanguageServer -from solidlsp.ls_config import Language -from test.conftest import language_tests_enabled +from solidlsp.ls_config import LanguageServerId +from test.conftest import language_server_tests_enabled log = logging.getLogger(__name__) -@pytest.mark.skipif(not language_tests_enabled(Language.OCAML), reason="OCaml tests are disabled (opam not available)") +@pytest.mark.skipif(not language_server_tests_enabled(LanguageServerId.OCAML), reason="OCaml tests are disabled (opam not available)") @pytest.mark.ocaml class TestCrossFileReferences: - @pytest.mark.parametrize("language_server", [Language.OCAML], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.OCAML], indirect=True) def test_fib_has_cross_file_references(self, language_server: SolidLanguageServer) -> None: """Test that fib function references are found across multiple files. diff --git a/test/solidlsp/ocaml/test_ocaml_basic.py b/test/solidlsp/ocaml/test_ocaml_basic.py index 86d3a874..c1a1298e 100644 --- a/test/solidlsp/ocaml/test_ocaml_basic.py +++ b/test/solidlsp/ocaml/test_ocaml_basic.py @@ -3,23 +3,23 @@ import os import pytest from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from solidlsp.ls_utils import SymbolUtils -from test.conftest import language_tests_enabled +from test.conftest import language_server_tests_enabled from test.solidlsp.conftest import format_symbol_for_assert, has_malformed_name, request_all_symbols -@pytest.mark.skipif(not language_tests_enabled(Language.OCAML), reason="OCaml tests are disabled (opam not available)") +@pytest.mark.skipif(not language_server_tests_enabled(LanguageServerId.OCAML), reason="OCaml tests are disabled (opam not available)") @pytest.mark.ocaml class TestOCamlLanguageServer: - @pytest.mark.parametrize("language_server", [Language.OCAML], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.OCAML], indirect=True) def test_find_symbol(self, language_server: SolidLanguageServer) -> None: symbols = language_server.request_full_symbol_tree() assert SymbolUtils.symbol_tree_contains_name(symbols, "DemoModule"), "DemoModule not found in symbol tree" assert SymbolUtils.symbol_tree_contains_name(symbols, "fib"), "fib not found in symbol tree" assert SymbolUtils.symbol_tree_contains_name(symbols, "someFunction"), "someFunction function not found in symbol tree" - @pytest.mark.parametrize("language_server", [Language.OCAML], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.OCAML], indirect=True) def test_find_referencing_symbols(self, language_server: SolidLanguageServer) -> None: file_path = os.path.join("lib", "test_repo.ml") @@ -38,7 +38,7 @@ class TestOCamlLanguageServer: lib_refs = [ref for ref in refs if "lib/test_repo.ml" in ref.get("uri", "")] assert len(lib_refs) >= 3, f"Expected at least 3 references in lib/test_repo.ml, found {len(lib_refs)}" - @pytest.mark.parametrize("language_server", [Language.OCAML], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.OCAML], indirect=True) def test_mixed_ocaml_modules(self, language_server: SolidLanguageServer) -> None: """Test that the language server can find symbols from OCaml modules""" # Test that full symbol tree includes symbols from various file types @@ -52,7 +52,7 @@ class TestOCamlLanguageServer: def test_reason_file_patterns(self) -> None: """Test that OCaml language configuration recognizes Reason file extensions""" - ocaml_lang = Language.OCAML + ocaml_lang = LanguageServerId.OCAML file_matcher = ocaml_lang.get_source_fn_matcher() # Test OCaml extensions @@ -67,7 +67,7 @@ class TestOCamlLanguageServer: assert not file_matcher.is_relevant_filename("test.py"), "Should not match .py files" assert not file_matcher.is_relevant_filename("test.js"), "Should not match .js files" - @pytest.mark.parametrize("language_server", [Language.OCAML], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.OCAML], indirect=True) def test_module_hierarchy_navigation(self, language_server: SolidLanguageServer) -> None: """Test navigation within module hierarchy including DemoModule.""" file_path = os.path.join("lib", "test_repo.ml") @@ -86,7 +86,7 @@ class TestOCamlLanguageServer: lib_refs = [ref for ref in refs if "lib/test_repo.ml" in ref.get("uri", "")] assert len(lib_refs) >= 1, f"Expected at least 1 reference in lib/test_repo.ml, found {len(lib_refs)}" - @pytest.mark.parametrize("language_server", [Language.OCAML], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.OCAML], indirect=True) def test_let_binding_references(self, language_server: SolidLanguageServer) -> None: """Test finding references to let-bound values across files.""" file_path = os.path.join("lib", "test_repo.ml") @@ -105,7 +105,7 @@ class TestOCamlLanguageServer: ml_refs = [ref for ref in refs if "lib/test_repo.ml" in ref.get("uri", "")] assert len(ml_refs) >= 1, f"Expected at least 1 reference in lib/test_repo.ml, found {len(ml_refs)}" - @pytest.mark.parametrize("language_server", [Language.OCAML], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.OCAML], indirect=True) def test_recursive_function_analysis(self, language_server: SolidLanguageServer) -> None: """Test that recursive function calls are properly identified within the definition file.""" file_path = os.path.join("lib", "test_repo.ml") @@ -130,7 +130,7 @@ class TestOCamlLanguageServer: unique_lines = len(set(ref_lines)) assert unique_lines >= 2, f"Recursive calls should appear on multiple lines, found {unique_lines} unique lines" - @pytest.mark.parametrize("language_server", [Language.OCAML], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.OCAML], indirect=True) def test_open_statement_resolution(self, language_server: SolidLanguageServer) -> None: """Test that open statements allow unqualified access to module contents.""" # In bin/main.ml, fib is called without Test_repo prefix due to 'open Test_repo' @@ -152,7 +152,7 @@ class TestOCamlLanguageServer: symbols, _roots = language_server.request_document_symbols(file_path).get_all_symbols_and_roots() assert len(symbols) > 0, "Should find symbols in main.ml that use opened modules" - @pytest.mark.parametrize("language_server", [Language.OCAML], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.OCAML], indirect=True) def test_bare_symbol_names(self, language_server) -> None: all_symbols = request_all_symbols(language_server) malformed_symbols = [] diff --git a/test/solidlsp/ocaml/test_ocaml_diagnostics.py b/test/solidlsp/ocaml/test_ocaml_diagnostics.py index 3817f225..dd8197b3 100644 --- a/test/solidlsp/ocaml/test_ocaml_diagnostics.py +++ b/test/solidlsp/ocaml/test_ocaml_diagnostics.py @@ -1,15 +1,15 @@ import pytest from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language -from test.conftest import language_tests_enabled +from solidlsp.ls_config import LanguageServerId +from test.conftest import language_server_tests_enabled from test.solidlsp.util.diagnostics import assert_file_diagnostics -@pytest.mark.skipif(not language_tests_enabled(Language.OCAML), reason="OCaml tests are disabled (opam not available)") +@pytest.mark.skipif(not language_server_tests_enabled(LanguageServerId.OCAML), reason="OCaml tests are disabled (opam not available)") @pytest.mark.ocaml class TestOcamlDiagnostics: - @pytest.mark.parametrize("language_server", [Language.OCAML], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.OCAML], indirect=True) def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None: assert_file_diagnostics( language_server, diff --git a/test/solidlsp/pascal/test_pascal_basic.py b/test/solidlsp/pascal/test_pascal_basic.py index e9636e94..74576459 100644 --- a/test/solidlsp/pascal/test_pascal_basic.py +++ b/test/solidlsp/pascal/test_pascal_basic.py @@ -15,14 +15,16 @@ import shutil import pytest from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from solidlsp.ls_types import SymbolKind -from test.conftest import is_ci, language_tests_enabled +from test.conftest import is_ci, language_server_tests_enabled from test.solidlsp.conftest import format_symbol_for_assert, has_malformed_name, request_all_symbols pytestmark = [ pytest.mark.pascal, - pytest.mark.skipif(not language_tests_enabled(Language.PASCAL), reason="Pascal tests are disabled (pasls/fpc not available)"), + pytest.mark.skipif( + not language_server_tests_enabled(LanguageServerId.PASCAL), reason="Pascal tests are disabled (pasls/fpc not available)" + ), ] @@ -31,13 +33,13 @@ pytestmark = [ class TestPascalLanguageServerBasics: """Test basic functionality of the Pascal language server.""" - @pytest.mark.parametrize("language_server", [Language.PASCAL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.PASCAL], indirect=True) def test_pascal_language_server_initialization(self, language_server: SolidLanguageServer) -> None: """Test that Pascal language server can be initialized successfully.""" assert language_server is not None - assert language_server.language == Language.PASCAL + assert language_server.ls_id == LanguageServerId.PASCAL - @pytest.mark.parametrize("language_server", [Language.PASCAL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.PASCAL], indirect=True) def test_pascal_request_document_symbols(self, language_server: SolidLanguageServer) -> None: """Test request_document_symbols for Pascal files. @@ -65,7 +67,7 @@ class TestPascalLanguageServerBasics: assert "TUser" in class_names, "Should find TUser class" assert "TUserManager" in class_names, "Should find TUserManager class" - @pytest.mark.parametrize("language_server", [Language.PASCAL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.PASCAL], indirect=True) def test_pascal_class_methods(self, language_server: SolidLanguageServer) -> None: """Test detection of class methods in Pascal files. @@ -89,7 +91,7 @@ class TestPascalLanguageServerBasics: found = method in method_names assert found, f"Should find method '{method}'" - @pytest.mark.parametrize("language_server", [Language.PASCAL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.PASCAL], indirect=True) def test_pascal_helper_unit_symbols(self, language_server: SolidLanguageServer) -> None: """Test function detection in Helper unit.""" # Test with lib/helper.pas @@ -113,7 +115,7 @@ class TestPascalLanguageServerBasics: assert "FormatString" in method_names, "Should find FormatString method" assert "IsEven" in method_names, "Should find IsEven method" - @pytest.mark.parametrize("language_server", [Language.PASCAL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.PASCAL], indirect=True) def test_pascal_cross_file_references(self, language_server: SolidLanguageServer) -> None: """Test that Pascal LSP can handle cross-file references.""" # main.pas uses Helper unit @@ -128,7 +130,7 @@ class TestPascalLanguageServerBasics: helper_function_names = [s["name"] for s in helper_symbols if s.get("kind") == SymbolKind.Function] assert "GetHelperMessage" in helper_function_names, "Helper unit should export GetHelperMessage" - @pytest.mark.parametrize("language_server", [Language.PASCAL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.PASCAL], indirect=True) def test_pascal_symbol_locations(self, language_server: SolidLanguageServer) -> None: """Test that symbols have correct location information. @@ -160,7 +162,7 @@ class TestPascalLanguageServerBasics: # genericptr pasls returns interface declaration location assert 35 <= line <= 45, f"CalculateSum should be around line 41 (interface), got {line}" - @pytest.mark.parametrize("language_server", [Language.PASCAL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.PASCAL], indirect=True) def test_pascal_namespace_symbol(self, language_server: SolidLanguageServer) -> None: """Test that genericptr pasls returns Interface namespace symbol.""" all_symbols, _root_symbols = language_server.request_document_symbols("main.pas").get_all_symbols_and_roots() @@ -174,7 +176,7 @@ class TestPascalLanguageServerBasics: # Interface namespace may or may not be present depending on pasls configuration _ = symbol_names # used for potential future assertions - @pytest.mark.parametrize("language_server", [Language.PASCAL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.PASCAL], indirect=True) def test_pascal_hover_with_doc_comments(self, language_server: SolidLanguageServer) -> None: """Test that hover returns documentation comments. @@ -198,7 +200,7 @@ class TestPascalLanguageServerBasics: # Should contain the doc comment assert "Calculates the sum" in value, f"Hover should include doc comment. Got: {value[:500]}" - @pytest.mark.parametrize("language_server", [Language.PASCAL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.PASCAL], indirect=True) def test_bare_symbol_names(self, language_server) -> None: all_symbols = request_all_symbols(language_server) malformed_symbols = [] diff --git a/test/solidlsp/pascal/test_pascal_diagnostics.py b/test/solidlsp/pascal/test_pascal_diagnostics.py index ad96a1ea..ac4b431c 100644 --- a/test/solidlsp/pascal/test_pascal_diagnostics.py +++ b/test/solidlsp/pascal/test_pascal_diagnostics.py @@ -3,19 +3,19 @@ import shutil import pytest from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language -from test.conftest import language_tests_enabled +from solidlsp.ls_config import LanguageServerId +from test.conftest import language_server_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(not language_server_tests_enabled(LanguageServerId.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) + @pytest.mark.parametrize("language_server", [LanguageServerId.PASCAL], indirect=True) def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None: assert_file_diagnostics( language_server, diff --git a/test/solidlsp/perl/test_perl_basic.py b/test/solidlsp/perl/test_perl_basic.py index f6e1bf66..6558d262 100644 --- a/test/solidlsp/perl/test_perl_basic.py +++ b/test/solidlsp/perl/test_perl_basic.py @@ -3,13 +3,13 @@ from pathlib import Path import pytest from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language -from test.conftest import language_tests_enabled +from solidlsp.ls_config import LanguageServerId +from test.conftest import language_server_tests_enabled from test.solidlsp.conftest import format_symbol_for_assert, has_malformed_name, request_all_symbols from test.solidlsp.util.diagnostics import assert_file_diagnostics pytestmark = pytest.mark.skipif( - not language_tests_enabled(Language.PERL), reason="Perl tests are disabled (Perl::LanguageServer not available)" + not language_server_tests_enabled(LanguageServerId.PERL), reason="Perl tests are disabled (Perl::LanguageServer not available)" ) @@ -24,15 +24,15 @@ class TestPerlLanguageServer: - Find references (including cross-file) - this was not available in PLS """ - @pytest.mark.parametrize("language_server", [Language.PERL], indirect=True) - @pytest.mark.parametrize("repo_path", [Language.PERL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.PERL], indirect=True) + @pytest.mark.parametrize("repo_path", [LanguageServerId.PERL], indirect=True) def test_ls_is_running(self, language_server: SolidLanguageServer, repo_path: Path) -> None: """Test that the language server starts and stops successfully.""" # The fixture already handles start and stop assert language_server.is_running() assert Path(language_server.language_server.repository_root_path).resolve() == repo_path.resolve() - @pytest.mark.parametrize("language_server", [Language.PERL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.PERL], indirect=True) def test_document_symbols(self, language_server: SolidLanguageServer) -> None: """Test that document symbols are correctly identified.""" # Request document symbols @@ -56,7 +56,7 @@ class TestPerlLanguageServer: assert "use_helper_function" in function_names, f"Expected 'use_helper_function' in symbols, found: {function_names}" # @pytest.mark.skip(reason="Perl::LanguageServer cross-file definition tracking needs configuration") - @pytest.mark.parametrize("language_server", [Language.PERL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.PERL], indirect=True) def test_find_definition_across_files(self, language_server: SolidLanguageServer) -> None: definition_location_list = language_server.request_definition("main.pl", 17, 0) @@ -66,7 +66,7 @@ class TestPerlLanguageServer: assert definition_location["uri"].endswith("helper.pl") assert definition_location["range"]["start"]["line"] == 4 # add method on line 2 (0-indexed 1) - @pytest.mark.parametrize("language_server", [Language.PERL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.PERL], indirect=True) def test_find_references_across_files(self, language_server: SolidLanguageServer) -> None: """Test finding references to a function across multiple files.""" reference_locations = language_server.request_references("helper.pl", 4, 5) @@ -80,7 +80,7 @@ class TestPerlLanguageServer: assert 17 in main_pl_lines, f"Expected reference at line 18 (0-indexed 17), found: {main_pl_lines}" assert 20 in main_pl_lines, f"Expected reference at line 21 (0-indexed 20), found: {main_pl_lines}" - @pytest.mark.parametrize("language_server", [Language.PERL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.PERL], indirect=True) def test_find_references_includes_t_files(self, language_server: SolidLanguageServer) -> None: """References to a .pm/.pl sub must surface callers in .t test files (fileFilter includes .t).""" reference_locations = language_server.request_references("helper.pl", 4, 5) @@ -88,7 +88,7 @@ class TestPerlLanguageServer: t_refs = [ref for ref in reference_locations if ref["uri"].endswith(".t")] assert t_refs, f"Expected at least one reference in a .t file, got: {[r['uri'] for r in reference_locations]}" - @pytest.mark.parametrize("language_server", [Language.PERL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.PERL], indirect=True) def test_bare_symbol_names(self, language_server) -> None: all_symbols = request_all_symbols(language_server) malformed_symbols = [] @@ -101,7 +101,7 @@ class TestPerlLanguageServer: pytrace=False, ) - @pytest.mark.parametrize("language_server", [Language.PERL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.PERL], indirect=True) def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None: assert_file_diagnostics( language_server, diff --git a/test/solidlsp/perl/test_perl_config.py b/test/solidlsp/perl/test_perl_config.py index 3b954d9d..c4ab9f44 100644 --- a/test/solidlsp/perl/test_perl_config.py +++ b/test/solidlsp/perl/test_perl_config.py @@ -18,7 +18,7 @@ from solidlsp.language_servers.perl_language_server import ( _DEFAULT_IGNORE_DIRS, PerlLanguageServer, ) -from solidlsp.ls_config import FilenameMatcher, Language +from solidlsp.ls_config import FilenameMatcher, LanguageServerId from solidlsp.settings import SolidLSPSettings @@ -40,7 +40,7 @@ class TestResolveFilterSettings: def test_defaults_when_perl_key_absent(self, tmp_path: Path) -> None: # ls_specific_settings configured for another language must not leak into Perl. - settings = _settings(tmp_path, {Language.PYTHON: {"something": "unrelated"}}) + settings = _settings(tmp_path, {LanguageServerId.PYTHON: {"something": "unrelated"}}) file_filter, ignore_dirs = PerlLanguageServer._resolve_filter_settings(settings) @@ -50,7 +50,7 @@ class TestResolveFilterSettings: def test_custom_file_filter_makes_extra_extensions_visible(self, tmp_path: Path) -> None: # #1449: a Perl web backend must be able to surface .cgi / .psgi handlers. custom = [".pm", ".pl", ".t", ".cgi", ".psgi"] - settings = _settings(tmp_path, {Language.PERL: {"file_filter": custom}}) + settings = _settings(tmp_path, {LanguageServerId.PERL: {"file_filter": custom}}) file_filter, _ = PerlLanguageServer._resolve_filter_settings(settings) @@ -59,7 +59,7 @@ class TestResolveFilterSettings: def test_custom_ignore_dirs(self, tmp_path: Path) -> None: custom = [".git", "blib", "local", "cover_db", "t"] - settings = _settings(tmp_path, {Language.PERL: {"ignore_dirs": custom}}) + settings = _settings(tmp_path, {LanguageServerId.PERL: {"ignore_dirs": custom}}) _, ignore_dirs = PerlLanguageServer._resolve_filter_settings(settings) @@ -70,7 +70,7 @@ class TestResolveFilterSettings: ignore_dirs = [".git", "vendor"] settings = _settings( tmp_path, - {Language.PERL: {"file_filter": file_filter, "ignore_dirs": ignore_dirs}}, + {LanguageServerId.PERL: {"file_filter": file_filter, "ignore_dirs": ignore_dirs}}, ) resolved_filter, resolved_dirs = PerlLanguageServer._resolve_filter_settings(settings) @@ -165,12 +165,12 @@ class TestSourceFnMatcherSync: # #1449: find_symbol relies on Language.PERL.get_source_fn_matcher(); unless the configured # extensions are synced into it, symbols in .cgi/.psgi files stay invisible even though the # LS indexes them. get_source_fn_matcher() is a @cache singleton, so reset() afterwards. - matcher = Language.PERL.get_source_fn_matcher() + matcher = LanguageServerId.PERL.get_source_fn_matcher() try: assert not matcher.is_relevant_filename("handler.cgi") # guard: not matched by default file_filter, _ = PerlLanguageServer._resolve_filter_settings( - _settings(tmp_path, {Language.PERL: {"file_filter": [".pm", ".pl", ".t", ".cgi", ".psgi"]}}) + _settings(tmp_path, {LanguageServerId.PERL: {"file_filter": [".pm", ".pl", ".t", ".cgi", ".psgi"]}}) ) PerlLanguageServer._sync_source_fn_matcher(file_filter) @@ -183,7 +183,7 @@ class TestSourceFnMatcherSync: def test_default_file_filter_leaves_matcher_unchanged(self, tmp_path: Path) -> None: # The default file_filter matches the existing Perl matcher extensions, so syncing it must # be a no-op (no duplicate entries, no new matches). - matcher = Language.PERL.get_source_fn_matcher() + matcher = LanguageServerId.PERL.get_source_fn_matcher() try: initial = list(matcher._file_extensions) file_filter, _ = PerlLanguageServer._resolve_filter_settings(_settings(tmp_path)) @@ -198,11 +198,11 @@ class TestSourceFnMatcherSync: # file_filter (adds .cgi); when project B is activated, SolidLanguageServer.__init__ resets # the matcher first, so project B must NOT see .cgi even though project A added it. # Mirrors the reset-then-sync ordering of PerlLanguageServer.__init__. - matcher = Language.PERL.get_source_fn_matcher() + matcher = LanguageServerId.PERL.get_source_fn_matcher() try: # project A: custom file_filter with .cgi filter_a, _ = PerlLanguageServer._resolve_filter_settings( - _settings(tmp_path, {Language.PERL: {"file_filter": [".pm", ".pl", ".t", ".cgi"]}}) + _settings(tmp_path, {LanguageServerId.PERL: {"file_filter": [".pm", ".pl", ".t", ".cgi"]}}) ) PerlLanguageServer._sync_source_fn_matcher(filter_a) assert matcher.is_relevant_filename("handler.cgi") diff --git a/test/solidlsp/php/test_php_basic.py b/test/solidlsp/php/test_php_basic.py index 947495b7..f934e68f 100644 --- a/test/solidlsp/php/test_php_basic.py +++ b/test/solidlsp/php/test_php_basic.py @@ -4,8 +4,8 @@ from pathlib import Path import pytest from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language -from test.conftest import is_ci, is_windows, language_tests_enabled +from solidlsp.ls_config import LanguageServerId +from test.conftest import is_ci, is_windows, language_server_tests_enabled from test.solidlsp.conftest import format_symbol_for_assert, has_malformed_name, request_all_symbols @@ -15,20 +15,20 @@ def _php_supports_phpactor() -> bool: return "openssl" in installed_extensions -_php_servers: list[Language] = [Language.PHP] -if language_tests_enabled(Language.PHP_PHPACTOR): +_php_servers: list[LanguageServerId] = [LanguageServerId.PHP] +if language_server_tests_enabled(LanguageServerId.PHP_PHPACTOR): if not (is_windows and is_ci) and _php_supports_phpactor(): - _php_servers.append(Language.PHP_PHPACTOR) -if language_tests_enabled(Language.PHP_PHPANTOM): - _php_servers.append(Language.PHP_PHPANTOM) + _php_servers.append(LanguageServerId.PHP_PHPACTOR) +if language_server_tests_enabled(LanguageServerId.PHP_PHPANTOM): + _php_servers.append(LanguageServerId.PHP_PHPANTOM) def _is_phpactor(language_server: SolidLanguageServer) -> bool: - return language_server.language_server.language == Language.PHP_PHPACTOR + return language_server.language_server.ls_id == LanguageServerId.PHP_PHPACTOR def _is_phpantom(language_server: SolidLanguageServer) -> bool: - return language_server.language_server.language == Language.PHP_PHPANTOM + return language_server.language_server.ls_id == LanguageServerId.PHP_PHPANTOM def _is_non_default_php_backend(language_server: SolidLanguageServer) -> bool: @@ -38,14 +38,14 @@ def _is_non_default_php_backend(language_server: SolidLanguageServer) -> bool: @pytest.mark.php class TestPhpLanguageServers: @pytest.mark.parametrize("language_server", _php_servers, indirect=True) - @pytest.mark.parametrize("repo_path", [Language.PHP], indirect=True) + @pytest.mark.parametrize("repo_path", [LanguageServerId.PHP], indirect=True) def test_ls_is_running(self, language_server: SolidLanguageServer, repo_path: Path) -> None: """Test that the language server starts and stops successfully.""" assert language_server.is_running() assert Path(language_server.language_server.repository_root_path).resolve() == repo_path.resolve() @pytest.mark.parametrize("language_server", _php_servers, indirect=True) - @pytest.mark.parametrize("repo_path", [Language.PHP], indirect=True) + @pytest.mark.parametrize("repo_path", [LanguageServerId.PHP], indirect=True) def test_find_definition_within_file(self, language_server: SolidLanguageServer, repo_path: Path) -> None: # In index.php: # Line 9 (1-indexed): $greeting = greet($userName); @@ -74,7 +74,7 @@ class TestPhpLanguageServers: assert definition_location["range"]["start"]["character"] == 0 @pytest.mark.parametrize("language_server", _php_servers, indirect=True) - @pytest.mark.parametrize("repo_path", [Language.PHP], indirect=True) + @pytest.mark.parametrize("repo_path", [LanguageServerId.PHP], indirect=True) def test_find_definition_across_files(self, language_server: SolidLanguageServer, repo_path: Path) -> None: # Intelephense uses line 12 (0-indexed), Phpactor uses line 13 (0-indexed) if _is_non_default_php_backend(language_server): @@ -94,7 +94,7 @@ class TestPhpLanguageServers: assert definition_location["range"]["start"]["character"] == 0 @pytest.mark.parametrize("language_server", _php_servers, indirect=True) - @pytest.mark.parametrize("repo_path", [Language.PHP], indirect=True) + @pytest.mark.parametrize("repo_path", [LanguageServerId.PHP], indirect=True) def test_find_definition_simple_variable(self, language_server: SolidLanguageServer, repo_path: Path) -> None: file_path = str(repo_path / "simple_var.php") @@ -119,7 +119,7 @@ class TestPhpLanguageServers: assert definition_location["range"]["start"]["character"] == 0 # $localVar (0-indexed) @pytest.mark.parametrize("language_server", _php_servers, indirect=True) - @pytest.mark.parametrize("repo_path", [Language.PHP], indirect=True) + @pytest.mark.parametrize("repo_path", [LanguageServerId.PHP], indirect=True) def test_find_references_within_file(self, language_server: SolidLanguageServer, repo_path: Path) -> None: index_php_path = str(repo_path / "index.php") @@ -167,7 +167,7 @@ class TestPhpLanguageServers: assert actual_locations == expected_locations @pytest.mark.parametrize("language_server", _php_servers, indirect=True) - @pytest.mark.parametrize("repo_path", [Language.PHP], indirect=True) + @pytest.mark.parametrize("repo_path", [LanguageServerId.PHP], indirect=True) def test_find_references_across_files(self, language_server: SolidLanguageServer, repo_path: Path) -> None: helper_php_path = str(repo_path / "helper.php") # In index.php (0-indexed lines): @@ -208,7 +208,7 @@ class TestPhpLanguageServers: usage_in_index_php = {"uri_suffix": "index.php", "line": 13, "character": 0} assert usage_in_index_php in actual_locations_comparable, "Usage of helperFunction in index.php not found" - @pytest.mark.parametrize("language_server", [Language.PHP, Language.PHP_PHPANTOM], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.PHP, LanguageServerId.PHP_PHPANTOM], indirect=True) def test_find_symbol(self, language_server: SolidLanguageServer) -> None: """Test that document symbols are properly retrieved after Intelephense capability fix.""" from solidlsp.ls_utils import SymbolUtils @@ -217,7 +217,7 @@ class TestPhpLanguageServers: assert SymbolUtils.symbol_tree_contains_name(symbols, "helperFunction"), "helperFunction not found in symbol tree" assert SymbolUtils.symbol_tree_contains_name(symbols, "greet"), "greet function not found in symbol tree" - @pytest.mark.parametrize("language_server", [Language.PHP, Language.PHP_PHPANTOM], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.PHP, LanguageServerId.PHP_PHPANTOM], indirect=True) def test_document_symbols(self, language_server: SolidLanguageServer) -> None: """Test that document symbols are properly retrieved for a specific file.""" doc_symbols = language_server.request_document_symbols("helper.php") @@ -225,7 +225,7 @@ class TestPhpLanguageServers: symbol_names = [sym.get("name") for sym in all_symbols[0] if sym.get("name")] assert "helperFunction" in symbol_names, f"helperFunction not found in document symbols. Found: {symbol_names}" - @pytest.mark.parametrize("language_server", [Language.PHP, Language.PHP_PHPANTOM], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.PHP, LanguageServerId.PHP_PHPANTOM], indirect=True) def test_document_symbols_hierarchical_structure(self, language_server: SolidLanguageServer) -> None: """Verify Intelephense returns hierarchical DocumentSymbol format. @@ -259,7 +259,7 @@ class TestPhpLanguageServers: assert "greet" not in root_names, f"greet should be a child of Dog, not at root level. Roots: {root_names}" assert "fetch" not in root_names, f"fetch should be a child of Dog, not at root level. Roots: {root_names}" - @pytest.mark.parametrize("language_server", [Language.PHP, Language.PHP_PHPANTOM], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.PHP, LanguageServerId.PHP_PHPANTOM], indirect=True) def test_full_symbol_tree_within_file(self, language_server: SolidLanguageServer) -> None: """Verify request_full_symbol_tree scoped to a PHP file returns correct symbols. diff --git a/test/solidlsp/php/test_php_config.py b/test/solidlsp/php/test_php_config.py index 953b4423..44d19c88 100644 --- a/test/solidlsp/php/test_php_config.py +++ b/test/solidlsp/php/test_php_config.py @@ -15,7 +15,7 @@ rest of the PHP suite. import pytest -from solidlsp.ls_config import FilenameMatcher, Language +from solidlsp.ls_config import FilenameMatcher, LanguageServerId from solidlsp.ls_utils import SymbolUtils from test.conftest import get_repo_path, start_ls_context @@ -24,14 +24,14 @@ class TestPhpSourceFnMatcherDefaults: def test_phtml_matched_by_default_for_all_php_language_servers(self) -> None: # .phtml is a standard (yet outdated) PHP extension, so all PHP language servers treat it # as a PHP source by default (#1710). - for language in (Language.PHP, Language.PHP_PHPACTOR, Language.PHP_PHPANTOM): + for language in (LanguageServerId.PHP, LanguageServerId.PHP_PHPACTOR, LanguageServerId.PHP_PHPANTOM): matcher = language.get_source_fn_matcher() assert matcher.is_relevant_filename("index.php"), f"{language}: .php not matched" assert matcher.is_relevant_filename("template.phtml"), f"{language}: .phtml not matched" def test_module_not_matched_by_default(self) -> None: # guard for the integration test below: .module files only become visible via file_filter - assert not Language.PHP.get_source_fn_matcher().is_relevant_filename("hooks.module") + assert not LanguageServerId.PHP.get_source_fn_matcher().is_relevant_filename("hooks.module") def test_file_extensions_property_returns_copy(self) -> None: # _create_base_initialize_params derives the files.associations globs from this property; @@ -54,14 +54,14 @@ class TestFileFilterIntegration: def test_module_file_symbols_and_references_visible(self) -> None: with start_ls_context( - Language.PHP, - ls_specific_settings={Language.PHP: {"file_filter": [".module"]}}, + LanguageServerId.PHP, + ls_specific_settings={LanguageServerId.PHP: {"file_filter": [".module"]}}, ) as ls: # Layer 2 (files.associations) must be asserted FIRST: the reference in the # never-opened drupal_module.module can only come from the server's association-driven # background index. request_full_symbol_tree below didOpens every matched file in the # LS, after which this assertion could pass even without the associations. - helper_php_path = str(get_repo_path(Language.PHP) / "helper.php") + helper_php_path = str(get_repo_path(LanguageServerId.PHP) / "helper.php") references = ls.request_references(helper_php_path, 2, len("function ")) assert any(ref["uri"].endswith("drupal_module.module") for ref in references), ( f"helperFunction call in drupal_module.module not found in references: {references}" diff --git a/test/solidlsp/php/test_php_diagnostics.py b/test/solidlsp/php/test_php_diagnostics.py index 2bfead13..8f80c112 100644 --- a/test/solidlsp/php/test_php_diagnostics.py +++ b/test/solidlsp/php/test_php_diagnostics.py @@ -1,13 +1,13 @@ import pytest from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from test.solidlsp.util.diagnostics import assert_file_diagnostics @pytest.mark.php class TestPhpDiagnostics: - @pytest.mark.parametrize("language_server", [Language.PHP, Language.PHP_PHPANTOM], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.PHP, LanguageServerId.PHP_PHPANTOM], indirect=True) def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None: assert_file_diagnostics( language_server, diff --git a/test/solidlsp/php/test_phpantom.py b/test/solidlsp/php/test_phpantom.py index 4ca4a0b4..337d4e2d 100644 --- a/test/solidlsp/php/test_phpantom.py +++ b/test/solidlsp/php/test_phpantom.py @@ -5,7 +5,7 @@ import pytest from serena.code_editor import LanguageServerCodeEditor from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from src.serena.symbol import LanguageServerSymbolRetriever from test.conftest import project_with_ls_context, start_ls_context @@ -22,7 +22,7 @@ def _extract_changes(workspace_edit: dict) -> dict[str, list[dict]]: def _copy_php_fixture(tmp_path: Path) -> Path: from test.conftest import get_repo_path - fixture_path = get_repo_path(Language.PHP) + fixture_path = get_repo_path(LanguageServerId.PHP) target_path = tmp_path / "test_repo" shutil.copytree(fixture_path, target_path) return target_path @@ -126,8 +126,8 @@ def _find_child_symbol(parent_symbol: dict, child_name: str) -> dict: @pytest.mark.php class TestPHPantom: - @pytest.mark.parametrize("language_server", [Language.PHP_PHPANTOM], indirect=True) - @pytest.mark.parametrize("repo_path", [Language.PHP], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.PHP_PHPANTOM], indirect=True) + @pytest.mark.parametrize("repo_path", [LanguageServerId.PHP], indirect=True) def test_rename_local_variable(self, language_server: SolidLanguageServer, repo_path: Path) -> None: workspace_edit = language_server.request_rename_symbol_edit(str(Path("index.php")), 9, 1, "welcomeMessage") assert workspace_edit is not None, "Rename should be supported for local PHP variables" @@ -145,7 +145,7 @@ class TestPHPantom: repo_path = _copy_php_fixture(tmp_path) _write_psr4_fixture(repo_path) - with start_ls_context(Language.PHP_PHPANTOM, repo_path=str(repo_path), solidlsp_dir=tmp_path) as language_server: + with start_ls_context(LanguageServerId.PHP_PHPANTOM, repo_path=str(repo_path), solidlsp_dir=tmp_path) as language_server: welcome_symbol = _find_root_symbol(language_server, "src/Welcome.php", "Welcome") greet_symbol = _find_child_symbol(welcome_symbol, "greet") selection = greet_symbol["selectionRange"]["start"] @@ -164,7 +164,7 @@ class TestPHPantom: repo_path = _copy_php_fixture(tmp_path) _write_psr4_fixture(repo_path) - with start_ls_context(Language.PHP_PHPANTOM, repo_path=str(repo_path), solidlsp_dir=tmp_path) as language_server: + with start_ls_context(LanguageServerId.PHP_PHPANTOM, repo_path=str(repo_path), solidlsp_dir=tmp_path) as language_server: welcome_symbol = _find_root_symbol(language_server, "src/Welcome.php", "Welcome") selection = welcome_symbol["selectionRange"]["start"] workspace_edit = language_server.request_rename_symbol_edit( @@ -182,7 +182,7 @@ class TestPHPantom: repo_path = _copy_php_fixture(tmp_path) _write_psr4_fixture(repo_path) - with project_with_ls_context(Language.PHP_PHPANTOM, str(repo_path)) as project: + with project_with_ls_context(LanguageServerId.PHP_PHPANTOM, str(repo_path)) as project: symbol_retriever = LanguageServerSymbolRetriever(project) code_editor = LanguageServerCodeEditor(symbol_retriever) status_message = code_editor.rename_symbol("Welcome", relative_path="src/Welcome.php", new_name="GreetingService") @@ -200,7 +200,7 @@ class TestPHPantom: repo_path = _copy_php_fixture(tmp_path) _write_psr4_fixture(repo_path) - with project_with_ls_context(Language.PHP_PHPANTOM, str(repo_path)) as project: + with project_with_ls_context(LanguageServerId.PHP_PHPANTOM, str(repo_path)) as project: symbol_retriever = LanguageServerSymbolRetriever(project) symbols = symbol_retriever.find("Welcome", within_relative_path="src/Welcome.php") info_by_symbol = symbol_retriever.request_info_for_symbol_batch(symbols) @@ -213,7 +213,7 @@ class TestPHPantom: repo_path = _copy_php_fixture(tmp_path) _write_psr4_fixture(repo_path) - with start_ls_context(Language.PHP_PHPANTOM, repo_path=str(repo_path), solidlsp_dir=tmp_path) as language_server: + with start_ls_context(LanguageServerId.PHP_PHPANTOM, repo_path=str(repo_path), solidlsp_dir=tmp_path) as language_server: class_symbols = language_server.request_workspace_symbol("Welcome") or [] function_symbols = language_server.request_workspace_symbol("format_name") or [] constant_symbols = language_server.request_workspace_symbol("MAX_GREETING_LENGTH") or [] diff --git a/test/solidlsp/powershell/test_powershell_basic.py b/test/solidlsp/powershell/test_powershell_basic.py index bf1b9e46..a2d761ee 100644 --- a/test/solidlsp/powershell/test_powershell_basic.py +++ b/test/solidlsp/powershell/test_powershell_basic.py @@ -8,7 +8,7 @@ like request_document_symbols using the PowerShell test repository. import pytest from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from solidlsp.ls_utils import SymbolUtils from test.solidlsp.conftest import format_symbol_for_assert, has_malformed_name, request_all_symbols @@ -17,13 +17,13 @@ from test.solidlsp.conftest import format_symbol_for_assert, has_malformed_name, class TestPowerShellLanguageServerBasics: """Test basic functionality of the PowerShell language server.""" - @pytest.mark.parametrize("language_server", [Language.POWERSHELL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.POWERSHELL], indirect=True) def test_powershell_language_server_initialization(self, language_server: SolidLanguageServer) -> None: """Test that PowerShell language server can be initialized successfully.""" assert language_server is not None - assert language_server.language == Language.POWERSHELL + assert language_server.ls_id == LanguageServerId.POWERSHELL - @pytest.mark.parametrize("language_server", [Language.POWERSHELL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.POWERSHELL], indirect=True) def test_powershell_request_document_symbols(self, language_server: SolidLanguageServer) -> None: """Test request_document_symbols for PowerShell files.""" # Test getting symbols from main.ps1 @@ -43,7 +43,7 @@ class TestPowerShellLanguageServerBasics: assert has_function("Main"), f"Should find Main function in {function_names}" assert len(function_symbols) >= 3, f"Should find at least 3 functions, found {len(function_symbols)}" - @pytest.mark.parametrize("language_server", [Language.POWERSHELL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.POWERSHELL], indirect=True) def test_powershell_utils_functions(self, language_server: SolidLanguageServer) -> None: """Test function detection in utils.ps1 file.""" # Test with utils.ps1 @@ -73,7 +73,7 @@ class TestPowerShellLanguageServerBasics: assert len(utils_function_symbols) >= 8, f"Should find at least 8 functions in utils.ps1, found {len(utils_function_symbols)}" - @pytest.mark.parametrize("language_server", [Language.POWERSHELL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.POWERSHELL], indirect=True) def test_powershell_function_with_parameters(self, language_server: SolidLanguageServer) -> None: """Test that functions with CmdletBinding and parameters are detected correctly.""" all_symbols, _root_symbols = language_server.request_document_symbols("main.ps1").get_all_symbols_and_roots() @@ -89,7 +89,7 @@ class TestPowerShellLanguageServerBasics: process_items_symbol = next((sym for sym in function_symbols if "Process-Items" in sym["name"]), None) assert process_items_symbol is not None, f"Should find Process-Items function in {[s['name'] for s in function_symbols]}" - @pytest.mark.parametrize("language_server", [Language.POWERSHELL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.POWERSHELL], indirect=True) def test_powershell_all_function_detection(self, language_server: SolidLanguageServer) -> None: """Test that all expected functions are detected across both files.""" # Get symbols from main.ps1 @@ -132,7 +132,7 @@ class TestPowerShellLanguageServerBasics: assert len(main_functions) >= 3, f"Should find at least 3 functions in main.ps1, found {len(main_functions)}" assert len(utils_functions) >= 8, f"Should find at least 8 functions in utils.ps1, found {len(utils_functions)}" - @pytest.mark.parametrize("language_server", [Language.POWERSHELL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.POWERSHELL], indirect=True) def test_powershell_class_method_symbols_use_bare_method_name(self, language_server: SolidLanguageServer) -> None: """Test whether PSES already reports class methods with bare names.""" symbols = language_server.request_full_symbol_tree(within_relative_path="main.ps1") @@ -140,7 +140,7 @@ class TestPowerShellLanguageServerBasics: assert SymbolUtils.symbol_tree_contains_name(symbols, "PersonFormatter"), "Should find PersonFormatter class in symbol tree" assert SymbolUtils.symbol_tree_contains_name(symbols, "FormatName"), "Expected PowerShell method to be exposed with bare name" - @pytest.mark.parametrize("language_server", [Language.POWERSHELL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.POWERSHELL], indirect=True) def test_powershell_find_references_within_file(self, language_server: SolidLanguageServer) -> None: """Test finding references to a function within the same file.""" main_path = "main.ps1" @@ -163,7 +163,7 @@ class TestPowerShellLanguageServerBasics: f"Should find reference in main.ps1, got {refs}" ) - @pytest.mark.parametrize("language_server", [Language.POWERSHELL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.POWERSHELL], indirect=True) def test_powershell_find_definition_across_files(self, language_server: SolidLanguageServer) -> None: """Test finding definition of functions across files (main.ps1 -> utils.ps1).""" # main.ps1 calls Convert-ToUpperCase from utils.ps1 at line 99 (0-indexed: 98) @@ -183,7 +183,7 @@ class TestPowerShellLanguageServerBasics: f"Should find definition in utils.ps1, got {definition_locations}" ) - @pytest.mark.parametrize("language_server", [Language.POWERSHELL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.POWERSHELL], indirect=True) def test_bare_symbol_names(self, language_server) -> None: all_symbols = request_all_symbols(language_server) malformed_symbols = [] diff --git a/test/solidlsp/powershell/test_powershell_diagnostics.py b/test/solidlsp/powershell/test_powershell_diagnostics.py index ac8706cf..c202f75e 100644 --- a/test/solidlsp/powershell/test_powershell_diagnostics.py +++ b/test/solidlsp/powershell/test_powershell_diagnostics.py @@ -1,13 +1,13 @@ import pytest from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from test.solidlsp.util.diagnostics import assert_file_diagnostics @pytest.mark.powershell class TestPowershellDiagnostics: - @pytest.mark.parametrize("language_server", [Language.POWERSHELL], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.POWERSHELL], indirect=True) def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None: assert_file_diagnostics( language_server, diff --git a/test/solidlsp/python/test_basedpyright.py b/test/solidlsp/python/test_basedpyright.py index e01b4219..90d97642 100644 --- a/test/solidlsp/python/test_basedpyright.py +++ b/test/solidlsp/python/test_basedpyright.py @@ -5,7 +5,7 @@ from textwrap import dedent import pytest from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from test.conftest import start_ls_context from test.solidlsp.conftest import document_symbol_names @@ -56,7 +56,7 @@ def basedpyright_project(tmp_path_factory: pytest.TempPathFactory) -> Path: @pytest.fixture(scope="module") def basedpyright_language_server(basedpyright_project: Path) -> Iterator[SolidLanguageServer]: with start_ls_context( - language=Language.PYTHON_BASEDPYRIGHT, + ls_id=LanguageServerId.PYTHON_BASEDPYRIGHT, repo_path=str(basedpyright_project), ) as language_server: yield language_server @@ -66,7 +66,7 @@ def test_basedpyright_starts( basedpyright_language_server: SolidLanguageServer, basedpyright_project: Path, ) -> None: - assert basedpyright_language_server.language == Language.PYTHON_BASEDPYRIGHT + assert basedpyright_language_server.ls_id == LanguageServerId.PYTHON_BASEDPYRIGHT assert basedpyright_language_server.is_running() assert Path(basedpyright_language_server.language_server.repository_root_path).resolve() == basedpyright_project.resolve() diff --git a/test/solidlsp/python/test_basedpyright_server.py b/test/solidlsp/python/test_basedpyright_server.py index eb788955..f0de6505 100644 --- a/test/solidlsp/python/test_basedpyright_server.py +++ b/test/solidlsp/python/test_basedpyright_server.py @@ -6,7 +6,7 @@ import pytest from solidlsp.dependency_provider import LanguageServerDependencyProviderUvx from solidlsp.language_servers.basedpyright_server import BASEDPYRIGHT_VERSION, BasedPyrightLanguageServer from solidlsp.language_servers.pyright_server import PyrightServer -from solidlsp.ls_config import Language, LanguageServerConfig +from solidlsp.ls_config import LanguageServerConfig, LanguageServerId from solidlsp.settings import SolidLSPSettings @@ -17,12 +17,12 @@ def _make_basedpyright_server( settings = SolidLSPSettings( solidlsp_dir=str(tmp_path / "global"), project_data_path=str(tmp_path / "project"), - ls_specific_settings={Language.PYTHON_BASEDPYRIGHT: custom_settings or {}}, + ls_specific_settings={LanguageServerId.PYTHON_BASEDPYRIGHT: custom_settings or {}}, ) server_interface = Mock() with patch.object(BasedPyrightLanguageServer, "_create_language_server_interface", return_value=server_interface): return BasedPyrightLanguageServer( - LanguageServerConfig(code_language=Language.PYTHON_BASEDPYRIGHT), + LanguageServerConfig(ls_id=LanguageServerId.PYTHON_BASEDPYRIGHT), str(tmp_path), settings, ) @@ -35,7 +35,7 @@ def _make_pyright_server(tmp_path: Path) -> PyrightServer: ) server_interface = Mock() with patch.object(PyrightServer, "_create_language_server_interface", return_value=server_interface): - return PyrightServer(LanguageServerConfig(code_language=Language.PYTHON), str(tmp_path), settings) + return PyrightServer(LanguageServerConfig(ls_id=LanguageServerId.PYTHON), str(tmp_path), settings) def test_dependency_provider_uses_basedpyright_profile(tmp_path: Path) -> None: @@ -128,14 +128,14 @@ def test_base_command_and_args_overrides_are_preserved(tmp_path: Path) -> None: def test_language_registry_uses_separate_server_classes() -> None: - assert Language.PYTHON.get_ls_class() is PyrightServer - assert Language.PYTHON_BASEDPYRIGHT.get_ls_class() is BasedPyrightLanguageServer + assert LanguageServerId.PYTHON.get_ls_class() is PyrightServer + assert LanguageServerId.PYTHON_BASEDPYRIGHT.get_ls_class() is BasedPyrightLanguageServer def test_language_identity_separates_cache_directories(tmp_path: Path) -> None: pyright_server = _make_pyright_server(tmp_path) basedpyright_server = _make_basedpyright_server(tmp_path) - assert pyright_server.language == Language.PYTHON - assert basedpyright_server.language == Language.PYTHON_BASEDPYRIGHT + assert pyright_server.ls_id == LanguageServerId.PYTHON + assert basedpyright_server.ls_id == LanguageServerId.PYTHON_BASEDPYRIGHT assert pyright_server.cache_dir != basedpyright_server.cache_dir diff --git a/test/solidlsp/python/test_retrieval_with_ignored_dirs.py b/test/solidlsp/python/test_retrieval_with_ignored_dirs.py index 9c12af8d..400ef183 100644 --- a/test/solidlsp/python/test_retrieval_with_ignored_dirs.py +++ b/test/solidlsp/python/test_retrieval_with_ignored_dirs.py @@ -4,7 +4,7 @@ from pathlib import Path import pytest from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from test.conftest import start_ls_context from test.solidlsp.conftest import PYTHON_BACKEND_LANGUAGES @@ -16,7 +16,7 @@ pytestmark = pytest.mark.python def ls_with_ignored_dirs() -> Generator[SolidLanguageServer, None, None]: """Fixture to set up an LS for the python test repo with the 'scripts' directory ignored.""" ignored_paths = ["scripts", "custom_test"] - with start_ls_context(language=Language.PYTHON, ignored_paths=ignored_paths) as ls: + with start_ls_context(ls_id=LanguageServerId.PYTHON, ignored_paths=ignored_paths) as ls: yield ls @@ -47,7 +47,7 @@ def test_find_references_ignores_dir(ls_with_ignored_dirs: SolidLanguageServer): def test_refs_and_symbols_with_glob_patterns(repo_path: Path) -> None: """Tests that refs and symbols with glob patterns are ignored.""" ignored_paths = ["*ipts", "custom_t*"] - with start_ls_context(language=Language.PYTHON, repo_path=str(repo_path), ignored_paths=ignored_paths) as ls: + with start_ls_context(ls_id=LanguageServerId.PYTHON, repo_path=str(repo_path), ignored_paths=ignored_paths) as ls: # same as in the above tests root = ls.request_full_symbol_tree()[0] root_children = root["children"] diff --git a/test/solidlsp/qml/test_qml_basic.py b/test/solidlsp/qml/test_qml_basic.py index 97b658a7..54624222 100644 --- a/test/solidlsp/qml/test_qml_basic.py +++ b/test/solidlsp/qml/test_qml_basic.py @@ -14,26 +14,28 @@ import pytest from serena.util.text_utils import find_text_coordinates from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language -from test.conftest import language_tests_enabled +from solidlsp.ls_config import LanguageServerId +from test.conftest import language_server_tests_enabled from test.solidlsp.conftest import read_repo_file from test.solidlsp.util.diagnostics import assert_file_diagnostics pytestmark = [ pytest.mark.qml, - pytest.mark.skipif(not language_tests_enabled(Language.QML), reason="QML tests are disabled (qmlls/qmlls6 not available)"), + pytest.mark.skipif( + not language_server_tests_enabled(LanguageServerId.QML), reason="QML tests are disabled (qmlls/qmlls6 not available)" + ), ] class TestQmlLanguageServer: """Test QML language server startup and basic features.""" - @pytest.mark.parametrize("language_server", [Language.QML], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.QML], indirect=True) def test_ls_is_running(self, language_server: SolidLanguageServer) -> None: """Test that the language server starts successfully.""" assert language_server.is_running() - @pytest.mark.parametrize("language_server", [Language.QML], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.QML], indirect=True) def test_document_symbols_main(self, language_server: SolidLanguageServer) -> None: """Test that document symbols are returned for the main file. @@ -49,7 +51,7 @@ class TestQmlLanguageServer: assert "ApplicationWindow" in root_names, f"ApplicationWindow root missing. Roots: {root_names}" assert "Button" in symbol_names, f"Button component missing. Symbols: {symbol_names}" - @pytest.mark.parametrize("language_server", [Language.QML], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.QML], indirect=True) def test_document_symbols_shapes(self, language_server: SolidLanguageServer) -> None: """Test that document symbols are returned for the shapes file.""" file_path = os.path.join("src", "shapes.qml") @@ -61,8 +63,8 @@ class TestQmlLanguageServer: assert "Rectangle" in root_names, f"Rectangle root missing. Roots: {root_names}" assert "Text" in symbol_names, f"Text component missing. Symbols: {symbol_names}" - @pytest.mark.parametrize("language_server", [Language.QML], indirect=True) - @pytest.mark.parametrize("repo_path", [Language.QML], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.QML], indirect=True) + @pytest.mark.parametrize("repo_path", [LanguageServerId.QML], indirect=True) def test_find_references_within_file(self, language_server: SolidLanguageServer, repo_path: Path) -> None: """Test that references are found within the same file. @@ -87,8 +89,8 @@ class TestQmlLanguageServer: ref_files = {loc["uri"].split("/")[-1] for loc in references} assert "CustomComponent.qml" in ref_files, f"All references should be in CustomComponent.qml, got {ref_files}" - @pytest.mark.parametrize("language_server", [Language.QML], indirect=True) - @pytest.mark.parametrize("repo_path", [Language.QML], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.QML], indirect=True) + @pytest.mark.parametrize("repo_path", [LanguageServerId.QML], indirect=True) def test_find_references_cross_file(self, language_server: SolidLanguageServer, repo_path: Path) -> None: """Test that references are found across files. @@ -110,7 +112,7 @@ class TestQmlLanguageServer: ref_files = {loc["uri"].split("/")[-1] for loc in references} assert "UserComponent.qml" in ref_files, f"Expected at least one reference in UserComponent.qml, got {ref_files}" - @pytest.mark.parametrize("language_server", [Language.QML], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.QML], indirect=True) def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None: """Test that diagnostics are reported for a QML file with errors. diff --git a/test/solidlsp/r/test_r_basic.py b/test/solidlsp/r/test_r_basic.py index 99190d5f..f9d4e82a 100644 --- a/test/solidlsp/r/test_r_basic.py +++ b/test/solidlsp/r/test_r_basic.py @@ -8,18 +8,18 @@ from pathlib import Path import pytest from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language -from test.conftest import language_tests_enabled +from solidlsp.ls_config import LanguageServerId +from test.conftest import language_server_tests_enabled from test.solidlsp.conftest import format_symbol_for_assert, has_malformed_name, request_all_symbols -@pytest.mark.skipif(not language_tests_enabled(Language.R), reason="R tests are disabled (R not available)") +@pytest.mark.skipif(not language_server_tests_enabled(LanguageServerId.R), reason="R tests are disabled (R not available)") @pytest.mark.r class TestRLanguageServer: """Test basic functionality of the R language server.""" - @pytest.mark.parametrize("language_server", [Language.R], indirect=True) - @pytest.mark.parametrize("repo_path", [Language.R], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.R], indirect=True) + @pytest.mark.parametrize("repo_path", [LanguageServerId.R], indirect=True) def test_server_initialization(self, language_server: SolidLanguageServer, repo_path: Path): """Test that the R language server initializes properly.""" assert language_server is not None @@ -27,7 +27,7 @@ class TestRLanguageServer: assert language_server.is_running() assert Path(language_server.language_server.repository_root_path).resolve() == repo_path.resolve() - @pytest.mark.parametrize("language_server", [Language.R], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.R], indirect=True) def test_symbol_retrieval(self, language_server: SolidLanguageServer): """Test R document symbol extraction.""" all_symbols, _root_symbols = language_server.request_document_symbols(os.path.join("R", "utils.R")).get_all_symbols_and_roots() @@ -41,7 +41,7 @@ class TestRLanguageServer: expected_functions = {"calculate_mean", "process_data", "create_data_frame"} assert expected_functions.issubset(function_names), f"Expected functions {expected_functions} but found {function_names}" - @pytest.mark.parametrize("language_server", [Language.R], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.R], indirect=True) def test_find_definition_across_files(self, language_server: SolidLanguageServer): """Test finding function definitions across files.""" analysis_file = os.path.join("examples", "analysis.R") @@ -58,7 +58,7 @@ class TestRLanguageServer: # Definition should be around line 37 (0-indexed: 36) where create_data_frame is defined assert definition_location["range"]["start"]["line"] >= 35 - @pytest.mark.parametrize("language_server", [Language.R], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.R], indirect=True) def test_find_references_across_files(self, language_server: SolidLanguageServer): """Test finding function references across files.""" analysis_file = os.path.join("examples", "analysis.R") @@ -85,7 +85,7 @@ class TestRLanguageServer: def test_file_matching(self): """Test that R files are properly matched.""" - matcher = Language.R.get_source_fn_matcher() + matcher = LanguageServerId.R.get_source_fn_matcher() assert matcher.is_relevant_filename("script.R") assert matcher.is_relevant_filename("analysis.r") @@ -94,10 +94,10 @@ class TestRLanguageServer: def test_r_language_enum(self): """Test R language enum value.""" - assert Language.R == "r" - assert str(Language.R) == "r" + assert LanguageServerId.R == "r" + assert str(LanguageServerId.R) == "r" - @pytest.mark.parametrize("language_server", [Language.R], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.R], indirect=True) def test_bare_symbol_names(self, language_server) -> None: all_symbols = request_all_symbols(language_server) malformed_symbols = [] diff --git a/test/solidlsp/rego/test_rego_basic.py b/test/solidlsp/rego/test_rego_basic.py index 8bbe730d..1e846c1c 100644 --- a/test/solidlsp/rego/test_rego_basic.py +++ b/test/solidlsp/rego/test_rego_basic.py @@ -5,19 +5,19 @@ import os import pytest from solidlsp.ls import SolidLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from solidlsp.ls_types import SymbolKind from solidlsp.ls_utils import SymbolUtils -from test.conftest import language_tests_enabled +from test.conftest import language_server_tests_enabled from test.solidlsp.conftest import format_symbol_for_assert, has_malformed_name, request_all_symbols -@pytest.mark.skipif(not language_tests_enabled(Language.REGO), reason="Rego tests are disabled (regal not available)") +@pytest.mark.skipif(not language_server_tests_enabled(LanguageServerId.REGO), reason="Rego tests are disabled (regal not available)") @pytest.mark.rego class TestRegoLanguageServer: """Test Regal language server functionality for Rego.""" - @pytest.mark.parametrize("language_server", [Language.REGO], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.REGO], indirect=True) def test_request_document_symbols_authz(self, language_server: SolidLanguageServer) -> None: """Test that document symbols can be retrieved from authz.rego.""" file_path = os.path.join("policies", "authz.rego") @@ -36,7 +36,7 @@ class TestRegoLanguageServer: assert "is_admin" in symbol_names, "is_admin function not found" assert "admin_roles" in symbol_names, "admin_roles constant not found" - @pytest.mark.parametrize("language_server", [Language.REGO], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.REGO], indirect=True) def test_request_document_symbols_helpers(self, language_server: SolidLanguageServer) -> None: """Test that document symbols can be retrieved from helpers.rego.""" file_path = os.path.join("utils", "helpers.rego") @@ -54,7 +54,7 @@ class TestRegoLanguageServer: assert "is_valid_email" in symbol_names, "is_valid_email function not found" assert "is_valid_username" in symbol_names, "is_valid_username function not found" - @pytest.mark.parametrize("language_server", [Language.REGO], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.REGO], indirect=True) def test_find_symbol_full_tree(self, language_server: SolidLanguageServer) -> None: """Test finding symbols across entire workspace using symbol tree.""" symbols = language_server.request_full_symbol_tree() @@ -64,7 +64,7 @@ class TestRegoLanguageServer: assert SymbolUtils.symbol_tree_contains_name(symbols, "is_valid_user"), "is_valid_user function not found in symbol tree" assert SymbolUtils.symbol_tree_contains_name(symbols, "is_admin"), "is_admin function not found in symbol tree" - @pytest.mark.parametrize("language_server", [Language.REGO], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.REGO], indirect=True) def test_request_definition_within_file(self, language_server: SolidLanguageServer) -> None: """Test go-to-definition for symbols within the same file.""" # In authz.rego, check_permission references admin_roles @@ -90,7 +90,7 @@ class TestRegoLanguageServer: # Verify the definition points to admin_roles in the same file assert any("authz.rego" in defn.get("relativePath", "") for defn in definitions), "Definition should be in authz.rego" - @pytest.mark.parametrize("language_server", [Language.REGO], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.REGO], indirect=True) def test_request_definition_across_files(self, language_server: SolidLanguageServer) -> None: """Test go-to-definition for symbols across files (cross-file references).""" # In authz.rego line 11, the allow rule calls utils.is_valid_user @@ -119,7 +119,7 @@ class TestRegoLanguageServer: "Definition should be in utils/helpers.rego (cross-file reference)" ) - @pytest.mark.parametrize("language_server", [Language.REGO], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.REGO], indirect=True) def test_find_symbols_validation(self, language_server: SolidLanguageServer) -> None: """Test finding symbols in validation.rego which has imports.""" file_path = os.path.join("policies", "validation.rego") @@ -137,7 +137,7 @@ class TestRegoLanguageServer: assert "has_valid_credentials" in symbol_names, "has_valid_credentials function not found" assert "validate_request" in symbol_names, "validate_request rule not found" - @pytest.mark.parametrize("language_server", [Language.REGO], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.REGO], indirect=True) def test_bare_symbol_names(self, language_server) -> None: all_symbols = request_all_symbols(language_server) malformed_symbols = [] diff --git a/test/solidlsp/ruby/test_ruby_basic.py b/test/solidlsp/ruby/test_ruby_basic.py index 2a76b4f8..4932b9b2 100644 --- a/test/solidlsp/ruby/test_ruby_basic.py +++ b/test/solidlsp/ruby/test_ruby_basic.py @@ -4,21 +4,21 @@ from pathlib import Path import pytest from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from solidlsp.ls_utils import SymbolUtils from test.solidlsp.conftest import format_symbol_for_assert, has_malformed_name, request_all_symbols @pytest.mark.ruby class TestRubyLanguageServer: - @pytest.mark.parametrize("language_server", [Language.RUBY], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.RUBY], indirect=True) def test_find_symbol(self, language_server: SolidLanguageServer) -> None: symbols = language_server.request_full_symbol_tree() assert SymbolUtils.symbol_tree_contains_name(symbols, "DemoClass"), "DemoClass not found in symbol tree" assert SymbolUtils.symbol_tree_contains_name(symbols, "helper_function"), "helper_function not found in symbol tree" assert SymbolUtils.symbol_tree_contains_name(symbols, "print_value"), "print_value not found in symbol tree" - @pytest.mark.parametrize("language_server", [Language.RUBY], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.RUBY], indirect=True) def test_find_referencing_symbols(self, language_server: SolidLanguageServer) -> None: file_path = os.path.join("main.rb") symbols = language_server.request_document_symbols(file_path).get_all_symbols_and_roots() @@ -30,8 +30,8 @@ class TestRubyLanguageServer: print(helper_symbol) assert helper_symbol is not None, "Could not find 'helper_function' symbol in main.rb" - @pytest.mark.parametrize("language_server", [Language.RUBY], indirect=True) - @pytest.mark.parametrize("repo_path", [Language.RUBY], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.RUBY], indirect=True) + @pytest.mark.parametrize("repo_path", [LanguageServerId.RUBY], indirect=True) def test_find_definition_across_files(self, language_server: SolidLanguageServer, repo_path: Path) -> None: # Test finding Calculator.add method definition from line 17: Calculator.new.add(demo.value, 10) definition_location_list = language_server.request_definition( @@ -55,7 +55,7 @@ class TestRubyLanguageServer: assert definition_location["uri"].endswith("lib.rb") assert definition_location["range"]["start"]["line"] == 1 # add method on line 2 (0-indexed 1) - @pytest.mark.parametrize("language_server", [Language.RUBY], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.RUBY], indirect=True) def test_bare_symbol_names(self, language_server) -> None: all_symbols = request_all_symbols(language_server) malformed_symbols = [] diff --git a/test/solidlsp/ruby/test_ruby_symbol_retrieval.py b/test/solidlsp/ruby/test_ruby_symbol_retrieval.py index ef0c50fe..67a29eb2 100644 --- a/test/solidlsp/ruby/test_ruby_symbol_retrieval.py +++ b/test/solidlsp/ruby/test_ruby_symbol_retrieval.py @@ -14,7 +14,7 @@ import pytest from serena.util.text_utils import find_text_coordinates from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from solidlsp.ls_types import SymbolKind pytestmark = pytest.mark.ruby @@ -23,7 +23,7 @@ pytestmark = pytest.mark.ruby class TestRubyLanguageServerSymbols: """Test the Ruby language server's symbol-related functionality.""" - @pytest.mark.parametrize("language_server", [Language.RUBY], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.RUBY], indirect=True) def test_request_containing_symbol_method(self, language_server: SolidLanguageServer) -> None: """Test request_containing_symbol for a method.""" # Test for a position inside the create_user method @@ -58,7 +58,7 @@ class TestRubyLanguageServerSymbols: assert "def create_user" in body, "Method body should contain method definition" assert len(body.strip()) > 0, "Method body should not be empty" - @pytest.mark.parametrize("language_server", [Language.RUBY], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.RUBY], indirect=True) def test_request_containing_symbol_class(self, language_server: SolidLanguageServer) -> None: """Test request_containing_symbol for a class.""" # Test for a position inside the UserService class but outside any method @@ -85,7 +85,7 @@ class TestRubyLanguageServerSymbols: f"Expected 'Services' as container, got '{containing_symbol['containerName']}'" ) - @pytest.mark.parametrize("language_server", [Language.RUBY], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.RUBY], indirect=True) def test_request_containing_symbol_module(self, language_server: SolidLanguageServer) -> None: """Test request_containing_symbol for a module context.""" # Test that we can find the Services module in document symbols @@ -112,7 +112,7 @@ class TestRubyLanguageServerSymbols: if "containerName" in containing_symbol: assert containing_symbol.get("containerName") == "Services" - @pytest.mark.parametrize("language_server", [Language.RUBY], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.RUBY], indirect=True) def test_request_containing_symbol_nested_class(self, language_server: SolidLanguageServer) -> None: """Test request_containing_symbol with nested classes.""" # Test for a position inside a nested class method @@ -125,7 +125,7 @@ class TestRubyLanguageServerSymbols: assert containing_symbol["name"] == "find_me" assert containing_symbol["kind"] == SymbolKind.Method - @pytest.mark.parametrize("language_server", [Language.RUBY], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.RUBY], indirect=True) def test_request_containing_symbol_none(self, language_server: SolidLanguageServer) -> None: """Test request_containing_symbol for a position with no containing symbol.""" # Test for a position outside any class/method (e.g., in requires) @@ -136,7 +136,7 @@ class TestRubyLanguageServerSymbols: # Should return None or an empty dictionary assert containing_symbol is None or containing_symbol == {} - @pytest.mark.parametrize("language_server", [Language.RUBY], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.RUBY], indirect=True) def test_request_referencing_symbols_method(self, language_server: SolidLanguageServer) -> None: """Test request_referencing_symbols for a method.""" # Test referencing symbols for create_user method @@ -164,7 +164,7 @@ class TestRubyLanguageServerSymbols: assert "name" in symbol assert "kind" in symbol - @pytest.mark.parametrize("language_server", [Language.RUBY], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.RUBY], indirect=True) def test_request_referencing_symbols_class(self, language_server: SolidLanguageServer) -> None: """Test request_referencing_symbols for a class.""" # Test referencing symbols for User class @@ -194,7 +194,7 @@ class TestRubyLanguageServerSymbols: assert "start" in symbol["location"]["range"] assert "end" in symbol["location"]["range"] - @pytest.mark.parametrize("language_server", [Language.RUBY], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.RUBY], indirect=True) def test_request_defining_symbol_variable(self, language_server: SolidLanguageServer) -> None: """Test request_defining_symbol for a variable usage.""" # Test finding the definition of a variable in a method @@ -207,7 +207,7 @@ class TestRubyLanguageServerSymbols: assert "name" in defining_symbol assert "kind" in defining_symbol - @pytest.mark.parametrize("language_server", [Language.RUBY], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.RUBY], indirect=True) def test_request_defining_symbol_class(self, language_server: SolidLanguageServer) -> None: """Test request_defining_symbol for a class reference.""" # Test finding the definition of the User class used in services @@ -221,7 +221,7 @@ class TestRubyLanguageServerSymbols: # The name might be "User" or the method that contains it assert defining_symbol.get("name") is not None - @pytest.mark.parametrize("language_server", [Language.RUBY], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.RUBY], indirect=True) def test_request_defining_symbol_none(self, language_server: SolidLanguageServer) -> None: """Test request_defining_symbol for a position with no symbol.""" # Test for a position with no symbol (e.g., whitespace or comment) @@ -232,7 +232,7 @@ class TestRubyLanguageServerSymbols: # Should return None for positions with no symbol assert defining_symbol is None or defining_symbol == {} - @pytest.mark.parametrize("language_server", [Language.RUBY], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.RUBY], indirect=True) def test_request_defining_symbol_nested_class(self, language_server: SolidLanguageServer) -> None: """Test request_defining_symbol for nested class access.""" # Test finding definition of NestedClass @@ -245,7 +245,7 @@ class TestRubyLanguageServerSymbols: assert "name" in defining_symbol assert defining_symbol.get("name") in ["NestedClass", "OuterClass"] - @pytest.mark.parametrize("language_server", [Language.RUBY], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.RUBY], indirect=True) def test_symbol_methods_integration(self, language_server: SolidLanguageServer) -> None: """Test the integration between different symbol-related methods.""" file_path = os.path.join("models.rb") @@ -263,7 +263,7 @@ class TestRubyLanguageServerSymbols: # Step 3: Verify that they refer to the same symbol type assert defining_symbol["kind"] == containing_symbol["kind"] - @pytest.mark.parametrize("language_server", [Language.RUBY], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.RUBY], indirect=True) def test_symbol_tree_structure_basic(self, language_server: SolidLanguageServer) -> None: """Test that the symbol tree structure includes Ruby symbols.""" # Get all symbols in the test repository @@ -282,7 +282,7 @@ class TestRubyLanguageServerSymbols: # We should find at least some Ruby files in the symbol tree assert found_ruby_files, "Ruby files not found in symbol tree" - @pytest.mark.parametrize("language_server", [Language.RUBY], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.RUBY], indirect=True) def test_document_symbols_detailed(self, language_server: SolidLanguageServer) -> None: """Test document symbols for detailed Ruby file structure.""" file_path = os.path.join("models.rb") @@ -307,7 +307,7 @@ class TestRubyLanguageServerSymbols: found_symbols = symbol_names.intersection(expected_symbols) assert len(found_symbols) > 0, f"Expected symbols not found. Found: {symbol_names}" - @pytest.mark.parametrize("language_server", [Language.RUBY], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.RUBY], indirect=True) def test_module_and_class_hierarchy(self, language_server: SolidLanguageServer) -> None: """Test symbol detection for modules and nested class hierarchies.""" file_path = os.path.join("nested.rb") @@ -333,7 +333,7 @@ class TestRubyLanguageServerSymbols: # Should find the outer class at minimum assert "OuterClass" in symbol_names, f"OuterClass not found in symbols: {symbol_names}" - @pytest.mark.parametrize("language_server", [Language.RUBY], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.RUBY], indirect=True) def test_references_to_variables(self, language_server: SolidLanguageServer) -> None: """Test request_referencing_symbols for a variable with detailed verification.""" file_path = os.path.join("variables.rb") @@ -358,7 +358,7 @@ class TestRubyLanguageServerSymbols: found_in_expected_range = any(any(start <= line <= end for start, end in expected_line_ranges) for line in ref_lines) assert found_in_expected_range, f"Expected references in ranges {expected_line_ranges}, found lines: {ref_lines}" - @pytest.mark.parametrize("language_server", [Language.RUBY], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.RUBY], indirect=True) def test_request_referencing_symbols_parameter(self, language_server: SolidLanguageServer) -> None: """Test request_referencing_symbols for a method parameter.""" # Test referencing symbols for a method parameter in get_user method @@ -393,7 +393,7 @@ class TestRubyLanguageServerSymbols: # Verify line number is valid (references can be before method definition too) assert range_info["start"]["line"] >= 0, "Reference line should be valid" - @pytest.mark.parametrize("language_server", [Language.RUBY], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.RUBY], indirect=True) def test_request_referencing_symbols_none(self, language_server: SolidLanguageServer) -> None: """Test request_referencing_symbols for a position with no symbol.""" # Test for a position with no symbol (comment or blank line) @@ -416,7 +416,7 @@ class TestRubyLanguageServerSymbols: f"Exception should be related to symbol/position/reference issues, got: {e}" ) - @pytest.mark.parametrize("language_server", [Language.RUBY], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.RUBY], indirect=True) def test_request_dir_overview(self, language_server: SolidLanguageServer) -> None: """Test that request_dir_overview returns correct symbol information for files in a directory.""" # Get overview of the test repo directory @@ -454,7 +454,7 @@ class TestRubyLanguageServerSymbols: found_expected = [name for name in expected_symbols if name in symbol_names] assert len(found_expected) >= 1, f"Should find at least one expected symbol, found: {found_expected} in {symbol_names}" - @pytest.mark.parametrize("language_server", [Language.RUBY], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.RUBY], indirect=True) def test_request_document_overview(self, language_server: SolidLanguageServer) -> None: """Test that request_document_overview returns correct symbol information for a file.""" # Get overview of the user_management.rb file @@ -479,7 +479,7 @@ class TestRubyLanguageServerSymbols: found_symbols = symbol_names.intersection(expected_symbols) assert len(found_symbols) > 0, f"Expected to find some symbols from {expected_symbols}, found: {symbol_names}" - @pytest.mark.parametrize("language_server", [Language.RUBY], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.RUBY], indirect=True) def test_request_containing_symbol_variable(self, language_server: SolidLanguageServer) -> None: """Test request_containing_symbol where the target is a variable.""" # Test for a position inside a variable definition or usage @@ -497,7 +497,7 @@ class TestRubyLanguageServerSymbols: f"Expected containing symbol to be method/class/function, got kind: {containing_symbol['kind']}" ) - @pytest.mark.parametrize("language_server", [Language.RUBY], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.RUBY], indirect=True) def test_request_containing_symbol_function(self, language_server: SolidLanguageServer) -> None: """Test request_containing_symbol for a function (not method).""" # Test for a position inside a standalone function @@ -515,7 +515,7 @@ class TestRubyLanguageServerSymbols: SymbolKind.Method.value, ], f"Expected function or method kind, got: {containing_symbol['kind']}" - @pytest.mark.parametrize("language_server", [Language.RUBY], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.RUBY], indirect=True) def test_request_containing_symbol_nested(self, language_server: SolidLanguageServer) -> None: """Test request_containing_symbol with nested scopes.""" # Test for a position inside a method which is inside a class @@ -532,7 +532,7 @@ class TestRubyLanguageServerSymbols: if "containerName" in containing_symbol: assert "UserService" in containing_symbol["containerName"] - @pytest.mark.parametrize("language_server", [Language.RUBY], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.RUBY], indirect=True) def test_symbol_tree_structure_subdir(self, language_server: SolidLanguageServer) -> None: """Test that the symbol tree structure correctly handles subdirectories.""" # Get symbols within the examples subdirectory @@ -562,7 +562,7 @@ class TestRubyLanguageServerSymbols: if not found_user_management: pytest.skip("user_management file not found in examples subdirectory structure") - @pytest.mark.parametrize("language_server", [Language.RUBY], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.RUBY], indirect=True) def test_request_defining_symbol_imported_class(self, language_server: SolidLanguageServer) -> None: """Test request_defining_symbol for an imported/required class.""" # Test finding the definition of a class used from another file @@ -579,7 +579,7 @@ class TestRubyLanguageServerSymbols: expected_names = ["UserService", "Services", "new", "UserManager"] assert defining_symbol.get("name") in expected_names, f"Expected one of {expected_names}, got: {defining_symbol.get('name')}" - @pytest.mark.parametrize("language_server", [Language.RUBY], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.RUBY], indirect=True) def test_request_defining_symbol_method_call(self, language_server: SolidLanguageServer) -> None: """Test request_defining_symbol for a method call.""" # Test finding the definition of a method being called @@ -596,7 +596,7 @@ class TestRubyLanguageServerSymbols: assert defining_symbol.get("name") == "create_user" assert defining_symbol.get("kind") == SymbolKind.Method.value - @pytest.mark.parametrize("language_server", [Language.RUBY], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.RUBY], indirect=True) def test_request_defining_symbol_nested_function(self, language_server: SolidLanguageServer) -> None: """Test request_defining_symbol for a nested function or block.""" # Test finding definition within nested contexts @@ -612,7 +612,7 @@ class TestRubyLanguageServerSymbols: valid_kinds = [SymbolKind.Method.value, SymbolKind.Function.value, SymbolKind.Variable.value, SymbolKind.Class.value] assert defining_symbol.get("kind") in valid_kinds - @pytest.mark.parametrize("language_server", [Language.RUBY], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.RUBY], indirect=True) def test_containing_symbol_of_var_is_file(self, language_server: SolidLanguageServer) -> None: """Test that the containing symbol of a file-level variable is handled appropriately.""" # Test behavior with file-level variables or constants diff --git a/test/solidlsp/rust/test_rust_2024_edition.py b/test/solidlsp/rust/test_rust_2024_edition.py index 77eb084a..74cba6ec 100644 --- a/test/solidlsp/rust/test_rust_2024_edition.py +++ b/test/solidlsp/rust/test_rust_2024_edition.py @@ -5,7 +5,7 @@ from pathlib import Path import pytest from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from solidlsp.ls_utils import SymbolUtils from test.conftest import start_ls_context @@ -19,7 +19,7 @@ def rust_language_server() -> Iterator[SolidLanguageServer]: pytest.skip("Rust 2024 edition test repository not found") # Create and start the language server for the 2024 edition repo - with start_ls_context(Language.RUST, str(test_repo_2024_path)) as ls: + with start_ls_context(LanguageServerId.RUST, str(test_repo_2024_path)) as ls: yield ls diff --git a/test/solidlsp/rust/test_rust_basic.py b/test/solidlsp/rust/test_rust_basic.py index 4c7ec2c0..446cdfbe 100644 --- a/test/solidlsp/rust/test_rust_basic.py +++ b/test/solidlsp/rust/test_rust_basic.py @@ -3,15 +3,15 @@ import os import pytest from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from solidlsp.ls_utils import SymbolUtils -from test.conftest import find_identifier_position, get_repo_path, language_has_verified_implementation_support +from test.conftest import find_identifier_position, get_repo_path, ls_has_verified_implementation_support from test.solidlsp.conftest import format_symbol_for_assert, has_malformed_name, request_all_symbols @pytest.mark.rust class TestRustLanguageServer: - @pytest.mark.parametrize("language_server", [Language.RUST], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.RUST], indirect=True) def test_find_references_raw(self, language_server: SolidLanguageServer) -> None: # Directly test the request_references method for the add function file_path = os.path.join("src", "lib.rs") @@ -28,14 +28,14 @@ class TestRustLanguageServer: "main.rs should reference add (raw, tried all positions in selectionRange)" ) - @pytest.mark.parametrize("language_server", [Language.RUST], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.RUST], indirect=True) def test_find_symbol(self, language_server: SolidLanguageServer) -> None: symbols = language_server.request_full_symbol_tree() assert SymbolUtils.symbol_tree_contains_name(symbols, "main"), "main function not found in symbol tree" assert SymbolUtils.symbol_tree_contains_name(symbols, "add"), "add function not found in symbol tree" # Add more as needed based on test_repo - @pytest.mark.parametrize("language_server", [Language.RUST], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.RUST], indirect=True) def test_find_referencing_symbols(self, language_server: SolidLanguageServer) -> None: # Find references to 'add' defined in lib.rs, should be referenced from main.rs file_path = os.path.join("src", "lib.rs") @@ -52,17 +52,17 @@ class TestRustLanguageServer: "main.rs should reference add (tried all positions in selectionRange)" ) - @pytest.mark.parametrize("language_server", [Language.RUST], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.RUST], indirect=True) def test_overview_methods(self, language_server: SolidLanguageServer) -> None: symbols = language_server.request_full_symbol_tree() assert SymbolUtils.symbol_tree_contains_name(symbols, "main"), "main missing from overview" assert SymbolUtils.symbol_tree_contains_name(symbols, "add"), "add missing from overview" - if language_has_verified_implementation_support(Language.RUST): + if ls_has_verified_implementation_support(LanguageServerId.RUST): - @pytest.mark.parametrize("language_server", [Language.RUST], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.RUST], indirect=True) def test_find_implementations(self, language_server: SolidLanguageServer) -> None: - repo_path = get_repo_path(Language.RUST) + repo_path = get_repo_path(LanguageServerId.RUST) pos = find_identifier_position(repo_path / os.path.join("src", "lib.rs"), "format_greeting") assert pos is not None, "Could not find Greeter.format_greeting in fixture" @@ -72,9 +72,9 @@ class TestRustLanguageServer: f"Expected ConsoleGreeter.format_greeting in implementations, got: {implementations}" ) - @pytest.mark.parametrize("language_server", [Language.RUST], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.RUST], indirect=True) def test_request_implementing_symbols(self, language_server: SolidLanguageServer) -> None: - repo_path = get_repo_path(Language.RUST) + repo_path = get_repo_path(LanguageServerId.RUST) pos = find_identifier_position(repo_path / os.path.join("src", "lib.rs"), "format_greeting") assert pos is not None, "Could not find Greeter.format_greeting in fixture" @@ -85,7 +85,7 @@ class TestRustLanguageServer: for symbol in implementing_symbols ), f"Expected ConsoleGreeter.format_greeting symbol, got: {implementing_symbols}" - @pytest.mark.parametrize("language_server", [Language.RUST], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.RUST], indirect=True) def test_bare_symbol_names(self, language_server) -> None: all_symbols = request_all_symbols(language_server) malformed_symbols = [] diff --git a/test/solidlsp/rust/test_rust_diagnostics.py b/test/solidlsp/rust/test_rust_diagnostics.py index b08f7cf7..f847bd13 100644 --- a/test/solidlsp/rust/test_rust_diagnostics.py +++ b/test/solidlsp/rust/test_rust_diagnostics.py @@ -1,13 +1,13 @@ import pytest from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from test.solidlsp.util.diagnostics import assert_file_diagnostics @pytest.mark.rust class TestRustDiagnostics: - @pytest.mark.parametrize("language_server", [Language.RUST], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.RUST], indirect=True) def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None: assert_file_diagnostics( language_server, diff --git a/test/solidlsp/scala/test_scala_language_server.py b/test/solidlsp/scala/test_scala_language_server.py index aa94eb32..7ac36710 100644 --- a/test/solidlsp/scala/test_scala_language_server.py +++ b/test/solidlsp/scala/test_scala_language_server.py @@ -3,7 +3,7 @@ import os import pytest from solidlsp.language_servers.scala_language_server import ScalaLanguageServer -from solidlsp.ls_config import Language, LanguageServerConfig +from solidlsp.ls_config import LanguageServerConfig, LanguageServerId from solidlsp.settings import SolidLSPSettings from test.solidlsp.util.diagnostics import assert_file_diagnostics @@ -17,7 +17,7 @@ pytestmark = pytest.mark.scala @pytest.fixture(scope="module") def scala_ls(): repo_root = os.path.abspath("test/resources/repos/scala") - config = LanguageServerConfig(code_language=Language.SCALA) + config = LanguageServerConfig(ls_id=LanguageServerId.SCALA) solidlsp_settings = SolidLSPSettings() ls = ScalaLanguageServer(config, repo_root, solidlsp_settings) diff --git a/test/solidlsp/scala/test_scala_stale_lock_handling.py b/test/solidlsp/scala/test_scala_stale_lock_handling.py index d2819c02..1a8fe984 100644 --- a/test/solidlsp/scala/test_scala_stale_lock_handling.py +++ b/test/solidlsp/scala/test_scala_stale_lock_handling.py @@ -14,7 +14,7 @@ import pytest from _pytest.logging import LogCaptureFixture from solidlsp.language_servers.scala_language_server import ScalaLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from solidlsp.settings import SolidLSPSettings from solidlsp.util.metals_db_utils import MetalsDbStatus, MetalsLockInfo @@ -69,7 +69,7 @@ class TestStaleLockHandling: ): # Create instance without calling __init__ ls = object.__new__(ScalaLanguageServer) - settings = SolidLSPSettings(ls_specific_settings={Language.SCALA: {"on_stale_lock": "auto-clean"}}) + settings = SolidLSPSettings(ls_specific_settings={LanguageServerId.SCALA: {"on_stale_lock": "auto-clean"}}) # Call the method under test ls._check_metals_db_status(str(tmp_path), settings) @@ -100,7 +100,7 @@ class TestStaleLockHandling: caplog.at_level(logging.WARNING), ): ls = object.__new__(ScalaLanguageServer) - settings = SolidLSPSettings(ls_specific_settings={Language.SCALA: {"on_stale_lock": "warn"}}) + settings = SolidLSPSettings(ls_specific_settings={LanguageServerId.SCALA: {"on_stale_lock": "warn"}}) ls._check_metals_db_status(str(tmp_path), settings) @@ -128,7 +128,7 @@ class TestStaleLockHandling: pytest.raises(MetalsStaleLockError) as exc_info, ): ls = object.__new__(ScalaLanguageServer) - settings = SolidLSPSettings(ls_specific_settings={Language.SCALA: {"on_stale_lock": "fail"}}) + settings = SolidLSPSettings(ls_specific_settings={LanguageServerId.SCALA: {"on_stale_lock": "fail"}}) ls._check_metals_db_status(str(tmp_path), settings) @@ -160,7 +160,7 @@ class TestStaleLockHandling: ls = object.__new__(ScalaLanguageServer) settings = SolidLSPSettings( ls_specific_settings={ - Language.SCALA: { + LanguageServerId.SCALA: { "on_stale_lock": "auto-clean", "log_multi_instance_notice": True, } @@ -198,7 +198,7 @@ class TestStaleLockHandling: ls = object.__new__(ScalaLanguageServer) settings = SolidLSPSettings( ls_specific_settings={ - Language.SCALA: { + LanguageServerId.SCALA: { "on_stale_lock": "auto-clean", "log_multi_instance_notice": False, } @@ -226,7 +226,7 @@ class TestStaleLockHandling: caplog.at_level(logging.DEBUG), ): ls = object.__new__(ScalaLanguageServer) - settings = SolidLSPSettings(ls_specific_settings={Language.SCALA: {"on_stale_lock": "auto-clean"}}) + settings = SolidLSPSettings(ls_specific_settings={LanguageServerId.SCALA: {"on_stale_lock": "auto-clean"}}) # Should complete without error ls._check_metals_db_status(str(tmp_path), settings) @@ -251,7 +251,7 @@ class TestStaleLockHandling: caplog.at_level(logging.DEBUG), ): ls = object.__new__(ScalaLanguageServer) - settings = SolidLSPSettings(ls_specific_settings={Language.SCALA: {"on_stale_lock": "auto-clean"}}) + settings = SolidLSPSettings(ls_specific_settings={LanguageServerId.SCALA: {"on_stale_lock": "auto-clean"}}) # Should complete without error ls._check_metals_db_status(str(tmp_path), settings) diff --git a/test/solidlsp/scss/test_scss_basic.py b/test/solidlsp/scss/test_scss_basic.py index ed879585..7266f85d 100644 --- a/test/solidlsp/scss/test_scss_basic.py +++ b/test/solidlsp/scss/test_scss_basic.py @@ -14,7 +14,7 @@ import pytest from serena.util.text_utils import find_text_coordinates from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from solidlsp.ls_types import SymbolKind from solidlsp.lsp_protocol_handler import lsp_types as LSPTypes from test.solidlsp.conftest import read_repo_file, request_all_symbols @@ -22,20 +22,20 @@ from test.solidlsp.conftest import read_repo_file, request_all_symbols @pytest.mark.scss class TestScssLanguageServerBasics: - @pytest.mark.parametrize("language_server", [Language.SCSS], indirect=True) - @pytest.mark.parametrize("repo_path", [Language.SCSS], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.SCSS], indirect=True) + @pytest.mark.parametrize("repo_path", [LanguageServerId.SCSS], indirect=True) def test_ls_is_running(self, language_server: SolidLanguageServer, repo_path: Path) -> None: assert language_server.is_running() assert Path(language_server.language_server.repository_root_path).resolve() == repo_path.resolve() - @pytest.mark.parametrize("language_server", [Language.SCSS], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.SCSS], indirect=True) def test_variables_document_symbols(self, language_server: SolidLanguageServer) -> None: all_symbols, _ = language_server.request_document_symbols("_variables.scss").get_all_symbols_and_roots() names = [s["name"] for s in all_symbols] for var in ("$color-primary", "$color-secondary", "$color-text", "$space-md", "$space-lg"): assert var in names, f"Expected variable {var} to appear in SCSS symbols: {names}" - @pytest.mark.parametrize("language_server", [Language.SCSS], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.SCSS], indirect=True) def test_mixins_document_symbols(self, language_server: SolidLanguageServer) -> None: all_symbols, _ = language_server.request_document_symbols("_mixins.scss").get_all_symbols_and_roots() names = [s["name"] for s in all_symbols] @@ -45,7 +45,7 @@ class TestScssLanguageServerBasics: for expected in ("card-surface", "focus-ring", "rem"): assert expected in joined, f"Expected '{expected}' to appear in SCSS mixin symbols: {names}" - @pytest.mark.parametrize("language_server", [Language.SCSS], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.SCSS], indirect=True) def test_buttons_document_symbols(self, language_server: SolidLanguageServer) -> None: all_symbols, _ = language_server.request_document_symbols("buttons.scss").get_all_symbols_and_roots() names = [s["name"] for s in all_symbols] @@ -53,7 +53,7 @@ class TestScssLanguageServerBasics: for selector in (".button", ".button-primary", ".button-secondary"): assert selector in joined, f"Expected selector '{selector}' to appear in SCSS symbols: {names}" - @pytest.mark.parametrize("language_server", [Language.SCSS], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.SCSS], indirect=True) def test_cross_file_definition_variable(self, language_server: SolidLanguageServer) -> None: """`vars.$color-text` in buttons.scss must resolve into _variables.scss.""" path = "buttons.scss" @@ -69,7 +69,7 @@ class TestScssLanguageServerBasics: f"Expected definition to resolve into _variables.scss, got URIs: {target_uris}" ) - @pytest.mark.parametrize("language_server", [Language.SCSS], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.SCSS], indirect=True) def test_cross_file_definition_mixin(self, language_server: SolidLanguageServer) -> None: """`mix.card-surface` in buttons.scss must resolve into _mixins.scss.""" path = "buttons.scss" @@ -84,7 +84,7 @@ class TestScssLanguageServerBasics: f"Expected definition to resolve into _mixins.scss, got URIs: {target_uris}" ) - @pytest.mark.parametrize("language_server", [Language.SCSS], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.SCSS], indirect=True) def test_cross_file_definition_function(self, language_server: SolidLanguageServer) -> None: """`mix.rem(16)` in main.scss must resolve into _mixins.scss (an @function).""" path = "main.scss" @@ -100,7 +100,7 @@ class TestScssLanguageServerBasics: f"Expected definition to resolve into _mixins.scss, got URIs: {target_uris}" ) - @pytest.mark.parametrize("language_server", [Language.SCSS], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.SCSS], indirect=True) def test_full_symbol_tree_includes_all_files(self, language_server: SolidLanguageServer) -> None: all_symbols = request_all_symbols(language_server) relative_paths = {s.get("location", {}).get("relativePath") for s in all_symbols} @@ -112,7 +112,7 @@ class TestScssLanguageServerBasics: class TestScssReferences: """Find-references for symbols re-exported via @use across files.""" - @pytest.mark.parametrize("language_server", [Language.SCSS], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.SCSS], indirect=True) def test_mixin_references_span_files(self, language_server: SolidLanguageServer) -> None: """References for ``card-surface`` must include both ``buttons.scss`` (`.button`, `.button-primary`, `.button-secondary` all `@include` it) and @@ -135,7 +135,7 @@ class TestScssReferences: ) assert any(p.endswith("main.scss") for p in ref_paths), f"Expected card-surface references to include main.scss, got: {ref_paths}" - @pytest.mark.parametrize("language_server", [Language.SCSS], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.SCSS], indirect=True) def test_variable_references_span_files(self, language_server: SolidLanguageServer) -> None: """`$color-primary` is read in ``buttons.scss`` (`.button-primary` background) and ``_mixins.scss`` (default value of ``focus-ring``); references invoked @@ -160,7 +160,7 @@ class TestScssReferences: class TestScssForward: """`@forward` re-exports a module; consumers should reach forwarded symbols.""" - @pytest.mark.parametrize("language_server", [Language.SCSS], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.SCSS], indirect=True) def test_forwarded_buttons_appear_in_workspace(self, language_server: SolidLanguageServer) -> None: """``main.scss`` does ``@forward "buttons"``; the workspace symbol tree must still include ``buttons.scss`` selectors so consumers of `main` can navigate. @@ -176,7 +176,7 @@ class TestScssForward: class TestScssHover: """Some Sass returns rich hover content (SassDoc / value preview).""" - @pytest.mark.parametrize("language_server", [Language.SCSS], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.SCSS], indirect=True) def test_hover_on_variable_use(self, language_server: SolidLanguageServer) -> None: path = "buttons.scss" needle = "$color-text" @@ -190,7 +190,7 @@ class TestScssHover: text = contents["value"] if isinstance(contents, dict) else str(contents) assert "color-text" in text, f"Expected '$color-text' or its value in hover text, got: {text}" - @pytest.mark.parametrize("language_server", [Language.SCSS], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.SCSS], indirect=True) def test_hover_on_mixin_call(self, language_server: SolidLanguageServer) -> None: path = "buttons.scss" needle = "card-surface" @@ -209,7 +209,7 @@ class TestScssHover: class TestScssCompletions: """Completions after a namespaced @use prefix should list re-exported members.""" - @pytest.mark.parametrize("language_server", [Language.SCSS], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.SCSS], indirect=True) def test_completion_after_namespace_dot(self, language_server: SolidLanguageServer) -> None: """Completion immediately after `vars.` in buttons.scss must include the variables defined in _variables.scss (e.g. ``$color-primary``). @@ -233,7 +233,7 @@ class TestScssCompletions: class TestScssSymbolKinds: """Validate that Some Sass classifies SCSS symbols with sensible LSP kinds.""" - @pytest.mark.parametrize("language_server", [Language.SCSS], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.SCSS], indirect=True) def test_variable_symbol_kind(self, language_server: SolidLanguageServer) -> None: all_symbols, _ = language_server.request_document_symbols("_variables.scss").get_all_symbols_and_roots() by_name = {s["name"]: s for s in all_symbols} @@ -243,7 +243,7 @@ class TestScssSymbolKinds: f"Expected $color-primary to be Variable/Constant/Property, got {kind.name}" ) - @pytest.mark.parametrize("language_server", [Language.SCSS], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.SCSS], indirect=True) def test_mixin_and_function_symbol_kinds(self, language_server: SolidLanguageServer) -> None: all_symbols, _ = language_server.request_document_symbols("_mixins.scss").get_all_symbols_and_roots() @@ -264,7 +264,7 @@ class TestScssSymbolKinds: ) assert SymbolKind(func["kind"]) in callable_kinds, f"Expected rem kind in {{Method, Function}}, got {SymbolKind(func['kind']).name}" - @pytest.mark.parametrize("language_server", [Language.SCSS], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.SCSS], indirect=True) def test_completion_kind_is_meaningful(self, language_server: SolidLanguageServer) -> None: """A `$variable` completion must come back with a meaningful kind. Some Sass tags color-valued variables as ``Color`` (so editors render swatches) and @@ -307,7 +307,7 @@ class TestScssSymbolKinds: class TestSomeSassWithPlainCss: """``Language.SCSS`` also handles plain ``.css`` via ``some-sass-language-server``.""" - @pytest.mark.parametrize("language_server", [Language.SCSS], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.SCSS], indirect=True) def test_main_css_document_symbols(self, language_server: SolidLanguageServer) -> None: """Each top-level rule selector in ``main.css`` must surface as a document symbol.""" all_symbols, _ = language_server.request_document_symbols("css/main.css").get_all_symbols_and_roots() @@ -316,7 +316,7 @@ class TestSomeSassWithPlainCss: for selector in ("body", "#page-header", "#site-title", ".button", ".button-primary", ".button-secondary"): assert selector in joined, f"Expected selector '{selector}' to appear in CSS symbols: {names}" - @pytest.mark.parametrize("language_server", [Language.SCSS], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.SCSS], indirect=True) def test_theme_css_document_symbols(self, language_server: SolidLanguageServer) -> None: """``theme.css`` contains a single ``:root`` block; the LS must report it as a symbol.""" all_symbols, _ = language_server.request_document_symbols("css/theme.css").get_all_symbols_and_roots() @@ -324,7 +324,7 @@ class TestSomeSassWithPlainCss: joined = " | ".join(names) assert ":root" in joined, f"Expected ':root' selector to appear in CSS symbols: {names}" - @pytest.mark.parametrize("language_server", [Language.SCSS], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.SCSS], indirect=True) def test_full_symbol_tree_includes_css_files(self, language_server: SolidLanguageServer) -> None: """The ``.css`` files alongside the SCSS workspace must populate the workspace symbol tree.""" all_symbols = request_all_symbols(language_server) @@ -334,7 +334,7 @@ class TestSomeSassWithPlainCss: for f in (os.path.join("css", "main.css"), os.path.join("css", "reset.css"), os.path.join("css", "theme.css")): assert f in relative_paths, f"Expected {f} to appear in symbol tree" - @pytest.mark.parametrize("language_server", [Language.SCSS], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.SCSS], indirect=True) def test_hover_on_css_property(self, language_server: SolidLanguageServer) -> None: """Hover on a CSS property name must produce non-empty MDN-backed content (Some Sass forwards ``vscode-css-languageservice``'s property reference data). @@ -351,7 +351,7 @@ class TestSomeSassWithPlainCss: text = contents["value"] if isinstance(contents, dict) else str(contents) assert "background" in text.lower(), f"Expected hover text to mention 'background', got: {text}" - @pytest.mark.parametrize("language_server", [Language.SCSS], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.SCSS], indirect=True) def test_property_completion_in_css_rule(self, language_server: SolidLanguageServer) -> None: """Inside a CSS rule body the LS must offer standard property names — proves ``somesass.css.completion.enabled = true`` is being honoured. @@ -367,7 +367,7 @@ class TestSomeSassWithPlainCss: f"Expected at least one common CSS property name in completions, got sample: {sorted(labels)[:20]}" ) - @pytest.mark.parametrize("language_server", [Language.SCSS], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.SCSS], indirect=True) def test_cross_file_completion_for_css_custom_property(self, language_server: SolidLanguageServer) -> None: """Completion inside a ``var(...)`` call in ``main.css`` must surface the ``--color-*`` custom properties declared in ``theme.css``. diff --git a/test/solidlsp/scss/test_scss_diagnostics.py b/test/solidlsp/scss/test_scss_diagnostics.py index f5a2c903..436c0611 100644 --- a/test/solidlsp/scss/test_scss_diagnostics.py +++ b/test/solidlsp/scss/test_scss_diagnostics.py @@ -11,13 +11,13 @@ prefixes / empty rules / etc.) so only syntax-level errors surface here. import pytest from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from test.solidlsp.util.diagnostics import assert_file_diagnostics @pytest.mark.scss class TestScssDiagnostics: - @pytest.mark.parametrize("language_server", [Language.SCSS], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.SCSS], indirect=True) def test_scss_file_diagnostics(self, language_server: SolidLanguageServer) -> None: assert_file_diagnostics( language_server, @@ -26,7 +26,7 @@ class TestScssDiagnostics: min_count=1, ) - @pytest.mark.parametrize("language_server", [Language.SCSS], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.SCSS], indirect=True) def test_plain_css_file_diagnostics(self, language_server: SolidLanguageServer) -> None: """Plain ``.css`` diagnostics flow through the same Some Sass server. diff --git a/test/solidlsp/solidity/test_solidity_basic.py b/test/solidlsp/solidity/test_solidity_basic.py index 2279140e..9c1512ae 100644 --- a/test/solidlsp/solidity/test_solidity_basic.py +++ b/test/solidlsp/solidity/test_solidity_basic.py @@ -12,8 +12,8 @@ from typing import Optional import pytest from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language -from test.conftest import language_has_verified_implementation_support +from solidlsp.ls_config import LanguageServerId +from test.conftest import ls_has_verified_implementation_support from test.solidlsp.conftest import format_symbol_for_assert, has_malformed_name, request_all_symbols @@ -37,17 +37,17 @@ def _find_identifier_position(file_path: Path, symbol_name: str) -> Optional[tup class TestSolidityLanguageServerBasics: """Test basic functionality of the Solidity language server.""" - @pytest.mark.parametrize("language_server", [Language.SOLIDITY], indirect=True) - @pytest.mark.parametrize("repo_path", [Language.SOLIDITY], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.SOLIDITY], indirect=True) + @pytest.mark.parametrize("repo_path", [LanguageServerId.SOLIDITY], indirect=True) def test_solidity_language_server_initialization(self, language_server: SolidLanguageServer, repo_path: Path) -> None: """Test that the Solidity language server starts and initializes correctly.""" assert language_server is not None - assert language_server.language == Language.SOLIDITY + assert language_server.ls_id == LanguageServerId.SOLIDITY assert language_server.is_running() assert Path(language_server.language_server.repository_root_path).resolve() == repo_path.resolve() - @pytest.mark.parametrize("language_server", [Language.SOLIDITY], indirect=True) - @pytest.mark.parametrize("repo_path", [Language.SOLIDITY], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.SOLIDITY], indirect=True) + @pytest.mark.parametrize("repo_path", [LanguageServerId.SOLIDITY], indirect=True) def test_token_contract_symbols(self, language_server: SolidLanguageServer, repo_path: Path) -> None: """Test that document symbols are found in Token.sol. @@ -79,8 +79,8 @@ class TestSolidityLanguageServerBasics: assert "approve" in symbol_names, "Should detect the 'approve' function" assert "transferFrom" in symbol_names, "Should detect the 'transferFrom' function" - @pytest.mark.parametrize("language_server", [Language.SOLIDITY], indirect=True) - @pytest.mark.parametrize("repo_path", [Language.SOLIDITY], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.SOLIDITY], indirect=True) + @pytest.mark.parametrize("repo_path", [LanguageServerId.SOLIDITY], indirect=True) def test_interface_symbols(self, language_server: SolidLanguageServer, repo_path: Path) -> None: """Test that document symbols are found in IERC20.sol.""" all_symbols, root_symbols = language_server.request_document_symbols("contracts/interfaces/IERC20.sol").get_all_symbols_and_roots() @@ -107,8 +107,8 @@ class TestSolidityLanguageServerBasics: assert "approve" in symbol_names, "Should detect approve" assert "transferFrom" in symbol_names, "Should detect transferFrom" - @pytest.mark.parametrize("language_server", [Language.SOLIDITY], indirect=True) - @pytest.mark.parametrize("repo_path", [Language.SOLIDITY], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.SOLIDITY], indirect=True) + @pytest.mark.parametrize("repo_path", [LanguageServerId.SOLIDITY], indirect=True) def test_library_symbols(self, language_server: SolidLanguageServer, repo_path: Path) -> None: """Test that document symbols are found in SafeMath.sol.""" all_symbols, root_symbols = language_server.request_document_symbols("contracts/lib/SafeMath.sol").get_all_symbols_and_roots() @@ -127,8 +127,8 @@ class TestSolidityLanguageServerBasics: assert "mul" in symbol_names, "Should detect the 'mul' function" assert "div" in symbol_names, "Should detect the 'div' function" - @pytest.mark.parametrize("language_server", [Language.SOLIDITY], indirect=True) - @pytest.mark.parametrize("repo_path", [Language.SOLIDITY], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.SOLIDITY], indirect=True) + @pytest.mark.parametrize("repo_path", [LanguageServerId.SOLIDITY], indirect=True) def test_within_file_references(self, language_server: SolidLanguageServer, repo_path: Path) -> None: """Test finding within-file references to the _transfer helper in Token.sol.""" # Use the file to find the exact identifier position: the Solidity LSP reports @@ -148,8 +148,8 @@ class TestSolidityLanguageServerBasics: ref_files = {ref.get("uri", "") for ref in references} assert any("Token.sol" in uri for uri in ref_files), "References should include Token.sol" - @pytest.mark.parametrize("language_server", [Language.SOLIDITY], indirect=True) - @pytest.mark.parametrize("repo_path", [Language.SOLIDITY], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.SOLIDITY], indirect=True) + @pytest.mark.parametrize("repo_path", [LanguageServerId.SOLIDITY], indirect=True) def test_cross_file_references(self, language_server: SolidLanguageServer, repo_path: Path) -> None: """Test finding cross-file references: IERC20.transfer implemented in Token.sol.""" # Use 'transfer' in the interface — Token.sol inherits IERC20 and overrides it, @@ -166,10 +166,10 @@ class TestSolidityLanguageServerBasics: ref_files = {ref.get("uri", "") for ref in references} assert any("Token.sol" in uri for uri in ref_files), "IERC20.transfer references should include Token.sol" - if language_has_verified_implementation_support(Language.SOLIDITY): + if ls_has_verified_implementation_support(LanguageServerId.SOLIDITY): - @pytest.mark.parametrize("language_server", [Language.SOLIDITY], indirect=True) - @pytest.mark.parametrize("repo_path", [Language.SOLIDITY], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.SOLIDITY], indirect=True) + @pytest.mark.parametrize("repo_path", [LanguageServerId.SOLIDITY], indirect=True) def test_find_implementations(self, language_server: SolidLanguageServer, repo_path: Path) -> None: pos = _find_identifier_position(repo_path / "contracts/interfaces/IERC20.sol", "transfer") assert pos is not None, "Should find 'transfer' identifier in IERC20.sol" @@ -180,8 +180,8 @@ class TestSolidityLanguageServerBasics: f"Expected Token.transfer implementation, got: {implementations}" ) - @pytest.mark.parametrize("language_server", [Language.SOLIDITY], indirect=True) - @pytest.mark.parametrize("repo_path", [Language.SOLIDITY], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.SOLIDITY], indirect=True) + @pytest.mark.parametrize("repo_path", [LanguageServerId.SOLIDITY], indirect=True) def test_request_implementing_symbols(self, language_server: SolidLanguageServer, repo_path: Path) -> None: pos = _find_identifier_position(repo_path / "contracts/interfaces/IERC20.sol", "transfer") assert pos is not None, "Should find 'transfer' identifier in IERC20.sol" @@ -193,7 +193,7 @@ class TestSolidityLanguageServerBasics: for symbol in implementing_symbols ), f"Expected Token.transfer symbol, got: {implementing_symbols}" - @pytest.mark.parametrize("language_server", [Language.SOLIDITY], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.SOLIDITY], indirect=True) def test_bare_symbol_names(self, language_server) -> None: all_symbols = request_all_symbols(language_server) malformed_symbols = [] diff --git a/test/solidlsp/solidity/test_solidity_diagnostics.py b/test/solidlsp/solidity/test_solidity_diagnostics.py index 21a11f3c..84f7e0d7 100644 --- a/test/solidlsp/solidity/test_solidity_diagnostics.py +++ b/test/solidlsp/solidity/test_solidity_diagnostics.py @@ -2,7 +2,7 @@ import pytest from solidlsp import SolidLanguageServer from solidlsp.language_servers.solidity_language_server import SolidityLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from test.solidlsp.util.diagnostics import assert_file_diagnostics @@ -37,7 +37,7 @@ class _AlwaysSignalledEvent: @pytest.mark.solidity class TestSolidityDiagnostics: - @pytest.mark.parametrize("language_server", [Language.SOLIDITY], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.SOLIDITY], indirect=True) def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None: assert_file_diagnostics( language_server, @@ -46,7 +46,7 @@ class TestSolidityDiagnostics: min_count=1, ) - @pytest.mark.parametrize("language_server", [Language.SOLIDITY], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.SOLIDITY], indirect=True) def test_file_diagnostics_via_validation_completion( self, language_server: SolidLanguageServer, monkeypatch: pytest.MonkeyPatch ) -> None: @@ -65,7 +65,7 @@ class TestSolidityDiagnostics: min_count=1, ) - @pytest.mark.parametrize("language_server", [Language.SOLIDITY], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.SOLIDITY], indirect=True) def test_file_diagnostics_without_validation_signal( self, language_server: SolidLanguageServer, monkeypatch: pytest.MonkeyPatch ) -> None: @@ -82,7 +82,7 @@ class TestSolidityDiagnostics: diagnostics = language_server.request_text_document_diagnostics("contracts/DiagnosticsSample.sol", min_severity=1) assert diagnostics == [] - @pytest.mark.parametrize("language_server", [Language.SOLIDITY], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.SOLIDITY], indirect=True) def test_file_diagnostics_rearms_after_spurious_completion( self, language_server: SolidLanguageServer, monkeypatch: pytest.MonkeyPatch ) -> None: diff --git a/test/solidlsp/svelte/test_svelte_basic.py b/test/solidlsp/svelte/test_svelte_basic.py index 7218cc0f..3757ff83 100644 --- a/test/solidlsp/svelte/test_svelte_basic.py +++ b/test/solidlsp/svelte/test_svelte_basic.py @@ -5,7 +5,7 @@ import pytest from serena.util.text_utils import find_text_coordinates from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from solidlsp.ls_utils import SymbolUtils from test.solidlsp.conftest import read_repo_file from test.solidlsp.svelte import conftest as svelte_test_conftest @@ -15,14 +15,14 @@ pytestmark = pytest.mark.svelte class TestSvelteLanguageServer: - @pytest.mark.parametrize("language_server", [Language.SVELTE], indirect=True) - @pytest.mark.parametrize("repo_path", [Language.SVELTE], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.SVELTE], indirect=True) + @pytest.mark.parametrize("repo_path", [LanguageServerId.SVELTE], indirect=True) def test_svelte_language_server_root_matches_repo_path(self, language_server: SolidLanguageServer, repo_path: Path) -> None: assert language_server.is_running() assert repo_path.resolve() == svelte_test_conftest.repo_path.resolve() assert Path(language_server.language_server.repo_path).resolve() == repo_path.resolve() - @pytest.mark.parametrize("language_server", [Language.SVELTE], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.SVELTE], indirect=True) def test_svelte_and_typescript_files_in_symbol_tree(self, language_server: SolidLanguageServer) -> None: symbols = language_server.request_full_symbol_tree() @@ -37,7 +37,7 @@ class TestSvelteLanguageServer: "GAME_VERSION (defined only in a .ts file) not found in symbol tree" ) - @pytest.mark.parametrize("language_server", [Language.SVELTE], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.SVELTE], indirect=True) def test_document_symbols_inside_svelte_file(self, language_server: SolidLanguageServer) -> None: file_path = os.path.join("src", "lib", "components", "Counter.svelte") symbols = language_server.request_document_symbols(file_path).get_all_symbols_and_roots() @@ -46,7 +46,7 @@ class TestSvelteLanguageServer: assert "offset" in symbol_names assert "modulo" in symbol_names - @pytest.mark.parametrize("language_server", [Language.SVELTE], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.SVELTE], indirect=True) def test_document_symbols_inside_typescript_file(self, language_server: SolidLanguageServer) -> None: # document symbols of a plain .ts file must be served by the companion TS server, not the # base svelte LS (which only provides documentSymbol for .svelte files); see issue #1552. @@ -60,7 +60,7 @@ class TestSvelteLanguageServer: assert "enter" in symbol_names, symbol_names assert "toString" in symbol_names, symbol_names - @pytest.mark.parametrize("language_server", [Language.SVELTE], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.SVELTE], indirect=True) def test_overview_of_typescript_file(self, language_server: SolidLanguageServer) -> None: # get_symbols_overview on a .ts file must not be empty in svelte-only mode (issue #1552). file_path = os.path.join("src", "lib", "game.ts") @@ -70,7 +70,7 @@ class TestSvelteLanguageServer: assert "GAME_VERSION" in top_level_names, overview assert "Game" in top_level_names, overview - @pytest.mark.parametrize("language_server", [Language.SVELTE], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.SVELTE], indirect=True) def test_definition_from_component_import_to_svelte_file(self, language_server: SolidLanguageServer) -> None: file_path = os.path.join("src", "lib", "components", "Header.svelte") coords = find_text_coordinates(read_repo_file(language_server, file_path), r"(count)") @@ -81,7 +81,7 @@ class TestSvelteLanguageServer: assert len(definitions) == 1, definition_paths assert definitions[0]["relativePath"].replace("\\", "/") == "src/lib/components/Counter.svelte", definition_paths - @pytest.mark.parametrize("language_server", [Language.SVELTE], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.SVELTE], indirect=True) def test_diagnostics_in_typescript_file(self, language_server: SolidLanguageServer) -> None: assert_file_diagnostics( language_server, @@ -90,7 +90,7 @@ class TestSvelteLanguageServer: min_count=2, ) - @pytest.mark.parametrize("language_server", [Language.SVELTE], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.SVELTE], indirect=True) def test_diagnostics_in_svelte_file(self, language_server: SolidLanguageServer) -> None: assert_file_diagnostics( language_server, diff --git a/test/solidlsp/svelte/test_svelte_references.py b/test/solidlsp/svelte/test_svelte_references.py index 07630c8d..2fc7bdbf 100644 --- a/test/solidlsp/svelte/test_svelte_references.py +++ b/test/solidlsp/svelte/test_svelte_references.py @@ -3,13 +3,13 @@ import os import pytest from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId pytestmark = pytest.mark.svelte class TestSvelteReferences: - @pytest.mark.parametrize("language_server", [Language.SVELTE], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.SVELTE], indirect=True) def test_references_across_svelte_and_typescript(self, language_server: SolidLanguageServer) -> None: refs = language_server.request_references(os.path.join("src", "lib", "components", "Words.svelte"), 1, 17) ref_paths = {ref["relativePath"].replace("\\", "/") for ref in refs} @@ -18,7 +18,7 @@ class TestSvelteReferences: assert "src/lib/game.ts" in ref_paths, sorted(ref_paths) assert "src/routes/(sverdle)/+page.svelte" in ref_paths, sorted(ref_paths) - @pytest.mark.parametrize("language_server", [Language.SVELTE], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.SVELTE], indirect=True) def test_references_from_typescript_file(self, language_server: SolidLanguageServer) -> None: refs = language_server.request_references(os.path.join("src", "lib", "game.ts"), 3, 13) ref_paths = {ref["relativePath"].replace("\\", "/") for ref in refs} diff --git a/test/solidlsp/svelte/test_svelte_rename.py b/test/solidlsp/svelte/test_svelte_rename.py index 58a0254b..ec550b82 100644 --- a/test/solidlsp/svelte/test_svelte_rename.py +++ b/test/solidlsp/svelte/test_svelte_rename.py @@ -6,7 +6,7 @@ import pytest from serena.util.text_utils import find_text_coordinates from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from solidlsp.ls_types import TextEdit, WorkspaceEdit from test.solidlsp.conftest import read_repo_file @@ -52,7 +52,7 @@ def _assert_rename_edit( class TestSvelteRename: - @pytest.mark.parametrize("language_server", [Language.SVELTE], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.SVELTE], indirect=True) def test_rename_svelte_export_updates_svelte_importers(self, language_server: SolidLanguageServer) -> None: file_path = os.path.join("src", "lib", "components", "Counter.svelte") coords = find_text_coordinates(read_repo_file(language_server, file_path), r"(count)") @@ -65,7 +65,7 @@ class TestSvelteRename: {"src/lib/components/Counter.svelte", "src/lib/components/Header.svelte"}, ) - @pytest.mark.parametrize("language_server", [Language.SVELTE], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.SVELTE], indirect=True) def test_rename_svelte_export_updates_ts_and_svelte_files(self, language_server: SolidLanguageServer) -> None: file_path = os.path.join("src", "lib", "components", "Words.svelte") coords = find_text_coordinates(read_repo_file(language_server, file_path), r"(words)") @@ -83,7 +83,7 @@ class TestSvelteRename: }, ) - @pytest.mark.parametrize("language_server", [Language.SVELTE], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.SVELTE], indirect=True) def test_rename_ts_export_declaration_site_workspace_edit(self, language_server: SolidLanguageServer) -> None: file_path = os.path.join("src", "routes", "(sverdle)", "words.server.ts") coords = find_text_coordinates(read_repo_file(language_server, file_path), r"(allowed)") @@ -98,7 +98,7 @@ class TestSvelteRename: {"src/routes/(sverdle)/words.server.ts"}, ) - @pytest.mark.parametrize("language_server", [Language.SVELTE], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.SVELTE], indirect=True) def test_rename_ts_class_cross_file_workspace_edit_when_supported(self, language_server: SolidLanguageServer) -> None: file_path = os.path.join("src", "lib", "game.ts") coords = find_text_coordinates(read_repo_file(language_server, file_path), r"(Game)") diff --git a/test/solidlsp/svelte/test_svelte_symbols.py b/test/solidlsp/svelte/test_svelte_symbols.py index c6171d4b..49d2b26b 100644 --- a/test/solidlsp/svelte/test_svelte_symbols.py +++ b/test/solidlsp/svelte/test_svelte_symbols.py @@ -17,7 +17,7 @@ import pytest from serena.project import Project from serena.symbol import LanguageServerSymbolRetriever -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from solidlsp.ls_types import SymbolKind pytestmark = pytest.mark.svelte @@ -27,7 +27,7 @@ GAME_TS = os.path.join("src", "lib", "game.ts") class TestSvelteTypeScriptSymbolDiscovery: - @pytest.mark.parametrize("project_with_ls", [Language.SVELTE], indirect=True) + @pytest.mark.parametrize("project_with_ls", [LanguageServerId.SVELTE], indirect=True) def test_find_symbol_in_typescript_file(self, project_with_ls: Project) -> None: retriever = LanguageServerSymbolRetriever(project_with_ls) @@ -47,7 +47,7 @@ class TestSvelteTypeScriptSymbolDiscovery: assert len(enter_symbols) == 1, enter_symbols assert enter_symbols[0].get_name_path() == "Game/enter" - @pytest.mark.parametrize("project_with_ls", [Language.SVELTE], indirect=True) + @pytest.mark.parametrize("project_with_ls", [LanguageServerId.SVELTE], indirect=True) def test_find_referencing_symbols_locates_typescript_symbol(self, project_with_ls: Project) -> None: retriever = LanguageServerSymbolRetriever(project_with_ls) diff --git a/test/solidlsp/swift/test_swift_basic.py b/test/solidlsp/swift/test_swift_basic.py index f4395f4c..22934fe9 100644 --- a/test/solidlsp/swift/test_swift_basic.py +++ b/test/solidlsp/swift/test_swift_basic.py @@ -12,18 +12,21 @@ import pytest from serena.project import Project from serena.util.text_utils import LineType from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language -from test.conftest import is_ci, language_tests_enabled +from solidlsp.ls_config import LanguageServerId +from test.conftest import is_ci, language_server_tests_enabled from test.solidlsp.conftest import format_symbol_for_assert, has_malformed_name, request_all_symbols from test.solidlsp.util.diagnostics import assert_file_diagnostics -pytestmark = [pytest.mark.swift, pytest.mark.skipif(not language_tests_enabled(Language.SWIFT), reason="Swift tests are disabled")] +pytestmark = [ + pytest.mark.swift, + pytest.mark.skipif(not language_server_tests_enabled(LanguageServerId.SWIFT), reason="Swift tests are disabled"), +] class TestSwiftLanguageServerBasics: """Test basic functionality of the Swift language server.""" - @pytest.mark.parametrize("language_server", [Language.SWIFT], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.SWIFT], indirect=True) def test_goto_definition_calculator_class(self, language_server: SolidLanguageServer) -> None: """Test goto_definition on Calculator class usage.""" file_path = os.path.join("src", "main.swift") @@ -42,7 +45,7 @@ class TestSwiftLanguageServerBasics: start_line = calculator_def.get("range", {}).get("start", {}).get("line") assert start_line == 15, f"Calculator class definition should be at line 16, got {start_line + 1}" - @pytest.mark.parametrize("language_server", [Language.SWIFT], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.SWIFT], indirect=True) def test_goto_definition_user_struct(self, language_server: SolidLanguageServer) -> None: """Test goto_definition on User struct usage.""" file_path = os.path.join("src", "main.swift") @@ -61,7 +64,7 @@ class TestSwiftLanguageServerBasics: start_line = user_def.get("range", {}).get("start", {}).get("line") assert start_line == 25, f"User struct definition should be at line 26, got {start_line + 1}" - @pytest.mark.parametrize("language_server", [Language.SWIFT], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.SWIFT], indirect=True) def test_goto_definition_calculator_method(self, language_server: SolidLanguageServer) -> None: """Test goto_definition on Calculator method usage.""" file_path = os.path.join("src", "main.swift") @@ -79,7 +82,7 @@ class TestSwiftLanguageServerBasics: start_line = add_def.get("range", {}).get("start", {}).get("line") assert start_line == 16, f"add method definition should be at line 17, got {start_line + 1}" - @pytest.mark.parametrize("language_server", [Language.SWIFT], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.SWIFT], indirect=True) def test_goto_definition_cross_file(self, language_server: SolidLanguageServer) -> None: """Test goto_definition across files - Utils struct.""" utils_file = os.path.join("src", "utils.swift") @@ -98,7 +101,7 @@ class TestSwiftLanguageServerBasics: assert utils_def.get("uri", "").endswith("utils.swift"), "Definition should be in utils.swift" @pytest.mark.xfail(is_ci, reason="Test is flaky in CI") # See #1040 - @pytest.mark.parametrize("language_server", [Language.SWIFT], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.SWIFT], indirect=True) def test_request_references_calculator_class(self, language_server: SolidLanguageServer) -> None: """Test request_references on the Calculator class.""" # Get references to the Calculator class in main.swift @@ -121,7 +124,7 @@ class TestSwiftLanguageServerBasics: assert len(line_5_refs) > 0, "Calculator should be referenced at line 5" @pytest.mark.xfail(is_ci, reason="Test is flaky in CI") # See #1040 - @pytest.mark.parametrize("language_server", [Language.SWIFT], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.SWIFT], indirect=True) def test_request_references_user_struct(self, language_server: SolidLanguageServer) -> None: """Test request_references on the User struct.""" # Get references to the User struct in main.swift @@ -143,7 +146,7 @@ class TestSwiftLanguageServerBasics: assert len(line_9_refs) > 0, "User should be referenced at line 9" @pytest.mark.xfail(is_ci, reason="Test is flaky in CI") # See #1040 - @pytest.mark.parametrize("language_server", [Language.SWIFT], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.SWIFT], indirect=True) def test_request_references_utils_struct(self, language_server: SolidLanguageServer) -> None: """Test request_references on the Utils struct.""" # Get references to the Utils struct in utils.swift @@ -167,7 +170,7 @@ class TestSwiftLanguageServerBasics: class TestSwiftProjectBasics: - @pytest.mark.parametrize("project", [Language.SWIFT], indirect=True) + @pytest.mark.parametrize("project", [LanguageServerId.SWIFT], indirect=True) def test_retrieve_content_around_line(self, project: Project) -> None: """Test retrieve_content_around_line functionality with various scenarios.""" file_path = os.path.join("src", "main.swift") @@ -222,7 +225,7 @@ class TestSwiftProjectBasics: status_matches = [m for m in matches if "Status" in str(m)] assert len(status_matches) > 0, "Should find Status enum" - @pytest.mark.parametrize("language_server", [Language.SWIFT], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.SWIFT], indirect=True) def test_bare_symbol_names(self, language_server) -> None: all_symbols = request_all_symbols(language_server) malformed_symbols = [] @@ -235,7 +238,7 @@ class TestSwiftProjectBasics: pytrace=False, ) - @pytest.mark.parametrize("language_server", [Language.SWIFT], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.SWIFT], indirect=True) def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None: assert_file_diagnostics( language_server, diff --git a/test/solidlsp/systemverilog/test_systemverilog_basic.py b/test/solidlsp/systemverilog/test_systemverilog_basic.py index 43d75d00..a24f6468 100644 --- a/test/solidlsp/systemverilog/test_systemverilog_basic.py +++ b/test/solidlsp/systemverilog/test_systemverilog_basic.py @@ -10,13 +10,14 @@ from typing import Any import pytest from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from solidlsp.ls_utils import SymbolUtils -from test.conftest import language_tests_enabled +from test.conftest import language_server_tests_enabled from test.solidlsp.conftest import format_symbol_for_assert, has_malformed_name, request_all_symbols pytestmark = pytest.mark.skipif( - not language_tests_enabled(Language.SYSTEMVERILOG), reason="SystemVerilog tests are disabled (verible-verilog-ls not available)" + not language_server_tests_enabled(LanguageServerId.SYSTEMVERILOG), + reason="SystemVerilog tests are disabled (verible-verilog-ls not available)", ) @@ -39,19 +40,19 @@ def _get_symbol_selection_start(language_server: SolidLanguageServer, file_path: class TestSystemVerilogSymbols: """Tests for document symbol extraction.""" - @pytest.mark.parametrize("language_server", [Language.SYSTEMVERILOG], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.SYSTEMVERILOG], indirect=True) def test_find_symbol(self, language_server: SolidLanguageServer) -> None: """Test that symbol tree contains expected modules.""" symbols = language_server.request_full_symbol_tree() assert SymbolUtils.symbol_tree_contains_name(symbols, "counter"), "Module 'counter' not found in symbol tree" - @pytest.mark.parametrize("language_server", [Language.SYSTEMVERILOG], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.SYSTEMVERILOG], indirect=True) def test_get_document_symbols(self, language_server: SolidLanguageServer) -> None: """Test document symbols for counter.sv.""" symbol = _find_symbol_by_name(language_server, "counter.sv", "counter") assert symbol is not None, "Expected 'counter' in document symbols" - @pytest.mark.parametrize("language_server", [Language.SYSTEMVERILOG], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.SYSTEMVERILOG], indirect=True) def test_find_top_module(self, language_server: SolidLanguageServer) -> None: """Test that top module is found (cross-file instantiation test).""" symbols = language_server.request_full_symbol_tree() @@ -62,7 +63,7 @@ class TestSystemVerilogSymbols: class TestSystemVerilogDefinition: """Tests for go-to-definition functionality.""" - @pytest.mark.parametrize("language_server", [Language.SYSTEMVERILOG], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.SYSTEMVERILOG], indirect=True) def test_goto_definition(self, language_server: SolidLanguageServer) -> None: """Test go to definition from signal usage to its declaration. @@ -79,7 +80,7 @@ class TestSystemVerilogDefinition: f"Expected definition at line 7 (output port count), got line {def_in_counter[0]['range']['start']['line']}" ) - @pytest.mark.parametrize("language_server", [Language.SYSTEMVERILOG], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.SYSTEMVERILOG], indirect=True) def test_goto_definition_cross_file(self, language_server: SolidLanguageServer) -> None: """Test go to definition from module instantiation in top.sv to counter.sv. @@ -102,7 +103,7 @@ class TestSystemVerilogDefinition: class TestSystemVerilogReferences: """Tests for find-references functionality.""" - @pytest.mark.parametrize("language_server", [Language.SYSTEMVERILOG], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.SYSTEMVERILOG], indirect=True) def test_find_references(self, language_server: SolidLanguageServer) -> None: """Test finding within-file references to a port signal. @@ -122,7 +123,7 @@ class TestSystemVerilogReferences: assert 13 in ref_lines, f"Expected reference at line 13 (count <= '0), got lines: {ref_lines}" assert 15 in ref_lines, f"Expected reference at line 15 (count <= count + 1'b1), got lines: {ref_lines}" - @pytest.mark.parametrize("language_server", [Language.SYSTEMVERILOG], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.SYSTEMVERILOG], indirect=True) def test_find_references_cross_file(self, language_server: SolidLanguageServer) -> None: """Test that references to counter include its instantiation in top.sv. @@ -154,7 +155,7 @@ def _extract_hover_text(hover_info: dict[str, Any]) -> str: class TestSystemVerilogHover: """Tests for hover information.""" - @pytest.mark.parametrize("language_server", [Language.SYSTEMVERILOG], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.SYSTEMVERILOG], indirect=True) def test_hover(self, language_server: SolidLanguageServer) -> None: """Test hover information (experimental in verible, requires --lsp_enable_hover).""" line, char = _get_symbol_selection_start(language_server, "counter.sv", "counter") @@ -166,7 +167,7 @@ class TestSystemVerilogHover: assert "counter" in hover_text.lower(), f"Hover should mention 'counter', got: {hover_text}" assert "module" in hover_text.lower(), f"Hover should identify 'counter' as a module, got: {hover_text}" - @pytest.mark.parametrize("language_server", [Language.SYSTEMVERILOG], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.SYSTEMVERILOG], indirect=True) def test_hover_includes_type_information(self, language_server: SolidLanguageServer) -> None: """Test that hover includes type information for a port signal. @@ -197,7 +198,7 @@ def _extract_changes(workspace_edit: dict[str, Any]) -> dict[str, list[dict[str, class TestSystemVerilogRename: """Tests for rename functionality.""" - @pytest.mark.parametrize("language_server", [Language.SYSTEMVERILOG], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.SYSTEMVERILOG], indirect=True) def test_rename_signal_within_file(self, language_server: SolidLanguageServer) -> None: """Test renaming a port signal from its declaration updates within-file occurrences. @@ -221,7 +222,7 @@ class TestSystemVerilogRename: for edit in edits: assert edit["newText"] == "cnt", f"Expected newText 'cnt', got {edit['newText']}" - @pytest.mark.parametrize("language_server", [Language.SYSTEMVERILOG], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.SYSTEMVERILOG], indirect=True) def test_rename_signal_cross_file(self, language_server: SolidLanguageServer) -> None: """Test renaming a port signal from a usage site includes cross-file edits. @@ -242,7 +243,7 @@ class TestSystemVerilogRename: for edit in edits: assert edit["newText"] == "cnt", f"Expected 'cnt' in {uri}, got {edit['newText']}" - @pytest.mark.parametrize("language_server", [Language.SYSTEMVERILOG], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.SYSTEMVERILOG], indirect=True) def test_rename_module_name(self, language_server: SolidLanguageServer) -> None: """Test renaming a module name at its declaration. @@ -269,7 +270,7 @@ class TestSystemVerilogRename: for edit in file_edits: assert edit["newText"] == "my_counter", f"Expected 'my_counter', got {edit['newText']}" - @pytest.mark.parametrize("language_server", [Language.SYSTEMVERILOG], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.SYSTEMVERILOG], indirect=True) def test_bare_symbol_names(self, language_server) -> None: all_symbols = request_all_symbols(language_server) malformed_symbols = [] diff --git a/test/solidlsp/systemverilog/test_systemverilog_diagnostics.py b/test/solidlsp/systemverilog/test_systemverilog_diagnostics.py index 3de588c2..feb6bdde 100644 --- a/test/solidlsp/systemverilog/test_systemverilog_diagnostics.py +++ b/test/solidlsp/systemverilog/test_systemverilog_diagnostics.py @@ -1,18 +1,19 @@ import pytest from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language -from test.conftest import language_tests_enabled +from solidlsp.ls_config import LanguageServerId +from test.conftest import language_server_tests_enabled from test.solidlsp.util.diagnostics import assert_file_diagnostics pytestmark = pytest.mark.skipif( - not language_tests_enabled(Language.SYSTEMVERILOG), reason="SystemVerilog tests are disabled (verible-verilog-ls not available)" + not language_server_tests_enabled(LanguageServerId.SYSTEMVERILOG), + reason="SystemVerilog tests are disabled (verible-verilog-ls not available)", ) @pytest.mark.systemverilog class TestSystemverilogDiagnostics: - @pytest.mark.parametrize("language_server", [Language.SYSTEMVERILOG], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.SYSTEMVERILOG], indirect=True) def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None: assert_file_diagnostics( language_server, diff --git a/test/solidlsp/terraform/test_terraform_basic.py b/test/solidlsp/terraform/test_terraform_basic.py index 1a91f0c9..0d9ddcd8 100644 --- a/test/solidlsp/terraform/test_terraform_basic.py +++ b/test/solidlsp/terraform/test_terraform_basic.py @@ -8,18 +8,20 @@ like request_references using the test repository. import pytest from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from solidlsp.ls_types import SymbolKind -from test.conftest import language_tests_enabled +from test.conftest import language_server_tests_enabled from test.solidlsp.conftest import format_symbol_for_assert, has_malformed_name, request_all_symbols -@pytest.mark.skipif(not language_tests_enabled(Language.TERRAFORM), reason="Terraform tests are disabled (terraform CLI not available)") +@pytest.mark.skipif( + not language_server_tests_enabled(LanguageServerId.TERRAFORM), reason="Terraform tests are disabled (terraform CLI not available)" +) @pytest.mark.terraform class TestLanguageServerBasics: """Test basic functionality of the Terraform language server.""" - @pytest.mark.parametrize("language_server", [Language.TERRAFORM], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.TERRAFORM], indirect=True) def test_basic_definition(self, language_server: SolidLanguageServer) -> None: """Test basic definition lookup functionality.""" # Simple test to verify the language server is working @@ -28,7 +30,7 @@ class TestLanguageServerBasics: symbols = language_server.request_document_symbols(file_path).get_all_symbols_and_roots() assert len(symbols) > 0, "Should find at least some symbols in main.tf" - @pytest.mark.parametrize("language_server", [Language.TERRAFORM], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.TERRAFORM], indirect=True) def test_request_references_aws_instance(self, language_server: SolidLanguageServer) -> None: """Test request_references on an aws_instance resource.""" # Get references to an aws_instance resource in main.tf @@ -42,7 +44,7 @@ class TestLanguageServerBasics: references = language_server.request_references(file_path, sel_start["line"], sel_start["character"]) assert len(references) >= 1, "aws_instance should be referenced at least once" - @pytest.mark.parametrize("language_server", [Language.TERRAFORM], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.TERRAFORM], indirect=True) def test_request_references_variable(self, language_server: SolidLanguageServer) -> None: """Test request_references on a variable.""" # Get references to a variable in variables.tf @@ -56,7 +58,7 @@ class TestLanguageServerBasics: references = language_server.request_references(file_path, sel_start["line"], sel_start["character"]) assert len(references) >= 1, "variable should be referenced at least once" - @pytest.mark.parametrize("language_server", [Language.TERRAFORM], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.TERRAFORM], indirect=True) def test_bare_symbol_names(self, language_server) -> None: all_symbols = request_all_symbols(language_server) malformed_symbols = [] diff --git a/test/solidlsp/terraform/test_terraform_diagnostics.py b/test/solidlsp/terraform/test_terraform_diagnostics.py index 318cc7f9..fa4e0bd7 100644 --- a/test/solidlsp/terraform/test_terraform_diagnostics.py +++ b/test/solidlsp/terraform/test_terraform_diagnostics.py @@ -1,13 +1,13 @@ import pytest from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from test.solidlsp.util.diagnostics import assert_file_diagnostics @pytest.mark.terraform class TestTerraformDiagnostics: - @pytest.mark.parametrize("language_server", [Language.TERRAFORM], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.TERRAFORM], indirect=True) def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None: assert_file_diagnostics( language_server, diff --git a/test/solidlsp/test_content_modified_retry.py b/test/solidlsp/test_content_modified_retry.py index b36669bb..4ea4db05 100644 --- a/test/solidlsp/test_content_modified_retry.py +++ b/test/solidlsp/test_content_modified_retry.py @@ -21,7 +21,7 @@ import logging import pytest from solidlsp import ls_process -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from solidlsp.ls_exceptions import SolidLSPException from solidlsp.ls_process import LanguageServerInterface, Request from solidlsp.lsp_protocol_handler.lsp_types import LSPErrorCodes @@ -40,7 +40,7 @@ class _ScriptedServer(LanguageServerInterface): """ def __init__(self, results: list[Request.Result], retry_methods: tuple[str, ...] = ("textDocument/hover",)) -> None: - super().__init__(Language.PYTHON, lambda _line: logging.INFO) + super().__init__(LanguageServerId.PYTHON, lambda _line: logging.INFO) self._results = list(results) self.sent_payload_count = 0 self.set_content_modified_retry_methods(retry_methods) diff --git a/test/solidlsp/test_is_ignored_path_missing.py b/test/solidlsp/test_is_ignored_path_missing.py index 56afc5e7..6847894b 100644 --- a/test/solidlsp/test_is_ignored_path_missing.py +++ b/test/solidlsp/test_is_ignored_path_missing.py @@ -17,7 +17,7 @@ import pathspec import pytest from solidlsp import SolidLanguageServer, ls_types -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from solidlsp.ls_utils import PathUtils @@ -27,13 +27,13 @@ class _IgnoredPathServer(SolidLanguageServer): def __init__( self, root: Path, - language: Language, + language: LanguageServerId, *, ignored_dirnames: tuple[str, ...] = (), ignore_lines: tuple[str, ...] = (), ) -> None: self.repository_root_path = str(root) - self.language = language + self.ls_id = language self._ignored_dirnames = frozenset(ignored_dirnames) self._ignore_spec = pathspec.PathSpec.from_lines(pathspec.patterns.GitWildMatchPattern, ignore_lines) @@ -49,7 +49,7 @@ class _IgnoredPathServer(SolidLanguageServer): def test_missing_lombok_class_under_target_is_ignored_not_raised(tmp_path: Path) -> None: """JDTLS-style missing build artifact under target/classes -- must be ignored, never raise.""" - ls = _IgnoredPathServer(tmp_path, Language.JAVA) + ls = _IgnoredPathServer(tmp_path, LanguageServerId.JAVA) missing = "target/classes/test_repo/LombokModel$LombokModelBuilder.class" assert not (tmp_path / missing).exists() @@ -57,7 +57,7 @@ def test_missing_lombok_class_under_target_is_ignored_not_raised(tmp_path: Path) def test_missing_unsupported_extension_is_ignored(tmp_path: Path) -> None: - ls = _IgnoredPathServer(tmp_path, Language.PYTHON) + ls = _IgnoredPathServer(tmp_path, LanguageServerId.PYTHON) missing = "src/foo.pyc" assert not (tmp_path / missing).exists() assert ls.is_ignored_path(missing) is True @@ -65,14 +65,14 @@ def test_missing_unsupported_extension_is_ignored(tmp_path: Path) -> None: def test_missing_source_file_not_in_ignored_dir_is_not_ignored(tmp_path: Path) -> None: """A missing source path classifies as not-ignored.""" - ls = _IgnoredPathServer(tmp_path, Language.PYTHON) + ls = _IgnoredPathServer(tmp_path, LanguageServerId.PYTHON) missing = "src/app.py" assert not (tmp_path / missing).exists() assert ls.is_ignored_path(missing) is False def test_missing_source_file_under_ignored_dirname_is_ignored(tmp_path: Path) -> None: - ls = _IgnoredPathServer(tmp_path, Language.PYTHON, ignored_dirnames=("generated",)) + ls = _IgnoredPathServer(tmp_path, LanguageServerId.PYTHON, ignored_dirnames=("generated",)) missing = "generated/app.py" assert not (tmp_path / missing).exists() assert ls.is_ignored_path(missing) is True @@ -80,7 +80,7 @@ def test_missing_source_file_under_ignored_dirname_is_ignored(tmp_path: Path) -> def test_missing_directory_with_ignored_dirname_leaf_is_ignored(tmp_path: Path) -> None: """The leaf of a missing suffixless path may denote a directory and is checked against ignored dirnames.""" - ls = _IgnoredPathServer(tmp_path, Language.PYTHON, ignored_dirnames=("generated",)) + ls = _IgnoredPathServer(tmp_path, LanguageServerId.PYTHON, ignored_dirnames=("generated",)) assert ls.is_ignored_path("generated", ignore_unsupported_files=False) is True assert ls.is_ignored_path("src/generated", ignore_unsupported_files=False) is True assert ls.is_ignored_path(".venv", ignore_unsupported_files=False) is True @@ -88,26 +88,26 @@ def test_missing_directory_with_ignored_dirname_leaf_is_ignored(tmp_path: Path) def test_missing_extensionless_path_is_treated_as_directory(tmp_path: Path) -> None: """A missing suffixless path is not subject to the unsupported-extension rule for files.""" - ls = _IgnoredPathServer(tmp_path, Language.PYTHON) + ls = _IgnoredPathServer(tmp_path, LanguageServerId.PYTHON) assert ls.is_ignored_path("newpkg") is False def test_missing_ignored_by_pathspec_is_ignored(tmp_path: Path) -> None: - ls = _IgnoredPathServer(tmp_path, Language.PYTHON, ignore_lines=("generated.py",)) + ls = _IgnoredPathServer(tmp_path, LanguageServerId.PYTHON, ignore_lines=("generated.py",)) missing = "generated.py" assert not (tmp_path / missing).exists() assert ls.is_ignored_path(missing) is True def test_missing_unsupported_extension_can_be_allowed(tmp_path: Path) -> None: - ls = _IgnoredPathServer(tmp_path, Language.PYTHON) + ls = _IgnoredPathServer(tmp_path, LanguageServerId.PYTHON) missing = "src/foo.pyc" assert not (tmp_path / missing).exists() assert ls.is_ignored_path(missing, ignore_unsupported_files=False) is False def test_existing_path_under_ignored_dirname_is_ignored(tmp_path: Path) -> None: - ls = _IgnoredPathServer(tmp_path, Language.PYTHON, ignored_dirnames=("generated",)) + ls = _IgnoredPathServer(tmp_path, LanguageServerId.PYTHON, ignored_dirnames=("generated",)) source_file = tmp_path / "generated" / "app.py" source_file.parent.mkdir(parents=True) source_file.write_text("x = 1\n") @@ -115,7 +115,7 @@ def test_existing_path_under_ignored_dirname_is_ignored(tmp_path: Path) -> None: def test_existing_source_file_is_not_ignored(tmp_path: Path) -> None: - ls = _IgnoredPathServer(tmp_path, Language.PYTHON) + ls = _IgnoredPathServer(tmp_path, LanguageServerId.PYTHON) src = tmp_path / "pkg" / "mod.py" src.parent.mkdir(parents=True) src.write_text("x = 1\n") @@ -134,7 +134,7 @@ def test_java_build_output_paths_never_raise(tmp_path: Path, rel: str) -> None: """Compiled-class paths classify as ignored via the unsupported-extension rule, present or not (build dirnames are deliberately not hard-ignored for Java). """ - ls = _IgnoredPathServer(tmp_path, Language.JAVA) + ls = _IgnoredPathServer(tmp_path, LanguageServerId.JAVA) # neither present nor absent should raise assert ls.is_ignored_path(rel) is True p = tmp_path / rel @@ -164,7 +164,7 @@ def _location_item(path: Path) -> dict: def test_location_at_missing_path_is_skipped(tmp_path: Path) -> None: """Locations whose absolute path is not on disk (e.g. LS-reported build artifacts) are dropped.""" - ls = _IgnoredPathServer(tmp_path, Language.JAVA) + ls = _IgnoredPathServer(tmp_path, LanguageServerId.JAVA) missing = tmp_path / "target" / "classes" / "LombokModel$LombokModelBuilder.class" assert not missing.exists() assert _location_request(ls).convert_location_item(_location_item(missing)) is None @@ -172,13 +172,13 @@ def test_location_at_missing_path_is_skipped(tmp_path: Path) -> None: def test_location_at_missing_source_path_is_skipped(tmp_path: Path) -> None: """A missing path that is not ignored is dropped by the existence check alone.""" - ls = _IgnoredPathServer(tmp_path, Language.PYTHON) + ls = _IgnoredPathServer(tmp_path, LanguageServerId.PYTHON) assert ls.is_ignored_path("pkg/mod.py") is False assert _location_request(ls).convert_location_item(_location_item(tmp_path / "pkg" / "mod.py")) is None def test_location_at_existing_ignored_path_is_skipped(tmp_path: Path) -> None: - ls = _IgnoredPathServer(tmp_path, Language.PYTHON, ignored_dirnames=("generated",)) + ls = _IgnoredPathServer(tmp_path, LanguageServerId.PYTHON, ignored_dirnames=("generated",)) source_file = tmp_path / "generated" / "app.py" source_file.parent.mkdir(parents=True) source_file.write_text("x = 1\n") @@ -186,7 +186,7 @@ def test_location_at_existing_ignored_path_is_skipped(tmp_path: Path) -> None: def test_location_at_existing_source_path_is_converted(tmp_path: Path) -> None: - ls = _IgnoredPathServer(tmp_path, Language.PYTHON) + ls = _IgnoredPathServer(tmp_path, LanguageServerId.PYTHON) source_file = tmp_path / "pkg" / "mod.py" source_file.parent.mkdir(parents=True) source_file.write_text("x = 1\n") diff --git a/test/solidlsp/test_ls_common.py b/test/solidlsp/test_ls_common.py index fab8f215..50315cf3 100644 --- a/test/solidlsp/test_ls_common.py +++ b/test/solidlsp/test_ls_common.py @@ -4,7 +4,7 @@ from collections.abc import Sequence import pytest from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from solidlsp.ls_utils import SymbolUtils from test.conftest import PYTHON_LANGUAGE_BACKENDS, start_ls_context @@ -61,15 +61,15 @@ class TestLanguageServerCommonFunctionality: symbols_in_subfolder_scripts = ["parse_args", "create_sample_users"] all_symbols = symbols_in_subfolder_test_repo + symbols_in_subfolder_scripts - with start_ls_context(language=Language.PYTHON, workspace_folders=["."]) as ls: + with start_ls_context(ls_id=LanguageServerId.PYTHON, workspace_folders=["."]) as ls: ls.request_full_symbol_tree() check(ls, present=all_symbols) - with start_ls_context(language=Language.PYTHON, workspace_folders=["./test_repo"]) as ls: + with start_ls_context(ls_id=LanguageServerId.PYTHON, workspace_folders=["./test_repo"]) as ls: ls.request_full_symbol_tree() check(ls, present=symbols_in_subfolder_test_repo, absent=symbols_in_subfolder_scripts) - with start_ls_context(language=Language.PYTHON, workspace_folders=["./scripts"]) as ls: + with start_ls_context(ls_id=LanguageServerId.PYTHON, workspace_folders=["./scripts"]) as ls: ls.request_full_symbol_tree() check(ls, present=symbols_in_subfolder_scripts, absent=symbols_in_subfolder_test_repo) diff --git a/test/solidlsp/toml/test_toml_basic.py b/test/solidlsp/toml/test_toml_basic.py index 522f8407..dc4db65e 100644 --- a/test/solidlsp/toml/test_toml_basic.py +++ b/test/solidlsp/toml/test_toml_basic.py @@ -10,7 +10,7 @@ from pathlib import Path import pytest from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from test.solidlsp.conftest import format_symbol_for_assert, has_malformed_name, request_all_symbols @@ -18,17 +18,17 @@ from test.solidlsp.conftest import format_symbol_for_assert, has_malformed_name, class TestTomlLanguageServerBasics: """Test basic functionality of the TOML language server (Taplo).""" - @pytest.mark.parametrize("language_server", [Language.TOML], indirect=True) - @pytest.mark.parametrize("repo_path", [Language.TOML], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.TOML], indirect=True) + @pytest.mark.parametrize("repo_path", [LanguageServerId.TOML], indirect=True) def test_toml_language_server_initialization(self, language_server: SolidLanguageServer, repo_path: Path) -> None: """Test that TOML language server can be initialized successfully.""" assert language_server is not None - assert language_server.language == Language.TOML + assert language_server.ls_id == LanguageServerId.TOML assert language_server.is_running() assert Path(language_server.language_server.repository_root_path).resolve() == repo_path.resolve() - @pytest.mark.parametrize("language_server", [Language.TOML], indirect=True) - @pytest.mark.parametrize("repo_path", [Language.TOML], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.TOML], indirect=True) + @pytest.mark.parametrize("repo_path", [LanguageServerId.TOML], indirect=True) def test_toml_cargo_file_symbols(self, language_server: SolidLanguageServer, repo_path: Path) -> None: """Test document symbols detection in Cargo.toml with specific symbol verification.""" all_symbols, root_symbols = language_server.request_document_symbols("Cargo.toml").get_all_symbols_and_roots() @@ -58,8 +58,8 @@ class TestTomlLanguageServerBasics: assert dependencies_symbol is not None, "Should find 'dependencies' symbol" assert dependencies_symbol.get("kind") == 19, "'dependencies' table should have kind 19 (object)" - @pytest.mark.parametrize("language_server", [Language.TOML], indirect=True) - @pytest.mark.parametrize("repo_path", [Language.TOML], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.TOML], indirect=True) + @pytest.mark.parametrize("repo_path", [LanguageServerId.TOML], indirect=True) def test_toml_pyproject_file_symbols(self, language_server: SolidLanguageServer, repo_path: Path) -> None: """Test document symbols detection in pyproject.toml.""" all_symbols, root_symbols = language_server.request_document_symbols("pyproject.toml").get_all_symbols_and_roots() @@ -87,8 +87,8 @@ class TestTomlLanguageServerBasics: assert project_symbol is not None, "Should find 'project' symbol" assert project_symbol.get("kind") == 19, "'project' table should have kind 19 (object)" - @pytest.mark.parametrize("language_server", [Language.TOML], indirect=True) - @pytest.mark.parametrize("repo_path", [Language.TOML], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.TOML], indirect=True) + @pytest.mark.parametrize("repo_path", [LanguageServerId.TOML], indirect=True) def test_toml_symbol_kinds(self, language_server: SolidLanguageServer, repo_path: Path) -> None: """Test that TOML symbols have appropriate LSP kinds for different value types.""" all_symbols, root_symbols = language_server.request_document_symbols("Cargo.toml").get_all_symbols_and_roots() @@ -122,8 +122,8 @@ class TestTomlLanguageServerBasics: assert default_symbol is not None, "Should find 'default' array symbol" assert default_symbol.get("kind") == 18, "'default' should have kind 18 (array)" - @pytest.mark.parametrize("language_server", [Language.TOML], indirect=True) - @pytest.mark.parametrize("repo_path", [Language.TOML], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.TOML], indirect=True) + @pytest.mark.parametrize("repo_path", [LanguageServerId.TOML], indirect=True) def test_toml_symbols_with_body(self, language_server: SolidLanguageServer, repo_path: Path) -> None: """Test request_document_symbols with body extraction.""" all_symbols, root_symbols = language_server.request_document_symbols("Cargo.toml").get_all_symbols_and_roots() @@ -164,8 +164,8 @@ class TestTomlLanguageServerBasics: features_body = features_symbol["body"].get_text() assert "default" in features_body, "Body should contain 'default' feature" - @pytest.mark.parametrize("language_server", [Language.TOML], indirect=True) - @pytest.mark.parametrize("repo_path", [Language.TOML], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.TOML], indirect=True) + @pytest.mark.parametrize("repo_path", [LanguageServerId.TOML], indirect=True) def test_toml_symbol_ranges(self, language_server: SolidLanguageServer, repo_path: Path) -> None: """Test that symbols have proper range information.""" all_symbols, root_symbols = language_server.request_document_symbols("Cargo.toml").get_all_symbols_and_roots() @@ -205,8 +205,8 @@ class TestTomlLanguageServerBasics: assert "line" in package_range["end"], "End should have line" assert "character" in package_range["end"], "End should have character" - @pytest.mark.parametrize("language_server", [Language.TOML], indirect=True) - @pytest.mark.parametrize("repo_path", [Language.TOML], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.TOML], indirect=True) + @pytest.mark.parametrize("repo_path", [LanguageServerId.TOML], indirect=True) def test_toml_nested_table_symbols(self, language_server: SolidLanguageServer, repo_path: Path) -> None: """Test detection of nested table symbols like profile.release and tool.ruff.""" # Test Cargo.toml for profile.release @@ -235,7 +235,7 @@ class TestTomlLanguageServerBasics: if strict_symbol: assert strict_symbol.get("kind") == 17, "'strict' should have kind 17 (boolean)" - @pytest.mark.parametrize("language_server", [Language.TOML], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.TOML], indirect=True) def test_bare_symbol_names(self, language_server) -> None: all_symbols = request_all_symbols(language_server) malformed_symbols = [] diff --git a/test/solidlsp/toml/test_toml_diagnostics.py b/test/solidlsp/toml/test_toml_diagnostics.py index dde2fc83..85b94446 100644 --- a/test/solidlsp/toml/test_toml_diagnostics.py +++ b/test/solidlsp/toml/test_toml_diagnostics.py @@ -1,13 +1,13 @@ import pytest from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from test.solidlsp.util.diagnostics import assert_file_diagnostics @pytest.mark.toml class TestTomlDiagnostics: - @pytest.mark.parametrize("language_server", [Language.TOML], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.TOML], indirect=True) def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None: assert_file_diagnostics( language_server, diff --git a/test/solidlsp/toml/test_toml_edge_cases.py b/test/solidlsp/toml/test_toml_edge_cases.py index faea142e..729c0d2e 100644 --- a/test/solidlsp/toml/test_toml_edge_cases.py +++ b/test/solidlsp/toml/test_toml_edge_cases.py @@ -14,7 +14,7 @@ from pathlib import Path import pytest from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId pytestmark = pytest.mark.toml @@ -22,8 +22,8 @@ pytestmark = pytest.mark.toml class TestTomlEdgeCases: """Test TOML language server handling of edge cases and advanced features.""" - @pytest.mark.parametrize("language_server", [Language.TOML], indirect=True) - @pytest.mark.parametrize("repo_path", [Language.TOML], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.TOML], indirect=True) + @pytest.mark.parametrize("repo_path", [LanguageServerId.TOML], indirect=True) def test_inline_table_detection(self, language_server: SolidLanguageServer, repo_path: Path) -> None: """Test that inline tables are properly detected.""" all_symbols, root_symbols = language_server.request_document_symbols("config.toml").get_all_symbols_and_roots() @@ -42,8 +42,8 @@ class TestTomlEdgeCases: # Inline tables should be kind 19 (object) assert endpoint_symbol.get("kind") == 19, "Inline table should have kind 19 (object)" - @pytest.mark.parametrize("language_server", [Language.TOML], indirect=True) - @pytest.mark.parametrize("repo_path", [Language.TOML], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.TOML], indirect=True) + @pytest.mark.parametrize("repo_path", [LanguageServerId.TOML], indirect=True) def test_nested_table_detection(self, language_server: SolidLanguageServer, repo_path: Path) -> None: """Test that deeply nested tables are properly detected.""" all_symbols, root_symbols = language_server.request_document_symbols("config.toml").get_all_symbols_and_roots() @@ -57,8 +57,8 @@ class TestTomlEdgeCases: assert has_ssl, f"Should detect 'server.ssl' nested table, got: {symbol_names}" assert has_pool, f"Should detect 'database.pool' nested table, got: {symbol_names}" - @pytest.mark.parametrize("language_server", [Language.TOML], indirect=True) - @pytest.mark.parametrize("repo_path", [Language.TOML], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.TOML], indirect=True) + @pytest.mark.parametrize("repo_path", [LanguageServerId.TOML], indirect=True) def test_array_of_tables_detection(self, language_server: SolidLanguageServer, repo_path: Path) -> None: """Test that [[array_of_tables]] syntax is properly detected.""" all_symbols, root_symbols = language_server.request_document_symbols("config.toml").get_all_symbols_and_roots() @@ -75,8 +75,8 @@ class TestTomlEdgeCases: # Array of tables should be kind 18 (array) assert endpoints_symbol.get("kind") == 18, "Array of tables should have kind 18 (array)" - @pytest.mark.parametrize("language_server", [Language.TOML], indirect=True) - @pytest.mark.parametrize("repo_path", [Language.TOML], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.TOML], indirect=True) + @pytest.mark.parametrize("repo_path", [LanguageServerId.TOML], indirect=True) def test_multiline_string_handling(self, language_server: SolidLanguageServer, repo_path: Path) -> None: """Test that multiline strings are handled correctly.""" all_symbols, root_symbols = language_server.request_document_symbols("config.toml").get_all_symbols_and_roots() @@ -93,8 +93,8 @@ class TestTomlEdgeCases: # String type should be kind 15 assert conn_symbol.get("kind") == 15, "Multiline string should have kind 15 (string)" - @pytest.mark.parametrize("language_server", [Language.TOML], indirect=True) - @pytest.mark.parametrize("repo_path", [Language.TOML], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.TOML], indirect=True) + @pytest.mark.parametrize("repo_path", [LanguageServerId.TOML], indirect=True) def test_array_value_detection(self, language_server: SolidLanguageServer, repo_path: Path) -> None: """Test that array values are properly detected.""" all_symbols, root_symbols = language_server.request_document_symbols("config.toml").get_all_symbols_and_roots() @@ -111,8 +111,8 @@ class TestTomlEdgeCases: # Arrays should have kind 18 assert outputs_symbol.get("kind") == 18, "'outputs' should have kind 18 (array)" - @pytest.mark.parametrize("language_server", [Language.TOML], indirect=True) - @pytest.mark.parametrize("repo_path", [Language.TOML], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.TOML], indirect=True) + @pytest.mark.parametrize("repo_path", [LanguageServerId.TOML], indirect=True) def test_float_value_detection(self, language_server: SolidLanguageServer, repo_path: Path) -> None: """Test that float values are properly detected.""" all_symbols, root_symbols = language_server.request_document_symbols("config.toml").get_all_symbols_and_roots() @@ -128,8 +128,8 @@ class TestTomlEdgeCases: # Numbers should have kind 16 assert timeout_symbol.get("kind") == 16, "'timeout' should have kind 16 (number)" - @pytest.mark.parametrize("language_server", [Language.TOML], indirect=True) - @pytest.mark.parametrize("repo_path", [Language.TOML], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.TOML], indirect=True) + @pytest.mark.parametrize("repo_path", [LanguageServerId.TOML], indirect=True) def test_datetime_value_detection(self, language_server: SolidLanguageServer, repo_path: Path) -> None: """Test that datetime values are detected.""" all_symbols, root_symbols = language_server.request_document_symbols("config.toml").get_all_symbols_and_roots() @@ -141,8 +141,8 @@ class TestTomlEdgeCases: assert "created" in symbol_names, "Should detect 'created' datetime field" assert "updated" in symbol_names, "Should detect 'updated' datetime field" - @pytest.mark.parametrize("language_server", [Language.TOML], indirect=True) - @pytest.mark.parametrize("repo_path", [Language.TOML], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.TOML], indirect=True) + @pytest.mark.parametrize("repo_path", [LanguageServerId.TOML], indirect=True) def test_symbol_body_with_inline_table(self, language_server: SolidLanguageServer, repo_path: Path) -> None: """Test that symbol bodies include inline table content.""" all_symbols, root_symbols = language_server.request_document_symbols("config.toml").get_all_symbols_and_roots() @@ -156,8 +156,8 @@ class TestTomlEdgeCases: # Body should contain the inline table syntax assert "url" in body or "version" in body, f"Body should contain inline table contents, got: {body}" - @pytest.mark.parametrize("language_server", [Language.TOML], indirect=True) - @pytest.mark.parametrize("repo_path", [Language.TOML], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.TOML], indirect=True) + @pytest.mark.parametrize("repo_path", [LanguageServerId.TOML], indirect=True) def test_symbol_ranges_in_config(self, language_server: SolidLanguageServer, repo_path: Path) -> None: """Test that symbol ranges are correct in config.toml.""" all_symbols, root_symbols = language_server.request_document_symbols("config.toml").get_all_symbols_and_roots() @@ -172,8 +172,8 @@ class TestTomlEdgeCases: assert server_range["start"]["line"] >= 0, "Server should start at or near the beginning" assert server_range["end"]["line"] > server_range["start"]["line"], "Server block should span multiple lines" - @pytest.mark.parametrize("language_server", [Language.TOML], indirect=True) - @pytest.mark.parametrize("repo_path", [Language.TOML], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.TOML], indirect=True) + @pytest.mark.parametrize("repo_path", [LanguageServerId.TOML], indirect=True) def test_comment_handling(self, language_server: SolidLanguageServer, repo_path: Path) -> None: """Test that comments don't interfere with symbol detection.""" all_symbols, root_symbols = language_server.request_document_symbols("config.toml").get_all_symbols_and_roots() @@ -186,8 +186,8 @@ class TestTomlEdgeCases: assert len(found_sections) >= 4, f"Should find most sections despite comments, found: {found_sections}" - @pytest.mark.parametrize("language_server", [Language.TOML], indirect=True) - @pytest.mark.parametrize("repo_path", [Language.TOML], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.TOML], indirect=True) + @pytest.mark.parametrize("repo_path", [LanguageServerId.TOML], indirect=True) def test_special_characters_in_strings(self, language_server: SolidLanguageServer, repo_path: Path) -> None: """Test that strings with escape sequences are handled.""" all_symbols, root_symbols = language_server.request_document_symbols("config.toml").get_all_symbols_and_roots() @@ -203,8 +203,8 @@ class TestTomlEdgeCases: class TestTomlDependencyTables: """Test handling of dependency-style tables common in Cargo.toml and pyproject.toml.""" - @pytest.mark.parametrize("language_server", [Language.TOML], indirect=True) - @pytest.mark.parametrize("repo_path", [Language.TOML], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.TOML], indirect=True) + @pytest.mark.parametrize("repo_path", [LanguageServerId.TOML], indirect=True) def test_complex_dependency_inline_table(self, language_server: SolidLanguageServer, repo_path: Path) -> None: """Test detection of complex inline table dependencies like serde = { version = "1.0", features = ["derive"] }.""" all_symbols, root_symbols = language_server.request_document_symbols("Cargo.toml").get_all_symbols_and_roots() @@ -222,8 +222,8 @@ class TestTomlDependencyTables: # Dependency with inline table should be kind 19 (object) assert serde_symbol.get("kind") == 19, "Complex dependency should have kind 19 (object)" - @pytest.mark.parametrize("language_server", [Language.TOML], indirect=True) - @pytest.mark.parametrize("repo_path", [Language.TOML], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.TOML], indirect=True) + @pytest.mark.parametrize("repo_path", [LanguageServerId.TOML], indirect=True) def test_simple_dependency_string(self, language_server: SolidLanguageServer, repo_path: Path) -> None: """Test detection of simple string dependencies like proptest = "1.0".""" all_symbols, root_symbols = language_server.request_document_symbols("Cargo.toml").get_all_symbols_and_roots() @@ -240,8 +240,8 @@ class TestTomlDependencyTables: # Simple string dependency should be kind 15 (string) assert proptest_symbol.get("kind") == 15, "Simple string dependency should have kind 15 (string)" - @pytest.mark.parametrize("language_server", [Language.TOML], indirect=True) - @pytest.mark.parametrize("repo_path", [Language.TOML], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.TOML], indirect=True) + @pytest.mark.parametrize("repo_path", [LanguageServerId.TOML], indirect=True) def test_pyproject_dependencies_array(self, language_server: SolidLanguageServer, repo_path: Path) -> None: """Test detection of pyproject.toml dependencies array.""" all_symbols, root_symbols = language_server.request_document_symbols("pyproject.toml").get_all_symbols_and_roots() @@ -258,8 +258,8 @@ class TestTomlDependencyTables: # Dependencies array should be kind 18 (array) assert deps_symbol.get("kind") == 18, "Dependencies array should have kind 18 (array)" - @pytest.mark.parametrize("language_server", [Language.TOML], indirect=True) - @pytest.mark.parametrize("repo_path", [Language.TOML], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.TOML], indirect=True) + @pytest.mark.parametrize("repo_path", [LanguageServerId.TOML], indirect=True) def test_optional_dependencies_table(self, language_server: SolidLanguageServer, repo_path: Path) -> None: """Test detection of optional-dependencies in pyproject.toml.""" all_symbols, root_symbols = language_server.request_document_symbols("pyproject.toml").get_all_symbols_and_roots() diff --git a/test/solidlsp/toml/test_toml_ignored_dirs.py b/test/solidlsp/toml/test_toml_ignored_dirs.py index 11d987f9..95611b4e 100644 --- a/test/solidlsp/toml/test_toml_ignored_dirs.py +++ b/test/solidlsp/toml/test_toml_ignored_dirs.py @@ -8,12 +8,12 @@ TOML-specific directories like target, .cargo, and node_modules. import pytest from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId pytestmark = pytest.mark.toml -@pytest.mark.parametrize("language_server", [Language.TOML], indirect=True) +@pytest.mark.parametrize("language_server", [LanguageServerId.TOML], indirect=True) class TestTomlIgnoredDirectories: """Test TOML-specific directory ignoring behavior.""" diff --git a/test/solidlsp/toml/test_toml_symbol_retrieval.py b/test/solidlsp/toml/test_toml_symbol_retrieval.py index 5538a4c8..9696784b 100644 --- a/test/solidlsp/toml/test_toml_symbol_retrieval.py +++ b/test/solidlsp/toml/test_toml_symbol_retrieval.py @@ -13,7 +13,7 @@ from pathlib import Path import pytest from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId pytestmark = pytest.mark.toml @@ -21,8 +21,8 @@ pytestmark = pytest.mark.toml class TestTomlSymbolRetrieval: """Test advanced symbol retrieval functionality for TOML files.""" - @pytest.mark.parametrize("language_server", [Language.TOML], indirect=True) - @pytest.mark.parametrize("repo_path", [Language.TOML], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.TOML], indirect=True) + @pytest.mark.parametrize("repo_path", [LanguageServerId.TOML], indirect=True) def test_request_containing_symbol_behavior(self, language_server: SolidLanguageServer, repo_path: Path) -> None: """Test request_containing_symbol behavior for TOML files. @@ -36,8 +36,8 @@ class TestTomlSymbolRetrieval: # This is expected behavior for a configuration file format assert containing_symbol is None, "TOML LSP doesn't support containing symbol lookup" - @pytest.mark.parametrize("language_server", [Language.TOML], indirect=True) - @pytest.mark.parametrize("repo_path", [Language.TOML], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.TOML], indirect=True) + @pytest.mark.parametrize("repo_path", [LanguageServerId.TOML], indirect=True) def test_request_document_overview_cargo(self, language_server: SolidLanguageServer, repo_path: Path) -> None: """Test request_document_overview for Cargo.toml.""" overview = language_server.request_document_overview("Cargo.toml") @@ -52,8 +52,8 @@ class TestTomlSymbolRetrieval: expected_tables = {"package", "dependencies", "dev-dependencies", "features", "workspace"} assert expected_tables.issubset(symbol_names), f"Missing expected tables in overview: {expected_tables - symbol_names}" - @pytest.mark.parametrize("language_server", [Language.TOML], indirect=True) - @pytest.mark.parametrize("repo_path", [Language.TOML], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.TOML], indirect=True) + @pytest.mark.parametrize("repo_path", [LanguageServerId.TOML], indirect=True) def test_request_document_overview_pyproject(self, language_server: SolidLanguageServer, repo_path: Path) -> None: """Test request_document_overview for pyproject.toml.""" overview = language_server.request_document_overview("pyproject.toml") @@ -68,8 +68,8 @@ class TestTomlSymbolRetrieval: assert "project" in symbol_names, "Should detect 'project' table" assert "build-system" in symbol_names, "Should detect 'build-system' table" - @pytest.mark.parametrize("language_server", [Language.TOML], indirect=True) - @pytest.mark.parametrize("repo_path", [Language.TOML], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.TOML], indirect=True) + @pytest.mark.parametrize("repo_path", [LanguageServerId.TOML], indirect=True) def test_request_full_symbol_tree(self, language_server: SolidLanguageServer, repo_path: Path) -> None: """Test request_full_symbol_tree returns TOML files.""" symbol_tree = language_server.request_full_symbol_tree() @@ -89,8 +89,8 @@ class TestTomlSymbolRetrieval: f"Should find Cargo.toml in tree, got: {child_names}" ) - @pytest.mark.parametrize("language_server", [Language.TOML], indirect=True) - @pytest.mark.parametrize("repo_path", [Language.TOML], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.TOML], indirect=True) + @pytest.mark.parametrize("repo_path", [LanguageServerId.TOML], indirect=True) def test_request_dir_overview(self, language_server: SolidLanguageServer, repo_path: Path) -> None: """Test request_dir_overview returns symbols for TOML files.""" overview = language_server.request_dir_overview(".") @@ -103,8 +103,8 @@ class TestTomlSymbolRetrieval: assert any("Cargo.toml" in path for path in file_paths), f"Should find Cargo.toml in overview, got: {file_paths}" assert any("pyproject.toml" in path for path in file_paths), f"Should find pyproject.toml in overview, got: {file_paths}" - @pytest.mark.parametrize("language_server", [Language.TOML], indirect=True) - @pytest.mark.parametrize("repo_path", [Language.TOML], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.TOML], indirect=True) + @pytest.mark.parametrize("repo_path", [LanguageServerId.TOML], indirect=True) def test_symbol_hierarchy_in_cargo(self, language_server: SolidLanguageServer, repo_path: Path) -> None: """Test that symbol hierarchy is properly preserved in Cargo.toml.""" all_symbols, root_symbols = language_server.request_document_symbols("Cargo.toml").get_all_symbols_and_roots() @@ -122,8 +122,8 @@ class TestTomlSymbolRetrieval: assert "version" in child_names, "'package' should have 'version' child" assert "edition" in child_names, "'package' should have 'edition' child" - @pytest.mark.parametrize("language_server", [Language.TOML], indirect=True) - @pytest.mark.parametrize("repo_path", [Language.TOML], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.TOML], indirect=True) + @pytest.mark.parametrize("repo_path", [LanguageServerId.TOML], indirect=True) def test_symbol_hierarchy_in_pyproject(self, language_server: SolidLanguageServer, repo_path: Path) -> None: """Test that symbol hierarchy is properly preserved in pyproject.toml.""" all_symbols, root_symbols = language_server.request_document_symbols("pyproject.toml").get_all_symbols_and_roots() @@ -140,8 +140,8 @@ class TestTomlSymbolRetrieval: assert "name" in child_names, "'project' should have 'name' child" assert "version" in child_names, "'project' should have 'version' child" - @pytest.mark.parametrize("language_server", [Language.TOML], indirect=True) - @pytest.mark.parametrize("repo_path", [Language.TOML], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.TOML], indirect=True) + @pytest.mark.parametrize("repo_path", [LanguageServerId.TOML], indirect=True) def test_tool_section_hierarchy(self, language_server: SolidLanguageServer, repo_path: Path) -> None: """Test that tool sections in pyproject.toml are properly structured.""" all_symbols, root_symbols = language_server.request_document_symbols("pyproject.toml").get_all_symbols_and_roots() @@ -156,8 +156,8 @@ class TestTomlSymbolRetrieval: assert has_ruff or has_mypy or has_pytest, f"Should detect tool sections, got names: {all_names}" - @pytest.mark.parametrize("language_server", [Language.TOML], indirect=True) - @pytest.mark.parametrize("repo_path", [Language.TOML], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.TOML], indirect=True) + @pytest.mark.parametrize("repo_path", [LanguageServerId.TOML], indirect=True) def test_array_of_tables_symbol(self, language_server: SolidLanguageServer, repo_path: Path) -> None: """Test that [[bin]] array of tables is detected.""" all_symbols, root_symbols = language_server.request_document_symbols("Cargo.toml").get_all_symbols_and_roots() diff --git a/test/solidlsp/typescript/test_typescript_basic.py b/test/solidlsp/typescript/test_typescript_basic.py index 1c9ed1ae..006bcc0e 100644 --- a/test/solidlsp/typescript/test_typescript_basic.py +++ b/test/solidlsp/typescript/test_typescript_basic.py @@ -3,22 +3,22 @@ import os import pytest from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from solidlsp.ls_utils import SymbolUtils -from test.conftest import find_identifier_position, get_repo_path, language_has_verified_implementation_support +from test.conftest import find_identifier_position, get_repo_path, ls_has_verified_implementation_support from test.solidlsp.conftest import format_symbol_for_assert, has_malformed_name, request_all_symbols @pytest.mark.typescript class TestTypescriptLanguageServer: - @pytest.mark.parametrize("language_server", [Language.TYPESCRIPT], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.TYPESCRIPT], indirect=True) def test_find_symbol(self, language_server: SolidLanguageServer) -> None: symbols = language_server.request_full_symbol_tree() assert SymbolUtils.symbol_tree_contains_name(symbols, "DemoClass"), "DemoClass not found in symbol tree" assert SymbolUtils.symbol_tree_contains_name(symbols, "helperFunction"), "helperFunction not found in symbol tree" assert SymbolUtils.symbol_tree_contains_name(symbols, "printValue"), "printValue method not found in symbol tree" - @pytest.mark.parametrize("language_server", [Language.TYPESCRIPT], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.TYPESCRIPT], indirect=True) def test_find_referencing_symbols(self, language_server: SolidLanguageServer) -> None: file_path = os.path.join("index.ts") symbols = language_server.request_document_symbols(file_path).get_all_symbols_and_roots() @@ -34,11 +34,11 @@ class TestTypescriptLanguageServer: "index.ts should reference helperFunction (tried all positions in selectionRange)" ) - if language_has_verified_implementation_support(Language.TYPESCRIPT): + if ls_has_verified_implementation_support(LanguageServerId.TYPESCRIPT): - @pytest.mark.parametrize("language_server", [Language.TYPESCRIPT], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.TYPESCRIPT], indirect=True) def test_find_implementations(self, language_server: SolidLanguageServer) -> None: - repo_path = get_repo_path(Language.TYPESCRIPT) + repo_path = get_repo_path(LanguageServerId.TYPESCRIPT) pos = find_identifier_position(repo_path / "formatters.ts", "formatGreeting") assert pos is not None, "Could not find Greeter.formatGreeting in fixture" @@ -48,9 +48,9 @@ class TestTypescriptLanguageServer: f"Expected ConsoleGreeter.formatGreeting in implementations, got: {implementations}" ) - @pytest.mark.parametrize("language_server", [Language.TYPESCRIPT], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.TYPESCRIPT], indirect=True) def test_request_implementing_symbols(self, language_server: SolidLanguageServer) -> None: - repo_path = get_repo_path(Language.TYPESCRIPT) + repo_path = get_repo_path(LanguageServerId.TYPESCRIPT) pos = find_identifier_position(repo_path / "formatters.ts", "formatGreeting") assert pos is not None, "Could not find Greeter.formatGreeting in fixture" @@ -61,7 +61,7 @@ class TestTypescriptLanguageServer: for symbol in implementing_symbols ), f"Expected ConsoleGreeter.formatGreeting symbol, got: {implementing_symbols}" - @pytest.mark.parametrize("language_server", [Language.TYPESCRIPT], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.TYPESCRIPT], indirect=True) def test_tsx_symbol_range_not_truncated_by_jsx(self, language_server: SolidLanguageServer) -> None: # Regression: when the language id is sent as "typescript" instead of # "typescriptreact" for .tsx files, tsserver parses JSX as syntax @@ -92,7 +92,7 @@ class TestTypescriptLanguageServer: "trailingHelper missing from jsx_component.tsx root symbols; tsserver likely stopped parsing at the first JSX expression." ) - @pytest.mark.parametrize("language_server", [Language.TYPESCRIPT], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.TYPESCRIPT], indirect=True) def test_bare_symbol_names(self, language_server) -> None: all_symbols = request_all_symbols(language_server) malformed_symbols = [] diff --git a/test/solidlsp/typescript/test_typescript_cross_package.py b/test/solidlsp/typescript/test_typescript_cross_package.py index 65582fb0..5dcf10ca 100644 --- a/test/solidlsp/typescript/test_typescript_cross_package.py +++ b/test/solidlsp/typescript/test_typescript_cross_package.py @@ -4,7 +4,7 @@ from pathlib import Path import pytest -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from test.conftest import start_ls_context CROSS_PKG_DIR = Path(__file__).parent.parent.parent / "resources" / "repos" / "typescript" @@ -23,7 +23,7 @@ class TestCrossPackageReferences: references in package_b should be discovered. """ with start_ls_context( - Language.TYPESCRIPT, + LanguageServerId.TYPESCRIPT, repo_path=PACKAGE_A, additional_workspace_folders=[PACKAGE_B], ) as ls: @@ -47,7 +47,7 @@ class TestCrossPackageReferences: def test_cross_package_referencing_symbols(self) -> None: """Test the higher-level request_referencing_symbols across packages.""" with start_ls_context( - Language.TYPESCRIPT, + LanguageServerId.TYPESCRIPT, repo_path=PACKAGE_A, additional_workspace_folders=[PACKAGE_B], ) as ls: @@ -79,7 +79,7 @@ class TestCrossPackageReferences: def test_without_additional_workspace_no_cross_refs(self) -> None: """Baseline: without additional_workspace_folders, cross-package refs should NOT appear.""" with start_ls_context( - Language.TYPESCRIPT, + LanguageServerId.TYPESCRIPT, repo_path=PACKAGE_A, ) as ls: symbols = ls.request_document_symbols("shared_utils.ts").get_all_symbols_and_roots() diff --git a/test/solidlsp/typescript/test_typescript_diagnostics.py b/test/solidlsp/typescript/test_typescript_diagnostics.py index 5e879e16..76e8c5fa 100644 --- a/test/solidlsp/typescript/test_typescript_diagnostics.py +++ b/test/solidlsp/typescript/test_typescript_diagnostics.py @@ -1,13 +1,13 @@ import pytest from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from test.solidlsp.util.diagnostics import assert_file_diagnostics @pytest.mark.typescript class TestTypeScriptDiagnostics: - @pytest.mark.parametrize("language_server", [Language.TYPESCRIPT], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.TYPESCRIPT], indirect=True) def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None: assert_file_diagnostics( language_server, diff --git a/test/solidlsp/typescript/test_typescript_ignored_dirs.py b/test/solidlsp/typescript/test_typescript_ignored_dirs.py index 7bbb0dfc..5194475d 100644 --- a/test/solidlsp/typescript/test_typescript_ignored_dirs.py +++ b/test/solidlsp/typescript/test_typescript_ignored_dirs.py @@ -10,12 +10,12 @@ excluded, and those are handled by gitignore. import pytest from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId pytestmark = pytest.mark.typescript -@pytest.mark.parametrize("language_server", [Language.TYPESCRIPT], indirect=True) +@pytest.mark.parametrize("language_server", [LanguageServerId.TYPESCRIPT], indirect=True) class TestTypescriptIgnoredDirectories: """TypeScript-specific directory ignoring behavior.""" diff --git a/test/solidlsp/vue/test_vue_basic.py b/test/solidlsp/vue/test_vue_basic.py index d3e05356..08ab9a9b 100644 --- a/test/solidlsp/vue/test_vue_basic.py +++ b/test/solidlsp/vue/test_vue_basic.py @@ -3,14 +3,14 @@ import os import pytest from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from solidlsp.ls_utils import SymbolUtils from test.solidlsp.conftest import format_symbol_for_assert, has_malformed_name, request_all_symbols @pytest.mark.vue class TestVueLanguageServer: - @pytest.mark.parametrize("language_server", [Language.VUE], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.VUE], indirect=True) def test_vue_files_in_symbol_tree(self, language_server: SolidLanguageServer) -> None: symbols = language_server.request_full_symbol_tree() assert SymbolUtils.symbol_tree_contains_name(symbols, "App"), "App not found in symbol tree" @@ -18,7 +18,7 @@ class TestVueLanguageServer: assert SymbolUtils.symbol_tree_contains_name(symbols, "CalculatorInput"), "CalculatorInput not found in symbol tree" assert SymbolUtils.symbol_tree_contains_name(symbols, "CalculatorDisplay"), "CalculatorDisplay not found in symbol tree" - @pytest.mark.parametrize("language_server", [Language.VUE], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.VUE], indirect=True) def test_find_referencing_symbols(self, language_server: SolidLanguageServer) -> None: store_file = os.path.join("src", "stores", "calculator.ts") symbols = language_server.request_document_symbols(store_file).get_all_symbols_and_roots() @@ -46,7 +46,7 @@ class TestVueLanguageServer: @pytest.mark.vue class TestVueDualLspArchitecture: - @pytest.mark.parametrize("language_server", [Language.VUE], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.VUE], indirect=True) def test_typescript_server_coordination(self, language_server: SolidLanguageServer) -> None: ts_file = os.path.join("src", "stores", "calculator.ts") ts_symbols = language_server.request_document_symbols(ts_file).get_all_symbols_and_roots() @@ -63,7 +63,7 @@ class TestVueDualLspArchitecture: assert len(vue_symbols[0]) >= 15, f"Vue server should return at least 15 symbols for App.vue, got {len(vue_symbols[0])}" assert "appTitle" in vue_symbol_names, "Vue server should extract ref declarations from script setup" - @pytest.mark.parametrize("language_server", [Language.VUE], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.VUE], indirect=True) def test_cross_file_references_vue_to_typescript(self, language_server: SolidLanguageServer) -> None: store_file = os.path.join("src", "stores", "calculator.ts") store_symbols = language_server.request_document_symbols(store_file).get_all_symbols_and_roots() @@ -103,7 +103,7 @@ class TestVueDualLspArchitecture: f"Expected any of {expected_vue_files}, found references in: {[ref.get('uri', '') for ref in vue_refs]}" ) - @pytest.mark.parametrize("language_server", [Language.VUE], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.VUE], indirect=True) def test_cross_file_references_typescript_to_vue(self, language_server: SolidLanguageServer) -> None: types_file = os.path.join("src", "types", "index.ts") types_symbols = language_server.request_document_symbols(types_file).get_all_symbols_and_roots() @@ -136,7 +136,7 @@ class TestVueDualLspArchitecture: f"Operation type should be referenced in TypeScript files like calculator.ts. Found references in: {all_ref_uris}" ) - @pytest.mark.parametrize("language_server", [Language.VUE], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.VUE], indirect=True) def test_reference_deduplication(self, language_server: SolidLanguageServer) -> None: store_file = os.path.join("src", "stores", "calculator.ts") store_symbols = language_server.request_document_symbols(store_file).get_all_symbols_and_roots() @@ -181,7 +181,7 @@ class TestVueDualLspArchitecture: @pytest.mark.vue class TestVueEdgeCases: - @pytest.mark.parametrize("language_server", [Language.VUE], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.VUE], indirect=True) def test_symbol_tree_structure(self, language_server: SolidLanguageServer) -> None: full_tree = language_server.request_full_symbol_tree() @@ -247,7 +247,7 @@ class TestVueEdgeCases: matching_files = [p for p in all_paths if expected_file in p] assert len(matching_files) > 0, f"Expected file '{expected_file}' should be in symbol tree. All paths: {all_paths}" - @pytest.mark.parametrize("language_server", [Language.VUE], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.VUE], indirect=True) def test_document_overview(self, language_server: SolidLanguageServer) -> None: app_file = os.path.join("src", "App.vue") overview = language_server.request_document_overview(app_file) @@ -294,7 +294,7 @@ class TestVueEdgeCases: f"Found {len(button_symbol_names)} symbols: {button_symbol_names}" ) - @pytest.mark.parametrize("language_server", [Language.VUE], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.VUE], indirect=True) def test_directory_overview(self, language_server: SolidLanguageServer) -> None: components_dir = os.path.join("src", "components") dir_overview = language_server.request_dir_overview(components_dir) @@ -362,7 +362,7 @@ class TestVueEdgeCases: f"Found {len(matching_files)} matches. All files: {list(composables_overview.keys())}" ) - @pytest.mark.parametrize("language_server", [Language.VUE], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.VUE], indirect=True) def test_bare_symbol_names(self, language_server) -> None: all_symbols = request_all_symbols(language_server) malformed_symbols = [] diff --git a/test/solidlsp/vue/test_vue_diagnostics.py b/test/solidlsp/vue/test_vue_diagnostics.py index 08ac2fed..fc8a58df 100644 --- a/test/solidlsp/vue/test_vue_diagnostics.py +++ b/test/solidlsp/vue/test_vue_diagnostics.py @@ -1,13 +1,13 @@ import pytest from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from test.solidlsp.util.diagnostics import assert_file_diagnostics @pytest.mark.vue class TestVueDiagnostics: - @pytest.mark.parametrize("language_server", [Language.VUE], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.VUE], indirect=True) def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None: assert_file_diagnostics( language_server, diff --git a/test/solidlsp/vue/test_vue_error_cases.py b/test/solidlsp/vue/test_vue_error_cases.py index 3a6aac8b..59bc98da 100644 --- a/test/solidlsp/vue/test_vue_error_cases.py +++ b/test/solidlsp/vue/test_vue_error_cases.py @@ -4,7 +4,7 @@ import sys import pytest from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId pytestmark = pytest.mark.vue @@ -28,7 +28,7 @@ class TypeScriptServerBehavior: class TestVueInvalidPositions: - @pytest.mark.parametrize("language_server", [Language.VUE], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.VUE], indirect=True) def test_negative_line_number(self, language_server: SolidLanguageServer) -> None: file_path = os.path.join("src", "components", "CalculatorInput.vue") @@ -36,7 +36,7 @@ class TestVueInvalidPositions: assert result is None or result == {}, f"Negative line number should return None or empty dict, got: {result}" - @pytest.mark.parametrize("language_server", [Language.VUE], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.VUE], indirect=True) def test_negative_character_number(self, language_server: SolidLanguageServer) -> None: """Test requesting containing symbol with negative character number. @@ -50,7 +50,7 @@ class TestVueInvalidPositions: # Should handle gracefully - return None or empty dict assert result is None or result == {}, f"Negative character number should return None or empty dict, got: {result}" - @pytest.mark.parametrize("language_server", [Language.VUE], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.VUE], indirect=True) def test_line_number_beyond_file_length(self, language_server: SolidLanguageServer) -> None: """Test requesting containing symbol beyond file length. @@ -67,7 +67,7 @@ class TestVueInvalidPositions: # Verify it's an index error for list access assert "list index out of range" in str(exc_info.value), f"Expected 'list index out of range' error, got: {exc_info.value}" - @pytest.mark.parametrize("language_server", [Language.VUE], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.VUE], indirect=True) def test_character_number_beyond_line_length(self, language_server: SolidLanguageServer) -> None: """Test requesting containing symbol beyond line length. @@ -81,7 +81,7 @@ class TestVueInvalidPositions: # Should handle gracefully - return None or empty dict assert result is None or result == {}, f"Character beyond line length should return None or empty dict, got: {result}" - @pytest.mark.parametrize("language_server", [Language.VUE], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.VUE], indirect=True) def test_references_at_negative_line(self, language_server: SolidLanguageServer) -> None: """Test requesting references with negative line number.""" from solidlsp.ls_exceptions import SolidLSPException @@ -96,7 +96,7 @@ class TestVueInvalidPositions: language_server.request_references(file_path, -1, 0) assert "Bad line number" in str(exc_info.value) or "Debug Failure" in str(exc_info.value) - @pytest.mark.parametrize("language_server", [Language.VUE], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.VUE], indirect=True) def test_definition_at_invalid_position(self, language_server: SolidLanguageServer) -> None: """Test requesting definition at invalid position.""" from solidlsp.ls_exceptions import SolidLSPException @@ -115,7 +115,7 @@ class TestVueInvalidPositions: class TestVueNonExistentFiles: """Tests for handling non-existent files.""" - @pytest.mark.parametrize("language_server", [Language.VUE], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.VUE], indirect=True) def test_requesting_on_nonexistent_file(self, language_server: SolidLanguageServer) -> None: """Test requesting references from non-existent file. @@ -134,7 +134,7 @@ class TestVueNonExistentFiles: class TestVueUndefinedSymbols: """Tests for handling undefined or unreferenced symbols.""" - @pytest.mark.parametrize("language_server", [Language.VUE], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.VUE], indirect=True) def test_references_for_unreferenced_symbol(self, language_server: SolidLanguageServer) -> None: """Test requesting references for a symbol that has no references. @@ -166,7 +166,7 @@ class TestVueUndefinedSymbols: f"Got {len(refs)} references. This is not necessarily an error, just documenting behavior." ) - @pytest.mark.parametrize("language_server", [Language.VUE], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.VUE], indirect=True) def test_containing_symbol_at_whitespace_only_line(self, language_server: SolidLanguageServer) -> None: """Test requesting containing symbol at a whitespace-only line. @@ -182,7 +182,7 @@ class TestVueUndefinedSymbols: f"Whitespace line should return None, empty dict, or valid symbol. Got: {result}" ) - @pytest.mark.parametrize("language_server", [Language.VUE], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.VUE], indirect=True) def test_definition_at_keyword_position(self, language_server: SolidLanguageServer) -> None: """Test requesting definition at language keyword position. @@ -201,7 +201,7 @@ class TestVueUndefinedSymbols: class TestVueEdgeCasePositions: """Tests for edge case positions (0,0 and file boundaries).""" - @pytest.mark.parametrize("language_server", [Language.VUE], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.VUE], indirect=True) def test_containing_symbol_at_file_start(self, language_server: SolidLanguageServer) -> None: """Test requesting containing symbol at position (0,0). @@ -218,7 +218,7 @@ class TestVueEdgeCasePositions: f"Position 0,0 should return None, empty dict, or valid symbol. Got: {result}" ) - @pytest.mark.parametrize("language_server", [Language.VUE], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.VUE], indirect=True) def test_references_at_file_start(self, language_server: SolidLanguageServer) -> None: """Test requesting references at position (0,0). @@ -232,7 +232,7 @@ class TestVueEdgeCasePositions: # Should handle gracefully assert result is None or isinstance(result, list), f"Position 0,0 should return None or list. Got: {type(result)}" - @pytest.mark.parametrize("language_server", [Language.VUE], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.VUE], indirect=True) def test_definition_at_file_start(self, language_server: SolidLanguageServer) -> None: """Test requesting definition at position (0,0). @@ -246,7 +246,7 @@ class TestVueEdgeCasePositions: # Should handle gracefully assert isinstance(result, list), f"request_definition should return a list. Got: {type(result)}" - @pytest.mark.parametrize("language_server", [Language.VUE], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.VUE], indirect=True) def test_containing_symbol_in_template_section(self, language_server: SolidLanguageServer) -> None: """Test requesting containing symbol in the template section. @@ -264,7 +264,7 @@ class TestVueEdgeCasePositions: f"Template position should return None, empty dict, or valid symbol. Got: {result}" ) - @pytest.mark.parametrize("language_server", [Language.VUE], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.VUE], indirect=True) def test_zero_character_positions(self, language_server: SolidLanguageServer) -> None: """Test requesting symbols at character position 0 (start of lines). @@ -285,7 +285,7 @@ class TestVueEdgeCasePositions: class TestVueTypescriptFileErrors: """Tests for error handling in TypeScript files within Vue projects.""" - @pytest.mark.parametrize("language_server", [Language.VUE], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.VUE], indirect=True) def test_typescript_file_invalid_position(self, language_server: SolidLanguageServer) -> None: """Test requesting symbols from TypeScript file at invalid position. @@ -299,7 +299,7 @@ class TestVueTypescriptFileErrors: # Should handle gracefully assert result is None or result == {}, f"Invalid position in .ts file should return None or empty dict. Got: {result}" - @pytest.mark.parametrize("language_server", [Language.VUE], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.VUE], indirect=True) def test_typescript_file_beyond_bounds(self, language_server: SolidLanguageServer) -> None: """Test requesting symbols from TypeScript file beyond file bounds. @@ -319,7 +319,7 @@ class TestVueTypescriptFileErrors: class TestVueReferenceEdgeCases: """Tests for edge cases in reference finding.""" - @pytest.mark.parametrize("language_server", [Language.VUE], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.VUE], indirect=True) def test_referencing_symbols_at_invalid_position(self, language_server: SolidLanguageServer) -> None: """Test requesting referencing symbols at invalid position.""" from solidlsp.ls_exceptions import SolidLSPException @@ -334,7 +334,7 @@ class TestVueReferenceEdgeCases: list(language_server.request_referencing_symbols(file_path, -1, -1, include_self=False)) assert "Bad line number" in str(exc_info.value) or "Debug Failure" in str(exc_info.value) - @pytest.mark.parametrize("language_server", [Language.VUE], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.VUE], indirect=True) def test_defining_symbol_at_invalid_position(self, language_server: SolidLanguageServer) -> None: """Test requesting defining symbol at invalid position.""" from solidlsp.ls_exceptions import SolidLSPException @@ -349,7 +349,7 @@ class TestVueReferenceEdgeCases: language_server.request_defining_symbol(file_path, -1, -1) assert "Bad line number" in str(exc_info.value) or "Debug Failure" in str(exc_info.value) - @pytest.mark.parametrize("language_server", [Language.VUE], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.VUE], indirect=True) def test_referencing_symbols_beyond_file_bounds(self, language_server: SolidLanguageServer) -> None: """Test requesting referencing symbols beyond file bounds.""" from solidlsp.ls_exceptions import SolidLSPException diff --git a/test/solidlsp/vue/test_vue_rename.py b/test/solidlsp/vue/test_vue_rename.py index 01ffbe25..efd0743e 100644 --- a/test/solidlsp/vue/test_vue_rename.py +++ b/test/solidlsp/vue/test_vue_rename.py @@ -3,13 +3,13 @@ import os import pytest from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId pytestmark = pytest.mark.vue class TestVueRename: - @pytest.mark.parametrize("language_server", [Language.VUE], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.VUE], indirect=True) def test_rename_function_within_single_file(self, language_server: SolidLanguageServer) -> None: file_path = os.path.join("src", "components", "CalculatorInput.vue") @@ -75,7 +75,7 @@ class TestVueRename: assert "line" in edit["range"]["start"], "Start position should have line number" assert "character" in edit["range"]["start"], "Start position should have character offset" - @pytest.mark.parametrize("language_server", [Language.VUE], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.VUE], indirect=True) def test_rename_composable_function_cross_file(self, language_server: SolidLanguageServer) -> None: composable_file = os.path.join("src", "composables", "useFormatter.ts") @@ -140,7 +140,7 @@ class TestVueRename: assert "start" in edit["range"], f"Range in {uri} should have start position" assert "end" in edit["range"], f"Range in {uri} should have end position" - @pytest.mark.parametrize("language_server", [Language.VUE], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.VUE], indirect=True) def test_rename_verifies_correct_file_paths_and_ranges(self, language_server: SolidLanguageServer) -> None: file_path = os.path.join("src", "App.vue") diff --git a/test/solidlsp/vue/test_vue_symbol_retrieval.py b/test/solidlsp/vue/test_vue_symbol_retrieval.py index 04a22e70..94856e60 100644 --- a/test/solidlsp/vue/test_vue_symbol_retrieval.py +++ b/test/solidlsp/vue/test_vue_symbol_retrieval.py @@ -3,14 +3,14 @@ import os import pytest from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from solidlsp.ls_types import SymbolKind pytestmark = pytest.mark.vue class TestVueSymbolRetrieval: - @pytest.mark.parametrize("language_server", [Language.VUE], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.VUE], indirect=True) def test_request_containing_symbol_script_setup_function(self, language_server: SolidLanguageServer) -> None: file_path = os.path.join("src", "components", "CalculatorInput.vue") @@ -45,7 +45,7 @@ class TestVueSymbolRetrieval: if "body" in containing_symbol: assert "handleDigit" in containing_symbol["body"].get_text(), "Function body should contain function name" - @pytest.mark.parametrize("language_server", [Language.VUE], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.VUE], indirect=True) def test_request_containing_symbol_computed_property(self, language_server: SolidLanguageServer) -> None: file_path = os.path.join("src", "components", "CalculatorInput.vue") @@ -80,7 +80,7 @@ class TestVueSymbolRetrieval: SymbolKind.Function, ], f"Expected property/variable/function kind for computed, got {containing_symbol.get('kind')}" - @pytest.mark.parametrize("language_server", [Language.VUE], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.VUE], indirect=True) def test_request_containing_symbol_no_containing_symbol(self, language_server: SolidLanguageServer) -> None: file_path = os.path.join("src", "components", "CalculatorInput.vue") @@ -97,7 +97,7 @@ class TestVueSymbolRetrieval: f"Expected None or empty dict for import position, got {containing_symbol}" ) - @pytest.mark.parametrize("language_server", [Language.VUE], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.VUE], indirect=True) def test_request_referencing_symbols_store_function(self, language_server: SolidLanguageServer) -> None: store_file = os.path.join("src", "stores", "calculator.ts") @@ -135,7 +135,7 @@ class TestVueSymbolRetrieval: assert "name" in ref, "Reference should have name" assert "location" in ref, "Reference should have location" - @pytest.mark.parametrize("language_server", [Language.VUE], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.VUE], indirect=True) def test_request_referencing_symbols_composable(self, language_server: SolidLanguageServer) -> None: composable_file = os.path.join("src", "composables", "useFormatter.ts") @@ -174,7 +174,7 @@ class TestVueSymbolRetrieval: f"Found references in: {[ref['location']['uri'] for ref in vue_refs if 'location' in ref and 'uri' in ref['location']]}" ) - @pytest.mark.parametrize("language_server", [Language.VUE], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.VUE], indirect=True) def test_vue_component_cross_references(self, language_server: SolidLanguageServer) -> None: input_file = os.path.join("src", "components", "CalculatorInput.vue") button_file = os.path.join("src", "components", "CalculatorButton.vue") @@ -199,7 +199,7 @@ class TestVueSymbolRetrieval: assert "Props" in symbol_names, "CalculatorButton.vue should have Props interface" assert "handleClick" in symbol_names, "CalculatorButton.vue should have handleClick function" - @pytest.mark.parametrize("language_server", [Language.VUE], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.VUE], indirect=True) def test_request_defining_symbol_import_resolution(self, language_server: SolidLanguageServer) -> None: file_path = os.path.join("src", "components", "CalculatorInput.vue") @@ -229,7 +229,7 @@ class TestVueSymbolRetrieval: f"Should point to calculator.ts, got {defining_symbol['location']['uri']}" ) - @pytest.mark.parametrize("language_server", [Language.VUE], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.VUE], indirect=True) def test_request_defining_symbol_component_import(self, language_server: SolidLanguageServer) -> None: file_path = os.path.join("src", "components", "CalculatorInput.vue") diff --git a/test/solidlsp/yaml_ls/test_yaml_basic.py b/test/solidlsp/yaml_ls/test_yaml_basic.py index da60e487..d0244060 100644 --- a/test/solidlsp/yaml_ls/test_yaml_basic.py +++ b/test/solidlsp/yaml_ls/test_yaml_basic.py @@ -10,7 +10,7 @@ from pathlib import Path import pytest from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from test.solidlsp.conftest import format_symbol_for_assert, has_malformed_name, request_all_symbols @@ -18,17 +18,17 @@ from test.solidlsp.conftest import format_symbol_for_assert, has_malformed_name, class TestYAMLLanguageServerBasics: """Test basic functionality of the YAML language server.""" - @pytest.mark.parametrize("language_server", [Language.YAML], indirect=True) - @pytest.mark.parametrize("repo_path", [Language.YAML], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.YAML], indirect=True) + @pytest.mark.parametrize("repo_path", [LanguageServerId.YAML], indirect=True) def test_yaml_language_server_initialization(self, language_server: SolidLanguageServer, repo_path: Path) -> None: """Test that YAML language server can be initialized successfully.""" assert language_server is not None - assert language_server.language == Language.YAML + assert language_server.ls_id == LanguageServerId.YAML assert language_server.is_running() assert Path(language_server.language_server.repository_root_path).resolve() == repo_path.resolve() - @pytest.mark.parametrize("language_server", [Language.YAML], indirect=True) - @pytest.mark.parametrize("repo_path", [Language.YAML], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.YAML], indirect=True) + @pytest.mark.parametrize("repo_path", [LanguageServerId.YAML], indirect=True) def test_yaml_config_file_symbols(self, language_server: SolidLanguageServer, repo_path: Path) -> None: """Test document symbols detection in config.yaml with specific symbol verification.""" all_symbols, root_symbols = language_server.request_document_symbols("config.yaml").get_all_symbols_and_roots() @@ -61,8 +61,8 @@ class TestYAMLLanguageServerBasics: assert debug_symbol is not None, "Should find 'debug' symbol" assert debug_symbol.get("kind") == 17, "'debug' should have kind 17 (boolean)" - @pytest.mark.parametrize("language_server", [Language.YAML], indirect=True) - @pytest.mark.parametrize("repo_path", [Language.YAML], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.YAML], indirect=True) + @pytest.mark.parametrize("repo_path", [LanguageServerId.YAML], indirect=True) def test_yaml_services_file_symbols(self, language_server: SolidLanguageServer, repo_path: Path) -> None: """Test symbol detection in services.yml Docker Compose file.""" all_symbols, root_symbols = language_server.request_document_symbols("services.yml").get_all_symbols_and_roots() @@ -89,8 +89,8 @@ class TestYAMLLanguageServerBasics: for ports_sym in ports_symbols: assert ports_sym.get("kind") == 18, "'ports' should have kind 18 (array)" - @pytest.mark.parametrize("language_server", [Language.YAML], indirect=True) - @pytest.mark.parametrize("repo_path", [Language.YAML], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.YAML], indirect=True) + @pytest.mark.parametrize("repo_path", [LanguageServerId.YAML], indirect=True) def test_yaml_data_file_symbols(self, language_server: SolidLanguageServer, repo_path: Path) -> None: """Test symbol detection in data.yaml file with array structures.""" all_symbols, root_symbols = language_server.request_document_symbols("data.yaml").get_all_symbols_and_roots() @@ -110,8 +110,8 @@ class TestYAMLLanguageServerBasics: assert "email" in symbol_names, "Should detect 'email' fields" assert "roles" in symbol_names, "Should detect 'roles' arrays" - @pytest.mark.parametrize("language_server", [Language.YAML], indirect=True) - @pytest.mark.parametrize("repo_path", [Language.YAML], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.YAML], indirect=True) + @pytest.mark.parametrize("repo_path", [LanguageServerId.YAML], indirect=True) def test_yaml_symbols_with_body(self, language_server: SolidLanguageServer, repo_path: Path) -> None: """Test request_document_symbols with body extraction.""" all_symbols, root_symbols = language_server.request_document_symbols("config.yaml").get_all_symbols_and_roots() @@ -147,8 +147,8 @@ class TestYAMLLanguageServerBasics: assert "host: localhost" in db_body, "Body should contain host configuration" assert "port: 5432" in db_body, "Body should contain port configuration" - @pytest.mark.parametrize("language_server", [Language.YAML], indirect=True) - @pytest.mark.parametrize("repo_path", [Language.YAML], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.YAML], indirect=True) + @pytest.mark.parametrize("repo_path", [LanguageServerId.YAML], indirect=True) def test_yaml_symbol_ranges(self, language_server: SolidLanguageServer, repo_path: Path) -> None: """Test that symbols have proper range information.""" all_symbols, root_symbols = language_server.request_document_symbols("config.yaml").get_all_symbols_and_roots() @@ -177,7 +177,7 @@ class TestYAMLLanguageServerBasics: assert app_port is not None, "Should find 'port' under 'app'" assert app_port["range"]["start"]["character"] == 2, "'port' should be indented 2 spaces" - @pytest.mark.parametrize("language_server", [Language.YAML], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.YAML], indirect=True) def test_bare_symbol_names(self, language_server) -> None: all_symbols = request_all_symbols(language_server) malformed_symbols = [] diff --git a/test/solidlsp/yaml_ls/test_yaml_diagnostics.py b/test/solidlsp/yaml_ls/test_yaml_diagnostics.py index 4ba774c7..270f603d 100644 --- a/test/solidlsp/yaml_ls/test_yaml_diagnostics.py +++ b/test/solidlsp/yaml_ls/test_yaml_diagnostics.py @@ -1,13 +1,13 @@ import pytest from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId from test.solidlsp.util.diagnostics import assert_file_diagnostics @pytest.mark.yaml class TestYamlDiagnostics: - @pytest.mark.parametrize("language_server", [Language.YAML], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.YAML], indirect=True) def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None: assert_file_diagnostics( language_server, diff --git a/test/solidlsp/zig/test_zig_basic.py b/test/solidlsp/zig/test_zig_basic.py index 7108774e..c9d9b6fe 100644 --- a/test/solidlsp/zig/test_zig_basic.py +++ b/test/solidlsp/zig/test_zig_basic.py @@ -11,7 +11,7 @@ import sys import pytest from solidlsp import SolidLanguageServer -from solidlsp.ls_config import Language +from solidlsp.ls_config import LanguageServerId 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 @@ -28,7 +28,7 @@ class TestZigLanguageServer: due to unreliable cross-file reference functionality. Reason unknown. """ - @pytest.mark.parametrize("language_server", [Language.ZIG], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ZIG], indirect=True) def test_find_symbols_in_main(self, language_server: SolidLanguageServer) -> None: """Test finding specific symbols in main.zig.""" file_path = os.path.join("src", "main.zig") @@ -45,7 +45,7 @@ class TestZigLanguageServer: assert "main" in symbol_names, "main function not found" assert "greeting" in symbol_names, "greeting function not found" - @pytest.mark.parametrize("language_server", [Language.ZIG], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ZIG], indirect=True) def test_find_symbols_in_calculator(self, language_server: SolidLanguageServer) -> None: """Test finding Calculator struct and its methods.""" file_path = os.path.join("src", "calculator.zig") @@ -88,7 +88,7 @@ class TestZigLanguageServer: found_methods = set(all_symbols) & expected_methods assert found_methods == expected_methods, f"Expected exactly {expected_methods}, found: {found_methods}" - @pytest.mark.parametrize("language_server", [Language.ZIG], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ZIG], indirect=True) def test_find_symbols_in_math_utils(self, language_server: SolidLanguageServer) -> None: """Test finding functions in math_utils.zig.""" file_path = os.path.join("src", "math_utils.zig") @@ -104,7 +104,7 @@ class TestZigLanguageServer: assert "factorial" in symbol_names, "factorial function not found" assert "isPrime" in symbol_names, "isPrime function not found" - @pytest.mark.parametrize("language_server", [Language.ZIG], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ZIG], indirect=True) def test_find_references_within_file(self, language_server: SolidLanguageServer) -> None: """Test finding references within the same file.""" file_path = os.path.join("src", "calculator.zig") @@ -141,7 +141,7 @@ class TestZigLanguageServer: for line in test_lines: assert line in ref_lines, f"Should find Calculator reference at line {line + 1}, found at lines {[l + 1 for l in ref_lines]}" - @pytest.mark.parametrize("language_server", [Language.ZIG], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ZIG], indirect=True) @pytest.mark.skipif( sys.platform == "win32", reason="ZLS cross-file references don't work reliably on Windows - URI path handling issues" ) @@ -204,7 +204,7 @@ class TestZigLanguageServer: f"Calculator reference in main.zig should be at line 8 (0-indexed: 7), found at line {main_ref_line + 1}" ) - @pytest.mark.parametrize("language_server", [Language.ZIG], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ZIG], indirect=True) def test_cross_file_references_within_file(self, language_server: SolidLanguageServer) -> None: """ Test that ZLS finds references within the same file. @@ -245,7 +245,7 @@ class TestZigLanguageServer: for line in test_lines: assert line in ref_lines, f"Should find Calculator reference at line {line + 1}, found at lines {[l + 1 for l in ref_lines]}" - @pytest.mark.parametrize("language_server", [Language.ZIG], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ZIG], indirect=True) @pytest.mark.skipif( sys.platform == "win32", reason="ZLS cross-file references don't work reliably on Windows - URI path handling issues" ) @@ -273,7 +273,7 @@ class TestZigLanguageServer: calc_def = definitions[0] assert "calculator.zig" in calc_def.get("uri", ""), "Definition should be in calculator.zig" - @pytest.mark.parametrize("language_server", [Language.ZIG], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ZIG], indirect=True) @pytest.mark.skipif( sys.platform == "win32", reason="ZLS cross-file references don't work reliably on Windows - URI path handling issues" ) @@ -294,7 +294,7 @@ class TestZigLanguageServer: math_def = [d for d in definitions if "math_utils.zig" in d.get("uri", "")] assert len(math_def) > 0, "Should find factorial definition in math_utils.zig" - @pytest.mark.parametrize("language_server", [Language.ZIG], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ZIG], indirect=True) def test_verify_cross_file_imports(self, language_server: SolidLanguageServer) -> None: """Verify that our test files have proper cross-file imports.""" # Verify main.zig imports @@ -322,7 +322,7 @@ class TestZigLanguageServer: assert "factorial" in math_names, "factorial function should be in math_utils.zig" assert "isPrime" in math_names, "isPrime function should be in math_utils.zig" - @pytest.mark.parametrize("language_server", [Language.ZIG], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ZIG], indirect=True) def test_hover_information(self, language_server: SolidLanguageServer) -> None: """Test hover information for symbols.""" file_path = os.path.join("src", "main.zig") @@ -336,7 +336,7 @@ class TestZigLanguageServer: if isinstance(hover_info, dict): assert "contents" in hover_info or "value" in hover_info, "Hover should have contents" - @pytest.mark.parametrize("language_server", [Language.ZIG], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ZIG], indirect=True) def test_full_symbol_tree(self, language_server: SolidLanguageServer) -> None: """Test that full symbol tree is not empty.""" symbols = language_server.request_full_symbol_tree() @@ -349,7 +349,7 @@ class TestZigLanguageServer: assert isinstance(root, dict), "Root should be a dict" assert "name" in root, "Root should have a name" - @pytest.mark.parametrize("language_server", [Language.ZIG], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ZIG], indirect=True) def test_bare_symbol_names(self, language_server) -> None: all_symbols = request_all_symbols(language_server) malformed_symbols = [] @@ -362,7 +362,7 @@ class TestZigLanguageServer: pytrace=False, ) - @pytest.mark.parametrize("language_server", [Language.ZIG], indirect=True) + @pytest.mark.parametrize("language_server", [LanguageServerId.ZIG], indirect=True) def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None: assert_file_diagnostics( language_server,