import { describe, it } from "vitest"; import fc from "fast-check"; import { PiBackend } from "../../src/backends/pi-backend.js"; import type { BackendAdapterConfig } from "../../src/backends/types.js"; // Feature: multi-cli-backend, Property: Pi backend required flags // Validates Pi-specific CLI argument construction /** * Arbitrary for non-empty strings that won't break CLI arg parsing. */ const nonEmptyString = fc.string({ minLength: 1, maxLength: 200 }); /** * Arbitrary for model strings (provider/model format). */ const modelString = fc.stringMatching(/^[a-z]{1,20}\/[a-z0-9-]{1,40}$/); function createBackend(model?: string): PiBackend { const config: BackendAdapterConfig = { cliPath: "pi", workingDir: "/tmp", queryTimeoutMs: 60000, allowedTools: [], maxTurns: 25, model, }; return new PiBackend(config); } describe("Pi backend required flags", () => { it("generated args always contain -p for print mode", () => { fc.assert( fc.property( nonEmptyString, (prompt) => { const backend = createBackend(); const args = backend.buildArgs(prompt); return args.includes("-p"); }, ), { numRuns: 100 }, ); }); it("generated args always contain --mode json", () => { fc.assert( fc.property( nonEmptyString, (prompt) => { const backend = createBackend(); const args = backend.buildArgs(prompt); const modeIndex = args.indexOf("--mode"); return modeIndex !== -1 && args[modeIndex + 1] === "json"; }, ), { numRuns: 100 }, ); }); it("generated args contain --model when a model is configured", () => { fc.assert( fc.property( nonEmptyString, modelString, (prompt, model) => { const backend = createBackend(model); const args = backend.buildArgs(prompt); const modelIndex = args.indexOf("--model"); return modelIndex !== -1 && args[modelIndex + 1] === model; }, ), { numRuns: 100 }, ); }); it("generated args do not contain --model when no model is configured", () => { fc.assert( fc.property( nonEmptyString, (prompt) => { const backend = createBackend(undefined); const args = backend.buildArgs(prompt); return !args.includes("--model"); }, ), { numRuns: 100 }, ); }); it("generated args contain --no-session for headless usage", () => { fc.assert( fc.property( nonEmptyString, (prompt) => { const backend = createBackend(); const args = backend.buildArgs(prompt); return args.includes("--no-session"); }, ), { numRuns: 100 }, ); }); it("generated args contain --no-extensions, --no-skills, --no-themes for deterministic runs", () => { fc.assert( fc.property( nonEmptyString, (prompt) => { const backend = createBackend(); const args = backend.buildArgs(prompt); return ( args.includes("--no-extensions") && args.includes("--no-skills") && args.includes("--no-themes") ); }, ), { numRuns: 100 }, ); }); it("prompt is always the last argument", () => { fc.assert( fc.property( nonEmptyString, (prompt) => { const backend = createBackend(); const args = backend.buildArgs(prompt); return args[args.length - 1] === prompt; }, ), { numRuns: 100 }, ); }); });