using LehrerApp.Core.Interfaces; using LehrerApp.Core.Models; using LehrerApp.Core.Services; using Xunit; namespace LehrerApp.Tests; public sealed class GroupRolloverServiceTests { [Fact] public void RollOver_KopiertStammdatenUndErzeugtNeueGanzjaehrigeMitgliedschaften() { var source = new LearningGroup { Name = "8a", SchoolYear = "2025/26", GradeLevel = 8, Type = GroupType.Class, SubjectId = Guid.NewGuid(), GradingSystem = GradingSystem.Grades1To6, HoursPerWeek = 4, IsOwnClass = true, IsDifferentiated = true, }; var oldMembership = new GroupMembership { StudentId = Guid.NewGuid(), GroupId = source.Id, Period = MembershipPeriod.H2Only, JoinedAt = new DateOnly(2026, 2, 1), LeftAt = new DateOnly(2026, 7, 31), Niveau = Niveau.E, }; var groups = new MemoryGroups([source]); var memberships = new MemoryMemberships([oldMembership]); var schemes = new MemorySchemes(); schemes.Save(new GradingScheme { GroupId = source.Id, ExamsPercent = 40, ParticipationPercent = 50, OtherPercent = 10, }); var service = new GroupRolloverService(groups, memberships, schemes, new SchoolYearService()); var target = service.RollOver(source, new GroupRolloverRequest( "9a", "2026/27", 9, [oldMembership.Id], true, true)); Assert.Equal("9a", target.Name); Assert.Equal(source.SubjectId, target.SubjectId); Assert.Equal(source.HoursPerWeek, target.HoursPerWeek); Assert.True(target.IsOwnClass); Assert.True(target.IsDifferentiated); Assert.False(source.IsActive); var copied = Assert.Single(memberships.GetByGroup(target.Id)); Assert.NotEqual(oldMembership.Id, copied.Id); Assert.Equal(MembershipPeriod.FullYear, copied.Period); Assert.Equal(new DateOnly(2026, 8, 1), copied.JoinedAt); Assert.Null(copied.LeftAt); Assert.Equal(Niveau.E, copied.Niveau); var scheme = schemes.GetByGroup(target.Id); Assert.NotNull(scheme); Assert.Equal(40, scheme.ExamsPercent); Assert.NotEqual(schemes.GetByGroup(source.Id)!.Id, scheme.Id); } [Fact] public void RollOver_GleichnamigeGruppeImZieljahr_WirdAbgelehnt() { var subjectId = Guid.NewGuid(); var source = new LearningGroup { Name = "8a", SchoolYear = "2025/26", GradeLevel = 8, Type = GroupType.Class, SubjectId = subjectId, }; var existing = new LearningGroup { Name = "9a", SchoolYear = "2026/27", GradeLevel = 9, Type = GroupType.Class, SubjectId = subjectId, }; var membership = new GroupMembership { StudentId = Guid.NewGuid(), GroupId = source.Id }; var service = new GroupRolloverService( new MemoryGroups([source, existing]), new MemoryMemberships([membership]), new MemorySchemes(), new SchoolYearService()); var error = Assert.Throws(() => service.RollOver(source, new GroupRolloverRequest("9a", "2026/27", 9, [membership.Id], false, false))); Assert.Contains("bereits", error.Message); } private sealed class MemoryGroups(List items) : IGroupRepository { public LearningGroup? GetById(Guid id) => items.FirstOrDefault(g => g.Id == id); public List GetAll(bool includeInactive = false) => items.Where(g => includeInactive || g.IsActive).ToList(); public List GetBySchoolYear(string schoolYear, bool includeInactive = false) => items.Where(g => g.SchoolYear == schoolYear && (includeInactive || g.IsActive)).ToList(); public void Save(LearningGroup group) { items.RemoveAll(g => g.Id == group.Id); items.Add(group); } public void Delete(Guid id) => items.RemoveAll(g => g.Id == id); } private sealed class MemoryMemberships(List items) : IGroupMembershipRepository { public List GetByStudent(Guid studentId) => items.Where(m => m.StudentId == studentId).ToList(); public List GetByGroup(Guid groupId) => items.Where(m => m.GroupId == groupId).ToList(); public GroupMembership? GetByStudentAndGroup(Guid studentId, Guid groupId) => items.FirstOrDefault(m => m.StudentId == studentId && m.GroupId == groupId); public void Save(GroupMembership membership) { items.RemoveAll(m => m.Id == membership.Id); items.Add(membership); } public void Delete(Guid id) => items.RemoveAll(m => m.Id == id); } private sealed class MemorySchemes : IGradingSchemeRepository { private readonly List _items = []; public GradingScheme? GetByGroup(Guid groupId) => _items.FirstOrDefault(s => s.GroupId == groupId); public GradingScheme? GetDefaultForType(GroupType type) => _items.FirstOrDefault(s => s.GroupType == type); public void Save(GradingScheme scheme) { _items.RemoveAll(s => s.Id == scheme.Id); _items.Add(scheme); } public void Delete(Guid id) => _items.RemoveAll(s => s.Id == id); } }