blob: 49dba787a400c519d6bf16972e9e609c53de41f7 [file] [log] [blame]
khenaidoo106c61a2021-08-11 18:05:46 -04001// Copyright 2011 Google Inc.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package gomock
16
17import (
18 "bytes"
19 "errors"
20 "fmt"
21)
22
23// callSet represents a set of expected calls, indexed by receiver and method
24// name.
25type callSet struct {
26 // Calls that are still expected.
27 expected map[callSetKey][]*Call
28 // Calls that have been exhausted.
29 exhausted map[callSetKey][]*Call
30}
31
32// callSetKey is the key in the maps in callSet
33type callSetKey struct {
34 receiver interface{}
35 fname string
36}
37
38func newCallSet() *callSet {
39 return &callSet{make(map[callSetKey][]*Call), make(map[callSetKey][]*Call)}
40}
41
42// Add adds a new expected call.
43func (cs callSet) Add(call *Call) {
44 key := callSetKey{call.receiver, call.method}
45 m := cs.expected
46 if call.exhausted() {
47 m = cs.exhausted
48 }
49 m[key] = append(m[key], call)
50}
51
52// Remove removes an expected call.
53func (cs callSet) Remove(call *Call) {
54 key := callSetKey{call.receiver, call.method}
55 calls := cs.expected[key]
56 for i, c := range calls {
57 if c == call {
58 // maintain order for remaining calls
59 cs.expected[key] = append(calls[:i], calls[i+1:]...)
60 cs.exhausted[key] = append(cs.exhausted[key], call)
61 break
62 }
63 }
64}
65
66// FindMatch searches for a matching call. Returns error with explanation message if no call matched.
67func (cs callSet) FindMatch(receiver interface{}, method string, args []interface{}) (*Call, error) {
68 key := callSetKey{receiver, method}
69
70 // Search through the expected calls.
71 expected := cs.expected[key]
72 var callsErrors bytes.Buffer
73 for _, call := range expected {
74 err := call.matches(args)
75 if err != nil {
76 _, _ = fmt.Fprintf(&callsErrors, "\n%v", err)
77 } else {
78 return call, nil
79 }
80 }
81
82 // If we haven't found a match then search through the exhausted calls so we
83 // get useful error messages.
84 exhausted := cs.exhausted[key]
85 for _, call := range exhausted {
86 if err := call.matches(args); err != nil {
87 _, _ = fmt.Fprintf(&callsErrors, "\n%v", err)
88 continue
89 }
90 _, _ = fmt.Fprintf(
91 &callsErrors, "all expected calls for method %q have been exhausted", method,
92 )
93 }
94
95 if len(expected)+len(exhausted) == 0 {
96 _, _ = fmt.Fprintf(&callsErrors, "there are no expected calls of the method %q for that receiver", method)
97 }
98
99 return nil, errors.New(callsErrors.String())
100}
101
102// Failures returns the calls that are not satisfied.
103func (cs callSet) Failures() []*Call {
104 failures := make([]*Call, 0, len(cs.expected))
105 for _, calls := range cs.expected {
106 for _, call := range calls {
107 if !call.satisfied() {
108 failures = append(failures, call)
109 }
110 }
111 }
112 return failures
113}