Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ type CsvReader struct {
// fileBaseName is the base name of the file extracted from filePath.
// Is used in logging.
fileBaseName string
// LazyQuotes is a flag used to allow quotes in an unquoted field and non-doubled quotes
// in a quoted field
LazyQuotes bool
}

// New instantiates a new CsvReader object with some default fields preset.
Expand Down Expand Up @@ -202,6 +205,7 @@ func (cr *CsvReader) readBetweenOffsetsAsync(
csvReader := csv.NewReader(bytesReader)
csvReader.Comma = cr.ColumnsDelimiter
csvReader.FieldsPerRecord = cr.ColumnsCount
csvReader.LazyQuotes = cr.LazyQuotes

ForLoop:
for {
Expand Down
44 changes: 44 additions & 0 deletions reader_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ func TestCsvReader(t *testing.T) {
t.Run("context is canceled", testCsvReaderWithContextCanceled)
t.Run("invalid row", testCsvReaderWithInvalidRow)
t.Run("small buffer size", testCsvReaderWithSmallBufferSize)
t.Run("quotes in unquoted field", testCsvReaderWithLazyQuotes)
}

func testCsvReaderByHeader(withHeader bool) func(t *testing.T) {
Expand Down Expand Up @@ -180,6 +181,49 @@ func testCsvReaderWithDifferentFileSizesAndMaxGoroutines(rowsCount int64) func(t
}
}

func testCsvReaderWithLazyQuotes(t *testing.T) {
t.Parallel()

// arrange
subject := bigcsvreader.New()
subject.SetFilePath("testdata/file_with_quote_in_unquoted_field.csv")
subject.ColumnsCount = 3
subject.FileHasHeader = false
subject.LazyQuotes = true

expectedRecords := [][]string{
{"1", "John \"The Bomb\" Miguel", "33"},
{"2", "Jane", "30"},
{"3", "Mike", "18"},
{"4", "Ronaldinho", "23"},
{"5", "Elisabeth", "45"},
}

ctx, cancelCtx := context.WithTimeout(context.Background(), 15*time.Second)
defer cancelCtx()

// act
rowsChans, errsChan := subject.Read(ctx)
records, err := gatherRecords(rowsChans, errsChan)

// assert
assertNil(t, err)
assertEqual(t, len(expectedRecords), len(records))
for _, expectedRecord := range expectedRecords {
found := false
for _, record := range records {
if reflect.DeepEqual(expectedRecord, record) {
found = true

break
}
}
if !found {
t.Errorf("record '%v' was expected to be found, but was not", expectedRecord)
}
}
}

func testCsvReaderWithInvalidRow(t *testing.T) {
t.Parallel()

Expand Down
5 changes: 5 additions & 0 deletions testdata/file_with_quote_in_unquoted_field.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
1,John "The Bomb" Miguel,33
2,"Jane",30
3,"Mike",18
4,"Ronaldinho",23
5,Elisabeth,45