/* * 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. * *

The argumentIndex represents the index in the argument array of the invocation.

*

If this number equals -1 then the last argument is returned.

* * @see org.mockito.AdditionalAnswers * @since 1.9.5 */ public class ReturnsArgumentAt implements Answer, 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 -1 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(); } } }