mirror of
https://github.com/VictoriaMetrics/VictoriaMetrics.git
synced 2024-12-26 20:30:10 +01:00
f4252f87e6
ReadLinesBlock may accept dstBuf with non-zero length. In this case the last line without trailing newline isn't read. Fix this by comparing len(dstBuf) to 0 instead of its original length.
147 lines
3.7 KiB
Go
147 lines
3.7 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("")
|
|
|
|
// 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", "")
|
|
f("foo", "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
|
|
}
|