Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions radioplayer/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,9 @@ swiftklib {
}

kotlin {
androidTarget {
androidTarget {}
jvm()

}

val xcf = XCFramework()
listOf(
iosX64(),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package dev.markturnip.radioplayer

actual final class PlatformMediaPlayer actual constructor() {

private val stateCallbacks = mutableListOf<(PlaybackState) -> Unit>()
private val progressCallbacks = mutableListOf<(Progress) -> Unit>()

var currentState: PlaybackState = PlaybackState.STOPPED
private set

actual fun playItem(mediaPlayerItem: MediaPlayerItem) {
updateState(PlaybackState.PLAYING)
}

actual fun play() {
updateState(PlaybackState.PLAYING)
}

actual fun pause() {
updateState(PlaybackState.PAUSED)
}

actual fun stop() {
updateState(PlaybackState.STOPPED)
}

actual fun skip(delta: Double) {}

actual fun seekWithPosition(position: Double) {}

actual fun subscribeState(callback: (PlaybackState) -> Unit) {
stateCallbacks += callback
}

actual fun subscribeProgress(callback: (Progress) -> Unit) {
progressCallbacks += callback
}

fun emitProgress(progress: Progress) {
progressCallbacks.forEach { it(progress) }
}

private fun updateState(newState: PlaybackState) {
currentState = newState
stateCallbacks.forEach { it(newState) }
}
}
3 changes: 2 additions & 1 deletion settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,5 @@ dependencyResolutionManagement {
}

rootProject.name = "radioplayer-kt"
include(":radioplayer")
include(":radioplayer")
include(":tests")
20 changes: 20 additions & 0 deletions tests/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
plugins {
alias(libs.plugins.kotlinMultiplatform)
}

kotlin {
jvm()

listOf(
iosX64(),
iosArm64(),
iosSimulatorArm64()
)

sourceSets {
commonTest.dependencies {
implementation(libs.kotlin.test)
implementation(projects.radioplayer)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package dev.markturnip.radioplayer

import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertNull
import kotlin.test.assertTrue

class MediaPlayerItemTest {

private class TestMediaPlayerItem(
override val id: String,
override val title: String,
override val artist: String?,
override val url: String,
override val isLive: Boolean,
override val artworkUrl: String?
) : MediaPlayerItem

@Test
fun testLiveRadioStation() {
val station = TestMediaPlayerItem(
id = "station-1",
title = "BBC Radio 1",
artist = null,
url = "https://stream.example.com/radio1.mp3",
isLive = true,
artworkUrl = "https://example.com/artwork.png"
)
assertEquals("station-1", station.id)
assertEquals("BBC Radio 1", station.title)
assertNull(station.artist)
assertTrue(station.isLive)
assertEquals("https://stream.example.com/radio1.mp3", station.url)
assertEquals("https://example.com/artwork.png", station.artworkUrl)
}

@Test
fun testOnDemandTrack() {
val track = TestMediaPlayerItem(
id = "track-42",
title = "Blue (Da Ba Dee)",
artist = "Eiffel 65",
url = "https://stream.example.com/track42.mp3",
isLive = false,
artworkUrl = null
)
assertEquals("track-42", track.id)
assertEquals("Eiffel 65", track.artist)
assertFalse(track.isLive)
assertNull(track.artworkUrl)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package dev.markturnip.radioplayer

import kotlin.test.Test
import kotlin.test.assertEquals

class PlatformMediaPlayerTest {

private class TestMediaPlayerItem(
override val id: String = "test-id",
override val title: String = "Test Track",
override val artist: String? = "Test Artist",
override val url: String = "https://stream.example.com/test.mp3",
override val isLive: Boolean = false,
override val artworkUrl: String? = null
) : MediaPlayerItem

@Test
fun testPlayTransitionsToPlayingState() {
val player = PlatformMediaPlayer()
val states = mutableListOf<PlaybackState>()
player.subscribeState { states += it }

player.play()

assertEquals(listOf(PlaybackState.PLAYING), states)
}

@Test
fun testPauseTransitionsToPausedState() {
val player = PlatformMediaPlayer()
val states = mutableListOf<PlaybackState>()
player.subscribeState { states += it }

player.play()
player.pause()

assertEquals(listOf(PlaybackState.PLAYING, PlaybackState.PAUSED), states)
}

@Test
fun testStopTransitionsToStoppedState() {
val player = PlatformMediaPlayer()
val states = mutableListOf<PlaybackState>()
player.subscribeState { states += it }

player.play()
player.stop()

assertEquals(listOf(PlaybackState.PLAYING, PlaybackState.STOPPED), states)
}

@Test
fun testPlayItemTransitionsToPlayingState() {
val player = PlatformMediaPlayer()
val states = mutableListOf<PlaybackState>()
player.subscribeState { states += it }

player.playItem(TestMediaPlayerItem())

assertEquals(listOf(PlaybackState.PLAYING), states)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package dev.markturnip.radioplayer

import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertNotEquals
import kotlin.test.assertTrue

class PlaybackStateTest {

@Test
fun testAllStatesExist() {
val states = PlaybackState.entries
assertTrue(states.contains(PlaybackState.PLAYING))
assertTrue(states.contains(PlaybackState.PAUSED))
assertTrue(states.contains(PlaybackState.STOPPED))
assertTrue(states.contains(PlaybackState.BUFFERING))
assertTrue(states.contains(PlaybackState.ERROR))
}

@Test
fun testStateEquality() {
assertEquals(PlaybackState.PLAYING, PlaybackState.PLAYING)
assertNotEquals(PlaybackState.PLAYING, PlaybackState.PAUSED)
}

@Test
fun testStateNames() {
assertEquals("PLAYING", PlaybackState.PLAYING.name)
assertEquals("PAUSED", PlaybackState.PAUSED.name)
assertEquals("STOPPED", PlaybackState.STOPPED.name)
assertEquals("BUFFERING", PlaybackState.BUFFERING.name)
assertEquals("ERROR", PlaybackState.ERROR.name)
}

@Test
fun testStateCount() {
assertEquals(5, PlaybackState.entries.size)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package dev.markturnip.radioplayer

import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertNotEquals

class ProgressTest {

@Test
fun testEquality() {
val p1 = Progress(elapsed = 30.0, duration = 120.0)
val p2 = Progress(elapsed = 30.0, duration = 120.0)
assertEquals(p1, p2)
}

@Test
fun testInequality() {
val p1 = Progress(elapsed = 30.0, duration = 120.0)
val p2 = Progress(elapsed = 60.0, duration = 120.0)
assertNotEquals(p1, p2)
}

@Test
fun testCopy() {
val original = Progress(elapsed = 30.0, duration = 120.0)
val updated = original.copy(elapsed = 60.0)
assertEquals(60.0, updated.elapsed)
assertEquals(120.0, updated.duration)
}

@Test
fun testElapsedDurationRatio() {
val progress = Progress(elapsed = 30.0, duration = 120.0)
assertEquals(0.25, progress.elapsed / progress.duration)
}

@Test
fun testZeroElapsedWithNonZeroDuration() {
val progress = Progress(elapsed = 0.0, duration = 120.0)
assertEquals(0.0, progress.elapsed)
assertEquals(0.0, progress.elapsed / progress.duration)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package dev.markturnip.radioplayer

import kotlin.test.Test
import kotlin.test.assertEquals

class PlatformMediaPlayerJvmTest {

@Test
fun testInitialStateIsStopped() {
val player = PlatformMediaPlayer()
assertEquals(PlaybackState.STOPPED, player.currentState)
}

@Test
fun testCurrentStateReflectsPlayPauseStop() {
val player = PlatformMediaPlayer()
player.play()
assertEquals(PlaybackState.PLAYING, player.currentState)
player.pause()
assertEquals(PlaybackState.PAUSED, player.currentState)
player.stop()
assertEquals(PlaybackState.STOPPED, player.currentState)
}

@Test
fun testSubscribeProgressReceivesEmittedUpdates() {
val player = PlatformMediaPlayer()
val received = mutableListOf<Progress>()
player.subscribeProgress { received += it }

player.emitProgress(Progress(elapsed = 10.0, duration = 180.0))
player.emitProgress(Progress(elapsed = 20.0, duration = 180.0))

assertEquals(2, received.size)
assertEquals(10.0, received[0].elapsed)
assertEquals(20.0, received[1].elapsed)
}
}