001/*
002 * Copyright © 2018. Sir Wellington.
003 * Licensed under the Apache License, Version 2.0 (the "License");
004 * you may not use this file except in compliance with the License.
005 *
006 * You may obtain a copy of the License at
007 *     http://www.apache.org/licenses/LICENSE-2.0
008 *
009 * Unless required by applicable law or agreed to in writing, software
010 * distributed under the License is distributed on an "AS IS" BASIS,
011 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012 * See the License for the specific language governing permissions and
013 * limitations under the License.
014 */
015
016package tech.sirwellington.alchemy.test.mockito;
017
018import org.mockito.invocation.InvocationOnMock;
019import org.mockito.stubbing.Answer;
020import tech.sirwellington.alchemy.annotations.access.NonInstantiable;
021
022import static tech.sirwellington.alchemy.test.Checks.Internal.checkThat;
023
024/**
025 * This class contains a variety of useful answers for use in combination with Mockito.
026 *
027 * @author SirWellington
028 */
029@NonInstantiable
030public final class MoreAnswers
031{
032
033    MoreAnswers() throws IllegalAccessException
034    {
035        throw new IllegalAccessException("cannot instantiate class");
036    }
037
038
039    /**
040     * For example:
041     * <p>
042     * <pre>
043     *
044     * {@code
045     * when(object.call("firstArg", 3)).then(returnFirst());
046     * }
047     * Will return the {@code "firstArg"} string when it is called.
048     * </pre>
049     *
050     * @param <T>
051     * @return
052     * @see #returnArgumentAtIndex(int)
053     */
054    public static <T> Answer<T> returnFirst()
055    {
056        return returnArgumentAtIndex(0);
057    }
058
059    /**
060     * An answer that returns one of the parameters as the return value.
061     * <p>
062     * Example:
063     * <pre>
064     * when(someMock.call(anyString(), anyString()).then(returnArgumentAtIndex(1));
065     *
066     * String result = someMock.call("arg1", "arg2");
067     * assertThat(result, is("arg2"));
068     * </pre>
069     *
070     * @param <T>
071     * @param index zero-based index which determines which parameter to return as an answer.
072     * @return
073     * @see #returnFirst()
074     */
075    public static <T> Answer<T> returnArgumentAtIndex(final int index)
076    {
077        checkThat(index >= 0, "Index is out of bounds.");
078
079        return new Answer<T>()
080        {
081            @Override
082            public T answer(InvocationOnMock invocation) throws Throwable
083            {
084                if (index >= invocation.getArguments().length)
085                {
086                    throw new IllegalArgumentException("Received an index of " + index + " but only " + invocation.getArguments().length + " arguments");
087                }
088
089                return (T) invocation.getArguments()[index];
090            }
091        };
092    }
093}