github.com/powerman/golang-tools@v0.1.11-0.20220410185822-5ad214d8d803/go/ast/astutil/imports_test.go (about) 1 // Copyright 2013 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package astutil 6 7 import ( 8 "bytes" 9 "go/ast" 10 "go/format" 11 "go/parser" 12 "go/token" 13 "reflect" 14 "strconv" 15 "testing" 16 ) 17 18 var fset = token.NewFileSet() 19 20 func parse(t *testing.T, name, in string) *ast.File { 21 file, err := parser.ParseFile(fset, name, in, parser.ParseComments) 22 if err != nil { 23 t.Fatalf("%s parse: %v", name, err) 24 } 25 return file 26 } 27 28 func print(t *testing.T, name string, f *ast.File) string { 29 var buf bytes.Buffer 30 if err := format.Node(&buf, fset, f); err != nil { 31 t.Fatalf("%s gofmt: %v", name, err) 32 } 33 return buf.String() 34 } 35 36 type test struct { 37 name string 38 renamedPkg string 39 pkg string 40 in string 41 out string 42 unchanged bool // Expect added/deleted return value to be false. 43 } 44 45 var addTests = []test{ 46 { 47 name: "leave os alone", 48 pkg: "os", 49 in: `package main 50 51 import ( 52 "os" 53 ) 54 `, 55 out: `package main 56 57 import ( 58 "os" 59 ) 60 `, 61 unchanged: true, 62 }, 63 { 64 name: "import.1", 65 pkg: "os", 66 in: `package main 67 `, 68 out: `package main 69 70 import "os" 71 `, 72 }, 73 { 74 name: "import.2", 75 pkg: "os", 76 in: `package main 77 78 // Comment 79 import "C" 80 `, 81 out: `package main 82 83 // Comment 84 import "C" 85 import "os" 86 `, 87 }, 88 { 89 name: "import.3", 90 pkg: "os", 91 in: `package main 92 93 // Comment 94 import "C" 95 96 import ( 97 "io" 98 "utf8" 99 ) 100 `, 101 out: `package main 102 103 // Comment 104 import "C" 105 106 import ( 107 "io" 108 "os" 109 "utf8" 110 ) 111 `, 112 }, 113 { 114 name: "import.17", 115 pkg: "x/y/z", 116 in: `package main 117 118 // Comment 119 import "C" 120 121 import ( 122 "a" 123 "b" 124 125 "x/w" 126 127 "d/f" 128 ) 129 `, 130 out: `package main 131 132 // Comment 133 import "C" 134 135 import ( 136 "a" 137 "b" 138 139 "x/w" 140 "x/y/z" 141 142 "d/f" 143 ) 144 `, 145 }, 146 { 147 name: "issue #19190", 148 pkg: "x.org/y/z", 149 in: `package main 150 151 // Comment 152 import "C" 153 154 import ( 155 "bytes" 156 "os" 157 158 "d.com/f" 159 ) 160 `, 161 out: `package main 162 163 // Comment 164 import "C" 165 166 import ( 167 "bytes" 168 "os" 169 170 "d.com/f" 171 "x.org/y/z" 172 ) 173 `, 174 }, 175 { 176 name: "issue #19190 with existing grouped import packages", 177 pkg: "x.org/y/z", 178 in: `package main 179 180 // Comment 181 import "C" 182 183 import ( 184 "bytes" 185 "os" 186 187 "c.com/f" 188 "d.com/f" 189 190 "y.com/a" 191 "y.com/b" 192 "y.com/c" 193 ) 194 `, 195 out: `package main 196 197 // Comment 198 import "C" 199 200 import ( 201 "bytes" 202 "os" 203 204 "c.com/f" 205 "d.com/f" 206 "x.org/y/z" 207 208 "y.com/a" 209 "y.com/b" 210 "y.com/c" 211 ) 212 `, 213 }, 214 { 215 name: "issue #19190 - match score is still respected", 216 pkg: "y.org/c", 217 in: `package main 218 219 import ( 220 "x.org/a" 221 222 "y.org/b" 223 ) 224 `, 225 out: `package main 226 227 import ( 228 "x.org/a" 229 230 "y.org/b" 231 "y.org/c" 232 ) 233 `, 234 }, 235 { 236 name: "import into singular group", 237 pkg: "bytes", 238 in: `package main 239 240 import "os" 241 242 `, 243 out: `package main 244 245 import ( 246 "bytes" 247 "os" 248 ) 249 `, 250 }, 251 { 252 name: "import into singular group with comment", 253 pkg: "bytes", 254 in: `package main 255 256 import /* why */ /* comment here? */ "os" 257 258 `, 259 out: `package main 260 261 import /* why */ /* comment here? */ ( 262 "bytes" 263 "os" 264 ) 265 `, 266 }, 267 { 268 name: "import into group with leading comment", 269 pkg: "strings", 270 in: `package main 271 272 import ( 273 // comment before bytes 274 "bytes" 275 "os" 276 ) 277 278 `, 279 out: `package main 280 281 import ( 282 // comment before bytes 283 "bytes" 284 "os" 285 "strings" 286 ) 287 `, 288 }, 289 { 290 name: "", 291 renamedPkg: "fmtpkg", 292 pkg: "fmt", 293 in: `package main 294 295 import "os" 296 297 `, 298 out: `package main 299 300 import ( 301 fmtpkg "fmt" 302 "os" 303 ) 304 `, 305 }, 306 { 307 name: "struct comment", 308 pkg: "time", 309 in: `package main 310 311 // This is a comment before a struct. 312 type T struct { 313 t time.Time 314 } 315 `, 316 out: `package main 317 318 import "time" 319 320 // This is a comment before a struct. 321 type T struct { 322 t time.Time 323 } 324 `, 325 }, 326 { 327 name: "issue 8729 import C", 328 pkg: "time", 329 in: `package main 330 331 import "C" 332 333 // comment 334 type T time.Time 335 `, 336 out: `package main 337 338 import "C" 339 import "time" 340 341 // comment 342 type T time.Time 343 `, 344 }, 345 { 346 name: "issue 8729 empty import", 347 pkg: "time", 348 in: `package main 349 350 import () 351 352 // comment 353 type T time.Time 354 `, 355 out: `package main 356 357 import "time" 358 359 // comment 360 type T time.Time 361 `, 362 }, 363 { 364 name: "issue 8729 comment on package line", 365 pkg: "time", 366 in: `package main // comment 367 368 type T time.Time 369 `, 370 out: `package main // comment 371 372 import "time" 373 374 type T time.Time 375 `, 376 }, 377 { 378 name: "issue 8729 comment after package", 379 pkg: "time", 380 in: `package main 381 // comment 382 383 type T time.Time 384 `, 385 out: `package main 386 387 import "time" 388 389 // comment 390 391 type T time.Time 392 `, 393 }, 394 { 395 name: "issue 8729 comment before and on package line", 396 pkg: "time", 397 in: `// comment before 398 package main // comment on 399 400 type T time.Time 401 `, 402 out: `// comment before 403 package main // comment on 404 405 import "time" 406 407 type T time.Time 408 `, 409 }, 410 411 // Issue 9961: Match prefixes using path segments rather than bytes 412 { 413 name: "issue 9961", 414 pkg: "regexp", 415 in: `package main 416 417 import ( 418 "flag" 419 "testing" 420 421 "rsc.io/p" 422 ) 423 `, 424 out: `package main 425 426 import ( 427 "flag" 428 "regexp" 429 "testing" 430 431 "rsc.io/p" 432 ) 433 `, 434 }, 435 // Issue 10337: Preserve comment position 436 { 437 name: "issue 10337", 438 pkg: "fmt", 439 in: `package main 440 441 import ( 442 "bytes" // a 443 "log" // c 444 ) 445 `, 446 out: `package main 447 448 import ( 449 "bytes" // a 450 "fmt" 451 "log" // c 452 ) 453 `, 454 }, 455 { 456 name: "issue 10337 new import at the start", 457 pkg: "bytes", 458 in: `package main 459 460 import ( 461 "fmt" // b 462 "log" // c 463 ) 464 `, 465 out: `package main 466 467 import ( 468 "bytes" 469 "fmt" // b 470 "log" // c 471 ) 472 `, 473 }, 474 { 475 name: "issue 10337 new import at the end", 476 pkg: "log", 477 in: `package main 478 479 import ( 480 "bytes" // a 481 "fmt" // b 482 ) 483 `, 484 out: `package main 485 486 import ( 487 "bytes" // a 488 "fmt" // b 489 "log" 490 ) 491 `, 492 }, 493 // Issue 14075: Merge import declarations 494 { 495 name: "issue 14075", 496 pkg: "bufio", 497 in: `package main 498 499 import "bytes" 500 import "fmt" 501 `, 502 out: `package main 503 504 import ( 505 "bufio" 506 "bytes" 507 "fmt" 508 ) 509 `, 510 }, 511 { 512 name: "issue 14075 update position", 513 pkg: "bufio", 514 in: `package main 515 516 import "bytes" 517 import ( 518 "fmt" 519 ) 520 `, 521 out: `package main 522 523 import ( 524 "bufio" 525 "bytes" 526 "fmt" 527 ) 528 `, 529 }, 530 { 531 name: `issue 14075 ignore import "C"`, 532 pkg: "bufio", 533 in: `package main 534 535 // Comment 536 import "C" 537 538 import "bytes" 539 import "fmt" 540 `, 541 out: `package main 542 543 // Comment 544 import "C" 545 546 import ( 547 "bufio" 548 "bytes" 549 "fmt" 550 ) 551 `, 552 }, 553 { 554 name: `issue 14075 ignore adjacent import "C"`, 555 pkg: "bufio", 556 in: `package main 557 558 // Comment 559 import "C" 560 import "fmt" 561 `, 562 out: `package main 563 564 // Comment 565 import "C" 566 import ( 567 "bufio" 568 "fmt" 569 ) 570 `, 571 }, 572 { 573 name: `issue 14075 ignore adjacent import "C" (without factored import)`, 574 pkg: "bufio", 575 in: `package main 576 577 // Comment 578 import "C" 579 import "fmt" 580 `, 581 out: `package main 582 583 // Comment 584 import "C" 585 import ( 586 "bufio" 587 "fmt" 588 ) 589 `, 590 }, 591 { 592 name: `issue 14075 ignore single import "C"`, 593 pkg: "bufio", 594 in: `package main 595 596 // Comment 597 import "C" 598 `, 599 out: `package main 600 601 // Comment 602 import "C" 603 import "bufio" 604 `, 605 }, 606 { 607 name: `issue 17212 several single-import lines with shared prefix ending in a slash`, 608 pkg: "net/http", 609 in: `package main 610 611 import "bufio" 612 import "net/url" 613 `, 614 out: `package main 615 616 import ( 617 "bufio" 618 "net/http" 619 "net/url" 620 ) 621 `, 622 }, 623 { 624 name: `issue 17212 block imports lines with shared prefix ending in a slash`, 625 pkg: "net/http", 626 in: `package main 627 628 import ( 629 "bufio" 630 "net/url" 631 ) 632 `, 633 out: `package main 634 635 import ( 636 "bufio" 637 "net/http" 638 "net/url" 639 ) 640 `, 641 }, 642 { 643 name: `issue 17213 many single-import lines`, 644 pkg: "fmt", 645 in: `package main 646 647 import "bufio" 648 import "bytes" 649 import "errors" 650 `, 651 out: `package main 652 653 import ( 654 "bufio" 655 "bytes" 656 "errors" 657 "fmt" 658 ) 659 `, 660 }, 661 662 // Issue 28605: Add specified import, even if that import path is imported under another name 663 { 664 name: "issue 28605 add unnamed path", 665 renamedPkg: "", 666 pkg: "path", 667 in: `package main 668 669 import ( 670 . "path" 671 _ "path" 672 pathpkg "path" 673 ) 674 `, 675 out: `package main 676 677 import ( 678 "path" 679 . "path" 680 _ "path" 681 pathpkg "path" 682 ) 683 `, 684 }, 685 { 686 name: "issue 28605 add pathpkg-renamed path", 687 renamedPkg: "pathpkg", 688 pkg: "path", 689 in: `package main 690 691 import ( 692 "path" 693 . "path" 694 _ "path" 695 ) 696 `, 697 out: `package main 698 699 import ( 700 "path" 701 . "path" 702 _ "path" 703 pathpkg "path" 704 ) 705 `, 706 }, 707 { 708 name: "issue 28605 add blank identifier path", 709 renamedPkg: "_", 710 pkg: "path", 711 in: `package main 712 713 import ( 714 "path" 715 . "path" 716 pathpkg "path" 717 ) 718 `, 719 out: `package main 720 721 import ( 722 "path" 723 . "path" 724 _ "path" 725 pathpkg "path" 726 ) 727 `, 728 }, 729 { 730 name: "issue 28605 add dot import path", 731 renamedPkg: ".", 732 pkg: "path", 733 in: `package main 734 735 import ( 736 "path" 737 _ "path" 738 pathpkg "path" 739 ) 740 `, 741 out: `package main 742 743 import ( 744 "path" 745 . "path" 746 _ "path" 747 pathpkg "path" 748 ) 749 `, 750 }, 751 752 { 753 name: "duplicate import declarations, add existing one", 754 renamedPkg: "f", 755 pkg: "fmt", 756 in: `package main 757 758 import "fmt" 759 import "fmt" 760 import f "fmt" 761 import f "fmt" 762 `, 763 out: `package main 764 765 import "fmt" 766 import "fmt" 767 import f "fmt" 768 import f "fmt" 769 `, 770 unchanged: true, 771 }, 772 } 773 774 func TestAddImport(t *testing.T) { 775 for _, test := range addTests { 776 file := parse(t, test.name, test.in) 777 var before bytes.Buffer 778 ast.Fprint(&before, fset, file, nil) 779 added := AddNamedImport(fset, file, test.renamedPkg, test.pkg) 780 if got := print(t, test.name, file); got != test.out { 781 t.Errorf("first run: %s:\ngot: %s\nwant: %s", test.name, got, test.out) 782 var after bytes.Buffer 783 ast.Fprint(&after, fset, file, nil) 784 t.Logf("AST before:\n%s\nAST after:\n%s\n", before.String(), after.String()) 785 } 786 if got, want := added, !test.unchanged; got != want { 787 t.Errorf("first run: %s: added = %v, want %v", test.name, got, want) 788 } 789 790 // AddNamedImport should be idempotent. Verify that by calling it again, 791 // expecting no change to the AST, and the returned added value to always be false. 792 added = AddNamedImport(fset, file, test.renamedPkg, test.pkg) 793 if got := print(t, test.name, file); got != test.out { 794 t.Errorf("second run: %s:\ngot: %s\nwant: %s", test.name, got, test.out) 795 } 796 if got, want := added, false; got != want { 797 t.Errorf("second run: %s: added = %v, want %v", test.name, got, want) 798 } 799 } 800 } 801 802 func TestDoubleAddImport(t *testing.T) { 803 file := parse(t, "doubleimport", "package main\n") 804 AddImport(fset, file, "os") 805 AddImport(fset, file, "bytes") 806 want := `package main 807 808 import ( 809 "bytes" 810 "os" 811 ) 812 ` 813 if got := print(t, "doubleimport", file); got != want { 814 t.Errorf("got: %s\nwant: %s", got, want) 815 } 816 } 817 818 func TestDoubleAddNamedImport(t *testing.T) { 819 file := parse(t, "doublenamedimport", "package main\n") 820 AddNamedImport(fset, file, "o", "os") 821 AddNamedImport(fset, file, "i", "io") 822 want := `package main 823 824 import ( 825 i "io" 826 o "os" 827 ) 828 ` 829 if got := print(t, "doublenamedimport", file); got != want { 830 t.Errorf("got: %s\nwant: %s", got, want) 831 } 832 } 833 834 // Part of issue 8729. 835 func TestDoubleAddImportWithDeclComment(t *testing.T) { 836 file := parse(t, "doubleimport", `package main 837 838 import ( 839 ) 840 841 // comment 842 type I int 843 `) 844 // The AddImport order here matters. 845 AddImport(fset, file, "github.com/powerman/golang-tools/go/ast/astutil") 846 AddImport(fset, file, "os") 847 want := `package main 848 849 import ( 850 "github.com/powerman/golang-tools/go/ast/astutil" 851 "os" 852 ) 853 854 // comment 855 type I int 856 ` 857 if got := print(t, "doubleimport_with_decl_comment", file); got != want { 858 t.Errorf("got: %s\nwant: %s", got, want) 859 } 860 } 861 862 var deleteTests = []test{ 863 { 864 name: "import.4", 865 pkg: "os", 866 in: `package main 867 868 import ( 869 "os" 870 ) 871 `, 872 out: `package main 873 `, 874 }, 875 { 876 name: "import.5", 877 pkg: "os", 878 in: `package main 879 880 // Comment 881 import "C" 882 import "os" 883 `, 884 out: `package main 885 886 // Comment 887 import "C" 888 `, 889 }, 890 { 891 name: "import.6", 892 pkg: "os", 893 in: `package main 894 895 // Comment 896 import "C" 897 898 import ( 899 "io" 900 "os" 901 "utf8" 902 ) 903 `, 904 out: `package main 905 906 // Comment 907 import "C" 908 909 import ( 910 "io" 911 "utf8" 912 ) 913 `, 914 }, 915 { 916 name: "import.7", 917 pkg: "io", 918 in: `package main 919 920 import ( 921 "io" // a 922 "os" // b 923 "utf8" // c 924 ) 925 `, 926 out: `package main 927 928 import ( 929 // a 930 "os" // b 931 "utf8" // c 932 ) 933 `, 934 }, 935 { 936 name: "import.8", 937 pkg: "os", 938 in: `package main 939 940 import ( 941 "io" // a 942 "os" // b 943 "utf8" // c 944 ) 945 `, 946 out: `package main 947 948 import ( 949 "io" // a 950 // b 951 "utf8" // c 952 ) 953 `, 954 }, 955 { 956 name: "import.9", 957 pkg: "utf8", 958 in: `package main 959 960 import ( 961 "io" // a 962 "os" // b 963 "utf8" // c 964 ) 965 `, 966 out: `package main 967 968 import ( 969 "io" // a 970 "os" // b 971 // c 972 ) 973 `, 974 }, 975 { 976 name: "import.10", 977 pkg: "io", 978 in: `package main 979 980 import ( 981 "io" 982 "os" 983 "utf8" 984 ) 985 `, 986 out: `package main 987 988 import ( 989 "os" 990 "utf8" 991 ) 992 `, 993 }, 994 { 995 name: "import.11", 996 pkg: "os", 997 in: `package main 998 999 import ( 1000 "io" 1001 "os" 1002 "utf8" 1003 ) 1004 `, 1005 out: `package main 1006 1007 import ( 1008 "io" 1009 "utf8" 1010 ) 1011 `, 1012 }, 1013 { 1014 name: "import.12", 1015 pkg: "utf8", 1016 in: `package main 1017 1018 import ( 1019 "io" 1020 "os" 1021 "utf8" 1022 ) 1023 `, 1024 out: `package main 1025 1026 import ( 1027 "io" 1028 "os" 1029 ) 1030 `, 1031 }, 1032 { 1033 name: "handle.raw.quote.imports", 1034 pkg: "os", 1035 in: "package main\n\nimport `os`", 1036 out: `package main 1037 `, 1038 }, 1039 { 1040 name: "import.13", 1041 pkg: "io", 1042 in: `package main 1043 1044 import ( 1045 "fmt" 1046 1047 "io" 1048 "os" 1049 "utf8" 1050 1051 "go/format" 1052 ) 1053 `, 1054 out: `package main 1055 1056 import ( 1057 "fmt" 1058 1059 "os" 1060 "utf8" 1061 1062 "go/format" 1063 ) 1064 `, 1065 }, 1066 { 1067 name: "import.14", 1068 pkg: "io", 1069 in: `package main 1070 1071 import ( 1072 "fmt" // a 1073 1074 "io" // b 1075 "os" // c 1076 "utf8" // d 1077 1078 "go/format" // e 1079 ) 1080 `, 1081 out: `package main 1082 1083 import ( 1084 "fmt" // a 1085 1086 // b 1087 "os" // c 1088 "utf8" // d 1089 1090 "go/format" // e 1091 ) 1092 `, 1093 }, 1094 { 1095 name: "import.15", 1096 pkg: "double", 1097 in: `package main 1098 1099 import ( 1100 "double" 1101 "double" 1102 ) 1103 `, 1104 out: `package main 1105 `, 1106 }, 1107 { 1108 name: "import.16", 1109 pkg: "bubble", 1110 in: `package main 1111 1112 import ( 1113 "toil" 1114 "bubble" 1115 "bubble" 1116 "trouble" 1117 ) 1118 `, 1119 out: `package main 1120 1121 import ( 1122 "toil" 1123 "trouble" 1124 ) 1125 `, 1126 }, 1127 { 1128 name: "import.17", 1129 pkg: "quad", 1130 in: `package main 1131 1132 import ( 1133 "quad" 1134 "quad" 1135 ) 1136 1137 import ( 1138 "quad" 1139 "quad" 1140 ) 1141 `, 1142 out: `package main 1143 `, 1144 }, 1145 { 1146 name: "import.18", 1147 renamedPkg: "x", 1148 pkg: "fmt", 1149 in: `package main 1150 1151 import ( 1152 "fmt" 1153 x "fmt" 1154 ) 1155 `, 1156 out: `package main 1157 1158 import ( 1159 "fmt" 1160 ) 1161 `, 1162 }, 1163 { 1164 name: "import.18", 1165 renamedPkg: "x", 1166 pkg: "fmt", 1167 in: `package main 1168 1169 import x "fmt" 1170 import y "fmt" 1171 `, 1172 out: `package main 1173 1174 import y "fmt" 1175 `, 1176 }, 1177 // Issue #15432, #18051 1178 { 1179 name: "import.19", 1180 pkg: "fmt", 1181 in: `package main 1182 1183 import ( 1184 "fmt" 1185 1186 // Some comment. 1187 "io" 1188 )`, 1189 out: `package main 1190 1191 import ( 1192 // Some comment. 1193 "io" 1194 ) 1195 `, 1196 }, 1197 { 1198 name: "import.20", 1199 pkg: "fmt", 1200 in: `package main 1201 1202 import ( 1203 "fmt" 1204 1205 // Some 1206 // comment. 1207 "io" 1208 )`, 1209 out: `package main 1210 1211 import ( 1212 // Some 1213 // comment. 1214 "io" 1215 ) 1216 `, 1217 }, 1218 { 1219 name: "import.21", 1220 pkg: "fmt", 1221 in: `package main 1222 1223 import ( 1224 "fmt" 1225 1226 /* 1227 Some 1228 comment. 1229 */ 1230 "io" 1231 )`, 1232 out: `package main 1233 1234 import ( 1235 /* 1236 Some 1237 comment. 1238 */ 1239 "io" 1240 ) 1241 `, 1242 }, 1243 { 1244 name: "import.22", 1245 pkg: "fmt", 1246 in: `package main 1247 1248 import ( 1249 /* Some */ 1250 // comment. 1251 "io" 1252 "fmt" 1253 )`, 1254 out: `package main 1255 1256 import ( 1257 /* Some */ 1258 // comment. 1259 "io" 1260 ) 1261 `, 1262 }, 1263 { 1264 name: "import.23", 1265 pkg: "fmt", 1266 in: `package main 1267 1268 import ( 1269 // comment 1 1270 "fmt" 1271 // comment 2 1272 "io" 1273 )`, 1274 out: `package main 1275 1276 import ( 1277 // comment 2 1278 "io" 1279 ) 1280 `, 1281 }, 1282 { 1283 name: "import.24", 1284 pkg: "fmt", 1285 in: `package main 1286 1287 import ( 1288 "fmt" // comment 1 1289 "io" // comment 2 1290 )`, 1291 out: `package main 1292 1293 import ( 1294 "io" // comment 2 1295 ) 1296 `, 1297 }, 1298 { 1299 name: "import.25", 1300 pkg: "fmt", 1301 in: `package main 1302 1303 import ( 1304 "fmt" 1305 /* comment */ "io" 1306 )`, 1307 out: `package main 1308 1309 import ( 1310 /* comment */ "io" 1311 ) 1312 `, 1313 }, 1314 { 1315 name: "import.26", 1316 pkg: "fmt", 1317 in: `package main 1318 1319 import ( 1320 "fmt" 1321 "io" /* comment */ 1322 )`, 1323 out: `package main 1324 1325 import ( 1326 "io" /* comment */ 1327 ) 1328 `, 1329 }, 1330 { 1331 name: "import.27", 1332 pkg: "fmt", 1333 in: `package main 1334 1335 import ( 1336 "fmt" /* comment */ 1337 "io" 1338 )`, 1339 out: `package main 1340 1341 import ( 1342 "io" 1343 ) 1344 `, 1345 }, 1346 { 1347 name: "import.28", 1348 pkg: "fmt", 1349 in: `package main 1350 1351 import ( 1352 /* comment */ "fmt" 1353 "io" 1354 )`, 1355 out: `package main 1356 1357 import ( 1358 "io" 1359 ) 1360 `, 1361 }, 1362 { 1363 name: "import.29", 1364 pkg: "fmt", 1365 in: `package main 1366 1367 // comment 1 1368 import ( 1369 "fmt" 1370 "io" // comment 2 1371 )`, 1372 out: `package main 1373 1374 // comment 1 1375 import ( 1376 "io" // comment 2 1377 ) 1378 `, 1379 }, 1380 { 1381 name: "import.30", 1382 pkg: "fmt", 1383 in: `package main 1384 1385 // comment 1 1386 import ( 1387 "fmt" // comment 2 1388 "io" 1389 )`, 1390 out: `package main 1391 1392 // comment 1 1393 import ( 1394 "io" 1395 ) 1396 `, 1397 }, 1398 { 1399 name: "import.31", 1400 pkg: "fmt", 1401 in: `package main 1402 1403 // comment 1 1404 import ( 1405 "fmt" 1406 /* comment 2 */ "io" 1407 )`, 1408 out: `package main 1409 1410 // comment 1 1411 import ( 1412 /* comment 2 */ "io" 1413 ) 1414 `, 1415 }, 1416 { 1417 name: "import.32", 1418 pkg: "fmt", 1419 renamedPkg: "f", 1420 in: `package main 1421 1422 // comment 1 1423 import ( 1424 f "fmt" 1425 /* comment 2 */ i "io" 1426 )`, 1427 out: `package main 1428 1429 // comment 1 1430 import ( 1431 /* comment 2 */ i "io" 1432 ) 1433 `, 1434 }, 1435 { 1436 name: "import.33", 1437 pkg: "fmt", 1438 renamedPkg: "f", 1439 in: `package main 1440 1441 // comment 1 1442 import ( 1443 /* comment 2 */ f "fmt" 1444 i "io" 1445 )`, 1446 out: `package main 1447 1448 // comment 1 1449 import ( 1450 i "io" 1451 ) 1452 `, 1453 }, 1454 { 1455 name: "import.34", 1456 pkg: "fmt", 1457 renamedPkg: "f", 1458 in: `package main 1459 1460 // comment 1 1461 import ( 1462 f "fmt" /* comment 2 */ 1463 i "io" 1464 )`, 1465 out: `package main 1466 1467 // comment 1 1468 import ( 1469 i "io" 1470 ) 1471 `, 1472 }, 1473 { 1474 name: "import.35", 1475 pkg: "fmt", 1476 in: `package main 1477 1478 // comment 1 1479 import ( 1480 "fmt" 1481 // comment 2 1482 "io" 1483 )`, 1484 out: `package main 1485 1486 // comment 1 1487 import ( 1488 // comment 2 1489 "io" 1490 ) 1491 `, 1492 }, 1493 { 1494 name: "import.36", 1495 pkg: "fmt", 1496 in: `package main 1497 1498 /* comment 1 */ 1499 import ( 1500 "fmt" 1501 /* comment 2 */ 1502 "io" 1503 )`, 1504 out: `package main 1505 1506 /* comment 1 */ 1507 import ( 1508 /* comment 2 */ 1509 "io" 1510 ) 1511 `, 1512 }, 1513 1514 // Issue 20229: MergeLine panic on weird input 1515 { 1516 name: "import.37", 1517 pkg: "io", 1518 in: `package main 1519 import("_" 1520 "io")`, 1521 out: `package main 1522 1523 import ( 1524 "_" 1525 ) 1526 `, 1527 }, 1528 1529 // Issue 28605: Delete specified import, even if that import path is imported under another name 1530 { 1531 name: "import.38", 1532 renamedPkg: "", 1533 pkg: "path", 1534 in: `package main 1535 1536 import ( 1537 "path" 1538 . "path" 1539 _ "path" 1540 pathpkg "path" 1541 ) 1542 `, 1543 out: `package main 1544 1545 import ( 1546 . "path" 1547 _ "path" 1548 pathpkg "path" 1549 ) 1550 `, 1551 }, 1552 { 1553 name: "import.39", 1554 renamedPkg: "pathpkg", 1555 pkg: "path", 1556 in: `package main 1557 1558 import ( 1559 "path" 1560 . "path" 1561 _ "path" 1562 pathpkg "path" 1563 ) 1564 `, 1565 out: `package main 1566 1567 import ( 1568 "path" 1569 . "path" 1570 _ "path" 1571 ) 1572 `, 1573 }, 1574 { 1575 name: "import.40", 1576 renamedPkg: "_", 1577 pkg: "path", 1578 in: `package main 1579 1580 import ( 1581 "path" 1582 . "path" 1583 _ "path" 1584 pathpkg "path" 1585 ) 1586 `, 1587 out: `package main 1588 1589 import ( 1590 "path" 1591 . "path" 1592 pathpkg "path" 1593 ) 1594 `, 1595 }, 1596 { 1597 name: "import.41", 1598 renamedPkg: ".", 1599 pkg: "path", 1600 in: `package main 1601 1602 import ( 1603 "path" 1604 . "path" 1605 _ "path" 1606 pathpkg "path" 1607 ) 1608 `, 1609 out: `package main 1610 1611 import ( 1612 "path" 1613 _ "path" 1614 pathpkg "path" 1615 ) 1616 `, 1617 }, 1618 1619 // Duplicate import declarations, all matching ones are deleted. 1620 { 1621 name: "import.42", 1622 renamedPkg: "f", 1623 pkg: "fmt", 1624 in: `package main 1625 1626 import "fmt" 1627 import "fmt" 1628 import f "fmt" 1629 import f "fmt" 1630 `, 1631 out: `package main 1632 1633 import "fmt" 1634 import "fmt" 1635 `, 1636 }, 1637 { 1638 name: "import.43", 1639 renamedPkg: "x", 1640 pkg: "fmt", 1641 in: `package main 1642 1643 import "fmt" 1644 import "fmt" 1645 import f "fmt" 1646 import f "fmt" 1647 `, 1648 out: `package main 1649 1650 import "fmt" 1651 import "fmt" 1652 import f "fmt" 1653 import f "fmt" 1654 `, 1655 unchanged: true, 1656 }, 1657 // this test panics without PositionFor in DeleteNamedImport 1658 { 1659 name: "import.44", 1660 pkg: "foo.com/other/v3", 1661 renamedPkg: "", 1662 in: `package main 1663 //line mah.go:600 1664 1665 import ( 1666 "foo.com/a.thing" 1667 "foo.com/surprise" 1668 "foo.com/v1" 1669 "foo.com/other/v2" 1670 "foo.com/other/v3" 1671 ) 1672 `, 1673 out: `package main 1674 1675 //line mah.go:600 1676 1677 import ( 1678 "foo.com/a.thing" 1679 "foo.com/other/v2" 1680 "foo.com/surprise" 1681 "foo.com/v1" 1682 ) 1683 `, 1684 }, 1685 } 1686 1687 func TestDeleteImport(t *testing.T) { 1688 for _, test := range deleteTests { 1689 file := parse(t, test.name, test.in) 1690 var before bytes.Buffer 1691 ast.Fprint(&before, fset, file, nil) 1692 deleted := DeleteNamedImport(fset, file, test.renamedPkg, test.pkg) 1693 if got := print(t, test.name, file); got != test.out { 1694 t.Errorf("first run: %s:\ngot: %s\nwant: %s", test.name, got, test.out) 1695 var after bytes.Buffer 1696 ast.Fprint(&after, fset, file, nil) 1697 t.Logf("AST before:\n%s\nAST after:\n%s\n", before.String(), after.String()) 1698 } 1699 if got, want := deleted, !test.unchanged; got != want { 1700 t.Errorf("first run: %s: deleted = %v, want %v", test.name, got, want) 1701 } 1702 1703 // DeleteNamedImport should be idempotent. Verify that by calling it again, 1704 // expecting no change to the AST, and the returned deleted value to always be false. 1705 deleted = DeleteNamedImport(fset, file, test.renamedPkg, test.pkg) 1706 if got := print(t, test.name, file); got != test.out { 1707 t.Errorf("second run: %s:\ngot: %s\nwant: %s", test.name, got, test.out) 1708 } 1709 if got, want := deleted, false; got != want { 1710 t.Errorf("second run: %s: deleted = %v, want %v", test.name, got, want) 1711 } 1712 } 1713 } 1714 1715 func TestDeleteImportAfterAddImport(t *testing.T) { 1716 file := parse(t, "test", `package main 1717 1718 import "os" 1719 `) 1720 if got, want := AddImport(fset, file, "fmt"), true; got != want { 1721 t.Errorf("AddImport: got: %v, want: %v", got, want) 1722 } 1723 if got, want := DeleteImport(fset, file, "fmt"), true; got != want { 1724 t.Errorf("DeleteImport: got: %v, want: %v", got, want) 1725 } 1726 } 1727 1728 type rewriteTest struct { 1729 name string 1730 srcPkg string 1731 dstPkg string 1732 in string 1733 out string 1734 } 1735 1736 var rewriteTests = []rewriteTest{ 1737 { 1738 name: "import.13", 1739 srcPkg: "utf8", 1740 dstPkg: "encoding/utf8", 1741 in: `package main 1742 1743 import ( 1744 "io" 1745 "os" 1746 "utf8" // thanks ken 1747 ) 1748 `, 1749 out: `package main 1750 1751 import ( 1752 "encoding/utf8" // thanks ken 1753 "io" 1754 "os" 1755 ) 1756 `, 1757 }, 1758 { 1759 name: "import.14", 1760 srcPkg: "asn1", 1761 dstPkg: "encoding/asn1", 1762 in: `package main 1763 1764 import ( 1765 "asn1" 1766 "crypto" 1767 "crypto/rsa" 1768 _ "crypto/sha1" 1769 "crypto/x509" 1770 "crypto/x509/pkix" 1771 "time" 1772 ) 1773 1774 var x = 1 1775 `, 1776 out: `package main 1777 1778 import ( 1779 "crypto" 1780 "crypto/rsa" 1781 _ "crypto/sha1" 1782 "crypto/x509" 1783 "crypto/x509/pkix" 1784 "encoding/asn1" 1785 "time" 1786 ) 1787 1788 var x = 1 1789 `, 1790 }, 1791 { 1792 name: "import.15", 1793 srcPkg: "url", 1794 dstPkg: "net/url", 1795 in: `package main 1796 1797 import ( 1798 "bufio" 1799 "net" 1800 "path" 1801 "url" 1802 ) 1803 1804 var x = 1 // comment on x, not on url 1805 `, 1806 out: `package main 1807 1808 import ( 1809 "bufio" 1810 "net" 1811 "net/url" 1812 "path" 1813 ) 1814 1815 var x = 1 // comment on x, not on url 1816 `, 1817 }, 1818 { 1819 name: "import.16", 1820 srcPkg: "http", 1821 dstPkg: "net/http", 1822 in: `package main 1823 1824 import ( 1825 "flag" 1826 "http" 1827 "log" 1828 "text/template" 1829 ) 1830 1831 var addr = flag.String("addr", ":1718", "http service address") // Q=17, R=18 1832 `, 1833 out: `package main 1834 1835 import ( 1836 "flag" 1837 "log" 1838 "net/http" 1839 "text/template" 1840 ) 1841 1842 var addr = flag.String("addr", ":1718", "http service address") // Q=17, R=18 1843 `, 1844 }, 1845 } 1846 1847 func TestRewriteImport(t *testing.T) { 1848 for _, test := range rewriteTests { 1849 file := parse(t, test.name, test.in) 1850 RewriteImport(fset, file, test.srcPkg, test.dstPkg) 1851 if got := print(t, test.name, file); got != test.out { 1852 t.Errorf("%s:\ngot: %s\nwant: %s", test.name, got, test.out) 1853 } 1854 } 1855 } 1856 1857 var importsTests = []struct { 1858 name string 1859 in string 1860 want [][]string 1861 }{ 1862 { 1863 name: "no packages", 1864 in: `package foo 1865 `, 1866 want: nil, 1867 }, 1868 { 1869 name: "one group", 1870 in: `package foo 1871 1872 import ( 1873 "fmt" 1874 "testing" 1875 ) 1876 `, 1877 want: [][]string{{"fmt", "testing"}}, 1878 }, 1879 { 1880 name: "four groups", 1881 in: `package foo 1882 1883 import "C" 1884 import ( 1885 "fmt" 1886 "testing" 1887 1888 "appengine" 1889 1890 "myproject/mylib1" 1891 "myproject/mylib2" 1892 ) 1893 `, 1894 want: [][]string{ 1895 {"C"}, 1896 {"fmt", "testing"}, 1897 {"appengine"}, 1898 {"myproject/mylib1", "myproject/mylib2"}, 1899 }, 1900 }, 1901 { 1902 name: "multiple factored groups", 1903 in: `package foo 1904 1905 import ( 1906 "fmt" 1907 "testing" 1908 1909 "appengine" 1910 ) 1911 import ( 1912 "reflect" 1913 1914 "bytes" 1915 ) 1916 `, 1917 want: [][]string{ 1918 {"fmt", "testing"}, 1919 {"appengine"}, 1920 {"reflect"}, 1921 {"bytes"}, 1922 }, 1923 }, 1924 } 1925 1926 func unquote(s string) string { 1927 res, err := strconv.Unquote(s) 1928 if err != nil { 1929 return "could_not_unquote" 1930 } 1931 return res 1932 } 1933 1934 func TestImports(t *testing.T) { 1935 fset := token.NewFileSet() 1936 for _, test := range importsTests { 1937 f, err := parser.ParseFile(fset, "test.go", test.in, 0) 1938 if err != nil { 1939 t.Errorf("%s: %v", test.name, err) 1940 continue 1941 } 1942 var got [][]string 1943 for _, group := range Imports(fset, f) { 1944 var b []string 1945 for _, spec := range group { 1946 b = append(b, unquote(spec.Path.Value)) 1947 } 1948 got = append(got, b) 1949 } 1950 if !reflect.DeepEqual(got, test.want) { 1951 t.Errorf("Imports(%s)=%v, want %v", test.name, got, test.want) 1952 } 1953 } 1954 } 1955 1956 var usesImportTests = []struct { 1957 name string 1958 path string 1959 in string 1960 want bool 1961 }{ 1962 { 1963 name: "no packages", 1964 path: "io", 1965 in: `package foo 1966 `, 1967 want: false, 1968 }, 1969 { 1970 name: "import.1", 1971 path: "io", 1972 in: `package foo 1973 1974 import "io" 1975 1976 var _ io.Writer 1977 `, 1978 want: true, 1979 }, 1980 { 1981 name: "import.2", 1982 path: "io", 1983 in: `package foo 1984 1985 import "io" 1986 `, 1987 want: false, 1988 }, 1989 { 1990 name: "import.3", 1991 path: "io", 1992 in: `package foo 1993 1994 import "io" 1995 1996 var io = 42 1997 `, 1998 want: false, 1999 }, 2000 { 2001 name: "import.4", 2002 path: "io", 2003 in: `package foo 2004 2005 import i "io" 2006 2007 var _ i.Writer 2008 `, 2009 want: true, 2010 }, 2011 { 2012 name: "import.5", 2013 path: "io", 2014 in: `package foo 2015 2016 import i "io" 2017 `, 2018 want: false, 2019 }, 2020 { 2021 name: "import.6", 2022 path: "io", 2023 in: `package foo 2024 2025 import i "io" 2026 2027 var i = 42 2028 var io = 42 2029 `, 2030 want: false, 2031 }, 2032 { 2033 name: "import.7", 2034 path: "encoding/json", 2035 in: `package foo 2036 2037 import "encoding/json" 2038 2039 var _ json.Encoder 2040 `, 2041 want: true, 2042 }, 2043 { 2044 name: "import.8", 2045 path: "encoding/json", 2046 in: `package foo 2047 2048 import "encoding/json" 2049 `, 2050 want: false, 2051 }, 2052 { 2053 name: "import.9", 2054 path: "encoding/json", 2055 in: `package foo 2056 2057 import "encoding/json" 2058 2059 var json = 42 2060 `, 2061 want: false, 2062 }, 2063 { 2064 name: "import.10", 2065 path: "encoding/json", 2066 in: `package foo 2067 2068 import j "encoding/json" 2069 2070 var _ j.Encoder 2071 `, 2072 want: true, 2073 }, 2074 { 2075 name: "import.11", 2076 path: "encoding/json", 2077 in: `package foo 2078 2079 import j "encoding/json" 2080 `, 2081 want: false, 2082 }, 2083 { 2084 name: "import.12", 2085 path: "encoding/json", 2086 in: `package foo 2087 2088 import j "encoding/json" 2089 2090 var j = 42 2091 var json = 42 2092 `, 2093 want: false, 2094 }, 2095 { 2096 name: "import.13", 2097 path: "io", 2098 in: `package foo 2099 2100 import _ "io" 2101 `, 2102 want: true, 2103 }, 2104 { 2105 name: "import.14", 2106 path: "io", 2107 in: `package foo 2108 2109 import . "io" 2110 `, 2111 want: true, 2112 }, 2113 } 2114 2115 func TestUsesImport(t *testing.T) { 2116 fset := token.NewFileSet() 2117 for _, test := range usesImportTests { 2118 f, err := parser.ParseFile(fset, "test.go", test.in, 0) 2119 if err != nil { 2120 t.Errorf("%s: %v", test.name, err) 2121 continue 2122 } 2123 got := UsesImport(f, test.path) 2124 if got != test.want { 2125 t.Errorf("UsesImport(%s)=%v, want %v", test.name, got, test.want) 2126 } 2127 } 2128 }