]> Cypherpunks.ru repositories - gostls13.git/blob - test/recover.go
runtime: turn run time errors checks into panics
[gostls13.git] / test / recover.go
1 // $G $D/$F.go && $L $F.$A && ./$A.out
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 basic recover functionality.
8
9 package main
10
11 import "runtime"
12
13 func main() {
14         test1()
15         test1WithClosures()
16         test2()
17         test3()
18         test4()
19         test5()
20         test6()
21         test6WithClosures()
22         test7()
23 }
24
25 func die() {
26         runtime.Breakpoint() // can't depend on panic
27 }
28
29 func mustRecover(x interface{}) {
30         mustNotRecover() // because it's not a defer call
31         v := recover()
32         if v == nil {
33                 println("missing recover")
34                 die() // panic is useless here
35         }
36         if v != x {
37                 println("wrong value", v, x)
38                 die()
39         }
40
41         // the value should be gone now regardless
42         v = recover()
43         if v != nil {
44                 println("recover didn't recover")
45                 die()
46         }
47 }
48
49 func mustNotRecover() {
50         v := recover()
51         if v != nil {
52                 println("spurious recover", v)
53                 die()
54         }
55 }
56
57 func withoutRecover() {
58         mustNotRecover() // because it's a sub-call
59 }
60
61 func test1() {
62         defer mustNotRecover() // because mustRecover will squelch it
63         defer mustRecover(1)   // because of panic below
64         defer withoutRecover() // should be no-op, leaving for mustRecover to find
65         panic(1)
66 }
67
68 // Repeat test1 with closures instead of standard function.
69 // Interesting because recover bases its decision
70 // on the frame pointer of its caller, and a closure's
71 // frame pointer is in the middle of its actual arguments
72 // (after the hidden ones for the closed-over variables).
73 func test1WithClosures() {
74         defer func() {
75                 v := recover()
76                 if v != nil {
77                         println("spurious recover in closure")
78                         die()
79                 }
80         }()
81         defer func(x interface{}) {
82                 mustNotRecover()
83                 v := recover()
84                 if v == nil {
85                         println("missing recover")
86                         die()
87                 }
88                 if v != x {
89                         println("wrong value", v, x)
90                         die()
91                 }
92         }(1)
93         defer func() {
94                 mustNotRecover()
95         }()
96         panic(1)
97 }
98
99 func test2() {
100         // Recover only sees the panic argument
101         // if it is called from a deferred call.
102         // It does not see the panic when called from a call within a deferred call (too late)
103         // nor does it see the panic when it *is* the deferred call (too early).
104         defer mustRecover(2)
105         defer recover() // should be no-op
106         panic(2)
107 }
108
109 func test3() {
110         defer mustNotRecover()
111         defer func() {
112                 recover() // should squelch
113         }()
114         panic(3)
115 }
116
117 func test4() {
118         // Equivalent to test3 but using defer to make the call.
119         defer mustNotRecover()
120         defer func() {
121                 defer recover() // should squelch
122         }()
123         panic(4)
124 }
125
126 // Check that closures can set output arguments.
127 // Run g().  If it panics, return x; else return deflt.
128 func try(g func(), deflt interface{}) (x interface{}) {
129         defer func() {
130                 if v := recover(); v != nil {
131                         x = v
132                 }
133         }()
134         defer g()
135         return deflt
136 }
137
138 // Check that closures can set output arguments.
139 // Run g().  If it panics, return x; else return deflt.
140 func try1(g func(), deflt interface{}) (x interface{}) {
141         defer func() {
142                 if v := recover(); v != nil {
143                         x = v
144                 }
145         }()
146         defer g()
147         x = deflt
148         return
149 }
150
151 func test5() {
152         v := try(func() { panic(5) }, 55).(int)
153         if v != 5 {
154                 println("wrong value", v, 5)
155                 die()
156         }
157
158         s := try(func() {}, "hi").(string)
159         if s != "hi" {
160                 println("wrong value", s, "hi")
161                 die()
162         }
163
164         v = try1(func() { panic(5) }, 55).(int)
165         if v != 5 {
166                 println("try1 wrong value", v, 5)
167                 die()
168         }
169
170         s = try1(func() {}, "hi").(string)
171         if s != "hi" {
172                 println("try1 wrong value", s, "hi")
173                 die()
174         }
175 }
176
177 // When a deferred big call starts, it must first
178 // create yet another stack segment to hold the
179 // giant frame for x.  Make sure that doesn't
180 // confuse recover.
181 func big(mustRecover bool) {
182         var x [100000]int
183         x[0] = 1
184         x[99999] = 1
185         _ = x
186
187         v := recover()
188         if mustRecover {
189                 if v == nil {
190                         println("missing big recover")
191                         die()
192                 }
193         } else {
194                 if v != nil {
195                         println("spurious big recover")
196                         die()
197                 }
198         }
199 }
200
201 func test6() {
202         defer big(false)
203         defer big(true)
204         panic(6)
205 }
206
207 func test6WithClosures() {
208         defer func() {
209                 var x [100000]int
210                 x[0] = 1
211                 x[99999] = 1
212                 _ = x
213                 if recover() != nil {
214                         println("spurious big closure recover")
215                         die()
216                 }
217         }()
218         defer func() {
219                 var x [100000]int
220                 x[0] = 1
221                 x[99999] = 1
222                 _ = x
223                 if recover() == nil {
224                         println("missing big closure recover")
225                         die()
226                 }
227         }()
228         panic("6WithClosures")
229 }
230
231 func test7() {
232         ok := false
233         func() {
234                 // should panic, then call mustRecover 7, which stops the panic.
235                 // then should keep processing ordinary defers earlier than that one
236                 // before returning.
237                 // this test checks that the defer func on the next line actually runs.
238                 defer func() { ok = true }()
239                 defer mustRecover(7)
240                 panic(7)
241         }()
242         if !ok {
243                 println("did not run ok func")
244                 die()
245         }
246 }