/* Unit tests for split sentences covering splitSentences. It also guards the documented public contract and regression-sensitive edge cases. Not a contract source of truth — the module under test owns the authoritative behavior; fixtures are minimal scaffolding only. RFC-1311: Compass header sweep — declares the split suite's contract for test-file scaffold coverage. */ import { describe, expect, it } from "vitest"; import { splitSentences } from "@warpgogol/werkstatt-shared/semantic"; describe("splitSentences", () => { it("splits simple English sentences", () => { const result = splitSentences("Hello world. This is a test. Goodbye!", "en"); expect(result).toHaveLength(3); expect(result[0]).toBe("Hello world."); expect(result[1]).toBe("This is a test."); expect(result[2]).toBe("Goodbye!"); }); it("handles German abbreviations", () => { const result = splitSentences("Das ist z.B. ein Test. Das ist ein weiterer Satz.", "de"); expect(result).toHaveLength(2); expect(result[0]).toBe("Das ist z.B. ein Test."); expect(result[1]).toBe("Das ist ein weiterer Satz."); }); it("handles English abbreviations", () => { const result = splitSentences("Use e.g. this pattern. It works well.", "en"); expect(result).toHaveLength(2); expect(result[0]).toBe("Use e.g. this pattern."); expect(result[1]).toBe("It works well."); }); it("handles Ukrainian text", () => { const result = splitSentences("Це перше речення. Це друге речення.", "uk"); expect(result).toHaveLength(2); }); it("returns empty array for empty input", () => { expect(splitSentences("", "en")).toEqual([]); expect(splitSentences(" ", "en")).toEqual([]); }); it("handles single sentence without terminal punctuation", () => { const result = splitSentences("Just some text without ending", "en"); expect(result).toHaveLength(1); expect(result[0]).toBe("Just some text without ending"); }); it("does not split on decimal numbers", () => { const result = splitSentences("The price is 3.50 euros. That is cheap.", "en"); expect(result).toHaveLength(2); expect(result[0]).toBe("The price is 3.50 euros."); expect(result[1]).toBe("That is cheap."); }); it("does not split on URLs in Ukrainian text", () => { const result = splitSentences( "Дивіться https://my.raceresult.com/317721/results для деталей. Це друге речення.", "uk", ); expect(result).toHaveLength(2); expect(result[0]).toBe("Дивіться https://my.raceresult.com/317721/results для деталей."); expect(result[1]).toBe("Це друге речення."); }); it("does not split on URLs in German text", () => { const result = splitSentences( "Siehe https://my.raceresult.com/317721/results für Details. Das ist ein zweiter Satz.", "de", ); expect(result).toHaveLength(2); expect(result[0]).toBe("Siehe https://my.raceresult.com/317721/results für Details."); expect(result[1]).toBe("Das ist ein zweiter Satz."); }); it("splits at period before German umlaut", () => { const result = splitSentences( "Die Version wird festgehalten. Änderungen erfolgen gemäß § 15.", "de", ); expect(result).toHaveLength(2); expect(result[0]).toBe("Die Version wird festgehalten."); expect(result[1]).toBe("Änderungen erfolgen gemäß § 15."); }); it("does not split at numbered list markers", () => { const result = splitSentences( "1. Vorlage eines konkreten Angebots durch das Studio; 2. ausdrücklicher Annahme des Angebots durch den Kunden; 3. Auftragsbestätigung durch das Studio zustande.", "de", ); expect(result).toHaveLength(1); }); it("handles spaced German abbreviation z. B.", () => { const result = splitSentences( "Das Studio kann nicht wesentliche Prozesse (z. B. Werkzeuge) ändern. Der wesentliche Leistungsumfang kann nicht einseitig geändert werden.", "de", ); expect(result).toHaveLength(2); expect(result[0]).toBe("Das Studio kann nicht wesentliche Prozesse (z. B. Werkzeuge) ändern."); expect(result[1]).toBe("Der wesentliche Leistungsumfang kann nicht einseitig geändert werden."); }); it("does not split on German business abbreviation zzgl.", () => { const result = splitSentences( "€ 49 / Monat (zzgl. USt.) — entspricht 10 Monaten. Zwei Monate gratis.", "de", ); expect(result).toHaveLength(2); expect(result[0]).toBe("€ 49 / Monat (zzgl. USt.) — entspricht 10 Monaten."); expect(result[1]).toBe("Zwei Monate gratis."); }); it("does not split on German abbreviation inkl.", () => { const result = splitSentences( "Das Paket enthält Hosting (inkl. SSL-Zertifikat). Das ist ein guter Deal.", "de", ); expect(result).toHaveLength(2); expect(result[0]).toBe("Das Paket enthält Hosting (inkl. SSL-Zertifikat)."); expect(result[1]).toBe("Das ist ein guter Deal."); }); it("does not split on German abbreviation bzw.", () => { const result = splitSentences( "Rechnungen werden monatlich bzw. jährlich erstellt. Das ist fair.", "de", ); expect(result).toHaveLength(2); expect(result[0]).toBe("Rechnungen werden monatlich bzw. jährlich erstellt."); expect(result[1]).toBe("Das ist fair."); }); it("does not split on German abbreviation ggf.", () => { const result = splitSentences( "Der Kunde kann ggf. weitere Module buchen. Das ist optional.", "de", ); expect(result).toHaveLength(2); expect(result[0]).toBe("Der Kunde kann ggf. weitere Module buchen."); expect(result[1]).toBe("Das ist optional."); }); it("does not split on Ukrainian abbreviation тис.", () => { const result = splitSentences( "Вартість складає 5 тис. гривень на місяць. Це вигідна пропозиція.", "uk", ); expect(result).toHaveLength(2); expect(result[0]).toBe("Вартість складає 5 тис. гривень на місяць."); expect(result[1]).toBe("Це вигідна пропозиція."); }); it("does not split on Ukrainian abbreviation грн.", () => { const result = splitSentences("Ціна: 1000 грн. за місяць. Друге речення.", "uk"); expect(result).toHaveLength(2); expect(result[0]).toBe("Ціна: 1000 грн. за місяць."); expect(result[1]).toBe("Друге речення."); }); });