Merge pull request #3554 from element-hq/feature/bma/testEmptyTimeline
Add unit tests on TimelineItemsSubscriber
This commit is contained in:
commit
4d554de838
14 changed files with 349 additions and 130 deletions
|
|
@ -0,0 +1,20 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2024 New Vector Ltd.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
* Please see LICENSE in the repository root for full details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.libraries.matrix.impl.fixtures.factories
|
||||||
|
|
||||||
|
import org.matrix.rustcomponents.sdk.EventTimelineItemDebugInfo
|
||||||
|
|
||||||
|
fun anEventTimelineItemDebugInfo(
|
||||||
|
model: String = "model",
|
||||||
|
originalJson: String? = null,
|
||||||
|
latestEditJson: String? = null,
|
||||||
|
) = EventTimelineItemDebugInfo(
|
||||||
|
model = model,
|
||||||
|
originalJson = originalJson,
|
||||||
|
latestEditJson = latestEditJson
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,44 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2024 New Vector Ltd.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
* Please see LICENSE in the repository root for full details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.libraries.matrix.impl.fixtures.fakes
|
||||||
|
|
||||||
|
import io.element.android.libraries.matrix.impl.fixtures.factories.anEventTimelineItemDebugInfo
|
||||||
|
import io.element.android.libraries.matrix.test.AN_EVENT_ID
|
||||||
|
import io.element.android.libraries.matrix.test.A_USER_ID
|
||||||
|
import org.matrix.rustcomponents.sdk.EventSendState
|
||||||
|
import org.matrix.rustcomponents.sdk.EventTimelineItem
|
||||||
|
import org.matrix.rustcomponents.sdk.EventTimelineItemDebugInfo
|
||||||
|
import org.matrix.rustcomponents.sdk.NoPointer
|
||||||
|
import org.matrix.rustcomponents.sdk.ProfileDetails
|
||||||
|
import org.matrix.rustcomponents.sdk.Reaction
|
||||||
|
import org.matrix.rustcomponents.sdk.Receipt
|
||||||
|
import org.matrix.rustcomponents.sdk.ShieldState
|
||||||
|
import org.matrix.rustcomponents.sdk.TimelineItemContent
|
||||||
|
import uniffi.matrix_sdk_ui.EventItemOrigin
|
||||||
|
|
||||||
|
class FakeRustEventTimelineItem(
|
||||||
|
private val origin: EventItemOrigin? = null,
|
||||||
|
) : EventTimelineItem(NoPointer) {
|
||||||
|
override fun origin(): EventItemOrigin? = origin
|
||||||
|
override fun eventId(): String = AN_EVENT_ID.value
|
||||||
|
override fun transactionId(): String? = null
|
||||||
|
override fun isEditable(): Boolean = false
|
||||||
|
override fun canBeRepliedTo(): Boolean = false
|
||||||
|
override fun isLocal(): Boolean = false
|
||||||
|
override fun isOwn(): Boolean = false
|
||||||
|
override fun isRemote(): Boolean = false
|
||||||
|
override fun localSendState(): EventSendState? = null
|
||||||
|
override fun reactions(): List<Reaction> = emptyList()
|
||||||
|
override fun readReceipts(): Map<String, Receipt> = emptyMap()
|
||||||
|
override fun sender(): String = A_USER_ID.value
|
||||||
|
override fun senderProfile(): ProfileDetails = ProfileDetails.Unavailable
|
||||||
|
override fun timestamp(): ULong = 0u
|
||||||
|
override fun content(): TimelineItemContent = FakeRustTimelineItemContent()
|
||||||
|
override fun debugInfo(): EventTimelineItemDebugInfo = anEventTimelineItemDebugInfo()
|
||||||
|
override fun getShield(strict: Boolean): ShieldState? = null
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2024 New Vector Ltd.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
* Please see LICENSE in the repository root for full details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.libraries.matrix.impl.fixtures.fakes
|
||||||
|
|
||||||
|
import org.matrix.rustcomponents.sdk.NoPointer
|
||||||
|
import org.matrix.rustcomponents.sdk.TaskHandle
|
||||||
|
import org.matrix.rustcomponents.sdk.Timeline
|
||||||
|
import org.matrix.rustcomponents.sdk.TimelineDiff
|
||||||
|
import org.matrix.rustcomponents.sdk.TimelineListener
|
||||||
|
|
||||||
|
class FakeRustTimeline : Timeline(NoPointer) {
|
||||||
|
private var listener: TimelineListener? = null
|
||||||
|
override suspend fun addListener(listener: TimelineListener): TaskHandle {
|
||||||
|
this.listener = listener
|
||||||
|
return FakeRustTaskHandle()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun emitDiff(diff: List<TimelineDiff>) {
|
||||||
|
listener!!.onUpdate(diff)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -12,8 +12,10 @@ import org.matrix.rustcomponents.sdk.NoPointer
|
||||||
import org.matrix.rustcomponents.sdk.TimelineItem
|
import org.matrix.rustcomponents.sdk.TimelineItem
|
||||||
import org.matrix.rustcomponents.sdk.VirtualTimelineItem
|
import org.matrix.rustcomponents.sdk.VirtualTimelineItem
|
||||||
|
|
||||||
class FakeRustTimelineItem : TimelineItem(NoPointer) {
|
class FakeRustTimelineItem(
|
||||||
override fun asEvent(): EventTimelineItem? = null
|
private val asEventResult: EventTimelineItem? = null,
|
||||||
|
) : TimelineItem(NoPointer) {
|
||||||
|
override fun asEvent(): EventTimelineItem? = asEventResult
|
||||||
override fun asVirtual(): VirtualTimelineItem? = null
|
override fun asVirtual(): VirtualTimelineItem? = null
|
||||||
override fun fmtDebug(): String = "fmtDebug"
|
override fun fmtDebug(): String = "fmtDebug"
|
||||||
override fun uniqueId(): String = "uniqueId"
|
override fun uniqueId(): String = "uniqueId"
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2024 New Vector Ltd.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
* Please see LICENSE in the repository root for full details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.libraries.matrix.impl.fixtures.fakes
|
||||||
|
|
||||||
|
import org.matrix.rustcomponents.sdk.Message
|
||||||
|
import org.matrix.rustcomponents.sdk.NoPointer
|
||||||
|
import org.matrix.rustcomponents.sdk.TimelineItemContent
|
||||||
|
import org.matrix.rustcomponents.sdk.TimelineItemContentKind
|
||||||
|
|
||||||
|
class FakeRustTimelineItemContent : TimelineItemContent(NoPointer) {
|
||||||
|
override fun asMessage(): Message? = null
|
||||||
|
override fun kind(): TimelineItemContentKind = TimelineItemContentKind.Message
|
||||||
|
}
|
||||||
|
|
@ -13,12 +13,12 @@ import io.element.android.libraries.matrix.api.roomdirectory.RoomDirectoryList
|
||||||
import io.element.android.libraries.matrix.impl.fixtures.factories.aRustRoomDescription
|
import io.element.android.libraries.matrix.impl.fixtures.factories.aRustRoomDescription
|
||||||
import io.element.android.libraries.matrix.impl.fixtures.fakes.FakeRoomDirectorySearch
|
import io.element.android.libraries.matrix.impl.fixtures.fakes.FakeRoomDirectorySearch
|
||||||
import io.element.android.libraries.matrix.test.A_ROOM_ID_2
|
import io.element.android.libraries.matrix.test.A_ROOM_ID_2
|
||||||
import io.element.android.tests.testutils.runCancellableScopeTestWithTestScope
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
import kotlinx.coroutines.test.StandardTestDispatcher
|
import kotlinx.coroutines.test.StandardTestDispatcher
|
||||||
import kotlinx.coroutines.test.TestScope
|
import kotlinx.coroutines.test.TestScope
|
||||||
import kotlinx.coroutines.test.runCurrent
|
import kotlinx.coroutines.test.runCurrent
|
||||||
|
import kotlinx.coroutines.test.runTest
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.matrix.rustcomponents.sdk.RoomDirectorySearch
|
import org.matrix.rustcomponents.sdk.RoomDirectorySearch
|
||||||
import org.matrix.rustcomponents.sdk.RoomDirectorySearchEntryUpdate
|
import org.matrix.rustcomponents.sdk.RoomDirectorySearchEntryUpdate
|
||||||
|
|
@ -26,15 +26,15 @@ import org.matrix.rustcomponents.sdk.RoomDirectorySearchEntryUpdate
|
||||||
@OptIn(ExperimentalCoroutinesApi::class)
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
class RustRoomDirectoryListTest {
|
class RustRoomDirectoryListTest {
|
||||||
@Test
|
@Test
|
||||||
fun `check that the state emits the expected values`() = runCancellableScopeTestWithTestScope { testScope, cancellableScope ->
|
fun `check that the state emits the expected values`() = runTest {
|
||||||
val fakeRoomDirectorySearch = FakeRoomDirectorySearch()
|
val fakeRoomDirectorySearch = FakeRoomDirectorySearch()
|
||||||
val mapper = RoomDescriptionMapper()
|
val mapper = RoomDescriptionMapper()
|
||||||
val sut = testScope.createRustRoomDirectoryList(
|
val sut = createRustRoomDirectoryList(
|
||||||
roomDirectorySearch = fakeRoomDirectorySearch,
|
roomDirectorySearch = fakeRoomDirectorySearch,
|
||||||
scope = cancellableScope,
|
scope = backgroundScope,
|
||||||
)
|
)
|
||||||
// Let the mxCallback be ready
|
// Let the mxCallback be ready
|
||||||
testScope.runCurrent()
|
runCurrent()
|
||||||
sut.state.test {
|
sut.state.test {
|
||||||
sut.filter("", 20)
|
sut.filter("", 20)
|
||||||
fakeRoomDirectorySearch.emitResult(
|
fakeRoomDirectorySearch.emitResult(
|
||||||
|
|
|
||||||
|
|
@ -8,18 +8,18 @@
|
||||||
package io.element.android.libraries.matrix.impl.roomdirectory
|
package io.element.android.libraries.matrix.impl.roomdirectory
|
||||||
|
|
||||||
import io.element.android.libraries.matrix.impl.fixtures.fakes.FakeRustClient
|
import io.element.android.libraries.matrix.impl.fixtures.fakes.FakeRustClient
|
||||||
import io.element.android.tests.testutils.runCancellableScopeTestWithTestScope
|
|
||||||
import kotlinx.coroutines.test.StandardTestDispatcher
|
import kotlinx.coroutines.test.StandardTestDispatcher
|
||||||
|
import kotlinx.coroutines.test.runTest
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
|
||||||
class RustRoomDirectoryServiceTest {
|
class RustRoomDirectoryServiceTest {
|
||||||
@Test
|
@Test
|
||||||
fun test() = runCancellableScopeTestWithTestScope { testScope, cancellableScope ->
|
fun test() = runTest {
|
||||||
val client = FakeRustClient()
|
val client = FakeRustClient()
|
||||||
val sut = RustRoomDirectoryService(
|
val sut = RustRoomDirectoryService(
|
||||||
client = client,
|
client = client,
|
||||||
sessionDispatcher = StandardTestDispatcher(testScope.testScheduler),
|
sessionDispatcher = StandardTestDispatcher(testScheduler),
|
||||||
)
|
)
|
||||||
sut.createRoomDirectoryList(cancellableScope)
|
sut.createRoomDirectoryList(backgroundScope)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,16 +9,16 @@ package io.element.android.libraries.matrix.impl.roomlist
|
||||||
|
|
||||||
import io.element.android.libraries.matrix.impl.fixtures.fakes.FakeRustRoomList
|
import io.element.android.libraries.matrix.impl.fixtures.fakes.FakeRustRoomList
|
||||||
import io.element.android.libraries.matrix.impl.fixtures.fakes.FakeRustRoomListService
|
import io.element.android.libraries.matrix.impl.fixtures.fakes.FakeRustRoomListService
|
||||||
import io.element.android.tests.testutils.runCancellableScopeTest
|
import kotlinx.coroutines.test.runTest
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import kotlin.coroutines.EmptyCoroutineContext
|
import kotlin.coroutines.EmptyCoroutineContext
|
||||||
|
|
||||||
class RoomListFactoryTest {
|
class RoomListFactoryTest {
|
||||||
@Test
|
@Test
|
||||||
fun `createRoomList should work`() = runCancellableScopeTest {
|
fun `createRoomList should work`() = runTest {
|
||||||
val sut = RoomListFactory(
|
val sut = RoomListFactory(
|
||||||
innerRoomListService = FakeRustRoomListService(),
|
innerRoomListService = FakeRustRoomListService(),
|
||||||
sessionCoroutineScope = it,
|
sessionCoroutineScope = backgroundScope,
|
||||||
)
|
)
|
||||||
sut.createRoomList(
|
sut.createRoomList(
|
||||||
pageSize = 10,
|
pageSize = 10,
|
||||||
|
|
|
||||||
|
|
@ -11,13 +11,13 @@ import com.google.common.truth.Truth.assertThat
|
||||||
import io.element.android.libraries.matrix.api.roomlist.RoomListService
|
import io.element.android.libraries.matrix.api.roomlist.RoomListService
|
||||||
import io.element.android.libraries.matrix.impl.fixtures.fakes.FakeRustRoomListService
|
import io.element.android.libraries.matrix.impl.fixtures.fakes.FakeRustRoomListService
|
||||||
import io.element.android.libraries.matrix.impl.room.RoomSyncSubscriber
|
import io.element.android.libraries.matrix.impl.room.RoomSyncSubscriber
|
||||||
import io.element.android.tests.testutils.runCancellableScopeTestWithTestScope
|
|
||||||
import io.element.android.tests.testutils.testCoroutineDispatchers
|
import io.element.android.tests.testutils.testCoroutineDispatchers
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
import kotlinx.coroutines.test.StandardTestDispatcher
|
import kotlinx.coroutines.test.StandardTestDispatcher
|
||||||
import kotlinx.coroutines.test.TestScope
|
import kotlinx.coroutines.test.TestScope
|
||||||
import kotlinx.coroutines.test.runCurrent
|
import kotlinx.coroutines.test.runCurrent
|
||||||
|
import kotlinx.coroutines.test.runTest
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.matrix.rustcomponents.sdk.RoomListServiceSyncIndicator
|
import org.matrix.rustcomponents.sdk.RoomListServiceSyncIndicator
|
||||||
import org.matrix.rustcomponents.sdk.RoomListService as RustRoomListService
|
import org.matrix.rustcomponents.sdk.RoomListService as RustRoomListService
|
||||||
|
|
@ -25,14 +25,14 @@ import org.matrix.rustcomponents.sdk.RoomListService as RustRoomListService
|
||||||
@OptIn(ExperimentalCoroutinesApi::class)
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
class RustRoomListServiceTest {
|
class RustRoomListServiceTest {
|
||||||
@Test
|
@Test
|
||||||
fun `syncIndicator should emit the expected values`() = runCancellableScopeTestWithTestScope { testScope, cancellableScope ->
|
fun `syncIndicator should emit the expected values`() = runTest {
|
||||||
val roomListService = FakeRustRoomListService()
|
val roomListService = FakeRustRoomListService()
|
||||||
val sut = testScope.createRustRoomListService(
|
val sut = createRustRoomListService(
|
||||||
sessionCoroutineScope = cancellableScope,
|
sessionCoroutineScope = backgroundScope,
|
||||||
roomListService = roomListService,
|
roomListService = roomListService,
|
||||||
)
|
)
|
||||||
// Give time for mxCallback to setup
|
// Give time for mxCallback to setup
|
||||||
testScope.runCurrent()
|
runCurrent()
|
||||||
sut.syncIndicator.test {
|
sut.syncIndicator.test {
|
||||||
assertThat(awaitItem()).isEqualTo(RoomListService.SyncIndicator.Hide)
|
assertThat(awaitItem()).isEqualTo(RoomListService.SyncIndicator.Hide)
|
||||||
roomListService.emitRoomListServiceSyncIndicator(RoomListServiceSyncIndicator.SHOW)
|
roomListService.emitRoomListServiceSyncIndicator(RoomListServiceSyncIndicator.SHOW)
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ import io.element.android.libraries.matrix.impl.timeline.item.virtual.VirtualTim
|
||||||
import io.element.android.libraries.matrix.test.A_UNIQUE_ID
|
import io.element.android.libraries.matrix.test.A_UNIQUE_ID
|
||||||
import io.element.android.libraries.matrix.test.A_UNIQUE_ID_2
|
import io.element.android.libraries.matrix.test.A_UNIQUE_ID_2
|
||||||
import io.element.android.libraries.matrix.test.timeline.anEventTimelineItem
|
import io.element.android.libraries.matrix.test.timeline.anEventTimelineItem
|
||||||
|
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.test.TestScope
|
import kotlinx.coroutines.test.TestScope
|
||||||
import kotlinx.coroutines.test.runTest
|
import kotlinx.coroutines.test.runTest
|
||||||
|
|
@ -31,7 +32,7 @@ class MatrixTimelineDiffProcessorTest {
|
||||||
@Test
|
@Test
|
||||||
fun `Append adds new entries at the end of the list`() = runTest {
|
fun `Append adds new entries at the end of the list`() = runTest {
|
||||||
timelineItems.value = listOf(anEvent)
|
timelineItems.value = listOf(anEvent)
|
||||||
val processor = createProcessor()
|
val processor = createMatrixTimelineDiffProcessor(timelineItems)
|
||||||
processor.postDiffs(listOf(FakeRustTimelineDiff(change = TimelineChange.APPEND)))
|
processor.postDiffs(listOf(FakeRustTimelineDiff(change = TimelineChange.APPEND)))
|
||||||
assertThat(timelineItems.value.count()).isEqualTo(2)
|
assertThat(timelineItems.value.count()).isEqualTo(2)
|
||||||
assertThat(timelineItems.value).containsExactly(
|
assertThat(timelineItems.value).containsExactly(
|
||||||
|
|
@ -43,7 +44,7 @@ class MatrixTimelineDiffProcessorTest {
|
||||||
@Test
|
@Test
|
||||||
fun `PushBack adds a new entry at the end of the list`() = runTest {
|
fun `PushBack adds a new entry at the end of the list`() = runTest {
|
||||||
timelineItems.value = listOf(anEvent)
|
timelineItems.value = listOf(anEvent)
|
||||||
val processor = createProcessor()
|
val processor = createMatrixTimelineDiffProcessor(timelineItems)
|
||||||
processor.postDiffs(listOf(FakeRustTimelineDiff(change = TimelineChange.PUSH_BACK)))
|
processor.postDiffs(listOf(FakeRustTimelineDiff(change = TimelineChange.PUSH_BACK)))
|
||||||
assertThat(timelineItems.value.count()).isEqualTo(2)
|
assertThat(timelineItems.value.count()).isEqualTo(2)
|
||||||
assertThat(timelineItems.value).containsExactly(
|
assertThat(timelineItems.value).containsExactly(
|
||||||
|
|
@ -55,7 +56,7 @@ class MatrixTimelineDiffProcessorTest {
|
||||||
@Test
|
@Test
|
||||||
fun `PushFront inserts a new entry at the start of the list`() = runTest {
|
fun `PushFront inserts a new entry at the start of the list`() = runTest {
|
||||||
timelineItems.value = listOf(anEvent)
|
timelineItems.value = listOf(anEvent)
|
||||||
val processor = createProcessor()
|
val processor = createMatrixTimelineDiffProcessor(timelineItems)
|
||||||
processor.postDiffs(listOf(FakeRustTimelineDiff(change = TimelineChange.PUSH_FRONT)))
|
processor.postDiffs(listOf(FakeRustTimelineDiff(change = TimelineChange.PUSH_FRONT)))
|
||||||
assertThat(timelineItems.value.count()).isEqualTo(2)
|
assertThat(timelineItems.value.count()).isEqualTo(2)
|
||||||
assertThat(timelineItems.value).containsExactly(
|
assertThat(timelineItems.value).containsExactly(
|
||||||
|
|
@ -67,7 +68,7 @@ class MatrixTimelineDiffProcessorTest {
|
||||||
@Test
|
@Test
|
||||||
fun `Set replaces an entry at some index`() = runTest {
|
fun `Set replaces an entry at some index`() = runTest {
|
||||||
timelineItems.value = listOf(anEvent, anEvent2)
|
timelineItems.value = listOf(anEvent, anEvent2)
|
||||||
val processor = createProcessor()
|
val processor = createMatrixTimelineDiffProcessor(timelineItems)
|
||||||
processor.postDiffs(listOf(FakeRustTimelineDiff(change = TimelineChange.SET)))
|
processor.postDiffs(listOf(FakeRustTimelineDiff(change = TimelineChange.SET)))
|
||||||
assertThat(timelineItems.value.count()).isEqualTo(2)
|
assertThat(timelineItems.value.count()).isEqualTo(2)
|
||||||
assertThat(timelineItems.value).containsExactly(
|
assertThat(timelineItems.value).containsExactly(
|
||||||
|
|
@ -79,7 +80,7 @@ class MatrixTimelineDiffProcessorTest {
|
||||||
@Test
|
@Test
|
||||||
fun `Insert inserts a new entry at the provided index`() = runTest {
|
fun `Insert inserts a new entry at the provided index`() = runTest {
|
||||||
timelineItems.value = listOf(anEvent, anEvent2)
|
timelineItems.value = listOf(anEvent, anEvent2)
|
||||||
val processor = createProcessor()
|
val processor = createMatrixTimelineDiffProcessor(timelineItems)
|
||||||
processor.postDiffs(listOf(FakeRustTimelineDiff(change = TimelineChange.INSERT)))
|
processor.postDiffs(listOf(FakeRustTimelineDiff(change = TimelineChange.INSERT)))
|
||||||
assertThat(timelineItems.value.count()).isEqualTo(3)
|
assertThat(timelineItems.value.count()).isEqualTo(3)
|
||||||
assertThat(timelineItems.value).containsExactly(
|
assertThat(timelineItems.value).containsExactly(
|
||||||
|
|
@ -92,7 +93,7 @@ class MatrixTimelineDiffProcessorTest {
|
||||||
@Test
|
@Test
|
||||||
fun `Remove removes an entry at some index`() = runTest {
|
fun `Remove removes an entry at some index`() = runTest {
|
||||||
timelineItems.value = listOf(anEvent, MatrixTimelineItem.Other, anEvent2)
|
timelineItems.value = listOf(anEvent, MatrixTimelineItem.Other, anEvent2)
|
||||||
val processor = createProcessor()
|
val processor = createMatrixTimelineDiffProcessor(timelineItems)
|
||||||
processor.postDiffs(listOf(FakeRustTimelineDiff(change = TimelineChange.REMOVE)))
|
processor.postDiffs(listOf(FakeRustTimelineDiff(change = TimelineChange.REMOVE)))
|
||||||
assertThat(timelineItems.value.count()).isEqualTo(2)
|
assertThat(timelineItems.value.count()).isEqualTo(2)
|
||||||
assertThat(timelineItems.value).containsExactly(
|
assertThat(timelineItems.value).containsExactly(
|
||||||
|
|
@ -104,7 +105,7 @@ class MatrixTimelineDiffProcessorTest {
|
||||||
@Test
|
@Test
|
||||||
fun `PopBack removes an entry at the end of the list`() = runTest {
|
fun `PopBack removes an entry at the end of the list`() = runTest {
|
||||||
timelineItems.value = listOf(anEvent, anEvent2)
|
timelineItems.value = listOf(anEvent, anEvent2)
|
||||||
val processor = createProcessor()
|
val processor = createMatrixTimelineDiffProcessor(timelineItems)
|
||||||
processor.postDiffs(listOf(FakeRustTimelineDiff(change = TimelineChange.POP_BACK)))
|
processor.postDiffs(listOf(FakeRustTimelineDiff(change = TimelineChange.POP_BACK)))
|
||||||
assertThat(timelineItems.value.count()).isEqualTo(1)
|
assertThat(timelineItems.value.count()).isEqualTo(1)
|
||||||
assertThat(timelineItems.value).containsExactly(
|
assertThat(timelineItems.value).containsExactly(
|
||||||
|
|
@ -115,7 +116,7 @@ class MatrixTimelineDiffProcessorTest {
|
||||||
@Test
|
@Test
|
||||||
fun `PopFront removes an entry at the start of the list`() = runTest {
|
fun `PopFront removes an entry at the start of the list`() = runTest {
|
||||||
timelineItems.value = listOf(anEvent, anEvent2)
|
timelineItems.value = listOf(anEvent, anEvent2)
|
||||||
val processor = createProcessor()
|
val processor = createMatrixTimelineDiffProcessor(timelineItems)
|
||||||
processor.postDiffs(listOf(FakeRustTimelineDiff(change = TimelineChange.POP_FRONT)))
|
processor.postDiffs(listOf(FakeRustTimelineDiff(change = TimelineChange.POP_FRONT)))
|
||||||
assertThat(timelineItems.value.count()).isEqualTo(1)
|
assertThat(timelineItems.value.count()).isEqualTo(1)
|
||||||
assertThat(timelineItems.value).containsExactly(
|
assertThat(timelineItems.value).containsExactly(
|
||||||
|
|
@ -126,7 +127,7 @@ class MatrixTimelineDiffProcessorTest {
|
||||||
@Test
|
@Test
|
||||||
fun `Clear removes all the entries`() = runTest {
|
fun `Clear removes all the entries`() = runTest {
|
||||||
timelineItems.value = listOf(anEvent, anEvent2)
|
timelineItems.value = listOf(anEvent, anEvent2)
|
||||||
val processor = createProcessor()
|
val processor = createMatrixTimelineDiffProcessor(timelineItems)
|
||||||
processor.postDiffs(listOf(FakeRustTimelineDiff(change = TimelineChange.CLEAR)))
|
processor.postDiffs(listOf(FakeRustTimelineDiff(change = TimelineChange.CLEAR)))
|
||||||
assertThat(timelineItems.value).isEmpty()
|
assertThat(timelineItems.value).isEmpty()
|
||||||
}
|
}
|
||||||
|
|
@ -134,7 +135,7 @@ class MatrixTimelineDiffProcessorTest {
|
||||||
@Test
|
@Test
|
||||||
fun `Truncate removes all entries after the provided length`() = runTest {
|
fun `Truncate removes all entries after the provided length`() = runTest {
|
||||||
timelineItems.value = listOf(anEvent, MatrixTimelineItem.Other, anEvent2)
|
timelineItems.value = listOf(anEvent, MatrixTimelineItem.Other, anEvent2)
|
||||||
val processor = createProcessor()
|
val processor = createMatrixTimelineDiffProcessor(timelineItems)
|
||||||
processor.postDiffs(listOf(FakeRustTimelineDiff(change = TimelineChange.TRUNCATE)))
|
processor.postDiffs(listOf(FakeRustTimelineDiff(change = TimelineChange.TRUNCATE)))
|
||||||
assertThat(timelineItems.value.count()).isEqualTo(1)
|
assertThat(timelineItems.value.count()).isEqualTo(1)
|
||||||
assertThat(timelineItems.value).containsExactly(
|
assertThat(timelineItems.value).containsExactly(
|
||||||
|
|
@ -145,27 +146,29 @@ class MatrixTimelineDiffProcessorTest {
|
||||||
@Test
|
@Test
|
||||||
fun `Reset removes all entries and add the provided ones`() = runTest {
|
fun `Reset removes all entries and add the provided ones`() = runTest {
|
||||||
timelineItems.value = listOf(anEvent, MatrixTimelineItem.Other, anEvent2)
|
timelineItems.value = listOf(anEvent, MatrixTimelineItem.Other, anEvent2)
|
||||||
val processor = createProcessor()
|
val processor = createMatrixTimelineDiffProcessor(timelineItems)
|
||||||
processor.postDiffs(listOf(FakeRustTimelineDiff(change = TimelineChange.RESET)))
|
processor.postDiffs(listOf(FakeRustTimelineDiff(change = TimelineChange.RESET)))
|
||||||
assertThat(timelineItems.value.count()).isEqualTo(1)
|
assertThat(timelineItems.value.count()).isEqualTo(1)
|
||||||
assertThat(timelineItems.value).containsExactly(
|
assertThat(timelineItems.value).containsExactly(
|
||||||
MatrixTimelineItem.Other,
|
MatrixTimelineItem.Other,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
private fun TestScope.createProcessor(): MatrixTimelineDiffProcessor {
|
|
||||||
val timelineEventContentMapper = TimelineEventContentMapper()
|
internal fun TestScope.createMatrixTimelineDiffProcessor(
|
||||||
val timelineItemMapper = MatrixTimelineItemMapper(
|
timelineItems: MutableSharedFlow<List<MatrixTimelineItem>>,
|
||||||
fetchDetailsForEvent = { _ -> Result.success(Unit) },
|
): MatrixTimelineDiffProcessor {
|
||||||
coroutineScope = this,
|
val timelineEventContentMapper = TimelineEventContentMapper()
|
||||||
virtualTimelineItemMapper = VirtualTimelineItemMapper(),
|
val timelineItemMapper = MatrixTimelineItemMapper(
|
||||||
eventTimelineItemMapper = EventTimelineItemMapper(
|
fetchDetailsForEvent = { _ -> Result.success(Unit) },
|
||||||
contentMapper = timelineEventContentMapper
|
coroutineScope = this,
|
||||||
)
|
virtualTimelineItemMapper = VirtualTimelineItemMapper(),
|
||||||
)
|
eventTimelineItemMapper = EventTimelineItemMapper(
|
||||||
return MatrixTimelineDiffProcessor(
|
contentMapper = timelineEventContentMapper
|
||||||
timelineItems,
|
)
|
||||||
timelineItemFactory = timelineItemMapper,
|
)
|
||||||
)
|
return MatrixTimelineDiffProcessor(
|
||||||
}
|
timelineItems = timelineItems,
|
||||||
|
timelineItemFactory = timelineItemMapper,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,139 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2024 New Vector Ltd.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
* Please see LICENSE in the repository root for full details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.libraries.matrix.impl.timeline
|
||||||
|
|
||||||
|
import app.cash.turbine.test
|
||||||
|
import com.google.common.truth.Truth.assertThat
|
||||||
|
import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem
|
||||||
|
import io.element.android.libraries.matrix.impl.fixtures.fakes.FakeRustEventTimelineItem
|
||||||
|
import io.element.android.libraries.matrix.impl.fixtures.fakes.FakeRustTimeline
|
||||||
|
import io.element.android.libraries.matrix.impl.fixtures.fakes.FakeRustTimelineDiff
|
||||||
|
import io.element.android.libraries.matrix.impl.fixtures.fakes.FakeRustTimelineItem
|
||||||
|
import io.element.android.tests.testutils.lambda.lambdaError
|
||||||
|
import io.element.android.tests.testutils.lambda.lambdaRecorder
|
||||||
|
import kotlinx.coroutines.CompletableDeferred
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
|
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||||
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
import kotlinx.coroutines.test.StandardTestDispatcher
|
||||||
|
import kotlinx.coroutines.test.TestScope
|
||||||
|
import kotlinx.coroutines.test.runCurrent
|
||||||
|
import kotlinx.coroutines.test.runTest
|
||||||
|
import org.junit.Test
|
||||||
|
import org.matrix.rustcomponents.sdk.Timeline
|
||||||
|
import org.matrix.rustcomponents.sdk.TimelineChange
|
||||||
|
import uniffi.matrix_sdk_ui.EventItemOrigin
|
||||||
|
|
||||||
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
|
class TimelineItemsSubscriberTest {
|
||||||
|
@Test
|
||||||
|
fun `when timeline emits an empty list of items, the flow must emits an empty list`() = runTest {
|
||||||
|
val timelineItems: MutableSharedFlow<List<MatrixTimelineItem>> =
|
||||||
|
MutableSharedFlow(replay = 1, extraBufferCapacity = Int.MAX_VALUE)
|
||||||
|
val timeline = FakeRustTimeline()
|
||||||
|
val timelineItemsSubscriber = createTimelineItemsSubscriber(
|
||||||
|
coroutineScope = backgroundScope,
|
||||||
|
timeline = timeline,
|
||||||
|
timelineItems = timelineItems,
|
||||||
|
)
|
||||||
|
timelineItems.test {
|
||||||
|
timelineItemsSubscriber.subscribeIfNeeded()
|
||||||
|
// Wait for the listener to be set.
|
||||||
|
runCurrent()
|
||||||
|
timeline.emitDiff(listOf(FakeRustTimelineDiff(item = null, change = TimelineChange.RESET)))
|
||||||
|
val final = awaitItem()
|
||||||
|
assertThat(final).isEmpty()
|
||||||
|
timelineItemsSubscriber.unsubscribeIfNeeded()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `when timeline emits a non empty list of items, the flow must emits a non empty list`() = runTest {
|
||||||
|
val timelineItems: MutableSharedFlow<List<MatrixTimelineItem>> =
|
||||||
|
MutableSharedFlow(replay = 1, extraBufferCapacity = Int.MAX_VALUE)
|
||||||
|
val timeline = FakeRustTimeline()
|
||||||
|
val timelineItemsSubscriber = createTimelineItemsSubscriber(
|
||||||
|
coroutineScope = backgroundScope,
|
||||||
|
timeline = timeline,
|
||||||
|
timelineItems = timelineItems,
|
||||||
|
)
|
||||||
|
timelineItems.test {
|
||||||
|
timelineItemsSubscriber.subscribeIfNeeded()
|
||||||
|
// Wait for the listener to be set.
|
||||||
|
runCurrent()
|
||||||
|
timeline.emitDiff(listOf(FakeRustTimelineDiff(item = FakeRustTimelineItem(), change = TimelineChange.RESET)))
|
||||||
|
val final = awaitItem()
|
||||||
|
assertThat(final).isNotEmpty()
|
||||||
|
timelineItemsSubscriber.unsubscribeIfNeeded()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `when timeline emits an item with SYNC origin, the callback onNewSyncedEvent is invoked`() = runTest {
|
||||||
|
val timelineItems: MutableSharedFlow<List<MatrixTimelineItem>> =
|
||||||
|
MutableSharedFlow(replay = 1, extraBufferCapacity = Int.MAX_VALUE)
|
||||||
|
val timeline = FakeRustTimeline()
|
||||||
|
val onNewSyncedEventRecorder = lambdaRecorder<Unit> { }
|
||||||
|
val timelineItemsSubscriber = createTimelineItemsSubscriber(
|
||||||
|
coroutineScope = backgroundScope,
|
||||||
|
timeline = timeline,
|
||||||
|
timelineItems = timelineItems,
|
||||||
|
onNewSyncedEvent = onNewSyncedEventRecorder,
|
||||||
|
)
|
||||||
|
timelineItems.test {
|
||||||
|
timelineItemsSubscriber.subscribeIfNeeded()
|
||||||
|
// Wait for the listener to be set.
|
||||||
|
runCurrent()
|
||||||
|
timeline.emitDiff(
|
||||||
|
listOf(
|
||||||
|
FakeRustTimelineDiff(
|
||||||
|
item = FakeRustTimelineItem(
|
||||||
|
asEventResult = FakeRustEventTimelineItem(origin = EventItemOrigin.SYNC)
|
||||||
|
),
|
||||||
|
change = TimelineChange.RESET,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
val final = awaitItem()
|
||||||
|
assertThat(final).isNotEmpty()
|
||||||
|
timelineItemsSubscriber.unsubscribeIfNeeded()
|
||||||
|
}
|
||||||
|
onNewSyncedEventRecorder.assertions().isCalledOnce()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `multiple subscriptions does not have side effect`() = runTest {
|
||||||
|
val timelineItemsSubscriber = createTimelineItemsSubscriber(
|
||||||
|
coroutineScope = backgroundScope,
|
||||||
|
)
|
||||||
|
timelineItemsSubscriber.subscribeIfNeeded()
|
||||||
|
timelineItemsSubscriber.subscribeIfNeeded()
|
||||||
|
timelineItemsSubscriber.unsubscribeIfNeeded()
|
||||||
|
timelineItemsSubscriber.unsubscribeIfNeeded()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun TestScope.createTimelineItemsSubscriber(
|
||||||
|
coroutineScope: CoroutineScope,
|
||||||
|
timeline: Timeline = FakeRustTimeline(),
|
||||||
|
timelineItems: MutableSharedFlow<List<MatrixTimelineItem>> = MutableSharedFlow(replay = 1, extraBufferCapacity = Int.MAX_VALUE),
|
||||||
|
initLatch: CompletableDeferred<Unit> = CompletableDeferred(),
|
||||||
|
isTimelineInitialized: MutableStateFlow<Boolean> = MutableStateFlow(false),
|
||||||
|
onNewSyncedEvent: () -> Unit = { lambdaError() },
|
||||||
|
): TimelineItemsSubscriber {
|
||||||
|
return TimelineItemsSubscriber(
|
||||||
|
timelineCoroutineScope = coroutineScope,
|
||||||
|
dispatcher = StandardTestDispatcher(testScheduler),
|
||||||
|
timeline = timeline,
|
||||||
|
timelineDiffProcessor = createMatrixTimelineDiffProcessor(timelineItems),
|
||||||
|
initLatch = initLatch,
|
||||||
|
isTimelineInitialized = isTimelineInitialized,
|
||||||
|
onNewSyncedEvent = onNewSyncedEvent,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -24,7 +24,6 @@ import io.element.android.services.analyticsproviders.api.AnalyticsProvider
|
||||||
import io.element.android.services.analyticsproviders.test.FakeAnalyticsProvider
|
import io.element.android.services.analyticsproviders.test.FakeAnalyticsProvider
|
||||||
import io.element.android.tests.testutils.lambda.lambdaRecorder
|
import io.element.android.tests.testutils.lambda.lambdaRecorder
|
||||||
import io.element.android.tests.testutils.lambda.value
|
import io.element.android.tests.testutils.lambda.value
|
||||||
import io.element.android.tests.testutils.runCancellableScopeTest
|
|
||||||
import kotlinx.coroutines.CompletableDeferred
|
import kotlinx.coroutines.CompletableDeferred
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
|
|
@ -37,13 +36,13 @@ import org.junit.Test
|
||||||
|
|
||||||
class DefaultAnalyticsServiceTest {
|
class DefaultAnalyticsServiceTest {
|
||||||
@Test
|
@Test
|
||||||
fun `getAvailableAnalyticsProviders return the set of provider`() = runCancellableScopeTest {
|
fun `getAvailableAnalyticsProviders return the set of provider`() = runTest {
|
||||||
val providers = setOf(
|
val providers = setOf(
|
||||||
FakeAnalyticsProvider(name = "provider1", stopLambda = { }),
|
FakeAnalyticsProvider(name = "provider1", stopLambda = { }),
|
||||||
FakeAnalyticsProvider(name = "provider2", stopLambda = { }),
|
FakeAnalyticsProvider(name = "provider2", stopLambda = { }),
|
||||||
)
|
)
|
||||||
val sut = createDefaultAnalyticsService(
|
val sut = createDefaultAnalyticsService(
|
||||||
coroutineScope = it,
|
coroutineScope = backgroundScope,
|
||||||
analyticsProviders = providers
|
analyticsProviders = providers
|
||||||
)
|
)
|
||||||
val result = sut.getAvailableAnalyticsProviders()
|
val result = sut.getAvailableAnalyticsProviders()
|
||||||
|
|
@ -51,17 +50,17 @@ class DefaultAnalyticsServiceTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `when consent is not provided, capture is no op`() = runCancellableScopeTest {
|
fun `when consent is not provided, capture is no op`() = runTest {
|
||||||
val sut = createDefaultAnalyticsService(it)
|
val sut = createDefaultAnalyticsService(backgroundScope)
|
||||||
sut.capture(anEvent)
|
sut.capture(anEvent)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `when consent is provided, capture is sent to the AnalyticsProvider`() = runCancellableScopeTest {
|
fun `when consent is provided, capture is sent to the AnalyticsProvider`() = runTest {
|
||||||
val initLambda = lambdaRecorder<Unit> { }
|
val initLambda = lambdaRecorder<Unit> { }
|
||||||
val captureLambda = lambdaRecorder<VectorAnalyticsEvent, Unit> { _ -> }
|
val captureLambda = lambdaRecorder<VectorAnalyticsEvent, Unit> { _ -> }
|
||||||
val sut = createDefaultAnalyticsService(
|
val sut = createDefaultAnalyticsService(
|
||||||
coroutineScope = it,
|
coroutineScope = backgroundScope,
|
||||||
analyticsStore = FakeAnalyticsStore(defaultUserConsent = true),
|
analyticsStore = FakeAnalyticsStore(defaultUserConsent = true),
|
||||||
analyticsProviders = setOf(
|
analyticsProviders = setOf(
|
||||||
FakeAnalyticsProvider(
|
FakeAnalyticsProvider(
|
||||||
|
|
@ -76,17 +75,17 @@ class DefaultAnalyticsServiceTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `when consent is not provided, screen is no op`() = runCancellableScopeTest {
|
fun `when consent is not provided, screen is no op`() = runTest {
|
||||||
val sut = createDefaultAnalyticsService(it)
|
val sut = createDefaultAnalyticsService(backgroundScope)
|
||||||
sut.screen(aScreen)
|
sut.screen(aScreen)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `when consent is provided, screen is sent to the AnalyticsProvider`() = runCancellableScopeTest {
|
fun `when consent is provided, screen is sent to the AnalyticsProvider`() = runTest {
|
||||||
val initLambda = lambdaRecorder<Unit> { }
|
val initLambda = lambdaRecorder<Unit> { }
|
||||||
val screenLambda = lambdaRecorder<VectorAnalyticsScreen, Unit> { _ -> }
|
val screenLambda = lambdaRecorder<VectorAnalyticsScreen, Unit> { _ -> }
|
||||||
val sut = createDefaultAnalyticsService(
|
val sut = createDefaultAnalyticsService(
|
||||||
coroutineScope = it,
|
coroutineScope = backgroundScope,
|
||||||
analyticsStore = FakeAnalyticsStore(defaultUserConsent = true),
|
analyticsStore = FakeAnalyticsStore(defaultUserConsent = true),
|
||||||
analyticsProviders = setOf(
|
analyticsProviders = setOf(
|
||||||
FakeAnalyticsProvider(
|
FakeAnalyticsProvider(
|
||||||
|
|
@ -101,17 +100,17 @@ class DefaultAnalyticsServiceTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `when consent is not provided, trackError is no op`() = runCancellableScopeTest {
|
fun `when consent is not provided, trackError is no op`() = runTest {
|
||||||
val sut = createDefaultAnalyticsService(it)
|
val sut = createDefaultAnalyticsService(backgroundScope)
|
||||||
sut.trackError(anError)
|
sut.trackError(anError)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `when consent is provided, trackError is sent to the AnalyticsProvider`() = runCancellableScopeTest {
|
fun `when consent is provided, trackError is sent to the AnalyticsProvider`() = runTest {
|
||||||
val initLambda = lambdaRecorder<Unit> { }
|
val initLambda = lambdaRecorder<Unit> { }
|
||||||
val trackErrorLambda = lambdaRecorder<Throwable, Unit> { _ -> }
|
val trackErrorLambda = lambdaRecorder<Throwable, Unit> { _ -> }
|
||||||
val sut = createDefaultAnalyticsService(
|
val sut = createDefaultAnalyticsService(
|
||||||
coroutineScope = it,
|
coroutineScope = backgroundScope,
|
||||||
analyticsStore = FakeAnalyticsStore(defaultUserConsent = true),
|
analyticsStore = FakeAnalyticsStore(defaultUserConsent = true),
|
||||||
analyticsProviders = setOf(
|
analyticsProviders = setOf(
|
||||||
FakeAnalyticsProvider(
|
FakeAnalyticsProvider(
|
||||||
|
|
@ -126,10 +125,10 @@ class DefaultAnalyticsServiceTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `setUserConsent is sent to the store`() = runCancellableScopeTest {
|
fun `setUserConsent is sent to the store`() = runTest {
|
||||||
val store = FakeAnalyticsStore()
|
val store = FakeAnalyticsStore()
|
||||||
val sut = createDefaultAnalyticsService(
|
val sut = createDefaultAnalyticsService(
|
||||||
coroutineScope = it,
|
coroutineScope = backgroundScope,
|
||||||
analyticsStore = store,
|
analyticsStore = store,
|
||||||
)
|
)
|
||||||
assertThat(store.userConsentFlow.first()).isFalse()
|
assertThat(store.userConsentFlow.first()).isFalse()
|
||||||
|
|
@ -140,10 +139,10 @@ class DefaultAnalyticsServiceTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `setAnalyticsId is sent to the store`() = runCancellableScopeTest {
|
fun `setAnalyticsId is sent to the store`() = runTest {
|
||||||
val store = FakeAnalyticsStore()
|
val store = FakeAnalyticsStore()
|
||||||
val sut = createDefaultAnalyticsService(
|
val sut = createDefaultAnalyticsService(
|
||||||
coroutineScope = it,
|
coroutineScope = backgroundScope,
|
||||||
analyticsStore = store,
|
analyticsStore = store,
|
||||||
)
|
)
|
||||||
assertThat(store.analyticsIdFlow.first()).isEqualTo("")
|
assertThat(store.analyticsIdFlow.first()).isEqualTo("")
|
||||||
|
|
@ -154,10 +153,10 @@ class DefaultAnalyticsServiceTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `setDidAskUserConsent is sent to the store`() = runCancellableScopeTest {
|
fun `setDidAskUserConsent is sent to the store`() = runTest {
|
||||||
val store = FakeAnalyticsStore()
|
val store = FakeAnalyticsStore()
|
||||||
val sut = createDefaultAnalyticsService(
|
val sut = createDefaultAnalyticsService(
|
||||||
coroutineScope = it,
|
coroutineScope = backgroundScope,
|
||||||
analyticsStore = store,
|
analyticsStore = store,
|
||||||
)
|
)
|
||||||
assertThat(store.didAskUserConsentFlow.first()).isFalse()
|
assertThat(store.didAskUserConsentFlow.first()).isFalse()
|
||||||
|
|
@ -168,13 +167,13 @@ class DefaultAnalyticsServiceTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `when a session is deleted, the store is reset`() = runCancellableScopeTest {
|
fun `when a session is deleted, the store is reset`() = runTest {
|
||||||
val resetLambda = lambdaRecorder<Unit> { }
|
val resetLambda = lambdaRecorder<Unit> { }
|
||||||
val store = FakeAnalyticsStore(
|
val store = FakeAnalyticsStore(
|
||||||
resetLambda = resetLambda,
|
resetLambda = resetLambda,
|
||||||
)
|
)
|
||||||
val sut = createDefaultAnalyticsService(
|
val sut = createDefaultAnalyticsService(
|
||||||
coroutineScope = it,
|
coroutineScope = backgroundScope,
|
||||||
analyticsStore = store,
|
analyticsStore = store,
|
||||||
)
|
)
|
||||||
sut.onSessionDeleted("userId")
|
sut.onSessionDeleted("userId")
|
||||||
|
|
@ -182,12 +181,12 @@ class DefaultAnalyticsServiceTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `when reset is invoked, the user consent is reset`() = runCancellableScopeTest {
|
fun `when reset is invoked, the user consent is reset`() = runTest {
|
||||||
val store = FakeAnalyticsStore(
|
val store = FakeAnalyticsStore(
|
||||||
defaultDidAskUserConsent = true,
|
defaultDidAskUserConsent = true,
|
||||||
)
|
)
|
||||||
val sut = createDefaultAnalyticsService(
|
val sut = createDefaultAnalyticsService(
|
||||||
coroutineScope = it,
|
coroutineScope = backgroundScope,
|
||||||
analyticsStore = store,
|
analyticsStore = store,
|
||||||
)
|
)
|
||||||
assertThat(store.didAskUserConsentFlow.first()).isTrue()
|
assertThat(store.didAskUserConsentFlow.first()).isTrue()
|
||||||
|
|
@ -196,9 +195,9 @@ class DefaultAnalyticsServiceTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `when a session is added, nothing happen`() = runCancellableScopeTest {
|
fun `when a session is added, nothing happen`() = runTest {
|
||||||
val sut = createDefaultAnalyticsService(
|
val sut = createDefaultAnalyticsService(
|
||||||
coroutineScope = it,
|
coroutineScope = backgroundScope,
|
||||||
)
|
)
|
||||||
sut.onSessionCreated("userId")
|
sut.onSessionCreated("userId")
|
||||||
}
|
}
|
||||||
|
|
@ -231,10 +230,10 @@ class DefaultAnalyticsServiceTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `when consent is provided, updateUserProperties is sent to the provider`() = runCancellableScopeTest {
|
fun `when consent is provided, updateUserProperties is sent to the provider`() = runTest {
|
||||||
val updateUserPropertiesLambda = lambdaRecorder<UserProperties, Unit> { _ -> }
|
val updateUserPropertiesLambda = lambdaRecorder<UserProperties, Unit> { _ -> }
|
||||||
val sut = createDefaultAnalyticsService(
|
val sut = createDefaultAnalyticsService(
|
||||||
coroutineScope = it,
|
coroutineScope = backgroundScope,
|
||||||
analyticsProviders = setOf(
|
analyticsProviders = setOf(
|
||||||
FakeAnalyticsProvider(
|
FakeAnalyticsProvider(
|
||||||
initLambda = { },
|
initLambda = { },
|
||||||
|
|
@ -248,10 +247,10 @@ class DefaultAnalyticsServiceTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `when super properties are updated, updateSuperProperties is sent to the provider`() = runCancellableScopeTest {
|
fun `when super properties are updated, updateSuperProperties is sent to the provider`() = runTest {
|
||||||
val updateSuperPropertiesLambda = lambdaRecorder<SuperProperties, Unit> { _ -> }
|
val updateSuperPropertiesLambda = lambdaRecorder<SuperProperties, Unit> { _ -> }
|
||||||
val sut = createDefaultAnalyticsService(
|
val sut = createDefaultAnalyticsService(
|
||||||
coroutineScope = it,
|
coroutineScope = backgroundScope,
|
||||||
analyticsProviders = setOf(
|
analyticsProviders = setOf(
|
||||||
FakeAnalyticsProvider(
|
FakeAnalyticsProvider(
|
||||||
initLambda = { },
|
initLambda = { },
|
||||||
|
|
|
||||||
|
|
@ -23,9 +23,9 @@ import io.element.android.services.appnavstate.test.A_SESSION_OWNER
|
||||||
import io.element.android.services.appnavstate.test.A_SPACE_OWNER
|
import io.element.android.services.appnavstate.test.A_SPACE_OWNER
|
||||||
import io.element.android.services.appnavstate.test.A_THREAD_OWNER
|
import io.element.android.services.appnavstate.test.A_THREAD_OWNER
|
||||||
import io.element.android.services.appnavstate.test.FakeAppForegroundStateService
|
import io.element.android.services.appnavstate.test.FakeAppForegroundStateService
|
||||||
import io.element.android.tests.testutils.runCancellableScopeTest
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.flow.first
|
import kotlinx.coroutines.flow.first
|
||||||
|
import kotlinx.coroutines.test.runTest
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
|
||||||
class DefaultNavigationStateServiceTest {
|
class DefaultNavigationStateServiceTest {
|
||||||
|
|
@ -51,8 +51,8 @@ class DefaultNavigationStateServiceTest {
|
||||||
)
|
)
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testNavigation() = runCancellableScopeTest { scope ->
|
fun testNavigation() = runTest {
|
||||||
val service = createStateService(scope)
|
val service = createStateService(backgroundScope)
|
||||||
assertThat(service.appNavigationState.first().navigationState).isEqualTo(navigationStateRoot)
|
assertThat(service.appNavigationState.first().navigationState).isEqualTo(navigationStateRoot)
|
||||||
service.onNavigateToSession(A_SESSION_OWNER, A_SESSION_ID)
|
service.onNavigateToSession(A_SESSION_OWNER, A_SESSION_ID)
|
||||||
assertThat(service.appNavigationState.first().navigationState).isEqualTo(navigationStateSession)
|
assertThat(service.appNavigationState.first().navigationState).isEqualTo(navigationStateSession)
|
||||||
|
|
@ -74,15 +74,15 @@ class DefaultNavigationStateServiceTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testFailure() = runCancellableScopeTest { scope ->
|
fun testFailure() = runTest {
|
||||||
val service = createStateService(scope)
|
val service = createStateService(backgroundScope)
|
||||||
service.onNavigateToSpace(A_SPACE_OWNER, A_SPACE_ID)
|
service.onNavigateToSpace(A_SPACE_OWNER, A_SPACE_ID)
|
||||||
assertThat(service.appNavigationState.value.navigationState).isEqualTo(NavigationState.Root)
|
assertThat(service.appNavigationState.value.navigationState).isEqualTo(NavigationState.Root)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testOnNavigateToThread() = runCancellableScopeTest { scope ->
|
fun testOnNavigateToThread() = runTest {
|
||||||
val service = createStateService(scope)
|
val service = createStateService(backgroundScope)
|
||||||
// From root (no effect)
|
// From root (no effect)
|
||||||
service.onNavigateToThread(A_THREAD_OWNER, A_THREAD_ID)
|
service.onNavigateToThread(A_THREAD_OWNER, A_THREAD_ID)
|
||||||
assertThat(service.appNavigationState.first().navigationState).isEqualTo(navigationStateRoot)
|
assertThat(service.appNavigationState.first().navigationState).isEqualTo(navigationStateRoot)
|
||||||
|
|
@ -110,8 +110,8 @@ class DefaultNavigationStateServiceTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testOnNavigateToRoom() = runCancellableScopeTest { scope ->
|
fun testOnNavigateToRoom() = runTest {
|
||||||
val service = createStateService(scope)
|
val service = createStateService(backgroundScope)
|
||||||
// From root (no effect)
|
// From root (no effect)
|
||||||
service.onNavigateToRoom(A_ROOM_OWNER, A_ROOM_ID)
|
service.onNavigateToRoom(A_ROOM_OWNER, A_ROOM_ID)
|
||||||
assertThat(service.appNavigationState.first().navigationState).isEqualTo(navigationStateRoot)
|
assertThat(service.appNavigationState.first().navigationState).isEqualTo(navigationStateRoot)
|
||||||
|
|
@ -139,8 +139,8 @@ class DefaultNavigationStateServiceTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testOnNavigateToSpace() = runCancellableScopeTest { scope ->
|
fun testOnNavigateToSpace() = runTest {
|
||||||
val service = createStateService(scope)
|
val service = createStateService(backgroundScope)
|
||||||
// From root (no effect)
|
// From root (no effect)
|
||||||
service.onNavigateToSpace(A_SPACE_OWNER, A_SPACE_ID)
|
service.onNavigateToSpace(A_SPACE_OWNER, A_SPACE_ID)
|
||||||
assertThat(service.appNavigationState.first().navigationState).isEqualTo(navigationStateRoot)
|
assertThat(service.appNavigationState.first().navigationState).isEqualTo(navigationStateRoot)
|
||||||
|
|
@ -168,8 +168,8 @@ class DefaultNavigationStateServiceTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testOnNavigateToSession() = runCancellableScopeTest { scope ->
|
fun testOnNavigateToSession() = runTest {
|
||||||
val service = createStateService(scope)
|
val service = createStateService(backgroundScope)
|
||||||
// From root
|
// From root
|
||||||
service.onNavigateToSession(A_SESSION_OWNER, A_SESSION_ID)
|
service.onNavigateToSession(A_SESSION_OWNER, A_SESSION_ID)
|
||||||
assertThat(service.appNavigationState.first().navigationState).isEqualTo(navigationStateSession)
|
assertThat(service.appNavigationState.first().navigationState).isEqualTo(navigationStateSession)
|
||||||
|
|
@ -197,8 +197,8 @@ class DefaultNavigationStateServiceTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testOnLeavingThread() = runCancellableScopeTest { scope ->
|
fun testOnLeavingThread() = runTest {
|
||||||
val service = createStateService(scope)
|
val service = createStateService(backgroundScope)
|
||||||
// From root (no effect)
|
// From root (no effect)
|
||||||
service.onLeavingThread(A_THREAD_OWNER)
|
service.onLeavingThread(A_THREAD_OWNER)
|
||||||
assertThat(service.appNavigationState.first().navigationState).isEqualTo(navigationStateRoot)
|
assertThat(service.appNavigationState.first().navigationState).isEqualTo(navigationStateRoot)
|
||||||
|
|
@ -225,8 +225,8 @@ class DefaultNavigationStateServiceTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testOnLeavingRoom() = runCancellableScopeTest { scope ->
|
fun testOnLeavingRoom() = runTest {
|
||||||
val service = createStateService(scope)
|
val service = createStateService(backgroundScope)
|
||||||
// From root (no effect)
|
// From root (no effect)
|
||||||
service.onLeavingRoom(A_ROOM_OWNER)
|
service.onLeavingRoom(A_ROOM_OWNER)
|
||||||
assertThat(service.appNavigationState.first().navigationState).isEqualTo(navigationStateRoot)
|
assertThat(service.appNavigationState.first().navigationState).isEqualTo(navigationStateRoot)
|
||||||
|
|
@ -253,8 +253,8 @@ class DefaultNavigationStateServiceTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testOnLeavingSpace() = runCancellableScopeTest { scope ->
|
fun testOnLeavingSpace() = runTest {
|
||||||
val service = createStateService(scope)
|
val service = createStateService(backgroundScope)
|
||||||
// From root (no effect)
|
// From root (no effect)
|
||||||
service.onLeavingSpace(A_SPACE_OWNER)
|
service.onLeavingSpace(A_SPACE_OWNER)
|
||||||
assertThat(service.appNavigationState.first().navigationState).isEqualTo(navigationStateRoot)
|
assertThat(service.appNavigationState.first().navigationState).isEqualTo(navigationStateRoot)
|
||||||
|
|
@ -281,8 +281,8 @@ class DefaultNavigationStateServiceTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testOnLeavingSession() = runCancellableScopeTest { scope ->
|
fun testOnLeavingSession() = runTest {
|
||||||
val service = createStateService(scope)
|
val service = createStateService(backgroundScope)
|
||||||
// From root
|
// From root
|
||||||
service.onLeavingSession(A_SESSION_OWNER)
|
service.onLeavingSession(A_SESSION_OWNER)
|
||||||
assertThat(service.appNavigationState.first().navigationState).isEqualTo(navigationStateRoot)
|
assertThat(service.appNavigationState.first().navigationState).isEqualTo(navigationStateRoot)
|
||||||
|
|
|
||||||
|
|
@ -1,32 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2023, 2024 New Vector Ltd.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
* Please see LICENSE in the repository root for full details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package io.element.android.tests.testutils
|
|
||||||
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
|
||||||
import kotlinx.coroutines.SupervisorJob
|
|
||||||
import kotlinx.coroutines.cancel
|
|
||||||
import kotlinx.coroutines.test.TestScope
|
|
||||||
import kotlinx.coroutines.test.runTest
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Run a test with a [CoroutineScope] that will be cancelled automatically and avoiding failing the test.
|
|
||||||
*/
|
|
||||||
fun runCancellableScopeTest(block: suspend (CoroutineScope) -> Unit) = runTest {
|
|
||||||
val scope = CoroutineScope(coroutineContext + SupervisorJob())
|
|
||||||
block(scope)
|
|
||||||
scope.cancel()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Run a test with a [CoroutineScope] that will be cancelled automatically and avoiding failing the test.
|
|
||||||
*/
|
|
||||||
fun runCancellableScopeTestWithTestScope(block: suspend (testScope: TestScope, cancellableScope: CoroutineScope) -> Unit) = runTest {
|
|
||||||
val scope = CoroutineScope(coroutineContext + SupervisorJob())
|
|
||||||
block(this, scope)
|
|
||||||
scope.cancel()
|
|
||||||
}
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue