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 15package android 16 17import ( 18 "path/filepath" 19 "runtime" 20 "testing" 21 22 "github.com/google/blueprint" 23) 24 25func TestSrcIsModule(t *testing.T) { 26 type args struct { 27 s string 28 } 29 tests := []struct { 30 name string 31 args args 32 wantModule string 33 }{ 34 { 35 name: "file", 36 args: args{ 37 s: "foo", 38 }, 39 wantModule: "", 40 }, 41 { 42 name: "module", 43 args: args{ 44 s: ":foo", 45 }, 46 wantModule: "foo", 47 }, 48 { 49 name: "tag", 50 args: args{ 51 s: ":foo{.bar}", 52 }, 53 wantModule: "foo{.bar}", 54 }, 55 { 56 name: "extra colon", 57 args: args{ 58 s: ":foo:bar", 59 }, 60 wantModule: "foo:bar", 61 }, 62 { 63 name: "fully qualified", 64 args: args{ 65 s: "//foo:bar", 66 }, 67 wantModule: "//foo:bar", 68 }, 69 { 70 name: "fully qualified with tag", 71 args: args{ 72 s: "//foo:bar{.tag}", 73 }, 74 wantModule: "//foo:bar{.tag}", 75 }, 76 { 77 name: "invalid unqualified name", 78 args: args{ 79 s: ":foo/bar", 80 }, 81 wantModule: "", 82 }, 83 } 84 for _, tt := range tests { 85 t.Run(tt.name, func(t *testing.T) { 86 if gotModule := SrcIsModule(tt.args.s); gotModule != tt.wantModule { 87 t.Errorf("SrcIsModule() = %v, want %v", gotModule, tt.wantModule) 88 } 89 }) 90 } 91} 92 93func TestSrcIsModuleWithTag(t *testing.T) { 94 type args struct { 95 s string 96 } 97 tests := []struct { 98 name string 99 args args 100 wantModule string 101 wantTag string 102 }{ 103 { 104 name: "file", 105 args: args{ 106 s: "foo", 107 }, 108 wantModule: "", 109 wantTag: "", 110 }, 111 { 112 name: "module", 113 args: args{ 114 s: ":foo", 115 }, 116 wantModule: "foo", 117 wantTag: "", 118 }, 119 { 120 name: "tag", 121 args: args{ 122 s: ":foo{.bar}", 123 }, 124 wantModule: "foo", 125 wantTag: ".bar", 126 }, 127 { 128 name: "empty tag", 129 args: args{ 130 s: ":foo{}", 131 }, 132 wantModule: "foo", 133 wantTag: "", 134 }, 135 { 136 name: "extra colon", 137 args: args{ 138 s: ":foo:bar", 139 }, 140 wantModule: "foo:bar", 141 }, 142 { 143 name: "invalid tag", 144 args: args{ 145 s: ":foo{.bar", 146 }, 147 wantModule: "foo{.bar", 148 }, 149 { 150 name: "invalid tag 2", 151 args: args{ 152 s: ":foo.bar}", 153 }, 154 wantModule: "foo.bar}", 155 }, 156 { 157 name: "fully qualified", 158 args: args{ 159 s: "//foo:bar", 160 }, 161 wantModule: "//foo:bar", 162 }, 163 { 164 name: "fully qualified with tag", 165 args: args{ 166 s: "//foo:bar{.tag}", 167 }, 168 wantModule: "//foo:bar", 169 wantTag: ".tag", 170 }, 171 { 172 name: "invalid unqualified name", 173 args: args{ 174 s: ":foo/bar", 175 }, 176 wantModule: "", 177 }, 178 { 179 name: "invalid unqualified name with tag", 180 args: args{ 181 s: ":foo/bar{.tag}", 182 }, 183 wantModule: "", 184 }, 185 } 186 for _, tt := range tests { 187 t.Run(tt.name, func(t *testing.T) { 188 gotModule, gotTag := SrcIsModuleWithTag(tt.args.s) 189 if gotModule != tt.wantModule { 190 t.Errorf("SrcIsModuleWithTag() gotModule = %v, want %v", gotModule, tt.wantModule) 191 } 192 if gotTag != tt.wantTag { 193 t.Errorf("SrcIsModuleWithTag() gotTag = %v, want %v", gotTag, tt.wantTag) 194 } 195 }) 196 } 197} 198 199type depsModule struct { 200 ModuleBase 201 props struct { 202 Deps []string 203 } 204} 205 206func (m *depsModule) GenerateAndroidBuildActions(ctx ModuleContext) { 207 outputFile := PathForModuleOut(ctx, ctx.ModuleName()) 208 ctx.Build(pctx, BuildParams{ 209 Rule: Touch, 210 Output: outputFile, 211 }) 212 installFile := ctx.InstallFile(PathForModuleInstall(ctx), ctx.ModuleName(), outputFile) 213 ctx.InstallSymlink(PathForModuleInstall(ctx, "symlinks"), ctx.ModuleName(), installFile) 214} 215 216func (m *depsModule) DepsMutator(ctx BottomUpMutatorContext) { 217 ctx.AddDependency(ctx.Module(), installDepTag{}, m.props.Deps...) 218} 219 220func depsModuleFactory() Module { 221 m := &depsModule{} 222 m.AddProperties(&m.props) 223 InitAndroidArchModule(m, HostAndDeviceDefault, MultilibCommon) 224 return m 225} 226 227var prepareForModuleTests = FixtureRegisterWithContext(func(ctx RegistrationContext) { 228 ctx.RegisterModuleType("deps", depsModuleFactory) 229}) 230 231func TestErrorDependsOnDisabledModule(t *testing.T) { 232 bp := ` 233 deps { 234 name: "foo", 235 deps: ["bar"], 236 } 237 deps { 238 name: "bar", 239 enabled: false, 240 } 241 ` 242 243 prepareForModuleTests. 244 ExtendWithErrorHandler(FixtureExpectsAtLeastOneErrorMatchingPattern(`module "foo": depends on disabled module "bar"`)). 245 RunTestWithBp(t, bp) 246} 247 248func TestDistErrorChecking(t *testing.T) { 249 bp := ` 250 deps { 251 name: "foo", 252 dist: { 253 dest: "../invalid-dest", 254 dir: "../invalid-dir", 255 suffix: "invalid/suffix", 256 }, 257 dists: [ 258 { 259 dest: "../invalid-dest0", 260 dir: "../invalid-dir0", 261 suffix: "invalid/suffix0", 262 }, 263 { 264 dest: "../invalid-dest1", 265 dir: "../invalid-dir1", 266 suffix: "invalid/suffix1", 267 }, 268 ], 269 } 270 ` 271 272 expectedErrs := []string{ 273 "\\QAndroid.bp:5:13: module \"foo\": dist.dest: Path is outside directory: ../invalid-dest\\E", 274 "\\QAndroid.bp:6:12: module \"foo\": dist.dir: Path is outside directory: ../invalid-dir\\E", 275 "\\QAndroid.bp:7:15: module \"foo\": dist.suffix: Suffix may not contain a '/' character.\\E", 276 "\\QAndroid.bp:11:15: module \"foo\": dists[0].dest: Path is outside directory: ../invalid-dest0\\E", 277 "\\QAndroid.bp:12:14: module \"foo\": dists[0].dir: Path is outside directory: ../invalid-dir0\\E", 278 "\\QAndroid.bp:13:17: module \"foo\": dists[0].suffix: Suffix may not contain a '/' character.\\E", 279 "\\QAndroid.bp:16:15: module \"foo\": dists[1].dest: Path is outside directory: ../invalid-dest1\\E", 280 "\\QAndroid.bp:17:14: module \"foo\": dists[1].dir: Path is outside directory: ../invalid-dir1\\E", 281 "\\QAndroid.bp:18:17: module \"foo\": dists[1].suffix: Suffix may not contain a '/' character.\\E", 282 } 283 284 prepareForModuleTests. 285 ExtendWithErrorHandler(FixtureExpectsAllErrorsToMatchAPattern(expectedErrs)). 286 RunTestWithBp(t, bp) 287} 288 289func TestInstall(t *testing.T) { 290 if runtime.GOOS != "linux" { 291 t.Skip("requires linux") 292 } 293 bp := ` 294 deps { 295 name: "foo", 296 deps: ["bar"], 297 } 298 299 deps { 300 name: "bar", 301 deps: ["baz", "qux"], 302 } 303 304 deps { 305 name: "baz", 306 deps: ["qux"], 307 } 308 309 deps { 310 name: "qux", 311 } 312 ` 313 314 result := GroupFixturePreparers( 315 prepareForModuleTests, 316 PrepareForTestWithArchMutator, 317 ).RunTestWithBp(t, bp) 318 319 module := func(name string, host bool) TestingModule { 320 variant := "android_common" 321 if host { 322 variant = result.Config.BuildOSCommonTarget.String() 323 } 324 return result.ModuleForTests(t, name, variant) 325 } 326 327 outputRule := func(name string) TestingBuildParams { return module(name, false).Output(name) } 328 329 installRule := func(name string) TestingBuildParams { 330 return module(name, false).Output(filepath.Join("out/target/product/test_device/system", name)) 331 } 332 333 symlinkRule := func(name string) TestingBuildParams { 334 return module(name, false).Output(filepath.Join("out/target/product/test_device/system/symlinks", name)) 335 } 336 337 hostOutputRule := func(name string) TestingBuildParams { return module(name, true).Output(name) } 338 339 hostInstallRule := func(name string) TestingBuildParams { 340 return module(name, true).Output(filepath.Join("out/host/linux-x86", name)) 341 } 342 343 hostSymlinkRule := func(name string) TestingBuildParams { 344 return module(name, true).Output(filepath.Join("out/host/linux-x86/symlinks", name)) 345 } 346 347 assertInputs := func(params TestingBuildParams, inputs ...Path) { 348 t.Helper() 349 AssertArrayString(t, "expected inputs", Paths(inputs).Strings(), 350 append(PathsIfNonNil(params.Input), params.Inputs...).Strings()) 351 } 352 353 assertImplicits := func(params TestingBuildParams, implicits ...Path) { 354 t.Helper() 355 AssertArrayString(t, "expected implicit dependencies", Paths(implicits).Strings(), 356 append(PathsIfNonNil(params.Implicit), params.Implicits...).Strings()) 357 } 358 359 assertOrderOnlys := func(params TestingBuildParams, orderonlys ...Path) { 360 t.Helper() 361 AssertArrayString(t, "expected orderonly dependencies", Paths(orderonlys).Strings(), 362 params.OrderOnly.Strings()) 363 } 364 365 // Check host install rule dependencies 366 assertInputs(hostInstallRule("foo"), hostOutputRule("foo").Output) 367 assertImplicits(hostInstallRule("foo"), 368 hostInstallRule("bar").Output, 369 hostSymlinkRule("bar").Output, 370 hostInstallRule("baz").Output, 371 hostSymlinkRule("baz").Output, 372 hostInstallRule("qux").Output, 373 hostSymlinkRule("qux").Output, 374 ) 375 assertOrderOnlys(hostInstallRule("foo")) 376 377 // Check host symlink rule dependencies. Host symlinks must use a normal dependency, not an 378 // order-only dependency, so that the tool gets updated when the symlink is depended on. 379 assertInputs(hostSymlinkRule("foo"), hostInstallRule("foo").Output) 380 assertImplicits(hostSymlinkRule("foo")) 381 assertOrderOnlys(hostSymlinkRule("foo")) 382 383 // Check device install rule dependencies 384 assertInputs(installRule("foo"), outputRule("foo").Output) 385 assertImplicits(installRule("foo")) 386 assertOrderOnlys(installRule("foo"), 387 installRule("bar").Output, 388 symlinkRule("bar").Output, 389 installRule("baz").Output, 390 symlinkRule("baz").Output, 391 installRule("qux").Output, 392 symlinkRule("qux").Output, 393 ) 394 395 // Check device symlink rule dependencies. Device symlinks could use an order-only dependency, 396 // but the current implementation uses a normal dependency. 397 assertInputs(symlinkRule("foo"), installRule("foo").Output) 398 assertImplicits(symlinkRule("foo")) 399 assertOrderOnlys(symlinkRule("foo")) 400} 401 402func TestInstallKatiEnabled(t *testing.T) { 403 if runtime.GOOS != "linux" { 404 t.Skip("requires linux") 405 } 406 bp := ` 407 deps { 408 name: "foo", 409 deps: ["bar"], 410 } 411 412 deps { 413 name: "bar", 414 deps: ["baz", "qux"], 415 } 416 417 deps { 418 name: "baz", 419 deps: ["qux"], 420 } 421 422 deps { 423 name: "qux", 424 } 425 ` 426 427 result := GroupFixturePreparers( 428 prepareForModuleTests, 429 PrepareForTestWithArchMutator, 430 FixtureModifyConfig(SetKatiEnabledForTests), 431 PrepareForTestWithMakevars, 432 ).RunTestWithBp(t, bp) 433 434 rules := result.InstallMakeRulesForTesting(t) 435 436 module := func(name string, host bool) TestingModule { 437 t.Helper() 438 variant := "android_common" 439 if host { 440 variant = result.Config.BuildOSCommonTarget.String() 441 } 442 return result.ModuleForTests(t, name, variant) 443 } 444 445 outputRule := func(name string) TestingBuildParams { return module(name, false).Output(name) } 446 447 ruleForOutput := func(output string) InstallMakeRule { 448 for _, rule := range rules { 449 if rule.Target == output { 450 return rule 451 } 452 } 453 t.Fatalf("no make install rule for %s", output) 454 return InstallMakeRule{} 455 } 456 457 installRule := func(name string) InstallMakeRule { 458 return ruleForOutput(filepath.Join("out/target/product/test_device/system", name)) 459 } 460 461 symlinkRule := func(name string) InstallMakeRule { 462 return ruleForOutput(filepath.Join("out/target/product/test_device/system/symlinks", name)) 463 } 464 465 hostOutputRule := func(name string) TestingBuildParams { return module(name, true).Output(name) } 466 467 hostInstallRule := func(name string) InstallMakeRule { 468 return ruleForOutput(filepath.Join("out/host/linux-x86", name)) 469 } 470 471 hostSymlinkRule := func(name string) InstallMakeRule { 472 return ruleForOutput(filepath.Join("out/host/linux-x86/symlinks", name)) 473 } 474 475 assertDeps := func(rule InstallMakeRule, deps ...string) { 476 t.Helper() 477 AssertArrayString(t, "expected inputs", deps, rule.Deps) 478 } 479 480 assertOrderOnlys := func(rule InstallMakeRule, orderonlys ...string) { 481 t.Helper() 482 AssertArrayString(t, "expected orderonly dependencies", orderonlys, rule.OrderOnlyDeps) 483 } 484 485 // Check host install rule dependencies 486 assertDeps(hostInstallRule("foo"), 487 hostOutputRule("foo").Output.String(), 488 hostInstallRule("bar").Target, 489 hostSymlinkRule("bar").Target, 490 hostInstallRule("baz").Target, 491 hostSymlinkRule("baz").Target, 492 hostInstallRule("qux").Target, 493 hostSymlinkRule("qux").Target, 494 ) 495 assertOrderOnlys(hostInstallRule("foo")) 496 497 // Check host symlink rule dependencies. Host symlinks must use a normal dependency, not an 498 // order-only dependency, so that the tool gets updated when the symlink is depended on. 499 assertDeps(hostSymlinkRule("foo"), hostInstallRule("foo").Target) 500 assertOrderOnlys(hostSymlinkRule("foo")) 501 502 // Check device install rule dependencies 503 assertDeps(installRule("foo"), outputRule("foo").Output.String()) 504 assertOrderOnlys(installRule("foo"), 505 installRule("bar").Target, 506 symlinkRule("bar").Target, 507 installRule("baz").Target, 508 symlinkRule("baz").Target, 509 installRule("qux").Target, 510 symlinkRule("qux").Target, 511 ) 512 513 // Check device symlink rule dependencies. Device symlinks could use an order-only dependency, 514 // but the current implementation uses a normal dependency. 515 assertDeps(symlinkRule("foo"), installRule("foo").Target) 516 assertOrderOnlys(symlinkRule("foo")) 517} 518 519type PropsTestModuleEmbedded struct { 520 Embedded_prop *string 521} 522 523type StructInSlice struct { 524 G string 525 H bool 526 I []string 527} 528 529type propsTestModule struct { 530 ModuleBase 531 DefaultableModuleBase 532 props struct { 533 A string `android:"arch_variant"` 534 B *bool 535 C []string 536 } 537 otherProps struct { 538 PropsTestModuleEmbedded 539 540 D *int64 541 Nested struct { 542 E *string 543 } 544 F *string `blueprint:"mutated"` 545 546 Slice_of_struct []StructInSlice 547 } 548} 549 550func propsTestModuleFactory() Module { 551 module := &propsTestModule{} 552 module.AddProperties(&module.props, &module.otherProps) 553 InitAndroidArchModule(module, HostAndDeviceSupported, MultilibBoth) 554 InitDefaultableModule(module) 555 return module 556} 557 558type propsTestModuleDefaults struct { 559 ModuleBase 560 DefaultsModuleBase 561} 562 563func propsTestModuleDefaultsFactory() Module { 564 defaults := &propsTestModuleDefaults{} 565 module := propsTestModule{} 566 defaults.AddProperties(&module.props, &module.otherProps) 567 InitDefaultsModule(defaults) 568 return defaults 569} 570 571func (p *propsTestModule) GenerateAndroidBuildActions(ctx ModuleContext) { 572 str := "abc" 573 p.otherProps.F = &str 574} 575 576func TestUsedProperties(t *testing.T) { 577 testCases := []struct { 578 desc string 579 bp string 580 expectedProps []propInfo 581 }{ 582 { 583 desc: "only name", 584 bp: `test { 585 name: "foo", 586 } 587 `, 588 expectedProps: []propInfo{ 589 propInfo{Name: "Name", Type: "string", Value: "foo"}, 590 }, 591 }, 592 { 593 desc: "some props", 594 bp: `test { 595 name: "foo", 596 a: "abc", 597 b: true, 598 d: 123, 599 } 600 `, 601 expectedProps: []propInfo{ 602 propInfo{Name: "A", Type: "string", Value: "abc"}, 603 propInfo{Name: "B", Type: "bool", Value: "true"}, 604 propInfo{Name: "D", Type: "int64", Value: "123"}, 605 propInfo{Name: "Name", Type: "string", Value: "foo"}, 606 }, 607 }, 608 { 609 desc: "unused non-pointer prop", 610 bp: `test { 611 name: "foo", 612 b: true, 613 d: 123, 614 } 615 `, 616 expectedProps: []propInfo{ 617 // for non-pointer cannot distinguish between unused and intentionally set to empty 618 propInfo{Name: "A", Type: "string", Value: ""}, 619 propInfo{Name: "B", Type: "bool", Value: "true"}, 620 propInfo{Name: "D", Type: "int64", Value: "123"}, 621 propInfo{Name: "Name", Type: "string", Value: "foo"}, 622 }, 623 }, 624 { 625 desc: "nested props", 626 bp: `test { 627 name: "foo", 628 nested: { 629 e: "abc", 630 } 631 } 632 `, 633 expectedProps: []propInfo{ 634 propInfo{Name: "Name", Type: "string", Value: "foo"}, 635 propInfo{Name: "Nested.E", Type: "string", Value: "abc"}, 636 }, 637 }, 638 { 639 desc: "arch props", 640 bp: `test { 641 name: "foo", 642 arch: { 643 x86_64: { 644 a: "abc", 645 }, 646 } 647 } 648 `, 649 expectedProps: []propInfo{ 650 propInfo{Name: "Arch.X86_64.A", Type: "string", Value: "abc"}, 651 propInfo{Name: "Name", Type: "string", Value: "foo"}, 652 }, 653 }, 654 { 655 desc: "embedded props", 656 bp: `test { 657 name: "foo", 658 embedded_prop: "a", 659 } 660 `, 661 expectedProps: []propInfo{ 662 propInfo{Name: "Embedded_prop", Type: "string", Value: "a"}, 663 propInfo{Name: "Name", Type: "string", Value: "foo"}, 664 }, 665 }, 666 { 667 desc: "struct slice", 668 bp: `test { 669 name: "foo", 670 slice_of_struct: [ 671 { 672 g: "abc", 673 h: false, 674 i: ["baz"], 675 }, 676 { 677 g: "def", 678 h: true, 679 i: [], 680 }, 681 ] 682 } 683 `, 684 expectedProps: []propInfo{ 685 propInfo{Name: "Name", Type: "string", Value: "foo"}, 686 propInfo{Name: "Slice_of_struct", Type: "struct slice", Values: []string{ 687 `android.StructInSlice{G: abc, H: false, I: [baz]}`, 688 `android.StructInSlice{G: def, H: true, I: []}`, 689 }}, 690 }, 691 }, 692 { 693 desc: "defaults", 694 bp: ` 695test_defaults { 696 name: "foo_defaults", 697 a: "a", 698 b: true, 699 c: ["default_c"], 700 embedded_prop:"a", 701 arch: { 702 x86_64: { 703 a: "x86_64 a", 704 }, 705 }, 706} 707test { 708 name: "foo", 709 defaults: ["foo_defaults"], 710 c: ["c"], 711 nested: { 712 e: "nested e", 713 }, 714 target: { 715 linux: { 716 a: "a", 717 }, 718 }, 719} 720 `, 721 expectedProps: []propInfo{ 722 propInfo{Name: "A", Type: "string", Value: "a"}, 723 propInfo{Name: "Arch.X86_64.A", Type: "string", Value: "x86_64 a"}, 724 propInfo{Name: "B", Type: "bool", Value: "true"}, 725 propInfo{Name: "C", Type: "string slice", Values: []string{"default_c", "c"}}, 726 propInfo{Name: "Defaults", Type: "string slice", Values: []string{"foo_defaults"}}, 727 propInfo{Name: "Embedded_prop", Type: "string", Value: "a"}, 728 propInfo{Name: "Name", Type: "string", Value: "foo"}, 729 propInfo{Name: "Nested.E", Type: "string", Value: "nested e"}, 730 propInfo{Name: "Target.Linux.A", Type: "string", Value: "a"}, 731 }, 732 }, 733 } 734 735 for _, tc := range testCases { 736 t.Run(tc.desc, func(t *testing.T) { 737 result := GroupFixturePreparers( 738 PrepareForTestWithAllowMissingDependencies, 739 PrepareForTestWithDefaults, 740 FixtureRegisterWithContext(func(ctx RegistrationContext) { 741 ctx.RegisterModuleType("test", propsTestModuleFactory) 742 ctx.RegisterModuleType("test_defaults", propsTestModuleDefaultsFactory) 743 }), 744 FixtureWithRootAndroidBp(tc.bp), 745 ).RunTest(t) 746 747 foo := result.ModuleForTests(t, "foo", "").Module().base() 748 749 AssertDeepEquals(t, "foo ", tc.expectedProps, foo.propertiesWithValues()) 750 }) 751 } 752} 753 754func TestSortedUniqueNamedPaths(t *testing.T) { 755 type np struct { 756 path, name string 757 } 758 makePaths := func(l []np) NamedPaths { 759 result := make(NamedPaths, 0, len(l)) 760 for _, p := range l { 761 result = append(result, NamedPath{PathForTesting(p.path), p.name}) 762 } 763 return result 764 } 765 766 tests := []struct { 767 name string 768 in []np 769 expectedOut []np 770 }{ 771 { 772 name: "empty", 773 in: []np{}, 774 expectedOut: []np{}, 775 }, 776 { 777 name: "all_same", 778 in: []np{ 779 {"a.txt", "A"}, 780 {"a.txt", "A"}, 781 {"a.txt", "A"}, 782 {"a.txt", "A"}, 783 {"a.txt", "A"}, 784 }, 785 expectedOut: []np{ 786 {"a.txt", "A"}, 787 }, 788 }, 789 { 790 name: "same_path_different_names", 791 in: []np{ 792 {"a.txt", "C"}, 793 {"a.txt", "A"}, 794 {"a.txt", "D"}, 795 {"a.txt", "B"}, 796 {"a.txt", "E"}, 797 }, 798 expectedOut: []np{ 799 {"a.txt", "A"}, 800 {"a.txt", "B"}, 801 {"a.txt", "C"}, 802 {"a.txt", "D"}, 803 {"a.txt", "E"}, 804 }, 805 }, 806 { 807 name: "different_paths_same_name", 808 in: []np{ 809 {"b/b.txt", "A"}, 810 {"a/a.txt", "A"}, 811 {"a/txt", "A"}, 812 {"b", "A"}, 813 {"a/b/d", "A"}, 814 }, 815 expectedOut: []np{ 816 {"a/a.txt", "A"}, 817 {"a/b/d", "A"}, 818 {"a/txt", "A"}, 819 {"b/b.txt", "A"}, 820 {"b", "A"}, 821 }, 822 }, 823 { 824 name: "all_different", 825 in: []np{ 826 {"b/b.txt", "A"}, 827 {"a/a.txt", "B"}, 828 {"a/txt", "D"}, 829 {"b", "C"}, 830 {"a/b/d", "E"}, 831 }, 832 expectedOut: []np{ 833 {"a/a.txt", "B"}, 834 {"a/b/d", "E"}, 835 {"a/txt", "D"}, 836 {"b/b.txt", "A"}, 837 {"b", "C"}, 838 }, 839 }, 840 { 841 name: "some_different", 842 in: []np{ 843 {"b/b.txt", "A"}, 844 {"a/a.txt", "B"}, 845 {"a/txt", "D"}, 846 {"a/b/d", "E"}, 847 {"b", "C"}, 848 {"a/a.txt", "B"}, 849 {"a/b/d", "E"}, 850 }, 851 expectedOut: []np{ 852 {"a/a.txt", "B"}, 853 {"a/b/d", "E"}, 854 {"a/txt", "D"}, 855 {"b/b.txt", "A"}, 856 {"b", "C"}, 857 }, 858 }, 859 } 860 for _, tt := range tests { 861 t.Run(tt.name, func(t *testing.T) { 862 actual := SortedUniqueNamedPaths(makePaths(tt.in)) 863 expected := makePaths(tt.expectedOut) 864 t.Logf("actual: %v", actual) 865 t.Logf("expected: %v", expected) 866 AssertDeepEquals(t, "SortedUniqueNamedPaths ", expected, actual) 867 }) 868 } 869} 870 871func TestSetAndroidMkEntriesWithTestOptions(t *testing.T) { 872 tests := []struct { 873 name string 874 testOptions CommonTestOptions 875 expected map[string][]string 876 }{ 877 { 878 name: "empty", 879 testOptions: CommonTestOptions{}, 880 expected: map[string][]string{}, 881 }, 882 { 883 name: "is unit test", 884 testOptions: CommonTestOptions{ 885 Unit_test: boolPtr(true), 886 }, 887 expected: map[string][]string{ 888 "LOCAL_IS_UNIT_TEST": []string{"true"}, 889 }, 890 }, 891 { 892 name: "is not unit test", 893 testOptions: CommonTestOptions{ 894 Unit_test: boolPtr(false), 895 }, 896 expected: map[string][]string{}, 897 }, 898 { 899 name: "empty tag", 900 testOptions: CommonTestOptions{ 901 Tags: []string{}, 902 }, 903 expected: map[string][]string{}, 904 }, 905 { 906 name: "single tag", 907 testOptions: CommonTestOptions{ 908 Tags: []string{"tag1"}, 909 }, 910 expected: map[string][]string{ 911 "LOCAL_TEST_OPTIONS_TAGS": []string{"tag1"}, 912 }, 913 }, 914 { 915 name: "multiple tag", 916 testOptions: CommonTestOptions{ 917 Tags: []string{"tag1", "tag2", "tag3"}, 918 }, 919 expected: map[string][]string{ 920 "LOCAL_TEST_OPTIONS_TAGS": []string{"tag1", "tag2", "tag3"}, 921 }, 922 }, 923 } 924 for _, tt := range tests { 925 t.Run(tt.name, func(t *testing.T) { 926 actualEntries := AndroidMkEntries{ 927 EntryMap: map[string][]string{}, 928 } 929 tt.testOptions.SetAndroidMkEntries(&actualEntries) 930 actual := actualEntries.EntryMap 931 t.Logf("actual: %v", actual) 932 t.Logf("expected: %v", tt.expected) 933 AssertDeepEquals(t, "TestProcessCommonTestOptions ", tt.expected, actual) 934 }) 935 } 936} 937 938type sourceProducerTestModule struct { 939 ModuleBase 940 props struct { 941 // A represents the source file 942 A string 943 } 944} 945 946func sourceProducerTestModuleFactory() Module { 947 module := &sourceProducerTestModule{} 948 module.AddProperties(&module.props) 949 InitAndroidModule(module) 950 return module 951} 952 953func (s sourceProducerTestModule) GenerateAndroidBuildActions(ModuleContext) {} 954 955func (s sourceProducerTestModule) Srcs() Paths { return PathsForTesting(s.props.A) } 956 957type outputFilesTestModule struct { 958 ModuleBase 959 props struct { 960 // A represents the tag 961 A string 962 // B represents the output file for tag A 963 B string 964 } 965} 966 967func outputFilesTestModuleFactory() Module { 968 module := &outputFilesTestModule{} 969 module.AddProperties(&module.props) 970 InitAndroidModule(module) 971 return module 972} 973 974func (o outputFilesTestModule) GenerateAndroidBuildActions(ctx ModuleContext) { 975 if o.props.A != "" || o.props.B != "" { 976 ctx.SetOutputFiles(PathsForTesting(o.props.B), o.props.A) 977 } 978 // This is to simulate the case that some module uses an object to set its 979 // OutputFilesProvider, but the object itself is empty. 980 ctx.SetOutputFiles(Paths{}, "missing") 981} 982 983type pathContextAddMissingDependenciesWrapper struct { 984 PathContext 985 OtherModuleProviderContext 986 missingDeps []string 987} 988 989func (p *pathContextAddMissingDependenciesWrapper) AddMissingDependencies(deps []string) { 990 p.missingDeps = append(p.missingDeps, deps...) 991} 992func (p *pathContextAddMissingDependenciesWrapper) OtherModuleName(module blueprint.Module) string { 993 return module.Name() 994} 995 996func (p *pathContextAddMissingDependenciesWrapper) Module() Module { return nil } 997 998func (p *pathContextAddMissingDependenciesWrapper) GetOutputFiles() OutputFilesInfo { 999 return OutputFilesInfo{} 1000} 1001 1002func (p *pathContextAddMissingDependenciesWrapper) EqualModules(m1, m2 Module) bool { 1003 return m1 == m2 1004} 1005 1006func TestOutputFileForModule(t *testing.T) { 1007 testcases := []struct { 1008 name string 1009 bp string 1010 tag string 1011 expected string 1012 missingDeps []string 1013 env map[string]string 1014 config func(*config) 1015 }{ 1016 { 1017 name: "SourceFileProducer", 1018 bp: `spt_module { 1019 name: "test_module", 1020 a: "spt.txt", 1021 } 1022 `, 1023 tag: "", 1024 expected: "spt.txt", 1025 }, 1026 { 1027 name: "OutputFileProviderEmptyStringTag", 1028 bp: `oft_module { 1029 name: "test_module", 1030 a: "", 1031 b: "empty.txt", 1032 } 1033 `, 1034 tag: "", 1035 expected: "empty.txt", 1036 }, 1037 { 1038 name: "OutputFileProviderTag", 1039 bp: `oft_module { 1040 name: "test_module", 1041 a: "foo", 1042 b: "foo.txt", 1043 } 1044 `, 1045 tag: "foo", 1046 expected: "foo.txt", 1047 }, 1048 { 1049 name: "OutputFileAllowMissingDependencies", 1050 bp: `oft_module { 1051 name: "test_module", 1052 } 1053 `, 1054 tag: "missing", 1055 expected: "missing_output_file/test_module", 1056 missingDeps: []string{"test_module"}, 1057 config: func(config *config) { 1058 config.TestProductVariables.Allow_missing_dependencies = boolPtr(true) 1059 }, 1060 }, 1061 } 1062 1063 for _, tt := range testcases { 1064 t.Run(tt.name, func(t *testing.T) { 1065 result := GroupFixturePreparers( 1066 PrepareForTestWithDefaults, 1067 FixtureRegisterWithContext(func(ctx RegistrationContext) { 1068 ctx.RegisterModuleType("spt_module", sourceProducerTestModuleFactory) 1069 ctx.RegisterModuleType("oft_module", outputFilesTestModuleFactory) 1070 }), 1071 FixtureWithRootAndroidBp(tt.bp), 1072 ).RunTest(t) 1073 1074 config := TestConfig(buildDir, tt.env, tt.bp, nil) 1075 if tt.config != nil { 1076 tt.config(config.config) 1077 } 1078 ctx := &pathContextAddMissingDependenciesWrapper{ 1079 PathContext: PathContextForTesting(config), 1080 OtherModuleProviderContext: result.TestContext.OtherModuleProviderAdaptor(), 1081 } 1082 got := OutputFileForModule(ctx, result.ModuleForTests(t, "test_module", "").Module(), tt.tag) 1083 AssertPathRelativeToTopEquals(t, "expected output path", tt.expected, got) 1084 AssertArrayString(t, "expected missing deps", tt.missingDeps, ctx.missingDeps) 1085 }) 1086 } 1087} 1088 1089func TestVintfFragmentModulesChecksPartition(t *testing.T) { 1090 bp := ` 1091 vintf_fragment { 1092 name: "vintfModA", 1093 src: "test_vintf_file", 1094 vendor: true, 1095 } 1096 deps { 1097 name: "modA", 1098 vintf_fragment_modules: [ 1099 "vintfModA", 1100 ] 1101 } 1102 ` 1103 1104 testPreparer := GroupFixturePreparers( 1105 PrepareForTestWithAndroidBuildComponents, 1106 prepareForModuleTests, 1107 ) 1108 1109 testPreparer. 1110 ExtendWithErrorHandler(FixtureExpectsOneErrorPattern( 1111 "Module .+ and Vintf_fragment .+ are installed to different partitions.")). 1112 RunTestWithBp(t, bp) 1113} 1114 1115func TestInvalidModuleName(t *testing.T) { 1116 bp := ` 1117 deps { 1118 name: "fo o", 1119 } 1120 ` 1121 prepareForModuleTests. 1122 ExtendWithErrorHandler(FixtureExpectsOneErrorPattern(`should use a valid name`)). 1123 RunTestWithBp(t, bp) 1124} 1125