updating github.com/golang/mock to v1.2.0

This commit is contained in:
Davanum Srinivas
2019-06-14 10:58:41 -04:00
parent 0861b3f30f
commit 03c222ca09
7 changed files with 464 additions and 187 deletions

View File

@@ -55,7 +55,13 @@
// - Handle different argument/return types (e.g. ..., chan, map, interface).
package gomock
import "sync"
import (
"context"
"fmt"
"reflect"
"runtime"
"sync"
)
// A TestReporter is something that can be used to report test failures.
// It is satisfied by the standard library's *testing.T.
@@ -64,85 +70,147 @@ type TestReporter 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()
}
// 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.
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 implment a TestHelper it will be wrapped
// with a nopTestHelper.
T TestHelper
mu sync.Mutex
t TestReporter
expectedCalls callSet
expectedCalls *callSet
finished bool
}
func NewController(t TestReporter) *Controller {
h, ok := t.(TestHelper)
if !ok {
h = nopTestHelper{t}
}
return &Controller{
t: t,
expectedCalls: make(callSet),
T: h,
expectedCalls: newCallSet(),
}
}
type cancelReporter struct {
TestHelper
cancel func()
}
func (r *cancelReporter) Errorf(format string, args ...interface{}) {
r.TestHelper.Errorf(format, args...)
}
func (r *cancelReporter) Fatalf(format string, args ...interface{}) {
defer r.cancel()
r.TestHelper.Fatalf(format, args...)
}
// WithContext returns a new Controller and a Context, which is cancelled on any
// fatal failure.
func WithContext(ctx context.Context, t TestReporter) (*Controller, context.Context) {
h, ok := t.(TestHelper)
if !ok {
h = nopTestHelper{t}
}
ctx, cancel := context.WithCancel(ctx)
return NewController(&cancelReporter{h, cancel}), ctx
}
type nopTestHelper struct {
TestReporter
}
func (h nopTestHelper) Helper() {}
func (ctrl *Controller) RecordCall(receiver interface{}, method string, args ...interface{}) *Call {
// TODO: check arity, types.
margs := make([]Matcher, len(args))
for i, arg := range args {
if m, ok := arg.(Matcher); ok {
margs[i] = m
} else if arg == nil {
// Handle nil specially so that passing a nil interface value
// will match the typed nils of concrete args.
margs[i] = Nil()
} else {
margs[i] = Eq(arg)
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()
call := &Call{t: ctrl.t, receiver: receiver, method: method, args: margs, minCalls: 1, maxCalls: 1}
ctrl.expectedCalls.Add(call)
return call
}
func (ctrl *Controller) Call(receiver interface{}, method string, args ...interface{}) []interface{} {
ctrl.mu.Lock()
defer ctrl.mu.Unlock()
ctrl.T.Helper()
expected := ctrl.expectedCalls.FindMatch(receiver, method, args)
if expected == nil {
ctrl.t.Fatalf("no matching expected call: %T.%v(%v)", receiver, method, args)
}
// Nest this code so we can use defer to make sure the lock is released.
actions := func() []func([]interface{}) []interface{} {
ctrl.T.Helper()
ctrl.mu.Lock()
defer ctrl.mu.Unlock()
// 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.
preReqCalls := expected.dropPrereqs()
for _, preReqCall := range preReqCalls {
ctrl.expectedCalls.Remove(preReqCall)
}
expected, err := ctrl.expectedCalls.FindMatch(receiver, method, args)
if err != nil {
origin := callerInfo(2)
ctrl.T.Fatalf("Unexpected call to %T.%v(%v) at %s because: %s", receiver, method, args, origin, err)
}
rets, action := expected.call(args)
if expected.exhausted() {
ctrl.expectedCalls.Remove(expected)
}
// 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.
preReqCalls := expected.dropPrereqs()
for _, preReqCall := range preReqCalls {
ctrl.expectedCalls.Remove(preReqCall)
}
// Don't hold the lock while doing the call's action (if any)
// so that actions may execute concurrently.
// We use the deferred Unlock to capture any panics that happen above;
// here we add a deferred Lock to balance it.
ctrl.mu.Unlock()
defer ctrl.mu.Lock()
if action != nil {
action()
actions := expected.call(args)
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() {
ctrl.T.Helper()
ctrl.mu.Lock()
defer ctrl.mu.Unlock()
if ctrl.finished {
ctrl.T.Fatalf("Controller.Finish was called more than once. It has to be called exactly once.")
}
ctrl.finished = true
// If we're currently panicking, probably because this is a deferred call,
// pass through the panic.
if err := recover(); err != nil {
@@ -150,18 +218,18 @@ func (ctrl *Controller) Finish() {
}
// Check that all remaining expected calls are satisfied.
failures := false
for _, methodMap := range ctrl.expectedCalls {
for _, calls := range methodMap {
for _, call := range calls {
if !call.satisfied() {
ctrl.t.Errorf("missing call(s) to %v", call)
failures = true
}
}
}
failures := ctrl.expectedCalls.Failures()
for _, call := range failures {
ctrl.T.Errorf("missing call(s) to %v", call)
}
if failures {
ctrl.t.Fatalf("aborting test due to missing call(s)")
if len(failures) != 0 {
ctrl.T.Fatalf("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"
}