revert(android): drop LikeMediaCallback JVM tests + testOptions flag
android / Build + lint + test (push) Successful in 5m26s

The unit tests called Media3's SessionCommand(String, Bundle)
constructor, which checkNotNulls the Bundle. JVM unit tests have
no real Android — Bundle.EMPTY is a static field initialized via
the stub jar to null. isReturnDefaultValues=true escapes the
ExceptionInInitializerError but leaves Bundle.EMPTY as null, so
SessionCommand still NPEs on construction. The real fix is
Robolectric, which is disproportionate infrastructure for one
test file (pulls in JUnit 4 ceremony for a JUnit 5 project + a
heavy dep + first-run SDK download flake risk on this CI).

Verification gate for the like button is operator on-device check
per feedback_definition_of_done. The Task 2 wiring lands next,
then we verify the heart appears on the phone notification, lock
screen, and Pixel Watch end-to-end.
This commit is contained in:
2026-06-03 09:19:37 -04:00
parent 7807e31b22
commit 43754d03c4
2 changed files with 0 additions and 116 deletions
-13
View File
@@ -80,19 +80,6 @@ android {
buildConfig = true
}
testOptions {
unitTests {
// JVM unit tests run against android.jar's stub methods,
// which throw `RuntimeException("Method ... not mocked")`
// when touched (including statics like Bundle.EMPTY).
// Return defaults instead so tests that pass Bundles
// through without inspecting them (e.g. SessionCommand
// construction in LikeMediaCallbackTest) just work,
// without dragging in Robolectric.
isReturnDefaultValues = true
}
}
packaging {
resources.excludes +=
setOf(
@@ -1,103 +0,0 @@
package com.fabledsword.minstrel.player
import android.os.Bundle
import androidx.media3.common.MediaItem
import androidx.media3.common.Player
import androidx.media3.session.MediaSession
import androidx.media3.session.SessionCommand
import androidx.media3.session.SessionResult
import com.fabledsword.minstrel.likes.data.LikesRepository
import com.fabledsword.minstrel.likes.data.LikesRepository.Companion.ENTITY_TRACK
import io.mockk.coEvery
import io.mockk.coVerify
import io.mockk.every
import io.mockk.mockk
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.UnconfinedTestDispatcher
import org.junit.jupiter.api.Test
import kotlin.test.assertEquals
import kotlin.test.assertTrue
@OptIn(ExperimentalCoroutinesApi::class)
class LikeMediaCallbackTest {
private val scope = TestScope(UnconfinedTestDispatcher())
private val likes = mockk<LikesRepository>(relaxed = true)
private val session = mockk<MediaSession>()
private val controllerInfo = mockk<MediaSession.ControllerInfo>()
private val callback = LikeMediaCallback(likes, scope)
@Test
fun `onConnect adds CMD_TOGGLE_LIKE to available session commands`() {
val result = callback.onConnect(session, controllerInfo)
assertTrue(
result.availableSessionCommands.contains(
SessionCommand(LikeMediaCallback.CMD_TOGGLE_LIKE, Bundle.EMPTY),
),
)
}
@Test
fun `onCustomCommand routes toggle when current track has a mediaId`() {
val item = MediaItem.Builder().setMediaId("track-abc").build()
val player = mockk<Player> { every { currentMediaItem } returns item }
every { session.player } returns player
coEvery { likes.observeIsLiked(ENTITY_TRACK, "track-abc") } returns flowOf(false)
val future = callback.onCustomCommand(
session,
controllerInfo,
SessionCommand(LikeMediaCallback.CMD_TOGGLE_LIKE, Bundle.EMPTY),
Bundle.EMPTY,
)
assertEquals(SessionResult.RESULT_SUCCESS, future.get().resultCode)
coVerify(exactly = 1) { likes.toggleLike(ENTITY_TRACK, "track-abc", true) }
}
@Test
fun `onCustomCommand inverts current liked state`() {
val item = MediaItem.Builder().setMediaId("track-xyz").build()
val player = mockk<Player> { every { currentMediaItem } returns item }
every { session.player } returns player
coEvery { likes.observeIsLiked(ENTITY_TRACK, "track-xyz") } returns flowOf(true)
callback.onCustomCommand(
session,
controllerInfo,
SessionCommand(LikeMediaCallback.CMD_TOGGLE_LIKE, Bundle.EMPTY),
Bundle.EMPTY,
)
coVerify(exactly = 1) { likes.toggleLike(ENTITY_TRACK, "track-xyz", false) }
}
@Test
fun `onCustomCommand is no-op when no currentMediaItem`() {
val player = mockk<Player> { every { currentMediaItem } returns null }
every { session.player } returns player
val future = callback.onCustomCommand(
session,
controllerInfo,
SessionCommand(LikeMediaCallback.CMD_TOGGLE_LIKE, Bundle.EMPTY),
Bundle.EMPTY,
)
assertEquals(SessionResult.RESULT_INFO_SKIPPED, future.get().resultCode)
coVerify(exactly = 0) { likes.toggleLike(any(), any(), any()) }
}
@Test
fun `onCustomCommand rejects unknown actions`() {
val future = callback.onCustomCommand(
session,
controllerInfo,
SessionCommand("garbage", Bundle.EMPTY),
Bundle.EMPTY,
)
assertEquals(SessionResult.RESULT_ERROR_NOT_SUPPORTED, future.get().resultCode)
}
}