// Copyright 2020 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.

package testing

import (
	
	
	
	
	
	
	
	
	
	
)

func initFuzzFlags() {
	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(&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 (for use only by cmd/go)")
	isFuzzWorker = flag.Bool("test.fuzzworker", false, "coordinate with the parent process to fuzz random values (for use only by cmd/go)")
}

var (
	matchFuzz        *string
	fuzzDuration     durationOrCountFlag
	minimizeDuration = durationOrCountFlag{d: 60 * time.Second, allowZero: true}
	fuzzCacheDir     *string
	isFuzzWorker     *bool

	// corpusDir is the parent directory of the fuzz test's seed corpus within
	// the package.
	corpusDir = "testdata/fuzz"
)

// fuzzWorkerExitCode is used as an exit code by fuzz worker processes after an
// internal error. This distinguishes internal errors from uncontrolled panics
// and other failures. Keep in sync with internal/fuzz.workerExitCode.
const fuzzWorkerExitCode = 70

// InternalFuzzTarget is an internal type but exported because it is
// cross-package; it is part of the implementation of the "go test" command.
type InternalFuzzTarget struct {
	Name string
	Fn   func(f *F)
}

// F is a type passed to fuzz tests.
//
// Fuzz tests run generated inputs against a provided fuzz target, which can
// find and report potential bugs in the code being tested.
//
// A fuzz test runs the seed corpus by default, which includes entries provided
// by (*F).Add and entries in the testdata/fuzz/<FuzzTestName> directory. After
// 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 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 {
	common
	fuzzContext *fuzzContext
	testContext *testContext

	// inFuzzFn is true when the fuzz function is running. Most F methods cannot
	// be called when inFuzzFn is true.
	inFuzzFn bool

	// corpus is a set of seed corpus entries, added with F.Add and loaded
	// from testdata.
	corpus []corpusEntry

	result     fuzzResult
	fuzzCalled bool
}

var _ TB = (*F)(nil)

// corpusEntry is an alias to the same type as internal/fuzz.CorpusEntry.
// We use a type alias because we don't want to export this type, and we can't
// import internal/fuzz from testing.
type corpusEntry = struct {
	Parent     string
	Path       string
	Data       []byte
	Values     []any
	Generation int
	IsSeed     bool
}

// Helper marks the calling function as a test helper function.
// When printing file and line information, that function will be skipped.
// Helper may be called simultaneously from multiple goroutines.
func ( *F) () {
	if .inFuzzFn {
		panic("testing: f.Helper was called inside the fuzz target, use t.Helper instead")
	}

	// common.Helper is inlined here.
	// If we called it, it would mark F.Helper as the helper
	// instead of the caller.
	.mu.Lock()
	defer .mu.Unlock()
	if .helperPCs == nil {
		.helperPCs = make(map[uintptr]struct{})
	}
	// repeating code from callerName here to save walking a stack frame
	var  [1]uintptr
	 := runtime.Callers(2, [:]) // skip runtime.Callers + Helper
	if  == 0 {
		panic("testing: zero callers found")
	}
	if ,  := .helperPCs[[0]]; ! {
		.helperPCs[[0]] = struct{}{}
		.helperNames = nil // map will be recreated next time it is needed
	}
}

// Fail marks the function as having failed but continues execution.
func ( *F) () {
	// (*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.
	if .inFuzzFn {
		panic("testing: f.Fail was called inside the fuzz target, use t.Fail instead")
	}
	.common.Helper()
	.common.Fail()
}

// Skipped reports whether the test was skipped.
func ( *F) () bool {
	// (*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.
	if .inFuzzFn {
		panic("testing: f.Skipped was called inside the fuzz target, use t.Skipped instead")
	}
	.common.Helper()
	return .common.Skipped()
}

// Add will add the arguments to the seed corpus for the fuzz test. This will be
// a no-op if called after or within the fuzz target, and args must match the
// arguments for the fuzz target.
func ( *F) ( ...any) {
	var  []any
	for  := range  {
		if  := reflect.TypeOf([]); !supportedTypes[] {
			panic(fmt.Sprintf("testing: unsupported type to Add %v", ))
		}
		 = append(, [])
	}
	.corpus = append(.corpus, corpusEntry{Values: , IsSeed: true, Path: fmt.Sprintf("seed#%d", len(.corpus))})
}

