Skip to content

Commit 9255a19

Browse files
committed
Add a test for sourcekit-lsp
1 parent e949519 commit 9255a19

File tree

7 files changed

+187
-0
lines changed

7 files changed

+187
-0
lines changed

lit.cfg

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,11 @@ repl_swift_dummy_path = lit_config.params.get(
187187
"repl_swift",
188188
os.path.join(package_path, "usr", "bin", "repl_swift"))
189189
lit_config.note("testing using 'repl_swift': {}".format(repl_swift_dummy_path))
190+
191+
sourcekit_lsp_path = lit_config.params.get(
192+
"sourcekit-lsp",
193+
os.path.join(package_path, "usr", "bin", "sourcekit-lsp"))
194+
lit_config.note("testing using 'sourcekit-lsp': {}".format(sourcekit_lsp_path))
190195

191196
# Verify they exist.
192197
if not os.path.exists(swift_path):
@@ -204,6 +209,9 @@ if not os.path.exists(repl_swift_dummy_path):
204209
if platform.system() == 'Linux':
205210
lit_config.fatal("repl_swift does not exist!")
206211

212+
if not os.path.exists(sourcekit_lsp_path):
213+
lit_config.fatal("sourcekit-lsp does not exist!")
214+
207215
# Define our supported substitutions.
208216
config.substitutions.append( ('%{package_path}', package_path) )
209217
config.substitutions.append( ('%{python}', sys.executable) )
@@ -215,6 +223,7 @@ config.substitutions.append( ('%{swift}', swift_path) )
215223
config.substitutions.append( ('%{swiftc}', swiftc_path) )
216224
config.substitutions.append( ('%{FileCheck}', filecheck_path) )
217225
config.substitutions.append( ('%{readelf}', readelf_path) )
226+
config.substitutions.append( ('%{sourcekit-lsp}', sourcekit_lsp_path) )
218227

