| // Copyright 2019 The Go Authors. All rights reserved. | 
 | // Use of this source code is governed by a BSD-style | 
 | // license that can be found in the LICENSE file. | 
 |  | 
 | package testing_test | 
 |  | 
 | import ( | 
 | 	"flag" | 
 | 	"fmt" | 
 | 	"internal/testenv" | 
 | 	"os" | 
 | 	"os/exec" | 
 | 	"regexp" | 
 | 	"strings" | 
 | 	"testing" | 
 | ) | 
 |  | 
 | var testPanicTest = flag.String("test_panic_test", "", "TestPanic: indicates which test should panic") | 
 | var testPanicParallel = flag.Bool("test_panic_parallel", false, "TestPanic: run subtests in parallel") | 
 | var testPanicCleanup = flag.Bool("test_panic_cleanup", false, "TestPanic: indicates whether test should call Cleanup") | 
 | var testPanicCleanupPanic = flag.String("test_panic_cleanup_panic", "", "TestPanic: indicate whether test should call Cleanup function that panics") | 
 |  | 
 | func TestPanic(t *testing.T) { | 
 | 	testenv.MustHaveExec(t) | 
 |  | 
 | 	testCases := []struct { | 
 | 		desc  string | 
 | 		flags []string | 
 | 		want  string | 
 | 	}{{ | 
 | 		desc:  "root test panics", | 
 | 		flags: []string{"-test_panic_test=TestPanicHelper"}, | 
 | 		want: ` | 
 | --- FAIL: TestPanicHelper (N.NNs) | 
 |     panic_test.go:NNN: TestPanicHelper | 
 | `, | 
 | 	}, { | 
 | 		desc:  "subtest panics", | 
 | 		flags: []string{"-test_panic_test=TestPanicHelper/1"}, | 
 | 		want: ` | 
 | --- FAIL: TestPanicHelper (N.NNs) | 
 |     panic_test.go:NNN: TestPanicHelper | 
 |     --- FAIL: TestPanicHelper/1 (N.NNs) | 
 |         panic_test.go:NNN: TestPanicHelper/1 | 
 | `, | 
 | 	}, { | 
 | 		desc:  "subtest panics with cleanup", | 
 | 		flags: []string{"-test_panic_test=TestPanicHelper/1", "-test_panic_cleanup"}, | 
 | 		want: ` | 
 | ran inner cleanup 1 | 
 | ran middle cleanup 1 | 
 | ran outer cleanup | 
 | --- FAIL: TestPanicHelper (N.NNs) | 
 |     panic_test.go:NNN: TestPanicHelper | 
 |     --- FAIL: TestPanicHelper/1 (N.NNs) | 
 |         panic_test.go:NNN: TestPanicHelper/1 | 
 | `, | 
 | 	}, { | 
 | 		desc:  "subtest panics with outer cleanup panic", | 
 | 		flags: []string{"-test_panic_test=TestPanicHelper/1", "-test_panic_cleanup", "-test_panic_cleanup_panic=outer"}, | 
 | 		want: ` | 
 | ran inner cleanup 1 | 
 | ran middle cleanup 1 | 
 | ran outer cleanup | 
 | --- FAIL: TestPanicHelper (N.NNs) | 
 |     panic_test.go:NNN: TestPanicHelper | 
 | `, | 
 | 	}, { | 
 | 		desc:  "subtest panics with middle cleanup panic", | 
 | 		flags: []string{"-test_panic_test=TestPanicHelper/1", "-test_panic_cleanup", "-test_panic_cleanup_panic=middle"}, | 
 | 		want: ` | 
 | ran inner cleanup 1 | 
 | ran middle cleanup 1 | 
 | ran outer cleanup | 
 | --- FAIL: TestPanicHelper (N.NNs) | 
 |     panic_test.go:NNN: TestPanicHelper | 
 |     --- FAIL: TestPanicHelper/1 (N.NNs) | 
 |         panic_test.go:NNN: TestPanicHelper/1 | 
 | `, | 
 | 	}, { | 
 | 		desc:  "subtest panics with inner cleanup panic", | 
 | 		flags: []string{"-test_panic_test=TestPanicHelper/1", "-test_panic_cleanup", "-test_panic_cleanup_panic=inner"}, | 
 | 		want: ` | 
 | ran inner cleanup 1 | 
 | ran middle cleanup 1 | 
 | ran outer cleanup | 
 | --- FAIL: TestPanicHelper (N.NNs) | 
 |     panic_test.go:NNN: TestPanicHelper | 
 |     --- FAIL: TestPanicHelper/1 (N.NNs) | 
 |         panic_test.go:NNN: TestPanicHelper/1 | 
 | `, | 
 | 	}, { | 
 | 		desc:  "parallel subtest panics with cleanup", | 
 | 		flags: []string{"-test_panic_test=TestPanicHelper/1", "-test_panic_cleanup", "-test_panic_parallel"}, | 
 | 		want: ` | 
 | ran inner cleanup 1 | 
 | ran middle cleanup 1 | 
 | ran outer cleanup | 
 | --- FAIL: TestPanicHelper (N.NNs) | 
 |     panic_test.go:NNN: TestPanicHelper | 
 |     --- FAIL: TestPanicHelper/1 (N.NNs) | 
 |         panic_test.go:NNN: TestPanicHelper/1 | 
 | `, | 
 | 	}, { | 
 | 		desc:  "parallel subtest panics with outer cleanup panic", | 
 | 		flags: []string{"-test_panic_test=TestPanicHelper/1", "-test_panic_cleanup", "-test_panic_cleanup_panic=outer", "-test_panic_parallel"}, | 
 | 		want: ` | 
 | ran inner cleanup 1 | 
 | ran middle cleanup 1 | 
 | ran outer cleanup | 
 | --- FAIL: TestPanicHelper (N.NNs) | 
 |     panic_test.go:NNN: TestPanicHelper | 
 | `, | 
 | 	}, { | 
 | 		desc:  "parallel subtest panics with middle cleanup panic", | 
 | 		flags: []string{"-test_panic_test=TestPanicHelper/1", "-test_panic_cleanup", "-test_panic_cleanup_panic=middle", "-test_panic_parallel"}, | 
 | 		want: ` | 
 | ran inner cleanup 1 | 
 | ran middle cleanup 1 | 
 | ran outer cleanup | 
 | --- FAIL: TestPanicHelper (N.NNs) | 
 |     panic_test.go:NNN: TestPanicHelper | 
 |     --- FAIL: TestPanicHelper/1 (N.NNs) | 
 |         panic_test.go:NNN: TestPanicHelper/1 | 
 | `, | 
 | 	}, { | 
 | 		desc:  "parallel subtest panics with inner cleanup panic", | 
 | 		flags: []string{"-test_panic_test=TestPanicHelper/1", "-test_panic_cleanup", "-test_panic_cleanup_panic=inner", "-test_panic_parallel"}, | 
 | 		want: ` | 
 | ran inner cleanup 1 | 
 | ran middle cleanup 1 | 
 | ran outer cleanup | 
 | --- FAIL: TestPanicHelper (N.NNs) | 
 |     panic_test.go:NNN: TestPanicHelper | 
 |     --- FAIL: TestPanicHelper/1 (N.NNs) | 
 |         panic_test.go:NNN: TestPanicHelper/1 | 
 | `, | 
 | 	}} | 
 | 	for _, tc := range testCases { | 
 | 		t.Run(tc.desc, func(t *testing.T) { | 
 | 			cmd := exec.Command(os.Args[0], "-test.run=TestPanicHelper") | 
 | 			cmd.Args = append(cmd.Args, tc.flags...) | 
 | 			cmd.Env = append(os.Environ(), "GO_WANT_HELPER_PROCESS=1") | 
 | 			b, _ := cmd.CombinedOutput() | 
 | 			got := string(b) | 
 | 			want := strings.TrimSpace(tc.want) | 
 | 			re := makeRegexp(want) | 
 | 			if ok, err := regexp.MatchString(re, got); !ok || err != nil { | 
 | 				t.Errorf("output:\ngot:\n%s\nwant:\n%s", got, want) | 
 | 			} | 
 | 		}) | 
 | 	} | 
 | } | 
 |  | 
 | func makeRegexp(s string) string { | 
 | 	s = regexp.QuoteMeta(s) | 
 | 	s = strings.ReplaceAll(s, ":NNN:", `:\d+:`) | 
 | 	s = strings.ReplaceAll(s, "N\\.NNs", `\d*\.\d*s`) | 
 | 	return s | 
 | } | 
 |  | 
 | func TestPanicHelper(t *testing.T) { | 
 | 	if os.Getenv("GO_WANT_HELPER_PROCESS") != "1" { | 
 | 		return | 
 | 	} | 
 | 	t.Log(t.Name()) | 
 | 	if t.Name() == *testPanicTest { | 
 | 		panic("panic") | 
 | 	} | 
 | 	switch *testPanicCleanupPanic { | 
 | 	case "", "outer", "middle", "inner": | 
 | 	default: | 
 | 		t.Fatalf("bad -test_panic_cleanup_panic: %s", *testPanicCleanupPanic) | 
 | 	} | 
 | 	t.Cleanup(func() { | 
 | 		fmt.Println("ran outer cleanup") | 
 | 		if *testPanicCleanupPanic == "outer" { | 
 | 			panic("outer cleanup") | 
 | 		} | 
 | 	}) | 
 | 	for i := 0; i < 3; i++ { | 
 | 		i := i | 
 | 		t.Run(fmt.Sprintf("%v", i), func(t *testing.T) { | 
 | 			chosen := t.Name() == *testPanicTest | 
 | 			if chosen && *testPanicCleanup { | 
 | 				t.Cleanup(func() { | 
 | 					fmt.Printf("ran middle cleanup %d\n", i) | 
 | 					if *testPanicCleanupPanic == "middle" { | 
 | 						panic("middle cleanup") | 
 | 					} | 
 | 				}) | 
 | 			} | 
 | 			if chosen && *testPanicParallel { | 
 | 				t.Parallel() | 
 | 			} | 
 | 			t.Log(t.Name()) | 
 | 			if chosen { | 
 | 				if *testPanicCleanup { | 
 | 					t.Cleanup(func() { | 
 | 						fmt.Printf("ran inner cleanup %d\n", i) | 
 | 						if *testPanicCleanupPanic == "inner" { | 
 | 							panic("inner cleanup") | 
 | 						} | 
 | 					}) | 
 | 				} | 
 | 				panic("panic") | 
 | 			} | 
 | 		}) | 
 | 	} | 
 | } |