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.
This commit is contained in:
@@ -26,6 +26,7 @@ public class SchoolApiTests(AppHostFixture fixture)
|
||||
// creation form would offer the wrong hour.
|
||||
Assert.Equal(DateTimeKind.Utc, state.DefaultStartDate.Kind);
|
||||
Assert.Equal(5d, state.GameMinutesPerRealSecond);
|
||||
Assert.Equal(5, state.SchoolWeekDays);
|
||||
Assert.Empty(state.Schools);
|
||||
}
|
||||
|
||||
@@ -167,6 +168,16 @@ public class SchoolApiTests(AppHostFixture fixture)
|
||||
Assert.Equal(16, classroom.DefaultSeats);
|
||||
Assert.Empty(classroom.Slots);
|
||||
Assert.Empty(classroom.Positions);
|
||||
Assert.NotNull(ru.DayFrame);
|
||||
Assert.Equal("08:30", ru.DayFrame.FirstLesson);
|
||||
Assert.Equal(7, ru.DayFrame.LessonCount);
|
||||
Assert.Equal(3, ru.DayFrame.LongBreakAfter);
|
||||
Assert.Equal("Учебный день", ru.DayFrame.Label);
|
||||
Assert.NotNull(en.DayFrame);
|
||||
Assert.Equal("School day", en.DayFrame.Label);
|
||||
Assert.Equal("GymHall", Assert.Single(ru.Subjects, subject => subject.DefName == "PhysicalEducation").Room);
|
||||
Assert.Null(Assert.Single(ru.Subjects, subject => subject.DefName == "Mathematics").Room);
|
||||
Assert.Contains(ru.Holidays, holiday => holiday.DefName == "SpringBreak");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -347,6 +358,7 @@ public class SchoolApiTests(AppHostFixture fixture)
|
||||
int MaxSchools,
|
||||
DateTime DefaultStartDate,
|
||||
double GameMinutesPerRealSecond,
|
||||
int SchoolWeekDays,
|
||||
IReadOnlyList<SchoolResponse> Schools);
|
||||
|
||||
private sealed record RandomNameResponse(string Name);
|
||||
@@ -367,6 +379,8 @@ public class SchoolApiTests(AppHostFixture fixture)
|
||||
IReadOnlyList<DefInfoResponse> Things,
|
||||
IReadOnlyList<DefInfoResponse> NameSets,
|
||||
IReadOnlyList<SubjectInfoResponse> Subjects,
|
||||
DayFrameResponse? DayFrame,
|
||||
IReadOnlyList<HolidayInfoResponse> Holidays,
|
||||
MapLayoutResponse DefaultMap);
|
||||
|
||||
private sealed record DefInfoResponse(string DefName, string Label);
|
||||
@@ -382,7 +396,19 @@ public class SchoolApiTests(AppHostFixture fixture)
|
||||
|
||||
private sealed record RoomSlotResponse(string Key, string Thing);
|
||||
|
||||
private sealed record SubjectInfoResponse(string DefName, string Label);
|
||||
private sealed record SubjectInfoResponse(string DefName, string Label, string? Room);
|
||||
|
||||
private sealed record DayFrameResponse(
|
||||
string DefName,
|
||||
string Label,
|
||||
string FirstLesson,
|
||||
int LessonCount,
|
||||
int LessonMinutes,
|
||||
int BreakMinutes,
|
||||
int LongBreakAfter,
|
||||
int LongBreakMinutes);
|
||||
|
||||
private sealed record HolidayInfoResponse(string DefName, string Label);
|
||||
|
||||
private sealed record MapLayoutResponse(TerritoryResponse? Territory);
|
||||
|
||||
|
||||
@@ -33,6 +33,46 @@ public class StaffingApiTests(AppHostFixture fixture)
|
||||
Assert.Empty(staffing.Staff);
|
||||
Assert.Contains(staffing.Uncovered, subject => subject.DefName == "Mathematics");
|
||||
Assert.Contains(staffing.Uncovered, subject => subject.DefName == "PrimarySchool");
|
||||
Assert.NotEmpty(staffing.Positions);
|
||||
Assert.Contains(staffing.Positions, position => position.DefName == "Teacher");
|
||||
Assert.Contains(staffing.Subjects, subject => subject.DefName == "Mathematics");
|
||||
Assert.All(staffing.Applicants, applicant => Assert.NotEmpty(applicant.Skills));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Card_OpensAGeneratedApplicant()
|
||||
{
|
||||
using var client = fixture.App.CreateHttpClient("server");
|
||||
await SchoolApiTests.ResetAsync(client);
|
||||
var school = await SchoolApiTests.CreateAsync(client, "Штат карточка пула", Start);
|
||||
var staffing = await GetStaffingAsync(client, school.Id);
|
||||
var generated = staffing.Applicants.First(applicant => !applicant.IsParent);
|
||||
|
||||
var card = await client.GetFromJsonAsync<PersonCardResponse>(
|
||||
$"/api/schools/{school.Id}/people/{Uri.EscapeDataString(generated.Id)}?lang=ru",
|
||||
TestContext.Current.CancellationToken);
|
||||
Assert.NotNull(card);
|
||||
Assert.Equal(generated.Id, card.Id);
|
||||
Assert.NotEmpty(card.Skills);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Hire_ParentKeepsBothRolesOnTheCard()
|
||||
{
|
||||
using var client = fixture.App.CreateHttpClient("server");
|
||||
await SchoolApiTests.ResetAsync(client);
|
||||
var school = await SchoolApiTests.CreateAsync(client, "Штат родитель", Start);
|
||||
var before = await GetStaffingAsync(client, school.Id);
|
||||
var parent = before.Applicants.First(applicant => applicant.IsParent);
|
||||
|
||||
await HireAsync(client, school.Id, parent.Id, "Teacher");
|
||||
|
||||
var card = await client.GetFromJsonAsync<PersonCardResponse>(
|
||||
$"/api/schools/{school.Id}/people/{Uri.EscapeDataString(parent.Id)}?lang=ru",
|
||||
TestContext.Current.CancellationToken);
|
||||
Assert.NotNull(card);
|
||||
Assert.Contains("parent", card.Roles);
|
||||
Assert.Contains("staff", card.Roles);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -217,11 +257,23 @@ public class StaffingApiTests(AppHostFixture fixture)
|
||||
float Remaining,
|
||||
IReadOnlyList<UncoveredSubjectResponse> Uncovered,
|
||||
IReadOnlyList<ApplicantResponse> Applicants,
|
||||
IReadOnlyList<StaffMemberResponse> Staff);
|
||||
IReadOnlyList<StaffMemberResponse> Staff,
|
||||
IReadOnlyList<DefLabelResponse> Positions,
|
||||
IReadOnlyList<UncoveredSubjectResponse> Subjects);
|
||||
|
||||
private sealed record UncoveredSubjectResponse(string DefName, string Label, int GradeMin, int GradeMax, int HoursPerWeek);
|
||||
|
||||
private sealed record ApplicantResponse(string Id, string FullName, bool Female, int Age, bool IsParent, float HourlyWageAsk, float MonthlyBase);
|
||||
private sealed record ApplicantResponse(
|
||||
string Id,
|
||||
string FullName,
|
||||
bool Female,
|
||||
int Age,
|
||||
bool IsParent,
|
||||
float HourlyWageAsk,
|
||||
float MonthlyBase,
|
||||
IReadOnlyList<LabeledStatResponse> Skills);
|
||||
|
||||
private sealed record LabeledStatResponse(string Id, string Label, string Value);
|
||||
|
||||
private sealed record StaffMemberResponse(
|
||||
string Id,
|
||||
@@ -237,6 +289,8 @@ public class StaffingApiTests(AppHostFixture fixture)
|
||||
|
||||
private sealed record DefLabelResponse(string DefName, string Label);
|
||||
|
||||
private sealed record PersonCardResponse(string Id, IReadOnlyList<string> Roles, IReadOnlyList<LabeledStatResponse> Skills);
|
||||
|
||||
private sealed record PeopleListResponse(
|
||||
int Total,
|
||||
int Page,
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user