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  }