From 15404276dff7dc351c76c811a65e4d10011218ca Mon Sep 17 00:00:00 2001 From: Felix Wiemuth <533601+felixwiemuth@users.noreply.github.com> Date: Sun, 2 Oct 2022 11:54:40 +0200 Subject: [PATCH] Add tests for active notifications persistence --- .../uhabits/core/preferences/Preferences.kt | 4 +- .../uhabits/core/ui/NotificationTray.kt | 20 ++- .../core/preferences/PreferencesTest.kt | 28 ++++ .../uhabits/core/ui/NotificationTrayTest.kt | 125 ++++++++++++++++++ 4 files changed, 174 insertions(+), 3 deletions(-) create mode 100644 uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/NotificationTrayTest.kt diff --git a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/preferences/Preferences.kt b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/preferences/Preferences.kt index aa0a010ef..37d0b6e06 100644 --- a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/preferences/Preferences.kt +++ b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/preferences/Preferences.kt @@ -142,13 +142,13 @@ open class Preferences(private val storage: Storage) { storage.putBoolean("pref_short_toggle", enabled) } - internal fun setActiveNotifications(activeNotifications: Map) { + internal open fun setActiveNotifications(activeNotifications: Map) { val activeById = activeNotifications.mapKeys { it.key.id } val serialized = Json.encodeToString(activeById) storage.putString("pref_active_notifications", serialized) } - internal fun getActiveNotifications(habitList: HabitList): HashMap { + internal open fun getActiveNotifications(habitList: HabitList): HashMap { val serialized = storage.getString("pref_active_notifications", "") return if (serialized == "") { HashMap() diff --git a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/NotificationTray.kt b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/NotificationTray.kt index dff03efe4..29a84e6e2 100644 --- a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/NotificationTray.kt +++ b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/NotificationTray.kt @@ -128,7 +128,25 @@ class NotificationTray @Inject constructor( internal class NotificationData( val timestamp: Timestamp, val reminderTime: Long, - ) + ) { + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as NotificationData + + if (timestamp != other.timestamp) return false + if (reminderTime != other.reminderTime) return false + + return true + } + + override fun hashCode(): Int { + var result = timestamp.hashCode() + result = 31 * result + reminderTime.hashCode() + return result + } + } private inner class ShowNotificationTask( private val habit: Habit, diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/preferences/PreferencesTest.kt b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/preferences/PreferencesTest.kt index 52117c181..4be8bedeb 100644 --- a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/preferences/PreferencesTest.kt +++ b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/preferences/PreferencesTest.kt @@ -25,8 +25,11 @@ import junit.framework.Assert.assertTrue import org.hamcrest.CoreMatchers.equalTo import org.hamcrest.MatcherAssert.assertThat import org.isoron.uhabits.core.BaseUnitTest +import org.isoron.uhabits.core.models.Habit import org.isoron.uhabits.core.models.HabitList +import org.isoron.uhabits.core.models.Timestamp import org.isoron.uhabits.core.models.Timestamp.Companion.ZERO +import org.isoron.uhabits.core.ui.NotificationTray import org.isoron.uhabits.core.ui.ThemeSwitcher import org.junit.Before import org.junit.Test @@ -162,6 +165,31 @@ class PreferencesTest : BaseUnitTest() { assertFalse(prefs.showCompleted) } + @Test + @Throws(Exception::class) + fun testActiveNotifications() { + repeat(5) { habitList.add(fixtures.createEmptyHabit()) } + + // Initially no active notifications + assertThat(prefs.getActiveNotifications(habitList), equalTo(HashMap())) + + // Example map of active notifications + val a = HashMap() + for (i in listOf(0, 1, 3)) { + val habit = habitList.getByPosition(i) + val data = NotificationTray.NotificationData(Timestamp(10000L * i), 200000L * i) + a[habit] = data + } + + // Persist and retrieve active notifications + prefs.setActiveNotifications(a) + val b = prefs.getActiveNotifications(habitList) + + // Assert that persisted and retrieved maps are teh same + assertThat(a.keys, equalTo(b.keys)) + a.forEach { e -> assertThat(b[e.key], equalTo(e.value)) } + } + @Test @Throws(Exception::class) fun testMidnightDelay() { diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/NotificationTrayTest.kt b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/NotificationTrayTest.kt new file mode 100644 index 000000000..931386367 --- /dev/null +++ b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/NotificationTrayTest.kt @@ -0,0 +1,125 @@ +package org.isoron.uhabits.core.ui + +import org.hamcrest.CoreMatchers.equalTo +import org.hamcrest.MatcherAssert.assertThat +import org.isoron.uhabits.core.BaseUnitTest +import org.isoron.uhabits.core.models.Habit +import org.isoron.uhabits.core.models.HabitList +import org.isoron.uhabits.core.models.Reminder +import org.isoron.uhabits.core.models.Timestamp +import org.isoron.uhabits.core.models.WeekdayList +import org.isoron.uhabits.core.preferences.Preferences +import org.isoron.uhabits.core.preferences.Preferences.Storage +import org.junit.Before +import org.junit.Test + +class NotificationTrayTest : BaseUnitTest() { + private val systemTray = object : NotificationTray.SystemTray { + override fun removeNotification(notificationId: Int) {} + + override fun showNotification( + habit: Habit, + notificationId: Int, + timestamp: Timestamp, + reminderTime: Long, + silent: Boolean + ) { + } + + override fun log(msg: String) {} + } + + private var preferences = MockPreferences() + private lateinit var notificationTray: NotificationTray + + class DummyStorage : Storage { + override fun clear() { + throw NotImplementedError("Mock implementation missing") + } + + override fun getBoolean(key: String, defValue: Boolean): Boolean { + throw NotImplementedError("Mock implementation missing") + } + + override fun getInt(key: String, defValue: Int): Int { + throw NotImplementedError("Mock implementation missing") + } + + override fun getLong(key: String, defValue: Long): Long { + throw NotImplementedError("Mock implementation missing") + } + + override fun getString(key: String, defValue: String): String { + throw NotImplementedError("Mock implementation missing") + } + + override fun onAttached(preferences: Preferences) { + } + + override fun putBoolean(key: String, value: Boolean) { + throw NotImplementedError("Mock implementation missing") + } + + override fun putInt(key: String, value: Int) { + throw NotImplementedError("Mock implementation missing") + } + + override fun putLong(key: String, value: Long) { + throw NotImplementedError("Mock implementation missing") + } + + override fun putString(key: String, value: String) { + throw NotImplementedError("Mock implementation missing") + } + + override fun remove(key: String) { + throw NotImplementedError("Mock implementation missing") + } + } + + class MockPreferences : Preferences(DummyStorage()) { + private var activeNotifications: HashMap = + HashMap() + + override fun setActiveNotifications(activeNotifications: Map) { + this.activeNotifications = HashMap(activeNotifications) + } + + override fun getActiveNotifications(habitList: HabitList): HashMap { + return activeNotifications + } + } + + @Before + @Throws(Exception::class) + override fun setUp() { + super.setUp() + notificationTray = + NotificationTray(taskRunner, commandRunner, preferences, systemTray, habitList) + } + + @Test + @Throws(Exception::class) + fun testShow() { + // Show a reminder for a habit + val habit = fixtures.createEmptyHabit() + habit.reminder = Reminder(8, 30, WeekdayList.EVERY_DAY) + val timestamp = Timestamp(System.currentTimeMillis()) + val reminderTime = System.currentTimeMillis() + notificationTray.show(habit, timestamp, reminderTime) + + // Verify that the active notifications include exactly the one shown reminder + // TODO are we guaranteed that task has executed? + assertThat(preferences.getActiveNotifications(habitList).size, equalTo(1)) + assertThat( + preferences.getActiveNotifications(habitList)[habit], + equalTo(NotificationTray.NotificationData(timestamp, reminderTime)) + ) + + // Remove the reminder from the notification tray and verify that active notifications are empty + notificationTray.cancel(habit) + assertThat(preferences.getActiveNotifications(habitList).size, equalTo(0)) + + // TODO test cases where reminders should be removed (e.g. reshowAll) + } +} \ No newline at end of file