1/*
2 * Copyright (c) 2007 Mockito contributors
3 * This program is made available under the terms of the MIT License.
4 */
5package org.mockito.internal;
6
7import org.mockito.InOrder;
8import org.mockito.MockSettings;
9import org.mockito.MockingDetails;
10import org.mockito.exceptions.Reporter;
11import org.mockito.exceptions.misusing.NotAMockException;
12import org.mockito.internal.creation.MockSettingsImpl;
13import org.mockito.internal.invocation.finder.VerifiableInvocationsFinder;
14import org.mockito.internal.progress.IOngoingStubbing;
15import org.mockito.internal.progress.MockingProgress;
16import org.mockito.internal.progress.ThreadSafeMockingProgress;
17import org.mockito.internal.stubbing.InvocationContainer;
18import org.mockito.internal.stubbing.OngoingStubbingImpl;
19import org.mockito.internal.stubbing.StubberImpl;
20import org.mockito.internal.util.DefaultMockingDetails;
21import org.mockito.internal.util.MockUtil;
22import org.mockito.internal.verification.MockAwareVerificationMode;
23import org.mockito.internal.verification.VerificationDataImpl;
24import org.mockito.internal.verification.VerificationModeFactory;
25import org.mockito.internal.verification.api.InOrderContext;
26import org.mockito.internal.verification.api.VerificationDataInOrder;
27import org.mockito.internal.verification.api.VerificationDataInOrderImpl;
28import org.mockito.invocation.Invocation;
29import org.mockito.mock.MockCreationSettings;
30import org.mockito.stubbing.*;
31import org.mockito.verification.VerificationMode;
32
33import java.util.Arrays;
34import java.util.List;
35
36@SuppressWarnings("unchecked")
37public class MockitoCore {
38
39    private final Reporter reporter = new Reporter();
40    private final MockUtil mockUtil = new MockUtil();
41    private final MockingProgress mockingProgress = new ThreadSafeMockingProgress();
42
43    public boolean isTypeMockable(Class<?> typeToMock) {
44        return mockUtil.isTypeMockable(typeToMock);
45    }
46
47    public <T> T mock(Class<T> typeToMock, MockSettings settings) {
48        if (!MockSettingsImpl.class.isInstance(settings)) {
49            throw new IllegalArgumentException(
50                    "Unexpected implementation of '" + settings.getClass().getCanonicalName() + "'\n"
51                    + "At the moment, you cannot provide your own implementations that class.");
52        }
53        MockSettingsImpl impl = MockSettingsImpl.class.cast(settings);
54        MockCreationSettings<T> creationSettings = impl.confirm(typeToMock);
55        T mock = mockUtil.createMock(creationSettings);
56        mockingProgress.mockingStarted(mock, typeToMock);
57        return mock;
58    }
59
60    public IOngoingStubbing stub() {
61        IOngoingStubbing stubbing = mockingProgress.pullOngoingStubbing();
62        if (stubbing == null) {
63            mockingProgress.reset();
64            reporter.missingMethodInvocation();
65        }
66        return stubbing;
67    }
68
69    public <T> DeprecatedOngoingStubbing<T> stub(T methodCall) {
70        mockingProgress.stubbingStarted();
71        return (DeprecatedOngoingStubbing) stub();
72    }
73
74    public <T> OngoingStubbing<T> when(T methodCall) {
75        mockingProgress.stubbingStarted();
76        return (OngoingStubbing) stub();
77    }
78
79    public <T> T verify(T mock, VerificationMode mode) {
80        if (mock == null) {
81            reporter.nullPassedToVerify();
82        } else if (!mockUtil.isMock(mock)) {
83            reporter.notAMockPassedToVerify(mock.getClass());
84        }
85        mockingProgress.verificationStarted(new MockAwareVerificationMode(mock, mode));
86        return mock;
87    }
88
89    public <T> void reset(T ... mocks) {
90        mockingProgress.validateState();
91        mockingProgress.reset();
92        mockingProgress.resetOngoingStubbing();
93
94        for (T m : mocks) {
95            mockUtil.resetMock(m);
96        }
97    }
98
99    public void verifyNoMoreInteractions(Object... mocks) {
100        assertMocksNotEmpty(mocks);
101        mockingProgress.validateState();
102        for (Object mock : mocks) {
103            try {
104                if (mock == null) {
105                    reporter.nullPassedToVerifyNoMoreInteractions();
106                }
107                InvocationContainer invocations = mockUtil.getMockHandler(mock).getInvocationContainer();
108                VerificationDataImpl data = new VerificationDataImpl(invocations, null);
109                VerificationModeFactory.noMoreInteractions().verify(data);
110            } catch (NotAMockException e) {
111                reporter.notAMockPassedToVerifyNoMoreInteractions();
112            }
113        }
114    }
115
116    public void verifyNoMoreInteractionsInOrder(List<Object> mocks, InOrderContext inOrderContext) {
117        mockingProgress.validateState();
118        VerifiableInvocationsFinder finder = new VerifiableInvocationsFinder();
119        VerificationDataInOrder data = new VerificationDataInOrderImpl(inOrderContext, finder.find(mocks), null);
120        VerificationModeFactory.noMoreInteractions().verifyInOrder(data);
121    }
122
123    private void assertMocksNotEmpty(Object[] mocks) {
124        if (mocks == null || mocks.length == 0) {
125            reporter.mocksHaveToBePassedToVerifyNoMoreInteractions();
126        }
127    }
128
129    public InOrder inOrder(Object... mocks) {
130        if (mocks == null || mocks.length == 0) {
131            reporter.mocksHaveToBePassedWhenCreatingInOrder();
132        }
133        for (Object mock : mocks) {
134            if (mock == null) {
135                reporter.nullPassedWhenCreatingInOrder();
136            } else if (!mockUtil.isMock(mock)) {
137                reporter.notAMockPassedWhenCreatingInOrder();
138            }
139        }
140        return new InOrderImpl(Arrays.asList(mocks));
141    }
142
143    public Stubber doAnswer(Answer answer) {
144        mockingProgress.stubbingStarted();
145        mockingProgress.resetOngoingStubbing();
146        return new StubberImpl().doAnswer(answer);
147    }
148
149    public <T> VoidMethodStubbable<T> stubVoid(T mock) {
150        InternalMockHandler<T> handler = mockUtil.getMockHandler(mock);
151        mockingProgress.stubbingStarted();
152        return handler.voidMethodStubbable(mock);
153    }
154
155    public void validateMockitoUsage() {
156        mockingProgress.validateState();
157    }
158
159    /**
160     * For testing purposes only. Is not the part of main API.
161     * @return last invocation
162     */
163    public Invocation getLastInvocation() {
164        OngoingStubbingImpl ongoingStubbing = ((OngoingStubbingImpl) mockingProgress.pullOngoingStubbing());
165        List<Invocation> allInvocations = ongoingStubbing.getRegisteredInvocations();
166        return allInvocations.get(allInvocations.size()-1);
167    }
168
169    public Object[] ignoreStubs(Object... mocks) {
170        for (Object m : mocks) {
171            InvocationContainer invocationContainer = new MockUtil().getMockHandler(m).getInvocationContainer();
172            List<Invocation> ins = invocationContainer.getInvocations();
173            for (Invocation in : ins) {
174                if (in.stubInfo() != null) {
175                    in.ignoreForVerification();
176                }
177            }
178        }
179        return mocks;
180    }
181
182    public MockingDetails mockingDetails(Object toInspect) {
183        return new DefaultMockingDetails(toInspect, new MockUtil());
184    }
185}