Source File
testing.go
Belonging Package
testing
func () {
if initRan {
return
}
chatty = flag.Bool("test.v", false, "verbose: print additional output")
count = flag.Uint("test.count", 1, "run tests and benchmarks `n` times")
coverProfile = flag.String("test.coverprofile", "", "write a coverage profile to `file`")
matchList = flag.String("test.list", "", "list tests, examples, and benchmarks matching `regexp` then exit")
match = flag.String("test.run", "", "run only tests and examples matching `regexp`")
memProfile = flag.String("test.memprofile", "", "write an allocation profile to `file`")
memProfileRate = flag.Int("test.memprofilerate", 0, "set memory allocation profiling `rate` (see runtime.MemProfileRate)")
cpuProfile = flag.String("test.cpuprofile", "", "write a cpu profile to `file`")
blockProfile = flag.String("test.blockprofile", "", "write a goroutine blocking profile to `file`")
blockProfileRate = flag.Int("test.blockprofilerate", 1, "set blocking profile `rate` (see runtime.SetBlockProfileRate)")
mutexProfile = flag.String("test.mutexprofile", "", "write a mutex contention profile to the named file after execution")
mutexProfileFraction = flag.Int("test.mutexprofilefraction", 1, "if >= 0, calls runtime.SetMutexProfileFraction()")
panicOnExit0 = flag.Bool("test.paniconexit0", false, "panic on call to os.Exit(0)")
traceFile = flag.String("test.trace", "", "write an execution trace to `file`")
timeout = flag.Duration("test.timeout", 0, "panic test binary after duration `d` (default 0, timeout disabled)")
cpuListStr = flag.String("test.cpu", "", "comma-separated `list` of cpu counts to run each test with")
parallel = flag.Int("test.parallel", runtime.GOMAXPROCS(0), "run at most `n` tests in parallel")
testlog = flag.String("test.testlogfile", "", "write test action log to `file` (for use only by cmd/go)")
initBenchmarkFlags()
}
short *bool
failFast *bool
outputDir *string
chatty *bool
count *uint
coverProfile *string
matchList *string
match *string
memProfile *string
memProfileRate *int
cpuProfile *string
blockProfile *string
blockProfileRate *int
mutexProfile *string
mutexProfileFraction *int
panicOnExit0 *bool
traceFile *string
timeout *time.Duration
cpuListStr *string
parallel *int
testlog *string
haveExamples bool // are there examples?
cpuList []int
testlogFile *os.File
numFailed uint32 // number of test failures
)
type chattyPrinter struct {
w io.Writer
lastNameMu sync.Mutex // guards lastName
lastName string // last printed test name in chatty mode
}
func ( io.Writer) *chattyPrinter {
return &chattyPrinter{w: }
}
func ( *chattyPrinter) (, string, ...interface{}) {
.lastNameMu.Lock()
defer .lastNameMu.Unlock()
const maxStackLen = 50
type common struct {
mu sync.RWMutex // guards this group of fields
output []byte // Output generated by test or benchmark.
w io.Writer // For flushToParent.
ran bool // Test or benchmark (or one of its subtests) was executed.
failed bool // Test or benchmark has failed.
skipped bool // Test of benchmark has been skipped.
done bool // Test is finished and all subtests have completed.
helperPCs map[uintptr]struct{} // functions to be skipped when writing file/line info
helperNames map[string]struct{} // helperPCs converted to function names
cleanups []func() // optional functions to be called at the end of the test
cleanupName string // Name of the cleanup function.
cleanupPc []uintptr // The stack trace at the point where Cleanup was called.
chatty *chattyPrinter // A copy of chattyPrinter, if the chatty flag is set.
bench bool // Whether the current test is a benchmark.
finished bool // Test function has completed.
hasSub int32 // Written atomically.
raceErrors int // Number of races detected during test.
runner string // Function name of tRunner running the test.
parent *common
level int // Nesting depth of test or benchmark.
creator []uintptr // If level > 0, the stack trace at the point where the parent called t.Run.
name string // Name of test or benchmark.
start time.Time // Time test or benchmark started
duration time.Duration
barrier chan bool // To signal parallel subtests they may start.
signal chan bool // To signal a test is done.
sub []*T // Queue of subtests to be run in parallel.
tempDirMu sync.Mutex
tempDir string
tempDirErr error
tempDirSeq int32
}
:= runtime.Callers(+2, [:])
if == 0 {
panic("testing: zero callers found")
}
:= runtime.CallersFrames([:])
var , , runtime.Frame
for := true; ; = {
, = .Next()
if .Function == .cleanupName {
= runtime.CallersFrames(.cleanupPc)
continue
}
if .PC == 0 {
=
}
if .level > 1 {
= runtime.CallersFrames(.creator)
if .helperNames == nil {
.helperNames = make(map[string]struct{})
for := range .helperPCs {
.helperNames[pcToName()] = struct{}{}
}
}
return
}
}
return
}
.WriteString("\n ")
}
.WriteString()
}
.WriteByte('\n')
return .String()
}
type TB interface {
Cleanup(func())
Error(args ...interface{})
Errorf(format string, args ...interface{})
Fail()
FailNow()
Failed() bool
Fatal(args ...interface{})
Fatalf(format string, args ...interface{})
Helper()
Log(args ...interface{})
Logf(format string, args ...interface{})
Name() string
Skip(args ...interface{})
SkipNow()
Skipf(format string, args ...interface{})
Skipped() bool
TempDir() string
type T struct {
common
isParallel bool
context *testContext // For running tests and subtests.
}
func ( *common) () {}
func ( *common) ( func()) {
:= runtime.Callers(2, [:])
:= [:]
:= func() {
defer func() {
.mu.Lock()
defer .mu.Unlock()
.cleanupName = ""
.cleanupPc = nil
}()
:= callerName(0)
.mu.Lock()
.cleanupName =
.cleanupPc =
.mu.Unlock()
()
}
.mu.Lock()
defer .mu.Unlock()
.cleanups = append(.cleanups, )
}
var tempDirReplacer struct {
sync.Once
r *strings.Replacer
}
tempDirReplacer.Do(func() {
tempDirReplacer.r = strings.NewReplacer("/", "_", "\\", "_", ":", "_")
})
:= tempDirReplacer.r.Replace(.Name())
.tempDir, .tempDirErr = os.MkdirTemp("", )
if .tempDirErr == nil {
.Cleanup(func() {
if := os.RemoveAll(.tempDir); != nil {
.Errorf("TempDir RemoveAll cleanup: %v", )
}
})
}
}
.tempDirMu.Unlock()
if .tempDirErr != nil {
.Fatalf("TempDir: %v", .tempDirErr)
}
:= atomic.AddInt32(&.tempDirSeq, 1)
:= fmt.Sprintf("%s%c%03d", .tempDir, os.PathSeparator, )
if := os.Mkdir(, 0777); != nil {
.Fatalf("TempDir: %v", )
}
return
}
type panicHandling int
const (
normalPanic panicHandling = iota
recoverAndReturnPanic
)
func ( *common) ( panicHandling) ( interface{}) {
if == recoverAndReturnPanic {
defer func() {
= recover()
}()
}
func ( *T) () {
if .isParallel {
panic("testing: t.Parallel called multiple times")
}
.isParallel = true
type InternalTest struct {
Name string
F func(*T)
}
var errNilPanicOrGoexit = errors.New("test executed panic(nil) or runtime.Goexit")
func ( *T, func( *T)) {
.runner = callerName(0)
.signal <-
}()
:= func( interface{}) {
.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())
if := .parent.runCleanup(recoverAndReturnPanic); != nil {
fmt.Fprintf(.parent.w, "cleanup panicked with %v", )
}
}
= true
panic()
}
if != nil {
()
}
.duration += time.Since(.start)
for , := range .sub {
<-.signal
}
:= time.Now()
:= .runCleanup(recoverAndReturnPanic)
.duration += time.Since()
if != nil {
()
}
.context.waitParallel()
}
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: .context,
}
.w = indenter{&.common}
if .chatty != nil {
.chatty.Updatef(.name, "=== RUN %s\n", .name)
go tRunner(, )
startParallel chan bool
maxParallel int
}
func ( int, *matcher) *testContext {
return &testContext{
match: ,
startParallel: make(chan bool),
maxParallel: ,
running: 1, // Set the count to 1 for the main (sequential) test.
}
}
func ( *testContext) () {
.mu.Lock()
if .running < .maxParallel {
.running++
.mu.Unlock()
return
}
.numWaiting++
.mu.Unlock()
<-.startParallel
}
func ( *testContext) () {
.mu.Lock()
if .numWaiting == 0 {
.running--
.mu.Unlock()
return
}
.numWaiting--
.mu.Unlock()
.startParallel <- true // Pick a waiting test to be run.
}
var errMain = errors.New("testing: unexpected use of func Main")
type matchStringOnly func(pat, str string) (bool, error)
func ( matchStringOnly) (, string) (bool, error) { return (, ) }
func ( matchStringOnly) ( io.Writer) error { return errMain }
func ( matchStringOnly) () {}
func ( matchStringOnly) (string, io.Writer, int) error { return errMain }
func ( matchStringOnly) () string { return "" }
func ( matchStringOnly) (io.Writer) {}
func ( matchStringOnly) () error { return errMain }
func ( matchStringOnly) (bool) {}
func ( func(, string) (bool, error), []InternalTest, []InternalBenchmark, []InternalExample) {
os.Exit(MainStart(matchStringOnly(), , , ).Run())
}
type M struct {
deps testDeps
tests []InternalTest
benchmarks []InternalBenchmark
examples []InternalExample
timer *time.Timer
afterOnce sync.Once
numRun int
func ( testDeps, []InternalTest, []InternalBenchmark, []InternalExample) *M {
Init()
return &M{
deps: ,
tests: ,
benchmarks: ,
examples: ,
}
}
.numRun++
if !flag.Parsed() {
flag.Parse()
}
if *parallel < 1 {
fmt.Fprintln(os.Stderr, "testing: -parallel can only be given a positive integer")
flag.Usage()
.exitCode = 2
return
}
if len(*matchList) != 0 {
listTests(.deps.MatchString, .tests, .benchmarks, .examples)
.exitCode = 0
return
}
parseCpuList()
.before()
defer .after()
:= .startAlarm()
haveExamples = len(.examples) > 0
, := runTests(.deps.MatchString, .tests, )
, := runExamples(.deps.MatchString, .examples)
.stopAlarm()
if ! && ! && *matchBenchmarks == "" {
fmt.Fprintln(os.Stderr, "testing: warning: no tests to run")
}
if ! || ! || !runBenchmarks(.deps.ImportPath(), .deps.MatchString, .benchmarks) || race.Errors() > 0 {
fmt.Println("FAIL")
.exitCode = 1
return
}
fmt.Println("PASS")
.exitCode = 0
return
}
func ( *T) () {
if .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, )
}
}
}
func ( func(, string) (bool, error), []InternalTest, []InternalBenchmark, []InternalExample) {
if , := (*matchList, "non-empty"); != nil {
fmt.Fprintf(os.Stderr, "testing: invalid regexp in -test.list (%q): %s\n", *matchList, )
os.Exit(1)
}
for , := range {
if , := (*matchList, .Name); {
fmt.Println(.Name)
}
}
for , := range {
if , := (*matchList, .Name); {
fmt.Println(.Name)
}
}
for , := range {
if , := (*matchList, .Name); {
fmt.Println(.Name)
}
}
}
func ( func(, string) (bool, error), []InternalTest) ( bool) {
var time.Time
if *timeout > 0 {
= time.Now().Add(*timeout)
}
, := runTests(, , )
if ! && !haveExamples {
fmt.Fprintln(os.Stderr, "testing: warning: no tests to run")
}
return
}
func ( func(, string) (bool, error), []InternalTest, time.Time) (, bool) {
= true
for , := range cpuList {
runtime.GOMAXPROCS()
for := uint(0); < *count; ++ {
if shouldFailFast() {
break
}
:= newTestContext(*parallel, newMatcher(, *match, "-test.run"))
.deadline =
:= &T{
common: common{
signal: make(chan bool),
barrier: make(chan bool),
w: os.Stdout,
},
context: ,
}
if Verbose() {
.chatty = newChattyPrinter(.w)
}
tRunner(, func( *T) {
for , := range {
.Run(.Name, .F)
func ( *M) () {
if *memProfileRate > 0 {
runtime.MemProfileRate = *memProfileRate
}
if *cpuProfile != "" {
, := os.Create(toOutputDir(*cpuProfile))
if != nil {
fmt.Fprintf(os.Stderr, "testing: %s\n", )
return
}
if := .deps.StartCPUProfile(); != nil {
fmt.Fprintf(os.Stderr, "testing: can't start cpu profile: %s\n", )
.Close()
return
}
if *blockProfile != "" && *blockProfileRate >= 0 {
runtime.SetBlockProfileRate(*blockProfileRate)
}
if *mutexProfile != "" && *mutexProfileFraction >= 0 {
runtime.SetMutexProfileFraction(*mutexProfileFraction)
}
if *coverProfile != "" && cover.Mode == "" {
fmt.Fprintf(os.Stderr, "testing: cannot use -test.coverprofile because test binary was not built with coverage enabled\n")
os.Exit(2)
}
var *os.File
var error
if .numRun == 1 {
, = os.Create(*testlog)
} else {
, = os.OpenFile(*testlog, os.O_WRONLY, 0)
if == nil {
.Seek(0, io.SeekEnd)
}
}
if != nil {
fmt.Fprintf(os.Stderr, "testing: %s\n", )
os.Exit(2)
}
.deps.StartTestLog()
testlogFile =
}
if *panicOnExit0 {
.deps.SetPanicOnExit0(true)
}
}
func ( *M) () {
.afterOnce.Do(func() {
.writeProfiles()
})
if *panicOnExit0 {
.deps.SetPanicOnExit0(false)
}
}
func ( *M) () {
if *testlog != "" {
if := .deps.StopTestLog(); != nil {
fmt.Fprintf(os.Stderr, "testing: can't write %s: %s\n", *testlog, )
os.Exit(2)
}
if := testlogFile.Close(); != nil {
fmt.Fprintf(os.Stderr, "testing: can't write %s: %s\n", *testlog, )
os.Exit(2)
}
}
if *cpuProfile != "" {
.deps.StopCPUProfile() // flushes profile to disk
}
if *traceFile != "" {
trace.Stop() // flushes trace to disk
}
if *memProfile != "" {
, := os.Create(toOutputDir(*memProfile))
if != nil {
fmt.Fprintf(os.Stderr, "testing: %s\n", )
os.Exit(2)
}
runtime.GC() // materialize all statistics
if = .deps.WriteProfileTo("allocs", , 0); != nil {
fmt.Fprintf(os.Stderr, "testing: can't write %s: %s\n", *memProfile, )
os.Exit(2)
}
.Close()
}
if *blockProfile != "" && *blockProfileRate >= 0 {
, := os.Create(toOutputDir(*blockProfile))
if != nil {
fmt.Fprintf(os.Stderr, "testing: %s\n", )
os.Exit(2)
}
if = .deps.WriteProfileTo("block", , 0); != nil {
fmt.Fprintf(os.Stderr, "testing: can't write %s: %s\n", *blockProfile, )
os.Exit(2)
}
.Close()
}
if *mutexProfile != "" && *mutexProfileFraction >= 0 {
, := os.Create(toOutputDir(*mutexProfile))
if != nil {
fmt.Fprintf(os.Stderr, "testing: %s\n", )
os.Exit(2)
}
if = .deps.WriteProfileTo("mutex", , 0); != nil {
fmt.Fprintf(os.Stderr, "testing: can't write %s: %s\n", *mutexProfile, )
os.Exit(2)
}
.Close()
}
if cover.Mode != "" {
coverReport()
}
}
return
}
}
if os.IsPathSeparator([0]) {
return
}
return fmt.Sprintf("%s%c%s", *outputDir, os.PathSeparator, )
}
func ( *M) () {
if *timeout > 0 {
.timer.Stop()
}
}
func () {
for , := range strings.Split(*cpuListStr, ",") {
= strings.TrimSpace()
if == "" {
continue
}
, := strconv.Atoi()
if != nil || <= 0 {
fmt.Fprintf(os.Stderr, "testing: invalid value %q for -test.cpu\n", )
os.Exit(1)
}
cpuList = append(cpuList, )
}
if cpuList == nil {
cpuList = append(cpuList, runtime.GOMAXPROCS(-1))
}
}
func () bool {
return *failFast && atomic.LoadUint32(&numFailed) > 0
![]() |
The pages are generated with Golds v0.3.2-preview. (GOOS=darwin GOARCH=amd64) Golds is a Go 101 project developed by Tapir Liu. PR and bug reports are welcome and can be submitted to the issue list. Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds. |