Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e183db7e69 | |||
| 60e4af8cca | |||
| 8bb1e08dc7 |
@@ -79,6 +79,7 @@ cover() {
|
||||
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
|
||||
go tool cover -func=coverage.out
|
||||
echo "Coverage profile for ${branch}: ${dir}/coverage.out" >&2
|
||||
popd
|
||||
|
||||
if [ "${branch}" != "HEAD" ]; then
|
||||
|
||||
@@ -2,4 +2,4 @@ module github.com/pelletier/go-toml/v2
|
||||
|
||||
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/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.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY=
|
||||
github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||
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/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
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)
|
||||
case reflect.Struct:
|
||||
return enc.encodeStruct(b, ctx, v)
|
||||
case reflect.Slice:
|
||||
case reflect.Slice, reflect.Array:
|
||||
return enc.encodeSlice(b, ctx, v)
|
||||
case reflect.Interface:
|
||||
if v.IsNil() {
|
||||
@@ -930,7 +930,7 @@ func willConvertToTableOrArrayTable(ctx encoderCtx, v reflect.Value) bool {
|
||||
return willConvertToTableOrArrayTable(ctx, v.Elem())
|
||||
}
|
||||
|
||||
if t.Kind() == reflect.Slice {
|
||||
if t.Kind() == reflect.Slice || t.Kind() == reflect.Array {
|
||||
if v.Len() == 0 {
|
||||
// An empty slice should be a kv = [].
|
||||
return false
|
||||
|
||||
@@ -206,6 +206,45 @@ b-1 = 'value 3'
|
||||
|
||||
[[top]]
|
||||
'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.
|
||||
func fieldByIndex(v reflect.Value, path []int) reflect.Value {
|
||||
for i, x := range path {
|
||||
for _, x := range path {
|
||||
v = v.Field(x)
|
||||
|
||||
if i < len(path)-1 && v.Kind() == reflect.Ptr {
|
||||
if v.Kind() == reflect.Ptr {
|
||||
if v.IsNil() {
|
||||
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",
|
||||
input: `foo = "bar"`,
|
||||
@@ -3511,3 +3569,47 @@ func TestUnmarshalEmbedNonString(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
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