package main import ( "slices" "testing" ) func TestNewRingBuffer(t *testing.T) { tests := []struct { name string capacity int }{ {"small buffer", 5}, {"standard buffer", 120}, {"single element", 1}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { rb := NewRingBuffer(tt.capacity) if rb == nil { t.Fatal("NewRingBuffer returned nil") } if rb.cap != tt.capacity { t.Errorf("NewRingBuffer(%d).cap = %d, want %d", tt.capacity, rb.cap, tt.capacity) } if rb.size != 0 { t.Errorf("NewRingBuffer(%d).size = %d, want 0", tt.capacity, rb.size) } if rb.index != 0 { t.Errorf("NewRingBuffer(%d).index = %d, want 0", tt.capacity, rb.index) } if len(rb.data) != tt.capacity { t.Errorf("len(NewRingBuffer(%d).data) = %d, want %d", tt.capacity, len(rb.data), tt.capacity) } }) } } func TestRingBuffer_EmptyBuffer(t *testing.T) { rb := NewRingBuffer(5) got := rb.Slice() if got != nil { t.Errorf("Slice() on empty buffer = %v, want nil", got) } } func TestRingBuffer_AddWithinCapacity(t *testing.T) { rb := NewRingBuffer(5) // Add 3 elements (less than capacity) rb.Add(1.0) rb.Add(2.0) rb.Add(3.0) if rb.size != 3 { t.Errorf("size after 3 adds = %d, want 3", rb.size) } got := rb.Slice() want := []float64{1.0, 2.0, 3.0} if !slices.Equal(got, want) { t.Errorf("Slice() = %v, want %v", got, want) } } func TestRingBuffer_ExactCapacity(t *testing.T) { rb := NewRingBuffer(5) // Fill exactly to capacity for i := 1; i <= 5; i++ { rb.Add(float64(i)) } if rb.size != 5 { t.Errorf("size after filling to capacity = %d, want 5", rb.size) } got := rb.Slice() want := []float64{1.0, 2.0, 3.0, 4.0, 5.0} if !slices.Equal(got, want) { t.Errorf("Slice() = %v, want %v", got, want) } } func TestRingBuffer_WrapAround(t *testing.T) { rb := NewRingBuffer(5) // Add 7 elements to trigger wrap-around (2 past capacity) // Internal state after: data=[6, 7, 3, 4, 5], index=2, size=5 // Oldest element is at index 2 (value 3) for i := 1; i <= 7; i++ { rb.Add(float64(i)) } if rb.size != 5 { t.Errorf("size after wrap-around = %d, want 5", rb.size) } // Verify index points to oldest element position if rb.index != 2 { t.Errorf("index after adding 7 elements to cap-5 buffer = %d, want 2", rb.index) } got := rb.Slice() // Should return chronological order: oldest (3) to newest (7) want := []float64{3.0, 4.0, 5.0, 6.0, 7.0} if !slices.Equal(got, want) { t.Errorf("Slice() = %v, want %v", got, want) } } func TestRingBuffer_MultipleWrapArounds(t *testing.T) { rb := NewRingBuffer(3) // Add 10 elements (wraps multiple times) for i := 1; i <= 10; i++ { rb.Add(float64(i)) } got := rb.Slice() // Should have the last 3 values: 8, 9, 10 want := []float64{8.0, 9.0, 10.0} if !slices.Equal(got, want) { t.Errorf("Slice() after 10 adds to cap-3 buffer = %v, want %v", got, want) } } func TestRingBuffer_SingleElementBuffer(t *testing.T) { rb := NewRingBuffer(1) rb.Add(5.0) if got := rb.Slice(); !slices.Equal(got, []float64{5.0}) { t.Errorf("Slice() = %v, want [5.0]", got) } // Overwrite the single element rb.Add(10.0) if got := rb.Slice(); !slices.Equal(got, []float64{10.0}) { t.Errorf("Slice() after overwrite = %v, want [10.0]", got) } } func TestRingBuffer_SliceReturnsNewSlice(t *testing.T) { rb := NewRingBuffer(3) rb.Add(1.0) rb.Add(2.0) slice1 := rb.Slice() slice2 := rb.Slice() // Modify slice1 and verify slice2 is unaffected // This ensures Slice() returns a copy, not a reference to internal data slice1[0] = 999.0 if slice2[0] == 999.0 { t.Error("Slice() should return a new copy, not a reference to internal data") } } func TestRingBuffer_NegativeAndZeroValues(t *testing.T) { rb := NewRingBuffer(4) // Test that negative and zero values are handled correctly rb.Add(-5.0) rb.Add(0.0) rb.Add(0.0) rb.Add(3.5) got := rb.Slice() want := []float64{-5.0, 0.0, 0.0, 3.5} if !slices.Equal(got, want) { t.Errorf("Slice() with negative/zero values = %v, want %v", got, want) } }