namespace HSchool.Content.Tests; /// /// Two sittings instead of one crowded canteen: juniors eat after the third lesson, seniors after /// the fourth. The list also decides which breaks are long, because fifteen minutes of lunch do /// not fit into ten. /// public class LunchBreakTests { private readonly CatalogLoader _loader = new(); [Fact] public void VanillaCore_FeedsJuniorsAndSeniorsAtDifferentBreaks() { var frame = LoadVanilla().DayFrame!; Assert.Equal(2, frame.LunchBreaks.Count); Assert.Equal(3, SchoolDay.LunchBreakAfter(frame, year: 1)); Assert.Equal(3, SchoolDay.LunchBreakAfter(frame, year: 5)); Assert.Equal(4, SchoolDay.LunchBreakAfter(frame, year: 6)); Assert.Equal(4, SchoolDay.LunchBreakAfter(frame, year: 11)); } [Fact] public void EveryBreakSomebodyEatsIn_IsALongOne() { var frame = LoadVanilla().DayFrame!; Assert.True(SchoolDay.IsLongBreakAfter(frame, 3)); Assert.True(SchoolDay.IsLongBreakAfter(frame, 4)); Assert.False(SchoolDay.IsLongBreakAfter(frame, 2)); // The fourth break is twenty minutes now, so the fifth lesson starts at half past noon // rather than twenty past: the second sitting has to fit into the day. Assert.Equal(new TimeOnly(12, 30), SchoolDay.PeriodStart(frame, 5)); } [Fact] public void LunchWindow_IsOpenOnlyAtTheSittingOfThatParallel() { var frame = LoadVanilla().DayFrame!; Assert.True(SchoolDay.IsLunchWindow(frame, DaySlot.BreakAfter(3), year: 4)); Assert.False(SchoolDay.IsLunchWindow(frame, DaySlot.BreakAfter(4), year: 4)); Assert.False(SchoolDay.IsLunchWindow(frame, DaySlot.BreakAfter(3), year: 9)); Assert.True(SchoolDay.IsLunchWindow(frame, DaySlot.BreakAfter(4), year: 9)); // Staff belong to no parallel and can eat at either sitting; a lesson is never a window. Assert.True(SchoolDay.IsLunchWindow(frame, DaySlot.BreakAfter(3), year: null)); Assert.True(SchoolDay.IsLunchWindow(frame, DaySlot.BreakAfter(4), year: null)); Assert.False(SchoolDay.IsLunchWindow(frame, DaySlot.Lesson(3), year: 4)); } [Fact] public void ASittingAfterTheLastLesson_FailsTheCatalog() { var error = Assert.Throws(() => LoadWithSittings( """{ "afterLesson": 7, "gradeMin": 1, "gradeMax": 11 }""")); Assert.Contains("lunch break", error.Message, StringComparison.OrdinalIgnoreCase); } [Fact] public void TwoSittingsForTheSameParallel_FailTheCatalog() { var error = Assert.Throws(() => LoadWithSittings( """{ "afterLesson": 3, "gradeMin": 1, "gradeMax": 5 }, { "afterLesson": 4, "gradeMin": 5, "gradeMax": 11 }""")); Assert.Contains("two lunch breaks", error.Message, StringComparison.OrdinalIgnoreCase); } private DefCatalog LoadWithSittings(string sittings) => _loader.Load( [CatalogLoader.CorePackId], [ PackDocuments.Def( CatalogLoader.CorePackId, "dayframe", "day", $$""" { "defName": "Day", "firstLesson": "08:30", "lessonCount": 7, "lessonMinutes": 45, "breakMinutes": 10, "longBreakAfter": 3, "longBreakMinutes": 20, "lunchBreaks": [{{sittings}}] } """), ]); private DefCatalog LoadVanilla() { var root = Path.Combine(AppContext.BaseDirectory, "vanilla"); return _loader.Load([CatalogLoader.CorePackId], PackDocuments.FromDirectory(CatalogLoader.CorePackId, root)); } }