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