Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding support for CRLF's #1

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
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
2 changes: 1 addition & 1 deletion reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ func New(r io.Reader) io.Reader {
func (r reader) Read(p []byte) (n int, err error) {
n, err = r.r.Read(p)
for i, b := range p {
if b == rByte {
if j := i + 1; b == rByte && ((j < len(p) && p[j] != nByte) || j == len(p)) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sadly, I think this won't work in all cases. Read() is allowed to return less than len(p) bytes, even if it's not the end of the underlying Reader. So it can happen that a \r falls on the last byte of a Read() call, then the \n is the first byte of the next Read() call.

You can test this by creating your own Reader implementation to pass into this for testing which simulates this unfortunate case.

One fix is to require that this reader take a bufio.Reader as input rather than a io.Reader so that you can always call Peek() to get the next byte (I think that works).

Another fix could be to continue taking io.Reader and then test whether it can be cast in bufio.Reader and if not manually wrapping it.

p[i] = nByte
}
}
Expand Down
62 changes: 62 additions & 0 deletions reader_test.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package macreader

import (
"testing"
"bytes"
"encoding/csv"
"fmt"
"strings"
)

func Example() {
Expand Down Expand Up @@ -32,3 +34,63 @@ func Example() {
// With macreader: [][]string{[]string{"a", "b", "c"}, []string{"1", "2", "3"}}

}


func TestCR(t *testing.T) {
testFile := bytes.NewBufferString("a,b,c\r1,2,3\r").Bytes()

r := csv.NewReader(New(bytes.NewReader(testFile)))
lines, err := r.ReadAll()

if err != nil {
t.Errorf("An error occurred while reading the data: %v", err)
}
if len(lines) != 2 {
t.Errorf("Wrong number of lines. Expected 2, got %d", len(lines))
}
}

func TestLF(t *testing.T) {
testFile := bytes.NewBufferString("a,b,c\n1,2,3\n").Bytes()

r := csv.NewReader(New(bytes.NewReader(testFile)))
lines, err := r.ReadAll()

if err != nil {
t.Errorf("An error occurred while reading the data: %v", err)
}
if len(lines) != 2 {
t.Errorf("Wrong number of lines. Expected 2, got %d", len(lines))
}
}

func TestCRLF(t *testing.T) {
testFile := bytes.NewBufferString("a,b,c\r\n1,2,3\r\n").Bytes()

r := csv.NewReader(New(bytes.NewReader(testFile)))
lines, err := r.ReadAll()

if err != nil {
t.Errorf("An error occurred while reading the data: %v", err)
}
if len(lines) != 2 {
t.Errorf("Wrong number of lines. Expected 2, got %d", len(lines))
}
}

func TestCRInQuote(t *testing.T) {
testFile := bytes.NewBufferString("a,\"foo,\rbar\",c\r1,\"2\r\n2\",3\r").Bytes()

r := csv.NewReader(New(bytes.NewReader(testFile)))
lines, err := r.ReadAll()

if err != nil {
t.Errorf("An error occurred while reading the data: %v", err)
}
if len(lines) != 2 {
t.Errorf("Wrong number of lines. Expected 2, got %d", len(lines))
}
if strings.Contains(lines[1][1], "\n\n") {
t.Error("The CRLF was converted to a LFLF")
}
}