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 TestTransitivelyErrorFreeFlag(t *testing.T) { // Create an minimal custom build.Context // that fakes the following packages: // // a --> b --> c! c has an error // \ d and e are transitively error-free. // e --> d // // Each package [a-e] consists of one file, x.go. pkgs := map[string]string{ "a": `package a; import (_ "b"; _ "e")`, "b": `package b; import _ "c"`, "c": `package c; func f() { _ = int(false) }`, // type error within function body "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) } } }
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) } } }
// Test that syntax (scan/parse), type, and loader errors are recorded // (in PackageInfo.Errors) and reported (via Config.TypeChecker.Error). func TestErrorReporting(t *testing.T) { pkgs := map[string]string{ "a": `package a; import (_ "b"; _ "c"); var x int = false`, "b": `package b; 'syntax error!`, } conf := loader.Config{ AllowErrors: true, Build: fakeContext(pkgs), } var mu sync.Mutex var allErrors []error conf.TypeChecker.Error = func(err error) { mu.Lock() allErrors = append(allErrors, err) mu.Unlock() } 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") } // TODO(adonovan): test keys of ImportMap. // Check errors recorded in each PackageInfo. for pkg, info := range prog.AllPackages { switch pkg.Path() { case "a": if !hasError(info.Errors, "cannot convert false") { t.Errorf("a.Errors = %v, want bool conversion (type) error", info.Errors) } if !hasError(info.Errors, "could not import c") { t.Errorf("a.Errors = %v, want import (loader) error", info.Errors) } case "b": if !hasError(info.Errors, "rune literal not terminated") { t.Errorf("b.Errors = %v, want unterminated literal (syntax) error", info.Errors) } } } // Check errors reported via error handler. if !hasError(allErrors, "cannot convert false") || !hasError(allErrors, "rune literal not terminated") || !hasError(allErrors, "could not import c") { t.Errorf("allErrors = %v, want syntax, type and loader errors", allErrors) } }
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_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_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 run(t *testing.T, dir, input string, success successPredicate) bool { fmt.Printf("Input: %s\n", input) start := time.Now() var inputs []string for _, i := range strings.Split(input, " ") { if strings.HasSuffix(i, ".go") { i = dir + i } inputs = append(inputs, i) } var conf loader.Config if _, err := conf.FromArgs(inputs, true); err != nil { t.Errorf("FromArgs(%s) failed: %s", inputs, err) return false } conf.Import("runtime") // Print a helpful hint if we don't make it to the end. var hint string defer func() { if hint != "" { fmt.Println("FAIL") fmt.Println(hint) } else { fmt.Println("PASS") } interp.CapturedOutput = nil }() hint = fmt.Sprintf("To dump SSA representation, run:\n%% go build golang.org/x/tools/cmd/ssadump && ./ssadump -build=CFP %s\n", input) iprog, err := conf.Load() if err != nil { t.Errorf("conf.Load(%s) failed: %s", inputs, err) return false } prog := ssa.Create(iprog, ssa.SanityCheckFunctions) prog.BuildAll() var mainPkg *ssa.Package var initialPkgs []*ssa.Package for _, info := range iprog.InitialPackages() { if info.Pkg.Path() == "runtime" { continue // not an initial package } p := prog.Package(info.Pkg) initialPkgs = append(initialPkgs, p) if mainPkg == nil && p.Func("main") != nil { mainPkg = p } } if mainPkg == nil { testmainPkg := prog.CreateTestMainPackage(initialPkgs...) if testmainPkg == nil { t.Errorf("CreateTestMainPackage(%s) returned nil", mainPkg) return false } if testmainPkg.Func("main") == nil { t.Errorf("synthetic testmain package has no main") return false } mainPkg = testmainPkg } var out bytes.Buffer interp.CapturedOutput = &out hint = fmt.Sprintf("To trace execution, run:\n%% go build golang.org/x/tools/cmd/ssadump && ./ssadump -build=C -run --interp=T %s\n", input) exitCode := interp.Interpret(mainPkg, 0, &types.StdSizes{8, 8}, inputs[0], []string{}) // The definition of success varies with each file. if err := success(exitCode, out.String()); err != nil { t.Errorf("interp.Interpret(%s) failed: %s", inputs, err) return false } hint = "" // call off the hounds if false { fmt.Println(input, time.Since(start)) // test profiling } return true }
func TestCgoOption(t *testing.T) { switch runtime.GOOS { // On these systems, the net and os/user packages don't use cgo. case "plan9", "solaris", "windows": return } // In nocgo builds (e.g. linux-amd64-nocgo), // there is no "runtime/cgo" package, // so cgo-generated Go files will have a failing import. if !build.Default.CgoEnabled { return } // Test that we can load cgo-using packages with // CGO_ENABLED=[01], which causes go/build to select pure // Go/native implementations, respectively, based on build // tags. // // Each entry specifies a package-level object and the generic // file expected to define it when cgo is disabled. // When cgo is enabled, the exact file is not specified (since // it varies by platform), but must differ from the generic one. // // The test also loads the actual file to verify that the // object is indeed defined at that location. for _, test := range []struct { pkg, name, genericFile string }{ {"net", "cgoLookupHost", "cgo_stub.go"}, {"os/user", "lookupId", "lookup_stubs.go"}, } { ctxt := build.Default for _, ctxt.CgoEnabled = range []bool{false, true} { conf := loader.Config{Build: &ctxt} conf.Import(test.pkg) prog, err := conf.Load() if err != nil { t.Errorf("Load failed: %v", err) continue } info := prog.Imported[test.pkg] if info == nil { t.Errorf("package %s not found", test.pkg) continue } obj := info.Pkg.Scope().Lookup(test.name) if obj == nil { t.Errorf("no object %s.%s", test.pkg, test.name) continue } posn := prog.Fset.Position(obj.Pos()) t.Logf("%s: %s (CgoEnabled=%t)", posn, obj, ctxt.CgoEnabled) gotFile := filepath.Base(posn.Filename) filesMatch := gotFile == test.genericFile if ctxt.CgoEnabled && filesMatch { t.Errorf("CGO_ENABLED=1: %s found in %s, want native file", obj, gotFile) } else if !ctxt.CgoEnabled && !filesMatch { t.Errorf("CGO_ENABLED=0: %s found in %s, want %s", obj, gotFile, test.genericFile) } // Load the file and check the object is declared at the right place. b, err := ioutil.ReadFile(posn.Filename) if err != nil { t.Errorf("can't read %s: %s", posn.Filename, err) continue } line := string(bytes.Split(b, []byte("\n"))[posn.Line-1]) ident := line[posn.Column-1:] if !strings.HasPrefix(ident, test.name) { t.Errorf("%s: %s not declared here (looking at %q)", posn, obj, ident) } } } }