Files
Leonid Pershin 5eabc90d53
ci / server (push) Failing after 3m43s
ci / client (push) Successful in 15s
Enhance school day structure and decision-making for lunch breaks
- Updated `ai.md` to clarify the mechanics of hunger restoration and the importance of lunch breaks in the school schedule.
- Revised `schedule.md` to detail the new lunch break structure, allowing for separate sittings for different grade levels.
- Enhanced `Decision.cs` and `DecisionPlanner.cs` to incorporate logic for lunch breaks, ensuring that students only leave lessons during their designated lunch windows.
- Updated `DayFrameDef` and related classes to support multiple lunch breaks and validate their configurations.
- Adjusted tests to validate the new decision-making logic regarding lunch breaks and hunger management, ensuring robust functionality.
- Improved localization strings to reflect changes in the school day structure and lunch functionalities.
2026-08-19 23:17:16 +03:00

100 lines
3.9 KiB
C#

namespace HSchool.Content.Tests;
/// <summary>
/// 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.
/// </summary>
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<ContentLoadException>(() => LoadWithSittings(
"""{ "afterLesson": 7, "gradeMin": 1, "gradeMax": 11 }"""));
Assert.Contains("lunch break", error.Message, StringComparison.OrdinalIgnoreCase);
}
[Fact]
public void TwoSittingsForTheSameParallel_FailTheCatalog()
{
var error = Assert.Throws<ContentLoadException>(() => 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));
}
}