func TestUnderlying(t *testing.T) { e1 := errors.New("") e2 := stackerr.Wrap(e1) errs := stackerr.Underlying(e2) if len(errs) != 2 || errs[0] != e2 || errs[1] != e1 { t.Fatal("failed Underlying") } }
// errorString returns the error string with our without the stack trace // depending on the environment variable. this exists because we want plain // messages for end users, but when we're working on the CLI we want the stack // trace for debugging. func errorString(e *env, err error) string { type hasUnderlying interface { HasUnderlying() error } parseErr := func(err error) error { if apiErr, ok := err.(*parse.Error); ok { return errors.New(apiErr.Message) } return err } lastErr := func(err error) error { if serr, ok := err.(*stackerr.Error); ok { if errs := stackerr.Underlying(serr); len(errs) != 0 { err = errs[len(errs)-1] } } else { if eu, ok := err.(hasUnderlying); ok { err = eu.HasUnderlying() } } return parseErr(err) } if !e.ErrorStack { if merr, ok := err.(errgroup.MultiError); ok { var multiError []error for _, ierr := range []error(merr) { multiError = append(multiError, lastErr(ierr)) } err = errgroup.MultiError(multiError) } else { err = lastErr(err) } return parseErr(err).Error() } return err.Error() }