github.com/lrita/cmap@v0.0.0-20231108122212-cb084a67f554/cmap_test.go (about) 1 // Copyright 2016 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 cmap_test 6 7 import ( 8 "math/rand" 9 "reflect" 10 "runtime" 11 "sync" 12 "testing" 13 "testing/quick" 14 15 "github.com/lrita/cmap" 16 ) 17 18 type mapOp string 19 20 const ( 21 opLoad = mapOp("Load") 22 opStore = mapOp("Store") 23 opLoadOrStore = mapOp("LoadOrStore") 24 opDelete = mapOp("Delete") 25 ) 26 27 var mapOps = [...]mapOp{opLoad, opStore, opLoadOrStore, opDelete} 28 29 // mapCall is a quick.Generator for calls on mapInterface. 30 type mapCall struct { 31 op mapOp 32 k, v interface{} 33 } 34 35 func (c mapCall) apply(m mapInterface) (interface{}, bool) { 36 switch c.op { 37 case opLoad: 38 return m.Load(c.k) 39 case opStore: 40 m.Store(c.k, c.v) 41 return nil, false 42 case opLoadOrStore: 43 return m.LoadOrStore(c.k, c.v) 44 case opDelete: 45 m.Delete(c.k) 46 return nil, false 47 default: 48 panic("invalid mapOp") 49 } 50 } 51 52 type mapResult struct { 53 value interface{} 54 ok bool 55 } 56 57 func randValue(r *rand.Rand) interface{} { 58 b := make([]byte, r.Intn(4)) 59 for i := range b { 60 b[i] = 'a' + byte(rand.Intn(26)) 61 } 62 return string(b) 63 } 64 65 func (mapCall) Generate(r *rand.Rand, size int) reflect.Value { 66 c := mapCall{op: mapOps[rand.Intn(len(mapOps))], k: randValue(r)} 67 switch c.op { 68 case opStore, opLoadOrStore: 69 c.v = randValue(r) 70 } 71 return reflect.ValueOf(c) 72 } 73 74 func applyCalls(m mapInterface, calls []mapCall) (results []mapResult, final map[interface{}]interface{}) { 75 for _, c := range calls { 76 v, ok := c.apply(m) 77 results = append(results, mapResult{v, ok}) 78 } 79 80 final = make(map[interface{}]interface{}) 81 m.Range(func(k, v interface{}) bool { 82 final[k] = v 83 return true 84 }) 85 86 return results, final 87 } 88 89 func applyMap(calls []mapCall) ([]mapResult, map[interface{}]interface{}) { 90 return applyCalls(new(cmap.Cmap), calls) 91 } 92 93 func applyRWMutexMap(calls []mapCall) ([]mapResult, map[interface{}]interface{}) { 94 return applyCalls(new(RWMutexMap), calls) 95 } 96 97 func applyDeepCopyMap(calls []mapCall) ([]mapResult, map[interface{}]interface{}) { 98 return applyCalls(new(DeepCopyMap), calls) 99 } 100 101 func TestMapMatchesRWMutex(t *testing.T) { 102 if err := quick.CheckEqual(applyMap, applyRWMutexMap, nil); err != nil { 103 t.Error(err) 104 } 105 } 106 107 func TestMapMatchesDeepCopy(t *testing.T) { 108 if err := quick.CheckEqual(applyMap, applyDeepCopyMap, nil); err != nil { 109 t.Error(err) 110 } 111 } 112 113 func TestConcurrentRange(t *testing.T) { 114 const mapSize = 1 << 10 115 116 m := new(cmap.Cmap) 117 for n := int64(1); n <= mapSize; n++ { 118 m.Store(n, int64(n)) 119 } 120 121 done := make(chan struct{}) 122 var wg sync.WaitGroup 123 defer func() { 124 close(done) 125 wg.Wait() 126 }() 127 for g := int64(runtime.GOMAXPROCS(0)); g > 0; g-- { 128 r := rand.New(rand.NewSource(g)) 129 wg.Add(1) 130 go func(g int64) { 131 defer wg.Done() 132 for i := int64(0); ; i++ { 133 select { 134 case <-done: 135 return 136 default: 137 } 138 for n := int64(1); n < mapSize; n++ { 139 if r.Int63n(mapSize) == 0 { 140 m.Store(n, n*i*g) 141 } else { 142 m.Load(n) 143 } 144 } 145 } 146 }(g) 147 } 148 149 iters := 1 << 10 150 if testing.Short() { 151 iters = 16 152 } 153 for n := iters; n > 0; n-- { 154 seen := make(map[int64]bool, mapSize) 155 156 m.Range(func(ki, vi interface{}) bool { 157 k, v := ki.(int64), vi.(int64) 158 if v%k != 0 { 159 t.Fatalf("while Storing multiples of %v, Range saw value %v", k, v) 160 } 161 if seen[k] { 162 t.Fatalf("Range visited key %v twice", k) 163 } 164 seen[k] = true 165 return true 166 }) 167 168 if len(seen) != mapSize { 169 t.Fatalf("Range visited %v elements of %v-element Map", len(seen), mapSize) 170 } 171 } 172 } 173 174 func TestMapCreation(t *testing.T) { 175 m := cmap.Cmap{} 176 177 if m.Count() != 0 { 178 t.Error("new map should be empty.") 179 } 180 if !m.IsEmpty() { 181 t.Error("new map should be empty.") 182 } 183 } 184 185 func TestStoreOperationDuplicatedKey(t *testing.T) { 186 m := cmap.Cmap{} 187 m.Store(t, "") 188 m.Store(t, "") 189 if v := m.Count(); v != 1 { 190 t.Errorf("map Count() should be %d, got %d", 1, v) 191 } 192 m.LoadOrStore("m", "") 193 if v := m.Count(); v != 2 { 194 t.Errorf("map Count() should be %d, got %d", 2, v) 195 } 196 m.Delete(t) 197 if v := m.Count(); v != 1 { 198 t.Errorf("map Count() should be %d, got %d", 1, v) 199 } 200 m.Delete(t) 201 if v := m.Count(); v != 1 { 202 t.Errorf("map Count() should be %d, got %d", 1, v) 203 } 204 } 205 206 func TestMapStoreAndLoad(t *testing.T) { 207 const mapSize = 1 << 14 208 209 var ( 210 m cmap.Cmap 211 wg sync.WaitGroup 212 seen = make(map[int64]bool, mapSize) 213 ) 214 215 for n := int64(1); n <= mapSize; n++ { 216 nn := n 217 wg.Add(1) 218 go func() { 219 defer wg.Done() 220 m.Store(nn, nn) 221 }() 222 } 223 224 wg.Wait() 225 226 m.Range(func(ki, vi interface{}) bool { 227 k, v := ki.(int64), vi.(int64) 228 if v%k != 0 { 229 t.Fatalf("while Storing multiples of %v, Range saw value %v", k, v) 230 } 231 if seen[k] { 232 t.Fatalf("Range visited key %v twice", k) 233 } 234 seen[k] = true 235 return true 236 }) 237 238 if len(seen) != mapSize { 239 t.Fatalf("Range visited %v elements of %v-element Map", len(seen), mapSize) 240 } 241 242 for n := int64(1); n <= mapSize; n++ { 243 nn := n 244 wg.Add(1) 245 go func() { 246 defer wg.Done() 247 m.Delete(nn) 248 }() 249 } 250 251 wg.Wait() 252 253 if !m.IsEmpty() { 254 t.Fatalf("Map should be empty, remained %v", m.Count()) 255 } 256 }