Skip to content

Commit

Permalink
✅ Improve HitTimer Test Coverage
Browse files Browse the repository at this point in the history
Signed-off-by: Leonardo Colman Lopes <[email protected]>
  • Loading branch information
LeoColman committed Jan 29, 2025
1 parent e23dbdc commit 2107fbe
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,10 @@ class HitTimer(val durationMillis: Long = 10_000L) : Parcelable {
startDate = null
}

@Suppress("UnsafeCallOnNullableType")
private fun calculateMillisLeft(): Long {
if (startDate == null) return durationMillis
val elapsed = startDate?.until(now(), MILLIS) ?: 0
val elapsed = startDate!!.until(now(), MILLIS)
return (durationMillis - elapsed).coerceAtLeast(0)
}

Expand Down
75 changes: 67 additions & 8 deletions app/src/test/kotlin/br/com/colman/petals/hittimer/HitTimerTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,12 @@ import io.kotest.datatest.withData
import io.kotest.inspectors.forAll
import io.kotest.matchers.collections.shouldBeMonotonicallyDecreasing
import io.kotest.matchers.ints.shouldBeGreaterThanOrEqual
import io.kotest.matchers.longs.shouldBeLessThanOrEqual
import io.kotest.matchers.shouldBe
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.take
import kotlinx.coroutines.flow.takeWhile
import kotlinx.coroutines.flow.toList

class HitTimerTest : FunSpec({
Expand Down Expand Up @@ -35,17 +39,72 @@ class HitTimerTest : FunSpec({
allResults.size shouldBeGreaterThanOrEqual (duration / 10).toInt()
}

context("Duration with milliseconds disabled should not show 0 while there are still milliseconds") {
context("Error Cases") {
test("Should return max duration if timer wasn't started") {
target.millisLeft.first() shouldBe duration
}
}

context("Reset functionality") {
test("Should reset to initial duration when reset is called after starting") {
target.start()
target.reset()
target.millisLeft.first() shouldBe duration
}

test("After timer completes, reset should restore duration") {
target.start()
target.millisLeft.takeWhile { it > 0 }.toList()
target.reset()
target.millisLeft.first() shouldBe duration
}
}

context("Start multiple times") {
test("Calling start multiple times resets the timer") {
target.start()
delay(20L)
val firstValue = target.millisLeft.first()
target.start()
val secondValue = target.millisLeft.first()

secondValue shouldBe duration
firstValue shouldBeLessThanOrEqual (duration - 20)
}
}

context("Duration formatting") {
withData(
nameFn = { (millis, string) -> "$millis milliseconds should be converted to $string" },
0L to "0.0",
100L to "0.1",
249L to "0.2",
250L to "0.3",
666L to "0.7",
1200L to "1"
nameFn = { (millis, expected) -> "$millis ms -> $expected" },
0L to "00:000",
1000L to "01:000",
1234L to "01:234",
9999L to "09:999",
10_000L to "10:000"
) { (millis, expected) ->
HitTimer.duration(millis) shouldBe expected
}
}

context("Duration with milliseconds disabled edge cases") {
withData(
nameFn = { (millis, string) -> "$millis ms -> $string" },
999L to "1.0",
1000L to "1.0",
1001L to "1",
500L to "0.5",
499L to "0.5",
1L to "0.0",
0L to "0.0"
) { (millis, string) ->
HitTimer.durationMillisecondsDisabled(millis) shouldBe string
}
}

test("Timer stays at zero after duration has passed") {
target.start()
delay(duration)
target.millisLeft.first() shouldBe 0
target.millisLeft.take(3).toList().forAll { it shouldBe 0 }
}
})

0 comments on commit 2107fbe

Please sign in to comment.