• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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