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}