|
2 | 2 |
|
3 | 3 | import static com.bumptech.glide.RobolectricConstants.ROBOLECTRIC_SDK;
|
4 | 4 | import static com.bumptech.glide.tests.Util.mockResource;
|
| 5 | +import static com.google.common.truth.Truth.assertThat; |
| 6 | +import static org.junit.Assert.assertSame; |
| 7 | +import static org.junit.Assert.assertThrows; |
5 | 8 | import static org.mockito.Mockito.doAnswer;
|
| 9 | +import static org.mockito.Mockito.doThrow; |
6 | 10 | import static org.mockito.Mockito.never;
|
7 | 11 | import static org.mockito.Mockito.verify;
|
8 | 12 |
|
9 | 13 | import android.os.Looper;
|
| 14 | +import com.google.common.truth.Correspondence; |
| 15 | +import java.util.ArrayList; |
| 16 | +import java.util.Arrays; |
| 17 | +import java.util.List; |
10 | 18 | import org.junit.Before;
|
11 | 19 | import org.junit.Test;
|
12 | 20 | import org.junit.runner.RunWith;
|
@@ -71,4 +79,49 @@ public Void answer(InvocationOnMock invocationOnMock) throws Throwable {
|
71 | 79 |
|
72 | 80 | verify(child).recycle();
|
73 | 81 | }
|
| 82 | + |
| 83 | + @Test |
| 84 | + public void recycle_withChild_asyncTraceable() { |
| 85 | + final Resource<?> child = mockResource(); |
| 86 | + Throwable someCause = new Throwable("Some simulated cause."); |
| 87 | + IllegalStateException testEx = new IllegalStateException("Simulated error for test.", someCause); |
| 88 | + doThrow(testEx).when(child).recycle(); |
| 89 | + Resource<?> parent = mockResource(); |
| 90 | + class ChildRecycler implements Answer<Void> { |
| 91 | + @Override |
| 92 | + public Void answer(InvocationOnMock invocationOnMock) throws Throwable { |
| 93 | + recycler.recycle(child, /* forceNextFrame= */ false); |
| 94 | + return null; |
| 95 | + } |
| 96 | + } |
| 97 | + doAnswer(new ChildRecycler()).when(parent).recycle(); |
| 98 | + |
| 99 | + Shadows.shadowOf(Looper.getMainLooper()).pause(); |
| 100 | + recycler.recycle(parent, /* forceNextFrame= */ false); |
| 101 | + IllegalStateException ex = assertThrows( |
| 102 | + IllegalStateException.class, |
| 103 | + () -> Shadows.shadowOf(Looper.getMainLooper()).runOneTask() |
| 104 | + ); |
| 105 | + assertSame("Original exception is thrown", testEx, ex); |
| 106 | + assertSame("Cause is kept", someCause, ex.getCause()); |
| 107 | + assertThat(fullStackOf(ex)) |
| 108 | + .comparingElementsUsing(className()) |
| 109 | + .contains(ChildRecycler.class.getName()); |
| 110 | + } |
| 111 | + |
| 112 | + private static Correspondence<StackTraceElement, String> className() { |
| 113 | + return Correspondence.from( |
| 114 | + (actual, expected) -> actual.getClassName().equals(expected), |
| 115 | + "StackTraceElement.className" |
| 116 | + ); |
| 117 | + } |
| 118 | + |
| 119 | + private static List<StackTraceElement> fullStackOf(Throwable t) { |
| 120 | + List<StackTraceElement> stack = new ArrayList<>(); |
| 121 | + do { |
| 122 | + stack.addAll(Arrays.asList(t.getStackTrace())); |
| 123 | + t = t.getCause(); |
| 124 | + } while (t != null); |
| 125 | + return stack; |
| 126 | + } |
74 | 127 | }
|
0 commit comments