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 package com.android.adservices.mockito; 17 18 import static org.mockito.ArgumentMatchers.any; 19 import static org.mockito.ArgumentMatchers.anyBoolean; 20 import static org.mockito.ArgumentMatchers.anyInt; 21 import static org.mockito.Mockito.doAnswer; 22 import static org.mockito.Mockito.mock; 23 import static org.mockito.Mockito.when; 24 25 import android.content.Context; 26 27 import com.android.adservices.shared.common.ApplicationContextSingleton; 28 import com.android.adservices.shared.spe.logging.JobServiceLogger; 29 import com.android.adservices.shared.testing.JobServiceLoggingCallback; 30 import com.android.adservices.shared.util.Clock; 31 32 import org.mockito.stubbing.OngoingStubbing; 33 34 import java.util.Arrays; 35 import java.util.Objects; 36 37 /** Implements {@link SharedMocker} using {@code Mockito}. */ 38 public final class SharedMockitoMocker extends AbstractMocker implements SharedMocker { 39 40 @Override setApplicationContextSingleton()41 public Context setApplicationContextSingleton() { 42 Context context = mock(Context.class); 43 logV("setApplicationContextSingleton(): will use %s as appContext", context); 44 45 when(context.getApplicationContext()).thenReturn(context); 46 ApplicationContextSingleton.setForTests(context); 47 48 return context; 49 } 50 51 @Override mockSetApplicationContextSingleton(Context context)52 public void mockSetApplicationContextSingleton(Context context) { 53 Objects.requireNonNull(context, "context cannot be null"); 54 logV("mockSetApplicationContextSingleton(%s)", context); 55 56 ApplicationContextSingleton.setForTests(context); 57 } 58 59 @Override syncRecordOnStopJob(JobServiceLogger logger)60 public JobServiceLoggingCallback syncRecordOnStopJob(JobServiceLogger logger) { 61 JobServiceLoggingCallback callback = new JobServiceLoggingCallback(); 62 63 doAnswer( 64 invocation -> { 65 logV("calling callback %s on %s", callback, invocation); 66 callback.onLoggingMethodCalled(); 67 return null; 68 }) 69 .when(logger) 70 .recordOnStopJob(any(), anyInt(), anyBoolean()); 71 72 return callback; 73 } 74 75 @Override mockCurrentTimeMillis(Clock mockClock, long... mockedValues)76 public void mockCurrentTimeMillis(Clock mockClock, long... mockedValues) { 77 logV("mockCurrentTimeMillis(%s, %s)", mockClock, Arrays.toString(mockedValues)); 78 Objects.requireNonNull(mockClock, "mockClock cannot be null"); 79 Objects.requireNonNull(mockedValues, "mockedValues cannot be null"); 80 81 unflatLongVararg(when(mockClock.currentTimeMillis()), mockedValues); 82 } 83 84 @Override mockElapsedRealtime(Clock mockClock, long... mockedValues)85 public void mockElapsedRealtime(Clock mockClock, long... mockedValues) { 86 logV("mockElapsedRealtime(%s, %s)", mockClock, Arrays.toString(mockedValues)); 87 Objects.requireNonNull(mockClock, "mockClock cannot be null"); 88 Objects.requireNonNull(mockedValues, "mockedValues cannot be null"); 89 90 unflatLongVararg(when(mockClock.elapsedRealtime()), mockedValues); 91 } 92 93 // TODO(b/359358687): Move to MockitoHelper / rename / unit test it 94 95 // Mockito's when() supporting passing a single value or a single value plus a vararg, but the 96 // signature of those methods take a T (object), so they cannot be used with primitive types. 97 // Hence, this method provides a "bridge" between helper methods that take long... and Mockito. unflatLongVararg(OngoingStubbing<Long> mockedMethod, long... mockedValues)98 private static void unflatLongVararg(OngoingStubbing<Long> mockedMethod, long... mockedValues) { 99 Long firstValue = mockedValues[0]; 100 if (mockedValues.length == 1) { 101 mockedMethod.thenReturn(firstValue); 102 return; 103 } 104 105 int remainingLength = mockedValues.length - 1; 106 Long[] remainingValues = new Long[remainingLength]; 107 for (int i = 0; i < remainingLength; i++) { 108 remainingValues[i] = mockedValues[i + 1]; 109 } 110 mockedMethod.thenReturn(firstValue, remainingValues); 111 } 112 } 113