1// Copyright 2015 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 "reflect" 19 "strconv" 20 "testing" 21 22 "github.com/google/blueprint/proptools" 23) 24 25type printfIntoPropertyTestCase struct { 26 in string 27 val interface{} 28 out string 29 err bool 30} 31 32var printfIntoPropertyTestCases = []printfIntoPropertyTestCase{ 33 { 34 in: "%d", 35 val: 0, 36 out: "0", 37 }, 38 { 39 in: "%d", 40 val: 1, 41 out: "1", 42 }, 43 { 44 in: "%d", 45 val: 2, 46 out: "2", 47 }, 48 { 49 in: "%d", 50 val: false, 51 out: "0", 52 }, 53 { 54 in: "%d", 55 val: true, 56 out: "1", 57 }, 58 { 59 in: "%d", 60 val: -1, 61 out: "-1", 62 }, 63 64 { 65 in: "-DA=%d", 66 val: 1, 67 out: "-DA=1", 68 }, 69 { 70 in: "-DA=%du", 71 val: 1, 72 out: "-DA=1u", 73 }, 74 { 75 in: "-DA=%s", 76 val: "abc", 77 out: "-DA=abc", 78 }, 79 { 80 in: `-DA="%s"`, 81 val: "abc", 82 out: `-DA="abc"`, 83 }, 84 85 { 86 in: "%%", 87 err: true, 88 }, 89 { 90 in: "%d%s", 91 err: true, 92 }, 93 { 94 in: "%d,%s", 95 err: true, 96 }, 97 { 98 in: "%d", 99 val: "", 100 err: true, 101 }, 102 { 103 in: "%d", 104 val: 1.5, 105 err: true, 106 }, 107 { 108 in: "%f", 109 val: 1.5, 110 err: true, 111 }, 112} 113 114func TestPrintfIntoProperty(t *testing.T) { 115 for _, testCase := range printfIntoPropertyTestCases { 116 s := testCase.in 117 v := reflect.ValueOf(&s).Elem() 118 err := printfIntoProperty(v, testCase.val) 119 if err != nil && !testCase.err { 120 t.Errorf("unexpected error %s", err) 121 } else if err == nil && testCase.err { 122 t.Errorf("expected error") 123 } else if err == nil && v.String() != testCase.out { 124 t.Errorf("expected %q got %q", testCase.out, v.String()) 125 } 126 } 127} 128 129type testProductVariableModule struct { 130 ModuleBase 131} 132 133func (m *testProductVariableModule) GenerateAndroidBuildActions(ctx ModuleContext) { 134} 135 136var testProductVariableProperties = struct { 137 Product_variables struct { 138 Eng struct { 139 Srcs []string 140 Cflags []string 141 } 142 } 143}{} 144 145func testProductVariableModuleFactoryFactory(props interface{}) func() Module { 146 return func() Module { 147 m := &testProductVariableModule{} 148 clonedProps := proptools.CloneProperties(reflect.ValueOf(props)).Interface() 149 m.AddProperties(clonedProps) 150 151 // Set a default soongConfigVariableProperties, this will be used as the input to the property struct filter 152 // for this test module. 153 m.variableProperties = testProductVariableProperties 154 InitAndroidModule(m) 155 return m 156 } 157} 158 159func TestProductVariables(t *testing.T) { 160 // Test that a module can use one product variable even if it doesn't have all the properties 161 // supported by that product variable. 162 bp := ` 163 module1 { 164 name: "foo", 165 product_variables: { 166 eng: { 167 srcs: ["foo.c"], 168 }, 169 }, 170 } 171 module2 { 172 name: "bar", 173 product_variables: { 174 eng: { 175 cflags: ["-DBAR"], 176 }, 177 }, 178 } 179 180 module3 { 181 name: "baz", 182 } 183 ` 184 185 GroupFixturePreparers( 186 FixtureModifyProductVariables(func(variables FixtureProductVariables) { 187 variables.Eng = proptools.BoolPtr(true) 188 }), 189 FixtureRegisterWithContext(func(ctx RegistrationContext) { 190 // A module type that has a srcs property but not a cflags property. 191 ctx.RegisterModuleType("module1", testProductVariableModuleFactoryFactory(&struct { 192 Srcs []string 193 }{})) 194 // A module type that has a cflags property but not a srcs property. 195 ctx.RegisterModuleType("module2", testProductVariableModuleFactoryFactory(&struct { 196 Cflags []string 197 }{})) 198 // A module type that does not have any properties that match product_variables. 199 ctx.RegisterModuleType("module3", testProductVariableModuleFactoryFactory(&struct { 200 Foo []string 201 }{})) 202 registerVariableBuildComponents(ctx) 203 }), 204 FixtureWithRootAndroidBp(bp), 205 ).RunTest(t) 206} 207 208var testProductVariableDefaultsProperties = struct { 209 Product_variables struct { 210 Eng struct { 211 Foo []string `android:"arch_variant"` 212 Bar []string 213 } `android:"arch_variant"` 214 } `android:"arch_variant"` 215}{} 216 217type productVariablesDefaultsTestProperties struct { 218 Foo []string `android:"arch_variant"` 219} 220 221type productVariablesDefaultsTestProperties2 struct { 222 Foo []string 223 Bar []string 224} 225 226type productVariablesDefaultsTestModule struct { 227 ModuleBase 228 DefaultableModuleBase 229 properties productVariablesDefaultsTestProperties 230} 231 232func (d *productVariablesDefaultsTestModule) GenerateAndroidBuildActions(ctx ModuleContext) { 233 ctx.Build(pctx, BuildParams{ 234 Rule: Touch, 235 Output: PathForModuleOut(ctx, "out"), 236 }) 237} 238 239func productVariablesDefaultsTestModuleFactory() Module { 240 module := &productVariablesDefaultsTestModule{} 241 module.AddProperties(&module.properties) 242 module.variableProperties = testProductVariableDefaultsProperties 243 InitAndroidArchModule(module, DeviceSupported, MultilibBoth) 244 InitDefaultableModule(module) 245 return module 246} 247 248type productVariablesDefaultsTestDefaults struct { 249 ModuleBase 250 DefaultsModuleBase 251} 252 253func productVariablesDefaultsTestDefaultsFactory() Module { 254 defaults := &productVariablesDefaultsTestDefaults{} 255 defaults.AddProperties(&productVariablesDefaultsTestProperties{}) 256 defaults.AddProperties(&productVariablesDefaultsTestProperties2{}) 257 defaults.variableProperties = testProductVariableDefaultsProperties 258 InitDefaultsModule(defaults) 259 return defaults 260} 261 262// Test a defaults module that supports more product variable properties than the target module. 263func TestProductVariablesDefaults(t *testing.T) { 264 bp := ` 265 defaults { 266 name: "defaults", 267 product_variables: { 268 eng: { 269 foo: ["product_variable_defaults"], 270 bar: ["product_variable_defaults"], 271 }, 272 }, 273 foo: ["defaults"], 274 bar: ["defaults"], 275 } 276 277 test { 278 name: "foo", 279 defaults: ["defaults"], 280 foo: ["module"], 281 product_variables: { 282 eng: { 283 foo: ["product_variable_module"], 284 }, 285 }, 286 } 287 ` 288 289 result := GroupFixturePreparers( 290 FixtureModifyProductVariables(func(variables FixtureProductVariables) { 291 variables.Eng = boolPtr(true) 292 }), 293 PrepareForTestWithDefaults, 294 PrepareForTestWithVariables, 295 FixtureRegisterWithContext(func(ctx RegistrationContext) { 296 ctx.RegisterModuleType("test", productVariablesDefaultsTestModuleFactory) 297 ctx.RegisterModuleType("defaults", productVariablesDefaultsTestDefaultsFactory) 298 }), 299 FixtureWithRootAndroidBp(bp), 300 ).RunTest(t) 301 302 foo := result.ModuleForTests("foo", "").Module().(*productVariablesDefaultsTestModule) 303 304 want := []string{"defaults", "module", "product_variable_defaults", "product_variable_module"} 305 AssertDeepEquals(t, "foo", want, foo.properties.Foo) 306} 307 308func BenchmarkSliceToTypeArray(b *testing.B) { 309 for _, n := range []int{1, 2, 4, 8, 100} { 310 var propStructs []interface{} 311 for i := 0; i < n; i++ { 312 propStructs = append(propStructs, &struct { 313 A *string 314 B string 315 }{}) 316 317 } 318 b.Run(strconv.Itoa(n), func(b *testing.B) { 319 for i := 0; i < b.N; i++ { 320 _ = sliceToTypeArray(propStructs) 321 } 322 }) 323 } 324} 325 326// Test a defaults module that supports more product variable properties than the target module. 327func TestProductVariablesArch(t *testing.T) { 328 bp := ` 329 test { 330 name: "foo", 331 arch: { 332 arm: { 333 product_variables: { 334 eng: { 335 foo: ["arm"], 336 }, 337 }, 338 }, 339 arm64: { 340 product_variables: { 341 eng: { 342 foo: ["arm64"], 343 }, 344 }, 345 }, 346 }, 347 foo: ["module"], 348 } 349 ` 350 351 result := GroupFixturePreparers( 352 FixtureModifyProductVariables(func(variables FixtureProductVariables) { 353 variables.Eng = boolPtr(true) 354 }), 355 PrepareForTestWithArchMutator, 356 PrepareForTestWithVariables, 357 FixtureRegisterWithContext(func(ctx RegistrationContext) { 358 ctx.RegisterModuleType("test", productVariablesDefaultsTestModuleFactory) 359 }), 360 FixtureWithRootAndroidBp(bp), 361 ).RunTest(t) 362 363 foo := result.ModuleForTests("foo", "android_arm64_armv8-a").Module().(*productVariablesDefaultsTestModule) 364 365 want := []string{"module", "arm64"} 366 AssertDeepEquals(t, "foo", want, foo.properties.Foo) 367} 368