mirror of
https://github.com/golang/go
synced 2024-11-18 21:34:46 -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",
|
// "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)
|
fmt.Printf("Input: %s\n", input)
|
||||||
|
|
||||||
start := time.Now()
|
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)
|
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 {
|
if _, err := imp.LoadPackage("runtime"); err != nil {
|
||||||
t.Errorf("LoadPackage(runtime) failed: %s", err)
|
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)
|
mainPkg := prog.Package(mainInfo.Pkg)
|
||||||
if mainPkg.Func("main") == nil {
|
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
|
var out bytes.Buffer
|
||||||
interp.CapturedOutput = &out
|
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)
|
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 {
|
exitCode := interp.Interpret(mainPkg, 0, inputs[0], []string{})
|
||||||
t.Errorf("interp.Interpret(%s) exited with code %d, want zero", inputs, exitCode)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// $GOROOT/tests are considered a failure if they print "BUG".
|
// The definition of success varies with each file.
|
||||||
if strings.Contains(out.String(), "BUG") {
|
if err := success(exitCode, out.String()); err != nil {
|
||||||
t.Errorf("interp.Interpret(%s) exited zero but output contained 'BUG'", inputs)
|
t.Errorf("interp.Interpret(%s) failed: %s", inputs, err)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -233,30 +241,7 @@ func run(t *testing.T, dir, input string) bool {
|
|||||||
|
|
||||||
const slash = string(os.PathSeparator)
|
const slash = string(os.PathSeparator)
|
||||||
|
|
||||||
// TestInterp runs the interpreter on a selection of small Go programs.
|
func printFailures(failures []string) {
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if failures != nil {
|
if failures != nil {
|
||||||
fmt.Println("The following tests failed:")
|
fmt.Println("The following tests failed:")
|
||||||
for _, f := range failures {
|
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,
|
Prog: prog,
|
||||||
}
|
}
|
||||||
init.startBody()
|
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 {
|
for _, pkg := range pkgs {
|
||||||
// Initialize package to test.
|
// Initialize package to test.
|
||||||
var v Call
|
var v Call
|
||||||
@ -52,7 +52,9 @@ func (prog *Program) CreateTestMainPackage(pkgs ...*Package) *Package {
|
|||||||
|
|
||||||
// Enumerate its possible tests/benchmarks.
|
// Enumerate its possible tests/benchmarks.
|
||||||
for _, mem := range pkg.Members {
|
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)
|
expfuncs = append(expfuncs, f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -107,12 +109,18 @@ func (prog *Program) CreateTestMainPackage(pkgs ...*Package) *Package {
|
|||||||
main.startBody()
|
main.startBody()
|
||||||
var c Call
|
var c Call
|
||||||
c.Call.Value = testingMain
|
c.Call.Value = testingMain
|
||||||
c.Call.Args = []Value{
|
|
||||||
matcher,
|
tests := testMainSlice(main, expfuncs, "Test", testingMainParams.At(1).Type())
|
||||||
testMainSlice(main, expfuncs, "Test", testingMainParams.At(1).Type()),
|
benchmarks := testMainSlice(main, expfuncs, "Benchmark", testingMainParams.At(2).Type())
|
||||||
testMainSlice(main, expfuncs, "Benchmark", testingMainParams.At(2).Type()),
|
examples := testMainSlice(main, expfuncs, "Example", testingMainParams.At(3).Type())
|
||||||
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)
|
// Emit: testing.Main(nil, tests, benchmarks, examples)
|
||||||
emitTailCall(main, &c)
|
emitTailCall(main, &c)
|
||||||
main.finishBody()
|
main.finishBody()
|
||||||
@ -122,6 +130,7 @@ func (prog *Program) CreateTestMainPackage(pkgs ...*Package) *Package {
|
|||||||
if prog.mode&LogPackages != 0 {
|
if prog.mode&LogPackages != 0 {
|
||||||
testmain.DumpTo(os.Stderr)
|
testmain.DumpTo(os.Stderr)
|
||||||
}
|
}
|
||||||
|
|
||||||
if prog.mode&SanityCheckFunctions != 0 {
|
if prog.mode&SanityCheckFunctions != 0 {
|
||||||
sanityCheckPackage(testmain)
|
sanityCheckPackage(testmain)
|
||||||
}
|
}
|
||||||
@ -141,7 +150,6 @@ func testMainSlice(fn *Function, expfuncs []*Function, prefix string, slice type
|
|||||||
|
|
||||||
var testfuncs []*Function
|
var testfuncs []*Function
|
||||||
for _, f := range expfuncs {
|
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) {
|
if isTest(f.Name(), prefix) && types.IsIdentical(f.Signature, tFunc) {
|
||||||
testfuncs = append(testfuncs, f)
|
testfuncs = append(testfuncs, f)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user