Skip to content

Commit f861377

Browse files
committed
go/ssa/interp: redirect interpreter std{out,err} to testing.T.Log
The interpreter tests have long been exceedingly noisy because they write to os.Stdout and os.Stderr directly. This CL temporarily redirects the output to a buffer (via a pipe), which is printed via t.Log once the interpreter returns. This means that a test failure only prints the output relevant to that test. Change-Id: Id1835a9b0f91a09fdc7e61dab38906a7b42e300f Reviewed-on: https://go-review.googlesource.com/c/tools/+/622355 Reviewed-by: Tim King <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]> Auto-Submit: Alan Donovan <[email protected]>
1 parent 9f3c646 commit f861377

File tree

1 file changed

+47
-3
lines changed

1 file changed

+47
-3
lines changed

go/ssa/interp/interp_test.go

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"fmt"
2121
"go/build"
2222
"go/types"
23+
"io"
2324
"log"
2425
"os"
2526
"path/filepath"
@@ -186,10 +187,10 @@ func run(t *testing.T, input string, goroot string) {
186187
var hint string
187188
defer func() {
188189
if hint != "" {
189-
fmt.Println("FAIL")
190-
fmt.Println(hint)
190+
t.Log("FAIL")
191+
t.Log(hint)
191192
} else {
192-
fmt.Println("PASS")
193+
t.Log("PASS")
193194
}
194195

195196
interp.CapturedOutput = nil
@@ -219,10 +220,53 @@ func run(t *testing.T, input string, goroot string) {
219220
panic("bogus SizesFor")
220221
}
221222
hint = fmt.Sprintf("To trace execution, run:\n%% go build golang.org/x/tools/cmd/ssadump && ./ssadump -build=C -test -run --interp=T %s\n", input)
223+
224+
// Capture anything written by the interpreter to os.Std{out,err}
225+
// by temporarily redirecting them to a buffer via a pipe.
226+
//
227+
// While capturing is in effect, we must not write any
228+
// test-related stuff to stderr (including log.Print, t.Log, etc).
229+
//
230+
// Suppress capturing if we are the child process of TestRangeFunc.
231+
// TODO(adonovan): simplify that test using this mechanism.
232+
// Also eliminate the redundant interp.CapturedOutput mechanism.
233+
restore := func() {} // restore files and log the mixed out/err.
234+
if os.Getenv("INTERPTEST_CHILD") == "" {
235+
// Connect std{out,err} to pipe.
236+
r, w, err := os.Pipe()
237+
if err != nil {
238+
t.Fatalf("can't create pipe for stderr: %v", err)
239+
}
240+
savedStdout := os.Stdout
241+
savedStderr := os.Stderr
242+
os.Stdout = w
243+
os.Stderr = w
244+
245+
// Buffer what is written.
246+
var buf bytes.Buffer
247+
done := make(chan struct{})
248+
go func() {
249+
if _, err := io.Copy(&buf, r); err != nil {
250+
fmt.Fprintf(savedStderr, "io.Copy: %v", err)
251+
}
252+
close(done)
253+
}()
254+
255+
// Finally, restore the files and log what was captured.
256+
restore = func() {
257+
os.Stdout = savedStdout
258+
os.Stderr = savedStderr
259+
w.Close()
260+
<-done
261+
t.Logf("Interpreter's stdout+stderr:\n%s", &buf)
262+
}
263+
}
264+
222265
var imode interp.Mode // default mode
223266
// imode |= interp.DisableRecover // enable for debugging
224267
// imode |= interp.EnableTracing // enable for debugging
225268
exitCode := interp.Interpret(mainPkg, imode, sizes, input, []string{})
269+
restore()
226270
if exitCode != 0 {
227271
t.Fatalf("interpreting %s: exit code was %d", input, exitCode)
228272
}

0 commit comments

Comments
 (0)