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(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/soong/target/product/test_device/system", name)) 331 } 332 333 symlinkRule := func(name string) TestingBuildParams { 334 return module(name, false).Output(filepath.Join("out/soong/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/soong/host/linux-x86", name)) 341 } 342 343 hostSymlinkRule := func(name string) TestingBuildParams { 344 return module(name, true).Output(filepath.Join("out/soong/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 variant := "android_common" 438 if host { 439 variant = result.Config.BuildOSCommonTarget.String() 440 } 441 return result.ModuleForTests(name, variant) 442 } 443 444 outputRule := func(name string) TestingBuildParams { return module(name, false).Output(name) } 445 446 ruleForOutput := func(output string) InstallMakeRule { 447 for _, rule := range rules { 448 if rule.Target == output { 449 return rule 450 } 451 } 452 t.Fatalf("no make install rule for %s", output) 453 return InstallMakeRule{} 454 } 455 456 installRule := func(name string) InstallMakeRule { 457 return ruleForOutput(filepath.Join("out/target/product/test_device/system", name)) 458 } 459 460 symlinkRule := func(name string) InstallMakeRule { 461 return ruleForOutput(filepath.Join("out/target/product/test_device/system/symlinks", name)) 462 } 463 464 hostOutputRule := func(name string) TestingBuildParams { return module(name, true).Output(name) } 465 466 hostInstallRule := func(name string) InstallMakeRule { 467 return ruleForOutput(filepath.Join("out/host/linux-x86", name)) 468 } 469 470 hostSymlinkRule := func(name string) InstallMakeRule { 471 return ruleForOutput(filepath.Join("out/host/linux-x86/symlinks", name)) 472 } 473 474 assertDeps := func(rule InstallMakeRule, deps ...string) { 475 t.Helper() 476 AssertArrayString(t, "expected inputs", deps, rule.Deps) 477 } 478 479 assertOrderOnlys := func(rule InstallMakeRule, orderonlys ...string) { 480 t.Helper() 481 AssertArrayString(t, "expected orderonly dependencies", orderonlys, rule.OrderOnlyDeps) 482 } 483 484 // Check host install rule dependencies 485 assertDeps(hostInstallRule("foo"), 486 hostOutputRule("foo").Output.String(), 487 hostInstallRule("bar").Target, 488 hostSymlinkRule("bar").Target, 489 hostInstallRule("baz").Target, 490 hostSymlinkRule("baz").Target, 491 hostInstallRule("qux").Target, 492 hostSymlinkRule("qux").Target, 493 ) 494 assertOrderOnlys(hostInstallRule("foo")) 495 496 // Check host symlink rule dependencies. Host symlinks must use a normal dependency, not an 497 // order-only dependency, so that the tool gets updated when the symlink is depended on. 498 assertDeps(hostSymlinkRule("foo"), hostInstallRule("foo").Target) 499 assertOrderOnlys(hostSymlinkRule("foo")) 500 501 // Check device install rule dependencies 502 assertDeps(installRule("foo"), outputRule("foo").Output.String()) 503 assertOrderOnlys(installRule("foo"), 504 installRule("bar").Target, 505 symlinkRule("bar").Target, 506 installRule("baz").Target, 507 symlinkRule("baz").Target, 508 installRule("qux").Target, 509 symlinkRule("qux").Target, 510 ) 511 512 // Check device symlink rule dependencies. Device symlinks could use an order-only dependency, 513 // but the current implementation uses a normal dependency. 514 assertDeps(symlinkRule("foo"), installRule("foo").Target) 515 assertOrderOnlys(symlinkRule("foo")) 516} 517 518type PropsTestModuleEmbedded struct { 519 Embedded_prop *string 520} 521 522type StructInSlice struct { 523 G string 524 H bool 525 I []string 526} 527 528type propsTestModule struct { 529 ModuleBase 530 DefaultableModuleBase 531 props struct { 532 A string `android:"arch_variant"` 533 B *bool 534 C []string 535 } 536 otherProps struct { 537 PropsTestModuleEmbedded 538 539 D *int64 540 Nested struct { 541 E *string 542 } 543 F *string `blueprint:"mutated"` 544 545 Slice_of_struct []StructInSlice 546 } 547} 548 549func propsTestModuleFactory() Module { 550 module := &propsTestModule{} 551 module.AddProperties(&module.props, &module.otherProps) 552 InitAndroidArchModule(module, HostAndDeviceSupported, MultilibBoth) 553 InitDefaultableModule(module) 554 return module 555} 556 557type propsTestModuleDefaults struct { 558 ModuleBase 559 DefaultsModuleBase 560} 561 562func propsTestModuleDefaultsFactory() Module { 563 defaults := &propsTestModuleDefaults{} 564 module := propsTestModule{} 565 defaults.AddProperties(&module.props, &module.otherProps) 566 InitDefaultsModule(defaults) 567 return defaults 568} 569 570func (p *propsTestModule) GenerateAndroidBuildActions(ctx ModuleContext) { 571 str := "abc" 572 p.otherProps.F = &str 573} 574 575func TestUsedProperties(t *testing.T) { 576 testCases := []struct { 577 desc string 578 bp string 579 expectedProps []propInfo 580 }{ 581 { 582 desc: "only name", 583 bp: `test { 584 name: "foo", 585 } 586 `, 587 expectedProps: []propInfo{ 588 propInfo{Name: "Name", Type: "string", Value: "foo"}, 589 }, 590 }, 591 { 592 desc: "some props", 593 bp: `test { 594 name: "foo", 595 a: "abc", 596 b: true, 597 d: 123, 598 } 599 `, 600 expectedProps: []propInfo{ 601 propInfo{Name: "A", Type: "string", Value: "abc"}, 602 propInfo{Name: "B", Type: "bool", Value: "true"}, 603 propInfo{Name: "D", Type: "int64", Value: "123"}, 604 propInfo{Name: "Name", Type: "string", Value: "foo"}, 605 }, 606 }, 607 { 608 desc: "unused non-pointer prop", 609 bp: `test { 610 name: "foo", 611 b: true, 612 d: 123, 613 } 614 `, 615 expectedProps: []propInfo{ 616 // for non-pointer cannot distinguish between unused and intentionally set to empty 617 propInfo{Name: "A", Type: "string", Value: ""}, 618 propInfo{Name: "B", Type: "bool", Value: "true"}, 619 propInfo{Name: "D", Type: "int64", Value: "123"}, 620 propInfo{Name: "Name", Type: "string", Value: "foo"}, 621 }, 622 }, 623 { 624 desc: "nested props", 625 bp: `test { 626 name: "foo", 627 nested: { 628 e: "abc", 629 } 630 } 631 `, 632 expectedProps: []propInfo{ 633 propInfo{Name: "Name", Type: "string", Value: "foo"}, 634 propInfo{Name: "Nested.E", Type: "string", Value: "abc"}, 635 }, 636 }, 637 { 638 desc: "arch props", 639 bp: `test { 640 name: "foo", 641 arch: { 642 x86_64: { 643 a: "abc", 644 }, 645 } 646 } 647 `, 648 expectedProps: []propInfo{ 649 propInfo{Name: "Arch.X86_64.A", Type: "string", Value: "abc"}, 650 propInfo{Name: "Name", Type: "string", Value: "foo"}, 651 }, 652 }, 653 { 654 desc: "embedded props", 655 bp: `test { 656 name: "foo", 657 embedded_prop: "a", 658 } 659 `, 660 expectedProps: []propInfo{ 661 propInfo{Name: "Embedded_prop", Type: "string", Value: "a"}, 662 propInfo{Name: "Name", Type: "string", Value: "foo"}, 663 }, 664 }, 665 { 666 desc: "struct slice", 667 bp: `test { 668 name: "foo", 669 slice_of_struct: [ 670 { 671 g: "abc", 672 h: false, 673 i: ["baz"], 674 }, 675 { 676 g: "def", 677 h: true, 678 i: [], 679 }, 680 ] 681 } 682 `, 683 expectedProps: []propInfo{ 684 propInfo{Name: "Name", Type: "string", Value: "foo"}, 685 propInfo{Name: "Slice_of_struct", Type: "struct slice", Values: []string{ 686 `android.StructInSlice{G: abc, H: false, I: [baz]}`, 687 `android.StructInSlice{G: def, H: true, I: []}`, 688 }}, 689 }, 690 }, 691 { 692 desc: "defaults", 693 bp: ` 694test_defaults { 695 name: "foo_defaults", 696 a: "a", 697 b: true, 698 c: ["default_c"], 699 embedded_prop:"a", 700 arch: { 701 x86_64: { 702 a: "x86_64 a", 703 }, 704 }, 705} 706test { 707 name: "foo", 708 defaults: ["foo_defaults"], 709 c: ["c"], 710 nested: { 711 e: "nested e", 712 }, 713 target: { 714 linux: { 715 a: "a", 716 }, 717 }, 718} 719 `, 720 expectedProps: []propInfo{ 721 propInfo{Name: "A", Type: "string", Value: "a"}, 722 propInfo{Name: "Arch.X86_64.A", Type: "string", Value: "x86_64 a"}, 723 propInfo{Name: "B", Type: "bool", Value: "true"}, 724 propInfo{Name: "C", Type: "string slice", Values: []string{"default_c", "c"}}, 725 propInfo{Name: "Defaults", Type: "string slice", Values: []string{"foo_defaults"}}, 726 propInfo{Name: "Embedded_prop", Type: "string", Value: "a"}, 727 propInfo{Name: "Name", Type: "string", Value: "foo"}, 728 propInfo{Name: "Nested.E", Type: "string", Value: "nested e"}, 729 propInfo{Name: "Target.Linux.A", Type: "string", Value: "a"}, 730 }, 731 }, 732 } 733 734 for _, tc := range testCases { 735 t.Run(tc.desc, func(t *testing.T) { 736 result := GroupFixturePreparers( 737 PrepareForTestWithAllowMissingDependencies, 738 PrepareForTestWithDefaults, 739 FixtureRegisterWithContext(func(ctx RegistrationContext) { 740 ctx.RegisterModuleType("test", propsTestModuleFactory) 741 ctx.RegisterModuleType("test_defaults", propsTestModuleDefaultsFactory) 742 }), 743 FixtureWithRootAndroidBp(tc.bp), 744 ).RunTest(t) 745 746 foo := result.ModuleForTests("foo", "").Module().base() 747 748 AssertDeepEquals(t, "foo ", tc.expectedProps, foo.propertiesWithValues()) 749 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 fakeBlueprintModule struct{} 939 940func (fakeBlueprintModule) Name() string { return "foo" } 941 942func (fakeBlueprintModule) GenerateBuildActions(blueprint.ModuleContext) {} 943 944type sourceProducerTestModule struct { 945 fakeBlueprintModule 946 source Path 947} 948 949func (s sourceProducerTestModule) Srcs() Paths { return Paths{s.source} } 950 951type outputFileProducerTestModule struct { 952 fakeBlueprintModule 953 output map[string]Path 954 error map[string]error 955} 956 957func (o outputFileProducerTestModule) OutputFiles(tag string) (Paths, error) { 958 return PathsIfNonNil(o.output[tag]), o.error[tag] 959} 960 961type pathContextAddMissingDependenciesWrapper struct { 962 PathContext 963 missingDeps []string 964} 965 966func (p *pathContextAddMissingDependenciesWrapper) AddMissingDependencies(deps []string) { 967 p.missingDeps = append(p.missingDeps, deps...) 968} 969func (p *pathContextAddMissingDependenciesWrapper) OtherModuleName(module blueprint.Module) string { 970 return module.Name() 971} 972 973func TestOutputFileForModule(t *testing.T) { 974 testcases := []struct { 975 name string 976 module blueprint.Module 977 tag string 978 env map[string]string 979 config func(*config) 980 expected string 981 missingDeps []string 982 }{ 983 { 984 name: "SourceFileProducer", 985 module: &sourceProducerTestModule{source: PathForTesting("foo.txt")}, 986 expected: "foo.txt", 987 }, 988 { 989 name: "OutputFileProducer", 990 module: &outputFileProducerTestModule{output: map[string]Path{"": PathForTesting("foo.txt")}}, 991 expected: "foo.txt", 992 }, 993 { 994 name: "OutputFileProducer_tag", 995 module: &outputFileProducerTestModule{output: map[string]Path{"foo": PathForTesting("foo.txt")}}, 996 tag: "foo", 997 expected: "foo.txt", 998 }, 999 { 1000 name: "OutputFileProducer_AllowMissingDependencies", 1001 config: func(config *config) { 1002 config.TestProductVariables.Allow_missing_dependencies = boolPtr(true) 1003 }, 1004 module: &outputFileProducerTestModule{}, 1005 missingDeps: []string{"foo"}, 1006 expected: "missing_output_file/foo", 1007 }, 1008 } 1009 for _, tt := range testcases { 1010 config := TestConfig(buildDir, tt.env, "", nil) 1011 if tt.config != nil { 1012 tt.config(config.config) 1013 } 1014 ctx := &pathContextAddMissingDependenciesWrapper{ 1015 PathContext: PathContextForTesting(config), 1016 } 1017 got := OutputFileForModule(ctx, tt.module, tt.tag) 1018 AssertPathRelativeToTopEquals(t, "expected source path", tt.expected, got) 1019 AssertArrayString(t, "expected missing deps", tt.missingDeps, ctx.missingDeps) 1020 } 1021} 1022