package spock.mock;
import org.spockframework.mock.MockImplementation;
import org.spockframework.mock.MockNature;
import org.spockframework.mock.MockUtil;
import org.spockframework.util.Beta;
import org.spockframework.util.Nullable;
import spock.lang.Specification;
import java.util.Collections;
import java.util.Map;
/**
* This factory allows the creations of mocks outside of a {@link spock.lang.Specification},
* e.g., in a Spring configuration.
* <p/>
* In order to be usable those Mocks must be manually attached to the {@link spock.lang.Specification}
* using {@link MockUtil#attachMock(Object, Specification)} and detached afterwards {@link MockUtil#detachMock(Object)}.
*/
@Beta
public class DetachedMockFactory implements MockFactory {
/**
* Creates a mock with the specified type. The mock name will be the types simple name.
*
* Example:
*
* <pre>
* def person = Mock(Person) // type is Person.class, name is "person"
* </pre>
*
* @param type the interface or class type of the mock
* @param <T> the interface or class type of the mock
*
* @return a mock with the specified type
*/
@Override
public <T> T Mock(Class<T> type) {
return createMock(inferNameFromType(type), type, MockNature.MOCK, Collections.<String, Object>emptyMap());
}
/**
* Creates a mock with the specified options and type. The mock name will be the types simple name.
*
* Example:
*
* <pre>
* def person = Mock(Person, name: "myPerson") // type is Person.class, name is "myPerson"
* </pre>
*
* @param options optional options for creating the mock
* @param type the interface or class type of the mock
* @param <T> the interface or class type of the mock
*
* @return a mock with the specified options and type
*/
@Override
public <T> T Mock(Map<String, Object> options, Class<T> type) {
return createMock(inferNameFromType(type), type, MockNature.MOCK, options);
}
/**
* Creates a stub with the specified type. The mock name will be the types simple name.
*
* Example:
*
* <pre>
* def person = Stub(Person) // type is Person.class, name is "person"
* </pre>
*
* @param type the interface or class type of the stub
* @param <T> the interface or class type of the stub
*
* @return a stub with the specified type
*/
@Override
public <T> T Stub(Class<T> type) {
return createMock(inferNameFromType(type), type, MockNature.STUB, Collections.<String, Object>emptyMap());
}
/**
* Creates a stub with the specified options and type. The mock name will be the types simple name.
*
* Example:
*
* <pre>
* def person = Stub(Person, name: "myPerson") // type is Person.class, name is "myPerson"
* </pre>
*
* @param options optional options for creating the stub
* @param type the interface or class type of the stub
* @param <T> the interface or class type of the stub
*
* @return a stub with the specified options and type
*/
@Override
public <T> T Stub(Map<String, Object> options, Class<T> type) {
return createMock(inferNameFromType(type), type, MockNature.STUB, options);
}
/**
* Creates a spy with the specified type. The mock name will be the types simple name.
*
* Example:
*
* <pre>
* def person = Spy(Person) // type is Person.class, name is "person"
* </pre>
*
* @param type the class type of the spy
* @param <T> the class type of the spy
*
* @return a spy with the specified type
*/
@Override
public <T> T Spy(Class<T> type) {
return createMock(inferNameFromType(type), type, MockNature.SPY, Collections.<String, Object>emptyMap());
}
@Override
public <T> T Spy(T obj) {
return createMock(inferNameFromType(obj.getClass()), obj, MockNature.SPY, Collections.<String, Object>emptyMap());
}
/**
* Creates a spy with the specified options and type. The mock name will be the types simple name.
*
* Example:
*
* <pre>
* def person = Spy(Person, name: "myPerson") // type is Person.class, name is "myPerson"
* </pre>
*
* @param options optional options for creating the spy
* @param type the class type of the spy
* @param <T> the class type of the spy
*
* @return a spy with the specified options and type
*/
@Override
public <T> T Spy(Map<String, Object> options, Class<T> type) {
return createMock(inferNameFromType(type), type, MockNature.SPY, options);
}
@SuppressWarnings("unchecked")
public <T> T createMock(@Nullable String name, Class<T> type, MockNature nature, Map<String, Object> options) {
ClassLoader classLoader = type.getClassLoader();
if (classLoader == null) {
classLoader = ClassLoader.getSystemClassLoader();
}
return (T) new MockUtil().createDetachedMock(name, type, nature, MockImplementation.JAVA, options, classLoader);
}
@SuppressWarnings("unchecked")
public <T> T createMock(@Nullable String name, T obj, MockNature nature, Map<String, Object> options) {
ClassLoader classLoader = obj.getClass().getClassLoader();
if (classLoader == null) {
classLoader = ClassLoader.getSystemClassLoader();
}
return (T) new MockUtil().createDetachedMock(name, obj, nature, MockImplementation.JAVA, options, classLoader);
}
private String inferNameFromType(Class<?> type) {
return type.getSimpleName();
}
}