QuestPDF-Vorlagensystem und Designer hinzufügen
CI / build-and-test (push) Canceled after 0s

This commit is contained in:
2026-08-30 15:37:22 +02:00
parent a088823b30
commit 2f2761caf8
40 changed files with 2177 additions and 738 deletions
@@ -0,0 +1,76 @@
using LehrerApp.TemplateDesigner;
using Xunit;
namespace LehrerApp.TemplateDesigner.Tests;
public sealed class AssetManagementTests
{
private static readonly byte[] OnePixelPng = Convert.FromBase64String(
"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNk+A8AAQUBAScY42YAAAAASUVORK5CYII=");
[Fact]
public void Import_ZeigtMetadatenUndBenenntKollisionenUm()
{
var viewModel = new DesignerViewModel();
var first = viewModel.ImportAsset("mein logo.png", OnePixelPng);
var second = viewModel.ImportAsset("mein logo.png", OnePixelPng);
Assert.Equal("mein-logo.png", first.Name);
Assert.Equal("mein-logo-2.png", second.Name);
Assert.Equal("1 × 1 px", first.Dimensions);
Assert.Equal(2, viewModel.AssetItems.Count);
}
[Fact]
public void AlsImageEinfuegen_VerwendetKoordinatenUndAktualisiertReferenzzaehler()
{
var viewModel = new DesignerViewModel
{ NewX = "15", NewY = "18", NewWidth = "32", NewHeight = "14" };
viewModel.ImportAsset("logo.png", OnePixelPng);
viewModel.InsertSelectedAssetAsImage();
Assert.Contains("IMG logo.png 15 18 32 14 scale=100%", viewModel.LayoutSource);
Assert.Equal(1, viewModel.SelectedAsset!.UsageCount);
}
[Fact]
public void AlsImageEinfuegen_SchreibtProzentualeSkalierung()
{
var viewModel = new DesignerViewModel { NewImageScale = "37,5" };
viewModel.ImportAsset("logo.png", OnePixelPng);
viewModel.InsertSelectedAssetAsImage();
Assert.Contains("scale=37.5%", viewModel.LayoutSource);
}
[Fact]
public void Entfernen_LoeschtAssetUndAlleLayoutReferenzen()
{
var viewModel = new DesignerViewModel();
viewModel.ImportAsset("logo.png", OnePixelPng);
viewModel.InsertSelectedAssetAsImage();
viewModel.RemoveSelectedAsset();
Assert.Empty(viewModel.AssetItems);
Assert.Empty(viewModel.Assets);
Assert.DoesNotContain("IMG logo.png", viewModel.LayoutSource);
}
[Fact]
public void Ersetzen_BehältDateinamenUndLayoutReferenzen()
{
var viewModel = new DesignerViewModel();
viewModel.ImportAsset("logo.png", OnePixelPng);
viewModel.InsertSelectedAssetAsImage();
viewModel.ReplaceSelectedAsset(OnePixelPng);
Assert.Equal("logo.png", Assert.Single(viewModel.AssetItems).Name);
Assert.Contains("IMG logo.png", viewModel.LayoutSource);
Assert.Equal(1, viewModel.SelectedAsset!.UsageCount);
}
}
@@ -0,0 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup><IsPackable>false</IsPackable></PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\LehrerApp.TemplateDesigner\LehrerApp.TemplateDesigner.csproj" />
<PackageReference Include="Microsoft.NET.Test.Sdk" />
<PackageReference Include="xunit" />
<PackageReference Include="xunit.runner.visualstudio"><PrivateAssets>all</PrivateAssets></PackageReference>
</ItemGroup>
</Project>
@@ -0,0 +1,80 @@
using LehrerApp.TemplateDesigner;
using LehrerApp.Templating;
using Xunit;
namespace LehrerApp.TemplateDesigner.Tests;
public sealed class StarterTemplateLibraryTests : IDisposable
{
private readonly string _directory = Path.Combine(Path.GetTempPath(), $"starter-library-{Guid.NewGuid():N}");
public StarterTemplateLibraryTests() => Directory.CreateDirectory(_directory);
[Fact]
public void SpeichernUndAktualisieren_VerwendetStabileIdUndErsetztInhalt()
{
var library = new StarterTemplateLibrary(_directory);
var manifest = Manifest("briefkopf", "Briefkopf");
library.Save(manifest, "PAGE 210 297 mm\nTEXT 10 10 \"Version 1\"", EmptyAssets());
library.Save(manifest, "PAGE 210 297 mm\nTEXT 10 10 \"Version 2\"", EmptyAssets());
var item = Assert.Single(library.GetAll());
var (_, layout) = library.Load(item);
Assert.Equal("briefkopf", item.Id);
Assert.Contains("Version 2", layout);
Assert.DoesNotContain("Version 1", layout);
}
[Fact]
public void Duplizieren_ErzeugtUnabhaengigeIdUndLaesstOriginalUnveraendert()
{
var library = new StarterTemplateLibrary(_directory);
var original = library.Save(Manifest("briefkopf", "Briefkopf"),
"PAGE 210 297 mm", EmptyAssets());
var firstCopy = library.Duplicate(original);
var secondCopy = library.Duplicate(original);
Assert.Equal("briefkopf-kopie", firstCopy.Id);
Assert.Equal("briefkopf-kopie-2", secondCopy.Id);
Assert.Equal(3, library.GetAll().Count);
Assert.Equal("Briefkopf", library.Load(original).Template.Manifest.Name);
}
[Fact]
public void ImportUndExport_UebertragenPortablesPaket()
{
var sourceLibrary = new StarterTemplateLibrary(Path.Combine(_directory, "source"));
var targetLibrary = new StarterTemplateLibrary(Path.Combine(_directory, "target"));
var item = sourceLibrary.Save(Manifest("kopf", "Schulbriefkopf"), "PAGE 210 297 mm", EmptyAssets());
var exported = Path.Combine(_directory, "export.lavorlage");
sourceLibrary.Export(item, exported);
var imported = targetLibrary.Import(exported);
Assert.Equal("kopf", imported.Id);
Assert.Equal("Schulbriefkopf", Assert.Single(targetLibrary.GetAll()).Name);
}
[Fact]
public void AlsNeuesProjekt_BehaeltLayoutUndVergibtNeueMetadaten()
{
var library = new StarterTemplateLibrary(_directory);
var item = library.Save(Manifest("kopf", "Schulbriefkopf"),
"PAGE 210 297 mm\nTEXT 10 10 \"Schule\"", EmptyAssets());
var (template, layout) = library.Load(item);
var viewModel = new DesignerViewModel();
viewModel.LoadAsNewProject(template, layout);
Assert.Equal("kopf-neu", viewModel.TemplateId);
Assert.Equal("Schulbriefkopf - Neu", viewModel.TemplateName);
Assert.Contains("Schule", viewModel.LayoutSource);
Assert.Equal("kopf", library.Load(item).Template.Manifest.Id);
}
private static TemplateManifest Manifest(string id, string name) => new()
{ Id = id, Name = name, Description = "Wiederverwendbarer Ausgangspunkt" };
private static IReadOnlyDictionary<string, byte[]> EmptyAssets() => new Dictionary<string, byte[]>();
public void Dispose() { if (Directory.Exists(_directory)) Directory.Delete(_directory, true); }
}