Unmarshal recursive structs (#557)
Co-authored-by: Nabetani <takenori@nabetani.sakura.ne.jp>
This commit is contained in:
@@ -370,6 +370,13 @@ func (d *decoder) handleKeyPart(key ast.Iterator, v reflect.Value, nextFn handle
|
||||
// First, dispatch over v to make sure it is a valid object.
|
||||
// There is no guarantee over what it could be.
|
||||
switch v.Kind() {
|
||||
case reflect.Ptr:
|
||||
elem := v.Elem()
|
||||
if !elem.IsValid() {
|
||||
v.Set(reflect.New(v.Type().Elem()))
|
||||
}
|
||||
elem = v.Elem()
|
||||
return d.handleKeyPart(key, elem, nextFn, makeFn)
|
||||
case reflect.Map:
|
||||
// Create the key for the map element. For now assume it's a string.
|
||||
mk := reflect.ValueOf(string(key.Node().Data))
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package toml_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
@@ -2120,6 +2121,177 @@ bar = 42
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnmarshal_RecursiveTable(t *testing.T) {
|
||||
type Foo struct {
|
||||
I int
|
||||
F *Foo
|
||||
}
|
||||
|
||||
examples := []struct {
|
||||
desc string
|
||||
input string
|
||||
expected string
|
||||
err bool
|
||||
}{
|
||||
{
|
||||
desc: "simplest",
|
||||
input: `
|
||||
I=1
|
||||
`,
|
||||
expected: `{"I":1,"F":null}`,
|
||||
},
|
||||
{
|
||||
desc: "depth 1",
|
||||
input: `
|
||||
I=1
|
||||
[F]
|
||||
I=2
|
||||
`,
|
||||
expected: `{"I":1,"F":{"I":2,"F":null}}`,
|
||||
},
|
||||
{
|
||||
desc: "depth 3",
|
||||
input: `
|
||||
I=1
|
||||
[F]
|
||||
I=2
|
||||
[F.F]
|
||||
I=3
|
||||
`,
|
||||
expected: `{"I":1,"F":{"I":2,"F":{"I":3,"F":null}}}`,
|
||||
},
|
||||
{
|
||||
desc: "depth 4",
|
||||
input: `
|
||||
I=1
|
||||
[F]
|
||||
I=2
|
||||
[F.F]
|
||||
I=3
|
||||
[F.F.F]
|
||||
I=4
|
||||
`,
|
||||
expected: `{"I":1,"F":{"I":2,"F":{"I":3,"F":{"I":4,"F":null}}}}`,
|
||||
},
|
||||
{
|
||||
desc: "skip mid step",
|
||||
input: `
|
||||
I=1
|
||||
[F.F]
|
||||
I=7
|
||||
`,
|
||||
expected: `{"I":1,"F":{"I":0,"F":{"I":7,"F":null}}}`,
|
||||
},
|
||||
}
|
||||
|
||||
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 := json.Marshal(foo)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, e.expected, string(j))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnmarshal_RecursiveTableArray(t *testing.T) {
|
||||
type Foo struct {
|
||||
I int
|
||||
F []*Foo
|
||||
}
|
||||
|
||||
examples := []struct {
|
||||
desc string
|
||||
input string
|
||||
expected string
|
||||
err bool
|
||||
}{
|
||||
{
|
||||
desc: "simplest",
|
||||
input: `
|
||||
I=1
|
||||
F=[]
|
||||
`,
|
||||
expected: `{"I":1,"F":[]}`,
|
||||
},
|
||||
{
|
||||
desc: "depth 1",
|
||||
input: `
|
||||
I=1
|
||||
[[F]]
|
||||
I=2
|
||||
F=[]
|
||||
`,
|
||||
expected: `{"I":1,"F":[{"I":2,"F":[]}]}`,
|
||||
},
|
||||
{
|
||||
desc: "depth 2",
|
||||
input: `
|
||||
I=1
|
||||
[[F]]
|
||||
I=2
|
||||
[[F.F]]
|
||||
I=3
|
||||
F=[]
|
||||
`,
|
||||
expected: `{"I":1,"F":[{"I":2,"F":[{"I":3,"F":[]}]}]}`,
|
||||
},
|
||||
{
|
||||
desc: "depth 3",
|
||||
input: `
|
||||
I=1
|
||||
[[F]]
|
||||
I=2
|
||||
[[F.F]]
|
||||
I=3
|
||||
[[F.F.F]]
|
||||
I=4
|
||||
F=[]
|
||||
`,
|
||||
expected: `{"I":1,"F":[{"I":2,"F":[{"I":3,"F":[{"I":4,"F":[]}]}]}]}`,
|
||||
},
|
||||
{
|
||||
desc: "depth 4",
|
||||
input: `
|
||||
I=1
|
||||
[[F]]
|
||||
I=2
|
||||
[[F.F]]
|
||||
I=3
|
||||
[[F.F.F]]
|
||||
I=4
|
||||
[[F.F.F.F]]
|
||||
I=5
|
||||
F=[]
|
||||
`,
|
||||
expected: `{"I":1,"F":[{"I":2,"F":[{"I":3,"F":[{"I":4,"F":[{"I":5,"F":[]}]}]}]}]}`,
|
||||
},
|
||||
}
|
||||
|
||||
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 := json.Marshal(foo)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, e.expected, string(j))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func ExampleDecoder_SetStrict() {
|
||||
type S struct {
|
||||
Key1 string
|
||||
|
||||
Reference in New Issue
Block a user