func TestTransitivelyErrorFreeFlag(t *testing.T) {
	pkgs := map[string]string{
		"a": `package a; import (_ "b"; _ "e")`,
		"b": `package b; import _ "c"`,
		"c": `package c; func f() { _ = int(false) }`,  
		"d": `package d;`,
		"e": `package e; import _ "d"`,
	}
	conf := loader.Config{
		AllowErrors: true,
		Build:       fakeContext(pkgs),
	}
	conf.Import("a")
	prog, err := conf.Load()
	if err != nil {
		t.Errorf("Load failed: %s", err)
	}
	if prog == nil {
		t.Fatalf("Load returned nil *Program")
	}
	for pkg, info := range prog.AllPackages {
		var wantErr, wantTEF bool
		switch pkg.Path() {
		case "a", "b":
		case "c":
			wantErr = true
		case "d", "e":
			wantTEF = true
		default:
			t.Errorf("unexpected package: %q", pkg.Path())
			continue
		}
		if (info.Errors != nil) != wantErr {
			if wantErr {
				t.Errorf("Package %q.Error = nil, want error", pkg.Path())
			} else {
				t.Errorf("Package %q has unexpected Errors: %v",
					pkg.Path(), info.Errors)
			}
		}
		if info.TransitivelyErrorFree != wantTEF {
			t.Errorf("Package %q.TransitivelyErrorFree=%t, want %t",
				pkg.Path(), info.TransitivelyErrorFree, wantTEF)
		}
	}
}
TODO(adonovan): more Load tests:

