From f8032b4304db5ccf71a3de1e5280bc22231cd3c5 Mon Sep 17 00:00:00 2001 From: James Harris Date: Wed, 15 Apr 2020 14:41:11 +1000 Subject: [PATCH] Implement `PanicWith()`. --- matchers.go | 10 ++++++++ matchers/panic_matcher.go | 44 ++++++++++++++++++++++++++++++--- matchers/panic_matcher_test.go | 45 +++++++++++++++++++++++++++++++++- 3 files changed, 94 insertions(+), 5 deletions(-) diff --git a/matchers.go b/matchers.go index cdf1476d6..16218d4c5 100644 --- a/matchers.go +++ b/matchers.go @@ -390,6 +390,16 @@ func Panic() types.GomegaMatcher { return &matchers.PanicMatcher{} } +//PanicWith succeeds if actual is a function that, when invoked, panics with a specific value. +//Actual must be a function that takes no arguments and returns no results. +// +//By default PanicWith uses Equal() to perform the match, however a +//matcher can be passed in instead: +// Expect(fn).Should(PanicWith(MatchRegexp(`.+Foo$`))) +func PanicWith(expected interface{}) types.GomegaMatcher { + return &matchers.PanicMatcher{Expected: expected} +} + //BeAnExistingFile succeeds if a file exists. //Actual must be a string representing the abs path to the file being checked. func BeAnExistingFile() types.GomegaMatcher { diff --git a/matchers/panic_matcher.go b/matchers/panic_matcher.go index 640f4db1a..002ba75f7 100644 --- a/matchers/panic_matcher.go +++ b/matchers/panic_matcher.go @@ -8,7 +8,8 @@ import ( ) type PanicMatcher struct { - object interface{} + Expected interface{} + object interface{} } func (matcher *PanicMatcher) Match(actual interface{}) (success bool, err error) { @@ -28,7 +29,21 @@ func (matcher *PanicMatcher) Match(actual interface{}) (success bool, err error) defer func() { if e := recover(); e != nil { matcher.object = e - success = true + + if matcher.Expected == nil { + success = true + return + } + + valueMatcher, valueIsMatcher := matcher.Expected.(omegaMatcher) + if !valueIsMatcher { + valueMatcher = &EqualMatcher{Expected: matcher.Expected} + } + + success, err = valueMatcher.Match(e) + if err != nil { + err = fmt.Errorf("PanicMatcher's value matcher failed with:\n%s%s", format.Indent, err.Error()) + } } }() @@ -38,9 +53,30 @@ func (matcher *PanicMatcher) Match(actual interface{}) (success bool, err error) } func (matcher *PanicMatcher) FailureMessage(actual interface{}) (message string) { - return format.Message(actual, "to panic") + switch matcher.Expected.(type) { + case nil: + return format.Message(actual, "to panic") + case omegaMatcher: + return format.Message(actual, "to panic with a value matching", matcher.Expected) + default: + return format.Message(actual, "to panic with", matcher.Expected) + } } func (matcher *PanicMatcher) NegatedFailureMessage(actual interface{}) (message string) { - return format.Message(actual, fmt.Sprintf("not to panic, but panicked with\n%s", format.Object(matcher.object, 1))) + switch matcher.Expected.(type) { + case nil: + return format.Message(actual, fmt.Sprintf("not to panic, but panicked with\n%s", format.Object(matcher.object, 1))) + case omegaMatcher: + return format.Message( + actual, + fmt.Sprintf( + "not to panic with a value matching\n%s\nbut panicked with\n%s", + format.Object(matcher.Expected, 1), + format.Object(matcher.object, 1), + ), + ) + default: + return format.Message(actual, "not to panic with", matcher.Expected) + } } diff --git a/matchers/panic_matcher_test.go b/matchers/panic_matcher_test.go index 899fc108a..904b229bf 100644 --- a/matchers/panic_matcher_test.go +++ b/matchers/panic_matcher_test.go @@ -35,7 +35,7 @@ var _ = Describe("Panic", func() { }) When("assertion fails", func() { - It("prints the object passed to Panic when negative", func() { + It("prints the object passed to panic() when negative", func() { failuresMessages := InterceptGomegaFailures(func() { Expect(func() { panic("ack!") }).NotTo(Panic()) }) @@ -50,3 +50,46 @@ var _ = Describe("Panic", func() { }) }) }) + +var _ = Describe("PanicWith", func() { + When("passed a function of the correct type", func() { + It("should call the function and pass if the function panics with the expected value", func() { + Expect(func() { panic("ack!") }).To(PanicWith("ack!")) + Expect(func() {}).NotTo(PanicWith("ack!")) + }) + }) + + When("assertion fails", func() { + It("prints simple message when positive", func() { + failuresMessages := InterceptGomegaFailures(func() { + Expect(func() {}).To(PanicWith("ack!")) + }) + Expect(failuresMessages).To(ConsistOf(MatchRegexp("Expected\n\\s+: .+\nto panic with\\s+: ack!"))) + }) + + It("prints simple message when negative", func() { + failuresMessages := InterceptGomegaFailures(func() { + Expect(func() { panic("ack!") }).NotTo(PanicWith("ack!")) + }) + Expect(failuresMessages).To(ConsistOf(MatchRegexp("Expected\n\\s+: .+\nnot to panic with\\s+: ack!"))) + }) + + When("the expected value is actually a matcher", func() { + It("prints simple message when positive", func() { + failuresMessages := InterceptGomegaFailures(func() { + Expect(func() {}).To(PanicWith(Equal("ack!"))) + }) + Expect(failuresMessages).To(ConsistOf(MatchRegexp("Expected\n\\s+: .+\nto panic with a value matching\n.+EqualMatcher.+ack!"))) + }) + + It("prints the object passed to panic() when negative", func() { + failuresMessages := InterceptGomegaFailures(func() { + Expect(func() { panic("ack!") }).NotTo(PanicWith(MatchRegexp("ack"))) + }) + Expect(failuresMessages).To(ConsistOf( + MatchRegexp("Expected\n\\s+: .+\nnot to panic with a value matching\n.+MatchRegexpMatcher.+ack.+\nbut panicked with\n : ack!"), + )) + }) + }) + }) +})