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}