116 lines
5.4 KiB
C#
116 lines
5.4 KiB
C#
using LehrerApp.Core.Models;
|
|
using LehrerApp.Desktop.Services;
|
|
using LehrerApp.Desktop.ViewModels.Students;
|
|
using LehrerApp.Templating;
|
|
using Xunit;
|
|
|
|
namespace LehrerApp.Desktop.Tests;
|
|
|
|
public sealed class CreateLetterDialogViewModelTests : IDisposable
|
|
{
|
|
private readonly string _directory = Path.Combine(Path.GetTempPath(), $"lehrerapp-letter-vm-tests-{Guid.NewGuid():N}");
|
|
public CreateLetterDialogViewModelTests() => Directory.CreateDirectory(_directory);
|
|
|
|
[Fact]
|
|
public void OhneVorlage_KannKeinenBriefErzeugen()
|
|
{
|
|
var vm = Build(StudentWithContact("Sehr geehrte Frau Muster,"), new TemplateStore(_directory));
|
|
Assert.False(vm.CanGenerate);
|
|
Assert.Contains(vm.Issues, i => i.Message.Contains("Vorlage", StringComparison.OrdinalIgnoreCase));
|
|
}
|
|
|
|
[Fact]
|
|
public void VerwendeteBriefanredeFehlt_BlockiertErzeugung()
|
|
{
|
|
var vm = Build(StudentWithContact(null), StoreWithTemplate(
|
|
new PlaceholderDefinition("Anrede", PlaceholderType.Text, true)));
|
|
Assert.False(vm.CanGenerate);
|
|
Assert.Contains(vm.Issues, i => i.Message.Contains("Anrede", StringComparison.OrdinalIgnoreCase));
|
|
}
|
|
|
|
[Fact]
|
|
public void VollstaendigeDaten_ErzeugenFlachesPdf()
|
|
{
|
|
var store = StoreWithTemplate(new PlaceholderDefinition("Anrede", PlaceholderType.Text, true),
|
|
new PlaceholderDefinition("Datum", PlaceholderType.Date, true),
|
|
new PlaceholderDefinition("Brieftext", PlaceholderType.Multiline, true));
|
|
var vm = Build(StudentWithContact("Sehr geehrte Frau Muster,"), store);
|
|
vm.LetterText = "Dies ist der Inhalt.";
|
|
var output = Path.Combine(_directory, "Brief.pdf");
|
|
|
|
Assert.True(vm.Generate(output));
|
|
Assert.Equal("%PDF", System.Text.Encoding.ASCII.GetString(File.ReadAllBytes(output), 0, 4));
|
|
}
|
|
|
|
[Fact]
|
|
public void KonstanterPflichttext_BenoetigtKeineExterneEingabe()
|
|
{
|
|
var store = StoreWithTemplate(new PlaceholderDefinition("Brieftext", PlaceholderType.Multiline,
|
|
Required: true, IsConstant: true, ConstantValue: "Fest im Vorlagenpaket"));
|
|
var vm = Build(StudentWithContact("Sehr geehrte Frau Muster,"), store);
|
|
var output = Path.Combine(_directory, "Konstant.pdf");
|
|
|
|
Assert.True(vm.CanGenerate);
|
|
Assert.True(vm.Generate(output));
|
|
Assert.Equal("%PDF", System.Text.Encoding.ASCII.GetString(File.ReadAllBytes(output), 0, 4));
|
|
}
|
|
|
|
[Fact]
|
|
public void AdvancedContent_Anwesenheitskalender_WirdAlsDrawingGerendert()
|
|
{
|
|
var store = StoreWithTemplate(new PlaceholderDefinition(
|
|
StudentAttendanceCalendarDrawingBuilder.PlaceholderName, PlaceholderType.Drawing, true));
|
|
var drawing = StudentAttendanceCalendarDrawingBuilder.Build("Lena Beispiel", new DateOnly(2026, 9, 1), [], []);
|
|
var vm = new CreateLetterDialogViewModel(StudentWithContact("Sehr geehrte Frau Muster,"), store,
|
|
new QuestTemplateRenderer(), new FakeMemberships([]), new FakeGroups([]), _ => drawing);
|
|
var output = Path.Combine(_directory, "Kalender.pdf");
|
|
|
|
Assert.True(vm.UsesAttendanceCalendar);
|
|
vm.SetAttendanceCalendarOptions(new AttendanceCalendarOptions(
|
|
new DateOnly(2026, 8, 19), 3, AttendanceCalendarSize.Large));
|
|
Assert.True(vm.AttendanceCalendarConfigured);
|
|
Assert.Contains("August 2026", vm.AttendanceCalendarSummary);
|
|
Assert.Contains("3 Monate", vm.AttendanceCalendarSummary);
|
|
Assert.Contains("Groß", vm.AttendanceCalendarSummary);
|
|
Assert.True(vm.Generate(output));
|
|
Assert.Equal("%PDF", System.Text.Encoding.ASCII.GetString(File.ReadAllBytes(output), 0, 4));
|
|
}
|
|
|
|
private CreateLetterDialogViewModel Build(Student student, TemplateStore store) =>
|
|
new(student, store, new QuestTemplateRenderer(), new FakeMemberships([]), new FakeGroups([]));
|
|
|
|
private TemplateStore StoreWithTemplate(params PlaceholderDefinition[] definitions)
|
|
{
|
|
var source = Path.Combine(_directory, $"{Guid.NewGuid():N}.lavorlage");
|
|
var manifest = new TemplateManifest { Id = $"brief-{Guid.NewGuid():N}", Name = "Elternbrief", Placeholders = [.. definitions] };
|
|
var lines = new List<string> { "PAGE 210 297 mm" };
|
|
var y = 20;
|
|
foreach (var definition in definitions)
|
|
{
|
|
var element = definition.Type switch
|
|
{
|
|
PlaceholderType.Multiline => "TEXTBOX",
|
|
PlaceholderType.Drawing => "DRAWBOX",
|
|
_ => "TEXT",
|
|
};
|
|
lines.Add(element switch
|
|
{
|
|
"TEXTBOX" => $"TEXTBOX 20 {y} 170 80 ${definition.Name}",
|
|
"DRAWBOX" => $"DRAWBOX 20 {y} 170 80 ${definition.Name}",
|
|
_ => $"TEXT 20 {y} ${definition.Name}",
|
|
});
|
|
y += 20;
|
|
}
|
|
TemplatePackage.Create(source, manifest, string.Join('\n', lines), new Dictionary<string, byte[]>());
|
|
var store = new TemplateStore(Path.Combine(_directory, $"store-{Guid.NewGuid():N}")); store.Import(source); return store;
|
|
}
|
|
|
|
private static Student StudentWithContact(string? salutation) => new()
|
|
{
|
|
FirstName = "Lena", LastName = "Beispiel",
|
|
Contacts = [new Contact { Name = "Frau Muster", Relation = "Mutter", LetterSalutation = salutation,
|
|
Street = "Hauptstraße 1", PostalCode = "12345", City = "Musterstadt" }],
|
|
};
|
|
public void Dispose() { if (Directory.Exists(_directory)) Directory.Delete(_directory, true); }
|
|
}
|