...
1 package matchers
2
3 import (
4 "errors"
5 "fmt"
6 "reflect"
7
8 "github.com/onsi/gomega/format"
9 )
10
11 type MatchErrorMatcher struct {
12 Expected any
13 FuncErrDescription []any
14 isFunc bool
15 }
16
17 func (matcher *MatchErrorMatcher) Match(actual any) (success bool, err error) {
18 matcher.isFunc = false
19
20 if isNil(actual) {
21 return false, fmt.Errorf("Expected an error, got nil")
22 }
23
24 if !isError(actual) {
25 return false, fmt.Errorf("Expected an error. Got:\n%s", format.Object(actual, 1))
26 }
27
28 actualErr := actual.(error)
29 expected := matcher.Expected
30
31 if isError(expected) {
32
33 if errors.Is(actualErr, expected.(error)) {
34 return true, nil
35 }
36
37 for unwrapped := actualErr; unwrapped != nil; unwrapped = errors.Unwrap(unwrapped) {
38 if reflect.DeepEqual(unwrapped, expected) {
39 return true, nil
40 }
41 }
42 return false, nil
43 }
44
45 if isString(expected) {
46 return actualErr.Error() == expected, nil
47 }
48
49 v := reflect.ValueOf(expected)
50 t := v.Type()
51 errorInterface := reflect.TypeOf((*error)(nil)).Elem()
52 if t.Kind() == reflect.Func && t.NumIn() == 1 && t.In(0).Implements(errorInterface) && t.NumOut() == 1 && t.Out(0).Kind() == reflect.Bool {
53 if len(matcher.FuncErrDescription) == 0 {
54 return false, fmt.Errorf("MatchError requires an additional description when passed a function")
55 }
56 matcher.isFunc = true
57 return v.Call([]reflect.Value{reflect.ValueOf(actualErr)})[0].Bool(), nil
58 }
59
60 var subMatcher omegaMatcher
61 var hasSubMatcher bool
62 if expected != nil {
63 subMatcher, hasSubMatcher = (expected).(omegaMatcher)
64 if hasSubMatcher {
65 return subMatcher.Match(actualErr.Error())
66 }
67 }
68
69 return false, fmt.Errorf(
70 "MatchError must be passed an error, a string, or a Matcher that can match on strings. Got:\n%s",
71 format.Object(expected, 1))
72 }
73
74 func (matcher *MatchErrorMatcher) FailureMessage(actual interface{}) (message string) {
75 if matcher.isFunc {
76 return format.Message(actual, fmt.Sprintf("to match error function %s", matcher.FuncErrDescription[0]))
77 }
78 return format.Message(actual, "to match error", matcher.Expected)
79 }
80
81 func (matcher *MatchErrorMatcher) NegatedFailureMessage(actual interface{}) (message string) {
82 if matcher.isFunc {
83 return format.Message(actual, fmt.Sprintf("not to match error function %s", matcher.FuncErrDescription[0]))
84 }
85 return format.Message(actual, "not to match error", matcher.Expected)
86 }
87
View as plain text