-
Notifications
You must be signed in to change notification settings - Fork 42
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
The following makes it easier to compare errors. Currently, if we attempt to use satisfies checker, we'll more thank likely endup with a deprecation warning that Is prefix predicate variants from the errors package is being used. The solution is to make a new checker that we can move to, which has the semantics that we want moving forward.
- Loading branch information
1 parent
9af10d6
commit 448af9c
Showing
2 changed files
with
121 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
// Copyright 2023 Canonical Ltd. | ||
// Licensed under the LGPLv3, see LICENCE file for details. | ||
|
||
package checkers | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
"reflect" | ||
|
||
gc "gopkg.in/check.v1" | ||
) | ||
|
||
type errorIsChecker struct { | ||
*gc.CheckerInfo | ||
} | ||
|
||
// ErrorIs checks whether a value is an error that matches the other | ||
// argument. | ||
var ErrorIs gc.Checker = &errorIsChecker{ | ||
CheckerInfo: &gc.CheckerInfo{ | ||
Name: "ErrorIs", | ||
Params: []string{"obtained", "error"}, | ||
}, | ||
} | ||
|
||
var ( | ||
errType = reflect.TypeOf((*error)(nil)).Elem() | ||
) | ||
|
||
func (checker *errorIsChecker) Check(params []interface{}, names []string) (result bool, err string) { | ||
if params[1] == nil || params[0] == nil { | ||
return params[1] == params[0], "" | ||
} | ||
|
||
f := reflect.ValueOf(params[1]) | ||
ft := f.Type() | ||
if !ft.Implements(errType) { | ||
return false, fmt.Sprintf("wrong error target type, got: %s", ft) | ||
} | ||
|
||
v := reflect.ValueOf(params[0]) | ||
vt := v.Type() | ||
if !v.IsValid() { | ||
return false, fmt.Sprintf("wrong argument type %s for %s", vt, ft) | ||
} | ||
if !vt.Implements(errType) { | ||
return false, fmt.Sprintf("wrong argument type %s for %s", vt, ft) | ||
} | ||
|
||
return errors.Is(v.Interface().(error), f.Interface().(error)), "" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
package checkers_test | ||
|
||
import ( | ||
"fmt" | ||
|
||
"github.com/juju/errors" | ||
jc "github.com/juju/testing/checkers" | ||
gc "gopkg.in/check.v1" | ||
) | ||
|
||
type ErrorSuite struct{} | ||
|
||
var _ = gc.Suite(&ErrorSuite{}) | ||
|
||
var errorIsTests = []struct { | ||
arg interface{} | ||
target interface{} | ||
result bool | ||
msg string | ||
}{{ | ||
arg: fmt.Errorf("bar"), | ||
target: nil, | ||
result: false, | ||
}, { | ||
arg: nil, | ||
target: fmt.Errorf("bar"), | ||
result: false, | ||
}, { | ||
arg: nil, | ||
target: nil, | ||
result: true, | ||
}, { | ||
arg: fmt.Errorf("bar"), | ||
target: fmt.Errorf("foo"), | ||
result: false, | ||
}, { | ||
arg: errors.ConstError("bar"), | ||
target: errors.ConstError("foo"), | ||
result: false, | ||
}, { | ||
arg: errors.ConstError("foo"), | ||
target: errors.ConstError("foo"), | ||
result: true, | ||
}, { | ||
arg: errors.Trace(errors.ConstError("foo")), | ||
target: errors.ConstError("foo"), | ||
result: true, | ||
}, { | ||
arg: errors.ConstError("foo"), | ||
target: "blah", | ||
msg: "wrong error target type, got: string", | ||
}, { | ||
arg: "blah", | ||
target: errors.ConstError("foo"), | ||
msg: "wrong argument type string for errors.ConstError", | ||
}, { | ||
arg: (*error)(nil), | ||
target: errors.ConstError("foo"), | ||
msg: "wrong argument type *error for errors.ConstError", | ||
}} | ||
|
||
func (s *ErrorSuite) TestErrorIs(c *gc.C) { | ||
for i, test := range errorIsTests { | ||
c.Logf("test %d. %T %T", i, test.arg, test.target) | ||
result, msg := jc.ErrorIs.Check([]interface{}{test.arg, test.target}, nil) | ||
c.Check(result, gc.Equals, test.result) | ||
c.Check(msg, gc.Equals, test.msg) | ||
} | ||
} |