package utils import ( "sync" "testing" ) func TestNew(t *testing.T) { q := New[int](5) if q.capacity != 5 { t.Errorf("expected capacity 5, got %d", q.capacity) } if q.Len() != 0 { t.Errorf("expected empty queue, got len %d", q.Len()) } } func TestPushPop(t *testing.T) { q := New[int](3) q.Push(1) q.Push(2) q.Push(3) if q.Len() != 3 { t.Errorf("expected len 3, got %d", q.Len()) } val, ok := q.Pop() if !ok || val != 1 { t.Errorf("expected (1, true), got (%d, %v)", val, ok) } val, ok = q.Pop() if !ok || val != 2 { t.Errorf("expected (2, true), got (%d, %v)", val, ok) } val, ok = q.Pop() if !ok || val != 3 { t.Errorf("expected (3, true), got (%d, %v)", val, ok) } val, ok = q.Pop() if ok { t.Errorf("expected (_, false), got (%d, %v)", val, ok) } } func TestPushDropsOldest(t *testing.T) { q := New[int](3) q.Push(1) q.Push(2) q.Push(3) q.Push(4) // should drop 1 if q.Len() != 3 { t.Errorf("expected len 3, got %d", q.Len()) } val, ok := q.Pop() if !ok || val != 2 { t.Errorf("expected (2, true), got (%d, %v)", val, ok) } val, ok = q.Pop() if !ok || val != 3 { t.Errorf("expected (3, true), got (%d, %v)", val, ok) } val, ok = q.Pop() if !ok || val != 4 { t.Errorf("expected (4, true), got (%d, %v)", val, ok) } } func TestPeek(t *testing.T) { q := New[string](2) _, ok := q.Peek() if ok { t.Error("expected Peek on empty queue to return false") } q.Push("a") q.Push("b") val, ok := q.Peek() if !ok || val != "a" { t.Errorf("expected (a, true), got (%s, %v)", val, ok) } // Peek should not remove if q.Len() != 2 { t.Errorf("Peek should not modify queue, len is %d", q.Len()) } } func TestIsEmpty(t *testing.T) { q := New[int](2) if !q.IsEmpty() { t.Error("new queue should be empty") } q.Push(1) if q.IsEmpty() { t.Error("queue with item should not be empty") } q.Pop() if !q.IsEmpty() { t.Error("queue after pop should be empty") } } func TestConcurrentAccess(t *testing.T) { q := New[int](100) var wg sync.WaitGroup // Concurrent pushes for i := 0; i < 10; i++ { wg.Add(1) go func(n int) { defer wg.Done() for j := 0; j < 20; j++ { q.Push(n*20 + j) } }(i) } // Concurrent pops for i := 0; i < 5; i++ { wg.Add(1) go func() { defer wg.Done() for j := 0; j < 10; j++ { q.Pop() } }() } wg.Wait() // Should not panic and queue should be in valid state _ = q.Len() _ = q.IsEmpty() } func TestCapacityOne(t *testing.T) { q := New[int](1) q.Push(1) q.Push(2) // drops 1 if q.Len() != 1 { t.Errorf("expected len 1, got %d", q.Len()) } val, ok := q.Pop() if !ok || val != 2 { t.Errorf("expected (2, true), got (%d, %v)", val, ok) } } func TestNewNonPositiveCapacityUsesMinimum(t *testing.T) { tests := []struct { name string capacity int wantCapacity int }{ {name: "zero", capacity: 0, wantCapacity: 1}, {name: "negative", capacity: -5, wantCapacity: 1}, } for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { q := New[int](tc.capacity) if q.capacity != tc.wantCapacity { t.Fatalf("expected capacity %d, got %d", tc.wantCapacity, q.capacity) } q.Push(42) if got := q.Len(); got != 1 { t.Fatalf("expected len 1 after push, got %d", got) } val, ok := q.Pop() if !ok || val != 42 { t.Fatalf("expected (42, true), got (%d, %v)", val, ok) } }) } } func TestPushNormalizesInvalidCapacityState(t *testing.T) { q := &Queue[int]{capacity: 0} q.Push(1) q.Push(2) if q.Len() != 0 { t.Errorf("expected len 0, got %d", q.Len()) } if _, ok := q.Pop(); ok { t.Error("expected pop on zero-capacity queue to return false") } } func TestItems(t *testing.T) { q := New[int](5) q.Push(10) q.Push(20) q.Push(30) items := q.Items() if len(items) != 3 { t.Fatalf("expected 3 items, got %d", len(items)) } if items[0] != 10 || items[1] != 20 || items[2] != 30 { t.Fatalf("unexpected items: %v", items) } // Verify Items returns a copy (doesn't drain the queue) if q.Len() != 3 { t.Fatalf("Items should not drain the queue, len=%d", q.Len()) } } func TestItems_Empty(t *testing.T) { q := New[int](5) items := q.Items() if items != nil { t.Fatalf("expected nil for empty queue, got %v", items) } }