import { describe, expect, it } from "vitest"; import { PASSWORT_IM_DRUCK } from "@/lib/passwort"; import { platzhalterErsetzen, platzhalterErsetzenRoh } from "@/lib/platzhalter-werte"; /** * Das Ersetzen der Platzhalter (#012). * * Hier entsteht der Text, den ein Techniker kopiert und auf einem * Domaenencontroller ausfuehrt. Entsprechend dicht ist die Abdeckung: jede * Regel, die der Auftrag nennt, hat einen Test, und jeder Weg, auf dem ein Wert * einen Befehl zerbrechen koennte, auch. */ const WERTE = { vorname: "Maria", nachname: "Huber", mitarbeiter: "Maria Huber", abteilung: "Buchhaltung", hostname: "PC-001", }; describe("Ersetzen", () => { it("ersetzt einen bekannten Platzhalter", () => { expect(platzhalterErsetzen("Hallo {{vorname}}", WERTE).text).toBe("Hallo Maria"); }); it("erlaubt Leerzeichen in den Klammern", () => { expect(platzhalterErsetzen("{{ vorname }} {{ nachname }}", WERTE).text).toBe("Maria Huber"); }); it("ersetzt denselben Platzhalter mehrfach", () => { expect(platzhalterErsetzen("{{vorname}} und nochmal {{vorname}}", WERTE).text).toBe( "Maria und nochmal Maria", ); }); it("lässt einen unbekannten Platzhalter stehen und meldet ihn", () => { // Akzeptanzkriterium: ein Tippfehler bleibt sichtbar. Eine leere Stelle im // Befehl faellt niemandem auf, `{{tipfehler}}` schon. const ergebnis = platzhalterErsetzen("New-ADUser -Name {{tipfehler}}", WERTE); expect(ergebnis.text).toBe("New-ADUser -Name {{tipfehler}}"); expect(ergebnis.unbekannt).toEqual(["tipfehler"]); }); it("macht einen bekannten Platzhalter ohne Wert leer", () => { // Der Unterschied zum unbekannten: „hier gibt es das nicht“ ist etwas // anderes als „falsch geschrieben“. `{{kunde}}` im Modus Intern ist leer. const ergebnis = platzhalterErsetzen("Kunde: {{kunde}}!", WERTE); expect(ergebnis.text).toBe("Kunde: !"); expect(ergebnis.unbekannt).toEqual([]); }); it("rührt Text ohne Platzhalter nicht an", () => { expect(platzhalterErsetzen("Nur Text { kein } Platzhalter", WERTE).text).toBe( "Nur Text { kein } Platzhalter", ); }); it("lässt einen falsch geschriebenen Platzhalter stehen und meldet ihn", () => { /* * Dieselbe Schluesselregel wie bei den Variablen (docs/vorlagen-format.md). * Gemeldet wird er trotzdem: ein falsch geschriebener Platzhalter ist * gefaehrlicher als ein unbekannter, weil er richtig aussieht. Bis zum * Review von #012 blieb er still stehen. */ const text = "{{Vorname}} {{vor-name}} {{2te}}"; const ergebnis = platzhalterErsetzen(text, WERTE); expect(ergebnis.text).toBe(text); expect([...ergebnis.unbekannt].sort()).toEqual(["2te", "Vorname", "vor-name"]); }); it("stolpert nicht über eine einzelne geschweifte Klammer", () => { const text = "Pfad {C:\\} und {{vorname}}"; expect(platzhalterErsetzen(text, WERTE).text).toBe("Pfad {C:\\} und Maria"); }); it("setzt einen Wert mit $-Zeichen wörtlich ein", () => { // `String.replace` deutet `$&`, `` $` ``, `$'` und `$1` im Ersatztext als // Rueckverweise. Ein Nachname „A$&B“ haette sonst den gefundenen // Platzhalter wieder eingesetzt. for (const wert of ["A$&B", "vor $` danach", "A $' B", "Gruppe $1"]) { expect(platzhalterErsetzenRoh("Name: {{nachname}}", { nachname: wert }).text, wert).toBe( `Name: ${wert}`, ); } }); }); describe("Maskierung für einen Befehl", () => { it("reicht jeden Wert durch die mitgegebene Maskierung", () => { const ergebnis = platzhalterErsetzen( 'New-ADUser -Name "{{mitarbeiter}}"', { mitarbeiter: 'Anna "Anni" Meier' }, { art: "befehl", maskieren: (wert) => wert.replaceAll('"', '""') }, ); expect(ergebnis.text).toBe('New-ADUser -Name "Anna ""Anni"" Meier"'); }); it("maskiert im Befehl nicht zusätzlich für HTML", () => { // Ein `&` in einem PowerShell-Befehl waere schlicht falsch. const ergebnis = platzhalterErsetzen( "Set-Name {{abteilung}}", { abteilung: "Forschung & Entwicklung" }, { art: "befehl", maskieren: (wert) => wert }, ); expect(ergebnis.text).toBe("Set-Name Forschung & Entwicklung"); }); it("lässt einen Wert für die Anzeige unverändert", () => { /* * Hier wird **nicht** HTML-maskiert: React maskiert Textknoten selbst, und * eine zweite Maskierung machte aus „Forschung & Entwicklung“ sichtbar * „Forschung & Entwicklung“. Dass die Maskierung wirklich * stattfindet, beweist tests/platzhalter-anzeige.test.tsx am gerenderten * HTML — nicht dieser Test hier. */ expect(platzhalterErsetzen("{{abteilung}}", { abteilung: "Forschung & Entwicklung" }).text).toBe( "Forschung & Entwicklung", ); }); }); describe("Generiertes Passwort", () => { const BEFEHL = '-AccountPassword "{{generiertes_passwort}}"'; it("erscheint im angezeigten Befehl", () => { const ergebnis = platzhalterErsetzen(BEFEHL, {}); expect(ergebnis.mitPasswort).toBe(true); expect(ergebnis.text).not.toContain("{{generiertes_passwort}}"); expect(ergebnis.text).toMatch(/-AccountPassword "\S{20}"/u); }); it("ist bei zwei Aufrufen verschieden", () => { // Akzeptanzkriterium: je Anzeige neu. Dasselbe Passwort zweimal waere eine // stillschweigende Speicherung. const erster = platzhalterErsetzen(BEFEHL, {}).text; const zweiter = platzhalterErsetzen(BEFEHL, {}).text; expect(erster).not.toBe(zweiter); }); it("steht in der Druckansicht als Hinweis statt als Passwort", () => { // Ein Ausdruck liegt herum – und das Passwort ist nirgends gespeichert, // also stuende dort ein Geheimnis, das niemand mehr zuordnen kann. const ergebnis = platzhalterErsetzen(BEFEHL, {}, { art: "druck" }); expect(ergebnis.text).toBe(`-AccountPassword "${PASSWORT_IM_DRUCK}"`); expect(ergebnis.mitPasswort).toBe(true); }); it("gibt das Passwort nicht neben dem Text zurück", () => { /* * Die harte Zusage des Meilensteins: es gibt **keinen** Weg, das erzeugte * Passwort ausser im Text zu bekommen. Gaebe es ein Feld dafuer, waere die * Versuchung gross, es „nur fuers Protokoll“ mitzuschreiben. */ const ergebnis = platzhalterErsetzen(BEFEHL, {}); expect(Object.keys(ergebnis).sort()).toEqual(["mitPasswort", "text", "unbekannt"]); expect(JSON.stringify(ergebnis)).not.toMatch(/passwort":\s*"[A-Za-z0-9]/u); }); it("meldet kein Passwort, wenn keines vorkam", () => { expect(platzhalterErsetzen("Hallo {{vorname}}", WERTE).mitPasswort).toBe(false); }); it("erzeugt für zwei Vorkommen im selben Text zwei verschiedene Passwörter", () => { /* * Fachlich fragwuerdig, aber die ehrliche Folge der Regel „bei jeder Anzeige * neu“: wer den Platzhalter zweimal in einen Befehl schreibt, meint * vermutlich dasselbe Passwort. Dass es zwei sind, faellt beim Lesen auf — * eines still zu speichern und wiederzuverwenden fiele nicht auf. */ const ergebnis = platzhalterErsetzen("{{generiertes_passwort}} und {{generiertes_passwort}}", {}); const [erstes, zweites] = ergebnis.text.split(" und "); expect(erstes).not.toBe(zweites); }); });