rolist_test.gno

3.59 Kb ยท 162 lines
  1package rolist
  2
  3import (
  4	"testing"
  5
  6	"gno.land/p/demo/avl/list"
  7)
  8
  9func TestExample(t *testing.T) {
 10	// User represents our internal data structure
 11	type User struct {
 12		ID       string
 13		Name     string
 14		Balance  int
 15		Internal string // sensitive internal data
 16	}
 17
 18	// Create and populate the original list
 19	l := &list.List{}
 20	l.Append(
 21		&User{
 22			ID:       "1",
 23			Name:     "Alice",
 24			Balance:  100,
 25			Internal: "sensitive_data_1",
 26		},
 27		&User{
 28			ID:       "2",
 29			Name:     "Bob",
 30			Balance:  200,
 31			Internal: "sensitive_data_2",
 32		},
 33	)
 34
 35	// Define a makeEntrySafeFn that:
 36	// 1. Creates a defensive copy of the User struct
 37	// 2. Omits sensitive internal data
 38	makeEntrySafeFn := func(v any) any {
 39		originalUser := v.(*User)
 40		return &User{
 41			ID:       originalUser.ID,
 42			Name:     originalUser.Name,
 43			Balance:  originalUser.Balance,
 44			Internal: "", // Omit sensitive data
 45		}
 46	}
 47
 48	// Create a read-only view of the list
 49	roList := Wrap(l, makeEntrySafeFn)
 50
 51	// Test retrieving and verifying a user
 52	t.Run("Get User", func(t *testing.T) {
 53		// Get user from read-only list
 54		value := roList.Get(0)
 55		if value == nil {
 56			t.Fatal("User at index 0 not found")
 57		}
 58
 59		user := value.(*User)
 60
 61		// Verify user data is correct
 62		if user.Name != "Alice" || user.Balance != 100 {
 63			t.Errorf("Unexpected user data: got name=%s balance=%d", user.Name, user.Balance)
 64		}
 65
 66		// Verify sensitive data is not exposed
 67		if user.Internal != "" {
 68			t.Error("Sensitive data should not be exposed")
 69		}
 70
 71		// Verify it's a different instance than the original
 72		originalUser := l.Get(0).(*User)
 73		if user == originalUser {
 74			t.Error("Read-only list should return a copy, not the original pointer")
 75		}
 76	})
 77
 78	// Test slice functionality
 79	t.Run("Slice Users", func(t *testing.T) {
 80		users := roList.Slice(0, 2)
 81		if len(users) != 2 {
 82			t.Fatalf("Expected 2 users, got %d", len(users))
 83		}
 84
 85		for _, v := range users {
 86			user := v.(*User)
 87			if user.Internal != "" {
 88				t.Error("Sensitive data exposed in slice")
 89			}
 90		}
 91	})
 92
 93	// Test ForEach functionality
 94	t.Run("ForEach Users", func(t *testing.T) {
 95		count := 0
 96		roList.ForEach(func(index int, value any) bool {
 97			user := value.(*User)
 98			if user.Internal != "" {
 99				t.Error("Sensitive data exposed during iteration")
100			}
101			count++
102			return false
103		})
104
105		if count != 2 {
106			t.Errorf("Expected 2 users, got %d", count)
107		}
108	})
109}
110
111func TestNilMakeEntrySafeFn(t *testing.T) {
112	// Create a list with some test data
113	l := &list.List{}
114	originalValue := []int{1, 2, 3}
115	l.Append(originalValue)
116
117	// Create a ReadOnlyList with nil makeEntrySafeFn
118	roList := Wrap(l, nil)
119
120	// Test that we get back the original value
121	value := roList.Get(0)
122	if value == nil {
123		t.Fatal("Value not found")
124	}
125
126	// Verify it's the exact same slice (not a copy)
127	retrievedSlice := value.([]int)
128	if &retrievedSlice[0] != &originalValue[0] {
129		t.Error("Expected to get back the original slice reference")
130	}
131}
132
133func TestReadOnlyList(t *testing.T) {
134	// Example of a makeEntrySafeFn that appends "_readonly" to demonstrate transformation
135	makeEntrySafeFn := func(value any) any {
136		return value.(string) + "_readonly"
137	}
138
139	l := &list.List{}
140	l.Append("value1", "value2", "value3")
141
142	roList := Wrap(l, makeEntrySafeFn)
143
144	tests := []struct {
145		name     string
146		index    int
147		expected any
148	}{
149		{"ExistingIndex0", 0, "value1_readonly"},
150		{"ExistingIndex1", 1, "value2_readonly"},
151		{"NonExistingIndex", 3, nil},
152	}
153
154	for _, tt := range tests {
155		t.Run(tt.name, func(t *testing.T) {
156			value := roList.Get(tt.index)
157			if value != tt.expected {
158				t.Errorf("For index %d, expected %v, got %v", tt.index, tt.expected, value)
159			}
160		})
161	}
162}