Skip to content

Commit a5847c9

Browse files
committed
Add comprehensive ULSP test suite
Add a complete test suite for the Unicon Language Server Protocol (ULSP) implementation with four main test categories: 1. JSON-RPC Tests (jsonrpc_test.icn) - Tests JSON-RPC protocol with calculator server - Validates concurrent request handling - Tests basic arithmetic operations 2. LSP Message Tests (lsp_message_test.icn) - Tests JSON-RPC message parsing and validation - Tests all LSP request/response message types - Tests notification handling - Tests error handling and malformed message rejection 3. LSP Feature Tests (lsp_feature_test.icn) - Tests LSP features with realistic Unicon code - Tests completion, hover, definition, symbols, formatting, folding - Tests signature help functionality - Uses LSPDB for symbol information 4. LSP Protocol Tests (lsp_protocol_test.icn) - Integration tests with actual server-client communication - Tests server initialization and capability negotiation - Tests document synchronization (didOpen, didChange, didSave) - Tests end-to-end LSP feature workflows Unified Test Runner (lsp_run_tests.icn): - Executes all four test suites sequentially - Aggregates test counts from all suites - Provides comprehensive test reporting - Supports individual test suite execution Test Framework Features: - Expected result capture mode with JSON output - Deep comparison for expected vs actual results - JSON-formatted error reporting - Consistent test structure across all test files - Proper Unicon success/failure semantics Makefile Integration: - Individual test targets for each test suite - Unified test runner target - Clean targets for test artifacts All test files follow consistent structure: - Package declaration (ulsptests) - Test class with run_all_tests() method - Global counters for test tracking - Standalone execution support via $ifdef STANDALONE
1 parent f978fb3 commit a5847c9

File tree

8 files changed

+2575
-111
lines changed

8 files changed

+2575
-111
lines changed

uni/ulsp/LSP_TESTING.md

Lines changed: 436 additions & 0 deletions
Large diffs are not rendered by default.

uni/ulsp/Makefile

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,6 @@ $(prog): $(OBJ)
1919
$(UC) -o $(prog) $(OBJ)
2020
$(CP) $(prog)$(EXE) ../../bin
2121

22-
jsonrpc-test: jsonrpc-test.u
23-
$(UC) -o jsonrpc-test jsonrpc-test.u
24-
2522
launch-lsp.u:launch-lsp.icn file_handler.u database.u server.u completion.u signature.u hover.u \
2623
definition.u symbols.u folding.u formatting.u
2724

@@ -30,8 +27,46 @@ server.u:server.icn database.u completion.u file_handler.u signature.u hover.u d
3027
hover.u:hover.icn signature.u
3128
definition.u: definition.icn hover.u
3229

30+
31+
jsonrpc_test: jsonrpc_test.u
32+
$(UC) -DSTANDALONE jsonrpc_test.icn
33+
34+
lsp_protocol_test: lsp_protocol_test.u
35+
$(UC) -DSTANDALONE lsp_protocol_test.icn
36+
37+
lsp_feature_test: lsp_feature_test.u
38+
$(UC) -DSTANDALONE lsp_feature_test.icn
39+
40+
lsp_message_test: lsp_message_test.u
41+
$(UC) -DSTANDALONE lsp_message_test.icn
42+
43+
lsp_run_tests.u: lsp_message_test.u lsp_feature_test.u lsp_protocol_test.u jsonrpc_test.u
44+
45+
lsp_run_tests: lsp_run_tests.u
46+
$(UC) -o lsp_run_tests lsp_run_tests.u lsp_message_test.u lsp_feature_test.u lsp_protocol_test.u jsonrpc_test.u
47+
48+
test: lsp_run_tests
49+
@echo "Running LSP Integration tests..."
50+
./lsp_run_tests
51+
52+
test-lsp: lsp_protocol_test lsp_feature_test lsp_message_test jsonrpc_test
53+
@echo "Running JSON-RPC tests..."
54+
./jsonrpc_test
55+
@echo ""
56+
@echo "Running LSP message tests..."
57+
./lsp_message_test
58+
@echo ""
59+
@echo "Running LSP feature tests..."
60+
./lsp_feature_test
61+
@echo ""
62+
@echo "Running LSP protocol tests..."
63+
./lsp_protocol_test
64+
3365
zip:
3466
zip ulsp.zip Makefile *.icn
3567

68+
clean-tests:
69+
$(RM) -f lsp_*_test.u lsp_*_test lsp_run_tests lsp_run_tests.u jsonrpc_test.u jsonrpc_test
70+
3671
clean:
3772
$(RM) -f *.u $(prog) uniclass*

uni/ulsp/jsonrpc-test.icn

Lines changed: 0 additions & 108 deletions
This file was deleted.

