From 7b985a9175e70d6891ad85507e73c0140dc0d86d Mon Sep 17 00:00:00 2001 From: Nicolas Mahe Date: Tue, 10 Sep 2019 18:06:50 +0700 Subject: [PATCH 1/3] Only bypass hash tag if it an type interface containing a struct or a pointer --- hash/structhash/structhash.go | 2 +- hash/structhash/structhash_test.go | 28 ++++++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/hash/structhash/structhash.go b/hash/structhash/structhash.go index 0d50188dd..9de949619 100644 --- a/hash/structhash/structhash.go +++ b/hash/structhash/structhash.go @@ -102,7 +102,7 @@ func write(buf *bytes.Buffer, v reflect.Value) *bytes.Buffer { // NOTE: structhash will allow to process all interface types. // gogo/protobuf is not able to set tags for directly oneof interface. // see: https://github.com/gogo/protobuf/issues/623 - if to.name == "" && reflect.Zero(sf.Type).Kind() == reflect.Interface { + if to.name == "" && reflect.Zero(sf.Type).Kind() == reflect.Interface && (v.Field(i).Elem().Kind() == reflect.Struct || v.Field(i).Elem().Kind() == reflect.Ptr) { to.skip = false to.name = sf.Name } diff --git a/hash/structhash/structhash_test.go b/hash/structhash/structhash_test.go index 5ac573f46..9434830ff 100644 --- a/hash/structhash/structhash_test.go +++ b/hash/structhash/structhash_test.go @@ -139,6 +139,34 @@ func TestDump(t *testing.T) { }{b: false}}, "{a:{b:false}}", }, + { + struct { + a interface{} + }{ + struct { + b int + c interface{} + }{ + b: 1, + c: 2, + }, + }, + "{a:{}}", + }, + { + struct { + a interface{} + }{ + &struct { + b int `hash:"name:b"` + c interface{} `hash:"name:c"` + }{ + b: 1, + c: 2, + }, + }, + "{a:{b:1,c:2}}", + }, } for _, tt := range tests { From 417fc35ca9ee36f9bf59b562b3623b4deb772e96 Mon Sep 17 00:00:00 2001 From: Nicolas Mahe Date: Tue, 10 Sep 2019 18:29:29 +0700 Subject: [PATCH 2/3] Only traverse pointer of struct for hash calculation --- hash/structhash/structhash.go | 2 +- hash/structhash/structhash_test.go | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/hash/structhash/structhash.go b/hash/structhash/structhash.go index 9de949619..9d706515b 100644 --- a/hash/structhash/structhash.go +++ b/hash/structhash/structhash.go @@ -102,7 +102,7 @@ func write(buf *bytes.Buffer, v reflect.Value) *bytes.Buffer { // NOTE: structhash will allow to process all interface types. // gogo/protobuf is not able to set tags for directly oneof interface. // see: https://github.com/gogo/protobuf/issues/623 - if to.name == "" && reflect.Zero(sf.Type).Kind() == reflect.Interface && (v.Field(i).Elem().Kind() == reflect.Struct || v.Field(i).Elem().Kind() == reflect.Ptr) { + if to.name == "" && reflect.Zero(sf.Type).Kind() == reflect.Interface && (v.Field(i).Elem().Kind() == reflect.Struct || (v.Field(i).Elem().Kind() == reflect.Ptr && v.Field(i).Elem().Elem().Kind() == reflect.Struct)) { to.skip = false to.name = sf.Name } diff --git a/hash/structhash/structhash_test.go b/hash/structhash/structhash_test.go index 9434830ff..b3ea85ec3 100644 --- a/hash/structhash/structhash_test.go +++ b/hash/structhash/structhash_test.go @@ -22,6 +22,7 @@ func TestMd5(t *testing.T) { //nolint:megacheck func TestDump(t *testing.T) { + int1 := int(1) tests := []struct { v interface{} s string @@ -167,6 +168,20 @@ func TestDump(t *testing.T) { }, "{a:{b:1,c:2}}", }, + { + struct { + a interface{} + }{ + &struct { + b *int + c interface{} + }{ + b: &int1, + c: &int1, + }, + }, + "{a:{}}", + }, } for _, tt := range tests { From ea408ca241736635aa6b054ec4100edb54887b83 Mon Sep 17 00:00:00 2001 From: Nicolas Mahe Date: Tue, 10 Sep 2019 18:34:51 +0700 Subject: [PATCH 3/3] add tests --- hash/structhash/structhash_test.go | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/hash/structhash/structhash_test.go b/hash/structhash/structhash_test.go index b3ea85ec3..b7c86a513 100644 --- a/hash/structhash/structhash_test.go +++ b/hash/structhash/structhash_test.go @@ -182,6 +182,26 @@ func TestDump(t *testing.T) { }, "{a:{}}", }, + { + struct { + a interface{} + }{ + &struct { + b *int + c interface{} + }{ + b: nil, + c: nil, + }, + }, + "{a:{}}", + }, + { + struct { + a interface{} + }{nil}, + "{}", + }, } for _, tt := range tests {