// 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 gomockimport ()// A TestReporter is something that can be used to report test failures. It// is satisfied by the standard library's *testing.T.typeTestReporterinterface {Errorf(format string, args ...any)Fatalf(format string, args ...any)}// TestHelper is a TestReporter that has the Helper method. It is satisfied// by the standard library's *testing.T.typeTestHelperinterface {TestReporterHelper()}// 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.typecleanuperinterface {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.//// func TestFoo(t *testing.T) {// ctrl := gomock.NewController(t)// // ..// }//// func TestBar(t *testing.T) {// t.Run("Sub-Test-1", st) {// ctrl := gomock.NewController(st)// // ..// })// t.Run("Sub-Test-2", st) {// ctrl := gomock.NewController(st)// // ..// })// })typeControllerstruct {// 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.TTestHelpermusync.MutexexpectedCalls *callSetfinishedbool}// NewController returns a new Controller. It is the preferred way to create a Controller.//// Passing [*testing.T] registers cleanup function to automatically call [Controller.Finish]// when the test and all its subtests complete.func ( TestReporter, ...ControllerOption) *Controller { , := .(TestHelper)if ! { = &nopTestHelper{} } := &Controller{T: ,expectedCalls: newCallSet(), }for , := range { .apply() }if , := isCleanuper(.T); { .Cleanup(func() { .T.Helper() .finish(true, nil) }) }return}// ControllerOption configures how a Controller should behave.typeControllerOptioninterface {apply(*Controller)}typeoverridableExpectationsOptionstruct{}// WithOverridableExpectations allows for overridable call expectations// i.e., subsequent call expectations override existing call expectationsfunc () overridableExpectationsOption {returnoverridableExpectationsOption{}}func ( overridableExpectationsOption) ( *Controller) { .expectedCalls = newOverridableCallSet()}typecancelReporterstruct {tTestHelpercancelfunc()}func ( *cancelReporter) ( string, ...any) { .t.Errorf(, ...)}func ( *cancelReporter) ( string, ...any) {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()returnNewController(&cancelReporter{t: , cancel: }), }typenopTestHelperstruct {tTestReporter}func ( *nopTestHelper) ( string, ...any) { .t.Errorf(, ...)}func ( *nopTestHelper) ( string, ...any) { .t.Fatalf(, ...)}func ( nopTestHelper) () {}// RecordCall is called by a mock. It should not be called by user code.func ( *Controller) ( any, string, ...any) *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) ( any, string, reflect.Type, ...any) *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) ( any, string, ...any) []any { .T.Helper()// Nest this code so we can use defer to make sure the lock is released. := func() []func([]any) []any { .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) := make([]string, len())for , := range { [] = getString() } .T.Fatalf("Unexpected call to %T.%v(%v) at %s because: %s", , , , , ) }// Two things happen here: // * the matching call no longer needs to check prerequisite calls, // * and the prerequisite calls are no longer expected, so remove them. := .dropPrereqs()for , := range { .expectedCalls.Remove() } := .call()if .exhausted() { .expectedCalls.Remove() }return }()var []anyfor , := range {if := (); != nil { = } }return}// Finish checks to see if all the methods that were expected to be called were called.// It is not idempotent and therefore can only be invoked once.//// Note: If you pass a *testing.T into [NewController], 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, )}// Satisfied returns whether all expected calls bound to this Controller have been satisfied.// Calling Finish is then guaranteed to not fail due to missing calls.func ( *Controller) () bool { .mu.Lock()defer .mu.Unlock()return .expectedCalls.Satisfied()}func ( *Controller) ( bool, any) { .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", ) }iflen() != 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); {returnfmt.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: = .tif , := .(*nopTestHelper); { = .t }case *nopTestHelper: = .tdefault:// not wrapped }return}
The pages are generated with Goldsv0.7.6. (GOOS=linux GOARCH=amd64)