• 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.handler;
6 
7 import static org.mockito.internal.listeners.StubbingLookupNotifier.notifyStubbedAnswerLookup;
8 import static org.mockito.internal.progress.ThreadSafeMockingProgress.mockingProgress;
9 
10 import org.mockito.internal.creation.settings.CreationSettings;
11 import org.mockito.internal.invocation.InvocationMatcher;
12 import org.mockito.internal.invocation.MatchersBinder;
13 import org.mockito.internal.stubbing.InvocationContainerImpl;
14 import org.mockito.internal.stubbing.OngoingStubbingImpl;
15 import org.mockito.internal.stubbing.StubbedInvocationMatcher;
16 import org.mockito.internal.stubbing.answers.DefaultAnswerValidator;
17 import org.mockito.internal.util.MockUtil;
18 import org.mockito.internal.verification.MockAwareVerificationMode;
19 import org.mockito.internal.verification.VerificationDataImpl;
20 import org.mockito.invocation.Invocation;
21 import org.mockito.invocation.InvocationContainer;
22 import org.mockito.invocation.MockHandler;
23 import org.mockito.mock.MockCreationSettings;
24 import org.mockito.verification.VerificationMode;
25 
26 /**
27  * Invocation handler set on mock objects.
28  *
29  * @param <T> type of mock object to handle
30  */
31 public class MockHandlerImpl<T> implements MockHandler<T> {
32 
33     private static final long serialVersionUID = -2917871070982574165L;
34 
35     InvocationContainerImpl invocationContainer;
36 
37     MatchersBinder matchersBinder = new MatchersBinder();
38 
39     private final MockCreationSettings<T> mockSettings;
40 
MockHandlerImpl(MockCreationSettings<T> mockSettings)41     public MockHandlerImpl(MockCreationSettings<T> mockSettings) {
42         this.mockSettings = mockSettings;
43 
44         this.matchersBinder = new MatchersBinder();
45         this.invocationContainer = new InvocationContainerImpl(mockSettings);
46     }
47 
48     @Override
handle(Invocation invocation)49     public Object handle(Invocation invocation) throws Throwable {
50         if (invocationContainer.hasAnswersForStubbing()) {
51             // stubbing voids with doThrow() or doAnswer() style
52             InvocationMatcher invocationMatcher =
53                     matchersBinder.bindMatchers(
54                             mockingProgress().getArgumentMatcherStorage(), invocation);
55             invocationContainer.setMethodForStubbing(invocationMatcher);
56             return null;
57         }
58         VerificationMode verificationMode = mockingProgress().pullVerificationMode();
59 
60         InvocationMatcher invocationMatcher =
61                 matchersBinder.bindMatchers(
62                         mockingProgress().getArgumentMatcherStorage(), invocation);
63 
64         mockingProgress().validateState();
65 
66         // if verificationMode is not null then someone is doing verify()
67         if (verificationMode != null) {
68             // We need to check if verification was started on the correct mock
69             // - see VerifyingWithAnExtraCallToADifferentMockTest (bug 138)
70             if (MockUtil.areSameMocks(
71                     ((MockAwareVerificationMode) verificationMode).getMock(),
72                     invocation.getMock())) {
73                 VerificationDataImpl data =
74                         new VerificationDataImpl(invocationContainer, invocationMatcher);
75                 verificationMode.verify(data);
76                 return null;
77             } else {
78                 // this means there is an invocation on a different mock. Re-adding verification
79                 // mode
80                 // - see VerifyingWithAnExtraCallToADifferentMockTest (bug 138)
81                 mockingProgress().verificationStarted(verificationMode);
82             }
83         }
84 
85         // prepare invocation for stubbing
86         invocationContainer.setInvocationForPotentialStubbing(invocationMatcher);
87         OngoingStubbingImpl<T> ongoingStubbing = new OngoingStubbingImpl<T>(invocationContainer);
88         mockingProgress().reportOngoingStubbing(ongoingStubbing);
89 
90         // look for existing answer for this invocation
91         StubbedInvocationMatcher stubbing = invocationContainer.findAnswerFor(invocation);
92         // TODO #793 - when completed, we should be able to get rid of the casting below
93         notifyStubbedAnswerLookup(
94                 invocation,
95                 stubbing,
96                 invocationContainer.getStubbingsAscending(),
97                 (CreationSettings) mockSettings);
98 
99         if (stubbing != null) {
100             stubbing.captureArgumentsFrom(invocation);
101 
102             try {
103                 return stubbing.answer(invocation);
104             } finally {
105                 // Needed so that we correctly isolate stubbings in some scenarios
106                 // see MockitoStubbedCallInAnswerTest or issue #1279
107                 mockingProgress().reportOngoingStubbing(ongoingStubbing);
108             }
109         } else {
110             Object ret = mockSettings.getDefaultAnswer().answer(invocation);
111             DefaultAnswerValidator.validateReturnValueFor(invocation, ret);
112 
113             // Mockito uses it to redo setting invocation for potential stubbing in case of partial
114             // mocks / spies.
115             // Without it, the real method inside 'when' might have delegated to other self method
116             // and overwrite the intended stubbed method with a different one.
117             // This means we would be stubbing a wrong method.
118             // Typically this would led to runtime exception that validates return type with stubbed
119             // method signature.
120             invocationContainer.resetInvocationForPotentialStubbing(invocationMatcher);
121             return ret;
122         }
123     }
124 
125     @Override
getMockSettings()126     public MockCreationSettings<T> getMockSettings() {
127         return mockSettings;
128     }
129 
130     @Override
getInvocationContainer()131     public InvocationContainer getInvocationContainer() {
132         return invocationContainer;
133     }
134 }
135