// Copyright 2010 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package gomock is a mock framework for Go. // // Standard usage: // (1) Define an interface that you wish to mock. // type MyInterface interface { // SomeMethod(x int64, y string) // } // (2) Use mockgen to generate a mock from the interface. // (3) Use the mock in a test: // func TestMyThing(t *testing.T) { // mockCtrl := gomock.NewController(t) // defer mockCtrl.Finish() // // mockObj := something.NewMockMyInterface(mockCtrl) // mockObj.EXPECT().SomeMethod(4, "blah") // // pass mockObj to a real object and play with it. // } // // By default, expected calls are not enforced to run in any particular order. // Call order dependency can be enforced by use of InOrder and/or Call.After. // Call.After can create more varied call order dependencies, but InOrder is // often more convenient. // // The following examples create equivalent call order dependencies. // // Example of using Call.After to chain expected call order: // // firstCall := mockObj.EXPECT().SomeMethod(1, "first") // secondCall := mockObj.EXPECT().SomeMethod(2, "second").After(firstCall) // mockObj.EXPECT().SomeMethod(3, "third").After(secondCall) // // Example of using InOrder to declare expected call order: // // gomock.InOrder( // mockObj.EXPECT().SomeMethod(1, "first"), // mockObj.EXPECT().SomeMethod(2, "second"), // mockObj.EXPECT().SomeMethod(3, "third"), // )
package gomock import ( ) // A TestReporter is something that can be used to report test failures. It // is satisfied by the standard library's *testing.T. type TestReporter interface { Errorf(format string, args ...interface{}) Fatalf(format string, args ...interface{}) } // TestHelper is a TestReporter that has the Helper method. It is satisfied // by the standard library's *testing.T. type TestHelper interface { TestReporter Helper() } // cleanuper is used to check if TestHelper also has the `Cleanup` method. A // common pattern is to pass in a `*testing.T` to // `NewController(t TestReporter)`. In Go 1.14+, `*testing.T` has a cleanup // method. This can be utilized to call `Finish()` so the caller of this library // does not have to. type cleanuper interface { Cleanup(func()) } // A Controller represents the top-level control of a mock ecosystem. It // defines the scope and lifetime of mock objects, as well as their // expectations. It is safe to call Controller's methods from multiple // goroutines. Each test should create a new Controller and invoke Finish via // defer. // // func TestFoo(t *testing.T) { // ctrl := gomock.NewController(t) // defer ctrl.Finish() // // .. // } // // func TestBar(t *testing.T) { // t.Run("Sub-Test-1", st) { // ctrl := gomock.NewController(st) // defer ctrl.Finish() // // .. // }) // t.Run("Sub-Test-2", st) { // ctrl := gomock.NewController(st) // defer ctrl.Finish() // // .. // }) // }) type Controller struct { // T should only be called within a generated mock. It is not intended to // be used in user code and may be changed in future versions. T is the // TestReporter passed in when creating the Controller via NewController. // If the TestReporter does not implement a TestHelper it will be wrapped // with a nopTestHelper. T TestHelper mu sync.Mutex expectedCalls *callSet finished bool } // NewController returns a new Controller. It is the preferred way to create a // Controller. // // New in go1.14+, if you are passing a *testing.T into this function you no // longer need to call ctrl.Finish() in your test methods. func ( TestReporter) *Controller { , := .(TestHelper) if ! { = &nopTestHelper{} } := &Controller{ T: , expectedCalls: newCallSet(), } if , := isCleanuper(.T); { .Cleanup(func() { .T.Helper() .finish(true, nil) }) } return } type cancelReporter struct { t TestHelper cancel func() } func ( *cancelReporter) ( string, ...interface{}) { .t.Errorf(, ...) } func ( *cancelReporter) ( string, ...interface{}) { defer .cancel() .t.Fatalf(, ...) } func ( *cancelReporter) () { .t.Helper() } // WithContext returns a new Controller and a Context, which is cancelled on any // fatal failure. func ( context.Context, TestReporter) (*Controller, context.Context) { , := .(TestHelper) if ! { = &nopTestHelper{t: } } , := context.WithCancel() return NewController(&cancelReporter{t: , cancel: }), } type nopTestHelper struct { t TestReporter } func ( *nopTestHelper) ( string, ...interface{}) { .t.Errorf(, ...) } func ( *nopTestHelper) ( string, ...interface{}) { .t.Fatalf(, ...) } func ( nopTestHelper) () {} // RecordCall is called by a mock. It should not be called by user code. func ( *Controller) ( interface{}, string, ...interface{}) *Call { .T.Helper() := reflect.ValueOf() for := 0; < .Type().NumMethod(); ++ { if .Type().Method().Name == { return .RecordCallWithMethodType(, , .Method().Type(), ...) } } .T.Fatalf("gomock: failed finding method %s on %T", , ) panic("unreachable") } // RecordCallWithMethodType is called by a mock. It should not be called by user code. func ( *Controller) ( interface{}, string, reflect.Type, ...interface{}) *Call { .T.Helper() := newCall(.T, , , , ...) .mu.Lock() defer .mu.Unlock() .expectedCalls.Add() return } // Call is called by a mock. It should not be called by user code. func ( *Controller) ( interface{}, string, ...interface{}) []interface{} { .T.Helper() // Nest this code so we can use defer to make sure the lock is released. := func() []func([]interface{}) []interface{} { .T.Helper() .mu.Lock() defer .mu.Unlock() , := .expectedCalls.FindMatch(, , ) if != nil { // callerInfo's skip should be updated if the number of calls between the user's test // and this line changes, i.e. this code is wrapped in another anonymous function. // 0 is us, 1 is controller.Call(), 2 is the generated mock, and 3 is the user's test. := callerInfo(3) .T.Fatalf("Unexpected call to %T.%v(%v) at %s because: %s", , , , , ) } // Two things happen here: // * the matching call no longer needs to check prerequite calls, // * and the prerequite calls are no longer expected, so remove them. := .dropPrereqs() for , := range { .expectedCalls.Remove() } := .call() if .exhausted() { .expectedCalls.Remove() } return }() var []interface{} for , := range { if := (); != nil { = } } return } // Finish checks to see if all the methods that were expected to be called // were called. It should be invoked for each Controller. It is not idempotent // and therefore can only be invoked once. // // New in go1.14+, if you are passing a *testing.T into NewController function you no // longer need to call ctrl.Finish() in your test methods. func ( *Controller) () { // If we're currently panicking, probably because this is a deferred call. // This must be recovered in the deferred function. := recover() .finish(false, ) } func ( *Controller) ( bool, interface{}) { .T.Helper() .mu.Lock() defer .mu.Unlock() if .finished { if , := isCleanuper(.T); ! { .T.Fatalf("Controller.Finish was called more than once. It has to be called exactly once.") } return } .finished = true // Short-circuit, pass through the panic. if != nil { panic() } // Check that all remaining expected calls are satisfied. := .expectedCalls.Failures() for , := range { .T.Errorf("missing call(s) to %v", ) } if len() != 0 { if ! { .T.Fatalf("aborting test due to missing call(s)") return } .T.Errorf("aborting test due to missing call(s)") } } // callerInfo returns the file:line of the call site. skip is the number // of stack frames to skip when reporting. 0 is callerInfo's call site. func ( int) string { if , , , := runtime.Caller( + 1); { return fmt.Sprintf("%s:%d", , ) } return "unknown file" } // isCleanuper checks it if t's base TestReporter has a Cleanup method. func ( TestReporter) (cleanuper, bool) { := unwrapTestReporter() , := .(cleanuper) return , } // unwrapTestReporter unwraps TestReporter to the base implementation. func ( TestReporter) TestReporter { := switch nt := .(type) { case *cancelReporter: = .t if , := .(*nopTestHelper); { = .t } case *nopTestHelper: = .t default: // not wrapped } return }