1 /* 2 * Copyright (C) 2024 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.adservices.shared.testing; 18 19 import com.android.adservices.shared.testing.concurrency.DeviceSideSyncCallback; 20 import com.android.adservices.shared.testing.concurrency.SyncCallbackFactory; 21 import com.android.adservices.shared.testing.concurrency.SyncCallbackSettings; 22 import com.android.adservices.shared.testing.mockito.MockitoHelper; 23 24 import org.mockito.invocation.InvocationOnMock; 25 import org.mockito.stubbing.Answer; 26 27 /** 28 * {@code SyncCallback} to be used when setting Mockito expectations with an {@link Answer}. 29 * 30 * @param <T> return type of the method being "answered". 31 */ 32 public final class AnswerSyncCallback<T> extends DeviceSideSyncCallback implements Answer<T> { 33 34 @Nullable private final T mAnswer; 35 @Nullable private final Throwable mFailure; 36 AnswerSyncCallback(T answer, Throwable failure, int numberOfExpectedCalls)37 private AnswerSyncCallback(T answer, Throwable failure, int numberOfExpectedCalls) { 38 this( 39 answer, 40 failure, 41 SyncCallbackFactory.newSettingsBuilder() 42 .setExpectedNumberCalls(numberOfExpectedCalls) 43 .build()); 44 } 45 AnswerSyncCallback(T answer, Throwable failure, SyncCallbackSettings settings)46 private AnswerSyncCallback(T answer, Throwable failure, SyncCallbackSettings settings) { 47 super(settings); 48 mAnswer = answer; 49 mFailure = failure; 50 } 51 52 /** 53 * Convenience method for {@link #forVoidAnswers(SyncCallbackSettings)} using a {@link 54 * SyncCallbackSettings settings} that expects just 1 call. 55 */ forSingleVoidAnswer()56 public static AnswerSyncCallback<Void> forSingleVoidAnswer() { 57 return new AnswerSyncCallback<Void>( 58 /* answer= */ null, /* failure= */ null, /* numberOfExpectedCalls= */ 1); 59 } 60 61 /** 62 * Convenience method for {@link #forAnswers(SyncCallbackSettings)} using a {@link 63 * SyncCallbackSettings settings} that expects just 1 call. 64 */ forSingleAnswer(A answer)65 public static <A> AnswerSyncCallback<A> forSingleAnswer(A answer) { 66 return new AnswerSyncCallback<A>( 67 answer, /* failure= */ null, /* numberOfExpectedCalls= */ 1); 68 } 69 70 /** 71 * Convenience method for {@link #forVoidAnswers(SyncCallbackSettings)} using a {@link 72 * SyncCallbackSettings settings} that expects {@code numberOfExpectedCalls} calls. 73 */ forMultipleVoidAnswers(int numberOfExpectedCalls)74 public static AnswerSyncCallback<Void> forMultipleVoidAnswers(int numberOfExpectedCalls) { 75 return new AnswerSyncCallback<>( 76 /* answer= */ null, /* failure= */ null, numberOfExpectedCalls); 77 } 78 79 /** 80 * Convenience method for {@link #forAnswers(SyncCallbackSettings)} using a {@link 81 * SyncCallbackSettings settings} that expects {@code numberOfExpectedCalls} calls. 82 */ forMultipleAnswers( A answer, int numberOfExpectedCalls)83 public static <A> AnswerSyncCallback<A> forMultipleAnswers( 84 A answer, int numberOfExpectedCalls) { 85 return new AnswerSyncCallback<A>(answer, /* failure= */ null, numberOfExpectedCalls); 86 } 87 88 /** 89 * Factory method for answers that return {@code Void} and take a generic {@link 90 * SyncCallbackSettings}. 91 */ forVoidAnswers(SyncCallbackSettings settings)92 public static AnswerSyncCallback<Void> forVoidAnswers(SyncCallbackSettings settings) { 93 return new AnswerSyncCallback<>(/* answer= */ null, /* failure= */ null, settings); 94 } 95 96 /** Factory method for answers that return non-{@code Void}. */ forAnswers(A answer, SyncCallbackSettings settings)97 public static <A> AnswerSyncCallback<A> forAnswers(A answer, SyncCallbackSettings settings) { 98 return new AnswerSyncCallback<A>(answer, /* failure= */ null, settings); 99 } 100 101 /** 102 * Factory method for {@link Answer}s that should thrown an exception. 103 * 104 * @param clazz type of the object that should be returned by the {@link Answer} 105 * @param failure exception that will be thrown. 106 */ forSingleFailure(Class<A> clazz, Throwable failure)107 public static <A> AnswerSyncCallback<A> forSingleFailure(Class<A> clazz, Throwable failure) { 108 return new AnswerSyncCallback<A>( 109 /* answer= */ null, failure, /* numberOfExpectedCalls= */ 1); 110 } 111 112 @Override answer(InvocationOnMock invocation)113 public T answer(InvocationOnMock invocation) throws Throwable { 114 String invocationString = MockitoHelper.toString(invocation); 115 super.internalSetCalled("answer(" + invocationString + ")"); 116 if (mFailure != null) { 117 logV("Throwing '%s' on %s", mFailure, invocationString); 118 throw mFailure; 119 } 120 logV("Answering '%s' on %s", mAnswer, invocationString); 121 return mAnswer; 122 } 123 } 124