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
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399 package testing
400
401 import (
402 "bytes"
403 "context"
404 "errors"
405 "flag"
406 "fmt"
407 "internal/race"
408 "io"
409 "math/rand"
410 "os"
411 "path/filepath"
412 "reflect"
413 "runtime"
414 "runtime/debug"
415 "runtime/trace"
416 "slices"
417 "strconv"
418 "strings"
419 "sync"
420 "sync/atomic"
421 "time"
422 "unicode"
423 _ "unsafe"
424 )
425
426 var initRan bool
427
428 var (
429 parallelStart atomic.Int64
430 parallelStop atomic.Int64
431 )
432
433
434
435
436
437
438 func Init() {
439 if initRan {
440 return
441 }
442 initRan = true
443
444
445
446
447
448 short = flag.Bool("test.short", false, "run smaller test suite to save time")
449
450
451 failFast = flag.Bool("test.failfast", false, "do not start new tests after the first test failure")
452
453
454
455
456
457 outputDir = flag.String("test.outputdir", "", "write profiles to `dir`")
458 artifacts = flag.Bool("test.artifacts", false, "store test artifacts in test.,outputdir")
459
460 flag.Var(&chatty, "test.v", "verbose: print additional output")
461 count = flag.Uint("test.count", 1, "run tests and benchmarks `n` times")
462 coverProfile = flag.String("test.coverprofile", "", "write a coverage profile to `file`")
463 gocoverdir = flag.String("test.gocoverdir", "", "write coverage intermediate files to this directory")
464 matchList = flag.String("test.list", "", "list tests, examples, and benchmarks matching `regexp` then exit")
465 match = flag.String("test.run", "", "run only tests and examples matching `regexp`")
466 skip = flag.String("test.skip", "", "do not list or run tests matching `regexp`")
467 memProfile = flag.String("test.memprofile", "", "write an allocation profile to `file`")
468 memProfileRate = flag.Int("test.memprofilerate", 0, "set memory allocation profiling `rate` (see runtime.MemProfileRate)")
469 cpuProfile = flag.String("test.cpuprofile", "", "write a cpu profile to `file`")
470 blockProfile = flag.String("test.blockprofile", "", "write a goroutine blocking profile to `file`")
471 blockProfileRate = flag.Int("test.blockprofilerate", 1, "set blocking profile `rate` (see runtime.SetBlockProfileRate)")
472 mutexProfile = flag.String("test.mutexprofile", "", "write a mutex contention profile to the named file after execution")
473 mutexProfileFraction = flag.Int("test.mutexprofilefraction", 1, "if >= 0, calls runtime.SetMutexProfileFraction()")
474 panicOnExit0 = flag.Bool("test.paniconexit0", false, "panic on call to os.Exit(0)")
475 traceFile = flag.String("test.trace", "", "write an execution trace to `file`")
476 timeout = flag.Duration("test.timeout", 0, "panic test binary after duration `d` (default 0, timeout disabled)")
477 cpuListStr = flag.String("test.cpu", "", "comma-separated `list` of cpu counts to run each test with")
478 parallel = flag.Int("test.parallel", runtime.GOMAXPROCS(0), "run at most `n` tests in parallel")
479 testlog = flag.String("test.testlogfile", "", "write test action log to `file` (for use only by cmd/go)")
480 shuffle = flag.String("test.shuffle", "off", "randomize the execution order of tests and benchmarks")
481 fullPath = flag.Bool("test.fullpath", false, "show full file names in error messages")
482
483 initBenchmarkFlags()
484 initFuzzFlags()
485 }
486
487 var (
488
489 short *bool
490 failFast *bool
491 outputDir *string
492 artifacts *bool
493 chatty chattyFlag
494 count *uint
495 coverProfile *string
496 gocoverdir *string
497 matchList *string
498 match *string
499 skip *string
500 memProfile *string
501 memProfileRate *int
502 cpuProfile *string
503 blockProfile *string
504 blockProfileRate *int
505 mutexProfile *string
506 mutexProfileFraction *int
507 panicOnExit0 *bool
508 traceFile *string
509 timeout *time.Duration
510 cpuListStr *string
511 parallel *int
512 shuffle *string
513 testlog *string
514 fullPath *bool
515
516 haveExamples bool
517
518 cpuList []int
519 testlogFile *os.File
520 artifactDir string
521
522 numFailed atomic.Uint32
523
524 running sync.Map
525 )
526
527 type chattyFlag struct {
528 on bool
529 json bool
530 }
531
532 func (*chattyFlag) IsBoolFlag() bool { return true }
533
534 func (f *chattyFlag) Set(arg string) error {
535 switch arg {
536 default:
537 return fmt.Errorf("invalid flag -test.v=%s", arg)
538 case "true", "test2json":
539 f.on = true
540 f.json = arg == "test2json"
541 case "false":
542 f.on = false
543 f.json = false
544 }
545 return nil
546 }
547
548 func (f *chattyFlag) String() string {
549 if f.json {
550 return "test2json"
551 }
552 if f.on {
553 return "true"
554 }
555 return "false"
556 }
557
558 func (f *chattyFlag) Get() any {
559 if f.json {
560 return "test2json"
561 }
562 return f.on
563 }
564
565 const (
566 markFraming byte = 'V' &^ '@'
567 markErrBegin byte = 'O' &^ '@'
568 markErrEnd byte = 'N' &^ '@'
569 markEscape byte = '[' &^ '@'
570 )
571
572 func (f *chattyFlag) prefix() string {
573 if f.json {
574 return string(markFraming)
575 }
576 return ""
577 }
578
579 type chattyPrinter struct {
580 w io.Writer
581 lastNameMu sync.Mutex
582 lastName string
583 json bool
584 }
585
586 func newChattyPrinter(w io.Writer) *chattyPrinter {
587 return &chattyPrinter{w: w, json: chatty.json}
588 }
589
590
591
592
593
594 func (p *chattyPrinter) prefix() string {
595 if p != nil && p.json {
596 return string(markFraming)
597 }
598 return ""
599 }
600
601
602
603
604 func (p *chattyPrinter) Updatef(testName, format string, args ...any) {
605 p.lastNameMu.Lock()
606 defer p.lastNameMu.Unlock()
607
608
609
610
611
612 p.lastName = testName
613 fmt.Fprintf(p.w, p.prefix()+format, args...)
614 }
615
616
617
618 func (p *chattyPrinter) Printf(testName, format string, args ...any) {
619 p.lastNameMu.Lock()
620 defer p.lastNameMu.Unlock()
621
622 if p.lastName == "" {
623 p.lastName = testName
624 } else if p.lastName != testName {
625 fmt.Fprintf(p.w, "%s=== NAME %s\n", p.prefix(), testName)
626 p.lastName = testName
627 }
628
629 fmt.Fprintf(p.w, format, args...)
630 }
631
632 type stringWriter interface {
633 io.Writer
634 io.StringWriter
635 }
636
637
638 type escapeWriter struct {
639 w stringWriter
640 }
641
642 func (w escapeWriter) WriteString(s string) (int, error) {
643 return w.Write([]byte(s))
644 }
645
646 func (w escapeWriter) Write(p []byte) (int, error) {
647 var n, m int
648 var err error
649 for len(p) > 0 {
650 i := w.nextMark(p)
651 if i < 0 {
652 break
653 }
654
655 m, err = w.w.Write(p[:i])
656 n += m
657 if err != nil {
658 break
659 }
660
661 m, err = w.w.Write([]byte{markEscape, p[i]})
662 if err != nil {
663 break
664 }
665 if m != 2 {
666 return n, fmt.Errorf("short write")
667 }
668 n++
669 p = p[i+1:]
670 }
671 m, err = w.w.Write(p)
672 n += m
673 return n, err
674 }
675
676 func (escapeWriter) nextMark(p []byte) int {
677 for i, b := range p {
678 switch b {
679 case markFraming, markErrBegin, markErrEnd, markEscape:
680 return i
681 }
682 }
683 return -1
684 }
685
686
687
688 const maxStackLen = 50
689
690
691
692 type common struct {
693 mu sync.RWMutex
694 output []byte
695 w io.Writer
696 o *outputWriter
697 ran bool
698 failed bool
699 skipped bool
700 done bool
701 helperPCs map[uintptr]struct{}
702 helperNames map[string]struct{}
703 cleanups []func()
704 cleanupName string
705 cleanupPc []uintptr
706 finished bool
707 inFuzzFn bool
708 isSynctest bool
709
710 chatty *chattyPrinter
711 bench bool
712 hasSub atomic.Bool
713 cleanupStarted atomic.Bool
714 runner string
715 isParallel bool
716
717 parent *common
718 level int
719 creator []uintptr
720 modulePath string
721 importPath string
722 name string
723 start highPrecisionTime
724 duration time.Duration
725 barrier chan bool
726 signal chan bool
727 sub []*T
728
729 lastRaceErrors atomic.Int64
730 raceErrorLogged atomic.Bool
731
732 tempDirMu sync.Mutex
733 tempDir string
734 tempDirErr error
735 tempDirSeq int32
736
737 artifactDirOnce sync.Once
738 artifactDir string
739 artifactDirErr error
740
741 ctx context.Context
742 cancelCtx context.CancelFunc
743 }
744
745
746 func Short() bool {
747 if short == nil {
748 panic("testing: Short called before Init")
749 }
750
751 if !flag.Parsed() {
752 panic("testing: Short called before Parse")
753 }
754
755 return *short
756 }
757
758
759
760
761
762
763
764
765 var testBinary = "0"
766
767
768
769
770 func Testing() bool {
771 return testBinary == "1"
772 }
773
774
775
776
777 func CoverMode() string {
778 return cover.mode
779 }
780
781
782 func Verbose() bool {
783
784 if !flag.Parsed() {
785 panic("testing: Verbose called before Parse")
786 }
787 return chatty.on
788 }
789
790 func (c *common) checkFuzzFn(name string) {
791 if c.inFuzzFn {
792 panic(fmt.Sprintf("testing: f.%s was called inside the fuzz target, use t.%s instead", name, name))
793 }
794 }
795
796
797
798
799
800
801 func (c *common) frameSkip(skip int) runtime.Frame {
802
803
804 shouldUnlock := false
805 defer func() {
806 if shouldUnlock {
807 c.mu.Unlock()
808 }
809 }()
810 var pc [maxStackLen]uintptr
811
812
813 n := runtime.Callers(skip+2, pc[:])
814 if n == 0 {
815 panic("testing: zero callers found")
816 }
817 frames := runtime.CallersFrames(pc[:n])
818 var firstFrame, prevFrame, frame runtime.Frame
819 skipRange := false
820 for more := true; more; prevFrame = frame {
821 frame, more = frames.Next()
822 if skipRange {
823
824
825 skipRange = false
826 continue
827 }
828 if frame.Function == "runtime.gopanic" {
829 continue
830 }
831 if frame.Function == c.cleanupName {
832 frames = runtime.CallersFrames(c.cleanupPc)
833 continue
834 }
835 if firstFrame.PC == 0 {
836 firstFrame = frame
837 }
838 if frame.Function == c.runner {
839
840
841
842
843
844
845 if c.level > 1 {
846 frames = runtime.CallersFrames(c.creator)
847 parent := c.parent
848
849
850
851 if shouldUnlock {
852 c.mu.Unlock()
853 }
854 c = parent
855
856
857
858 shouldUnlock = true
859 c.mu.Lock()
860 continue
861 }
862 return prevFrame
863 }
864
865 if c.helperNames == nil {
866 c.helperNames = make(map[string]struct{})
867 for pc := range c.helperPCs {
868 c.helperNames[pcToName(pc)] = struct{}{}
869 }
870 }
871
872 fnName := frame.Function
873
874 const rangeSuffix = "-range"
875 if suffixIdx := strings.LastIndex(fnName, rangeSuffix); suffixIdx > 0 {
876 ok := true
877 for i := suffixIdx + len(rangeSuffix); i < len(fnName); i++ {
878 if fnName[i] < '0' || fnName[i] > '9' {
879 ok = false
880 break
881 }
882 }
883 if ok {
884 fnName = fnName[:suffixIdx]
885 skipRange = true
886 }
887 }
888
889 if _, ok := c.helperNames[fnName]; !ok {
890
891 return frame
892 }
893 }
894 return firstFrame
895 }
896
897
898
899 func (c *common) flushToParent(testName, format string, args ...any) {
900 p := c.parent
901 p.mu.Lock()
902 defer p.mu.Unlock()
903
904 c.mu.Lock()
905 defer c.mu.Unlock()
906
907 if len(c.output) > 0 {
908
909
910
911 format += "%s"
912 args = append(args[:len(args):len(args)], c.output)
913 c.output = c.output[:0]
914 }
915
916 if c.chatty != nil && (p.w == c.chatty.w || c.chatty.json) {
917
918
919
920
921
922
923
924
925
926
927
928
929
930 c.chatty.Updatef(testName, format, args...)
931 } else {
932
933
934 fmt.Fprintf(p.w, c.chatty.prefix()+format, args...)
935 }
936 }
937
938 type indenter struct {
939 c *common
940 }
941
942 const indent = " "
943
944 func (w indenter) Write(b []byte) (n int, err error) {
945 n = len(b)
946 for len(b) > 0 {
947 end := bytes.IndexByte(b, '\n')
948 if end == -1 {
949 end = len(b)
950 } else {
951 end++
952 }
953
954
955 line := b[:end]
956 if line[0] == markFraming {
957 w.c.output = append(w.c.output, markFraming)
958 line = line[1:]
959 }
960 w.c.output = append(w.c.output, indent...)
961 w.c.output = append(w.c.output, line...)
962 b = b[end:]
963 }
964 return
965 }
966
967
968 func fmtDuration(d time.Duration) string {
969 return fmt.Sprintf("%.2fs", d.Seconds())
970 }
971
972
973 type TB interface {
974 ArtifactDir() string
975 Attr(key, value string)
976 Cleanup(func())
977 Error(args ...any)
978 Errorf(format string, args ...any)
979 Fail()
980 FailNow()
981 Failed() bool
982 Fatal(args ...any)
983 Fatalf(format string, args ...any)
984 Helper()
985 Log(args ...any)
986 Logf(format string, args ...any)
987 Name() string
988 Setenv(key, value string)
989 Chdir(dir string)
990 Skip(args ...any)
991 SkipNow()
992 Skipf(format string, args ...any)
993 Skipped() bool
994 TempDir() string
995 Context() context.Context
996 Output() io.Writer
997
998
999
1000
1001 private()
1002 }
1003
1004 var (
1005 _ TB = (*T)(nil)
1006 _ TB = (*B)(nil)
1007 )
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018 type T struct {
1019 common
1020 denyParallel bool
1021 tstate *testState
1022 }
1023
1024 func (c *common) private() {}
1025
1026
1027
1028
1029
1030
1031 func (c *common) Name() string {
1032 return c.name
1033 }
1034
1035 func (c *common) setRan() {
1036 if c.parent != nil {
1037 c.parent.setRan()
1038 }
1039 c.mu.Lock()
1040 defer c.mu.Unlock()
1041 c.ran = true
1042 }
1043
1044
1045 func (c *common) Fail() {
1046 if c.parent != nil {
1047 c.parent.Fail()
1048 }
1049 c.mu.Lock()
1050 defer c.mu.Unlock()
1051
1052 if c.done {
1053 panic("Fail in goroutine after " + c.name + " has completed")
1054 }
1055 c.failed = true
1056 }
1057
1058
1059 func (c *common) Failed() bool {
1060 c.mu.RLock()
1061 defer c.mu.RUnlock()
1062
1063 if !c.done && int64(race.Errors()) > c.lastRaceErrors.Load() {
1064 c.mu.RUnlock()
1065 c.checkRaces()
1066 c.mu.RLock()
1067 }
1068
1069 return c.failed
1070 }
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080 func (c *common) FailNow() {
1081 c.checkFuzzFn("FailNow")
1082 c.Fail()
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103 c.mu.Lock()
1104 c.finished = true
1105 c.mu.Unlock()
1106 runtime.Goexit()
1107 }
1108
1109
1110
1111
1112 func (c *common) log(s string, isErr bool) {
1113 s = strings.TrimSuffix(s, "\n")
1114
1115
1116
1117 s = strings.ReplaceAll(s, "\n", "\n"+indent)
1118 s += "\n"
1119
1120 n := c.destination()
1121 if n == nil {
1122
1123 panic("Log in goroutine after " + c.name + " has completed: " + s)
1124 }
1125
1126
1127
1128 s = n.callSite(3) + s
1129
1130
1131 n.flushPartial()
1132
1133 n.o.write([]byte(s), isErr)
1134 }
1135
1136
1137
1138 func (c *common) destination() *common {
1139 c.mu.Lock()
1140 defer c.mu.Unlock()
1141
1142 if !c.done && !c.isSynctest {
1143 return c
1144 }
1145 for parent := c.parent; parent != nil; parent = parent.parent {
1146 parent.mu.Lock()
1147 defer parent.mu.Unlock()
1148 if !parent.done {
1149 return parent
1150 }
1151 }
1152 return nil
1153 }
1154
1155
1156 func (c *common) callSite(skip int) string {
1157 c.mu.Lock()
1158 defer c.mu.Unlock()
1159
1160 frame := c.frameSkip(skip)
1161 file := frame.File
1162 line := frame.Line
1163 if file != "" {
1164 if *fullPath {
1165
1166 } else {
1167 file = filepath.Base(file)
1168 }
1169 } else {
1170 file = "???"
1171 }
1172 if line == 0 {
1173 line = 1
1174 }
1175
1176 return fmt.Sprintf("%s:%d: ", file, line)
1177 }
1178
1179
1180 func (c *common) flushPartial() {
1181 partial := func() bool {
1182 c.mu.Lock()
1183 defer c.mu.Unlock()
1184 return (c.o != nil) && (len(c.o.partial) > 0)
1185 }
1186
1187 if partial() {
1188 c.o.Write([]byte("\n"))
1189 }
1190 }
1191
1192
1193
1194
1195
1196
1197
1198 func (c *common) Output() io.Writer {
1199 c.checkFuzzFn("Output")
1200 n := c.destination()
1201 if n == nil {
1202 panic("Output called after " + c.name + " has completed")
1203 }
1204 return n.o
1205 }
1206
1207
1208 func (c *common) setOutputWriter() {
1209 c.o = &outputWriter{c: c}
1210 }
1211
1212
1213 type outputWriter struct {
1214 c *common
1215 partial []byte
1216 }
1217
1218
1219
1220 func (o *outputWriter) Write(p []byte) (int, error) {
1221 return o.write(p, false)
1222 }
1223
1224 func (o *outputWriter) write(p []byte, isErr bool) (int, error) {
1225
1226
1227 if o == nil || o.c == nil {
1228 return 0, nil
1229 }
1230 if o.c.destination() == nil {
1231 panic("Write called after " + o.c.name + " has completed")
1232 }
1233
1234 o.c.mu.Lock()
1235 defer o.c.mu.Unlock()
1236
1237
1238 lines := bytes.SplitAfter(p, []byte("\n"))
1239 last := len(lines) - 1
1240 for i, line := range lines[:last] {
1241
1242 if i == 0 && len(o.partial) > 0 {
1243 line = slices.Concat(o.partial, line)
1244 o.partial = o.partial[:0]
1245 }
1246 o.writeLine(line, isErr && i == 0, isErr && i == last-1)
1247 }
1248
1249 o.partial = append(o.partial, lines[last]...)
1250
1251 return len(p), nil
1252 }
1253
1254
1255 func (o *outputWriter) writeLine(b []byte, errBegin, errEnd bool) {
1256 if o.c.done || (o.c.chatty == nil) {
1257 o.c.output = append(o.c.output, indent...)
1258 o.c.output = append(o.c.output, b...)
1259 return
1260 }
1261
1262
1263 if o.c.chatty.json {
1264 b = escapeMarkers(b)
1265 }
1266
1267
1268 var strErrBegin, strErrEnd string
1269 if errBegin && o.c.chatty.json {
1270 strErrBegin = string(markErrBegin)
1271 }
1272
1273
1274
1275
1276 var c []byte
1277 if errEnd && o.c.chatty.json {
1278 i := len(b)
1279 if len(b) > 0 && b[i-1] == '\n' {
1280 b, c = b[:i-1], b[i-1:]
1281 }
1282 strErrEnd = string(markErrEnd)
1283 }
1284
1285 if o.c.bench {
1286
1287
1288 fmt.Printf("%s%s%s%s%s", strErrBegin, indent, b, strErrEnd, c)
1289 } else {
1290 o.c.chatty.Printf(o.c.name, "%s%s%s%s%s", strErrBegin, indent, b, strErrEnd, c)
1291 }
1292 }
1293
1294 func escapeMarkers(b []byte) []byte {
1295 j := nextMark(b)
1296 if j < 0 {
1297
1298 return b
1299 }
1300
1301 c := make([]byte, 0, len(b)+10)
1302 i := 0
1303 for i < len(b) && j >= i {
1304 if j > i {
1305 c = append(c, b[i:j]...)
1306 }
1307 c = append(c, markEscape, b[j])
1308 i = j + 1
1309 j = i + nextMark(b[i:])
1310 }
1311 if i < len(b) {
1312 c = append(c, b[i:]...)
1313 }
1314 return c
1315 }
1316
1317 func nextMark(b []byte) int {
1318 for i, b := range b {
1319 switch b {
1320 case markFraming, markEscape, markErrBegin, markErrEnd:
1321 return i
1322 }
1323 }
1324 return -1
1325 }
1326
1327
1328
1329
1330
1331
1332 func (c *common) Log(args ...any) {
1333 c.checkFuzzFn("Log")
1334 c.log(fmt.Sprintln(args...), false)
1335 }
1336
1337
1338
1339
1340
1341
1342
1343 func (c *common) Logf(format string, args ...any) {
1344 c.checkFuzzFn("Logf")
1345 c.log(fmt.Sprintf(format, args...), false)
1346 }
1347
1348
1349 func (c *common) Error(args ...any) {
1350 c.checkFuzzFn("Error")
1351 c.log(fmt.Sprintln(args...), true)
1352 c.Fail()
1353 }
1354
1355
1356 func (c *common) Errorf(format string, args ...any) {
1357 c.checkFuzzFn("Errorf")
1358 c.log(fmt.Sprintf(format, args...), true)
1359 c.Fail()
1360 }
1361
1362
1363 func (c *common) Fatal(args ...any) {
1364 c.checkFuzzFn("Fatal")
1365 c.log(fmt.Sprintln(args...), true)
1366 c.FailNow()
1367 }
1368
1369
1370 func (c *common) Fatalf(format string, args ...any) {
1371 c.checkFuzzFn("Fatalf")
1372 c.log(fmt.Sprintf(format, args...), true)
1373 c.FailNow()
1374 }
1375
1376
1377 func (c *common) Skip(args ...any) {
1378 c.checkFuzzFn("Skip")
1379 c.log(fmt.Sprintln(args...), false)
1380 c.SkipNow()
1381 }
1382
1383
1384 func (c *common) Skipf(format string, args ...any) {
1385 c.checkFuzzFn("Skipf")
1386 c.log(fmt.Sprintf(format, args...), false)
1387 c.SkipNow()
1388 }
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398 func (c *common) SkipNow() {
1399 c.checkFuzzFn("SkipNow")
1400 c.mu.Lock()
1401 c.skipped = true
1402 c.finished = true
1403 c.mu.Unlock()
1404 runtime.Goexit()
1405 }
1406
1407
1408 func (c *common) Skipped() bool {
1409 c.mu.RLock()
1410 defer c.mu.RUnlock()
1411 return c.skipped
1412 }
1413
1414
1415
1416
1417 func (c *common) Helper() {
1418 if c.isSynctest {
1419 c = c.parent
1420 }
1421 c.mu.Lock()
1422 defer c.mu.Unlock()
1423 if c.helperPCs == nil {
1424 c.helperPCs = make(map[uintptr]struct{})
1425 }
1426
1427 var pc [1]uintptr
1428 n := runtime.Callers(2, pc[:])
1429 if n == 0 {
1430 panic("testing: zero callers found")
1431 }
1432 if _, found := c.helperPCs[pc[0]]; !found {
1433 c.helperPCs[pc[0]] = struct{}{}
1434 c.helperNames = nil
1435 }
1436 }
1437
1438
1439
1440
1441 func (c *common) Cleanup(f func()) {
1442 c.checkFuzzFn("Cleanup")
1443 var pc [maxStackLen]uintptr
1444
1445 n := runtime.Callers(2, pc[:])
1446 cleanupPc := pc[:n]
1447
1448 fn := func() {
1449 defer func() {
1450 c.mu.Lock()
1451 defer c.mu.Unlock()
1452 c.cleanupName = ""
1453 c.cleanupPc = nil
1454 }()
1455
1456 name := callerName(0)
1457 c.mu.Lock()
1458 c.cleanupName = name
1459 c.cleanupPc = cleanupPc
1460 c.mu.Unlock()
1461
1462 f()
1463 }
1464
1465 c.mu.Lock()
1466 defer c.mu.Unlock()
1467 c.cleanups = append(c.cleanups, fn)
1468 }
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478 func (c *common) ArtifactDir() string {
1479 c.checkFuzzFn("ArtifactDir")
1480 c.artifactDirOnce.Do(func() {
1481 c.artifactDir, c.artifactDirErr = c.makeArtifactDir()
1482 })
1483 if c.artifactDirErr != nil {
1484 c.Fatalf("ArtifactDir: %v", c.artifactDirErr)
1485 }
1486 return c.artifactDir
1487 }
1488
1489 func hashString(s string) (h uint64) {
1490
1491 for i := 0; i < len(s); i++ {
1492 h ^= uint64(s[i])
1493 h *= 1099511628211
1494 }
1495 return
1496 }
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506 func (c *common) makeArtifactDir() (string, error) {
1507 if !*artifacts {
1508 return c.makeTempDir()
1509 }
1510
1511 artifactBase := filepath.Join(artifactDir, c.relativeArtifactBase())
1512 if err := os.MkdirAll(artifactBase, 0o777); err != nil {
1513 return "", err
1514 }
1515 dir, err := os.MkdirTemp(artifactBase, "")
1516 if err != nil {
1517 return "", err
1518 }
1519 if c.chatty != nil {
1520 c.chatty.Updatef(c.name, "=== ARTIFACTS %s %v\n", c.name, dir)
1521 }
1522 return dir, nil
1523 }
1524
1525 func (c *common) relativeArtifactBase() string {
1526
1527
1528 const maxNameSize = 64
1529 name := strings.ReplaceAll(c.name, "/", "__")
1530 if len(name) > maxNameSize {
1531 h := fmt.Sprintf("%0x", hashString(name))
1532 name = name[:maxNameSize-len(h)] + h
1533 }
1534
1535
1536
1537 pkg := strings.TrimPrefix(c.importPath, c.modulePath)
1538
1539 pkg = strings.TrimPrefix(pkg, "/")
1540
1541 base := name
1542 if pkg != "" {
1543
1544
1545 base = pkg + "/" + name
1546 }
1547 base = removeSymbolsExcept(base, "!#$%&()+,-.=@^_{}~ /")
1548 base, err := filepath.Localize(base)
1549 if err != nil {
1550
1551
1552 base = ""
1553 }
1554
1555 return base
1556 }
1557
1558 func removeSymbolsExcept(s, allowed string) string {
1559 mapper := func(r rune) rune {
1560 if unicode.IsLetter(r) ||
1561 unicode.IsNumber(r) ||
1562 strings.ContainsRune(allowed, r) {
1563 return r
1564 }
1565 return -1
1566 }
1567 return strings.Map(mapper, s)
1568 }
1569
1570
1571
1572
1573
1574
1575
1576
1577 func (c *common) TempDir() string {
1578 c.checkFuzzFn("TempDir")
1579 dir, err := c.makeTempDir()
1580 if err != nil {
1581 c.Fatalf("TempDir: %v", err)
1582 }
1583 return dir
1584 }
1585
1586 func (c *common) makeTempDir() (string, error) {
1587
1588
1589 c.tempDirMu.Lock()
1590 var nonExistent bool
1591 if c.tempDir == "" {
1592 nonExistent = true
1593 } else {
1594 _, err := os.Stat(c.tempDir)
1595 nonExistent = os.IsNotExist(err)
1596 if err != nil && !nonExistent {
1597 return "", err
1598 }
1599 }
1600
1601 if nonExistent {
1602 c.Helper()
1603
1604 pattern := c.Name()
1605
1606
1607 pattern = pattern[:min(len(pattern), 64)]
1608
1609
1610
1611
1612 const allowed = "!#$%&()+,-.=@^_{}~ "
1613 pattern = removeSymbolsExcept(pattern, allowed)
1614
1615 c.tempDir, c.tempDirErr = os.MkdirTemp(os.Getenv("GOTMPDIR"), pattern)
1616 if c.tempDirErr == nil {
1617 c.Cleanup(func() {
1618 if err := removeAll(c.tempDir); err != nil {
1619 c.Errorf("TempDir RemoveAll cleanup: %v", err)
1620 }
1621 })
1622 }
1623 }
1624
1625 if c.tempDirErr == nil {
1626 c.tempDirSeq++
1627 }
1628 seq := c.tempDirSeq
1629 c.tempDirMu.Unlock()
1630
1631 if c.tempDirErr != nil {
1632 return "", c.tempDirErr
1633 }
1634
1635 dir := fmt.Sprintf("%s%c%03d", c.tempDir, os.PathSeparator, seq)
1636 if err := os.Mkdir(dir, 0o777); err != nil {
1637 return "", err
1638 }
1639 return dir, nil
1640 }
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651 func removeAll(path string) error {
1652 const arbitraryTimeout = 2 * time.Second
1653 var (
1654 start time.Time
1655 nextSleep = 1 * time.Millisecond
1656 )
1657 for {
1658 err := os.RemoveAll(path)
1659 if !isWindowsRetryable(err) {
1660 return err
1661 }
1662 if start.IsZero() {
1663 start = time.Now()
1664 } else if d := time.Since(start) + nextSleep; d >= arbitraryTimeout {
1665 return err
1666 }
1667 time.Sleep(nextSleep)
1668 nextSleep += time.Duration(rand.Int63n(int64(nextSleep)))
1669 }
1670 }
1671
1672
1673
1674
1675
1676
1677
1678 func (c *common) Setenv(key, value string) {
1679 c.checkFuzzFn("Setenv")
1680 prevValue, ok := os.LookupEnv(key)
1681
1682 if err := os.Setenv(key, value); err != nil {
1683 c.Fatalf("cannot set environment variable: %v", err)
1684 }
1685
1686 if ok {
1687 c.Cleanup(func() {
1688 os.Setenv(key, prevValue)
1689 })
1690 } else {
1691 c.Cleanup(func() {
1692 os.Unsetenv(key)
1693 })
1694 }
1695 }
1696
1697
1698
1699
1700
1701
1702
1703 func (c *common) Chdir(dir string) {
1704 c.checkFuzzFn("Chdir")
1705 oldwd, err := os.Open(".")
1706 if err != nil {
1707 c.Fatal(err)
1708 }
1709 if err := os.Chdir(dir); err != nil {
1710 c.Fatal(err)
1711 }
1712
1713
1714
1715 switch runtime.GOOS {
1716 case "windows", "plan9":
1717
1718 default:
1719 if !filepath.IsAbs(dir) {
1720 dir, err = os.Getwd()
1721 if err != nil {
1722 c.Fatal(err)
1723 }
1724 }
1725 c.Setenv("PWD", dir)
1726 }
1727 c.Cleanup(func() {
1728 err := oldwd.Chdir()
1729 oldwd.Close()
1730 if err != nil {
1731
1732
1733
1734 panic("testing.Chdir: " + err.Error())
1735 }
1736 })
1737 }
1738
1739
1740
1741
1742
1743
1744 func (c *common) Context() context.Context {
1745 c.checkFuzzFn("Context")
1746 return c.ctx
1747 }
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759 func (c *common) Attr(key, value string) {
1760 if strings.ContainsFunc(key, unicode.IsSpace) {
1761 c.Errorf("disallowed whitespace in attribute key %q", key)
1762 return
1763 }
1764 if strings.ContainsAny(value, "\r\n") {
1765 c.Errorf("disallowed newline in attribute value %q", value)
1766 return
1767 }
1768 if c.chatty == nil {
1769 return
1770 }
1771 c.chatty.Updatef(c.name, "=== ATTR %s %v %v\n", c.name, key, value)
1772 }
1773
1774
1775 type panicHandling int
1776
1777 const (
1778 normalPanic panicHandling = iota
1779 recoverAndReturnPanic
1780 )
1781
1782
1783
1784
1785 func (c *common) runCleanup(ph panicHandling) (panicVal any) {
1786 c.cleanupStarted.Store(true)
1787 defer c.cleanupStarted.Store(false)
1788
1789 if ph == recoverAndReturnPanic {
1790 defer func() {
1791 panicVal = recover()
1792 }()
1793 }
1794
1795
1796
1797 defer func() {
1798 c.mu.Lock()
1799 recur := len(c.cleanups) > 0
1800 c.mu.Unlock()
1801 if recur {
1802 c.runCleanup(normalPanic)
1803 }
1804 }()
1805
1806 if c.cancelCtx != nil {
1807 c.cancelCtx()
1808 }
1809
1810 for {
1811 var cleanup func()
1812 c.mu.Lock()
1813 if len(c.cleanups) > 0 {
1814 last := len(c.cleanups) - 1
1815 cleanup = c.cleanups[last]
1816 c.cleanups = c.cleanups[:last]
1817 }
1818 c.mu.Unlock()
1819 if cleanup == nil {
1820 return nil
1821 }
1822 cleanup()
1823 }
1824 }
1825
1826
1827
1828
1829
1830
1831 func (c *common) resetRaces() {
1832 if c.parent == nil {
1833 c.lastRaceErrors.Store(int64(race.Errors()))
1834 } else {
1835 c.lastRaceErrors.Store(c.parent.checkRaces())
1836 }
1837 }
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849 func (c *common) checkRaces() (raceErrors int64) {
1850 raceErrors = int64(race.Errors())
1851 for {
1852 last := c.lastRaceErrors.Load()
1853 if raceErrors <= last {
1854
1855 return raceErrors
1856 }
1857 if c.lastRaceErrors.CompareAndSwap(last, raceErrors) {
1858 break
1859 }
1860 }
1861
1862 if c.raceErrorLogged.CompareAndSwap(false, true) {
1863
1864
1865
1866
1867 c.Errorf("race detected during execution of test")
1868 }
1869
1870
1871 parent := c.parent
1872 for parent != nil {
1873 for {
1874 last := parent.lastRaceErrors.Load()
1875 if raceErrors <= last {
1876
1877 return raceErrors
1878 }
1879 if parent.lastRaceErrors.CompareAndSwap(last, raceErrors) {
1880 break
1881 }
1882 }
1883 parent = parent.parent
1884 }
1885
1886 return raceErrors
1887 }
1888
1889
1890
1891 func callerName(skip int) string {
1892 var pc [1]uintptr
1893 n := runtime.Callers(skip+2, pc[:])
1894 if n == 0 {
1895 panic("testing: zero callers found")
1896 }
1897 return pcToName(pc[0])
1898 }
1899
1900 func pcToName(pc uintptr) string {
1901 pcs := []uintptr{pc}
1902 frames := runtime.CallersFrames(pcs)
1903 frame, _ := frames.Next()
1904 return frame.Function
1905 }
1906
1907 const parallelConflict = `testing: test using t.Setenv, t.Chdir, or cryptotest.SetGlobalRandom can not use t.Parallel`
1908
1909
1910
1911
1912
1913
1914 func (t *T) Parallel() {
1915 if t.isParallel {
1916 panic("testing: t.Parallel called multiple times")
1917 }
1918 if t.isSynctest {
1919 panic("testing: t.Parallel called inside synctest bubble")
1920 }
1921 if t.denyParallel {
1922 panic(parallelConflict)
1923 }
1924 if t.parent.barrier == nil {
1925
1926
1927
1928 return
1929 }
1930
1931 t.isParallel = true
1932
1933
1934
1935
1936 t.duration += highPrecisionTimeSince(t.start)
1937
1938
1939 t.parent.sub = append(t.parent.sub, t)
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951 t.checkRaces()
1952
1953 if t.chatty != nil {
1954 t.chatty.Updatef(t.name, "=== PAUSE %s\n", t.name)
1955 }
1956 running.Delete(t.name)
1957
1958 t.signal <- true
1959 <-t.parent.barrier
1960 t.tstate.waitParallel()
1961 parallelStart.Add(1)
1962
1963 if t.chatty != nil {
1964 t.chatty.Updatef(t.name, "=== CONT %s\n", t.name)
1965 }
1966 running.Store(t.name, highPrecisionTimeNow())
1967 t.start = highPrecisionTimeNow()
1968
1969
1970
1971
1972
1973
1974
1975
1976 t.lastRaceErrors.Store(int64(race.Errors()))
1977 }
1978
1979
1980
1981
1982 func checkParallel(t *T) {
1983 t.checkParallel()
1984 }
1985
1986 func (t *T) checkParallel() {
1987
1988
1989
1990
1991
1992 for c := &t.common; c != nil; c = c.parent {
1993 if c.isParallel {
1994 panic(parallelConflict)
1995 }
1996 }
1997
1998 t.denyParallel = true
1999 }
2000
2001
2002
2003
2004
2005
2006
2007 func (t *T) Setenv(key, value string) {
2008 t.checkParallel()
2009 t.common.Setenv(key, value)
2010 }
2011
2012
2013
2014
2015
2016
2017
2018 func (t *T) Chdir(dir string) {
2019 t.checkParallel()
2020 t.common.Chdir(dir)
2021 }
2022
2023
2024
2025 type InternalTest struct {
2026 Name string
2027 F func(*T)
2028 }
2029
2030 var errNilPanicOrGoexit = errors.New("test executed panic(nil) or runtime.Goexit")
2031
2032 func tRunner(t *T, fn func(t *T)) {
2033 t.runner = callerName(0)
2034
2035
2036
2037
2038
2039 defer func() {
2040 t.checkRaces()
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050 err := recover()
2051 signal := true
2052
2053 t.mu.RLock()
2054 finished := t.finished
2055 t.mu.RUnlock()
2056 if !finished && err == nil {
2057 err = errNilPanicOrGoexit
2058 for p := t.parent; p != nil; p = p.parent {
2059 p.mu.RLock()
2060 finished = p.finished
2061 p.mu.RUnlock()
2062 if finished {
2063 if !t.isParallel {
2064 t.Errorf("%v: subtest may have called FailNow on a parent test", err)
2065 err = nil
2066 }
2067 signal = false
2068 break
2069 }
2070 }
2071 }
2072
2073 if err != nil && t.tstate.isFuzzing {
2074 prefix := "panic: "
2075 if err == errNilPanicOrGoexit {
2076 prefix = ""
2077 }
2078 t.Errorf("%s%s\n%s\n", prefix, err, string(debug.Stack()))
2079 t.mu.Lock()
2080 t.finished = true
2081 t.mu.Unlock()
2082 err = nil
2083 }
2084
2085
2086
2087 didPanic := false
2088 defer func() {
2089
2090
2091
2092 if didPanic {
2093 return
2094 }
2095 if err != nil {
2096 panic(err)
2097 }
2098 running.Delete(t.name)
2099 if t.isParallel {
2100 parallelStop.Add(1)
2101 }
2102 t.signal <- signal
2103 }()
2104
2105 doPanic := func(err any) {
2106 t.Fail()
2107 if r := t.runCleanup(recoverAndReturnPanic); r != nil {
2108 t.Logf("cleanup panicked with %v", r)
2109 }
2110
2111
2112 for root := &t.common; !root.isSynctest && root.parent != nil; root = root.parent {
2113 root.mu.Lock()
2114 root.duration += highPrecisionTimeSince(root.start)
2115 d := root.duration
2116 root.mu.Unlock()
2117
2118 root.flushPartial()
2119 root.flushToParent(root.name, "--- FAIL: %s (%s)\n", root.name, fmtDuration(d))
2120 if r := root.parent.runCleanup(recoverAndReturnPanic); r != nil {
2121 fmt.Fprintf(root.parent.w, "cleanup panicked with %v", r)
2122 }
2123 }
2124 didPanic = true
2125 panic(err)
2126 }
2127 if err != nil {
2128 doPanic(err)
2129 }
2130
2131 t.duration += highPrecisionTimeSince(t.start)
2132
2133 if len(t.sub) > 0 {
2134
2135
2136
2137 t.tstate.release()
2138 running.Delete(t.name)
2139
2140
2141 close(t.barrier)
2142
2143 for _, sub := range t.sub {
2144 <-sub.signal
2145 }
2146
2147
2148
2149 cleanupStart := highPrecisionTimeNow()
2150 running.Store(t.name, cleanupStart)
2151 err := t.runCleanup(recoverAndReturnPanic)
2152 t.duration += highPrecisionTimeSince(cleanupStart)
2153 if err != nil {
2154 doPanic(err)
2155 }
2156 t.checkRaces()
2157 if !t.isParallel {
2158
2159 t.tstate.waitParallel()
2160 }
2161 } else if t.isParallel {
2162
2163
2164 t.tstate.release()
2165 }
2166
2167 for root := &t.common; root.parent != nil; root = root.parent {
2168 root.flushPartial()
2169 }
2170
2171
2172
2173
2174 if t.Failed() {
2175 numFailed.Add(1)
2176 }
2177
2178 t.report()
2179
2180
2181
2182 t.done = true
2183 if t.parent != nil && !t.hasSub.Load() {
2184 t.setRan()
2185 }
2186 }()
2187 defer func() {
2188 if len(t.sub) == 0 {
2189 t.runCleanup(normalPanic)
2190 }
2191 }()
2192
2193 t.start = highPrecisionTimeNow()
2194 t.resetRaces()
2195 fn(t)
2196
2197
2198 t.mu.Lock()
2199 t.finished = true
2200 t.mu.Unlock()
2201 }
2202
2203
2204
2205
2206
2207
2208
2209 func (t *T) Run(name string, f func(t *T)) bool {
2210 if t.isSynctest {
2211 panic("testing: t.Run called inside synctest bubble")
2212 }
2213 if t.cleanupStarted.Load() {
2214 panic("testing: t.Run called during t.Cleanup")
2215 }
2216
2217 t.hasSub.Store(true)
2218 testName, ok, _ := t.tstate.match.fullName(&t.common, name)
2219 if !ok || shouldFailFast() {
2220 return true
2221 }
2222
2223
2224
2225 var pc [maxStackLen]uintptr
2226 n := runtime.Callers(2, pc[:])
2227
2228
2229
2230 ctx, cancelCtx := context.WithCancel(context.Background())
2231 t = &T{
2232 common: common{
2233 barrier: make(chan bool),
2234 signal: make(chan bool, 1),
2235 name: testName,
2236 modulePath: t.modulePath,
2237 importPath: t.importPath,
2238 parent: &t.common,
2239 level: t.level + 1,
2240 creator: pc[:n],
2241 chatty: t.chatty,
2242 ctx: ctx,
2243 cancelCtx: cancelCtx,
2244 },
2245 tstate: t.tstate,
2246 }
2247 t.w = indenter{&t.common}
2248 t.setOutputWriter()
2249
2250 if t.chatty != nil {
2251 t.chatty.Updatef(t.name, "=== RUN %s\n", t.name)
2252 }
2253 running.Store(t.name, highPrecisionTimeNow())
2254
2255
2256
2257
2258
2259
2260 go tRunner(t, f)
2261
2262
2263
2264
2265
2266
2267
2268 if !<-t.signal {
2269
2270
2271 runtime.Goexit()
2272 }
2273
2274 if t.chatty != nil && t.chatty.json {
2275 t.chatty.Updatef(t.parent.name, "=== NAME %s\n", t.parent.name)
2276 }
2277 return !t.failed
2278 }
2279
2280
2281
2282
2283
2284 func testingSynctestTest(t *T, f func(*T)) (ok bool) {
2285 if t.cleanupStarted.Load() {
2286 panic("testing: synctest.Run called during t.Cleanup")
2287 }
2288
2289 var pc [maxStackLen]uintptr
2290 n := runtime.Callers(2, pc[:])
2291
2292 ctx, cancelCtx := context.WithCancel(context.Background())
2293 t2 := &T{
2294 common: common{
2295 barrier: make(chan bool),
2296 signal: make(chan bool, 1),
2297 name: t.name,
2298 parent: &t.common,
2299 level: t.level + 1,
2300 creator: pc[:n],
2301 chatty: t.chatty,
2302 ctx: ctx,
2303 cancelCtx: cancelCtx,
2304 isSynctest: true,
2305 },
2306 tstate: t.tstate,
2307 }
2308
2309 go tRunner(t2, f)
2310 if !<-t2.signal {
2311
2312
2313 runtime.Goexit()
2314 }
2315 return !t2.failed
2316 }
2317
2318
2319
2320
2321
2322 func (t *T) Deadline() (deadline time.Time, ok bool) {
2323 if t.isSynctest {
2324
2325
2326
2327 panic("testing: t.Deadline called inside synctest bubble")
2328 }
2329 deadline = t.tstate.deadline
2330 return deadline, !deadline.IsZero()
2331 }
2332
2333
2334
2335 type testState struct {
2336 match *matcher
2337 deadline time.Time
2338
2339
2340
2341
2342
2343 isFuzzing bool
2344
2345 mu sync.Mutex
2346
2347
2348 startParallel chan bool
2349
2350
2351
2352 running int
2353
2354
2355 numWaiting int
2356
2357
2358 maxParallel int
2359 }
2360
2361 func newTestState(maxParallel int, m *matcher) *testState {
2362 return &testState{
2363 match: m,
2364 startParallel: make(chan bool),
2365 maxParallel: maxParallel,
2366 running: 1,
2367 }
2368 }
2369
2370 func (s *testState) waitParallel() {
2371 s.mu.Lock()
2372 if s.running < s.maxParallel {
2373 s.running++
2374 s.mu.Unlock()
2375 return
2376 }
2377 s.numWaiting++
2378 s.mu.Unlock()
2379 <-s.startParallel
2380 }
2381
2382 func (s *testState) release() {
2383 s.mu.Lock()
2384 if s.numWaiting == 0 {
2385 s.running--
2386 s.mu.Unlock()
2387 return
2388 }
2389 s.numWaiting--
2390 s.mu.Unlock()
2391 s.startParallel <- true
2392 }
2393
2394
2395
2396 var errMain = errors.New("testing: unexpected use of func Main")
2397
2398 type matchStringOnly func(pat, str string) (bool, error)
2399
2400 func (f matchStringOnly) MatchString(pat, str string) (bool, error) { return f(pat, str) }
2401 func (f matchStringOnly) StartCPUProfile(w io.Writer) error { return errMain }
2402 func (f matchStringOnly) StopCPUProfile() {}
2403 func (f matchStringOnly) WriteProfileTo(string, io.Writer, int) error { return errMain }
2404 func (f matchStringOnly) ModulePath() string { return "" }
2405 func (f matchStringOnly) ImportPath() string { return "" }
2406 func (f matchStringOnly) StartTestLog(io.Writer) {}
2407 func (f matchStringOnly) StopTestLog() error { return errMain }
2408 func (f matchStringOnly) SetPanicOnExit0(bool) {}
2409 func (f matchStringOnly) CoordinateFuzzing(time.Duration, int64, time.Duration, int64, int, []corpusEntry, []reflect.Type, string, string) error {
2410 return errMain
2411 }
2412 func (f matchStringOnly) RunFuzzWorker(func(corpusEntry) error) error { return errMain }
2413 func (f matchStringOnly) ReadCorpus(string, []reflect.Type) ([]corpusEntry, error) {
2414 return nil, errMain
2415 }
2416 func (f matchStringOnly) CheckCorpus([]any, []reflect.Type) error { return nil }
2417 func (f matchStringOnly) ResetCoverage() {}
2418 func (f matchStringOnly) SnapshotCoverage() {}
2419
2420 func (f matchStringOnly) InitRuntimeCoverage() (mode string, tearDown func(string, string) (string, error), snapcov func() float64) {
2421 return
2422 }
2423
2424
2425
2426
2427
2428
2429
2430 func Main(matchString func(pat, str string) (bool, error), tests []InternalTest, benchmarks []InternalBenchmark, examples []InternalExample) {
2431 os.Exit(MainStart(matchStringOnly(matchString), tests, benchmarks, nil, examples).Run())
2432 }
2433
2434
2435 type M struct {
2436 deps testDeps
2437 tests []InternalTest
2438 benchmarks []InternalBenchmark
2439 fuzzTargets []InternalFuzzTarget
2440 examples []InternalExample
2441
2442 timer *time.Timer
2443 afterOnce sync.Once
2444
2445 numRun int
2446
2447
2448
2449 exitCode int
2450 }
2451
2452
2453
2454
2455
2456 type testDeps interface {
2457 ImportPath() string
2458 ModulePath() string
2459 MatchString(pat, str string) (bool, error)
2460 SetPanicOnExit0(bool)
2461 StartCPUProfile(io.Writer) error
2462 StopCPUProfile()
2463 StartTestLog(io.Writer)
2464 StopTestLog() error
2465 WriteProfileTo(string, io.Writer, int) error
2466 CoordinateFuzzing(time.Duration, int64, time.Duration, int64, int, []corpusEntry, []reflect.Type, string, string) error
2467 RunFuzzWorker(func(corpusEntry) error) error
2468 ReadCorpus(string, []reflect.Type) ([]corpusEntry, error)
2469 CheckCorpus([]any, []reflect.Type) error
2470 ResetCoverage()
2471 SnapshotCoverage()
2472 InitRuntimeCoverage() (mode string, tearDown func(coverprofile string, gocoverdir string) (string, error), snapcov func() float64)
2473 }
2474
2475
2476
2477
2478 func MainStart(deps testDeps, tests []InternalTest, benchmarks []InternalBenchmark, fuzzTargets []InternalFuzzTarget, examples []InternalExample) *M {
2479 registerCover(deps.InitRuntimeCoverage())
2480 Init()
2481 return &M{
2482 deps: deps,
2483 tests: tests,
2484 benchmarks: benchmarks,
2485 fuzzTargets: fuzzTargets,
2486 examples: examples,
2487 }
2488 }
2489
2490 var (
2491 testingTesting bool
2492 realStderr *os.File
2493 )
2494
2495
2496
2497
2498
2499 func (m *M) Run() (code int) {
2500 defer func() {
2501 code = m.exitCode
2502 }()
2503
2504
2505
2506
2507
2508 m.numRun++
2509
2510
2511 if !flag.Parsed() {
2512 flag.Parse()
2513 }
2514
2515 if chatty.json {
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549 realStderr = os.Stderr
2550 os.Stderr = os.Stdout
2551 }
2552
2553 if *parallel < 1 {
2554 fmt.Fprintln(os.Stderr, "testing: -parallel can only be given a positive integer")
2555 flag.Usage()
2556 m.exitCode = 2
2557 return
2558 }
2559 if *matchFuzz != "" && *fuzzCacheDir == "" {
2560 fmt.Fprintln(os.Stderr, "testing: -test.fuzzcachedir must be set if -test.fuzz is set")
2561 flag.Usage()
2562 m.exitCode = 2
2563 return
2564 }
2565
2566 if *matchList != "" {
2567 listTests(m.deps.MatchString, m.tests, m.benchmarks, m.fuzzTargets, m.examples)
2568 m.exitCode = 0
2569 return
2570 }
2571
2572 if *shuffle != "off" {
2573 var n int64
2574 var err error
2575 if *shuffle == "on" {
2576 n = time.Now().UnixNano()
2577 } else {
2578 n, err = strconv.ParseInt(*shuffle, 10, 64)
2579 if err != nil {
2580 fmt.Fprintln(os.Stderr, `testing: -shuffle should be "off", "on", or a valid integer:`, err)
2581 m.exitCode = 2
2582 return
2583 }
2584 }
2585 fmt.Println("-test.shuffle", n)
2586 rng := rand.New(rand.NewSource(n))
2587 rng.Shuffle(len(m.tests), func(i, j int) { m.tests[i], m.tests[j] = m.tests[j], m.tests[i] })
2588 rng.Shuffle(len(m.benchmarks), func(i, j int) { m.benchmarks[i], m.benchmarks[j] = m.benchmarks[j], m.benchmarks[i] })
2589 }
2590
2591 parseCpuList()
2592
2593 m.before()
2594 defer m.after()
2595
2596
2597
2598
2599 if !*isFuzzWorker {
2600 deadline := m.startAlarm()
2601 haveExamples = len(m.examples) > 0
2602 testRan, testOk := runTests(m.deps.ModulePath(), m.deps.ImportPath(), m.deps.MatchString, m.tests, deadline)
2603 fuzzTargetsRan, fuzzTargetsOk := runFuzzTests(m.deps, m.fuzzTargets, deadline)
2604 exampleRan, exampleOk := runExamples(m.deps.MatchString, m.examples)
2605 m.stopAlarm()
2606 if !testRan && !exampleRan && !fuzzTargetsRan && *matchBenchmarks == "" && *matchFuzz == "" {
2607 fmt.Fprintln(os.Stderr, "testing: warning: no tests to run")
2608 if testingTesting && *match != "^$" {
2609
2610
2611
2612
2613
2614 fmt.Print(chatty.prefix(), "FAIL: package testing must run tests\n")
2615 testOk = false
2616 }
2617 }
2618 anyFailed := !testOk || !exampleOk || !fuzzTargetsOk || !runBenchmarks(m.deps.ImportPath(), m.deps.MatchString, m.benchmarks)
2619 if !anyFailed && race.Errors() > 0 {
2620 fmt.Print(chatty.prefix(), "testing: race detected outside of test execution\n")
2621 anyFailed = true
2622 }
2623 if anyFailed {
2624 fmt.Print(chatty.prefix(), "FAIL\n")
2625 m.exitCode = 1
2626 return
2627 }
2628 }
2629
2630 fuzzingOk := runFuzzing(m.deps, m.fuzzTargets)
2631 if !fuzzingOk {
2632 fmt.Print(chatty.prefix(), "FAIL\n")
2633 if *isFuzzWorker {
2634 m.exitCode = fuzzWorkerExitCode
2635 } else {
2636 m.exitCode = 1
2637 }
2638 return
2639 }
2640
2641 m.exitCode = 0
2642 if !*isFuzzWorker {
2643 fmt.Print(chatty.prefix(), "PASS\n")
2644 }
2645 return
2646 }
2647
2648 func (t *T) report() {
2649 if t.parent == nil {
2650 return
2651 }
2652 if t.isSynctest {
2653 return
2654 }
2655 dstr := fmtDuration(t.duration)
2656 format := "--- %s: %s (%s)\n"
2657 if t.Failed() {
2658 t.flushToParent(t.name, format, "FAIL", t.name, dstr)
2659 } else if t.chatty != nil {
2660 if t.Skipped() {
2661 t.flushToParent(t.name, format, "SKIP", t.name, dstr)
2662 } else {
2663 t.flushToParent(t.name, format, "PASS", t.name, dstr)
2664 }
2665 }
2666 }
2667
2668 func listTests(matchString func(pat, str string) (bool, error), tests []InternalTest, benchmarks []InternalBenchmark, fuzzTargets []InternalFuzzTarget, examples []InternalExample) {
2669 if _, err := matchString(*matchList, "non-empty"); err != nil {
2670 fmt.Fprintf(os.Stderr, "testing: invalid regexp in -test.list (%q): %s\n", *matchList, err)
2671 os.Exit(1)
2672 }
2673
2674 for _, test := range tests {
2675 if ok, _ := matchString(*matchList, test.Name); ok {
2676 fmt.Println(test.Name)
2677 }
2678 }
2679 for _, bench := range benchmarks {
2680 if ok, _ := matchString(*matchList, bench.Name); ok {
2681 fmt.Println(bench.Name)
2682 }
2683 }
2684 for _, fuzzTarget := range fuzzTargets {
2685 if ok, _ := matchString(*matchList, fuzzTarget.Name); ok {
2686 fmt.Println(fuzzTarget.Name)
2687 }
2688 }
2689 for _, example := range examples {
2690 if ok, _ := matchString(*matchList, example.Name); ok {
2691 fmt.Println(example.Name)
2692 }
2693 }
2694 }
2695
2696
2697
2698 func RunTests(matchString func(pat, str string) (bool, error), tests []InternalTest) (ok bool) {
2699 var deadline time.Time
2700 if *timeout > 0 {
2701 deadline = time.Now().Add(*timeout)
2702 }
2703 ran, ok := runTests("", "", matchString, tests, deadline)
2704 if !ran && !haveExamples {
2705 fmt.Fprintln(os.Stderr, "testing: warning: no tests to run")
2706 }
2707 return ok
2708 }
2709
2710 func runTests(modulePath, importPath string, matchString func(pat, str string) (bool, error), tests []InternalTest, deadline time.Time) (ran, ok bool) {
2711 ok = true
2712 for _, procs := range cpuList {
2713 runtime.GOMAXPROCS(procs)
2714 for i := uint(0); i < *count; i++ {
2715 if shouldFailFast() {
2716 break
2717 }
2718 if i > 0 && !ran {
2719
2720
2721
2722 break
2723 }
2724 ctx, cancelCtx := context.WithCancel(context.Background())
2725 tstate := newTestState(*parallel, newMatcher(matchString, *match, "-test.run", *skip))
2726 tstate.deadline = deadline
2727 t := &T{
2728 common: common{
2729 signal: make(chan bool, 1),
2730 barrier: make(chan bool),
2731 w: os.Stdout,
2732 ctx: ctx,
2733 cancelCtx: cancelCtx,
2734 modulePath: modulePath,
2735 importPath: importPath,
2736 },
2737 tstate: tstate,
2738 }
2739 if Verbose() {
2740 t.chatty = newChattyPrinter(t.w)
2741 }
2742 tRunner(t, func(t *T) {
2743 for _, test := range tests {
2744 t.Run(test.Name, test.F)
2745 }
2746 })
2747 select {
2748 case <-t.signal:
2749 default:
2750 panic("internal error: tRunner exited without sending on t.signal")
2751 }
2752 ok = ok && !t.Failed()
2753 ran = ran || t.ran
2754 }
2755 }
2756 return ran, ok
2757 }
2758
2759
2760 func (m *M) before() {
2761 if *memProfileRate > 0 {
2762 runtime.MemProfileRate = *memProfileRate
2763 }
2764 if *cpuProfile != "" {
2765 f, err := os.Create(toOutputDir(*cpuProfile))
2766 if err != nil {
2767 fmt.Fprintf(os.Stderr, "testing: %s\n", err)
2768 return
2769 }
2770 if err := m.deps.StartCPUProfile(f); err != nil {
2771 fmt.Fprintf(os.Stderr, "testing: can't start cpu profile: %s\n", err)
2772 f.Close()
2773 return
2774 }
2775
2776 }
2777 if *traceFile != "" {
2778 f, err := os.Create(toOutputDir(*traceFile))
2779 if err != nil {
2780 fmt.Fprintf(os.Stderr, "testing: %s\n", err)
2781 return
2782 }
2783 if err := trace.Start(f); err != nil {
2784 fmt.Fprintf(os.Stderr, "testing: can't start tracing: %s\n", err)
2785 f.Close()
2786 return
2787 }
2788
2789 }
2790 if *blockProfile != "" && *blockProfileRate >= 0 {
2791 runtime.SetBlockProfileRate(*blockProfileRate)
2792 }
2793 if *mutexProfile != "" && *mutexProfileFraction >= 0 {
2794 runtime.SetMutexProfileFraction(*mutexProfileFraction)
2795 }
2796 if *coverProfile != "" && CoverMode() == "" {
2797 fmt.Fprintf(os.Stderr, "testing: cannot use -test.coverprofile because test binary was not built with coverage enabled\n")
2798 os.Exit(2)
2799 }
2800 if *gocoverdir != "" && CoverMode() == "" {
2801 fmt.Fprintf(os.Stderr, "testing: cannot use -test.gocoverdir because test binary was not built with coverage enabled\n")
2802 os.Exit(2)
2803 }
2804 if *artifacts {
2805 var err error
2806 artifactDir, err = filepath.Abs(toOutputDir("_artifacts"))
2807 if err != nil {
2808 fmt.Fprintf(os.Stderr, "testing: cannot make -test.outputdir absolute: %v\n", err)
2809 os.Exit(2)
2810 }
2811 if err := os.Mkdir(artifactDir, 0o777); err != nil && !errors.Is(err, os.ErrExist) {
2812 fmt.Fprintf(os.Stderr, "testing: %v\n", err)
2813 os.Exit(2)
2814 }
2815 }
2816 if *testlog != "" {
2817
2818
2819 var f *os.File
2820 var err error
2821 if m.numRun == 1 {
2822 f, err = os.Create(*testlog)
2823 } else {
2824 f, err = os.OpenFile(*testlog, os.O_WRONLY, 0)
2825 if err == nil {
2826 f.Seek(0, io.SeekEnd)
2827 }
2828 }
2829 if err != nil {
2830 fmt.Fprintf(os.Stderr, "testing: %s\n", err)
2831 os.Exit(2)
2832 }
2833 m.deps.StartTestLog(f)
2834 testlogFile = f
2835 }
2836 if *panicOnExit0 {
2837 m.deps.SetPanicOnExit0(true)
2838 }
2839 }
2840
2841
2842 func (m *M) after() {
2843 m.afterOnce.Do(func() {
2844 m.writeProfiles()
2845 })
2846
2847
2848
2849
2850 if *panicOnExit0 {
2851 m.deps.SetPanicOnExit0(false)
2852 }
2853 }
2854
2855 func (m *M) writeProfiles() {
2856 if *testlog != "" {
2857 if err := m.deps.StopTestLog(); err != nil {
2858 fmt.Fprintf(os.Stderr, "testing: can't write %s: %s\n", *testlog, err)
2859 os.Exit(2)
2860 }
2861 if err := testlogFile.Close(); err != nil {
2862 fmt.Fprintf(os.Stderr, "testing: can't write %s: %s\n", *testlog, err)
2863 os.Exit(2)
2864 }
2865 }
2866 if *cpuProfile != "" {
2867 m.deps.StopCPUProfile()
2868 }
2869 if *traceFile != "" {
2870 trace.Stop()
2871 }
2872 if *memProfile != "" {
2873 f, err := os.Create(toOutputDir(*memProfile))
2874 if err != nil {
2875 fmt.Fprintf(os.Stderr, "testing: %s\n", err)
2876 os.Exit(2)
2877 }
2878 runtime.GC()
2879 if err = m.deps.WriteProfileTo("allocs", f, 0); err != nil {
2880 fmt.Fprintf(os.Stderr, "testing: can't write %s: %s\n", *memProfile, err)
2881 os.Exit(2)
2882 }
2883 f.Close()
2884 }
2885 if *blockProfile != "" && *blockProfileRate >= 0 {
2886 f, err := os.Create(toOutputDir(*blockProfile))
2887 if err != nil {
2888 fmt.Fprintf(os.Stderr, "testing: %s\n", err)
2889 os.Exit(2)
2890 }
2891 if err = m.deps.WriteProfileTo("block", f, 0); err != nil {
2892 fmt.Fprintf(os.Stderr, "testing: can't write %s: %s\n", *blockProfile, err)
2893 os.Exit(2)
2894 }
2895 f.Close()
2896 }
2897 if *mutexProfile != "" && *mutexProfileFraction >= 0 {
2898 f, err := os.Create(toOutputDir(*mutexProfile))
2899 if err != nil {
2900 fmt.Fprintf(os.Stderr, "testing: %s\n", err)
2901 os.Exit(2)
2902 }
2903 if err = m.deps.WriteProfileTo("mutex", f, 0); err != nil {
2904 fmt.Fprintf(os.Stderr, "testing: can't write %s: %s\n", *mutexProfile, err)
2905 os.Exit(2)
2906 }
2907 f.Close()
2908 }
2909 if CoverMode() != "" {
2910 coverReport()
2911 }
2912 }
2913
2914
2915
2916 func toOutputDir(path string) string {
2917 if *outputDir == "" || path == "" {
2918 return path
2919 }
2920
2921
2922
2923
2924
2925
2926
2927 if runtime.GOOS == "windows" && len(path) >= 2 {
2928 letter, colon := path[0], path[1]
2929 if ('a' <= letter && letter <= 'z' || 'A' <= letter && letter <= 'Z') && colon == ':' {
2930
2931 return path
2932 }
2933 }
2934 if os.IsPathSeparator(path[0]) {
2935 return path
2936 }
2937 return fmt.Sprintf("%s%c%s", *outputDir, os.PathSeparator, path)
2938 }
2939
2940
2941 func (m *M) startAlarm() time.Time {
2942 if *timeout <= 0 {
2943 return time.Time{}
2944 }
2945
2946 deadline := time.Now().Add(*timeout)
2947 m.timer = time.AfterFunc(*timeout, func() {
2948 m.after()
2949 debug.SetTraceback("all")
2950 extra := ""
2951
2952 if list := runningList(); len(list) > 0 {
2953 var b strings.Builder
2954 b.WriteString("\nrunning tests:")
2955 for _, name := range list {
2956 b.WriteString("\n\t")
2957 b.WriteString(name)
2958 }
2959 extra = b.String()
2960 }
2961 panic(fmt.Sprintf("test timed out after %v%s", *timeout, extra))
2962 })
2963 return deadline
2964 }
2965
2966
2967 func runningList() []string {
2968 var list []string
2969 running.Range(func(k, v any) bool {
2970 list = append(list, fmt.Sprintf("%s (%v)", k.(string), highPrecisionTimeSince(v.(highPrecisionTime)).Round(time.Second)))
2971 return true
2972 })
2973 slices.Sort(list)
2974 return list
2975 }
2976
2977
2978 func (m *M) stopAlarm() {
2979 if *timeout > 0 {
2980 m.timer.Stop()
2981 }
2982 }
2983
2984 func parseCpuList() {
2985 for val := range strings.SplitSeq(*cpuListStr, ",") {
2986 val = strings.TrimSpace(val)
2987 if val == "" {
2988 continue
2989 }
2990 cpu, err := strconv.Atoi(val)
2991 if err != nil || cpu <= 0 {
2992 fmt.Fprintf(os.Stderr, "testing: invalid value %q for -test.cpu\n", val)
2993 os.Exit(1)
2994 }
2995 cpuList = append(cpuList, cpu)
2996 }
2997 if cpuList == nil {
2998 cpuList = append(cpuList, runtime.GOMAXPROCS(-1))
2999 }
3000 }
3001
3002 func shouldFailFast() bool {
3003 return *failFast && numFailed.Load() > 0
3004 }
3005
View as plain text