github.com/mhmtszr/concurrent-swiss-map@v1.0.8/concurrent_swiss_map_test.go (about) 1 package csmap_test 2 3 import ( 4 "strconv" 5 "sync" 6 "testing" 7 8 csmap "github.com/mhmtszr/concurrent-swiss-map" 9 ) 10 11 func TestHas(t *testing.T) { 12 myMap := csmap.Create[int, string]() 13 myMap.Store(1, "test") 14 if !myMap.Has(1) { 15 t.Fatal("1 should exists") 16 } 17 } 18 19 func TestLoad(t *testing.T) { 20 myMap := csmap.Create[int, string]() 21 myMap.Store(1, "test") 22 v, ok := myMap.Load(1) 23 v2, ok2 := myMap.Load(2) 24 if v != "test" || !ok { 25 t.Fatal("1 should test") 26 } 27 if v2 != "" || ok2 { 28 t.Fatal("2 should not exist") 29 } 30 } 31 32 func TestDelete(t *testing.T) { 33 myMap := csmap.Create[int, string]() 34 myMap.Store(1, "test") 35 ok1 := myMap.Delete(20) 36 ok2 := myMap.Delete(1) 37 if myMap.Has(1) { 38 t.Fatal("1 should be deleted") 39 } 40 if ok1 { 41 t.Fatal("ok1 should be false") 42 } 43 if !ok2 { 44 t.Fatal("ok2 should be true") 45 } 46 } 47 48 func TestSetIfAbsent(t *testing.T) { 49 myMap := csmap.Create[int, string]() 50 myMap.SetIfAbsent(1, "test") 51 if !myMap.Has(1) { 52 t.Fatal("1 should be exist") 53 } 54 } 55 56 func TestSetIfPresent(t *testing.T) { 57 myMap := csmap.Create[int, string]() 58 myMap.SetIfPresent(1, "test") 59 if myMap.Has(1) { 60 t.Fatal("1 should be not exist") 61 } 62 63 myMap.Store(1, "test") 64 myMap.SetIfPresent(1, "new-test") 65 val, _ := myMap.Load(1) 66 if val != "new-test" { 67 t.Fatal("val should be new-test") 68 } 69 } 70 71 func TestSetIf(t *testing.T) { 72 myMap := csmap.Create[int, string]() 73 valueA := "value a" 74 myMap.SetIf(1, func(previousVale string, previousFound bool) (value string, set bool) { 75 // operate like a SetIfAbsent... 76 if !previousFound { 77 return valueA, true 78 } 79 return "", false 80 }) 81 value, _ := myMap.Load(1) 82 if value != valueA { 83 t.Fatal("value should value a") 84 } 85 86 myMap.SetIf(1, func(previousVale string, previousFound bool) (value string, set bool) { 87 // operate like a SetIfAbsent... 88 if !previousFound { 89 return "bad", true 90 } 91 return "", false 92 }) 93 value, _ = myMap.Load(1) 94 if value != valueA { 95 t.Fatal("value should value a") 96 } 97 } 98 99 func TestDeleteIf(t *testing.T) { 100 myMap := csmap.Create[int, string]() 101 myMap.Store(1, "value b") 102 ok1 := myMap.DeleteIf(20, func(value string) bool { 103 t.Fatal("condition function should not have been called") 104 return false 105 }) 106 if ok1 { 107 t.Fatal("ok1 should be false") 108 } 109 110 ok2 := myMap.DeleteIf(1, func(value string) bool { 111 if value != "value b" { 112 t.Fatal("condition function arg should be tests") 113 } 114 return false // don't delete 115 }) 116 if ok2 { 117 t.Fatal("ok1 should be false") 118 } 119 120 ok3 := myMap.DeleteIf(1, func(value string) bool { 121 if value != "value b" { 122 t.Fatal("condition function arg should be tests") 123 } 124 return true // delete the entry 125 }) 126 if !ok3 { 127 t.Fatal("ok2 should be true") 128 } 129 } 130 131 func TestCount(t *testing.T) { 132 myMap := csmap.Create[int, string]() 133 myMap.SetIfAbsent(1, "test") 134 myMap.SetIfAbsent(2, "test2") 135 if myMap.Count() != 2 { 136 t.Fatal("count should be 2") 137 } 138 } 139 140 func TestIsEmpty(t *testing.T) { 141 myMap := csmap.Create[int, string]() 142 if !myMap.IsEmpty() { 143 t.Fatal("map should be empty") 144 } 145 } 146 147 func TestRangeStop(t *testing.T) { 148 myMap := csmap.Create[int, string]( 149 csmap.WithShardCount[int, string](1), 150 ) 151 myMap.SetIfAbsent(1, "test") 152 myMap.SetIfAbsent(2, "test2") 153 myMap.SetIfAbsent(3, "test2") 154 total := 0 155 myMap.Range(func(key int, value string) (stop bool) { 156 total++ 157 return true 158 }) 159 if total != 1 { 160 t.Fatal("total should be 1") 161 } 162 } 163 164 func TestRange(t *testing.T) { 165 myMap := csmap.Create[int, string]() 166 myMap.SetIfAbsent(1, "test") 167 myMap.SetIfAbsent(2, "test2") 168 total := 0 169 myMap.Range(func(key int, value string) (stop bool) { 170 total++ 171 return 172 }) 173 if total != 2 { 174 t.Fatal("total should be 2") 175 } 176 } 177 178 func TestCustomHasherWithRange(t *testing.T) { 179 myMap := csmap.Create[int, string]( 180 csmap.WithCustomHasher[int, string](func(key int) uint64 { 181 return 0 182 }), 183 ) 184 myMap.SetIfAbsent(1, "test") 185 myMap.SetIfAbsent(2, "test2") 186 myMap.SetIfAbsent(3, "test2") 187 myMap.SetIfAbsent(4, "test2") 188 total := 0 189 myMap.Range(func(key int, value string) (stop bool) { 190 total++ 191 return true 192 }) 193 if total != 1 { 194 t.Fatal("total should be 1, because currently range stops current shard only.") 195 } 196 } 197 198 func TestDeleteFromRange(t *testing.T) { 199 myMap := csmap.Create[string, int]( 200 csmap.WithSize[string, int](1024), 201 ) 202 203 myMap.Store("aaa", 10) 204 myMap.Store("aab", 11) 205 myMap.Store("aac", 15) 206 myMap.Store("aad", 124) 207 myMap.Store("aaf", 987) 208 209 myMap.Range(func(key string, value int) (stop bool) { 210 if value > 20 { 211 myMap.Delete(key) 212 } 213 return false 214 }) 215 if myMap.Count() != 3 { 216 t.Fatal("total should be 3, because currently range deletes values that bigger than 20.") 217 } 218 } 219 220 func TestMarshal(t *testing.T) { 221 myMap := csmap.Create[string, int]( 222 csmap.WithSize[string, int](1024), 223 ) 224 225 myMap.Store("aaa", 10) 226 myMap.Store("aab", 11) 227 228 b, _ := myMap.MarshalJSON() 229 230 newMap := csmap.Create[string, int]( 231 csmap.WithSize[string, int](1024), 232 ) 233 234 _ = newMap.UnmarshalJSON(b) 235 236 if myMap.Count() != 2 || !myMap.Has("aaa") || !myMap.Has("aab") { 237 t.Fatal("count should be 2 after unmarshal") 238 } 239 } 240 241 func TestBasicConcurrentWriteDeleteCount(t *testing.T) { 242 myMap := csmap.Create[int, string]( 243 csmap.WithShardCount[int, string](32), 244 csmap.WithSize[int, string](1000), 245 ) 246 247 var wg sync.WaitGroup 248 wg.Add(1000000) 249 for i := 0; i < 1000000; i++ { 250 i := i 251 go func() { 252 defer wg.Done() 253 myMap.Store(i, strconv.Itoa(i)) 254 }() 255 } 256 wg.Wait() 257 wg.Add(1000000) 258 for i := 0; i < 1000000; i++ { 259 i := i 260 go func() { 261 defer wg.Done() 262 if !myMap.Has(i) { 263 t.Error(strconv.Itoa(i) + " should exist") 264 return 265 } 266 }() 267 } 268 269 wg.Wait() 270 wg.Add(1000000) 271 272 for i := 0; i < 1000000; i++ { 273 i := i 274 go func() { 275 defer wg.Done() 276 myMap.Delete(i) 277 }() 278 } 279 280 wg.Wait() 281 wg.Add(1000000) 282 283 for i := 0; i < 1000000; i++ { 284 i := i 285 go func() { 286 defer wg.Done() 287 if myMap.Has(i) { 288 t.Error(strconv.Itoa(i) + " should not exist") 289 return 290 } 291 }() 292 } 293 294 wg.Wait() 295 } 296 297 func TestClear(t *testing.T) { 298 myMap := csmap.Create[int, string]() 299 loop := 10000 300 for i := 0; i < loop; i++ { 301 myMap.Store(i, "test") 302 } 303 304 myMap.Clear() 305 306 if !myMap.IsEmpty() { 307 t.Fatal("count should be true") 308 } 309 310 // store again 311 for i := 0; i < loop; i++ { 312 myMap.Store(i, "test") 313 } 314 315 // get again 316 for i := 0; i < loop; i++ { 317 val, ok := myMap.Load(i) 318 if ok != true { 319 t.Fatal("ok should be true") 320 } 321 322 if val != "test" { 323 t.Fatal("val should be test") 324 } 325 } 326 327 // check again 328 count := myMap.Count() 329 if count != loop { 330 t.Fatal("count should be 1000") 331 } 332 }