1 // Copyright 2018 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.
14 constantpkg "go/constant"
29 "golang.org/x/tools/go/packages"
30 "golang.org/x/tools/go/packages/packagestest"
31 "golang.org/x/tools/internal/packagesinternal"
32 "golang.org/x/tools/internal/testenv"
35 // testCtx is canceled when the test binary is about to time out.
37 // If https://golang.org/issue/28135 is accepted, uses of this variable in test
38 // functions should be replaced by t.Context().
39 var testCtx = context.Background()
41 func TestMain(m *testing.M) {
42 testenv.ExitIfSmallMachine()
44 timeoutFlag := flag.Lookup("test.timeout")
45 if timeoutFlag != nil {
46 if d := timeoutFlag.Value.(flag.Getter).Get().(time.Duration); d != 0 {
47 aBitShorter := d * 95 / 100
48 var cancel context.CancelFunc
49 testCtx, cancel = context.WithTimeout(testCtx, aBitShorter)
57 // TODO(adonovan): more test cases to write:
59 // - When the tests fail, make them print a 'cd & load' command
60 // that will allow the maintainer to interact with the failing scenario.
61 // - errors in go-list metadata
62 // - a foo.test package that cannot be built for some reason (e.g.
63 // import error) will result in a JSON blob with no name and a
64 // nonexistent testmain file in GoFiles. Test that we handle this
68 // LoadSyntax & LoadAllSyntax modes:
69 // - Fset may be user-supplied or not.
70 // - Packages.Info is correctly set.
71 // - typechecker configuration is honored
72 // - import cycles are gracefully handled in type checker.
73 // - test typechecking of generated test main and cgo.
75 // The zero-value of Config has LoadFiles mode.
76 func TestLoadZeroConfig(t *testing.T) {
77 testenv.NeedsGoPackages(t)
79 initial, err := packages.Load(nil, "hash")
83 if len(initial) != 1 {
84 t.Fatalf("got %s, want [hash]", initial)
87 // Even though the hash package has imports,
88 // they are not reported.
89 got := fmt.Sprintf("iamashamedtousethedisabledqueryname=%s srcs=%v imports=%v", hash.Name, srcs(hash), hash.Imports)
90 want := "iamashamedtousethedisabledqueryname=hash srcs=[hash.go] imports=map[]"
92 t.Fatalf("got %s, want %s", got, want)
96 func TestLoadImportsGraph(t *testing.T) { packagestest.TestAll(t, testLoadImportsGraph) }
97 func testLoadImportsGraph(t *testing.T, exporter packagestest.Exporter) {
98 exported := packagestest.Export(t, exporter, []packagestest.Module{{
99 Name: "golang.org/fake",
100 Files: map[string]interface{}{
101 "a/a.go": `package a; const A = 1`,
102 "b/b.go": `package b; import ("golang.org/fake/a"; _ "container/list"); var B = a.A`,
103 "c/c.go": `package c; import (_ "golang.org/fake/b"; _ "unsafe")`,
104 "c/c2.go": "// +build ignore\n\n" + `package c; import _ "fmt"`,
105 "subdir/d/d.go": `package d`,
106 "subdir/d/d_test.go": `package d; import _ "math/bits"`,
107 "subdir/d/x_test.go": `package d_test; import _ "golang.org/fake/subdir/d"`, // TODO(adonovan): test bad import here
108 "subdir/e/d.go": `package e`,
109 "e/e.go": `package main; import _ "golang.org/fake/b"`,
110 "e/e2.go": `package main; import _ "golang.org/fake/c"`,
111 "f/f.go": `package f`,
113 defer exported.Cleanup()
114 exported.Config.Mode = packages.LoadImports
115 initial, err := packages.Load(exported.Config, "golang.org/fake/c", "golang.org/fake/subdir/d", "golang.org/fake/e")
120 // Check graph topology.
121 graph, _ := importGraph(initial)
128 * golang.org/fake/subdir/d
129 * golang.org/fake/subdir/d [golang.org/fake/subdir/d.test]
130 * golang.org/fake/subdir/d.test
131 * golang.org/fake/subdir/d_test [golang.org/fake/subdir/d.test]
134 golang.org/fake/b -> container/list
135 golang.org/fake/b -> golang.org/fake/a
136 golang.org/fake/c -> golang.org/fake/b
137 golang.org/fake/c -> unsafe
138 golang.org/fake/e -> golang.org/fake/b
139 golang.org/fake/e -> golang.org/fake/c
140 golang.org/fake/subdir/d [golang.org/fake/subdir/d.test] -> math/bits
141 golang.org/fake/subdir/d.test -> golang.org/fake/subdir/d [golang.org/fake/subdir/d.test]
142 golang.org/fake/subdir/d.test -> golang.org/fake/subdir/d_test [golang.org/fake/subdir/d.test]
143 golang.org/fake/subdir/d_test [golang.org/fake/subdir/d.test] -> golang.org/fake/subdir/d [golang.org/fake/subdir/d.test]
146 if graph != wantGraph {
147 t.Errorf("wrong import graph: got <<%s>>, want <<%s>>", graph, wantGraph)
150 exported.Config.Tests = true
151 initial, err = packages.Load(exported.Config, "golang.org/fake/c", "golang.org/fake/subdir/d", "golang.org/fake/e")
156 // Check graph topology.
157 graph, all := importGraph(initial)
164 * golang.org/fake/subdir/d
165 * golang.org/fake/subdir/d [golang.org/fake/subdir/d.test]
166 * golang.org/fake/subdir/d.test
167 * golang.org/fake/subdir/d_test [golang.org/fake/subdir/d.test]
170 golang.org/fake/b -> container/list
171 golang.org/fake/b -> golang.org/fake/a
172 golang.org/fake/c -> golang.org/fake/b
173 golang.org/fake/c -> unsafe
174 golang.org/fake/e -> golang.org/fake/b
175 golang.org/fake/e -> golang.org/fake/c
176 golang.org/fake/subdir/d [golang.org/fake/subdir/d.test] -> math/bits
177 golang.org/fake/subdir/d.test -> golang.org/fake/subdir/d [golang.org/fake/subdir/d.test]
178 golang.org/fake/subdir/d.test -> golang.org/fake/subdir/d_test [golang.org/fake/subdir/d.test]
179 golang.org/fake/subdir/d_test [golang.org/fake/subdir/d.test] -> golang.org/fake/subdir/d [golang.org/fake/subdir/d.test]
182 if graph != wantGraph {
183 t.Errorf("wrong import graph: got <<%s>>, want <<%s>>", graph, wantGraph)
186 // Check node information: kind, name, srcs.
187 for _, test := range []struct {
194 {"golang.org/fake/a", "a", "package", "a.go", ""},
195 {"golang.org/fake/b", "b", "package", "b.go", ""},
196 {"golang.org/fake/c", "c", "package", "c.go", "c2.go"}, // c2.go is ignored
197 {"golang.org/fake/e", "main", "command", "e.go e2.go", ""},
198 {"container/list", "list", "package", "list.go", ""},
199 {"golang.org/fake/subdir/d", "d", "package", "d.go", ""},
200 {"golang.org/fake/subdir/d.test", "main", "command", "0.go", ""},
201 {"unsafe", "unsafe", "package", "", ""},
203 p, ok := all[test.id]
205 t.Errorf("no package %s", test.id)
208 if p.Name != test.wantName {
209 t.Errorf("%s.Name = %q, want %q", test.id, p.Name, test.wantName)
214 if p.Name == "main" {
219 if kind != test.wantKind {
220 t.Errorf("%s.Kind = %q, want %q", test.id, kind, test.wantKind)
223 if srcs := strings.Join(srcs(p), " "); srcs != test.wantSrcs {
224 t.Errorf("%s.Srcs = [%s], want [%s]", test.id, srcs, test.wantSrcs)
226 if ignored := strings.Join(cleanPaths(p.IgnoredFiles), " "); ignored != test.wantIgnored {
227 t.Errorf("%s.Srcs = [%s], want [%s]", test.id, ignored, test.wantIgnored)
231 // Test an ad-hoc package, analogous to "go run hello.go".
232 if initial, err := packages.Load(exported.Config, exported.File("golang.org/fake", "c/c.go")); len(initial) == 0 {
233 t.Errorf("failed to obtain metadata for ad-hoc package: %s", err)
235 got := fmt.Sprintf("%s %s", initial[0].ID, srcs(initial[0]))
236 if want := "command-line-arguments [c.go]"; got != want {
237 t.Errorf("oops: got %s, want %s", got, want)
242 // See StdlibTest for effective test of "std" wildcard.
243 // TODO(adonovan): test "all" returns everything in the current module.
245 // "..." (subdirectory)
246 initial, err = packages.Load(exported.Config, "golang.org/fake/subdir/...")
250 graph, _ = importGraph(initial)
252 * golang.org/fake/subdir/d
253 * golang.org/fake/subdir/d [golang.org/fake/subdir/d.test]
254 * golang.org/fake/subdir/d.test
255 * golang.org/fake/subdir/d_test [golang.org/fake/subdir/d.test]
256 * golang.org/fake/subdir/e
258 golang.org/fake/subdir/d [golang.org/fake/subdir/d.test] -> math/bits
259 golang.org/fake/subdir/d.test -> golang.org/fake/subdir/d [golang.org/fake/subdir/d.test]
260 golang.org/fake/subdir/d.test -> golang.org/fake/subdir/d_test [golang.org/fake/subdir/d.test]
261 golang.org/fake/subdir/d_test [golang.org/fake/subdir/d.test] -> golang.org/fake/subdir/d [golang.org/fake/subdir/d.test]
264 if graph != wantGraph {
265 t.Errorf("wrong import graph: got <<%s>>, want <<%s>>", graph, wantGraph)
270 func TestLoadImportsTestVariants(t *testing.T) { packagestest.TestAll(t, testLoadImportsTestVariants) }
271 func testLoadImportsTestVariants(t *testing.T, exporter packagestest.Exporter) {
272 exported := packagestest.Export(t, exporter, []packagestest.Module{{
273 Name: "golang.org/fake",
274 Files: map[string]interface{}{
275 "a/a.go": `package a; import _ "golang.org/fake/b"`,
276 "b/b.go": `package b`,
277 "b/b_test.go": `package b`,
278 "b/bx_test.go": `package b_test; import _ "golang.org/fake/a"`,
280 defer exported.Cleanup()
281 exported.Config.Mode = packages.LoadImports
282 exported.Config.Tests = true
284 initial, err := packages.Load(exported.Config, "golang.org/fake/a", "golang.org/fake/b")
289 // Check graph topology.
290 graph, _ := importGraph(initial)
293 golang.org/fake/a [golang.org/fake/b.test]
295 * golang.org/fake/b [golang.org/fake/b.test]
296 * golang.org/fake/b.test
297 * golang.org/fake/b_test [golang.org/fake/b.test]
298 golang.org/fake/a -> golang.org/fake/b
299 golang.org/fake/a [golang.org/fake/b.test] -> golang.org/fake/b [golang.org/fake/b.test]
300 golang.org/fake/b.test -> golang.org/fake/b [golang.org/fake/b.test]
301 golang.org/fake/b.test -> golang.org/fake/b_test [golang.org/fake/b.test]
302 golang.org/fake/b_test [golang.org/fake/b.test] -> golang.org/fake/a [golang.org/fake/b.test]
305 if graph != wantGraph {
306 t.Errorf("wrong import graph: got <<%s>>, want <<%s>>", graph, wantGraph)
310 func TestLoadAbsolutePath(t *testing.T) {
311 exported := packagestest.Export(t, packagestest.GOPATH, []packagestest.Module{{
312 Name: "golang.org/gopatha",
313 Files: map[string]interface{}{
314 "a/a.go": `package a`,
316 Name: "golang.org/gopathb",
317 Files: map[string]interface{}{
318 "b/b.go": `package b`,
320 defer exported.Cleanup()
322 initial, err := packages.Load(exported.Config, filepath.Dir(exported.File("golang.org/gopatha", "a/a.go")), filepath.Dir(exported.File("golang.org/gopathb", "b/b.go")))
324 t.Fatalf("failed to load imports: %v", err)
328 for _, p := range initial {
329 got = append(got, p.ID)
332 want := []string{"golang.org/gopatha/a", "golang.org/gopathb/b"}
333 if !reflect.DeepEqual(got, want) {
334 t.Fatalf("initial packages loaded: got [%s], want [%s]", got, want)
338 func TestVendorImports(t *testing.T) {
339 exported := packagestest.Export(t, packagestest.GOPATH, []packagestest.Module{{
340 Name: "golang.org/fake",
341 Files: map[string]interface{}{
342 "a/a.go": `package a; import _ "b"; import _ "golang.org/fake/c";`,
343 "a/vendor/b/b.go": `package b; import _ "golang.org/fake/c"`,
344 "c/c.go": `package c; import _ "b"`,
345 "c/vendor/b/b.go": `package b`,
347 defer exported.Cleanup()
348 exported.Config.Mode = packages.LoadImports
349 initial, err := packages.Load(exported.Config, "golang.org/fake/a", "golang.org/fake/c")
354 graph, all := importGraph(initial)
357 golang.org/fake/a/vendor/b
359 golang.org/fake/c/vendor/b
360 golang.org/fake/a -> golang.org/fake/a/vendor/b
361 golang.org/fake/a -> golang.org/fake/c
362 golang.org/fake/a/vendor/b -> golang.org/fake/c
363 golang.org/fake/c -> golang.org/fake/c/vendor/b
365 if graph != wantGraph {
366 t.Errorf("wrong import graph: got <<%s>>, want <<%s>>", graph, wantGraph)
369 for _, test := range []struct {
373 {"golang.org/fake/a", "b:golang.org/fake/a/vendor/b golang.org/fake/c:golang.org/fake/c"},
374 {"golang.org/fake/c", "b:golang.org/fake/c/vendor/b"},
375 {"golang.org/fake/a/vendor/b", "golang.org/fake/c:golang.org/fake/c"},
376 {"golang.org/fake/c/vendor/b", ""},
378 // Test the import paths.
379 pkg := all[test.pattern]
380 if imports := strings.Join(imports(pkg), " "); imports != test.wantImports {
381 t.Errorf("package %q: got %s, want %s", test.pattern, imports, test.wantImports)
386 func imports(p *packages.Package) []string {
390 keys := make([]string, 0, len(p.Imports))
391 for k, v := range p.Imports {
392 keys = append(keys, fmt.Sprintf("%s:%s", k, v.ID))
398 func TestConfigDir(t *testing.T) { packagestest.TestAll(t, testConfigDir) }
399 func testConfigDir(t *testing.T, exporter packagestest.Exporter) {
400 exported := packagestest.Export(t, exporter, []packagestest.Module{{
401 Name: "golang.org/fake",
402 Files: map[string]interface{}{
403 "a/a.go": `package a; const Name = "a" `,
404 "a/b/b.go": `package b; const Name = "a/b"`,
405 "b/b.go": `package b; const Name = "b"`,
407 defer exported.Cleanup()
408 aDir := filepath.Dir(exported.File("golang.org/fake", "a/a.go"))
409 bDir := filepath.Dir(exported.File("golang.org/fake", "b/b.go"))
410 baseDir := filepath.Dir(aDir)
412 for _, test := range []struct {
415 want string // value of Name constant
418 {dir: bDir, pattern: "golang.org/fake/a", want: `"a"`},
419 {dir: bDir, pattern: "golang.org/fake/b", want: `"b"`},
420 {dir: bDir, pattern: "./a", fails: true},
421 {dir: bDir, pattern: "./b", fails: true},
422 {dir: baseDir, pattern: "golang.org/fake/a", want: `"a"`},
423 {dir: baseDir, pattern: "golang.org/fake/b", want: `"b"`},
424 {dir: baseDir, pattern: "./a", want: `"a"`},
425 {dir: baseDir, pattern: "./b", want: `"b"`},
426 {dir: aDir, pattern: "golang.org/fake/a", want: `"a"`},
427 {dir: aDir, pattern: "golang.org/fake/b", want: `"b"`},
428 {dir: aDir, pattern: "./a", fails: true},
429 {dir: aDir, pattern: "./b", want: `"a/b"`},
431 exported.Config.Mode = packages.LoadSyntax // Use LoadSyntax to ensure that files can be opened.
432 exported.Config.Dir = test.dir
433 initial, err := packages.Load(exported.Config, test.pattern)
438 } else if len(initial) > 0 {
439 if len(initial[0].Errors) > 0 {
441 } else if c := constant(initial[0], "Name"); c != nil {
442 got = c.Val().String()
445 if got != test.want {
446 t.Errorf("dir %q, pattern %q: got %s, want %s",
447 test.dir, test.pattern, got, test.want)
449 if fails != test.fails {
450 // TODO: remove when go#28023 is fixed
451 if test.fails && strings.HasPrefix(test.pattern, "./") && exporter == packagestest.Modules {
452 // Currently go list in module mode does not handle missing directories correctly.
455 t.Errorf("dir %q, pattern %q: error %v, want %v",
456 test.dir, test.pattern, fails, test.fails)
461 func TestConfigFlags(t *testing.T) { packagestest.TestAll(t, testConfigFlags) }
462 func testConfigFlags(t *testing.T, exporter packagestest.Exporter) {
463 // Test satisfying +build line tags, with -tags flag.
464 exported := packagestest.Export(t, exporter, []packagestest.Module{{
465 Name: "golang.org/fake",
466 Files: map[string]interface{}{
468 "a/a.go": `package a; import _ "golang.org/fake/a/b"`,
469 "a/b.go": `// +build tag
472 "a/c.go": `// +build tag tag2
475 "a/d.go": `// +build tag,tag2
479 "a/b/a.go": `package b`,
480 "a/b/b.go": `// +build tag
484 defer exported.Cleanup()
486 for _, test := range []struct {
490 wantImportSrcs string
492 {`golang.org/fake/a`, []string{}, "a.go", "a.go"},
493 {`golang.org/fake/a`, []string{`-tags=tag`}, "a.go b.go c.go", "a.go b.go"},
494 {`golang.org/fake/a`, []string{`-tags=tag2`}, "a.go c.go", "a.go"},
495 {`golang.org/fake/a`, []string{`-tags=tag tag2`}, "a.go b.go c.go d.go", "a.go b.go"},
497 exported.Config.Mode = packages.LoadImports
498 exported.Config.BuildFlags = test.tags
500 initial, err := packages.Load(exported.Config, test.pattern)
505 if len(initial) != 1 {
506 t.Errorf("test tags %v: pattern %s, expected 1 package, got %d packages.", test.tags, test.pattern, len(initial))
510 if srcs := strings.Join(srcs(pkg), " "); srcs != test.wantSrcs {
511 t.Errorf("test tags %v: srcs of package %s = [%s], want [%s]", test.tags, test.pattern, srcs, test.wantSrcs)
513 for path, ipkg := range pkg.Imports {
514 if srcs := strings.Join(srcs(ipkg), " "); srcs != test.wantImportSrcs {
515 t.Errorf("build tags %v: srcs of imported package %s = [%s], want [%s]", test.tags, path, srcs, test.wantImportSrcs)
522 func TestLoadTypes(t *testing.T) { packagestest.TestAll(t, testLoadTypes) }
523 func testLoadTypes(t *testing.T, exporter packagestest.Exporter) {
524 // In LoadTypes and LoadSyntax modes, the compiler will
525 // fail to generate an export data file for c, because it has
526 // a type error. The loader should fall back loading a and c
527 // from source, but use the export data for b.
529 exported := packagestest.Export(t, exporter, []packagestest.Module{{
530 Name: "golang.org/fake",
531 Files: map[string]interface{}{
532 "a/a.go": `package a; import "golang.org/fake/b"; import "golang.org/fake/c"; const A = "a" + b.B + c.C`,
533 "b/b.go": `package b; const B = "b"`,
534 "c/c.go": `package c; const C = "c" + 1`,
536 defer exported.Cleanup()
538 exported.Config.Mode = packages.LoadTypes
539 initial, err := packages.Load(exported.Config, "golang.org/fake/a")
544 graph, all := importGraph(initial)
549 golang.org/fake/a -> golang.org/fake/b
550 golang.org/fake/a -> golang.org/fake/c
552 if graph != wantGraph {
553 t.Errorf("wrong import graph: got <<%s>>, want <<%s>>", graph, wantGraph)
556 for _, id := range []string{
563 t.Errorf("missing package: %s", id)
567 t.Errorf("missing types.Package for %s", p)
569 } else if !p.Types.Complete() {
570 t.Errorf("incomplete types.Package for %s", p)
571 } else if p.TypesSizes == nil {
572 t.Errorf("TypesSizes is not filled in for %s", p)
578 // TestLoadTypesBits is equivalent to TestLoadTypes except that it only requests
579 // the types using the NeedTypes bit.
580 func TestLoadTypesBits(t *testing.T) { packagestest.TestAll(t, testLoadTypesBits) }
581 func testLoadTypesBits(t *testing.T, exporter packagestest.Exporter) {
582 exported := packagestest.Export(t, exporter, []packagestest.Module{{
583 Name: "golang.org/fake",
584 Files: map[string]interface{}{
585 "a/a.go": `package a; import "golang.org/fake/b"; const A = "a" + b.B`,
586 "b/b.go": `package b; import "golang.org/fake/c"; const B = "b" + c.C`,
587 "c/c.go": `package c; import "golang.org/fake/d"; const C = "c" + d.D`,
588 "d/d.go": `package d; import "golang.org/fake/e"; const D = "d" + e.E`,
589 "e/e.go": `package e; import "golang.org/fake/f"; const E = "e" + f.F`,
590 "f/f.go": `package f; const F = "f"`,
592 defer exported.Cleanup()
594 exported.Config.Mode = packages.NeedTypes | packages.NeedImports
595 initial, err := packages.Load(exported.Config, "golang.org/fake/a", "golang.org/fake/c")
600 graph, all := importGraph(initial)
608 golang.org/fake/a -> golang.org/fake/b
609 golang.org/fake/b -> golang.org/fake/c
610 golang.org/fake/c -> golang.org/fake/d
611 golang.org/fake/d -> golang.org/fake/e
612 golang.org/fake/e -> golang.org/fake/f
614 if graph != wantGraph {
615 t.Errorf("wrong import graph: got <<%s>>, want <<%s>>", graph, wantGraph)
618 for _, test := range []struct {
621 {"golang.org/fake/a"},
622 {"golang.org/fake/b"},
623 {"golang.org/fake/c"},
624 {"golang.org/fake/d"},
625 {"golang.org/fake/e"},
626 {"golang.org/fake/f"},
630 t.Errorf("missing package: %s", test.id)
634 t.Errorf("missing types.Package for %s", p)
637 // We don't request the syntax, so we shouldn't get it.
639 t.Errorf("Syntax unexpectedly provided for %s", p)
642 t.Errorf("errors in package: %s: %s", p, p.Errors)
646 // Check value of constant.
647 aA := constant(all["golang.org/fake/a"], "A")
649 t.Fatalf("a.A: got nil")
651 if got, want := fmt.Sprintf("%v %v", aA, aA.Val()), `const golang.org/fake/a.A untyped string "abcdef"`; got != want {
652 t.Errorf("a.A: got %s, want %s", got, want)
656 func TestLoadSyntaxOK(t *testing.T) { packagestest.TestAll(t, testLoadSyntaxOK) }
657 func testLoadSyntaxOK(t *testing.T, exporter packagestest.Exporter) {
658 exported := packagestest.Export(t, exporter, []packagestest.Module{{
659 Name: "golang.org/fake",
660 Files: map[string]interface{}{
661 "a/a.go": `package a; import "golang.org/fake/b"; const A = "a" + b.B`,
662 "b/b.go": `package b; import "golang.org/fake/c"; const B = "b" + c.C`,
663 "c/c.go": `package c; import "golang.org/fake/d"; const C = "c" + d.D`,
664 "d/d.go": `package d; import "golang.org/fake/e"; const D = "d" + e.E`,
665 "e/e.go": `package e; import "golang.org/fake/f"; const E = "e" + f.F`,
666 "f/f.go": `package f; const F = "f"`,
668 defer exported.Cleanup()
670 exported.Config.Mode = packages.LoadSyntax
671 initial, err := packages.Load(exported.Config, "golang.org/fake/a", "golang.org/fake/c")
676 graph, all := importGraph(initial)
684 golang.org/fake/a -> golang.org/fake/b
685 golang.org/fake/b -> golang.org/fake/c
686 golang.org/fake/c -> golang.org/fake/d
687 golang.org/fake/d -> golang.org/fake/e
688 golang.org/fake/e -> golang.org/fake/f
690 if graph != wantGraph {
691 t.Errorf("wrong import graph: got <<%s>>, want <<%s>>", graph, wantGraph)
694 for _, test := range []struct {
699 {"golang.org/fake/a", true, true}, // source package
700 {"golang.org/fake/b", true, true}, // source package because depends on initial package
701 {"golang.org/fake/c", true, true}, // source package
702 {"golang.org/fake/d", false, true}, // export data package
703 {"golang.org/fake/e", false, false}, // export data package
704 {"golang.org/fake/f", false, false}, // export data package
706 // TODO(matloob): LoadSyntax and LoadAllSyntax are now equivalent, wantSyntax and wantComplete
707 // are true for all packages in the transitive dependency set. Add test cases on the individual
708 // Need* fields to check the equivalents on the new API.
711 t.Errorf("missing package: %s", test.id)
715 t.Errorf("missing types.Package for %s", p)
717 } else if p.Types.Complete() != test.wantComplete {
718 if test.wantComplete {
719 t.Errorf("incomplete types.Package for %s", p)
721 t.Errorf("unexpected complete types.Package for %s", p)
724 if (p.Syntax != nil) != test.wantSyntax {
726 t.Errorf("missing ast.Files for %s", p)
728 t.Errorf("unexpected ast.Files for for %s", p)
732 t.Errorf("errors in package: %s: %s", p, p.Errors)
736 // Check value of constant.
737 aA := constant(all["golang.org/fake/a"], "A")
739 t.Fatalf("a.A: got nil")
741 if got, want := fmt.Sprintf("%v %v", aA, aA.Val()), `const golang.org/fake/a.A untyped string "abcdef"`; got != want {
742 t.Errorf("a.A: got %s, want %s", got, want)
746 func TestLoadDiamondTypes(t *testing.T) { packagestest.TestAll(t, testLoadDiamondTypes) }
747 func testLoadDiamondTypes(t *testing.T, exporter packagestest.Exporter) {
748 // We make a diamond dependency and check the type d.D is the same through both paths
749 exported := packagestest.Export(t, exporter, []packagestest.Module{{
750 Name: "golang.org/fake",
751 Files: map[string]interface{}{
752 "a/a.go": `package a; import ("golang.org/fake/b"; "golang.org/fake/c"); var _ = b.B == c.C`,
753 "b/b.go": `package b; import "golang.org/fake/d"; var B d.D`,
754 "c/c.go": `package c; import "golang.org/fake/d"; var C d.D`,
755 "d/d.go": `package d; type D int`,
757 defer exported.Cleanup()
759 exported.Config.Mode = packages.LoadSyntax
760 initial, err := packages.Load(exported.Config, "golang.org/fake/a")
764 packages.Visit(initial, nil, func(pkg *packages.Package) {
765 for _, err := range pkg.Errors {
766 t.Errorf("package %s: %v", pkg.ID, err)
770 graph, _ := importGraph(initial)
776 golang.org/fake/a -> golang.org/fake/b
777 golang.org/fake/a -> golang.org/fake/c
778 golang.org/fake/b -> golang.org/fake/d
779 golang.org/fake/c -> golang.org/fake/d
781 if graph != wantGraph {
782 t.Errorf("wrong import graph: got <<%s>>, want <<%s>>", graph, wantGraph)
786 func TestLoadSyntaxError(t *testing.T) { packagestest.TestAll(t, testLoadSyntaxError) }
787 func testLoadSyntaxError(t *testing.T, exporter packagestest.Exporter) {
788 // A type error in a lower-level package (e) prevents go list
789 // from producing export data for all packages that depend on it
790 // [a-e]. Only f should be loaded from export data, and the rest
791 // should be IllTyped.
792 exported := packagestest.Export(t, exporter, []packagestest.Module{{
793 Name: "golang.org/fake",
794 Files: map[string]interface{}{
795 "a/a.go": `package a; import "golang.org/fake/b"; const A = "a" + b.B`,
796 "b/b.go": `package b; import "golang.org/fake/c"; const B = "b" + c.C`,
797 "c/c.go": `package c; import "golang.org/fake/d"; const C = "c" + d.D`,
798 "d/d.go": `package d; import "golang.org/fake/e"; const D = "d" + e.E`,
799 "e/e.go": `package e; import "golang.org/fake/f"; const E = "e" + f.F + 1`, // type error
800 "f/f.go": `package f; const F = "f"`,
802 defer exported.Cleanup()
804 exported.Config.Mode = packages.LoadSyntax
805 initial, err := packages.Load(exported.Config, "golang.org/fake/a", "golang.org/fake/c")
810 all := make(map[string]*packages.Package)
811 packages.Visit(initial, nil, func(p *packages.Package) {
815 for _, test := range []struct {
820 {"golang.org/fake/a", true, true},
821 {"golang.org/fake/b", true, true},
822 {"golang.org/fake/c", true, true},
823 {"golang.org/fake/d", true, true},
824 {"golang.org/fake/e", true, true},
825 {"golang.org/fake/f", false, false},
829 t.Errorf("missing package: %s", test.id)
833 t.Errorf("missing types.Package for %s", p)
835 } else if !p.Types.Complete() {
836 t.Errorf("incomplete types.Package for %s", p)
838 if (p.Syntax != nil) != test.wantSyntax {
840 t.Errorf("missing ast.Files for %s", test.id)
842 t.Errorf("unexpected ast.Files for for %s", test.id)
845 if p.IllTyped != test.wantIllTyped {
846 t.Errorf("IllTyped was %t for %s", p.IllTyped, test.id)
850 // Check value of constant.
851 aA := constant(all["golang.org/fake/a"], "A")
853 t.Fatalf("a.A: got nil")
855 if got, want := aA.String(), `const golang.org/fake/a.A invalid type`; got != want {
856 t.Errorf("a.A: got %s, want %s", got, want)
860 // This function tests use of the ParseFile hook to modify
861 // the AST after parsing.
862 func TestParseFileModifyAST(t *testing.T) { packagestest.TestAll(t, testParseFileModifyAST) }
863 func testParseFileModifyAST(t *testing.T, exporter packagestest.Exporter) {
864 exported := packagestest.Export(t, exporter, []packagestest.Module{{
865 Name: "golang.org/fake",
866 Files: map[string]interface{}{
867 "a/a.go": `package a; const A = "a" `,
869 defer exported.Cleanup()
871 exported.Config.Mode = packages.LoadAllSyntax
872 exported.Config.ParseFile = func(fset *token.FileSet, filename string, src []byte) (*ast.File, error) {
873 const mode = parser.AllErrors | parser.ParseComments
874 f, err := parser.ParseFile(fset, filename, src, mode)
875 // modify AST to change `const A = "a"` to `const A = "b"`
876 spec := f.Decls[0].(*ast.GenDecl).Specs[0].(*ast.ValueSpec)
877 spec.Values[0].(*ast.BasicLit).Value = `"b"`
880 initial, err := packages.Load(exported.Config, "golang.org/fake/a")
885 // Check value of a.A has been set to "b"
887 got := constant(a, "A").Val().String()
889 t.Errorf("a.A: got %s, want %s", got, `"b"`)
893 func TestAdHocPackagesBadImport(t *testing.T) {
894 // This test doesn't use packagestest because we are testing ad-hoc packages,
895 // which are outside of $GOPATH and outside of a module.
896 tmp, err := ioutil.TempDir("", "a")
900 defer os.RemoveAll(tmp)
902 filename := filepath.Join(tmp, "a.go")
903 content := []byte(`package a
907 if err := ioutil.WriteFile(filename, content, 0775); err != nil {
911 // Make sure that the user's value of GO111MODULE does not affect test results.
912 for _, go111module := range []string{"off", "auto", "on"} {
913 config := &packages.Config{
914 Env: append(os.Environ(), "GOPACKAGESDRIVER=off", fmt.Sprintf("GO111MODULE=%s", go111module)),
916 Mode: packages.LoadAllSyntax,
919 initial, err := packages.Load(config, fmt.Sprintf("file=%s", filename))
923 if len(initial) == 0 {
924 t.Fatalf("no packages for %s with GO111MODULE=%s", filename, go111module)
926 // Check value of a.A.
928 // There's an error because there's a bad import.
929 aA := constant(a, "A")
931 t.Errorf("a.A: got nil")
934 got := aA.Val().String()
935 if want := "1"; got != want {
936 t.Errorf("a.A: got %s, want %s", got, want)
941 func TestLoadAllSyntaxImportErrors(t *testing.T) {
942 packagestest.TestAll(t, testLoadAllSyntaxImportErrors)
944 func testLoadAllSyntaxImportErrors(t *testing.T, exporter packagestest.Exporter) {
945 // TODO(matloob): Remove this once go list -e -compiled is fixed.
946 // See https://golang.org/issue/26755
947 t.Skip("go list -compiled -e fails with non-zero exit status for empty packages")
949 exported := packagestest.Export(t, exporter, []packagestest.Module{{
950 Name: "golang.org/fake",
951 Files: map[string]interface{}{
952 "unicycle/unicycle.go": `package unicycle; import _ "unicycle"`,
953 "bicycle1/bicycle1.go": `package bicycle1; import _ "bicycle2"`,
954 "bicycle2/bicycle2.go": `package bicycle2; import _ "bicycle1"`,
955 "bad/bad.go": `not a package declaration`,
956 "empty/README.txt": `not a go file`,
957 "root/root.go": `package root
966 defer exported.Cleanup()
968 exported.Config.Mode = packages.LoadAllSyntax
969 initial, err := packages.Load(exported.Config, "root")
974 // Cycle-forming edges are removed from the graph:
975 // bicycle2 -> bicycle1
976 // unicycle -> unicycle
977 graph, all := importGraph(initial)
987 if graph != wantGraph {
988 t.Errorf("wrong import graph: got <<%s>>, want <<%s>>", graph, wantGraph)
990 for _, test := range []struct {
995 {"bicycle2", []string{
996 "could not import bicycle1 (import cycle: [root bicycle1 bicycle2])",
998 {"unicycle", []string{
999 "could not import unicycle (import cycle: [root unicycle])",
1002 `could not import bad (missing package: "bad")`,
1003 `could not import empty (missing package: "empty")`,
1004 `could not import nonesuch (missing package: "nonesuch")`,
1009 t.Errorf("missing package: %s", test.id)
1013 t.Errorf("missing types.Package for %s", test.id)
1015 if p.Syntax == nil {
1016 t.Errorf("missing ast.Files for %s", test.id)
1019 t.Errorf("IllTyped was false for %s", test.id)
1021 if errs := errorMessages(p.Errors); !reflect.DeepEqual(errs, test.wantErrs) {
1022 t.Errorf("in package %s, got errors %s, want %s", p, errs, test.wantErrs)
1027 func TestAbsoluteFilenames(t *testing.T) { packagestest.TestAll(t, testAbsoluteFilenames) }
1028 func testAbsoluteFilenames(t *testing.T, exporter packagestest.Exporter) {
1029 exported := packagestest.Export(t, exporter, []packagestest.Module{{
1030 Name: "golang.org/fake",
1031 Files: map[string]interface{}{
1032 "a/a.go": `package a; const A = 1`,
1033 "b/b.go": `package b; import ("golang.org/fake/a"; _ "errors"); var B = a.A`,
1034 "b/vendor/a/a.go": `package a; const A = 1`,
1035 "c/c.go": `package c; import (_ "golang.org/fake/b"; _ "unsafe")`,
1036 "c/c2.go": "// +build ignore\n\n" + `package c; import _ "fmt"`,
1037 "subdir/d/d.go": `package d`,
1038 "subdir/e/d.go": `package e`,
1039 "e/e.go": `package main; import _ "golang.org/fake/b"`,
1040 "e/e2.go": `package main; import _ "golang.org/fake/c"`,
1041 "f/f.go": `package f`,
1044 defer exported.Cleanup()
1045 exported.Config.Dir = filepath.Dir(filepath.Dir(exported.File("golang.org/fake", "a/a.go")))
1047 checkFile := func(filename string) {
1048 if !filepath.IsAbs(filename) {
1049 t.Errorf("filename is not absolute: %s", filename)
1051 if _, err := os.Stat(filename); err != nil {
1052 t.Errorf("stat error, %s: %v", filename, err)
1056 for _, test := range []struct {
1061 {"golang.org/fake/a", "a.go"},
1062 {"golang.org/fake/b/vendor/a", "a.go"},
1063 {"golang.org/fake/b", "b.go"},
1064 {"golang.org/fake/c", "c.go"},
1065 {"golang.org/fake/subdir/d", "d.go"},
1066 {"golang.org/fake/subdir/e", "d.go"},
1067 {"golang.org/fake/e", "e.go e2.go"},
1068 {"golang.org/fake/f", "f.go f.s"},
1071 {"./b/vendor/a", "a.go"},
1074 {"./subdir/d", "d.go"},
1075 {"./subdir/e", "d.go"},
1076 {"./e", "e.go e2.go"},
1077 {"./f", "f.go f.s"},
1079 exported.Config.Mode = packages.LoadFiles
1080 pkgs, err := packages.Load(exported.Config, test.pattern)
1082 t.Errorf("pattern %s: %v", test.pattern, err)
1086 if got := strings.Join(srcs(pkgs[0]), " "); got != test.want {
1087 t.Errorf("in package %s, got %s, want %s", test.pattern, got, test.want)
1090 // Test that files in all packages exist and are absolute paths.
1091 _, all := importGraph(pkgs)
1092 for _, pkg := range all {
1093 for _, filename := range pkg.GoFiles {
1096 for _, filename := range pkg.OtherFiles {
1099 for _, filename := range pkg.IgnoredFiles {
1106 func TestContains(t *testing.T) { packagestest.TestAll(t, testContains) }
1107 func testContains(t *testing.T, exporter packagestest.Exporter) {
1108 exported := packagestest.Export(t, exporter, []packagestest.Module{{
1109 Name: "golang.org/fake",
1110 Files: map[string]interface{}{
1111 "a/a.go": `package a; import "golang.org/fake/b"`,
1112 "b/b.go": `package b; import "golang.org/fake/c"`,
1113 "c/c.go": `package c`,
1115 defer exported.Cleanup()
1116 bFile := exported.File("golang.org/fake", "b/b.go")
1117 exported.Config.Mode = packages.LoadImports
1118 initial, err := packages.Load(exported.Config, "file="+bFile)
1123 graph, _ := importGraph(initial)
1127 golang.org/fake/b -> golang.org/fake/c
1129 if graph != wantGraph {
1130 t.Errorf("wrong import graph: got <<%s>>, want <<%s>>", graph, wantGraph)
1134 // This test ensures that the effective GOARCH variable in the
1135 // application determines the Sizes function used by the type checker.
1136 // This behavior is a stop-gap until we make the build system's query
1137 // tool report the correct sizes function for the actual configuration.
1138 func TestSizes(t *testing.T) { packagestest.TestAll(t, testSizes) }
1139 func testSizes(t *testing.T, exporter packagestest.Exporter) {
1140 // Only run this test on operating systems that have both an amd64 and 386 port.
1141 switch runtime.GOOS {
1142 case "linux", "windows", "freebsd", "openbsd", "netbsd", "android":
1144 t.Skipf("skipping test on %s", runtime.GOOS)
1147 exported := packagestest.Export(t, exporter, []packagestest.Module{{
1148 Name: "golang.org/fake",
1149 Files: map[string]interface{}{
1150 "a/a.go": `package a; import "unsafe"; const WordSize = 8*unsafe.Sizeof(int(0))`,
1152 defer exported.Cleanup()
1154 exported.Config.Mode = packages.LoadSyntax
1155 savedEnv := exported.Config.Env
1156 for arch, wantWordSize := range map[string]int64{"386": 32, "amd64": 64} {
1157 exported.Config.Env = append(savedEnv, "GOARCH="+arch)
1158 initial, err := packages.Load(exported.Config, "golang.org/fake/a")
1162 if packages.PrintErrors(initial) > 0 {
1163 t.Fatal("there were errors")
1165 gotWordSize, _ := constantpkg.Int64Val(constant(initial[0], "WordSize").Val())
1166 if gotWordSize != wantWordSize {
1167 t.Errorf("for GOARCH=%s, got word size %d, want %d", arch, gotWordSize, wantWordSize)
1172 // TestContainsFallbackSticks ensures that when there are both contains and non-contains queries
1173 // the decision whether to fallback to the pre-1.11 go list sticks across both sets of calls to
1175 func TestContainsFallbackSticks(t *testing.T) { packagestest.TestAll(t, testContainsFallbackSticks) }
1176 func testContainsFallbackSticks(t *testing.T, exporter packagestest.Exporter) {
1177 exported := packagestest.Export(t, exporter, []packagestest.Module{{
1178 Name: "golang.org/fake",
1179 Files: map[string]interface{}{
1180 "a/a.go": `package a; import "golang.org/fake/b"`,
1181 "b/b.go": `package b; import "golang.org/fake/c"`,
1182 "c/c.go": `package c`,
1184 defer exported.Cleanup()
1186 exported.Config.Mode = packages.LoadImports
1187 bFile := exported.File("golang.org/fake", "b/b.go")
1188 initial, err := packages.Load(exported.Config, "golang.org/fake/a", "file="+bFile)
1193 graph, _ := importGraph(initial)
1198 golang.org/fake/a -> golang.org/fake/b
1199 golang.org/fake/b -> golang.org/fake/c
1201 if graph != wantGraph {
1202 t.Errorf("wrong import graph: got <<%s>>, want <<%s>>", graph, wantGraph)
1206 // Test that Load with no patterns is equivalent to loading "." via the golist
1208 func TestNoPatterns(t *testing.T) { packagestest.TestAll(t, testNoPatterns) }
1209 func testNoPatterns(t *testing.T, exporter packagestest.Exporter) {
1210 exported := packagestest.Export(t, exporter, []packagestest.Module{{
1211 Name: "golang.org/fake",
1212 Files: map[string]interface{}{
1213 "a/a.go": `package a;`,
1214 "a/b/b.go": `package b;`,
1216 defer exported.Cleanup()
1218 aDir := filepath.Dir(exported.File("golang.org/fake", "a/a.go"))
1219 exported.Config.Dir = aDir
1221 initial, err := packages.Load(exported.Config)
1225 if len(initial) != 1 || initial[0].Name != "a" {
1226 t.Fatalf(`Load() = %v, wanted just the package in the current directory`, initial)
1230 func TestJSON(t *testing.T) { packagestest.TestAll(t, testJSON) }
1231 func testJSON(t *testing.T, exporter packagestest.Exporter) {
1232 //TODO: add in some errors
1233 exported := packagestest.Export(t, exporter, []packagestest.Module{{
1234 Name: "golang.org/fake",
1235 Files: map[string]interface{}{
1236 "a/a.go": `package a; const A = 1`,
1237 "b/b.go": `package b; import "golang.org/fake/a"; var B = a.A`,
1238 "c/c.go": `package c; import "golang.org/fake/b" ; var C = b.B`,
1239 "d/d.go": `package d; import "golang.org/fake/b" ; var D = b.B`,
1241 defer exported.Cleanup()
1243 exported.Config.Mode = packages.LoadImports
1244 initial, err := packages.Load(exported.Config, "golang.org/fake/c", "golang.org/fake/d")
1249 // Visit and print all packages.
1250 buf := &bytes.Buffer{}
1251 enc := json.NewEncoder(buf)
1252 enc.SetIndent("", "\t")
1253 packages.Visit(initial, nil, func(pkg *packages.Package) {
1254 // trim the source lists for stable results
1255 pkg.GoFiles = cleanPaths(pkg.GoFiles)
1256 pkg.CompiledGoFiles = cleanPaths(pkg.CompiledGoFiles)
1257 pkg.OtherFiles = cleanPaths(pkg.OtherFiles)
1258 pkg.IgnoredFiles = cleanPaths(pkg.IgnoredFiles)
1259 if err := enc.Encode(pkg); err != nil {
1266 "ID": "golang.org/fake/a",
1268 "PkgPath": "golang.org/fake/a",
1272 "CompiledGoFiles": [
1277 "ID": "golang.org/fake/b",
1279 "PkgPath": "golang.org/fake/b",
1283 "CompiledGoFiles": [
1287 "golang.org/fake/a": "golang.org/fake/a"
1291 "ID": "golang.org/fake/c",
1293 "PkgPath": "golang.org/fake/c",
1297 "CompiledGoFiles": [
1301 "golang.org/fake/b": "golang.org/fake/b"
1305 "ID": "golang.org/fake/d",
1307 "PkgPath": "golang.org/fake/d",
1311 "CompiledGoFiles": [
1315 "golang.org/fake/b": "golang.org/fake/b"
1320 if buf.String() != wantJSON {
1321 t.Errorf("wrong JSON: got <<%s>>, want <<%s>>", buf.String(), wantJSON)
1323 // now decode it again
1324 var decoded []*packages.Package
1325 dec := json.NewDecoder(buf)
1327 p := new(packages.Package)
1328 if err := dec.Decode(p); err != nil {
1331 decoded = append(decoded, p)
1333 if len(decoded) != 4 {
1334 t.Fatalf("got %d packages, want 4", len(decoded))
1336 for i, want := range []*packages.Package{{
1337 ID: "golang.org/fake/a",
1340 ID: "golang.org/fake/b",
1342 Imports: map[string]*packages.Package{
1343 "golang.org/fake/a": {ID: "golang.org/fake/a"},
1346 ID: "golang.org/fake/c",
1348 Imports: map[string]*packages.Package{
1349 "golang.org/fake/b": {ID: "golang.org/fake/b"},
1352 ID: "golang.org/fake/d",
1354 Imports: map[string]*packages.Package{
1355 "golang.org/fake/b": {ID: "golang.org/fake/b"},
1359 if got.ID != want.ID {
1360 t.Errorf("Package %d has ID %q want %q", i, got.ID, want.ID)
1362 if got.Name != want.Name {
1363 t.Errorf("Package %q has Name %q want %q", got.ID, got.Name, want.Name)
1365 if len(got.Imports) != len(want.Imports) {
1366 t.Errorf("Package %q has %d imports want %d", got.ID, len(got.Imports), len(want.Imports))
1369 for path, ipkg := range got.Imports {
1370 if want.Imports[path] == nil {
1371 t.Errorf("Package %q has unexpected import %q", got.ID, path)
1374 if want.Imports[path].ID != ipkg.ID {
1375 t.Errorf("Package %q import %q is %q want %q", got.ID, path, ipkg.ID, want.Imports[path].ID)
1381 func TestRejectInvalidQueries(t *testing.T) {
1382 queries := []string{"key=", "key=value"}
1383 cfg := &packages.Config{
1384 Mode: packages.LoadImports,
1385 Env: append(os.Environ(), "GO111MODULE=off", "GOPACKAGESDRIVER=off"),
1387 for _, q := range queries {
1388 if _, err := packages.Load(cfg, q); err == nil {
1389 t.Errorf("packages.Load(%q) succeeded. Expected \"invalid query type\" error", q)
1390 } else if !strings.Contains(err.Error(), "invalid query type") {
1391 t.Errorf("packages.Load(%q): got error %v, want \"invalid query type\" error", q, err)
1396 func TestPatternPassthrough(t *testing.T) { packagestest.TestAll(t, testPatternPassthrough) }
1397 func testPatternPassthrough(t *testing.T, exporter packagestest.Exporter) {
1398 exported := packagestest.Export(t, exporter, []packagestest.Module{{
1399 Name: "golang.org/fake",
1400 Files: map[string]interface{}{
1401 "a/a.go": `package a;`,
1403 defer exported.Cleanup()
1405 initial, err := packages.Load(exported.Config, "pattern=a")
1410 graph, _ := importGraph(initial)
1414 if graph != wantGraph {
1415 t.Errorf("wrong import graph: got <<%s>>, want <<%s>>", graph, wantGraph)
1420 func TestConfigDefaultEnv(t *testing.T) { packagestest.TestAll(t, testConfigDefaultEnv) }
1421 func testConfigDefaultEnv(t *testing.T, exporter packagestest.Exporter) {
1422 const driverJSON = `{
1423 "Roots": ["gopackagesdriver"],
1424 "Packages": [{"ID": "gopackagesdriver", "Name": "gopackagesdriver"}]
1428 driverScript packagestest.Writer
1430 switch runtime.GOOS {
1432 t.Skip("doesn't run on android")
1434 // TODO(jayconrod): write an equivalent batch script for windows.
1435 // Hint: "type" can be used to read a file to stdout.
1436 t.Skip("test requires sh")
1439 driverScript = packagestest.Script(`#!/bin/rc
1447 driverScript = packagestest.Script(`#!/bin/sh
1454 exported := packagestest.Export(t, exporter, []packagestest.Module{{
1455 Name: "golang.org/fake",
1456 Files: map[string]interface{}{
1457 "bin/gopackagesdriver": driverScript,
1458 "golist/golist.go": "package golist",
1460 defer exported.Cleanup()
1461 driver := exported.File("golang.org/fake", "bin/gopackagesdriver")
1462 binDir := filepath.Dir(driver)
1463 if err := os.Chmod(driver, 0755); err != nil {
1467 path, ok := os.LookupEnv(pathKey)
1468 var pathWithDriver string
1470 pathWithDriver = binDir + string(os.PathListSeparator) + path
1472 pathWithDriver = binDir
1474 for _, test := range []struct {
1482 path: pathWithDriver,
1484 wantIDs: "[golist]",
1486 desc: "driver_unset",
1487 path: pathWithDriver,
1489 wantIDs: "[gopackagesdriver]",
1494 wantIDs: "[gopackagesdriver]",
1497 t.Run(test.desc, func(t *testing.T) {
1498 oldPath := os.Getenv(pathKey)
1499 os.Setenv(pathKey, test.path)
1500 defer os.Setenv(pathKey, oldPath)
1501 // Clone exported.Config
1502 config := exported.Config
1503 config.Env = append([]string{}, exported.Config.Env...)
1504 config.Env = append(config.Env, "GOPACKAGESDRIVER="+test.driver)
1505 pkgs, err := packages.Load(exported.Config, "golist")
1510 gotIds := make([]string, len(pkgs))
1511 for i, pkg := range pkgs {
1514 if fmt.Sprint(pkgs) != test.wantIDs {
1515 t.Errorf("got %v; want %v", gotIds, test.wantIDs)
1521 // This test that a simple x test package layout loads correctly.
1522 // There was a bug in go list where it returned multiple copies of the same
1523 // package (specifically in this case of golang.org/fake/a), and this triggered
1524 // a bug in go/packages where it would leave an empty entry in the root package
1525 // list. This would then cause a nil pointer crash.
1526 // This bug was triggered by the simple package layout below, and thus this
1527 // test will make sure the bug remains fixed.
1528 func TestBasicXTest(t *testing.T) { packagestest.TestAll(t, testBasicXTest) }
1529 func testBasicXTest(t *testing.T, exporter packagestest.Exporter) {
1530 exported := packagestest.Export(t, exporter, []packagestest.Module{{
1531 Name: "golang.org/fake",
1532 Files: map[string]interface{}{
1533 "a/a.go": `package a;`,
1534 "a/a_test.go": `package a_test;`,
1536 defer exported.Cleanup()
1538 exported.Config.Mode = packages.LoadFiles
1539 exported.Config.Tests = true
1540 _, err := packages.Load(exported.Config, "golang.org/fake/a")
1546 func TestErrorMissingFile(t *testing.T) { packagestest.TestAll(t, testErrorMissingFile) }
1547 func testErrorMissingFile(t *testing.T, exporter packagestest.Exporter) {
1548 exported := packagestest.Export(t, exporter, []packagestest.Module{{
1549 Name: "golang.org/fake",
1550 Files: map[string]interface{}{
1551 "a/a_test.go": `package a;`,
1553 defer exported.Cleanup()
1555 exported.Config.Mode = packages.LoadSyntax
1556 exported.Config.Tests = false
1557 pkgs, err := packages.Load(exported.Config, "missing.go")
1561 if len(pkgs) == 0 && runtime.GOOS == "windows" {
1562 t.Skip("Issue #31344: the ad-hoc command-line-arguments package isn't created on windows")
1564 if len(pkgs) != 1 || (pkgs[0].PkgPath != "command-line-arguments" && pkgs[0].PkgPath != "missing.go") {
1565 t.Fatalf("packages.Load: want [command-line-arguments] or [missing.go], got %v", pkgs)
1567 if len(pkgs[0].Errors) == 0 {
1568 t.Errorf("result of Load: want package with errors, got none: %+v", pkgs[0])
1572 func TestReturnErrorWhenUsingNonGoFiles(t *testing.T) {
1573 packagestest.TestAll(t, testReturnErrorWhenUsingNonGoFiles)
1575 func testReturnErrorWhenUsingNonGoFiles(t *testing.T, exporter packagestest.Exporter) {
1576 exported := packagestest.Export(t, exporter, []packagestest.Module{{
1577 Name: "golang.org/gopatha",
1578 Files: map[string]interface{}{
1579 "a/a.go": `package a`,
1581 Name: "golang.org/gopathb",
1582 Files: map[string]interface{}{
1583 "b/b.c": `package b`,
1585 defer exported.Cleanup()
1586 config := packages.Config{Env: append(os.Environ(), "GOPACKAGESDRIVER=off")}
1587 pkgs, err := packages.Load(&config, "b/b.c")
1591 // Go <1.14 calls the package command-line-arguments while Go 1.14+ uses the file names.
1592 if len(pkgs) != 1 || (pkgs[0].PkgPath != "command-line-arguments" && pkgs[0].PkgPath != "b/b.c") {
1593 t.Fatalf("packages.Load: want [command-line-arguments] or [b/b.c], got %v", pkgs)
1595 if len(pkgs[0].Errors) != 1 {
1596 t.Fatalf("result of Load: want package with one error, got: %+v", pkgs[0])
1600 func TestReturnErrorWhenUsingGoFilesInMultipleDirectories(t *testing.T) {
1601 packagestest.TestAll(t, testReturnErrorWhenUsingGoFilesInMultipleDirectories)
1603 func testReturnErrorWhenUsingGoFilesInMultipleDirectories(t *testing.T, exporter packagestest.Exporter) {
1604 exported := packagestest.Export(t, exporter, []packagestest.Module{{
1605 Name: "golang.org/gopatha",
1606 Files: map[string]interface{}{
1607 "a/a.go": `package a`,
1608 "b/b.go": `package b`,
1610 defer exported.Cleanup()
1611 want := "named files must all be in one directory"
1612 pkgs, err := packages.Load(exported.Config, exported.File("golang.org/gopatha", "a/a.go"), exported.File("golang.org/gopatha", "b/b.go"))
1614 // Check if the error returned is the one we expected.
1615 if !strings.Contains(err.Error(), want) {
1616 t.Fatalf("want error message: %s, got: %s", want, err.Error())
1620 if len(pkgs) != 1 || pkgs[0].PkgPath != "command-line-arguments" {
1621 t.Fatalf("packages.Load: want [command-line-arguments], got %v", pkgs)
1623 if len(pkgs[0].Errors) != 1 {
1624 t.Fatalf("result of Load: want package with one error, got: %+v", pkgs[0])
1626 got := pkgs[0].Errors[0].Error()
1627 if !strings.Contains(got, want) {
1628 t.Fatalf("want error message: %s, got: %s", want, got)
1632 func TestReturnErrorForUnexpectedDirectoryLayout(t *testing.T) {
1633 packagestest.TestAll(t, testReturnErrorForUnexpectedDirectoryLayout)
1635 func testReturnErrorForUnexpectedDirectoryLayout(t *testing.T, exporter packagestest.Exporter) {
1636 exported := packagestest.Export(t, exporter, []packagestest.Module{{
1637 Name: "golang.org/gopatha",
1638 Files: map[string]interface{}{
1639 "a/testdata/a.go": `package a; import _ "b"`,
1640 "a/vendor/b/b.go": `package b; import _ "fmt"`,
1642 defer exported.Cleanup()
1643 want := "unexpected directory layout"
1644 // triggering this error requires a relative package path
1645 exported.Config.Dir = filepath.Dir(exported.File("golang.org/gopatha", "a/testdata/a.go"))
1646 pkgs, err := packages.Load(exported.Config, ".")
1648 // This error doesn't seem to occur in module mode; so only
1649 // complain if we get zero packages while also getting no error.
1652 // TODO(dh): we'll need to expand on the error check if/when Go stops emitting this error
1653 t.Fatalf("want error, got nil")
1657 // Check if the error returned is the one we expected.
1658 if !strings.Contains(err.Error(), want) {
1659 t.Fatalf("want error message: %s, got: %s", want, err.Error())
1663 func TestMissingDependency(t *testing.T) { packagestest.TestAll(t, testMissingDependency) }
1664 func testMissingDependency(t *testing.T, exporter packagestest.Exporter) {
1665 exported := packagestest.Export(t, exporter, []packagestest.Module{{
1666 Name: "golang.org/fake",
1667 Files: map[string]interface{}{
1668 "a/a.go": `package a; import _ "this/package/doesnt/exist"`,
1670 defer exported.Cleanup()
1672 exported.Config.Mode = packages.LoadAllSyntax
1673 pkgs, err := packages.Load(exported.Config, "golang.org/fake/a")
1677 if len(pkgs) != 1 && pkgs[0].PkgPath != "golang.org/fake/a" {
1678 t.Fatalf("packages.Load: want [golang.org/fake/a], got %v", pkgs)
1680 if len(pkgs[0].Errors) == 0 {
1681 t.Errorf("result of Load: want package with errors, got none: %+v", pkgs[0])
1685 func TestAdHocContains(t *testing.T) { packagestest.TestAll(t, testAdHocContains) }
1686 func testAdHocContains(t *testing.T, exporter packagestest.Exporter) {
1687 exported := packagestest.Export(t, exporter, []packagestest.Module{{
1688 Name: "golang.org/fake",
1689 Files: map[string]interface{}{
1690 "a/a.go": `package a;`,
1692 defer exported.Cleanup()
1694 tmpfile, err := ioutil.TempFile("", "adhoc*.go")
1695 filename := tmpfile.Name()
1699 fmt.Fprint(tmpfile, `package main; import "fmt"; func main() { fmt.Println("time for coffee") }`)
1700 if err := tmpfile.Close(); err != nil {
1705 if err := os.Remove(filename); err != nil {
1710 exported.Config.Mode = packages.NeedImports | packages.NeedFiles
1711 pkgs, err := packages.Load(exported.Config, "file="+filename)
1715 if len(pkgs) != 1 && pkgs[0].PkgPath != "command-line-arguments" {
1716 t.Fatalf("packages.Load: want [command-line-arguments], got %v", pkgs)
1719 if _, ok := pkg.Imports["fmt"]; !ok || len(pkg.Imports) != 1 {
1720 t.Fatalf("Imports of loaded package: want [fmt], got %v", pkg.Imports)
1722 if len(pkg.GoFiles) != 1 || pkg.GoFiles[0] != filename {
1723 t.Fatalf("GoFiles of loaded package: want [%s], got %v", filename, pkg.GoFiles)
1727 func TestCgoNoCcompiler(t *testing.T) { packagestest.TestAll(t, testCgoNoCcompiler) }
1728 func testCgoNoCcompiler(t *testing.T, exporter packagestest.Exporter) {
1729 testenv.NeedsTool(t, "cgo")
1730 exported := packagestest.Export(t, exporter, []packagestest.Module{{
1731 Name: "golang.org/fake",
1732 Files: map[string]interface{}{
1733 "a/a.go": `package a
1735 const A = http.MethodGet
1738 defer exported.Cleanup()
1740 // Explicitly enable cgo but configure a nonexistent C compiler.
1741 exported.Config.Env = append(exported.Config.Env, "CGO_ENABLED=1", "CC=doesnotexist")
1742 exported.Config.Mode = packages.LoadAllSyntax
1743 initial, err := packages.Load(exported.Config, "golang.org/fake/a")
1749 // Check value of a.A.
1751 aA := constant(a, "A")
1753 t.Fatalf("a.A: got nil")
1755 got := aA.Val().String()
1756 if got != "\"GET\"" {
1757 t.Errorf("a.A: got %s, want %s", got, "\"GET\"")
1761 func TestCgoMissingFile(t *testing.T) { packagestest.TestAll(t, testCgoMissingFile) }
1762 func testCgoMissingFile(t *testing.T, exporter packagestest.Exporter) {
1763 testenv.NeedsTool(t, "cgo")
1764 exported := packagestest.Export(t, exporter, []packagestest.Module{{
1765 Name: "golang.org/fake",
1766 Files: map[string]interface{}{
1767 "a/a.go": `package a
1775 defer exported.Cleanup()
1777 // Explicitly enable cgo.
1778 exported.Config.Env = append(exported.Config.Env, "CGO_ENABLED=1")
1779 exported.Config.Mode = packages.LoadAllSyntax
1780 initial, err := packages.Load(exported.Config, "golang.org/fake/a")
1786 // Check value of a.A.
1788 aA := constant(a, "A")
1790 t.Fatalf("a.A: got nil")
1792 got := aA.Val().String()
1794 t.Errorf("a.A: got %s, want %s", got, "4")
1798 func TestLoadImportsC(t *testing.T) {
1799 // This test checks that when a package depends on the
1800 // test variant of "syscall", "unsafe", or "runtime/cgo", that dependency
1801 // is not removed when those packages are added when it imports "C".
1803 // For this test to work, the external test of syscall must have a dependency
1804 // on net, and net must import "syscall" and "C".
1805 if runtime.GOOS == "windows" {
1806 t.Skipf("skipping on windows; packages on windows do not satisfy conditions for test.")
1808 if runtime.GOOS == "plan9" {
1809 // See https://golang.org/issue/27100.
1810 t.Skip(`skipping on plan9; for some reason "net [syscall.test]" is not loaded`)
1812 testenv.NeedsGoPackages(t)
1814 cfg := &packages.Config{
1816 Mode: packages.LoadImports,
1819 initial, err := packages.Load(cfg, "syscall", "net")
1821 t.Fatalf("failed to load imports: %v", err)
1824 _, all := importGraph(initial)
1826 for _, test := range []struct {
1828 wantImport string // an import to check for
1830 {"net", "syscall:syscall"},
1831 {"net [syscall.test]", "syscall:syscall [syscall.test]"},
1832 {"syscall_test [syscall.test]", "net:net [syscall.test]"},
1834 // Test the import paths.
1835 pkg := all[test.pattern]
1837 t.Errorf("package %q not loaded", test.pattern)
1840 if imports := strings.Join(imports(pkg), " "); !strings.Contains(imports, test.wantImport) {
1841 t.Errorf("package %q: got \n%s, \nwant to have %s", test.pattern, imports, test.wantImport)
1846 func TestCgoNoSyntax(t *testing.T) {
1847 packagestest.TestAll(t, testCgoNoSyntax)
1849 func testCgoNoSyntax(t *testing.T, exporter packagestest.Exporter) {
1850 testenv.NeedsTool(t, "cgo")
1852 exported := packagestest.Export(t, exporter, []packagestest.Module{{
1853 Name: "golang.org/fake",
1854 Files: map[string]interface{}{
1855 "c/c.go": `package c; import "C"`,
1859 // Explicitly enable cgo.
1860 exported.Config.Env = append(exported.Config.Env, "CGO_ENABLED=1")
1862 modes := []packages.LoadMode{
1864 packages.NeedName | packages.NeedTypes,
1865 packages.NeedName | packages.NeedTypes | packages.NeedImports,
1866 packages.NeedName | packages.NeedTypes | packages.NeedImports | packages.NeedDeps,
1867 packages.NeedName | packages.NeedImports,
1869 for _, mode := range modes {
1870 t.Run(fmt.Sprint(mode), func(t *testing.T) {
1871 exported.Config.Mode = mode
1872 pkgs, err := packages.Load(exported.Config, "golang.org/fake/c")
1877 t.Fatalf("Expected 1 package, got %v", pkgs)
1880 if len(pkg.Errors) != 0 {
1881 t.Fatalf("Expected no errors in package, got %v", pkg.Errors)
1887 func TestCgoBadPkgConfig(t *testing.T) {
1888 packagestest.TestAll(t, testCgoBadPkgConfig)
1890 func testCgoBadPkgConfig(t *testing.T, exporter packagestest.Exporter) {
1891 testenv.NeedsTool(t, "cgo")
1893 exported := packagestest.Export(t, exporter, []packagestest.Module{{
1894 Name: "golang.org/fake",
1895 Files: map[string]interface{}{
1896 "c/c.go": `package c
1898 // #cgo pkg-config: --cflags -- foo
1903 dir := buildFakePkgconfig(t, exported.Config.Env)
1904 defer os.RemoveAll(dir)
1905 env := exported.Config.Env
1906 for i, v := range env {
1907 if strings.HasPrefix(v, "PATH=") {
1908 env[i] = "PATH=" + dir + string(os.PathListSeparator) + v[len("PATH="):]
1912 exported.Config.Env = append(exported.Config.Env, "CGO_ENABLED=1")
1914 exported.Config.Mode = packages.NeedName | packages.NeedCompiledGoFiles
1915 pkgs, err := packages.Load(exported.Config, "golang.org/fake/c")
1920 t.Fatalf("Expected 1 package, got %v", pkgs)
1922 if pkgs[0].Name != "c" {
1923 t.Fatalf("Expected package to have name \"c\", got %q", pkgs[0].Name)
1927 func buildFakePkgconfig(t *testing.T, env []string) string {
1928 tmpdir, err := ioutil.TempDir("", "fakepkgconfig")
1932 err = ioutil.WriteFile(filepath.Join(tmpdir, "pkg-config.go"), []byte(`
1939 fmt.Fprintln(os.Stderr, "bad")
1944 os.RemoveAll(tmpdir)
1947 cmd := exec.Command("go", "build", "-o", "pkg-config", "pkg-config.go")
1951 if b, err := cmd.CombinedOutput(); err != nil {
1952 os.RemoveAll(tmpdir)
1953 fmt.Println(os.Environ())
1960 func TestIssue32814(t *testing.T) { packagestest.TestAll(t, testIssue32814) }
1961 func testIssue32814(t *testing.T, exporter packagestest.Exporter) {
1962 exported := packagestest.Export(t, exporter, []packagestest.Module{{
1963 Name: "golang.org/fake",
1964 Files: map[string]interface{}{}}})
1965 defer exported.Cleanup()
1967 exported.Config.Mode = packages.NeedName | packages.NeedTypes | packages.NeedSyntax | packages.NeedTypesInfo | packages.NeedTypesSizes
1968 pkgs, err := packages.Load(exported.Config, "fmt")
1974 if len(pkgs) != 1 && pkgs[0].PkgPath != "fmt" {
1975 t.Fatalf("packages.Load: want [fmt], got %v", pkgs)
1978 if len(pkg.Errors) != 0 {
1979 t.Fatalf("Errors for fmt pkg: got %v, want none", pkg.Errors)
1981 if !pkg.Types.Complete() {
1982 t.Fatalf("Types.Complete() for fmt pkg: got %v, want true", pkgs[0].Types.Complete())
1987 func TestLoadTypesInfoWithoutNeedDeps(t *testing.T) {
1988 packagestest.TestAll(t, testLoadTypesInfoWithoutNeedDeps)
1990 func testLoadTypesInfoWithoutNeedDeps(t *testing.T, exporter packagestest.Exporter) {
1991 exported := packagestest.Export(t, exporter, []packagestest.Module{{
1992 Name: "golang.org/fake",
1993 Files: map[string]interface{}{
1994 "a/a.go": `package a; import _ "golang.org/fake/b"`,
1995 "b/b.go": `package b`,
1997 defer exported.Cleanup()
1999 exported.Config.Mode = packages.NeedTypes | packages.NeedTypesInfo | packages.NeedImports
2000 pkgs, err := packages.Load(exported.Config, "golang.org/fake/a")
2006 t.Fatal("Loaded package is ill typed")
2008 const expectedImport = "golang.org/fake/b"
2009 if _, ok := pkg.Imports[expectedImport]; !ok || len(pkg.Imports) != 1 {
2010 t.Fatalf("Imports of loaded package: want [%s], got %v", expectedImport, pkg.Imports)
2014 func TestLoadWithNeedDeps(t *testing.T) {
2015 packagestest.TestAll(t, testLoadWithNeedDeps)
2017 func testLoadWithNeedDeps(t *testing.T, exporter packagestest.Exporter) {
2018 exported := packagestest.Export(t, exporter, []packagestest.Module{{
2019 Name: "golang.org/fake",
2020 Files: map[string]interface{}{
2021 "a/a.go": `package a; import _ "golang.org/fake/b"`,
2022 "b/b.go": `package b; import _ "golang.org/fake/c"`,
2023 "c/c.go": `package c`,
2025 defer exported.Cleanup()
2027 exported.Config.Mode = packages.NeedTypes | packages.NeedTypesInfo | packages.NeedImports | packages.NeedDeps
2028 pkgs, err := packages.Load(exported.Config, "golang.org/fake/a")
2033 t.Fatalf("Expected 1 package, got %d", len(pkgs))
2038 t.Fatal("Loaded package is ill typed")
2041 pkgB := pkgA.Imports["golang.org/fake/b"]
2042 if pkgB == nil || len(pkgA.Imports) != 1 {
2043 t.Fatalf("Imports of loaded package 'a' are invalid: %v", pkgA.Imports)
2045 if pkgB.Types == nil || !pkgB.Types.Complete() || pkgB.TypesInfo == nil {
2046 t.Fatalf("Types of package 'b' are nil or incomplete: %v, %v", pkgB.Types, pkgB.TypesInfo)
2049 pkgC := pkgB.Imports["golang.org/fake/c"]
2050 if pkgC == nil || len(pkgB.Imports) != 1 {
2051 t.Fatalf("Imports of loaded package 'c' are invalid: %v", pkgB.Imports)
2053 if pkgC.Types == nil || !pkgC.Types.Complete() || pkgC.TypesInfo == nil {
2054 t.Fatalf("Types of package 'b' are nil or incomplete: %v, %v", pkgC.Types, pkgC.TypesInfo)
2058 func TestImpliedLoadMode(t *testing.T) {
2059 packagestest.TestAll(t, testImpliedLoadMode)
2061 func testImpliedLoadMode(t *testing.T, exporter packagestest.Exporter) {
2062 exported := packagestest.Export(t, exporter, []packagestest.Module{{
2063 Name: "golang.org/fake",
2064 Files: map[string]interface{}{
2065 "a/a.go": `package a; import _ "golang.org/fake/b"`,
2066 "b/b.go": `package b`,
2068 defer exported.Cleanup()
2070 exported.Config.Mode = packages.NeedTypes | packages.NeedTypesInfo
2071 pkgs, err := packages.Load(exported.Config, "golang.org/fake/a")
2076 t.Fatalf("Expected 1 package, got %d", len(pkgs))
2081 t.Fatalf("Loaded package is ill typed: %v", pkg.Errors)
2084 // Check that packages.NeedTypesInfo worked well.
2085 if !pkg.Types.Complete() {
2086 t.Fatalf("Loaded package types are incomplete")
2089 // Check that implied packages.NeedImports by packages.NeedTypesInfo
2090 // didn't add Imports.
2091 if len(pkg.Imports) != 0 {
2092 t.Fatalf("Package imports weren't requested but were returned: %v", pkg.Imports)
2096 func TestIssue35331(t *testing.T) {
2097 packagestest.TestAll(t, testIssue35331)
2099 func testIssue35331(t *testing.T, exporter packagestest.Exporter) {
2100 exported := packagestest.Export(t, exporter, []packagestest.Module{{
2101 Name: "golang.org/fake",
2103 defer exported.Cleanup()
2105 exported.Config.Mode = packages.NeedName | packages.NeedFiles | packages.NeedCompiledGoFiles |
2106 packages.NeedImports | packages.NeedDeps | packages.NeedSyntax
2107 exported.Config.Tests = false
2108 pkgs, err := packages.Load(exported.Config, "strconv")
2113 t.Fatalf("Expected 1 package, got %v", pkgs)
2115 packages.Visit(pkgs, func(pkg *packages.Package) bool {
2116 if len(pkg.Errors) > 0 {
2117 t.Errorf("Expected no errors in package %q, got %v", pkg.ID, pkg.Errors)
2119 if len(pkg.Syntax) == 0 && pkg.ID != "unsafe" {
2120 t.Errorf("Expected syntax on package %q, got none.", pkg.ID)
2126 func TestMultiplePackageVersionsIssue36188(t *testing.T) {
2127 packagestest.TestAll(t, testMultiplePackageVersionsIssue36188)
2130 func testMultiplePackageVersionsIssue36188(t *testing.T, exporter packagestest.Exporter) {
2131 exported := packagestest.Export(t, exporter, []packagestest.Module{{
2132 Name: "golang.org/fake",
2133 Files: map[string]interface{}{
2134 "a/a.go": `package a; import _ "golang.org/fake/b"`,
2135 "b/b.go": `package main`,
2137 pkgs, err := packages.Load(exported.Config, "golang.org/fake/a", "golang.org/fake/b")
2141 sort.Slice(pkgs, func(i, j int) bool { return pkgs[i].ID < pkgs[j].ID })
2143 t.Fatalf("expected two packages, got %v", pkgs)
2145 if pkgs[0].ID != "golang.org/fake/a" && pkgs[1].ID != "golang.org/fake/b" {
2146 t.Fatalf(`expected (sorted) IDs "golang.org/fake/a" and "golang.org/fake/b", got %q and %q`,
2147 pkgs[0].ID, pkgs[1].ID)
2149 if pkgs[0].Errors == nil {
2150 t.Errorf(`expected error on package "golang.org/fake/a", got none`)
2152 if pkgs[1].Errors != nil {
2153 t.Errorf(`expected no errors on package "golang.org/fake/b", got %v`, pkgs[1].Errors)
2155 defer exported.Cleanup()
2158 func TestLoadModeStrings(t *testing.T) {
2159 testcases := []struct {
2160 mode packages.LoadMode
2164 packages.LoadMode(0),
2169 "LoadMode(NeedName)",
2173 "LoadMode(NeedFiles)",
2176 packages.NeedCompiledGoFiles,
2177 "LoadMode(NeedCompiledGoFiles)",
2180 packages.NeedImports,
2181 "LoadMode(NeedImports)",
2185 "LoadMode(NeedDeps)",
2188 packages.NeedExportsFile,
2189 "LoadMode(NeedExportsFile)",
2193 "LoadMode(NeedTypes)",
2196 packages.NeedSyntax,
2197 "LoadMode(NeedSyntax)",
2200 packages.NeedTypesInfo,
2201 "LoadMode(NeedTypesInfo)",
2204 packages.NeedTypesSizes,
2205 "LoadMode(NeedTypesSizes)",
2208 packages.NeedName | packages.NeedExportsFile,
2209 "LoadMode(NeedName|NeedExportsFile)",
2212 packages.NeedName | packages.NeedFiles | packages.NeedCompiledGoFiles | packages.NeedImports | packages.NeedDeps | packages.NeedExportsFile | packages.NeedTypes | packages.NeedSyntax | packages.NeedTypesInfo | packages.NeedTypesSizes,
2213 "LoadMode(NeedName|NeedFiles|NeedCompiledGoFiles|NeedImports|NeedDeps|NeedExportsFile|NeedTypes|NeedSyntax|NeedTypesInfo|NeedTypesSizes)",
2216 packages.NeedName | 8192,
2217 "LoadMode(NeedName|Unknown)",
2221 "LoadMode(Unknown)",
2225 for tcInd, tc := range testcases {
2226 t.Run(fmt.Sprintf("test-%d", tcInd), func(t *testing.T) {
2227 actual := tc.mode.String()
2228 if tc.expected != actual {
2229 t.Errorf("want %#v, got %#v", tc.expected, actual)
2235 func TestCycleImportStack(t *testing.T) {
2236 packagestest.TestAll(t, testCycleImportStack)
2238 func testCycleImportStack(t *testing.T, exporter packagestest.Exporter) {
2239 exported := packagestest.Export(t, exporter, []packagestest.Module{{
2240 Name: "golang.org/fake",
2241 Files: map[string]interface{}{
2242 "a/a.go": `package a; import _ "golang.org/fake/b"`,
2243 "b/b.go": `package b; import _ "golang.org/fake/a"`,
2245 defer exported.Cleanup()
2247 exported.Config.Mode = packages.NeedName | packages.NeedImports
2248 pkgs, err := packages.Load(exported.Config, "golang.org/fake/a")
2253 t.Fatalf("Expected 1 package, got %v", pkgs)
2256 if len(pkg.Errors) != 1 {
2257 t.Fatalf("Expected one error in package, got %v", pkg.Errors)
2259 expected := "import cycle not allowed: import stack: [golang.org/fake/a golang.org/fake/b golang.org/fake/a]"
2260 if pkg.Errors[0].Msg != expected {
2261 t.Fatalf("Expected error %q, got %q", expected, pkg.Errors[0].Msg)
2265 func TestForTestField(t *testing.T) {
2266 packagestest.TestAll(t, testForTestField)
2268 func testForTestField(t *testing.T, exporter packagestest.Exporter) {
2269 exported := packagestest.Export(t, exporter, []packagestest.Module{{
2270 Name: "golang.org/fake",
2271 Files: map[string]interface{}{
2272 "a/a.go": `package a; func hello() {};`,
2273 "a/a_test.go": `package a; import "testing"; func TestA1(t *testing.T) {};`,
2274 "a/x_test.go": `package a_test; import "testing"; func TestA2(t *testing.T) {};`,
2276 defer exported.Cleanup()
2278 // Add overlays to make sure they don't affect anything.
2279 exported.Config.Overlay = map[string][]byte{
2280 "a/a_test.go": []byte(`package a; import "testing"; func TestA1(t *testing.T) { hello(); };`),
2281 "a/x_test.go": []byte(`package a_test; import "testing"; func TestA2(t *testing.T) { hello(); };`),
2283 exported.Config.Tests = true
2284 exported.Config.Mode = packages.NeedName | packages.NeedImports
2285 forTest := "golang.org/fake/a"
2286 pkgs, err := packages.Load(exported.Config, forTest)
2291 t.Errorf("expected 4 packages, got %v", len(pkgs))
2293 for _, pkg := range pkgs {
2294 var hasTestFile bool
2295 for _, f := range pkg.CompiledGoFiles {
2296 if strings.Contains(f, "a_test.go") || strings.Contains(f, "x_test.go") {
2304 got := packagesinternal.GetForTest(pkg)
2306 t.Errorf("expected %q, got %q", forTest, got)
2311 func TestIssue37529(t *testing.T) {
2312 packagestest.TestAll(t, testIssue37529)
2314 func testIssue37529(t *testing.T, exporter packagestest.Exporter) {
2315 // Tests #37529. When automatic vendoring is triggered, and we try to determine
2316 // the module root dir for a new overlay package, we previously would do a go list -m all,
2317 // which is incompatible with automatic vendoring.
2319 exported := packagestest.Export(t, exporter, []packagestest.Module{{
2320 Name: "golang.org/fake",
2321 Files: map[string]interface{}{
2322 "c/c2.go": `package c`,
2323 "a/a.go": `package a; import "b.com/b"; const A = b.B`,
2324 "vendor/b.com/b/b.go": `package b; const B = 4`,
2326 rootDir := filepath.Dir(filepath.Dir(exported.File("golang.org/fake", "a/a.go")))
2327 exported.Config.Overlay = map[string][]byte{
2328 filepath.Join(rootDir, "c/c.go"): []byte(`package c; import "golang.org/fake/a"; const C = a.A`),
2330 exported.Config.Env = append(exported.Config.Env, "GOFLAGS=-mod=vendor")
2331 exported.Config.Mode = packages.LoadAllSyntax
2333 defer exported.Cleanup()
2335 initial, err := packages.Load(exported.Config, "golang.org/fake/c")
2340 // Check value of a.A.
2342 aA := constant(a, "C")
2344 t.Fatalf("a.A: got nil")
2346 got := aA.Val().String()
2348 t.Errorf("a.A: got %s, want %s", got, "4")
2352 func TestIssue37098(t *testing.T) { packagestest.TestAll(t, testIssue37098) }
2353 func testIssue37098(t *testing.T, exporter packagestest.Exporter) {
2354 // packages.Load should only return Go sources in
2355 // (*Package).CompiledGoFiles. This tests #37098, where using SWIG to
2356 // causes C++ sources to be inadvertently included in
2357 // (*Package).CompiledGoFiles.
2358 t.Skip("Issue #37098: SWIG causes generated C++ sources in CompiledGoFiles")
2360 // Create a fake package with an empty Go source, and a SWIG interface
2362 exported := packagestest.Export(t, exporter, []packagestest.Module{{
2363 Name: "golang.org/fake",
2364 Files: map[string]interface{}{
2365 // The "package" statement must be included for SWIG sources to
2367 "a/a.go": "package a",
2370 defer exported.Cleanup()
2372 initial, err := packages.Load(exported.Config, "golang.org/fake/a")
2374 t.Fatalf("failed to load the package: %v", err)
2376 // Try and parse each of the files
2377 for _, pkg := range initial {
2378 for _, file := range pkg.CompiledGoFiles {
2380 // Validate that each file can be parsed as a Go source.
2381 fset := token.NewFileSet()
2382 _, err := parser.ParseFile(fset, file, nil, parser.ImportsOnly)
2384 t.Errorf("Failed to parse file '%s' as a Go source: %v", file, err)
2386 contents, err := ioutil.ReadFile(file)
2388 t.Fatalf("Failed to read the un-parsable file '%s': %v", file, err)
2391 // Print out some of the un-parsable file to aid in debugging.
2394 // Don't print the whole file if it is too large.
2395 const maxBytes = 1000
2400 t.Logf("First %d bytes of un-parsable file: %s", n, contents[:n])
2406 // TestInvalidFilesInXTest checks the fix for golang/go#37971 in Go 1.15.
2407 func TestInvalidFilesInXTest(t *testing.T) { packagestest.TestAll(t, testInvalidFilesInXTest) }
2408 func testInvalidFilesInXTest(t *testing.T, exporter packagestest.Exporter) {
2409 testenv.NeedsGo1Point(t, 15)
2410 exported := packagestest.Export(t, exporter, []packagestest.Module{
2412 Name: "golang.org/fake",
2413 Files: map[string]interface{}{
2414 "d/d.go": `package d; import "net/http"; const d = http.MethodGet; func Get() string { return d; }`,
2415 "d/d2.go": ``, // invalid file
2416 "d/d_test.go": `package d_test; import "testing"; import "golang.org/fake/d"; func TestD(t *testing.T) { d.Get(); }`,
2420 defer exported.Cleanup()
2422 exported.Config.Mode = packages.NeedName | packages.NeedFiles
2423 exported.Config.Tests = true
2425 initial, err := packages.Load(exported.Config, "golang.org/fake/d")
2429 if len(initial) != 3 {
2430 t.Errorf("expected 3 packages, got %d", len(initial))
2434 func TestTypecheckCgo(t *testing.T) { packagestest.TestAll(t, testTypecheckCgo) }
2435 func testTypecheckCgo(t *testing.T, exporter packagestest.Exporter) {
2436 testenv.NeedsGo1Point(t, 15)
2437 testenv.NeedsTool(t, "cgo")
2439 const cgo = `package cgo
2446 exported := packagestest.Export(t, exporter, []packagestest.Module{
2448 Name: "golang.org/fake",
2449 Files: map[string]interface{}{
2454 defer exported.Cleanup()
2456 exported.Config.Mode = packages.NeedFiles | packages.NeedCompiledGoFiles |
2457 packages.NeedSyntax | packages.NeedDeps | packages.NeedTypes |
2458 packages.LoadMode(packagesinternal.TypecheckCgo)
2460 initial, err := packages.Load(exported.Config, "golang.org/fake/cgo")
2465 if len(pkg.Errors) != 0 {
2466 t.Fatalf("package has errors: %v", pkg.Errors)
2469 expos := pkg.Types.Scope().Lookup("Example").Pos()
2470 fname := pkg.Fset.File(expos).Name()
2471 if !strings.HasSuffix(fname, "cgo.go") {
2472 t.Errorf("position for cgo package was loaded from %v, wanted cgo.go", fname)
2476 func TestModule(t *testing.T) {
2477 packagestest.TestAll(t, testModule)
2479 func testModule(t *testing.T, exporter packagestest.Exporter) {
2480 exported := packagestest.Export(t, exporter, []packagestest.Module{{
2481 Name: "golang.org/fake",
2482 Files: map[string]interface{}{"a/a.go": `package a`}}})
2483 exported.Config.Mode = packages.NeedModule
2484 rootDir := filepath.Dir(filepath.Dir(exported.File("golang.org/fake", "a/a.go")))
2486 initial, err := packages.Load(exported.Config, "golang.org/fake/a")
2491 if len(initial) != 1 {
2492 t.Fatal("want exactly one package, got ", initial)
2495 switch exported.Exporter.Name() {
2497 if a.Module != nil {
2498 t.Fatal("package.Module: want nil, got ", a.Module)
2501 // Make sure Modules field is set, and spot check a few of its fields.
2502 if a.Module == nil {
2503 t.Fatal("package.Module: want non-nil, got nil")
2505 if a.Module.Path != "golang.org/fake" {
2506 t.Fatalf("package.Modile.Path: want \"golang.org/fake\", got %q", a.Module.Path)
2508 if a.Module.GoMod != filepath.Join(rootDir, "go.mod") {
2509 t.Fatalf("package.Module.GoMod: want %q, got %q", filepath.Join(rootDir, "go.mod"), a.Module.GoMod)
2512 t.Fatalf("Expected exporter to be GOPATH or Modules, got %v", exported.Exporter.Name())
2516 func TestExternal_NotHandled(t *testing.T) {
2517 packagestest.TestAll(t, testExternal_NotHandled)
2519 func testExternal_NotHandled(t *testing.T, exporter packagestest.Exporter) {
2520 testenv.NeedsGoBuild(t)
2522 tempdir, err := ioutil.TempDir("", "testexternal")
2526 defer os.RemoveAll(tempdir)
2528 exported := packagestest.Export(t, exporter, []packagestest.Module{{
2529 Name: "golang.org/fake",
2530 Files: map[string]interface{}{
2531 "a/a.go": `package a`,
2532 "empty_driver/main.go": `package main
2541 ioutil.ReadAll(os.Stdin)
2545 "nothandled_driver/main.go": `package main
2554 ioutil.ReadAll(os.Stdin)
2555 fmt.Println("{\"NotHandled\": true}")
2559 baseEnv := exported.Config.Env
2561 // As a control, create a fake driver that always returns an empty response.
2562 emptyDriverPath := filepath.Join(tempdir, "empty_driver.exe") // Add .exe because Windows expects it.
2563 cmd := exec.Command("go", "build", "-o", emptyDriverPath, "golang.org/fake/empty_driver")
2565 cmd.Dir = exported.Config.Dir
2566 if b, err := cmd.CombinedOutput(); err != nil {
2571 exported.Config.Env = append(append([]string{}, baseEnv...), "GOPACKAGESDRIVER="+emptyDriverPath)
2572 initial, err := packages.Load(exported.Config, "golang.org/fake/a")
2577 if len(initial) != 0 {
2578 t.Errorf("package.Load with empty driver: want [], got %v", initial)
2581 // Create a fake driver that always returns a NotHandled response.
2582 notHandledDriverPath := filepath.Join(tempdir, "nothandled_driver.exe")
2583 cmd = exec.Command("go", "build", "-o", notHandledDriverPath, "golang.org/fake/nothandled_driver")
2585 cmd.Dir = exported.Config.Dir
2586 if b, err := cmd.CombinedOutput(); err != nil {
2591 exported.Config.Env = append(append([]string{}, baseEnv...), "GOPACKAGESDRIVER="+notHandledDriverPath)
2592 initial, err = packages.Load(exported.Config, "golang.org/fake/a")
2597 if len(initial) != 1 || initial[0].PkgPath != "golang.org/fake/a" {
2598 t.Errorf("package.Load: want [golang.org/fake/a], got %v", initial)
2602 func TestInvalidPackageName(t *testing.T) {
2603 packagestest.TestAll(t, testInvalidPackageName)
2606 func testInvalidPackageName(t *testing.T, exporter packagestest.Exporter) {
2607 testenv.NeedsGo1Point(t, 15)
2609 exported := packagestest.Export(t, exporter, []packagestest.Module{{
2610 Name: "golang.org/fake",
2611 Files: map[string]interface{}{
2612 "main.go": `package default
2619 defer exported.Cleanup()
2621 initial, err := packages.Load(exported.Config, "golang.org/fake")
2626 if len(pkg.CompiledGoFiles) != 1 {
2627 t.Fatalf("expected 1 Go file in package %s, got %v", pkg.ID, len(pkg.CompiledGoFiles))
2631 func errorMessages(errors []packages.Error) []string {
2633 for _, err := range errors {
2634 msgs = append(msgs, err.Msg)
2639 func srcs(p *packages.Package) []string {
2640 return cleanPaths(append(p.GoFiles[:len(p.GoFiles):len(p.GoFiles)], p.OtherFiles...))
2643 // cleanPaths attempts to reduce path names to stable forms
2644 func cleanPaths(paths []string) []string {
2645 result := make([]string, len(paths))
2646 for i, src := range paths {
2647 // If the source file doesn't have an extension like .go or .s,
2648 // it comes from GOCACHE. The names there aren't predictable.
2649 name := filepath.Base(src)
2650 if !strings.Contains(name, ".") {
2651 result[i] = fmt.Sprintf("%d.go", i) // make cache names predictable
2659 // importGraph returns the import graph as a user-friendly string,
2660 // and a map containing all packages keyed by ID.
2661 func importGraph(initial []*packages.Package) (string, map[string]*packages.Package) {
2662 out := new(bytes.Buffer)
2664 initialSet := make(map[*packages.Package]bool)
2665 for _, p := range initial {
2666 initialSet[p] = true
2669 // We can't use Visit because we need to prune
2670 // the traversal of specific edges, not just nodes.
2671 var nodes, edges []string
2672 res := make(map[string]*packages.Package)
2673 seen := make(map[*packages.Package]bool)
2674 var visit func(p *packages.Package)
2675 visit = func(p *packages.Package) {
2678 if res[p.ID] != nil {
2679 panic("duplicate ID: " + p.ID)
2683 star := ' ' // mark initial packages with a star
2687 nodes = append(nodes, fmt.Sprintf("%c %s", star, p.ID))
2689 // To avoid a lot of noise,
2690 // we prune uninteresting dependencies of testmain packages,
2691 // which we identify by this import:
2692 isTestMain := p.Imports["testing/internal/testdeps"] != nil
2694 for _, imp := range p.Imports {
2697 case "os", "reflect", "testing", "testing/internal/testdeps":
2701 // math/bits took on a dependency on unsafe in 1.12, which breaks some
2702 // tests. As a short term hack, prune that edge.
2703 // ditto for ("errors", "internal/reflectlite") in 1.13.
2704 // TODO(matloob): think of a cleaner solution, or remove math/bits from the test.
2705 if p.ID == "math/bits" && imp.ID == "unsafe" {
2708 edges = append(edges, fmt.Sprintf("%s -> %s", p, imp))
2713 for _, p := range initial {
2717 // Sort, ignoring leading optional star prefix.
2718 sort.Slice(nodes, func(i, j int) bool { return nodes[i][2:] < nodes[j][2:] })
2719 for _, node := range nodes {
2720 fmt.Fprintf(out, "%s\n", node)
2724 for _, edge := range edges {
2725 fmt.Fprintf(out, " %s\n", edge)
2728 return out.String(), res
2731 func constant(p *packages.Package, name string) *types.Const {
2732 if p == nil || p.Types == nil {
2735 c := p.Types.Scope().Lookup(name)
2739 return c.(*types.Const)
2742 func copyAll(srcPath, dstPath string) error {
2743 return filepath.Walk(srcPath, func(path string, info os.FileInfo, _ error) error {
2747 contents, err := ioutil.ReadFile(path)
2751 rel, err := filepath.Rel(srcPath, path)
2755 dstFilePath := strings.Replace(filepath.Join(dstPath, rel), "definitelynot_go.mod", "go.mod", -1)
2756 if err := os.MkdirAll(filepath.Dir(dstFilePath), 0755); err != nil {
2759 if err := ioutil.WriteFile(dstFilePath, contents, 0644); err != nil {