// supportedTypes represents all of the supported types which can be fuzzed.
var supportedTypes = map[reflect.Type]bool{
	reflect.TypeOf(([]byte)("")):  true,
	reflect.TypeOf((string)("")):  true,
	reflect.TypeOf((bool)(false)): true,
	reflect.TypeOf((byte)(0)):     true,
	reflect.TypeOf((rune)(0)):     true,
	reflect.TypeOf((float32)(0)):  true,
	reflect.TypeOf((float64)(0)):  true,
	reflect.TypeOf((int)(0)):      true,
	reflect.TypeOf((int8)(0)):     true,
	reflect.TypeOf((int16)(0)):    true,
	reflect.TypeOf((int32)(0)):    true,
	reflect.TypeOf((int64)(0)):    true,
	reflect.TypeOf((uint)(0)):     true,
	reflect.TypeOf((uint8)(0)):    true,
	reflect.TypeOf((uint16)(0)):   true,
	reflect.TypeOf((uint32)(0)):   true,
	reflect.TypeOf((uint64)(0)):   true,
}

// Fuzz runs the fuzz function, ff, for fuzz testing. If ff fails for a set of
// arguments, those arguments will be added to the seed corpus.
//
// ff must be a function with no return value whose first argument is *T and
// whose remaining arguments are the types to be fuzzed.
// For example:
//
//	f.Fuzz(func(t *testing.T, b []byte, i int) { ... })
//
// The following types are allowed: []byte, string, bool, byte, rune, float32,
// float64, int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64.
// More types may be supported in the future.
//
// ff must not call any *F methods, e.g. (*F).Log, (*F).Error, (*F).Skip. Use
// the corresponding *T method instead. The only *F methods that are allowed in
// the (*F).Fuzz function are (*F).Failed and (*F).Name.
//
// This function should be fast and deterministic, and its behavior should not
// depend on shared state. No mutatable input arguments, or pointers to them,
// should be retained between executions of the fuzz function, as the memory
// backing them may be mutated during a subsequent invocation. ff must not
// modify the underlying data of the arguments provided by the fuzzing engine.
//
// When fuzzing, F.Fuzz does not return until a problem is found, time runs out
// (set with -fuzztime), or the test process is interrupted by a signal. F.Fuzz
// should be called exactly once, unless F.Skip or [F.Fail] is called beforehand.
func ( *F) ( any) {
	if .fuzzCalled {
		panic("testing: F.Fuzz called more than once")
	}
	.fuzzCalled = true
	if .failed {
		return
	}
	.Helper()

	// ff should be in the form func(*testing.T, ...interface{})
	 := reflect.ValueOf()
	 := .Type()
	if .Kind() != reflect.Func {
		panic("testing: F.Fuzz must receive a function")
	}
	if .NumIn() < 2 || .In(0) != reflect.TypeOf((*T)(nil)) {
		panic("testing: fuzz target must receive at least two arguments, where the first argument is a *T")
	}
	if .NumOut() != 0 {
		panic("testing: fuzz target must not return a value")
	}

	// Save the types of the function to compare against the corpus.
	var  []reflect.Type
	for  := 1;  < .NumIn(); ++ {
		 := .In()
		if !supportedTypes[] {
			panic(fmt.Sprintf("testing: unsupported type for fuzzing %v", ))
		}
		 = append(, )
	}

	// Load the testdata seed corpus. Check types of entries in the testdata
	// corpus and entries declared with F.Add.
	//
	// Don't load the seed corpus if this is a worker process; we won't use it.
	if .fuzzContext.mode != fuzzWorker {
		for ,  := range .corpus {
			if  := .fuzzContext.deps.CheckCorpus(.Values, );  != nil {
				// TODO(#48302): Report the source location of the F.Add call.
				.Fatal()
			}
		}

		// Load seed corpus
		,  := .fuzzContext.deps.ReadCorpus(filepath.Join(corpusDir, .name), )
		if  != nil {
			.Fatal()
		}
		for  := range  {
			[].IsSeed = true // these are all seed corpus values
			if .fuzzContext.mode == fuzzCoordinator {
				// If this is the coordinator process, zero the values, since we don't need
				// to hold onto them.
				[].Values = nil
			}
		}

		.corpus = append(.corpus, ...)
	}

	// 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.
	 := func( io.Writer,  corpusEntry) ( bool) {
		if .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", .Path))
		}
		if shouldFailFast() {
			return true
		}
		 := .name
		if .Path != "" {
			 = fmt.Sprintf("%s/%s", , filepath.Base(.Path))
		}
		if .testContext.isFuzzing {
			// Don't preserve subtest names while fuzzing. If fn calls T.Run,
			// there will be a very large number of subtests with duplicate names,
			// which will use a large amount of memory. The subtest names aren't
			// useful since there's no way to re-run them deterministically.
			.testContext.match.clearSubNames()
		}

		// Record the stack trace at the point of this call so that if the subtest
		// function - which runs in a separate stack - is marked as a helper, we can
		// continue walking the stack into the parent test.
		var  [maxStackLen]uintptr
		 := runtime.Callers(2, [:])
		 := &T{
			common: common{
				barrier: make(chan bool),
				signal:  make(chan bool),
				name:    ,
				parent:  &.common,
				level:   .level + 1,
				creator: [:],
				chatty:  .chatty,
			},
			context: .testContext,
		}
		if  != nil {
			// t.parent aliases f.common.
			.parent.w = 
		}
		.w = indenter{&.common}
		if .chatty != nil {
			.chatty.Updatef(.name, "=== RUN   %s\n", .name)
		}
		.common.inFuzzFn, .inFuzzFn = true, true
		go tRunner(, func( *T) {
			 := []reflect.Value{reflect.ValueOf()}
			for ,  := range .Values {
				 = append(, reflect.ValueOf())
			}
			// Before resetting the current coverage, defer the snapshot so that
			// we make sure it is called right before the tRunner function
			// exits, regardless of whether it was executed cleanly, panicked,
			// or if the fuzzFn called t.Fatal.
			if .testContext.isFuzzing {
				defer .fuzzContext.deps.SnapshotCoverage()
				.fuzzContext.deps.ResetCoverage()
			}
			.Call()
		})
		<-.signal
		if .chatty != nil && .chatty.json {
			.chatty.Updatef(.parent.name, "=== NAME  %s\n", .parent.name)
		}
		.common.inFuzzFn, .inFuzzFn = false, false
		return !.Failed()
	}

	switch .fuzzContext.mode {
	case fuzzCoordinator:
		// Fuzzing is enabled, and this is the test process started by 'go test'.
		// Act as the coordinator process, and coordinate workers to perform the
		// actual fuzzing.
		 := filepath.Join(corpusDir, .name)
		 := filepath.Join(*fuzzCacheDir, .name)
		 := .fuzzContext.deps.CoordinateFuzzing(
			fuzzDuration.d,
			int64(fuzzDuration.n),
			minimizeDuration.d,
			int64(minimizeDuration.n),
			*parallel,
			.corpus,
			,
			,
			)
		if  != nil {
			.result = fuzzResult{Error: }
			.Fail()
			fmt.Fprintf(.w, "%v\n", )
			if ,  := .(fuzzCrashError);  {
				 := .CrashPath()
				fmt.Fprintf(.w, "Failing input written to %s\n", )
				 := filepath.Base()
				fmt.Fprintf(.w, "To re-run:\ngo test -run=%s/%s\n", .name, )
			}
		}
		// TODO(jayconrod,katiehockman): Aggregate statistics across workers
		// and add to FuzzResult (ie. time taken, num iterations)

	case fuzzWorker:
		// Fuzzing is enabled, and this is a worker process. Follow instructions
		// from the coordinator.
		if  := .fuzzContext.deps.RunFuzzWorker(func( 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  strings.Builder
			if  := (&, ); ! {
				return errors.New(.String())
			}
			return nil
		});  != 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 failing input should not be recorded.
			.Errorf("communicating with fuzzing coordinator: %v", )
		}

	default:
		// Fuzzing is not enabled, or will be done later. Only run the seed
		// corpus now.
		for ,  := range .corpus {
			 := fmt.Sprintf("%s/%s", .name, filepath.Base(.Path))
			if , ,  := .testContext.match.fullName(nil, );  {
				(.w, )
			}
		}
	}
}

