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 android.util.Log;
20 
21 import com.android.adservices.shared.testing.concurrency.DeviceSideSyncCallback;
22 import com.android.adservices.shared.testing.concurrency.SyncCallbackFactory;
23 import com.android.adservices.shared.testing.concurrency.SyncCallbackSettings;
24 import com.android.adservices.shared.testing.mockito.MockitoHelper;
25 
26 import org.mockito.invocation.InvocationOnMock;
27 import org.mockito.stubbing.Answer;
28 
29 /**
30  * {@code SyncCallback} to be used when setting Mockito expectations with an {@link Answer}.
31  *
32  * @param <T> return type of the method being "answered".
33  */
34 public final class AnswerSyncCallback<T> extends DeviceSideSyncCallback implements Answer<T> {
35 
36     private static final String TAG = AnswerSyncCallback.class.getSimpleName();
37 
38     @Nullable private final T mAnswer;
39     @Nullable private final Throwable mFailure;
40 
AnswerSyncCallback(T answer, Throwable failure, int numberOfExpectedCalls)41     private AnswerSyncCallback(T answer, Throwable failure, int numberOfExpectedCalls) {
42         this(
43                 answer,
44                 failure,
45                 SyncCallbackFactory.newSettingsBuilder()
46                         .setExpectedNumberCalls(numberOfExpectedCalls)
47                         .build());
48     }
49 
AnswerSyncCallback(T answer, Throwable failure, SyncCallbackSettings settings)50     private AnswerSyncCallback(T answer, Throwable failure, SyncCallbackSettings settings) {
51         super(settings);
52         mAnswer = answer;
53         mFailure = failure;
54     }
55 
56     /**
57      * Convenience method for {@link #forVoidAnswers(SyncCallbackSettings)} using a {@link
58      * SyncCallbackSettings settings} that expects just 1 call.
59      */
forSingleVoidAnswer()60     public static AnswerSyncCallback<Void> forSingleVoidAnswer() {
61         return new AnswerSyncCallback<Void>(
62                 /* answer= */ null, /* failure= */ null, /* numberOfExpectedCalls= */ 1);
63     }
64 
65     /**
66      * Convenience method for {@link #forAnswers(SyncCallbackSettings)} using a {@link
67      * SyncCallbackSettings settings} that expects just 1 call.
68      */
forSingleAnswer(A answer)69     public static <A> AnswerSyncCallback<A> forSingleAnswer(A answer) {
70         return new AnswerSyncCallback<A>(
71                 answer, /* failure= */ null, /* numberOfExpectedCalls= */ 1);
72     }
73 
74     /**
75      * Convenience method for {@link #forVoidAnswers(SyncCallbackSettings)} using a {@link
76      * SyncCallbackSettings settings} that expects {@code numberOfExpectedCalls} calls.
77      */
forMultipleVoidAnswers(int numberOfExpectedCalls)78     public static AnswerSyncCallback<Void> forMultipleVoidAnswers(int numberOfExpectedCalls) {
79         return new AnswerSyncCallback<>(
80                 /* answer= */ null, /* failure= */ null, numberOfExpectedCalls);
81     }
82 
83     /**
84      * Convenience method for {@link #forAnswers(SyncCallbackSettings)} using a {@link
85      * SyncCallbackSettings settings} that expects {@code numberOfExpectedCalls} calls.
86      */
forMultipleAnswers( A answer, int numberOfExpectedCalls)87     public static <A> AnswerSyncCallback<A> forMultipleAnswers(
88             A answer, int numberOfExpectedCalls) {
89         return new AnswerSyncCallback<A>(answer, /* failure= */ null, numberOfExpectedCalls);
90     }
91 
92     /**
93      * Factory method for answers that return {@code Void} and take a generic {@link
94      * SyncCallbackSettings}.
95      */
forVoidAnswers(SyncCallbackSettings settings)96     public static AnswerSyncCallback<Void> forVoidAnswers(SyncCallbackSettings settings) {
97         return new AnswerSyncCallback<>(/* answer= */ null, /* failure= */ null, settings);
98     }
99 
100     /** Factory method for answers that return non-{@code Void}. */
forAnswers(A answer, SyncCallbackSettings settings)101     public static <A> AnswerSyncCallback<A> forAnswers(A answer, SyncCallbackSettings settings) {
102         return new AnswerSyncCallback<A>(answer, /* failure= */ null, settings);
103     }
104 
105     /**
106      * Factory method for {@link Answer}s that should thrown an exception.
107      *
108      * @param clazz type of the object that should be returned by the {@link Answer}
109      * @param failure exception that will be thrown.
110      */
forSingleFailure(Class<A> clazz, Throwable failure)111     public static <A> AnswerSyncCallback<A> forSingleFailure(Class<A> clazz, Throwable failure) {
112         return new AnswerSyncCallback<A>(
113                 /* answer= */ null, failure, /* numberOfExpectedCalls= */ 1);
114     }
115 
116     @Override
answer(InvocationOnMock invocation)117     public T answer(InvocationOnMock invocation) throws Throwable {
118         super.internalSetCalled(MockitoHelper.toString(invocation));
119         if (mFailure != null) {
120             Log.v(TAG, "Throwing '" + mFailure + "' on " + invocation);
121             throw mFailure;
122         }
123         Log.v(TAG, "Answering '" + mAnswer + "' on " + invocation);
124         return mAnswer;
125     }
126 }
127