lplist_test.gno
6.02 Kb ยท 242 lines
1package lplist
2
3import (
4 "testing"
5
6 "gno.land/p/moul/ulist"
7)
8
9// TestLayeredProxyListBasicOperations tests the basic operations of LayeredProxyList
10func TestLayeredProxyListBasicOperations(t *testing.T) {
11 // Create source list with initial data
12 source := ulist.New()
13 source.Append(1, 2, 3)
14
15 // Create proxy list with a simple multiplier migrator
16 migrator := func(v any) any {
17 return v.(int) * 2
18 }
19 proxy := NewLayeredProxyList(source, migrator)
20
21 // Test initial state
22 if got := proxy.Size(); got != 3 {
23 t.Errorf("initial Size() = %v, want %v", got, 3)
24 }
25 if got := proxy.TotalSize(); got != 3 {
26 t.Errorf("initial TotalSize() = %v, want %v", got, 3)
27 }
28
29 // Test Get with migration
30 tests := []struct {
31 index int
32 want any
33 }{
34 {0, 2}, // 1 * 2
35 {1, 4}, // 2 * 2
36 {2, 6}, // 3 * 2
37 }
38
39 for _, tt := range tests {
40 if got := proxy.Get(tt.index); got != tt.want {
41 t.Errorf("Get(%v) = %v, want %v", tt.index, got, tt.want)
42 }
43 }
44
45 // Test Append to target
46 proxy.Append(7, 8)
47 if got := proxy.Size(); got != 5 {
48 t.Errorf("Size() after append = %v, want %v", got, 5)
49 }
50
51 // Test Get from target (no migration)
52 if got := proxy.Get(3); got != 7 {
53 t.Errorf("Get(3) = %v, want %v", got, 7)
54 }
55}
56
57// TestLayeredProxyListDelete tests delete operations
58func TestLayeredProxyListDelete(t *testing.T) {
59 source := ulist.New()
60 source.Append(1, 2, 3)
61 proxy := NewLayeredProxyList(source, nil)
62 proxy.Append(4, 5)
63
64 // Test deleting from source (should fail)
65 if err := proxy.Delete(1); err == nil {
66 t.Error("Delete from source should return error")
67 }
68
69 // Test deleting from target (should succeed)
70 if err := proxy.Delete(3); err != nil {
71 t.Errorf("Delete from target failed: %s", err.Error())
72 }
73
74 // After deletion, the value might be undefined rather than nil
75 // Check that it's not equal to the original value
76 if got := proxy.Get(3); got == 5 {
77 t.Errorf("Get(3) after delete = %v, want it to be deleted", got)
78 }
79}
80
81// TestLayeredProxyListIteration tests iteration methods
82func TestLayeredProxyListIteration(t *testing.T) {
83 source := ulist.New()
84 source.Append(1, 2, 3)
85 proxy := NewLayeredProxyList(source, nil)
86 proxy.Append(4, 5)
87
88 // Test GetRange
89 entries := proxy.GetRange(0, 4)
90 if len(entries) != 5 {
91 t.Errorf("GetRange returned %v entries, want 5", len(entries))
92 }
93
94 // Test reverse iteration
95 entries = proxy.GetRange(4, 0)
96 if len(entries) != 5 {
97 t.Errorf("Reverse GetRange returned %v entries, want 5", len(entries))
98 }
99
100 // Test IteratorByOffset with positive count
101 var values []any
102 proxy.IteratorByOffset(1, 3, func(index int, value any) bool {
103 values = append(values, value)
104 return false
105 })
106 if len(values) != 3 {
107 t.Errorf("IteratorByOffset returned %v values, want 3", len(values))
108 }
109}
110
111// TestLayeredProxyListMustOperations tests must operations
112func TestLayeredProxyListMustOperations(t *testing.T) {
113 source := ulist.New()
114 source.Append(1, 2)
115 proxy := NewLayeredProxyList(source, nil)
116
117 // Test MustGet success
118 defer func() {
119 if r := recover(); r != nil {
120 t.Errorf("MustGet panicked unexpectedly: %v", r)
121 }
122 }()
123 if got := proxy.MustGet(1); got != 2 {
124 t.Errorf("MustGet(1) = %v, want 2", got)
125 }
126
127 // Test MustGet panic
128 defer func() {
129 if r := recover(); r == nil {
130 t.Error("MustGet should have panicked")
131 }
132 }()
133 proxy.MustGet(99) // Should panic
134}
135
136// TestLayeredProxyListWithNilMigrator tests behavior without a migrator
137func TestLayeredProxyListWithNilMigrator(t *testing.T) {
138 source := ulist.New()
139 source.Append(1, 2)
140 proxy := NewLayeredProxyList(source, nil)
141
142 if got := proxy.Get(0); got != 1 {
143 t.Errorf("Get(0) with nil migrator = %v, want 1", got)
144 }
145}
146
147// TestLayeredProxyListEmpty tests operations on empty lists
148func TestLayeredProxyListEmpty(t *testing.T) {
149 source := ulist.New()
150 proxy := NewLayeredProxyList(source, nil)
151
152 if got := proxy.Size(); got != 0 {
153 t.Errorf("Size() of empty list = %v, want 0", got)
154 }
155
156 if got := proxy.Get(0); got != nil {
157 t.Errorf("Get(0) of empty list = %v, want nil", got)
158 }
159
160 entries := proxy.GetRange(0, 10)
161 if len(entries) != 0 {
162 t.Errorf("GetRange on empty list returned %v entries, want 0", len(entries))
163 }
164}
165
166// TestLayeredProxyListChaining tests chaining of layered proxies with struct migrations
167func TestLayeredProxyListChaining(t *testing.T) {
168 // Define struct types for different versions
169 type v1 struct {
170 namev1 string
171 }
172 type v2 struct {
173 namev2 string
174 }
175 type v3 struct {
176 namev3 string
177 }
178
179 // Create source list with v1 objects
180 source := ulist.New()
181 source.Append(v1{namev1: "object1"}, v1{namev1: "object2"})
182
183 // Migration function from v1 to v2
184 v1Tov2 := func(v any) any {
185 obj := v.(v1)
186 return v2{namev2: obj.namev1 + "_v2"}
187 }
188
189 // Create first proxy with v1->v2 migration
190 proxyV2 := NewLayeredProxyList(source, v1Tov2)
191 proxyV2.Append(v2{namev2: "direct_v2"})
192
193 // Migration function from v2 to v3
194 v2Tov3 := func(v any) any {
195 obj := v.(v2)
196 return v3{namev3: obj.namev2 + "_v3"}
197 }
198
199 // Create second proxy with v2->v3 migration, using the first proxy as source
200 proxyV3 := NewLayeredProxyList(proxyV2, v2Tov3)
201 proxyV3.Append(v3{namev3: "direct_v3"})
202
203 // Verify sizes
204 if got := proxyV3.Size(); got != 4 {
205 t.Errorf("proxyV3.Size() = %v, want 4", got)
206 }
207
208 // Test that all objects are correctly migrated when accessed through proxyV3
209 expected := []struct {
210 index int
211 name string
212 }{
213 {0, "object1_v2_v3"}, // v1 -> v2 -> v3
214 {1, "object2_v2_v3"}, // v1 -> v2 -> v3
215 {2, "direct_v2_v3"}, // v2 -> v3
216 {3, "direct_v3"}, // v3 (no migration)
217 }
218
219 for _, tt := range expected {
220 obj := proxyV3.Get(tt.index).(v3)
221 if obj.namev3 != tt.name {
222 t.Errorf("proxyV3.Get(%d).namev3 = %v, want %v", tt.index, obj.namev3, tt.name)
223 }
224 }
225
226 // Verify getting items from middle layer (proxyV2)
227 middleExpected := []struct {
228 index int
229 name string
230 }{
231 {0, "object1_v2"}, // v1 -> v2
232 {1, "object2_v2"}, // v1 -> v2
233 {2, "direct_v2"}, // v2 (no migration)
234 }
235
236 for _, tt := range middleExpected {
237 obj := proxyV2.Get(tt.index).(v2)
238 if obj.namev2 != tt.name {
239 t.Errorf("proxyV2.Get(%d).namev2 = %v, want %v", tt.index, obj.namev2, tt.name)
240 }
241 }
242}