aboutsummaryrefslogtreecommitdiff
path: root/internal/admin/room_rename_state_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/admin/room_rename_state_test.go')
-rw-r--r--internal/admin/room_rename_state_test.go68
1 files changed, 68 insertions, 0 deletions
diff --git a/internal/admin/room_rename_state_test.go b/internal/admin/room_rename_state_test.go
new file mode 100644
index 0000000..8c5be93
--- /dev/null
+++ b/internal/admin/room_rename_state_test.go
@@ -0,0 +1,68 @@
+package admin
+
+// Room-rename runtime-state regressions: renaming a room must move its live
+// contents (ground items, seeded spawn markers, object state) to the new ID
+// — never clear them — and undo must bring them back.
+
+import (
+ "testing"
+)
+
+// TestRoomRenameMovesRuntimeState: renaming a room with ground items moves
+// them to the new room ID. The old implementation cleared the state before
+// the migration callback could rekey it, destroying the room's contents.
+func TestRoomRenameMovesRuntimeState(t *testing.T) {
+ s := newTestAdminServer(t, map[int]string{
+ 1: "id: 1\nname: Room\nexits:\n east:\n room: 2\n",
+ 2: "id: 2\nname: Neighbor\nexits:\n west:\n room: 1\n",
+ })
+ s.world.AddGroundItem(1, "chips", 50)
+ s.world.AddGroundItem(1, "chips", 10) // second entry: rekey must move the whole list
+ s.rewriteRoomIDs = func(idMap map[int]int) { s.world.RekeyRooms(idMap) }
+ s.undoStack.SetMigrateRoomIDs(s.rewriteRoomIDs)
+
+ if rec := renameRoom(t, s, 1, 3); rec.Code != 200 {
+ t.Fatalf("rename failed: %d %s", rec.Code, rec.Body.String())
+ }
+ if got := s.world.GroundItems(3)["chips"]; got != 60 {
+ t.Fatalf("ground items after rename = %d, want 60 in room 3", got)
+ }
+ if got := s.world.GroundItems(1)["chips"]; got != 0 {
+ t.Fatalf("ground items left behind in the old room: %d", got)
+ }
+
+ // Undo restores the files AND the runtime state through the inverse map.
+ if s.undoStack.Undo() == nil {
+ t.Fatal("undo failed")
+ }
+ if got := s.world.GroundItems(1)["chips"]; got != 60 {
+ t.Fatalf("ground items after undo = %d, want 60 back in room 1", got)
+ }
+}
+
+// TestRoomRenameUndoDoesNotClearSurvivingRoomState: undoing a rename must
+// not clear runtime state of rooms whose files still exist afterwards
+// (only undo-of-create / redo-of-delete drops state).
+func TestRoomRenameUndoDoesNotClearSurvivingRoomState(t *testing.T) {
+ s := newTestAdminServer(t, map[int]string{
+ 1: "id: 1\nname: Room\n",
+ 2: "id: 2\nname: Unrelated\n",
+ })
+ s.world.AddGroundItem(2, "chips", 5)
+ s.rewriteRoomIDs = func(idMap map[int]int) { s.world.RekeyRooms(idMap) }
+ s.undoStack.SetMigrateRoomIDs(s.rewriteRoomIDs)
+
+ if rec := renameRoom(t, s, 1, 3); rec.Code != 200 {
+ t.Fatalf("rename failed: %d %s", rec.Code, rec.Body.String())
+ }
+ // The unrelated room's state must survive the rename and its undo.
+ if got := s.world.GroundItems(2)["chips"]; got != 5 {
+ t.Fatalf("unrelated room state lost during rename: %d", got)
+ }
+ if s.undoStack.Undo() == nil {
+ t.Fatal("undo failed")
+ }
+ if got := s.world.GroundItems(2)["chips"]; got != 5 {
+ t.Fatalf("unrelated room state lost during undo: %d", got)
+ }
+}