Files
Leonid Pershin 5df341f91b Restore Slavic save lift and redress abstract underwear on load.
Recheck of slice 7 stage A found UpgradeOlderSave removed after UpperUnderwear, so format-2 nameSetId saves never started, and golden people.json wearing abstract Underwear failed RequireKnownApparel. Bring back the lift, treat unusable items as undressed, and restore GoldenSaveTests.
2026-08-20 15:52:17 +03:00

220 lines
8.7 KiB
C#

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