mirror of
https://github.com/golang/go.git
synced 2025-05-24 17:01:26 +00:00
all: update terminology for fuzzing
This change doesn't modify any functionality. It also doesn't update all of the comments and variable names of the internal code, but everything user facing should be correct. Updates #49185 Change-Id: Ia8b2c94b89ba45897c4085ea0c17a3d8896f7ec7 Reviewed-on: https://go-review.googlesource.com/c/go/+/362794 Trust: Katie Hockman <katie@golang.org> Run-TryBot: Katie Hockman <katie@golang.org> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Roland Shoemaker <roland@golang.org>
This commit is contained in:
parent
ccd41cc05e
commit
9d89a5eb64
@ -1547,7 +1547,7 @@
|
|||||||
// 'Go test' recompiles each package along with any files with names matching
|
// 'Go test' recompiles each package along with any files with names matching
|
||||||
// the file pattern "*_test.go".
|
// the file pattern "*_test.go".
|
||||||
// These additional files can contain test functions, benchmark functions, fuzz
|
// These additional files can contain test functions, benchmark functions, fuzz
|
||||||
// targets and example functions. See 'go help testfunc' for more.
|
// tests and example functions. See 'go help testfunc' for more.
|
||||||
// Each listed package causes the execution of a separate test binary.
|
// Each listed package causes the execution of a separate test binary.
|
||||||
// Files whose names begin with "_" (including "_test.go") or "." are ignored.
|
// Files whose names begin with "_" (including "_test.go") or "." are ignored.
|
||||||
//
|
//
|
||||||
@ -2796,7 +2796,7 @@
|
|||||||
// Run each test, benchmark, and fuzz seed n times (default 1).
|
// Run each test, benchmark, and fuzz seed n times (default 1).
|
||||||
// If -cpu is set, run n times for each GOMAXPROCS value.
|
// If -cpu is set, run n times for each GOMAXPROCS value.
|
||||||
// Examples are always run once. -count does not apply to
|
// Examples are always run once. -count does not apply to
|
||||||
// fuzz targets matched by -fuzz.
|
// fuzz tests matched by -fuzz.
|
||||||
//
|
//
|
||||||
// -cover
|
// -cover
|
||||||
// Enable coverage analysis.
|
// Enable coverage analysis.
|
||||||
@ -2824,20 +2824,19 @@
|
|||||||
//
|
//
|
||||||
// -cpu 1,2,4
|
// -cpu 1,2,4
|
||||||
// Specify a list of GOMAXPROCS values for which the tests, benchmarks or
|
// Specify a list of GOMAXPROCS values for which the tests, benchmarks or
|
||||||
// fuzz targets should be executed. The default is the current value
|
// fuzz tests should be executed. The default is the current value
|
||||||
// of GOMAXPROCS. -cpu does not apply to fuzz targets matched by -fuzz.
|
// of GOMAXPROCS. -cpu does not apply to fuzz tests matched by -fuzz.
|
||||||
//
|
//
|
||||||
// -failfast
|
// -failfast
|
||||||
// Do not start new tests after the first test failure.
|
// Do not start new tests after the first test failure.
|
||||||
//
|
//
|
||||||
// -fuzz regexp
|
// -fuzz regexp
|
||||||
// Run the fuzz target matching the regular expression. When specified,
|
// Run the fuzz test matching the regular expression. When specified,
|
||||||
// the command line argument must match exactly one package within the
|
// the command line argument must match exactly one package within the
|
||||||
// main module, and regexp must match exactly one fuzz target within
|
// main module, and regexp must match exactly one fuzz test within
|
||||||
// that package. After tests, benchmarks, seed corpora of other fuzz
|
// that package. Fuzzing will occur after tests, benchmarks, seed corpora
|
||||||
// targets, and examples have completed, the matching target will be
|
// of other fuzz tests, and examples have completed. See the Fuzzing
|
||||||
// fuzzed. See the Fuzzing section of the testing package documentation
|
// section of the testing package documentation for details.
|
||||||
// for details.
|
|
||||||
//
|
//
|
||||||
// -fuzztime t
|
// -fuzztime t
|
||||||
// Run enough iterations of the fuzz test to take t, specified as a
|
// Run enough iterations of the fuzz test to take t, specified as a
|
||||||
@ -2851,14 +2850,14 @@
|
|||||||
// same information as the -v flag in a machine-readable format.
|
// same information as the -v flag in a machine-readable format.
|
||||||
//
|
//
|
||||||
// -list regexp
|
// -list regexp
|
||||||
// List tests, benchmarks, fuzz targets, or examples matching the regular
|
// List tests, benchmarks, fuzz tests, or examples matching the regular
|
||||||
// expression. No tests, benchmarks, fuzz targets, or examples will be run.
|
// expression. No tests, benchmarks, fuzz tests, or examples will be run.
|
||||||
// This will only list top-level tests. No subtest or subbenchmarks will be
|
// This will only list top-level tests. No subtest or subbenchmarks will be
|
||||||
// shown.
|
// shown.
|
||||||
//
|
//
|
||||||
// -parallel n
|
// -parallel n
|
||||||
// Allow parallel execution of test functions that call t.Parallel, and
|
// Allow parallel execution of test functions that call t.Parallel, and
|
||||||
// f.Fuzz functions that call t.Parallel when running the seed corpus.
|
// fuzz targets that call t.Parallel when running the seed corpus.
|
||||||
// The value of this flag is the maximum number of tests to run
|
// The value of this flag is the maximum number of tests to run
|
||||||
// simultaneously.
|
// simultaneously.
|
||||||
// While fuzzing, the value of this flag is the maximum number of
|
// While fuzzing, the value of this flag is the maximum number of
|
||||||
@ -2873,7 +2872,7 @@
|
|||||||
// (see 'go help build').
|
// (see 'go help build').
|
||||||
//
|
//
|
||||||
// -run regexp
|
// -run regexp
|
||||||
// Run only those tests, examples, and fuzz targets matching the regular
|
// Run only those tests, examples, and fuzz tests matching the regular
|
||||||
// expression. For tests, the regular expression is split by unbracketed
|
// expression. For tests, the regular expression is split by unbracketed
|
||||||
// slash (/) characters into a sequence of regular expressions, and each
|
// slash (/) characters into a sequence of regular expressions, and each
|
||||||
// part of a test's identifier must match the corresponding element in
|
// part of a test's identifier must match the corresponding element in
|
||||||
@ -3047,7 +3046,7 @@
|
|||||||
//
|
//
|
||||||
// func BenchmarkXxx(b *testing.B) { ... }
|
// func BenchmarkXxx(b *testing.B) { ... }
|
||||||
//
|
//
|
||||||
// A fuzz target is one named FuzzXxx and should have the signature,
|
// A fuzz test is one named FuzzXxx and should have the signature,
|
||||||
//
|
//
|
||||||
// func FuzzXxx(f *testing.F) { ... }
|
// func FuzzXxx(f *testing.F) { ... }
|
||||||
//
|
//
|
||||||
@ -3090,7 +3089,7 @@
|
|||||||
//
|
//
|
||||||
// The entire test file is presented as the example when it contains a single
|
// The entire test file is presented as the example when it contains a single
|
||||||
// example function, at least one other function, type, variable, or constant
|
// example function, at least one other function, type, variable, or constant
|
||||||
// declaration, and no fuzz targets or test or benchmark functions.
|
// declaration, and no tests, benchmarks, or fuzz tests.
|
||||||
//
|
//
|
||||||
// See the documentation of the testing package for more information.
|
// See the documentation of the testing package for more information.
|
||||||
//
|
//
|
||||||
|
@ -65,7 +65,7 @@ followed by detailed output for each failed package.
|
|||||||
'Go test' recompiles each package along with any files with names matching
|
'Go test' recompiles each package along with any files with names matching
|
||||||
the file pattern "*_test.go".
|
the file pattern "*_test.go".
|
||||||
These additional files can contain test functions, benchmark functions, fuzz
|
These additional files can contain test functions, benchmark functions, fuzz
|
||||||
targets and example functions. See 'go help testfunc' for more.
|
tests and example functions. See 'go help testfunc' for more.
|
||||||
Each listed package causes the execution of a separate test binary.
|
Each listed package causes the execution of a separate test binary.
|
||||||
Files whose names begin with "_" (including "_test.go") or "." are ignored.
|
Files whose names begin with "_" (including "_test.go") or "." are ignored.
|
||||||
|
|
||||||
@ -214,7 +214,7 @@ control the execution of any test:
|
|||||||
Run each test, benchmark, and fuzz seed n times (default 1).
|
Run each test, benchmark, and fuzz seed n times (default 1).
|
||||||
If -cpu is set, run n times for each GOMAXPROCS value.
|
If -cpu is set, run n times for each GOMAXPROCS value.
|
||||||
Examples are always run once. -count does not apply to
|
Examples are always run once. -count does not apply to
|
||||||
fuzz targets matched by -fuzz.
|
fuzz tests matched by -fuzz.
|
||||||
|
|
||||||
-cover
|
-cover
|
||||||
Enable coverage analysis.
|
Enable coverage analysis.
|
||||||
@ -242,20 +242,19 @@ control the execution of any test:
|
|||||||
|
|
||||||
-cpu 1,2,4
|
-cpu 1,2,4
|
||||||
Specify a list of GOMAXPROCS values for which the tests, benchmarks or
|
Specify a list of GOMAXPROCS values for which the tests, benchmarks or
|
||||||
fuzz targets should be executed. The default is the current value
|
fuzz tests should be executed. The default is the current value
|
||||||
of GOMAXPROCS. -cpu does not apply to fuzz targets matched by -fuzz.
|
of GOMAXPROCS. -cpu does not apply to fuzz tests matched by -fuzz.
|
||||||
|
|
||||||
-failfast
|
-failfast
|
||||||
Do not start new tests after the first test failure.
|
Do not start new tests after the first test failure.
|
||||||
|
|
||||||
-fuzz regexp
|
-fuzz regexp
|
||||||
Run the fuzz target matching the regular expression. When specified,
|
Run the fuzz test matching the regular expression. When specified,
|
||||||
the command line argument must match exactly one package within the
|
the command line argument must match exactly one package within the
|
||||||
main module, and regexp must match exactly one fuzz target within
|
main module, and regexp must match exactly one fuzz test within
|
||||||
that package. After tests, benchmarks, seed corpora of other fuzz
|
that package. Fuzzing will occur after tests, benchmarks, seed corpora
|
||||||
targets, and examples have completed, the matching target will be
|
of other fuzz tests, and examples have completed. See the Fuzzing
|
||||||
fuzzed. See the Fuzzing section of the testing package documentation
|
section of the testing package documentation for details.
|
||||||
for details.
|
|
||||||
|
|
||||||
-fuzztime t
|
-fuzztime t
|
||||||
Run enough iterations of the fuzz test to take t, specified as a
|
Run enough iterations of the fuzz test to take t, specified as a
|
||||||
@ -269,14 +268,14 @@ control the execution of any test:
|
|||||||
same information as the -v flag in a machine-readable format.
|
same information as the -v flag in a machine-readable format.
|
||||||
|
|
||||||
-list regexp
|
-list regexp
|
||||||
List tests, benchmarks, fuzz targets, or examples matching the regular
|
List tests, benchmarks, fuzz tests, or examples matching the regular
|
||||||
expression. No tests, benchmarks, fuzz targets, or examples will be run.
|
expression. No tests, benchmarks, fuzz tests, or examples will be run.
|
||||||
This will only list top-level tests. No subtest or subbenchmarks will be
|
This will only list top-level tests. No subtest or subbenchmarks will be
|
||||||
shown.
|
shown.
|
||||||
|
|
||||||
-parallel n
|
-parallel n
|
||||||
Allow parallel execution of test functions that call t.Parallel, and
|
Allow parallel execution of test functions that call t.Parallel, and
|
||||||
f.Fuzz functions that call t.Parallel when running the seed corpus.
|
fuzz targets that call t.Parallel when running the seed corpus.
|
||||||
The value of this flag is the maximum number of tests to run
|
The value of this flag is the maximum number of tests to run
|
||||||
simultaneously.
|
simultaneously.
|
||||||
While fuzzing, the value of this flag is the maximum number of
|
While fuzzing, the value of this flag is the maximum number of
|
||||||
@ -291,7 +290,7 @@ control the execution of any test:
|
|||||||
(see 'go help build').
|
(see 'go help build').
|
||||||
|
|
||||||
-run regexp
|
-run regexp
|
||||||
Run only those tests, examples, and fuzz targets matching the regular
|
Run only those tests, examples, and fuzz tests matching the regular
|
||||||
expression. For tests, the regular expression is split by unbracketed
|
expression. For tests, the regular expression is split by unbracketed
|
||||||
slash (/) characters into a sequence of regular expressions, and each
|
slash (/) characters into a sequence of regular expressions, and each
|
||||||
part of a test's identifier must match the corresponding element in
|
part of a test's identifier must match the corresponding element in
|
||||||
@ -468,7 +467,7 @@ A benchmark function is one named BenchmarkXxx and should have the signature,
|
|||||||
|
|
||||||
func BenchmarkXxx(b *testing.B) { ... }
|
func BenchmarkXxx(b *testing.B) { ... }
|
||||||
|
|
||||||
A fuzz target is one named FuzzXxx and should have the signature,
|
A fuzz test is one named FuzzXxx and should have the signature,
|
||||||
|
|
||||||
func FuzzXxx(f *testing.F) { ... }
|
func FuzzXxx(f *testing.F) { ... }
|
||||||
|
|
||||||
@ -511,7 +510,7 @@ Here is another example where the ordering of the output is ignored:
|
|||||||
|
|
||||||
The entire test file is presented as the example when it contains a single
|
The entire test file is presented as the example when it contains a single
|
||||||
example function, at least one other function, type, variable, or constant
|
example function, at least one other function, type, variable, or constant
|
||||||
declaration, and no fuzz targets or test or benchmark functions.
|
declaration, and no tests, benchmarks, or fuzz tests.
|
||||||
|
|
||||||
See the documentation of the testing package for more information.
|
See the documentation of the testing package for more information.
|
||||||
`,
|
`,
|
||||||
@ -1196,8 +1195,8 @@ func declareCoverVars(p *load.Package, files ...string) map[string]*load.CoverVa
|
|||||||
}
|
}
|
||||||
|
|
||||||
var noTestsToRun = []byte("\ntesting: warning: no tests to run\n")
|
var noTestsToRun = []byte("\ntesting: warning: no tests to run\n")
|
||||||
var noTargetsToFuzz = []byte("\ntesting: warning: no targets to fuzz\n")
|
var noFuzzTestsToFuzz = []byte("\ntesting: warning: no fuzz tests to fuzz\n")
|
||||||
var tooManyTargetsToFuzz = []byte("\ntesting: warning: -fuzz matches more than one target, won't fuzz\n")
|
var tooManyFuzzTestsToFuzz = []byte("\ntesting: warning: -fuzz matches more than one fuzz test, won't fuzz\n")
|
||||||
|
|
||||||
type runCache struct {
|
type runCache struct {
|
||||||
disableCache bool // cache should be disabled for this run
|
disableCache bool // cache should be disabled for this run
|
||||||
@ -1399,11 +1398,11 @@ func (c *runCache) builderRunTest(b *work.Builder, ctx context.Context, a *work.
|
|||||||
if bytes.HasPrefix(out, noTestsToRun[1:]) || bytes.Contains(out, noTestsToRun) {
|
if bytes.HasPrefix(out, noTestsToRun[1:]) || bytes.Contains(out, noTestsToRun) {
|
||||||
norun = " [no tests to run]"
|
norun = " [no tests to run]"
|
||||||
}
|
}
|
||||||
if bytes.HasPrefix(out, noTargetsToFuzz[1:]) || bytes.Contains(out, noTargetsToFuzz) {
|
if bytes.HasPrefix(out, noFuzzTestsToFuzz[1:]) || bytes.Contains(out, noFuzzTestsToFuzz) {
|
||||||
norun = " [no targets to fuzz]"
|
norun = " [no fuzz tests to fuzz]"
|
||||||
}
|
}
|
||||||
if bytes.HasPrefix(out, tooManyTargetsToFuzz[1:]) || bytes.Contains(out, tooManyTargetsToFuzz) {
|
if bytes.HasPrefix(out, tooManyFuzzTestsToFuzz[1:]) || bytes.Contains(out, tooManyFuzzTestsToFuzz) {
|
||||||
norun = " [will not fuzz, -fuzz matches more than one target]"
|
norun = "[-fuzz matches more than one fuzz test, won't fuzz]"
|
||||||
}
|
}
|
||||||
if len(out) > 0 && !bytes.HasSuffix(out, []byte("\n")) {
|
if len(out) > 0 && !bytes.HasSuffix(out, []byte("\n")) {
|
||||||
// Ensure that the output ends with a newline before the "ok"
|
// Ensure that the output ends with a newline before the "ok"
|
||||||
|
10
src/cmd/go/testdata/script/test_fuzz.txt
vendored
10
src/cmd/go/testdata/script/test_fuzz.txt
vendored
@ -60,34 +60,34 @@ stdout ok
|
|||||||
! stdout ^ok
|
! stdout ^ok
|
||||||
! stdout 'fatal here'
|
! stdout 'fatal here'
|
||||||
stdout FAIL
|
stdout FAIL
|
||||||
stdout 'f.Fuzz function'
|
stdout 'fuzz target'
|
||||||
|
|
||||||
# Test that f.Error within f.Fuzz panics
|
# Test that f.Error within f.Fuzz panics
|
||||||
! go test error_fuzz_fn_fuzz_test.go
|
! go test error_fuzz_fn_fuzz_test.go
|
||||||
! stdout ^ok
|
! stdout ^ok
|
||||||
! stdout 'error here'
|
! stdout 'error here'
|
||||||
stdout FAIL
|
stdout FAIL
|
||||||
stdout 'f.Fuzz function'
|
stdout 'fuzz target'
|
||||||
|
|
||||||
# Test that f.Fail within f.Fuzz panics
|
# Test that f.Fail within f.Fuzz panics
|
||||||
! go test fail_fuzz_fn_fuzz_test.go
|
! go test fail_fuzz_fn_fuzz_test.go
|
||||||
! stdout ^ok
|
! stdout ^ok
|
||||||
stdout FAIL
|
stdout FAIL
|
||||||
stdout 'f.Fuzz function'
|
stdout 'fuzz target'
|
||||||
|
|
||||||
# Test that f.Skip within f.Fuzz panics
|
# Test that f.Skip within f.Fuzz panics
|
||||||
! go test skip_fuzz_fn_fuzz_test.go
|
! go test skip_fuzz_fn_fuzz_test.go
|
||||||
! stdout ^ok
|
! stdout ^ok
|
||||||
! stdout 'skip here'
|
! stdout 'skip here'
|
||||||
stdout FAIL
|
stdout FAIL
|
||||||
stdout 'f.Fuzz function'
|
stdout 'fuzz target'
|
||||||
|
|
||||||
# Test that f.Skipped within f.Fuzz panics
|
# Test that f.Skipped within f.Fuzz panics
|
||||||
! go test skipped_fuzz_fn_fuzz_test.go
|
! go test skipped_fuzz_fn_fuzz_test.go
|
||||||
! stdout ^ok
|
! stdout ^ok
|
||||||
! stdout 'f.Skipped is'
|
! stdout 'f.Skipped is'
|
||||||
stdout FAIL
|
stdout FAIL
|
||||||
stdout 'f.Fuzz function'
|
stdout 'fuzz target'
|
||||||
stdout 't.Skipped is false'
|
stdout 't.Skipped is false'
|
||||||
|
|
||||||
# Test that runtime.Goexit within the fuzz function is an error.
|
# Test that runtime.Goexit within the fuzz function is an error.
|
||||||
|
@ -14,7 +14,7 @@ stdout '^ok'
|
|||||||
go test -fuzz ThisWillNotMatch -fuzztime 1x standalone_fuzz_test.go
|
go test -fuzz ThisWillNotMatch -fuzztime 1x standalone_fuzz_test.go
|
||||||
! stdout '^ok.*no tests to run'
|
! stdout '^ok.*no tests to run'
|
||||||
stdout '^ok'
|
stdout '^ok'
|
||||||
stdout 'no targets to fuzz'
|
stdout 'no fuzz tests to fuzz'
|
||||||
|
|
||||||
[short] stop
|
[short] stop
|
||||||
|
|
||||||
@ -26,7 +26,7 @@ stdout '^ok'
|
|||||||
# Matches no fuzz targets.
|
# Matches no fuzz targets.
|
||||||
go test -run ThisWillNotMatch standalone_fuzz_test.go
|
go test -run ThisWillNotMatch standalone_fuzz_test.go
|
||||||
stdout '^ok.*no tests to run'
|
stdout '^ok.*no tests to run'
|
||||||
! stdout 'no targets to fuzz'
|
! stdout 'no fuzz tests to fuzz'
|
||||||
|
|
||||||
-- standalone_fuzz_test.go --
|
-- standalone_fuzz_test.go --
|
||||||
package standalone_fuzz
|
package standalone_fuzz
|
||||||
|
@ -18,7 +18,7 @@ go test -fuzz=. -fuzztime=1x ./one
|
|||||||
|
|
||||||
# With fuzzing enabled, at most one target in the same package may match.
|
# With fuzzing enabled, at most one target in the same package may match.
|
||||||
! go test -fuzz=. ./two
|
! go test -fuzz=. ./two
|
||||||
stdout '^testing: will not fuzz, -fuzz matches more than one target: \[FuzzOne FuzzTwo\]$'
|
stdout '^testing: will not fuzz, -fuzz matches more than one fuzz test: \[FuzzOne FuzzTwo\]$'
|
||||||
go test -fuzz=FuzzTwo -fuzztime=1x ./two
|
go test -fuzz=FuzzTwo -fuzztime=1x ./two
|
||||||
|
|
||||||
-- go.mod --
|
-- go.mod --
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
! exists want
|
! exists want
|
||||||
! go test -fuzz=. -parallel=1 -fuzztime=110x -fuzzminimizetime=10x -v
|
! go test -fuzz=. -parallel=1 -fuzztime=110x -fuzzminimizetime=10x -v
|
||||||
stdout 'fuzzing process terminated unexpectedly'
|
stdout 'fuzzing process terminated unexpectedly'
|
||||||
stdout 'Crash written to testdata'
|
stdout 'Failing input written to testdata'
|
||||||
|
|
||||||
# Run the fuzz target without fuzzing. The fuzz function is called with the
|
# Run the fuzz target without fuzzing. The fuzz function is called with the
|
||||||
# crashing input in testdata. The test passes if that input is identical to
|
# crashing input in testdata. The test passes if that input is identical to
|
||||||
|
@ -6,7 +6,7 @@ env GOCACHE=$WORK/cache
|
|||||||
# and doesn't write anything to testdata/fuzz
|
# and doesn't write anything to testdata/fuzz
|
||||||
! go test -fuzz=FuzzWithAdd -run=FuzzWithAdd -fuzztime=1x
|
! go test -fuzz=FuzzWithAdd -run=FuzzWithAdd -fuzztime=1x
|
||||||
! stdout ^ok
|
! stdout ^ok
|
||||||
! stdout 'Crash written to testdata[/\\]fuzz[/\\]FuzzWithAdd[/\\]'
|
! stdout 'Failing input written to testdata[/\\]fuzz[/\\]FuzzWithAdd[/\\]'
|
||||||
stdout FAIL
|
stdout FAIL
|
||||||
|
|
||||||
# Test that fuzzing a target with a sucess in f.Add and a fuzztime of only
|
# Test that fuzzing a target with a sucess in f.Add and a fuzztime of only
|
||||||
@ -19,15 +19,15 @@ stdout ok
|
|||||||
# and doesn't write anything to testdata/fuzz
|
# and doesn't write anything to testdata/fuzz
|
||||||
! go test -fuzz=FuzzWithTestdata -run=FuzzWithTestdata -fuzztime=1x
|
! go test -fuzz=FuzzWithTestdata -run=FuzzWithTestdata -fuzztime=1x
|
||||||
! stdout ^ok
|
! stdout ^ok
|
||||||
! stdout 'Crash written to testdata[/\\]fuzz[/\\]FuzzWithTestdata[/\\]'
|
! stdout 'Failing input written to testdata[/\\]fuzz[/\\]FuzzWithTestdata[/\\]'
|
||||||
stdout 'found a crash while testing seed corpus entry: FuzzWithTestdata/1'
|
stdout 'failure while testing seed corpus entry: FuzzWithTestdata/1'
|
||||||
stdout FAIL
|
stdout FAIL
|
||||||
|
|
||||||
# Test that fuzzing a target with no seed corpus or cache finds a crash, prints
|
# Test that fuzzing a target with no seed corpus or cache finds a crash, prints
|
||||||
# it, and write it to testdata
|
# it, and write it to testdata
|
||||||
! go test -fuzz=FuzzWithNoCache -run=FuzzWithNoCache -fuzztime=1x
|
! go test -fuzz=FuzzWithNoCache -run=FuzzWithNoCache -fuzztime=1x
|
||||||
! stdout ^ok
|
! stdout ^ok
|
||||||
stdout 'Crash written to testdata[/\\]fuzz[/\\]FuzzWithNoCache[/\\]'
|
stdout 'Failing input written to testdata[/\\]fuzz[/\\]FuzzWithNoCache[/\\]'
|
||||||
stdout FAIL
|
stdout FAIL
|
||||||
|
|
||||||
# Write a crashing input to the cache
|
# Write a crashing input to the cache
|
||||||
@ -38,7 +38,7 @@ cp cache-file $GOCACHE/fuzz/example.com/x/FuzzWithCache/1
|
|||||||
# and writes this as a "new" crash to testdata/fuzz
|
# and writes this as a "new" crash to testdata/fuzz
|
||||||
! go test -fuzz=FuzzWithCache -run=FuzzWithCache -fuzztime=1x
|
! go test -fuzz=FuzzWithCache -run=FuzzWithCache -fuzztime=1x
|
||||||
! stdout ^ok
|
! stdout ^ok
|
||||||
stdout 'Crash written to testdata[/\\]fuzz[/\\]FuzzWithCache[/\\]'
|
stdout 'Failing input written to testdata[/\\]fuzz[/\\]FuzzWithCache[/\\]'
|
||||||
stdout FAIL
|
stdout FAIL
|
||||||
|
|
||||||
# Write a crashing input to the cache
|
# Write a crashing input to the cache
|
||||||
@ -52,7 +52,7 @@ cp cache-file-bytes $GOCACHE/fuzz/example.com/x/FuzzWithMinimizableCache/1
|
|||||||
stdout 'gathering baseline coverage'
|
stdout 'gathering baseline coverage'
|
||||||
stdout 'got the minimum size!'
|
stdout 'got the minimum size!'
|
||||||
stdout 'contains a non-zero byte of length 10'
|
stdout 'contains a non-zero byte of length 10'
|
||||||
stdout 'Crash written to testdata[/\\]fuzz[/\\]FuzzWithMinimizableCache[/\\]'
|
stdout 'Failing input written to testdata[/\\]fuzz[/\\]FuzzWithMinimizableCache[/\\]'
|
||||||
stdout FAIL
|
stdout FAIL
|
||||||
# Make sure this crash didn't come from fuzzing
|
# Make sure this crash didn't come from fuzzing
|
||||||
# (the log line that states fuzzing began shouldn't have printed)
|
# (the log line that states fuzzing began shouldn't have printed)
|
||||||
@ -70,7 +70,7 @@ go clean -fuzzcache
|
|||||||
# the crash and doesn't write anything to testdata/fuzz -fuzztime=1x
|
# the crash and doesn't write anything to testdata/fuzz -fuzztime=1x
|
||||||
! go test -fuzz=FuzzWithAdd -run=None
|
! go test -fuzz=FuzzWithAdd -run=None
|
||||||
! stdout ^ok
|
! stdout ^ok
|
||||||
! stdout 'Crash written to testdata[/\\]fuzz[/\\]FuzzWithAdd[/\\]'
|
! stdout 'Failing input written to testdata[/\\]fuzz[/\\]FuzzWithAdd[/\\]'
|
||||||
stdout FAIL
|
stdout FAIL
|
||||||
|
|
||||||
# Test that fuzzing a target (with -run=None set) with a sucess in f.Add and a
|
# Test that fuzzing a target (with -run=None set) with a sucess in f.Add and a
|
||||||
@ -83,7 +83,7 @@ stdout ok
|
|||||||
# testdata/fuzz prints the crash and doesn't write anything to testdata/fuzz
|
# testdata/fuzz prints the crash and doesn't write anything to testdata/fuzz
|
||||||
! go test -fuzz=FuzzWithTestdata -run=None -fuzztime=1x
|
! go test -fuzz=FuzzWithTestdata -run=None -fuzztime=1x
|
||||||
! stdout ^ok
|
! stdout ^ok
|
||||||
! stdout 'Crash written to testdata[/\\]fuzz[/\\]FuzzWithTestdata[/\\]'
|
! stdout 'Failing input written to testdata[/\\]fuzz[/\\]FuzzWithTestdata[/\\]'
|
||||||
stdout FAIL
|
stdout FAIL
|
||||||
|
|
||||||
# Write a crashing input to the cache
|
# Write a crashing input to the cache
|
||||||
@ -94,7 +94,7 @@ cp cache-file $GOCACHE/fuzz/example.com/x/FuzzRunNoneWithCache/1
|
|||||||
# prints the crash and writes this as a "new" crash to testdata/fuzz
|
# prints the crash and writes this as a "new" crash to testdata/fuzz
|
||||||
! go test -fuzz=FuzzRunNoneWithCache -run=None -fuzztime=1x
|
! go test -fuzz=FuzzRunNoneWithCache -run=None -fuzztime=1x
|
||||||
! stdout ^ok
|
! stdout ^ok
|
||||||
stdout 'Crash written to testdata[/\\]fuzz[/\\]FuzzRunNoneWithCache[/\\]'
|
stdout 'Failing input written to testdata[/\\]fuzz[/\\]FuzzRunNoneWithCache[/\\]'
|
||||||
stdout FAIL
|
stdout FAIL
|
||||||
|
|
||||||
# Clear the fuzz cache and make sure it's gone
|
# Clear the fuzz cache and make sure it's gone
|
||||||
@ -109,14 +109,14 @@ go clean -fuzzcache
|
|||||||
go test -c
|
go test -c
|
||||||
! exec ./x.test$GOEXE -test.fuzz=FuzzWithAdd -test.run=FuzzWithAdd -test.fuzztime=1x -test.fuzzcachedir=$WORK/cache
|
! exec ./x.test$GOEXE -test.fuzz=FuzzWithAdd -test.run=FuzzWithAdd -test.fuzztime=1x -test.fuzzcachedir=$WORK/cache
|
||||||
! stdout ^ok
|
! stdout ^ok
|
||||||
! stdout 'Crash written to testdata[/\\]fuzz[/\\]FuzzWithAdd[/\\]'
|
! stdout 'Failing input written to testdata[/\\]fuzz[/\\]FuzzWithAdd[/\\]'
|
||||||
stdout FAIL
|
stdout FAIL
|
||||||
stderr warning
|
stderr warning
|
||||||
|
|
||||||
go test -c
|
go test -c
|
||||||
! exec ./x.test$GOEXE -test.fuzz=FuzzWithTestdata -test.run=FuzzWithTestdata -test.fuzztime=1x -test.fuzzcachedir=$WORK/cache
|
! exec ./x.test$GOEXE -test.fuzz=FuzzWithTestdata -test.run=FuzzWithTestdata -test.fuzztime=1x -test.fuzzcachedir=$WORK/cache
|
||||||
! stdout ^ok
|
! stdout ^ok
|
||||||
! stdout 'Crash written to testdata[/\\]fuzz[/\\]FuzzWithTestdata[/\\]'
|
! stdout 'Failing input written to testdata[/\\]fuzz[/\\]FuzzWithTestdata[/\\]'
|
||||||
stdout FAIL
|
stdout FAIL
|
||||||
stderr warning
|
stderr warning
|
||||||
|
|
||||||
|
@ -44,13 +44,13 @@ type Example struct {
|
|||||||
// identifiers from other packages (or predeclared identifiers, such as
|
// identifiers from other packages (or predeclared identifiers, such as
|
||||||
// "int") and the test file does not include a dot import.
|
// "int") and the test file does not include a dot import.
|
||||||
// - The entire test file is the example: the file contains exactly one
|
// - The entire test file is the example: the file contains exactly one
|
||||||
// example function, zero test, fuzz target, or benchmark function, and at
|
// example function, zero test, fuzz test, or benchmark function, and at
|
||||||
// least one top-level function, type, variable, or constant declaration
|
// least one top-level function, type, variable, or constant declaration
|
||||||
// other than the example function.
|
// other than the example function.
|
||||||
func Examples(testFiles ...*ast.File) []*Example {
|
func Examples(testFiles ...*ast.File) []*Example {
|
||||||
var list []*Example
|
var list []*Example
|
||||||
for _, file := range testFiles {
|
for _, file := range testFiles {
|
||||||
hasTests := false // file contains tests, fuzz targets, or benchmarks
|
hasTests := false // file contains tests, fuzz test, or benchmarks
|
||||||
numDecl := 0 // number of non-import declarations in the file
|
numDecl := 0 // number of non-import declarations in the file
|
||||||
var flist []*Example
|
var flist []*Example
|
||||||
for _, decl := range file.Decls {
|
for _, decl := range file.Decls {
|
||||||
@ -133,7 +133,7 @@ func exampleOutput(b *ast.BlockStmt, comments []*ast.CommentGroup) (output strin
|
|||||||
return "", false, false // no suitable comment found
|
return "", false, false // no suitable comment found
|
||||||
}
|
}
|
||||||
|
|
||||||
// isTest tells whether name looks like a test, example, fuzz target, or
|
// isTest tells whether name looks like a test, example, fuzz test, or
|
||||||
// benchmark. It is a Test (say) if there is a character after Test that is not
|
// benchmark. It is a Test (say) if there is a character after Test that is not
|
||||||
// a lower-case letter. (We don't want Testiness.)
|
// a lower-case letter. (We don't want Testiness.)
|
||||||
func isTest(name, prefix string) bool {
|
func isTest(name, prefix string) bool {
|
||||||
|
@ -232,7 +232,7 @@ func CoordinateFuzzing(ctx context.Context, opts CoordinateFuzzingOpts) (err err
|
|||||||
if result.crasherMsg != "" {
|
if result.crasherMsg != "" {
|
||||||
if c.warmupRun() && result.entry.IsSeed {
|
if c.warmupRun() && result.entry.IsSeed {
|
||||||
target := filepath.Base(c.opts.CorpusDir)
|
target := filepath.Base(c.opts.CorpusDir)
|
||||||
fmt.Fprintf(c.opts.Log, "found a crash while testing seed corpus entry: %s/%s\n", target, testName(result.entry.Parent))
|
fmt.Fprintf(c.opts.Log, "failure while testing seed corpus entry: %s/%s\n", target, testName(result.entry.Parent))
|
||||||
stop(errors.New(result.crasherMsg))
|
stop(errors.New(result.crasherMsg))
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -246,7 +246,7 @@ func CoordinateFuzzing(ctx context.Context, opts CoordinateFuzzingOpts) (err err
|
|||||||
// Send it back to a worker for minimization. Disable inputC so
|
// Send it back to a worker for minimization. Disable inputC so
|
||||||
// other workers don't continue fuzzing.
|
// other workers don't continue fuzzing.
|
||||||
c.crashMinimizing = &result
|
c.crashMinimizing = &result
|
||||||
fmt.Fprintf(c.opts.Log, "fuzz: minimizing %d-byte crash file\n", len(result.entry.Data))
|
fmt.Fprintf(c.opts.Log, "fuzz: minimizing %d-byte failing input file\n", len(result.entry.Data))
|
||||||
c.queueForMinimization(result, nil)
|
c.queueForMinimization(result, nil)
|
||||||
} else if !crashWritten {
|
} else if !crashWritten {
|
||||||
// Found a crasher that's either minimized or not minimizable.
|
// Found a crasher that's either minimized or not minimizable.
|
||||||
|
@ -19,9 +19,9 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func initFuzzFlags() {
|
func initFuzzFlags() {
|
||||||
matchFuzz = flag.String("test.fuzz", "", "run the fuzz target matching `regexp`")
|
matchFuzz = flag.String("test.fuzz", "", "run the fuzz test matching `regexp`")
|
||||||
flag.Var(&fuzzDuration, "test.fuzztime", "time to spend fuzzing; default is to run indefinitely")
|
flag.Var(&fuzzDuration, "test.fuzztime", "time to spend fuzzing; default is to run indefinitely")
|
||||||
flag.Var(&minimizeDuration, "test.fuzzminimizetime", "time to spend minimizing a value after finding a crash")
|
flag.Var(&minimizeDuration, "test.fuzzminimizetime", "time to spend minimizing a value after finding a failing input")
|
||||||
fuzzCacheDir = flag.String("test.fuzzcachedir", "", "directory where interesting fuzzing inputs are stored")
|
fuzzCacheDir = flag.String("test.fuzzcachedir", "", "directory where interesting fuzzing inputs are stored")
|
||||||
isFuzzWorker = flag.Bool("test.fuzzworker", false, "coordinate with the parent process to fuzz random values")
|
isFuzzWorker = flag.Bool("test.fuzzworker", false, "coordinate with the parent process to fuzz random values")
|
||||||
}
|
}
|
||||||
@ -33,34 +33,38 @@ var (
|
|||||||
fuzzCacheDir *string
|
fuzzCacheDir *string
|
||||||
isFuzzWorker *bool
|
isFuzzWorker *bool
|
||||||
|
|
||||||
// corpusDir is the parent directory of the target's seed corpus within
|
// corpusDir is the parent directory of the fuzz test's seed corpus within
|
||||||
// the package.
|
// the package.
|
||||||
corpusDir = "testdata/fuzz"
|
corpusDir = "testdata/fuzz"
|
||||||
)
|
)
|
||||||
|
|
||||||
// fuzzWorkerExitCode is used as an exit code by fuzz worker processes after an internal error.
|
// fuzzWorkerExitCode is used as an exit code by fuzz worker processes after an
|
||||||
// This distinguishes internal errors from uncontrolled panics and other crashes.
|
// internal error. This distinguishes internal errors from uncontrolled panics
|
||||||
// Keep in sync with internal/fuzz.workerExitCode.
|
// and other failiures. Keep in sync with internal/fuzz.workerExitCode.
|
||||||
const fuzzWorkerExitCode = 70
|
const fuzzWorkerExitCode = 70
|
||||||
|
|
||||||
// InternalFuzzTarget is an internal type but exported because it is cross-package;
|
// InternalFuzzTarget is an internal type but exported because it is
|
||||||
// it is part of the implementation of the "go test" command.
|
// cross-package; it is part of the implementation of the "go test" command.
|
||||||
type InternalFuzzTarget struct {
|
type InternalFuzzTarget struct {
|
||||||
Name string
|
Name string
|
||||||
Fn func(f *F)
|
Fn func(f *F)
|
||||||
}
|
}
|
||||||
|
|
||||||
// F is a type passed to fuzz targets.
|
// F is a type passed to fuzz tests.
|
||||||
//
|
//
|
||||||
// A fuzz target may add seed corpus entries using F.Add or by storing files in
|
// Fuzz tests run generated inputs against a provided fuzz target, which can
|
||||||
// the testdata/fuzz/<FuzzTargetName> directory. The fuzz target must then
|
// find and report potential bugs in the code being tested.
|
||||||
// call F.Fuzz once to provide a fuzz function. See the testing package
|
|
||||||
// documentation for an example, and see the F.Fuzz and F.Add method
|
|
||||||
// documentation for details.
|
|
||||||
//
|
//
|
||||||
// *F methods can only be called before (*F).Fuzz. Once inside the function
|
// A fuzz test runs the seed corpus by default, which includes entries provided
|
||||||
// passed to (*F).Fuzz, only (*T) methods can be used. The only *F methods that
|
// by (*F).Add and entries in the testdata/fuzz/<FuzzTestName> directory. After
|
||||||
// are allowed in the (*F).Fuzz function are (*F).Failed and (*F).Name.
|
// any necessary setup and calls to (*F).Add, the fuzz test must then call
|
||||||
|
// (*F).Fuzz to provide the fuzz target. See the testing package documentation
|
||||||
|
// for an example, and see the F.Fuzz and F.Add method documentation for
|
||||||
|
// details.
|
||||||
|
//
|
||||||
|
// *F methods can only be called before (*F).Fuzz. Once the the test is
|
||||||
|
// executing the fuzz target, only (*T) methods can be used. The only *F methods
|
||||||
|
// that are allowed in the (*F).Fuzz function are (*F).Failed and (*F).Name.
|
||||||
type F struct {
|
type F struct {
|
||||||
common
|
common
|
||||||
fuzzContext *fuzzContext
|
fuzzContext *fuzzContext
|
||||||
@ -97,7 +101,7 @@ type corpusEntry = struct {
|
|||||||
// Helper may be called simultaneously from multiple goroutines.
|
// Helper may be called simultaneously from multiple goroutines.
|
||||||
func (f *F) Helper() {
|
func (f *F) Helper() {
|
||||||
if f.inFuzzFn {
|
if f.inFuzzFn {
|
||||||
panic("testing: f.Helper was called inside the f.Fuzz function, use t.Helper instead")
|
panic("testing: f.Helper was called inside the fuzz target, use t.Helper instead")
|
||||||
}
|
}
|
||||||
|
|
||||||
// common.Helper is inlined here.
|
// common.Helper is inlined here.
|
||||||
@ -125,7 +129,7 @@ func (f *F) Fail() {
|
|||||||
// (*F).Fail may be called by (*T).Fail, which we should allow. However, we
|
// (*F).Fail may be called by (*T).Fail, which we should allow. However, we
|
||||||
// shouldn't allow direct (*F).Fail calls from inside the (*F).Fuzz function.
|
// shouldn't allow direct (*F).Fail calls from inside the (*F).Fuzz function.
|
||||||
if f.inFuzzFn {
|
if f.inFuzzFn {
|
||||||
panic("testing: f.Fail was called inside the f.Fuzz function, use t.Fail instead")
|
panic("testing: f.Fail was called inside the fuzz target, use t.Fail instead")
|
||||||
}
|
}
|
||||||
f.common.Helper()
|
f.common.Helper()
|
||||||
f.common.Fail()
|
f.common.Fail()
|
||||||
@ -136,15 +140,15 @@ func (f *F) Skipped() bool {
|
|||||||
// (*F).Skipped may be called by tRunner, which we should allow. However, we
|
// (*F).Skipped may be called by tRunner, which we should allow. However, we
|
||||||
// shouldn't allow direct (*F).Skipped calls from inside the (*F).Fuzz function.
|
// shouldn't allow direct (*F).Skipped calls from inside the (*F).Fuzz function.
|
||||||
if f.inFuzzFn {
|
if f.inFuzzFn {
|
||||||
panic("testing: f.Skipped was called inside the f.Fuzz function, use t.Skipped instead")
|
panic("testing: f.Skipped was called inside the fuzz target, use t.Skipped instead")
|
||||||
}
|
}
|
||||||
f.common.Helper()
|
f.common.Helper()
|
||||||
return f.common.Skipped()
|
return f.common.Skipped()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add will add the arguments to the seed corpus for the fuzz target. This will
|
// Add will add the arguments to the seed corpus for the fuzz test. This will be
|
||||||
// be a no-op if called after or within the Fuzz function. The args must match
|
// a no-op if called after or within the fuzz target, and args must match the
|
||||||
// those in the Fuzz function.
|
// arguments for the fuzz target.
|
||||||
func (f *F) Add(args ...interface{}) {
|
func (f *F) Add(args ...interface{}) {
|
||||||
var values []interface{}
|
var values []interface{}
|
||||||
for i := range args {
|
for i := range args {
|
||||||
@ -220,7 +224,7 @@ func (f *F) Fuzz(ff interface{}) {
|
|||||||
panic("testing: F.Fuzz must receive a function")
|
panic("testing: F.Fuzz must receive a function")
|
||||||
}
|
}
|
||||||
if fnType.NumIn() < 2 || fnType.In(0) != reflect.TypeOf((*T)(nil)) {
|
if fnType.NumIn() < 2 || fnType.In(0) != reflect.TypeOf((*T)(nil)) {
|
||||||
panic("testing: F.Fuzz function must receive at least two arguments, where the first argument is a *T")
|
panic("testing: fuzz target must receive at least two arguments, where the first argument is a *T")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save the types of the function to compare against the corpus.
|
// Save the types of the function to compare against the corpus.
|
||||||
@ -354,7 +358,7 @@ func (f *F) Fuzz(ff interface{}) {
|
|||||||
fmt.Fprintf(f.w, "%v\n", err)
|
fmt.Fprintf(f.w, "%v\n", err)
|
||||||
if crashErr, ok := err.(fuzzCrashError); ok {
|
if crashErr, ok := err.(fuzzCrashError); ok {
|
||||||
crashPath := crashErr.CrashPath()
|
crashPath := crashErr.CrashPath()
|
||||||
fmt.Fprintf(f.w, "Crash written to %s\n", crashPath)
|
fmt.Fprintf(f.w, "Failing input written to %s\n", crashPath)
|
||||||
testName := filepath.Base(crashPath)
|
testName := filepath.Base(crashPath)
|
||||||
fmt.Fprintf(f.w, "To re-run:\ngo test -run=%s/%s\n", f.name, testName)
|
fmt.Fprintf(f.w, "To re-run:\ngo test -run=%s/%s\n", f.name, testName)
|
||||||
}
|
}
|
||||||
@ -378,7 +382,7 @@ func (f *F) Fuzz(ff interface{}) {
|
|||||||
}); err != nil {
|
}); err != nil {
|
||||||
// Internal errors are marked with f.Fail; user code may call this too, before F.Fuzz.
|
// 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
|
// 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.
|
// (and 'go test' should exit non-zero) but a failing input should not be recorded.
|
||||||
f.Errorf("communicating with fuzzing coordinator: %v", err)
|
f.Errorf("communicating with fuzzing coordinator: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -415,7 +419,7 @@ func (f *F) report() {
|
|||||||
type fuzzResult struct {
|
type fuzzResult struct {
|
||||||
N int // The number of iterations.
|
N int // The number of iterations.
|
||||||
T time.Duration // The total time taken.
|
T time.Duration // The total time taken.
|
||||||
Error error // Error is the error from the crash
|
Error error // Error is the error from the failing input
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r fuzzResult) String() string {
|
func (r fuzzResult) String() string {
|
||||||
@ -427,7 +431,7 @@ func (r fuzzResult) String() string {
|
|||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
// fuzzCrashError is satisfied by a crash detected within the fuzz function.
|
// fuzzCrashError is satisfied by a failing input detected while fuzzing.
|
||||||
// These errors are written to the seed corpus and can be re-run with 'go test'.
|
// These errors are written to the seed corpus and can be re-run with 'go test'.
|
||||||
// Errors within the fuzzing framework (like I/O errors between coordinator
|
// Errors within the fuzzing framework (like I/O errors between coordinator
|
||||||
// and worker processes) don't satisfy this interface.
|
// and worker processes) don't satisfy this interface.
|
||||||
@ -437,12 +441,12 @@ type fuzzCrashError interface {
|
|||||||
|
|
||||||
// CrashPath returns the path of the subtest that corresponds to the saved
|
// CrashPath returns the path of the subtest that corresponds to the saved
|
||||||
// crash input file in the seed corpus. The test can be re-run with go test
|
// crash input file in the seed corpus. The test can be re-run with go test
|
||||||
// -run=$target/$name $target is the fuzz target name, and $name is the
|
// -run=$test/$name $test is the fuzz test name, and $name is the
|
||||||
// filepath.Base of the string returned here.
|
// filepath.Base of the string returned here.
|
||||||
CrashPath() string
|
CrashPath() string
|
||||||
}
|
}
|
||||||
|
|
||||||
// fuzzContext holds fields common to all fuzz targets.
|
// fuzzContext holds fields common to all fuzz tests.
|
||||||
type fuzzContext struct {
|
type fuzzContext struct {
|
||||||
deps testDeps
|
deps testDeps
|
||||||
mode fuzzMode
|
mode fuzzMode
|
||||||
@ -456,12 +460,12 @@ const (
|
|||||||
fuzzWorker
|
fuzzWorker
|
||||||
)
|
)
|
||||||
|
|
||||||
// runFuzzTargets runs the fuzz targets matching the pattern for -run. This will
|
// runFuzzTests runs the fuzz tests matching the pattern for -run. This will
|
||||||
// only run the f.Fuzz function for each seed corpus without using the fuzzing
|
// only run the (*F).Fuzz function for each seed corpus without using the
|
||||||
// engine to generate or mutate inputs.
|
// fuzzing engine to generate or mutate inputs.
|
||||||
func runFuzzTargets(deps testDeps, fuzzTargets []InternalFuzzTarget, deadline time.Time) (ran, ok bool) {
|
func runFuzzTests(deps testDeps, fuzzTests []InternalFuzzTarget, deadline time.Time) (ran, ok bool) {
|
||||||
ok = true
|
ok = true
|
||||||
if len(fuzzTargets) == 0 || *isFuzzWorker {
|
if len(fuzzTests) == 0 || *isFuzzWorker {
|
||||||
return ran, ok
|
return ran, ok
|
||||||
}
|
}
|
||||||
m := newMatcher(deps.MatchString, *match, "-test.run")
|
m := newMatcher(deps.MatchString, *match, "-test.run")
|
||||||
@ -476,7 +480,7 @@ func runFuzzTargets(deps testDeps, fuzzTargets []InternalFuzzTarget, deadline ti
|
|||||||
if Verbose() {
|
if Verbose() {
|
||||||
root.chatty = newChattyPrinter(root.w)
|
root.chatty = newChattyPrinter(root.w)
|
||||||
}
|
}
|
||||||
for _, ft := range fuzzTargets {
|
for _, ft := range fuzzTests {
|
||||||
if shouldFailFast() {
|
if shouldFailFast() {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -486,7 +490,7 @@ func runFuzzTargets(deps testDeps, fuzzTargets []InternalFuzzTarget, deadline ti
|
|||||||
}
|
}
|
||||||
if mFuzz != nil {
|
if mFuzz != nil {
|
||||||
if _, fuzzMatched, _ := mFuzz.fullName(nil, ft.Name); fuzzMatched {
|
if _, fuzzMatched, _ := mFuzz.fullName(nil, ft.Name); fuzzMatched {
|
||||||
// If this target will be fuzzed, then don't run the seed corpus
|
// If this will be fuzzed, then don't run the seed corpus
|
||||||
// right now. That will happen later.
|
// right now. That will happen later.
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -515,17 +519,14 @@ func runFuzzTargets(deps testDeps, fuzzTargets []InternalFuzzTarget, deadline ti
|
|||||||
return root.ran, !root.Failed()
|
return root.ran, !root.Failed()
|
||||||
}
|
}
|
||||||
|
|
||||||
// runFuzzing runs the fuzz target matching the pattern for -fuzz. Only one such
|
// runFuzzing runs the fuzz test matching the pattern for -fuzz. Only one such
|
||||||
// fuzz target must match. This will run the fuzzing engine to generate and
|
// fuzz test must match. This will run the fuzzing engine to generate and
|
||||||
// mutate new inputs against the f.Fuzz function.
|
// mutate new inputs against the fuzz target.
|
||||||
//
|
//
|
||||||
// If fuzzing is disabled (-test.fuzz is not set), runFuzzing
|
// If fuzzing is disabled (-test.fuzz is not set), runFuzzing
|
||||||
// returns immediately.
|
// returns immediately.
|
||||||
func runFuzzing(deps testDeps, fuzzTargets []InternalFuzzTarget) (ok bool) {
|
func runFuzzing(deps testDeps, fuzzTests []InternalFuzzTarget) (ok bool) {
|
||||||
// TODO(katiehockman,jayconrod): Should we do something special to make sure
|
if len(fuzzTests) == 0 || *matchFuzz == "" {
|
||||||
// we don't print f.Log statements again with runFuzzing, since we already
|
|
||||||
// would have printed them when we ran runFuzzTargets (ie. seed corpus run)?
|
|
||||||
if len(fuzzTargets) == 0 || *matchFuzz == "" {
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
m := newMatcher(deps.MatchString, *matchFuzz, "-test.fuzz")
|
m := newMatcher(deps.MatchString, *matchFuzz, "-test.fuzz")
|
||||||
@ -544,24 +545,24 @@ func runFuzzing(deps testDeps, fuzzTargets []InternalFuzzTarget) (ok bool) {
|
|||||||
if Verbose() && !*isFuzzWorker {
|
if Verbose() && !*isFuzzWorker {
|
||||||
root.chatty = newChattyPrinter(root.w)
|
root.chatty = newChattyPrinter(root.w)
|
||||||
}
|
}
|
||||||
var target *InternalFuzzTarget
|
var fuzzTest *InternalFuzzTarget
|
||||||
var targetName string
|
var testName string
|
||||||
var matched []string
|
var matched []string
|
||||||
for i := range fuzzTargets {
|
for i := range fuzzTests {
|
||||||
name, ok, _ := tctx.match.fullName(nil, fuzzTargets[i].Name)
|
name, ok, _ := tctx.match.fullName(nil, fuzzTests[i].Name)
|
||||||
if !ok {
|
if !ok {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
matched = append(matched, name)
|
matched = append(matched, name)
|
||||||
target = &fuzzTargets[i]
|
fuzzTest = &fuzzTests[i]
|
||||||
targetName = name
|
testName = name
|
||||||
}
|
}
|
||||||
if len(matched) == 0 {
|
if len(matched) == 0 {
|
||||||
fmt.Fprintln(os.Stderr, "testing: warning: no targets to fuzz")
|
fmt.Fprintln(os.Stderr, "testing: warning: no fuzz tests to fuzz")
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
if len(matched) > 1 {
|
if len(matched) > 1 {
|
||||||
fmt.Fprintf(os.Stderr, "testing: will not fuzz, -fuzz matches more than one target: %v\n", matched)
|
fmt.Fprintf(os.Stderr, "testing: will not fuzz, -fuzz matches more than one fuzz test: %v\n", matched)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -569,7 +570,7 @@ func runFuzzing(deps testDeps, fuzzTargets []InternalFuzzTarget) (ok bool) {
|
|||||||
common: common{
|
common: common{
|
||||||
signal: make(chan bool),
|
signal: make(chan bool),
|
||||||
barrier: nil, // T.Parallel has no effect when fuzzing.
|
barrier: nil, // T.Parallel has no effect when fuzzing.
|
||||||
name: targetName,
|
name: testName,
|
||||||
parent: &root,
|
parent: &root,
|
||||||
level: root.level + 1,
|
level: root.level + 1,
|
||||||
chatty: root.chatty,
|
chatty: root.chatty,
|
||||||
@ -582,31 +583,32 @@ func runFuzzing(deps testDeps, fuzzTargets []InternalFuzzTarget) (ok bool) {
|
|||||||
// TODO(#48132): adjust this to work with test2json.
|
// TODO(#48132): adjust this to work with test2json.
|
||||||
f.chatty.Updatef(f.name, "=== FUZZ %s\n", f.name)
|
f.chatty.Updatef(f.name, "=== FUZZ %s\n", f.name)
|
||||||
}
|
}
|
||||||
go fRunner(f, target.Fn)
|
go fRunner(f, fuzzTest.Fn)
|
||||||
<-f.signal
|
<-f.signal
|
||||||
return !f.failed
|
return !f.failed
|
||||||
}
|
}
|
||||||
|
|
||||||
// fRunner wraps a call to a fuzz target and ensures that cleanup functions are
|
// fRunner wraps a call to a fuzz test and ensures that cleanup functions are
|
||||||
// called and status flags are set. fRunner should be called in its own
|
// called and status flags are set. fRunner should be called in its own
|
||||||
// goroutine. To wait for its completion, receive from f.signal.
|
// goroutine. To wait for its completion, receive from f.signal.
|
||||||
//
|
//
|
||||||
// fRunner is analogous to tRunner, which wraps subtests started with T.Run.
|
// fRunner is analogous to tRunner, which wraps subtests started with T.Run.
|
||||||
// Tests and fuzz targets work a little differently, so for now, these functions
|
// Unit tests and fuzz tests work a little differently, so for now, these
|
||||||
// aren't consolidated. In particular, because there are no F.Run and F.Parallel
|
// functions aren't consolidated. In particular, because there are no F.Run and
|
||||||
// methods, i.e., no fuzz sub-targets or parallel fuzz targets, a few
|
// F.Parallel methods, i.e., no fuzz sub-tests or parallel fuzz tests, a few
|
||||||
// simplifications are made. We also require that F.Fuzz, F.Skip, or F.Fail is
|
// simplifications are made. We also require that F.Fuzz, F.Skip, or F.Fail is
|
||||||
// called.
|
// called.
|
||||||
func fRunner(f *F, fn func(*F)) {
|
func fRunner(f *F, fn func(*F)) {
|
||||||
// When this goroutine is done, either because runtime.Goexit was called,
|
// When this goroutine is done, either because runtime.Goexit was called, a
|
||||||
// a panic started, or fn returned normally, record the duration and send
|
// panic started, or fn returned normally, record the duration and send
|
||||||
// t.signal, indicating the fuzz target is done.
|
// t.signal, indicating the fuzz test is done.
|
||||||
defer func() {
|
defer func() {
|
||||||
// Detect whether the fuzz target panicked or called runtime.Goexit without
|
// Detect whether the fuzz test panicked or called runtime.Goexit
|
||||||
// calling F.Fuzz, F.Fail, or F.Skip. If it did, panic (possibly replacing a
|
// without calling F.Fuzz, F.Fail, or F.Skip. If it did, panic (possibly
|
||||||
// nil panic value). Nothing should recover after fRunner unwinds, so this
|
// replacing a nil panic value). Nothing should recover after fRunner
|
||||||
// should crash the process and print stack. Unfortunately, recovering here
|
// unwinds, so this should crash the process and print stack.
|
||||||
// adds stack frames, but the location of the original panic should still be
|
// Unfortunately, recovering here adds stack frames, but the location of
|
||||||
|
// the original panic should still be
|
||||||
// clear.
|
// clear.
|
||||||
if f.Failed() {
|
if f.Failed() {
|
||||||
atomic.AddUint32(&numFailed, 1)
|
atomic.AddUint32(&numFailed, 1)
|
||||||
@ -662,7 +664,7 @@ func fRunner(f *F, fn func(*F)) {
|
|||||||
|
|
||||||
if len(f.sub) > 0 {
|
if len(f.sub) > 0 {
|
||||||
// Unblock inputs that called T.Parallel while running the seed corpus.
|
// Unblock inputs that called T.Parallel while running the seed corpus.
|
||||||
// This only affects fuzz targets run as normal tests.
|
// This only affects fuzz tests run as normal tests.
|
||||||
// While fuzzing, T.Parallel has no effect, so f.sub is empty, and this
|
// While fuzzing, T.Parallel has no effect, so f.sub is empty, and this
|
||||||
// branch is not taken. f.barrier is nil in that case.
|
// branch is not taken. f.barrier is nil in that case.
|
||||||
close(f.barrier)
|
close(f.barrier)
|
||||||
|
@ -146,11 +146,9 @@
|
|||||||
// a function is called with randomly generated inputs to find bugs not
|
// a function is called with randomly generated inputs to find bugs not
|
||||||
// anticipated by unit tests.
|
// anticipated by unit tests.
|
||||||
//
|
//
|
||||||
// A fuzz target is a function that declares a set of "seed" inputs by calling
|
// Functions of the form
|
||||||
// F.Add, then provides a fuzz function by calling F.Fuzz. A fuzz target has
|
|
||||||
// the form:
|
|
||||||
//
|
|
||||||
// func FuzzXxx(*testing.F)
|
// func FuzzXxx(*testing.F)
|
||||||
|
// are considered fuzz tests.
|
||||||
//
|
//
|
||||||
// For example:
|
// For example:
|
||||||
//
|
//
|
||||||
@ -170,35 +168,38 @@
|
|||||||
// })
|
// })
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// Seed inputs may be registered by calling F.Add or by storing files in the
|
// A fuzz test maintains a seed corpus, or a set of inputs which are run by
|
||||||
// directory testdata/fuzz/<Name> (where <Name> is the name of the fuzz target)
|
// default, and can seed input generation. Seed inputs may be registered by
|
||||||
// within the package containing the fuzz target. Seed inputs are optional, but
|
// calling (*F).Add or by storing files in the directory testdata/fuzz/<Name>
|
||||||
// the fuzzing engine may find bugs more efficiently when provided with a set
|
// (where <Name> is the name of the fuzz test) within the package containing
|
||||||
// of small seed inputs with good code coverage.
|
// the fuzz test. Seed inputs are optional, but the fuzzing engine may find
|
||||||
|
// bugs more efficiently when provided with a set of small seed inputs with good
|
||||||
|
// code coverage. These seed inputs can also serve as regression tests for bugs
|
||||||
|
// identified through fuzzing.
|
||||||
//
|
//
|
||||||
// The fuzz function provided to F.Fuzz must accept a *testing.T parameter,
|
// The function passed to (*F).Fuzz within the fuzz test is considered the fuzz
|
||||||
// followed by one or more parameters for random inputs. The types of arguments
|
// target. A fuzz target must accept a *T parameter, followed by one or more
|
||||||
// passed to F.Add must be identical to the types of these parameters. The fuzz
|
// parameters for random inputs. The types of arguments passed to (*F).Add must
|
||||||
// function may signal that it's found a problem the same way tests do: by
|
// be identical to the types of these parameters. The fuzz target may signal
|
||||||
// calling T.Fail (or any method that calls it like T.Error or T.Fatal) or by
|
// that it's found a problem the same way tests do: by calling T.Fail (or any
|
||||||
// panicking.
|
// method that calls it like T.Error or T.Fatal) or by panicking.
|
||||||
//
|
//
|
||||||
// When fuzzing is enabled (by setting the -fuzz flag to a regular expression
|
// When fuzzing is enabled (by setting the -fuzz flag to a regular expression
|
||||||
// that matches a specific fuzz target), the fuzz function is called with
|
// that matches a specific fuzz test), the fuzz target is called with arguments
|
||||||
// arguments generated by repeatedly making random changes to the seed inputs.
|
// generated by repeatedly making random changes to the seed inputs. On
|
||||||
// On supported platforms, 'go test' compiles the test executable with fuzzing
|
// supported platforms, 'go test' compiles the test executable with fuzzing
|
||||||
// coverage instrumentation. The fuzzing engine uses that instrumentation to
|
// coverage instrumentation. The fuzzing engine uses that instrumentation to
|
||||||
// find and cache inputs that expand coverage, increasing the liklihood of
|
// find and cache inputs that expand coverage, increasing the likelihood of
|
||||||
// finding bugs. If the fuzz function finds a problem, the fuzzing engine writes
|
// finding bugs. If the fuzz target fails for a given input, the fuzzing engine
|
||||||
// the inputs that caused the problem to a file in the directory
|
// writes the inputs that caused the failure to a file in the directory
|
||||||
// testdata/fuzz/<Name> within the package directory. This file later serves as
|
// testdata/fuzz/<Name> within the package directory. This file later serves as
|
||||||
// a seed input. If the file can't be written at that location (for example,
|
// a seed input. If the file can't be written at that location (for example,
|
||||||
// because the directory is read-only), the fuzzing engine writes the file to
|
// because the directory is read-only), the fuzzing engine writes the file to
|
||||||
// the fuzz cache directory within the build cache instead.
|
// the fuzz cache directory within the build cache instead.
|
||||||
//
|
//
|
||||||
// When fuzzing is disabled, the fuzz function is called with the seed inputs
|
// When fuzzing is disabled, the fuzz target is called with the seed inputs
|
||||||
// registered with F.Add and seed inputs from testdata/fuzz/<Name>. In this
|
// registered with F.Add and seed inputs from testdata/fuzz/<Name>. In this
|
||||||
// mode, the fuzz target acts much like a regular test, with subtests started
|
// mode, the fuzz test acts much like a regular test, with subtests started
|
||||||
// with F.Fuzz instead of T.Run.
|
// with F.Fuzz instead of T.Run.
|
||||||
//
|
//
|
||||||
// TODO(#48255): write and link to documentation that will be helpful to users
|
// TODO(#48255): write and link to documentation that will be helpful to users
|
||||||
@ -217,7 +218,7 @@
|
|||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// The Skip method of *T can be used in a fuzz target if the input is invalid,
|
// The Skip method of *T can be used in a fuzz target if the input is invalid,
|
||||||
// but should not be considered a crash. For example:
|
// but should not be considered a failing input. For example:
|
||||||
//
|
//
|
||||||
// func FuzzJSONMarshalling(f *testing.F) {
|
// func FuzzJSONMarshalling(f *testing.F) {
|
||||||
// f.Fuzz(func(t *testing.T, b []byte) {
|
// f.Fuzz(func(t *testing.T, b []byte) {
|
||||||
@ -500,7 +501,7 @@ type common struct {
|
|||||||
cleanupName string // Name of the cleanup function.
|
cleanupName string // Name of the cleanup function.
|
||||||
cleanupPc []uintptr // The stack trace at the point where Cleanup was called.
|
cleanupPc []uintptr // The stack trace at the point where Cleanup was called.
|
||||||
finished bool // Test function has completed.
|
finished bool // Test function has completed.
|
||||||
inFuzzFn bool // Whether the fuzz function, if this is one, is running.
|
inFuzzFn bool // Whether the fuzz target, if this is one, is running.
|
||||||
|
|
||||||
chatty *chattyPrinter // A copy of chattyPrinter, if the chatty flag is set.
|
chatty *chattyPrinter // A copy of chattyPrinter, if the chatty flag is set.
|
||||||
bench bool // Whether the current test is a benchmark.
|
bench bool // Whether the current test is a benchmark.
|
||||||
@ -558,7 +559,7 @@ func Verbose() bool {
|
|||||||
|
|
||||||
func (c *common) checkFuzzFn(name string) {
|
func (c *common) checkFuzzFn(name string) {
|
||||||
if c.inFuzzFn {
|
if c.inFuzzFn {
|
||||||
panic(fmt.Sprintf("testing: f.%s was called inside the f.Fuzz function, use t.%s instead", name, name))
|
panic(fmt.Sprintf("testing: f.%s was called inside the fuzz target, use t.%s instead", name, name))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1687,7 +1688,7 @@ func (m *M) Run() (code int) {
|
|||||||
deadline := m.startAlarm()
|
deadline := m.startAlarm()
|
||||||
haveExamples = len(m.examples) > 0
|
haveExamples = len(m.examples) > 0
|
||||||
testRan, testOk := runTests(m.deps.MatchString, m.tests, deadline)
|
testRan, testOk := runTests(m.deps.MatchString, m.tests, deadline)
|
||||||
fuzzTargetsRan, fuzzTargetsOk := runFuzzTargets(m.deps, m.fuzzTargets, deadline)
|
fuzzTargetsRan, fuzzTargetsOk := runFuzzTests(m.deps, m.fuzzTargets, deadline)
|
||||||
exampleRan, exampleOk := runExamples(m.deps.MatchString, m.examples)
|
exampleRan, exampleOk := runExamples(m.deps.MatchString, m.examples)
|
||||||
m.stopAlarm()
|
m.stopAlarm()
|
||||||
if !testRan && !exampleRan && !fuzzTargetsRan && *matchBenchmarks == "" && *matchFuzz == "" {
|
if !testRan && !exampleRan && !fuzzTargetsRan && *matchBenchmarks == "" && *matchFuzz == "" {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user