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