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