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);
}
|