Skip to content

Commit

Permalink
Merge pull request #456 from savaki/master
Browse files Browse the repository at this point in the history
errors.Errorf preserves original error similar to fmt.Error
  • Loading branch information
pavelnikolov committed Apr 30, 2021
2 parents b8f211c + ce94028 commit 4378f8e
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 0 deletions.
17 changes: 17 additions & 0 deletions errors/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
)

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

func Errorf(format string, a ...interface{}) *QueryError {
// similar to fmt.Errorf, Errorf will wrap the last argument if it is an instance of error
var err error
if n := len(a); n > 0 {
if v, ok := a[n-1].(error); ok {
err = v
}
}

return &QueryError{
Err: err,
Message: fmt.Sprintf(format, a...),
}
}
Expand All @@ -39,4 +49,11 @@ func (err *QueryError) Error() string {
return str
}

func (err *QueryError) Unwrap() error {
if err == nil {
return nil
}
return err.Err
}

var _ error = &QueryError{}
55 changes: 55 additions & 0 deletions errors/errors_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package errors

import (
"io"
"testing"
)

// Is is simplified facsimile of the go 1.13 errors.Is to ensure QueryError is compatible
func Is(err, target error) bool {
for err != nil {
if target == err {
return true
}

switch e := err.(type) {
case interface{ Unwrap() error }:
err = e.Unwrap()
default:
break
}
}
return false
}

func TestErrorf(t *testing.T) {
cause := io.EOF

t.Run("wrap error", func(t *testing.T) {
err := Errorf("boom: %v", cause)
if !Is(err, cause) {
t.Fatalf("expected errors.Is to return true")
}
})

t.Run("handles nil", func(t *testing.T) {
var err *QueryError
if Is(err, cause) {
t.Fatalf("expected errors.Is to return false")
}
})

t.Run("handle no arguments", func(t *testing.T) {
err := Errorf("boom")
if Is(err, cause) {
t.Fatalf("expected errors.Is to return false")
}
})

t.Run("handle non-error argument arguments", func(t *testing.T) {
err := Errorf("boom: %v", "shaka")
if Is(err, cause) {
t.Fatalf("expected errors.Is to return false")
}
})
}
6 changes: 6 additions & 0 deletions gqltesting/testing.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,12 @@ func checkErrors(t *testing.T, want, got []*errors.QueryError) {
sortErrors(want)
sortErrors(got)

// Clear the underlying error before the DeepEqual check. It's too
// much to ask the tester to include the raw failing error.
for _, err := range got {
err.Err = nil
}

if !reflect.DeepEqual(got, want) {
t.Fatalf("unexpected error: got %+v, want %+v", got, want)
}
Expand Down

0 comments on commit 4378f8e

Please sign in to comment.