Make unmarshal to interface{} consistent with encoding/json

This commit is contained in:
Thomas Pelletier
2021-03-23 20:03:45 -04:00
parent 0703eeb262
commit bfeb32c9ce
3 changed files with 51 additions and 32 deletions
@@ -126,10 +126,10 @@ func TestInterface(t *testing.T) {
expected := Conf{
Name: "rui",
Age: 18,
Inter: &NestedStruct{
FirstName: "wang",
LastName: "jl",
Age: 100,
Inter: map[string]interface{}{
"FirstName": "wang",
"LastName": "jl",
"Age": int64(100),
},
}
assert.Equal(t, expected, config)
@@ -1663,25 +1663,21 @@ Age = 23
},
NilField: nil,
InterfacePointerField: &s,
StructArrayField: []map[string]interface{}{
{
StructArrayField: []interface{}{
map[string]interface{}{
"Name": "Allen",
"Age": int64(20),
},
{
map[string]interface{}{
"Name": "Jack",
"Age": int64(23),
},
},
}
actual := OuterStruct{}
if err := toml.Unmarshal(doc, &actual); err == nil {
if !reflect.DeepEqual(actual, expected) {
t.Errorf("Bad unmarshal: expected %v, got %v", expected, actual)
}
} else {
t.Fatal(err)
}
err := toml.Unmarshal(doc, &actual)
require.NoError(t, err)
assert.Equal(t, expected, actual)
}
func TestUnmarshalToNonNilInterface(t *testing.T) {
@@ -1727,8 +1723,8 @@ InnerField = "After4"
var s interface{} = InnerStruct{"After"}
expected := OuterStruct{
PrimitiveField: "Allen",
ArrayField: []int{1, 2, 3},
StructField: InnerStruct{InnerField: "After1"},
ArrayField: []interface{}{int64(1), int64(2), int64(3)},
StructField: map[string]interface{}{"InnerField": "After1"},
MapField: map[string]interface{}{
"MapField1": []interface{}{int64(4), int64(5), int64(6)},
"MapField2": map[string]interface{}{
@@ -1736,12 +1732,12 @@ InnerField = "After4"
},
"MapField3": false,
},
PointerField: &InnerStruct{InnerField: "After2"},
PointerField: map[string]interface{}{"InnerField": "After2"},
NilField: nil,
InterfacePointerField: &s,
StructArrayField: []InnerStruct{
{InnerField: "After3"},
{InnerField: "After4"},
StructArrayField: []interface{}{
map[string]interface{}{"InnerField": "After3"},
map[string]interface{}{"InnerField": "After4"},
},
}
actual := OuterStruct{
@@ -1763,13 +1759,10 @@ InnerField = "After4"
{InnerField: "Before4"},
},
}
if err := toml.Unmarshal(doc, &actual); err == nil {
if !reflect.DeepEqual(actual, expected) {
t.Errorf("Bad unmarshal: expected %v, got %v", expected, actual)
}
} else {
t.Fatal(err)
}
err := toml.Unmarshal(doc, &actual)
require.NoError(t, err)
assert.Equal(t, expected, actual)
}
func TestUnmarshalNil(t *testing.T) {
+6 -5
View File
@@ -129,10 +129,10 @@ func ensureSlice(t target) error {
return t.set(reflect.MakeSlice(f.Type(), 0, 0))
}
case reflect.Interface:
if f.IsNil() {
if f.IsNil() || f.Elem().Type() != sliceInterfaceType {
return t.set(reflect.MakeSlice(sliceInterfaceType, 0, 0))
}
if f.Type().Elem().Kind() != reflect.Slice {
if f.Elem().Type().Kind() != reflect.Slice {
return fmt.Errorf("interface is pointing to a %s, not a slice", f.Kind())
}
case reflect.Ptr:
@@ -152,6 +152,7 @@ func ensureSlice(t target) error {
}
var sliceInterfaceType = reflect.TypeOf([]interface{}{})
var mapStringInterfaceType = reflect.TypeOf(map[string]interface{}{})
func setString(t target, v string) error {
f := t.get()
@@ -409,15 +410,15 @@ func initInterface(append bool, t target) error {
panic("this should only be called on interfaces")
}
if !x.IsNil() {
if !x.IsNil() && (x.Elem().Type() == sliceInterfaceType || x.Elem().Type() == mapStringInterfaceType) {
return nil
}
var newElement reflect.Value
if append {
newElement = reflect.MakeSlice(reflect.TypeOf([]interface{}{}), 0, 0)
newElement = reflect.MakeSlice(sliceInterfaceType, 0, 0)
} else {
newElement = reflect.MakeMap(reflect.TypeOf(map[string]interface{}{}))
newElement = reflect.MakeMap(mapStringInterfaceType)
}
err := t.set(newElement)
if err != nil {
+25
View File
@@ -588,6 +588,31 @@ B = "data"`,
}
},
},
{
desc: "interface holding a struct",
input: `[A]
B = "After"`,
gen: func() test {
type inner struct {
B interface{}
}
type doc struct {
A interface{}
}
return test{
target: &doc{
A: inner{
B: "Before",
},
},
expected: &doc{
A: map[string]interface{}{
"B": "After",
},
},
}
},
},
}
for _, e := range examples {