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 `android:"path"` 70 C *string `android:"path"` 71 D *string `android:"path"` 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 276var prepareForArchTest = GroupFixturePreparers( 277 PrepareForTestWithArchMutator, 278 FixtureRegisterWithContext(func(ctx RegistrationContext) { 279 ctx.RegisterModuleType("module", archTestModuleFactory) 280 }), 281) 282 283func TestArchMutator(t *testing.T) { 284 var buildOSVariants []string 285 var buildOS32Variants []string 286 switch runtime.GOOS { 287 case "linux": 288 buildOSVariants = []string{"linux_glibc_x86_64", "linux_glibc_x86"} 289 buildOS32Variants = []string{"linux_glibc_x86"} 290 case "darwin": 291 buildOSVariants = []string{"darwin_x86_64"} 292 buildOS32Variants = nil 293 } 294 295 bp := ` 296 module { 297 name: "foo", 298 } 299 300 module { 301 name: "bar", 302 host_supported: true, 303 } 304 305 module { 306 name: "baz", 307 device_supported: false, 308 } 309 310 module { 311 name: "qux", 312 host_supported: true, 313 compile_multilib: "32", 314 } 315 ` 316 317 testCases := []struct { 318 name string 319 preparer FixturePreparer 320 fooVariants []string 321 barVariants []string 322 bazVariants []string 323 quxVariants []string 324 }{ 325 { 326 name: "normal", 327 preparer: nil, 328 fooVariants: []string{"android_arm64_armv8-a", "android_arm_armv7-a-neon"}, 329 barVariants: append(buildOSVariants, "android_arm64_armv8-a", "android_arm_armv7-a-neon"), 330 bazVariants: nil, 331 quxVariants: append(buildOS32Variants, "android_arm_armv7-a-neon"), 332 }, 333 { 334 name: "host-only", 335 preparer: FixtureModifyConfig(func(config Config) { 336 config.BuildOSTarget = Target{} 337 config.BuildOSCommonTarget = Target{} 338 config.Targets[Android] = nil 339 }), 340 fooVariants: nil, 341 barVariants: buildOSVariants, 342 bazVariants: nil, 343 quxVariants: buildOS32Variants, 344 }, 345 } 346 347 enabledVariants := func(ctx *TestContext, name string) []string { 348 var ret []string 349 variants := ctx.ModuleVariantsForTests(name) 350 for _, variant := range variants { 351 m := ctx.ModuleForTests(name, variant) 352 if m.Module().Enabled() { 353 ret = append(ret, variant) 354 } 355 } 356 return ret 357 } 358 359 for _, tt := range testCases { 360 t.Run(tt.name, func(t *testing.T) { 361 result := GroupFixturePreparers( 362 prepareForArchTest, 363 // Test specific preparer 364 OptionalFixturePreparer(tt.preparer), 365 FixtureWithRootAndroidBp(bp), 366 ).RunTest(t) 367 ctx := result.TestContext 368 369 if g, w := enabledVariants(ctx, "foo"), tt.fooVariants; !reflect.DeepEqual(w, g) { 370 t.Errorf("want foo variants:\n%q\ngot:\n%q\n", w, g) 371 } 372 373 if g, w := enabledVariants(ctx, "bar"), tt.barVariants; !reflect.DeepEqual(w, g) { 374 t.Errorf("want bar variants:\n%q\ngot:\n%q\n", w, g) 375 } 376 377 if g, w := enabledVariants(ctx, "baz"), tt.bazVariants; !reflect.DeepEqual(w, g) { 378 t.Errorf("want baz variants:\n%q\ngot:\n%q\n", w, g) 379 } 380 381 if g, w := enabledVariants(ctx, "qux"), tt.quxVariants; !reflect.DeepEqual(w, g) { 382 t.Errorf("want qux variants:\n%q\ngot:\n%q\n", w, g) 383 } 384 }) 385 } 386} 387 388func TestArchMutatorNativeBridge(t *testing.T) { 389 bp := ` 390 // This module is only enabled for x86. 391 module { 392 name: "foo", 393 } 394 395 // This module is enabled for x86 and arm (via native bridge). 396 module { 397 name: "bar", 398 native_bridge_supported: true, 399 } 400 401 // This module is enabled for arm (native_bridge) only. 402 module { 403 name: "baz", 404 native_bridge_supported: true, 405 enabled: false, 406 target: { 407 native_bridge: { 408 enabled: true, 409 } 410 } 411 } 412 ` 413 414 testCases := []struct { 415 name string 416 preparer FixturePreparer 417 fooVariants []string 418 barVariants []string 419 bazVariants []string 420 }{ 421 { 422 name: "normal", 423 preparer: nil, 424 fooVariants: []string{"android_x86_64_silvermont", "android_x86_silvermont"}, 425 barVariants: []string{"android_x86_64_silvermont", "android_native_bridge_arm64_armv8-a", "android_x86_silvermont", "android_native_bridge_arm_armv7-a-neon"}, 426 bazVariants: []string{"android_native_bridge_arm64_armv8-a", "android_native_bridge_arm_armv7-a-neon"}, 427 }, 428 } 429 430 enabledVariants := func(ctx *TestContext, name string) []string { 431 var ret []string 432 variants := ctx.ModuleVariantsForTests(name) 433 for _, variant := range variants { 434 m := ctx.ModuleForTests(name, variant) 435 if m.Module().Enabled() { 436 ret = append(ret, variant) 437 } 438 } 439 return ret 440 } 441 442 for _, tt := range testCases { 443 t.Run(tt.name, func(t *testing.T) { 444 result := GroupFixturePreparers( 445 prepareForArchTest, 446 // Test specific preparer 447 OptionalFixturePreparer(tt.preparer), 448 // Prepare for native bridge test 449 FixtureModifyConfig(func(config Config) { 450 config.Targets[Android] = []Target{ 451 {Android, Arch{ArchType: X86_64, ArchVariant: "silvermont", Abi: []string{"arm64-v8a"}}, NativeBridgeDisabled, "", "", false}, 452 {Android, Arch{ArchType: X86, ArchVariant: "silvermont", Abi: []string{"armeabi-v7a"}}, NativeBridgeDisabled, "", "", false}, 453 {Android, Arch{ArchType: Arm64, ArchVariant: "armv8-a", Abi: []string{"arm64-v8a"}}, NativeBridgeEnabled, "x86_64", "arm64", false}, 454 {Android, Arch{ArchType: Arm, ArchVariant: "armv7-a-neon", Abi: []string{"armeabi-v7a"}}, NativeBridgeEnabled, "x86", "arm", false}, 455 } 456 }), 457 FixtureWithRootAndroidBp(bp), 458 ).RunTest(t) 459 460 ctx := result.TestContext 461 462 if g, w := enabledVariants(ctx, "foo"), tt.fooVariants; !reflect.DeepEqual(w, g) { 463 t.Errorf("want foo variants:\n%q\ngot:\n%q\n", w, g) 464 } 465 466 if g, w := enabledVariants(ctx, "bar"), tt.barVariants; !reflect.DeepEqual(w, g) { 467 t.Errorf("want bar variants:\n%q\ngot:\n%q\n", w, g) 468 } 469 470 if g, w := enabledVariants(ctx, "baz"), tt.bazVariants; !reflect.DeepEqual(w, g) { 471 t.Errorf("want qux variants:\n%q\ngot:\n%q\n", w, g) 472 } 473 }) 474 } 475} 476 477type testArchPropertiesModule struct { 478 ModuleBase 479 properties struct { 480 A []string `android:"arch_variant"` 481 } 482} 483 484func (testArchPropertiesModule) GenerateAndroidBuildActions(ctx ModuleContext) {} 485 486func TestArchProperties(t *testing.T) { 487 bp := ` 488 module { 489 name: "foo", 490 a: ["root"], 491 arch: { 492 arm: { 493 a: ["arm"], 494 }, 495 arm64: { 496 a: ["arm64"], 497 }, 498 x86: { a: ["x86"] }, 499 x86_64: { a: ["x86_64"] }, 500 }, 501 multilib: { 502 lib32: { a: ["lib32"] }, 503 lib64: { a: ["lib64"] }, 504 }, 505 target: { 506 bionic: { a: ["bionic"] }, 507 host: { a: ["host"] }, 508 android: { a: ["android"] }, 509 glibc: { a: ["glibc"] }, 510 musl: { a: ["musl"] }, 511 linux_bionic: { a: ["linux_bionic"] }, 512 linux: { a: ["linux"] }, 513 host_linux: { a: ["host_linux"] }, 514 linux_glibc: { a: ["linux_glibc"] }, 515 linux_musl: { a: ["linux_musl"] }, 516 windows: { a: ["windows"], enabled: true }, 517 darwin: { a: ["darwin"] }, 518 not_windows: { a: ["not_windows"] }, 519 android32: { a: ["android32"] }, 520 android64: { a: ["android64"] }, 521 android_arm: { a: ["android_arm"] }, 522 android_arm64: { a: ["android_arm64"] }, 523 linux_x86: { a: ["linux_x86"] }, 524 linux_x86_64: { a: ["linux_x86_64"] }, 525 linux_glibc_x86: { a: ["linux_glibc_x86"] }, 526 linux_glibc_x86_64: { a: ["linux_glibc_x86_64"] }, 527 linux_musl_x86: { a: ["linux_musl_x86"] }, 528 linux_musl_x86_64: { a: ["linux_musl_x86_64"] }, 529 darwin_x86_64: { a: ["darwin_x86_64"] }, 530 windows_x86: { a: ["windows_x86"] }, 531 windows_x86_64: { a: ["windows_x86_64"] }, 532 }, 533 } 534 ` 535 536 type result struct { 537 module string 538 variant string 539 property []string 540 } 541 542 testCases := []struct { 543 name string 544 goOS string 545 preparer FixturePreparer 546 results []result 547 }{ 548 { 549 name: "default", 550 results: []result{ 551 { 552 module: "foo", 553 variant: "android_arm64_armv8-a", 554 property: []string{"root", "linux", "bionic", "android", "android64", "arm64", "lib64", "android_arm64"}, 555 }, 556 { 557 module: "foo", 558 variant: "android_arm_armv7-a-neon", 559 property: []string{"root", "linux", "bionic", "android", "android64", "arm", "lib32", "android_arm"}, 560 }, 561 }, 562 }, 563 { 564 name: "linux", 565 goOS: "linux", 566 results: []result{ 567 { 568 module: "foo", 569 variant: "linux_glibc_x86_64", 570 property: []string{"root", "host", "linux", "host_linux", "glibc", "linux_glibc", "not_windows", "x86_64", "lib64", "linux_x86_64", "linux_glibc_x86_64"}, 571 }, 572 { 573 module: "foo", 574 variant: "linux_glibc_x86", 575 property: []string{"root", "host", "linux", "host_linux", "glibc", "linux_glibc", "not_windows", "x86", "lib32", "linux_x86", "linux_glibc_x86"}, 576 }, 577 }, 578 }, 579 { 580 name: "windows", 581 goOS: "linux", 582 preparer: FixtureModifyConfig(func(config Config) { 583 config.Targets[Windows] = []Target{ 584 {Windows, Arch{ArchType: X86_64}, NativeBridgeDisabled, "", "", true}, 585 {Windows, Arch{ArchType: X86}, NativeBridgeDisabled, "", "", true}, 586 } 587 }), 588 results: []result{ 589 { 590 module: "foo", 591 variant: "windows_x86_64", 592 property: []string{"root", "host", "windows", "x86_64", "lib64", "windows_x86_64"}, 593 }, 594 { 595 module: "foo", 596 variant: "windows_x86", 597 property: []string{"root", "host", "windows", "x86", "lib32", "windows_x86"}, 598 }, 599 }, 600 }, 601 { 602 name: "linux_musl", 603 goOS: "linux", 604 preparer: FixtureModifyConfig(modifyTestConfigForMusl), 605 results: []result{ 606 { 607 module: "foo", 608 variant: "linux_musl_x86_64", 609 property: []string{"root", "host", "linux", "host_linux", "musl", "linux_musl", "not_windows", "x86_64", "lib64", "linux_x86_64", "linux_musl_x86_64"}, 610 }, 611 { 612 module: "foo", 613 variant: "linux_musl_x86", 614 property: []string{"root", "host", "linux", "host_linux", "musl", "linux_musl", "not_windows", "x86", "lib32", "linux_x86", "linux_musl_x86"}, 615 }, 616 }, 617 }, 618 { 619 name: "darwin", 620 goOS: "darwin", 621 results: []result{ 622 { 623 module: "foo", 624 variant: "darwin_x86_64", 625 property: []string{"root", "host", "darwin", "not_windows", "x86_64", "lib64", "darwin_x86_64"}, 626 }, 627 }, 628 }, 629 } 630 631 for _, tt := range testCases { 632 t.Run(tt.name, func(t *testing.T) { 633 if tt.goOS != "" && tt.goOS != runtime.GOOS { 634 t.Skipf("test requires runtime.GOOS==%s, got %s", tt.goOS, runtime.GOOS) 635 } 636 result := GroupFixturePreparers( 637 PrepareForTestWithArchMutator, 638 OptionalFixturePreparer(tt.preparer), 639 FixtureRegisterWithContext(func(ctx RegistrationContext) { 640 ctx.RegisterModuleType("module", func() Module { 641 module := &testArchPropertiesModule{} 642 module.AddProperties(&module.properties) 643 InitAndroidArchModule(module, HostAndDeviceDefault, MultilibBoth) 644 return module 645 }) 646 }), 647 ).RunTestWithBp(t, bp) 648 649 for _, want := range tt.results { 650 t.Run(want.module+"_"+want.variant, func(t *testing.T) { 651 got := result.ModuleForTests(want.module, want.variant).Module().(*testArchPropertiesModule).properties.A 652 AssertArrayString(t, "arch mutator property", want.property, got) 653 }) 654 } 655 }) 656 } 657} 658