package csmap_test import ( "strconv" "sync" "testing" csmap "github.com/mhmtszr/concurrent-swiss-map" ) func TestHas(t *testing.T) { myMap := csmap.New[int, string]() myMap.Store(1, "test") if !myMap.Has(1) { t.Fatal("1 should exists") } } func TestLoad(t *testing.T) { myMap := csmap.New[int, string]() myMap.Store(1, "test") v, ok := myMap.Load(1) v2, ok2 := myMap.Load(2) if v != "test" || !ok { t.Fatal("1 should test") } if v2 != "" || ok2 { t.Fatal("2 should not exist") } } func TestDelete(t *testing.T) { myMap := csmap.New[int, string]() myMap.Store(1, "test") ok1 := myMap.Delete(20) ok2 := myMap.Delete(1) if myMap.Has(1) { t.Fatal("1 should be deleted") } if ok1 { t.Fatal("ok1 should be false") } if !ok2 { t.Fatal("ok2 should be true") } } func TestSetIfAbsent(t *testing.T) { myMap := csmap.New[int, string]() myMap.SetIfAbsent(1, "test") if !myMap.Has(1) { t.Fatal("1 should be exist") } } func TestSetIfPresent(t *testing.T) { myMap := csmap.New[int, string]() myMap.SetIfPresent(1, "test") if myMap.Has(1) { t.Fatal("1 should be not exist") } myMap.Store(1, "test") myMap.SetIfPresent(1, "new-test") val, _ := myMap.Load(1) if val != "new-test" { t.Fatal("val should be new-test") } } func TestSetIf(t *testing.T) { myMap := csmap.New[int, string]() valueA := "value a" myMap.SetIf(1, func(previousVale string, previousFound bool) (value string, set bool) { // operate like a SetIfAbsent... if !previousFound { return valueA, true } return "", false }) value, _ := myMap.Load(1) if value != valueA { t.Fatal("value should value a") } myMap.SetIf(1, func(previousVale string, previousFound bool) (value string, set bool) { // operate like a SetIfAbsent... if !previousFound { return "bad", true } return "", false }) value, _ = myMap.Load(1) if value != valueA { t.Fatal("value should value a") } } func TestDeleteIf(t *testing.T) { myMap := csmap.New[int, string]() myMap.Store(1, "value b") ok1 := myMap.DeleteIf(20, func(value string) bool { t.Fatal("condition function should not have been called") return false }) if ok1 { t.Fatal("ok1 should be false") } ok2 := myMap.DeleteIf(1, func(value string) bool { if value != "value b" { t.Fatal("condition function arg should be tests") } return false // don't delete }) if ok2 { t.Fatal("ok1 should be false") } ok3 := myMap.DeleteIf(1, func(value string) bool { if value != "value b" { t.Fatal("condition function arg should be tests") } return true // delete the entry }) if !ok3 { t.Fatal("ok2 should be true") } } func TestCount(t *testing.T) { myMap := csmap.New[int, string]() myMap.SetIfAbsent(1, "test") myMap.SetIfAbsent(2, "test2") if myMap.Count() != 2 { t.Fatal("count should be 2") } } func TestIsEmpty(t *testing.T) { myMap := csmap.New[int, string]() if !myMap.IsEmpty() { t.Fatal("map should be empty") } } func TestRangeStop(t *testing.T) { myMap := csmap.New[int, string]( csmap.WithShardCount[int, string](1), ) myMap.SetIfAbsent(1, "test") myMap.SetIfAbsent(2, "test2") myMap.SetIfAbsent(3, "test2") total := 0 myMap.Range(func(key int, value string) (stop bool) { total++ return true }) if total != 1 { t.Fatal("total should be 1") } } func TestRange(t *testing.T) { myMap := csmap.New[int, string]() myMap.SetIfAbsent(1, "test") myMap.SetIfAbsent(2, "test2") total := 0 myMap.Range(func(key int, value string) (stop bool) { total++ return }) if total != 2 { t.Fatal("total should be 2") } } func TestCustomHasherWithRange(t *testing.T) { myMap := csmap.New[int, string]( csmap.WithCustomHasher[int, string](func(key int) uint64 { return 0 }), ) myMap.SetIfAbsent(1, "test") myMap.SetIfAbsent(2, "test2") myMap.SetIfAbsent(3, "test2") myMap.SetIfAbsent(4, "test2") total := 0 myMap.Range(func(key int, value string) (stop bool) { total++ return true }) if total != 1 { t.Fatal("total should be 1, because currently range stops current shard only.") } } func TestDeleteFromRange(t *testing.T) { myMap := csmap.New[string, int]( csmap.WithSize[string, int](1024), ) myMap.Store("aaa", 10) myMap.Store("aab", 11) myMap.Store("aac", 15) myMap.Store("aad", 124) myMap.Store("aaf", 987) myMap.Range(func(key string, value int) (stop bool) { if value > 20 { myMap.Delete(key) } return false }) if myMap.Count() != 3 { t.Fatal("total should be 3, because currently range deletes values that bigger than 20.") } } func TestMarshal(t *testing.T) { myMap := csmap.New[string, int]( csmap.WithSize[string, int](1024), ) myMap.Store("aaa", 10) myMap.Store("aab", 11) b, _ := myMap.MarshalJSON() newMap := csmap.New[string, int]( csmap.WithSize[string, int](1024), ) _ = newMap.UnmarshalJSON(b) if myMap.Count() != 2 || !myMap.Has("aaa") || !myMap.Has("aab") { t.Fatal("count should be 2 after unmarshal") } } func TestBasicConcurrentWriteDeleteCount(t *testing.T) { myMap := csmap.New[int, string]( csmap.WithShardCount[int, string](32), csmap.WithSize[int, string](1000), ) var wg sync.WaitGroup wg.Add(1000000) for i := 0; i < 1000000; i++ { i := i go func() { defer wg.Done() myMap.Store(i, strconv.Itoa(i)) }() } wg.Wait() wg.Add(1000000) for i := 0; i < 1000000; i++ { i := i go func() { defer wg.Done() if !myMap.Has(i) { t.Error(strconv.Itoa(i) + " should exist") return } }() } wg.Wait() wg.Add(1000000) for i := 0; i < 1000000; i++ { i := i go func() { defer wg.Done() myMap.Delete(i) }() } wg.Wait() wg.Add(1000000) for i := 0; i < 1000000; i++ { i := i go func() { defer wg.Done() if myMap.Has(i) { t.Error(strconv.Itoa(i) + " should not exist") return } }() } wg.Wait() } func TestClear(t *testing.T) { myMap := csmap.New[int, string]() loop := 10000 for i := 0; i < loop; i++ { myMap.Store(i, "test") } myMap.Clear() if !myMap.IsEmpty() { t.Fatal("count should be true") } // store again for i := 0; i < loop; i++ { myMap.Store(i, "test") } // get again for i := 0; i < loop; i++ { val, ok := myMap.Load(i) if ok != true { t.Fatal("ok should be true") } if val != "test" { t.Fatal("val should be test") } } // check again count := myMap.Count() if count != loop { t.Fatal("count should be 1000") } }