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}