Loading sdk/build_release.go +39 −27 Original line number Diff line number Diff line Loading @@ -230,7 +230,9 @@ func (p *propertyPruner) gatherFields(structType reflect.Type, containingStructA return container.Field(fieldIndex) } zeroValue := reflect.Zero(field.Type) 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 Loading @@ -243,7 +245,7 @@ func (p *propertyPruner) gatherFields(structType reflect.Type, containingStructA 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())) panic(fmt.Errorf("%s\n\tfor field (index %d, name %s)", r, fieldIndex, name)) } }() Loading @@ -251,13 +253,14 @@ func (p *propertyPruner) gatherFields(structType reflect.Type, containingStructA 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 { } else { switch fieldType.Kind() { case reflect.Struct: // Gather fields from the nested or embedded structure. var subNamePrefix string if field.Anonymous { Loading @@ -265,16 +268,25 @@ func (p *propertyPruner) gatherFields(structType reflect.Type, containingStructA } else { subNamePrefix = name + "." } p.gatherFields(field.Type, fieldGetter, subNamePrefix, selector) p.gatherFields(fieldType, 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) Loading sdk/build_release_test.go +39 −19 Original line number Diff line number Diff line Loading @@ -15,6 +15,7 @@ package sdk import ( "encoding/json" "fmt" "testing" Loading Loading @@ -132,7 +133,8 @@ func TestPropertyPrunerByBuildRelease(t *testing.T) { Nested nested } input := testBuildReleasePruner{ inputFactory := func() testBuildReleasePruner { return testBuildReleasePruner{ Default: "Default", S_and_T_only: "S_and_T_only", T_later: "T_later", Loading @@ -140,46 +142,64 @@ func TestPropertyPrunerByBuildRelease(t *testing.T) { 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) }) } Loading
sdk/build_release.go +39 −27 Original line number Diff line number Diff line Loading @@ -230,7 +230,9 @@ func (p *propertyPruner) gatherFields(structType reflect.Type, containingStructA return container.Field(fieldIndex) } zeroValue := reflect.Zero(field.Type) 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 Loading @@ -243,7 +245,7 @@ func (p *propertyPruner) gatherFields(structType reflect.Type, containingStructA 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())) panic(fmt.Errorf("%s\n\tfor field (index %d, name %s)", r, fieldIndex, name)) } }() Loading @@ -251,13 +253,14 @@ func (p *propertyPruner) gatherFields(structType reflect.Type, containingStructA 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 { } else { switch fieldType.Kind() { case reflect.Struct: // Gather fields from the nested or embedded structure. var subNamePrefix string if field.Anonymous { Loading @@ -265,16 +268,25 @@ func (p *propertyPruner) gatherFields(structType reflect.Type, containingStructA } else { subNamePrefix = name + "." } p.gatherFields(field.Type, fieldGetter, subNamePrefix, selector) p.gatherFields(fieldType, 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) Loading
sdk/build_release_test.go +39 −19 Original line number Diff line number Diff line Loading @@ -15,6 +15,7 @@ package sdk import ( "encoding/json" "fmt" "testing" Loading Loading @@ -132,7 +133,8 @@ func TestPropertyPrunerByBuildRelease(t *testing.T) { Nested nested } input := testBuildReleasePruner{ inputFactory := func() testBuildReleasePruner { return testBuildReleasePruner{ Default: "Default", S_and_T_only: "S_and_T_only", T_later: "T_later", Loading @@ -140,46 +142,64 @@ func TestPropertyPrunerByBuildRelease(t *testing.T) { 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) }) }