Skip to content

Commit bf93408

Browse files
authoredSep 27, 2021
allow transform functions to report errors (#472)
1 parent 07f405d commit bf93408

File tree

3 files changed

+34
-4
lines changed

3 files changed

+34
-4
lines changed
 

‎matchers.go

+6-1
Original file line numberDiff line numberDiff line change
@@ -485,10 +485,15 @@ func Not(matcher types.GomegaMatcher) types.GomegaMatcher {
485485
}
486486

487487
//WithTransform applies the `transform` to the actual value and matches it against `matcher`.
488-
//The given transform must be a function of one parameter that returns one value.
488+
//The given transform must be either a function of one parameter that returns one value or a
489+
// function of one parameter that returns two values, where the second value must be of the
490+
// error type.
489491
// var plus1 = func(i int) int { return i + 1 }
490492
// Expect(1).To(WithTransform(plus1, Equal(2))
491493
//
494+
// var failingplus1 = func(i int) (int, error) { return 42, "this does not compute" }
495+
// Expect(1).To(WithTrafo(failingplus1, Equal(2)))
496+
//
492497
//And(), Or(), Not() and WithTransform() allow matchers to be composed into complex expressions.
493498
func WithTransform(transform interface{}, matcher types.GomegaMatcher) types.GomegaMatcher {
494499
return matchers.NewWithTransformMatcher(transform, matcher)

‎matchers/with_transform.go

+13-3
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import (
99

1010
type WithTransformMatcher struct {
1111
// input
12-
Transform interface{} // must be a function of one parameter that returns one value
12+
Transform interface{} // must be a function of one parameter that returns one value and an optional error
1313
Matcher types.GomegaMatcher
1414

1515
// cached value
@@ -19,6 +19,9 @@ type WithTransformMatcher struct {
1919
transformedValue interface{}
2020
}
2121

22+
// reflect.Type for error
23+
var errorT = reflect.TypeOf((*error)(nil)).Elem()
24+
2225
func NewWithTransformMatcher(transform interface{}, matcher types.GomegaMatcher) *WithTransformMatcher {
2326
if transform == nil {
2427
panic("transform function cannot be nil")
@@ -27,8 +30,10 @@ func NewWithTransformMatcher(transform interface{}, matcher types.GomegaMatcher)
2730
if txType.NumIn() != 1 {
2831
panic("transform function must have 1 argument")
2932
}
30-
if txType.NumOut() != 1 {
31-
panic("transform function must have 1 return value")
33+
if numout := txType.NumOut(); numout != 1 {
34+
if numout != 2 || !txType.Out(1).AssignableTo(errorT) {
35+
panic("transform function must either have 1 return value, or 1 return value plus 1 error value")
36+
}
3237
}
3338

3439
return &WithTransformMatcher{
@@ -57,6 +62,11 @@ func (m *WithTransformMatcher) Match(actual interface{}) (bool, error) {
5762
// call the Transform function with `actual`
5863
fn := reflect.ValueOf(m.Transform)
5964
result := fn.Call([]reflect.Value{param})
65+
if len(result) == 2 {
66+
if !result[1].IsNil() {
67+
return false, fmt.Errorf("Transform function failed: %e", result[1].Interface())
68+
}
69+
}
6070
m.transformedValue = result[0].Interface() // expect exactly one value
6171

6272
return m.Matcher.Match(m.transformedValue)

‎matchers/with_transform_test.go

+15
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,11 @@ var _ = Describe("WithTransformMatcher", func() {
3535
panicsWithTransformer(func(i int) (int, int) { return 5, 6 })
3636
})
3737
})
38+
Context("Invalid number of return values, but correct number of arguments", func() {
39+
It("Two return values, but second return value not an error", func() {
40+
panicsWithTransformer(func(interface{}) (int, int) { return 5, 6 })
41+
})
42+
})
3843
})
3944

4045
When("the actual value is incompatible", func() {
@@ -121,6 +126,16 @@ var _ = Describe("WithTransformMatcher", func() {
121126
})
122127
})
123128

129+
When("transform fails", func() {
130+
It("reports the transformation error", func() {
131+
actual, trafo := "foo", func(string) (string, error) { return "", errors.New("that does not transform") }
132+
success, err := WithTransform(trafo, Equal(actual)).Match(actual)
133+
Expect(success).To(BeFalse())
134+
Expect(err).To(HaveOccurred())
135+
Expect(err.Error()).To(ContainSubstring("that does not transform"))
136+
})
137+
})
138+
124139
Context("actual value is incompatible with transform function's argument type", func() {
125140
It("gracefully fails if transform cannot be performed", func() {
126141
m := WithTransform(plus1, Equal(3))

0 commit comments

Comments
 (0)
Please sign in to comment.