pi_coder/test-utils.ts
dschlueter 7b13c4996d test: Unit-Tests für normalizeForComparison, parseVerdict, parseBlockers
28 Tests für die drei reinen Hilfsfunktionen aus pi-coder-judge-extension.ts.
run-tests.sh führt test-utils.ts ohne ts-node aus (sed-basiertes TS→JS-Stripping).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-29 18:14:03 +02:00

193 lines
6.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Unit-Tests für reine Hilfsfunktionen aus pi-coder-judge-extension.ts
//
// Ausführung (TypeScript):
// npx ts-node test-utils.ts
//
// Ausführung ohne ts-node (schneller):
// node --input-type=module < <(sed 's/: string//g; s/: unknown//g; s/: void//g; s/: boolean//g' test-utils.ts)
//
// Oder: Funktionen aus dieser Datei kopieren und als .js ausführen.
// ── Funktionen (aus Extension kopiert, kein pi-API-Import nötig) ─────────────
function normalizeForComparison(s: string): string {
return s.trim().replace(/\s+/g, " ").replace(/[.,;:!?]+$/g, "").toLowerCase();
}
function parseVerdict(text: string): string {
const m = text.match(/Urteil:\s*(PASS WITH CONCERNS|PASS|FAIL)/i);
return m ? m[1].toUpperCase() : "UNREADABLE";
}
function parseBlockers(text: string): string {
const m = text.match(
/(?:\*\*Blocker\*\*|##\s*Blocker|[-*]\s*Blocker)[:\n]([\s\S]*?)(?:\n(?:\*\*Major\*\*|##\s*Major|[-*]\s*Major)|\n(?:\*\*Minor\*\*|##\s*Minor|[-*]\s*Minor)|$)/i
);
return m ? m[1].trim() : "";
}
// ── Test-Harness ──────────────────────────────────────────────────────────────
let passed = 0;
let failed = 0;
function expect(actual: unknown, expected: unknown, label: string): void {
if (actual === expected) {
console.log(`${label}`);
passed++;
} else {
console.error(`${label}`);
console.error(` erwartet: ${JSON.stringify(expected)}`);
console.error(` erhalten: ${JSON.stringify(actual)}`);
failed++;
}
}
// ── normalizeForComparison ────────────────────────────────────────────────────
console.log("\nnormalizeForComparison()");
expect(normalizeForComparison(" Foo Bar "), "foo bar",
"trimmt führende/nachfolgende Leerzeichen");
expect(normalizeForComparison("Foo.\n"), "foo",
"entfernt trailing Punkt + Newline");
expect(normalizeForComparison("A B"), "a b",
"kollabiert mehrfache Leerzeichen");
expect(normalizeForComparison("Foo:"), "foo",
"entfernt trailing Doppelpunkt");
expect(normalizeForComparison("Foo;"), "foo",
"entfernt trailing Semikolon");
expect(normalizeForComparison("Foo!"), "foo",
"entfernt trailing Ausrufezeichen");
expect(normalizeForComparison("Foo?"), "foo",
"entfernt trailing Fragezeichen");
expect(normalizeForComparison("UPPER CASE"), "upper case",
"konvertiert zu Kleinbuchstaben");
// Loop-Detection: gleiche Blocker nach Normalisierung erkannt
expect(
normalizeForComparison("missing error handling.") ===
normalizeForComparison("missing error handling"),
true,
"Loop-Detection: trailing Punkt macht keinen Unterschied"
);
expect(
normalizeForComparison("null check missing\n") ===
normalizeForComparison("null check missing"),
true,
"Loop-Detection: Newline am Ende macht keinen Unterschied"
);
expect(
normalizeForComparison("Fehler bei Import.") ===
normalizeForComparison("Fehler bei Import"),
true,
"Loop-Detection: mehrfache Leerzeichen + Punkt machen keinen Unterschied"
);
expect(
normalizeForComparison("Blocker A") === normalizeForComparison("Blocker B"),
false,
"Loop-Detection: verschiedene Blocker werden NICHT als gleich erkannt"
);
// ── parseVerdict ──────────────────────────────────────────────────────────────
console.log("\nparseVerdict()");
expect(parseVerdict("Urteil: PASS"), "PASS",
"erkennt PASS");
expect(parseVerdict("Urteil: PASS WITH CONCERNS"), "PASS WITH CONCERNS",
"erkennt PASS WITH CONCERNS (vor PASS gematcht)");
expect(parseVerdict("Urteil: FAIL"), "FAIL",
"erkennt FAIL");
expect(parseVerdict("kein Urteil hier"), "UNREADABLE",
"gibt UNREADABLE zurück wenn kein Urteil");
expect(parseVerdict("urteil: pass"), "PASS",
"case-insensitiv: 'urteil: pass'");
expect(parseVerdict("urteil: Pass With Concerns"), "PASS WITH CONCERNS",
"case-insensitiv: gemischte Groß-/Kleinschreibung");
expect(parseVerdict("Das ist mein Urteil: PASS — und mehr Text dahinter"), "PASS",
"ignoriert Text nach dem Urteil");
expect(parseVerdict("Urteil:PASS"), "PASS",
"toleriert fehlenden Leerzeichen nach Doppelpunkt");
expect(parseVerdict(""), "UNREADABLE",
"leerer String → UNREADABLE");
// ── parseBlockers ─────────────────────────────────────────────────────────────
console.log("\nparseBlockers()");
expect(
parseBlockers("**Blocker**:\n- fehlende Validierung\n**Major**:\n- anderes Problem"),
"- fehlende Validierung",
"erkennt **Blocker** mit Bold-Syntax"
);
expect(
parseBlockers("## Blocker\nNull-Check fehlt\n## Major\nanderes"),
"Null-Check fehlt",
"erkennt ## Blocker mit Heading-Syntax"
);
expect(
parseBlockers("- Blocker:\n- fehlender Import\n- Minor:\n- Stil"),
"- fehlender Import",
"erkennt - Blocker mit Bullet-Syntax"
);
expect(
parseBlockers(" Blocker\nKein Logging\n- Minor\nKleinigkeit"),
"Kein Logging",
"erkennt Blocker (Gedankenstrich)"
);
expect(
parseBlockers("Urteil: PASS\n\nAlles ok."),
"",
"gibt leeren String zurück wenn kein Blocker-Abschnitt"
);
expect(
parseBlockers("**Blocker**:\nkeine\n**Minor**:\n- Stil"),
"keine",
"extrahiert 'keine' als Blocker-Text"
);
// Mehrzeiliger Blocker
const multilineInput = `**Blocker**:
- Import fehlt
- Funktion nicht definiert
**Major**:
- weitere Sache`;
const multilineResult = parseBlockers(multilineInput);
expect(
multilineResult.includes("Import fehlt") && multilineResult.includes("Funktion nicht definiert"),
true,
"extrahiert mehrzeiligen Blocker vollständig"
);
// ── Ergebnis ──────────────────────────────────────────────────────────────────
console.log(`\n${"─".repeat(50)}`);
console.log(`Gesamt: ${passed + failed} Tests — ${passed} bestanden, ${failed} fehlgeschlagen`);
if (failed > 0) {
process.exit(1);
}