mirror of
https://github.com/golang/go
synced 2024-11-18 18:54:42 -07:00
go.tools/ssa: don't synthesize an empty "testmain" package.
Also, only examine functions defined in *_test.go files. Added tests for empty and nonempty behaviour of CreateTestMainPackage. (Required some surgery to interp_test.) R=gri, gri CC=golang-dev https://golang.org/cl/25570044
This commit is contained in:
parent
3f686cae84
commit
cadc2255fe
@ -155,7 +155,9 @@ var gorootSrcPkgTests = []string{
|
||||
// "strings.go strings/search.go strings/search_test.go",
|
||||
}
|
||||
|
||||
func run(t *testing.T, dir, input string) bool {
|
||||
type successPredicate func(exitcode int, output string) error
|
||||
|
||||
func run(t *testing.T, dir, input string, success successPredicate) bool {
|
||||
fmt.Printf("Input: %s\n", input)
|
||||
|
||||
start := time.Now()
|
||||
@ -189,7 +191,7 @@ func run(t *testing.T, dir, input string) bool {
|
||||
}()
|
||||
|
||||
hint = fmt.Sprintf("To dump SSA representation, run:\n%% go build code.google.com/p/go.tools/cmd/ssadump && ./ssadump -build=CFP %s\n", input)
|
||||
mainInfo := imp.CreatePackage("main", files...)
|
||||
mainInfo := imp.CreatePackage(files[0].Name.Name, files...)
|
||||
|
||||
if _, err := imp.LoadPackage("runtime"); err != nil {
|
||||
t.Errorf("LoadPackage(runtime) failed: %s", err)
|
||||
@ -204,21 +206,27 @@ func run(t *testing.T, dir, input string) bool {
|
||||
|
||||
mainPkg := prog.Package(mainInfo.Pkg)
|
||||
if mainPkg.Func("main") == nil {
|
||||
mainPkg = prog.CreateTestMainPackage(mainPkg)
|
||||
testmainPkg := prog.CreateTestMainPackage(mainPkg)
|
||||
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 code.google.com/p/go.tools/cmd/ssadump && ./ssadump -build=C -run --interp=T %s\n", input)
|
||||
if exitCode := interp.Interpret(mainPkg, 0, inputs[0], []string{}); exitCode != 0 {
|
||||
t.Errorf("interp.Interpret(%s) exited with code %d, want zero", inputs, exitCode)
|
||||
return false
|
||||
}
|
||||
exitCode := interp.Interpret(mainPkg, 0, inputs[0], []string{})
|
||||
|
||||
// $GOROOT/tests are considered a failure if they print "BUG".
|
||||
if strings.Contains(out.String(), "BUG") {
|
||||
t.Errorf("interp.Interpret(%s) exited zero but output contained 'BUG'", inputs)
|
||||
// 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
|
||||
}
|
||||
|
||||
@ -233,30 +241,7 @@ func run(t *testing.T, dir, input string) bool {
|
||||
|
||||
const slash = string(os.PathSeparator)
|
||||
|
||||
// TestInterp runs the interpreter on a selection of small Go programs.
|
||||
func TestInterp(t *testing.T) {
|
||||
var failures []string
|
||||
|
||||
for _, input := range testdataTests {
|
||||
if !run(t, "testdata"+slash, input) {
|
||||
failures = append(failures, input)
|
||||
}
|
||||
}
|
||||
|
||||
if !testing.Short() {
|
||||
for _, input := range gorootTestTests {
|
||||
if !run(t, filepath.Join(build.Default.GOROOT, "test")+slash, input) {
|
||||
failures = append(failures, input)
|
||||
}
|
||||
}
|
||||
|
||||
for _, input := range gorootSrcPkgTests {
|
||||
if !run(t, filepath.Join(build.Default.GOROOT, "src/pkg")+slash, input) {
|
||||
failures = append(failures, input)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func printFailures(failures []string) {
|
||||
if failures != nil {
|
||||
fmt.Println("The following tests failed:")
|
||||
for _, f := range failures {
|
||||
@ -264,3 +249,92 @@ func TestInterp(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The "normal" success predicate.
|
||||
func exitsZero(exitcode int, _ string) error {
|
||||
if exitcode != 0 {
|
||||
return fmt.Errorf("exit code was %d", exitcode)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// TestTestdataFiles runs the interpreter on testdata/*.go.
|
||||
func TestTestdataFiles(t *testing.T) {
|
||||
var failures []string
|
||||
for _, input := range testdataTests {
|
||||
if !run(t, "testdata"+slash, input, exitsZero) {
|
||||
failures = append(failures, input)
|
||||
}
|
||||
}
|
||||
printFailures(failures)
|
||||
}
|
||||
|
||||
// TestGorootTest runs the interpreter on $GOROOT/test/*.go.
|
||||
func TestGorootTest(t *testing.T) {
|
||||
if testing.Short() {
|
||||
return // too slow (~30s)
|
||||
}
|
||||
|
||||
var failures []string
|
||||
|
||||
// $GOROOT/tests are also considered a failure if they print "BUG".
|
||||
success := func(exitcode int, output string) error {
|
||||
if exitcode != 0 {
|
||||
return fmt.Errorf("exit code was %d", exitcode)
|
||||
}
|
||||
if strings.Contains(output, "BUG") {
|
||||
return fmt.Errorf("exited zero but output contained 'BUG'")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
for _, input := range gorootTestTests {
|
||||
if !run(t, filepath.Join(build.Default.GOROOT, "test")+slash, input, success) {
|
||||
failures = append(failures, input)
|
||||
}
|
||||
}
|
||||
for _, input := range gorootSrcPkgTests {
|
||||
if !run(t, filepath.Join(build.Default.GOROOT, "src/pkg")+slash, input, success) {
|
||||
failures = append(failures, input)
|
||||
}
|
||||
}
|
||||
printFailures(failures)
|
||||
}
|
||||
|
||||
// TestTestmainPackage runs the interpreter on a synthetic "testmain" package.
|
||||
func TestTestmainPackage(t *testing.T) {
|
||||
success := func(exitcode int, output string) error {
|
||||
if exitcode == 0 {
|
||||
return fmt.Errorf("unexpected success")
|
||||
}
|
||||
if !strings.Contains(output, "FAIL: TestFoo") {
|
||||
return fmt.Errorf("missing failure log for TestFoo")
|
||||
}
|
||||
if !strings.Contains(output, "FAIL: TestBar") {
|
||||
return fmt.Errorf("missing failure log for TestBar")
|
||||
}
|
||||
// TODO(adonovan): test benchmarks too
|
||||
return nil
|
||||
}
|
||||
run(t, "testdata"+slash, "a_test.go", success)
|
||||
}
|
||||
|
||||
// CreateTestMainPackage should return nil if there were no tests.
|
||||
func TestNullTestmainPackage(t *testing.T) {
|
||||
imp := importer.New(&importer.Config{Build: build.Default})
|
||||
files, err := importer.ParseFiles(imp.Fset, ".", "testdata/b_test.go")
|
||||
if err != nil {
|
||||
t.Fatalf("ParseFiles failed: %s", err)
|
||||
}
|
||||
mainInfo := imp.CreatePackage("b", files...)
|
||||
prog := ssa.NewProgram(imp.Fset, ssa.SanityCheckFunctions)
|
||||
if err := prog.CreatePackages(imp); err != nil {
|
||||
t.Fatalf("CreatePackages failed: %s", err)
|
||||
}
|
||||
mainPkg := prog.Package(mainInfo.Pkg)
|
||||
if mainPkg.Func("main") != nil {
|
||||
t.Fatalf("unexpected main function")
|
||||
}
|
||||
if prog.CreateTestMainPackage(mainPkg) != nil {
|
||||
t.Fatalf("CreateTestMainPackage returned non-nil")
|
||||
}
|
||||
}
|
||||
|
17
ssa/interp/testdata/a_test.go
vendored
Normal file
17
ssa/interp/testdata/a_test.go
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
package a
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestFoo(t *testing.T) {
|
||||
t.Error("foo")
|
||||
}
|
||||
|
||||
func TestBar(t *testing.T) {
|
||||
t.Error("bar")
|
||||
}
|
||||
|
||||
func BenchmarkWiz(b *testing.B) {
|
||||
b.Error("wiz")
|
||||
}
|
||||
|
||||
// Don't test Examples since that testing package needs pipe(2) for that.
|
11
ssa/interp/testdata/b_test.go
vendored
Normal file
11
ssa/interp/testdata/b_test.go
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
package b
|
||||
|
||||
import "testing"
|
||||
|
||||
func NotATest(t *testing.T) {
|
||||
t.Error("foo")
|
||||
}
|
||||
|
||||
func NotABenchmark(b *testing.B) {
|
||||
b.Error("wiz")
|
||||
}
|
@ -42,7 +42,7 @@ func (prog *Program) CreateTestMainPackage(pkgs ...*Package) *Package {
|
||||
Prog: prog,
|
||||
}
|
||||
init.startBody()
|
||||
var expfuncs []*Function // all exported functions of pkgs, unordered
|
||||
var expfuncs []*Function // all exported functions of *_test.go in pkgs, unordered
|
||||
for _, pkg := range pkgs {
|
||||
// Initialize package to test.
|
||||
var v Call
|
||||
@ -52,7 +52,9 @@ func (prog *Program) CreateTestMainPackage(pkgs ...*Package) *Package {
|
||||
|
||||
// Enumerate its possible tests/benchmarks.
|
||||
for _, mem := range pkg.Members {
|
||||
if f, ok := mem.(*Function); ok && ast.IsExported(f.Name()) {
|
||||
if f, ok := mem.(*Function); ok &&
|
||||
ast.IsExported(f.Name()) &&
|
||||
strings.HasSuffix(prog.Fset.Position(f.Pos()).Filename, "_test.go") {
|
||||
expfuncs = append(expfuncs, f)
|
||||
}
|
||||
}
|
||||
@ -107,12 +109,18 @@ func (prog *Program) CreateTestMainPackage(pkgs ...*Package) *Package {
|
||||
main.startBody()
|
||||
var c Call
|
||||
c.Call.Value = testingMain
|
||||
c.Call.Args = []Value{
|
||||
matcher,
|
||||
testMainSlice(main, expfuncs, "Test", testingMainParams.At(1).Type()),
|
||||
testMainSlice(main, expfuncs, "Benchmark", testingMainParams.At(2).Type()),
|
||||
testMainSlice(main, expfuncs, "Example", testingMainParams.At(3).Type()),
|
||||
|
||||
tests := testMainSlice(main, expfuncs, "Test", testingMainParams.At(1).Type())
|
||||
benchmarks := testMainSlice(main, expfuncs, "Benchmark", testingMainParams.At(2).Type())
|
||||
examples := testMainSlice(main, expfuncs, "Example", testingMainParams.At(3).Type())
|
||||
_, noTests := tests.(*Const) // i.e. nil slice
|
||||
_, noBenchmarks := benchmarks.(*Const)
|
||||
_, noExamples := examples.(*Const)
|
||||
if noTests && noBenchmarks && noExamples {
|
||||
return nil
|
||||
}
|
||||
|
||||
c.Call.Args = []Value{matcher, tests, benchmarks, examples}
|
||||
// Emit: testing.Main(nil, tests, benchmarks, examples)
|
||||
emitTailCall(main, &c)
|
||||
main.finishBody()
|
||||
@ -122,6 +130,7 @@ func (prog *Program) CreateTestMainPackage(pkgs ...*Package) *Package {
|
||||
if prog.mode&LogPackages != 0 {
|
||||
testmain.DumpTo(os.Stderr)
|
||||
}
|
||||
|
||||
if prog.mode&SanityCheckFunctions != 0 {
|
||||
sanityCheckPackage(testmain)
|
||||
}
|
||||
@ -141,7 +150,6 @@ func testMainSlice(fn *Function, expfuncs []*Function, prefix string, slice type
|
||||
|
||||
var testfuncs []*Function
|
||||
for _, f := range expfuncs {
|
||||
// TODO(adonovan): only look at members defined in *_test.go files.
|
||||
if isTest(f.Name(), prefix) && types.IsIdentical(f.Signature, tFunc) {
|
||||
testfuncs = append(testfuncs, f)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user