Skip to content

Commit

Permalink
Merge pull request #7 from alex/eof-on-read-line
Browse files Browse the repository at this point in the history
Fixes #6 -- expose if an EOF happens in Decoder.Decoder
  • Loading branch information
ianlopshire authored May 9, 2019
2 parents 0481af4 + 404a7f3 commit 0fb80fa
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 5 deletions.
17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,5 +63,22 @@ fmt.Printf("%+v\n", people[2])
//{ID:3 FirstName:Jane LastName:Doe Grade:79.5}
```

It is also possible to read data incrementally

```go
decoder := fixedwidth.NewDecoder(bytes.NewReader(data))
for {
var element myStruct
err := decoder.Decode(&element)
if err == io.EOF {
break
}
if err != nil {
log.Fatal(err)
}
handle(element)
}
```

## Licence
MIT
11 changes: 9 additions & 2 deletions decode.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,8 @@ func (e *UnmarshalTypeError) Error() string {
// pointed to by v.
//
// In the case that v points to a struct value, Decode will read a
// single line from the input.
// single line from the input. If there is no data remaining in the file,
// returns io.EOF
//
// In the case that v points to a slice value, Decode will read until
// the end of its input.
Expand All @@ -88,7 +89,13 @@ func (d *Decoder) Decode(v interface{}) error {
return d.readLines(reflect.ValueOf(v).Elem())
}

err, _ := d.readLine(reflect.ValueOf(v))
err, ok := d.readLine(reflect.ValueOf(v))
if d.done && err == nil && !ok {
// d.done means we've reached the end of the file. err == nil && !ok
// indicates that there was no data to read, so we propagate an io.EOF
// upwards so our caller knows there is no data left.
return io.EOF
}
return err
}

Expand Down
37 changes: 34 additions & 3 deletions decode_test.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package fixedwidth

import (
"bytes"
"encoding"
"fmt"
"io"
"log"
"reflect"
"testing"
Expand Down Expand Up @@ -101,8 +103,8 @@ func TestUnmarshal(t *testing.T) {
name: "Empty Line",
rawValue: []byte(""),
target: &allTypes{},
expected: &allTypes{"", 0, 0, EncodableString{"", nil}},
shouldErr: false,
expected: &allTypes{},
shouldErr: true,
},
{
name: "Invalid Target",
Expand Down Expand Up @@ -149,7 +151,7 @@ func TestUnmarshal(t *testing.T) {
{"Invalid Unmarshal Not Pointer 1", struct{}{}, true},
{"Invalid Unmarshal Not Pointer 2", []struct{}{}, true},
{"Valid Unmarshal slice", &[]struct{}{}, false},
{"Valid Unmarshal struct", &struct{}{}, false},
{"Valid Unmarshal struct", &struct{}{}, true},
} {
t.Run(tt.name, func(t *testing.T) {
err := Unmarshal([]byte{}, tt.v)
Expand Down Expand Up @@ -219,3 +221,32 @@ func TestNewValueSetter(t *testing.T) {
})
}
}

// Verify the behavior of Decoder.Decode at the end of a file. See
// https://github.com/ianlopshire/go-fixedwidth/issues/6 for more details.
func TestDecode_EOF(t *testing.T) {
d := NewDecoder(bytes.NewReader([]byte("")))
type S struct {
Field1 string `fixed:"1,1"`
Field2 string `fixed:"2,2"`
Field3 string `fixed:"3,3"`
}
var s S
err := d.Decode(&s)
if err != io.EOF {
t.Errorf("Decode should have returned an EOF error. Returned: %v", err)
}

d = NewDecoder(bytes.NewReader([]byte("ABC\n")))
err = d.Decode(&s)
if err != nil {
t.Errorf("Unexpected error from decode")
}
if !reflect.DeepEqual(&s, &S{Field1: "A", Field2: "B", Field3: "C"}) {
t.Errorf("Unexpected result from Decode: %#v", s)
}
err = d.Decode(&s)
if err != io.EOF {
t.Errorf("Decode should have returned an EOF error. Returned: %v", err)
}
}

0 comments on commit 0fb80fa

Please sign in to comment.