2014-05-14 20:54:19 -04:00
|
|
|
package csvstruct
|
|
|
|
|
|
|
|
|
|
import (
|
2014-05-15 12:31:56 -04:00
|
|
|
"fmt"
|
2014-05-14 20:54:19 -04:00
|
|
|
"io"
|
2014-05-14 21:11:21 -04:00
|
|
|
"reflect"
|
2014-05-14 20:54:19 -04:00
|
|
|
"strings"
|
|
|
|
|
"testing"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
func TestDecode(t *testing.T) {
|
|
|
|
|
type row struct {
|
|
|
|
|
Foo, Bar, Baz string
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, c := range []struct {
|
|
|
|
|
data string
|
|
|
|
|
out []row
|
|
|
|
|
}{{
|
|
|
|
|
data: `Foo,Bar,Baz
|
|
|
|
|
a,b,c
|
2014-05-15 10:07:07 -04:00
|
|
|
d,e,f
|
|
|
|
|
`,
|
2014-05-14 20:54:19 -04:00
|
|
|
out: []row{{"a", "b", "c"}, {"d", "e", "f"}},
|
|
|
|
|
}, {
|
|
|
|
|
// Rows that only have partial data are only partially filled.
|
2014-05-15 08:31:35 -04:00
|
|
|
data: `Foo,Bar,Baz
|
|
|
|
|
a,,
|
2014-05-15 10:07:07 -04:00
|
|
|
,b,
|
|
|
|
|
`,
|
2014-05-15 08:31:35 -04:00
|
|
|
out: []row{{"a", "", ""}, {"", "b", ""}},
|
|
|
|
|
}, {
|
|
|
|
|
// Rows that don't define all the columns are partially filled.
|
2014-05-14 20:54:19 -04:00
|
|
|
data: `Foo,Bar
|
|
|
|
|
a,
|
2014-05-15 10:07:07 -04:00
|
|
|
,b
|
|
|
|
|
`,
|
2014-05-14 20:54:19 -04:00
|
|
|
out: []row{{"a", "", ""}, {"", "b", ""}},
|
2014-05-15 10:07:07 -04:00
|
|
|
}, {
|
|
|
|
|
// Entirely disjoint columns produce empty structs.
|
|
|
|
|
data: `Qux
|
|
|
|
|
d
|
|
|
|
|
`,
|
|
|
|
|
out: []row{{}},
|
2014-05-14 20:54:19 -04:00
|
|
|
}} {
|
|
|
|
|
d := NewDecoder(strings.NewReader(c.data))
|
2014-05-14 21:11:21 -04:00
|
|
|
rows := []row{}
|
2014-05-15 10:32:47 -04:00
|
|
|
var r row
|
2014-05-14 20:54:19 -04:00
|
|
|
for {
|
2014-05-15 10:32:47 -04:00
|
|
|
if err := d.DecodeNext(&r); err == io.EOF {
|
2014-05-14 20:54:19 -04:00
|
|
|
break
|
2014-05-15 10:07:07 -04:00
|
|
|
} else if err != nil {
|
2014-05-14 20:54:19 -04:00
|
|
|
t.Errorf("%v", err)
|
|
|
|
|
break
|
|
|
|
|
}
|
2014-05-15 10:32:47 -04:00
|
|
|
rows = append(rows, r)
|
2014-05-14 21:11:21 -04:00
|
|
|
}
|
2014-05-15 08:31:35 -04:00
|
|
|
if !reflect.DeepEqual(rows, c.out) {
|
2014-05-14 21:11:21 -04:00
|
|
|
t.Errorf("unexpected result, got %v, want %v", rows, c.out)
|
2014-05-14 20:54:19 -04:00
|
|
|
}
|
2014-05-15 12:55:24 -04:00
|
|
|
if !isDone(d) {
|
|
|
|
|
t.Errorf("decoder unexpectedly not done")
|
|
|
|
|
}
|
2014-05-14 20:54:19 -04:00
|
|
|
}
|
|
|
|
|
}
|
2014-05-15 10:32:47 -04:00
|
|
|
|
|
|
|
|
func TestDecode_Unexported(t *testing.T) {
|
|
|
|
|
type row struct {
|
|
|
|
|
Exported, unexported string
|
|
|
|
|
}
|
|
|
|
|
var r row
|
2014-05-15 11:22:29 -04:00
|
|
|
if err := NewDecoder(strings.NewReader(`Exported,unexported
|
|
|
|
|
a,b`)).DecodeNext(&r); err != nil {
|
2014-05-15 10:32:47 -04:00
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
|
}
|
|
|
|
|
exp := row{Exported: "a"}
|
|
|
|
|
if !reflect.DeepEqual(r, exp) {
|
|
|
|
|
t.Errorf("unexpected result, got %v, want %v", r, exp)
|
|
|
|
|
}
|
|
|
|
|
}
|
2014-05-15 10:42:25 -04:00
|
|
|
|
|
|
|
|
func TestDecode_Tags(t *testing.T) {
|
|
|
|
|
type row struct {
|
|
|
|
|
Foo string `csv:"renamed_foo"`
|
|
|
|
|
Bar string
|
|
|
|
|
Ignored string `csv:"-"`
|
|
|
|
|
}
|
|
|
|
|
var r row
|
2014-05-15 11:22:29 -04:00
|
|
|
if err := NewDecoder(strings.NewReader(`renamed_foo,Bar,Ignored
|
|
|
|
|
a,b,c`)).DecodeNext(&r); err != nil {
|
2014-05-15 10:42:25 -04:00
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
|
}
|
|
|
|
|
exp := row{"a", "b", ""}
|
|
|
|
|
if !reflect.DeepEqual(r, exp) {
|
|
|
|
|
t.Errorf("unexpected results, got %v, want %v", r, exp)
|
|
|
|
|
}
|
|
|
|
|
}
|
2014-05-15 11:22:29 -04:00
|
|
|
|
|
|
|
|
func TestDecode_NonStrings(t *testing.T) {
|
|
|
|
|
type row struct {
|
|
|
|
|
Int int
|
|
|
|
|
Int64 int64
|
2014-05-15 12:20:41 -04:00
|
|
|
Uint64 uint64
|
2014-05-15 11:22:29 -04:00
|
|
|
Float64 float64
|
|
|
|
|
Bool bool
|
|
|
|
|
}
|
|
|
|
|
var r row
|
2014-05-15 12:20:41 -04:00
|
|
|
if err := NewDecoder(strings.NewReader(`Int,Int64,Uint64,Float64,Bool
|
|
|
|
|
123,-123456789,123456789,123.456,true`)).DecodeNext(&r); err != nil {
|
2014-05-15 11:22:29 -04:00
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
|
}
|
2014-05-15 12:20:41 -04:00
|
|
|
exp := row{123, -123456789, 123456789, 123.456, true}
|
2014-05-15 11:22:29 -04:00
|
|
|
if !reflect.DeepEqual(r, exp) {
|
|
|
|
|
t.Errorf("unexpected results, got %v, want %v", r, exp)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestDecode_Pointers(t *testing.T) {
|
|
|
|
|
t.Skip("pointers are not yet supported")
|
|
|
|
|
type row struct {
|
|
|
|
|
S string
|
|
|
|
|
SP *string
|
|
|
|
|
}
|
|
|
|
|
var r row
|
|
|
|
|
if err := NewDecoder(strings.NewReader(`S,SP
|
|
|
|
|
a,b`)).DecodeNext(&r); err != nil {
|
|
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
|
}
|
|
|
|
|
if r.S != "a" || r.SP == nil || *r.SP != "b" {
|
|
|
|
|
t.Errorf("unexpected results, got %v", r)
|
|
|
|
|
}
|
|
|
|
|
}
|
2014-05-15 12:31:56 -04:00
|
|
|
|
2014-05-15 12:55:24 -04:00
|
|
|
func TestDecode_DecodeNil(t *testing.T) {
|
|
|
|
|
type row struct {
|
|
|
|
|
Foo, Bar string
|
|
|
|
|
}
|
|
|
|
|
d := NewDecoder(strings.NewReader(`Foo,Bar
|
|
|
|
|
ignore,this
|
|
|
|
|
a,b`))
|
|
|
|
|
if err := d.DecodeNext(nil); err != nil {
|
|
|
|
|
t.Errorf("unexpected error while skipping line: %v", err)
|
|
|
|
|
}
|
|
|
|
|
var r row
|
|
|
|
|
if err := d.DecodeNext(&r); err != nil {
|
|
|
|
|
t.Errorf("unexpected error decoding after skip: %v", err)
|
|
|
|
|
}
|
|
|
|
|
exp := row{"a", "b"}
|
|
|
|
|
if r != exp {
|
|
|
|
|
t.Errorf("unexpected result, got %v, want %v", r, exp)
|
|
|
|
|
}
|
|
|
|
|
if !isDone(d) {
|
|
|
|
|
t.Errorf("decoder unexpectedly not done")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func isDone(d Decoder) bool {
|
|
|
|
|
return d.DecodeNext(nil) == io.EOF
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-15 12:31:56 -04:00
|
|
|
func ExampleDecoder_DecodeNext() {
|
|
|
|
|
csv := `Foo,Bar,Baz
|
|
|
|
|
a,b,c
|
|
|
|
|
d,e,f`
|
|
|
|
|
type row struct {
|
|
|
|
|
Foo, Bar, Baz string
|
|
|
|
|
}
|
|
|
|
|
var r row
|
|
|
|
|
d := NewDecoder(strings.NewReader(csv))
|
|
|
|
|
for {
|
|
|
|
|
if err := d.DecodeNext(&r); err == io.EOF {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
fmt.Println(r)
|
|
|
|
|
}
|
|
|
|
|
// Output:
|
|
|
|
|
// {a b c}
|
|
|
|
|
// {d e f}
|
|
|
|
|
}
|