From c138986dd9b9ae8c0ef8bc8fb29f4c4d2d7af3e2 Mon Sep 17 00:00:00 2001 From: Rebecca Stambler Date: Fri, 26 Jun 2020 18:40:43 -0400 Subject: [PATCH] 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 Run-TryBot: Rebecca Stambler TryBot-Result: Gobot Gobot --- go/packages/overlay_test.go | 535 +++++++++++++++++++++++++++++++++++ go/packages/packages_test.go | 530 ---------------------------------- 2 files changed, 535 insertions(+), 530 deletions(-) diff --git a/go/packages/overlay_test.go b/go/packages/overlay_test.go index 618b5082c6..d48c47bb14 100644 --- a/go/packages/overlay_test.go +++ b/go/packages/overlay_test.go @@ -2,13 +2,17 @@ package packages_test 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 TestHello(t *testing.T) { } } +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 8eb87b5ade..2974eccd7a 100644 --- a/go/packages/packages_test.go +++ b/go/packages/packages_test.go @@ -886,251 +886,6 @@ func testParseFileModifyAST(t *testing.T, exporter packagestest.Exporter) { } } -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 @@ const A = 1 } } -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 testContains(t *testing.T, exporter packagestest.Exporter) { } } -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 @@ func testIssue37529(t *testing.T, exporter packagestest.Exporter) { } } -// 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) {