Files
honeyDueKMP/composeApp/src/androidUnitTest/kotlin/com/tt/honeyDue/notifications/SnoozeSchedulerTest.kt
Trey T 19471d780d P2 Stream H: standalone TaskSuggestionsScreen
Port iOS TaskSuggestionsView as a standalone route reachable outside
onboarding. Uses shared suggestions API + accept/skip analytics in
non-onboarding variant.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 13:10:47 -05:00

92 lines
3.0 KiB
Kotlin

package com.tt.honeyDue.notifications
import android.app.AlarmManager
import android.content.Context
import android.os.Build
import androidx.test.core.app.ApplicationProvider
import org.junit.Assert.assertEquals
import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner
import org.robolectric.Shadows.shadowOf
import org.robolectric.annotation.Config
/**
* Tests for [SnoozeScheduler] — verifies the AlarmManager scheduling path
* used by the P4 Stream O notification Snooze action.
*/
@RunWith(RobolectricTestRunner::class)
@Config(sdk = [Build.VERSION_CODES.TIRAMISU])
class SnoozeSchedulerTest {
private lateinit var context: Context
private lateinit var am: AlarmManager
@Before
fun setUp() {
context = ApplicationProvider.getApplicationContext()
am = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
// Robolectric's ShadowAlarmManager doesn't have an explicit clear, but
// scheduledAlarms is filtered by live pending intents so cancel() the
// world before each test.
shadowOf(am).scheduledAlarms.toList().forEach { alarm ->
alarm.operation?.let { am.cancel(it) }
}
}
// ---------- 7. schedule() sets alarm 30 minutes in future ----------
@Test
fun schedule_setsAlarmThirtyMinutesInFuture() {
val before = System.currentTimeMillis()
SnoozeScheduler.schedule(
context = context,
taskId = 123L,
title = "t",
body = "b",
type = NotificationChannels.TASK_REMINDER
)
val scheduled = shadowOf(am).scheduledAlarms
assertEquals(1, scheduled.size)
val delta = scheduled.first().triggerAtTime - before
val expected = NotificationActions.SNOOZE_DELAY_MS
assertTrue(
"expected ~30 min trigger, got delta=$delta",
delta in (expected - 2_000)..(expected + 2_000)
)
}
// ---------- 8. cancel() removes the pending alarm ----------
@Test
fun cancel_preventsLaterDelivery() {
SnoozeScheduler.schedule(context, taskId = 456L)
assertEquals(
"precondition: alarm scheduled",
1,
shadowOf(am).scheduledAlarms.size
)
SnoozeScheduler.cancel(context, taskId = 456L)
// After cancel(), the PendingIntent is consumed so scheduledAlarms
// shrinks back to zero (Robolectric matches by PI equality).
assertEquals(
"alarm should be gone after cancel()",
0,
shadowOf(am).scheduledAlarms.size
)
}
// Bonus coverage: different task ids get independent scheduling slots.
@Test
fun schedule_twoDifferentTasks_yieldsTwoAlarms() {
SnoozeScheduler.schedule(context, taskId = 1L)
SnoozeScheduler.schedule(context, taskId = 2L)
assertEquals(2, shadowOf(am).scheduledAlarms.size)
}
}