priorityq/lib_test.go

180 lines
3.1 KiB
Go
Raw Normal View History

package priorityq_test
2023-03-01 04:33:22 +00:00
import (
"math/rand"
"sync"
"testing"
"gogs.humancabbage.net/sam/priorityq"
2023-03-01 04:33:22 +00:00
)
func TestRecvHighestFirst(t *testing.T) {
2023-03-01 04:33:22 +00:00
t.Parallel()
q := priorityq.Make[int, int](8)
q.Send(4, 4)
q.Send(2, 2)
q.Send(1, 1)
q.Send(5, 5)
q.Send(7, 7)
q.Send(8, 8)
q.Send(3, 3)
q.Send(6, 6)
2023-03-01 04:33:22 +00:00
checkRecv := func(n int) {
if _, v, _ := q.Recv(); v != n {
2023-03-01 04:33:22 +00:00
t.Errorf("popped %d, expected %d", v, n)
}
}
checkRecv(8)
checkRecv(7)
checkRecv(6)
checkRecv(5)
2023-03-01 04:33:22 +00:00
checkRecv(4)
checkRecv(3)
checkRecv(2)
checkRecv(1)
2023-03-01 04:33:22 +00:00
}
func TestSendClosedPanic(t *testing.T) {
t.Parallel()
defer func() {
if r := recover(); r == nil {
t.Errorf("sending to closed queue did not panic")
}
}()
q := priorityq.Make[int, int](4)
2023-03-01 04:33:22 +00:00
q.Close()
q.Send(1, 1)
2023-03-01 04:33:22 +00:00
}
func TestRecvClosed(t *testing.T) {
t.Parallel()
q := priorityq.Make[int, int](4)
q.Send(1, 1)
2023-03-01 04:33:22 +00:00
q.Close()
_, _, ok := q.Recv()
2023-03-01 04:33:22 +00:00
if !ok {
t.Errorf("queue should have item to receive")
}
_, _, ok = q.Recv()
2023-03-01 04:33:22 +00:00
if ok {
t.Errorf("queue should be closed")
}
}
func TestTrySendRecv(t *testing.T) {
t.Parallel()
q := priorityq.Make[int, int](4)
assumeSendOk := func(n int) {
ok := q.TrySend(n, n)
2023-03-01 04:33:22 +00:00
if !ok {
t.Errorf("expected to be able to send")
}
}
assumeRecvOk := func(expected int) {
_, actual, ok := q.TryRecv()
2023-03-01 04:33:22 +00:00
if !ok {
t.Errorf("expected to be able to receive")
}
if actual != expected {
t.Errorf("expected %d, got %d", expected, actual)
}
}
assumeSendOk(1)
assumeSendOk(2)
assumeSendOk(3)
assumeSendOk(4)
ok := q.TrySend(5, 5)
2023-03-01 04:33:22 +00:00
if ok {
t.Errorf("expected queue to be full")
2023-03-01 04:33:22 +00:00
}
assumeRecvOk(4)
assumeRecvOk(3)
assumeRecvOk(2)
assumeRecvOk(1)
2023-03-01 04:33:22 +00:00
_, _, ok = q.TryRecv()
2023-03-01 04:33:22 +00:00
if ok {
t.Errorf("expected queue to be empty")
}
}
func TestConcProducerConsumer(t *testing.T) {
t.Parallel()
q := priorityq.Make[int, int](4)
2023-03-01 04:33:22 +00:00
var wg sync.WaitGroup
produceDone := make(chan struct{})
wg.Add(2)
go func() {
for i := 0; i < 10000; i++ {
q.Send(rand.Int(), i)
2023-03-01 04:33:22 +00:00
}
close(produceDone)
wg.Done()
}()
go func() {
ok := true
for ok {
_, _, ok = q.Recv()
2023-03-01 04:33:22 +00:00
}
wg.Done()
}()
<-produceDone
t.Logf("producer done, closing channel")
q.Close()
wg.Wait()
}
func BenchmarkSend(b *testing.B) {
q := priorityq.Make[int, int](b.N)
// randomize priorities to get amortized cost per op
ps := make([]int, b.N)
2023-03-01 04:33:22 +00:00
for i := 0; i < b.N; i++ {
ps[i] = rand.Int()
2023-03-01 04:33:22 +00:00
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
q.Send(ps[i], i)
2023-03-01 04:33:22 +00:00
}
}
func BenchmarkRecv(b *testing.B) {
q := priorityq.Make[int, int](b.N)
// randomize priorities to get amortized cost per op
2023-03-01 04:33:22 +00:00
for i := 0; i < b.N; i++ {
q.Send(rand.Int(), i)
2023-03-01 04:33:22 +00:00
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
q.Recv()
}
}
func BenchmarkConcSendRecv(b *testing.B) {
q := priorityq.Make[int, int](b.N)
// randomize priorities to get amortized cost per op
ps := make([]int, b.N)
2023-03-01 04:33:22 +00:00
for i := 0; i < b.N; i++ {
ps[i] = rand.Int()
2023-03-01 04:33:22 +00:00
}
var wg sync.WaitGroup
wg.Add(2)
start := make(chan struct{})
go func() {
<-start
for i := 0; i < b.N; i++ {
q.Send(ps[i], i)
2023-03-01 04:33:22 +00:00
}
wg.Done()
}()
go func() {
<-start
for i := 0; i < b.N; i++ {
q.Recv()
}
wg.Done()
}()
b.ResetTimer()
close(start)
wg.Wait()
}