1// Copyright 2010 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 is a mock framework for Go. 16// 17// Standard usage: 18// (1) Define an interface that you wish to mock. 19// type MyInterface interface { 20// SomeMethod(x int64, y string) 21// } 22// (2) Use mockgen to generate a mock from the interface. 23// (3) Use the mock in a test: 24// func TestMyThing(t *testing.T) { 25// mockCtrl := gomock.NewController(t) 26// defer mockCtrl.Finish() 27// 28// mockObj := something.NewMockMyInterface(mockCtrl) 29// mockObj.EXPECT().SomeMethod(4, "blah") 30// // pass mockObj to a real object and play with it. 31// } 32// 33// By default, expected calls are not enforced to run in any particular order. 34// Call order dependency can be enforced by use of InOrder and/or Call.After. 35// Call.After can create more varied call order dependencies, but InOrder is 36// often more convenient. 37// 38// The following examples create equivalent call order dependencies. 39// 40// Example of using Call.After to chain expected call order: 41// 42// firstCall := mockObj.EXPECT().SomeMethod(1, "first") 43// secondCall := mockObj.EXPECT().SomeMethod(2, "second").After(firstCall) 44// mockObj.EXPECT().SomeMethod(3, "third").After(secondCall) 45// 46// Example of using InOrder to declare expected call order: 47// 48// gomock.InOrder( 49// mockObj.EXPECT().SomeMethod(1, "first"), 50// mockObj.EXPECT().SomeMethod(2, "second"), 51// mockObj.EXPECT().SomeMethod(3, "third"), 52// ) 53package gomock 54 55import ( 56 "context" 57 "fmt" 58 "reflect" 59 "runtime" 60 "sync" 61) 62 63// A TestReporter is something that can be used to report test failures. It 64// is satisfied by the standard library's *testing.T. 65type TestReporter interface { 66 Errorf(format string, args ...interface{}) 67 Fatalf(format string, args ...interface{}) 68} 69 70// TestHelper is a TestReporter that has the Helper method. It is satisfied 71// by the standard library's *testing.T. 72type TestHelper interface { 73 TestReporter 74 Helper() 75} 76 77// cleanuper is used to check if TestHelper also has the `Cleanup` method. A 78// common pattern is to pass in a `*testing.T` to 79// `NewController(t TestReporter)`. In Go 1.14+, `*testing.T` has a cleanup 80// method. This can be utilized to call `Finish()` so the caller of this library 81// does not have to. 82type cleanuper interface { 83 Cleanup(func()) 84} 85 86// A Controller represents the top-level control of a mock ecosystem. It 87// defines the scope and lifetime of mock objects, as well as their 88// expectations. It is safe to call Controller's methods from multiple 89// goroutines. Each test should create a new Controller and invoke Finish via 90// defer. 91// 92// func TestFoo(t *testing.T) { 93// ctrl := gomock.NewController(t) 94// defer ctrl.Finish() 95// // .. 96// } 97// 98// func TestBar(t *testing.T) { 99// t.Run("Sub-Test-1", st) { 100// ctrl := gomock.NewController(st) 101// defer ctrl.Finish() 102// // .. 103// }) 104// t.Run("Sub-Test-2", st) { 105// ctrl := gomock.NewController(st) 106// defer ctrl.Finish() 107// // .. 108// }) 109// }) 110type Controller struct { 111 // T should only be called within a generated mock. It is not intended to 112 // be used in user code and may be changed in future versions. T is the 113 // TestReporter passed in when creating the Controller via NewController. 114 // If the TestReporter does not implement a TestHelper it will be wrapped 115 // with a nopTestHelper. 116 T TestHelper 117 mu sync.Mutex 118 expectedCalls *callSet 119 finished bool 120} 121 122// NewController returns a new Controller. It is the preferred way to create a 123// Controller. 124// 125// New in go1.14+, if you are passing a *testing.T into this function you no 126// longer need to call ctrl.Finish() in your test methods 127func NewController(t TestReporter) *Controller { 128 h, ok := t.(TestHelper) 129 if !ok { 130 h = &nopTestHelper{t} 131 } 132 ctrl := &Controller{ 133 T: h, 134 expectedCalls: newCallSet(), 135 } 136 if c, ok := isCleanuper(ctrl.T); ok { 137 c.Cleanup(func() { 138 ctrl.T.Helper() 139 ctrl.finish(true, nil) 140 }) 141 } 142 143 return ctrl 144} 145 146type cancelReporter struct { 147 t TestHelper 148 cancel func() 149} 150 151func (r *cancelReporter) Errorf(format string, args ...interface{}) { 152 r.t.Errorf(format, args...) 153} 154func (r *cancelReporter) Fatalf(format string, args ...interface{}) { 155 defer r.cancel() 156 r.t.Fatalf(format, args...) 157} 158 159func (r *cancelReporter) Helper() { 160 r.t.Helper() 161} 162 163// WithContext returns a new Controller and a Context, which is cancelled on any 164// fatal failure. 165func WithContext(ctx context.Context, t TestReporter) (*Controller, context.Context) { 166 h, ok := t.(TestHelper) 167 if !ok { 168 h = &nopTestHelper{t: t} 169 } 170 171 ctx, cancel := context.WithCancel(ctx) 172 return NewController(&cancelReporter{t: h, cancel: cancel}), ctx 173} 174 175type nopTestHelper struct { 176 t TestReporter 177} 178 179func (h *nopTestHelper) Errorf(format string, args ...interface{}) { 180 h.t.Errorf(format, args...) 181} 182func (h *nopTestHelper) Fatalf(format string, args ...interface{}) { 183 h.t.Fatalf(format, args...) 184} 185 186func (h nopTestHelper) Helper() {} 187 188// RecordCall is called by a mock. It should not be called by user code. 189func (ctrl *Controller) RecordCall(receiver interface{}, method string, args ...interface{}) *Call { 190 ctrl.T.Helper() 191 192 recv := reflect.ValueOf(receiver) 193 for i := 0; i < recv.Type().NumMethod(); i++ { 194 if recv.Type().Method(i).Name == method { 195 return ctrl.RecordCallWithMethodType(receiver, method, recv.Method(i).Type(), args...) 196 } 197 } 198 ctrl.T.Fatalf("gomock: failed finding method %s on %T", method, receiver) 199 panic("unreachable") 200} 201 202// RecordCallWithMethodType is called by a mock. It should not be called by user code. 203func (ctrl *Controller) RecordCallWithMethodType(receiver interface{}, method string, methodType reflect.Type, args ...interface{}) *Call { 204 ctrl.T.Helper() 205 206 call := newCall(ctrl.T, receiver, method, methodType, args...) 207 208 ctrl.mu.Lock() 209 defer ctrl.mu.Unlock() 210 ctrl.expectedCalls.Add(call) 211 212 return call 213} 214 215// Call is called by a mock. It should not be called by user code. 216func (ctrl *Controller) Call(receiver interface{}, method string, args ...interface{}) []interface{} { 217 ctrl.T.Helper() 218 219 // Nest this code so we can use defer to make sure the lock is released. 220 actions := func() []func([]interface{}) []interface{} { 221 ctrl.T.Helper() 222 ctrl.mu.Lock() 223 defer ctrl.mu.Unlock() 224 225 expected, err := ctrl.expectedCalls.FindMatch(receiver, method, args) 226 if err != nil { 227 // callerInfo's skip should be updated if the number of calls between the user's test 228 // and this line changes, i.e. this code is wrapped in another anonymous function. 229 // 0 is us, 1 is controller.Call(), 2 is the generated mock, and 3 is the user's test. 230 origin := callerInfo(3) 231 ctrl.T.Fatalf("Unexpected call to %T.%v(%v) at %s because: %s", receiver, method, args, origin, err) 232 } 233 234 // Two things happen here: 235 // * the matching call no longer needs to check prerequite calls, 236 // * and the prerequite calls are no longer expected, so remove them. 237 preReqCalls := expected.dropPrereqs() 238 for _, preReqCall := range preReqCalls { 239 ctrl.expectedCalls.Remove(preReqCall) 240 } 241 242 actions := expected.call() 243 if expected.exhausted() { 244 ctrl.expectedCalls.Remove(expected) 245 } 246 return actions 247 }() 248 249 var rets []interface{} 250 for _, action := range actions { 251 if r := action(args); r != nil { 252 rets = r 253 } 254 } 255 256 return rets 257} 258 259// Finish checks to see if all the methods that were expected to be called 260// were called. It should be invoked for each Controller. It is not idempotent 261// and therefore can only be invoked once. 262func (ctrl *Controller) Finish() { 263 // If we're currently panicking, probably because this is a deferred call. 264 // This must be recovered in the deferred function. 265 err := recover() 266 ctrl.finish(false, err) 267} 268 269func (ctrl *Controller) finish(cleanup bool, panicErr interface{}) { 270 ctrl.T.Helper() 271 272 ctrl.mu.Lock() 273 defer ctrl.mu.Unlock() 274 275 if ctrl.finished { 276 if _, ok := isCleanuper(ctrl.T); !ok { 277 ctrl.T.Fatalf("Controller.Finish was called more than once. It has to be called exactly once.") 278 } 279 return 280 } 281 ctrl.finished = true 282 283 // Short-circuit, pass through the panic. 284 if panicErr != nil { 285 panic(panicErr) 286 } 287 288 // Check that all remaining expected calls are satisfied. 289 failures := ctrl.expectedCalls.Failures() 290 for _, call := range failures { 291 ctrl.T.Errorf("missing call(s) to %v", call) 292 } 293 if len(failures) != 0 { 294 if !cleanup { 295 ctrl.T.Fatalf("aborting test due to missing call(s)") 296 return 297 } 298 ctrl.T.Errorf("aborting test due to missing call(s)") 299 } 300} 301 302// callerInfo returns the file:line of the call site. skip is the number 303// of stack frames to skip when reporting. 0 is callerInfo's call site. 304func callerInfo(skip int) string { 305 if _, file, line, ok := runtime.Caller(skip + 1); ok { 306 return fmt.Sprintf("%s:%d", file, line) 307 } 308 return "unknown file" 309} 310 311// isCleanuper checks it if t's base TestReporter has a Cleanup method. 312func isCleanuper(t TestReporter) (cleanuper, bool) { 313 tr := unwrapTestReporter(t) 314 c, ok := tr.(cleanuper) 315 return c, ok 316} 317 318// unwrapTestReporter unwraps TestReporter to the base implementation. 319func unwrapTestReporter(t TestReporter) TestReporter { 320 tr := t 321 switch nt := t.(type) { 322 case *cancelReporter: 323 tr = nt.t 324 if h, check := tr.(*nopTestHelper); check { 325 tr = h.t 326 } 327 case *nopTestHelper: 328 tr = nt.t 329 default: 330 // not wrapped 331 } 332 return tr 333} 334