Home | History | Annotate | Download | only in answers
      1 /*
      2  * Copyright (c) 2007 Mockito contributors
      3  * This program is made available under the terms of the MIT License.
      4  */
      5 package org.mockito.internal.stubbing.answers;
      6 
      7 import org.mockito.exceptions.Reporter;
      8 import org.mockito.invocation.InvocationOnMock;
      9 import org.mockito.stubbing.Answer;
     10 
     11 import java.io.Serializable;
     12 
     13 /**
     14  * Returns the passed parameter identity at specified index.
     15  *
     16  * <p>The <code>argumentIndex</code> represents the index in the argument array of the invocation.</p>
     17  * <p>If this number equals -1 then the last argument is returned.</p>
     18  *
     19  * @see org.mockito.AdditionalAnswers
     20  * @since 1.9.5
     21  */
     22 public class ReturnsArgumentAt implements Answer<Object>, Serializable {
     23 
     24     private static final long serialVersionUID = -589315085166295101L;
     25 
     26     public static final int LAST_ARGUMENT = -1;
     27 
     28     private final int wantedArgumentPosition;
     29 
     30     /**
     31      * Build the identity answer to return the argument at the given position in the argument array.
     32      *
     33      * @param wantedArgumentPosition The position of the argument identity to return in the invocation.
     34      *                      Using <code>-1</code> indicates the last argument.
     35      */
     36     public ReturnsArgumentAt(int wantedArgumentPosition) {
     37         this.wantedArgumentPosition = checkWithinAllowedRange(wantedArgumentPosition);
     38     }
     39 
     40     public Object answer(InvocationOnMock invocation) throws Throwable {
     41         validateIndexWithinInvocationRange(invocation);
     42         return invocation.getArguments()[actualArgumentPosition(invocation)];
     43     }
     44 
     45 
     46     private int actualArgumentPosition(InvocationOnMock invocation) {
     47         return returningLastArg() ?
     48                 lastArgumentIndexOf(invocation) :
     49                 argumentIndexOf(invocation);
     50     }
     51 
     52     private boolean returningLastArg() {
     53         return wantedArgumentPosition == LAST_ARGUMENT;
     54     }
     55 
     56     private int argumentIndexOf(InvocationOnMock invocation) {
     57         return wantedArgumentPosition;
     58     }
     59 
     60     private int lastArgumentIndexOf(InvocationOnMock invocation) {
     61         return invocation.getArguments().length - 1;
     62     }
     63 
     64     private int checkWithinAllowedRange(int argumentPosition) {
     65         if (argumentPosition != LAST_ARGUMENT && argumentPosition < 0) {
     66             new Reporter().invalidArgumentRangeAtIdentityAnswerCreationTime();
     67         }
     68         return argumentPosition;
     69     }
     70 
     71     public int wantedArgumentPosition() {
     72         return wantedArgumentPosition;
     73     }
     74 
     75     public void validateIndexWithinInvocationRange(InvocationOnMock invocation) {
     76         if (!argumentPositionInRange(invocation)) {
     77             new Reporter().invalidArgumentPositionRangeAtInvocationTime(invocation,
     78                                                                         returningLastArg(),
     79                                                                         wantedArgumentPosition);
     80         }
     81     }
     82 
     83     private boolean argumentPositionInRange(InvocationOnMock invocation) {
     84         int actualArgumentPosition = actualArgumentPosition(invocation);
     85         if (actualArgumentPosition < 0) {
     86             return false;
     87         }
     88         if (!invocation.getMethod().isVarArgs()) {
     89             return invocation.getArguments().length > actualArgumentPosition;
     90         }
     91         // for all varargs accepts positive ranges
     92         return true;
     93     }
     94 
     95     public Class returnedTypeOnSignature(InvocationOnMock invocation) {
     96         int actualArgumentPosition = actualArgumentPosition(invocation);
     97 
     98         if(!invocation.getMethod().isVarArgs()) {
     99             return invocation.getMethod().getParameterTypes()[actualArgumentPosition];
    100         }
    101 
    102         Class<?>[] parameterTypes = invocation.getMethod().getParameterTypes();
    103         int varargPosition = parameterTypes.length - 1;
    104 
    105         if(actualArgumentPosition < varargPosition) {
    106             return parameterTypes[actualArgumentPosition];
    107         } else {
    108             return parameterTypes[varargPosition].getComponentType();
    109         }
    110     }
    111 }
    112