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