github.com/powerman/golang-tools@v0.1.11-0.20220410185822-5ad214d8d803/go/loader/loader_test.go (about) 1 // Copyright 2013 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 // No testdata on Android. 6 7 //go:build !android 8 // +build !android 9 10 package loader_test 11 12 import ( 13 "fmt" 14 "go/build" 15 "go/constant" 16 "go/types" 17 "os" 18 "path/filepath" 19 "reflect" 20 "runtime" 21 "sort" 22 "strings" 23 "sync" 24 "testing" 25 26 "github.com/powerman/golang-tools/go/buildutil" 27 "github.com/powerman/golang-tools/go/loader" 28 "github.com/powerman/golang-tools/internal/testenv" 29 ) 30 31 func TestMain(m *testing.M) { 32 testenv.ExitIfSmallMachine() 33 os.Exit(m.Run()) 34 } 35 36 // TestFromArgs checks that conf.FromArgs populates conf correctly. 37 // It does no I/O. 38 func TestFromArgs(t *testing.T) { 39 type result struct { 40 Err string 41 Rest []string 42 ImportPkgs map[string]bool 43 CreatePkgs []loader.PkgSpec 44 } 45 for _, test := range []struct { 46 args []string 47 tests bool 48 want result 49 }{ 50 // Mix of existing and non-existent packages. 51 { 52 args: []string{"nosuchpkg", "errors"}, 53 want: result{ 54 ImportPkgs: map[string]bool{"errors": false, "nosuchpkg": false}, 55 }, 56 }, 57 // Same, with -test flag. 58 { 59 args: []string{"nosuchpkg", "errors"}, 60 tests: true, 61 want: result{ 62 ImportPkgs: map[string]bool{"errors": true, "nosuchpkg": true}, 63 }, 64 }, 65 // Surplus arguments. 66 { 67 args: []string{"fmt", "errors", "--", "surplus"}, 68 want: result{ 69 Rest: []string{"surplus"}, 70 ImportPkgs: map[string]bool{"errors": false, "fmt": false}, 71 }, 72 }, 73 // Ad hoc package specified as *.go files. 74 { 75 args: []string{"foo.go", "bar.go"}, 76 want: result{CreatePkgs: []loader.PkgSpec{{ 77 Filenames: []string{"foo.go", "bar.go"}, 78 }}}, 79 }, 80 // Mixture of *.go and import paths. 81 { 82 args: []string{"foo.go", "fmt"}, 83 want: result{ 84 Err: "named files must be .go files: fmt", 85 }, 86 }, 87 } { 88 var conf loader.Config 89 rest, err := conf.FromArgs(test.args, test.tests) 90 got := result{ 91 Rest: rest, 92 ImportPkgs: conf.ImportPkgs, 93 CreatePkgs: conf.CreatePkgs, 94 } 95 if err != nil { 96 got.Err = err.Error() 97 } 98 if !reflect.DeepEqual(got, test.want) { 99 t.Errorf("FromArgs(%q) = %+v, want %+v", test.args, got, test.want) 100 } 101 } 102 } 103 104 func TestLoad_NoInitialPackages(t *testing.T) { 105 var conf loader.Config 106 107 const wantErr = "no initial packages were loaded" 108 109 prog, err := conf.Load() 110 if err == nil { 111 t.Errorf("Load succeeded unexpectedly, want %q", wantErr) 112 } else if err.Error() != wantErr { 113 t.Errorf("Load failed with wrong error %q, want %q", err, wantErr) 114 } 115 if prog != nil { 116 t.Errorf("Load unexpectedly returned a Program") 117 } 118 } 119 120 func TestLoad_MissingInitialPackage(t *testing.T) { 121 var conf loader.Config 122 conf.Import("nosuchpkg") 123 conf.Import("errors") 124 125 const wantErr = "couldn't load packages due to errors: nosuchpkg" 126 127 prog, err := conf.Load() 128 if err == nil { 129 t.Errorf("Load succeeded unexpectedly, want %q", wantErr) 130 } else if err.Error() != wantErr { 131 t.Errorf("Load failed with wrong error %q, want %q", err, wantErr) 132 } 133 if prog != nil { 134 t.Errorf("Load unexpectedly returned a Program") 135 } 136 } 137 138 func TestLoad_MissingInitialPackage_AllowErrors(t *testing.T) { 139 if runtime.Compiler == "gccgo" { 140 t.Skip("gccgo has no standard library test files") 141 } 142 143 var conf loader.Config 144 conf.AllowErrors = true 145 conf.Import("nosuchpkg") 146 conf.ImportWithTests("errors") 147 148 prog, err := conf.Load() 149 if err != nil { 150 t.Errorf("Load failed unexpectedly: %v", err) 151 } 152 if prog == nil { 153 t.Fatalf("Load returned a nil Program") 154 } 155 if got, want := created(prog), "errors_test"; got != want { 156 t.Errorf("Created = %s, want %s", got, want) 157 } 158 if got, want := imported(prog), "errors"; got != want { 159 t.Errorf("Imported = %s, want %s", got, want) 160 } 161 } 162 163 func TestCreateUnnamedPackage(t *testing.T) { 164 var conf loader.Config 165 conf.CreateFromFilenames("") 166 prog, err := conf.Load() 167 if err != nil { 168 t.Fatalf("Load failed: %v", err) 169 } 170 if got, want := fmt.Sprint(prog.InitialPackages()), "[(unnamed)]"; got != want { 171 t.Errorf("InitialPackages = %s, want %s", got, want) 172 } 173 } 174 175 func TestLoad_MissingFileInCreatedPackage(t *testing.T) { 176 var conf loader.Config 177 conf.CreateFromFilenames("", "missing.go") 178 179 const wantErr = "couldn't load packages due to errors: (unnamed)" 180 181 prog, err := conf.Load() 182 if prog != nil { 183 t.Errorf("Load unexpectedly returned a Program") 184 } 185 if err == nil { 186 t.Fatalf("Load succeeded unexpectedly, want %q", wantErr) 187 } 188 if err.Error() != wantErr { 189 t.Fatalf("Load failed with wrong error %q, want %q", err, wantErr) 190 } 191 } 192 193 func TestLoad_MissingFileInCreatedPackage_AllowErrors(t *testing.T) { 194 conf := loader.Config{AllowErrors: true} 195 conf.CreateFromFilenames("", "missing.go") 196 197 prog, err := conf.Load() 198 if err != nil { 199 t.Errorf("Load failed: %v", err) 200 } 201 if got, want := fmt.Sprint(prog.InitialPackages()), "[(unnamed)]"; got != want { 202 t.Fatalf("InitialPackages = %s, want %s", got, want) 203 } 204 } 205 206 func TestLoad_ParseError(t *testing.T) { 207 var conf loader.Config 208 conf.CreateFromFilenames("badpkg", "testdata/badpkgdecl.go") 209 210 const wantErr = "couldn't load packages due to errors: badpkg" 211 212 prog, err := conf.Load() 213 if prog != nil { 214 t.Errorf("Load unexpectedly returned a Program") 215 } 216 if err == nil { 217 t.Fatalf("Load succeeded unexpectedly, want %q", wantErr) 218 } 219 if err.Error() != wantErr { 220 t.Fatalf("Load failed with wrong error %q, want %q", err, wantErr) 221 } 222 } 223 224 func TestLoad_ParseError_AllowErrors(t *testing.T) { 225 var conf loader.Config 226 conf.AllowErrors = true 227 conf.CreateFromFilenames("badpkg", "testdata/badpkgdecl.go") 228 229 prog, err := conf.Load() 230 if err != nil { 231 t.Errorf("Load failed unexpectedly: %v", err) 232 } 233 if prog == nil { 234 t.Fatalf("Load returned a nil Program") 235 } 236 if got, want := created(prog), "badpkg"; got != want { 237 t.Errorf("Created = %s, want %s", got, want) 238 } 239 240 badpkg := prog.Created[0] 241 if len(badpkg.Files) != 1 { 242 t.Errorf("badpkg has %d files, want 1", len(badpkg.Files)) 243 } 244 wantErr := filepath.Join("testdata", "badpkgdecl.go") + ":1:34: expected 'package', found 'EOF'" 245 if !hasError(badpkg.Errors, wantErr) { 246 t.Errorf("badpkg.Errors = %v, want %s", badpkg.Errors, wantErr) 247 } 248 } 249 250 func TestLoad_FromSource_Success(t *testing.T) { 251 var conf loader.Config 252 conf.CreateFromFilenames("P", "testdata/a.go", "testdata/b.go") 253 254 prog, err := conf.Load() 255 if err != nil { 256 t.Errorf("Load failed unexpectedly: %v", err) 257 } 258 if prog == nil { 259 t.Fatalf("Load returned a nil Program") 260 } 261 if got, want := created(prog), "P"; got != want { 262 t.Errorf("Created = %s, want %s", got, want) 263 } 264 } 265 266 func TestLoad_FromImports_Success(t *testing.T) { 267 if runtime.Compiler == "gccgo" { 268 t.Skip("gccgo has no standard library test files") 269 } 270 271 var conf loader.Config 272 conf.ImportWithTests("fmt") 273 conf.ImportWithTests("errors") 274 275 prog, err := conf.Load() 276 if err != nil { 277 t.Errorf("Load failed unexpectedly: %v", err) 278 } 279 if prog == nil { 280 t.Fatalf("Load returned a nil Program") 281 } 282 if got, want := created(prog), "errors_test fmt_test"; got != want { 283 t.Errorf("Created = %q, want %s", got, want) 284 } 285 if got, want := imported(prog), "errors fmt"; got != want { 286 t.Errorf("Imported = %s, want %s", got, want) 287 } 288 // Check set of transitive packages. 289 // There are >30 and the set may grow over time, so only check a few. 290 want := map[string]bool{ 291 "strings": true, 292 "time": true, 293 "runtime": true, 294 "testing": true, 295 "unicode": true, 296 } 297 for _, path := range all(prog) { 298 delete(want, path) 299 } 300 if len(want) > 0 { 301 t.Errorf("AllPackages is missing these keys: %q", keys(want)) 302 } 303 } 304 305 func TestLoad_MissingIndirectImport(t *testing.T) { 306 pkgs := map[string]string{ 307 "a": `package a; import _ "b"`, 308 "b": `package b; import _ "c"`, 309 } 310 conf := loader.Config{Build: fakeContext(pkgs)} 311 conf.Import("a") 312 313 const wantErr = "couldn't load packages due to errors: b" 314 315 prog, err := conf.Load() 316 if err == nil { 317 t.Errorf("Load succeeded unexpectedly, want %q", wantErr) 318 } else if err.Error() != wantErr { 319 t.Errorf("Load failed with wrong error %q, want %q", err, wantErr) 320 } 321 if prog != nil { 322 t.Errorf("Load unexpectedly returned a Program") 323 } 324 } 325 326 func TestLoad_BadDependency_AllowErrors(t *testing.T) { 327 for _, test := range []struct { 328 descr string 329 pkgs map[string]string 330 wantPkgs string 331 }{ 332 333 { 334 descr: "missing dependency", 335 pkgs: map[string]string{ 336 "a": `package a; import _ "b"`, 337 "b": `package b; import _ "c"`, 338 }, 339 wantPkgs: "a b", 340 }, 341 { 342 descr: "bad package decl in dependency", 343 pkgs: map[string]string{ 344 "a": `package a; import _ "b"`, 345 "b": `package b; import _ "c"`, 346 "c": `package`, 347 }, 348 wantPkgs: "a b", 349 }, 350 { 351 descr: "parse error in dependency", 352 pkgs: map[string]string{ 353 "a": `package a; import _ "b"`, 354 "b": `package b; import _ "c"`, 355 "c": `package c; var x = `, 356 }, 357 wantPkgs: "a b c", 358 }, 359 } { 360 conf := loader.Config{ 361 AllowErrors: true, 362 Build: fakeContext(test.pkgs), 363 } 364 conf.Import("a") 365 366 prog, err := conf.Load() 367 if err != nil { 368 t.Errorf("%s: Load failed unexpectedly: %v", test.descr, err) 369 } 370 if prog == nil { 371 t.Fatalf("%s: Load returned a nil Program", test.descr) 372 } 373 374 if got, want := imported(prog), "a"; got != want { 375 t.Errorf("%s: Imported = %s, want %s", test.descr, got, want) 376 } 377 if got := all(prog); strings.Join(got, " ") != test.wantPkgs { 378 t.Errorf("%s: AllPackages = %s, want %s", test.descr, got, test.wantPkgs) 379 } 380 } 381 } 382 383 func TestCwd(t *testing.T) { 384 ctxt := fakeContext(map[string]string{"one/two/three": `package three`}) 385 for _, test := range []struct { 386 cwd, arg, want string 387 }{ 388 {cwd: "/go/src/one", arg: "./two/three", want: "one/two/three"}, 389 {cwd: "/go/src/one", arg: "../one/two/three", want: "one/two/three"}, 390 {cwd: "/go/src/one", arg: "one/two/three", want: "one/two/three"}, 391 {cwd: "/go/src/one/two/three", arg: ".", want: "one/two/three"}, 392 {cwd: "/go/src/one", arg: "two/three", want: ""}, 393 } { 394 conf := loader.Config{ 395 Cwd: test.cwd, 396 Build: ctxt, 397 } 398 conf.Import(test.arg) 399 400 var got string 401 prog, err := conf.Load() 402 if prog != nil { 403 got = imported(prog) 404 } 405 if got != test.want { 406 t.Errorf("Load(%s) from %s: Imported = %s, want %s", 407 test.arg, test.cwd, got, test.want) 408 if err != nil { 409 t.Errorf("Load failed: %v", err) 410 } 411 } 412 } 413 } 414 415 func TestLoad_vendor(t *testing.T) { 416 pkgs := map[string]string{ 417 "a": `package a; import _ "x"`, 418 "a/vendor": ``, // mkdir a/vendor 419 "a/vendor/x": `package xa`, 420 "b": `package b; import _ "x"`, 421 "b/vendor": ``, // mkdir b/vendor 422 "b/vendor/x": `package xb`, 423 "c": `package c; import _ "x"`, 424 "x": `package xc`, 425 } 426 conf := loader.Config{Build: fakeContext(pkgs)} 427 conf.Import("a") 428 conf.Import("b") 429 conf.Import("c") 430 431 prog, err := conf.Load() 432 if err != nil { 433 t.Fatal(err) 434 } 435 436 // Check that a, b, and c see different versions of x. 437 for _, r := range "abc" { 438 name := string(r) 439 got := prog.Package(name).Pkg.Imports()[0] 440 want := "x" + name 441 if got.Name() != want { 442 t.Errorf("package %s import %q = %s, want %s", 443 name, "x", got.Name(), want) 444 } 445 } 446 } 447 448 func TestVendorCwd(t *testing.T) { 449 // Test the interaction of cwd and vendor directories. 450 ctxt := fakeContext(map[string]string{ 451 "net": ``, // mkdir net 452 "net/http": `package http; import _ "hpack"`, 453 "vendor": ``, // mkdir vendor 454 "vendor/hpack": `package vendorhpack`, 455 "hpack": `package hpack`, 456 }) 457 for i, test := range []struct { 458 cwd, arg, want string 459 }{ 460 {cwd: "/go/src/net", arg: "http"}, // not found 461 {cwd: "/go/src/net", arg: "./http", want: "net/http vendor/hpack"}, 462 {cwd: "/go/src/net", arg: "hpack", want: "vendor/hpack"}, 463 {cwd: "/go/src/vendor", arg: "hpack", want: "vendor/hpack"}, 464 {cwd: "/go/src/vendor", arg: "./hpack", want: "vendor/hpack"}, 465 } { 466 conf := loader.Config{ 467 Cwd: test.cwd, 468 Build: ctxt, 469 } 470 conf.Import(test.arg) 471 472 var got string 473 prog, err := conf.Load() 474 if prog != nil { 475 got = strings.Join(all(prog), " ") 476 } 477 if got != test.want { 478 t.Errorf("#%d: Load(%s) from %s: got %s, want %s", 479 i, test.arg, test.cwd, got, test.want) 480 if err != nil { 481 t.Errorf("Load failed: %v", err) 482 } 483 } 484 } 485 } 486 487 func TestVendorCwdIssue16580(t *testing.T) { 488 // Regression test for Go issue 16580. 489 // Import decls in "created" packages were vendor-resolved 490 // w.r.t. cwd, not the parent directory of the package's files. 491 ctxt := fakeContext(map[string]string{ 492 "a": ``, // mkdir a 493 "a/vendor": ``, // mkdir a/vendor 494 "a/vendor/b": `package b; const X = true`, 495 "b": `package b; const X = false`, 496 }) 497 for _, test := range []struct { 498 filename, cwd string 499 want bool // expected value of b.X; depends on filename, not on cwd 500 }{ 501 {filename: "c.go", cwd: "/go/src", want: false}, 502 {filename: "c.go", cwd: "/go/src/a", want: false}, 503 {filename: "c.go", cwd: "/go/src/a/b", want: false}, 504 {filename: "c.go", cwd: "/go/src/a/vendor/b", want: false}, 505 506 {filename: "/go/src/a/c.go", cwd: "/go/src", want: true}, 507 {filename: "/go/src/a/c.go", cwd: "/go/src/a", want: true}, 508 {filename: "/go/src/a/c.go", cwd: "/go/src/a/b", want: true}, 509 {filename: "/go/src/a/c.go", cwd: "/go/src/a/vendor/b", want: true}, 510 511 {filename: "/go/src/c/c.go", cwd: "/go/src", want: false}, 512 {filename: "/go/src/c/c.go", cwd: "/go/src/a", want: false}, 513 {filename: "/go/src/c/c.go", cwd: "/go/src/a/b", want: false}, 514 {filename: "/go/src/c/c.go", cwd: "/go/src/a/vendor/b", want: false}, 515 } { 516 conf := loader.Config{ 517 Cwd: test.cwd, 518 Build: ctxt, 519 } 520 f, err := conf.ParseFile(test.filename, `package dummy; import "b"; const X = b.X`) 521 if err != nil { 522 t.Fatal(f) 523 } 524 conf.CreateFromFiles("dummy", f) 525 526 prog, err := conf.Load() 527 if err != nil { 528 t.Errorf("%+v: Load failed: %v", test, err) 529 continue 530 } 531 532 x := constant.BoolVal(prog.Created[0].Pkg.Scope().Lookup("X").(*types.Const).Val()) 533 if x != test.want { 534 t.Errorf("%+v: b.X = %t", test, x) 535 } 536 } 537 538 // TODO(adonovan): also test imports within XTestGoFiles. 539 } 540 541 // TODO(adonovan): more Load tests: 542 // 543 // failures: 544 // - to parse package decl of *_test.go files 545 // - to parse package decl of external *_test.go files 546 // - to parse whole of *_test.go files 547 // - to parse whole of external *_test.go files 548 // - to open a *.go file during import scanning 549 // - to import from binary 550 551 // features: 552 // - InitialPackages 553 // - PackageCreated hook 554 // - TypeCheckFuncBodies hook 555 556 func TestTransitivelyErrorFreeFlag(t *testing.T) { 557 // Create an minimal custom build.Context 558 // that fakes the following packages: 559 // 560 // a --> b --> c! c has an error 561 // \ d and e are transitively error-free. 562 // e --> d 563 // 564 // Each package [a-e] consists of one file, x.go. 565 pkgs := map[string]string{ 566 "a": `package a; import (_ "b"; _ "e")`, 567 "b": `package b; import _ "c"`, 568 "c": `package c; func f() { _ = int(false) }`, // type error within function body 569 "d": `package d;`, 570 "e": `package e; import _ "d"`, 571 } 572 conf := loader.Config{ 573 AllowErrors: true, 574 Build: fakeContext(pkgs), 575 } 576 conf.Import("a") 577 578 prog, err := conf.Load() 579 if err != nil { 580 t.Errorf("Load failed: %s", err) 581 } 582 if prog == nil { 583 t.Fatalf("Load returned nil *Program") 584 } 585 586 for pkg, info := range prog.AllPackages { 587 var wantErr, wantTEF bool 588 switch pkg.Path() { 589 case "a", "b": 590 case "c": 591 wantErr = true 592 case "d", "e": 593 wantTEF = true 594 default: 595 t.Errorf("unexpected package: %q", pkg.Path()) 596 continue 597 } 598 599 if (info.Errors != nil) != wantErr { 600 if wantErr { 601 t.Errorf("Package %q.Error = nil, want error", pkg.Path()) 602 } else { 603 t.Errorf("Package %q has unexpected Errors: %v", 604 pkg.Path(), info.Errors) 605 } 606 } 607 608 if info.TransitivelyErrorFree != wantTEF { 609 t.Errorf("Package %q.TransitivelyErrorFree=%t, want %t", 610 pkg.Path(), info.TransitivelyErrorFree, wantTEF) 611 } 612 } 613 } 614 615 // Test that syntax (scan/parse), type, and loader errors are recorded 616 // (in PackageInfo.Errors) and reported (via Config.TypeChecker.Error). 617 func TestErrorReporting(t *testing.T) { 618 pkgs := map[string]string{ 619 "a": `package a; import (_ "b"; _ "c"); var x int = false`, 620 "b": `package b; 'syntax error!`, 621 } 622 conf := loader.Config{ 623 AllowErrors: true, 624 Build: fakeContext(pkgs), 625 } 626 var mu sync.Mutex 627 var allErrors []error 628 conf.TypeChecker.Error = func(err error) { 629 mu.Lock() 630 allErrors = append(allErrors, err) 631 mu.Unlock() 632 } 633 conf.Import("a") 634 635 prog, err := conf.Load() 636 if err != nil { 637 t.Errorf("Load failed: %s", err) 638 } 639 if prog == nil { 640 t.Fatalf("Load returned nil *Program") 641 } 642 643 // TODO(adonovan): test keys of ImportMap. 644 645 // Check errors recorded in each PackageInfo. 646 for pkg, info := range prog.AllPackages { 647 switch pkg.Path() { 648 case "a": 649 // The match below is unfortunately vague, because in go1.16 the error 650 // message in go/types changed from "cannot convert ..." to "cannot use 651 // ... as ... in assignment". 652 if !hasError(info.Errors, "cannot") { 653 t.Errorf("a.Errors = %v, want bool assignment (type) error", info.Errors) 654 } 655 if !hasError(info.Errors, "could not import c") { 656 t.Errorf("a.Errors = %v, want import (loader) error", info.Errors) 657 } 658 case "b": 659 if !hasError(info.Errors, "rune literal not terminated") { 660 t.Errorf("b.Errors = %v, want unterminated literal (syntax) error", info.Errors) 661 } 662 } 663 } 664 665 // Check errors reported via error handler. 666 if !hasError(allErrors, "cannot") || 667 !hasError(allErrors, "rune literal not terminated") || 668 !hasError(allErrors, "could not import c") { 669 t.Errorf("allErrors = %v, want syntax, type and loader errors", allErrors) 670 } 671 } 672 673 func TestCycles(t *testing.T) { 674 for _, test := range []struct { 675 descr string 676 ctxt *build.Context 677 wantErr string 678 }{ 679 { 680 "self-cycle", 681 fakeContext(map[string]string{ 682 "main": `package main; import _ "selfcycle"`, 683 "selfcycle": `package selfcycle; import _ "selfcycle"`, 684 }), 685 `import cycle: selfcycle -> selfcycle`, 686 }, 687 { 688 "three-package cycle", 689 fakeContext(map[string]string{ 690 "main": `package main; import _ "a"`, 691 "a": `package a; import _ "b"`, 692 "b": `package b; import _ "c"`, 693 "c": `package c; import _ "a"`, 694 }), 695 `import cycle: c -> a -> b -> c`, 696 }, 697 { 698 "self-cycle in dependency of test file", 699 buildutil.FakeContext(map[string]map[string]string{ 700 "main": { 701 "main.go": `package main`, 702 "main_test.go": `package main; import _ "a"`, 703 }, 704 "a": { 705 "a.go": `package a; import _ "a"`, 706 }, 707 }), 708 `import cycle: a -> a`, 709 }, 710 // TODO(adonovan): fix: these fail 711 // { 712 // "two-package cycle in dependency of test file", 713 // buildutil.FakeContext(map[string]map[string]string{ 714 // "main": { 715 // "main.go": `package main`, 716 // "main_test.go": `package main; import _ "a"`, 717 // }, 718 // "a": { 719 // "a.go": `package a; import _ "main"`, 720 // }, 721 // }), 722 // `import cycle: main -> a -> main`, 723 // }, 724 // { 725 // "self-cycle in augmented package", 726 // buildutil.FakeContext(map[string]map[string]string{ 727 // "main": { 728 // "main.go": `package main`, 729 // "main_test.go": `package main; import _ "main"`, 730 // }, 731 // }), 732 // `import cycle: main -> main`, 733 // }, 734 } { 735 conf := loader.Config{ 736 AllowErrors: true, 737 Build: test.ctxt, 738 } 739 var mu sync.Mutex 740 var allErrors []error 741 conf.TypeChecker.Error = func(err error) { 742 mu.Lock() 743 allErrors = append(allErrors, err) 744 mu.Unlock() 745 } 746 conf.ImportWithTests("main") 747 748 prog, err := conf.Load() 749 if err != nil { 750 t.Errorf("%s: Load failed: %s", test.descr, err) 751 } 752 if prog == nil { 753 t.Fatalf("%s: Load returned nil *Program", test.descr) 754 } 755 756 if !hasError(allErrors, test.wantErr) { 757 t.Errorf("%s: Load() errors = %q, want %q", 758 test.descr, allErrors, test.wantErr) 759 } 760 } 761 762 // TODO(adonovan): 763 // - Test that in a legal test cycle, none of the symbols 764 // defined by augmentation are visible via import. 765 } 766 767 // ---- utilities ---- 768 769 // Simplifying wrapper around buildutil.FakeContext for single-file packages. 770 func fakeContext(pkgs map[string]string) *build.Context { 771 pkgs2 := make(map[string]map[string]string) 772 for path, content := range pkgs { 773 pkgs2[path] = map[string]string{"x.go": content} 774 } 775 return buildutil.FakeContext(pkgs2) 776 } 777 778 func hasError(errors []error, substr string) bool { 779 for _, err := range errors { 780 if strings.Contains(err.Error(), substr) { 781 return true 782 } 783 } 784 return false 785 } 786 787 func keys(m map[string]bool) (keys []string) { 788 for key := range m { 789 keys = append(keys, key) 790 } 791 sort.Strings(keys) 792 return 793 } 794 795 // Returns all loaded packages. 796 func all(prog *loader.Program) []string { 797 var pkgs []string 798 for _, info := range prog.AllPackages { 799 pkgs = append(pkgs, info.Pkg.Path()) 800 } 801 sort.Strings(pkgs) 802 return pkgs 803 } 804 805 // Returns initially imported packages, as a string. 806 func imported(prog *loader.Program) string { 807 var pkgs []string 808 for _, info := range prog.Imported { 809 pkgs = append(pkgs, info.Pkg.Path()) 810 } 811 sort.Strings(pkgs) 812 return strings.Join(pkgs, " ") 813 } 814 815 // Returns initially created packages, as a string. 816 func created(prog *loader.Program) string { 817 var pkgs []string 818 for _, info := range prog.Created { 819 pkgs = append(pkgs, info.Pkg.Path()) 820 } 821 return strings.Join(pkgs, " ") 822 } 823 824 // Load package "io" twice in parallel. 825 // When run with -race, this is a regression test for Go issue 20718, in 826 // which the global "unsafe" package was modified concurrently. 827 func TestLoad1(t *testing.T) { loadIO(t) } 828 func TestLoad2(t *testing.T) { loadIO(t) } 829 830 func loadIO(t *testing.T) { 831 t.Parallel() 832 conf := &loader.Config{ImportPkgs: map[string]bool{"io": false}} 833 if _, err := conf.Load(); err != nil { 834 t.Fatal(err) 835 } 836 } 837 838 func TestCgoCwdIssue46877(t *testing.T) { 839 var conf loader.Config 840 conf.Import("github.com/powerman/golang-tools/go/loader/testdata/issue46877") 841 if _, err := conf.Load(); err != nil { 842 t.Errorf("Load failed: %v", err) 843 } 844 }