aboutsummaryrefslogtreecommitdiff
path: root/internal/validate/hardening_fixes_batch2_test.go
diff options
context:
space:
mode:
authorhistoria <[not public]>2026-09-18 15:16:44 -0400
committerhistoria <[not public]>2026-09-18 15:16:44 -0400
commit7eab582d8a8ee2af1a6baae7baf0696c7005de2e (patch)
tree902bbc8c6e39c9f62f779ca23267714ec420b9f5 /internal/validate/hardening_fixes_batch2_test.go
parent153acb7f644d755c45533b7c5311e3ffa47e8973 (diff)
downloadthehouseoficarus-7eab582d8a8ee2af1a6baae7baf0696c7005de2e.tar.gz
fix: harden triggers, economy, casino, world data, and admin/net paths
Diffstat (limited to 'internal/validate/hardening_fixes_batch2_test.go')
-rw-r--r--internal/validate/hardening_fixes_batch2_test.go89
1 files changed, 89 insertions, 0 deletions
diff --git a/internal/validate/hardening_fixes_batch2_test.go b/internal/validate/hardening_fixes_batch2_test.go
new file mode 100644
index 0000000..f88c924
--- /dev/null
+++ b/internal/validate/hardening_fixes_batch2_test.go
@@ -0,0 +1,89 @@
+package validate
+
+import (
+ "path/filepath"
+ "strings"
+ "testing"
+
+ "thehouseoficarus/internal/item"
+ "thehouseoficarus/internal/object"
+ "thehouseoficarus/internal/world"
+)
+
+// TestValidateModuleDestinationMissingRoom: a transport destination that is
+// not a real room soft-locks the player, so it must be a startup ERROR.
+func TestValidateModuleDestinationMissingRoom(t *testing.T) {
+ dir := t.TempDir()
+ writeFile(t, filepath.Join(dir, "rooms", "1.yaml"), "id: 1\nname: Root\n")
+
+ src := Source{
+ DataDir: dir,
+ World: world.New(dir),
+ ModuleDestinations: map[string]int{"transport_bad": 999},
+ }
+ issues := validateModuleDestinations(src)
+ if len(issues) != 1 {
+ t.Fatalf("issues = %+v, want exactly one", issues)
+ }
+ if issues[0].Level != "ERROR" || !strings.Contains(issues[0].Message, "999") {
+ t.Fatalf("unexpected issue: %+v", issues[0])
+ }
+}
+
+// TestValidateReachabilityFlagsDisconnectedComponent: a component whose rooms
+// only link to each other has no inbound edge from outside, so the orphan
+// check misses it; the reachability BFS must warn.
+func TestValidateReachabilityFlagsDisconnectedComponent(t *testing.T) {
+ dir := t.TempDir()
+ writeFile(t, filepath.Join(dir, "rooms", "1.yaml"), "id: 1\nname: Root\n")
+ writeFile(t, filepath.Join(dir, "rooms", "2.yaml"), "id: 2\nname: A\nexits:\n north:\n room: 3\n")
+ writeFile(t, filepath.Join(dir, "rooms", "3.yaml"), "id: 3\nname: B\nexits:\n south:\n room: 2\n")
+
+ src := Source{DataDir: dir, World: world.New(dir), RootRooms: []int{1}}
+ issues := validateRoomWiring(src)
+
+ found := false
+ for _, issue := range issues {
+ if strings.Contains(issue.Message, "Unreachable rooms") &&
+ strings.Contains(issue.Message, "2") && strings.Contains(issue.Message, "3") {
+ found = true
+ if issue.Level != "WARN" {
+ t.Fatalf("reachability issue must be a WARN: %+v", issue)
+ }
+ }
+ if strings.Contains(issue.Message, "Orphan") {
+ t.Fatalf("disconnected component must not be reported as an orphan: %+v", issue)
+ }
+ }
+ if !found {
+ t.Fatalf("expected an unreachable-rooms warning, got %+v", issues)
+ }
+}
+
+// TestValidateCraftEmptyIngredientIsError: an ingredient entry with no items
+// makes formatMaterials index out of range at runtime, so it must be an ERROR.
+func TestValidateCraftEmptyIngredientIsError(t *testing.T) {
+ dir := t.TempDir()
+ writeFile(t, filepath.Join(dir, "items", "thing.yaml"),
+ "name: thing\ncraft:\n - type: cooking\n ingredients:\n - quantity: 2\n")
+
+ src := Source{
+ DataDir: dir,
+ Items: item.NewItemStore(dir),
+ Objects: object.NewObjectStore(dir),
+ Mobs: world.NewMobStore(dir),
+ World: world.New(dir),
+ }
+ found := false
+ for _, issue := range validateCraftBlocks(src) {
+ if strings.Contains(issue.Message, "has no items") {
+ found = true
+ if issue.Level != "ERROR" {
+ t.Fatalf("empty ingredient must be an ERROR: %+v", issue)
+ }
+ }
+ }
+ if !found {
+ t.Fatal("expected an ERROR for an ingredient entry with no items")
+ }
+}