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