test: 完善 hub.ObjectPool 测试用例

This commit is contained in:
kercylan98 2024-01-12 12:51:49 +08:00
parent 161fbfe4e3
commit c439ef6424
3 changed files with 118 additions and 8 deletions

View File

@ -1,16 +1,14 @@
package hub
import (
"errors"
"fmt"
"sync"
)
// NewObjectPool 创建一个线程安全的对象缓冲池
// - 通过 Get 获取一个对象,如果缓冲区内存在可用对象则直接返回,否则新建一个进行返回
// - 通过 Release 将使用完成的对象放回缓冲区,超出缓冲区大小的对象将被放弃
// NewObjectPool 创建一个 ObjectPool
func NewObjectPool[T any](generator func() *T, releaser func(data *T)) *ObjectPool[*T] {
if generator == nil || releaser == nil {
panic(errors.New("generator or releaser is nil"))
panic(fmt.Errorf("generator and releaser can not be nil, generator check: %v, releaser check: %v", generator != nil, releaser != nil))
}
return &ObjectPool[*T]{
releaser: releaser,
@ -22,10 +20,8 @@ func NewObjectPool[T any](generator func() *T, releaser func(data *T)) *ObjectPo
}
}
// ObjectPool 线程安全的对象缓冲
// ObjectPool 基于 sync.Pool 实现的线程安全的对象池
// - 一些高频临时生成使用的对象可以通过 ObjectPool 进行管理,例如属性计算等
// - 缓冲区内存在可用对象时直接返回,否则新建一个进行返回
// - 通过 Release 将使用完成的对象放回缓冲区,超出缓冲区大小的对象将被放弃
type ObjectPool[T any] struct {
p sync.Pool
releaser func(data T)

View File

@ -0,0 +1,22 @@
package hub_test
import (
"fmt"
"github.com/kercylan98/minotaur/utils/collection"
"github.com/kercylan98/minotaur/utils/hub"
)
func ExampleNewObjectPool() {
var p = hub.NewObjectPool[map[int]int](func() *map[int]int {
return &map[int]int{}
}, func(data *map[int]int) {
collection.ClearMap(*data)
})
m := *p.Get()
m[1] = 1
p.Release(&m)
fmt.Println(m)
// Output:
// map[]
}

View File

@ -1 +1,93 @@
package hub_test
import (
"github.com/kercylan98/minotaur/utils/hub"
"testing"
)
func TestNewObjectPool(t *testing.T) {
var cases = []struct {
name string
generator func() *map[string]int
releaser func(data *map[string]int)
shouldPanic bool
}{
{name: "TestNewObjectPool_NilGenerator", generator: nil, releaser: func(data *map[string]int) {}, shouldPanic: true},
{name: "TestNewObjectPool_NilReleaser", generator: func() *map[string]int { return &map[string]int{} }, releaser: nil, shouldPanic: true},
{name: "TestNewObjectPool_NilGeneratorAndReleaser", generator: nil, releaser: nil, shouldPanic: true},
{name: "TestNewObjectPool_Normal", generator: func() *map[string]int { return &map[string]int{} }, releaser: func(data *map[string]int) {}, shouldPanic: false},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
defer func() {
if err := recover(); c.shouldPanic && err == nil {
t.Error("TestNewObjectPool should panic")
}
}()
_ = hub.NewObjectPool[map[string]int](c.generator, c.releaser)
})
}
}
func TestObjectPool_Get(t *testing.T) {
var cases = []struct {
name string
generator func() *map[string]int
releaser func(data *map[string]int)
}{
{
name: "TestObjectPool_Get_Normal",
generator: func() *map[string]int {
return &map[string]int{}
},
releaser: func(data *map[string]int) {
for k := range *data {
delete(*data, k)
}
},
},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
pool := hub.NewObjectPool[map[string]int](c.generator, c.releaser)
if actual := pool.Get(); len(*actual) != 0 {
t.Error("TestObjectPool_Get failed")
}
})
}
}
func TestObjectPool_Release(t *testing.T) {
var cases = []struct {
name string
generator func() *map[string]int
releaser func(data *map[string]int)
}{
{
name: "TestObjectPool_Release_Normal",
generator: func() *map[string]int {
return &map[string]int{}
},
releaser: func(data *map[string]int) {
for k := range *data {
delete(*data, k)
}
},
},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
pool := hub.NewObjectPool[map[string]int](c.generator, c.releaser)
msg := pool.Get()
m := *msg
m["test"] = 1
pool.Release(msg)
if len(m) != 0 {
t.Error("TestObjectPool_Release failed")
}
})
}
}