How do you implement specific behavior for a Mockery function - go

I'm using the Go Mockery package, and I want the function Next to do some actions before returning. However, when I do this:
mockIter.On("Next", mock.AnythingOfType("*types.Query")).Return(func(q *types.Query) bool {
condition := (do something that returns a boolean)
return condition
})
I get this error:
panic: interface conversion: interface {} is func(*types.Query) bool, not bool
I must be using the package wrong, but it seems like this is correct because they have this very similar example in their docs:
Mock.On("passthrough", mock.AnythingOfType("context.Context"), mock.AnythingOfType("string")).Return(func(ctx context.Context, s string) string {
return s
})
Any ideas on what I'm doing wrong?

Return function is used to return values on call of the mocked function. You can't change the signature of the mocked function.
Here you're returning func(*types.Query) bool (function that returns boolean) instead of bool, as the error message say.
You can have the function to make some computation and then return the value. You just have to add () (or whatever arguments your function accepts) after function definition to invoke it and you'll be good to go.
This works:
mockIter.On("Next", mock.AnythingOfType("*types.Query")).Return(func() bool {
condition := (do something that returns a boolean)
return condition
}())
But it seems to me that you want to do some computation based on the argument that is passed on the mocked call. I don't think mockery supports that at the moment.

Related

Go: Access a struct's properties through an interface{}

I am having trouble in accessing the one struct's properties (named Params) in different file.
please consider x.go where i invoke a function(CreateTodo)
type Params struct {
Title string `json:"title"`
IsCompleted int `json:is_completed`
Status string `json:status`
}
var data = &Params{Title:"booking hotel", IsCompleted :0,Status:"not started"}
isCreated := todoModel.CreateTodo(data) // assume todoModel is imported
now CreateTodo is a method on a struct (named Todo) in different file lets say y.go
type Todo struct {
Id int `json:todo_id`
Title string `json:"title"`
IsCompleted int `json:is_completed`
Status string `json:status`
}
func (mytodo Todo)CreateTodo(data interface{}) bool{
// want to access the properties of data here
fmt.Println(data.Title)
return true
}
Now I just want to use properties of data in CreateTodo function in y.go.
But i am not able to do so and getting following error
data.Title undefined (type interface {} is interface with no methods)
I am sure issue is around accepting struct as an empty interface but i am not able to figure out.
Please help here.Thanks
So you have one of two options, depending on your model:
#1
Switch to data *Params instead of data interface{} as suggested in another answer but it looks like you are expecting different types in this function, if so; check option #2 below.
#2
Use Type switches as follows:
func (t Todo) CreateTodo(data interface{}) bool {
switch x := data.(type) {
case Params:
fmt.Println(x.Title)
return true
// Other expected types
default:
// Unexpected type
return false
}
}
P.S. Be careful with your json tags: it should be json:"tagName". Notice the ""! Check go vet.
You could just type the function parameter:
func (mytodo Todo)CreateTodo(data *Params) bool{
// want to access the properties of data here
fmt.Println(data.Title)
return true
}
See: https://play.golang.org/p/9N8ixBaSHdP
If you want to operate on a Params (or *Params), you must do that.
If you want to operate on an opaque type hidden behind an interface{}, you must do that.
In short, you cannot peek behind the curtain without peeking behind the curtain. Either expose the actual type Params, so that you can look at it, or keep all the code that does look at it elsewhere. The "keep the code elsewhere" is where interface really shines, because it allows you to declare that something otherwise-opaque has behaviors and ask for those behaviors to happen:
type Titler interface {
GetTitle() string
}
If Params has a GetTitle function, it becomes a Titler.
You can now define your CreateTodo as a function that takes a Titler, and then you can pass &data to this function.
This structure is overall quite klunky and it seems much more likely that Todo itself should be an embeddable struct instead, but see a more complete example starting from a stripped-down version of your sample code here, in the Go Playground.

Difference in a function implementation when instantiating an object with different function signatures

