Stundenplan verbesserung
CI / build-and-test (push) Canceled after 0s

This commit is contained in:
2026-08-30 00:53:32 +02:00
parent 2b299fc940
commit dade41ee8d
16 changed files with 639 additions and 75 deletions
@@ -0,0 +1,90 @@
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 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<InvalidOperationException>(() =>
new LessonSchedulingService(repo).Move(source, occupied.Date, 4, false));
Assert.Contains("bereits eine Planung", error.Message);
}
}
@@ -277,7 +277,23 @@ public sealed class TimetableViewModelTests
Assert.Equal(group.Id, navigatedTo);
Assert.False(viewerOpened);
Assert.Equal("Zur Lerngruppe", vm.TodayItems[0].OpenButtonLabel);
Assert.Equal("Stunde anlegen", vm.TodayItems[0].OpenButtonLabel);
}
[Fact]
public async Task OpenTodayLesson_OhneLesson_StartetDirektanlageMitExaktemTermin()
{
var today = DateOnly.FromDateTime(DateTime.Today);
var group = new LearningGroup { Name = "Q1 Chemie" };
var slots = new FakeTimetableSlots();
slots.Add(new TimetableSlot { GroupId = group.Id, Weekday = today.DayOfWeek, PeriodNumber = 4 });
var vm = BuildViewModel(slots, new FakeGroups([group]));
TimetableLessonRequest? requested = null;
vm.OnCreateLesson = request => { requested = request; return Task.CompletedTask; };
await vm.OpenTodayLessonCommand.ExecuteAsync(vm.TodayItems[0]);
Assert.Equal(new TimetableLessonRequest(group.Id, today, 4), requested);
}
// ── Unterrichtsmodus (14.x) ────────────────────────────────────────────────