Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions noxfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ def tests(session: nox.Session):
"""Run tests for generator and generated code in all languages."""
_install_requirements(session)

session.log("Running test data generator.")
session.run("python", "-m", "generator", "--plugin", "testdata")

session.log("Running tests: generator and generated Python code.")
session.run("pytest", "./tests")

Expand Down
117 changes: 117 additions & 0 deletions packages/python/lsprotocol/_hooks.py
Original file line number Diff line number Diff line change
Expand Up @@ -634,6 +634,88 @@ def _notebook_sync_option_selector_hook(
object_, lsp_types.NotebookDocumentSyncOptionsNotebookSelectorType2
)

def _semantic_token_registration_options_hook(
object_: Any, _: type
) -> Optional[
Union[OptionalPrimitive, lsp_types.SemanticTokensRegistrationOptionsFullType1]
]:
if object_ is None:
return None
if isinstance(object_, (bool, int, str, float)):
return object_
return converter.structure(
object_, lsp_types.SemanticTokensRegistrationOptionsFullType1
)

def _inline_completion_provider_hook(
object_: Any, _: type
) -> Optional[Union[OptionalPrimitive, lsp_types.InlineCompletionOptions]]:
if object_ is None:
return None
if isinstance(object_, (bool, int, str, float)):
return object_
return converter.structure(object_, lsp_types.InlineCompletionOptions)

def _inline_completion_list_hook(
object_: Any, _: type
) -> Optional[
Union[lsp_types.InlineCompletionList, List[lsp_types.InlineCompletionItem]]
]:
if object_ is None:
return None
if isinstance(object_, list):
return [
converter.structure(item, lsp_types.InlineCompletionItem)
for item in object_
]
return converter.structure(object_, lsp_types.InlineCompletionList)

def _string_value_hook(
object_: Any, _: type
) -> Union[OptionalPrimitive, lsp_types.StringValue]:
if object_ is None:
return None
if isinstance(object_, (bool, int, str, float)):
return object_
return converter.structure(object_, lsp_types.StringValue)

def _symbol_list_hook(
object_: Any, _: type
) -> Optional[
Union[List[lsp_types.SymbolInformation], List[lsp_types.WorkspaceSymbol]]
]:
if object_ is None:
return None
assert isinstance(object_, list)
if len(object_) == 0:
return [] # type: ignore[return-value]
if "location" in object_[0]:
return [
converter.structure(item, lsp_types.SymbolInformation)
for item in object_
]
else:
return [
converter.structure(item, lsp_types.WorkspaceSymbol) for item in object_
]

def _notebook_sync_registration_option_selector_hook(
object_: Any, _: type
) -> Union[
lsp_types.NotebookDocumentSyncRegistrationOptionsNotebookSelectorType1,
lsp_types.NotebookDocumentSyncRegistrationOptionsNotebookSelectorType2,
]:
if "notebook" in object_:
return converter.structure(
object_,
lsp_types.NotebookDocumentSyncRegistrationOptionsNotebookSelectorType1,
)
else:
return converter.structure(
object_,
lsp_types.NotebookDocumentSyncRegistrationOptionsNotebookSelectorType2,
)

structure_hooks = [
(
Optional[
Expand Down Expand Up @@ -940,6 +1022,41 @@ def _notebook_sync_option_selector_hook(
],
_position_encoding_hook,
),
(
Optional[Union[bool, lsp_types.SemanticTokensRegistrationOptionsFullType1]],
_semantic_token_registration_options_hook,
),
(
Optional[Union[bool, lsp_types.InlineCompletionOptions]],
_inline_completion_provider_hook,
),
(
Optional[
Union[
lsp_types.InlineCompletionList, List[lsp_types.InlineCompletionItem]
]
],
_inline_completion_list_hook,
),
(
Union[str, lsp_types.StringValue],
_string_value_hook,
),
(
Optional[
Union[
List[lsp_types.SymbolInformation], List[lsp_types.WorkspaceSymbol]
]
],
_symbol_list_hook,
),
(
Union[
lsp_types.NotebookDocumentSyncRegistrationOptionsNotebookSelectorType1,
lsp_types.NotebookDocumentSyncRegistrationOptionsNotebookSelectorType2,
],
_notebook_sync_registration_option_selector_hook,
),
]
for type_, hook in structure_hooks:
converter.register_structure_hook(type_, hook)
Expand Down
34 changes: 34 additions & 0 deletions tests/python/test_generated_data.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.

import json
import pathlib
from typing import Generator, List, Union

import pytest

import lsprotocol.converters as cv
import lsprotocol.types as lsp

TEST_DATA_ROOT = pathlib.Path(__file__).parent.parent.parent / "packages" / "testdata"


def get_all_json_files(root: Union[pathlib.Path, str]) -> List[pathlib.Path]:
root_path = pathlib.Path(root)
return list(root_path.glob("**/*.json"))


converter = cv.get_converter()


@pytest.mark.parametrize("json_file", get_all_json_files(TEST_DATA_ROOT))
def test_generated_data(json_file: str) -> None:
type_name, result_type, _ = json_file.name.split("-", 2)
lsp_type = getattr(lsp, type_name)
data = json.loads(json_file.read_text(encoding="utf-8"))

try:
converter.structure(data, lsp_type)
assert result_type == "True", "Expected error, but succeeded structuring"
except Exception as e:
assert result_type == "False", "Expected success, but failed structuring"