Home | History | Annotate | Download | only in test
      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