1
0
mirror of https://github.com/golang/go synced 2024-11-12 07:40:23 -07:00

cmd/compile: unify compilation of compiler tests

Before this CL we would build&run each test file individually.
Building the test takes most of the time, a significant fraction of a
second. Running the tests are really fast.

After this CL, we build all the tests at once, then run each
individually. We only have to run the compiler&linker once (or twice,
for softfloat architectures) instead of once per test.

While we're here, organize these tests to fit a bit more into the
standard testing framework.

This is just the organizational CL that changes the testing framework
and migrates 2 tests.  Future tests will follow.

R=go1.12

Update #26469

Change-Id: I1a1e7338c054b51f0c1c4c539d48d3d046b08b7d
Reviewed-on: https://go-review.googlesource.com/126995
Run-TryBot: Keith Randall <khr@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: David Chase <drchase@google.com>
This commit is contained in:
Keith Randall 2018-07-31 12:40:20 -07:00 committed by Keith Randall
parent 97cc4b5123
commit 45e7e66844
4 changed files with 184 additions and 75 deletions

View File

@ -6,11 +6,16 @@ package gc
import (
"bytes"
"fmt"
"go/ast"
"go/parser"
"go/token"
"internal/testenv"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"runtime"
"strings"
"testing"
)
@ -104,11 +109,123 @@ func TestGenFlowGraph(t *testing.T) {
runGenTest(t, "flowgraph_generator1.go", "ssa_fg_tmp1")
}
// TestShortCircuit tests OANDAND and OOROR expressions and short circuiting.
func TestShortCircuit(t *testing.T) { runTest(t, "short.go") }
// TestCode runs all the tests in the testdata directory as subtests.
// These tests are special because we want to run them with different
// compiler flags set (and thus they can't just be _test.go files in
// this directory).
func TestCode(t *testing.T) {
testenv.MustHaveGoBuild(t)
gotool := testenv.GoToolPath(t)
// TestBreakContinue tests that continue and break statements do what they say.
func TestBreakContinue(t *testing.T) { runTest(t, "break.go") }
// Make a temporary directory to work in.
tmpdir, err := ioutil.TempDir("", "TestCode")
if err != nil {
t.Fatalf("Failed to create temporary directory: %v", err)
}
defer os.RemoveAll(tmpdir)
// Find all the test functions (and the files containing them).
var srcs []string // files containing Test functions
type test struct {
name string // TestFoo
usesFloat bool // might use float operations
}
var tests []test
files, err := ioutil.ReadDir("testdata")
if err != nil {
t.Fatalf("can't read testdata directory: %v", err)
}
for _, f := range files {
if !strings.HasSuffix(f.Name(), "_test.go") {
continue
}
text, err := ioutil.ReadFile(filepath.Join("testdata", f.Name()))
if err != nil {
t.Fatalf("can't read testdata/%s: %v", f.Name(), err)
}
fset := token.NewFileSet()
code, err := parser.ParseFile(fset, f.Name(), text, 0)
if err != nil {
t.Fatalf("can't parse testdata/%s: %v", f.Name(), err)
}
srcs = append(srcs, filepath.Join("testdata", f.Name()))
foundTest := false
for _, d := range code.Decls {
fd, ok := d.(*ast.FuncDecl)
if !ok {
continue
}
if !strings.HasPrefix(fd.Name.Name, "Test") {
continue
}
if fd.Recv != nil {
continue
}
if fd.Type.Results != nil {
continue
}
if len(fd.Type.Params.List) != 1 {
continue
}
p := fd.Type.Params.List[0]
if len(p.Names) != 1 {
continue
}
s, ok := p.Type.(*ast.StarExpr)
if !ok {
continue
}
sel, ok := s.X.(*ast.SelectorExpr)
if !ok {
continue
}
base, ok := sel.X.(*ast.Ident)
if !ok {
continue
}
if base.Name != "testing" {
continue
}
if sel.Sel.Name != "T" {
continue
}
// Found a testing function.
tests = append(tests, test{name: fd.Name.Name, usesFloat: bytes.Contains(text, []byte("float"))})
foundTest = true
}
if !foundTest {
t.Fatalf("test file testdata/%s has no tests in it", f.Name())
}
}
flags := []string{""}
if runtime.GOARCH == "arm" || runtime.GOARCH == "mips" || runtime.GOARCH == "mips64" {
flags = append(flags, ",softfloat")
}
for _, flag := range flags {
args := []string{"test", "-c", "-gcflags=-d=ssa/check/on" + flag, "-o", filepath.Join(tmpdir, "code.test")}
args = append(args, srcs...)
out, err := exec.Command(gotool, args...).CombinedOutput()
if err != nil || len(out) != 0 {
t.Fatalf("Build failed: %v\n%s\n", err, out)
}
// Now we have a test binary. Run it with all the tests as subtests of this one.
for _, test := range tests {
test := test
if flag == ",softfloat" && !test.usesFloat {
// No point in running the soft float version if the test doesn't use floats.
continue
}
t.Run(fmt.Sprintf("%s%s", test.name[4:], flag), func(t *testing.T) {
out, err := exec.Command(filepath.Join(tmpdir, "code.test"), "-test.run="+test.name).CombinedOutput()
if err != nil || string(out) != "PASS\n" {
t.Errorf("Failed:\n%s\n", out)
}
})
}
}
}
// TestTypeAssertion tests type assertions.
func TestTypeAssertion(t *testing.T) { runTest(t, "assert.go") }