uni/ulsp/jsonrpc_test.icn

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
#
2+
# JSON-RPC Test Suite
3+
# Tests JSON-RPC protocol with a calculator server
4+
#
5+
6+
import ulsp
7+
import json
8+
9+
global work_items
10+
global jsonrpc_test_count, jsonrpc_pass_count, jsonrpc_fail_count
11+
12+
#############################
13+
# JRPC server Calculator
14+
#############################
15+
class JRPC_Calc(jrpc_server)
16+
17+
method start(addr)
18+
local sock, msg
19+
if not (jrpc_server := JRPC_HTTPSocket(addr,"n")) then
20+
write("server open(",addr,") ERROR: ", \&errortext | "Unknown") & fail
21+
22+
repeat {
23+
msg := jrpc_server.get_msg() | next
24+
case msg.get_kind() of {
25+
"request" : thread handle_request(msg)
26+
default:
27+
write("jrpc:msg: " || msg.get_kind(), image(msg.get_content()))
28+
}
29+
}
30+
end
31+
32+
method handle_request(msg)
33+
local id := msg.get_id(),
34+
x := integer(msg.get_params()[1]),
35+
y := integer(msg.get_params()[2])
36+
37+
# uncomment to trigger some test failures
38+
#if x = 9 then fail
39+
case msg.get_method() of {
40+
"+" : {jrpc_server.send_msg(msg.make_result_response(x + y))}
41+
"-" : jrpc_server.send_msg(msg.make_result_response(x - y))
42+
"*" : jrpc_server.send_msg(msg.make_result_response(x * y))
43+
"/" : jrpc_server.send_msg(msg.make_result_response(x / y))
44+
default: write("jrpc:request:unsupported: ", msg.get_method())
45+
}
46+
47+
end
48+
end
49+
50+
###############################
51+
# client
52+
###############################
53+
class JRPC_client(jrpc_client)
54+
55+
method listen(addr)
56+
if not (jrpc_client := JRPC_HTTPSocket(addr,"na")) then
57+
stop("client open(", addr, ") ERROR: ", \&errortext | "Unknown")
58+
end
59+
60+
method test(op, params, answer)
61+
local id
62+
static idx := 0, mtx := mutex()
63+
critical mtx: id := idx +:=1
64+
jrpc_client.send_msg(JRPC_Message().make_request(id, op, params))
65+
work_items[id] := [op, params, answer]
66+
end
67+
68+
method start()
69+
local x := ?9, y := ?8+1
70+
test("+", [x, y], x+y)
71+
test("-", [x, y], x-y)
72+
test("*", [x, y], x*y)
73+
test("/", [x, y], x/y)
74+
end
75+
76+
end
77+
78+
class JSONRPCTest()
79+
method run_all_tests()
80+
local calc, client, jobset, addr, id, op, x, y, answer,
81+
workers, i, response, job
82+
83+
jsonrpc_test_count := 0
84+
jsonrpc_pass_count := 0
85+
jsonrpc_fail_count := 0
86+
87+
write("JSON-RPC Test Suite")
88+
write("========================================")
89+
90+
addr := ":" || 5000 + ?1000
91+
if &features == ("MacOS" | "MS Windows NT") then
92+
addr := "127.0.0.1" || addr
93+
94+
client := JRPC_client()
95+
calc := JRPC_Calc()
96+
thread calc.start(addr)
97+
client.listen(addr)
98+
workers:=[]
99+
work_items := mutex(table())
100+
every !4 do put(workers, thread client.start())
101+
every wait(!workers)
102+
jobset:=set()
103+
every insert(jobset, !*work_items)
104+
105+
every i := !(*work_items*2) do {
106+
if *jobset = 0 then break
107+
if response := client.jrpc_client.get_msg(100) then {
108+
delete(jobset, id:=response.get_id())
109+
job := work_items[id]
110+
op:=job[1]; x:=job[2][1]; y:=job[2][2]; answer := job[3]
111+
jsonrpc_test_count +:= 1
112+
if response.get_result() = answer then {
113+
jsonrpc_pass_count +:= 1
114+
write(left(id, 2), ": ", x, " ", op, " ", y, " = ", right(response.get_result(), 3),
115+
" Pass")
116+
} else {
117+
jsonrpc_fail_count +:= 1
118+
write(left(id, 2), ": ", x, " ", op, " ", y, " = ", right(response.get_result(), 3),
119+
" Fail (expected ", answer, ")")
120+
}
121+
}
122+
}
123+
124+
every job := work_items[id:=!jobset] do {
125+
op:=job[1]; x:=job[2][1]; y:=job[2][2]
126+
jsonrpc_test_count +:= 1
127+
jsonrpc_fail_count +:= 1
128+
write(left(id, 2), ": ", x, " ", op, " ", y, " = Failed to get a response")
129+
}
130+
131+
# Print results
132+
write("\n========================================")
133+
write("Test Results:")
134+
write("Total tests: ", jsonrpc_test_count)
135+
write("Passed: ", jsonrpc_pass_count)
136+
write("Failed: ", jsonrpc_fail_count)
137+
if jsonrpc_test_count > 0 then {
138+
write("Success rate: ", real(jsonrpc_pass_count) / real(jsonrpc_test_count) * 100, "%")
139+
}
140+
141+
if jsonrpc_pass_count = jsonrpc_test_count then
142+
return
143+
end
144+
end
145+
146+
$ifdef STANDALONE
147+
procedure main()
148+
local test_suite
149+
150+
test_suite := JSONRPCTest()
151+
if test_suite.run_all_tests() then {
152+
write("✓ All tests passed")
153+
exit(0)
154+
} else {
155+
write("✗ Some tests failed")
156+
exit(1)
157+
}
158+
end
159+
$endif
160+

0 commit comments

Comments
 (0)