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
1021
1022 denyParallel string
1023 tstate *testState
1024 }
1025
1026 func (c *common) private() {}
1027
1028
1029
1030
1031
1032
1033 func (c *common) Name() string {
1034 return c.name
1035 }
1036
1037 func (c *common) setRan() {
1038 if c.parent != nil {
1039 c.parent.setRan()
1040 }
1041 c.mu.Lock()
1042 defer c.mu.Unlock()
1043 c.ran = true
1044 }
1045
1046
1047 func (c *common) Fail() {
1048 if c.parent != nil {
1049 c.parent.Fail()
1050 }
1051 c.mu.Lock()
1052 defer c.mu.Unlock()
1053
1054 if c.done {
1055 panic("Fail in goroutine after " + c.name + " has completed")
1056 }
1057 c.failed = true
1058 }
1059
1060
1061 func (c *common) Failed() bool {
1062 c.mu.RLock()
1063 defer c.mu.RUnlock()
1064
1065 if !c.done && int64(race.Errors()) > c.lastRaceErrors.Load() {
1066 c.mu.RUnlock()
1067 c.checkRaces()
1068 c.mu.RLock()
1069 }
1070
1071 return c.failed
1072 }
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082 func (c *common) FailNow() {
1083 c.checkFuzzFn("FailNow")
1084 c.Fail()
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105 c.mu.Lock()
1106 c.finished = true
1107 c.mu.Unlock()
1108 runtime.Goexit()
1109 }
1110
1111
1112
1113
1114 func (c *common) log(s string, isErr bool) {
1115 s = strings.TrimSuffix(s, "\n")
1116
1117
1118
1119 s = strings.ReplaceAll(s, "\n", "\n"+indent)
1120 s += "\n"
1121
1122 n := c.destination()
1123 if n == nil {
1124
1125 panic("Log in goroutine after " + c.name + " has completed: " + s)
1126 }
1127
1128
1129
1130 s = n.callSite(3) + s
1131
1132
1133 n.flushPartial()
1134
1135 n.o.write([]byte(s), isErr)
1136 }
1137
1138
1139
1140 func (c *common) destination() *common {
1141 c.mu.Lock()
1142 defer c.mu.Unlock()
1143
1144 if !c.done && !c.isSynctest {
1145 return c
1146 }
1147 for parent := c.parent; parent != nil; parent = parent.parent {
1148 parent.mu.Lock()
1149 defer parent.mu.Unlock()
1150 if !parent.done {
1151 return parent
1152 }
1153 }
1154 return nil
1155 }
1156
1157
1158 func (c *common) callSite(skip int) string {
1159 c.mu.Lock()
1160 defer c.mu.Unlock()
1161
1162 frame := c.frameSkip(skip)
1163 file := frame.File
1164 line := frame.Line
1165 if file != "" {
1166 if *fullPath {
1167
1168 } else {
1169 file = filepath.Base(file)
1170 }
1171 } else {
1172 file = "???"
1173 }
1174 if line == 0 {
1175 line = 1
1176 }
1177
1178 return fmt.Sprintf("%s:%d: ", file, line)
1179 }
1180
1181
1182 func (c *common) flushPartial() {
1183 partial := func() bool {
1184 c.mu.Lock()
1185 defer c.mu.Unlock()
1186 return (c.o != nil) && (len(c.o.partial) > 0)
1187 }
1188
1189 if partial() {
1190 c.o.Write([]byte("\n"))
1191 }
1192 }
1193
1194
1195
1196
1197
1198
1199
1200 func (c *common) Output() io.Writer {
1201 c.checkFuzzFn("Output")
1202 n := c.destination()
1203 if n == nil {
1204 panic("Output called after " + c.name + " has completed")
1205 }
1206 return n.o
1207 }
1208
1209
1210 func (c *common) setOutputWriter() {
1211 c.o = &outputWriter{c: c}
1212 }
1213
1214
1215 type outputWriter struct {
1216 c *common
1217 partial []byte
1218 }
1219
1220
1221
1222 func (o *outputWriter) Write(p []byte) (int, error) {
1223 return o.write(p, false)
1224 }
1225
1226 func (o *outputWriter) write(p []byte, isErr bool) (int, error) {
1227
1228
1229 if o == nil || o.c == nil {
1230 return 0, nil
1231 }
1232 if o.c.destination() == nil {
1233 panic("Write called after " + o.c.name + " has completed")
1234 }
1235
1236 o.c.mu.Lock()
1237 defer o.c.mu.Unlock()
1238
1239
1240 lines := bytes.SplitAfter(p, []byte("\n"))
1241 last := len(lines) - 1
1242 for i, line := range lines[:last] {
1243
1244 if i == 0 && len(o.partial) > 0 {
1245 line = slices.Concat(o.partial, line)
1246 o.partial = o.partial[:0]
1247 }
1248 o.writeLine(line, isErr && i == 0, isErr && i == last-1)
1249 }
1250
1251 o.partial = append(o.partial, lines[last]...)
1252
1253 return len(p), nil
1254 }
1255
1256
1257 func (o *outputWriter) writeLine(b []byte, errBegin, errEnd bool) {
1258 if o.c.done || (o.c.chatty == nil) {
1259 o.c.output = append(o.c.output, indent...)
1260 o.c.output = append(o.c.output, b...)
1261 return
1262 }
1263
1264
1265 if o.c.chatty.json {
1266 b = escapeMarkers(b)
1267 }
1268
1269
1270 var strErrBegin, strErrEnd string
1271 if errBegin && o.c.chatty.json {
1272 strErrBegin = string(markErrBegin)
1273 }
1274
1275
1276
1277
1278 var c []byte
1279 if errEnd && o.c.chatty.json {
1280 i := len(b)
1281 if len(b) > 0 && b[i-1] == '\n' {
1282 b, c = b[:i-1], b[i-1:]
1283 }
1284 strErrEnd = string(markErrEnd)
1285 }
1286
1287 if o.c.bench {
1288
1289
1290 fmt.Printf("%s%s%s%s%s", strErrBegin, indent, b, strErrEnd, c)
1291 } else {
1292 o.c.chatty.Printf(o.c.name, "%s%s%s%s%s", strErrBegin, indent, b, strErrEnd, c)
1293 }
1294 }
1295
1296 func escapeMarkers(b []byte) []byte {
1297 j := nextMark(b)
1298 if j < 0 {
1299
1300 return b
1301 }
1302
1303 c := make([]byte, 0, len(b)+10)
1304 i := 0
1305 for i < len(b) && j >= i {
1306 if j > i {
1307 c = append(c, b[i:j]...)
1308 }
1309 c = append(c, markEscape, b[j])
1310 i = j + 1
1311 j = i + nextMark(b[i:])
1312 }
1313 if i < len(b) {
1314 c = append(c, b[i:]...)
1315 }
1316 return c
1317 }
1318
1319 func nextMark(b []byte) int {
1320 for i, b := range b {
1321 switch b {
1322 case markFraming, markEscape, markErrBegin, markErrEnd:
1323 return i
1324 }
1325 }
1326 return -1
1327 }
1328
1329
1330
1331
1332
1333
1334 func (c *common) Log(args ...any) {
1335 c.checkFuzzFn("Log")
1336 c.log(fmt.Sprintln(args...), false)
1337 }
1338
1339
1340
1341
1342
1343
1344
1345 func (c *common) Logf(format string, args ...any) {
1346 c.checkFuzzFn("Logf")
1347 c.log(fmt.Sprintf(format, args...), false)
1348 }
1349
1350
1351 func (c *common) Error(args ...any) {
1352 c.checkFuzzFn("Error")
1353 c.log(fmt.Sprintln(args...), true)
1354 c.Fail()
1355 }
1356
1357
1358 func (c *common) Errorf(format string, args ...any) {
1359 c.checkFuzzFn("Errorf")
1360 c.log(fmt.Sprintf(format, args...), true)
1361 c.Fail()
1362 }
1363
1364
1365 func (c *common) Fatal(args ...any) {
1366 c.checkFuzzFn("Fatal")
1367 c.log(fmt.Sprintln(args...), true)
1368 c.FailNow()
1369 }
1370
1371
1372 func (c *common) Fatalf(format string, args ...any) {
1373 c.checkFuzzFn("Fatalf")
1374 c.log(fmt.Sprintf(format, args...), true)
1375 c.FailNow()
1376 }
1377
1378
1379 func (c *common) Skip(args ...any) {
1380 c.checkFuzzFn("Skip")
1381 c.log(fmt.Sprintln(args...), false)
1382 c.SkipNow()
1383 }
1384
1385
1386 func (c *common) Skipf(format string, args ...any) {
1387 c.checkFuzzFn("Skipf")
1388 c.log(fmt.Sprintf(format, args...), false)
1389 c.SkipNow()
1390 }
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400 func (c *common) SkipNow() {
1401 c.checkFuzzFn("SkipNow")
1402 c.mu.Lock()
1403 c.skipped = true
1404 c.finished = true
1405 c.mu.Unlock()
1406 runtime.Goexit()
1407 }
1408
1409
1410 func (c *common) Skipped() bool {
1411 c.mu.RLock()
1412 defer c.mu.RUnlock()
1413 return c.skipped
1414 }
1415
1416
1417
1418
1419 func (c *common) Helper() {
1420 if c.isSynctest {
1421 c = c.parent
1422 }
1423 c.mu.Lock()
1424 defer c.mu.Unlock()
1425 if c.helperPCs == nil {
1426 c.helperPCs = make(map[uintptr]struct{})
1427 }
1428
1429 var pc [1]uintptr
1430 n := runtime.Callers(2, pc[:])
1431 if n == 0 {
1432 panic("testing: zero callers found")
1433 }
1434 if _, found := c.helperPCs[pc[0]]; !found {
1435 c.helperPCs[pc[0]] = struct{}{}
1436 c.helperNames = nil
1437 }
1438 }
1439
1440
1441
1442
1443 func (c *common) Cleanup(f func()) {
1444 c.checkFuzzFn("Cleanup")
1445 var pc [maxStackLen]uintptr
1446
1447 n := runtime.Callers(2, pc[:])
1448 cleanupPc := pc[:n]
1449
1450 fn := func() {
1451 defer func() {
1452 c.mu.Lock()
1453 defer c.mu.Unlock()
1454 c.cleanupName = ""
1455 c.cleanupPc = nil
1456 }()
1457
1458 name := callerName(0)
1459 c.mu.Lock()
1460 c.cleanupName = name
1461 c.cleanupPc = cleanupPc
1462 c.mu.Unlock()
1463
1464 f()
1465 }
1466
1467 c.mu.Lock()
1468 defer c.mu.Unlock()
1469 c.cleanups = append(c.cleanups, fn)
1470 }
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480 func (c *common) ArtifactDir() string {
1481 c.checkFuzzFn("ArtifactDir")
1482 c.artifactDirOnce.Do(func() {
1483 c.artifactDir, c.artifactDirErr = c.makeArtifactDir()
1484 })
1485 if c.artifactDirErr != nil {
1486 c.Fatalf("ArtifactDir: %v", c.artifactDirErr)
1487 }
1488 return c.artifactDir
1489 }
1490
1491 func hashString(s string) (h uint64) {
1492
1493 for i := 0; i < len(s); i++ {
1494 h ^= uint64(s[i])
1495 h *= 1099511628211
1496 }
1497 return
1498 }
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508 func (c *common) makeArtifactDir() (string, error) {
1509 if !*artifacts {
1510 return c.makeTempDir()
1511 }
1512
1513 artifactBase := filepath.Join(artifactDir, c.relativeArtifactBase())
1514 if err := os.MkdirAll(artifactBase, 0o777); err != nil {
1515 return "", err
1516 }
1517 dir, err := os.MkdirTemp(artifactBase, "")
1518 if err != nil {
1519 return "", err
1520 }
1521 if c.chatty != nil {
1522 c.chatty.Updatef(c.name, "=== ARTIFACTS %s %v\n", c.name, dir)
1523 }
1524 return dir, nil
1525 }
1526
1527 func (c *common) relativeArtifactBase() string {
1528
1529
1530 const maxNameSize = 64
1531 name := strings.ReplaceAll(c.name, "/", "__")
1532 if len(name) > maxNameSize {
1533 h := fmt.Sprintf("%0x", hashString(name))
1534 name = name[:maxNameSize-len(h)] + h
1535 }
1536
1537
1538
1539 pkg := strings.TrimPrefix(c.importPath, c.modulePath)
1540
1541 pkg = strings.TrimPrefix(pkg, "/")
1542
1543 base := name
1544 if pkg != "" {
1545
1546
1547 base = pkg + "/" + name
1548 }
1549 base = removeSymbolsExcept(base, "!#$%&()+,-.=@^_{}~ /")
1550 base, err := filepath.Localize(base)
1551 if err != nil {
1552
1553
1554 base = ""
1555 }
1556
1557 return base
1558 }
1559
1560 func removeSymbolsExcept(s, allowed string) string {
1561 mapper := func(r rune) rune {
1562 if unicode.IsLetter(r) ||
1563 unicode.IsNumber(r) ||
1564 strings.ContainsRune(allowed, r) {
1565 return r
1566 }
1567 return -1
1568 }
1569 return strings.Map(mapper, s)
1570 }
1571
1572
1573
1574
1575
1576
1577
1578
1579 func (c *common) TempDir() string {
1580 c.checkFuzzFn("TempDir")
1581 dir, err := c.makeTempDir()
1582 if err != nil {
1583 c.Fatalf("TempDir: %v", err)
1584 }
1585 return dir
1586 }
1587
1588 func (c *common) makeTempDir() (string, error) {
1589
1590
1591 c.tempDirMu.Lock()
1592 var nonExistent bool
1593 if c.tempDir == "" {
1594 nonExistent = true
1595 } else {
1596 _, err := os.Stat(c.tempDir)
1597 nonExistent = os.IsNotExist(err)
1598 if err != nil && !nonExistent {
1599 return "", err
1600 }
1601 }
1602
1603 if nonExistent {
1604 c.Helper()
1605
1606 pattern := c.Name()
1607
1608
1609 pattern = pattern[:min(len(pattern), 64)]
1610
1611
1612
1613
1614 const allowed = "!#$%&()+,-.=@^_{}~ "
1615 pattern = removeSymbolsExcept(pattern, allowed)
1616
1617 c.tempDir, c.tempDirErr = os.MkdirTemp(os.Getenv("GOTMPDIR"), pattern)
1618 if c.tempDirErr == nil {
1619 c.Cleanup(func() {
1620 if err := removeAll(c.tempDir); err != nil {
1621 c.Errorf("TempDir RemoveAll cleanup: %v", err)
1622 }
1623 })
1624 }
1625 }
1626
1627 if c.tempDirErr == nil {
1628 c.tempDirSeq++
1629 }
1630 seq := c.tempDirSeq
1631 c.tempDirMu.Unlock()
1632
1633 if c.tempDirErr != nil {
1634 return "", c.tempDirErr
1635 }
1636
1637 dir := fmt.Sprintf("%s%c%03d", c.tempDir, os.PathSeparator, seq)
1638 if err := os.Mkdir(dir, 0o777); err != nil {
1639 return "", err
1640 }
1641 return dir, nil
1642 }
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653 func removeAll(path string) error {
1654 const arbitraryTimeout = 2 * time.Second
1655 var (
1656 start time.Time
1657 nextSleep = 1 * time.Millisecond
1658 )
1659 for {
1660 err := os.RemoveAll(path)
1661 if !isWindowsRetryable(err) {
1662 return err
1663 }
1664 if start.IsZero() {
1665 start = time.Now()
1666 } else if d := time.Since(start) + nextSleep; d >= arbitraryTimeout {
1667 return err
1668 }
1669 time.Sleep(nextSleep)
1670 nextSleep += time.Duration(rand.Int63n(int64(nextSleep)))
1671 }
1672 }
1673
1674
1675
1676
1677
1678
1679
1680 func (c *common) Setenv(key, value string) {
1681 c.checkFuzzFn("Setenv")
1682 prevValue, ok := os.LookupEnv(key)
1683
1684 if err := os.Setenv(key, value); err != nil {
1685 c.Fatalf("cannot set environment variable: %v", err)
1686 }
1687
1688 if ok {
1689 c.Cleanup(func() {
1690 os.Setenv(key, prevValue)
1691 })
1692 } else {
1693 c.Cleanup(func() {
1694 os.Unsetenv(key)
1695 })
1696 }
1697 }
1698
1699
1700
1701
1702
1703
1704
1705 func (c *common) Chdir(dir string) {
1706 c.checkFuzzFn("Chdir")
1707 oldwd, err := os.Open(".")
1708 if err != nil {
1709 c.Fatal(err)
1710 }
1711 if err := os.Chdir(dir); err != nil {
1712 c.Fatal(err)
1713 }
1714
1715
1716
1717 switch runtime.GOOS {
1718 case "windows", "plan9":
1719
1720 default:
1721 if !filepath.IsAbs(dir) {
1722 dir, err = os.Getwd()
1723 if err != nil {
1724 c.Fatal(err)
1725 }
1726 }
1727 c.Setenv("PWD", dir)
1728 }
1729 c.Cleanup(func() {
1730 err := oldwd.Chdir()
1731 oldwd.Close()
1732 if err != nil {
1733
1734
1735
1736 panic("testing.Chdir: " + err.Error())
1737 }
1738 })
1739 }
1740
1741
1742
1743
1744
1745
1746 func (c *common) Context() context.Context {
1747 c.checkFuzzFn("Context")
1748 return c.ctx
1749 }
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761 func (c *common) Attr(key, value string) {
1762 if strings.ContainsFunc(key, unicode.IsSpace) {
1763 c.Errorf("disallowed whitespace in attribute key %q", key)
1764 return
1765 }
1766 if strings.ContainsAny(value, "\r\n") {
1767 c.Errorf("disallowed newline in attribute value %q", value)
1768 return
1769 }
1770 if c.chatty == nil {
1771 return
1772 }
1773 c.chatty.Updatef(c.name, "=== ATTR %s %v %v\n", c.name, key, value)
1774 }
1775
1776
1777 type panicHandling int
1778
1779 const (
1780 normalPanic panicHandling = iota
1781 recoverAndReturnPanic
1782 )
1783
1784
1785
1786
1787 func (c *common) runCleanup(ph panicHandling) (panicVal any) {
1788 c.cleanupStarted.Store(true)
1789 defer c.cleanupStarted.Store(false)
1790
1791 if ph == recoverAndReturnPanic {
1792 defer func() {
1793 panicVal = recover()
1794 }()
1795 }
1796
1797
1798
1799 defer func() {
1800 c.mu.Lock()
1801 recur := len(c.cleanups) > 0
1802 c.mu.Unlock()
1803 if recur {
1804 c.runCleanup(normalPanic)
1805 }
1806 }()
1807
1808 if c.cancelCtx != nil {
1809 c.cancelCtx()
1810 }
1811
1812 for {
1813 var cleanup func()
1814 c.mu.Lock()
1815 if len(c.cleanups) > 0 {
1816 last := len(c.cleanups) - 1
1817 cleanup = c.cleanups[last]
1818 c.cleanups = c.cleanups[:last]
1819 }
1820 c.mu.Unlock()
1821 if cleanup == nil {
1822 return nil
1823 }
1824 cleanup()
1825 }
1826 }
1827
1828
1829
1830
1831
1832
1833 func (c *common) resetRaces() {
1834 if c.parent == nil {
1835 c.lastRaceErrors.Store(int64(race.Errors()))
1836 } else {
1837 c.lastRaceErrors.Store(c.parent.checkRaces())
1838 }
1839 }
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851 func (c *common) checkRaces() (raceErrors int64) {
1852 raceErrors = int64(race.Errors())
1853 for {
1854 last := c.lastRaceErrors.Load()
1855 if raceErrors <= last {
1856
1857 return raceErrors
1858 }
1859 if c.lastRaceErrors.CompareAndSwap(last, raceErrors) {
1860 break
1861 }
1862 }
1863
1864 if c.raceErrorLogged.CompareAndSwap(false, true) {
1865
1866
1867
1868
1869 c.Errorf("race detected during execution of test")
1870 }
1871
1872
1873 parent := c.parent
1874 for parent != nil {
1875 for {
1876 last := parent.lastRaceErrors.Load()
1877 if raceErrors <= last {
1878
1879 return raceErrors
1880 }
1881 if parent.lastRaceErrors.CompareAndSwap(last, raceErrors) {
1882 break
1883 }
1884 }
1885 parent = parent.parent
1886 }
1887
1888 return raceErrors
1889 }
1890
1891
1892
1893 func callerName(skip int) string {
1894 var pc [1]uintptr
1895 n := runtime.Callers(skip+2, pc[:])
1896 if n == 0 {
1897 panic("testing: zero callers found")
1898 }
1899 return pcToName(pc[0])
1900 }
1901
1902 func pcToName(pc uintptr) string {
1903 pcs := []uintptr{pc}
1904 frames := runtime.CallersFrames(pcs)
1905 frame, _ := frames.Next()
1906 return frame.Function
1907 }
1908
1909
1910
1911
1912 func parallelConflict(op string) string {
1913 return "testing: test using " + op + " can not use t.Parallel"
1914 }
1915
1916
1917
1918
1919
1920
1921 func (t *T) Parallel() {
1922 if t.isParallel {
1923 panic("testing: t.Parallel called multiple times")
1924 }
1925 if t.isSynctest {
1926 panic("testing: t.Parallel called inside synctest bubble")
1927 }
1928 if t.denyParallel != "" {
1929 panic(parallelConflict(t.denyParallel))
1930 }
1931 if t.parent.barrier == nil {
1932
1933
1934
1935 return
1936 }
1937
1938 t.isParallel = true
1939
1940
1941
1942
1943 t.duration += highPrecisionTimeSince(t.start)
1944
1945
1946 t.parent.sub = append(t.parent.sub, t)
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958 t.checkRaces()
1959
1960 if t.chatty != nil {
1961 t.chatty.Updatef(t.name, "=== PAUSE %s\n", t.name)
1962 }
1963 running.Delete(t.name)
1964
1965 t.signal <- true
1966 <-t.parent.barrier
1967 t.tstate.waitParallel()
1968 parallelStart.Add(1)
1969
1970 if t.chatty != nil {
1971 t.chatty.Updatef(t.name, "=== CONT %s\n", t.name)
1972 }
1973 running.Store(t.name, highPrecisionTimeNow())
1974 t.start = highPrecisionTimeNow()
1975
1976
1977
1978
1979
1980
1981
1982
1983 t.lastRaceErrors.Store(int64(race.Errors()))
1984 }
1985
1986
1987
1988
1989 func checkParallel(t *T) {
1990 t.checkParallel("cryptotest.SetGlobalRandom")
1991 }
1992
1993 func (t *T) checkParallel(op string) {
1994
1995
1996
1997
1998
1999 for c := &t.common; c != nil; c = c.parent {
2000 if c.isParallel {
2001 panic(parallelConflict(op))
2002 }
2003 }
2004
2005 t.denyParallel = op
2006 }
2007
2008
2009
2010
2011
2012
2013
2014 func (t *T) Setenv(key, value string) {
2015 t.checkParallel("t.Setenv")
2016 t.common.Setenv(key, value)
2017 }
2018
2019
2020
2021
2022
2023
2024
2025 func (t *T) Chdir(dir string) {
2026 t.checkParallel("t.Chdir")
2027 t.common.Chdir(dir)
2028 }
2029
2030
2031
2032 type InternalTest struct {
2033 Name string
2034 F func(*T)
2035 }
2036
2037 var errNilPanicOrGoexit = errors.New("test executed panic(nil) or runtime.Goexit")
2038
2039 func tRunner(t *T, fn func(t *T)) {
2040 t.runner = callerName(0)
2041
2042
2043
2044
2045
2046 defer func() {
2047 t.checkRaces()
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057 err := recover()
2058 signal := true
2059
2060 t.mu.RLock()
2061 finished := t.finished
2062 t.mu.RUnlock()
2063 if !finished && err == nil {
2064 err = errNilPanicOrGoexit
2065 for p := t.parent; p != nil; p = p.parent {
2066 p.mu.RLock()
2067 finished = p.finished
2068 p.mu.RUnlock()
2069 if finished {
2070 if !t.isParallel {
2071 t.Errorf("%v: subtest may have called FailNow on a parent test", err)
2072 err = nil
2073 }
2074 signal = false
2075 break
2076 }
2077 }
2078 }
2079
2080 if err != nil && t.tstate.isFuzzing {
2081 prefix := "panic: "
2082 if err == errNilPanicOrGoexit {
2083 prefix = ""
2084 }
2085 t.Errorf("%s%s\n%s\n", prefix, err, string(debug.Stack()))
2086 t.mu.Lock()
2087 t.finished = true
2088 t.mu.Unlock()
2089 err = nil
2090 }
2091
2092
2093
2094 didPanic := false
2095 defer func() {
2096
2097
2098
2099 if didPanic {
2100 return
2101 }
2102 if err != nil {
2103 panic(err)
2104 }
2105 running.Delete(t.name)
2106 if t.isParallel {
2107 parallelStop.Add(1)
2108 }
2109 t.signal <- signal
2110 }()
2111
2112 doPanic := func(err any) {
2113 t.Fail()
2114 if r := t.runCleanup(recoverAndReturnPanic); r != nil {
2115 t.Logf("cleanup panicked with %v", r)
2116 }
2117
2118
2119 for root := &t.common; !root.isSynctest && root.parent != nil; root = root.parent {
2120 root.mu.Lock()
2121 root.duration += highPrecisionTimeSince(root.start)
2122 d := root.duration
2123 root.mu.Unlock()
2124
2125 root.flushPartial()
2126 root.flushToParent(root.name, "--- FAIL: %s (%s)\n", root.name, fmtDuration(d))
2127 if r := root.parent.runCleanup(recoverAndReturnPanic); r != nil {
2128 fmt.Fprintf(root.parent.w, "cleanup panicked with %v", r)
2129 }
2130 }
2131 didPanic = true
2132 panic(err)
2133 }
2134 if err != nil {
2135 doPanic(err)
2136 }
2137
2138 t.duration += highPrecisionTimeSince(t.start)
2139
2140 if len(t.sub) > 0 {
2141
2142
2143
2144 t.tstate.release()
2145 running.Delete(t.name)
2146
2147
2148 close(t.barrier)
2149
2150 for _, sub := range t.sub {
2151 <-sub.signal
2152 }
2153
2154
2155
2156 cleanupStart := highPrecisionTimeNow()
2157 running.Store(t.name, cleanupStart)
2158 err := t.runCleanup(recoverAndReturnPanic)
2159 t.duration += highPrecisionTimeSince(cleanupStart)
2160 if err != nil {
2161 doPanic(err)
2162 }
2163 t.checkRaces()
2164 if !t.isParallel {
2165
2166 t.tstate.waitParallel()
2167 }
2168 } else if t.isParallel {
2169
2170
2171 t.tstate.release()
2172 }
2173
2174 for root := &t.common; root.parent != nil; root = root.parent {
2175 root.flushPartial()
2176 }
2177
2178
2179
2180
2181 if t.Failed() {
2182 numFailed.Add(1)
2183 }
2184
2185 t.report()
2186
2187
2188
2189 t.done = true
2190 if t.parent != nil && !t.hasSub.Load() {
2191 t.setRan()
2192 }
2193 }()
2194 defer func() {
2195 if len(t.sub) == 0 {
2196 t.runCleanup(normalPanic)
2197 }
2198 }()
2199
2200 t.start = highPrecisionTimeNow()
2201 t.resetRaces()
2202 fn(t)
2203
2204
2205 t.mu.Lock()
2206 t.finished = true
2207 t.mu.Unlock()
2208 }
2209
2210
2211
2212
2213
2214
2215
2216 func (t *T) Run(name string, f func(t *T)) bool {
2217 if t.isSynctest {
2218 panic("testing: t.Run called inside synctest bubble")
2219 }
2220 if t.cleanupStarted.Load() {
2221 panic("testing: t.Run called during t.Cleanup")
2222 }
2223
2224 t.hasSub.Store(true)
2225 testName, ok, _ := t.tstate.match.fullName(&t.common, name)
2226 if !ok || shouldFailFast() {
2227 return true
2228 }
2229
2230
2231
2232 var pc [maxStackLen]uintptr
2233 n := runtime.Callers(2, pc[:])
2234
2235
2236
2237 ctx, cancelCtx := context.WithCancel(context.Background())
2238 t = &T{
2239 common: common{
2240 barrier: make(chan bool),
2241 signal: make(chan bool, 1),
2242 name: testName,
2243 modulePath: t.modulePath,
2244 importPath: t.importPath,
2245 parent: &t.common,
2246 level: t.level + 1,
2247 creator: pc[:n],
2248 chatty: t.chatty,
2249 ctx: ctx,
2250 cancelCtx: cancelCtx,
2251 },
2252 tstate: t.tstate,
2253 }
2254 t.w = indenter{&t.common}
2255 t.setOutputWriter()
2256
2257 if t.chatty != nil {
2258 t.chatty.Updatef(t.name, "=== RUN %s\n", t.name)
2259 }
2260 running.Store(t.name, highPrecisionTimeNow())
2261
2262
2263
2264
2265
2266
2267 go tRunner(t, f)
2268
2269
2270
2271
2272
2273
2274
2275 if !<-t.signal {
2276
2277
2278 runtime.Goexit()
2279 }
2280
2281 if t.chatty != nil && t.chatty.json {
2282 t.chatty.Updatef(t.parent.name, "=== NAME %s\n", t.parent.name)
2283 }
2284 return !t.failed
2285 }
2286
2287
2288
2289
2290
2291 func testingSynctestTest(t *T, f func(*T)) (ok bool) {
2292 if t.cleanupStarted.Load() {
2293 panic("testing: synctest.Run called during t.Cleanup")
2294 }
2295
2296 var pc [maxStackLen]uintptr
2297 n := runtime.Callers(2, pc[:])
2298
2299 ctx, cancelCtx := context.WithCancel(context.Background())
2300 t2 := &T{
2301 common: common{
2302 barrier: make(chan bool),
2303 signal: make(chan bool, 1),
2304 name: t.name,
2305 parent: &t.common,
2306 level: t.level + 1,
2307 creator: pc[:n],
2308 chatty: t.chatty,
2309 ctx: ctx,
2310 cancelCtx: cancelCtx,
2311 isSynctest: true,
2312 },
2313 tstate: t.tstate,
2314 }
2315
2316 go tRunner(t2, f)
2317 if !<-t2.signal {
2318
2319
2320 runtime.Goexit()
2321 }
2322 return !t2.failed
2323 }
2324
2325
2326
2327
2328
2329 func (t *T) Deadline() (deadline time.Time, ok bool) {
2330 if t.isSynctest {
2331
2332
2333
2334 panic("testing: t.Deadline called inside synctest bubble")
2335 }
2336 deadline = t.tstate.deadline
2337 return deadline, !deadline.IsZero()
2338 }
2339
2340
2341
2342 type testState struct {
2343 match *matcher
2344 deadline time.Time
2345
2346
2347
2348
2349
2350 isFuzzing bool
2351
2352 mu sync.Mutex
2353
2354
2355 startParallel chan bool
2356
2357
2358
2359 running int
2360
2361
2362 numWaiting int
2363
2364
2365 maxParallel int
2366 }
2367
2368 func newTestState(maxParallel int, m *matcher) *testState {
2369 return &testState{
2370 match: m,
2371 startParallel: make(chan bool),
2372 maxParallel: maxParallel,
2373 running: 1,
2374 }
2375 }
2376
2377 func (s *testState) waitParallel() {
2378 s.mu.Lock()
2379 if s.running < s.maxParallel {
2380 s.running++
2381 s.mu.Unlock()
2382 return
2383 }
2384 s.numWaiting++
2385 s.mu.Unlock()
2386 <-s.startParallel
2387 }
2388
2389 func (s *testState) release() {
2390 s.mu.Lock()
2391 if s.numWaiting == 0 {
2392 s.running--
2393 s.mu.Unlock()
2394 return
2395 }
2396 s.numWaiting--
2397 s.mu.Unlock()
2398 s.startParallel <- true
2399 }
2400
2401
2402
2403 var errMain = errors.New("testing: unexpected use of func Main")
2404
2405 type matchStringOnly func(pat, str string) (bool, error)
2406
2407 func (f matchStringOnly) MatchString(pat, str string) (bool, error) { return f(pat, str) }
2408 func (f matchStringOnly) StartCPUProfile(w io.Writer) error { return errMain }
2409 func (f matchStringOnly) StopCPUProfile() {}
2410 func (f matchStringOnly) WriteProfileTo(string, io.Writer, int) error { return errMain }
2411 func (f matchStringOnly) ModulePath() string { return "" }
2412 func (f matchStringOnly) ImportPath() string { return "" }
2413 func (f matchStringOnly) StartTestLog(io.Writer) {}
2414 func (f matchStringOnly) StopTestLog() error { return errMain }
2415 func (f matchStringOnly) SetPanicOnExit0(bool) {}
2416 func (f matchStringOnly) CoordinateFuzzing(time.Duration, int64, time.Duration, int64, int, []corpusEntry, []reflect.Type, string, string) error {
2417 return errMain
2418 }
2419 func (f matchStringOnly) RunFuzzWorker(func(corpusEntry) error) error { return errMain }
2420 func (f matchStringOnly) ReadCorpus(string, []reflect.Type) ([]corpusEntry, error) {
2421 return nil, errMain
2422 }
2423 func (f matchStringOnly) CheckCorpus([]any, []reflect.Type) error { return nil }
2424 func (f matchStringOnly) ResetCoverage() {}
2425 func (f matchStringOnly) SnapshotCoverage() {}
2426
2427 func (f matchStringOnly) InitRuntimeCoverage() (mode string, tearDown func(string, string) (string, error), snapcov func() float64) {
2428 return
2429 }
2430
2431
2432
2433
2434
2435
2436
2437 func Main(matchString func(pat, str string) (bool, error), tests []InternalTest, benchmarks []InternalBenchmark, examples []InternalExample) {
2438 os.Exit(MainStart(matchStringOnly(matchString), tests, benchmarks, nil, examples).Run())
2439 }
2440
2441
2442 type M struct {
2443 deps testDeps
2444 tests []InternalTest
2445 benchmarks []InternalBenchmark
2446 fuzzTargets []InternalFuzzTarget
2447 examples []InternalExample
2448
2449 timer *time.Timer
2450 afterOnce sync.Once
2451
2452 numRun int
2453
2454
2455
2456 exitCode int
2457 }
2458
2459
2460
2461
2462
2463 type testDeps interface {
2464 ImportPath() string
2465 ModulePath() string
2466 MatchString(pat, str string) (bool, error)
2467 SetPanicOnExit0(bool)
2468 StartCPUProfile(io.Writer) error
2469 StopCPUProfile()
2470 StartTestLog(io.Writer)
2471 StopTestLog() error
2472 WriteProfileTo(string, io.Writer, int) error
2473 CoordinateFuzzing(time.Duration, int64, time.Duration, int64, int, []corpusEntry, []reflect.Type, string, string) error
2474 RunFuzzWorker(func(corpusEntry) error) error
2475 ReadCorpus(string, []reflect.Type) ([]corpusEntry, error)
2476 CheckCorpus([]any, []reflect.Type) error
2477 ResetCoverage()
2478 SnapshotCoverage()
2479 InitRuntimeCoverage() (mode string, tearDown func(coverprofile string, gocoverdir string) (string, error), snapcov func() float64)
2480 }
2481
2482
2483
2484
2485 func MainStart(deps testDeps, tests []InternalTest, benchmarks []InternalBenchmark, fuzzTargets []InternalFuzzTarget, examples []InternalExample) *M {
2486 registerCover(deps.InitRuntimeCoverage())
2487 Init()
2488 return &M{
2489 deps: deps,
2490 tests: tests,
2491 benchmarks: benchmarks,
2492 fuzzTargets: fuzzTargets,
2493 examples: examples,
2494 }
2495 }
2496
2497 var (
2498 testingTesting bool
2499 realStderr *os.File
2500 )
2501
2502
2503
2504
2505
2506 func (m *M) Run() (code int) {
2507 defer func() {
2508 code = m.exitCode
2509 }()
2510
2511
2512
2513
2514
2515 m.numRun++
2516
2517
2518 if !flag.Parsed() {
2519 flag.Parse()
2520 }
2521
2522 if chatty.json {
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
2550
2551
2552
2553
2554
2555
2556 realStderr = os.Stderr
2557 os.Stderr = os.Stdout
2558 }
2559
2560 if *parallel < 1 {
2561 fmt.Fprintln(os.Stderr, "testing: -parallel can only be given a positive integer")
2562 flag.Usage()
2563 m.exitCode = 2
2564 return
2565 }
2566 if *matchFuzz != "" && *fuzzCacheDir == "" {
2567 fmt.Fprintln(os.Stderr, "testing: -test.fuzzcachedir must be set if -test.fuzz is set")
2568 flag.Usage()
2569 m.exitCode = 2
2570 return
2571 }
2572
2573 if *matchList != "" {
2574 listTests(m.deps.MatchString, m.tests, m.benchmarks, m.fuzzTargets, m.examples)
2575 m.exitCode = 0
2576 return
2577 }
2578
2579 if *shuffle != "off" {
2580 var n int64
2581 var err error
2582 if *shuffle == "on" {
2583 n = time.Now().UnixNano()
2584 } else {
2585 n, err = strconv.ParseInt(*shuffle, 10, 64)
2586 if err != nil {
2587 fmt.Fprintln(os.Stderr, `testing: -shuffle should be "off", "on", or a valid integer:`, err)
2588 m.exitCode = 2
2589 return
2590 }
2591 }
2592 fmt.Println("-test.shuffle", n)
2593 rng := rand.New(rand.NewSource(n))
2594 rng.Shuffle(len(m.tests), func(i, j int) { m.tests[i], m.tests[j] = m.tests[j], m.tests[i] })
2595 rng.Shuffle(len(m.benchmarks), func(i, j int) { m.benchmarks[i], m.benchmarks[j] = m.benchmarks[j], m.benchmarks[i] })
2596 }
2597
2598 parseCpuList()
2599
2600 m.before()
2601 defer m.after()
2602
2603
2604
2605
2606 if !*isFuzzWorker {
2607 deadline := m.startAlarm()
2608 haveExamples = len(m.examples) > 0
2609 testRan, testOk := runTests(m.deps.ModulePath(), m.deps.ImportPath(), m.deps.MatchString, m.tests, deadline)
2610 fuzzTargetsRan, fuzzTargetsOk := runFuzzTests(m.deps, m.fuzzTargets, deadline)
2611 exampleRan, exampleOk := runExamples(m.deps.MatchString, m.examples)
2612 m.stopAlarm()
2613 if !testRan && !exampleRan && !fuzzTargetsRan && *matchBenchmarks == "" && *matchFuzz == "" {
2614 fmt.Fprintln(os.Stderr, "testing: warning: no tests to run")
2615 if testingTesting && *match != "^$" {
2616
2617
2618
2619
2620
2621 fmt.Print(chatty.prefix(), "FAIL: package testing must run tests\n")
2622 testOk = false
2623 }
2624 }
2625 anyFailed := !testOk || !exampleOk || !fuzzTargetsOk || !runBenchmarks(m.deps.ImportPath(), m.deps.MatchString, m.benchmarks)
2626 if !anyFailed && race.Errors() > 0 {
2627 fmt.Print(chatty.prefix(), "testing: race detected outside of test execution\n")
2628 anyFailed = true
2629 }
2630 if anyFailed {
2631 fmt.Print(chatty.prefix(), "FAIL\n")
2632 m.exitCode = 1
2633 return
2634 }
2635 }
2636
2637 fuzzingOk := runFuzzing(m.deps, m.fuzzTargets)
2638 if !fuzzingOk {
2639 fmt.Print(chatty.prefix(), "FAIL\n")
2640 if *isFuzzWorker {
2641 m.exitCode = fuzzWorkerExitCode
2642 } else {
2643 m.exitCode = 1
2644 }
2645 return
2646 }
2647
2648 m.exitCode = 0
2649 if !*isFuzzWorker {
2650 fmt.Print(chatty.prefix(), "PASS\n")
2651 }
2652 return
2653 }
2654
2655 func (t *T) report() {
2656 if t.parent == nil {
2657 return
2658 }
2659 if t.isSynctest {
2660 return
2661 }
2662 dstr := fmtDuration(t.duration)
2663 format := "--- %s: %s (%s)\n"
2664 if t.Failed() {
2665 t.flushToParent(t.name, format, "FAIL", t.name, dstr)
2666 } else if t.chatty != nil {
2667 if t.Skipped() {
2668 t.flushToParent(t.name, format, "SKIP", t.name, dstr)
2669 } else {
2670 t.flushToParent(t.name, format, "PASS", t.name, dstr)
2671 }
2672 }
2673 }
2674
2675 func listTests(matchString func(pat, str string) (bool, error), tests []InternalTest, benchmarks []InternalBenchmark, fuzzTargets []InternalFuzzTarget, examples []InternalExample) {
2676 if _, err := matchString(*matchList, "non-empty"); err != nil {
2677 fmt.Fprintf(os.Stderr, "testing: invalid regexp in -test.list (%q): %s\n", *matchList, err)
2678 os.Exit(1)
2679 }
2680
2681 for _, test := range tests {
2682 if ok, _ := matchString(*matchList, test.Name); ok {
2683 fmt.Println(test.Name)
2684 }
2685 }
2686 for _, bench := range benchmarks {
2687 if ok, _ := matchString(*matchList, bench.Name); ok {
2688 fmt.Println(bench.Name)
2689 }
2690 }
2691 for _, fuzzTarget := range fuzzTargets {
2692 if ok, _ := matchString(*matchList, fuzzTarget.Name); ok {
2693 fmt.Println(fuzzTarget.Name)
2694 }
2695 }
2696 for _, example := range examples {
2697 if ok, _ := matchString(*matchList, example.Name); ok {
2698 fmt.Println(example.Name)
2699 }
2700 }
2701 }
2702
2703
2704
2705 func RunTests(matchString func(pat, str string) (bool, error), tests []InternalTest) (ok bool) {
2706 var deadline time.Time
2707 if *timeout > 0 {
2708 deadline = time.Now().Add(*timeout)
2709 }
2710 ran, ok := runTests("", "", matchString, tests, deadline)
2711 if !ran && !haveExamples {
2712 fmt.Fprintln(os.Stderr, "testing: warning: no tests to run")
2713 }
2714 return ok
2715 }
2716
2717 func runTests(modulePath, importPath string, matchString func(pat, str string) (bool, error), tests []InternalTest, deadline time.Time) (ran, ok bool) {
2718 ok = true
2719 for _, procs := range cpuList {
2720 runtime.GOMAXPROCS(procs)
2721 for i := uint(0); i < *count; i++ {
2722 if shouldFailFast() {
2723 break
2724 }
2725 if i > 0 && !ran {
2726
2727
2728
2729 break
2730 }
2731 ctx, cancelCtx := context.WithCancel(context.Background())
2732 tstate := newTestState(*parallel, newMatcher(matchString, *match, "-test.run", *skip))
2733 tstate.deadline = deadline
2734 t := &T{
2735 common: common{
2736 signal: make(chan bool, 1),
2737 barrier: make(chan bool),
2738 w: os.Stdout,
2739 ctx: ctx,
2740 cancelCtx: cancelCtx,
2741 modulePath: modulePath,
2742 importPath: importPath,
2743 },
2744 tstate: tstate,
2745 }
2746 if Verbose() {
2747 t.chatty = newChattyPrinter(t.w)
2748 }
2749 tRunner(t, func(t *T) {
2750 for _, test := range tests {
2751 t.Run(test.Name, test.F)
2752 }
2753 })
2754 select {
2755 case <-t.signal:
2756 default:
2757 panic("internal error: tRunner exited without sending on t.signal")
2758 }
2759 ok = ok && !t.Failed()
2760 ran = ran || t.ran
2761 }
2762 }
2763 return ran, ok
2764 }
2765
2766
2767 func (m *M) before() {
2768 if *memProfileRate > 0 {
2769 runtime.MemProfileRate = *memProfileRate
2770 }
2771 if *cpuProfile != "" {
2772 f, err := os.Create(toOutputDir(*cpuProfile))
2773 if err != nil {
2774 fmt.Fprintf(os.Stderr, "testing: %s\n", err)
2775 return
2776 }
2777 if err := m.deps.StartCPUProfile(f); err != nil {
2778 fmt.Fprintf(os.Stderr, "testing: can't start cpu profile: %s\n", err)
2779 f.Close()
2780 return
2781 }
2782
2783 }
2784 if *traceFile != "" {
2785 f, err := os.Create(toOutputDir(*traceFile))
2786 if err != nil {
2787 fmt.Fprintf(os.Stderr, "testing: %s\n", err)
2788 return
2789 }
2790 if err := trace.Start(f); err != nil {
2791 fmt.Fprintf(os.Stderr, "testing: can't start tracing: %s\n", err)
2792 f.Close()
2793 return
2794 }
2795
2796 }
2797 if *blockProfile != "" && *blockProfileRate >= 0 {
2798 runtime.SetBlockProfileRate(*blockProfileRate)
2799 }
2800 if *mutexProfile != "" && *mutexProfileFraction >= 0 {
2801 runtime.SetMutexProfileFraction(*mutexProfileFraction)
2802 }
2803 if *coverProfile != "" && CoverMode() == "" {
2804 fmt.Fprintf(os.Stderr, "testing: cannot use -test.coverprofile because test binary was not built with coverage enabled\n")
2805 os.Exit(2)
2806 }
2807 if *gocoverdir != "" && CoverMode() == "" {
2808 fmt.Fprintf(os.Stderr, "testing: cannot use -test.gocoverdir because test binary was not built with coverage enabled\n")
2809 os.Exit(2)
2810 }
2811 if *artifacts {
2812 var err error
2813 artifactDir, err = filepath.Abs(toOutputDir("_artifacts"))
2814 if err != nil {
2815 fmt.Fprintf(os.Stderr, "testing: cannot make -test.outputdir absolute: %v\n", err)
2816 os.Exit(2)
2817 }
2818 if err := os.Mkdir(artifactDir, 0o777); err != nil && !errors.Is(err, os.ErrExist) {
2819 fmt.Fprintf(os.Stderr, "testing: %v\n", err)
2820 os.Exit(2)
2821 }
2822 }
2823 if *testlog != "" {
2824
2825
2826 var f *os.File
2827 var err error
2828 if m.numRun == 1 {
2829 f, err = os.Create(*testlog)
2830 } else {
2831 f, err = os.OpenFile(*testlog, os.O_WRONLY, 0)
2832 if err == nil {
2833 f.Seek(0, io.SeekEnd)
2834 }
2835 }
2836 if err != nil {
2837 fmt.Fprintf(os.Stderr, "testing: %s\n", err)
2838 os.Exit(2)
2839 }
2840 m.deps.StartTestLog(f)
2841 testlogFile = f
2842 }
2843 if *panicOnExit0 {
2844 m.deps.SetPanicOnExit0(true)
2845 }
2846 }
2847
2848
2849 func (m *M) after() {
2850 m.afterOnce.Do(func() {
2851 m.writeProfiles()
2852 })
2853
2854
2855
2856
2857 if *panicOnExit0 {
2858 m.deps.SetPanicOnExit0(false)
2859 }
2860 }
2861
2862 func (m *M) writeProfiles() {
2863 if *testlog != "" {
2864 if err := m.deps.StopTestLog(); err != nil {
2865 fmt.Fprintf(os.Stderr, "testing: can't write %s: %s\n", *testlog, err)
2866 os.Exit(2)
2867 }
2868 if err := testlogFile.Close(); err != nil {
2869 fmt.Fprintf(os.Stderr, "testing: can't write %s: %s\n", *testlog, err)
2870 os.Exit(2)
2871 }
2872 }
2873 if *cpuProfile != "" {
2874 m.deps.StopCPUProfile()
2875 }
2876 if *traceFile != "" {
2877 trace.Stop()
2878 }
2879 if *memProfile != "" {
2880 f, err := os.Create(toOutputDir(*memProfile))
2881 if err != nil {
2882 fmt.Fprintf(os.Stderr, "testing: %s\n", err)
2883 os.Exit(2)
2884 }
2885 runtime.GC()
2886 if err = m.deps.WriteProfileTo("allocs", f, 0); err != nil {
2887 fmt.Fprintf(os.Stderr, "testing: can't write %s: %s\n", *memProfile, err)
2888 os.Exit(2)
2889 }
2890 f.Close()
2891 }
2892 if *blockProfile != "" && *blockProfileRate >= 0 {
2893 f, err := os.Create(toOutputDir(*blockProfile))
2894 if err != nil {
2895 fmt.Fprintf(os.Stderr, "testing: %s\n", err)
2896 os.Exit(2)
2897 }
2898 if err = m.deps.WriteProfileTo("block", f, 0); err != nil {
2899 fmt.Fprintf(os.Stderr, "testing: can't write %s: %s\n", *blockProfile, err)
2900 os.Exit(2)
2901 }
2902 f.Close()
2903 }
2904 if *mutexProfile != "" && *mutexProfileFraction >= 0 {
2905 f, err := os.Create(toOutputDir(*mutexProfile))
2906 if err != nil {
2907 fmt.Fprintf(os.Stderr, "testing: %s\n", err)
2908 os.Exit(2)
2909 }
2910 if err = m.deps.WriteProfileTo("mutex", f, 0); err != nil {
2911 fmt.Fprintf(os.Stderr, "testing: can't write %s: %s\n", *mutexProfile, err)
2912 os.Exit(2)
2913 }
2914 f.Close()
2915 }
2916 if CoverMode() != "" {
2917 coverReport()
2918 }
2919 }
2920
2921
2922
2923 func toOutputDir(path string) string {
2924 if *outputDir == "" || path == "" {
2925 return path
2926 }
2927
2928
2929
2930
2931
2932
2933
2934 if runtime.GOOS == "windows" && len(path) >= 2 {
2935 letter, colon := path[0], path[1]
2936 if ('a' <= letter && letter <= 'z' || 'A' <= letter && letter <= 'Z') && colon == ':' {
2937
2938 return path
2939 }
2940 }
2941 if os.IsPathSeparator(path[0]) {
2942 return path
2943 }
2944 return fmt.Sprintf("%s%c%s", *outputDir, os.PathSeparator, path)
2945 }
2946
2947
2948 func (m *M) startAlarm() time.Time {
2949 if *timeout <= 0 {
2950 return time.Time{}
2951 }
2952
2953 deadline := time.Now().Add(*timeout)
2954 m.timer = time.AfterFunc(*timeout, func() {
2955 m.after()
2956 debug.SetTraceback("all")
2957 extra := ""
2958
2959 if list := runningList(); len(list) > 0 {
2960 var b strings.Builder
2961 b.WriteString("\nrunning tests:")
2962 for _, name := range list {
2963 b.WriteString("\n\t")
2964 b.WriteString(name)
2965 }
2966 extra = b.String()
2967 }
2968 panic(fmt.Sprintf("test timed out after %v%s", *timeout, extra))
2969 })
2970 return deadline
2971 }
2972
2973
2974 func runningList() []string {
2975 var list []string
2976 running.Range(func(k, v any) bool {
2977 list = append(list, fmt.Sprintf("%s (%v)", k.(string), highPrecisionTimeSince(v.(highPrecisionTime)).Round(time.Second)))
2978 return true
2979 })
2980 slices.Sort(list)
2981 return list
2982 }
2983
2984
2985 func (m *M) stopAlarm() {
2986 if *timeout > 0 {
2987 m.timer.Stop()
2988 }
2989 }
2990
2991 func parseCpuList() {
2992 for val := range strings.SplitSeq(*cpuListStr, ",") {
2993 val = strings.TrimSpace(val)
2994 if val == "" {
2995 continue
2996 }
2997 cpu, err := strconv.Atoi(val)
2998 if err != nil || cpu <= 0 {
2999 fmt.Fprintf(os.Stderr, "testing: invalid value %q for -test.cpu\n", val)
3000 os.Exit(1)
3001 }
3002 cpuList = append(cpuList, cpu)
3003 }
3004 if cpuList == nil {
3005 cpuList = append(cpuList, runtime.GOMAXPROCS(-1))
3006 }
3007 }
3008
3009 func shouldFailFast() bool {
3010 return *failFast && numFailed.Load() > 0
3011 }
3012
View as plain text