using LehrerApp.Core.Models; using LehrerApp.Core.Services; using LehrerApp.Desktop.ViewModels.Planning; using Xunit; namespace LehrerApp.Desktop.Tests; public sealed class LessonSchedulingServiceTests { [Fact] public void UnitPicker_SchlaegtLaufendeEinheitVor_UndSpeichertNeuanlageNochNicht() { var groupId = Guid.NewGuid(); var planned = new Unit { GroupId = groupId, Title = "Später", Status = UnitStatus.Planned }; var active = new Unit { GroupId = groupId, Title = "Aktuell", Status = UnitStatus.Active }; var repo = new FakeUnits(); repo.Add(planned); repo.Add(active); var vm = new TimetableUnitPickerViewModel(repo, groupId, "10c", new(2026, 9, 2), 3); Assert.Equal(active.Id, vm.SelectedUnit?.Model.Id); vm.NewUnitTitle = "Neue Reihe"; vm.SaveCommand.Execute(null); Assert.True(vm.ResultIsNew); Assert.Equal("Neue Reihe", vm.Result?.Title); Assert.Null(repo.GetById(vm.Result!.Id)); } [Fact] public void Move_AendertDatumUndStunde_UndRuecktNurNichtDurchgefuehrteFolgestundenNach() { var unitId = Guid.NewGuid(); var groupId = Guid.NewGuid(); var moved = new Lesson { UnitId = unitId, GroupId = groupId, Date = new(2026, 9, 1), LessonNumber = 2 }; var draftFollowing = new Lesson { UnitId = unitId, GroupId = groupId, Date = new(2026, 9, 3), Status = LessonStatus.Draft }; var conducted = new Lesson { UnitId = unitId, GroupId = groupId, Date = new(2026, 9, 4), Status = LessonStatus.Conducted }; var repo = new FakeLessons(); repo.Add(moved); repo.Add(draftFollowing); repo.Add(conducted); new LessonSchedulingService(repo).Move(moved, new(2026, 9, 8), 5, shiftFollowing: true); Assert.Equal(new DateOnly(2026, 9, 8), moved.Date); Assert.Equal(5, moved.LessonNumber); Assert.Equal(new DateOnly(2026, 9, 10), draftFollowing.Date); Assert.Equal(new DateOnly(2026, 9, 4), conducted.Date); } [Fact] public void Move_RuecktAuchAusgefalleneFolgestundenNichtNach() { var unitId = Guid.NewGuid(); var groupId = Guid.NewGuid(); var moved = new Lesson { UnitId = unitId, GroupId = groupId, Date = new(2026, 9, 1) }; var cancelledFollowing = new Lesson { UnitId = unitId, GroupId = groupId, Date = new(2026, 9, 4), Status = LessonStatus.Cancelled }; var repo = new FakeLessons(); repo.Add(moved); repo.Add(cancelledFollowing); new LessonSchedulingService(repo).Move(moved, new(2026, 9, 8), null, shiftFollowing: true); Assert.Equal(new DateOnly(2026, 9, 4), cancelledFollowing.Date); } [Fact] public void SplitAndMoveSecondPart_AusgefalleneQuellstundeSetztFortsetzungAufEntwurfZurueck() { var source = new Lesson { UnitId = Guid.NewGuid(), GroupId = Guid.NewGuid(), Date = new(2026, 9, 1), Status = LessonStatus.Cancelled, Phases = [new LessonPhaseStep { Name = "Einstieg", DurationMinutes = 60 }], }; var repo = new FakeLessons(); repo.Add(source); var continuation = new LessonSchedulingService(repo).SplitAndMoveSecondPart(source, 30, new(2026, 9, 3), 1, null); Assert.Equal(LessonStatus.Draft, continuation.Status); } [Fact] public void SplitAndMoveSecondPart_TeiltAuchEineUeberDieGrenzeLaufendePhase() { var source = new Lesson { UnitId = Guid.NewGuid(), GroupId = Guid.NewGuid(), Date = new(2026, 9, 1), LessonNumber = 3, Topic = "Fotosynthese", Homework = "Aufgabe 2", Phases = [ new LessonPhaseStep { Name = "Einstieg", DurationMinutes = 30 }, new LessonPhaseStep { Name = "Experiment", DurationMinutes = 30 }, new LessonPhaseStep { Name = "Sicherung", DurationMinutes = 20 }, ], }; var repo = new FakeLessons(); repo.Add(source); var continuation = new LessonSchedulingService(repo).SplitAndMoveSecondPart(source, 45, new(2026, 9, 3), 6, new TimeOnly(12, 15)); Assert.Equal([30, 15], source.Phases.Select(p => p.DurationMinutes)); Assert.Equal([15, 20], continuation.Phases.Select(p => p.DurationMinutes)); Assert.Equal("Fotosynthese – Fortsetzung", continuation.Topic); Assert.Null(source.Homework); Assert.Equal("Aufgabe 2", continuation.Homework); Assert.Equal(6, continuation.LessonNumber); } [Fact] public void Move_LehntBelegtenZielterminAb() { var groupId = Guid.NewGuid(); var source = new Lesson { GroupId = groupId, Date = new(2026, 9, 1), LessonNumber = 1 }; var occupied = new Lesson { GroupId = groupId, Date = new(2026, 9, 2), LessonNumber = 4 }; var repo = new FakeLessons(); repo.Add(source); repo.Add(occupied); var error = Assert.Throws(() => new LessonSchedulingService(repo).Move(source, occupied.Date, 4, false)); Assert.Contains("bereits eine Planung", error.Message); } }