influx-cli/pkg/csv2lp/line_reader_test.go
Daniel Moran f2d10e34f9
feat: port csv2lp from influxdb (#37)
Co-authored-by: William Baker <55118525+wbaker85@users.noreply.github.com>
2021-04-26 09:12:29 -04:00

149 lines
4.2 KiB
Go

package csv2lp_test
import (
"encoding/csv"
"fmt"
"io"
"strings"
"testing"
"testing/iotest"
"github.com/influxdata/influx-cli/v2/pkg/csv2lp"
"github.com/stretchr/testify/require"
)
// TestLineReader tests correctness of line reporting and reader implementation of LineReader
func TestLineReader(t *testing.T) {
type TestInput = struct {
lines [4]string
withDataErrorReader bool
}
tests := []TestInput{
{
lines: [4]string{"a\n", "\n", "\n", "bcxy"},
withDataErrorReader: false,
}, {
lines: [4]string{"a\n", "\n", "\n", "bcxy"},
withDataErrorReader: true,
}, {
lines: [4]string{"a\n", "\n", "\n", "bcx\n"},
withDataErrorReader: false,
}, {
lines: [4]string{"a\n", "\n", "\n", "bcx\n"},
withDataErrorReader: true,
}}
for _, test := range tests {
lines := test.lines
input := strings.Join(lines[:], "")
withDataErrorReader := test.withDataErrorReader
t.Run(fmt.Sprintf("%s withDataErrorReader=%v", input, withDataErrorReader), func(t *testing.T) {
var reader io.Reader = strings.NewReader(input)
if withDataErrorReader {
// ensures that the reader reports the last EOF error also with data
reader = iotest.DataErrReader(reader)
}
lineReader := csv2lp.NewLineReaderSize(reader, 2)
var buf []byte = make([]byte, 4)
var err error
var read int
// patologic case: reading from empty buffer returns 0 without an error
read, err = lineReader.Read(buf[0:0])
require.Equal(t, 0, read)
require.Nil(t, err)
require.Equal(t, 0, lineReader.LastLineNumber)
// 1st line
read, err = lineReader.Read(buf)
require.Equal(t, []byte(lines[0]), buf[0:read])
require.Nil(t, err)
require.Equal(t, 0, lineReader.LastLineNumber)
// 2nd
read, err = lineReader.Read(buf)
require.Equal(t, []byte(lines[1]), buf[0:read])
require.Nil(t, err)
require.Equal(t, 1, lineReader.LastLineNumber)
// reading into empty does not change the game
read, err = lineReader.Read(buf[0:0])
require.Equal(t, 0, read)
require.Nil(t, err)
require.Equal(t, 1, lineReader.LastLineNumber)
// 3rd
read, err = lineReader.Read(buf)
require.Equal(t, []byte(lines[2]), buf[0:read])
require.Nil(t, err)
require.Equal(t, 2, lineReader.LastLineNumber)
// 4th line cannot be fully read, because buffer size is 2
read, err = lineReader.Read(buf)
require.Equal(t, []byte(lines[3][:2]), buf[0:read])
require.Nil(t, err)
require.Equal(t, 3, lineReader.LastLineNumber)
read, err = lineReader.Read(buf)
require.Equal(t, []byte(lines[3][2:]), buf[0:read])
require.Nil(t, err)
require.Equal(t, 3, lineReader.LastLineNumber)
// 5th line => error
_, err = lineReader.Read(buf)
require.NotNil(t, err)
})
}
}
// TestLineReader_Read_BufferOverflow ensures calling Open into
// a slice does not panic. Fixes https://github.com/influxdata/influxdb/issues/19586
func TestLineReader_Read_BufferOverflow(t *testing.T) {
sr := strings.NewReader("foo\nbar")
rd := csv2lp.NewLineReader(sr)
buf := make([]byte, 2)
n, err := rd.Read(buf)
require.Equal(t, n, 2)
require.NoError(t, err)
}
// TestLineReader_viaCsv tests correct line reporting when read through a CSV reader with various buffer sizes
// to emulate multiple required reads with a small test data set
func TestLineReader_viaCsv(t *testing.T) {
type RowWithLine = struct {
row []string
lineNumber int
}
input := "a\n\nb\n\nc"
expected := []RowWithLine{
{[]string{"a"}, 1},
{[]string{"b"}, 3},
{[]string{"c"}, 5},
}
bufferSizes := []int{-1, 0, 2, 50}
for _, bufferSize := range bufferSizes {
t.Run(fmt.Sprintf("buffer size: %d", bufferSize), func(t *testing.T) {
var lineReader *csv2lp.LineReader
if bufferSize < 0 {
lineReader = csv2lp.NewLineReader(strings.NewReader(input))
} else {
lineReader = csv2lp.NewLineReaderSize(strings.NewReader(input), bufferSize)
}
lineReader.LineNumber = 1 // start with 1
csvReader := csv.NewReader(lineReader)
results := make([]RowWithLine, 0, 3)
for {
row, _ := csvReader.Read()
lineNumber := lineReader.LastLineNumber
if row == nil {
break
}
results = append(results, RowWithLine{row, lineNumber})
}
require.Equal(t, expected, results)
})
}
}