// Copyright 2016 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 testdeps provides access to dependencies needed by test execution. // // This package is imported by the generated main package, which passes // TestDeps into testing.Main. This allows tests to use packages at run time // without making those packages direct dependencies of package testing. // Direct dependencies of package testing are harder to write tests for.
package testdeps import ( ) // Cover indicates whether coverage is enabled. var Cover bool // TestDeps is an implementation of the testing.testDeps interface, // suitable for passing to [testing.MainStart]. type TestDeps struct{} var matchPat string var matchRe *regexp.Regexp func (TestDeps) (, string) ( bool, error) { if matchRe == nil || matchPat != { matchPat = matchRe, = regexp.Compile(matchPat) if != nil { return } } return matchRe.MatchString(), nil } func (TestDeps) ( io.Writer) error { return pprof.StartCPUProfile() } func (TestDeps) () { pprof.StopCPUProfile() } func (TestDeps) ( string, io.Writer, int) error { return pprof.Lookup().WriteTo(, ) } // ImportPath is the import path of the testing binary, set by the generated main function. var ImportPath string func (TestDeps) () string { return ImportPath } // testLog implements testlog.Interface, logging actions by package os. type testLog struct { mu sync.Mutex w *bufio.Writer set bool } func ( *testLog) ( string) { .add("getenv", ) } func ( *testLog) ( string) { .add("open", ) } func ( *testLog) ( string) { .add("stat", ) } func ( *testLog) ( string) { .add("chdir", ) } // add adds the (op, name) pair to the test log. func ( *testLog) (, string) { if strings.Contains(, "\n") || == "" { return } .mu.Lock() defer .mu.Unlock() if .w == nil { return } .w.WriteString() .w.WriteByte(' ') .w.WriteString() .w.WriteByte('\n') } var log testLog func (TestDeps) ( io.Writer) { log.mu.Lock() log.w = bufio.NewWriter() if !log.set { // Tests that define TestMain and then run m.Run multiple times // will call StartTestLog/StopTestLog multiple times. // Checking log.set avoids calling testlog.SetLogger multiple times // (which will panic) and also avoids writing the header multiple times. log.set = true testlog.SetLogger(&log) log.w.WriteString("# test log\n") // known to cmd/go/internal/test/test.go } log.mu.Unlock() } func (TestDeps) () error { log.mu.Lock() defer log.mu.Unlock() := log.w.Flush() log.w = nil return } // SetPanicOnExit0 tells the os package whether to panic on os.Exit(0). func (TestDeps) ( bool) { testlog.SetPanicOnExit0() } func (TestDeps) ( time.Duration, int64, time.Duration, int64, int, []fuzz.CorpusEntry, []reflect.Type, , string) ( error) { // Fuzzing may be interrupted with a timeout or if the user presses ^C. // In either case, we'll stop worker processes gracefully and save // crashers and interesting values. , := signal.NotifyContext(context.Background(), os.Interrupt) defer () = fuzz.CoordinateFuzzing(, fuzz.CoordinateFuzzingOpts{ Log: os.Stderr, Timeout: , Limit: , MinimizeTimeout: , MinimizeLimit: , Parallel: , Seed: , Types: , CorpusDir: , CacheDir: , }) if == .Err() { return nil } return } func (TestDeps) ( func(fuzz.CorpusEntry) error) error { // Worker processes may or may not receive a signal when the user presses ^C // On POSIX operating systems, a signal sent to a process group is delivered // to all processes in that group. This is not the case on Windows. // If the worker is interrupted, return quickly and without error. // If only the coordinator process is interrupted, it tells each worker // process to stop by closing its "fuzz_in" pipe. , := signal.NotifyContext(context.Background(), os.Interrupt) defer () := fuzz.RunFuzzWorker(, ) if == .Err() { return nil } return } func (TestDeps) ( string, []reflect.Type) ([]fuzz.CorpusEntry, error) { return fuzz.ReadCorpus(, ) } func (TestDeps) ( []any, []reflect.Type) error { return fuzz.CheckCorpus(, ) } func (TestDeps) () { fuzz.ResetCoverage() } func (TestDeps) () { fuzz.SnapshotCoverage() } var CoverMode string var Covered string var CoverSelectedPackages []string // These variables below are set at runtime (via code in testmain) to point // to the equivalent functions in package internal/coverage/cfile; doing // things this way allows us to have tests import internal/coverage/cfile // only when -cover is in effect (as opposed to importing for all tests). var ( CoverSnapshotFunc func() float64 CoverProcessTestDirFunc func(dir string, cfile string, cm string, cpkg string, w io.Writer, selpkgs []string) error CoverMarkProfileEmittedFunc func(val bool) ) func (TestDeps) () ( string, func(string, string) (string, error), func() float64) { if CoverMode == "" { return } return CoverMode, coverTearDown, CoverSnapshotFunc } func coverTearDown( string, string) (string, error) { var error if == "" { , = os.MkdirTemp("", "gocoverdir") if != nil { return "error setting GOCOVERDIR: bad os.MkdirTemp return", } defer os.RemoveAll() } CoverMarkProfileEmittedFunc(true) := CoverMode if := CoverProcessTestDirFunc(, , , Covered, os.Stdout, CoverSelectedPackages); != nil { return "error generating coverage report", } return "", nil }