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") } }