mirror of
https://github.com/VictoriaMetrics/VictoriaMetrics.git
synced 2024-12-20 23:46:23 +01:00
149 lines
3.8 KiB
Go
149 lines
3.8 KiB
Go
|
package common
|
||
|
|
||
|
import (
|
||
|
"bytes"
|
||
|
"fmt"
|
||
|
"io"
|
||
|
"testing"
|
||
|
)
|
||
|
|
||
|
func TestReadLinesBlockFailure(t *testing.T) {
|
||
|
f := func(s string) {
|
||
|
t.Helper()
|
||
|
r := bytes.NewBufferString(s)
|
||
|
if _, _, err := ReadLinesBlock(r, nil, nil); err == nil {
|
||
|
t.Fatalf("expecting non-nil error")
|
||
|
}
|
||
|
sbr := &singleByteReader{
|
||
|
b: []byte(s),
|
||
|
}
|
||
|
if _, _, err := ReadLinesBlock(sbr, nil, nil); err == nil {
|
||
|
t.Fatalf("expecting non-nil error")
|
||
|
}
|
||
|
fr := &failureReader{}
|
||
|
if _, _, err := ReadLinesBlock(fr, nil, nil); err == nil {
|
||
|
t.Fatalf("expecting non-nil error")
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// empty string
|
||
|
f("")
|
||
|
|
||
|
// no newline in nonempty string
|
||
|
f("foobar")
|
||
|
|
||
|
// too long string
|
||
|
b := make([]byte, maxLineSize+1)
|
||
|
f(string(b))
|
||
|
}
|
||
|
|
||
|
type failureReader struct{}
|
||
|
|
||
|
func (fr *failureReader) Read(p []byte) (int, error) {
|
||
|
return 0, fmt.Errorf("some error")
|
||
|
}
|
||
|
|
||
|
func TestReadLineBlockSuccessSingleByteReader(t *testing.T) {
|
||
|
f := func(s, dstBufExpected, tailBufExpected string) {
|
||
|
t.Helper()
|
||
|
|
||
|
r := &singleByteReader{
|
||
|
b: []byte(s),
|
||
|
}
|
||
|
dstBuf, tailBuf, err := ReadLinesBlock(r, nil, nil)
|
||
|
if err != nil {
|
||
|
t.Fatalf("unexpected error: %s", err)
|
||
|
}
|
||
|
if string(dstBuf) != dstBufExpected {
|
||
|
t.Fatalf("unexpected dstBuf; got %q; want %q; tailBuf=%q", dstBuf, dstBufExpected, tailBuf)
|
||
|
}
|
||
|
if string(tailBuf) != tailBufExpected {
|
||
|
t.Fatalf("unexpected tailBuf; got %q; want %q; dstBuf=%q", tailBuf, tailBufExpected, dstBuf)
|
||
|
}
|
||
|
|
||
|
// Verify the same with non-empty dstBuf and tailBuf
|
||
|
r = &singleByteReader{
|
||
|
b: []byte(s),
|
||
|
}
|
||
|
dstBuf, tailBuf, err = ReadLinesBlock(r, dstBuf, tailBuf[:0])
|
||
|
if err != nil {
|
||
|
t.Fatalf("non-empty bufs: unexpected error: %s", err)
|
||
|
}
|
||
|
if string(dstBuf) != dstBufExpected {
|
||
|
t.Fatalf("non-empty bufs: unexpected dstBuf; got %q; want %q; tailBuf=%q", dstBuf, dstBufExpected, tailBuf)
|
||
|
}
|
||
|
if string(tailBuf) != tailBufExpected {
|
||
|
t.Fatalf("non-empty bufs: unexpected tailBuf; got %q; want %q; dstBuf=%q", tailBuf, tailBufExpected, dstBuf)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
f("\n", "", "")
|
||
|
f("foo\n", "foo", "")
|
||
|
f("\nfoo", "", "")
|
||
|
f("foo\nbar", "foo", "")
|
||
|
f("foo\nbar\nbaz", "foo", "")
|
||
|
|
||
|
// The maximum line size
|
||
|
b := make([]byte, maxLineSize+10)
|
||
|
b[maxLineSize] = '\n'
|
||
|
f(string(b), string(b[:maxLineSize]), "")
|
||
|
}
|
||
|
|
||
|
func TestReadLineBlockSuccessBytesBuffer(t *testing.T) {
|
||
|
f := func(s, dstBufExpected, tailBufExpected string) {
|
||
|
t.Helper()
|
||
|
|
||
|
r := bytes.NewBufferString(s)
|
||
|
dstBuf, tailBuf, err := ReadLinesBlock(r, nil, nil)
|
||
|
if err != nil {
|
||
|
t.Fatalf("unexpected error: %s", err)
|
||
|
}
|
||
|
if string(dstBuf) != dstBufExpected {
|
||
|
t.Fatalf("unexpected dstBuf; got %q; want %q; tailBuf=%q", dstBuf, dstBufExpected, tailBuf)
|
||
|
}
|
||
|
if string(tailBuf) != tailBufExpected {
|
||
|
t.Fatalf("unexpected tailBuf; got %q; want %q; dstBuf=%q", tailBuf, tailBufExpected, dstBuf)
|
||
|
}
|
||
|
|
||
|
// Verify the same with non-empty dstBuf and tailBuf
|
||
|
r = bytes.NewBufferString(s)
|
||
|
dstBuf, tailBuf, err = ReadLinesBlock(r, dstBuf, tailBuf[:0])
|
||
|
if err != nil {
|
||
|
t.Fatalf("non-empty bufs: unexpected error: %s", err)
|
||
|
}
|
||
|
if string(dstBuf) != dstBufExpected {
|
||
|
t.Fatalf("non-empty bufs: unexpected dstBuf; got %q; want %q; tailBuf=%q", dstBuf, dstBufExpected, tailBuf)
|
||
|
}
|
||
|
if string(tailBuf) != tailBufExpected {
|
||
|
t.Fatalf("non-empty bufs: unexpected tailBuf; got %q; want %q; dstBuf=%q", tailBuf, tailBufExpected, dstBuf)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
f("\n", "", "")
|
||
|
f("foo\n", "foo", "")
|
||
|
f("\nfoo", "", "foo")
|
||
|
f("foo\nbar", "foo", "bar")
|
||
|
f("foo\nbar\nbaz", "foo\nbar", "baz")
|
||
|
|
||
|
// The maximum line size
|
||
|
b := make([]byte, maxLineSize+10)
|
||
|
b[maxLineSize] = '\n'
|
||
|
f(string(b), string(b[:maxLineSize]), string(b[maxLineSize+1:]))
|
||
|
}
|
||
|
|
||
|
type singleByteReader struct {
|
||
|
b []byte
|
||
|
}
|
||
|
|
||
|
func (sbr *singleByteReader) Read(p []byte) (int, error) {
|
||
|
if len(sbr.b) == 0 {
|
||
|
return 0, io.EOF
|
||
|
}
|
||
|
n := copy(p, sbr.b[:1])
|
||
|
sbr.b = sbr.b[n:]
|
||
|
if len(sbr.b) == 0 {
|
||
|
return n, io.EOF
|
||
|
}
|
||
|
return n, nil
|
||
|
}
|