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 "errors" 19 "fmt" 20 "io/ioutil" 21 "os" 22 "reflect" 23 "strings" 24 "testing" 25 26 "github.com/google/blueprint/pathtools" 27 "github.com/google/blueprint/proptools" 28) 29 30type strsTestCase struct { 31 in []string 32 out string 33 err []error 34} 35 36var commonValidatePathTestCases = []strsTestCase{ 37 { 38 in: []string{""}, 39 out: "", 40 }, 41 { 42 in: []string{"a/b"}, 43 out: "a/b", 44 }, 45 { 46 in: []string{"a/b", "c"}, 47 out: "a/b/c", 48 }, 49 { 50 in: []string{"a/.."}, 51 out: ".", 52 }, 53 { 54 in: []string{"."}, 55 out: ".", 56 }, 57 { 58 in: []string{".."}, 59 out: "", 60 err: []error{errors.New("Path is outside directory: ..")}, 61 }, 62 { 63 in: []string{"../a"}, 64 out: "", 65 err: []error{errors.New("Path is outside directory: ../a")}, 66 }, 67 { 68 in: []string{"b/../../a"}, 69 out: "", 70 err: []error{errors.New("Path is outside directory: ../a")}, 71 }, 72 { 73 in: []string{"/a"}, 74 out: "", 75 err: []error{errors.New("Path is outside directory: /a")}, 76 }, 77 { 78 in: []string{"a", "../b"}, 79 out: "", 80 err: []error{errors.New("Path is outside directory: ../b")}, 81 }, 82 { 83 in: []string{"a", "b/../../c"}, 84 out: "", 85 err: []error{errors.New("Path is outside directory: ../c")}, 86 }, 87 { 88 in: []string{"a", "./.."}, 89 out: "", 90 err: []error{errors.New("Path is outside directory: ..")}, 91 }, 92} 93 94var validateSafePathTestCases = append(commonValidatePathTestCases, []strsTestCase{ 95 { 96 in: []string{"$host/../$a"}, 97 out: "$a", 98 }, 99}...) 100 101var validatePathTestCases = append(commonValidatePathTestCases, []strsTestCase{ 102 { 103 in: []string{"$host/../$a"}, 104 out: "", 105 err: []error{errors.New("Path contains invalid character($): $host/../$a")}, 106 }, 107 { 108 in: []string{"$host/.."}, 109 out: "", 110 err: []error{errors.New("Path contains invalid character($): $host/..")}, 111 }, 112}...) 113 114func TestValidateSafePath(t *testing.T) { 115 for _, testCase := range validateSafePathTestCases { 116 t.Run(strings.Join(testCase.in, ","), func(t *testing.T) { 117 ctx := &configErrorWrapper{} 118 out, err := validateSafePath(testCase.in...) 119 if err != nil { 120 reportPathError(ctx, err) 121 } 122 check(t, "validateSafePath", p(testCase.in), out, ctx.errors, testCase.out, testCase.err) 123 }) 124 } 125} 126 127func TestValidatePath(t *testing.T) { 128 for _, testCase := range validatePathTestCases { 129 t.Run(strings.Join(testCase.in, ","), func(t *testing.T) { 130 ctx := &configErrorWrapper{} 131 out, err := validatePath(testCase.in...) 132 if err != nil { 133 reportPathError(ctx, err) 134 } 135 check(t, "validatePath", p(testCase.in), out, ctx.errors, testCase.out, testCase.err) 136 }) 137 } 138} 139 140func TestOptionalPath(t *testing.T) { 141 var path OptionalPath 142 checkInvalidOptionalPath(t, path) 143 144 path = OptionalPathForPath(nil) 145 checkInvalidOptionalPath(t, path) 146} 147 148func checkInvalidOptionalPath(t *testing.T, path OptionalPath) { 149 t.Helper() 150 if path.Valid() { 151 t.Errorf("Uninitialized OptionalPath should not be valid") 152 } 153 if path.String() != "" { 154 t.Errorf("Uninitialized OptionalPath String() should return \"\", not %q", path.String()) 155 } 156 defer func() { 157 if r := recover(); r == nil { 158 t.Errorf("Expected a panic when calling Path() on an uninitialized OptionalPath") 159 } 160 }() 161 path.Path() 162} 163 164func check(t *testing.T, testType, testString string, 165 got interface{}, err []error, 166 expected interface{}, expectedErr []error) { 167 t.Helper() 168 169 printedTestCase := false 170 e := func(s string, expected, got interface{}) { 171 t.Helper() 172 if !printedTestCase { 173 t.Errorf("test case %s: %s", testType, testString) 174 printedTestCase = true 175 } 176 t.Errorf("incorrect %s", s) 177 t.Errorf(" expected: %s", p(expected)) 178 t.Errorf(" got: %s", p(got)) 179 } 180 181 if !reflect.DeepEqual(expectedErr, err) { 182 e("errors:", expectedErr, err) 183 } 184 185 if !reflect.DeepEqual(expected, got) { 186 e("output:", expected, got) 187 } 188} 189 190func p(in interface{}) string { 191 if v, ok := in.([]interface{}); ok { 192 s := make([]string, len(v)) 193 for i := range v { 194 s[i] = fmt.Sprintf("%#v", v[i]) 195 } 196 return "[" + strings.Join(s, ", ") + "]" 197 } else { 198 return fmt.Sprintf("%#v", in) 199 } 200} 201 202type moduleInstallPathContextImpl struct { 203 androidBaseContextImpl 204 205 inData bool 206 inSanitizerDir bool 207 inRecovery bool 208} 209 210func (moduleInstallPathContextImpl) Fs() pathtools.FileSystem { 211 return pathtools.MockFs(nil) 212} 213 214func (m moduleInstallPathContextImpl) Config() Config { 215 return m.androidBaseContextImpl.config 216} 217 218func (moduleInstallPathContextImpl) AddNinjaFileDeps(deps ...string) {} 219 220func (m moduleInstallPathContextImpl) InstallInData() bool { 221 return m.inData 222} 223 224func (m moduleInstallPathContextImpl) InstallInSanitizerDir() bool { 225 return m.inSanitizerDir 226} 227 228func (m moduleInstallPathContextImpl) InstallInRecovery() bool { 229 return m.inRecovery 230} 231 232func TestPathForModuleInstall(t *testing.T) { 233 testConfig := TestConfig("", nil) 234 235 hostTarget := Target{Os: Linux} 236 deviceTarget := Target{Os: Android} 237 238 testCases := []struct { 239 name string 240 ctx *moduleInstallPathContextImpl 241 in []string 242 out string 243 }{ 244 { 245 name: "host binary", 246 ctx: &moduleInstallPathContextImpl{ 247 androidBaseContextImpl: androidBaseContextImpl{ 248 target: hostTarget, 249 }, 250 }, 251 in: []string{"bin", "my_test"}, 252 out: "host/linux-x86/bin/my_test", 253 }, 254 255 { 256 name: "system binary", 257 ctx: &moduleInstallPathContextImpl{ 258 androidBaseContextImpl: androidBaseContextImpl{ 259 target: deviceTarget, 260 }, 261 }, 262 in: []string{"bin", "my_test"}, 263 out: "target/product/test_device/system/bin/my_test", 264 }, 265 { 266 name: "vendor binary", 267 ctx: &moduleInstallPathContextImpl{ 268 androidBaseContextImpl: androidBaseContextImpl{ 269 target: deviceTarget, 270 kind: socSpecificModule, 271 }, 272 }, 273 in: []string{"bin", "my_test"}, 274 out: "target/product/test_device/vendor/bin/my_test", 275 }, 276 { 277 name: "odm binary", 278 ctx: &moduleInstallPathContextImpl{ 279 androidBaseContextImpl: androidBaseContextImpl{ 280 target: deviceTarget, 281 kind: deviceSpecificModule, 282 }, 283 }, 284 in: []string{"bin", "my_test"}, 285 out: "target/product/test_device/odm/bin/my_test", 286 }, 287 { 288 name: "product binary", 289 ctx: &moduleInstallPathContextImpl{ 290 androidBaseContextImpl: androidBaseContextImpl{ 291 target: deviceTarget, 292 kind: productSpecificModule, 293 }, 294 }, 295 in: []string{"bin", "my_test"}, 296 out: "target/product/test_device/product/bin/my_test", 297 }, 298 { 299 name: "product_services binary", 300 ctx: &moduleInstallPathContextImpl{ 301 androidBaseContextImpl: androidBaseContextImpl{ 302 target: deviceTarget, 303 kind: productServicesSpecificModule, 304 }, 305 }, 306 in: []string{"bin", "my_test"}, 307 out: "target/product/test_device/product_services/bin/my_test", 308 }, 309 310 { 311 name: "system native test binary", 312 ctx: &moduleInstallPathContextImpl{ 313 androidBaseContextImpl: androidBaseContextImpl{ 314 target: deviceTarget, 315 }, 316 inData: true, 317 }, 318 in: []string{"nativetest", "my_test"}, 319 out: "target/product/test_device/data/nativetest/my_test", 320 }, 321 { 322 name: "vendor native test binary", 323 ctx: &moduleInstallPathContextImpl{ 324 androidBaseContextImpl: androidBaseContextImpl{ 325 target: deviceTarget, 326 kind: socSpecificModule, 327 }, 328 inData: true, 329 }, 330 in: []string{"nativetest", "my_test"}, 331 out: "target/product/test_device/data/nativetest/my_test", 332 }, 333 { 334 name: "odm native test binary", 335 ctx: &moduleInstallPathContextImpl{ 336 androidBaseContextImpl: androidBaseContextImpl{ 337 target: deviceTarget, 338 kind: deviceSpecificModule, 339 }, 340 inData: true, 341 }, 342 in: []string{"nativetest", "my_test"}, 343 out: "target/product/test_device/data/nativetest/my_test", 344 }, 345 { 346 name: "product native test binary", 347 ctx: &moduleInstallPathContextImpl{ 348 androidBaseContextImpl: androidBaseContextImpl{ 349 target: deviceTarget, 350 kind: productSpecificModule, 351 }, 352 inData: true, 353 }, 354 in: []string{"nativetest", "my_test"}, 355 out: "target/product/test_device/data/nativetest/my_test", 356 }, 357 358 { 359 name: "product_services native test binary", 360 ctx: &moduleInstallPathContextImpl{ 361 androidBaseContextImpl: androidBaseContextImpl{ 362 target: deviceTarget, 363 kind: productServicesSpecificModule, 364 }, 365 inData: true, 366 }, 367 in: []string{"nativetest", "my_test"}, 368 out: "target/product/test_device/data/nativetest/my_test", 369 }, 370 371 { 372 name: "sanitized system binary", 373 ctx: &moduleInstallPathContextImpl{ 374 androidBaseContextImpl: androidBaseContextImpl{ 375 target: deviceTarget, 376 }, 377 inSanitizerDir: true, 378 }, 379 in: []string{"bin", "my_test"}, 380 out: "target/product/test_device/data/asan/system/bin/my_test", 381 }, 382 { 383 name: "sanitized vendor binary", 384 ctx: &moduleInstallPathContextImpl{ 385 androidBaseContextImpl: androidBaseContextImpl{ 386 target: deviceTarget, 387 kind: socSpecificModule, 388 }, 389 inSanitizerDir: true, 390 }, 391 in: []string{"bin", "my_test"}, 392 out: "target/product/test_device/data/asan/vendor/bin/my_test", 393 }, 394 { 395 name: "sanitized odm binary", 396 ctx: &moduleInstallPathContextImpl{ 397 androidBaseContextImpl: androidBaseContextImpl{ 398 target: deviceTarget, 399 kind: deviceSpecificModule, 400 }, 401 inSanitizerDir: true, 402 }, 403 in: []string{"bin", "my_test"}, 404 out: "target/product/test_device/data/asan/odm/bin/my_test", 405 }, 406 { 407 name: "sanitized product binary", 408 ctx: &moduleInstallPathContextImpl{ 409 androidBaseContextImpl: androidBaseContextImpl{ 410 target: deviceTarget, 411 kind: productSpecificModule, 412 }, 413 inSanitizerDir: true, 414 }, 415 in: []string{"bin", "my_test"}, 416 out: "target/product/test_device/data/asan/product/bin/my_test", 417 }, 418 419 { 420 name: "sanitized product_services binary", 421 ctx: &moduleInstallPathContextImpl{ 422 androidBaseContextImpl: androidBaseContextImpl{ 423 target: deviceTarget, 424 kind: productServicesSpecificModule, 425 }, 426 inSanitizerDir: true, 427 }, 428 in: []string{"bin", "my_test"}, 429 out: "target/product/test_device/data/asan/product_services/bin/my_test", 430 }, 431 432 { 433 name: "sanitized system native test binary", 434 ctx: &moduleInstallPathContextImpl{ 435 androidBaseContextImpl: androidBaseContextImpl{ 436 target: deviceTarget, 437 }, 438 inData: true, 439 inSanitizerDir: true, 440 }, 441 in: []string{"nativetest", "my_test"}, 442 out: "target/product/test_device/data/asan/data/nativetest/my_test", 443 }, 444 { 445 name: "sanitized vendor native test binary", 446 ctx: &moduleInstallPathContextImpl{ 447 androidBaseContextImpl: androidBaseContextImpl{ 448 target: deviceTarget, 449 kind: socSpecificModule, 450 }, 451 inData: true, 452 inSanitizerDir: true, 453 }, 454 in: []string{"nativetest", "my_test"}, 455 out: "target/product/test_device/data/asan/data/nativetest/my_test", 456 }, 457 { 458 name: "sanitized odm native test binary", 459 ctx: &moduleInstallPathContextImpl{ 460 androidBaseContextImpl: androidBaseContextImpl{ 461 target: deviceTarget, 462 kind: deviceSpecificModule, 463 }, 464 inData: true, 465 inSanitizerDir: true, 466 }, 467 in: []string{"nativetest", "my_test"}, 468 out: "target/product/test_device/data/asan/data/nativetest/my_test", 469 }, 470 { 471 name: "sanitized product native test binary", 472 ctx: &moduleInstallPathContextImpl{ 473 androidBaseContextImpl: androidBaseContextImpl{ 474 target: deviceTarget, 475 kind: productSpecificModule, 476 }, 477 inData: true, 478 inSanitizerDir: true, 479 }, 480 in: []string{"nativetest", "my_test"}, 481 out: "target/product/test_device/data/asan/data/nativetest/my_test", 482 }, 483 { 484 name: "sanitized product_services native test binary", 485 ctx: &moduleInstallPathContextImpl{ 486 androidBaseContextImpl: androidBaseContextImpl{ 487 target: deviceTarget, 488 kind: productServicesSpecificModule, 489 }, 490 inData: true, 491 inSanitizerDir: true, 492 }, 493 in: []string{"nativetest", "my_test"}, 494 out: "target/product/test_device/data/asan/data/nativetest/my_test", 495 }, 496 } 497 498 for _, tc := range testCases { 499 t.Run(tc.name, func(t *testing.T) { 500 tc.ctx.androidBaseContextImpl.config = testConfig 501 output := PathForModuleInstall(tc.ctx, tc.in...) 502 if output.basePath.path != tc.out { 503 t.Errorf("unexpected path:\n got: %q\nwant: %q\n", 504 output.basePath.path, 505 tc.out) 506 } 507 }) 508 } 509} 510 511func TestDirectorySortedPaths(t *testing.T) { 512 config := TestConfig("out", nil) 513 514 ctx := PathContextForTesting(config, map[string][]byte{ 515 "a.txt": nil, 516 "a/txt": nil, 517 "a/b/c": nil, 518 "a/b/d": nil, 519 "b": nil, 520 "b/b.txt": nil, 521 "a/a.txt": nil, 522 }) 523 524 makePaths := func() Paths { 525 return Paths{ 526 PathForSource(ctx, "a.txt"), 527 PathForSource(ctx, "a/txt"), 528 PathForSource(ctx, "a/b/c"), 529 PathForSource(ctx, "a/b/d"), 530 PathForSource(ctx, "b"), 531 PathForSource(ctx, "b/b.txt"), 532 PathForSource(ctx, "a/a.txt"), 533 } 534 } 535 536 expected := []string{ 537 "a.txt", 538 "a/a.txt", 539 "a/b/c", 540 "a/b/d", 541 "a/txt", 542 "b", 543 "b/b.txt", 544 } 545 546 paths := makePaths() 547 reversePaths := ReversePaths(paths) 548 549 sortedPaths := PathsToDirectorySortedPaths(paths) 550 reverseSortedPaths := PathsToDirectorySortedPaths(reversePaths) 551 552 if !reflect.DeepEqual(Paths(sortedPaths).Strings(), expected) { 553 t.Fatalf("sorted paths:\n %#v\n != \n %#v", paths.Strings(), expected) 554 } 555 556 if !reflect.DeepEqual(Paths(reverseSortedPaths).Strings(), expected) { 557 t.Fatalf("sorted reversed paths:\n %#v\n !=\n %#v", reversePaths.Strings(), expected) 558 } 559 560 expectedA := []string{ 561 "a/a.txt", 562 "a/b/c", 563 "a/b/d", 564 "a/txt", 565 } 566 567 inA := sortedPaths.PathsInDirectory("a") 568 if !reflect.DeepEqual(inA.Strings(), expectedA) { 569 t.Errorf("FilesInDirectory(a):\n %#v\n != \n %#v", inA.Strings(), expectedA) 570 } 571 572 expectedA_B := []string{ 573 "a/b/c", 574 "a/b/d", 575 } 576 577 inA_B := sortedPaths.PathsInDirectory("a/b") 578 if !reflect.DeepEqual(inA_B.Strings(), expectedA_B) { 579 t.Errorf("FilesInDirectory(a/b):\n %#v\n != \n %#v", inA_B.Strings(), expectedA_B) 580 } 581 582 expectedB := []string{ 583 "b/b.txt", 584 } 585 586 inB := sortedPaths.PathsInDirectory("b") 587 if !reflect.DeepEqual(inB.Strings(), expectedB) { 588 t.Errorf("FilesInDirectory(b):\n %#v\n != \n %#v", inA.Strings(), expectedA) 589 } 590} 591 592func TestMaybeRel(t *testing.T) { 593 testCases := []struct { 594 name string 595 base string 596 target string 597 out string 598 isRel bool 599 }{ 600 { 601 name: "normal", 602 base: "a/b/c", 603 target: "a/b/c/d", 604 out: "d", 605 isRel: true, 606 }, 607 { 608 name: "parent", 609 base: "a/b/c/d", 610 target: "a/b/c", 611 isRel: false, 612 }, 613 { 614 name: "not relative", 615 base: "a/b", 616 target: "c/d", 617 isRel: false, 618 }, 619 { 620 name: "abs1", 621 base: "/a", 622 target: "a", 623 isRel: false, 624 }, 625 { 626 name: "abs2", 627 base: "a", 628 target: "/a", 629 isRel: false, 630 }, 631 } 632 633 for _, testCase := range testCases { 634 t.Run(testCase.name, func(t *testing.T) { 635 ctx := &configErrorWrapper{} 636 out, isRel := MaybeRel(ctx, testCase.base, testCase.target) 637 if len(ctx.errors) > 0 { 638 t.Errorf("MaybeRel(..., %s, %s) reported unexpected errors %v", 639 testCase.base, testCase.target, ctx.errors) 640 } 641 if isRel != testCase.isRel || out != testCase.out { 642 t.Errorf("MaybeRel(..., %s, %s) want %v, %v got %v, %v", 643 testCase.base, testCase.target, testCase.out, testCase.isRel, out, isRel) 644 } 645 }) 646 } 647} 648 649func TestPathForSource(t *testing.T) { 650 testCases := []struct { 651 name string 652 buildDir string 653 src string 654 err string 655 }{ 656 { 657 name: "normal", 658 buildDir: "out", 659 src: "a/b/c", 660 }, 661 { 662 name: "abs", 663 buildDir: "out", 664 src: "/a/b/c", 665 err: "is outside directory", 666 }, 667 { 668 name: "in out dir", 669 buildDir: "out", 670 src: "out/a/b/c", 671 err: "is in output", 672 }, 673 } 674 675 funcs := []struct { 676 name string 677 f func(ctx PathContext, pathComponents ...string) (SourcePath, error) 678 }{ 679 {"pathForSource", pathForSource}, 680 {"safePathForSource", safePathForSource}, 681 } 682 683 for _, f := range funcs { 684 t.Run(f.name, func(t *testing.T) { 685 for _, test := range testCases { 686 t.Run(test.name, func(t *testing.T) { 687 testConfig := TestConfig(test.buildDir, nil) 688 ctx := &configErrorWrapper{config: testConfig} 689 _, err := f.f(ctx, test.src) 690 if len(ctx.errors) > 0 { 691 t.Fatalf("unexpected errors %v", ctx.errors) 692 } 693 if err != nil { 694 if test.err == "" { 695 t.Fatalf("unexpected error %q", err.Error()) 696 } else if !strings.Contains(err.Error(), test.err) { 697 t.Fatalf("incorrect error, want substring %q got %q", test.err, err.Error()) 698 } 699 } else { 700 if test.err != "" { 701 t.Fatalf("missing error %q", test.err) 702 } 703 } 704 }) 705 } 706 }) 707 } 708} 709 710type pathForModuleSrcTestModule struct { 711 ModuleBase 712 props struct { 713 Srcs []string `android:"path"` 714 Exclude_srcs []string `android:"path"` 715 716 Src *string `android:"path"` 717 718 Module_handles_missing_deps bool 719 } 720 721 src string 722 rel string 723 724 srcs []string 725 rels []string 726 727 missingDeps []string 728} 729 730func pathForModuleSrcTestModuleFactory() Module { 731 module := &pathForModuleSrcTestModule{} 732 module.AddProperties(&module.props) 733 InitAndroidModule(module) 734 return module 735} 736 737func (p *pathForModuleSrcTestModule) GenerateAndroidBuildActions(ctx ModuleContext) { 738 var srcs Paths 739 if p.props.Module_handles_missing_deps { 740 srcs, p.missingDeps = PathsAndMissingDepsForModuleSrcExcludes(ctx, p.props.Srcs, p.props.Exclude_srcs) 741 } else { 742 srcs = PathsForModuleSrcExcludes(ctx, p.props.Srcs, p.props.Exclude_srcs) 743 } 744 p.srcs = srcs.Strings() 745 746 for _, src := range srcs { 747 p.rels = append(p.rels, src.Rel()) 748 } 749 750 if p.props.Src != nil { 751 src := PathForModuleSrc(ctx, *p.props.Src) 752 if src != nil { 753 p.src = src.String() 754 p.rel = src.Rel() 755 } 756 } 757 758 if !p.props.Module_handles_missing_deps { 759 p.missingDeps = ctx.GetMissingDependencies() 760 } 761} 762 763type pathForModuleSrcTestCase struct { 764 name string 765 bp string 766 srcs []string 767 rels []string 768 src string 769 rel string 770} 771 772func testPathForModuleSrc(t *testing.T, buildDir string, tests []pathForModuleSrcTestCase) { 773 for _, test := range tests { 774 t.Run(test.name, func(t *testing.T) { 775 config := TestConfig(buildDir, nil) 776 ctx := NewTestContext() 777 778 ctx.RegisterModuleType("test", ModuleFactoryAdaptor(pathForModuleSrcTestModuleFactory)) 779 ctx.RegisterModuleType("filegroup", ModuleFactoryAdaptor(FileGroupFactory)) 780 781 fgBp := ` 782 filegroup { 783 name: "a", 784 srcs: ["src/a"], 785 } 786 ` 787 788 mockFS := map[string][]byte{ 789 "fg/Android.bp": []byte(fgBp), 790 "foo/Android.bp": []byte(test.bp), 791 "fg/src/a": nil, 792 "foo/src/b": nil, 793 "foo/src/c": nil, 794 "foo/src/d": nil, 795 "foo/src/e/e": nil, 796 "foo/src_special/$": nil, 797 } 798 799 ctx.MockFileSystem(mockFS) 800 801 ctx.Register() 802 _, errs := ctx.ParseFileList(".", []string{"fg/Android.bp", "foo/Android.bp"}) 803 FailIfErrored(t, errs) 804 _, errs = ctx.PrepareBuildActions(config) 805 FailIfErrored(t, errs) 806 807 m := ctx.ModuleForTests("foo", "").Module().(*pathForModuleSrcTestModule) 808 809 if g, w := m.srcs, test.srcs; !reflect.DeepEqual(g, w) { 810 t.Errorf("want srcs %q, got %q", w, g) 811 } 812 813 if g, w := m.rels, test.rels; !reflect.DeepEqual(g, w) { 814 t.Errorf("want rels %q, got %q", w, g) 815 } 816 817 if g, w := m.src, test.src; g != w { 818 t.Errorf("want src %q, got %q", w, g) 819 } 820 821 if g, w := m.rel, test.rel; g != w { 822 t.Errorf("want rel %q, got %q", w, g) 823 } 824 }) 825 } 826} 827 828func TestPathsForModuleSrc(t *testing.T) { 829 tests := []pathForModuleSrcTestCase{ 830 { 831 name: "path", 832 bp: ` 833 test { 834 name: "foo", 835 srcs: ["src/b"], 836 }`, 837 srcs: []string{"foo/src/b"}, 838 rels: []string{"src/b"}, 839 }, 840 { 841 name: "glob", 842 bp: ` 843 test { 844 name: "foo", 845 srcs: [ 846 "src/*", 847 "src/e/*", 848 ], 849 }`, 850 srcs: []string{"foo/src/b", "foo/src/c", "foo/src/d", "foo/src/e/e"}, 851 rels: []string{"src/b", "src/c", "src/d", "src/e/e"}, 852 }, 853 { 854 name: "recursive glob", 855 bp: ` 856 test { 857 name: "foo", 858 srcs: ["src/**/*"], 859 }`, 860 srcs: []string{"foo/src/b", "foo/src/c", "foo/src/d", "foo/src/e/e"}, 861 rels: []string{"src/b", "src/c", "src/d", "src/e/e"}, 862 }, 863 { 864 name: "filegroup", 865 bp: ` 866 test { 867 name: "foo", 868 srcs: [":a"], 869 }`, 870 srcs: []string{"fg/src/a"}, 871 rels: []string{"src/a"}, 872 }, 873 { 874 name: "special characters glob", 875 bp: ` 876 test { 877 name: "foo", 878 srcs: ["src_special/*"], 879 }`, 880 srcs: []string{"foo/src_special/$"}, 881 rels: []string{"src_special/$"}, 882 }, 883 } 884 885 buildDir, err := ioutil.TempDir("", "soong_paths_for_module_src_test") 886 if err != nil { 887 t.Fatal(err) 888 } 889 defer os.RemoveAll(buildDir) 890 891 testPathForModuleSrc(t, buildDir, tests) 892} 893 894func TestPathForModuleSrc(t *testing.T) { 895 tests := []pathForModuleSrcTestCase{ 896 { 897 name: "path", 898 bp: ` 899 test { 900 name: "foo", 901 src: "src/b", 902 }`, 903 src: "foo/src/b", 904 rel: "src/b", 905 }, 906 { 907 name: "glob", 908 bp: ` 909 test { 910 name: "foo", 911 src: "src/e/*", 912 }`, 913 src: "foo/src/e/e", 914 rel: "src/e/e", 915 }, 916 { 917 name: "filegroup", 918 bp: ` 919 test { 920 name: "foo", 921 src: ":a", 922 }`, 923 src: "fg/src/a", 924 rel: "src/a", 925 }, 926 { 927 name: "special characters glob", 928 bp: ` 929 test { 930 name: "foo", 931 src: "src_special/*", 932 }`, 933 src: "foo/src_special/$", 934 rel: "src_special/$", 935 }, 936 } 937 938 buildDir, err := ioutil.TempDir("", "soong_path_for_module_src_test") 939 if err != nil { 940 t.Fatal(err) 941 } 942 defer os.RemoveAll(buildDir) 943 944 testPathForModuleSrc(t, buildDir, tests) 945} 946 947func TestPathsForModuleSrc_AllowMissingDependencies(t *testing.T) { 948 buildDir, err := ioutil.TempDir("", "soong_paths_for_module_src_allow_missing_dependencies_test") 949 if err != nil { 950 t.Fatal(err) 951 } 952 defer os.RemoveAll(buildDir) 953 954 config := TestConfig(buildDir, nil) 955 config.TestProductVariables.Allow_missing_dependencies = proptools.BoolPtr(true) 956 957 ctx := NewTestContext() 958 ctx.SetAllowMissingDependencies(true) 959 960 ctx.RegisterModuleType("test", ModuleFactoryAdaptor(pathForModuleSrcTestModuleFactory)) 961 962 bp := ` 963 test { 964 name: "foo", 965 srcs: [":a"], 966 exclude_srcs: [":b"], 967 src: ":c", 968 } 969 970 test { 971 name: "bar", 972 srcs: [":d"], 973 exclude_srcs: [":e"], 974 module_handles_missing_deps: true, 975 } 976 ` 977 978 mockFS := map[string][]byte{ 979 "Android.bp": []byte(bp), 980 } 981 982 ctx.MockFileSystem(mockFS) 983 984 ctx.Register() 985 _, errs := ctx.ParseFileList(".", []string{"Android.bp"}) 986 FailIfErrored(t, errs) 987 _, errs = ctx.PrepareBuildActions(config) 988 FailIfErrored(t, errs) 989 990 foo := ctx.ModuleForTests("foo", "").Module().(*pathForModuleSrcTestModule) 991 992 if g, w := foo.missingDeps, []string{"a", "b", "c"}; !reflect.DeepEqual(g, w) { 993 t.Errorf("want foo missing deps %q, got %q", w, g) 994 } 995 996 if g, w := foo.srcs, []string{}; !reflect.DeepEqual(g, w) { 997 t.Errorf("want foo srcs %q, got %q", w, g) 998 } 999 1000 if g, w := foo.src, ""; g != w { 1001 t.Errorf("want foo src %q, got %q", w, g) 1002 } 1003 1004 bar := ctx.ModuleForTests("bar", "").Module().(*pathForModuleSrcTestModule) 1005 1006 if g, w := bar.missingDeps, []string{"d", "e"}; !reflect.DeepEqual(g, w) { 1007 t.Errorf("want bar missing deps %q, got %q", w, g) 1008 } 1009 1010 if g, w := bar.srcs, []string{}; !reflect.DeepEqual(g, w) { 1011 t.Errorf("want bar srcs %q, got %q", w, g) 1012 } 1013} 1014 1015func ExampleOutputPath_ReplaceExtension() { 1016 ctx := &configErrorWrapper{ 1017 config: TestConfig("out", nil), 1018 } 1019 p := PathForOutput(ctx, "system/framework").Join(ctx, "boot.art") 1020 p2 := p.ReplaceExtension(ctx, "oat") 1021 fmt.Println(p, p2) 1022 fmt.Println(p.Rel(), p2.Rel()) 1023 1024 // Output: 1025 // out/system/framework/boot.art out/system/framework/boot.oat 1026 // boot.art boot.oat 1027} 1028 1029func ExampleOutputPath_FileInSameDir() { 1030 ctx := &configErrorWrapper{ 1031 config: TestConfig("out", nil), 1032 } 1033 p := PathForOutput(ctx, "system/framework").Join(ctx, "boot.art") 1034 p2 := p.InSameDir(ctx, "oat", "arm", "boot.vdex") 1035 fmt.Println(p, p2) 1036 fmt.Println(p.Rel(), p2.Rel()) 1037 1038 // Output: 1039 // out/system/framework/boot.art out/system/framework/oat/arm/boot.vdex 1040 // boot.art oat/arm/boot.vdex 1041} 1042