...

Source file src/github.com/golang/mock/gomock/call_test.go

Documentation: github.com/golang/mock/gomock

     1  // Copyright 2020 Google Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    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