import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs"; import { tmpdir } from "node:os"; import path from "node:path"; import { afterEach, describe, expect, it } from "vitest"; import { createTestSession, type TestSession } from "../../../test/harness"; import intellijExtension from "../index"; type Case = { user?: unknown; project?: unknown; untrusted?: boolean }; describe("intellij.url resolution", () => { let t: TestSession | undefined; let root: string | undefined; afterEach(() => { t?.dispose(); t = undefined; if (root) rmSync(root, { recursive: true, force: true }); root = undefined; }); async function run(input: Case, command: string) { root = mkdtempSync(path.join(tmpdir(), "pi-ext-intellij-settings-")); const write = (dir: string, value: unknown) => { mkdirSync(dir, { recursive: true }); writeFileSync( path.join(dir, "settings.json"), JSON.stringify({ intellij: { url: value } }), ); }; if ("user" in input) write(path.join(root, ".test-home/.pi/agent"), input.user); if ("project" in input) write(path.join(root, ".pi"), input.project); t = await createTestSession({ cwd: root, extensionFactories: [intellijExtension], }); if (input.untrusted) t.session.settingsManager.setProjectTrusted(false); const [extension] = t.session.extensionRunner.extensions; await extension.commands .get("intellij") .handler(command, t.session.extensionRunner.createCommandContext()); return t.events.uiCallsFor("notify").at(-1)?.args; } it.each([ ["none", {}, "none"], ["user", { user: "http://127.0.0.1:1/user" }, "http://127.0.0.1:1/user"], [ "project over user", { user: "http://127.0.0.1:1/user", project: "http://127.0.0.1:1/proj" }, "http://127.0.0.1:1/proj", ], [ "untrusted project ignored", { user: "http://127.0.0.1:1/user", project: "http://127.0.0.1:1/proj", untrusted: true, }, "http://127.0.0.1:1/user", ], ] satisfies [string, Case, string][])( "status shows %s", async (_name, input, endpoint) => { const [message, level] = (await run(input, "status")) ?? []; expect(message).toContain(`endpoint: ${endpoint}\n`); expect(level).toBe("info"); }, ); const invalid = [ ["project", { user: "http://127.0.0.1:1/user", project: 1 }], ["user", { user: true }], ] satisfies [string, Case][]; it.each(invalid)( "status rejects non-string %s value without falling through", async (source, input) => { expect(await run(input, "status")).toEqual([ expect.stringContaining( `endpoint: unavailable (Invalid intellij.url from ${source} settings)`, ), "warning", ]); }, ); it.each(invalid)( "connect rejects non-string %s value without falling through", async (source, input) => { expect(await run(input, "connect")).toEqual([ expect.stringMatching( new RegExp(`^Invalid intellij\\.url from ${source} settings\\. `), ), "warning", ]); }, ); });