/* Unit tests for version bumper covering calculateNextVersion; version bump rules; breaking changes. Not a contract source of truth — the module under test owns the authoritative behavior; fixtures are minimal scaffolding only. RFC-1311: Compass header sweep — declares the version suite's contract for test-file scaffold coverage. */ import { describe, it, expect } from "vitest"; import { calculateNextVersion } from "../changelog/core/version-bumper.ts"; import type { ClassifiedCommit } from "../changelog/types.ts"; const THRESHOLD = 0.85; function makeCommit(overrides: Partial): ClassifiedCommit { return { hash: "abc", type: "chore", severity: "patch", module: "general", summary: "misc", isConventional: true, isBreaking: false, confidence: 0.95, ...overrides, }; } const feat = makeCommit({ type: "feat", severity: "minor" }); const fix = makeCommit({ type: "fix", severity: "patch" }); describe("calculateNextVersion", () => { describe("version bump rules", () => { it("feat commit → minor bump", () => { const r = calculateNextVersion("1.5.3", [feat], THRESHOLD); expect(r.version).toBe("1.6.0"); }); it("fix commit → patch bump", () => { const r = calculateNextVersion("1.5.3", [fix], THRESHOLD); expect(r.version).toBe("1.5.4"); }); it("chore commit → patch bump", () => { const chore = makeCommit({ type: "chore" }); const r = calculateNextVersion("1.5.3", [chore], THRESHOLD); expect(r.version).toBe("1.5.4"); }); it("feat + fix → minor bump (feat wins)", () => { const r = calculateNextVersion("1.5.3", [fix, feat], THRESHOLD); expect(r.version).toBe("1.6.0"); }); it("empty commits → patch bump", () => { const r = calculateNextVersion("1.5.3", [], THRESHOLD); expect(r.version).toBe("1.5.4"); }); }); describe("breaking changes", () => { it("breaking + high confidence → minor bump, hasBreakingChanges=true", () => { const breaking = makeCommit({ type: "breaking", isBreaking: true, confidence: 0.9 }); const r = calculateNextVersion("1.5.3", [breaking], THRESHOLD); expect(r.version).toBe("1.6.0"); expect(r.hasBreakingChanges).toBe(true); }); it("breaking + low confidence → requiresReview=true", () => { const breaking = makeCommit({ type: "breaking", isBreaking: true, confidence: 0.7 }); const r = calculateNextVersion("1.5.3", [breaking], THRESHOLD); expect(r.requiresReview).toBe(true); }); it("breaking + low confidence still bumps version (patch — no feat or high-conf breaking)", () => { const breaking = makeCommit({ type: "breaking", isBreaking: true, confidence: 0.7 }); const r = calculateNextVersion("1.5.3", [breaking], THRESHOLD); expect(r.version).toBe("1.5.4"); }); it("no breaking commits → hasBreakingChanges=false, requiresReview=false", () => { const r = calculateNextVersion("1.5.3", [feat], THRESHOLD); expect(r.hasBreakingChanges).toBe(false); expect(r.requiresReview).toBe(false); }); }); describe("major version guard", () => { it("does not throw for normal minor bump within same major", () => { expect(() => calculateNextVersion("2.9.3", [feat], THRESHOLD)).not.toThrow(); expect(calculateNextVersion("2.9.3", [feat], THRESHOLD).version).toBe("2.10.0"); }); it("does not throw for patch bump at x.y.9", () => { expect(() => calculateNextVersion("1.5.9", [fix], THRESHOLD)).not.toThrow(); expect(calculateNextVersion("1.5.9", [fix], THRESHOLD).version).toBe("1.5.10"); }); }); describe("invalid input", () => { it("throws for invalid semver string", () => { expect(() => calculateNextVersion("not-a-version", [feat], THRESHOLD)).toThrow( "Invalid current version", ); }); }); });