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

Fix csv marshaller for marshal chan #15

Merged
merged 3 commits into from
Jul 11, 2019
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
9 changes: 9 additions & 0 deletions encode.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,15 @@ func writeFromChan(writer *SafeCSVWriter, c <-chan interface{}) error {
return err
}
write := func(val reflect.Value) error {
if !val.CanAddr() {
// Make an addressable copy
//
// Admittedly this is a kludge but downstream operations (like reflect.Value.Interface())
// require addressability
ptr := reflect.New(val.Type())
ptr.Elem().Set(val)
val = ptr.Elem()
}
for j, fieldInfo := range inInnerStructInfo.Fields {
csvHeadersLabels[j] = ""
inInnerFieldValue, err := getInnerField(val, inInnerWasPointer, fieldInfo.IndexChain) // Get the correct field header <-> position
Expand Down
29 changes: 15 additions & 14 deletions encode_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
)

func assertLine(t *testing.T, expected, actual []string) {
t.Helper()
if len(expected) != len(actual) {
t.Fatalf("line length mismatch between expected: %d and actual: %d", len(expected), len(actual))
}
Expand All @@ -28,8 +29,8 @@ func Test_writeTo(t *testing.T) {
blah := 2
sptr := "*string"
s := []Sample{
{Foo: "f", Bar: 1, Baz: "baz", Frop: 0.1, Blah: &blah, SPtr: &sptr},
{Foo: "e", Bar: 3, Baz: "b", Frop: 6.0 / 13, Blah: nil, SPtr: nil},
{Foo: "f", Bar: 1, Baz: "baz", Frop: 0.1, Blah: &blah, Marshaller: MarshallerStruct{Foo: "foo", Bar: 1}, SPtr: &sptr},
{Foo: "e", Bar: 3, Baz: "b", Frop: 6.0 / 13, Blah: nil, Marshaller: MarshallerStruct{Foo: "foo", Bar: 2}, SPtr: nil},
}
if err := writeTo(NewSafeCSVWriter(csv.NewWriter(e.out)), s, false); err != nil {
t.Fatal(err)
Expand All @@ -42,9 +43,9 @@ func Test_writeTo(t *testing.T) {
if len(lines) != 3 {
t.Fatalf("expected 3 lines, got %d", len(lines))
}
assertLine(t, []string{"foo", "BAR", "Baz", "Quux", "Blah", "SPtr", "Omit"}, lines[0])
assertLine(t, []string{"f", "1", "baz", "0.1", "2", "*string", ""}, lines[1])
assertLine(t, []string{"e", "3", "b", "0.46153846153846156", "", "", ""}, lines[2])
assertLine(t, []string{"foo", "BAR", "Baz", "Quux", "Blah", "SPtr", "Marshaller", "Omit"}, lines[0])
assertLine(t, []string{"f", "1", "baz", "0.1", "2", "*string", "foo 1", ""}, lines[1])
assertLine(t, []string{"e", "3", "b", "0.46153846153846156", "", "", "foo 2", ""}, lines[2])
}

func Test_writeTo_Time(t *testing.T) {
Expand Down Expand Up @@ -96,8 +97,8 @@ func Test_writeTo_NoHeaders(t *testing.T) {
if len(lines) != 2 {
t.Fatalf("expected 2 lines, got %d", len(lines))
}
assertLine(t, []string{"f", "1", "baz", "0.1", "2", "*string", ""}, lines[0])
assertLine(t, []string{"e", "3", "b", "0.46153846153846156", "", "", ""}, lines[1])
assertLine(t, []string{"f", "1", "baz", "0.1", "2", "*string", " 0", ""}, lines[0])
assertLine(t, []string{"e", "3", "b", "0.46153846153846156", "", "", " 0", ""}, lines[1])
}

func Test_writeTo_multipleTags(t *testing.T) {
Expand Down Expand Up @@ -149,8 +150,8 @@ func Test_writeTo_embed(t *testing.T) {
if len(lines) != 2 {
t.Fatalf("expected 2 lines, got %d", len(lines))
}
assertLine(t, []string{"first", "foo", "BAR", "Baz", "Quux", "Blah", "SPtr", "Omit", "garply", "last"}, lines[0])
assertLine(t, []string{"aaa", "f", "1", "baz", "0.2", "2", "*string", "", "3.141592653589793", "zzz"}, lines[1])
assertLine(t, []string{"first", "foo", "BAR", "Baz", "Quux", "Blah", "SPtr", "Marshaller", "Omit", "garply", "last"}, lines[0])
assertLine(t, []string{"aaa", "f", "1", "baz", "0.2", "2", "*string", " 0", "", "3.141592653589793", "zzz"}, lines[1])
}

func Test_writeTo_complex_embed(t *testing.T) {
Expand Down Expand Up @@ -187,8 +188,8 @@ func Test_writeTo_complex_embed(t *testing.T) {
if len(lines) != 2 {
t.Fatalf("expected 2 lines, got %d", len(lines))
}
assertLine(t, []string{"first", "foo", "BAR", "Baz", "Quux", "Blah", "SPtr", "Omit", "garply", "last", "abc"}, lines[0])
assertLine(t, []string{"aaa", "bbb", "111", "ddd", "12000000000000000000000", "", "*string", "", "0.1", "fff", "hhh"}, lines[1])
assertLine(t, []string{"first", "foo", "BAR", "Baz", "Quux", "Blah", "SPtr", "Marshaller", "Omit", "garply", "last", "abc"}, lines[0])
assertLine(t, []string{"aaa", "bbb", "111", "ddd", "12000000000000000000000", "", "*string", " 0", "", "0.1", "fff", "hhh"}, lines[1])
}

func Test_writeToChan(t *testing.T) {
Expand All @@ -198,7 +199,7 @@ func Test_writeToChan(t *testing.T) {
sptr := "*string"
go func() {
for i := 0; i < 100; i++ {
v := Sample{Foo: "f", Bar: i, Baz: "baz" + strconv.Itoa(i), Frop: float64(i), Blah: nil, SPtr: &sptr}
v := Sample{Foo: "f", Bar: i, Baz: "baz" + strconv.Itoa(i), Frop: float64(i), Blah: nil, Marshaller: MarshallerStruct{"foo", 1}, SPtr: &sptr}
c <- v
}
close(c)
Expand All @@ -215,10 +216,10 @@ func Test_writeToChan(t *testing.T) {
}
for i, l := range lines {
if i == 0 {
assertLine(t, []string{"foo", "BAR", "Baz", "Quux", "Blah", "SPtr", "Omit"}, l)
assertLine(t, []string{"foo", "BAR", "Baz", "Quux", "Blah", "SPtr", "Marshaller", "Omit"}, l)
continue
}
assertLine(t, []string{"f", strconv.Itoa(i - 1), "baz" + strconv.Itoa(i-1), strconv.FormatFloat(float64(i-1), 'f', -1, 64), "", "*string", ""}, l)
assertLine(t, []string{"f", strconv.Itoa(i - 1), "baz" + strconv.Itoa(i-1), strconv.FormatFloat(float64(i-1), 'f', -1, 64), "", "*string", "foo 1", ""}, l)
}
}

Expand Down
34 changes: 26 additions & 8 deletions sample_structs_test.go
Original file line number Diff line number Diff line change
@@ -1,15 +1,33 @@
package gocsv

import "time"
import (
"fmt"
"time"
)

type MarshallerStruct struct {
Foo string
Bar int
}

func (m MarshallerStruct) MarshalCSV() (string, error) {
return fmt.Sprintf("%s %d", m.Foo, m.Bar), nil
}

func (m MarshallerStruct) UnmarshalCSV(s string) error {
_, err := fmt.Sscanf("%s %d", s, &m.Foo, &m.Bar)
return err
}

type Sample struct {
Foo string `csv:"foo"`
Bar int `csv:"BAR"`
Baz string `csv:"Baz"`
Frop float64 `csv:"Quux"`
Blah *int `csv:"Blah"`
SPtr *string `csv:"SPtr"`
Omit *string `csv:"Omit,omitempty"`
Foo string `csv:"foo"`
Bar int `csv:"BAR"`
Baz string `csv:"Baz"`
Frop float64 `csv:"Quux"`
Blah *int `csv:"Blah"`
SPtr *string `csv:"SPtr"`
Marshaller MarshallerStruct `csv:"Marshaller"`
Omit *string `csv:"Omit,omitempty"`
}

type EmbedSample struct {
Expand Down