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