diff options
Diffstat (limited to 'robolectric/src/test/java/org/robolectric/shadows/ShadowLooperResetterTest.java')
-rw-r--r-- | robolectric/src/test/java/org/robolectric/shadows/ShadowLooperResetterTest.java | 191 |
1 files changed, 191 insertions, 0 deletions
diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowLooperResetterTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowLooperResetterTest.java new file mode 100644 index 000000000..92e1643c5 --- /dev/null +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowLooperResetterTest.java @@ -0,0 +1,191 @@ +package org.robolectric.shadows; + +import static android.os.Looper.getMainLooper; +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; +import static com.google.common.truth.Truth.assertThat; +import static org.robolectric.Shadows.shadowOf; + +import android.os.Handler; +import android.os.HandlerThread; +import java.time.Duration; +import java.util.concurrent.atomic.AtomicBoolean; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runner.Runner; +import org.junit.runner.notification.Failure; +import org.junit.runner.notification.RunListener; +import org.junit.runner.notification.RunNotifier; +import org.junit.runners.JUnit4; +import org.junit.runners.model.InitializationError; +import org.robolectric.RobolectricTestRunner; + +/** A specialized test for verifying that looper state is cleared properly between tests. */ +@RunWith(JUnit4.class) +public class ShadowLooperResetterTest { + private final RunNotifier runNotifier = new RunNotifier(); + + @Before + public void setup() { + runNotifier.addListener( + new RunListener() { + @Override + public void testFailure(Failure failure) throws Exception { + throw new AssertionError("Unexpected test failure: " + failure, failure.getException()); + } + }); + } + + /** + * Basic test class that interacts with Looper in two different tests, to ensure Looper remains + * functional after reset. + */ + public static class BasicLooperTest { + + private void doPostToLooperTest() { + checkNotNull(getMainLooper()); + + AtomicBoolean didRun = new AtomicBoolean(false); + new Handler(getMainLooper()).post(() -> didRun.set(true)); + + assertThat(didRun.get()).isFalse(); + shadowOf(getMainLooper()).idle(); + assertThat(didRun.get()).isTrue(); + } + + @Test + public void postToLooperTest() { + doPostToLooperTest(); + } + + @Test + public void anotherPostToLooperTest() { + doPostToLooperTest(); + } + } + + @Test + public void basicPostAndRun() throws InitializationError { + Runner runner = new RobolectricTestRunner(BasicLooperTest.class); + + // run and assert no failures + runner.run(runNotifier); + } + + /** Test that leaves an unexecuted runnable on Looper and verifies it is removed between tests. */ + public static class PendingLooperTest { + + private void doPostToLooperTest() { + checkState(shadowOf(getMainLooper()).isIdle()); + + AtomicBoolean didRun = new AtomicBoolean(false); + new Handler(getMainLooper()).post(() -> didRun.set(true)); + + assertThat(didRun.get()).isFalse(); + assertThat(shadowOf(getMainLooper()).isIdle()).isFalse(); + } + + @Test + public void postToLooperTest() { + doPostToLooperTest(); + } + + @Test + public void anotherPostToLooperTest() { + doPostToLooperTest(); + } + } + + @Test + public void pendingTasksClearer() throws InitializationError { + Runner runner = new RobolectricTestRunner(PendingLooperTest.class); + + // run and assert no failures + runner.run(runNotifier); + } + + /** Test that uses delayed tasks */ + public static class DelayedTaskTest { + + private void doDelayedPostToLooperTest() { + checkState(shadowOf(getMainLooper()).isIdle()); + + AtomicBoolean didRun = new AtomicBoolean(false); + new Handler(getMainLooper()).postDelayed(() -> didRun.set(true), 100); + shadowOf(getMainLooper()).idle(); + assertThat(didRun.get()).isFalse(); + shadowOf(getMainLooper()).idleFor(Duration.ofMillis(100)); + assertThat(didRun.get()).isTrue(); + } + + @Test + public void postToLooperTest() { + doDelayedPostToLooperTest(); + } + + @Test + public void anotherPostToLooperTest() { + doDelayedPostToLooperTest(); + } + } + + @Test + public void delayedTask() throws InitializationError { + Runner runner = new RobolectricTestRunner(DelayedTaskTest.class); + + // run and assert no failures + runner.run(runNotifier); + } + + /** Test that uses delayed tasks on a running looper */ + public static class DelayedTaskRunningLooperTest { + + // use a static thread so both tests share the same looper + static HandlerThread handlerThread; + + @Before + public void init() { + if (handlerThread == null) { + handlerThread = new HandlerThread("DelayedTaskRunningLooperTest"); + handlerThread.start(); + } + } + + @AfterClass + public static void shutDown() throws InterruptedException { + handlerThread.quit(); + handlerThread.join(); + } + + private void doDelayedPostToLooperTest() { + checkNotNull(handlerThread.getLooper()); + + AtomicBoolean didRun = new AtomicBoolean(false); + new Handler(handlerThread.getLooper()).postDelayed(() -> didRun.set(true), 100); + shadowOf(handlerThread.getLooper()).idle(); + assertThat(didRun.get()).isFalse(); + shadowOf(handlerThread.getLooper()).idleFor(Duration.ofMillis(100)); + assertThat(didRun.get()).isTrue(); + } + + @Test + public void postToLooperTest() { + doDelayedPostToLooperTest(); + } + + @Test + public void anotherPostToLooperTest() { + doDelayedPostToLooperTest(); + } + } + + @Test + public void delayedTaskRunningLooper() throws InitializationError { + Runner runner = new RobolectricTestRunner(DelayedTaskRunningLooperTest.class); + + // run and assert no failures + runner.run(runNotifier); + } +} |