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 | } |