Skip to content

Commit 45e7e66

Browse files
committed
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 <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: David Chase <[email protected]>
1 parent 97cc4b5 commit 45e7e66

File tree

4 files changed

+184
-75
lines changed

4 files changed

+184
-75
lines changed

src/cmd/compile/internal/gc/ssa_test.go

+121-4
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,16 @@ package gc
66

77
import (
88
"bytes"
9+
"fmt"
10+
"go/ast"
11+
"go/parser"
12+
"go/token"
913
"internal/testenv"
1014
"io/ioutil"
1115
"os"
1216
"os/exec"
1317
"path/filepath"
18+
"runtime"
1419
"strings"
1520
"testing"
1621
)
@@ -104,11 +109,123 @@ func TestGenFlowGraph(t *testing.T) {
104109
runGenTest(t, "flowgraph_generator1.go", "ssa_fg_tmp1")
105110
}
106111

107-
// TestShortCircuit tests OANDAND and OOROR expressions and short circuiting.
108-
func TestShortCircuit(t *testing.T) { runTest(t, "short.go") }
112+
// TestCode runs all the tests in the testdata directory as subtests.
113+
// These tests are special because we want to run them with different
114+
// compiler flags set (and thus they can't just be _test.go files in
115+
// this directory).
116+
func TestCode(t *testing.T) {
117+
testenv.MustHaveGoBuild(t)
118+
gotool := testenv.GoToolPath(t)
119+
120+
// Make a temporary directory to work in.
121+
tmpdir, err := ioutil.TempDir("", "TestCode")
122+
if err != nil {
123+
t.Fatalf("Failed to create temporary directory: %v", err)
124+
}
125+
defer os.RemoveAll(tmpdir)
126+
127+
// Find all the test functions (and the files containing them).
128+
var srcs []string // files containing Test functions
129+
type test struct {
130+
name string // TestFoo
131+
usesFloat bool // might use float operations
132+
}
133+
var tests []test
134+
files, err := ioutil.ReadDir("testdata")
135+
if err != nil {
136+
t.Fatalf("can't read testdata directory: %v", err)
137+
}
138+
for _, f := range files {
139+
if !strings.HasSuffix(f.Name(), "_test.go") {
140+
continue
141+
}
142+
text, err := ioutil.ReadFile(filepath.Join("testdata", f.Name()))
143+
if err != nil {
144+
t.Fatalf("can't read testdata/%s: %v", f.Name(), err)
145+
}
146+
fset := token.NewFileSet()
147+
code, err := parser.ParseFile(fset, f.Name(), text, 0)
148+
if err != nil {
149+
t.Fatalf("can't parse testdata/%s: %v", f.Name(), err)
150+
}
151+
srcs = append(srcs, filepath.Join("testdata", f.Name()))
152+
foundTest := false
153+
for _, d := range code.Decls {
154+
fd, ok := d.(*ast.FuncDecl)
155+
if !ok {
156+
continue
157+
}
158+
if !strings.HasPrefix(fd.Name.Name, "Test") {
159+
continue
160+
}
161+
if fd.Recv != nil {
162+
continue
163+
}
164+
if fd.Type.Results != nil {
165+
continue
166+
}
167+
if len(fd.Type.Params.List) != 1 {
168+
continue
169+
}
170+
p := fd.Type.Params.List[0]
171+
if len(p.Names) != 1 {
172+
continue
173+
}
174+
s, ok := p.Type.(*ast.StarExpr)
175+
if !ok {
176+
continue
177+
}
178+
sel, ok := s.X.(*ast.SelectorExpr)
179+
if !ok {
180+
continue
181+
}
182+
base, ok := sel.X.(*ast.Ident)
183+
if !ok {
184+
continue
185+
}
186+
if base.Name != "testing" {
187+
continue
188+
}
189+
if sel.Sel.Name != "T" {
190+
continue
191+
}
192+
// Found a testing function.
193+
tests = append(tests, test{name: fd.Name.Name, usesFloat: bytes.Contains(text, []byte("float"))})
194+
foundTest = true
195+
}
196+
if !foundTest {
197+
t.Fatalf("test file testdata/%s has no tests in it", f.Name())
198+
}
199+
}
109200

110-
// TestBreakContinue tests that continue and break statements do what they say.
111-
func TestBreakContinue(t *testing.T) { runTest(t, "break.go") }
201+
flags := []string{""}
202+
if runtime.GOARCH == "arm" || runtime.GOARCH == "mips" || runtime.GOARCH == "mips64" {
203+
flags = append(flags, ",softfloat")
204+
}
205+
for _, flag := range flags {
206+
args := []string{"test", "-c", "-gcflags=-d=ssa/check/on" + flag, "-o", filepath.Join(tmpdir, "code.test")}
207+
args = append(args, srcs...)
208+
out, err := exec.Command(gotool, args...).CombinedOutput()
209+
if err != nil || len(out) != 0 {
210+
t.Fatalf("Build failed: %v\n%s\n", err, out)
211+
}
212+
213+
// Now we have a test binary. Run it with all the tests as subtests of this one.
214+
for _, test := range tests {
215+
test := test
216+
if flag == ",softfloat" && !test.usesFloat {
217+
// No point in running the soft float version if the test doesn't use floats.
218+
continue
219+
}
220+
t.Run(fmt.Sprintf("%s%s", test.name[4:], flag), func(t *testing.T) {
221+
out, err := exec.Command(filepath.Join(tmpdir, "code.test"), "-test.run="+test.name).CombinedOutput()
222+
if err != nil || string(out) != "PASS\n" {
223+
t.Errorf("Failed:\n%s\n", out)
224+
}
225+
})
226+
}
227+
}
228+
}
112229

