Luigit
repositories / pi-ext

pi-ext

bugabingas pi extensions

owned by admin

extensions/good-job/__tests__/settings.test.ts

Raw
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";

const extensionPath = path.resolve(import.meta.dirname, "../index.ts");

type Case = { user?: unknown; project?: unknown; untrusted?: boolean };

describe("good-job settings 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 status(input: Case): Promise<string> {
		root = mkdtempSync(path.join(tmpdir(), "pi-ext-good-job-settings-"));
		const write = (dir: string, value: unknown) => {
			mkdirSync(dir, { recursive: true });
			writeFileSync(path.join(dir, "settings.json"), JSON.stringify(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);
		const session = await createTestSession({
			cwd: root,
			extensions: [extensionPath],
		});
		t = session;
		if (input.untrusted)
			session.session.settingsManager.setProjectTrusted(false);
		const runner = session.session.extensionRunner;
		const gj = runner.extensions[0].commands.get("gj");
		await gj.handler("status", runner.createContext() as never);
		return String(session.events.uiCallsFor("notify").at(-1)?.args[0]);
	}

	const user = {
		"good-job": { model: "user/model", thinkingLevel: "low" },
	};

	it.each([
		["defaults", {}, "current", "provider default"],
		["user", { user }, "user/model", "low"],
		[
			"project over user per key",
			{ user, project: { "good-job": { thinkingLevel: "high" } } },
			"user/model",
			"high",
		],
		[
			"untrusted project ignored",
			{
				user,
				project: { "good-job": { model: "project/model" } },
				untrusted: true,
			},
			"user/model",
			"low",
		],
		[
			"old goodJob key ignored",
			{ user: { goodJob: { model: "old/model", thinkingLevel: "max" } } },
			"current",
			"provider default",
		],
	] satisfies [string, Case, string, string][])(
		"%s",
		async (_name, input, model, thinking) => {
			const message = await status(input);
			expect(message).toContain(`analysis model: ${model}`);
			expect(message).toContain(`thinking: ${thinking}`);
		},
	);

	it("resolves directory from settings", async () => {
		const message = await status({
			user: { "good-job": { directory: "  gj-store  " } },
		});
		expect(message).toContain(path.join(root ?? "", "gj-store"));
	});

	it.each([
		[
			"project thinkingLevel",
			{ user, project: { "good-job": { thinkingLevel: "invalid" } } },
			"Invalid good-job.thinkingLevel from project settings: must be minimal, low, medium, high, xhigh, or max",
		],
		[
			"user model",
			{ user: { "good-job": { model: "no-slash" } } },
			"Invalid good-job.model from user settings: must be provider/model",
		],
		[
			"user directory",
			{ user: { "good-job": { directory: " " } } },
			"Invalid good-job.directory from user settings: must be a non-empty path",
		],
	] satisfies [string, Case, string][])(
		"rejects invalid %s without falling through",
		async (_name, input, error) => {
			await expect(status(input)).rejects.toThrow(error);
		},
	);
});