namespace HSchool.People.Tests; public class DressGeneratorTests { [Fact] public void SameSeedCountryMapAndLanguage_YieldTheSameItemsColorsAndPlaces() { var map = Fixtures.Classrooms(11); var a = Fixtures.Generate(map); var b = Fixtures.Generate(map); Assert.Equal(ItemsSnapshot(a), ItemsSnapshot(b)); } [Fact] public void WornLayers_DoNotOverlap_AndADressFillsBottomAndTop() { var catalog = Fixtures.Catalog(); var roster = Fixtures.Generate(Fixtures.Classrooms(11)); foreach (var person in roster.People) { var occupied = new HashSet(StringComparer.Ordinal); foreach (var item in person.Items.Where(row => row.Location == ItemLocations.Worn)) { Assert.True(catalog.Things.TryGetValue(item.Def, out var def)); foreach (var layer in def.Layers) { Assert.True(occupied.Add(layer), $"{person.Id} wears two things on {layer}."); } } } Assert.Contains( roster.People, person => person.Items.Any(item => item.Location == ItemLocations.Worn && item.Def.Equals("Dress", StringComparison.Ordinal))); var dressed = roster.People.First(person => person.Items.Any(item => item.Location == ItemLocations.Worn && item.Def == "Dress")); var worn = dressed.Items.Where(item => item.Location == ItemLocations.Worn).Select(item => item.Def).ToHashSet(); Assert.DoesNotContain("TShirt", worn); Assert.DoesNotContain("Shirt", worn); Assert.DoesNotContain("Skirt", worn); Assert.DoesNotContain("Pants", worn); } [Fact] public void Men_DoNotWearSkirts_AndWornColors_AreNotBright() { var catalog = Fixtures.Catalog(); var roster = Fixtures.Generate(Fixtures.Classrooms(11)); foreach (var person in roster.People) { foreach (var item in person.Items.Where(row => row.Location == ItemLocations.Worn)) { Assert.True(catalog.Things.TryGetValue(item.Def, out var def)); if (!person.Female) { Assert.False( def.Sex is not null && def.Sex.Equals("female", StringComparison.OrdinalIgnoreCase), $"{person.Id} wears {item.Def}."); } if (item.Color is { } color && catalog.Colors.TryGetValue(color, out var colorDef)) { Assert.DoesNotContain(ColorTags.Bright, colorDef.Tags, StringComparer.Ordinal); } } } } [Fact] public void PupilInAMathematicsYear_HasAMathematicsTextbook() { var roster = Fixtures.Generate(Fixtures.Classrooms(11)); var years = roster.Classes.ToDictionary(row => row.Id, row => row.Year, StringComparer.Ordinal); var pupil = roster.People.First(person => person.IsStudent && person.ClassId is { } classId && years[classId] >= 5); Assert.Contains( pupil.Items, item => item.Def.Equals("Textbook", StringComparison.Ordinal) && item.Subject is not null && item.Subject.Equals("Mathematics", StringComparison.Ordinal)); } [Fact] public void ParentsAndApplicants_AreDressed() { var catalog = Fixtures.Catalog(); var roster = Fixtures.Generate(Fixtures.VanillaMap()); var pool = ApplicantPool.Create(catalog, roster, Fixtures.SchoolSeed, "Russia", Fixtures.AsOf); Assert.Contains(roster.People, person => person.IsParent); Assert.All( roster.People.Where(person => person.IsParent), parent => Assert.Contains(parent.Items, item => item.Location == ItemLocations.Worn)); Assert.NotEmpty(pool.Applicants); Assert.All( pool.Applicants, applicant => Assert.Contains(applicant.Person.Items, item => item.Location == ItemLocations.Worn)); } [Fact] public void BagMass_DoesNotExceedCapacity() { var catalog = Fixtures.Catalog(); var roster = Fixtures.Generate(Fixtures.Classrooms(11)); var pool = ApplicantPool.Create(catalog, roster, Fixtures.SchoolSeed, "Russia", Fixtures.AsOf); foreach (var person in roster.People.Concat(pool.Applicants.Select(row => row.Person))) { var held = CarryMass.Held(catalog, person.Items); var cap = CarryMass.Capacity(catalog, person.Skills); Assert.True(held <= cap, $"{person.Id} carries {held} over {cap}."); } } [Fact] public void PeopleJsonWithoutInventory_IsDressedOnEnsure() { var catalog = Fixtures.Catalog(); var roster = Fixtures.Generate(Fixtures.Classrooms(4)); var stripped = new Roster( roster.People.Select(person => person with { Items = [] }).ToArray(), roster.Families, roster.Classes); Assert.True(DressGenerator.NeedsDressing(catalog, stripped, ApplicantPool.Empty)); var dressed = DressGenerator.EnsureRoster(catalog, stripped, Fixtures.SchoolSeed, Fixtures.AsOf); Assert.False(DressGenerator.NeedsDressing(catalog, dressed, ApplicantPool.Empty)); Assert.Equal(ItemsSnapshot(roster), ItemsSnapshot(dressed)); } [Fact] public void Underwear_IsSplitBySex_AndAdultFemalesWearABra() { var roster = Fixtures.Generate(Fixtures.Classrooms(11)); var bras = new HashSet(StringComparer.Ordinal) { "Bra", "SportsBra", "SoftBra" }; foreach (var person in roster.People) { var worn = person.Items .Where(item => item.Location == ItemLocations.Worn) .Select(item => item.Def) .ToHashSet(StringComparer.Ordinal); Assert.DoesNotContain("Underwear", worn); if (person.Female) { Assert.Contains("Panties", worn); Assert.DoesNotContain("Briefs", worn); Assert.DoesNotContain("Boxers", worn); if (person.AgeOn(Fixtures.AsOf) >= 11) { Assert.True(worn.Overlaps(bras), $"{person.Id} age {person.AgeOn(Fixtures.AsOf)} has no bra."); } else { Assert.False(worn.Overlaps(bras), $"{person.Id} is too young for a bra."); } } else { Assert.True(worn.Contains("Briefs") || worn.Contains("Boxers"), $"{person.Id} has no male underwear."); Assert.DoesNotContain("Panties", worn); Assert.False(worn.Overlaps(bras), $"{person.Id} wears a bra."); } } } [Fact] public void EveryoneHasHauling() { var roster = Fixtures.Generate(Fixtures.Classrooms(4)); Assert.All(roster.People, person => Assert.True(person.Skills.ContainsKey("Hauling"))); } [Fact] public void AbstractUnderwearInASave_IsRedressedOnEnsure() { var catalog = Fixtures.Catalog(); var roster = Fixtures.Generate(Fixtures.Classrooms(4)); var broken = new Roster( roster.People.Select(person => { var items = person.Items.Select(item => item.Def.Equals("Briefs", StringComparison.Ordinal) || item.Def.Equals("Boxers", StringComparison.Ordinal) || item.Def.Equals("Panties", StringComparison.Ordinal) ? item with { Def = "Underwear" } : item).ToArray(); return person with { Items = items }; }).ToArray(), roster.Families, roster.Classes); Assert.True(DressGenerator.NeedsDressing(catalog, broken, ApplicantPool.Empty)); var dressed = DressGenerator.EnsureRoster(catalog, broken, Fixtures.SchoolSeed, Fixtures.AsOf); Assert.False(DressGenerator.NeedsDressing(catalog, dressed, ApplicantPool.Empty)); Assert.Equal(ItemsSnapshot(roster), ItemsSnapshot(dressed)); Assert.DoesNotContain( dressed.People.SelectMany(person => person.Items), item => item.Def.Equals("Underwear", StringComparison.Ordinal)); } private static string ItemsSnapshot(Roster roster) => string.Join( '\n', roster.People.OrderBy(person => person.Id, StringComparer.Ordinal).Select(person => $"{person.Id}|" + string.Join( ',', person.Items.Select(item => $"{item.Def}:{item.Color ?? "-"}:{item.Location}:{item.Subject ?? "-"}:{item.Condition}")))); }