Decode: assigned empty struct to empty defined sections (#879)

Co-authored-by: Thomas Pelletier <thomas@pelletier.codes>
This commit is contained in:
David Barroso
2023-07-12 16:53:17 +02:00
committed by GitHub
parent 60e4af8cca
commit e183db7e69
3 changed files with 105 additions and 2 deletions
+1
View File
@@ -79,6 +79,7 @@ cover() {
go test -covermode=atomic -coverpkg=./... -coverprofile=coverage.out.tmp ./... go test -covermode=atomic -coverpkg=./... -coverprofile=coverage.out.tmp ./...
cat coverage.out.tmp | grep -v fuzz | grep -v testsuite | grep -v tomltestgen | grep -v gotoml-test-decoder > coverage.out cat coverage.out.tmp | grep -v fuzz | grep -v testsuite | grep -v tomltestgen | grep -v gotoml-test-decoder > coverage.out
go tool cover -func=coverage.out go tool cover -func=coverage.out
echo "Coverage profile for ${branch}: ${dir}/coverage.out" >&2
popd popd
if [ "${branch}" != "HEAD" ]; then if [ "${branch}" != "HEAD" ]; then
+2 -2
View File
@@ -1170,10 +1170,10 @@ func initAndDereferencePointer(v reflect.Value) reflect.Value {
// Same as reflect.Value.FieldByIndex, but creates pointers if needed. // Same as reflect.Value.FieldByIndex, but creates pointers if needed.
func fieldByIndex(v reflect.Value, path []int) reflect.Value { func fieldByIndex(v reflect.Value, path []int) reflect.Value {
for i, x := range path { for _, x := range path {
v = v.Field(x) v = v.Field(x)
if i < len(path)-1 && v.Kind() == reflect.Ptr { if v.Kind() == reflect.Ptr {
if v.IsNil() { if v.IsNil() {
v.Set(reflect.New(v.Type().Elem())) v.Set(reflect.New(v.Type().Elem()))
} }
+102
View File
@@ -1277,6 +1277,64 @@ B = "data"`,
} }
}, },
}, },
{
desc: "array table into maps with pointer on last key",
input: `[[foo]]
bar = "hello"`,
gen: func() test {
type doc struct {
Foo **[]interface{}
}
x := &[]interface{}{
map[string]interface{}{
"bar": "hello",
},
}
return test{
target: &doc{},
expected: &doc{
Foo: &x,
},
}
},
},
{
desc: "array table into maps with pointer on intermediate key",
input: `[[foo.foo2]]
bar = "hello"`,
gen: func() test {
type doc struct {
Foo **map[string]interface{}
}
x := &map[string]interface{}{
"foo2": []interface{}{
map[string]interface{}{
"bar": "hello",
},
},
}
return test{
target: &doc{},
expected: &doc{
Foo: &x,
},
}
},
},
{
desc: "array table into maps with pointer on last key with invalid leaf type",
input: `[[foo]]
bar = "hello"`,
gen: func() test {
type doc struct {
Foo **[]map[string]int
}
return test{
target: &doc{},
err: true,
}
},
},
{ {
desc: "unexported struct fields are ignored", desc: "unexported struct fields are ignored",
input: `foo = "bar"`, input: `foo = "bar"`,
@@ -3511,3 +3569,47 @@ func TestUnmarshalEmbedNonString(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
require.Nil(t, d.Foo) require.Nil(t, d.Foo)
} }
func TestUnmarshal_Nil(t *testing.T) {
type Foo struct {
Foo *Foo `toml:"foo,omitempty"`
Bar *Foo `toml:"bar,omitempty"`
}
examples := []struct {
desc string
input string
expected string
err bool
}{
{
desc: "empty",
input: ``,
expected: ``,
},
{
desc: "simplest",
input: `
[foo]
[foo.foo]
`,
expected: "[foo]\n[foo.foo]\n",
},
}
for _, ex := range examples {
e := ex
t.Run(e.desc, func(t *testing.T) {
foo := Foo{}
err := toml.Unmarshal([]byte(e.input), &foo)
if e.err {
require.Error(t, err)
} else {
require.NoError(t, err)
j, err := toml.Marshal(foo)
require.NoError(t, err)
assert.Equal(t, e.expected, string(j))
}
})
}
}