/*
* Copyright 2012 the original author or authors.
*
* 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.powermock.api.mockito.internal.expectation;
import org.mockito.Matchers;
import org.mockito.stubbing.Answer;
import org.mockito.stubbing.OngoingStubbing;
import org.powermock.core.spi.support.InvocationSubstitute;
import java.lang.reflect.Constructor;
import static org.mockito.Mockito.when;
/**
* Implementation of OngoingStubbing that delegates invocations to all supplied ctors
* @param <T>
*/
public class DelegatingToConstructorsOngoingStubbing<T> implements OngoingStubbing<T>{
private final OngoingStubbing<T> stubbing;
private final Constructor<?>[] ctors;
public DelegatingToConstructorsOngoingStubbing(Constructor<?>[] ctors, OngoingStubbing<T> stubbing) {
if(stubbing == null) {
throw new IllegalArgumentException("Internal error: Ongoing stubbing must be provided");
}
this.ctors = ctors;
this.stubbing = stubbing;
}
@Override
public OngoingStubbing<T> thenReturn(final T value) {
stubbing.thenReturn(value);
return new InvokeStubMethod() {
@Override
public void performStubbing(OngoingStubbing<T> when) {
when.thenReturn(value);
}
}.invoke();
}
@Override
public OngoingStubbing<T> thenReturn(final T value, final T... values) {
stubbing.thenReturn(value, values);
return new InvokeStubMethod() {
@Override
public void performStubbing(OngoingStubbing<T> when) {
when.thenReturn(value, values);
}
}.invoke();
}
@Override
public OngoingStubbing<T> thenThrow(final Throwable... throwables) {
stubbing.thenThrow(throwables);
return new InvokeStubMethod() {
@Override
public void performStubbing(OngoingStubbing<T> when) {
when.thenThrow(throwables);
}
}.invoke();
}
@Override
public OngoingStubbing<T> thenThrow(final Class<? extends Throwable>... throwableClasses) {
stubbing.thenThrow(throwableClasses);
return new InvokeStubMethod() {
@Override
public void performStubbing(OngoingStubbing<T> when) {
when.thenThrow(throwableClasses);
}
}.invoke();
}
@Override
public OngoingStubbing<T> thenCallRealMethod() {
stubbing.thenCallRealMethod();
return new InvokeStubMethod() {
@Override
public void performStubbing(OngoingStubbing<T> when) {
when.thenCallRealMethod();
}
}.invoke();
}
@Override
public OngoingStubbing<T> thenAnswer(final Answer<?> answer) {
stubbing.thenAnswer(answer);
return new InvokeStubMethod() {
@Override
public void performStubbing(OngoingStubbing<T> when) {
when.thenAnswer(answer);
}
}.invoke();
}
@Override
public OngoingStubbing<T> then(final Answer<?> answer) {
stubbing.then(answer);
return new InvokeStubMethod() {
@Override
public void performStubbing(OngoingStubbing<T> when) {
when.then(answer);
}
}.invoke();
}
@Override
public <M> M getMock() {
return stubbing.getMock();
}
private abstract class InvokeStubMethod {
public OngoingStubbing<T> invoke() {
final InvocationSubstitute<T> mock = stubbing.getMock();
for (Constructor<?> constructor : ctors) {
final Class<?>[] parameterTypesForCtor = constructor.getParameterTypes();
Object[] paramArgs = new Object[parameterTypesForCtor.length];
for (int i = 0; i < parameterTypesForCtor.length; i++) {
Class<?> paramType = parameterTypesForCtor[i];
paramArgs[i] = Matchers.any(paramType);
}
try {
final OngoingStubbing<T> when = when(mock.performSubstitutionLogic(paramArgs));
performStubbing(when);
} catch (Exception e) {
throw new RuntimeException("PowerMock internal error",e);
}
}
return stubbing;
}
public abstract void performStubbing(OngoingStubbing<T> when);
}
}