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 ctx.PreDepsMutators(func(ctx RegisterMutatorsContext) { 203 ctx.BottomUp("variable", VariableMutator).Parallel() 204 }) 205 }), 206 FixtureWithRootAndroidBp(bp), 207 ).RunTest(t) 208} 209 210var testProductVariableDefaultsProperties = struct { 211 Product_variables struct { 212 Eng struct { 213 Foo []string 214 Bar []string 215 } 216 } 217}{} 218 219type productVariablesDefaultsTestProperties struct { 220 Foo []string 221} 222 223type productVariablesDefaultsTestProperties2 struct { 224 Foo []string 225 Bar []string 226} 227 228type productVariablesDefaultsTestModule struct { 229 ModuleBase 230 DefaultableModuleBase 231 properties productVariablesDefaultsTestProperties 232} 233 234func (d *productVariablesDefaultsTestModule) GenerateAndroidBuildActions(ctx ModuleContext) { 235 ctx.Build(pctx, BuildParams{ 236 Rule: Touch, 237 Output: PathForModuleOut(ctx, "out"), 238 }) 239} 240 241func productVariablesDefaultsTestModuleFactory() Module { 242 module := &productVariablesDefaultsTestModule{} 243 module.AddProperties(&module.properties) 244 module.variableProperties = testProductVariableDefaultsProperties 245 InitAndroidModule(module) 246 InitDefaultableModule(module) 247 return module 248} 249 250type productVariablesDefaultsTestDefaults struct { 251 ModuleBase 252 DefaultsModuleBase 253} 254 255func productVariablesDefaultsTestDefaultsFactory() Module { 256 defaults := &productVariablesDefaultsTestDefaults{} 257 defaults.AddProperties(&productVariablesDefaultsTestProperties{}) 258 defaults.AddProperties(&productVariablesDefaultsTestProperties2{}) 259 defaults.variableProperties = testProductVariableDefaultsProperties 260 InitDefaultsModule(defaults) 261 return defaults 262} 263 264// Test a defaults module that supports more product variable properties than the target module. 265func TestProductVariablesDefaults(t *testing.T) { 266 bp := ` 267 defaults { 268 name: "defaults", 269 product_variables: { 270 eng: { 271 foo: ["product_variable_defaults"], 272 bar: ["product_variable_defaults"], 273 }, 274 }, 275 foo: ["defaults"], 276 bar: ["defaults"], 277 } 278 279 test { 280 name: "foo", 281 defaults: ["defaults"], 282 foo: ["module"], 283 product_variables: { 284 eng: { 285 foo: ["product_variable_module"], 286 }, 287 }, 288 } 289 ` 290 291 result := GroupFixturePreparers( 292 FixtureModifyProductVariables(func(variables FixtureProductVariables) { 293 variables.Eng = boolPtr(true) 294 }), 295 PrepareForTestWithDefaults, 296 PrepareForTestWithVariables, 297 FixtureRegisterWithContext(func(ctx RegistrationContext) { 298 ctx.RegisterModuleType("test", productVariablesDefaultsTestModuleFactory) 299 ctx.RegisterModuleType("defaults", productVariablesDefaultsTestDefaultsFactory) 300 }), 301 FixtureWithRootAndroidBp(bp), 302 ).RunTest(t) 303 304 foo := result.ModuleForTests("foo", "").Module().(*productVariablesDefaultsTestModule) 305 306 want := []string{"defaults", "module", "product_variable_defaults", "product_variable_module"} 307 AssertDeepEquals(t, "foo", want, foo.properties.Foo) 308} 309 310func BenchmarkSliceToTypeArray(b *testing.B) { 311 for _, n := range []int{1, 2, 4, 8, 100} { 312 var propStructs []interface{} 313 for i := 0; i < n; i++ { 314 propStructs = append(propStructs, &struct { 315 A *string 316 B string 317 }{}) 318 319 } 320 b.Run(strconv.Itoa(n), func(b *testing.B) { 321 for i := 0; i < b.N; i++ { 322 _ = sliceToTypeArray(propStructs) 323 } 324 }) 325 } 326} 327