codekingpro/portable-devtools
114k
1// Copyright 2019 The Go Authors. All rights reserved.2// Use of this source code is governed by a BSD-style3// license that can be found in the LICENSE file.4 5package testing_test6 7import (8 "flag"9 "fmt"10 "internal/testenv"11 "os"12 "os/exec"13 "regexp"14 "runtime"15 "strings"16 "testing"17)18 19var testPanicTest = flag.String("test_panic_test", "", "TestPanic: indicates which test should panic")20var testPanicParallel = flag.Bool("test_panic_parallel", false, "TestPanic: run subtests in parallel")21var testPanicCleanup = flag.Bool("test_panic_cleanup", false, "TestPanic: indicates whether test should call Cleanup")22var testPanicCleanupPanic = flag.String("test_panic_cleanup_panic", "", "TestPanic: indicate whether test should call Cleanup function that panics")23 24func TestPanic(t *testing.T) {25 testenv.MustHaveExec(t)26 27 testCases := []struct {28 desc string29 flags []string30 want string31 }{{32 desc: "root test panics",33 flags: []string{"-test_panic_test=TestPanicHelper"},34 want: `35--- FAIL: TestPanicHelper (N.NNs)36 panic_test.go:NNN: TestPanicHelper37 TestPanicHelper38`,39 }, {40 desc: "subtest panics",41 flags: []string{"-test_panic_test=TestPanicHelper/1"},42 want: `43--- FAIL: TestPanicHelper (N.NNs)44 panic_test.go:NNN: TestPanicHelper45 TestPanicHelper46 --- FAIL: TestPanicHelper/1 (N.NNs)47 panic_test.go:NNN: TestPanicHelper/148 TestPanicHelper/149`,50 }, {51 desc: "subtest panics with cleanup",52 flags: []string{"-test_panic_test=TestPanicHelper/1", "-test_panic_cleanup"},53 want: `54ran inner cleanup 155ran middle cleanup 156ran outer cleanup57--- FAIL: TestPanicHelper (N.NNs)58 panic_test.go:NNN: TestPanicHelper59 TestPanicHelper60 --- FAIL: TestPanicHelper/1 (N.NNs)61 panic_test.go:NNN: TestPanicHelper/162 TestPanicHelper/163`,64 }, {65 desc: "subtest panics with outer cleanup panic",66 flags: []string{"-test_panic_test=TestPanicHelper/1", "-test_panic_cleanup", "-test_panic_cleanup_panic=outer"},67 want: `68ran inner cleanup 169ran middle cleanup 170ran outer cleanup71--- FAIL: TestPanicHelper (N.NNs)72 panic_test.go:NNN: TestPanicHelper73 TestPanicHelper74`,75 }, {76 desc: "subtest panics with middle cleanup panic",77 flags: []string{"-test_panic_test=TestPanicHelper/1", "-test_panic_cleanup", "-test_panic_cleanup_panic=middle"},78 want: `79ran inner cleanup 180ran middle cleanup 181ran outer cleanup82--- FAIL: TestPanicHelper (N.NNs)83 panic_test.go:NNN: TestPanicHelper84 TestPanicHelper85 --- FAIL: TestPanicHelper/1 (N.NNs)86 panic_test.go:NNN: TestPanicHelper/187 TestPanicHelper/188`,89 }, {90 desc: "subtest panics with inner cleanup panic",91 flags: []string{"-test_panic_test=TestPanicHelper/1", "-test_panic_cleanup", "-test_panic_cleanup_panic=inner"},92 want: `93ran inner cleanup 194ran middle cleanup 195ran outer cleanup96--- FAIL: TestPanicHelper (N.NNs)97 panic_test.go:NNN: TestPanicHelper98 TestPanicHelper99 --- FAIL: TestPanicHelper/1 (N.NNs)100 panic_test.go:NNN: TestPanicHelper/1101 TestPanicHelper/1102`,103 }, {104 desc: "parallel subtest panics with cleanup",105 flags: []string{"-test_panic_test=TestPanicHelper/1", "-test_panic_cleanup", "-test_panic_parallel"},106 want: `107ran inner cleanup 1108ran middle cleanup 1109ran outer cleanup110--- FAIL: TestPanicHelper (N.NNs)111 panic_test.go:NNN: TestPanicHelper112 TestPanicHelper113 --- FAIL: TestPanicHelper/1 (N.NNs)114 panic_test.go:NNN: TestPanicHelper/1115 TestPanicHelper/1116`,117 }, {118 desc: "parallel subtest panics with outer cleanup panic",119 flags: []string{"-test_panic_test=TestPanicHelper/1", "-test_panic_cleanup", "-test_panic_cleanup_panic=outer", "-test_panic_parallel"},120 want: `121ran inner cleanup 1122ran middle cleanup 1123ran outer cleanup124--- FAIL: TestPanicHelper (N.NNs)125 panic_test.go:NNN: TestPanicHelper126 TestPanicHelper127`,128 }, {129 desc: "parallel subtest panics with middle cleanup panic",130 flags: []string{"-test_panic_test=TestPanicHelper/1", "-test_panic_cleanup", "-test_panic_cleanup_panic=middle", "-test_panic_parallel"},131 want: `132ran inner cleanup 1133ran middle cleanup 1134ran outer cleanup135--- FAIL: TestPanicHelper (N.NNs)136 panic_test.go:NNN: TestPanicHelper137 TestPanicHelper138 --- FAIL: TestPanicHelper/1 (N.NNs)139 panic_test.go:NNN: TestPanicHelper/1140 TestPanicHelper/1141`,142 }, {143 desc: "parallel subtest panics with inner cleanup panic",144 flags: []string{"-test_panic_test=TestPanicHelper/1", "-test_panic_cleanup", "-test_panic_cleanup_panic=inner", "-test_panic_parallel"},145 want: `146ran inner cleanup 1147ran middle cleanup 1148ran outer cleanup149--- FAIL: TestPanicHelper (N.NNs)150 panic_test.go:NNN: TestPanicHelper151 TestPanicHelper152 --- FAIL: TestPanicHelper/1 (N.NNs)153 panic_test.go:NNN: TestPanicHelper/1154 TestPanicHelper/1155`,156 }}157 for _, tc := range testCases {158 t.Run(tc.desc, func(t *testing.T) {159 cmd := exec.Command(testenv.Executable(t), "-test.run=^TestPanicHelper$")160 cmd.Args = append(cmd.Args, tc.flags...)161 cmd.Env = append(os.Environ(), "GO_WANT_HELPER_PROCESS=1")162 b, _ := cmd.CombinedOutput()163 got := string(b)164 want := strings.TrimSpace(tc.want)165 re := makeRegexp(want)166 if ok, err := regexp.MatchString(re, got); !ok || err != nil {167 t.Errorf("output:\ngot:\n%s\nwant:\n%s", got, want)168 }169 })170 }171}172 173func makeRegexp(s string) string {174 s = regexp.QuoteMeta(s)175 s = strings.ReplaceAll(s, ":NNN:", `:\d+:`)176 s = strings.ReplaceAll(s, "N\\.NNs", `\d*\.\d*s`)177 return s178}179 180func TestPanicHelper(t *testing.T) {181 if os.Getenv("GO_WANT_HELPER_PROCESS") != "1" {182 return183 }184 t.Log(t.Name())185 t.Output().Write([]byte(t.Name()))186 if t.Name() == *testPanicTest {187 panic("panic")188 }189 switch *testPanicCleanupPanic {190 case "", "outer", "middle", "inner":191 default:192 t.Fatalf("bad -test_panic_cleanup_panic: %s", *testPanicCleanupPanic)193 }194 t.Cleanup(func() {195 fmt.Println("ran outer cleanup")196 if *testPanicCleanupPanic == "outer" {197 panic("outer cleanup")198 }199 })200 for i := 0; i < 3; i++ {201 t.Run(fmt.Sprintf("%v", i), func(t *testing.T) {202 chosen := t.Name() == *testPanicTest203 if chosen && *testPanicCleanup {204 t.Cleanup(func() {205 fmt.Printf("ran middle cleanup %d\n", i)206 if *testPanicCleanupPanic == "middle" {207 panic("middle cleanup")208 }209 })210 }211 if chosen && *testPanicParallel {212 t.Parallel()213 }214 t.Log(t.Name())215 t.Output().Write([]byte(t.Name()))216 if chosen {217 if *testPanicCleanup {218 t.Cleanup(func() {219 fmt.Printf("ran inner cleanup %d\n", i)220 if *testPanicCleanupPanic == "inner" {221 panic("inner cleanup")222 }223 })224 }225 panic("panic")226 }227 })228 }229}230 231func TestMorePanic(t *testing.T) {232 testenv.MustHaveExec(t)233 234 testCases := []struct {235 desc string236 flags []string237 want string238 }{239 {240 desc: "Issue 48502: call runtime.Goexit in t.Cleanup after panic",241 flags: []string{"-test.run=^TestGoexitInCleanupAfterPanicHelper$"},242 want: `panic: die243 panic: test executed panic(nil) or runtime.Goexit`,244 },245 {246 desc: "Issue 48515: call t.Run in t.Cleanup should trigger panic",247 flags: []string{"-test.run=^TestCallRunInCleanupHelper$"},248 want: `panic: testing: t.Run called during t.Cleanup`,249 },250 }251 252 for _, tc := range testCases {253 cmd := exec.Command(testenv.Executable(t), tc.flags...)254 cmd.Env = append(os.Environ(), "GO_WANT_HELPER_PROCESS=1")255 b, _ := cmd.CombinedOutput()256 got := string(b)257 want := tc.want258 re := makeRegexp(want)259 if ok, err := regexp.MatchString(re, got); !ok || err != nil {260 t.Errorf("output:\ngot:\n%s\nwant:\n%s", got, want)261 }262 }263}264 265func TestCallRunInCleanupHelper(t *testing.T) {266 if os.Getenv("GO_WANT_HELPER_PROCESS") != "1" {267 return268 }269 270 t.Cleanup(func() {271 t.Run("in-cleanup", func(t *testing.T) {272 t.Log("must not be executed")273 })274 })275}276 277func TestGoexitInCleanupAfterPanicHelper(t *testing.T) {278 if os.Getenv("GO_WANT_HELPER_PROCESS") != "1" {279 return280 }281 282 t.Cleanup(func() { runtime.Goexit() })283 t.Parallel()284 panic("die")285}286 