Skip to content

Commit

Permalink
testing: fail Example tests that invoke runtime.Goexit
Browse files Browse the repository at this point in the history
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 <emm.odeke@gmail.com>
Reviewed-by: Bryan C. Mills <bcmills@google.com>
Run-TryBot: Bryan C. Mills <bcmills@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
  • Loading branch information
changkun authored and odeke-em committed Sep 1, 2020
1 parent ac55d58 commit afa150c
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 5 deletions.
25 changes: 25 additions & 0 deletions src/cmd/go/testdata/script/test_example_goexit.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# For issue golang.org/issue/41084
[short] skip

! go test -v examplegoexit
stdout '(?s)--- PASS.*--- FAIL.*'
stdout 'panic: test executed panic\(nil\) or runtime\.Goexit'

-- examplegoexit/example_test.go --
package main

import (
"fmt"
"runtime"
)

func ExamplePass() {
fmt.Println("pass")
// Output:
// pass
}

func ExampleGoexit() {
runtime.Goexit()
// Output:
}
11 changes: 8 additions & 3 deletions src/testing/example.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,10 @@ func sortLines(output string) string {
// If stdout doesn't match the expected output or if recovered is non-nil, it'll print the cause of failure to stdout.
// If the test is chatty/verbose, it'll print a success message to stdout.
// If recovered is non-nil, it'll panic with that value.
func (eg *InternalExample) processRunResult(stdout string, timeSpent time.Duration, recovered interface{}) (passed bool) {
// If the test panicked with nil, or invoked runtime.Goexit, it'll be
// made to fail and panic with errNilPanicOrGoexit
func (eg *InternalExample) processRunResult(stdout string, timeSpent time.Duration, finished bool, recovered interface{}) (passed bool) {
passed = true

dstr := fmtDuration(timeSpent)
var fail string
got := strings.TrimSpace(stdout)
Expand All @@ -78,16 +79,20 @@ func (eg *InternalExample) processRunResult(stdout string, timeSpent time.Durati
fail = fmt.Sprintf("got:\n%s\nwant:\n%s\n", got, want)
}
}
if fail != "" || recovered != nil {
if fail != "" || !finished || recovered != nil {
fmt.Printf("--- FAIL: %s (%s)\n%s", eg.Name, dstr, fail)
passed = false
} else if *chatty {
fmt.Printf("--- PASS: %s (%s)\n", eg.Name, dstr)
}

if recovered != nil {
// Propagate the previously recovered result, by panicking.
panic(recovered)
}
if !finished && recovered == nil {
panic(errNilPanicOrGoexit)
}

return
}
4 changes: 3 additions & 1 deletion src/testing/run_example.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ func runExample(eg InternalExample) (ok bool) {
outC <- buf.String()
}()

finished := false
start := time.Now()

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

err := recover()
ok = eg.processRunResult(out, timeSpent, err)
ok = eg.processRunResult(out, timeSpent, finished, err)
}()

// Run example.
eg.F()
finished = true
return
}
4 changes: 3 additions & 1 deletion src/testing/run_example_js.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ func runExample(eg InternalExample) (ok bool) {
stdout := os.Stdout
f := createTempFile(eg.Name)
os.Stdout = f
finished := false
start := time.Now()

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

err := recover()
ok = eg.processRunResult(out, timeSpent, err)
ok = eg.processRunResult(out, timeSpent, finished, err)
}()

// Run example.
eg.F()
finished = true
return
}

Expand Down

0 comments on commit afa150c

Please sign in to comment.