GoPLS Viewer

Home|gopls/internal/persistent/map_test.go
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
5package persistent
6
7import (
8    "fmt"
9    "math/rand"
10    "reflect"
11    "sync/atomic"
12    "testing"
13)
14
15type mapEntry struct {
16    key   int
17    value int
18}
19
20type validatedMap struct {
21    impl     *Map
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
28func TestSimpleMap(t *testing.T) {
29    deletedEntries := make(map[mapEntry]int)
30    seenEntries := make(map[mapEntry]int)
31
32    m1 := &validatedMap{
33        implNewMap(func(ab interface{}) bool {
34            return a.(int) < b.(int)
35        }),
36        expectedmake(map[int]int),
37        deleted:  deletedEntries,
38        seen:     seenEntries,
39    }
40
41    m3 := m1.clone()
42    validateRef(tm1m3)
43    m3.set(t88)
44    validateRef(tm1m3)
45    m3.destroy()
46
47    assertSameMap(tentrySet(deletedEntries), map[mapEntry]struct{}{
48        {key8value8}: {},
49    })
50
51    validateRef(tm1)
52    m1.set(t11)
53    validateRef(tm1)
54    m1.set(t22)
55    validateRef(tm1)
56    m1.set(t33)
57    validateRef(tm1)
58    m1.remove(t2)
59    validateRef(tm1)
60    m1.set(t66)
61    validateRef(tm1)
62
63    assertSameMap(tentrySet(deletedEntries), map[mapEntry]struct{}{
64        {key2value2}: {},
65        {key8value8}: {},
66    })
67
68    m2 := m1.clone()
69    validateRef(tm1m2)
70    m1.set(t660)
71    validateRef(tm1m2)
72    m1.remove(t1)
73    validateRef(tm1m2)
74
75    gotAllocs := int(testing.AllocsPerRun(10, func() {
76        m1.impl.Delete(100)
77        m1.impl.Delete(1)
78    }))
79    wantAllocs := 0
80    if gotAllocs != wantAllocs {
81        t.Errorf("wanted %d allocs, got %d"wantAllocsgotAllocs)
82    }
83
84    for i := 10i < 14i++ {
85        m1.set(tii)
86        validateRef(tm1m2)
87    }
88
89    m1.set(t10100)
90    validateRef(tm1m2)
91
92    m1.remove(t12)
93    validateRef(tm1m2)
94
95    m2.set(t44)
96    validateRef(tm1m2)
97    m2.set(t55)
98    validateRef(tm1m2)
99
100    m1.destroy()
101
102    assertSameMap(tentrySet(deletedEntries), map[mapEntry]struct{}{
103        {key2value2}:    {},
104        {key6value60}:   {},
105        {key8value8}:    {},
106        {key10value10}:  {},
107        {key10value100}: {},
108        {key11value11}:  {},
109        {key12value12}:  {},
110        {key13value13}:  {},
111    })
112
113    m2.set(t77)
114    validateRef(tm2)
115
116    m2.destroy()
117
118    assertSameMap(tentrySet(seenEntries), entrySet(deletedEntries))
119}
120
121func TestRandomMap(t *testing.T) {
122    deletedEntries := make(map[mapEntry]int)
123    seenEntries := make(map[mapEntry]int)
124
125    m := &validatedMap{
126        implNewMap(func(ab interface{}) bool {
127            return a.(int) < b.(int)
128        }),
129        expectedmake(map[int]int),
130        deleted:  deletedEntries,
131        seen:     seenEntries,
132    }
133
134    keys := make([]int01000)
135    for i := 0i < 1000i++ {
136        key := rand.Intn(10000)
137        m.set(tkeykey)
138        keys = append(keyskey)
139
140        if i%10 == 1 {
141            index := rand.Intn(len(keys))
142            last := len(keys) - 1
143            key = keys[index]
144            keys[index], keys[last] = keys[last], keys[index]
145            keys = keys[:last]
146
147            m.remove(tkey)
148        }
149    }
150
151    m.destroy()
152    assertSameMap(tentrySet(seenEntries), entrySet(deletedEntries))
153}
154
155func entrySet(m map[mapEntry]int) map[mapEntry]struct{} {
156    set := make(map[mapEntry]struct{})
157    for k := range m {
158        set[k] = struct{}{}
159    }
160    return set
161}
162
163func TestUpdate(t *testing.T) {
164    deletedEntries := make(map[mapEntry]int)
165    seenEntries := make(map[mapEntry]int)
166
167    m1 := &validatedMap{
168        implNewMap(func(ab interface{}) bool {
169            return a.(int) < b.(int)
170        }),
171        expectedmake(map[int]int),
172        deleted:  deletedEntries,
173        seen:     seenEntries,
174    }
175    m2 := m1.clone()
176
177    m1.set(t11)
178    m1.set(t22)
179    m2.set(t220)
180    m2.set(t33)
181    m1.setAll(tm2)
182
183    m1.destroy()
184    m2.destroy()
185    assertSameMap(tentrySet(seenEntries), entrySet(deletedEntries))
186}
187
188func validateRef(t *testing.Tmaps ...*validatedMap) {
189    t.Helper()
190
191    actualCountByEntry := make(map[mapEntry]int32)
192    nodesByEntry := make(map[mapEntry]map[*mapNode]struct{})
193    expectedCountByEntry := make(map[mapEntry]int32)
194    for im := range maps {
195        dfsRef(m.impl.rootactualCountByEntrynodesByEntry)
196        dumpMap(tfmt.Sprintf("%d:"i), m.impl.root)
197    }
198    for entrynodes := range nodesByEntry {
199        expectedCountByEntry[entry] = int32(len(nodes))
200    }
201    assertSameMap(texpectedCountByEntryactualCountByEntry)
202}
203
204func dfsRef(node *mapNodecountByEntry map[mapEntry]int32nodesByEntry map[mapEntry]map[*mapNode]struct{}) {
205    if node == nil {
206        return
207    }
208
209    entry := mapEntry{keynode.key.(int), valuenode.value.value.(int)}
210    countByEntry[entry] = atomic.LoadInt32(&node.value.refCount)
211
212    nodesok := nodesByEntry[entry]
213    if !ok {
214        nodes = make(map[*mapNode]struct{})
215        nodesByEntry[entry] = nodes
216    }
217    nodes[node] = struct{}{}
218
219    dfsRef(node.leftcountByEntrynodesByEntry)
220    dfsRef(node.rightcountByEntrynodesByEntry)
221}
222
223func dumpMap(t *testing.Tprefix stringn *mapNode) {
224    if n == nil {
225        t.Logf("%s nil"prefix)
226        return
227    }
228    t.Logf("%s {key: %v, value: %v (ref: %v), ref: %v, weight: %v}"prefixn.keyn.value.valuen.value.refCountn.refCountn.weight)
229    dumpMap(tprefix+"l"n.left)
230    dumpMap(tprefix+"r"n.right)
231}
232
233func (vm *validatedMapvalidate(t *testing.T) {
234    t.Helper()
235
236    validateNode(tvm.impl.rootvm.impl.less)
237
238    // Note: this validation may not make sense if maps were constructed using
239    // SetAll operations. If this proves to be problematic, remove the clock,
240    // deleted, and seen fields.
241    for keyvalue := range vm.expected {
242        entry := mapEntry{keykeyvaluevalue}
243        if deleteAt := vm.deleted[entry]; deleteAt > vm.seen[entry] {
244            t.Fatalf("entry is deleted prematurely, key: %d, value: %d"keyvalue)
245        }
246    }
247
248    actualMap := make(map[int]intlen(vm.expected))
249    vm.impl.Range(func(keyvalue interface{}) {
250        if otherok := actualMap[key.(int)]; ok {
251            t.Fatalf("key is present twice, key: %d, first value: %d, second value: %d"keyvalueother)
252        }
253        actualMap[key.(int)] = value.(int)
254    })
255
256    assertSameMap(tactualMapvm.expected)
257}
258
259func validateNode(t *testing.Tnode *mapNodeless func(ab interface{}) bool) {
260    if node == nil {
261        return
262    }
263
264    if node.left != nil {
265        if less(node.keynode.left.key) {
266            t.Fatalf("left child has larger key: %v vs %v"node.left.keynode.key)
267        }
268        if node.left.weight > node.weight {
269            t.Fatalf("left child has larger weight: %v vs %v"node.left.weightnode.weight)
270        }
271    }
272
273    if node.right != nil {
274        if less(node.right.keynode.key) {
275            t.Fatalf("right child has smaller key: %v vs %v"node.right.keynode.key)
276        }
277        if node.right.weight > node.weight {
278            t.Fatalf("right child has larger weight: %v vs %v"node.right.weightnode.weight)
279        }
280    }
281
282    validateNode(tnode.leftless)
283    validateNode(tnode.rightless)
284}
285
286func (vm *validatedMapsetAll(t *testing.Tother *validatedMap) {
287    vm.impl.SetAll(other.impl)
288
289    // Note: this is buggy because we are not updating vm.clock, vm.deleted, or
290    // vm.seen.
291    for keyvalue := range other.expected {
292        vm.expected[key] = value
293    }
294    vm.validate(t)
295}
296
297func (vm *validatedMapset(t *testing.Tkeyvalue int) {
298    entry := mapEntry{keykeyvaluevalue}
299
300    vm.clock++
301    vm.seen[entry] = vm.clock
302
303    vm.impl.Set(keyvalue, func(deletedKeydeletedValue interface{}) {
304        if deletedKey != key || deletedValue != value {
305            t.Fatalf("unexpected passed in deleted entry: %v/%v, expected: %v/%v"deletedKeydeletedValuekeyvalue)
306        }
307        // Not safe if closure shared between two validatedMaps.
308        vm.deleted[entry] = vm.clock
309    })
310    vm.expected[key] = value
311    vm.validate(t)
312
313    gotValueok := vm.impl.Get(key)
314    if !ok || gotValue != value {
315        t.Fatalf("unexpected get result after insertion, key: %v, expected: %v, got: %v (%v)"keyvaluegotValueok)
316    }
317}
318
319func (vm *validatedMapremove(t *testing.Tkey int) {
320    vm.clock++
321    vm.impl.Delete(key)
322    delete(vm.expectedkey)
323    vm.validate(t)
324
325    gotValueok := vm.impl.Get(key)
326    if ok {
327        t.Fatalf("unexpected get result after removal, key: %v, got: %v"keygotValue)
328    }
329}
330
331func (vm *validatedMapclone() *validatedMap {
332    expected := make(map[int]intlen(vm.expected))
333    for keyvalue := range vm.expected {
334        expected[key] = value
335    }
336
337    return &validatedMap{
338        impl:     vm.impl.Clone(),
339        expectedexpected,
340        deleted:  vm.deleted,
341        seen:     vm.seen,
342    }
343}
344
345func (vm *validatedMapdestroy() {
346    vm.impl.Destroy()
347}
348
349func assertSameMap(t *testing.Tmap1map2 interface{}) {
350    t.Helper()
351
352    if !reflect.DeepEqual(map1map2) {
353        t.Fatalf("different maps:\n%v\nvs\n%v"map1map2)
354    }
355}
356
MembersX
validatedMap.validate.RangeStmt_5466.BlockStmt.entry
validatedMap.set
validatedMap.remove.gotValue
TestSimpleMap.m1
TestSimpleMap.m3
TestSimpleMap.i
dfsRef
validateNode
testing
mapEntry
TestRandomMap.t
TestRandomMap.seenEntries
validatedMap.setAll
validatedMap.remove.vm
TestSimpleMap.m2
TestRandomMap.i
validateRef.expectedCountByEntry
validatedMap.validate
validateRef.t
dfsRef.node
validatedMap.set.value
assertSameMap.t
validatedMap.set.gotValue
validatedMap.clone.vm
entrySet.RangeStmt_3263.k
TestUpdate.t
validateRef.RangeStmt_4055.m
dumpMap.prefix
validatedMap.set.ok
validatedMap.deleted
dfsRef.countByEntry
dfsRef.nodesByEntry
validatedMap.setAll.RangeStmt_6951.value
entrySet.m
TestUpdate.deletedEntries
validateRef.maps
dumpMap
validatedMap.clock
TestSimpleMap.seenEntries
TestRandomMap.deletedEntries
TestRandomMap.BlockStmt.BlockStmt.index
dumpMap.n
validatedMap.remove.t
TestUpdate.seenEntries
validateRef
dfsRef.entry
mapEntry.value
validatedMap
TestRandomMap.keys
entrySet.set
assertSameMap.map1
mapEntry.key
validatedMap.validate.RangeStmt_5466.value
validatedMap.setAll.other
validatedMap.clone
dumpMap.t
validatedMap.validate.actualMap
assertSameMap.map2
TestSimpleMap.deletedEntries
TestSimpleMap.wantAllocs
TestRandomMap.m
TestRandomMap.BlockStmt.key
validatedMap.setAll.vm
validatedMap.clone.RangeStmt_8106.value
validatedMap.destroy
TestSimpleMap.gotAllocs
TestUpdate.m2
validateNode.t
validateNode.node
validatedMap.remove
validatedMap.remove.key
validatedMap.clone.RangeStmt_8106.key
TestUpdate
validateRef.RangeStmt_4189.nodes
validatedMap.setAll.t
validatedMap.set.t
validateRef.nodesByEntry
validatedMap.validate.vm
validatedMap.validate.RangeStmt_5466.key
validatedMap.set.vm
validatedMap.expected
TestSimpleMap
TestSimpleMap.t
TestRandomMap
validatedMap.set.key
validatedMap.destroy.vm
assertSameMap
validateRef.actualCountByEntry
validateRef.RangeStmt_4055.i
validatedMap.validate.t
reflect
validatedMap.seen
entrySet
TestUpdate.m1
validatedMap.set.entry
validatedMap.remove.ok
validatedMap.clone.expected
validatedMap.impl
validateRef.RangeStmt_4189.entry
validateNode.less
validatedMap.setAll.RangeStmt_6951.key
Members
X