Enhance school creation and staffing management with native language support
- Updated protocol documentation to include `nativeLanguages` in `nameSets` and added `nativeLanguage` to school creation options. - Enhanced the UI for school creation to allow selection of native languages, improving user experience. - Revised API interfaces to accommodate new native language features, ensuring proper data handling. - Improved localization strings to support new native language functionalities in both English and Russian. - Updated tests to validate the new native language features and ensure robust functionality in staffing scenarios.
This commit is contained in:
@@ -96,7 +96,7 @@ internal static class Fixtures
|
||||
}
|
||||
|
||||
public static Roster Generate(MapLayout map, int seed = SchoolSeed) =>
|
||||
RosterGenerator.Generate(Catalog(), map, seed, "Slavic", AsOf);
|
||||
RosterGenerator.Generate(Catalog(), map, seed, "Slavic", AsOf, "RussianLanguage");
|
||||
|
||||
public static string RepoRoot()
|
||||
{
|
||||
|
||||
@@ -0,0 +1,185 @@
|
||||
namespace HSchool.People.Tests;
|
||||
|
||||
public class SkillGrantTests
|
||||
{
|
||||
[Fact]
|
||||
public void FirstYear_HasCoreAndPrimary_ButNotChemistryOrEnglish()
|
||||
{
|
||||
var roster = Fixtures.Generate(Fixtures.Classrooms(11));
|
||||
var pupils = PupilsIn(roster, 1).ToArray();
|
||||
Assert.NotEmpty(pupils);
|
||||
Assert.All(
|
||||
pupils,
|
||||
person =>
|
||||
{
|
||||
Assert.True(person.Skills.ContainsKey("Communication"));
|
||||
Assert.True(person.Skills.ContainsKey("RussianLanguage"));
|
||||
Assert.True(person.Skills.ContainsKey("Agility"));
|
||||
Assert.True(person.Skills.ContainsKey("Mathematics"));
|
||||
Assert.False(person.Skills.ContainsKey("Chemistry"));
|
||||
Assert.False(person.Skills.ContainsKey("Physics"));
|
||||
Assert.False(person.Skills.ContainsKey("English"));
|
||||
Assert.False(person.Skills.ContainsKey("German"));
|
||||
Assert.False(person.Skills.ContainsKey("Pedagogy"));
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void YearFive_HasEnglish_YearEight_HasChemistry()
|
||||
{
|
||||
var roster = Fixtures.Generate(Fixtures.Classrooms(11));
|
||||
Assert.All(
|
||||
PupilsIn(roster, 5),
|
||||
person =>
|
||||
{
|
||||
Assert.True(person.Skills.ContainsKey("English"));
|
||||
Assert.False(person.Skills.ContainsKey("Chemistry"));
|
||||
Assert.False(person.Skills.ContainsKey("German"));
|
||||
});
|
||||
Assert.All(PupilsIn(roster, 8), person => Assert.True(person.Skills.ContainsKey("Chemistry")));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Adults_HaveNativeAndCommunication_ButNotEverySkill()
|
||||
{
|
||||
var catalog = Fixtures.Catalog();
|
||||
var roster = Fixtures.Generate(Fixtures.Classrooms(11));
|
||||
var adults = roster.People.Where(person => !person.IsStudent).ToArray();
|
||||
Assert.NotEmpty(adults);
|
||||
|
||||
var concrete = catalog.Skills.Values.Count(skill => !skill.Abstract);
|
||||
Assert.All(
|
||||
adults,
|
||||
person =>
|
||||
{
|
||||
Assert.True(person.Skills.ContainsKey("Communication"));
|
||||
Assert.True(person.Skills.ContainsKey("RussianLanguage"));
|
||||
Assert.True(person.Skills.Count < concrete);
|
||||
Assert.InRange(person.Skills.Keys.Count(name => catalog.Skills[name].Work), 0, 2);
|
||||
});
|
||||
Assert.Contains(
|
||||
adults,
|
||||
person => person.Skills.Keys.Any(name => catalog.Skills[name].Work));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BelarusianNative_IsGrantedToEveryone_PupilsStillStudyRussian()
|
||||
{
|
||||
var catalog = Fixtures.Catalog();
|
||||
var roster = RosterGenerator.Generate(
|
||||
catalog,
|
||||
Fixtures.Classrooms(11),
|
||||
Fixtures.SchoolSeed,
|
||||
"Slavic",
|
||||
Fixtures.AsOf,
|
||||
"BelarusianLanguage");
|
||||
|
||||
var max = catalog.NameSets["Slavic"].RelatedLanguageMax;
|
||||
Assert.All(
|
||||
roster.People,
|
||||
person =>
|
||||
{
|
||||
Assert.True(person.Skills.ContainsKey("BelarusianLanguage"));
|
||||
if (person.Skills.TryGetValue("UkrainianLanguage", out var ukrainian))
|
||||
{
|
||||
Assert.InRange(ukrainian, 0, max);
|
||||
}
|
||||
});
|
||||
Assert.All(
|
||||
roster.People.Where(person => person.IsStudent),
|
||||
person => Assert.True(person.Skills.ContainsKey("RussianLanguage")));
|
||||
Assert.Contains(
|
||||
roster.People.Where(person => person.IsStudent),
|
||||
person => person.Skills["RussianLanguage"] > max);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RelatedLanguages_AreCommonAndStayLow()
|
||||
{
|
||||
var catalog = Fixtures.Catalog();
|
||||
var max = catalog.NameSets["Slavic"].RelatedLanguageMax;
|
||||
var roster = Fixtures.Generate(Fixtures.Classrooms(11));
|
||||
Assert.Contains(
|
||||
roster.People,
|
||||
person =>
|
||||
person.Skills.ContainsKey("BelarusianLanguage")
|
||||
|| person.Skills.ContainsKey("UkrainianLanguage"));
|
||||
Assert.Contains(roster.People, person => !person.Skills.ContainsKey("BelarusianLanguage"));
|
||||
Assert.Contains(roster.People, person => !person.Skills.ContainsKey("UkrainianLanguage"));
|
||||
Assert.True(
|
||||
roster.People.Count(person =>
|
||||
person.Skills.ContainsKey("BelarusianLanguage")
|
||||
|| person.Skills.ContainsKey("UkrainianLanguage"))
|
||||
> roster.People.Count / 2);
|
||||
|
||||
Assert.All(
|
||||
roster.People,
|
||||
person =>
|
||||
{
|
||||
Assert.True(person.Skills.ContainsKey("RussianLanguage"));
|
||||
if (person.Skills.TryGetValue("BelarusianLanguage", out var belarusian))
|
||||
{
|
||||
Assert.InRange(belarusian, 0, max);
|
||||
}
|
||||
|
||||
if (person.Skills.TryGetValue("UkrainianLanguage", out var ukrainian))
|
||||
{
|
||||
Assert.InRange(ukrainian, 0, max);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OmittedNativeLanguage_IsStableForTheSameSeed()
|
||||
{
|
||||
var map = Fixtures.Classrooms(2);
|
||||
var a = RosterGenerator.Generate(Fixtures.Catalog(), map, 7, "Slavic", Fixtures.AsOf);
|
||||
var b = RosterGenerator.Generate(Fixtures.Catalog(), map, 7, "Slavic", Fixtures.AsOf);
|
||||
Assert.Equal(
|
||||
a.People.Select(person => string.Join(',', person.Skills.Keys.Order(StringComparer.Ordinal))),
|
||||
b.People.Select(person => string.Join(',', person.Skills.Keys.Order(StringComparer.Ordinal))));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Pupils_DoNotRollWorkSkills()
|
||||
{
|
||||
var catalog = Fixtures.Catalog();
|
||||
var roster = Fixtures.Generate(Fixtures.Classrooms(11));
|
||||
Assert.All(
|
||||
roster.People.Where(person => person.IsStudent),
|
||||
person => Assert.DoesNotContain(person.Skills.Keys, name => catalog.Skills[name].Work));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Intake_YearFourGainsEnglishWithoutRerollingMath()
|
||||
{
|
||||
var catalog = Fixtures.Catalog();
|
||||
var before = Fixtures.Generate(Fixtures.Classrooms(5));
|
||||
var year4 = before.Classes.Single(schoolClass => schoolClass.Year == 4);
|
||||
var pupil = before.People.First(person => person.Id == year4.PupilIds[0]);
|
||||
Assert.False(pupil.Skills.ContainsKey("English"));
|
||||
var math = pupil.Skills["Mathematics"];
|
||||
|
||||
var after = YearlyIntake.Apply(
|
||||
catalog,
|
||||
before,
|
||||
Fixtures.SchoolSeed,
|
||||
"Slavic",
|
||||
new DateTime(2012, 9, 1, 0, 0, 0, DateTimeKind.Utc));
|
||||
var grown = after.People.First(person => person.Id == pupil.Id);
|
||||
Assert.True(grown.ClassId is { } classId && after.Classes.Any(schoolClass =>
|
||||
schoolClass.Id.Equals(classId, StringComparison.Ordinal) && schoolClass.Year == 5));
|
||||
Assert.True(grown.Skills.ContainsKey("English"));
|
||||
Assert.Equal(math, grown.Skills["Mathematics"]);
|
||||
}
|
||||
|
||||
private static IEnumerable<Person> PupilsIn(Roster roster, int year)
|
||||
{
|
||||
var classIds = roster.Classes
|
||||
.Where(schoolClass => schoolClass.Year == year)
|
||||
.Select(schoolClass => schoolClass.Id)
|
||||
.ToHashSet(StringComparer.Ordinal);
|
||||
return roster.People.Where(person =>
|
||||
person.IsStudent && person.ClassId is { } classId && classIds.Contains(classId));
|
||||
}
|
||||
}
|
||||
@@ -224,9 +224,10 @@ public class StaffingTests
|
||||
Assert.Equal(catalog.Subjects.Values.Count(subject => !subject.Abstract), uncovered.Count);
|
||||
|
||||
var applicant = pool.Applicants[0];
|
||||
var hired = Staffing.Hire(catalog, map, roster, pool, applicant.Person.Id, Staffing.TeacherPosition, Cap);
|
||||
var assigned = Staffing.AssignSubject(catalog, hired.Roster, hired.Pool, applicant.Person.Id, "Mathematics", Cap);
|
||||
var hired = Staffing.Hire(catalog, map, roster, pool, applicant.Person.Id, Staffing.TeacherPosition, 100_000f);
|
||||
var assigned = Staffing.AssignSubject(catalog, hired.Roster, hired.Pool, applicant.Person.Id, "Mathematics", 100_000f);
|
||||
|
||||
Assert.Equal(StaffingError.None, assigned.Error);
|
||||
Assert.DoesNotContain(Staffing.Uncovered(catalog, assigned.Roster), subject => subject.DefName == "Mathematics");
|
||||
Assert.Contains(Staffing.Uncovered(catalog, assigned.Roster), subject => subject.DefName == "PrimarySchool");
|
||||
}
|
||||
@@ -236,8 +237,9 @@ public class StaffingTests
|
||||
{
|
||||
var (catalog, map, roster, pool) = Fresh();
|
||||
var applicant = pool.Applicants[0];
|
||||
var hired = Staffing.Hire(catalog, map, roster, pool, applicant.Person.Id, Staffing.TeacherPosition, Cap);
|
||||
var assigned = Staffing.AssignSubject(catalog, hired.Roster, hired.Pool, applicant.Person.Id, "Mathematics", Cap);
|
||||
var hired = Staffing.Hire(catalog, map, roster, pool, applicant.Person.Id, Staffing.TeacherPosition, 100_000f);
|
||||
var assigned = Staffing.AssignSubject(catalog, hired.Roster, hired.Pool, applicant.Person.Id, "Mathematics", 100_000f);
|
||||
Assert.Equal(StaffingError.None, assigned.Error);
|
||||
|
||||
var json = RosterJson.Serialize(RosterDocument.From(Fixtures.SchoolSeed, assigned.Roster, assigned.Pool));
|
||||
var loaded = RosterJson.Parse(json);
|
||||
|
||||
@@ -118,5 +118,8 @@ public class YearlyIntakeTests
|
||||
|
||||
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}"));
|
||||
$"{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}"));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user