| Colin Cross | 7e0eaf1 | 2017-05-05 16:16:24 -0700 | [diff] [blame] | 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 |  | 
|  | 15 | package android | 
|  | 16 |  | 
|  | 17 | import ( | 
|  | 18 | "reflect" | 
| Colin Cross | 18c4680 | 2019-09-24 22:19:02 -0700 | [diff] [blame] | 19 | "strconv" | 
| Colin Cross | 7e0eaf1 | 2017-05-05 16:16:24 -0700 | [diff] [blame] | 20 | "testing" | 
| Colin Cross | 18c4680 | 2019-09-24 22:19:02 -0700 | [diff] [blame] | 21 |  | 
|  | 22 | "github.com/google/blueprint/proptools" | 
| Colin Cross | 7e0eaf1 | 2017-05-05 16:16:24 -0700 | [diff] [blame] | 23 | ) | 
|  | 24 |  | 
|  | 25 | type printfIntoPropertyTestCase struct { | 
|  | 26 | in  string | 
|  | 27 | val interface{} | 
|  | 28 | out string | 
|  | 29 | err bool | 
|  | 30 | } | 
|  | 31 |  | 
|  | 32 | var 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 |  | 
|  | 114 | func 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 | } | 
| Colin Cross | 18c4680 | 2019-09-24 22:19:02 -0700 | [diff] [blame] | 128 |  | 
|  | 129 | type testProductVariableModule struct { | 
|  | 130 | ModuleBase | 
|  | 131 | } | 
|  | 132 |  | 
|  | 133 | func (m *testProductVariableModule) GenerateAndroidBuildActions(ctx ModuleContext) { | 
|  | 134 | } | 
|  | 135 |  | 
|  | 136 | var testProductVariableProperties = struct { | 
|  | 137 | Product_variables struct { | 
|  | 138 | Eng struct { | 
|  | 139 | Srcs   []string | 
|  | 140 | Cflags []string | 
|  | 141 | } | 
|  | 142 | } | 
|  | 143 | }{} | 
|  | 144 |  | 
|  | 145 | func 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 |  | 
| Colin Cross | 9d34f35 | 2019-11-22 16:03:51 -0800 | [diff] [blame] | 151 | // Set a default soongConfigVariableProperties, this will be used as the input to the property struct filter | 
| Colin Cross | 18c4680 | 2019-09-24 22:19:02 -0700 | [diff] [blame] | 152 | // for this test module. | 
|  | 153 | m.variableProperties = testProductVariableProperties | 
|  | 154 | InitAndroidModule(m) | 
|  | 155 | return m | 
|  | 156 | } | 
|  | 157 | } | 
|  | 158 |  | 
|  | 159 | func TestProductVariables(t *testing.T) { | 
| Colin Cross | 18c4680 | 2019-09-24 22:19:02 -0700 | [diff] [blame] | 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 | ` | 
| Colin Cross | 18c4680 | 2019-09-24 22:19:02 -0700 | [diff] [blame] | 184 |  | 
| Paul Duffin | 30ac3e7 | 2021-03-20 00:36:14 +0000 | [diff] [blame] | 185 | GroupFixturePreparers( | 
| Paul Duffin | 4bb2b21 | 2021-03-16 23:36:24 +0000 | [diff] [blame] | 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), | 
| Paul Duffin | 30ac3e7 | 2021-03-20 00:36:14 +0000 | [diff] [blame] | 207 | ).RunTest(t) | 
| Colin Cross | 18c4680 | 2019-09-24 22:19:02 -0700 | [diff] [blame] | 208 | } | 
|  | 209 |  | 
| Colin Cross | eabaedd | 2020-02-06 17:01:55 -0800 | [diff] [blame] | 210 | var testProductVariableDefaultsProperties = struct { | 
|  | 211 | Product_variables struct { | 
|  | 212 | Eng struct { | 
|  | 213 | Foo []string | 
|  | 214 | Bar []string | 
|  | 215 | } | 
|  | 216 | } | 
|  | 217 | }{} | 
|  | 218 |  | 
|  | 219 | type productVariablesDefaultsTestProperties struct { | 
|  | 220 | Foo []string | 
|  | 221 | } | 
|  | 222 |  | 
|  | 223 | type productVariablesDefaultsTestProperties2 struct { | 
|  | 224 | Foo []string | 
|  | 225 | Bar []string | 
|  | 226 | } | 
|  | 227 |  | 
|  | 228 | type productVariablesDefaultsTestModule struct { | 
|  | 229 | ModuleBase | 
|  | 230 | DefaultableModuleBase | 
|  | 231 | properties productVariablesDefaultsTestProperties | 
|  | 232 | } | 
|  | 233 |  | 
|  | 234 | func (d *productVariablesDefaultsTestModule) GenerateAndroidBuildActions(ctx ModuleContext) { | 
|  | 235 | ctx.Build(pctx, BuildParams{ | 
|  | 236 | Rule:   Touch, | 
|  | 237 | Output: PathForModuleOut(ctx, "out"), | 
|  | 238 | }) | 
|  | 239 | } | 
|  | 240 |  | 
|  | 241 | func 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 |  | 
|  | 250 | type productVariablesDefaultsTestDefaults struct { | 
|  | 251 | ModuleBase | 
|  | 252 | DefaultsModuleBase | 
|  | 253 | } | 
|  | 254 |  | 
|  | 255 | func 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. | 
|  | 265 | func 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 |  | 
| Paul Duffin | 30ac3e7 | 2021-03-20 00:36:14 +0000 | [diff] [blame] | 291 | result := GroupFixturePreparers( | 
| Paul Duffin | 4bb2b21 | 2021-03-16 23:36:24 +0000 | [diff] [blame] | 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), | 
| Paul Duffin | 30ac3e7 | 2021-03-20 00:36:14 +0000 | [diff] [blame] | 302 | ).RunTest(t) | 
| Colin Cross | eabaedd | 2020-02-06 17:01:55 -0800 | [diff] [blame] | 303 |  | 
| Paul Duffin | 4bb2b21 | 2021-03-16 23:36:24 +0000 | [diff] [blame] | 304 | foo := result.ModuleForTests("foo", "").Module().(*productVariablesDefaultsTestModule) | 
| Colin Cross | eabaedd | 2020-02-06 17:01:55 -0800 | [diff] [blame] | 305 |  | 
|  | 306 | want := []string{"defaults", "module", "product_variable_defaults", "product_variable_module"} | 
| Paul Duffin | 4bb2b21 | 2021-03-16 23:36:24 +0000 | [diff] [blame] | 307 | AssertDeepEquals(t, "foo", want, foo.properties.Foo) | 
| Colin Cross | eabaedd | 2020-02-06 17:01:55 -0800 | [diff] [blame] | 308 | } | 
|  | 309 |  | 
| Colin Cross | 18c4680 | 2019-09-24 22:19:02 -0700 | [diff] [blame] | 310 | func 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 | } |