github.com/onsi/gomega@v1.32.0/matchers/match_error_matcher_test.go (about) 1 package matchers_test 2 3 import ( 4 "errors" 5 "fmt" 6 7 . "github.com/onsi/ginkgo/v2" 8 . "github.com/onsi/gomega" 9 . "github.com/onsi/gomega/matchers" 10 ) 11 12 type CustomError struct { 13 } 14 15 func (c CustomError) Error() string { 16 return "an error" 17 } 18 19 type ComplexError struct { 20 Key string 21 } 22 23 func (t *ComplexError) Error() string { 24 return fmt.Sprintf("err: %s", t.Key) 25 } 26 27 var _ = Describe("MatchErrorMatcher", func() { 28 Context("When asserting against an error", func() { 29 When("passed an error", func() { 30 It("should succeed when errors are deeply equal", func() { 31 err := errors.New("an error") 32 fmtErr := fmt.Errorf("an error") 33 customErr := CustomError{} 34 35 Expect(err).Should(MatchError(errors.New("an error"))) 36 Expect(err).ShouldNot(MatchError(errors.New("another error"))) 37 38 Expect(fmtErr).Should(MatchError(errors.New("an error"))) 39 Expect(customErr).Should(MatchError(CustomError{})) 40 }) 41 42 It("should succeed when any error in the chain matches the passed error", func() { 43 innerErr := errors.New("inner error") 44 outerErr := fmt.Errorf("outer error wrapping: %w", innerErr) 45 46 Expect(outerErr).Should(MatchError(innerErr)) 47 }) 48 49 It("uses deep equality with unwrapped errors", func() { 50 innerErr := &ComplexError{Key: "abc"} 51 outerErr := fmt.Errorf("outer error wrapping: %w", &ComplexError{Key: "abc"}) 52 Expect(outerErr).To(MatchError(innerErr)) 53 }) 54 }) 55 56 When("actual an expected are both pointers to an error", func() { 57 It("should succeed when errors are deeply equal", func() { 58 err := CustomError{} 59 Expect(&err).To(MatchError(&err)) 60 }) 61 }) 62 63 It("should succeed when matching with a string", func() { 64 err := errors.New("an error") 65 fmtErr := fmt.Errorf("an error") 66 customErr := CustomError{} 67 68 Expect(err).Should(MatchError("an error")) 69 Expect(err).ShouldNot(MatchError("another error")) 70 71 Expect(fmtErr).Should(MatchError("an error")) 72 Expect(customErr).Should(MatchError("an error")) 73 }) 74 75 When("passed a matcher", func() { 76 It("should pass if the matcher passes against the error string", func() { 77 err := errors.New("error 123 abc") 78 79 Expect(err).Should(MatchError(MatchRegexp(`\d{3}`))) 80 }) 81 82 It("should fail if the matcher fails against the error string", func() { 83 err := errors.New("no digits") 84 Expect(err).ShouldNot(MatchError(MatchRegexp(`\d`))) 85 }) 86 }) 87 88 When("passed a function that takes error and returns bool", func() { 89 var IsFooError = func(err error) bool { 90 return err.Error() == "foo" 91 } 92 93 It("requires an additional description", func() { 94 _, err := (&MatchErrorMatcher{ 95 Expected: IsFooError, 96 }).Match(errors.New("foo")) 97 Expect(err).Should(MatchError("MatchError requires an additional description when passed a function")) 98 }) 99 100 It("matches iff the function returns true", func() { 101 Ω(errors.New("foo")).Should(MatchError(IsFooError, "FooError")) 102 Ω(errors.New("fooo")).ShouldNot(MatchError(IsFooError, "FooError")) 103 }) 104 105 It("uses the error description to construct its message", func() { 106 failuresMessages := InterceptGomegaFailures(func() { 107 Ω(errors.New("fooo")).Should(MatchError(IsFooError, "FooError")) 108 }) 109 Ω(failuresMessages[0]).Should(ContainSubstring("fooo\n {s: \"fooo\"}\nto match error function FooError")) 110 111 failuresMessages = InterceptGomegaFailures(func() { 112 Ω(errors.New("foo")).ShouldNot(MatchError(IsFooError, "FooError")) 113 }) 114 Ω(failuresMessages[0]).Should(ContainSubstring("foo\n {s: \"foo\"}\nnot to match error function FooError")) 115 }) 116 }) 117 118 It("should fail when passed anything else", func() { 119 actualErr := errors.New("an error") 120 _, err := (&MatchErrorMatcher{ 121 Expected: []byte("an error"), 122 }).Match(actualErr) 123 Expect(err).Should(HaveOccurred()) 124 125 _, err = (&MatchErrorMatcher{ 126 Expected: 3, 127 }).Match(actualErr) 128 Expect(err).Should(HaveOccurred()) 129 130 _, err = (&MatchErrorMatcher{ 131 Expected: func(e error) {}, 132 }).Match(actualErr) 133 Expect(err).Should(HaveOccurred()) 134 135 _, err = (&MatchErrorMatcher{ 136 Expected: func() bool { return false }, 137 }).Match(actualErr) 138 Expect(err).Should(HaveOccurred()) 139 140 _, err = (&MatchErrorMatcher{ 141 Expected: func() {}, 142 }).Match(actualErr) 143 Expect(err).Should(HaveOccurred()) 144 145 _, err = (&MatchErrorMatcher{ 146 Expected: func(e error, a string) (bool, error) { return false, nil }, 147 }).Match(actualErr) 148 Expect(err).Should(HaveOccurred()) 149 }) 150 }) 151 152 When("passed nil", func() { 153 It("should fail", func() { 154 _, err := (&MatchErrorMatcher{ 155 Expected: "an error", 156 }).Match(nil) 157 Expect(err).Should(HaveOccurred()) 158 }) 159 }) 160 161 When("passed a non-error", func() { 162 It("should fail", func() { 163 _, err := (&MatchErrorMatcher{ 164 Expected: "an error", 165 }).Match("an error") 166 Expect(err).Should(HaveOccurred()) 167 168 _, err = (&MatchErrorMatcher{ 169 Expected: "an error", 170 }).Match(3) 171 Expect(err).Should(HaveOccurred()) 172 }) 173 }) 174 175 When("passed an error that is also a string", func() { 176 It("should use it as an error", func() { 177 var e mockErr = "mockErr" 178 179 // this fails if the matcher casts e to a string before comparison 180 Expect(e).Should(MatchError(e)) 181 }) 182 }) 183 184 It("shows failure message", func() { 185 failuresMessages := InterceptGomegaFailures(func() { 186 Expect(errors.New("foo")).To(MatchError("bar")) 187 }) 188 Expect(failuresMessages[0]).To(ContainSubstring("foo\n {s: \"foo\"}\nto match error\n <string>: bar")) 189 }) 190 191 It("shows negated failure message", func() { 192 failuresMessages := InterceptGomegaFailures(func() { 193 Expect(errors.New("foo")).ToNot(MatchError("foo")) 194 }) 195 Expect(failuresMessages[0]).To(ContainSubstring("foo\n {s: \"foo\"}\nnot to match error\n <string>: foo")) 196 }) 197 198 }) 199 200 type mockErr string 201 202 func (m mockErr) Error() string { return string(m) }