Files
LehrerApp/LehrerApp.Desktop.Tests/GenerateLessonSeriesDialogViewModelTests.cs
T
adminandClaude Sonnet 5 f73bd6c9ec Sitzungen (3.3): aus Stunde erzeugen, löschen, Kalenderüberblick; Doppelstunden-Bugfix Serienerzeugung
Kapitel 3.3: neuer Button erzeugt eine Mitarbeitssitzung aus einer geplanten
Stunde (Datum/Thema, dupl.-sicher über Lesson.LessonId), Sitzungen lassen
sich jetzt mit Rückfrage bei vorhandenen Bewertungen löschen, und der
Dashboard-Kalender zeigt Sitzungen als dritten Termintyp neben Stunden/
Klausuren. Das Bearbeiten von Sitzungen war bereits vorhanden (undokumentiert
aus früherer Ad-hoc-Arbeit) und wird hier nur nachgezogen.

Bugfix: "Serie erzeugen" legte für Doppelstunden zwei Lessons mit gleichem
Datum an statt einer, da jede Stundenplan-Periode einzeln behandelt wurde.
Folgeperioden werden jetzt der Lesson der ersten Periode zugerechnet.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-19 22:17:46 +02:00

184 lines
7.7 KiB
C#

using LehrerApp.Core.Models;
using LehrerApp.Core.Services;
using LehrerApp.Desktop.ViewModels.Groups;
using Xunit;
namespace LehrerApp.Desktop.Tests;
/// Tests für die Serienerzeugung von Stunden aus dem Stundenplan (4.2.5).
public sealed class GenerateLessonSeriesDialogViewModelTests
{
private static GenerateLessonSeriesDialogViewModel BuildVm(FakeTimetableSlots slots, FakeLessons lessons,
FakeSchoolHolidays holidays, Guid unitId, Guid groupId, DateOnly? from = null, DateOnly? to = null)
{
// Bewusst kein "using": SchoolCalendarSettingsService liest den Pfad nur bei Bedarf.
var tempPath = System.IO.Path.Combine(
System.IO.Path.GetTempPath(), $"lehrerapp-lessonseries-tests-{Guid.NewGuid():N}");
Directory.CreateDirectory(tempPath);
var vm = new GenerateLessonSeriesDialogViewModel(slots, lessons, holidays,
new PublicHolidayService(), new SchoolCalendarSettingsService(tempPath), unitId, groupId, null, null);
if (from is not null) vm.FromDateText = from.Value.ToString("dd.MM.yyyy");
if (to is not null) vm.ToDateText = to.Value.ToString("dd.MM.yyyy");
return vm;
}
[Fact]
public void Save_ErzeugtStundeProVorkommenDesWochentagsImZeitraum()
{
var groupId = Guid.NewGuid();
var unitId = Guid.NewGuid();
var from = new DateOnly(2025, 9, 1);
var to = from.AddDays(13); // deckt zwei Vorkommen des Wochentags von "from" ab (Tag 0 und 7)
var slots = new FakeTimetableSlots();
slots.Add(new TimetableSlot { GroupId = groupId, Weekday = from.DayOfWeek, PeriodNumber = 1 });
var lessons = new FakeLessons();
var vm = BuildVm(slots, lessons, new FakeSchoolHolidays(), unitId, groupId, from, to);
vm.SaveCommand.Execute(null);
Assert.NotNull(vm.Result);
Assert.Equal(2, vm.Result!.Created);
Assert.Equal(0, vm.Result.SkippedHoliday);
Assert.Equal(0, vm.Result.SkippedExisting);
Assert.All(lessons.GetByGroupAndRange(groupId, from, to), l => Assert.Equal(unitId, l.UnitId));
}
[Fact]
public void Save_UeberspringtTerminInSchulferien()
{
var groupId = Guid.NewGuid();
var unitId = Guid.NewGuid();
var from = new DateOnly(2025, 9, 1);
var to = from.AddDays(13);
var secondOccurrence = from.AddDays(7);
var slots = new FakeTimetableSlots();
slots.Add(new TimetableSlot { GroupId = groupId, Weekday = from.DayOfWeek, PeriodNumber = 1 });
var holidays = new FakeSchoolHolidays();
holidays.Add(new SchoolHoliday { Name = "Ferien", StartDate = secondOccurrence, EndDate = secondOccurrence.AddDays(3) });
var vm = BuildVm(slots, new FakeLessons(), holidays, unitId, groupId, from, to);
vm.SaveCommand.Execute(null);
Assert.Equal(1, vm.Result!.Created);
Assert.Equal(1, vm.Result.SkippedHoliday);
}
[Fact]
public void Save_UeberspringtBereitsVorhandeneStundeAmSelbenDatumUndPeriode()
{
var groupId = Guid.NewGuid();
var unitId = Guid.NewGuid();
var from = new DateOnly(2025, 9, 1);
var to = from.AddDays(13);
var slots = new FakeTimetableSlots();
slots.Add(new TimetableSlot { GroupId = groupId, Weekday = from.DayOfWeek, PeriodNumber = 1 });
var lessons = new FakeLessons();
lessons.Add(new Lesson { UnitId = Guid.NewGuid(), GroupId = groupId, Date = from, LessonNumber = 1, Topic = "Bestehend" });
var vm = BuildVm(slots, lessons, new FakeSchoolHolidays(), unitId, groupId, from, to);
vm.SaveCommand.Execute(null);
Assert.Equal(1, vm.Result!.Created);
Assert.Equal(1, vm.Result.SkippedExisting);
Assert.Equal(2, lessons.GetByGroupAndRange(groupId, from, to).Count); // 1 alt + 1 neu
}
[Fact]
public void Save_Doppelstunde_ErzeugtNurEineStundeVerankertAnDerErstenPeriode()
{
var groupId = Guid.NewGuid();
var unitId = Guid.NewGuid();
var from = new DateOnly(2025, 9, 1);
var slots = new FakeTimetableSlots();
slots.Add(new TimetableSlot { GroupId = groupId, Weekday = from.DayOfWeek, PeriodNumber = 3 });
slots.Add(new TimetableSlot { GroupId = groupId, Weekday = from.DayOfWeek, PeriodNumber = 4 });
var lessons = new FakeLessons();
var vm = BuildVm(slots, lessons, new FakeSchoolHolidays(), unitId, groupId, from, from);
vm.SaveCommand.Execute(null);
Assert.Equal(1, vm.Result!.Created);
var created = lessons.GetByGroupAndRange(groupId, from, from).Select(l => l.LessonNumber).ToList();
Assert.Equal([3], created);
}
[Fact]
public void Save_Dreifachstunde_ErzeugtNurEineStundeVerankertAnDerErstenPeriode()
{
var groupId = Guid.NewGuid();
var unitId = Guid.NewGuid();
var from = new DateOnly(2025, 9, 1);
var slots = new FakeTimetableSlots();
slots.Add(new TimetableSlot { GroupId = groupId, Weekday = from.DayOfWeek, PeriodNumber = 3 });
slots.Add(new TimetableSlot { GroupId = groupId, Weekday = from.DayOfWeek, PeriodNumber = 4 });
slots.Add(new TimetableSlot { GroupId = groupId, Weekday = from.DayOfWeek, PeriodNumber = 5 });
var lessons = new FakeLessons();
var vm = BuildVm(slots, lessons, new FakeSchoolHolidays(), unitId, groupId, from, from);
vm.SaveCommand.Execute(null);
Assert.Equal(1, vm.Result!.Created);
var created = lessons.GetByGroupAndRange(groupId, from, from).Select(l => l.LessonNumber).ToList();
Assert.Equal([3], created);
}
[Fact]
public void Save_ZweiGetrennteEinzelstundenAmSelbenTagBleibenGetrennt()
{
// Perioden 1 und 3 sind NICHT aufeinanderfolgend (Periode 2 fehlt) — keine Doppelstunde,
// beide bekommen eine eigene Lesson.
var groupId = Guid.NewGuid();
var unitId = Guid.NewGuid();
var from = new DateOnly(2025, 9, 1);
var slots = new FakeTimetableSlots();
slots.Add(new TimetableSlot { GroupId = groupId, Weekday = from.DayOfWeek, PeriodNumber = 1 });
slots.Add(new TimetableSlot { GroupId = groupId, Weekday = from.DayOfWeek, PeriodNumber = 3 });
var lessons = new FakeLessons();
var vm = BuildVm(slots, lessons, new FakeSchoolHolidays(), unitId, groupId, from, from);
vm.SaveCommand.Execute(null);
Assert.Equal(2, vm.Result!.Created);
var created = lessons.GetByGroupAndRange(groupId, from, from).Select(l => l.LessonNumber).OrderBy(n => n).ToList();
Assert.Equal([1, 3], created);
}
[Fact]
public void Save_OhneStundenplanEintrag_SetztFehlerUndErzeugtNichts()
{
var groupId = Guid.NewGuid();
var vm = BuildVm(new FakeTimetableSlots(), new FakeLessons(), new FakeSchoolHolidays(), Guid.NewGuid(), groupId,
new DateOnly(2025, 9, 1), new DateOnly(2025, 9, 14));
vm.SaveCommand.Execute(null);
Assert.Null(vm.Result);
Assert.NotEqual("", vm.DateError);
}
[Fact]
public void Save_UngueltigesDatumsformat_SetztFehler()
{
var vm = BuildVm(new FakeTimetableSlots(), new FakeLessons(), new FakeSchoolHolidays(), Guid.NewGuid(), Guid.NewGuid());
vm.FromDateText = "keinDatum";
vm.SaveCommand.Execute(null);
Assert.Null(vm.Result);
Assert.NotEqual("", vm.DateError);
}
[Fact]
public void Save_EndeVorBeginn_SetztFehler()
{
var vm = BuildVm(new FakeTimetableSlots(), new FakeLessons(), new FakeSchoolHolidays(), Guid.NewGuid(), Guid.NewGuid(),
new DateOnly(2025, 9, 10), new DateOnly(2025, 9, 1));
vm.SaveCommand.Execute(null);
Assert.Null(vm.Result);
Assert.NotEqual("", vm.DateError);
}
}