blob: 54448a053ece672989ce80a0e7b2c1087de64822 [file] [log] [blame]
// 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)
}
}