1// Copyright 2019 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 "runtime" 20 "testing" 21 22 "github.com/google/blueprint/proptools" 23) 24 25type Named struct { 26 A *string `android:"arch_variant"` 27 B *string 28} 29 30type NamedAllFiltered struct { 31 A *string 32} 33 34type NamedNoneFiltered struct { 35 A *string `android:"arch_variant"` 36} 37 38func TestFilterArchStruct(t *testing.T) { 39 tests := []struct { 40 name string 41 in interface{} 42 out interface{} 43 filtered bool 44 }{ 45 // Property tests 46 { 47 name: "basic", 48 in: &struct { 49 A *string `android:"arch_variant"` 50 B *string 51 }{}, 52 out: &struct { 53 A *string 54 }{}, 55 filtered: true, 56 }, 57 { 58 name: "tags", 59 in: &struct { 60 A *string `android:"arch_variant"` 61 B *string `android:"arch_variant,path"` 62 C *string `android:"arch_variant,path,variant_prepend"` 63 D *string `android:"path,variant_prepend,arch_variant"` 64 E *string `android:"path"` 65 F *string 66 }{}, 67 out: &struct { 68 A *string 69 B *string 70 C *string 71 D *string 72 }{}, 73 filtered: true, 74 }, 75 { 76 name: "all filtered", 77 in: &struct { 78 A *string 79 }{}, 80 out: nil, 81 filtered: true, 82 }, 83 { 84 name: "none filtered", 85 in: &struct { 86 A *string `android:"arch_variant"` 87 }{}, 88 out: &struct { 89 A *string `android:"arch_variant"` 90 }{}, 91 filtered: false, 92 }, 93 94 // Sub-struct tests 95 { 96 name: "substruct", 97 in: &struct { 98 A struct { 99 A *string `android:"arch_variant"` 100 B *string 101 } `android:"arch_variant"` 102 }{}, 103 out: &struct { 104 A struct { 105 A *string 106 } 107 }{}, 108 filtered: true, 109 }, 110 { 111 name: "substruct all filtered", 112 in: &struct { 113 A struct { 114 A *string 115 } `android:"arch_variant"` 116 }{}, 117 out: nil, 118 filtered: true, 119 }, 120 { 121 name: "substruct none filtered", 122 in: &struct { 123 A struct { 124 A *string `android:"arch_variant"` 125 } `android:"arch_variant"` 126 }{}, 127 out: &struct { 128 A struct { 129 A *string `android:"arch_variant"` 130 } `android:"arch_variant"` 131 }{}, 132 filtered: false, 133 }, 134 135 // Named sub-struct tests 136 { 137 name: "named substruct", 138 in: &struct { 139 A Named `android:"arch_variant"` 140 }{}, 141 out: &struct { 142 A struct { 143 A *string 144 } 145 }{}, 146 filtered: true, 147 }, 148 { 149 name: "substruct all filtered", 150 in: &struct { 151 A NamedAllFiltered `android:"arch_variant"` 152 }{}, 153 out: nil, 154 filtered: true, 155 }, 156 { 157 name: "substruct none filtered", 158 in: &struct { 159 A NamedNoneFiltered `android:"arch_variant"` 160 }{}, 161 out: &struct { 162 A NamedNoneFiltered `android:"arch_variant"` 163 }{}, 164 filtered: false, 165 }, 166 167 // Pointer to sub-struct tests 168 { 169 name: "pointer substruct", 170 in: &struct { 171 A *struct { 172 A *string `android:"arch_variant"` 173 B *string 174 } `android:"arch_variant"` 175 }{}, 176 out: &struct { 177 A *struct { 178 A *string 179 } 180 }{}, 181 filtered: true, 182 }, 183 { 184 name: "pointer substruct all filtered", 185 in: &struct { 186 A *struct { 187 A *string 188 } `android:"arch_variant"` 189 }{}, 190 out: nil, 191 filtered: true, 192 }, 193 { 194 name: "pointer substruct none filtered", 195 in: &struct { 196 A *struct { 197 A *string `android:"arch_variant"` 198 } `android:"arch_variant"` 199 }{}, 200 out: &struct { 201 A *struct { 202 A *string `android:"arch_variant"` 203 } `android:"arch_variant"` 204 }{}, 205 filtered: false, 206 }, 207 208 // Pointer to named sub-struct tests 209 { 210 name: "pointer named substruct", 211 in: &struct { 212 A *Named `android:"arch_variant"` 213 }{}, 214 out: &struct { 215 A *struct { 216 A *string 217 } 218 }{}, 219 filtered: true, 220 }, 221 { 222 name: "pointer substruct all filtered", 223 in: &struct { 224 A *NamedAllFiltered `android:"arch_variant"` 225 }{}, 226 out: nil, 227 filtered: true, 228 }, 229 { 230 name: "pointer substruct none filtered", 231 in: &struct { 232 A *NamedNoneFiltered `android:"arch_variant"` 233 }{}, 234 out: &struct { 235 A *NamedNoneFiltered `android:"arch_variant"` 236 }{}, 237 filtered: false, 238 }, 239 } 240 241 for _, test := range tests { 242 t.Run(test.name, func(t *testing.T) { 243 out, filtered := proptools.FilterPropertyStruct(reflect.TypeOf(test.in), filterArchStruct) 244 if filtered != test.filtered { 245 t.Errorf("expected filtered %v, got %v", test.filtered, filtered) 246 } 247 expected := reflect.TypeOf(test.out) 248 if out != expected { 249 t.Errorf("expected type %v, got %v", expected, out) 250 } 251 }) 252 } 253} 254 255type archTestModule struct { 256 ModuleBase 257 props struct { 258 Deps []string 259 } 260} 261 262func (m *archTestModule) GenerateAndroidBuildActions(ctx ModuleContext) { 263} 264 265func (m *archTestModule) DepsMutator(ctx BottomUpMutatorContext) { 266 ctx.AddDependency(ctx.Module(), nil, m.props.Deps...) 267} 268 269func archTestModuleFactory() Module { 270 m := &archTestModule{} 271 m.AddProperties(&m.props) 272 InitAndroidArchModule(m, HostAndDeviceSupported, MultilibBoth) 273 return m 274} 275 276func TestArchMutator(t *testing.T) { 277 var buildOSVariants []string 278 var buildOS32Variants []string 279 switch runtime.GOOS { 280 case "linux": 281 buildOSVariants = []string{"linux_glibc_x86_64", "linux_glibc_x86"} 282 buildOS32Variants = []string{"linux_glibc_x86"} 283 case "darwin": 284 buildOSVariants = []string{"darwin_x86_64"} 285 buildOS32Variants = nil 286 } 287 288 bp := ` 289 module { 290 name: "foo", 291 } 292 293 module { 294 name: "bar", 295 host_supported: true, 296 } 297 298 module { 299 name: "baz", 300 device_supported: false, 301 } 302 303 module { 304 name: "qux", 305 host_supported: true, 306 compile_multilib: "32", 307 } 308 ` 309 310 testCases := []struct { 311 name string 312 config func(Config) 313 fooVariants []string 314 barVariants []string 315 bazVariants []string 316 quxVariants []string 317 }{ 318 { 319 name: "normal", 320 config: nil, 321 fooVariants: []string{"android_arm64_armv8-a", "android_arm_armv7-a-neon"}, 322 barVariants: append(buildOSVariants, "android_arm64_armv8-a", "android_arm_armv7-a-neon"), 323 bazVariants: nil, 324 quxVariants: append(buildOS32Variants, "android_arm_armv7-a-neon"), 325 }, 326 { 327 name: "host-only", 328 config: func(config Config) { 329 config.BuildOSTarget = Target{} 330 config.BuildOSCommonTarget = Target{} 331 config.Targets[Android] = nil 332 }, 333 fooVariants: nil, 334 barVariants: buildOSVariants, 335 bazVariants: nil, 336 quxVariants: buildOS32Variants, 337 }, 338 } 339 340 enabledVariants := func(ctx *TestContext, name string) []string { 341 var ret []string 342 variants := ctx.ModuleVariantsForTests(name) 343 for _, variant := range variants { 344 m := ctx.ModuleForTests(name, variant) 345 if m.Module().Enabled() { 346 ret = append(ret, variant) 347 } 348 } 349 return ret 350 } 351 352 for _, tt := range testCases { 353 t.Run(tt.name, func(t *testing.T) { 354 config := TestArchConfig(buildDir, nil, bp, nil) 355 356 ctx := NewTestArchContext() 357 ctx.RegisterModuleType("module", archTestModuleFactory) 358 ctx.Register(config) 359 if tt.config != nil { 360 tt.config(config) 361 } 362 363 _, errs := ctx.ParseFileList(".", []string{"Android.bp"}) 364 FailIfErrored(t, errs) 365 _, errs = ctx.PrepareBuildActions(config) 366 FailIfErrored(t, errs) 367 368 if g, w := enabledVariants(ctx, "foo"), tt.fooVariants; !reflect.DeepEqual(w, g) { 369 t.Errorf("want foo variants:\n%q\ngot:\n%q\n", w, g) 370 } 371 372 if g, w := enabledVariants(ctx, "bar"), tt.barVariants; !reflect.DeepEqual(w, g) { 373 t.Errorf("want bar variants:\n%q\ngot:\n%q\n", w, g) 374 } 375 376 if g, w := enabledVariants(ctx, "baz"), tt.bazVariants; !reflect.DeepEqual(w, g) { 377 t.Errorf("want baz variants:\n%q\ngot:\n%q\n", w, g) 378 } 379 380 if g, w := enabledVariants(ctx, "qux"), tt.quxVariants; !reflect.DeepEqual(w, g) { 381 t.Errorf("want qux variants:\n%q\ngot:\n%q\n", w, g) 382 } 383 }) 384 } 385} 386 387func TestArchMutatorNativeBridge(t *testing.T) { 388 bp := ` 389 // This module is only enabled for x86. 390 module { 391 name: "foo", 392 } 393 394 // This module is enabled for x86 and arm (via native bridge). 395 module { 396 name: "bar", 397 native_bridge_supported: true, 398 } 399 400 // This module is enabled for arm (native_bridge) only. 401 module { 402 name: "baz", 403 native_bridge_supported: true, 404 enabled: false, 405 target: { 406 native_bridge: { 407 enabled: true, 408 } 409 } 410 } 411 ` 412 413 testCases := []struct { 414 name string 415 config func(Config) 416 fooVariants []string 417 barVariants []string 418 bazVariants []string 419 }{ 420 { 421 name: "normal", 422 config: nil, 423 fooVariants: []string{"android_x86_64_silvermont", "android_x86_silvermont"}, 424 barVariants: []string{"android_x86_64_silvermont", "android_native_bridge_arm64_armv8-a", "android_x86_silvermont", "android_native_bridge_arm_armv7-a-neon"}, 425 bazVariants: []string{"android_native_bridge_arm64_armv8-a", "android_native_bridge_arm_armv7-a-neon"}, 426 }, 427 } 428 429 enabledVariants := func(ctx *TestContext, name string) []string { 430 var ret []string 431 variants := ctx.ModuleVariantsForTests(name) 432 for _, variant := range variants { 433 m := ctx.ModuleForTests(name, variant) 434 if m.Module().Enabled() { 435 ret = append(ret, variant) 436 } 437 } 438 return ret 439 } 440 441 for _, tt := range testCases { 442 t.Run(tt.name, func(t *testing.T) { 443 config := TestArchConfigNativeBridge(buildDir, nil, bp, nil) 444 445 ctx := NewTestArchContext() 446 ctx.RegisterModuleType("module", archTestModuleFactory) 447 ctx.Register(config) 448 if tt.config != nil { 449 tt.config(config) 450 } 451 452 _, errs := ctx.ParseFileList(".", []string{"Android.bp"}) 453 FailIfErrored(t, errs) 454 _, errs = ctx.PrepareBuildActions(config) 455 FailIfErrored(t, errs) 456 457 if g, w := enabledVariants(ctx, "foo"), tt.fooVariants; !reflect.DeepEqual(w, g) { 458 t.Errorf("want foo variants:\n%q\ngot:\n%q\n", w, g) 459 } 460 461 if g, w := enabledVariants(ctx, "bar"), tt.barVariants; !reflect.DeepEqual(w, g) { 462 t.Errorf("want bar variants:\n%q\ngot:\n%q\n", w, g) 463 } 464 465 if g, w := enabledVariants(ctx, "baz"), tt.bazVariants; !reflect.DeepEqual(w, g) { 466 t.Errorf("want qux variants:\n%q\ngot:\n%q\n", w, g) 467 } 468 }) 469 } 470} 471