Skip to content

Commit 4378f8e

Browse files
authored
Merge pull request #456 from savaki/master
errors.Errorf preserves original error similar to fmt.Error
2 parents b8f211c + ce94028 commit 4378f8e

File tree

3 files changed

+78
-0
lines changed

3 files changed

+78
-0
lines changed

errors/errors.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
)
66

77
type QueryError struct {
8+
Err error `json:"-"` // Err holds underlying if available
89
Message string `json:"message"`
910
Locations []Location `json:"locations,omitempty"`
1011
Path []interface{} `json:"path,omitempty"`
@@ -23,7 +24,16 @@ func (a Location) Before(b Location) bool {
2324
}
2425

2526
func Errorf(format string, a ...interface{}) *QueryError {
27+
// similar to fmt.Errorf, Errorf will wrap the last argument if it is an instance of error
28+
var err error
29+
if n := len(a); n > 0 {
30+
if v, ok := a[n-1].(error); ok {
31+
err = v
32+
}
33+
}
34+
2635
return &QueryError{
36+
Err: err,
2737
Message: fmt.Sprintf(format, a...),
2838
}
2939
}
@@ -39,4 +49,11 @@ func (err *QueryError) Error() string {
3949
return str
4050
}
4151

52+
func (err *QueryError) Unwrap() error {
53+
if err == nil {
54+
return nil
55+
}
56+
return err.Err
57+
}
58+
4259
var _ error = &QueryError{}

errors/errors_test.go

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package errors
2+
3+
import (
4+
"io"
5+
"testing"
6+
)
7+
8+
// Is is simplified facsimile of the go 1.13 errors.Is to ensure QueryError is compatible
9+
func Is(err, target error) bool {
10+
for err != nil {
11+
if target == err {
12+
return true
13+
}
14+
15+
switch e := err.(type) {
16+
case interface{ Unwrap() error }:
17+
err = e.Unwrap()
18+
default:
19+
break
20+
}
21+
}
22+
return false
23+
}
24+
25+
func TestErrorf(t *testing.T) {
26+
cause := io.EOF
27+
28+
t.Run("wrap error", func(t *testing.T) {
29+
err := Errorf("boom: %v", cause)
30+
if !Is(err, cause) {
31+
t.Fatalf("expected errors.Is to return true")
32+
}
33+
})
34+
35+
t.Run("handles nil", func(t *testing.T) {
36+
var err *QueryError
37+
if Is(err, cause) {
38+
t.Fatalf("expected errors.Is to return false")
39+
}
40+
})
41+
42+
t.Run("handle no arguments", func(t *testing.T) {
43+
err := Errorf("boom")
44+
if Is(err, cause) {
45+
t.Fatalf("expected errors.Is to return false")
46+
}
47+
})
48+
49+
t.Run("handle non-error argument arguments", func(t *testing.T) {
50+
err := Errorf("boom: %v", "shaka")
51+
if Is(err, cause) {
52+
t.Fatalf("expected errors.Is to return false")
53+
}
54+
})
55+
}

gqltesting/testing.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,12 @@ func checkErrors(t *testing.T, want, got []*errors.QueryError) {
102102
sortErrors(want)
103103
sortErrors(got)
104104

105+
// Clear the underlying error before the DeepEqual check. It's too
106+
// much to ask the tester to include the raw failing error.
107+
for _, err := range got {
108+
err.Err = nil
109+
}
110+
105111
if !reflect.DeepEqual(got, want) {
106112
t.Fatalf("unexpected error: got %+v, want %+v", got, want)
107113
}

0 commit comments

Comments
 (0)