golang.org/x/tools/gopls@v0.15.3/internal/util/persistent/map_test.go (about) 1 // Copyright 2022 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package persistent 6 7 import ( 8 "fmt" 9 "math/rand" 10 "reflect" 11 "sync/atomic" 12 "testing" 13 ) 14 15 type mapEntry struct { 16 key int 17 value int 18 } 19 20 type validatedMap struct { 21 impl *Map[int, int] 22 expected map[int]int // current key-value mapping. 23 deleted map[mapEntry]int // maps deleted entries to their clock time of last deletion 24 seen map[mapEntry]int // maps seen entries to their clock time of last insertion 25 clock int 26 } 27 28 func TestSimpleMap(t *testing.T) { 29 deletedEntries := make(map[mapEntry]int) 30 seenEntries := make(map[mapEntry]int) 31 32 m1 := &validatedMap{ 33 impl: new(Map[int, int]), 34 expected: make(map[int]int), 35 deleted: deletedEntries, 36 seen: seenEntries, 37 } 38 39 m3 := m1.clone() 40 validateRef(t, m1, m3) 41 m3.set(t, 8, 8) 42 validateRef(t, m1, m3) 43 m3.destroy() 44 45 assertSameMap(t, entrySet(deletedEntries), map[mapEntry]struct{}{ 46 {key: 8, value: 8}: {}, 47 }) 48 49 validateRef(t, m1) 50 m1.set(t, 1, 1) 51 validateRef(t, m1) 52 m1.set(t, 2, 2) 53 validateRef(t, m1) 54 m1.set(t, 3, 3) 55 validateRef(t, m1) 56 m1.remove(t, 2) 57 validateRef(t, m1) 58 m1.set(t, 6, 6) 59 validateRef(t, m1) 60 61 assertSameMap(t, entrySet(deletedEntries), map[mapEntry]struct{}{ 62 {key: 2, value: 2}: {}, 63 {key: 8, value: 8}: {}, 64 }) 65 66 m2 := m1.clone() 67 validateRef(t, m1, m2) 68 m1.set(t, 6, 60) 69 validateRef(t, m1, m2) 70 m1.remove(t, 1) 71 validateRef(t, m1, m2) 72 73 gotAllocs := int(testing.AllocsPerRun(10, func() { 74 m1.impl.Delete(100) 75 m1.impl.Delete(1) 76 })) 77 wantAllocs := 0 78 if gotAllocs != wantAllocs { 79 t.Errorf("wanted %d allocs, got %d", wantAllocs, gotAllocs) 80 } 81 82 for i := 10; i < 14; i++ { 83 m1.set(t, i, i) 84 validateRef(t, m1, m2) 85 } 86 87 m1.set(t, 10, 100) 88 validateRef(t, m1, m2) 89 90 m1.remove(t, 12) 91 validateRef(t, m1, m2) 92 93 m2.set(t, 4, 4) 94 validateRef(t, m1, m2) 95 m2.set(t, 5, 5) 96 validateRef(t, m1, m2) 97 98 m1.destroy() 99 100 assertSameMap(t, entrySet(deletedEntries), map[mapEntry]struct{}{ 101 {key: 2, value: 2}: {}, 102 {key: 6, value: 60}: {}, 103 {key: 8, value: 8}: {}, 104 {key: 10, value: 10}: {}, 105 {key: 10, value: 100}: {}, 106 {key: 11, value: 11}: {}, 107 {key: 12, value: 12}: {}, 108 {key: 13, value: 13}: {}, 109 }) 110 111 m2.set(t, 7, 7) 112 validateRef(t, m2) 113 114 m2.destroy() 115 116 assertSameMap(t, entrySet(seenEntries), entrySet(deletedEntries)) 117 } 118 119 func TestRandomMap(t *testing.T) { 120 deletedEntries := make(map[mapEntry]int) 121 seenEntries := make(map[mapEntry]int) 122 123 m := &validatedMap{ 124 impl: new(Map[int, int]), 125 expected: make(map[int]int), 126 deleted: deletedEntries, 127 seen: seenEntries, 128 } 129 130 keys := make([]int, 0, 1000) 131 for i := 0; i < 1000; i++ { 132 key := rand.Intn(10000) 133 m.set(t, key, key) 134 keys = append(keys, key) 135 136 if i%10 == 1 { 137 index := rand.Intn(len(keys)) 138 last := len(keys) - 1 139 key = keys[index] 140 keys[index], keys[last] = keys[last], keys[index] 141 keys = keys[:last] 142 143 m.remove(t, key) 144 } 145 } 146 147 m.destroy() 148 assertSameMap(t, entrySet(seenEntries), entrySet(deletedEntries)) 149 } 150 151 func entrySet(m map[mapEntry]int) map[mapEntry]struct{} { 152 set := make(map[mapEntry]struct{}) 153 for k := range m { 154 set[k] = struct{}{} 155 } 156 return set 157 } 158 159 func TestUpdate(t *testing.T) { 160 deletedEntries := make(map[mapEntry]int) 161 seenEntries := make(map[mapEntry]int) 162 163 m1 := &validatedMap{ 164 impl: new(Map[int, int]), 165 expected: make(map[int]int), 166 deleted: deletedEntries, 167 seen: seenEntries, 168 } 169 m2 := m1.clone() 170 171 m1.set(t, 1, 1) 172 m1.set(t, 2, 2) 173 m2.set(t, 2, 20) 174 m2.set(t, 3, 3) 175 m1.setAll(t, m2) 176 177 m1.destroy() 178 m2.destroy() 179 assertSameMap(t, entrySet(seenEntries), entrySet(deletedEntries)) 180 } 181 182 func validateRef(t *testing.T, maps ...*validatedMap) { 183 t.Helper() 184 185 actualCountByEntry := make(map[mapEntry]int32) 186 nodesByEntry := make(map[mapEntry]map[*mapNode]struct{}) 187 expectedCountByEntry := make(map[mapEntry]int32) 188 for i, m := range maps { 189 dfsRef(m.impl.root, actualCountByEntry, nodesByEntry) 190 dumpMap(t, fmt.Sprintf("%d:", i), m.impl.root) 191 } 192 for entry, nodes := range nodesByEntry { 193 expectedCountByEntry[entry] = int32(len(nodes)) 194 } 195 assertSameMap(t, expectedCountByEntry, actualCountByEntry) 196 } 197 198 func dfsRef(node *mapNode, countByEntry map[mapEntry]int32, nodesByEntry map[mapEntry]map[*mapNode]struct{}) { 199 if node == nil { 200 return 201 } 202 203 entry := mapEntry{key: node.key.(int), value: node.value.value.(int)} 204 countByEntry[entry] = atomic.LoadInt32(&node.value.refCount) 205 206 nodes, ok := nodesByEntry[entry] 207 if !ok { 208 nodes = make(map[*mapNode]struct{}) 209 nodesByEntry[entry] = nodes 210 } 211 nodes[node] = struct{}{} 212 213 dfsRef(node.left, countByEntry, nodesByEntry) 214 dfsRef(node.right, countByEntry, nodesByEntry) 215 } 216 217 func dumpMap(t *testing.T, prefix string, n *mapNode) { 218 if n == nil { 219 t.Logf("%s nil", prefix) 220 return 221 } 222 t.Logf("%s {key: %v, value: %v (ref: %v), ref: %v, weight: %v}", prefix, n.key, n.value.value, n.value.refCount, n.refCount, n.weight) 223 dumpMap(t, prefix+"l", n.left) 224 dumpMap(t, prefix+"r", n.right) 225 } 226 227 func (vm *validatedMap) validate(t *testing.T) { 228 t.Helper() 229 230 validateNode(t, vm.impl.root) 231 232 // Note: this validation may not make sense if maps were constructed using 233 // SetAll operations. If this proves to be problematic, remove the clock, 234 // deleted, and seen fields. 235 for key, value := range vm.expected { 236 entry := mapEntry{key: key, value: value} 237 if deleteAt := vm.deleted[entry]; deleteAt > vm.seen[entry] { 238 t.Fatalf("entry is deleted prematurely, key: %d, value: %d", key, value) 239 } 240 } 241 242 actualMap := make(map[int]int, len(vm.expected)) 243 vm.impl.Range(func(key, value int) { 244 if other, ok := actualMap[key]; ok { 245 t.Fatalf("key is present twice, key: %d, first value: %d, second value: %d", key, value, other) 246 } 247 actualMap[key] = value 248 }) 249 250 assertSameMap(t, actualMap, vm.expected) 251 } 252 253 func validateNode(t *testing.T, node *mapNode) { 254 if node == nil { 255 return 256 } 257 258 if node.left != nil { 259 if node.key.(int) < node.left.key.(int) { 260 t.Fatalf("left child has larger key: %v vs %v", node.left.key, node.key) 261 } 262 if node.left.weight > node.weight { 263 t.Fatalf("left child has larger weight: %v vs %v", node.left.weight, node.weight) 264 } 265 } 266 267 if node.right != nil { 268 if node.right.key.(int) < node.key.(int) { 269 t.Fatalf("right child has smaller key: %v vs %v", node.right.key, node.key) 270 } 271 if node.right.weight > node.weight { 272 t.Fatalf("right child has larger weight: %v vs %v", node.right.weight, node.weight) 273 } 274 } 275 276 validateNode(t, node.left) 277 validateNode(t, node.right) 278 } 279 280 func (vm *validatedMap) setAll(t *testing.T, other *validatedMap) { 281 vm.impl.SetAll(other.impl) 282 283 // Note: this is buggy because we are not updating vm.clock, vm.deleted, or 284 // vm.seen. 285 for key, value := range other.expected { 286 vm.expected[key] = value 287 } 288 vm.validate(t) 289 } 290 291 func (vm *validatedMap) set(t *testing.T, key, value int) { 292 entry := mapEntry{key: key, value: value} 293 294 vm.clock++ 295 vm.seen[entry] = vm.clock 296 297 vm.impl.Set(key, value, func(deletedKey, deletedValue any) { 298 if deletedKey != key || deletedValue != value { 299 t.Fatalf("unexpected passed in deleted entry: %v/%v, expected: %v/%v", deletedKey, deletedValue, key, value) 300 } 301 // Not safe if closure shared between two validatedMaps. 302 vm.deleted[entry] = vm.clock 303 }) 304 vm.expected[key] = value 305 vm.validate(t) 306 307 gotValue, ok := vm.impl.Get(key) 308 if !ok || gotValue != value { 309 t.Fatalf("unexpected get result after insertion, key: %v, expected: %v, got: %v (%v)", key, value, gotValue, ok) 310 } 311 } 312 313 func (vm *validatedMap) remove(t *testing.T, key int) { 314 vm.clock++ 315 deleted := vm.impl.Delete(key) 316 if _, ok := vm.expected[key]; ok != deleted { 317 t.Fatalf("Delete(%d) = %t, want %t", key, deleted, ok) 318 } 319 delete(vm.expected, key) 320 vm.validate(t) 321 322 gotValue, ok := vm.impl.Get(key) 323 if ok { 324 t.Fatalf("unexpected get result after removal, key: %v, got: %v", key, gotValue) 325 } 326 } 327 328 func (vm *validatedMap) clone() *validatedMap { 329 expected := make(map[int]int, len(vm.expected)) 330 for key, value := range vm.expected { 331 expected[key] = value 332 } 333 334 return &validatedMap{ 335 impl: vm.impl.Clone(), 336 expected: expected, 337 deleted: vm.deleted, 338 seen: vm.seen, 339 } 340 } 341 342 func (vm *validatedMap) destroy() { 343 vm.impl.Destroy() 344 } 345 346 func assertSameMap(t *testing.T, map1, map2 any) { 347 t.Helper() 348 349 if !reflect.DeepEqual(map1, map2) { 350 t.Fatalf("different maps:\n%v\nvs\n%v", map1, map2) 351 } 352 }