import { describe, expect, it } from "vitest"; import { readFileSync, readdirSync } from "node:fs"; import { resolve } from "node:path"; import { COMMAND_VERBS, parseScript, type Command } from "../../runner/parser"; import { parseExpectation } from "../../tools/selfCheck"; import { loadScripts } from "../../tools/selfCheckRun"; /** P2-4 acceptance: every command has a passing and a failing fixture script, and the fixtures are what they say they are. */ const root = resolve(__dirname, "../.."); const scripts = loadScripts(root); const commandsOf = (text: string): Command[] => { const r = parseScript(text); return r.ok ? r.script.steps.flatMap((s) => s.commands) : r.partial.steps.flatMap((s) => s.commands); }; describe("fixture scripts", () => { it("every script says what it must do", () => { for (const s of scripts) expect(parseExpectation(s.text), s.name).not.toHaveProperty("error"); }); it.each(COMMAND_VERBS)("%s has a passing script and a failing script", (verb) => { const names = scripts.map((s) => s.name); expect(names, `a passing fixture for ${verb}`).toContain(`${verb}.pass`); expect(names.filter((n) => n.startsWith(`${verb}.fail`)).length, `a failing fixture for ${verb}`).toBeGreaterThan(0); }); it("a passing script uses its command, and parses with no error", () => { for (const verb of COMMAND_VERBS) { const s = scripts.find((x) => x.name === `${verb}.pass`)!; const r = parseScript(s.text); expect(r.ok, `${s.name}: ${JSON.stringify(!r.ok && r.errors)}`).toBe(true); expect(commandsOf(s.text).map((c) => c.verb), s.name).toContain(verb); } }); it("a script that must fail at run time parses, and it uses the command it says fails", () => { for (const s of scripts) { const e = parseExpectation(s.text); if ("error" in e || e.kind !== "fail") continue; const r = parseScript(s.text); expect(r.ok, `${s.name} must be a valid script that fails when it runs: ${JSON.stringify(!r.ok && r.errors)}`).toBe(true); // when the failure is in an included script, the command is in that file, not in this one if (e.file === undefined) expect(commandsOf(s.text).map((c) => c.verb), s.name).toContain(e.verb); } }); it("a script that must be refused is refused by the parser with the text it names (except run, which is refused when its file is read)", () => { for (const s of scripts) { const e = parseExpectation(s.text); if ("error" in e || e.kind !== "refused" || s.name.startsWith("run.")) continue; const r = parseScript(s.text); expect(r.ok, `${s.name} must be refused`).toBe(false); expect(JSON.stringify(!r.ok && r.errors), s.name).toContain(e.fragment); } }); it("every failing script has a tight timeout, so the failures do not make the self-check slow", () => { for (const s of scripts) { const e = parseExpectation(s.text); if ("error" in e || e.kind === "pass") continue; const timeout = /^\s*timeout\s+(\d+)(ms|s)\b/m.exec(s.text); const ms = timeout ? Number(timeout[1]) * (timeout[2] === "s" ? 1000 : 1) : 10_000; expect(ms, `${s.name} has timeout ${timeout?.[0]?.trim() ?? "(default 10 s)"}`).toBeLessThanOrEqual(1500); } }); it("the shared scripts and checks the fixtures use exist", () => { expect(readdirSync(resolve(root, "fixtures/commands/scripts/shared")).sort()).toEqual(["broken.aite", "send.aite"]); expect(readdirSync(resolve(root, "fixtures/commands/checks")).sort()).toEqual(["alwaysFails.ts", "matches.ts"]); expect(readFileSync(resolve(root, "fixtures/commands/scripts/call.pass.aite"), "utf8")).toContain("call matches"); }); });