Came across the following differences a function implementations. What is the reasoning behind Example 1 returning a pointer and Example 2 returning an actual object?
type MyInterface interface {
Func (param int) float64 //just random signature
}
//MyInterfaceImpl implements MyInterface
type MyInterfaceImpl struct {
}
//actual implementation
func (myObj *MyInterfaceImpl) Func(param int) float64 {
return float64(param)
}
Example 1: the pointer to the MyInterfaceImpl is returned when function returns an interface
func NewMyInterface() MyInterface {
return &MyInterfaceImpl{}
}
Example 2: actual object of MyInterfaceImpl is returned when function returns the object
func NewMyInterfaceImpl() MyInterfaceImpl {
return MyInterfaceImpl{}
}
UPDATE: This piece of code compiles and runs
func main() {
myIf := NewMyInterface()
fmt.Printf("Hi from inteface %f\n", myIf.Func(1000))
myImpl := NewMyInterfaceImpl()
fmt.Printf("Hi from impl %f\n", myImpl.Func(100))
}
UPDATE2: Question clarification.
This sounds weird (for me) to have a declaration of func NewMyInterface() MyInterface and a valid implementation of return &MyInterfaceImpl{} where a pointer is returned. I would expect to return an object of MyInterfaceImpl with return MyInterfaceImpl{}
If the language allows such types of constructs, there must be a reason for that. Eventually, I am looking for a following answer: "The function declaration returns an interface. Because the interface has a property X it is does not make sense to return an object, but the only valid option is a pointer".
Even though I'm not sure which part of the code the question is about, let me explain what the code does:
MyInterface is implemented by anything having a Func(int)float64 method.
*MyInterfaceImpl has such a method. However, MyInterfaceImpl does not (the method has a pointer receiver).
NewMyInterface() thus has to return a pointer. MyInterfaceImpl{} wouldn't implement MyInterface.
Does this answer your question?
Another question might be why the call myImpl.Func(100) works, despite the above. This is because Go automatically takes the address of the receiver when calling its methods with pointer receivers.
This is explained in more detail for example here.

Implementing interface type to function type in Golang

