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