Example #1
0
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)
			}
		}
	}
}
Example #2
0
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)
		}
	}
}
Example #3
0
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)
		}
	}
}
Example #4
0
// 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)
	}
}
Example #5
0
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")
	}
}
Example #6
0
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")
	}
}
Example #7
0
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)
	}
}
Example #8
0
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
}
Example #9
0
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)
			}
		}
	}
}