gocarina / gocsv

The GoCSV package aims to provide easy CSV serialization and deserialization to the golang programming language
MIT License
1.99k stars 245 forks source link

UnmarshalString cannot parse string from MarshalString #263

Open PatrLind opened 1 year ago

PatrLind commented 1 year ago

I get a panic trying to unmarshal a string marshaled by marshal. This happens when I try to use json struct tag as the field name.

The output is:

$ go test /tmp/gocsv_test.go 
str name,subObj.a,subObj.b,subObjs
Obj1,a1,b1,"[{""a"":""a2"",""b"":""b2""},{""a"":""a3"",""b"":""b3""}]"

--- FAIL: TestCSV (0.00s)
    --- FAIL: TestCSV/test_1_json (0.00s)
panic: reflect: call of reflect.Value.Field on zero Value [recovered]
        panic: reflect: call of reflect.Value.Field on zero Value

goroutine 7 [running]:
testing.tRunner.func1.2({0x54b8a0, 0xc000012288})
        /usr/local/go/src/testing/testing.go:1545 +0x238
testing.tRunner.func1()
        /usr/local/go/src/testing/testing.go:1548 +0x397
panic({0x54b8a0?, 0xc000012288?})
        /usr/local/go/src/runtime/panic.go:914 +0x21f
reflect.Value.Field({0x0?, 0x0?, 0xc0000169f0?}, 0xc0000d39e0?)
        /usr/local/go/src/reflect/value.go:1278 +0xcf
reflect.Value.FieldByIndex({0x0?, 0x0?, 0x404da8?}, {0xc000014268?, 0x0?, 0xc0000169f0?})
        /usr/local/go/src/reflect/value.go:1311 +0x4e
github.com/gocarina/gocsv.setInnerField(0xc0000d3aa8?, 0xf0?, {0xc000014268?, 0x1, 0x1}, {0xc000020404, 0x2}, 0x28?)
        /home/patrik/go/pkg/mod/github.com/gocarina/gocsv@v0.0.0-20230616125104-99d496ca653d/decode.go:504 +0x69c
github.com/gocarina/gocsv.setInnerField(0x54d640?, 0x0?, {0xc000014260?, 0x2, 0x2}, {0xc000020404, 0x2}, 0x70?)
        /home/patrik/go/pkg/mod/github.com/gocarina/gocsv@v0.0.0-20230616125104-99d496ca653d/decode.go:502 +0x67c
github.com/gocarina/gocsv.readToWithErrorHandler({0x7fd9c18a2898, 0xc00002c590}, 0x0, {0x543400?, 0xc000012228?})
        /home/patrik/go/pkg/mod/github.com/gocarina/gocsv@v0.0.0-20230616125104-99d496ca653d/decode.go:226 +0x7c8
github.com/gocarina/gocsv.readTo(...)
        /home/patrik/go/pkg/mod/github.com/gocarina/gocsv@v0.0.0-20230616125104-99d496ca653d/decode.go:144
github.com/gocarina/gocsv.Unmarshal({0x5a9580?, 0xc00007e160?}, {0x543400, 0xc000012228})
        /home/patrik/go/pkg/mod/github.com/gocarina/gocsv@v0.0.0-20230616125104-99d496ca653d/csv.go:214 +0x7d
github.com/gocarina/gocsv.UnmarshalString(...)
        /home/patrik/go/pkg/mod/github.com/gocarina/gocsv@v0.0.0-20230616125104-99d496ca653d/csv.go:204
command-line-arguments.TestCSV.func1(0xc0000c24e0)
        /tmp/gocsv_test.go:57 +0x19b
testing.tRunner(0xc0000c24e0, 0xc000016690)
        /usr/local/go/src/testing/testing.go:1595 +0xff
created by testing.(*T).Run in goroutine 6
        /usr/local/go/src/testing/testing.go:1648 +0x3ad
FAIL    command-line-arguments  0.004s
FAIL

Test code:

package main

import (
    "fmt"
    "testing"

    "github.com/gocarina/gocsv"
)

type TestObj struct {
    Name    string     `json:"name,omitempty"`
    SubObj  *TestOb2   `json:"subObj,omitempty"`
    SubObjs []*TestOb2 `json:"subObjs,omitempty"`
}

type TestOb2 struct {
    A string `json:"a,omitempty"`
    B string `json:"b,omitempty"`
}

func TestCSV(t *testing.T) {
    obj1 := []*TestObj{
        {
            Name: "Obj1",
            SubObj: &TestOb2{
                A: "a1",
                B: "b1",
            },
            SubObjs: []*TestOb2{
                {
                    A: "a2",
                    B: "b2",
                },
                {
                    A: "a3",
                    B: "b3",
                },
            },
        },
    }

    testCases := []struct {
        TagName string
    }{
        {"json"}, {"csv"},
    }
    for i, tc := range testCases {
        tc := tc
        t.Run(fmt.Sprintf("test_%d_%s", i+1, tc.TagName), func(t *testing.T) {
            gocsv.TagName = tc.TagName
            str, err := gocsv.MarshalString(obj1)
            if err != nil {
                t.Error(err)
            }
            obj2 := []*TestObj{}
            fmt.Println("str", str)
            err = gocsv.UnmarshalString(str, &obj2)
            if err != nil {
                t.Error(err)
            }
        })
    }
}