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