113230
// TestTypeAssertion tests type assertions.
114231
func TestTypeAssertion(t *testing.T) { runTest(t, "assert.go") }

src/cmd/compile/internal/gc/testdata/break.go renamed to src/cmd/compile/internal/gc/testdata/break_test.go

+6-11
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
// run
2-
31
// Copyright 2015 The Go Authors. All rights reserved.
42
// Use of this source code is governed by a BSD-style
53
// license that can be found in the LICENSE file.
@@ -8,6 +6,8 @@
86

97
package main
108

9+
import "testing"
10+
1111
func continuePlain_ssa() int {
1212
var n int
1313
for i := 0; i < 10; i++ {
@@ -214,7 +214,8 @@ Done:
214214
return n
215215
}
216216

217-
func main() {
217+
// TestBreakContinue tests that continue and break statements do what they say.
218+
func TestBreakContinue(t *testing.T) {
218219
tests := [...]struct {
219220
name string
220221
fn func() int
@@ -241,15 +242,9 @@ func main() {
241242
// no select tests; they're identical to switch
242243
}
243244

244-
var failed bool
245245
for _, test := range tests {
246-
if got := test.fn(); test.fn() != test.want {
247-
print(test.name, "()=", got, ", want ", test.want, "\n")
248-
failed = true
246+
if got := test.fn(); got != test.want {
247+
t.Errorf("%s()=%d, want %d", test.name, got, test.want)
249248
}
250249
}
251-
252-
if failed {
253-
panic("failed")
254-
}
255250
}

src/cmd/compile/internal/gc/testdata/short.go

-60
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// Copyright 2015 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
// Tests short circuiting.
6+
7+
package main
8+
9+
import "testing"
10+
11+
func and_ssa(arg1, arg2 bool) bool {
12+
return arg1 && rightCall(arg2)
13+
}
14+
15+
func or_ssa(arg1, arg2 bool) bool {
16+
return arg1 || rightCall(arg2)
17+
}
18+
19+
var rightCalled bool
20+
21+
//go:noinline
22+
func rightCall(v bool) bool {
23+
rightCalled = true
24+
return v
25+
panic("unreached")
26+
}
27+
28+
func testAnd(t *testing.T, arg1, arg2, wantRes bool) {
29+
testShortCircuit(t, "AND", arg1, arg2, and_ssa, arg1, wantRes)
30+
}
31+
func testOr(t *testing.T, arg1, arg2, wantRes bool) {
32+
testShortCircuit(t, "OR", arg1, arg2, or_ssa, !arg1, wantRes)
33+
}
34+
35+
func testShortCircuit(t *testing.T, opName string, arg1, arg2 bool, fn func(bool, bool) bool, wantRightCall, wantRes bool) {
36+
rightCalled = false
37+
got := fn(arg1, arg2)
38+
if rightCalled != wantRightCall {
39+
t.Errorf("failed for %t %s %t; rightCalled=%t want=%t", arg1, opName, arg2, rightCalled, wantRightCall)
40+
}
41+
if wantRes != got {
42+
t.Errorf("failed for %t %s %t; res=%t want=%t", arg1, opName, arg2, got, wantRes)
43+
}
44+
}
45+
46+
// TestShortCircuit tests OANDAND and OOROR expressions and short circuiting.
47+
func TestShortCircuit(t *testing.T) {
48+
testAnd(t, false, false, false)
49+
testAnd(t, false, true, false)
50+
testAnd(t, true, false, false)
51+
testAnd(t, true, true, true)
52+
53+
testOr(t, false, false, false)
54+
testOr(t, false, true, true)
55+
testOr(t, true, false, true)
56+
testOr(t, true, true, true)
57+
}

0 commit comments

Comments
 (0)