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