Browse Source

Add test on TimelineItemsSubscriber.

pull/3554/head
Benoit Marty 3 weeks ago
parent
commit
b7c6369ebf
  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. 27
      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. 3
      libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/timeline/MatrixTimelineDiffProcessorTest.kt
  7. 139
      libraries/matrix/impl/src/test/kotlin/io/element/android/libraries/matrix/impl/timeline/TimelineItemsSubscriberTest.kt

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

@ -0,0 +1,20 @@ @@ -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 @@ @@ -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
}

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

@ -0,0 +1,27 @@ @@ -0,0 +1,27 @@
/*
* 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 @@ -12,8 +12,10 @@ import org.matrix.rustcomponents.sdk.NoPointer
import org.matrix.rustcomponents.sdk.TimelineItem
import org.matrix.rustcomponents.sdk.VirtualTimelineItem
class FakeRustTimelineItem : TimelineItem(NoPointer) {
override fun asEvent(): EventTimelineItem? = null
class FakeRustTimelineItem(
private val asEventResult: EventTimelineItem? = null,
) : TimelineItem(NoPointer) {
override fun asEvent(): EventTimelineItem? = asEventResult
override fun asVirtual(): VirtualTimelineItem? = null
override fun fmtDebug(): String = "fmtDebug"
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 @@ @@ -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
}

3
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 @@ -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_2
import io.element.android.libraries.matrix.test.timeline.anEventTimelineItem
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runTest
@ -155,7 +156,7 @@ class MatrixTimelineDiffProcessorTest { @@ -155,7 +156,7 @@ class MatrixTimelineDiffProcessorTest {
}
internal fun TestScope.createMatrixTimelineDiffProcessor(
timelineItems: MutableStateFlow<List<MatrixTimelineItem>>,
timelineItems: MutableSharedFlow<List<MatrixTimelineItem>>,
): MatrixTimelineDiffProcessor {
val timelineEventContentMapper = TimelineEventContentMapper()
val timelineItemMapper = MatrixTimelineItemMapper(

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

@ -0,0 +1,139 @@ @@ -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 io.element.android.tests.testutils.runCancellableScopeTestWithTestScope
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 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`() = runCancellableScopeTestWithTestScope { testScope, cancellableScope ->
val timelineItems: MutableSharedFlow<List<MatrixTimelineItem>> =
MutableSharedFlow(replay = 1, extraBufferCapacity = Int.MAX_VALUE)
val timeline = FakeRustTimeline()
val timelineItemsSubscriber = testScope.createTimelineItemsSubscriber(
coroutineScope = cancellableScope,
timeline = timeline,
timelineItems = timelineItems,
)
timelineItems.test {
timelineItemsSubscriber.subscribeIfNeeded()
// Wait for the listener to be set.
testScope.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`() = runCancellableScopeTestWithTestScope { testScope, cancellableScope ->
val timelineItems: MutableSharedFlow<List<MatrixTimelineItem>> =
MutableSharedFlow(replay = 1, extraBufferCapacity = Int.MAX_VALUE)
val timeline = FakeRustTimeline()
val timelineItemsSubscriber = testScope.createTimelineItemsSubscriber(
coroutineScope = cancellableScope,
timeline = timeline,
timelineItems = timelineItems,
)
timelineItems.test {
timelineItemsSubscriber.subscribeIfNeeded()
// Wait for the listener to be set.
testScope.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`() = runCancellableScopeTestWithTestScope { testScope, cancellableScope ->
val timelineItems: MutableSharedFlow<List<MatrixTimelineItem>> =
MutableSharedFlow(replay = 1, extraBufferCapacity = Int.MAX_VALUE)
val timeline = FakeRustTimeline()
val onNewSyncedEventRecorder = lambdaRecorder<Unit> { }
val timelineItemsSubscriber = testScope.createTimelineItemsSubscriber(
coroutineScope = cancellableScope,
timeline = timeline,
timelineItems = timelineItems,
onNewSyncedEvent = onNewSyncedEventRecorder,
)
timelineItems.test {
timelineItemsSubscriber.subscribeIfNeeded()
// Wait for the listener to be set.
testScope.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`() = runCancellableScopeTestWithTestScope { testScope, cancellableScope ->
val timelineItemsSubscriber = testScope.createTimelineItemsSubscriber(
coroutineScope = cancellableScope,
)
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,
)
}
}
Loading…
Cancel
Save