// focused regressions for growing document, uri, hover, and name-set storage. // usage: node tests/drivers/lsp_growth_test.js path/to/zclsp-or-lsp.wasm // interpreted hosts (no jit) are far slower; ZC_TEST_TIMEOUT_SCALE stretches every deadline const TIMEOUT_SCALE = Number(process.env.ZC_TEST_TIMEOUT_SCALE) || 1; const assert = require('assert'); const cp = require('child_process'); const { wasmProcess } = require('../../editors/vscode/client/wasmproc'); const target = process.argv[2]; const frame = m => { const body = Buffer.from(JSON.stringify(m)); return Buffer.concat([Buffer.from('Content-Length: ' + body.length + '\r\n\r\n'), body]); }; function parse(input) { const messages = []; for (let offset = 0; offset < input.length;) { const end = input.indexOf('\r\n\r\n', offset); assert.ok(end >= 0, 'complete response header'); const length = Number(/Content-Length:\s*(\d+)/i.exec(input.subarray(offset, end).toString())[1]); const start = end + 4; assert.ok(start + length <= input.length, 'complete response body'); messages.push(JSON.parse(input.subarray(start, start + length).toString())); offset = start + length; } return messages; } const uri = 'file:///' + 'long-directory/'.repeat(30) + 'main.zc'; const docs = '// **formatted** documentation with `inline code`.\n' + ('// a long paragraph of documentation.\n').repeat(150) + '// final documentation line\n'; const source = docs + 'int helper() { return 1; }\nfn main() { return helper(); }\n'; const messages = [{ jsonrpc: '2.0', id: 1, method: 'initialize', params: {} }]; for (let i = 0; i < 32; i++) messages.push({ jsonrpc: '2.0', method: 'textDocument/didOpen', params: { textDocument: { uri: i === 31 ? uri : 'file:///doc' + i + '.zc', languageId: 'zc', version: 1, text: source } } }); messages.push({ jsonrpc: '2.0', id: 2, method: 'textDocument/hover', params: { textDocument: { uri }, position: { line: source.split('\n').length - 2, character: 19 } } }); messages.push({ jsonrpc: '2.0', method: 'exit' }); let output; if (target.endsWith('.wasm')) { const chunks = []; const server = wasmProcess(target); server.stdout.on('data', data => chunks.push(data)); for (const message of messages) assert.ok(server.stdin.write(frame(message))); output = Buffer.concat(chunks); } else { const result = cp.spawnSync(target, [], { input: Buffer.concat(messages.map(frame)), timeout: 30000 * TIMEOUT_SCALE, maxBuffer: 8 << 20 }); assert.strictEqual(result.status, 0, String(result.stderr)); output = result.stdout; } const responses = parse(output); const published = responses.filter(m => m.method === 'textDocument/publishDiagnostics'); assert.strictEqual(published.length, 32, 'every open document is published'); assert.strictEqual(published[31].params.uri, uri, 'a long uri is echoed without truncation'); assert.ok(published.every(m => !m.params.diagnostics.some(d => d.severity === 1)), 'all documents check cleanly'); const hover = responses.find(m => m.id === 2).result.contents; assert.strictEqual(hover.kind, 'markdown'); assert.match(hover.value, /^```zc\nint helper\(\)\n```\n\n/); assert.ok(hover.value.includes('**formatted**')); assert.ok(hover.value.includes('final documentation line'), 'hover documentation grows past its initial buffer'); console.log('ok lsp grows beyond 16 documents, 160 uri bytes, and 2300 hover characters');