Skip to content

Commit

Permalink
412 update player tests with turbine (#418)
Browse files Browse the repository at this point in the history
Co-authored-by: Gaëtan Muller <[email protected]>
Co-authored-by: Gaëtan Muller <[email protected]>
  • Loading branch information
3 people authored Jan 26, 2024
1 parent 340bb20 commit 21042aa
Show file tree
Hide file tree
Showing 6 changed files with 241 additions and 246 deletions.
2 changes: 2 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ okhttp = "4.12.0"
srg-data-provider = "0.8.0"
tag-commander-core = "5.4.2"
tag-commander-server-side = "5.5.2"
turbine = "1.0.0"

[libraries]
accompanist-navigation-material = { module = "com.google.accompanist:accompanist-navigation-material", version.ref = "accompanist" }
Expand Down Expand Up @@ -120,6 +121,7 @@ androidx-compose-runtime-saveable = { module = "androidx.compose.runtime:runtime
leanback = { group = "androidx.leanback", name = "leanback", version.ref = "androidx-leanback" }
androidx-test-ext-junit = { group = "androidx.test.ext", name = "junit", version.ref = "androidx-test-ext-junit" }
guava = { module = "com.google.guava:guava", version.ref = "guava" }
turbine = { module = "app.cash.turbine:turbine", version.ref = "turbine" }

[plugins]
android-application = { id = "com.android.application", version.ref = "android-gradle-plugin" }
Expand Down
1 change: 1 addition & 0 deletions pillarbox-player/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ dependencies {
testImplementation(libs.kotlinx.coroutines.test)
testImplementation(libs.mockk)
testImplementation(libs.mockk.dsl)
testImplementation(libs.turbine)

androidTestImplementation(project(":pillarbox-player-testutils"))

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ import kotlinx.coroutines.currentCoroutineContext
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.emptyFlow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.merge
import kotlinx.coroutines.flow.transformLatest
Expand Down Expand Up @@ -149,6 +152,7 @@ fun Player.mediaItemCountAsFlow(): Flow<Int> = callbackFlow {

/**
* Ticker emits event every [interval] when [Player.isPlaying] is true.
* Emit a value once at least once.
*/
@OptIn(ExperimentalCoroutinesApi::class)
fun Player.tickerWhilePlayingAsFlow(
Expand All @@ -162,9 +166,11 @@ fun Player.tickerWhilePlayingAsFlow(

/**
* Current position of the player update every [updateInterval] when it is playing.
* Send current position once if not playing.
*/
fun Player.currentPositionAsFlow(updateInterval: Duration = DefaultUpdateInterval): Flow<Long> =
merge(
if (isPlaying) emptyFlow() else flowOf(currentPosition),
tickerWhilePlayingAsFlow(updateInterval).map {
currentPosition
},
Expand All @@ -178,14 +184,11 @@ private fun Player.positionChangedFlow(): Flow<Long> = callbackFlow {
newPosition: Player.PositionInfo,
reason: Int
) {
if (reason == Player.DISCONTINUITY_REASON_SEEK) {
trySend(currentPosition)
}
trySend(newPosition.positionMs)
}
}
trySend(currentPosition)
addPlayerListener(player = this@positionChangedFlow, listener)
}
}.distinctUntilChanged()

/**
* Current buffered percentage as flow [Player.getBufferedPercentage]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,15 +50,15 @@ class TestCurrentMediaItemTracker {

@Test
fun testAreEqualsDifferentMediaItem() {
val mediaItem = createMediaItem("M1")
val mediaItem2 = createMediaItem("M2")
val mediaItem = createMediaItemWithMediaId("M1")
val mediaItem2 = createMediaItemWithMediaId("M2")
Assert.assertFalse(CurrentMediaItemTracker.areEqual(mediaItem, mediaItem2))
}

@Test
fun testAreEqualsSameMediaId() {
val mediaItem = createMediaItem("M1")
val mediaItem2 = createMediaItem("M1")
val mediaItem = createMediaItemWithMediaId("M1")
val mediaItem2 = createMediaItemWithMediaId("M1")
Assert.assertTrue(CurrentMediaItemTracker.areEqual(mediaItem, mediaItem2))
}

Expand Down Expand Up @@ -95,7 +95,7 @@ class TestCurrentMediaItemTracker {

@Test
fun testStartEnd() = runTest {
val mediaItem = createMediaItem("M1")
val mediaItem = createMediaItemWithMediaId("M1")
val expected = listOf(EventState.IDLE, EventState.START, EventState.EOF)
analyticsCommander.simulateItemStart(mediaItem)
analyticsCommander.simulateItemEnd(mediaItem)
Expand All @@ -105,7 +105,7 @@ class TestCurrentMediaItemTracker {
@Test
fun testStartAsyncLoadEnd() = runTest {
val mediaItemEmpty = MediaItem.Builder().setMediaId("M1").build()
val mediaItemLoaded = createMediaItem("M1")
val mediaItemLoaded = createMediaItemWithMediaId("M1")
val expected = listOf(EventState.IDLE, EventState.START, EventState.EOF)
analyticsCommander.simulateItemStart(mediaItemEmpty)
analyticsCommander.simulateItemLoaded(mediaItemLoaded)
Expand All @@ -116,7 +116,7 @@ class TestCurrentMediaItemTracker {
@Test
fun testStartAsyncLoadRelease() = runTest {
val mediaItemEmpty = MediaItem.Builder().setMediaId("M1").build()
val mediaItemLoaded = createMediaItem("M1")
val mediaItemLoaded = createMediaItemWithMediaId("M1")
val expected = listOf(EventState.IDLE, EventState.START, EventState.END)
analyticsCommander.simulateItemStart(mediaItemEmpty)
analyticsCommander.simulateItemLoaded(mediaItemLoaded)
Expand All @@ -126,7 +126,7 @@ class TestCurrentMediaItemTracker {

@Test
fun testStartReleased() = runTest {
val mediaItem = createMediaItem("M1")
val mediaItem = createMediaItemWithMediaId("M1")
val expected = listOf(EventState.IDLE, EventState.START, EventState.END)
analyticsCommander.simulateItemStart(mediaItem)
analyticsCommander.simulateRelease(mediaItem)
Expand All @@ -135,15 +135,15 @@ class TestCurrentMediaItemTracker {

@Test
fun testRelease() = runTest {
val mediaItem = createMediaItem("M1")
val mediaItem = createMediaItemWithMediaId("M1")
val expected = listOf(EventState.IDLE)
analyticsCommander.simulateRelease(mediaItem)
Assert.assertEquals(expected, tracker.stateList)
}

@Test
fun testRestartAfterEnd() = runTest {
val mediaItem = createMediaItem("M1")
val mediaItem = createMediaItemWithMediaId("M1")
val expected = listOf(EventState.IDLE, EventState.START, EventState.EOF, EventState.START, EventState.EOF)
analyticsCommander.simulateItemStart(mediaItem)
analyticsCommander.simulateItemEnd(mediaItem)
Expand All @@ -157,15 +157,15 @@ class TestCurrentMediaItemTracker {
@Test
fun testMediaTransitionSeekToNext() = runTest {
val expectedStates = listOf(EventState.IDLE, EventState.START, EventState.END, EventState.START, EventState.EOF)
val mediaItem = createMediaItem("M1")
val mediaItem2 = createMediaItem("M2")
val mediaItem = createMediaItemWithMediaId("M1")
val mediaItem2 = createMediaItemWithMediaId("M2")
analyticsCommander.simulateItemStart(mediaItem)
analyticsCommander.simulateItemTransitionSeek(mediaItem, mediaItem2)
analyticsCommander.simulateItemEnd(mediaItem2)
Assert.assertEquals("Different Item", expectedStates, tracker.stateList)
tracker.clear()

val mediaItem3 = createMediaItem("M1")
val mediaItem3 = createMediaItemWithMediaId("M1")
analyticsCommander.simulateItemStart(mediaItem)
analyticsCommander.simulateItemTransitionSeek(mediaItem, mediaItem3)
analyticsCommander.simulateItemEnd(mediaItem3)
Expand All @@ -175,9 +175,9 @@ class TestCurrentMediaItemTracker {
@Test
fun testMediaItemTransitionWithAsyncItem() = runTest {
val expectedStates = listOf(EventState.IDLE, EventState.START, EventState.END, EventState.START, EventState.END)
val mediaItem = createMediaItem("M1")
val mediaItem = createMediaItemWithMediaId("M1")
val mediaItem2 = MediaItem.Builder().setMediaId("M2").build()
val mediaItem2Loaded = createMediaItem("M2")
val mediaItem2Loaded = createMediaItemWithMediaId("M2")
analyticsCommander.simulateItemStart(mediaItem)
analyticsCommander.simulateItemTransitionSeek(mediaItem, mediaItem2)
Assert.assertEquals(listOf(EventState.IDLE, EventState.START, EventState.END), tracker.stateList)
Expand All @@ -203,15 +203,15 @@ class TestCurrentMediaItemTracker {
@Test
fun testMediaTransitionSameItemAuto() = runTest {
val expectedStates = listOf(EventState.IDLE, EventState.START, EventState.EOF, EventState.START, EventState.EOF)
val mediaItem = createMediaItem("M1")
val mediaItem2 = createMediaItem("M2")
val mediaItem = createMediaItemWithMediaId("M1")
val mediaItem2 = createMediaItemWithMediaId("M2")
analyticsCommander.simulateItemStart(mediaItem)
analyticsCommander.simulateItemTransitionAuto(mediaItem, mediaItem2)
analyticsCommander.simulateItemEnd(mediaItem2)
Assert.assertEquals("Different Item", expectedStates, tracker.stateList)
tracker.clear()

val mediaItem3 = createMediaItem("M1")
val mediaItem3 = createMediaItemWithMediaId("M1")
analyticsCommander.simulateItemStart(mediaItem)
analyticsCommander.simulateItemTransitionAuto(mediaItem, mediaItem3)
analyticsCommander.simulateItemEnd(mediaItem3)
Expand All @@ -221,7 +221,7 @@ class TestCurrentMediaItemTracker {
@Test
fun testMediaTransitionRepeat() = runTest {
val expectedStates = listOf(EventState.IDLE, EventState.START, EventState.EOF, EventState.START)
val mediaItem = createMediaItem("M1")
val mediaItem = createMediaItemWithMediaId("M1")

analyticsCommander.simulateItemStart(mediaItem)
analyticsCommander.simulateItemTransitionRepeat(mediaItem)
Expand All @@ -231,7 +231,7 @@ class TestCurrentMediaItemTracker {

@Test
fun testMultipleStop() = runTest {
val mediaItem = createMediaItem("M1")
val mediaItem = createMediaItemWithMediaId("M1")
analyticsCommander.simulateItemStart(mediaItem)
analyticsCommander.simulateItemEnd(mediaItem)
analyticsCommander.simulateRelease(mediaItem)
Expand All @@ -242,7 +242,7 @@ class TestCurrentMediaItemTracker {

@Test
fun testStartEndDisableAtStartAnalytics() = runTest {
val mediaItem = createMediaItem("M1")
val mediaItem = createMediaItemWithMediaId("M1")
val expected = listOf(EventState.IDLE)
currentItemTracker.enabled = false
analyticsCommander.simulateItemStart(mediaItem)
Expand All @@ -252,7 +252,7 @@ class TestCurrentMediaItemTracker {

@Test
fun testStartEndToggleAnalytics() = runTest {
val mediaItem = createMediaItem("M1")
val mediaItem = createMediaItemWithMediaId("M1")
val expected = listOf(EventState.IDLE, EventState.START, EventState.END, EventState.START, EventState.EOF)
currentItemTracker.enabled = true
analyticsCommander.simulateItemStart(mediaItem)
Expand All @@ -266,7 +266,7 @@ class TestCurrentMediaItemTracker {
@Test
fun testStartAsyncLoadEndToggleAnalytics() = runTest {
val mediaItemEmpty = MediaItem.Builder().setMediaId("M1").build()
val mediaItemLoaded = createMediaItem("M1")
val mediaItemLoaded = createMediaItemWithMediaId("M1")
val expected = listOf(EventState.IDLE, EventState.START, EventState.END, EventState.START, EventState.EOF)
currentItemTracker.enabled = true
analyticsCommander.simulateItemStart(mediaItemEmpty)
Expand All @@ -281,7 +281,7 @@ class TestCurrentMediaItemTracker {
@Test
fun testStartAsyncLoadEndDisableAtEnd() = runTest {
val mediaItemEmpty = MediaItem.Builder().setMediaId("M1").build()
val mediaItemLoaded = createMediaItem("M1")
val mediaItemLoaded = createMediaItemWithMediaId("M1")
val expected = listOf(EventState.IDLE, EventState.START, EventState.EOF)
currentItemTracker.enabled = true
analyticsCommander.simulateItemStart(mediaItemEmpty)
Expand All @@ -293,7 +293,7 @@ class TestCurrentMediaItemTracker {

@Test
fun testStartRemoveItem() = runTest {
val mediaItem = createMediaItem("M1")
val mediaItem = createMediaItemWithMediaId("M1")
val expected = listOf(EventState.IDLE, EventState.START, EventState.END)
analyticsCommander.simulateItemStart(mediaItem)
analyticsCommander.simulateItemRemoved(mediaItem)
Expand All @@ -303,9 +303,9 @@ class TestCurrentMediaItemTracker {
companion object {
private val uri: Uri = mockk(relaxed = true)

fun createMediaItem(mediaId: String): MediaItem {
fun createMediaItemWithMediaId(mediaId: String): MediaItem {
every { uri.toString() } returns "https://host/media.mp4"
every { uri.equals(Any()) } returns true
every { uri == Any() } returns true
return MediaItem.Builder()
.setUri(uri)
.setMediaId(mediaId)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,30 +89,21 @@ class TestMediaItemTrackerList {
Assert.assertNull(trackerC)
}

private class ItemTrackerA : MediaItemTracker {
private open class EmptyItemTracker : MediaItemTracker {
override fun start(player: ExoPlayer, initialData: Any?) {
// Nothing
}

override fun stop(player: ExoPlayer, reason: MediaItemTracker.StopReason, positionMs: Long) {
// Nothing
}

}

private class ItemTrackerB : MediaItemTracker {
override fun start(player: ExoPlayer, initialData: Any?) {
}

override fun stop(player: ExoPlayer, reason: MediaItemTracker.StopReason, positionMs: Long) {
}
}
private class ItemTrackerA : EmptyItemTracker()

private open class ItemTrackerC : MediaItemTracker {
override fun start(player: ExoPlayer, initialData: Any?) {
}
private class ItemTrackerB : EmptyItemTracker()

override fun stop(player: ExoPlayer, reason: MediaItemTracker.StopReason, positionMs: Long) {
}
}
private open class ItemTrackerC : EmptyItemTracker()

private class ItemTrackerD : ItemTrackerC()
}
Loading

0 comments on commit 21042aa

Please sign in to comment.