golang.org/x/tools@v0.21.0/go/packages/packages_test.go (about) 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. 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 // testCtx is canceled when the test binary is about to time out. 35 // 36 // If https://golang.org/issue/28135 is accepted, uses of this variable in test 37 // functions should be replaced by t.Context(). 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 // testAllOrModulesParallel tests f, in parallel, against all packagestest 63 // exporters in long mode, but only against the Modules exporter in short mode. 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 // TODO(adonovan): more test cases to write: 85 // 86 // - When the tests fail, make them print a 'cd & load' command 87 // that will allow the maintainer to interact with the failing scenario. 88 // - errors in go-list metadata 89 // - a foo.test package that cannot be built for some reason (e.g. 90 // import error) will result in a JSON blob with no name and a 91 // nonexistent testmain file in GoFiles. Test that we handle this 92 // gracefully. 93 // - test more Flags. 94 // 95 // LoadSyntax & LoadAllSyntax modes: 96 // - Fset may be user-supplied or not. 97 // - Packages.Info is correctly set. 98 // - typechecker configuration is honored 99 // - import cycles are gracefully handled in type checker. 100 // - test typechecking of generated test main and cgo. 101 102 // The zero-value of Config has LoadFiles mode. 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 // Even though the hash package has imports, 116 // they are not reported. 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"`, // TODO(adonovan): test bad import here 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 // Check graph topology. 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 // Check graph topology. 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 // Check node information: kind, name, srcs. 215 for _, test := range []struct { 216 id string 217 wantName string 218 wantKind string 219 wantSrcs string // = {Go,Other,Embed}Files 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"}, // c2.go is ignored 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 // kind 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 // Test an ad-hoc package, analogous to "go run hello.go". 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 // Wildcards 270 // See StdlibTest for effective test of "std" wildcard. 271 // TODO(adonovan): test "all" returns everything in the current module. 272 { 273 // "..." (subdirectory) 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 // Check graph topology. 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 // NOTE: this test adds about 2s to the test suite running time 372 373 t.Parallel() 374 375 // using the real ARG_MAX for some platforms increases the running time of this test by a lot, 376 // 1_000_000 seems like enough to break Windows and macOS if Load doesn't split provided patterns 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 // the pattern below is approx. 16 chars 385 patterns := make([]string, numOfPatterns) 386 for i := 0; i < numOfPatterns; i++ { 387 patterns[i] = fmt.Sprintf("golang.org/mod/p%d", i) 388 } // patterns have more than argMax number of chars combined with whitespaces b/w patterns 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 // Test the import paths. 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 // value of Name constant 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 // Use LoadSyntax to ensure that files can be opened. 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 // TODO: remove when go#28023 is fixed 511 if test.fails && strings.HasPrefix(test.pattern, "./") && exporter == packagestest.Modules { 512 // Currently go list in module mode does not handle missing directories correctly. 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 // Test satisfying +build line tags, with -tags flag. 524 exported := packagestest.Export(t, exporter, []packagestest.Module{{ 525 Name: "golang.org/fake", 526 Files: map[string]interface{}{ 527 // package a 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 // package a/b 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 // In LoadTypes and LoadSyntax modes, the compiler will 585 // fail to generate an export data file for c, because it has 586 // a type error. The loader should fall back loading a and c 587 // from source, but use the export data for b. 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 // TestLoadTypesBits is equivalent to TestLoadTypes except that it only requests 639 // the types using the NeedTypes bit. 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 // We don't request the syntax, so we shouldn't get it. 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 // Check value of constant. 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}, // source package 760 {"golang.org/fake/b", true, true}, // source package because depends on initial package 761 {"golang.org/fake/c", true, true}, // source package 762 {"golang.org/fake/d", false, true}, // export data package 763 {"golang.org/fake/e", false, false}, // export data package 764 {"golang.org/fake/f", false, false}, // export data package 765 } { 766 // TODO(matloob): LoadSyntax and LoadAllSyntax are now equivalent, wantSyntax and wantComplete 767 // are true for all packages in the transitive dependency set. Add test cases on the individual 768 // Need* fields to check the equivalents on the new API. 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 // Check value of constant. 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 // We make a diamond dependency and check the type d.D is the same through both paths 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 // A type error in a lower-level package (e) prevents go list 849 // from producing export data for all packages that depend on it 850 // [a-e]. Only f should be loaded from export data, and the rest 851 // should be IllTyped. 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`, // type error 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 // Check value of constant. 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 // This function tests use of the ParseFile hook to modify 921 // the AST after parsing. 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 // modify AST to change `const A = "a"` to `const A = "b"` 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 // Check value of a.A has been set to "b" 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 // This test doesn't use packagestest because we are testing ad-hoc packages, 958 // which are outside of $GOPATH and outside of a module. 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 // Make sure that the user's value of GO111MODULE does not affect test results. 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 // Check value of a.A. 990 a := initial[0] 991 // There's an error because there's a bad import. 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 // TODO(matloob): Remove this once go list -e -compiled is fixed. 1009 // See https://golang.org/issue/26755 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 // Cycle-forming edges are removed from the graph: 1038 // bicycle2 -> bicycle1 1039 // unicycle -> unicycle 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 // Import paths 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 // Relative paths 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 // Test that files in all packages exist and are absolute paths. 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 // This test ensures that the effective GOARCH variable in the 1209 // application determines the Sizes function used by the type checker. 1210 // This behavior is a stop-gap until we make the build system's query 1211 // tool report the correct sizes function for the actual configuration. 1212 func TestSizes(t *testing.T) { testAllOrModulesParallel(t, testSizes) } 1213 func testSizes(t *testing.T, exporter packagestest.Exporter) { 1214 // Only run this test on operating systems that have both an amd64 and 386 port. 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 // This is a regression test for a bug related to 1247 // github.com/golang/vscode-go/issues/3021: if types are needed (any 1248 // of NeedTypes{,Info,Sizes} and the types.Sizes cannot be obtained 1249 // (e.g. due to a bad GOARCH) then the Load operation must fail. It 1250 // must not return a nil TypesSizes, or use the default (wrong) size. 1251 // (The root cause of that issue turned out to be due to skew in the 1252 // Bazel GOPACKAGESDRIVER; see CL 537876.) 1253 // 1254 // We use a file=... query because it suppresses the bad-GOARCH check 1255 // that the go command would otherwise perform eagerly. 1256 // (Gopls relies on this as a fallback.) 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 // or {,Info,Sizes} 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 // TestContainsFallbackSticks ensures that when there are both contains and non-contains queries 1276 // the decision whether to fallback to the pre-1.11 go list sticks across both sets of calls to 1277 // go list. 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 // Test that Load with no patterns is equivalent to loading "." via the golist 1312 // driver. 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 // TODO: add in some errors 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 // Visit and print all packages. 1355 buf := &bytes.Buffer{} 1356 enc := json.NewEncoder(buf) 1357 enc.SetIndent("", "\t") 1358 packages.Visit(initial, nil, func(pkg *packages.Package) { 1359 // trim the source lists for stable results 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 // now decode it again 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 // packagestest.TestAll instead of testAllOrModulesParallel because this test 1529 // can't be parallelized (it modifies the environment). 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 // TODO(jayconrod): write an equivalent batch script for windows. 1546 // Hint: "type" can be used to read a file to stdout. 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 // Clone exported.Config 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 // This test that a simple x test package layout loads correctly. 1633 // There was a bug in go list where it returned multiple copies of the same 1634 // package (specifically in this case of golang.org/fake/a), and this triggered 1635 // a bug in go/packages where it would leave an empty entry in the root package 1636 // list. This would then cause a nil pointer crash. 1637 // This bug was triggered by the simple package layout below, and thus this 1638 // test will make sure the bug remains fixed. 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 // Go <1.14 calls the package command-line-arguments while Go 1.14+ uses the file names. 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 // Check if the error returned is the one we expected. 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 // triggering this error requires a relative package path 1756 exported.Config.Dir = filepath.Dir(exported.File("golang.org/gopatha", "a/testdata/a.go")) 1757 pkgs, err := packages.Load(exported.Config, ".") 1758 1759 // This error doesn't seem to occur in module mode; so only 1760 // complain if we get zero packages while also getting no error. 1761 if err == nil { 1762 if len(pkgs) == 0 { 1763 // TODO(dh): we'll need to expand on the error check if/when Go stops emitting this error 1764 t.Fatalf("want error, got nil") 1765 } 1766 return 1767 } 1768 // Check if the error returned is the one we expected. 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 // Explicitly enable cgo but configure a nonexistent C compiler. 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 // Check value of a.A. 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 // Explicitly enable cgo. 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 // Check value of a.A. 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 // This test checks that when a package depends on the 1911 // test variant of "syscall", "unsafe", or "runtime/cgo", that dependency 1912 // is not removed when those packages are added when it imports "C". 1913 // 1914 // For this test to work, the external test of syscall must have a dependency 1915 // on net, and net must import "syscall" and "C". 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 // See https://golang.org/issue/27100. 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 // an import to check for 1941 }{ 1942 {"net", "syscall:syscall"}, 1943 {"net [syscall.test]", "syscall:syscall [syscall.test]"}, 1944 {"syscall_test [syscall.test]", "net:net [syscall.test]"}, 1945 } { 1946 // Test the import paths. 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 // Explicitly enable cgo. 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 // Check that packages.NeedTypesInfo worked well. 2199 if !pkg.Types.Complete() { 2200 t.Fatalf("Loaded package types are incomplete") 2201 } 2202 2203 // Check that implied packages.NeedImports by packages.NeedTypesInfo 2204 // didn't add Imports. 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 // Add overlays to make sure they don't affect anything. 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 // Tests #37629. When automatic vendoring is triggered, and we try to determine 2430 // the module root dir for a new overlay package, we previously would do a go list -m all, 2431 // which is incompatible with automatic vendoring. 2432 2433 exported := packagestest.Export(t, exporter, []packagestest.Module{{ 2434 Name: "golang.org/fake", 2435 Files: map[string]interface{}{ 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 }}}) 2440 rootDir := filepath.Dir(filepath.Dir(exported.File("golang.org/fake", "a/a.go"))) 2441 exported.Config.Overlay = map[string][]byte{ 2442 filepath.Join(rootDir, "c/c.go"): []byte(`package c; import "golang.org/fake/a"; const C = a.A`), 2443 } 2444 exported.Config.Env = append(exported.Config.Env, "GOFLAGS=-mod=vendor") 2445 exported.Config.Mode = packages.LoadAllSyntax 2446 2447 defer exported.Cleanup() 2448 2449 initial, err := packages.Load(exported.Config, "golang.org/fake/c") 2450 if err != nil { 2451 t.Fatal(err) 2452 } 2453 2454 // Check value of a.A. 2455 a := initial[0] 2456 aA := constant(a, "C") 2457 if aA == nil { 2458 t.Fatalf("a.A: got nil") 2459 } 2460 got := aA.Val().String() 2461 if got != "4" { 2462 t.Errorf("a.A: got %s, want %s", got, "4") 2463 } 2464 } 2465 2466 func TestIssue37098(t *testing.T) { testAllOrModulesParallel(t, testIssue37098) } 2467 func testIssue37098(t *testing.T, exporter packagestest.Exporter) { 2468 // packages.Load should only return Go sources in 2469 // (*Package).CompiledGoFiles. This tests #37098, where using SWIG to 2470 // causes C++ sources to be inadvertently included in 2471 // (*Package).CompiledGoFiles. 2472 2473 if _, err := exec.LookPath("swig"); err != nil { 2474 t.Skip("skipping test: swig not available") 2475 } 2476 if _, err := exec.LookPath("g++"); err != nil { 2477 t.Skip("skipping test: g++ not available") 2478 } 2479 2480 // Create a fake package with an empty Go source, and a SWIG interface 2481 // file. 2482 exported := packagestest.Export(t, exporter, []packagestest.Module{{ 2483 Name: "golang.org/fake", 2484 Files: map[string]interface{}{ 2485 // The "package" statement must be included for SWIG sources to 2486 // be generated. 2487 "a/a.go": "package a", 2488 "a/a.swigcxx": "", 2489 }}}) 2490 defer exported.Cleanup() 2491 2492 initial, err := packages.Load(exported.Config, "golang.org/fake/a") 2493 if err != nil { 2494 t.Fatalf("failed to load the package: %v", err) 2495 } 2496 // Try and parse each of the files 2497 for _, pkg := range initial { 2498 for _, file := range pkg.CompiledGoFiles { 2499 2500 // Validate that each file can be parsed as a Go source. 2501 fset := token.NewFileSet() 2502 _, err := parser.ParseFile(fset, file, nil, parser.ImportsOnly) 2503 if err != nil { 2504 t.Errorf("Failed to parse file '%s' as a Go source: %v", file, err) 2505 2506 contents, err := os.ReadFile(file) 2507 if err != nil { 2508 t.Fatalf("Failed to read the un-parsable file '%s': %v", file, err) 2509 } 2510 2511 // Print out some of the un-parsable file to aid in debugging. 2512 n := len(contents) 2513 2514 // Don't print the whole file if it is too large. 2515 const maxBytes = 1000 2516 if n > maxBytes { 2517 n = maxBytes 2518 } 2519 2520 t.Logf("First %d bytes of un-parsable file: %s", n, contents[:n]) 2521 } 2522 } 2523 } 2524 } 2525 2526 // TestIssue56632 checks that CompiledGoFiles does not contain non-go files regardless of 2527 // whether the NeedFiles mode bit is set. 2528 func TestIssue56632(t *testing.T) { 2529 t.Parallel() 2530 testenv.NeedsGoBuild(t) 2531 testenv.NeedsTool(t, "cgo") 2532 2533 exported := packagestest.Export(t, packagestest.GOPATH, []packagestest.Module{{ 2534 Name: "golang.org/issue56632", 2535 Files: map[string]interface{}{ 2536 "a/a.go": `package a`, 2537 "a/a_cgo.go": `package a 2538 2539 import "C"`, 2540 "a/a.s": ``, 2541 "a/a.c": ``, 2542 }}}) 2543 defer exported.Cleanup() 2544 2545 modes := []packages.LoadMode{packages.NeedCompiledGoFiles, packages.NeedCompiledGoFiles | packages.NeedFiles, packages.NeedImports | packages.NeedCompiledGoFiles, packages.NeedImports | packages.NeedFiles | packages.NeedCompiledGoFiles} 2546 for _, mode := range modes { 2547 exported.Config.Mode = mode 2548 2549 initial, err := packages.Load(exported.Config, "golang.org/issue56632/a") 2550 if err != nil { 2551 t.Fatalf("failed to load package: %v", err) 2552 } 2553 2554 if len(initial) != 1 { 2555 t.Errorf("expected 3 packages, got %d", len(initial)) 2556 } 2557 2558 p := initial[0] 2559 2560 if len(p.Errors) != 0 { 2561 t.Errorf("expected no errors, got %v", p.Errors) 2562 } 2563 2564 for _, f := range p.CompiledGoFiles { 2565 if strings.HasSuffix(f, ".s") || strings.HasSuffix(f, ".c") { 2566 t.Errorf("expected no non-Go CompiledGoFiles, got file %q in CompiledGoFiles", f) 2567 } 2568 } 2569 } 2570 } 2571 2572 // TestInvalidFilesInXTest checks the fix for golang/go#37971 in Go 1.15. 2573 func TestInvalidFilesInXTest(t *testing.T) { testAllOrModulesParallel(t, testInvalidFilesInXTest) } 2574 func testInvalidFilesInXTest(t *testing.T, exporter packagestest.Exporter) { 2575 exported := packagestest.Export(t, exporter, []packagestest.Module{ 2576 { 2577 Name: "golang.org/fake", 2578 Files: map[string]interface{}{ 2579 "d/d.go": `package d; import "net/http"; const d = http.MethodGet; func Get() string { return d; }`, 2580 "d/d2.go": ``, // invalid file 2581 "d/d_test.go": `package d_test; import "testing"; import "golang.org/fake/d"; func TestD(t *testing.T) { d.Get(); }`, 2582 }, 2583 }, 2584 }) 2585 defer exported.Cleanup() 2586 2587 exported.Config.Mode = packages.NeedName | packages.NeedFiles 2588 exported.Config.Tests = true 2589 2590 initial, err := packages.Load(exported.Config, "golang.org/fake/d") 2591 if err != nil { 2592 t.Fatal(err) 2593 } 2594 if len(initial) != 3 { 2595 t.Errorf("expected 3 packages, got %d", len(initial)) 2596 } 2597 } 2598 2599 func TestTypecheckCgo(t *testing.T) { testAllOrModulesParallel(t, testTypecheckCgo) } 2600 func testTypecheckCgo(t *testing.T, exporter packagestest.Exporter) { 2601 testenv.NeedsTool(t, "cgo") 2602 2603 const cgo = `package cgo 2604 import "C" 2605 2606 func Example() { 2607 C.CString("hi") 2608 } 2609 ` 2610 exported := packagestest.Export(t, exporter, []packagestest.Module{ 2611 { 2612 Name: "golang.org/fake", 2613 Files: map[string]interface{}{ 2614 "cgo/cgo.go": cgo, 2615 }, 2616 }, 2617 }) 2618 defer exported.Cleanup() 2619 2620 exported.Config.Mode = packages.NeedFiles | packages.NeedCompiledGoFiles | 2621 packages.NeedSyntax | packages.NeedDeps | packages.NeedTypes | 2622 packages.LoadMode(packagesinternal.TypecheckCgo) 2623 2624 initial, err := packages.Load(exported.Config, "golang.org/fake/cgo") 2625 if err != nil { 2626 t.Fatal(err) 2627 } 2628 pkg := initial[0] 2629 if len(pkg.Errors) != 0 { 2630 t.Fatalf("package has errors: %v", pkg.Errors) 2631 } 2632 2633 expos := pkg.Types.Scope().Lookup("Example").Pos() 2634 fname := pkg.Fset.File(expos).Name() 2635 if !strings.HasSuffix(fname, "cgo.go") { 2636 t.Errorf("position for cgo package was loaded from %v, wanted cgo.go", fname) 2637 } 2638 } 2639 2640 func TestModule(t *testing.T) { 2641 testAllOrModulesParallel(t, testModule) 2642 } 2643 func testModule(t *testing.T, exporter packagestest.Exporter) { 2644 exported := packagestest.Export(t, exporter, []packagestest.Module{{ 2645 Name: "golang.org/fake", 2646 Files: map[string]interface{}{"a/a.go": `package a`}}}) 2647 exported.Config.Mode = packages.NeedModule 2648 rootDir := filepath.Dir(filepath.Dir(exported.File("golang.org/fake", "a/a.go"))) 2649 2650 initial, err := packages.Load(exported.Config, "golang.org/fake/a") 2651 if err != nil { 2652 t.Fatal(err) 2653 } 2654 2655 if len(initial) != 1 { 2656 t.Fatal("want exactly one package, got ", initial) 2657 } 2658 a := initial[0] 2659 switch exported.Exporter.Name() { 2660 case "GOPATH": 2661 if a.Module != nil { 2662 t.Fatal("package.Module: want nil, got ", a.Module) 2663 } 2664 case "Modules": 2665 // Make sure Modules field is set, and spot check a few of its fields. 2666 if a.Module == nil { 2667 t.Fatal("package.Module: want non-nil, got nil") 2668 } 2669 if a.Module.Path != "golang.org/fake" { 2670 t.Fatalf("package.Modile.Path: want \"golang.org/fake\", got %q", a.Module.Path) 2671 } 2672 if a.Module.GoMod != filepath.Join(rootDir, "go.mod") { 2673 t.Fatalf("package.Module.GoMod: want %q, got %q", filepath.Join(rootDir, "go.mod"), a.Module.GoMod) 2674 } 2675 default: 2676 t.Fatalf("Expected exporter to be GOPATH or Modules, got %v", exported.Exporter.Name()) 2677 } 2678 } 2679 2680 func TestExternal_NotHandled(t *testing.T) { 2681 testAllOrModulesParallel(t, testExternal_NotHandled) 2682 } 2683 func testExternal_NotHandled(t *testing.T, exporter packagestest.Exporter) { 2684 skipIfShort(t, "builds and links fake driver binaries") 2685 testenv.NeedsGoBuild(t) 2686 2687 tempdir, err := os.MkdirTemp("", "testexternal") 2688 if err != nil { 2689 t.Fatal(err) 2690 } 2691 defer os.RemoveAll(tempdir) 2692 2693 exported := packagestest.Export(t, exporter, []packagestest.Module{{ 2694 Name: "golang.org/fake", 2695 Files: map[string]interface{}{ 2696 "a/a.go": `package a`, 2697 "empty_driver/main.go": `package main 2698 2699 import ( 2700 "fmt" 2701 "io" 2702 "os" 2703 ) 2704 2705 func main() { 2706 io.ReadAll(os.Stdin) 2707 fmt.Println("{}") 2708 } 2709 `, 2710 "nothandled_driver/main.go": `package main 2711 2712 import ( 2713 "fmt" 2714 "io" 2715 "os" 2716 ) 2717 2718 func main() { 2719 io.ReadAll(os.Stdin) 2720 fmt.Println("{\"NotHandled\": true}") 2721 } 2722 `, 2723 }}}) 2724 baseEnv := exported.Config.Env 2725 2726 // As a control, create a fake driver that always returns an empty response. 2727 emptyDriverPath := filepath.Join(tempdir, "empty_driver.exe") // Add .exe because Windows expects it. 2728 cmd := exec.Command("go", "build", "-o", emptyDriverPath, "golang.org/fake/empty_driver") 2729 cmd.Env = baseEnv 2730 cmd.Dir = exported.Config.Dir 2731 if b, err := cmd.CombinedOutput(); err != nil { 2732 t.Log(string(b)) 2733 t.Fatal(err) 2734 } 2735 2736 exported.Config.Env = append(append([]string{}, baseEnv...), "GOPACKAGESDRIVER="+emptyDriverPath) 2737 initial, err := packages.Load(exported.Config, "golang.org/fake/a") 2738 if err != nil { 2739 t.Fatal(err) 2740 } 2741 2742 if len(initial) != 0 { 2743 t.Errorf("package.Load with empty driver: want [], got %v", initial) 2744 } 2745 2746 // Create a fake driver that always returns a NotHandled response. 2747 notHandledDriverPath := filepath.Join(tempdir, "nothandled_driver.exe") 2748 cmd = exec.Command("go", "build", "-o", notHandledDriverPath, "golang.org/fake/nothandled_driver") 2749 cmd.Env = baseEnv 2750 cmd.Dir = exported.Config.Dir 2751 if b, err := cmd.CombinedOutput(); err != nil { 2752 t.Log(string(b)) 2753 t.Fatal(err) 2754 } 2755 2756 exported.Config.Env = append(append([]string{}, baseEnv...), "GOPACKAGESDRIVER="+notHandledDriverPath) 2757 initial, err = packages.Load(exported.Config, "golang.org/fake/a") 2758 if err != nil { 2759 t.Fatal(err) 2760 } 2761 2762 if len(initial) != 1 || initial[0].PkgPath != "golang.org/fake/a" { 2763 t.Errorf("package.Load: want [golang.org/fake/a], got %v", initial) 2764 } 2765 } 2766 2767 func TestInvalidPackageName(t *testing.T) { 2768 testAllOrModulesParallel(t, testInvalidPackageName) 2769 } 2770 2771 func testInvalidPackageName(t *testing.T, exporter packagestest.Exporter) { 2772 exported := packagestest.Export(t, exporter, []packagestest.Module{{ 2773 Name: "golang.org/fake", 2774 Files: map[string]interface{}{ 2775 "main.go": `package default 2776 2777 func main() { 2778 } 2779 `, 2780 }, 2781 }}) 2782 defer exported.Cleanup() 2783 2784 initial, err := packages.Load(exported.Config, "golang.org/fake") 2785 if err != nil { 2786 t.Fatal(err) 2787 } 2788 pkg := initial[0] 2789 if len(pkg.CompiledGoFiles) != 1 { 2790 t.Fatalf("expected 1 Go file in package %s, got %v", pkg.ID, len(pkg.CompiledGoFiles)) 2791 } 2792 } 2793 2794 func TestEmptyEnvironment(t *testing.T) { 2795 t.Parallel() 2796 2797 cfg := &packages.Config{ 2798 Env: []string{"FOO=BAR"}, 2799 } 2800 _, err := packages.Load(cfg, "fmt") 2801 if err == nil { 2802 t.Fatal("Load with explicitly empty environment should fail") 2803 } 2804 } 2805 2806 func TestPackageLoadSingleFile(t *testing.T) { 2807 testenv.NeedsTool(t, "go") 2808 2809 tmp, err := os.MkdirTemp("", "a") 2810 if err != nil { 2811 t.Fatal(err) 2812 } 2813 defer os.RemoveAll(tmp) 2814 2815 filename := filepath.Join(tmp, "a.go") 2816 2817 if err := os.WriteFile(filename, []byte(`package main; func main() { println("hello world") }`), 0775); err != nil { 2818 t.Fatal(err) 2819 } 2820 2821 pkgs, err := packages.Load(&packages.Config{Mode: packages.LoadSyntax, Dir: tmp}, "file="+filename) 2822 if err != nil { 2823 t.Fatalf("could not load package: %v", err) 2824 } 2825 if len(pkgs) != 1 { 2826 t.Fatalf("expected one package to be loaded, got %d", len(pkgs)) 2827 } 2828 if len(pkgs[0].CompiledGoFiles) != 1 || pkgs[0].CompiledGoFiles[0] != filename { 2829 t.Fatalf("expected one compiled go file (%q), got %v", filename, pkgs[0].CompiledGoFiles) 2830 } 2831 } 2832 2833 func errorMessages(errors []packages.Error) []string { 2834 var msgs []string 2835 for _, err := range errors { 2836 msgs = append(msgs, err.Msg) 2837 } 2838 return msgs 2839 } 2840 2841 func srcs(p *packages.Package) []string { 2842 var files []string 2843 files = append(files, p.GoFiles...) 2844 files = append(files, p.OtherFiles...) 2845 files = append(files, p.EmbedFiles...) 2846 return cleanPaths(files) 2847 } 2848 2849 // cleanPaths attempts to reduce path names to stable forms 2850 func cleanPaths(paths []string) []string { 2851 result := make([]string, len(paths)) 2852 for i, src := range paths { 2853 // If the source file doesn't have an extension like .go or .s, 2854 // it comes from GOCACHE. The names there aren't predictable. 2855 name := filepath.Base(src) 2856 if !strings.Contains(name, ".") { 2857 result[i] = fmt.Sprintf("%d.go", i) // make cache names predictable 2858 } else { 2859 result[i] = name 2860 } 2861 } 2862 return result 2863 } 2864 2865 // importGraph returns the import graph as a user-friendly string, 2866 // and a map containing all packages keyed by ID. 2867 func importGraph(initial []*packages.Package) (string, map[string]*packages.Package) { 2868 out := new(bytes.Buffer) 2869 2870 initialSet := make(map[*packages.Package]bool) 2871 for _, p := range initial { 2872 initialSet[p] = true 2873 } 2874 2875 // We can't use Visit because we need to prune 2876 // the traversal of specific edges, not just nodes. 2877 var nodes, edges []string 2878 res := make(map[string]*packages.Package) 2879 seen := make(map[*packages.Package]bool) 2880 var visit func(p *packages.Package) 2881 visit = func(p *packages.Package) { 2882 if !seen[p] { 2883 seen[p] = true 2884 if res[p.ID] != nil { 2885 panic("duplicate ID: " + p.ID) 2886 } 2887 res[p.ID] = p 2888 2889 star := ' ' // mark initial packages with a star 2890 if initialSet[p] { 2891 star = '*' 2892 } 2893 nodes = append(nodes, fmt.Sprintf("%c %s", star, p.ID)) 2894 2895 // To avoid a lot of noise, 2896 // we prune uninteresting dependencies of testmain packages, 2897 // which we identify by this import: 2898 isTestMain := p.Imports["testing/internal/testdeps"] != nil 2899 2900 for _, imp := range p.Imports { 2901 if isTestMain { 2902 switch imp.ID { 2903 case "os", "reflect", "testing", "testing/internal/testdeps": 2904 continue 2905 } 2906 } 2907 // math/bits took on a dependency on unsafe in 1.12, which breaks some 2908 // tests. As a short term hack, prune that edge. 2909 // ditto for ("errors", "internal/reflectlite") in 1.13. 2910 // TODO(matloob): think of a cleaner solution, or remove math/bits from the test. 2911 if p.ID == "math/bits" && imp.ID == "unsafe" { 2912 continue 2913 } 2914 edges = append(edges, fmt.Sprintf("%s -> %s", p, imp)) 2915 visit(imp) 2916 } 2917 } 2918 } 2919 for _, p := range initial { 2920 visit(p) 2921 } 2922 2923 // Sort, ignoring leading optional star prefix. 2924 sort.Slice(nodes, func(i, j int) bool { return nodes[i][2:] < nodes[j][2:] }) 2925 for _, node := range nodes { 2926 fmt.Fprintf(out, "%s\n", node) 2927 } 2928 2929 sort.Strings(edges) 2930 for _, edge := range edges { 2931 fmt.Fprintf(out, " %s\n", edge) 2932 } 2933 2934 return out.String(), res 2935 } 2936 2937 func constant(p *packages.Package, name string) *types.Const { 2938 if p == nil || p.Types == nil { 2939 return nil 2940 } 2941 c := p.Types.Scope().Lookup(name) 2942 if c == nil { 2943 return nil 2944 } 2945 return c.(*types.Const) 2946 } 2947 2948 func copyAll(srcPath, dstPath string) error { 2949 return filepath.Walk(srcPath, func(path string, info os.FileInfo, _ error) error { 2950 if info.IsDir() { 2951 return nil 2952 } 2953 contents, err := os.ReadFile(path) 2954 if err != nil { 2955 return err 2956 } 2957 rel, err := filepath.Rel(srcPath, path) 2958 if err != nil { 2959 return err 2960 } 2961 dstFilePath := strings.Replace(filepath.Join(dstPath, rel), "definitelynot_go.mod", "go.mod", -1) 2962 if err := os.MkdirAll(filepath.Dir(dstFilePath), 0755); err != nil { 2963 return err 2964 } 2965 if err := os.WriteFile(dstFilePath, contents, 0644); err != nil { 2966 return err 2967 } 2968 return nil 2969 }) 2970 } 2971 2972 func TestExportFile(t *testing.T) { 2973 // This used to trigger the log.Fatal in loadFromExportData. 2974 // See go.dev/issue/45584. 2975 cfg := new(packages.Config) 2976 cfg.Mode = packages.NeedTypes 2977 packages.Load(cfg, "fmt") 2978 } 2979 2980 // TestLoadEitherSucceedsOrFails is an attempt to reproduce a sporadic 2981 // failure observed on the Android emu builders in which Load would 2982 // return an empty list of packages but no error. We don't expect 2983 // packages.Load to succeed on that platform, and testenv.NeedsGoBuild 2984 // would ordinarily suppress the attempt if called early. But 2985 // regardless of whether the 'go' command is functional, Load should 2986 // never return an empty set of packages but no error. 2987 func TestLoadEitherSucceedsOrFails(t *testing.T) { 2988 const src = `package p` 2989 dir := t.TempDir() 2990 cfg := &packages.Config{ 2991 Dir: dir, 2992 Mode: packages.LoadSyntax, 2993 Overlay: map[string][]byte{ 2994 filepath.Join(dir, "p.go"): []byte(src), 2995 }, 2996 } 2997 initial, err := packages.Load(cfg, "./p.go") 2998 if err != nil { 2999 // If Load failed because it needed 'go' and the 3000 // platform doesn't have it, silently skip the test. 3001 testenv.NeedsGoBuild(t) 3002 3003 // Otherwise, it's a real failure. 3004 t.Fatal(err) 3005 } 3006 3007 // If Load returned without error, 3008 // it had better give us error-free packages. 3009 if packages.PrintErrors(initial) > 0 { 3010 t.Errorf("packages contain errors") 3011 } 3012 3013 // If Load returned without error, 3014 // it had better give us the correct number packages. 3015 if len(initial) != 1 { 3016 t.Errorf("Load returned %d packages (want 1) and no error", len(initial)) 3017 } 3018 }