petergtz/pegomock

any matcher and creating matchers for structures

godolatry opened this issue · 9 comments

I see that pegomock has specific matchers for strings and other basic objects, but I can't see an "any" matcher. Have I missed something?

Also, when I create my own structures, is it possible to use matchers for them?

Since Go does not have generics, it's not possible to write a generic Any matcher. The matcher must return a proper type. It cannot just return interface{}, because that wouldn't satisfy the mocks function signature.

You should be able to create your own matchers very easily though. Have a look at matcher_factories.go. I think something like this should work:

func AnyMyType() MyType {
    RegisterMatcher(&matcher.AnyMatcher{Type: reflect.Struct})
    return MyType{}
}

I think at some point I will add the auto-generation of some default matchers based on the types used in the interface signatures for which a mock is generated. For the time being, they must be added manually though.

Hope this helps.

Or do you mean:

func AnyMyType() MyType {
RegisterMatcher(&matcher.AnyMatcher{Type: reflect.Struct})
return nil
}

which follows the style of the existing "Any..." matchers - they all
seem to return an appropriate zero value.

Question is, where do I put this function?

matcher is an internal package so I can't import it into my code. This
means that I can't add the method shown above to my test module.

As far as I can see, I would have to hack the pegomock code that I have
downloaded and add my matcher method there, which seems like a bad idea.

Am I missing something obvious?

On Sat, Sep 3, 2016 at 8:32 PM, Peter Götz notifications@github.com wrote:

Since Go does not have generics, it's not possible to write a generic Any
matcher. The matcher must return a proper type. It cannot just return
interface{}, because that wouldn't satisfy the mocks function signature.

You should be able to create your own matchers very easily though. Have a
look at matcher_factories.go. I think something like this should work:

func AnyMyType() MyType {
RegisterMatcher(&matcher.AnyMatcher{Type: reflect.Struct})
return MyType{}
}

I think at some point I will add the auto-generation of some default
matchers based on the types used in the interface signatures for which a
mock is generated. For the time being, they must be added manually though.

Hope this helps.


You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
#22 (comment),
or mute the thread
https://github.com/notifications/unsubscribe-auth/AIfV71bGnFlKOP0BH4QZCGK0mPJZoCi_ks5qmcs9gaJpZM4Jzce3
.

The zero value for MyType is MyType{}. nil can only be used for pointer types, i.e. *MyType. So it depends on the method signature in your interface.

You're right that matcher is not visible outside. That's a bug. I will try to fix it soon, but feel free to provide a pull request, if you need it now.

Thanks.

@godolatry Does this solve your issue?

I'm away at present. I will try this tomorrow (Friday)

Thanks and Regards

Simon

On Wednesday, September 7, 2016, Peter Götz notifications@github.com
wrote:

@godolatry https://github.com/godolatry Does this solve your issue?


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
#22 (comment),
or mute the thread
https://github.com/notifications/unsubscribe-auth/AIfV76ljUyBB6YfrQwHSICazsANle7Spks5qnoINgaJpZM4Jzce3
.

That seems to work, but it only allows me to create a matcher for one of my own own structures. This is because of the "reflect.Struct" part:
func AnyMyType() MyType {
pegomock.RegisterMatcher(&matcher.AnyMatcher{Type: reflect.Struct})
return MyType{}
}

I also need to create a matcher for an interface type.

For example, assume I have defined interfaces A and B plus a structure C. I have objects of those types called a, b and c. Both a and b are mocks. My application makes this call:

a.fun(b, c)

If I need to write a WHEN that uses a matcher for c, then I must supply matchers for all of the parameters, so I need something like:

pegomock.When(a.fun(EqB(b), EqC(c)))

So I need to create a matcher for b, which is an interface with a mock behind it.

Is that possible?

Hi @goblimey,

Can you try with reflect.Interface instead of reflect.Struct when MyType is an interface? Something like this:

func AnyMyType() MyType {
    pegomock.RegisterMatcher(&matcher.AnyMatcher{Type: reflect.Interface})
    return MyType{}
}

I will try this out myself as soon as possible, but maybe it already solves your problem.

@goblimey, @godolatry (you are both called Simon. Are you the same person actually?)

I've just pushed a change which will now properly support custom any-matchers based on interface types.

E.g. if you want to write a custom matcher for the error interface, you would do it like this:

func AnyError() error {
    RegisterMatcher(NewAnyMatcher(reflect.TypeOf((*error)(nil)).Elem()))
    return nil
}

The TypeOf construct looks a bit convoluted, but it's the recommended way.

Let me know if this solves your issue. Thanks.

@goblimey, @godolatry I'm closing this issue due to inactivity. Feel free to re-open, if you don't think the issue is solved.