import { describe, expect, it } from "vitest"; import { allResolved, buildAcceptRequest, emptyDecisions, missingConflictIndices, setNote, setVerdict, unresolvedIndices, } from "./decisions"; describe("emptyDecisions", () => { it("creates N unresolved drafts", () => { expect(emptyDecisions(2)).toEqual([ { verdict: null, note: "" }, { verdict: null, note: "" }, ]); }); }); describe("setVerdict / setNote (immutable)", () => { it("sets verdict at index without mutating others", () => { const drafts = emptyDecisions(2); const next = setVerdict(drafts, 1, "ignore"); expect(next[1]?.verdict).toBe("ignore"); expect(next[0]?.verdict).toBeNull(); expect(drafts[1]?.verdict).toBeNull(); // 原数组不变 }); it("sets note at index", () => { const drafts = emptyDecisions(1); const next = setNote(drafts, 0, "手改说明"); expect(next[0]?.note).toBe("手改说明"); expect(drafts[0]?.note).toBe(""); }); }); describe("allResolved / unresolvedIndices", () => { it("zero conflicts pass through (allResolved true)", () => { expect(allResolved([])).toBe(true); expect(unresolvedIndices([])).toEqual([]); }); it("requires every conflict to have a verdict", () => { let drafts = emptyDecisions(3); expect(allResolved(drafts)).toBe(false); expect(unresolvedIndices(drafts)).toEqual([0, 1, 2]); drafts = setVerdict(drafts, 0, "accept"); drafts = setVerdict(drafts, 2, "manual"); expect(allResolved(drafts)).toBe(false); expect(unresolvedIndices(drafts)).toEqual([1]); drafts = setVerdict(drafts, 1, "ignore"); expect(allResolved(drafts)).toBe(true); expect(unresolvedIndices(drafts)).toEqual([]); }); }); describe("buildAcceptRequest", () => { it("includes only resolved decisions and trims notes", () => { let drafts = emptyDecisions(3); drafts = setVerdict(drafts, 0, "accept"); drafts = setVerdict(drafts, 2, "manual"); drafts = setNote(drafts, 2, " 改成后天淬炼 "); // index 1 仍未决 → 不应进入请求 const req = buildAcceptRequest("终稿正文", drafts); expect(req.final_text).toBe("终稿正文"); expect(req.decisions).toEqual([ { conflict_index: 0, verdict: "accept" }, { conflict_index: 2, verdict: "manual", note: "改成后天淬炼" }, ]); }); it("omits empty/whitespace-only notes", () => { let drafts = emptyDecisions(1); drafts = setVerdict(drafts, 0, "ignore"); drafts = setNote(drafts, 0, " "); const req = buildAcceptRequest("t", drafts); expect(req.decisions).toEqual([{ conflict_index: 0, verdict: "ignore" }]); }); }); describe("missingConflictIndices", () => { it("extracts a set from 409 details", () => { const set = missingConflictIndices({ missing_conflict_indices: [1, 3], conflict_count: 4, }); expect(set.has(1)).toBe(true); expect(set.has(3)).toBe(true); expect(set.has(0)).toBe(false); }); it("returns empty set for malformed/missing details", () => { expect(missingConflictIndices(null).size).toBe(0); expect(missingConflictIndices({}).size).toBe(0); expect(missingConflictIndices({ missing_conflict_indices: "x" }).size).toBe( 0, ); }); });