Add test on MediaViewerDataSource
This commit is contained in:
committed by
Benoit Marty
parent
36924070df
commit
b0bfea9cc4
@@ -9,6 +9,7 @@ package io.element.android.libraries.mediaviewer.impl.gallery.ui
|
||||
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
import io.element.android.libraries.core.preview.loremIpsum
|
||||
import io.element.android.libraries.matrix.api.core.EventId
|
||||
import io.element.android.libraries.matrix.api.core.UniqueId
|
||||
import io.element.android.libraries.matrix.api.media.MediaSource
|
||||
import io.element.android.libraries.mediaviewer.api.aPdfMediaInfo
|
||||
@@ -30,12 +31,13 @@ class MediaItemFileProvider : PreviewParameterProvider<MediaItem.File> {
|
||||
|
||||
fun aMediaItemFile(
|
||||
id: UniqueId = UniqueId("fileId"),
|
||||
eventId: EventId? = null,
|
||||
filename: String = "filename",
|
||||
caption: String? = null,
|
||||
): MediaItem.File {
|
||||
return MediaItem.File(
|
||||
id = id,
|
||||
eventId = null,
|
||||
eventId = eventId,
|
||||
mediaInfo = aPdfMediaInfo(
|
||||
filename = filename,
|
||||
caption = caption,
|
||||
|
||||
@@ -13,10 +13,11 @@ import io.element.android.libraries.mediaviewer.impl.gallery.MediaItem
|
||||
|
||||
fun aMediaItemLoadingIndicator(
|
||||
id: UniqueId = UniqueId("loadingId"),
|
||||
direction: Timeline.PaginationDirection = Timeline.PaginationDirection.BACKWARDS,
|
||||
): MediaItem.LoadingIndicator {
|
||||
return MediaItem.LoadingIndicator(
|
||||
id = id,
|
||||
direction = Timeline.PaginationDirection.BACKWARDS,
|
||||
direction = direction,
|
||||
timestamp = 123,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
package io.element.android.libraries.mediaviewer.impl.viewer
|
||||
|
||||
import androidx.annotation.VisibleForTesting
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.State
|
||||
@@ -63,7 +64,8 @@ class MediaViewerDataSource(
|
||||
return remember { dataFlow() }.collectAsState(initialData())
|
||||
}
|
||||
|
||||
private fun dataFlow(): Flow<PersistentList<MediaViewerPageData>> {
|
||||
@VisibleForTesting
|
||||
fun dataFlow(): Flow<PersistentList<MediaViewerPageData>> {
|
||||
return galleryDataSource.groupedMediaItemsFlow()
|
||||
.map { groupedItems ->
|
||||
val mediaItems = groupedItems.dataOrNull()?.getItems(galleryMode).orEmpty()
|
||||
@@ -104,7 +106,7 @@ class MediaViewerDataSource(
|
||||
}
|
||||
}
|
||||
if (isEmpty()) {
|
||||
MediaViewerPageData.Loading(Timeline.PaginationDirection.BACKWARDS)
|
||||
add(MediaViewerPageData.Loading(Timeline.PaginationDirection.BACKWARDS))
|
||||
}
|
||||
}.toPersistentList()
|
||||
|
||||
|
||||
@@ -0,0 +1,275 @@
|
||||
/*
|
||||
* Copyright 2025 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.mediaviewer.impl.viewer
|
||||
|
||||
import android.net.Uri
|
||||
import app.cash.turbine.test
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import io.element.android.libraries.architecture.AsyncData
|
||||
import io.element.android.libraries.matrix.api.media.MatrixMediaLoader
|
||||
import io.element.android.libraries.matrix.api.timeline.Timeline
|
||||
import io.element.android.libraries.matrix.test.AN_EVENT_ID
|
||||
import io.element.android.libraries.matrix.test.AN_EVENT_ID_2
|
||||
import io.element.android.libraries.matrix.test.AN_EXCEPTION
|
||||
import io.element.android.libraries.matrix.test.media.FakeMatrixMediaLoader
|
||||
import io.element.android.libraries.mediaviewer.api.local.LocalMediaFactory
|
||||
import io.element.android.libraries.mediaviewer.impl.gallery.FakeMediaGalleryDataSource
|
||||
import io.element.android.libraries.mediaviewer.impl.gallery.MediaGalleryDataSource
|
||||
import io.element.android.libraries.mediaviewer.impl.gallery.MediaGalleryMode
|
||||
import io.element.android.libraries.mediaviewer.impl.gallery.aGroupedMediaItems
|
||||
import io.element.android.libraries.mediaviewer.impl.gallery.ui.aMediaItemDateSeparator
|
||||
import io.element.android.libraries.mediaviewer.impl.gallery.ui.aMediaItemFile
|
||||
import io.element.android.libraries.mediaviewer.impl.gallery.ui.aMediaItemImage
|
||||
import io.element.android.libraries.mediaviewer.impl.gallery.ui.aMediaItemLoadingIndicator
|
||||
import io.element.android.libraries.mediaviewer.test.FakeLocalMediaFactory
|
||||
import io.element.android.tests.testutils.lambda.lambdaRecorder
|
||||
import io.element.android.tests.testutils.lambda.value
|
||||
import io.element.android.tests.testutils.testCoroutineDispatchers
|
||||
import io.mockk.mockk
|
||||
import kotlinx.coroutines.test.TestScope
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Test
|
||||
|
||||
class MediaViewerDataSourceTest {
|
||||
private val mockMediaUrl: Uri = mockk("localMediaUri")
|
||||
|
||||
@Test
|
||||
fun `setup should start the gallery data source`() = runTest {
|
||||
val startLambda = lambdaRecorder<Unit> { }
|
||||
val galleryDataSource = FakeMediaGalleryDataSource(
|
||||
startLambda = startLambda
|
||||
)
|
||||
val sut = createMediaViewerDataSource(
|
||||
galleryDataSource = galleryDataSource,
|
||||
)
|
||||
sut.setup()
|
||||
startLambda.assertions().isCalledOnce()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test dispose`() = runTest {
|
||||
val sut = createMediaViewerDataSource()
|
||||
sut.dispose()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test dataFlow uninitialized, loading and error`() = runTest {
|
||||
val galleryDataSource = FakeMediaGalleryDataSource()
|
||||
val sut = createMediaViewerDataSource(
|
||||
galleryDataSource = galleryDataSource,
|
||||
)
|
||||
sut.dataFlow().test {
|
||||
galleryDataSource.emitGroupedMediaItems(AsyncData.Uninitialized)
|
||||
assertThat(awaitItem().first()).isInstanceOf(MediaViewerPageData.Loading::class.java)
|
||||
galleryDataSource.emitGroupedMediaItems(AsyncData.Loading())
|
||||
assertThat(awaitItem().first()).isInstanceOf(MediaViewerPageData.Loading::class.java)
|
||||
galleryDataSource.emitGroupedMediaItems(AsyncData.Failure(AN_EXCEPTION))
|
||||
// TODO Add an error screen in the ui
|
||||
assertThat(awaitItem().first()).isInstanceOf(MediaViewerPageData.Loading::class.java)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test dataFlow empty`() = runTest {
|
||||
val galleryDataSource = FakeMediaGalleryDataSource()
|
||||
val sut = createMediaViewerDataSource(
|
||||
galleryDataSource = galleryDataSource,
|
||||
)
|
||||
sut.dataFlow().test {
|
||||
galleryDataSource.emitGroupedMediaItems(
|
||||
AsyncData.Success(
|
||||
aGroupedMediaItems(
|
||||
imageAndVideoItems = listOf(),
|
||||
fileItems = listOf(),
|
||||
)
|
||||
)
|
||||
)
|
||||
val result = awaitItem()
|
||||
assertThat(result).hasSize(1)
|
||||
assertThat(result.first()).isEqualTo(MediaViewerPageData.Loading(Timeline.PaginationDirection.BACKWARDS))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test dataFlow loading items`() = runTest {
|
||||
val galleryDataSource = FakeMediaGalleryDataSource()
|
||||
val sut = createMediaViewerDataSource(
|
||||
galleryDataSource = galleryDataSource,
|
||||
)
|
||||
sut.dataFlow().test {
|
||||
galleryDataSource.emitGroupedMediaItems(
|
||||
AsyncData.Success(
|
||||
aGroupedMediaItems(
|
||||
imageAndVideoItems = listOf(
|
||||
aMediaItemLoadingIndicator(
|
||||
direction = Timeline.PaginationDirection.BACKWARDS,
|
||||
),
|
||||
aMediaItemLoadingIndicator(
|
||||
direction = Timeline.PaginationDirection.FORWARDS,
|
||||
),
|
||||
),
|
||||
fileItems = listOf(),
|
||||
)
|
||||
)
|
||||
)
|
||||
val result = awaitItem()
|
||||
assertThat(result).containsExactly(
|
||||
MediaViewerPageData.Loading(Timeline.PaginationDirection.BACKWARDS),
|
||||
MediaViewerPageData.Loading(Timeline.PaginationDirection.FORWARDS),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test dataFlow with data galleryMode image`() = runTest {
|
||||
val galleryDataSource = FakeMediaGalleryDataSource()
|
||||
val sut = createMediaViewerDataSource(
|
||||
galleryMode = MediaGalleryMode.Images,
|
||||
galleryDataSource = galleryDataSource,
|
||||
)
|
||||
sut.dataFlow().test {
|
||||
galleryDataSource.emitGroupedMediaItems(
|
||||
AsyncData.Success(
|
||||
aGroupedMediaItems(
|
||||
imageAndVideoItems = listOf(aMediaItemImage(eventId = AN_EVENT_ID)),
|
||||
fileItems = listOf(aMediaItemFile(eventId = AN_EVENT_ID_2)),
|
||||
)
|
||||
)
|
||||
)
|
||||
val result = awaitItem()
|
||||
assertThat(result).hasSize(1)
|
||||
assertThat((result.first() as MediaViewerPageData.MediaViewerData).eventId).isEqualTo(AN_EVENT_ID)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test dataFlow with data galleryMode files`() = runTest {
|
||||
val galleryDataSource = FakeMediaGalleryDataSource()
|
||||
val sut = createMediaViewerDataSource(
|
||||
galleryMode = MediaGalleryMode.Files,
|
||||
galleryDataSource = galleryDataSource,
|
||||
)
|
||||
sut.dataFlow().test {
|
||||
galleryDataSource.emitGroupedMediaItems(
|
||||
AsyncData.Success(
|
||||
aGroupedMediaItems(
|
||||
imageAndVideoItems = listOf(aMediaItemImage(eventId = AN_EVENT_ID)),
|
||||
fileItems = listOf(aMediaItemFile(eventId = AN_EVENT_ID_2)),
|
||||
)
|
||||
)
|
||||
)
|
||||
val result = awaitItem()
|
||||
assertThat(result).hasSize(1)
|
||||
assertThat((result.first() as MediaViewerPageData.MediaViewerData).eventId).isEqualTo(AN_EVENT_ID_2)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test dataFlow - date separator are filtered out`() = runTest {
|
||||
val galleryDataSource = FakeMediaGalleryDataSource()
|
||||
val sut = createMediaViewerDataSource(
|
||||
galleryDataSource = galleryDataSource,
|
||||
)
|
||||
sut.dataFlow().test {
|
||||
galleryDataSource.emitGroupedMediaItems(
|
||||
AsyncData.Success(
|
||||
aGroupedMediaItems(
|
||||
imageAndVideoItems = listOf(aMediaItemDateSeparator(), aMediaItemImage(), aMediaItemDateSeparator()),
|
||||
fileItems = emptyList(),
|
||||
)
|
||||
)
|
||||
)
|
||||
val result = awaitItem()
|
||||
assertThat(result).hasSize(1)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `loadMore invokes the gallery data source loadMore`() = runTest {
|
||||
val loadMoreLambda = lambdaRecorder<Timeline.PaginationDirection, Unit> { }
|
||||
val galleryDataSource = FakeMediaGalleryDataSource(
|
||||
loadMoreLambda = loadMoreLambda
|
||||
)
|
||||
val sut = createMediaViewerDataSource(
|
||||
galleryDataSource = galleryDataSource,
|
||||
)
|
||||
sut.loadMore(Timeline.PaginationDirection.BACKWARDS)
|
||||
loadMoreLambda.assertions().isCalledOnce().with(value(Timeline.PaginationDirection.BACKWARDS))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test dataFlow with data galleryMode image and load media`() = runTest {
|
||||
val galleryDataSource = FakeMediaGalleryDataSource()
|
||||
val sut = createMediaViewerDataSource(
|
||||
galleryDataSource = galleryDataSource,
|
||||
)
|
||||
sut.dataFlow().test {
|
||||
galleryDataSource.emitGroupedMediaItems(
|
||||
AsyncData.Success(
|
||||
aGroupedMediaItems(
|
||||
imageAndVideoItems = listOf(aMediaItemImage(eventId = AN_EVENT_ID)),
|
||||
)
|
||||
)
|
||||
)
|
||||
val result = awaitItem()
|
||||
val mediaViewerData = result.first() as MediaViewerPageData.MediaViewerData
|
||||
assertThat(mediaViewerData.downloadedMedia.value).isEqualTo(AsyncData.Uninitialized)
|
||||
sut.loadMedia(mediaViewerData)
|
||||
assertThat(mediaViewerData.downloadedMedia.value.isSuccess()).isTrue()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test dataFlow with data galleryMode image and load media with failure then success`() = runTest {
|
||||
val galleryDataSource = FakeMediaGalleryDataSource()
|
||||
val mediaLoader = FakeMatrixMediaLoader()
|
||||
val sut = createMediaViewerDataSource(
|
||||
galleryDataSource = galleryDataSource,
|
||||
mediaLoader = mediaLoader,
|
||||
)
|
||||
sut.dataFlow().test {
|
||||
galleryDataSource.emitGroupedMediaItems(
|
||||
AsyncData.Success(
|
||||
aGroupedMediaItems(
|
||||
imageAndVideoItems = listOf(aMediaItemImage(eventId = AN_EVENT_ID)),
|
||||
)
|
||||
)
|
||||
)
|
||||
val result = awaitItem()
|
||||
val mediaViewerData = result.first() as MediaViewerPageData.MediaViewerData
|
||||
assertThat(mediaViewerData.downloadedMedia.value).isEqualTo(AsyncData.Uninitialized)
|
||||
mediaLoader.shouldFail = true
|
||||
sut.loadMedia(mediaViewerData)
|
||||
assertThat(mediaViewerData.downloadedMedia.value.isFailure()).isTrue()
|
||||
// clear the error
|
||||
sut.clearLoadingError(mediaViewerData)
|
||||
assertThat(mediaViewerData.downloadedMedia.value).isEqualTo(AsyncData.Uninitialized)
|
||||
// load again with success
|
||||
mediaLoader.shouldFail = false
|
||||
sut.loadMedia(mediaViewerData)
|
||||
assertThat(mediaViewerData.downloadedMedia.value.isSuccess()).isTrue()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun clearLoadingError() {
|
||||
}
|
||||
|
||||
private fun TestScope.createMediaViewerDataSource(
|
||||
galleryMode: MediaGalleryMode = MediaGalleryMode.Images,
|
||||
galleryDataSource: MediaGalleryDataSource = FakeMediaGalleryDataSource(),
|
||||
mediaLoader: MatrixMediaLoader = FakeMatrixMediaLoader(),
|
||||
localMediaFactory: LocalMediaFactory = FakeLocalMediaFactory(mockMediaUrl),
|
||||
) = MediaViewerDataSource(
|
||||
galleryMode = galleryMode,
|
||||
dispatcher = testCoroutineDispatchers().computation,
|
||||
galleryDataSource = galleryDataSource,
|
||||
mediaLoader = mediaLoader,
|
||||
localMediaFactory = localMediaFactory,
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user