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
1912 func (t *T) Parallel() {
1913 if t.isParallel {
1914 panic("testing: t.Parallel called multiple times")
1915 }
1916 if t.isSynctest {
1917 panic("testing: t.Parallel called inside synctest bubble")
1918 }
1919 if t.denyParallel {
1920 panic(parallelConflict)
1921 }
1922 if t.parent.barrier == nil {
1923
1924
1925
1926 return
1927 }
1928
1929 t.isParallel = true
1930
1931
1932
1933
1934 t.duration += highPrecisionTimeSince(t.start)
1935
1936
1937 t.parent.sub = append(t.parent.sub, t)
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949 t.checkRaces()
1950
1951 if t.chatty != nil {
1952 t.chatty.Updatef(t.name, "=== PAUSE %s\n", t.name)
1953 }
1954 running.Delete(t.name)
1955
1956 t.signal <- true
1957 <-t.parent.barrier
1958 t.tstate.waitParallel()
1959 parallelStart.Add(1)
1960
1961 if t.chatty != nil {
1962 t.chatty.Updatef(t.name, "=== CONT %s\n", t.name)
1963 }
1964 running.Store(t.name, highPrecisionTimeNow())
1965 t.start = highPrecisionTimeNow()
1966
1967
1968
1969
1970
1971
1972
1973
1974 t.lastRaceErrors.Store(int64(race.Errors()))
1975 }
1976
1977
1978
1979
1980 func checkParallel(t *T) {
1981 t.checkParallel()
1982 }
1983
1984 func (t *T) checkParallel() {
1985
1986
1987
1988
1989
1990 for c := &t.common; c != nil; c = c.parent {
1991 if c.isParallel {
1992 panic(parallelConflict)
1993 }
1994 }
1995
1996 t.denyParallel = true
1997 }
1998
1999
2000
2001
2002
2003
2004
2005 func (t *T) Setenv(key, value string) {
2006 t.checkParallel()
2007 t.common.Setenv(key, value)
2008 }
2009
2010
2011
2012
2013
2014
2015
2016 func (t *T) Chdir(dir string) {
2017 t.checkParallel()
2018 t.common.Chdir(dir)
2019 }
2020
2021
2022
2023 type InternalTest struct {
2024 Name string
2025 F func(*T)
2026 }
2027
2028 var errNilPanicOrGoexit = errors.New("test executed panic(nil) or runtime.Goexit")
2029
2030 func tRunner(t *T, fn func(t *T)) {
2031 t.runner = callerName(0)
2032
2033
2034
2035
2036
2037 defer func() {
2038 t.checkRaces()
2039
2040
2041 if t.Failed() {
2042 numFailed.Add(1)
2043 }
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053 err := recover()
2054 signal := true
2055
2056 t.mu.RLock()
2057 finished := t.finished
2058 t.mu.RUnlock()
2059 if !finished && err == nil {
2060 err = errNilPanicOrGoexit
2061 for p := t.parent; p != nil; p = p.parent {
2062 p.mu.RLock()
2063 finished = p.finished
2064 p.mu.RUnlock()
2065 if finished {
2066 if !t.isParallel {
2067 t.Errorf("%v: subtest may have called FailNow on a parent test", err)
2068 err = nil
2069 }
2070 signal = false
2071 break
2072 }
2073 }
2074 }
2075
2076 if err != nil && t.tstate.isFuzzing {
2077 prefix := "panic: "
2078 if err == errNilPanicOrGoexit {
2079 prefix = ""
2080 }
2081 t.Errorf("%s%s\n%s\n", prefix, err, string(debug.Stack()))
2082 t.mu.Lock()
2083 t.finished = true
2084 t.mu.Unlock()
2085 err = nil
2086 }
2087
2088
2089
2090 didPanic := false
2091 defer func() {
2092
2093
2094
2095 if didPanic {
2096 return
2097 }
2098 if err != nil {
2099 panic(err)
2100 }
2101 running.Delete(t.name)
2102 if t.isParallel {
2103 parallelStop.Add(1)
2104 }
2105 t.signal <- signal
2106 }()
2107
2108 doPanic := func(err any) {
2109 t.Fail()
2110 if r := t.runCleanup(recoverAndReturnPanic); r != nil {
2111 t.Logf("cleanup panicked with %v", r)
2112 }
2113
2114
2115 for root := &t.common; !root.isSynctest && root.parent != nil; root = root.parent {
2116 root.mu.Lock()
2117 root.duration += highPrecisionTimeSince(root.start)
2118 d := root.duration
2119 root.mu.Unlock()
2120
2121 root.flushPartial()
2122 root.flushToParent(root.name, "--- FAIL: %s (%s)\n", root.name, fmtDuration(d))
2123 if r := root.parent.runCleanup(recoverAndReturnPanic); r != nil {
2124 fmt.Fprintf(root.parent.w, "cleanup panicked with %v", r)
2125 }
2126 }
2127 didPanic = true
2128 panic(err)
2129 }
2130 if err != nil {
2131 doPanic(err)
2132 }
2133
2134 t.duration += highPrecisionTimeSince(t.start)
2135
2136 if len(t.sub) > 0 {
2137
2138
2139
2140 t.tstate.release()
2141 running.Delete(t.name)
2142
2143
2144 close(t.barrier)
2145
2146 for _, sub := range t.sub {
2147 <-sub.signal
2148 }
2149
2150
2151
2152 cleanupStart := highPrecisionTimeNow()
2153 running.Store(t.name, cleanupStart)
2154 err := t.runCleanup(recoverAndReturnPanic)
2155 t.duration += highPrecisionTimeSince(cleanupStart)
2156 if err != nil {
2157 doPanic(err)
2158 }
2159 t.checkRaces()
2160 if !t.isParallel {
2161
2162 t.tstate.waitParallel()
2163 }
2164 } else if t.isParallel {
2165
2166
2167 t.tstate.release()
2168 }
2169
2170 for root := &t.common; root.parent != nil; root = root.parent {
2171 root.flushPartial()
2172 }
2173 t.report()
2174
2175
2176
2177 t.done = true
2178 if t.parent != nil && !t.hasSub.Load() {
2179 t.setRan()
2180 }
2181 }()
2182 defer func() {
2183 if len(t.sub) == 0 {
2184 t.runCleanup(normalPanic)
2185 }
2186 }()
2187
2188 t.start = highPrecisionTimeNow()
2189 t.resetRaces()
2190 fn(t)
2191
2192
2193 t.mu.Lock()
2194 t.finished = true
2195 t.mu.Unlock()
2196 }
2197
2198
2199
2200
2201
2202
2203
2204 func (t *T) Run(name string, f func(t *T)) bool {
2205 if t.isSynctest {
2206 panic("testing: t.Run called inside synctest bubble")
2207 }
2208 if t.cleanupStarted.Load() {
2209 panic("testing: t.Run called during t.Cleanup")
2210 }
2211
2212 t.hasSub.Store(true)
2213 testName, ok, _ := t.tstate.match.fullName(&t.common, name)
2214 if !ok || shouldFailFast() {
2215 return true
2216 }
2217
2218
2219
2220 var pc [maxStackLen]uintptr
2221 n := runtime.Callers(2, pc[:])
2222
2223
2224
2225 ctx, cancelCtx := context.WithCancel(context.Background())
2226 t = &T{
2227 common: common{
2228 barrier: make(chan bool),
2229 signal: make(chan bool, 1),
2230 name: testName,
2231 modulePath: t.modulePath,
2232 importPath: t.importPath,
2233 parent: &t.common,
2234 level: t.level + 1,
2235 creator: pc[:n],
2236 chatty: t.chatty,
2237 ctx: ctx,
2238 cancelCtx: cancelCtx,
2239 },
2240 tstate: t.tstate,
2241 }
2242 t.w = indenter{&t.common}
2243 t.setOutputWriter()
2244
2245 if t.chatty != nil {
2246 t.chatty.Updatef(t.name, "=== RUN %s\n", t.name)
2247 }
2248 running.Store(t.name, highPrecisionTimeNow())
2249
2250
2251
2252
2253
2254
2255 go tRunner(t, f)
2256
2257
2258
2259
2260
2261
2262
2263 if !<-t.signal {
2264
2265
2266 runtime.Goexit()
2267 }
2268
2269 if t.chatty != nil && t.chatty.json {
2270 t.chatty.Updatef(t.parent.name, "=== NAME %s\n", t.parent.name)
2271 }
2272 return !t.failed
2273 }
2274
2275
2276
2277
2278
2279 func testingSynctestTest(t *T, f func(*T)) (ok bool) {
2280 if t.cleanupStarted.Load() {
2281 panic("testing: synctest.Run called during t.Cleanup")
2282 }
2283
2284 var pc [maxStackLen]uintptr
2285 n := runtime.Callers(2, pc[:])
2286
2287 ctx, cancelCtx := context.WithCancel(context.Background())
2288 t2 := &T{
2289 common: common{
2290 barrier: make(chan bool),
2291 signal: make(chan bool, 1),
2292 name: t.name,
2293 parent: &t.common,
2294 level: t.level + 1,
2295 creator: pc[:n],
2296 chatty: t.chatty,
2297 ctx: ctx,
2298 cancelCtx: cancelCtx,
2299 isSynctest: true,
2300 },
2301 tstate: t.tstate,
2302 }
2303
2304 go tRunner(t2, f)
2305 if !<-t2.signal {
2306
2307
2308 runtime.Goexit()
2309 }
2310 return !t2.failed
2311 }
2312
2313
2314
2315
2316
2317 func (t *T) Deadline() (deadline time.Time, ok bool) {
2318 if t.isSynctest {
2319
2320
2321
2322 panic("testing: t.Deadline called inside synctest bubble")
2323 }
2324 deadline = t.tstate.deadline
2325 return deadline, !deadline.IsZero()
2326 }
2327
2328
2329
2330 type testState struct {
2331 match *matcher
2332 deadline time.Time
2333
2334
2335
2336
2337
2338 isFuzzing bool
2339
2340 mu sync.Mutex
2341
2342
2343 startParallel chan bool
2344
2345
2346
2347 running int
2348
2349
2350 numWaiting int
2351
2352
2353 maxParallel int
2354 }
2355
2356 func newTestState(maxParallel int, m *matcher) *testState {
2357 return &testState{
2358 match: m,
2359 startParallel: make(chan bool),
2360 maxParallel: maxParallel,
2361 running: 1,
2362 }
2363 }
2364
2365 func (s *testState) waitParallel() {
2366 s.mu.Lock()
2367 if s.running < s.maxParallel {
2368 s.running++
2369 s.mu.Unlock()
2370 return
2371 }
2372 s.numWaiting++
2373 s.mu.Unlock()
2374 <-s.startParallel
2375 }
2376
2377 func (s *testState) release() {
2378 s.mu.Lock()
2379 if s.numWaiting == 0 {
2380 s.running--
2381 s.mu.Unlock()
2382 return
2383 }
2384 s.numWaiting--
2385 s.mu.Unlock()
2386 s.startParallel <- true
2387 }
2388
2389
2390
2391 var errMain = errors.New("testing: unexpected use of func Main")
2392
2393 type matchStringOnly func(pat, str string) (bool, error)
2394
2395 func (f matchStringOnly) MatchString(pat, str string) (bool, error) { return f(pat, str) }
2396 func (f matchStringOnly) StartCPUProfile(w io.Writer) error { return errMain }
2397 func (f matchStringOnly) StopCPUProfile() {}
2398 func (f matchStringOnly) WriteProfileTo(string, io.Writer, int) error { return errMain }
2399 func (f matchStringOnly) ModulePath() string { return "" }
2400 func (f matchStringOnly) ImportPath() string { return "" }
2401 func (f matchStringOnly) StartTestLog(io.Writer) {}
2402 func (f matchStringOnly) StopTestLog() error { return errMain }
2403 func (f matchStringOnly) SetPanicOnExit0(bool) {}
2404 func (f matchStringOnly) CoordinateFuzzing(time.Duration, int64, time.Duration, int64, int, []corpusEntry, []reflect.Type, string, string) error {
2405 return errMain
2406 }
2407 func (f matchStringOnly) RunFuzzWorker(func(corpusEntry) error) error { return errMain }
2408 func (f matchStringOnly) ReadCorpus(string, []reflect.Type) ([]corpusEntry, error) {
2409 return nil, errMain
2410 }
2411 func (f matchStringOnly) CheckCorpus([]any, []reflect.Type) error { return nil }
2412 func (f matchStringOnly) ResetCoverage() {}
2413 func (f matchStringOnly) SnapshotCoverage() {}
2414
2415 func (f matchStringOnly) InitRuntimeCoverage() (mode string, tearDown func(string, string) (string, error), snapcov func() float64) {
2416 return
2417 }
2418
2419
2420
2421
2422
2423
2424
2425 func Main(matchString func(pat, str string) (bool, error), tests []InternalTest, benchmarks []InternalBenchmark, examples []InternalExample) {
2426 os.Exit(MainStart(matchStringOnly(matchString), tests, benchmarks, nil, examples).Run())
2427 }
2428
2429
2430 type M struct {
2431 deps testDeps
2432 tests []InternalTest
2433 benchmarks []InternalBenchmark
2434 fuzzTargets []InternalFuzzTarget
2435 examples []InternalExample
2436
2437 timer *time.Timer
2438 afterOnce sync.Once
2439
2440 numRun int
2441
2442
2443
2444 exitCode int
2445 }
2446
2447
2448
2449
2450
2451 type testDeps interface {
2452 ImportPath() string
2453 ModulePath() string
2454 MatchString(pat, str string) (bool, error)
2455 SetPanicOnExit0(bool)
2456 StartCPUProfile(io.Writer) error
2457 StopCPUProfile()
2458 StartTestLog(io.Writer)
2459 StopTestLog() error
2460 WriteProfileTo(string, io.Writer, int) error
2461 CoordinateFuzzing(time.Duration, int64, time.Duration, int64, int, []corpusEntry, []reflect.Type, string, string) error
2462 RunFuzzWorker(func(corpusEntry) error) error
2463 ReadCorpus(string, []reflect.Type) ([]corpusEntry, error)
2464 CheckCorpus([]any, []reflect.Type) error
2465 ResetCoverage()
2466 SnapshotCoverage()
2467 InitRuntimeCoverage() (mode string, tearDown func(coverprofile string, gocoverdir string) (string, error), snapcov func() float64)
2468 }
2469
2470
2471
2472
2473 func MainStart(deps testDeps, tests []InternalTest, benchmarks []InternalBenchmark, fuzzTargets []InternalFuzzTarget, examples []InternalExample) *M {
2474 registerCover(deps.InitRuntimeCoverage())
2475 Init()
2476 return &M{
2477 deps: deps,
2478 tests: tests,
2479 benchmarks: benchmarks,
2480 fuzzTargets: fuzzTargets,
2481 examples: examples,
2482 }
2483 }
2484
2485 var (
2486 testingTesting bool
2487 realStderr *os.File
2488 )
2489
2490
2491
2492
2493
2494 func (m *M) Run() (code int) {
2495 defer func() {
2496 code = m.exitCode
2497 }()
2498
2499
2500
2501
2502
2503 m.numRun++
2504
2505
2506 if !flag.Parsed() {
2507 flag.Parse()
2508 }
2509
2510 if chatty.json {
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
2544 realStderr = os.Stderr
2545 os.Stderr = os.Stdout
2546 }
2547
2548 if *parallel < 1 {
2549 fmt.Fprintln(os.Stderr, "testing: -parallel can only be given a positive integer")
2550 flag.Usage()
2551 m.exitCode = 2
2552 return
2553 }
2554 if *matchFuzz != "" && *fuzzCacheDir == "" {
2555 fmt.Fprintln(os.Stderr, "testing: -test.fuzzcachedir must be set if -test.fuzz is set")
2556 flag.Usage()
2557 m.exitCode = 2
2558 return
2559 }
2560
2561 if *matchList != "" {
2562 listTests(m.deps.MatchString, m.tests, m.benchmarks, m.fuzzTargets, m.examples)
2563 m.exitCode = 0
2564 return
2565 }
2566
2567 if *shuffle != "off" {
2568 var n int64
2569 var err error
2570 if *shuffle == "on" {
2571 n = time.Now().UnixNano()
2572 } else {
2573 n, err = strconv.ParseInt(*shuffle, 10, 64)
2574 if err != nil {
2575 fmt.Fprintln(os.Stderr, `testing: -shuffle should be "off", "on", or a valid integer:`, err)
2576 m.exitCode = 2
2577 return
2578 }
2579 }
2580 fmt.Println("-test.shuffle", n)
2581 rng := rand.New(rand.NewSource(n))
2582 rng.Shuffle(len(m.tests), func(i, j int) { m.tests[i], m.tests[j] = m.tests[j], m.tests[i] })
2583 rng.Shuffle(len(m.benchmarks), func(i, j int) { m.benchmarks[i], m.benchmarks[j] = m.benchmarks[j], m.benchmarks[i] })
2584 }
2585
2586 parseCpuList()
2587
2588 m.before()
2589 defer m.after()
2590
2591
2592
2593
2594 if !*isFuzzWorker {
2595 deadline := m.startAlarm()
2596 haveExamples = len(m.examples) > 0
2597 testRan, testOk := runTests(m.deps.ModulePath(), m.deps.ImportPath(), m.deps.MatchString, m.tests, deadline)
2598 fuzzTargetsRan, fuzzTargetsOk := runFuzzTests(m.deps, m.fuzzTargets, deadline)
2599 exampleRan, exampleOk := runExamples(m.deps.MatchString, m.examples)
2600 m.stopAlarm()
2601 if !testRan && !exampleRan && !fuzzTargetsRan && *matchBenchmarks == "" && *matchFuzz == "" {
2602 fmt.Fprintln(os.Stderr, "testing: warning: no tests to run")
2603 if testingTesting && *match != "^$" {
2604
2605
2606
2607
2608
2609 fmt.Print(chatty.prefix(), "FAIL: package testing must run tests\n")
2610 testOk = false
2611 }
2612 }
2613 anyFailed := !testOk || !exampleOk || !fuzzTargetsOk || !runBenchmarks(m.deps.ImportPath(), m.deps.MatchString, m.benchmarks)
2614 if !anyFailed && race.Errors() > 0 {
2615 fmt.Print(chatty.prefix(), "testing: race detected outside of test execution\n")
2616 anyFailed = true
2617 }
2618 if anyFailed {
2619 fmt.Print(chatty.prefix(), "FAIL\n")
2620 m.exitCode = 1
2621 return
2622 }
2623 }
2624
2625 fuzzingOk := runFuzzing(m.deps, m.fuzzTargets)
2626 if !fuzzingOk {
2627 fmt.Print(chatty.prefix(), "FAIL\n")
2628 if *isFuzzWorker {
2629 m.exitCode = fuzzWorkerExitCode
2630 } else {
2631 m.exitCode = 1
2632 }
2633 return
2634 }
2635
2636 m.exitCode = 0
2637 if !*isFuzzWorker {
2638 fmt.Print(chatty.prefix(), "PASS\n")
2639 }
2640 return
2641 }
2642
2643 func (t *T) report() {
2644 if t.parent == nil {
2645 return
2646 }
2647 if t.isSynctest {
2648 return
2649 }
2650 dstr := fmtDuration(t.duration)
2651 format := "--- %s: %s (%s)\n"
2652 if t.Failed() {
2653 t.flushToParent(t.name, format, "FAIL", t.name, dstr)
2654 } else if t.chatty != nil {
2655 if t.Skipped() {
2656 t.flushToParent(t.name, format, "SKIP", t.name, dstr)
2657 } else {
2658 t.flushToParent(t.name, format, "PASS", t.name, dstr)
2659 }
2660 }
2661 }
2662
2663 func listTests(matchString func(pat, str string) (bool, error), tests []InternalTest, benchmarks []InternalBenchmark, fuzzTargets []InternalFuzzTarget, examples []InternalExample) {
2664 if _, err := matchString(*matchList, "non-empty"); err != nil {
2665 fmt.Fprintf(os.Stderr, "testing: invalid regexp in -test.list (%q): %s\n", *matchList, err)
2666 os.Exit(1)
2667 }
2668
2669 for _, test := range tests {
2670 if ok, _ := matchString(*matchList, test.Name); ok {
2671 fmt.Println(test.Name)
2672 }
2673 }
2674 for _, bench := range benchmarks {
2675 if ok, _ := matchString(*matchList, bench.Name); ok {
2676 fmt.Println(bench.Name)
2677 }
2678 }
2679 for _, fuzzTarget := range fuzzTargets {
2680 if ok, _ := matchString(*matchList, fuzzTarget.Name); ok {
2681 fmt.Println(fuzzTarget.Name)
2682 }
2683 }
2684 for _, example := range examples {
2685 if ok, _ := matchString(*matchList, example.Name); ok {
2686 fmt.Println(example.Name)
2687 }
2688 }
2689 }
2690
2691
2692
2693 func RunTests(matchString func(pat, str string) (bool, error), tests []InternalTest) (ok bool) {
2694 var deadline time.Time
2695 if *timeout > 0 {
2696 deadline = time.Now().Add(*timeout)
2697 }
2698 ran, ok := runTests("", "", matchString, tests, deadline)
2699 if !ran && !haveExamples {
2700 fmt.Fprintln(os.Stderr, "testing: warning: no tests to run")
2701 }
2702 return ok
2703 }
2704
2705 func runTests(modulePath, importPath string, matchString func(pat, str string) (bool, error), tests []InternalTest, deadline time.Time) (ran, ok bool) {
2706 ok = true
2707 for _, procs := range cpuList {
2708 runtime.GOMAXPROCS(procs)
2709 for i := uint(0); i < *count; i++ {
2710 if shouldFailFast() {
2711 break
2712 }
2713 if i > 0 && !ran {
2714
2715
2716
2717 break
2718 }
2719 ctx, cancelCtx := context.WithCancel(context.Background())
2720 tstate := newTestState(*parallel, newMatcher(matchString, *match, "-test.run", *skip))
2721 tstate.deadline = deadline
2722 t := &T{
2723 common: common{
2724 signal: make(chan bool, 1),
2725 barrier: make(chan bool),
2726 w: os.Stdout,
2727 ctx: ctx,
2728 cancelCtx: cancelCtx,
2729 modulePath: modulePath,
2730 importPath: importPath,
2731 },
2732 tstate: tstate,
2733 }
2734 if Verbose() {
2735 t.chatty = newChattyPrinter(t.w)
2736 }
2737 tRunner(t, func(t *T) {
2738 for _, test := range tests {
2739 t.Run(test.Name, test.F)
2740 }
2741 })
2742 select {
2743 case <-t.signal:
2744 default:
2745 panic("internal error: tRunner exited without sending on t.signal")
2746 }
2747 ok = ok && !t.Failed()
2748 ran = ran || t.ran
2749 }
2750 }
2751 return ran, ok
2752 }
2753
2754
2755 func (m *M) before() {
2756 if *memProfileRate > 0 {
2757 runtime.MemProfileRate = *memProfileRate
2758 }
2759 if *cpuProfile != "" {
2760 f, err := os.Create(toOutputDir(*cpuProfile))
2761 if err != nil {
2762 fmt.Fprintf(os.Stderr, "testing: %s\n", err)
2763 return
2764 }
2765 if err := m.deps.StartCPUProfile(f); err != nil {
2766 fmt.Fprintf(os.Stderr, "testing: can't start cpu profile: %s\n", err)
2767 f.Close()
2768 return
2769 }
2770
2771 }
2772 if *traceFile != "" {
2773 f, err := os.Create(toOutputDir(*traceFile))
2774 if err != nil {
2775 fmt.Fprintf(os.Stderr, "testing: %s\n", err)
2776 return
2777 }
2778 if err := trace.Start(f); err != nil {
2779 fmt.Fprintf(os.Stderr, "testing: can't start tracing: %s\n", err)
2780 f.Close()
2781 return
2782 }
2783
2784 }
2785 if *blockProfile != "" && *blockProfileRate >= 0 {
2786 runtime.SetBlockProfileRate(*blockProfileRate)
2787 }
2788 if *mutexProfile != "" && *mutexProfileFraction >= 0 {
2789 runtime.SetMutexProfileFraction(*mutexProfileFraction)
2790 }
2791 if *coverProfile != "" && CoverMode() == "" {
2792 fmt.Fprintf(os.Stderr, "testing: cannot use -test.coverprofile because test binary was not built with coverage enabled\n")
2793 os.Exit(2)
2794 }
2795 if *gocoverdir != "" && CoverMode() == "" {
2796 fmt.Fprintf(os.Stderr, "testing: cannot use -test.gocoverdir because test binary was not built with coverage enabled\n")
2797 os.Exit(2)
2798 }
2799 if *artifacts {
2800 var err error
2801 artifactDir, err = filepath.Abs(toOutputDir("_artifacts"))
2802 if err != nil {
2803 fmt.Fprintf(os.Stderr, "testing: cannot make -test.outputdir absolute: %v\n", err)
2804 os.Exit(2)
2805 }
2806 if err := os.Mkdir(artifactDir, 0o777); err != nil && !errors.Is(err, os.ErrExist) {
2807 fmt.Fprintf(os.Stderr, "testing: %v\n", err)
2808 os.Exit(2)
2809 }
2810 }
2811 if *testlog != "" {
2812
2813
2814 var f *os.File
2815 var err error
2816 if m.numRun == 1 {
2817 f, err = os.Create(*testlog)
2818 } else {
2819 f, err = os.OpenFile(*testlog, os.O_WRONLY, 0)
2820 if err == nil {
2821 f.Seek(0, io.SeekEnd)
2822 }
2823 }
2824 if err != nil {
2825 fmt.Fprintf(os.Stderr, "testing: %s\n", err)
2826 os.Exit(2)
2827 }
2828 m.deps.StartTestLog(f)
2829 testlogFile = f
2830 }
2831 if *panicOnExit0 {
2832 m.deps.SetPanicOnExit0(true)
2833 }
2834 }
2835
2836
2837 func (m *M) after() {
2838 m.afterOnce.Do(func() {
2839 m.writeProfiles()
2840 })
2841
2842
2843
2844
2845 if *panicOnExit0 {
2846 m.deps.SetPanicOnExit0(false)
2847 }
2848 }
2849
2850 func (m *M) writeProfiles() {
2851 if *testlog != "" {
2852 if err := m.deps.StopTestLog(); err != nil {
2853 fmt.Fprintf(os.Stderr, "testing: can't write %s: %s\n", *testlog, err)
2854 os.Exit(2)
2855 }
2856 if err := testlogFile.Close(); err != nil {
2857 fmt.Fprintf(os.Stderr, "testing: can't write %s: %s\n", *testlog, err)
2858 os.Exit(2)
2859 }
2860 }
2861 if *cpuProfile != "" {
2862 m.deps.StopCPUProfile()
2863 }
2864 if *traceFile != "" {
2865 trace.Stop()
2866 }
2867 if *memProfile != "" {
2868 f, err := os.Create(toOutputDir(*memProfile))
2869 if err != nil {
2870 fmt.Fprintf(os.Stderr, "testing: %s\n", err)
2871 os.Exit(2)
2872 }
2873 runtime.GC()
2874 if err = m.deps.WriteProfileTo("allocs", f, 0); err != nil {
2875 fmt.Fprintf(os.Stderr, "testing: can't write %s: %s\n", *memProfile, err)
2876 os.Exit(2)
2877 }
2878 f.Close()
2879 }
2880 if *blockProfile != "" && *blockProfileRate >= 0 {
2881 f, err := os.Create(toOutputDir(*blockProfile))
2882 if err != nil {
2883 fmt.Fprintf(os.Stderr, "testing: %s\n", err)
2884 os.Exit(2)
2885 }
2886 if err = m.deps.WriteProfileTo("block", f, 0); err != nil {
2887 fmt.Fprintf(os.Stderr, "testing: can't write %s: %s\n", *blockProfile, err)
2888 os.Exit(2)
2889 }
2890 f.Close()
2891 }
2892 if *mutexProfile != "" && *mutexProfileFraction >= 0 {
2893 f, err := os.Create(toOutputDir(*mutexProfile))
2894 if err != nil {
2895 fmt.Fprintf(os.Stderr, "testing: %s\n", err)
2896 os.Exit(2)
2897 }
2898 if err = m.deps.WriteProfileTo("mutex", f, 0); err != nil {
2899 fmt.Fprintf(os.Stderr, "testing: can't write %s: %s\n", *mutexProfile, err)
2900 os.Exit(2)
2901 }
2902 f.Close()
2903 }
2904 if CoverMode() != "" {
2905 coverReport()
2906 }
2907 }
2908
2909
2910
2911 func toOutputDir(path string) string {
2912 if *outputDir == "" || path == "" {
2913 return path
2914 }
2915
2916
2917
2918
2919
2920
2921
2922 if runtime.GOOS == "windows" && len(path) >= 2 {
2923 letter, colon := path[0], path[1]
2924 if ('a' <= letter && letter <= 'z' || 'A' <= letter && letter <= 'Z') && colon == ':' {
2925
2926 return path
2927 }
2928 }
2929 if os.IsPathSeparator(path[0]) {
2930 return path
2931 }
2932 return fmt.Sprintf("%s%c%s", *outputDir, os.PathSeparator, path)
2933 }
2934
2935
2936 func (m *M) startAlarm() time.Time {
2937 if *timeout <= 0 {
2938 return time.Time{}
2939 }
2940
2941 deadline := time.Now().Add(*timeout)
2942 m.timer = time.AfterFunc(*timeout, func() {
2943 m.after()
2944 debug.SetTraceback("all")
2945 extra := ""
2946
2947 if list := runningList(); len(list) > 0 {
2948 var b strings.Builder
2949 b.WriteString("\nrunning tests:")
2950 for _, name := range list {
2951 b.WriteString("\n\t")
2952 b.WriteString(name)
2953 }
2954 extra = b.String()
2955 }
2956 panic(fmt.Sprintf("test timed out after %v%s", *timeout, extra))
2957 })
2958 return deadline
2959 }
2960
2961
2962 func runningList() []string {
2963 var list []string
2964 running.Range(func(k, v any) bool {
2965 list = append(list, fmt.Sprintf("%s (%v)", k.(string), highPrecisionTimeSince(v.(highPrecisionTime)).Round(time.Second)))
2966 return true
2967 })
2968 slices.Sort(list)
2969 return list
2970 }
2971
2972
2973 func (m *M) stopAlarm() {
2974 if *timeout > 0 {
2975 m.timer.Stop()
2976 }
2977 }
2978
2979 func parseCpuList() {
2980 for val := range strings.SplitSeq(*cpuListStr, ",") {
2981 val = strings.TrimSpace(val)
2982 if val == "" {
2983 continue
2984 }
2985 cpu, err := strconv.Atoi(val)
2986 if err != nil || cpu <= 0 {
2987 fmt.Fprintf(os.Stderr, "testing: invalid value %q for -test.cpu\n", val)
2988 os.Exit(1)
2989 }
2990 cpuList = append(cpuList, cpu)
2991 }
2992 if cpuList == nil {
2993 cpuList = append(cpuList, runtime.GOMAXPROCS(-1))
2994 }
2995 }
2996
2997 func shouldFailFast() bool {
2998 return *failFast && numFailed.Load() > 0
2999 }
3000
View as plain text