func ( *F) () {
	if *isFuzzWorker || .parent == nil {
		return
	}
	 := fmtDuration(.duration)
	 := "--- %s: %s (%s)\n"
	if .Failed() {
		.flushToParent(.name, , "FAIL", .name, )
	} else if .chatty != nil {
		if .Skipped() {
			.flushToParent(.name, , "SKIP", .name, )
		} else {
			.flushToParent(.name, , "PASS", .name, )
		}
	}
}

// fuzzResult contains the results of a fuzz run.
type fuzzResult struct {
	N     int           // The number of iterations.
	T     time.Duration // The total time taken.
	Error error         // Error is the error from the failing input
}

func ( fuzzResult) () string {
	if .Error == nil {
		return ""
	}
	return .Error.Error()
}

// 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'.
// Errors within the fuzzing framework (like I/O errors between coordinator
// and worker processes) don't satisfy this interface.
type fuzzCrashError interface {
	error
	Unwrap() error

	// 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
	// -run=$test/$name $test is the fuzz test name, and $name is the
	// filepath.Base of the string returned here.
	CrashPath() string
}

// fuzzContext holds fields common to all fuzz tests.
type fuzzContext struct {
	deps testDeps
	mode fuzzMode
}

type fuzzMode uint8

const (
	seedCorpusOnly fuzzMode = iota
	fuzzCoordinator
	fuzzWorker
)

