1/* 2 * Copyright (c) 2007 Mockito contributors 3 * This program is made available under the terms of the MIT License. 4 */ 5 6package org.mockito.internal.invocation; 7 8import java.util.LinkedList; 9import java.util.List; 10 11import org.mockito.internal.util.collections.ListUtil; 12import org.mockito.internal.util.collections.ListUtil.Filter; 13import org.mockito.internal.verification.api.InOrderContext; 14import org.mockito.invocation.Invocation; 15import org.mockito.invocation.Location; 16 17public class InvocationsFinder { 18 19 public List<Invocation> findInvocations(List<Invocation> invocations, InvocationMatcher wanted) { 20 return ListUtil.filter(invocations, new RemoveNotMatching(wanted)); 21 } 22 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 */ 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 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 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 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 92 public Invocation findFirstUnverified(List<Invocation> invocations) { 93 return findFirstUnverified(invocations, null); 94 } 95 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 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 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 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 140 private RemoveNotMatching(InvocationMatcher wanted) { 141 this.wanted = wanted; 142 } 143 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 152 public RemoveUnverifiedInOrder(InOrderContext orderingContext) { 153 this.orderingContext = orderingContext; 154 } 155 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 */ 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}