blob: ca677307930c811d3acd53ef6ceea7b21a5c409e [file] [log] [blame]
/*
* Copyright (c) 2007 Mockito contributors
* This program is made available under the terms of the MIT License.
*/
package org.mockito.internal.creation;
import org.mockito.MockSettings;
import org.mockito.internal.creation.settings.CreationSettings;
import org.mockito.internal.debugging.VerboseMockInvocationLogger;
import org.mockito.internal.util.Checks;
import org.mockito.internal.util.MockCreationValidator;
import org.mockito.internal.util.MockNameImpl;
import org.mockito.listeners.InvocationListener;
import org.mockito.listeners.VerificationStartedListener;
import org.mockito.mock.MockCreationSettings;
import org.mockito.mock.MockName;
import org.mockito.mock.SerializableMode;
import org.mockito.stubbing.Answer;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import static org.mockito.internal.exceptions.Reporter.defaultAnswerDoesNotAcceptNullParameter;
import static org.mockito.internal.exceptions.Reporter.extraInterfacesAcceptsOnlyInterfaces;
import static org.mockito.internal.exceptions.Reporter.extraInterfacesDoesNotAcceptNullParameters;
import static org.mockito.internal.exceptions.Reporter.extraInterfacesRequiresAtLeastOneInterface;
import static org.mockito.internal.exceptions.Reporter.invocationListenersRequiresAtLeastOneListener;
import static org.mockito.internal.exceptions.Reporter.methodDoesNotAcceptParameter;
import static org.mockito.internal.util.collections.Sets.newSet;
@SuppressWarnings("unchecked")
public class MockSettingsImpl<T> extends CreationSettings<T> implements MockSettings, MockCreationSettings<T> {
private static final long serialVersionUID = 4475297236197939569L;
private boolean useConstructor;
private Object outerClassInstance;
private Object[] constructorArgs;
@Override
public MockSettings serializable() {
return serializable(SerializableMode.BASIC);
}
@Override
public MockSettings serializable(SerializableMode mode) {
this.serializableMode = mode;
return this;
}
@Override
public MockSettings extraInterfaces(Class<?>... extraInterfaces) {
if (extraInterfaces == null || extraInterfaces.length == 0) {
throw extraInterfacesRequiresAtLeastOneInterface();
}
for (Class<?> i : extraInterfaces) {
if (i == null) {
throw extraInterfacesDoesNotAcceptNullParameters();
} else if (!i.isInterface()) {
throw extraInterfacesAcceptsOnlyInterfaces(i);
}
}
this.extraInterfaces = newSet(extraInterfaces);
return this;
}
@Override
public MockName getMockName() {
return mockName;
}
@Override
public Set<Class<?>> getExtraInterfaces() {
return extraInterfaces;
}
@Override
public Object getSpiedInstance() {
return spiedInstance;
}
@Override
public MockSettings name(String name) {
this.name = name;
return this;
}
@Override
public MockSettings spiedInstance(Object spiedInstance) {
this.spiedInstance = spiedInstance;
return this;
}
@Override
public MockSettings defaultAnswer(Answer defaultAnswer) {
this.defaultAnswer = defaultAnswer;
if (defaultAnswer == null) {
throw defaultAnswerDoesNotAcceptNullParameter();
}
return this;
}
@Override
public Answer<Object> getDefaultAnswer() {
return defaultAnswer;
}
@Override
public MockSettingsImpl<T> stubOnly() {
this.stubOnly = true;
return this;
}
@Override
public MockSettings useConstructor(Object... constructorArgs) {
Checks.checkNotNull(constructorArgs,
"constructorArgs",
"If you need to pass null, please cast it to the right type, e.g.: useConstructor((String) null)");
this.useConstructor = true;
this.constructorArgs = constructorArgs;
return this;
}
@Override
public MockSettings outerInstance(Object outerClassInstance) {
this.outerClassInstance = outerClassInstance;
return this;
}
@Override
public MockSettings withoutAnnotations() {
stripAnnotations = true;
return this;
}
@Override
public boolean isUsingConstructor() {
return useConstructor;
}
@Override
public Object getOuterClassInstance() {
return outerClassInstance;
}
@Override
public Object[] getConstructorArgs() {
if (outerClassInstance == null) {
return constructorArgs;
}
List<Object> resultArgs = new ArrayList<Object>(constructorArgs.length + 1);
resultArgs.add(outerClassInstance);
resultArgs.addAll(Arrays.asList(constructorArgs));
return resultArgs.toArray(new Object[constructorArgs.length + 1]);
}
@Override
public boolean isStubOnly() {
return this.stubOnly;
}
@Override
public MockSettings verboseLogging() {
if (!invocationListenersContainsType(VerboseMockInvocationLogger.class)) {
invocationListeners(new VerboseMockInvocationLogger());
}
return this;
}
@Override
public MockSettings invocationListeners(InvocationListener... listeners) {
if (listeners == null || listeners.length == 0) {
throw invocationListenersRequiresAtLeastOneListener();
}
addListeners(listeners, invocationListeners, "invocationListeners");
return this;
}
private static <T> void addListeners(T[] listeners, List<T> container, String method) {
if (listeners == null) {
throw methodDoesNotAcceptParameter(method, "null vararg array.");
}
for (T listener : listeners) {
if (listener == null) {
throw methodDoesNotAcceptParameter(method, "null listeners.");
}
container.add(listener);
}
}
@Override
public MockSettings verificationStartedListeners(VerificationStartedListener... listeners) {
addListeners(listeners, this.verificationStartedListeners, "verificationStartedListeners");
return this;
}
private boolean invocationListenersContainsType(Class<?> clazz) {
for (InvocationListener listener : invocationListeners) {
if (listener.getClass().equals(clazz)) {
return true;
}
}
return false;
}
@Override
public List<InvocationListener> getInvocationListeners() {
return this.invocationListeners;
}
public boolean hasInvocationListeners() {
return !invocationListeners.isEmpty();
}
@Override
public Class<T> getTypeToMock() {
return typeToMock;
}
@Override
public <T> MockCreationSettings<T> build(Class<T> typeToMock) {
return validatedSettings(typeToMock, (CreationSettings<T>) this);
}
@Override
public MockSettings lenient() {
this.lenient = true;
return this;
}
private static <T> CreationSettings<T> validatedSettings(Class<T> typeToMock, CreationSettings<T> source) {
MockCreationValidator validator = new MockCreationValidator();
validator.validateType(typeToMock);
validator.validateExtraInterfaces(typeToMock, source.getExtraInterfaces());
validator.validateMockedType(typeToMock, source.getSpiedInstance());
//TODO SF - add this validation and also add missing coverage
// validator.validateDelegatedInstance(classToMock, settings.getDelegatedInstance());
validator.validateConstructorUse(source.isUsingConstructor(), source.getSerializableMode());
//TODO SF - I don't think we really need CreationSettings type
//TODO do we really need to copy the entire settings every time we create mock object? it does not seem necessary.
CreationSettings<T> settings = new CreationSettings<T>(source);
settings.setMockName(new MockNameImpl(source.getName(), typeToMock));
settings.setTypeToMock(typeToMock);
settings.setExtraInterfaces(prepareExtraInterfaces(source));
return settings;
}
private static Set<Class<?>> prepareExtraInterfaces(CreationSettings settings) {
Set<Class<?>> interfaces = new HashSet<Class<?>>(settings.getExtraInterfaces());
if(settings.isSerializable()) {
interfaces.add(Serializable.class);
}
return interfaces;
}
}