Add server tests

This commit is contained in:
Regen
2020-01-03 23:23:34 +09:00
parent 9e6fc1a277
commit c870e3d512
4 changed files with 173 additions and 7 deletions

View File

@@ -23,8 +23,8 @@ class CMakeLanguageServer(LanguageServer):
_parser: ListParser _parser: ListParser
_api: API _api: API
def __init__(self): def __init__(self, *args):
super().__init__() super().__init__(*args)
self._parser = ListParser() self._parser = ListParser()
self._api = None self._api = None

View File

@@ -1,9 +1,19 @@
import asyncio
import logging
import os
import pprint
from subprocess import PIPE, run
from threading import Thread
import pytest import pytest
from pygls import features
from pygls.server import LanguageServer
from cmake_language_server.server import CMakeLanguageServer
@pytest.fixture() @pytest.fixture()
def cmake_build(shared_datadir): def cmake_build(shared_datadir):
from subprocess import run, PIPE
source = shared_datadir / 'cmake' source = shared_datadir / 'cmake'
build = source / 'build' build = source / 'build'
build.mkdir() build.mkdir()
@@ -13,11 +23,37 @@ def cmake_build(shared_datadir):
stderr=PIPE, stderr=PIPE,
universal_newlines=True) universal_newlines=True)
if p.returncode != 0: if p.returncode != 0:
import logging
import os
import pprint
logging.error('env:\n' + pprint.pformat(os.environ)) logging.error('env:\n' + pprint.pformat(os.environ))
logging.error('stdout:\n' + p.stdout) logging.error('stdout:\n' + p.stdout)
logging.error('stderr:\n' + p.stderr) logging.error('stderr:\n' + p.stderr)
raise RuntimeError("CMake failed") raise RuntimeError("CMake failed")
yield build yield build
@pytest.fixture()
def client_server():
c2s_r, c2s_w = os.pipe()
s2c_r, s2c_w = os.pipe()
def start(ls: LanguageServer, fdr, fdw):
# TODO: better patch is needed
# disable `close()` to avoid error messages
close = ls.loop.close
ls.loop.close = lambda: None
ls.start_io(os.fdopen(fdr, 'rb'), os.fdopen(fdw, 'wb'))
ls.loop.close = close
server = CMakeLanguageServer(asyncio.new_event_loop())
server_thread = Thread(target=start, args=(server, c2s_r, s2c_w))
server_thread.start()
client = LanguageServer(asyncio.new_event_loop())
client_thread = Thread(target=start, args=(client, s2c_r, c2s_w))
client_thread.start()
yield client, server
client.send_notification(features.EXIT)
server.send_notification(features.EXIT)
server_thread.join()
client_thread.join()

130
tests/test_server.py Normal file
View File

@@ -0,0 +1,130 @@
from concurrent import futures
from pathlib import Path
from typing import Optional
from pygls.features import (COMPLETION, FORMATTING, HOVER, INITIALIZE,
TEXT_DOCUMENT_DID_OPEN)
from pygls.server import LanguageServer
from pygls.types import (CompletionContext, CompletionParams,
CompletionTriggerKind, DidOpenTextDocumentParams,
DocumentFormattingParams, FormattingOptions,
InitializeParams, Position, TextDocumentIdentifier,
TextDocumentItem, TextDocumentPositionParams)
CALL_TIMEOUT = 2
def _init(client: LanguageServer, root: Path):
retry = 3
while retry > 0:
try:
client.lsp.send_request(
INITIALIZE,
InitializeParams(
process_id=1234, root_uri=root.as_uri(),
capabilities=None)).result(timeout=CALL_TIMEOUT)
except futures.TimeoutError:
retry -= 1
else:
break
def _open(client: LanguageServer, path: Path, text: Optional[str] = None):
if text is None:
with open(path) as fp:
text = fp.read()
client.lsp.notify(
TEXT_DOCUMENT_DID_OPEN,
DidOpenTextDocumentParams(
TextDocumentItem(path.as_uri(), 'cmake', 1, text)))
def test_initialize(client_server, datadir):
client, server = client_server
assert server._api is None
_init(client, datadir)
assert server._api is not None
def test_completions_invoked(client_server, datadir):
client, server = client_server
_init(client, datadir)
path = datadir / 'CMakeLists.txt'
_open(client, path, 'projec')
response = client.lsp.send_request(
COMPLETION,
CompletionParams(TextDocumentIdentifier(path.as_uri()), Position(
0, 6), CompletionContext(
CompletionTriggerKind.Invoked))).result(timeout=CALL_TIMEOUT)
item = next(filter(lambda x: x.label == 'project', response.items), None)
assert item is not None
assert '<PROJECT-NAME>' in item.documentation
def test_completions_triggercharacter_variable(client_server, datadir):
client, server = client_server
_init(client, datadir)
path = datadir / 'CMakeLists.txt'
_open(client, path, '${')
response = client.lsp.send_request(
COMPLETION,
CompletionParams(
TextDocumentIdentifier(path.as_uri()), Position(0, 2),
CompletionContext(CompletionTriggerKind.TriggerCharacter,
'{'))).result(timeout=CALL_TIMEOUT)
assert 'PROJECT_VERSION' in [x.label for x in response.items]
def test_completions_triggercharacter_module(client_server, datadir):
client, server = client_server
_init(client, datadir)
path = datadir / 'CMakeLists.txt'
_open(client, path, 'include(')
response = client.lsp.send_request(
COMPLETION,
CompletionParams(
TextDocumentIdentifier(path.as_uri()), Position(0, 8),
CompletionContext(CompletionTriggerKind.TriggerCharacter,
'('))).result(timeout=CALL_TIMEOUT)
assert 'GoogleTest' in [x.label for x in response.items]
def test_completions_triggercharacter_package(client_server, datadir):
client, server = client_server
_init(client, datadir)
path = datadir / 'CMakeLists.txt'
_open(client, path, 'find_package(')
response = client.lsp.send_request(
COMPLETION,
CompletionParams(
TextDocumentIdentifier(path.as_uri()), Position(0, 13),
CompletionContext(CompletionTriggerKind.TriggerCharacter,
'('))).result(timeout=CALL_TIMEOUT)
assert 'Boost' in [x.label for x in response.items]
def test_formatting(client_server, datadir):
client, server = client_server
_init(client, datadir)
path = datadir / 'CMakeLists.txt'
_open(client, path, 'a ( b c ) ')
response = client.lsp.send_request(
FORMATTING,
DocumentFormattingParams(TextDocumentIdentifier(path.as_uri()),
FormattingOptions(
2, True))).result(timeout=CALL_TIMEOUT)
assert response[0].newText == 'a(b c)\n'
def test_hover(client_server, datadir):
client, server = client_server
_init(client, datadir)
path = datadir / 'CMakeLists.txt'
_open(client, path, 'project()')
response = client.lsp.send_request(
HOVER,
TextDocumentPositionParams(TextDocumentIdentifier(path.as_uri()),
Position())).result(timeout=CALL_TIMEOUT)
assert '<PROJECT-NAME>' in response.contents.value

View File

@@ -16,7 +16,7 @@ passenv = INCLUDE LIB LIBPATH Platform VCTools* VSCMD_* WindowsSDK*
commands_pre = commands_pre =
poetry install poetry install
commands = commands =
poetry run pytest --cov-report=xml --cov=src -sv tests poetry run pytest --cov-report=term --cov-report=xml --cov=src -sv tests
[testenv:lint] [testenv:lint]
commands = commands =