372 lines
7.1 KiB
Go
372 lines
7.1 KiB
Go
package buffer_test
|
|
|
|
import (
|
|
"testing"
|
|
"code.squareroundforest.org/arpio/buffer"
|
|
"io"
|
|
"bytes"
|
|
"errors"
|
|
)
|
|
|
|
func TestRead(t *testing.T) {
|
|
t.Run("small", func(t *testing.T) {
|
|
g := &gen{max: 3}
|
|
r := buffer.ReaderFrom(g, buffer.Options{Pool: buffer.NoPool(1 << 12)})
|
|
b, err := io.ReadAll(r)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if !bytes.Equal(b, generate(3)) {
|
|
t.Fatal("output does not match", len(b))
|
|
}
|
|
})
|
|
|
|
t.Run("large", func(t *testing.T) {
|
|
g := &gen{max: 1 << 18}
|
|
r := buffer.ReaderFrom(g, buffer.Options{Pool: buffer.NoPool(1 << 12)})
|
|
b, err := io.ReadAll(r)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if !bytes.Equal(b, generate(1<<18)) {
|
|
t.Fatal("output does not match", len(b))
|
|
}
|
|
})
|
|
|
|
t.Run("zero first", func(t *testing.T) {
|
|
g := &gen{max: 1 << 15}
|
|
o := buffer.Options{Pool: buffer.NoPool(1 << 12)}
|
|
r := buffer.ReaderFrom(g, o)
|
|
|
|
var p []byte
|
|
n, err := r.Read(p)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if n != 0 {
|
|
t.Fatal("invalid length")
|
|
}
|
|
|
|
p = make([]byte, 256)
|
|
n, err = r.Read(p)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if n != 256 {
|
|
t.Fatal("invalid length")
|
|
}
|
|
|
|
if !bytes.Equal(p, generate(256)) {
|
|
t.Fatal("invalid content")
|
|
}
|
|
})
|
|
|
|
t.Run("large with non-divisible fragments", func(t *testing.T) {
|
|
g := &gen{max: 1 << 15}
|
|
o := buffer.Options{
|
|
Pool: buffer.NoPool(1 << 12 / 2),
|
|
ReadSize: 1 << 12 / 7,
|
|
}
|
|
|
|
r := buffer.ReaderFrom(g, o)
|
|
b, err := io.ReadAll(r)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if !bytes.Equal(b, generate(1<<15)) {
|
|
t.Fatal("output does not match", len(b))
|
|
}
|
|
})
|
|
|
|
t.Run("partial segment", func(t *testing.T) {
|
|
g := &gen{max: 1 << 15}
|
|
o := buffer.Options{
|
|
Pool: buffer.NoPool(128),
|
|
ReadSize: 8,
|
|
}
|
|
|
|
r := buffer.ReaderFrom(g, o)
|
|
r.Peek(30)
|
|
p := make([]byte, 60)
|
|
n, err := r.Read(p)
|
|
if n != 60 {
|
|
t.Fatal("invalid read length", n)
|
|
}
|
|
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if !bytes.Equal(p, generate(60)) {
|
|
t.Fatal("invalid content")
|
|
}
|
|
})
|
|
|
|
t.Run("partial segment nth", func(t *testing.T) {
|
|
g := &gen{max: 1 << 15}
|
|
o := buffer.Options{
|
|
Pool: buffer.NoPool(128),
|
|
ReadSize: 8,
|
|
}
|
|
|
|
r := buffer.ReaderFrom(g, o)
|
|
r.Peek(2*128 + 30)
|
|
p := make([]byte, 2*128+60)
|
|
n, err := r.Read(p)
|
|
if n != 2*128+60 {
|
|
t.Fatal("invalid read length", n)
|
|
}
|
|
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if !bytes.Equal(p, generate(2*128+60)) {
|
|
t.Fatal("invalid content")
|
|
}
|
|
})
|
|
|
|
t.Run("read buffer larger than read size", func(t *testing.T) {
|
|
g := &gen{max: 1 << 15}
|
|
o := buffer.Options{
|
|
Pool: buffer.NoPool(128),
|
|
ReadSize: 8,
|
|
}
|
|
|
|
r := buffer.ReaderFrom(g, o)
|
|
p := make([]byte, 12)
|
|
n, err := r.Read(p)
|
|
if n != 12 {
|
|
t.Fatal("invalid read size")
|
|
}
|
|
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if !bytes.Equal(p, generate(12)) {
|
|
t.Fatal("invalid content")
|
|
}
|
|
})
|
|
|
|
t.Run("read buffer larger than segment", func(t *testing.T) {
|
|
g := &gen{max: 1 << 15}
|
|
o := buffer.Options{
|
|
Pool: buffer.NoPool(128),
|
|
ReadSize: 8,
|
|
}
|
|
|
|
r := buffer.ReaderFrom(g, o)
|
|
p := make([]byte, 192)
|
|
n, err := r.Read(p)
|
|
if n != 192 {
|
|
t.Fatal("invalid read size")
|
|
}
|
|
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if !bytes.Equal(p, generate(192)) {
|
|
t.Fatal("invalid content")
|
|
}
|
|
})
|
|
|
|
t.Run("read buffer larger than available data", func(t *testing.T) {
|
|
g := &gen{max: 256}
|
|
o := buffer.Options{
|
|
Pool: buffer.NoPool(128),
|
|
ReadSize: 8,
|
|
}
|
|
|
|
r := buffer.ReaderFrom(g, o)
|
|
p := make([]byte, 384)
|
|
n, err := r.Read(p)
|
|
if n != 256 {
|
|
t.Fatal("invalid read size")
|
|
}
|
|
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if !bytes.Equal(p[:n], generate(256)) {
|
|
t.Fatal("invalid content")
|
|
}
|
|
|
|
n, err = r.Read(p)
|
|
if n != 0 || !errors.Is(err, io.EOF) {
|
|
t.Fatal("invalid post read", n, err)
|
|
}
|
|
})
|
|
|
|
t.Run("null read on empty", func(t *testing.T) {
|
|
g := &gen{
|
|
max: 1 << 15,
|
|
nullReadAfter: []int{0, 0},
|
|
}
|
|
|
|
o := buffer.Options{
|
|
Pool: buffer.NoPool(128),
|
|
ReadSize: 8,
|
|
}
|
|
|
|
r := buffer.ReaderFrom(g, o)
|
|
p := make([]byte, 64)
|
|
n, err := r.Read(p)
|
|
if n != 0 || err != nil {
|
|
t.Fatal("failed to handle null read", n, err)
|
|
}
|
|
|
|
n, err = r.Read(p)
|
|
if n != 64 || err != nil || !bytes.Equal(p, generate(64)) {
|
|
t.Fatal("failed to recover after null read", n, err)
|
|
}
|
|
})
|
|
|
|
t.Run("null read on non-empty", func(t *testing.T) {
|
|
g := &gen{
|
|
max: 1 << 15,
|
|
nullReadAfter: []int{32, 32},
|
|
}
|
|
|
|
o := buffer.Options{
|
|
Pool: buffer.NoPool(128),
|
|
ReadSize: 32,
|
|
}
|
|
|
|
r := buffer.ReaderFrom(g, o)
|
|
p := make([]byte, 32)
|
|
n, err := r.Read(p)
|
|
if n != 32 || err != nil || !bytes.Equal(p, generate(32)) {
|
|
t.Fatal("initial read failed")
|
|
}
|
|
|
|
n, err = r.Read(p)
|
|
if n != 0 || err != nil {
|
|
t.Fatal("failed to handle null read", n, err)
|
|
}
|
|
|
|
n, err = r.Read(p)
|
|
if n != 32 || err != nil || !bytes.Equal(p, generate(64)[32:]) {
|
|
t.Fatal("failed to recover after null read", n, err)
|
|
}
|
|
})
|
|
|
|
t.Run("partial read on null read", func(t *testing.T) {
|
|
g := &gen{
|
|
max: 1 << 15,
|
|
nullReadAfter: []int{32, 32},
|
|
}
|
|
|
|
o := buffer.Options{
|
|
Pool: buffer.NoPool(128),
|
|
ReadSize: 32,
|
|
}
|
|
|
|
r := buffer.ReaderFrom(g, o)
|
|
p := make([]byte, 24)
|
|
n, err := r.Read(p)
|
|
if n != 24 || err != nil || !bytes.Equal(p, generate(24)) {
|
|
t.Fatal("initial read failed")
|
|
}
|
|
|
|
n, err = r.Read(p)
|
|
if n != 8 || err != nil || !bytes.Equal(p[:n], generate(32)[24:]) {
|
|
t.Fatal("failed to handle null read", n, err)
|
|
}
|
|
|
|
n, err = r.Read(p)
|
|
if n != 24 || err != nil || !bytes.Equal(p, generate(56)[32:]) {
|
|
t.Fatal("failed to recover after null read", n, err)
|
|
}
|
|
})
|
|
|
|
t.Run("read error without content", func(t *testing.T) {
|
|
g := &gen{
|
|
max: 1 << 15,
|
|
errAfter: []int{32},
|
|
}
|
|
|
|
o := buffer.Options{
|
|
Pool: buffer.NoPool(128),
|
|
ReadSize: 32,
|
|
}
|
|
|
|
r := buffer.ReaderFrom(g, o)
|
|
p := make([]byte, 64)
|
|
n, err := r.Read(p)
|
|
if n != 64 || err != nil {
|
|
t.Fatal("failed to read", n, err)
|
|
}
|
|
|
|
n, err = r.Read(p)
|
|
if n != 0 || !errors.Is(err, errTest) {
|
|
t.Fatal("failed to process read error", n, err)
|
|
}
|
|
})
|
|
|
|
t.Run("read error with content", func(t *testing.T) {
|
|
g := &gen{
|
|
max: 1 << 15,
|
|
errAfter: []int{32},
|
|
fastErr: true,
|
|
}
|
|
|
|
o := buffer.Options{
|
|
Pool: buffer.NoPool(128),
|
|
ReadSize: 32,
|
|
}
|
|
|
|
r := buffer.ReaderFrom(g, o)
|
|
p := make([]byte, 64)
|
|
n, err := r.Read(p)
|
|
if n != 64 || err != nil {
|
|
t.Fatal("failed to read", n, err)
|
|
}
|
|
|
|
n, err = r.Read(p)
|
|
if n != 0 || !errors.Is(err, errTest) {
|
|
t.Fatal("failed to process read error", n, err)
|
|
}
|
|
})
|
|
|
|
t.Run("read after error", func(t *testing.T) {
|
|
g := &gen{
|
|
max: 1 << 15,
|
|
errAfter: []int{32},
|
|
fastErr: true,
|
|
}
|
|
|
|
o := buffer.Options{
|
|
Pool: buffer.NoPool(128),
|
|
ReadSize: 32,
|
|
}
|
|
|
|
var result []byte
|
|
r := buffer.ReaderFrom(g, o)
|
|
p := make([]byte, 9)
|
|
for i := 0; i < 3; i++ {
|
|
if n, err := r.Read(p); n != 9 || err != nil {
|
|
t.Fatal(n, err)
|
|
}
|
|
|
|
result = append(result, p...)
|
|
}
|
|
|
|
if n, err := r.Read(p); n != 5 || err != nil {
|
|
t.Fatal(n, err)
|
|
}
|
|
|
|
result = append(result, p[:5]...)
|
|
if !bytes.Equal(result, generate(32)) {
|
|
t.Fatal("invalid content")
|
|
}
|
|
})
|
|
}
|