dynreplacer_test.gno
6.00 Kb ยท 235 lines
1package dynreplacer
2
3import (
4 "strings"
5 "testing"
6
7 "gno.land/p/demo/uassert"
8)
9
10func TestNew(t *testing.T) {
11 tests := []struct {
12 name string
13 pairs []Pair
14 }{
15 {
16 name: "empty constructor",
17 pairs: []Pair{},
18 },
19 {
20 name: "single pair",
21 pairs: []Pair{
22 {":name:", func() string { return "World" }},
23 },
24 },
25 {
26 name: "multiple pairs",
27 pairs: []Pair{
28 {":greeting:", func() string { return "Hello" }},
29 {":name:", func() string { return "World" }},
30 },
31 },
32 }
33
34 for _, tt := range tests {
35 t.Run(tt.name, func(t *testing.T) {
36 r := New(tt.pairs...)
37 uassert.True(t, r.callbacks != nil, "callbacks map should be initialized")
38 uassert.True(t, r.cachedValues != nil, "cachedValues map should be initialized")
39
40 // Verify all callbacks were registered
41 for _, pair := range tt.pairs {
42 _, exists := r.callbacks[pair.Placeholder]
43 uassert.True(t, exists, "callback should be registered for "+pair.Placeholder)
44 }
45 })
46 }
47}
48
49func TestReplace(t *testing.T) {
50 tests := []struct {
51 name string
52 layout string
53 setup func(*Replacer)
54 expected string
55 }{
56 {
57 name: "empty layout",
58 layout: "",
59 setup: func(r *Replacer) {},
60 expected: "",
61 },
62 {
63 name: "single replacement",
64 layout: "Hello :name:!",
65 setup: func(r *Replacer) {
66 r.RegisterCallback(":name:", func() string { return "World" })
67 },
68 expected: "Hello World!",
69 },
70 {
71 name: "multiple replacements",
72 layout: ":greeting: :name:!",
73 setup: func(r *Replacer) {
74 r.RegisterCallback(":greeting:", func() string { return "Hello" })
75 r.RegisterCallback(":name:", func() string { return "World" })
76 },
77 expected: "Hello World!",
78 },
79 {
80 name: "no recursive replacement",
81 layout: ":outer:",
82 setup: func(r *Replacer) {
83 r.RegisterCallback(":outer:", func() string { return ":inner:" })
84 r.RegisterCallback(":inner:", func() string { return "content" })
85 },
86 expected: ":inner:",
87 },
88 {
89 name: "unused callbacks",
90 layout: "Hello :name:!",
91 setup: func(r *Replacer) {
92 r.RegisterCallback(":name:", func() string { return "World" })
93 r.RegisterCallback(":unused:", func() string { return "Never Called" })
94 },
95 expected: "Hello World!",
96 },
97 }
98
99 for _, tt := range tests {
100 t.Run(tt.name, func(t *testing.T) {
101 r := New()
102 tt.setup(r)
103 result := r.Replace(tt.layout)
104 uassert.Equal(t, tt.expected, result)
105 })
106 }
107}
108
109func TestCaching(t *testing.T) {
110 r := New()
111 callCount := 0
112 r.RegisterCallback(":expensive:", func() string {
113 callCount++
114 return "computed"
115 })
116
117 layout := "Value: :expensive:"
118
119 // First call should compute
120 result1 := r.Replace(layout)
121 uassert.Equal(t, "Value: computed", result1)
122 uassert.Equal(t, 1, callCount)
123
124 // Second call should use cache
125 result2 := r.Replace(layout)
126 uassert.Equal(t, "Value: computed", result2)
127 uassert.Equal(t, 1, callCount)
128
129 // After clearing cache, should recompute
130 r.ClearCache()
131 result3 := r.Replace(layout)
132 uassert.Equal(t, "Value: computed", result3)
133 uassert.Equal(t, 2, callCount)
134}
135
136func TestComplexExample(t *testing.T) {
137 layout := `
138 # Welcome to gno.land
139
140 ## Blog
141 :latest-blogposts:
142
143 ## Events
144 :next-events:
145
146 ## Awesome Gno
147 :awesome-gno:
148 `
149
150 r := New(
151 Pair{":latest-blogposts:", func() string { return "Latest blog posts content here" }},
152 Pair{":next-events:", func() string { return "Upcoming events listed here" }},
153 Pair{":awesome-gno:", func() string { return ":latest-blogposts: (This should NOT be replaced again)" }},
154 )
155
156 result := r.Replace(layout)
157
158 // Check that original placeholders are replaced
159 uassert.True(t, !strings.Contains(result, ":latest-blogposts:\n"), "':latest-blogposts:' placeholder should be replaced")
160 uassert.True(t, !strings.Contains(result, ":next-events:\n"), "':next-events:' placeholder should be replaced")
161 uassert.True(t, !strings.Contains(result, ":awesome-gno:\n"), "':awesome-gno:' placeholder should be replaced")
162
163 // Check that the replacement content is present
164 uassert.True(t, strings.Contains(result, "Latest blog posts content here"), "Blog posts content should be present")
165 uassert.True(t, strings.Contains(result, "Upcoming events listed here"), "Events content should be present")
166 uassert.True(t, strings.Contains(result, ":latest-blogposts: (This should NOT be replaced again)"),
167 "Nested placeholder should not be replaced")
168}
169
170func TestEdgeCases(t *testing.T) {
171 tests := []struct {
172 name string
173 layout string
174 setup func(*Replacer)
175 expected string
176 }{
177 {
178 name: "empty string placeholder",
179 layout: "Hello :",
180 setup: func(r *Replacer) {
181 r.RegisterCallback("", func() string { return "World" })
182 },
183 expected: "WorldHWorldeWorldlWorldlWorldoWorld World:World",
184 },
185 {
186 name: "overlapping placeholders",
187 layout: "Hello :name::greeting:",
188 setup: func(r *Replacer) {
189 r.RegisterCallback(":name:", func() string { return "World" })
190 r.RegisterCallback(":greeting:", func() string { return "Hi" })
191 r.RegisterCallback(":name::greeting:", func() string { return "Should not match" })
192 },
193 expected: "Hello WorldHi",
194 },
195 {
196 name: "replacement order",
197 layout: ":a::b::c:",
198 setup: func(r *Replacer) {
199 r.RegisterCallback(":c:", func() string { return "3" })
200 r.RegisterCallback(":b:", func() string { return "2" })
201 r.RegisterCallback(":a:", func() string { return "1" })
202 },
203 expected: "123",
204 },
205 {
206 name: "special characters in placeholders",
207 layout: "Hello :$name#123:!",
208 setup: func(r *Replacer) {
209 r.RegisterCallback(":$name#123:", func() string { return "World" })
210 },
211 expected: "Hello World!",
212 },
213 {
214 name: "multiple occurrences of same placeholder",
215 layout: ":name: and :name: again",
216 setup: func(r *Replacer) {
217 callCount := 0
218 r.RegisterCallback(":name:", func() string {
219 callCount++
220 return "World"
221 })
222 },
223 expected: "World and World again",
224 },
225 }
226
227 for _, tt := range tests {
228 t.Run(tt.name, func(t *testing.T) {
229 r := New()
230 tt.setup(r)
231 result := r.Replace(tt.layout)
232 uassert.Equal(t, tt.expected, result)
233 })
234 }
235}