diff options
Diffstat (limited to 'internal/validate/hardening_fixes_batch2_test.go')
| -rw-r--r-- | internal/validate/hardening_fixes_batch2_test.go | 89 |
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") + } +} |
