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  }