Source file
src/testing/testing_test.go
1
2
3
4
5 package testing_test
6
7 import (
8 "bytes"
9 "context"
10 "errors"
11 "fmt"
12 "internal/race"
13 "internal/testenv"
14 "os"
15 "os/exec"
16 "path/filepath"
17 "regexp"
18 "runtime"
19 "slices"
20 "strings"
21 "sync"
22 "testing"
23 "time"
24 )
25
26
27
28
29
30 func TestMain(m *testing.M) {
31 if os.Getenv("GO_WANT_RACE_BEFORE_TESTS") == "1" {
32 doRace()
33 }
34
35 m.Run()
36
37
38
39
40
41
42
43
44
45
46
47 }
48
49 func TestTempDirInCleanup(t *testing.T) {
50 var dir string
51
52 t.Run("test", func(t *testing.T) {
53 t.Cleanup(func() {
54 dir = t.TempDir()
55 })
56 _ = t.TempDir()
57 })
58
59 fi, err := os.Stat(dir)
60 if fi != nil {
61 t.Fatalf("Directory %q from user Cleanup still exists", dir)
62 }
63 if !os.IsNotExist(err) {
64 t.Fatalf("Unexpected error: %v", err)
65 }
66 }
67
68 func TestTempDirInBenchmark(t *testing.T) {
69 testing.Benchmark(func(b *testing.B) {
70 if !b.Run("test", func(b *testing.B) {
71
72 for i := 0; i < b.N; i++ {
73 _ = b.TempDir()
74 }
75 }) {
76 t.Fatal("Sub test failure in a benchmark")
77 }
78 })
79 }
80
81 func TestTempDir(t *testing.T) {
82 testTempDir(t)
83 t.Run("InSubtest", testTempDir)
84 t.Run("test/subtest", testTempDir)
85 t.Run("test\\subtest", testTempDir)
86 t.Run("test:subtest", testTempDir)
87 t.Run("test/..", testTempDir)
88 t.Run("../test", testTempDir)
89 t.Run("test[]", testTempDir)
90 t.Run("test*", testTempDir)
91 t.Run("äöüéè", testTempDir)
92 t.Run(strings.Repeat("a", 300), testTempDir)
93 }
94
95 func testTempDir(t *testing.T) {
96 dirCh := make(chan string, 1)
97 t.Cleanup(func() {
98
99 select {
100 case dir := <-dirCh:
101 fi, err := os.Stat(dir)
102 if os.IsNotExist(err) {
103
104 return
105 }
106 if err != nil {
107 t.Fatal(err)
108 }
109 t.Errorf("directory %q still exists: %v, isDir=%v", dir, fi, fi.IsDir())
110 default:
111 if !t.Failed() {
112 t.Fatal("never received dir channel")
113 }
114 }
115 })
116
117 dir := t.TempDir()
118 if dir == "" {
119 t.Fatal("expected dir")
120 }
121 dir2 := t.TempDir()
122 if dir == dir2 {
123 t.Fatal("subsequent calls to TempDir returned the same directory")
124 }
125 if filepath.Dir(dir) != filepath.Dir(dir2) {
126 t.Fatalf("calls to TempDir do not share a parent; got %q, %q", dir, dir2)
127 }
128 dirCh <- dir
129 fi, err := os.Stat(dir)
130 if err != nil {
131 t.Fatal(err)
132 }
133 if !fi.IsDir() {
134 t.Errorf("dir %q is not a dir", dir)
135 }
136 files, err := os.ReadDir(dir)
137 if err != nil {
138 t.Fatal(err)
139 }
140 if len(files) > 0 {
141 t.Errorf("unexpected %d files in TempDir: %v", len(files), files)
142 }
143
144 glob := filepath.Join(dir, "*.txt")
145 if _, err := filepath.Glob(glob); err != nil {
146 t.Error(err)
147 }
148 }
149
150 func TestSetenv(t *testing.T) {
151 tests := []struct {
152 name string
153 key string
154 initialValueExists bool
155 initialValue string
156 newValue string
157 }{
158 {
159 name: "initial value exists",
160 key: "GO_TEST_KEY_1",
161 initialValueExists: true,
162 initialValue: "111",
163 newValue: "222",
164 },
165 {
166 name: "initial value exists but empty",
167 key: "GO_TEST_KEY_2",
168 initialValueExists: true,
169 initialValue: "",
170 newValue: "222",
171 },
172 {
173 name: "initial value is not exists",
174 key: "GO_TEST_KEY_3",
175 initialValueExists: false,
176 initialValue: "",
177 newValue: "222",
178 },
179 }
180
181 for _, test := range tests {
182 if test.initialValueExists {
183 if err := os.Setenv(test.key, test.initialValue); err != nil {
184 t.Fatalf("unable to set env: got %v", err)
185 }
186 } else {
187 os.Unsetenv(test.key)
188 }
189
190 t.Run(test.name, func(t *testing.T) {
191 t.Setenv(test.key, test.newValue)
192 if os.Getenv(test.key) != test.newValue {
193 t.Fatalf("unexpected value after t.Setenv: got %s, want %s", os.Getenv(test.key), test.newValue)
194 }
195 })
196
197 got, exists := os.LookupEnv(test.key)
198 if got != test.initialValue {
199 t.Fatalf("unexpected value after t.Setenv cleanup: got %s, want %s", got, test.initialValue)
200 }
201 if exists != test.initialValueExists {
202 t.Fatalf("unexpected value after t.Setenv cleanup: got %t, want %t", exists, test.initialValueExists)
203 }
204 }
205 }
206
207 func expectParallelConflict(t *testing.T) {
208 want := testing.ParallelConflict
209 if got := recover(); got != want {
210 t.Fatalf("expected panic; got %#v want %q", got, want)
211 }
212 }
213
214 func testWithParallelAfter(t *testing.T, fn func(*testing.T)) {
215 defer expectParallelConflict(t)
216
217 fn(t)
218 t.Parallel()
219 }
220
221 func testWithParallelBefore(t *testing.T, fn func(*testing.T)) {
222 defer expectParallelConflict(t)
223
224 t.Parallel()
225 fn(t)
226 }
227
228 func testWithParallelParentBefore(t *testing.T, fn func(*testing.T)) {
229 t.Parallel()
230
231 t.Run("child", func(t *testing.T) {
232 defer expectParallelConflict(t)
233
234 fn(t)
235 })
236 }
237
238 func testWithParallelGrandParentBefore(t *testing.T, fn func(*testing.T)) {
239 t.Parallel()
240
241 t.Run("child", func(t *testing.T) {
242 t.Run("grand-child", func(t *testing.T) {
243 defer expectParallelConflict(t)
244
245 fn(t)
246 })
247 })
248 }
249
250 func tSetenv(t *testing.T) {
251 t.Setenv("GO_TEST_KEY_1", "value")
252 }
253
254 func TestSetenvWithParallelAfter(t *testing.T) {
255 testWithParallelAfter(t, tSetenv)
256 }
257
258 func TestSetenvWithParallelBefore(t *testing.T) {
259 testWithParallelBefore(t, tSetenv)
260 }
261
262 func TestSetenvWithParallelParentBefore(t *testing.T) {
263 testWithParallelParentBefore(t, tSetenv)
264 }
265
266 func TestSetenvWithParallelGrandParentBefore(t *testing.T) {
267 testWithParallelGrandParentBefore(t, tSetenv)
268 }
269
270 func tChdir(t *testing.T) {
271 t.Chdir(t.TempDir())
272 }
273
274 func TestChdirWithParallelAfter(t *testing.T) {
275 testWithParallelAfter(t, tChdir)
276 }
277
278 func TestChdirWithParallelBefore(t *testing.T) {
279 testWithParallelBefore(t, tChdir)
280 }
281
282 func TestChdirWithParallelParentBefore(t *testing.T) {
283 testWithParallelParentBefore(t, tChdir)
284 }
285
286 func TestChdirWithParallelGrandParentBefore(t *testing.T) {
287 testWithParallelGrandParentBefore(t, tChdir)
288 }
289
290 func TestChdir(t *testing.T) {
291 oldDir, err := os.Getwd()
292 if err != nil {
293 t.Fatal(err)
294 }
295 defer os.Chdir(oldDir)
296
297
298 tmp, err := filepath.EvalSymlinks(t.TempDir())
299 if err != nil {
300 t.Fatal(err)
301 }
302 rel, err := filepath.Rel(oldDir, tmp)
303 if err != nil {
304
305
306 rel = "skip"
307 }
308
309 for _, tc := range []struct {
310 name, dir, pwd string
311 extraChdir bool
312 }{
313 {
314 name: "absolute",
315 dir: tmp,
316 pwd: tmp,
317 },
318 {
319 name: "relative",
320 dir: rel,
321 pwd: tmp,
322 },
323 {
324 name: "current (absolute)",
325 dir: oldDir,
326 pwd: oldDir,
327 },
328 {
329 name: "current (relative) with extra os.Chdir",
330 dir: ".",
331 pwd: oldDir,
332
333 extraChdir: true,
334 },
335 } {
336 t.Run(tc.name, func(t *testing.T) {
337 if tc.dir == "skip" {
338 t.Skipf("skipping test because there is no relative path between %s and %s", oldDir, tmp)
339 }
340 if !filepath.IsAbs(tc.pwd) {
341 t.Fatalf("Bad tc.pwd: %q (must be absolute)", tc.pwd)
342 }
343
344 t.Chdir(tc.dir)
345
346 newDir, err := os.Getwd()
347 if err != nil {
348 t.Fatal(err)
349 }
350 if newDir != tc.pwd {
351 t.Fatalf("failed to chdir to %q: getwd: got %q, want %q", tc.dir, newDir, tc.pwd)
352 }
353
354 switch runtime.GOOS {
355 case "windows", "plan9":
356
357 default:
358 if pwd := os.Getenv("PWD"); pwd != tc.pwd {
359 t.Fatalf("PWD: got %q, want %q", pwd, tc.pwd)
360 }
361 }
362
363 if tc.extraChdir {
364 os.Chdir("..")
365 }
366 })
367
368 newDir, err := os.Getwd()
369 if err != nil {
370 t.Fatal(err)
371 }
372 if newDir != oldDir {
373 t.Fatalf("failed to restore wd to %s: getwd: %s", oldDir, newDir)
374 }
375 }
376 }
377
378
379 var testingTrueInInit = false
380
381
382 var testingTrueInPackageVarInit = testing.Testing()
383
384
385 func init() {
386 if testing.Testing() {
387 testingTrueInInit = true
388 }
389 }
390
391 var testingProg = `
392 package main
393
394 import (
395 "fmt"
396 "testing"
397 )
398
399 func main() {
400 fmt.Println(testing.Testing())
401 }
402 `
403
404 func TestTesting(t *testing.T) {
405 if !testing.Testing() {
406 t.Errorf("testing.Testing() == %t, want %t", testing.Testing(), true)
407 }
408 if !testingTrueInInit {
409 t.Errorf("testing.Testing() called by init function == %t, want %t", testingTrueInInit, true)
410 }
411 if !testingTrueInPackageVarInit {
412 t.Errorf("testing.Testing() variable initialized as %t, want %t", testingTrueInPackageVarInit, true)
413 }
414
415 if testing.Short() {
416 t.Skip("skipping building a binary in short mode")
417 }
418 testenv.MustHaveGoRun(t)
419
420 fn := filepath.Join(t.TempDir(), "x.go")
421 if err := os.WriteFile(fn, []byte(testingProg), 0644); err != nil {
422 t.Fatal(err)
423 }
424
425 cmd := testenv.Command(t, testenv.GoToolPath(t), "run", fn)
426 out, err := cmd.CombinedOutput()
427 if err != nil {
428 t.Fatalf("%v failed: %v\n%s", cmd, err, out)
429 }
430
431 s := string(bytes.TrimSpace(out))
432 if s != "false" {
433 t.Errorf("in non-test testing.Test() returned %q, want %q", s, "false")
434 }
435 }
436
437
438
439 func runTest(t *testing.T, test string) []byte {
440 t.Helper()
441
442 testenv.MustHaveExec(t)
443
444 cmd := testenv.Command(t, testenv.Executable(t), "-test.run=^"+test+"$", "-test.bench="+test, "-test.v", "-test.parallel=2", "-test.benchtime=2x")
445 cmd = testenv.CleanCmdEnv(cmd)
446 cmd.Env = append(cmd.Env, "GO_WANT_HELPER_PROCESS=1")
447 out, err := cmd.CombinedOutput()
448 t.Logf("%v: %v\n%s", cmd, err, out)
449
450 return out
451 }
452
453
454
455 func doRace() {
456 var x int
457 c1 := make(chan bool)
458 go func() {
459 x = 1
460 c1 <- true
461 }()
462 _ = x
463 <-c1
464 }
465
466 func TestRaceReports(t *testing.T) {
467 if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" {
468
469 t.Run("Sub", func(t *testing.T) {
470 doRace()
471 })
472 return
473 }
474
475 out := runTest(t, "TestRaceReports")
476
477
478 c := bytes.Count(out, []byte("race detected"))
479 want := 0
480 if race.Enabled {
481 want = 1
482 }
483 if c != want {
484 t.Errorf("got %d race reports, want %d", c, want)
485 }
486 }
487
488
489 func TestRaceName(t *testing.T) {
490 if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" {
491 doRace()
492 return
493 }
494
495 out := runTest(t, "TestRaceName")
496
497 if regexp.MustCompile(`=== NAME\s*$`).Match(out) {
498 t.Errorf("incorrectly reported test with no name")
499 }
500 }
501
502 func TestRaceSubReports(t *testing.T) {
503 if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" {
504 t.Parallel()
505 c1 := make(chan bool, 1)
506 t.Run("sub", func(t *testing.T) {
507 t.Run("subsub1", func(t *testing.T) {
508 t.Parallel()
509 doRace()
510 c1 <- true
511 })
512 t.Run("subsub2", func(t *testing.T) {
513 t.Parallel()
514 doRace()
515 <-c1
516 })
517 })
518 doRace()
519 return
520 }
521
522 out := runTest(t, "TestRaceSubReports")
523
524
525
526
527
528 cReport := bytes.Count(out, []byte("race detected during execution of test"))
529 wantReport := 0
530 if race.Enabled {
531 wantReport = 3
532 }
533 if cReport != wantReport {
534 t.Errorf("got %d race reports, want %d", cReport, wantReport)
535 }
536
537
538
539 cFail := bytes.Count(out, []byte("--- FAIL:"))
540 wantFail := 0
541 if race.Enabled {
542 wantFail = 4
543 }
544 if cFail != wantFail {
545 t.Errorf(`got %d "--- FAIL:" lines, want %d`, cReport, wantReport)
546 }
547 }
548
549 func TestRaceInCleanup(t *testing.T) {
550 if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" {
551 t.Cleanup(doRace)
552 t.Parallel()
553 t.Run("sub", func(t *testing.T) {
554 t.Parallel()
555
556 })
557 return
558 }
559
560 out := runTest(t, "TestRaceInCleanup")
561
562
563 cReport := bytes.Count(out, []byte("race detected during execution of test"))
564 wantReport := 0
565 if race.Enabled {
566 wantReport = 1
567 }
568 if cReport != wantReport {
569 t.Errorf("got %d race reports, want %d", cReport, wantReport)
570 }
571
572
573
574 cFail := bytes.Count(out, []byte("--- FAIL:"))
575 wantFail := 0
576 if race.Enabled {
577 wantFail = 1
578 }
579 if cFail != wantFail {
580 t.Errorf(`got %d "--- FAIL:" lines, want %d`, cReport, wantReport)
581 }
582 }
583
584 func TestDeepSubtestRace(t *testing.T) {
585 if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" {
586 t.Run("sub", func(t *testing.T) {
587 t.Run("subsub", func(t *testing.T) {
588 t.Run("subsubsub", func(t *testing.T) {
589 doRace()
590 })
591 })
592 doRace()
593 })
594 return
595 }
596
597 out := runTest(t, "TestDeepSubtestRace")
598
599 c := bytes.Count(out, []byte("race detected during execution of test"))
600 want := 0
601
602 if race.Enabled {
603 want = 2
604 }
605 if c != want {
606 t.Errorf("got %d race reports, want %d", c, want)
607 }
608 }
609
610 func TestRaceDuringParallelFailsAllSubtests(t *testing.T) {
611 if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" {
612 var ready sync.WaitGroup
613 ready.Add(2)
614 done := make(chan struct{})
615 go func() {
616 ready.Wait()
617 doRace()
618 close(done)
619 }()
620
621 t.Run("sub", func(t *testing.T) {
622 t.Run("subsub1", func(t *testing.T) {
623 t.Parallel()
624 ready.Done()
625 <-done
626 })
627 t.Run("subsub2", func(t *testing.T) {
628 t.Parallel()
629 ready.Done()
630 <-done
631 })
632 })
633
634 return
635 }
636
637 out := runTest(t, "TestRaceDuringParallelFailsAllSubtests")
638
639 c := bytes.Count(out, []byte("race detected during execution of test"))
640 want := 0
641
642 if race.Enabled {
643 want = 2
644 }
645 if c != want {
646 t.Errorf("got %d race reports, want %d", c, want)
647 }
648 }
649
650 func TestRaceBeforeParallel(t *testing.T) {
651 if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" {
652 t.Run("sub", func(t *testing.T) {
653 doRace()
654 t.Parallel()
655 })
656 return
657 }
658
659 out := runTest(t, "TestRaceBeforeParallel")
660
661 c := bytes.Count(out, []byte("race detected during execution of test"))
662 want := 0
663
664 if race.Enabled {
665 want = 1
666 }
667 if c != want {
668 t.Errorf("got %d race reports, want %d", c, want)
669 }
670 }
671
672 func TestRaceBeforeTests(t *testing.T) {
673 cmd := testenv.Command(t, testenv.Executable(t), "-test.run=^$")
674 cmd = testenv.CleanCmdEnv(cmd)
675 cmd.Env = append(cmd.Env, "GO_WANT_RACE_BEFORE_TESTS=1")
676 out, _ := cmd.CombinedOutput()
677 t.Logf("%s", out)
678
679 c := bytes.Count(out, []byte("race detected outside of test execution"))
680
681 want := 0
682 if race.Enabled {
683 want = 1
684 }
685 if c != want {
686 t.Errorf("got %d race reports; want %d", c, want)
687 }
688 }
689
690 func TestBenchmarkRace(t *testing.T) {
691 out := runTest(t, "BenchmarkRacy")
692 c := bytes.Count(out, []byte("race detected during execution of test"))
693
694 want := 0
695
696 if race.Enabled {
697 want = 1
698 }
699 if c != want {
700 t.Errorf("got %d race reports; want %d", c, want)
701 }
702 }
703
704 func TestBenchmarkRaceBLoop(t *testing.T) {
705 out := runTest(t, "BenchmarkBLoopRacy")
706 c := bytes.Count(out, []byte("race detected during execution of test"))
707
708 want := 0
709
710 if race.Enabled {
711 want = 1
712 }
713 if c != want {
714 t.Errorf("got %d race reports; want %d", c, want)
715 }
716 }
717
718 func BenchmarkRacy(b *testing.B) {
719 if os.Getenv("GO_WANT_HELPER_PROCESS") != "1" {
720 b.Skipf("skipping intentionally-racy benchmark")
721 }
722 for i := 0; i < b.N; i++ {
723 doRace()
724 }
725 }
726
727 func BenchmarkBLoopRacy(b *testing.B) {
728 if os.Getenv("GO_WANT_HELPER_PROCESS") != "1" {
729 b.Skipf("skipping intentionally-racy benchmark")
730 }
731 for b.Loop() {
732 doRace()
733 }
734 }
735
736 func TestBenchmarkSubRace(t *testing.T) {
737 out := runTest(t, "BenchmarkSubRacy")
738 c := bytes.Count(out, []byte("race detected during execution of test"))
739
740 want := 0
741
742
743
744 if race.Enabled {
745 want = 3
746 }
747 if c != want {
748 t.Errorf("got %d race reports; want %d", c, want)
749 }
750 }
751
752 func BenchmarkSubRacy(b *testing.B) {
753 if os.Getenv("GO_WANT_HELPER_PROCESS") != "1" {
754 b.Skipf("skipping intentionally-racy benchmark")
755 }
756
757 b.Run("non-racy", func(b *testing.B) {
758 tot := 0
759 for i := 0; i < b.N; i++ {
760 tot++
761 }
762 _ = tot
763 })
764
765 b.Run("racy", func(b *testing.B) {
766 for i := 0; i < b.N; i++ {
767 doRace()
768 }
769 })
770
771 b.Run("racy-bLoop", func(b *testing.B) {
772 for b.Loop() {
773 doRace()
774 }
775 })
776
777 doRace()
778 }
779
780 func TestRunningTests(t *testing.T) {
781 t.Parallel()
782
783
784
785
786
787 if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" {
788 for i := 0; i < 2; i++ {
789 t.Run(fmt.Sprintf("outer%d", i), func(t *testing.T) {
790 t.Parallel()
791 for j := 0; j < 2; j++ {
792 t.Run(fmt.Sprintf("inner%d", j), func(t *testing.T) {
793 t.Parallel()
794 for {
795 time.Sleep(1 * time.Millisecond)
796 }
797 })
798 }
799 })
800 }
801 }
802
803 timeout := 10 * time.Millisecond
804 for {
805 cmd := testenv.Command(t, testenv.Executable(t), "-test.run=^"+t.Name()+"$", "-test.timeout="+timeout.String(), "-test.parallel=4")
806 cmd.Env = append(cmd.Environ(), "GO_WANT_HELPER_PROCESS=1")
807 out, err := cmd.CombinedOutput()
808 t.Logf("%v:\n%s", cmd, out)
809 if _, ok := err.(*exec.ExitError); !ok {
810 t.Fatal(err)
811 }
812
813
814
815
816
817 want := []string{
818 "TestRunningTests/outer0/inner0",
819 "TestRunningTests/outer0/inner1",
820 "TestRunningTests/outer1/inner0",
821 "TestRunningTests/outer1/inner1",
822 }
823
824 got, ok := parseRunningTests(out)
825 if slices.Equal(got, want) {
826 break
827 }
828 if ok {
829 t.Logf("found running tests:\n%s\nwant:\n%s", strings.Join(got, "\n"), strings.Join(want, "\n"))
830 } else {
831 t.Logf("no running tests found")
832 }
833 t.Logf("retrying with longer timeout")
834 timeout *= 2
835 }
836 }
837
838 func TestRunningTestsInCleanup(t *testing.T) {
839 t.Parallel()
840
841 if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" {
842 for i := 0; i < 2; i++ {
843 t.Run(fmt.Sprintf("outer%d", i), func(t *testing.T) {
844
845
846
847 t.Cleanup(func() {
848 for {
849 time.Sleep(1 * time.Millisecond)
850 }
851 })
852
853 for j := 0; j < 2; j++ {
854 t.Run(fmt.Sprintf("inner%d", j), func(t *testing.T) {
855 t.Parallel()
856 })
857 }
858 })
859 }
860 }
861
862 timeout := 10 * time.Millisecond
863 for {
864 cmd := testenv.Command(t, testenv.Executable(t), "-test.run=^"+t.Name()+"$", "-test.timeout="+timeout.String())
865 cmd.Env = append(cmd.Environ(), "GO_WANT_HELPER_PROCESS=1")
866 out, err := cmd.CombinedOutput()
867 t.Logf("%v:\n%s", cmd, out)
868 if _, ok := err.(*exec.ExitError); !ok {
869 t.Fatal(err)
870 }
871
872
873
874
875
876
877 want := []string{
878 "TestRunningTestsInCleanup",
879 "TestRunningTestsInCleanup/outer0",
880 }
881
882 got, ok := parseRunningTests(out)
883 if slices.Equal(got, want) {
884 break
885 }
886 if ok {
887 t.Logf("found running tests:\n%s\nwant:\n%s", strings.Join(got, "\n"), strings.Join(want, "\n"))
888 } else {
889 t.Logf("no running tests found")
890 }
891 t.Logf("retrying with longer timeout")
892 timeout *= 2
893 }
894 }
895
896 func parseRunningTests(out []byte) (runningTests []string, ok bool) {
897 inRunningTests := false
898 for line := range strings.SplitSeq(string(out), "\n") {
899 if inRunningTests {
900
901 if trimmed, ok := strings.CutPrefix(line, "\t\t"); ok {
902 if name, _, ok := strings.Cut(trimmed, " "); ok {
903 runningTests = append(runningTests, name)
904 continue
905 }
906 }
907
908
909 return runningTests, true
910 }
911
912 if strings.TrimSpace(line) == "running tests:" {
913 inRunningTests = true
914 }
915 }
916
917 return nil, false
918 }
919
920 func TestConcurrentRun(t *testing.T) {
921
922
923
924 block := make(chan struct{})
925 var ready, done sync.WaitGroup
926 for i := 0; i < 2; i++ {
927 ready.Add(1)
928 done.Add(1)
929 go t.Run("", func(*testing.T) {
930 ready.Done()
931 <-block
932 done.Done()
933 })
934 }
935 ready.Wait()
936 close(block)
937 done.Wait()
938 }
939
940 func TestParentRun(t1 *testing.T) {
941
942
943
944 t1.Run("outer", func(t2 *testing.T) {
945 t2.Log("Hello outer!")
946 t1.Run("not_inner", func(t3 *testing.T) {
947 t3.Log("Hello inner!")
948 })
949 })
950 }
951
952 func TestContext(t *testing.T) {
953 ctx := t.Context()
954 if err := ctx.Err(); err != nil {
955 t.Fatalf("expected non-canceled context, got %v", err)
956 }
957
958 var innerCtx context.Context
959 t.Run("inner", func(t *testing.T) {
960 innerCtx = t.Context()
961 if err := innerCtx.Err(); err != nil {
962 t.Fatalf("expected inner test to not inherit canceled context, got %v", err)
963 }
964 })
965 t.Run("inner2", func(t *testing.T) {
966 if !errors.Is(innerCtx.Err(), context.Canceled) {
967 t.Fatal("expected context of sibling test to be canceled after its test function finished")
968 }
969 })
970
971 t.Cleanup(func() {
972 if !errors.Is(ctx.Err(), context.Canceled) {
973 t.Fatal("expected context canceled before cleanup")
974 }
975 })
976 }
977
978
979
980 func TestAttrExample(t *testing.T) {
981 t.Attr("key", "value")
982 }
983
984 func TestAttrSet(t *testing.T) {
985 out := string(runTest(t, "TestAttrExample"))
986
987 want := "=== ATTR TestAttrExample key value\n"
988 if !strings.Contains(out, want) {
989 t.Errorf("expected output containing %q, got:\n%q", want, out)
990 }
991 }
992
993 func TestAttrInvalid(t *testing.T) {
994 tests := []struct {
995 key string
996 value string
997 }{
998 {"k ey", "value"},
999 {"k\tey", "value"},
1000 {"k\rey", "value"},
1001 {"k\ney", "value"},
1002 {"key", "val\rue"},
1003 {"key", "val\nue"},
1004 }
1005
1006 if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" {
1007 for i, test := range tests {
1008 t.Run(fmt.Sprint(i), func(t *testing.T) {
1009 t.Attr(test.key, test.value)
1010 })
1011 }
1012 return
1013 }
1014
1015 out := string(runTest(t, "TestAttrInvalid"))
1016
1017 for i := range tests {
1018 want := fmt.Sprintf("--- FAIL: TestAttrInvalid/%v ", i)
1019 if !strings.Contains(out, want) {
1020 t.Errorf("expected output containing %q, got:\n%q", want, out)
1021 }
1022 }
1023 }
1024
1025 func TestBenchmarkBLoopIterationCorrect(t *testing.T) {
1026 out := runTest(t, "BenchmarkBLoopPrint")
1027 c := bytes.Count(out, []byte("Printing from BenchmarkBLoopPrint"))
1028
1029 want := 2
1030 if c != want {
1031 t.Errorf("got %d loop iterations; want %d", c, want)
1032 }
1033
1034
1035 c = bytes.Count(out, []byte("Ramping up from BenchmarkBLoopPrint"))
1036 want = 1
1037 if c != want {
1038 t.Errorf("got %d loop rampup; want %d", c, want)
1039 }
1040
1041 re := regexp.MustCompile(`BenchmarkBLoopPrint(-[0-9]+)?\s+2\s+[0-9]+\s+ns/op`)
1042 if !re.Match(out) {
1043 t.Error("missing benchmark output")
1044 }
1045 }
1046
1047 func TestBenchmarkBNIterationCorrect(t *testing.T) {
1048 out := runTest(t, "BenchmarkBNPrint")
1049 c := bytes.Count(out, []byte("Printing from BenchmarkBNPrint"))
1050
1051
1052
1053 want := 3
1054 if c != want {
1055 t.Errorf("got %d loop iterations; want %d", c, want)
1056 }
1057
1058
1059
1060 c = bytes.Count(out, []byte("Ramping up from BenchmarkBNPrint"))
1061 want = 2
1062 if c != want {
1063 t.Errorf("got %d loop rampup; want %d", c, want)
1064 }
1065 }
1066
1067 func BenchmarkBLoopPrint(b *testing.B) {
1068 b.Logf("Ramping up from BenchmarkBLoopPrint")
1069 for b.Loop() {
1070 b.Logf("Printing from BenchmarkBLoopPrint")
1071 }
1072 }
1073
1074 func BenchmarkBNPrint(b *testing.B) {
1075 b.Logf("Ramping up from BenchmarkBNPrint")
1076 for i := 0; i < b.N; i++ {
1077 b.Logf("Printing from BenchmarkBNPrint")
1078 }
1079 }
1080
View as plain text