tree_test.gno
9.31 Kb ยท 392 lines
1package cow
2
3import (
4 "testing"
5)
6
7func TestNewTree(t *testing.T) {
8 tree := NewTree()
9 if tree.node != nil {
10 t.Error("Expected tree.node to be nil")
11 }
12}
13
14func TestTreeSize(t *testing.T) {
15 tree := NewTree()
16 if tree.Size() != 0 {
17 t.Error("Expected empty tree size to be 0")
18 }
19
20 tree.Set("key1", "value1")
21 tree.Set("key2", "value2")
22 if tree.Size() != 2 {
23 t.Error("Expected tree size to be 2")
24 }
25}
26
27func TestTreeHas(t *testing.T) {
28 tree := NewTree()
29 tree.Set("key1", "value1")
30
31 if !tree.Has("key1") {
32 t.Error("Expected tree to have key1")
33 }
34
35 if tree.Has("key2") {
36 t.Error("Expected tree to not have key2")
37 }
38}
39
40func TestTreeGet(t *testing.T) {
41 tree := NewTree()
42 tree.Set("key1", "value1")
43
44 value, exists := tree.Get("key1")
45 if !exists || value != "value1" {
46 t.Error("Expected Get to return value1 and true")
47 }
48
49 _, exists = tree.Get("key2")
50 if exists {
51 t.Error("Expected Get to return false for non-existent key")
52 }
53}
54
55func TestTreeGetByIndex(t *testing.T) {
56 tree := NewTree()
57 tree.Set("key1", "value1")
58 tree.Set("key2", "value2")
59
60 key, value := tree.GetByIndex(0)
61 if key != "key1" || value != "value1" {
62 t.Error("Expected GetByIndex(0) to return key1 and value1")
63 }
64
65 key, value = tree.GetByIndex(1)
66 if key != "key2" || value != "value2" {
67 t.Error("Expected GetByIndex(1) to return key2 and value2")
68 }
69
70 defer func() {
71 if r := recover(); r == nil {
72 t.Error("Expected GetByIndex to panic for out-of-range index")
73 }
74 }()
75 tree.GetByIndex(2)
76}
77
78func TestTreeRemove(t *testing.T) {
79 tree := NewTree()
80 tree.Set("key1", "value1")
81
82 value, removed := tree.Remove("key1")
83 if !removed || value != "value1" || tree.Size() != 0 {
84 t.Error("Expected Remove to remove key-value pair")
85 }
86
87 _, removed = tree.Remove("key2")
88 if removed {
89 t.Error("Expected Remove to return false for non-existent key")
90 }
91}
92
93func TestTreeIterate(t *testing.T) {
94 tree := NewTree()
95 tree.Set("key1", "value1")
96 tree.Set("key2", "value2")
97 tree.Set("key3", "value3")
98
99 var keys []string
100 tree.Iterate("", "", func(key string, value any) bool {
101 keys = append(keys, key)
102 return false
103 })
104
105 expectedKeys := []string{"key1", "key2", "key3"}
106 if !slicesEqual(keys, expectedKeys) {
107 t.Errorf("Expected keys %v, got %v", expectedKeys, keys)
108 }
109}
110
111func TestTreeReverseIterate(t *testing.T) {
112 tree := NewTree()
113 tree.Set("key1", "value1")
114 tree.Set("key2", "value2")
115 tree.Set("key3", "value3")
116
117 var keys []string
118 tree.ReverseIterate("", "", func(key string, value any) bool {
119 keys = append(keys, key)
120 return false
121 })
122
123 expectedKeys := []string{"key3", "key2", "key1"}
124 if !slicesEqual(keys, expectedKeys) {
125 t.Errorf("Expected keys %v, got %v", expectedKeys, keys)
126 }
127}
128
129func TestTreeIterateByOffset(t *testing.T) {
130 tree := NewTree()
131 tree.Set("key1", "value1")
132 tree.Set("key2", "value2")
133 tree.Set("key3", "value3")
134
135 var keys []string
136 tree.IterateByOffset(1, 2, func(key string, value any) bool {
137 keys = append(keys, key)
138 return false
139 })
140
141 expectedKeys := []string{"key2", "key3"}
142 if !slicesEqual(keys, expectedKeys) {
143 t.Errorf("Expected keys %v, got %v", expectedKeys, keys)
144 }
145}
146
147func TestTreeReverseIterateByOffset(t *testing.T) {
148 tree := NewTree()
149 tree.Set("key1", "value1")
150 tree.Set("key2", "value2")
151 tree.Set("key3", "value3")
152
153 var keys []string
154 tree.ReverseIterateByOffset(1, 2, func(key string, value any) bool {
155 keys = append(keys, key)
156 return false
157 })
158
159 expectedKeys := []string{"key2", "key1"}
160 if !slicesEqual(keys, expectedKeys) {
161 t.Errorf("Expected keys %v, got %v", expectedKeys, keys)
162 }
163}
164
165// Verify that Tree implements avl.ITree
166// var _ avl.ITree = (*Tree)(nil) // TODO: fix gnovm bug: ./examples/gno.land/p/moul/cow: test pkg: panic: gno.land/p/moul/cow/tree_test.gno:166:5: name avl not defined in fileset with files [node.gno tree.gno node_test.gno tree_test.gno]:
167
168func TestCopyOnWrite(t *testing.T) {
169 // Create original tree
170 original := NewTree()
171 original.Set("A", 1)
172 original.Set("B", 2)
173 original.Set("C", 3)
174
175 // Create a clone
176 clone := original.Clone()
177
178 // Modify clone
179 clone.Set("B", 20)
180 clone.Set("D", 4)
181
182 // Verify original is unchanged
183 if val, _ := original.Get("B"); val != 2 {
184 t.Errorf("Original tree was modified: expected B=2, got B=%v", val)
185 }
186 if original.Has("D") {
187 t.Error("Original tree was modified: found key D")
188 }
189
190 // Verify clone has new values
191 if val, _ := clone.Get("B"); val != 20 {
192 t.Errorf("Clone not updated: expected B=20, got B=%v", val)
193 }
194 if val, _ := clone.Get("D"); val != 4 {
195 t.Errorf("Clone not updated: expected D=4, got D=%v", val)
196 }
197}
198
199func TestCopyOnWriteEdgeCases(t *testing.T) {
200 t.Run("nil tree clone", func(t *testing.T) {
201 var original *Tree
202 clone := original.Clone()
203 if clone != nil {
204 t.Error("Expected nil clone from nil tree")
205 }
206 })
207
208 t.Run("empty tree clone", func(t *testing.T) {
209 original := NewTree()
210 clone := original.Clone()
211
212 // Modify clone
213 clone.Set("A", 1)
214
215 if original.Size() != 0 {
216 t.Error("Original empty tree was modified")
217 }
218 if clone.Size() != 1 {
219 t.Error("Clone was not modified")
220 }
221 })
222
223 t.Run("multiple clones", func(t *testing.T) {
224 original := NewTree()
225 original.Set("A", 1)
226 original.Set("B", 2)
227
228 // Create multiple clones
229 clone1 := original.Clone()
230 clone2 := original.Clone()
231 clone3 := clone1.Clone()
232
233 // Modify each clone differently
234 clone1.Set("A", 10)
235 clone2.Set("B", 20)
236 clone3.Set("C", 30)
237
238 // Check original remains unchanged
239 if val, _ := original.Get("A"); val != 1 {
240 t.Errorf("Original modified: expected A=1, got A=%v", val)
241 }
242 if val, _ := original.Get("B"); val != 2 {
243 t.Errorf("Original modified: expected B=2, got B=%v", val)
244 }
245
246 // Verify each clone has correct values
247 if val, _ := clone1.Get("A"); val != 10 {
248 t.Errorf("Clone1 incorrect: expected A=10, got A=%v", val)
249 }
250 if val, _ := clone2.Get("B"); val != 20 {
251 t.Errorf("Clone2 incorrect: expected B=20, got B=%v", val)
252 }
253 if val, _ := clone3.Get("C"); val != 30 {
254 t.Errorf("Clone3 incorrect: expected C=30, got C=%v", val)
255 }
256 })
257
258 t.Run("clone after removal", func(t *testing.T) {
259 original := NewTree()
260 original.Set("A", 1)
261 original.Set("B", 2)
262 original.Set("C", 3)
263
264 // Remove a node and then clone
265 original.Remove("B")
266 clone := original.Clone()
267
268 // Modify clone
269 clone.Set("B", 20)
270
271 // Verify original state
272 if original.Has("B") {
273 t.Error("Original tree should not have key B")
274 }
275
276 // Verify clone state
277 if val, _ := clone.Get("B"); val != 20 {
278 t.Errorf("Clone incorrect: expected B=20, got B=%v", val)
279 }
280 })
281
282 t.Run("concurrent modifications", func(t *testing.T) {
283 original := NewTree()
284 original.Set("A", 1)
285 original.Set("B", 2)
286
287 clone1 := original.Clone()
288 clone2 := original.Clone()
289
290 // Modify same key in different clones
291 clone1.Set("B", 20)
292 clone2.Set("B", 30)
293
294 // Each clone should have its own value
295 if val, _ := clone1.Get("B"); val != 20 {
296 t.Errorf("Clone1 incorrect: expected B=20, got B=%v", val)
297 }
298 if val, _ := clone2.Get("B"); val != 30 {
299 t.Errorf("Clone2 incorrect: expected B=30, got B=%v", val)
300 }
301 })
302
303 t.Run("deep tree modifications", func(t *testing.T) {
304 original := NewTree()
305 // Create a deeper tree
306 keys := []string{"M", "F", "T", "B", "H", "P", "Z"}
307 for _, k := range keys {
308 original.Set(k, k)
309 }
310
311 clone := original.Clone()
312
313 // Modify a deep node
314 clone.Set("H", "modified")
315
316 // Check original remains unchanged
317 if val, _ := original.Get("H"); val != "H" {
318 t.Errorf("Original modified: expected H='H', got H=%v", val)
319 }
320
321 // Verify clone modification
322 if val, _ := clone.Get("H"); val != "modified" {
323 t.Errorf("Clone incorrect: expected H='modified', got H=%v", val)
324 }
325 })
326
327 t.Run("rebalancing test", func(t *testing.T) {
328 original := NewTree()
329 // Insert nodes that will cause rotations
330 keys := []string{"A", "B", "C", "D", "E"}
331 for _, k := range keys {
332 original.Set(k, k)
333 }
334
335 clone := original.Clone()
336
337 // Add more nodes to clone to trigger rebalancing
338 clone.Set("F", "F")
339 clone.Set("G", "G")
340
341 // Verify original structure remains unchanged
342 originalKeys := collectKeys(original)
343 expectedOriginal := []string{"A", "B", "C", "D", "E"}
344 if !slicesEqual(originalKeys, expectedOriginal) {
345 t.Errorf("Original tree structure changed: got %v, want %v", originalKeys, expectedOriginal)
346 }
347
348 // Verify clone has all keys
349 cloneKeys := collectKeys(clone)
350 expectedClone := []string{"A", "B", "C", "D", "E", "F", "G"}
351 if !slicesEqual(cloneKeys, expectedClone) {
352 t.Errorf("Clone tree structure incorrect: got %v, want %v", cloneKeys, expectedClone)
353 }
354 })
355
356 t.Run("value mutation test", func(t *testing.T) {
357 type MutableValue struct {
358 Data string
359 }
360
361 original := NewTree()
362 mutable := &MutableValue{Data: "original"}
363 original.Set("key", mutable)
364
365 clone := original.Clone()
366
367 // Modify the mutable value
368 mutable.Data = "modified"
369
370 // Both original and clone should see the modification
371 // because we're not deep copying values
372 origVal, _ := original.Get("key")
373 cloneVal, _ := clone.Get("key")
374
375 if origVal.(*MutableValue).Data != "modified" {
376 t.Error("Original value not modified as expected")
377 }
378 if cloneVal.(*MutableValue).Data != "modified" {
379 t.Error("Clone value not modified as expected")
380 }
381 })
382}
383
384// Helper function to collect all keys in order
385func collectKeys(tree *Tree) []string {
386 var keys []string
387 tree.Iterate("", "", func(key string, _ any) bool {
388 keys = append(keys, key)
389 return false
390 })
391 return keys
392}