diff --git a/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/ExoPlayerTest.java b/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/ExoPlayerTest.java index a6d9d4b6ff..dbbb47fc69 100644 --- a/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/ExoPlayerTest.java +++ b/libraries/exoplayer/src/test/java/androidx/media3/exoplayer/ExoPlayerTest.java @@ -53,6 +53,7 @@ import static androidx.media3.test.utils.FakeSampleStream.FakeSampleStreamItem.o import static androidx.media3.test.utils.FakeTimeline.TimelineWindowDefinition.DEFAULT_WINDOW_DURATION_US; import static androidx.media3.test.utils.FakeTimeline.TimelineWindowDefinition.DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US; import static androidx.media3.test.utils.TestUtil.assertTimelinesSame; +import static androidx.media3.test.utils.TestUtil.timelinesAreSame; import static androidx.media3.test.utils.robolectric.RobolectricUtil.runMainLooperUntil; import static androidx.media3.test.utils.robolectric.TestPlayerRunHelper.playUntilPosition; import static androidx.media3.test.utils.robolectric.TestPlayerRunHelper.playUntilStartOfMediaItem; @@ -156,7 +157,6 @@ import androidx.media3.test.utils.FakeTimeline.TimelineWindowDefinition; import androidx.media3.test.utils.FakeTrackSelection; import androidx.media3.test.utils.FakeTrackSelector; import androidx.media3.test.utils.FakeVideoRenderer; -import androidx.media3.test.utils.NoUidTimeline; import androidx.media3.test.utils.TestExoPlayerBuilder; import androidx.media3.test.utils.robolectric.TestPlayerRunHelper; import androidx.test.core.app.ApplicationProvider; @@ -12257,6 +12257,6 @@ public final class ExoPlayerTest { * Returns an argument matcher for {@link Timeline} instances that ignores period and window uids. */ private static ArgumentMatcher noUid(Timeline timeline) { - return argument -> new NoUidTimeline(timeline).equals(new NoUidTimeline(argument)); + return argument -> timelinesAreSame(argument, timeline); } } diff --git a/libraries/test_utils/src/main/java/androidx/media3/test/utils/Action.java b/libraries/test_utils/src/main/java/androidx/media3/test/utils/Action.java index f025836ba2..cf5f420c6a 100644 --- a/libraries/test_utils/src/main/java/androidx/media3/test/utils/Action.java +++ b/libraries/test_utils/src/main/java/androidx/media3/test/utils/Action.java @@ -15,6 +15,8 @@ */ package androidx.media3.test.utils; +import static androidx.media3.test.utils.TestUtil.timelinesAreSame; + import android.os.Looper; import android.view.Surface; import androidx.annotation.Nullable; @@ -765,7 +767,7 @@ public abstract class Action { @Nullable Timeline expectedTimeline, @Player.TimelineChangeReason int expectedReason) { super(tag, "WaitForTimelineChanged"); - this.expectedTimeline = expectedTimeline != null ? new NoUidTimeline(expectedTimeline) : null; + this.expectedTimeline = expectedTimeline; this.ignoreExpectedReason = false; this.expectedReason = expectedReason; } @@ -797,7 +799,7 @@ public abstract class Action { @Override public void onTimelineChanged( Timeline timeline, @Player.TimelineChangeReason int reason) { - if ((expectedTimeline == null || new NoUidTimeline(timeline).equals(expectedTimeline)) + if ((expectedTimeline == null || timelinesAreSame(timeline, expectedTimeline)) && (ignoreExpectedReason || expectedReason == reason)) { player.removeListener(this); nextAction.schedule(player, trackSelector, surface, handler); @@ -805,8 +807,8 @@ public abstract class Action { } }; player.addListener(listener); - Timeline currentTimeline = new NoUidTimeline(player.getCurrentTimeline()); - if (currentTimeline.equals(expectedTimeline)) { + if (expectedTimeline != null + && timelinesAreSame(player.getCurrentTimeline(), expectedTimeline)) { player.removeListener(listener); nextAction.schedule(player, trackSelector, surface, handler); } diff --git a/libraries/test_utils/src/main/java/androidx/media3/test/utils/ExoPlayerTestRunner.java b/libraries/test_utils/src/main/java/androidx/media3/test/utils/ExoPlayerTestRunner.java index 3bf7bc3866..0cb7b4d935 100644 --- a/libraries/test_utils/src/main/java/androidx/media3/test/utils/ExoPlayerTestRunner.java +++ b/libraries/test_utils/src/main/java/androidx/media3/test/utils/ExoPlayerTestRunner.java @@ -43,6 +43,7 @@ import androidx.media3.exoplayer.analytics.AnalyticsListener; import androidx.media3.exoplayer.source.MediaSource; import androidx.media3.exoplayer.trackselection.DefaultTrackSelector; import androidx.media3.exoplayer.upstream.BandwidthMeter; +import com.google.common.collect.ImmutableList; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -536,11 +537,8 @@ public final class ExoPlayerTestRunner implements Player.Listener, ActionSchedul * @param timelines A list of expected {@link Timeline}s. */ public void assertTimelinesSame(Timeline... timelines) { - assertThat(this.timelines).hasSize(timelines.length); - for (int i = 0; i < timelines.length; i++) { - assertThat(new NoUidTimeline(timelines[i])) - .isEqualTo(new NoUidTimeline(this.timelines.get(i))); - } + TestUtil.assertTimelinesSame( + ImmutableList.copyOf(this.timelines), ImmutableList.copyOf(timelines)); } /** diff --git a/libraries/test_utils/src/main/java/androidx/media3/test/utils/NoUidTimeline.java b/libraries/test_utils/src/main/java/androidx/media3/test/utils/NoUidTimeline.java deleted file mode 100644 index 5cd0adad0c..0000000000 --- a/libraries/test_utils/src/main/java/androidx/media3/test/utils/NoUidTimeline.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (C) 2019 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 androidx.media3.test.utils; - -import androidx.media3.common.Timeline; -import androidx.media3.common.util.UnstableApi; -import androidx.media3.exoplayer.source.ForwardingTimeline; - -/** - * A timeline which wraps another timeline and overrides all window and period uids to 0. This is - * useful for testing timeline equality without taking uids into account. - */ -@UnstableApi -public class NoUidTimeline extends ForwardingTimeline { - - /** - * Creates an instance. - * - * @param timeline The underlying timeline. - */ - public NoUidTimeline(Timeline timeline) { - super(timeline); - } - - @Override - public Window getWindow(int windowIndex, Window window, long defaultPositionProjectionUs) { - timeline.getWindow(windowIndex, window, defaultPositionProjectionUs); - window.uid = 0; - return window; - } - - @Override - public Period getPeriod(int periodIndex, Period period, boolean setIds) { - timeline.getPeriod(periodIndex, period, setIds); - period.uid = 0; - return period; - } -} diff --git a/libraries/test_utils/src/main/java/androidx/media3/test/utils/TestUtil.java b/libraries/test_utils/src/main/java/androidx/media3/test/utils/TestUtil.java index a59377c27d..f6ac5ecb99 100644 --- a/libraries/test_utils/src/main/java/androidx/media3/test/utils/TestUtil.java +++ b/libraries/test_utils/src/main/java/androidx/media3/test/utils/TestUtil.java @@ -44,6 +44,7 @@ import androidx.media3.extractor.SeekMap; import androidx.media3.extractor.metadata.MetadataInputBuffer; import com.google.common.collect.ImmutableList; import com.google.common.primitives.Bytes; +import com.google.common.truth.Correspondence; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; @@ -207,11 +208,20 @@ public class TestUtil { */ public static void assertTimelinesSame( List actualTimelines, List expectedTimelines) { - assertThat(actualTimelines).hasSize(expectedTimelines.size()); - for (int i = 0; i < actualTimelines.size(); i++) { - assertThat(new NoUidTimeline(actualTimelines.get(i))) - .isEqualTo(new NoUidTimeline(expectedTimelines.get(i))); - } + assertThat(actualTimelines) + .comparingElementsUsing( + Correspondence.from( + TestUtil::timelinesAreSame, "is equal to (ignoring Window.uid and Period.uid)")) + .containsExactlyElementsIn(expectedTimelines) + .inOrder(); + } + + /** + * Returns true if {@code thisTimeline} is equal to {@code thatTimeline}, ignoring {@link + * Timeline.Window#uid} and {@link Timeline.Period#uid} values. + */ + public static boolean timelinesAreSame(Timeline thisTimeline, Timeline thatTimeline) { + return new NoUidTimeline(thisTimeline).equals(new NoUidTimeline(thatTimeline)); } /** @@ -494,4 +504,47 @@ public class TestUtil { return list; } + + private static final class NoUidTimeline extends Timeline { + + private final Timeline delegate; + + public NoUidTimeline(Timeline timeline) { + this.delegate = timeline; + } + + @Override + public int getWindowCount() { + return delegate.getWindowCount(); + } + + @Override + public Window getWindow(int windowIndex, Window window, long defaultPositionProjectionUs) { + delegate.getWindow(windowIndex, window, defaultPositionProjectionUs); + window.uid = 0; + return window; + } + + @Override + public int getPeriodCount() { + return delegate.getPeriodCount(); + } + + @Override + public Period getPeriod(int periodIndex, Period period, boolean setIds) { + delegate.getPeriod(periodIndex, period, setIds); + period.uid = 0; + return period; + } + + @Override + public int getIndexOfPeriod(Object uid) { + return delegate.getIndexOfPeriod(uid); + } + + @Override + public Object getUidOfPeriod(int periodIndex) { + return 0; + } + } }