Source file test/recover1.go

     1  // run
     2  
     3  // Copyright 2010 The Go Authors. All rights reserved.
     4  // Use of this source code is governed by a BSD-style
     5  // license that can be found in the LICENSE file.
     6  
     7  // Test of recover during recursive panics.
     8  // Here be dragons.
     9  
    10  package main
    11  
    12  import "runtime"
    13  
    14  func main() {
    15  	test1()
    16  	test2()
    17  	test3()
    18  	test4()
    19  	test5()
    20  	test6()
    21  	test7()
    22  }
    23  
    24  func die() {
    25  	runtime.Breakpoint()	// can't depend on panic
    26  }
    27  
    28  func mustRecover(x interface{}) {
    29  	mustNotRecover()	// because it's not a defer call
    30  	v := recover()
    31  	if v == nil {
    32  		println("missing recover")
    33  		die()	// panic is useless here
    34  	}
    35  	if v != x {
    36  		println("wrong value", v, x)
    37  		die()
    38  	}
    39  
    40  	// the value should be gone now regardless
    41  	v = recover()
    42  	if v != nil {
    43  		println("recover didn't recover")
    44  		die()
    45  	}
    46  }
    47  
    48  func mustNotRecover() {
    49  	v := recover()
    50  	if v != nil {
    51  		println("spurious recover")
    52  		die()
    53  	}
    54  }
    55  
    56  func withoutRecover() {
    57  	mustNotRecover()	// because it's a sub-call
    58  }
    59  
    60  func test1() {
    61  	// Easy nested recursive panic.
    62  	defer mustRecover(1)
    63  	defer func() {
    64  		defer mustRecover(2)
    65  		panic(2)
    66  	}()
    67  	panic(1)
    68  }
    69  
    70  func test2() {
    71  	// Sequential panic.
    72  	defer mustNotRecover()
    73  	defer func() {
    74  		v := recover()
    75  		if v == nil || v.(int) != 2 {
    76  			println("wrong value", v, 2)
    77  			die()
    78  		}
    79  		defer mustRecover(3)
    80  		panic(3)
    81  	}()
    82  	panic(2)
    83  }
    84  
    85  func test3() {
    86  	// Sequential panic - like test2 but less picky.
    87  	defer mustNotRecover()
    88  	defer func() {
    89  		recover()
    90  		defer mustRecover(3)
    91  		panic(3)
    92  	}()
    93  	panic(2)
    94  }
    95  
    96  func test4() {
    97  	// Single panic.
    98  	defer mustNotRecover()
    99  	defer func() {
   100  		recover()
   101  	}()
   102  	panic(4)
   103  }
   104  
   105  func test5() {
   106  	// Single panic but recover called via defer
   107  	defer mustNotRecover()
   108  	defer func() {
   109  		defer recover()
   110  	}()
   111  	panic(5)
   112  }
   113  
   114  func test6() {
   115  	// Sequential panic.
   116  	// Like test3, but changed recover to defer (same change as test4 → test5).
   117  	defer mustNotRecover()
   118  	defer func() {
   119  		defer recover()	// like a normal call from this func; runs because mustRecover stops the panic
   120  		defer mustRecover(3)
   121  		panic(3)
   122  	}()
   123  	panic(2)
   124  }
   125  
   126  func test7() {
   127  	// Like test6, but swapped defer order.
   128  	// The recover in "defer recover()" is now a no-op,
   129  	// because it runs called from panic, not from the func,
   130  	// and therefore cannot see the panic of 2.
   131  	// (Alternately, it cannot see the panic of 2 because
   132  	// there is an active panic of 3.  And it cannot see the
   133  	// panic of 3 because it is at the wrong level (too high on the stack).)
   134  	defer mustRecover(2)
   135  	defer func() {
   136  		defer mustRecover(3)
   137  		defer recover()	// now a no-op, unlike in test6.
   138  		panic(3)
   139  	}()
   140  	panic(2)
   141  }
   142  

View as plain text