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 "reflect" 21 "strconv" 22 "strings" 23 "testing" 24 25 "github.com/google/blueprint/proptools" 26) 27 28type strsTestCase struct { 29 in []string 30 out string 31 err []error 32} 33 34var commonValidatePathTestCases = []strsTestCase{ 35 { 36 in: []string{""}, 37 out: "", 38 }, 39 { 40 in: []string{"", ""}, 41 out: "", 42 }, 43 { 44 in: []string{"a", ""}, 45 out: "a", 46 }, 47 { 48 in: []string{"", "a"}, 49 out: "a", 50 }, 51 { 52 in: []string{"", "a", ""}, 53 out: "a", 54 }, 55 { 56 in: []string{"a/b"}, 57 out: "a/b", 58 }, 59 { 60 in: []string{"a/b", "c"}, 61 out: "a/b/c", 62 }, 63 { 64 in: []string{"a/.."}, 65 out: ".", 66 }, 67 { 68 in: []string{"."}, 69 out: ".", 70 }, 71 { 72 in: []string{".."}, 73 out: "", 74 err: []error{errors.New("Path is outside directory: ..")}, 75 }, 76 { 77 in: []string{"../a"}, 78 out: "", 79 err: []error{errors.New("Path is outside directory: ../a")}, 80 }, 81 { 82 in: []string{"b/../../a"}, 83 out: "", 84 err: []error{errors.New("Path is outside directory: ../a")}, 85 }, 86 { 87 in: []string{"/a"}, 88 out: "", 89 err: []error{errors.New("Path is outside directory: /a")}, 90 }, 91 { 92 in: []string{"a", "../b"}, 93 out: "", 94 err: []error{errors.New("Path is outside directory: ../b")}, 95 }, 96 { 97 in: []string{"a", "b/../../c"}, 98 out: "", 99 err: []error{errors.New("Path is outside directory: ../c")}, 100 }, 101 { 102 in: []string{"a", "./.."}, 103 out: "", 104 err: []error{errors.New("Path is outside directory: ..")}, 105 }, 106} 107 108var validateSafePathTestCases = append(commonValidatePathTestCases, []strsTestCase{ 109 { 110 in: []string{"$host/../$a"}, 111 out: "$a", 112 }, 113}...) 114 115var validatePathTestCases = append(commonValidatePathTestCases, []strsTestCase{ 116 { 117 in: []string{"$host/../$a"}, 118 out: "", 119 err: []error{errors.New("Path contains invalid character($): $host/../$a")}, 120 }, 121 { 122 in: []string{"$host/.."}, 123 out: "", 124 err: []error{errors.New("Path contains invalid character($): $host/..")}, 125 }, 126}...) 127 128func TestValidateSafePath(t *testing.T) { 129 for _, testCase := range validateSafePathTestCases { 130 t.Run(strings.Join(testCase.in, ","), func(t *testing.T) { 131 ctx := &configErrorWrapper{} 132 out, err := validateSafePath(testCase.in...) 133 if err != nil { 134 reportPathError(ctx, err) 135 } 136 check(t, "validateSafePath", p(testCase.in), out, ctx.errors, testCase.out, testCase.err) 137 }) 138 } 139} 140 141func TestValidatePath(t *testing.T) { 142 for _, testCase := range validatePathTestCases { 143 t.Run(strings.Join(testCase.in, ","), func(t *testing.T) { 144 ctx := &configErrorWrapper{} 145 out, err := validatePath(testCase.in...) 146 if err != nil { 147 reportPathError(ctx, err) 148 } 149 check(t, "validatePath", p(testCase.in), out, ctx.errors, testCase.out, testCase.err) 150 }) 151 } 152} 153 154func TestOptionalPath(t *testing.T) { 155 var path OptionalPath 156 checkInvalidOptionalPath(t, path, "unknown") 157 158 path = OptionalPathForPath(nil) 159 checkInvalidOptionalPath(t, path, "unknown") 160 161 path = InvalidOptionalPath("foo") 162 checkInvalidOptionalPath(t, path, "foo") 163 164 path = InvalidOptionalPath("") 165 checkInvalidOptionalPath(t, path, "unknown") 166 167 path = OptionalPathForPath(PathForTesting("path")) 168 checkValidOptionalPath(t, path, "path") 169} 170 171func checkInvalidOptionalPath(t *testing.T, path OptionalPath, expectedInvalidReason string) { 172 t.Helper() 173 if path.Valid() { 174 t.Errorf("Invalid OptionalPath should not be valid") 175 } 176 if path.InvalidReason() != expectedInvalidReason { 177 t.Errorf("Wrong invalid reason: expected %q, got %q", expectedInvalidReason, path.InvalidReason()) 178 } 179 if path.String() != "" { 180 t.Errorf("Invalid OptionalPath String() should return \"\", not %q", path.String()) 181 } 182 paths := path.AsPaths() 183 if len(paths) != 0 { 184 t.Errorf("Invalid OptionalPath AsPaths() should return empty Paths, not %q", paths) 185 } 186 defer func() { 187 if r := recover(); r == nil { 188 t.Errorf("Expected a panic when calling Path() on an uninitialized OptionalPath") 189 } 190 }() 191 path.Path() 192} 193 194func checkValidOptionalPath(t *testing.T, path OptionalPath, expectedString string) { 195 t.Helper() 196 if !path.Valid() { 197 t.Errorf("Initialized OptionalPath should not be invalid") 198 } 199 if path.InvalidReason() != "" { 200 t.Errorf("Initialized OptionalPath should not have an invalid reason, got: %q", path.InvalidReason()) 201 } 202 if path.String() != expectedString { 203 t.Errorf("Initialized OptionalPath String() should return %q, not %q", expectedString, path.String()) 204 } 205 paths := path.AsPaths() 206 if len(paths) != 1 { 207 t.Errorf("Initialized OptionalPath AsPaths() should return Paths with length 1, not %q", paths) 208 } 209 path.Path() 210} 211 212func check(t *testing.T, testType, testString string, 213 got interface{}, err []error, 214 expected interface{}, expectedErr []error) { 215 t.Helper() 216 217 printedTestCase := false 218 e := func(s string, expected, got interface{}) { 219 t.Helper() 220 if !printedTestCase { 221 t.Errorf("test case %s: %s", testType, testString) 222 printedTestCase = true 223 } 224 t.Errorf("incorrect %s", s) 225 t.Errorf(" expected: %s", p(expected)) 226 t.Errorf(" got: %s", p(got)) 227 } 228 229 if !reflect.DeepEqual(expectedErr, err) { 230 e("errors:", expectedErr, err) 231 } 232 233 if !reflect.DeepEqual(expected, got) { 234 e("output:", expected, got) 235 } 236} 237 238func p(in interface{}) string { 239 if v, ok := in.([]interface{}); ok { 240 s := make([]string, len(v)) 241 for i := range v { 242 s[i] = fmt.Sprintf("%#v", v[i]) 243 } 244 return "[" + strings.Join(s, ", ") + "]" 245 } else { 246 return fmt.Sprintf("%#v", in) 247 } 248} 249 250func pathTestConfig(buildDir string) Config { 251 return TestConfig(buildDir, nil, "", nil) 252} 253 254func TestPathForModuleInstall(t *testing.T) { 255 testConfig := pathTestConfig("") 256 257 hostTarget := Target{Os: Linux, Arch: Arch{ArchType: X86}} 258 deviceTarget := Target{Os: Android, Arch: Arch{ArchType: Arm64}} 259 260 testCases := []struct { 261 name string 262 ctx *testModuleInstallPathContext 263 in []string 264 out string 265 partitionDir string 266 }{ 267 { 268 name: "host binary", 269 ctx: &testModuleInstallPathContext{ 270 baseModuleContext: baseModuleContext{ 271 archModuleContext: archModuleContext{ 272 os: hostTarget.Os, 273 target: hostTarget, 274 }, 275 }, 276 }, 277 in: []string{"bin", "my_test"}, 278 out: "host/linux-x86/bin/my_test", 279 partitionDir: "host/linux-x86", 280 }, 281 282 { 283 name: "system binary", 284 ctx: &testModuleInstallPathContext{ 285 baseModuleContext: baseModuleContext{ 286 archModuleContext: archModuleContext{ 287 os: deviceTarget.Os, 288 target: deviceTarget, 289 }, 290 }, 291 }, 292 in: []string{"bin", "my_test"}, 293 out: "target/product/test_device/system/bin/my_test", 294 partitionDir: "target/product/test_device/system", 295 }, 296 { 297 name: "vendor binary", 298 ctx: &testModuleInstallPathContext{ 299 baseModuleContext: baseModuleContext{ 300 archModuleContext: archModuleContext{ 301 os: deviceTarget.Os, 302 target: deviceTarget, 303 }, 304 earlyModuleContext: earlyModuleContext{ 305 kind: socSpecificModule, 306 }, 307 }, 308 }, 309 in: []string{"bin", "my_test"}, 310 out: "target/product/test_device/vendor/bin/my_test", 311 partitionDir: "target/product/test_device/vendor", 312 }, 313 { 314 name: "odm binary", 315 ctx: &testModuleInstallPathContext{ 316 baseModuleContext: baseModuleContext{ 317 archModuleContext: archModuleContext{ 318 os: deviceTarget.Os, 319 target: deviceTarget, 320 }, 321 earlyModuleContext: earlyModuleContext{ 322 kind: deviceSpecificModule, 323 }, 324 }, 325 }, 326 in: []string{"bin", "my_test"}, 327 out: "target/product/test_device/odm/bin/my_test", 328 partitionDir: "target/product/test_device/odm", 329 }, 330 { 331 name: "product binary", 332 ctx: &testModuleInstallPathContext{ 333 baseModuleContext: baseModuleContext{ 334 archModuleContext: archModuleContext{ 335 os: deviceTarget.Os, 336 target: deviceTarget, 337 }, 338 earlyModuleContext: earlyModuleContext{ 339 kind: productSpecificModule, 340 }, 341 }, 342 }, 343 in: []string{"bin", "my_test"}, 344 out: "target/product/test_device/product/bin/my_test", 345 partitionDir: "target/product/test_device/product", 346 }, 347 { 348 name: "system_ext binary", 349 ctx: &testModuleInstallPathContext{ 350 baseModuleContext: baseModuleContext{ 351 archModuleContext: archModuleContext{ 352 os: deviceTarget.Os, 353 target: deviceTarget, 354 }, 355 earlyModuleContext: earlyModuleContext{ 356 kind: systemExtSpecificModule, 357 }, 358 }, 359 }, 360 in: []string{"bin", "my_test"}, 361 out: "target/product/test_device/system_ext/bin/my_test", 362 partitionDir: "target/product/test_device/system_ext", 363 }, 364 { 365 name: "root binary", 366 ctx: &testModuleInstallPathContext{ 367 baseModuleContext: baseModuleContext{ 368 archModuleContext: archModuleContext{ 369 os: deviceTarget.Os, 370 target: deviceTarget, 371 }, 372 }, 373 inRoot: true, 374 }, 375 in: []string{"my_test"}, 376 out: "target/product/test_device/root/my_test", 377 partitionDir: "target/product/test_device/root", 378 }, 379 { 380 name: "recovery binary", 381 ctx: &testModuleInstallPathContext{ 382 baseModuleContext: baseModuleContext{ 383 archModuleContext: archModuleContext{ 384 os: deviceTarget.Os, 385 target: deviceTarget, 386 }, 387 }, 388 inRecovery: true, 389 }, 390 in: []string{"bin/my_test"}, 391 out: "target/product/test_device/recovery/root/system/bin/my_test", 392 partitionDir: "target/product/test_device/recovery/root/system", 393 }, 394 { 395 name: "recovery root binary", 396 ctx: &testModuleInstallPathContext{ 397 baseModuleContext: baseModuleContext{ 398 archModuleContext: archModuleContext{ 399 os: deviceTarget.Os, 400 target: deviceTarget, 401 }, 402 }, 403 inRecovery: true, 404 inRoot: true, 405 }, 406 in: []string{"my_test"}, 407 out: "target/product/test_device/recovery/root/my_test", 408 partitionDir: "target/product/test_device/recovery/root", 409 }, 410 411 { 412 name: "ramdisk binary", 413 ctx: &testModuleInstallPathContext{ 414 baseModuleContext: baseModuleContext{ 415 archModuleContext: archModuleContext{ 416 os: deviceTarget.Os, 417 target: deviceTarget, 418 }, 419 }, 420 inRamdisk: true, 421 }, 422 in: []string{"my_test"}, 423 out: "target/product/test_device/ramdisk/system/my_test", 424 partitionDir: "target/product/test_device/ramdisk/system", 425 }, 426 { 427 name: "ramdisk root binary", 428 ctx: &testModuleInstallPathContext{ 429 baseModuleContext: baseModuleContext{ 430 archModuleContext: archModuleContext{ 431 os: deviceTarget.Os, 432 target: deviceTarget, 433 }, 434 }, 435 inRamdisk: true, 436 inRoot: true, 437 }, 438 in: []string{"my_test"}, 439 out: "target/product/test_device/ramdisk/my_test", 440 partitionDir: "target/product/test_device/ramdisk", 441 }, 442 { 443 name: "vendor_ramdisk binary", 444 ctx: &testModuleInstallPathContext{ 445 baseModuleContext: baseModuleContext{ 446 archModuleContext: archModuleContext{ 447 os: deviceTarget.Os, 448 target: deviceTarget, 449 }, 450 }, 451 inVendorRamdisk: true, 452 }, 453 in: []string{"my_test"}, 454 out: "target/product/test_device/vendor_ramdisk/system/my_test", 455 partitionDir: "target/product/test_device/vendor_ramdisk/system", 456 }, 457 { 458 name: "vendor_ramdisk root binary", 459 ctx: &testModuleInstallPathContext{ 460 baseModuleContext: baseModuleContext{ 461 archModuleContext: archModuleContext{ 462 os: deviceTarget.Os, 463 target: deviceTarget, 464 }, 465 }, 466 inVendorRamdisk: true, 467 inRoot: true, 468 }, 469 in: []string{"my_test"}, 470 out: "target/product/test_device/vendor_ramdisk/my_test", 471 partitionDir: "target/product/test_device/vendor_ramdisk", 472 }, 473 { 474 name: "debug_ramdisk binary", 475 ctx: &testModuleInstallPathContext{ 476 baseModuleContext: baseModuleContext{ 477 archModuleContext: archModuleContext{ 478 os: deviceTarget.Os, 479 target: deviceTarget, 480 }, 481 }, 482 inDebugRamdisk: true, 483 }, 484 in: []string{"my_test"}, 485 out: "target/product/test_device/debug_ramdisk/my_test", 486 partitionDir: "target/product/test_device/debug_ramdisk", 487 }, 488 { 489 name: "system native test binary", 490 ctx: &testModuleInstallPathContext{ 491 baseModuleContext: baseModuleContext{ 492 archModuleContext: archModuleContext{ 493 os: deviceTarget.Os, 494 target: deviceTarget, 495 }, 496 }, 497 inData: true, 498 }, 499 in: []string{"nativetest", "my_test"}, 500 out: "target/product/test_device/data/nativetest/my_test", 501 partitionDir: "target/product/test_device/data", 502 }, 503 { 504 name: "vendor native test binary", 505 ctx: &testModuleInstallPathContext{ 506 baseModuleContext: baseModuleContext{ 507 archModuleContext: archModuleContext{ 508 os: deviceTarget.Os, 509 target: deviceTarget, 510 }, 511 earlyModuleContext: earlyModuleContext{ 512 kind: socSpecificModule, 513 }, 514 }, 515 inData: true, 516 }, 517 in: []string{"nativetest", "my_test"}, 518 out: "target/product/test_device/data/nativetest/my_test", 519 partitionDir: "target/product/test_device/data", 520 }, 521 { 522 name: "odm native test binary", 523 ctx: &testModuleInstallPathContext{ 524 baseModuleContext: baseModuleContext{ 525 archModuleContext: archModuleContext{ 526 os: deviceTarget.Os, 527 target: deviceTarget, 528 }, 529 earlyModuleContext: earlyModuleContext{ 530 kind: deviceSpecificModule, 531 }, 532 }, 533 inData: true, 534 }, 535 in: []string{"nativetest", "my_test"}, 536 out: "target/product/test_device/data/nativetest/my_test", 537 partitionDir: "target/product/test_device/data", 538 }, 539 { 540 name: "product native test binary", 541 ctx: &testModuleInstallPathContext{ 542 baseModuleContext: baseModuleContext{ 543 archModuleContext: archModuleContext{ 544 os: deviceTarget.Os, 545 target: deviceTarget, 546 }, 547 earlyModuleContext: earlyModuleContext{ 548 kind: productSpecificModule, 549 }, 550 }, 551 inData: true, 552 }, 553 in: []string{"nativetest", "my_test"}, 554 out: "target/product/test_device/data/nativetest/my_test", 555 partitionDir: "target/product/test_device/data", 556 }, 557 558 { 559 name: "system_ext native test binary", 560 ctx: &testModuleInstallPathContext{ 561 baseModuleContext: baseModuleContext{ 562 archModuleContext: archModuleContext{ 563 os: deviceTarget.Os, 564 target: deviceTarget, 565 }, 566 earlyModuleContext: earlyModuleContext{ 567 kind: systemExtSpecificModule, 568 }, 569 }, 570 inData: true, 571 }, 572 in: []string{"nativetest", "my_test"}, 573 out: "target/product/test_device/data/nativetest/my_test", 574 partitionDir: "target/product/test_device/data", 575 }, 576 577 { 578 name: "sanitized system binary", 579 ctx: &testModuleInstallPathContext{ 580 baseModuleContext: baseModuleContext{ 581 archModuleContext: archModuleContext{ 582 os: deviceTarget.Os, 583 target: deviceTarget, 584 }, 585 }, 586 inSanitizerDir: true, 587 }, 588 in: []string{"bin", "my_test"}, 589 out: "target/product/test_device/data/asan/system/bin/my_test", 590 partitionDir: "target/product/test_device/data/asan/system", 591 }, 592 { 593 name: "sanitized vendor binary", 594 ctx: &testModuleInstallPathContext{ 595 baseModuleContext: baseModuleContext{ 596 archModuleContext: archModuleContext{ 597 os: deviceTarget.Os, 598 target: deviceTarget, 599 }, 600 earlyModuleContext: earlyModuleContext{ 601 kind: socSpecificModule, 602 }, 603 }, 604 inSanitizerDir: true, 605 }, 606 in: []string{"bin", "my_test"}, 607 out: "target/product/test_device/data/asan/vendor/bin/my_test", 608 partitionDir: "target/product/test_device/data/asan/vendor", 609 }, 610 { 611 name: "sanitized odm binary", 612 ctx: &testModuleInstallPathContext{ 613 baseModuleContext: baseModuleContext{ 614 archModuleContext: archModuleContext{ 615 os: deviceTarget.Os, 616 target: deviceTarget, 617 }, 618 earlyModuleContext: earlyModuleContext{ 619 kind: deviceSpecificModule, 620 }, 621 }, 622 inSanitizerDir: true, 623 }, 624 in: []string{"bin", "my_test"}, 625 out: "target/product/test_device/data/asan/odm/bin/my_test", 626 partitionDir: "target/product/test_device/data/asan/odm", 627 }, 628 { 629 name: "sanitized product binary", 630 ctx: &testModuleInstallPathContext{ 631 baseModuleContext: baseModuleContext{ 632 archModuleContext: archModuleContext{ 633 os: deviceTarget.Os, 634 target: deviceTarget, 635 }, 636 earlyModuleContext: earlyModuleContext{ 637 kind: productSpecificModule, 638 }, 639 }, 640 inSanitizerDir: true, 641 }, 642 in: []string{"bin", "my_test"}, 643 out: "target/product/test_device/data/asan/product/bin/my_test", 644 partitionDir: "target/product/test_device/data/asan/product", 645 }, 646 647 { 648 name: "sanitized system_ext binary", 649 ctx: &testModuleInstallPathContext{ 650 baseModuleContext: baseModuleContext{ 651 archModuleContext: archModuleContext{ 652 os: deviceTarget.Os, 653 target: deviceTarget, 654 }, 655 earlyModuleContext: earlyModuleContext{ 656 kind: systemExtSpecificModule, 657 }, 658 }, 659 inSanitizerDir: true, 660 }, 661 in: []string{"bin", "my_test"}, 662 out: "target/product/test_device/data/asan/system_ext/bin/my_test", 663 partitionDir: "target/product/test_device/data/asan/system_ext", 664 }, 665 666 { 667 name: "sanitized system native test binary", 668 ctx: &testModuleInstallPathContext{ 669 baseModuleContext: baseModuleContext{ 670 archModuleContext: archModuleContext{ 671 os: deviceTarget.Os, 672 target: deviceTarget, 673 }, 674 }, 675 inData: true, 676 inSanitizerDir: true, 677 }, 678 in: []string{"nativetest", "my_test"}, 679 out: "target/product/test_device/data/asan/data/nativetest/my_test", 680 partitionDir: "target/product/test_device/data/asan/data", 681 }, 682 { 683 name: "sanitized vendor native test binary", 684 ctx: &testModuleInstallPathContext{ 685 baseModuleContext: baseModuleContext{ 686 archModuleContext: archModuleContext{ 687 os: deviceTarget.Os, 688 target: deviceTarget, 689 }, 690 earlyModuleContext: earlyModuleContext{ 691 kind: socSpecificModule, 692 }, 693 }, 694 inData: true, 695 inSanitizerDir: true, 696 }, 697 in: []string{"nativetest", "my_test"}, 698 out: "target/product/test_device/data/asan/data/nativetest/my_test", 699 partitionDir: "target/product/test_device/data/asan/data", 700 }, 701 { 702 name: "sanitized odm native test binary", 703 ctx: &testModuleInstallPathContext{ 704 baseModuleContext: baseModuleContext{ 705 archModuleContext: archModuleContext{ 706 os: deviceTarget.Os, 707 target: deviceTarget, 708 }, 709 earlyModuleContext: earlyModuleContext{ 710 kind: deviceSpecificModule, 711 }, 712 }, 713 inData: true, 714 inSanitizerDir: true, 715 }, 716 in: []string{"nativetest", "my_test"}, 717 out: "target/product/test_device/data/asan/data/nativetest/my_test", 718 partitionDir: "target/product/test_device/data/asan/data", 719 }, 720 { 721 name: "sanitized product native test binary", 722 ctx: &testModuleInstallPathContext{ 723 baseModuleContext: baseModuleContext{ 724 archModuleContext: archModuleContext{ 725 os: deviceTarget.Os, 726 target: deviceTarget, 727 }, 728 earlyModuleContext: earlyModuleContext{ 729 kind: productSpecificModule, 730 }, 731 }, 732 inData: true, 733 inSanitizerDir: true, 734 }, 735 in: []string{"nativetest", "my_test"}, 736 out: "target/product/test_device/data/asan/data/nativetest/my_test", 737 partitionDir: "target/product/test_device/data/asan/data", 738 }, 739 { 740 name: "sanitized system_ext native test binary", 741 ctx: &testModuleInstallPathContext{ 742 baseModuleContext: baseModuleContext{ 743 archModuleContext: archModuleContext{ 744 os: deviceTarget.Os, 745 target: deviceTarget, 746 }, 747 earlyModuleContext: earlyModuleContext{ 748 kind: systemExtSpecificModule, 749 }, 750 }, 751 inData: true, 752 inSanitizerDir: true, 753 }, 754 in: []string{"nativetest", "my_test"}, 755 out: "target/product/test_device/data/asan/data/nativetest/my_test", 756 partitionDir: "target/product/test_device/data/asan/data", 757 }, { 758 name: "device testcases", 759 ctx: &testModuleInstallPathContext{ 760 baseModuleContext: baseModuleContext{ 761 archModuleContext: archModuleContext{ 762 os: deviceTarget.Os, 763 target: deviceTarget, 764 }, 765 }, 766 inTestcases: true, 767 }, 768 in: []string{"my_test", "my_test_bin"}, 769 out: "target/product/test_device/testcases/my_test/my_test_bin", 770 partitionDir: "target/product/test_device/testcases", 771 }, { 772 name: "host testcases", 773 ctx: &testModuleInstallPathContext{ 774 baseModuleContext: baseModuleContext{ 775 archModuleContext: archModuleContext{ 776 os: hostTarget.Os, 777 target: hostTarget, 778 }, 779 }, 780 inTestcases: true, 781 }, 782 in: []string{"my_test", "my_test_bin"}, 783 out: "host/linux-x86/testcases/my_test/my_test_bin", 784 partitionDir: "host/linux-x86/testcases", 785 }, { 786 name: "forced host testcases", 787 ctx: &testModuleInstallPathContext{ 788 baseModuleContext: baseModuleContext{ 789 archModuleContext: archModuleContext{ 790 os: deviceTarget.Os, 791 target: deviceTarget, 792 }, 793 }, 794 inTestcases: true, 795 forceOS: &Linux, 796 forceArch: &X86, 797 }, 798 in: []string{"my_test", "my_test_bin"}, 799 out: "host/linux-x86/testcases/my_test/my_test_bin", 800 partitionDir: "host/linux-x86/testcases", 801 }, 802 } 803 804 for _, tc := range testCases { 805 t.Run(tc.name, func(t *testing.T) { 806 tc.ctx.baseModuleContext.config = testConfig 807 output := PathForModuleInstall(tc.ctx, tc.in...) 808 if output.basePath.path != tc.out { 809 t.Errorf("unexpected path:\n got: %q\nwant: %q\n", 810 output.basePath.path, 811 tc.out) 812 } 813 if output.partitionDir != tc.partitionDir { 814 t.Errorf("unexpected partitionDir:\n got: %q\nwant: %q\n", 815 output.partitionDir, tc.partitionDir) 816 } 817 }) 818 } 819} 820 821func TestPathForModuleInstallRecoveryAsBoot(t *testing.T) { 822 testConfig := pathTestConfig("") 823 testConfig.TestProductVariables.BoardUsesRecoveryAsBoot = proptools.BoolPtr(true) 824 testConfig.TestProductVariables.BoardMoveRecoveryResourcesToVendorBoot = proptools.BoolPtr(true) 825 deviceTarget := Target{Os: Android, Arch: Arch{ArchType: Arm64}} 826 827 testCases := []struct { 828 name string 829 ctx *testModuleInstallPathContext 830 in []string 831 out string 832 partitionDir string 833 }{ 834 { 835 name: "ramdisk binary", 836 ctx: &testModuleInstallPathContext{ 837 baseModuleContext: baseModuleContext{ 838 archModuleContext: archModuleContext{ 839 os: deviceTarget.Os, 840 target: deviceTarget, 841 }, 842 }, 843 inRamdisk: true, 844 inRoot: true, 845 }, 846 in: []string{"my_test"}, 847 out: "target/product/test_device/recovery/root/first_stage_ramdisk/my_test", 848 partitionDir: "target/product/test_device/recovery/root/first_stage_ramdisk", 849 }, 850 851 { 852 name: "vendor_ramdisk binary", 853 ctx: &testModuleInstallPathContext{ 854 baseModuleContext: baseModuleContext{ 855 archModuleContext: archModuleContext{ 856 os: deviceTarget.Os, 857 target: deviceTarget, 858 }, 859 }, 860 inVendorRamdisk: true, 861 inRoot: true, 862 }, 863 in: []string{"my_test"}, 864 out: "target/product/test_device/vendor_ramdisk/first_stage_ramdisk/my_test", 865 partitionDir: "target/product/test_device/vendor_ramdisk/first_stage_ramdisk", 866 }, 867 } 868 869 for _, tc := range testCases { 870 t.Run(tc.name, func(t *testing.T) { 871 tc.ctx.baseModuleContext.config = testConfig 872 output := PathForModuleInstall(tc.ctx, tc.in...) 873 if output.basePath.path != tc.out { 874 t.Errorf("unexpected path:\n got: %q\nwant: %q\n", 875 output.basePath.path, 876 tc.out) 877 } 878 if output.partitionDir != tc.partitionDir { 879 t.Errorf("unexpected partitionDir:\n got: %q\nwant: %q\n", 880 output.partitionDir, tc.partitionDir) 881 } 882 }) 883 } 884} 885 886func TestBaseDirForInstallPath(t *testing.T) { 887 testConfig := pathTestConfig("") 888 deviceTarget := Target{Os: Android, Arch: Arch{ArchType: Arm64}} 889 890 ctx := &testModuleInstallPathContext{ 891 baseModuleContext: baseModuleContext{ 892 archModuleContext: archModuleContext{ 893 os: deviceTarget.Os, 894 target: deviceTarget, 895 }, 896 }, 897 } 898 ctx.baseModuleContext.config = testConfig 899 900 actual := PathForModuleInstall(ctx, "foo", "bar") 901 expectedBaseDir := "target/product/test_device/system" 902 if actual.partitionDir != expectedBaseDir { 903 t.Errorf("unexpected partitionDir:\n got: %q\nwant: %q\n", actual.partitionDir, expectedBaseDir) 904 } 905 expectedRelPath := "foo/bar" 906 if actual.Rel() != expectedRelPath { 907 t.Errorf("unexpected Rel():\n got: %q\nwant: %q\n", actual.Rel(), expectedRelPath) 908 } 909 910 actualAfterJoin := actual.Join(ctx, "baz") 911 // partitionDir is preserved even after joining 912 if actualAfterJoin.partitionDir != expectedBaseDir { 913 t.Errorf("unexpected partitionDir after joining:\n got: %q\nwant: %q\n", actualAfterJoin.partitionDir, expectedBaseDir) 914 } 915 // Rel() is updated though 916 expectedRelAfterJoin := "baz" 917 if actualAfterJoin.Rel() != expectedRelAfterJoin { 918 t.Errorf("unexpected Rel() after joining:\n got: %q\nwant: %q\n", actualAfterJoin.Rel(), expectedRelAfterJoin) 919 } 920} 921 922func TestDirectorySortedPaths(t *testing.T) { 923 config := TestConfig("out", nil, "", map[string][]byte{ 924 "Android.bp": nil, 925 "a.txt": nil, 926 "a/txt": nil, 927 "a/b/c": nil, 928 "a/b/d": nil, 929 "b": nil, 930 "b/b.txt": nil, 931 "a/a.txt": nil, 932 }) 933 934 ctx := PathContextForTesting(config) 935 936 makePaths := func() Paths { 937 return Paths{ 938 PathForSource(ctx, "a.txt"), 939 PathForSource(ctx, "a/txt"), 940 PathForSource(ctx, "a/b/c"), 941 PathForSource(ctx, "a/b/d"), 942 PathForSource(ctx, "b"), 943 PathForSource(ctx, "b/b.txt"), 944 PathForSource(ctx, "a/a.txt"), 945 } 946 } 947 948 expected := []string{ 949 "a.txt", 950 "a/a.txt", 951 "a/b/c", 952 "a/b/d", 953 "a/txt", 954 "b", 955 "b/b.txt", 956 } 957 958 paths := makePaths() 959 reversePaths := ReversePaths(paths) 960 961 sortedPaths := PathsToDirectorySortedPaths(paths) 962 reverseSortedPaths := PathsToDirectorySortedPaths(reversePaths) 963 964 if !reflect.DeepEqual(Paths(sortedPaths).Strings(), expected) { 965 t.Fatalf("sorted paths:\n %#v\n != \n %#v", paths.Strings(), expected) 966 } 967 968 if !reflect.DeepEqual(Paths(reverseSortedPaths).Strings(), expected) { 969 t.Fatalf("sorted reversed paths:\n %#v\n !=\n %#v", reversePaths.Strings(), expected) 970 } 971 972 expectedA := []string{ 973 "a/a.txt", 974 "a/b/c", 975 "a/b/d", 976 "a/txt", 977 } 978 979 inA := sortedPaths.PathsInDirectory("a") 980 if !reflect.DeepEqual(inA.Strings(), expectedA) { 981 t.Errorf("FilesInDirectory(a):\n %#v\n != \n %#v", inA.Strings(), expectedA) 982 } 983 984 expectedA_B := []string{ 985 "a/b/c", 986 "a/b/d", 987 } 988 989 inA_B := sortedPaths.PathsInDirectory("a/b") 990 if !reflect.DeepEqual(inA_B.Strings(), expectedA_B) { 991 t.Errorf("FilesInDirectory(a/b):\n %#v\n != \n %#v", inA_B.Strings(), expectedA_B) 992 } 993 994 expectedB := []string{ 995 "b/b.txt", 996 } 997 998 inB := sortedPaths.PathsInDirectory("b") 999 if !reflect.DeepEqual(inB.Strings(), expectedB) { 1000 t.Errorf("FilesInDirectory(b):\n %#v\n != \n %#v", inA.Strings(), expectedA) 1001 } 1002} 1003 1004func TestMaybeRel(t *testing.T) { 1005 testCases := []struct { 1006 name string 1007 base string 1008 target string 1009 out string 1010 isRel bool 1011 }{ 1012 { 1013 name: "normal", 1014 base: "a/b/c", 1015 target: "a/b/c/d", 1016 out: "d", 1017 isRel: true, 1018 }, 1019 { 1020 name: "parent", 1021 base: "a/b/c/d", 1022 target: "a/b/c", 1023 isRel: false, 1024 }, 1025 { 1026 name: "not relative", 1027 base: "a/b", 1028 target: "c/d", 1029 isRel: false, 1030 }, 1031 { 1032 name: "abs1", 1033 base: "/a", 1034 target: "a", 1035 isRel: false, 1036 }, 1037 { 1038 name: "abs2", 1039 base: "a", 1040 target: "/a", 1041 isRel: false, 1042 }, 1043 } 1044 1045 for _, testCase := range testCases { 1046 t.Run(testCase.name, func(t *testing.T) { 1047 ctx := &configErrorWrapper{} 1048 out, isRel := MaybeRel(ctx, testCase.base, testCase.target) 1049 if len(ctx.errors) > 0 { 1050 t.Errorf("MaybeRel(..., %s, %s) reported unexpected errors %v", 1051 testCase.base, testCase.target, ctx.errors) 1052 } 1053 if isRel != testCase.isRel || out != testCase.out { 1054 t.Errorf("MaybeRel(..., %s, %s) want %v, %v got %v, %v", 1055 testCase.base, testCase.target, testCase.out, testCase.isRel, out, isRel) 1056 } 1057 }) 1058 } 1059} 1060 1061func TestPathForSource(t *testing.T) { 1062 testCases := []struct { 1063 name string 1064 buildDir string 1065 src string 1066 err string 1067 }{ 1068 { 1069 name: "normal", 1070 buildDir: "out", 1071 src: "a/b/c", 1072 }, 1073 { 1074 name: "abs", 1075 buildDir: "out", 1076 src: "/a/b/c", 1077 err: "is outside directory", 1078 }, 1079 { 1080 name: "in out dir", 1081 buildDir: "out", 1082 src: "out/soong/a/b/c", 1083 err: "is in output", 1084 }, 1085 } 1086 1087 funcs := []struct { 1088 name string 1089 f func(ctx PathContext, pathComponents ...string) (SourcePath, error) 1090 }{ 1091 {"pathForSource", pathForSource}, 1092 {"safePathForSource", safePathForSource}, 1093 } 1094 1095 for _, f := range funcs { 1096 t.Run(f.name, func(t *testing.T) { 1097 for _, test := range testCases { 1098 t.Run(test.name, func(t *testing.T) { 1099 testConfig := pathTestConfig(test.buildDir) 1100 ctx := &configErrorWrapper{config: testConfig} 1101 _, err := f.f(ctx, test.src) 1102 if len(ctx.errors) > 0 { 1103 t.Fatalf("unexpected errors %v", ctx.errors) 1104 } 1105 if err != nil { 1106 if test.err == "" { 1107 t.Fatalf("unexpected error %q", err.Error()) 1108 } else if !strings.Contains(err.Error(), test.err) { 1109 t.Fatalf("incorrect error, want substring %q got %q", test.err, err.Error()) 1110 } 1111 } else { 1112 if test.err != "" { 1113 t.Fatalf("missing error %q", test.err) 1114 } 1115 } 1116 }) 1117 } 1118 }) 1119 } 1120} 1121 1122type pathForModuleSrcTestModule struct { 1123 ModuleBase 1124 props struct { 1125 Srcs []string `android:"path"` 1126 Exclude_srcs []string `android:"path"` 1127 1128 Src *string `android:"path"` 1129 1130 Module_handles_missing_deps bool 1131 } 1132 1133 src string 1134 rel string 1135 1136 srcs []string 1137 rels []string 1138 1139 missingDeps []string 1140} 1141 1142func pathForModuleSrcTestModuleFactory() Module { 1143 module := &pathForModuleSrcTestModule{} 1144 module.AddProperties(&module.props) 1145 InitAndroidModule(module) 1146 return module 1147} 1148 1149func (p *pathForModuleSrcTestModule) GenerateAndroidBuildActions(ctx ModuleContext) { 1150 var srcs Paths 1151 if p.props.Module_handles_missing_deps { 1152 srcs, p.missingDeps = PathsAndMissingDepsForModuleSrcExcludes(ctx, p.props.Srcs, p.props.Exclude_srcs) 1153 } else { 1154 srcs = PathsForModuleSrcExcludes(ctx, p.props.Srcs, p.props.Exclude_srcs) 1155 } 1156 p.srcs = srcs.Strings() 1157 1158 for _, src := range srcs { 1159 p.rels = append(p.rels, src.Rel()) 1160 } 1161 1162 if p.props.Src != nil { 1163 src := PathForModuleSrc(ctx, *p.props.Src) 1164 if src != nil { 1165 p.src = src.String() 1166 p.rel = src.Rel() 1167 } 1168 } 1169 1170 if !p.props.Module_handles_missing_deps { 1171 p.missingDeps = ctx.GetMissingDependencies() 1172 } 1173 1174 ctx.Build(pctx, BuildParams{ 1175 Rule: Touch, 1176 Output: PathForModuleOut(ctx, "output"), 1177 }) 1178} 1179 1180type pathForModuleSrcOutputFileProviderModule struct { 1181 ModuleBase 1182 props struct { 1183 Outs []string 1184 Tagged []string 1185 } 1186} 1187 1188func pathForModuleSrcOutputFileProviderModuleFactory() Module { 1189 module := &pathForModuleSrcOutputFileProviderModule{} 1190 module.AddProperties(&module.props) 1191 InitAndroidModule(module) 1192 return module 1193} 1194 1195func (p *pathForModuleSrcOutputFileProviderModule) GenerateAndroidBuildActions(ctx ModuleContext) { 1196 var outs, taggedOuts Paths 1197 for _, out := range p.props.Outs { 1198 outs = append(outs, PathForModuleOut(ctx, out)) 1199 } 1200 1201 for _, tagged := range p.props.Tagged { 1202 taggedOuts = append(taggedOuts, PathForModuleOut(ctx, tagged)) 1203 } 1204 1205 ctx.SetOutputFiles(outs, "") 1206 ctx.SetOutputFiles(taggedOuts, ".tagged") 1207} 1208 1209type pathForModuleSrcTestCase struct { 1210 name string 1211 bp string 1212 srcs []string 1213 rels []string 1214 src string 1215 rel string 1216 1217 // Make test specific preparations to the test fixture. 1218 preparer FixturePreparer 1219 1220 // A test specific error handler. 1221 errorHandler FixtureErrorHandler 1222} 1223 1224func testPathForModuleSrc(t *testing.T, tests []pathForModuleSrcTestCase) { 1225 for _, test := range tests { 1226 t.Run(test.name, func(t *testing.T) { 1227 fgBp := ` 1228 filegroup { 1229 name: "a", 1230 srcs: ["src/a"], 1231 } 1232 ` 1233 1234 ofpBp := ` 1235 output_file_provider { 1236 name: "b", 1237 outs: ["gen/b"], 1238 tagged: ["gen/c"], 1239 } 1240 ` 1241 1242 mockFS := MockFS{ 1243 "fg/Android.bp": []byte(fgBp), 1244 "foo/Android.bp": []byte(test.bp), 1245 "ofp/Android.bp": []byte(ofpBp), 1246 "fg/src/a": nil, 1247 "foo/src/b": nil, 1248 "foo/src/c": nil, 1249 "foo/src/d": nil, 1250 "foo/src/e/e": nil, 1251 "foo/src_special/$": nil, 1252 } 1253 1254 errorHandler := test.errorHandler 1255 if errorHandler == nil { 1256 errorHandler = FixtureExpectsNoErrors 1257 } 1258 1259 result := GroupFixturePreparers( 1260 FixtureRegisterWithContext(func(ctx RegistrationContext) { 1261 ctx.RegisterModuleType("test", pathForModuleSrcTestModuleFactory) 1262 ctx.RegisterModuleType("output_file_provider", pathForModuleSrcOutputFileProviderModuleFactory) 1263 }), 1264 PrepareForTestWithFilegroup, 1265 PrepareForTestWithNamespace, 1266 mockFS.AddToFixture(), 1267 OptionalFixturePreparer(test.preparer), 1268 ). 1269 ExtendWithErrorHandler(errorHandler). 1270 RunTest(t) 1271 1272 m := result.ModuleForTests("foo", "").Module().(*pathForModuleSrcTestModule) 1273 1274 AssertStringPathsRelativeToTopEquals(t, "srcs", result.Config, test.srcs, m.srcs) 1275 AssertStringPathsRelativeToTopEquals(t, "rels", result.Config, test.rels, m.rels) 1276 AssertStringPathRelativeToTopEquals(t, "src", result.Config, test.src, m.src) 1277 AssertStringPathRelativeToTopEquals(t, "rel", result.Config, test.rel, m.rel) 1278 }) 1279 } 1280} 1281 1282func TestPathsForModuleSrc(t *testing.T) { 1283 tests := []pathForModuleSrcTestCase{ 1284 { 1285 name: "path", 1286 bp: ` 1287 test { 1288 name: "foo", 1289 srcs: ["src/b"], 1290 }`, 1291 srcs: []string{"foo/src/b"}, 1292 rels: []string{"src/b"}, 1293 }, 1294 { 1295 name: "glob", 1296 bp: ` 1297 test { 1298 name: "foo", 1299 srcs: [ 1300 "src/*", 1301 "src/e/*", 1302 ], 1303 }`, 1304 srcs: []string{"foo/src/b", "foo/src/c", "foo/src/d", "foo/src/e/e"}, 1305 rels: []string{"src/b", "src/c", "src/d", "src/e/e"}, 1306 }, 1307 { 1308 name: "recursive glob", 1309 bp: ` 1310 test { 1311 name: "foo", 1312 srcs: ["src/**/*"], 1313 }`, 1314 srcs: []string{"foo/src/b", "foo/src/c", "foo/src/d", "foo/src/e/e"}, 1315 rels: []string{"src/b", "src/c", "src/d", "src/e/e"}, 1316 }, 1317 { 1318 name: "filegroup", 1319 bp: ` 1320 test { 1321 name: "foo", 1322 srcs: [":a"], 1323 }`, 1324 srcs: []string{"fg/src/a"}, 1325 rels: []string{"src/a"}, 1326 }, 1327 { 1328 name: "output file provider", 1329 bp: ` 1330 test { 1331 name: "foo", 1332 srcs: [":b"], 1333 }`, 1334 srcs: []string{"out/soong/.intermediates/ofp/b/gen/b"}, 1335 rels: []string{"gen/b"}, 1336 }, 1337 { 1338 name: "output file provider tagged", 1339 bp: ` 1340 test { 1341 name: "foo", 1342 srcs: [":b{.tagged}"], 1343 }`, 1344 srcs: []string{"out/soong/.intermediates/ofp/b/gen/c"}, 1345 rels: []string{"gen/c"}, 1346 }, 1347 { 1348 name: "output file provider with exclude", 1349 bp: ` 1350 test { 1351 name: "foo", 1352 srcs: [":b", ":c"], 1353 exclude_srcs: [":c"] 1354 } 1355 output_file_provider { 1356 name: "c", 1357 outs: ["gen/c"], 1358 }`, 1359 srcs: []string{"out/soong/.intermediates/ofp/b/gen/b"}, 1360 rels: []string{"gen/b"}, 1361 }, 1362 { 1363 name: "special characters glob", 1364 bp: ` 1365 test { 1366 name: "foo", 1367 srcs: ["src_special/*"], 1368 }`, 1369 srcs: []string{"foo/src_special/$"}, 1370 rels: []string{"src_special/$"}, 1371 }, 1372 } 1373 1374 testPathForModuleSrc(t, tests) 1375} 1376 1377func TestPathForModuleSrc(t *testing.T) { 1378 tests := []pathForModuleSrcTestCase{ 1379 { 1380 name: "path", 1381 bp: ` 1382 test { 1383 name: "foo", 1384 src: "src/b", 1385 }`, 1386 src: "foo/src/b", 1387 rel: "src/b", 1388 }, 1389 { 1390 name: "glob", 1391 bp: ` 1392 test { 1393 name: "foo", 1394 src: "src/e/*", 1395 }`, 1396 src: "foo/src/e/e", 1397 rel: "src/e/e", 1398 }, 1399 { 1400 name: "filegroup", 1401 bp: ` 1402 test { 1403 name: "foo", 1404 src: ":a", 1405 }`, 1406 src: "fg/src/a", 1407 rel: "src/a", 1408 }, 1409 { 1410 name: "output file provider", 1411 bp: ` 1412 test { 1413 name: "foo", 1414 src: ":b", 1415 }`, 1416 src: "out/soong/.intermediates/ofp/b/gen/b", 1417 rel: "gen/b", 1418 }, 1419 { 1420 name: "output file provider tagged", 1421 bp: ` 1422 test { 1423 name: "foo", 1424 src: ":b{.tagged}", 1425 }`, 1426 src: "out/soong/.intermediates/ofp/b/gen/c", 1427 rel: "gen/c", 1428 }, 1429 { 1430 name: "special characters glob", 1431 bp: ` 1432 test { 1433 name: "foo", 1434 src: "src_special/*", 1435 }`, 1436 src: "foo/src_special/$", 1437 rel: "src_special/$", 1438 }, 1439 { 1440 // This test makes sure that an unqualified module name cannot contain characters that make 1441 // it appear as a qualified module name. 1442 name: "output file provider, invalid fully qualified name", 1443 bp: ` 1444 test { 1445 name: "foo", 1446 src: "://other:b", 1447 srcs: ["://other:c"], 1448 }`, 1449 preparer: FixtureAddTextFile("other/Android.bp", ` 1450 soong_namespace {} 1451 1452 output_file_provider { 1453 name: "b", 1454 outs: ["gen/b"], 1455 } 1456 1457 output_file_provider { 1458 name: "c", 1459 outs: ["gen/c"], 1460 } 1461 `), 1462 src: "foo/:/other:b", 1463 rel: ":/other:b", 1464 srcs: []string{"foo/:/other:c"}, 1465 rels: []string{":/other:c"}, 1466 }, 1467 { 1468 name: "output file provider, missing fully qualified name", 1469 bp: ` 1470 test { 1471 name: "foo", 1472 src: "//other:b", 1473 srcs: ["//other:c"], 1474 }`, 1475 errorHandler: FixtureExpectsAllErrorsToMatchAPattern([]string{ 1476 `"foo" depends on undefined module "//other:b"`, 1477 `"foo" depends on undefined module "//other:c"`, 1478 }), 1479 }, 1480 { 1481 name: "output file provider, fully qualified name", 1482 bp: ` 1483 test { 1484 name: "foo", 1485 src: "//other:b", 1486 srcs: ["//other:c"], 1487 }`, 1488 src: "out/soong/.intermediates/other/b/gen/b", 1489 rel: "gen/b", 1490 srcs: []string{"out/soong/.intermediates/other/c/gen/c"}, 1491 rels: []string{"gen/c"}, 1492 preparer: FixtureAddTextFile("other/Android.bp", ` 1493 soong_namespace {} 1494 1495 output_file_provider { 1496 name: "b", 1497 outs: ["gen/b"], 1498 } 1499 1500 output_file_provider { 1501 name: "c", 1502 outs: ["gen/c"], 1503 } 1504 `), 1505 }, 1506 } 1507 1508 testPathForModuleSrc(t, tests) 1509} 1510 1511func TestPathsForModuleSrc_AllowMissingDependencies(t *testing.T) { 1512 bp := ` 1513 test { 1514 name: "foo", 1515 srcs: [":a"], 1516 exclude_srcs: [":b"], 1517 src: ":c", 1518 } 1519 1520 test { 1521 name: "bar", 1522 srcs: [":d"], 1523 exclude_srcs: [":e"], 1524 module_handles_missing_deps: true, 1525 } 1526 ` 1527 1528 result := GroupFixturePreparers( 1529 PrepareForTestWithAllowMissingDependencies, 1530 FixtureRegisterWithContext(func(ctx RegistrationContext) { 1531 ctx.RegisterModuleType("test", pathForModuleSrcTestModuleFactory) 1532 }), 1533 FixtureWithRootAndroidBp(bp), 1534 ).RunTest(t) 1535 1536 foo := result.ModuleForTests("foo", "").Module().(*pathForModuleSrcTestModule) 1537 1538 AssertArrayString(t, "foo missing deps", []string{"a", "b", "c"}, foo.missingDeps) 1539 AssertArrayString(t, "foo srcs", []string{}, foo.srcs) 1540 AssertStringEquals(t, "foo src", "", foo.src) 1541 1542 bar := result.ModuleForTests("bar", "").Module().(*pathForModuleSrcTestModule) 1543 1544 AssertArrayString(t, "bar missing deps", []string{"d", "e"}, bar.missingDeps) 1545 AssertArrayString(t, "bar srcs", []string{}, bar.srcs) 1546} 1547 1548func TestPathRelativeToTop(t *testing.T) { 1549 testConfig := pathTestConfig("/tmp/build/top") 1550 deviceTarget := Target{Os: Android, Arch: Arch{ArchType: Arm64}} 1551 1552 ctx := &testModuleInstallPathContext{ 1553 baseModuleContext: baseModuleContext{ 1554 archModuleContext: archModuleContext{ 1555 os: deviceTarget.Os, 1556 target: deviceTarget, 1557 }, 1558 }, 1559 } 1560 ctx.baseModuleContext.config = testConfig 1561 1562 t.Run("install for soong", func(t *testing.T) { 1563 p := PathForModuleInstall(ctx, "install/path") 1564 AssertPathRelativeToTopEquals(t, "install path for soong", "out/soong/target/product/test_device/system/install/path", p) 1565 }) 1566 t.Run("install for make", func(t *testing.T) { 1567 p := PathForModuleInstall(ctx, "install/path") 1568 p.makePath = true 1569 AssertPathRelativeToTopEquals(t, "install path for make", "out/target/product/test_device/system/install/path", p) 1570 }) 1571 t.Run("output", func(t *testing.T) { 1572 p := PathForOutput(ctx, "output/path") 1573 AssertPathRelativeToTopEquals(t, "output path", "out/soong/output/path", p) 1574 }) 1575 t.Run("source", func(t *testing.T) { 1576 p := PathForSource(ctx, "source/path") 1577 AssertPathRelativeToTopEquals(t, "source path", "source/path", p) 1578 }) 1579 t.Run("mixture", func(t *testing.T) { 1580 paths := Paths{ 1581 PathForModuleInstall(ctx, "install/path"), 1582 PathForOutput(ctx, "output/path"), 1583 PathForSource(ctx, "source/path"), 1584 } 1585 1586 expected := []string{ 1587 "out/soong/target/product/test_device/system/install/path", 1588 "out/soong/output/path", 1589 "source/path", 1590 } 1591 AssertPathsRelativeToTopEquals(t, "mixture", expected, paths) 1592 }) 1593} 1594 1595func TestDirectoryPathIsIncompatibleWithPath(t *testing.T) { 1596 d := (DirectoryPath)(&directoryPath{}) 1597 _, ok := d.(Path) 1598 AssertBoolEquals(t, "directoryPath shouldn't implement Path", ok, false) 1599} 1600 1601func ExampleOutputPath_ReplaceExtension() { 1602 ctx := &configErrorWrapper{ 1603 config: TestConfig("out", nil, "", nil), 1604 } 1605 p := PathForOutput(ctx, "system/framework").Join(ctx, "boot.art") 1606 p2 := p.ReplaceExtension(ctx, "oat") 1607 fmt.Println(p, p2) 1608 fmt.Println(p.Rel(), p2.Rel()) 1609 1610 // Output: 1611 // out/soong/system/framework/boot.art out/soong/system/framework/boot.oat 1612 // boot.art boot.oat 1613} 1614 1615func ExampleOutputPath_InSameDir() { 1616 ctx := &configErrorWrapper{ 1617 config: TestConfig("out", nil, "", nil), 1618 } 1619 p := PathForOutput(ctx, "system/framework").Join(ctx, "boot.art") 1620 p2 := p.InSameDir(ctx, "oat", "arm", "boot.vdex") 1621 fmt.Println(p, p2) 1622 fmt.Println(p.Rel(), p2.Rel()) 1623 1624 // Output: 1625 // out/soong/system/framework/boot.art out/soong/system/framework/oat/arm/boot.vdex 1626 // boot.art oat/arm/boot.vdex 1627} 1628 1629func BenchmarkFirstUniquePaths(b *testing.B) { 1630 implementations := []struct { 1631 name string 1632 f func(Paths) Paths 1633 }{ 1634 { 1635 name: "list", 1636 f: firstUniquePathsList, 1637 }, 1638 { 1639 name: "map", 1640 f: firstUniquePathsMap, 1641 }, 1642 } 1643 const maxSize = 1024 1644 uniquePaths := make(Paths, maxSize) 1645 for i := range uniquePaths { 1646 uniquePaths[i] = PathForTesting(strconv.Itoa(i)) 1647 } 1648 samePath := make(Paths, maxSize) 1649 for i := range samePath { 1650 samePath[i] = uniquePaths[0] 1651 } 1652 1653 f := func(b *testing.B, imp func(Paths) Paths, paths Paths) { 1654 for i := 0; i < b.N; i++ { 1655 b.ReportAllocs() 1656 paths = append(Paths(nil), paths...) 1657 imp(paths) 1658 } 1659 } 1660 1661 for n := 1; n <= maxSize; n <<= 1 { 1662 b.Run(strconv.Itoa(n), func(b *testing.B) { 1663 for _, implementation := range implementations { 1664 b.Run(implementation.name, func(b *testing.B) { 1665 b.Run("same", func(b *testing.B) { 1666 f(b, implementation.f, samePath[:n]) 1667 }) 1668 b.Run("unique", func(b *testing.B) { 1669 f(b, implementation.f, uniquePaths[:n]) 1670 }) 1671 }) 1672 } 1673 }) 1674 } 1675} 1676