176 lines
7.1 KiB
TypeScript
176 lines
7.1 KiB
TypeScript
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);
|
||
});
|
||
});
|