Skip to content

Commit

Permalink
refactor: simplify end-to-end test client fixture definition
Browse files Browse the repository at this point in the history
  • Loading branch information
alcarney committed Aug 14, 2023
1 parent 5c6a891 commit 8b448d8
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 132 deletions.
41 changes: 41 additions & 0 deletions tests/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,19 @@
############################################################################
import asyncio
import logging
import pathlib
import sys
from concurrent.futures import Future
from typing import Dict
from typing import List
from typing import Type

import pytest
import pytest_asyncio
from lsprotocol import types

from pygls import IS_PYODIDE
from pygls import uris
from pygls.exceptions import JsonRpcMethodNotFound
from pygls.lsp.client import LanguageClient as BaseLanguageClient
from pygls.protocol import LanguageServerProtocol
Expand Down Expand Up @@ -137,3 +143,38 @@ def show_message(client: LanguageClient, params):
client.messages.append(params)

return client


def create_client_for_server(server_name: str):
"""Automate the process of creating a language client connected to the given server
and tearing it down again.
"""

@pytest_asyncio.fixture
async def fixture_func():
if IS_PYODIDE:
pytest.skip("not available in pyodide")

client = make_test_lsp_client()
server_dir = pathlib.Path(__file__, "..", "..", "examples", "servers").resolve()
root_dir = pathlib.Path(__file__, "..", "..", "examples", "workspace").resolve()

await client.start_io(sys.executable, str(server_dir / server_name))

# Initialize the server
response = await client.initialize_async(
types.InitializeParams(
capabilities=types.ClientCapabilities(),
root_uri=uris.from_fs_path(root_dir),
)
)
assert response is not None

yield client, response

await client.shutdown_async(None)
client.exit(None)

await client.stop()

return fixture_func
32 changes: 4 additions & 28 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@
import sys

import pytest
import pytest_asyncio
from lsprotocol import types

from pygls import uris, IS_PYODIDE, IS_WIN
from pygls.feature_manager import FeatureManager
Expand All @@ -34,7 +32,7 @@
setup_ls_features,
)

from .client import make_test_lsp_client
from .client import create_client_for_server

