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 *archTestMultiTargetsModule) GenerateAndroidBuildActions(ctx ModuleContext) { 263} 264 265func (m *archTestMultiTargetsModule) DepsMutator(ctx BottomUpMutatorContext) { 266 ctx.AddDependency(ctx.Module(), nil, m.props.Deps...) 267} 268 269func archTestMultiTargetsModuleFactory() Module { 270 m := &archTestMultiTargetsModule{} 271 m.AddProperties(&m.props) 272 InitAndroidMultiTargetsArchModule(m, HostAndDeviceSupported, MultilibCommon) 273 return m 274} 275 276type archTestMultiTargetsModule struct { 277 ModuleBase 278 props struct { 279 Deps []string 280 } 281} 282 283func (m *archTestModule) GenerateAndroidBuildActions(ctx ModuleContext) { 284} 285 286func (m *archTestModule) DepsMutator(ctx BottomUpMutatorContext) { 287 ctx.AddDependency(ctx.Module(), nil, m.props.Deps...) 288} 289 290func archTestModuleFactory() Module { 291 m := &archTestModule{} 292 m.AddProperties(&m.props) 293 InitAndroidArchModule(m, HostAndDeviceSupported, MultilibBoth) 294 return m 295} 296 297var prepareForArchTest = GroupFixturePreparers( 298 PrepareForTestWithArchMutator, 299 FixtureRegisterWithContext(func(ctx RegistrationContext) { 300 ctx.RegisterModuleType("module", archTestModuleFactory) 301 ctx.RegisterModuleType("multi_targets_module", archTestMultiTargetsModuleFactory) 302 }), 303) 304 305func TestArchMutator(t *testing.T) { 306 var buildOSVariants []string 307 var buildOS64Variants []string 308 var buildOS32Variants []string 309 var buildOSCommonVariant string 310 311 switch runtime.GOOS { 312 case "linux": 313 buildOSVariants = []string{"linux_glibc_x86_64", "linux_glibc_x86"} 314 buildOS64Variants = []string{"linux_glibc_x86_64"} 315 buildOS32Variants = []string{"linux_glibc_x86"} 316 buildOSCommonVariant = "linux_glibc_common" 317 case "darwin": 318 buildOSVariants = []string{"darwin_x86_64"} 319 buildOS64Variants = []string{"darwin_x86_64"} 320 buildOS32Variants = nil 321 buildOSCommonVariant = "darwin_common" 322 } 323 324 bp := ` 325 module { 326 name: "foo", 327 } 328 329 module { 330 name: "bar", 331 host_supported: true, 332 } 333 334 module { 335 name: "baz", 336 device_supported: false, 337 } 338 339 module { 340 name: "qux", 341 host_supported: true, 342 compile_multilib: "32", 343 } 344 345 module { 346 name: "first", 347 host_supported: true, 348 compile_multilib: "first", 349 } 350 351 multi_targets_module { 352 name: "multi_targets", 353 host_supported: true, 354 } 355 ` 356 357 testCases := []struct { 358 name string 359 preparer FixturePreparer 360 fooVariants []string 361 barVariants []string 362 bazVariants []string 363 quxVariants []string 364 firstVariants []string 365 366 multiTargetVariants []string 367 multiTargetVariantsMap map[string][]string 368 369 goOS string 370 }{ 371 { 372 name: "normal", 373 preparer: nil, 374 fooVariants: []string{"android_arm64_armv8-a", "android_arm_armv7-a-neon"}, 375 barVariants: append(buildOSVariants, "android_arm64_armv8-a", "android_arm_armv7-a-neon"), 376 bazVariants: nil, 377 quxVariants: append(buildOS32Variants, "android_arm_armv7-a-neon"), 378 firstVariants: append(buildOS64Variants, "android_arm64_armv8-a"), 379 multiTargetVariants: []string{buildOSCommonVariant, "android_common"}, 380 multiTargetVariantsMap: map[string][]string{ 381 buildOSCommonVariant: buildOS64Variants, 382 "android_common": {"android_arm64_armv8-a"}, 383 }}, 384 { 385 name: "host-only", 386 preparer: FixtureModifyConfig(func(config Config) { 387 config.BuildOSTarget = Target{} 388 config.BuildOSCommonTarget = Target{} 389 config.Targets[Android] = nil 390 }), 391 fooVariants: nil, 392 barVariants: buildOSVariants, 393 bazVariants: nil, 394 quxVariants: buildOS32Variants, 395 firstVariants: buildOS64Variants, 396 multiTargetVariants: []string{buildOSCommonVariant}, 397 multiTargetVariantsMap: map[string][]string{ 398 buildOSCommonVariant: buildOS64Variants, 399 }, 400 }, 401 { 402 name: "same arch host and host cross", 403 preparer: FixtureModifyConfig(func(config Config) { 404 ModifyTestConfigForMusl(config) 405 modifyTestConfigForMuslArm64HostCross(config) 406 }), 407 fooVariants: []string{"android_arm64_armv8-a", "android_arm_armv7-a-neon"}, 408 barVariants: []string{"linux_musl_x86_64", "linux_musl_arm64", "linux_musl_x86", "android_arm64_armv8-a", "android_arm_armv7-a-neon"}, 409 bazVariants: nil, 410 quxVariants: []string{"linux_musl_x86", "android_arm_armv7-a-neon"}, 411 firstVariants: []string{"linux_musl_x86_64", "linux_musl_arm64", "android_arm64_armv8-a"}, 412 multiTargetVariants: []string{"linux_musl_common", "android_common"}, 413 multiTargetVariantsMap: map[string][]string{ 414 "linux_musl_common": {"linux_musl_x86_64"}, 415 "android_common": {"android_arm64_armv8-a"}, 416 }, 417 goOS: "linux", 418 }, 419 } 420 421 enabledVariants := func(ctx *TestContext, name string) []string { 422 var ret []string 423 variants := ctx.ModuleVariantsForTests(name) 424 for _, variant := range variants { 425 m := ctx.ModuleForTests(name, variant) 426 if m.Module().Enabled() { 427 ret = append(ret, variant) 428 } 429 } 430 return ret 431 } 432 433 moduleMultiTargets := func(ctx *TestContext, name string, variant string) []string { 434 var ret []string 435 targets := ctx.ModuleForTests(name, variant).Module().MultiTargets() 436 for _, t := range targets { 437 ret = append(ret, t.String()) 438 } 439 return ret 440 } 441 442 for _, tt := range testCases { 443 t.Run(tt.name, func(t *testing.T) { 444 if tt.goOS != runtime.GOOS { 445 t.Skipf("requries runtime.GOOS %s", tt.goOS) 446 } 447 448 result := GroupFixturePreparers( 449 prepareForArchTest, 450 // Test specific preparer 451 OptionalFixturePreparer(tt.preparer), 452 FixtureWithRootAndroidBp(bp), 453 ).RunTest(t) 454 ctx := result.TestContext 455 456 if g, w := enabledVariants(ctx, "foo"), tt.fooVariants; !reflect.DeepEqual(w, g) { 457 t.Errorf("want foo variants:\n%q\ngot:\n%q\n", w, g) 458 } 459 460 if g, w := enabledVariants(ctx, "bar"), tt.barVariants; !reflect.DeepEqual(w, g) { 461 t.Errorf("want bar variants:\n%q\ngot:\n%q\n", w, g) 462 } 463 464 if g, w := enabledVariants(ctx, "baz"), tt.bazVariants; !reflect.DeepEqual(w, g) { 465 t.Errorf("want baz variants:\n%q\ngot:\n%q\n", w, g) 466 } 467 468 if g, w := enabledVariants(ctx, "qux"), tt.quxVariants; !reflect.DeepEqual(w, g) { 469 t.Errorf("want qux variants:\n%q\ngot:\n%q\n", w, g) 470 } 471 if g, w := enabledVariants(ctx, "first"), tt.firstVariants; !reflect.DeepEqual(w, g) { 472 t.Errorf("want first variants:\n%q\ngot:\n%q\n", w, g) 473 } 474 475 if g, w := enabledVariants(ctx, "multi_targets"), tt.multiTargetVariants; !reflect.DeepEqual(w, g) { 476 t.Fatalf("want multi_target variants:\n%q\ngot:\n%q\n", w, g) 477 } 478 479 for _, variant := range tt.multiTargetVariants { 480 targets := moduleMultiTargets(ctx, "multi_targets", variant) 481 if g, w := targets, tt.multiTargetVariantsMap[variant]; !reflect.DeepEqual(w, g) { 482 t.Errorf("want ctx.MultiTarget() for %q:\n%q\ngot:\n%q\n", variant, w, g) 483 } 484 } 485 }) 486 } 487} 488 489func TestArchMutatorNativeBridge(t *testing.T) { 490 bp := ` 491 // This module is only enabled for x86. 492 module { 493 name: "foo", 494 } 495 496 // This module is enabled for x86 and arm (via native bridge). 497 module { 498 name: "bar", 499 native_bridge_supported: true, 500 } 501 502 // This module is enabled for arm (native_bridge) only. 503 module { 504 name: "baz", 505 native_bridge_supported: true, 506 enabled: false, 507 target: { 508 native_bridge: { 509 enabled: true, 510 } 511 } 512 } 513 ` 514 515 testCases := []struct { 516 name string 517 preparer FixturePreparer 518 fooVariants []string 519 barVariants []string 520 bazVariants []string 521 }{ 522 { 523 name: "normal", 524 preparer: nil, 525 fooVariants: []string{"android_x86_64_silvermont", "android_x86_silvermont"}, 526 barVariants: []string{"android_x86_64_silvermont", "android_native_bridge_arm64_armv8-a", "android_x86_silvermont", "android_native_bridge_arm_armv7-a-neon"}, 527 bazVariants: []string{"android_native_bridge_arm64_armv8-a", "android_native_bridge_arm_armv7-a-neon"}, 528 }, 529 } 530 531 enabledVariants := func(ctx *TestContext, name string) []string { 532 var ret []string 533 variants := ctx.ModuleVariantsForTests(name) 534 for _, variant := range variants { 535 m := ctx.ModuleForTests(name, variant) 536 if m.Module().Enabled() { 537 ret = append(ret, variant) 538 } 539 } 540 return ret 541 } 542 543 for _, tt := range testCases { 544 t.Run(tt.name, func(t *testing.T) { 545 result := GroupFixturePreparers( 546 prepareForArchTest, 547 // Test specific preparer 548 OptionalFixturePreparer(tt.preparer), 549 // Prepare for native bridge test 550 FixtureModifyConfig(func(config Config) { 551 config.Targets[Android] = []Target{ 552 {Android, Arch{ArchType: X86_64, ArchVariant: "silvermont", Abi: []string{"arm64-v8a"}}, NativeBridgeDisabled, "", "", false}, 553 {Android, Arch{ArchType: X86, ArchVariant: "silvermont", Abi: []string{"armeabi-v7a"}}, NativeBridgeDisabled, "", "", false}, 554 {Android, Arch{ArchType: Arm64, ArchVariant: "armv8-a", Abi: []string{"arm64-v8a"}}, NativeBridgeEnabled, "x86_64", "arm64", false}, 555 {Android, Arch{ArchType: Arm, ArchVariant: "armv7-a-neon", Abi: []string{"armeabi-v7a"}}, NativeBridgeEnabled, "x86", "arm", false}, 556 } 557 }), 558 FixtureWithRootAndroidBp(bp), 559 ).RunTest(t) 560 561 ctx := result.TestContext 562 563 if g, w := enabledVariants(ctx, "foo"), tt.fooVariants; !reflect.DeepEqual(w, g) { 564 t.Errorf("want foo variants:\n%q\ngot:\n%q\n", w, g) 565 } 566 567 if g, w := enabledVariants(ctx, "bar"), tt.barVariants; !reflect.DeepEqual(w, g) { 568 t.Errorf("want bar variants:\n%q\ngot:\n%q\n", w, g) 569 } 570 571 if g, w := enabledVariants(ctx, "baz"), tt.bazVariants; !reflect.DeepEqual(w, g) { 572 t.Errorf("want qux variants:\n%q\ngot:\n%q\n", w, g) 573 } 574 }) 575 } 576} 577 578type testArchPropertiesModule struct { 579 ModuleBase 580 properties struct { 581 A []string `android:"arch_variant"` 582 } 583} 584 585func (testArchPropertiesModule) GenerateAndroidBuildActions(ctx ModuleContext) {} 586 587// Module property "a" does not have "variant_prepend" tag. 588// Expected variant property orders are based on this fact. 589func TestArchProperties(t *testing.T) { 590 bp := ` 591 module { 592 name: "foo", 593 a: ["root"], 594 arch: { 595 arm: { 596 a: ["arm"], 597 }, 598 arm64: { 599 a: ["arm64"], 600 }, 601 riscv64: { a: ["riscv64"] }, 602 x86: { a: ["x86"] }, 603 x86_64: { a: ["x86_64"] }, 604 }, 605 multilib: { 606 lib32: { a: ["lib32"] }, 607 lib64: { a: ["lib64"] }, 608 }, 609 target: { 610 bionic: { a: ["bionic"] }, 611 host: { a: ["host"] }, 612 android: { a: ["android"] }, 613 glibc: { a: ["glibc"] }, 614 musl: { a: ["musl"] }, 615 linux_bionic: { a: ["linux_bionic"] }, 616 linux: { a: ["linux"] }, 617 host_linux: { a: ["host_linux"] }, 618 linux_glibc: { a: ["linux_glibc"] }, 619 linux_musl: { a: ["linux_musl"] }, 620 windows: { a: ["windows"], enabled: true }, 621 darwin: { a: ["darwin"] }, 622 not_windows: { a: ["not_windows"] }, 623 android32: { a: ["android32"] }, 624 android64: { a: ["android64"] }, 625 android_arm: { a: ["android_arm"] }, 626 android_arm64: { a: ["android_arm64"] }, 627 linux_x86: { a: ["linux_x86"] }, 628 linux_x86_64: { a: ["linux_x86_64"] }, 629 linux_glibc_x86: { a: ["linux_glibc_x86"] }, 630 linux_glibc_x86_64: { a: ["linux_glibc_x86_64"] }, 631 linux_musl_x86: { a: ["linux_musl_x86"] }, 632 linux_musl_x86_64: { a: ["linux_musl_x86_64"] }, 633 darwin_x86_64: { a: ["darwin_x86_64"] }, 634 windows_x86: { a: ["windows_x86"] }, 635 windows_x86_64: { a: ["windows_x86_64"] }, 636 }, 637 } 638 ` 639 640 type result struct { 641 module string 642 variant string 643 property []string 644 } 645 646 testCases := []struct { 647 name string 648 goOS string 649 preparer FixturePreparer 650 results []result 651 }{ 652 { 653 name: "default", 654 results: []result{ 655 { 656 module: "foo", 657 variant: "android_arm64_armv8-a", 658 property: []string{"root", "linux", "bionic", "android", "android64", "arm64", "lib64", "android_arm64"}, 659 }, 660 { 661 module: "foo", 662 variant: "android_arm_armv7-a-neon", 663 property: []string{"root", "linux", "bionic", "android", "android64", "arm", "lib32", "android_arm"}, 664 }, 665 }, 666 }, 667 { 668 name: "linux", 669 goOS: "linux", 670 results: []result{ 671 { 672 module: "foo", 673 variant: "linux_glibc_x86_64", 674 property: []string{"root", "host", "linux", "host_linux", "glibc", "linux_glibc", "not_windows", "x86_64", "lib64", "linux_x86_64", "linux_glibc_x86_64"}, 675 }, 676 { 677 module: "foo", 678 variant: "linux_glibc_x86", 679 property: []string{"root", "host", "linux", "host_linux", "glibc", "linux_glibc", "not_windows", "x86", "lib32", "linux_x86", "linux_glibc_x86"}, 680 }, 681 }, 682 }, 683 { 684 name: "windows", 685 goOS: "linux", 686 preparer: FixtureModifyConfig(func(config Config) { 687 config.Targets[Windows] = []Target{ 688 {Windows, Arch{ArchType: X86_64}, NativeBridgeDisabled, "", "", true}, 689 {Windows, Arch{ArchType: X86}, NativeBridgeDisabled, "", "", true}, 690 } 691 }), 692 results: []result{ 693 { 694 module: "foo", 695 variant: "windows_x86_64", 696 property: []string{"root", "host", "windows", "x86_64", "lib64", "windows_x86_64"}, 697 }, 698 { 699 module: "foo", 700 variant: "windows_x86", 701 property: []string{"root", "host", "windows", "x86", "lib32", "windows_x86"}, 702 }, 703 }, 704 }, 705 { 706 name: "linux_musl", 707 goOS: "linux", 708 preparer: FixtureModifyConfig(ModifyTestConfigForMusl), 709 results: []result{ 710 { 711 module: "foo", 712 variant: "linux_musl_x86_64", 713 property: []string{"root", "host", "linux", "host_linux", "musl", "linux_musl", "not_windows", "x86_64", "lib64", "linux_x86_64", "linux_musl_x86_64"}, 714 }, 715 { 716 module: "foo", 717 variant: "linux_musl_x86", 718 property: []string{"root", "host", "linux", "host_linux", "musl", "linux_musl", "not_windows", "x86", "lib32", "linux_x86", "linux_musl_x86"}, 719 }, 720 }, 721 }, 722 { 723 name: "darwin", 724 goOS: "darwin", 725 results: []result{ 726 { 727 module: "foo", 728 variant: "darwin_x86_64", 729 property: []string{"root", "host", "darwin", "not_windows", "x86_64", "lib64", "darwin_x86_64"}, 730 }, 731 }, 732 }, 733 } 734 735 for _, tt := range testCases { 736 t.Run(tt.name, func(t *testing.T) { 737 if tt.goOS != "" && tt.goOS != runtime.GOOS { 738 t.Skipf("test requires runtime.GOOS==%s, got %s", tt.goOS, runtime.GOOS) 739 } 740 result := GroupFixturePreparers( 741 PrepareForTestWithArchMutator, 742 OptionalFixturePreparer(tt.preparer), 743 FixtureRegisterWithContext(func(ctx RegistrationContext) { 744 ctx.RegisterModuleType("module", func() Module { 745 module := &testArchPropertiesModule{} 746 module.AddProperties(&module.properties) 747 InitAndroidArchModule(module, HostAndDeviceDefault, MultilibBoth) 748 return module 749 }) 750 }), 751 ).RunTestWithBp(t, bp) 752 753 for _, want := range tt.results { 754 t.Run(want.module+"_"+want.variant, func(t *testing.T) { 755 got := result.ModuleForTests(want.module, want.variant).Module().(*testArchPropertiesModule).properties.A 756 AssertArrayString(t, "arch mutator property", want.property, got) 757 }) 758 } 759 }) 760 } 761} 762