diff --git a/app/src/main/kotlin/com/wire/android/ui/home/conversations/MessageExpiration.kt b/app/src/main/kotlin/com/wire/android/ui/home/conversations/MessageExpiration.kt index 94f40bd33a1..cb3b04720bb 100644 --- a/app/src/main/kotlin/com/wire/android/ui/home/conversations/MessageExpiration.kt +++ b/app/src/main/kotlin/com/wire/android/ui/home/conversations/MessageExpiration.kt @@ -17,8 +17,6 @@ */ package com.wire.android.ui.home.conversations -import android.content.Context -import android.content.res.Resources import androidx.annotation.VisibleForTesting import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect @@ -50,23 +48,44 @@ import kotlin.time.toDuration @Composable fun rememberSelfDeletionTimer(expirationStatus: ExpirationStatus): SelfDeletionTimerHelper.SelfDeletionTimerState { - val context = LocalContext.current + val stringResourceProvider: StringResourceProvider = stringResourceProvider() + val currentTimeProvider: CurrentTimeProvider = { Clock.System.now() } - return remember( - (expirationStatus as? ExpirationStatus.Expirable)?.selfDeletionStatus ?: true - ) { SelfDeletionTimerHelper(context).fromExpirationStatus(expirationStatus) } + return remember((expirationStatus as? ExpirationStatus.Expirable)?.selfDeletionStatus ?: true) { + SelfDeletionTimerHelper(stringResourceProvider, currentTimeProvider) + .fromExpirationStatus(expirationStatus) + } } -class SelfDeletionTimerHelper(private val context: Context) { +@Composable +private fun stringResourceProvider(): StringResourceProvider { + with(LocalContext.current.resources) { + return object : StringResourceProvider { + override fun quantityString(type: StringResourceType, quantity: Int): String = + getQuantityString( + when (type) { + StringResourceType.WEEKS -> R.plurals.weeks_left + StringResourceType.DAYS -> R.plurals.days_left + StringResourceType.HOURS -> R.plurals.hours_left + StringResourceType.MINUTES -> R.plurals.minutes_left + StringResourceType.SECONDS -> R.plurals.seconds_left + }, quantity, quantity + ) + } + } +} + +class SelfDeletionTimerHelper(private val stringResourceProvider: StringResourceProvider, private val currentTime: CurrentTimeProvider) { fun fromExpirationStatus(expirationStatus: ExpirationStatus): SelfDeletionTimerState { return if (expirationStatus is ExpirationStatus.Expirable) { with(expirationStatus) { val expireAt = calculateExpireAt(selfDeletionStatus, expireAfter) SelfDeletionTimerState.Expirable( - context.resources, + stringResourceProvider, expireAfter, expireAt, + currentTime ) } } else { @@ -87,9 +106,10 @@ class SelfDeletionTimerHelper(private val context: Context) { sealed class SelfDeletionTimerState { class Expirable( - private val resources: Resources, + private val stringResourceProvider: StringResourceProvider, private val expireAfter: Duration, private val expireAt: Instant, + private val currentTime: CurrentTimeProvider, ) : SelfDeletionTimerState() { companion object { /** @@ -115,60 +135,28 @@ class SelfDeletionTimerHelper(private val context: Context) { val timeLeftFormatted: String by derivedStateOf { when { timeLeft > 28.days -> - resources.getQuantityString( - R.plurals.weeks_left, - 4, - 4 - ) + stringResourceProvider.quantityString(StringResourceType.WEEKS, 4) // 4 weeks timeLeft >= 27.days && timeLeft <= 28.days -> - resources.getQuantityString( - R.plurals.weeks_left, - 4, - 4 - ) + stringResourceProvider.quantityString(StringResourceType.WEEKS, 4) // days below 4 weeks timeLeft <= 27.days && timeLeft > 7.days -> - resources.getQuantityString( - R.plurals.days_left, - timeLeft.inWholeDays.toInt(), - timeLeft.inWholeDays.toInt() - ) + stringResourceProvider.quantityString(StringResourceType.DAYS, timeLeft.inWholeDays.toInt()) // one week timeLeft >= 6.days && timeLeft <= 7.days -> - resources.getQuantityString( - R.plurals.weeks_left, - 1, - 1 - ) + stringResourceProvider.quantityString(StringResourceType.WEEKS, 1) // days below 1 week timeLeft < 7.days && timeLeft >= 1.days -> - resources.getQuantityString( - R.plurals.days_left, - timeLeft.inWholeDays.toInt(), - timeLeft.inWholeDays.toInt() - ) + stringResourceProvider.quantityString(StringResourceType.DAYS, timeLeft.inWholeDays.toInt()) // hours below one day timeLeft >= 1.hours && timeLeft < 24.hours -> - resources.getQuantityString( - R.plurals.hours_left, - timeLeft.inWholeHours.toInt(), - timeLeft.inWholeHours.toInt() - ) + stringResourceProvider.quantityString(StringResourceType.HOURS, timeLeft.inWholeHours.toInt()) // minutes below hour timeLeft >= 1.minutes && timeLeft < 60.minutes -> - resources.getQuantityString( - R.plurals.minutes_left, - timeLeft.inWholeMinutes.toInt(), - timeLeft.inWholeMinutes.toInt() - ) + stringResourceProvider.quantityString(StringResourceType.MINUTES, timeLeft.inWholeMinutes.toInt()) // seconds below minute timeLeft < 60.seconds -> - resources.getQuantityString( - R.plurals.seconds_left, - timeLeft.inWholeSeconds.toInt(), - timeLeft.inWholeSeconds.toInt() - ) + stringResourceProvider.quantityString(StringResourceType.SECONDS, timeLeft.inWholeSeconds.toInt()) else -> throw IllegalStateException("Not possible state for a time left label") } @@ -327,8 +315,10 @@ class SelfDeletionTimerHelper(private val context: Context) { object NotExpirable : SelfDeletionTimerState() } +} - companion object { - fun currentTime(): Instant = Clock.System.now() - } +typealias CurrentTimeProvider = () -> Instant +enum class StringResourceType { WEEKS, DAYS, HOURS, MINUTES, SECONDS; } +interface StringResourceProvider { + fun quantityString(type: StringResourceType, quantity: Int): String } diff --git a/app/src/androidTest/java/com/wire/android/SelfDeletionTimerTest.kt b/app/src/test/kotlin/com/wire/android/SelfDeletionTimerTest.kt similarity index 68% rename from app/src/androidTest/java/com/wire/android/SelfDeletionTimerTest.kt rename to app/src/test/kotlin/com/wire/android/SelfDeletionTimerTest.kt index cca20017c6c..e626114820a 100644 --- a/app/src/androidTest/java/com/wire/android/SelfDeletionTimerTest.kt +++ b/app/src/test/kotlin/com/wire/android/SelfDeletionTimerTest.kt @@ -17,20 +17,18 @@ */ package com.wire.android -import androidx.test.platform.app.InstrumentationRegistry +import com.wire.android.ui.home.conversations.CurrentTimeProvider import com.wire.android.ui.home.conversations.SelfDeletionTimerHelper +import com.wire.android.ui.home.conversations.StringResourceProvider +import com.wire.android.ui.home.conversations.StringResourceType import com.wire.android.ui.home.conversations.model.ExpirationStatus import com.wire.kalium.logic.data.message.Message -import io.mockk.every -import io.mockk.mockkObject -import io.mockk.unmockkObject import kotlinx.coroutines.test.StandardTestDispatcher +import kotlinx.coroutines.test.TestDispatcher import kotlinx.coroutines.test.advanceTimeBy import kotlinx.coroutines.test.runTest import kotlinx.datetime.Instant -import org.junit.After -import org.junit.Before -import org.junit.Test +import org.junit.jupiter.api.Test import kotlin.time.Duration.Companion.days import kotlin.time.Duration.Companion.hours import kotlin.time.Duration.Companion.milliseconds @@ -39,26 +37,12 @@ import kotlin.time.Duration.Companion.seconds class SelfDeletionTimerTest { - private val selfDeletionTimer by lazy { - SelfDeletionTimerHelper(context = InstrumentationRegistry.getInstrumentation().targetContext) - } private val dispatcher = StandardTestDispatcher() - private fun currentTime(): Instant = Instant.fromEpochMilliseconds(dispatcher.scheduler.currentTime) - - @Before - fun setUp() { - mockkObject(SelfDeletionTimerHelper.Companion) - every { SelfDeletionTimerHelper.Companion.currentTime() } answers { currentTime() } - } - - @After - fun cleanUp() { - unmockkObject(SelfDeletionTimerHelper.Companion) - } @Test fun givenTimeLeftIsAboveOneHour_whenGettingTheUpdateInterval_ThenIsEqualToMinutesLeftTillWholeHour() = runTest(dispatcher) { - val selfDeletionTimer = selfDeletionTimer.fromExpirationStatus( + val (_, selfDeletionTimerHelper) = Arrangement(dispatcher).arrange() + val selfDeletionTimer = selfDeletionTimerHelper.fromExpirationStatus( ExpirationStatus.Expirable( expireAfter = 23.hours + 30.minutes, selfDeletionStatus = Message.ExpirationData.SelfDeletionStatus.NotStarted @@ -71,7 +55,8 @@ class SelfDeletionTimerTest { @Test fun givenTimeLeftIsEqualToWholeHour_whenGettingTheUpdateInterval_ThenIsEqualToOneMinute() = runTest(dispatcher) { - val selfDeletionTimer = selfDeletionTimer.fromExpirationStatus( + val (_, selfDeletionTimerHelper) = Arrangement(dispatcher).arrange() + val selfDeletionTimer = selfDeletionTimerHelper.fromExpirationStatus( ExpirationStatus.Expirable( expireAfter = 23.hours, selfDeletionStatus = Message.ExpirationData.SelfDeletionStatus.NotStarted @@ -84,7 +69,8 @@ class SelfDeletionTimerTest { @Test fun givenTimeLeftIsEqualToOneHour_whenGettingTheUpdateInterval_ThenIsEqualToOneMinute() = runTest(dispatcher) { - val selfDeletionTimer = selfDeletionTimer.fromExpirationStatus( + val (_, selfDeletionTimerHelper) = Arrangement(dispatcher).arrange() + val selfDeletionTimer = selfDeletionTimerHelper.fromExpirationStatus( ExpirationStatus.Expirable( expireAfter = 1.hours, selfDeletionStatus = Message.ExpirationData.SelfDeletionStatus.NotStarted @@ -97,7 +83,8 @@ class SelfDeletionTimerTest { @Test fun givenTimeLeftIsEqualToOneMinute_whenGettingTheUpdateInterval_ThenIsEqualToOneSeconds() = runTest(dispatcher) { - val selfDeletionTimer = selfDeletionTimer.fromExpirationStatus( + val (_, selfDeletionTimerHelper) = Arrangement(dispatcher).arrange() + val selfDeletionTimer = selfDeletionTimerHelper.fromExpirationStatus( ExpirationStatus.Expirable( expireAfter = 1.minutes, selfDeletionStatus = Message.ExpirationData.SelfDeletionStatus.NotStarted @@ -110,7 +97,8 @@ class SelfDeletionTimerTest { @Test fun givenTimeLeftIsEqualTo1Min10SecAnd900Millis_whenGettingTheUpdateInterval_ThenIsEqualTo10SecAnd900Millis() = runTest(dispatcher) { - val selfDeletionTimer = selfDeletionTimer.fromExpirationStatus( + val (_, selfDeletionTimerHelper) = Arrangement(dispatcher).arrange() + val selfDeletionTimer = selfDeletionTimerHelper.fromExpirationStatus( ExpirationStatus.Expirable( expireAfter = 1.minutes + 10.seconds + 900.milliseconds, selfDeletionStatus = Message.ExpirationData.SelfDeletionStatus.NotStarted @@ -122,8 +110,9 @@ class SelfDeletionTimerTest { } @Test - fun givenTimeLeftIsEqualToThirtySeconds_whenGettingTheUpdateInterval_ThenIsEqualToOneSeconds() { - val selfDeletionTimer = selfDeletionTimer.fromExpirationStatus( + fun givenTimeLeftIsEqualToThirtySeconds_whenGettingTheUpdateInterval_ThenIsEqualToOneSeconds() = runTest(dispatcher) { + val (_, selfDeletionTimerHelper) = Arrangement(dispatcher).arrange() + val selfDeletionTimer = selfDeletionTimerHelper.fromExpirationStatus( ExpirationStatus.Expirable( expireAfter = 30.seconds, selfDeletionStatus = Message.ExpirationData.SelfDeletionStatus.NotStarted @@ -136,7 +125,8 @@ class SelfDeletionTimerTest { @Test fun givenTimeLeftIsEqualToFiftyDays_whenGettingThTimeLeftFormatted_ThenIsEqualToFourWeeksLeft() = runTest(dispatcher) { - val selfDeletionTimer = selfDeletionTimer.fromExpirationStatus( + val (arrangement, selfDeletionTimerHelper) = Arrangement(dispatcher).arrange() + val selfDeletionTimer = selfDeletionTimerHelper.fromExpirationStatus( ExpirationStatus.Expirable( expireAfter = 50.days, selfDeletionStatus = Message.ExpirationData.SelfDeletionStatus.NotStarted @@ -144,12 +134,13 @@ class SelfDeletionTimerTest { ) assert(selfDeletionTimer is SelfDeletionTimerHelper.SelfDeletionTimerState.Expirable) val timeLeftLabel = (selfDeletionTimer as SelfDeletionTimerHelper.SelfDeletionTimerState.Expirable).timeLeftFormatted - assert(timeLeftLabel == "4 weeks left") + assert(timeLeftLabel == arrangement.stringsProvider.quantityString(StringResourceType.WEEKS, 4)) } @Test fun givenTimeLeftIsEqualToTwentySevenDays_whenGettingThTimeLeftFormatted_ThenIsEqualToFourWeeksLeft() = runTest(dispatcher) { - val selfDeletionTimer = selfDeletionTimer.fromExpirationStatus( + val (arrangement, selfDeletionTimerHelper) = Arrangement(dispatcher).arrange() + val selfDeletionTimer = selfDeletionTimerHelper.fromExpirationStatus( ExpirationStatus.Expirable( expireAfter = 27.days, selfDeletionStatus = Message.ExpirationData.SelfDeletionStatus.NotStarted @@ -157,12 +148,13 @@ class SelfDeletionTimerTest { ) assert(selfDeletionTimer is SelfDeletionTimerHelper.SelfDeletionTimerState.Expirable) val timeLeftLabel = (selfDeletionTimer as SelfDeletionTimerHelper.SelfDeletionTimerState.Expirable).timeLeftFormatted - assert(timeLeftLabel == "4 weeks left") + assert(timeLeftLabel == arrangement.stringsProvider.quantityString(StringResourceType.WEEKS, 4)) } @Test fun givenTimeLeftIsEqualTo27DaysAnd12Hours_whenGettingThTimeLeftFormatted_ThenIsEqualToFourWeeksLeft() = runTest(dispatcher) { - val selfDeletionTimer = selfDeletionTimer.fromExpirationStatus( + val (arrangement, selfDeletionTimerHelper) = Arrangement(dispatcher).arrange() + val selfDeletionTimer = selfDeletionTimerHelper.fromExpirationStatus( ExpirationStatus.Expirable( expireAfter = 27.days + 12.hours, selfDeletionStatus = Message.ExpirationData.SelfDeletionStatus.NotStarted @@ -170,12 +162,13 @@ class SelfDeletionTimerTest { ) assert(selfDeletionTimer is SelfDeletionTimerHelper.SelfDeletionTimerState.Expirable) val timeLeftLabel = (selfDeletionTimer as SelfDeletionTimerHelper.SelfDeletionTimerState.Expirable).timeLeftFormatted - assert(timeLeftLabel == "4 weeks left") + assert(timeLeftLabel == arrangement.stringsProvider.quantityString(StringResourceType.WEEKS, 4)) } @Test fun givenTimeLeftIsEqualTo27DaysAnd1Second_whenGettingThTimeLeftFormatted_ThenIsEqualToFourWeeksLeft() = runTest(dispatcher) { - val selfDeletionTimer = selfDeletionTimer.fromExpirationStatus( + val (arrangement, selfDeletionTimerHelper) = Arrangement(dispatcher).arrange() + val selfDeletionTimer = selfDeletionTimerHelper.fromExpirationStatus( ExpirationStatus.Expirable( expireAfter = 27.days + 1.seconds, selfDeletionStatus = Message.ExpirationData.SelfDeletionStatus.NotStarted @@ -183,12 +176,13 @@ class SelfDeletionTimerTest { ) assert(selfDeletionTimer is SelfDeletionTimerHelper.SelfDeletionTimerState.Expirable) val timeLeftLabel = (selfDeletionTimer as SelfDeletionTimerHelper.SelfDeletionTimerState.Expirable).timeLeftFormatted - assert(timeLeftLabel == "4 weeks left") + assert(timeLeftLabel == arrangement.stringsProvider.quantityString(StringResourceType.WEEKS, 4)) } @Test fun givenTimeLeftIsEqualTo28Days_whenGettingThTimeLeftFormatted_ThenIsEqualToFourWeeksLeft() = runTest(dispatcher) { - val selfDeletionTimer = selfDeletionTimer.fromExpirationStatus( + val (arrangement, selfDeletionTimerHelper) = Arrangement(dispatcher).arrange() + val selfDeletionTimer = selfDeletionTimerHelper.fromExpirationStatus( ExpirationStatus.Expirable( expireAfter = 28.days, selfDeletionStatus = Message.ExpirationData.SelfDeletionStatus.NotStarted @@ -196,12 +190,13 @@ class SelfDeletionTimerTest { ) assert(selfDeletionTimer is SelfDeletionTimerHelper.SelfDeletionTimerState.Expirable) val timeLeftLabel = (selfDeletionTimer as SelfDeletionTimerHelper.SelfDeletionTimerState.Expirable).timeLeftFormatted - assert(timeLeftLabel == "4 weeks left") + assert(timeLeftLabel == arrangement.stringsProvider.quantityString(StringResourceType.WEEKS, 4)) } @Test fun givenTimeLeftIsEqualTo21Days_whenGettingThTimeLeftFormatted_ThenIsEqualToTwentyOneLeft() = runTest(dispatcher) { - val selfDeletionTimer = selfDeletionTimer.fromExpirationStatus( + val (arrangement, selfDeletionTimerHelper) = Arrangement(dispatcher).arrange() + val selfDeletionTimer = selfDeletionTimerHelper.fromExpirationStatus( ExpirationStatus.Expirable( expireAfter = 21.days, selfDeletionStatus = Message.ExpirationData.SelfDeletionStatus.NotStarted @@ -209,12 +204,13 @@ class SelfDeletionTimerTest { ) assert(selfDeletionTimer is SelfDeletionTimerHelper.SelfDeletionTimerState.Expirable) val timeLeftLabel = (selfDeletionTimer as SelfDeletionTimerHelper.SelfDeletionTimerState.Expirable).timeLeftFormatted - assert(timeLeftLabel == "21 days left") + assert(timeLeftLabel == arrangement.stringsProvider.quantityString(StringResourceType.DAYS, 21)) } @Test fun givenTimeLeftIsEqualTo14Days_whenGettingThTimeLeftFormatted_ThenIsEqualToFourTeenDaysLeft() = runTest(dispatcher) { - val selfDeletionTimer = selfDeletionTimer.fromExpirationStatus( + val (arrangement, selfDeletionTimerHelper) = Arrangement(dispatcher).arrange() + val selfDeletionTimer = selfDeletionTimerHelper.fromExpirationStatus( ExpirationStatus.Expirable( expireAfter = 14.days, selfDeletionStatus = Message.ExpirationData.SelfDeletionStatus.NotStarted @@ -222,12 +218,13 @@ class SelfDeletionTimerTest { ) assert(selfDeletionTimer is SelfDeletionTimerHelper.SelfDeletionTimerState.Expirable) val timeLeftLabel = (selfDeletionTimer as SelfDeletionTimerHelper.SelfDeletionTimerState.Expirable).timeLeftFormatted - assert(timeLeftLabel == "14 days left") + assert(timeLeftLabel == arrangement.stringsProvider.quantityString(StringResourceType.DAYS, 14)) } @Test fun givenTimeLeftIsEqualTo20Days_whenGettingThTimeLeftFormatted_ThenIsEqualToTwentyDaysLeft() = runTest(dispatcher) { - val selfDeletionTimer = selfDeletionTimer.fromExpirationStatus( + val (arrangement, selfDeletionTimerHelper) = Arrangement(dispatcher).arrange() + val selfDeletionTimer = selfDeletionTimerHelper.fromExpirationStatus( ExpirationStatus.Expirable( expireAfter = 20.days, selfDeletionStatus = Message.ExpirationData.SelfDeletionStatus.NotStarted @@ -235,12 +232,13 @@ class SelfDeletionTimerTest { ) assert(selfDeletionTimer is SelfDeletionTimerHelper.SelfDeletionTimerState.Expirable) val timeLeftLabel = (selfDeletionTimer as SelfDeletionTimerHelper.SelfDeletionTimerState.Expirable).timeLeftFormatted - assert(timeLeftLabel == "20 days left") + assert(timeLeftLabel == arrangement.stringsProvider.quantityString(StringResourceType.DAYS, 20)) } @Test fun givenTimeLeftIsEqualToSevenDays_whenGettingThTimeLeftFormatted_ThenIsEqualToOneWeekLeft() = runTest(dispatcher) { - val selfDeletionTimer = selfDeletionTimer.fromExpirationStatus( + val (arrangement, selfDeletionTimerHelper) = Arrangement(dispatcher).arrange() + val selfDeletionTimer = selfDeletionTimerHelper.fromExpirationStatus( ExpirationStatus.Expirable( expireAfter = 7.days, selfDeletionStatus = Message.ExpirationData.SelfDeletionStatus.NotStarted @@ -248,12 +246,13 @@ class SelfDeletionTimerTest { ) assert(selfDeletionTimer is SelfDeletionTimerHelper.SelfDeletionTimerState.Expirable) val timeLeftLabel = (selfDeletionTimer as SelfDeletionTimerHelper.SelfDeletionTimerState.Expirable).timeLeftFormatted - assert(timeLeftLabel == "1 week left") + assert(timeLeftLabel == arrangement.stringsProvider.quantityString(StringResourceType.WEEKS, 1)) } @Test fun givenTimeLeftIsEqualToSixDays_whenGettingThTimeLeftFormatted_ThenIsEqualToOneWeekLeft() = runTest(dispatcher) { - val selfDeletionTimer = selfDeletionTimer.fromExpirationStatus( + val (arrangement, selfDeletionTimerHelper) = Arrangement(dispatcher).arrange() + val selfDeletionTimer = selfDeletionTimerHelper.fromExpirationStatus( ExpirationStatus.Expirable( expireAfter = 6.days, selfDeletionStatus = Message.ExpirationData.SelfDeletionStatus.NotStarted @@ -261,12 +260,13 @@ class SelfDeletionTimerTest { ) assert(selfDeletionTimer is SelfDeletionTimerHelper.SelfDeletionTimerState.Expirable) val timeLeftLabel = (selfDeletionTimer as SelfDeletionTimerHelper.SelfDeletionTimerState.Expirable).timeLeftFormatted - assert(timeLeftLabel == "1 week left") + assert(timeLeftLabel == arrangement.stringsProvider.quantityString(StringResourceType.WEEKS, 1)) } @Test fun givenTimeLeftIsEqualToSixDaysAnd12Hours_whenGettingThTimeLeftFormatted_ThenIsEqualToOneWeekLeft() = runTest(dispatcher) { - val selfDeletionTimer = selfDeletionTimer.fromExpirationStatus( + val (arrangement, selfDeletionTimerHelper) = Arrangement(dispatcher).arrange() + val selfDeletionTimer = selfDeletionTimerHelper.fromExpirationStatus( ExpirationStatus.Expirable( expireAfter = 6.days + 12.hours, selfDeletionStatus = Message.ExpirationData.SelfDeletionStatus.NotStarted @@ -274,12 +274,13 @@ class SelfDeletionTimerTest { ) assert(selfDeletionTimer is SelfDeletionTimerHelper.SelfDeletionTimerState.Expirable) val timeLeftLabel = (selfDeletionTimer as SelfDeletionTimerHelper.SelfDeletionTimerState.Expirable).timeLeftFormatted - assert(timeLeftLabel == "1 week left") + assert(timeLeftLabel == arrangement.stringsProvider.quantityString(StringResourceType.WEEKS, 1)) } @Test fun givenTimeLeftIsEqualToSixDaysAndOneSecond_whenGettingThTimeLeftFormatted_ThenIsEqualToOneWeekLeft() = runTest(dispatcher) { - val selfDeletionTimer = selfDeletionTimer.fromExpirationStatus( + val (arrangement, selfDeletionTimerHelper) = Arrangement(dispatcher).arrange() + val selfDeletionTimer = selfDeletionTimerHelper.fromExpirationStatus( ExpirationStatus.Expirable( expireAfter = 6.days + 1.seconds, selfDeletionStatus = Message.ExpirationData.SelfDeletionStatus.NotStarted @@ -287,12 +288,13 @@ class SelfDeletionTimerTest { ) assert(selfDeletionTimer is SelfDeletionTimerHelper.SelfDeletionTimerState.Expirable) val timeLeftLabel = (selfDeletionTimer as SelfDeletionTimerHelper.SelfDeletionTimerState.Expirable).timeLeftFormatted - assert(timeLeftLabel == "1 week left") + assert(timeLeftLabel == arrangement.stringsProvider.quantityString(StringResourceType.WEEKS, 1)) } @Test fun givenTimeLeftIsEqualToThirteenDays_whenGettingThTimeLeftFormatted_ThenIsEqualToThirteenDays() = runTest(dispatcher) { - val selfDeletionTimer = selfDeletionTimer.fromExpirationStatus( + val (arrangement, selfDeletionTimerHelper) = Arrangement(dispatcher).arrange() + val selfDeletionTimer = selfDeletionTimerHelper.fromExpirationStatus( ExpirationStatus.Expirable( expireAfter = 13.days, selfDeletionStatus = Message.ExpirationData.SelfDeletionStatus.NotStarted @@ -300,12 +302,13 @@ class SelfDeletionTimerTest { ) assert(selfDeletionTimer is SelfDeletionTimerHelper.SelfDeletionTimerState.Expirable) val timeLeftLabel = (selfDeletionTimer as SelfDeletionTimerHelper.SelfDeletionTimerState.Expirable).timeLeftFormatted - assert(timeLeftLabel == "13 days left") + assert(timeLeftLabel == arrangement.stringsProvider.quantityString(StringResourceType.DAYS, 13)) } @Test fun givenTimeLeftIsEqualToOneDay_whenGettingThTimeLeftFormatted_ThenIsEqualToOneDayLeft() = runTest(dispatcher) { - val selfDeletionTimer = selfDeletionTimer.fromExpirationStatus( + val (arrangement, selfDeletionTimerHelper) = Arrangement(dispatcher).arrange() + val selfDeletionTimer = selfDeletionTimerHelper.fromExpirationStatus( ExpirationStatus.Expirable( expireAfter = 1.days, selfDeletionStatus = Message.ExpirationData.SelfDeletionStatus.NotStarted @@ -313,12 +316,13 @@ class SelfDeletionTimerTest { ) assert(selfDeletionTimer is SelfDeletionTimerHelper.SelfDeletionTimerState.Expirable) val timeLeftLabel = (selfDeletionTimer as SelfDeletionTimerHelper.SelfDeletionTimerState.Expirable).timeLeftFormatted - assert(timeLeftLabel == "1 day left") + assert(timeLeftLabel == arrangement.stringsProvider.quantityString(StringResourceType.DAYS, 1)) } @Test fun givenTimeLeftIsEqualToTwentyFourHours_whenGettingThTimeLeftFormatted_ThenIsEqualToOneDayLeft() = runTest(dispatcher) { - val selfDeletionTimer = selfDeletionTimer.fromExpirationStatus( + val (arrangement, selfDeletionTimerHelper) = Arrangement(dispatcher).arrange() + val selfDeletionTimer = selfDeletionTimerHelper.fromExpirationStatus( ExpirationStatus.Expirable( expireAfter = 24.hours, selfDeletionStatus = Message.ExpirationData.SelfDeletionStatus.NotStarted @@ -326,12 +330,13 @@ class SelfDeletionTimerTest { ) assert(selfDeletionTimer is SelfDeletionTimerHelper.SelfDeletionTimerState.Expirable) val timeLeftLabel = (selfDeletionTimer as SelfDeletionTimerHelper.SelfDeletionTimerState.Expirable).timeLeftFormatted - assert(timeLeftLabel == "1 day left") + assert(timeLeftLabel == arrangement.stringsProvider.quantityString(StringResourceType.DAYS, 1)) } @Test fun givenTimeLeftIsEqualToTwentyThreeHours_whenGettingThTimeLeftFormatted_ThenIsEqualToTwentyThreeHourLeft() = runTest(dispatcher) { - val selfDeletionTimer = selfDeletionTimer.fromExpirationStatus( + val (arrangement, selfDeletionTimerHelper) = Arrangement(dispatcher).arrange() + val selfDeletionTimer = selfDeletionTimerHelper.fromExpirationStatus( ExpirationStatus.Expirable( expireAfter = 23.hours, selfDeletionStatus = Message.ExpirationData.SelfDeletionStatus.NotStarted @@ -339,12 +344,13 @@ class SelfDeletionTimerTest { ) assert(selfDeletionTimer is SelfDeletionTimerHelper.SelfDeletionTimerState.Expirable) val timeLeftLabel = (selfDeletionTimer as SelfDeletionTimerHelper.SelfDeletionTimerState.Expirable).timeLeftFormatted - assert(timeLeftLabel == "23 hours left") + assert(timeLeftLabel == arrangement.stringsProvider.quantityString(StringResourceType.HOURS, 23)) } @Test fun givenTimeLeftIsEqualToSixtyMinutes_whenGettingThTimeLeftFormatted_ThenIsEqualToOneHourLeft() = runTest(dispatcher) { - val selfDeletionTimer = selfDeletionTimer.fromExpirationStatus( + val (arrangement, selfDeletionTimerHelper) = Arrangement(dispatcher).arrange() + val selfDeletionTimer = selfDeletionTimerHelper.fromExpirationStatus( ExpirationStatus.Expirable( expireAfter = 60.minutes, selfDeletionStatus = Message.ExpirationData.SelfDeletionStatus.NotStarted @@ -352,12 +358,13 @@ class SelfDeletionTimerTest { ) assert(selfDeletionTimer is SelfDeletionTimerHelper.SelfDeletionTimerState.Expirable) val timeLeftLabel = (selfDeletionTimer as SelfDeletionTimerHelper.SelfDeletionTimerState.Expirable).timeLeftFormatted - assert(timeLeftLabel == "1 hour left") + assert(timeLeftLabel == arrangement.stringsProvider.quantityString(StringResourceType.HOURS, 1)) } @Test fun givenTimeLeftIsEqualToOneMinute_whenGettingThTimeLeftFormatted_ThenIsEqualToOneMinuteLeft() = runTest(dispatcher) { - val selfDeletionTimer = selfDeletionTimer.fromExpirationStatus( + val (arrangement, selfDeletionTimerHelper) = Arrangement(dispatcher).arrange() + val selfDeletionTimer = selfDeletionTimerHelper.fromExpirationStatus( ExpirationStatus.Expirable( expireAfter = 1.minutes, selfDeletionStatus = Message.ExpirationData.SelfDeletionStatus.NotStarted @@ -365,12 +372,13 @@ class SelfDeletionTimerTest { ) assert(selfDeletionTimer is SelfDeletionTimerHelper.SelfDeletionTimerState.Expirable) val timeLeftLabel = (selfDeletionTimer as SelfDeletionTimerHelper.SelfDeletionTimerState.Expirable).timeLeftFormatted - assert(timeLeftLabel == "1 minute left") + assert(timeLeftLabel == arrangement.stringsProvider.quantityString(StringResourceType.MINUTES, 1)) } @Test fun givenTimeLeftIsEqualToOFiftyNineMinutes_whenGettingThTimeLeftFormatted_ThenIsEqualToFiftyNineMinutes() = runTest(dispatcher) { - val selfDeletionTimer = selfDeletionTimer.fromExpirationStatus( + val (arrangement, selfDeletionTimerHelper) = Arrangement(dispatcher).arrange() + val selfDeletionTimer = selfDeletionTimerHelper.fromExpirationStatus( ExpirationStatus.Expirable( expireAfter = 59.minutes, selfDeletionStatus = Message.ExpirationData.SelfDeletionStatus.NotStarted @@ -378,12 +386,13 @@ class SelfDeletionTimerTest { ) assert(selfDeletionTimer is SelfDeletionTimerHelper.SelfDeletionTimerState.Expirable) val timeLeftLabel = (selfDeletionTimer as SelfDeletionTimerHelper.SelfDeletionTimerState.Expirable).timeLeftFormatted - assert(timeLeftLabel == "59 minutes left") + assert(timeLeftLabel == arrangement.stringsProvider.quantityString(StringResourceType.MINUTES, 59)) } @Test fun givenTimeLeftIsEqualToSixtySeconds_whenGettingThTimeLeftFormatted_ThenIsEqualToOneMinute() = runTest(dispatcher) { - val selfDeletionTimer = selfDeletionTimer.fromExpirationStatus( + val (arrangement, selfDeletionTimerHelper) = Arrangement(dispatcher).arrange() + val selfDeletionTimer = selfDeletionTimerHelper.fromExpirationStatus( ExpirationStatus.Expirable( expireAfter = 60.seconds, selfDeletionStatus = Message.ExpirationData.SelfDeletionStatus.NotStarted @@ -391,12 +400,13 @@ class SelfDeletionTimerTest { ) assert(selfDeletionTimer is SelfDeletionTimerHelper.SelfDeletionTimerState.Expirable) val timeLeftLabel = (selfDeletionTimer as SelfDeletionTimerHelper.SelfDeletionTimerState.Expirable).timeLeftFormatted - assert(timeLeftLabel == "1 minute left") + assert(timeLeftLabel == arrangement.stringsProvider.quantityString(StringResourceType.MINUTES, 1)) } @Test fun givenTimeLeftIs1DayAnd12Hours_whenRecalculatingTimeAfterIntervals_thenTimeLeftIsEqualToExpected() = runTest(dispatcher) { - val selfDeletionTimer = selfDeletionTimer.fromExpirationStatus( + val (arrangement, selfDeletionTimerHelper) = Arrangement(dispatcher).arrange() + val selfDeletionTimer = selfDeletionTimerHelper.fromExpirationStatus( ExpirationStatus.Expirable( expireAfter = 1.days + 12.hours, selfDeletionStatus = Message.ExpirationData.SelfDeletionStatus.NotStarted @@ -406,17 +416,18 @@ class SelfDeletionTimerTest { with(selfDeletionTimer as SelfDeletionTimerHelper.SelfDeletionTimerState.Expirable) { advanceTimeBy(updateInterval()) recalculateTimeLeft() - assert(selfDeletionTimer.timeLeftFormatted == "1 day left") + assert(selfDeletionTimer.timeLeftFormatted == arrangement.stringsProvider.quantityString(StringResourceType.DAYS, 1)) advanceTimeBy(updateInterval()) recalculateTimeLeft() - assert(selfDeletionTimer.timeLeftFormatted == "23 hours left") + assert(selfDeletionTimer.timeLeftFormatted == arrangement.stringsProvider.quantityString(StringResourceType.HOURS, 23)) } } @Test fun givenTimeLeftIs23HoursAnd23Minutes_whenRecalculatingTimeAfterIntervals_thenTimeLeftIsEqualToExpected() = runTest(dispatcher) { - val selfDeletionTimer = selfDeletionTimer.fromExpirationStatus( + val (arrangement, selfDeletionTimerHelper) = Arrangement(dispatcher).arrange() + val selfDeletionTimer = selfDeletionTimerHelper.fromExpirationStatus( ExpirationStatus.Expirable( expireAfter = 23.hours + 23.minutes, selfDeletionStatus = Message.ExpirationData.SelfDeletionStatus.NotStarted @@ -426,13 +437,14 @@ class SelfDeletionTimerTest { with(selfDeletionTimer as SelfDeletionTimerHelper.SelfDeletionTimerState.Expirable) { advanceTimeBy(updateInterval()) recalculateTimeLeft() - assert(selfDeletionTimer.timeLeftFormatted == "23 hours left") + assert(selfDeletionTimer.timeLeftFormatted == arrangement.stringsProvider.quantityString(StringResourceType.HOURS, 23)) } } @Test fun givenTimeLeftIs1HourAnd12Minutes_whenRecalculatingTimeAfterIntervals_thenTimeLeftIsEqualToExpected() = runTest(dispatcher) { - val selfDeletionTimer = selfDeletionTimer.fromExpirationStatus( + val (arrangement, selfDeletionTimerHelper) = Arrangement(dispatcher).arrange() + val selfDeletionTimer = selfDeletionTimerHelper.fromExpirationStatus( ExpirationStatus.Expirable( expireAfter = 1.hours + 12.minutes, selfDeletionStatus = Message.ExpirationData.SelfDeletionStatus.NotStarted @@ -442,17 +454,18 @@ class SelfDeletionTimerTest { with(selfDeletionTimer as SelfDeletionTimerHelper.SelfDeletionTimerState.Expirable) { advanceTimeBy(updateInterval()) recalculateTimeLeft() - assert(selfDeletionTimer.timeLeftFormatted == "1 hour left") + assert(selfDeletionTimer.timeLeftFormatted == arrangement.stringsProvider.quantityString(StringResourceType.HOURS, 1)) advanceTimeBy(updateInterval()) recalculateTimeLeft() - assert(selfDeletionTimer.timeLeftFormatted == "59 minutes left") + assert(selfDeletionTimer.timeLeftFormatted == arrangement.stringsProvider.quantityString(StringResourceType.MINUTES, 59)) } } @Test fun givenTimeLeftIs1HourAnd23Seconds_whenRecalculatingTimeAfterIntervals_thenTimeLeftIsEqualToExpected() = runTest(dispatcher) { - val selfDeletionTimer = selfDeletionTimer.fromExpirationStatus( + val (arrangement, selfDeletionTimerHelper) = Arrangement(dispatcher).arrange() + val selfDeletionTimer = selfDeletionTimerHelper.fromExpirationStatus( ExpirationStatus.Expirable( expireAfter = 1.minutes + 23.seconds, selfDeletionStatus = Message.ExpirationData.SelfDeletionStatus.NotStarted @@ -462,11 +475,22 @@ class SelfDeletionTimerTest { with(selfDeletionTimer as SelfDeletionTimerHelper.SelfDeletionTimerState.Expirable) { advanceTimeBy(updateInterval()) recalculateTimeLeft() - assert(selfDeletionTimer.timeLeftFormatted == "1 minute left") + assert(selfDeletionTimer.timeLeftFormatted == arrangement.stringsProvider.quantityString(StringResourceType.MINUTES, 1)) advanceTimeBy(updateInterval()) recalculateTimeLeft() - assert(selfDeletionTimer.timeLeftFormatted == "59 seconds left") + assert(selfDeletionTimer.timeLeftFormatted == arrangement.stringsProvider.quantityString(StringResourceType.SECONDS, 59)) } } + + internal class Arrangement(val dispatcher: TestDispatcher) { + + val stringsProvider: StringResourceProvider = object : StringResourceProvider { + override fun quantityString(type: StringResourceType, quantity: Int): String = "${type.name}: $quantity" + } + private val currentTime: CurrentTimeProvider = { Instant.fromEpochMilliseconds(dispatcher.scheduler.currentTime) } + + private val selfDeletionTimerHelper by lazy { SelfDeletionTimerHelper(stringsProvider, currentTime) } + fun arrange() = this to selfDeletionTimerHelper + } }