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

@@ -1,9 +1,19 @@
import asyncio
import logging
import os
import pprint
from subprocess import PIPE, run
from threading import Thread
import pytest
from pygls import features
from pygls.server import LanguageServer
from cmake_language_server.server import CMakeLanguageServer
@pytest.fixture()
def cmake_build(shared_datadir):
from subprocess import run, PIPE
source = shared_datadir / 'cmake'
build = source / 'build'
build.mkdir()
@@ -13,11 +23,37 @@ def cmake_build(shared_datadir):
stderr=PIPE,
universal_newlines=True)
if p.returncode != 0:
import logging
import os
import pprint
logging.error('env:\n' + pprint.pformat(os.environ))
logging.error('stdout:\n' + p.stdout)
logging.error('stderr:\n' + p.stderr)
raise RuntimeError("CMake failed")
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