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>
import (
"bytes"
+ "fmt"
+ "go/ast"
+ "go/parser"
+ "go/token"
"internal/testenv"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
+ "runtime"
"strings"
"testing"
)
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)
+
+ // 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())
+ }
+ }
-// TestBreakContinue tests that continue and break statements do what they say.
-func TestBreakContinue(t *testing.T) { runTest(t, "break.go") }
+ 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") }
-// 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.
package main
+import "testing"
+
func continuePlain_ssa() int {
var n int
for i := 0; i < 10; i++ {
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
// 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")
- }
}
+++ /dev/null
-// 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")
- }
-}
--- /dev/null
+// 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)
+}