117 lines
2.5 KiB
Go
117 lines
2.5 KiB
Go
|
|
// Copyright 2016 The Go Authors. All rights reserved.
|
||
|
|
// Use of this source code is governed by a BSD-style
|
||
|
|
// license that can be found in the LICENSE file.
|
||
|
|
|
||
|
|
package syncmap_test
|
||
|
|
|
||
|
|
import (
|
||
|
|
"fmt"
|
||
|
|
"math/rand"
|
||
|
|
"reflect"
|
||
|
|
"testing"
|
||
|
|
"testing/quick"
|
||
|
|
|
||
|
|
"golang.org/x/sync/syncmap"
|
||
|
|
)
|
||
|
|
|
||
|
|
// mapCall is a quick.Generator for calls on mapInterface.
|
||
|
|
type mapCall struct {
|
||
|
|
key interface{}
|
||
|
|
apply func(mapInterface) (interface{}, bool)
|
||
|
|
desc string
|
||
|
|
}
|
||
|
|
|
||
|
|
type mapResult struct {
|
||
|
|
value interface{}
|
||
|
|
ok bool
|
||
|
|
}
|
||
|
|
|
||
|
|
var stringType = reflect.TypeOf("")
|
||
|
|
|
||
|
|
func randValue(r *rand.Rand) interface{} {
|
||
|
|
k, ok := quick.Value(stringType, r)
|
||
|
|
if !ok {
|
||
|
|
panic(fmt.Sprintf("quick.Value(%v, _) failed", stringType))
|
||
|
|
}
|
||
|
|
return k.Interface()
|
||
|
|
}
|
||
|
|
|
||
|
|
func (mapCall) Generate(r *rand.Rand, size int) reflect.Value {
|
||
|
|
k := randValue(r)
|
||
|
|
|
||
|
|
var (
|
||
|
|
app func(mapInterface) (interface{}, bool)
|
||
|
|
desc string
|
||
|
|
)
|
||
|
|
switch rand.Intn(4) {
|
||
|
|
case 0:
|
||
|
|
app = func(m mapInterface) (interface{}, bool) {
|
||
|
|
return m.Load(k)
|
||
|
|
}
|
||
|
|
desc = fmt.Sprintf("Load(%q)", k)
|
||
|
|
|
||
|
|
case 1:
|
||
|
|
v := randValue(r)
|
||
|
|
app = func(m mapInterface) (interface{}, bool) {
|
||
|
|
m.Store(k, v)
|
||
|
|
return nil, false
|
||
|
|
}
|
||
|
|
desc = fmt.Sprintf("Store(%q, %q)", k, v)
|
||
|
|
|
||
|
|
case 2:
|
||
|
|
v := randValue(r)
|
||
|
|
app = func(m mapInterface) (interface{}, bool) {
|
||
|
|
return m.LoadOrStore(k, v)
|
||
|
|
}
|
||
|
|
desc = fmt.Sprintf("LoadOrStore(%q, %q)", k, v)
|
||
|
|
|
||
|
|
case 3:
|
||
|
|
app = func(m mapInterface) (interface{}, bool) {
|
||
|
|
m.Delete(k)
|
||
|
|
return nil, false
|
||
|
|
}
|
||
|
|
desc = fmt.Sprintf("Delete(%q)", k)
|
||
|
|
}
|
||
|
|
|
||
|
|
return reflect.ValueOf(mapCall{k, app, desc})
|
||
|
|
}
|
||
|
|
|
||
|
|
func applyCalls(m mapInterface, calls []mapCall) (results []mapResult, final map[interface{}]interface{}) {
|
||
|
|
for _, c := range calls {
|
||
|
|
v, ok := c.apply(m)
|
||
|
|
results = append(results, mapResult{v, ok})
|
||
|
|
}
|
||
|
|
|
||
|
|
final = make(map[interface{}]interface{})
|
||
|
|
m.Range(func(k, v interface{}) bool {
|
||
|
|
final[k] = v
|
||
|
|
return true
|
||
|
|
})
|
||
|
|
|
||
|
|
return results, final
|
||
|
|
}
|
||
|
|
|
||
|
|
func applyMap(calls []mapCall) ([]mapResult, map[interface{}]interface{}) {
|
||
|
|
return applyCalls(new(syncmap.Map), calls)
|
||
|
|
}
|
||
|
|
|
||
|
|
func applyRWMutexMap(calls []mapCall) ([]mapResult, map[interface{}]interface{}) {
|
||
|
|
return applyCalls(new(RWMutexMap), calls)
|
||
|
|
}
|
||
|
|
|
||
|
|
func applyDeepCopyMap(calls []mapCall) ([]mapResult, map[interface{}]interface{}) {
|
||
|
|
return applyCalls(new(DeepCopyMap), calls)
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestMapMatchesRWMutex(t *testing.T) {
|
||
|
|
if err := quick.CheckEqual(applyMap, applyRWMutexMap, nil); err != nil {
|
||
|
|
t.Error(err)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestMapMatchesDeepCopy(t *testing.T) {
|
||
|
|
if err := quick.CheckEqual(applyMap, applyRWMutexMap, nil); err != nil {
|
||
|
|
t.Error(err)
|
||
|
|
}
|
||
|
|
}
|