Files
LehrerApp/LehrerApp.Templating.Tests/ExamCoverTemplatingTests.cs
T
adminandClaude Opus 5.5 dd92128464 Klausur-Deckblätter als Sammel-PDF aus Vorlagen vom Typ exam-cover
Neuer Dialog "Deckblätter…" bei Klausuren, Punktetabelle als Drawing mit
festen Spaltenbreiten, FLOWDRAWBOX-Attribut fit=content, Stapel-Rendering
mit Seitenzahl je Datensatz, Kursbezeichnung und konfigurierbares Kürzel.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 10:39:09 +02:00

116 lines
4.6 KiB
C#

using LehrerApp.Templating;
using Xunit;
namespace LehrerApp.Templating.Tests;
public sealed class ExamCoverTemplatingTests : IDisposable
{
private readonly string _appData = Path.Combine(Path.GetTempPath(), $"lavorlage-cover-{Guid.NewGuid():N}");
private const string FlowLayout = """
PAGE 210 297 mm
#pragma format-version 3
#pragma page-template first
#pragma flow-slot body x=20 y=20 w=170 h=250
#pragma end-page-template
#pragma content-flow body
FLOWDRAWBOX $Tabelle w=170 h=100 {0}
TEXT "DANACH" size=11
#pragma end-content-flow
""";
private static readonly DrawingValue ShortDrawing = new(
[new DrawStringEx(0, 0, 12, 170, "TABELLE", DrawingTextAlignment.AlignLeft, 10)], 20);
[Fact]
public void FlowDrawBox_FitContent_NachfolgendesElementRuecktAnDenInhalt()
{
var fixedHeight = TextTop(Render("", ShortDrawing), "DANACH");
var fitted = TextTop(Render("fit=content", ShortDrawing), "DANACH");
// PDF-Koordinaten wachsen nach oben: 100 mm Box gegen 20 mm Inhalt = 80 mm höher.
Assert.Equal(80 * 72 / 25.4, fitted - fixedHeight, 0);
}
[Fact]
public void FlowDrawBox_FitContent_LangerInhaltFliesstWeiterhinUeberVolleAusschnitte()
{
var drawing = new DrawingValue(
[
new DrawStringEx(0, 0, 12, 170, "OBEN", DrawingTextAlignment.AlignLeft, 10),
new DrawStringEx(0, 105, 12, 170, "UNTEN", DrawingTextAlignment.AlignLeft, 10),
], 120);
using var document = UglyToad.PdfPig.PdfDocument.Open(Render("fit=content", drawing));
var text = document.GetPage(1).Text;
Assert.Contains("OBEN", text);
Assert.Contains("UNTEN", text);
Assert.Contains("DANACH", text);
}
[Fact]
public void FlowDrawBox_UnbekannterFitWert_IstEinLayoutfehler() =>
Assert.Throws<TemplateValidationException>(() =>
new LayoutParser().Parse("PAGE 210 297 mm\nFLOWDRAWBOX 20 20 170 100 $Tabelle fit=page"));
[Fact]
public void RenderBatchToPdf_FuegtDatensaetzeZusammenUndMeldetSeitenzahlen()
{
var template = Template("fit=content");
var tall = new DrawingValue(
[new DrawStringEx(0, 290, 12, 170, "LANG", DrawingTextAlignment.AlignLeft, 10)], 300);
var result = new QuestTemplateRenderer().RenderBatchToPdf(template,
[
new DictionaryProvider(new Dictionary<string, PlaceholderValue> { ["Tabelle"] = ShortDrawing }),
new DictionaryProvider(new Dictionary<string, PlaceholderValue> { ["Tabelle"] = tall }),
]);
using var document = UglyToad.PdfPig.PdfDocument.Open(result.Pdf);
Assert.Equal([1, 2], result.PageCounts);
Assert.Equal(3, document.NumberOfPages);
Assert.Contains("TABELLE", document.GetPage(1).Text);
}
[Fact]
public void TemplateStore_LiestVorlagentypAusDenMetadaten()
{
var store = new TemplateStore(_appData);
var cover = Path.Combine(_appData, "cover.lavorlage");
var letter = Path.Combine(_appData, "letter.lavorlage");
TemplatePackage.Create(cover, new TemplateManifest
{
Id = "deckblatt", Name = "Deckblatt",
Metadata = new(StringComparer.OrdinalIgnoreCase) { [TemplateMetadataKeys.ReportType] = TemplateReportTypes.ExamCover },
}, "PAGE 210 297 mm\nTEXT 20 20 \"Text\"", new Dictionary<string, byte[]>());
TemplatePackage.Create(letter, new TemplateManifest { Id = "brief", Name = "Brief" },
"PAGE 210 297 mm\nTEXT 20 20 \"Text\"", new Dictionary<string, byte[]>());
Assert.True(store.Import(cover).IsExamCover);
store.Import(letter);
Assert.Equal(["deckblatt"], store.GetTemplates().Where(x => x.IsExamCover).Select(x => x.Id));
}
private static LoadedTemplate Template(string attributes) => new(new TemplateManifest
{
Placeholders = [new("Tabelle", PlaceholderType.Drawing, true)],
}, new LayoutParser().Parse(FlowLayout.Replace("{0}", attributes)), new Dictionary<string, byte[]>());
private static byte[] Render(string attributes, DrawingValue drawing) =>
new QuestTemplateRenderer().RenderToPdf(Template(attributes),
new DictionaryProvider(new Dictionary<string, PlaceholderValue> { ["Tabelle"] = drawing }));
private static double TextTop(byte[] pdf, string word)
{
using var document = UglyToad.PdfPig.PdfDocument.Open(pdf);
return document.GetPage(1).GetWords().Single(x => x.Text == word).BoundingBox.Top;
}
public void Dispose()
{
if (Directory.Exists(_appData)) Directory.Delete(_appData, recursive: true);
}
}