github.com/cockroachdb/tools@v0.0.0-20230222021103-a6d27438930d/go/packages/overlay_test.go (about)

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