shinway / internal /ringbuffer /ringbuffer_test.go
sshinmen's picture
Configure for HF Spaces: port 7860, cloud deploy mode, PORT env support
5e6ff88
Raw
History Blame Contribute Delete
4.16 kB
package ringbuffer
import (
"sync"
"testing"
)
func TestRingBufferBasic(t *testing.T) {
rb := New[int](16)
// Test Push and Pop
if !rb.Push(42) {
t.Fatal("Push failed")
}
val, ok := rb.Pop()
if !ok {
t.Fatal("Pop failed")
}
if val != 42 {
t.Errorf("Expected 42, got %d", val)
}
}
func TestRingBufferFillAndEmpty(t *testing.T) {
rb := New[int](4)
// Fill the buffer
for i := 0; i < 4; i++ {
if !rb.Push(i) {
t.Fatalf("Push failed at index %d", i)
}
}
// Buffer should be full
if !rb.IsFull() {
t.Error("Buffer should be full")
}
// Push should fail
if rb.Push(99) {
t.Error("Push should fail on full buffer")
}
// Empty the buffer
for i := 0; i < 4; i++ {
val, ok := rb.Pop()
if !ok {
t.Fatalf("Pop failed at index %d", i)
}
if val != i {
t.Errorf("Expected %d, got %d", i, val)
}
}
// Buffer should be empty
if !rb.IsEmpty() {
t.Error("Buffer should be empty")
}
}
func TestRingBufferLen(t *testing.T) {
rb := New[int](8)
if rb.Len() != 0 {
t.Errorf("New buffer should have len 0, got %d", rb.Len())
}
rb.Push(1)
rb.Push(2)
if rb.Len() != 2 {
t.Errorf("Expected len 2, got %d", rb.Len())
}
rb.Pop()
if rb.Len() != 1 {
t.Errorf("Expected len 1 after pop, got %d", rb.Len())
}
}
func TestRingBufferReset(t *testing.T) {
rb := New[int](8)
for i := 0; i < 5; i++ {
rb.Push(i)
}
rb.Reset()
if !rb.IsEmpty() {
t.Error("Buffer should be empty after reset")
}
// Should be able to push again
if !rb.Push(100) {
t.Error("Push should work after reset")
}
}
func TestRingBufferString(t *testing.T) {
rb := New[string](4)
rb.Push("hello")
rb.Push("world")
val, ok := rb.Pop()
if !ok || val != "hello" {
t.Errorf("Expected 'hello', got '%s'", val)
}
val, ok = rb.Pop()
if !ok || val != "world" {
t.Errorf("Expected 'world', got '%s'", val)
}
}
func TestMPMCQueueBasic(t *testing.T) {
q := NewMPMC[int](16)
if !q.Enqueue(42) {
t.Fatal("Enqueue failed")
}
val, ok := q.Dequeue()
if !ok {
t.Fatal("Dequeue failed")
}
if val != 42 {
t.Errorf("Expected 42, got %d", val)
}
}
func TestMPMCQueueConcurrent(t *testing.T) {
q := NewMPMC[int](1024)
const numProducers = 4
const numConsumers = 4
const itemsPerProducer = 1000
var wg sync.WaitGroup
// Start consumers
results := make(chan int, numProducers*itemsPerProducer)
for i := 0; i < numConsumers; i++ {
wg.Add(1)
go func() {
defer wg.Done()
for {
val, ok := q.Dequeue()
if !ok {
// Check if producers are done
if q.Len() == 0 {
return
}
continue
}
results <- val
}
}()
}
// Start producers
for i := 0; i < numProducers; i++ {
wg.Add(1)
go func(id int) {
defer wg.Done()
for j := 0; j < itemsPerProducer; j++ {
item := id*itemsPerProducer + j
for !q.Enqueue(item) {
// Retry if full
}
}
}(i)
}
// Wait for producers
wg.Wait()
// Give consumers time to finish
close(results)
// Count results
count := 0
for range results {
count++
}
expected := numProducers * itemsPerProducer
if count != expected {
t.Errorf("Expected %d items, got %d", expected, count)
}
}
func TestRoundUpPowerOf2(t *testing.T) {
tests := []struct {
input int
expected int
}{
{0, 1},
{1, 1},
{2, 2},
{3, 4},
{4, 4},
{5, 8},
{7, 8},
{8, 8},
{9, 16},
{100, 128},
{1023, 1024},
{1024, 1024},
}
for _, tt := range tests {
result := roundUpPowerOf2(tt.input)
if result != tt.expected {
t.Errorf("roundUpPowerOf2(%d) = %d, expected %d", tt.input, result, tt.expected)
}
}
}
func BenchmarkRingBufferPushPop(b *testing.B) {
rb := New[int](1024)
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
rb.Push(i)
rb.Pop()
}
}
func BenchmarkMPMCQueueEnqueueDequeue(b *testing.B) {
q := NewMPMC[int](1024)
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
q.Enqueue(i)
q.Dequeue()
}
}
func BenchmarkRingBufferConcurrent(b *testing.B) {
rb := New[int](1024)
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
i := 0
for pb.Next() {
if i%2 == 0 {
rb.Push(i)
} else {
rb.Pop()
}
i++
}
})
}