Skip to content
This repository has been archived by the owner on Feb 1, 2019. It is now read-only.

Add test cases to continuous integration #10

Merged
merged 13 commits into from
Feb 23, 2017
Merged
41 changes: 41 additions & 0 deletions .coafile
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
[Default]
files = *.py, coala_langserver/*.py, tests/**/*.py

max_line_length = 79
use_spaces = True

[python]
# Patches may conflict with autopep8 so putting them in own section so they
# will be executed sequentially; also we need the LineLengthBear to double
# check the line length because PEP8Bear sometimes isn't able to correct the
# linelength.
bears = SpaceConsistencyBear, QuotesBear
language = python
preferred_quotation = '

[autopep8]
bears = PEP8Bear, PycodestyleBear

[linelength] # Sometimes autopep8 makes too long lines, need to check after!
bears = LineLengthBear
ignore_length_regex = ^.*https?://

[commit]
bears = GitCommitBear
shortlog_trailing_period = False
shortlog_regex = ([^:]*|[^:]+[^ ]: [A-Z0-9*].*)

[LineCounting]
enabled = False
bears = LineCountBear
max_lines_per_file = 1000

[TODOS]
enabled = False
bears = KeywordBear
language = python3

# Note that the ci_keywords and cs_keywords are only used here because coala
# 0.8.x (current stable release) needs them.
ci_keywords, keywords = \#TODO, \# TODO, \#FIXME, \# FIXME
cs_keywords =
9 changes: 9 additions & 0 deletions .codecov.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
comment: false
coverage:
status:
changes: false
patch: false
project:
default:
enabled: true
target: 80%
16 changes: 16 additions & 0 deletions .coveragerc
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[run]
branch = True
source = .
omit =
coala-langserver.py
tests/*

[report]
exclude_lines =
if self.debug:
pass
pragma: no cover
raise NotImplementedError
def main
if __name__ == .__main__.:
ignore_errors = True
62 changes: 62 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
sudo: false
language: python
python:
- 3.4
- 3.5
- 3.6

cache:
pip: true
directories:
- node_modules

os:
# # The macOS build in travis is really slow.
# - osx
- linux

# Note that in order to run the tests on Linux,
# you need to have a before_install configuration
# to enable Linux to start VS Code from the build.
# ref https://code.visualstudio.com/Docs/extensions/testing-extensions
before_install:
- if [ $TRAVIS_OS_NAME == "linux" ]; then
export CXX="g++-4.9" CC="gcc-4.9" DISPLAY=:99.0;
sh -e /etc/init.d/xvfb start;
sleep 3;
fi

before_script:
# nltk 3.2.2 dropped support for Python 3.3
- >
if [[ "$TRAVIS_PYTHON_VERSION" != "3.3" ]]; then
python -m nltk.downloader punkt maxent_treebank_pos_tagger averaged_perceptron_tagger
fi

install:
# beheve is a dev dependeny, so not in requirements.txt.
- pip install behave
- pip install -r ./requirements.txt
# codecov is a code coverage tool.
- pip install codecov
- cd ./vscode-client
- npm install
- mkdir ./out
- npm run vscode:prepublish
- cd - > /dev/null

script:
- >
# https://github.com/coala/coala-bears/issues/1037
- sed -i.bak '/bears = GitCommitBear/d' .coafile
# Server side tests.
- coverage run $(which behave) ./tests/server.features
# # Integration tests.
# - cd ./vscode-client
# - npm test
# - cd - > /dev/null

after_success:
- codecov
# # If the build was triggered by a tag, publish the new version
# - 'if [[ $TRAVIS_TAG == v* ]]; then vsce publish -p $VSCE_TOKEN; fi'
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# coala-vs-code

[![Build Status](https://travis-ci.org/coala/coala-vs-code.svg?branch=master)](https://travis-ci.org/coala/coala-vs-code)
[![codecov](https://codecov.io/gh/coala/coala-vs-code/branch/master/graph/badge.svg)](https://codecov.io/gh/coala/coala-vs-code)

A visual studio code plugin working via [Language Server Protocol (LSP)](https://github.com/Microsoft/language-server-protocol/blob/master/protocol.md).Python versions 3.x is supported.

## Feature preview
2 changes: 1 addition & 1 deletion coala-langserver.py
Original file line number Diff line number Diff line change
@@ -8,4 +8,4 @@
langserver.main()
except Exception as e:
tb = traceback.format_exc()
print("FATAL ERROR: {} {}".format(e, tb))
print('FATAL ERROR: {} {}'.format(e, tb))
18 changes: 9 additions & 9 deletions coala_langserver/coalashim.py
Original file line number Diff line number Diff line change
@@ -5,25 +5,25 @@


def run_coala_with_specific_file(working_dir, file):
"""Run coala in a specified directory."""
command = ["coala", "--json", "--find-config", "--files", file]
'""Run coala in a specified directory.""'
command = ['coala', '--json', '--find-config', '--files', file]
stdout_file = tempfile.TemporaryFile()
kwargs = {"stdout": stdout_file,
"cwd": working_dir}
kwargs = {'stdout': stdout_file,
'cwd': working_dir}
process = subprocess.Popen(command, **kwargs)
retval = process.wait()
output_str = None

if retval == 1:
stdout_file.seek(0)
output_str = stdout_file.read().decode("utf-8", "ignore")
output_str = stdout_file.read().decode('utf-8', 'ignore')
if output_str:
log("Output =", output_str)
log('Output =', output_str)
else:
log("No results for the file")
log('No results for the file')
elif retval == 0:
log("No issues found")
log('No issues found')
else:
log("Exited with:", retval)
log('Exited with:', retval)
stdout_file.close()
return output_str
50 changes: 17 additions & 33 deletions coala_langserver/diagnostic.py
Original file line number Diff line number Diff line change
@@ -1,50 +1,34 @@
import json


class Diagnostic(object):
"""Diagnostic class for VS Code."""

def __init__(self, severity, range, message, section, origin):
self.severity = severity
self.range = range
self.message = message
self.source = "coala"
self.section = section
self.origin = origin
self.real_message = self.make_real_message()

def make_real_message(self):
return "[{}] {}: {}".format(self.section, self.origin, self.message)


def output_to_diagnostics(output):
"""Turn output to diagnstics."""
'""Turn output to diagnstics.""'
if output is None:
return None
output_json = json.loads(output)["results"]
output_json = json.loads(output)['results']
res = []
for key, problems in output_json.items():
section = key
for problem in problems:
severity = problem["severity"]
message = problem["message"]
origin = problem["origin"]
real_message = "[{}] {}: {}".format(section, origin, message)
for code in problem["affected_code"]:
severity = problem['severity']
message = problem['message']
origin = problem['origin']
real_message = '[{}] {}: {}'.format(section, origin, message)
for code in problem['affected_code']:
res.append({
"severity": severity,
"range": {
"start": {
'severity': severity,
'range': {
'start': {
# Trick: VS Code starts from 0?
"line": code["start"]["line"] - 1,
"character": code["start"]["column"]
'line': code['start']['line'] - 1,
'character': code['start']['column']
},
"end": {
"line": code["end"]["line"] - 1,
"character": code["end"]["column"]
'end': {
'line': code['end']['line'] - 1,
'character': code['end']['column']
}
},
"source": "coala",
"message": real_message
'source': 'coala',
'message': real_message
})
return res
57 changes: 0 additions & 57 deletions coala_langserver/fs.py

This file was deleted.

70 changes: 35 additions & 35 deletions coala_langserver/jsonrpc.py
Original file line number Diff line number Diff line change
@@ -31,10 +31,10 @@ class TCPReadWriter(ReadWriter):

def readline(self, *args):
data = self.reader.readline(*args)
return data.decode("utf-8")
return data.decode('utf-8')

def read(self, *args):
return self.reader.read(*args).decode("utf-8")
return self.reader.read(*args).decode('utf-8')

def write(self, out):
self.writer.write(out.encode())
@@ -52,30 +52,30 @@ def handle(self, id, request):

@staticmethod
def _read_header_content_length(line):
if len(line) < 2 or line[-2:] != "\r\n":
raise JSONRPC2Error("Line endings must be \\r\\n")
if line.startswith("Content-Length: "):
_, value = line.split("Content-Length: ")
if len(line) < 2 or line[-2:] != '\r\n':
raise JSONRPC2Error('Line endings must be \\r\\n')
if line.startswith('Content-Length: '):
_, value = line.split('Content-Length: ')
value = value.strip()
try:
return int(value)
except ValueError:
raise JSONRPC2Error(
"Invalid Content-Length header: {}".format(value))
'Invalid Content-Length header: {}'.format(value))

def _receive(self):
line = self.conn.readline()
if line == "":
if line == '':
raise EOFError()
length = self._read_header_content_length(line)
# Keep reading headers until we find the sentinel line for the JSON
# request.
while line != "\r\n":
while line != '\r\n':
line = self.conn.readline()
body = self.conn.read(length)
obj = json.loads(body)
# If the next message doesn't have an id, just give it a random key.
self._msg_buffer[obj.get("id") or uuid.uuid4()] = obj
self._msg_buffer[obj.get('id') or uuid.uuid4()] = obj

def read_message(self, _id=None):
"""Read a JSON RPC message sent over the current connection. If
@@ -92,50 +92,50 @@ def read_message(self, _id=None):

def write_response(self, _id, result):
body = {
"jsonrpc": "2.0",
"id": _id,
"result": result,
'jsonrpc': '2.0',
'id': _id,
'result': result,
}
body = json.dumps(body, separators=(",", ":"))
body = json.dumps(body, separators=(',', ':'))
content_length = len(body)
response = (
"Content-Length: {}\r\n"
"Content-Type: application/vscode-jsonrpc; charset=utf8\r\n\r\n"
"{}".format(content_length, body))
'Content-Length: {}\r\n'
'Content-Type: application/vscode-jsonrpc; charset=utf8\r\n\r\n'
'{}'.format(content_length, body))
self.conn.write(response)
log("RESPONSE: ", response)
log('RESPONSE: ', response)

def send_request(self, method: str, params):
_id = random.randint(0, 2 ** 16) # TODO(renfred) guarantee uniqueness.
body = {
"jsonrpc": "2.0",
"id": _id,
"method": method,
"params": params,
'jsonrpc': '2.0',
'id': _id,
'method': method,
'params': params,
}
body = json.dumps(body, separators=(",", ":"))
body = json.dumps(body, separators=(',', ':'))
content_length = len(body)
request = (
"Content-Length: {}\r\n"
"Content-Type: application/vscode-jsonrpc; charset=utf8\r\n\r\n"
"{}".format(content_length, body))
log("SENDING REQUEST: ", request)
'Content-Length: {}\r\n'
'Content-Type: application/vscode-jsonrpc; charset=utf8\r\n\r\n'
'{}'.format(content_length, body))
log('SENDING REQUEST: ', request)
self.conn.write(request)
return self.read_message(_id)

def send_notification(self, method: str, params):
body = {
"jsonrpc": "2.0",
"method": method,
"params": params,
'jsonrpc': '2.0',
'method': method,
'params': params,
}
body = json.dumps(body, separators=(",", ":"))
body = json.dumps(body, separators=(',', ':'))
content_length = len(body)
notification = (
"Content-Length: {}\r\n"
"Content-Type: application/vscode-jsonrpc; charset=utf8\r\n\r\n"
"{}".format(content_length, body))
log("SENDING notification: ", notification)
'Content-Length: {}\r\n'
'Content-Type: application/vscode-jsonrpc; charset=utf8\r\n\r\n'
'{}'.format(content_length, body))
log('SENDING notification: ', notification)
self.conn.write(notification)
return None

111 changes: 54 additions & 57 deletions coala_langserver/langserver.py
Original file line number Diff line number Diff line change
@@ -3,7 +3,6 @@
import socketserver
import traceback

from .fs import LocalFileSystem
from .jsonrpc import JSONRPC2Connection, ReadWriter, TCPReadWriter
from .log import log
from .coalashim import run_coala_with_specific_file
@@ -23,107 +22,105 @@ def handle(self):
s.listen()
except Exception as e:
tb = traceback.format_exc()
log("ERROR: {} {}".format(e, tb))
log('ERROR: {} {}'.format(e, tb))


class LangServer(JSONRPC2Connection):
"""Language server for coala base on JSON RPC."""
'""Language server for coala base on JSON RPC.""'

def __init__(self, conn=None):
super().__init__(conn=conn)
self.root_path = None
self.symbol_cache = None
self.fs = LocalFileSystem()

def handle(self, _id, request):
"""Handle the request from language client."""
log("REQUEST: ", request)
'""Handle the request from language client.""'
log('REQUEST: ', request)
resp = None

if request["method"] == "initialize":
if request['method'] == 'initialize':
resp = self.serve_initialize(request)
# TODO: Support didChange.
# TODO: Support did_change and did_change_watched_files.
# elif request["method"] == "textDocument/didChange":
# resp = self.serve_change(request)
# elif request["method"] == "workspace/didChangeWatchedFiles":
# resp = self.serve_did_change_watched_files(request)
elif request["method"] == "textDocument/didSave":
resp = self.serve_did_save(request)
elif request['method'] == 'textDocument/didSave':
self.serve_did_save(request)

if resp is not None:
self.write_response(request["id"], resp)
self.write_response(request['id'], resp)

def serve_initialize(self, request):
"""Serve for the initialization request."""
params = request["params"]
'""Serve for the initialization request.""'
params = request['params']
# Notice that the root_path could be None.
if "rootUri" in params:
self.root_path = path_from_uri(params["rootUri"])
elif "rootPath" in params:
self.root_path = path_from_uri(params["rootPath"])
if 'rootUri' in params:
self.root_path = path_from_uri(params['rootUri'])
elif 'rootPath' in params:
self.root_path = path_from_uri(params['rootPath'])
return {
"capabilities": {
"textDocumentSync": 1
'capabilities': {
'textDocumentSync': 1
}
}

def serve_did_save(self, request):
"""Serve for did_change request."""
params = request["params"]
uri = params["textDocument"]["uri"]
'""Serve for did_change request.""'
params = request['params']
uri = params['textDocument']['uri']
path = path_from_uri(uri)
diagnostics = output_to_diagnostics(
run_coala_with_specific_file(self.root_path, path))
self.send_diagnostics(path, diagnostics)
return None

def serve_change(self, request):
"""Serve for the request of documentation changed."""
params = request["params"]
uri = params["textDocument"]["uri"]
path = path_from_uri(uri)
diagnostics = output_to_diagnostics(
run_coala_with_specific_file(self.root_path, path))
self.send_diagnostics(path, diagnostics)
return None

def serve_did_change_watched_files(self, request):
"""Serve for thr workspace/didChangeWatchedFiles request."""
changes = request["changes"]
for fileEvent in changes:
uri = fileEvent["uri"]
path = path_from_uri(uri)
diagnostics = output_to_diagnostics(
run_coala_with_specific_file(self.root_path, path))
self.send_diagnostics(path, diagnostics)
# TODO: Support did_change and did_change_watched_files.
# def serve_change(self, request):
# '""Serve for the request of documentation changed.""'
# params = request['params']
# uri = params['textDocument']['uri']
# path = path_from_uri(uri)
# diagnostics = output_to_diagnostics(
# run_coala_with_specific_file(self.root_path, path))
# self.send_diagnostics(path, diagnostics)
# return None
#
# def serve_did_change_watched_files(self, request):
# '""Serve for thr workspace/didChangeWatchedFiles request.""'
# changes = request['changes']
# for fileEvent in changes:
# uri = fileEvent['uri']
# path = path_from_uri(uri)
# diagnostics = output_to_diagnostics(
# run_coala_with_specific_file(self.root_path, path))
# self.send_diagnostics(path, diagnostics)

def send_diagnostics(self, path, diagnostics):
_diagnostics = []
if diagnostics is not None:
_diagnostics = diagnostics
params = {
"uri": "file://{0}".format(path),
"diagnostics": _diagnostics,
'uri': 'file://{0}'.format(path),
'diagnostics': _diagnostics,
}
self.send_notification("textDocument/publishDiagnostics", params)
self.send_notification('textDocument/publishDiagnostics', params)


def main():
parser = argparse.ArgumentParser(description="")
parser.add_argument("--mode", default="stdio",
help="communication (stdio|tcp)")
parser.add_argument("--addr", default=2087,
help="server listen (tcp)", type=int)
parser = argparse.ArgumentParser(description='')
parser.add_argument('--mode', default='stdio',
help='communication (stdio|tcp)')
parser.add_argument('--addr', default=2087,
help='server listen (tcp)', type=int)

args = parser.parse_args()

if args.mode == "stdio":
log("Reading on stdin, writing on stdout")
if args.mode == 'stdio':
log('Reading on stdin, writing on stdout')
s = LangServer(conn=ReadWriter(sys.stdin, sys.stdout))
s.listen()
elif args.mode == "tcp":
host, addr = "0.0.0.0", args.addr
log("Accepting TCP connections on {}:{}".format(host, addr))
elif args.mode == 'tcp':
host, addr = '0.0.0.0', args.addr
log('Accepting TCP connections on {}:{}'.format(host, addr))
ThreadingTCPServer.allow_reuse_address = True
s = ThreadingTCPServer((host, addr), LangserverTCPTransport)
try:
@@ -132,5 +129,5 @@ def main():
s.shutdown()


if __name__ == "__main__":
if __name__ == '__main__':
main()
7 changes: 4 additions & 3 deletions coala_langserver/uri.py
Original file line number Diff line number Diff line change
@@ -2,12 +2,13 @@


def path_from_uri(uri):
"""Get the path from JSON RPC initialization request."""
if not uri.startswith("file://"):
'""Get the path from JSON RPC initialization request.""'
if not uri.startswith('file://'):
return uri
_, path = uri.split("file://", 1)
_, path = uri.split('file://', 1)
return path


def dir_from_uri(uri):
'""Get the directory name from the path.""'
return os.path.dirname(path_from_uri(uri))
3 changes: 2 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
coala>=0.10.0.dev20170122051037
coala>=0.10.0.dev20170213201648
typing>=3.5.3.0
coala-bears>=0.10.0.dev20170215041744
1 change: 1 addition & 0 deletions tests/resources/qualified.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
print('Hello, World.')
2 changes: 2 additions & 0 deletions tests/resources/unqualified.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
def test():
a = 1
14 changes: 14 additions & 0 deletions tests/server.features/coalashim.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
Feature: coalashim module
coalashim is a module of language-server, it interacts with coala core.

Scenario: Test run_coala_with_specific_file
Given the current directory and path of qualified.py
When I pass the qualified.py to run_coala_with_specific_file
Then it should return output in json format
And with no error in the output

Scenario: Test run_coala_with_specific_file
Given the current directory and path of unqualified.py
When I pass the unqualified.py to run_coala_with_specific_file
Then it should return output in json format
And with autopep8 errors in the output
7 changes: 7 additions & 0 deletions tests/server.features/diagnostic.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Feature: diagnostic module
diagnostic is a module of language-server.

Scenario: Test output_to_diagnostics
Given the output with errors by coala
When I pass the parameters to output_to_diagnostics
Then it should return output in vscode format
38 changes: 38 additions & 0 deletions tests/server.features/jsonrpc.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
Feature: jsonrpc module
jsonrpc is a module of language-server.

Scenario: Test ReadWriter
Given the string
When I write it to ReadWriter
Then it should read from ReadWriter

Scenario: Test ReadWriter
Given the string
When I write it to ReadWriter
Then it should readline from ReadWriter

Scenario: Test TCPReadWriter
Given the string
When I write it to TCPReadWriter
Then it should read from TCPReadWriter

Scenario: Test TCPReadWriter
Given the string
When I write it to TCPReadWriter
Then it should readline from TCPReadWriter

Scenario: Test send_notification and read_message
Given the JSONRPC2Connection instance
When I write a notification to the JSONRPC2Connection
Then it should return the notification from JSONRPC2Connection

Scenario: Test write_response
Given the JSONRPC2Connection instance
When I write a response to the JSONRPC2Connection
Then it should return the response from JSONRPC2Connection

# TODO: block until we have generantee the unique request.
# Scenario: Test send_request
# Given the JSONRPC2Connection instance
# When I write a request to the JSONRPC2Connection with id
# Then it should return the request from JSONRPC2Connection with id
13 changes: 13 additions & 0 deletions tests/server.features/langserver.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
Feature: langserver module
langserver is the main program of language-server.

Scenario: Test serve_initialize
Given the LangServer instance
When I send a initialize request to the server
Then it should return the response with textDocumentSync

# TODO: Add positive test case.
Scenario: Test serve_did_save
Given the LangServer instance
When I send a did_save request about a non-existed file to the server
Then it should send a publishDiagnostics request
7 changes: 7 additions & 0 deletions tests/server.features/log.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Feature: log module
log is a module of language-server.

Scenario: Test log
Given There is a string
When I pass the string to log
Then it should return normally
61 changes: 61 additions & 0 deletions tests/server.features/steps/coalashim_steps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# -*- coding: UTF-8 -*-

# @mark.steps
# ----------------------------------------------------------------------------
# STEPS:
# ----------------------------------------------------------------------------
import os
import json
from behave import given, when, then
from coala_langserver.coalashim import run_coala_with_specific_file


@given('the current directory and path of qualified.py')
def step_impl(context):
context.dir = os.path.abspath(
os.path.join(
os.path.dirname(os.path.abspath(__file__)),
os.pardir,
os.pardir,
os.pardir
)
)
context.path = os.path.join(context.dir, 'tests', 'resources', 'qualified.py')


@when('I pass the qualified.py to run_coala_with_specific_file')
def step_impl(context):
context.output = run_coala_with_specific_file(context.dir, context.path)


@then('it should return output in json format')
def step_impl(context):
assert context.failed is False


@then('with no error in the output')
def step_impl(context):
assert context.output is None


@given('the current directory and path of unqualified.py')
def step_impl(context):
context.dir = os.path.abspath(
os.path.join(
os.path.dirname(os.path.abspath(__file__)),
os.pardir,
os.pardir,
os.pardir
)
)
context.path = os.path.join(context.dir, 'tests', 'resources', 'unqualified.py')


@when('I pass the unqualified.py to run_coala_with_specific_file')
def step_impl(context):
context.output = run_coala_with_specific_file(context.dir, context.path)


@then('with autopep8 errors in the output')
def step_impl(context):
assert json.loads(context.output)['results']['autopep8'] is not None
35 changes: 35 additions & 0 deletions tests/server.features/steps/diagnostic_steps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# -*- coding: UTF-8 -*-

# @mark.steps
# ----------------------------------------------------------------------------
# STEPS:
# ----------------------------------------------------------------------------
import os
from behave import given, when, then
from coala_langserver.diagnostic import output_to_diagnostics
from coala_langserver.coalashim import run_coala_with_specific_file


@given('the output with errors by coala')
def step_impl(context):
context.dir = os.path.abspath(
os.path.join(
os.path.dirname(os.path.abspath(__file__)),
os.pardir,
os.pardir,
'resources'
)
)
context.path = os.path.join(context.dir, 'unqualified.py')

context.output = run_coala_with_specific_file(context.dir, context.path)


@when('I pass the parameters to output_to_diagnostics')
def step_impl(context):
context.message = output_to_diagnostics(context.output)


@then('it should return output in vscode format')
def step_impl(context):
assert len(context.message) is not 0
107 changes: 107 additions & 0 deletions tests/server.features/steps/jsonrpc_steps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
# -*- coding: UTF-8 -*-

# @mark.steps
# ----------------------------------------------------------------------------
# STEPS:
# ----------------------------------------------------------------------------
import tempfile
import json
from behave import given, when, then
from coala_langserver.jsonrpc import ReadWriter, TCPReadWriter, JSONRPC2Connection


@given('the string')
def step_impl(context):
context.str = 'test-cases'


@when('I write it to ReadWriter')
def step_impl(context):
context.f = tempfile.TemporaryFile(mode='w+')
context.readWriter = ReadWriter(context.f, context.f)
context.readWriter.write(context.str)


@then('it should read from ReadWriter')
def step_impl(context):
context.f.seek(0)
assert context.readWriter.read(len(context.str)) is not ''
context.f.close()


@then('it should readline from ReadWriter')
def step_impl(context):
context.f.seek(0)
assert context.readWriter.readline() is not ''
context.f.close()


@when('I write it to TCPReadWriter')
def step_impl(context):
context.f = tempfile.TemporaryFile()
context.readWriter = TCPReadWriter(context.f, context.f)
context.readWriter.write(context.str)


@then('it should read from TCPReadWriter')
def step_impl(context):
context.f.seek(0)
assert context.readWriter.read(len(context.str)) is not ''
context.f.close()


@then('it should readline from TCPReadWriter')
def step_impl(context):
context.f.seek(0)
assert context.readWriter.readline() is not ''
context.f.close()


@given('the JSONRPC2Connection instance')
def step_impl(context):
context.f = tempfile.TemporaryFile()
context.jsonConn = JSONRPC2Connection(conn=TCPReadWriter(context.f, context.f))


@when('I write a request to the JSONRPC2Connection with id')
def step_impl(context):
context.jsonConn.send_request('mockMethod', {
'mock': 'mock'
})


@then('it should return the request from JSONRPC2Connection with id')
def step_impl(context):
context.f.seek(0)
assert context.jsonConn.read_message() is not None
context.f.close()


@when('I write a notification to the JSONRPC2Connection')
def step_impl(context):
context.jsonConn.send_notification('mockMethod', {
'mock': 'mock'
})


@then('it should return the notification from JSONRPC2Connection')
def step_impl(context):
context.f.seek(0)
assert context.jsonConn.read_message() is not None
context.f.close()


@when('I write a response to the JSONRPC2Connection')
def step_impl(context):
# BUG: when id = 0
context.ID = 1
context.jsonConn.write_response(context.ID, {
'mock': 'mock'
})


@then('it should return the response from JSONRPC2Connection')
def step_impl(context):
context.f.seek(0)
assert context.jsonConn.read_message(context.ID) is not None
context.f.close()
63 changes: 63 additions & 0 deletions tests/server.features/steps/langserver_steps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# -*- coding: UTF-8 -*-

# @mark.steps
# ----------------------------------------------------------------------------
# STEPS:
# ----------------------------------------------------------------------------
import tempfile
from behave import given, when, then
from coala_langserver.jsonrpc import TCPReadWriter
from coala_langserver.langserver import LangServer


@given('the LangServer instance')
def step_impl(context):
context.f = tempfile.TemporaryFile()
context.langServer = LangServer(conn=TCPReadWriter(context.f, context.f))


@when('I send a initialize request to the server')
def step_impl(context):
request = {
'method': 'initialize',
'params': {
'rootPath': '/Users/mock-user/mock-dir',
'capabilities': {},
},
'id': 1,
'jsonrpc': '2.0'
}
context.langServer.handle(1, request)


@then('it should return the response with textDocumentSync')
def step_impl(context):
context.f.seek(0)
response = context.langServer.read_message(1)
assert response is not None
assert response['result']['capabilities']['textDocumentSync'] is 1
context.f.close()


@when('I send a did_save request about a non-existed file to the server')
def step_impl(context):
request = {
'method': 'textDocument/didSave',
'params': {
'textDocument': {
'uri': 'file:///Users/mock-user/non-exist.py'
}
},
'jsonrpc': '2.0'
}
context.langServer.handle(None, request)


@then('it should send a publishDiagnostics request')
def step_impl(context):
context.f.seek(0)
response = context.langServer.read_message()
assert response is not None
assert response['method'] == 'textDocument/publishDiagnostics'
assert len(response['params']['diagnostics']) is 0
context.f.close()
23 changes: 23 additions & 0 deletions tests/server.features/steps/log_steps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# -*- coding: UTF-8 -*-

# @mark.steps
# ----------------------------------------------------------------------------
# STEPS:
# ----------------------------------------------------------------------------
from behave import given, when, then
from coala_langserver.log import log


@given('There is a string')
def step_impl(context):
context.str = 'file://Users'


@when('I pass the string to log')
def step_impl(context):
log(context.str)


@then('it should return normally')
def step_impl(context):
assert context.failed is False
45 changes: 45 additions & 0 deletions tests/server.features/steps/uri_steps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# -*- coding: UTF-8 -*-

# @mark.steps
# ----------------------------------------------------------------------------
# STEPS:
# ----------------------------------------------------------------------------
from behave import given, when, then
from coala_langserver.uri import path_from_uri, dir_from_uri


@given('There is a string with "file://"')
def step_impl(context):
context.str = 'file://Users'


@when('I pass the string with the prefix to path_from_uri')
def step_impl(context):
context.path = path_from_uri(context.str)


@given('There is a string without "file://"')
def step_impl(context):
context.str = '/Users'


@when('I pass the string without the prefix to path_from_uri')
def step_impl(context):
context.path = path_from_uri(context.str)


@then('it should return a string without "file://"')
def step_impl(context):
assert context.failed is False
assert 'file://' not in context.path


@when('I pass the string to dir_from_uri')
def step_impl(context):
context.path = dir_from_uri(context.str)


@then('it should return the directory of the path')
def step_impl(context):
assert context.failed is False
assert context.path is '/'
17 changes: 17 additions & 0 deletions tests/server.features/uri.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
Feature: uri module
uri is a module of language-server.

Scenario: Test path_from_uri
Given There is a string with "file://"
When I pass the string with the prefix to path_from_uri
Then it should return a string without "file://"

Scenario: Test path_from_uri
Given There is a string without "file://"
When I pass the string without the prefix to path_from_uri
Then it should return a string without "file://"

Scenario: Test dir_from_uri
Given There is a string without "file://"
When I pass the string to dir_from_uri
Then it should return the directory of the path
4 changes: 3 additions & 1 deletion vscode-client/.gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
out
server
node_modules
.vscode-dev
.vscode-dev
.vscode-test

8 changes: 5 additions & 3 deletions vscode-client/package.json
Original file line number Diff line number Diff line change
@@ -20,13 +20,15 @@
"vscode:prepublish": "cp -r ../coala-langserver.sh ../coala-langserver.py ../coala_langserver ./out && node ./node_modules/vscode/bin/compile",
"compile": "python3 ../setup.py install && node ./node_modules/vscode/bin/compile -watch -p ./",
"postinstall": "node ./node_modules/vscode/bin/install",
"vscode": "npm run vscode:prepublish && VSCODE=$(which code-insiders || which code || echo echo ERROR: neither the code nor code-insiders vscode executable is installed); USER=dummy-dont-share-vscode-instance $VSCODE --user-data-dir=$PWD/.vscode-dev/user-data --extensionHomePath=$PWD/.vscode-dev/extensions --extensionDevelopmentPath=$PWD $*"
"vscode": "npm run vscode:prepublish && VSCODE=$(which code-insiders || which code || echo echo ERROR: neither the code nor code-insiders vscode executable is installed); USER=dummy-dont-share-vscode-instance $VSCODE --user-data-dir=$PWD/.vscode-dev/user-data --extensionHomePath=$PWD/.vscode-dev/extensions --extensionDevelopmentPath=$PWD $*",
"test": "node ./node_modules/vscode/bin/test"
},
"devDependencies": {
"typescript": "^1.8.9",
"vscode": "^0.11.0"
"vscode": "^0.11.0",
"vsce": "^1.18.0"
},
"dependencies": {
"vscode-languageclient": "^2.4.2-next.12"
}
}
}
17 changes: 17 additions & 0 deletions vscode-client/test/extension.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// The module 'assert' provides assertion methods from node
import * as assert from 'assert';

// You can import and use all API from the 'vscode' module
// as well as import your extension to test it
// import * as vscode from 'vscode';
// import * as myExtension from '../extension';

// Defines a Mocha test suite to group tests of similar kind together
suite('Extension Tests', () => {

// Defines a Mocha unit test
test('Something 1', () => {
assert.equal(-1, [1, 2, 3].indexOf(5));
assert.equal(-1, [1, 2, 3].indexOf(0));
});
});