package go_int32_handle import ( "fmt" "math/rand" "runtime" "sync" "testing" ) func TestFunc1(t *testing.T) { hm := New[string]() h1 := testUtilAlloc(hm, t, "hello") h2 := testUtilAlloc(hm, t, "world") testUtilGet(hm, t, h1, "hello") testUtilGet(hm, t, h2, "world") testUtilRelease(hm, t, h1, "hello") h3 := testUtilAlloc(hm, t, "gensoukyo") testUtilGet(hm, t, h3, "gensoukyo") testUtilRelease(hm, t, h2, "world") testUtilRelease(hm, t, h3, "gensoukyo") h4 := testUtilAlloc(hm, t, "satori") h5 := testUtilAlloc(hm, t, "koishi") h6 := testUtilAlloc(hm, t, "cirno") testUtilGet(hm, t, h4, "satori") testUtilGet(hm, t, h5, "koishi") testUtilGet(hm, t, h6, "cirno") } func TestFunc2(t *testing.T) { hm := NewWithRange[string](0, 32) var i int32 for i = 0; i < 31; i++ { testUtilAlloc(hm, t, fmt.Sprintf("val-%d", i)) } for i = 0; i < 31; i++ { testUtilGet(hm, t, i+1, fmt.Sprintf("val-%d", i)) } testUtilAllocOverflow(hm, t, "val-32") testUtilRelease(hm, t, 15, "val-14") hr := testUtilAlloc(hm, t, "val-xr-14") if hr != 15 { t.Fatalf("allocate behavior mismatch: expected 15, got %d", hr) } testUtilGet(hm, t, hr, "val-xr-14") } func TestFunc3(t *testing.T) { tryCount := 65536 hm := New[string]() tlist := make([]struct { h int32 v string }, 0, tryCount) t.Log("==== Do Random Alloc and Release ====") for i := 0; i < tryCount; i++ { ri := rand.Int31() rk := rand.Intn(10) if rk == 0 && len(tlist) > 0 { sel := rand.Intn(len(tlist)) testUtilReleaseSilent(hm, t, tlist[sel].h, tlist[sel].v) tlist = append(tlist[:sel], tlist[sel+1:]...) } else { v := fmt.Sprintf("val-test-%d", ri) h := testUtilAllocSilent(hm, t, v) tlist = append(tlist, struct { h int32 v string }{h: h, v: v}) } } t.Log("==== Do Verification ====") for i := 0; i < len(tlist); i++ { testUtilGetSilent(hm, t, tlist[i].h, tlist[i].v) } } func TestFunc4(t *testing.T) { eachRoutineTryCount := 65536 routineCount := runtime.NumCPU() hm := New[string]() wg := sync.WaitGroup{} wg.Add(routineCount) t.Logf("routineCount: %d", routineCount) t.Log("==== Do Parallel Random Alloc and Release Test ====") for i := 0; i < routineCount; i++ { go func() { testUtilDoRandom(hm, eachRoutineTryCount) wg.Done() }() } wg.Wait() t.Log("==== Done ====") } func BenchmarkAlloc(b *testing.B) { hm := New[string]() b.ResetTimer() b.RunParallel(func(pb *testing.PB) { for pb.Next() { _, _ = hm.AllocateAndPut("hello") } }) } func BenchmarkGet(b *testing.B) { maxCount := 65536 hm := New[string]() for i := 0; i < maxCount; i++ { _, _ = hm.AllocateAndPut(fmt.Sprintf("val-%d", i)) } b.ResetTimer() b.RunParallel(func(pb *testing.PB) { for pb.Next() { _, _ = hm.Get(int32(rand.Intn(maxCount))) } }) } func BenchmarkComprehensive(b *testing.B) { hm := New[string]() b.ResetTimer() b.RunParallel(func(pb *testing.PB) { for pb.Next() { op := rand.Intn(3) switch op { case 0: _, _ = hm.AllocateAndPut("hello") case 1: if hm.Count() <= 0 { _, _ = hm.AllocateAndPut("hello") } else { _, _ = hm.Get(int32(rand.Intn(hm.Count()))) } case 2: if hm.Count() <= 0 { _, _ = hm.AllocateAndPut("hello") } else { hm.ReleaseSilently(int32(rand.Intn(hm.Count()))) } } } }) } func testUtilDoRandom(hm *HandleManager[string], tryCount int) { tlist := make([]struct { h int32 v string }, 0, tryCount) for i := 0; i < tryCount; i++ { ri := rand.Int31() rk := rand.Intn(10) if rk == 0 && len(tlist) > 0 { sel := rand.Intn(len(tlist)) h := tlist[sel].h v := tlist[sel].v releasedVal, ok := hm.Release(h) if !ok { panic(fmt.Errorf("failed to release handle %d: not found", h)) } if releasedVal != v { panic(fmt.Errorf("release handle %d result mismatched: expected %s, got %s", h, v, releasedVal)) } tlist = append(tlist[:sel], tlist[sel+1:]...) } else { v := fmt.Sprintf("val-test-%d", ri) h, err := hm.AllocateAndPut(v) if err != nil { panic(fmt.Errorf("failed to allocate handle: %v", err)) } tlist = append(tlist, struct { h int32 v string }{h: h, v: v}) } } for i := 0; i < len(tlist); i++ { h := tlist[i].h v := tlist[i].v vr, ok := hm.Get(h) if !ok { panic(fmt.Errorf("failed to get handle %d: not found", h)) return } if vr != v { panic(fmt.Errorf("get handle %d result mismatched: expected %s, got %s", h, v, vr)) return } } } func testUtilAlloc(hm *HandleManager[string], t *testing.T, val string) int32 { h, err := hm.AllocateAndPut(val) if err != nil { t.Fatalf("failed to allocate handle: %v", err) return 0 } t.Logf("allocated handle %d", h) return h } func testUtilAllocSilent(hm *HandleManager[string], t *testing.T, val string) int32 { h, err := hm.AllocateAndPut(val) if err != nil { t.Fatalf("failed to allocate handle: %v", err) return 0 } return h } func testUtilAllocOverflow(hm *HandleManager[string], t *testing.T, val string) { _, err := hm.AllocateAndPut(val) if err == ErrHandleExceedMax { t.Log("allocated a overflowed handle got expected error") return } else { t.Fatalf("allocated a overflowed handle got unexpected error: %v", err) return } } func testUtilGet(hm *HandleManager[string], t *testing.T, h int32, expected string) { v, ok := hm.Get(h) if !ok { t.Fatalf("failed to get handle %d: not found", h) return } if v != expected { t.Fatalf("get handle %d result mismatched: expected %s, got %s", h, expected, v) return } t.Logf("get handle %d: %v", h, v) } func testUtilGetSilent(hm *HandleManager[string], t *testing.T, h int32, expected string) { v, ok := hm.Get(h) if !ok { t.Fatalf("failed to get handle %d: not found", h) return } if v != expected { t.Fatalf("get handle %d result mismatched: expected %s, got %s", h, expected, v) return } } func testUtilRelease(hm *HandleManager[string], t *testing.T, h int32, expected string) { releasedVal, ok := hm.Release(h) if !ok { t.Fatalf("failed to release handle %d: not found", h) return } if releasedVal != expected { t.Fatalf("release handle %d result mismatched: expected %s, got %s", h, expected, releasedVal) return } t.Logf("release handle %d ok", h) } func testUtilReleaseSilent(hm *HandleManager[string], t *testing.T, h int32, expected string) { releasedVal, ok := hm.Release(h) if !ok { t.Fatalf("failed to release handle %d: not found", h) return } if releasedVal != expected { t.Fatalf("release handle %d result mismatched: expected %s, got %s", h, expected, releasedVal) return } }