mirror of
https://github.com/zeromicro/go-zero.git
synced 2026-08-01 21:37:40 +08:00
269 lines
4.9 KiB
Go
269 lines
4.9 KiB
Go
package collection
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
func TestQueueOrder(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
size int
|
|
initial []int
|
|
takeBefore int
|
|
additional []int
|
|
wantCapacity int
|
|
}{
|
|
{
|
|
name: "within initial capacity",
|
|
size: 8,
|
|
initial: []int{1, 2, 3},
|
|
wantCapacity: 8,
|
|
},
|
|
{
|
|
name: "grow from beginning",
|
|
size: 2,
|
|
initial: []int{1, 2, 3},
|
|
wantCapacity: 4,
|
|
},
|
|
{
|
|
name: "grow after wrapping",
|
|
size: 4,
|
|
initial: []int{1, 2, 3, 4},
|
|
takeBefore: 1,
|
|
additional: []int{5, 6},
|
|
wantCapacity: 8,
|
|
},
|
|
{
|
|
name: "grow repeatedly",
|
|
size: 1,
|
|
initial: sequence(20),
|
|
wantCapacity: 32,
|
|
},
|
|
{
|
|
name: "grow above threshold",
|
|
size: queueGrowThreshold,
|
|
initial: sequence(queueGrowThreshold + 1),
|
|
wantCapacity: queueGrowThreshold * 2,
|
|
},
|
|
{
|
|
name: "grow well above threshold",
|
|
size: 1024,
|
|
initial: sequence(1025),
|
|
wantCapacity: 1472,
|
|
},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
t.Run(test.name, func(t *testing.T) {
|
|
queue := NewQueue(test.size)
|
|
assert.True(t, queue.Empty())
|
|
|
|
for _, value := range test.initial {
|
|
queue.Put(value)
|
|
}
|
|
for i := 0; i < test.takeBefore; i++ {
|
|
value, ok := queue.Take()
|
|
assert.True(t, ok)
|
|
assert.Equal(t, test.initial[i], value)
|
|
}
|
|
for _, value := range test.additional {
|
|
queue.Put(value)
|
|
}
|
|
|
|
want := append([]int(nil), test.initial[test.takeBefore:]...)
|
|
want = append(want, test.additional...)
|
|
for _, expected := range want {
|
|
actual, ok := queue.Take()
|
|
assert.True(t, ok)
|
|
assert.Equal(t, expected, actual)
|
|
}
|
|
|
|
assert.Equal(t, test.wantCapacity, len(queue.elements))
|
|
assert.True(t, queue.Empty())
|
|
_, ok := queue.Take()
|
|
assert.False(t, ok)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestQueueTakeClearsElement(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
size int
|
|
operations string
|
|
}{
|
|
{
|
|
name: "take from beginning",
|
|
size: 2,
|
|
operations: "ppt",
|
|
},
|
|
{
|
|
name: "take after wrapping",
|
|
size: 2,
|
|
operations: "pptptt",
|
|
},
|
|
{
|
|
name: "take after growing",
|
|
size: 2,
|
|
operations: "pppt",
|
|
},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
t.Run(test.name, func(t *testing.T) {
|
|
queue := NewQueue(test.size)
|
|
value := 0
|
|
|
|
for _, operation := range test.operations {
|
|
switch operation {
|
|
case 'p':
|
|
value++
|
|
element := new(int)
|
|
*element = value
|
|
queue.Put(element)
|
|
case 't':
|
|
index := queue.head
|
|
_, ok := queue.Take()
|
|
assert.True(t, ok)
|
|
assert.Nil(t, queue.elements[index])
|
|
default:
|
|
t.Fatalf("unknown operation: %q", operation)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestNewQueueWithInvalidSize(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
size int
|
|
}{
|
|
{
|
|
name: "zero",
|
|
},
|
|
{
|
|
name: "negative",
|
|
size: -1,
|
|
},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
t.Run(test.name, func(t *testing.T) {
|
|
assert.Panics(t, func() {
|
|
NewQueue(test.size)
|
|
})
|
|
})
|
|
}
|
|
}
|
|
|
|
func BenchmarkQueueGrowth(b *testing.B) {
|
|
tests := []struct {
|
|
name string
|
|
size int
|
|
count int
|
|
}{
|
|
{
|
|
name: "initial_1_count_256",
|
|
size: 1,
|
|
count: 256,
|
|
},
|
|
{
|
|
name: "initial_1_count_4096",
|
|
size: 1,
|
|
count: 4096,
|
|
},
|
|
{
|
|
name: "initial_1_count_65536",
|
|
size: 1,
|
|
count: 65536,
|
|
},
|
|
{
|
|
name: "initial_8_count_4096",
|
|
size: 8,
|
|
count: 4096,
|
|
},
|
|
{
|
|
name: "initial_256_count_4096",
|
|
size: 256,
|
|
count: 4096,
|
|
},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
b.Run(test.name, func(b *testing.B) {
|
|
elements := make([]any, test.count)
|
|
for i := range elements {
|
|
elements[i] = i
|
|
}
|
|
|
|
b.ReportAllocs()
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
queue := NewQueue(test.size)
|
|
for _, element := range elements {
|
|
queue.Put(element)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func BenchmarkQueueWrappedGrowth(b *testing.B) {
|
|
tests := []struct {
|
|
name string
|
|
size int
|
|
}{
|
|
{
|
|
name: "capacity_8",
|
|
size: 8,
|
|
},
|
|
{
|
|
name: "capacity_256",
|
|
size: 256,
|
|
},
|
|
{
|
|
name: "capacity_4096",
|
|
size: 4096,
|
|
},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
b.Run(test.name, func(b *testing.B) {
|
|
elements := make([]any, test.size)
|
|
for i := range elements {
|
|
elements[i] = i
|
|
}
|
|
|
|
b.ReportAllocs()
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
queue := NewQueue(test.size)
|
|
for _, element := range elements {
|
|
queue.Put(element)
|
|
}
|
|
for j := 0; j < test.size/2; j++ {
|
|
queue.Take()
|
|
}
|
|
for j := 0; j < test.size/2; j++ {
|
|
queue.Put(elements[j])
|
|
}
|
|
|
|
// The queue is full and wrapped. One more Put triggers growth
|
|
// and copies both sides of the ring into FIFO order.
|
|
queue.Put(elements[0])
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func sequence(size int) []int {
|
|
values := make([]int, size)
|
|
for i := range values {
|
|
values[i] = i
|
|
}
|
|
return values
|
|
}
|