aboutsummaryrefslogtreecommitdiff
path: root/internal/behavior/roomrefs_test.go
blob: 9651b170a62a7611c3b10ce3a20279516d94a1b9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
package behavior

// Structural room-reference remapping for non-room content files. The walker
// must rewrite only known room-ID keys and must not touch author values that
// merely happen to equal a room ID.

import (
	"os"
	"path/filepath"
	"strings"
	"testing"

	"gopkg.in/yaml.v3"
)

func decode(t *testing.T, src string) any {
	t.Helper()
	var v any
	if err := yaml.Unmarshal([]byte(src), &v); err != nil {
		t.Fatalf("unmarshal: %v", err)
	}
	return v
}

func TestRemapRoomRefsRewritesStructuralKeys(t *testing.T) {
	src := `
destination: 10
on_fail: 11
room_id: 12
start_room: 13
wander_rooms: [14, 15]
despawn_rooms: [16]
teleport: 17
nested:
  room: 18
  condition:
    room: 19
`
	v := decode(t, src)
	idMap := map[int]int{
		10: 110, 11: 111, 12: 112, 13: 113, 14: 114, 15: 115,
		16: 116, 17: 117, 18: 118, 19: 119,
	}
	if !RemapRoomRefs(v, idMap) {
		t.Fatal("expected changed=true")
	}
	out, err := MarshalYAMLMap(v.(map[string]any))
	if err != nil {
		t.Fatal(err)
	}
	s := string(out)
	for _, want := range []string{
		"destination: 110", "on_fail: 111", "room_id: 112", "start_room: 113",
		"teleport: 117",
	} {
		if !strings.Contains(s, want) {
			t.Errorf("missing rewritten %q in:\n%s", want, s)
		}
	}
	// Lists are rewritten in place.
	for _, want := range []string{"- 114", "- 115", "- 116"} {
		if !strings.Contains(s, want) {
			t.Errorf("missing rewritten list entry %q in:\n%s", want, s)
		}
	}
	for _, want := range []string{"room: 118", "room: 119"} {
		if !strings.Contains(s, want) {
			t.Errorf("missing nested rewritten %q in:\n%s", want, s)
		}
	}
}

func TestRemapRoomRefsLeavesAuthorValues(t *testing.T) {
	// A delay, quantity, color index, and author flag value that equal room
	// IDs must never be rewritten: only structural keys are room references.
	src := `
value: 10
delay: 11
quantity: 12
color: "13"
set_global_flags:
  last_room: 14
steps:
  - wait: 15
    credits: 16
`
	v := decode(t, src)
	idMap := map[int]int{10: 110, 11: 111, 12: 112, 13: 113, 14: 114, 15: 115, 16: 116}
	if RemapRoomRefs(v, idMap) {
		t.Fatal("author values were remapped; only structural room keys may change")
	}
}

func TestRewriteRoomRefsInDir(t *testing.T) {
	dir := t.TempDir()
	write := func(name, body string) {
		t.Helper()
		if err := os.WriteFile(filepath.Join(dir, name), []byte(body), 0o644); err != nil {
			t.Fatal(err)
		}
	}
	write("course.yaml", "start_room: 5\nobstacles:\n  - room_id: 6\n")
	write("unrelated.yaml", "value: 5\nname: keeps its value\n")

	changes, err := RewriteRoomRefsInDir(dir, map[int]int{5: 50, 6: 60})
	if err != nil {
		t.Fatal(err)
	}
	if len(changes) != 1 {
		t.Fatalf("changed %d files, want 1: %+v", len(changes), changes)
	}
	if !strings.Contains(string(changes[0].Content), "start_room: 50") ||
		!strings.Contains(string(changes[0].Content), "room_id: 60") {
		t.Fatalf("course not rewritten: %s", changes[0].Content)
	}
	if changes[0].Old == nil {
		t.Fatal("before-image not captured for undo")
	}
}

// Missing content directories are not an error (a family may be absent).
func TestRewriteRoomRefsInDirMissingDir(t *testing.T) {
	changes, err := RewriteRoomRefsInDir(t.TempDir()+"/nope", map[int]int{1: 2})
	if err != nil {
		t.Fatalf("missing dir must not error: %v", err)
	}
	if len(changes) != 0 {
		t.Fatalf("expected no changes, got %+v", changes)
	}
}