func unwrapTestReporter(t TestReporter) TestReporter {
	tr := t
	switch nt := t.(type) {
	case *cancelReporter:
		tr = nt.t
		if h, check := tr.(*nopTestHelper); check {
			tr = h.t
		}
	case *nopTestHelper:
		tr = nt.t
	default:
	}
	return tr
}
unwrapTestReporter unwraps TestReporter to the base implementation.
package gomock
import (
	"context"
	"fmt"
	"reflect"
	"runtime"
	"sync"
)
type TestReporter interface {
	Errorf(format string, args ...interface{})
	Fatalf(format string, args ...interface{})
}
type TestHelper interface {
	TestReporter
	Helper()
}
type cleanuper interface {
	Cleanup(func())
}
type Controller struct {
	T             TestHelper
	mu            sync.Mutex
	expectedCalls *callSet
	finished      bool
}
func NewController(t TestReporter) *Controller {
	h, ok := t.(TestHelper)
	if !ok {
		h = &nopTestHelper{t}
	}
	ctrl := &Controller{
		T:             h,
		expectedCalls: newCallSet(),
	}
	if c, ok := isCleanuper(ctrl.T); ok {
		c.Cleanup(func() {
			ctrl.T.Helper()
			ctrl.finish(true, nil)
		})
	}
	return ctrl
}
type cancelReporter struct {
	t      TestHelper
	cancel func()
}
func (r *cancelReporter) Errorf(format string, args ...interface{}) {
	r.t.Errorf(format, args...)
}
func (r *cancelReporter) Fatalf(format string, args ...interface{}) {
	defer r.cancel()
	r.t.Fatalf(format, args...)
}
func (r *cancelReporter) Helper() {
	r.t.Helper()
}
func WithContext(ctx context.Context, t TestReporter) (*Controller, context.Context) {
	h, ok := t.(TestHelper)
	if !ok {
		h = &nopTestHelper{t: t}
	}
	ctx, cancel := context.WithCancel(ctx)
	return NewController(&cancelReporter{t: h, cancel: cancel}), ctx
}
type nopTestHelper struct {
	t TestReporter
}
func (h *nopTestHelper) Errorf(format string, args ...interface{}) {
	h.t.Errorf(format, args...)
}
func (h *nopTestHelper) Fatalf(format string, args ...interface{}) {
	h.t.Fatalf(format, args...)
}
func (h nopTestHelper) Helper() {}
func (ctrl *Controller) RecordCall(receiver interface{}, method string, args ...interface{}) *Call {
	ctrl.T.Helper()
	recv := reflect.ValueOf(receiver)
	for i := 0; i < recv.Type().NumMethod(); i++ {
		if recv.Type().Method(i).Name == method {
			return ctrl.RecordCallWithMethodType(receiver, method, recv.Method(i).Type(), args...)
		}
	}
	ctrl.T.Fatalf("gomock: failed finding method %s on %T", method, receiver)
	panic("unreachable")
}
func (ctrl *Controller) RecordCallWithMethodType(receiver interface{}, method string, methodType reflect.Type, args ...interface{}) *Call {
	ctrl.T.Helper()
	call := newCall(ctrl.T, receiver, method, methodType, args...)
	ctrl.mu.Lock()
	defer ctrl.mu.Unlock()
	ctrl.expectedCalls.Add(call)
	return call
}
func (ctrl *Controller) Call(receiver interface{}, method string, args ...interface{}) []interface{} {
	ctrl.T.Helper()
	actions := func() []func([]interface{}) []interface{} {
		ctrl.T.Helper()
		ctrl.mu.Lock()
		defer ctrl.mu.Unlock()
		expected, err := ctrl.expectedCalls.FindMatch(receiver, method, args)
		if err != nil {
			origin := callerInfo(3)
			ctrl.T.Fatalf("Unexpected call to %T.%v(%v) at %s because: %s", receiver, method, args, origin, err)
		}
		preReqCalls := expected.dropPrereqs()
		for _, preReqCall := range preReqCalls {
			ctrl.expectedCalls.Remove(preReqCall)
		}
		actions := expected.call()
		if expected.exhausted() {
			ctrl.expectedCalls.Remove(expected)
		}
		return actions
	}()
	var rets []interface{}
	for _, action := range actions {
		if r := action(args); r != nil {
			rets = r
		}
	}
	return rets
}
func (ctrl *Controller) Finish() {
	err := recover()
	ctrl.finish(false, err)
}
func (ctrl *Controller) finish(cleanup bool, panicErr interface{}) {
	ctrl.T.Helper()
	ctrl.mu.Lock()
	defer ctrl.mu.Unlock()
	if ctrl.finished {
		if _, ok := isCleanuper(ctrl.T); !ok {
			ctrl.T.Fatalf("Controller.Finish was called more than once. It has to be called exactly once.")
		}
		return
	}
	ctrl.finished = true
	if panicErr != nil {
		panic(panicErr)
	}
	failures := ctrl.expectedCalls.Failures()
	for _, call := range failures {
		ctrl.T.Errorf("missing call(s) to %v", call)
	}
	if len(failures) != 0 {
		if !cleanup {
			ctrl.T.Fatalf("aborting test due to missing call(s)")
			return
		}
		ctrl.T.Errorf("aborting test due to missing call(s)")
	}
}
func callerInfo(skip int) string {
	if _, file, line, ok := runtime.Caller(skip + 1); ok {
		return fmt.Sprintf("%s:%d", file, line)
	}
	return "unknown file"
}
func isCleanuper(t TestReporter) (cleanuper, bool) {
	tr := unwrapTestReporter(t)
	c, ok := tr.(cleanuper)
	return c, ok
}