diff --git a/testutils/src/main/java/com/google/android/exoplayer2/testutil/ExoPlayerTestRunner.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/ExoPlayerTestRunner.java index a87066415d..a1f8fc7861 100644 --- a/testutils/src/main/java/com/google/android/exoplayer2/testutil/ExoPlayerTestRunner.java +++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/ExoPlayerTestRunner.java @@ -62,14 +62,30 @@ public final class ExoPlayerTestRunner extends Player.DefaultEventListener { */ public interface PlayerFactory { + /** + * Creates a new {@link SimpleExoPlayer} using the provided renderers factory, track selector, + * and load control. + * + * @param renderersFactory A {@link RenderersFactory} to be used for the new player. + * @param trackSelector A {@link MappingTrackSelector} to be used for the new player. + * @param loadControl A {@link LoadControl} to be used for the new player. + * @return A new {@link SimpleExoPlayer}. + */ SimpleExoPlayer createExoPlayer(RenderersFactory renderersFactory, MappingTrackSelector trackSelector, LoadControl loadControl); } + /** + * A generic video {@link Format} which can be used to set up media sources and renderers. + */ public static final Format VIDEO_FORMAT = Format.createVideoSampleFormat(null, MimeTypes.VIDEO_H264, null, Format.NO_VALUE, Format.NO_VALUE, 1280, 720, Format.NO_VALUE, null, null); + + /** + * A generic audio {@link Format} which can be used to set up media sources and renderers. + */ public static final Format AUDIO_FORMAT = Format.createAudioSampleFormat(null, MimeTypes.AUDIO_AAC, null, Format.NO_VALUE, Format.NO_VALUE, 2, 44100, null, null, 0, null); @@ -85,19 +101,45 @@ public final class ExoPlayerTestRunner extends Player.DefaultEventListener { private ActionSchedule actionSchedule; private Player.EventListener eventListener; + /** + * Sets a {@link Timeline} to be used by a {@link FakeMediaSource} in the test runner. The + * default value is a non-seekable, non-dynamic {@link FakeTimeline} with zero duration. Setting + * the timeline is not allowed after a call to {@link #setMediaSource(MediaSource)}. + * + * @param timeline A {@link Timeline} to be used by a {@link FakeMediaSource} in the test + * runner. + * @return This builder. + */ public Builder setTimeline(Timeline timeline) { Assert.assertNull(mediaSource); this.timeline = timeline; return this; } + /** + * Sets a manifest to be used by a {@link FakeMediaSource} in the test runner. The default value + * is null. Setting the manifest is not allowed after a call to + * {@link #setMediaSource(MediaSource)}. + * + * @param manifest A manifest to be used by a {@link FakeMediaSource} in the test runner. + * @return This builder. + */ public Builder setManifest(Object manifest) { Assert.assertNull(mediaSource); this.manifest = manifest; return this; } - /** Replaces {@link #setTimeline(Timeline)} and {@link #setManifest(Object)}. */ + /** + * Sets a {@link MediaSource} to be used by the test runner. The default value is a + * {@link FakeMediaSource} with the timeline and manifest provided by + * {@link #setTimeline(Timeline)} and {@link #setManifest(Object)}. Setting the media source is + * not allowed after calls to {@link #setTimeline(Timeline)} and/or + * {@link #setManifest(Object)}. + * + * @param mediaSource A {@link MediaSource} to be used by the test runner. + * @return This builder. + */ public Builder setMediaSource(MediaSource mediaSource) { Assert.assertNull(timeline); Assert.assertNull(manifest); @@ -105,49 +147,118 @@ public final class ExoPlayerTestRunner extends Player.DefaultEventListener { return this; } + /** + * Sets a {@link MappingTrackSelector} to be used by the test runner. The default value is a + * {@link DefaultTrackSelector}. + * + * @param trackSelector A {@link MappingTrackSelector} to be used by the test runner. + * @return This builder. + */ public Builder setTrackSelector(MappingTrackSelector trackSelector) { this.trackSelector = trackSelector; return this; } + /** + * Sets a {@link LoadControl} to be used by the test runner. The default value is a + * {@link DefaultLoadControl}. + * + * @param loadControl A {@link LoadControl} to be used by the test runner. + * @return This builder. + */ public Builder setLoadControl(LoadControl loadControl) { this.loadControl = loadControl; return this; } + /** + * Sets a list of {@link Format}s to be used by a {@link FakeMediaSource} to create media + * periods and for setting up a {@link FakeRenderer}. The default value is a single + * {@link #VIDEO_FORMAT}. Note that this parameter doesn't have any influence if both a media + * source with {@link #setMediaSource(MediaSource)} and renderers with + * {@link #setRenderers(Renderer...)} or {@link #setRenderersFactory(RenderersFactory)} are set. + * + * @param supportedFormats A list of supported {@link Format}s. + * @return This builder. + */ public Builder setSupportedFormats(Format... supportedFormats) { this.supportedFormats = supportedFormats; return this; } + /** + * Sets the {@link Renderer}s to be used by the test runner. The default value is a single + * {@link FakeRenderer} supporting the formats set by {@link #setSupportedFormats(Format...)}. + * Setting the renderers is not allowed after a call to + * {@link #setRenderersFactory(RenderersFactory)}. + * + * @param renderers A list of {@link Renderer}s to be used by the test runner. + * @return This builder. + */ public Builder setRenderers(Renderer... renderers) { Assert.assertNull(renderersFactory); this.renderers = renderers; return this; } - /** Replaces {@link #setRenderers(Renderer...)}. */ + /** + * Sets the {@link RenderersFactory} to be used by the test runner. The default factory creates + * all renderers set by {@link #setRenderers(Renderer...)}. Setting the renderer factory is not + * allowed after a call to {@link #setRenderers(Renderer...)}. + * + * @param renderersFactory A {@link RenderersFactory} to be used by the test runner. + * @return This builder. + */ public Builder setRenderersFactory(RenderersFactory renderersFactory) { Assert.assertNull(renderers); this.renderersFactory = renderersFactory; return this; } + /** + * Sets the {@link PlayerFactory} which creates the {@link SimpleExoPlayer} to be used by the + * test runner. The default value is a {@link SimpleExoPlayer} with the renderers provided by + * {@link #setRenderers(Renderer...)} or {@link #setRenderersFactory(RenderersFactory)}, the + * track selector provided by {@link #setTrackSelector(MappingTrackSelector)} and the load + * control provided by {@link #setLoadControl(LoadControl)}. + * + * @param playerFactory A {@link PlayerFactory} to create the player. + * @return This builder. + */ public Builder setExoPlayer(PlayerFactory playerFactory) { this.playerFactory = playerFactory; return this; } + /** + * Sets an {@link ActionSchedule} to be run by the test runner. The first action will be + * executed immediately before {@link SimpleExoPlayer#prepare(MediaSource)}. + * + * @param actionSchedule An {@link ActionSchedule} to be used by the test runner. + * @return This builder. + */ public Builder setActionSchedule(ActionSchedule actionSchedule) { this.actionSchedule = actionSchedule; return this; } + /** + * Sets an {@link Player.EventListener} to be registered to listen to player events. + * + * @param eventListener A {@link Player.EventListener} to be registered by the test runner to + * listen to player events. + * @return This builder. + */ public Builder setEventListener(Player.EventListener eventListener) { this.eventListener = eventListener; return this; } + /** + * Builds an {@link ExoPlayerTestRunner} using the provided values or their defaults. + * + * @return The built {@link ExoPlayerTestRunner}. + */ public ExoPlayerTestRunner build() { if (supportedFormats == null) { supportedFormats = new Format[] { VIDEO_FORMAT }; @@ -234,6 +345,13 @@ public final class ExoPlayerTestRunner extends Player.DefaultEventListener { // Called on the test thread to run the test. + /** + * Starts the test runner on its own thread. This will trigger the creation of the player, the + * listener registration, the start of the action schedule, and the preparation of the player + * with the provided media source. + * + * @return This test runner. + */ public ExoPlayerTestRunner start() { handler.post(new Runnable() { @Override @@ -257,6 +375,16 @@ public final class ExoPlayerTestRunner extends Player.DefaultEventListener { return this; } + /** + * Blocks the current thread until the test runner finishes. A test is deemed to be finished when + * the playback state transitions to {@link Player#STATE_ENDED} or {@link Player#STATE_IDLE}, or + * when am {@link ExoPlaybackException} is thrown. + * + * @param timeoutMs The maximum time to wait for the test runner to finish. If this time elapsed + * the method will throw a {@link TimeoutException}. + * @return This test runner. + * @throws Exception If any exception occurred during playback, release, or due to a timeout. + */ public ExoPlayerTestRunner blockUntilEnded(long timeoutMs) throws Exception { if (!endedCountDownLatch.await(timeoutMs, TimeUnit.MILLISECONDS)) { exception = new TimeoutException("Test playback timed out waiting for playback to end."); @@ -271,6 +399,13 @@ public final class ExoPlayerTestRunner extends Player.DefaultEventListener { // Assertions called on the test thread after test finished. + /** + * Asserts that the timelines reported by + * {@link Player.EventListener#onTimelineChanged(Timeline, Object, int)} are equal to the provided + * timelines. + * + * @param timelines A list of expected {@link Timeline}s. + */ public void assertTimelinesEqual(Timeline... timelines) { Assert.assertEquals(timelines.length, this.timelines.size()); for (Timeline timeline : timelines) { @@ -278,6 +413,13 @@ public final class ExoPlayerTestRunner extends Player.DefaultEventListener { } } + /** + * Asserts that the manifests reported by + * {@link Player.EventListener#onTimelineChanged(Timeline, Object, int)} are equal to the provided + * manifest. + * + * @param manifests A list of expected manifests. + */ public void assertManifestsEqual(Object... manifests) { Assert.assertEquals(manifests.length, this.manifests.size()); for (Object manifest : manifests) { @@ -285,14 +427,35 @@ public final class ExoPlayerTestRunner extends Player.DefaultEventListener { } } + /** + * Asserts that the last track group array reported by + * {@link Player.EventListener#onTracksChanged(TrackGroupArray, TrackSelectionArray)} is equal to + * the provided track group array. + * + * @param trackGroupArray The expected {@link TrackGroupArray}. + */ public void assertTrackGroupsEqual(TrackGroupArray trackGroupArray) { Assert.assertEquals(trackGroupArray, this.trackGroups); } + /** + * Asserts that the number of reported discontinuities by + * {@link Player.EventListener#onPositionDiscontinuity(int)} is equal to the provided number. + * + * @param expectedCount The expected number of position discontinuities. + */ public void assertPositionDiscontinuityCount(int expectedCount) { Assert.assertEquals(expectedCount, positionDiscontinuityCount); } + /** + * Asserts that the indices of played periods is equal to the provided list of periods. A period + * is considered to be played if it was the current period after a position discontinuity or a + * media source preparation. When the same period is repeated automatically due to enabled repeat + * modes, it is reported twice. Seeks within the current period are not reported. + * + * @param periodIndices A list of expected period indices. + */ public void assertPlayedPeriodIndices(int... periodIndices) { Assert.assertEquals(periodIndices.length, this.periodIndices.size()); for (int periodIndex : periodIndices) {