1
2
3
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
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
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
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
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
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
791
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
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
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
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
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
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
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 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
1704
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 }
2129
View as plain text