Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e183db7e69 | |||
| 60e4af8cca | |||
| 8bb1e08dc7 |
@@ -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,4 +2,4 @@ module github.com/pelletier/go-toml/v2
|
|||||||
|
|
||||||
go 1.16
|
go 1.16
|
||||||
|
|
||||||
require github.com/stretchr/testify v1.8.3
|
require github.com/stretchr/testify v1.8.4
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSS
|
|||||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY=
|
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||||
github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
|||||||
+2
-2
@@ -273,7 +273,7 @@ func (enc *Encoder) encode(b []byte, ctx encoderCtx, v reflect.Value) ([]byte, e
|
|||||||
return enc.encodeMap(b, ctx, v)
|
return enc.encodeMap(b, ctx, v)
|
||||||
case reflect.Struct:
|
case reflect.Struct:
|
||||||
return enc.encodeStruct(b, ctx, v)
|
return enc.encodeStruct(b, ctx, v)
|
||||||
case reflect.Slice:
|
case reflect.Slice, reflect.Array:
|
||||||
return enc.encodeSlice(b, ctx, v)
|
return enc.encodeSlice(b, ctx, v)
|
||||||
case reflect.Interface:
|
case reflect.Interface:
|
||||||
if v.IsNil() {
|
if v.IsNil() {
|
||||||
@@ -930,7 +930,7 @@ func willConvertToTableOrArrayTable(ctx encoderCtx, v reflect.Value) bool {
|
|||||||
return willConvertToTableOrArrayTable(ctx, v.Elem())
|
return willConvertToTableOrArrayTable(ctx, v.Elem())
|
||||||
}
|
}
|
||||||
|
|
||||||
if t.Kind() == reflect.Slice {
|
if t.Kind() == reflect.Slice || t.Kind() == reflect.Array {
|
||||||
if v.Len() == 0 {
|
if v.Len() == 0 {
|
||||||
// An empty slice should be a kv = [].
|
// An empty slice should be a kv = [].
|
||||||
return false
|
return false
|
||||||
|
|||||||
@@ -206,6 +206,45 @@ b-1 = 'value 3'
|
|||||||
|
|
||||||
[[top]]
|
[[top]]
|
||||||
'map2.1' = 'v2.1'
|
'map2.1' = 'v2.1'
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "fixed size string array",
|
||||||
|
v: map[string][3]string{
|
||||||
|
"array": {"one", "two", "three"},
|
||||||
|
},
|
||||||
|
expected: `array = ['one', 'two', 'three']
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "fixed size nested string arrays",
|
||||||
|
v: map[string][2][2]string{
|
||||||
|
"array": {{"one", "two"}, {"three"}},
|
||||||
|
},
|
||||||
|
expected: `array = [['one', 'two'], ['three', '']]
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "mixed strings and fixed size nested string arrays",
|
||||||
|
v: map[string][]interface{}{
|
||||||
|
"array": {"a string", [2]string{"one", "two"}, "last"},
|
||||||
|
},
|
||||||
|
expected: `array = ['a string', ['one', 'two'], 'last']
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "fixed size array of maps",
|
||||||
|
v: map[string][2]map[string]string{
|
||||||
|
"ftop": {
|
||||||
|
{"map1.1": "v1.1"},
|
||||||
|
{"map2.1": "v2.1"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: `[[ftop]]
|
||||||
|
'map1.1' = 'v1.1'
|
||||||
|
|
||||||
|
[[ftop]]
|
||||||
|
'map2.1' = 'v2.1'
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
+2
-2
@@ -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()))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user