Giant blob of minor changes
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.0.0-20201028153306-37f0764111ff / internal / imports / fix_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 imports
6
7 import (
8         "context"
9         "flag"
10         "fmt"
11         "go/build"
12         "io/ioutil"
13         "log"
14         "path/filepath"
15         "reflect"
16         "runtime"
17         "sort"
18         "strings"
19         "sync"
20         "testing"
21
22         "golang.org/x/tools/go/packages/packagestest"
23         "golang.org/x/tools/internal/gocommand"
24 )
25
26 var testDebug = flag.Bool("debug", false, "enable debug output")
27
28 var tests = []struct {
29         name       string
30         formatOnly bool
31         in, out    string
32 }{
33         // Adding an import to an existing parenthesized import
34         {
35                 name: "factored_imports_add",
36                 in: `package foo
37 import (
38   "fmt"
39 )
40 func bar() {
41 var b bytes.Buffer
42 fmt.Println(b.String())
43 }
44 `,
45                 out: `package foo
46
47 import (
48         "bytes"
49         "fmt"
50 )
51
52 func bar() {
53         var b bytes.Buffer
54         fmt.Println(b.String())
55 }
56 `,
57         },
58
59         // Adding an import to an existing parenthesized import,
60         // verifying it goes into the first section.
61         {
62                 name: "factored_imports_add_first_sec",
63                 in: `package foo
64 import (
65   "fmt"
66
67   "github.com/golang/snappy"
68 )
69 func bar() {
70 var b bytes.Buffer
71 _ = snappy.ErrCorrupt
72 fmt.Println(b.String())
73 }
74 `,
75                 out: `package foo
76
77 import (
78         "bytes"
79         "fmt"
80
81         "github.com/golang/snappy"
82 )
83
84 func bar() {
85         var b bytes.Buffer
86         _ = snappy.ErrCorrupt
87         fmt.Println(b.String())
88 }
89 `,
90         },
91
92         // Adding an import to an existing parenthesized import,
93         // verifying it goes into the first section. (test 2)
94         {
95                 name: "factored_imports_add_first_sec_2",
96                 in: `package foo
97 import (
98   "fmt"
99
100   "github.com/golang/snappy"
101 )
102 func bar() {
103 _ = math.NaN
104 _ = fmt.Sprintf
105 _ = snappy.ErrCorrupt
106 }
107 `,
108                 out: `package foo
109
110 import (
111         "fmt"
112         "math"
113
114         "github.com/golang/snappy"
115 )
116
117 func bar() {
118         _ = math.NaN
119         _ = fmt.Sprintf
120         _ = snappy.ErrCorrupt
121 }
122 `,
123         },
124
125         // Adding a new import line, without parens
126         {
127                 name: "add_import_section",
128                 in: `package foo
129 func bar() {
130 var b bytes.Buffer
131 }
132 `,
133                 out: `package foo
134
135 import "bytes"
136
137 func bar() {
138         var b bytes.Buffer
139 }
140 `,
141         },
142
143         // Adding two new imports, which should make a parenthesized import decl.
144         {
145                 name: "add_import_paren_section",
146                 in: `package foo
147 func bar() {
148 _, _ := bytes.Buffer, zip.NewReader
149 }
150 `,
151                 out: `package foo
152
153 import (
154         "archive/zip"
155         "bytes"
156 )
157
158 func bar() {
159         _, _ := bytes.Buffer, zip.NewReader
160 }
161 `,
162         },
163
164         // Make sure we don't add things twice
165         {
166                 name: "no_double_add",
167                 in: `package foo
168 func bar() {
169 _, _ := bytes.Buffer, bytes.NewReader
170 }
171 `,
172                 out: `package foo
173
174 import "bytes"
175
176 func bar() {
177         _, _ := bytes.Buffer, bytes.NewReader
178 }
179 `,
180         },
181
182         // Make sure we don't add packages that don't have the right exports
183         {
184                 name: "no_mismatched_add",
185                 in: `package foo
186
187 func bar() {
188         _ := bytes.NonexistentSymbol
189 }
190 `,
191                 out: `package foo
192
193 func bar() {
194         _ := bytes.NonexistentSymbol
195 }
196 `,
197         },
198
199         // Remove unused imports, 1 of a factored block
200         {
201                 name: "remove_unused_1_of_2",
202                 in: `package foo
203 import (
204 "bytes"
205 "fmt"
206 )
207
208 func bar() {
209 _, _ := bytes.Buffer, bytes.NewReader
210 }
211 `,
212                 out: `package foo
213
214 import (
215         "bytes"
216 )
217
218 func bar() {
219         _, _ := bytes.Buffer, bytes.NewReader
220 }
221 `,
222         },
223
224         // Remove unused imports, 2 of 2
225         {
226                 name: "remove_unused_2_of_2",
227                 in: `package foo
228 import (
229 "bytes"
230 "fmt"
231 )
232
233 func bar() {
234 }
235 `,
236                 out: `package foo
237
238 func bar() {
239 }
240 `,
241         },
242
243         // Remove unused imports, 1 of 1
244         {
245                 name: "remove_unused_1_of_1",
246                 in: `package foo
247
248 import "fmt"
249
250 func bar() {
251 }
252 `,
253                 out: `package foo
254
255 func bar() {
256 }
257 `,
258         },
259
260         // Don't remove empty imports.
261         {
262                 name: "dont_remove_empty_imports",
263                 in: `package foo
264 import (
265 _ "image/png"
266 _ "image/jpeg"
267 )
268 `,
269                 out: `package foo
270
271 import (
272         _ "image/jpeg"
273         _ "image/png"
274 )
275 `,
276         },
277
278         // Don't remove dot imports.
279         {
280                 name: "dont_remove_dot_imports",
281                 in: `package foo
282 import (
283 . "foo"
284 . "bar"
285 )
286 `,
287                 out: `package foo
288
289 import (
290         . "bar"
291         . "foo"
292 )
293 `,
294         },
295
296         // Skip refs the parser can resolve.
297         {
298                 name: "skip_resolved_refs",
299                 in: `package foo
300
301 func f() {
302         type t struct{ Println func(string) }
303         fmt := t{Println: func(string) {}}
304         fmt.Println("foo")
305 }
306 `,
307                 out: `package foo
308
309 func f() {
310         type t struct{ Println func(string) }
311         fmt := t{Println: func(string) {}}
312         fmt.Println("foo")
313 }
314 `,
315         },
316
317         // Do not add a package we already have a resolution for.
318         {
319                 name: "skip_template",
320                 in: `package foo
321
322 import "html/template"
323
324 func f() { t = template.New("sometemplate") }
325 `,
326                 out: `package foo
327
328 import "html/template"
329
330 func f() { t = template.New("sometemplate") }
331 `,
332         },
333
334         // Don't touch cgo
335         {
336                 name: "cgo",
337                 in: `package foo
338
339 /*
340 #include <foo.h>
341 */
342 import "C"
343 `,
344                 out: `package foo
345
346 /*
347 #include <foo.h>
348 */
349 import "C"
350 `,
351         },
352
353         // Put some things in their own section
354         {
355                 name: "make_sections",
356                 in: `package foo
357
358 import (
359 "os"
360 )
361
362 func foo () {
363 _, _ = os.Args, fmt.Println
364 _, _ = snappy.ErrCorrupt, p.P
365 }
366 `,
367                 out: `package foo
368
369 import (
370         "fmt"
371         "os"
372
373         "github.com/golang/snappy"
374         "rsc.io/p"
375 )
376
377 func foo() {
378         _, _ = os.Args, fmt.Println
379         _, _ = snappy.ErrCorrupt, p.P
380 }
381 `,
382         },
383         // Merge import blocks, even when no additions are required.
384         {
385                 name: "merge_import_blocks_no_fix",
386                 in: `package foo
387
388 import (
389         "fmt"
390 )
391 import "os"
392
393 import (
394         "rsc.io/p"
395 )
396
397 var _, _ = os.Args, fmt.Println
398 var _, _ = snappy.ErrCorrupt, p.P
399 `,
400                 out: `package foo
401
402 import (
403         "fmt"
404         "os"
405
406         "github.com/golang/snappy"
407         "rsc.io/p"
408 )
409
410 var _, _ = os.Args, fmt.Println
411 var _, _ = snappy.ErrCorrupt, p.P
412 `,
413         },
414         // Delete existing empty import block
415         {
416                 name: "delete_empty_import_block",
417                 in: `package foo
418
419 import ()
420 `,
421                 out: `package foo
422 `,
423         },
424
425         // Use existing empty import block
426         {
427                 name: "use_empty_import_block",
428                 in: `package foo
429
430 import ()
431
432 func f() {
433         _ = fmt.Println
434 }
435 `,
436                 out: `package foo
437
438 import "fmt"
439
440 func f() {
441         _ = fmt.Println
442 }
443 `,
444         },
445
446         // Blank line before adding new section.
447         {
448                 name: "blank_line_before_new_group",
449                 in: `package foo
450
451 import (
452         "fmt"
453         "net"
454 )
455
456 func f() {
457         _ = net.Dial
458         _ = fmt.Printf
459         _ = snappy.ErrCorrupt
460 }
461 `,
462                 out: `package foo
463
464 import (
465         "fmt"
466         "net"
467
468         "github.com/golang/snappy"
469 )
470
471 func f() {
472         _ = net.Dial
473         _ = fmt.Printf
474         _ = snappy.ErrCorrupt
475 }
476 `,
477         },
478
479         // Blank line between standard library and third-party stuff.
480         {
481                 name: "blank_line_separating_std_and_third_party",
482                 in: `package foo
483
484 import (
485         "github.com/golang/snappy"
486         "fmt"
487         "net"
488 )
489
490 func f() {
491         _ = net.Dial
492         _ = fmt.Printf
493         _ = snappy.Foo
494 }
495 `,
496                 out: `package foo
497
498 import (
499         "fmt"
500         "net"
501
502         "github.com/golang/snappy"
503 )
504
505 func f() {
506         _ = net.Dial
507         _ = fmt.Printf
508         _ = snappy.Foo
509 }
510 `,
511         },
512
513         // golang.org/issue/6884
514         {
515                 name: "new_imports_before_comment",
516                 in: `package main
517
518 // A comment
519 func main() {
520         fmt.Println("Hello, world")
521 }
522 `,
523                 out: `package main
524
525 import "fmt"
526
527 // A comment
528 func main() {
529         fmt.Println("Hello, world")
530 }
531 `,
532         },
533
534         // golang.org/issue/7132
535         {
536                 name: "new_section_for_dotless_import",
537                 in: `package main
538
539 import (
540 "fmt"
541
542 "gu"
543 "manypackages.com/packagea"
544 )
545
546 var (
547 a = packagea.A
548 b = gu.A
549 c = fmt.Printf
550 )
551 `,
552                 out: `package main
553
554 import (
555         "fmt"
556
557         "gu"
558
559         "manypackages.com/packagea"
560 )
561
562 var (
563         a = packagea.A
564         b = gu.A
565         c = fmt.Printf
566 )
567 `,
568         },
569
570         {
571                 name: "fragment_with_main",
572                 in:   `func main(){fmt.Println("Hello, world")}`,
573                 out: `package main
574
575 import "fmt"
576
577 func main() { fmt.Println("Hello, world") }
578 `,
579         },
580
581         {
582                 name: "fragment_without_main",
583                 in:   `func notmain(){fmt.Println("Hello, world")}`,
584                 out: `import "fmt"
585
586 func notmain() { fmt.Println("Hello, world") }`,
587         },
588
589         // Remove first import within in a 2nd/3rd/4th/etc. section.
590         // golang.org/issue/7679
591         {
592                 name: "remove_first_import_in_section",
593                 in: `package main
594
595 import (
596         "fmt"
597
598         "manypackages.com/packagea"
599         "manypackages.com/packageb"
600 )
601
602 func main() {
603         var _ = fmt.Println
604         //var _ = packagea.A
605         var _ = packageb.B
606 }
607 `,
608                 out: `package main
609
610 import (
611         "fmt"
612
613         "manypackages.com/packageb"
614 )
615
616 func main() {
617         var _ = fmt.Println
618         //var _ = packagea.A
619         var _ = packageb.B
620 }
621 `,
622         },
623
624         // Blank line can be added before all types of import declarations.
625         // golang.org/issue/7866
626         {
627                 name: "new_section_for_all_kinds_of_imports",
628                 in: `package main
629
630 import (
631         "fmt"
632         renamed_packagea "manypackages.com/packagea"
633
634         . "manypackages.com/packageb"
635         "io"
636
637         _ "manypackages.com/packagec"
638         "strings"
639 )
640
641 var _, _, _, _, _ = fmt.Errorf, io.Copy, strings.Contains, renamed_packagea.A, B
642 `,
643                 out: `package main
644
645 import (
646         "fmt"
647
648         renamed_packagea "manypackages.com/packagea"
649
650         "io"
651
652         . "manypackages.com/packageb"
653
654         "strings"
655
656         _ "manypackages.com/packagec"
657 )
658
659 var _, _, _, _, _ = fmt.Errorf, io.Copy, strings.Contains, renamed_packagea.A, B
660 `,
661         },
662
663         // Non-idempotent comment formatting
664         // golang.org/issue/8035
665         {
666                 name: "comments_formatted",
667                 in: `package main
668
669 import (
670         "fmt"                     // A
671         "go/ast"                  // B
672         _ "manypackages.com/packagec"    // C
673 )
674
675 func main() { _, _ = fmt.Print, ast.Walk }
676 `,
677                 out: `package main
678
679 import (
680         "fmt"    // A
681         "go/ast" // B
682
683         _ "manypackages.com/packagec" // C
684 )
685
686 func main() { _, _ = fmt.Print, ast.Walk }
687 `,
688         },
689
690         // Failure to delete all duplicate imports
691         // golang.org/issue/8459
692         {
693                 name: "remove_duplicates",
694                 in: `package main
695
696 import (
697         "fmt"
698         "log"
699         "log"
700         "math"
701 )
702
703 func main() { fmt.Println("pi:", math.Pi) }
704 `,
705                 out: `package main
706
707 import (
708         "fmt"
709         "math"
710 )
711
712 func main() { fmt.Println("pi:", math.Pi) }
713 `,
714         },
715
716         // Too aggressive prefix matching
717         // golang.org/issue/9961
718         {
719                 name: "no_extra_groups",
720                 in: `package p
721
722 import (
723         "zip"
724
725         "rsc.io/p"
726 )
727
728 var (
729         _ = fmt.Print
730         _ = zip.Store
731         _ p.P
732         _ = regexp.Compile
733 )
734 `,
735                 out: `package p
736
737 import (
738         "fmt"
739         "regexp"
740         "zip"
741
742         "rsc.io/p"
743 )
744
745 var (
746         _ = fmt.Print
747         _ = zip.Store
748         _ p.P
749         _ = regexp.Compile
750 )
751 `,
752         },
753
754         // Unused named import is mistaken for unnamed import
755         // golang.org/issue/8149
756         {
757                 name: "named_import_doesnt_provide_package_name",
758                 in: `package main
759
760 import foo "fmt"
761
762 func main() { fmt.Println() }
763 `,
764                 out: `package main
765
766 import "fmt"
767
768 func main() { fmt.Println() }
769 `,
770         },
771
772         // Unused named import is mistaken for unnamed import
773         // golang.org/issue/8149
774         {
775                 name: "unused_named_import_removed",
776                 in: `package main
777
778 import (
779         "fmt"
780         x "fmt"
781 )
782
783 func main() { fmt.Println() }
784 `,
785                 out: `package main
786
787 import (
788         "fmt"
789 )
790
791 func main() { fmt.Println() }
792 `,
793         },
794
795         {
796                 name: "ignore_unexported_identifier",
797                 in: `package main
798 var _ = fmt.unexported`,
799                 out: `package main
800
801 var _ = fmt.unexported
802 `,
803         },
804
805         // FormatOnly
806         {
807                 name:       "formatonly_works",
808                 formatOnly: true,
809                 in: `package main
810
811 import (
812 "fmt"
813 "manypackages.com/packagea"
814 )
815
816 func main() {}
817 `,
818                 out: `package main
819
820 import (
821         "fmt"
822
823         "manypackages.com/packagea"
824 )
825
826 func main() {}
827 `,
828         },
829
830         {
831                 name: "preserve_import_group",
832                 in: `package p
833
834 import (
835         "bytes"
836         "fmt"
837 )
838
839 var _ = fmt.Sprintf
840 `,
841                 out: `package p
842
843 import (
844         "fmt"
845 )
846
847 var _ = fmt.Sprintf
848 `,
849         },
850         {
851                 name: "import_grouping_not_path_dependent_no_groups",
852                 in: `package main
853
854 import (
855         "time"
856 )
857
858 func main() {
859         _ = snappy.ErrCorrupt
860         _ = p.P
861         _ = time.Parse
862 }
863 `,
864                 out: `package main
865
866 import (
867         "time"
868
869         "github.com/golang/snappy"
870         "rsc.io/p"
871 )
872
873 func main() {
874         _ = snappy.ErrCorrupt
875         _ = p.P
876         _ = time.Parse
877 }
878 `,
879         },
880
881         {
882                 name: "import_grouping_not_path_dependent_existing_group",
883                 in: `package main
884
885 import (
886         "time"
887
888         "github.com/golang/snappy"
889 )
890
891 func main() {
892         _ = snappy.ErrCorrupt
893         _ = p.P
894         _ = time.Parse
895 }
896 `,
897                 out: `package main
898
899 import (
900         "time"
901
902         "github.com/golang/snappy"
903         "rsc.io/p"
904 )
905
906 func main() {
907         _ = snappy.ErrCorrupt
908         _ = p.P
909         _ = time.Parse
910 }
911 `,
912         },
913
914         // golang.org/issue/12097
915         {
916                 name: "package_statement_insertion_preserves_comments",
917                 in: `// a
918 // b
919 // c
920
921 func main() {
922     _ = fmt.Println
923 }`,
924                 out: `package main
925
926 import "fmt"
927
928 // a
929 // b
930 // c
931
932 func main() {
933         _ = fmt.Println
934 }
935 `,
936         },
937
938         {
939                 name: "import_comment_stays_on_import",
940                 in: `package main
941
942 import (
943         "math" // fun
944 )
945
946 func main() {
947         x := math.MaxInt64
948         fmt.Println(strings.Join(",", []string{"hi"}), x)
949 }`,
950                 out: `package main
951
952 import (
953         "fmt"
954         "math" // fun
955         "strings"
956 )
957
958 func main() {
959         x := math.MaxInt64
960         fmt.Println(strings.Join(",", []string{"hi"}), x)
961 }
962 `,
963         },
964
965         {
966                 name: "no_blank_after_comment",
967                 in: `package main
968
969 import (
970         _ "io"
971         _ "net/http"
972         _ "net/http/pprof" // install the pprof http handlers
973         _ "strings"
974 )
975
976 func main() {
977 }
978 `,
979                 out: `package main
980
981 import (
982         _ "io"
983         _ "net/http"
984         _ "net/http/pprof" // install the pprof http handlers
985         _ "strings"
986 )
987
988 func main() {
989 }
990 `,
991         },
992
993         {
994                 name: "no_blank_after_comment_reordered",
995                 in: `package main
996
997 import (
998         _ "io"
999         _ "net/http/pprof" // install the pprof http handlers
1000         _ "net/http"
1001         _ "strings"
1002 )
1003
1004 func main() {
1005 }
1006 `,
1007                 out: `package main
1008
1009 import (
1010         _ "io"
1011         _ "net/http"
1012         _ "net/http/pprof" // install the pprof http handlers
1013         _ "strings"
1014 )
1015
1016 func main() {
1017 }
1018 `,
1019         },
1020
1021         {
1022                 name: "no_blank_after_comment_unnamed",
1023                 in: `package main
1024
1025 import (
1026         "encoding/json"
1027         "io"
1028         "net/http"
1029         _ "net/http/pprof" // install the pprof http handlers
1030         "strings"
1031
1032         "manypackages.com/packagea"
1033 )
1034
1035 func main() {
1036         _ = strings.ToUpper("hello")
1037         _ = io.EOF
1038         var (
1039                 _ json.Number
1040                 _ *http.Request
1041                 _ packagea.A
1042         )
1043 }
1044 `,
1045                 out: `package main
1046
1047 import (
1048         "encoding/json"
1049         "io"
1050         "net/http"
1051         _ "net/http/pprof" // install the pprof http handlers
1052         "strings"
1053
1054         "manypackages.com/packagea"
1055 )
1056
1057 func main() {
1058         _ = strings.ToUpper("hello")
1059         _ = io.EOF
1060         var (
1061                 _ json.Number
1062                 _ *http.Request
1063                 _ packagea.A
1064         )
1065 }
1066 `,
1067         },
1068
1069         {
1070                 name: "blank_after_package_statement_with_comment",
1071                 in: `package p // comment
1072
1073 import "math"
1074
1075 var _ = fmt.Printf
1076 `,
1077                 out: `package p // comment
1078
1079 import "fmt"
1080
1081 var _ = fmt.Printf
1082 `,
1083         },
1084
1085         {
1086                 name: "blank_after_package_statement_no_comment",
1087                 in: `package p
1088
1089 import "math"
1090
1091 var _ = fmt.Printf
1092 `,
1093                 out: `package p
1094
1095 import "fmt"
1096
1097 var _ = fmt.Printf
1098 `,
1099         },
1100
1101         {
1102                 name: "cryptorand_preferred_easy_possible",
1103                 in: `package p
1104
1105 var _ = rand.Read
1106 `,
1107                 out: `package p
1108
1109 import "crypto/rand"
1110
1111 var _ = rand.Read
1112 `,
1113         },
1114
1115         {
1116                 name: "cryptorand_preferred_easy_impossible",
1117                 in: `package p
1118
1119 var _ = rand.NewZipf
1120 `,
1121                 out: `package p
1122
1123 import "math/rand"
1124
1125 var _ = rand.NewZipf
1126 `,
1127         },
1128
1129         {
1130                 name: "cryptorand_preferred_complex_possible",
1131                 in: `package p
1132
1133 var _, _ = rand.Read, rand.Prime
1134 `,
1135                 out: `package p
1136
1137 import "crypto/rand"
1138
1139 var _, _ = rand.Read, rand.Prime
1140 `,
1141         },
1142
1143         {
1144                 name: "cryptorand_preferred_complex_impossible",
1145                 in: `package p
1146
1147 var _, _ = rand.Read, rand.NewZipf
1148 `,
1149                 out: `package p
1150
1151 import "math/rand"
1152
1153 var _, _ = rand.Read, rand.NewZipf
1154 `,
1155         },
1156 }
1157
1158 func TestSimpleCases(t *testing.T) {
1159         const localPrefix = "local.com,github.com/local"
1160         for _, tt := range tests {
1161                 t.Run(tt.name, func(t *testing.T) {
1162                         testConfig{
1163                                 modules: []packagestest.Module{
1164                                         {
1165                                                 Name:  "golang.org/fake",
1166                                                 Files: fm{"x.go": tt.in},
1167                                         },
1168                                         // Skeleton non-stdlib packages for use during testing.
1169                                         // Each includes one arbitrary symbol, e.g. the first declaration in the first file.
1170                                         // Try not to add more without a good reason.
1171                                         // DO NOT USE PACKAGES NOT LISTED HERE -- they will be downloaded!
1172                                         {
1173                                                 Name:  "rsc.io",
1174                                                 Files: fm{"p/x.go": "package p\nfunc P(){}\n"},
1175                                         },
1176                                         {
1177                                                 Name:  "github.com/golang/snappy",
1178                                                 Files: fm{"x.go": "package snappy\nvar ErrCorrupt error\n"},
1179                                         },
1180                                         {
1181                                                 Name: "manypackages.com",
1182                                                 Files: fm{
1183                                                         "packagea/x.go": "package packagea\nfunc A(){}\n",
1184                                                         "packageb/x.go": "package packageb\nfunc B(){}\n",
1185                                                         "packagec/x.go": "package packagec\nfunc C(){}\n",
1186                                                         "packaged/x.go": "package packaged\nfunc D(){}\n",
1187                                                 },
1188                                         },
1189                                         {
1190                                                 Name:  "local.com",
1191                                                 Files: fm{"foo/x.go": "package foo\nfunc Foo(){}\n"},
1192                                         },
1193                                         {
1194                                                 Name:  "github.com/local",
1195                                                 Files: fm{"bar/x.go": "package bar\nfunc Bar(){}\n"},
1196                                         },
1197                                 },
1198                         }.test(t, func(t *goimportTest) {
1199                                 options := &Options{
1200                                         LocalPrefix: localPrefix,
1201                                         TabWidth:    8,
1202                                         TabIndent:   true,
1203                                         Comments:    true,
1204                                         Fragment:    true,
1205                                         FormatOnly:  tt.formatOnly,
1206                                 }
1207                                 t.assertProcessEquals("golang.org/fake", "x.go", nil, options, tt.out)
1208                         })
1209
1210                 })
1211         }
1212 }
1213
1214 func TestAppengine(t *testing.T) {
1215         const input = `package p
1216
1217 var _, _, _ = fmt.Printf, appengine.Main, datastore.ErrInvalidEntityType
1218 `
1219
1220         const want = `package p
1221
1222 import (
1223         "fmt"
1224
1225         "appengine"
1226         "appengine/datastore"
1227 )
1228
1229 var _, _, _ = fmt.Printf, appengine.Main, datastore.ErrInvalidEntityType
1230 `
1231
1232         testConfig{
1233                 gopathOnly: true, // can't create a module named appengine, so no module tests.
1234                 modules: []packagestest.Module{
1235                         {
1236                                 Name:  "golang.org/fake",
1237                                 Files: fm{"x.go": input},
1238                         },
1239                         {
1240                                 Name: "appengine",
1241                                 Files: fm{
1242                                         "x.go":           "package appengine\nfunc Main(){}\n",
1243                                         "datastore/x.go": "package datastore\nvar ErrInvalidEntityType error\n",
1244                                 },
1245                         },
1246                 },
1247         }.processTest(t, "golang.org/fake", "x.go", nil, nil, want)
1248 }
1249
1250 func TestReadFromFilesystem(t *testing.T) {
1251         tests := []struct {
1252                 name    string
1253                 in, out string
1254         }{
1255                 {
1256                         name: "works",
1257                         in: `package foo
1258 func bar() {
1259 fmt.Println("hi")
1260 }
1261 `,
1262                         out: `package foo
1263
1264 import "fmt"
1265
1266 func bar() {
1267         fmt.Println("hi")
1268 }
1269 `,
1270                 },
1271                 {
1272                         name: "missing_package",
1273                         in: `
1274 func bar() {
1275 fmt.Println("hi")
1276 }
1277 `,
1278                         out: `
1279 import "fmt"
1280
1281 func bar() {
1282         fmt.Println("hi")
1283 }
1284 `,
1285                 },
1286         }
1287
1288         for _, tt := range tests {
1289                 t.Run(tt.name, func(t *testing.T) {
1290                         options := &Options{
1291                                 TabWidth:  8,
1292                                 TabIndent: true,
1293                                 Comments:  true,
1294                                 Fragment:  true,
1295                         }
1296                         testConfig{
1297                                 module: packagestest.Module{
1298                                         Name:  "golang.org/fake",
1299                                         Files: fm{"x.go": tt.in},
1300                                 },
1301                         }.processTest(t, "golang.org/fake", "x.go", nil, options, tt.out)
1302                 })
1303         }
1304
1305 }
1306
1307 // Test support for packages in GOPATH that are actually symlinks.
1308 // Also test that a symlink loop does not block the process.
1309 func TestImportSymlinks(t *testing.T) {
1310         switch runtime.GOOS {
1311         case "windows", "plan9":
1312                 t.Skipf("skipping test on %q as there are no symlinks", runtime.GOOS)
1313         }
1314
1315         const input = `package p
1316
1317 var (
1318         _ = fmt.Print
1319         _ = mypkg.Foo
1320 )
1321 `
1322         const want = `package p
1323
1324 import (
1325         "fmt"
1326
1327         "golang.org/fake/x/y/mypkg"
1328 )
1329
1330 var (
1331         _ = fmt.Print
1332         _ = mypkg.Foo
1333 )
1334 `
1335
1336         testConfig{
1337                 module: packagestest.Module{
1338                         Name: "golang.org/fake",
1339                         Files: fm{
1340                                 "target/f.go":                "package mypkg\nvar Foo = 123\n",
1341                                 "x/y/mypkg":                  packagestest.Symlink("../../target"), // valid symlink
1342                                 "x/y/apkg":                   packagestest.Symlink(".."),           // symlink loop
1343                                 "myotherpackage/toformat.go": input,
1344                         },
1345                 },
1346         }.processTest(t, "golang.org/fake", "myotherpackage/toformat.go", nil, nil, want)
1347 }
1348
1349 func TestImportSymlinksWithIgnore(t *testing.T) {
1350         switch runtime.GOOS {
1351         case "windows", "plan9":
1352                 t.Skipf("skipping test on %q as there are no symlinks", runtime.GOOS)
1353         }
1354
1355         const input = `package p
1356
1357 var (
1358         _ = fmt.Print
1359         _ = mypkg.Foo
1360 )
1361 `
1362         const want = `package p
1363
1364 import "fmt"
1365
1366 var (
1367         _ = fmt.Print
1368         _ = mypkg.Foo
1369 )
1370 `
1371
1372         testConfig{
1373                 gopathOnly: true,
1374                 module: packagestest.Module{
1375                         Name: "golang.org/fake",
1376                         Files: fm{
1377                                 "target/f.go":            "package mypkg\nvar Foo = 123\n",
1378                                 "x/y/mypkg":              packagestest.Symlink("../../target"), // valid symlink
1379                                 "x/y/apkg":               packagestest.Symlink(".."),           // symlink loop
1380                                 "myotherpkg/toformat.go": input,
1381                                 "../../.goimportsignore": "golang.org/fake/x/y/mypkg\n",
1382                         },
1383                 },
1384         }.processTest(t, "golang.org/fake", "myotherpkg/toformat.go", nil, nil, want)
1385 }
1386
1387 // Test for x/y/v2 convention for package y.
1388 func TestModuleVersion(t *testing.T) {
1389         const input = `package p
1390
1391 import (
1392         "fmt"
1393
1394         "github.com/foo/v2"
1395 )
1396
1397 var (
1398         _ = fmt.Print
1399         _ = foo.Foo
1400 )
1401 `
1402
1403         testConfig{
1404                 modules: []packagestest.Module{
1405                         {
1406                                 Name:  "mypkg.com/outpkg",
1407                                 Files: fm{"toformat.go": input},
1408                         },
1409                         {
1410                                 Name:  "github.com/foo/v2",
1411                                 Files: fm{"x.go": "package foo\n func Foo(){}\n"},
1412                         },
1413                 },
1414         }.processTest(t, "mypkg.com/outpkg", "toformat.go", nil, nil, input)
1415 }
1416
1417 // Test for correctly identifying the name of a vendored package when it
1418 // differs from its directory name. In this test, the import line
1419 // "mypkg.com/mypkg_v1" would be removed if goimports wasn't able to detect
1420 // that the package name is "mypkg".
1421 func TestVendorPackage(t *testing.T) {
1422         const input = `package p
1423 import (
1424         "fmt"
1425         "mypkg.com/mypkg_v1"
1426 )
1427 var _, _ = fmt.Print, mypkg.Foo
1428 `
1429
1430         const want = `package p
1431
1432 import (
1433         "fmt"
1434
1435         mypkg "mypkg.com/mypkg_v1"
1436 )
1437
1438 var _, _ = fmt.Print, mypkg.Foo
1439 `
1440
1441         testConfig{
1442                 gopathOnly: true,
1443                 module: packagestest.Module{
1444                         Name: "mypkg.com/outpkg",
1445                         Files: fm{
1446                                 "vendor/mypkg.com/mypkg_v1/f.go": "package mypkg\nvar Foo = 123\n",
1447                                 "toformat.go":                    input,
1448                         },
1449                 },
1450         }.processTest(t, "mypkg.com/outpkg", "toformat.go", nil, nil, want)
1451 }
1452
1453 func TestInternal(t *testing.T) {
1454         const input = `package bar
1455
1456 var _ = race.Acquire
1457 `
1458         const importAdded = `package bar
1459
1460 import "foo.com/internal/race"
1461
1462 var _ = race.Acquire
1463 `
1464
1465         // Packages under the same directory should be able to use internal packages.
1466         testConfig{
1467                 module: packagestest.Module{
1468                         Name: "foo.com",
1469                         Files: fm{
1470                                 "internal/race/x.go": "package race\n func Acquire(){}\n",
1471                                 "bar/x.go":           input,
1472                         },
1473                 },
1474         }.processTest(t, "foo.com", "bar/x.go", nil, nil, importAdded)
1475
1476         // Packages outside the same directory should not.
1477         testConfig{
1478                 modules: []packagestest.Module{
1479                         {
1480                                 Name:  "foo.com",
1481                                 Files: fm{"internal/race/x.go": "package race\n func Acquire(){}\n"},
1482                         },
1483                         {
1484                                 Name:  "bar.com",
1485                                 Files: fm{"x.go": input},
1486                         },
1487                 },
1488         }.processTest(t, "bar.com", "x.go", nil, nil, input)
1489 }
1490
1491 func TestProcessVendor(t *testing.T) {
1492         const input = `package p
1493
1494 var _ = hpack.HuffmanDecode
1495 `
1496         const want = `package p
1497
1498 import "golang.org/x/net/http2/hpack"
1499
1500 var _ = hpack.HuffmanDecode
1501 `
1502         testConfig{
1503                 gopathOnly: true,
1504                 module: packagestest.Module{
1505                         Name: "foo.com",
1506                         Files: fm{
1507                                 "vendor/golang.org/x/net/http2/hpack/huffman.go": "package hpack\nfunc HuffmanDecode() { }\n",
1508                                 "bar/x.go": input,
1509                         },
1510                 },
1511         }.processTest(t, "foo.com", "bar/x.go", nil, nil, want)
1512 }
1513
1514 func TestFindStdlib(t *testing.T) {
1515         tests := []struct {
1516                 pkg     string
1517                 symbols []string
1518                 want    string
1519         }{
1520                 {"http", []string{"Get"}, "net/http"},
1521                 {"http", []string{"Get", "Post"}, "net/http"},
1522                 {"http", []string{"Get", "Foo"}, ""},
1523                 {"bytes", []string{"Buffer"}, "bytes"},
1524                 {"ioutil", []string{"Discard"}, "io/ioutil"},
1525         }
1526         for _, tt := range tests {
1527                 input := "package p\n"
1528                 for _, sym := range tt.symbols {
1529                         input += fmt.Sprintf("var _ = %s.%s\n", tt.pkg, sym)
1530                 }
1531                 testConfig{
1532                         module: packagestest.Module{
1533                                 Name:  "foo.com",
1534                                 Files: fm{"x.go": input},
1535                         },
1536                 }.test(t, func(t *goimportTest) {
1537                         buf, err := t.process("foo.com", "x.go", nil, nil)
1538                         if err != nil {
1539                                 t.Fatal(err)
1540                         }
1541                         if got := string(buf); !strings.Contains(got, tt.want) {
1542                                 t.Errorf("Process(%q) = %q, wanted it to contain %q", input, buf, tt.want)
1543                         }
1544                 })
1545         }
1546 }
1547
1548 // https://golang.org/issue/31814
1549 func TestStdlibNotPrefixed(t *testing.T) {
1550         const input = `package p
1551 var _ = bytes.Buffer
1552 `
1553         const want = `package p
1554
1555 import "bytes"
1556
1557 var _ = bytes.Buffer
1558 `
1559         // Force a scan of the stdlib.
1560         savedStdlib := stdlib
1561         defer func() { stdlib = savedStdlib }()
1562         stdlib = map[string][]string{}
1563
1564         testConfig{
1565                 module: packagestest.Module{
1566                         Name:  "ignored.com",
1567                         Files: fm{"x.go": "package x"},
1568                 },
1569         }.test(t, func(t *goimportTest) {
1570                 // Run in GOROOT/src so that the std module shows up in go list -m all.
1571                 t.env.WorkingDir = filepath.Join(t.goroot, "src")
1572                 got, err := t.processNonModule(filepath.Join(t.goroot, "src/x.go"), []byte(input), nil)
1573                 if err != nil {
1574                         t.Fatalf("Process() = %v", err)
1575                 }
1576                 if string(got) != want {
1577                         t.Errorf("Got:\n%s\nWant:\n%s", got, want)
1578                 }
1579         })
1580 }
1581
1582 func TestStdlibSelfImports(t *testing.T) {
1583         const input = `package ecdsa
1584
1585 var _ = ecdsa.GenerateKey
1586 `
1587
1588         testConfig{
1589                 module: packagestest.Module{
1590                         Name:  "ignored.com",
1591                         Files: fm{"x.go": "package x"},
1592                 },
1593         }.test(t, func(t *goimportTest) {
1594                 got, err := t.processNonModule(filepath.Join(t.goroot, "src/crypto/ecdsa/foo.go"), []byte(input), nil)
1595                 if err != nil {
1596                         t.Fatalf("Process() = %v", err)
1597                 }
1598                 if string(got) != input {
1599                         t.Errorf("Got:\n%s\nWant:\n%s", got, input)
1600                 }
1601         })
1602 }
1603
1604 type testConfig struct {
1605         gopathOnly bool
1606         module     packagestest.Module
1607         modules    []packagestest.Module
1608 }
1609
1610 // fm is the type for a packagestest.Module's Files, abbreviated for shorter lines.
1611 type fm map[string]interface{}
1612
1613 func (c testConfig) test(t *testing.T, fn func(*goimportTest)) {
1614         t.Helper()
1615
1616         if c.module.Name != "" {
1617                 c.modules = []packagestest.Module{c.module}
1618         }
1619
1620         for _, exporter := range packagestest.All {
1621                 t.Run(exporter.Name(), func(t *testing.T) {
1622                         t.Helper()
1623                         if c.gopathOnly && exporter.Name() == "Modules" {
1624                                 t.Skip("test marked GOPATH-only")
1625                         }
1626                         exported := packagestest.Export(t, exporter, c.modules)
1627                         defer exported.Cleanup()
1628
1629                         env := map[string]string{}
1630                         for _, kv := range exported.Config.Env {
1631                                 split := strings.SplitN(kv, "=", 2)
1632                                 env[split[0]] = split[1]
1633                         }
1634                         it := &goimportTest{
1635                                 T: t,
1636                                 env: &ProcessEnv{
1637                                         Env:         env,
1638                                         WorkingDir:  exported.Config.Dir,
1639                                         GocmdRunner: &gocommand.Runner{},
1640                                 },
1641                                 exported: exported,
1642                         }
1643                         if *testDebug {
1644                                 it.env.Logf = log.Printf
1645                         }
1646                         // packagestest clears out GOROOT to work around golang/go#32849,
1647                         // which isn't relevant here. Fill it back in so we can find the standard library.
1648                         it.env.Env["GOROOT"] = build.Default.GOROOT
1649                         it.goroot = build.Default.GOROOT
1650
1651                         fn(it)
1652                 })
1653         }
1654 }
1655
1656 func (c testConfig) processTest(t *testing.T, module, file string, contents []byte, opts *Options, want string) {
1657         t.Helper()
1658         c.test(t, func(t *goimportTest) {
1659                 t.Helper()
1660                 t.assertProcessEquals(module, file, contents, opts, want)
1661         })
1662 }
1663
1664 type goimportTest struct {
1665         *testing.T
1666         goroot   string
1667         env      *ProcessEnv
1668         exported *packagestest.Exported
1669 }
1670
1671 func (t *goimportTest) process(module, file string, contents []byte, opts *Options) ([]byte, error) {
1672         t.Helper()
1673         f := t.exported.File(module, file)
1674         if f == "" {
1675                 t.Fatalf("%v not found in exported files (typo in filename?)", file)
1676         }
1677         return t.processNonModule(f, contents, opts)
1678 }
1679
1680 func (t *goimportTest) processNonModule(file string, contents []byte, opts *Options) ([]byte, error) {
1681         if contents == nil {
1682                 var err error
1683                 contents, err = ioutil.ReadFile(file)
1684                 if err != nil {
1685                         return nil, err
1686                 }
1687         }
1688         if opts == nil {
1689                 opts = &Options{Comments: true, TabIndent: true, TabWidth: 8}
1690         }
1691         // ProcessEnv is not safe for concurrent use. Make a copy.
1692         opts.Env = t.env.CopyConfig()
1693         return Process(file, contents, opts)
1694 }
1695
1696 func (t *goimportTest) assertProcessEquals(module, file string, contents []byte, opts *Options, want string) {
1697         buf, err := t.process(module, file, contents, opts)
1698         if err != nil {
1699                 t.Fatalf("Process() = %v", err)
1700         }
1701         if string(buf) != want {
1702                 t.Errorf("Got:\n%s\nWant:\n%s", buf, want)
1703         }
1704 }
1705
1706 // Tests that added imports are renamed when the import path's base doesn't
1707 // match its package name.
1708 func TestRenameWhenPackageNameMismatch(t *testing.T) {
1709         const input = `package main
1710  const Y = bar.X`
1711
1712         const want = `package main
1713
1714 import bar "foo.com/foo/bar/baz"
1715
1716 const Y = bar.X
1717 `
1718         testConfig{
1719                 module: packagestest.Module{
1720                         Name: "foo.com",
1721                         Files: fm{
1722                                 "foo/bar/baz/x.go": "package bar \n const X = 1",
1723                                 "test/t.go":        input,
1724                         },
1725                 },
1726         }.processTest(t, "foo.com", "test/t.go", nil, nil, want)
1727 }
1728
1729 // Tests that an existing import with badly mismatched path/name has its name
1730 // correctly added. See #28645 and #29041.
1731 func TestAddNameToMismatchedImport(t *testing.T) {
1732         const input = `package main
1733
1734 import (
1735 "foo.com/a.thing"
1736 "foo.com/surprise"
1737 "foo.com/v1"
1738 "foo.com/other/v2"
1739 "foo.com/other/v3"
1740 "foo.com/go-thing"
1741 "foo.com/go-wrong"
1742 )
1743
1744 var _ = []interface{}{bar.X, v1.Y, a.A, v2.V2, other.V3, thing.Thing, gow.Wrong}`
1745
1746         const want = `package main
1747
1748 import (
1749         "foo.com/a.thing"
1750         "foo.com/go-thing"
1751         gow "foo.com/go-wrong"
1752         v2 "foo.com/other/v2"
1753         "foo.com/other/v3"
1754         bar "foo.com/surprise"
1755         v1 "foo.com/v1"
1756 )
1757
1758 var _ = []interface{}{bar.X, v1.Y, a.A, v2.V2, other.V3, thing.Thing, gow.Wrong}
1759 `
1760
1761         testConfig{
1762                 module: packagestest.Module{
1763                         Name: "foo.com",
1764                         Files: fm{
1765                                 "a.thing/a.go":  "package a \n const A = 1",
1766                                 "surprise/x.go": "package bar \n const X = 1",
1767                                 "v1/x.go":       "package v1 \n const Y = 1",
1768                                 "other/v2/y.go": "package v2 \n const V2 = 1",
1769                                 "other/v3/z.go": "package other \n const V3 = 1",
1770                                 "go-thing/b.go": "package thing \n const Thing = 1",
1771                                 "go-wrong/b.go": "package gow \n const Wrong = 1",
1772                                 "test/t.go":     input,
1773                         },
1774                 },
1775         }.processTest(t, "foo.com", "test/t.go", nil, nil, want)
1776 }
1777
1778 // Tests that the LocalPrefix option causes imports
1779 // to be added into a later group (num=3).
1780 func TestLocalPrefix(t *testing.T) {
1781         tests := []struct {
1782                 name        string
1783                 modules     []packagestest.Module
1784                 localPrefix string
1785                 src         string
1786                 want        string
1787         }{
1788                 {
1789                         name: "one_local",
1790                         modules: []packagestest.Module{
1791                                 {
1792                                         Name: "foo.com",
1793                                         Files: fm{
1794                                                 "bar/bar.go": "package bar \n const X = 1",
1795                                         },
1796                                 },
1797                         },
1798                         localPrefix: "foo.com/",
1799                         src:         "package main \n const Y = bar.X \n const _ = runtime.GOOS",
1800                         want: `package main
1801
1802 import (
1803         "runtime"
1804
1805         "foo.com/bar"
1806 )
1807
1808 const Y = bar.X
1809 const _ = runtime.GOOS
1810 `,
1811                 },
1812                 {
1813                         name: "two_local",
1814                         modules: []packagestest.Module{
1815                                 {
1816                                         Name: "foo.com",
1817                                         Files: fm{
1818                                                 "foo/foo.go":     "package foo \n const X = 1",
1819                                                 "foo/bar/bar.go": "package bar \n const X = 1",
1820                                         },
1821                                 },
1822                         },
1823                         localPrefix: "foo.com/foo",
1824                         src:         "package main \n const Y = bar.X \n const Z = foo.X \n const _ = runtime.GOOS",
1825                         want: `package main
1826
1827 import (
1828         "runtime"
1829
1830         "foo.com/foo"
1831         "foo.com/foo/bar"
1832 )
1833
1834 const Y = bar.X
1835 const Z = foo.X
1836 const _ = runtime.GOOS
1837 `,
1838                 },
1839                 {
1840                         name: "three_prefixes",
1841                         modules: []packagestest.Module{
1842                                 {
1843                                         Name:  "example.org/pkg",
1844                                         Files: fm{"pkg.go": "package pkg \n const A = 1"},
1845                                 },
1846                                 {
1847                                         Name:  "foo.com",
1848                                         Files: fm{"bar/bar.go": "package bar \n const B = 1"},
1849                                 },
1850                                 {
1851                                         Name:  "code.org/r/p",
1852                                         Files: fm{"expproj/expproj.go": "package expproj \n const C = 1"},
1853                                 },
1854                         },
1855                         localPrefix: "example.org/pkg,foo.com/,code.org",
1856                         src:         "package main \n const X = pkg.A \n const Y = bar.B \n const Z = expproj.C \n const _ = runtime.GOOS",
1857                         want: `package main
1858
1859 import (
1860         "runtime"
1861
1862         "code.org/r/p/expproj"
1863         "example.org/pkg"
1864         "foo.com/bar"
1865 )
1866
1867 const X = pkg.A
1868 const Y = bar.B
1869 const Z = expproj.C
1870 const _ = runtime.GOOS
1871 `,
1872                 },
1873         }
1874
1875         for _, tt := range tests {
1876                 t.Run(tt.name, func(t *testing.T) {
1877                         testConfig{
1878                                 // The module being processed has to be first so it's the primary module.
1879                                 modules: append([]packagestest.Module{{
1880                                         Name:  "test.com",
1881                                         Files: fm{"t.go": tt.src},
1882                                 }}, tt.modules...),
1883                         }.test(t, func(t *goimportTest) {
1884                                 options := &Options{
1885                                         LocalPrefix: tt.localPrefix,
1886                                         TabWidth:    8,
1887                                         TabIndent:   true,
1888                                         Comments:    true,
1889                                         Fragment:    true,
1890                                 }
1891                                 t.assertProcessEquals("test.com", "t.go", nil, options, tt.want)
1892                         })
1893                 })
1894         }
1895 }
1896
1897 // Tests that "package documentation" files are ignored.
1898 func TestIgnoreDocumentationPackage(t *testing.T) {
1899         const input = `package x
1900
1901 const Y = foo.X
1902 `
1903         const want = `package x
1904
1905 import "foo.com/foo"
1906
1907 const Y = foo.X
1908 `
1909
1910         testConfig{
1911                 module: packagestest.Module{
1912                         Name: "foo.com",
1913                         Files: fm{
1914                                 "foo/foo.go": "package foo\nconst X = 1\n",
1915                                 "foo/doc.go": "package documentation \n // just to confuse things\n",
1916                                 "x/x.go":     input,
1917                         },
1918                 },
1919         }.processTest(t, "foo.com", "x/x.go", nil, nil, want)
1920 }
1921
1922 // Tests importPathToNameGoPathParse and in particular that it stops
1923 // after finding the first non-documentation package name, not
1924 // reporting an error on inconsistent package names (since it should
1925 // never make it that far).
1926 func TestImportPathToNameGoPathParse(t *testing.T) {
1927         testConfig{
1928                 module: packagestest.Module{
1929                         Name: "example.net/pkg",
1930                         Files: fm{
1931                                 "doc.go": "package documentation\n", // ignored
1932                                 "gen.go": "package main\n",          // also ignored
1933                                 "pkg.go": "package the_pkg_name_to_find\n  and this syntax error is ignored because of parser.PackageClauseOnly",
1934                                 "z.go":   "package inconsistent\n", // inconsistent but ignored
1935                         },
1936                 },
1937         }.test(t, func(t *goimportTest) {
1938                 if strings.Contains(t.Name(), "GoPackages") {
1939                         t.Skip("go/packages does not ignore package main")
1940                 }
1941                 r, err := t.env.GetResolver()
1942                 if err != nil {
1943                         t.Fatal(err)
1944                 }
1945                 srcDir := filepath.Dir(t.exported.File("example.net/pkg", "z.go"))
1946                 names, err := r.loadPackageNames([]string{"example.net/pkg"}, srcDir)
1947                 if err != nil {
1948                         t.Fatal(err)
1949                 }
1950                 const want = "the_pkg_name_to_find"
1951                 if got := names["example.net/pkg"]; got != want {
1952                         t.Errorf("loadPackageNames(..) = %q; want %q", got, want)
1953                 }
1954         })
1955 }
1956
1957 func TestIgnoreConfiguration(t *testing.T) {
1958         const input = `package x
1959
1960 const _ = pkg.X
1961 `
1962         const want = `package x
1963
1964 import "foo.com/otherwise-longer-so-worse-example/foo/pkg"
1965
1966 const _ = pkg.X
1967 `
1968
1969         testConfig{
1970                 gopathOnly: true,
1971                 module: packagestest.Module{
1972                         Name: "foo.com",
1973                         Files: fm{
1974                                 "../.goimportsignore":                              "# comment line\n\n foo.com/example", // tests comment, blank line, whitespace trimming
1975                                 "example/pkg/pkg.go":                               "package pkg\nconst X = 1",
1976                                 "otherwise-longer-so-worse-example/foo/pkg/pkg.go": "package pkg\nconst X = 1",
1977                                 "x/x.go": input,
1978                         },
1979                 },
1980         }.processTest(t, "foo.com", "x/x.go", nil, nil, want)
1981 }
1982
1983 // Skip "node_modules" directory.
1984 func TestSkipNodeModules(t *testing.T) {
1985         const input = `package x
1986
1987 const _ = pkg.X
1988 `
1989         const want = `package x
1990
1991 import "foo.com/otherwise-longer/not_modules/pkg"
1992
1993 const _ = pkg.X
1994 `
1995
1996         testConfig{
1997                 gopathOnly: true,
1998                 module: packagestest.Module{
1999                         Name: "foo.com",
2000                         Files: fm{
2001                                 "example/node_modules/pkg/a.go":         "package pkg\nconst X = 1",
2002                                 "otherwise-longer/not_modules/pkg/a.go": "package pkg\nconst X = 1",
2003                                 "x/x.go":                                input,
2004                         },
2005                 },
2006         }.processTest(t, "foo.com", "x/x.go", nil, nil, want)
2007 }
2008
2009 // Tests that package global variables with the same name and function name as
2010 // a function in a separate package do not result in an import which masks
2011 // the global variable
2012 func TestGlobalImports(t *testing.T) {
2013         const usesGlobal = `package pkg
2014
2015 func doSomething() {
2016         t := time.Now()
2017 }
2018 `
2019
2020         const declaresGlobal = `package pkg
2021
2022 type Time struct{}
2023
2024 func (t Time) Now() Time {
2025         return Time{}
2026 }
2027
2028 var time Time
2029 `
2030
2031         testConfig{
2032                 module: packagestest.Module{
2033                         Name: "foo.com",
2034                         Files: fm{
2035                                 "pkg/uses.go":   usesGlobal,
2036                                 "pkg/global.go": declaresGlobal,
2037                         },
2038                 },
2039         }.processTest(t, "foo.com", "pkg/uses.go", nil, nil, usesGlobal)
2040 }
2041
2042 // Some people put multiple packages' files in the same directory. Globals
2043 // declared in other packages should be ignored.
2044 func TestGlobalImports_DifferentPackage(t *testing.T) {
2045         const declaresGlobal = `package main
2046 var fmt int
2047 `
2048         const input = `package pkg
2049 var _ = fmt.Printf
2050 `
2051         const want = `package pkg
2052
2053 import "fmt"
2054
2055 var _ = fmt.Printf
2056 `
2057
2058         testConfig{
2059                 module: packagestest.Module{
2060                         Name: "foo.com",
2061                         Files: fm{
2062                                 "pkg/main.go": declaresGlobal,
2063                                 "pkg/uses.go": input,
2064                         },
2065                 },
2066         }.processTest(t, "foo.com", "pkg/uses.go", nil, nil, want)
2067 }
2068
2069 func TestGlobalImports_MultipleMains(t *testing.T) {
2070         const declaresGlobal = `package main
2071 var fmt int
2072 `
2073         const input = `package main
2074 import "fmt"
2075 var _, _ = fmt.Printf, bytes.Equal
2076 `
2077         const want = `package main
2078
2079 import (
2080         "bytes"
2081         "fmt"
2082 )
2083
2084 var _, _ = fmt.Printf, bytes.Equal
2085 `
2086
2087         testConfig{
2088                 module: packagestest.Module{
2089                         Name: "foo.com",
2090                         Files: fm{
2091                                 "pkg/main.go": declaresGlobal,
2092                                 "pkg/uses.go": input,
2093                         },
2094                 },
2095         }.processTest(t, "foo.com", "pkg/uses.go", nil, nil, want)
2096 }
2097
2098 // Tests that sibling files - other files in the same package - can provide an
2099 // import that may not be the default one otherwise.
2100 func TestSiblingImports(t *testing.T) {
2101
2102         // provide is the sibling file that provides the desired import.
2103         const provide = `package siblingimporttest
2104
2105 import "local/log"
2106 import "my/bytes"
2107 import renamed "fmt"
2108
2109 func LogSomething() {
2110         log.Print("Something")
2111         bytes.SomeFunc()
2112         renamed.Println("Something")
2113 }
2114 `
2115
2116         // need is the file being tested that needs the import.
2117         const need = `package siblingimporttest
2118
2119 var _ = bytes.Buffer{}
2120
2121 func LogSomethingElse() {
2122         log.Print("Something else")
2123         renamed.Println("Yet another")
2124 }
2125 `
2126
2127         // want is the expected result file
2128         const want = `package siblingimporttest
2129
2130 import (
2131         "bytes"
2132         renamed "fmt"
2133         "local/log"
2134 )
2135
2136 var _ = bytes.Buffer{}
2137
2138 func LogSomethingElse() {
2139         log.Print("Something else")
2140         renamed.Println("Yet another")
2141 }
2142 `
2143
2144         testConfig{
2145                 module: packagestest.Module{
2146                         Name: "foo.com",
2147                         Files: fm{
2148                                 "p/needs_import.go":    need,
2149                                 "p/provides_import.go": provide,
2150                         },
2151                 },
2152         }.processTest(t, "foo.com", "p/needs_import.go", nil, nil, want)
2153 }
2154
2155 // Tests #29180: a sibling import of the right package with the wrong name is used.
2156 func TestSiblingImport_Misnamed(t *testing.T) {
2157         const sibling = `package main
2158 import renamed "fmt"
2159 var _ = renamed.Printf
2160 `
2161         const input = `package pkg
2162 var _ = fmt.Printf
2163 `
2164         const want = `package pkg
2165
2166 import "fmt"
2167
2168 var _ = fmt.Printf
2169 `
2170
2171         testConfig{
2172                 module: packagestest.Module{
2173                         Name: "foo.com",
2174                         Files: fm{
2175                                 "pkg/main.go": sibling,
2176                                 "pkg/uses.go": input,
2177                         },
2178                 },
2179         }.processTest(t, "foo.com", "pkg/uses.go", nil, nil, want)
2180
2181 }
2182
2183 // Tests that an input file's own package is ignored.
2184 func TestIgnoreOwnPackage(t *testing.T) {
2185         const input = `package pkg
2186
2187 const _ = pkg.X
2188 `
2189         const want = `package pkg
2190
2191 const _ = pkg.X
2192 `
2193
2194         testConfig{
2195                 module: packagestest.Module{
2196                         Name: "foo.com",
2197                         Files: fm{
2198                                 "pkg/a.go": "package pkg\nconst X = 1",
2199                                 "pkg/b.go": input,
2200                         },
2201                 },
2202         }.processTest(t, "foo.com", "pkg/b.go", nil, nil, want)
2203 }
2204
2205 func TestExternalTestImportsPackageUnderTest(t *testing.T) {
2206         const provide = `package pkg
2207 func DoIt(){}
2208 `
2209         const input = `package pkg_test
2210
2211 var _ = pkg.DoIt`
2212
2213         const want = `package pkg_test
2214
2215 import "foo.com/pkg"
2216
2217 var _ = pkg.DoIt
2218 `
2219
2220         testConfig{
2221                 module: packagestest.Module{
2222                         Name: "foo.com",
2223                         Files: fm{
2224                                 "pkg/provide.go": provide,
2225                                 "pkg/x_test.go":  input,
2226                         },
2227                 },
2228         }.processTest(t, "foo.com", "pkg/x_test.go", nil, nil, want)
2229 }
2230
2231 func TestPkgIsCandidate(t *testing.T) {
2232         tests := []struct {
2233                 name     string
2234                 filename string
2235                 pkgIdent string
2236                 pkg      *pkg
2237                 want     bool
2238         }{
2239                 {
2240                         name:     "normal_match",
2241                         filename: "/gopath/src/my/pkg/pkg.go",
2242                         pkgIdent: "client",
2243                         pkg: &pkg{
2244                                 dir:             "/gopath/src/client",
2245                                 importPathShort: "client",
2246                         },
2247                         want: true,
2248                 },
2249                 {
2250                         name:     "no_match",
2251                         filename: "/gopath/src/my/pkg/pkg.go",
2252                         pkgIdent: "zzz",
2253                         pkg: &pkg{
2254                                 dir:             "/gopath/src/client",
2255                                 importPathShort: "client",
2256                         },
2257                         want: false,
2258                 },
2259                 {
2260                         name:     "match_too_early",
2261                         filename: "/gopath/src/my/pkg/pkg.go",
2262                         pkgIdent: "client",
2263                         pkg: &pkg{
2264                                 dir:             "/gopath/src/client/foo/foo/foo",
2265                                 importPathShort: "client/foo/foo",
2266                         },
2267                         want: false,
2268                 },
2269                 {
2270                         name:     "substring_match",
2271                         filename: "/gopath/src/my/pkg/pkg.go",
2272                         pkgIdent: "client",
2273                         pkg: &pkg{
2274                                 dir:             "/gopath/src/foo/go-client",
2275                                 importPathShort: "foo/go-client",
2276                         },
2277                         want: true,
2278                 },
2279                 {
2280                         name:     "hidden_internal",
2281                         filename: "/gopath/src/my/pkg/pkg.go",
2282                         pkgIdent: "client",
2283                         pkg: &pkg{
2284                                 dir:             "/gopath/src/foo/internal/client",
2285                                 importPathShort: "foo/internal/client",
2286                         },
2287                         want: false,
2288                 },
2289                 {
2290                         name:     "visible_internal",
2291                         filename: "/gopath/src/foo/bar.go",
2292                         pkgIdent: "client",
2293                         pkg: &pkg{
2294                                 dir:             "/gopath/src/foo/internal/client",
2295                                 importPathShort: "foo/internal/client",
2296                         },
2297                         want: true,
2298                 },
2299                 {
2300                         name:     "invisible_vendor",
2301                         filename: "/gopath/src/foo/bar.go",
2302                         pkgIdent: "client",
2303                         pkg: &pkg{
2304                                 dir:             "/gopath/src/other/vendor/client",
2305                                 importPathShort: "client",
2306                         },
2307                         want: false,
2308                 },
2309                 {
2310                         name:     "visible_vendor",
2311                         filename: "/gopath/src/foo/bar.go",
2312                         pkgIdent: "client",
2313                         pkg: &pkg{
2314                                 dir:             "/gopath/src/foo/vendor/client",
2315                                 importPathShort: "client",
2316                         },
2317                         want: true,
2318                 },
2319                 {
2320                         name:     "match_with_hyphens",
2321                         filename: "/gopath/src/foo/bar.go",
2322                         pkgIdent: "socketio",
2323                         pkg: &pkg{
2324                                 dir:             "/gopath/src/foo/socket-io",
2325                                 importPathShort: "foo/socket-io",
2326                         },
2327                         want: true,
2328                 },
2329                 {
2330                         name:     "match_with_mixed_case",
2331                         filename: "/gopath/src/foo/bar.go",
2332                         pkgIdent: "fooprod",
2333                         pkg: &pkg{
2334                                 dir:             "/gopath/src/foo/FooPROD",
2335                                 importPathShort: "foo/FooPROD",
2336                         },
2337                         want: true,
2338                 },
2339                 {
2340                         name:     "matches_with_hyphen_and_caps",
2341                         filename: "/gopath/src/foo/bar.go",
2342                         pkgIdent: "fooprod",
2343                         pkg: &pkg{
2344                                 dir:             "/gopath/src/foo/Foo-PROD",
2345                                 importPathShort: "foo/Foo-PROD",
2346                         },
2347                         want: true,
2348                 },
2349         }
2350         for i, tt := range tests {
2351                 t.Run(tt.name, func(t *testing.T) {
2352                         refs := references{tt.pkgIdent: nil}
2353                         got := pkgIsCandidate(tt.filename, refs, tt.pkg)
2354                         if got != tt.want {
2355                                 t.Errorf("test %d. pkgIsCandidate(%q, %q, %+v) = %v; want %v",
2356                                         i, tt.filename, tt.pkgIdent, *tt.pkg, got, tt.want)
2357                         }
2358                 })
2359         }
2360 }
2361
2362 // Issue 20941: this used to panic on Windows.
2363 func TestProcessStdin(t *testing.T) {
2364         testConfig{
2365                 module: packagestest.Module{
2366                         Name: "foo.com",
2367                 },
2368         }.test(t, func(t *goimportTest) {
2369                 got, err := t.processNonModule("<standard input>", []byte("package main\nfunc main() {\n\tfmt.Println(123)\n}\n"), nil)
2370                 if err != nil {
2371                         t.Fatal(err)
2372                 }
2373                 if !strings.Contains(string(got), `"fmt"`) {
2374                         t.Errorf("expected fmt import; got: %s", got)
2375                 }
2376         })
2377 }
2378
2379 // Tests LocalPackagePromotion when there is a local package that matches, it
2380 // should be the closest match.
2381 // https://golang.org/issues/17557
2382 func TestLocalPackagePromotion(t *testing.T) {
2383         const input = `package main
2384 var c = &config.SystemConfig{}
2385 `
2386         const want = `package main
2387
2388 import "mycompany.net/tool/config"
2389
2390 var c = &config.SystemConfig{}
2391 `
2392
2393         testConfig{
2394                 modules: []packagestest.Module{
2395                         {
2396                                 Name:  "config.net/config",
2397                                 Files: fm{"config.go": "package config\n type SystemConfig struct {}"}, // Will match but should not be first choice
2398                         },
2399                         {
2400                                 Name:  "mycompany.net/config",
2401                                 Files: fm{"config.go": "package config\n type SystemConfig struct {}"}, // Will match but should not be first choice
2402                         },
2403                         {
2404                                 Name: "mycompany.net/tool",
2405                                 Files: fm{
2406                                         "config/config.go": "package config\n type SystemConfig struct {}", // Local package should be promoted over shorter package
2407                                         "main.go":          input,
2408                                 },
2409                         },
2410                 },
2411         }.processTest(t, "mycompany.net/tool", "main.go", nil, nil, want)
2412 }
2413
2414 // Tests FindImportInLocalGoFiles looks at the import lines for other Go files in the
2415 // local directory, since the user is likely to import the same packages in the current
2416 // Go file.  If an import is found that satisfies the need, it should be used over the
2417 // standard library.
2418 // https://golang.org/issues/17557
2419 func TestFindImportInLocalGoFiles(t *testing.T) {
2420         const input = `package main
2421  var _ = &bytes.Buffer{}`
2422
2423         const want = `package main
2424
2425 import "bytes.net/bytes"
2426
2427 var _ = &bytes.Buffer{}
2428 `
2429         testConfig{
2430                 modules: []packagestest.Module{
2431                         {
2432                                 Name: "mycompany.net/tool",
2433                                 Files: fm{
2434                                         "io.go":   "package main\n import \"bytes.net/bytes\"\n var _ = &bytes.Buffer{}", // Contains package import that will cause stdlib to be ignored
2435                                         "main.go": input,
2436                                 },
2437                         },
2438                         {
2439                                 Name:  "bytes.net/bytes",
2440                                 Files: fm{"bytes.go": "package bytes\n type Buffer struct {}"}, // Should be selected over standard library
2441                         },
2442                 },
2443         }.processTest(t, "mycompany.net/tool", "main.go", nil, nil, want)
2444 }
2445
2446 func TestInMemoryFile(t *testing.T) {
2447         const input = `package main
2448  var _ = &bytes.Buffer{}`
2449
2450         const want = `package main
2451
2452 import "bytes"
2453
2454 var _ = &bytes.Buffer{}
2455 `
2456         testConfig{
2457                 module: packagestest.Module{
2458                         Name:  "foo.com",
2459                         Files: fm{"x.go": "package x\n"},
2460                 },
2461         }.processTest(t, "foo.com", "x.go", []byte(input), nil, want)
2462 }
2463
2464 func TestImportNoGoFiles(t *testing.T) {
2465         const input = `package main
2466  var _ = &bytes.Buffer{}`
2467
2468         const want = `package main
2469
2470 import "bytes"
2471
2472 var _ = &bytes.Buffer{}
2473 `
2474         testConfig{
2475                 module: packagestest.Module{
2476                         Name: "mycompany.net",
2477                 },
2478         }.test(t, func(t *goimportTest) {
2479                 buf, err := t.processNonModule("mycompany.net/tool/main.go", []byte(input), nil)
2480                 if err != nil {
2481                         t.Fatalf("Process() = %v", err)
2482                 }
2483                 if string(buf) != want {
2484                         t.Errorf("Got:\n%s\nWant:\n%s", buf, want)
2485                 }
2486         })
2487
2488 }
2489
2490 // Ensures a token as large as 500000 bytes can be handled
2491 // https://golang.org/issues/18201
2492 func TestProcessLargeToken(t *testing.T) {
2493         largeString := strings.Repeat("x", 500000)
2494
2495         input := `package testimports
2496
2497 import (
2498         "bytes"
2499 )
2500
2501 const s = fmt.Sprintf("%s", "` + largeString + `")
2502 var _ = bytes.Buffer{}
2503
2504 // end
2505 `
2506
2507         want := `package testimports
2508
2509 import (
2510         "bytes"
2511         "fmt"
2512 )
2513
2514 const s = fmt.Sprintf("%s", "` + largeString + `")
2515
2516 var _ = bytes.Buffer{}
2517
2518 // end
2519 `
2520
2521         testConfig{
2522                 module: packagestest.Module{
2523                         Name:  "foo.com",
2524                         Files: fm{"foo.go": input},
2525                 },
2526         }.processTest(t, "foo.com", "foo.go", nil, nil, want)
2527 }
2528
2529 // Tests that an external test package will import the package under test if it
2530 // also uses symbols exported only in test files.
2531 // https://golang.org/issues/29979
2532 func TestExternalTest(t *testing.T) {
2533         const input = `package a_test
2534 func TestX() {
2535         a.X()
2536         a.Y()
2537 }
2538 `
2539         const want = `package a_test
2540
2541 import "foo.com/a"
2542
2543 func TestX() {
2544         a.X()
2545         a.Y()
2546 }
2547 `
2548
2549         testConfig{
2550                 modules: []packagestest.Module{
2551                         {
2552                                 Name: "foo.com/a",
2553                                 Files: fm{
2554                                         "a.go":           "package a\n func X() {}",
2555                                         "export_test.go": "package a\n func Y() {}",
2556                                         "a_test.go":      input,
2557                                 },
2558                         },
2559                 },
2560         }.processTest(t, "foo.com/a", "a_test.go", nil, nil, want)
2561 }
2562
2563 // TestGetCandidates tests that get packages finds packages
2564 // with correct priorities.
2565 func TestGetCandidates(t *testing.T) {
2566         type res struct {
2567                 relevance  float64
2568                 name, path string
2569         }
2570         want := []res{
2571                 {0, "bytes", "bytes"},
2572                 {0, "http", "net/http"},
2573                 {0, "rand", "crypto/rand"},
2574                 {0, "bar", "bar.com/bar"},
2575                 {0, "foo", "foo.com/foo"},
2576         }
2577
2578         testConfig{
2579                 modules: []packagestest.Module{
2580                         {
2581                                 Name:  "bar.com",
2582                                 Files: fm{"bar/bar.go": "package bar\n"},
2583                         },
2584                         {
2585                                 Name:  "foo.com",
2586                                 Files: fm{"foo/foo.go": "package foo\n"},
2587                         },
2588                 },
2589         }.test(t, func(t *goimportTest) {
2590                 var mu sync.Mutex
2591                 var got []res
2592                 add := func(c ImportFix) {
2593                         mu.Lock()
2594                         defer mu.Unlock()
2595                         for _, w := range want {
2596                                 if c.StmtInfo.ImportPath == w.path {
2597                                         got = append(got, res{c.Relevance, c.IdentName, c.StmtInfo.ImportPath})
2598                                 }
2599                         }
2600                 }
2601                 if err := GetAllCandidates(context.Background(), add, "", "x.go", "x", t.env); err != nil {
2602                         t.Fatalf("GetAllCandidates() = %v", err)
2603                 }
2604                 // Sort, then clear out relevance so it doesn't mess up the DeepEqual.
2605                 sort.Slice(got, func(i, j int) bool {
2606                         ri, rj := got[i], got[j]
2607                         if ri.relevance != rj.relevance {
2608                                 return ri.relevance > rj.relevance // Highest first.
2609                         }
2610                         return ri.name < rj.name
2611                 })
2612                 for i := range got {
2613                         got[i].relevance = 0
2614                 }
2615                 if !reflect.DeepEqual(want, got) {
2616                         t.Errorf("wanted results in order %v, got %v", want, got)
2617                 }
2618         })
2619 }
2620
2621 func TestGetImportPaths(t *testing.T) {
2622         type res struct {
2623                 relevance  float64
2624                 name, path string
2625         }
2626         want := []res{
2627                 {0, "http", "net/http"},
2628                 {0, "net", "net"},
2629                 {0, "neta", "neta.com/neta"},
2630         }
2631
2632         testConfig{
2633                 modules: []packagestest.Module{
2634                         {
2635                                 Name:  "neta.com",
2636                                 Files: fm{"neta/neta.go": "package neta\n"},
2637                         },
2638                 },
2639         }.test(t, func(t *goimportTest) {
2640                 var mu sync.Mutex
2641                 var got []res
2642                 add := func(c ImportFix) {
2643                         mu.Lock()
2644                         defer mu.Unlock()
2645                         for _, w := range want {
2646                                 if c.StmtInfo.ImportPath == w.path {
2647                                         got = append(got, res{c.Relevance, c.IdentName, c.StmtInfo.ImportPath})
2648                                 }
2649                         }
2650                 }
2651                 if err := GetImportPaths(context.Background(), add, "ne", "x.go", "x", t.env); err != nil {
2652                         t.Fatalf("GetImportPaths() = %v", err)
2653                 }
2654                 // Sort, then clear out relevance so it doesn't mess up the DeepEqual.
2655                 sort.Slice(got, func(i, j int) bool {
2656                         ri, rj := got[i], got[j]
2657                         if ri.relevance != rj.relevance {
2658                                 return ri.relevance > rj.relevance // Highest first.
2659                         }
2660                         return ri.name < rj.name
2661                 })
2662                 for i := range got {
2663                         got[i].relevance = 0
2664                 }
2665                 if !reflect.DeepEqual(want, got) {
2666                         t.Errorf("wanted results in order %v, got %v", want, got)
2667                 }
2668         })
2669 }
2670
2671 func TestGetPackageCompletions(t *testing.T) {
2672         type res struct {
2673                 relevance          float64
2674                 name, path, symbol string
2675         }
2676         want := []res{
2677                 {0, "rand", "math/rand", "Seed"},
2678                 {0, "rand", "bar.com/rand", "Bar"},
2679         }
2680
2681         testConfig{
2682                 modules: []packagestest.Module{
2683                         {
2684                                 Name:  "bar.com",
2685                                 Files: fm{"rand/bar.go": "package rand\nvar Bar int\n"},
2686                         },
2687                 },
2688         }.test(t, func(t *goimportTest) {
2689                 var mu sync.Mutex
2690                 var got []res
2691                 add := func(c PackageExport) {
2692                         mu.Lock()
2693                         defer mu.Unlock()
2694                         for _, csym := range c.Exports {
2695                                 for _, w := range want {
2696                                         if c.Fix.StmtInfo.ImportPath == w.path && csym == w.symbol {
2697                                                 got = append(got, res{c.Fix.Relevance, c.Fix.IdentName, c.Fix.StmtInfo.ImportPath, csym})
2698                                         }
2699                                 }
2700                         }
2701                 }
2702                 if err := GetPackageExports(context.Background(), add, "rand", "x.go", "x", t.env); err != nil {
2703                         t.Fatalf("getPackageCompletions() = %v", err)
2704                 }
2705                 // Sort, then clear out relevance so it doesn't mess up the DeepEqual.
2706                 sort.Slice(got, func(i, j int) bool {
2707                         ri, rj := got[i], got[j]
2708                         if ri.relevance != rj.relevance {
2709                                 return ri.relevance > rj.relevance // Highest first.
2710                         }
2711                         return ri.name < rj.name
2712                 })
2713                 for i := range got {
2714                         got[i].relevance = 0
2715                 }
2716                 if !reflect.DeepEqual(want, got) {
2717                         t.Errorf("wanted results in order %v, got %v", want, got)
2718                 }
2719         })
2720 }
2721
2722 // Tests #34895: process should not panic on concurrent calls.
2723 func TestConcurrentProcess(t *testing.T) {
2724         testConfig{
2725                 module: packagestest.Module{
2726                         Name: "foo.com",
2727                         Files: fm{
2728                                 "p/first.go": `package foo
2729
2730 func _() {
2731         fmt.Println()
2732 }
2733 `,
2734                                 "p/second.go": `package foo
2735
2736 import "fmt"
2737
2738 func _() {
2739         fmt.Println()
2740         imports.Bar() // not imported.
2741 }
2742 `,
2743                         },
2744                 },
2745         }.test(t, func(t *goimportTest) {
2746                 var (
2747                         n  = 10
2748                         wg sync.WaitGroup
2749                 )
2750                 wg.Add(n)
2751                 for i := 0; i < n; i++ {
2752                         go func() {
2753                                 defer wg.Done()
2754                                 _, err := t.process("foo.com", "p/first.go", nil, nil)
2755                                 if err != nil {
2756                                         t.Error(err)
2757                                 }
2758                         }()
2759                 }
2760                 wg.Wait()
2761         })
2762 }
2763
2764 func TestNonlocalDot(t *testing.T) {
2765         const input = `package main
2766 import (
2767         "fmt"
2768 )
2769 var _, _ = fmt.Sprintf, dot.Dot
2770 `
2771         const want = `package main
2772
2773 import (
2774         "fmt"
2775         "noninternet/dot.v1/dot"
2776 )
2777
2778 var _, _ = fmt.Sprintf, dot.Dot
2779 `
2780         testConfig{
2781                 modules: []packagestest.Module{
2782                         {
2783                                 Name:  "golang.org/fake",
2784                                 Files: fm{"x.go": input},
2785                         },
2786                         {
2787                                 Name: "noninternet/dot.v1",
2788                                 Files: fm{
2789                                         "dot/dot.go": "package dot\nfunc Dot(){}\n",
2790                                 },
2791                         },
2792                 },
2793                 gopathOnly: true, // our modules testing setup doesn't allow modules without dots.
2794         }.processTest(t, "golang.org/fake", "x.go", nil, nil, want)
2795 }