aboutsummaryrefslogtreecommitdiff
path: root/src/testing
diff options
context:
space:
mode:
authorKatie Hockman <katie@golang.org>2021-10-14 12:32:58 -0400
committerKatie Hockman <katie@golang.org>2021-10-19 15:48:56 +0000
commit067d796549242bec2d33226c9da1e67f092a7be2 (patch)
treebcf3633c27756e3b5bd26b0c119f50e1785b17e1 /src/testing
parent6294207a1c79e318124850155c7b6c23997c8c13 (diff)
downloadgo-067d796549242bec2d33226c9da1e67f092a7be2.tar.xz
testing: write output to buffer when fuzzing
Fixes #48709 Change-Id: Ia6376a2f792946498d6565a53605b3e6c985ea7c Reviewed-on: https://go-review.googlesource.com/c/go/+/355909 Trust: Katie Hockman <katie@golang.org> Run-TryBot: Katie Hockman <katie@golang.org> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Jay Conrod <jayconrod@google.com> Reviewed-by: Roland Shoemaker <roland@golang.org> Reviewed-by: Bryan C. Mills <bcmills@google.com>
Diffstat (limited to 'src/testing')
-rw-r--r--src/testing/fuzz.go28
1 files changed, 20 insertions, 8 deletions
diff --git a/src/testing/fuzz.go b/src/testing/fuzz.go
index 0429f8243d..d5cb5e853f 100644
--- a/src/testing/fuzz.go
+++ b/src/testing/fuzz.go
@@ -5,6 +5,7 @@
package testing
import (
+ "bytes"
"errors"
"flag"
"fmt"
@@ -367,14 +368,14 @@ func (f *F) Fuzz(ff interface{}) {
// run calls fn on a given input, as a subtest with its own T.
// run is analogous to T.Run. The test filtering and cleanup works similarly.
// fn is called in its own goroutine.
- run := func(e corpusEntry) error {
+ run := func(captureOut io.Writer, e corpusEntry) (ok bool) {
if e.Values == nil {
// The corpusEntry must have non-nil Values in order to run the
// test. If Values is nil, it is a bug in our code.
panic(fmt.Sprintf("corpus file %q was not unmarshaled", e.Path))
}
if shouldFailFast() {
- return nil
+ return true
}
testName := f.name
if e.Path != "" {
@@ -405,6 +406,10 @@ func (f *F) Fuzz(ff interface{}) {
},
context: f.testContext,
}
+ if captureOut != nil {
+ // t.parent aliases f.common.
+ t.parent.w = captureOut
+ }
t.w = indenter{&t.common}
if t.chatty != nil {
// TODO(#48132): adjust this to work with test2json.
@@ -426,10 +431,7 @@ func (f *F) Fuzz(ff interface{}) {
})
<-t.signal
f.inFuzzFn = false
- if t.Failed() {
- return errors.New(string(f.output))
- }
- return nil
+ return !t.Failed()
}
switch f.fuzzContext.mode {
@@ -466,7 +468,17 @@ func (f *F) Fuzz(ff interface{}) {
case fuzzWorker:
// Fuzzing is enabled, and this is a worker process. Follow instructions
// from the coordinator.
- if err := f.fuzzContext.deps.RunFuzzWorker(run); err != nil {
+ if err := f.fuzzContext.deps.RunFuzzWorker(func(e corpusEntry) error {
+ // Don't write to f.w (which points to Stdout) if running from a
+ // fuzz worker. This would become very verbose, particularly during
+ // minimization. Return the error instead, and let the caller deal
+ // with the output.
+ var buf bytes.Buffer
+ if ok := run(&buf, e); !ok {
+ return errors.New(buf.String())
+ }
+ return nil
+ }); err != nil {
// Internal errors are marked with f.Fail; user code may call this too, before F.Fuzz.
// The worker will exit with fuzzWorkerExitCode, indicating this is a failure
// (and 'go test' should exit non-zero) but a crasher should not be recorded.
@@ -479,7 +491,7 @@ func (f *F) Fuzz(ff interface{}) {
for _, e := range f.corpus {
name := fmt.Sprintf("%s/%s", f.name, filepath.Base(e.Path))
if _, ok, _ := f.testContext.match.fullName(nil, name); ok {
- run(e)
+ run(f.w, e)
}
}
}