332 lines
6.6 KiB
Go
332 lines
6.6 KiB
Go
package ring
|
|
|
|
import (
|
|
"math/rand"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
func TestRingWrite(t *testing.T) {
|
|
type writeTest struct {
|
|
name string
|
|
initBufSize int // Initial buffer size
|
|
initData []byte // Initial data to preload the buffer
|
|
writeData []byte // Data to write in the test
|
|
wantWritten int // Expected number of bytes written
|
|
wantBufSize int // Expected buffer size after write
|
|
wantBufData []byte // Expected buffer data after write
|
|
}
|
|
|
|
testCases := []writeTest{
|
|
{
|
|
name: "WriteWithEmptyBuffer",
|
|
initBufSize: 10,
|
|
initData: nil,
|
|
writeData: []byte("hello"),
|
|
wantWritten: 5,
|
|
wantBufSize: 10,
|
|
wantBufData: []byte("hello"),
|
|
},
|
|
{
|
|
name: "WriteWithExactFillNoInitialData",
|
|
initBufSize: 5,
|
|
initData: nil,
|
|
writeData: []byte("hello"),
|
|
wantWritten: 5,
|
|
wantBufSize: 5,
|
|
wantBufData: []byte("hello"),
|
|
},
|
|
{
|
|
name: "WriteWithPartialFill",
|
|
initBufSize: 10,
|
|
initData: []byte("hi"),
|
|
writeData: []byte("there"),
|
|
wantWritten: 5,
|
|
wantBufSize: 10,
|
|
wantBufData: []byte("hithere"),
|
|
},
|
|
{
|
|
name: "WriteWithExactFill",
|
|
initBufSize: 5,
|
|
initData: []byte("hi"),
|
|
writeData: []byte("123"),
|
|
wantWritten: 3,
|
|
wantBufSize: 5,
|
|
wantBufData: []byte("hi123"),
|
|
},
|
|
{
|
|
name: "WriteWithOverflowRequiresResize",
|
|
initBufSize: 5,
|
|
initData: []byte("hi"),
|
|
writeData: []byte("12345"),
|
|
wantWritten: 5,
|
|
wantBufSize: 10, // Expected double the size of the initial buffer
|
|
wantBufData: []byte("hi12345\x00\x00\x00"), // Including the extra null bytes
|
|
},
|
|
{
|
|
name: "WriteWithZeroLengthData",
|
|
initBufSize: 10,
|
|
initData: []byte("data"),
|
|
writeData: nil,
|
|
wantWritten: 0,
|
|
wantBufSize: 10,
|
|
wantBufData: []byte("data"),
|
|
},
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
tc := tc
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
r := NewRingBuffer(tc.initBufSize)
|
|
if len(tc.initData) > 0 {
|
|
_, _ = r.Write(tc.initData)
|
|
}
|
|
|
|
gotWritten, err := r.Write(tc.writeData)
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, tc.wantWritten, gotWritten)
|
|
assert.Equal(t, tc.wantBufSize, len(r.buf))
|
|
if tc.wantWritten >= tc.initBufSize {
|
|
assert.Equal(t, tc.wantBufData, r.buf)
|
|
} else {
|
|
assert.Equal(t, tc.wantBufData, r.buf[:tc.wantWritten+len(tc.initData)])
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func BenchmarkBufferWrite(b *testing.B) {
|
|
type benchCase struct {
|
|
name string
|
|
dataSize int // Size of the data to write in bytes
|
|
}
|
|
|
|
benchmarks := []benchCase{
|
|
{"1KB", 1 << 10}, // 1KB
|
|
{"4KB", 4 << 10}, // 4KB
|
|
{"16KB", 16 << 10}, // 16KB
|
|
{"64KB", 64 << 10}, // 64KB
|
|
{"256KB", 256 << 10}, // 256KB
|
|
{"1MB", 1 << 20}, // 1MB
|
|
{"4MB", 4 << 20}, // 4MB
|
|
{"16MB", 16 << 20}, // 16MB
|
|
{"64MB", 64 << 20}, // 64MB
|
|
}
|
|
|
|
for _, bc := range benchmarks {
|
|
bc := bc
|
|
b.Run(bc.name, func(b *testing.B) {
|
|
data := generateData(bc.dataSize) // Generate pseudo-random data for this benchmark case
|
|
r := NewRingBuffer(defaultBufferSize)
|
|
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
_, err := r.Write(data)
|
|
assert.NoError(b, err)
|
|
r.Reset()
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func generateData(size int) []byte {
|
|
rand.Seed(42)
|
|
data := make([]byte, size)
|
|
for i := range data {
|
|
data[i] = byte(rand.Intn(256))
|
|
}
|
|
return data
|
|
}
|
|
|
|
func TestRingBufferBytes(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
initBufSize int
|
|
initData []byte
|
|
wantBytes []byte
|
|
}{
|
|
{
|
|
name: "EmptyBuffer",
|
|
initBufSize: 10,
|
|
},
|
|
{
|
|
name: "PartialFill",
|
|
initBufSize: 10,
|
|
initData: []byte("hello"),
|
|
wantBytes: []byte("hello"),
|
|
},
|
|
{
|
|
name: "FullFill",
|
|
initBufSize: 5,
|
|
initData: []byte("hello"),
|
|
wantBytes: []byte("hello"),
|
|
},
|
|
}
|
|
|
|
for _, tc := range tests {
|
|
tc := tc
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
t.Parallel()
|
|
r := NewRingBuffer(tc.initBufSize)
|
|
if tc.initData != nil {
|
|
_, _ = r.Write(tc.initData)
|
|
}
|
|
|
|
assert.Equal(t, tc.wantBytes, r.Bytes())
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestRingBufferLen(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
initBufSize int
|
|
initData []byte
|
|
wantLen int
|
|
}{
|
|
{
|
|
name: "EmptyBuffer",
|
|
initBufSize: 10,
|
|
},
|
|
{
|
|
name: "PartialFill",
|
|
initBufSize: 10,
|
|
initData: []byte("hello"),
|
|
wantLen: 5,
|
|
},
|
|
{
|
|
name: "FullFill",
|
|
initBufSize: 5,
|
|
initData: []byte("hello"),
|
|
wantLen: 5,
|
|
},
|
|
}
|
|
|
|
for _, tc := range tests {
|
|
tc := tc
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
t.Parallel()
|
|
r := NewRingBuffer(tc.initBufSize)
|
|
if tc.initData != nil {
|
|
_, _ = r.Write(tc.initData)
|
|
}
|
|
|
|
assert.Equal(t, tc.wantLen, r.Len())
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestRingBufferCap(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
initBufSize int
|
|
wantCap int
|
|
}{
|
|
{
|
|
name: "InitialCapacity",
|
|
initBufSize: 10,
|
|
wantCap: 10,
|
|
},
|
|
{
|
|
name: "ZeroCapacity",
|
|
},
|
|
}
|
|
|
|
for _, tc := range tests {
|
|
tc := tc
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
t.Parallel()
|
|
r := NewRingBuffer(tc.initBufSize)
|
|
|
|
assert.Equal(t, tc.wantCap, r.Cap())
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestRingBufferReset(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
initBufSize int
|
|
initData []byte
|
|
}{
|
|
{
|
|
name: "AfterWrite",
|
|
initBufSize: 10,
|
|
initData: []byte("reset"),
|
|
},
|
|
{
|
|
name: "EmptyBuffer",
|
|
initBufSize: 10,
|
|
},
|
|
}
|
|
|
|
for _, tc := range tests {
|
|
tc := tc
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
t.Parallel()
|
|
r := NewRingBuffer(tc.initBufSize)
|
|
if tc.initData != nil {
|
|
_, _ = r.Write(tc.initData)
|
|
}
|
|
|
|
r.Reset()
|
|
assert.Equal(t, 0, r.Len())
|
|
assert.Equal(t, tc.initBufSize, r.Cap())
|
|
assert.True(t, r.isEmpty())
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestRingBufferRead(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
initBufSize int
|
|
writeData []byte
|
|
readLen int
|
|
wantReadData []byte
|
|
}{
|
|
{
|
|
name: "ReadPartialData",
|
|
initBufSize: 10,
|
|
writeData: []byte("hello"),
|
|
readLen: 5,
|
|
wantReadData: []byte("hello"),
|
|
},
|
|
{
|
|
name: "ReadFullData",
|
|
initBufSize: 5,
|
|
writeData: []byte("hello"),
|
|
readLen: 5,
|
|
wantReadData: []byte("hello"),
|
|
},
|
|
{
|
|
name: "ReadEmptyBuffer",
|
|
initBufSize: 10,
|
|
writeData: nil,
|
|
readLen: 5,
|
|
wantReadData: []byte{},
|
|
},
|
|
}
|
|
|
|
for _, tc := range tests {
|
|
tc := tc
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
t.Parallel()
|
|
r := NewRingBuffer(tc.initBufSize)
|
|
if tc.writeData != nil {
|
|
_, _ = r.Write(tc.writeData)
|
|
}
|
|
|
|
readData := make([]byte, tc.readLen)
|
|
n, err := r.Read(readData)
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, tc.wantReadData, readData[:n])
|
|
})
|
|
}
|
|
}
|