Add unit test on count up timer
This commit is contained in:
parent
3f6b60c63d
commit
6f18c020ea
|
@ -53,4 +53,12 @@ android {
|
|||
|
||||
dependencies {
|
||||
implementation libs.jetbrains.coroutinesAndroid
|
||||
|
||||
// TESTS
|
||||
testImplementation libs.tests.junit
|
||||
testImplementation libs.tests.kluent
|
||||
testImplementation libs.mockk.mockk
|
||||
testImplementation(libs.jetbrains.coroutinesTest) {
|
||||
exclude group: "org.jetbrains.kotlinx", module: "kotlinx-coroutines-debug"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,22 +19,21 @@ package im.vector.lib.core.utils.timer
|
|||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.cancel
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import java.util.concurrent.atomic.AtomicLong
|
||||
|
||||
@OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class)
|
||||
class CountUpTimer(
|
||||
private val coroutineScope: CoroutineScope = CoroutineScope(Dispatchers.Main),
|
||||
private val clock: Clock = DefaultClock(),
|
||||
private val intervalInMs: Long = 1_000,
|
||||
initialTime: Long = 0L,
|
||||
) {
|
||||
|
||||
private val coroutineScope = CoroutineScope(Dispatchers.Main)
|
||||
private var counterJob: Job? = null
|
||||
|
||||
private val lastTime: AtomicLong = AtomicLong()
|
||||
private val lastTime: AtomicLong = AtomicLong(clock.epochMillis())
|
||||
private val elapsedTime: AtomicLong = AtomicLong(initialTime)
|
||||
|
||||
private fun startCounter() {
|
||||
|
@ -70,7 +69,7 @@ class CountUpTimer(
|
|||
|
||||
fun stop() {
|
||||
tickListener?.onTick(elapsedTime())
|
||||
coroutineScope.cancel()
|
||||
counterJob?.cancel()
|
||||
counterJob = null
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* Copyright (c) 2023 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.lib.core.utils.test.fakes
|
||||
|
||||
import im.vector.lib.core.utils.timer.Clock
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
|
||||
class FakeClock : Clock by mockk() {
|
||||
fun givenEpoch(epoch: Long) {
|
||||
every { epochMillis() } returns epoch
|
||||
}
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* Copyright (c) 2023 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.lib.core.utils.timer
|
||||
|
||||
import im.vector.lib.core.utils.test.fakes.FakeClock
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.verifySequence
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.test.advanceTimeBy
|
||||
import kotlinx.coroutines.test.currentTime
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Test
|
||||
|
||||
private const val AN_INTERVAL = 500L
|
||||
private const val AN_INITIAL_TIME = 2_333L
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
internal class CountUpTimerTest {
|
||||
|
||||
private val fakeClock = FakeClock()
|
||||
|
||||
@Test
|
||||
fun `when pausing and resuming the timer, the timer ticks the right values at the right moments`() = runTest {
|
||||
every { fakeClock.epochMillis() } answers { currentTime }
|
||||
val tickListener = mockk<CountUpTimer.TickListener>(relaxed = true)
|
||||
val timer = CountUpTimer(
|
||||
coroutineScope = this,
|
||||
clock = fakeClock,
|
||||
intervalInMs = AN_INTERVAL,
|
||||
initialTime = 0,
|
||||
).also { it.tickListener = tickListener }
|
||||
|
||||
timer.resume()
|
||||
advanceTimeBy(AN_INTERVAL / 2) // no tick
|
||||
timer.pause() // tick
|
||||
advanceTimeBy(AN_INTERVAL * 10) // no tick
|
||||
timer.resume() // no tick
|
||||
advanceTimeBy(AN_INTERVAL * 4) // tick * 4
|
||||
timer.stop() // tick
|
||||
|
||||
verifySequence {
|
||||
tickListener.onTick(AN_INTERVAL / 2)
|
||||
tickListener.onTick(AN_INTERVAL)
|
||||
tickListener.onTick(AN_INTERVAL * 2)
|
||||
tickListener.onTick(AN_INTERVAL * 3)
|
||||
tickListener.onTick(AN_INTERVAL * 4)
|
||||
tickListener.onTick(AN_INTERVAL * 4 + AN_INTERVAL / 2)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `given an initial time, the timer ticks the right values at the right moments`() = runTest {
|
||||
every { fakeClock.epochMillis() } answers { currentTime }
|
||||
val tickListener = mockk<CountUpTimer.TickListener>(relaxed = true)
|
||||
val timer = CountUpTimer(
|
||||
coroutineScope = this,
|
||||
clock = fakeClock,
|
||||
intervalInMs = AN_INTERVAL,
|
||||
initialTime = AN_INITIAL_TIME,
|
||||
).also { it.tickListener = tickListener }
|
||||
|
||||
timer.resume()
|
||||
advanceTimeBy(AN_INTERVAL) // tick
|
||||
timer.pause() // tick
|
||||
advanceTimeBy(AN_INTERVAL * 10) // no tick
|
||||
timer.resume() // no tick
|
||||
advanceTimeBy(AN_INTERVAL * 4) // tick * 4
|
||||
timer.stop() // tick
|
||||
|
||||
val offset = AN_INITIAL_TIME % AN_INTERVAL
|
||||
verifySequence {
|
||||
tickListener.onTick(AN_INITIAL_TIME + AN_INTERVAL - offset)
|
||||
tickListener.onTick(AN_INITIAL_TIME + AN_INTERVAL)
|
||||
tickListener.onTick(AN_INITIAL_TIME + AN_INTERVAL * 2 - offset)
|
||||
tickListener.onTick(AN_INITIAL_TIME + AN_INTERVAL * 3 - offset)
|
||||
tickListener.onTick(AN_INITIAL_TIME + AN_INTERVAL * 4 - offset)
|
||||
tickListener.onTick(AN_INITIAL_TIME + AN_INTERVAL * 5 - offset)
|
||||
tickListener.onTick(AN_INITIAL_TIME + AN_INTERVAL * 5)
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue