Update test_defaults_and_patches implementation, assets and documentation
This commit is contained in:
1 parent
039c68d448
commit
a6f790fb4d
5 files changed
+126
-2
No files matched your search
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"Kind": "item",
|
||||
"Items": [
|
||||
{
|
||||
"Id": "test_patches/base",
|
||||
"Name": "items/food/ration/name",
|
||||
"Description": "items/food/ration/desc",
|
||||
"Cost": 10,
|
||||
"Sprite": "food/ration",
|
||||
"ItemType": "Food",
|
||||
"Shelf": {"Row": 1, "Col": 2}
|
||||
},
|
||||
{
|
||||
"Id": "test_patches/child",
|
||||
"Extends": "test_patches/base",
|
||||
"Cost": 20,
|
||||
"Shelf": {"Col": 5}
|
||||
},
|
||||
{
|
||||
"Id": "test_patches/doomed",
|
||||
"Name": "items/food/ration/name",
|
||||
"Sprite": "food/ration",
|
||||
"ItemType": "Food"
|
||||
},
|
||||
{
|
||||
"Id": "test_patches/loop_a",
|
||||
"Extends": "test_patches/loop_b",
|
||||
"Sprite": "food/ration"
|
||||
},
|
||||
{
|
||||
"Id": "test_patches/loop_b",
|
||||
"Extends": "test_patches/loop_a",
|
||||
"Sprite": "food/ration"
|
||||
}
|
||||
]
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 126 KiB After Width: | Height: | Size: 142 KiB |
@@ -9,6 +9,26 @@
|
||||
"Id": "*",
|
||||
"Durability": 50,
|
||||
"GlobalItemProp": "patched"
|
||||
},
|
||||
{
|
||||
"Id": "FOOD/WOLF_MEAT",
|
||||
"Cost": 77
|
||||
},
|
||||
{
|
||||
"Id": "food/wolf_meat",
|
||||
"Cost": "many"
|
||||
},
|
||||
{
|
||||
"Id": "food/wolf_meat",
|
||||
"Name$add": ["broken"]
|
||||
},
|
||||
{
|
||||
"Id": "test_patches/base",
|
||||
"Sprite": "food/wolf_meat"
|
||||
},
|
||||
{
|
||||
"Id": "test_patches/doomed",
|
||||
"$delete": true
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"Items": [
|
||||
{
|
||||
"Id": "test_patches/child",
|
||||
"Description": "items/food/wolf_meat/desc"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -38,7 +38,9 @@ namespace Mods.TestDefaultsAndPatches
|
||||
/// <c>patches/item.json</c> into the real entities of other mods, as the
|
||||
/// game resolves them: a targeted patch wins over the wildcard, the
|
||||
/// wildcard reaches every entity of the kind, and untouched typed fields
|
||||
/// survive. Prints <c>[TEST_RESULT] name=property_patches</c> and quits.
|
||||
/// survive; patch ids match case-insensitively, a broken patch is skipped
|
||||
/// alone, <c>$delete</c> removes an entity, <c>Extends</c> inherits from a
|
||||
/// parent resolved with its own patches and a cycle skips its members. Prints <c>[TEST_RESULT] name=property_patches</c> and quits.
|
||||
/// </summary>
|
||||
public partial class PropertyPatchesTestDriverNode : Node
|
||||
{
|
||||
@@ -113,9 +115,67 @@ namespace Mods.TestDefaultsAndPatches
|
||||
Check("food/ration resolved", false);
|
||||
|
||||
if (items.TryGetValue("food/wolf_meat", out var meat))
|
||||
{
|
||||
Expect(meat.ExtraProperties, "Durability", "50", "wolf_meat: wildcard value");
|
||||
Check($"wolf_meat: patch id is case-insensitive (FOOD/WOLF_MEAT → Cost 77, got {meat.Cost})", meat.Cost == 77);
|
||||
Check("wolf_meat: broken patches (Cost \"many\", Name$add) are skipped, the item keeps its name",
|
||||
meat.Name == "items/food/wolf_meat/name");
|
||||
}
|
||||
else
|
||||
Check("food/wolf_meat resolved", false);
|
||||
Check("food/wolf_meat resolved (a broken patch must not drop the kind)", false);
|
||||
|
||||
Check("$delete removes test_patches/doomed", !items.ContainsKey("test_patches/doomed"));
|
||||
Check("an Extends cycle skips both entities", !items.ContainsKey("test_patches/loop_a") && !items.ContainsKey("test_patches/loop_b"));
|
||||
if (items.TryGetValue("test_patches/child", out var child))
|
||||
{
|
||||
Check("Extends: child inherits Name", child.Name == "items/food/ration/name");
|
||||
Check($"Extends: child's own Cost wins (got {child.Cost})", child.Cost == 20);
|
||||
Check($"Extends: the parent is resolved with its patches first (Sprite {child.Sprite})", child.Sprite == "food/wolf_meat");
|
||||
var shelf = child.ExtraProperties != null && child.ExtraProperties.TryGetValue("Shelf", out var value) && value is JsonElement element
|
||||
&& element.ValueKind == JsonValueKind.Object ? element : default;
|
||||
Check($"Extends: nested objects deep-merge (Shelf {(shelf.ValueKind == JsonValueKind.Object ? shelf.GetRawText() : "missing")})",
|
||||
shelf.ValueKind == JsonValueKind.Object && shelf.TryGetProperty("Row", out var row) && row.GetInt32() == 1
|
||||
&& shelf.TryGetProperty("Col", out var col) && col.GetInt32() == 5);
|
||||
Expect(child.ExtraProperties, "Durability", "50", "child: wildcard patch applies after Extends");
|
||||
}
|
||||
else
|
||||
Check("test_patches/child resolved", false);
|
||||
|
||||
ExplainChild();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <c>EntityResolver.Explain</c> on an <c>Extends</c> chain with patches on the parent, the
|
||||
/// child (a second file) and a wildcard: every field names its layer, entity, mod and file.
|
||||
/// </summary>
|
||||
private void ExplainChild()
|
||||
{
|
||||
const string mod = "test_defaults_and_patches";
|
||||
const string data = "items/test_patches.json";
|
||||
var resolver = Cthangover.Core.Mods.ModManager.Instance.GetResolver<EntityResolver>();
|
||||
var explanation = resolver?.Explain("item", "test_patches/child");
|
||||
Check("Explain(item, test_patches/child) returns a value", explanation?.Value != null);
|
||||
if (explanation?.Value == null)
|
||||
return;
|
||||
|
||||
Check($"Explain value matches Collect (Cost {explanation.Value["Cost"]})", explanation.Value["Cost"]?.GetValue<int>() == 20);
|
||||
ExpectOrigin(explanation, "Name", EntityLayer.Definition, "test_patches/base", mod, data);
|
||||
ExpectOrigin(explanation, "Cost", EntityLayer.Definition, "test_patches/child", mod, data);
|
||||
ExpectOrigin(explanation, "Shelf.Row", EntityLayer.Definition, "test_patches/base", mod, data);
|
||||
ExpectOrigin(explanation, "Shelf.Col", EntityLayer.Definition, "test_patches/child", mod, data);
|
||||
ExpectOrigin(explanation, "Sprite", EntityLayer.Patch, "test_patches/base", mod, "patches/item.json");
|
||||
ExpectOrigin(explanation, "Description", EntityLayer.Patch, "test_patches/child", mod, "patches/item/explain.json");
|
||||
ExpectOrigin(explanation, "Durability", EntityLayer.Patch, "*", mod, "patches/item.json");
|
||||
Check("Explain of a $delete-d entity says Deleted", resolver.Explain("item", "test_patches/doomed")?.Deleted == true);
|
||||
Check("Explain of an Extends cycle member is null", resolver.Explain("item", "test_patches/loop_a") == null);
|
||||
}
|
||||
|
||||
private void ExpectOrigin(EntityExplanation explanation, string path, EntityLayer layer, string entity, string mod, string file)
|
||||
{
|
||||
explanation.Fields.TryGetValue(path, out var origin);
|
||||
var actual = origin == null ? "default" : $"{origin.Layer} {origin.EntityId} {origin.ModId}/{origin.File}";
|
||||
Check($"Explain {path}: {layer} {entity} {mod}/{file} (got {actual})",
|
||||
origin != null && origin.Layer == layer && origin.EntityId == entity && origin.ModId == mod && origin.File == file);
|
||||
}
|
||||
|
||||
private void Expect(Dictionary<string, object> properties, string key, string expected, string what)
|
||||
|
||||
Reference in new issue
Block a user