list_test.gno

10.54 Kb ยท 491 lines
  1package list
  2
  3import (
  4	"testing"
  5
  6	"gno.land/p/nt/ufmt"
  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 v := l.Get(-1); v != nil {
 36		t.Errorf("expected nil for negative index, got %v", v)
 37	}
 38	if v := l.Get(3); v != nil {
 39		t.Errorf("expected nil for out of bounds index, got %v", v)
 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		if clone.Get(i) != l.Get(i) {
167			t.Errorf("clone.Get(%d) = %v; want %v", i, clone.Get(i), l.Get(i))
168		}
169	}
170
171	// Test independence
172	l.Set(0, 42)
173	if clone.Get(0) == l.Get(0) {
174		t.Error("clone should be independent of original")
175	}
176}
177
178func TestList_DeleteRange(t *testing.T) {
179	var l List
180	l.Append(1, 2, 3, 4, 5)
181
182	// Test valid range delete
183	deleted := l.DeleteRange(1, 4)
184	if deleted != 3 {
185		t.Errorf("DeleteRange(1,4) deleted %d elements; want 3", deleted)
186	}
187	if l.Len() != 2 {
188		t.Errorf("after DeleteRange(1,4) len = %d; want 2", l.Len())
189	}
190	expected := []any{1, 5}
191	for i, want := range expected {
192		if got := l.Get(i); got != want {
193			t.Errorf("after DeleteRange(1,4) index %d = %v; want %v", i, got, want)
194		}
195	}
196
197	// Test edge cases
198	l = List{}
199	l.Append(1, 2, 3)
200
201	// Delete with negative start
202	if deleted := l.DeleteRange(-1, 2); deleted != 2 {
203		t.Errorf("DeleteRange(-1,2) deleted %d elements; want 2", deleted)
204	}
205
206	// Delete with end > length
207	l = List{}
208	l.Append(1, 2, 3)
209	if deleted := l.DeleteRange(1, 5); deleted != 2 {
210		t.Errorf("DeleteRange(1,5) deleted %d elements; want 2", deleted)
211	}
212
213	// Delete invalid range
214	if deleted := l.DeleteRange(2, 1); deleted != 0 {
215		t.Errorf("DeleteRange(2,1) deleted %d elements; want 0", deleted)
216	}
217
218	// Delete empty range
219	if deleted := l.DeleteRange(1, 1); deleted != 0 {
220		t.Errorf("DeleteRange(1,1) deleted %d elements; want 0", deleted)
221	}
222}
223
224func TestList_Tree(t *testing.T) {
225	var l List
226	l.Append(1, 2, 3)
227
228	rotree := l.Tree()
229	expected := 3
230
231	// Reverse iterate through the ReadOnlyTree
232	rotree.ReverseIterateByOffset(0, rotree.Size(), func(key string, value any) bool {
233		intValue := value.(int)
234		if intValue != expected {
235			t.Errorf("ReadOnlyTree expected %d, got %d", expected, intValue)
236		}
237		expected--
238		return false
239	})
240}
241
242func TestList_EmptyOperations(t *testing.T) {
243	var l List
244
245	// Operations on empty list
246	if v := l.Get(0); v != nil {
247		t.Errorf("Get(0) on empty list = %v; want nil", v)
248	}
249
250	// Set should work at index 0 for empty list (append case)
251	if ok := l.Set(0, 1); !ok {
252		t.Error("Set(0,1) on empty list = false; want true")
253	}
254	if v := l.Get(0); v != 1 {
255		t.Errorf("Get(0) after Set = %v; want 1", v)
256	}
257
258	l = List{} // Reset to empty list
259	if v, ok := l.Delete(0); ok || v != nil {
260		t.Errorf("Delete(0) on empty list = %v, %v; want nil, false", v, ok)
261	}
262	if values := l.Slice(0, 1); values != nil {
263		t.Errorf("Range(0,1) on empty list = %v; want nil", values)
264	}
265}
266
267func TestList_DifferentTypes(t *testing.T) {
268	var l List
269
270	// Test with different types
271	l.Append(42, "hello", true, 3.14)
272
273	if v := l.Get(0).(int); v != 42 {
274		t.Errorf("Get(0) = %v; want 42", v)
275	}
276	if v := l.Get(1).(string); v != "hello" {
277		t.Errorf("Get(1) = %v; want 'hello'", v)
278	}
279	if v := l.Get(2).(bool); !v {
280		t.Errorf("Get(2) = %v; want true", v)
281	}
282	if v := l.Get(3).(float64); v != 3.14 {
283		t.Errorf("Get(3) = %v; want 3.14", v)
284	}
285}
286
287func TestList_LargeOperations(t *testing.T) {
288	var l List
289
290	// Test with larger number of elements
291	n := 1000
292	for i := 0; i < n; i++ {
293		l.Append(i)
294	}
295
296	if l.Len() != n {
297		t.Errorf("Len() = %d; want %d", l.Len(), n)
298	}
299
300	// Test range on large list
301	values := l.Slice(n-3, n)
302	expected := []any{n - 3, n - 2, n - 1}
303	if !sliceEqual(values, expected) {
304		t.Errorf("Range(%d,%d) = %v; want %v", n-3, n, values, expected)
305	}
306
307	// Test large range deletion
308	deleted := l.DeleteRange(100, 900)
309	if deleted != 800 {
310		t.Errorf("DeleteRange(100,900) = %d; want 800", deleted)
311	}
312	if l.Len() != 200 {
313		t.Errorf("Len() after large delete = %d; want 200", l.Len())
314	}
315}
316
317func TestList_ChainedOperations(t *testing.T) {
318	var l List
319
320	// Test sequence of operations
321	l.Append(1, 2, 3)
322	l.Delete(1)
323	l.Append(4)
324	l.Set(1, 5)
325
326	expected := []any{1, 5, 4}
327	for i, want := range expected {
328		if got := l.Get(i); got != want {
329			t.Errorf("index %d = %v; want %v", i, got, want)
330		}
331	}
332}
333
334func TestList_RangeEdgeCases(t *testing.T) {
335	var l List
336	l.Append(1, 2, 3, 4, 5)
337
338	// Test various edge cases for Range
339	cases := []struct {
340		start, end int
341		want       []any
342	}{
343		{-10, 2, []any{1, 2}},
344		{3, 10, []any{4, 5}},
345		{0, 0, nil},
346		{5, 5, nil},
347		{4, 3, nil},
348		{-1, -1, nil},
349	}
350
351	for _, tc := range cases {
352		got := l.Slice(tc.start, tc.end)
353		if !sliceEqual(got, tc.want) {
354			t.Errorf("Slice(%d,%d) = %v; want %v", tc.start, tc.end, got, tc.want)
355		}
356	}
357}
358
359func TestList_IndexConsistency(t *testing.T) {
360	var l List
361
362	// Initial additions
363	l.Append(1, 2, 3, 4, 5) // [1,2,3,4,5]
364
365	// Delete from middle
366	l.Delete(2) // [1,2,4,5]
367
368	// Add more elements
369	l.Append(6, 7) // [1,2,4,5,6,7]
370
371	// Delete range from middle
372	l.DeleteRange(1, 4) // [1,6,7]
373
374	// Add more elements
375	l.Append(8, 9, 10) // [1,6,7,8,9,10]
376
377	// Verify sequence is continuous
378	expected := []any{1, 6, 7, 8, 9, 10}
379	for i, want := range expected {
380		if got := l.Get(i); got != want {
381			t.Errorf("index %d = %v; want %v", i, got, want)
382		}
383	}
384
385	// Verify no extra elements exist
386	if l.Len() != len(expected) {
387		t.Errorf("length = %d; want %d", l.Len(), len(expected))
388	}
389
390	// Verify all indices are accessible
391	allValues := l.Slice(0, l.Len())
392	if !sliceEqual(allValues, expected) {
393		t.Errorf("Slice(0, Len()) = %v; want %v", allValues, expected)
394	}
395
396	// Verify no gaps in iteration
397	var iteratedValues []any
398	var indices []int
399	l.ForEach(func(index int, value any) bool {
400		iteratedValues = append(iteratedValues, value)
401		indices = append(indices, index)
402		return false
403	})
404
405	// Check values from iteration
406	if !sliceEqual(iteratedValues, expected) {
407		t.Errorf("ForEach values = %v; want %v", iteratedValues, expected)
408	}
409
410	// Check indices are sequential
411	for i, idx := range indices {
412		if idx != i {
413			t.Errorf("ForEach index %d = %d; want %d", i, idx, i)
414		}
415	}
416}
417
418func TestList_RecursiveSafety(t *testing.T) {
419	// Create a new list
420	l := &List{}
421
422	// Add some initial values
423	l.Append("id1")
424	l.Append("id2")
425	l.Append("id3")
426
427	// Test deep list traversal
428	found := false
429	l.ForEach(func(i int, v any) bool {
430		if str, ok := v.(string); ok {
431			if str == "id2" {
432				found = true
433				return true // stop iteration
434			}
435		}
436		return false // continue iteration
437	})
438
439	if !found {
440		t.Error("Failed to find expected value in list")
441	}
442
443	short := testing.Short()
444
445	// Test recursive safety by performing multiple operations
446	for i := 0; i < 1000; i++ {
447		// Add new value
448		l.Append(ufmt.Sprintf("id%d", i+4))
449
450		if !short {
451			// Search for a value
452			var lastFound bool
453			l.ForEach(func(j int, v any) bool {
454				if str, ok := v.(string); ok {
455					if str == ufmt.Sprintf("id%d", i+3) {
456						lastFound = true
457						return true
458					}
459				}
460				return false
461			})
462
463			if !lastFound {
464				t.Errorf("Failed to find value id%d after insertion", i+3)
465			}
466		}
467	}
468
469	// Verify final length
470	expectedLen := 1003 // 3 initial + 1000 added
471	if l.Len() != expectedLen {
472		t.Errorf("Expected length %d, got %d", expectedLen, l.Len())
473	}
474
475	if short {
476		t.Skip("skipping extended recursive safety test in short mode")
477	}
478}
479
480// Helper function to compare slices
481func sliceEqual(a, b []any) bool {
482	if len(a) != len(b) {
483		return false
484	}
485	for i := range a {
486		if a[i] != b[i] {
487			return false
488		}
489	}
490	return true
491}