func TestMultiErrorString(t *testing.T) { t.Parallel() h := newHarness(t) defer h.Stop() err := errgroup.MultiError( []error{ stackerr.New("error"), stackerr.Wrap(&parse.Error{Message: "message", Code: 1}), }, ) h.env.ErrorStack = false errStr := errorString(h.env, err) ensure.DeepEqual(t, errStr, "multiple errors: error | message") h.env.ErrorStack = true errStr = errorString(h.env, err) ensure.StringContains(t, errStr, "multiple errors") ensure.StringContains(t, errStr, `parse: api error with code=1 and message="message"`) ensure.StringContains(t, errStr, ".go") }
// 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() }