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) { |
| 160 | ctx := NewTestContext() |
| 161 | // A module type that has a srcs property but not a cflags property. |
Colin Cross | 43e789d | 2020-01-28 09:46:50 -0800 | [diff] [blame] | 162 | ctx.RegisterModuleType("module1", testProductVariableModuleFactoryFactory(&struct { |
Colin Cross | 18c4680 | 2019-09-24 22:19:02 -0700 | [diff] [blame] | 163 | Srcs []string |
Colin Cross | 4b49b76 | 2019-11-22 15:25:03 -0800 | [diff] [blame] | 164 | }{})) |
Colin Cross | 18c4680 | 2019-09-24 22:19:02 -0700 | [diff] [blame] | 165 | // A module type that has a cflags property but not a srcs property. |
Colin Cross | 43e789d | 2020-01-28 09:46:50 -0800 | [diff] [blame] | 166 | ctx.RegisterModuleType("module2", testProductVariableModuleFactoryFactory(&struct { |
Colin Cross | 18c4680 | 2019-09-24 22:19:02 -0700 | [diff] [blame] | 167 | Cflags []string |
Colin Cross | 4b49b76 | 2019-11-22 15:25:03 -0800 | [diff] [blame] | 168 | }{})) |
Colin Cross | 18c4680 | 2019-09-24 22:19:02 -0700 | [diff] [blame] | 169 | // A module type that does not have any properties that match product_variables. |
Colin Cross | 43e789d | 2020-01-28 09:46:50 -0800 | [diff] [blame] | 170 | ctx.RegisterModuleType("module3", testProductVariableModuleFactoryFactory(&struct { |
Colin Cross | 18c4680 | 2019-09-24 22:19:02 -0700 | [diff] [blame] | 171 | Foo []string |
Colin Cross | 4b49b76 | 2019-11-22 15:25:03 -0800 | [diff] [blame] | 172 | }{})) |
Colin Cross | 18c4680 | 2019-09-24 22:19:02 -0700 | [diff] [blame] | 173 | ctx.PreDepsMutators(func(ctx RegisterMutatorsContext) { |
Colin Cross | eabaedd | 2020-02-06 17:01:55 -0800 | [diff] [blame^] | 174 | ctx.BottomUp("variable", VariableMutator).Parallel() |
Colin Cross | 18c4680 | 2019-09-24 22:19:02 -0700 | [diff] [blame] | 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 | ` |
Colin Cross | 98be1bb | 2019-12-13 20:41:13 -0800 | [diff] [blame] | 201 | config := TestConfig(buildDir, nil, bp, nil) |
Colin Cross | 18c4680 | 2019-09-24 22:19:02 -0700 | [diff] [blame] | 202 | config.TestProductVariables.Eng = proptools.BoolPtr(true) |
| 203 | |
Colin Cross | 98be1bb | 2019-12-13 20:41:13 -0800 | [diff] [blame] | 204 | ctx.Register(config) |
| 205 | |
Colin Cross | 18c4680 | 2019-09-24 22:19:02 -0700 | [diff] [blame] | 206 | _, errs := ctx.ParseFileList(".", []string{"Android.bp"}) |
| 207 | FailIfErrored(t, errs) |
| 208 | _, errs = ctx.PrepareBuildActions(config) |
| 209 | FailIfErrored(t, errs) |
| 210 | } |
| 211 | |
Colin Cross | eabaedd | 2020-02-06 17:01:55 -0800 | [diff] [blame^] | 212 | var testProductVariableDefaultsProperties = struct { |
| 213 | Product_variables struct { |
| 214 | Eng struct { |
| 215 | Foo []string |
| 216 | Bar []string |
| 217 | } |
| 218 | } |
| 219 | }{} |
| 220 | |
| 221 | type productVariablesDefaultsTestProperties struct { |
| 222 | Foo []string |
| 223 | } |
| 224 | |
| 225 | type productVariablesDefaultsTestProperties2 struct { |
| 226 | Foo []string |
| 227 | Bar []string |
| 228 | } |
| 229 | |
| 230 | type productVariablesDefaultsTestModule struct { |
| 231 | ModuleBase |
| 232 | DefaultableModuleBase |
| 233 | properties productVariablesDefaultsTestProperties |
| 234 | } |
| 235 | |
| 236 | func (d *productVariablesDefaultsTestModule) GenerateAndroidBuildActions(ctx ModuleContext) { |
| 237 | ctx.Build(pctx, BuildParams{ |
| 238 | Rule: Touch, |
| 239 | Output: PathForModuleOut(ctx, "out"), |
| 240 | }) |
| 241 | } |
| 242 | |
| 243 | func 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 | |
| 252 | type productVariablesDefaultsTestDefaults struct { |
| 253 | ModuleBase |
| 254 | DefaultsModuleBase |
| 255 | } |
| 256 | |
| 257 | func 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. |
| 267 | func 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 | |
Colin Cross | 18c4680 | 2019-09-24 22:19:02 -0700 | [diff] [blame] | 321 | func 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 | } |