Giant blob of minor changes
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.0.0-20201105173854-bc9fc8d8c4bc / go / ast / astutil / imports_test.go
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, "golang.org/x/tools/go/ast/astutil")
846         AddImport(fset, file, "os")
847         want := `package main
848
849 import (
850         "golang.org/x/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 }
1658
1659 func TestDeleteImport(t *testing.T) {
1660         for _, test := range deleteTests {
1661                 file := parse(t, test.name, test.in)
1662                 var before bytes.Buffer
1663                 ast.Fprint(&before, fset, file, nil)
1664                 deleted := DeleteNamedImport(fset, file, test.renamedPkg, test.pkg)
1665                 if got := print(t, test.name, file); got != test.out {
1666                         t.Errorf("first run: %s:\ngot: %s\nwant: %s", test.name, got, test.out)
1667                         var after bytes.Buffer
1668                         ast.Fprint(&after, fset, file, nil)
1669                         t.Logf("AST before:\n%s\nAST after:\n%s\n", before.String(), after.String())
1670                 }
1671                 if got, want := deleted, !test.unchanged; got != want {
1672                         t.Errorf("first run: %s: deleted = %v, want %v", test.name, got, want)
1673                 }
1674
1675                 // DeleteNamedImport should be idempotent. Verify that by calling it again,
1676                 // expecting no change to the AST, and the returned deleted value to always be false.
1677                 deleted = DeleteNamedImport(fset, file, test.renamedPkg, test.pkg)
1678                 if got := print(t, test.name, file); got != test.out {
1679                         t.Errorf("second run: %s:\ngot: %s\nwant: %s", test.name, got, test.out)
1680                 }
1681                 if got, want := deleted, false; got != want {
1682                         t.Errorf("second run: %s: deleted = %v, want %v", test.name, got, want)
1683                 }
1684         }
1685 }
1686
1687 func TestDeleteImportAfterAddImport(t *testing.T) {
1688         file := parse(t, "test", `package main
1689
1690 import "os"
1691 `)
1692         if got, want := AddImport(fset, file, "fmt"), true; got != want {
1693                 t.Errorf("AddImport: got: %v, want: %v", got, want)
1694         }
1695         if got, want := DeleteImport(fset, file, "fmt"), true; got != want {
1696                 t.Errorf("DeleteImport: got: %v, want: %v", got, want)
1697         }
1698 }
1699
1700 type rewriteTest struct {
1701         name   string
1702         srcPkg string
1703         dstPkg string
1704         in     string
1705         out    string
1706 }
1707
1708 var rewriteTests = []rewriteTest{
1709         {
1710                 name:   "import.13",
1711                 srcPkg: "utf8",
1712                 dstPkg: "encoding/utf8",
1713                 in: `package main
1714
1715 import (
1716         "io"
1717         "os"
1718         "utf8" // thanks ken
1719 )
1720 `,
1721                 out: `package main
1722
1723 import (
1724         "encoding/utf8" // thanks ken
1725         "io"
1726         "os"
1727 )
1728 `,
1729         },
1730         {
1731                 name:   "import.14",
1732                 srcPkg: "asn1",
1733                 dstPkg: "encoding/asn1",
1734                 in: `package main
1735
1736 import (
1737         "asn1"
1738         "crypto"
1739         "crypto/rsa"
1740         _ "crypto/sha1"
1741         "crypto/x509"
1742         "crypto/x509/pkix"
1743         "time"
1744 )
1745
1746 var x = 1
1747 `,
1748                 out: `package main
1749
1750 import (
1751         "crypto"
1752         "crypto/rsa"
1753         _ "crypto/sha1"
1754         "crypto/x509"
1755         "crypto/x509/pkix"
1756         "encoding/asn1"
1757         "time"
1758 )
1759
1760 var x = 1
1761 `,
1762         },
1763         {
1764                 name:   "import.15",
1765                 srcPkg: "url",
1766                 dstPkg: "net/url",
1767                 in: `package main
1768
1769 import (
1770         "bufio"
1771         "net"
1772         "path"
1773         "url"
1774 )
1775
1776 var x = 1 // comment on x, not on url
1777 `,
1778                 out: `package main
1779
1780 import (
1781         "bufio"
1782         "net"
1783         "net/url"
1784         "path"
1785 )
1786
1787 var x = 1 // comment on x, not on url
1788 `,
1789         },
1790         {
1791                 name:   "import.16",
1792                 srcPkg: "http",
1793                 dstPkg: "net/http",
1794                 in: `package main
1795
1796 import (
1797         "flag"
1798         "http"
1799         "log"
1800         "text/template"
1801 )
1802
1803 var addr = flag.String("addr", ":1718", "http service address") // Q=17, R=18
1804 `,
1805                 out: `package main
1806
1807 import (
1808         "flag"
1809         "log"
1810         "net/http"
1811         "text/template"
1812 )
1813
1814 var addr = flag.String("addr", ":1718", "http service address") // Q=17, R=18
1815 `,
1816         },
1817 }
1818
1819 func TestRewriteImport(t *testing.T) {
1820         for _, test := range rewriteTests {
1821                 file := parse(t, test.name, test.in)
1822                 RewriteImport(fset, file, test.srcPkg, test.dstPkg)
1823                 if got := print(t, test.name, file); got != test.out {
1824                         t.Errorf("%s:\ngot: %s\nwant: %s", test.name, got, test.out)
1825                 }
1826         }
1827 }
1828
1829 var importsTests = []struct {
1830         name string
1831         in   string
1832         want [][]string
1833 }{
1834         {
1835                 name: "no packages",
1836                 in: `package foo
1837 `,
1838                 want: nil,
1839         },
1840         {
1841                 name: "one group",
1842                 in: `package foo
1843
1844 import (
1845         "fmt"
1846         "testing"
1847 )
1848 `,
1849                 want: [][]string{{"fmt", "testing"}},
1850         },
1851         {
1852                 name: "four groups",
1853                 in: `package foo
1854
1855 import "C"
1856 import (
1857         "fmt"
1858         "testing"
1859
1860         "appengine"
1861
1862         "myproject/mylib1"
1863         "myproject/mylib2"
1864 )
1865 `,
1866                 want: [][]string{
1867                         {"C"},
1868                         {"fmt", "testing"},
1869                         {"appengine"},
1870                         {"myproject/mylib1", "myproject/mylib2"},
1871                 },
1872         },
1873         {
1874                 name: "multiple factored groups",
1875                 in: `package foo
1876
1877 import (
1878         "fmt"
1879         "testing"
1880
1881         "appengine"
1882 )
1883 import (
1884         "reflect"
1885
1886         "bytes"
1887 )
1888 `,
1889                 want: [][]string{
1890                         {"fmt", "testing"},
1891                         {"appengine"},
1892                         {"reflect"},
1893                         {"bytes"},
1894                 },
1895         },
1896 }
1897
1898 func unquote(s string) string {
1899         res, err := strconv.Unquote(s)
1900         if err != nil {
1901                 return "could_not_unquote"
1902         }
1903         return res
1904 }
1905
1906 func TestImports(t *testing.T) {
1907         fset := token.NewFileSet()
1908         for _, test := range importsTests {
1909                 f, err := parser.ParseFile(fset, "test.go", test.in, 0)
1910                 if err != nil {
1911                         t.Errorf("%s: %v", test.name, err)
1912                         continue
1913                 }
1914                 var got [][]string
1915                 for _, group := range Imports(fset, f) {
1916                         var b []string
1917                         for _, spec := range group {
1918                                 b = append(b, unquote(spec.Path.Value))
1919                         }
1920                         got = append(got, b)
1921                 }
1922                 if !reflect.DeepEqual(got, test.want) {
1923                         t.Errorf("Imports(%s)=%v, want %v", test.name, got, test.want)
1924                 }
1925         }
1926 }
1927
1928 var usesImportTests = []struct {
1929         name string
1930         path string
1931         in   string
1932         want bool
1933 }{
1934         {
1935                 name: "no packages",
1936                 path: "io",
1937                 in: `package foo
1938 `,
1939                 want: false,
1940         },
1941         {
1942                 name: "import.1",
1943                 path: "io",
1944                 in: `package foo
1945
1946 import "io"
1947
1948 var _ io.Writer
1949 `,
1950                 want: true,
1951         },
1952         {
1953                 name: "import.2",
1954                 path: "io",
1955                 in: `package foo
1956
1957 import "io"
1958 `,
1959                 want: false,
1960         },
1961         {
1962                 name: "import.3",
1963                 path: "io",
1964                 in: `package foo
1965
1966 import "io"
1967
1968 var io = 42
1969 `,
1970                 want: false,
1971         },
1972         {
1973                 name: "import.4",
1974                 path: "io",
1975                 in: `package foo
1976
1977 import i "io"
1978
1979 var _ i.Writer
1980 `,
1981                 want: true,
1982         },
1983         {
1984                 name: "import.5",
1985                 path: "io",
1986                 in: `package foo
1987
1988 import i "io"
1989 `,
1990                 want: false,
1991         },
1992         {
1993                 name: "import.6",
1994                 path: "io",
1995                 in: `package foo
1996
1997 import i "io"
1998
1999 var i = 42
2000 var io = 42
2001 `,
2002                 want: false,
2003         },
2004         {
2005                 name: "import.7",
2006                 path: "encoding/json",
2007                 in: `package foo
2008
2009 import "encoding/json"
2010
2011 var _ json.Encoder
2012 `,
2013                 want: true,
2014         },
2015         {
2016                 name: "import.8",
2017                 path: "encoding/json",
2018                 in: `package foo
2019
2020 import "encoding/json"
2021 `,
2022                 want: false,
2023         },
2024         {
2025                 name: "import.9",
2026                 path: "encoding/json",
2027                 in: `package foo
2028
2029 import "encoding/json"
2030
2031 var json = 42
2032 `,
2033                 want: false,
2034         },
2035         {
2036                 name: "import.10",
2037                 path: "encoding/json",
2038                 in: `package foo
2039
2040 import j "encoding/json"
2041
2042 var _ j.Encoder
2043 `,
2044                 want: true,
2045         },
2046         {
2047                 name: "import.11",
2048                 path: "encoding/json",
2049                 in: `package foo
2050
2051 import j "encoding/json"
2052 `,
2053                 want: false,
2054         },
2055         {
2056                 name: "import.12",
2057                 path: "encoding/json",
2058                 in: `package foo
2059
2060 import j "encoding/json"
2061
2062 var j = 42
2063 var json = 42
2064 `,
2065                 want: false,
2066         },
2067         {
2068                 name: "import.13",
2069                 path: "io",
2070                 in: `package foo
2071
2072 import _ "io"
2073 `,
2074                 want: true,
2075         },
2076         {
2077                 name: "import.14",
2078                 path: "io",
2079                 in: `package foo
2080
2081 import . "io"
2082 `,
2083                 want: true,
2084         },
2085 }
2086
2087 func TestUsesImport(t *testing.T) {
2088         fset := token.NewFileSet()
2089         for _, test := range usesImportTests {
2090                 f, err := parser.ParseFile(fset, "test.go", test.in, 0)
2091                 if err != nil {
2092                         t.Errorf("%s: %v", test.name, err)
2093                         continue
2094                 }
2095                 got := UsesImport(f, test.path)
2096                 if got != test.want {
2097                         t.Errorf("UsesImport(%s)=%v, want %v", test.name, got, test.want)
2098                 }
2099         }
2100 }