Source file src/testing/panic_test.go

     1  // Copyright 2019 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package testing_test
     6  
     7  import (
     8  	"flag"
     9  	"fmt"
    10  	"internal/testenv"
    11  	"os"
    12  	"os/exec"
    13  	"regexp"
    14  	"strings"
    15  	"testing"
    16  )
    17  
    18  var testPanicTest = flag.String("test_panic_test", "", "TestPanic: indicates which test should panic")
    19  var testPanicParallel = flag.Bool("test_panic_parallel", false, "TestPanic: run subtests in parallel")
    20  var testPanicCleanup = flag.Bool("test_panic_cleanup", false, "TestPanic: indicates whether test should call Cleanup")
    21  var testPanicCleanupPanic = flag.String("test_panic_cleanup_panic", "", "TestPanic: indicate whether test should call Cleanup function that panics")
    22  
    23  func TestPanic(t *testing.T) {
    24  	testenv.MustHaveExec(t)
    25  
    26  	testCases := []struct {
    27  		desc  string
    28  		flags []string
    29  		want  string
    30  	}{{
    31  		desc:  "root test panics",
    32  		flags: []string{"-test_panic_test=TestPanicHelper"},
    33  		want: `
    34  --- FAIL: TestPanicHelper (N.NNs)
    35      panic_test.go:NNN: TestPanicHelper
    36  `,
    37  	}, {
    38  		desc:  "subtest panics",
    39  		flags: []string{"-test_panic_test=TestPanicHelper/1"},
    40  		want: `
    41  --- FAIL: TestPanicHelper (N.NNs)
    42      panic_test.go:NNN: TestPanicHelper
    43      --- FAIL: TestPanicHelper/1 (N.NNs)
    44          panic_test.go:NNN: TestPanicHelper/1
    45  `,
    46  	}, {
    47  		desc:  "subtest panics with cleanup",
    48  		flags: []string{"-test_panic_test=TestPanicHelper/1", "-test_panic_cleanup"},
    49  		want: `
    50  ran inner cleanup 1
    51  ran middle cleanup 1
    52  ran outer cleanup
    53  --- FAIL: TestPanicHelper (N.NNs)
    54      panic_test.go:NNN: TestPanicHelper
    55      --- FAIL: TestPanicHelper/1 (N.NNs)
    56          panic_test.go:NNN: TestPanicHelper/1
    57  `,
    58  	}, {
    59  		desc:  "subtest panics with outer cleanup panic",
    60  		flags: []string{"-test_panic_test=TestPanicHelper/1", "-test_panic_cleanup", "-test_panic_cleanup_panic=outer"},
    61  		want: `
    62  ran inner cleanup 1
    63  ran middle cleanup 1
    64  ran outer cleanup
    65  --- FAIL: TestPanicHelper (N.NNs)
    66      panic_test.go:NNN: TestPanicHelper
    67  `,
    68  	}, {
    69  		desc:  "subtest panics with middle cleanup panic",
    70  		flags: []string{"-test_panic_test=TestPanicHelper/1", "-test_panic_cleanup", "-test_panic_cleanup_panic=middle"},
    71  		want: `
    72  ran inner cleanup 1
    73  ran middle cleanup 1
    74  ran outer cleanup
    75  --- FAIL: TestPanicHelper (N.NNs)
    76      panic_test.go:NNN: TestPanicHelper
    77      --- FAIL: TestPanicHelper/1 (N.NNs)
    78          panic_test.go:NNN: TestPanicHelper/1
    79  `,
    80  	}, {
    81  		desc:  "subtest panics with inner cleanup panic",
    82  		flags: []string{"-test_panic_test=TestPanicHelper/1", "-test_panic_cleanup", "-test_panic_cleanup_panic=inner"},
    83  		want: `
    84  ran inner cleanup 1
    85  ran middle cleanup 1
    86  ran outer cleanup
    87  --- FAIL: TestPanicHelper (N.NNs)
    88      panic_test.go:NNN: TestPanicHelper
    89      --- FAIL: TestPanicHelper/1 (N.NNs)
    90          panic_test.go:NNN: TestPanicHelper/1
    91  `,
    92  	}, {
    93  		desc:  "parallel subtest panics with cleanup",
    94  		flags: []string{"-test_panic_test=TestPanicHelper/1", "-test_panic_cleanup", "-test_panic_parallel"},
    95  		want: `
    96  ran inner cleanup 1
    97  ran middle cleanup 1
    98  ran outer cleanup
    99  --- FAIL: TestPanicHelper (N.NNs)
   100      panic_test.go:NNN: TestPanicHelper
   101      --- FAIL: TestPanicHelper/1 (N.NNs)
   102          panic_test.go:NNN: TestPanicHelper/1
   103  `,
   104  	}, {
   105  		desc:  "parallel subtest panics with outer cleanup panic",
   106  		flags: []string{"-test_panic_test=TestPanicHelper/1", "-test_panic_cleanup", "-test_panic_cleanup_panic=outer", "-test_panic_parallel"},
   107  		want: `
   108  ran inner cleanup 1
   109  ran middle cleanup 1
   110  ran outer cleanup
   111  --- FAIL: TestPanicHelper (N.NNs)
   112      panic_test.go:NNN: TestPanicHelper
   113  `,
   114  	}, {
   115  		desc:  "parallel subtest panics with middle cleanup panic",
   116  		flags: []string{"-test_panic_test=TestPanicHelper/1", "-test_panic_cleanup", "-test_panic_cleanup_panic=middle", "-test_panic_parallel"},
   117  		want: `
   118  ran inner cleanup 1
   119  ran middle cleanup 1
   120  ran outer cleanup
   121  --- FAIL: TestPanicHelper (N.NNs)
   122      panic_test.go:NNN: TestPanicHelper
   123      --- FAIL: TestPanicHelper/1 (N.NNs)
   124          panic_test.go:NNN: TestPanicHelper/1
   125  `,
   126  	}, {
   127  		desc:  "parallel subtest panics with inner cleanup panic",
   128  		flags: []string{"-test_panic_test=TestPanicHelper/1", "-test_panic_cleanup", "-test_panic_cleanup_panic=inner", "-test_panic_parallel"},
   129  		want: `
   130  ran inner cleanup 1
   131  ran middle cleanup 1
   132  ran outer cleanup
   133  --- FAIL: TestPanicHelper (N.NNs)
   134      panic_test.go:NNN: TestPanicHelper
   135      --- FAIL: TestPanicHelper/1 (N.NNs)
   136          panic_test.go:NNN: TestPanicHelper/1
   137  `,
   138  	}}
   139  	for _, tc := range testCases {
   140  		t.Run(tc.desc, func(t *testing.T) {
   141  			cmd := exec.Command(os.Args[0], "-test.run=TestPanicHelper")
   142  			cmd.Args = append(cmd.Args, tc.flags...)
   143  			cmd.Env = append(os.Environ(), "GO_WANT_HELPER_PROCESS=1")
   144  			b, _ := cmd.CombinedOutput()
   145  			got := string(b)
   146  			want := strings.TrimSpace(tc.want)
   147  			re := makeRegexp(want)
   148  			if ok, err := regexp.MatchString(re, got); !ok || err != nil {
   149  				t.Errorf("output:\ngot:\n%s\nwant:\n%s", got, want)
   150  			}
   151  		})
   152  	}
   153  }
   154  
   155  func makeRegexp(s string) string {
   156  	s = regexp.QuoteMeta(s)
   157  	s = strings.ReplaceAll(s, ":NNN:", `:\d+:`)
   158  	s = strings.ReplaceAll(s, "N\\.NNs", `\d*\.\d*s`)
   159  	return s
   160  }
   161  
   162  func TestPanicHelper(t *testing.T) {
   163  	if os.Getenv("GO_WANT_HELPER_PROCESS") != "1" {
   164  		return
   165  	}
   166  	t.Log(t.Name())
   167  	if t.Name() == *testPanicTest {
   168  		panic("panic")
   169  	}
   170  	switch *testPanicCleanupPanic {
   171  	case "", "outer", "middle", "inner":
   172  	default:
   173  		t.Fatalf("bad -test_panic_cleanup_panic: %s", *testPanicCleanupPanic)
   174  	}
   175  	t.Cleanup(func() {
   176  		fmt.Println("ran outer cleanup")
   177  		if *testPanicCleanupPanic == "outer" {
   178  			panic("outer cleanup")
   179  		}
   180  	})
   181  	for i := 0; i < 3; i++ {
   182  		i := i
   183  		t.Run(fmt.Sprintf("%v", i), func(t *testing.T) {
   184  			chosen := t.Name() == *testPanicTest
   185  			if chosen && *testPanicCleanup {
   186  				t.Cleanup(func() {
   187  					fmt.Printf("ran middle cleanup %d\n", i)
   188  					if *testPanicCleanupPanic == "middle" {
   189  						panic("middle cleanup")
   190  					}
   191  				})
   192  			}
   193  			if chosen && *testPanicParallel {
   194  				t.Parallel()
   195  			}
   196  			t.Log(t.Name())
   197  			if chosen {
   198  				if *testPanicCleanup {
   199  					t.Cleanup(func() {
   200  						fmt.Printf("ran inner cleanup %d\n", i)
   201  						if *testPanicCleanupPanic == "inner" {
   202  							panic("inner cleanup")
   203  						}
   204  					})
   205  				}
   206  				panic("panic")
   207  			}
   208  		})
   209  	}
   210  }
   211  

View as plain text