Minor restructuring of the build_release pruning code to make it easier to add logic for handling fields of maps of structs. That includes: 1. Moving some code that is specific to clearing a selected field inside the associated if block. 2. Replacing an if with a switch. 3. Improving the error handling by separating the reporting of the container that broke from information about which field could not be set. That allows follow up code to provide information about the map key instead. The tests were restructed by: 1. Switching from using AssertDeepEquals to compare the structs to comparing the output of marshalling the structs to JSON. That was for a couple of reasons. Firstly, because JSON will marshal (and so allow comparison of) the contents of pointers to structs whereas AssertDeepEquals will just compare the pointers themselves. Secondly, because JSON can pretty print the output and make it easier to read. 2. Using a func to create a new instance of the input structure for each test. That is to allow the test to modify the input structure, e.g. by clearing a field in a struct that is pointed to by a map. The test previously relied on the input structure being immutable and passed by value but a follow up change will change that by adding a map field that contains pointers to structs. Bug: 204763318 Test: m nothing Change-Id: I84dc99621497b7263e30466895b823eb02cb2b56
206 lines
7.0 KiB
Go
206 lines
7.0 KiB
Go
// Copyright (C) 2021 The Android Open Source Project
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package sdk
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"testing"
|
|
|
|
"android/soong/android"
|
|
)
|
|
|
|
// Tests for build_release.go
|
|
|
|
var (
|
|
// Some additional test specific releases that are added after the currently supported ones and
|
|
// so are treated as being for future releases.
|
|
buildReleaseFuture1 = initBuildRelease("F1")
|
|
buildReleaseFuture2 = initBuildRelease("F2")
|
|
)
|
|
|
|
func TestNameToRelease(t *testing.T) {
|
|
t.Run("single release", func(t *testing.T) {
|
|
release, err := nameToRelease("S")
|
|
android.AssertDeepEquals(t, "errors", nil, err)
|
|
android.AssertDeepEquals(t, "release", buildReleaseS, release)
|
|
})
|
|
t.Run("invalid release", func(t *testing.T) {
|
|
release, err := nameToRelease("A")
|
|
android.AssertDeepEquals(t, "release", (*buildRelease)(nil), release)
|
|
// Uses a wildcard in the error message to allow for additional build releases to be added to
|
|
// the supported set without breaking this test.
|
|
android.FailIfNoMatchingErrors(t, `unknown release "A", expected one of \[S,T.*,F1,F2\]`, []error{err})
|
|
})
|
|
}
|
|
|
|
func TestParseBuildReleaseSet(t *testing.T) {
|
|
t.Run("single release", func(t *testing.T) {
|
|
set, err := parseBuildReleaseSet("S")
|
|
android.AssertDeepEquals(t, "errors", nil, err)
|
|
android.AssertStringEquals(t, "set", "[S]", set.String())
|
|
})
|
|
t.Run("open range", func(t *testing.T) {
|
|
set, err := parseBuildReleaseSet("F1+")
|
|
android.AssertDeepEquals(t, "errors", nil, err)
|
|
android.AssertStringEquals(t, "set", "[F1,F2]", set.String())
|
|
})
|
|
t.Run("closed range", func(t *testing.T) {
|
|
set, err := parseBuildReleaseSet("S-F1")
|
|
android.AssertDeepEquals(t, "errors", nil, err)
|
|
android.AssertStringEquals(t, "set", "[S,T,F1]", set.String())
|
|
})
|
|
invalidAReleaseMessage := `unknown release "A", expected one of ` + allBuildReleaseSet.String()
|
|
t.Run("invalid release", func(t *testing.T) {
|
|
set, err := parseBuildReleaseSet("A")
|
|
android.AssertDeepEquals(t, "set", (*buildReleaseSet)(nil), set)
|
|
android.AssertStringDoesContain(t, "errors", fmt.Sprint(err), invalidAReleaseMessage)
|
|
})
|
|
t.Run("invalid release in open range", func(t *testing.T) {
|
|
set, err := parseBuildReleaseSet("A+")
|
|
android.AssertDeepEquals(t, "set", (*buildReleaseSet)(nil), set)
|
|
android.AssertStringDoesContain(t, "errors", fmt.Sprint(err), invalidAReleaseMessage)
|
|
})
|
|
t.Run("invalid release in closed range start", func(t *testing.T) {
|
|
set, err := parseBuildReleaseSet("A-S")
|
|
android.AssertDeepEquals(t, "set", (*buildReleaseSet)(nil), set)
|
|
android.AssertStringDoesContain(t, "errors", fmt.Sprint(err), invalidAReleaseMessage)
|
|
})
|
|
t.Run("invalid release in closed range end", func(t *testing.T) {
|
|
set, err := parseBuildReleaseSet("T-A")
|
|
android.AssertDeepEquals(t, "set", (*buildReleaseSet)(nil), set)
|
|
android.AssertStringDoesContain(t, "errors", fmt.Sprint(err), invalidAReleaseMessage)
|
|
})
|
|
t.Run("invalid closed range reversed", func(t *testing.T) {
|
|
set, err := parseBuildReleaseSet("F1-S")
|
|
android.AssertDeepEquals(t, "set", (*buildReleaseSet)(nil), set)
|
|
android.AssertStringDoesContain(t, "errors", fmt.Sprint(err), `invalid closed range, start release "F1" is later than end release "S"`)
|
|
})
|
|
}
|
|
|
|
func TestBuildReleaseSetContains(t *testing.T) {
|
|
t.Run("contains", func(t *testing.T) {
|
|
set, _ := parseBuildReleaseSet("F1-F2")
|
|
android.AssertBoolEquals(t, "set contains F1", true, set.contains(buildReleaseFuture1))
|
|
android.AssertBoolEquals(t, "set does not contain S", false, set.contains(buildReleaseS))
|
|
android.AssertBoolEquals(t, "set contains F2", true, set.contains(buildReleaseFuture2))
|
|
android.AssertBoolEquals(t, "set does not contain T", false, set.contains(buildReleaseT))
|
|
})
|
|
}
|
|
|
|
func TestPropertyPrunerInvalidTag(t *testing.T) {
|
|
type brokenStruct struct {
|
|
Broken string `supported_build_releases:"A"`
|
|
}
|
|
type containingStruct struct {
|
|
Nested brokenStruct
|
|
}
|
|
|
|
t.Run("broken struct", func(t *testing.T) {
|
|
android.AssertPanicMessageContains(t, "error", "invalid `supported_build_releases` tag on Broken of *sdk.brokenStruct: unknown release \"A\"", func() {
|
|
newPropertyPrunerByBuildRelease(&brokenStruct{}, buildReleaseS)
|
|
})
|
|
})
|
|
|
|
t.Run("nested broken struct", func(t *testing.T) {
|
|
android.AssertPanicMessageContains(t, "error", "invalid `supported_build_releases` tag on Nested.Broken of *sdk.containingStruct: unknown release \"A\"", func() {
|
|
newPropertyPrunerByBuildRelease(&containingStruct{}, buildReleaseS)
|
|
})
|
|
})
|
|
}
|
|
|
|
func TestPropertyPrunerByBuildRelease(t *testing.T) {
|
|
type nested struct {
|
|
F1_only string `supported_build_releases:"F1"`
|
|
}
|
|
|
|
type testBuildReleasePruner struct {
|
|
Default string
|
|
S_and_T_only string `supported_build_releases:"S-T"`
|
|
T_later string `supported_build_releases:"T+"`
|
|
Nested nested
|
|
}
|
|
|
|
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 := inputFactory()
|
|
pruner := newPropertyPrunerByBuildRelease(&testStruct, buildReleaseS)
|
|
pruner.pruneProperties(&testStruct)
|
|
|
|
expected := inputFactory()
|
|
expected.T_later = ""
|
|
expected.Nested.F1_only = ""
|
|
assertJsonEquals(t, expected, testStruct)
|
|
})
|
|
|
|
t.Run("target T", func(t *testing.T) {
|
|
testStruct := inputFactory()
|
|
pruner := newPropertyPrunerByBuildRelease(&testStruct, buildReleaseT)
|
|
pruner.pruneProperties(&testStruct)
|
|
|
|
expected := inputFactory()
|
|
expected.Nested.F1_only = ""
|
|
assertJsonEquals(t, expected, testStruct)
|
|
})
|
|
|
|
t.Run("target F1", func(t *testing.T) {
|
|
testStruct := inputFactory()
|
|
pruner := newPropertyPrunerByBuildRelease(&testStruct, buildReleaseFuture1)
|
|
pruner.pruneProperties(&testStruct)
|
|
|
|
expected := inputFactory()
|
|
expected.S_and_T_only = ""
|
|
assertJsonEquals(t, expected, testStruct)
|
|
})
|
|
|
|
t.Run("target F2", func(t *testing.T) {
|
|
testStruct := inputFactory()
|
|
pruner := newPropertyPrunerByBuildRelease(&testStruct, buildReleaseFuture2)
|
|
pruner.pruneProperties(&testStruct)
|
|
|
|
expected := inputFactory()
|
|
expected.S_and_T_only = ""
|
|
expected.Nested.F1_only = ""
|
|
assertJsonEquals(t, expected, testStruct)
|
|
})
|
|
}
|