Skip to content
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package app.muxtv

import app.muxtv.catalog.ChannelFavoriteMutationResult
import app.muxtv.catalog.ChannelPreferenceMutationResult
import app.muxtv.catalog.ChannelPreferencesRepository

internal object NoChannelPreferencesRepository : ChannelPreferencesRepository {
Expand All @@ -9,4 +10,27 @@ internal object NoChannelPreferencesRepository : ChannelPreferencesRepository {
channelId: String,
isFavorite: Boolean,
): ChannelFavoriteMutationResult = ChannelFavoriteMutationResult.NotFound

override suspend fun setHidden(
profileId: String,
channelId: String,
isHidden: Boolean,
): ChannelPreferenceMutationResult = ChannelPreferenceMutationResult.NotFound

override suspend fun setCustomName(
profileId: String,
channelId: String,
customName: String?,
): ChannelPreferenceMutationResult = ChannelPreferenceMutationResult.NotFound

override suspend fun setChannelNumber(
profileId: String,
channelId: String,
channelNumber: Int?,
): ChannelPreferenceMutationResult = ChannelPreferenceMutationResult.NotFound

override suspend fun resetCustomization(
profileId: String,
channelId: String,
): ChannelPreferenceMutationResult = ChannelPreferenceMutationResult.NotFound
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,40 @@ enum class ChannelFavoriteMutationResult {
NotFound,
}

enum class ChannelPreferenceMutationResult {
Applied,
Unchanged,
NotFound,
InvalidInput,
}

interface ChannelPreferencesRepository {
suspend fun setFavorite(
profileId: String,
channelId: String,
isFavorite: Boolean,
): ChannelFavoriteMutationResult

suspend fun setHidden(
profileId: String,
channelId: String,
isHidden: Boolean,
): ChannelPreferenceMutationResult

suspend fun setCustomName(
profileId: String,
channelId: String,
customName: String?,
): ChannelPreferenceMutationResult

suspend fun setChannelNumber(
profileId: String,
channelId: String,
channelNumber: Int?,
): ChannelPreferenceMutationResult

suspend fun resetCustomization(
profileId: String,
channelId: String,
): ChannelPreferenceMutationResult
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import androidx.room3.Room
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import app.muxtv.catalog.ChannelFavoriteMutationResult
import app.muxtv.catalog.ChannelPreferenceMutationResult
import app.muxtv.catalog.ChannelQuery
import app.muxtv.catalog.RejectAllPlaybackAccessPolicyResolver
import app.muxtv.catalog.UnhandledPlaybackReferenceResolver
Expand Down Expand Up @@ -98,11 +99,130 @@ class ChannelPreferencesRepositoryTest {
assertThat(channel.summary.channelNumber).isEqualTo("7")
}

@Test
fun hiddenMutationCreatesOverlayAndSupportsUnhide() = runTest {
assertThat(
channelPreferences.setHidden(PROFILE_ID, CHANNEL_ID, true),
).isEqualTo(ChannelPreferenceMutationResult.Applied)
assertThat(playbackCatalog.getChannel(PROFILE_ID, CHANNEL_ID)).isNull()

assertThat(
channelPreferences.setHidden(PROFILE_ID, CHANNEL_ID, true),
).isEqualTo(ChannelPreferenceMutationResult.Unchanged)

assertThat(
channelPreferences.setHidden(PROFILE_ID, CHANNEL_ID, false),
).isEqualTo(ChannelPreferenceMutationResult.Applied)
assertThat(playbackCatalog.getChannel(PROFILE_ID, CHANNEL_ID)).isNotNull()
}

@Test
fun customNameMutationTrimsAndPreservesOtherOverlayFields() = runTest {
database.catalogDao().insertOverlay(
UserChannelOverlayEntity(
profileId = PROFILE_ID,
canonicalChannelId = CHANNEL_ID,
isFavorite = true,
channelNumber = 7,
),
)

assertThat(
channelPreferences.setCustomName(PROFILE_ID, CHANNEL_ID, " My News "),
).isEqualTo(ChannelPreferenceMutationResult.Applied)

val channel = requireNotNull(playbackCatalog.getChannel(PROFILE_ID, CHANNEL_ID))
assertThat(channel.summary.displayName).isEqualTo("My News")
assertThat(channel.summary.channelNumber).isEqualTo("7")
assertThat(channel.summary.isFavorite).isTrue()

assertThat(
channelPreferences.setCustomName(PROFILE_ID, CHANNEL_ID, "My News"),
).isEqualTo(ChannelPreferenceMutationResult.Unchanged)
}

@Test
fun customNameMutationRejectsInvalidInputWithoutCreatingOverlay() = runTest {
assertThat(
channelPreferences.setCustomName(PROFILE_ID, CHANNEL_ID, " "),
).isEqualTo(ChannelPreferenceMutationResult.InvalidInput)
assertThat(
channelPreferences.setCustomName(PROFILE_ID, CHANNEL_ID, "News\u0000HD"),
).isEqualTo(ChannelPreferenceMutationResult.InvalidInput)
assertThat(
channelPreferences.setCustomName(PROFILE_ID, CHANNEL_ID, "N".repeat(129)),
).isEqualTo(ChannelPreferenceMutationResult.InvalidInput)
assertThat(database.catalogDao().countOverlays(PROFILE_ID)).isEqualTo(0)
}

@Test
fun channelNumberMutationPersistsValidNumberAndSupportsReset() = runTest {
assertThat(
channelPreferences.setChannelNumber(PROFILE_ID, CHANNEL_ID, 7),
).isEqualTo(ChannelPreferenceMutationResult.Applied)
assertThat(
requireNotNull(playbackCatalog.getChannel(PROFILE_ID, CHANNEL_ID)).summary.channelNumber,
).isEqualTo("7")

assertThat(
channelPreferences.setChannelNumber(PROFILE_ID, CHANNEL_ID, 0),
).isEqualTo(ChannelPreferenceMutationResult.InvalidInput)
assertThat(
channelPreferences.setChannelNumber(PROFILE_ID, CHANNEL_ID, 10_000),
).isEqualTo(ChannelPreferenceMutationResult.InvalidInput)

assertThat(
channelPreferences.setChannelNumber(PROFILE_ID, CHANNEL_ID, null),
).isEqualTo(ChannelPreferenceMutationResult.Applied)
assertThat(
requireNotNull(playbackCatalog.getChannel(PROFILE_ID, CHANNEL_ID)).summary.channelNumber,
).isEqualTo("10")
}

@Test
fun resetCustomizationRestoresProviderPresentationAndPreservesFavorite() = runTest {
database.catalogDao().insertOverlay(
UserChannelOverlayEntity(
profileId = PROFILE_ID,
canonicalChannelId = CHANNEL_ID,
isFavorite = true,
isHidden = true,
customName = "Hidden News",
channelNumber = 77,
),
)

assertThat(
channelPreferences.resetCustomization(PROFILE_ID, CHANNEL_ID),
).isEqualTo(ChannelPreferenceMutationResult.Applied)

val channel = requireNotNull(playbackCatalog.getChannel(PROFILE_ID, CHANNEL_ID))
assertThat(channel.summary.displayName).isEqualTo("News")
assertThat(channel.summary.channelNumber).isEqualTo("10")
assertThat(channel.summary.isFavorite).isTrue()

assertThat(
channelPreferences.resetCustomization(PROFILE_ID, CHANNEL_ID),
).isEqualTo(ChannelPreferenceMutationResult.Unchanged)
}

@Test
fun missingChannelReturnsNotFoundWithoutCreatingOverlay() = runTest {
assertThat(
channelPreferences.setFavorite(PROFILE_ID, "missing-channel", true),
).isEqualTo(ChannelFavoriteMutationResult.NotFound)
assertThat(
channelPreferences.setHidden(PROFILE_ID, "missing-channel", true),
).isEqualTo(ChannelPreferenceMutationResult.NotFound)
assertThat(
channelPreferences.setCustomName(PROFILE_ID, "missing-channel", "Missing"),
).isEqualTo(ChannelPreferenceMutationResult.NotFound)
assertThat(
channelPreferences.setChannelNumber(PROFILE_ID, "missing-channel", 1),
).isEqualTo(ChannelPreferenceMutationResult.NotFound)
assertThat(
channelPreferences.resetCustomization(PROFILE_ID, "missing-channel"),
).isEqualTo(ChannelPreferenceMutationResult.NotFound)
assertThat(database.catalogDao().countOverlays(PROFILE_ID)).isEqualTo(0)
}

Expand Down Expand Up @@ -134,6 +254,18 @@ class ChannelPreferencesRepositoryTest {
assertThat(
channelPreferences.setFavorite(PROFILE_ID, CHANNEL_ID, true),
).isEqualTo(ChannelFavoriteMutationResult.NotFound)
assertThat(
channelPreferences.setHidden(PROFILE_ID, CHANNEL_ID, true),
).isEqualTo(ChannelPreferenceMutationResult.NotFound)
assertThat(
channelPreferences.setCustomName(PROFILE_ID, CHANNEL_ID, "Old News"),
).isEqualTo(ChannelPreferenceMutationResult.NotFound)
assertThat(
channelPreferences.setChannelNumber(PROFILE_ID, CHANNEL_ID, 7),
).isEqualTo(ChannelPreferenceMutationResult.NotFound)
assertThat(
channelPreferences.resetCustomization(PROFILE_ID, CHANNEL_ID),
).isEqualTo(ChannelPreferenceMutationResult.NotFound)
assertThat(database.catalogDao().countOverlays(PROFILE_ID)).isEqualTo(0)
}

Expand Down
Loading