go/packages: move all overlay tests into overlay_test.go
It's hard to see what tests we have for overlays right now. Centralize
them all in overlay_test.go.
Change-Id: I8e48c2332771a9b73997775780ab14a798a4086b
Reviewed-on: https://go-review.googlesource.com/c/tools/+/240184
Reviewed-by: Michael Matloob <matloob@golang.org>
Run-TryBot: Rebecca Stambler <rstambler@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
diff --git a/go/packages/overlay_test.go b/go/packages/overlay_test.go
index 618b508..d48c47b 100644
--- a/go/packages/overlay_test.go
+++ b/go/packages/overlay_test.go
@@ -2,13 +2,17 @@
import (
"fmt"
+ "io/ioutil"
"log"
+ "os"
"path/filepath"
"reflect"
+ "sort"
"testing"
"golang.org/x/tools/go/packages"
"golang.org/x/tools/go/packages/packagestest"
+ "golang.org/x/tools/internal/testenv"
)
const commonMode = packages.NeedName | packages.NeedFiles |
@@ -212,6 +216,537 @@
}
}
+func TestOverlay(t *testing.T) { packagestest.TestAll(t, testOverlay) }
+func testOverlay(t *testing.T, exporter packagestest.Exporter) {
+ exported := packagestest.Export(t, exporter, []packagestest.Module{{
+ Name: "golang.org/fake",
+ Files: map[string]interface{}{
+ "a/a.go": `package a; import "golang.org/fake/b"; const A = "a" + b.B`,
+ "b/b.go": `package b; import "golang.org/fake/c"; const B = "b" + c.C`,
+ "c/c.go": `package c; const C = "c"`,
+ "c/c_test.go": `package c; import "testing"; func TestC(t *testing.T) {}`,
+ "d/d.go": `package d; const D = "d"`,
+ }}})
+ defer exported.Cleanup()
+
+ for i, test := range []struct {
+ overlay map[string][]byte
+ want string // expected value of a.A
+ wantErrs []string
+ }{
+ {nil, `"abc"`, nil}, // default
+ {map[string][]byte{}, `"abc"`, nil}, // empty overlay
+ {map[string][]byte{exported.File("golang.org/fake", "c/c.go"): []byte(`package c; const C = "C"`)}, `"abC"`, nil},
+ {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},
+ // Overlay with an existing file in an existing package adding a new import.
+ {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},
+ // Overlay with an existing file in an existing package.
+ {map[string][]byte{exported.File("golang.org/fake", "c/c.go"): []byte(`package c; import "net/http"; const C = http.MethodGet`)}, `"abGET"`, nil},
+ // Overlay with a new file in an existing package.
+ {map[string][]byte{
+ exported.File("golang.org/fake", "c/c.go"): []byte(`package c;`),
+ filepath.Join(filepath.Dir(exported.File("golang.org/fake", "c/c.go")), "c_new_file.go"): []byte(`package c; const C = "Ç"`)},
+ `"abÇ"`, nil},
+ // Overlay with a new file in an existing package, adding a new dependency to that package.
+ {map[string][]byte{
+ exported.File("golang.org/fake", "c/c.go"): []byte(`package c;`),
+ 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`)},
+ `"abcd"`, nil},
+ } {
+ exported.Config.Overlay = test.overlay
+ exported.Config.Mode = packages.LoadAllSyntax
+ initial, err := packages.Load(exported.Config, "golang.org/fake/a")
+ if err != nil {
+ t.Error(err)
+ continue
+ }
+
+ // Check value of a.A.
+ a := initial[0]
+ aA := constant(a, "A")
+ if aA == nil {
+ t.Errorf("%d. a.A: got nil", i)
+ continue
+ }
+ got := aA.Val().String()
+ if got != test.want {
+ t.Errorf("%d. a.A: got %s, want %s", i, got, test.want)
+ }
+
+ // Check errors.
+ var errors []packages.Error
+ packages.Visit(initial, nil, func(pkg *packages.Package) {
+ errors = append(errors, pkg.Errors...)
+ })
+ if errs := errorMessages(errors); !reflect.DeepEqual(errs, test.wantErrs) {
+ t.Errorf("%d. got errors %s, want %s", i, errs, test.wantErrs)
+ }
+ }
+}
+
+func TestOverlayDeps(t *testing.T) { packagestest.TestAll(t, testOverlayDeps) }
+func testOverlayDeps(t *testing.T, exporter packagestest.Exporter) {
+ exported := packagestest.Export(t, exporter, []packagestest.Module{{
+ Name: "golang.org/fake",
+ Files: map[string]interface{}{
+ "c/c.go": `package c; const C = "c"`,
+ "c/c_test.go": `package c; import "testing"; func TestC(t *testing.T) {}`,
+ },
+ }})
+ defer exported.Cleanup()
+
+ exported.Config.Overlay = map[string][]byte{exported.File("golang.org/fake", "c/c.go"): []byte(`package c; import "net/http"; const C = http.MethodGet`)}
+ exported.Config.Mode = packages.NeedName |
+ packages.NeedFiles |
+ packages.NeedCompiledGoFiles |
+ packages.NeedImports |
+ packages.NeedDeps |
+ packages.NeedTypesSizes
+ pkgs, err := packages.Load(exported.Config, fmt.Sprintf("file=%s", exported.File("golang.org/fake", "c/c.go")))
+ if err != nil {
+ t.Error(err)
+ }
+
+ // Find package golang.org/fake/c
+ sort.Slice(pkgs, func(i, j int) bool { return pkgs[i].ID < pkgs[j].ID })
+ pkgc := pkgs[0]
+ if pkgc.ID != "golang.org/fake/c" {
+ t.Errorf("expected first package in sorted list to be \"golang.org/fake/c\", got %v", pkgc.ID)
+ }
+
+ // Make sure golang.org/fake/c imports net/http, as per the overlay.
+ contains := func(imports map[string]*packages.Package, wantImport string) bool {
+ for imp := range imports {
+ if imp == wantImport {
+ return true
+ }
+ }
+ return false
+ }
+ if !contains(pkgc.Imports, "net/http") {
+ t.Errorf("expected import of %s in package %s, got the following imports: %v",
+ "net/http", pkgc.ID, pkgc.Imports)
+ }
+
+}
+
+func TestNewPackagesInOverlay(t *testing.T) { packagestest.TestAll(t, testNewPackagesInOverlay) }
+func testNewPackagesInOverlay(t *testing.T, exporter packagestest.Exporter) {
+ exported := packagestest.Export(t, exporter, []packagestest.Module{
+ {
+ Name: "golang.org/fake",
+ Files: map[string]interface{}{
+ "a/a.go": `package a; import "golang.org/fake/b"; const A = "a" + b.B`,
+ "b/b.go": `package b; import "golang.org/fake/c"; const B = "b" + c.C`,
+ "c/c.go": `package c; const C = "c"`,
+ "d/d.go": `package d; const D = "d"`,
+ },
+ },
+ {
+ Name: "example.com/extramodule",
+ Files: map[string]interface{}{
+ "pkg/x.go": "package pkg\n",
+ },
+ },
+ })
+ defer exported.Cleanup()
+
+ dir := filepath.Dir(filepath.Dir(exported.File("golang.org/fake", "a/a.go")))
+
+ for _, test := range []struct {
+ name string
+ overlay map[string][]byte
+ want string // expected value of e.E
+ }{
+ {"one_file",
+ map[string][]byte{
+ filepath.Join(dir, "e", "e.go"): []byte(`package e; import "golang.org/fake/a"; const E = "e" + a.A`)},
+ `"eabc"`},
+ {"multiple_files_same_package",
+ map[string][]byte{
+ filepath.Join(dir, "e", "e.go"): []byte(`package e; import "golang.org/fake/a"; const E = "e" + a.A + underscore`),
+ filepath.Join(dir, "e", "e_util.go"): []byte(`package e; const underscore = "_"`),
+ },
+ `"eabc_"`},
+ {"multiple_files_two_packages",
+ map[string][]byte{
+ filepath.Join(dir, "e", "e.go"): []byte(`package e; import "golang.org/fake/f"; const E = "e" + f.F + underscore`),
+ filepath.Join(dir, "e", "e_util.go"): []byte(`package e; const underscore = "_"`),
+ filepath.Join(dir, "f", "f.go"): []byte(`package f; const F = "f"`),
+ },
+ `"ef_"`},
+ {"multiple_files_three_packages",
+ map[string][]byte{
+ filepath.Join(dir, "e", "e.go"): []byte(`package e; import "golang.org/fake/f"; const E = "e" + f.F + underscore`),
+ filepath.Join(dir, "e", "e_util.go"): []byte(`package e; const underscore = "_"`),
+ filepath.Join(dir, "f", "f.go"): []byte(`package f; import "golang.org/fake/g"; const F = "f" + g.G`),
+ filepath.Join(dir, "g", "g.go"): []byte(`package g; const G = "g"`),
+ },
+ `"efg_"`},
+ {"multiple_files_four_packages",
+ map[string][]byte{
+ 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`),
+ filepath.Join(dir, "e", "e_util.go"): []byte(`package e; const underscore = "_"`),
+ filepath.Join(dir, "f", "f.go"): []byte(`package f; import "golang.org/fake/g"; const F = "f" + g.G`),
+ filepath.Join(dir, "g", "g.go"): []byte(`package g; const G = "g"`),
+ filepath.Join(dir, "h", "h.go"): []byte(`package h; const H = "h"`),
+ },
+ `"efgh_"`},
+ {"multiple_files_four_packages_again",
+ map[string][]byte{
+ filepath.Join(dir, "e", "e.go"): []byte(`package e; import "golang.org/fake/f"; const E = "e" + f.F + underscore`),
+ filepath.Join(dir, "e", "e_util.go"): []byte(`package e; const underscore = "_"`),
+ filepath.Join(dir, "f", "f.go"): []byte(`package f; import "golang.org/fake/g"; const F = "f" + g.G`),
+ filepath.Join(dir, "g", "g.go"): []byte(`package g; import "golang.org/fake/h"; const G = "g" + h.H`),
+ filepath.Join(dir, "h", "h.go"): []byte(`package h; const H = "h"`),
+ },
+ `"efgh_"`},
+ {"main_overlay",
+ map[string][]byte{
+ filepath.Join(dir, "e", "main.go"): []byte(`package main; import "golang.org/fake/a"; const E = "e" + a.A; func main(){}`)},
+ `"eabc"`},
+ } {
+ t.Run(test.name, func(t *testing.T) {
+ exported.Config.Overlay = test.overlay
+ exported.Config.Mode = packages.LoadAllSyntax
+ exported.Config.Logf = t.Logf
+
+ // With an overlay, we don't know the expected import path,
+ // so load with the absolute path of the directory.
+ initial, err := packages.Load(exported.Config, filepath.Join(dir, "e"))
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // Check value of e.E.
+ e := initial[0]
+ eE := constant(e, "E")
+ if eE == nil {
+ t.Fatalf("e.E: was nil in %#v", e)
+ }
+ got := eE.Val().String()
+ if got != test.want {
+ t.Fatalf("e.E: got %s, want %s", got, test.want)
+ }
+ })
+ }
+}
+
+// Test that we can create a package and its test package in an overlay.
+func TestOverlayNewPackageAndTest(t *testing.T) {
+ packagestest.TestAll(t, testOverlayNewPackageAndTest)
+}
+func testOverlayNewPackageAndTest(t *testing.T, exporter packagestest.Exporter) {
+ exported := packagestest.Export(t, exporter, []packagestest.Module{
+ {
+ Name: "golang.org/fake",
+ Files: map[string]interface{}{
+ "foo.txt": "placeholder",
+ },
+ },
+ })
+ defer exported.Cleanup()
+
+ dir := filepath.Dir(exported.File("golang.org/fake", "foo.txt"))
+ exported.Config.Overlay = map[string][]byte{
+ filepath.Join(dir, "a.go"): []byte(`package a;`),
+ filepath.Join(dir, "a_test.go"): []byte(`package a; import "testing";`),
+ }
+ initial, err := packages.Load(exported.Config, "file="+filepath.Join(dir, "a.go"), "file="+filepath.Join(dir, "a_test.go"))
+ if err != nil {
+ t.Fatal(err)
+ }
+ if len(initial) != 2 {
+ t.Errorf("got %v packages, wanted %v", len(initial), 2)
+ }
+}
+
+func TestAdHocOverlays(t *testing.T) {
+ testenv.NeedsTool(t, "go")
+
+ // This test doesn't use packagestest because we are testing ad-hoc packages,
+ // which are outside of $GOPATH and outside of a module.
+ tmp, err := ioutil.TempDir("", "testAdHocOverlays")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(tmp)
+
+ filename := filepath.Join(tmp, "a.go")
+ content := []byte(`package a
+const A = 1
+`)
+
+ // Make sure that the user's value of GO111MODULE does not affect test results.
+ for _, go111module := range []string{"off", "auto", "on"} {
+ t.Run("GO111MODULE="+go111module, func(t *testing.T) {
+ config := &packages.Config{
+ Dir: tmp,
+ Env: append(os.Environ(), "GOPACKAGESDRIVER=off", fmt.Sprintf("GO111MODULE=%s", go111module)),
+ Mode: packages.LoadAllSyntax,
+ Overlay: map[string][]byte{
+ filename: content,
+ },
+ Logf: t.Logf,
+ }
+ initial, err := packages.Load(config, fmt.Sprintf("file=%s", filename))
+ if err != nil {
+ t.Fatal(err)
+ }
+ if len(initial) == 0 {
+ t.Fatalf("no packages for %s", filename)
+ }
+ // Check value of a.A.
+ a := initial[0]
+ if a.Errors != nil {
+ t.Fatalf("a: got errors %+v, want no error", err)
+ }
+ aA := constant(a, "A")
+ if aA == nil {
+ t.Errorf("a.A: got nil")
+ return
+ }
+ got := aA.Val().String()
+ if want := "1"; got != want {
+ t.Errorf("a.A: got %s, want %s", got, want)
+ }
+ })
+ }
+}
+
+// TestOverlayModFileChanges tests the behavior resulting from having files from
+// multiple modules in overlays.
+func TestOverlayModFileChanges(t *testing.T) {
+ testenv.NeedsTool(t, "go")
+
+ // Create two unrelated modules in a temporary directory.
+ tmp, err := ioutil.TempDir("", "tmp")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(tmp)
+
+ // mod1 has a dependency on golang.org/x/xerrors.
+ mod1, err := ioutil.TempDir(tmp, "mod1")
+ if err != nil {
+ t.Fatal(err)
+ }
+ if err := ioutil.WriteFile(filepath.Join(mod1, "go.mod"), []byte(`module mod1
+
+ require (
+ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7
+ )
+ `), 0775); err != nil {
+ t.Fatal(err)
+ }
+
+ // mod2 does not have any dependencies.
+ mod2, err := ioutil.TempDir(tmp, "mod2")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ want := `module mod2
+
+go 1.11
+`
+ if err := ioutil.WriteFile(filepath.Join(mod2, "go.mod"), []byte(want), 0775); err != nil {
+ t.Fatal(err)
+ }
+
+ // Run packages.Load on mod2, while passing the contents over mod1/main.go in the overlay.
+ config := &packages.Config{
+ Dir: mod2,
+ Env: append(os.Environ(), "GOPACKAGESDRIVER=off"),
+ Mode: packages.LoadImports,
+ Overlay: map[string][]byte{
+ filepath.Join(mod1, "main.go"): []byte(`package main
+import "golang.org/x/xerrors"
+func main() {
+ _ = errors.New("")
+}
+`),
+ filepath.Join(mod2, "main.go"): []byte(`package main
+func main() {}
+`),
+ },
+ }
+ if _, err := packages.Load(config, fmt.Sprintf("file=%s", filepath.Join(mod2, "main.go"))); err != nil {
+ t.Fatal(err)
+ }
+
+ // Check that mod2/go.mod has not been modified.
+ got, err := ioutil.ReadFile(filepath.Join(mod2, "go.mod"))
+ if err != nil {
+ t.Fatal(err)
+ }
+ if string(got) != want {
+ t.Errorf("expected %s, got %s", want, string(got))
+ }
+}
+
+func TestOverlayGOPATHVendoring(t *testing.T) {
+ exported := packagestest.Export(t, packagestest.GOPATH, []packagestest.Module{{
+ Name: "golang.org/fake",
+ Files: map[string]interface{}{
+ "vendor/vendor.com/foo/foo.go": `package foo; const X = "hi"`,
+ "user/user.go": `package user`,
+ },
+ }})
+ defer exported.Cleanup()
+
+ exported.Config.Mode = packages.LoadAllSyntax
+ exported.Config.Logf = t.Logf
+ exported.Config.Overlay = map[string][]byte{
+ exported.File("golang.org/fake", "user/user.go"): []byte(`package user; import "vendor.com/foo"; var x = foo.X`),
+ }
+ initial, err := packages.Load(exported.Config, "golang.org/fake/user")
+ if err != nil {
+ t.Fatal(err)
+ }
+ user := initial[0]
+ if len(user.Imports) != 1 {
+ t.Fatal("no imports for user")
+ }
+ if user.Imports["vendor.com/foo"].Name != "foo" {
+ t.Errorf("failed to load vendored package foo, imports: %#v", user.Imports["vendor.com/foo"])
+ }
+}
+
+func TestContainsOverlay(t *testing.T) { packagestest.TestAll(t, testContainsOverlay) }
+func testContainsOverlay(t *testing.T, exporter packagestest.Exporter) {
+ exported := packagestest.Export(t, exporter, []packagestest.Module{{
+ Name: "golang.org/fake",
+ Files: map[string]interface{}{
+ "a/a.go": `package a; import "golang.org/fake/b"`,
+ "b/b.go": `package b; import "golang.org/fake/c"`,
+ "c/c.go": `package c`,
+ }}})
+ defer exported.Cleanup()
+ bOverlayFile := filepath.Join(filepath.Dir(exported.File("golang.org/fake", "b/b.go")), "b_overlay.go")
+ exported.Config.Mode = packages.LoadImports
+ exported.Config.Overlay = map[string][]byte{bOverlayFile: []byte(`package b;`)}
+ initial, err := packages.Load(exported.Config, "file="+bOverlayFile)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ graph, _ := importGraph(initial)
+ wantGraph := `
+* golang.org/fake/b
+ golang.org/fake/c
+ golang.org/fake/b -> golang.org/fake/c
+`[1:]
+ if graph != wantGraph {
+ t.Errorf("wrong import graph: got <<%s>>, want <<%s>>", graph, wantGraph)
+ }
+}
+
+func TestContainsOverlayXTest(t *testing.T) { packagestest.TestAll(t, testContainsOverlayXTest) }
+func testContainsOverlayXTest(t *testing.T, exporter packagestest.Exporter) {
+ exported := packagestest.Export(t, exporter, []packagestest.Module{{
+ Name: "golang.org/fake",
+ Files: map[string]interface{}{
+ "a/a.go": `package a; import "golang.org/fake/b"`,
+ "b/b.go": `package b; import "golang.org/fake/c"`,
+ "c/c.go": `package c`,
+ }}})
+ defer exported.Cleanup()
+
+ bOverlayXTestFile := filepath.Join(filepath.Dir(exported.File("golang.org/fake", "b/b.go")), "b_overlay_x_test.go")
+ exported.Config.Mode = packages.NeedName | packages.NeedFiles | packages.NeedImports
+ exported.Config.Overlay = map[string][]byte{bOverlayXTestFile: []byte(`package b_test; import "golang.org/fake/b"`)}
+ initial, err := packages.Load(exported.Config, "file="+bOverlayXTestFile)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ graph, _ := importGraph(initial)
+ wantGraph := `
+ golang.org/fake/b
+* golang.org/fake/b_test [golang.org/fake/b.test]
+ golang.org/fake/c
+ golang.org/fake/b -> golang.org/fake/c
+ golang.org/fake/b_test [golang.org/fake/b.test] -> golang.org/fake/b
+`[1:]
+ if graph != wantGraph {
+ t.Errorf("wrong import graph: got <<%s>>, want <<%s>>", graph, wantGraph)
+ }
+}
+
+// Tests golang/go#35973, fixed in Go 1.14.
+func TestInvalidFilesInOverlay(t *testing.T) { packagestest.TestAll(t, testInvalidFilesInOverlay) }
+func testInvalidFilesInOverlay(t *testing.T, exporter packagestest.Exporter) {
+ testenv.NeedsGo1Point(t, 14)
+
+ exported := packagestest.Export(t, exporter, []packagestest.Module{
+ {
+ Name: "golang.org/fake",
+ Files: map[string]interface{}{
+ "d/d.go": `package d; import "net/http"; const d = http.MethodGet;`,
+ "d/util.go": ``,
+ "d/d_test.go": ``,
+ },
+ },
+ })
+ defer exported.Cleanup()
+
+ dir := filepath.Dir(filepath.Dir(exported.File("golang.org/fake", "d/d.go")))
+
+ // Additional tests for test variants.
+ for i, tt := range []struct {
+ name string
+ overlay map[string][]byte
+ want string // expected value of d.D
+
+ }{
+ // Overlay with a test variant.
+ {"test_variant",
+ map[string][]byte{
+ filepath.Join(dir, "d", "d_test.go"): []byte(`package d; import "testing"; const D = d + "_test"; func TestD(t *testing.T) {};`)},
+ `"GET_test"`},
+ // Overlay in package.
+ {"second_file",
+ map[string][]byte{
+ filepath.Join(dir, "d", "util.go"): []byte(`package d; const D = d + "_util";`)},
+ `"GET_util"`},
+ } {
+ t.Run(tt.name, func(t *testing.T) {
+ exported.Config.Overlay = tt.overlay
+ exported.Config.Mode = packages.NeedName | packages.NeedFiles | packages.NeedCompiledGoFiles |
+ packages.NeedDeps | packages.NeedTypes | packages.NeedTypesSizes
+ exported.Config.Tests = true
+
+ for f := range tt.overlay {
+ initial, err := packages.Load(exported.Config, fmt.Sprintf("file=%s", f))
+ if err != nil {
+ t.Fatal(err)
+ }
+ d := initial[0]
+ var containsFile bool
+ for _, goFile := range d.CompiledGoFiles {
+ if f == goFile {
+ containsFile = true
+ break
+ }
+ }
+ if !containsFile {
+ t.Fatalf("expected %s in CompiledGoFiles, got %v", f, d.CompiledGoFiles)
+ }
+ // Check value of d.D.
+ dD := constant(d, "D")
+ if dD == nil {
+ t.Fatalf("%d. d.D: got nil", i)
+ }
+ got := dD.Val().String()
+ if got != tt.want {
+ t.Fatalf("%d. d.D: got %s, want %s", i, got, tt.want)
+ }
+ }
+ })
+ }
+}
+
func checkPkg(t *testing.T, p *packages.Package, id, name string, syntax int) bool {
t.Helper()
if p.ID == id && p.Name == name && len(p.Syntax) == syntax {
diff --git a/go/packages/packages_test.go b/go/packages/packages_test.go
index 8eb87b5..2974ecc 100644
--- a/go/packages/packages_test.go
+++ b/go/packages/packages_test.go
@@ -886,251 +886,6 @@
}
}
-func TestOverlay(t *testing.T) { packagestest.TestAll(t, testOverlay) }
-func testOverlay(t *testing.T, exporter packagestest.Exporter) {
- exported := packagestest.Export(t, exporter, []packagestest.Module{{
- Name: "golang.org/fake",
- Files: map[string]interface{}{
- "a/a.go": `package a; import "golang.org/fake/b"; const A = "a" + b.B`,
- "b/b.go": `package b; import "golang.org/fake/c"; const B = "b" + c.C`,
- "c/c.go": `package c; const C = "c"`,
- "c/c_test.go": `package c; import "testing"; func TestC(t *testing.T) {}`,
- "d/d.go": `package d; const D = "d"`,
- }}})
- defer exported.Cleanup()
-
- for i, test := range []struct {
- overlay map[string][]byte
- want string // expected value of a.A
- wantErrs []string
- }{
- {nil, `"abc"`, nil}, // default
- {map[string][]byte{}, `"abc"`, nil}, // empty overlay
- {map[string][]byte{exported.File("golang.org/fake", "c/c.go"): []byte(`package c; const C = "C"`)}, `"abC"`, nil},
- {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},
- // Overlay with an existing file in an existing package adding a new import.
- {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},
- // Overlay with an existing file in an existing package.
- {map[string][]byte{exported.File("golang.org/fake", "c/c.go"): []byte(`package c; import "net/http"; const C = http.MethodGet`)}, `"abGET"`, nil},
- // Overlay with a new file in an existing package.
- {map[string][]byte{
- exported.File("golang.org/fake", "c/c.go"): []byte(`package c;`),
- filepath.Join(filepath.Dir(exported.File("golang.org/fake", "c/c.go")), "c_new_file.go"): []byte(`package c; const C = "Ç"`)},
- `"abÇ"`, nil},
- // Overlay with a new file in an existing package, adding a new dependency to that package.
- {map[string][]byte{
- exported.File("golang.org/fake", "c/c.go"): []byte(`package c;`),
- 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`)},
- `"abcd"`, nil},
- } {
- exported.Config.Overlay = test.overlay
- exported.Config.Mode = packages.LoadAllSyntax
- initial, err := packages.Load(exported.Config, "golang.org/fake/a")
- if err != nil {
- t.Error(err)
- continue
- }
-
- // Check value of a.A.
- a := initial[0]
- aA := constant(a, "A")
- if aA == nil {
- t.Errorf("%d. a.A: got nil", i)
- continue
- }
- got := aA.Val().String()
- if got != test.want {
- t.Errorf("%d. a.A: got %s, want %s", i, got, test.want)
- }
-
- // Check errors.
- var errors []packages.Error
- packages.Visit(initial, nil, func(pkg *packages.Package) {
- errors = append(errors, pkg.Errors...)
- })
- if errs := errorMessages(errors); !reflect.DeepEqual(errs, test.wantErrs) {
- t.Errorf("%d. got errors %s, want %s", i, errs, test.wantErrs)
- }
- }
-}
-
-func TestOverlayDeps(t *testing.T) { packagestest.TestAll(t, testOverlayDeps) }
-func testOverlayDeps(t *testing.T, exporter packagestest.Exporter) {
- exported := packagestest.Export(t, exporter, []packagestest.Module{{
- Name: "golang.org/fake",
- Files: map[string]interface{}{
- "c/c.go": `package c; const C = "c"`,
- "c/c_test.go": `package c; import "testing"; func TestC(t *testing.T) {}`,
- },
- }})
- defer exported.Cleanup()
-
- exported.Config.Overlay = map[string][]byte{exported.File("golang.org/fake", "c/c.go"): []byte(`package c; import "net/http"; const C = http.MethodGet`)}
- exported.Config.Mode = packages.NeedName |
- packages.NeedFiles |
- packages.NeedCompiledGoFiles |
- packages.NeedImports |
- packages.NeedDeps |
- packages.NeedTypesSizes
- pkgs, err := packages.Load(exported.Config, fmt.Sprintf("file=%s", exported.File("golang.org/fake", "c/c.go")))
- if err != nil {
- t.Error(err)
- }
-
- // Find package golang.org/fake/c
- sort.Slice(pkgs, func(i, j int) bool { return pkgs[i].ID < pkgs[j].ID })
- pkgc := pkgs[0]
- if pkgc.ID != "golang.org/fake/c" {
- t.Errorf("expected first package in sorted list to be \"golang.org/fake/c\", got %v", pkgc.ID)
- }
-
- // Make sure golang.org/fake/c imports net/http, as per the overlay.
- contains := func(imports map[string]*packages.Package, wantImport string) bool {
- for imp := range imports {
- if imp == wantImport {
- return true
- }
- }
- return false
- }
- if !contains(pkgc.Imports, "net/http") {
- t.Errorf("expected import of %s in package %s, got the following imports: %v",
- "net/http", pkgc.ID, pkgc.Imports)
- }
-
-}
-
-func TestNewPackagesInOverlay(t *testing.T) { packagestest.TestAll(t, testNewPackagesInOverlay) }
-func testNewPackagesInOverlay(t *testing.T, exporter packagestest.Exporter) {
- exported := packagestest.Export(t, exporter, []packagestest.Module{
- {
- Name: "golang.org/fake",
- Files: map[string]interface{}{
- "a/a.go": `package a; import "golang.org/fake/b"; const A = "a" + b.B`,
- "b/b.go": `package b; import "golang.org/fake/c"; const B = "b" + c.C`,
- "c/c.go": `package c; const C = "c"`,
- "d/d.go": `package d; const D = "d"`,
- },
- },
- {
- Name: "example.com/extramodule",
- Files: map[string]interface{}{
- "pkg/x.go": "package pkg\n",
- },
- },
- })
- defer exported.Cleanup()
-
- dir := filepath.Dir(filepath.Dir(exported.File("golang.org/fake", "a/a.go")))
-
- for _, test := range []struct {
- name string
- overlay map[string][]byte
- want string // expected value of e.E
- }{
- {"one_file",
- map[string][]byte{
- filepath.Join(dir, "e", "e.go"): []byte(`package e; import "golang.org/fake/a"; const E = "e" + a.A`)},
- `"eabc"`},
- {"multiple_files_same_package",
- map[string][]byte{
- filepath.Join(dir, "e", "e.go"): []byte(`package e; import "golang.org/fake/a"; const E = "e" + a.A + underscore`),
- filepath.Join(dir, "e", "e_util.go"): []byte(`package e; const underscore = "_"`),
- },
- `"eabc_"`},
- {"multiple_files_two_packages",
- map[string][]byte{
- filepath.Join(dir, "e", "e.go"): []byte(`package e; import "golang.org/fake/f"; const E = "e" + f.F + underscore`),
- filepath.Join(dir, "e", "e_util.go"): []byte(`package e; const underscore = "_"`),
- filepath.Join(dir, "f", "f.go"): []byte(`package f; const F = "f"`),
- },
- `"ef_"`},
- {"multiple_files_three_packages",
- map[string][]byte{
- filepath.Join(dir, "e", "e.go"): []byte(`package e; import "golang.org/fake/f"; const E = "e" + f.F + underscore`),
- filepath.Join(dir, "e", "e_util.go"): []byte(`package e; const underscore = "_"`),
- filepath.Join(dir, "f", "f.go"): []byte(`package f; import "golang.org/fake/g"; const F = "f" + g.G`),
- filepath.Join(dir, "g", "g.go"): []byte(`package g; const G = "g"`),
- },
- `"efg_"`},
- {"multiple_files_four_packages",
- map[string][]byte{
- 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`),
- filepath.Join(dir, "e", "e_util.go"): []byte(`package e; const underscore = "_"`),
- filepath.Join(dir, "f", "f.go"): []byte(`package f; import "golang.org/fake/g"; const F = "f" + g.G`),
- filepath.Join(dir, "g", "g.go"): []byte(`package g; const G = "g"`),
- filepath.Join(dir, "h", "h.go"): []byte(`package h; const H = "h"`),
- },
- `"efgh_"`},
- {"multiple_files_four_packages_again",
- map[string][]byte{
- filepath.Join(dir, "e", "e.go"): []byte(`package e; import "golang.org/fake/f"; const E = "e" + f.F + underscore`),
- filepath.Join(dir, "e", "e_util.go"): []byte(`package e; const underscore = "_"`),
- filepath.Join(dir, "f", "f.go"): []byte(`package f; import "golang.org/fake/g"; const F = "f" + g.G`),
- filepath.Join(dir, "g", "g.go"): []byte(`package g; import "golang.org/fake/h"; const G = "g" + h.H`),
- filepath.Join(dir, "h", "h.go"): []byte(`package h; const H = "h"`),
- },
- `"efgh_"`},
- {"main_overlay",
- map[string][]byte{
- filepath.Join(dir, "e", "main.go"): []byte(`package main; import "golang.org/fake/a"; const E = "e" + a.A; func main(){}`)},
- `"eabc"`},
- } {
- t.Run(test.name, func(t *testing.T) {
- exported.Config.Overlay = test.overlay
- exported.Config.Mode = packages.LoadAllSyntax
- exported.Config.Logf = t.Logf
-
- // With an overlay, we don't know the expected import path,
- // so load with the absolute path of the directory.
- initial, err := packages.Load(exported.Config, filepath.Join(dir, "e"))
- if err != nil {
- t.Fatal(err)
- }
-
- // Check value of e.E.
- e := initial[0]
- eE := constant(e, "E")
- if eE == nil {
- t.Fatalf("e.E: was nil in %#v", e)
- }
- got := eE.Val().String()
- if got != test.want {
- t.Fatalf("e.E: got %s, want %s", got, test.want)
- }
- })
- }
-}
-
-// Test that we can create a package and its test package in an overlay.
-func TestOverlayNewPackageAndTest(t *testing.T) {
- packagestest.TestAll(t, testOverlayNewPackageAndTest)
-}
-func testOverlayNewPackageAndTest(t *testing.T, exporter packagestest.Exporter) {
- exported := packagestest.Export(t, exporter, []packagestest.Module{
- {
- Name: "golang.org/fake",
- Files: map[string]interface{}{
- "foo.txt": "placeholder",
- },
- },
- })
- defer exported.Cleanup()
-
- dir := filepath.Dir(exported.File("golang.org/fake", "foo.txt"))
- exported.Config.Overlay = map[string][]byte{
- filepath.Join(dir, "a.go"): []byte(`package a;`),
- filepath.Join(dir, "a_test.go"): []byte(`package a; import "testing";`),
- }
- initial, err := packages.Load(exported.Config, "file="+filepath.Join(dir, "a.go"), "file="+filepath.Join(dir, "a_test.go"))
- if err != nil {
- t.Fatal(err)
- }
- if len(initial) != 2 {
- t.Errorf("got %v packages, wanted %v", len(initial), 2)
- }
-}
-
func TestAdHocPackagesBadImport(t *testing.T) {
// This test doesn't use packagestest because we are testing ad-hoc packages,
// which are outside of $GOPATH and outside of a module.
@@ -1179,158 +934,6 @@
}
}
-func TestAdHocOverlays(t *testing.T) {
- testenv.NeedsTool(t, "go")
-
- // This test doesn't use packagestest because we are testing ad-hoc packages,
- // which are outside of $GOPATH and outside of a module.
- tmp, err := ioutil.TempDir("", "testAdHocOverlays")
- if err != nil {
- t.Fatal(err)
- }
- defer os.RemoveAll(tmp)
-
- filename := filepath.Join(tmp, "a.go")
- content := []byte(`package a
-const A = 1
-`)
-
- // Make sure that the user's value of GO111MODULE does not affect test results.
- for _, go111module := range []string{"off", "auto", "on"} {
- t.Run("GO111MODULE="+go111module, func(t *testing.T) {
- config := &packages.Config{
- Dir: tmp,
- Env: append(os.Environ(), "GOPACKAGESDRIVER=off", fmt.Sprintf("GO111MODULE=%s", go111module)),
- Mode: packages.LoadAllSyntax,
- Overlay: map[string][]byte{
- filename: content,
- },
- Logf: t.Logf,
- }
- initial, err := packages.Load(config, fmt.Sprintf("file=%s", filename))
- if err != nil {
- t.Fatal(err)
- }
- if len(initial) == 0 {
- t.Fatalf("no packages for %s", filename)
- }
- // Check value of a.A.
- a := initial[0]
- if a.Errors != nil {
- t.Fatalf("a: got errors %+v, want no error", err)
- }
- aA := constant(a, "A")
- if aA == nil {
- t.Errorf("a.A: got nil")
- return
- }
- got := aA.Val().String()
- if want := "1"; got != want {
- t.Errorf("a.A: got %s, want %s", got, want)
- }
- })
- }
-}
-
-// TestOverlayModFileChanges tests the behavior resulting from having files from
-// multiple modules in overlays.
-func TestOverlayModFileChanges(t *testing.T) {
- testenv.NeedsTool(t, "go")
-
- // Create two unrelated modules in a temporary directory.
- tmp, err := ioutil.TempDir("", "tmp")
- if err != nil {
- t.Fatal(err)
- }
- defer os.RemoveAll(tmp)
-
- // mod1 has a dependency on golang.org/x/xerrors.
- mod1, err := ioutil.TempDir(tmp, "mod1")
- if err != nil {
- t.Fatal(err)
- }
- if err := ioutil.WriteFile(filepath.Join(mod1, "go.mod"), []byte(`module mod1
-
- require (
- golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7
- )
- `), 0775); err != nil {
- t.Fatal(err)
- }
-
- // mod2 does not have any dependencies.
- mod2, err := ioutil.TempDir(tmp, "mod2")
- if err != nil {
- t.Fatal(err)
- }
-
- want := `module mod2
-
-go 1.11
-`
- if err := ioutil.WriteFile(filepath.Join(mod2, "go.mod"), []byte(want), 0775); err != nil {
- t.Fatal(err)
- }
-
- // Run packages.Load on mod2, while passing the contents over mod1/main.go in the overlay.
- config := &packages.Config{
- Dir: mod2,
- Env: append(os.Environ(), "GOPACKAGESDRIVER=off"),
- Mode: packages.LoadImports,
- Overlay: map[string][]byte{
- filepath.Join(mod1, "main.go"): []byte(`package main
-import "golang.org/x/xerrors"
-func main() {
- _ = errors.New("")
-}
-`),
- filepath.Join(mod2, "main.go"): []byte(`package main
-func main() {}
-`),
- },
- }
- if _, err := packages.Load(config, fmt.Sprintf("file=%s", filepath.Join(mod2, "main.go"))); err != nil {
- t.Fatal(err)
- }
-
- // Check that mod2/go.mod has not been modified.
- got, err := ioutil.ReadFile(filepath.Join(mod2, "go.mod"))
- if err != nil {
- t.Fatal(err)
- }
- if string(got) != want {
- t.Errorf("expected %s, got %s", want, string(got))
- }
-}
-
-func TestOverlayGOPATHVendoring(t *testing.T) {
- exported := packagestest.Export(t, packagestest.GOPATH, []packagestest.Module{{
- Name: "golang.org/fake",
- Files: map[string]interface{}{
- "vendor/vendor.com/foo/foo.go": `package foo; const X = "hi"`,
- "user/user.go": `package user`,
- },
- }})
- defer exported.Cleanup()
-
- exported.Config.Mode = packages.LoadAllSyntax
- exported.Config.Logf = t.Logf
- exported.Config.Overlay = map[string][]byte{
- exported.File("golang.org/fake", "user/user.go"): []byte(`package user; import "vendor.com/foo"; var x = foo.X`),
- }
- initial, err := packages.Load(exported.Config, "golang.org/fake/user")
- if err != nil {
- t.Fatal(err)
- }
- user := initial[0]
- if len(user.Imports) != 1 {
- t.Fatal("no imports for user")
- }
- if user.Imports["vendor.com/foo"].Name != "foo" {
- t.Errorf("failed to load vendored package foo, imports: %#v", user.Imports["vendor.com/foo"])
- }
-}
-
func TestLoadAllSyntaxImportErrors(t *testing.T) {
packagestest.TestAll(t, testLoadAllSyntaxImportErrors)
}
@@ -1521,67 +1124,6 @@
}
}
-func TestContainsOverlay(t *testing.T) { packagestest.TestAll(t, testContainsOverlay) }
-func testContainsOverlay(t *testing.T, exporter packagestest.Exporter) {
- exported := packagestest.Export(t, exporter, []packagestest.Module{{
- Name: "golang.org/fake",
- Files: map[string]interface{}{
- "a/a.go": `package a; import "golang.org/fake/b"`,
- "b/b.go": `package b; import "golang.org/fake/c"`,
- "c/c.go": `package c`,
- }}})
- defer exported.Cleanup()
- bOverlayFile := filepath.Join(filepath.Dir(exported.File("golang.org/fake", "b/b.go")), "b_overlay.go")
- exported.Config.Mode = packages.LoadImports
- exported.Config.Overlay = map[string][]byte{bOverlayFile: []byte(`package b;`)}
- initial, err := packages.Load(exported.Config, "file="+bOverlayFile)
- if err != nil {
- t.Fatal(err)
- }
-
- graph, _ := importGraph(initial)
- wantGraph := `
-* golang.org/fake/b
- golang.org/fake/c
- golang.org/fake/b -> golang.org/fake/c
-`[1:]
- if graph != wantGraph {
- t.Errorf("wrong import graph: got <<%s>>, want <<%s>>", graph, wantGraph)
- }
-}
-
-func TestContainsOverlayXTest(t *testing.T) { packagestest.TestAll(t, testContainsOverlayXTest) }
-func testContainsOverlayXTest(t *testing.T, exporter packagestest.Exporter) {
- exported := packagestest.Export(t, exporter, []packagestest.Module{{
- Name: "golang.org/fake",
- Files: map[string]interface{}{
- "a/a.go": `package a; import "golang.org/fake/b"`,
- "b/b.go": `package b; import "golang.org/fake/c"`,
- "c/c.go": `package c`,
- }}})
- defer exported.Cleanup()
-
- bOverlayXTestFile := filepath.Join(filepath.Dir(exported.File("golang.org/fake", "b/b.go")), "b_overlay_x_test.go")
- exported.Config.Mode = packages.NeedName | packages.NeedFiles | packages.NeedImports
- exported.Config.Overlay = map[string][]byte{bOverlayXTestFile: []byte(`package b_test; import "golang.org/fake/b"`)}
- initial, err := packages.Load(exported.Config, "file="+bOverlayXTestFile)
- if err != nil {
- t.Fatal(err)
- }
-
- graph, _ := importGraph(initial)
- wantGraph := `
- golang.org/fake/b
-* golang.org/fake/b_test [golang.org/fake/b.test]
- golang.org/fake/c
- golang.org/fake/b -> golang.org/fake/c
- golang.org/fake/b_test [golang.org/fake/b.test] -> golang.org/fake/b
-`[1:]
- if graph != wantGraph {
- t.Errorf("wrong import graph: got <<%s>>, want <<%s>>", graph, wantGraph)
- }
-}
-
// This test ensures that the effective GOARCH variable in the
// application determines the Sizes function used by the type checker.
// This behavior is a stop-gap until we make the build system's query
@@ -2799,78 +2341,6 @@
}
}
-// Tests golang/go#35973, fixed in Go 1.14.
-func TestInvalidFilesInOverlay(t *testing.T) { packagestest.TestAll(t, testInvalidFilesInOverlay) }
-func testInvalidFilesInOverlay(t *testing.T, exporter packagestest.Exporter) {
- testenv.NeedsGo1Point(t, 14)
- exported := packagestest.Export(t, exporter, []packagestest.Module{
- {
- Name: "golang.org/fake",
- Files: map[string]interface{}{
- "d/d.go": `package d; import "net/http"; const d = http.MethodGet;`,
- "d/util.go": ``,
- "d/d_test.go": ``,
- },
- },
- })
- defer exported.Cleanup()
-
- dir := filepath.Dir(filepath.Dir(exported.File("golang.org/fake", "d/d.go")))
-
- // Additional tests for test variants.
- for i, tt := range []struct {
- name string
- overlay map[string][]byte
- want string // expected value of d.D
-
- }{
- // Overlay with a test variant.
- {"test_variant",
- map[string][]byte{
- filepath.Join(dir, "d", "d_test.go"): []byte(`package d; import "testing"; const D = d + "_test"; func TestD(t *testing.T) {};`)},
- `"GET_test"`},
- // Overlay in package.
- {"second_file",
- map[string][]byte{
- filepath.Join(dir, "d", "util.go"): []byte(`package d; const D = d + "_util";`)},
- `"GET_util"`},
- } {
- t.Run(tt.name, func(t *testing.T) {
- exported.Config.Overlay = tt.overlay
- exported.Config.Mode = packages.NeedName | packages.NeedFiles | packages.NeedCompiledGoFiles |
- packages.NeedDeps | packages.NeedTypes | packages.NeedTypesSizes
- exported.Config.Tests = true
-
- for f := range tt.overlay {
- initial, err := packages.Load(exported.Config, fmt.Sprintf("file=%s", f))
- if err != nil {
- t.Fatal(err)
- }
- d := initial[0]
- var containsFile bool
- for _, goFile := range d.CompiledGoFiles {
- if f == goFile {
- containsFile = true
- break
- }
- }
- if !containsFile {
- t.Fatalf("expected %s in CompiledGoFiles, got %v", f, d.CompiledGoFiles)
- }
- // Check value of d.D.
- dD := constant(d, "D")
- if dD == nil {
- t.Fatalf("%d. d.D: got nil", i)
- }
- got := dD.Val().String()
- if got != tt.want {
- t.Fatalf("%d. d.D: got %s, want %s", i, got, tt.want)
- }
- }
- })
- }
-}
-
// TestInvalidFilesInXTest checks the fix for golang/go#37971 in Go 1.15.
func TestInvalidFilesInXTest(t *testing.T) { packagestest.TestAll(t, testInvalidFilesInXTest) }
func testInvalidFilesInXTest(t *testing.T, exporter packagestest.Exporter) {