I have created few types including interface as:
// GetProfileHandlerFunc turns a function with the right signature into a get profile handler
type GetProfileHandlerFunc func(GetProfileParams, interface{}) middleware.Responder
// Handle executing the request and returning a response
func (fn GetProfileHandlerFunc) Handle(params GetProfileParams, principal interface{}) middleware.Responder {
return fn(params, principal)
}
// GetProfileHandler interface for that can handle valid get profile params
type GetProfileHandler interface {
Handle(GetProfileParams, interface{}) middleware.Responder
}
Now in my api implementation package. I am using a logic to handle the request parameters. I am trying to assign GetProfileHandlerFunc to another type since it implements GetProfileHandler interface as you can see above.
api.ProfileGetProfileHandler = profile.GetProfileHandlerFunc(func(params profile.GetProfileParams, principal *models.User) middleware.Responder {
// contains logic to handle the request
}
Now I think I can do above logic. But I am getting type mismatch error.
cannot convert func literal (type func(profile.GetProfileParams,
*"userproj/models".User)
middleware.Responder) to type profile.GetProfileHandlerFuncgo
the point is:
if you have a function like
func A(param interface{}) {}
you can pass anything to param when you make a call to function A. like
A(10)
A(true)
A(nil)
Because interface{} means everything. So your handle func definition:
type GetProfileHandlerFunc func(GetProfileParams, interface{}) middleware.Responder
means a function GetProfileHandlerFunc which takes two params, the first is of type GetProfileParams, the second is of type interface{}. That means second param canbe anything.
But
func(params profile.GetProfileParams, principal *models.User) middleware.Responder
means a function which takes two params, the first is of type GetProfileParams, the second is of type *models.User. So, do you think they are the same? No.
I need a function can take anything as second param,not a function who can only take User as second function.
When you call your handle
GetProfileHandlerFunc(params, 10) // this is ok
So is that ok for
func(params profile.GetProfileParams, principal *models.User) middleware.Responder
No.
The right way to do this is :
api.ProfileGetProfileHandler = profile.GetProfileHandlerFunc(func(params profile.GetProfileParams, principal interface) middleware.Responder {
user:=principal.(*model.User) // watch this.
}

Override interface's function callback arguments

I am using a package that has a Router interface, and I have created my own app-specific Router interface that wraps the third party package.
Everything is working well, however one of the methods is throwing a compilation error:
controllers/auth.go:52:17: cannot use func literal (type func(router.Router)) as type func(chi.Router) in argument to c.router.Group
This is the interface of the third party package (chi):
type Router interface {
// ...
// Group adds a new inline-Router along the current routing
// path, with a fresh middleware stack for the inline-Router.
Group(fn func(r Router)) Router
// ...
}
This is my wrapper interface:
type Router interface {
chi.Router
// Custom methods...
}
My usage of the Group function is like so:
type AuthController struct {
router router.Router
// ...
}
func (c *AuthController) SetRoutes() {
c.router.Group(func(r router.Router) {
r.Use(middleware.Anyone)
r.Post("/auth/register", c.Register)
r.Post("/auth/login", c.Authenticate)
r.Post("/auth/token/refresh", c.RefreshToken)
})
c.router.Group(func(r router.Router) {
r.Use(middleware.Authorized)
r.Get("/auth/ping", c.Ping)
r.Post("/auth/logout", c.Logout)
})
}
Why is it screaming at my function callbacks argument type? My wrapper router.Router implements the chi.Router interface, so it should work fine shouldn't it? Am I misunderstanding how Go works here?
I can see how this can be confusing so I will try to break it down. You have this method:
Group(fn func(r Router)) Router
This method takes a function as a parameter. That function must have a specific signature:
func(r Router)
That is, it takes a single argument of type chi.Router and has no return values. However, when you call it:
c.router.Group(func(r router.Router) { /***/ }
You're passing in a function of the wrong signature; your function signature is:
func(r router.Router)
That's not the signature required by the method you're calling, so it won't compile. It doesn't matter if router.Router implements chi.Router; the parameter (a func(router.Router)) passed is not of the expected type (a func(chi.Router)).
This may seem silly at first - after all, any router.Router must implement chi.Router. But, think about it: that method, Group, is expecting to receive a function, to which it can pass any chi.Router. That means it can pass a chi.Router which does not implement router.Router. If it were to accept your function, it would break type safety, and what in Go is meant to be a compile-time error (the error you're getting, in fact) would become a run-time error. Basically, by passing a function with a different (and more strict) argument type, you're expecting a guarantee which that method never offered.
The parameter types aren't the same, so the function type doesn't match what's expected, even though your interface includes the interface from the other package (the type has to match exactly). You need to have your functions take a chi.router and then use a type assertion, i.e., myRouter := r.(Router), to convert to your type.

How pass different structures to function?

I have several different structures.
Here show two:
type AdsResponse struct {
Body struct {
Docs []struct {
ID int `json:"ID"`
// others
} `json:"docs"`
} `json:"response"`
Header `json:"responseHeader"`
}
type OtherResponse struct {
Body struct {
Docs []struct {
ID int `json:"ID"`
// others
} `json:"docs"`
} `json:"response"`
Header `json:"responseHeader"`
}
but i don't know how i can do for this method accepts and return both.
func Get(url string, response Response) (Response, bool) {
res, err := goreq.Request{
Uri: url,
}.Do()
// several validations
res.Body.FromJsonTo(&response)
return response, true
}
And use like this:
var struct1 AdsResponse
var struct2 OtherResponse
Get("someURL", struct1)
Get("someURL", struct2)
There are any form?
Your code example is somewhat confusing since both structs appear to be identical. I'll assume that they differ somewhere in "others".
First, I generally recommend creating a wrapper around these kinds of JSON deserializations. Working directly on the JSON structure is fragile. Most of your program should not be aware of the fact that the data comes down in JSON. So for instance, you can wrap this in an Ads struct that contains an AdsResponse, or just copies the pieces it cares about out of it. Doing that will also make some of the below slightly easier to implement and less fragile.
The most common solution is probably to create an interface:
type Response interface {
ID() int
}
You make both Ads and Others conform to Response. Then you can return Response. If necessary, you can type-switch later to figure out which one you have and unload other data.
switch response := response.(type) {
case Ads:
...
case Other:
...
}
I don't quite get why you have the reponse as a parameter and as a return. I think you dont need to return it. You should pass a pointer to the reponse and fill it with the data. Also, I'd return an Error instead of a boolean, but that is another topic.
Anyway, the solution is to use interface{} (empty interface).
You are lucky because the function you are using (FromJsonTo) accepts an empty interface as a parameter, so you can safely change your parameter type to interface{} and just pass it to FromJsonTo. Like this:
func Get(url string, response interface{}) bool {
res, err := goreq.Request{
Uri: url,
}.Do()
// several validations
res.Body.FromJsonTo(response)
return true
}
Warning: I did not compile the code.
Then you would call this function with the url and a pointer to one of the reponse structs like this:
var struct1 AdsResponse
var struct2 OtherResponse
Get("someURL", &struct1)
Get("someURL", &struct2)
The way to achieve this is through Go's interfaces.
Two options:
empty interface
Get(url string, response interface{}) (Response, bool)
This option allows any value to be given to this function.
custom interface
Creating a custom interface will allow you to narrow down the types that can be provided as arguments to your function.
In this case you'll have to create an interface that all your Response structs will need to abide by. Any struct really that abides by that interface will be able to be used as an argument of your function.
Something like this:
type MyResponse interface {
SomeFunction()
}
Then your function signature could look like
Get(url string, response MyResponse) (MyResponse, bool)
As long as AdsResponse and OtherResponse abide by the MyResponse interface, they will be allowed to be used as arguments to the function.
Follow the solution working at Go Playground
Go has no polymorphic or any other OO like behaviour, so, when you try to pass a AdsResponse or OtherResponse struct as an Response (or any interface{}), these values becomes an Response (or other param type specified), and is not possible to Go to infer the real type that originate these interface{} and correctly decode your json to these struct types as expected.
This kind of thing should works perfectly in OO languages, like Java, C# etc. There is no hierarchy generalization/specialization on structs/interfaces in Go.
You would need to do a type assertion in your Rest executor, or a switch case, but it seems that you need a generic REST executor, like a generic lib some thing like that. Would not reasonable create a switch case for each struct in your program. Maybe you have dozens or hundreds of structs soon.
I think that a reasonable solution is the rest client pass a lambda function to do the last step for your, that is just create a correct struct destination type and call json decode.
As i say above, the return type of executeRest() in my example will became an interface{}, but the rest client can securely do the type assertion of returned value after executeRest() call.

Resources