All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.fitbur.mockito.internal.handler.MockHandlerImpl Maven / Gradle / Ivy

There is a newer version: 1.0.0
Show newest version
/*
 * Copyright (c) 2007 Mockito contributors
 * This program is made available under the terms of the MIT License.
 */
package com.fitbur.mockito.internal.handler;

import com.fitbur.mockito.internal.InternalMockHandler;
import com.fitbur.mockito.internal.invocation.InvocationMatcher;
import com.fitbur.mockito.internal.invocation.MatchersBinder;
import com.fitbur.mockito.internal.progress.MockingProgress;
import com.fitbur.mockito.internal.progress.ThreadSafeMockingProgress;
import com.fitbur.mockito.internal.stubbing.InvocationContainer;
import com.fitbur.mockito.internal.stubbing.InvocationContainerImpl;
import com.fitbur.mockito.internal.stubbing.OngoingStubbingImpl;
import com.fitbur.mockito.internal.stubbing.StubbedInvocationMatcher;
import com.fitbur.mockito.internal.stubbing.answers.AnswersValidator;
import com.fitbur.mockito.internal.verification.MockAwareVerificationMode;
import com.fitbur.mockito.internal.verification.VerificationDataImpl;
import com.fitbur.mockito.invocation.Invocation;
import com.fitbur.mockito.mock.MockCreationSettings;
import com.fitbur.mockito.stubbing.Answer;
import com.fitbur.mockito.verification.VerificationMode;

import java.util.List;

import static com.fitbur.mockito.exceptions.Reporter.stubPassedToVerify;

/**
 * Invocation handler set on mock objects.
 *
 * @param  type of mock object to handle
 */
class MockHandlerImpl implements InternalMockHandler {

    private static final long serialVersionUID = -2917871070982574165L;

    InvocationContainerImpl invocationContainerImpl;

    MatchersBinder matchersBinder = new MatchersBinder();

    MockingProgress mockingProgress = new ThreadSafeMockingProgress();

    private final MockCreationSettings mockSettings;

    public MockHandlerImpl(MockCreationSettings mockSettings) {
        this.mockSettings = mockSettings;
        this.mockingProgress = new ThreadSafeMockingProgress();
        this.matchersBinder = new MatchersBinder();
        this.invocationContainerImpl = new InvocationContainerImpl(mockingProgress, mockSettings);
    }

    public Object handle(Invocation invocation) throws Throwable {
        if (invocationContainerImpl.hasAnswersForStubbing()) {
            // stubbing voids with doThrow() or doAnswer() style
            InvocationMatcher invocationMatcher = matchersBinder.bindMatchers(
                    mockingProgress.getArgumentMatcherStorage(),
                    invocation
            );
            invocationContainerImpl.setMethodForStubbing(invocationMatcher);
            return null;
        }
        VerificationMode verificationMode = mockingProgress.pullVerificationMode();

        InvocationMatcher invocationMatcher = matchersBinder.bindMatchers(
                mockingProgress.getArgumentMatcherStorage(),
                invocation
        );

        mockingProgress.validateState();

        // if verificationMode is not null then someone is doing verify()
        if (verificationMode != null) {
            // We need to check if verification was started on the correct mock
            // - see VerifyingWithAnExtraCallToADifferentMockTest (bug 138)
            if (((MockAwareVerificationMode) verificationMode).getMock() == invocation.getMock()) {
                VerificationDataImpl data = createVerificationData(invocationContainerImpl, invocationMatcher);
                verificationMode.verify(data);
                return null;
            } else {
                // this means there is an invocation on a different mock. Re-adding verification mode
                // - see VerifyingWithAnExtraCallToADifferentMockTest (bug 138)
                mockingProgress.verificationStarted(verificationMode);
            }
        }

        // prepare invocation for stubbing
        invocationContainerImpl.setInvocationForPotentialStubbing(invocationMatcher);
        OngoingStubbingImpl ongoingStubbing = new OngoingStubbingImpl(invocationContainerImpl);
        mockingProgress.reportOngoingStubbing(ongoingStubbing);

        // look for existing answer for this invocation
        StubbedInvocationMatcher stubbedInvocation = invocationContainerImpl.findAnswerFor(invocation);

        if (stubbedInvocation != null) {
            stubbedInvocation.captureArgumentsFrom(invocation);
            return stubbedInvocation.answer(invocation);
        } else {
            Object ret = mockSettings.getDefaultAnswer().answer(invocation);
            new AnswersValidator().validateDefaultAnswerReturnedValue(invocation, ret);

            // redo setting invocation for potential stubbing in case of partial
            // mocks / spies.
            // Without it, the real method inside 'when' might have delegated
            // to other self method and overwrite the intended stubbed method
            // with a different one. The reset is required to avoid runtime exception that validates return type with stubbed method signature.
            invocationContainerImpl.resetInvocationForPotentialStubbing(invocationMatcher);
            return ret;
        }
    }

    public MockCreationSettings getMockSettings() {
        return mockSettings;
    }

    @SuppressWarnings("unchecked")
    public void setAnswersForStubbing(List> answers) {
        invocationContainerImpl.setAnswersForStubbing(answers);
    }

    public InvocationContainer getInvocationContainer() {
        return invocationContainerImpl;
    }

    private VerificationDataImpl createVerificationData(InvocationContainerImpl invocationContainerImpl, InvocationMatcher invocationMatcher) {
        if (mockSettings.isStubOnly()) {
            throw stubPassedToVerify();     // this throws an exception
        }

        return new VerificationDataImpl(invocationContainerImpl, invocationMatcher);
    }
}





© 2015 - 2024 Weber Informatics LLC | Privacy Policy