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

124 lines
4.8 KiB
C#

namespace HSchool.People.Tests;
public class ApplicantPoolTests
{
[Fact]
public void SameSeedAndWeek_YieldTheSamePool()
{
var roster = Fixtures.Generate(Fixtures.VanillaMap());
var a = Create(roster);
var b = Create(roster);
Assert.Equal(Snapshot(a), Snapshot(b));
}
[Fact]
public void Advance_KeepsSomePeopleWithTheSameSkillsAndAsk()
{
var roster = Fixtures.Generate(Fixtures.VanillaMap());
var first = Create(roster);
var next = first.Advance(Fixtures.Catalog(), roster, Fixtures.SchoolSeed, "Slavic", Fixtures.AsOf.AddDays(7));
Assert.NotEqual(first.Week, next.Week);
var stayed = first.Applicants
.Join(
next.Applicants,
applicant => applicant.Person.Id,
applicant => applicant.Person.Id,
(before, after) => (before, after),
StringComparer.Ordinal)
.ToArray();
Assert.NotEmpty(stayed);
foreach (var (before, after) in stayed)
{
Assert.Equal(before.HourlyWageAsk, after.HourlyWageAsk);
Assert.Equal(Skills(before.Person), Skills(after.Person));
Assert.Equal(before.Person.Name.Full, after.Person.Name.Full);
}
}
[Fact]
public void FiftyWeeks_StayAtPoolSize()
{
var catalog = Fixtures.Catalog();
var roster = Fixtures.Generate(Fixtures.VanillaMap());
var size = catalog.StaffingRules!.PoolSize;
var asOf = Fixtures.AsOf;
var pool = ApplicantPool.Create(catalog, roster, Fixtures.SchoolSeed, "Slavic", asOf);
for (var week = 0; week < 50; week++)
{
asOf = asOf.AddDays(7);
pool = pool.Advance(catalog, roster, Fixtures.SchoolSeed, "Slavic", asOf);
Assert.Equal(size, pool.Applicants.Count);
}
}
[Fact]
public void StrongerSkills_AskForMore()
{
var catalog = Fixtures.Catalog();
var person = Fixtures.Generate(Fixtures.Classrooms(1)).People.First(candidate => candidate.IsParent);
var weak = person with { Skills = person.Skills.ToDictionary(pair => pair.Key, _ => 15) };
var strong = person with { Skills = person.Skills.ToDictionary(pair => pair.Key, _ => 90) };
Assert.True(ApplicantPool.HourlyAsk(catalog, strong) > ApplicantPool.HourlyAsk(catalog, weak));
}
[Fact]
public void GeneratedApplicants_AreNotOnTheRoster_ParentsKeepTheirId()
{
var roster = Fixtures.Generate(Fixtures.VanillaMap());
ApplicantPool? pool = null;
for (var seed = 1; seed <= 20 && pool is null; seed++)
{
var candidate = Fixtures.Generate(Fixtures.VanillaMap(), seed);
var created = ApplicantPool.Create(Fixtures.Catalog(), candidate, seed, "Slavic", Fixtures.AsOf);
if (created.Applicants.Any(applicant => candidate.People.Any(person => person.Id == applicant.Person.Id)))
{
roster = candidate;
pool = created;
}
}
Assert.NotNull(pool);
var rosterIds = roster.People.Select(person => person.Id).ToHashSet(StringComparer.Ordinal);
foreach (var applicant in pool.Applicants)
{
if (rosterIds.Contains(applicant.Person.Id))
{
Assert.Contains(roster.People, person => person.Id == applicant.Person.Id && person.IsParent && !person.IsStaff);
}
else
{
Assert.StartsWith("a", applicant.Person.Id, StringComparison.Ordinal);
Assert.False(applicant.Person.IsStaff);
}
}
}
[Fact]
public void PeopleJson_RoundTripsThePool()
{
var roster = Fixtures.Generate(Fixtures.Classrooms(1));
var pool = Create(roster);
var json = RosterJson.Serialize(RosterDocument.From(Fixtures.SchoolSeed, roster, pool));
var loaded = RosterJson.Parse(json);
Assert.Equal(Snapshot(pool), Snapshot(loaded.Applicants!));
Assert.DoesNotContain(loaded.People, person => pool.Applicants.Any(applicant =>
applicant.Person.Id.StartsWith('a') && applicant.Person.Id == person.Id));
}
private static ApplicantPool Create(Roster roster) =>
ApplicantPool.Create(Fixtures.Catalog(), roster, Fixtures.SchoolSeed, "Slavic", Fixtures.AsOf);
private static string Snapshot(ApplicantPool pool) =>
string.Join('\n', pool.Applicants.Select(applicant =>
$"{pool.Week}|{pool.NextIndex}|{applicant.Person.Id}|{applicant.HourlyWageAsk:0.00}|{applicant.Person.Name.Full}|{Skills(applicant.Person)}"));
private static string Skills(Person person) =>
string.Join(',', person.Skills.OrderBy(pair => pair.Key, StringComparer.Ordinal).Select(pair => $"{pair.Key}={pair.Value}"));
}