1 /* 2 * Copyright (C) 2023 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.mockito; 18 19 import static com.android.adservices.mockito.ExtendedMockitoInlineCleanerRule.shouldClearInlineMocksAfterTest; 20 import static com.android.adservices.shared.testing.TestHelper.getAnnotation; 21 22 import android.util.Log; 23 24 import com.android.adservices.mockito.ExtendedMockitoInlineCleanerRule.ClearInlineMocksMode; 25 import com.android.adservices.shared.testing.TestHelper; 26 import com.android.modules.utils.testing.AbstractExtendedMockitoRule; 27 import com.android.modules.utils.testing.StaticMockFixture; 28 29 import com.google.common.collect.ImmutableSet; 30 31 import org.junit.runner.Description; 32 import org.junit.runners.model.Statement; 33 34 import java.util.HashSet; 35 import java.util.Set; 36 import java.util.function.Supplier; 37 38 // TODO(b/338132355): move to shared.common package and rename to just ExtendedMockitoRule 39 40 // NOTE: javadoc below copied mostly as-is from ExtendedMockitoRule 41 /** 42 * Rule to make it easier to use Extended Mockito: 43 * 44 * <ul> 45 * <li>Automatically creates and finishes the mock session. 46 * <li>Provides multiple ways to set which classes must be statically mocked or spied 47 * <li>Automatically starts mocking (so tests don't need a mockito runner or rule) 48 * <li>Automatically clears the inlined mocks at the end (to avoid OOM) 49 * <li>Allows other customization like strictness 50 * </ul> 51 * 52 * <p>Typical usage: 53 * 54 * <pre class="prettyprint"> 55 * @Rule 56 * public final AdServicesExtendedMockitoRule extendedMockito = 57 * new AdServicesExtendedMockitoRule.Builder(this) 58 * .spyStatic(SomeClassWithStaticMethodsToBeMocked) 59 * .build(); 60 * </pre> 61 */ 62 public final class AdServicesExtendedMockitoRule 63 extends AbstractExtendedMockitoRule< 64 AdServicesExtendedMockitoRule, AdServicesExtendedMockitoRule.Builder> 65 implements StaticClassChecker { 66 67 private static final String TAG = AdServicesExtendedMockitoRule.class.getSimpleName(); 68 69 private final Set<Class<?>> mSpiedOrMockedStaticClasses = new HashSet<>(); 70 71 private String mTestName = DEFAULT_TEST_NAME; 72 AdServicesExtendedMockitoRule(Builder builder)73 public AdServicesExtendedMockitoRule(Builder builder) { 74 super(builder); 75 } 76 77 @SafeVarargs AdServicesExtendedMockitoRule(Supplier<? extends StaticMockFixture>.... suppliers)78 public AdServicesExtendedMockitoRule(Supplier<? extends StaticMockFixture>... suppliers) { 79 super(new Builder().addStaticMockFixtures(suppliers)); 80 } 81 82 @Override getTestName()83 public final String getTestName() { 84 return mTestName; 85 } 86 87 // Overridden to get test name 88 @Override apply(Statement base, Description description)89 public final Statement apply(Statement base, Description description) { 90 Statement realStatement = super.apply(base, description); 91 return new Statement() { 92 93 @Override 94 public void evaluate() throws Throwable { 95 mTestName = TestHelper.getTestName(description); 96 try { 97 realStatement.evaluate(); 98 } finally { 99 mTestName = DEFAULT_TEST_NAME; 100 } 101 } 102 }; 103 } 104 105 @Override 106 protected final Set<Class<?>> getSpiedStaticClasses(Description description) { 107 Set<Class<?>> spiedStaticClasses = super.getSpiedStaticClasses(description); 108 mSpiedOrMockedStaticClasses.addAll(spiedStaticClasses); 109 return spiedStaticClasses; 110 } 111 112 @Override 113 protected final Set<Class<?>> getMockedStaticClasses(Description description) { 114 Set<Class<?>> mockedStaticClasses = super.getMockedStaticClasses(description); 115 mSpiedOrMockedStaticClasses.addAll(mockedStaticClasses); 116 return mockedStaticClasses; 117 } 118 119 @Override 120 protected final boolean getClearInlineMethodsAtTheEnd(Description description) { 121 ClearInlineMocksMode annotation = getAnnotation(description, ClearInlineMocksMode.class); 122 if (annotation != null) { 123 boolean shouldClear = shouldClearInlineMocksAfterTest(description, annotation.value()); 124 Log.d( 125 TAG, 126 "getClearInlineMethodsAtTheEnd(): returning value based on annotation (" 127 + shouldClear 128 + ") for " 129 + TestHelper.getTestName(description)); 130 return shouldClear; 131 } 132 return super.getClearInlineMethodsAtTheEnd(description); 133 } 134 135 @Override 136 public ImmutableSet<Class<?>> getSpiedOrMockedClasses() { 137 return ImmutableSet.copyOf(mSpiedOrMockedStaticClasses); 138 } 139 140 @Override 141 public boolean isSpiedOrMocked(Class<?> clazz) { 142 return mSpiedOrMockedStaticClasses.contains(clazz); 143 } 144 145 @Override 146 public String toString() { 147 return "[" 148 + getClass().getSimpleName() 149 + ": spying / mocking on " 150 + mSpiedOrMockedStaticClasses.size() 151 + " classes: " 152 + mSpiedOrMockedStaticClasses 153 + "]"; 154 } 155 156 public static final class Builder 157 extends AbstractBuilder<AdServicesExtendedMockitoRule, Builder> { 158 159 public Builder() { 160 super(); 161 } 162 163 public Builder(Object testClassInstance) { 164 super(testClassInstance); 165 } 166 167 @Override 168 public AdServicesExtendedMockitoRule build() { 169 return new AdServicesExtendedMockitoRule(this); 170 } 171 } 172 } 173