Enhance school simulation management by introducing a new SchoolWeekDays option, allowing configuration of the number of working days in a week. Update the API to include school week days in responses and enhance documentation to reflect these changes. Revise UI components to support the new management features, ensuring a seamless user experience when hiring and assigning staff. Update localization strings for improved clarity and consistency across the application.
ci / server (push) Failing after 3m37s
ci / client (push) Successful in 13s

This commit is contained in:
Leonid Pershin
2026-08-19 00:47:09 +03:00
parent 94842ab192
commit 2ebc783585
38 changed files with 1837 additions and 208 deletions
@@ -0,0 +1,140 @@
namespace HSchool.Content.Tests;
public class CalendarTests
{
private readonly CatalogLoader _loader = new();
[Fact]
public void VanillaCore_LoadsDayFrameAndHolidays()
{
var catalog = LoadVanilla();
var frame = catalog.DayFrame;
Assert.NotNull(frame);
Assert.Equal("08:30", frame.FirstLesson);
Assert.Equal(7, frame.LessonCount);
Assert.Equal(45, frame.LessonMinutes);
Assert.Equal(10, frame.BreakMinutes);
Assert.Equal(3, frame.LongBreakAfter);
Assert.Equal(20, frame.LongBreakMinutes);
Assert.Equal("Учебный день", catalog.Label("ru", frame));
Assert.Equal("School day", catalog.Label("en", frame));
Assert.Equal("GymHall", catalog.Subjects["PhysicalEducation"].Room);
Assert.Equal("ComputerLab", catalog.Subjects["Informatics"].Room);
Assert.Null(catalog.Subjects["Mathematics"].Room);
Assert.True(catalog.Holidays.ContainsKey("SpringBreak"));
Assert.Equal(24, catalog.Holidays["SpringBreak"].Start.Day);
Assert.Equal(31, catalog.Holidays["SpringBreak"].End.Day);
}
[Fact]
public void Saturday_IsOutsideOnAFiveDayWeek()
{
var slot = SchoolDay.At(LoadVanilla(), new DateTime(2012, 3, 31, 10, 20, 0, DateTimeKind.Utc), weekDays: 5);
Assert.Equal(DaySlot.Outside, slot);
}
[Fact]
public void Holiday_IsOutsideEvenOnASevenDayWeek()
{
var slot = SchoolDay.At(LoadVanilla(), new DateTime(2012, 3, 31, 10, 20, 0, DateTimeKind.Utc), weekDays: 7);
Assert.Equal(DaySlot.Outside, slot);
}
[Fact]
public void WeekdaySchoolMorning_IsLessonThree()
{
var slot = SchoolDay.At(LoadVanilla(), new DateTime(2012, 4, 3, 10, 20, 0, DateTimeKind.Utc), weekDays: 5);
Assert.Equal(DaySlot.Lesson(3), slot);
}
[Fact]
public void WeekdayNight_IsOutside()
{
var slot = SchoolDay.At(LoadVanilla(), new DateTime(2012, 4, 3, 23, 0, 0, DateTimeKind.Utc), weekDays: 5);
Assert.Equal(DaySlot.Outside, slot);
}
[Fact]
public void SixDayWeek_MakesANonHolidaySaturdayASchoolDay()
{
var slot = SchoolDay.At(LoadVanilla(), new DateTime(2012, 4, 7, 10, 20, 0, DateTimeKind.Utc), weekDays: 6);
Assert.Equal(DaySlot.Lesson(3), slot);
}
[Fact]
public void WinterBreak_WrapsTheNewYear()
{
var catalog = LoadVanilla();
var inside = SchoolDay.At(catalog, new DateTime(2012, 1, 5, 10, 20, 0, DateTimeKind.Utc), weekDays: 5);
var after = SchoolDay.At(catalog, new DateTime(2012, 1, 16, 10, 20, 0, DateTimeKind.Utc), weekDays: 5);
Assert.Equal(DaySlot.Outside, inside);
Assert.Equal(DaySlot.Lesson(3), after);
}
[Fact]
public void BreakAfterLessonTwo_IsTenFifteen()
{
var slot = SchoolDay.At(LoadVanilla(), new DateTime(2012, 4, 3, 10, 15, 0, DateTimeKind.Utc), weekDays: 5);
Assert.Equal(DaySlot.BreakAfter(2), slot);
}
[Fact]
public void Subject_UnknownRoom_FailsTheCatalog()
{
var ex = Assert.Throws<ContentLoadException>(() => _loader.Load(
[CatalogLoader.CorePackId],
[
PackDocuments.Def(CatalogLoader.CorePackId, "skills", "math", """{ "defName": "Mathematics" }"""),
PackDocuments.Def(
CatalogLoader.CorePackId,
"subjects",
"pe",
"""
{
"defName": "PhysicalEducation",
"grades": { "min": 1, "max": 11 },
"hoursPerWeek": 3,
"room": "GhostHall",
"skills": [{ "skill": "Mathematics", "share": 1 }]
}
"""),
]));
Assert.Contains("GhostHall", ex.Message);
}
[Fact]
public void TwoConcreteDayFrames_FailTheCatalog()
{
var ex = Assert.Throws<ContentLoadException>(() => _loader.Load(
[CatalogLoader.CorePackId],
[
PackDocuments.Def(
CatalogLoader.CorePackId,
"dayframe",
"a",
"""{ "defName": "A", "firstLesson": "08:30", "lessonCount": 1, "lessonMinutes": 45 }"""),
PackDocuments.Def(
CatalogLoader.CorePackId,
"dayframe",
"b",
"""{ "defName": "B", "firstLesson": "08:30", "lessonCount": 1, "lessonMinutes": 45 }"""),
]));
Assert.Contains("DayFrameDef", ex.Message);
}
private DefCatalog LoadVanilla()
{
var root = Path.Combine(AppContext.BaseDirectory, "vanilla");
return _loader.Load([CatalogLoader.CorePackId], PackDocuments.FromDirectory(CatalogLoader.CorePackId, root));
}
}
@@ -31,6 +31,11 @@ public class PeopleDefTests
Assert.Equal(0.25f, catalog.StaffingRules.ExtraSubjectSurcharge);
Assert.Equal("Начальные классы", catalog.Label("ru", catalog.Subjects["PrimarySchool"]));
Assert.Equal("Primary", catalog.Label("en", catalog.Subjects["PrimarySchool"]));
Assert.NotNull(catalog.DayFrame);
Assert.Equal(3, catalog.DayFrame.LongBreakAfter);
Assert.Equal("GymHall", catalog.Subjects["PhysicalEducation"].Room);
Assert.Equal("ComputerLab", catalog.Subjects["Informatics"].Room);
Assert.Null(catalog.Subjects["Mathematics"].Room);
}
[Fact]
@@ -45,6 +45,10 @@ public class VanillaCoreTests
Assert.Equal(12, catalog.StaffingRules.PoolSize);
Assert.Equal(20, catalog.StaffingRules.BaseWeeklyHours);
Assert.Equal(0.25f, catalog.StaffingRules.ExtraSubjectSurcharge);
Assert.NotNull(catalog.DayFrame);
Assert.Equal("08:30", catalog.DayFrame.FirstLesson);
Assert.Equal(7, catalog.DayFrame.LessonCount);
Assert.Equal("GymHall", catalog.Subjects["PhysicalEducation"].Room);
Assert.Equal(2, map.Buildings.Count);
var homerooms = map.Rooms.Where(room => room.Def == "Classroom").ToList();
Assert.Equal(11, homerooms.Count);
@@ -84,6 +88,8 @@ public class VanillaCoreTests
keys.AddRange(Names(catalog.NameSets.Values));
keys.AddRange(Names(catalog.Subjects.Values));
keys.AddRange(Names(catalog.Staffing.Values));
keys.AddRange(Names(catalog.DayFrames.Values));
keys.AddRange(Names(catalog.Holidays.Values));
// Derived in code, so no def carries them.
keys.Add(BodyBuilds.Attribute);