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>
116 lines
4.6 KiB
C#
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);
|
|
}
|
|
}
|