1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package gomock
16
17 import (
18 "fmt"
19 "reflect"
20 "testing"
21 )
22
23 type foo struct{}
24
25 func (f foo) String() string {
26 return "meow"
27 }
28
29 type a struct {
30 name string
31 }
32
33 func (testObj a) Name() string {
34 return testObj.name
35 }
36
37 type b struct {
38 foo string
39 }
40
41 func (testObj b) Foo() string {
42 return testObj.foo
43 }
44
45 type mockTestReporter struct {
46 errorCalls int
47 fatalCalls int
48 }
49
50 func (o *mockTestReporter) Errorf(format string, args ...interface{}) {
51 o.errorCalls++
52 }
53
54 func (o *mockTestReporter) Fatalf(format string, args ...interface{}) {
55 o.fatalCalls++
56 }
57
58 func (o *mockTestReporter) Helper() {}
59
60 func TestCall_After(t *testing.T) {
61 t.Run("SelfPrereqCallsFatalf", func(t *testing.T) {
62 tr1 := &mockTestReporter{}
63
64 c := &Call{t: tr1}
65 c.After(c)
66
67 if tr1.fatalCalls != 1 {
68 t.Errorf("number of fatal calls == %v, want 1", tr1.fatalCalls)
69 }
70 })
71
72 t.Run("LoopInCallOrderCallsFatalf", func(t *testing.T) {
73 tr1 := &mockTestReporter{}
74 tr2 := &mockTestReporter{}
75
76 c1 := &Call{t: tr1}
77 c2 := &Call{t: tr2}
78 c1.After(c2)
79 c2.After(c1)
80
81 if tr1.errorCalls != 0 || tr1.fatalCalls != 0 {
82 t.Error("unexpected errors")
83 }
84
85 if tr2.fatalCalls != 1 {
86 t.Errorf("number of fatal calls == %v, want 1", tr2.fatalCalls)
87 }
88 })
89 }
90
91 func prepareDoCall(doFunc, callFunc interface{}) *Call {
92 tr := &mockTestReporter{}
93
94 c := &Call{
95 t: tr,
96 methodType: reflect.TypeOf(callFunc),
97 }
98
99 c.Do(doFunc)
100
101 return c
102 }
103
104 func prepareDoAndReturnCall(doFunc, callFunc interface{}) *Call {
105 tr := &mockTestReporter{}
106
107 c := &Call{
108 t: tr,
109 methodType: reflect.TypeOf(callFunc),
110 }
111
112 c.DoAndReturn(doFunc)
113
114 return c
115 }
116
117 type testCase struct {
118 description string
119 doFunc interface{}
120 callFunc interface{}
121 args []interface{}
122 expectPanic bool
123 }
124
125 var testCases []testCase = []testCase{
126 {
127 description: "argument to Do is not a function",
128 doFunc: "meow",
129 callFunc: func(x int, y int) {},
130 args: []interface{}{0, 1},
131 expectPanic: true,
132 }, {
133 description: "argument to Do is not a function",
134 doFunc: "meow",
135 callFunc: func(x int, y int) bool {
136 return true
137 },
138 args: []interface{}{0, 1},
139 expectPanic: true,
140 }, {
141 description: "number of args for Do func don't match Call func",
142 doFunc: func(x int) {},
143 callFunc: func(x int, y int) {},
144 args: []interface{}{0, 1},
145 expectPanic: false,
146 }, {
147 description: "number of args for Do func don't match Call func",
148 doFunc: func(x int) bool {
149 return true
150 },
151 callFunc: func(x int, y int) bool {
152 return true
153 },
154 args: []interface{}{0, 1},
155 expectPanic: false,
156 }, {
157 description: "arg type for Do func incompatible with Call func",
158 doFunc: func(x int) {},
159 callFunc: func(x string) {},
160 args: []interface{}{"meow"},
161 expectPanic: true,
162 }, {
163 description: "arg type for Do func incompatible with Call func",
164 doFunc: func(x int) bool {
165 return true
166 },
167 callFunc: func(x string) bool {
168 return true
169 },
170 args: []interface{}{"meow"},
171 expectPanic: true,
172 }, {
173 description: "Do func(int) Call func(int)",
174 doFunc: func(x int) {},
175 callFunc: func(x int) {},
176 args: []interface{}{0},
177 }, {
178 description: "Do func(int) Call func(interface{})",
179 doFunc: func(x int) {},
180 callFunc: func(x interface{}) {},
181 args: []interface{}{0},
182 }, {
183 description: "Do func(int) bool Call func(int) bool",
184 doFunc: func(x int) bool {
185 return true
186 },
187 callFunc: func(x int) bool {
188 return true
189 },
190 args: []interface{}{0},
191 }, {
192 description: "Do func(int) bool Call func(interface{}) bool",
193 doFunc: func(x int) bool {
194 return true
195 },
196 callFunc: func(x interface{}) bool {
197 return true
198 },
199 args: []interface{}{0},
200 }, {
201 description: "Do func(string) Call func([]byte)",
202 doFunc: func(x string) {},
203 callFunc: func(x []byte) {},
204 args: []interface{}{[]byte("meow")},
205 expectPanic: true,
206 }, {
207 description: "Do func(string) bool Call func([]byte) bool",
208 doFunc: func(x string) bool {
209 return true
210 },
211 callFunc: func(x []byte) bool {
212 return true
213 },
214 args: []interface{}{[]byte("meow")},
215 expectPanic: true,
216 }, {
217 description: "Do func(map[int]string) Call func(map[interface{}]int)",
218 doFunc: func(x map[int]string) {},
219 callFunc: func(x map[interface{}]int) {},
220 args: []interface{}{map[interface{}]int{"meow": 0}},
221 expectPanic: true,
222 }, {
223 description: "Do func(map[int]string) Call func(map[interface{}]interface{})",
224 doFunc: func(x map[int]string) {},
225 callFunc: func(x map[interface{}]interface{}) {},
226 args: []interface{}{map[interface{}]interface{}{"meow": "meow"}},
227 expectPanic: true,
228 }, {
229 description: "Do func(map[int]string) bool Call func(map[interface{}]int) bool",
230 doFunc: func(x map[int]string) bool {
231 return true
232 },
233 callFunc: func(x map[interface{}]int) bool {
234 return true
235 },
236 args: []interface{}{map[interface{}]int{"meow": 0}},
237 expectPanic: true,
238 }, {
239 description: "Do func(map[int]string) bool Call func(map[interface{}]interface{}) bool",
240 doFunc: func(x map[int]string) bool {
241 return true
242 },
243 callFunc: func(x map[interface{}]interface{}) bool {
244 return true
245 },
246 args: []interface{}{map[interface{}]interface{}{"meow": "meow"}},
247 expectPanic: true,
248 }, {
249 description: "Do func([]string) Call func([]interface{})",
250 doFunc: func(x []string) {},
251 callFunc: func(x []interface{}) {},
252 args: []interface{}{[]interface{}{0}},
253 expectPanic: true,
254 }, {
255 description: "Do func([]string) Call func([]int)",
256 doFunc: func(x []string) {},
257 callFunc: func(x []int) {},
258 args: []interface{}{[]int{0, 1}},
259 expectPanic: true,
260 }, {
261 description: "Do func([]int) Call func([]int)",
262 doFunc: func(x []int) {},
263 callFunc: func(x []int) {},
264 args: []interface{}{[]int{0, 1}},
265 }, {
266 description: "Do func([]int) Call func([]interface{})",
267 doFunc: func(x []int) {},
268 callFunc: func(x []interface{}) {},
269 args: []interface{}{[]interface{}{0}},
270 expectPanic: true,
271 }, {
272 description: "Do func([]int) Call func(...interface{})",
273 doFunc: func(x []int) {},
274 callFunc: func(x ...interface{}) {},
275 args: []interface{}{0, 1},
276 expectPanic: true,
277 }, {
278 description: "Do func([]int) Call func(...int)",
279 doFunc: func(x []int) {},
280 callFunc: func(x ...int) {},
281 args: []interface{}{0, 1},
282 expectPanic: true,
283 }, {
284 description: "Do func([]string) bool Call func([]interface{}) bool",
285 doFunc: func(x []string) bool {
286 return true
287 },
288 callFunc: func(x []interface{}) bool {
289 return true
290 },
291 args: []interface{}{[]interface{}{0}},
292 expectPanic: true,
293 }, {
294 description: "Do func([]string) bool Call func([]int) bool",
295 doFunc: func(x []string) bool {
296 return true
297 },
298 callFunc: func(x []int) bool {
299 return true
300 },
301 args: []interface{}{[]int{0, 1}},
302 expectPanic: true,
303 }, {
304 description: "Do func([]int) bool Call func([]int) bool",
305 doFunc: func(x []int) bool {
306 return true
307 },
308 callFunc: func(x []int) bool {
309 return true
310 },
311 args: []interface{}{[]int{0, 1}},
312 }, {
313 description: "Do func([]int) bool Call func([]interface{}) bool",
314 doFunc: func(x []int) bool {
315 return true
316 },
317 callFunc: func(x []interface{}) bool {
318 return true
319 },
320 args: []interface{}{[]interface{}{0}},
321 expectPanic: true,
322 }, {
323 description: "Do func([]int) bool Call func(...interface{}) bool",
324 doFunc: func(x []int) bool {
325 return true
326 },
327 callFunc: func(x ...interface{}) bool {
328 return true
329 },
330 args: []interface{}{0, 1},
331 expectPanic: true,
332 }, {
333 description: "Do func([]int) bool Call func(...int) bool",
334 doFunc: func(x []int) bool {
335 return true
336 },
337 callFunc: func(x ...int) bool {
338 return true
339 },
340 args: []interface{}{0, 1},
341 expectPanic: true,
342 }, {
343 description: "Do func(...int) Call func([]int)",
344 doFunc: func(x ...int) {},
345 callFunc: func(x []int) {},
346 args: []interface{}{[]int{0, 1}},
347 expectPanic: true,
348 }, {
349 description: "Do func(...int) Call func([]interface{})",
350 doFunc: func(x ...int) {},
351 callFunc: func(x []interface{}) {},
352 args: []interface{}{[]interface{}{0, 1}},
353 expectPanic: true,
354 }, {
355 description: "Do func(...int) Call func(...interface{})",
356 doFunc: func(x ...int) {},
357 callFunc: func(x ...interface{}) {},
358 args: []interface{}{0, 1},
359 }, {
360 description: "Do func(...int) bool Call func(...int) bool",
361 doFunc: func(x ...int) bool {
362 return true
363 },
364 callFunc: func(x ...int) bool {
365 return true
366 },
367 args: []interface{}{0, 1},
368 }, {
369 description: "Do func(...int) bool Call func([]int) bool",
370 doFunc: func(x ...int) bool {
371 return true
372 },
373 callFunc: func(x []int) bool {
374 return true
375 },
376 args: []interface{}{[]int{0, 1}},
377 expectPanic: true,
378 }, {
379 description: "Do func(...int) bool Call func([]interface{}) bool",
380 doFunc: func(x ...int) bool {
381 return true
382 },
383 callFunc: func(x []interface{}) bool {
384 return true
385 },
386 args: []interface{}{[]interface{}{0, 1}},
387 expectPanic: true,
388 }, {
389 description: "Do func(...int) bool Call func(...interface{}) bool",
390 doFunc: func(x ...int) bool {
391 return true
392 },
393 callFunc: func(x ...interface{}) bool {
394 return true
395 },
396 args: []interface{}{0, 1},
397 }, {
398 description: "Do func(...int) Call func(...int)",
399 doFunc: func(x ...int) {},
400 callFunc: func(x ...int) {},
401 args: []interface{}{0, 1},
402 }, {
403 description: "Do func(foo); foo implements interface X Call func(interface X)",
404 doFunc: func(x foo) {},
405 callFunc: func(x fmt.Stringer) {},
406 args: []interface{}{foo{}},
407 }, {
408 description: "Do func(b); b does not implement interface X Call func(interface X)",
409 doFunc: func(x b) {},
410 callFunc: func(x fmt.Stringer) {},
411 args: []interface{}{foo{}},
412 expectPanic: true,
413 }, {
414 description: "Do func(b) Call func(a); a and b are not aliases",
415 doFunc: func(x b) {},
416 callFunc: func(x a) {},
417 args: []interface{}{a{}},
418 expectPanic: true,
419 }, {
420 description: "Do func(foo) bool; foo implements interface X Call func(interface X) bool",
421 doFunc: func(x foo) bool {
422 return true
423 },
424 callFunc: func(x fmt.Stringer) bool {
425 return true
426 },
427 args: []interface{}{foo{}},
428 }, {
429 description: "Do func(b) bool; b does not implement interface X Call func(interface X) bool",
430 doFunc: func(x b) bool {
431 return true
432 },
433 callFunc: func(x fmt.Stringer) bool {
434 return true
435 },
436 args: []interface{}{foo{}},
437 expectPanic: true,
438 }, {
439 description: "Do func(b) bool Call func(a) bool; a and b are not aliases",
440 doFunc: func(x b) bool {
441 return true
442 },
443 callFunc: func(x a) bool {
444 return true
445 },
446 args: []interface{}{a{}},
447 expectPanic: true,
448 }, {
449 description: "Do func(bool) b Call func(bool) a; a and b are not aliases",
450 doFunc: func(x bool) b {
451 return b{}
452 },
453 callFunc: func(x bool) a {
454 return a{}
455 },
456 args: []interface{}{true},
457 },
458 }
459
460 func TestCall_Do(t *testing.T) {
461 for _, tc := range testCases {
462 t.Run(tc.description, func(t *testing.T) {
463 c := prepareDoCall(tc.doFunc, tc.callFunc)
464
465 if len(c.actions) != 1 {
466 t.Errorf("expected %d actions but got %d", 1, len(c.actions))
467 }
468
469 action := c.actions[0]
470
471 if tc.expectPanic {
472 defer func() {
473 if r := recover(); r == nil {
474 t.Error("expected Do to panic")
475 }
476 }()
477 }
478
479 action(tc.args)
480 })
481 }
482 }
483
484 func TestCall_Do_NumArgValidation(t *testing.T) {
485 tests := []struct {
486 name string
487 methodType reflect.Type
488 doFn interface{}
489 args []interface{}
490 wantErr bool
491 }{
492 {
493 name: "too few",
494 methodType: reflect.TypeOf(func(one, two string) {}),
495 doFn: func(one string) {},
496 args: []interface{}{"too", "few"},
497 wantErr: true,
498 },
499 {
500 name: "too many",
501 methodType: reflect.TypeOf(func(one, two string) {}),
502 doFn: func(one, two, three string) {},
503 args: []interface{}{"too", "few"},
504 wantErr: true,
505 },
506 {
507 name: "just right",
508 methodType: reflect.TypeOf(func(one, two string) {}),
509 doFn: func(one string, two string) {},
510 args: []interface{}{"just", "right"},
511 wantErr: false,
512 },
513 {
514 name: "variadic",
515 methodType: reflect.TypeOf(func(one, two string) {}),
516 doFn: func(args ...interface{}) {},
517 args: []interface{}{"just", "right"},
518 wantErr: true,
519 },
520 }
521 for _, tt := range tests {
522 t.Run(tt.name, func(t *testing.T) {
523 tr := &mockTestReporter{}
524 call := &Call{
525 t: tr,
526 methodType: tt.methodType,
527 }
528 call.Do(tt.doFn)
529 call.actions[0](tt.args)
530 if tt.wantErr && tr.fatalCalls != 1 {
531 t.Fatalf("expected call to fail")
532 }
533 if !tt.wantErr && tr.fatalCalls != 0 {
534 t.Fatalf("expected call to pass")
535 }
536 })
537 }
538 }
539
540 func TestCall_DoAndReturn_NumArgValidation(t *testing.T) {
541 tests := []struct {
542 name string
543 methodType reflect.Type
544 doFn interface{}
545 args []interface{}
546 wantErr bool
547 }{
548 {
549 name: "too few",
550 methodType: reflect.TypeOf(func(one, two string) string { return "" }),
551 doFn: func(one string) {},
552 args: []interface{}{"too", "few"},
553 wantErr: true,
554 },
555 {
556 name: "too many",
557 methodType: reflect.TypeOf(func(one, two string) string { return "" }),
558 doFn: func(one, two, three string) string { return "" },
559 args: []interface{}{"too", "few"},
560 wantErr: true,
561 },
562 {
563 name: "just right",
564 methodType: reflect.TypeOf(func(one, two string) string { return "" }),
565 doFn: func(one string, two string) string { return "" },
566 args: []interface{}{"just", "right"},
567 wantErr: false,
568 },
569 {
570 name: "variadic",
571 methodType: reflect.TypeOf(func(one, two string) {}),
572 doFn: func(args ...interface{}) string { return "" },
573 args: []interface{}{"just", "right"},
574 wantErr: true,
575 },
576 }
577 for _, tt := range tests {
578 t.Run(tt.name, func(t *testing.T) {
579 tr := &mockTestReporter{}
580 call := &Call{
581 t: tr,
582 methodType: tt.methodType,
583 }
584 call.DoAndReturn(tt.doFn)
585 call.actions[0](tt.args)
586 if tt.wantErr && tr.fatalCalls != 1 {
587 t.Fatalf("expected call to fail")
588 }
589 if !tt.wantErr && tr.fatalCalls != 0 {
590 t.Fatalf("expected call to pass")
591 }
592 })
593 }
594 }
595
596 func TestCall_DoAndReturn(t *testing.T) {
597 for _, tc := range testCases {
598 t.Run(tc.description, func(t *testing.T) {
599 c := prepareDoAndReturnCall(tc.doFunc, tc.callFunc)
600
601 if len(c.actions) != 1 {
602 t.Errorf("expected %d actions but got %d", 1, len(c.actions))
603 }
604
605 action := c.actions[0]
606
607 if tc.expectPanic {
608 defer func() {
609 if r := recover(); r == nil {
610 t.Error("expected DoAndReturn to panic")
611 }
612 }()
613 }
614
615 action(tc.args)
616 })
617 }
618 }
619
View as plain text