src.elv.sh@v0.21.0-dev.0.20240515223629-06979efb9a2a/pkg/eval/exception_test.go (about)

     1  package eval_test
     2  
     3  import (
     4  	"errors"
     5  	"reflect"
     6  	"testing"
     7  	"unsafe"
     8  
     9  	"src.elv.sh/pkg/diag"
    10  	. "src.elv.sh/pkg/eval"
    11  	"src.elv.sh/pkg/testutil"
    12  
    13  	"src.elv.sh/pkg/eval/vals"
    14  	"src.elv.sh/pkg/persistent/hash"
    15  	"src.elv.sh/pkg/tt"
    16  )
    17  
    18  func TestReason(t *testing.T) {
    19  	err := errors.New("ordinary error")
    20  	tt.Test(t, Reason,
    21  		Args(err).Rets(err),
    22  		Args(makeException(err)).Rets(err),
    23  	)
    24  }
    25  
    26  func TestException(t *testing.T) {
    27  	err := FailError{"error"}
    28  	exc := makeException(err)
    29  	vals.TestValue(t, exc).
    30  		Kind("exception").
    31  		Bool(false).
    32  		Hash(hash.Pointer(unsafe.Pointer(reflect.ValueOf(exc).Pointer()))).
    33  		Equal(exc).
    34  		NotEqual(makeException(errors.New("error"))).
    35  		AllKeys("reason", "stack-trace").
    36  		Index("reason", err).
    37  		IndexError("stack", vals.NoSuchKey("stack")).
    38  		Repr("[^exception &reason=[^fail-error &content=error &type=fail] &stack-trace=<...>]")
    39  
    40  	vals.TestValue(t, OK).
    41  		Kind("exception").
    42  		Bool(true).
    43  		Repr("$ok")
    44  }
    45  
    46  func TestException_Show(t *testing.T) {
    47  	for _, p := range []*string{
    48  		ExceptionCauseStartMarker, ExceptionCauseEndMarker,
    49  		&diag.ContextBodyStartMarker, &diag.ContextBodyEndMarker} {
    50  
    51  		testutil.Set(t, p, "")
    52  	}
    53  
    54  	tt.Test(t, Exception.Show,
    55  		It("supports exceptions with one traceback frame").
    56  			Args(makeException(
    57  				errors.New("internal error"),
    58  				diag.NewContext("a.elv", "echo bad", diag.Ranging{From: 5, To: 8})), "").
    59  			Rets(Dedent(`
    60  				Exception: internal error
    61  				  a.elv:1:6-8: echo bad`)),
    62  
    63  		It("supports exceptions with multiple traceback frames").
    64  			Args(makeException(
    65  				errors.New("internal error"),
    66  				diag.NewContext("a.elv", "echo bad", diag.Ranging{From: 5, To: 8}),
    67  				diag.NewContext("b.elv", "use foo", diag.Ranging{From: 0, To: 7})), "").
    68  			Rets(Dedent(`
    69  				Exception: internal error
    70  				  a.elv:1:6-8: echo bad
    71  				  b.elv:1:1-7: use foo`)),
    72  
    73  		It("supports traceback frames with multi-line body text").
    74  			Args(makeException(
    75  				errors.New("internal error"),
    76  				diag.NewContext("a.elv", "echo ba\nd", diag.Ranging{From: 5, To: 9})), "").
    77  			Rets(Dedent(`
    78  				Exception: internal error
    79  				  a.elv:1:6-2:1:
    80  				    echo ba
    81  				    d`)),
    82  	)
    83  }
    84  
    85  func makeException(cause error, entries ...*diag.Context) Exception {
    86  	return NewException(cause, makeStackTrace(entries...))
    87  }
    88  
    89  // Creates a new StackTrace, using the first entry as the head.
    90  func makeStackTrace(entries ...*diag.Context) *StackTrace {
    91  	var s *StackTrace
    92  	for i := len(entries) - 1; i >= 0; i-- {
    93  		s = &StackTrace{Head: entries[i], Next: s}
    94  	}
    95  	return s
    96  }
    97  
    98  func TestErrorMethods(t *testing.T) {
    99  	tt.Test(t, error.Error,
   100  		Args(makeException(errors.New("err"))).Rets("err"),
   101  
   102  		Args(MakePipelineError([]Exception{
   103  			makeException(errors.New("err1")),
   104  			makeException(errors.New("err2"))})).Rets("(err1 | err2)"),
   105  
   106  		Args(Return).Rets("return"),
   107  		Args(Break).Rets("break"),
   108  		Args(Continue).Rets("continue"),
   109  		Args(Flow(1000)).Rets("!(BAD FLOW: 1000)"),
   110  	)
   111  }