View File

@ -1,5 +1,3 @@
// run
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@ -8,6 +6,8 @@
package main
import "testing"
func continuePlain_ssa() int {
var n int
for i := 0; i < 10; i++ {
@ -214,7 +214,8 @@ Done:
return n
}
func main() {
// TestBreakContinue tests that continue and break statements do what they say.
func TestBreakContinue(t *testing.T) {
tests := [...]struct {
name string
fn func() int
@ -241,15 +242,9 @@ func main() {
// no select tests; they're identical to switch
}
var failed bool
for _, test := range tests {
if got := test.fn(); test.fn() != test.want {
print(test.name, "()=", got, ", want ", test.want, "\n")
failed = true
if got := test.fn(); got != test.want {
t.Errorf("%s()=%d, want %d", test.name, got, test.want)
}
}
if failed {
panic("failed")
}
}

View File

@ -1,60 +0,0 @@
// run
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Tests short circuiting.
package main
func and_ssa(arg1, arg2 bool) bool {
return arg1 && rightCall(arg2)
}
func or_ssa(arg1, arg2 bool) bool {
return arg1 || rightCall(arg2)
}
var rightCalled bool
//go:noinline
func rightCall(v bool) bool {
rightCalled = true
return v
panic("unreached")
}
func testAnd(arg1, arg2, wantRes bool) { testShortCircuit("AND", arg1, arg2, and_ssa, arg1, wantRes) }
func testOr(arg1, arg2, wantRes bool) { testShortCircuit("OR", arg1, arg2, or_ssa, !arg1, wantRes) }
func testShortCircuit(opName string, arg1, arg2 bool, fn func(bool, bool) bool, wantRightCall, wantRes bool) {
rightCalled = false
got := fn(arg1, arg2)
if rightCalled != wantRightCall {
println("failed for", arg1, opName, arg2, "; rightCalled=", rightCalled, "want=", wantRightCall)
failed = true
}
if wantRes != got {
println("failed for", arg1, opName, arg2, "; res=", got, "want=", wantRes)
failed = true
}
}
var failed = false
func main() {
testAnd(false, false, false)
testAnd(false, true, false)
testAnd(true, false, false)
testAnd(true, true, true)
testOr(false, false, false)
testOr(false, true, true)
testOr(true, false, true)
testOr(true, true, true)
if failed {
panic("failed")
}
}

View File

@ -0,0 +1,57 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Tests short circuiting.
package main
import "testing"
func and_ssa(arg1, arg2 bool) bool {
return arg1 && rightCall(arg2)
}
func or_ssa(arg1, arg2 bool) bool {
return arg1 || rightCall(arg2)
}
var rightCalled bool
//go:noinline
func rightCall(v bool) bool {
rightCalled = true
return v
panic("unreached")
}
func testAnd(t *testing.T, arg1, arg2, wantRes bool) {
testShortCircuit(t, "AND", arg1, arg2, and_ssa, arg1, wantRes)
}
func testOr(t *testing.T, arg1, arg2, wantRes bool) {
testShortCircuit(t, "OR", arg1, arg2, or_ssa, !arg1, wantRes)
}
func testShortCircuit(t *testing.T, opName string, arg1, arg2 bool, fn func(bool, bool) bool, wantRightCall, wantRes bool) {
rightCalled = false
got := fn(arg1, arg2)
if rightCalled != wantRightCall {
t.Errorf("failed for %t %s %t; rightCalled=%t want=%t", arg1, opName, arg2, rightCalled, wantRightCall)
}
if wantRes != got {
t.Errorf("failed for %t %s %t; res=%t want=%t", arg1, opName, arg2, got, wantRes)
}
}
// TestShortCircuit tests OANDAND and OOROR expressions and short circuiting.
func TestShortCircuit(t *testing.T) {
testAnd(t, false, false, false)
testAnd(t, false, true, false)
testAnd(t, true, false, false)
testAnd(t, true, true, true)
testOr(t, false, false, false)
testOr(t, false, true, true)
testOr(t, true, false, true)
testOr(t, true, true, true)
}