219228
# Add substitutions for swiftpm executables.
220229
swiftpm_build = lit_config.params.get("swiftpm-build")
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// swift-tools-version:5.1
2+
import PackageDescription
3+
4+
let package = Package(
5+
name: "pkg",
6+
targets: [
7+
.target(name: "exec", dependencies: ["lib", "clib"]),
8+
.target(name: "lib", dependencies: []),
9+
.target(name: "clib", dependencies: []),
10+
]
11+
)
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
#include "clib.h"
2+
3+
void clib_func(void) {}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#ifndef CLIB_H
2+
#define CLIB_H
3+
4+
void clib_func(void);
5+
void clib_other(void);
6+
7+
#endif // CLIB_H
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import lib
2+
import clib
3+
4+
Lib().foo()
5+
clib_func()
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
public struct Lib {
2+
public func foo() {}
3+
public init() {}
4+
}
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
# Canary test for sourcekit-lsp, covering interaction with swiftpm and toolchain
2+
# language services.
3+
4+
# Make a sandbox dir.
5+
# RUN: rm -rf %t.dir
6+
# RUN: mkdir -p %t.dir
7+
# RUN: cp -r %S/pkg %t.dir/
8+
9+
# RUN: %{swift-build} --package-path %t.dir/pkg -Xswiftc -index-ignore-system-modules -v 2>&1 | tee %t.build-log
10+
# RUN: %{FileCheck} --check-prefix CHECK-BUILD-LOG --input-file %t.build-log %s
11+
# CHECK-BUILD-LOG-NOT: error:
12+
13+
# RUN: %{python} -u %s %{sourcekit-lsp} %t.dir/pkg 2>&1 | tee %t.run-log
14+
# RUN: %{FileCheck} --input-file %t.run-log %s
15+
16+
import argparse
17+
import json
18+
import os
19+
import subprocess
20+
import sys
21+
22+
class LspScript(object):
23+
def __init__(self):
24+
self.request_id = 0
25+
self.script = ''
26+
27+
def request(self, method, params):
28+
body = json.dumps({
29+
'jsonrpc': '2.0',
30+
'id': self.request_id,
31+
'method': method,
32+
'params': params
33+
})
34+
self.request_id += 1
35+
self.script += 'Content-Length: {}\r\n\r\n{}'.format(len(body), body)
36+
37+
def note(self, method, params):
38+
body = json.dumps({
39+
'jsonrpc': '2.0',
40+
'method': method,
41+
'params': params
42+
})
43+
self.script += 'Content-Length: {}\r\n\r\n{}'.format(len(body), body)
44+
45+
def main():
46+
parser = argparse.ArgumentParser()
47+
parser.add_argument('sourcekit_lsp')
48+
parser.add_argument('package')
49+
args = parser.parse_args()
50+
51+
lsp = LspScript()
52+
lsp.request('initialize', {
53+
'rootPath': args.package,
54+
'capabilities': {},
55+
'initializationOptions': {
56+
'listenToUnitEvents': False,
57+
}
58+
})
59+
60+
main_swift = os.path.join(args.package, 'Sources', 'exec', 'main.swift')
61+
with open(main_swift, 'r') as f:
62+
main_swift_content = f.read()
63+
64+
lsp.note('textDocument/didOpen', {
65+
'textDocument': {
66+
'uri': 'file://' + main_swift,
67+
'languageId': 'swift',
68+
'version': 0,
69+
'text': main_swift_content,
70+
}
71+
})
72+
73+
lsp.request('workspace/_pollIndex', {})
74+
lsp.request('textDocument/definition', {
75+
'textDocument': { 'uri': 'file://' + main_swift },
76+
'position': { 'line': 3, 'character': 6}, ## zero-based
77+
})
78+
79+
# CHECK: "result":[
80+
# CHECK-DAG: lib.swift
81+
# CHECK-DAG: "line":1
82+
# CHECK-DAG: "character":14
83+
# CHECK: ]
84+
85+
lsp.request('textDocument/definition', {
86+
'textDocument': { 'uri': 'file://' + main_swift },
87+
'position': { 'line': 4, 'character': 0}, ## zero-based
88+
})
89+
90+
# CHECK: "result":[
91+
# CHECK-DAG: clib.c
92+
# CHECK-DAG: "line":2
93+
# CHECK-DAG: "character":5
94+
# CHECK: ]
95+
96+
lsp.request('textDocument/completion', {
97+
'textDocument': { 'uri': 'file://' + main_swift },
98+
'position': { 'line': 3, 'character': 6}, ## zero-based
99+
})
100+
# CHECK: "items":[
101+
# CHECK-DAG: "label":"foo()"
102+
# CHECK-DAG: "label":"self"
103+
# CHECK: ]
104+
105+
clib_c = os.path.join(args.package, 'Sources', 'clib', 'clib.c')
106+
with open(clib_c, 'r') as f:
107+
clib_c_content = f.read()
108+
109+
lsp.note('textDocument/didOpen', {
110+
'textDocument': {
111+
'uri': 'file://' + clib_c,
112+
'languageId': 'c',
113+
'version': 0,
114+
'text': clib_c_content,
115+
}
116+
})
117+
118+
lsp.request('textDocument/completion', {
119+
'textDocument': { 'uri': 'file://' + clib_c },
120+
'position': { 'line': 2, 'character': 22}, ## zero-based
121+
})
122+
# CHECK: "items":[
123+
# FIXME: Extra space?
124+
# CHECK-DAG: "label":" clib_func()"
125+
# CHECK-DAG: "label":" clib_other()"
126+
# CHECK: ]
127+
128+
lsp.request('shutdown', {})
129+
lsp.note('exit', {})
130+
131+
print('==== INPUT ====')
132+
print(lsp.script)
133+
print('')
134+
print('==== OUTPUT ====')
135+
136+
p = subprocess.Popen([args.sourcekit_lsp, '--sync'], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
137+
out, _ = p.communicate(lsp.script)
138+
print(out)
139+
print('')
140+
141+
if p.returncode == 0:
142+
print('OK')
143+
else:
144+
print('error: sourcekit-lsp exited with code {}'.format(exitcode))
145+
# CHECK: OK
146+
147+
if __name__ == "__main__":
148+
main()

0 commit comments

Comments
 (0)