// Unit-Tests (Story A7-2) für die Reifegrad-Engine gegen die C5-Regelbeispiele. // Lauf: npx tsx scripts/test-maturity.ts import { suggestMaturity, targetMaturity, openPoints, specForControl, type ControlEvidence, } from "../src/lib/maturity"; let failed = 0; function check(name: string, cond: boolean, detail = "") { if (cond) console.log(` ok ${name}`); else { failed++; console.error(`FAIL ${name}${detail ? ` — ${detail}` : ""}`); } } const base: ControlEvidence = { policy: "fehlt", verfahren: "fehlt", assetLinked: false, riskLinked: false, operationalProof: false, }; // Control mit Richtlinie + Verfahren + Asset (1.3.1: R02 / VA-08 / (A)). const s131 = specForControl("1.3.1"); check("1.3.1 hat Verfahren + needsAsset", s131.verfahren.length === 1 && s131.needsAsset); console.log("§2 Belegkonstellationen (Control 1.3.1):"); check("R0 — keine Belege → 0", suggestMaturity(s131, base).value === 0); check("R1a — Richtlinie verknüpft, unvalidiert → 1", suggestMaturity(s131, { ...base, policy: "verknuepft" }).rule === "R1a"); check( "R1b — Richtlinie validiert, Verfahren fehlt → 1", suggestMaturity(s131, { ...base, policy: "validiert" }).rule === "R1b", ); check( "R1c — nur operativer Nachweis, keine validierte Richtlinie → 1", suggestMaturity(s131, { ...base, operationalProof: true }).rule === "R1c", ); check( "R2 — Richtlinie+Verfahren validiert + Asset, kein Nachweis → 2", suggestMaturity(s131, { ...base, policy: "validiert", verfahren: "validiert", assetLinked: true }).value === 2, ); check( "R2 verweigert bei fehlender Asset-Verknüpfung → 1", suggestMaturity(s131, { ...base, policy: "validiert", verfahren: "validiert", assetLinked: false }).value === 1, ); check( "R3 — R2 + aktueller Wirksamkeitsnachweis → 3", suggestMaturity(s131, { ...base, policy: "validiert", verfahren: "validiert", assetLinked: true, operationalProof: true }).value === 3, ); check( "Deckelung — Widerspruch/Findings → max. 1 (CAP)", suggestMaturity(s131, { ...base, policy: "validiert", verfahren: "validiert", assetLinked: true, operationalProof: true, contradiction: true }).value === 1, ); // Control ohne Verfahren (1.1.1: L00 / — / …): Grad 2 über validierte Umsetzungsregelung (N-basisch). console.log("§2 Sonderfall ohne Verfahren (Control 1.1.1):"); const s111 = specForControl("1.1.1"); check("1.1.1 ohne Verfahren", s111.verfahren.length === 0); check( "R2 ohne V — Richtlinie validiert + validierte Umsetzungsregelung → 2", suggestMaturity(s111, { ...base, policy: "validiert", implementationRule: true }).value === 2, ); check( "R1b ohne V — Richtlinie validiert, keine Umsetzungsregelung → 1", suggestMaturity(s111, { ...base, policy: "validiert" }).value === 1, ); check( "R3 ohne V — Umsetzungsregelung + aktueller Wirksamkeitsnachweis → 3", suggestMaturity(s111, { ...base, policy: "validiert", implementationRule: true, operationalProof: true }).value === 3, ); // Zielreifegrad (§3). console.log("§3 Zielreifegrad:"); check("AL3 → 3", targetMaturity({ level: "AL3", flags: {} }) === 3); check("AL2 reiner MUSS-Scope → 2", targetMaturity({ level: "AL2", flags: {} }) === 2); check("AL2 + SOLL → 3", targetMaturity({ level: "AL2", flags: { FLAG_INCLUDE_SHOULD: true } }) === 3); check("AL2 + HOCH → 3", targetMaturity({ level: "AL2", flags: { FLAG_HIGH_PROTECTION: true } }) === 3); // Offene Punkte (§4). console.log("§4 Offene Punkte:"); const evGap: ControlEvidence = { ...base, policy: "validiert", verfahren: "fehlt", assetLinked: false }; const sugGap = suggestMaturity(s131, evGap); const ops = openPoints(s131, evGap, sugGap, 3); check("Verfahren-Gap erzeugt Punkt", ops.some((o) => o.kind === "verfahren")); check("Asset-Verknüpfungs-Gap erzeugt Punkt", ops.some((o) => o.kind === "verknuepfung")); check("Nachweis-Gap bei Ziel 3 erzeugt Punkt", ops.some((o) => o.kind === "nachweis")); check( "kein Gap bei erfülltem Ziel", openPoints(s131, { ...base, policy: "validiert", verfahren: "validiert", assetLinked: true, operationalProof: true }, suggestMaturity(s131, { ...base, policy: "validiert", verfahren: "validiert", assetLinked: true, operationalProof: true }), 3).length === 0, ); console.log(failed === 0 ? "\nAlle Reifegrad-Tests grün." : `\n${failed} Test(s) fehlgeschlagen.`); process.exit(failed === 0 ? 0 : 1);