Skip to content

Commit afa150c

Browse files
changkunodeke-em
authored andcommitted
testing: fail Example tests that invoke runtime.Goexit
Previously, if an example test invoked runtime.Goexit, it would pass yet hang until a timeout, while regular tests that invoke runtime.Goexit do fail. This change removes that inconsistent behavior and makes such example tests fail, and panic with an indication of having invoked runtime.Goexit. Fixes #41084 Change-Id: I0ffa152204f2b1580f4d5d6961ba1ce6b13fc022 Reviewed-on: https://go-review.googlesource.com/c/go/+/251857 Reviewed-by: Emmanuel Odeke <[email protected]> Reviewed-by: Bryan C. Mills <[email protected]> Run-TryBot: Bryan C. Mills <[email protected]> TryBot-Result: Gobot Gobot <[email protected]>
1 parent ac55d58 commit afa150c

File tree

4 files changed

+39
-5
lines changed

4 files changed

+39
-5
lines changed
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# For issue golang.org/issue/41084
2+
[short] skip
3+
4+
! go test -v examplegoexit
5+
stdout '(?s)--- PASS.*--- FAIL.*'
6+
stdout 'panic: test executed panic\(nil\) or runtime\.Goexit'
7+
8+
-- examplegoexit/example_test.go --
9+
package main
10+
11+
import (
12+
"fmt"
13+
"runtime"
14+
)
15+
16+
func ExamplePass() {
17+
fmt.Println("pass")
18+
// Output:
19+
// pass
20+
}
21+
22+
func ExampleGoexit() {
23+
runtime.Goexit()
24+
// Output:
25+
}

src/testing/example.go

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,9 +62,10 @@ func sortLines(output string) string {
6262
// If stdout doesn't match the expected output or if recovered is non-nil, it'll print the cause of failure to stdout.
6363
// If the test is chatty/verbose, it'll print a success message to stdout.
6464
// If recovered is non-nil, it'll panic with that value.
65-
func (eg *InternalExample) processRunResult(stdout string, timeSpent time.Duration, recovered interface{}) (passed bool) {
65+
// If the test panicked with nil, or invoked runtime.Goexit, it'll be
66+
// made to fail and panic with errNilPanicOrGoexit
67+
func (eg *InternalExample) processRunResult(stdout string, timeSpent time.Duration, finished bool, recovered interface{}) (passed bool) {
6668
passed = true
67-
6869
dstr := fmtDuration(timeSpent)
6970
var fail string
7071
got := strings.TrimSpace(stdout)
@@ -78,16 +79,20 @@ func (eg *InternalExample) processRunResult(stdout string, timeSpent time.Durati
7879
fail = fmt.Sprintf("got:\n%s\nwant:\n%s\n", got, want)
7980
}
8081
}
81-
if fail != "" || recovered != nil {
82+
if fail != "" || !finished || recovered != nil {
8283
fmt.Printf("--- FAIL: %s (%s)\n%s", eg.Name, dstr, fail)
8384
passed = false
8485
} else if *chatty {
8586
fmt.Printf("--- PASS: %s (%s)\n", eg.Name, dstr)
8687
}
88+
8789
if recovered != nil {
8890
// Propagate the previously recovered result, by panicking.
8991
panic(recovered)
9092
}
93+
if !finished && recovered == nil {
94+
panic(errNilPanicOrGoexit)
95+
}
9196

9297
return
9398
}

src/testing/run_example.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ func runExample(eg InternalExample) (ok bool) {
4343
outC <- buf.String()
4444
}()
4545

46+
finished := false
4647
start := time.Now()
4748

4849
// Clean up in a deferred call so we can recover if the example panics.
@@ -55,10 +56,11 @@ func runExample(eg InternalExample) (ok bool) {
5556
out := <-outC
5657

5758
err := recover()
58-
ok = eg.processRunResult(out, timeSpent, err)
59+
ok = eg.processRunResult(out, timeSpent, finished, err)
5960
}()
6061

6162
// Run example.
6263
eg.F()
64+
finished = true
6365
return
6466
}

src/testing/run_example_js.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ func runExample(eg InternalExample) (ok bool) {
2626
stdout := os.Stdout
2727
f := createTempFile(eg.Name)
2828
os.Stdout = f
29+
finished := false
2930
start := time.Now()
3031

3132
// Clean up in a deferred call so we can recover if the example panics.
@@ -50,11 +51,12 @@ func runExample(eg InternalExample) (ok bool) {
5051
}
5152

5253
err := recover()
53-
ok = eg.processRunResult(out, timeSpent, err)
54+
ok = eg.processRunResult(out, timeSpent, finished, err)
5455
}()
5556

5657
// Run example.
5758
eg.F()
59+
finished = true
5860
return
5961
}
6062

0 commit comments

Comments
 (0)