-
Notifications
You must be signed in to change notification settings - Fork 707
Proposal: Unpack standard library error wrapping types #112
Description
There are several error types in the standard library that wrap errors. net/url.Error, for example, 'reports an error and the operation and URL that caused it.' This error type is used (among other places) within the net/http.Client
to annotate any errors it gets from its http.RoundTripper
transport.
As a result, this test (for example) would not pass:
package main
import (
"fmt"
"net/http"
"testing"
"github.com/pkg/errors"
)
// failingTransport is a http.RoundTripper which always returns an error.
type failingTransport struct {
err error // the error to return
}
func (t failingTransport) RoundTrip(*http.Request) (*http.Response, error) {
return nil, t.err
}
func TestClientErrorsCanBeCaused(t *testing.T) {
rootErr := fmt.Errorf("some root cause")
c := &http.Client{
Transport: &failingTransport{rootErr},
}
_, err := c.Get("bogus")
cause := errors.Cause(err)
if cause != rootErr {
t.Errorf("err cause is %q, want %q", cause, rootErr)
}
}
-> % go test -v ./errwrap_test.go
=== RUN TestClientErrorsCanBeCaused
--- FAIL: TestClientErrorsCanBeCaused (0.00s)
errwrap_test.go:28: err cause is "Get bogus: some root cause", want "some root cause"
FAIL
exit status 1
FAIL command-line-arguments 1.090s
I think that test should pass, though. Otherwise, I need to write my own series of type assertions to unpack the real root cause. The errors package could unpack the standard library types which are clearly wrappers. I think those are these:
- net.OpError
- net.DNSConfigError (deprecated)
- net/url.Error
- os.LinkError
- os.PathError
- os.SyscallError
- text/template.ExecError
- encoding/json.MarshalerError
All of these may be useful, but I think the most important are the net
ones, in my experience.
The implementation seems straightforward, if you're willing to accept the smelliness of a series of special-case type assertions in the Cause function.