1package rotree23import (4 "testing"56 "gno.land/p/nt/avl/v0"7)89func TestExample(t *testing.T) {10 // User represents our internal data structure11 type User struct {12 ID string13 Name string14 Balance int15 Internal string // sensitive internal data16 }1718 // Create and populate the original tree with user pointers19 tree := avl.NewTree()20 tree.Set("alice", &User{21 ID: "1",22 Name: "Alice",23 Balance: 100,24 Internal: "sensitive_data_1",25 })26 tree.Set("bob", &User{27 ID: "2",28 Name: "Bob",29 Balance: 200,30 Internal: "sensitive_data_2",31 })3233 // Define a makeEntrySafeFn that:34 // 1. Creates a defensive copy of the User struct35 // 2. Omits sensitive internal data36 makeEntrySafeFn := func(v any) any {37 originalUser := v.(*User)38 return &User{39 ID: originalUser.ID,40 Name: originalUser.Name,41 Balance: originalUser.Balance,42 Internal: "", // Omit sensitive data43 }44 }4546 // Create a read-only view of the tree47 roTree := Wrap(tree, makeEntrySafeFn)4849 // Test retrieving and verifying a user50 t.Run("Get User", func(t *testing.T) {51 // Get user from read-only tree52 value := roTree.Get("alice")53 if value == nil {54 t.Fatal("User 'alice' not found")55 }5657 user := value.(*User)5859 // Verify user data is correct60 if user.Name != "Alice" || user.Balance != 100 {61 t.Errorf("Unexpected user data: got name=%s balance=%d", user.Name, user.Balance)62 }6364 // Verify sensitive data is not exposed65 if user.Internal != "" {66 t.Error("Sensitive data should not be exposed")67 }6869 // Verify it's a different instance than the original70 originalValue := tree.Get("alice")71 originalUser := originalValue.(*User)72 if user == originalUser {73 t.Error("Read-only tree should return a copy, not the original pointer")74 }75 })7677 // Test iterating over users78 t.Run("Iterate Users", func(t *testing.T) {79 count := 080 roTree.Iterate("", "", func(key string, value any) bool {81 user := value.(*User)82 // Verify each user has empty Internal field83 if user.Internal != "" {84 t.Error("Sensitive data exposed during iteration")85 }86 count++87 return false88 })8990 if count != 2 {91 t.Errorf("Expected 2 users, got %d", count)92 }93 })9495 // Verify that modifications to the returned user don't affect the original96 t.Run("Modification Safety", func(t *testing.T) {97 value := roTree.Get("alice")98 user := value.(*User)99100 // Try to modify the returned user101 user.Balance = 999102 user.Internal = "hacked"103104 // Verify original is unchanged105 originalValue := tree.Get("alice")106 originalUser := originalValue.(*User)107 if originalUser.Balance != 100 || originalUser.Internal != "sensitive_data_1" {108 t.Error("Original user data was modified")109 }110 })111}112113func TestReadOnlyTree(t *testing.T) {114 // Example of a makeEntrySafeFn that appends "_readonly" to demonstrate transformation115 makeEntrySafeFn := func(value any) any {116 return value.(string) + "_readonly"117 }118119 tree := avl.NewTree()120 tree.Set("key1", "value1")121 tree.Set("key2", "value2")122 tree.Set("key3", "value3")123124 roTree := Wrap(tree, makeEntrySafeFn)125126 tests := []struct {127 name string128 key string129 expected any130 }{131 {"ExistingKey1", "key1", "value1_readonly"},132 {"ExistingKey2", "key2", "value2_readonly"},133 {"NonExistingKey", "key4", nil},134 }135136 for _, tt := range tests {137 t.Run(tt.name, func(t *testing.T) {138 value := roTree.Get(tt.key)139 if value != tt.expected {140 t.Errorf("For key %s, expected %v, got %v", tt.key, tt.expected, value)141 }142 })143 }144}145146// Add example tests showing different makeEntrySafeFn implementations147func TestMakeEntrySafeFnVariants(t *testing.T) {148 tree := avl.NewTree()149 tree.Set("slice", []int{1, 2, 3})150 tree.Set("map", map[string]int{"a": 1})151152 tests := []struct {153 name string154 makeEntrySafeFn func(any) any155 key string156 validate func(t *testing.T, value any)157 }{158 {159 name: "Defensive Copy Slice",160 makeEntrySafeFn: func(v any) any {161 original := v.([]int)162 return append([]int{}, original...)163 },164 key: "slice",165 validate: func(t *testing.T, value any) {166 slice := value.([]int)167 // Modify the returned slice168 slice[0] = 999169 // Verify original is unchanged170 originalValue := tree.Get("slice")171 original := originalValue.([]int)172 if original[0] != 1 {173 t.Error("Original slice was modified")174 }175 },176 },177 // Add more test cases for different makeEntrySafeFn implementations178 }179180 for _, tt := range tests {181 t.Run(tt.name, func(t *testing.T) {182 roTree := Wrap(tree, tt.makeEntrySafeFn)183 value := roTree.Get(tt.key)184 if value == nil {185 t.Fatal("Key not found")186 }187 tt.validate(t, value)188 })189 }190}191192func TestNilMakeEntrySafeFn(t *testing.T) {193 // Create a tree with some test data194 tree := avl.NewTree()195 originalValue := []int{1, 2, 3}196 tree.Set("test", originalValue)197198 // Create a ReadOnlyTree with nil makeEntrySafeFn199 roTree := Wrap(tree, nil)200201 // Test that we get back the original value202 value := roTree.Get("test")203 if value == nil {204 t.Fatal("Key not found")205 }206207 // Verify it's the exact same slice (not a copy)208 retrievedSlice := value.([]int)209 if &retrievedSlice[0] != &originalValue[0] {210 t.Error("Expected to get back the original slice reference")211 }212213 // Test through iteration as well214 roTree.Iterate("", "", func(key string, value any) bool {215 retrievedSlice := value.([]int)216 if &retrievedSlice[0] != &originalValue[0] {217 t.Error("Expected to get back the original slice reference in iteration")218 }219 return false220 })221}222Signatures reconstructed verbatim from vm/qfuncs — interface params keep their inline definitions.