more tests, and travis yaml integration
This commit is contained in:
parent
0d7bfb4ea9
commit
11cef6c233
16
.travis.yml
Normal file
16
.travis.yml
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
language: python
|
||||||
|
python:
|
||||||
|
# - "2.6"
|
||||||
|
- "2.7"
|
||||||
|
# - "3.3"
|
||||||
|
# - "3.4"
|
||||||
|
# - "3.5"
|
||||||
|
- "3.6"
|
||||||
|
# - "3.6-dev" # 3.6 development branch
|
||||||
|
# - "3.7-dev" # 3.7 development branch
|
||||||
|
# command to install dependencies
|
||||||
|
#install:
|
||||||
|
# - pip install -r requirements.txt
|
||||||
|
# command to run tests
|
||||||
|
script:
|
||||||
|
- pytest
|
10
README.md
10
README.md
@ -1 +1,9 @@
|
|||||||
# python-lsp
|
# pylspclient
|
||||||
|
The library implements a LSP client in Python.
|
||||||
|
|
||||||
|
[![Build Status](https://travis-ci.org/yeger00/pylspclient.svg?branch=master)](https://travis-ci.org/yeger00/pylspclient)
|
||||||
|
|
||||||
|
# Run the tests
|
||||||
|
```
|
||||||
|
tox
|
||||||
|
```
|
||||||
|
@ -3,13 +3,10 @@ import subprocess
|
|||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
# clangd_path = "/usr/bin/clangd-6.0"
|
clangd_path = "/usr/bin/clangd-6.0"
|
||||||
clangd_path = "/home/osboxes/projects/build/bin/clangd"
|
|
||||||
p = subprocess.Popen(clangd_path, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
p = subprocess.Popen(clangd_path, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||||
json_rpc_endpoint = pylspclient.JsonRpcEndpoint(p.stdin, p.stdout)
|
json_rpc_endpoint = pylspclient.JsonRpcEndpoint(p.stdin, p.stdout)
|
||||||
# Working with socket:
|
# To work with socket: sock_fd = sock.makefile()
|
||||||
# sock_fd = sock.makefile()
|
|
||||||
# json_rpc_endpoint = JsonRpcEndpoint(sock_fd, stext_document_res = lpc_client.send_notification(text_document_message)ock_fd)
|
|
||||||
lsp_endpoint = pylspclient.LspEndpoint(json_rpc_endpoint)
|
lsp_endpoint = pylspclient.LspEndpoint(json_rpc_endpoint)
|
||||||
|
|
||||||
lsp_client = pylspclient.LspClient(lsp_endpoint)
|
lsp_client = pylspclient.LspClient(lsp_endpoint)
|
||||||
@ -125,12 +122,12 @@ if __name__ == "__main__":
|
|||||||
25,
|
25,
|
||||||
26]}},'workspaceEdit': {'documentChanges': True},
|
26]}},'workspaceEdit': {'documentChanges': True},
|
||||||
'workspaceFolders': True}}
|
'workspaceFolders': True}}
|
||||||
workspace_folders = [{'name': 'python-lsp', 'uri': 'file:///home/osboxes/projects/ctest'}]
|
workspace_folders = [{'name': 'python-lsp', 'uri': 'file:///path/to/dir'}]
|
||||||
root_uri = 'file:///home/osboxes/projects/ctest'
|
root_uri = 'file:///path/to/dir'
|
||||||
print(lsp_client.initialize(p.pid, None, root_uri, None, capabilities, "off", workspace_folders))
|
print(lsp_client.initialize(p.pid, None, root_uri, None, capabilities, "off", workspace_folders))
|
||||||
print(lsp_client.initialized())
|
print(lsp_client.initialized())
|
||||||
|
|
||||||
file_path = "/home/osboxes/projects/ctest/test.c"
|
file_path = "/path/to/dir/file.c"
|
||||||
uri = "file://" + file_path
|
uri = "file://" + file_path
|
||||||
text = open(file_path, "r").read()
|
text = open(file_path, "r").read()
|
||||||
languageId = pylspclient.lsp_structs.LANGUAGE_IDENTIFIER.C
|
languageId = pylspclient.lsp_structs.LANGUAGE_IDENTIFIER.C
|
||||||
|
@ -4,7 +4,7 @@ import re
|
|||||||
from pylspclient import lsp_structs
|
from pylspclient import lsp_structs
|
||||||
import threading
|
import threading
|
||||||
|
|
||||||
JSON_RPC_REQ_FORMAT = "Content-Length: {json_string_len}\r\n\r\n{json_string}\r\n\r\n"
|
JSON_RPC_REQ_FORMAT = "Content-Length: {json_string_len}\r\n\r\n{json_string}"
|
||||||
JSON_RPC_RES_REGEX = "Content-Length: ([0-9]*)\r\n"
|
JSON_RPC_RES_REGEX = "Content-Length: ([0-9]*)\r\n"
|
||||||
# TODO: add content-type
|
# TODO: add content-type
|
||||||
|
|
||||||
@ -30,11 +30,19 @@ class JsonRpcEndpoint(object):
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def __add_header(json_string):
|
def __add_header(json_string):
|
||||||
|
'''
|
||||||
|
Adds a header for the given json string
|
||||||
|
|
||||||
|
:param str json_string: The string
|
||||||
|
:return: the string with the header
|
||||||
|
'''
|
||||||
return JSON_RPC_REQ_FORMAT.format(json_string_len=len(json_string), json_string=json_string)
|
return JSON_RPC_REQ_FORMAT.format(json_string_len=len(json_string), json_string=json_string)
|
||||||
|
|
||||||
|
|
||||||
def send_request(self, message):
|
def send_request(self, message):
|
||||||
'''
|
'''
|
||||||
|
Sends the given message.
|
||||||
|
|
||||||
:param dict message: The message to send.
|
:param dict message: The message to send.
|
||||||
'''
|
'''
|
||||||
json_string = json.dumps(message, cls=MyEncoder)
|
json_string = json.dumps(message, cls=MyEncoder)
|
||||||
@ -47,26 +55,26 @@ class JsonRpcEndpoint(object):
|
|||||||
|
|
||||||
def recv_response(self):
|
def recv_response(self):
|
||||||
'''
|
'''
|
||||||
|
Recives a message.
|
||||||
|
|
||||||
|
:return: a message
|
||||||
'''
|
'''
|
||||||
with self.read_lock:
|
with self.read_lock:
|
||||||
line = self.stdout.readline()
|
line = self.stdout.readline()
|
||||||
if line is None:
|
if not line:
|
||||||
return None
|
return None
|
||||||
|
print(line)
|
||||||
line = line.decode()
|
line = line.decode()
|
||||||
# TODO: handle content type as well.
|
# TODO: handle content type as well.
|
||||||
match = re.match(JSON_RPC_RES_REGEX, line)
|
match = re.match(JSON_RPC_RES_REGEX, line)
|
||||||
if match is None or not match.groups():
|
if match is None or not match.groups():
|
||||||
# TODO: handle
|
raise RuntimeError("Bad header: " + line)
|
||||||
print("error1: ", line)
|
|
||||||
return None
|
|
||||||
size = int(match.groups()[0])
|
size = int(match.groups()[0])
|
||||||
line = self.stdout.readline()
|
line = self.stdout.readline()
|
||||||
if line is None:
|
if not line:
|
||||||
return None
|
return None
|
||||||
line = line.decode()
|
line = line.decode()
|
||||||
if line != "\r\n":
|
if line != "\r\n":
|
||||||
# TODO: handle
|
raise RuntimeError("Bad header: missing newline")
|
||||||
print("error2")
|
|
||||||
return None
|
|
||||||
jsonrpc_res = self.stdout.read(size)
|
jsonrpc_res = self.stdout.read(size)
|
||||||
return json.loads(jsonrpc_res)
|
return json.loads(jsonrpc_res)
|
||||||
|
@ -2,6 +2,11 @@ from pylspclient import lsp_structs
|
|||||||
|
|
||||||
class LspClient(object):
|
class LspClient(object):
|
||||||
def __init__(self, lsp_endpoint):
|
def __init__(self, lsp_endpoint):
|
||||||
|
"""
|
||||||
|
Constructs a new LspClient instance.
|
||||||
|
|
||||||
|
:param lsp_endpoint: TODO
|
||||||
|
"""
|
||||||
self.lsp_endpoint = lsp_endpoint
|
self.lsp_endpoint = lsp_endpoint
|
||||||
|
|
||||||
|
|
||||||
|
2
setup.py
2
setup.py
@ -11,7 +11,7 @@ class PyTest(TestCommand):
|
|||||||
|
|
||||||
def initialize_options(self):
|
def initialize_options(self):
|
||||||
TestCommand.initialize_options(self)
|
TestCommand.initialize_options(self)
|
||||||
self.pytest_args = ""
|
self.pytest_args = []
|
||||||
|
|
||||||
def run_tests(self):
|
def run_tests(self):
|
||||||
# import here, cause outside the eggs aren't loaded
|
# import here, cause outside the eggs aren't loaded
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
|
import os
|
||||||
|
#from pytest_mock import mocker
|
||||||
|
import pytest
|
||||||
import pylspclient
|
import pylspclient
|
||||||
from pytest_mock import mocker
|
|
||||||
|
|
||||||
|
|
||||||
class StdinMock(object):
|
class StdinMock(object):
|
||||||
@ -10,36 +12,72 @@ class StdinMock(object):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def test_sanity(mocker):
|
class StdoutMock(object):
|
||||||
stdin_mock = StdinMock();
|
def readline(self):
|
||||||
mocker.patch.object(stdin_mock, 'write')
|
pass
|
||||||
json_rpc_endpoint = pylspclient.JsonRpcEndpoint(stdin_mock, None)
|
|
||||||
|
def read(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
JSON_RPC_RESULT_LIST = [
|
||||||
|
'Content-Length: 40\r\n\r\n{"key_str": "some_string", "key_num": 1}'.encode("utf-8"),
|
||||||
|
'Content-Length: 40\r\n\r\n{"key_num": 1, "key_str": "some_string"}'.encode("utf-8")
|
||||||
|
]
|
||||||
|
|
||||||
|
def test_send_sanity():
|
||||||
|
pipein, pipeout = os.pipe()
|
||||||
|
pipein = os.fdopen(pipein, "rb")
|
||||||
|
pipeout = os.fdopen(pipeout, "wb")
|
||||||
|
json_rpc_endpoint = pylspclient.JsonRpcEndpoint(pipeout, None)
|
||||||
json_rpc_endpoint.send_request({"key_num":1, "key_str":"some_string"})
|
json_rpc_endpoint.send_request({"key_num":1, "key_str":"some_string"})
|
||||||
stdin_mock.write.assert_called()
|
result = pipein.read(len(JSON_RPC_RESULT_LIST[0]))
|
||||||
|
assert(result in JSON_RPC_RESULT_LIST)
|
||||||
assert(stdin_mock.write.call_args not in [
|
|
||||||
'''Content-Length: 40\r\n\r\n{"key_str": "some_string", "key_num": 1}\r\n\r\n'''.encode("utf-8"),
|
|
||||||
'''Content-Length: 40\r\n\r\n{"key_num": 1, "key_str": "some_string"}\r\n\r\n'''.encode("utf-8")
|
|
||||||
])
|
|
||||||
|
|
||||||
|
|
||||||
def test_class(mocker):
|
def test_send_class():
|
||||||
class RpcClass(object):
|
class RpcClass(object):
|
||||||
def __init__(self, value_num, value_str):
|
def __init__(self, value_num, value_str):
|
||||||
self.key_num = value_num
|
self.key_num = value_num
|
||||||
self.key_str = value_str
|
self.key_str = value_str
|
||||||
|
|
||||||
stdin_mock = StdinMock();
|
pipein, pipeout = os.pipe()
|
||||||
mocker.patch.object(stdin_mock, 'write')
|
pipein = os.fdopen(pipein, "rb")
|
||||||
json_rpc_endpoint = pylspclient.JsonRpcEndpoint(stdin_mock, None)
|
pipeout = os.fdopen(pipeout, "wb")
|
||||||
|
json_rpc_endpoint = pylspclient.JsonRpcEndpoint(pipeout, None)
|
||||||
json_rpc_endpoint.send_request(RpcClass(1, "some_string"))
|
json_rpc_endpoint.send_request(RpcClass(1, "some_string"))
|
||||||
stdin_mock.write.assert_called()
|
result = pipein.read(len(JSON_RPC_RESULT_LIST[0]))
|
||||||
|
assert(result in JSON_RPC_RESULT_LIST)
|
||||||
|
|
||||||
|
|
||||||
|
def test_recv_sanity():
|
||||||
|
pipein, pipeout = os.pipe()
|
||||||
|
pipein = os.fdopen(pipein, "rb")
|
||||||
|
pipeout = os.fdopen(pipeout, "wb")
|
||||||
|
json_rpc_endpoint = pylspclient.JsonRpcEndpoint(None, pipein)
|
||||||
|
pipeout.write('Content-Length: 40\r\n\r\n{"key_str": "some_string", "key_num": 1}'.encode("utf-8"))
|
||||||
|
pipeout.flush()
|
||||||
|
result = json_rpc_endpoint.recv_response()
|
||||||
|
assert({"key_num":1, "key_str":"some_string"} == result)
|
||||||
|
|
||||||
|
|
||||||
|
def test_recv_wrong_header():
|
||||||
|
pipein, pipeout = os.pipe()
|
||||||
|
pipein = os.fdopen(pipein, "rb")
|
||||||
|
pipeout = os.fdopen(pipeout, "wb")
|
||||||
|
json_rpc_endpoint = pylspclient.JsonRpcEndpoint(None, pipein)
|
||||||
|
pipeout.write('Contentength: 40\r\n\r\n{"key_str": "some_string", "key_num": 1}'.encode("utf-8"))
|
||||||
|
pipeout.flush()
|
||||||
|
with pytest.raises(RuntimeError):
|
||||||
|
result = json_rpc_endpoint.recv_response()
|
||||||
|
|
||||||
|
|
||||||
|
def test_recv_close_pipe():
|
||||||
|
pipein, pipeout = os.pipe()
|
||||||
|
pipein = os.fdopen(pipein, "rb")
|
||||||
|
pipeout = os.fdopen(pipeout, "wb")
|
||||||
|
json_rpc_endpoint = pylspclient.JsonRpcEndpoint(None, pipein)
|
||||||
|
pipeout.close()
|
||||||
|
result = json_rpc_endpoint.recv_response()
|
||||||
|
assert(result is None)
|
||||||
|
|
||||||
assert(stdin_mock.write.call_args not in [
|
|
||||||
'''Content-Length: 40\r\n\r\n{"key_str": "some_string", "key_num": 1}\r\n\r\n'''.encode("utf-8"),
|
|
||||||
'''Content-Length: 40\r\n\r\n{"key_num": 1, "key_str": "some_string"}\r\n\r\n'''.encode("utf-8")
|
|
||||||
])
|
|
||||||
|
|
||||||
# content of test_sample.py
|
|
||||||
def func(x):
|
|
||||||
return x + 1
|
|
||||||
|
Loading…
Reference in New Issue
Block a user