github.com/jhump/golang-x-tools@v0.0.0-20220218190644-4958d6d39439/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/jhump/golang-x-tools/go/packages" 30 "github.com/jhump/golang-x-tools/go/packages/packagestest" 31 "github.com/jhump/golang-x-tools/internal/packagesinternal" 32 "github.com/jhump/golang-x-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 }}}) 1081 defer exported.Cleanup() 1082 exported.Config.Dir = filepath.Dir(filepath.Dir(exported.File("golang.org/fake", "a/a.go"))) 1083 1084 checkFile := func(filename string) { 1085 if !filepath.IsAbs(filename) { 1086 t.Errorf("filename is not absolute: %s", filename) 1087 } 1088 if _, err := os.Stat(filename); err != nil { 1089 t.Errorf("stat error, %s: %v", filename, err) 1090 } 1091 } 1092 1093 for _, test := range []struct { 1094 pattern string 1095 want string 1096 }{ 1097 // Import paths 1098 {"golang.org/fake/a", "a.go"}, 1099 {"golang.org/fake/b/vendor/a", "a.go"}, 1100 {"golang.org/fake/b", "b.go"}, 1101 {"golang.org/fake/c", "c.go"}, 1102 {"golang.org/fake/subdir/d", "d.go"}, 1103 {"golang.org/fake/subdir/e", "d.go"}, 1104 {"golang.org/fake/e", "e.go e2.go"}, 1105 {"golang.org/fake/f", "f.go f.s"}, 1106 // Relative paths 1107 {"./a", "a.go"}, 1108 {"./b/vendor/a", "a.go"}, 1109 {"./b", "b.go"}, 1110 {"./c", "c.go"}, 1111 {"./subdir/d", "d.go"}, 1112 {"./subdir/e", "d.go"}, 1113 {"./e", "e.go e2.go"}, 1114 {"./f", "f.go f.s"}, 1115 } { 1116 exported.Config.Mode = packages.LoadFiles 1117 pkgs, err := packages.Load(exported.Config, test.pattern) 1118 if err != nil { 1119 t.Errorf("pattern %s: %v", test.pattern, err) 1120 continue 1121 } 1122 1123 if got := strings.Join(srcs(pkgs[0]), " "); got != test.want { 1124 t.Errorf("in package %s, got %s, want %s", test.pattern, got, test.want) 1125 } 1126 1127 // Test that files in all packages exist and are absolute paths. 1128 _, all := importGraph(pkgs) 1129 for _, pkg := range all { 1130 for _, filename := range pkg.GoFiles { 1131 checkFile(filename) 1132 } 1133 for _, filename := range pkg.OtherFiles { 1134 checkFile(filename) 1135 } 1136 for _, filename := range pkg.IgnoredFiles { 1137 checkFile(filename) 1138 } 1139 } 1140 } 1141 } 1142 1143 func TestContains(t *testing.T) { testAllOrModulesParallel(t, testContains) } 1144 func testContains(t *testing.T, exporter packagestest.Exporter) { 1145 exported := packagestest.Export(t, exporter, []packagestest.Module{{ 1146 Name: "golang.org/fake", 1147 Files: map[string]interface{}{ 1148 "a/a.go": `package a; import "golang.org/fake/b"`, 1149 "b/b.go": `package b; import "golang.org/fake/c"`, 1150 "c/c.go": `package c`, 1151 }}}) 1152 defer exported.Cleanup() 1153 bFile := exported.File("golang.org/fake", "b/b.go") 1154 exported.Config.Mode = packages.LoadImports 1155 initial, err := packages.Load(exported.Config, "file="+bFile) 1156 if err != nil { 1157 t.Fatal(err) 1158 } 1159 1160 graph, _ := importGraph(initial) 1161 wantGraph := ` 1162 * golang.org/fake/b 1163 golang.org/fake/c 1164 golang.org/fake/b -> golang.org/fake/c 1165 `[1:] 1166 if graph != wantGraph { 1167 t.Errorf("wrong import graph: got <<%s>>, want <<%s>>", graph, wantGraph) 1168 } 1169 } 1170 1171 // This test ensures that the effective GOARCH variable in the 1172 // application determines the Sizes function used by the type checker. 1173 // This behavior is a stop-gap until we make the build system's query 1174 // tool report the correct sizes function for the actual configuration. 1175 func TestSizes(t *testing.T) { testAllOrModulesParallel(t, testSizes) } 1176 func testSizes(t *testing.T, exporter packagestest.Exporter) { 1177 // Only run this test on operating systems that have both an amd64 and 386 port. 1178 switch runtime.GOOS { 1179 case "linux", "windows", "freebsd", "openbsd", "netbsd", "android": 1180 default: 1181 t.Skipf("skipping test on %s", runtime.GOOS) 1182 } 1183 1184 exported := packagestest.Export(t, exporter, []packagestest.Module{{ 1185 Name: "golang.org/fake", 1186 Files: map[string]interface{}{ 1187 "a/a.go": `package a; import "unsafe"; const WordSize = 8*unsafe.Sizeof(int(0))`, 1188 }}}) 1189 defer exported.Cleanup() 1190 1191 exported.Config.Mode = packages.LoadSyntax 1192 savedEnv := exported.Config.Env 1193 for arch, wantWordSize := range map[string]int64{"386": 32, "amd64": 64} { 1194 exported.Config.Env = append(savedEnv, "GOARCH="+arch) 1195 initial, err := packages.Load(exported.Config, "golang.org/fake/a") 1196 if err != nil { 1197 t.Fatal(err) 1198 } 1199 if packages.PrintErrors(initial) > 0 { 1200 t.Fatal("there were errors") 1201 } 1202 gotWordSize, _ := constantpkg.Int64Val(constant(initial[0], "WordSize").Val()) 1203 if gotWordSize != wantWordSize { 1204 t.Errorf("for GOARCH=%s, got word size %d, want %d", arch, gotWordSize, wantWordSize) 1205 } 1206 } 1207 } 1208 1209 // TestContainsFallbackSticks ensures that when there are both contains and non-contains queries 1210 // the decision whether to fallback to the pre-1.11 go list sticks across both sets of calls to 1211 // go list. 1212 func TestContainsFallbackSticks(t *testing.T) { 1213 testAllOrModulesParallel(t, testContainsFallbackSticks) 1214 } 1215 func testContainsFallbackSticks(t *testing.T, exporter packagestest.Exporter) { 1216 exported := packagestest.Export(t, exporter, []packagestest.Module{{ 1217 Name: "golang.org/fake", 1218 Files: map[string]interface{}{ 1219 "a/a.go": `package a; import "golang.org/fake/b"`, 1220 "b/b.go": `package b; import "golang.org/fake/c"`, 1221 "c/c.go": `package c`, 1222 }}}) 1223 defer exported.Cleanup() 1224 1225 exported.Config.Mode = packages.LoadImports 1226 bFile := exported.File("golang.org/fake", "b/b.go") 1227 initial, err := packages.Load(exported.Config, "golang.org/fake/a", "file="+bFile) 1228 if err != nil { 1229 t.Fatal(err) 1230 } 1231 1232 graph, _ := importGraph(initial) 1233 wantGraph := ` 1234 * golang.org/fake/a 1235 * golang.org/fake/b 1236 golang.org/fake/c 1237 golang.org/fake/a -> golang.org/fake/b 1238 golang.org/fake/b -> golang.org/fake/c 1239 `[1:] 1240 if graph != wantGraph { 1241 t.Errorf("wrong import graph: got <<%s>>, want <<%s>>", graph, wantGraph) 1242 } 1243 } 1244 1245 // Test that Load with no patterns is equivalent to loading "." via the golist 1246 // driver. 1247 func TestNoPatterns(t *testing.T) { testAllOrModulesParallel(t, testNoPatterns) } 1248 func testNoPatterns(t *testing.T, exporter packagestest.Exporter) { 1249 exported := packagestest.Export(t, exporter, []packagestest.Module{{ 1250 Name: "golang.org/fake", 1251 Files: map[string]interface{}{ 1252 "a/a.go": `package a;`, 1253 "a/b/b.go": `package b;`, 1254 }}}) 1255 defer exported.Cleanup() 1256 1257 aDir := filepath.Dir(exported.File("golang.org/fake", "a/a.go")) 1258 exported.Config.Dir = aDir 1259 1260 initial, err := packages.Load(exported.Config) 1261 if err != nil { 1262 t.Fatal(err) 1263 } 1264 if len(initial) != 1 || initial[0].Name != "a" { 1265 t.Fatalf(`Load() = %v, wanted just the package in the current directory`, initial) 1266 } 1267 } 1268 1269 func TestJSON(t *testing.T) { testAllOrModulesParallel(t, testJSON) } 1270 func testJSON(t *testing.T, exporter packagestest.Exporter) { 1271 //TODO: add in some errors 1272 exported := packagestest.Export(t, exporter, []packagestest.Module{{ 1273 Name: "golang.org/fake", 1274 Files: map[string]interface{}{ 1275 "a/a.go": `package a; const A = 1`, 1276 "b/b.go": `package b; import "golang.org/fake/a"; var B = a.A`, 1277 "c/c.go": `package c; import "golang.org/fake/b" ; var C = b.B`, 1278 "d/d.go": `package d; import "golang.org/fake/b" ; var D = b.B`, 1279 }}}) 1280 defer exported.Cleanup() 1281 1282 exported.Config.Mode = packages.LoadImports 1283 initial, err := packages.Load(exported.Config, "golang.org/fake/c", "golang.org/fake/d") 1284 if err != nil { 1285 t.Fatal(err) 1286 } 1287 1288 // Visit and print all packages. 1289 buf := &bytes.Buffer{} 1290 enc := json.NewEncoder(buf) 1291 enc.SetIndent("", "\t") 1292 packages.Visit(initial, nil, func(pkg *packages.Package) { 1293 // trim the source lists for stable results 1294 pkg.GoFiles = cleanPaths(pkg.GoFiles) 1295 pkg.CompiledGoFiles = cleanPaths(pkg.CompiledGoFiles) 1296 pkg.OtherFiles = cleanPaths(pkg.OtherFiles) 1297 pkg.IgnoredFiles = cleanPaths(pkg.IgnoredFiles) 1298 if err := enc.Encode(pkg); err != nil { 1299 t.Fatal(err) 1300 } 1301 }) 1302 1303 wantJSON := ` 1304 { 1305 "ID": "golang.org/fake/a", 1306 "Name": "a", 1307 "PkgPath": "golang.org/fake/a", 1308 "GoFiles": [ 1309 "a.go" 1310 ], 1311 "CompiledGoFiles": [ 1312 "a.go" 1313 ] 1314 } 1315 { 1316 "ID": "golang.org/fake/b", 1317 "Name": "b", 1318 "PkgPath": "golang.org/fake/b", 1319 "GoFiles": [ 1320 "b.go" 1321 ], 1322 "CompiledGoFiles": [ 1323 "b.go" 1324 ], 1325 "Imports": { 1326 "golang.org/fake/a": "golang.org/fake/a" 1327 } 1328 } 1329 { 1330 "ID": "golang.org/fake/c", 1331 "Name": "c", 1332 "PkgPath": "golang.org/fake/c", 1333 "GoFiles": [ 1334 "c.go" 1335 ], 1336 "CompiledGoFiles": [ 1337 "c.go" 1338 ], 1339 "Imports": { 1340 "golang.org/fake/b": "golang.org/fake/b" 1341 } 1342 } 1343 { 1344 "ID": "golang.org/fake/d", 1345 "Name": "d", 1346 "PkgPath": "golang.org/fake/d", 1347 "GoFiles": [ 1348 "d.go" 1349 ], 1350 "CompiledGoFiles": [ 1351 "d.go" 1352 ], 1353 "Imports": { 1354 "golang.org/fake/b": "golang.org/fake/b" 1355 } 1356 } 1357 `[1:] 1358 1359 if buf.String() != wantJSON { 1360 t.Errorf("wrong JSON: got <<%s>>, want <<%s>>", buf.String(), wantJSON) 1361 } 1362 // now decode it again 1363 var decoded []*packages.Package 1364 dec := json.NewDecoder(buf) 1365 for dec.More() { 1366 p := new(packages.Package) 1367 if err := dec.Decode(p); err != nil { 1368 t.Fatal(err) 1369 } 1370 decoded = append(decoded, p) 1371 } 1372 if len(decoded) != 4 { 1373 t.Fatalf("got %d packages, want 4", len(decoded)) 1374 } 1375 for i, want := range []*packages.Package{{ 1376 ID: "golang.org/fake/a", 1377 Name: "a", 1378 }, { 1379 ID: "golang.org/fake/b", 1380 Name: "b", 1381 Imports: map[string]*packages.Package{ 1382 "golang.org/fake/a": {ID: "golang.org/fake/a"}, 1383 }, 1384 }, { 1385 ID: "golang.org/fake/c", 1386 Name: "c", 1387 Imports: map[string]*packages.Package{ 1388 "golang.org/fake/b": {ID: "golang.org/fake/b"}, 1389 }, 1390 }, { 1391 ID: "golang.org/fake/d", 1392 Name: "d", 1393 Imports: map[string]*packages.Package{ 1394 "golang.org/fake/b": {ID: "golang.org/fake/b"}, 1395 }, 1396 }} { 1397 got := decoded[i] 1398 if got.ID != want.ID { 1399 t.Errorf("Package %d has ID %q want %q", i, got.ID, want.ID) 1400 } 1401 if got.Name != want.Name { 1402 t.Errorf("Package %q has Name %q want %q", got.ID, got.Name, want.Name) 1403 } 1404 if len(got.Imports) != len(want.Imports) { 1405 t.Errorf("Package %q has %d imports want %d", got.ID, len(got.Imports), len(want.Imports)) 1406 continue 1407 } 1408 for path, ipkg := range got.Imports { 1409 if want.Imports[path] == nil { 1410 t.Errorf("Package %q has unexpected import %q", got.ID, path) 1411 continue 1412 } 1413 if want.Imports[path].ID != ipkg.ID { 1414 t.Errorf("Package %q import %q is %q want %q", got.ID, path, ipkg.ID, want.Imports[path].ID) 1415 } 1416 } 1417 } 1418 } 1419 1420 func TestRejectInvalidQueries(t *testing.T) { 1421 t.Parallel() 1422 1423 queries := []string{"key=", "key=value"} 1424 cfg := &packages.Config{ 1425 Mode: packages.LoadImports, 1426 Env: append(os.Environ(), "GO111MODULE=off", "GOPACKAGESDRIVER=off"), 1427 } 1428 for _, q := range queries { 1429 if _, err := packages.Load(cfg, q); err == nil { 1430 t.Errorf("packages.Load(%q) succeeded. Expected \"invalid query type\" error", q) 1431 } else if !strings.Contains(err.Error(), "invalid query type") { 1432 t.Errorf("packages.Load(%q): got error %v, want \"invalid query type\" error", q, err) 1433 } 1434 } 1435 } 1436 1437 func TestPatternPassthrough(t *testing.T) { testAllOrModulesParallel(t, testPatternPassthrough) } 1438 func testPatternPassthrough(t *testing.T, exporter packagestest.Exporter) { 1439 exported := packagestest.Export(t, exporter, []packagestest.Module{{ 1440 Name: "golang.org/fake", 1441 Files: map[string]interface{}{ 1442 "a/a.go": `package a;`, 1443 }}}) 1444 defer exported.Cleanup() 1445 1446 initial, err := packages.Load(exported.Config, "pattern=a") 1447 if err != nil { 1448 t.Fatal(err) 1449 } 1450 1451 graph, _ := importGraph(initial) 1452 wantGraph := ` 1453 * a 1454 `[1:] 1455 if graph != wantGraph { 1456 t.Errorf("wrong import graph: got <<%s>>, want <<%s>>", graph, wantGraph) 1457 } 1458 1459 } 1460 1461 func TestConfigDefaultEnv(t *testing.T) { 1462 // packagestest.TestAll instead of testAllOrModulesParallel because this test 1463 // can't be parallelized (it modifies the environment). 1464 packagestest.TestAll(t, testConfigDefaultEnv) 1465 } 1466 func testConfigDefaultEnv(t *testing.T, exporter packagestest.Exporter) { 1467 const driverJSON = `{ 1468 "Roots": ["gopackagesdriver"], 1469 "Packages": [{"ID": "gopackagesdriver", "Name": "gopackagesdriver"}] 1470 }` 1471 var ( 1472 pathKey string 1473 driverScript packagestest.Writer 1474 ) 1475 switch runtime.GOOS { 1476 case "android": 1477 t.Skip("doesn't run on android") 1478 case "windows": 1479 // TODO(jayconrod): write an equivalent batch script for windows. 1480 // Hint: "type" can be used to read a file to stdout. 1481 t.Skip("test requires sh") 1482 case "plan9": 1483 pathKey = "path" 1484 driverScript = packagestest.Script(`#!/bin/rc 1485 1486 cat <<'EOF' 1487 ` + driverJSON + ` 1488 EOF 1489 `) 1490 default: 1491 pathKey = "PATH" 1492 driverScript = packagestest.Script(`#!/bin/sh 1493 1494 cat - <<'EOF' 1495 ` + driverJSON + ` 1496 EOF 1497 `) 1498 } 1499 exported := packagestest.Export(t, exporter, []packagestest.Module{{ 1500 Name: "golang.org/fake", 1501 Files: map[string]interface{}{ 1502 "bin/gopackagesdriver": driverScript, 1503 "golist/golist.go": "package golist", 1504 }}}) 1505 defer exported.Cleanup() 1506 driver := exported.File("golang.org/fake", "bin/gopackagesdriver") 1507 binDir := filepath.Dir(driver) 1508 if err := os.Chmod(driver, 0755); err != nil { 1509 t.Fatal(err) 1510 } 1511 1512 path, ok := os.LookupEnv(pathKey) 1513 var pathWithDriver string 1514 if ok { 1515 pathWithDriver = binDir + string(os.PathListSeparator) + path 1516 } else { 1517 pathWithDriver = binDir 1518 } 1519 for _, test := range []struct { 1520 desc string 1521 path string 1522 driver string 1523 wantIDs string 1524 }{ 1525 { 1526 desc: "driver_off", 1527 path: pathWithDriver, 1528 driver: "off", 1529 wantIDs: "[golist]", 1530 }, { 1531 desc: "driver_unset", 1532 path: pathWithDriver, 1533 driver: "", 1534 wantIDs: "[gopackagesdriver]", 1535 }, { 1536 desc: "driver_set", 1537 path: "", 1538 driver: driver, 1539 wantIDs: "[gopackagesdriver]", 1540 }, 1541 } { 1542 t.Run(test.desc, func(t *testing.T) { 1543 oldPath := os.Getenv(pathKey) 1544 os.Setenv(pathKey, test.path) 1545 defer os.Setenv(pathKey, oldPath) 1546 // Clone exported.Config 1547 config := exported.Config 1548 config.Env = append([]string{}, exported.Config.Env...) 1549 config.Env = append(config.Env, "GOPACKAGESDRIVER="+test.driver) 1550 pkgs, err := packages.Load(exported.Config, "golist") 1551 if err != nil { 1552 t.Fatal(err) 1553 } 1554 1555 gotIds := make([]string, len(pkgs)) 1556 for i, pkg := range pkgs { 1557 gotIds[i] = pkg.ID 1558 } 1559 if fmt.Sprint(pkgs) != test.wantIDs { 1560 t.Errorf("got %v; want %v", gotIds, test.wantIDs) 1561 } 1562 }) 1563 } 1564 } 1565 1566 // This test that a simple x test package layout loads correctly. 1567 // There was a bug in go list where it returned multiple copies of the same 1568 // package (specifically in this case of golang.org/fake/a), and this triggered 1569 // a bug in go/packages where it would leave an empty entry in the root package 1570 // list. This would then cause a nil pointer crash. 1571 // This bug was triggered by the simple package layout below, and thus this 1572 // test will make sure the bug remains fixed. 1573 func TestBasicXTest(t *testing.T) { testAllOrModulesParallel(t, testBasicXTest) } 1574 func testBasicXTest(t *testing.T, exporter packagestest.Exporter) { 1575 exported := packagestest.Export(t, exporter, []packagestest.Module{{ 1576 Name: "golang.org/fake", 1577 Files: map[string]interface{}{ 1578 "a/a.go": `package a;`, 1579 "a/a_test.go": `package a_test;`, 1580 }}}) 1581 defer exported.Cleanup() 1582 1583 exported.Config.Mode = packages.LoadFiles 1584 exported.Config.Tests = true 1585 _, err := packages.Load(exported.Config, "golang.org/fake/a") 1586 if err != nil { 1587 t.Fatal(err) 1588 } 1589 } 1590 1591 func TestErrorMissingFile(t *testing.T) { testAllOrModulesParallel(t, testErrorMissingFile) } 1592 func testErrorMissingFile(t *testing.T, exporter packagestest.Exporter) { 1593 exported := packagestest.Export(t, exporter, []packagestest.Module{{ 1594 Name: "golang.org/fake", 1595 Files: map[string]interface{}{ 1596 "a/a_test.go": `package a;`, 1597 }}}) 1598 defer exported.Cleanup() 1599 1600 exported.Config.Mode = packages.LoadSyntax 1601 exported.Config.Tests = false 1602 pkgs, err := packages.Load(exported.Config, "missing.go") 1603 if err != nil { 1604 t.Fatal(err) 1605 } 1606 if len(pkgs) == 0 && runtime.GOOS == "windows" { 1607 t.Skip("Issue #31344: the ad-hoc command-line-arguments package isn't created on windows") 1608 } 1609 if len(pkgs) != 1 || (pkgs[0].PkgPath != "command-line-arguments" && pkgs[0].PkgPath != "missing.go") { 1610 t.Fatalf("packages.Load: want [command-line-arguments] or [missing.go], got %v", pkgs) 1611 } 1612 if len(pkgs[0].Errors) == 0 { 1613 t.Errorf("result of Load: want package with errors, got none: %+v", pkgs[0]) 1614 } 1615 } 1616 1617 func TestReturnErrorWhenUsingNonGoFiles(t *testing.T) { 1618 testAllOrModulesParallel(t, testReturnErrorWhenUsingNonGoFiles) 1619 } 1620 func testReturnErrorWhenUsingNonGoFiles(t *testing.T, exporter packagestest.Exporter) { 1621 exported := packagestest.Export(t, exporter, []packagestest.Module{{ 1622 Name: "golang.org/gopatha", 1623 Files: map[string]interface{}{ 1624 "a/a.go": `package a`, 1625 }}, { 1626 Name: "golang.org/gopathb", 1627 Files: map[string]interface{}{ 1628 "b/b.c": `package b`, 1629 }}}) 1630 defer exported.Cleanup() 1631 config := packages.Config{Env: append(os.Environ(), "GOPACKAGESDRIVER=off")} 1632 pkgs, err := packages.Load(&config, "b/b.c") 1633 if err != nil { 1634 return 1635 } 1636 // Go <1.14 calls the package command-line-arguments while Go 1.14+ uses the file names. 1637 if len(pkgs) != 1 || (pkgs[0].PkgPath != "command-line-arguments" && pkgs[0].PkgPath != "b/b.c") { 1638 t.Fatalf("packages.Load: want [command-line-arguments] or [b/b.c], got %v", pkgs) 1639 } 1640 if len(pkgs[0].Errors) != 1 { 1641 t.Fatalf("result of Load: want package with one error, got: %+v", pkgs[0]) 1642 } 1643 } 1644 1645 func TestReturnErrorWhenUsingGoFilesInMultipleDirectories(t *testing.T) { 1646 testAllOrModulesParallel(t, testReturnErrorWhenUsingGoFilesInMultipleDirectories) 1647 } 1648 func testReturnErrorWhenUsingGoFilesInMultipleDirectories(t *testing.T, exporter packagestest.Exporter) { 1649 exported := packagestest.Export(t, exporter, []packagestest.Module{{ 1650 Name: "golang.org/gopatha", 1651 Files: map[string]interface{}{ 1652 "a/a.go": `package a`, 1653 "b/b.go": `package b`, 1654 }}}) 1655 defer exported.Cleanup() 1656 want := "named files must all be in one directory" 1657 pkgs, err := packages.Load(exported.Config, exported.File("golang.org/gopatha", "a/a.go"), exported.File("golang.org/gopatha", "b/b.go")) 1658 if err != nil { 1659 // Check if the error returned is the one we expected. 1660 if !strings.Contains(err.Error(), want) { 1661 t.Fatalf("want error message: %s, got: %s", want, err.Error()) 1662 } 1663 return 1664 } 1665 if len(pkgs) != 1 || pkgs[0].PkgPath != "command-line-arguments" { 1666 t.Fatalf("packages.Load: want [command-line-arguments], got %v", pkgs) 1667 } 1668 if len(pkgs[0].Errors) != 1 { 1669 t.Fatalf("result of Load: want package with one error, got: %+v", pkgs[0]) 1670 } 1671 got := pkgs[0].Errors[0].Error() 1672 if !strings.Contains(got, want) { 1673 t.Fatalf("want error message: %s, got: %s", want, got) 1674 } 1675 } 1676 1677 func TestReturnErrorForUnexpectedDirectoryLayout(t *testing.T) { 1678 testAllOrModulesParallel(t, testReturnErrorForUnexpectedDirectoryLayout) 1679 } 1680 func testReturnErrorForUnexpectedDirectoryLayout(t *testing.T, exporter packagestest.Exporter) { 1681 exported := packagestest.Export(t, exporter, []packagestest.Module{{ 1682 Name: "golang.org/gopatha", 1683 Files: map[string]interface{}{ 1684 "a/testdata/a.go": `package a; import _ "b"`, 1685 "a/vendor/b/b.go": `package b; import _ "fmt"`, 1686 }}}) 1687 defer exported.Cleanup() 1688 want := "unexpected directory layout" 1689 // triggering this error requires a relative package path 1690 exported.Config.Dir = filepath.Dir(exported.File("golang.org/gopatha", "a/testdata/a.go")) 1691 pkgs, err := packages.Load(exported.Config, ".") 1692 1693 // This error doesn't seem to occur in module mode; so only 1694 // complain if we get zero packages while also getting no error. 1695 if err == nil { 1696 if len(pkgs) == 0 { 1697 // TODO(dh): we'll need to expand on the error check if/when Go stops emitting this error 1698 t.Fatalf("want error, got nil") 1699 } 1700 return 1701 } 1702 // Check if the error returned is the one we expected. 1703 if !strings.Contains(err.Error(), want) { 1704 t.Fatalf("want error message: %s, got: %s", want, err.Error()) 1705 } 1706 } 1707 1708 func TestMissingDependency(t *testing.T) { testAllOrModulesParallel(t, testMissingDependency) } 1709 func testMissingDependency(t *testing.T, exporter packagestest.Exporter) { 1710 exported := packagestest.Export(t, exporter, []packagestest.Module{{ 1711 Name: "golang.org/fake", 1712 Files: map[string]interface{}{ 1713 "a/a.go": `package a; import _ "this/package/doesnt/exist"`, 1714 }}}) 1715 defer exported.Cleanup() 1716 1717 exported.Config.Mode = packages.LoadAllSyntax 1718 pkgs, err := packages.Load(exported.Config, "golang.org/fake/a") 1719 if err != nil { 1720 t.Fatal(err) 1721 } 1722 if len(pkgs) != 1 && pkgs[0].PkgPath != "golang.org/fake/a" { 1723 t.Fatalf("packages.Load: want [golang.org/fake/a], got %v", pkgs) 1724 } 1725 if len(pkgs[0].Errors) == 0 { 1726 t.Errorf("result of Load: want package with errors, got none: %+v", pkgs[0]) 1727 } 1728 } 1729 1730 func TestAdHocContains(t *testing.T) { testAllOrModulesParallel(t, testAdHocContains) } 1731 func testAdHocContains(t *testing.T, exporter packagestest.Exporter) { 1732 exported := packagestest.Export(t, exporter, []packagestest.Module{{ 1733 Name: "golang.org/fake", 1734 Files: map[string]interface{}{ 1735 "a/a.go": `package a;`, 1736 }}}) 1737 defer exported.Cleanup() 1738 1739 tmpfile, err := ioutil.TempFile("", "adhoc*.go") 1740 filename := tmpfile.Name() 1741 if err != nil { 1742 t.Fatal(err) 1743 } 1744 fmt.Fprint(tmpfile, `package main; import "fmt"; func main() { fmt.Println("time for coffee") }`) 1745 if err := tmpfile.Close(); err != nil { 1746 t.Fatal(err) 1747 } 1748 1749 defer func() { 1750 if err := os.Remove(filename); err != nil { 1751 t.Fatal(err) 1752 } 1753 }() 1754 1755 exported.Config.Mode = packages.NeedImports | packages.NeedFiles 1756 pkgs, err := packages.Load(exported.Config, "file="+filename) 1757 if err != nil { 1758 t.Fatal(err) 1759 } 1760 if len(pkgs) != 1 && pkgs[0].PkgPath != "command-line-arguments" { 1761 t.Fatalf("packages.Load: want [command-line-arguments], got %v", pkgs) 1762 } 1763 pkg := pkgs[0] 1764 if _, ok := pkg.Imports["fmt"]; !ok || len(pkg.Imports) != 1 { 1765 t.Fatalf("Imports of loaded package: want [fmt], got %v", pkg.Imports) 1766 } 1767 if len(pkg.GoFiles) != 1 || pkg.GoFiles[0] != filename { 1768 t.Fatalf("GoFiles of loaded package: want [%s], got %v", filename, pkg.GoFiles) 1769 } 1770 } 1771 1772 func TestCgoNoCcompiler(t *testing.T) { testAllOrModulesParallel(t, testCgoNoCcompiler) } 1773 func testCgoNoCcompiler(t *testing.T, exporter packagestest.Exporter) { 1774 testenv.NeedsTool(t, "cgo") 1775 exported := packagestest.Export(t, exporter, []packagestest.Module{{ 1776 Name: "golang.org/fake", 1777 Files: map[string]interface{}{ 1778 "a/a.go": `package a 1779 import "net/http" 1780 const A = http.MethodGet 1781 `, 1782 }}}) 1783 defer exported.Cleanup() 1784 1785 // Explicitly enable cgo but configure a nonexistent C compiler. 1786 exported.Config.Env = append(exported.Config.Env, "CGO_ENABLED=1", "CC=doesnotexist") 1787 exported.Config.Mode = packages.LoadAllSyntax 1788 initial, err := packages.Load(exported.Config, "golang.org/fake/a") 1789 1790 if err != nil { 1791 t.Fatal(err) 1792 } 1793 1794 // Check value of a.A. 1795 a := initial[0] 1796 aA := constant(a, "A") 1797 if aA == nil { 1798 t.Fatalf("a.A: got nil") 1799 } 1800 got := aA.Val().String() 1801 if got != "\"GET\"" { 1802 t.Errorf("a.A: got %s, want %s", got, "\"GET\"") 1803 } 1804 } 1805 1806 func TestCgoMissingFile(t *testing.T) { testAllOrModulesParallel(t, testCgoMissingFile) } 1807 func testCgoMissingFile(t *testing.T, exporter packagestest.Exporter) { 1808 testenv.NeedsTool(t, "cgo") 1809 exported := packagestest.Export(t, exporter, []packagestest.Module{{ 1810 Name: "golang.org/fake", 1811 Files: map[string]interface{}{ 1812 "a/a.go": `package a 1813 1814 // #include "foo.h" 1815 import "C" 1816 1817 const A = 4 1818 `, 1819 }}}) 1820 defer exported.Cleanup() 1821 1822 // Explicitly enable cgo. 1823 exported.Config.Env = append(exported.Config.Env, "CGO_ENABLED=1") 1824 exported.Config.Mode = packages.LoadAllSyntax 1825 initial, err := packages.Load(exported.Config, "golang.org/fake/a") 1826 1827 if err != nil { 1828 t.Fatal(err) 1829 } 1830 1831 // Check value of a.A. 1832 a := initial[0] 1833 aA := constant(a, "A") 1834 if aA == nil { 1835 t.Fatalf("a.A: got nil") 1836 } 1837 got := aA.Val().String() 1838 if got != "4" { 1839 t.Errorf("a.A: got %s, want %s", got, "4") 1840 } 1841 } 1842 1843 func TestLoadImportsC(t *testing.T) { 1844 // This test checks that when a package depends on the 1845 // test variant of "syscall", "unsafe", or "runtime/cgo", that dependency 1846 // is not removed when those packages are added when it imports "C". 1847 // 1848 // For this test to work, the external test of syscall must have a dependency 1849 // on net, and net must import "syscall" and "C". 1850 if runtime.GOOS == "windows" { 1851 t.Skipf("skipping on windows; packages on windows do not satisfy conditions for test.") 1852 } 1853 if runtime.GOOS == "plan9" { 1854 // See https://golang.org/issue/27100. 1855 t.Skip(`skipping on plan9; for some reason "net [syscall.test]" is not loaded`) 1856 } 1857 t.Parallel() 1858 testenv.NeedsGoPackages(t) 1859 1860 cfg := &packages.Config{ 1861 Context: testCtx, 1862 Mode: packages.LoadImports, 1863 Tests: true, 1864 } 1865 initial, err := packages.Load(cfg, "syscall", "net") 1866 if err != nil { 1867 t.Fatalf("failed to load imports: %v", err) 1868 } 1869 1870 _, all := importGraph(initial) 1871 1872 for _, test := range []struct { 1873 pattern string 1874 wantImport string // an import to check for 1875 }{ 1876 {"net", "syscall:syscall"}, 1877 {"net [syscall.test]", "syscall:syscall [syscall.test]"}, 1878 {"syscall_test [syscall.test]", "net:net [syscall.test]"}, 1879 } { 1880 // Test the import paths. 1881 pkg := all[test.pattern] 1882 if pkg == nil { 1883 t.Errorf("package %q not loaded", test.pattern) 1884 continue 1885 } 1886 if imports := strings.Join(imports(pkg), " "); !strings.Contains(imports, test.wantImport) { 1887 t.Errorf("package %q: got \n%s, \nwant to have %s", test.pattern, imports, test.wantImport) 1888 } 1889 } 1890 } 1891 1892 func TestCgoNoSyntax(t *testing.T) { 1893 testAllOrModulesParallel(t, testCgoNoSyntax) 1894 } 1895 func testCgoNoSyntax(t *testing.T, exporter packagestest.Exporter) { 1896 testenv.NeedsTool(t, "cgo") 1897 1898 exported := packagestest.Export(t, exporter, []packagestest.Module{{ 1899 Name: "golang.org/fake", 1900 Files: map[string]interface{}{ 1901 "c/c.go": `package c; import "C"`, 1902 }, 1903 }}) 1904 1905 // Explicitly enable cgo. 1906 exported.Config.Env = append(exported.Config.Env, "CGO_ENABLED=1") 1907 1908 modes := []packages.LoadMode{ 1909 packages.NeedTypes, 1910 packages.NeedName | packages.NeedTypes, 1911 packages.NeedName | packages.NeedTypes | packages.NeedImports, 1912 packages.NeedName | packages.NeedTypes | packages.NeedImports | packages.NeedDeps, 1913 packages.NeedName | packages.NeedImports, 1914 } 1915 for _, mode := range modes { 1916 mode := mode 1917 t.Run(fmt.Sprint(mode), func(t *testing.T) { 1918 exported.Config.Mode = mode 1919 pkgs, err := packages.Load(exported.Config, "golang.org/fake/c") 1920 if err != nil { 1921 t.Fatal(err) 1922 } 1923 if len(pkgs) != 1 { 1924 t.Fatalf("Expected 1 package, got %v", pkgs) 1925 } 1926 pkg := pkgs[0] 1927 if len(pkg.Errors) != 0 { 1928 t.Fatalf("Expected no errors in package, got %v", pkg.Errors) 1929 } 1930 }) 1931 } 1932 } 1933 1934 func TestCgoBadPkgConfig(t *testing.T) { 1935 testAllOrModulesParallel(t, testCgoBadPkgConfig) 1936 } 1937 func testCgoBadPkgConfig(t *testing.T, exporter packagestest.Exporter) { 1938 skipIfShort(t, "builds and links a fake pkgconfig binary") 1939 testenv.NeedsTool(t, "cgo") 1940 1941 exported := packagestest.Export(t, exporter, []packagestest.Module{{ 1942 Name: "golang.org/fake", 1943 Files: map[string]interface{}{ 1944 "c/c.go": `package c 1945 1946 // #cgo pkg-config: --cflags -- foo 1947 import "C"`, 1948 }, 1949 }}) 1950 1951 dir := buildFakePkgconfig(t, exported.Config.Env) 1952 defer os.RemoveAll(dir) 1953 env := exported.Config.Env 1954 for i, v := range env { 1955 if strings.HasPrefix(v, "PATH=") { 1956 env[i] = "PATH=" + dir + string(os.PathListSeparator) + v[len("PATH="):] 1957 } 1958 } 1959 1960 exported.Config.Env = append(exported.Config.Env, "CGO_ENABLED=1") 1961 1962 exported.Config.Mode = packages.NeedName | packages.NeedCompiledGoFiles 1963 pkgs, err := packages.Load(exported.Config, "golang.org/fake/c") 1964 if err != nil { 1965 t.Fatal(err) 1966 } 1967 if len(pkgs) != 1 { 1968 t.Fatalf("Expected 1 package, got %v", pkgs) 1969 } 1970 if pkgs[0].Name != "c" { 1971 t.Fatalf("Expected package to have name \"c\", got %q", pkgs[0].Name) 1972 } 1973 } 1974 1975 func buildFakePkgconfig(t *testing.T, env []string) string { 1976 tmpdir, err := ioutil.TempDir("", "fakepkgconfig") 1977 if err != nil { 1978 t.Fatal(err) 1979 } 1980 err = ioutil.WriteFile(filepath.Join(tmpdir, "pkg-config.go"), []byte(` 1981 package main 1982 1983 import "fmt" 1984 import "os" 1985 1986 func main() { 1987 fmt.Fprintln(os.Stderr, "bad") 1988 os.Exit(2) 1989 } 1990 `), 0644) 1991 if err != nil { 1992 os.RemoveAll(tmpdir) 1993 t.Fatal(err) 1994 } 1995 cmd := exec.Command("go", "build", "-o", "pkg-config", "pkg-config.go") 1996 cmd.Dir = tmpdir 1997 cmd.Env = env 1998 1999 if b, err := cmd.CombinedOutput(); err != nil { 2000 os.RemoveAll(tmpdir) 2001 fmt.Println(os.Environ()) 2002 t.Log(string(b)) 2003 t.Fatal(err) 2004 } 2005 return tmpdir 2006 } 2007 2008 func TestIssue32814(t *testing.T) { testAllOrModulesParallel(t, testIssue32814) } 2009 func testIssue32814(t *testing.T, exporter packagestest.Exporter) { 2010 exported := packagestest.Export(t, exporter, []packagestest.Module{{ 2011 Name: "golang.org/fake", 2012 Files: map[string]interface{}{}}}) 2013 defer exported.Cleanup() 2014 2015 exported.Config.Mode = packages.NeedName | packages.NeedTypes | packages.NeedSyntax | packages.NeedTypesInfo | packages.NeedTypesSizes 2016 pkgs, err := packages.Load(exported.Config, "fmt") 2017 2018 if err != nil { 2019 t.Fatal(err) 2020 } 2021 2022 if len(pkgs) != 1 && pkgs[0].PkgPath != "fmt" { 2023 t.Fatalf("packages.Load: want [fmt], got %v", pkgs) 2024 } 2025 pkg := pkgs[0] 2026 if len(pkg.Errors) != 0 { 2027 t.Fatalf("Errors for fmt pkg: got %v, want none", pkg.Errors) 2028 } 2029 if !pkg.Types.Complete() { 2030 t.Fatalf("Types.Complete() for fmt pkg: got %v, want true", pkgs[0].Types.Complete()) 2031 2032 } 2033 } 2034 2035 func TestLoadTypesInfoWithoutNeedDeps(t *testing.T) { 2036 testAllOrModulesParallel(t, testLoadTypesInfoWithoutNeedDeps) 2037 } 2038 func testLoadTypesInfoWithoutNeedDeps(t *testing.T, exporter packagestest.Exporter) { 2039 exported := packagestest.Export(t, exporter, []packagestest.Module{{ 2040 Name: "golang.org/fake", 2041 Files: map[string]interface{}{ 2042 "a/a.go": `package a; import _ "golang.org/fake/b"`, 2043 "b/b.go": `package b`, 2044 }}}) 2045 defer exported.Cleanup() 2046 2047 exported.Config.Mode = packages.NeedTypes | packages.NeedTypesInfo | packages.NeedImports 2048 pkgs, err := packages.Load(exported.Config, "golang.org/fake/a") 2049 if err != nil { 2050 t.Fatal(err) 2051 } 2052 pkg := pkgs[0] 2053 if pkg.IllTyped { 2054 t.Fatal("Loaded package is ill typed") 2055 } 2056 const expectedImport = "golang.org/fake/b" 2057 if _, ok := pkg.Imports[expectedImport]; !ok || len(pkg.Imports) != 1 { 2058 t.Fatalf("Imports of loaded package: want [%s], got %v", expectedImport, pkg.Imports) 2059 } 2060 } 2061 2062 func TestLoadWithNeedDeps(t *testing.T) { 2063 testAllOrModulesParallel(t, testLoadWithNeedDeps) 2064 } 2065 func testLoadWithNeedDeps(t *testing.T, exporter packagestest.Exporter) { 2066 exported := packagestest.Export(t, exporter, []packagestest.Module{{ 2067 Name: "golang.org/fake", 2068 Files: map[string]interface{}{ 2069 "a/a.go": `package a; import _ "golang.org/fake/b"`, 2070 "b/b.go": `package b; import _ "golang.org/fake/c"`, 2071 "c/c.go": `package c`, 2072 }}}) 2073 defer exported.Cleanup() 2074 2075 exported.Config.Mode = packages.NeedTypes | packages.NeedTypesInfo | packages.NeedImports | packages.NeedDeps 2076 pkgs, err := packages.Load(exported.Config, "golang.org/fake/a") 2077 if err != nil { 2078 t.Fatal(err) 2079 } 2080 if len(pkgs) != 1 { 2081 t.Fatalf("Expected 1 package, got %d", len(pkgs)) 2082 } 2083 2084 pkgA := pkgs[0] 2085 if pkgA.IllTyped { 2086 t.Fatal("Loaded package is ill typed") 2087 } 2088 2089 pkgB := pkgA.Imports["golang.org/fake/b"] 2090 if pkgB == nil || len(pkgA.Imports) != 1 { 2091 t.Fatalf("Imports of loaded package 'a' are invalid: %v", pkgA.Imports) 2092 } 2093 if pkgB.Types == nil || !pkgB.Types.Complete() || pkgB.TypesInfo == nil { 2094 t.Fatalf("Types of package 'b' are nil or incomplete: %v, %v", pkgB.Types, pkgB.TypesInfo) 2095 } 2096 2097 pkgC := pkgB.Imports["golang.org/fake/c"] 2098 if pkgC == nil || len(pkgB.Imports) != 1 { 2099 t.Fatalf("Imports of loaded package 'c' are invalid: %v", pkgB.Imports) 2100 } 2101 if pkgC.Types == nil || !pkgC.Types.Complete() || pkgC.TypesInfo == nil { 2102 t.Fatalf("Types of package 'b' are nil or incomplete: %v, %v", pkgC.Types, pkgC.TypesInfo) 2103 } 2104 } 2105 2106 func TestImpliedLoadMode(t *testing.T) { 2107 testAllOrModulesParallel(t, testImpliedLoadMode) 2108 } 2109 func testImpliedLoadMode(t *testing.T, exporter packagestest.Exporter) { 2110 exported := packagestest.Export(t, exporter, []packagestest.Module{{ 2111 Name: "golang.org/fake", 2112 Files: map[string]interface{}{ 2113 "a/a.go": `package a; import _ "golang.org/fake/b"`, 2114 "b/b.go": `package b`, 2115 }}}) 2116 defer exported.Cleanup() 2117 2118 exported.Config.Mode = packages.NeedTypes | packages.NeedTypesInfo 2119 pkgs, err := packages.Load(exported.Config, "golang.org/fake/a") 2120 if err != nil { 2121 t.Fatal(err) 2122 } 2123 if len(pkgs) != 1 { 2124 t.Fatalf("Expected 1 package, got %d", len(pkgs)) 2125 } 2126 2127 pkg := pkgs[0] 2128 if pkg.IllTyped { 2129 t.Fatalf("Loaded package is ill typed: %v", pkg.Errors) 2130 } 2131 2132 // Check that packages.NeedTypesInfo worked well. 2133 if !pkg.Types.Complete() { 2134 t.Fatalf("Loaded package types are incomplete") 2135 } 2136 2137 // Check that implied packages.NeedImports by packages.NeedTypesInfo 2138 // didn't add Imports. 2139 if len(pkg.Imports) != 0 { 2140 t.Fatalf("Package imports weren't requested but were returned: %v", pkg.Imports) 2141 } 2142 } 2143 2144 func TestIssue35331(t *testing.T) { 2145 testAllOrModulesParallel(t, testIssue35331) 2146 } 2147 func testIssue35331(t *testing.T, exporter packagestest.Exporter) { 2148 exported := packagestest.Export(t, exporter, []packagestest.Module{{ 2149 Name: "golang.org/fake", 2150 }}) 2151 defer exported.Cleanup() 2152 2153 exported.Config.Mode = packages.NeedName | packages.NeedFiles | packages.NeedCompiledGoFiles | 2154 packages.NeedImports | packages.NeedDeps | packages.NeedSyntax 2155 exported.Config.Tests = false 2156 pkgs, err := packages.Load(exported.Config, "strconv") 2157 if err != nil { 2158 t.Fatal(err) 2159 } 2160 if len(pkgs) != 1 { 2161 t.Fatalf("Expected 1 package, got %v", pkgs) 2162 } 2163 packages.Visit(pkgs, func(pkg *packages.Package) bool { 2164 if len(pkg.Errors) > 0 { 2165 t.Errorf("Expected no errors in package %q, got %v", pkg.ID, pkg.Errors) 2166 } 2167 if len(pkg.Syntax) == 0 && pkg.ID != "unsafe" { 2168 t.Errorf("Expected syntax on package %q, got none.", pkg.ID) 2169 } 2170 return true 2171 }, nil) 2172 } 2173 2174 func TestMultiplePackageVersionsIssue36188(t *testing.T) { 2175 testAllOrModulesParallel(t, testMultiplePackageVersionsIssue36188) 2176 } 2177 2178 func testMultiplePackageVersionsIssue36188(t *testing.T, exporter packagestest.Exporter) { 2179 exported := packagestest.Export(t, exporter, []packagestest.Module{{ 2180 Name: "golang.org/fake", 2181 Files: map[string]interface{}{ 2182 "a/a.go": `package a; import _ "golang.org/fake/b"`, 2183 "b/b.go": `package main`, 2184 }}}) 2185 pkgs, err := packages.Load(exported.Config, "golang.org/fake/a", "golang.org/fake/b") 2186 if err != nil { 2187 t.Fatal(err) 2188 } 2189 sort.Slice(pkgs, func(i, j int) bool { return pkgs[i].ID < pkgs[j].ID }) 2190 if len(pkgs) != 2 { 2191 t.Fatalf("expected two packages, got %v", pkgs) 2192 } 2193 if pkgs[0].ID != "golang.org/fake/a" && pkgs[1].ID != "golang.org/fake/b" { 2194 t.Fatalf(`expected (sorted) IDs "golang.org/fake/a" and "golang.org/fake/b", got %q and %q`, 2195 pkgs[0].ID, pkgs[1].ID) 2196 } 2197 if pkgs[0].Errors == nil { 2198 t.Errorf(`expected error on package "golang.org/fake/a", got none`) 2199 } 2200 if pkgs[1].Errors != nil { 2201 t.Errorf(`expected no errors on package "golang.org/fake/b", got %v`, pkgs[1].Errors) 2202 } 2203 defer exported.Cleanup() 2204 } 2205 2206 func TestLoadModeStrings(t *testing.T) { 2207 testcases := []struct { 2208 mode packages.LoadMode 2209 expected string 2210 }{ 2211 { 2212 packages.LoadMode(0), 2213 "LoadMode(0)", 2214 }, 2215 { 2216 packages.NeedName, 2217 "LoadMode(NeedName)", 2218 }, 2219 { 2220 packages.NeedFiles, 2221 "LoadMode(NeedFiles)", 2222 }, 2223 { 2224 packages.NeedCompiledGoFiles, 2225 "LoadMode(NeedCompiledGoFiles)", 2226 }, 2227 { 2228 packages.NeedImports, 2229 "LoadMode(NeedImports)", 2230 }, 2231 { 2232 packages.NeedDeps, 2233 "LoadMode(NeedDeps)", 2234 }, 2235 { 2236 packages.NeedExportsFile, 2237 "LoadMode(NeedExportsFile)", 2238 }, 2239 { 2240 packages.NeedTypes, 2241 "LoadMode(NeedTypes)", 2242 }, 2243 { 2244 packages.NeedSyntax, 2245 "LoadMode(NeedSyntax)", 2246 }, 2247 { 2248 packages.NeedTypesInfo, 2249 "LoadMode(NeedTypesInfo)", 2250 }, 2251 { 2252 packages.NeedTypesSizes, 2253 "LoadMode(NeedTypesSizes)", 2254 }, 2255 { 2256 packages.NeedName | packages.NeedExportsFile, 2257 "LoadMode(NeedName|NeedExportsFile)", 2258 }, 2259 { 2260 packages.NeedName | packages.NeedFiles | packages.NeedCompiledGoFiles | packages.NeedImports | packages.NeedDeps | packages.NeedExportsFile | packages.NeedTypes | packages.NeedSyntax | packages.NeedTypesInfo | packages.NeedTypesSizes, 2261 "LoadMode(NeedName|NeedFiles|NeedCompiledGoFiles|NeedImports|NeedDeps|NeedExportsFile|NeedTypes|NeedSyntax|NeedTypesInfo|NeedTypesSizes)", 2262 }, 2263 { 2264 packages.NeedName | 8192, 2265 "LoadMode(NeedName|Unknown)", 2266 }, 2267 { 2268 4096, 2269 "LoadMode(Unknown)", 2270 }, 2271 } 2272 2273 for tcInd, tc := range testcases { 2274 t.Run(fmt.Sprintf("test-%d", tcInd), func(t *testing.T) { 2275 actual := tc.mode.String() 2276 if tc.expected != actual { 2277 t.Errorf("want %#v, got %#v", tc.expected, actual) 2278 } 2279 }) 2280 } 2281 } 2282 2283 func TestCycleImportStack(t *testing.T) { 2284 testAllOrModulesParallel(t, testCycleImportStack) 2285 } 2286 func testCycleImportStack(t *testing.T, exporter packagestest.Exporter) { 2287 exported := packagestest.Export(t, exporter, []packagestest.Module{{ 2288 Name: "golang.org/fake", 2289 Files: map[string]interface{}{ 2290 "a/a.go": `package a; import _ "golang.org/fake/b"`, 2291 "b/b.go": `package b; import _ "golang.org/fake/a"`, 2292 }}}) 2293 defer exported.Cleanup() 2294 2295 exported.Config.Mode = packages.NeedName | packages.NeedImports 2296 pkgs, err := packages.Load(exported.Config, "golang.org/fake/a") 2297 if err != nil { 2298 t.Fatal(err) 2299 } 2300 if len(pkgs) != 1 { 2301 t.Fatalf("Expected 1 package, got %v", pkgs) 2302 } 2303 pkg := pkgs[0] 2304 if len(pkg.Errors) != 1 { 2305 t.Fatalf("Expected one error in package, got %v", pkg.Errors) 2306 } 2307 expected := "import cycle not allowed: import stack: [golang.org/fake/a golang.org/fake/b golang.org/fake/a]" 2308 if pkg.Errors[0].Msg != expected { 2309 t.Fatalf("Expected error %q, got %q", expected, pkg.Errors[0].Msg) 2310 } 2311 } 2312 2313 func TestForTestField(t *testing.T) { 2314 testAllOrModulesParallel(t, testForTestField) 2315 } 2316 func testForTestField(t *testing.T, exporter packagestest.Exporter) { 2317 exported := packagestest.Export(t, exporter, []packagestest.Module{{ 2318 Name: "golang.org/fake", 2319 Files: map[string]interface{}{ 2320 "a/a.go": `package a; func hello() {};`, 2321 "a/a_test.go": `package a; import "testing"; func TestA1(t *testing.T) {};`, 2322 "a/x_test.go": `package a_test; import "testing"; func TestA2(t *testing.T) {};`, 2323 }}}) 2324 defer exported.Cleanup() 2325 2326 // Add overlays to make sure they don't affect anything. 2327 exported.Config.Overlay = map[string][]byte{ 2328 "a/a_test.go": []byte(`package a; import "testing"; func TestA1(t *testing.T) { hello(); };`), 2329 "a/x_test.go": []byte(`package a_test; import "testing"; func TestA2(t *testing.T) { hello(); };`), 2330 } 2331 exported.Config.Tests = true 2332 exported.Config.Mode = packages.NeedName | packages.NeedImports 2333 forTest := "golang.org/fake/a" 2334 pkgs, err := packages.Load(exported.Config, forTest) 2335 if err != nil { 2336 t.Fatal(err) 2337 } 2338 if len(pkgs) != 4 { 2339 t.Errorf("expected 4 packages, got %v", len(pkgs)) 2340 } 2341 for _, pkg := range pkgs { 2342 var hasTestFile bool 2343 for _, f := range pkg.CompiledGoFiles { 2344 if strings.Contains(f, "a_test.go") || strings.Contains(f, "x_test.go") { 2345 hasTestFile = true 2346 break 2347 } 2348 } 2349 if !hasTestFile { 2350 continue 2351 } 2352 got := packagesinternal.GetForTest(pkg) 2353 if got != forTest { 2354 t.Errorf("expected %q, got %q", forTest, got) 2355 } 2356 } 2357 } 2358 2359 func TestIssue37529(t *testing.T) { 2360 testAllOrModulesParallel(t, testIssue37529) 2361 } 2362 func testIssue37529(t *testing.T, exporter packagestest.Exporter) { 2363 // Tests #37529. When automatic vendoring is triggered, and we try to determine 2364 // the module root dir for a new overlay package, we previously would do a go list -m all, 2365 // which is incompatible with automatic vendoring. 2366 2367 exported := packagestest.Export(t, exporter, []packagestest.Module{{ 2368 Name: "golang.org/fake", 2369 Files: map[string]interface{}{ 2370 "c/c2.go": `package c`, 2371 "a/a.go": `package a; import "b.com/b"; const A = b.B`, 2372 "vendor/b.com/b/b.go": `package b; const B = 4`, 2373 }}}) 2374 rootDir := filepath.Dir(filepath.Dir(exported.File("golang.org/fake", "a/a.go"))) 2375 exported.Config.Overlay = map[string][]byte{ 2376 filepath.Join(rootDir, "c/c.go"): []byte(`package c; import "golang.org/fake/a"; const C = a.A`), 2377 } 2378 exported.Config.Env = append(exported.Config.Env, "GOFLAGS=-mod=vendor") 2379 exported.Config.Mode = packages.LoadAllSyntax 2380 2381 defer exported.Cleanup() 2382 2383 initial, err := packages.Load(exported.Config, "golang.org/fake/c") 2384 if err != nil { 2385 t.Fatal(err) 2386 } 2387 2388 // Check value of a.A. 2389 a := initial[0] 2390 aA := constant(a, "C") 2391 if aA == nil { 2392 t.Fatalf("a.A: got nil") 2393 } 2394 got := aA.Val().String() 2395 if got != "4" { 2396 t.Errorf("a.A: got %s, want %s", got, "4") 2397 } 2398 } 2399 2400 func TestIssue37098(t *testing.T) { testAllOrModulesParallel(t, testIssue37098) } 2401 func testIssue37098(t *testing.T, exporter packagestest.Exporter) { 2402 // packages.Load should only return Go sources in 2403 // (*Package).CompiledGoFiles. This tests #37098, where using SWIG to 2404 // causes C++ sources to be inadvertently included in 2405 // (*Package).CompiledGoFiles. 2406 2407 // This is fixed in Go 1.17, but not earlier. 2408 testenv.NeedsGo1Point(t, 17) 2409 2410 if _, err := exec.LookPath("swig"); err != nil { 2411 t.Skip("skipping test: swig not available") 2412 } 2413 if _, err := exec.LookPath("g++"); err != nil { 2414 t.Skip("skipping test: g++ not available") 2415 } 2416 2417 // Create a fake package with an empty Go source, and a SWIG interface 2418 // file. 2419 exported := packagestest.Export(t, exporter, []packagestest.Module{{ 2420 Name: "golang.org/fake", 2421 Files: map[string]interface{}{ 2422 // The "package" statement must be included for SWIG sources to 2423 // be generated. 2424 "a/a.go": "package a", 2425 "a/a.swigcxx": "", 2426 }}}) 2427 defer exported.Cleanup() 2428 2429 initial, err := packages.Load(exported.Config, "golang.org/fake/a") 2430 if err != nil { 2431 t.Fatalf("failed to load the package: %v", err) 2432 } 2433 // Try and parse each of the files 2434 for _, pkg := range initial { 2435 for _, file := range pkg.CompiledGoFiles { 2436 2437 // Validate that each file can be parsed as a Go source. 2438 fset := token.NewFileSet() 2439 _, err := parser.ParseFile(fset, file, nil, parser.ImportsOnly) 2440 if err != nil { 2441 t.Errorf("Failed to parse file '%s' as a Go source: %v", file, err) 2442 2443 contents, err := ioutil.ReadFile(file) 2444 if err != nil { 2445 t.Fatalf("Failed to read the un-parsable file '%s': %v", file, err) 2446 } 2447 2448 // Print out some of the un-parsable file to aid in debugging. 2449 n := len(contents) 2450 2451 // Don't print the whole file if it is too large. 2452 const maxBytes = 1000 2453 if n > maxBytes { 2454 n = maxBytes 2455 } 2456 2457 t.Logf("First %d bytes of un-parsable file: %s", n, contents[:n]) 2458 } 2459 } 2460 } 2461 } 2462 2463 // TestInvalidFilesInXTest checks the fix for golang/go#37971 in Go 1.15. 2464 func TestInvalidFilesInXTest(t *testing.T) { testAllOrModulesParallel(t, testInvalidFilesInXTest) } 2465 func testInvalidFilesInXTest(t *testing.T, exporter packagestest.Exporter) { 2466 testenv.NeedsGo1Point(t, 15) 2467 exported := packagestest.Export(t, exporter, []packagestest.Module{ 2468 { 2469 Name: "golang.org/fake", 2470 Files: map[string]interface{}{ 2471 "d/d.go": `package d; import "net/http"; const d = http.MethodGet; func Get() string { return d; }`, 2472 "d/d2.go": ``, // invalid file 2473 "d/d_test.go": `package d_test; import "testing"; import "golang.org/fake/d"; func TestD(t *testing.T) { d.Get(); }`, 2474 }, 2475 }, 2476 }) 2477 defer exported.Cleanup() 2478 2479 exported.Config.Mode = packages.NeedName | packages.NeedFiles 2480 exported.Config.Tests = true 2481 2482 initial, err := packages.Load(exported.Config, "golang.org/fake/d") 2483 if err != nil { 2484 t.Fatal(err) 2485 } 2486 if len(initial) != 3 { 2487 t.Errorf("expected 3 packages, got %d", len(initial)) 2488 } 2489 } 2490 2491 func TestTypecheckCgo(t *testing.T) { testAllOrModulesParallel(t, testTypecheckCgo) } 2492 func testTypecheckCgo(t *testing.T, exporter packagestest.Exporter) { 2493 testenv.NeedsGo1Point(t, 15) 2494 testenv.NeedsTool(t, "cgo") 2495 2496 const cgo = `package cgo 2497 import "C" 2498 2499 func Example() { 2500 C.CString("hi") 2501 } 2502 ` 2503 exported := packagestest.Export(t, exporter, []packagestest.Module{ 2504 { 2505 Name: "golang.org/fake", 2506 Files: map[string]interface{}{ 2507 "cgo/cgo.go": cgo, 2508 }, 2509 }, 2510 }) 2511 defer exported.Cleanup() 2512 2513 exported.Config.Mode = packages.NeedFiles | packages.NeedCompiledGoFiles | 2514 packages.NeedSyntax | packages.NeedDeps | packages.NeedTypes | 2515 packages.LoadMode(packagesinternal.TypecheckCgo) 2516 2517 initial, err := packages.Load(exported.Config, "golang.org/fake/cgo") 2518 if err != nil { 2519 t.Fatal(err) 2520 } 2521 pkg := initial[0] 2522 if len(pkg.Errors) != 0 { 2523 t.Fatalf("package has errors: %v", pkg.Errors) 2524 } 2525 2526 expos := pkg.Types.Scope().Lookup("Example").Pos() 2527 fname := pkg.Fset.File(expos).Name() 2528 if !strings.HasSuffix(fname, "cgo.go") { 2529 t.Errorf("position for cgo package was loaded from %v, wanted cgo.go", fname) 2530 } 2531 } 2532 2533 func TestModule(t *testing.T) { 2534 testAllOrModulesParallel(t, testModule) 2535 } 2536 func testModule(t *testing.T, exporter packagestest.Exporter) { 2537 exported := packagestest.Export(t, exporter, []packagestest.Module{{ 2538 Name: "golang.org/fake", 2539 Files: map[string]interface{}{"a/a.go": `package a`}}}) 2540 exported.Config.Mode = packages.NeedModule 2541 rootDir := filepath.Dir(filepath.Dir(exported.File("golang.org/fake", "a/a.go"))) 2542 2543 initial, err := packages.Load(exported.Config, "golang.org/fake/a") 2544 if err != nil { 2545 t.Fatal(err) 2546 } 2547 2548 if len(initial) != 1 { 2549 t.Fatal("want exactly one package, got ", initial) 2550 } 2551 a := initial[0] 2552 switch exported.Exporter.Name() { 2553 case "GOPATH": 2554 if a.Module != nil { 2555 t.Fatal("package.Module: want nil, got ", a.Module) 2556 } 2557 case "Modules": 2558 // Make sure Modules field is set, and spot check a few of its fields. 2559 if a.Module == nil { 2560 t.Fatal("package.Module: want non-nil, got nil") 2561 } 2562 if a.Module.Path != "golang.org/fake" { 2563 t.Fatalf("package.Modile.Path: want \"golang.org/fake\", got %q", a.Module.Path) 2564 } 2565 if a.Module.GoMod != filepath.Join(rootDir, "go.mod") { 2566 t.Fatalf("package.Module.GoMod: want %q, got %q", filepath.Join(rootDir, "go.mod"), a.Module.GoMod) 2567 } 2568 default: 2569 t.Fatalf("Expected exporter to be GOPATH or Modules, got %v", exported.Exporter.Name()) 2570 } 2571 } 2572 2573 func TestExternal_NotHandled(t *testing.T) { 2574 testAllOrModulesParallel(t, testExternal_NotHandled) 2575 } 2576 func testExternal_NotHandled(t *testing.T, exporter packagestest.Exporter) { 2577 skipIfShort(t, "builds and links fake driver binaries") 2578 testenv.NeedsGoBuild(t) 2579 2580 tempdir, err := ioutil.TempDir("", "testexternal") 2581 if err != nil { 2582 t.Fatal(err) 2583 } 2584 defer os.RemoveAll(tempdir) 2585 2586 exported := packagestest.Export(t, exporter, []packagestest.Module{{ 2587 Name: "golang.org/fake", 2588 Files: map[string]interface{}{ 2589 "a/a.go": `package a`, 2590 "empty_driver/main.go": `package main 2591 2592 import ( 2593 "fmt" 2594 "io/ioutil" 2595 "os" 2596 ) 2597 2598 func main() { 2599 ioutil.ReadAll(os.Stdin) 2600 fmt.Println("{}") 2601 } 2602 `, 2603 "nothandled_driver/main.go": `package main 2604 2605 import ( 2606 "fmt" 2607 "io/ioutil" 2608 "os" 2609 ) 2610 2611 func main() { 2612 ioutil.ReadAll(os.Stdin) 2613 fmt.Println("{\"NotHandled\": true}") 2614 } 2615 `, 2616 }}}) 2617 baseEnv := exported.Config.Env 2618 2619 // As a control, create a fake driver that always returns an empty response. 2620 emptyDriverPath := filepath.Join(tempdir, "empty_driver.exe") // Add .exe because Windows expects it. 2621 cmd := exec.Command("go", "build", "-o", emptyDriverPath, "golang.org/fake/empty_driver") 2622 cmd.Env = baseEnv 2623 cmd.Dir = exported.Config.Dir 2624 if b, err := cmd.CombinedOutput(); err != nil { 2625 t.Log(string(b)) 2626 t.Fatal(err) 2627 } 2628 2629 exported.Config.Env = append(append([]string{}, baseEnv...), "GOPACKAGESDRIVER="+emptyDriverPath) 2630 initial, err := packages.Load(exported.Config, "golang.org/fake/a") 2631 if err != nil { 2632 t.Fatal(err) 2633 } 2634 2635 if len(initial) != 0 { 2636 t.Errorf("package.Load with empty driver: want [], got %v", initial) 2637 } 2638 2639 // Create a fake driver that always returns a NotHandled response. 2640 notHandledDriverPath := filepath.Join(tempdir, "nothandled_driver.exe") 2641 cmd = exec.Command("go", "build", "-o", notHandledDriverPath, "golang.org/fake/nothandled_driver") 2642 cmd.Env = baseEnv 2643 cmd.Dir = exported.Config.Dir 2644 if b, err := cmd.CombinedOutput(); err != nil { 2645 t.Log(string(b)) 2646 t.Fatal(err) 2647 } 2648 2649 exported.Config.Env = append(append([]string{}, baseEnv...), "GOPACKAGESDRIVER="+notHandledDriverPath) 2650 initial, err = packages.Load(exported.Config, "golang.org/fake/a") 2651 if err != nil { 2652 t.Fatal(err) 2653 } 2654 2655 if len(initial) != 1 || initial[0].PkgPath != "golang.org/fake/a" { 2656 t.Errorf("package.Load: want [golang.org/fake/a], got %v", initial) 2657 } 2658 } 2659 2660 func TestInvalidPackageName(t *testing.T) { 2661 testAllOrModulesParallel(t, testInvalidPackageName) 2662 } 2663 2664 func testInvalidPackageName(t *testing.T, exporter packagestest.Exporter) { 2665 testenv.NeedsGo1Point(t, 15) 2666 2667 exported := packagestest.Export(t, exporter, []packagestest.Module{{ 2668 Name: "golang.org/fake", 2669 Files: map[string]interface{}{ 2670 "main.go": `package default 2671 2672 func main() { 2673 } 2674 `, 2675 }, 2676 }}) 2677 defer exported.Cleanup() 2678 2679 initial, err := packages.Load(exported.Config, "golang.org/fake") 2680 if err != nil { 2681 t.Fatal(err) 2682 } 2683 pkg := initial[0] 2684 if len(pkg.CompiledGoFiles) != 1 { 2685 t.Fatalf("expected 1 Go file in package %s, got %v", pkg.ID, len(pkg.CompiledGoFiles)) 2686 } 2687 } 2688 2689 func TestEmptyEnvironment(t *testing.T) { 2690 t.Parallel() 2691 2692 cfg := &packages.Config{ 2693 Env: []string{"FOO=BAR"}, 2694 } 2695 _, err := packages.Load(cfg, "fmt") 2696 if err == nil { 2697 t.Fatal("Load with explicitly empty environment should fail") 2698 } 2699 } 2700 2701 func errorMessages(errors []packages.Error) []string { 2702 var msgs []string 2703 for _, err := range errors { 2704 msgs = append(msgs, err.Msg) 2705 } 2706 return msgs 2707 } 2708 2709 func srcs(p *packages.Package) []string { 2710 return cleanPaths(append(p.GoFiles[:len(p.GoFiles):len(p.GoFiles)], p.OtherFiles...)) 2711 } 2712 2713 // cleanPaths attempts to reduce path names to stable forms 2714 func cleanPaths(paths []string) []string { 2715 result := make([]string, len(paths)) 2716 for i, src := range paths { 2717 // If the source file doesn't have an extension like .go or .s, 2718 // it comes from GOCACHE. The names there aren't predictable. 2719 name := filepath.Base(src) 2720 if !strings.Contains(name, ".") { 2721 result[i] = fmt.Sprintf("%d.go", i) // make cache names predictable 2722 } else { 2723 result[i] = name 2724 } 2725 } 2726 return result 2727 } 2728 2729 // importGraph returns the import graph as a user-friendly string, 2730 // and a map containing all packages keyed by ID. 2731 func importGraph(initial []*packages.Package) (string, map[string]*packages.Package) { 2732 out := new(bytes.Buffer) 2733 2734 initialSet := make(map[*packages.Package]bool) 2735 for _, p := range initial { 2736 initialSet[p] = true 2737 } 2738 2739 // We can't use Visit because we need to prune 2740 // the traversal of specific edges, not just nodes. 2741 var nodes, edges []string 2742 res := make(map[string]*packages.Package) 2743 seen := make(map[*packages.Package]bool) 2744 var visit func(p *packages.Package) 2745 visit = func(p *packages.Package) { 2746 if !seen[p] { 2747 seen[p] = true 2748 if res[p.ID] != nil { 2749 panic("duplicate ID: " + p.ID) 2750 } 2751 res[p.ID] = p 2752 2753 star := ' ' // mark initial packages with a star 2754 if initialSet[p] { 2755 star = '*' 2756 } 2757 nodes = append(nodes, fmt.Sprintf("%c %s", star, p.ID)) 2758 2759 // To avoid a lot of noise, 2760 // we prune uninteresting dependencies of testmain packages, 2761 // which we identify by this import: 2762 isTestMain := p.Imports["testing/internal/testdeps"] != nil 2763 2764 for _, imp := range p.Imports { 2765 if isTestMain { 2766 switch imp.ID { 2767 case "os", "reflect", "testing", "testing/internal/testdeps": 2768 continue 2769 } 2770 } 2771 // math/bits took on a dependency on unsafe in 1.12, which breaks some 2772 // tests. As a short term hack, prune that edge. 2773 // ditto for ("errors", "internal/reflectlite") in 1.13. 2774 // TODO(matloob): think of a cleaner solution, or remove math/bits from the test. 2775 if p.ID == "math/bits" && imp.ID == "unsafe" { 2776 continue 2777 } 2778 edges = append(edges, fmt.Sprintf("%s -> %s", p, imp)) 2779 visit(imp) 2780 } 2781 } 2782 } 2783 for _, p := range initial { 2784 visit(p) 2785 } 2786 2787 // Sort, ignoring leading optional star prefix. 2788 sort.Slice(nodes, func(i, j int) bool { return nodes[i][2:] < nodes[j][2:] }) 2789 for _, node := range nodes { 2790 fmt.Fprintf(out, "%s\n", node) 2791 } 2792 2793 sort.Strings(edges) 2794 for _, edge := range edges { 2795 fmt.Fprintf(out, " %s\n", edge) 2796 } 2797 2798 return out.String(), res 2799 } 2800 2801 func constant(p *packages.Package, name string) *types.Const { 2802 if p == nil || p.Types == nil { 2803 return nil 2804 } 2805 c := p.Types.Scope().Lookup(name) 2806 if c == nil { 2807 return nil 2808 } 2809 return c.(*types.Const) 2810 } 2811 2812 func copyAll(srcPath, dstPath string) error { 2813 return filepath.Walk(srcPath, func(path string, info os.FileInfo, _ error) error { 2814 if info.IsDir() { 2815 return nil 2816 } 2817 contents, err := ioutil.ReadFile(path) 2818 if err != nil { 2819 return err 2820 } 2821 rel, err := filepath.Rel(srcPath, path) 2822 if err != nil { 2823 return err 2824 } 2825 dstFilePath := strings.Replace(filepath.Join(dstPath, rel), "definitelynot_go.mod", "go.mod", -1) 2826 if err := os.MkdirAll(filepath.Dir(dstFilePath), 0755); err != nil { 2827 return err 2828 } 2829 if err := ioutil.WriteFile(dstFilePath, contents, 0644); err != nil { 2830 return err 2831 } 2832 return nil 2833 }) 2834 }