1 // Copyright 2020 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.
17 "golang.org/x/tools/go/packages"
18 "golang.org/x/tools/go/packages/packagestest"
19 "golang.org/x/tools/internal/testenv"
23 commonMode = packages.NeedName | packages.NeedFiles |
24 packages.NeedCompiledGoFiles | packages.NeedImports | packages.NeedSyntax
25 everythingMode = commonMode | packages.NeedDeps | packages.NeedTypes |
26 packages.NeedTypesSizes
29 func TestOverlayChangesPackageName(t *testing.T) {
30 packagestest.TestAll(t, testOverlayChangesPackageName)
32 func testOverlayChangesPackageName(t *testing.T, exporter packagestest.Exporter) {
33 log.SetFlags(log.Lshortfile)
34 exported := packagestest.Export(t, exporter, []packagestest.Module{{
36 Files: map[string]interface{}{
37 "a.go": "package foo\nfunc f(){}\n",
39 Overlay: map[string][]byte{
40 "a.go": []byte("package foox\nfunc f(){}\n"),
43 defer exported.Cleanup()
44 exported.Config.Mode = packages.NeedName
46 initial, err := packages.Load(exported.Config,
47 filepath.Dir(exported.File("fake", "a.go")))
49 t.Fatalf("failed to load: %v", err)
51 if len(initial) != 1 || initial[0].ID != "fake" || initial[0].Name != "foox" {
52 t.Fatalf("got %v, expected [fake]", initial)
54 if len(initial[0].Errors) != 0 {
55 t.Fatalf("got %v, expected no errors", initial[0].Errors)
59 func TestOverlayChangesBothPackageNames(t *testing.T) {
60 packagestest.TestAll(t, testOverlayChangesBothPackageNames)
62 func testOverlayChangesBothPackageNames(t *testing.T, exporter packagestest.Exporter) {
63 log.SetFlags(log.Lshortfile)
64 exported := packagestest.Export(t, exporter, []packagestest.Module{{
66 Files: map[string]interface{}{
67 "a.go": "package foo\nfunc g(){}\n",
68 "a_test.go": "package foo\nfunc f(){}\n",
70 Overlay: map[string][]byte{
71 "a.go": []byte("package foox\nfunc g(){}\n"),
72 "a_test.go": []byte("package foox\nfunc f(){}\n"),
75 defer exported.Cleanup()
76 exported.Config.Mode = commonMode
78 initial, err := packages.Load(exported.Config,
79 filepath.Dir(exported.File("fake", "a.go")))
81 t.Fatalf("failed to load: %v", err)
83 if len(initial) != 3 {
84 t.Errorf("got %d packges, expected 3", len(initial))
91 {"fake [fake.test]", "foox", 2},
92 {"fake.test", "main", 1},
94 if len(initial) != 3 {
95 t.Fatalf("expected 3 packages, got %v", len(initial))
97 for i := 0; i < 3; i++ {
98 if ok := checkPkg(t, initial[i], want[i].id, want[i].name, want[i].count); !ok {
99 t.Errorf("%d: got {%s %s %d}, expected %v", i, initial[i].ID,
100 initial[i].Name, len(initial[i].Syntax), want[i])
102 if len(initial[i].Errors) != 0 {
103 t.Errorf("%d: got %v, expected no errors", i, initial[i].Errors)
108 func TestOverlayChangesTestPackageName(t *testing.T) {
109 packagestest.TestAll(t, testOverlayChangesTestPackageName)
111 func testOverlayChangesTestPackageName(t *testing.T, exporter packagestest.Exporter) {
112 testenv.NeedsGo1Point(t, 16)
114 exported := packagestest.Export(t, exporter, []packagestest.Module{{
116 Files: map[string]interface{}{
117 "a_test.go": "package foo\nfunc f(){}\n",
119 Overlay: map[string][]byte{
120 "a_test.go": []byte("package foox\nfunc f(){}\n"),
123 defer exported.Cleanup()
124 exported.Config.Mode = commonMode
126 initial, err := packages.Load(exported.Config,
127 filepath.Dir(exported.File("fake", "a_test.go")))
129 t.Fatalf("failed to load: %v", err)
131 if len(initial) != 3 {
132 t.Errorf("got %d packges, expected 3", len(initial))
139 {"fake [fake.test]", "foox", 1},
140 {"fake.test", "main", 1},
142 if len(initial) != 3 {
143 t.Fatalf("expected 3 packages, got %v", len(initial))
145 for i := 0; i < 3; i++ {
146 if ok := checkPkg(t, initial[i], want[i].id, want[i].name, want[i].count); !ok {
147 t.Errorf("got {%s %s %d}, expected %v", initial[i].ID,
148 initial[i].Name, len(initial[i].Syntax), want[i])
151 if len(initial[0].Errors) != 0 {
152 t.Fatalf("got %v, expected no errors", initial[0].Errors)
157 func checkPkg(t *testing.T, p *packages.Package, id, name string, syntax int) bool {
159 if p.ID == id && p.Name == name && len(p.Syntax) == syntax {
165 func TestOverlayXTests(t *testing.T) {
166 packagestest.TestAll(t, testOverlayXTests)
169 // This test checks the behavior of go/packages.Load with an overlaid
170 // x test. The source of truth is the go/packages.Load results for the
171 // exact same package, just on-disk.
172 func testOverlayXTests(t *testing.T, exporter packagestest.Exporter) {
173 const aFile = `package a; const C = "C"; func Hello() {}`
174 const aTestVariant = `package a
178 const TestC = "test" + C
183 const aXTest = `package a_test
191 const xTestC = "x" + a.C
193 func TestHello(t *testing.T) {
197 // First, get the source of truth by loading the package, all on disk.
198 onDisk := packagestest.Export(t, exporter, []packagestest.Module{{
199 Name: "golang.org/fake",
200 Files: map[string]interface{}{
202 "a/a_test.go": aTestVariant,
203 "a/a_x_test.go": aXTest,
206 defer onDisk.Cleanup()
208 onDisk.Config.Mode = commonMode
209 onDisk.Config.Tests = true
210 onDisk.Config.Mode = packages.LoadTypes
211 initial, err := packages.Load(onDisk.Config, fmt.Sprintf("file=%s", onDisk.File("golang.org/fake", "a/a_x_test.go")))
215 wantPkg := initial[0]
217 exported := packagestest.Export(t, exporter, []packagestest.Module{{
218 Name: "golang.org/fake",
219 Files: map[string]interface{}{
221 "a/a_test.go": aTestVariant,
222 "a/a_x_test.go": ``, // empty x test on disk
224 Overlay: map[string][]byte{
225 "a/a_x_test.go": []byte(aXTest),
228 defer exported.Cleanup()
230 if len(initial) != 1 {
231 t.Fatalf("expected 1 package, got %d", len(initial))
233 // Confirm that the overlaid package is identical to the on-disk version.
235 if !reflect.DeepEqual(wantPkg, pkg) {
236 t.Fatalf("mismatched packages: want %#v, got %#v", wantPkg, pkg)
238 xTestC := constant(pkg, "xTestC")
240 t.Fatalf("no value for xTestC")
242 got := xTestC.Val().String()
243 // TODO(rstambler): Ideally, this test would check that the test variant
244 // was imported, but that's pretty complicated.
245 if want := `"xC"`; got != want {
246 t.Errorf("got: %q, want %q", got, want)
250 func TestOverlay(t *testing.T) { packagestest.TestAll(t, testOverlay) }
251 func testOverlay(t *testing.T, exporter packagestest.Exporter) {
252 exported := packagestest.Export(t, exporter, []packagestest.Module{{
253 Name: "golang.org/fake",
254 Files: map[string]interface{}{
255 "a/a.go": `package a; import "golang.org/fake/b"; const A = "a" + b.B`,
256 "b/b.go": `package b; import "golang.org/fake/c"; const B = "b" + c.C`,
257 "c/c.go": `package c; const C = "c"`,
258 "c/c_test.go": `package c; import "testing"; func TestC(t *testing.T) {}`,
259 "d/d.go": `package d; const D = "d"`,
261 defer exported.Cleanup()
263 for i, test := range []struct {
264 overlay map[string][]byte
265 want string // expected value of a.A
268 {nil, `"abc"`, nil}, // default
269 {map[string][]byte{}, `"abc"`, nil}, // empty overlay
270 {map[string][]byte{exported.File("golang.org/fake", "c/c.go"): []byte(`package c; const C = "C"`)}, `"abC"`, nil},
271 {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},
272 // Overlay with an existing file in an existing package adding a new import.
273 {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},
274 // Overlay with an existing file in an existing package.
275 {map[string][]byte{exported.File("golang.org/fake", "c/c.go"): []byte(`package c; import "net/http"; const C = http.MethodGet`)}, `"abGET"`, nil},
276 // Overlay with a new file in an existing package.
278 exported.File("golang.org/fake", "c/c.go"): []byte(`package c;`),
279 filepath.Join(filepath.Dir(exported.File("golang.org/fake", "c/c.go")), "c_new_file.go"): []byte(`package c; const C = "Ç"`)},
281 // Overlay with a new file in an existing package, adding a new dependency to that package.
283 exported.File("golang.org/fake", "c/c.go"): []byte(`package c;`),
284 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`)},
287 exported.Config.Overlay = test.overlay
288 exported.Config.Mode = packages.LoadAllSyntax
289 initial, err := packages.Load(exported.Config, "golang.org/fake/a")
295 // Check value of a.A.
297 aA := constant(a, "A")
299 t.Errorf("%d. a.A: got nil", i)
302 got := aA.Val().String()
303 if got != test.want {
304 t.Errorf("%d. a.A: got %s, want %s", i, got, test.want)
308 var errors []packages.Error
309 packages.Visit(initial, nil, func(pkg *packages.Package) {
310 errors = append(errors, pkg.Errors...)
312 if errs := errorMessages(errors); !reflect.DeepEqual(errs, test.wantErrs) {
313 t.Errorf("%d. got errors %s, want %s", i, errs, test.wantErrs)
318 func TestOverlayDeps(t *testing.T) { packagestest.TestAll(t, testOverlayDeps) }
319 func testOverlayDeps(t *testing.T, exporter packagestest.Exporter) {
320 exported := packagestest.Export(t, exporter, []packagestest.Module{{
321 Name: "golang.org/fake",
322 Files: map[string]interface{}{
323 "c/c.go": `package c; const C = "c"`,
324 "c/c_test.go": `package c; import "testing"; func TestC(t *testing.T) {}`,
327 defer exported.Cleanup()
329 exported.Config.Overlay = map[string][]byte{exported.File("golang.org/fake", "c/c.go"): []byte(`package c; import "net/http"; const C = http.MethodGet`)}
330 exported.Config.Mode = packages.NeedName |
332 packages.NeedCompiledGoFiles |
333 packages.NeedImports |
335 packages.NeedTypesSizes
336 pkgs, err := packages.Load(exported.Config, fmt.Sprintf("file=%s", exported.File("golang.org/fake", "c/c.go")))
341 // Find package golang.org/fake/c
342 sort.Slice(pkgs, func(i, j int) bool { return pkgs[i].ID < pkgs[j].ID })
344 t.Fatalf("expected 2 packages, got %v", len(pkgs))
347 if pkgc.ID != "golang.org/fake/c" {
348 t.Errorf("expected first package in sorted list to be \"golang.org/fake/c\", got %v", pkgc.ID)
351 // Make sure golang.org/fake/c imports net/http, as per the overlay.
352 contains := func(imports map[string]*packages.Package, wantImport string) bool {
353 for imp := range imports {
354 if imp == wantImport {
360 if !contains(pkgc.Imports, "net/http") {
361 t.Errorf("expected import of %s in package %s, got the following imports: %v",
362 "net/http", pkgc.ID, pkgc.Imports)
367 func TestNewPackagesInOverlay(t *testing.T) { packagestest.TestAll(t, testNewPackagesInOverlay) }
368 func testNewPackagesInOverlay(t *testing.T, exporter packagestest.Exporter) {
369 exported := packagestest.Export(t, exporter, []packagestest.Module{
371 Name: "golang.org/fake",
372 Files: map[string]interface{}{
373 "a/a.go": `package a; import "golang.org/fake/b"; const A = "a" + b.B`,
374 "b/b.go": `package b; import "golang.org/fake/c"; const B = "b" + c.C`,
375 "c/c.go": `package c; const C = "c"`,
376 "d/d.go": `package d; const D = "d"`,
380 Name: "example.com/extramodule",
381 Files: map[string]interface{}{
382 "pkg/x.go": "package pkg\n",
386 defer exported.Cleanup()
388 dir := filepath.Dir(filepath.Dir(exported.File("golang.org/fake", "a/a.go")))
390 for _, test := range []struct {
392 overlay map[string][]byte
393 want string // expected value of e.E
397 filepath.Join(dir, "e", "e.go"): []byte(`package e; import "golang.org/fake/a"; const E = "e" + a.A`)},
399 {"multiple_files_same_package",
401 filepath.Join(dir, "e", "e.go"): []byte(`package e; import "golang.org/fake/a"; const E = "e" + a.A + underscore`),
402 filepath.Join(dir, "e", "e_util.go"): []byte(`package e; const underscore = "_"`),
405 {"multiple_files_two_packages",
407 filepath.Join(dir, "e", "e.go"): []byte(`package e; import "golang.org/fake/f"; const E = "e" + f.F + underscore`),
408 filepath.Join(dir, "e", "e_util.go"): []byte(`package e; const underscore = "_"`),
409 filepath.Join(dir, "f", "f.go"): []byte(`package f; const F = "f"`),
412 {"multiple_files_three_packages",
414 filepath.Join(dir, "e", "e.go"): []byte(`package e; import "golang.org/fake/f"; const E = "e" + f.F + underscore`),
415 filepath.Join(dir, "e", "e_util.go"): []byte(`package e; const underscore = "_"`),
416 filepath.Join(dir, "f", "f.go"): []byte(`package f; import "golang.org/fake/g"; const F = "f" + g.G`),
417 filepath.Join(dir, "g", "g.go"): []byte(`package g; const G = "g"`),
420 {"multiple_files_four_packages",
422 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`),
423 filepath.Join(dir, "e", "e_util.go"): []byte(`package e; const underscore = "_"`),
424 filepath.Join(dir, "f", "f.go"): []byte(`package f; import "golang.org/fake/g"; const F = "f" + g.G`),
425 filepath.Join(dir, "g", "g.go"): []byte(`package g; const G = "g"`),
426 filepath.Join(dir, "h", "h.go"): []byte(`package h; const H = "h"`),
429 {"multiple_files_four_packages_again",
431 filepath.Join(dir, "e", "e.go"): []byte(`package e; import "golang.org/fake/f"; const E = "e" + f.F + underscore`),
432 filepath.Join(dir, "e", "e_util.go"): []byte(`package e; const underscore = "_"`),
433 filepath.Join(dir, "f", "f.go"): []byte(`package f; import "golang.org/fake/g"; const F = "f" + g.G`),
434 filepath.Join(dir, "g", "g.go"): []byte(`package g; import "golang.org/fake/h"; const G = "g" + h.H`),
435 filepath.Join(dir, "h", "h.go"): []byte(`package h; const H = "h"`),
440 filepath.Join(dir, "e", "main.go"): []byte(`package main; import "golang.org/fake/a"; const E = "e" + a.A; func main(){}`)},
443 t.Run(test.name, func(t *testing.T) {
444 exported.Config.Overlay = test.overlay
445 exported.Config.Mode = packages.LoadAllSyntax
446 exported.Config.Logf = t.Logf
448 // With an overlay, we don't know the expected import path,
449 // so load with the absolute path of the directory.
450 initial, err := packages.Load(exported.Config, filepath.Join(dir, "e"))
455 // Check value of e.E.
457 eE := constant(e, "E")
459 t.Fatalf("e.E: was nil in %#v", e)
461 got := eE.Val().String()
462 if got != test.want {
463 t.Fatalf("e.E: got %s, want %s", got, test.want)
469 // Test that we can create a package and its test package in an overlay.
470 func TestOverlayNewPackageAndTest(t *testing.T) {
471 packagestest.TestAll(t, testOverlayNewPackageAndTest)
473 func testOverlayNewPackageAndTest(t *testing.T, exporter packagestest.Exporter) {
474 exported := packagestest.Export(t, exporter, []packagestest.Module{
476 Name: "golang.org/fake",
477 Files: map[string]interface{}{
478 "foo.txt": "placeholder",
482 defer exported.Cleanup()
484 dir := filepath.Dir(exported.File("golang.org/fake", "foo.txt"))
485 exported.Config.Overlay = map[string][]byte{
486 filepath.Join(dir, "a.go"): []byte(`package a;`),
487 filepath.Join(dir, "a_test.go"): []byte(`package a; import "testing";`),
489 initial, err := packages.Load(exported.Config, "file="+filepath.Join(dir, "a.go"), "file="+filepath.Join(dir, "a_test.go"))
493 if len(initial) != 2 {
494 t.Errorf("got %v packages, wanted %v", len(initial), 2)
498 func TestAdHocOverlays(t *testing.T) {
499 testenv.NeedsTool(t, "go")
501 // This test doesn't use packagestest because we are testing ad-hoc packages,
502 // which are outside of $GOPATH and outside of a module.
503 tmp, err := ioutil.TempDir("", "testAdHocOverlays")
507 defer os.RemoveAll(tmp)
509 filename := filepath.Join(tmp, "a.go")
510 content := []byte(`package a
514 // Make sure that the user's value of GO111MODULE does not affect test results.
515 for _, go111module := range []string{"off", "auto", "on"} {
516 t.Run("GO111MODULE="+go111module, func(t *testing.T) {
517 config := &packages.Config{
519 Env: append(os.Environ(), "GOPACKAGESDRIVER=off", fmt.Sprintf("GO111MODULE=%s", go111module)),
520 Mode: packages.LoadAllSyntax,
521 Overlay: map[string][]byte{
526 initial, err := packages.Load(config, fmt.Sprintf("file=%s", filename))
530 if len(initial) == 0 {
531 t.Fatalf("no packages for %s", filename)
533 // Check value of a.A.
536 t.Fatalf("a: got errors %+v, want no error", err)
538 aA := constant(a, "A")
540 t.Errorf("a.A: got nil")
543 got := aA.Val().String()
544 if want := "1"; got != want {
545 t.Errorf("a.A: got %s, want %s", got, want)
551 // TestOverlayModFileChanges tests the behavior resulting from having files
552 // from multiple modules in overlays.
553 func TestOverlayModFileChanges(t *testing.T) {
554 testenv.NeedsTool(t, "go")
556 // Create two unrelated modules in a temporary directory.
557 tmp, err := ioutil.TempDir("", "tmp")
561 defer os.RemoveAll(tmp)
563 // mod1 has a dependency on golang.org/x/xerrors.
564 mod1, err := ioutil.TempDir(tmp, "mod1")
568 if err := ioutil.WriteFile(filepath.Join(mod1, "go.mod"), []byte(`module mod1
571 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7
573 `), 0775); err != nil {
577 // mod2 does not have any dependencies.
578 mod2, err := ioutil.TempDir(tmp, "mod2")
587 if err := ioutil.WriteFile(filepath.Join(mod2, "go.mod"), []byte(want), 0775); err != nil {
591 // Run packages.Load on mod2, while passing the contents over mod1/main.go in the overlay.
592 config := &packages.Config{
594 Env: append(os.Environ(), "GOPACKAGESDRIVER=off"),
595 Mode: packages.LoadImports,
596 Overlay: map[string][]byte{
597 filepath.Join(mod1, "main.go"): []byte(`package main
598 import "golang.org/x/xerrors"
603 filepath.Join(mod2, "main.go"): []byte(`package main
608 if _, err := packages.Load(config, fmt.Sprintf("file=%s", filepath.Join(mod2, "main.go"))); err != nil {
612 // Check that mod2/go.mod has not been modified.
613 got, err := ioutil.ReadFile(filepath.Join(mod2, "go.mod"))
617 if string(got) != want {
618 t.Errorf("expected %s, got %s", want, string(got))
622 func TestOverlayGOPATHVendoring(t *testing.T) {
623 exported := packagestest.Export(t, packagestest.GOPATH, []packagestest.Module{{
624 Name: "golang.org/fake",
625 Files: map[string]interface{}{
626 "vendor/vendor.com/foo/foo.go": `package foo; const X = "hi"`,
627 "user/user.go": `package user`,
630 defer exported.Cleanup()
632 exported.Config.Mode = packages.LoadAllSyntax
633 exported.Config.Logf = t.Logf
634 exported.Config.Overlay = map[string][]byte{
635 exported.File("golang.org/fake", "user/user.go"): []byte(`package user; import "vendor.com/foo"; var x = foo.X`),
637 initial, err := packages.Load(exported.Config, "golang.org/fake/user")
642 if len(user.Imports) != 1 {
643 t.Fatal("no imports for user")
645 if user.Imports["vendor.com/foo"].Name != "foo" {
646 t.Errorf("failed to load vendored package foo, imports: %#v", user.Imports["vendor.com/foo"])
650 func TestContainsOverlay(t *testing.T) { packagestest.TestAll(t, testContainsOverlay) }
651 func testContainsOverlay(t *testing.T, exporter packagestest.Exporter) {
652 exported := packagestest.Export(t, exporter, []packagestest.Module{{
653 Name: "golang.org/fake",
654 Files: map[string]interface{}{
655 "a/a.go": `package a; import "golang.org/fake/b"`,
656 "b/b.go": `package b; import "golang.org/fake/c"`,
657 "c/c.go": `package c`,
659 defer exported.Cleanup()
660 bOverlayFile := filepath.Join(filepath.Dir(exported.File("golang.org/fake", "b/b.go")), "b_overlay.go")
661 exported.Config.Mode = packages.LoadImports
662 exported.Config.Overlay = map[string][]byte{bOverlayFile: []byte(`package b;`)}
663 initial, err := packages.Load(exported.Config, "file="+bOverlayFile)
668 graph, _ := importGraph(initial)
672 golang.org/fake/b -> golang.org/fake/c
674 if graph != wantGraph {
675 t.Errorf("wrong import graph: got <<%s>>, want <<%s>>", graph, wantGraph)
679 func TestContainsOverlayXTest(t *testing.T) { packagestest.TestAll(t, testContainsOverlayXTest) }
680 func testContainsOverlayXTest(t *testing.T, exporter packagestest.Exporter) {
681 exported := packagestest.Export(t, exporter, []packagestest.Module{{
682 Name: "golang.org/fake",
683 Files: map[string]interface{}{
684 "a/a.go": `package a; import "golang.org/fake/b"`,
685 "b/b.go": `package b; import "golang.org/fake/c"`,
686 "c/c.go": `package c`,
688 defer exported.Cleanup()
690 bOverlayXTestFile := filepath.Join(filepath.Dir(exported.File("golang.org/fake", "b/b.go")), "b_overlay_x_test.go")
691 exported.Config.Mode = packages.NeedName | packages.NeedFiles | packages.NeedImports
692 exported.Config.Overlay = map[string][]byte{bOverlayXTestFile: []byte(`package b_test; import "golang.org/fake/b"`)}
693 initial, err := packages.Load(exported.Config, "file="+bOverlayXTestFile)
698 graph, _ := importGraph(initial)
701 * golang.org/fake/b_test [golang.org/fake/b.test]
703 golang.org/fake/b -> golang.org/fake/c
704 golang.org/fake/b_test [golang.org/fake/b.test] -> golang.org/fake/b
706 if graph != wantGraph {
707 t.Errorf("wrong import graph: got <<%s>>, want <<%s>>", graph, wantGraph)
711 func TestInvalidFilesBeforeOverlay(t *testing.T) {
712 packagestest.TestAll(t, testInvalidFilesBeforeOverlay)
715 func testInvalidFilesBeforeOverlay(t *testing.T, exporter packagestest.Exporter) {
716 testenv.NeedsGo1Point(t, 15)
718 exported := packagestest.Export(t, exporter, []packagestest.Module{
720 Name: "golang.org/fake",
721 Files: map[string]interface{}{
727 defer exported.Cleanup()
729 dir := filepath.Dir(filepath.Dir(exported.File("golang.org/fake", "d/d.go")))
731 exported.Config.Mode = everythingMode
732 exported.Config.Tests = true
734 // First, check that all packages returned have files associated with them.
735 // Tests the work-around for golang/go#39986.
736 t.Run("no overlay", func(t *testing.T) {
737 initial, err := packages.Load(exported.Config, fmt.Sprintf("%s/...", dir))
741 for _, pkg := range initial {
742 if len(pkg.CompiledGoFiles) == 0 {
743 t.Fatalf("expected at least 1 CompiledGoFile for %s, got none", pkg.PkgPath)
750 // Tests golang/go#35973, fixed in Go 1.14.
751 func TestInvalidFilesBeforeOverlayContains(t *testing.T) {
752 packagestest.TestAll(t, testInvalidFilesBeforeOverlayContains)
754 func testInvalidFilesBeforeOverlayContains(t *testing.T, exporter packagestest.Exporter) {
755 testenv.NeedsGo1Point(t, 15)
757 exported := packagestest.Export(t, exporter, []packagestest.Module{
759 Name: "golang.org/fake",
760 Files: map[string]interface{}{
761 "d/d.go": `package d; import "net/http"; const Get = http.MethodGet; const Hello = "hello";`,
768 defer exported.Cleanup()
770 dir := filepath.Dir(filepath.Dir(exported.File("golang.org/fake", "d/d.go")))
772 // Additional tests for test variants.
773 for i, tt := range []struct {
775 overlay map[string][]byte
776 want string // expected value of d.D
777 wantID string // expected value for the package ID
779 // Overlay with a test variant.
783 filepath.Join(dir, "d", "d_test.go"): []byte(`package d; import "testing"; const D = Get + "_test"; func TestD(t *testing.T) {};`),
785 `"GET_test"`, "golang.org/fake/d [golang.org/fake/d.test]",
787 // Overlay in package.
791 filepath.Join(dir, "d", "util.go"): []byte(`package d; const D = Get + "_util";`),
793 `"GET_util"`, "golang.org/fake/d",
795 // Overlay on the main file.
799 filepath.Join(dir, "main.go"): []byte(`package main; import "golang.org/fake/d"; const D = d.Get + "_main"; func main() {};`),
801 `"GET_main"`, "golang.org/fake",
806 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) {};`),
808 `"GET_xtest"`, "golang.org/fake/d_test [golang.org/fake/d.test]",
811 t.Run(tt.name, func(t *testing.T) {
812 exported.Config.Overlay = tt.overlay
813 exported.Config.Mode = everythingMode
814 exported.Config.Tests = true
816 for f := range tt.overlay {
817 initial, err := packages.Load(exported.Config, fmt.Sprintf("file=%s", f))
821 if len(initial) != 1 {
822 t.Fatalf("expected 1 packages, got %v", len(initial))
825 if pkg.ID != tt.wantID {
826 t.Fatalf("expected package ID %q, got %q", tt.wantID, pkg.ID)
828 var containsFile bool
829 for _, goFile := range pkg.CompiledGoFiles {
836 t.Fatalf("expected %s in CompiledGoFiles, got %v", f, pkg.CompiledGoFiles)
838 // Check value of d.D.
839 D := constant(pkg, "D")
841 t.Fatalf("%d. D: got nil", i)
843 got := D.Val().String()
845 t.Fatalf("%d. D: got %s, want %s", i, got, tt.want)
852 func TestInvalidXTestInGOPATH(t *testing.T) {
853 packagestest.TestAll(t, testInvalidXTestInGOPATH)
855 func testInvalidXTestInGOPATH(t *testing.T, exporter packagestest.Exporter) {
856 t.Skip("Not fixed yet. See golang.org/issue/40825.")
858 exported := packagestest.Export(t, exporter, []packagestest.Module{
860 Name: "golang.org/fake",
861 Files: map[string]interface{}{
862 "x/x.go": `package x`,
867 defer exported.Cleanup()
869 dir := filepath.Dir(filepath.Dir(exported.File("golang.org/fake", "x/x.go")))
871 exported.Config.Mode = everythingMode
872 exported.Config.Tests = true
874 initial, err := packages.Load(exported.Config, fmt.Sprintf("%s/...", dir))
879 if len(pkg.CompiledGoFiles) != 2 {
880 t.Fatalf("expected at least 2 CompiledGoFiles for %s, got %v", pkg.PkgPath, len(pkg.CompiledGoFiles))
884 // Reproduces golang/go#40685.
885 func TestAddImportInOverlay(t *testing.T) {
886 packagestest.TestAll(t, testAddImportInOverlay)
888 func testAddImportInOverlay(t *testing.T, exporter packagestest.Exporter) {
889 exported := packagestest.Export(t, exporter, []packagestest.Module{
891 Name: "golang.org/fake",
892 Files: map[string]interface{}{
903 "a/a_test.go": `package a
910 func TestA(t *testing.T) {
916 defer exported.Cleanup()
918 exported.Config.Mode = everythingMode
919 exported.Config.Tests = true
921 dir := filepath.Dir(exported.File("golang.org/fake", "a/a.go"))
922 exported.Config.Overlay = map[string][]byte{
923 filepath.Join(dir, "a.go"): []byte(`package a
936 initial, err := packages.Load(exported.Config, "golang.org/fake/a")
942 for _, imp := range pkg.Imports {
943 if imp.PkgPath == "os" {
949 t.Fatalf(`expected import "os", found none: %v`, pkg.Imports)
953 // Tests that overlays are applied for different kinds of load patterns.
954 func TestLoadDifferentPatterns(t *testing.T) {
955 packagestest.TestAll(t, testLoadDifferentPatterns)
957 func testLoadDifferentPatterns(t *testing.T, exporter packagestest.Exporter) {
958 exported := packagestest.Export(t, exporter, []packagestest.Module{
960 Name: "golang.org/fake",
961 Files: map[string]interface{}{
962 "foo.txt": "placeholder",
964 import "golang.org/fake/a"
972 defer exported.Cleanup()
974 exported.Config.Mode = everythingMode
975 exported.Config.Tests = true
977 dir := filepath.Dir(exported.File("golang.org/fake", "foo.txt"))
978 exported.Config.Overlay = map[string][]byte{
979 filepath.Join(dir, "a", "a.go"): []byte(`package a
986 for _, tc := range []struct {
989 {"golang.org/fake/a"},
990 {"golang.org/fake/..."},
991 {fmt.Sprintf("file=%s", filepath.Join(dir, "a", "a.go"))},
993 t.Run(tc.pattern, func(t *testing.T) {
994 initial, err := packages.Load(exported.Config, tc.pattern)
998 var match *packages.Package
999 for _, pkg := range initial {
1000 if pkg.PkgPath == "golang.org/fake/a" {
1006 t.Fatalf(`expected package path "golang.org/fake/a", got none`)
1008 if match.PkgPath != "golang.org/fake/a" {
1009 t.Fatalf(`expected package path "golang.org/fake/a", got %q`, match.PkgPath)
1011 if _, ok := match.Imports["fmt"]; !ok {
1012 t.Fatalf(`expected import "fmt", got none`)
1017 // Now, load "golang.org/fake/b" and confirm that "golang.org/fake/a" is
1018 // not returned as a root.
1019 initial, err := packages.Load(exported.Config, "golang.org/fake/b")
1023 if len(initial) > 1 {
1024 t.Fatalf("expected 1 package, got %v", initial)
1027 if pkg.PkgPath != "golang.org/fake/b" {
1028 t.Fatalf(`expected package path "golang.org/fake/b", got %q`, pkg.PkgPath)
1030 if _, ok := pkg.Imports["golang.org/fake/a"]; !ok {
1031 t.Fatalf(`expected import "golang.org/fake/a", got none`)
1035 // Tests that overlays are applied for a replaced module.
1036 // This does not use go/packagestest because it needs to write a replace
1037 // directive with an absolute path in one of the module's go.mod files.
1038 func TestOverlaysInReplace(t *testing.T) {
1039 // Create module b.com in a temporary directory. Do not add any Go files
1041 tmpPkgs, err := ioutil.TempDir("", "modules")
1045 defer os.RemoveAll(tmpPkgs)
1047 dirB := filepath.Join(tmpPkgs, "b")
1048 if err := os.Mkdir(dirB, 0775); err != nil {
1051 if err := ioutil.WriteFile(filepath.Join(dirB, "go.mod"), []byte(fmt.Sprintf("module %s.com", dirB)), 0775); err != nil {
1054 if err := os.MkdirAll(filepath.Join(dirB, "inner"), 0775); err != nil {
1058 // Create a separate module that requires and replaces b.com.
1059 tmpWorkspace, err := ioutil.TempDir("", "workspace")
1063 defer os.RemoveAll(tmpWorkspace)
1064 goModContent := fmt.Sprintf(`module workspace.com
1067 b.com v0.0.0-00010101000000-000000000000
1074 if err := ioutil.WriteFile(filepath.Join(tmpWorkspace, "go.mod"), []byte(goModContent), 0775); err != nil {
1078 // Add Go files for b.com/inner in an overlay and try loading it from the
1079 // workspace.com module.
1080 config := &packages.Config{
1082 Mode: packages.LoadAllSyntax,
1084 Overlay: map[string][]byte{
1085 filepath.Join(dirB, "inner", "b.go"): []byte(`package inner; import "fmt"; func _() { fmt.Println("");`),
1088 initial, err := packages.Load(config, "b.com/...")
1092 if len(initial) != 1 {
1093 t.Fatalf(`expected 1 package, got %v`, len(initial))
1096 if pkg.PkgPath != "b.com/inner" {
1097 t.Fatalf(`expected package path "b.com/inner", got %q`, pkg.PkgPath)
1099 if _, ok := pkg.Imports["fmt"]; !ok {
1100 t.Fatalf(`expected import "fmt", got none`)