/* * * * Copyright 2010, Unitils.org * * * * Licensed under the Apache License, Version 2.0 (the "License"); * * you may not use this file except in compliance with the License. * * You may obtain a copy of the License at * * * * http://www.apache.org/licenses/LICENSE-2.0 * * * * Unless required by applicable law or agreed to in writing, software * * distributed under the License is distributed on an "AS IS" BASIS, * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * * See the License for the specific language governing permissions and * * limitations under the License. * */ package org.unitils.mock.core; import org.unitils.core.UnitilsException; import org.unitils.mock.core.matching.MatchingInvocationBuilder; import org.unitils.mock.core.proxy.ProxyInvocation; import org.unitils.mock.core.proxy.ProxyInvocationHandler; import org.unitils.mock.mockbehavior.MockBehavior; import org.unitils.mock.mockbehavior.ValidatableMockBehavior; import org.unitils.mock.mockbehavior.impl.DefaultValueReturningMockBehavior; import static org.unitils.mock.core.proxy.ProxyFactory.createProxy; public class MockProxy<T> { /* The mock proxy instance */ protected T proxy; protected BehaviorDefiningInvocations oneTimeMatchingBehaviorDefiningInvocations; protected BehaviorDefiningInvocations alwaysMatchingBehaviorDefiningInvocations; /* The scenario that will record all observed invocations */ protected Scenario scenario; protected MatchingInvocationBuilder matchingInvocationBuilder; public MockProxy(String mockName, Class<T> mockedType, BehaviorDefiningInvocations oneTimeMatchingBehaviorDefiningInvocations, BehaviorDefiningInvocations alwaysMatchingBehaviorDefiningInvocations, Scenario scenario, MatchingInvocationBuilder matchingInvocationBuilder) { this.oneTimeMatchingBehaviorDefiningInvocations = oneTimeMatchingBehaviorDefiningInvocations; this.alwaysMatchingBehaviorDefiningInvocations = alwaysMatchingBehaviorDefiningInvocations; this.scenario = scenario; this.matchingInvocationBuilder = matchingInvocationBuilder; this.proxy = createProxy(mockName, new InvocationHandler(), mockedType, Cloneable.class); } @SuppressWarnings("unchecked") public T getProxy() { return proxy; } protected Object handleMockInvocation(ProxyInvocation proxyInvocation) throws Throwable { matchingInvocationBuilder.assertNotExpectingInvocation(); BehaviorDefiningInvocation behaviorDefiningInvocation = getMatchingBehaviorDefiningInvocation(proxyInvocation); MockBehavior mockBehavior = getValidMockBehavior(proxyInvocation, behaviorDefiningInvocation); ObservedInvocation observedInvocation = new ObservedInvocation(proxyInvocation, behaviorDefiningInvocation, mockBehavior); scenario.addObservedMockInvocation(observedInvocation); Throwable throwable = null; Object result = null; if (mockBehavior != null) { try { result = mockBehavior.execute(proxyInvocation); } catch (Throwable t) { throwable = t; } } observedInvocation.setResult(result); if (throwable != null) { throw throwable; } return result; } protected BehaviorDefiningInvocation getMatchingBehaviorDefiningInvocation(ProxyInvocation proxyInvocation) throws Throwable { BehaviorDefiningInvocation behaviorDefiningInvocation = oneTimeMatchingBehaviorDefiningInvocations.getMatchingBehaviorDefiningInvocation(proxyInvocation); if (behaviorDefiningInvocation == null) { behaviorDefiningInvocation = alwaysMatchingBehaviorDefiningInvocations.getMatchingBehaviorDefiningInvocation(proxyInvocation); } return behaviorDefiningInvocation; } protected MockBehavior getValidMockBehavior(ProxyInvocation proxyInvocation, BehaviorDefiningInvocation behaviorDefiningInvocation) { if (behaviorDefiningInvocation != null) { MockBehavior mockBehavior = behaviorDefiningInvocation.getMockBehavior(); assertCanExecute(mockBehavior, proxyInvocation, behaviorDefiningInvocation); return mockBehavior; } return getDefaultMockBehavior(proxyInvocation); } /** * Check whether the mock behavior can applied for this invocation * * @param mockBehavior The behavior to verify, not null * @param proxyInvocation The invocation, not null * @param behaviorDefiningInvocation The invocation that defined the behavior, not null */ protected void assertCanExecute(MockBehavior mockBehavior, ProxyInvocation proxyInvocation, BehaviorDefiningInvocation behaviorDefiningInvocation) { if (!(mockBehavior instanceof ValidatableMockBehavior)) { return; } ValidatableMockBehavior validatableMockBehavior = (ValidatableMockBehavior) mockBehavior; try { validatableMockBehavior.assertCanExecute(proxyInvocation); } catch (UnitilsException e) { e.setStackTrace(behaviorDefiningInvocation.getInvokedAtTrace()); throw e; } } protected MockBehavior getDefaultMockBehavior(ProxyInvocation proxyInvocation) { if (proxyInvocation.getMethod().getReturnType() == Void.TYPE) { return null; } return new DefaultValueReturningMockBehavior(); } protected class InvocationHandler implements ProxyInvocationHandler { public Object handleInvocation(ProxyInvocation invocation) throws Throwable { return handleMockInvocation(invocation); } } }