From 022970d970af03abe3b84776d7bb34637ade66bc Mon Sep 17 00:00:00 2001 From: Guillaume Scott Date: Fri, 19 Jun 2020 11:26:49 -0400 Subject: [PATCH 1/3] Allow decoding embedded struct pointer --- mapstructure.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/mapstructure.go b/mapstructure.go index b384d9d9..72d5e307 100644 --- a/mapstructure.go +++ b/mapstructure.go @@ -894,6 +894,11 @@ func (d *Decoder) decodeMapFromStruct(name string, dataVal reflect.Value, val re keyName = tagValue } + // This is an embedded struct pointer, handle it as a embedded struct below + if v.Kind() == reflect.Ptr && reflect.Indirect(v).Kind() == reflect.Struct { + v = reflect.Indirect(v) + } + switch v.Kind() { // this is an embedded struct, so handle it differently case reflect.Struct: From 4ee867eae6894a29980fb934f171b4faf2814679 Mon Sep 17 00:00:00 2001 From: Guillaume Scott Date: Fri, 19 Jun 2020 11:54:42 -0400 Subject: [PATCH 2/3] Adjust unit test to new behavior for nested struct pointer --- mapstructure_test.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/mapstructure_test.go b/mapstructure_test.go index 63614e83..261a57a0 100644 --- a/mapstructure_test.go +++ b/mapstructure_test.go @@ -2322,6 +2322,11 @@ func TestDecode_StructTaggedWithOmitempty_KeepNonEmptyValues(t *testing.T) { var emptySlice []interface{} var emptyMap map[string]interface{} var emptyNested *Nested + nestedMap := map[string]interface{}{} + err := Decode(input.OmitNestedField, &nestedMap) + if err != nil { + t.Fatalf("got an err: %s", err.Error()) + } expected := &map[string]interface{}{ "visible-string": "", "omittable-string": "string", @@ -2334,7 +2339,7 @@ func TestDecode_StructTaggedWithOmitempty_KeepNonEmptyValues(t *testing.T) { "visible-map": emptyMap, "omittable-map": map[string]interface{}{"k": "v"}, "visible-nested": emptyNested, - "omittable-nested": &Nested{}, + "omittable-nested": nestedMap, } actual := &map[string]interface{}{} From 1ccc1c6b2196b2edb40b66f6a674f17c86596c6b Mon Sep 17 00:00:00 2001 From: Guillaume Scott Date: Sun, 21 Jun 2020 21:44:37 -0400 Subject: [PATCH 3/3] Add test case for nested struct pointer decoding --- mapstructure_test.go | 43 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 36 insertions(+), 7 deletions(-) diff --git a/mapstructure_test.go b/mapstructure_test.go index 261a57a0..86ebb1b7 100644 --- a/mapstructure_test.go +++ b/mapstructure_test.go @@ -1352,6 +1352,41 @@ func TestNestedTypePointer(t *testing.T) { } } +func TestNestedTypeStructPointer(t *testing.T) { + t.Parallel() + + nestedInput := Basic{ + Vstring: "foo", + Vint: 42, + Vbool: true, + } + input := NestedPointer{ + Vfoo: "foo", + Vbar: &nestedInput, + } + + // nestedResult is validated in TestBasicTypes + nestedResult := map[string]interface{}{} + err := Decode(nestedInput, &nestedResult) + if err != nil { + t.Fatalf("got an err: %s", err.Error()) + } + + result := map[string]interface{}{} + err = Decode(input, &result) + if err != nil { + t.Fatalf("got an err: %s", err.Error()) + } + + expected := map[string]interface{}{ + "Vfoo": "foo", + "Vbar": nestedResult, + } + if !reflect.DeepEqual(result, expected) { + t.Errorf("bad: %#v", result) + } +} + // Test for issue #46. func TestNestedTypeInterface(t *testing.T) { t.Parallel() @@ -2316,17 +2351,12 @@ func TestDecode_StructTaggedWithOmitempty_KeepNonEmptyValues(t *testing.T) { VisibleMapField: nil, OmitMapField: map[string]interface{}{"k": "v"}, NestedField: nil, - OmitNestedField: &Nested{}, + OmitNestedField: nil, } var emptySlice []interface{} var emptyMap map[string]interface{} var emptyNested *Nested - nestedMap := map[string]interface{}{} - err := Decode(input.OmitNestedField, &nestedMap) - if err != nil { - t.Fatalf("got an err: %s", err.Error()) - } expected := &map[string]interface{}{ "visible-string": "", "omittable-string": "string", @@ -2339,7 +2369,6 @@ func TestDecode_StructTaggedWithOmitempty_KeepNonEmptyValues(t *testing.T) { "visible-map": emptyMap, "omittable-map": map[string]interface{}{"k": "v"}, "visible-nested": emptyNested, - "omittable-nested": nestedMap, } actual := &map[string]interface{}{}