ulist_test.gno
27.10 Kb ยท 1422 lines
1package ulist
2
3import (
4 "testing"
5
6 "gno.land/p/demo/uassert"
7 "gno.land/p/demo/ufmt"
8 "gno.land/p/moul/typeutil"
9)
10
11func TestNew(t *testing.T) {
12 l := New()
13 uassert.Equal(t, 0, l.Size())
14 uassert.Equal(t, 0, l.TotalSize())
15}
16
17func TestListAppendAndGet(t *testing.T) {
18 tests := []struct {
19 name string
20 setup func() *List
21 index int
22 expected any
23 }{
24 {
25 name: "empty list",
26 setup: func() *List {
27 return New()
28 },
29 index: 0,
30 expected: nil,
31 },
32 {
33 name: "single append and get",
34 setup: func() *List {
35 l := New()
36 l.Append(42)
37 return l
38 },
39 index: 0,
40 expected: 42,
41 },
42 {
43 name: "multiple appends and get first",
44 setup: func() *List {
45 l := New()
46 l.Append(1)
47 l.Append(2)
48 l.Append(3)
49 return l
50 },
51 index: 0,
52 expected: 1,
53 },
54 {
55 name: "multiple appends and get last",
56 setup: func() *List {
57 l := New()
58 l.Append(1)
59 l.Append(2)
60 l.Append(3)
61 return l
62 },
63 index: 2,
64 expected: 3,
65 },
66 {
67 name: "get with invalid index",
68 setup: func() *List {
69 l := New()
70 l.Append(1)
71 return l
72 },
73 index: 1,
74 expected: nil,
75 },
76 {
77 name: "31 items get first",
78 setup: func() *List {
79 l := New()
80 for i := 0; i < 31; i++ {
81 l.Append(i)
82 }
83 return l
84 },
85 index: 0,
86 expected: 0,
87 },
88 {
89 name: "31 items get last",
90 setup: func() *List {
91 l := New()
92 for i := 0; i < 31; i++ {
93 l.Append(i)
94 }
95 return l
96 },
97 index: 30,
98 expected: 30,
99 },
100 {
101 name: "31 items get middle",
102 setup: func() *List {
103 l := New()
104 for i := 0; i < 31; i++ {
105 l.Append(i)
106 }
107 return l
108 },
109 index: 15,
110 expected: 15,
111 },
112 {
113 name: "values around power of 2 boundary",
114 setup: func() *List {
115 l := New()
116 for i := 0; i < 18; i++ {
117 l.Append(i)
118 }
119 return l
120 },
121 index: 15,
122 expected: 15,
123 },
124 {
125 name: "values at power of 2",
126 setup: func() *List {
127 l := New()
128 for i := 0; i < 18; i++ {
129 l.Append(i)
130 }
131 return l
132 },
133 index: 16,
134 expected: 16,
135 },
136 {
137 name: "values after power of 2",
138 setup: func() *List {
139 l := New()
140 for i := 0; i < 18; i++ {
141 l.Append(i)
142 }
143 return l
144 },
145 index: 17,
146 expected: 17,
147 },
148 }
149
150 for _, tt := range tests {
151 t.Run(tt.name, func(t *testing.T) {
152 l := tt.setup()
153 got := l.Get(tt.index)
154 if got != tt.expected {
155 t.Errorf("List.Get() = %v, want %v", got, tt.expected)
156 }
157 })
158 }
159}
160
161// generateSequence creates a slice of integers from 0 to n-1
162func generateSequence(n int) []any {
163 result := make([]any, n)
164 for i := 0; i < n; i++ {
165 result[i] = i
166 }
167 return result
168}
169
170func TestListDelete(t *testing.T) {
171 tests := []struct {
172 name string
173 setup func() *List
174 deleteIndices []int
175 expectedErr error
176 expectedSize int
177 }{
178 {
179 name: "delete single element",
180 setup: func() *List {
181 l := New()
182 l.Append(1, 2, 3)
183 return l
184 },
185 deleteIndices: []int{1},
186 expectedErr: nil,
187 expectedSize: 2,
188 },
189 {
190 name: "delete multiple elements",
191 setup: func() *List {
192 l := New()
193 l.Append(1, 2, 3, 4, 5)
194 return l
195 },
196 deleteIndices: []int{0, 2, 4},
197 expectedErr: nil,
198 expectedSize: 2,
199 },
200 {
201 name: "delete with negative index",
202 setup: func() *List {
203 l := New()
204 l.Append(1)
205 return l
206 },
207 deleteIndices: []int{-1},
208 expectedErr: ErrOutOfBounds,
209 expectedSize: 1,
210 },
211 {
212 name: "delete beyond size",
213 setup: func() *List {
214 l := New()
215 l.Append(1)
216 return l
217 },
218 deleteIndices: []int{1},
219 expectedErr: ErrOutOfBounds,
220 expectedSize: 1,
221 },
222 {
223 name: "delete already deleted element",
224 setup: func() *List {
225 l := New()
226 l.Append(1)
227 l.Delete(0)
228 return l
229 },
230 deleteIndices: []int{0},
231 expectedErr: ErrDeleted,
232 expectedSize: 0,
233 },
234 {
235 name: "delete multiple elements in reverse",
236 setup: func() *List {
237 l := New()
238 l.Append(1, 2, 3, 4, 5)
239 return l
240 },
241 deleteIndices: []int{4, 2, 0},
242 expectedErr: nil,
243 expectedSize: 2,
244 },
245 }
246
247 for _, tt := range tests {
248 t.Run(tt.name, func(t *testing.T) {
249 l := tt.setup()
250 initialSize := l.Size()
251 err := l.Delete(tt.deleteIndices...)
252 if err != nil && tt.expectedErr != nil {
253 uassert.Equal(t, tt.expectedErr.Error(), err.Error())
254 } else {
255 uassert.Equal(t, tt.expectedErr, err)
256 }
257 uassert.Equal(t, tt.expectedSize, l.Size(),
258 ufmt.Sprintf("Expected size %d after deleting %d elements from size %d, got %d",
259 tt.expectedSize, len(tt.deleteIndices), initialSize, l.Size()))
260 })
261 }
262}
263
264func TestListSizeAndTotalSize(t *testing.T) {
265 t.Run("empty list", func(t *testing.T) {
266 list := New()
267 uassert.Equal(t, 0, list.Size())
268 uassert.Equal(t, 0, list.TotalSize())
269 })
270
271 t.Run("list with elements", func(t *testing.T) {
272 list := New()
273 list.Append(1)
274 list.Append(2)
275 list.Append(3)
276 uassert.Equal(t, 3, list.Size())
277 uassert.Equal(t, 3, list.TotalSize())
278 })
279
280 t.Run("list with deleted elements", func(t *testing.T) {
281 list := New()
282 list.Append(1)
283 list.Append(2)
284 list.Append(3)
285 list.Delete(1)
286 uassert.Equal(t, 2, list.Size())
287 uassert.Equal(t, 3, list.TotalSize())
288 })
289}
290
291func TestIterator(t *testing.T) {
292 tests := []struct {
293 name string
294 values []any
295 start int
296 end int
297 expected []Entry
298 wantStop bool
299 stopAfter int // stop after N elements, -1 for no stop
300 }{
301 {
302 name: "empty list",
303 values: []any{},
304 start: 0,
305 end: 10,
306 expected: []Entry{},
307 stopAfter: -1,
308 },
309 {
310 name: "nil list",
311 values: nil,
312 start: 0,
313 end: 0,
314 expected: []Entry{},
315 stopAfter: -1,
316 },
317 {
318 name: "single element forward",
319 values: []any{42},
320 start: 0,
321 end: 0,
322 expected: []Entry{
323 {Index: 0, Value: 42},
324 },
325 stopAfter: -1,
326 },
327 {
328 name: "multiple elements forward",
329 values: []any{1, 2, 3, 4, 5},
330 start: 0,
331 end: 4,
332 expected: []Entry{
333 {Index: 0, Value: 1},
334 {Index: 1, Value: 2},
335 {Index: 2, Value: 3},
336 {Index: 3, Value: 4},
337 {Index: 4, Value: 5},
338 },
339 stopAfter: -1,
340 },
341 {
342 name: "multiple elements reverse",
343 values: []any{1, 2, 3, 4, 5},
344 start: 4,
345 end: 0,
346 expected: []Entry{
347 {Index: 4, Value: 5},
348 {Index: 3, Value: 4},
349 {Index: 2, Value: 3},
350 {Index: 1, Value: 2},
351 {Index: 0, Value: 1},
352 },
353 stopAfter: -1,
354 },
355 {
356 name: "partial range forward",
357 values: []any{1, 2, 3, 4, 5},
358 start: 1,
359 end: 3,
360 expected: []Entry{
361 {Index: 1, Value: 2},
362 {Index: 2, Value: 3},
363 {Index: 3, Value: 4},
364 },
365 stopAfter: -1,
366 },
367 {
368 name: "partial range reverse",
369 values: []any{1, 2, 3, 4, 5},
370 start: 3,
371 end: 1,
372 expected: []Entry{
373 {Index: 3, Value: 4},
374 {Index: 2, Value: 3},
375 {Index: 1, Value: 2},
376 },
377 stopAfter: -1,
378 },
379 {
380 name: "stop iteration early",
381 values: []any{1, 2, 3, 4, 5},
382 start: 0,
383 end: 4,
384 wantStop: true,
385 stopAfter: 2,
386 expected: []Entry{
387 {Index: 0, Value: 1},
388 {Index: 1, Value: 2},
389 },
390 },
391 {
392 name: "negative start",
393 values: []any{1, 2, 3},
394 start: -1,
395 end: 2,
396 expected: []Entry{
397 {Index: 0, Value: 1},
398 {Index: 1, Value: 2},
399 {Index: 2, Value: 3},
400 },
401 stopAfter: -1,
402 },
403 {
404 name: "negative end",
405 values: []any{1, 2, 3},
406 start: 0,
407 end: -2,
408 expected: []Entry{
409 {Index: 0, Value: 1},
410 },
411 stopAfter: -1,
412 },
413 {
414 name: "start beyond size",
415 values: []any{1, 2, 3},
416 start: 5,
417 end: 6,
418 expected: []Entry{},
419 stopAfter: -1,
420 },
421 {
422 name: "end beyond size",
423 values: []any{1, 2, 3},
424 start: 0,
425 end: 5,
426 expected: []Entry{
427 {Index: 0, Value: 1},
428 {Index: 1, Value: 2},
429 {Index: 2, Value: 3},
430 },
431 stopAfter: -1,
432 },
433 {
434 name: "with deleted elements",
435 values: []any{1, 2, nil, 4, 5},
436 start: 0,
437 end: 4,
438 expected: []Entry{
439 {Index: 0, Value: 1},
440 {Index: 1, Value: 2},
441 {Index: 3, Value: 4},
442 {Index: 4, Value: 5},
443 },
444 stopAfter: -1,
445 },
446 {
447 name: "with deleted elements reverse",
448 values: []any{1, nil, 3, nil, 5},
449 start: 4,
450 end: 0,
451 expected: []Entry{
452 {Index: 4, Value: 5},
453 {Index: 2, Value: 3},
454 {Index: 0, Value: 1},
455 },
456 stopAfter: -1,
457 },
458 {
459 name: "start equals end",
460 values: []any{1, 2, 3},
461 start: 1,
462 end: 1,
463 expected: []Entry{{Index: 1, Value: 2}},
464 stopAfter: -1,
465 },
466 }
467
468 for _, tt := range tests {
469 t.Run(tt.name, func(t *testing.T) {
470 list := New()
471 list.Append(tt.values...)
472
473 var result []Entry
474 stopped := list.Iterator(tt.start, tt.end, func(index int, value any) bool {
475 result = append(result, Entry{Index: index, Value: value})
476 return tt.stopAfter >= 0 && len(result) >= tt.stopAfter
477 })
478
479 uassert.Equal(t, len(result), len(tt.expected), "comparing length")
480
481 for i := range result {
482 uassert.Equal(t, result[i].Index, tt.expected[i].Index, "comparing index")
483 uassert.Equal(t, typeutil.ToString(result[i].Value), typeutil.ToString(tt.expected[i].Value), "comparing value")
484 }
485
486 uassert.Equal(t, stopped, tt.wantStop, "comparing stopped")
487 })
488 }
489}
490
491func TestLargeListAppendGetAndDelete(t *testing.T) {
492 l := New()
493 size := 100
494
495 // Append values from 0 to 99
496 for i := 0; i < size; i++ {
497 l.Append(i)
498 val := l.Get(i)
499 uassert.Equal(t, i, val)
500 }
501
502 // Verify size
503 uassert.Equal(t, size, l.Size())
504 uassert.Equal(t, size, l.TotalSize())
505
506 // Get and verify each value
507 for i := 0; i < size; i++ {
508 val := l.Get(i)
509 uassert.Equal(t, i, val)
510 }
511
512 // Get and verify each value
513 for i := 0; i < size; i++ {
514 err := l.Delete(i)
515 uassert.Equal(t, nil, err)
516 }
517
518 // Verify size
519 uassert.Equal(t, 0, l.Size())
520 uassert.Equal(t, size, l.TotalSize())
521
522 // Get and verify each value
523 for i := 0; i < size; i++ {
524 val := l.Get(i)
525 uassert.Equal(t, nil, val)
526 }
527}
528
529func TestEdgeCases(t *testing.T) {
530 tests := []struct {
531 name string
532 test func(t *testing.T)
533 }{
534 {
535 name: "nil list operations",
536 test: func(t *testing.T) {
537 var l *List
538 uassert.Equal(t, 0, l.Size())
539 uassert.Equal(t, 0, l.TotalSize())
540 uassert.Equal(t, nil, l.Get(0))
541 err := l.Delete(0)
542 uassert.Equal(t, ErrOutOfBounds.Error(), err.Error())
543 },
544 },
545 {
546 name: "delete empty indices slice",
547 test: func(t *testing.T) {
548 l := New()
549 l.Append(1)
550 err := l.Delete()
551 uassert.Equal(t, nil, err)
552 uassert.Equal(t, 1, l.Size())
553 },
554 },
555 {
556 name: "append nil values",
557 test: func(t *testing.T) {
558 l := New()
559 l.Append(nil, nil)
560 uassert.Equal(t, 2, l.Size())
561 uassert.Equal(t, nil, l.Get(0))
562 uassert.Equal(t, nil, l.Get(1))
563 },
564 },
565 {
566 name: "delete same index multiple times",
567 test: func(t *testing.T) {
568 l := New()
569 l.Append(1, 2, 3)
570 err := l.Delete(1)
571 uassert.Equal(t, nil, err)
572 err = l.Delete(1)
573 uassert.Equal(t, ErrDeleted.Error(), err.Error())
574 },
575 },
576 {
577 name: "iterator with all deleted elements",
578 test: func(t *testing.T) {
579 l := New()
580 l.Append(1, 2, 3)
581 l.Delete(0, 1, 2)
582 var count int
583 l.Iterator(0, 2, func(index int, value any) bool {
584 count++
585 return false
586 })
587 uassert.Equal(t, 0, count)
588 },
589 },
590 {
591 name: "append after delete",
592 test: func(t *testing.T) {
593 l := New()
594 l.Append(1, 2)
595 l.Delete(1)
596 l.Append(3)
597 uassert.Equal(t, 2, l.Size())
598 uassert.Equal(t, 3, l.TotalSize())
599 uassert.Equal(t, 1, l.Get(0))
600 uassert.Equal(t, nil, l.Get(1))
601 uassert.Equal(t, 3, l.Get(2))
602 },
603 },
604 }
605
606 for _, tt := range tests {
607 t.Run(tt.name, func(t *testing.T) {
608 tt.test(t)
609 })
610 }
611}
612
613func TestIteratorByOffset(t *testing.T) {
614 tests := []struct {
615 name string
616 values []any
617 offset int
618 count int
619 expected []Entry
620 wantStop bool
621 }{
622 {
623 name: "empty list",
624 values: []any{},
625 offset: 0,
626 count: 5,
627 expected: []Entry{},
628 wantStop: false,
629 },
630 {
631 name: "positive count forward iteration",
632 values: []any{1, 2, 3, 4, 5},
633 offset: 1,
634 count: 2,
635 expected: []Entry{
636 {Index: 1, Value: 2},
637 {Index: 2, Value: 3},
638 },
639 wantStop: false,
640 },
641 {
642 name: "negative count backward iteration",
643 values: []any{1, 2, 3, 4, 5},
644 offset: 3,
645 count: -2,
646 expected: []Entry{
647 {Index: 3, Value: 4},
648 {Index: 2, Value: 3},
649 },
650 wantStop: false,
651 },
652 {
653 name: "count exceeds available elements forward",
654 values: []any{1, 2, 3},
655 offset: 1,
656 count: 5,
657 expected: []Entry{
658 {Index: 1, Value: 2},
659 {Index: 2, Value: 3},
660 },
661 wantStop: false,
662 },
663 {
664 name: "count exceeds available elements backward",
665 values: []any{1, 2, 3},
666 offset: 1,
667 count: -5,
668 expected: []Entry{
669 {Index: 1, Value: 2},
670 {Index: 0, Value: 1},
671 },
672 wantStop: false,
673 },
674 {
675 name: "zero count",
676 values: []any{1, 2, 3},
677 offset: 0,
678 count: 0,
679 expected: []Entry{},
680 wantStop: false,
681 },
682 {
683 name: "negative offset",
684 values: []any{1, 2, 3},
685 offset: -1,
686 count: 2,
687 expected: []Entry{
688 {Index: 0, Value: 1},
689 {Index: 1, Value: 2},
690 },
691 wantStop: false,
692 },
693 {
694 name: "offset beyond size",
695 values: []any{1, 2, 3},
696 offset: 5,
697 count: -2,
698 expected: []Entry{
699 {Index: 2, Value: 3},
700 {Index: 1, Value: 2},
701 },
702 wantStop: false,
703 },
704 {
705 name: "with deleted elements",
706 values: []any{1, nil, 3, nil, 5},
707 offset: 0,
708 count: 3,
709 expected: []Entry{
710 {Index: 0, Value: 1},
711 {Index: 2, Value: 3},
712 {Index: 4, Value: 5},
713 },
714 wantStop: false,
715 },
716 {
717 name: "early stop in forward iteration",
718 values: []any{1, 2, 3, 4, 5},
719 offset: 0,
720 count: 5,
721 expected: []Entry{
722 {Index: 0, Value: 1},
723 {Index: 1, Value: 2},
724 },
725 wantStop: true, // The callback will return true after 2 elements
726 },
727 {
728 name: "early stop in backward iteration",
729 values: []any{1, 2, 3, 4, 5},
730 offset: 4,
731 count: -5,
732 expected: []Entry{
733 {Index: 4, Value: 5},
734 {Index: 3, Value: 4},
735 },
736 wantStop: true, // The callback will return true after 2 elements
737 },
738 {
739 name: "nil list",
740 values: nil,
741 offset: 0,
742 count: 5,
743 expected: []Entry{},
744 wantStop: false,
745 },
746 {
747 name: "single element forward",
748 values: []any{1},
749 offset: 0,
750 count: 5,
751 expected: []Entry{
752 {Index: 0, Value: 1},
753 },
754 wantStop: false,
755 },
756 {
757 name: "single element backward",
758 values: []any{1},
759 offset: 0,
760 count: -5,
761 expected: []Entry{
762 {Index: 0, Value: 1},
763 },
764 wantStop: false,
765 },
766 {
767 name: "all deleted elements",
768 values: []any{nil, nil, nil},
769 offset: 0,
770 count: 3,
771 expected: []Entry{},
772 wantStop: false,
773 },
774 }
775
776 for _, tt := range tests {
777 t.Run(tt.name, func(t *testing.T) {
778 list := New()
779 list.Append(tt.values...)
780
781 var result []Entry
782 var cb IterCbFn
783 if tt.wantStop {
784 cb = func(index int, value any) bool {
785 result = append(result, Entry{Index: index, Value: value})
786 return len(result) >= 2 // Stop after 2 elements for early stop tests
787 }
788 } else {
789 cb = func(index int, value any) bool {
790 result = append(result, Entry{Index: index, Value: value})
791 return false
792 }
793 }
794
795 stopped := list.IteratorByOffset(tt.offset, tt.count, cb)
796
797 uassert.Equal(t, len(tt.expected), len(result), "comparing length")
798 for i := range result {
799 uassert.Equal(t, tt.expected[i].Index, result[i].Index, "comparing index")
800 uassert.Equal(t, typeutil.ToString(tt.expected[i].Value), typeutil.ToString(result[i].Value), "comparing value")
801 }
802 uassert.Equal(t, tt.wantStop, stopped, "comparing stopped")
803 })
804 }
805}
806
807func TestMustDelete(t *testing.T) {
808 tests := []struct {
809 name string
810 setup func() *List
811 indices []int
812 shouldPanic bool
813 panicMsg string
814 }{
815 {
816 name: "successful delete",
817 setup: func() *List {
818 l := New()
819 l.Append(1, 2, 3)
820 return l
821 },
822 indices: []int{1},
823 shouldPanic: false,
824 },
825 {
826 name: "out of bounds",
827 setup: func() *List {
828 l := New()
829 l.Append(1)
830 return l
831 },
832 indices: []int{1},
833 shouldPanic: true,
834 panicMsg: ErrOutOfBounds.Error(),
835 },
836 {
837 name: "already deleted",
838 setup: func() *List {
839 l := New()
840 l.Append(1)
841 l.Delete(0)
842 return l
843 },
844 indices: []int{0},
845 shouldPanic: true,
846 panicMsg: ErrDeleted.Error(),
847 },
848 }
849
850 for _, tt := range tests {
851 t.Run(tt.name, func(t *testing.T) {
852 l := tt.setup()
853 if tt.shouldPanic {
854 defer func() {
855 r := recover()
856 if r == nil {
857 t.Error("Expected panic but got none")
858 }
859 err, ok := r.(error)
860 if !ok {
861 t.Errorf("Expected error but got %v", r)
862 }
863 uassert.Equal(t, tt.panicMsg, err.Error())
864 }()
865 }
866 l.MustDelete(tt.indices...)
867 if tt.shouldPanic {
868 t.Error("Expected panic")
869 }
870 })
871 }
872}
873
874func TestMustGet(t *testing.T) {
875 tests := []struct {
876 name string
877 setup func() *List
878 index int
879 expected any
880 shouldPanic bool
881 panicMsg string
882 }{
883 {
884 name: "successful get",
885 setup: func() *List {
886 l := New()
887 l.Append(42)
888 return l
889 },
890 index: 0,
891 expected: 42,
892 shouldPanic: false,
893 },
894 {
895 name: "out of bounds negative",
896 setup: func() *List {
897 l := New()
898 l.Append(1)
899 return l
900 },
901 index: -1,
902 shouldPanic: true,
903 panicMsg: ErrOutOfBounds.Error(),
904 },
905 {
906 name: "out of bounds positive",
907 setup: func() *List {
908 l := New()
909 l.Append(1)
910 return l
911 },
912 index: 1,
913 shouldPanic: true,
914 panicMsg: ErrOutOfBounds.Error(),
915 },
916 {
917 name: "deleted element",
918 setup: func() *List {
919 l := New()
920 l.Append(1)
921 l.Delete(0)
922 return l
923 },
924 index: 0,
925 shouldPanic: true,
926 panicMsg: ErrDeleted.Error(),
927 },
928 {
929 name: "nil list",
930 setup: func() *List {
931 return nil
932 },
933 index: 0,
934 shouldPanic: true,
935 panicMsg: ErrOutOfBounds.Error(),
936 },
937 }
938
939 for _, tt := range tests {
940 t.Run(tt.name, func(t *testing.T) {
941 l := tt.setup()
942 if tt.shouldPanic {
943 defer func() {
944 r := recover()
945 if r == nil {
946 t.Error("Expected panic but got none")
947 }
948 err, ok := r.(error)
949 if !ok {
950 t.Errorf("Expected error but got %v", r)
951 }
952 uassert.Equal(t, tt.panicMsg, err.Error())
953 }()
954 }
955 result := l.MustGet(tt.index)
956 if tt.shouldPanic {
957 t.Error("Expected panic")
958 }
959 uassert.Equal(t, typeutil.ToString(tt.expected), typeutil.ToString(result))
960 })
961 }
962}
963
964func TestGetRange(t *testing.T) {
965 tests := []struct {
966 name string
967 values []any
968 start int
969 end int
970 expected []Entry
971 }{
972 {
973 name: "empty list",
974 values: []any{},
975 start: 0,
976 end: 10,
977 expected: []Entry{},
978 },
979 {
980 name: "single element",
981 values: []any{42},
982 start: 0,
983 end: 0,
984 expected: []Entry{
985 {Index: 0, Value: 42},
986 },
987 },
988 {
989 name: "multiple elements forward",
990 values: []any{1, 2, 3, 4, 5},
991 start: 1,
992 end: 3,
993 expected: []Entry{
994 {Index: 1, Value: 2},
995 {Index: 2, Value: 3},
996 {Index: 3, Value: 4},
997 },
998 },
999 {
1000 name: "multiple elements reverse",
1001 values: []any{1, 2, 3, 4, 5},
1002 start: 3,
1003 end: 1,
1004 expected: []Entry{
1005 {Index: 3, Value: 4},
1006 {Index: 2, Value: 3},
1007 {Index: 1, Value: 2},
1008 },
1009 },
1010 {
1011 name: "with deleted elements",
1012 values: []any{1, nil, 3, nil, 5},
1013 start: 0,
1014 end: 4,
1015 expected: []Entry{
1016 {Index: 0, Value: 1},
1017 {Index: 2, Value: 3},
1018 {Index: 4, Value: 5},
1019 },
1020 },
1021 {
1022 name: "nil list",
1023 values: nil,
1024 start: 0,
1025 end: 5,
1026 expected: []Entry{},
1027 },
1028 {
1029 name: "negative indices",
1030 values: []any{1, 2, 3},
1031 start: -1,
1032 end: -2,
1033 expected: []Entry{},
1034 },
1035 {
1036 name: "indices beyond size",
1037 values: []any{1, 2, 3},
1038 start: 1,
1039 end: 5,
1040 expected: []Entry{
1041 {Index: 1, Value: 2},
1042 {Index: 2, Value: 3},
1043 },
1044 },
1045 }
1046
1047 for _, tt := range tests {
1048 t.Run(tt.name, func(t *testing.T) {
1049 list := New()
1050 list.Append(tt.values...)
1051
1052 result := list.GetRange(tt.start, tt.end)
1053
1054 uassert.Equal(t, len(tt.expected), len(result), "comparing length")
1055 for i := range result {
1056 uassert.Equal(t, tt.expected[i].Index, result[i].Index, "comparing index")
1057 uassert.Equal(t, typeutil.ToString(tt.expected[i].Value), typeutil.ToString(result[i].Value), "comparing value")
1058 }
1059 })
1060 }
1061}
1062
1063func TestGetByOffset(t *testing.T) {
1064 tests := []struct {
1065 name string
1066 values []any
1067 offset int
1068 count int
1069 expected []Entry
1070 }{
1071 {
1072 name: "empty list",
1073 values: []any{},
1074 offset: 0,
1075 count: 5,
1076 expected: []Entry{},
1077 },
1078 {
1079 name: "positive count forward",
1080 values: []any{1, 2, 3, 4, 5},
1081 offset: 1,
1082 count: 2,
1083 expected: []Entry{
1084 {Index: 1, Value: 2},
1085 {Index: 2, Value: 3},
1086 },
1087 },
1088 {
1089 name: "negative count backward",
1090 values: []any{1, 2, 3, 4, 5},
1091 offset: 3,
1092 count: -2,
1093 expected: []Entry{
1094 {Index: 3, Value: 4},
1095 {Index: 2, Value: 3},
1096 },
1097 },
1098 {
1099 name: "count exceeds available elements",
1100 values: []any{1, 2, 3},
1101 offset: 1,
1102 count: 5,
1103 expected: []Entry{
1104 {Index: 1, Value: 2},
1105 {Index: 2, Value: 3},
1106 },
1107 },
1108 {
1109 name: "zero count",
1110 values: []any{1, 2, 3},
1111 offset: 0,
1112 count: 0,
1113 expected: []Entry{},
1114 },
1115 {
1116 name: "with deleted elements",
1117 values: []any{1, nil, 3, nil, 5},
1118 offset: 0,
1119 count: 3,
1120 expected: []Entry{
1121 {Index: 0, Value: 1},
1122 {Index: 2, Value: 3},
1123 {Index: 4, Value: 5},
1124 },
1125 },
1126 {
1127 name: "negative offset",
1128 values: []any{1, 2, 3},
1129 offset: -1,
1130 count: 2,
1131 expected: []Entry{
1132 {Index: 0, Value: 1},
1133 {Index: 1, Value: 2},
1134 },
1135 },
1136 {
1137 name: "offset beyond size",
1138 values: []any{1, 2, 3},
1139 offset: 5,
1140 count: -2,
1141 expected: []Entry{
1142 {Index: 2, Value: 3},
1143 {Index: 1, Value: 2},
1144 },
1145 },
1146 {
1147 name: "nil list",
1148 values: nil,
1149 offset: 0,
1150 count: 5,
1151 expected: []Entry{},
1152 },
1153 }
1154
1155 for _, tt := range tests {
1156 t.Run(tt.name, func(t *testing.T) {
1157 list := New()
1158 list.Append(tt.values...)
1159
1160 result := list.GetByOffset(tt.offset, tt.count)
1161
1162 uassert.Equal(t, len(tt.expected), len(result), "comparing length")
1163 for i := range result {
1164 uassert.Equal(t, tt.expected[i].Index, result[i].Index, "comparing index")
1165 uassert.Equal(t, typeutil.ToString(tt.expected[i].Value), typeutil.ToString(result[i].Value), "comparing value")
1166 }
1167 })
1168 }
1169}
1170
1171func TestMustSet(t *testing.T) {
1172 tests := []struct {
1173 name string
1174 setup func() *List
1175 index int
1176 value any
1177 shouldPanic bool
1178 panicMsg string
1179 }{
1180 {
1181 name: "successful set",
1182 setup: func() *List {
1183 l := New()
1184 l.Append(42)
1185 return l
1186 },
1187 index: 0,
1188 value: 99,
1189 shouldPanic: false,
1190 },
1191 {
1192 name: "restore deleted element",
1193 setup: func() *List {
1194 l := New()
1195 l.Append(42)
1196 l.Delete(0)
1197 return l
1198 },
1199 index: 0,
1200 value: 99,
1201 shouldPanic: false,
1202 },
1203 {
1204 name: "out of bounds negative",
1205 setup: func() *List {
1206 l := New()
1207 l.Append(1)
1208 return l
1209 },
1210 index: -1,
1211 value: 99,
1212 shouldPanic: true,
1213 panicMsg: ErrOutOfBounds.Error(),
1214 },
1215 {
1216 name: "out of bounds positive",
1217 setup: func() *List {
1218 l := New()
1219 l.Append(1)
1220 return l
1221 },
1222 index: 1,
1223 value: 99,
1224 shouldPanic: true,
1225 panicMsg: ErrOutOfBounds.Error(),
1226 },
1227 {
1228 name: "nil list",
1229 setup: func() *List {
1230 return nil
1231 },
1232 index: 0,
1233 value: 99,
1234 shouldPanic: true,
1235 panicMsg: ErrOutOfBounds.Error(),
1236 },
1237 }
1238
1239 for _, tt := range tests {
1240 t.Run(tt.name, func(t *testing.T) {
1241 l := tt.setup()
1242 if tt.shouldPanic {
1243 defer func() {
1244 r := recover()
1245 if r == nil {
1246 t.Error("Expected panic but got none")
1247 }
1248 err, ok := r.(error)
1249 if !ok {
1250 t.Errorf("Expected error but got %v", r)
1251 }
1252 uassert.Equal(t, tt.panicMsg, err.Error())
1253 }()
1254 }
1255 l.MustSet(tt.index, tt.value)
1256 if tt.shouldPanic {
1257 t.Error("Expected panic")
1258 }
1259 // Verify the value was set correctly for non-panic cases
1260 if !tt.shouldPanic {
1261 result := l.Get(tt.index)
1262 uassert.Equal(t, typeutil.ToString(tt.value), typeutil.ToString(result))
1263 }
1264 })
1265 }
1266}
1267
1268func TestSet(t *testing.T) {
1269 tests := []struct {
1270 name string
1271 setup func() *List
1272 index int
1273 value any
1274 expectedErr error
1275 verify func(t *testing.T, l *List)
1276 }{
1277 {
1278 name: "set value in empty list",
1279 setup: func() *List {
1280 return New()
1281 },
1282 index: 0,
1283 value: 42,
1284 expectedErr: ErrOutOfBounds,
1285 verify: func(t *testing.T, l *List) {
1286 uassert.Equal(t, 0, l.Size())
1287 },
1288 },
1289 {
1290 name: "set value at valid index",
1291 setup: func() *List {
1292 l := New()
1293 l.Append(1)
1294 return l
1295 },
1296 index: 0,
1297 value: 42,
1298 verify: func(t *testing.T, l *List) {
1299 uassert.Equal(t, 42, l.Get(0))
1300 uassert.Equal(t, 1, l.Size())
1301 uassert.Equal(t, 1, l.TotalSize())
1302 },
1303 },
1304 {
1305 name: "set value at negative index",
1306 setup: func() *List {
1307 l := New()
1308 l.Append(1)
1309 return l
1310 },
1311 index: -1,
1312 value: 42,
1313 expectedErr: ErrOutOfBounds,
1314 verify: func(t *testing.T, l *List) {
1315 uassert.Equal(t, 1, l.Get(0))
1316 },
1317 },
1318 {
1319 name: "set value beyond size",
1320 setup: func() *List {
1321 l := New()
1322 l.Append(1)
1323 return l
1324 },
1325 index: 1,
1326 value: 42,
1327 expectedErr: ErrOutOfBounds,
1328 verify: func(t *testing.T, l *List) {
1329 uassert.Equal(t, 1, l.Get(0))
1330 uassert.Equal(t, 1, l.Size())
1331 },
1332 },
1333 {
1334 name: "set nil value",
1335 setup: func() *List {
1336 l := New()
1337 l.Append(1)
1338 return l
1339 },
1340 index: 0,
1341 value: nil,
1342 verify: func(t *testing.T, l *List) {
1343 uassert.Equal(t, nil, l.Get(0))
1344 uassert.Equal(t, 0, l.Size())
1345 },
1346 },
1347 {
1348 name: "set value at deleted index",
1349 setup: func() *List {
1350 l := New()
1351 l.Append(1, 2, 3)
1352 l.Delete(1)
1353 return l
1354 },
1355 index: 1,
1356 value: 42,
1357 verify: func(t *testing.T, l *List) {
1358 uassert.Equal(t, 42, l.Get(1))
1359 uassert.Equal(t, 3, l.Size())
1360 uassert.Equal(t, 3, l.TotalSize())
1361 },
1362 },
1363 {
1364 name: "set value in nil list",
1365 setup: func() *List {
1366 return nil
1367 },
1368 index: 0,
1369 value: 42,
1370 expectedErr: ErrOutOfBounds,
1371 verify: func(t *testing.T, l *List) {
1372 uassert.Equal(t, 0, l.Size())
1373 },
1374 },
1375 {
1376 name: "set multiple values at same index",
1377 setup: func() *List {
1378 l := New()
1379 l.Append(1)
1380 return l
1381 },
1382 index: 0,
1383 value: 42,
1384 verify: func(t *testing.T, l *List) {
1385 uassert.Equal(t, 42, l.Get(0))
1386 err := l.Set(0, 99)
1387 uassert.Equal(t, nil, err)
1388 uassert.Equal(t, 99, l.Get(0))
1389 uassert.Equal(t, 1, l.Size())
1390 },
1391 },
1392 {
1393 name: "set value at last index",
1394 setup: func() *List {
1395 l := New()
1396 l.Append(1, 2, 3)
1397 return l
1398 },
1399 index: 2,
1400 value: 42,
1401 verify: func(t *testing.T, l *List) {
1402 uassert.Equal(t, 42, l.Get(2))
1403 uassert.Equal(t, 3, l.Size())
1404 },
1405 },
1406 }
1407
1408 for _, tt := range tests {
1409 t.Run(tt.name, func(t *testing.T) {
1410 l := tt.setup()
1411 err := l.Set(tt.index, tt.value)
1412
1413 if tt.expectedErr != nil {
1414 uassert.Equal(t, tt.expectedErr.Error(), err.Error())
1415 } else {
1416 uassert.Equal(t, nil, err)
1417 }
1418
1419 tt.verify(t, l)
1420 })
1421 }
1422}