aboutsummaryrefslogtreecommitdiff
path: root/internal/validate/polish_destructive_fail_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/validate/polish_destructive_fail_test.go')
-rw-r--r--internal/validate/polish_destructive_fail_test.go64
1 files changed, 64 insertions, 0 deletions
diff --git a/internal/validate/polish_destructive_fail_test.go b/internal/validate/polish_destructive_fail_test.go
new file mode 100644
index 0000000..8c9a038
--- /dev/null
+++ b/internal/validate/polish_destructive_fail_test.go
@@ -0,0 +1,64 @@
+package validate
+
+// Regression: the "a failable recipe must not yield nothing" invariant was
+// enforced only for smelting (and only by a shipped-data test), so a future
+// cooking/fletching/combine recipe with a success formula (or a declared
+// fail_message) and no fail product would silently consume materials and
+// return nothing. validateCraftBlocks now warns on it.
+
+import (
+ "path/filepath"
+ "testing"
+)
+
+func writePolishCraftRecipe(t *testing.T, dir, craftBody string) {
+ t.Helper()
+ writeFile(t, filepath.Join(dir, "items", "polish_in.yaml"), "id: polish_in\nname: polish in\n")
+ writeFile(t, filepath.Join(dir, "items", "polish_out.yaml"),
+ "id: polish_out\nname: polish out\ncraft:\n - type: cooking\n"+craftBody+
+ " ingredients:\n - items: [polish_in]\n quantity: 1\n")
+}
+
+func TestCraftFailableWithoutFailProductIsWarned(t *testing.T) {
+ cases := []struct {
+ name string
+ craftBody string
+ }{
+ {"success formula", " success:\n base: 0.5\n cap: 0.95\n per_level: 0.02\n"},
+ {"declared fail_message", " fail_message: You burn it.\n"},
+ }
+ for _, c := range cases {
+ t.Run(c.name, func(t *testing.T) {
+ dir := t.TempDir()
+ writePolishCraftRecipe(t, dir, c.craftBody)
+ issues := validateCraftBlocks(newSource(dir))
+ if !containsMsg(issues, "failure destroys materials with no fail product") {
+ t.Fatalf("expected a destructive-failure warning, got: %+v", issues)
+ }
+ for _, issue := range issues {
+ if issue.Level != "WARN" {
+ t.Fatalf("destructive failure must be a WARN, got: %+v", issue)
+ }
+ }
+ })
+ }
+}
+
+func TestCraftWithFailProductOrGuaranteedSuccessDoesNotWarn(t *testing.T) {
+ cases := []struct {
+ name string
+ craftBody string
+ }{
+ {"declares a fail product", " fail: polish_in\n success:\n base: 0.5\n cap: 0.95\n per_level: 0.02\n"},
+ {"success cannot fall below 1", " success:\n base: 1.0\n cap: 1.0\n per_level: 0\n"},
+ }
+ for _, c := range cases {
+ t.Run(c.name, func(t *testing.T) {
+ dir := t.TempDir()
+ writePolishCraftRecipe(t, dir, c.craftBody)
+ if issues := validateCraftBlocks(newSource(dir)); containsMsg(issues, "failure destroys materials with no fail product") {
+ t.Fatalf("did not expect a destructive-failure warning, got: %+v", issues)
+ }
+ })
+ }
+}