// 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 ()// Call represents an expected call to a mock.typeCallstruct {tTestHelper// for triggering test failures on invalid call setupreceiverinterface{} // the receiver of the method callmethodstring// the name of the methodmethodTypereflect.Type// the type of the methodargs []Matcher// the argsoriginstring// file and line number of call setuppreReqs []*Call// prerequisite calls// ExpectationsminCalls, maxCallsintnumCallsint// 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 ( TestHelper, interface{}, string, reflect.Type, ...interface{}) *Call { .Helper()// TODO: check arity, types. := make([]Matcher, len())for , := range {if , := .(Matcher); { [] = } elseif == nil {// Handle nil specially so that passing a nil interface value // will match the typed nils of concrete args. [] = Nil() } else { [] = Eq() } }// 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. := callerInfo(3) := []func([]interface{}) []interface{}{func([]interface{}) []interface{} {// Synthesize the zero value for each of the return args' types. := make([]interface{}, .NumOut())for := 0; < .NumOut(); ++ { [] = reflect.Zero(.Out()).Interface() }return }}return &Call{t: , receiver: , method: , methodType: ,args: , origin: , minCalls: 1, maxCalls: 1, actions: }}// AnyTimes allows the expectation to be called 0 or more timesfunc ( *Call) () *Call { .minCalls, .maxCalls = 0, 1e8// close enough to infinityreturn}// 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 ( *Call) ( int) *Call { .minCalls = if .maxCalls == 1 { .maxCalls = 1e8 }return}// 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 ( *Call) ( int) *Call { .maxCalls = if .minCalls == 1 { .minCalls = 0 }return}// 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 ( *Call) ( interface{}) *Call {// TODO: Check arity and types here, rather than dying badly elsewhere. := reflect.ValueOf() .addAction(func( []interface{}) []interface{} { .t.Helper() := make([]reflect.Value, len()) := .Type()if .methodType.NumIn() != .NumIn() { .t.Fatalf("wrong number of arguments in DoAndReturn func for %T.%v: got %d, want %d [%s]", .receiver, .method, .NumIn(), .methodType.NumIn(), .origin)returnnil }for := 0; < len(); ++ {if [] != nil { [] = reflect.ValueOf([]) } else {// Use the zero value for the arg. [] = reflect.Zero(.In()) } } := .Call() := make([]interface{}, len())for , := range { [] = .Interface() }return })return}// 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 ( *Call) ( interface{}) *Call {// TODO: Check arity and types here, rather than dying badly elsewhere. := reflect.ValueOf() .addAction(func( []interface{}) []interface{} { .t.Helper()if .methodType.NumIn() != .Type().NumIn() { .t.Fatalf("wrong number of arguments in Do func for %T.%v: got %d, want %d [%s]", .receiver, .method, .Type().NumIn(), .methodType.NumIn(), .origin)returnnil } := make([]reflect.Value, len()) := .Type()for := 0; < len(); ++ {if [] != nil { [] = reflect.ValueOf([]) } else {// Use the zero value for the arg. [] = reflect.Zero(.In()) } } .Call()returnnil })return}// Return declares the values to be returned by the mocked function call.func ( *Call) ( ...interface{}) *Call { .t.Helper() := .methodTypeiflen() != .NumOut() { .t.Fatalf("wrong number of arguments to Return for %T.%v: got %d, want %d [%s]", .receiver, .method, len(), .NumOut(), .origin) }for , := range {if , := reflect.TypeOf(), .Out(); == {// Identical types; nothing to do. } elseif == nil {// Nil needs special handling.switch .Kind() {casereflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:// okdefault: .t.Fatalf("argument %d to Return for %T.%v is nil, but %v is not nillable [%s]", , .receiver, .method, , .origin) } } elseif .AssignableTo() {// Assignable type relation. Make the assignment now so that the generated code // can return the values with a type assertion. := reflect.New().Elem() .Set(reflect.ValueOf()) [] = .Interface() } else { .t.Fatalf("wrong type of argument %d to Return for %T.%v: %v is not assignable to %v [%s]", , .receiver, .method, , , .origin) } } .addAction(func([]interface{}) []interface{} {return })return}// Times declares the exact number of times a function call is expected to be executed.func ( *Call) ( int) *Call { .minCalls, .maxCalls = , return}// 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 ( *Call) ( int, interface{}) *Call { .t.Helper() := .methodType// TODO: This will break on variadic methods. // We will need to check those at invocation time.if < 0 || >= .NumIn() { .t.Fatalf("SetArg(%d, ...) called for a method with %d args [%s]", , .NumIn(), .origin) }// Permit setting argument through an interface. // In the interface case, we don't (nay, can't) check the type here. := .In()switch .Kind() {casereflect.Ptr: := .Elem()if := reflect.TypeOf(); !.AssignableTo() { .t.Fatalf("SetArg(%d, ...) argument is a %v, not assignable to %v [%s]", , , , .origin) }casereflect.Interface:// nothing to docasereflect.Slice:// nothing to dodefault: .t.Fatalf("SetArg(%d, ...) referring to argument of non-pointer non-interface non-slice type %v [%s]", , , .origin) } .addAction(func( []interface{}) []interface{} { := reflect.ValueOf()switchreflect.TypeOf([]).Kind() {casereflect.Slice:setSlice([], )default:reflect.ValueOf([]).Elem().Set() }returnnil })return}// isPreReq returns true if other is a direct or indirect prerequisite to c.func ( *Call) ( *Call) bool {for , := range .preReqs {if == || .() {returntrue } }returnfalse}// After declares that the call may only match after preReq has been exhausted.func ( *Call) ( *Call) *Call { .t.Helper()if == { .t.Fatalf("A call isn't allowed to be its own prerequisite") }if .isPreReq() { .t.Fatalf("Loop in call order: %v is a prerequisite to %v (possibly indirectly).", , ) } .preReqs = append(.preReqs, )return}// Returns true if the minimum number of calls have been made.func ( *Call) () bool {return .numCalls >= .minCalls}// Returns true if the maximum number of calls have been made.func ( *Call) () bool {return .numCalls >= .maxCalls}func ( *Call) () string { := make([]string, len(.args))for , := range .args { [] = .String() } := strings.Join(, ", ")returnfmt.Sprintf("%T.%v(%s) %s", .receiver, .method, , .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 ( *Call) ( []interface{}) error {if !.methodType.IsVariadic() {iflen() != len(.args) {returnfmt.Errorf("expected call at %s has the wrong number of arguments. Got: %d, want: %d", .origin, len(), len(.args)) }for , := range .args {if !.Matches([]) {returnfmt.Errorf("expected call at %s doesn't match the argument at index %d.\nGot: %v\nWant: %v", .origin, , formatGottenArg(, []), , ) } } } else {iflen(.args) < .methodType.NumIn()-1 {returnfmt.Errorf("expected call at %s has the wrong number of matchers. Got: %d, want: %d", .origin, len(.args), .methodType.NumIn()-1) }iflen(.args) != .methodType.NumIn() && len() != len(.args) {returnfmt.Errorf("expected call at %s has the wrong number of arguments. Got: %d, want: %d", .origin, len(), len(.args)) }iflen() < len(.args)-1 {returnfmt.Errorf("expected call at %s has the wrong number of arguments. Got: %d, want: greater than or equal to %d", .origin, len(), len(.args)-1) }for , := range .args {if < .methodType.NumIn()-1 {// Non-variadic argsif !.Matches([]) {returnfmt.Errorf("expected call at %s doesn't match the argument at index %s.\nGot: %v\nWant: %v", .origin, strconv.Itoa(), formatGottenArg(, []), ) }continue }// The last arg has a possibility of a variadic argument, so let it branch// sample: Foo(a int, b int, c ...int)if < len(.args) && < len() {if .Matches([]) {// 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. := .methodType.In(.methodType.NumIn() - 1) := reflect.MakeSlice(, 0, len()-)for , := range [:] { = reflect.Append(, reflect.ValueOf()) }if .Matches(.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)returnfmt.Errorf("expected call at %s doesn't match the argument at index %s.\nGot: %v\nWant: %v", .origin, strconv.Itoa(), formatGottenArg(, [:]), .args[]) } }// Check that all prerequisite calls have been satisfied.for , := range .preReqs {if !.satisfied() {returnfmt.Errorf("expected call at %s doesn't have a prerequisite call satisfied:\n%v\nshould be called before:\n%v", .origin, , ) } }// Check that the call is not exhausted.if .exhausted() {returnfmt.Errorf("expected call at %s has already been called the max number of times", .origin) }returnnil}// dropPrereqs tells the expected Call to not re-check prerequisite calls any// longer, and to return its current set.func ( *Call) () ( []*Call) { = .preReqs .preReqs = nilreturn}func ( *Call) () []func([]interface{}) []interface{} { .numCalls++return .actions}// InOrder declares that the given calls should occur in order.func ( ...*Call) {for := 1; < len(); ++ { [].After([-1]) }}func ( interface{}, reflect.Value) { := reflect.ValueOf()for := 0; < .Len(); ++ { .Index().Set(.Index()) }}func ( *Call) ( func([]interface{}) []interface{}) { .actions = append(.actions, )}func ( Matcher, interface{}) string { := fmt.Sprintf("%v (%T)", , )if , := .(GotFormatter); { = .Got() }return}
The pages are generated with Goldsv0.4.9. (GOOS=linux GOARCH=amd64)