]> Cypherpunks repositories - gostls13.git/commitdiff
testing: fail Example tests that invoke runtime.Goexit
authorChangkun Ou <hi@changkun.us>
Mon, 31 Aug 2020 18:54:17 +0000 (20:54 +0200)
committerEmmanuel Odeke <emm.odeke@gmail.com>
Tue, 1 Sep 2020 20:13:34 +0000 (20:13 +0000)
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>

src/cmd/go/testdata/script/test_example_goexit.txt [new file with mode: 0644]
src/testing/example.go
src/testing/run_example.go
src/testing/run_example_js.go

diff --git a/src/cmd/go/testdata/script/test_example_goexit.txt b/src/cmd/go/testdata/script/test_example_goexit.txt
new file mode 100644 (file)
index 0000000..59219e3
--- /dev/null
@@ -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:
+}
index adc91d5faf66488f3e3f451cc213df9c1c1f150f..0217c5d2425a61ba69421a97c11434adc599b043 100644 (file)
@@ -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)
@@ -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
 }
index 10bde49e5b48e6f494862b2505925a7b68308249..4dc83f7d32476247ec65b089520da4f4533d0933 100644 (file)
@@ -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.
@@ -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
 }
index 472e0c57fa8e28a1f863a5f593b81e5da6391a88..1d4164b61f9ecc37d7e98b6a7878da48245f29b1 100644 (file)
@@ -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.
@@ -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
 }