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

Commit 6244772

Browse files
authored
Merge pull request #89 from golang/unexported_methods
Fix mocks with unexported methods
2 parents 3006cc2 + e6ff1b0 commit 6244772

File tree

10 files changed

+160
-81
lines changed

10 files changed

+160
-81
lines changed

gomock/call.go

Lines changed: 8 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,11 @@ import (
2424
type Call struct {
2525
t TestReporter // for triggering test failures on invalid call setup
2626

27-
receiver interface{} // the receiver of the method call
28-
method string // the name of the method
29-
args []Matcher // the args
30-
rets []interface{} // the return values (if any)
27+
receiver interface{} // the receiver of the method call
28+
method string // the name of the method
29+
methodType reflect.Type // the type of the method
30+
args []Matcher // the args
31+
rets []interface{} // the return values (if any)
3132

3233
preReqs []*Call // prerequisite calls
3334

@@ -76,7 +77,7 @@ func (c *Call) Do(f interface{}) *Call {
7677
}
7778

7879
func (c *Call) Return(rets ...interface{}) *Call {
79-
mt := c.methodType()
80+
mt := c.methodType
8081
if len(rets) != mt.NumOut() {
8182
c.t.Fatalf("wrong number of arguments to Return for %T.%v: got %d, want %d",
8283
c.receiver, c.method, len(rets), mt.NumOut())
@@ -120,7 +121,7 @@ func (c *Call) SetArg(n int, value interface{}) *Call {
120121
if c.setArgs == nil {
121122
c.setArgs = make(map[int]reflect.Value)
122123
}
123-
mt := c.methodType()
124+
mt := c.methodType
124125
// TODO: This will break on variadic methods.
125126
// We will need to check those at invocation time.
126127
if n < 0 || n >= mt.NumIn() {
@@ -239,7 +240,7 @@ func (c *Call) call(args []interface{}) (rets []interface{}, action func()) {
239240
rets = c.rets
240241
if rets == nil {
241242
// Synthesize the zero value for each of the return args' types.
242-
mt := c.methodType()
243+
mt := c.methodType
243244
rets = make([]interface{}, mt.NumOut())
244245
for i := 0; i < mt.NumOut(); i++ {
245246
rets[i] = reflect.Zero(mt.Out(i)).Interface()
@@ -249,16 +250,6 @@ func (c *Call) call(args []interface{}) (rets []interface{}, action func()) {
249250
return
250251
}
251252

252-
func (c *Call) methodType() reflect.Type {
253-
recv := reflect.ValueOf(c.receiver)
254-
for i := 0; i < recv.Type().NumMethod(); i++ {
255-
if recv.Type().Method(i).Name == c.method {
256-
return recv.Method(i).Type()
257-
}
258-
}
259-
panic(fmt.Sprintf("gomock: failed finding method %s on %T", c.method, c.receiver))
260-
}
261-
262253
// InOrder declares that the given calls should occur in order.
263254
func InOrder(calls ...*Call) {
264255
for i := 1; i < len(calls); i++ {

gomock/controller.go

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,10 @@
5555
// - Handle different argument/return types (e.g. ..., chan, map, interface).
5656
package gomock
5757

58-
import "sync"
58+
import (
59+
"reflect"
60+
"sync"
61+
)
5962

6063
// A TestReporter is something that can be used to report test failures.
6164
// It is satisfied by the standard library's *testing.T.
@@ -80,7 +83,7 @@ func NewController(t TestReporter) *Controller {
8083
}
8184
}
8285

83-
func (ctrl *Controller) RecordCall(receiver interface{}, method string, args ...interface{}) *Call {
86+
func (ctrl *Controller) RecordCall(receiver interface{}, method string, methodType reflect.Type, args ...interface{}) *Call {
8487
// TODO: check arity, types.
8588
margs := make([]Matcher, len(args))
8689
for i, arg := range args {
@@ -98,7 +101,7 @@ func (ctrl *Controller) RecordCall(receiver interface{}, method string, args ...
98101
ctrl.mu.Lock()
99102
defer ctrl.mu.Unlock()
100103

101-
call := &Call{t: ctrl.t, receiver: receiver, method: method, args: margs, minCalls: 1, maxCalls: 1}
104+
call := &Call{t: ctrl.t, receiver: receiver, method: method, methodType: methodType, args: margs, minCalls: 1, maxCalls: 1}
102105

103106
ctrl.expectedCalls.Add(call)
104107
return call

gomock/controller_test.go

Lines changed: 36 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ func (e *ErrorReporter) assertPass(msg string) {
4848

4949
func (e *ErrorReporter) assertFail(msg string) {
5050
if !e.failed {
51-
e.t.Error("Expected failure, but got pass: %s", msg)
51+
e.t.Errorf("Expected failure, but got pass: %s", msg)
5252
}
5353
}
5454

@@ -119,9 +119,14 @@ func (s *Subject) BarMethod(arg string) int {
119119
return 0
120120
}
121121

122+
var (
123+
FooMethodType = reflect.TypeOf((*Subject).FooMethod)
124+
BarMethodType = reflect.TypeOf((*Subject).BarMethod)
125+
)
126+
122127
func assertEqual(t *testing.T, expected interface{}, actual interface{}) {
123128
if !reflect.DeepEqual(expected, actual) {
124-
t.Error("Expected %+v, but got %+v", expected, actual)
129+
t.Errorf("Expected %+v, but got %+v", expected, actual)
125130
}
126131
}
127132

@@ -144,7 +149,7 @@ func TestExpectedMethodCall(t *testing.T) {
144149
reporter, ctrl := createFixtures(t)
145150
subject := new(Subject)
146151

147-
ctrl.RecordCall(subject, "FooMethod", "argument")
152+
ctrl.RecordCall(subject, "FooMethod", FooMethodType, "argument")
148153
ctrl.Call(subject, "FooMethod", "argument")
149154
ctrl.Finish()
150155

@@ -166,7 +171,7 @@ func TestRepeatedCall(t *testing.T) {
166171
reporter, ctrl := createFixtures(t)
167172
subject := new(Subject)
168173

169-
ctrl.RecordCall(subject, "FooMethod", "argument").Times(3)
174+
ctrl.RecordCall(subject, "FooMethod", FooMethodType, "argument").Times(3)
170175
ctrl.Call(subject, "FooMethod", "argument")
171176
ctrl.Call(subject, "FooMethod", "argument")
172177
ctrl.Call(subject, "FooMethod", "argument")
@@ -183,7 +188,7 @@ func TestUnexpectedArgCount(t *testing.T) {
183188
defer reporter.recoverUnexpectedFatal()
184189
subject := new(Subject)
185190

186-
ctrl.RecordCall(subject, "FooMethod", "argument")
191+
ctrl.RecordCall(subject, "FooMethod", FooMethodType, "argument")
187192
reporter.assertFatal(func() {
188193
// This call is made with the wrong number of arguments...
189194
ctrl.Call(subject, "FooMethod", "argument", "extra_argument")
@@ -202,7 +207,7 @@ func TestAnyTimes(t *testing.T) {
202207
reporter, ctrl := createFixtures(t)
203208
subject := new(Subject)
204209

205-
ctrl.RecordCall(subject, "FooMethod", "argument").AnyTimes()
210+
ctrl.RecordCall(subject, "FooMethod", FooMethodType, "argument").AnyTimes()
206211
for i := 0; i < 100; i++ {
207212
ctrl.Call(subject, "FooMethod", "argument")
208213
}
@@ -214,22 +219,22 @@ func TestMinTimes1(t *testing.T) {
214219
// It fails if there are no calls
215220
reporter, ctrl := createFixtures(t)
216221
subject := new(Subject)
217-
ctrl.RecordCall(subject, "FooMethod", "argument").MinTimes(1)
222+
ctrl.RecordCall(subject, "FooMethod", FooMethodType, "argument").MinTimes(1)
218223
reporter.assertFatal(func() {
219224
ctrl.Finish()
220225
})
221226

222227
// It succeeds if there is one call
223228
reporter, ctrl = createFixtures(t)
224229
subject = new(Subject)
225-
ctrl.RecordCall(subject, "FooMethod", "argument").MinTimes(1)
230+
ctrl.RecordCall(subject, "FooMethod", FooMethodType, "argument").MinTimes(1)
226231
ctrl.Call(subject, "FooMethod", "argument")
227232
ctrl.Finish()
228233

229234
// It succeeds if there are many calls
230235
reporter, ctrl = createFixtures(t)
231236
subject = new(Subject)
232-
ctrl.RecordCall(subject, "FooMethod", "argument").MinTimes(1)
237+
ctrl.RecordCall(subject, "FooMethod", FooMethodType, "argument").MinTimes(1)
233238
for i := 0; i < 100; i++ {
234239
ctrl.Call(subject, "FooMethod", "argument")
235240
}
@@ -240,20 +245,20 @@ func TestMaxTimes1(t *testing.T) {
240245
// It succeeds if there are no calls
241246
_, ctrl := createFixtures(t)
242247
subject := new(Subject)
243-
ctrl.RecordCall(subject, "FooMethod", "argument").MaxTimes(1)
248+
ctrl.RecordCall(subject, "FooMethod", FooMethodType, "argument").MaxTimes(1)
244249
ctrl.Finish()
245250

246251
// It succeeds if there is one call
247252
_, ctrl = createFixtures(t)
248253
subject = new(Subject)
249-
ctrl.RecordCall(subject, "FooMethod", "argument").MaxTimes(1)
254+
ctrl.RecordCall(subject, "FooMethod", FooMethodType, "argument").MaxTimes(1)
250255
ctrl.Call(subject, "FooMethod", "argument")
251256
ctrl.Finish()
252257

253258
//It fails if there are more
254259
reporter, ctrl := createFixtures(t)
255260
subject = new(Subject)
256-
ctrl.RecordCall(subject, "FooMethod", "argument").MaxTimes(1)
261+
ctrl.RecordCall(subject, "FooMethod", FooMethodType, "argument").MaxTimes(1)
257262
ctrl.Call(subject, "FooMethod", "argument")
258263
reporter.assertFatal(func() {
259264
ctrl.Call(subject, "FooMethod", "argument")
@@ -265,7 +270,7 @@ func TestMinMaxTimes(t *testing.T) {
265270
// It fails if there are less calls than specified
266271
reporter, ctrl := createFixtures(t)
267272
subject := new(Subject)
268-
ctrl.RecordCall(subject, "FooMethod", "argument").MinTimes(2).MaxTimes(2)
273+
ctrl.RecordCall(subject, "FooMethod", FooMethodType, "argument").MinTimes(2).MaxTimes(2)
269274
ctrl.Call(subject, "FooMethod", "argument")
270275
reporter.assertFatal(func() {
271276
ctrl.Finish()
@@ -274,7 +279,7 @@ func TestMinMaxTimes(t *testing.T) {
274279
// It fails if there are more calls than specified
275280
reporter, ctrl = createFixtures(t)
276281
subject = new(Subject)
277-
ctrl.RecordCall(subject, "FooMethod", "argument").MinTimes(2).MaxTimes(2)
282+
ctrl.RecordCall(subject, "FooMethod", FooMethodType, "argument").MinTimes(2).MaxTimes(2)
278283
ctrl.Call(subject, "FooMethod", "argument")
279284
ctrl.Call(subject, "FooMethod", "argument")
280285
reporter.assertFatal(func() {
@@ -284,7 +289,7 @@ func TestMinMaxTimes(t *testing.T) {
284289
// It succeeds if there is just the right number of calls
285290
reporter, ctrl = createFixtures(t)
286291
subject = new(Subject)
287-
ctrl.RecordCall(subject, "FooMethod", "argument").MaxTimes(2).MinTimes(2)
292+
ctrl.RecordCall(subject, "FooMethod", FooMethodType, "argument").MaxTimes(2).MinTimes(2)
288293
ctrl.Call(subject, "FooMethod", "argument")
289294
ctrl.Call(subject, "FooMethod", "argument")
290295
ctrl.Finish()
@@ -296,7 +301,7 @@ func TestDo(t *testing.T) {
296301

297302
doCalled := false
298303
var argument string
299-
ctrl.RecordCall(subject, "FooMethod", "argument").Do(
304+
ctrl.RecordCall(subject, "FooMethod", FooMethodType, "argument").Do(
300305
func(arg string) {
301306
doCalled = true
302307
argument = arg
@@ -322,8 +327,8 @@ func TestReturn(t *testing.T) {
322327
subject := new(Subject)
323328

324329
// Unspecified return should produce "zero" result.
325-
ctrl.RecordCall(subject, "FooMethod", "zero")
326-
ctrl.RecordCall(subject, "FooMethod", "five").Return(5)
330+
ctrl.RecordCall(subject, "FooMethod", FooMethodType, "zero")
331+
ctrl.RecordCall(subject, "FooMethod", FooMethodType, "five").Return(5)
327332

328333
assertEqual(
329334
t,
@@ -343,10 +348,10 @@ func TestUnorderedCalls(t *testing.T) {
343348
subjectTwo := new(Subject)
344349
subjectOne := new(Subject)
345350

346-
ctrl.RecordCall(subjectOne, "FooMethod", "1")
347-
ctrl.RecordCall(subjectOne, "BarMethod", "2")
348-
ctrl.RecordCall(subjectTwo, "FooMethod", "3")
349-
ctrl.RecordCall(subjectTwo, "BarMethod", "4")
351+
ctrl.RecordCall(subjectOne, "FooMethod", FooMethodType, "1")
352+
ctrl.RecordCall(subjectOne, "BarMethod", BarMethodType, "2")
353+
ctrl.RecordCall(subjectTwo, "FooMethod", FooMethodType, "3")
354+
ctrl.RecordCall(subjectTwo, "BarMethod", BarMethodType, "4")
350355

351356
// Make the calls in a different order, which should be fine.
352357
ctrl.Call(subjectOne, "BarMethod", "2")
@@ -368,9 +373,9 @@ func commonTestOrderedCalls(t *testing.T) (reporter *ErrorReporter, ctrl *gomock
368373
subjectTwo = new(Subject)
369374

370375
gomock.InOrder(
371-
ctrl.RecordCall(subjectOne, "FooMethod", "1").AnyTimes(),
372-
ctrl.RecordCall(subjectTwo, "FooMethod", "2"),
373-
ctrl.RecordCall(subjectTwo, "BarMethod", "3"),
376+
ctrl.RecordCall(subjectOne, "FooMethod", FooMethodType, "1").AnyTimes(),
377+
ctrl.RecordCall(subjectTwo, "FooMethod", FooMethodType, "2"),
378+
ctrl.RecordCall(subjectTwo, "BarMethod", BarMethodType, "3"),
374379
)
375380

376381
return
@@ -423,9 +428,9 @@ func TestCallAfterLoopPanic(t *testing.T) {
423428

424429
subject := new(Subject)
425430

426-
firstCall := ctrl.RecordCall(subject, "Foo", "1")
427-
secondCall := ctrl.RecordCall(subject, "Foo", "2")
428-
thirdCall := ctrl.RecordCall(subject, "Foo", "3")
431+
firstCall := ctrl.RecordCall(subject, "FooMethod", FooMethodType, "1")
432+
secondCall := ctrl.RecordCall(subject, "FooMethod", FooMethodType, "2")
433+
thirdCall := ctrl.RecordCall(subject, "FooMethod", FooMethodType, "3")
429434

430435
gomock.InOrder(firstCall, secondCall, thirdCall)
431436

@@ -445,7 +450,7 @@ func TestPanicOverridesExpectationChecks(t *testing.T) {
445450
reporter := NewErrorReporter(t)
446451

447452
reporter.assertFatal(func() {
448-
ctrl.RecordCall(new(Subject), "FooMethod", "1")
453+
ctrl.RecordCall(new(Subject), "FooMethod", FooMethodType, "1")
449454
defer ctrl.Finish()
450455
reporter.Fatalf("Intentional panic")
451456
})
@@ -458,7 +463,7 @@ func TestSetArgWithBadType(t *testing.T) {
458463
s := new(Subject)
459464
// This should catch a type error:
460465
rep.assertFatal(func() {
461-
ctrl.RecordCall(s, "FooMethod", "1").SetArg(0, "blah")
466+
ctrl.RecordCall(s, "FooMethod", FooMethodType, "1").SetArg(0, "blah")
462467
})
463468
ctrl.Call(s, "FooMethod", "1")
464469
}
@@ -468,7 +473,7 @@ func TestTimes0(t *testing.T) {
468473
defer ctrl.Finish()
469474

470475
s := new(Subject)
471-
ctrl.RecordCall(s, "FooMethod", "arg").Times(0)
476+
ctrl.RecordCall(s, "FooMethod", FooMethodType, "arg").Times(0)
472477
rep.assertFatal(func() {
473478
ctrl.Call(s, "FooMethod", "arg")
474479
})

gomock/mock_matcher/mock_matcher.go

Lines changed: 3 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

mockgen/mockgen.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,7 @@ func (g *generator) Generate(pkg *model.Package, pkgName string) error {
193193
// Get all required imports, and generate unique names for them all.
194194
im := pkg.Imports()
195195
im[gomockImportPath] = true
196+
im["reflect"] = true
196197

197198
// Sort keys to make import alias generation predictable
198199
sorted_paths := make([]string, len(im), len(im))
@@ -424,7 +425,7 @@ func (g *generator) GenerateMockRecorderMethod(mockType string, m *model.Method)
424425
callArgs = ", _s..."
425426
}
426427
}
427-
g.p(`return _mr.mock.ctrl.RecordCall(_mr.mock, "%v"%v)`, m.Name, callArgs)
428+
g.p(`return _mr.mock.ctrl.RecordCall(_mr.mock, "%s", reflect.TypeOf((*%s)(nil).%s)%s)`, m.Name, mockType, m.Name, callArgs)
428429

429430
g.out()
430431
g.p("}")
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
From #52, this tests an unexported method in the mocked interface.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
//go:generate mockgen -destination bugreport_mock.go -package bugreport -source=bugreport.go Example
2+
3+
package bugreport
4+
5+
import "fmt"
6+
7+
// Example is an interface with a non exported method
8+
type Example interface {
9+
someMethod(string) string
10+
}
11+
12+
// CallExample is a simple function that uses the interface
13+
func CallExample(e Example) {
14+
fmt.Println(e.someMethod("test"))
15+
}

0 commit comments

Comments
 (0)