-
Notifications
You must be signed in to change notification settings - Fork 31
Add go 1.13 errors feature support #32
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Cc @pacejackson |
Travis tests are not run for some reason. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
error_113.go
Outdated
|
||
// todo add errorx.As()? | ||
// todo make another 'go error type' for passing into errors.As()? | ||
// todo when fixed, add tests for wrap/decorate etc. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't really see the problem with As
. Let's remember the use case of errors.As
:
// errors.As is designed to replace the following error drilling pattern:
if exitErr, ok := err.(*exec.ExitError); ok && exitErr.ExitCode() == 42 {
// handle error code 42
}
When you don't need actual error value buried deep in an error chain, errors.Is
would suffice.
When you do actually need that, let's remember that all errorx.Error
properties are being propagated to topmost error. And that topmost errorx.Error
is really what you need because there is no other way to attach additional information to error other than carried by properties.
Therefore, I suggest that errorx.Error
shouldn't implement As
method.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suggest you copy this comment to the next PR I sent, and I'll remove this part of change from current PR.
I think we're trying to solve wrong problem here. What we really want is:
err := fmt.Errorf("wrapped: %w", errorx.IllegalState.NewWithNoMessage())
require.True(t, errorx.IsOfType(err, errorx.IllegalState))
err := errorx.Decorate(context.Canceled, "fancy decoration")
require.True(t, errors.Is(err, context.Canceled)) |
Let's dissect those arguments a bit. At this point, as I see it, we must choose whether to have a solution that solves only the case shown above, or a wider range of scenarios. The former must be supported by the argument as to what harm does those additions bring. Historically, similar concepts in The second argument here is that optional
So, it seems to me that making a check in code like
return true on any errorx type is not only a lost opportunity, it is a potential for bugs that are hard to track, as we all know that negative cases are often neglected in tests. The only argument I can find not to do this is in having several ways of doing the same thing, which may be confusing. Currently, godoc aims to help with this, it can be enhanced further. Possibly this is in argument in favour of deprecation and then removal of some of |
type.go
Outdated
// The original error will not pass its dynamic properties, and those are accessible only via direct walk over Cause() chain. | ||
// Without args, leaves the original message intact, so a message may be generated or provided externally. | ||
// With args, a formatting is performed, and it is therefore expected a format string to be constant. | ||
// NB: Wrap is NOT the reverse of Error.Unwrap method; name may be changed in future releases to avoid confusion. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we should refer to errors.Unwrap
instead of Error.Unwrap
?
|
||
t.Run("Wrap", func(t *testing.T) { | ||
8000 | err := testTypeBar1.Wrap(testType.NewWithNoMessage(), "") | |
unwrapped := errors.Unwrap(err) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is where unrelatedness between Wrap
and Unwrap
hits particularly hard :(
err := Decorate(testType.NewWithNoMessage(), "") | ||
unwrapped := errors.Unwrap(err) | ||
require.NotNil(t, unwrapped) | ||
require.True(t, IsOfType(unwrapped, testType)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Technically, unwrapped
may be the same as err
and the assertions will still pass.
err := Decorate(io.EOF, "") | ||
unwrapped := errors.Unwrap(err) | ||
require.NotNil(t, unwrapped) | ||
require.True(t, errors.Is(unwrapped, io.EOF)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will be true even if errors.Unwrap
returned original err
.
error_113_test.go
Outdated
}) | ||
|
||
t.Run("Wrap", func(t *testing.T) { | ||
err := testTypeBar1.Wrap(testType.NewWithNoMessage(),"") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Lack of gofmt detect I.
t.Run("DecorateForeign", func(t *testing.T) { | ||
err := Decorate(io.EOF,"") | ||
require.True(t, errors.Is(err, io.EOF)) | ||
}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should add a test that errorx.IsOfType(err, errorType)
penetrates fmt.Errorf("blabla: %w", errorType.NewWithNoMessage())
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As of this PR, it doesn't. I intend to add both feature and tests in a separate PR.
As tests show,
errors.Unwrap
anderrors.Is
work exactly as intended and preserve all existing errorx contracts.On the other hand,
errors.As
is broken for errorx. It is not a regression of this PR, some tests are added for cases that work, issue will be addressed further in future PRs.