Closed jpopadak closed 5 years ago
It turns out setting the values of params
to each individual value of _paramX
works properly and successfully propagates the value up (if the value is passed by pointer).
Here is an example that works properly:
func (mock *MockDatabase) GetSingle(_param0 interface{}, _param1 interface{}) serviceerror.ServiceError {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockDatabase().")
}
params := []pegomock.Param{_param0, _param1}
result := pegomock.GetGenericMockFrom(mock).Invoke("GetSingle", params, []reflect.Type{reflect.TypeOf((*serviceerror.ServiceError)(nil)).Elem()})
var ret0 serviceerror.ServiceError
if len(result) != 0 {
_param0 = params[0]
_param1 = params[1]
if result[0] != nil {
ret0 = result[0].(serviceerror.ServiceError)
}
}
return ret0
}
Hi @jpopadak, thanks for reporting this. It's an interesting use case I haven't thought of (not using out args very often). So yes, I think we can treat this as a bug.
2 Things:
_param0 = params[0]
and _param1 = params[1]
could actually live outside the if condition unless I'm missing something, because it's independent of return values._param0 = params[0]
changes the parameter on the caller's side of GetSingle
. Because when you assign to _param0
you're working on a copy which is on the stack. I need some time and reproduce this locally. Will get back to you.@petergtz - So after going through this more and debugging it all through, it turns out it is not a bug in the library, but a bug in my code. 👎
If passed by a pointer, or passing an interface type to the empty interface, it successfully updates the value if you are operating directly on it instead of setting the param itself like this:
This does not work:
Whenever(database.GetSingle(argmatchers.AnyType(), argmatchers.AnyType())).Then(func(params []pegomock.Param) pegomock.ReturnValues {
param[0] = &group.Entity{}
param[1] = &group.Entity{}
return pegomock.ReturnValues{nil}
})
This works because we are modifying the object via a pointer:
Whenever(database.GetSingle(argmatchers.AnyType(), argmatchers.AnyType())).Then(func(params []pegomock.Param) pegomock.ReturnValues {
where := params[0].(*group.Entity)
entity := params[1].(*group.Entity)
entity.UUID = where.UUID
entity.Description = description
entity.ResourceGroupTypeUUID = groupTypeUuid
entity.CreatedAt = time.Now()
entity.UpdatedAt = time.Now()
return pegomock.ReturnValues{nil}
})
This works because we are copying an empty object into the already created one:
Whenever(database.GetSingle(argmatchers.AnyType(), argmatchers.AnyType())).Then(func(params []pegomock.Param) pegomock.ReturnValues {
zero := params[0].(*group.Entity)
*zero = group.Entity{}
one := params[1].(*group.Entity)
*one = group.Entity{}
return pegomock.ReturnValues{nil}
})
Okay, cool. Yea, I just confirmed this as well :-D :
type Entity struct{ i int }
var input = []Entity{}
When(func() { display.InterfaceParam(AnyInterface()) }).Then(func(params []pegomock.Param) pegomock.ReturnValues {
*params[0].(*[]Entity) = append(*params[0].(*[]Entity), Entity{3})
return nil
})
fmt.Printf("%#v\n", input)
display.InterfaceParam(&input)
fmt.Printf("%#v\n", input)
prints:
[]pegomock_test.Entity{}
[]pegomock_test.Entity{pegomock_test.Entity{i:3}}
So I guess this can be closed, can it?
Writing a
When().Then()
response allows for a user to modify the response object based upon input parameters. However, when updating the inputparams []pegomock.Param
objects does not get reflected in the response.Example: Create an interface like the following:
Run
pegomock
to generate a mocked object. CallDoStuff()
with an address of a slice ofstruct
s.In the
Then
response, updateparam[0]
itself by either appending or setting the value to a new slice.Doing this all updates the
params
object and sends it back to theMockInter
mocked object code. In the mocked methodDoStuff()
, theparams
object (the one with the combined input params) has the updated data. However, the_param0
object is not updated.Due to this, one cannot successfully mock what a method does as one can pass a reference to a slice inside of an empty interface
interface{}
type.I do not know the best way to solve this or how Go would deal with this.