|
@@ -0,0 +1,270 @@
|
|
|
+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
|
|
|
+ }
|
|
|
+}
|