| // 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 |
| |
| import ( |
| "fmt" |
| "reflect" |
| "strconv" |
| "strings" |
| ) |
| |
| // Call represents an expected call to a mock. |
| type Call struct { |
| t TestHelper // for triggering test failures on invalid call setup |
| |
| receiver interface{} // the receiver of the method call |
| method string // the name of the method |
| methodType reflect.Type // the type of the method |
| args []Matcher // the args |
| origin string // file and line number of call setup |
| |
| preReqs []*Call // prerequisite calls |
| |
| // Expectations |
| minCalls, maxCalls int |
| |
| numCalls int // actual number made |
| |
| // actions are called when this Call is called. Each action gets the args and |
| // can set the return values by returning a non-nil slice. Actions run in the |
| // order they are created. |
| actions []func([]interface{}) []interface{} |
| } |
| |
| // newCall creates a *Call. It requires the method type in order to support |
| // unexported methods. |
| func newCall(t TestHelper, receiver interface{}, method string, methodType reflect.Type, args ...interface{}) *Call { |
| t.Helper() |
| |
| // 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) |
| } |
| } |
| |
| // 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 RecordCallWithMethodType(), 2 is the generated recorder, and 3 is the user's test. |
| origin := callerInfo(3) |
| actions := []func([]interface{}) []interface{}{func([]interface{}) []interface{} { |
| // Synthesize the zero value for each of the return args' types. |
| rets := make([]interface{}, methodType.NumOut()) |
| for i := 0; i < methodType.NumOut(); i++ { |
| rets[i] = reflect.Zero(methodType.Out(i)).Interface() |
| } |
| return rets |
| }} |
| return &Call{t: t, receiver: receiver, method: method, methodType: methodType, |
| args: margs, origin: origin, minCalls: 1, maxCalls: 1, actions: actions} |
| } |
| |
| // AnyTimes allows the expectation to be called 0 or more times |
| func (c *Call) AnyTimes() *Call { |
| c.minCalls, c.maxCalls = 0, 1e8 // close enough to infinity |
| return c |
| } |
| |
| // MinTimes requires the call to occur at least n times. If AnyTimes or MaxTimes have not been called or if MaxTimes |
| // was previously called with 1, MinTimes also sets the maximum number of calls to infinity. |
| func (c *Call) MinTimes(n int) *Call { |
| c.minCalls = n |
| if c.maxCalls == 1 { |
| c.maxCalls = 1e8 |
| } |
| return c |
| } |
| |
| // MaxTimes limits the number of calls to n times. If AnyTimes or MinTimes have not been called or if MinTimes was |
| // previously called with 1, MaxTimes also sets the minimum number of calls to 0. |
| func (c *Call) MaxTimes(n int) *Call { |
| c.maxCalls = n |
| if c.minCalls == 1 { |
| c.minCalls = 0 |
| } |
| return c |
| } |
| |
| // DoAndReturn declares the action to run when the call is matched. |
| // The return values from this function are returned by the mocked function. |
| // It takes an interface{} argument to support n-arity functions. |
| func (c *Call) DoAndReturn(f interface{}) *Call { |
| // TODO: Check arity and types here, rather than dying badly elsewhere. |
| v := reflect.ValueOf(f) |
| |
| c.addAction(func(args []interface{}) []interface{} { |
| vargs := make([]reflect.Value, len(args)) |
| ft := v.Type() |
| for i := 0; i < len(args); i++ { |
| if args[i] != nil { |
| vargs[i] = reflect.ValueOf(args[i]) |
| } else { |
| // Use the zero value for the arg. |
| vargs[i] = reflect.Zero(ft.In(i)) |
| } |
| } |
| vrets := v.Call(vargs) |
| rets := make([]interface{}, len(vrets)) |
| for i, ret := range vrets { |
| rets[i] = ret.Interface() |
| } |
| return rets |
| }) |
| return c |
| } |
| |
| // Do declares the action to run when the call is matched. The function's |
| // return values are ignored to retain backward compatibility. To use the |
| // return values call DoAndReturn. |
| // It takes an interface{} argument to support n-arity functions. |
| func (c *Call) Do(f interface{}) *Call { |
| // TODO: Check arity and types here, rather than dying badly elsewhere. |
| v := reflect.ValueOf(f) |
| |
| c.addAction(func(args []interface{}) []interface{} { |
| vargs := make([]reflect.Value, len(args)) |
| ft := v.Type() |
| for i := 0; i < len(args); i++ { |
| if args[i] != nil { |
| vargs[i] = reflect.ValueOf(args[i]) |
| } else { |
| // Use the zero value for the arg. |
| vargs[i] = reflect.Zero(ft.In(i)) |
| } |
| } |
| v.Call(vargs) |
| return nil |
| }) |
| return c |
| } |
| |
| // Return declares the values to be returned by the mocked function call. |
| func (c *Call) Return(rets ...interface{}) *Call { |
| c.t.Helper() |
| |
| mt := c.methodType |
| if len(rets) != mt.NumOut() { |
| c.t.Fatalf("wrong number of arguments to Return for %T.%v: got %d, want %d [%s]", |
| c.receiver, c.method, len(rets), mt.NumOut(), c.origin) |
| } |
| for i, ret := range rets { |
| if got, want := reflect.TypeOf(ret), mt.Out(i); got == want { |
| // Identical types; nothing to do. |
| } else if got == nil { |
| // Nil needs special handling. |
| switch want.Kind() { |
| case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice: |
| // ok |
| default: |
| c.t.Fatalf("argument %d to Return for %T.%v is nil, but %v is not nillable [%s]", |
| i, c.receiver, c.method, want, c.origin) |
| } |
| } else if got.AssignableTo(want) { |
| // Assignable type relation. Make the assignment now so that the generated code |
| // can return the values with a type assertion. |
| v := reflect.New(want).Elem() |
| v.Set(reflect.ValueOf(ret)) |
| rets[i] = v.Interface() |
| } else { |
| c.t.Fatalf("wrong type of argument %d to Return for %T.%v: %v is not assignable to %v [%s]", |
| i, c.receiver, c.method, got, want, c.origin) |
| } |
| } |
| |
| c.addAction(func([]interface{}) []interface{} { |
| return rets |
| }) |
| |
| return c |
| } |
| |
| // Times declares the exact number of times a function call is expected to be executed. |
| func (c *Call) Times(n int) *Call { |
| c.minCalls, c.maxCalls = n, n |
| return c |
| } |
| |
| // SetArg declares an action that will set the nth argument's value, |
| // indirected through a pointer. Or, in the case of a slice, SetArg |
| // will copy value's elements into the nth argument. |
| func (c *Call) SetArg(n int, value interface{}) *Call { |
| c.t.Helper() |
| |
| mt := c.methodType |
| // TODO: This will break on variadic methods. |
| // We will need to check those at invocation time. |
| if n < 0 || n >= mt.NumIn() { |
| c.t.Fatalf("SetArg(%d, ...) called for a method with %d args [%s]", |
| n, mt.NumIn(), c.origin) |
| } |
| // Permit setting argument through an interface. |
| // In the interface case, we don't (nay, can't) check the type here. |
| at := mt.In(n) |
| switch at.Kind() { |
| case reflect.Ptr: |
| dt := at.Elem() |
| if vt := reflect.TypeOf(value); !vt.AssignableTo(dt) { |
| c.t.Fatalf("SetArg(%d, ...) argument is a %v, not assignable to %v [%s]", |
| n, vt, dt, c.origin) |
| } |
| case reflect.Interface: |
| // nothing to do |
| case reflect.Slice: |
| // nothing to do |
| default: |
| c.t.Fatalf("SetArg(%d, ...) referring to argument of non-pointer non-interface non-slice type %v [%s]", |
| n, at, c.origin) |
| } |
| |
| c.addAction(func(args []interface{}) []interface{} { |
| v := reflect.ValueOf(value) |
| switch reflect.TypeOf(args[n]).Kind() { |
| case reflect.Slice: |
| setSlice(args[n], v) |
| default: |
| reflect.ValueOf(args[n]).Elem().Set(v) |
| } |
| return nil |
| }) |
| return c |
| } |
| |
| // isPreReq returns true if other is a direct or indirect prerequisite to c. |
| func (c *Call) isPreReq(other *Call) bool { |
| for _, preReq := range c.preReqs { |
| if other == preReq || preReq.isPreReq(other) { |
| return true |
| } |
| } |
| return false |
| } |
| |
| // After declares that the call may only match after preReq has been exhausted. |
| func (c *Call) After(preReq *Call) *Call { |
| c.t.Helper() |
| |
| if c == preReq { |
| c.t.Fatalf("A call isn't allowed to be its own prerequisite") |
| } |
| if preReq.isPreReq(c) { |
| c.t.Fatalf("Loop in call order: %v is a prerequisite to %v (possibly indirectly).", c, preReq) |
| } |
| |
| c.preReqs = append(c.preReqs, preReq) |
| return c |
| } |
| |
| // Returns true if the minimum number of calls have been made. |
| func (c *Call) satisfied() bool { |
| return c.numCalls >= c.minCalls |
| } |
| |
| // Returns true if the maximum number of calls have been made. |
| func (c *Call) exhausted() bool { |
| return c.numCalls >= c.maxCalls |
| } |
| |
| func (c *Call) String() string { |
| args := make([]string, len(c.args)) |
| for i, arg := range c.args { |
| args[i] = arg.String() |
| } |
| arguments := strings.Join(args, ", ") |
| return fmt.Sprintf("%T.%v(%s) %s", c.receiver, c.method, arguments, c.origin) |
| } |
| |
| // Tests if the given call matches the expected call. |
| // If yes, returns nil. If no, returns error with message explaining why it does not match. |
| func (c *Call) matches(args []interface{}) error { |
| if !c.methodType.IsVariadic() { |
| if len(args) != len(c.args) { |
| return fmt.Errorf("expected call at %s has the wrong number of arguments. Got: %d, want: %d", |
| c.origin, len(args), len(c.args)) |
| } |
| |
| for i, m := range c.args { |
| if !m.Matches(args[i]) { |
| return fmt.Errorf( |
| "expected call at %s doesn't match the argument at index %d.\nGot: %v\nWant: %v", |
| c.origin, i, formatGottenArg(m, args[i]), m, |
| ) |
| } |
| } |
| } else { |
| if len(c.args) < c.methodType.NumIn()-1 { |
| return fmt.Errorf("expected call at %s has the wrong number of matchers. Got: %d, want: %d", |
| c.origin, len(c.args), c.methodType.NumIn()-1) |
| } |
| if len(c.args) != c.methodType.NumIn() && len(args) != len(c.args) { |
| return fmt.Errorf("expected call at %s has the wrong number of arguments. Got: %d, want: %d", |
| c.origin, len(args), len(c.args)) |
| } |
| if len(args) < len(c.args)-1 { |
| return fmt.Errorf("expected call at %s has the wrong number of arguments. Got: %d, want: greater than or equal to %d", |
| c.origin, len(args), len(c.args)-1) |
| } |
| |
| for i, m := range c.args { |
| if i < c.methodType.NumIn()-1 { |
| // Non-variadic args |
| if !m.Matches(args[i]) { |
| return fmt.Errorf("expected call at %s doesn't match the argument at index %s.\nGot: %v\nWant: %v", |
| c.origin, strconv.Itoa(i), formatGottenArg(m, args[i]), m) |
| } |
| continue |
| } |
| // The last arg has a possibility of a variadic argument, so let it branch |
| |
| // sample: Foo(a int, b int, c ...int) |
| if i < len(c.args) && i < len(args) { |
| if m.Matches(args[i]) { |
| // Got Foo(a, b, c) want Foo(matcherA, matcherB, gomock.Any()) |
| // Got Foo(a, b, c) want Foo(matcherA, matcherB, someSliceMatcher) |
| // Got Foo(a, b, c) want Foo(matcherA, matcherB, matcherC) |
| // Got Foo(a, b) want Foo(matcherA, matcherB) |
| // Got Foo(a, b, c, d) want Foo(matcherA, matcherB, matcherC, matcherD) |
| continue |
| } |
| } |
| |
| // The number of actual args don't match the number of matchers, |
| // or the last matcher is a slice and the last arg is not. |
| // If this function still matches it is because the last matcher |
| // matches all the remaining arguments or the lack of any. |
| // Convert the remaining arguments, if any, into a slice of the |
| // expected type. |
| vargsType := c.methodType.In(c.methodType.NumIn() - 1) |
| vargs := reflect.MakeSlice(vargsType, 0, len(args)-i) |
| for _, arg := range args[i:] { |
| vargs = reflect.Append(vargs, reflect.ValueOf(arg)) |
| } |
| if m.Matches(vargs.Interface()) { |
| // Got Foo(a, b, c, d, e) want Foo(matcherA, matcherB, gomock.Any()) |
| // Got Foo(a, b, c, d, e) want Foo(matcherA, matcherB, someSliceMatcher) |
| // Got Foo(a, b) want Foo(matcherA, matcherB, gomock.Any()) |
| // Got Foo(a, b) want Foo(matcherA, matcherB, someEmptySliceMatcher) |
| break |
| } |
| // Wrong number of matchers or not match. Fail. |
| // Got Foo(a, b) want Foo(matcherA, matcherB, matcherC, matcherD) |
| // Got Foo(a, b, c) want Foo(matcherA, matcherB, matcherC, matcherD) |
| // Got Foo(a, b, c, d) want Foo(matcherA, matcherB, matcherC, matcherD, matcherE) |
| // Got Foo(a, b, c, d, e) want Foo(matcherA, matcherB, matcherC, matcherD) |
| // Got Foo(a, b, c) want Foo(matcherA, matcherB) |
| |
| return fmt.Errorf("expected call at %s doesn't match the argument at index %s.\nGot: %v\nWant: %v", |
| c.origin, strconv.Itoa(i), formatGottenArg(m, args[i:]), c.args[i]) |
| } |
| } |
| |
| // Check that all prerequisite calls have been satisfied. |
| for _, preReqCall := range c.preReqs { |
| if !preReqCall.satisfied() { |
| return fmt.Errorf("Expected call at %s doesn't have a prerequisite call satisfied:\n%v\nshould be called before:\n%v", |
| c.origin, preReqCall, c) |
| } |
| } |
| |
| // Check that the call is not exhausted. |
| if c.exhausted() { |
| return fmt.Errorf("expected call at %s has already been called the max number of times", c.origin) |
| } |
| |
| return nil |
| } |
| |
| // dropPrereqs tells the expected Call to not re-check prerequisite calls any |
| // longer, and to return its current set. |
| func (c *Call) dropPrereqs() (preReqs []*Call) { |
| preReqs = c.preReqs |
| c.preReqs = nil |
| return |
| } |
| |
| func (c *Call) call() []func([]interface{}) []interface{} { |
| c.numCalls++ |
| return c.actions |
| } |
| |
| // InOrder declares that the given calls should occur in order. |
| func InOrder(calls ...*Call) { |
| for i := 1; i < len(calls); i++ { |
| calls[i].After(calls[i-1]) |
| } |
| } |
| |
| func setSlice(arg interface{}, v reflect.Value) { |
| va := reflect.ValueOf(arg) |
| for i := 0; i < v.Len(); i++ { |
| va.Index(i).Set(v.Index(i)) |
| } |
| } |
| |
| func (c *Call) addAction(action func([]interface{}) []interface{}) { |
| c.actions = append(c.actions, action) |
| } |
| |
| func formatGottenArg(m Matcher, arg interface{}) string { |
| got := fmt.Sprintf("%v", arg) |
| if gs, ok := m.(GotFormatter); ok { |
| got = gs.Got(arg) |
| } |
| return got |
| } |