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 package com.android.modules.utils.testing;
17 
18 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
19 
20 import static com.google.common.truth.Truth.assertWithMessage;
21 
22 import static org.junit.Assert.assertThrows;
23 import static org.mockito.ArgumentMatchers.any;
24 import static org.mockito.ArgumentMatchers.notNull;
25 import static org.mockito.Mockito.doThrow;
26 import static org.mockito.Mockito.inOrder;
27 import static org.mockito.Mockito.verify;
28 import static org.mockito.Mockito.when;
29 
30 import android.util.Log;
31 
32 import androidx.annotation.Nullable;
33 
34 import com.android.modules.utils.testing.ExtendedMockitoRule.MockStatic;
35 import com.android.modules.utils.testing.ExtendedMockitoRule.SpyStatic;
36 
37 import org.junit.Test;
38 import org.junit.runner.Description;
39 import org.junit.runner.RunWith;
40 import org.junit.runners.model.Statement;
41 import org.mockito.InOrder;
42 import org.mockito.Mock;
43 import org.mockito.MockitoFramework;
44 import org.mockito.MockitoSession;
45 import org.mockito.exceptions.misusing.UnnecessaryStubbingException;
46 import org.mockito.invocation.InvocationFactory;
47 import org.mockito.junit.MockitoJUnitRunner;
48 import org.mockito.listeners.MockitoListener;
49 import org.mockito.plugins.MockitoPlugins;
50 import org.mockito.quality.Strictness;
51 
52 import java.lang.annotation.Annotation;
53 import java.util.Collection;
54 import java.util.Objects;
55 import java.util.Set;
56 import java.util.function.Supplier;
57 
58 @RunWith(MockitoJUnitRunner.class)
59 public final class ExtendedMockitoRuleTest {
60 
61     public static final String TAG = ExtendedMockitoRuleTest.class.getSimpleName();
62 
63     // Not a real test (i.e., it doesn't exist on this class), but it's passed to Description
64     private static final String TEST_METHOD_BEING_EXECUTED = "testAmI..OrNot";
65 
66     private @Mock Statement mStatement;
67     private @Mock Runnable mRunnable;
68     private @Mock StaticMockFixture mStaticMockFixture1;
69     private @Mock StaticMockFixture mStaticMockFixture2;
70     private @Mock StaticMockFixture mStaticMockFixture3;
71 
72     private final Description mDescription = newTestMethod();
73     private final ClassUnderTest mClassUnderTest = new ClassUnderTest();
74     private final ExtendedMockitoRule.Builder mBuilder =
75             new ExtendedMockitoRule.Builder(mClassUnderTest);
76     // Builder that doesn't clear inline methods at the end - should be used in methods that
77     // need to verify mocks
78     private final ExtendedMockitoRule.Builder mUnsafeBuilder =
79             new ExtendedMockitoRule.Builder(mClassUnderTest).dontClearInlineMocks();
80 
81     private final Supplier<StaticMockFixture> mSupplier1 = () -> {
82         return mStaticMockFixture1;
83     };
84     private final Supplier<StaticMockFixture> mSupplier2 = () -> {
85         return mStaticMockFixture2;
86     };
87     private final Supplier<StaticMockFixture> mSupplier3 = () -> {
88         return mStaticMockFixture3;
89     };
90 
91     @Test
testBuilder_constructor_null()92     public void testBuilder_constructor_null() {
93         assertThrows(NullPointerException.class, () -> new ExtendedMockitoRule.Builder(null));
94     }
95 
96     @Test
testBuilder_setStrictness_null()97     public void testBuilder_setStrictness_null() {
98         assertThrows(NullPointerException.class, () -> mBuilder.setStrictness(null));
99     }
100 
101     @Test
testBuilder_mockStatic_null()102     public void testBuilder_mockStatic_null() {
103         assertThrows(NullPointerException.class, () -> mBuilder.mockStatic(null));
104     }
105 
106     @Test
testBuilder_spyStatic_null()107     public void testBuilder_spyStatic_null() {
108         assertThrows(NullPointerException.class, () -> mBuilder.spyStatic(null));
109     }
110 
111     @Test
testBuilder_addStaticMockFixtures_null()112     public void testBuilder_addStaticMockFixtures_null() {
113         assertThrows(NullPointerException.class,
114                 () -> mBuilder.addStaticMockFixtures((Supplier<StaticMockFixture>) null));
115     }
116 
117     @Test
testBuilder_afterSessionFinished_null()118     public void testBuilder_afterSessionFinished_null() {
119         assertThrows(NullPointerException.class, () -> mBuilder.afterSessionFinished(null));
120     }
121 
122     @Test
testBuilder_setMockitoFrameworkForTesting_null()123     public void testBuilder_setMockitoFrameworkForTesting_null() {
124         assertThrows(NullPointerException.class,
125                 () -> mBuilder.setMockitoFrameworkForTesting(null));
126     }
127 
128     @Test
testBuilder_setMockitoSessionForTesting_null()129     public void testBuilder_setMockitoSessionForTesting_null() {
130         assertThrows(NullPointerException.class,
131                 () -> mBuilder.setMockitoSessionForTesting(null));
132     }
133 
134     @Test
testMocksInitialized()135     public void testMocksInitialized() throws Throwable {
136         mBuilder.build().apply(mStatement, mDescription).evaluate();
137 
138         assertWithMessage("@Mock object").that(mClassUnderTest.mMock).isNotNull();
139     }
140 
141     @Test
testMocksNotInitialized()142     public void testMocksNotInitialized() throws Throwable {
143         new ExtendedMockitoRule.Builder().build().apply(mStatement, mDescription).evaluate();
144 
145         assertWithMessage("@Mock object").that(mClassUnderTest.mMock).isNull();
146     }
147 
148     @Test
testStrictness_lenientByDefault()149     public void testStrictness_lenientByDefault() throws Throwable {
150         applyRuleOnTestThatDoesntUseExpectation(/* strictness= */ null);
151     }
152 
153     @Test
testStrictness_lenient()154     public void testStrictness_lenient() throws Throwable {
155         applyRuleOnTestThatDoesntUseExpectation(Strictness.LENIENT);
156     }
157 
158     @Test
testStrictness_warn()159     public void testStrictness_warn() throws Throwable {
160         applyRuleOnTestThatDoesntUseExpectation(Strictness.WARN);
161     }
162 
163     @Test
testStrictness_strict()164     public void testStrictness_strict() throws Throwable {
165         assertThrows(UnnecessaryStubbingException.class,
166                 () -> applyRuleOnTestThatDoesntUseExpectation(Strictness.STRICT_STUBS));
167     }
168 
169     @Test
testMocksStatic()170     public void testMocksStatic() throws Throwable {
171         ExtendedMockitoRule rule = mBuilder.mockStatic(StaticClass.class).build();
172         rule.apply(new Statement() {
173             @Override
174             public void evaluate() throws Throwable {
175                 doReturn("mocko()").when(() -> StaticClass.marco());
176 
177                 assertWithMessage("StaticClass.marco()")
178                         .that(StaticClass.marco()).isEqualTo("mocko()");
179                 assertWithMessage("StaticClass.water()")
180                         .that(StaticClass.water()).isNull(); // not mocked
181             }
182         }, mDescription).evaluate();
183 
184         Set<Class<?>> mockedClasses = rule.getMockedStaticClasses(mDescription);
185         assertWithMessage("rule.getMockedStaticClasses()").that(mockedClasses)
186                 .containsExactly(StaticClass.class);
187         assertThrows(RuntimeException.class,
188                 () -> mockedClasses.add(ExtendedMockitoRuleTest.class));
189     }
190 
191     @Test
testMockStatic_sameClass()192     public void testMockStatic_sameClass() throws Throwable {
193         mBuilder.mockStatic(StaticClass.class);
194 
195         assertThrows(IllegalStateException.class, () -> mBuilder.mockStatic(StaticClass.class));
196     }
197 
198     @Test
testMocksStatic_multipleClasses()199     public void testMocksStatic_multipleClasses() throws Throwable {
200         ExtendedMockitoRule rule = mBuilder.mockStatic(StaticClass.class)
201                 .mockStatic(AnotherStaticClass.class).build();
202         rule.apply(new Statement() {
203             @Override
204             public void evaluate() throws Throwable {
205                 doReturn("mocko()").when(() -> StaticClass.marco());
206                 doReturn("MOCKO()").when(() -> AnotherStaticClass.marco());
207 
208                 assertWithMessage("StaticClass.marco()")
209                         .that(StaticClass.marco()).isEqualTo("mocko()");
210                 assertWithMessage("StaticClass.water()")
211                         .that(StaticClass.water()).isNull(); // not mocked
212 
213                 assertWithMessage("AnotherStaticClass.marco()")
214                         .that(AnotherStaticClass.marco()).isEqualTo("MOCKO()");
215                 assertWithMessage("AnotherStaticClass.water()")
216                         .that(AnotherStaticClass.water()).isNull(); // not mocked
217             }
218         }, mDescription).evaluate();
219 
220         Set<Class<?>> mockedClasses = rule.getMockedStaticClasses(mDescription);
221         assertWithMessage("rule.getMockedStaticClasses()").that(mockedClasses)
222                 .containsExactly(StaticClass.class, AnotherStaticClass.class);
223         assertThrows(RuntimeException.class,
224                 () -> mockedClasses.add(ExtendedMockitoRuleTest.class));
225     }
226 
227     @Test
testMockStatic_ruleAndAnnotation()228     public void testMockStatic_ruleAndAnnotation() throws Throwable {
229         ExtendedMockitoRule rule = mBuilder.mockStatic(StaticClass.class).build();
230 
231         rule.apply(new Statement() {
232             @Override
233             public void evaluate() throws Throwable {
234                 doReturn("mocko()").when(() -> StaticClass.marco());
235                 doReturn("MOCKO()").when(() -> AnotherStaticClass.marco());
236 
237                 assertWithMessage("StaticClass.marco()")
238                         .that(StaticClass.marco()).isEqualTo("mocko()");
239                 assertWithMessage("StaticClass.water()")
240                         .that(StaticClass.water()).isNull(); // not mocked
241 
242                 assertWithMessage("AnotherStaticClass.marco()")
243                         .that(AnotherStaticClass.marco()).isEqualTo("MOCKO()");
244                 assertWithMessage("AnotherStaticClass.water()")
245                         .that(AnotherStaticClass.water()).isNull(); // not mocked
246             }
247         }, newTestMethod(new MockStaticAnnotation(AnotherStaticClass.class))).evaluate();
248     }
249 
250     // Ideally, we should test the annotations indirectly (i.e., by asserting their static classes
251     // are properly mocked, but pragmatically speaking, testing the getSpiedStatic() is enough - and
252     // much simpler
253     @Test
testMockStatic_fromEverywhere()254     public void testMockStatic_fromEverywhere() throws Throwable {
255         ExtendedMockitoRule rule = mBuilder.mockStatic(StaticClass.class).build();
256 
257         Set<Class<?>> mockedClasses = rule.getMockedStaticClasses(newTestMethod(SubClass.class,
258                 new MockStaticAnnotation(AnotherStaticClass.class)));
259 
260         assertWithMessage("rule.getMockedStaticClasses()").that(mockedClasses).containsExactly(
261                 StaticClass.class, AnotherStaticClass.class, StaticClassMockedBySuperClass.class,
262                 AnotherStaticClassMockedBySuperClass.class, StaticClassMockedBySubClass.class,
263                 AnotherStaticClassMockedBySubClass.class);
264         assertThrows(RuntimeException.class,
265                 () -> mockedClasses.add(ExtendedMockitoRuleTest.class));
266     }
267 
268     @Test
testSpyStatic()269     public void testSpyStatic() throws Throwable {
270         ExtendedMockitoRule rule = mBuilder.spyStatic(StaticClass.class).build();
271 
272         rule.apply(new Statement() {
273             @Override
274             public void evaluate() throws Throwable {
275                 doReturn("mocko()").when(() -> StaticClass.marco());
276 
277                 assertWithMessage("StaticClass.marco()")
278                         .that(StaticClass.marco()).isEqualTo("mocko()");
279                 assertWithMessage("StaticClass.water()")
280                         .that(StaticClass.water()).isEqualTo("polo");
281             }
282         }, mDescription).evaluate();
283 
284         Set<Class<?>> spiedClasses = rule.getSpiedStaticClasses(mDescription);
285         assertWithMessage("rule.getSpiedStaticClasses()").that(spiedClasses)
286                 .containsExactly(StaticClass.class);
287         assertThrows(RuntimeException.class, () -> spiedClasses.add(ExtendedMockitoRuleTest.class));
288     }
289 
290     @Test
testSpyStatic_sameClass()291     public void testSpyStatic_sameClass() throws Throwable {
292         mBuilder.spyStatic(StaticClass.class);
293 
294         assertThrows(IllegalStateException.class, () -> mBuilder.spyStatic(StaticClass.class));
295     }
296 
297     @Test
testSpyStatic_multipleClasses()298     public void testSpyStatic_multipleClasses() throws Throwable {
299         ExtendedMockitoRule rule = mBuilder.spyStatic(StaticClass.class)
300                 .spyStatic(AnotherStaticClass.class).build();
301 
302         rule.apply(new Statement() {
303                     @Override
304                     public void evaluate() throws Throwable {
305                         doReturn("mocko()").when(() -> StaticClass.marco());
306                         doReturn("MOCKO()").when(() -> AnotherStaticClass.marco());
307 
308                         assertWithMessage("StaticClass.marco()")
309                                 .that(StaticClass.marco()).isEqualTo("mocko()");
310                         assertWithMessage("StaticClass.water()")
311                                 .that(StaticClass.water()).isEqualTo("polo");
312 
313                         assertWithMessage("AnotherStaticClass.marco()")
314                                 .that(AnotherStaticClass.marco()).isEqualTo("MOCKO()");
315                         assertWithMessage("AnotherStaticClass.water()")
316                                 .that(AnotherStaticClass.water()).isEqualTo("POLO");
317                     }
318                 }, mDescription).evaluate();
319 
320         Set<Class<?>> spiedClasses = rule.getSpiedStaticClasses(mDescription);
321         assertWithMessage("rule.getSpiedStaticClasses()").that(spiedClasses)
322                 .containsExactly(StaticClass.class, AnotherStaticClass.class);
323         assertThrows(RuntimeException.class, () -> spiedClasses.add(ExtendedMockitoRuleTest.class));
324     }
325 
326     @Test
testSpyStatic_ruleAndAnnotation()327     public void testSpyStatic_ruleAndAnnotation() throws Throwable {
328         ExtendedMockitoRule rule = mBuilder.spyStatic(StaticClass.class).build();
329         rule.apply(new Statement() {
330             @Override
331             public void evaluate() throws Throwable {
332                 doReturn("mocko()").when(() -> StaticClass.marco());
333                 doReturn("MOCKO()").when(() -> AnotherStaticClass.marco());
334 
335                 assertWithMessage("StaticClass.marco()")
336                         .that(StaticClass.marco()).isEqualTo("mocko()");
337                 assertWithMessage("StaticClass.water()")
338                         .that(StaticClass.water()).isEqualTo("polo");
339 
340                 assertWithMessage("AnotherStaticClass.marco()")
341                         .that(AnotherStaticClass.marco()).isEqualTo("MOCKO()");
342                 assertWithMessage("AnotherStaticClass.water()")
343                         .that(AnotherStaticClass.water()).isEqualTo("POLO");
344             }
345         }, newTestMethod(new SpyStaticAnnotation(AnotherStaticClass.class))).evaluate();
346     }
347 
348     // Ideally, we should test the annotations indirectly (i.e., by asserting their static classes
349     // are properly spied, but pragmatically speaking, testing the getSpiedStatic() is enough - and
350     // much simpler
351     @Test
testSpyStatic_fromEverywhere()352     public void testSpyStatic_fromEverywhere() throws Throwable {
353         ExtendedMockitoRule rule = mBuilder.spyStatic(StaticClass.class).build();
354 
355         Set<Class<?>> spiedClasses = rule.getSpiedStaticClasses(newTestMethod(SubClass.class,
356                 new SpyStaticAnnotation(AnotherStaticClass.class)));
357 
358         assertWithMessage("rule.getSpiedStaticClasses()").that(spiedClasses).containsExactly(
359                 StaticClass.class, AnotherStaticClass.class, StaticClassSpiedBySuperClass.class,
360                 AnotherStaticClassSpiedBySuperClass.class, StaticClassSpiedBySubClass.class,
361                 AnotherStaticClassSpiedBySubClass.class);
362         assertThrows(RuntimeException.class, () -> spiedClasses.add(ExtendedMockitoRuleTest.class));
363     }
364 
365     @Test
testMockAndSpyStatic()366     public void testMockAndSpyStatic() throws Throwable {
367         ExtendedMockitoRule rule = mBuilder.mockStatic(StaticClass.class)
368                 .spyStatic(AnotherStaticClass.class).build();
369 
370         rule.apply(new Statement() {
371                     @Override
372                     public void evaluate() throws Throwable {
373                         doReturn("mocko()").when(() -> StaticClass.marco());
374                         doReturn("MOCKO()").when(() -> AnotherStaticClass.marco());
375 
376                         assertWithMessage("StaticClass.marco()")
377                                 .that(StaticClass.marco()).isEqualTo("mocko()");
378                         assertWithMessage("StaticClass.water()")
379                                 .that(StaticClass.water()).isNull(); // not mocked
380 
381                         assertWithMessage("AnotherStaticClass.marco()")
382                                 .that(AnotherStaticClass.marco()).isEqualTo("MOCKO()");
383                         assertWithMessage("AnotherStaticClass.water()")
384                                 .that(AnotherStaticClass.water()).isEqualTo("POLO");
385                     }
386                 }, mDescription).evaluate();
387 
388         Set<Class<?>> spiedStaticClasses = rule.getSpiedStaticClasses(mDescription);
389         assertWithMessage("rule.getSpiedStaticClasses()").that(spiedStaticClasses)
390                 .containsExactly(AnotherStaticClass.class);
391         assertThrows(RuntimeException.class,
392                 () -> spiedStaticClasses.add(ExtendedMockitoRuleTest.class));
393 
394         Set<Class<?>> mockedStaticClasses = rule.getMockedStaticClasses(mDescription);
395         assertWithMessage("rule.getMockedStaticClasses()").that(mockedStaticClasses)
396                 .containsExactly(StaticClass.class);
397         assertThrows(RuntimeException.class,
398                 () -> mockedStaticClasses.add(ExtendedMockitoRuleTest.class));
399     }
400 
401     @Test
testMockAndSpyStatic_sameClass()402     public void testMockAndSpyStatic_sameClass() throws Throwable {
403         mBuilder.mockStatic(StaticClass.class);
404 
405         assertThrows(IllegalStateException.class, () -> mBuilder.spyStatic(StaticClass.class));
406     }
407 
408     @Test
testSpyAndMockStatic_sameClass()409     public void testSpyAndMockStatic_sameClass() throws Throwable {
410         mBuilder.spyStatic(StaticClass.class);
411 
412         assertThrows(IllegalStateException.class, () -> mBuilder.mockStatic(StaticClass.class));
413     }
414 
415     @Test
testAddStaticMockFixtures_once()416     public void testAddStaticMockFixtures_once() throws Throwable {
417         InOrder inOrder = inOrder(mStaticMockFixture1, mStaticMockFixture2);
418 
419         mUnsafeBuilder
420                 .addStaticMockFixtures(mSupplier1, mSupplier2)
421                 .build().apply(mStatement, mDescription).evaluate();
422 
423         inOrder.verify(mStaticMockFixture1).setUpMockedClasses(any());
424         inOrder.verify(mStaticMockFixture2).setUpMockedClasses(any());
425 
426         inOrder.verify(mStaticMockFixture1).setUpMockBehaviors();
427         inOrder.verify(mStaticMockFixture2).setUpMockBehaviors();
428 
429         inOrder.verify(mStaticMockFixture2).tearDown();
430         inOrder.verify(mStaticMockFixture1).tearDown();
431     }
432 
433     @Test
testAddStaticMockFixtures_twice()434     public void testAddStaticMockFixtures_twice() throws Throwable {
435         InOrder inOrder = inOrder(mStaticMockFixture1, mStaticMockFixture2, mStaticMockFixture3,
436                 mStaticMockFixture3);
437 
438         mUnsafeBuilder
439                 .addStaticMockFixtures(mSupplier1, mSupplier2)
440                 .addStaticMockFixtures(mSupplier3)
441                 .build().apply(mStatement, mDescription).evaluate();
442 
443         inOrder.verify(mStaticMockFixture1).setUpMockedClasses(any());
444         inOrder.verify(mStaticMockFixture2).setUpMockedClasses(any());
445         inOrder.verify(mStaticMockFixture3).setUpMockedClasses(any());
446 
447         inOrder.verify(mStaticMockFixture1).setUpMockBehaviors();
448         inOrder.verify(mStaticMockFixture2).setUpMockBehaviors();
449         inOrder.verify(mStaticMockFixture3).setUpMockBehaviors();
450 
451         inOrder.verify(mStaticMockFixture3).tearDown();
452         inOrder.verify(mStaticMockFixture2).tearDown();
453         inOrder.verify(mStaticMockFixture1).tearDown();
454     }
455 
456     @Test
testMockAndSpyStaticAndAddStaticMockFixtures()457     public void testMockAndSpyStaticAndAddStaticMockFixtures() throws Throwable {
458         InOrder inOrder = inOrder(mStaticMockFixture1, mStaticMockFixture2, mStaticMockFixture3,
459                 mStaticMockFixture3);
460 
461         mUnsafeBuilder
462                 .mockStatic(StaticClass.class)
463                 .spyStatic(AnotherStaticClass.class)
464                 .addStaticMockFixtures(mSupplier1, mSupplier2)
465                 .addStaticMockFixtures(mSupplier3)
466                 .build()
467                 .apply(new Statement() {
468                     @Override
469                     public void evaluate() throws Throwable {
470                         doReturn("mocko()").when(() -> StaticClass.marco());
471                         doReturn("MOCKO()").when(() -> AnotherStaticClass.marco());
472 
473                         assertWithMessage("StaticClass.marco()")
474                                 .that(StaticClass.marco()).isEqualTo("mocko()");
475                         assertWithMessage("StaticClass.water()")
476                                 .that(StaticClass.water()).isNull(); // not mocked
477 
478                         assertWithMessage("AnotherStaticClass.marco()")
479                                 .that(AnotherStaticClass.marco()).isEqualTo("MOCKO()");
480                         assertWithMessage("AnotherStaticClass.water()")
481                                 .that(AnotherStaticClass.water()).isEqualTo("POLO");
482                     }
483                 }, mDescription).evaluate();
484 
485         inOrder.verify(mStaticMockFixture1).setUpMockedClasses(any());
486         inOrder.verify(mStaticMockFixture2).setUpMockedClasses(any());
487         inOrder.verify(mStaticMockFixture3).setUpMockedClasses(any());
488 
489         inOrder.verify(mStaticMockFixture1).setUpMockBehaviors();
490         inOrder.verify(mStaticMockFixture2).setUpMockBehaviors();
491         inOrder.verify(mStaticMockFixture3).setUpMockBehaviors();
492 
493         inOrder.verify(mStaticMockFixture3).tearDown();
494         inOrder.verify(mStaticMockFixture2).tearDown();
495         inOrder.verify(mStaticMockFixture1).tearDown();
496     }
497 
498     @Test
testAfterSessionFinished()499     public void testAfterSessionFinished() throws Throwable {
500         mUnsafeBuilder.afterSessionFinished(mRunnable).build().apply(mStatement, mDescription)
501                 .evaluate();
502 
503         verify(mRunnable).run();
504     }
505 
506     @Test
testAfterSessionFinished_whenSessionFailsToFinish()507     public void testAfterSessionFinished_whenSessionFailsToFinish() throws Throwable {
508         MockitoSessionThatFailsToFinish mockitoSession = new MockitoSessionThatFailsToFinish();
509 
510         Exception thrown = assertThrows(Exception.class,
511                 () -> mUnsafeBuilder.afterSessionFinished(mRunnable)
512                         .setMockitoSessionForTesting(mockitoSession)
513                         .build().apply(mStatement, mDescription).evaluate());
514 
515         assertWithMessage("exception").that(thrown).isSameInstanceAs(mockitoSession.e);
516         verify(mRunnable).run();
517     }
518 
519     @Test
testMockitoFrameworkCleared()520     public void testMockitoFrameworkCleared() throws Throwable {
521         MyMockitoFramework mockitoFramework = new MyMockitoFramework();
522 
523         mBuilder.setMockitoFrameworkForTesting(mockitoFramework).build()
524                 .apply(mStatement, mDescription)
525                 .evaluate();
526 
527         assertWithMessage("mockito framework cleared").that(mockitoFramework.called).isTrue();
528     }
529 
530     @Test
testMockitoFrameworkNotCleared_whenSetOnBuilder()531     public void testMockitoFrameworkNotCleared_whenSetOnBuilder() throws Throwable {
532         MyMockitoFramework mockitoFramework = new MyMockitoFramework();
533 
534         mBuilder.dontClearInlineMocks().setMockitoFrameworkForTesting(mockitoFramework).build()
535                 .apply(mStatement, mDescription)
536                 .evaluate();
537 
538         assertWithMessage("mockito framework cleared").that(mockitoFramework.called).isFalse();
539     }
540 
541     @Test
testMockitoFrameworkCleared_whenTestFails()542     public void testMockitoFrameworkCleared_whenTestFails() throws Throwable {
543         MyMockitoFramework mockitoFramework = new MyMockitoFramework();
544         Exception exception = new Exception("D'OH!");
545 
546         Exception thrown = assertThrows(Exception.class,
547                 () -> mBuilder.setMockitoFrameworkForTesting(mockitoFramework).build()
548                         .apply(new Statement() {
549                             @Override
550                             public void evaluate() throws Throwable {
551                                 throw exception;
552                             }
553                         }, mDescription).evaluate());
554 
555         assertWithMessage("exception").that(thrown).isSameInstanceAs(exception);
556         assertWithMessage("mockito framework cleared").that(mockitoFramework.called).isTrue();
557     }
558 
559     @Test
testMockitoFrameworkCleared_whenAfterSessionFinished()560     public void testMockitoFrameworkCleared_whenAfterSessionFinished() throws Throwable {
561         MyMockitoFramework mockitoFramework = new MyMockitoFramework();
562         RuntimeException exception = new RuntimeException("D'OH!");
563 
564         Exception thrown = assertThrows(Exception.class,
565                 () -> mBuilder.setMockitoFrameworkForTesting(mockitoFramework)
566                         .afterSessionFinished(() -> {
567                             throw exception;
568                         }).build().apply(mStatement, mDescription).evaluate());
569 
570         assertWithMessage("exception").that(thrown).isSameInstanceAs(exception);
571         assertWithMessage("mockito framework cleared").that(mockitoFramework.called).isTrue();
572     }
573 
574     @Test
testMockitoFrameworkCleared_whenStaticMockFixturesFailed()575     public void testMockitoFrameworkCleared_whenStaticMockFixturesFailed() throws Throwable {
576         MyMockitoFramework mockitoFramework = new MyMockitoFramework();
577         RuntimeException exception = new RuntimeException("D'OH!");
578         doThrow(exception).when(mStaticMockFixture1).tearDown();
579 
580         Exception thrown = assertThrows(Exception.class,
581                 () -> mBuilder.setMockitoFrameworkForTesting(mockitoFramework)
582                         .addStaticMockFixtures(mSupplier1).build().apply(mStatement, mDescription)
583                         .evaluate());
584 
585         assertWithMessage("exception").that(thrown).isSameInstanceAs(exception);
586         assertWithMessage("mockito framework cleared").that(mockitoFramework.called).isTrue();
587     }
588 
589     @Test
testMockitoFrameworkCleared_whenSessionFailsToFinish()590     public void testMockitoFrameworkCleared_whenSessionFailsToFinish() throws Throwable {
591         MyMockitoFramework mockitoFramework = new MyMockitoFramework();
592         MockitoSessionThatFailsToFinish mockitoSession = new MockitoSessionThatFailsToFinish();
593 
594         Exception thrown = assertThrows(Exception.class,
595                 () -> mBuilder.setMockitoFrameworkForTesting(mockitoFramework)
596                         .setMockitoSessionForTesting(mockitoSession).build()
597                         .apply(mStatement, mDescription).evaluate());
598 
599         assertWithMessage("exception").that(thrown).isSameInstanceAs(mockitoSession.e);
600         assertWithMessage("mockito framework cleared").that(mockitoFramework.called).isTrue();
601     }
602 
603     @Test
testGetClearInlineMethodsAtTheEnd()604     public void testGetClearInlineMethodsAtTheEnd() throws Throwable {
605         assertWithMessage("getClearInlineMethodsAtTheEnd() by default")
606                 .that(mBuilder.build().getClearInlineMethodsAtTheEnd(mDescription)).isTrue();
607         assertWithMessage("getClearInlineMethodsAtTheEnd() when built with dontClearInlineMocks()")
608                 .that(mBuilder.dontClearInlineMocks().build()
609                         .getClearInlineMethodsAtTheEnd(mDescription))
610                 .isFalse();
611     }
612 
applyRuleOnTestThatDoesntUseExpectation(@ullable Strictness strictness)613     private void applyRuleOnTestThatDoesntUseExpectation(@Nullable Strictness strictness)
614             throws Throwable {
615         Log.d(TAG, "applyRuleOnTestThatDoesntUseExpectation(): strictness= " + strictness);
616         if (strictness != null) {
617             mBuilder.setStrictness(strictness);
618         }
619         mBuilder.build().apply(new Statement() {
620             @Override
621             public void evaluate() throws Throwable {
622                 when(mClassUnderTest.mMock.getMeaningOfLife()).thenReturn(42);
623             }
624         }, mDescription).evaluate();
625     }
626 
newTestMethod(Annotation... annotations)627     private static Description newTestMethod(Annotation... annotations) {
628         return newTestMethod(ClassUnderTest.class, annotations);
629     }
630 
newTestMethod(Class<?> testClass, Annotation... annotations)631     private static Description newTestMethod(Class<?> testClass, Annotation... annotations) {
632         return Description.createTestDescription(testClass, TEST_METHOD_BEING_EXECUTED,
633                 annotations);
634     }
635 
636     private static final class ClassUnderTest {
637         @Mock
638         public DumbObject mMock;
639     }
640 
641     private static final class StaticClass {
642 
marco()643         public static String marco() {
644             Log.d(TAG, "StaticClass.marco() called");
645             return "polo";
646         }
647 
water()648         public static String water() {
649             Log.d(TAG, "StaticClass.water() called");
650             return "polo";
651         }
652     }
653 
654     private static final class AnotherStaticClass {
655 
marco()656         public static String marco() {
657             Log.d(TAG, "AnotherStaticClass.marco() called");
658             return "POLO";
659         }
660 
water()661         public static String water() {
662             Log.d(TAG, "AnotherStaticClass.water() called");
663             return "POLO";
664         }
665     }
666 
667     private static class DumbObject {
668 
getMeaningOfLife()669         public int getMeaningOfLife() {
670             Log.d(TAG, "getMeaningOfLife() called");
671             throw new UnsupportedOperationException("Ask Bard");
672         }
673     }
674 
675     // Used on tests that check if the clearInlineMocks() is called - such tests cannot mock a
676     // MockitoFramework because of that
677     private static final class MyMockitoFramework implements MockitoFramework {
678 
679         private static int sCounter;
680 
681         private final int mId = ++sCounter;
682         public boolean called;
683 
684         @Override
removeListener(MockitoListener arg0)685         public MockitoFramework removeListener(MockitoListener arg0) {
686             return null;
687         }
688 
689         @Override
getPlugins()690         public MockitoPlugins getPlugins() {
691             return null;
692         }
693 
694         @Override
getInvocationFactory()695         public InvocationFactory getInvocationFactory() {
696             return null;
697         }
698 
699         @Override
clearInlineMocks()700         public void clearInlineMocks() {
701             called = true;
702         }
703 
704         @Override
clearInlineMock(Object arg0)705         public void clearInlineMock(Object arg0) {
706         }
707 
708         @Override
addListener(MockitoListener arg0)709         public MockitoFramework addListener(MockitoListener arg0) {
710             return null;
711         }
712 
713         @Override
toString()714         public String toString() {
715             return "MyMockitoFramework-" + mId;
716         }
717     };
718 
719     // Used on tests that check if the clearInlineMocks() is called - such tests cannot mock a
720     // MockitoSession because of that
721     private static final class MockitoSessionThatFailsToFinish implements MockitoSession {
722         public final RuntimeException e = new RuntimeException("D'OH!");
723 
724         @Override
setStrictness(Strictness strictness)725         public void setStrictness(Strictness strictness) {
726         }
727 
728         @Override
finishMocking()729         public void finishMocking() {
730             throw e;
731         }
732 
733         @Override
finishMocking(Throwable failure)734         public void finishMocking(Throwable failure) {
735             throw e;
736         }
737     }
738 
739     private abstract static class ClassAnnotation<A extends Annotation> implements Annotation {
740         private Class<A> mAnnotationType;
741         private Class<?> mClass;
742 
ClassAnnotation(Class<A> annotationType, Class<?> clazz)743         private ClassAnnotation(Class<A> annotationType, Class<?> clazz) {
744             mAnnotationType = annotationType;
745             mClass = clazz;
746         }
747 
748         @Override
annotationType()749         public final Class<A> annotationType() {
750             return mAnnotationType;
751         }
752 
value()753         public final Class<?> value() {
754             return mClass;
755         }
756 
757         @Override
hashCode()758         public int hashCode() {
759             return Objects.hash(mAnnotationType, mClass);
760         }
761 
762         @Override
equals(Object obj)763         public boolean equals(Object obj) {
764             if (this == obj) {
765                 return true;
766             }
767             if (obj == null) {
768                 return false;
769             }
770             if (getClass() != obj.getClass()) {
771                 return false;
772             }
773             ClassAnnotation other = (ClassAnnotation) obj;
774             return Objects.equals(mAnnotationType, other.mAnnotationType)
775                     && Objects.equals(mClass, other.mClass);
776         }
777 
778         @Override
toString()779         public String toString() {
780             return getClass().getSimpleName() + "[" + mClass.getSimpleName() + "]";
781         }
782     }
783 
784     private static final class SpyStaticAnnotation extends ClassAnnotation<SpyStatic>
785             implements SpyStatic {
786 
SpyStaticAnnotation(Class<?> clazz)787         private SpyStaticAnnotation(Class<?> clazz) {
788             super(SpyStatic.class, clazz);
789         }
790     }
791 
792     private static final class MockStaticAnnotation extends ClassAnnotation<MockStatic>
793             implements MockStatic {
794 
MockStaticAnnotation(Class<?> clazz)795         private MockStaticAnnotation(Class<?> clazz) {
796             super(MockStatic.class, clazz);
797         }
798     }
799 
800     private static final class StaticClassMockedBySuperClass {
801     }
802 
803     private static final class AnotherStaticClassMockedBySuperClass {
804     }
805     private static final class StaticClassSpiedBySuperClass {
806     }
807 
808     private static final class AnotherStaticClassSpiedBySuperClass {
809     }
810 
811     @SpyStatic(StaticClassSpiedBySuperClass.class)
812     @SpyStatic(AnotherStaticClassSpiedBySuperClass.class)
813     @MockStatic(StaticClassMockedBySuperClass.class)
814     @MockStatic(AnotherStaticClassMockedBySuperClass.class)
815     private static class SuperClass {
816 
817     }
818 
819     private static final class StaticClassMockedBySubClass {
820     }
821 
822     private static final class AnotherStaticClassMockedBySubClass {
823     }
824 
825     private static final class StaticClassSpiedBySubClass {
826     }
827 
828     private static final class AnotherStaticClassSpiedBySubClass {
829     }
830 
831     @SpyStatic(StaticClassSpiedBySubClass.class)
832     @SpyStatic(AnotherStaticClassSpiedBySubClass.class)
833     @MockStatic(StaticClassMockedBySubClass.class)
834     @MockStatic(AnotherStaticClassMockedBySubClass.class)
835     private static final class SubClass extends SuperClass{
836     }
837 }