summaryrefslogtreecommitdiffhomepage
path: root/packages/core/tests/fixture
diff options
context:
space:
mode:
authorAdam Malczewski <[email protected]>2026-06-02 21:10:09 +0900
committerAdam Malczewski <[email protected]>2026-06-02 21:10:09 +0900
commitd9f53727845dface3e6d8a84ba2270b1de55482b (patch)
tree6d42f0a0fbda15057296992e78c4b4e12046f9ed /packages/core/tests/fixture
parent80212bfb009eaf71a4743310dee6ed08b8f7e1da (diff)
parent9d8cf7005ba4c0bb8ade0775f54c2557aa1c5683 (diff)
downloaddispatch-d9f53727845dface3e6d8a84ba2270b1de55482b.tar.gz
dispatch-d9f53727845dface3e6d8a84ba2270b1de55482b.zip
Merge branch 'dev' into feat/cs-code-search-tool
# Conflicts: # packages/api/src/agent-manager.ts # packages/api/tests/agent-manager.test.ts # packages/frontend/src/lib/components/ToolPermissions.svelte # packages/frontend/src/lib/settings.svelte.ts
Diffstat (limited to 'packages/core/tests/fixture')
-rw-r--r--packages/core/tests/fixture/lsp/fake-lsp-server.js195
1 files changed, 195 insertions, 0 deletions
diff --git a/packages/core/tests/fixture/lsp/fake-lsp-server.js b/packages/core/tests/fixture/lsp/fake-lsp-server.js
new file mode 100644
index 0000000..d771ebd
--- /dev/null
+++ b/packages/core/tests/fixture/lsp/fake-lsp-server.js
@@ -0,0 +1,195 @@
+// Minimal JSON-RPC 2.0 LSP-like fake server over stdio, for testing the LSP
+// client without a real language server binary. Ported from opencode's
+// test/fixture/lsp/fake-lsp-server.js (trimmed to what dispatch's client and
+// manager exercise: initialize, didOpen/didChange, push + pull diagnostics).
+//
+// Test hooks (custom JSON-RPC methods the test driver can call):
+// test/get-initialize-params → returns the params sent to `initialize`
+// test/get-last-change → returns the last `didChange` params
+// test/publish-diagnostics → forwards a `publishDiagnostics` push
+// test/configure-pull-diagnostics → sets up pull-diagnostic responses
+// test/get-diagnostic-request-count→ how many pull requests were received
+
+let nextId = 1;
+let readBuffer = Buffer.alloc(0);
+let lastChange = null;
+let initializeParams = null;
+let diagnosticRequestCount = 0;
+let registeredCapability = false;
+let pullConfig = {
+ registerOn: undefined,
+ registrations: [],
+ documentDiagnostics: [],
+ workspaceDiagnostics: [],
+ hasDiagnosticProvider: false,
+};
+
+function encode(message) {
+ const json = JSON.stringify(message);
+ const header = `Content-Length: ${Buffer.byteLength(json, "utf8")}\r\n\r\n`;
+ return Buffer.concat([Buffer.from(header, "utf8"), Buffer.from(json, "utf8")]);
+}
+
+function decodeFrames(buffer) {
+ const results = [];
+ while (true) {
+ const idx = buffer.indexOf("\r\n\r\n");
+ if (idx === -1) break;
+ const header = buffer.slice(0, idx).toString("utf8");
+ const match = /Content-Length:\s*(\d+)/i.exec(header);
+ const length = match ? parseInt(match[1], 10) : 0;
+ const bodyStart = idx + 4;
+ const bodyEnd = bodyStart + length;
+ if (buffer.length < bodyEnd) break;
+ results.push(buffer.slice(bodyStart, bodyEnd).toString("utf8"));
+ buffer = buffer.slice(bodyEnd);
+ }
+ return { messages: results, rest: buffer };
+}
+
+function send(message) {
+ process.stdout.write(encode(message));
+}
+function sendRequest(method, params) {
+ const id = nextId++;
+ send({ jsonrpc: "2.0", id, method, params });
+ return id;
+}
+function sendResponse(id, result) {
+ send({ jsonrpc: "2.0", id, result });
+}
+function sendNotification(method, params) {
+ send({ jsonrpc: "2.0", method, params });
+}
+
+function maybeRegister(method) {
+ if (pullConfig.registerOn !== method || registeredCapability) return;
+ registeredCapability = true;
+ sendRequest("client/registerCapability", {
+ registrations: pullConfig.registrations.map((registration, index) => ({
+ id: registration.id ?? `pull-${index}`,
+ method: registration.method ?? "textDocument/diagnostic",
+ registerOptions: registration.registerOptions ?? registration,
+ })),
+ });
+}
+
+function handle(raw) {
+ let data;
+ try {
+ data = JSON.parse(raw);
+ } catch {
+ return;
+ }
+
+ if (data.method === "initialize") {
+ initializeParams = data.params;
+ sendResponse(data.id, {
+ capabilities: {
+ textDocumentSync: { change: 2, openClose: true },
+ ...(pullConfig.hasDiagnosticProvider
+ ? {
+ diagnosticProvider: {
+ identifier: "fake",
+ interFileDependencies: false,
+ workspaceDiagnostics: false,
+ },
+ }
+ : {}),
+ },
+ });
+ return;
+ }
+
+ if (data.method === "test/get-initialize-params") {
+ sendResponse(data.id, initializeParams);
+ return;
+ }
+
+ if (data.method === "initialized" || data.method === "workspace/didChangeConfiguration") {
+ return;
+ }
+
+ if (data.method === "textDocument/didOpen") {
+ maybeRegister("didOpen");
+ return;
+ }
+
+ if (data.method === "textDocument/didChange") {
+ lastChange = data.params;
+ maybeRegister("didChange");
+ return;
+ }
+
+ if (data.method === "workspace/didChangeWatchedFiles") {
+ return;
+ }
+
+ if (data.method === "test/configure-pull-diagnostics") {
+ pullConfig = {
+ registerOn: data.params?.registerOn,
+ registrations: data.params?.registrations ?? [],
+ documentDiagnostics: data.params?.documentDiagnostics ?? [],
+ workspaceDiagnostics: data.params?.workspaceDiagnostics ?? [],
+ hasDiagnosticProvider: data.params?.hasDiagnosticProvider ?? false,
+ };
+ registeredCapability = false;
+ sendResponse(data.id, null);
+ return;
+ }
+
+ if (data.method === "test/publish-diagnostics") {
+ sendNotification("textDocument/publishDiagnostics", data.params);
+ sendResponse(data.id, null);
+ return;
+ }
+
+ if (data.method === "test/get-last-change") {
+ sendResponse(data.id, lastChange);
+ return;
+ }
+
+ if (data.method === "test/get-diagnostic-request-count") {
+ sendResponse(data.id, diagnosticRequestCount);
+ return;
+ }
+
+ if (data.method === "textDocument/diagnostic") {
+ diagnosticRequestCount += 1;
+ sendResponse(data.id, { kind: "full", items: pullConfig.documentDiagnostics });
+ return;
+ }
+
+ if (data.method === "workspace/diagnostic") {
+ diagnosticRequestCount += 1;
+ sendResponse(data.id, { items: pullConfig.workspaceDiagnostics });
+ return;
+ }
+
+ if (data.method === "textDocument/hover") {
+ sendResponse(data.id, { contents: { kind: "plaintext", value: "fake hover" } });
+ return;
+ }
+
+ if (data.method === "textDocument/definition") {
+ sendResponse(data.id, [
+ {
+ uri: data.params?.textDocument?.uri,
+ range: { start: { line: 0, character: 0 }, end: { line: 0, character: 1 } },
+ },
+ ]);
+ return;
+ }
+
+ // Default: respond null to any other request so the client never hangs.
+ if (typeof data.id !== "undefined") {
+ sendResponse(data.id, null);
+ }
+}
+
+process.stdin.on("data", (chunk) => {
+ readBuffer = Buffer.concat([readBuffer, chunk]);
+ const { messages, rest } = decodeFrames(readBuffer);
+ readBuffer = rest;
+ for (const message of messages) handle(message);
+});