Files
h-school/tests/HSchool.People.Tests/RosterGeneratorTests.cs
T

154 lines
6.2 KiB
C#

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();
}
}