github.com/min1324/cmap@v1.0.3-0.20220418125848-74e72bbe3be4/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 "sync/atomic" 13 "testing" 14 "testing/quick" 15 16 "github.com/min1324/cmap" 17 ) 18 19 type mapOp string 20 21 const ( 22 opLoad = mapOp("Load") 23 opStore = mapOp("Store") 24 opLoadOrStore = mapOp("LoadOrStore") 25 opLoadAndDelete = mapOp("LoadAndDelete") 26 opDelete = mapOp("Delete") 27 ) 28 29 var mapOps = [...]mapOp{opLoad, opStore, opLoadOrStore, opLoadAndDelete, opDelete} 30 31 // mapCall is a quick.Generator for calls on mapInterface. 32 type mapCall struct { 33 op mapOp 34 k, v interface{} 35 } 36 37 func (c mapCall) apply(m mapInterface) (interface{}, bool) { 38 switch c.op { 39 case opLoad: 40 return m.Load(c.k) 41 case opStore: 42 m.Store(c.k, c.v) 43 return nil, false 44 case opLoadOrStore: 45 return m.LoadOrStore(c.k, c.v) 46 case opLoadAndDelete: 47 return m.LoadAndDelete(c.k) 48 case opDelete: 49 m.Delete(c.k) 50 return nil, false 51 default: 52 panic("invalid mapOp") 53 } 54 } 55 56 type mapResult struct { 57 value interface{} 58 ok bool 59 } 60 61 func randValue(r *rand.Rand) interface{} { 62 b := make([]byte, r.Intn(4)) 63 for i := range b { 64 b[i] = 'a' + byte(rand.Intn(26)) 65 } 66 return string(b) 67 } 68 69 func (mapCall) Generate(r *rand.Rand, size int) reflect.Value { 70 c := mapCall{op: mapOps[rand.Intn(len(mapOps))], k: randValue(r)} 71 switch c.op { 72 case opStore, opLoadOrStore: 73 c.v = randValue(r) 74 } 75 return reflect.ValueOf(c) 76 } 77 78 func applyCalls(m mapInterface, calls []mapCall) (results []mapResult, final map[interface{}]interface{}) { 79 for _, c := range calls { 80 v, ok := c.apply(m) 81 results = append(results, mapResult{v, ok}) 82 } 83 84 final = make(map[interface{}]interface{}) 85 m.Range(func(k, v interface{}) bool { 86 final[k] = v 87 return true 88 }) 89 90 return results, final 91 } 92 93 func applyCMap(calls []mapCall) ([]mapResult, map[interface{}]interface{}) { 94 return applyCalls(new(cmap.CMap), calls) 95 } 96 97 func applyFMap(calls []mapCall) ([]mapResult, map[interface{}]interface{}) { 98 return applyCalls(new(cmap.FMap), calls) 99 } 100 101 func applySyncMap(calls []mapCall) ([]mapResult, map[interface{}]interface{}) { 102 return applyCalls(new(cmap.Map), calls) 103 } 104 105 func applyRWMutexMap(calls []mapCall) ([]mapResult, map[interface{}]interface{}) { 106 return applyCalls(new(RWMutexMap), calls) 107 } 108 109 func applyDeepCopyMap(calls []mapCall) ([]mapResult, map[interface{}]interface{}) { 110 return applyCalls(new(DeepCopyMap), calls) 111 } 112 113 func TestMapEvacute(t *testing.T) { 114 var m cmap.CMap 115 for i := 0; i < 1<<20; i++ { 116 m.Store(i, i) 117 } 118 v, ok := m.Load(1 << 15) 119 if !ok || v != 1<<15 { 120 t.Errorf("i!=15") 121 } 122 if m.Count() != 1<<20 { 123 t.Errorf("Count!=1<<20") 124 } 125 } 126 127 func TestMapMatchesSync(t *testing.T) { 128 if err := quick.CheckEqual(applyCMap, applySyncMap, nil); err != nil { 129 t.Error(err) 130 } 131 } 132 133 func TestFMapMatchesSync(t *testing.T) { 134 if err := quick.CheckEqual(applyFMap, applyRWMutexMap, nil); err != nil { 135 t.Error(err) 136 } 137 } 138 139 func TestMapMatchesRWMutex(t *testing.T) { 140 if err := quick.CheckEqual(applyCMap, applyRWMutexMap, nil); err != nil { 141 t.Error(err) 142 } 143 } 144 145 func TestMapMatchesDeepCopy(t *testing.T) { 146 if err := quick.CheckEqual(applyCMap, applyDeepCopyMap, nil); err != nil { 147 t.Error(err) 148 } 149 } 150 151 func TestConcurrentRange(t *testing.T) { 152 const mapSize = 1 << 10 153 154 m := new(cmap.CMap) 155 for n := int64(1); n <= mapSize; n++ { 156 m.Store(n, int64(n)) 157 } 158 159 done := make(chan struct{}) 160 var wg sync.WaitGroup 161 defer func() { 162 close(done) 163 wg.Wait() 164 }() 165 for g := int64(runtime.GOMAXPROCS(0)); g > 0; g-- { 166 r := rand.New(rand.NewSource(g)) 167 wg.Add(1) 168 go func(g int64) { 169 defer wg.Done() 170 for i := int64(0); ; i++ { 171 select { 172 case <-done: 173 return 174 default: 175 } 176 for n := int64(1); n < mapSize; n++ { 177 if r.Int63n(mapSize) == 0 { 178 m.Store(n, n*i*g) 179 } else { 180 m.Load(n) 181 } 182 } 183 } 184 }(g) 185 } 186 187 iters := 1 << 10 188 if testing.Short() { 189 iters = 16 190 } 191 for n := iters; n > 0; n-- { 192 seen := make(map[int64]bool, mapSize) 193 194 m.Range(func(ki, vi interface{}) bool { 195 k, v := ki.(int64), vi.(int64) 196 if v%k != 0 { 197 t.Fatalf("while Storing multiples of %v, Range saw value %v", k, v) 198 } 199 if seen[k] { 200 t.Fatalf("Range visited key %v twice", k) 201 } 202 seen[k] = true 203 return true 204 }) 205 206 if len(seen) != mapSize { 207 t.Fatalf("Range visited %v elements of %v-element Map", len(seen), mapSize) 208 } 209 } 210 } 211 212 func TestIssue40999(t *testing.T) { 213 var m cmap.CMap 214 215 // Since the miss-counting in missLocked (via Delete) 216 // compares the miss count with len(m.dirty), 217 // add an initial entry to bias len(m.dirty) above the miss count. 218 m.Store(nil, struct{}{}) 219 220 var finalized uint32 221 222 // Set finalizers that count for collected keys. A non-zero count 223 // indicates that keys have not been leaked. 224 for atomic.LoadUint32(&finalized) == 0 { 225 p := new(int) 226 runtime.SetFinalizer(p, func(*int) { 227 atomic.AddUint32(&finalized, 1) 228 }) 229 m.Store(p, struct{}{}) 230 m.Delete(p) 231 runtime.GC() 232 } 233 } 234 235 func TestMapStoreAndLoad(t *testing.T) { 236 const mapSize = 1 << 14 237 238 var ( 239 m cmap.CMap 240 wg sync.WaitGroup 241 seen = make(map[int64]bool, mapSize) 242 ) 243 244 for n := int64(1); n <= mapSize; n++ { 245 nn := n 246 wg.Add(1) 247 go func() { 248 defer wg.Done() 249 m.Store(nn, nn) 250 }() 251 } 252 253 wg.Wait() 254 255 m.Range(func(ki, vi interface{}) bool { 256 k, v := ki.(int64), vi.(int64) 257 if v%k != 0 { 258 t.Fatalf("while Storing multiples of %v, Range saw value %v", k, v) 259 } 260 if seen[k] { 261 t.Fatalf("Range visited key %v twice", k) 262 } 263 seen[k] = true 264 return true 265 }) 266 267 if len(seen) != mapSize { 268 t.Fatalf("Range visited %v elements of %v-element Map", len(seen), mapSize) 269 } 270 271 for n := int64(1); n <= mapSize; n++ { 272 nn := n 273 wg.Add(1) 274 go func() { 275 defer wg.Done() 276 m.Delete(nn) 277 }() 278 } 279 280 wg.Wait() 281 282 m.Range(func(key, value interface{}) bool { 283 t.Fatalf("Map should be empty") 284 return false 285 }) 286 } 287 288 func TestCount(t *testing.T) { 289 const want = 1025 290 tests := []struct { 291 name string 292 m cmap.Interface 293 want int 294 }{ 295 // TODO: Add test cases. 296 { 297 "fmap", 298 &cmap.FMap{}, 299 want, 300 }, 301 { 302 "cmap", 303 &cmap.CMap{}, 304 want, 305 }, 306 { 307 "map", 308 &cmap.Map{}, 309 want, 310 }, 311 } 312 for _, tt := range tests { 313 for i := 0; i < tt.want; i++ { 314 tt.m.Store(i, i) 315 } 316 t.Run(tt.name, func(t *testing.T) { 317 318 if got := tt.m.Count(); int(got) != tt.want { 319 t.Errorf("Count() = %v, want %v", got, tt.want) 320 } 321 }) 322 } 323 }