aboutsummaryrefslogtreecommitdiff
path: root/tests/drivers/core_lsp_test.js
blob: 983f9aa666da3fc55a5121d16559a9976339e089 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
// 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/core/core.zc', 'src/runtime/rt.zc', 'src/compiler/compiler.zc', 'src/runtime/run.zc', 'src/lib/std.zc', 'src/lib/icon.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', id: 4, method: 'textDocument/semanticTokens/full', params: { textDocument: { uri } } },
        { 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.ok(diagnostics.length >= 3, file + ': open and change are checked before close, with streamed publications allowed');
    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.ok(replies.find(m => m.id === 4).result.data.length, file + ': the changed source also has semantic tokens');
    assert.deepStrictEqual(diagnostics.at(-1).params.diagnostics, [], 'close clears diagnostics');
    console.log('ok   editor open, highlight, change, and close: ' + file);
}