1
2
3
4
5 package packages_test
6
7 import (
8 "bytes"
9 "context"
10 "encoding/json"
11 "flag"
12 "fmt"
13 "go/ast"
14 constantpkg "go/constant"
15 "go/parser"
16 "go/token"
17 "go/types"
18 "os"
19 "os/exec"
20 "path/filepath"
21 "reflect"
22 "runtime"
23 "sort"
24 "strings"
25 "testing"
26 "time"
27
28 "golang.org/x/tools/go/packages"
29 "golang.org/x/tools/go/packages/packagestest"
30 "golang.org/x/tools/internal/packagesinternal"
31 "golang.org/x/tools/internal/testenv"
32 )
33
34
35
36
37
38 var testCtx = context.Background()
39
40 func TestMain(m *testing.M) {
41 testenv.ExitIfSmallMachine()
42
43 timeoutFlag := flag.Lookup("test.timeout")
44 if timeoutFlag != nil {
45 if d := timeoutFlag.Value.(flag.Getter).Get().(time.Duration); d != 0 {
46 aBitShorter := d * 95 / 100
47 var cancel context.CancelFunc
48 testCtx, cancel = context.WithTimeout(testCtx, aBitShorter)
49 defer cancel()
50 }
51 }
52
53 os.Exit(m.Run())
54 }
55
56 func skipIfShort(t *testing.T, reason string) {
57 if testing.Short() {
58 t.Skipf("skipping slow test in short mode: %s", reason)
59 }
60 }
61
62
63
64 func testAllOrModulesParallel(t *testing.T, f func(*testing.T, packagestest.Exporter)) {
65 t.Parallel()
66 packagestest.TestAll(t, func(t *testing.T, exporter packagestest.Exporter) {
67 t.Helper()
68
69 switch exporter.Name() {
70 case "Modules":
71 case "GOPATH":
72 if testing.Short() {
73 t.Skipf("skipping GOPATH test in short mode")
74 }
75 default:
76 t.Fatalf("unexpected exporter %q", exporter.Name())
77 }
78
79 t.Parallel()
80 f(t, exporter)
81 })
82 }
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103 func TestLoadZeroConfig(t *testing.T) {
104 testenv.NeedsGoPackages(t)
105 t.Parallel()
106
107 initial, err := packages.Load(nil, "hash")
108 if err != nil {
109 t.Fatal(err)
110 }
111 if len(initial) != 1 {
112 t.Fatalf("got %s, want [hash]", initial)
113 }
114 hash := initial[0]
115
116
117 got := fmt.Sprintf("srcs=%v imports=%v", srcs(hash), hash.Imports)
118 want := "srcs=[hash.go] imports=map[]"
119 if got != want {
120 t.Fatalf("got %s, want %s", got, want)
121 }
122 }
123
124 func TestLoadImportsGraph(t *testing.T) { testAllOrModulesParallel(t, testLoadImportsGraph) }
125 func testLoadImportsGraph(t *testing.T, exporter packagestest.Exporter) {
126 exported := packagestest.Export(t, exporter, []packagestest.Module{{
127 Name: "golang.org/fake",
128 Files: map[string]interface{}{
129 "a/a.go": `package a; const A = 1`,
130 "b/b.go": `package b; import ("golang.org/fake/a"; _ "container/list"); var B = a.A`,
131 "c/c.go": `package c; import (_ "golang.org/fake/b"; _ "unsafe")`,
132 "c/c2.go": "// +build ignore\n\n" + `package c; import _ "fmt"`,
133 "subdir/d/d.go": `package d`,
134 "subdir/d/d_test.go": `package d; import _ "math/bits"`,
135 "subdir/d/x_test.go": `package d_test; import _ "golang.org/fake/subdir/d"`,
136 "subdir/e/d.go": `package e`,
137 "e/e.go": `package main; import _ "golang.org/fake/b"`,
138 "e/e2.go": `package main; import _ "golang.org/fake/c"`,
139 "f/f.go": `package f`,
140 }}})
141 defer exported.Cleanup()
142 exported.Config.Mode = packages.LoadImports
143 initial, err := packages.Load(exported.Config, "golang.org/fake/c", "golang.org/fake/subdir/d", "golang.org/fake/e")
144 if err != nil {
145 t.Fatal(err)
146 }
147
148
149 graph, _ := importGraph(initial)
150 wantGraph := `
151 container/list
152 golang.org/fake/a
153 golang.org/fake/b
154 * golang.org/fake/c
155 * golang.org/fake/e
156 * golang.org/fake/subdir/d
157 * golang.org/fake/subdir/d [golang.org/fake/subdir/d.test]
158 * golang.org/fake/subdir/d.test
159 * golang.org/fake/subdir/d_test [golang.org/fake/subdir/d.test]
160 math/bits
161 unsafe
162 golang.org/fake/b -> container/list
163 golang.org/fake/b -> golang.org/fake/a
164 golang.org/fake/c -> golang.org/fake/b
165 golang.org/fake/c -> unsafe
166 golang.org/fake/e -> golang.org/fake/b
167 golang.org/fake/e -> golang.org/fake/c
168 golang.org/fake/subdir/d [golang.org/fake/subdir/d.test] -> math/bits
169 golang.org/fake/subdir/d.test -> golang.org/fake/subdir/d [golang.org/fake/subdir/d.test]
170 golang.org/fake/subdir/d.test -> golang.org/fake/subdir/d_test [golang.org/fake/subdir/d.test]
171 golang.org/fake/subdir/d_test [golang.org/fake/subdir/d.test] -> golang.org/fake/subdir/d [golang.org/fake/subdir/d.test]
172 `[1:]
173
174 if graph != wantGraph {
175 t.Errorf("wrong import graph: got <<%s>>, want <<%s>>", graph, wantGraph)
176 }
177
178 exported.Config.Tests = true
179 initial, err = packages.Load(exported.Config, "golang.org/fake/c", "golang.org/fake/subdir/d", "golang.org/fake/e")
180 if err != nil {
181 t.Fatal(err)
182 }
183
184
185 graph, all := importGraph(initial)
186 wantGraph = `
187 container/list
188 golang.org/fake/a
189 golang.org/fake/b
190 * golang.org/fake/c
191 * golang.org/fake/e
192 * golang.org/fake/subdir/d
193 * golang.org/fake/subdir/d [golang.org/fake/subdir/d.test]
194 * golang.org/fake/subdir/d.test
195 * golang.org/fake/subdir/d_test [golang.org/fake/subdir/d.test]
196 math/bits
197 unsafe
198 golang.org/fake/b -> container/list
199 golang.org/fake/b -> golang.org/fake/a
200 golang.org/fake/c -> golang.org/fake/b
201 golang.org/fake/c -> unsafe
202 golang.org/fake/e -> golang.org/fake/b
203 golang.org/fake/e -> golang.org/fake/c
204 golang.org/fake/subdir/d [golang.org/fake/subdir/d.test] -> math/bits
205 golang.org/fake/subdir/d.test -> golang.org/fake/subdir/d [golang.org/fake/subdir/d.test]
206 golang.org/fake/subdir/d.test -> golang.org/fake/subdir/d_test [golang.org/fake/subdir/d.test]
207 golang.org/fake/subdir/d_test [golang.org/fake/subdir/d.test] -> golang.org/fake/subdir/d [golang.org/fake/subdir/d.test]
208 `[1:]
209
210 if graph != wantGraph {
211 t.Errorf("wrong import graph: got <<%s>>, want <<%s>>", graph, wantGraph)
212 }
213
214
215 for _, test := range []struct {
216 id string
217 wantName string
218 wantKind string
219 wantSrcs string
220 wantIgnored string
221 }{
222 {"golang.org/fake/a", "a", "package", "a.go", ""},
223 {"golang.org/fake/b", "b", "package", "b.go", ""},
224 {"golang.org/fake/c", "c", "package", "c.go", "c2.go"},
225 {"golang.org/fake/e", "main", "command", "e.go e2.go", ""},
226 {"container/list", "list", "package", "list.go", ""},
227 {"golang.org/fake/subdir/d", "d", "package", "d.go", ""},
228 {"golang.org/fake/subdir/d.test", "main", "command", "0.go", ""},
229 {"unsafe", "unsafe", "package", "unsafe.go", ""},
230 } {
231 p, ok := all[test.id]
232 if !ok {
233 t.Errorf("no package %s", test.id)
234 continue
235 }
236 if p.Name != test.wantName {
237 t.Errorf("%s.Name = %q, want %q", test.id, p.Name, test.wantName)
238 }
239
240
241 var kind string
242 if p.Name == "main" {
243 kind += "command"
244 } else {
245 kind += "package"
246 }
247 if kind != test.wantKind {
248 t.Errorf("%s.Kind = %q, want %q", test.id, kind, test.wantKind)
249 }
250
251 if srcs := strings.Join(srcs(p), " "); srcs != test.wantSrcs {
252 t.Errorf("%s.{Go,Other,Embed}Files = [%s], want [%s]", test.id, srcs, test.wantSrcs)
253 }
254 if ignored := strings.Join(cleanPaths(p.IgnoredFiles), " "); ignored != test.wantIgnored {
255 t.Errorf("%s.IgnoredFiles = [%s], want [%s]", test.id, ignored, test.wantIgnored)
256 }
257 }
258
259
260 if initial, err := packages.Load(exported.Config, exported.File("golang.org/fake", "c/c.go")); len(initial) == 0 {
261 t.Errorf("failed to obtain metadata for ad-hoc package: %s", err)
262 } else {
263 got := fmt.Sprintf("%s %s", initial[0].ID, srcs(initial[0]))
264 if want := "command-line-arguments [c.go]"; got != want {
265 t.Errorf("oops: got %s, want %s", got, want)
266 }
267 }
268
269
270
271
272 {
273
274 initial, err = packages.Load(exported.Config, "golang.org/fake/subdir/...")
275 if err != nil {
276 t.Fatal(err)
277 }
278 graph, _ = importGraph(initial)
279 wantGraph = `
280 * golang.org/fake/subdir/d
281 * golang.org/fake/subdir/d [golang.org/fake/subdir/d.test]
282 * golang.org/fake/subdir/d.test
283 * golang.org/fake/subdir/d_test [golang.org/fake/subdir/d.test]
284 * golang.org/fake/subdir/e
285 math/bits
286 golang.org/fake/subdir/d [golang.org/fake/subdir/d.test] -> math/bits
287 golang.org/fake/subdir/d.test -> golang.org/fake/subdir/d [golang.org/fake/subdir/d.test]
288 golang.org/fake/subdir/d.test -> golang.org/fake/subdir/d_test [golang.org/fake/subdir/d.test]
289 golang.org/fake/subdir/d_test [golang.org/fake/subdir/d.test] -> golang.org/fake/subdir/d [golang.org/fake/subdir/d.test]
290 `[1:]
291
292 if graph != wantGraph {
293 t.Errorf("wrong import graph: got <<%s>>, want <<%s>>", graph, wantGraph)
294 }
295 }
296 }
297
298 func TestLoadImportsTestVariants(t *testing.T) {
299 testAllOrModulesParallel(t, testLoadImportsTestVariants)
300 }
301 func testLoadImportsTestVariants(t *testing.T, exporter packagestest.Exporter) {
302 exported := packagestest.Export(t, exporter, []packagestest.Module{{
303 Name: "golang.org/fake",
304 Files: map[string]interface{}{
305 "a/a.go": `package a; import _ "golang.org/fake/b"`,
306 "b/b.go": `package b`,
307 "b/b_test.go": `package b`,
308 "b/bx_test.go": `package b_test; import _ "golang.org/fake/a"`,
309 }}})
310 defer exported.Cleanup()
311 exported.Config.Mode = packages.LoadImports
312 exported.Config.Tests = true
313
314 initial, err := packages.Load(exported.Config, "golang.org/fake/a", "golang.org/fake/b")
315 if err != nil {
316 t.Fatal(err)
317 }
318
319
320 graph, _ := importGraph(initial)
321 wantGraph := `
322 * golang.org/fake/a
323 golang.org/fake/a [golang.org/fake/b.test]
324 * golang.org/fake/b
325 * golang.org/fake/b [golang.org/fake/b.test]
326 * golang.org/fake/b.test
327 * golang.org/fake/b_test [golang.org/fake/b.test]
328 golang.org/fake/a -> golang.org/fake/b
329 golang.org/fake/a [golang.org/fake/b.test] -> golang.org/fake/b [golang.org/fake/b.test]
330 golang.org/fake/b.test -> golang.org/fake/b [golang.org/fake/b.test]
331 golang.org/fake/b.test -> golang.org/fake/b_test [golang.org/fake/b.test]
332 golang.org/fake/b_test [golang.org/fake/b.test] -> golang.org/fake/a [golang.org/fake/b.test]
333 `[1:]
334
335 if graph != wantGraph {
336 t.Errorf("wrong import graph: got <<%s>>, want <<%s>>", graph, wantGraph)
337 }
338 }
339
340 func TestLoadAbsolutePath(t *testing.T) {
341 t.Parallel()
342
343 exported := packagestest.Export(t, packagestest.GOPATH, []packagestest.Module{{
344 Name: "golang.org/gopatha",
345 Files: map[string]interface{}{
346 "a/a.go": `package a`,
347 }}, {
348 Name: "golang.org/gopathb",
349 Files: map[string]interface{}{
350 "b/b.go": `package b`,
351 }}})
352 defer exported.Cleanup()
353
354 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")))
355 if err != nil {
356 t.Fatalf("failed to load imports: %v", err)
357 }
358
359 got := []string{}
360 for _, p := range initial {
361 got = append(got, p.ID)
362 }
363 sort.Strings(got)
364 want := []string{"golang.org/gopatha/a", "golang.org/gopathb/b"}
365 if !reflect.DeepEqual(got, want) {
366 t.Fatalf("initial packages loaded: got [%s], want [%s]", got, want)
367 }
368 }
369
370 func TestLoadArgumentListIsNotTooLong(t *testing.T) {
371
372
373 t.Parallel()
374
375
376
377 argMax := 1_000_000
378 exported := packagestest.Export(t, packagestest.GOPATH, []packagestest.Module{{
379 Name: "golang.org/mod",
380 Files: map[string]interface{}{
381 "main.go": `package main"`,
382 }}})
383 defer exported.Cleanup()
384 numOfPatterns := argMax/16 + 1
385 patterns := make([]string, numOfPatterns)
386 for i := 0; i < numOfPatterns; i++ {
387 patterns[i] = fmt.Sprintf("golang.org/mod/p%d", i)
388 }
389
390 _, err := packages.Load(exported.Config, patterns...)
391 if err != nil {
392 t.Fatalf("failed to load: %v", err)
393 }
394 }
395
396 func TestVendorImports(t *testing.T) {
397 t.Parallel()
398
399 exported := packagestest.Export(t, packagestest.GOPATH, []packagestest.Module{{
400 Name: "golang.org/fake",
401 Files: map[string]interface{}{
402 "a/a.go": `package a; import _ "b"; import _ "golang.org/fake/c";`,
403 "a/vendor/b/b.go": `package b; import _ "golang.org/fake/c"`,
404 "c/c.go": `package c; import _ "b"`,
405 "c/vendor/b/b.go": `package b`,
406 }}})
407 defer exported.Cleanup()
408 exported.Config.Mode = packages.LoadImports
409 initial, err := packages.Load(exported.Config, "golang.org/fake/a", "golang.org/fake/c")
410 if err != nil {
411 t.Fatal(err)
412 }
413
414 graph, all := importGraph(initial)
415 wantGraph := `
416 * golang.org/fake/a
417 golang.org/fake/a/vendor/b
418 * golang.org/fake/c
419 golang.org/fake/c/vendor/b
420 golang.org/fake/a -> golang.org/fake/a/vendor/b
421 golang.org/fake/a -> golang.org/fake/c
422 golang.org/fake/a/vendor/b -> golang.org/fake/c
423 golang.org/fake/c -> golang.org/fake/c/vendor/b
424 `[1:]
425 if graph != wantGraph {
426 t.Errorf("wrong import graph: got <<%s>>, want <<%s>>", graph, wantGraph)
427 }
428
429 for _, test := range []struct {
430 pattern string
431 wantImports string
432 }{
433 {"golang.org/fake/a", "b:golang.org/fake/a/vendor/b golang.org/fake/c:golang.org/fake/c"},
434 {"golang.org/fake/c", "b:golang.org/fake/c/vendor/b"},
435 {"golang.org/fake/a/vendor/b", "golang.org/fake/c:golang.org/fake/c"},
436 {"golang.org/fake/c/vendor/b", ""},
437 } {
438
439 pkg := all[test.pattern]
440 if imports := strings.Join(imports(pkg), " "); imports != test.wantImports {
441 t.Errorf("package %q: got %s, want %s", test.pattern, imports, test.wantImports)
442 }
443 }
444 }
445
446 func imports(p *packages.Package) []string {
447 if p == nil {
448 return nil
449 }
450 keys := make([]string, 0, len(p.Imports))
451 for k, v := range p.Imports {
452 keys = append(keys, fmt.Sprintf("%s:%s", k, v.ID))
453 }
454 sort.Strings(keys)
455 return keys
456 }
457
458 func TestConfigDir(t *testing.T) { testAllOrModulesParallel(t, testConfigDir) }
459 func testConfigDir(t *testing.T, exporter packagestest.Exporter) {
460 exported := packagestest.Export(t, exporter, []packagestest.Module{{
461 Name: "golang.org/fake",
462 Files: map[string]interface{}{
463 "a/a.go": `package a; const Name = "a" `,
464 "a/b/b.go": `package b; const Name = "a/b"`,
465 "b/b.go": `package b; const Name = "b"`,
466 }}})
467 defer exported.Cleanup()
468 aDir := filepath.Dir(exported.File("golang.org/fake", "a/a.go"))
469 bDir := filepath.Dir(exported.File("golang.org/fake", "b/b.go"))
470 baseDir := filepath.Dir(aDir)
471
472 for _, test := range []struct {
473 dir string
474 pattern string
475 want string
476 fails bool
477 }{
478 {dir: bDir, pattern: "golang.org/fake/a", want: `"a"`},
479 {dir: bDir, pattern: "golang.org/fake/b", want: `"b"`},
480 {dir: bDir, pattern: "./a", fails: true},
481 {dir: bDir, pattern: "./b", fails: true},
482 {dir: baseDir, pattern: "golang.org/fake/a", want: `"a"`},
483 {dir: baseDir, pattern: "golang.org/fake/b", want: `"b"`},
484 {dir: baseDir, pattern: "./a", want: `"a"`},
485 {dir: baseDir, pattern: "./b", want: `"b"`},
486 {dir: aDir, pattern: "golang.org/fake/a", want: `"a"`},
487 {dir: aDir, pattern: "golang.org/fake/b", want: `"b"`},
488 {dir: aDir, pattern: "./a", fails: true},
489 {dir: aDir, pattern: "./b", want: `"a/b"`},
490 } {
491 exported.Config.Mode = packages.LoadSyntax
492 exported.Config.Dir = test.dir
493 initial, err := packages.Load(exported.Config, test.pattern)
494 var got string
495 fails := false
496 if err != nil {
497 fails = true
498 } else if len(initial) > 0 {
499 if len(initial[0].Errors) > 0 {
500 fails = true
501 } else if c := constant(initial[0], "Name"); c != nil {
502 got = c.Val().String()
503 }
504 }
505 if got != test.want {
506 t.Errorf("dir %q, pattern %q: got %s, want %s",
507 test.dir, test.pattern, got, test.want)
508 }
509 if fails != test.fails {
510
511 if test.fails && strings.HasPrefix(test.pattern, "./") && exporter == packagestest.Modules {
512
513 continue
514 }
515 t.Errorf("dir %q, pattern %q: error %v, want %v",
516 test.dir, test.pattern, fails, test.fails)
517 }
518 }
519 }
520
521 func TestConfigFlags(t *testing.T) { testAllOrModulesParallel(t, testConfigFlags) }
522 func testConfigFlags(t *testing.T, exporter packagestest.Exporter) {
523
524 exported := packagestest.Export(t, exporter, []packagestest.Module{{
525 Name: "golang.org/fake",
526 Files: map[string]interface{}{
527
528 "a/a.go": `package a; import _ "golang.org/fake/a/b"`,
529 "a/b.go": `// +build tag
530
531 package a`,
532 "a/c.go": `// +build tag tag2
533
534 package a`,
535 "a/d.go": `// +build tag,tag2
536
537 package a`,
538
539 "a/b/a.go": `package b`,
540 "a/b/b.go": `// +build tag
541
542 package b`,
543 }}})
544 defer exported.Cleanup()
545
546 for _, test := range []struct {
547 pattern string
548 tags []string
549 wantSrcs string
550 wantImportSrcs string
551 }{
552 {`golang.org/fake/a`, []string{}, "a.go", "a.go"},
553 {`golang.org/fake/a`, []string{`-tags=tag`}, "a.go b.go c.go", "a.go b.go"},
554 {`golang.org/fake/a`, []string{`-tags=tag2`}, "a.go c.go", "a.go"},
555 {`golang.org/fake/a`, []string{`-tags=tag tag2`}, "a.go b.go c.go d.go", "a.go b.go"},
556 } {
557 exported.Config.Mode = packages.LoadImports
558 exported.Config.BuildFlags = test.tags
559
560 initial, err := packages.Load(exported.Config, test.pattern)
561 if err != nil {
562 t.Error(err)
563 continue
564 }
565 if len(initial) != 1 {
566 t.Errorf("test tags %v: pattern %s, expected 1 package, got %d packages.", test.tags, test.pattern, len(initial))
567 continue
568 }
569 pkg := initial[0]
570 if srcs := strings.Join(srcs(pkg), " "); srcs != test.wantSrcs {
571 t.Errorf("test tags %v: srcs of package %s = [%s], want [%s]", test.tags, test.pattern, srcs, test.wantSrcs)
572 }
573 for path, ipkg := range pkg.Imports {
574 if srcs := strings.Join(srcs(ipkg), " "); srcs != test.wantImportSrcs {
575 t.Errorf("build tags %v: srcs of imported package %s = [%s], want [%s]", test.tags, path, srcs, test.wantImportSrcs)
576 }
577 }
578
579 }
580 }
581
582 func TestLoadTypes(t *testing.T) { testAllOrModulesParallel(t, testLoadTypes) }
583 func testLoadTypes(t *testing.T, exporter packagestest.Exporter) {
584
585
586
587
588
589 exported := packagestest.Export(t, exporter, []packagestest.Module{{
590 Name: "golang.org/fake",
591 Files: map[string]interface{}{
592 "a/a.go": `package a; import "golang.org/fake/b"; import "golang.org/fake/c"; const A = "a" + b.B + c.C`,
593 "b/b.go": `package b; const B = "b"`,
594 "c/c.go": `package c; const C = "c" + 1`,
595 }}})
596 defer exported.Cleanup()
597
598 exported.Config.Mode = packages.LoadTypes
599 initial, err := packages.Load(exported.Config, "golang.org/fake/a")
600 if err != nil {
601 t.Fatal(err)
602 }
603
604 graph, all := importGraph(initial)
605 wantGraph := `
606 * golang.org/fake/a
607 golang.org/fake/b
608 golang.org/fake/c
609 golang.org/fake/a -> golang.org/fake/b
610 golang.org/fake/a -> golang.org/fake/c
611 `[1:]
612 if graph != wantGraph {
613 t.Errorf("wrong import graph: got <<%s>>, want <<%s>>", graph, wantGraph)
614 }
615
616 for _, id := range []string{
617 "golang.org/fake/a",
618 "golang.org/fake/b",
619 "golang.org/fake/c",
620 } {
621 p := all[id]
622 if p == nil {
623 t.Errorf("missing package: %s", id)
624 continue
625 }
626 if p.Types == nil {
627 t.Errorf("missing types.Package for %s", p)
628 continue
629 } else if !p.Types.Complete() {
630 t.Errorf("incomplete types.Package for %s", p)
631 } else if p.TypesSizes == nil {
632 t.Errorf("TypesSizes is not filled in for %s", p)
633 }
634
635 }
636 }
637
638
639
640 func TestLoadTypesBits(t *testing.T) { testAllOrModulesParallel(t, testLoadTypesBits) }
641 func testLoadTypesBits(t *testing.T, exporter packagestest.Exporter) {
642 exported := packagestest.Export(t, exporter, []packagestest.Module{{
643 Name: "golang.org/fake",
644 Files: map[string]interface{}{
645 "a/a.go": `package a; import "golang.org/fake/b"; const A = "a" + b.B`,
646 "b/b.go": `package b; import "golang.org/fake/c"; const B = "b" + c.C`,
647 "c/c.go": `package c; import "golang.org/fake/d"; const C = "c" + d.D`,
648 "d/d.go": `package d; import "golang.org/fake/e"; const D = "d" + e.E`,
649 "e/e.go": `package e; import "golang.org/fake/f"; const E = "e" + f.F`,
650 "f/f.go": `package f; const F = "f"`,
651 }}})
652 defer exported.Cleanup()
653
654 exported.Config.Mode = packages.NeedTypes | packages.NeedImports
655 initial, err := packages.Load(exported.Config, "golang.org/fake/a", "golang.org/fake/c")
656 if err != nil {
657 t.Fatal(err)
658 }
659
660 graph, all := importGraph(initial)
661 wantGraph := `
662 * golang.org/fake/a
663 golang.org/fake/b
664 * golang.org/fake/c
665 golang.org/fake/d
666 golang.org/fake/e
667 golang.org/fake/f
668 golang.org/fake/a -> golang.org/fake/b
669 golang.org/fake/b -> golang.org/fake/c
670 golang.org/fake/c -> golang.org/fake/d
671 golang.org/fake/d -> golang.org/fake/e
672 golang.org/fake/e -> golang.org/fake/f
673 `[1:]
674 if graph != wantGraph {
675 t.Errorf("wrong import graph: got <<%s>>, want <<%s>>", graph, wantGraph)
676 }
677
678 for _, test := range []struct {
679 id string
680 }{
681 {"golang.org/fake/a"},
682 {"golang.org/fake/b"},
683 {"golang.org/fake/c"},
684 {"golang.org/fake/d"},
685 {"golang.org/fake/e"},
686 {"golang.org/fake/f"},
687 } {
688 p := all[test.id]
689 if p == nil {
690 t.Errorf("missing package: %s", test.id)
691 continue
692 }
693 if p.Types == nil {
694 t.Errorf("missing types.Package for %s", p)
695 continue
696 }
697
698 if p.Syntax != nil {
699 t.Errorf("Syntax unexpectedly provided for %s", p)
700 }
701 if p.Errors != nil {
702 t.Errorf("errors in package: %s: %s", p, p.Errors)
703 }
704 }
705
706
707 aA := constant(all["golang.org/fake/a"], "A")
708 if aA == nil {
709 t.Fatalf("a.A: got nil")
710 }
711 if got, want := fmt.Sprintf("%v %v", aA, aA.Val()), `const golang.org/fake/a.A untyped string "abcdef"`; got != want {
712 t.Errorf("a.A: got %s, want %s", got, want)
713 }
714 }
715
716 func TestLoadSyntaxOK(t *testing.T) { testAllOrModulesParallel(t, testLoadSyntaxOK) }
717 func testLoadSyntaxOK(t *testing.T, exporter packagestest.Exporter) {
718 exported := packagestest.Export(t, exporter, []packagestest.Module{{
719 Name: "golang.org/fake",
720 Files: map[string]interface{}{
721 "a/a.go": `package a; import "golang.org/fake/b"; const A = "a" + b.B`,
722 "b/b.go": `package b; import "golang.org/fake/c"; const B = "b" + c.C`,
723 "c/c.go": `package c; import "golang.org/fake/d"; const C = "c" + d.D`,
724 "d/d.go": `package d; import "golang.org/fake/e"; const D = "d" + e.E`,
725 "e/e.go": `package e; import "golang.org/fake/f"; const E = "e" + f.F`,
726 "f/f.go": `package f; const F = "f"`,
727 }}})
728 defer exported.Cleanup()
729
730 exported.Config.Mode = packages.LoadSyntax
731 initial, err := packages.Load(exported.Config, "golang.org/fake/a", "golang.org/fake/c")
732 if err != nil {
733 t.Fatal(err)
734 }
735
736 graph, all := importGraph(initial)
737 wantGraph := `
738 * golang.org/fake/a
739 golang.org/fake/b
740 * golang.org/fake/c
741 golang.org/fake/d
742 golang.org/fake/e
743 golang.org/fake/f
744 golang.org/fake/a -> golang.org/fake/b
745 golang.org/fake/b -> golang.org/fake/c
746 golang.org/fake/c -> golang.org/fake/d
747 golang.org/fake/d -> golang.org/fake/e
748 golang.org/fake/e -> golang.org/fake/f
749 `[1:]
750 if graph != wantGraph {
751 t.Errorf("wrong import graph: got <<%s>>, want <<%s>>", graph, wantGraph)
752 }
753
754 for _, test := range []struct {
755 id string
756 wantSyntax bool
757 wantComplete bool
758 }{
759 {"golang.org/fake/a", true, true},
760 {"golang.org/fake/b", true, true},
761 {"golang.org/fake/c", true, true},
762 {"golang.org/fake/d", false, true},
763 {"golang.org/fake/e", false, false},
764 {"golang.org/fake/f", false, false},
765 } {
766
767
768
769 p := all[test.id]
770 if p == nil {
771 t.Errorf("missing package: %s", test.id)
772 continue
773 }
774 if p.Types == nil {
775 t.Errorf("missing types.Package for %s", p)
776 continue
777 } else if p.Types.Complete() != test.wantComplete {
778 if test.wantComplete {
779 t.Errorf("incomplete types.Package for %s", p)
780 } else {
781 t.Errorf("unexpected complete types.Package for %s", p)
782 }
783 }
784 if (p.Syntax != nil) != test.wantSyntax {
785 if test.wantSyntax {
786 t.Errorf("missing ast.Files for %s", p)
787 } else {
788 t.Errorf("unexpected ast.Files for for %s", p)
789 }
790 }
791 if p.Errors != nil {
792 t.Errorf("errors in package: %s: %s", p, p.Errors)
793 }
794 }
795
796
797 aA := constant(all["golang.org/fake/a"], "A")
798 if aA == nil {
799 t.Fatalf("a.A: got nil")
800 }
801 if got, want := fmt.Sprintf("%v %v", aA, aA.Val()), `const golang.org/fake/a.A untyped string "abcdef"`; got != want {
802 t.Errorf("a.A: got %s, want %s", got, want)
803 }
804 }
805
806 func TestLoadDiamondTypes(t *testing.T) { testAllOrModulesParallel(t, testLoadDiamondTypes) }
807 func testLoadDiamondTypes(t *testing.T, exporter packagestest.Exporter) {
808
809 exported := packagestest.Export(t, exporter, []packagestest.Module{{
810 Name: "golang.org/fake",
811 Files: map[string]interface{}{
812 "a/a.go": `package a; import ("golang.org/fake/b"; "golang.org/fake/c"); var _ = b.B == c.C`,
813 "b/b.go": `package b; import "golang.org/fake/d"; var B d.D`,
814 "c/c.go": `package c; import "golang.org/fake/d"; var C d.D`,
815 "d/d.go": `package d; type D int`,
816 }}})
817 defer exported.Cleanup()
818
819 exported.Config.Mode = packages.LoadSyntax
820 initial, err := packages.Load(exported.Config, "golang.org/fake/a")
821 if err != nil {
822 t.Fatal(err)
823 }
824 packages.Visit(initial, nil, func(pkg *packages.Package) {
825 for _, err := range pkg.Errors {
826 t.Errorf("package %s: %v", pkg.ID, err)
827 }
828 })
829
830 graph, _ := importGraph(initial)
831 wantGraph := `
832 * golang.org/fake/a
833 golang.org/fake/b
834 golang.org/fake/c
835 golang.org/fake/d
836 golang.org/fake/a -> golang.org/fake/b
837 golang.org/fake/a -> golang.org/fake/c
838 golang.org/fake/b -> golang.org/fake/d
839 golang.org/fake/c -> golang.org/fake/d
840 `[1:]
841 if graph != wantGraph {
842 t.Errorf("wrong import graph: got <<%s>>, want <<%s>>", graph, wantGraph)
843 }
844 }
845
846 func TestLoadSyntaxError(t *testing.T) { testAllOrModulesParallel(t, testLoadSyntaxError) }
847 func testLoadSyntaxError(t *testing.T, exporter packagestest.Exporter) {
848
849
850
851
852 exported := packagestest.Export(t, exporter, []packagestest.Module{{
853 Name: "golang.org/fake",
854 Files: map[string]interface{}{
855 "a/a.go": `package a; import "golang.org/fake/b"; const A = "a" + b.B`,
856 "b/b.go": `package b; import "golang.org/fake/c"; const B = "b" + c.C`,
857 "c/c.go": `package c; import "golang.org/fake/d"; const C = "c" + d.D`,
858 "d/d.go": `package d; import "golang.org/fake/e"; const D = "d" + e.E`,
859 "e/e.go": `package e; import "golang.org/fake/f"; const E = "e" + f.F + 1`,
860 "f/f.go": `package f; const F = "f"`,
861 }}})
862 defer exported.Cleanup()
863
864 exported.Config.Mode = packages.LoadSyntax
865 initial, err := packages.Load(exported.Config, "golang.org/fake/a", "golang.org/fake/c")
866 if err != nil {
867 t.Fatal(err)
868 }
869
870 all := make(map[string]*packages.Package)
871 packages.Visit(initial, nil, func(p *packages.Package) {
872 all[p.ID] = p
873 })
874
875 for _, test := range []struct {
876 id string
877 wantSyntax bool
878 wantIllTyped bool
879 }{
880 {"golang.org/fake/a", true, true},
881 {"golang.org/fake/b", true, true},
882 {"golang.org/fake/c", true, true},
883 {"golang.org/fake/d", true, true},
884 {"golang.org/fake/e", true, true},
885 {"golang.org/fake/f", false, false},
886 } {
887 p := all[test.id]
888 if p == nil {
889 t.Errorf("missing package: %s", test.id)
890 continue
891 }
892 if p.Types == nil {
893 t.Errorf("missing types.Package for %s", p)
894 continue
895 } else if !p.Types.Complete() {
896 t.Errorf("incomplete types.Package for %s", p)
897 }
898 if (p.Syntax != nil) != test.wantSyntax {
899 if test.wantSyntax {
900 t.Errorf("missing ast.Files for %s", test.id)
901 } else {
902 t.Errorf("unexpected ast.Files for for %s", test.id)
903 }
904 }
905 if p.IllTyped != test.wantIllTyped {
906 t.Errorf("IllTyped was %t for %s", p.IllTyped, test.id)
907 }
908 }
909
910
911 aA := constant(all["golang.org/fake/a"], "A")
912 if aA == nil {
913 t.Fatalf("a.A: got nil")
914 }
915 if got, want := aA.String(), `const golang.org/fake/a.A invalid type`; got != want {
916 t.Errorf("a.A: got %s, want %s", got, want)
917 }
918 }
919
920
921
922 func TestParseFileModifyAST(t *testing.T) { testAllOrModulesParallel(t, testParseFileModifyAST) }
923 func testParseFileModifyAST(t *testing.T, exporter packagestest.Exporter) {
924 exported := packagestest.Export(t, exporter, []packagestest.Module{{
925 Name: "golang.org/fake",
926 Files: map[string]interface{}{
927 "a/a.go": `package a; const A = "a" `,
928 }}})
929 defer exported.Cleanup()
930
931 exported.Config.Mode = packages.LoadAllSyntax
932 exported.Config.ParseFile = func(fset *token.FileSet, filename string, src []byte) (*ast.File, error) {
933 const mode = parser.AllErrors | parser.ParseComments
934 f, err := parser.ParseFile(fset, filename, src, mode)
935
936 spec := f.Decls[0].(*ast.GenDecl).Specs[0].(*ast.ValueSpec)
937 spec.Values[0].(*ast.BasicLit).Value = `"b"`
938 return f, err
939 }
940 initial, err := packages.Load(exported.Config, "golang.org/fake/a")
941 if err != nil {
942 t.Error(err)
943 }
944
945
946 a := initial[0]
947 got := constant(a, "A").Val().String()
948 if got != `"b"` {
949 t.Errorf("a.A: got %s, want %s", got, `"b"`)
950 }
951 }
952
953 func TestAdHocPackagesBadImport(t *testing.T) {
954 t.Parallel()
955 testenv.NeedsTool(t, "go")
956
957
958
959 tmp, err := os.MkdirTemp("", "a")
960 if err != nil {
961 t.Fatal(err)
962 }
963 defer os.RemoveAll(tmp)
964
965 filename := filepath.Join(tmp, "a.go")
966 content := []byte(`package a
967 import _ "badimport"
968 const A = 1
969 `)
970 if err := os.WriteFile(filename, content, 0775); err != nil {
971 t.Fatal(err)
972 }
973
974
975 for _, go111module := range []string{"off", "auto", "on"} {
976 config := &packages.Config{
977 Env: append(os.Environ(), "GOPACKAGESDRIVER=off", fmt.Sprintf("GO111MODULE=%s", go111module)),
978 Dir: tmp,
979 Mode: packages.LoadAllSyntax,
980 Logf: t.Logf,
981 }
982 initial, err := packages.Load(config, fmt.Sprintf("file=%s", filename))
983 if err != nil {
984 t.Error(err)
985 }
986 if len(initial) == 0 {
987 t.Fatalf("no packages for %s with GO111MODULE=%s", filename, go111module)
988 }
989
990 a := initial[0]
991
992 aA := constant(a, "A")
993 if aA == nil {
994 t.Errorf("a.A: got nil")
995 return
996 }
997 got := aA.Val().String()
998 if want := "1"; got != want {
999 t.Errorf("a.A: got %s, want %s", got, want)
1000 }
1001 }
1002 }
1003
1004 func TestLoadAllSyntaxImportErrors(t *testing.T) {
1005 testAllOrModulesParallel(t, testLoadAllSyntaxImportErrors)
1006 }
1007 func testLoadAllSyntaxImportErrors(t *testing.T, exporter packagestest.Exporter) {
1008
1009
1010 t.Skip("go list -compiled -e fails with non-zero exit status for empty packages")
1011
1012 exported := packagestest.Export(t, exporter, []packagestest.Module{{
1013 Name: "golang.org/fake",
1014 Files: map[string]interface{}{
1015 "unicycle/unicycle.go": `package unicycle; import _ "unicycle"`,
1016 "bicycle1/bicycle1.go": `package bicycle1; import _ "bicycle2"`,
1017 "bicycle2/bicycle2.go": `package bicycle2; import _ "bicycle1"`,
1018 "bad/bad.go": `not a package declaration`,
1019 "empty/README.txt": `not a go file`,
1020 "root/root.go": `package root
1021 import (
1022 _ "bicycle1"
1023 _ "unicycle"
1024 _ "nonesuch"
1025 _ "empty"
1026 _ "bad"
1027 )`,
1028 }}})
1029 defer exported.Cleanup()
1030
1031 exported.Config.Mode = packages.LoadAllSyntax
1032 initial, err := packages.Load(exported.Config, "root")
1033 if err != nil {
1034 t.Fatal(err)
1035 }
1036
1037
1038
1039
1040 graph, all := importGraph(initial)
1041 wantGraph := `
1042 bicycle1
1043 bicycle2
1044 * root
1045 unicycle
1046 bicycle1 -> bicycle2
1047 root -> bicycle1
1048 root -> unicycle
1049 `[1:]
1050 if graph != wantGraph {
1051 t.Errorf("wrong import graph: got <<%s>>, want <<%s>>", graph, wantGraph)
1052 }
1053 for _, test := range []struct {
1054 id string
1055 wantErrs []string
1056 }{
1057 {"bicycle1", nil},
1058 {"bicycle2", []string{
1059 "could not import bicycle1 (import cycle: [root bicycle1 bicycle2])",
1060 }},
1061 {"unicycle", []string{
1062 "could not import unicycle (import cycle: [root unicycle])",
1063 }},
1064 {"root", []string{
1065 `could not import bad (missing package: "bad")`,
1066 `could not import empty (missing package: "empty")`,
1067 `could not import nonesuch (missing package: "nonesuch")`,
1068 }},
1069 } {
1070 p := all[test.id]
1071 if p == nil {
1072 t.Errorf("missing package: %s", test.id)
1073 continue
1074 }
1075 if p.Types == nil {
1076 t.Errorf("missing types.Package for %s", test.id)
1077 }
1078 if p.Syntax == nil {
1079 t.Errorf("missing ast.Files for %s", test.id)
1080 }
1081 if !p.IllTyped {
1082 t.Errorf("IllTyped was false for %s", test.id)
1083 }
1084 if errs := errorMessages(p.Errors); !reflect.DeepEqual(errs, test.wantErrs) {
1085 t.Errorf("in package %s, got errors %s, want %s", p, errs, test.wantErrs)
1086 }
1087 }
1088 }
1089
1090 func TestAbsoluteFilenames(t *testing.T) { testAllOrModulesParallel(t, testAbsoluteFilenames) }
1091 func testAbsoluteFilenames(t *testing.T, exporter packagestest.Exporter) {
1092 exported := packagestest.Export(t, exporter, []packagestest.Module{{
1093 Name: "golang.org/fake",
1094 Files: map[string]interface{}{
1095 "a/a.go": `package a; const A = 1`,
1096 "b/b.go": `package b; import ("golang.org/fake/a"; _ "errors"); var B = a.A`,
1097 "b/vendor/a/a.go": `package a; const A = 1`,
1098 "c/c.go": `package c; import (_ "golang.org/fake/b"; _ "unsafe")`,
1099 "c/c2.go": "// +build ignore\n\n" + `package c; import _ "fmt"`,
1100 "subdir/d/d.go": `package d`,
1101 "subdir/e/d.go": `package e`,
1102 "e/e.go": `package main; import _ "golang.org/fake/b"`,
1103 "e/e2.go": `package main; import _ "golang.org/fake/c"`,
1104 "f/f.go": `package f`,
1105 "f/f.s": ``,
1106 "g/g.go": `package g; import _ "embed";` + "\n//go:embed g2.txt\n" + `var s string`,
1107 "g/g2.txt": "hello",
1108 "h/h.go": `package g; import _ "embed";` + "\n//go:embed a*.txt\n" + `var s string`,
1109 "h/aa.txt": "hello",
1110 }}})
1111 defer exported.Cleanup()
1112 exported.Config.Dir = filepath.Dir(filepath.Dir(exported.File("golang.org/fake", "a/a.go")))
1113
1114 checkFile := func(filename string) {
1115 if !filepath.IsAbs(filename) {
1116 t.Errorf("filename is not absolute: %s", filename)
1117 }
1118 if _, err := os.Stat(filename); err != nil {
1119 t.Errorf("stat error, %s: %v", filename, err)
1120 }
1121 }
1122
1123 for _, test := range []struct {
1124 pattern string
1125 want string
1126 }{
1127
1128 {"golang.org/fake/a", "a.go"},
1129 {"golang.org/fake/b/vendor/a", "a.go"},
1130 {"golang.org/fake/b", "b.go"},
1131 {"golang.org/fake/c", "c.go"},
1132 {"golang.org/fake/subdir/d", "d.go"},
1133 {"golang.org/fake/subdir/e", "d.go"},
1134 {"golang.org/fake/e", "e.go e2.go"},
1135 {"golang.org/fake/f", "f.go f.s"},
1136 {"golang.org/fake/g", "g.go g2.txt"},
1137 {"golang.org/fake/h", "h.go aa.txt"},
1138
1139 {"./a", "a.go"},
1140 {"./b/vendor/a", "a.go"},
1141 {"./b", "b.go"},
1142 {"./c", "c.go"},
1143 {"./subdir/d", "d.go"},
1144 {"./subdir/e", "d.go"},
1145 {"./e", "e.go e2.go"},
1146 {"./f", "f.go f.s"},
1147 {"./g", "g.go g2.txt"},
1148 {"./h", "h.go aa.txt"},
1149 } {
1150 exported.Config.Mode = packages.LoadFiles | packages.NeedEmbedFiles
1151 pkgs, err := packages.Load(exported.Config, test.pattern)
1152 if err != nil {
1153 t.Errorf("pattern %s: %v", test.pattern, err)
1154 continue
1155 }
1156
1157 if got := strings.Join(srcs(pkgs[0]), " "); got != test.want {
1158 t.Errorf("in package %s, got %s, want %s", test.pattern, got, test.want)
1159 }
1160
1161
1162 _, all := importGraph(pkgs)
1163 for _, pkg := range all {
1164 for _, filename := range pkg.GoFiles {
1165 checkFile(filename)
1166 }
1167 for _, filename := range pkg.OtherFiles {
1168 checkFile(filename)
1169 }
1170 for _, filename := range pkg.EmbedFiles {
1171 checkFile(filename)
1172 }
1173 for _, filename := range pkg.IgnoredFiles {
1174 checkFile(filename)
1175 }
1176 }
1177 }
1178 }
1179
1180 func TestContains(t *testing.T) { testAllOrModulesParallel(t, testContains) }
1181 func testContains(t *testing.T, exporter packagestest.Exporter) {
1182 exported := packagestest.Export(t, exporter, []packagestest.Module{{
1183 Name: "golang.org/fake",
1184 Files: map[string]interface{}{
1185 "a/a.go": `package a; import "golang.org/fake/b"`,
1186 "b/b.go": `package b; import "golang.org/fake/c"`,
1187 "c/c.go": `package c`,
1188 }}})
1189 defer exported.Cleanup()
1190 bFile := exported.File("golang.org/fake", "b/b.go")
1191 exported.Config.Mode = packages.LoadImports
1192 initial, err := packages.Load(exported.Config, "file="+bFile)
1193 if err != nil {
1194 t.Fatal(err)
1195 }
1196
1197 graph, _ := importGraph(initial)
1198 wantGraph := `
1199 * golang.org/fake/b
1200 golang.org/fake/c
1201 golang.org/fake/b -> golang.org/fake/c
1202 `[1:]
1203 if graph != wantGraph {
1204 t.Errorf("wrong import graph: got <<%s>>, want <<%s>>", graph, wantGraph)
1205 }
1206 }
1207
1208
1209
1210
1211
1212 func TestSizes(t *testing.T) { testAllOrModulesParallel(t, testSizes) }
1213 func testSizes(t *testing.T, exporter packagestest.Exporter) {
1214
1215 switch runtime.GOOS {
1216 case "linux", "windows", "freebsd", "openbsd", "netbsd", "android":
1217 default:
1218 t.Skipf("skipping test on %s", runtime.GOOS)
1219 }
1220
1221 exported := packagestest.Export(t, exporter, []packagestest.Module{{
1222 Name: "golang.org/fake",
1223 Files: map[string]interface{}{
1224 "a/a.go": `package a; import "unsafe"; const WordSize = 8*unsafe.Sizeof(int(0))`,
1225 }}})
1226 defer exported.Cleanup()
1227
1228 exported.Config.Mode = packages.LoadSyntax
1229 savedEnv := exported.Config.Env
1230 for arch, wantWordSize := range map[string]int64{"386": 32, "amd64": 64} {
1231 exported.Config.Env = append(savedEnv, "GOARCH="+arch)
1232 initial, err := packages.Load(exported.Config, "golang.org/fake/a")
1233 if err != nil {
1234 t.Fatal(err)
1235 }
1236 if packages.PrintErrors(initial) > 0 {
1237 t.Fatal("there were errors")
1238 }
1239 gotWordSize, _ := constantpkg.Int64Val(constant(initial[0], "WordSize").Val())
1240 if gotWordSize != wantWordSize {
1241 t.Errorf("for GOARCH=%s, got word size %d, want %d", arch, gotWordSize, wantWordSize)
1242 }
1243 }
1244 }
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257 func TestNeedTypeSizesWithBadGOARCH(t *testing.T) {
1258 testAllOrModulesParallel(t, func(t *testing.T, exporter packagestest.Exporter) {
1259 exported := packagestest.Export(t, exporter, []packagestest.Module{{
1260 Name: "testdata",
1261 Files: map[string]interface{}{"a/a.go": `package a`}}})
1262 defer exported.Cleanup()
1263
1264 exported.Config.Mode = packages.NeedTypesSizes
1265 exported.Config.Env = append(exported.Config.Env, "GOARCH=286")
1266 _, err := packages.Load(exported.Config, "file=./a/a.go")
1267 got := fmt.Sprint(err)
1268 want := "can't determine type sizes"
1269 if !strings.Contains(got, want) {
1270 t.Errorf("Load error %q does not contain substring %q", got, want)
1271 }
1272 })
1273 }
1274
1275
1276
1277
1278 func TestContainsFallbackSticks(t *testing.T) {
1279 testAllOrModulesParallel(t, testContainsFallbackSticks)
1280 }
1281 func testContainsFallbackSticks(t *testing.T, exporter packagestest.Exporter) {
1282 exported := packagestest.Export(t, exporter, []packagestest.Module{{
1283 Name: "golang.org/fake",
1284 Files: map[string]interface{}{
1285 "a/a.go": `package a; import "golang.org/fake/b"`,
1286 "b/b.go": `package b; import "golang.org/fake/c"`,
1287 "c/c.go": `package c`,
1288 }}})
1289 defer exported.Cleanup()
1290
1291 exported.Config.Mode = packages.LoadImports
1292 bFile := exported.File("golang.org/fake", "b/b.go")
1293 initial, err := packages.Load(exported.Config, "golang.org/fake/a", "file="+bFile)
1294 if err != nil {
1295 t.Fatal(err)
1296 }
1297
1298 graph, _ := importGraph(initial)
1299 wantGraph := `
1300 * golang.org/fake/a
1301 * golang.org/fake/b
1302 golang.org/fake/c
1303 golang.org/fake/a -> golang.org/fake/b
1304 golang.org/fake/b -> golang.org/fake/c
1305 `[1:]
1306 if graph != wantGraph {
1307 t.Errorf("wrong import graph: got <<%s>>, want <<%s>>", graph, wantGraph)
1308 }
1309 }
1310
1311
1312
1313 func TestNoPatterns(t *testing.T) { testAllOrModulesParallel(t, testNoPatterns) }
1314 func testNoPatterns(t *testing.T, exporter packagestest.Exporter) {
1315 exported := packagestest.Export(t, exporter, []packagestest.Module{{
1316 Name: "golang.org/fake",
1317 Files: map[string]interface{}{
1318 "a/a.go": `package a;`,
1319 "a/b/b.go": `package b;`,
1320 }}})
1321 defer exported.Cleanup()
1322
1323 aDir := filepath.Dir(exported.File("golang.org/fake", "a/a.go"))
1324 exported.Config.Dir = aDir
1325
1326 initial, err := packages.Load(exported.Config)
1327 if err != nil {
1328 t.Fatal(err)
1329 }
1330 if len(initial) != 1 || initial[0].Name != "a" {
1331 t.Fatalf(`Load() = %v, wanted just the package in the current directory`, initial)
1332 }
1333 }
1334
1335 func TestJSON(t *testing.T) { testAllOrModulesParallel(t, testJSON) }
1336 func testJSON(t *testing.T, exporter packagestest.Exporter) {
1337
1338 exported := packagestest.Export(t, exporter, []packagestest.Module{{
1339 Name: "golang.org/fake",
1340 Files: map[string]interface{}{
1341 "a/a.go": `package a; const A = 1`,
1342 "b/b.go": `package b; import "golang.org/fake/a"; var B = a.A`,
1343 "c/c.go": `package c; import "golang.org/fake/b" ; var C = b.B`,
1344 "d/d.go": `package d; import "golang.org/fake/b" ; var D = b.B`,
1345 }}})
1346 defer exported.Cleanup()
1347
1348 exported.Config.Mode = packages.LoadImports
1349 initial, err := packages.Load(exported.Config, "golang.org/fake/c", "golang.org/fake/d")
1350 if err != nil {
1351 t.Fatal(err)
1352 }
1353
1354
1355 buf := &bytes.Buffer{}
1356 enc := json.NewEncoder(buf)
1357 enc.SetIndent("", "\t")
1358 packages.Visit(initial, nil, func(pkg *packages.Package) {
1359
1360 pkg.GoFiles = cleanPaths(pkg.GoFiles)
1361 pkg.CompiledGoFiles = cleanPaths(pkg.CompiledGoFiles)
1362 pkg.OtherFiles = cleanPaths(pkg.OtherFiles)
1363 pkg.IgnoredFiles = cleanPaths(pkg.IgnoredFiles)
1364 if err := enc.Encode(pkg); err != nil {
1365 t.Fatal(err)
1366 }
1367 })
1368
1369 wantJSON := `
1370 {
1371 "ID": "golang.org/fake/a",
1372 "Name": "a",
1373 "PkgPath": "golang.org/fake/a",
1374 "GoFiles": [
1375 "a.go"
1376 ],
1377 "CompiledGoFiles": [
1378 "a.go"
1379 ]
1380 }
1381 {
1382 "ID": "golang.org/fake/b",
1383 "Name": "b",
1384 "PkgPath": "golang.org/fake/b",
1385 "GoFiles": [
1386 "b.go"
1387 ],
1388 "CompiledGoFiles": [
1389 "b.go"
1390 ],
1391 "Imports": {
1392 "golang.org/fake/a": "golang.org/fake/a"
1393 }
1394 }
1395 {
1396 "ID": "golang.org/fake/c",
1397 "Name": "c",
1398 "PkgPath": "golang.org/fake/c",
1399 "GoFiles": [
1400 "c.go"
1401 ],
1402 "CompiledGoFiles": [
1403 "c.go"
1404 ],
1405 "Imports": {
1406 "golang.org/fake/b": "golang.org/fake/b"
1407 }
1408 }
1409 {
1410 "ID": "golang.org/fake/d",
1411 "Name": "d",
1412 "PkgPath": "golang.org/fake/d",
1413 "GoFiles": [
1414 "d.go"
1415 ],
1416 "CompiledGoFiles": [
1417 "d.go"
1418 ],
1419 "Imports": {
1420 "golang.org/fake/b": "golang.org/fake/b"
1421 }
1422 }
1423 `[1:]
1424
1425 if buf.String() != wantJSON {
1426 t.Errorf("wrong JSON: got <<%s>>, want <<%s>>", buf.String(), wantJSON)
1427 }
1428
1429 var decoded []*packages.Package
1430 dec := json.NewDecoder(buf)
1431 for dec.More() {
1432 p := new(packages.Package)
1433 if err := dec.Decode(p); err != nil {
1434 t.Fatal(err)
1435 }
1436 decoded = append(decoded, p)
1437 }
1438 if len(decoded) != 4 {
1439 t.Fatalf("got %d packages, want 4", len(decoded))
1440 }
1441 for i, want := range []*packages.Package{{
1442 ID: "golang.org/fake/a",
1443 Name: "a",
1444 }, {
1445 ID: "golang.org/fake/b",
1446 Name: "b",
1447 Imports: map[string]*packages.Package{
1448 "golang.org/fake/a": {ID: "golang.org/fake/a"},
1449 },
1450 }, {
1451 ID: "golang.org/fake/c",
1452 Name: "c",
1453 Imports: map[string]*packages.Package{
1454 "golang.org/fake/b": {ID: "golang.org/fake/b"},
1455 },
1456 }, {
1457 ID: "golang.org/fake/d",
1458 Name: "d",
1459 Imports: map[string]*packages.Package{
1460 "golang.org/fake/b": {ID: "golang.org/fake/b"},
1461 },
1462 }} {
1463 got := decoded[i]
1464 if got.ID != want.ID {
1465 t.Errorf("Package %d has ID %q want %q", i, got.ID, want.ID)
1466 }
1467 if got.Name != want.Name {
1468 t.Errorf("Package %q has Name %q want %q", got.ID, got.Name, want.Name)
1469 }
1470 if len(got.Imports) != len(want.Imports) {
1471 t.Errorf("Package %q has %d imports want %d", got.ID, len(got.Imports), len(want.Imports))
1472 continue
1473 }
1474 for path, ipkg := range got.Imports {
1475 if want.Imports[path] == nil {
1476 t.Errorf("Package %q has unexpected import %q", got.ID, path)
1477 continue
1478 }
1479 if want.Imports[path].ID != ipkg.ID {
1480 t.Errorf("Package %q import %q is %q want %q", got.ID, path, ipkg.ID, want.Imports[path].ID)
1481 }
1482 }
1483 }
1484 }
1485
1486 func TestRejectInvalidQueries(t *testing.T) {
1487 t.Parallel()
1488
1489 queries := []string{"key=", "key=value"}
1490 cfg := &packages.Config{
1491 Mode: packages.LoadImports,
1492 Env: append(os.Environ(), "GO111MODULE=off", "GOPACKAGESDRIVER=off"),
1493 }
1494 for _, q := range queries {
1495 if _, err := packages.Load(cfg, q); err == nil {
1496 t.Errorf("packages.Load(%q) succeeded. Expected \"invalid query type\" error", q)
1497 } else if !strings.Contains(err.Error(), "invalid query type") {
1498 t.Errorf("packages.Load(%q): got error %v, want \"invalid query type\" error", q, err)
1499 }
1500 }
1501 }
1502
1503 func TestPatternPassthrough(t *testing.T) { testAllOrModulesParallel(t, testPatternPassthrough) }
1504 func testPatternPassthrough(t *testing.T, exporter packagestest.Exporter) {
1505 exported := packagestest.Export(t, exporter, []packagestest.Module{{
1506 Name: "golang.org/fake",
1507 Files: map[string]interface{}{
1508 "a/a.go": `package a;`,
1509 }}})
1510 defer exported.Cleanup()
1511
1512 initial, err := packages.Load(exported.Config, "pattern=a")
1513 if err != nil {
1514 t.Fatal(err)
1515 }
1516
1517 graph, _ := importGraph(initial)
1518 wantGraph := `
1519 * a
1520 `[1:]
1521 if graph != wantGraph {
1522 t.Errorf("wrong import graph: got <<%s>>, want <<%s>>", graph, wantGraph)
1523 }
1524
1525 }
1526
1527 func TestConfigDefaultEnv(t *testing.T) {
1528
1529
1530 packagestest.TestAll(t, testConfigDefaultEnv)
1531 }
1532 func testConfigDefaultEnv(t *testing.T, exporter packagestest.Exporter) {
1533 const driverJSON = `{
1534 "Roots": ["gopackagesdriver"],
1535 "Packages": [{"ID": "gopackagesdriver", "Name": "gopackagesdriver"}]
1536 }`
1537 var (
1538 pathKey string
1539 driverScript packagestest.Writer
1540 )
1541 switch runtime.GOOS {
1542 case "android":
1543 t.Skip("doesn't run on android")
1544 case "windows":
1545
1546
1547 t.Skip("test requires sh")
1548 case "plan9":
1549 pathKey = "path"
1550 driverScript = packagestest.Script(`#!/bin/rc
1551
1552 cat <<'EOF'
1553 ` + driverJSON + `
1554 EOF
1555 `)
1556 default:
1557 pathKey = "PATH"
1558 driverScript = packagestest.Script(`#!/bin/sh
1559
1560 cat - <<'EOF'
1561 ` + driverJSON + `
1562 EOF
1563 `)
1564 }
1565 exported := packagestest.Export(t, exporter, []packagestest.Module{{
1566 Name: "golang.org/fake",
1567 Files: map[string]interface{}{
1568 "bin/gopackagesdriver": driverScript,
1569 "golist/golist.go": "package golist",
1570 }}})
1571 defer exported.Cleanup()
1572 driver := exported.File("golang.org/fake", "bin/gopackagesdriver")
1573 binDir := filepath.Dir(driver)
1574 if err := os.Chmod(driver, 0755); err != nil {
1575 t.Fatal(err)
1576 }
1577
1578 path, ok := os.LookupEnv(pathKey)
1579 var pathWithDriver string
1580 if ok {
1581 pathWithDriver = binDir + string(os.PathListSeparator) + path
1582 } else {
1583 pathWithDriver = binDir
1584 }
1585 for _, test := range []struct {
1586 desc string
1587 path string
1588 driver string
1589 wantIDs string
1590 }{
1591 {
1592 desc: "driver_off",
1593 path: pathWithDriver,
1594 driver: "off",
1595 wantIDs: "[golist]",
1596 }, {
1597 desc: "driver_unset",
1598 path: pathWithDriver,
1599 driver: "",
1600 wantIDs: "[gopackagesdriver]",
1601 }, {
1602 desc: "driver_set",
1603 path: "",
1604 driver: driver,
1605 wantIDs: "[gopackagesdriver]",
1606 },
1607 } {
1608 t.Run(test.desc, func(t *testing.T) {
1609 oldPath := os.Getenv(pathKey)
1610 os.Setenv(pathKey, test.path)
1611 defer os.Setenv(pathKey, oldPath)
1612
1613 config := exported.Config
1614 config.Env = append([]string{}, exported.Config.Env...)
1615 config.Env = append(config.Env, "GOPACKAGESDRIVER="+test.driver)
1616 pkgs, err := packages.Load(exported.Config, "golist")
1617 if err != nil {
1618 t.Fatal(err)
1619 }
1620
1621 gotIds := make([]string, len(pkgs))
1622 for i, pkg := range pkgs {
1623 gotIds[i] = pkg.ID
1624 }
1625 if fmt.Sprint(pkgs) != test.wantIDs {
1626 t.Errorf("got %v; want %v", gotIds, test.wantIDs)
1627 }
1628 })
1629 }
1630 }
1631
1632
1633
1634
1635
1636
1637
1638
1639 func TestBasicXTest(t *testing.T) { testAllOrModulesParallel(t, testBasicXTest) }
1640 func testBasicXTest(t *testing.T, exporter packagestest.Exporter) {
1641 exported := packagestest.Export(t, exporter, []packagestest.Module{{
1642 Name: "golang.org/fake",
1643 Files: map[string]interface{}{
1644 "a/a.go": `package a;`,
1645 "a/a_test.go": `package a_test;`,
1646 }}})
1647 defer exported.Cleanup()
1648
1649 exported.Config.Mode = packages.LoadFiles
1650 exported.Config.Tests = true
1651 _, err := packages.Load(exported.Config, "golang.org/fake/a")
1652 if err != nil {
1653 t.Fatal(err)
1654 }
1655 }
1656
1657 func TestErrorMissingFile(t *testing.T) { testAllOrModulesParallel(t, testErrorMissingFile) }
1658 func testErrorMissingFile(t *testing.T, exporter packagestest.Exporter) {
1659 exported := packagestest.Export(t, exporter, []packagestest.Module{{
1660 Name: "golang.org/fake",
1661 Files: map[string]interface{}{
1662 "a/a_test.go": `package a;`,
1663 }}})
1664 defer exported.Cleanup()
1665
1666 exported.Config.Mode = packages.LoadSyntax
1667 exported.Config.Tests = false
1668 pkgs, err := packages.Load(exported.Config, "missing.go")
1669 if err != nil {
1670 t.Fatal(err)
1671 }
1672 if len(pkgs) == 0 && runtime.GOOS == "windows" {
1673 t.Skip("Issue #31344: the ad-hoc command-line-arguments package isn't created on windows")
1674 }
1675 if len(pkgs) != 1 || (pkgs[0].PkgPath != "command-line-arguments" && pkgs[0].PkgPath != "missing.go") {
1676 t.Fatalf("packages.Load: want [command-line-arguments] or [missing.go], got %v", pkgs)
1677 }
1678 if len(pkgs[0].Errors) == 0 {
1679 t.Errorf("result of Load: want package with errors, got none: %+v", pkgs[0])
1680 }
1681 }
1682
1683 func TestReturnErrorWhenUsingNonGoFiles(t *testing.T) {
1684 testAllOrModulesParallel(t, testReturnErrorWhenUsingNonGoFiles)
1685 }
1686 func testReturnErrorWhenUsingNonGoFiles(t *testing.T, exporter packagestest.Exporter) {
1687 exported := packagestest.Export(t, exporter, []packagestest.Module{{
1688 Name: "golang.org/gopatha",
1689 Files: map[string]interface{}{
1690 "a/a.go": `package a`,
1691 }}, {
1692 Name: "golang.org/gopathb",
1693 Files: map[string]interface{}{
1694 "b/b.c": `package b`,
1695 }}})
1696 defer exported.Cleanup()
1697 config := packages.Config{Env: append(os.Environ(), "GOPACKAGESDRIVER=off")}
1698 pkgs, err := packages.Load(&config, "b/b.c")
1699 if err != nil {
1700 return
1701 }
1702
1703 if len(pkgs) != 1 || (pkgs[0].PkgPath != "command-line-arguments" && pkgs[0].PkgPath != "b/b.c") {
1704 t.Fatalf("packages.Load: want [command-line-arguments] or [b/b.c], got %v", pkgs)
1705 }
1706 if len(pkgs[0].Errors) != 1 {
1707 t.Fatalf("result of Load: want package with one error, got: %+v", pkgs[0])
1708 }
1709 }
1710
1711 func TestReturnErrorWhenUsingGoFilesInMultipleDirectories(t *testing.T) {
1712 testAllOrModulesParallel(t, testReturnErrorWhenUsingGoFilesInMultipleDirectories)
1713 }
1714 func testReturnErrorWhenUsingGoFilesInMultipleDirectories(t *testing.T, exporter packagestest.Exporter) {
1715 exported := packagestest.Export(t, exporter, []packagestest.Module{{
1716 Name: "golang.org/gopatha",
1717 Files: map[string]interface{}{
1718 "a/a.go": `package a`,
1719 "b/b.go": `package b`,
1720 }}})
1721 defer exported.Cleanup()
1722 want := "named files must all be in one directory"
1723 pkgs, err := packages.Load(exported.Config, exported.File("golang.org/gopatha", "a/a.go"), exported.File("golang.org/gopatha", "b/b.go"))
1724 if err != nil {
1725
1726 if !strings.Contains(err.Error(), want) {
1727 t.Fatalf("want error message: %s, got: %s", want, err.Error())
1728 }
1729 return
1730 }
1731 if len(pkgs) != 1 || pkgs[0].PkgPath != "command-line-arguments" {
1732 t.Fatalf("packages.Load: want [command-line-arguments], got %v", pkgs)
1733 }
1734 if len(pkgs[0].Errors) != 1 {
1735 t.Fatalf("result of Load: want package with one error, got: %+v", pkgs[0])
1736 }
1737 got := pkgs[0].Errors[0].Error()
1738 if !strings.Contains(got, want) {
1739 t.Fatalf("want error message: %s, got: %s", want, got)
1740 }
1741 }
1742
1743 func TestReturnErrorForUnexpectedDirectoryLayout(t *testing.T) {
1744 testAllOrModulesParallel(t, testReturnErrorForUnexpectedDirectoryLayout)
1745 }
1746 func testReturnErrorForUnexpectedDirectoryLayout(t *testing.T, exporter packagestest.Exporter) {
1747 exported := packagestest.Export(t, exporter, []packagestest.Module{{
1748 Name: "golang.org/gopatha",
1749 Files: map[string]interface{}{
1750 "a/testdata/a.go": `package a; import _ "b"`,
1751 "a/vendor/b/b.go": `package b; import _ "fmt"`,
1752 }}})
1753 defer exported.Cleanup()
1754 want := "unexpected directory layout"
1755
1756 exported.Config.Dir = filepath.Dir(exported.File("golang.org/gopatha", "a/testdata/a.go"))
1757 pkgs, err := packages.Load(exported.Config, ".")
1758
1759
1760
1761 if err == nil {
1762 if len(pkgs) == 0 {
1763
1764 t.Fatalf("want error, got nil")
1765 }
1766 return
1767 }
1768
1769 if !strings.Contains(err.Error(), want) {
1770 t.Fatalf("want error message: %s, got: %s", want, err.Error())
1771 }
1772 }
1773
1774 func TestMissingDependency(t *testing.T) { testAllOrModulesParallel(t, testMissingDependency) }
1775 func testMissingDependency(t *testing.T, exporter packagestest.Exporter) {
1776 exported := packagestest.Export(t, exporter, []packagestest.Module{{
1777 Name: "golang.org/fake",
1778 Files: map[string]interface{}{
1779 "a/a.go": `package a; import _ "this/package/doesnt/exist"`,
1780 }}})
1781 defer exported.Cleanup()
1782
1783 exported.Config.Mode = packages.LoadAllSyntax
1784 pkgs, err := packages.Load(exported.Config, "golang.org/fake/a")
1785 if err != nil {
1786 t.Fatal(err)
1787 }
1788 if len(pkgs) != 1 && pkgs[0].PkgPath != "golang.org/fake/a" {
1789 t.Fatalf("packages.Load: want [golang.org/fake/a], got %v", pkgs)
1790 }
1791 if len(pkgs[0].Errors) == 0 {
1792 t.Errorf("result of Load: want package with errors, got none: %+v", pkgs[0])
1793 }
1794 }
1795
1796 func TestAdHocContains(t *testing.T) { testAllOrModulesParallel(t, testAdHocContains) }
1797 func testAdHocContains(t *testing.T, exporter packagestest.Exporter) {
1798 exported := packagestest.Export(t, exporter, []packagestest.Module{{
1799 Name: "golang.org/fake",
1800 Files: map[string]interface{}{
1801 "a/a.go": `package a;`,
1802 }}})
1803 defer exported.Cleanup()
1804
1805 tmpfile, err := os.CreateTemp("", "adhoc*.go")
1806 filename := tmpfile.Name()
1807 if err != nil {
1808 t.Fatal(err)
1809 }
1810 fmt.Fprint(tmpfile, `package main; import "fmt"; func main() { fmt.Println("time for coffee") }`)
1811 if err := tmpfile.Close(); err != nil {
1812 t.Fatal(err)
1813 }
1814
1815 defer func() {
1816 if err := os.Remove(filename); err != nil {
1817 t.Fatal(err)
1818 }
1819 }()
1820
1821 exported.Config.Mode = packages.NeedImports | packages.NeedFiles
1822 pkgs, err := packages.Load(exported.Config, "file="+filename)
1823 if err != nil {
1824 t.Fatal(err)
1825 }
1826 if len(pkgs) != 1 && pkgs[0].PkgPath != "command-line-arguments" {
1827 t.Fatalf("packages.Load: want [command-line-arguments], got %v", pkgs)
1828 }
1829 pkg := pkgs[0]
1830 if _, ok := pkg.Imports["fmt"]; !ok || len(pkg.Imports) != 1 {
1831 t.Fatalf("Imports of loaded package: want [fmt], got %v", pkg.Imports)
1832 }
1833 if len(pkg.GoFiles) != 1 || pkg.GoFiles[0] != filename {
1834 t.Fatalf("GoFiles of loaded package: want [%s], got %v", filename, pkg.GoFiles)
1835 }
1836 }
1837
1838 func TestCgoNoCcompiler(t *testing.T) { testAllOrModulesParallel(t, testCgoNoCcompiler) }
1839 func testCgoNoCcompiler(t *testing.T, exporter packagestest.Exporter) {
1840 testenv.NeedsTool(t, "cgo")
1841 exported := packagestest.Export(t, exporter, []packagestest.Module{{
1842 Name: "golang.org/fake",
1843 Files: map[string]interface{}{
1844 "a/a.go": `package a
1845 import "net/http"
1846 const A = http.MethodGet
1847 `,
1848 }}})
1849 defer exported.Cleanup()
1850
1851
1852 exported.Config.Env = append(exported.Config.Env, "CGO_ENABLED=1", "CC=doesnotexist")
1853 exported.Config.Mode = packages.LoadAllSyntax
1854 initial, err := packages.Load(exported.Config, "golang.org/fake/a")
1855
1856 if err != nil {
1857 t.Fatal(err)
1858 }
1859
1860
1861 a := initial[0]
1862 aA := constant(a, "A")
1863 if aA == nil {
1864 t.Fatalf("a.A: got nil")
1865 }
1866 got := aA.Val().String()
1867 if got != "\"GET\"" {
1868 t.Errorf("a.A: got %s, want %s", got, "\"GET\"")
1869 }
1870 }
1871
1872 func TestCgoMissingFile(t *testing.T) { testAllOrModulesParallel(t, testCgoMissingFile) }
1873 func testCgoMissingFile(t *testing.T, exporter packagestest.Exporter) {
1874 testenv.NeedsTool(t, "cgo")
1875 exported := packagestest.Export(t, exporter, []packagestest.Module{{
1876 Name: "golang.org/fake",
1877 Files: map[string]interface{}{
1878 "a/a.go": `package a
1879
1880 // #include "foo.h"
1881 import "C"
1882
1883 const A = 4
1884 `,
1885 }}})
1886 defer exported.Cleanup()
1887
1888
1889 exported.Config.Env = append(exported.Config.Env, "CGO_ENABLED=1")
1890 exported.Config.Mode = packages.LoadAllSyntax
1891 initial, err := packages.Load(exported.Config, "golang.org/fake/a")
1892
1893 if err != nil {
1894 t.Fatal(err)
1895 }
1896
1897
1898 a := initial[0]
1899 aA := constant(a, "A")
1900 if aA == nil {
1901 t.Fatalf("a.A: got nil")
1902 }
1903 got := aA.Val().String()
1904 if got != "4" {
1905 t.Errorf("a.A: got %s, want %s", got, "4")
1906 }
1907 }
1908
1909 func TestLoadImportsC(t *testing.T) {
1910
1911
1912
1913
1914
1915
1916 if runtime.GOOS == "windows" {
1917 t.Skipf("skipping on windows; packages on windows do not satisfy conditions for test.")
1918 }
1919 if runtime.GOOS == "plan9" {
1920
1921 t.Skip(`skipping on plan9; for some reason "net [syscall.test]" is not loaded`)
1922 }
1923 t.Parallel()
1924 testenv.NeedsGoPackages(t)
1925
1926 cfg := &packages.Config{
1927 Context: testCtx,
1928 Mode: packages.LoadImports,
1929 Tests: true,
1930 }
1931 initial, err := packages.Load(cfg, "syscall", "net")
1932 if err != nil {
1933 t.Fatalf("failed to load imports: %v", err)
1934 }
1935
1936 _, all := importGraph(initial)
1937
1938 for _, test := range []struct {
1939 pattern string
1940 wantImport string
1941 }{
1942 {"net", "syscall:syscall"},
1943 {"net [syscall.test]", "syscall:syscall [syscall.test]"},
1944 {"syscall_test [syscall.test]", "net:net [syscall.test]"},
1945 } {
1946
1947 pkg := all[test.pattern]
1948 if pkg == nil {
1949 t.Errorf("package %q not loaded", test.pattern)
1950 continue
1951 }
1952 if imports := strings.Join(imports(pkg), " "); !strings.Contains(imports, test.wantImport) {
1953 t.Errorf("package %q: got \n%s, \nwant to have %s", test.pattern, imports, test.wantImport)
1954 }
1955 }
1956 }
1957
1958 func TestCgoNoSyntax(t *testing.T) {
1959 testAllOrModulesParallel(t, testCgoNoSyntax)
1960 }
1961 func testCgoNoSyntax(t *testing.T, exporter packagestest.Exporter) {
1962 testenv.NeedsTool(t, "cgo")
1963
1964 exported := packagestest.Export(t, exporter, []packagestest.Module{{
1965 Name: "golang.org/fake",
1966 Files: map[string]interface{}{
1967 "c/c.go": `package c; import "C"`,
1968 },
1969 }})
1970
1971
1972 exported.Config.Env = append(exported.Config.Env, "CGO_ENABLED=1")
1973
1974 modes := []packages.LoadMode{
1975 packages.NeedTypes,
1976 packages.NeedName | packages.NeedTypes,
1977 packages.NeedName | packages.NeedTypes | packages.NeedImports,
1978 packages.NeedName | packages.NeedTypes | packages.NeedImports | packages.NeedDeps,
1979 packages.NeedName | packages.NeedImports,
1980 }
1981 for _, mode := range modes {
1982 mode := mode
1983 t.Run(fmt.Sprint(mode), func(t *testing.T) {
1984 exported.Config.Mode = mode
1985 pkgs, err := packages.Load(exported.Config, "golang.org/fake/c")
1986 if err != nil {
1987 t.Fatal(err)
1988 }
1989 if len(pkgs) != 1 {
1990 t.Fatalf("Expected 1 package, got %v", pkgs)
1991 }
1992 pkg := pkgs[0]
1993 if len(pkg.Errors) != 0 {
1994 t.Fatalf("Expected no errors in package, got %v", pkg.Errors)
1995 }
1996 })
1997 }
1998 }
1999
2000 func TestCgoBadPkgConfig(t *testing.T) {
2001 testAllOrModulesParallel(t, testCgoBadPkgConfig)
2002 }
2003 func testCgoBadPkgConfig(t *testing.T, exporter packagestest.Exporter) {
2004 skipIfShort(t, "builds and links a fake pkgconfig binary")
2005 testenv.NeedsTool(t, "cgo")
2006
2007 exported := packagestest.Export(t, exporter, []packagestest.Module{{
2008 Name: "golang.org/fake",
2009 Files: map[string]interface{}{
2010 "c/c.go": `package c
2011
2012 // #cgo pkg-config: --cflags -- foo
2013 import "C"`,
2014 },
2015 }})
2016
2017 dir := buildFakePkgconfig(t, exported.Config.Env)
2018 defer os.RemoveAll(dir)
2019 env := exported.Config.Env
2020 for i, v := range env {
2021 if strings.HasPrefix(v, "PATH=") {
2022 env[i] = "PATH=" + dir + string(os.PathListSeparator) + v[len("PATH="):]
2023 }
2024 }
2025
2026 exported.Config.Env = append(exported.Config.Env, "CGO_ENABLED=1")
2027
2028 exported.Config.Mode = packages.NeedName | packages.NeedCompiledGoFiles
2029 pkgs, err := packages.Load(exported.Config, "golang.org/fake/c")
2030 if err != nil {
2031 t.Fatal(err)
2032 }
2033 if len(pkgs) != 1 {
2034 t.Fatalf("Expected 1 package, got %v", pkgs)
2035 }
2036 if pkgs[0].Name != "c" {
2037 t.Fatalf("Expected package to have name \"c\", got %q", pkgs[0].Name)
2038 }
2039 }
2040
2041 func buildFakePkgconfig(t *testing.T, env []string) string {
2042 tmpdir, err := os.MkdirTemp("", "fakepkgconfig")
2043 if err != nil {
2044 t.Fatal(err)
2045 }
2046 err = os.WriteFile(filepath.Join(tmpdir, "pkg-config.go"), []byte(`
2047 package main
2048
2049 import "fmt"
2050 import "os"
2051
2052 func main() {
2053 fmt.Fprintln(os.Stderr, "bad")
2054 os.Exit(2)
2055 }
2056 `), 0644)
2057 if err != nil {
2058 os.RemoveAll(tmpdir)
2059 t.Fatal(err)
2060 }
2061 cmd := exec.Command("go", "build", "-o", "pkg-config", "pkg-config.go")
2062 cmd.Dir = tmpdir
2063 cmd.Env = env
2064
2065 if b, err := cmd.CombinedOutput(); err != nil {
2066 os.RemoveAll(tmpdir)
2067 fmt.Println(os.Environ())
2068 t.Log(string(b))
2069 t.Fatal(err)
2070 }
2071 return tmpdir
2072 }
2073
2074 func TestIssue32814(t *testing.T) { testAllOrModulesParallel(t, testIssue32814) }
2075 func testIssue32814(t *testing.T, exporter packagestest.Exporter) {
2076 exported := packagestest.Export(t, exporter, []packagestest.Module{{
2077 Name: "golang.org/fake",
2078 Files: map[string]interface{}{}}})
2079 defer exported.Cleanup()
2080
2081 exported.Config.Mode = packages.NeedName | packages.NeedTypes | packages.NeedSyntax | packages.NeedTypesInfo | packages.NeedTypesSizes
2082 pkgs, err := packages.Load(exported.Config, "fmt")
2083
2084 if err != nil {
2085 t.Fatal(err)
2086 }
2087
2088 if len(pkgs) != 1 && pkgs[0].PkgPath != "fmt" {
2089 t.Fatalf("packages.Load: want [fmt], got %v", pkgs)
2090 }
2091 pkg := pkgs[0]
2092 if len(pkg.Errors) != 0 {
2093 t.Fatalf("Errors for fmt pkg: got %v, want none", pkg.Errors)
2094 }
2095 if !pkg.Types.Complete() {
2096 t.Fatalf("Types.Complete() for fmt pkg: got %v, want true", pkgs[0].Types.Complete())
2097
2098 }
2099 }
2100
2101 func TestLoadTypesInfoWithoutNeedDeps(t *testing.T) {
2102 testAllOrModulesParallel(t, testLoadTypesInfoWithoutNeedDeps)
2103 }
2104 func testLoadTypesInfoWithoutNeedDeps(t *testing.T, exporter packagestest.Exporter) {
2105 exported := packagestest.Export(t, exporter, []packagestest.Module{{
2106 Name: "golang.org/fake",
2107 Files: map[string]interface{}{
2108 "a/a.go": `package a; import _ "golang.org/fake/b"`,
2109 "b/b.go": `package b`,
2110 }}})
2111 defer exported.Cleanup()
2112
2113 exported.Config.Mode = packages.NeedTypes | packages.NeedTypesInfo | packages.NeedImports
2114 pkgs, err := packages.Load(exported.Config, "golang.org/fake/a")
2115 if err != nil {
2116 t.Fatal(err)
2117 }
2118 pkg := pkgs[0]
2119 if pkg.IllTyped {
2120 t.Fatal("Loaded package is ill typed")
2121 }
2122 const expectedImport = "golang.org/fake/b"
2123 if _, ok := pkg.Imports[expectedImport]; !ok || len(pkg.Imports) != 1 {
2124 t.Fatalf("Imports of loaded package: want [%s], got %v", expectedImport, pkg.Imports)
2125 }
2126 }
2127
2128 func TestLoadWithNeedDeps(t *testing.T) {
2129 testAllOrModulesParallel(t, testLoadWithNeedDeps)
2130 }
2131 func testLoadWithNeedDeps(t *testing.T, exporter packagestest.Exporter) {
2132 exported := packagestest.Export(t, exporter, []packagestest.Module{{
2133 Name: "golang.org/fake",
2134 Files: map[string]interface{}{
2135 "a/a.go": `package a; import _ "golang.org/fake/b"`,
2136 "b/b.go": `package b; import _ "golang.org/fake/c"`,
2137 "c/c.go": `package c`,
2138 }}})
2139 defer exported.Cleanup()
2140
2141 exported.Config.Mode = packages.NeedTypes | packages.NeedTypesInfo | packages.NeedImports | packages.NeedDeps
2142 pkgs, err := packages.Load(exported.Config, "golang.org/fake/a")
2143 if err != nil {
2144 t.Fatal(err)
2145 }
2146 if len(pkgs) != 1 {
2147 t.Fatalf("Expected 1 package, got %d", len(pkgs))
2148 }
2149
2150 pkgA := pkgs[0]
2151 if pkgA.IllTyped {
2152 t.Fatal("Loaded package is ill typed")
2153 }
2154
2155 pkgB := pkgA.Imports["golang.org/fake/b"]
2156 if pkgB == nil || len(pkgA.Imports) != 1 {
2157 t.Fatalf("Imports of loaded package 'a' are invalid: %v", pkgA.Imports)
2158 }
2159 if pkgB.Types == nil || !pkgB.Types.Complete() || pkgB.TypesInfo == nil {
2160 t.Fatalf("Types of package 'b' are nil or incomplete: %v, %v", pkgB.Types, pkgB.TypesInfo)
2161 }
2162
2163 pkgC := pkgB.Imports["golang.org/fake/c"]
2164 if pkgC == nil || len(pkgB.Imports) != 1 {
2165 t.Fatalf("Imports of loaded package 'c' are invalid: %v", pkgB.Imports)
2166 }
2167 if pkgC.Types == nil || !pkgC.Types.Complete() || pkgC.TypesInfo == nil {
2168 t.Fatalf("Types of package 'b' are nil or incomplete: %v, %v", pkgC.Types, pkgC.TypesInfo)
2169 }
2170 }
2171
2172 func TestImpliedLoadMode(t *testing.T) {
2173 testAllOrModulesParallel(t, testImpliedLoadMode)
2174 }
2175 func testImpliedLoadMode(t *testing.T, exporter packagestest.Exporter) {
2176 exported := packagestest.Export(t, exporter, []packagestest.Module{{
2177 Name: "golang.org/fake",
2178 Files: map[string]interface{}{
2179 "a/a.go": `package a; import _ "golang.org/fake/b"`,
2180 "b/b.go": `package b`,
2181 }}})
2182 defer exported.Cleanup()
2183
2184 exported.Config.Mode = packages.NeedTypes | packages.NeedTypesInfo
2185 pkgs, err := packages.Load(exported.Config, "golang.org/fake/a")
2186 if err != nil {
2187 t.Fatal(err)
2188 }
2189 if len(pkgs) != 1 {
2190 t.Fatalf("Expected 1 package, got %d", len(pkgs))
2191 }
2192
2193 pkg := pkgs[0]
2194 if pkg.IllTyped {
2195 t.Fatalf("Loaded package is ill typed: %v", pkg.Errors)
2196 }
2197
2198
2199 if !pkg.Types.Complete() {
2200 t.Fatalf("Loaded package types are incomplete")
2201 }
2202
2203
2204
2205 if len(pkg.Imports) != 0 {
2206 t.Fatalf("Package imports weren't requested but were returned: %v", pkg.Imports)
2207 }
2208 }
2209
2210 func TestIssue35331(t *testing.T) {
2211 testAllOrModulesParallel(t, testIssue35331)
2212 }
2213 func testIssue35331(t *testing.T, exporter packagestest.Exporter) {
2214 exported := packagestest.Export(t, exporter, []packagestest.Module{{
2215 Name: "golang.org/fake",
2216 }})
2217 defer exported.Cleanup()
2218
2219 exported.Config.Mode = packages.NeedName | packages.NeedFiles | packages.NeedCompiledGoFiles |
2220 packages.NeedImports | packages.NeedDeps | packages.NeedSyntax
2221 exported.Config.Tests = false
2222 pkgs, err := packages.Load(exported.Config, "strconv")
2223 if err != nil {
2224 t.Fatal(err)
2225 }
2226 if len(pkgs) != 1 {
2227 t.Fatalf("Expected 1 package, got %v", pkgs)
2228 }
2229 packages.Visit(pkgs, func(pkg *packages.Package) bool {
2230 if len(pkg.Errors) > 0 {
2231 t.Errorf("Expected no errors in package %q, got %v", pkg.ID, pkg.Errors)
2232 }
2233 if len(pkg.Syntax) == 0 && pkg.ID != "unsafe" {
2234 t.Errorf("Expected syntax on package %q, got none.", pkg.ID)
2235 }
2236 return true
2237 }, nil)
2238 }
2239
2240 func TestMultiplePackageVersionsIssue36188(t *testing.T) {
2241 testAllOrModulesParallel(t, testMultiplePackageVersionsIssue36188)
2242 }
2243
2244 func testMultiplePackageVersionsIssue36188(t *testing.T, exporter packagestest.Exporter) {
2245 exported := packagestest.Export(t, exporter, []packagestest.Module{{
2246 Name: "golang.org/fake",
2247 Files: map[string]interface{}{
2248 "a/a.go": `package a; import _ "golang.org/fake/b"`,
2249 "b/b.go": `package main`,
2250 }}})
2251 pkgs, err := packages.Load(exported.Config, "golang.org/fake/a", "golang.org/fake/b")
2252 if err != nil {
2253 t.Fatal(err)
2254 }
2255 sort.Slice(pkgs, func(i, j int) bool { return pkgs[i].ID < pkgs[j].ID })
2256 if len(pkgs) != 2 {
2257 t.Fatalf("expected two packages, got %v", pkgs)
2258 }
2259 if pkgs[0].ID != "golang.org/fake/a" && pkgs[1].ID != "golang.org/fake/b" {
2260 t.Fatalf(`expected (sorted) IDs "golang.org/fake/a" and "golang.org/fake/b", got %q and %q`,
2261 pkgs[0].ID, pkgs[1].ID)
2262 }
2263 if pkgs[0].Errors == nil {
2264 t.Errorf(`expected error on package "golang.org/fake/a", got none`)
2265 }
2266 if pkgs[1].Errors != nil {
2267 t.Errorf(`expected no errors on package "golang.org/fake/b", got %v`, pkgs[1].Errors)
2268 }
2269 defer exported.Cleanup()
2270 }
2271
2272 func TestLoadModeStrings(t *testing.T) {
2273 testcases := []struct {
2274 mode packages.LoadMode
2275 expected string
2276 }{
2277 {
2278 packages.LoadMode(0),
2279 "LoadMode(0)",
2280 },
2281 {
2282 packages.NeedName,
2283 "LoadMode(NeedName)",
2284 },
2285 {
2286 packages.NeedFiles,
2287 "LoadMode(NeedFiles)",
2288 },
2289 {
2290 packages.NeedCompiledGoFiles,
2291 "LoadMode(NeedCompiledGoFiles)",
2292 },
2293 {
2294 packages.NeedImports,
2295 "LoadMode(NeedImports)",
2296 },
2297 {
2298 packages.NeedDeps,
2299 "LoadMode(NeedDeps)",
2300 },
2301 {
2302 packages.NeedExportFile,
2303 "LoadMode(NeedExportFile)",
2304 },
2305 {
2306 packages.NeedTypes,
2307 "LoadMode(NeedTypes)",
2308 },
2309 {
2310 packages.NeedSyntax,
2311 "LoadMode(NeedSyntax)",
2312 },
2313 {
2314 packages.NeedTypesInfo,
2315 "LoadMode(NeedTypesInfo)",
2316 },
2317 {
2318 packages.NeedTypesSizes,
2319 "LoadMode(NeedTypesSizes)",
2320 },
2321 {
2322 packages.NeedName | packages.NeedExportFile,
2323 "LoadMode(NeedName|NeedExportFile)",
2324 },
2325 {
2326 packages.NeedName | packages.NeedFiles | packages.NeedCompiledGoFiles | packages.NeedImports | packages.NeedDeps | packages.NeedExportFile | packages.NeedTypes | packages.NeedSyntax | packages.NeedTypesInfo | packages.NeedTypesSizes,
2327 "LoadMode(NeedName|NeedFiles|NeedCompiledGoFiles|NeedImports|NeedDeps|NeedExportFile|NeedTypes|NeedSyntax|NeedTypesInfo|NeedTypesSizes)",
2328 },
2329 {
2330 packages.NeedName | 8192,
2331 "LoadMode(NeedName|Unknown)",
2332 },
2333 {
2334 4096,
2335 "LoadMode(Unknown)",
2336 },
2337 }
2338
2339 for tcInd, tc := range testcases {
2340 t.Run(fmt.Sprintf("test-%d", tcInd), func(t *testing.T) {
2341 actual := tc.mode.String()
2342 if tc.expected != actual {
2343 t.Errorf("want %#v, got %#v", tc.expected, actual)
2344 }
2345 })
2346 }
2347 }
2348
2349 func TestCycleImportStack(t *testing.T) {
2350 testAllOrModulesParallel(t, testCycleImportStack)
2351 }
2352 func testCycleImportStack(t *testing.T, exporter packagestest.Exporter) {
2353 exported := packagestest.Export(t, exporter, []packagestest.Module{{
2354 Name: "golang.org/fake",
2355 Files: map[string]interface{}{
2356 "a/a.go": `package a; import _ "golang.org/fake/b"`,
2357 "b/b.go": `package b; import _ "golang.org/fake/a"`,
2358 }}})
2359 defer exported.Cleanup()
2360
2361 exported.Config.Mode = packages.NeedName | packages.NeedImports
2362 pkgs, err := packages.Load(exported.Config, "golang.org/fake/a")
2363 if err != nil {
2364 t.Fatal(err)
2365 }
2366 if len(pkgs) != 1 {
2367 t.Fatalf("Expected 1 package, got %v", pkgs)
2368 }
2369 pkg := pkgs[0]
2370 if len(pkg.Errors) != 1 {
2371 t.Fatalf("Expected one error in package, got %v", pkg.Errors)
2372 }
2373 expected := "import cycle not allowed: import stack: [golang.org/fake/a golang.org/fake/b golang.org/fake/a]"
2374 if pkg.Errors[0].Msg != expected {
2375 t.Fatalf("Expected error %q, got %q", expected, pkg.Errors[0].Msg)
2376 }
2377 }
2378
2379 func TestForTestField(t *testing.T) {
2380 testAllOrModulesParallel(t, testForTestField)
2381 }
2382 func testForTestField(t *testing.T, exporter packagestest.Exporter) {
2383 exported := packagestest.Export(t, exporter, []packagestest.Module{{
2384 Name: "golang.org/fake",
2385 Files: map[string]interface{}{
2386 "a/a.go": `package a; func hello() {};`,
2387 "a/a_test.go": `package a; import "testing"; func TestA1(t *testing.T) {};`,
2388 "a/x_test.go": `package a_test; import "testing"; func TestA2(t *testing.T) {};`,
2389 }}})
2390 defer exported.Cleanup()
2391
2392
2393 exported.Config.Overlay = map[string][]byte{
2394 "a/a_test.go": []byte(`package a; import "testing"; func TestA1(t *testing.T) { hello(); };`),
2395 "a/x_test.go": []byte(`package a_test; import "testing"; func TestA2(t *testing.T) { hello(); };`),
2396 }
2397 exported.Config.Tests = true
2398 exported.Config.Mode = packages.NeedName | packages.NeedImports
2399 forTest := "golang.org/fake/a"
2400 pkgs, err := packages.Load(exported.Config, forTest)
2401 if err != nil {
2402 t.Fatal(err)
2403 }
2404 if len(pkgs) != 4 {
2405 t.Errorf("expected 4 packages, got %v", len(pkgs))
2406 }
2407 for _, pkg := range pkgs {
2408 var hasTestFile bool
2409 for _, f := range pkg.CompiledGoFiles {
2410 if strings.Contains(f, "a_test.go") || strings.Contains(f, "x_test.go") {
2411 hasTestFile = true
2412 break
2413 }
2414 }
2415 if !hasTestFile {
2416 continue
2417 }
2418 got := packagesinternal.GetForTest(pkg)
2419 if got != forTest {
2420 t.Errorf("expected %q, got %q", forTest, got)
2421 }
2422 }
2423 }
2424
2425 func TestIssue37629(t *testing.T) {
2426 testAllOrModulesParallel(t, testIssue37629)
2427 }
2428 func testIssue37629(t *testing.T, exporter packagestest.Exporter) {
2429
2430
2431
2432
2433 exported := packagestest.Export(t, exporter, []packagestest.Module{{
2434 Name: "golang.org/fake",
2435 Files: map[string]any{
2436 "c/c2.go": `package c`,
2437 "a/a.go": `package a; import "b.com/b"; const A = b.B`,
2438 "vendor/b.com/b/b.go": `package b; const B = 4`,
2439 "vendor/modules.txt": `# b.com/b v1.0.0
2440 ## explicit
2441 b.com/b`,
2442 }}, {
2443 Name: "b.com/b@v1.0.0",
2444 Files: map[string]any{
2445 "arbitrary.txt": "",
2446 }},
2447 })
2448 rootDir := filepath.Dir(filepath.Dir(exported.File("golang.org/fake", "a/a.go")))
2449 exported.Config.Overlay = map[string][]byte{
2450 filepath.Join(rootDir, "c/c.go"): []byte(`package c; import "golang.org/fake/a"; const C = a.A`),
2451 }
2452 exported.Config.Env = append(exported.Config.Env, "GOFLAGS=-mod=vendor")
2453 exported.Config.Mode = packages.LoadAllSyntax
2454
2455 defer exported.Cleanup()
2456
2457 initial, err := packages.Load(exported.Config, "golang.org/fake/c")
2458 if err != nil {
2459 t.Fatal(err)
2460 }
2461
2462
2463 a := initial[0]
2464 aA := constant(a, "C")
2465 if aA == nil {
2466 t.Fatalf("a.A: got nil")
2467 }
2468 got := aA.Val().String()
2469 if got != "4" {
2470 t.Errorf("a.A: got %s, want %s", got, "4")
2471 }
2472 }
2473
2474 func TestIssue37098(t *testing.T) { testAllOrModulesParallel(t, testIssue37098) }
2475 func testIssue37098(t *testing.T, exporter packagestest.Exporter) {
2476
2477
2478
2479
2480
2481 if _, err := exec.LookPath("swig"); err != nil {
2482 t.Skip("skipping test: swig not available")
2483 }
2484 if _, err := exec.LookPath("g++"); err != nil {
2485 t.Skip("skipping test: g++ not available")
2486 }
2487
2488
2489
2490 exported := packagestest.Export(t, exporter, []packagestest.Module{{
2491 Name: "golang.org/fake",
2492 Files: map[string]interface{}{
2493
2494
2495 "a/a.go": "package a",
2496 "a/a.swigcxx": "",
2497 }}})
2498 defer exported.Cleanup()
2499
2500 initial, err := packages.Load(exported.Config, "golang.org/fake/a")
2501 if err != nil {
2502 t.Fatalf("failed to load the package: %v", err)
2503 }
2504
2505 for _, pkg := range initial {
2506 for _, file := range pkg.CompiledGoFiles {
2507
2508
2509 fset := token.NewFileSet()
2510 _, err := parser.ParseFile(fset, file, nil, parser.ImportsOnly)
2511 if err != nil {
2512 t.Errorf("Failed to parse file '%s' as a Go source: %v", file, err)
2513
2514 contents, err := os.ReadFile(file)
2515 if err != nil {
2516 t.Fatalf("Failed to read the un-parsable file '%s': %v", file, err)
2517 }
2518
2519
2520 n := len(contents)
2521
2522
2523 const maxBytes = 1000
2524 if n > maxBytes {
2525 n = maxBytes
2526 }
2527
2528 t.Logf("First %d bytes of un-parsable file: %s", n, contents[:n])
2529 }
2530 }
2531 }
2532 }
2533
2534
2535
2536 func TestIssue56632(t *testing.T) {
2537 t.Parallel()
2538 testenv.NeedsGoBuild(t)
2539 testenv.NeedsTool(t, "cgo")
2540
2541 exported := packagestest.Export(t, packagestest.GOPATH, []packagestest.Module{{
2542 Name: "golang.org/issue56632",
2543 Files: map[string]interface{}{
2544 "a/a.go": `package a`,
2545 "a/a_cgo.go": `package a
2546
2547 import "C"`,
2548 "a/a.s": ``,
2549 "a/a.c": ``,
2550 }}})
2551 defer exported.Cleanup()
2552
2553 modes := []packages.LoadMode{packages.NeedCompiledGoFiles, packages.NeedCompiledGoFiles | packages.NeedFiles, packages.NeedImports | packages.NeedCompiledGoFiles, packages.NeedImports | packages.NeedFiles | packages.NeedCompiledGoFiles}
2554 for _, mode := range modes {
2555 exported.Config.Mode = mode
2556
2557 initial, err := packages.Load(exported.Config, "golang.org/issue56632/a")
2558 if err != nil {
2559 t.Fatalf("failed to load package: %v", err)
2560 }
2561
2562 if len(initial) != 1 {
2563 t.Errorf("expected 3 packages, got %d", len(initial))
2564 }
2565
2566 p := initial[0]
2567
2568 if len(p.Errors) != 0 {
2569 t.Errorf("expected no errors, got %v", p.Errors)
2570 }
2571
2572 for _, f := range p.CompiledGoFiles {
2573 if strings.HasSuffix(f, ".s") || strings.HasSuffix(f, ".c") {
2574 t.Errorf("expected no non-Go CompiledGoFiles, got file %q in CompiledGoFiles", f)
2575 }
2576 }
2577 }
2578 }
2579
2580
2581 func TestInvalidFilesInXTest(t *testing.T) { testAllOrModulesParallel(t, testInvalidFilesInXTest) }
2582 func testInvalidFilesInXTest(t *testing.T, exporter packagestest.Exporter) {
2583 exported := packagestest.Export(t, exporter, []packagestest.Module{
2584 {
2585 Name: "golang.org/fake",
2586 Files: map[string]interface{}{
2587 "d/d.go": `package d; import "net/http"; const d = http.MethodGet; func Get() string { return d; }`,
2588 "d/d2.go": ``,
2589 "d/d_test.go": `package d_test; import "testing"; import "golang.org/fake/d"; func TestD(t *testing.T) { d.Get(); }`,
2590 },
2591 },
2592 })
2593 defer exported.Cleanup()
2594
2595 exported.Config.Mode = packages.NeedName | packages.NeedFiles
2596 exported.Config.Tests = true
2597
2598 initial, err := packages.Load(exported.Config, "golang.org/fake/d")
2599 if err != nil {
2600 t.Fatal(err)
2601 }
2602 if len(initial) != 3 {
2603 t.Errorf("expected 3 packages, got %d", len(initial))
2604 }
2605 }
2606
2607 func TestTypecheckCgo(t *testing.T) { testAllOrModulesParallel(t, testTypecheckCgo) }
2608 func testTypecheckCgo(t *testing.T, exporter packagestest.Exporter) {
2609 testenv.NeedsTool(t, "cgo")
2610
2611 const cgo = `package cgo
2612 import "C"
2613
2614 func Example() {
2615 C.CString("hi")
2616 }
2617 `
2618 exported := packagestest.Export(t, exporter, []packagestest.Module{
2619 {
2620 Name: "golang.org/fake",
2621 Files: map[string]interface{}{
2622 "cgo/cgo.go": cgo,
2623 },
2624 },
2625 })
2626 defer exported.Cleanup()
2627
2628 exported.Config.Mode = packages.NeedFiles | packages.NeedCompiledGoFiles |
2629 packages.NeedSyntax | packages.NeedDeps | packages.NeedTypes |
2630 packages.LoadMode(packagesinternal.TypecheckCgo)
2631
2632 initial, err := packages.Load(exported.Config, "golang.org/fake/cgo")
2633 if err != nil {
2634 t.Fatal(err)
2635 }
2636 pkg := initial[0]
2637 if len(pkg.Errors) != 0 {
2638 t.Fatalf("package has errors: %v", pkg.Errors)
2639 }
2640
2641 expos := pkg.Types.Scope().Lookup("Example").Pos()
2642 fname := pkg.Fset.File(expos).Name()
2643 if !strings.HasSuffix(fname, "cgo.go") {
2644 t.Errorf("position for cgo package was loaded from %v, wanted cgo.go", fname)
2645 }
2646 }
2647
2648 func TestModule(t *testing.T) {
2649 testAllOrModulesParallel(t, testModule)
2650 }
2651 func testModule(t *testing.T, exporter packagestest.Exporter) {
2652 exported := packagestest.Export(t, exporter, []packagestest.Module{{
2653 Name: "golang.org/fake",
2654 Files: map[string]interface{}{"a/a.go": `package a`}}})
2655 exported.Config.Mode = packages.NeedModule
2656 rootDir := filepath.Dir(filepath.Dir(exported.File("golang.org/fake", "a/a.go")))
2657
2658 initial, err := packages.Load(exported.Config, "golang.org/fake/a")
2659 if err != nil {
2660 t.Fatal(err)
2661 }
2662
2663 if len(initial) != 1 {
2664 t.Fatal("want exactly one package, got ", initial)
2665 }
2666 a := initial[0]
2667 switch exported.Exporter.Name() {
2668 case "GOPATH":
2669 if a.Module != nil {
2670 t.Fatal("package.Module: want nil, got ", a.Module)
2671 }
2672 case "Modules":
2673
2674 if a.Module == nil {
2675 t.Fatal("package.Module: want non-nil, got nil")
2676 }
2677 if a.Module.Path != "golang.org/fake" {
2678 t.Fatalf("package.Modile.Path: want \"golang.org/fake\", got %q", a.Module.Path)
2679 }
2680 if a.Module.GoMod != filepath.Join(rootDir, "go.mod") {
2681 t.Fatalf("package.Module.GoMod: want %q, got %q", filepath.Join(rootDir, "go.mod"), a.Module.GoMod)
2682 }
2683 default:
2684 t.Fatalf("Expected exporter to be GOPATH or Modules, got %v", exported.Exporter.Name())
2685 }
2686 }
2687
2688 func TestExternal_NotHandled(t *testing.T) {
2689 testAllOrModulesParallel(t, testExternal_NotHandled)
2690 }
2691 func testExternal_NotHandled(t *testing.T, exporter packagestest.Exporter) {
2692 skipIfShort(t, "builds and links fake driver binaries")
2693 testenv.NeedsGoBuild(t)
2694
2695 tempdir, err := os.MkdirTemp("", "testexternal")
2696 if err != nil {
2697 t.Fatal(err)
2698 }
2699 defer os.RemoveAll(tempdir)
2700
2701 exported := packagestest.Export(t, exporter, []packagestest.Module{{
2702 Name: "golang.org/fake",
2703 Files: map[string]interface{}{
2704 "a/a.go": `package a`,
2705 "empty_driver/main.go": `package main
2706
2707 import (
2708 "fmt"
2709 "io"
2710 "os"
2711 )
2712
2713 func main() {
2714 io.ReadAll(os.Stdin)
2715 fmt.Println("{}")
2716 }
2717 `,
2718 "nothandled_driver/main.go": `package main
2719
2720 import (
2721 "fmt"
2722 "io"
2723 "os"
2724 )
2725
2726 func main() {
2727 io.ReadAll(os.Stdin)
2728 fmt.Println("{\"NotHandled\": true}")
2729 }
2730 `,
2731 }}})
2732 baseEnv := exported.Config.Env
2733
2734
2735 emptyDriverPath := filepath.Join(tempdir, "empty_driver.exe")
2736 cmd := exec.Command("go", "build", "-o", emptyDriverPath, "golang.org/fake/empty_driver")
2737 cmd.Env = baseEnv
2738 cmd.Dir = exported.Config.Dir
2739 if b, err := cmd.CombinedOutput(); err != nil {
2740 t.Log(string(b))
2741 t.Fatal(err)
2742 }
2743
2744 exported.Config.Env = append(append([]string{}, baseEnv...), "GOPACKAGESDRIVER="+emptyDriverPath)
2745 initial, err := packages.Load(exported.Config, "golang.org/fake/a")
2746 if err != nil {
2747 t.Fatal(err)
2748 }
2749
2750 if len(initial) != 0 {
2751 t.Errorf("package.Load with empty driver: want [], got %v", initial)
2752 }
2753
2754
2755 notHandledDriverPath := filepath.Join(tempdir, "nothandled_driver.exe")
2756 cmd = exec.Command("go", "build", "-o", notHandledDriverPath, "golang.org/fake/nothandled_driver")
2757 cmd.Env = baseEnv
2758 cmd.Dir = exported.Config.Dir
2759 if b, err := cmd.CombinedOutput(); err != nil {
2760 t.Log(string(b))
2761 t.Fatal(err)
2762 }
2763
2764 exported.Config.Env = append(append([]string{}, baseEnv...), "GOPACKAGESDRIVER="+notHandledDriverPath)
2765 initial, err = packages.Load(exported.Config, "golang.org/fake/a")
2766 if err != nil {
2767 t.Fatal(err)
2768 }
2769
2770 if len(initial) != 1 || initial[0].PkgPath != "golang.org/fake/a" {
2771 t.Errorf("package.Load: want [golang.org/fake/a], got %v", initial)
2772 }
2773 }
2774
2775 func TestInvalidPackageName(t *testing.T) {
2776 testAllOrModulesParallel(t, testInvalidPackageName)
2777 }
2778
2779 func testInvalidPackageName(t *testing.T, exporter packagestest.Exporter) {
2780 exported := packagestest.Export(t, exporter, []packagestest.Module{{
2781 Name: "golang.org/fake",
2782 Files: map[string]interface{}{
2783 "main.go": `package default
2784
2785 func main() {
2786 }
2787 `,
2788 },
2789 }})
2790 defer exported.Cleanup()
2791
2792 initial, err := packages.Load(exported.Config, "golang.org/fake")
2793 if err != nil {
2794 t.Fatal(err)
2795 }
2796 pkg := initial[0]
2797 if len(pkg.CompiledGoFiles) != 1 {
2798 t.Fatalf("expected 1 Go file in package %s, got %v", pkg.ID, len(pkg.CompiledGoFiles))
2799 }
2800 }
2801
2802 func TestEmptyEnvironment(t *testing.T) {
2803 t.Parallel()
2804
2805 cfg := &packages.Config{
2806 Env: []string{"FOO=BAR"},
2807 }
2808 _, err := packages.Load(cfg, "fmt")
2809 if err == nil {
2810 t.Fatal("Load with explicitly empty environment should fail")
2811 }
2812 }
2813
2814 func TestPackageLoadSingleFile(t *testing.T) {
2815 testenv.NeedsTool(t, "go")
2816
2817 tmp, err := os.MkdirTemp("", "a")
2818 if err != nil {
2819 t.Fatal(err)
2820 }
2821 defer os.RemoveAll(tmp)
2822
2823 filename := filepath.Join(tmp, "a.go")
2824
2825 if err := os.WriteFile(filename, []byte(`package main; func main() { println("hello world") }`), 0775); err != nil {
2826 t.Fatal(err)
2827 }
2828
2829 pkgs, err := packages.Load(&packages.Config{Mode: packages.LoadSyntax, Dir: tmp}, "file="+filename)
2830 if err != nil {
2831 t.Fatalf("could not load package: %v", err)
2832 }
2833 if len(pkgs) != 1 {
2834 t.Fatalf("expected one package to be loaded, got %d", len(pkgs))
2835 }
2836 if len(pkgs[0].CompiledGoFiles) != 1 || pkgs[0].CompiledGoFiles[0] != filename {
2837 t.Fatalf("expected one compiled go file (%q), got %v", filename, pkgs[0].CompiledGoFiles)
2838 }
2839 }
2840
2841 func errorMessages(errors []packages.Error) []string {
2842 var msgs []string
2843 for _, err := range errors {
2844 msgs = append(msgs, err.Msg)
2845 }
2846 return msgs
2847 }
2848
2849 func srcs(p *packages.Package) []string {
2850 var files []string
2851 files = append(files, p.GoFiles...)
2852 files = append(files, p.OtherFiles...)
2853 files = append(files, p.EmbedFiles...)
2854 return cleanPaths(files)
2855 }
2856
2857
2858 func cleanPaths(paths []string) []string {
2859 result := make([]string, len(paths))
2860 for i, src := range paths {
2861
2862
2863 name := filepath.Base(src)
2864 if !strings.Contains(name, ".") {
2865 result[i] = fmt.Sprintf("%d.go", i)
2866 } else {
2867 result[i] = name
2868 }
2869 }
2870 return result
2871 }
2872
2873
2874
2875 func importGraph(initial []*packages.Package) (string, map[string]*packages.Package) {
2876 out := new(bytes.Buffer)
2877
2878 initialSet := make(map[*packages.Package]bool)
2879 for _, p := range initial {
2880 initialSet[p] = true
2881 }
2882
2883
2884
2885 var nodes, edges []string
2886 res := make(map[string]*packages.Package)
2887 seen := make(map[*packages.Package]bool)
2888 var visit func(p *packages.Package)
2889 visit = func(p *packages.Package) {
2890 if !seen[p] {
2891 seen[p] = true
2892 if res[p.ID] != nil {
2893 panic("duplicate ID: " + p.ID)
2894 }
2895 res[p.ID] = p
2896
2897 star := ' '
2898 if initialSet[p] {
2899 star = '*'
2900 }
2901 nodes = append(nodes, fmt.Sprintf("%c %s", star, p.ID))
2902
2903
2904
2905
2906 isTestMain := p.Imports["testing/internal/testdeps"] != nil
2907
2908 for _, imp := range p.Imports {
2909 if isTestMain {
2910 switch imp.ID {
2911 case "os", "reflect", "testing", "testing/internal/testdeps":
2912 continue
2913 }
2914 }
2915
2916
2917
2918
2919 if p.ID == "math/bits" && imp.ID == "unsafe" {
2920 continue
2921 }
2922 edges = append(edges, fmt.Sprintf("%s -> %s", p, imp))
2923 visit(imp)
2924 }
2925 }
2926 }
2927 for _, p := range initial {
2928 visit(p)
2929 }
2930
2931
2932 sort.Slice(nodes, func(i, j int) bool { return nodes[i][2:] < nodes[j][2:] })
2933 for _, node := range nodes {
2934 fmt.Fprintf(out, "%s\n", node)
2935 }
2936
2937 sort.Strings(edges)
2938 for _, edge := range edges {
2939 fmt.Fprintf(out, " %s\n", edge)
2940 }
2941
2942 return out.String(), res
2943 }
2944
2945 func constant(p *packages.Package, name string) *types.Const {
2946 if p == nil || p.Types == nil {
2947 return nil
2948 }
2949 c := p.Types.Scope().Lookup(name)
2950 if c == nil {
2951 return nil
2952 }
2953 return c.(*types.Const)
2954 }
2955
2956 func copyAll(srcPath, dstPath string) error {
2957 return filepath.Walk(srcPath, func(path string, info os.FileInfo, _ error) error {
2958 if info.IsDir() {
2959 return nil
2960 }
2961 contents, err := os.ReadFile(path)
2962 if err != nil {
2963 return err
2964 }
2965 rel, err := filepath.Rel(srcPath, path)
2966 if err != nil {
2967 return err
2968 }
2969 dstFilePath := strings.Replace(filepath.Join(dstPath, rel), "definitelynot_go.mod", "go.mod", -1)
2970 if err := os.MkdirAll(filepath.Dir(dstFilePath), 0755); err != nil {
2971 return err
2972 }
2973 if err := os.WriteFile(dstFilePath, contents, 0644); err != nil {
2974 return err
2975 }
2976 return nil
2977 })
2978 }
2979
2980 func TestExportFile(t *testing.T) {
2981
2982
2983 cfg := new(packages.Config)
2984 cfg.Mode = packages.NeedTypes
2985 packages.Load(cfg, "fmt")
2986 }
2987
2988
2989
2990
2991
2992
2993
2994
2995 func TestLoadEitherSucceedsOrFails(t *testing.T) {
2996 const src = `package p`
2997 dir := t.TempDir()
2998 cfg := &packages.Config{
2999 Dir: dir,
3000 Mode: packages.LoadSyntax,
3001 Overlay: map[string][]byte{
3002 filepath.Join(dir, "p.go"): []byte(src),
3003 },
3004 }
3005 initial, err := packages.Load(cfg, "./p.go")
3006 if err != nil {
3007
3008
3009 testenv.NeedsGoBuild(t)
3010
3011
3012 t.Fatal(err)
3013 }
3014
3015
3016
3017 if packages.PrintErrors(initial) > 0 {
3018 t.Errorf("packages contain errors")
3019 }
3020
3021
3022
3023 if len(initial) != 1 {
3024 t.Errorf("Load returned %d packages (want 1) and no error", len(initial))
3025 }
3026 }
3027
View as plain text