github.com/haraldrudell/parl@v0.4.176/panic-to-err_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 "strings" 11 "testing" 12 13 "github.com/haraldrudell/parl/perrors" 14 "github.com/haraldrudell/parl/perrors/errorglue" 15 "github.com/haraldrudell/parl/pruntime" 16 ) 17 18 func TestPanicToErr(t *testing.T) { 19 // "runtime error: invalid memory address or nil pointer dereference" 20 var panicMessage = func() (message string) { 21 defer func() { message = recover().(error).Error() }() 22 var intp *int 23 if false { 24 var i int 25 intp = &i 26 } 27 _ = *intp // causes nil pointer dereference panic 28 return 29 }() 30 // “runtime error: invalid memory address or nil pointer dereference” 31 var expMessage = fmt.Sprintf("“%s”", panicMessage) 32 33 var panicLine *pruntime.CodeLocation 34 var err error 35 var stack pruntime.Stack 36 var errorShort string 37 38 // get [parl.RecoverErr] values from recovering a panic 39 panicLine, err = panicFunction() 40 41 // there should be an error 42 if err == nil { 43 t.Error("expected error missing") 44 t.FailNow() 45 } 46 stack = errorglue.GetStackTrace(err) 47 errorShort = perrors.Short(err) 48 49 // panicLine: “ 50 // File: "/opt/sw/parl/recover-err_test.go" 51 // Line: 24 52 // FuncName: "github.com/haraldrudell/parl.panicFunction" 53 //” 54 t.Logf("panicLine: “%s”", panicLine.Dump()) 55 56 // stack trace: 57 // runtime.gopanic 58 // /opt/homebrew/Cellar/go/1.21.3/libexec/src/runtime/panic.go:914 59 // runtime.panicmem 60 // /opt/homebrew/Cellar/go/1.21.3/libexec/src/runtime/panic.go:261 61 // runtime.sigpanic 62 // /opt/homebrew/Cellar/go/1.21.3/libexec/src/runtime/signal_unix.go:861 63 // github.com/haraldrudell/parl.panicFunction 64 // /opt/sw/parl/recover-err_test.go:23 65 // github.com/haraldrudell/parl.TestRecoverErr 66 // /opt/sw/parl/recover-err_test.go:32 67 // testing.tRunner 68 // /opt/homebrew/Cellar/go/1.21.3/libexec/src/testing/testing.go:1595 69 // runtime.goexit 70 // /opt/homebrew/Cellar/go/1.21.3/libexec/src/runtime/asm_arm64.s:1197 71 // /opt/sw/parl/recover-err_test.go:43: bad error message 72 t.Logf("stack trace: %s", stack) 73 74 // error: 75 // Recover from panic in runtime.gopanic:: panic: 76 // 'runtime error: invalid memory address or nil pointer dereference' 77 // at runtime.gopanic()-panic.go:914 78 t.Logf("error: %s", errorShort) 79 80 // perrors.Short should detect the exact location of the panic 81 var panicLineShort = panicLine.Short() 82 if !strings.HasSuffix(errorShort, panicLineShort) { 83 t.Errorf("perrors.Short does not end with exact panic location:\n%s\n%s", 84 errorShort, 85 panicLineShort, 86 ) 87 } 88 89 // perrors.Short should contain the message 90 if !strings.Contains(errorShort, expMessage) { 91 t.Errorf("perrors.Short does not contain expected error message::\n%s\n%s", 92 errorShort, 93 expMessage, 94 ) 95 } 96 } 97 98 // panicFunction recovers a panic using [parl.RecoverErr] 99 // - panicLine is the exact code line of the panic 100 // - err is the error value produced by [parl.RecoverErr] 101 func panicFunction() (panicLine *pruntime.CodeLocation, err error) { 102 defer PanicToErr(&err) 103 104 // get exact code line and generate a nil pointer dereference panic 105 var intp *int 106 if false { 107 var i int 108 intp = &i 109 } 110 if panicLine = pruntime.NewCodeLocation(0); *intp != 0 { 111 _ = 1 112 } 113 114 return 115 }