github.com/haraldrudell/parl@v0.4.176/recover_test.go (about) 1 /* 2 © 2023–present Harald Rudell <harald.rudell@gmail.com> (https://haraldrudell.github.io/haraldrudell/) 3 ISC License 4 */ 5 6 package parl 7 8 import ( 9 "fmt" 10 "testing" 11 12 "github.com/haraldrudell/parl/perrors" 13 "github.com/haraldrudell/parl/perrors/errorglue" 14 "github.com/haraldrudell/parl/pruntime" 15 ) 16 17 func TestRecoverDA(t *testing.T) { 18 // expFormat recreates panic formatting 19 var expFormat = "panic detected in %s: “%s” at %s" 20 // the panic message for the type of panic carried out 21 // - “runtime error: invalid memory address or nil pointer dereference” 22 var expPanicMessage = func() (message string) { 23 defer func() { 24 message = recover().(error).Error() 25 }() 26 27 var intp *int 28 if false { 29 var i int 30 intp = &i 31 } 32 _ = *intp 33 return 34 }() 35 36 // expPanicMessage: "runtime error: invalid memory address or nil pointer dereference" 37 t.Logf("expPanicMessage: %q", expPanicMessage) 38 39 // deferCL is the line of function recoverDaPanic where deferLocation is assigned 40 var deferCL *pruntime.CodeLocation 41 // panicCL is the line in panickingFunction where panicLine is assigned 42 var panicCL *pruntime.CodeLocation 43 var err error 44 var message string 45 46 tStatic = t 47 deferCL, panicCL, err = recoverDaPanic() 48 49 // should be error 50 if err == nil { 51 t.Fatalf("missing error") 52 } 53 // error-chain: *fmt.wrapError *errorglue.errorStack runtime.errorString 54 t.Logf("error-chain: %s", errorglue.DumpChain(err)) 55 56 // defer location: parl.recoverDaPanic()-recover3_test.go:16 57 t.Logf("defer location: %s", deferCL.Short()) 58 // panic location: parl.panickingFunction()-recover3_test.go:24 59 t.Logf("panic location: %s", panicCL.Short()) 60 61 var expMessage = fmt.Sprintf(expFormat, 62 deferCL.PackFunc(), // parl.recoverDaPanic 63 expPanicMessage, // runtime error… 64 panicCL.Short(), 65 ) 66 message = perrors.Short(err) 67 if message != expMessage { 68 t.Errorf("FAIL bad message:\n%q exp\n%q", 69 message, 70 expMessage, 71 ) 72 } 73 } 74 75 var tStatic *testing.T 76 77 func diagnosingNoOnerror(err error) { 78 tStatic.Logf("OnError function at %s: Recovered err: %s", pruntime.NewCodeLocation(0).Short(), perrors.Short(err)) 79 } 80 81 // recovers a panic in a called function 82 // - deferLocation is the function where ercovery takes place 83 // - panicLocation is the called function where the panic occurred 84 // - err is the resultfrom [Recover] 85 func recoverDaPanic() (deferLocation, panicLocation *pruntime.CodeLocation, err error) { 86 deferLocation = pruntime.NewCodeLocation(0) 87 defer Recover(func() DA { return A() }, &err, diagnosingNoOnerror) 88 89 panickingFunction(&panicLocation) 90 return 91 } 92 93 // provides a code location on the same line as a panic is caused 94 func panickingFunction(panicLine **pruntime.CodeLocation) { 95 var intp *int 96 if false { 97 var i int 98 intp = &i 99 } 100 if *panicLine = pruntime.NewCodeLocation(0); *intp != 0 { 101 _ = 1 102 } 103 }