namespace HSchool.Content.Tests; public class PeopleDefTests { private readonly CatalogLoader _loader = new(); [Fact] public void VanillaCore_LoadsPeopleDefs() { var root = Path.Combine(AppContext.BaseDirectory, "vanilla"); var catalog = _loader.Load([CatalogLoader.CorePackId], PackDocuments.FromDirectory(CatalogLoader.CorePackId, root)); Assert.True(catalog.Skills.Count >= 10); Assert.Equal(10, catalog.Traits.Count); Assert.Equal(4, catalog.Needs.Count); Assert.True(catalog.BodyAttributes.ContainsKey("Height")); Assert.Equal(BodyAttributeKind.Number, catalog.BodyAttributes["Height"].Kind); Assert.Equal(BodyAttributeKind.Choice, catalog.BodyAttributes["HairColor"].Kind); Assert.All(catalog.Needs.Values, need => Assert.Equal(0, need.DecayPerHour)); Assert.Contains(catalog.Skills["Agility"].BodyLimits, limit => limit.Attribute == "Build" && limit.Value == "Obese"); Assert.True(catalog.NameSets.ContainsKey("Slavic")); Assert.True(catalog.NameSets["Slavic"].MaleGiven.Count >= 20); Assert.Equal("Славянский", catalog.Label("ru", catalog.NameSets["Slavic"])); Assert.Equal("Slavic", catalog.Label("en", catalog.NameSets["Slavic"])); Assert.Equal("Усидчивый", catalog.Label("ru", catalog.Traits["Diligent"])); } [Fact] public void Skill_InheritsRangeFromParent() { var catalog = _loader.Load( [CatalogLoader.CorePackId], [ PackDocuments.Def( CatalogLoader.CorePackId, "skills", "base", """{ "defName": "AcademicBase", "abstract": true, "range": { "min": 0, "max": 100 }, "distribution": { "mean": 40, "stdDev": 10 } }"""), PackDocuments.Def( CatalogLoader.CorePackId, "skills", "math", """{ "defName": "Mathematics", "parent": "AcademicBase", "distribution": { "mean": 55, "stdDev": 12 } }"""), ]); Assert.Equal(0, catalog.Skills["Mathematics"].Range.Min); Assert.Equal(100, catalog.Skills["Mathematics"].Range.Max); Assert.Equal(55, catalog.Skills["Mathematics"].Distribution?.Mean); Assert.False(catalog.Skills["Mathematics"].Abstract); Assert.True(catalog.Skills["AcademicBase"].Abstract); } [Fact] public void TraitPatch_AddsAnIncompatibility() { var catalog = _loader.Load( [CatalogLoader.CorePackId, "addon"], [ PackDocuments.Def(CatalogLoader.CorePackId, "skills", "math", """{ "defName": "Mathematics" }"""), PackDocuments.Def( CatalogLoader.CorePackId, "traits", "kind", """{ "defName": "Kind", "weight": 1, "incompatible": [] }"""), PackDocuments.Def( CatalogLoader.CorePackId, "traits", "bully", """{ "defName": "Bully", "weight": 1 }"""), PackDocuments.Patch( "addon", "kind", """{ "target": "Kind", "ops": [ { "op": "add", "path": "/incompatible/-", "value": "Bully" } ] }"""), ]); Assert.Equal(["Bully"], catalog.Traits["Kind"].Incompatible); Assert.Contains("Bully", catalog.TraitIncompatibilities("Kind")); Assert.Contains("Kind", catalog.TraitIncompatibilities("Bully")); } [Fact] public void UnknownBodyLimitAttribute_FailsTheCatalog() { var ex = Assert.Throws(() => _loader.Load( [CatalogLoader.CorePackId], [ PackDocuments.Def( CatalogLoader.CorePackId, "skills", "agility", """{ "defName": "Agility", "bodyLimits": [ { "attribute": "Missing", "value": "X", "max": 10 } ] }"""), ])); Assert.Contains("Missing", ex.Message); } [Fact] public void UnknownBuildValue_FailsTheCatalog() { var ex = Assert.Throws(() => _loader.Load( [CatalogLoader.CorePackId], [ PackDocuments.Def( CatalogLoader.CorePackId, "skills", "agility", """{ "defName": "Agility", "bodyLimits": [ { "attribute": "Build", "value": "Huge", "max": 10 } ] }"""), ])); Assert.Contains("Huge", ex.Message); } [Fact] public void UnknownTraitIncompatibility_FailsTheCatalog() { var ex = Assert.Throws(() => _loader.Load( [CatalogLoader.CorePackId], [ PackDocuments.Def( CatalogLoader.CorePackId, "traits", "kind", """{ "defName": "Kind", "incompatible": ["Ghost"] }"""), ])); Assert.Contains("Ghost", ex.Message); } [Fact] public void OneWayIncompatibility_IsMutual() { var catalog = _loader.Load( [CatalogLoader.CorePackId], [ PackDocuments.Def(CatalogLoader.CorePackId, "traits", "a", """{ "defName": "Diligent", "weight": 1, "incompatible": ["Lazy"] }"""), PackDocuments.Def(CatalogLoader.CorePackId, "traits", "b", """{ "defName": "Lazy", "weight": 1 }"""), ]); Assert.Equal(["Lazy"], catalog.Traits["Diligent"].Incompatible); Assert.Empty(catalog.Traits["Lazy"].Incompatible); Assert.Contains("Lazy", catalog.TraitIncompatibilities("Diligent")); Assert.Contains("Diligent", catalog.TraitIncompatibilities("Lazy")); } [Fact] public void ExtraPack_AddsANameSetAndTrait() { var catalog = _loader.Load( [CatalogLoader.CorePackId, "addon"], [ PackDocuments.Def(CatalogLoader.CorePackId, "traits", "kind", """{ "defName": "Kind", "weight": 1 }"""), PackDocuments.Def( CatalogLoader.CorePackId, "namesets", "slavic", """ { "defName": "Slavic", "maleGiven": [{ "form": "Иван" }], "femaleGiven": [{ "form": "Анна", "declension": "a" }], "surnames": [{ "male": "Иванов", "female": "Иванова" }] } """), PackDocuments.Def("addon", "traits", "stoic", """{ "defName": "Stoic", "weight": 3 }"""), PackDocuments.Def("addon", "traits", "cheerful", """{ "defName": "Cheerful", "weight": 2 }"""), PackDocuments.Def( "addon", "namesets", "nordic", """ { "defName": "Nordic", "maleGiven": [{ "form": "Lars", "declension": "indeclinable" }], "femaleGiven": [{ "form": "Ingrid", "declension": "indeclinable" }], "surnames": [{ "male": "Berg", "female": "Berg", "declension": "indeclinable" }] } """), PackDocuments.Locale("addon", "ru", """{ "Nordic": "Северный", "Stoic": "Стоик", "Cheerful": "Жизнерадостный" }"""), ]); Assert.True(catalog.NameSets.ContainsKey("Nordic")); Assert.True(catalog.Traits.ContainsKey("Stoic")); Assert.True(catalog.Traits.ContainsKey("Cheerful")); Assert.Equal("Северный", catalog.Label("ru", catalog.NameSets["Nordic"])); Assert.Equal("Стоик", catalog.Label("ru", catalog.Traits["Stoic"])); } } public class NameGrammarTests { [Fact] public void HardGiven_FollowsTheConsonantModel() { var entry = new GivenNameEntry { Form = "Иван", Declension = NameGrammar.Hard }; Assert.Equal("Иван", NameGrammar.InflectGiven(entry, GrammaticalCase.Nominative, NameGrammar.Hard)); Assert.Equal("Ивана", NameGrammar.InflectGiven(entry, GrammaticalCase.Genitive, NameGrammar.Hard)); Assert.Equal("Ивану", NameGrammar.InflectGiven(entry, GrammaticalCase.Dative, NameGrammar.Hard)); Assert.Equal("Иваном", NameGrammar.InflectGiven(entry, GrammaticalCase.Instrumental, NameGrammar.Hard)); } [Fact] public void ExplicitTable_OverridesTheModel() { var entry = new GivenNameEntry { Form = "Любовь", Declension = NameGrammar.Soft, Cases = new CaseTable { Nom = "Любовь", Gen = "Любови", Dat = "Любови", Acc = "Любовь", Ins = "Любовью", Pre = "Любови", }, }; Assert.Equal("Любови", NameGrammar.InflectGiven(entry, GrammaticalCase.Genitive, NameGrammar.Soft)); Assert.Equal("Любовью", NameGrammar.InflectGiven(entry, GrammaticalCase.Instrumental, NameGrammar.Soft)); Assert.Equal("Любовя", NameGrammar.InflectGivenForm("Любовь", NameGrammar.Soft, GrammaticalCase.Genitive)); } [Fact] public void OvSurname_UsesGenderedEndings() { var entry = new SurnameEntry { Male = "Иванов", Female = "Иванова", Declension = NameGrammar.Ov }; Assert.Equal("Иванова", NameGrammar.InflectSurname(entry, female: false, GrammaticalCase.Genitive, NameGrammar.Ov)); Assert.Equal("Ивановой", NameGrammar.InflectSurname(entry, female: true, GrammaticalCase.Genitive, NameGrammar.Ov)); Assert.Equal("Иванову", NameGrammar.InflectSurname(entry, female: true, GrammaticalCase.Accusative, NameGrammar.Ov)); } [Fact] public void SlavicPatronymic_FromTheFathersName() { Assert.Equal("Иванович", NameGrammar.Patronymic("Иван", female: false, NameGrammar.SlavicPatronymic)); Assert.Equal("Ивановна", NameGrammar.Patronymic("Иван", female: true, NameGrammar.SlavicPatronymic)); Assert.Equal("Андреевич", NameGrammar.Patronymic("Андрей", female: false, NameGrammar.SlavicPatronymic)); Assert.Equal("Дмитриевич", NameGrammar.Patronymic("Дмитрий", female: false, NameGrammar.SlavicPatronymic)); Assert.Equal("Ильинична", NameGrammar.Patronymic("Илья", female: true, NameGrammar.SlavicPatronymic)); } [Fact] public void BodyBuild_ComesFromBmiBands() { Assert.Equal(BodyBuilds.Skinny, BodyBuilds.FromHeightAndWeight(170, 50)); Assert.Equal(BodyBuilds.Athletic, BodyBuilds.FromHeightAndWeight(170, 68)); Assert.Equal(BodyBuilds.Obese, BodyBuilds.FromHeightAndWeight(170, 90)); } [Fact] public void Patronymic_InflectsLikeAHardOrAStem() { Assert.Equal("Ивановича", NameGrammar.InflectPatronymic("Иванович", female: false, GrammaticalCase.Genitive)); Assert.Equal("Ивановны", NameGrammar.InflectPatronymic("Ивановна", female: true, GrammaticalCase.Genitive)); Assert.Equal("Ивановну", NameGrammar.InflectPatronymic("Ивановна", female: true, GrammaticalCase.Accusative)); } }