Basis: Certvia dev@a48c5fb als Fundament für Craftvia
Unveränderter Stand von certvia/dev (a48c5fb) plus Craftvia-Spezifikation und Brandbook unter docs/craftvia/. ISMS-Module werden im Folgecommit entfernt. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
// Akzeptanztest der Readiness-Logik (Story B7-1, C9 §1/§2). Reine Logik, kein DB-Zugriff.
|
||||
// Lauf: npx tsx scripts/test-readiness.ts (Exit 1 bei Fehler).
|
||||
|
||||
import { interpretationBand, averageReifegrad, buildNextSteps, computeReadiness, type ControlAssessment } from "../src/lib/readiness";
|
||||
|
||||
let failures = 0;
|
||||
const ok = (cond: boolean, msg: string) => {
|
||||
console.log(`${cond ? "✓" : "✗ FEHLER"} ${msg}`);
|
||||
if (!cond) failures++;
|
||||
};
|
||||
|
||||
// — C9 §1: Textbänder je Ø-Reifegrad —
|
||||
ok(interpretationBand(0).band === "Aufbau", "Ø 0 → Aufbau");
|
||||
ok(interpretationBand(1.49).band === "Aufbau", "Ø 1,49 → Aufbau");
|
||||
ok(interpretationBand(1.5).band === "Etabliert im Aufbau", "Ø 1,5 → Etabliert im Aufbau");
|
||||
ok(interpretationBand(2.49).band === "Etabliert im Aufbau", "Ø 2,49 → Etabliert im Aufbau");
|
||||
ok(interpretationBand(2.5).band === "Assessment-nah", "Ø 2,5 → Assessment-nah");
|
||||
ok(interpretationBand(2.99).band === "Assessment-nah", "Ø 2,99 → Assessment-nah");
|
||||
ok(interpretationBand(3.0).band === "Assessment-reif", "Ø 3,0 → Assessment-reif");
|
||||
|
||||
// — Ø-Reifegrad: „unbestätigt zählt nicht als erfüllt" (geht mit 0 ein) —
|
||||
{
|
||||
const a: ControlAssessment[] = [
|
||||
{ control: "1.1.1", chapter: "1", reifegrad: 3, bestaetigt: true },
|
||||
{ control: "1.1.2", chapter: "1", reifegrad: 3, bestaetigt: false }, // zählt als 0
|
||||
];
|
||||
ok(averageReifegrad(a) === 1.5, "unbestätigt zählt als 0 → Ø(3,0) = 1,5");
|
||||
ok(averageReifegrad([]) === null, "keine Assessments → null (A7 ausstehend)");
|
||||
}
|
||||
|
||||
// — C9 §2: dynamische nächste Schritte —
|
||||
{
|
||||
const all = buildNextSteps({ openHighCount: 2, unvalidatedCount: 5, prototypeGap: true, evidenceUploadPending: true });
|
||||
ok(all.some((s) => s.includes("2 Hoch-Punkte")), "Hoch-Punkte → Schritt mit Anzahl");
|
||||
ok(all.some((s) => s.includes("5 Objekte")), "unvalidierte Objekte → Schritt mit Anzahl");
|
||||
ok(all.some((s) => s.includes("Prototypen")), "Prototyp-Gap → Prototyp-Schritt");
|
||||
ok(all.length === 4, "alle vier Regeln greifen");
|
||||
const none = buildNextSteps({ openHighCount: 0, unvalidatedCount: 0, prototypeGap: false, evidenceUploadPending: false });
|
||||
ok(none.length === 0, "keine Bedingung → keine Schritte");
|
||||
}
|
||||
|
||||
// — computeReadiness: assessmentPending ohne A7-Daten —
|
||||
{
|
||||
const r = computeReadiness({
|
||||
assessments: [], bestaetigtAnteil: 0,
|
||||
offenJePrioritaet: { hoch: 1, mittel: 2, niedrig: 0 },
|
||||
pruefzielAbdeckung: [{ pruefziel: "informationssicherheit", anforderungen: 300 }],
|
||||
zielReifegrad: 3,
|
||||
nextSteps: { openHighCount: 1, unvalidatedCount: 0, prototypeGap: false, evidenceUploadPending: false },
|
||||
});
|
||||
ok(r.assessmentPending === true && r.avgReifegrad === null && r.band === null, "ohne Assessments → pending, kein Reifegrad/Band");
|
||||
ok(r.nextSteps.length === 1, "Kennzahlen-basierte Schritte trotzdem berechnet");
|
||||
}
|
||||
|
||||
console.log(failures === 0 ? "\nOK — alle Readiness-Tests grün" : `\nPRUEFEN — ${failures} Fehler`);
|
||||
process.exit(failures === 0 ? 0 : 1);
|
||||
Reference in New Issue
Block a user