Source file
src/testing/testing.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369 package testing
370
371 import (
372 "bytes"
373 "errors"
374 "flag"
375 "fmt"
376 "internal/goexperiment"
377 "internal/race"
378 "io"
379 "math/rand"
380 "os"
381 "reflect"
382 "runtime"
383 "runtime/debug"
384 "runtime/trace"
385 "sort"
386 "strconv"
387 "strings"
388 "sync"
389 "sync/atomic"
390 "time"
391 "unicode"
392 "unicode/utf8"
393 )
394
395 var initRan bool
396
397
398
399
400
401
402 func Init() {
403 if initRan {
404 return
405 }
406 initRan = true
407
408
409
410
411
412 short = flag.Bool("test.short", false, "run smaller test suite to save time")
413
414
415 failFast = flag.Bool("test.failfast", false, "do not start new tests after the first test failure")
416
417
418
419
420
421 outputDir = flag.String("test.outputdir", "", "write profiles to `dir`")
422
423 flag.Var(&chatty, "test.v", "verbose: print additional output")
424 count = flag.Uint("test.count", 1, "run tests and benchmarks `n` times")
425 coverProfile = flag.String("test.coverprofile", "", "write a coverage profile to `file`")
426 gocoverdir = flag.String("test.gocoverdir", "", "write coverage intermediate files to this directory")
427 matchList = flag.String("test.list", "", "list tests, examples, and benchmarks matching `regexp` then exit")
428 match = flag.String("test.run", "", "run only tests and examples matching `regexp`")
429 skip = flag.String("test.skip", "", "do not list or run tests matching `regexp`")
430 memProfile = flag.String("test.memprofile", "", "write an allocation profile to `file`")
431 memProfileRate = flag.Int("test.memprofilerate", 0, "set memory allocation profiling `rate` (see runtime.MemProfileRate)")
432 cpuProfile = flag.String("test.cpuprofile", "", "write a cpu profile to `file`")
433 blockProfile = flag.String("test.blockprofile", "", "write a goroutine blocking profile to `file`")
434 blockProfileRate = flag.Int("test.blockprofilerate", 1, "set blocking profile `rate` (see runtime.SetBlockProfileRate)")
435 mutexProfile = flag.String("test.mutexprofile", "", "write a mutex contention profile to the named file after execution")
436 mutexProfileFraction = flag.Int("test.mutexprofilefraction", 1, "if >= 0, calls runtime.SetMutexProfileFraction()")
437 panicOnExit0 = flag.Bool("test.paniconexit0", false, "panic on call to os.Exit(0)")
438 traceFile = flag.String("test.trace", "", "write an execution trace to `file`")
439 timeout = flag.Duration("test.timeout", 0, "panic test binary after duration `d` (default 0, timeout disabled)")
440 cpuListStr = flag.String("test.cpu", "", "comma-separated `list` of cpu counts to run each test with")
441 parallel = flag.Int("test.parallel", runtime.GOMAXPROCS(0), "run at most `n` tests in parallel")
442 testlog = flag.String("test.testlogfile", "", "write test action log to `file` (for use only by cmd/go)")
443 shuffle = flag.String("test.shuffle", "off", "randomize the execution order of tests and benchmarks")
444 fullPath = flag.Bool("test.fullpath", false, "show full file names in error messages")
445
446 initBenchmarkFlags()
447 initFuzzFlags()
448 }
449
450 var (
451
452 short *bool
453 failFast *bool
454 outputDir *string
455 chatty chattyFlag
456 count *uint
457 coverProfile *string
458 gocoverdir *string
459 matchList *string
460 match *string
461 skip *string
462 memProfile *string
463 memProfileRate *int
464 cpuProfile *string
465 blockProfile *string
466 blockProfileRate *int
467 mutexProfile *string
468 mutexProfileFraction *int
469 panicOnExit0 *bool
470 traceFile *string
471 timeout *time.Duration
472 cpuListStr *string
473 parallel *int
474 shuffle *string
475 testlog *string
476 fullPath *bool
477
478 haveExamples bool
479
480 cpuList []int
481 testlogFile *os.File
482
483 numFailed atomic.Uint32
484
485 running sync.Map
486 )
487
488 type chattyFlag struct {
489 on bool
490 json bool
491 }
492
493 func (*chattyFlag) IsBoolFlag() bool { return true }
494
495 func (f *chattyFlag) Set(arg string) error {
496 switch arg {
497 default:
498 return fmt.Errorf("invalid flag -test.v=%s", arg)
499 case "true", "test2json":
500 f.on = true
501 f.json = arg == "test2json"
502 case "false":
503 f.on = false
504 f.json = false
505 }
506 return nil
507 }
508
509 func (f *chattyFlag) String() string {
510 if f.json {
511 return "test2json"
512 }
513 if f.on {
514 return "true"
515 }
516 return "false"
517 }
518
519 func (f *chattyFlag) Get() any {
520 if f.json {
521 return "test2json"
522 }
523 return f.on
524 }
525
526 const marker = byte(0x16)
527
528 func (f *chattyFlag) prefix() string {
529 if f.json {
530 return string(marker)
531 }
532 return ""
533 }
534
535 type chattyPrinter struct {
536 w io.Writer
537 lastNameMu sync.Mutex
538 lastName string
539 json bool
540 }
541
542 func newChattyPrinter(w io.Writer) *chattyPrinter {
543 return &chattyPrinter{w: w, json: chatty.json}
544 }
545
546
547
548
549
550 func (p *chattyPrinter) prefix() string {
551 if p != nil && p.json {
552 return string(marker)
553 }
554 return ""
555 }
556
557
558
559
560 func (p *chattyPrinter) Updatef(testName, format string, args ...any) {
561 p.lastNameMu.Lock()
562 defer p.lastNameMu.Unlock()
563
564
565
566
567
568 p.lastName = testName
569 fmt.Fprintf(p.w, p.prefix()+format, args...)
570 }
571
572
573
574 func (p *chattyPrinter) Printf(testName, format string, args ...any) {
575 p.lastNameMu.Lock()
576 defer p.lastNameMu.Unlock()
577
578 if p.lastName == "" {
579 p.lastName = testName
580 } else if p.lastName != testName {
581 fmt.Fprintf(p.w, "%s=== NAME %s\n", p.prefix(), testName)
582 p.lastName = testName
583 }
584
585 fmt.Fprintf(p.w, format, args...)
586 }
587
588
589
590 const maxStackLen = 50
591
592
593
594 type common struct {
595 mu sync.RWMutex
596 output []byte
597 w io.Writer
598 ran bool
599 failed bool
600 skipped bool
601 done bool
602 helperPCs map[uintptr]struct{}
603 helperNames map[string]struct{}
604 cleanups []func()
605 cleanupName string
606 cleanupPc []uintptr
607 finished bool
608 inFuzzFn bool
609
610 chatty *chattyPrinter
611 bench bool
612 hasSub atomic.Bool
613 cleanupStarted atomic.Bool
614 raceErrors int
615 runner string
616 isParallel bool
617
618 parent *common
619 level int
620 creator []uintptr
621 name string
622 start time.Time
623 duration time.Duration
624 barrier chan bool
625 signal chan bool
626 sub []*T
627
628 tempDirMu sync.Mutex
629 tempDir string
630 tempDirErr error
631 tempDirSeq int32
632 }
633
634
635 func Short() bool {
636 if short == nil {
637 panic("testing: Short called before Init")
638 }
639
640 if !flag.Parsed() {
641 panic("testing: Short called before Parse")
642 }
643
644 return *short
645 }
646
647
648
649
650
651
652
653
654 var testBinary = "0"
655
656
657
658
659 func Testing() bool {
660 return testBinary == "1"
661 }
662
663
664
665
666 func CoverMode() string {
667 if goexperiment.CoverageRedesign {
668 return cover2.mode
669 }
670 return cover.Mode
671 }
672
673
674 func Verbose() bool {
675
676 if !flag.Parsed() {
677 panic("testing: Verbose called before Parse")
678 }
679 return chatty.on
680 }
681
682 func (c *common) checkFuzzFn(name string) {
683 if c.inFuzzFn {
684 panic(fmt.Sprintf("testing: f.%s was called inside the fuzz target, use t.%s instead", name, name))
685 }
686 }
687
688
689
690
691
692
693 func (c *common) frameSkip(skip int) runtime.Frame {
694
695
696 shouldUnlock := false
697 defer func() {
698 if shouldUnlock {
699 c.mu.Unlock()
700 }
701 }()
702 var pc [maxStackLen]uintptr
703
704
705 n := runtime.Callers(skip+2, pc[:])
706 if n == 0 {
707 panic("testing: zero callers found")
708 }
709 frames := runtime.CallersFrames(pc[:n])
710 var firstFrame, prevFrame, frame runtime.Frame
711 for more := true; more; prevFrame = frame {
712 frame, more = frames.Next()
713 if frame.Function == "runtime.gopanic" {
714 continue
715 }
716 if frame.Function == c.cleanupName {
717 frames = runtime.CallersFrames(c.cleanupPc)
718 continue
719 }
720 if firstFrame.PC == 0 {
721 firstFrame = frame
722 }
723 if frame.Function == c.runner {
724
725
726
727
728
729
730 if c.level > 1 {
731 frames = runtime.CallersFrames(c.creator)
732 parent := c.parent
733
734
735
736 if shouldUnlock {
737 c.mu.Unlock()
738 }
739 c = parent
740
741
742
743 shouldUnlock = true
744 c.mu.Lock()
745 continue
746 }
747 return prevFrame
748 }
749
750 if c.helperNames == nil {
751 c.helperNames = make(map[string]struct{})
752 for pc := range c.helperPCs {
753 c.helperNames[pcToName(pc)] = struct{}{}
754 }
755 }
756 if _, ok := c.helperNames[frame.Function]; !ok {
757
758 return frame
759 }
760 }
761 return firstFrame
762 }
763
764
765
766
767 func (c *common) decorate(s string, skip int) string {
768 frame := c.frameSkip(skip)
769 file := frame.File
770 line := frame.Line
771 if file != "" {
772 if *fullPath {
773
774 } else if index := strings.LastIndex(file, "/"); index >= 0 {
775 file = file[index+1:]
776 } else if index = strings.LastIndex(file, "\\"); index >= 0 {
777 file = file[index+1:]
778 }
779 } else {
780 file = "???"
781 }
782 if line == 0 {
783 line = 1
784 }
785 buf := new(strings.Builder)
786
787 buf.WriteString(" ")
788 fmt.Fprintf(buf, "%s:%d: ", file, line)
789 lines := strings.Split(s, "\n")
790 if l := len(lines); l > 1 && lines[l-1] == "" {
791 lines = lines[:l-1]
792 }
793 for i, line := range lines {
794 if i > 0 {
795
796 buf.WriteString("\n ")
797 }
798 buf.WriteString(line)
799 }
800 buf.WriteByte('\n')
801 return buf.String()
802 }
803
804
805
806 func (c *common) flushToParent(testName, format string, args ...any) {
807 p := c.parent
808 p.mu.Lock()
809 defer p.mu.Unlock()
810
811 c.mu.Lock()
812 defer c.mu.Unlock()
813
814 if len(c.output) > 0 {
815
816
817
818 format += "%s"
819 args = append(args[:len(args):len(args)], c.output)
820 c.output = c.output[:0]
821 }
822
823 if c.chatty != nil && (p.w == c.chatty.w || c.chatty.json) {
824
825
826
827
828
829
830
831
832
833
834
835
836
837 c.chatty.Updatef(testName, format, args...)
838 } else {
839
840
841 fmt.Fprintf(p.w, c.chatty.prefix()+format, args...)
842 }
843 }
844
845 type indenter struct {
846 c *common
847 }
848
849 func (w indenter) Write(b []byte) (n int, err error) {
850 n = len(b)
851 for len(b) > 0 {
852 end := bytes.IndexByte(b, '\n')
853 if end == -1 {
854 end = len(b)
855 } else {
856 end++
857 }
858
859
860 line := b[:end]
861 if line[0] == marker {
862 w.c.output = append(w.c.output, marker)
863 line = line[1:]
864 }
865 const indent = " "
866 w.c.output = append(w.c.output, indent...)
867 w.c.output = append(w.c.output, line...)
868 b = b[end:]
869 }
870 return
871 }
872
873
874 func fmtDuration(d time.Duration) string {
875 return fmt.Sprintf("%.2fs", d.Seconds())
876 }
877
878
879 type TB interface {
880 Cleanup(func())
881 Error(args ...any)
882 Errorf(format string, args ...any)
883 Fail()
884 FailNow()
885 Failed() bool
886 Fatal(args ...any)
887 Fatalf(format string, args ...any)
888 Helper()
889 Log(args ...any)
890 Logf(format string, args ...any)
891 Name() string
892 Setenv(key, value string)
893 Skip(args ...any)
894 SkipNow()
895 Skipf(format string, args ...any)
896 Skipped() bool
897 TempDir() string
898
899
900
901
902 private()
903 }
904
905 var _ TB = (*T)(nil)
906 var _ TB = (*B)(nil)
907
908
909
910
911
912
913
914
915
916
917 type T struct {
918 common
919 isEnvSet bool
920 context *testContext
921 }
922
923 func (c *common) private() {}
924
925
926
927
928
929
930 func (c *common) Name() string {
931 return c.name
932 }
933
934 func (c *common) setRan() {
935 if c.parent != nil {
936 c.parent.setRan()
937 }
938 c.mu.Lock()
939 defer c.mu.Unlock()
940 c.ran = true
941 }
942
943
944 func (c *common) Fail() {
945 if c.parent != nil {
946 c.parent.Fail()
947 }
948 c.mu.Lock()
949 defer c.mu.Unlock()
950
951 if c.done {
952 panic("Fail in goroutine after " + c.name + " has completed")
953 }
954 c.failed = true
955 }
956
957
958 func (c *common) Failed() bool {
959 c.mu.RLock()
960 failed := c.failed
961 c.mu.RUnlock()
962 return failed || c.raceErrors+race.Errors() > 0
963 }
964
965
966
967
968
969
970
971
972
973 func (c *common) FailNow() {
974 c.checkFuzzFn("FailNow")
975 c.Fail()
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996 c.mu.Lock()
997 c.finished = true
998 c.mu.Unlock()
999 runtime.Goexit()
1000 }
1001
1002
1003 func (c *common) log(s string) {
1004 c.logDepth(s, 3)
1005 }
1006
1007
1008 func (c *common) logDepth(s string, depth int) {
1009 c.mu.Lock()
1010 defer c.mu.Unlock()
1011 if c.done {
1012
1013
1014 for parent := c.parent; parent != nil; parent = parent.parent {
1015 parent.mu.Lock()
1016 defer parent.mu.Unlock()
1017 if !parent.done {
1018 parent.output = append(parent.output, parent.decorate(s, depth+1)...)
1019 return
1020 }
1021 }
1022 panic("Log in goroutine after " + c.name + " has completed: " + s)
1023 } else {
1024 if c.chatty != nil {
1025 if c.bench {
1026
1027
1028 fmt.Print(c.decorate(s, depth+1))
1029 } else {
1030 c.chatty.Printf(c.name, "%s", c.decorate(s, depth+1))
1031 }
1032
1033 return
1034 }
1035 c.output = append(c.output, c.decorate(s, depth+1)...)
1036 }
1037 }
1038
1039
1040
1041
1042
1043 func (c *common) Log(args ...any) {
1044 c.checkFuzzFn("Log")
1045 c.log(fmt.Sprintln(args...))
1046 }
1047
1048
1049
1050
1051
1052
1053 func (c *common) Logf(format string, args ...any) {
1054 c.checkFuzzFn("Logf")
1055 c.log(fmt.Sprintf(format, args...))
1056 }
1057
1058
1059 func (c *common) Error(args ...any) {
1060 c.checkFuzzFn("Error")
1061 c.log(fmt.Sprintln(args...))
1062 c.Fail()
1063 }
1064
1065
1066 func (c *common) Errorf(format string, args ...any) {
1067 c.checkFuzzFn("Errorf")
1068 c.log(fmt.Sprintf(format, args...))
1069 c.Fail()
1070 }
1071
1072
1073 func (c *common) Fatal(args ...any) {
1074 c.checkFuzzFn("Fatal")
1075 c.log(fmt.Sprintln(args...))
1076 c.FailNow()
1077 }
1078
1079
1080 func (c *common) Fatalf(format string, args ...any) {
1081 c.checkFuzzFn("Fatalf")
1082 c.log(fmt.Sprintf(format, args...))
1083 c.FailNow()
1084 }
1085
1086
1087 func (c *common) Skip(args ...any) {
1088 c.checkFuzzFn("Skip")
1089 c.log(fmt.Sprintln(args...))
1090 c.SkipNow()
1091 }
1092
1093
1094 func (c *common) Skipf(format string, args ...any) {
1095 c.checkFuzzFn("Skipf")
1096 c.log(fmt.Sprintf(format, args...))
1097 c.SkipNow()
1098 }
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108 func (c *common) SkipNow() {
1109 c.checkFuzzFn("SkipNow")
1110 c.mu.Lock()
1111 c.skipped = true
1112 c.finished = true
1113 c.mu.Unlock()
1114 runtime.Goexit()
1115 }
1116
1117
1118 func (c *common) Skipped() bool {
1119 c.mu.RLock()
1120 defer c.mu.RUnlock()
1121 return c.skipped
1122 }
1123
1124
1125
1126
1127 func (c *common) Helper() {
1128 c.mu.Lock()
1129 defer c.mu.Unlock()
1130 if c.helperPCs == nil {
1131 c.helperPCs = make(map[uintptr]struct{})
1132 }
1133
1134 var pc [1]uintptr
1135 n := runtime.Callers(2, pc[:])
1136 if n == 0 {
1137 panic("testing: zero callers found")
1138 }
1139 if _, found := c.helperPCs[pc[0]]; !found {
1140 c.helperPCs[pc[0]] = struct{}{}
1141 c.helperNames = nil
1142 }
1143 }
1144
1145
1146
1147
1148 func (c *common) Cleanup(f func()) {
1149 c.checkFuzzFn("Cleanup")
1150 var pc [maxStackLen]uintptr
1151
1152 n := runtime.Callers(2, pc[:])
1153 cleanupPc := pc[:n]
1154
1155 fn := func() {
1156 defer func() {
1157 c.mu.Lock()
1158 defer c.mu.Unlock()
1159 c.cleanupName = ""
1160 c.cleanupPc = nil
1161 }()
1162
1163 name := callerName(0)
1164 c.mu.Lock()
1165 c.cleanupName = name
1166 c.cleanupPc = cleanupPc
1167 c.mu.Unlock()
1168
1169 f()
1170 }
1171
1172 c.mu.Lock()
1173 defer c.mu.Unlock()
1174 c.cleanups = append(c.cleanups, fn)
1175 }
1176
1177
1178
1179
1180
1181
1182 func (c *common) TempDir() string {
1183 c.checkFuzzFn("TempDir")
1184
1185
1186 c.tempDirMu.Lock()
1187 var nonExistent bool
1188 if c.tempDir == "" {
1189 nonExistent = true
1190 } else {
1191 _, err := os.Stat(c.tempDir)
1192 nonExistent = os.IsNotExist(err)
1193 if err != nil && !nonExistent {
1194 c.Fatalf("TempDir: %v", err)
1195 }
1196 }
1197
1198 if nonExistent {
1199 c.Helper()
1200
1201
1202
1203
1204 mapper := func(r rune) rune {
1205 if r < utf8.RuneSelf {
1206 const allowed = "!#$%&()+,-.=@^_{}~ "
1207 if '0' <= r && r <= '9' ||
1208 'a' <= r && r <= 'z' ||
1209 'A' <= r && r <= 'Z' {
1210 return r
1211 }
1212 if strings.ContainsRune(allowed, r) {
1213 return r
1214 }
1215 } else if unicode.IsLetter(r) || unicode.IsNumber(r) {
1216 return r
1217 }
1218 return -1
1219 }
1220 pattern := strings.Map(mapper, c.Name())
1221 c.tempDir, c.tempDirErr = os.MkdirTemp("", pattern)
1222 if c.tempDirErr == nil {
1223 c.Cleanup(func() {
1224 if err := removeAll(c.tempDir); err != nil {
1225 c.Errorf("TempDir RemoveAll cleanup: %v", err)
1226 }
1227 })
1228 }
1229 }
1230
1231 if c.tempDirErr == nil {
1232 c.tempDirSeq++
1233 }
1234 seq := c.tempDirSeq
1235 c.tempDirMu.Unlock()
1236
1237 if c.tempDirErr != nil {
1238 c.Fatalf("TempDir: %v", c.tempDirErr)
1239 }
1240
1241 dir := fmt.Sprintf("%s%c%03d", c.tempDir, os.PathSeparator, seq)
1242 if err := os.Mkdir(dir, 0777); err != nil {
1243 c.Fatalf("TempDir: %v", err)
1244 }
1245 return dir
1246 }
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257 func removeAll(path string) error {
1258 const arbitraryTimeout = 2 * time.Second
1259 var (
1260 start time.Time
1261 nextSleep = 1 * time.Millisecond
1262 )
1263 for {
1264 err := os.RemoveAll(path)
1265 if !isWindowsRetryable(err) {
1266 return err
1267 }
1268 if start.IsZero() {
1269 start = time.Now()
1270 } else if d := time.Since(start) + nextSleep; d >= arbitraryTimeout {
1271 return err
1272 }
1273 time.Sleep(nextSleep)
1274 nextSleep += time.Duration(rand.Int63n(int64(nextSleep)))
1275 }
1276 }
1277
1278
1279
1280
1281
1282
1283
1284 func (c *common) Setenv(key, value string) {
1285 c.checkFuzzFn("Setenv")
1286 prevValue, ok := os.LookupEnv(key)
1287
1288 if err := os.Setenv(key, value); err != nil {
1289 c.Fatalf("cannot set environment variable: %v", err)
1290 }
1291
1292 if ok {
1293 c.Cleanup(func() {
1294 os.Setenv(key, prevValue)
1295 })
1296 } else {
1297 c.Cleanup(func() {
1298 os.Unsetenv(key)
1299 })
1300 }
1301 }
1302
1303
1304 type panicHandling int
1305
1306 const (
1307 normalPanic panicHandling = iota
1308 recoverAndReturnPanic
1309 )
1310
1311
1312
1313
1314 func (c *common) runCleanup(ph panicHandling) (panicVal any) {
1315 c.cleanupStarted.Store(true)
1316 defer c.cleanupStarted.Store(false)
1317
1318 if ph == recoverAndReturnPanic {
1319 defer func() {
1320 panicVal = recover()
1321 }()
1322 }
1323
1324
1325
1326 defer func() {
1327 c.mu.Lock()
1328 recur := len(c.cleanups) > 0
1329 c.mu.Unlock()
1330 if recur {
1331 c.runCleanup(normalPanic)
1332 }
1333 }()
1334
1335 for {
1336 var cleanup func()
1337 c.mu.Lock()
1338 if len(c.cleanups) > 0 {
1339 last := len(c.cleanups) - 1
1340 cleanup = c.cleanups[last]
1341 c.cleanups = c.cleanups[:last]
1342 }
1343 c.mu.Unlock()
1344 if cleanup == nil {
1345 return nil
1346 }
1347 cleanup()
1348 }
1349 }
1350
1351
1352
1353 func callerName(skip int) string {
1354 var pc [1]uintptr
1355 n := runtime.Callers(skip+2, pc[:])
1356 if n == 0 {
1357 panic("testing: zero callers found")
1358 }
1359 return pcToName(pc[0])
1360 }
1361
1362 func pcToName(pc uintptr) string {
1363 pcs := []uintptr{pc}
1364 frames := runtime.CallersFrames(pcs)
1365 frame, _ := frames.Next()
1366 return frame.Function
1367 }
1368
1369
1370
1371
1372
1373 func (t *T) Parallel() {
1374 if t.isParallel {
1375 panic("testing: t.Parallel called multiple times")
1376 }
1377 if t.isEnvSet {
1378 panic("testing: t.Parallel called after t.Setenv; cannot set environment variables in parallel tests")
1379 }
1380 t.isParallel = true
1381 if t.parent.barrier == nil {
1382
1383
1384
1385 return
1386 }
1387
1388
1389
1390
1391 t.duration += time.Since(t.start)
1392
1393
1394 t.parent.sub = append(t.parent.sub, t)
1395 t.raceErrors += race.Errors()
1396
1397 if t.chatty != nil {
1398 t.chatty.Updatef(t.name, "=== PAUSE %s\n", t.name)
1399 }
1400 running.Delete(t.name)
1401
1402 t.signal <- true
1403 <-t.parent.barrier
1404 t.context.waitParallel()
1405
1406 if t.chatty != nil {
1407 t.chatty.Updatef(t.name, "=== CONT %s\n", t.name)
1408 }
1409 running.Store(t.name, time.Now())
1410
1411 t.start = time.Now()
1412 t.raceErrors += -race.Errors()
1413 }
1414
1415
1416
1417
1418
1419
1420
1421 func (t *T) Setenv(key, value string) {
1422
1423
1424
1425
1426
1427 isParallel := false
1428 for c := &t.common; c != nil; c = c.parent {
1429 if c.isParallel {
1430 isParallel = true
1431 break
1432 }
1433 }
1434 if isParallel {
1435 panic("testing: t.Setenv called after t.Parallel; cannot set environment variables in parallel tests")
1436 }
1437
1438 t.isEnvSet = true
1439
1440 t.common.Setenv(key, value)
1441 }
1442
1443
1444
1445 type InternalTest struct {
1446 Name string
1447 F func(*T)
1448 }
1449
1450 var errNilPanicOrGoexit = errors.New("test executed panic(nil) or runtime.Goexit")
1451
1452 func tRunner(t *T, fn func(t *T)) {
1453 t.runner = callerName(0)
1454
1455
1456
1457
1458
1459 defer func() {
1460 if t.Failed() {
1461 numFailed.Add(1)
1462 }
1463
1464 if t.raceErrors+race.Errors() > 0 {
1465 t.Errorf("race detected during execution of test")
1466 }
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476 err := recover()
1477 signal := true
1478
1479 t.mu.RLock()
1480 finished := t.finished
1481 t.mu.RUnlock()
1482 if !finished && err == nil {
1483 err = errNilPanicOrGoexit
1484 for p := t.parent; p != nil; p = p.parent {
1485 p.mu.RLock()
1486 finished = p.finished
1487 p.mu.RUnlock()
1488 if finished {
1489 if !t.isParallel {
1490 t.Errorf("%v: subtest may have called FailNow on a parent test", err)
1491 err = nil
1492 }
1493 signal = false
1494 break
1495 }
1496 }
1497 }
1498
1499 if err != nil && t.context.isFuzzing {
1500 prefix := "panic: "
1501 if err == errNilPanicOrGoexit {
1502 prefix = ""
1503 }
1504 t.Errorf("%s%s\n%s\n", prefix, err, string(debug.Stack()))
1505 t.mu.Lock()
1506 t.finished = true
1507 t.mu.Unlock()
1508 err = nil
1509 }
1510
1511
1512
1513 didPanic := false
1514 defer func() {
1515
1516
1517
1518 if didPanic {
1519 return
1520 }
1521 if err != nil {
1522 panic(err)
1523 }
1524 running.Delete(t.name)
1525 t.signal <- signal
1526 }()
1527
1528 doPanic := func(err any) {
1529 t.Fail()
1530 if r := t.runCleanup(recoverAndReturnPanic); r != nil {
1531 t.Logf("cleanup panicked with %v", r)
1532 }
1533
1534 for root := &t.common; root.parent != nil; root = root.parent {
1535 root.mu.Lock()
1536 root.duration += time.Since(root.start)
1537 d := root.duration
1538 root.mu.Unlock()
1539 root.flushToParent(root.name, "--- FAIL: %s (%s)\n", root.name, fmtDuration(d))
1540 if r := root.parent.runCleanup(recoverAndReturnPanic); r != nil {
1541 fmt.Fprintf(root.parent.w, "cleanup panicked with %v", r)
1542 }
1543 }
1544 didPanic = true
1545 panic(err)
1546 }
1547 if err != nil {
1548 doPanic(err)
1549 }
1550
1551 t.duration += time.Since(t.start)
1552
1553 if len(t.sub) > 0 {
1554
1555
1556 t.context.release()
1557
1558 close(t.barrier)
1559
1560 for _, sub := range t.sub {
1561 <-sub.signal
1562 }
1563 cleanupStart := time.Now()
1564 err := t.runCleanup(recoverAndReturnPanic)
1565 t.duration += time.Since(cleanupStart)
1566 if err != nil {
1567 doPanic(err)
1568 }
1569 if !t.isParallel {
1570
1571 t.context.waitParallel()
1572 }
1573 } else if t.isParallel {
1574
1575
1576 t.context.release()
1577 }
1578 t.report()
1579
1580
1581
1582 t.done = true
1583 if t.parent != nil && !t.hasSub.Load() {
1584 t.setRan()
1585 }
1586 }()
1587 defer func() {
1588 if len(t.sub) == 0 {
1589 t.runCleanup(normalPanic)
1590 }
1591 }()
1592
1593 t.start = time.Now()
1594 t.raceErrors = -race.Errors()
1595 fn(t)
1596
1597
1598 t.mu.Lock()
1599 t.finished = true
1600 t.mu.Unlock()
1601 }
1602
1603
1604
1605
1606
1607
1608
1609 func (t *T) Run(name string, f func(t *T)) bool {
1610 if t.cleanupStarted.Load() {
1611 panic("testing: t.Run called during t.Cleanup")
1612 }
1613
1614 t.hasSub.Store(true)
1615 testName, ok, _ := t.context.match.fullName(&t.common, name)
1616 if !ok || shouldFailFast() {
1617 return true
1618 }
1619
1620
1621
1622 var pc [maxStackLen]uintptr
1623 n := runtime.Callers(2, pc[:])
1624 t = &T{
1625 common: common{
1626 barrier: make(chan bool),
1627 signal: make(chan bool, 1),
1628 name: testName,
1629 parent: &t.common,
1630 level: t.level + 1,
1631 creator: pc[:n],
1632 chatty: t.chatty,
1633 },
1634 context: t.context,
1635 }
1636 t.w = indenter{&t.common}
1637
1638 if t.chatty != nil {
1639 t.chatty.Updatef(t.name, "=== RUN %s\n", t.name)
1640 }
1641 running.Store(t.name, time.Now())
1642
1643
1644
1645
1646
1647
1648 go tRunner(t, f)
1649 if !<-t.signal {
1650
1651
1652 runtime.Goexit()
1653 }
1654 if t.chatty != nil && t.chatty.json {
1655 t.chatty.Updatef(t.parent.name, "=== NAME %s\n", t.parent.name)
1656 }
1657 return !t.failed
1658 }
1659
1660
1661
1662
1663
1664 func (t *T) Deadline() (deadline time.Time, ok bool) {
1665 deadline = t.context.deadline
1666 return deadline, !deadline.IsZero()
1667 }
1668
1669
1670
1671 type testContext struct {
1672 match *matcher
1673 deadline time.Time
1674
1675
1676
1677
1678
1679 isFuzzing bool
1680
1681 mu sync.Mutex
1682
1683
1684 startParallel chan bool
1685
1686
1687
1688 running int
1689
1690
1691 numWaiting int
1692
1693
1694 maxParallel int
1695 }
1696
1697 func newTestContext(maxParallel int, m *matcher) *testContext {
1698 return &testContext{
1699 match: m,
1700 startParallel: make(chan bool),
1701 maxParallel: maxParallel,
1702 running: 1,
1703 }
1704 }
1705
1706 func (c *testContext) waitParallel() {
1707 c.mu.Lock()
1708 if c.running < c.maxParallel {
1709 c.running++
1710 c.mu.Unlock()
1711 return
1712 }
1713 c.numWaiting++
1714 c.mu.Unlock()
1715 <-c.startParallel
1716 }
1717
1718 func (c *testContext) release() {
1719 c.mu.Lock()
1720 if c.numWaiting == 0 {
1721 c.running--
1722 c.mu.Unlock()
1723 return
1724 }
1725 c.numWaiting--
1726 c.mu.Unlock()
1727 c.startParallel <- true
1728 }
1729
1730
1731
1732 var errMain = errors.New("testing: unexpected use of func Main")
1733
1734 type matchStringOnly func(pat, str string) (bool, error)
1735
1736 func (f matchStringOnly) MatchString(pat, str string) (bool, error) { return f(pat, str) }
1737 func (f matchStringOnly) StartCPUProfile(w io.Writer) error { return errMain }
1738 func (f matchStringOnly) StopCPUProfile() {}
1739 func (f matchStringOnly) WriteProfileTo(string, io.Writer, int) error { return errMain }
1740 func (f matchStringOnly) ImportPath() string { return "" }
1741 func (f matchStringOnly) StartTestLog(io.Writer) {}
1742 func (f matchStringOnly) StopTestLog() error { return errMain }
1743 func (f matchStringOnly) SetPanicOnExit0(bool) {}
1744 func (f matchStringOnly) CoordinateFuzzing(time.Duration, int64, time.Duration, int64, int, []corpusEntry, []reflect.Type, string, string) error {
1745 return errMain
1746 }
1747 func (f matchStringOnly) RunFuzzWorker(func(corpusEntry) error) error { return errMain }
1748 func (f matchStringOnly) ReadCorpus(string, []reflect.Type) ([]corpusEntry, error) {
1749 return nil, errMain
1750 }
1751 func (f matchStringOnly) CheckCorpus([]any, []reflect.Type) error { return nil }
1752 func (f matchStringOnly) ResetCoverage() {}
1753 func (f matchStringOnly) SnapshotCoverage() {}
1754
1755
1756
1757
1758
1759
1760
1761 func Main(matchString func(pat, str string) (bool, error), tests []InternalTest, benchmarks []InternalBenchmark, examples []InternalExample) {
1762 os.Exit(MainStart(matchStringOnly(matchString), tests, benchmarks, nil, examples).Run())
1763 }
1764
1765
1766 type M struct {
1767 deps testDeps
1768 tests []InternalTest
1769 benchmarks []InternalBenchmark
1770 fuzzTargets []InternalFuzzTarget
1771 examples []InternalExample
1772
1773 timer *time.Timer
1774 afterOnce sync.Once
1775
1776 numRun int
1777
1778
1779
1780 exitCode int
1781 }
1782
1783
1784
1785
1786
1787 type testDeps interface {
1788 ImportPath() string
1789 MatchString(pat, str string) (bool, error)
1790 SetPanicOnExit0(bool)
1791 StartCPUProfile(io.Writer) error
1792 StopCPUProfile()
1793 StartTestLog(io.Writer)
1794 StopTestLog() error
1795 WriteProfileTo(string, io.Writer, int) error
1796 CoordinateFuzzing(time.Duration, int64, time.Duration, int64, int, []corpusEntry, []reflect.Type, string, string) error
1797 RunFuzzWorker(func(corpusEntry) error) error
1798 ReadCorpus(string, []reflect.Type) ([]corpusEntry, error)
1799 CheckCorpus([]any, []reflect.Type) error
1800 ResetCoverage()
1801 SnapshotCoverage()
1802 }
1803
1804
1805
1806
1807 func MainStart(deps testDeps, tests []InternalTest, benchmarks []InternalBenchmark, fuzzTargets []InternalFuzzTarget, examples []InternalExample) *M {
1808 Init()
1809 return &M{
1810 deps: deps,
1811 tests: tests,
1812 benchmarks: benchmarks,
1813 fuzzTargets: fuzzTargets,
1814 examples: examples,
1815 }
1816 }
1817
1818 var testingTesting bool
1819 var realStderr *os.File
1820
1821
1822 func (m *M) Run() (code int) {
1823 defer func() {
1824 code = m.exitCode
1825 }()
1826
1827
1828
1829
1830
1831 m.numRun++
1832
1833
1834 if !flag.Parsed() {
1835 flag.Parse()
1836 }
1837
1838 if chatty.json {
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872 realStderr = os.Stderr
1873 os.Stderr = os.Stdout
1874 }
1875
1876 if *parallel < 1 {
1877 fmt.Fprintln(os.Stderr, "testing: -parallel can only be given a positive integer")
1878 flag.Usage()
1879 m.exitCode = 2
1880 return
1881 }
1882 if *matchFuzz != "" && *fuzzCacheDir == "" {
1883 fmt.Fprintln(os.Stderr, "testing: -test.fuzzcachedir must be set if -test.fuzz is set")
1884 flag.Usage()
1885 m.exitCode = 2
1886 return
1887 }
1888
1889 if *matchList != "" {
1890 listTests(m.deps.MatchString, m.tests, m.benchmarks, m.fuzzTargets, m.examples)
1891 m.exitCode = 0
1892 return
1893 }
1894
1895 if *shuffle != "off" {
1896 var n int64
1897 var err error
1898 if *shuffle == "on" {
1899 n = time.Now().UnixNano()
1900 } else {
1901 n, err = strconv.ParseInt(*shuffle, 10, 64)
1902 if err != nil {
1903 fmt.Fprintln(os.Stderr, `testing: -shuffle should be "off", "on", or a valid integer:`, err)
1904 m.exitCode = 2
1905 return
1906 }
1907 }
1908 fmt.Println("-test.shuffle", n)
1909 rng := rand.New(rand.NewSource(n))
1910 rng.Shuffle(len(m.tests), func(i, j int) { m.tests[i], m.tests[j] = m.tests[j], m.tests[i] })
1911 rng.Shuffle(len(m.benchmarks), func(i, j int) { m.benchmarks[i], m.benchmarks[j] = m.benchmarks[j], m.benchmarks[i] })
1912 }
1913
1914 parseCpuList()
1915
1916 m.before()
1917 defer m.after()
1918
1919
1920
1921
1922 if !*isFuzzWorker {
1923 deadline := m.startAlarm()
1924 haveExamples = len(m.examples) > 0
1925 testRan, testOk := runTests(m.deps.MatchString, m.tests, deadline)
1926 fuzzTargetsRan, fuzzTargetsOk := runFuzzTests(m.deps, m.fuzzTargets, deadline)
1927 exampleRan, exampleOk := runExamples(m.deps.MatchString, m.examples)
1928 m.stopAlarm()
1929 if !testRan && !exampleRan && !fuzzTargetsRan && *matchBenchmarks == "" && *matchFuzz == "" {
1930 fmt.Fprintln(os.Stderr, "testing: warning: no tests to run")
1931 if testingTesting && *match != "^$" {
1932
1933
1934
1935
1936
1937 fmt.Print(chatty.prefix(), "FAIL: package testing must run tests\n")
1938 testOk = false
1939 }
1940 }
1941 if !testOk || !exampleOk || !fuzzTargetsOk || !runBenchmarks(m.deps.ImportPath(), m.deps.MatchString, m.benchmarks) || race.Errors() > 0 {
1942 fmt.Print(chatty.prefix(), "FAIL\n")
1943 m.exitCode = 1
1944 return
1945 }
1946 }
1947
1948 fuzzingOk := runFuzzing(m.deps, m.fuzzTargets)
1949 if !fuzzingOk {
1950 fmt.Print(chatty.prefix(), "FAIL\n")
1951 if *isFuzzWorker {
1952 m.exitCode = fuzzWorkerExitCode
1953 } else {
1954 m.exitCode = 1
1955 }
1956 return
1957 }
1958
1959 m.exitCode = 0
1960 if !*isFuzzWorker {
1961 fmt.Print(chatty.prefix(), "PASS\n")
1962 }
1963 return
1964 }
1965
1966 func (t *T) report() {
1967 if t.parent == nil {
1968 return
1969 }
1970 dstr := fmtDuration(t.duration)
1971 format := "--- %s: %s (%s)\n"
1972 if t.Failed() {
1973 t.flushToParent(t.name, format, "FAIL", t.name, dstr)
1974 } else if t.chatty != nil {
1975 if t.Skipped() {
1976 t.flushToParent(t.name, format, "SKIP", t.name, dstr)
1977 } else {
1978 t.flushToParent(t.name, format, "PASS", t.name, dstr)
1979 }
1980 }
1981 }
1982
1983 func listTests(matchString func(pat, str string) (bool, error), tests []InternalTest, benchmarks []InternalBenchmark, fuzzTargets []InternalFuzzTarget, examples []InternalExample) {
1984 if _, err := matchString(*matchList, "non-empty"); err != nil {
1985 fmt.Fprintf(os.Stderr, "testing: invalid regexp in -test.list (%q): %s\n", *matchList, err)
1986 os.Exit(1)
1987 }
1988
1989 for _, test := range tests {
1990 if ok, _ := matchString(*matchList, test.Name); ok {
1991 fmt.Println(test.Name)
1992 }
1993 }
1994 for _, bench := range benchmarks {
1995 if ok, _ := matchString(*matchList, bench.Name); ok {
1996 fmt.Println(bench.Name)
1997 }
1998 }
1999 for _, fuzzTarget := range fuzzTargets {
2000 if ok, _ := matchString(*matchList, fuzzTarget.Name); ok {
2001 fmt.Println(fuzzTarget.Name)
2002 }
2003 }
2004 for _, example := range examples {
2005 if ok, _ := matchString(*matchList, example.Name); ok {
2006 fmt.Println(example.Name)
2007 }
2008 }
2009 }
2010
2011
2012
2013 func RunTests(matchString func(pat, str string) (bool, error), tests []InternalTest) (ok bool) {
2014 var deadline time.Time
2015 if *timeout > 0 {
2016 deadline = time.Now().Add(*timeout)
2017 }
2018 ran, ok := runTests(matchString, tests, deadline)
2019 if !ran && !haveExamples {
2020 fmt.Fprintln(os.Stderr, "testing: warning: no tests to run")
2021 }
2022 return ok
2023 }
2024
2025 func runTests(matchString func(pat, str string) (bool, error), tests []InternalTest, deadline time.Time) (ran, ok bool) {
2026 ok = true
2027 for _, procs := range cpuList {
2028 runtime.GOMAXPROCS(procs)
2029 for i := uint(0); i < *count; i++ {
2030 if shouldFailFast() {
2031 break
2032 }
2033 if i > 0 && !ran {
2034
2035
2036
2037 break
2038 }
2039 ctx := newTestContext(*parallel, newMatcher(matchString, *match, "-test.run", *skip))
2040 ctx.deadline = deadline
2041 t := &T{
2042 common: common{
2043 signal: make(chan bool, 1),
2044 barrier: make(chan bool),
2045 w: os.Stdout,
2046 },
2047 context: ctx,
2048 }
2049 if Verbose() {
2050 t.chatty = newChattyPrinter(t.w)
2051 }
2052 tRunner(t, func(t *T) {
2053 for _, test := range tests {
2054 t.Run(test.Name, test.F)
2055 }
2056 })
2057 select {
2058 case <-t.signal:
2059 default:
2060 panic("internal error: tRunner exited without sending on t.signal")
2061 }
2062 ok = ok && !t.Failed()
2063 ran = ran || t.ran
2064 }
2065 }
2066 return ran, ok
2067 }
2068
2069
2070 func (m *M) before() {
2071 if *memProfileRate > 0 {
2072 runtime.MemProfileRate = *memProfileRate
2073 }
2074 if *cpuProfile != "" {
2075 f, err := os.Create(toOutputDir(*cpuProfile))
2076 if err != nil {
2077 fmt.Fprintf(os.Stderr, "testing: %s\n", err)
2078 return
2079 }
2080 if err := m.deps.StartCPUProfile(f); err != nil {
2081 fmt.Fprintf(os.Stderr, "testing: can't start cpu profile: %s\n", err)
2082 f.Close()
2083 return
2084 }
2085
2086 }
2087 if *traceFile != "" {
2088 f, err := os.Create(toOutputDir(*traceFile))
2089 if err != nil {
2090 fmt.Fprintf(os.Stderr, "testing: %s\n", err)
2091 return
2092 }
2093 if err := trace.Start(f); err != nil {
2094 fmt.Fprintf(os.Stderr, "testing: can't start tracing: %s\n", err)
2095 f.Close()
2096 return
2097 }
2098
2099 }
2100 if *blockProfile != "" && *blockProfileRate >= 0 {
2101 runtime.SetBlockProfileRate(*blockProfileRate)
2102 }
2103 if *mutexProfile != "" && *mutexProfileFraction >= 0 {
2104 runtime.SetMutexProfileFraction(*mutexProfileFraction)
2105 }
2106 if *coverProfile != "" && CoverMode() == "" {
2107 fmt.Fprintf(os.Stderr, "testing: cannot use -test.coverprofile because test binary was not built with coverage enabled\n")
2108 os.Exit(2)
2109 }
2110 if *gocoverdir != "" && CoverMode() == "" {
2111 fmt.Fprintf(os.Stderr, "testing: cannot use -test.gocoverdir because test binary was not built with coverage enabled\n")
2112 os.Exit(2)
2113 }
2114 if *testlog != "" {
2115
2116
2117 var f *os.File
2118 var err error
2119 if m.numRun == 1 {
2120 f, err = os.Create(*testlog)
2121 } else {
2122 f, err = os.OpenFile(*testlog, os.O_WRONLY, 0)
2123 if err == nil {
2124 f.Seek(0, io.SeekEnd)
2125 }
2126 }
2127 if err != nil {
2128 fmt.Fprintf(os.Stderr, "testing: %s\n", err)
2129 os.Exit(2)
2130 }
2131 m.deps.StartTestLog(f)
2132 testlogFile = f
2133 }
2134 if *panicOnExit0 {
2135 m.deps.SetPanicOnExit0(true)
2136 }
2137 }
2138
2139
2140 func (m *M) after() {
2141 m.afterOnce.Do(func() {
2142 m.writeProfiles()
2143 })
2144
2145
2146
2147
2148 if *panicOnExit0 {
2149 m.deps.SetPanicOnExit0(false)
2150 }
2151 }
2152
2153 func (m *M) writeProfiles() {
2154 if *testlog != "" {
2155 if err := m.deps.StopTestLog(); err != nil {
2156 fmt.Fprintf(os.Stderr, "testing: can't write %s: %s\n", *testlog, err)
2157 os.Exit(2)
2158 }
2159 if err := testlogFile.Close(); err != nil {
2160 fmt.Fprintf(os.Stderr, "testing: can't write %s: %s\n", *testlog, err)
2161 os.Exit(2)
2162 }
2163 }
2164 if *cpuProfile != "" {
2165 m.deps.StopCPUProfile()
2166 }
2167 if *traceFile != "" {
2168 trace.Stop()
2169 }
2170 if *memProfile != "" {
2171 f, err := os.Create(toOutputDir(*memProfile))
2172 if err != nil {
2173 fmt.Fprintf(os.Stderr, "testing: %s\n", err)
2174 os.Exit(2)
2175 }
2176 runtime.GC()
2177 if err = m.deps.WriteProfileTo("allocs", f, 0); err != nil {
2178 fmt.Fprintf(os.Stderr, "testing: can't write %s: %s\n", *memProfile, err)
2179 os.Exit(2)
2180 }
2181 f.Close()
2182 }
2183 if *blockProfile != "" && *blockProfileRate >= 0 {
2184 f, err := os.Create(toOutputDir(*blockProfile))
2185 if err != nil {
2186 fmt.Fprintf(os.Stderr, "testing: %s\n", err)
2187 os.Exit(2)
2188 }
2189 if err = m.deps.WriteProfileTo("block", f, 0); err != nil {
2190 fmt.Fprintf(os.Stderr, "testing: can't write %s: %s\n", *blockProfile, err)
2191 os.Exit(2)
2192 }
2193 f.Close()
2194 }
2195 if *mutexProfile != "" && *mutexProfileFraction >= 0 {
2196 f, err := os.Create(toOutputDir(*mutexProfile))
2197 if err != nil {
2198 fmt.Fprintf(os.Stderr, "testing: %s\n", err)
2199 os.Exit(2)
2200 }
2201 if err = m.deps.WriteProfileTo("mutex", f, 0); err != nil {
2202 fmt.Fprintf(os.Stderr, "testing: can't write %s: %s\n", *mutexProfile, err)
2203 os.Exit(2)
2204 }
2205 f.Close()
2206 }
2207 if CoverMode() != "" {
2208 coverReport()
2209 }
2210 }
2211
2212
2213
2214 func toOutputDir(path string) string {
2215 if *outputDir == "" || path == "" {
2216 return path
2217 }
2218
2219
2220
2221
2222
2223
2224
2225 if runtime.GOOS == "windows" && len(path) >= 2 {
2226 letter, colon := path[0], path[1]
2227 if ('a' <= letter && letter <= 'z' || 'A' <= letter && letter <= 'Z') && colon == ':' {
2228
2229 return path
2230 }
2231 }
2232 if os.IsPathSeparator(path[0]) {
2233 return path
2234 }
2235 return fmt.Sprintf("%s%c%s", *outputDir, os.PathSeparator, path)
2236 }
2237
2238
2239 func (m *M) startAlarm() time.Time {
2240 if *timeout <= 0 {
2241 return time.Time{}
2242 }
2243
2244 deadline := time.Now().Add(*timeout)
2245 m.timer = time.AfterFunc(*timeout, func() {
2246 m.after()
2247 debug.SetTraceback("all")
2248 extra := ""
2249
2250 if list := runningList(); len(list) > 0 {
2251 var b strings.Builder
2252 b.WriteString("\nrunning tests:")
2253 for _, name := range list {
2254 b.WriteString("\n\t")
2255 b.WriteString(name)
2256 }
2257 extra = b.String()
2258 }
2259 panic(fmt.Sprintf("test timed out after %v%s", *timeout, extra))
2260 })
2261 return deadline
2262 }
2263
2264
2265 func runningList() []string {
2266 var list []string
2267 running.Range(func(k, v any) bool {
2268 list = append(list, fmt.Sprintf("%s (%v)", k.(string), time.Since(v.(time.Time)).Round(time.Second)))
2269 return true
2270 })
2271 sort.Strings(list)
2272 return list
2273 }
2274
2275
2276 func (m *M) stopAlarm() {
2277 if *timeout > 0 {
2278 m.timer.Stop()
2279 }
2280 }
2281
2282 func parseCpuList() {
2283 for _, val := range strings.Split(*cpuListStr, ",") {
2284 val = strings.TrimSpace(val)
2285 if val == "" {
2286 continue
2287 }
2288 cpu, err := strconv.Atoi(val)
2289 if err != nil || cpu <= 0 {
2290 fmt.Fprintf(os.Stderr, "testing: invalid value %q for -test.cpu\n", val)
2291 os.Exit(1)
2292 }
2293 cpuList = append(cpuList, cpu)
2294 }
2295 if cpuList == nil {
2296 cpuList = append(cpuList, runtime.GOMAXPROCS(-1))
2297 }
2298 }
2299
2300 func shouldFailFast() bool {
2301 return *failFast && numFailed.Load() > 0
2302 }
2303
View as plain text