]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: unify compilation of compiler tests
authorKeith Randall <khr@google.com>
Tue, 31 Jul 2018 19:40:20 +0000 (12:40 -0700)
committerKeith Randall <khr@golang.org>
Fri, 24 Aug 2018 21:24:58 +0000 (21:24 +0000)
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>
src/cmd/compile/internal/gc/ssa_test.go
src/cmd/compile/internal/gc/testdata/break_test.go [moved from src/cmd/compile/internal/gc/testdata/break.go with 93% similarity]
src/cmd/compile/internal/gc/testdata/short.go [deleted file]
src/cmd/compile/internal/gc/testdata/short_test.go [new file with mode: 0644]

index 73110ea65a7d2d3891ac313ced0e4ab4c133ae0d..9f927262ca7eddeca5436d420d00f65caa345c04 100644 (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)
+
+       // 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") }
similarity index 93%
rename from src/cmd/compile/internal/gc/testdata/break.go
rename to src/cmd/compile/internal/gc/testdata/break_test.go
index 855ef70049c88c37dbcfb13da069ea12c0125acf..50245dfd3186d8eee41a5d787620ae1ee9c4c4d7 100644 (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")
-       }
 }
diff --git a/src/cmd/compile/internal/gc/testdata/short.go b/src/cmd/compile/internal/gc/testdata/short.go
deleted file mode 100644 (file)
index fcec1ba..0000000
+++ /dev/null
@@ -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")
-       }
-}
diff --git a/src/cmd/compile/internal/gc/testdata/short_test.go b/src/cmd/compile/internal/gc/testdata/short_test.go
new file mode 100644 (file)
index 0000000..7a743b5
--- /dev/null
@@ -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)
+}