All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
mockit.internal.expectations.ReturnTypeConversion Maven / Gradle / Ivy
Go to download
JMockit is a Java toolkit for automated developer testing.
It contains APIs for the creation of the objects to be tested, for mocking dependencies, and for faking external
APIs; JUnit (4 & 5) and TestNG test runners are supported.
It also contains an advanced code coverage tool.
/*
* Copyright (c) 2006 Rogério Liesenfeld
* This file is subject to the terms of the MIT license (see LICENSE.txt).
*/
package mockit.internal.expectations;
import java.io.*;
import java.lang.reflect.*;
import java.nio.*;
import java.util.*;
import javax.annotation.*;
import mockit.internal.expectations.invocation.*;
import mockit.internal.util.*;
import static mockit.internal.reflection.ConstructorReflection.*;
import static mockit.internal.reflection.MethodReflection.*;
public final class ReturnTypeConversion
{
private static final Class[] STRING = {String.class};
@Nullable private final Expectation expectation;
@Nonnull ExpectedInvocation invocation;
@Nonnull private final Class returnType;
@Nonnull private final Object valueToReturn;
ReturnTypeConversion(@Nonnull Expectation expectation, @Nonnull Class returnType, @Nonnull Object value)
{
this.expectation = expectation;
invocation = expectation.invocation;
this.returnType = returnType;
valueToReturn = value;
}
public ReturnTypeConversion(@Nonnull ExpectedInvocation invocation, @Nonnull Class returnType, @Nonnull Object value)
{
expectation = null;
this.invocation = invocation;
this.returnType = returnType;
valueToReturn = value;
}
@Nonnull
public Object getConvertedValue()
{
Class wrapperType =
AutoBoxing.isWrapperOfPrimitiveType(returnType) ? returnType : AutoBoxing.getWrapperType(returnType);
Class valueType = valueToReturn.getClass();
if (valueType == wrapperType) {
return valueToReturn;
}
if (wrapperType != null && AutoBoxing.isWrapperOfPrimitiveType(valueType)) {
return getPrimitiveValueConvertingAsNeeded(wrapperType);
}
throw newIncompatibleTypesException();
}
void addConvertedValue()
{
Class wrapperType =
AutoBoxing.isWrapperOfPrimitiveType(returnType) ? returnType : AutoBoxing.getWrapperType(returnType);
Class valueType = valueToReturn.getClass();
if (valueType == wrapperType) {
addReturnValue(valueToReturn);
}
else if (wrapperType != null && AutoBoxing.isWrapperOfPrimitiveType(valueType)) {
addPrimitiveValueConvertingAsNeeded(wrapperType);
}
else {
boolean valueIsArray = valueType.isArray();
if (valueIsArray || valueToReturn instanceof Iterable || valueToReturn instanceof Iterator) {
addMultiValuedResultBasedOnTheReturnType(valueIsArray);
}
else if (wrapperType != null) {
throw newIncompatibleTypesException();
}
else {
addResultFromSingleValue();
}
}
}
private void addReturnValue(@Nonnull Object returnValue)
{
getInvocationResults().addReturnValueResult(returnValue);
}
@Nonnull
private InvocationResults getInvocationResults()
{
assert expectation != null;
return expectation.getResults();
}
private void addMultiValuedResultBasedOnTheReturnType(boolean valueIsArray)
{
if (returnType == void.class) {
addMultiValuedResult(valueIsArray);
}
else if (returnType == Object.class) {
addReturnValue(valueToReturn);
}
else if (valueIsArray && addCollectionOrMapWithElementsFromArray()) {
return;
}
else if (hasReturnOfDifferentType()) {
addMultiValuedResult(valueIsArray);
}
else {
addReturnValue(valueToReturn);
}
}
private boolean hasReturnOfDifferentType()
{
return
!returnType.isArray() &&
!Iterable.class.isAssignableFrom(returnType) && !Iterator.class.isAssignableFrom(returnType) &&
!returnType.isAssignableFrom(valueToReturn.getClass());
}
private void addMultiValuedResult(boolean valueIsArray)
{
InvocationResults results = getInvocationResults();
if (valueIsArray) {
results.addResults(valueToReturn);
}
else if (valueToReturn instanceof Iterable) {
results.addResults((Iterable) valueToReturn);
}
else {
results.addDeferredResults((Iterator) valueToReturn);
}
}
private boolean addCollectionOrMapWithElementsFromArray()
{
int n = Array.getLength(valueToReturn);
Object values = null;
if (returnType.isAssignableFrom(ListIterator.class)) {
List list = new ArrayList(n);
addArrayElements(list, n);
values = list.listIterator();
}
else if (returnType.isAssignableFrom(List.class)) {
values = addArrayElements(new ArrayList(n), n);
}
else if (returnType.isAssignableFrom(Set.class)) {
values = addArrayElements(new LinkedHashSet(n), n);
}
else if (returnType.isAssignableFrom(SortedSet.class)) {
values = addArrayElements(new TreeSet(), n);
}
else if (returnType.isAssignableFrom(Map.class)) {
values = addArrayElements(new LinkedHashMap(n), n);
}
else if (returnType.isAssignableFrom(SortedMap.class)) {
values = addArrayElements(new TreeMap(), n);
}
if (values != null) {
getInvocationResults().addReturnValue(values);
return true;
}
return false;
}
@Nonnull
private Object addArrayElements(@Nonnull Collection values, int elementCount)
{
for (int i = 0; i < elementCount; i++) {
Object element = Array.get(valueToReturn, i);
values.add(element);
}
return values;
}
@Nullable
private Object addArrayElements(@Nonnull Map values, int elementPairCount)
{
for (int i = 0; i < elementPairCount; i++) {
Object keyAndValue = Array.get(valueToReturn, i);
if (keyAndValue == null || !keyAndValue.getClass().isArray()) {
return null;
}
Object key = Array.get(keyAndValue, 0);
Object element = Array.getLength(keyAndValue) > 1 ? Array.get(keyAndValue, 1) : null;
values.put(key, element);
}
return values;
}
@Nonnull
private Object getResultFromSingleValue()
{
if (returnType == Object.class) {
return valueToReturn;
}
else if (returnType == void.class) {
throw newIncompatibleTypesException();
}
else if (valueToReturn instanceof CharSequence) {
return getCharSequence((CharSequence) valueToReturn);
}
else {
return getPrimitiveValue();
}
}
private void addResultFromSingleValue()
{
if (returnType == Object.class) {
addReturnValue(valueToReturn);
}
else if (returnType == void.class) {
throw newIncompatibleTypesException();
}
else if (returnType.isArray()) {
addArray();
}
else if (returnType.isAssignableFrom(ArrayList.class)) {
addCollectionWithSingleElement(new ArrayList(1));
}
else if (returnType.isAssignableFrom(LinkedList.class)) {
addCollectionWithSingleElement(new LinkedList());
}
else if (returnType.isAssignableFrom(HashSet.class)) {
addCollectionWithSingleElement(new HashSet(1));
}
else if (returnType.isAssignableFrom(TreeSet.class)) {
addCollectionWithSingleElement(new TreeSet());
}
else if (returnType.isAssignableFrom(ListIterator.class)) {
addListIterator();
}
else if (valueToReturn instanceof CharSequence) {
addCharSequence((CharSequence) valueToReturn);
}
else {
addPrimitiveValue();
}
}
@Nonnull
private IllegalArgumentException newIncompatibleTypesException()
{
String valueTypeName = valueToReturn.getClass().getName().replace("java.lang.", "");
String returnTypeName = returnType.getName().replace("java.lang.", "");
MethodFormatter methodDesc =
new MethodFormatter(invocation.getClassDesc(), invocation.getMethodNameAndDescription());
String msg =
"Value of type " + valueTypeName + " incompatible with return type " + returnTypeName + " of " + methodDesc;
return new IllegalArgumentException(msg);
}
private void addArray()
{
Object array = Array.newInstance(returnType.getComponentType(), 1);
Array.set(array, 0, valueToReturn);
addReturnValue(array);
}
private void addCollectionWithSingleElement(@Nonnull Collection container)
{
container.add(valueToReturn);
addReturnValue(container);
}
private void addListIterator()
{
List l = new ArrayList(1);
l.add(valueToReturn);
ListIterator iterator = l.listIterator();
addReturnValue(iterator);
}
@Nonnull
private Object getCharSequence(@Nonnull CharSequence textualValue)
{
@Nonnull Object convertedValue = textualValue;
if (returnType.isAssignableFrom(ByteArrayInputStream.class)) {
convertedValue = new ByteArrayInputStream(textualValue.toString().getBytes());
}
else if (returnType.isAssignableFrom(StringReader.class)) {
convertedValue = new StringReader(textualValue.toString());
}
else if (!(textualValue instanceof StringBuilder) && returnType.isAssignableFrom(StringBuilder.class)) {
convertedValue = new StringBuilder(textualValue);
}
else if (!(textualValue instanceof CharBuffer) && returnType.isAssignableFrom(CharBuffer.class)) {
convertedValue = CharBuffer.wrap(textualValue);
}
else {
Object valueFromText = newInstanceUsingPublicConstructorIfAvailable(returnType, STRING, textualValue);
if (valueFromText != null) {
convertedValue = valueFromText;
}
}
return convertedValue;
}
private void addCharSequence(@Nonnull CharSequence textualValue)
{
Object convertedValue = getCharSequence(textualValue);
addReturnValue(convertedValue);
}
@Nonnull
private Object getPrimitiveValue()
{
Class primitiveType = AutoBoxing.getPrimitiveType(valueToReturn.getClass());
if (primitiveType != null) {
Class[] parameterType = {primitiveType};
Object convertedValue =
newInstanceUsingPublicConstructorIfAvailable(returnType, parameterType, valueToReturn);
if (convertedValue == null) {
convertedValue = invokePublicIfAvailable(returnType, null, "valueOf", parameterType, valueToReturn);
}
if (convertedValue != null) {
return convertedValue;
}
}
throw newIncompatibleTypesException();
}
private void addPrimitiveValue()
{
Object convertedValue = getPrimitiveValue();
addReturnValue(convertedValue);
}
@Nonnull
private Object getPrimitiveValueConvertingAsNeeded(@Nonnull Class targetType)
{
Object convertedValue = null;
if (valueToReturn instanceof Number) {
convertedValue = convertFromNumber(targetType, (Number) valueToReturn);
}
else if (valueToReturn instanceof Character) {
convertedValue = convertFromChar(targetType, (Character) valueToReturn);
}
if (convertedValue == null) {
throw newIncompatibleTypesException();
}
return convertedValue;
}
private void addPrimitiveValueConvertingAsNeeded(@Nonnull Class targetType)
{
Object convertedValue = getPrimitiveValueConvertingAsNeeded(targetType);
addReturnValue(convertedValue);
}
@Nullable
private static Object convertFromNumber(@Nonnull Class targetType, @Nonnull Number number)
{
if (targetType == Integer.class) {
return number.intValue();
}
if (targetType == Short.class) {
return number.shortValue();
}
if (targetType == Long.class) {
return number.longValue();
}
if (targetType == Byte.class) {
return number.byteValue();
}
if (targetType == Double.class) {
return number.doubleValue();
}
if (targetType == Float.class) {
return number.floatValue();
}
if (targetType == Character.class) {
return (char) number.intValue();
}
return null;
}
@Nullable
private static Object convertFromChar(@Nonnull Class targetType, char c)
{
if (targetType == Integer.class) {
return (int) c;
}
if (targetType == Short.class) {
return (short) c;
}
if (targetType == Long.class) {
return (long) c;
}
if (targetType == Byte.class) {
//noinspection NumericCastThatLosesPrecision
return (byte) c;
}
if (targetType == Double.class) {
return (double) c;
}
if (targetType == Float.class) {
return (float) c;
}
return null;
}
}