DOC = """document
for
Expand Down Expand Up @@ -106,31 +104,9 @@ def server_dir():
return path.resolve()


@pytest_asyncio.fixture()
async def json_server_client(server_dir, uri_for):
"""Returns a language client connected to server_dir/json_server.py."""

if IS_PYODIDE:
pytest.skip("subprocesses are not available in pyodide")

client = make_test_lsp_client()
await client.start_io(sys.executable, str(server_dir / "json_server.py"))

# Initialize the server
response = await client.initialize_async(
types.InitializeParams(
capabilities=types.ClientCapabilities(),
root_uri=uri_for("."), # root of example workspace
)
)
assert response is not None

yield client, response

await client.shutdown_async(None)
client.exit(None)

await client.stop()
code_action_client = create_client_for_server("code_actions.py")
inlay_hints_client = create_client_for_server("inlay_hints.py")
json_server_client = create_client_for_server("json_server.py")


@pytest.fixture
Expand Down
77 changes: 21 additions & 56 deletions tests/lsp/test_code_action.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,82 +14,47 @@
# See the License for the specific language governing permissions and #
# limitations under the License. #
############################################################################
import sys
from typing import Tuple

import pytest
import pytest_asyncio
from lsprotocol.types import (
ClientCapabilities,
CodeActionContext,
CodeActionKind,
CodeActionParams,
InitializeParams,
Position,
Range,
TextDocumentIdentifier,
)
from lsprotocol import types

import pygls.uris as uri
from pygls import IS_PYODIDE
from pygls.lsp.client import LanguageClient
from ..client import LanguageClient


@pytest_asyncio.fixture()
async def client(server_dir):
"""Setup and teardown the client."""

server_py = server_dir / "code_actions.py"

client = LanguageClient("pygls-test-client", "0.1")
await client.start_io(sys.executable, str(server_py))

yield client

await client.shutdown_async(None)
client.exit(None)

await client.stop()


@pytest.mark.skipif(IS_PYODIDE, reason="subprocesses are not available in pyodide.")
async def test_code_actions(client: LanguageClient, workspace_dir):
async def test_code_actions(
code_action_client: Tuple[LanguageClient, types.InitializeResult],
uri_for
):
"""Ensure that the example code action server is working as expected."""
client, initialize_result = code_action_client

response = await client.initialize_async(
InitializeParams(
capabilities=ClientCapabilities(),
root_uri=uri.from_fs_path(str(workspace_dir)),
)
)
assert response is not None

code_action_options = response.capabilities.code_action_provider
assert code_action_options.code_action_kinds == [CodeActionKind.QuickFix]
code_action_options = initialize_result.capabilities.code_action_provider
assert code_action_options.code_action_kinds == [types.CodeActionKind.QuickFix]

test_uri = uri.from_fs_path(str(workspace_dir / "sums.txt"))
test_uri = uri_for("sums.txt")
assert test_uri is not None

response = await client.text_document_code_action_async(
CodeActionParams(
text_document=TextDocumentIdentifier(uri=test_uri),
range=Range(
start=Position(line=0, character=0),
end=Position(line=1, character=0),
types.CodeActionParams(
text_document=types.TextDocumentIdentifier(uri=test_uri),
range=types.Range(
start=types.Position(line=0, character=0),
end=types.Position(line=1, character=0),
),
context=CodeActionContext(diagnostics=[]),
context=types.CodeActionContext(diagnostics=[]),
)
)

assert len(response) == 1
code_action = response[0]

assert code_action.title == "Evaluate '1 + 1 ='"
assert code_action.kind == CodeActionKind.QuickFix
assert code_action.kind == types.CodeActionKind.QuickFix

fix = code_action.edit.changes[test_uri][0]
expected_range = Range(
start=Position(line=0, character=0),
end=Position(line=0, character=7),
expected_range = types.Range(
start=types.Position(line=0, character=0),
end=types.Position(line=0, character=7),
)

assert fix.range == expected_range
Expand Down
63 changes: 15 additions & 48 deletions tests/lsp/test_inlay_hints.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,65 +14,32 @@
# See the License for the specific language governing permissions and #
# limitations under the License. #
############################################################################
import sys
from typing import Tuple

import pytest
import pytest_asyncio
from lsprotocol.types import (
ClientCapabilities,
InlayHintParams,
InitializeParams,
Position,
Range,
TextDocumentIdentifier,
)
from lsprotocol import types

import pygls.uris as uri
from pygls import IS_PYODIDE
from pygls.lsp.client import LanguageClient
from ..client import LanguageClient


@pytest_asyncio.fixture()
async def client(server_dir):
"""Setup and teardown the client."""

server_py = server_dir / "inlay_hints.py"

client = LanguageClient("pygls-test-client", "0.1")
await client.start_io(sys.executable, str(server_py))

yield client

await client.shutdown_async(None)
client.exit(None)

await client.stop()


@pytest.mark.skipif(IS_PYODIDE, reason="subprocesses are not available in pyodide.")
async def test_code_actions(client: LanguageClient, workspace_dir):
async def test_code_actions(
inlay_hints_client: Tuple[LanguageClient, types.InitializeResult],
uri_for
):
"""Ensure that the example code action server is working as expected."""
client, initialize_result = inlay_hints_client

response = await client.initialize_async(
InitializeParams(
capabilities=ClientCapabilities(),
root_uri=uri.from_fs_path(str(workspace_dir)),
)
)
assert response is not None

inlay_hint_provider = response.capabilities.inlay_hint_provider
inlay_hint_provider = initialize_result.capabilities.inlay_hint_provider
assert inlay_hint_provider.resolve_provider is True

test_uri = uri.from_fs_path(str(workspace_dir / "sums.txt"))
test_uri = uri_for("sums.txt")
assert test_uri is not None

response = await client.text_document_inlay_hint_async(
InlayHintParams(
text_document=TextDocumentIdentifier(uri=test_uri),
range=Range(
start=Position(line=3, character=0),
end=Position(line=4, character=0),
types.InlayHintParams(
text_document=types.TextDocumentIdentifier(uri=test_uri),
range=types.Range(
start=types.Position(line=3, character=0),
end=types.Position(line=4, character=0),
),
)
)
Expand Down

0 comments on commit 8b448d8

Please sign in to comment.