package validate import ( "testing" ) // Regression: CraftDef.Tool was validated against item ids, but it is a tool // *type* ("knife", "pickaxe", "fire"): runtime consumers match it with // ItemDef.ToolType() (g.hasToolType). Tool types such as pickaxe, axe, fire, // big_net and fly_rod have no same-named item file, so the old check rejected // legitimate recipes. These tests pin the tool-type namespace and the // byproduct/index pairing rule. func TestCraftToolTypeAcceptedWithoutSameNamedItem(t *testing.T) { dir := t.TempDir() // A pickaxe item defines tool.type: pickaxe but there is no item "pickaxe". writeCraftItem(t, dir, "bronze_pickaxe", `id: bronze_pickaxe name: bronze pickaxe tool: type: pickaxe speed: 2 `) writeCraftItem(t, dir, "test_in", "id: test_in\nname: test in\n") writeCraftItem(t, dir, "test_out", `id: test_out name: test out craft: - type: crafting tool: pickaxe ingredients: - items: [test_in] quantity: 1 `) issues := validateCraftBlocks(newSource(dir)) for _, issue := range issues { if issue.Level == "ERROR" { t.Fatalf("a bare tool type must validate, got: %+v", issue) } } } func TestCraftToolTypeUnknownIsRejected(t *testing.T) { dir := t.TempDir() writeCraftItem(t, dir, "bronze_pickaxe", "id: bronze_pickaxe\nname: bronze pickaxe\ntool:\n type: pickaxe\n") writeCraftItem(t, dir, "test_in", "id: test_in\nname: test in\n") writeCraftItem(t, dir, "test_out", `id: test_out name: test out craft: - type: crafting tool: made_up_type ingredients: - items: [test_in] quantity: 1 `) if issues := validateCraftBlocks(newSource(dir)); !containsMsg(issues, "nonexistent tool") { t.Fatalf("expected nonexistent-tool error, got: %+v", issues) } } func TestCraftByproductLengthMismatchIsFlagged(t *testing.T) { dir := t.TempDir() writeCraftItem(t, dir, "test_in", "id: test_in\nname: test in\n") writeCraftItem(t, dir, "test_alt", "id: test_alt\nname: test alt\n") writeCraftItem(t, dir, "empty_container", "id: empty_container\nname: empty container\n") // Two alternatives paired with a single byproduct: consuming the second // alternative returns nothing (collectByproducts indexes by position). writeCraftItem(t, dir, "test_out", `id: test_out name: test out craft: - type: combine ingredients: - items: [test_in, test_alt] quantity: 1 byproducts: [empty_container] `) if issues := validateCraftBlocks(newSource(dir)); !containsMsg(issues, "pair with items by index") { t.Fatalf("expected byproduct length-mismatch error, got: %+v", issues) } } func TestCraftByproductLengthMatchIsAccepted(t *testing.T) { dir := t.TempDir() writeCraftItem(t, dir, "test_in", "id: test_in\nname: test in\n") writeCraftItem(t, dir, "test_alt", "id: test_alt\nname: test alt\n") writeCraftItem(t, dir, "empty_one", "id: empty_one\nname: empty one\n") writeCraftItem(t, dir, "empty_two", "id: empty_two\nname: empty two\n") writeCraftItem(t, dir, "test_out", `id: test_out name: test out craft: - type: combine ingredients: - items: [test_in, test_alt] quantity: 1 byproducts: [empty_one, empty_two] `) if issues := validateCraftBlocks(newSource(dir)); len(issues) != 0 { t.Fatalf("positionally paired byproducts must validate cleanly, got: %+v", issues) } }