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.stubbing; 6 7 import static org.mockito.internal.progress.ThreadSafeMockingProgress.mockingProgress; 8 9 import java.io.Serializable; 10 import java.util.Collection; 11 import java.util.Collections; 12 import java.util.LinkedList; 13 import java.util.List; 14 15 import org.mockito.internal.invocation.StubInfoImpl; 16 import org.mockito.internal.verification.DefaultRegisteredInvocations; 17 import org.mockito.internal.verification.RegisteredInvocations; 18 import org.mockito.internal.verification.SingleRegisteredInvocation; 19 import org.mockito.invocation.Invocation; 20 import org.mockito.invocation.InvocationContainer; 21 import org.mockito.invocation.MatchableInvocation; 22 import org.mockito.mock.MockCreationSettings; 23 import org.mockito.quality.Strictness; 24 import org.mockito.stubbing.Answer; 25 import org.mockito.stubbing.Stubbing; 26 import org.mockito.stubbing.ValidableAnswer; 27 28 @SuppressWarnings("unchecked") 29 public class InvocationContainerImpl implements InvocationContainer, Serializable { 30 31 private static final long serialVersionUID = -5334301962749537177L; 32 private final LinkedList<StubbedInvocationMatcher> stubbed = new LinkedList<>(); 33 private final DoAnswerStyleStubbing doAnswerStyleStubbing; 34 private final RegisteredInvocations registeredInvocations; 35 private final Strictness mockStrictness; 36 37 private MatchableInvocation invocationForStubbing; 38 InvocationContainerImpl(MockCreationSettings mockSettings)39 public InvocationContainerImpl(MockCreationSettings mockSettings) { 40 this.registeredInvocations = createRegisteredInvocations(mockSettings); 41 this.mockStrictness = mockSettings.isLenient() ? Strictness.LENIENT : null; 42 this.doAnswerStyleStubbing = new DoAnswerStyleStubbing(); 43 } 44 setInvocationForPotentialStubbing(MatchableInvocation invocation)45 public void setInvocationForPotentialStubbing(MatchableInvocation invocation) { 46 registeredInvocations.add(invocation.getInvocation()); 47 this.invocationForStubbing = invocation; 48 } 49 resetInvocationForPotentialStubbing(MatchableInvocation invocationMatcher)50 public void resetInvocationForPotentialStubbing(MatchableInvocation invocationMatcher) { 51 this.invocationForStubbing = invocationMatcher; 52 } 53 addAnswer(Answer answer, Strictness stubbingStrictness)54 public void addAnswer(Answer answer, Strictness stubbingStrictness) { 55 registeredInvocations.removeLast(); 56 addAnswer(answer, false, stubbingStrictness); 57 } 58 59 /** Adds new stubbed answer and returns the invocation matcher the answer was added to. */ addAnswer( Answer answer, boolean isConsecutive, Strictness stubbingStrictness)60 public StubbedInvocationMatcher addAnswer( 61 Answer answer, boolean isConsecutive, Strictness stubbingStrictness) { 62 Invocation invocation = invocationForStubbing.getInvocation(); 63 mockingProgress().stubbingCompleted(); 64 if (answer instanceof ValidableAnswer) { 65 ((ValidableAnswer) answer).validateFor(invocation); 66 } 67 68 synchronized (stubbed) { 69 if (isConsecutive) { 70 stubbed.getFirst().addAnswer(answer); 71 } else { 72 Strictness effectiveStrictness = 73 stubbingStrictness != null ? stubbingStrictness : this.mockStrictness; 74 stubbed.addFirst( 75 new StubbedInvocationMatcher( 76 answer, invocationForStubbing, effectiveStrictness)); 77 } 78 return stubbed.getFirst(); 79 } 80 } 81 addConsecutiveAnswer(Answer answer)82 public void addConsecutiveAnswer(Answer answer) { 83 addAnswer(answer, true, null); 84 } 85 answerTo(Invocation invocation)86 Object answerTo(Invocation invocation) throws Throwable { 87 return findAnswerFor(invocation).answer(invocation); 88 } 89 findAnswerFor(Invocation invocation)90 public StubbedInvocationMatcher findAnswerFor(Invocation invocation) { 91 synchronized (stubbed) { 92 for (StubbedInvocationMatcher s : stubbed) { 93 if (s.matches(invocation)) { 94 s.markStubUsed(invocation); 95 // TODO we should mark stubbed at the point of stubbing, not at the point where 96 // the stub is being used 97 invocation.markStubbed(new StubInfoImpl(s)); 98 return s; 99 } 100 } 101 } 102 103 return null; 104 } 105 106 /** 107 * Sets the answers declared with 'doAnswer' style. 108 */ setAnswersForStubbing(List<Answer<?>> answers, Strictness strictness)109 public void setAnswersForStubbing(List<Answer<?>> answers, Strictness strictness) { 110 doAnswerStyleStubbing.setAnswers(answers, strictness); 111 } 112 hasAnswersForStubbing()113 public boolean hasAnswersForStubbing() { 114 return !doAnswerStyleStubbing.isSet(); 115 } 116 hasInvocationForPotentialStubbing()117 public boolean hasInvocationForPotentialStubbing() { 118 return !registeredInvocations.isEmpty(); 119 } 120 setMethodForStubbing(MatchableInvocation invocation)121 public void setMethodForStubbing(MatchableInvocation invocation) { 122 invocationForStubbing = invocation; 123 assert hasAnswersForStubbing(); 124 for (int i = 0; i < doAnswerStyleStubbing.getAnswers().size(); i++) { 125 addAnswer( 126 doAnswerStyleStubbing.getAnswers().get(i), 127 i != 0, 128 doAnswerStyleStubbing.getStubbingStrictness()); 129 } 130 doAnswerStyleStubbing.clear(); 131 } 132 133 @Override toString()134 public String toString() { 135 return "invocationForStubbing: " + invocationForStubbing; 136 } 137 getInvocations()138 public List<Invocation> getInvocations() { 139 return registeredInvocations.getAll(); 140 } 141 clearInvocations()142 public void clearInvocations() { 143 registeredInvocations.clear(); 144 } 145 146 /** 147 * Stubbings in descending order, most recent first 148 */ getStubbingsDescending()149 public List<Stubbing> getStubbingsDescending() { 150 return (List) stubbed; 151 } 152 153 /** 154 * Stubbings in ascending order, most recent last 155 */ getStubbingsAscending()156 public Collection<Stubbing> getStubbingsAscending() { 157 List<Stubbing> result = new LinkedList<>(stubbed); 158 Collections.reverse(result); 159 return result; 160 } 161 invokedMock()162 public Object invokedMock() { 163 return invocationForStubbing.getInvocation().getMock(); 164 } 165 createRegisteredInvocations(MockCreationSettings mockSettings)166 private RegisteredInvocations createRegisteredInvocations(MockCreationSettings mockSettings) { 167 return mockSettings.isStubOnly() 168 ? new SingleRegisteredInvocation() 169 : new DefaultRegisteredInvocations(); 170 } 171 findStubbedAnswer()172 public Answer findStubbedAnswer() { 173 synchronized (stubbed) { 174 for (StubbedInvocationMatcher s : stubbed) { 175 if (invocationForStubbing.matches(s.getInvocation())) { 176 return s; 177 } 178 } 179 } 180 return null; 181 } 182 } 183