Files
locode/src/tools/codeIntel.test.ts
T
kim c8cc78e8f1 docs+test: document LSP code intelligence; cover the LSP tools
- README.md: list definition/references/diagnostics + multi_edit in the tools
  overview; add a Code intelligence (LSP) section (lazy per-language servers,
  required binaries, post-edit sync, freshness wait); add a lspServers config
  example.
- src/tools/codeIntel.test.ts: mock lspManager and assert each tool dispatches
  the right args (path/cwd, 1-indexed positions, includeDeclaration default true)
  and returns the manager result verbatim — no servers spawned. 7 tests.

Verified: typecheck clean, 263 tests pass (+7).
2026-08-21 13:45:40 +09:00

68 lines
2.9 KiB
TypeScript

import { describe, it, expect, vi, beforeEach } from "vitest";
// The LSP tools (definition/references/diagnostics) are thin dispatchers over lspManager. We mock
// the manager functions so the tests run without spawning a language server, and assert each tool
// forwards the right arguments (path resolved against cwd, 1-indexed→handled by the manager,
// includeDeclaration default) and returns the manager's result verbatim.
vi.mock("../codeintel/lspManager.js", () => ({
getDefinition: vi.fn(async () => ({ definitions: [{ path: "/abs/a.ts", line: 3, column: 5 }] })),
getReferences: vi.fn(async () => ({ references: [{ path: "/abs/a.ts", line: 3, column: 5 }] })),
getDiagnostics: vi.fn(async () => ({
diagnostics: [{ path: "/abs/a.ts", line: 1, column: 1, severity: "error", message: "oops" }],
})),
}));
import { definitionTool, referencesTool, diagnosticsTool } from "./codeIntel.js";
import { getDefinition, getReferences, getDiagnostics } from "../codeintel/lspManager.js";
const ctx = { cwd: "/proj" };
describe("definition tool", () => {
beforeEach(() => vi.clearAllMocks());
it("forwards path/line/column/cwd to getDefinition and returns its result", async () => {
const out = await definitionTool.handler({ path: "src/a.ts", line: 3, column: 5 }, ctx);
expect(getDefinition).toHaveBeenCalledWith("src/a.ts", 3, 5, "/proj");
expect(out).toEqual({ definitions: [{ path: "/abs/a.ts", line: 3, column: 5 }] });
});
it("is read-only (no permission prompt)", () => {
expect(definitionTool.mutating).toBe(false);
});
});
describe("references tool", () => {
beforeEach(() => vi.clearAllMocks());
it("defaults includeDeclaration to true when omitted", async () => {
await referencesTool.handler({ path: "src/a.ts", line: 3, column: 5 }, ctx);
expect(getReferences).toHaveBeenCalledWith("src/a.ts", 3, 5, "/proj", true);
});
it("passes an explicit includeDeclaration through", async () => {
await referencesTool.handler({ path: "src/a.ts", line: 3, column: 5, include_declaration: false }, ctx);
expect(getReferences).toHaveBeenCalledWith("src/a.ts", 3, 5, "/proj", false);
});
it("returns the manager's references result", async () => {
const out = await referencesTool.handler({ path: "src/a.ts", line: 3, column: 5 }, ctx);
expect(out).toEqual({ references: [{ path: "/abs/a.ts", line: 3, column: 5 }] });
});
});
describe("diagnostics tool", () => {
beforeEach(() => vi.clearAllMocks());
it("forwards path/cwd to getDiagnostics and returns its result", async () => {
const out = await diagnosticsTool.handler({ path: "src/a.ts" }, ctx);
expect(getDiagnostics).toHaveBeenCalledWith("src/a.ts", "/proj");
expect(out).toEqual({
diagnostics: [{ path: "/abs/a.ts", line: 1, column: 1, severity: "error", message: "oops" }],
});
});
it("is read-only", () => {
expect(diagnosticsTool.mutating).toBe(false);
});
});