• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2007 Mockito contributors
3  * This program is made available under the terms of the MIT License.
4  */
5 
6 package org.mockito.internal.invocation;
7 
8 import java.util.LinkedList;
9 import java.util.List;
10 
11 import org.mockito.internal.util.collections.ListUtil;
12 import org.mockito.internal.util.collections.ListUtil.Filter;
13 import org.mockito.internal.verification.api.InOrderContext;
14 import org.mockito.invocation.Invocation;
15 import org.mockito.invocation.Location;
16 
17 public class InvocationsFinder {
18 
findInvocations(List<Invocation> invocations, InvocationMatcher wanted)19     public List<Invocation> findInvocations(List<Invocation> invocations, InvocationMatcher wanted) {
20         return ListUtil.filter(invocations, new RemoveNotMatching(wanted));
21     }
22 
findAllMatchingUnverifiedChunks(List<Invocation> invocations, InvocationMatcher wanted, InOrderContext orderingContext)23     public List<Invocation> findAllMatchingUnverifiedChunks(List<Invocation> invocations, InvocationMatcher wanted, InOrderContext orderingContext) {
24         List<Invocation> unverified = removeVerifiedInOrder(invocations, orderingContext);
25         return ListUtil.filter(unverified, new RemoveNotMatching(wanted));
26     }
27 
28     /**
29      * some examples how it works:
30      *
31      * Given invocations sequence:
32      * 1,1,2,1
33      *
34      * if wanted is 1 and mode is times(2) then returns
35      * 1,1
36      *
37      * if wanted is 1 and mode is atLeast() then returns
38      * 1,1,1
39      *
40      * if wanted is 1 and mode is times(x), where x != 2 then returns
41      * 1,1,1
42      */
findMatchingChunk(List<Invocation> invocations, InvocationMatcher wanted, int wantedCount, InOrderContext context)43     public List<Invocation> findMatchingChunk(List<Invocation> invocations, InvocationMatcher wanted, int wantedCount, InOrderContext context) {
44         List<Invocation> unverified = removeVerifiedInOrder(invocations, context);
45         List<Invocation> firstChunk = getFirstMatchingChunk(wanted, unverified);
46 
47         if (wantedCount != firstChunk.size()) {
48             return this.findAllMatchingUnverifiedChunks(invocations, wanted, context);
49         } else {
50             return firstChunk;
51         }
52     }
53 
getFirstMatchingChunk(InvocationMatcher wanted, List<Invocation> unverified)54     private List<Invocation> getFirstMatchingChunk(InvocationMatcher wanted, List<Invocation> unverified) {
55         List<Invocation> firstChunk = new LinkedList<Invocation>();
56         for (Invocation invocation : unverified) {
57             if (wanted.matches(invocation)) {
58                 firstChunk.add(invocation);
59             } else if (!firstChunk.isEmpty()) {
60                 break;
61             }
62         }
63         return firstChunk;
64     }
65 
findFirstMatchingUnverifiedInvocation( List<Invocation> invocations, InvocationMatcher wanted, InOrderContext context )66     public Invocation findFirstMatchingUnverifiedInvocation( List<Invocation> invocations, InvocationMatcher wanted, InOrderContext context ){
67         for( Invocation invocation : removeVerifiedInOrder( invocations, context )){
68             if( wanted.matches( invocation )){
69                 return invocation;
70             }
71         }
72         return null;
73     }
74 
findSimilarInvocation(List<Invocation> invocations, InvocationMatcher wanted)75     public Invocation findSimilarInvocation(List<Invocation> invocations, InvocationMatcher wanted) {
76         Invocation firstSimilar = null;
77         for (Invocation invocation : invocations) {
78             if (!wanted.hasSimilarMethod(invocation)) {
79                 continue;
80             }
81             if (firstSimilar == null) {
82                 firstSimilar = invocation;
83             }
84             if (wanted.hasSameMethod(invocation)) {
85                 return invocation;
86             }
87         }
88 
89         return firstSimilar;
90     }
91 
findFirstUnverified(List<Invocation> invocations)92     public Invocation findFirstUnverified(List<Invocation> invocations) {
93         return findFirstUnverified(invocations, null);
94     }
95 
findFirstUnverified(List<Invocation> invocations, Object mock)96     Invocation findFirstUnverified(List<Invocation> invocations, Object mock) {
97         for (Invocation i : invocations) {
98             boolean mockIsValid = mock == null || mock == i.getMock();
99             if (!i.isVerified() && mockIsValid) {
100                 return i;
101             }
102         }
103         return null;
104     }
105 
getLastLocation(List<Invocation> invocations)106     public Location getLastLocation(List<Invocation> invocations) {
107         if (invocations.isEmpty()) {
108             return null;
109         } else {
110             Invocation last = invocations.get(invocations.size() - 1);
111             return last.getLocation();
112         }
113     }
114 
findPreviousVerifiedInOrder(List<Invocation> invocations, InOrderContext context)115     public Invocation findPreviousVerifiedInOrder(List<Invocation> invocations, InOrderContext context) {
116         LinkedList<Invocation> verifiedOnly = ListUtil.filter(invocations, new RemoveUnverifiedInOrder(context));
117 
118         if (verifiedOnly.isEmpty()) {
119             return null;
120         } else {
121             return verifiedOnly.getLast();
122         }
123     }
124 
removeVerifiedInOrder(List<Invocation> invocations, InOrderContext orderingContext)125     private List<Invocation> removeVerifiedInOrder(List<Invocation> invocations, InOrderContext orderingContext) {
126         List<Invocation> unverified = new LinkedList<Invocation>();
127         for (Invocation i : invocations) {
128             if (orderingContext.isVerified(i)) {
129                 unverified.clear();
130             } else {
131                 unverified.add(i);
132             }
133         }
134         return unverified;
135     }
136 
137     private class RemoveNotMatching implements Filter<Invocation> {
138         private final InvocationMatcher wanted;
139 
RemoveNotMatching(InvocationMatcher wanted)140         private RemoveNotMatching(InvocationMatcher wanted) {
141             this.wanted = wanted;
142         }
143 
isOut(Invocation invocation)144         public boolean isOut(Invocation invocation) {
145             return !wanted.matches(invocation);
146         }
147     }
148 
149     private class RemoveUnverifiedInOrder implements Filter<Invocation> {
150         private final InOrderContext orderingContext;
151 
RemoveUnverifiedInOrder(InOrderContext orderingContext)152         public RemoveUnverifiedInOrder(InOrderContext orderingContext) {
153             this.orderingContext = orderingContext;
154         }
155 
isOut(Invocation invocation)156         public boolean isOut(Invocation invocation) {
157             return !orderingContext.isVerified(invocation);
158         }
159     }
160 
161     /**
162      * i3 is unverified here:
163      *
164      * i1, i2, i3
165      *     v
166      *
167      * all good here:
168      *
169      * i1, i2, i3
170      *     v   v
171      *
172      * @param context
173      * @param orderedInvocations
174      */
findFirstUnverifiedInOrder(InOrderContext context, List<Invocation> orderedInvocations)175     public Invocation findFirstUnverifiedInOrder(InOrderContext context, List<Invocation> orderedInvocations) {
176         Invocation candidate = null;
177         for(Invocation i : orderedInvocations) {
178             if (!context.isVerified(i)) {
179                 candidate = candidate != null ? candidate : i;
180             } else {
181                 candidate = null;
182             }
183         }
184         return candidate;
185     }
186 }