Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow WithTransform()'s function to accept a nil value #422

Merged
merged 1 commit into from Feb 26, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
20 changes: 15 additions & 5 deletions matchers/with_transform.go
Expand Up @@ -40,15 +40,25 @@ func NewWithTransformMatcher(transform interface{}, matcher types.GomegaMatcher)
}

func (m *WithTransformMatcher) Match(actual interface{}) (bool, error) {
// return error if actual's type is incompatible with Transform function's argument type
actualType := reflect.TypeOf(actual)
if !actualType.AssignableTo(m.transformArgType) {
return false, fmt.Errorf("Transform function expects '%s' but we have '%s'", m.transformArgType, actualType)
// prepare a parameter to pass to the Transform function
var param reflect.Value
{
if actual != nil {
// return error if actual's type is incompatible with Transform function's argument type
actualType := reflect.TypeOf(actual)
if !actualType.AssignableTo(m.transformArgType) {
return false, fmt.Errorf("Transform function expects '%s' but we have '%s'", m.transformArgType, actualType)
}
param = reflect.ValueOf(actual)
} else {
// make a nil value of the expected type
param = reflect.New(m.transformArgType).Elem()
}
Comment on lines +53 to +56
Copy link
Contributor

@cbandy cbandy Feb 26, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is no longer checking that the actual = nil is appropriate for the transform function. This incorrectly succeeds:

gomega.WithTransform(
	func(int) bool { return true },
	gomega.BeTrue(),
).Match(nil)

I recommend the following:

	var param reflect.Value
	if actual != nil && reflect.TypeOf(actual).AssignableTo(m.transformArgType) {
		// The original type of actual is compatible with the transform argument.
		param = reflect.ValueOf(actual)

	} else if actual == nil && m.transformArgType.Kind() == reflect.Interface {
		// The original type of actual is unknown, so there's no way to make its
		// reflect.Value. Create a nil of the transform argument, which is known.
		param = reflect.Zero(m.transformArgType)

	} else {
		return false, fmt.Errorf("Transform function expects '%s' but we have '%T'", m.transformArgType, actual)
	}

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks @cbandy - are you up for submitting this as a PR?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, no problem. Submitted #423.

}

// call the Transform function with `actual`
fn := reflect.ValueOf(m.Transform)
result := fn.Call([]reflect.Value{reflect.ValueOf(actual)})
result := fn.Call([]reflect.Value{param})
m.transformedValue = result[0].Interface() // expect exactly one value

return m.Matcher.Match(m.transformedValue)
Expand Down
8 changes: 7 additions & 1 deletion matchers/with_transform_test.go
Expand Up @@ -51,7 +51,13 @@ var _ = Describe("WithTransformMatcher", func() {
Expect(S{1, "hi"}).To(WithTransform(transformer, Equal("hi")))

// transform expects interface
errString := func(e error) string { return e.Error() }
errString := func(e error) string {
if e == nil {
return "<nil>"
}
return e.Error()
}
Expect(nil).To(WithTransform(errString, Equal("<nil>")), "handles nil actual values")
Expect(errors.New("abc")).To(WithTransform(errString, Equal("abc")))
})

Expand Down