using LehrerApp.Templating; using Xunit; namespace LehrerApp.Templating.Tests; public sealed class ConstantPlaceholderTests { [Fact] public void Resolver_KonstanterWertUeberschreibtExternenWert() { var manifest = new TemplateManifest { Placeholders = [new("Hinweis", PlaceholderType.Multiline, true, true, "Interner Langtext")], }; var external = new Dictionary { ["Hinweis"] = new MultilineValue("Extern manipuliert") }; var resolved = TemplateDataResolver.Resolve(manifest, external); Assert.Equal("Interner Langtext", Assert.IsType(resolved["Hinweis"]).Value); } [Fact] public void Renderer_BenoetigtFuerKonstantenPflichtwertKeineExternenDatenUndUnterstuetztHervorhebung() { var manifest = new TemplateManifest { Id = "konstant", Name = "Konstant", Placeholders = [new("Hinweis", PlaceholderType.Multiline, true, true, "Dieser Text lebt im Paket.", Bold: true, Italic: true, Underline: true)], }; var layout = new LayoutParser().Parse("PAGE 210 297 mm\nTEXTBOX 20 20 170 50 $Hinweis size=11"); var template = new LoadedTemplate(manifest, layout, new Dictionary()); var pdf = new QuestTemplateRenderer().RenderToPdf(template, new EmptyProvider()); Assert.Equal("%PDF", System.Text.Encoding.ASCII.GetString(pdf, 0, 4)); } [Fact] public void Validate_BehandeltKonstantenPflichtwertAlsInternErfuellt() { var manifest = new TemplateManifest { Placeholders = [ new("Intern", PlaceholderType.Text, true, true, "Fest"), new("Extern", PlaceholderType.Text, true), ], }; var template = new LoadedTemplate(manifest, new(210, 297, "mm", []), new Dictionary()); var result = new TemplateLoader().Validate(template, new Dictionary()); Assert.Single(result.Issues); Assert.Contains("Extern", result.Issues[0].Message); } [Fact] public void PaketRoundtrip_BehaeltKonstantenWertUndTextformatierung() { var path = Path.Combine(Path.GetTempPath(), $"constant-{Guid.NewGuid():N}.lavorlage"); try { var manifest = new TemplateManifest { Id = "konstant", Name = "Konstant", Placeholders = [new("Baustein", PlaceholderType.Text, false, true, "Fest im Paket", Bold: true, Italic: false, Underline: true)], }; TemplatePackage.Create(path, manifest, "PAGE 210 297 mm\nTEXT 20 20 $Baustein", new Dictionary()); var definition = Assert.Single(new TemplateLoader().LoadFromPackage(path).Manifest.Placeholders); Assert.True(definition.IsConstant); Assert.Equal("Fest im Paket", definition.ConstantValue); Assert.True(definition.Bold); Assert.True(definition.Underline); } finally { if (File.Exists(path)) File.Delete(path); } } [Fact] public void RichTextParser_UnterstuetztVerschachtelteHervorhebungUndExternePlatzhalter() { var runs = TemplateRichText.Parse("Hallo [b]Familie [i]${Student.LastName}[/i][/b]!"); var placeholder = Assert.Single(runs, x => x.IsPlaceholder); Assert.Equal("Student.LastName", placeholder.Placeholder); Assert.True(placeholder.Bold); Assert.True(placeholder.Italic); Assert.False(placeholder.Underline); Assert.Throws(() => TemplateRichText.Parse("[b]nicht geschlossen")); } [Fact] public void ExternerWertWirdImKonstantenRichTextNichtAlsMarkupInterpretiert() { var manifest = new TemplateManifest { Id = "sicher", Name = "Sicher", Placeholders = [ new("Baustein", PlaceholderType.Multiline, true, true, "Sehr geehrte Familie [b]${Student.LastName}[/b],"), new("Student.LastName", PlaceholderType.Text, true), ], }; var template = new LoadedTemplate(manifest, new LayoutParser().Parse("PAGE 210 297 mm\nTEXTBOX 20 20 170 50 $Baustein"), new Dictionary()); var provider = new ValuesProvider(new Dictionary { ["Student.LastName"] = new TextValue("[u]nicht als Markup geƶffnet") }); var pdf = new QuestTemplateRenderer().RenderToPdf(template, provider); Assert.Equal("%PDF", System.Text.Encoding.ASCII.GetString(pdf, 0, 4)); } [Fact] public void KonstantenValidierung_MeldetNichtDeklarierteEingebettetePlatzhalter() { var manifest = new TemplateManifest { Placeholders = [new("Baustein", PlaceholderType.Text, false, true, "Hallo ${Unbekannt}")], }; var issue = Assert.Single(TemplateDataResolver.ValidateConstants(manifest)); Assert.Contains("Unbekannt", issue); } private sealed class EmptyProvider : ITemplateDataProvider { public IReadOnlyDictionary GetValues() => new Dictionary(); } private sealed class ValuesProvider(IReadOnlyDictionary values) : ITemplateDataProvider { public IReadOnlyDictionary GetValues() => values; } }