// Akzeptanztest der Funktionstrennungs-Regeln FT-01…FT-06 (Story A4-2, C7 §2). // Reine Logik, kein DB-Zugriff. Lauf: npx tsx scripts/test-ft-rules.ts import { evaluateFt, type FtRoleInput } from "../src/lib/ft-rules"; let failures = 0; const ok = (cond: boolean, msg: string) => { console.log(`${cond ? "✓" : "✗ FEHLER"} ${msg}`); if (!cond) failures++; }; const base: FtRoleInput = { roles: { ISB: "Frau A", MANAGEMENT: "Herr B", IT_LEAD: "Herr C", HR_LEAD: "Frau D", DPO: "Herr E" }, isbNamed: true, isbIsIt: false, isbInternal: false, personalData: false, }; const codes = (i: FtRoleInput) => evaluateFt(i).map((f) => f.code); const byCode = (i: FtRoleInput, c: string) => evaluateFt(i).find((f) => f.code === c); // — Sauberer Fall: nur FT-06 (manueller Hinweis) — ok(JSON.stringify(codes(base)) === JSON.stringify(["FT-06"]), "sauber → nur FT-06 (manuell)"); // — FT-04: ISB nicht benannt → Lücke + Aufgabe (reuse isb_not_named) — { const f = byCode({ ...base, isbNamed: false }, "FT-04"); ok(!!f && f.severity === "luecke" && f.task?.origin === "isb_not_named" && f.task?.reuse === true, "FT-04 ISB nicht benannt → Lücke + Aufgabe (reuse)"); } // — FT-01: ISB = IT → Konflikt + Aufgabe (reuse isb_equals_it) — { const f = byCode({ ...base, isbIsIt: true }, "FT-01"); ok(!!f && f.severity === "konflikt" && f.task?.origin === "isb_equals_it" && f.task?.reuse === true, "FT-01 ISB=IT → Konflikt + Aufgabe (reuse)"); } // — FT-03: ISB = Leitung → Konflikt + neue Aufgabe ft-03 — { const f = byCode({ ...base, roles: { ...base.roles, MANAGEMENT: "Frau A" } }, "FT-03"); ok(!!f && f.severity === "konflikt" && f.task?.origin === "ft-03" && f.task?.reuse === false, "FT-03 ISB=Leitung → Konflikt + neue Aufgabe"); } // — FT-05: DPO fehlt trotz personenbezogener Daten → Lücke + neue Aufgabe ft-05 — { const f = byCode({ ...base, personalData: true, roles: { ...base.roles, DPO: "" } }, "FT-05"); ok(!!f && f.severity === "luecke" && f.task?.origin === "ft-05" && f.task?.reuse === false, "FT-05 DPO fehlt + FLAG_PERSONAL_DATA → Lücke + neue Aufgabe"); // Kein FT-05, wenn DPO gesetzt: ok(!byCode({ ...base, personalData: true }, "FT-05"), "FT-05 nicht, wenn DPO benannt"); // Kein FT-05, wenn keine personenbezogenen Daten: ok(!byCode({ ...base, roles: { ...base.roles, DPO: "" } }, "FT-05"), "FT-05 nicht ohne FLAG_PERSONAL_DATA"); } // — FT-02: interner ISB (nicht IT) → schwacher Hinweis, keine Aufgabe — { const f = byCode({ ...base, isbInternal: true }, "FT-02"); ok(!!f && f.severity === "schwach" && !f.task, "FT-02 interner ISB → Hinweis ohne Aufgabe"); } // — FT-06 immer vorhanden (manuell) — ok(!!byCode(base, "FT-06") && !byCode(base, "FT-06")!.task, "FT-06 immer vorhanden, ohne Aufgabe"); console.log(failures === 0 ? "\nOK — alle FT-Tests grün" : `\nPRUEFEN — ${failures} Fehler`); process.exit(failures === 0 ? 0 : 1);