Search Apps Documentation Source Content File Folder Download Copy Actions Download

rolist_test.gno

3.68 Kb · 164 lines
  1package rolist
  2
  3import (
  4	"testing"
  5
  6	"gno.land/p/nt/bptree/v0/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, ok := roList.Get(0)
 55		if !ok {
 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		origVal, _ := l.Get(0)
 73		originalUser := origVal.(*User)
 74		if user == originalUser {
 75			t.Error("Read-only list should return a copy, not the original pointer")
 76		}
 77	})
 78
 79	// Test slice functionality
 80	t.Run("Slice Users", func(t *testing.T) {
 81		users := roList.Slice(0, 2)
 82		if len(users) != 2 {
 83			t.Fatalf("Expected 2 users, got %d", len(users))
 84		}
 85
 86		for _, v := range users {
 87			user := v.(*User)
 88			if user.Internal != "" {
 89				t.Error("Sensitive data exposed in slice")
 90			}
 91		}
 92	})
 93
 94	// Test ForEach functionality
 95	t.Run("ForEach Users", func(t *testing.T) {
 96		count := 0
 97		roList.ForEach(func(index int, value any) bool {
 98			user := value.(*User)
 99			if user.Internal != "" {
100				t.Error("Sensitive data exposed during iteration")
101			}
102			count++
103			return false
104		})
105
106		if count != 2 {
107			t.Errorf("Expected 2 users, got %d", count)
108		}
109	})
110}
111
112func TestNilMakeEntrySafeFn(t *testing.T) {
113	// Create a list with some test data
114	l := &list.List{}
115	originalValue := []int{1, 2, 3}
116	l.Append(originalValue)
117
118	// Create a ReadOnlyList with nil makeEntrySafeFn
119	roList := Wrap(l, nil)
120
121	// Test that we get back the original value
122	value, ok := roList.Get(0)
123	if !ok {
124		t.Fatal("Value not found")
125	}
126
127	// Verify it's the exact same slice (not a copy)
128	retrievedSlice := value.([]int)
129	if &retrievedSlice[0] != &originalValue[0] {
130		t.Error("Expected to get back the original slice reference")
131	}
132}
133
134func TestReadOnlyList(t *testing.T) {
135	// Example of a makeEntrySafeFn that appends "_readonly" to demonstrate transformation
136	makeEntrySafeFn := func(value any) any {
137		return value.(string) + "_readonly"
138	}
139
140	l := &list.List{}
141	l.Append("value1", "value2", "value3")
142
143	roList := Wrap(l, makeEntrySafeFn)
144
145	tests := []struct {
146		name     string
147		index    int
148		expected any
149		ok       bool
150	}{
151		{"ExistingIndex0", 0, "value1_readonly", true},
152		{"ExistingIndex1", 1, "value2_readonly", true},
153		{"NonExistingIndex", 3, nil, false},
154	}
155
156	for _, tt := range tests {
157		t.Run(tt.name, func(t *testing.T) {
158			value, ok := roList.Get(tt.index)
159			if ok != tt.ok || value != tt.expected {
160				t.Errorf("For index %d, expected (%v, %v), got (%v, %v)", tt.index, tt.expected, tt.ok, value, ok)
161			}
162		})
163	}
164}