test(PlaybackState): add state machine transition tests
- Idle → Connecting, Connecting → Playing/Paused/Reconnecting/Idle - Playing → Paused/Reconnecting/Idle - Paused → Connecting - Reconnecting → Connecting/Idle - Stop from any state returns to Idle Made-with: Cursor
This commit is contained in:
@@ -0,0 +1,163 @@
|
||||
package xyz.cottongin.radio247.service
|
||||
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import xyz.cottongin.radio247.data.model.Station
|
||||
|
||||
class PlaybackStateMachineTest {
|
||||
|
||||
private lateinit var stateFlow: MutableStateFlow<PlaybackState>
|
||||
private val testStation = Station(
|
||||
id = 1L,
|
||||
name = "Test Station",
|
||||
url = "http://example.com/stream"
|
||||
)
|
||||
private val testUrls = listOf(
|
||||
"http://example.com/stream1",
|
||||
"http://example.com/stream2"
|
||||
)
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
stateFlow = MutableStateFlow(PlaybackState.Idle)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `idle to connecting on play`() {
|
||||
val newState = PlaybackState.Connecting(
|
||||
station = testStation,
|
||||
urls = testUrls,
|
||||
currentUrlIndex = 0
|
||||
)
|
||||
stateFlow.value = newState
|
||||
assertTrue(stateFlow.value is PlaybackState.Connecting)
|
||||
assertEquals(0, (stateFlow.value as PlaybackState.Connecting).currentUrlIndex)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `connecting to playing on engine started`() {
|
||||
stateFlow.value = PlaybackState.Connecting(station = testStation, urls = testUrls)
|
||||
val connectionStartedAt = System.currentTimeMillis()
|
||||
stateFlow.value = PlaybackState.Playing(
|
||||
station = testStation,
|
||||
sessionStartedAt = connectionStartedAt,
|
||||
connectionStartedAt = connectionStartedAt
|
||||
)
|
||||
assertTrue(stateFlow.value is PlaybackState.Playing)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `connecting advances URL index on connection failure`() {
|
||||
stateFlow.value = PlaybackState.Connecting(
|
||||
station = testStation, urls = testUrls, currentUrlIndex = 0
|
||||
)
|
||||
stateFlow.value = PlaybackState.Connecting(
|
||||
station = testStation, urls = testUrls, currentUrlIndex = 1
|
||||
)
|
||||
assertEquals(1, (stateFlow.value as PlaybackState.Connecting).currentUrlIndex)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `connecting to reconnecting when all URLs exhausted and stayConnected`() {
|
||||
stateFlow.value = PlaybackState.Connecting(
|
||||
station = testStation, urls = testUrls, currentUrlIndex = 1
|
||||
)
|
||||
stateFlow.value = PlaybackState.Reconnecting(
|
||||
station = testStation, attempt = 1, sessionStartedAt = 0L
|
||||
)
|
||||
assertTrue(stateFlow.value is PlaybackState.Reconnecting)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `connecting to idle when all URLs exhausted and not stayConnected`() {
|
||||
stateFlow.value = PlaybackState.Connecting(
|
||||
station = testStation, urls = testUrls, currentUrlIndex = 1
|
||||
)
|
||||
stateFlow.value = PlaybackState.Idle
|
||||
assertTrue(stateFlow.value is PlaybackState.Idle)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `playing to paused on user pause`() {
|
||||
val now = System.currentTimeMillis()
|
||||
stateFlow.value = PlaybackState.Playing(
|
||||
station = testStation, sessionStartedAt = now, connectionStartedAt = now
|
||||
)
|
||||
stateFlow.value = PlaybackState.Paused(
|
||||
station = testStation, sessionStartedAt = now
|
||||
)
|
||||
assertTrue(stateFlow.value is PlaybackState.Paused)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `playing to reconnecting on connection lost with stayConnected`() {
|
||||
val now = System.currentTimeMillis()
|
||||
stateFlow.value = PlaybackState.Playing(
|
||||
station = testStation, sessionStartedAt = now, connectionStartedAt = now
|
||||
)
|
||||
stateFlow.value = PlaybackState.Reconnecting(
|
||||
station = testStation, sessionStartedAt = now, attempt = 1
|
||||
)
|
||||
assertTrue(stateFlow.value is PlaybackState.Reconnecting)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `playing to idle on connection lost without stayConnected`() {
|
||||
val now = System.currentTimeMillis()
|
||||
stateFlow.value = PlaybackState.Playing(
|
||||
station = testStation, sessionStartedAt = now, connectionStartedAt = now
|
||||
)
|
||||
stateFlow.value = PlaybackState.Idle
|
||||
assertTrue(stateFlow.value is PlaybackState.Idle)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `paused to connecting on resume`() {
|
||||
val now = System.currentTimeMillis()
|
||||
stateFlow.value = PlaybackState.Paused(
|
||||
station = testStation, sessionStartedAt = now
|
||||
)
|
||||
stateFlow.value = PlaybackState.Connecting(
|
||||
station = testStation, urls = testUrls, currentUrlIndex = 0
|
||||
)
|
||||
assertTrue(stateFlow.value is PlaybackState.Connecting)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `reconnecting to connecting on retry`() {
|
||||
stateFlow.value = PlaybackState.Reconnecting(
|
||||
station = testStation, sessionStartedAt = 0L, attempt = 3
|
||||
)
|
||||
stateFlow.value = PlaybackState.Connecting(
|
||||
station = testStation, urls = testUrls, currentUrlIndex = 0
|
||||
)
|
||||
assertTrue(stateFlow.value is PlaybackState.Connecting)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `reconnecting to idle on user stop`() {
|
||||
stateFlow.value = PlaybackState.Reconnecting(
|
||||
station = testStation, sessionStartedAt = 0L, attempt = 2
|
||||
)
|
||||
stateFlow.value = PlaybackState.Idle
|
||||
assertTrue(stateFlow.value is PlaybackState.Idle)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `stop from any state returns to idle`() {
|
||||
val states = listOf(
|
||||
PlaybackState.Connecting(station = testStation, urls = testUrls),
|
||||
PlaybackState.Playing(station = testStation, sessionStartedAt = 0L, connectionStartedAt = 0L),
|
||||
PlaybackState.Paused(station = testStation, sessionStartedAt = 0L),
|
||||
PlaybackState.Reconnecting(station = testStation, sessionStartedAt = 0L, attempt = 1)
|
||||
)
|
||||
for (state in states) {
|
||||
stateFlow.value = state
|
||||
stateFlow.value = PlaybackState.Idle
|
||||
assertTrue("Should be Idle after stop from $state", stateFlow.value is PlaybackState.Idle)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user