diff --git a/constants.gradle b/constants.gradle index 5063c59141..fd61b6f08e 100644 --- a/constants.gradle +++ b/constants.gradle @@ -20,8 +20,9 @@ project.ext { compileSdkVersion = 28 dexmakerVersion = '2.21.0' mockitoVersion = '2.25.0' - robolectricVersion = '4.2' + robolectricVersion = '4.3-alpha-2' autoValueVersion = '1.6' + autoServiceVersion = '1.0-rc4' checkerframeworkVersion = '2.5.0' androidXTestVersion = '1.1.0' modulePrefix = ':' diff --git a/library/core/src/test/java/com/google/android/exoplayer2/ExoPlayerTest.java b/library/core/src/test/java/com/google/android/exoplayer2/ExoPlayerTest.java index a715289a04..4172a61271 100644 --- a/library/core/src/test/java/com/google/android/exoplayer2/ExoPlayerTest.java +++ b/library/core/src/test/java/com/google/android/exoplayer2/ExoPlayerTest.java @@ -50,7 +50,6 @@ import com.google.android.exoplayer2.testutil.FakeTimeline; import com.google.android.exoplayer2.testutil.FakeTimeline.TimelineWindowDefinition; import com.google.android.exoplayer2.testutil.FakeTrackSelection; import com.google.android.exoplayer2.testutil.FakeTrackSelector; -import com.google.android.exoplayer2.testutil.RobolectricUtil; import com.google.android.exoplayer2.trackselection.DefaultTrackSelector; import com.google.android.exoplayer2.trackselection.TrackSelectionArray; import com.google.android.exoplayer2.upstream.Allocator; @@ -68,11 +67,11 @@ import java.util.concurrent.atomic.AtomicReference; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.annotation.Config; +import org.robolectric.annotation.LooperMode; /** Unit test for {@link ExoPlayer}. */ @RunWith(AndroidJUnit4.class) -@Config(shadows = {RobolectricUtil.CustomLooper.class, RobolectricUtil.CustomMessageQueue.class}) +@LooperMode(LooperMode.Mode.PAUSED) public final class ExoPlayerTest { /** diff --git a/library/core/src/test/java/com/google/android/exoplayer2/analytics/AnalyticsCollectorTest.java b/library/core/src/test/java/com/google/android/exoplayer2/analytics/AnalyticsCollectorTest.java index af9591d1b7..d175a5eab3 100644 --- a/library/core/src/test/java/com/google/android/exoplayer2/analytics/AnalyticsCollectorTest.java +++ b/library/core/src/test/java/com/google/android/exoplayer2/analytics/AnalyticsCollectorTest.java @@ -48,7 +48,6 @@ import com.google.android.exoplayer2.testutil.ExoPlayerTestRunner.Builder; import com.google.android.exoplayer2.testutil.FakeMediaSource; import com.google.android.exoplayer2.testutil.FakeRenderer; import com.google.android.exoplayer2.testutil.FakeTimeline; -import com.google.android.exoplayer2.testutil.RobolectricUtil; import com.google.android.exoplayer2.trackselection.TrackSelectionArray; import com.google.android.exoplayer2.util.Util; import com.google.android.exoplayer2.video.VideoRendererEventListener; @@ -58,11 +57,12 @@ import java.util.Iterator; import java.util.List; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.annotation.Config; +import org.robolectric.annotation.LooperMode; +import org.robolectric.annotation.LooperMode.Mode; /** Integration test for {@link AnalyticsCollector}. */ @RunWith(AndroidJUnit4.class) -@Config(shadows = {RobolectricUtil.CustomLooper.class, RobolectricUtil.CustomMessageQueue.class}) +@LooperMode(Mode.PAUSED) public final class AnalyticsCollectorTest { private static final int EVENT_PLAYER_STATE_CHANGED = 0; diff --git a/library/core/src/test/java/com/google/android/exoplayer2/drm/OfflineLicenseHelperTest.java b/library/core/src/test/java/com/google/android/exoplayer2/drm/OfflineLicenseHelperTest.java index 30dde1db57..83ca752114 100644 --- a/library/core/src/test/java/com/google/android/exoplayer2/drm/OfflineLicenseHelperTest.java +++ b/library/core/src/test/java/com/google/android/exoplayer2/drm/OfflineLicenseHelperTest.java @@ -24,7 +24,6 @@ import android.util.Pair; import androidx.test.ext.junit.runners.AndroidJUnit4; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.drm.DrmInitData.SchemeData; -import com.google.android.exoplayer2.testutil.RobolectricUtil; import java.util.HashMap; import org.junit.After; import org.junit.Before; @@ -32,11 +31,11 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import org.robolectric.annotation.Config; +import org.robolectric.annotation.LooperMode; /** Tests {@link OfflineLicenseHelper}. */ @RunWith(AndroidJUnit4.class) -@Config(shadows = {RobolectricUtil.CustomLooper.class, RobolectricUtil.CustomMessageQueue.class}) +@LooperMode(LooperMode.Mode.PAUSED) public class OfflineLicenseHelperTest { private OfflineLicenseHelper offlineLicenseHelper; diff --git a/library/core/src/test/java/com/google/android/exoplayer2/offline/DownloadHelperTest.java b/library/core/src/test/java/com/google/android/exoplayer2/offline/DownloadHelperTest.java index f06e90dc48..3b78a2e3ae 100644 --- a/library/core/src/test/java/com/google/android/exoplayer2/offline/DownloadHelperTest.java +++ b/library/core/src/test/java/com/google/android/exoplayer2/offline/DownloadHelperTest.java @@ -16,6 +16,7 @@ package com.google.android.exoplayer2.offline; import static com.google.common.truth.Truth.assertThat; +import static org.robolectric.shadows.ShadowBaseLooper.shadowMainLooper; import android.net.Uri; import androidx.test.ext.junit.runners.AndroidJUnit4; @@ -34,7 +35,6 @@ import com.google.android.exoplayer2.testutil.FakeMediaSource; import com.google.android.exoplayer2.testutil.FakeRenderer; import com.google.android.exoplayer2.testutil.FakeTimeline; import com.google.android.exoplayer2.testutil.FakeTimeline.TimelineWindowDefinition; -import com.google.android.exoplayer2.testutil.RobolectricUtil; import com.google.android.exoplayer2.trackselection.DefaultTrackSelector; import com.google.android.exoplayer2.trackselection.DefaultTrackSelector.ParametersBuilder; import com.google.android.exoplayer2.trackselection.MappingTrackSelector.MappedTrackInfo; @@ -51,12 +51,11 @@ import java.util.concurrent.atomic.AtomicReference; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.annotation.Config; -import org.robolectric.shadows.ShadowLooper; +import org.robolectric.annotation.LooperMode; /** Unit tests for {@link DownloadHelper}. */ @RunWith(AndroidJUnit4.class) -@Config(shadows = {RobolectricUtil.CustomLooper.class, RobolectricUtil.CustomMessageQueue.class}) +@LooperMode(LooperMode.Mode.PAUSED) public class DownloadHelperTest { private static final String TEST_DOWNLOAD_TYPE = "downloadType"; @@ -426,7 +425,7 @@ public class DownloadHelperTest { } }); while (!preparedCondition.block(0)) { - ShadowLooper.runMainLooperToNextTask(); + shadowMainLooper().idleFor(shadowMainLooper().getNextScheduledTaskTime()); } if (prepareException.get() != null) { throw prepareException.get(); diff --git a/library/core/src/test/java/com/google/android/exoplayer2/offline/DownloadManagerTest.java b/library/core/src/test/java/com/google/android/exoplayer2/offline/DownloadManagerTest.java index f23248952c..5b2f47d2e5 100644 --- a/library/core/src/test/java/com/google/android/exoplayer2/offline/DownloadManagerTest.java +++ b/library/core/src/test/java/com/google/android/exoplayer2/offline/DownloadManagerTest.java @@ -24,7 +24,6 @@ import com.google.android.exoplayer2.offline.Download.State; import com.google.android.exoplayer2.scheduler.Requirements; import com.google.android.exoplayer2.testutil.DummyMainThread; import com.google.android.exoplayer2.testutil.DummyMainThread.TestRunnable; -import com.google.android.exoplayer2.testutil.RobolectricUtil; import com.google.android.exoplayer2.testutil.TestDownloadManagerListener; import com.google.android.exoplayer2.testutil.TestUtil; import com.google.android.exoplayer2.upstream.cache.CacheUtil.CachingCounters; @@ -41,12 +40,13 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.MockitoAnnotations; -import org.robolectric.annotation.Config; +import org.robolectric.annotation.LooperMode; +import org.robolectric.annotation.LooperMode.Mode; import org.robolectric.shadows.ShadowLog; /** Tests {@link DownloadManager}. */ @RunWith(AndroidJUnit4.class) -@Config(shadows = {RobolectricUtil.CustomLooper.class, RobolectricUtil.CustomMessageQueue.class}) +@LooperMode(Mode.PAUSED) public class DownloadManagerTest { /** Used to check if condition becomes true in this time interval. */ diff --git a/library/core/src/test/java/com/google/android/exoplayer2/source/ClippingMediaSourceTest.java b/library/core/src/test/java/com/google/android/exoplayer2/source/ClippingMediaSourceTest.java index fc29e134d9..846600f243 100644 --- a/library/core/src/test/java/com/google/android/exoplayer2/source/ClippingMediaSourceTest.java +++ b/library/core/src/test/java/com/google/android/exoplayer2/source/ClippingMediaSourceTest.java @@ -35,7 +35,6 @@ import com.google.android.exoplayer2.testutil.FakeMediaSource; import com.google.android.exoplayer2.testutil.FakeTimeline; import com.google.android.exoplayer2.testutil.FakeTimeline.TimelineWindowDefinition; import com.google.android.exoplayer2.testutil.MediaSourceTestRunner; -import com.google.android.exoplayer2.testutil.RobolectricUtil; import com.google.android.exoplayer2.testutil.TimelineAsserts; import com.google.android.exoplayer2.upstream.Allocator; import com.google.android.exoplayer2.upstream.TransferListener; @@ -43,11 +42,12 @@ import java.io.IOException; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.annotation.Config; +import org.robolectric.annotation.LooperMode; +import org.robolectric.annotation.LooperMode.Mode; /** Unit tests for {@link ClippingMediaSource}. */ @RunWith(AndroidJUnit4.class) -@Config(shadows = {RobolectricUtil.CustomLooper.class, RobolectricUtil.CustomMessageQueue.class}) +@LooperMode(Mode.PAUSED) public final class ClippingMediaSourceTest { private static final long TEST_PERIOD_DURATION_US = 1000000; diff --git a/library/core/src/test/java/com/google/android/exoplayer2/source/ConcatenatingMediaSourceTest.java b/library/core/src/test/java/com/google/android/exoplayer2/source/ConcatenatingMediaSourceTest.java index 2c4ca7c334..17cdd9e7ae 100644 --- a/library/core/src/test/java/com/google/android/exoplayer2/source/ConcatenatingMediaSourceTest.java +++ b/library/core/src/test/java/com/google/android/exoplayer2/source/ConcatenatingMediaSourceTest.java @@ -34,7 +34,6 @@ import com.google.android.exoplayer2.testutil.FakeShuffleOrder; import com.google.android.exoplayer2.testutil.FakeTimeline; import com.google.android.exoplayer2.testutil.FakeTimeline.TimelineWindowDefinition; import com.google.android.exoplayer2.testutil.MediaSourceTestRunner; -import com.google.android.exoplayer2.testutil.RobolectricUtil; import com.google.android.exoplayer2.testutil.TimelineAsserts; import java.io.IOException; import java.util.ArrayList; @@ -44,11 +43,11 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.annotation.Config; +import org.robolectric.annotation.LooperMode; /** Unit tests for {@link ConcatenatingMediaSource}. */ @RunWith(AndroidJUnit4.class) -@Config(shadows = {RobolectricUtil.CustomLooper.class, RobolectricUtil.CustomMessageQueue.class}) +@LooperMode(LooperMode.Mode.PAUSED) public final class ConcatenatingMediaSourceTest { private ConcatenatingMediaSource mediaSource; diff --git a/library/core/src/test/java/com/google/android/exoplayer2/source/LoopingMediaSourceTest.java b/library/core/src/test/java/com/google/android/exoplayer2/source/LoopingMediaSourceTest.java index 68de5fef18..df6506ed52 100644 --- a/library/core/src/test/java/com/google/android/exoplayer2/source/LoopingMediaSourceTest.java +++ b/library/core/src/test/java/com/google/android/exoplayer2/source/LoopingMediaSourceTest.java @@ -23,17 +23,16 @@ import com.google.android.exoplayer2.testutil.FakeMediaSource; import com.google.android.exoplayer2.testutil.FakeTimeline; import com.google.android.exoplayer2.testutil.FakeTimeline.TimelineWindowDefinition; import com.google.android.exoplayer2.testutil.MediaSourceTestRunner; -import com.google.android.exoplayer2.testutil.RobolectricUtil; import com.google.android.exoplayer2.testutil.TimelineAsserts; import java.io.IOException; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.annotation.Config; +import org.robolectric.annotation.LooperMode; /** Unit tests for {@link LoopingMediaSource}. */ @RunWith(AndroidJUnit4.class) -@Config(shadows = {RobolectricUtil.CustomLooper.class, RobolectricUtil.CustomMessageQueue.class}) +@LooperMode(LooperMode.Mode.PAUSED) public class LoopingMediaSourceTest { private FakeTimeline multiWindowTimeline; diff --git a/library/core/src/test/java/com/google/android/exoplayer2/source/MergingMediaSourceTest.java b/library/core/src/test/java/com/google/android/exoplayer2/source/MergingMediaSourceTest.java index 130ba3c2dd..5ea15ac2e8 100644 --- a/library/core/src/test/java/com/google/android/exoplayer2/source/MergingMediaSourceTest.java +++ b/library/core/src/test/java/com/google/android/exoplayer2/source/MergingMediaSourceTest.java @@ -26,15 +26,14 @@ import com.google.android.exoplayer2.testutil.FakeMediaSource; import com.google.android.exoplayer2.testutil.FakeTimeline; import com.google.android.exoplayer2.testutil.FakeTimeline.TimelineWindowDefinition; import com.google.android.exoplayer2.testutil.MediaSourceTestRunner; -import com.google.android.exoplayer2.testutil.RobolectricUtil; import java.io.IOException; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.annotation.Config; +import org.robolectric.annotation.LooperMode; /** Unit tests for {@link MergingMediaSource}. */ @RunWith(AndroidJUnit4.class) -@Config(shadows = {RobolectricUtil.CustomLooper.class, RobolectricUtil.CustomMessageQueue.class}) +@LooperMode(LooperMode.Mode.PAUSED) public class MergingMediaSourceTest { @Test diff --git a/library/dash/src/test/java/com/google/android/exoplayer2/source/dash/DashMediaPeriodTest.java b/library/dash/src/test/java/com/google/android/exoplayer2/source/dash/DashMediaPeriodTest.java index 9f92e7df3c..fa077df209 100644 --- a/library/dash/src/test/java/com/google/android/exoplayer2/source/dash/DashMediaPeriodTest.java +++ b/library/dash/src/test/java/com/google/android/exoplayer2/source/dash/DashMediaPeriodTest.java @@ -35,7 +35,6 @@ import com.google.android.exoplayer2.source.dash.manifest.SegmentBase.SingleSegm import com.google.android.exoplayer2.source.dash.manifest.UtcTimingElement; import com.google.android.exoplayer2.testutil.MediaPeriodAsserts; import com.google.android.exoplayer2.testutil.MediaPeriodAsserts.FilterableManifestMediaPeriodFactory; -import com.google.android.exoplayer2.testutil.RobolectricUtil; import com.google.android.exoplayer2.upstream.Allocator; import com.google.android.exoplayer2.upstream.LoadErrorHandlingPolicy; import com.google.android.exoplayer2.upstream.LoaderErrorThrower; @@ -45,11 +44,11 @@ import java.util.Arrays; import java.util.Collections; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.annotation.Config; +import org.robolectric.annotation.LooperMode; /** Unit tests for {@link DashMediaPeriod}. */ @RunWith(AndroidJUnit4.class) -@Config(shadows = {RobolectricUtil.CustomLooper.class, RobolectricUtil.CustomMessageQueue.class}) +@LooperMode(LooperMode.Mode.PAUSED) public final class DashMediaPeriodTest { @Test diff --git a/library/dash/src/test/java/com/google/android/exoplayer2/source/dash/offline/DownloadManagerDashTest.java b/library/dash/src/test/java/com/google/android/exoplayer2/source/dash/offline/DownloadManagerDashTest.java index 76356cf3a8..6d7e2a881b 100644 --- a/library/dash/src/test/java/com/google/android/exoplayer2/source/dash/offline/DownloadManagerDashTest.java +++ b/library/dash/src/test/java/com/google/android/exoplayer2/source/dash/offline/DownloadManagerDashTest.java @@ -36,7 +36,6 @@ import com.google.android.exoplayer2.scheduler.Requirements; import com.google.android.exoplayer2.testutil.DummyMainThread; import com.google.android.exoplayer2.testutil.FakeDataSet; import com.google.android.exoplayer2.testutil.FakeDataSource; -import com.google.android.exoplayer2.testutil.RobolectricUtil; import com.google.android.exoplayer2.testutil.TestDownloadManagerListener; import com.google.android.exoplayer2.testutil.TestUtil; import com.google.android.exoplayer2.upstream.DataSource.Factory; @@ -52,12 +51,12 @@ import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.MockitoAnnotations; -import org.robolectric.annotation.Config; +import org.robolectric.annotation.LooperMode; import org.robolectric.shadows.ShadowLog; /** Tests {@link DownloadManager}. */ @RunWith(AndroidJUnit4.class) -@Config(shadows = {RobolectricUtil.CustomLooper.class, RobolectricUtil.CustomMessageQueue.class}) +@LooperMode(LooperMode.Mode.PAUSED) public class DownloadManagerDashTest { private static final int ASSERT_TRUE_TIMEOUT = 1000; diff --git a/library/dash/src/test/java/com/google/android/exoplayer2/source/dash/offline/DownloadServiceDashTest.java b/library/dash/src/test/java/com/google/android/exoplayer2/source/dash/offline/DownloadServiceDashTest.java index a35b6d1ea4..05d8979666 100644 --- a/library/dash/src/test/java/com/google/android/exoplayer2/source/dash/offline/DownloadServiceDashTest.java +++ b/library/dash/src/test/java/com/google/android/exoplayer2/source/dash/offline/DownloadServiceDashTest.java @@ -40,7 +40,6 @@ import com.google.android.exoplayer2.scheduler.Scheduler; import com.google.android.exoplayer2.testutil.DummyMainThread; import com.google.android.exoplayer2.testutil.FakeDataSet; import com.google.android.exoplayer2.testutil.FakeDataSource; -import com.google.android.exoplayer2.testutil.RobolectricUtil; import com.google.android.exoplayer2.testutil.TestDownloadManagerListener; import com.google.android.exoplayer2.testutil.TestUtil; import com.google.android.exoplayer2.upstream.DataSource; @@ -58,11 +57,11 @@ import org.junit.Before; import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.annotation.Config; +import org.robolectric.annotation.LooperMode; /** Unit tests for {@link DownloadService}. */ @RunWith(AndroidJUnit4.class) -@Config(shadows = {RobolectricUtil.CustomLooper.class, RobolectricUtil.CustomMessageQueue.class}) +@LooperMode(LooperMode.Mode.PAUSED) public class DownloadServiceDashTest { private SimpleCache cache; diff --git a/library/hls/src/test/java/com/google/android/exoplayer2/source/hls/HlsMediaPeriodTest.java b/library/hls/src/test/java/com/google/android/exoplayer2/source/hls/HlsMediaPeriodTest.java index 5988391213..dc9c0e0644 100644 --- a/library/hls/src/test/java/com/google/android/exoplayer2/source/hls/HlsMediaPeriodTest.java +++ b/library/hls/src/test/java/com/google/android/exoplayer2/source/hls/HlsMediaPeriodTest.java @@ -32,7 +32,6 @@ import com.google.android.exoplayer2.source.hls.playlist.HlsPlaylist; import com.google.android.exoplayer2.source.hls.playlist.HlsPlaylistTracker; import com.google.android.exoplayer2.testutil.MediaPeriodAsserts; import com.google.android.exoplayer2.testutil.MediaPeriodAsserts.FilterableManifestMediaPeriodFactory; -import com.google.android.exoplayer2.testutil.RobolectricUtil; import com.google.android.exoplayer2.upstream.Allocator; import com.google.android.exoplayer2.upstream.DataSource; import com.google.android.exoplayer2.upstream.LoadErrorHandlingPolicy; @@ -43,11 +42,11 @@ import java.util.Collections; import java.util.List; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.annotation.Config; +import org.robolectric.annotation.LooperMode; /** Unit test for {@link HlsMediaPeriod}. */ @RunWith(AndroidJUnit4.class) -@Config(shadows = {RobolectricUtil.CustomLooper.class, RobolectricUtil.CustomMessageQueue.class}) +@LooperMode(LooperMode.Mode.PAUSED) public final class HlsMediaPeriodTest { @Test diff --git a/library/smoothstreaming/src/test/java/com/google/android/exoplayer2/source/smoothstreaming/SsMediaPeriodTest.java b/library/smoothstreaming/src/test/java/com/google/android/exoplayer2/source/smoothstreaming/SsMediaPeriodTest.java index cb1dd2b700..787659fffe 100644 --- a/library/smoothstreaming/src/test/java/com/google/android/exoplayer2/source/smoothstreaming/SsMediaPeriodTest.java +++ b/library/smoothstreaming/src/test/java/com/google/android/exoplayer2/source/smoothstreaming/SsMediaPeriodTest.java @@ -28,7 +28,6 @@ import com.google.android.exoplayer2.source.MediaSourceEventListener.EventDispat import com.google.android.exoplayer2.source.smoothstreaming.manifest.SsManifest; import com.google.android.exoplayer2.testutil.MediaPeriodAsserts; import com.google.android.exoplayer2.testutil.MediaPeriodAsserts.FilterableManifestMediaPeriodFactory; -import com.google.android.exoplayer2.testutil.RobolectricUtil; import com.google.android.exoplayer2.upstream.Allocator; import com.google.android.exoplayer2.upstream.LoadErrorHandlingPolicy; import com.google.android.exoplayer2.upstream.LoaderErrorThrower; @@ -36,11 +35,11 @@ import com.google.android.exoplayer2.upstream.TransferListener; import com.google.android.exoplayer2.util.MimeTypes; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.annotation.Config; +import org.robolectric.annotation.LooperMode; /** Unit tests for {@link SsMediaPeriod}. */ @RunWith(AndroidJUnit4.class) -@Config(shadows = {RobolectricUtil.CustomLooper.class, RobolectricUtil.CustomMessageQueue.class}) +@LooperMode(LooperMode.Mode.PAUSED) public class SsMediaPeriodTest { @Test diff --git a/testutils/src/test/java/com/google/android/exoplayer2/testutil/FakeClockTest.java b/testutils/src/test/java/com/google/android/exoplayer2/testutil/FakeClockTest.java index 65b0efa72a..c82980d7a4 100644 --- a/testutils/src/test/java/com/google/android/exoplayer2/testutil/FakeClockTest.java +++ b/testutils/src/test/java/com/google/android/exoplayer2/testutil/FakeClockTest.java @@ -26,11 +26,11 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.annotation.Config; +import org.robolectric.annotation.LooperMode; /** Unit test for {@link FakeClock}. */ @RunWith(AndroidJUnit4.class) -@Config(shadows = {RobolectricUtil.CustomLooper.class, RobolectricUtil.CustomMessageQueue.class}) +@LooperMode(LooperMode.Mode.PAUSED) public final class FakeClockTest { private static final long TIMEOUT_MS = 10000; diff --git a/testutils_robolectric/build.gradle b/testutils_robolectric/build.gradle index 44459ea272..feee9536bb 100644 --- a/testutils_robolectric/build.gradle +++ b/testutils_robolectric/build.gradle @@ -42,4 +42,5 @@ dependencies { api project(modulePrefix + 'testutils') implementation project(modulePrefix + 'library-core') implementation 'androidx.annotation:annotation:1.0.1' + annotationProcessor 'com.google.auto.service:auto-service:' + autoServiceVersion } diff --git a/testutils_robolectric/src/main/java/com/google/android/exoplayer2/testutil/RobolectricUtil.java b/testutils_robolectric/src/main/java/com/google/android/exoplayer2/testutil/RobolectricUtil.java deleted file mode 100644 index ad1fa6bb29..0000000000 --- a/testutils_robolectric/src/main/java/com/google/android/exoplayer2/testutil/RobolectricUtil.java +++ /dev/null @@ -1,231 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.google.android.exoplayer2.testutil; - -import static org.robolectric.Shadows.shadowOf; -import static org.robolectric.util.ReflectionHelpers.callInstanceMethod; - -import android.os.Handler; -import android.os.Looper; -import android.os.Message; -import android.os.MessageQueue; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import com.google.android.exoplayer2.util.Util; -import java.util.concurrent.CopyOnWriteArraySet; -import java.util.concurrent.PriorityBlockingQueue; -import java.util.concurrent.atomic.AtomicLong; -import org.robolectric.annotation.Implementation; -import org.robolectric.annotation.Implements; -import org.robolectric.shadows.ShadowLooper; -import org.robolectric.shadows.ShadowMessageQueue; - -/** Collection of shadow classes used to run tests with Robolectric which require Loopers. */ -public final class RobolectricUtil { - - private static final AtomicLong sequenceNumberGenerator = new AtomicLong(0); - private static final int ANY_MESSAGE = Integer.MIN_VALUE; - - private RobolectricUtil() {} - - /** - * A custom implementation of Robolectric's ShadowLooper which runs all scheduled messages in the - * loop method of the looper. Also ensures to correctly emulate the message order of the real - * message loop and to avoid blocking caused by Robolectric's default implementation. - * - *

Only works in conjunction with {@link CustomMessageQueue}. Note that the test's {@code - * SystemClock} is not advanced automatically. - */ - @Implements(Looper.class) - public static final class CustomLooper extends ShadowLooper { - - private final PriorityBlockingQueue pendingMessages; - private final CopyOnWriteArraySet removedMessages; - - public CustomLooper() { - pendingMessages = new PriorityBlockingQueue<>(); - removedMessages = new CopyOnWriteArraySet<>(); - } - - @Implementation - public static void loop() { - Looper looper = Looper.myLooper(); - if (shadowOf(looper) instanceof CustomLooper) { - ((CustomLooper) shadowOf(looper)).doLoop(); - } - } - - @Implementation - @Override - public void quitUnchecked() { - super.quitUnchecked(); - // Insert message at the front of the queue to quit loop as soon as possible. - addPendingMessage(/* message= */ null, /* when= */ Long.MIN_VALUE); - } - - private void addPendingMessage(@Nullable Message message, long when) { - pendingMessages.put(new PendingMessage(message, when)); - } - - private void removeMessages(Handler handler, int what, Object object) { - RemovedMessage newRemovedMessage = new RemovedMessage(handler, what, object); - removedMessages.add(newRemovedMessage); - for (RemovedMessage removedMessage : removedMessages) { - if (removedMessage != newRemovedMessage - && removedMessage.handler == handler - && removedMessage.what == what - && removedMessage.object == object) { - removedMessages.remove(removedMessage); - } - } - } - - private void doLoop() { - boolean wasInterrupted = false; - while (true) { - try { - PendingMessage pendingMessage = pendingMessages.take(); - if (pendingMessage.message == null) { - // Null message is signal to end message loop. - return; - } - // Call through to real {@code Message.markInUse()} and {@code Message.recycle()} to - // ensure message recycling works. This is also done in Robolectric's own implementation - // of the message queue. - callInstanceMethod(pendingMessage.message, "markInUse"); - Handler target = pendingMessage.message.getTarget(); - if (target != null) { - boolean isRemoved = false; - for (RemovedMessage removedMessage : removedMessages) { - if (removedMessage.handler == target - && (removedMessage.what == ANY_MESSAGE - || removedMessage.what == pendingMessage.message.what) - && (removedMessage.object == null - || removedMessage.object == pendingMessage.message.obj) - && pendingMessage.sequenceNumber < removedMessage.sequenceNumber) { - isRemoved = true; - } - } - if (!isRemoved) { - try { - if (wasInterrupted) { - wasInterrupted = false; - // Restore the interrupt status flag, so long-running messages will exit early. - Thread.currentThread().interrupt(); - } - target.dispatchMessage(pendingMessage.message); - } catch (Throwable t) { - // Interrupt the main thread to terminate the test. Robolectric's HandlerThread will - // print the rethrown error to standard output. - Looper.getMainLooper().getThread().interrupt(); - throw t; - } - } - } - if (Util.SDK_INT >= 21) { - callInstanceMethod(pendingMessage.message, "recycleUnchecked"); - } else { - callInstanceMethod(pendingMessage.message, "recycle"); - } - } catch (InterruptedException e) { - wasInterrupted = true; - } - } - } - } - - /** - * Custom implementation of Robolectric's ShadowMessageQueue which is needed to let {@link - * CustomLooper} work as intended. - */ - @Implements(MessageQueue.class) - public static final class CustomMessageQueue extends ShadowMessageQueue { - - private final Thread looperThread; - - public CustomMessageQueue() { - looperThread = Thread.currentThread(); - } - - @Implementation - @Override - public boolean enqueueMessage(Message msg, long when) { - Looper looper = ShadowLooper.getLooperForThread(looperThread); - if (shadowOf(looper) instanceof CustomLooper - && shadowOf(looper) != shadowOf(Looper.getMainLooper())) { - ((CustomLooper) shadowOf(looper)).addPendingMessage(msg, when); - } else { - super.enqueueMessage(msg, when); - } - return true; - } - - @Implementation - public void removeMessages(Handler handler, int what, Object object) { - Looper looper = ShadowLooper.getLooperForThread(looperThread); - if (shadowOf(looper) instanceof CustomLooper - && shadowOf(looper) != shadowOf(Looper.getMainLooper())) { - ((CustomLooper) shadowOf(looper)).removeMessages(handler, what, object); - } - } - - @Implementation - public void removeCallbacksAndMessages(Handler handler, Object object) { - Looper looper = ShadowLooper.getLooperForThread(looperThread); - if (shadowOf(looper) instanceof CustomLooper - && shadowOf(looper) != shadowOf(Looper.getMainLooper())) { - ((CustomLooper) shadowOf(looper)).removeMessages(handler, ANY_MESSAGE, object); - } - } - } - - private static final class PendingMessage implements Comparable { - - public final @Nullable Message message; - public final long when; - public final long sequenceNumber; - - public PendingMessage(@Nullable Message message, long when) { - this.message = message; - this.when = when; - sequenceNumber = sequenceNumberGenerator.getAndIncrement(); - } - - @Override - public int compareTo(@NonNull PendingMessage other) { - int res = Util.compareLong(this.when, other.when); - if (res == 0 && this != other) { - res = Util.compareLong(this.sequenceNumber, other.sequenceNumber); - } - return res; - } - } - - private static final class RemovedMessage { - - public final Handler handler; - public final int what; - public final Object object; - public final long sequenceNumber; - - public RemovedMessage(Handler handler, int what, Object object) { - this.handler = handler; - this.what = what; - this.object = object; - this.sequenceNumber = sequenceNumberGenerator.get(); - } - } -}