Skip to content
This repository was archived by the owner on Jun 27, 2023. It is now read-only.

calling Recorder methods with numbers causes misses due to Go's untyped constant rules #16

Closed
jmhodges opened this issue Dec 13, 2015 · 4 comments

Comments

@jmhodges
Copy link
Contributor

With an interface

type Adder interface{
   Inc(x int64) error
 }

the code generated for the MockAdder has the correct int type:

 func (_m *MockAdder) Do(_param0 int64) error {

while the Recorder has interface{}s for the argument:

func (_m *MockAdderRecoder) Do(arg0 interface{}) error {

This, unfortunately, causes spurious missed expectation in the test case below. This is because the "2" is handed to the AdderRecorder as an int. This is Go's untyped int handling code choosing int instead of int64 as its default type since none is provided explicitly.

It looks plausible from the code to generate the Recorder methods with the right argument types and convert them down as the call method one does. (But maybe I haven't seen the bug that prevented that in the first place.)

One workaround is to just use the same variable in both places and another is to explicitly convert it to the right type, but it might nice for small tests to just make the right type.

type Thing struct { a Adder }
func (t Thing) CallsAdderInc(x int64) { t.a.Inc(x) }

func TestAdder(t *testing.T) {
    ctrl := gomock.NewController(t)
    defer ctrl.Finish()
    adder := NewMockAdder(ctrl)
    myThing := Thing{adder}
    adder.EXPECT().Inc(2).Return(nil) // This 2 is turned into int instead of int64
    myThing.CallsAdderInc(2)
}
@jmhodges jmhodges changed the title calling Recorder methods with numbers causes weird misses calling Recorder methods with numbers causes misses due to Go's untyped constant rules Dec 13, 2015
@jmhodges
Copy link
Contributor Author

Sorry, had a bug in the test case. Fixed it up.

@jmhodges
Copy link
Contributor Author

Ugh, this also occurs with constants called on the recorder that will never change. I'm mocking out a statsd wrapper that always passes 1.0 to a method on the statsd interface that is correctly turned into a float32 in the actual code but the recorder will see it as a float64.

jmhodges added a commit to jmhodges/mock that referenced this issue Dec 13, 2015
This uses the exact types needed in the Recorder methods. It avoids
spurious expectation misses caused by Go converting untyped
constants to
types that do not match the interface generated for.

One example is float literals passed to a `float32` argument were being
converted on x86_64 machines to `float64` because the Recoder methods
had a `interface{}` arg instead of a `float32` arg.

Fixes golang#16
@dsymonds
Copy link
Contributor

The arg types to Recorder methods are interface{} so that Matcher values may be passed (e.g. gomock.Any()). That's not possible if the real types are used.

This is just an unfortunate consequence of trying to squeeze this kind of mocking into Go's type system.

@jmhodges
Copy link
Contributor Author

Of course. How silly of me. Sorry!

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants