blob: 059074d254441ba0f89636c9b8234117f0a1d4c2 [file] [log] [blame]
/*
* Copyright (c) 2007 Mockito contributors
* This program is made available under the terms of the MIT License.
*/
package org.mockito.internal.stubbing.answers;
import org.mockito.exceptions.Reporter;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import java.io.Serializable;
/**
* Returns the passed parameter identity at specified index.
*
* <p>The <code>argumentIndex</code> represents the index in the argument array of the invocation.</p>
* <p>If this number equals -1 then the last argument is returned.</p>
*
* @see org.mockito.AdditionalAnswers
* @since 1.9.5
*/
public class ReturnsArgumentAt implements Answer<Object>, Serializable {
private static final long serialVersionUID = -589315085166295101L;
public static final int LAST_ARGUMENT = -1;
private final int wantedArgumentPosition;
/**
* Build the identity answer to return the argument at the given position in the argument array.
*
* @param wantedArgumentPosition The position of the argument identity to return in the invocation.
* Using <code>-1</code> indicates the last argument.
*/
public ReturnsArgumentAt(int wantedArgumentPosition) {
this.wantedArgumentPosition = checkWithinAllowedRange(wantedArgumentPosition);
}
public Object answer(InvocationOnMock invocation) throws Throwable {
validateIndexWithinInvocationRange(invocation);
return invocation.getArguments()[actualArgumentPosition(invocation)];
}
private int actualArgumentPosition(InvocationOnMock invocation) {
return returningLastArg() ?
lastArgumentIndexOf(invocation) :
argumentIndexOf(invocation);
}
private boolean returningLastArg() {
return wantedArgumentPosition == LAST_ARGUMENT;
}
private int argumentIndexOf(InvocationOnMock invocation) {
return wantedArgumentPosition;
}
private int lastArgumentIndexOf(InvocationOnMock invocation) {
return invocation.getArguments().length - 1;
}
private int checkWithinAllowedRange(int argumentPosition) {
if (argumentPosition != LAST_ARGUMENT && argumentPosition < 0) {
new Reporter().invalidArgumentRangeAtIdentityAnswerCreationTime();
}
return argumentPosition;
}
public int wantedArgumentPosition() {
return wantedArgumentPosition;
}
public void validateIndexWithinInvocationRange(InvocationOnMock invocation) {
if (!argumentPositionInRange(invocation)) {
new Reporter().invalidArgumentPositionRangeAtInvocationTime(invocation,
returningLastArg(),
wantedArgumentPosition);
}
}
private boolean argumentPositionInRange(InvocationOnMock invocation) {
int actualArgumentPosition = actualArgumentPosition(invocation);
if (actualArgumentPosition < 0) {
return false;
}
if (!invocation.getMethod().isVarArgs()) {
return invocation.getArguments().length > actualArgumentPosition;
}
// for all varargs accepts positive ranges
return true;
}
public Class returnedTypeOnSignature(InvocationOnMock invocation) {
int actualArgumentPosition = actualArgumentPosition(invocation);
if(!invocation.getMethod().isVarArgs()) {
return invocation.getMethod().getParameterTypes()[actualArgumentPosition];
}
Class<?>[] parameterTypes = invocation.getMethod().getParameterTypes();
int varargPosition = parameterTypes.length - 1;
if(actualArgumentPosition < varargPosition) {
return parameterTypes[actualArgumentPosition];
} else {
return parameterTypes[varargPosition].getComponentType();
}
}
}