Browse Source

Merge pull request #3554 from element-hq/feature/bma/testEmptyTimeline

Add unit tests on TimelineItemsSubscriber
pull/3585/head
Benoit Marty 2 weeks ago committed by GitHub
parent
commit
29356b96c1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 20
      libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/fixtures/factories/EventTimelineItemDebugInfo.kt
  2. 44
      libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/fixtures/fakes/FakeRustEventTimelineItem.kt
  3. 26
      libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/fixtures/fakes/FakeRustTimeline.kt
  4. 6
      libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/fixtures/fakes/FakeRustTimelineItem.kt
  5. 18
      libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/fixtures/fakes/FakeRustTimelineItemContent.kt
  6. 10
      libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/roomdirectory/RustRoomDirectoryListTest.kt
  7. 8
      libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/roomdirectory/RustRoomDirectoryServiceTest.kt
  8. 6
      libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomListFactoryTest.kt
  9. 10
      libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/roomlist/RustRoomListServiceTest.kt
  10. 31
      libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/timeline/MatrixTimelineDiffProcessorTest.kt
  11. 139
      libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/timeline/TimelineItemsSubscriberTest.kt
  12. 61
      services/analytics/impl/src/test/kotlin/io/element/android/services/analytics/impl/DefaultAnalyticsServiceTest.kt
  13. 42
      services/appnavstate/impl/src/test/kotlin/io/element/android/services/appnavstate/impl/DefaultNavigationStateServiceTest.kt
  14. 32
      tests/testutils/src/main/kotlin/io/element/android/tests/testutils/RunCancellableTest.kt

20
libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/fixtures/factories/EventTimelineItemDebugInfo.kt

@ -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
)

44
libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/fixtures/fakes/FakeRustEventTimelineItem.kt

@ -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
}

26
libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/fixtures/fakes/FakeRustTimeline.kt

@ -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)
}
}

6
libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/fixtures/fakes/FakeRustTimelineItem.kt

@ -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"

18
libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/fixtures/fakes/FakeRustTimelineItemContent.kt

@ -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
}

10
libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/roomdirectory/RustRoomDirectoryListTest.kt

@ -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
libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/roomdirectory/RustRoomDirectoryServiceTest.kt

@ -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)
} }
} }

6
libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/roomlist/RoomListFactoryTest.kt

@ -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,

10
libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/roomlist/RustRoomListServiceTest.kt

@ -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)

31
libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/timeline/MatrixTimelineDiffProcessorTest.kt

@ -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,15 +146,18 @@ 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 { internal fun TestScope.createMatrixTimelineDiffProcessor(
timelineItems: MutableSharedFlow<List<MatrixTimelineItem>>,
): MatrixTimelineDiffProcessor {
val timelineEventContentMapper = TimelineEventContentMapper() val timelineEventContentMapper = TimelineEventContentMapper()
val timelineItemMapper = MatrixTimelineItemMapper( val timelineItemMapper = MatrixTimelineItemMapper(
fetchDetailsForEvent = { _ -> Result.success(Unit) }, fetchDetailsForEvent = { _ -> Result.success(Unit) },
@ -164,8 +168,7 @@ class MatrixTimelineDiffProcessorTest {
) )
) )
return MatrixTimelineDiffProcessor( return MatrixTimelineDiffProcessor(
timelineItems, timelineItems = timelineItems,
timelineItemFactory = timelineItemMapper, timelineItemFactory = timelineItemMapper,
) )
} }
}

139
libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/timeline/TimelineItemsSubscriberTest.kt

@ -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,
)
}

61
services/analytics/impl/src/test/kotlin/io/element/android/services/analytics/impl/DefaultAnalyticsServiceTest.kt

@ -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 = { },

42
services/appnavstate/impl/src/test/kotlin/io/element/android/services/appnavstate/impl/DefaultNavigationStateServiceTest.kt

@ -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)

32
tests/testutils/src/main/kotlin/io/element/android/tests/testutils/RunCancellableTest.kt

@ -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…
Cancel
Save