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  }