diff --git a/proptools/clone.go b/proptools/clone.go index 7496584386cfd6be8a330b32c9ae250d0c193c01..3b23a5706d4cd858588b79141e7d0a42064c3546 100644 --- a/proptools/clone.go +++ b/proptools/clone.go @@ -140,7 +140,7 @@ func ZeroProperties(structValue reflect.Value) { fieldValue := structValue.Field(i) switch fieldValue.Kind() { - case reflect.Bool, reflect.String, reflect.Struct, reflect.Slice, reflect.Int, reflect.Uint: + case reflect.Bool, reflect.String, reflect.Slice, reflect.Int, reflect.Uint: fieldValue.Set(reflect.Zero(fieldValue.Type())) case reflect.Interface: if fieldValue.IsNil() { @@ -172,7 +172,8 @@ func ZeroProperties(structValue reflect.Value) { panic(fmt.Errorf("can't zero field %q: points to a %s", field.Name, fieldValue.Elem().Kind())) } - + case reflect.Struct: + ZeroProperties(fieldValue) default: panic(fmt.Errorf("unexpected kind for property struct field %q: %s", field.Name, fieldValue.Kind())) diff --git a/proptools/clone_test.go b/proptools/clone_test.go index f7460cf15de3576ee123cd524cf8c4c1ae8875b6..acbd50cddc6c95b443741d778bafcea22ef664b0 100644 --- a/proptools/clone_test.go +++ b/proptools/clone_test.go @@ -130,6 +130,26 @@ var clonePropertiesTestCases = []struct { }, }, { + // Clone nested interface + in: &struct { + Nested struct{ S interface{} } + }{ + Nested: struct{ S interface{} }{ + S: &struct{ S string }{ + S: "string1", + }, + }, + }, + out: &struct { + Nested struct{ S interface{} } + }{ + Nested: struct{ S interface{} }{ + S: &struct{ S string }{ + S: "string1", + }, + }, + }, + }, { // Empty struct in: &struct{}{}, out: &struct{}{}, @@ -267,6 +287,25 @@ var cloneEmptyPropertiesTestCases = []struct { S: &struct{ S string }{}, }, }, + { + // Clone nested interface + in: &struct { + Nested struct{ S interface{} } + }{ + Nested: struct{ S interface{} }{ + S: &struct{ S string }{ + S: "string1", + }, + }, + }, + out: &struct { + Nested struct{ S interface{} } + }{ + Nested: struct{ S interface{} }{ + S: &struct{ S string }{}, + }, + }, + }, { // Empty struct in: &struct{}{}, @@ -295,11 +334,61 @@ var cloneEmptyPropertiesTestCases = []struct { }, out: &struct{ S *struct{} }{}, }, + { + // Anonymous struct + in: &struct { + EmbeddedStruct + Nested struct{ EmbeddedStruct } + }{ + EmbeddedStruct: EmbeddedStruct{ + S: "string1", + }, + Nested: struct{ EmbeddedStruct }{ + EmbeddedStruct: EmbeddedStruct{ + S: "string2", + }, + }, + }, + out: &struct { + EmbeddedStruct + Nested struct{ EmbeddedStruct } + }{ + EmbeddedStruct: EmbeddedStruct{}, + Nested: struct{ EmbeddedStruct }{ + EmbeddedStruct: EmbeddedStruct{}, + }, + }, + }, + { + // Anonymous interface + in: &struct { + EmbeddedInterface + Nested struct{ EmbeddedInterface } + }{ + EmbeddedInterface: &struct{ S string }{ + S: "string1", + }, + Nested: struct{ EmbeddedInterface }{ + EmbeddedInterface: &struct{ S string }{ + S: "string2", + }, + }, + }, + out: &struct { + EmbeddedInterface + Nested struct{ EmbeddedInterface } + }{ + EmbeddedInterface: &struct{ S string }{}, + Nested: struct{ EmbeddedInterface }{ + EmbeddedInterface: &struct{ S string }{}, + }, + }, + }, } func TestCloneEmptyProperties(t *testing.T) { for _, testCase := range cloneEmptyPropertiesTestCases { - testString := fmt.Sprintf("%s", testCase.in) + testString := fmt.Sprintf("%#v", testCase.in) got := CloneEmptyProperties(reflect.ValueOf(testCase.in).Elem()).Interface() @@ -314,9 +403,9 @@ func TestCloneEmptyProperties(t *testing.T) { func TestZeroProperties(t *testing.T) { for _, testCase := range cloneEmptyPropertiesTestCases { - testString := fmt.Sprintf("%s", testCase.in) + testString := fmt.Sprintf("%#v", testCase.in) - got := CloneEmptyProperties(reflect.ValueOf(testCase.in).Elem()).Interface() + got := CloneProperties(reflect.ValueOf(testCase.in).Elem()).Interface() ZeroProperties(reflect.ValueOf(got).Elem()) if !reflect.DeepEqual(testCase.out, got) {