Skip to content

Commit

Permalink
Improve Gomega's representation of unexpected errors passed in to an …
Browse files Browse the repository at this point in the history
…assertion
  • Loading branch information
onsi committed Oct 24, 2022
1 parent a54887c commit 78deb62
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 14 deletions.
8 changes: 7 additions & 1 deletion internal/assertion.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"fmt"
"reflect"

"github.com/onsi/gomega/format"
"github.com/onsi/gomega/types"
)

Expand Down Expand Up @@ -146,7 +147,12 @@ func vetActuals(actuals []interface{}, skipIndex int) (bool, string) {
if actual != nil {
zeroValue := reflect.Zero(reflect.TypeOf(actual)).Interface()
if !reflect.DeepEqual(zeroValue, actual) {
message := fmt.Sprintf("Unexpected non-nil/non-zero argument at index %d:\n\t<%T>: %#v", i, actual, actual)
var message string
if err, ok := actual.(error); ok {
message = fmt.Sprintf("Unexpected error: %s\n%s", err, format.Object(err, 1))
} else {
message = fmt.Sprintf("Unexpected non-nil/non-zero argument at index %d:\n\t<%T>: %#v", i, actual, actual)
}
return false, message
}
}
Expand Down
20 changes: 12 additions & 8 deletions internal/assertion_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ var _ = Describe("Making Synchronous Assertions", func() {
ig := NewInstrumentedGomega()
returnValue := ig.G.Expect(actual, extras...).To(SpecMatch(), optionalDescription...)
Expect(returnValue).To(Equal(expectedReturnValue))
Expect(ig.FailureMessage).To(Equal(expectedFailureMessage))
Expect(ig.FailureMessage).To(ContainSubstring(expectedFailureMessage))
if expectedFailureMessage != "" {
Expect(ig.FailureSkip).To(Equal([]int{2}))
}
Expand All @@ -38,7 +38,7 @@ var _ = Describe("Making Synchronous Assertions", func() {
ig = NewInstrumentedGomega()
returnValue = ig.G.ExpectWithOffset(3, actual, extras...).To(SpecMatch(), optionalDescription...)
Expect(returnValue).To(Equal(expectedReturnValue))
Expect(ig.FailureMessage).To(Equal(expectedFailureMessage))
Expect(ig.FailureMessage).To(ContainSubstring(expectedFailureMessage))
if expectedFailureMessage != "" {
Expect(ig.FailureSkip).To(Equal([]int{5}))
}
Expand All @@ -47,7 +47,7 @@ var _ = Describe("Making Synchronous Assertions", func() {
ig = NewInstrumentedGomega()
returnValue = ig.G.Ω(actual, extras...).Should(SpecMatch(), optionalDescription...)
Expect(returnValue).To(Equal(expectedReturnValue))
Expect(ig.FailureMessage).To(Equal(expectedFailureMessage))
Expect(ig.FailureMessage).To(ContainSubstring(expectedFailureMessage))
if expectedFailureMessage != "" {
Expect(ig.FailureSkip).To(Equal([]int{2}))
}
Expand All @@ -56,7 +56,7 @@ var _ = Describe("Making Synchronous Assertions", func() {
ig := NewInstrumentedGomega()
returnValue := ig.G.Expect(actual, extras...).ToNot(SpecMatch(), optionalDescription...)
Expect(returnValue).To(Equal(expectedReturnValue))
Expect(ig.FailureMessage).To(Equal(expectedFailureMessage))
Expect(ig.FailureMessage).To(ContainSubstring(expectedFailureMessage))
if expectedFailureMessage != "" {
Expect(ig.FailureSkip).To(Equal([]int{2}))
}
Expand All @@ -65,7 +65,7 @@ var _ = Describe("Making Synchronous Assertions", func() {
ig = NewInstrumentedGomega()
returnValue = ig.G.Expect(actual, extras...).NotTo(SpecMatch(), optionalDescription...)
Expect(returnValue).To(Equal(expectedReturnValue))
Expect(ig.FailureMessage).To(Equal(expectedFailureMessage))
Expect(ig.FailureMessage).To(ContainSubstring(expectedFailureMessage))
if expectedFailureMessage != "" {
Expect(ig.FailureSkip).To(Equal([]int{2}))
}
Expand All @@ -74,7 +74,7 @@ var _ = Describe("Making Synchronous Assertions", func() {
ig = NewInstrumentedGomega()
returnValue = ig.G.ExpectWithOffset(3, actual, extras...).NotTo(SpecMatch(), optionalDescription...)
Expect(returnValue).To(Equal(expectedReturnValue))
Expect(ig.FailureMessage).To(Equal(expectedFailureMessage))
Expect(ig.FailureMessage).To(ContainSubstring(expectedFailureMessage))
if expectedFailureMessage != "" {
Expect(ig.FailureSkip).To(Equal([]int{5}))
}
Expand All @@ -83,7 +83,7 @@ var _ = Describe("Making Synchronous Assertions", func() {
ig = NewInstrumentedGomega()
returnValue = ig.G.Ω(actual, extras...).ShouldNot(SpecMatch(), optionalDescription...)
Expect(returnValue).To(Equal(expectedReturnValue))
Expect(ig.FailureMessage).To(Equal(expectedFailureMessage))
Expect(ig.FailureMessage).To(ContainSubstring(expectedFailureMessage))
if expectedFailureMessage != "" {
Expect(ig.FailureSkip).To(Equal([]int{2}))
}
Expand Down Expand Up @@ -145,6 +145,11 @@ var _ = Describe("Making Synchronous Assertions", func() {
MATCH, Extras(1, "bam", struct{ Foo string }{Foo: "foo"}, nil), OptionalDescription(),
SHOULD_MATCH, "Unexpected non-nil/non-zero argument at index 1:\n\t<int>: 1", IT_FAILS,
),
Entry(
"when the matcher matches but an error is included, it fails",
MATCH, Extras(0, "", errors.New("welp!")), OptionalDescription(),
SHOULD_MATCH, "Unexpected error: welp!", IT_FAILS,
),
)

var SHOULD_OCCUR = true
Expand Down Expand Up @@ -191,7 +196,6 @@ var _ = Describe("Making Synchronous Assertions", func() {
)

When("vetting optional description parameters", func() {

It("panics when Gomega matcher is at the beginning of optional description parameters", func() {
ig := NewInstrumentedGomega()
for _, expectator := range []string{
Expand Down
12 changes: 10 additions & 2 deletions internal/async_assertion.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"sync"
"time"

"github.com/onsi/gomega/format"
"github.com/onsi/gomega/types"
)

Expand Down Expand Up @@ -164,6 +165,8 @@ func (assertion *AsyncAssertion) buildDescription(optionalDescription ...interfa
return fmt.Sprintf(optionalDescription[0].(string), optionalDescription[1:]...) + "\n"
}

var errInterface = reflect.TypeOf((*error)(nil)).Elem()

func (assertion *AsyncAssertion) processReturnValues(values []reflect.Value) (interface{}, error, StopTryingError) {
var err error
var stopTrying StopTryingError
Expand All @@ -184,12 +187,17 @@ func (assertion *AsyncAssertion) processReturnValues(values []reflect.Value) (in
stopTrying = stopTryingErr
continue
}
zero := reflect.Zero(reflect.TypeOf(extra)).Interface()
extraType := reflect.TypeOf(extra)
zero := reflect.Zero(extraType).Interface()
if reflect.DeepEqual(extra, zero) {
continue
}
if i == len(values)-2 && extraType.Implements(errInterface) {
err = fmt.Errorf("function returned error: %s\n%s", extra, format.Object(extra, 1))
continue
}
if err == nil {
err = fmt.Errorf("Unexpected non-nil/non-zero argument at index %d:\n\t<%T>: %#v", i+1, extra, extra)
err = fmt.Errorf("Unexpected non-nil/non-zero return value at index %d:\n\t<%T>: %#v", i+1, extra, extra)
}
}
return actual, err, stopTrying
Expand Down
13 changes: 10 additions & 3 deletions internal/async_assertion_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -508,10 +508,17 @@ var _ = Describe("Asynchronous Assertions", func() {
ig.G.Eventually(func() (int, string, Foo, error) {
return 1, "", Foo{Bar: "hi"}, nil
}).WithTimeout(30 * time.Millisecond).WithPolling(10 * time.Millisecond).Should(BeNumerically("<", 100))
Ω(ig.FailureMessage).Should(ContainSubstring("Error: Unexpected non-nil/non-zero argument at index 2:"))
Ω(ig.FailureMessage).Should(ContainSubstring("Error: Unexpected non-nil/non-zero return value at index 2:"))
Ω(ig.FailureMessage).Should(ContainSubstring(`Foo{Bar:"hi"}`))
})

It("has a meaningful message if all the return values are zero except the final return value, and it is an error", func() {
ig.G.Eventually(func() (int, string, Foo, error) {
return 1, "", Foo{}, errors.New("welp!")
}).WithTimeout(50 * time.Millisecond).WithPolling(10 * time.Millisecond).Should(BeNumerically("<", 100))
Ω(ig.FailureMessage).Should(ContainSubstring("Error: function returned error: welp!"))
})

Context("when making a ShouldNot assertion", func() {
It("doesn't succeed until the matcher is (not) satisfied with the first returned value _and_ all additional values are zero", func() {
counter, s, f, err := 0, "hi", Foo{Bar: "hi"}, errors.New("hi")
Expand Down Expand Up @@ -554,7 +561,7 @@ var _ = Describe("Asynchronous Assertions", func() {
}
return counter, s, f, err
}).WithTimeout(50 * time.Millisecond).WithPolling(10 * time.Millisecond).Should(BeNumerically("<", 100))
Ω(ig.FailureMessage).Should(ContainSubstring("Error: Unexpected non-nil/non-zero argument at index 2:"))
Ω(ig.FailureMessage).Should(ContainSubstring("Error: Unexpected non-nil/non-zero return value at index 2:"))
Ω(ig.FailureMessage).Should(ContainSubstring(`Foo{Bar:"welp"}`))
Ω(counter).Should(Equal(3))
})
Expand All @@ -581,7 +588,7 @@ var _ = Describe("Asynchronous Assertions", func() {
}
return counter, s, f, err
}).WithTimeout(50 * time.Millisecond).WithPolling(10 * time.Millisecond).ShouldNot(BeNumerically(">", 100))
Ω(ig.FailureMessage).Should(ContainSubstring("Error: Unexpected non-nil/non-zero argument at index 1:"))
Ω(ig.FailureMessage).Should(ContainSubstring("Error: Unexpected non-nil/non-zero return value at index 1:"))
Ω(ig.FailureMessage).Should(ContainSubstring(`<string>: "welp"`))
Ω(counter).Should(Equal(3))
})
Expand Down

0 comments on commit 78deb62

Please sign in to comment.