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 ctx := NewTestContext() 161 // A module type that has a srcs property but not a cflags property. 162 ctx.RegisterModuleType("module1", testProductVariableModuleFactoryFactory(&struct { 163 Srcs []string 164 }{})) 165 // A module type that has a cflags property but not a srcs property. 166 ctx.RegisterModuleType("module2", testProductVariableModuleFactoryFactory(&struct { 167 Cflags []string 168 }{})) 169 // A module type that does not have any properties that match product_variables. 170 ctx.RegisterModuleType("module3", testProductVariableModuleFactoryFactory(&struct { 171 Foo []string 172 }{})) 173 ctx.PreDepsMutators(func(ctx RegisterMutatorsContext) { 174 ctx.BottomUp("variable", VariableMutator).Parallel() 175 }) 176 177 // Test that a module can use one product variable even if it doesn't have all the properties 178 // supported by that product variable. 179 bp := ` 180 module1 { 181 name: "foo", 182 product_variables: { 183 eng: { 184 srcs: ["foo.c"], 185 }, 186 }, 187 } 188 module2 { 189 name: "bar", 190 product_variables: { 191 eng: { 192 cflags: ["-DBAR"], 193 }, 194 }, 195 } 196 197 module3 { 198 name: "baz", 199 } 200 ` 201 config := TestConfig(buildDir, nil, bp, nil) 202 config.TestProductVariables.Eng = proptools.BoolPtr(true) 203 204 ctx.Register(config) 205 206 _, errs := ctx.ParseFileList(".", []string{"Android.bp"}) 207 FailIfErrored(t, errs) 208 _, errs = ctx.PrepareBuildActions(config) 209 FailIfErrored(t, errs) 210} 211 212var testProductVariableDefaultsProperties = struct { 213 Product_variables struct { 214 Eng struct { 215 Foo []string 216 Bar []string 217 } 218 } 219}{} 220 221type productVariablesDefaultsTestProperties struct { 222 Foo []string 223} 224 225type productVariablesDefaultsTestProperties2 struct { 226 Foo []string 227 Bar []string 228} 229 230type productVariablesDefaultsTestModule struct { 231 ModuleBase 232 DefaultableModuleBase 233 properties productVariablesDefaultsTestProperties 234} 235 236func (d *productVariablesDefaultsTestModule) GenerateAndroidBuildActions(ctx ModuleContext) { 237 ctx.Build(pctx, BuildParams{ 238 Rule: Touch, 239 Output: PathForModuleOut(ctx, "out"), 240 }) 241} 242 243func productVariablesDefaultsTestModuleFactory() Module { 244 module := &productVariablesDefaultsTestModule{} 245 module.AddProperties(&module.properties) 246 module.variableProperties = testProductVariableDefaultsProperties 247 InitAndroidModule(module) 248 InitDefaultableModule(module) 249 return module 250} 251 252type productVariablesDefaultsTestDefaults struct { 253 ModuleBase 254 DefaultsModuleBase 255} 256 257func productVariablesDefaultsTestDefaultsFactory() Module { 258 defaults := &productVariablesDefaultsTestDefaults{} 259 defaults.AddProperties(&productVariablesDefaultsTestProperties{}) 260 defaults.AddProperties(&productVariablesDefaultsTestProperties2{}) 261 defaults.variableProperties = testProductVariableDefaultsProperties 262 InitDefaultsModule(defaults) 263 return defaults 264} 265 266// Test a defaults module that supports more product variable properties than the target module. 267func TestProductVariablesDefaults(t *testing.T) { 268 bp := ` 269 defaults { 270 name: "defaults", 271 product_variables: { 272 eng: { 273 foo: ["product_variable_defaults"], 274 bar: ["product_variable_defaults"], 275 }, 276 }, 277 foo: ["defaults"], 278 bar: ["defaults"], 279 } 280 281 test { 282 name: "foo", 283 defaults: ["defaults"], 284 foo: ["module"], 285 product_variables: { 286 eng: { 287 foo: ["product_variable_module"], 288 }, 289 }, 290 } 291 ` 292 293 config := TestConfig(buildDir, nil, bp, nil) 294 config.TestProductVariables.Eng = boolPtr(true) 295 296 ctx := NewTestContext() 297 298 ctx.RegisterModuleType("test", productVariablesDefaultsTestModuleFactory) 299 ctx.RegisterModuleType("defaults", productVariablesDefaultsTestDefaultsFactory) 300 301 ctx.PreArchMutators(RegisterDefaultsPreArchMutators) 302 ctx.PreDepsMutators(func(ctx RegisterMutatorsContext) { 303 ctx.BottomUp("variable", VariableMutator).Parallel() 304 }) 305 306 ctx.Register(config) 307 308 _, errs := ctx.ParseFileList(".", []string{"Android.bp"}) 309 FailIfErrored(t, errs) 310 _, errs = ctx.PrepareBuildActions(config) 311 FailIfErrored(t, errs) 312 313 foo := ctx.ModuleForTests("foo", "").Module().(*productVariablesDefaultsTestModule) 314 315 want := []string{"defaults", "module", "product_variable_defaults", "product_variable_module"} 316 if g, w := foo.properties.Foo, want; !reflect.DeepEqual(g, w) { 317 t.Errorf("expected foo %q, got %q", w, g) 318 } 319} 320 321func BenchmarkSliceToTypeArray(b *testing.B) { 322 for _, n := range []int{1, 2, 4, 8, 100} { 323 var propStructs []interface{} 324 for i := 0; i < n; i++ { 325 propStructs = append(propStructs, &struct { 326 A *string 327 B string 328 }{}) 329 330 } 331 b.Run(strconv.Itoa(n), func(b *testing.B) { 332 for i := 0; i < b.N; i++ { 333 _ = sliceToTypeArray(propStructs) 334 } 335 }) 336 } 337} 338