1// Copyright 2019 Google Inc. All rights reserved. 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 android 16 17import ( 18 "testing" 19) 20 21type soongConfigTestDefaultsModuleProperties struct { 22} 23 24type soongConfigTestDefaultsModule struct { 25 ModuleBase 26 DefaultsModuleBase 27} 28 29func soongConfigTestDefaultsModuleFactory() Module { 30 m := &soongConfigTestDefaultsModule{} 31 m.AddProperties(&soongConfigTestModuleProperties{}) 32 InitDefaultsModule(m) 33 return m 34} 35 36type soongConfigTestModule struct { 37 ModuleBase 38 DefaultableModuleBase 39 props soongConfigTestModuleProperties 40} 41 42type soongConfigTestModuleProperties struct { 43 Cflags []string 44} 45 46func soongConfigTestModuleFactory() Module { 47 m := &soongConfigTestModule{} 48 m.AddProperties(&m.props) 49 InitAndroidModule(m) 50 InitDefaultableModule(m) 51 return m 52} 53 54func (t soongConfigTestModule) GenerateAndroidBuildActions(ModuleContext) {} 55 56func TestSoongConfigModule(t *testing.T) { 57 configBp := ` 58 soong_config_module_type { 59 name: "acme_test", 60 module_type: "test", 61 config_namespace: "acme", 62 variables: ["board", "feature1", "FEATURE3", "unused_string_var"], 63 bool_variables: ["feature2", "unused_feature"], 64 value_variables: ["size", "unused_size"], 65 properties: ["cflags", "srcs", "defaults"], 66 } 67 68 soong_config_string_variable { 69 name: "board", 70 values: ["soc_a", "soc_b", "soc_c", "soc_d"], 71 } 72 73 soong_config_string_variable { 74 name: "unused_string_var", 75 values: ["a", "b"], 76 } 77 78 soong_config_bool_variable { 79 name: "feature1", 80 } 81 82 soong_config_bool_variable { 83 name: "FEATURE3", 84 } 85 ` 86 87 importBp := ` 88 soong_config_module_type_import { 89 from: "SoongConfig.bp", 90 module_types: ["acme_test"], 91 } 92 ` 93 94 bp := ` 95 test_defaults { 96 name: "foo_defaults", 97 cflags: ["DEFAULT"], 98 } 99 100 acme_test { 101 name: "foo", 102 cflags: ["-DGENERIC"], 103 defaults: ["foo_defaults"], 104 soong_config_variables: { 105 board: { 106 soc_a: { 107 cflags: ["-DSOC_A"], 108 }, 109 soc_b: { 110 cflags: ["-DSOC_B"], 111 }, 112 soc_c: {}, 113 conditions_default: { 114 cflags: ["-DSOC_CONDITIONS_DEFAULT"], 115 }, 116 }, 117 size: { 118 cflags: ["-DSIZE=%s"], 119 conditions_default: { 120 cflags: ["-DSIZE=CONDITIONS_DEFAULT"], 121 }, 122 }, 123 feature1: { 124 conditions_default: { 125 cflags: ["-DF1_CONDITIONS_DEFAULT"], 126 }, 127 cflags: ["-DFEATURE1"], 128 }, 129 feature2: { 130 cflags: ["-DFEATURE2"], 131 conditions_default: { 132 cflags: ["-DF2_CONDITIONS_DEFAULT"], 133 }, 134 }, 135 FEATURE3: { 136 cflags: ["-DFEATURE3"], 137 }, 138 }, 139 } 140 141 test_defaults { 142 name: "foo_defaults_a", 143 cflags: ["DEFAULT_A"], 144 } 145 146 test_defaults { 147 name: "foo_defaults_b", 148 cflags: ["DEFAULT_B"], 149 } 150 151 acme_test { 152 name: "foo_with_defaults", 153 cflags: ["-DGENERIC"], 154 defaults: ["foo_defaults"], 155 soong_config_variables: { 156 board: { 157 soc_a: { 158 cflags: ["-DSOC_A"], 159 defaults: ["foo_defaults_a"], 160 }, 161 soc_b: { 162 cflags: ["-DSOC_B"], 163 defaults: ["foo_defaults_b"], 164 }, 165 soc_c: {}, 166 }, 167 size: { 168 cflags: ["-DSIZE=%s"], 169 }, 170 feature1: { 171 cflags: ["-DFEATURE1"], 172 }, 173 feature2: { 174 cflags: ["-DFEATURE2"], 175 }, 176 FEATURE3: { 177 cflags: ["-DFEATURE3"], 178 }, 179 }, 180 } 181 ` 182 183 fixtureForVendorVars := func(vars map[string]map[string]string) FixturePreparer { 184 return FixtureModifyProductVariables(func(variables FixtureProductVariables) { 185 variables.VendorVars = vars 186 }) 187 } 188 189 run := func(t *testing.T, bp string, fs MockFS) { 190 testCases := []struct { 191 name string 192 preparer FixturePreparer 193 fooExpectedFlags []string 194 fooDefaultsExpectedFlags []string 195 }{ 196 { 197 name: "withValues", 198 preparer: fixtureForVendorVars(map[string]map[string]string{ 199 "acme": { 200 "board": "soc_a", 201 "size": "42", 202 "feature1": "true", 203 "feature2": "false", 204 // FEATURE3 unset 205 "unused_feature": "true", // unused 206 "unused_size": "1", // unused 207 "unused_string_var": "a", // unused 208 }, 209 }), 210 fooExpectedFlags: []string{ 211 "DEFAULT", 212 "-DGENERIC", 213 "-DF2_CONDITIONS_DEFAULT", 214 "-DSIZE=42", 215 "-DSOC_A", 216 "-DFEATURE1", 217 }, 218 fooDefaultsExpectedFlags: []string{ 219 "DEFAULT_A", 220 "DEFAULT", 221 "-DGENERIC", 222 "-DSIZE=42", 223 "-DSOC_A", 224 "-DFEATURE1", 225 }, 226 }, 227 { 228 name: "empty_prop_for_string_var", 229 preparer: fixtureForVendorVars(map[string]map[string]string{ 230 "acme": {"board": "soc_c"}}), 231 fooExpectedFlags: []string{ 232 "DEFAULT", 233 "-DGENERIC", 234 "-DF2_CONDITIONS_DEFAULT", 235 "-DSIZE=CONDITIONS_DEFAULT", 236 "-DF1_CONDITIONS_DEFAULT", 237 }, 238 fooDefaultsExpectedFlags: []string{ 239 "DEFAULT", 240 "-DGENERIC", 241 }, 242 }, 243 { 244 name: "unused_string_var", 245 preparer: fixtureForVendorVars(map[string]map[string]string{ 246 "acme": {"board": "soc_d"}}), 247 fooExpectedFlags: []string{ 248 "DEFAULT", 249 "-DGENERIC", 250 "-DF2_CONDITIONS_DEFAULT", 251 "-DSIZE=CONDITIONS_DEFAULT", 252 "-DSOC_CONDITIONS_DEFAULT", // foo does not contain a prop "soc_d", so we use the default 253 "-DF1_CONDITIONS_DEFAULT", 254 }, 255 fooDefaultsExpectedFlags: []string{ 256 "DEFAULT", 257 "-DGENERIC", 258 }, 259 }, 260 261 { 262 name: "conditions_default", 263 preparer: fixtureForVendorVars(map[string]map[string]string{}), 264 fooExpectedFlags: []string{ 265 "DEFAULT", 266 "-DGENERIC", 267 "-DF2_CONDITIONS_DEFAULT", 268 "-DSIZE=CONDITIONS_DEFAULT", 269 "-DSOC_CONDITIONS_DEFAULT", 270 "-DF1_CONDITIONS_DEFAULT", 271 }, 272 fooDefaultsExpectedFlags: []string{ 273 "DEFAULT", 274 "-DGENERIC", 275 }, 276 }, 277 } 278 279 for _, tc := range testCases { 280 t.Run(tc.name, func(t *testing.T) { 281 result := GroupFixturePreparers( 282 tc.preparer, 283 PrepareForTestWithDefaults, 284 FixtureRegisterWithContext(func(ctx RegistrationContext) { 285 ctx.RegisterModuleType("soong_config_module_type_import", soongConfigModuleTypeImportFactory) 286 ctx.RegisterModuleType("soong_config_module_type", soongConfigModuleTypeFactory) 287 ctx.RegisterModuleType("soong_config_string_variable", soongConfigStringVariableDummyFactory) 288 ctx.RegisterModuleType("soong_config_bool_variable", soongConfigBoolVariableDummyFactory) 289 ctx.RegisterModuleType("test_defaults", soongConfigTestDefaultsModuleFactory) 290 ctx.RegisterModuleType("test", soongConfigTestModuleFactory) 291 }), 292 fs.AddToFixture(), 293 FixtureWithRootAndroidBp(bp), 294 ).RunTest(t) 295 296 foo := result.ModuleForTests("foo", "").Module().(*soongConfigTestModule) 297 AssertDeepEquals(t, "foo cflags", tc.fooExpectedFlags, foo.props.Cflags) 298 299 fooDefaults := result.ModuleForTests("foo_with_defaults", "").Module().(*soongConfigTestModule) 300 AssertDeepEquals(t, "foo_with_defaults cflags", tc.fooDefaultsExpectedFlags, fooDefaults.props.Cflags) 301 }) 302 } 303 } 304 305 t.Run("single file", func(t *testing.T) { 306 run(t, configBp+bp, nil) 307 }) 308 309 t.Run("import", func(t *testing.T) { 310 run(t, importBp+bp, map[string][]byte{ 311 "SoongConfig.bp": []byte(configBp), 312 }) 313 }) 314} 315 316func testConfigWithVendorVars(buildDir, bp string, fs map[string][]byte, vendorVars map[string]map[string]string) Config { 317 config := TestConfig(buildDir, nil, bp, fs) 318 319 config.TestProductVariables.VendorVars = vendorVars 320 321 return config 322} 323