Enhance school creation functionality by introducing support for name sets in the API and UI. Update the catalog to include skills, traits, body attributes, needs, and name sets, improving character generation capabilities. Revise localization strings for better user guidance and update tests to validate the new name set functionality and ensure robustness in school creation processes.
This commit is contained in:
@@ -0,0 +1,153 @@
|
||||
namespace HSchool.People.Tests;
|
||||
|
||||
public class RosterGeneratorTests
|
||||
{
|
||||
[Fact]
|
||||
public void SameSeedMapAndNameSet_YieldTheSameRoster()
|
||||
{
|
||||
var map = Fixtures.Classrooms(4);
|
||||
var a = Fixtures.Generate(map);
|
||||
var b = Fixtures.Generate(map);
|
||||
|
||||
Assert.Equal(Snapshot(a), Snapshot(b));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ThirteenthFamily_DoesNotChangeTheFirstTwelve()
|
||||
{
|
||||
var twelve = FamilySnapshots(Fixtures.Generate(Fixtures.Classrooms(4)), take: 12);
|
||||
var thirteen = FamilySnapshots(Fixtures.Generate(Fixtures.Classrooms(5)), take: 12);
|
||||
|
||||
Assert.Equal(12, twelve.Count);
|
||||
Assert.Equal(twelve, thirteen);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FamilyNames_ShareSurnameAndPatronymicFromTheFather()
|
||||
{
|
||||
var roster = Fixtures.Generate(Fixtures.Classrooms(4));
|
||||
var people = roster.People.ToDictionary(person => person.Id, StringComparer.Ordinal);
|
||||
|
||||
foreach (var family in roster.Families)
|
||||
{
|
||||
if (family.ChildIds.Count == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var father = people[family.ParentIds[0]];
|
||||
var mother = people[family.ParentIds[1]];
|
||||
Assert.False(father.Female);
|
||||
Assert.True(mother.Female);
|
||||
|
||||
foreach (var childId in family.ChildIds)
|
||||
{
|
||||
var child = people[childId];
|
||||
Assert.Equal(
|
||||
NameGrammar.Patronymic(father.Name.Given, child.Female, NameGrammar.SlavicPatronymic),
|
||||
child.Name.Patronymic);
|
||||
Assert.Equal(child.Female ? mother.Name.Surname : father.Name.Surname, child.Name.Surname);
|
||||
Assert.Equal(father.Name.SurnameCases.Nom, father.Name.Surname);
|
||||
Assert.Equal(mother.Name.SurnameCases.Nom, mother.Name.Surname);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ObesePupil_CannotHaveHighAgility()
|
||||
{
|
||||
var agility = Fixtures.Catalog().Skills["Agility"];
|
||||
var clamped = PersonSampler.ApplyBodyLimits(
|
||||
80,
|
||||
agility,
|
||||
new Dictionary<string, string> { [BodyBuilds.Attribute] = BodyBuilds.Obese });
|
||||
Assert.Equal(25, clamped);
|
||||
|
||||
var roster = Fixtures.Generate(Fixtures.Classrooms(11));
|
||||
var obesePupils = roster.People.Where(person =>
|
||||
person.IsStudent
|
||||
&& person.Choices.TryGetValue(BodyBuilds.Attribute, out var build)
|
||||
&& build == BodyBuilds.Obese);
|
||||
|
||||
Assert.All(
|
||||
obesePupils,
|
||||
person => Assert.True(
|
||||
person.Skills["Agility"] <= 25,
|
||||
$"{person.Name.Surname} {person.Name.Given} is obese with agility {person.Skills["Agility"]}."));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OneClassroomAndEleven_BothFillSeatsAndJobs()
|
||||
{
|
||||
AssertFilled(Fixtures.Generate(Fixtures.Classrooms(1)), classrooms: 1);
|
||||
AssertFilled(Fixtures.Generate(Fixtures.Classrooms(11)), classrooms: 11);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SomeStaffAreAlsoParents()
|
||||
{
|
||||
var roster = Fixtures.Generate(Fixtures.Classrooms(4));
|
||||
Assert.Contains(roster.People, person => person.IsStaff && person.IsParent);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Assembly_DoesNotReferenceArchAspNetOrSockets()
|
||||
{
|
||||
var names = typeof(RosterGenerator).Assembly.GetReferencedAssemblies().Select(assembly => assembly.Name!);
|
||||
Assert.DoesNotContain(names, name => name.StartsWith("Arch", StringComparison.OrdinalIgnoreCase));
|
||||
Assert.DoesNotContain(names, name => name.Contains("AspNet", StringComparison.OrdinalIgnoreCase));
|
||||
Assert.DoesNotContain(names, name => name.Contains("Sockets", StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Sources_DoNotUseWallClock()
|
||||
{
|
||||
var root = Path.Combine(Fixtures.RepoRoot(), "src", "HSchool.People");
|
||||
foreach (var path in Directory.EnumerateFiles(root, "*.cs"))
|
||||
{
|
||||
var text = File.ReadAllText(path);
|
||||
Assert.DoesNotContain("DateTime.Now", text, StringComparison.Ordinal);
|
||||
Assert.DoesNotContain("DateTime.UtcNow", text, StringComparison.Ordinal);
|
||||
}
|
||||
}
|
||||
|
||||
private static void AssertFilled(Roster roster, int classrooms)
|
||||
{
|
||||
Assert.Equal(classrooms, roster.Classes.Count);
|
||||
Assert.Equal(classrooms * 16, roster.People.Count(person => person.IsStudent));
|
||||
Assert.All(roster.Classes, schoolClass =>
|
||||
{
|
||||
Assert.Equal(schoolClass.Capacity, schoolClass.PupilIds.Count);
|
||||
Assert.InRange(schoolClass.Year, 1, 11);
|
||||
});
|
||||
|
||||
var demand = SchoolDemand.From(Fixtures.Catalog(), Fixtures.Classrooms(classrooms));
|
||||
Assert.Equal(demand.Staff.Count, roster.People.Count(person => person.IsStaff));
|
||||
Assert.All(demand.Staff, opening =>
|
||||
Assert.Contains(
|
||||
roster.People,
|
||||
person => person.IsStaff && person.Position == opening.Position && person.WorkplaceRoomId == opening.RoomId));
|
||||
}
|
||||
|
||||
private static string Snapshot(Roster roster) =>
|
||||
string.Join('\n', roster.People.Select(person =>
|
||||
$"{person.Id}|{person.FamilyId}|{person.Female}|{person.BirthDate:O}|{person.Name.Given}|{person.Name.Surname}|{person.Name.Patronymic}|{person.IsStudent}|{person.IsStaff}|{person.IsParent}|{person.ClassId}|{person.Position}|{person.Choices[BodyBuilds.Attribute]}|{Skills(person)}|{string.Join(',', person.Traits)}"));
|
||||
|
||||
private static string Skills(Person person) =>
|
||||
string.Join(',', person.Skills.OrderBy(pair => pair.Key, StringComparer.Ordinal).Select(pair => $"{pair.Key}={pair.Value}"));
|
||||
|
||||
private static List<string> FamilySnapshots(Roster roster, int take)
|
||||
{
|
||||
var people = roster.People.ToDictionary(person => person.Id, StringComparer.Ordinal);
|
||||
return roster.Families
|
||||
.OrderBy(family => family.Id, StringComparer.Ordinal)
|
||||
.Take(take)
|
||||
.Select(family =>
|
||||
{
|
||||
var members = family.ParentIds.Concat(family.ChildIds).Select(id => people[id]);
|
||||
return string.Join(';', members.Select(person =>
|
||||
$"{person.Id}:{person.Name.Surname} {person.Name.Given} {person.Name.Patronymic}:{person.BirthDate:O}:{person.Female}:{Skills(person)}"));
|
||||
})
|
||||
.ToList();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user