diff options
| -rw-r--r-- | sdk/build_release.go | 66 | ||||
| -rw-r--r-- | sdk/build_release_test.go | 58 |
2 files changed, 78 insertions, 46 deletions
diff --git a/sdk/build_release.go b/sdk/build_release.go index a3f089973..212582ac6 100644 --- a/sdk/build_release.go +++ b/sdk/build_release.go @@ -230,51 +230,63 @@ func (p *propertyPruner) gatherFields(structType reflect.Type, containingStructA return container.Field(fieldIndex) } - zeroValue := reflect.Zero(field.Type) - fieldPruner := func(container reflect.Value) { - if containingStructAccessor != nil { - // This is an embedded structure so first access the field for the embedded - // structure. - container = containingStructAccessor(container) - } + fieldType := field.Type + if selector(name, field) { + zeroValue := reflect.Zero(fieldType) + fieldPruner := func(container reflect.Value) { + if containingStructAccessor != nil { + // This is an embedded structure so first access the field for the embedded + // structure. + container = containingStructAccessor(container) + } - // Skip through interface and pointer values to find the structure. - container = getStructValue(container) + // Skip through interface and pointer values to find the structure. + container = getStructValue(container) - defer func() { - if r := recover(); r != nil { - panic(fmt.Errorf("%s for fieldIndex %d of field %s of container %#v", r, fieldIndex, name, container.Interface())) - } - }() + defer func() { + if r := recover(); r != nil { + panic(fmt.Errorf("%s\n\tfor field (index %d, name %s)", r, fieldIndex, name)) + } + }() - // Set the field. - container.Field(fieldIndex).Set(zeroValue) - } + // Set the field. + container.Field(fieldIndex).Set(zeroValue) + } - if selector(name, field) { property := prunerProperty{ name, fieldPruner, } p.properties = append(p.properties, property) - } else if field.Type.Kind() == reflect.Struct { - // Gather fields from the nested or embedded structure. - var subNamePrefix string - if field.Anonymous { - subNamePrefix = namePrefix - } else { - subNamePrefix = name + "." + } else { + switch fieldType.Kind() { + case reflect.Struct: + // Gather fields from the nested or embedded structure. + var subNamePrefix string + if field.Anonymous { + subNamePrefix = namePrefix + } else { + subNamePrefix = name + "." + } + p.gatherFields(fieldType, fieldGetter, subNamePrefix, selector) } - p.gatherFields(field.Type, fieldGetter, subNamePrefix, selector) } } } -// pruneProperties will prune (set to zero value) any properties in the supplied struct. +// pruneProperties will prune (set to zero value) any properties in the struct referenced by the +// supplied struct pointer. // // The struct must be of the same type as was originally passed to newPropertyPruner to create this // propertyPruner. func (p *propertyPruner) pruneProperties(propertiesStruct interface{}) { + + defer func() { + if r := recover(); r != nil { + panic(fmt.Errorf("%s\n\tof container %#v", r, propertiesStruct)) + } + }() + structValue := reflect.ValueOf(propertiesStruct) for _, property := range p.properties { property.prunerFunc(structValue) diff --git a/sdk/build_release_test.go b/sdk/build_release_test.go index dff276d0c..0ec10409f 100644 --- a/sdk/build_release_test.go +++ b/sdk/build_release_test.go @@ -15,6 +15,7 @@ package sdk import ( + "encoding/json" "fmt" "testing" @@ -132,54 +133,73 @@ func TestPropertyPrunerByBuildRelease(t *testing.T) { Nested nested } - input := testBuildReleasePruner{ - Default: "Default", - S_and_T_only: "S_and_T_only", - T_later: "T_later", - Nested: nested{ - F1_only: "F1_only", - }, + inputFactory := func() testBuildReleasePruner { + return testBuildReleasePruner{ + Default: "Default", + S_and_T_only: "S_and_T_only", + T_later: "T_later", + Nested: nested{ + F1_only: "F1_only", + }, + } + } + + marshal := func(t interface{}) string { + bytes, err := json.MarshalIndent(t, "", " ") + if err != nil { + panic(err) + } + return string(bytes) + } + + assertJsonEquals := func(t *testing.T, expected, actual interface{}) { + t.Helper() + expectedJson := marshal(expected) + actualJson := marshal(actual) + if actualJson != expectedJson { + t.Errorf("test struct: expected:\n%s\n got:\n%s", expectedJson, actualJson) + } } t.Run("target S", func(t *testing.T) { - testStruct := input + testStruct := inputFactory() pruner := newPropertyPrunerByBuildRelease(&testStruct, buildReleaseS) pruner.pruneProperties(&testStruct) - expected := input + expected := inputFactory() expected.T_later = "" expected.Nested.F1_only = "" - android.AssertDeepEquals(t, "test struct", expected, testStruct) + assertJsonEquals(t, expected, testStruct) }) t.Run("target T", func(t *testing.T) { - testStruct := input + testStruct := inputFactory() pruner := newPropertyPrunerByBuildRelease(&testStruct, buildReleaseT) pruner.pruneProperties(&testStruct) - expected := input + expected := inputFactory() expected.Nested.F1_only = "" - android.AssertDeepEquals(t, "test struct", expected, testStruct) + assertJsonEquals(t, expected, testStruct) }) t.Run("target F1", func(t *testing.T) { - testStruct := input + testStruct := inputFactory() pruner := newPropertyPrunerByBuildRelease(&testStruct, buildReleaseFuture1) pruner.pruneProperties(&testStruct) - expected := input + expected := inputFactory() expected.S_and_T_only = "" - android.AssertDeepEquals(t, "test struct", expected, testStruct) + assertJsonEquals(t, expected, testStruct) }) t.Run("target F2", func(t *testing.T) { - testStruct := input + testStruct := inputFactory() pruner := newPropertyPrunerByBuildRelease(&testStruct, buildReleaseFuture2) pruner.pruneProperties(&testStruct) - expected := input + expected := inputFactory() expected.S_and_T_only = "" expected.Nested.F1_only = "" - android.AssertDeepEquals(t, "test struct", expected, testStruct) + assertJsonEquals(t, expected, testStruct) }) } |