mirror of
https://github.com/tiennm99/serena.git
synced 2026-10-04 22:13:47 +00:00
219 lines
6.8 KiB
Python
219 lines
6.8 KiB
Python
import logging
|
|
import os
|
|
from collections.abc import Iterator
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
from blib2to3.pgen2.parse import contextmanager
|
|
from sensai.util.logging import configure
|
|
|
|
from serena.config.serena_config import SerenaPaths
|
|
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.settings import SolidLSPSettings
|
|
|
|
from .solidlsp.clojure import is_clojure_cli_available
|
|
|
|
configure(level=logging.INFO)
|
|
|
|
log = logging.getLogger(__name__)
|
|
|
|
|
|
@pytest.fixture(scope="session")
|
|
def resources_dir() -> Path:
|
|
"""Path to the test resources directory."""
|
|
current_dir = Path(__file__).parent
|
|
return current_dir / "resources"
|
|
|
|
|
|
class LanguageParamRequest:
|
|
param: Language
|
|
|
|
|
|
def get_repo_path(language: Language) -> Path:
|
|
return Path(__file__).parent / "resources" / "repos" / language / "test_repo"
|
|
|
|
|
|
def _create_ls(
|
|
language: Language, repo_path: str | None = None, ignored_paths: list[str] | None = None, trace_lsp_communication: bool = False
|
|
) -> SolidLanguageServer:
|
|
ignored_paths = ignored_paths or []
|
|
if repo_path is None:
|
|
repo_path = str(get_repo_path(language))
|
|
gitignore_parser = GitignoreParser(str(repo_path))
|
|
for spec in gitignore_parser.get_ignore_specs():
|
|
ignored_paths.extend(spec.patterns)
|
|
config = LanguageServerConfig(code_language=language, ignored_paths=ignored_paths, trace_lsp_communication=trace_lsp_communication)
|
|
return SolidLanguageServer.create(
|
|
config,
|
|
repo_path,
|
|
solidlsp_settings=SolidLSPSettings(
|
|
solidlsp_dir=SerenaPaths().serena_user_home_dir, project_data_relative_path=SERENA_MANAGED_DIR_NAME
|
|
),
|
|
)
|
|
|
|
|
|
@contextmanager
|
|
def start_ls_context(
|
|
language: Language, repo_path: str | None = None, ignored_paths: list[str] | None = None, trace_lsp_communication: bool = False
|
|
) -> Iterator[SolidLanguageServer]:
|
|
ls = _create_ls(language, repo_path, ignored_paths, trace_lsp_communication)
|
|
log.info(f"Starting language server for {language} {repo_path}")
|
|
ls.start()
|
|
try:
|
|
log.info(f"Language server started for {language} {repo_path}")
|
|
yield ls
|
|
finally:
|
|
log.info(f"Stopping language server for {language} {repo_path}")
|
|
try:
|
|
ls.stop(shutdown_timeout=5)
|
|
except Exception as e:
|
|
log.warning(f"Warning: Error stopping language server: {e}")
|
|
# try to force cleanup
|
|
if hasattr(ls, "server") and hasattr(ls.server, "process"):
|
|
try:
|
|
ls.server.process.terminate()
|
|
except:
|
|
pass
|
|
|
|
|
|
@contextmanager
|
|
def start_default_ls_context(language: Language) -> Iterator[SolidLanguageServer]:
|
|
with start_ls_context(language) as ls:
|
|
yield ls
|
|
|
|
|
|
def _create_default_project(language: Language) -> Project:
|
|
repo_path = str(get_repo_path(language))
|
|
return Project.load(repo_path)
|
|
|
|
|
|
@pytest.fixture(scope="session")
|
|
def repo_path(request: LanguageParamRequest) -> Path:
|
|
"""Get the repository path for a specific language.
|
|
|
|
This fixture requires a language parameter via pytest.mark.parametrize:
|
|
|
|
Example:
|
|
```
|
|
@pytest.mark.parametrize("repo_path", [Language.PYTHON], indirect=True)
|
|
def test_python_repo(repo_path):
|
|
assert (repo_path / "src").exists()
|
|
```
|
|
|
|
"""
|
|
if not hasattr(request, "param"):
|
|
raise ValueError("Language parameter must be provided via pytest.mark.parametrize")
|
|
|
|
language = request.param
|
|
return get_repo_path(language)
|
|
|
|
|
|
# Note: using module scope here to avoid restarting LS for each test function but still terminate between test modules
|
|
@pytest.fixture(scope="module")
|
|
def language_server(request: LanguageParamRequest):
|
|
"""Create a language server instance configured for the specified language.
|
|
|
|
This fixture requires a language parameter via pytest.mark.parametrize:
|
|
|
|
Example:
|
|
```
|
|
@pytest.mark.parametrize("language_server", [Language.PYTHON], indirect=True)
|
|
def test_python_server(language_server: SyncLanguageServer) -> None:
|
|
# Use the Python language server
|
|
pass
|
|
```
|
|
|
|
You can also test multiple languages in a single test:
|
|
```
|
|
@pytest.mark.parametrize("language_server", [Language.PYTHON, Language.TYPESCRIPT], indirect=True)
|
|
def test_multiple_languages(language_server: SyncLanguageServer) -> None:
|
|
# This test will run once for each language
|
|
pass
|
|
```
|
|
|
|
"""
|
|
if not hasattr(request, "param"):
|
|
raise ValueError("Language parameter must be provided via pytest.mark.parametrize")
|
|
|
|
language = request.param
|
|
with start_default_ls_context(language) as ls:
|
|
yield ls
|
|
|
|
|
|
@pytest.fixture(scope="module")
|
|
def project(request: LanguageParamRequest):
|
|
"""Create a Project for the specified language.
|
|
|
|
This fixture requires a language parameter via pytest.mark.parametrize:
|
|
|
|
Example:
|
|
```
|
|
@pytest.mark.parametrize("project", [Language.PYTHON], indirect=True)
|
|
def test_python_project(project: Project) -> None:
|
|
# Use the Python project to test something
|
|
pass
|
|
```
|
|
|
|
You can also test multiple languages in a single test:
|
|
```
|
|
@pytest.mark.parametrize("project", [Language.PYTHON, Language.TYPESCRIPT], indirect=True)
|
|
def test_multiple_languages(project: SyncLanguageServer) -> None:
|
|
# This test will run once for each language
|
|
pass
|
|
```
|
|
|
|
"""
|
|
if not hasattr(request, "param"):
|
|
raise ValueError("Language parameter must be provided via pytest.mark.parametrize")
|
|
|
|
language = request.param
|
|
project = _create_default_project(language)
|
|
yield project
|
|
project.shutdown(timeout=5)
|
|
|
|
|
|
is_ci = os.getenv("CI") == "true" or os.getenv("GITHUB_ACTIONS") == "true"
|
|
"""
|
|
Flag indicating whether the tests are running in the GitHub CI environment.
|
|
"""
|
|
|
|
|
|
def _determine_disabled_languages() -> list[Language]:
|
|
"""
|
|
Determine which language tests should be disabled (based on the environment)
|
|
|
|
:return: the list of disabled languages
|
|
"""
|
|
result: list[Language] = []
|
|
|
|
java_tests_enabled = True
|
|
if not java_tests_enabled:
|
|
result.append(Language.JAVA)
|
|
|
|
clojure_tests_enabled = is_clojure_cli_available()
|
|
if not clojure_tests_enabled:
|
|
result.append(Language.CLOJURE)
|
|
|
|
al_tests_enabled = True
|
|
if not al_tests_enabled:
|
|
result.append(Language.AL)
|
|
|
|
return result
|
|
|
|
|
|
_disabled_languages = _determine_disabled_languages()
|
|
|
|
|
|
def language_tests_enabled(language: Language) -> bool:
|
|
"""
|
|
Check if tests for the given language are enabled in the current environment.
|
|
|
|
:param language: the language to check
|
|
:return: True if tests for the language are enabled, False otherwise
|
|
"""
|
|
return language not in _disabled_languages
|