753 lines
15 KiB
Go
753 lines
15 KiB
Go
package buffer_test
|
|
|
|
import (
|
|
"testing"
|
|
"code.squareroundforest.org/arpio/buffer"
|
|
"bytes"
|
|
"errors"
|
|
"io"
|
|
)
|
|
|
|
func TestReadBytes(t *testing.T) {
|
|
t.Run("find", func(t *testing.T) {
|
|
g := &gen{
|
|
max: 1 << 15,
|
|
customContentAfter: []int{12},
|
|
customContent: map[int][]byte{12: []byte("123")},
|
|
}
|
|
|
|
o := buffer.Options{Pool: buffer.NoPool(1 << 12)}
|
|
r := buffer.ReaderFrom(g, o)
|
|
b, ok, err := r.ReadBytes([]byte("123"), 64)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if !ok {
|
|
t.Fatal("delimiter")
|
|
}
|
|
|
|
if !bytes.Equal(b, append(generate(12), []byte("123")...)) {
|
|
t.Fatal("failed to generate right content")
|
|
}
|
|
})
|
|
|
|
t.Run("find not", func(t *testing.T) {
|
|
g := &gen{max: 1 << 15}
|
|
o := buffer.Options{Pool: buffer.NoPool(1 << 12)}
|
|
r := buffer.ReaderFrom(g, o)
|
|
b, ok, err := r.ReadBytes([]byte("123"), 64)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if ok || len(b) != 0 {
|
|
t.Fatal("failed to not find delimiter")
|
|
}
|
|
})
|
|
|
|
t.Run("find across segments", func(t *testing.T) {
|
|
g := &gen{
|
|
max: 1 << 15,
|
|
customContentAfter: []int{12},
|
|
customContent: map[int][]byte{12: []byte("123")},
|
|
}
|
|
|
|
o := buffer.Options{
|
|
Pool: buffer.NoPool(14),
|
|
ReadSize: 14,
|
|
}
|
|
|
|
r := buffer.ReaderFrom(g, o)
|
|
b, ok, err := r.ReadBytes([]byte("123"), 64)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if !ok {
|
|
t.Fatal("failed to find delimiter")
|
|
}
|
|
|
|
if !bytes.Equal(b, append(generate(12), []byte("123")...)) {
|
|
t.Fatal("invalid content")
|
|
}
|
|
})
|
|
|
|
t.Run("find across multiple segments", func(t *testing.T) {
|
|
d := generateFrom([]byte("123"), 12)
|
|
g := &gen{
|
|
max: 1 << 15,
|
|
customContentAfter: []int{6},
|
|
customContent: map[int][]byte{6: d},
|
|
}
|
|
|
|
o := buffer.Options{
|
|
Pool: buffer.NoPool(8),
|
|
ReadSize: 8,
|
|
}
|
|
|
|
r := buffer.ReaderFrom(g, o)
|
|
b, ok, err := r.ReadBytes(d, 64)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if !ok {
|
|
t.Fatal("failed to find delimiter")
|
|
}
|
|
|
|
if !bytes.Equal(b, append(generate(6), d...)) {
|
|
t.Fatal("invalid content")
|
|
}
|
|
})
|
|
|
|
t.Run("find not across segments", func(t *testing.T) {
|
|
g := &gen{max: 1 << 15}
|
|
o := buffer.Options{
|
|
Pool: buffer.NoPool(15),
|
|
ReadSize: 15,
|
|
}
|
|
|
|
r := buffer.ReaderFrom(g, o)
|
|
b, ok, err := r.ReadBytes([]byte("123"), 24)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if ok {
|
|
t.Fatal("invalid delimiter found")
|
|
}
|
|
|
|
if len(b) != 0 {
|
|
t.Fatal("invalid content", len(b), string(b))
|
|
}
|
|
})
|
|
|
|
t.Run("find not across multiple segments", func(t *testing.T) {
|
|
g := &gen{max: 1 << 15}
|
|
o := buffer.Options{
|
|
Pool: buffer.NoPool(15),
|
|
ReadSize: 15,
|
|
}
|
|
|
|
r := buffer.ReaderFrom(g, o)
|
|
b, ok, err := r.ReadBytes([]byte("123"), 64)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if ok {
|
|
t.Fatal("invalid delimiter found")
|
|
}
|
|
|
|
if len(b) != 0 {
|
|
t.Fatal("invalid content", len(b), string(b))
|
|
}
|
|
})
|
|
|
|
t.Run("find not due to max", func(t *testing.T) {
|
|
g := &gen{
|
|
max: 1 << 15,
|
|
customContentAfter: []int{12},
|
|
customContent: map[int][]byte{12: []byte("123")},
|
|
}
|
|
|
|
o := buffer.Options{Pool: buffer.NoPool(1 << 12)}
|
|
r := buffer.ReaderFrom(g, o)
|
|
b, ok, err := r.ReadBytes([]byte("8"), 64)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if ok {
|
|
t.Fatal("invalid delimiter found")
|
|
}
|
|
|
|
if len(b) != 0 {
|
|
t.Fatal("invalid content")
|
|
}
|
|
})
|
|
|
|
t.Run("find partial", func(t *testing.T) {
|
|
g := &gen{
|
|
max: 1 << 15,
|
|
customContentAfter: []int{12},
|
|
customContent: map[int][]byte{12: []byte("12")},
|
|
}
|
|
|
|
o := buffer.Options{Pool: buffer.NoPool(1 << 12)}
|
|
r := buffer.ReaderFrom(g, o)
|
|
b, ok, err := r.ReadBytes([]byte("123"), 64)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if ok {
|
|
t.Fatal("invalid delimiter found")
|
|
}
|
|
|
|
if len(b) != 0 {
|
|
t.Fatal("invalid content")
|
|
}
|
|
})
|
|
|
|
t.Run("find partial and then full", func(t *testing.T) {
|
|
g := &gen{
|
|
max: 1 << 15,
|
|
customContentAfter: []int{12, 18},
|
|
customContent: map[int][]byte{
|
|
12: []byte("12"),
|
|
18: []byte("123"),
|
|
},
|
|
}
|
|
|
|
o := buffer.Options{Pool: buffer.NoPool(1 << 12)}
|
|
r := buffer.ReaderFrom(g, o)
|
|
b, ok, err := r.ReadBytes([]byte("123"), 16)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if ok {
|
|
t.Fatal("invalid delimiter found")
|
|
}
|
|
|
|
if len(b) != 0 {
|
|
t.Fatal("invalid content")
|
|
}
|
|
|
|
b, ok, err = r.ReadBytes([]byte("123"), 24)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if !ok {
|
|
t.Fatal("delimiter")
|
|
}
|
|
|
|
check := append(
|
|
append(generate(12), append([]byte("12"), generate(18)[14:]...)...),
|
|
[]byte("123")...,
|
|
)
|
|
|
|
if !bytes.Equal(b, check) {
|
|
t.Fatal("invalid content", len(b), string(b), len(check), string(check))
|
|
}
|
|
})
|
|
|
|
t.Run("find partial across segments", func(t *testing.T) {
|
|
g := &gen{
|
|
max: 1 << 15,
|
|
customContentAfter: []int{7},
|
|
customContent: map[int][]byte{7: []byte("12")},
|
|
}
|
|
|
|
o := buffer.Options{
|
|
Pool: buffer.NoPool(8),
|
|
ReadSize: 8,
|
|
}
|
|
|
|
r := buffer.ReaderFrom(g, o)
|
|
b, ok, err := r.ReadBytes([]byte("123"), 64)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if ok {
|
|
t.Fatal("invalid delimiter found")
|
|
}
|
|
|
|
if len(b) != 0 {
|
|
t.Fatal("invalid content")
|
|
}
|
|
})
|
|
|
|
t.Run("find partial across multiple segments", func(t *testing.T) {
|
|
g := &gen{
|
|
max: 1 << 15,
|
|
customContentAfter: []int{7},
|
|
customContent: map[int][]byte{7: []byte("1234567890")},
|
|
}
|
|
|
|
o := buffer.Options{
|
|
Pool: buffer.NoPool(8),
|
|
ReadSize: 8,
|
|
}
|
|
|
|
r := buffer.ReaderFrom(g, o)
|
|
b, ok, err := r.ReadBytes([]byte("1234567890123"), 64)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if ok {
|
|
t.Fatal("invalid delimiter found")
|
|
}
|
|
|
|
if len(b) != 0 {
|
|
t.Fatal("invalid content")
|
|
}
|
|
})
|
|
|
|
t.Run("find partial across segments and then full", func(t *testing.T) {
|
|
g := &gen{
|
|
max: 1 << 15,
|
|
customContentAfter: []int{7, 15},
|
|
customContent: map[int][]byte{
|
|
7: []byte("12"),
|
|
15: []byte("123"),
|
|
},
|
|
}
|
|
|
|
o := buffer.Options{
|
|
Pool: buffer.NoPool(8),
|
|
ReadSize: 8,
|
|
}
|
|
|
|
r := buffer.ReaderFrom(g, o)
|
|
b, ok, err := r.ReadBytes([]byte("123"), 10)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if ok {
|
|
t.Fatal("invalid delimiter found")
|
|
}
|
|
|
|
if len(b) != 0 {
|
|
t.Fatal("invalid content")
|
|
}
|
|
|
|
b, ok, err = r.ReadBytes([]byte("123"), 64)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if !ok {
|
|
t.Fatal("delimiter")
|
|
}
|
|
|
|
check := append(
|
|
append(generate(7), append([]byte("12"), generate(15)[9:]...)...),
|
|
[]byte("123")...,
|
|
)
|
|
|
|
if !bytes.Equal(b, check) {
|
|
t.Fatal("invalid content", len(b), string(b), len(check), string(check))
|
|
}
|
|
})
|
|
|
|
t.Run("find partial across multiple segments and then full", func(t *testing.T) {
|
|
g := &gen{
|
|
max: 1 << 15,
|
|
customContentAfter: []int{7, 22},
|
|
customContent: map[int][]byte{
|
|
7: []byte("1234567890"),
|
|
22: []byte("1234567890123"),
|
|
},
|
|
}
|
|
|
|
o := buffer.Options{
|
|
Pool: buffer.NoPool(8),
|
|
ReadSize: 8,
|
|
}
|
|
|
|
r := buffer.ReaderFrom(g, o)
|
|
b, ok, err := r.ReadBytes([]byte("1234567890123"), 20)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if ok {
|
|
t.Fatal("invalid delimiter found")
|
|
}
|
|
|
|
if len(b) != 0 {
|
|
t.Fatal("invalid content")
|
|
}
|
|
|
|
b, ok, err = r.ReadBytes([]byte("1234567890123"), 64)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if !ok {
|
|
t.Fatal("delimiter")
|
|
}
|
|
|
|
check := append(
|
|
append(append(generate(7), []byte("1234567890")...), generate(22)[17:]...),
|
|
[]byte("1234567890123")...,
|
|
)
|
|
|
|
if !bytes.Equal(b, check) {
|
|
t.Fatal("invalid content", len(b), string(b), len(check), string(check))
|
|
}
|
|
})
|
|
|
|
t.Run("find partial due to max", func(t *testing.T) {
|
|
g := &gen{
|
|
max: 1 << 15,
|
|
customContentAfter: []int{12},
|
|
customContent: map[int][]byte{12: []byte("123")},
|
|
}
|
|
|
|
o := buffer.Options{Pool: buffer.NoPool(1 << 12)}
|
|
r := buffer.ReaderFrom(g, o)
|
|
b, ok, err := r.ReadBytes([]byte("123"), 14)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if ok {
|
|
t.Fatal("delimiter")
|
|
}
|
|
|
|
if len(b) != 0 {
|
|
t.Fatal("invalid content")
|
|
}
|
|
})
|
|
|
|
t.Run("find partial due to max and then full", func(t *testing.T) {
|
|
g := &gen{
|
|
max: 1 << 15,
|
|
customContentAfter: []int{12},
|
|
customContent: map[int][]byte{12: []byte("123")},
|
|
}
|
|
|
|
o := buffer.Options{Pool: buffer.NoPool(1 << 12)}
|
|
r := buffer.ReaderFrom(g, o)
|
|
b, ok, err := r.ReadBytes([]byte("123"), 14)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if ok {
|
|
t.Fatal("delimiter")
|
|
}
|
|
|
|
if len(b) != 0 {
|
|
t.Fatal("invalid content")
|
|
}
|
|
|
|
b, ok, err = r.ReadBytes([]byte("123"), 64)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if !ok {
|
|
t.Fatal("delimiter")
|
|
}
|
|
|
|
if !bytes.Equal(b, append(generate(12), []byte("123")...)) {
|
|
t.Fatal("invalid content")
|
|
}
|
|
})
|
|
|
|
t.Run("error before found", func(t *testing.T) {
|
|
g := &gen{
|
|
max: 1 << 15,
|
|
errAfter: []int{8},
|
|
customContentAfter: []int{12},
|
|
customContent: map[int][]byte{12: []byte("123")},
|
|
}
|
|
|
|
o := buffer.Options{
|
|
Pool: buffer.NoPool(8),
|
|
ReadSize: 8,
|
|
}
|
|
|
|
r := buffer.ReaderFrom(g, o)
|
|
b, ok, err := r.ReadBytes([]byte("123"), 64)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if ok {
|
|
t.Fatal("delimiter")
|
|
}
|
|
|
|
if !bytes.Equal(b, generate(8)) {
|
|
t.Fatal("invalid content")
|
|
}
|
|
|
|
b, ok, err = r.ReadBytes([]byte("123"), 64)
|
|
if !errors.Is(err, errTest) {
|
|
t.Fatal("failed to fail", err)
|
|
}
|
|
|
|
if ok {
|
|
t.Fatal("delimiter")
|
|
}
|
|
|
|
if len(b) != 0 {
|
|
t.Fatal("invalid content")
|
|
}
|
|
})
|
|
|
|
t.Run("error when found", func(t *testing.T) {
|
|
g := &gen{
|
|
max: 1 << 15,
|
|
errAfter: []int{15},
|
|
fastErr: true,
|
|
customContentAfter: []int{12},
|
|
customContent: map[int][]byte{12: []byte("123")},
|
|
}
|
|
|
|
o := buffer.Options{
|
|
Pool: buffer.NoPool(8),
|
|
ReadSize: 8,
|
|
}
|
|
|
|
r := buffer.ReaderFrom(g, o)
|
|
b, ok, err := r.ReadBytes([]byte("123"), 64)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if !ok {
|
|
t.Fatal("delimiter", len(b), string(b))
|
|
}
|
|
|
|
if !bytes.Equal(b, append(generate(12), []byte("123")...)) {
|
|
t.Fatal("invalid content")
|
|
}
|
|
|
|
b, ok, err = r.ReadBytes([]byte("123"), 64)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if ok {
|
|
t.Fatal("unexpected delimiter")
|
|
}
|
|
|
|
if !bytes.Equal(b, generate(16)[15:]) {
|
|
t.Fatal("invalid content", len(b), string(b))
|
|
}
|
|
|
|
b, ok, err = r.ReadBytes([]byte("123"), 64)
|
|
if !errors.Is(err, errTest) {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if ok {
|
|
t.Fatal("unexpected delimiter")
|
|
}
|
|
|
|
if len(b) != 0 {
|
|
t.Fatal("invalid content", len(b), string(b))
|
|
}
|
|
})
|
|
|
|
t.Run("error after found", func(t *testing.T) {
|
|
g := &gen{
|
|
max: 1 << 15,
|
|
errAfter: []int{18},
|
|
fastErr: true,
|
|
customContentAfter: []int{12},
|
|
customContent: map[int][]byte{12: []byte("123")},
|
|
}
|
|
|
|
o := buffer.Options{
|
|
Pool: buffer.NoPool(8),
|
|
ReadSize: 8,
|
|
}
|
|
|
|
r := buffer.ReaderFrom(g, o)
|
|
b, ok, err := r.ReadBytes([]byte("123"), 64)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if !ok {
|
|
t.Fatal("delimiter", len(b), string(b))
|
|
}
|
|
|
|
if !bytes.Equal(b, append(generate(12), []byte("123")...)) {
|
|
t.Fatal("invalid content")
|
|
}
|
|
|
|
b, ok, err = r.ReadBytes([]byte("123"), 64)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if ok {
|
|
t.Fatal("unexpected delimiter")
|
|
}
|
|
|
|
if !bytes.Equal(b, generate(24)[15:]) {
|
|
t.Fatal("invalid content", len(b), string(b))
|
|
}
|
|
|
|
b, ok, err = r.ReadBytes([]byte("123"), 64)
|
|
if !errors.Is(err, errTest) {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if ok {
|
|
t.Fatal("unexpected delimiter")
|
|
}
|
|
|
|
if len(b) != 0 {
|
|
t.Fatal("invalid content", len(b), string(b))
|
|
}
|
|
})
|
|
|
|
t.Run("null delimiter", func(t *testing.T) {
|
|
g := &gen{
|
|
max: 1 << 15,
|
|
customContentAfter: []int{12},
|
|
customContent: map[int][]byte{12: []byte("123")},
|
|
}
|
|
|
|
o := buffer.Options{Pool: buffer.NoPool(1 << 12)}
|
|
r := buffer.ReaderFrom(g, o)
|
|
b, ok, err := r.ReadBytes(nil, 64)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if !ok {
|
|
t.Fatal("failed to find delimiter")
|
|
}
|
|
|
|
if len(b) != 0 {
|
|
t.Fatal("failed to generate right content")
|
|
}
|
|
})
|
|
|
|
t.Run("null read", func(t *testing.T) {
|
|
g := &gen{
|
|
max: 1 << 15,
|
|
nullReadAfter: []int{8, 8},
|
|
customContentAfter: []int{12},
|
|
customContent: map[int][]byte{12: []byte("123")},
|
|
}
|
|
|
|
o := buffer.Options{
|
|
Pool: buffer.NoPool(8),
|
|
ReadSize: 8,
|
|
}
|
|
|
|
r := buffer.ReaderFrom(g, o)
|
|
b, ok, err := r.ReadBytes([]byte("123"), 64)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if ok {
|
|
t.Fatal("delimiter")
|
|
}
|
|
|
|
if len(b) != 0 {
|
|
t.Fatal("invalid content")
|
|
}
|
|
|
|
b, ok, err = r.ReadBytes([]byte("123"), 64)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if !ok {
|
|
t.Fatal("delimiter")
|
|
}
|
|
|
|
if !bytes.Equal(b, append(generate(12), []byte("123")...)) {
|
|
t.Fatal("failed to generate right content")
|
|
}
|
|
})
|
|
|
|
t.Run("find not more than max", func(t *testing.T) {
|
|
g := &gen{
|
|
max: 256,
|
|
fastErr: true,
|
|
}
|
|
|
|
o := buffer.Options{
|
|
Pool: buffer.NoPool(256),
|
|
ReadSize: 256,
|
|
}
|
|
|
|
r := buffer.ReaderFrom(g, o)
|
|
b, ok, err := r.ReadBytes([]byte("123"), 64)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if ok {
|
|
t.Fatal("delimiter")
|
|
}
|
|
|
|
if !bytes.Equal(b, generate(64)) {
|
|
t.Fatal("failed to generate right content")
|
|
}
|
|
})
|
|
|
|
t.Run("find not none consumed", func(t *testing.T) {
|
|
g := &gen{}
|
|
o := buffer.Options{Pool: buffer.NoPool(1 << 12)}
|
|
r := buffer.ReaderFrom(g, o)
|
|
b, ok, err := r.ReadBytes([]byte("123"), 64)
|
|
if !errors.Is(err, io.EOF) {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if ok {
|
|
t.Fatal("failed to find delimiter")
|
|
}
|
|
|
|
if len(b) != 0 {
|
|
t.Fatal("invalid content")
|
|
}
|
|
})
|
|
|
|
// conditions:
|
|
// - A0: error before read
|
|
// - A1: error during read
|
|
// - B0: allocation error
|
|
// - B1: read error
|
|
// - B2: eof
|
|
// - C0: error right before delimiter
|
|
// - C1: error during delimiter
|
|
// - C2: error right after full delimiter
|
|
// - D0: error before max
|
|
// - D1: error right at max
|
|
// - D2: error after max
|
|
// - E0: error at zero segment position
|
|
// - E1: error at not first segment boundary
|
|
// - E2: error in first segment
|
|
// - E3: error in subsequent segment
|
|
// - F0: error at zero data position
|
|
// - F1: error at not zero data position
|
|
// - F3: error at last data position
|
|
// - G0: less than max buffered
|
|
// - G1: exactly max buffered
|
|
// - G2: more than max buffered
|
|
// - H0: max at first segment start
|
|
// - H1: max at segment boundary
|
|
// - H2: max in first segment
|
|
// - H3: max in subsequent segment
|
|
// - I0: delimiter in newly read
|
|
// - I1: delimiter in buffered
|
|
// - J0: delimiter before max
|
|
// - J1: delimiter right up to max
|
|
// - J2: delimiter over max
|
|
// - J3: delimiter right after max
|
|
// - J4: delimiter after max
|
|
// - K0: delimiter at zero segment position
|
|
// - K1: delimiter at subsequent segment boundary
|
|
// - K2: delimiter within segment
|
|
// - L0: delimiter at zero data position
|
|
// - L1: delimiter at within buffered data
|
|
// - L2: delimiter at the end of buffered data
|
|
// - L3: partial delimiter at the end of buffered data
|
|
// - L4: delimiter right after buffered data
|
|
// - M0: delimiter found
|
|
// - M1: delimiter not found
|
|
//
|
|
// variations:
|
|
// - A0B0...
|
|
}
|