package priorityq_test import ( "math/rand" "sync" "testing" "gogs.humancabbage.net/sam/priorityq" ) func TestRecvHighestFirst(t *testing.T) { 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) checkRecv := func(n int) { if _, v, _ := q.Recv(); v != n { t.Errorf("popped %d, expected %d", v, n) } } checkRecv(8) checkRecv(7) checkRecv(6) checkRecv(5) checkRecv(4) checkRecv(3) checkRecv(2) checkRecv(1) } 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) q.Close() q.Send(1, 1) } func TestRecvClosed(t *testing.T) { t.Parallel() q := priorityq.Make[int, int](4) q.Send(1, 1) q.Close() _, _, ok := q.Recv() if !ok { t.Errorf("queue should have item to receive") } _, _, ok = q.Recv() 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) if !ok { t.Errorf("expected to be able to send") } } assumeRecvOk := func(expected int) { _, actual, ok := q.TryRecv() 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) if ok { t.Errorf("expected queue to be full") } assumeRecvOk(4) assumeRecvOk(3) assumeRecvOk(2) assumeRecvOk(1) _, _, ok = q.TryRecv() if ok { t.Errorf("expected queue to be empty") } } func TestConcProducerConsumer(t *testing.T) { t.Parallel() q := priorityq.Make[int, int](4) var wg sync.WaitGroup produceDone := make(chan struct{}) wg.Add(2) go func() { for i := 0; i < 10000; i++ { q.Send(rand.Int(), i) } close(produceDone) wg.Done() }() go func() { ok := true for ok { _, _, ok = q.Recv() } 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) for i := 0; i < b.N; i++ { ps[i] = rand.Int() } b.ResetTimer() for i := 0; i < b.N; i++ { q.Send(ps[i], i) } } func BenchmarkRecv(b *testing.B) { q := priorityq.Make[int, int](b.N) // randomize priorities to get amortized cost per op for i := 0; i < b.N; i++ { q.Send(rand.Int(), i) } 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) for i := 0; i < b.N; i++ { ps[i] = rand.Int() } 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) } wg.Done() }() go func() { <-start for i := 0; i < b.N; i++ { q.Recv() } wg.Done() }() b.ResetTimer() close(start) wg.Wait() }