// 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 engine to generate or mutate inputs.
func runFuzzTests( testDeps,  []InternalFuzzTarget,  time.Time) (,  bool) {
	 = true
	if len() == 0 || *isFuzzWorker {
		return , 
	}
	 := newMatcher(.MatchString, *match, "-test.run", *skip)
	var  *matcher
	if *matchFuzz != "" {
		 = newMatcher(.MatchString, *matchFuzz, "-test.fuzz", *skip)
	}

	for ,  := range cpuList {
		runtime.GOMAXPROCS()
		for  := uint(0);  < *count; ++ {
			if shouldFailFast() {
				break
			}

			 := newTestContext(*parallel, )
			.deadline = 
			 := &fuzzContext{deps: , mode: seedCorpusOnly}
			 := common{w: os.Stdout} // gather output in one place
			if Verbose() {
				.chatty = newChattyPrinter(.w)
			}
			for ,  := range  {
				if shouldFailFast() {
					break
				}
				, ,  := .match.fullName(nil, .Name)
				if ! {
					continue
				}
				if  != nil {
					if , ,  := .fullName(nil, .Name);  {
						// If this will be fuzzed, then don't run the seed corpus
						// right now. That will happen later.
						continue
					}
				}
				 := &F{
					common: common{
						signal:  make(chan bool),
						barrier: make(chan bool),
						name:    ,
						parent:  &,
						level:   .level + 1,
						chatty:  .chatty,
					},
					testContext: ,
					fuzzContext: ,
				}
				.w = indenter{&.common}
				if .chatty != nil {
					.chatty.Updatef(.name, "=== RUN   %s\n", .name)
				}
				go fRunner(, .Fn)
				<-.signal
				if .chatty != nil && .chatty.json {
					.chatty.Updatef(.parent.name, "=== NAME  %s\n", .parent.name)
				}
				 =  && !.Failed()
				 =  || .ran
			}
			if ! {
				// There were no tests to run on this iteration.
				// This won't change, so no reason to keep trying.
				break
			}
		}
	}

	return , 
}

// runFuzzing runs the fuzz test matching the pattern for -fuzz. Only one such
// fuzz test must match. This will run the fuzzing engine to generate and
// mutate new inputs against the fuzz target.
//
// If fuzzing is disabled (-test.fuzz is not set), runFuzzing
// returns immediately.
func runFuzzing( testDeps,  []InternalFuzzTarget) ( bool) {
	if len() == 0 || *matchFuzz == "" {
		return true
	}
	 := newMatcher(.MatchString, *matchFuzz, "-test.fuzz", *skip)
	 := newTestContext(1, )
	.isFuzzing = true
	 := &fuzzContext{
		deps: ,
	}
	 := common{w: os.Stdout}
	if *isFuzzWorker {
		.w = io.Discard
		.mode = fuzzWorker
	} else {
		.mode = fuzzCoordinator
	}
	if Verbose() && !*isFuzzWorker {
		.chatty = newChattyPrinter(.w)
	}
	var  *InternalFuzzTarget
	var  string
	var  []string
	for  := range  {
		, ,  := .match.fullName(nil, [].Name)
		if ! {
			continue
		}
		 = append(, )
		 = &[]
		 = 
	}
	if len() == 0 {
		fmt.Fprintln(os.Stderr, "testing: warning: no fuzz tests to fuzz")
		return true
	}
	if len() > 1 {
		fmt.Fprintf(os.Stderr, "testing: will not fuzz, -fuzz matches more than one fuzz test: %v\n", )
		return false
	}

	 := &F{
		common: common{
			signal:  make(chan bool),
			barrier: nil, // T.Parallel has no effect when fuzzing.
			name:    ,
			parent:  &,
			level:   .level + 1,
			chatty:  .chatty,
		},
		fuzzContext: ,
		testContext: ,
	}
	.w = indenter{&.common}
	if .chatty != nil {
		.chatty.Updatef(.name, "=== RUN   %s\n", .name)
	}
	go fRunner(, .Fn)
	<-.signal
	if .chatty != nil {
		.chatty.Updatef(.parent.name, "=== NAME  %s\n", .parent.name)
	}
	return !.failed
}

