namespace HSchool.People.Tests; public class YearlyIntakeTests { private static readonly DateTime September = new(2012, 9, 1, 0, 0, 0, DateTimeKind.Utc); [Fact] public void DatesBetween_SkipsAStartAlreadyOnFirstSeptember() { var start = new DateTime(2012, 9, 1, 0, 0, 0, DateTimeKind.Utc); Assert.Empty(YearlyIntake.DatesBetween(start, start.AddMinutes(1))); Assert.Equal( [new DateTime(2012, 9, 1, 0, 0, 0, DateTimeKind.Utc)], YearlyIntake.DatesBetween(new DateTime(2012, 4, 3, 6, 0, 0, DateTimeKind.Utc), start)); } [Fact] public void FourClassrooms_GraduatesTheOldestYearNotEleventh() { var map = Fixtures.Classrooms(4); var catalog = Fixtures.Catalog(); var before = Fixtures.Generate(map); Assert.Equal(4, before.Classes.Max(schoolClass => schoolClass.Year)); Assert.DoesNotContain(before.Classes, schoolClass => schoolClass.Year == 11); var after = YearlyIntake.Apply(catalog, before, Fixtures.SchoolSeed, "Russia", September); var demand = SchoolDemand.From(catalog, map); Assert.True(RosterFit.Matches(after, demand)); Assert.Equal(before.People.Count(person => person.IsStudent), after.People.Count(person => person.IsStudent)); Assert.Equal(before.Classes.Sum(schoolClass => schoolClass.Capacity), after.Classes.Sum(schoolClass => schoolClass.Capacity)); Assert.Equal(4, after.Classes.Max(schoolClass => schoolClass.Year)); Assert.Contains(after.Classes, schoolClass => schoolClass.Year == 1); Assert.All(after.Classes, schoolClass => Assert.Equal(schoolClass.Capacity, schoolClass.PupilIds.Count)); var graduated = before.Classes .Where(schoolClass => schoolClass.Year == 4) .SelectMany(schoolClass => schoolClass.PupilIds) .ToHashSet(StringComparer.Ordinal); Assert.All(graduated, id => Assert.DoesNotContain(after.People, person => person.Id == id)); } [Fact] public void SameInputs_YieldTheSameIntake() { var map = Fixtures.Classrooms(4); var catalog = Fixtures.Catalog(); var before = Fixtures.Generate(map); var a = Snapshot(YearlyIntake.Apply(catalog, before, Fixtures.SchoolSeed, "Russia", September)); var b = Snapshot(YearlyIntake.Apply(catalog, before, Fixtures.SchoolSeed, "Russia", September)); Assert.Equal(a, b); } [Fact] public void NewFirstYear_CanShareAFamilyWithAnOlderPupil() { var map = Fixtures.Classrooms(4); var catalog = Fixtures.Catalog(); var before = Fixtures.Generate(map); var after = YearlyIntake.Apply(catalog, before, Fixtures.SchoolSeed, "Russia", September); var people = after.People.ToDictionary(person => person.Id, StringComparer.Ordinal); var yearOf = after.Classes.ToDictionary(schoolClass => schoolClass.Id, schoolClass => schoolClass.Year, StringComparer.Ordinal); Assert.Contains(after.Families, family => { var years = family.ChildIds .Select(id => people[id]) .Where(person => person.IsStudent && person.ClassId is not null) .Select(person => yearOf[person.ClassId!]) .ToHashSet(); return years.Contains(1) && years.Any(year => year > 1); }); } [Fact] public void ParentsOfOnlyGraduates_LeaveUnlessTheyWorkHere() { var map = Fixtures.Classrooms(4); var catalog = Fixtures.Catalog(); var before = Fixtures.Generate(map); var people = before.People.ToDictionary(person => person.Id, StringComparer.Ordinal); var graduating = before.Classes .Where(schoolClass => schoolClass.Year == 4) .SelectMany(schoolClass => schoolClass.PupilIds) .ToHashSet(StringComparer.Ordinal); var shouldLeave = new List(); var staffWhoStay = new List(); foreach (var family in before.Families) { if (family.ChildIds.Count == 0 || family.ChildIds.Any(id => !graduating.Contains(id))) { continue; } foreach (var parentId in family.ParentIds) { if (people[parentId].IsStaff) { staffWhoStay.Add(parentId); } else { shouldLeave.Add(parentId); } } } var after = YearlyIntake.Apply(catalog, before, Fixtures.SchoolSeed, "Russia", September); var afterIds = after.People.Select(person => person.Id).ToHashSet(StringComparer.Ordinal); Assert.NotEmpty(shouldLeave); Assert.All(shouldLeave, id => Assert.DoesNotContain(id, afterIds)); Assert.All(staffWhoStay, id => Assert.Contains(id, afterIds)); Assert.All( after.People.Where(person => staffWhoStay.Contains(person.Id)), person => Assert.False(person.IsParent)); } private static string Snapshot(Roster roster) => string.Join('\n', roster.People.Select(person => $"{person.Id}|{person.FamilyId}|{person.IsStudent}|{person.IsStaff}|{person.IsParent}|{person.ClassId}|{person.Name.Full}|{Skills(person)}")); private static string Skills(Person person) => string.Join(',', person.Skills.OrderBy(pair => pair.Key, StringComparer.Ordinal).Select(pair => $"{pair.Key}={pair.Value}")); }