| // 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) |
| } |
| } |