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