Make unmarshal to interface{} consistent with encoding/json
This commit is contained in:
@@ -126,10 +126,10 @@ func TestInterface(t *testing.T) {
|
|||||||
expected := Conf{
|
expected := Conf{
|
||||||
Name: "rui",
|
Name: "rui",
|
||||||
Age: 18,
|
Age: 18,
|
||||||
Inter: &NestedStruct{
|
Inter: map[string]interface{}{
|
||||||
FirstName: "wang",
|
"FirstName": "wang",
|
||||||
LastName: "jl",
|
"LastName": "jl",
|
||||||
Age: 100,
|
"Age": int64(100),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
assert.Equal(t, expected, config)
|
assert.Equal(t, expected, config)
|
||||||
@@ -1663,25 +1663,21 @@ Age = 23
|
|||||||
},
|
},
|
||||||
NilField: nil,
|
NilField: nil,
|
||||||
InterfacePointerField: &s,
|
InterfacePointerField: &s,
|
||||||
StructArrayField: []map[string]interface{}{
|
StructArrayField: []interface{}{
|
||||||
{
|
map[string]interface{}{
|
||||||
"Name": "Allen",
|
"Name": "Allen",
|
||||||
"Age": int64(20),
|
"Age": int64(20),
|
||||||
},
|
},
|
||||||
{
|
map[string]interface{}{
|
||||||
"Name": "Jack",
|
"Name": "Jack",
|
||||||
"Age": int64(23),
|
"Age": int64(23),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
actual := OuterStruct{}
|
actual := OuterStruct{}
|
||||||
if err := toml.Unmarshal(doc, &actual); err == nil {
|
err := toml.Unmarshal(doc, &actual)
|
||||||
if !reflect.DeepEqual(actual, expected) {
|
require.NoError(t, err)
|
||||||
t.Errorf("Bad unmarshal: expected %v, got %v", expected, actual)
|
assert.Equal(t, expected, actual)
|
||||||
}
|
|
||||||
} else {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUnmarshalToNonNilInterface(t *testing.T) {
|
func TestUnmarshalToNonNilInterface(t *testing.T) {
|
||||||
@@ -1727,8 +1723,8 @@ InnerField = "After4"
|
|||||||
var s interface{} = InnerStruct{"After"}
|
var s interface{} = InnerStruct{"After"}
|
||||||
expected := OuterStruct{
|
expected := OuterStruct{
|
||||||
PrimitiveField: "Allen",
|
PrimitiveField: "Allen",
|
||||||
ArrayField: []int{1, 2, 3},
|
ArrayField: []interface{}{int64(1), int64(2), int64(3)},
|
||||||
StructField: InnerStruct{InnerField: "After1"},
|
StructField: map[string]interface{}{"InnerField": "After1"},
|
||||||
MapField: map[string]interface{}{
|
MapField: map[string]interface{}{
|
||||||
"MapField1": []interface{}{int64(4), int64(5), int64(6)},
|
"MapField1": []interface{}{int64(4), int64(5), int64(6)},
|
||||||
"MapField2": map[string]interface{}{
|
"MapField2": map[string]interface{}{
|
||||||
@@ -1736,12 +1732,12 @@ InnerField = "After4"
|
|||||||
},
|
},
|
||||||
"MapField3": false,
|
"MapField3": false,
|
||||||
},
|
},
|
||||||
PointerField: &InnerStruct{InnerField: "After2"},
|
PointerField: map[string]interface{}{"InnerField": "After2"},
|
||||||
NilField: nil,
|
NilField: nil,
|
||||||
InterfacePointerField: &s,
|
InterfacePointerField: &s,
|
||||||
StructArrayField: []InnerStruct{
|
StructArrayField: []interface{}{
|
||||||
{InnerField: "After3"},
|
map[string]interface{}{"InnerField": "After3"},
|
||||||
{InnerField: "After4"},
|
map[string]interface{}{"InnerField": "After4"},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
actual := OuterStruct{
|
actual := OuterStruct{
|
||||||
@@ -1763,13 +1759,10 @@ InnerField = "After4"
|
|||||||
{InnerField: "Before4"},
|
{InnerField: "Before4"},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
if err := toml.Unmarshal(doc, &actual); err == nil {
|
|
||||||
if !reflect.DeepEqual(actual, expected) {
|
err := toml.Unmarshal(doc, &actual)
|
||||||
t.Errorf("Bad unmarshal: expected %v, got %v", expected, actual)
|
require.NoError(t, err)
|
||||||
}
|
assert.Equal(t, expected, actual)
|
||||||
} else {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUnmarshalNil(t *testing.T) {
|
func TestUnmarshalNil(t *testing.T) {
|
||||||
|
|||||||
+6
-5
@@ -129,10 +129,10 @@ func ensureSlice(t target) error {
|
|||||||
return t.set(reflect.MakeSlice(f.Type(), 0, 0))
|
return t.set(reflect.MakeSlice(f.Type(), 0, 0))
|
||||||
}
|
}
|
||||||
case reflect.Interface:
|
case reflect.Interface:
|
||||||
if f.IsNil() {
|
if f.IsNil() || f.Elem().Type() != sliceInterfaceType {
|
||||||
return t.set(reflect.MakeSlice(sliceInterfaceType, 0, 0))
|
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())
|
return fmt.Errorf("interface is pointing to a %s, not a slice", f.Kind())
|
||||||
}
|
}
|
||||||
case reflect.Ptr:
|
case reflect.Ptr:
|
||||||
@@ -152,6 +152,7 @@ func ensureSlice(t target) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var sliceInterfaceType = reflect.TypeOf([]interface{}{})
|
var sliceInterfaceType = reflect.TypeOf([]interface{}{})
|
||||||
|
var mapStringInterfaceType = reflect.TypeOf(map[string]interface{}{})
|
||||||
|
|
||||||
func setString(t target, v string) error {
|
func setString(t target, v string) error {
|
||||||
f := t.get()
|
f := t.get()
|
||||||
@@ -409,15 +410,15 @@ func initInterface(append bool, t target) error {
|
|||||||
panic("this should only be called on interfaces")
|
panic("this should only be called on interfaces")
|
||||||
}
|
}
|
||||||
|
|
||||||
if !x.IsNil() {
|
if !x.IsNil() && (x.Elem().Type() == sliceInterfaceType || x.Elem().Type() == mapStringInterfaceType) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var newElement reflect.Value
|
var newElement reflect.Value
|
||||||
if append {
|
if append {
|
||||||
newElement = reflect.MakeSlice(reflect.TypeOf([]interface{}{}), 0, 0)
|
newElement = reflect.MakeSlice(sliceInterfaceType, 0, 0)
|
||||||
} else {
|
} else {
|
||||||
newElement = reflect.MakeMap(reflect.TypeOf(map[string]interface{}{}))
|
newElement = reflect.MakeMap(mapStringInterfaceType)
|
||||||
}
|
}
|
||||||
err := t.set(newElement)
|
err := t.set(newElement)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -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 {
|
for _, e := range examples {
|
||||||
|
|||||||
Reference in New Issue
Block a user