diff --git a/core/src/testFixtures/kotlin/test/MockkExtensions.kt b/core/src/testFixtures/kotlin/test/MockkExtensions.kt index bcddce0..2bafc94 100644 --- a/core/src/testFixtures/kotlin/test/MockkExtensions.kt +++ b/core/src/testFixtures/kotlin/test/MockkExtensions.kt @@ -1,6 +1,8 @@ package test import io.mockk.* +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flowOf inline fun T.expect(crossinline block: suspend MockKMatcherScope.(T) -> R) { coEvery { block(this@expect) } returns mockk(relaxed = true) @@ -16,11 +18,22 @@ fun MockKStubScope.delegateReturn() = object : Returns { } } +fun MockKStubScope, B>.delegateEmit() = object : Emits { + override fun emits(vararg values: T) { + answers(ConstantAnswer(flowOf(*values))) + } +} + + fun returns(block: (T) -> Unit) = object : Returns { override fun returns(value: T) = block(value) override fun throws(value: Throwable) = throw value } +interface Emits { + fun emits(vararg values: T) +} + interface Returns { fun returns(value: T) fun throws(value: Throwable) diff --git a/features/notifications/src/main/kotlin/app/dapk/st/notifications/NotificationsModule.kt b/features/notifications/src/main/kotlin/app/dapk/st/notifications/NotificationsModule.kt index c861e60..2972b52 100644 --- a/features/notifications/src/main/kotlin/app/dapk/st/notifications/NotificationsModule.kt +++ b/features/notifications/src/main/kotlin/app/dapk/st/notifications/NotificationsModule.kt @@ -31,7 +31,7 @@ class NotificationsModule( fun credentialProvider() = credentialsStore fun firebasePushTokenUseCase() = firebasePushTokenUseCase fun roomStore() = roomStore - fun notificationsUseCase() = NotificationsUseCase( + fun notificationsUseCase() = RenderNotificationsUseCase( NotificationRenderer(notificationManager(), NotificationFactory(iconLoader, context, intentFactory), dispatchers), ObserveUnreadNotificationsUseCaseImpl(roomStore), NotificationChannels(notificationManager()), diff --git a/features/notifications/src/main/kotlin/app/dapk/st/notifications/NotificationsUseCase.kt b/features/notifications/src/main/kotlin/app/dapk/st/notifications/RenderNotificationsUseCase.kt similarity index 97% rename from features/notifications/src/main/kotlin/app/dapk/st/notifications/NotificationsUseCase.kt rename to features/notifications/src/main/kotlin/app/dapk/st/notifications/RenderNotificationsUseCase.kt index ac58f29..d05da67 100644 --- a/features/notifications/src/main/kotlin/app/dapk/st/notifications/NotificationsUseCase.kt +++ b/features/notifications/src/main/kotlin/app/dapk/st/notifications/RenderNotificationsUseCase.kt @@ -7,7 +7,7 @@ import app.dapk.st.matrix.sync.RoomOverview import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.onEach -class NotificationsUseCase( +class RenderNotificationsUseCase( private val notificationRenderer: NotificationRenderer, private val observeRenderableUnreadEventsUseCase: ObserveUnreadNotificationsUseCase, notificationChannels: NotificationChannels, diff --git a/features/notifications/src/test/kotlin/app/dapk/st/notifications/NotificationRendererTest.kt b/features/notifications/src/test/kotlin/app/dapk/st/notifications/NotificationRendererTest.kt index 8889a10..a89ae5e 100644 --- a/features/notifications/src/test/kotlin/app/dapk/st/notifications/NotificationRendererTest.kt +++ b/features/notifications/src/test/kotlin/app/dapk/st/notifications/NotificationRendererTest.kt @@ -1,6 +1,6 @@ package app.dapk.st.notifications -import app.dapk.st.notifications.NotificationFixtures.aNotifications +import fixture.NotificationFixtures.aNotifications import fake.FakeNotificationFactory import fake.FakeNotificationManager import fake.aFakeNotification diff --git a/features/notifications/src/test/kotlin/app/dapk/st/notifications/ObserveUnreadNotificationsUseCaseTest.kt b/features/notifications/src/test/kotlin/app/dapk/st/notifications/ObserveUnreadRenderNotificationsUseCaseTest.kt similarity index 87% rename from features/notifications/src/test/kotlin/app/dapk/st/notifications/ObserveUnreadNotificationsUseCaseTest.kt rename to features/notifications/src/test/kotlin/app/dapk/st/notifications/ObserveUnreadRenderNotificationsUseCaseTest.kt index bb3c01a..b052378 100644 --- a/features/notifications/src/test/kotlin/app/dapk/st/notifications/ObserveUnreadNotificationsUseCaseTest.kt +++ b/features/notifications/src/test/kotlin/app/dapk/st/notifications/ObserveUnreadRenderNotificationsUseCaseTest.kt @@ -1,14 +1,10 @@ package app.dapk.st.notifications -import app.dapk.st.matrix.common.EventId -import app.dapk.st.matrix.common.RoomId import app.dapk.st.matrix.sync.RoomEvent import app.dapk.st.matrix.sync.RoomOverview import fake.FakeRoomStore -import fixture.aRoomId -import fixture.aRoomMessageEvent -import fixture.aRoomOverview -import fixture.anEventId +import fixture.* +import fixture.NotificationDiffFixtures.aNotificationDiff import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.toList import kotlinx.coroutines.test.runTest @@ -21,7 +17,7 @@ val A_MESSAGE_2 = aRoomMessageEvent(eventId = anEventId("2"), content = "world") val A_ROOM_OVERVIEW = aRoomOverview(roomId = aRoomId("1")) val A_ROOM_OVERVIEW_2 = aRoomOverview(roomId = aRoomId("2")) -class ObserveUnreadNotificationsUseCaseTest { +class ObserveUnreadRenderNotificationsUseCaseTest { private val fakeRoomStore = FakeRoomStore() @@ -94,12 +90,5 @@ class ObserveUnreadNotificationsUseCaseTest { private fun givenNoInitialUnreads(vararg unreads: Map>) = fakeRoomStore.givenUnreadEvents(flowOf(NO_UNREADS, *unreads)) } -private fun aNotificationDiff( - unchanged: Map> = emptyMap(), - changedOrNew: Map> = emptyMap(), - removed: Map> = emptyMap(), - newRooms: Set = emptySet(), -) = NotificationDiff(unchanged, changedOrNew, removed, newRooms) - private fun RoomOverview.withUnreads(vararg events: RoomEvent) = mapOf(this to events.toList()) private fun RoomOverview.toDiff(vararg events: RoomEvent) = mapOf(this.roomId to events.map { it.eventId }) diff --git a/features/notifications/src/test/kotlin/app/dapk/st/notifications/RenderNotificationsUseCaseTest.kt b/features/notifications/src/test/kotlin/app/dapk/st/notifications/RenderNotificationsUseCaseTest.kt new file mode 100644 index 0000000..4cc7f04 --- /dev/null +++ b/features/notifications/src/test/kotlin/app/dapk/st/notifications/RenderNotificationsUseCaseTest.kt @@ -0,0 +1,41 @@ +package app.dapk.st.notifications + +import fake.FakeNotificationChannels +import fake.FakeNotificationRenderer +import fake.FakeObserveUnreadNotificationsUseCase +import fixture.NotificationDiffFixtures.aNotificationDiff +import kotlinx.coroutines.test.runTest +import org.junit.Test +import test.expect + +private val AN_UNREAD_NOTIFICATIONS = UnreadNotifications(emptyMap(), aNotificationDiff()) + +class RenderNotificationsUseCaseTest { + + private val fakeNotificationRenderer = FakeNotificationRenderer() + private val fakeObserveUnreadNotificationsUseCase = FakeObserveUnreadNotificationsUseCase() + private val fakeNotificationChannels = FakeNotificationChannels().also { + it.instance.expect { it.initChannels() } + } + + private val renderNotificationsUseCase = RenderNotificationsUseCase( + fakeNotificationRenderer.instance, + fakeObserveUnreadNotificationsUseCase, + fakeNotificationChannels.instance, + ) + + @Test + fun `when creating use case instance, then initiates channels`() { + fakeNotificationChannels.verifyInitiated() + } + + @Test + fun `given renderable unread events, when listening for changes, then renders change`() = runTest { + fakeNotificationRenderer.instance.expect { it.render(any(), any(), any(), any()) } + fakeObserveUnreadNotificationsUseCase.given().emits(AN_UNREAD_NOTIFICATIONS) + + renderNotificationsUseCase.listenForNotificationChanges() + + fakeNotificationRenderer.verifyRenders(AN_UNREAD_NOTIFICATIONS) + } +} diff --git a/features/notifications/src/test/kotlin/fake/FakeNotificationChannels.kt b/features/notifications/src/test/kotlin/fake/FakeNotificationChannels.kt new file mode 100644 index 0000000..ed51858 --- /dev/null +++ b/features/notifications/src/test/kotlin/fake/FakeNotificationChannels.kt @@ -0,0 +1,13 @@ +package fake + +import app.dapk.st.notifications.NotificationChannels +import io.mockk.mockk +import io.mockk.verify + +class FakeNotificationChannels { + val instance = mockk() + + fun verifyInitiated() { + verify { instance.initChannels() } + } +} \ No newline at end of file diff --git a/features/notifications/src/test/kotlin/fake/FakeNotificationRenderer.kt b/features/notifications/src/test/kotlin/fake/FakeNotificationRenderer.kt new file mode 100644 index 0000000..ad5d03b --- /dev/null +++ b/features/notifications/src/test/kotlin/fake/FakeNotificationRenderer.kt @@ -0,0 +1,23 @@ +package fake + +import app.dapk.st.notifications.NotificationRenderer +import app.dapk.st.notifications.UnreadNotifications +import io.mockk.coVerify +import io.mockk.mockk + +class FakeNotificationRenderer { + val instance = mockk() + + fun verifyRenders(vararg unreadNotifications: UnreadNotifications) { + unreadNotifications.forEach { unread -> + coVerify { + instance.render( + allUnread = unread.first, + removedRooms = unread.second.removed.keys, + roomsWithNewEvents = unread.second.changedOrNew.keys, + newRooms = unread.second.newRooms, + ) + } + } + } +} \ No newline at end of file diff --git a/features/notifications/src/test/kotlin/fake/FakeObserveUnreadNotificationsUseCase.kt b/features/notifications/src/test/kotlin/fake/FakeObserveUnreadNotificationsUseCase.kt new file mode 100644 index 0000000..dd881d2 --- /dev/null +++ b/features/notifications/src/test/kotlin/fake/FakeObserveUnreadNotificationsUseCase.kt @@ -0,0 +1,10 @@ +package fake + +import app.dapk.st.notifications.ObserveUnreadNotificationsUseCase +import io.mockk.coEvery +import io.mockk.mockk +import test.delegateEmit + +class FakeObserveUnreadNotificationsUseCase : ObserveUnreadNotificationsUseCase by mockk() { + fun given() = coEvery { this@FakeObserveUnreadNotificationsUseCase.invoke() }.delegateEmit() +} \ No newline at end of file diff --git a/features/notifications/src/test/kotlin/fixture/NotificationDiffFixtures.kt b/features/notifications/src/test/kotlin/fixture/NotificationDiffFixtures.kt new file mode 100644 index 0000000..7b9f0e9 --- /dev/null +++ b/features/notifications/src/test/kotlin/fixture/NotificationDiffFixtures.kt @@ -0,0 +1,16 @@ +package fixture + +import app.dapk.st.matrix.common.EventId +import app.dapk.st.matrix.common.RoomId +import app.dapk.st.notifications.NotificationDiff + +object NotificationDiffFixtures { + + fun aNotificationDiff( + unchanged: Map> = emptyMap(), + changedOrNew: Map> = emptyMap(), + removed: Map> = emptyMap(), + newRooms: Set = emptySet(), + ) = NotificationDiff(unchanged, changedOrNew, removed, newRooms) + +} \ No newline at end of file diff --git a/features/notifications/src/test/kotlin/fixture/NotificationFixtures.kt b/features/notifications/src/test/kotlin/fixture/NotificationFixtures.kt index a34d0a1..fcd6734 100644 --- a/features/notifications/src/test/kotlin/fixture/NotificationFixtures.kt +++ b/features/notifications/src/test/kotlin/fixture/NotificationFixtures.kt @@ -1,6 +1,8 @@ -package app.dapk.st.notifications +package fixture import android.app.Notification +import app.dapk.st.notifications.NotificationDelegate +import app.dapk.st.notifications.Notifications object NotificationFixtures {