using LehrerApp.Core.Models; using LehrerApp.Desktop.Services.Mcp.Tools; using LehrerApp.Templating; using Xunit; namespace LehrerApp.Desktop.Tests; public sealed class LetterTemplateToolsTests : IDisposable { private readonly string _directory = Path.Combine(Path.GetTempPath(), $"lehrerapp-lettertools-tests-{Guid.NewGuid():N}"); public LetterTemplateToolsTests() => Directory.CreateDirectory(_directory); public void Dispose() { if (Directory.Exists(_directory)) Directory.Delete(_directory, true); } private LetterTemplateTools BuildTool(TemplateStore store, FakeStudents? students = null, FakeGroups? groups = null) => new(store, new TemplateLoader(), new QuestTemplateRenderer(), students ?? new FakeStudents([]), groups ?? new FakeGroups([])); private TemplateStore StoreWithTemplate(string name, params PlaceholderDefinition[] definitions) { var source = Path.Combine(_directory, $"{Guid.NewGuid():N}.lavorlage"); var manifest = new TemplateManifest { Id = $"brief-{Guid.NewGuid():N}", Name = name, Placeholders = [.. definitions] }; var lines = new List { "PAGE 210 297 mm" }; var y = 20; foreach (var definition in definitions) { var element = definition.Type == PlaceholderType.Multiline ? "TEXTBOX" : "TEXT"; lines.Add(element == "TEXTBOX" ? $"TEXTBOX 20 {y} 170 80 ${definition.Name}" : $"TEXT 20 {y} ${definition.Name}"); y += 20; } TemplatePackage.Create(source, manifest, string.Join('\n', lines), new Dictionary()); var store = new TemplateStore(Path.Combine(_directory, $"store-{Guid.NewGuid():N}")); store.Import(source); return store; } private static Student StudentWithContact(string? salutation = "Sehr geehrte Frau Muster,") => new() { FirstName = "Lena", LastName = "Beispiel", Contacts = [new Contact { Name = "Frau Muster", Relation = "Mutter", LetterSalutation = salutation, Street = "Hauptstraße 1", PostalCode = "12345", City = "Musterstadt", }], }; [Fact] public void ListLetterTemplates_ListetVorlageMitPlatzhaltern() { var store = StoreWithTemplate("Elternbrief", new PlaceholderDefinition("Anrede", PlaceholderType.Text, true)); var tool = BuildTool(store); var result = Assert.Single(tool.ListLetterTemplates()); Assert.Equal("Elternbrief", result.Name); Assert.Contains(result.Placeholders, p => p.Name == "Anrede" && p.Required); } [Fact] public void RenderLetter_UnbekannteVorlage_LiefertFehler() { var student = StudentWithContact(); var tool = BuildTool(new TemplateStore(_directory), new FakeStudents([student])); var result = tool.RenderLetter("nicht-vorhanden", student.Id, "Text", "Frau Lehrer"); Assert.False(result.Success); Assert.Null(result.Base64Pdf); } [Fact] public void RenderLetter_UnbekannterSchueler_LiefertFehler() { var store = StoreWithTemplate("Elternbrief", new PlaceholderDefinition("Anrede", PlaceholderType.Text, true)); var installed = Assert.Single(store.GetTemplates()); var tool = BuildTool(store); var result = tool.RenderLetter(installed.Id, Guid.NewGuid(), "Text", "Frau Lehrer"); Assert.False(result.Success); } [Fact] public void RenderLetter_PflichtplatzhalterFehlt_LiefertFehlerOhnePdf() { var store = StoreWithTemplate("Elternbrief", new PlaceholderDefinition("Anrede", PlaceholderType.Text, true)); var installed = Assert.Single(store.GetTemplates()); var student = StudentWithContact(salutation: null); // keine Anrede hinterlegt var tool = BuildTool(store, new FakeStudents([student])); var result = tool.RenderLetter(installed.Id, student.Id, "Text", "Frau Lehrer"); Assert.False(result.Success); Assert.Contains("Anrede", result.Message); Assert.Null(result.Base64Pdf); } [Fact] public void RenderLetter_VollstaendigeDaten_LiefertBase64Pdf() { var store = StoreWithTemplate("Elternbrief", new PlaceholderDefinition("Anrede", PlaceholderType.Text, true), new PlaceholderDefinition("Datum", PlaceholderType.Date, true), new PlaceholderDefinition("Brieftext", PlaceholderType.Multiline, true)); var installed = Assert.Single(store.GetTemplates()); var student = StudentWithContact(); var tool = BuildTool(store, new FakeStudents([student])); var result = tool.RenderLetter(installed.Id, student.Id, "Dies ist der Inhalt.", "Frau Lehrer"); Assert.True(result.Success); Assert.NotNull(result.Base64Pdf); var bytes = Convert.FromBase64String(result.Base64Pdf!); Assert.Equal("%PDF", System.Text.Encoding.ASCII.GetString(bytes, 0, 4)); Assert.Equal("Elternbrief_Beispiel_Lena.pdf", result.SuggestedFileName); } [Fact] public void RenderLetter_ExtraValues_FuelltZusaetzlichenPlatzhalter() { var store = StoreWithTemplate("Elternbrief", new PlaceholderDefinition("Anrede", PlaceholderType.Text, true), new PlaceholderDefinition("Betreff", PlaceholderType.Text, true)); var installed = Assert.Single(store.GetTemplates()); var student = StudentWithContact(); var tool = BuildTool(store, new FakeStudents([student])); var result = tool.RenderLetter(installed.Id, student.Id, "Text", "Frau Lehrer", extraValues: new Dictionary { ["Betreff"] = "Elternabend" }); Assert.True(result.Success); Assert.NotNull(result.Base64Pdf); } }