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:
parent
97cc4b5123
commit
45e7e66844
@ -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") }
|
||||
|
@ -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")
|
||||
}
|
||||
}
|
60
src/cmd/compile/internal/gc/testdata/short.go
vendored
60
src/cmd/compile/internal/gc/testdata/short.go
vendored
@ -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")
|
||||
}
|
||||
}
|
57
src/cmd/compile/internal/gc/testdata/short_test.go
vendored
Normal file
57
src/cmd/compile/internal/gc/testdata/short_test.go
vendored
Normal 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)
|
||||
}
|
Loading…
Reference in New Issue
Block a user