import { describe, expect, it, vi } from "vitest"; import { HOSTNAME_HOECHSTLAENGE, NamensregelFehler, NamensregelnSchema, SAM_HOECHSTLAENGE, UNTERSCHEIDUNG_HOECHSTWERT, UNTERSCHEIDUNG_STELLEN, ZIELFORMATE, hatZaehler, kleinGefaltet, namenBilden, namenEindeutigBilden, transliterieren, } from "@/lib/namensregeln"; /** * Namensregeln, Transliteration und Zaehler (#012). * * Aus diesen Werten werden Befehle auf einem Domaenencontroller. Die Tests sind * deshalb nicht nur auf den guten Fall gerichtet, sondern vor allem darauf, dass * bei fehlenden Angaben **nichts** herauskommt und dass die Grenzen des Ziel- * systems eingehalten werden, auch wenn gekuerzt werden muss. */ /** Der Fall aus dem Akzeptanzkriterium — er kommt in mehreren Tests wieder. */ const JOERG = { vorname: "Jörg", nachname: "Müller-Lüdenscheid" } as const; const MIT_KUNDE = { ...JOERG, kundenkuerzel: "KND" } as const; describe("transliterieren", () => { it("faltet „Jörg Müller-Lüdenscheid“ und laesst den Bindestrich stehen", () => { expect(transliterieren("Jörg Müller-Lüdenscheid")).toBe("Joerg Mueller-Luedenscheid"); expect(kleinGefaltet("Jörg Müller-Lüdenscheid")).toBe("joerg mueller-luedenscheid"); }); it.each([ ["ä", "ae"], ["ö", "oe"], ["ü", "ue"], ["Ä", "Ae"], ["Ö", "Oe"], ["Ü", "Ue"], ["ß", "ss"], ["Straße", "Strasse"], ])("macht aus %s zwei Zeichen: %s", (ein, aus) => { expect(transliterieren(ein)).toBe(aus); }); it.each([ ["é", "e"], ["è", "e"], ["ç", "c"], ["ñ", "n"], ["å", "a"], ["ě", "e"], ["ą", "a"], ["Ş", "S"], ["René Ćosić", "Rene Cosic"], ])("entfernt den Akzent von %s", (ein, aus) => { expect(transliterieren(ein)).toBe(aus); }); it.each([ ["ł", "l"], ["Łukasz", "Lukasz"], ["ø", "o"], ["Øyvind", "Oyvind"], ["æ", "ae"], ["œ", "oe"], ["đ", "d"], ["þ", "th"], ["ı", "i"], ])("faltet %s, das Unicode nicht zerlegt, zu %s", (ein, aus) => { // Ohne eigene Tabelle fiele dieser Buchstabe als Nicht-ASCII ganz weg, und // aus „Kowalski“ wuerde „Kowaski“ — ein Anmeldename, der nie funktioniert. expect(transliterieren(ein)).toBe(aus); }); it("wirft alles uebrige Nicht-ASCII weg", () => { expect(transliterieren("Александр")).toBe(""); expect(transliterieren("李雷")).toBe(""); expect(transliterieren("Max 🎉 Mustermann")).toBe("Max Mustermann"); }); it("wirft Steuerzeichen weg, statt sie zu Leerzeichen zu machen", () => { // Ein Zeilenumbruch in einem Namen hat in einem Befehl nichts zu suchen. expect(transliterieren("Max\nMustermann")).toBe("MaxMustermann"); expect(transliterieren("Max\tMustermann")).toBe("MaxMustermann"); }); it("laesst reines ASCII unveraendert", () => { expect(transliterieren("Max Mustermann-Meier 1970")).toBe("Max Mustermann-Meier 1970"); }); it("kommt mit einer leeren Eingabe zurecht", () => { expect(transliterieren("")).toBe(""); expect(kleinGefaltet("")).toBe(""); }); it("faltet auch die zerlegte Schreibweise eines Umlauts zu zwei Zeichen", () => { // „ü“ kann als ein Zeichen oder als u + Trema ankommen — aus einer CSV-Datei // eines Mac kommt regelmaessig die zweite Form. Beide muessen `mueller` // ergeben, nicht einmal `mueller` und einmal `muller`. // `normalize("NFD")` macht aus dem einen Zeichen die zerlegte Form. Sie hier // als Fluchtfolge hinzuschreiben geht nicht: Prettier schreibt sie in das // unsichtbare Zeichen zurueck, und dann steht im Test etwas, was niemand sieht. expect(kleinGefaltet("Müller".normalize("NFD"))).toBe("mueller"); expect(kleinGefaltet("Müller")).toBe("mueller"); }); }); describe("namenBilden – die Akzeptanzkriterien aus #012", () => { it("bildet joerg.mueller-luedenscheid@firma.de", () => { expect(namenBilden("upn", "{vorname}.{nachname}@firma.de", JOERG)).toBe( "joerg.mueller-luedenscheid@firma.de", ); expect(namenBilden("mail", "{vorname}.{nachname}@firma.de", JOERG)).toBe( "joerg.mueller-luedenscheid@firma.de", ); }); it("bildet den sam jmuellerluedensch", () => { const sam = namenBilden("sam", "{v}{nachname}", JOERG); expect(sam).toBe("jmuellerluedensch"); // 17 Zeichen: 20 erlaubt das Active Directory, drei bleiben fuer die // Unterscheidung frei, damit ein zweiter Traeger desselben Namens den ersten // nicht umbenennt. expect(sam).toHaveLength(SAM_HOECHSTLAENGE - UNTERSCHEIDUNG_STELLEN); }); }); describe("namenBilden – Platzhalter", () => { it("setzt {v} auf den ersten Buchstaben des Vornamens", () => { expect(namenBilden("sam", "{v}", JOERG)).toBe("j"); expect(namenBilden("sam", "{v}.{nachname}", { vorname: "Ed", nachname: "Ng" })).toBe("e.ng"); }); it("nimmt fuer {v} den ersten Buchstaben, nicht das erste Zeichen", () => { expect(namenBilden("sam", "{v}{nachname}", { vorname: "'Abd al-Rahman", nachname: "Farouk" })).toBe( "afarouk", ); }); it("entfernt Leerzeichen aus zusammengesetzten Vornamen", () => { expect(namenBilden("sam", "{vorname}.{nachname}", { vorname: "Anna Lena", nachname: "Meier" })).toBe( "annalena.meier", ); }); it("setzt {kundenkuerzel} ein", () => { expect(namenBilden("hostname", "{kundenkuerzel}-PC-{nnn}", MIT_KUNDE, 7)).toBe("KND-PC-007"); }); it("richtet die Stellen des Zaehlers nach der Zahl der n", () => { expect(namenBilden("hostname", "PC{n}", MIT_KUNDE, 7)).toBe("PC7"); expect(namenBilden("hostname", "PC{nn}", MIT_KUNDE, 7)).toBe("PC07"); expect(namenBilden("hostname", "PC{nnnn}", MIT_KUNDE, 7)).toBe("PC0007"); expect(namenBilden("hostname", "PC{nnnn}", MIT_KUNDE, 1234)).toBe("PC1234"); }); it("liefert nichts, wenn die Zahl nicht in ihre Stellen passt", () => { // `{nn}` kann keine 100 tragen; ein Hostname mit einer Stelle mehr waere // ausserhalb der Regel, die der Admin aufgeschrieben hat. expect(namenBilden("hostname", "PC{nn}", MIT_KUNDE, 100)).toBeUndefined(); expect(namenBilden("hostname", "PC{nn}", MIT_KUNDE, -1)).toBeUndefined(); expect(namenBilden("hostname", "PC{nn}", MIT_KUNDE, 1.5)).toBeUndefined(); }); it("liefert nichts, wenn die Regel einen Zaehler braucht, aber keiner mitkommt", () => { // Die naechste freie Nummer kennt nur der Aufrufer. `001` zu raten hiesse // einen Hostnamen zu liefern, der schon an einem anderen Geraet haengt. expect(namenBilden("hostname", "{kundenkuerzel}-PC-{nnn}", MIT_KUNDE)).toBeUndefined(); }); it("liefert nichts bei zwei Zaehlern in einer Regel", () => { expect(namenBilden("hostname", "PC{nn}-{nn}", MIT_KUNDE, 7)).toBeUndefined(); }); }); describe("namenBilden – wenn etwas fehlt, kommt nichts heraus", () => { it.each([ ["keine Regel", undefined], ["null", null], ["leere Regel", ""], ["nur Leerzeichen", " "], ])("liefert bei %s nichts", (_fall, regel) => { expect(namenBilden("upn", regel, JOERG)).toBeUndefined(); }); it.each([ ["fehlender Nachname", { vorname: "Jörg" }], ["leerer Nachname", { vorname: "Jörg", nachname: "" }], ["Nachname nur aus Leerzeichen", { vorname: "Jörg", nachname: " " }], ["fehlender Vorname", { nachname: "Müller" }], ["null als Wert", { vorname: null, nachname: "Müller" }], ])("liefert bei %s nichts", (_fall, werte) => { expect(namenBilden("upn", "{vorname}.{nachname}@firma.de", werte)).toBeUndefined(); }); it("liefert nichts, wenn das Kundenkuerzel fehlt", () => { // Im Modus INTERN gibt es kein Kuerzel. Ein Hostname `-PC-001` waere // schlimmer als keiner: er sieht richtig aus. expect(namenBilden("hostname", "{kundenkuerzel}-PC-{nnn}", JOERG, 1)).toBeUndefined(); }); it("liefert nichts bei einem Platzhalter, den es nicht gibt", () => { expect(namenBilden("upn", "{vorname}.{abteilung}@firma.de", JOERG)).toBeUndefined(); expect(namenBilden("sam", "{titel}", JOERG)).toBeUndefined(); }); it("liefert nichts bei einem verunglueckten Platzhalter", () => { // Sonst faellt die Klammer beim Normalisieren weg und der Text bleibt: aus // `{Nachname}@firma.de` wuerde die Adresse `nachname@firma.de`, und die // sieht echt aus. expect(namenBilden("upn", "{Nachname}@firma.de", JOERG)).toBeUndefined(); expect(namenBilden("upn", "{NACHNAME}@firma.de", JOERG)).toBeUndefined(); expect(namenBilden("upn", "{vorname@firma.de", JOERG)).toBeUndefined(); expect(namenBilden("sam", "{vorname}}", JOERG)).toBeUndefined(); }); it("liefert nichts, wenn vom Namen nach der Faltung nichts bleibt", () => { expect(namenBilden("sam", "{v}{nachname}", { vorname: "###", nachname: "###" })).toBeUndefined(); expect(namenBilden("upn", "{nachname}@firma.de", { nachname: "###" })).toBeUndefined(); expect(namenBilden("sam", "{nachname}", { nachname: "李雷" })).toBeUndefined(); expect(namenBilden("hostname", "{nachname}", { nachname: "___" })).toBeUndefined(); }); it("liefert bei jedem Zielformat nichts, wenn die Regel fehlt", () => { for (const zielformat of ZIELFORMATE) { expect(namenBilden(zielformat, undefined, JOERG)).toBeUndefined(); } }); }); describe("namenBilden – Adressform fuer upn und mail", () => { it("schreibt klein", () => { expect(namenBilden("upn", "{vorname}@FIRMA.DE", JOERG)).toBe("joerg@firma.de"); expect(namenBilden("mail", "{NACHNAME}@firma.de", JOERG)).toBeUndefined(); }); it("laesst keine doppelten Punkte stehen", () => { expect(namenBilden("upn", "{vorname}..{nachname}@firma.de", JOERG)).toBe( "joerg.mueller-luedenscheid@firma.de", ); expect(namenBilden("upn", "{vorname}@firma..de", JOERG)).toBe("joerg@firma.de"); }); it("laesst keinen Punkt vor dem @ stehen", () => { expect(namenBilden("upn", "{vorname}.@firma.de", JOERG)).toBe("joerg@firma.de"); expect(namenBilden("upn", ".{vorname}@firma.de", JOERG)).toBe("joerg@firma.de"); }); it("verlangt genau ein @ und beide Haelften", () => { expect(namenBilden("upn", "{vorname}.{nachname}", JOERG)).toBeUndefined(); expect(namenBilden("upn", "{vorname}@{nachname}@firma.de", JOERG)).toBeUndefined(); expect(namenBilden("upn", "{vorname}@", JOERG)).toBeUndefined(); expect(namenBilden("upn", "@firma.de", JOERG)).toBeUndefined(); }); it("weist einen Namensbereich mit unbrauchbarer Stufe ab", () => { expect(namenBilden("upn", "{vorname}@firma.-de", JOERG)).toBeUndefined(); expect(namenBilden("upn", "{vorname}@firma.de-.x", JOERG)).toBeUndefined(); }); it("raeumt Bindestriche am Rand des Namensbereichs weg", () => { expect(namenBilden("upn", "{vorname}@-firma.de", JOERG)).toBe("joerg@firma.de"); expect(namenBilden("upn", "{vorname}@firma.de-", JOERG)).toBe("joerg@firma.de"); }); it("wirft Zeichen weg, die in einer Adresse nicht vorkommen duerfen", () => { // „Müller, Jörg“ aus einer CSV-Spalte, in der Vor- und Nachname zusammen // stehen: das Komma gehoert in keine Adresse. expect(namenBilden("mail", "{nachname}@firma.de", { nachname: "Mül,ler" })).toBe("mueller@firma.de"); }); it("kuerzt eine Adresse nicht", () => { // Eine gekuerzte Mail-Adresse ist keine Adresse, sie ist eine falsche. const lang = namenBilden("mail", "{vorname}.{nachname}@firma.de", { vorname: "Jörg", nachname: "Lüdenscheid".repeat(10), }); expect(lang?.length).toBeGreaterThan(100); expect(lang?.endsWith("@firma.de")).toBe(true); }); }); describe("namenBilden – sam", () => { it("laesst den Punkt stehen und den Bindestrich weg", () => { expect(namenBilden("sam", "{vorname}.{nachname}", JOERG)).toBe("joerg.muellerlued"); }); it("kuerzt am Ende auf die nutzbare Laenge", () => { const sam = namenBilden("sam", "{v}{nachname}", { vorname: "Jörg", nachname: "Lüdenscheid".repeat(20) }); expect(sam).toHaveLength(SAM_HOECHSTLAENGE - UNTERSCHEIDUNG_STELLEN); expect(sam?.startsWith("jluedenscheid")).toBe(true); }); it("laesst keinen Punkt am Ende stehen, auch nicht nach dem Kuerzen", () => { // Ein `sAMAccountName` mit Punkt am Ende ist unzulaessig; beim Kuerzen kann // er genau dort landen. const sam = namenBilden("sam", "{nachname}.{vorname}", { vorname: "Jörg", nachname: "Mueller-Luedensch", }); expect(sam).toBe("muellerluedensch"); expect(sam?.endsWith(".")).toBe(false); }); it("nimmt einen Namen aus einem Zeichen", () => { expect(namenBilden("sam", "{v}{nachname}", { vorname: "Ed", nachname: "Ng" })).toBe("eng"); expect(namenBilden("sam", "{vorname}", { vorname: "Ü" })).toBe("ue"); }); }); describe("namenBilden – hostname", () => { it("schreibt gross", () => { // Windows fuehrt den NetBIOS-Namen gross; stuende auf dem Aufkleber etwas // anderes als das Geraet meldet, sucht der naechste Techniker einen Fehler, // den es nicht gibt. expect(namenBilden("hostname", "{kundenkuerzel}-nb-{nnn}", MIT_KUNDE, 3)).toBe("KND-NB-003"); expect(namenBilden("hostname", "{vorname}", JOERG)).toBe("JOERG"); }); it("laesst Unterstrich und Punkt weg", () => { expect(namenBilden("hostname", "{kundenkuerzel}_PC_{nn}", MIT_KUNDE, 7)).toBe("KNDPC07"); expect(namenBilden("hostname", "{kundenkuerzel}.pc.{nn}", MIT_KUNDE, 7)).toBe("KNDPC07"); }); it("laesst keinen fuehrenden oder abschliessenden Bindestrich stehen", () => { expect(namenBilden("hostname", "-{kundenkuerzel}-", MIT_KUNDE)).toBe("KND"); expect(namenBilden("hostname", "{kundenkuerzel}--", MIT_KUNDE)).toBe("KND"); }); it("haelt die 15 Zeichen des NetBIOS-Namens ein und kuerzt nie in der Nummer", () => { // Das ist die gefaehrliche Stelle: wuerde am Ende gekuerzt, verschwaende die // Nummer, und zwei Geraete bekaemen denselben Namen. const hostname = namenBilden("hostname", "{nachname}-{nnn}", JOERG, 1); expect(hostname).toBe("MUELLER-LUED001"); expect(hostname).toHaveLength(HOSTNAME_HOECHSTLAENGE); expect(hostname?.endsWith("001")).toBe(true); }); it("behaelt die Nummer auch bei einem sehr langen Namen", () => { const hostname = namenBilden("hostname", "{nachname}-{nnnn}", { nachname: "Lüdenscheid".repeat(30) }, 42); expect(hostname).toHaveLength(HOSTNAME_HOECHSTLAENGE); expect(hostname?.endsWith("0042")).toBe(true); }); it("behaelt die Nummer auch, wenn sie nicht am Ende der Regel steht", () => { const hostname = namenBilden("hostname", "{nnn}-{nachname}", { nachname: "Lüdenscheid".repeat(30) }, 42); expect(hostname).toHaveLength(HOSTNAME_HOECHSTLAENGE); expect(hostname?.startsWith("042-")).toBe(true); }); it("haelt ohne Zaehler in der Regel den Vorrat fuer die Unterscheidung frei", () => { const hostname = namenBilden("hostname", "{nachname}", { nachname: "Lüdenscheid".repeat(5) }); expect(hostname).toHaveLength(HOSTNAME_HOECHSTLAENGE - UNTERSCHEIDUNG_STELLEN); }); it("liefert nichts, wenn die Nummer allein schon zu lang ist", () => { expect(namenBilden("hostname", "{nachname}-{nnnnnnnnnnnnnnnn}", JOERG, 1)).toBeUndefined(); }); }); describe("hatZaehler", () => { it.each([ ["{nnn}", true], ["{kundenkuerzel}-PC-{nnn}", true], ["PC{n}", true], ["{vorname}.{nachname}@firma.de", false], ["{nachname}", false], ["", false], ])("erkennt %s", (regel, erwartet) => { expect(hatZaehler(regel)).toBe(erwartet); }); }); describe("namenEindeutigBilden – mit Zaehler in der Regel", () => { it("nimmt die erste Nummer, wenn sie frei ist", async () => { const istVergeben = vi.fn(async () => false); await expect( namenEindeutigBilden("hostname", "{kundenkuerzel}-PC-{nnn}", MIT_KUNDE, istVergeben), ).resolves.toBe("KND-PC-001"); expect(istVergeben).toHaveBeenCalledTimes(1); expect(istVergeben).toHaveBeenCalledWith("KND-PC-001"); }); it("zaehlt weiter, solange Nummern vergeben sind", async () => { const vergeben = new Set(["KND-PC-001", "KND-PC-002"]); const istVergeben = vi.fn(async (kandidat: string) => vergeben.has(kandidat)); await expect( namenEindeutigBilden("hostname", "{kundenkuerzel}-PC-{nnn}", MIT_KUNDE, istVergeben), ).resolves.toBe("KND-PC-003"); expect(istVergeben).toHaveBeenCalledTimes(3); }); it("wirft, wenn der Vorrat der Regel erschoepft ist", async () => { const istVergeben = vi.fn(async () => true); // `{n}` gibt neun Nummern her. Danach ist die Regel zu eng — das ist eine // Einstellung, die geaendert werden muss, und keine Nummer, die man // erfinden darf. await expect(namenEindeutigBilden("hostname", "PC{n}", MIT_KUNDE, istVergeben)).rejects.toThrow( NamensregelFehler, ); expect(istVergeben).toHaveBeenCalledTimes(9); }); it("fragt nicht nach, wenn die Regel keinen Namen ergibt", async () => { const istVergeben = vi.fn(async () => false); await expect( namenEindeutigBilden("hostname", "{kundenkuerzel}-PC-{nnn}", JOERG, istVergeben), ).resolves.toBeUndefined(); expect(istVergeben).not.toHaveBeenCalled(); }); }); describe("namenEindeutigBilden – ohne Zaehler in der Regel", () => { it("liefert den Namen unveraendert, wenn er frei ist", async () => { const istVergeben = vi.fn(async () => false); await expect(namenEindeutigBilden("sam", "{v}{nachname}", JOERG, istVergeben)).resolves.toBe( "jmuellerluedensch", ); expect(istVergeben).toHaveBeenCalledTimes(1); }); it("haengt bei einer Kollision eine Unterscheidung an und bleibt in der Grenze", async () => { const vergeben = new Set(["jmuellerluedensch"]); const istVergeben = vi.fn(async (kandidat: string) => vergeben.has(kandidat)); const sam = await namenEindeutigBilden("sam", "{v}{nachname}", JOERG, istVergeben); expect(sam).toBe("jmuellerluedensch2"); expect(sam?.length).toBeLessThanOrEqual(SAM_HOECHSTLAENGE); }); it("bleibt auch bei dreistelliger Unterscheidung in den 20 Zeichen", async () => { // Die drei zurueckgehaltenen Stellen sind genau dafuer da. const istVergeben = vi.fn(async (kandidat: string) => kandidat !== "jmuellerluedensch999"); const sam = await namenEindeutigBilden("sam", "{v}{nachname}", JOERG, istVergeben); expect(sam).toBe("jmuellerluedensch999"); expect(sam).toHaveLength(SAM_HOECHSTLAENGE); }); it("setzt die Unterscheidung bei Adressen vor das @", async () => { const vergeben = new Set(["joerg.mueller-luedenscheid@firma.de"]); const istVergeben = vi.fn(async (kandidat: string) => vergeben.has(kandidat)); await expect( namenEindeutigBilden("upn", "{vorname}.{nachname}@firma.de", JOERG, istVergeben), ).resolves.toBe("joerg.mueller-luedenscheid2@firma.de"); }); it("bleibt beim Hostnamen in den 15 Zeichen", async () => { const istVergeben = vi.fn(async (kandidat: string) => kandidat.length < HOSTNAME_HOECHSTLAENGE); const hostname = await namenEindeutigBilden( "hostname", "{nachname}", { nachname: "Lüdenscheid".repeat(5) }, istVergeben, ); expect(hostname).toHaveLength(HOSTNAME_HOECHSTLAENGE); }); it("wirft, wenn auch alle Unterscheidungen vergeben sind", async () => { const istVergeben = vi.fn(async () => true); await expect(namenEindeutigBilden("sam", "{v}{nachname}", JOERG, istVergeben)).rejects.toThrow( NamensregelFehler, ); // Der Name selbst und die Zusaetze 2 bis 999. expect(istVergeben).toHaveBeenCalledTimes(UNTERSCHEIDUNG_HOECHSTWERT); }); it("fragt ohne Regel nicht nach", async () => { const istVergeben = vi.fn(async () => false); await expect(namenEindeutigBilden("sam", undefined, JOERG, istVergeben)).resolves.toBeUndefined(); await expect(namenEindeutigBilden("sam", " ", JOERG, istVergeben)).resolves.toBeUndefined(); expect(istVergeben).not.toHaveBeenCalled(); }); it("gibt einen Fehler der Vergabepruefung unveraendert weiter", async () => { const istVergeben = vi.fn(async () => { throw new Error("Datenbank nicht erreichbar"); }); await expect(namenEindeutigBilden("sam", "{v}{nachname}", JOERG, istVergeben)).rejects.toThrow( "Datenbank nicht erreichbar", ); }); }); describe("NamensregelnSchema", () => { it("nimmt die vier Zielformate und trimmt", () => { const gelesen = NamensregelnSchema.parse({ upn: " {vorname}.{nachname}@firma.de ", sam: "{v}{nachname}", mail: "{vorname}.{nachname}@firma.de", hostname: "{kundenkuerzel}-PC-{nnn}", }); expect(gelesen.upn).toBe("{vorname}.{nachname}@firma.de"); expect(gelesen.sam).toBe("{v}{nachname}"); }); it("nimmt ein leeres Objekt", () => { expect(NamensregelnSchema.parse({})).toEqual({}); }); it("weist eine zu lange Regel ab", () => { expect(NamensregelnSchema.safeParse({ upn: "x".repeat(201) }).success).toBe(false); }); }); describe("Hostnamen, die Windows ablehnt", () => { it("schlägt keinen reservierten Gerätenamen vor", () => { /* * `CON`, `PRN`, `NUL` und Geschwister sind die alten Geraetenamen von * MS-DOS. Ein Nachname „Con“ reicht, damit die Regel sie vorschlaegt — und * Windows nimmt den Computernamen dann nicht an. Gefunden im Review zu #012. */ for (const name of ["con", "prn", "aux", "nul", "com1", "lpt9"]) { expect(namenBilden("hostname", "{nachname}", { nachname: name }), name).toBeUndefined(); } // Mit etwas davor oder dahinter ist der Name in Ordnung. expect(namenBilden("hostname", "PC-{nachname}", { nachname: "con" })).toBe("PC-CON"); }); it("schlägt keinen rein numerischen Hostnamen vor", () => { // Er waere von einer IP-Adresse nicht zu unterscheiden; Windows lehnt ihn ab. expect(namenBilden("hostname", "{nachname}", { nachname: "12345" })).toBeUndefined(); expect(namenBilden("hostname", "{nnn}", {}, 1)).toBeUndefined(); expect(namenBilden("hostname", "PC-{nnn}", {}, 1)).toBe("PC-001"); }); });