Dress people at generation from a separate apparel stream.
Wardrobes live on the person in people.json: everyday layers, textbooks per parallel, and chance-based bags from catalog data. Hauling and the carry cap are defs, not constants. The golden roster gains an items column; later family members shift because Hauling consumes extra appearance rolls. Old saves without items are dressed on load. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,154 @@
|
||||
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<string>(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(stripped, ApplicantPool.Empty));
|
||||
var dressed = DressGenerator.EnsureRoster(catalog, stripped, Fixtures.SchoolSeed, Fixtures.AsOf);
|
||||
Assert.False(DressGenerator.NeedsDressing(dressed, ApplicantPool.Empty));
|
||||
Assert.Equal(ItemsSnapshot(roster), ItemsSnapshot(dressed));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EveryoneHasHauling()
|
||||
{
|
||||
var roster = Fixtures.Generate(Fixtures.Classrooms(4));
|
||||
Assert.All(roster.People, person => Assert.True(person.Skills.ContainsKey("Hauling")));
|
||||
}
|
||||
|
||||
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}"))));
|
||||
}
|
||||
Reference in New Issue
Block a user