1
0
buffer/lib_test.go

304 lines
5.9 KiB
Go
Raw Normal View History

2026-02-22 18:45:57 +01:00
package buffer_test
import (
2026-02-22 20:55:38 +01:00
"bufio"
2026-02-22 18:45:57 +01:00
"bytes"
"code.squareroundforest.org/arpio/buffer"
"errors"
"io"
2026-02-23 00:22:19 +01:00
"runtime"
2026-02-22 18:45:57 +01:00
"testing"
)
func TestLib(t *testing.T) {
t.Run("default pool", func(t *testing.T) {
t.Run("buffered reader", func(t *testing.T) {
g := &gen{max: 1 << 18}
r := buffer.BufferedReader(g, buffer.Options{})
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("buffered content", func(t *testing.T) {
c := buffer.ContentFunc(func(w io.Writer) (int64, error) {
g := &gen{max: 1 << 18}
return io.Copy(w, g)
})
r := buffer.BufferedContent(c, buffer.Options{})
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 reader", func(t *testing.T) {
t.Run("buffered reader", func(t *testing.T) {
r := buffer.BufferedReader(nil, buffer.Options{})
b, err := io.ReadAll(r)
if err != nil {
t.Fatal(err)
}
if len(b) != 0 {
t.Fatal("output does not match", len(b))
}
})
t.Run("buffered content", func(t *testing.T) {
r := buffer.BufferedContent(nil, buffer.Options{})
b, err := io.ReadAll(r)
if err != nil {
t.Fatal(err)
}
if len(b) != 0 {
t.Fatal("output does not match", len(b))
}
})
})
t.Run("uninitialized reader", func(t *testing.T) {
t.Run("read", func(t *testing.T) {
var r buffer.Reader
p := make([]byte, 512)
n, err := r.Read(p)
if !errors.Is(err, io.EOF) {
t.Fatal(err)
}
if n != 0 {
t.Fatal(n)
}
})
t.Run("read bytes", func(t *testing.T) {
var r buffer.Reader
b, ok, err := r.ReadBytes([]byte("123"), 512)
if !errors.Is(err, io.EOF) {
t.Fatal(err)
}
if ok {
t.Fatal(ok)
}
if len(b) != 0 {
t.Fatal(len(b))
}
})
t.Run("read utf8", func(t *testing.T) {
var r buffer.Reader
runes, n, err := r.ReadUTF8(512)
if !errors.Is(err, io.EOF) {
t.Fatal(err)
}
if n != 0 {
t.Fatal(n)
}
if len(runes) != 0 {
t.Fatal(len(runes))
}
})
t.Run("peek", func(t *testing.T) {
var r buffer.Reader
b, err := r.Peek(512)
if !errors.Is(err, io.EOF) {
t.Fatal(err)
}
if len(b) != 0 {
t.Fatal(len(b))
}
})
t.Run("buffered", func(t *testing.T) {
var r buffer.Reader
b := r.Buffered()
if len(b) != 0 {
t.Fatal(len(b))
}
})
t.Run("write to", func(t *testing.T) {
var (
r buffer.Reader
b bytes.Buffer
)
n, err := r.WriteTo(&b)
if err != nil {
t.Fatal(err)
}
if n != 0 {
t.Fatal(n)
}
})
})
}
2026-02-22 20:55:38 +01:00
// -- bench
type readerOnly struct {
in io.Reader
}
type writerOnly struct {
in io.Writer
}
func (r readerOnly) Read(p []byte) (int, error) {
return r.in.Read(p)
}
func (w writerOnly) Write(p []byte) (int, error) {
return w.in.Write(p)
}
2026-02-23 00:22:19 +01:00
func TestBenchmarkThroughput(t *testing.T) {
p := buffer.DefaultPool(0)
dst := bytes.NewBuffer(nil)
wo := writerOnly{dst}
src := &gen{max: 1 << 18}
r := buffer.BufferedReader(src, buffer.Options{Pool: p})
ro := readerOnly{r}
dst.Reset()
if n, err := io.Copy(wo, ro); n != 1<<18 || err != nil {
t.Fatal(n, err)
}
}
func TestBenchmarkCompare(t *testing.T) {
dst := bytes.NewBuffer(nil)
wo := writerOnly{dst}
src := &gen{max: 1 << 18}
r := bufio.NewReader(src)
ro := readerOnly{r}
dst.Reset()
if n, err := io.Copy(wo, ro); n != 1<<18 || err != nil {
t.Fatal(n, err)
}
}
func TestBenchmarkThroughputSTDLib(t *testing.T) {
p := buffer.DefaultPool(0)
dst := bytes.NewBuffer(nil)
wo := writerOnly{dst}
src := bytes.NewBuffer(make([]byte, 1<<18))
r := buffer.BufferedReader(src, buffer.Options{Pool: p})
ro := readerOnly{r}
dst.Reset()
if n, err := io.Copy(wo, ro); n != 1<<18 || err != nil {
t.Fatal(n, err)
}
}
func TestBenchmarkCompareSTDLib(t *testing.T) {
dst := bytes.NewBuffer(nil)
wo := writerOnly{dst}
src := bytes.NewBuffer(make([]byte, 1<<18))
r := bufio.NewReader(src)
ro := readerOnly{r}
dst.Reset()
if n, err := io.Copy(wo, ro); n != 1<<18 || err != nil {
t.Fatal(n, err)
}
}
2026-02-22 20:55:38 +01:00
func BenchmarkThroughput(b *testing.B) {
p := buffer.DefaultPool(0)
dst := bytes.NewBuffer(nil)
wo := writerOnly{dst}
for i := 0; i < b.N; i++ {
2026-02-23 00:22:19 +01:00
src := &gen{max: 1 << 18}
2026-02-22 20:55:38 +01:00
r := buffer.BufferedReader(src, buffer.Options{Pool: p})
ro := readerOnly{r}
dst.Reset()
io.Copy(wo, ro)
}
}
func BenchmarkCompare(b *testing.B) {
2026-02-23 00:22:19 +01:00
dst := bytes.NewBuffer(nil)
wo := writerOnly{dst}
2026-02-22 20:55:38 +01:00
for i := 0; i < b.N; i++ {
2026-02-23 00:22:19 +01:00
src := &gen{max: 1 << 18}
r := bufio.NewReader(src)
ro := readerOnly{r}
dst.Reset()
io.Copy(wo, ro)
}
}
func BenchmarkThroughputP(b *testing.B) {
p := buffer.DefaultPool(0)
b.SetParallelism(runtime.GOMAXPROCS(-1))
b.RunParallel(func(pb *testing.PB) {
dst := bytes.NewBuffer(nil)
wo := writerOnly{dst}
for pb.Next() {
src := &gen{max: 1 << 18}
r := buffer.BufferedReader(src, buffer.Options{Pool: p})
ro := readerOnly{r}
dst.Reset()
io.Copy(wo, ro)
}
})
}
func BenchmarkCompareP(b *testing.B) {
b.SetParallelism(runtime.GOMAXPROCS(-1))
b.RunParallel(func(pb *testing.PB) {
dst := bytes.NewBuffer(nil)
wo := writerOnly{dst}
for pb.Next() {
src := &gen{max: 1 << 18}
r := bufio.NewReader(src)
ro := readerOnly{r}
dst.Reset()
io.Copy(wo, ro)
}
})
}
func BenchmarkThroughputSTDLib(b *testing.B) {
p := buffer.DefaultPool(0)
dst := bytes.NewBuffer(nil)
wo := writerOnly{dst}
for i := 0; i < b.N; i++ {
src := bytes.NewBuffer(make([]byte, 1<<18))
r := buffer.BufferedReader(src, buffer.Options{Pool: p})
ro := readerOnly{r}
dst.Reset()
io.Copy(wo, ro)
}
}
func BenchmarkCompareSTDLib(b *testing.B) {
dst := bytes.NewBuffer(nil)
wo := writerOnly{dst}
for i := 0; i < b.N; i++ {
src := bytes.NewBuffer(make([]byte, 1<<18))
r := bufio.NewReader(src)
ro := readerOnly{r}
dst.Reset()
io.Copy(wo, ro)
2026-02-22 20:55:38 +01:00
}
}