1// Copyright 2017 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 15// This file implements the logic of bpfix and also provides a programmatic interface 16 17package bpfix 18 19import ( 20 "bytes" 21 "fmt" 22 "strings" 23 "testing" 24 25 "reflect" 26 27 "github.com/google/blueprint/parser" 28) 29 30// TODO(jeffrygaston) remove this when position is removed from ParseNode (in b/38325146) and we can directly do reflect.DeepEqual 31func printListOfStrings(items []string) (text string) { 32 if len(items) == 0 { 33 return "[]" 34 } 35 return fmt.Sprintf("[\"%s\"]", strings.Join(items, "\", \"")) 36 37} 38 39func buildTree(local_include_dirs []string, export_include_dirs []string) (file *parser.File, errs []error) { 40 // TODO(jeffrygaston) use the builder class when b/38325146 is done 41 input := fmt.Sprintf(`cc_library_shared { 42 name: "iAmAModule", 43 local_include_dirs: %s, 44 export_include_dirs: %s, 45 } 46 `, 47 printListOfStrings(local_include_dirs), printListOfStrings(export_include_dirs)) 48 tree, errs := parser.Parse("", strings.NewReader(input), parser.NewScope(nil)) 49 if len(errs) > 0 { 50 errs = append([]error{fmt.Errorf("failed to parse:\n%s", input)}, errs...) 51 } 52 return tree, errs 53} 54 55func implFilterListTest(t *testing.T, local_include_dirs []string, export_include_dirs []string, expectedResult []string) { 56 // build tree 57 tree, errs := buildTree(local_include_dirs, export_include_dirs) 58 if len(errs) > 0 { 59 t.Error("failed to build tree") 60 for _, err := range errs { 61 t.Error(err) 62 } 63 t.Fatalf("%d parse errors", len(errs)) 64 } 65 66 fixer := NewFixer(tree) 67 68 // apply simplifications 69 err := runPatchListMod(simplifyKnownPropertiesDuplicatingEachOther)(fixer) 70 if len(errs) > 0 { 71 t.Fatal(err) 72 } 73 74 // lookup legacy property 75 mod := fixer.tree.Defs[0].(*parser.Module) 76 77 expectedResultString := fmt.Sprintf("%q", expectedResult) 78 if expectedResult == nil { 79 expectedResultString = "unset" 80 } 81 82 // check that the value for the legacy property was updated to the correct value 83 errorHeader := fmt.Sprintf("\nFailed to correctly simplify key 'local_include_dirs' in the presence of 'export_include_dirs.'\n"+ 84 "original local_include_dirs: %q\n"+ 85 "original export_include_dirs: %q\n"+ 86 "expected result: %s\n"+ 87 "actual result: ", 88 local_include_dirs, export_include_dirs, expectedResultString) 89 result, found := mod.GetProperty("local_include_dirs") 90 if !found { 91 if expectedResult == nil { 92 return 93 } 94 t.Fatal(errorHeader + "property not found") 95 } 96 97 listResult, ok := result.Value.(*parser.List) 98 if !ok { 99 t.Fatalf("%sproperty is not a list: %v", errorHeader, listResult) 100 } 101 102 if expectedResult == nil { 103 t.Fatalf("%sproperty exists: %v", errorHeader, listResult) 104 } 105 106 actualExpressions := listResult.Values 107 actualValues := make([]string, 0) 108 for _, expr := range actualExpressions { 109 str := expr.(*parser.String) 110 actualValues = append(actualValues, str.Value) 111 } 112 113 if !reflect.DeepEqual(actualValues, expectedResult) { 114 t.Fatalf("%s%q\nlists are different", errorHeader, actualValues) 115 } 116} 117 118func TestSimplifyKnownVariablesDuplicatingEachOther(t *testing.T) { 119 // TODO use []Expression{} once buildTree above can support it (which is after b/38325146 is done) 120 implFilterListTest(t, []string{"include"}, []string{"include"}, nil) 121 implFilterListTest(t, []string{"include1"}, []string{"include2"}, []string{"include1"}) 122 implFilterListTest(t, []string{"include1", "include2", "include3", "include4"}, []string{"include2"}, 123 []string{"include1", "include3", "include4"}) 124 implFilterListTest(t, []string{}, []string{"include"}, []string{}) 125 implFilterListTest(t, []string{}, []string{}, []string{}) 126} 127 128func runPass(t *testing.T, in, out string, innerTest func(*Fixer) error) { 129 expected, err := Reformat(out) 130 if err != nil { 131 t.Fatal(err) 132 } 133 134 in, err = Reformat(in) 135 if err != nil { 136 t.Fatal(err) 137 } 138 139 tree, errs := parser.Parse("<testcase>", bytes.NewBufferString(in), parser.NewScope(nil)) 140 if errs != nil { 141 t.Fatal(errs) 142 } 143 144 fixer := NewFixer(tree) 145 146 got := "" 147 prev := "foo" 148 passes := 0 149 for got != prev && passes < 10 { 150 err := innerTest(fixer) 151 if err != nil { 152 t.Fatal(err) 153 } 154 155 out, err := parser.Print(fixer.tree) 156 if err != nil { 157 t.Fatal(err) 158 } 159 160 prev = got 161 got = string(out) 162 passes++ 163 } 164 165 if got != expected { 166 t.Errorf("output didn't match:\ninput:\n%s\n\nexpected:\n%s\ngot:\n%s\n", 167 in, expected, got) 168 } 169} 170 171func TestMergeMatchingProperties(t *testing.T) { 172 tests := []struct { 173 name string 174 in string 175 out string 176 }{ 177 { 178 name: "empty", 179 in: ` 180 java_library { 181 name: "foo", 182 static_libs: [], 183 static_libs: [], 184 } 185 `, 186 out: ` 187 java_library { 188 name: "foo", 189 static_libs: [], 190 } 191 `, 192 }, 193 { 194 name: "single line into multiline", 195 in: ` 196 java_library { 197 name: "foo", 198 static_libs: [ 199 "a", 200 "b", 201 ], 202 //c1 203 static_libs: ["c" /*c2*/], 204 } 205 `, 206 out: ` 207 java_library { 208 name: "foo", 209 static_libs: [ 210 "a", 211 "b", 212 "c", /*c2*/ 213 ], 214 //c1 215 } 216 `, 217 }, 218 { 219 name: "multiline into multiline", 220 in: ` 221 java_library { 222 name: "foo", 223 static_libs: [ 224 "a", 225 "b", 226 ], 227 //c1 228 static_libs: [ 229 //c2 230 "c", //c3 231 "d", 232 ], 233 } 234 `, 235 out: ` 236 java_library { 237 name: "foo", 238 static_libs: [ 239 "a", 240 "b", 241 //c2 242 "c", //c3 243 "d", 244 ], 245 //c1 246 } 247 `, 248 }, 249 } 250 251 for _, test := range tests { 252 t.Run(test.name, func(t *testing.T) { 253 runPass(t, test.in, test.out, func(fixer *Fixer) error { 254 return runPatchListMod(mergeMatchingModuleProperties)(fixer) 255 }) 256 }) 257 } 258} 259 260func TestReorderCommonProperties(t *testing.T) { 261 var tests = []struct { 262 name string 263 in string 264 out string 265 }{ 266 { 267 name: "empty", 268 in: `cc_library {}`, 269 out: `cc_library {}`, 270 }, 271 { 272 name: "only priority", 273 in: ` 274 cc_library { 275 name: "foo", 276 } 277 `, 278 out: ` 279 cc_library { 280 name: "foo", 281 } 282 `, 283 }, 284 { 285 name: "already in order", 286 in: ` 287 cc_library { 288 name: "foo", 289 defaults: ["bar"], 290 } 291 `, 292 out: ` 293 cc_library { 294 name: "foo", 295 defaults: ["bar"], 296 } 297 `, 298 }, 299 { 300 name: "reorder only priority", 301 in: ` 302 cc_library { 303 defaults: ["bar"], 304 name: "foo", 305 } 306 `, 307 out: ` 308 cc_library { 309 name: "foo", 310 defaults: ["bar"], 311 } 312 `, 313 }, 314 { 315 name: "reorder", 316 in: ` 317 cc_library { 318 name: "foo", 319 srcs: ["a.c"], 320 host_supported: true, 321 defaults: ["bar"], 322 shared_libs: ["baz"], 323 } 324 `, 325 out: ` 326 cc_library { 327 name: "foo", 328 defaults: ["bar"], 329 host_supported: true, 330 srcs: ["a.c"], 331 shared_libs: ["baz"], 332 } 333 `, 334 }, 335 } 336 337 for _, test := range tests { 338 t.Run(test.name, func(t *testing.T) { 339 runPass(t, test.in, test.out, func(fixer *Fixer) error { 340 return runPatchListMod(reorderCommonProperties)(fixer) 341 }) 342 }) 343 } 344} 345 346func TestRemoveMatchingModuleListProperties(t *testing.T) { 347 var tests = []struct { 348 name string 349 in string 350 out string 351 }{ 352 { 353 name: "simple", 354 in: ` 355 cc_library { 356 name: "foo", 357 foo: ["a"], 358 bar: ["a"], 359 } 360 `, 361 out: ` 362 cc_library { 363 name: "foo", 364 bar: ["a"], 365 } 366 `, 367 }, 368 { 369 name: "long", 370 in: ` 371 cc_library { 372 name: "foo", 373 foo: [ 374 "a", 375 "b", 376 ], 377 bar: ["a"], 378 } 379 `, 380 out: ` 381 cc_library { 382 name: "foo", 383 foo: [ 384 "b", 385 ], 386 bar: ["a"], 387 } 388 `, 389 }, 390 { 391 name: "long fully removed", 392 in: ` 393 cc_library { 394 name: "foo", 395 foo: [ 396 "a", 397 ], 398 bar: ["a"], 399 } 400 `, 401 out: ` 402 cc_library { 403 name: "foo", 404 bar: ["a"], 405 } 406 `, 407 }, 408 { 409 name: "comment", 410 in: ` 411 cc_library { 412 name: "foo", 413 414 // comment 415 foo: ["a"], 416 417 bar: ["a"], 418 } 419 `, 420 out: ` 421 cc_library { 422 name: "foo", 423 424 // comment 425 426 bar: ["a"], 427 } 428 `, 429 }, 430 { 431 name: "inner comment", 432 in: ` 433 cc_library { 434 name: "foo", 435 foo: [ 436 // comment 437 "a", 438 ], 439 bar: ["a"], 440 } 441 `, 442 out: ` 443 cc_library { 444 name: "foo", 445 bar: ["a"], 446 } 447 `, 448 }, 449 { 450 name: "eol comment", 451 in: ` 452 cc_library { 453 name: "foo", 454 foo: ["a"], // comment 455 bar: ["a"], 456 } 457 `, 458 out: ` 459 cc_library { 460 name: "foo", 461 // comment 462 bar: ["a"], 463 } 464 `, 465 }, 466 { 467 name: "eol comment with blank lines", 468 in: ` 469 cc_library { 470 name: "foo", 471 472 foo: ["a"], // comment 473 474 // bar 475 bar: ["a"], 476 } 477 `, 478 out: ` 479 cc_library { 480 name: "foo", 481 482 // comment 483 484 // bar 485 bar: ["a"], 486 } 487 `, 488 }, 489 } 490 for _, test := range tests { 491 t.Run(test.name, func(t *testing.T) { 492 runPass(t, test.in, test.out, func(fixer *Fixer) error { 493 return runPatchListMod(func(mod *parser.Module, buf []byte, patchList *parser.PatchList) error { 494 return removeMatchingModuleListProperties(mod, patchList, "bar", "foo") 495 })(fixer) 496 }) 497 }) 498 } 499} 500 501func TestReplaceJavaStaticLibs(t *testing.T) { 502 tests := []struct { 503 name string 504 in string 505 out string 506 }{ 507 { 508 name: "static lib", 509 in: ` 510 java_library_static { 511 name: "foo", 512 } 513 `, 514 out: ` 515 java_library { 516 name: "foo", 517 } 518 `, 519 }, 520 { 521 name: "java lib", 522 in: ` 523 java_library { 524 name: "foo", 525 } 526 `, 527 out: ` 528 java_library { 529 name: "foo", 530 } 531 `, 532 }, 533 { 534 name: "java installable lib", 535 in: ` 536 java_library { 537 name: "foo", 538 installable: true, 539 } 540 `, 541 out: ` 542 java_library { 543 name: "foo", 544 installable: true, 545 } 546 `, 547 }, 548 } 549 550 for _, test := range tests { 551 t.Run(test.name, func(t *testing.T) { 552 runPass(t, test.in, test.out, func(fixer *Fixer) error { 553 return rewriteJavaStaticLibs(fixer) 554 }) 555 }) 556 } 557} 558 559func TestRewritePrebuilts(t *testing.T) { 560 tests := []struct { 561 name string 562 in string 563 out string 564 }{ 565 { 566 name: "jar srcs", 567 in: ` 568 java_import { 569 name: "foo", 570 srcs: ["foo.jar"], 571 } 572 `, 573 out: ` 574 java_import { 575 name: "foo", 576 jars: ["foo.jar"], 577 } 578 `, 579 }, 580 { 581 name: "aar srcs", 582 in: ` 583 java_import { 584 name: "foo", 585 srcs: ["foo.aar"], 586 installable: true, 587 } 588 `, 589 out: ` 590 android_library_import { 591 name: "foo", 592 aars: ["foo.aar"], 593 594 } 595 `, 596 }, 597 { 598 name: "host prebuilt", 599 in: ` 600 java_import { 601 name: "foo", 602 srcs: ["foo.jar"], 603 host: true, 604 } 605 `, 606 out: ` 607 java_import_host { 608 name: "foo", 609 jars: ["foo.jar"], 610 611 } 612 `, 613 }, 614 } 615 616 for _, test := range tests { 617 t.Run(test.name, func(t *testing.T) { 618 runPass(t, test.in, test.out, func(fixer *Fixer) error { 619 return rewriteIncorrectAndroidmkPrebuilts(fixer) 620 }) 621 }) 622 } 623} 624 625func TestRewriteCtsModuleTypes(t *testing.T) { 626 tests := []struct { 627 name string 628 in string 629 out string 630 }{ 631 { 632 name: "cts_support_package", 633 in: ` 634 cts_support_package { 635 name: "foo", 636 } 637 `, 638 out: ` 639 android_test { 640 name: "foo", 641 defaults: ["cts_support_defaults"], 642 } 643 `, 644 }, 645 { 646 name: "cts_package", 647 in: ` 648 cts_package { 649 name: "foo", 650 } 651 `, 652 out: ` 653 android_test { 654 name: "foo", 655 defaults: ["cts_defaults"], 656 } 657 `, 658 }, 659 { 660 name: "cts_target_java_library", 661 in: ` 662 cts_target_java_library { 663 name: "foo", 664 } 665 `, 666 out: ` 667 java_library { 668 name: "foo", 669 defaults: ["cts_defaults"], 670 } 671 `, 672 }, 673 { 674 name: "cts_host_java_library", 675 in: ` 676 cts_host_java_library { 677 name: "foo", 678 } 679 `, 680 out: ` 681 java_library_host { 682 name: "foo", 683 defaults: ["cts_defaults"], 684 } 685 `, 686 }, 687 } 688 689 for _, test := range tests { 690 t.Run(test.name, func(t *testing.T) { 691 runPass(t, test.in, test.out, rewriteCtsModuleTypes) 692 }) 693 } 694} 695 696func TestRewritePrebuiltEtc(t *testing.T) { 697 tests := []struct { 698 name string 699 in string 700 out string 701 }{ 702 { 703 name: "prebuilt_etc src", 704 in: ` 705 prebuilt_etc { 706 name: "foo", 707 srcs: ["bar"], 708 } 709 `, 710 out: `prebuilt_etc { 711 name: "foo", 712 src: "bar", 713 } 714 `, 715 }, 716 { 717 name: "prebuilt_etc src", 718 in: ` 719 prebuilt_etc { 720 name: "foo", 721 srcs: FOO, 722 } 723 `, 724 out: `prebuilt_etc { 725 name: "foo", 726 src: FOO, 727 } 728 `, 729 }, 730 { 731 name: "prebuilt_etc src", 732 in: ` 733 prebuilt_etc { 734 name: "foo", 735 srcs: ["bar", "baz"], 736 } 737 `, 738 out: `prebuilt_etc { 739 name: "foo", 740 src: "ERROR: LOCAL_SRC_FILES should contain at most one item", 741 742 } 743 `, 744 }, 745 { 746 name: "prebuilt_etc sub_dir", 747 in: ` 748 prebuilt_etc { 749 name: "foo", 750 src: "bar", 751 sub_dir: "baz", 752 } 753 `, 754 out: `prebuilt_etc { 755 name: "foo", 756 src: "bar", 757 relative_install_dir: "baz", 758 } 759 `, 760 }, 761 } 762 for _, test := range tests { 763 t.Run(test.name, func(t *testing.T) { 764 runPass(t, test.in, test.out, func(fixer *Fixer) error { 765 return rewriteAndroidmkPrebuiltEtc(fixer) 766 }) 767 }) 768 } 769} 770 771func TestRewriteAndroidTest(t *testing.T) { 772 tests := []struct { 773 name string 774 in string 775 out string 776 }{ 777 { 778 name: "android_test valid module path", 779 in: ` 780 android_test { 781 name: "foo", 782 local_module_path: { 783 var: "TARGET_OUT_DATA_APPS", 784 }, 785 } 786 `, 787 out: ` 788 android_test { 789 name: "foo", 790 791 } 792 `, 793 }, 794 } 795 for _, test := range tests { 796 t.Run(test.name, func(t *testing.T) { 797 runPass(t, test.in, test.out, func(fixer *Fixer) error { 798 return rewriteAndroidTest(fixer) 799 }) 800 }) 801 } 802} 803 804func TestRewriteAndroidAppImport(t *testing.T) { 805 tests := []struct { 806 name string 807 in string 808 out string 809 }{ 810 { 811 name: "android_app_import apk", 812 in: ` 813 android_app_import { 814 name: "foo", 815 srcs: ["package.apk"], 816 } 817 `, 818 out: ` 819 android_app_import { 820 name: "foo", 821 apk: "package.apk", 822 } 823 `, 824 }, 825 { 826 name: "android_app_import presigned", 827 in: ` 828 android_app_import { 829 name: "foo", 830 apk: "package.apk", 831 certificate: "PRESIGNED", 832 } 833 `, 834 out: ` 835 android_app_import { 836 name: "foo", 837 apk: "package.apk", 838 presigned: true, 839 840 } 841 `, 842 }, 843 } 844 for _, test := range tests { 845 t.Run(test.name, func(t *testing.T) { 846 runPass(t, test.in, test.out, func(fixer *Fixer) error { 847 return rewriteAndroidAppImport(fixer) 848 }) 849 }) 850 } 851} 852 853func TestRemoveEmptyLibDependencies(t *testing.T) { 854 tests := []struct { 855 name string 856 in string 857 out string 858 }{ 859 { 860 name: "remove sole shared lib", 861 in: ` 862 cc_library { 863 name: "foo", 864 shared_libs: ["libhwbinder"], 865 } 866 `, 867 out: ` 868 cc_library { 869 name: "foo", 870 871 } 872 `, 873 }, 874 { 875 name: "remove a shared lib", 876 in: ` 877 cc_library { 878 name: "foo", 879 shared_libs: [ 880 "libhwbinder", 881 "libfoo", 882 "libhidltransport", 883 ], 884 } 885 `, 886 out: ` 887 cc_library { 888 name: "foo", 889 shared_libs: [ 890 891 "libfoo", 892 893 ], 894 } 895 `, 896 }, 897 } 898 for _, test := range tests { 899 t.Run(test.name, func(t *testing.T) { 900 runPass(t, test.in, test.out, func(fixer *Fixer) error { 901 return removeEmptyLibDependencies(fixer) 902 }) 903 }) 904 } 905} 906 907func TestRemoveHidlInterfaceTypes(t *testing.T) { 908 tests := []struct { 909 name string 910 in string 911 out string 912 }{ 913 { 914 name: "remove types", 915 in: ` 916 hidl_interface { 917 name: "foo@1.0", 918 types: ["ParcelFooBar"], 919 } 920 `, 921 out: ` 922 hidl_interface { 923 name: "foo@1.0", 924 925 } 926 `, 927 }, 928 } 929 for _, test := range tests { 930 t.Run(test.name, func(t *testing.T) { 931 runPass(t, test.in, test.out, func(fixer *Fixer) error { 932 return removeHidlInterfaceTypes(fixer) 933 }) 934 }) 935 } 936} 937 938func TestRemoveSoongConfigBoolVariable(t *testing.T) { 939 tests := []struct { 940 name string 941 in string 942 out string 943 }{ 944 { 945 name: "remove bool", 946 in: ` 947 soong_config_module_type { 948 name: "foo", 949 variables: ["bar", "baz"], 950 } 951 952 soong_config_bool_variable { 953 name: "bar", 954 } 955 956 soong_config_string_variable { 957 name: "baz", 958 } 959 `, 960 out: ` 961 soong_config_module_type { 962 name: "foo", 963 variables: [ 964 "baz" 965 ], 966 bool_variables: ["bar"], 967 } 968 969 soong_config_string_variable { 970 name: "baz", 971 } 972 `, 973 }, 974 { 975 name: "existing bool_variables", 976 in: ` 977 soong_config_module_type { 978 name: "foo", 979 variables: ["baz"], 980 bool_variables: ["bar"], 981 } 982 983 soong_config_bool_variable { 984 name: "baz", 985 } 986 `, 987 out: ` 988 soong_config_module_type { 989 name: "foo", 990 bool_variables: ["bar", "baz"], 991 } 992 `, 993 }, 994 } 995 for _, test := range tests { 996 t.Run(test.name, func(t *testing.T) { 997 runPass(t, test.in, test.out, removeSoongConfigBoolVariable) 998 }) 999 } 1000} 1001 1002func TestRemovePdkProperty(t *testing.T) { 1003 tests := []struct { 1004 name string 1005 in string 1006 out string 1007 }{ 1008 { 1009 name: "remove property", 1010 in: ` 1011 cc_library_shared { 1012 name: "foo", 1013 product_variables: { 1014 other: { 1015 bar: true, 1016 }, 1017 pdk: { 1018 enabled: false, 1019 }, 1020 }, 1021 } 1022 `, 1023 out: ` 1024 cc_library_shared { 1025 name: "foo", 1026 product_variables: { 1027 other: { 1028 bar: true, 1029 }, 1030 }, 1031 } 1032 `, 1033 }, 1034 { 1035 name: "remove property and empty product_variables", 1036 in: ` 1037 cc_library_shared { 1038 name: "foo", 1039 product_variables: { 1040 pdk: { 1041 enabled: false, 1042 }, 1043 }, 1044 } 1045 `, 1046 out: ` 1047 cc_library_shared { 1048 name: "foo", 1049 } 1050 `, 1051 }, 1052 } 1053 for _, test := range tests { 1054 t.Run(test.name, func(t *testing.T) { 1055 runPass(t, test.in, test.out, runPatchListMod(removePdkProperty)) 1056 }) 1057 } 1058} 1059 1060func TestRewriteRuntimeResourceOverlay(t *testing.T) { 1061 tests := []struct { 1062 name string 1063 in string 1064 out string 1065 }{ 1066 { 1067 name: "product_specific runtime_resource_overlay", 1068 in: ` 1069 runtime_resource_overlay { 1070 name: "foo", 1071 resource_dirs: ["res"], 1072 product_specific: true, 1073 } 1074 `, 1075 out: ` 1076 runtime_resource_overlay { 1077 name: "foo", 1078 resource_dirs: ["res"], 1079 product_specific: true, 1080 } 1081 `, 1082 }, 1083 { 1084 // It's probably wrong for runtime_resource_overlay not to be product specific, but let's not 1085 // debate it here. 1086 name: "non-product_specific runtime_resource_overlay", 1087 in: ` 1088 runtime_resource_overlay { 1089 name: "foo", 1090 resource_dirs: ["res"], 1091 product_specific: false, 1092 } 1093 `, 1094 out: ` 1095 runtime_resource_overlay { 1096 name: "foo", 1097 resource_dirs: ["res"], 1098 product_specific: false, 1099 } 1100 `, 1101 }, 1102 { 1103 name: "runtime_resource_overlay without product_specific value", 1104 in: ` 1105 runtime_resource_overlay { 1106 name: "foo", 1107 resource_dirs: ["res"], 1108 } 1109 `, 1110 out: ` 1111 runtime_resource_overlay { 1112 name: "foo", 1113 resource_dirs: ["res"], 1114 product_specific: true, 1115 } 1116 `, 1117 }, 1118 } 1119 for _, test := range tests { 1120 t.Run(test.name, func(t *testing.T) { 1121 runPass(t, test.in, test.out, func(fixer *Fixer) error { 1122 return RewriteRuntimeResourceOverlay(fixer) 1123 }) 1124 }) 1125 } 1126} 1127