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 / go / packages / overlay_test.go
1 package packages_test
2
3 import (
4         "fmt"
5         "io/ioutil"
6         "log"
7         "os"
8         "path/filepath"
9         "reflect"
10         "sort"
11         "testing"
12
13         "golang.org/x/tools/go/packages"
14         "golang.org/x/tools/go/packages/packagestest"
15         "golang.org/x/tools/internal/testenv"
16 )
17
18 const (
19         commonMode = packages.NeedName | packages.NeedFiles |
20                 packages.NeedCompiledGoFiles | packages.NeedImports | packages.NeedSyntax
21         everythingMode = commonMode | packages.NeedDeps | packages.NeedTypes |
22                 packages.NeedTypesSizes
23 )
24
25 func TestOverlayChangesPackageName(t *testing.T) {
26         packagestest.TestAll(t, testOverlayChangesPackageName)
27 }
28 func testOverlayChangesPackageName(t *testing.T, exporter packagestest.Exporter) {
29         log.SetFlags(log.Lshortfile)
30         exported := packagestest.Export(t, exporter, []packagestest.Module{{
31                 Name: "fake",
32                 Files: map[string]interface{}{
33                         "a.go": "package foo\nfunc f(){}\n",
34                 },
35                 Overlay: map[string][]byte{
36                         "a.go": []byte("package foox\nfunc f(){}\n"),
37                 },
38         }})
39         defer exported.Cleanup()
40         exported.Config.Mode = packages.NeedName
41
42         initial, err := packages.Load(exported.Config,
43                 filepath.Dir(exported.File("fake", "a.go")))
44         if err != nil {
45                 t.Fatalf("failed to load: %v", err)
46         }
47         if len(initial) != 1 || initial[0].ID != "fake" || initial[0].Name != "foox" {
48                 t.Fatalf("got %v, expected [fake]", initial)
49         }
50         if len(initial[0].Errors) != 0 {
51                 t.Fatalf("got %v, expected no errors", initial[0].Errors)
52         }
53         log.SetFlags(0)
54 }
55 func TestOverlayChangesBothPackageNames(t *testing.T) {
56         packagestest.TestAll(t, testOverlayChangesBothPackageNames)
57 }
58 func testOverlayChangesBothPackageNames(t *testing.T, exporter packagestest.Exporter) {
59         log.SetFlags(log.Lshortfile)
60         exported := packagestest.Export(t, exporter, []packagestest.Module{{
61                 Name: "fake",
62                 Files: map[string]interface{}{
63                         "a.go":      "package foo\nfunc g(){}\n",
64                         "a_test.go": "package foo\nfunc f(){}\n",
65                 },
66                 Overlay: map[string][]byte{
67                         "a.go":      []byte("package foox\nfunc g(){}\n"),
68                         "a_test.go": []byte("package foox\nfunc f(){}\n"),
69                 },
70         }})
71         defer exported.Cleanup()
72         exported.Config.Mode = commonMode
73
74         initial, err := packages.Load(exported.Config,
75                 filepath.Dir(exported.File("fake", "a.go")))
76         if err != nil {
77                 t.Fatalf("failed to load: %v", err)
78         }
79         if len(initial) != 3 {
80                 t.Errorf("got %d packges, expected 3", len(initial))
81         }
82         want := []struct {
83                 id, name string
84                 count    int
85         }{
86                 {"fake", "foox", 1},
87                 {"fake [fake.test]", "foox", 2},
88                 {"fake.test", "main", 1},
89         }
90         for i := 0; i < 3; i++ {
91                 if ok := checkPkg(t, initial[i], want[i].id, want[i].name, want[i].count); !ok {
92                         t.Errorf("%d: got {%s %s %d}, expected %v", i, initial[i].ID,
93                                 initial[i].Name, len(initial[i].Syntax), want[i])
94                 }
95                 if len(initial[i].Errors) != 0 {
96                         t.Errorf("%d: got %v, expected no errors", i, initial[i].Errors)
97                 }
98         }
99         log.SetFlags(0)
100 }
101 func TestOverlayChangesTestPackageName(t *testing.T) {
102         packagestest.TestAll(t, testOverlayChangesTestPackageName)
103 }
104 func testOverlayChangesTestPackageName(t *testing.T, exporter packagestest.Exporter) {
105         log.SetFlags(log.Lshortfile)
106         exported := packagestest.Export(t, exporter, []packagestest.Module{{
107                 Name: "fake",
108                 Files: map[string]interface{}{
109                         "a_test.go": "package foo\nfunc f(){}\n",
110                 },
111                 Overlay: map[string][]byte{
112                         "a_test.go": []byte("package foox\nfunc f(){}\n"),
113                 },
114         }})
115         defer exported.Cleanup()
116         exported.Config.Mode = commonMode
117
118         initial, err := packages.Load(exported.Config,
119                 filepath.Dir(exported.File("fake", "a_test.go")))
120         if err != nil {
121                 t.Fatalf("failed to load: %v", err)
122         }
123         if len(initial) != 3 {
124                 t.Errorf("got %d packges, expected 3", len(initial))
125         }
126         want := []struct {
127                 id, name string
128                 count    int
129         }{
130                 {"fake", "foo", 0},
131                 {"fake [fake.test]", "foox", 1},
132                 {"fake.test", "main", 1},
133         }
134         for i := 0; i < 3; i++ {
135                 if ok := checkPkg(t, initial[i], want[i].id, want[i].name, want[i].count); !ok {
136                         t.Errorf("got {%s %s %d}, expected %v", initial[i].ID,
137                                 initial[i].Name, len(initial[i].Syntax), want[i])
138                 }
139         }
140         if len(initial[0].Errors) != 0 {
141                 t.Fatalf("got %v, expected no errors", initial[0].Errors)
142         }
143         log.SetFlags(0)
144 }
145
146 func checkPkg(t *testing.T, p *packages.Package, id, name string, syntax int) bool {
147         t.Helper()
148         if p.ID == id && p.Name == name && len(p.Syntax) == syntax {
149                 return true
150         }
151         return false
152 }
153
154 func TestOverlayXTests(t *testing.T) {
155         packagestest.TestAll(t, testOverlayXTests)
156 }
157
158 // This test checks the behavior of go/packages.Load with an overlaid
159 // x test. The source of truth is the go/packages.Load results for the
160 // exact same package, just on-disk.
161 func testOverlayXTests(t *testing.T, exporter packagestest.Exporter) {
162         const aFile = `package a; const C = "C"; func Hello() {}`
163         const aTestVariant = `package a
164
165 import "testing"
166
167 const TestC = "test" + C
168
169 func TestHello(){
170         Hello()
171 }`
172         const aXTest = `package a_test
173
174 import (
175         "testing"
176
177         "golang.org/fake/a"
178 )
179
180 const xTestC = "x" + a.C
181
182 func TestHello(t *testing.T) {
183         a.Hello()
184 }`
185
186         // First, get the source of truth by loading the package, all on disk.
187         onDisk := packagestest.Export(t, exporter, []packagestest.Module{{
188                 Name: "golang.org/fake",
189                 Files: map[string]interface{}{
190                         "a/a.go":        aFile,
191                         "a/a_test.go":   aTestVariant,
192                         "a/a_x_test.go": aXTest,
193                 },
194         }})
195         defer onDisk.Cleanup()
196
197         onDisk.Config.Mode = commonMode
198         onDisk.Config.Tests = true
199         onDisk.Config.Mode = packages.LoadTypes
200         initial, err := packages.Load(onDisk.Config, fmt.Sprintf("file=%s", onDisk.File("golang.org/fake", "a/a_x_test.go")))
201         if err != nil {
202                 t.Fatal(err)
203         }
204         wantPkg := initial[0]
205
206         exported := packagestest.Export(t, exporter, []packagestest.Module{{
207                 Name: "golang.org/fake",
208                 Files: map[string]interface{}{
209                         "a/a.go":        aFile,
210                         "a/a_test.go":   aTestVariant,
211                         "a/a_x_test.go": ``, // empty x test on disk
212                 },
213                 Overlay: map[string][]byte{
214                         "a/a_x_test.go": []byte(aXTest),
215                 },
216         }})
217         defer exported.Cleanup()
218
219         if len(initial) != 1 {
220                 t.Fatalf("expected 1 package, got %d", len(initial))
221         }
222         // Confirm that the overlaid package is identical to the on-disk version.
223         pkg := initial[0]
224         if !reflect.DeepEqual(wantPkg, pkg) {
225                 t.Fatalf("mismatched packages: want %#v, got %#v", wantPkg, pkg)
226         }
227         xTestC := constant(pkg, "xTestC")
228         if xTestC == nil {
229                 t.Fatalf("no value for xTestC")
230         }
231         got := xTestC.Val().String()
232         // TODO(rstambler): Ideally, this test would check that the test variant
233         // was imported, but that's pretty complicated.
234         if want := `"xC"`; got != want {
235                 t.Errorf("got: %q, want %q", got, want)
236         }
237 }
238
239 func TestOverlay(t *testing.T) { packagestest.TestAll(t, testOverlay) }
240 func testOverlay(t *testing.T, exporter packagestest.Exporter) {
241         exported := packagestest.Export(t, exporter, []packagestest.Module{{
242                 Name: "golang.org/fake",
243                 Files: map[string]interface{}{
244                         "a/a.go":      `package a; import "golang.org/fake/b"; const A = "a" + b.B`,
245                         "b/b.go":      `package b; import "golang.org/fake/c"; const B = "b" + c.C`,
246                         "c/c.go":      `package c; const C = "c"`,
247                         "c/c_test.go": `package c; import "testing"; func TestC(t *testing.T) {}`,
248                         "d/d.go":      `package d; const D = "d"`,
249                 }}})
250         defer exported.Cleanup()
251
252         for i, test := range []struct {
253                 overlay  map[string][]byte
254                 want     string // expected value of a.A
255                 wantErrs []string
256         }{
257                 {nil, `"abc"`, nil},                 // default
258                 {map[string][]byte{}, `"abc"`, nil}, // empty overlay
259                 {map[string][]byte{exported.File("golang.org/fake", "c/c.go"): []byte(`package c; const C = "C"`)}, `"abC"`, nil},
260                 {map[string][]byte{exported.File("golang.org/fake", "b/b.go"): []byte(`package b; import "golang.org/fake/c"; const B = "B" + c.C`)}, `"aBc"`, nil},
261                 // Overlay with an existing file in an existing package adding a new import.
262                 {map[string][]byte{exported.File("golang.org/fake", "b/b.go"): []byte(`package b; import "golang.org/fake/d"; const B = "B" + d.D`)}, `"aBd"`, nil},
263                 // Overlay with an existing file in an existing package.
264                 {map[string][]byte{exported.File("golang.org/fake", "c/c.go"): []byte(`package c; import "net/http"; const C = http.MethodGet`)}, `"abGET"`, nil},
265                 // Overlay with a new file in an existing package.
266                 {map[string][]byte{
267                         exported.File("golang.org/fake", "c/c.go"):                                               []byte(`package c;`),
268                         filepath.Join(filepath.Dir(exported.File("golang.org/fake", "c/c.go")), "c_new_file.go"): []byte(`package c; const C = "Ç"`)},
269                         `"abÇ"`, nil},
270                 // Overlay with a new file in an existing package, adding a new dependency to that package.
271                 {map[string][]byte{
272                         exported.File("golang.org/fake", "c/c.go"):                                               []byte(`package c;`),
273                         filepath.Join(filepath.Dir(exported.File("golang.org/fake", "c/c.go")), "c_new_file.go"): []byte(`package c; import "golang.org/fake/d"; const C = "c" + d.D`)},
274                         `"abcd"`, nil},
275         } {
276                 exported.Config.Overlay = test.overlay
277                 exported.Config.Mode = packages.LoadAllSyntax
278                 initial, err := packages.Load(exported.Config, "golang.org/fake/a")
279                 if err != nil {
280                         t.Error(err)
281                         continue
282                 }
283
284                 // Check value of a.A.
285                 a := initial[0]
286                 aA := constant(a, "A")
287                 if aA == nil {
288                         t.Errorf("%d. a.A: got nil", i)
289                         continue
290                 }
291                 got := aA.Val().String()
292                 if got != test.want {
293                         t.Errorf("%d. a.A: got %s, want %s", i, got, test.want)
294                 }
295
296                 // Check errors.
297                 var errors []packages.Error
298                 packages.Visit(initial, nil, func(pkg *packages.Package) {
299                         errors = append(errors, pkg.Errors...)
300                 })
301                 if errs := errorMessages(errors); !reflect.DeepEqual(errs, test.wantErrs) {
302                         t.Errorf("%d. got errors %s, want %s", i, errs, test.wantErrs)
303                 }
304         }
305 }
306
307 func TestOverlayDeps(t *testing.T) { packagestest.TestAll(t, testOverlayDeps) }
308 func testOverlayDeps(t *testing.T, exporter packagestest.Exporter) {
309         exported := packagestest.Export(t, exporter, []packagestest.Module{{
310                 Name: "golang.org/fake",
311                 Files: map[string]interface{}{
312                         "c/c.go":      `package c; const C = "c"`,
313                         "c/c_test.go": `package c; import "testing"; func TestC(t *testing.T) {}`,
314                 },
315         }})
316         defer exported.Cleanup()
317
318         exported.Config.Overlay = map[string][]byte{exported.File("golang.org/fake", "c/c.go"): []byte(`package c; import "net/http"; const C = http.MethodGet`)}
319         exported.Config.Mode = packages.NeedName |
320                 packages.NeedFiles |
321                 packages.NeedCompiledGoFiles |
322                 packages.NeedImports |
323                 packages.NeedDeps |
324                 packages.NeedTypesSizes
325         pkgs, err := packages.Load(exported.Config, fmt.Sprintf("file=%s", exported.File("golang.org/fake", "c/c.go")))
326         if err != nil {
327                 t.Error(err)
328         }
329
330         // Find package golang.org/fake/c
331         sort.Slice(pkgs, func(i, j int) bool { return pkgs[i].ID < pkgs[j].ID })
332         pkgc := pkgs[0]
333         if pkgc.ID != "golang.org/fake/c" {
334                 t.Errorf("expected first package in sorted list to be \"golang.org/fake/c\", got %v", pkgc.ID)
335         }
336
337         // Make sure golang.org/fake/c imports net/http, as per the overlay.
338         contains := func(imports map[string]*packages.Package, wantImport string) bool {
339                 for imp := range imports {
340                         if imp == wantImport {
341                                 return true
342                         }
343                 }
344                 return false
345         }
346         if !contains(pkgc.Imports, "net/http") {
347                 t.Errorf("expected import of %s in package %s, got the following imports: %v",
348                         "net/http", pkgc.ID, pkgc.Imports)
349         }
350
351 }
352
353 func TestNewPackagesInOverlay(t *testing.T) { packagestest.TestAll(t, testNewPackagesInOverlay) }
354 func testNewPackagesInOverlay(t *testing.T, exporter packagestest.Exporter) {
355         exported := packagestest.Export(t, exporter, []packagestest.Module{
356                 {
357                         Name: "golang.org/fake",
358                         Files: map[string]interface{}{
359                                 "a/a.go": `package a; import "golang.org/fake/b"; const A = "a" + b.B`,
360                                 "b/b.go": `package b; import "golang.org/fake/c"; const B = "b" + c.C`,
361                                 "c/c.go": `package c; const C = "c"`,
362                                 "d/d.go": `package d; const D = "d"`,
363                         },
364                 },
365                 {
366                         Name: "example.com/extramodule",
367                         Files: map[string]interface{}{
368                                 "pkg/x.go": "package pkg\n",
369                         },
370                 },
371         })
372         defer exported.Cleanup()
373
374         dir := filepath.Dir(filepath.Dir(exported.File("golang.org/fake", "a/a.go")))
375
376         for _, test := range []struct {
377                 name    string
378                 overlay map[string][]byte
379                 want    string // expected value of e.E
380         }{
381                 {"one_file",
382                         map[string][]byte{
383                                 filepath.Join(dir, "e", "e.go"): []byte(`package e; import "golang.org/fake/a"; const E = "e" + a.A`)},
384                         `"eabc"`},
385                 {"multiple_files_same_package",
386                         map[string][]byte{
387                                 filepath.Join(dir, "e", "e.go"):      []byte(`package e; import "golang.org/fake/a"; const E = "e" + a.A + underscore`),
388                                 filepath.Join(dir, "e", "e_util.go"): []byte(`package e; const underscore = "_"`),
389                         },
390                         `"eabc_"`},
391                 {"multiple_files_two_packages",
392                         map[string][]byte{
393                                 filepath.Join(dir, "e", "e.go"):      []byte(`package e; import "golang.org/fake/f"; const E = "e" + f.F + underscore`),
394                                 filepath.Join(dir, "e", "e_util.go"): []byte(`package e; const underscore = "_"`),
395                                 filepath.Join(dir, "f", "f.go"):      []byte(`package f; const F = "f"`),
396                         },
397                         `"ef_"`},
398                 {"multiple_files_three_packages",
399                         map[string][]byte{
400                                 filepath.Join(dir, "e", "e.go"):      []byte(`package e; import "golang.org/fake/f"; const E = "e" + f.F + underscore`),
401                                 filepath.Join(dir, "e", "e_util.go"): []byte(`package e; const underscore = "_"`),
402                                 filepath.Join(dir, "f", "f.go"):      []byte(`package f; import "golang.org/fake/g"; const F = "f" + g.G`),
403                                 filepath.Join(dir, "g", "g.go"):      []byte(`package g; const G = "g"`),
404                         },
405                         `"efg_"`},
406                 {"multiple_files_four_packages",
407                         map[string][]byte{
408                                 filepath.Join(dir, "e", "e.go"):      []byte(`package e; import "golang.org/fake/f"; import "golang.org/fake/h"; const E = "e" + f.F + h.H + underscore`),
409                                 filepath.Join(dir, "e", "e_util.go"): []byte(`package e; const underscore = "_"`),
410                                 filepath.Join(dir, "f", "f.go"):      []byte(`package f; import "golang.org/fake/g"; const F = "f" + g.G`),
411                                 filepath.Join(dir, "g", "g.go"):      []byte(`package g; const G = "g"`),
412                                 filepath.Join(dir, "h", "h.go"):      []byte(`package h; const H = "h"`),
413                         },
414                         `"efgh_"`},
415                 {"multiple_files_four_packages_again",
416                         map[string][]byte{
417                                 filepath.Join(dir, "e", "e.go"):      []byte(`package e; import "golang.org/fake/f"; const E = "e" + f.F + underscore`),
418                                 filepath.Join(dir, "e", "e_util.go"): []byte(`package e; const underscore = "_"`),
419                                 filepath.Join(dir, "f", "f.go"):      []byte(`package f; import "golang.org/fake/g"; const F = "f" + g.G`),
420                                 filepath.Join(dir, "g", "g.go"):      []byte(`package g; import "golang.org/fake/h"; const G = "g" + h.H`),
421                                 filepath.Join(dir, "h", "h.go"):      []byte(`package h; const H = "h"`),
422                         },
423                         `"efgh_"`},
424                 {"main_overlay",
425                         map[string][]byte{
426                                 filepath.Join(dir, "e", "main.go"): []byte(`package main; import "golang.org/fake/a"; const E = "e" + a.A; func main(){}`)},
427                         `"eabc"`},
428         } {
429                 t.Run(test.name, func(t *testing.T) {
430                         exported.Config.Overlay = test.overlay
431                         exported.Config.Mode = packages.LoadAllSyntax
432                         exported.Config.Logf = t.Logf
433
434                         // With an overlay, we don't know the expected import path,
435                         // so load with the absolute path of the directory.
436                         initial, err := packages.Load(exported.Config, filepath.Join(dir, "e"))
437                         if err != nil {
438                                 t.Fatal(err)
439                         }
440
441                         // Check value of e.E.
442                         e := initial[0]
443                         eE := constant(e, "E")
444                         if eE == nil {
445                                 t.Fatalf("e.E: was nil in %#v", e)
446                         }
447                         got := eE.Val().String()
448                         if got != test.want {
449                                 t.Fatalf("e.E: got %s, want %s", got, test.want)
450                         }
451                 })
452         }
453 }
454
455 // Test that we can create a package and its test package in an overlay.
456 func TestOverlayNewPackageAndTest(t *testing.T) {
457         packagestest.TestAll(t, testOverlayNewPackageAndTest)
458 }
459 func testOverlayNewPackageAndTest(t *testing.T, exporter packagestest.Exporter) {
460         exported := packagestest.Export(t, exporter, []packagestest.Module{
461                 {
462                         Name: "golang.org/fake",
463                         Files: map[string]interface{}{
464                                 "foo.txt": "placeholder",
465                         },
466                 },
467         })
468         defer exported.Cleanup()
469
470         dir := filepath.Dir(exported.File("golang.org/fake", "foo.txt"))
471         exported.Config.Overlay = map[string][]byte{
472                 filepath.Join(dir, "a.go"):      []byte(`package a;`),
473                 filepath.Join(dir, "a_test.go"): []byte(`package a; import "testing";`),
474         }
475         initial, err := packages.Load(exported.Config, "file="+filepath.Join(dir, "a.go"), "file="+filepath.Join(dir, "a_test.go"))
476         if err != nil {
477                 t.Fatal(err)
478         }
479         if len(initial) != 2 {
480                 t.Errorf("got %v packages, wanted %v", len(initial), 2)
481         }
482 }
483
484 func TestAdHocOverlays(t *testing.T) {
485         testenv.NeedsTool(t, "go")
486
487         // This test doesn't use packagestest because we are testing ad-hoc packages,
488         // which are outside of $GOPATH and outside of a module.
489         tmp, err := ioutil.TempDir("", "testAdHocOverlays")
490         if err != nil {
491                 t.Fatal(err)
492         }
493         defer os.RemoveAll(tmp)
494
495         filename := filepath.Join(tmp, "a.go")
496         content := []byte(`package a
497 const A = 1
498 `)
499
500         // Make sure that the user's value of GO111MODULE does not affect test results.
501         for _, go111module := range []string{"off", "auto", "on"} {
502                 t.Run("GO111MODULE="+go111module, func(t *testing.T) {
503                         config := &packages.Config{
504                                 Dir:  tmp,
505                                 Env:  append(os.Environ(), "GOPACKAGESDRIVER=off", fmt.Sprintf("GO111MODULE=%s", go111module)),
506                                 Mode: packages.LoadAllSyntax,
507                                 Overlay: map[string][]byte{
508                                         filename: content,
509                                 },
510                                 Logf: t.Logf,
511                         }
512                         initial, err := packages.Load(config, fmt.Sprintf("file=%s", filename))
513                         if err != nil {
514                                 t.Fatal(err)
515                         }
516                         if len(initial) == 0 {
517                                 t.Fatalf("no packages for %s", filename)
518                         }
519                         // Check value of a.A.
520                         a := initial[0]
521                         if a.Errors != nil {
522                                 t.Fatalf("a: got errors %+v, want no error", err)
523                         }
524                         aA := constant(a, "A")
525                         if aA == nil {
526                                 t.Errorf("a.A: got nil")
527                                 return
528                         }
529                         got := aA.Val().String()
530                         if want := "1"; got != want {
531                                 t.Errorf("a.A: got %s, want %s", got, want)
532                         }
533                 })
534         }
535 }
536
537 // TestOverlayModFileChanges tests the behavior resulting from having files
538 // from multiple modules in overlays.
539 func TestOverlayModFileChanges(t *testing.T) {
540         testenv.NeedsTool(t, "go")
541
542         // Create two unrelated modules in a temporary directory.
543         tmp, err := ioutil.TempDir("", "tmp")
544         if err != nil {
545                 t.Fatal(err)
546         }
547         defer os.RemoveAll(tmp)
548
549         // mod1 has a dependency on golang.org/x/xerrors.
550         mod1, err := ioutil.TempDir(tmp, "mod1")
551         if err != nil {
552                 t.Fatal(err)
553         }
554         if err := ioutil.WriteFile(filepath.Join(mod1, "go.mod"), []byte(`module mod1
555
556         require (
557                 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7
558         )
559         `), 0775); err != nil {
560                 t.Fatal(err)
561         }
562
563         // mod2 does not have any dependencies.
564         mod2, err := ioutil.TempDir(tmp, "mod2")
565         if err != nil {
566                 t.Fatal(err)
567         }
568
569         want := `module mod2
570
571 go 1.11
572 `
573         if err := ioutil.WriteFile(filepath.Join(mod2, "go.mod"), []byte(want), 0775); err != nil {
574                 t.Fatal(err)
575         }
576
577         // Run packages.Load on mod2, while passing the contents over mod1/main.go in the overlay.
578         config := &packages.Config{
579                 Dir:  mod2,
580                 Env:  append(os.Environ(), "GOPACKAGESDRIVER=off"),
581                 Mode: packages.LoadImports,
582                 Overlay: map[string][]byte{
583                         filepath.Join(mod1, "main.go"): []byte(`package main
584 import "golang.org/x/xerrors"
585 func main() {
586         _ = errors.New("")
587 }
588 `),
589                         filepath.Join(mod2, "main.go"): []byte(`package main
590 func main() {}
591 `),
592                 },
593         }
594         if _, err := packages.Load(config, fmt.Sprintf("file=%s", filepath.Join(mod2, "main.go"))); err != nil {
595                 t.Fatal(err)
596         }
597
598         // Check that mod2/go.mod has not been modified.
599         got, err := ioutil.ReadFile(filepath.Join(mod2, "go.mod"))
600         if err != nil {
601                 t.Fatal(err)
602         }
603         if string(got) != want {
604                 t.Errorf("expected %s, got %s", want, string(got))
605         }
606 }
607
608 func TestOverlayGOPATHVendoring(t *testing.T) {
609         exported := packagestest.Export(t, packagestest.GOPATH, []packagestest.Module{{
610                 Name: "golang.org/fake",
611                 Files: map[string]interface{}{
612                         "vendor/vendor.com/foo/foo.go": `package foo; const X = "hi"`,
613                         "user/user.go":                 `package user`,
614                 },
615         }})
616         defer exported.Cleanup()
617
618         exported.Config.Mode = packages.LoadAllSyntax
619         exported.Config.Logf = t.Logf
620         exported.Config.Overlay = map[string][]byte{
621                 exported.File("golang.org/fake", "user/user.go"): []byte(`package user; import "vendor.com/foo"; var x = foo.X`),
622         }
623         initial, err := packages.Load(exported.Config, "golang.org/fake/user")
624         if err != nil {
625                 t.Fatal(err)
626         }
627         user := initial[0]
628         if len(user.Imports) != 1 {
629                 t.Fatal("no imports for user")
630         }
631         if user.Imports["vendor.com/foo"].Name != "foo" {
632                 t.Errorf("failed to load vendored package foo, imports: %#v", user.Imports["vendor.com/foo"])
633         }
634 }
635
636 func TestContainsOverlay(t *testing.T) { packagestest.TestAll(t, testContainsOverlay) }
637 func testContainsOverlay(t *testing.T, exporter packagestest.Exporter) {
638         exported := packagestest.Export(t, exporter, []packagestest.Module{{
639                 Name: "golang.org/fake",
640                 Files: map[string]interface{}{
641                         "a/a.go": `package a; import "golang.org/fake/b"`,
642                         "b/b.go": `package b; import "golang.org/fake/c"`,
643                         "c/c.go": `package c`,
644                 }}})
645         defer exported.Cleanup()
646         bOverlayFile := filepath.Join(filepath.Dir(exported.File("golang.org/fake", "b/b.go")), "b_overlay.go")
647         exported.Config.Mode = packages.LoadImports
648         exported.Config.Overlay = map[string][]byte{bOverlayFile: []byte(`package b;`)}
649         initial, err := packages.Load(exported.Config, "file="+bOverlayFile)
650         if err != nil {
651                 t.Fatal(err)
652         }
653
654         graph, _ := importGraph(initial)
655         wantGraph := `
656 * golang.org/fake/b
657   golang.org/fake/c
658   golang.org/fake/b -> golang.org/fake/c
659 `[1:]
660         if graph != wantGraph {
661                 t.Errorf("wrong import graph: got <<%s>>, want <<%s>>", graph, wantGraph)
662         }
663 }
664
665 func TestContainsOverlayXTest(t *testing.T) { packagestest.TestAll(t, testContainsOverlayXTest) }
666 func testContainsOverlayXTest(t *testing.T, exporter packagestest.Exporter) {
667         exported := packagestest.Export(t, exporter, []packagestest.Module{{
668                 Name: "golang.org/fake",
669                 Files: map[string]interface{}{
670                         "a/a.go": `package a; import "golang.org/fake/b"`,
671                         "b/b.go": `package b; import "golang.org/fake/c"`,
672                         "c/c.go": `package c`,
673                 }}})
674         defer exported.Cleanup()
675
676         bOverlayXTestFile := filepath.Join(filepath.Dir(exported.File("golang.org/fake", "b/b.go")), "b_overlay_x_test.go")
677         exported.Config.Mode = packages.NeedName | packages.NeedFiles | packages.NeedImports
678         exported.Config.Overlay = map[string][]byte{bOverlayXTestFile: []byte(`package b_test; import "golang.org/fake/b"`)}
679         initial, err := packages.Load(exported.Config, "file="+bOverlayXTestFile)
680         if err != nil {
681                 t.Fatal(err)
682         }
683
684         graph, _ := importGraph(initial)
685         wantGraph := `
686   golang.org/fake/b
687 * golang.org/fake/b_test [golang.org/fake/b.test]
688   golang.org/fake/c
689   golang.org/fake/b -> golang.org/fake/c
690   golang.org/fake/b_test [golang.org/fake/b.test] -> golang.org/fake/b
691 `[1:]
692         if graph != wantGraph {
693                 t.Errorf("wrong import graph: got <<%s>>, want <<%s>>", graph, wantGraph)
694         }
695 }
696
697 func TestInvalidFilesBeforeOverlay(t *testing.T) {
698         packagestest.TestAll(t, testInvalidFilesBeforeOverlay)
699 }
700
701 func testInvalidFilesBeforeOverlay(t *testing.T, exporter packagestest.Exporter) {
702         testenv.NeedsGo1Point(t, 15)
703
704         exported := packagestest.Export(t, exporter, []packagestest.Module{
705                 {
706                         Name: "golang.org/fake",
707                         Files: map[string]interface{}{
708                                 "d/d.go":  ``,
709                                 "main.go": ``,
710                         },
711                 },
712         })
713         defer exported.Cleanup()
714
715         dir := filepath.Dir(filepath.Dir(exported.File("golang.org/fake", "d/d.go")))
716
717         exported.Config.Mode = everythingMode
718         exported.Config.Tests = true
719
720         // First, check that all packages returned have files associated with them.
721         // Tests the work-around for golang/go#39986.
722         t.Run("no overlay", func(t *testing.T) {
723                 initial, err := packages.Load(exported.Config, fmt.Sprintf("%s/...", dir))
724                 if err != nil {
725                         t.Fatal(err)
726                 }
727                 for _, pkg := range initial {
728                         if len(pkg.CompiledGoFiles) == 0 {
729                                 t.Fatalf("expected at least 1 CompiledGoFile for %s, got none", pkg.PkgPath)
730                         }
731                 }
732         })
733
734 }
735
736 // Tests golang/go#35973, fixed in Go 1.14.
737 func TestInvalidFilesBeforeOverlayContains(t *testing.T) {
738         packagestest.TestAll(t, testInvalidFilesBeforeOverlayContains)
739 }
740 func testInvalidFilesBeforeOverlayContains(t *testing.T, exporter packagestest.Exporter) {
741         testenv.NeedsGo1Point(t, 15)
742
743         exported := packagestest.Export(t, exporter, []packagestest.Module{
744                 {
745                         Name: "golang.org/fake",
746                         Files: map[string]interface{}{
747                                 "d/d.go":      `package d; import "net/http"; const Get = http.MethodGet; const Hello = "hello";`,
748                                 "d/util.go":   ``,
749                                 "d/d_test.go": ``,
750                                 "main.go":     ``,
751                         },
752                 },
753         })
754         defer exported.Cleanup()
755
756         dir := filepath.Dir(filepath.Dir(exported.File("golang.org/fake", "d/d.go")))
757
758         // Additional tests for test variants.
759         for i, tt := range []struct {
760                 name    string
761                 overlay map[string][]byte
762                 want    string // expected value of d.D
763                 wantID  string // expected value for the package ID
764         }{
765                 // Overlay with a test variant.
766                 {
767                         "test_variant",
768                         map[string][]byte{
769                                 filepath.Join(dir, "d", "d_test.go"): []byte(`package d; import "testing"; const D = Get + "_test"; func TestD(t *testing.T) {};`),
770                         },
771                         `"GET_test"`, "golang.org/fake/d [golang.org/fake/d.test]",
772                 },
773                 // Overlay in package.
774                 {
775                         "second_file",
776                         map[string][]byte{
777                                 filepath.Join(dir, "d", "util.go"): []byte(`package d; const D = Get + "_util";`),
778                         },
779                         `"GET_util"`, "golang.org/fake/d",
780                 },
781                 // Overlay on the main file.
782                 {
783                         "main",
784                         map[string][]byte{
785                                 filepath.Join(dir, "main.go"): []byte(`package main; import "golang.org/fake/d"; const D = d.Get + "_main"; func main() {};`),
786                         },
787                         `"GET_main"`, "golang.org/fake",
788                 },
789                 {
790                         "xtest",
791                         map[string][]byte{
792                                 filepath.Join(dir, "d", "d_test.go"): []byte(`package d_test; import "golang.org/fake/d"; import "testing"; const D = d.Get + "_xtest"; func TestD(t *testing.T) {};`),
793                         },
794                         `"GET_xtest"`, "golang.org/fake/d_test [golang.org/fake/d.test]",
795                 },
796         } {
797                 t.Run(tt.name, func(t *testing.T) {
798                         exported.Config.Overlay = tt.overlay
799                         exported.Config.Mode = everythingMode
800                         exported.Config.Tests = true
801
802                         for f := range tt.overlay {
803                                 initial, err := packages.Load(exported.Config, fmt.Sprintf("file=%s", f))
804                                 if err != nil {
805                                         t.Fatal(err)
806                                 }
807                                 pkg := initial[0]
808                                 if pkg.ID != tt.wantID {
809                                         t.Fatalf("expected package ID %q, got %q", tt.wantID, pkg.ID)
810                                 }
811                                 var containsFile bool
812                                 for _, goFile := range pkg.CompiledGoFiles {
813                                         if f == goFile {
814                                                 containsFile = true
815                                                 break
816                                         }
817                                 }
818                                 if !containsFile {
819                                         t.Fatalf("expected %s in CompiledGoFiles, got %v", f, pkg.CompiledGoFiles)
820                                 }
821                                 // Check value of d.D.
822                                 D := constant(pkg, "D")
823                                 if D == nil {
824                                         t.Fatalf("%d. D: got nil", i)
825                                 }
826                                 got := D.Val().String()
827                                 if got != tt.want {
828                                         t.Fatalf("%d. D: got %s, want %s", i, got, tt.want)
829                                 }
830                         }
831                 })
832         }
833 }
834
835 func TestInvalidXTestInGOPATH(t *testing.T) {
836         packagestest.TestAll(t, testInvalidXTestInGOPATH)
837 }
838 func testInvalidXTestInGOPATH(t *testing.T, exporter packagestest.Exporter) {
839         t.Skip("Not fixed yet. See golang.org/issue/40825.")
840
841         exported := packagestest.Export(t, exporter, []packagestest.Module{
842                 {
843                         Name: "golang.org/fake",
844                         Files: map[string]interface{}{
845                                 "x/x.go":      `package x`,
846                                 "x/x_test.go": ``,
847                         },
848                 },
849         })
850         defer exported.Cleanup()
851
852         dir := filepath.Dir(filepath.Dir(exported.File("golang.org/fake", "x/x.go")))
853
854         exported.Config.Mode = everythingMode
855         exported.Config.Tests = true
856
857         initial, err := packages.Load(exported.Config, fmt.Sprintf("%s/...", dir))
858         if err != nil {
859                 t.Fatal(err)
860         }
861         pkg := initial[0]
862         if len(pkg.CompiledGoFiles) != 2 {
863                 t.Fatalf("expected at least 2 CompiledGoFiles for %s, got %v", pkg.PkgPath, len(pkg.CompiledGoFiles))
864         }
865 }
866
867 // Reproduces golang/go#40685.
868 func TestAddImportInOverlay(t *testing.T) {
869         packagestest.TestAll(t, testAddImportInOverlay)
870 }
871 func testAddImportInOverlay(t *testing.T, exporter packagestest.Exporter) {
872         exported := packagestest.Export(t, exporter, []packagestest.Module{
873                 {
874                         Name: "golang.org/fake",
875                         Files: map[string]interface{}{
876                                 "a/a.go": `package a
877
878 import (
879         "fmt"
880 )
881
882 func _() {
883         fmt.Println("")
884         os.Stat("")
885 }`,
886                                 "a/a_test.go": `package a
887
888 import (
889         "os"
890         "testing"
891 )
892
893 func TestA(t *testing.T) {
894         os.Stat("")
895 }`,
896                         },
897                 },
898         })
899         defer exported.Cleanup()
900
901         exported.Config.Mode = everythingMode
902         exported.Config.Tests = true
903
904         dir := filepath.Dir(exported.File("golang.org/fake", "a/a.go"))
905         exported.Config.Overlay = map[string][]byte{
906                 filepath.Join(dir, "a.go"): []byte(`package a
907
908 import (
909         "fmt"
910         "os"
911 )
912
913 func _() {
914         fmt.Println("")
915         os.Stat("")
916 }
917 `),
918         }
919         initial, err := packages.Load(exported.Config, "golang.org/fake/a")
920         if err != nil {
921                 t.Fatal(err)
922         }
923         pkg := initial[0]
924         var foundOs bool
925         for _, imp := range pkg.Imports {
926                 if imp.PkgPath == "os" {
927                         foundOs = true
928                         break
929                 }
930         }
931         if !foundOs {
932                 t.Fatalf(`expected import "os", found none: %v`, pkg.Imports)
933         }
934 }
935
936 // Tests that overlays are applied for different kinds of load patterns.
937 func TestLoadDifferentPatterns(t *testing.T) {
938         packagestest.TestAll(t, testLoadDifferentPatterns)
939 }
940 func testLoadDifferentPatterns(t *testing.T, exporter packagestest.Exporter) {
941         exported := packagestest.Export(t, exporter, []packagestest.Module{
942                 {
943                         Name: "golang.org/fake",
944                         Files: map[string]interface{}{
945                                 "foo.txt": "placeholder",
946                                 "b/b.go": `package b
947 import "golang.org/fake/a"
948 func _() {
949         a.Hi()
950 }
951 `,
952                         },
953                 },
954         })
955         defer exported.Cleanup()
956
957         exported.Config.Mode = everythingMode
958         exported.Config.Tests = true
959
960         dir := filepath.Dir(exported.File("golang.org/fake", "foo.txt"))
961         exported.Config.Overlay = map[string][]byte{
962                 filepath.Join(dir, "a", "a.go"): []byte(`package a
963 import "fmt"
964 func Hi() {
965         fmt.Println("")
966 }
967 `),
968         }
969         for _, tc := range []struct {
970                 pattern string
971         }{
972                 {"golang.org/fake/a"},
973                 {"golang.org/fake/..."},
974                 {fmt.Sprintf("file=%s", filepath.Join(dir, "a", "a.go"))},
975         } {
976                 t.Run(tc.pattern, func(t *testing.T) {
977                         initial, err := packages.Load(exported.Config, tc.pattern)
978                         if err != nil {
979                                 t.Fatal(err)
980                         }
981                         var match *packages.Package
982                         for _, pkg := range initial {
983                                 if pkg.PkgPath == "golang.org/fake/a" {
984                                         match = pkg
985                                         break
986                                 }
987                         }
988                         if match == nil {
989                                 t.Fatalf(`expected package path "golang.org/fake/a", got %q`, match.PkgPath)
990                         }
991                         if match.PkgPath != "golang.org/fake/a" {
992                                 t.Fatalf(`expected package path "golang.org/fake/a", got %q`, match.PkgPath)
993                         }
994                         if _, ok := match.Imports["fmt"]; !ok {
995                                 t.Fatalf(`expected import "fmt", got none`)
996                         }
997                 })
998         }
999
1000         // Now, load "golang.org/fake/b" and confirm that "golang.org/fake/a" is
1001         // not returned as a root.
1002         initial, err := packages.Load(exported.Config, "golang.org/fake/b")
1003         if err != nil {
1004                 t.Fatal(err)
1005         }
1006         if len(initial) > 1 {
1007                 t.Fatalf("expected 1 package, got %v", initial)
1008         }
1009         pkg := initial[0]
1010         if pkg.PkgPath != "golang.org/fake/b" {
1011                 t.Fatalf(`expected package path "golang.org/fake/b", got %q`, pkg.PkgPath)
1012         }
1013         if _, ok := pkg.Imports["golang.org/fake/a"]; !ok {
1014                 t.Fatalf(`expected import "golang.org/fake/a", got none`)
1015         }
1016 }
1017
1018 // Tests that overlays are applied for a replaced module.
1019 // This does not use go/packagestest because it needs to write a replace
1020 // directive with an absolute path in one of the module's go.mod files.
1021 func TestOverlaysInReplace(t *testing.T) {
1022         // Create module b.com in a temporary directory. Do not add any Go files
1023         // on disk.
1024         tmpPkgs, err := ioutil.TempDir("", "modules")
1025         if err != nil {
1026                 t.Fatal(err)
1027         }
1028         defer os.RemoveAll(tmpPkgs)
1029
1030         dirB := filepath.Join(tmpPkgs, "b")
1031         if err := os.Mkdir(dirB, 0775); err != nil {
1032                 t.Fatal(err)
1033         }
1034         if err := ioutil.WriteFile(filepath.Join(dirB, "go.mod"), []byte(fmt.Sprintf("module %s.com", dirB)), 0775); err != nil {
1035                 t.Fatal(err)
1036         }
1037         if err := os.MkdirAll(filepath.Join(dirB, "inner"), 0775); err != nil {
1038                 t.Fatal(err)
1039         }
1040
1041         // Create a separate module that requires and replaces b.com.
1042         tmpWorkspace, err := ioutil.TempDir("", "workspace")
1043         if err != nil {
1044                 t.Fatal(err)
1045         }
1046         defer os.RemoveAll(tmpWorkspace)
1047         goModContent := fmt.Sprintf(`module workspace.com
1048
1049 require (
1050         b.com v0.0.0-00010101000000-000000000000
1051 )
1052
1053 replace (
1054         b.com => %s
1055 )
1056 `, dirB)
1057         if err := ioutil.WriteFile(filepath.Join(tmpWorkspace, "go.mod"), []byte(goModContent), 0775); err != nil {
1058                 t.Fatal(err)
1059         }
1060
1061         // Add Go files for b.com/inner in an overlay and try loading it from the
1062         // workspace.com module.
1063         config := &packages.Config{
1064                 Dir:  tmpWorkspace,
1065                 Mode: packages.LoadAllSyntax,
1066                 Logf: t.Logf,
1067                 Overlay: map[string][]byte{
1068                         filepath.Join(dirB, "inner", "b.go"): []byte(`package inner; import "fmt"; func _() { fmt.Println("");`),
1069                 },
1070         }
1071         initial, err := packages.Load(config, "b.com/...")
1072         if err != nil {
1073                 t.Error(err)
1074         }
1075         pkg := initial[0]
1076         if pkg.PkgPath != "b.com/inner" {
1077                 t.Fatalf(`expected package path "b.com/inner", got %q`, pkg.PkgPath)
1078         }
1079         if _, ok := pkg.Imports["fmt"]; !ok {
1080                 t.Fatalf(`expected import "fmt", got none`)
1081         }
1082 }