// 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
// goroutine. To wait for its completion, receive from f.signal.
//
// fRunner is analogous to tRunner, which wraps subtests started with T.Run.
// Unit tests and fuzz tests work a little differently, so for now, these
// functions aren't consolidated. In particular, because there are no F.Run and
// 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
// called.
func fRunner( *F,  func(*F)) {
	// When this goroutine is done, either because runtime.Goexit was called, a
	// panic started, or fn returned normally, record the duration and send
	// t.signal, indicating the fuzz test is done.
	defer func() {
		// Detect whether the fuzz test panicked or called runtime.Goexit
		// without calling F.Fuzz, F.Fail, or F.Skip. If it did, panic (possibly
		// replacing a nil panic value). Nothing should recover after fRunner
		// unwinds, so this should crash the process and print stack.
		// Unfortunately, recovering here adds stack frames, but the location of
		// the original panic should still be
		// clear.
		.checkRaces()
		if .Failed() {
			numFailed.Add(1)
		}
		 := recover()
		if  == nil {
			.mu.RLock()
			 := !.fuzzCalled && !.skipped && !.failed
			if !.finished && !.skipped && !.failed {
				 = errNilPanicOrGoexit
			}
			.mu.RUnlock()
			if  &&  == nil {
				.Error("returned without calling F.Fuzz, F.Fail, or F.Skip")
			}
		}

		// Use a deferred call to ensure that we report that the test is
		// complete even if a cleanup function calls F.FailNow. See issue 41355.
		 := false
		defer func() {
			if ! {
				// Only report that the test is complete if it doesn't panic,
				// as otherwise the test binary can exit before the panic is
				// reported to the user. See issue 41479.
				.signal <- true
			}
		}()

		// If we recovered a panic or inappropriate runtime.Goexit, fail the test,
		// flush the output log up to the root, then panic.
		 := func( any) {
			.Fail()
			if  := .runCleanup(recoverAndReturnPanic);  != nil {
				.Logf("cleanup panicked with %v", )
			}
			for  := &.common; .parent != nil;  = .parent {
				.mu.Lock()
				.duration += time.Since(.start)
				 := .duration
				.mu.Unlock()
				.flushToParent(.name, "--- FAIL: %s (%s)\n", .name, fmtDuration())
			}
			 = true
			panic()
		}
		if  != nil {
			()
		}

		// No panic or inappropriate Goexit.
		.duration += time.Since(.start)

		if len(.sub) > 0 {
			// Unblock inputs that called T.Parallel while running the seed corpus.
			// This only affects fuzz tests run as normal tests.
			// 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.
			.testContext.release()
			close(.barrier)
			// Wait for the subtests to complete.
			for ,  := range .sub {
				<-.signal
			}
			 := time.Now()
			 := .runCleanup(recoverAndReturnPanic)
			.duration += time.Since()
			if  != nil {
				()
			}
		}

		// Report after all subtests have finished.
		.report()
		.done = true
		.setRan()
	}()
	defer func() {
		if len(.sub) == 0 {
			.runCleanup(normalPanic)
		}
	}()

	.start = time.Now()
	.resetRaces()
	()

	// Code beyond this point will not be executed when FailNow or SkipNow
	// is invoked.
	.mu.Lock()
	.finished = true
	.mu.Unlock()
}