Search Apps Documentation Source Content File Folder Download Copy Actions Download

list_test.gno

11.93 Kb · 553 lines
  1package list
  2
  3import (
  4	"testing"
  5
  6	"gno.land/p/nt/ufmt/v0"
  7)
  8
  9func TestList_Basic(t *testing.T) {
 10	var l List
 11
 12	// Test empty list
 13	if l.Len() != 0 {
 14		t.Errorf("new list should be empty, got len %d", l.Len())
 15	}
 16
 17	// Test append and length
 18	l.Append(1, 2, 3)
 19	if l.Len() != 3 {
 20		t.Errorf("expected len 3, got %d", l.Len())
 21	}
 22
 23	// Test get
 24	if v, _ := l.Get(0); v != 1 {
 25		t.Errorf("expected 1 at index 0, got %v", v)
 26	}
 27	if v, _ := l.Get(1); v != 2 {
 28		t.Errorf("expected 2 at index 1, got %v", v)
 29	}
 30	if v, _ := l.Get(2); v != 3 {
 31		t.Errorf("expected 3 at index 2, got %v", v)
 32	}
 33
 34	// Test out of bounds
 35	if _, ok := l.Get(-1); ok {
 36		t.Error("expected ok=false for negative index")
 37	}
 38	if _, ok := l.Get(3); ok {
 39		t.Error("expected ok=false for out of bounds index")
 40	}
 41}
 42
 43func TestList_Set(t *testing.T) {
 44	var l List
 45	l.Append(1, 2, 3)
 46
 47	// Test valid set within bounds
 48	if ok := l.Set(1, 42); !ok {
 49		t.Error("Set should return true for valid index")
 50	}
 51	if v, _ := l.Get(1); v != 42 {
 52		t.Errorf("expected 42 after Set, got %v", v)
 53	}
 54
 55	// Test set at size (append)
 56	if ok := l.Set(3, 4); !ok {
 57		t.Error("Set should return true when appending at size")
 58	}
 59	if v, _ := l.Get(3); v != 4 {
 60		t.Errorf("expected 4 after Set at size, got %v", v)
 61	}
 62
 63	// Test invalid sets
 64	if ok := l.Set(-1, 10); ok {
 65		t.Error("Set should return false for negative index")
 66	}
 67	if ok := l.Set(5, 10); ok {
 68		t.Error("Set should return false for index > size")
 69	}
 70
 71	// Verify list state hasn't changed after invalid operations
 72	expected := []any{1, 42, 3, 4}
 73	for i, want := range expected {
 74		if got, _ := l.Get(i); got != want {
 75			t.Errorf("index %d = %v; want %v", i, got, want)
 76		}
 77	}
 78}
 79
 80func TestList_Delete(t *testing.T) {
 81	var l List
 82	l.Append(1, 2, 3)
 83
 84	// Test valid delete
 85	if v, ok := l.Delete(1); !ok || v != 2 {
 86		t.Errorf("Delete(1) = %v, %v; want 2, true", v, ok)
 87	}
 88	if l.Len() != 2 {
 89		t.Errorf("expected len 2 after delete, got %d", l.Len())
 90	}
 91	if v, _ := l.Get(1); v != 3 {
 92		t.Errorf("expected 3 at index 1 after delete, got %v", v)
 93	}
 94
 95	// Test invalid delete
 96	if v, ok := l.Delete(-1); ok || v != nil {
 97		t.Errorf("Delete(-1) = %v, %v; want nil, false", v, ok)
 98	}
 99	if v, ok := l.Delete(2); ok || v != nil {
100		t.Errorf("Delete(2) = %v, %v; want nil, false", v, ok)
101	}
102}
103
104func TestList_Slice(t *testing.T) {
105	var l List
106	l.Append(1, 2, 3, 4, 5)
107
108	// Test valid ranges
109	values := l.Slice(1, 4)
110	expected := []any{2, 3, 4}
111	if !sliceEqual(values, expected) {
112		t.Errorf("Slice(1,4) = %v; want %v", values, expected)
113	}
114
115	// Test edge cases
116	if values := l.Slice(-1, 2); !sliceEqual(values, []any{1, 2}) {
117		t.Errorf("Slice(-1,2) = %v; want [1 2]", values)
118	}
119	if values := l.Slice(3, 10); !sliceEqual(values, []any{4, 5}) {
120		t.Errorf("Slice(3,10) = %v; want [4 5]", values)
121	}
122	if values := l.Slice(3, 2); values != nil {
123		t.Errorf("Slice(3,2) = %v; want nil", values)
124	}
125}
126
127func TestList_ForEach(t *testing.T) {
128	var l List
129	l.Append(1, 2, 3)
130
131	sum := 0
132	l.ForEach(func(index int, value any) bool {
133		sum += value.(int)
134		return false
135	})
136
137	if sum != 6 {
138		t.Errorf("ForEach sum = %d; want 6", sum)
139	}
140
141	// Test early termination
142	count := 0
143	l.ForEach(func(index int, value any) bool {
144		count++
145		return true // stop after first item
146	})
147
148	if count != 1 {
149		t.Errorf("ForEach early termination count = %d; want 1", count)
150	}
151}
152
153func TestList_Clone(t *testing.T) {
154	var l List
155	l.Append(1, 2, 3)
156
157	clone := l.Clone()
158
159	// Test same length
160	if clone.Len() != l.Len() {
161		t.Errorf("clone.Len() = %d; want %d", clone.Len(), l.Len())
162	}
163
164	// Test same values
165	for i := 0; i < l.Len(); i++ {
166		cv, _ := clone.Get(i)
167		lv, _ := l.Get(i)
168		if cv != lv {
169			t.Errorf("clone.Get(%d) = %v; want %v", i, cv, lv)
170		}
171	}
172
173	// Test independence
174	l.Set(0, 42)
175	cv, _ := clone.Get(0)
176	lv, _ := l.Get(0)
177	if cv == lv {
178		t.Error("clone should be independent of original")
179	}
180
181	// Test that appending to both after clone works independently.
182	var l2 List
183	l2.Append("a", "b", "c")
184	clone2 := l2.Clone()
185
186	l2.Append("d", "e")
187	clone2.Append("x", "y")
188
189	if l2.Len() != 5 {
190		t.Errorf("original after append: Len() = %d; want 5", l2.Len())
191	}
192	if clone2.Len() != 5 {
193		t.Errorf("clone after append: Len() = %d; want 5", clone2.Len())
194	}
195	origExpected := []any{"a", "b", "c", "d", "e"}
196	cloneExpected := []any{"a", "b", "c", "x", "y"}
197	for i := 0; i < 5; i++ {
198		ov, _ := l2.Get(i)
199		if ov != origExpected[i] {
200			t.Errorf("original.Get(%d) = %v; want %v", i, ov, origExpected[i])
201		}
202		cv, _ := clone2.Get(i)
203		if cv != cloneExpected[i] {
204			t.Errorf("clone.Get(%d) = %v; want %v", i, cv, cloneExpected[i])
205		}
206	}
207}
208
209func TestList_DeleteRange(t *testing.T) {
210	var l List
211	l.Append(1, 2, 3, 4, 5)
212
213	// Test valid range delete
214	deleted := l.DeleteRange(1, 4)
215	if deleted != 3 {
216		t.Errorf("DeleteRange(1,4) deleted %d elements; want 3", deleted)
217	}
218	if l.Len() != 2 {
219		t.Errorf("after DeleteRange(1,4) len = %d; want 2", l.Len())
220	}
221	expected := []any{1, 5}
222	for i, want := range expected {
223		if got, _ := l.Get(i); got != want {
224			t.Errorf("after DeleteRange(1,4) index %d = %v; want %v", i, got, want)
225		}
226	}
227
228	// Test edge cases
229	l = List{}
230	l.Append(1, 2, 3)
231
232	// Delete with negative start
233	if deleted := l.DeleteRange(-1, 2); deleted != 2 {
234		t.Errorf("DeleteRange(-1,2) deleted %d elements; want 2", deleted)
235	}
236
237	// Delete with end > length
238	l = List{}
239	l.Append(1, 2, 3)
240	if deleted := l.DeleteRange(1, 5); deleted != 2 {
241		t.Errorf("DeleteRange(1,5) deleted %d elements; want 2", deleted)
242	}
243
244	// Delete invalid range
245	if deleted := l.DeleteRange(2, 1); deleted != 0 {
246		t.Errorf("DeleteRange(2,1) deleted %d elements; want 0", deleted)
247	}
248
249	// Delete empty range
250	if deleted := l.DeleteRange(1, 1); deleted != 0 {
251		t.Errorf("DeleteRange(1,1) deleted %d elements; want 0", deleted)
252	}
253}
254
255func TestList_Tree(t *testing.T) {
256	var l List
257	l.Append(1, 2, 3)
258
259	rotree := l.Tree()
260	expected := 3
261
262	// Reverse iterate through the ReadOnlyTree
263	rotree.ReverseIterateByOffset(0, rotree.Size(), func(key string, value any) bool {
264		intValue := value.(int)
265		if intValue != expected {
266			t.Errorf("ReadOnlyTree expected %d, got %d", expected, intValue)
267		}
268		expected--
269		return false
270	})
271}
272
273func TestList_EmptyOperations(t *testing.T) {
274	var l List
275
276	// Operations on empty list
277	if _, ok := l.Get(0); ok {
278		t.Error("Get(0) on empty list should return ok=false")
279	}
280
281	// Set should work at index 0 for empty list (append case)
282	if ok := l.Set(0, 1); !ok {
283		t.Error("Set(0,1) on empty list = false; want true")
284	}
285	if v, _ := l.Get(0); v != 1 {
286		t.Errorf("Get(0) after Set = %v; want 1", v)
287	}
288
289	l = List{} // Reset to empty list
290	if v, ok := l.Delete(0); ok || v != nil {
291		t.Errorf("Delete(0) on empty list = %v, %v; want nil, false", v, ok)
292	}
293	if values := l.Slice(0, 1); values != nil {
294		t.Errorf("Range(0,1) on empty list = %v; want nil", values)
295	}
296}
297
298func TestList_DifferentTypes(t *testing.T) {
299	var l List
300
301	// Test with different types
302	l.Append(42, "hello", true, 3.14)
303
304	v0, _ := l.Get(0)
305	if v := v0.(int); v != 42 {
306		t.Errorf("Get(0) = %v; want 42", v)
307	}
308	v1, _ := l.Get(1)
309	if v := v1.(string); v != "hello" {
310		t.Errorf("Get(1) = %v; want 'hello'", v)
311	}
312	v2, _ := l.Get(2)
313	if v := v2.(bool); !v {
314		t.Errorf("Get(2) = %v; want true", v)
315	}
316	v3, _ := l.Get(3)
317	if v := v3.(float64); v != 3.14 {
318		t.Errorf("Get(3) = %v; want 3.14", v)
319	}
320}
321
322func TestList_LargeOperations(t *testing.T) {
323	var l List
324
325	// Test with larger number of elements
326	n := 1000
327	for i := 0; i < n; i++ {
328		l.Append(i)
329	}
330
331	if l.Len() != n {
332		t.Errorf("Len() = %d; want %d", l.Len(), n)
333	}
334
335	// Test range on large list
336	values := l.Slice(n-3, n)
337	expected := []any{n - 3, n - 2, n - 1}
338	if !sliceEqual(values, expected) {
339		t.Errorf("Range(%d,%d) = %v; want %v", n-3, n, values, expected)
340	}
341
342	// Test large range deletion
343	deleted := l.DeleteRange(100, 900)
344	if deleted != 800 {
345		t.Errorf("DeleteRange(100,900) = %d; want 800", deleted)
346	}
347	if l.Len() != 200 {
348		t.Errorf("Len() after large delete = %d; want 200", l.Len())
349	}
350}
351
352func TestList_ChainedOperations(t *testing.T) {
353	var l List
354
355	// Test sequence of operations
356	l.Append(1, 2, 3)
357	l.Delete(1)
358	l.Append(4)
359	l.Set(1, 5)
360
361	expected := []any{1, 5, 4}
362	for i, want := range expected {
363		if got, _ := l.Get(i); got != want {
364			t.Errorf("index %d = %v; want %v", i, got, want)
365		}
366	}
367}
368
369func TestList_RangeEdgeCases(t *testing.T) {
370	var l List
371	l.Append(1, 2, 3, 4, 5)
372
373	// Test various edge cases for Range
374	cases := []struct {
375		start, end int
376		want       []any
377	}{
378		{-10, 2, []any{1, 2}},
379		{3, 10, []any{4, 5}},
380		{0, 0, nil},
381		{5, 5, nil},
382		{4, 3, nil},
383		{-1, -1, nil},
384	}
385
386	for _, tc := range cases {
387		got := l.Slice(tc.start, tc.end)
388		if !sliceEqual(got, tc.want) {
389			t.Errorf("Slice(%d,%d) = %v; want %v", tc.start, tc.end, got, tc.want)
390		}
391	}
392}
393
394func TestList_IndexConsistency(t *testing.T) {
395	var l List
396
397	// Initial additions
398	l.Append(1, 2, 3, 4, 5) // [1,2,3,4,5]
399
400	// Delete from middle
401	l.Delete(2) // [1,2,4,5]
402
403	// Add more elements
404	l.Append(6, 7) // [1,2,4,5,6,7]
405
406	// Delete range from middle
407	l.DeleteRange(1, 4) // [1,6,7]
408
409	// Add more elements
410	l.Append(8, 9, 10) // [1,6,7,8,9,10]
411
412	// Verify sequence is continuous
413	expected := []any{1, 6, 7, 8, 9, 10}
414	for i, want := range expected {
415		if got, _ := l.Get(i); got != want {
416			t.Errorf("index %d = %v; want %v", i, got, want)
417		}
418	}
419
420	// Verify no extra elements exist
421	if l.Len() != len(expected) {
422		t.Errorf("length = %d; want %d", l.Len(), len(expected))
423	}
424
425	// Verify all indices are accessible
426	allValues := l.Slice(0, l.Len())
427	if !sliceEqual(allValues, expected) {
428		t.Errorf("Slice(0, Len()) = %v; want %v", allValues, expected)
429	}
430
431	// Verify no gaps in iteration
432	var iteratedValues []any
433	var indices []int
434	l.ForEach(func(index int, value any) bool {
435		iteratedValues = append(iteratedValues, value)
436		indices = append(indices, index)
437		return false
438	})
439
440	// Check values from iteration
441	if !sliceEqual(iteratedValues, expected) {
442		t.Errorf("ForEach values = %v; want %v", iteratedValues, expected)
443	}
444
445	// Check indices are sequential
446	for i, idx := range indices {
447		if idx != i {
448			t.Errorf("ForEach index %d = %d; want %d", i, idx, i)
449		}
450	}
451}
452
453func TestList_RecursiveSafety(t *testing.T) {
454	// Create a new list
455	l := &List{}
456
457	// Add some initial values
458	l.Append("id1")
459	l.Append("id2")
460	l.Append("id3")
461
462	// Test deep list traversal
463	found := false
464	l.ForEach(func(i int, v any) bool {
465		if str, ok := v.(string); ok {
466			if str == "id2" {
467				found = true
468				return true // stop iteration
469			}
470		}
471		return false // continue iteration
472	})
473
474	if !found {
475		t.Error("Failed to find expected value in list")
476	}
477
478	short := testing.Short()
479
480	// Test recursive safety by performing multiple operations
481	for i := 0; i < 1000; i++ {
482		// Add new value
483		l.Append(ufmt.Sprintf("id%d", i+4))
484
485		if !short {
486			// Search for a value
487			var lastFound bool
488			l.ForEach(func(j int, v any) bool {
489				if str, ok := v.(string); ok {
490					if str == ufmt.Sprintf("id%d", i+3) {
491						lastFound = true
492						return true
493					}
494				}
495				return false
496			})
497
498			if !lastFound {
499				t.Errorf("Failed to find value id%d after insertion", i+3)
500			}
501		}
502	}
503
504	// Verify final length
505	expectedLen := 1003 // 3 initial + 1000 added
506	if l.Len() != expectedLen {
507		t.Errorf("Expected length %d, got %d", expectedLen, l.Len())
508	}
509
510	if short {
511		t.Skip("skipping extended recursive safety test in short mode")
512	}
513}
514
515func TestList_NilValueDistinguishable(t *testing.T) {
516	var l List
517	l.Append(nil)
518	l.Append("hello")
519
520	// Stored nil is distinguishable from out-of-bounds.
521	v, ok := l.Get(0)
522	if !ok {
523		t.Error("Get(0) should return ok=true for stored nil")
524	}
525	if v != nil {
526		t.Errorf("Get(0) should return nil value, got %v", v)
527	}
528
529	// Out of bounds returns false.
530	_, ok = l.Get(5)
531	if ok {
532		t.Error("Get(5) should return ok=false for out of bounds")
533	}
534
535	// Normal value still works.
536	v, ok = l.Get(1)
537	if !ok || v != "hello" {
538		t.Errorf("Get(1) = (%v, %v); want (hello, true)", v, ok)
539	}
540}
541
542// Helper function to compare slices
543func sliceEqual(a, b []any) bool {
544	if len(a) != len(b) {
545		return false
546	}
547	for i := range a {
548		if a[i] != b[i] {
549			return false
550		}
551	}
552	return true
553}