import { test, expect } from "bun:test"; import { parseCommit, computeProgress } from "./a31_commits.ts"; test("parseCommit reads a phase prefix", () => { expect(parseCommit("red: failing test for empty")).toEqual({ phase: "red", step: null, subject: "failing test for empty", }); }); test("parseCommit extracts step from phase(step): form", () => { expect(parseCommit("green(single-number): return n for one number")).toEqual({ phase: "green", step: "single-number", subject: "return n for one number", }); }); test("parseCommit recognizes 'Initial commit' as init", () => { expect(parseCommit("Initial commit").phase).toBe("init"); }); test("parseCommit returns untagged for unknown messages", () => { expect(parseCommit("wip — fixing something").phase).toBe("untagged"); }); test("parseCommit recognizes spike: prefix", () => { expect(parseCommit("spike: try the regex approach").phase).toBe("spike"); }); test("parseCommit extracts step from spike(step):", () => { const p = parseCommit("spike(custom-separator): explore Forge regex"); expect(p.phase).toBe("spike"); expect(p.step).toBe("custom-separator"); }); test("computeProgress verifies a step after red→green for the same step", () => { const commits = [ { commit: { message: "green(empty): returns 0" } }, { commit: { message: "red(empty): empty string returns 0" } }, ]; // newest first, like Forgejo const p = computeProgress(commits); expect(p.verifiedSteps).toEqual(new Set(["empty"])); expect(p.redCount).toBe(1); expect(p.greenCount).toBe(1); }); test("computeProgress does not verify green-without-prior-red", () => { const commits = [{ commit: { message: "green(empty): returns 0" } }]; expect(computeProgress(commits).verifiedSteps.size).toBe(0); });