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 outs Paths 1188 tagged Paths 1189} 1190 1191func pathForModuleSrcOutputFileProviderModuleFactory() Module { 1192 module := &pathForModuleSrcOutputFileProviderModule{} 1193 module.AddProperties(&module.props) 1194 InitAndroidModule(module) 1195 return module 1196} 1197 1198func (p *pathForModuleSrcOutputFileProviderModule) GenerateAndroidBuildActions(ctx ModuleContext) { 1199 for _, out := range p.props.Outs { 1200 p.outs = append(p.outs, PathForModuleOut(ctx, out)) 1201 } 1202 1203 for _, tagged := range p.props.Tagged { 1204 p.tagged = append(p.tagged, PathForModuleOut(ctx, tagged)) 1205 } 1206} 1207 1208func (p *pathForModuleSrcOutputFileProviderModule) OutputFiles(tag string) (Paths, error) { 1209 switch tag { 1210 case "": 1211 return p.outs, nil 1212 case ".tagged": 1213 return p.tagged, nil 1214 default: 1215 return nil, fmt.Errorf("unsupported tag %q", tag) 1216 } 1217} 1218 1219type pathForModuleSrcTestCase struct { 1220 name string 1221 bp string 1222 srcs []string 1223 rels []string 1224 src string 1225 rel string 1226 1227 // Make test specific preparations to the test fixture. 1228 preparer FixturePreparer 1229 1230 // A test specific error handler. 1231 errorHandler FixtureErrorHandler 1232} 1233 1234func testPathForModuleSrc(t *testing.T, tests []pathForModuleSrcTestCase) { 1235 for _, test := range tests { 1236 t.Run(test.name, func(t *testing.T) { 1237 fgBp := ` 1238 filegroup { 1239 name: "a", 1240 srcs: ["src/a"], 1241 } 1242 ` 1243 1244 ofpBp := ` 1245 output_file_provider { 1246 name: "b", 1247 outs: ["gen/b"], 1248 tagged: ["gen/c"], 1249 } 1250 ` 1251 1252 mockFS := MockFS{ 1253 "fg/Android.bp": []byte(fgBp), 1254 "foo/Android.bp": []byte(test.bp), 1255 "ofp/Android.bp": []byte(ofpBp), 1256 "fg/src/a": nil, 1257 "foo/src/b": nil, 1258 "foo/src/c": nil, 1259 "foo/src/d": nil, 1260 "foo/src/e/e": nil, 1261 "foo/src_special/$": nil, 1262 } 1263 1264 errorHandler := test.errorHandler 1265 if errorHandler == nil { 1266 errorHandler = FixtureExpectsNoErrors 1267 } 1268 1269 result := GroupFixturePreparers( 1270 FixtureRegisterWithContext(func(ctx RegistrationContext) { 1271 ctx.RegisterModuleType("test", pathForModuleSrcTestModuleFactory) 1272 ctx.RegisterModuleType("output_file_provider", pathForModuleSrcOutputFileProviderModuleFactory) 1273 }), 1274 PrepareForTestWithFilegroup, 1275 PrepareForTestWithNamespace, 1276 mockFS.AddToFixture(), 1277 OptionalFixturePreparer(test.preparer), 1278 ). 1279 ExtendWithErrorHandler(errorHandler). 1280 RunTest(t) 1281 1282 m := result.ModuleForTests("foo", "").Module().(*pathForModuleSrcTestModule) 1283 1284 AssertStringPathsRelativeToTopEquals(t, "srcs", result.Config, test.srcs, m.srcs) 1285 AssertStringPathsRelativeToTopEquals(t, "rels", result.Config, test.rels, m.rels) 1286 AssertStringPathRelativeToTopEquals(t, "src", result.Config, test.src, m.src) 1287 AssertStringPathRelativeToTopEquals(t, "rel", result.Config, test.rel, m.rel) 1288 }) 1289 } 1290} 1291 1292func TestPathsForModuleSrc(t *testing.T) { 1293 tests := []pathForModuleSrcTestCase{ 1294 { 1295 name: "path", 1296 bp: ` 1297 test { 1298 name: "foo", 1299 srcs: ["src/b"], 1300 }`, 1301 srcs: []string{"foo/src/b"}, 1302 rels: []string{"src/b"}, 1303 }, 1304 { 1305 name: "glob", 1306 bp: ` 1307 test { 1308 name: "foo", 1309 srcs: [ 1310 "src/*", 1311 "src/e/*", 1312 ], 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: "recursive glob", 1319 bp: ` 1320 test { 1321 name: "foo", 1322 srcs: ["src/**/*"], 1323 }`, 1324 srcs: []string{"foo/src/b", "foo/src/c", "foo/src/d", "foo/src/e/e"}, 1325 rels: []string{"src/b", "src/c", "src/d", "src/e/e"}, 1326 }, 1327 { 1328 name: "filegroup", 1329 bp: ` 1330 test { 1331 name: "foo", 1332 srcs: [":a"], 1333 }`, 1334 srcs: []string{"fg/src/a"}, 1335 rels: []string{"src/a"}, 1336 }, 1337 { 1338 name: "output file provider", 1339 bp: ` 1340 test { 1341 name: "foo", 1342 srcs: [":b"], 1343 }`, 1344 srcs: []string{"out/soong/.intermediates/ofp/b/gen/b"}, 1345 rels: []string{"gen/b"}, 1346 }, 1347 { 1348 name: "output file provider tagged", 1349 bp: ` 1350 test { 1351 name: "foo", 1352 srcs: [":b{.tagged}"], 1353 }`, 1354 srcs: []string{"out/soong/.intermediates/ofp/b/gen/c"}, 1355 rels: []string{"gen/c"}, 1356 }, 1357 { 1358 name: "output file provider with exclude", 1359 bp: ` 1360 test { 1361 name: "foo", 1362 srcs: [":b", ":c"], 1363 exclude_srcs: [":c"] 1364 } 1365 output_file_provider { 1366 name: "c", 1367 outs: ["gen/c"], 1368 }`, 1369 srcs: []string{"out/soong/.intermediates/ofp/b/gen/b"}, 1370 rels: []string{"gen/b"}, 1371 }, 1372 { 1373 name: "special characters glob", 1374 bp: ` 1375 test { 1376 name: "foo", 1377 srcs: ["src_special/*"], 1378 }`, 1379 srcs: []string{"foo/src_special/$"}, 1380 rels: []string{"src_special/$"}, 1381 }, 1382 } 1383 1384 testPathForModuleSrc(t, tests) 1385} 1386 1387func TestPathForModuleSrc(t *testing.T) { 1388 tests := []pathForModuleSrcTestCase{ 1389 { 1390 name: "path", 1391 bp: ` 1392 test { 1393 name: "foo", 1394 src: "src/b", 1395 }`, 1396 src: "foo/src/b", 1397 rel: "src/b", 1398 }, 1399 { 1400 name: "glob", 1401 bp: ` 1402 test { 1403 name: "foo", 1404 src: "src/e/*", 1405 }`, 1406 src: "foo/src/e/e", 1407 rel: "src/e/e", 1408 }, 1409 { 1410 name: "filegroup", 1411 bp: ` 1412 test { 1413 name: "foo", 1414 src: ":a", 1415 }`, 1416 src: "fg/src/a", 1417 rel: "src/a", 1418 }, 1419 { 1420 name: "output file provider", 1421 bp: ` 1422 test { 1423 name: "foo", 1424 src: ":b", 1425 }`, 1426 src: "out/soong/.intermediates/ofp/b/gen/b", 1427 rel: "gen/b", 1428 }, 1429 { 1430 name: "output file provider tagged", 1431 bp: ` 1432 test { 1433 name: "foo", 1434 src: ":b{.tagged}", 1435 }`, 1436 src: "out/soong/.intermediates/ofp/b/gen/c", 1437 rel: "gen/c", 1438 }, 1439 { 1440 name: "special characters glob", 1441 bp: ` 1442 test { 1443 name: "foo", 1444 src: "src_special/*", 1445 }`, 1446 src: "foo/src_special/$", 1447 rel: "src_special/$", 1448 }, 1449 { 1450 // This test makes sure that an unqualified module name cannot contain characters that make 1451 // it appear as a qualified module name. 1452 name: "output file provider, invalid fully qualified name", 1453 bp: ` 1454 test { 1455 name: "foo", 1456 src: "://other:b", 1457 srcs: ["://other:c"], 1458 }`, 1459 preparer: FixtureAddTextFile("other/Android.bp", ` 1460 soong_namespace {} 1461 1462 output_file_provider { 1463 name: "b", 1464 outs: ["gen/b"], 1465 } 1466 1467 output_file_provider { 1468 name: "c", 1469 outs: ["gen/c"], 1470 } 1471 `), 1472 src: "foo/:/other:b", 1473 rel: ":/other:b", 1474 srcs: []string{"foo/:/other:c"}, 1475 rels: []string{":/other:c"}, 1476 }, 1477 { 1478 name: "output file provider, missing fully qualified name", 1479 bp: ` 1480 test { 1481 name: "foo", 1482 src: "//other:b", 1483 srcs: ["//other:c"], 1484 }`, 1485 errorHandler: FixtureExpectsAllErrorsToMatchAPattern([]string{ 1486 `"foo" depends on undefined module "//other:b"`, 1487 `"foo" depends on undefined module "//other:c"`, 1488 }), 1489 }, 1490 { 1491 name: "output file provider, fully qualified name", 1492 bp: ` 1493 test { 1494 name: "foo", 1495 src: "//other:b", 1496 srcs: ["//other:c"], 1497 }`, 1498 src: "out/soong/.intermediates/other/b/gen/b", 1499 rel: "gen/b", 1500 srcs: []string{"out/soong/.intermediates/other/c/gen/c"}, 1501 rels: []string{"gen/c"}, 1502 preparer: FixtureAddTextFile("other/Android.bp", ` 1503 soong_namespace {} 1504 1505 output_file_provider { 1506 name: "b", 1507 outs: ["gen/b"], 1508 } 1509 1510 output_file_provider { 1511 name: "c", 1512 outs: ["gen/c"], 1513 } 1514 `), 1515 }, 1516 } 1517 1518 testPathForModuleSrc(t, tests) 1519} 1520 1521func TestPathsForModuleSrc_AllowMissingDependencies(t *testing.T) { 1522 bp := ` 1523 test { 1524 name: "foo", 1525 srcs: [":a"], 1526 exclude_srcs: [":b"], 1527 src: ":c", 1528 } 1529 1530 test { 1531 name: "bar", 1532 srcs: [":d"], 1533 exclude_srcs: [":e"], 1534 module_handles_missing_deps: true, 1535 } 1536 ` 1537 1538 result := GroupFixturePreparers( 1539 PrepareForTestWithAllowMissingDependencies, 1540 FixtureRegisterWithContext(func(ctx RegistrationContext) { 1541 ctx.RegisterModuleType("test", pathForModuleSrcTestModuleFactory) 1542 }), 1543 FixtureWithRootAndroidBp(bp), 1544 ).RunTest(t) 1545 1546 foo := result.ModuleForTests("foo", "").Module().(*pathForModuleSrcTestModule) 1547 1548 AssertArrayString(t, "foo missing deps", []string{"a", "b", "c"}, foo.missingDeps) 1549 AssertArrayString(t, "foo srcs", []string{}, foo.srcs) 1550 AssertStringEquals(t, "foo src", "", foo.src) 1551 1552 bar := result.ModuleForTests("bar", "").Module().(*pathForModuleSrcTestModule) 1553 1554 AssertArrayString(t, "bar missing deps", []string{"d", "e"}, bar.missingDeps) 1555 AssertArrayString(t, "bar srcs", []string{}, bar.srcs) 1556} 1557 1558func TestPathRelativeToTop(t *testing.T) { 1559 testConfig := pathTestConfig("/tmp/build/top") 1560 deviceTarget := Target{Os: Android, Arch: Arch{ArchType: Arm64}} 1561 1562 ctx := &testModuleInstallPathContext{ 1563 baseModuleContext: baseModuleContext{ 1564 archModuleContext: archModuleContext{ 1565 os: deviceTarget.Os, 1566 target: deviceTarget, 1567 }, 1568 }, 1569 } 1570 ctx.baseModuleContext.config = testConfig 1571 1572 t.Run("install for soong", func(t *testing.T) { 1573 p := PathForModuleInstall(ctx, "install/path") 1574 AssertPathRelativeToTopEquals(t, "install path for soong", "out/soong/target/product/test_device/system/install/path", p) 1575 }) 1576 t.Run("install for make", func(t *testing.T) { 1577 p := PathForModuleInstall(ctx, "install/path") 1578 p.makePath = true 1579 AssertPathRelativeToTopEquals(t, "install path for make", "out/target/product/test_device/system/install/path", p) 1580 }) 1581 t.Run("output", func(t *testing.T) { 1582 p := PathForOutput(ctx, "output/path") 1583 AssertPathRelativeToTopEquals(t, "output path", "out/soong/output/path", p) 1584 }) 1585 t.Run("source", func(t *testing.T) { 1586 p := PathForSource(ctx, "source/path") 1587 AssertPathRelativeToTopEquals(t, "source path", "source/path", p) 1588 }) 1589 t.Run("mixture", func(t *testing.T) { 1590 paths := Paths{ 1591 PathForModuleInstall(ctx, "install/path"), 1592 PathForOutput(ctx, "output/path"), 1593 PathForSource(ctx, "source/path"), 1594 } 1595 1596 expected := []string{ 1597 "out/soong/target/product/test_device/system/install/path", 1598 "out/soong/output/path", 1599 "source/path", 1600 } 1601 AssertPathsRelativeToTopEquals(t, "mixture", expected, paths) 1602 }) 1603} 1604 1605func ExampleOutputPath_ReplaceExtension() { 1606 ctx := &configErrorWrapper{ 1607 config: TestConfig("out", nil, "", nil), 1608 } 1609 p := PathForOutput(ctx, "system/framework").Join(ctx, "boot.art") 1610 p2 := p.ReplaceExtension(ctx, "oat") 1611 fmt.Println(p, p2) 1612 fmt.Println(p.Rel(), p2.Rel()) 1613 1614 // Output: 1615 // out/soong/system/framework/boot.art out/soong/system/framework/boot.oat 1616 // boot.art boot.oat 1617} 1618 1619func ExampleOutputPath_InSameDir() { 1620 ctx := &configErrorWrapper{ 1621 config: TestConfig("out", nil, "", nil), 1622 } 1623 p := PathForOutput(ctx, "system/framework").Join(ctx, "boot.art") 1624 p2 := p.InSameDir(ctx, "oat", "arm", "boot.vdex") 1625 fmt.Println(p, p2) 1626 fmt.Println(p.Rel(), p2.Rel()) 1627 1628 // Output: 1629 // out/soong/system/framework/boot.art out/soong/system/framework/oat/arm/boot.vdex 1630 // boot.art oat/arm/boot.vdex 1631} 1632 1633func BenchmarkFirstUniquePaths(b *testing.B) { 1634 implementations := []struct { 1635 name string 1636 f func(Paths) Paths 1637 }{ 1638 { 1639 name: "list", 1640 f: firstUniquePathsList, 1641 }, 1642 { 1643 name: "map", 1644 f: firstUniquePathsMap, 1645 }, 1646 } 1647 const maxSize = 1024 1648 uniquePaths := make(Paths, maxSize) 1649 for i := range uniquePaths { 1650 uniquePaths[i] = PathForTesting(strconv.Itoa(i)) 1651 } 1652 samePath := make(Paths, maxSize) 1653 for i := range samePath { 1654 samePath[i] = uniquePaths[0] 1655 } 1656 1657 f := func(b *testing.B, imp func(Paths) Paths, paths Paths) { 1658 for i := 0; i < b.N; i++ { 1659 b.ReportAllocs() 1660 paths = append(Paths(nil), paths...) 1661 imp(paths) 1662 } 1663 } 1664 1665 for n := 1; n <= maxSize; n <<= 1 { 1666 b.Run(strconv.Itoa(n), func(b *testing.B) { 1667 for _, implementation := range implementations { 1668 b.Run(implementation.name, func(b *testing.B) { 1669 b.Run("same", func(b *testing.B) { 1670 f(b, implementation.f, samePath[:n]) 1671 }) 1672 b.Run("unique", func(b *testing.B) { 1673 f(b, implementation.f, uniquePaths[:n]) 1674 }) 1675 }) 1676 } 1677 }) 1678 } 1679} 1680