Skip to content

Commit

Permalink
Fixes #726 Mockito Public API Support
Browse files Browse the repository at this point in the history
Replace using ThrowsException and other Mockito's internals answers by calling public API.
  • Loading branch information
Arthur Zagretdinov authored and thekingn0thing committed Sep 10, 2017
1 parent 8a91e41 commit db008a1
Show file tree
Hide file tree
Showing 15 changed files with 441 additions and 328 deletions.
Expand Up @@ -1990,8 +1990,8 @@ public void run() {
}

private static <T> Class<?> createReplicaType(Class<T> type, boolean isStatic, ConstructorArgs constructorArgs) {
ClassReplicaCreator classReplicaCreator = new ClassReplicaCreator();
Class<?> replicaType = null;
final ClassReplicaCreator classReplicaCreator = new ClassReplicaCreator();
final Class<?> replicaType;
if (isStatic || constructorArgs == null) {
replicaType = classReplicaCreator.createClassReplica(type);
} else {
Expand Down
Expand Up @@ -28,11 +28,11 @@
import org.mockito.stubbing.OngoingStubbing;
import org.mockito.verification.VerificationMode;
import org.powermock.api.mockito.expectation.ConstructorExpectationSetup;
import org.powermock.api.mockito.expectation.DefaultConstructorExpectationSetup;
import org.powermock.api.mockito.expectation.PowerMockitoStubber;
import org.powermock.api.mockito.expectation.WithOrWithoutExpectedArguments;
import org.powermock.api.mockito.internal.PowerMockitoCore;
import org.powermock.api.mockito.internal.expectation.ConstructorAwareExpectationSetup;
import org.powermock.api.mockito.internal.expectation.DefaultConstructorExpectationSetup;
import org.powermock.api.mockito.expectation.ConstructorAwareExpectationSetup;
import org.powermock.api.mockito.internal.expectation.DefaultMethodExpectationSetup;
import org.powermock.api.mockito.internal.mockcreation.DefaultMockCreator;
import org.powermock.api.mockito.internal.stubbing.answers.ChainReturns;
Expand Down
@@ -0,0 +1,51 @@
/*
* Copyright 2016 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.expectation;

import org.mockito.stubbing.OngoingStubbing;

import java.lang.reflect.Constructor;

public class ConstructorAwareExpectationSetup<T> implements WithOrWithoutExpectedArguments<T> {

private final Constructor<T> ctor;
private final DefaultConstructorExpectationSetup<T> expectationSetup;

public ConstructorAwareExpectationSetup(Constructor<T> ctor) {
if (ctor == null) {
throw new IllegalArgumentException("Constructor to expect cannot be null");
}
this.ctor = ctor;
this.expectationSetup = setupExpectation();
}

@Override
public OngoingStubbing<T> withArguments(Object firstArgument, Object... additionalArguments) throws Exception {
return expectationSetup.withArguments(firstArgument, additionalArguments);
}

@Override
public OngoingStubbing<T> withNoArguments() throws Exception {
return expectationSetup.withNoArguments();
}

private DefaultConstructorExpectationSetup<T> setupExpectation() {
DefaultConstructorExpectationSetup<T> setup = new DefaultConstructorExpectationSetup<T>(ctor.getDeclaringClass());
setup.setParameterTypes(ctor.getParameterTypes());
return setup;
}
}
@@ -1,9 +1,28 @@
package org.powermock.api.mockito.internal.expectation;

/*
*
* Copyright 2017 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.expectation;

import org.mockito.ArgumentMatchers;
import org.mockito.stubbing.OngoingStubbing;
import org.powermock.api.mockito.expectation.ConstructorExpectationSetup;
import org.powermock.api.mockito.expectation.WithExpectedArguments;
import org.powermock.api.mockito.internal.mockcreation.MockCreator;
import org.powermock.api.mockito.internal.expectation.DelegatingToConstructorsOngoingStubbing;
import org.powermock.api.mockito.internal.invocation.MockitoNewInvocationControl;
import org.powermock.api.mockito.internal.mockcreation.DefaultMockCreator;
import org.powermock.core.MockRepository;
import org.powermock.core.spi.NewInvocationControl;
import org.powermock.core.spi.support.InvocationSubstitute;
Expand All @@ -14,63 +33,59 @@
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

public abstract class AbstractConstructorExpectationSetup<T> implements ConstructorExpectationSetup<T> {

protected final Class<T> mockType;
protected final ArrayMerger arrayMerger;
public class DefaultConstructorExpectationSetup<T> implements ConstructorExpectationSetup<T> {

private final Class<T> mockType;
private final ArrayMerger arrayMerger;
private final DefaultMockCreator mockCreator;
private Class<?>[] parameterTypes = null;

public AbstractConstructorExpectationSetup(Class<T> mockType) {
private final InvocationSubstitute mock;

public DefaultConstructorExpectationSetup(Class<T> mockType) {
this.arrayMerger = new ArrayMergerImpl();
this.mockType = mockType;
this.mockCreator = new DefaultMockCreator();
this.mock = getMockCreator().createMock(InvocationSubstitute.class, false, false, null, null, (Method[]) null);
}


@Override
public OngoingStubbing<T> withArguments(Object firstArgument, Object... additionalArguments) throws Exception {
return createNewSubstituteMock(mockType, parameterTypes, arrayMerger.mergeArrays(Object.class, new Object[]{firstArgument},
additionalArguments));
}

@SuppressWarnings({"unchecked", "rawtypes"})
private <T> OngoingStubbing<T> createNewSubstituteMock(Class<T> type, Class<?>[] parameterTypes,
Object... arguments) throws Exception {
private OngoingStubbing<T> createNewSubstituteMock(Class<T> type, Class<?>[] parameterTypes, Object... arguments) throws Exception {
if (type == null) {
throw new IllegalArgumentException("type cannot be null");
}

final Class<T> unmockedType = (Class<T>) WhiteboxImpl.getOriginalUnmockedType(type);
if (parameterTypes == null) {
WhiteboxImpl.findUniqueConstructorOrThrowException(type, arguments);
} else {
WhiteboxImpl.getConstructor(unmockedType, parameterTypes);
}


NewInvocationControl<OngoingStubbing<T>> newInvocationControl = createNewInvocationControl(type, unmockedType);

return newInvocationControl.expectSubstitutionLogic(arguments);
}

private NewInvocationControl<OngoingStubbing<T>> createNewInvocationControl(final Class<T> type, final Class<T> unmockedType) {
/*
* Check if this type has been mocked before
*/
NewInvocationControl<OngoingStubbing<T>> newInvocationControl =
(NewInvocationControl<OngoingStubbing<T>>) MockRepository.getNewInstanceControl(unmockedType);
(NewInvocationControl<OngoingStubbing<T>>) MockRepository.getNewInstanceControl(unmockedType);
if (newInvocationControl == null) {
InvocationSubstitute<T> mock = getMockCreator().createMock(InvocationSubstitute.class, false, false, null, null, (Method[]) null);
newInvocationControl = createNewInvocationControl(mock);
MockRepository.putNewInstanceControl(type, newInvocationControl);
MockRepository.addObjectsToAutomaticallyReplayAndVerify(WhiteboxImpl.getOriginalUnmockedType(type));
}

return newInvocationControl.expectSubstitutionLogic(arguments);
}

abstract MockCreator getMockCreator();
abstract <T> NewInvocationControl<OngoingStubbing<T>> createNewInvocationControl(InvocationSubstitute<T> mock);

void setParameterTypes(Class<?>[] parameterTypes) {
this.parameterTypes = parameterTypes;
return newInvocationControl;
}

OngoingStubbing<T> withArguments(Object[] additionalArguments) throws Exception {
return createNewSubstituteMock(mockType, parameterTypes, additionalArguments);
}

@Override
public OngoingStubbing<T> withArguments(Object firstArgument, Object... additionalArguments) throws Exception {
return createNewSubstituteMock(mockType, parameterTypes, arrayMerger.mergeArrays(Object.class, new Object[]{firstArgument},
additionalArguments));
}


@Override
public OngoingStubbing<T> withAnyArguments() throws Exception {
if (mockType == null) {
Expand All @@ -85,23 +100,35 @@ public OngoingStubbing<T> withAnyArguments() throws Exception {
Class<?> paramType = parameterTypes[i];
paramArgs[i] = createParamArgMatcher(paramType);
}
final OngoingStubbing<T> ongoingStubbing = createNewSubstituteMock(mockType, parameterTypes, paramArgs);
Constructor<?>[] otherCtors = new Constructor<?>[allConstructors.length - 1];
System.arraycopy(allConstructors, 1, otherCtors, 0, allConstructors.length - 1);

final OngoingStubbing<T> ongoingStubbing = createNewSubstituteMock(mockType, parameterTypes, paramArgs);
return new DelegatingToConstructorsOngoingStubbing<T>(otherCtors, ongoingStubbing);
}

abstract Object createParamArgMatcher(Class<?> paramType);


private Object createParamArgMatcher(Class<?> paramType) {
return ArgumentMatchers.nullable(paramType);
}

@Override
public OngoingStubbing<T> withNoArguments() throws Exception {
return createNewSubstituteMock(mockType, parameterTypes);
}

@Override
public WithExpectedArguments<T> withParameterTypes(Class<?> parameterType, Class<?>... additionalParameterTypes) {
this.parameterTypes = arrayMerger.mergeArrays(Class.class, new Class<?>[]{parameterType}, additionalParameterTypes);
return this;
}


private DefaultMockCreator getMockCreator() {return mockCreator;}

private NewInvocationControl<OngoingStubbing<T>> createNewInvocationControl(InvocationSubstitute<T> mock) {
return new MockitoNewInvocationControl<T>(mock);
}

void setParameterTypes(Class<?>[] parameterTypes) {
this.parameterTypes = parameterTypes;
}
}

This file was deleted.

This file was deleted.

Expand Up @@ -17,12 +17,12 @@
package org.powermock.api.mockito.internal.expectation;

import org.mockito.internal.stubbing.StubberImpl;
import org.mockito.invocation.InvocationContainer;
import org.mockito.invocation.MockHandler;
import org.mockito.stubbing.Answer;
import org.mockito.stubbing.Stubber;
import org.powermock.api.mockito.expectation.PowerMockitoStubber;
import org.powermock.api.mockito.expectation.PrivatelyExpectedArguments;
import org.powermock.api.mockito.internal.invocation.MockitoMethodInvocationControl;
import org.powermock.api.mockito.invocation.MockitoMethodInvocationControl;
import org.powermock.api.mockito.invocation.MockHandlerAdaptor;
import org.powermock.core.MockRepository;
import org.powermock.reflect.Whitebox;

Expand Down Expand Up @@ -64,14 +64,9 @@ public <T> T when(T instanceMock) {

@SuppressWarnings("unchecked")
private void addAnswersForStubbing(MockitoMethodInvocationControl invocationControl) {
final MockHandler mockHandler = invocationControl.getMockHandler();
InvocationContainer invocationContainer = mockHandler.getInvocationContainer();
final List list = Whitebox.getInternalState(this, List.class);
try {
Whitebox.invokeMethod(invocationContainer, "setAnswersForStubbing", list);
} catch (Exception e) {
throw new RuntimeException(e);
}
final MockHandlerAdaptor mockHandler = invocationControl.getMockHandlerAdaptor();
final List<Answer<?>> answers = Whitebox.getInternalState(this, List.class);
mockHandler.setAnswersForStubbing(answers);
}

@Override
Expand Down

0 comments on commit db008a1

Please sign in to comment.