aboutsummaryrefslogtreecommitdiff
path: root/tests/drivers/core_lsp_test.js
diff options
context:
space:
mode:
authorGravatar Moon Flower <moonflower@elhenney.local> 2026-10-12 08:46:23 +0330
committerGravatar Moon Flower <moonflower@elhenney.local> 2026-10-12 08:46:23 +0330
commitecc350ca5c2eb50be8309c5f14f8bf0d87db9a02 (patch)
tree70e0af76a1b13affff7c6cc8aac7b3e6ef960478 /tests/drivers/core_lsp_test.js
a
Diffstat (limited to 'tests/drivers/core_lsp_test.js')
-rw-r--r--tests/drivers/core_lsp_test.js43
1 files changed, 43 insertions, 0 deletions
diff --git a/tests/drivers/core_lsp_test.js b/tests/drivers/core_lsp_test.js
new file mode 100644
index 0000000..41d0095
--- /dev/null
+++ b/tests/drivers/core_lsp_test.js
@@ -0,0 +1,43 @@
+// check maintained zc sources through the editor document protocol, one file at a time.
+const assert = require('assert');
+const fs = require('fs');
+const cp = require('child_process');
+const path = require('path');
+const target = process.argv[2];
+const files = ['src/runtime/rt.zc', 'src/compiler/compiler.zc', 'src/runtime/run.zc', 'src/lib/std.zc', 'src/lsp/server.zc', 'src/tools/build.zc'];
+const frame = message => {
+ const body = Buffer.from(JSON.stringify(message));
+ return Buffer.concat([Buffer.from('Content-Length: ' + body.length + '\r\n\r\n'), body]);
+};
+for (const file of files) {
+ const uri = 'file://' + path.resolve(file);
+ const text = fs.readFileSync(file, 'utf8');
+ const messages = [
+ { jsonrpc: '2.0', id: 1, method: 'initialize', params: {} },
+ { jsonrpc: '2.0', method: 'initialized', params: {} },
+ { jsonrpc: '2.0', method: 'textDocument/didOpen', params: { textDocument: { uri, version: 1, languageId: 'zc', text } } },
+ { jsonrpc: '2.0', id: 2, method: 'textDocument/semanticTokens/full', params: { textDocument: { uri } } },
+ { jsonrpc: '2.0', method: 'textDocument/didChange', params: { textDocument: { uri, version: 2 }, contentChanges: [{ text: text + '\n' }] } },
+ { jsonrpc: '2.0', method: 'textDocument/didClose', params: { textDocument: { uri } } },
+ { jsonrpc: '2.0', id: 3, method: 'shutdown', params: null },
+ { jsonrpc: '2.0', method: 'exit' },
+ ];
+ const result = cp.spawnSync(target, [], { input: Buffer.concat(messages.map(frame)), timeout: 30000, maxBuffer: 32 << 20 });
+ assert.strictEqual(result.status, 0, file + ': ' + result.stderr);
+ let data = result.stdout;
+ const replies = [];
+ while (data.length) {
+ const end = data.indexOf('\r\n\r\n');
+ assert.ok(end >= 0, 'complete protocol header');
+ const length = Number(/Content-Length:\s*(\d+)/i.exec(data.subarray(0, end).toString())[1]);
+ replies.push(JSON.parse(data.subarray(end + 4, end + 4 + length)));
+ data = data.subarray(end + 4 + length);
+ }
+ const diagnostics = replies.filter(m => m.method === 'textDocument/publishDiagnostics');
+ assert.strictEqual(diagnostics.length, 3, file + ': open, change, and close publish diagnostics');
+ const errors = diagnostics.flatMap(m => m.params.diagnostics).filter(d => d.severity === 1);
+ assert.deepStrictEqual(errors, [], file + ': ' + errors.map(d => (d.range.start.line + 1) + ': ' + d.message).join('\n'));
+ assert.ok(replies.find(m => m.id === 2).result.data.length, file + ': semantic tokens are available');
+ assert.deepStrictEqual(diagnostics[2].params.diagnostics, [], 'close clears diagnostics');
+ console.log('ok editor open, highlight, change, and close: ' + file);
+}