1// Copyright (C) 2021 The Android Open Source Project 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15package sdk 16 17import ( 18 "encoding/json" 19 "fmt" 20 "testing" 21 22 "android/soong/android" 23) 24 25// Tests for build_release.go 26 27var ( 28 // Some additional test specific releases that are added after the currently supported ones and 29 // so are treated as being for future releases. 30 buildReleaseFuture1 = initBuildRelease("F1") 31 buildReleaseFuture2 = initBuildRelease("F2") 32) 33 34func TestNameToRelease(t *testing.T) { 35 t.Run("single release", func(t *testing.T) { 36 release, err := nameToRelease("S") 37 android.AssertDeepEquals(t, "errors", nil, err) 38 android.AssertDeepEquals(t, "release", buildReleaseS, release) 39 }) 40 t.Run("invalid release", func(t *testing.T) { 41 release, err := nameToRelease("A") 42 android.AssertDeepEquals(t, "release", (*buildRelease)(nil), release) 43 // Uses a wildcard in the error message to allow for additional build releases to be added to 44 // the supported set without breaking this test. 45 android.FailIfNoMatchingErrors(t, `unknown release "A", expected one of \[S,T.*,F1,F2\]`, []error{err}) 46 }) 47} 48 49func TestParseBuildReleaseSet(t *testing.T) { 50 t.Run("single release", func(t *testing.T) { 51 set, err := parseBuildReleaseSet("S") 52 android.AssertDeepEquals(t, "errors", nil, err) 53 android.AssertStringEquals(t, "set", "[S]", set.String()) 54 }) 55 t.Run("open range", func(t *testing.T) { 56 set, err := parseBuildReleaseSet("F1+") 57 android.AssertDeepEquals(t, "errors", nil, err) 58 android.AssertStringEquals(t, "set", "[F1,F2]", set.String()) 59 }) 60 t.Run("closed range", func(t *testing.T) { 61 set, err := parseBuildReleaseSet("S-F1") 62 android.AssertDeepEquals(t, "errors", nil, err) 63 android.AssertStringEquals(t, "set", "[S,Tiramisu,F1]", set.String()) 64 }) 65 invalidAReleaseMessage := `unknown release "A", expected one of ` + allBuildReleaseSet.String() 66 t.Run("invalid release", func(t *testing.T) { 67 set, err := parseBuildReleaseSet("A") 68 android.AssertDeepEquals(t, "set", (*buildReleaseSet)(nil), set) 69 android.AssertStringDoesContain(t, "errors", fmt.Sprint(err), invalidAReleaseMessage) 70 }) 71 t.Run("invalid release in open range", func(t *testing.T) { 72 set, err := parseBuildReleaseSet("A+") 73 android.AssertDeepEquals(t, "set", (*buildReleaseSet)(nil), set) 74 android.AssertStringDoesContain(t, "errors", fmt.Sprint(err), invalidAReleaseMessage) 75 }) 76 t.Run("invalid release in closed range start", func(t *testing.T) { 77 set, err := parseBuildReleaseSet("A-S") 78 android.AssertDeepEquals(t, "set", (*buildReleaseSet)(nil), set) 79 android.AssertStringDoesContain(t, "errors", fmt.Sprint(err), invalidAReleaseMessage) 80 }) 81 t.Run("invalid release in closed range end", func(t *testing.T) { 82 set, err := parseBuildReleaseSet("Tiramisu-A") 83 android.AssertDeepEquals(t, "set", (*buildReleaseSet)(nil), set) 84 android.AssertStringDoesContain(t, "errors", fmt.Sprint(err), invalidAReleaseMessage) 85 }) 86 t.Run("invalid closed range reversed", func(t *testing.T) { 87 set, err := parseBuildReleaseSet("F1-S") 88 android.AssertDeepEquals(t, "set", (*buildReleaseSet)(nil), set) 89 android.AssertStringDoesContain(t, "errors", fmt.Sprint(err), `invalid closed range, start release "F1" is later than end release "S"`) 90 }) 91} 92 93func TestBuildReleaseSetContains(t *testing.T) { 94 t.Run("contains", func(t *testing.T) { 95 set, _ := parseBuildReleaseSet("F1-F2") 96 android.AssertBoolEquals(t, "set contains F1", true, set.contains(buildReleaseFuture1)) 97 android.AssertBoolEquals(t, "set does not contain S", false, set.contains(buildReleaseS)) 98 android.AssertBoolEquals(t, "set contains F2", true, set.contains(buildReleaseFuture2)) 99 android.AssertBoolEquals(t, "set does not contain T", false, set.contains(buildReleaseT)) 100 }) 101} 102 103func TestPropertyPrunerInvalidTag(t *testing.T) { 104 type brokenStruct struct { 105 Broken string `supported_build_releases:"A"` 106 } 107 type containingStruct struct { 108 Nested brokenStruct 109 } 110 111 t.Run("broken struct", func(t *testing.T) { 112 android.AssertPanicMessageContains(t, "error", "invalid `supported_build_releases` tag on Broken of *sdk.brokenStruct: unknown release \"A\"", func() { 113 newPropertyPrunerByBuildRelease(&brokenStruct{}, buildReleaseS) 114 }) 115 }) 116 117 t.Run("nested broken struct", func(t *testing.T) { 118 android.AssertPanicMessageContains(t, "error", "invalid `supported_build_releases` tag on Nested.Broken of *sdk.containingStruct: unknown release \"A\"", func() { 119 newPropertyPrunerByBuildRelease(&containingStruct{}, buildReleaseS) 120 }) 121 }) 122} 123 124func TestPropertyPrunerByBuildRelease(t *testing.T) { 125 type nested struct { 126 F1_only string `supported_build_releases:"F1"` 127 } 128 129 type mapped struct { 130 Default string 131 T_only string `supported_build_releases:"Tiramisu"` 132 } 133 134 type testBuildReleasePruner struct { 135 Default string 136 S_and_T_only string `supported_build_releases:"S-Tiramisu"` 137 T_later string `supported_build_releases:"Tiramisu+"` 138 Nested nested 139 Mapped map[string]*mapped 140 } 141 142 inputFactory := func() testBuildReleasePruner { 143 return testBuildReleasePruner{ 144 Default: "Default", 145 S_and_T_only: "S_and_T_only", 146 T_later: "T_later", 147 Nested: nested{ 148 F1_only: "F1_only", 149 }, 150 Mapped: map[string]*mapped{ 151 "one": { 152 Default: "one-default", 153 T_only: "one-t-only", 154 }, 155 "two": { 156 Default: "two-default", 157 T_only: "two-t-only", 158 }, 159 }, 160 } 161 } 162 163 marshal := func(t interface{}) string { 164 bytes, err := json.MarshalIndent(t, "", " ") 165 if err != nil { 166 panic(err) 167 } 168 return string(bytes) 169 } 170 171 assertJsonEquals := func(t *testing.T, expected, actual interface{}) { 172 t.Helper() 173 expectedJson := marshal(expected) 174 actualJson := marshal(actual) 175 if actualJson != expectedJson { 176 t.Errorf("test struct: expected:\n%s\n got:\n%s", expectedJson, actualJson) 177 } 178 } 179 180 t.Run("target S", func(t *testing.T) { 181 testStruct := inputFactory() 182 pruner := newPropertyPrunerByBuildRelease(&testStruct, buildReleaseS) 183 pruner.pruneProperties(&testStruct) 184 185 expected := inputFactory() 186 expected.T_later = "" 187 expected.Nested.F1_only = "" 188 expected.Mapped["one"].T_only = "" 189 expected.Mapped["two"].T_only = "" 190 assertJsonEquals(t, expected, testStruct) 191 }) 192 193 t.Run("target T", func(t *testing.T) { 194 testStruct := inputFactory() 195 pruner := newPropertyPrunerByBuildRelease(&testStruct, buildReleaseT) 196 pruner.pruneProperties(&testStruct) 197 198 expected := inputFactory() 199 expected.Nested.F1_only = "" 200 assertJsonEquals(t, expected, testStruct) 201 }) 202 203 t.Run("target F1", func(t *testing.T) { 204 testStruct := inputFactory() 205 pruner := newPropertyPrunerByBuildRelease(&testStruct, buildReleaseFuture1) 206 pruner.pruneProperties(&testStruct) 207 208 expected := inputFactory() 209 expected.S_and_T_only = "" 210 expected.Mapped["one"].T_only = "" 211 expected.Mapped["two"].T_only = "" 212 assertJsonEquals(t, expected, testStruct) 213 }) 214 215 t.Run("target F2", func(t *testing.T) { 216 testStruct := inputFactory() 217 pruner := newPropertyPrunerByBuildRelease(&testStruct, buildReleaseFuture2) 218 pruner.pruneProperties(&testStruct) 219 220 expected := inputFactory() 221 expected.S_and_T_only = "" 222 expected.Nested.F1_only = "" 223 expected.Mapped["one"].T_only = "" 224 expected.Mapped["two"].T_only = "" 225 assertJsonEquals(t, expected, testStruct) 226 }) 227} 228