failures:
- to parse package decl of *_test.go files
- to parse package decl of external *_test.go files
- to parse whole of *_test.go files
- to parse whole of external *_test.go files
- to open a *.go file during import scanning
- to import from binary
features:
- InitialPackages
- PackageCreated hook
- TypeCheckFuncBodies hook
package loader_test
import (
	"fmt"
	"go/build"
	"go/constant"
	"go/types"
	"path/filepath"
	"reflect"
	"sort"
	"strings"
	"sync"
	"testing"
	"golang.org/x/tools/go/buildutil"
	"golang.org/x/tools/go/loader"
)
func TestFromArgs(t *testing.T) {
	type result struct {
		Err        string
		Rest       []string
		ImportPkgs map[string]bool
		CreatePkgs []loader.PkgSpec
	}
	for _, test := range []struct {
		args  []string
		tests bool
		want  result
	}{
		{
			args: []string{"nosuchpkg", "errors"},
			want: result{
				ImportPkgs: map[string]bool{"errors": false, "nosuchpkg": false},
			},
		},
		{
			args:  []string{"nosuchpkg", "errors"},
			tests: true,
			want: result{
				ImportPkgs: map[string]bool{"errors": true, "nosuchpkg": true},
			},
		},
		{
			args: []string{"fmt", "errors", "--", "surplus"},
			want: result{
				Rest:       []string{"surplus"},
				ImportPkgs: map[string]bool{"errors": false, "fmt": false},
			},
		},
		{
			args: []string{"foo.go", "bar.go"},
			want: result{CreatePkgs: []loader.PkgSpec{{
				Filenames: []string{"foo.go", "bar.go"},
			}}},
		},
		{
			args: []string{"foo.go", "fmt"},
			want: result{
				Err: "named files must be .go files: fmt",
			},
		},
	} {
		var conf loader.Config
		rest, err := conf.FromArgs(test.args, test.tests)
		got := result{
			Rest:       rest,
			ImportPkgs: conf.ImportPkgs,
			CreatePkgs: conf.CreatePkgs,
		}
		if err != nil {
			got.Err = err.Error()
		}
		if !reflect.DeepEqual(got, test.want) {
			t.Errorf("FromArgs(%q) = %+v, want %+v", test.args, got, test.want)
		}
	}
}
func TestLoad_NoInitialPackages(t *testing.T) {
	var conf loader.Config
	const wantErr = "no initial packages were loaded"
	prog, err := conf.Load()
	if err == nil {
		t.Errorf("Load succeeded unexpectedly, want %q", wantErr)
	} else if err.Error() != wantErr {
		t.Errorf("Load failed with wrong error %q, want %q", err, wantErr)
	}
	if prog != nil {
		t.Errorf("Load unexpectedly returned a Program")
	}
}
func TestLoad_MissingInitialPackage(t *testing.T) {
	var conf loader.Config
	conf.Import("nosuchpkg")
	conf.Import("errors")
	const wantErr = "couldn't load packages due to errors: nosuchpkg"
	prog, err := conf.Load()
	if err == nil {
		t.Errorf("Load succeeded unexpectedly, want %q", wantErr)
	} else if err.Error() != wantErr {
		t.Errorf("Load failed with wrong error %q, want %q", err, wantErr)
	}
	if prog != nil {
		t.Errorf("Load unexpectedly returned a Program")
	}
}
func TestLoad_MissingInitialPackage_AllowErrors(t *testing.T) {
	var conf loader.Config
	conf.AllowErrors = true
	conf.Import("nosuchpkg")
	conf.ImportWithTests("errors")
	prog, err := conf.Load()
	if err != nil {
		t.Errorf("Load failed unexpectedly: %v", err)
	}
	if prog == nil {
		t.Fatalf("Load returned a nil Program")
	}
	if got, want := created(prog), "errors_test"; got != want {
		t.Errorf("Created = %s, want %s", got, want)
	}
	if got, want := imported(prog), "errors"; got != want {
		t.Errorf("Imported = %s, want %s", got, want)
	}
}
func TestCreateUnnamedPackage(t *testing.T) {
	var conf loader.Config
	conf.CreateFromFilenames("")
	prog, err := conf.Load()
	if err != nil {
		t.Fatalf("Load failed: %v", err)
	}
	if got, want := fmt.Sprint(prog.InitialPackages()), "[(unnamed)]"; got != want {
		t.Errorf("InitialPackages = %s, want %s", got, want)
	}
}
func TestLoad_MissingFileInCreatedPackage(t *testing.T) {
	var conf loader.Config
	conf.CreateFromFilenames("", "missing.go")
	const wantErr = "couldn't load packages due to errors: (unnamed)"
	prog, err := conf.Load()
	if prog != nil {
		t.Errorf("Load unexpectedly returned a Program")
	}
	if err == nil {
		t.Fatalf("Load succeeded unexpectedly, want %q", wantErr)
	}
	if err.Error() != wantErr {
		t.Fatalf("Load failed with wrong error %q, want %q", err, wantErr)
	}
}
func TestLoad_MissingFileInCreatedPackage_AllowErrors(t *testing.T) {
	conf := loader.Config{AllowErrors: true}
	conf.CreateFromFilenames("", "missing.go")
	prog, err := conf.Load()
	if err != nil {
		t.Errorf("Load failed: %v", err)
	}
	if got, want := fmt.Sprint(prog.InitialPackages()), "[(unnamed)]"; got != want {
		t.Fatalf("InitialPackages = %s, want %s", got, want)
	}
}
func TestLoad_ParseError(t *testing.T) {
	var conf loader.Config
	conf.CreateFromFilenames("badpkg", "testdata/badpkgdecl.go")
	const wantErr = "couldn't load packages due to errors: badpkg"
	prog, err := conf.Load()
	if prog != nil {
		t.Errorf("Load unexpectedly returned a Program")
	}
	if err == nil {
		t.Fatalf("Load succeeded unexpectedly, want %q", wantErr)
	}
	if err.Error() != wantErr {
		t.Fatalf("Load failed with wrong error %q, want %q", err, wantErr)
	}
}
func TestLoad_ParseError_AllowErrors(t *testing.T) {
	var conf loader.Config
	conf.AllowErrors = true
	conf.CreateFromFilenames("badpkg", "testdata/badpkgdecl.go")
	prog, err := conf.Load()
	if err != nil {
		t.Errorf("Load failed unexpectedly: %v", err)
	}
	if prog == nil {
		t.Fatalf("Load returned a nil Program")
	}
	if got, want := created(prog), "badpkg"; got != want {
		t.Errorf("Created = %s, want %s", got, want)
	}
	badpkg := prog.Created[0]
	if len(badpkg.Files) != 1 {
		t.Errorf("badpkg has %d files, want 1", len(badpkg.Files))
	}
	wantErr := filepath.Join("testdata", "badpkgdecl.go") + ":1:34: expected 'package', found 'EOF'"
	if !hasError(badpkg.Errors, wantErr) {
		t.Errorf("badpkg.Errors = %v, want %s", badpkg.Errors, wantErr)
	}
}
func TestLoad_FromSource_Success(t *testing.T) {
	var conf loader.Config
	conf.CreateFromFilenames("P", "testdata/a.go", "testdata/b.go")
	prog, err := conf.Load()
	if err != nil {
		t.Errorf("Load failed unexpectedly: %v", err)
	}
	if prog == nil {
		t.Fatalf("Load returned a nil Program")
	}
	if got, want := created(prog), "P"; got != want {
		t.Errorf("Created = %s, want %s", got, want)
	}
}
func TestLoad_FromImports_Success(t *testing.T) {
	var conf loader.Config
	conf.ImportWithTests("fmt")
	conf.ImportWithTests("errors")
	prog, err := conf.Load()
	if err != nil {
		t.Errorf("Load failed unexpectedly: %v", err)
	}
	if prog == nil {
		t.Fatalf("Load returned a nil Program")
	}
	if got, want := created(prog), "errors_test fmt_test"; got != want {
		t.Errorf("Created = %q, want %s", got, want)
	}
	if got, want := imported(prog), "errors fmt"; got != want {
		t.Errorf("Imported = %s, want %s", got, want)
	}
	want := map[string]bool{
		"strings": true,
		"time":    true,
		"runtime": true,
		"testing": true,
		"unicode": true,
	}
	for _, path := range all(prog) {
		delete(want, path)
	}
	if len(want) > 0 {
		t.Errorf("AllPackages is missing these keys: %q", keys(want))
	}
}
func TestLoad_MissingIndirectImport(t *testing.T) {
	pkgs := map[string]string{
		"a": `package a; import _ "b"`,
		"b": `package b; import _ "c"`,
	}
	conf := loader.Config{Build: fakeContext(pkgs)}
	conf.Import("a")
	const wantErr = "couldn't load packages due to errors: b"
	prog, err := conf.Load()
	if err == nil {
		t.Errorf("Load succeeded unexpectedly, want %q", wantErr)
	} else if err.Error() != wantErr {
		t.Errorf("Load failed with wrong error %q, want %q", err, wantErr)
	}
	if prog != nil {
		t.Errorf("Load unexpectedly returned a Program")
	}
}
func TestLoad_BadDependency_AllowErrors(t *testing.T) {
	for _, test := range []struct {
		descr    string
		pkgs     map[string]string
		wantPkgs string
	}{
		{
			descr: "missing dependency",
			pkgs: map[string]string{
				"a": `package a; import _ "b"`,
				"b": `package b; import _ "c"`,
			},
			wantPkgs: "a b",
		},
		{
			descr: "bad package decl in dependency",
			pkgs: map[string]string{
				"a": `package a; import _ "b"`,
				"b": `package b; import _ "c"`,
				"c": `package`,
			},
			wantPkgs: "a b",
		},
		{
			descr: "parse error in dependency",
			pkgs: map[string]string{
				"a": `package a; import _ "b"`,
				"b": `package b; import _ "c"`,
				"c": `package c; var x = `,
			},
			wantPkgs: "a b c",
		},
	} {
		conf := loader.Config{
			AllowErrors: true,
			Build:       fakeContext(test.pkgs),
		}
		conf.Import("a")
		prog, err := conf.Load()
		if err != nil {
			t.Errorf("%s: Load failed unexpectedly: %v", test.descr, err)
		}
		if prog == nil {
			t.Fatalf("%s: Load returned a nil Program", test.descr)
		}
		if got, want := imported(prog), "a"; got != want {
			t.Errorf("%s: Imported = %s, want %s", test.descr, got, want)
		}
		if got := all(prog); strings.Join(got, " ") != test.wantPkgs {
			t.Errorf("%s: AllPackages = %s, want %s", test.descr, got, test.wantPkgs)
		}
	}
}
func TestCwd(t *testing.T) {
	ctxt := fakeContext(map[string]string{"one/two/three": `package three`})
	for _, test := range []struct {
		cwd, arg, want string
	}{
		{cwd: "/go/src/one", arg: "./two/three", want: "one/two/three"},
		{cwd: "/go/src/one", arg: "../one/two/three", want: "one/two/three"},
		{cwd: "/go/src/one", arg: "one/two/three", want: "one/two/three"},
		{cwd: "/go/src/one/two/three", arg: ".", want: "one/two/three"},
		{cwd: "/go/src/one", arg: "two/three", want: ""},
	} {
		conf := loader.Config{
			Cwd:   test.cwd,
			Build: ctxt,
		}
		conf.Import(test.arg)
		var got string
		prog, err := conf.Load()
		if prog != nil {
			got = imported(prog)
		}
		if got != test.want {
			t.Errorf("Load(%s) from %s: Imported = %s, want %s",
				test.arg, test.cwd, got, test.want)
			if err != nil {
				t.Errorf("Load failed: %v", err)
			}
		}
	}
}
func TestLoad_vendor(t *testing.T) {
	pkgs := map[string]string{
		"a":          `package a; import _ "x"`,
		"a/vendor":   ``,  
		"a/vendor/x": `package xa`,
		"b":          `package b; import _ "x"`,
		"b/vendor":   ``,  
		"b/vendor/x": `package xb`,
		"c":          `package c; import _ "x"`,
		"x":          `package xc`,
	}
	conf := loader.Config{Build: fakeContext(pkgs)}
	conf.Import("a")
	conf.Import("b")
	conf.Import("c")
	prog, err := conf.Load()
	if err != nil {
		t.Fatal(err)
	}
	for _, r := range "abc" {
		name := string(r)
		got := prog.Package(name).Pkg.Imports()[0]
		want := "x" + name
		if got.Name() != want {
			t.Errorf("package %s import %q = %s, want %s",
				name, "x", got.Name(), want)
		}
	}
}
func TestVendorCwd(t *testing.T) {
	ctxt := fakeContext(map[string]string{
		"net":          ``,  
		"net/http":     `package http; import _ "hpack"`,
		"vendor":       ``,  
		"vendor/hpack": `package vendorhpack`,
		"hpack":        `package hpack`,
	})
	for i, test := range []struct {
		cwd, arg, want string
	}{
		{cwd: "/go/src/net", arg: "http"},  
		{cwd: "/go/src/net", arg: "./http", want: "net/http vendor/hpack"},
		{cwd: "/go/src/net", arg: "hpack", want: "vendor/hpack"},
		{cwd: "/go/src/vendor", arg: "hpack", want: "vendor/hpack"},
		{cwd: "/go/src/vendor", arg: "./hpack", want: "vendor/hpack"},
	} {
		conf := loader.Config{
			Cwd:   test.cwd,
			Build: ctxt,
		}
		conf.Import(test.arg)
		var got string
		prog, err := conf.Load()
		if prog != nil {
			got = strings.Join(all(prog), " ")
		}
		if got != test.want {
			t.Errorf("#%d: Load(%s) from %s: got %s, want %s",
				i, test.arg, test.cwd, got, test.want)
			if err != nil {
				t.Errorf("Load failed: %v", err)
			}
		}
	}
}
func TestVendorCwdIssue16580(t *testing.T) {
	ctxt := fakeContext(map[string]string{
		"a":          ``,  
		"a/vendor":   ``,  
		"a/vendor/b": `package b; const X = true`,
		"b":          `package b; const X = false`,
	})
	for _, test := range []struct {
		filename, cwd string
		want          bool  
	}{
		{filename: "c.go", cwd: "/go/src", want: false},
		{filename: "c.go", cwd: "/go/src/a", want: false},
		{filename: "c.go", cwd: "/go/src/a/b", want: false},
		{filename: "c.go", cwd: "/go/src/a/vendor/b", want: false},
		{filename: "/go/src/a/c.go", cwd: "/go/src", want: true},
		{filename: "/go/src/a/c.go", cwd: "/go/src/a", want: true},
		{filename: "/go/src/a/c.go", cwd: "/go/src/a/b", want: true},
		{filename: "/go/src/a/c.go", cwd: "/go/src/a/vendor/b", want: true},
		{filename: "/go/src/c/c.go", cwd: "/go/src", want: false},
		{filename: "/go/src/c/c.go", cwd: "/go/src/a", want: false},
		{filename: "/go/src/c/c.go", cwd: "/go/src/a/b", want: false},
		{filename: "/go/src/c/c.go", cwd: "/go/src/a/vendor/b", want: false},
	} {
		conf := loader.Config{
			Cwd:   test.cwd,
			Build: ctxt,
		}
		f, err := conf.ParseFile(test.filename, `package dummy; import "b"; const X = b.X`)
		if err != nil {
			t.Fatal(f)
		}
		conf.CreateFromFiles("dummy", f)
		prog, err := conf.Load()
		if err != nil {
			t.Errorf("%+v: Load failed: %v", test, err)
			continue
		}
		x := constant.BoolVal(prog.Created[0].Pkg.Scope().Lookup("X").(*types.Const).Val())
		if x != test.want {
			t.Errorf("%+v: b.X = %t", test, x)
		}
	}
}