Add test on DefaultEntryPoints

This commit is contained in:
Benoit Marty 2025-09-12 21:32:24 +02:00
parent a575019760
commit a1aeb24f23
93 changed files with 2426 additions and 418 deletions

View file

@ -14,7 +14,7 @@ import io.element.android.libraries.matrix.api.core.EventId
import io.element.android.libraries.matrix.api.room.JoinedRoom
import io.element.android.libraries.mediaviewer.impl.model.MediaItem
interface FocusedTimelineMediaGalleryDataSourceFactory {
fun interface FocusedTimelineMediaGalleryDataSourceFactory {
fun createFor(
eventId: EventId,
mediaItem: MediaItem.Event,

View file

@ -58,7 +58,7 @@ class MediaViewerPresenter(
private val localMediaActions: LocalMediaActions,
) : Presenter<MediaViewerState> {
@AssistedFactory
interface Factory {
fun interface Factory {
fun create(
inputs: MediaViewerEntryPoint.Params,
navigator: MediaViewerNavigator,

View file

@ -0,0 +1,47 @@
/*
* 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
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.bumble.appyx.core.modality.BuildContext
import com.bumble.appyx.core.node.Node
import com.google.common.truth.Truth.assertThat
import io.element.android.libraries.matrix.api.core.EventId
import io.element.android.libraries.mediaviewer.api.MediaGalleryEntryPoint
import io.element.android.libraries.mediaviewer.api.MediaViewerEntryPoint
import io.element.android.libraries.mediaviewer.impl.gallery.root.MediaGalleryRootNode
import io.element.android.tests.testutils.lambda.lambdaError
import io.element.android.tests.testutils.node.TestParentNode
import org.junit.Test
import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class DefaultMediaGalleryEntryPointTest {
@Test
fun `test node builder`() {
val entryPoint = DefaultMediaGalleryEntryPoint()
val parentNode = TestParentNode.create { buildContext, plugins ->
MediaGalleryRootNode(
buildContext = buildContext,
plugins = plugins,
mediaViewerEntryPoint = object : MediaViewerEntryPoint {
override fun nodeBuilder(parentNode: Node, buildContext: BuildContext) = lambdaError()
}
)
}
val callback = object : MediaGalleryEntryPoint.Callback {
override fun onBackClick() = lambdaError()
override fun onViewInTimeline(eventId: EventId) = lambdaError()
}
val result = entryPoint.nodeBuilder(parentNode, BuildContext.root(null))
.callback(callback)
.build()
assertThat(result).isInstanceOf(MediaGalleryRootNode::class.java)
assertThat(result.plugins).contains(callback)
}
}

View file

@ -0,0 +1,145 @@
/*
* 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
import android.net.Uri
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.bumble.appyx.core.modality.BuildContext
import com.google.common.truth.Truth.assertThat
import io.element.android.libraries.core.mimetype.MimeTypes
import io.element.android.libraries.matrix.api.core.EventId
import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.api.media.MediaSource
import io.element.android.libraries.matrix.test.media.FakeMatrixMediaLoader
import io.element.android.libraries.mediaplayer.test.FakeAudioFocus
import io.element.android.libraries.mediaviewer.api.MediaInfo
import io.element.android.libraries.mediaviewer.api.MediaViewerEntryPoint
import io.element.android.libraries.mediaviewer.impl.datasource.createTimelineMediaGalleryDataSource
import io.element.android.libraries.mediaviewer.impl.viewer.MediaViewerNode
import io.element.android.libraries.mediaviewer.impl.viewer.PagerKeysHandler
import io.element.android.libraries.mediaviewer.impl.viewer.createMediaViewerEntryPointParams
import io.element.android.libraries.mediaviewer.impl.viewer.createMediaViewerPresenter
import io.element.android.libraries.mediaviewer.test.FakeLocalMediaFactory
import io.element.android.services.toolbox.test.systemclock.FakeSystemClock
import io.element.android.tests.testutils.lambda.lambdaError
import io.element.android.tests.testutils.node.TestParentNode
import io.element.android.tests.testutils.testCoroutineDispatchers
import io.mockk.mockk
import kotlinx.coroutines.test.runTest
import org.junit.Test
import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class DefaultMediaViewerEntryPointTest {
@Test
fun `test node builder`() = runTest {
val entryPoint = DefaultMediaViewerEntryPoint()
val mockMediaUri: Uri = mockk("localMediaUri")
val localMediaFactory = FakeLocalMediaFactory(mockMediaUri)
val parentNode = TestParentNode.create { buildContext, plugins ->
MediaViewerNode(
buildContext = buildContext,
plugins = plugins,
presenterFactory = { _, _, _ ->
createMediaViewerPresenter(
localMediaFactory = localMediaFactory,
)
},
timelineMediaGalleryDataSource = createTimelineMediaGalleryDataSource(),
focusedTimelineMediaGalleryDataSourceFactory = { _, _, _ ->
lambdaError()
},
mediaLoader = FakeMatrixMediaLoader(),
localMediaFactory = FakeLocalMediaFactory(mockMediaUri),
coroutineDispatchers = testCoroutineDispatchers(),
systemClock = FakeSystemClock(),
pagerKeysHandler = PagerKeysHandler(),
textFileViewer = { _, _ -> lambdaError() },
audioFocus = FakeAudioFocus(),
)
}
val callback = object : MediaViewerEntryPoint.Callback {
override fun onDone() = lambdaError()
override fun onViewInTimeline(eventId: EventId) = lambdaError()
}
val params = createMediaViewerEntryPointParams()
val result = entryPoint.nodeBuilder(parentNode, BuildContext.root(null))
.params(params)
.callback(callback)
.build()
assertThat(result).isInstanceOf(MediaViewerNode::class.java)
assertThat(result.plugins).contains(params)
assertThat(result.plugins).contains(callback)
}
@Test
fun `test node builder avatar`() = runTest {
val entryPoint = DefaultMediaViewerEntryPoint()
val mockMediaUri: Uri = mockk("localMediaUri")
val localMediaFactory = FakeLocalMediaFactory(mockMediaUri)
val parentNode = TestParentNode.create { buildContext, plugins ->
MediaViewerNode(
buildContext = buildContext,
plugins = plugins,
presenterFactory = { _, _, _ ->
createMediaViewerPresenter(
localMediaFactory = localMediaFactory,
)
},
timelineMediaGalleryDataSource = createTimelineMediaGalleryDataSource(),
focusedTimelineMediaGalleryDataSourceFactory = { _, _, _ ->
lambdaError()
},
mediaLoader = FakeMatrixMediaLoader(),
localMediaFactory = FakeLocalMediaFactory(mockMediaUri),
coroutineDispatchers = testCoroutineDispatchers(),
systemClock = FakeSystemClock(),
pagerKeysHandler = PagerKeysHandler(),
textFileViewer = { _, _ -> lambdaError() },
audioFocus = FakeAudioFocus(),
)
}
val callback = object : MediaViewerEntryPoint.Callback {
override fun onDone() = lambdaError()
override fun onViewInTimeline(eventId: EventId) = lambdaError()
}
val result = entryPoint.nodeBuilder(parentNode, BuildContext.root(null))
.avatar(
filename = "fn",
avatarUrl = "avatarUrl",
)
.callback(callback)
.build()
assertThat(result).isInstanceOf(MediaViewerNode::class.java)
assertThat(result.plugins).contains(
MediaViewerEntryPoint.Params(
mode = MediaViewerEntryPoint.MediaViewerMode.SingleMedia,
eventId = null,
mediaInfo = MediaInfo(
filename = "fn",
fileSize = null,
caption = null,
mimeType = MimeTypes.Images,
formattedFileSize = "",
fileExtension = "",
senderId = UserId("@dummy:server.org"),
senderName = null,
senderAvatar = null,
dateSent = null,
dateSentFull = null,
waveform = null,
duration = null,
),
mediaSource = MediaSource(url = "avatarUrl"),
thumbnailSource = null,
canShowInfo = false,
)
)
assertThat(result.plugins).contains(callback)
}
}

View file

@ -255,19 +255,19 @@ class TimelineMediaGalleryDataSourceTest {
)
}
}
}
private fun TestScope.createTimelineMediaGalleryDataSource(
room: JoinedRoom = FakeJoinedRoom(
liveTimeline = FakeTimeline(),
),
): TimelineMediaGalleryDataSource {
return TimelineMediaGalleryDataSource(
room = room,
mediaTimeline = LiveMediaTimeline(room),
timelineMediaItemsFactory = createTimelineMediaItemsFactory(),
mediaItemsPostProcessor = MediaItemsPostProcessor(),
)
}
internal fun TestScope.createTimelineMediaGalleryDataSource(
room: JoinedRoom = FakeJoinedRoom(
liveTimeline = FakeTimeline(),
),
): TimelineMediaGalleryDataSource {
return TimelineMediaGalleryDataSource(
room = room,
mediaTimeline = LiveMediaTimeline(room),
timelineMediaItemsFactory = createTimelineMediaItemsFactory(),
mediaItemsPostProcessor = MediaItemsPostProcessor(),
)
}
fun TestScope.createTimelineMediaItemsFactory() = TimelineMediaItemsFactory(

View file

@ -29,6 +29,7 @@ import io.element.android.libraries.matrix.test.room.FakeJoinedRoom
import io.element.android.libraries.matrix.test.timeline.FakeTimeline
import io.element.android.libraries.mediaviewer.api.MediaViewerEntryPoint
import io.element.android.libraries.mediaviewer.api.anApkMediaInfo
import io.element.android.libraries.mediaviewer.api.local.LocalMediaFactory
import io.element.android.libraries.mediaviewer.impl.R
import io.element.android.libraries.mediaviewer.impl.datasource.FakeMediaGalleryDataSource
import io.element.android.libraries.mediaviewer.impl.datasource.MediaGalleryDataSource
@ -78,12 +79,13 @@ class MediaViewerPresenterTest {
@Test
fun `present - initial state null Event`() = runTest {
val presenter = createMediaViewerPresenter(
localMediaFactory = localMediaFactory,
room = FakeJoinedRoom(
baseRoom = FakeBaseRoom(
canRedactOwnResult = { Result.success(true) },
canRedactOwnResult = { Result.success(true) },
)
)
)
)
presenter.test {
val initialState = awaitFirstItem()
assertThat(initialState.listData).isEmpty()
@ -97,13 +99,14 @@ class MediaViewerPresenterTest {
@Test
fun `present - initial state cannot show info`() = runTest {
val presenter = createMediaViewerPresenter(
localMediaFactory = localMediaFactory,
canShowInfo = false,
room = FakeJoinedRoom(
baseRoom = FakeBaseRoom(
canRedactOwnResult = { Result.success(true) },
canRedactOwnResult = { Result.success(true) },
)
)
)
)
presenter.test {
val initialState = awaitFirstItem()
assertThat(initialState.listData).isEmpty()
@ -117,13 +120,14 @@ class MediaViewerPresenterTest {
@Test
fun `present - initial state Event`() = runTest {
val presenter = createMediaViewerPresenter(
localMediaFactory = localMediaFactory,
eventId = AN_EVENT_ID,
room = FakeJoinedRoom(
baseRoom = FakeBaseRoom(
canRedactOwnResult = { Result.success(true) },
canRedactOwnResult = { Result.success(true) },
)
)
)
)
presenter.test {
val initialState = awaitFirstItem()
assertThat(initialState.listData).isEmpty()
@ -137,14 +141,15 @@ class MediaViewerPresenterTest {
@Test
fun `present - initial state Event from other`() = runTest {
val presenter = createMediaViewerPresenter(
localMediaFactory = localMediaFactory,
eventId = AN_EVENT_ID,
room = FakeJoinedRoom(
baseRoom = FakeBaseRoom(
sessionId = A_SESSION_ID_2,
canRedactOtherResult = { Result.success(false) },
sessionId = A_SESSION_ID_2,
canRedactOtherResult = { Result.success(false) },
)
)
)
)
presenter.test {
val initialState = awaitFirstItem()
assertThat(initialState.listData).isEmpty()
@ -161,6 +166,7 @@ class MediaViewerPresenterTest {
startLambda = { },
)
val presenter = createMediaViewerPresenter(
localMediaFactory = localMediaFactory,
mediaGalleryDataSource = mediaGalleryDataSource,
)
val anImage = aMediaItemImage()
@ -192,6 +198,7 @@ class MediaViewerPresenterTest {
startLambda = { },
)
val presenter = createMediaViewerPresenter(
localMediaFactory = localMediaFactory,
mediaGalleryDataSource = mediaGalleryDataSource,
)
val anImage = aMediaItemImage(
@ -224,10 +231,13 @@ class MediaViewerPresenterTest {
startLambda = { },
)
val presenter = createMediaViewerPresenter(
localMediaFactory = localMediaFactory,
mediaGalleryDataSource = mediaGalleryDataSource,
room = FakeJoinedRoom(baseRoom = FakeBaseRoom(
canRedactOwnResult = { Result.success(true) },
))
room = FakeJoinedRoom(
baseRoom = FakeBaseRoom(
canRedactOwnResult = { Result.success(true) },
)
)
)
val anImage = aMediaItemImage(
mediaSourceUrl = aUrl,
@ -266,6 +276,7 @@ class MediaViewerPresenterTest {
startLambda = { },
)
val presenter = createMediaViewerPresenter(
localMediaFactory = localMediaFactory,
mediaGalleryDataSource = mediaGalleryDataSource,
)
val anImage = aMediaItemImage(
@ -298,6 +309,7 @@ class MediaViewerPresenterTest {
startLambda = { },
)
val presenter = createMediaViewerPresenter(
localMediaFactory = localMediaFactory,
mediaGalleryDataSource = mediaGalleryDataSource,
)
val anImage = aMediaItemImage(
@ -330,6 +342,7 @@ class MediaViewerPresenterTest {
startLambda = { },
)
val presenter = createMediaViewerPresenter(
localMediaFactory = localMediaFactory,
mediaGalleryDataSource = mediaGalleryDataSource,
)
val anImage = aMediaItemImage(
@ -362,6 +375,7 @@ class MediaViewerPresenterTest {
startLambda = { },
)
val presenter = createMediaViewerPresenter(
localMediaFactory = localMediaFactory,
mediaGalleryDataSource = mediaGalleryDataSource,
)
val anImage = aMediaItemImage(
@ -394,6 +408,7 @@ class MediaViewerPresenterTest {
startLambda = { },
)
val presenter = createMediaViewerPresenter(
localMediaFactory = localMediaFactory,
mediaGalleryDataSource = mediaGalleryDataSource,
)
val anImage = aMediaItemImage(
@ -441,6 +456,7 @@ class MediaViewerPresenterTest {
startLambda = { },
)
val presenter = createMediaViewerPresenter(
localMediaFactory = localMediaFactory,
room = FakeJoinedRoom(
liveTimeline = timeline,
baseRoom = FakeBaseRoom(canRedactOwnResult = { Result.success(true) }),
@ -498,6 +514,7 @@ class MediaViewerPresenterTest {
startLambda = { },
)
val presenter = createMediaViewerPresenter(
localMediaFactory = localMediaFactory,
mediaGalleryDataSource = mediaGalleryDataSource,
)
val anImage = aMediaItemImage(
@ -549,6 +566,7 @@ class MediaViewerPresenterTest {
startLambda = { },
)
val presenter = createMediaViewerPresenter(
localMediaFactory = localMediaFactory,
mode = mode,
mediaGalleryDataSource = mediaGalleryDataSource,
)
@ -620,6 +638,7 @@ class MediaViewerPresenterTest {
startLambda = { },
)
val presenter = createMediaViewerPresenter(
localMediaFactory = localMediaFactory,
mode = mode,
mediaGalleryDataSource = mediaGalleryDataSource,
)
@ -674,6 +693,7 @@ class MediaViewerPresenterTest {
startLambda = { },
)
val presenter = createMediaViewerPresenter(
localMediaFactory = localMediaFactory,
mediaGalleryDataSource = mediaGalleryDataSource,
)
presenter.test {
@ -714,6 +734,7 @@ class MediaViewerPresenterTest {
loadMoreLambda = loadMoreLambda,
)
val presenter = createMediaViewerPresenter(
localMediaFactory = localMediaFactory,
mediaGalleryDataSource = mediaGalleryDataSource,
)
val anImage = aMediaItemImage(
@ -744,6 +765,7 @@ class MediaViewerPresenterTest {
onViewInTimelineClickLambda = onViewInTimelineClickLambda,
)
val presenter = createMediaViewerPresenter(
localMediaFactory = localMediaFactory,
mediaViewerNavigator = navigator,
room = FakeJoinedRoom(
baseRoom = FakeBaseRoom(canRedactOwnResult = { Result.success(true) }),
@ -764,42 +786,53 @@ class MediaViewerPresenterTest {
private suspend fun <T> ReceiveTurbine<T>.awaitFirstItem(): T {
return awaitItem()
}
private fun TestScope.createMediaViewerPresenter(
eventId: EventId? = null,
mode: MediaViewerEntryPoint.MediaViewerMode = MediaViewerEntryPoint.MediaViewerMode.SingleMedia,
matrixMediaLoader: FakeMatrixMediaLoader = FakeMatrixMediaLoader(),
localMediaActions: FakeLocalMediaActions = FakeLocalMediaActions(),
mediaGalleryDataSource: MediaGalleryDataSource = FakeMediaGalleryDataSource(
startLambda = { },
),
canShowInfo: Boolean = true,
mediaViewerNavigator: MediaViewerNavigator = FakeMediaViewerNavigator(),
room: JoinedRoom = FakeJoinedRoom(
liveTimeline = FakeTimeline(),
),
): MediaViewerPresenter {
return MediaViewerPresenter(
inputs = MediaViewerEntryPoint.Params(
mode = mode,
eventId = eventId,
mediaInfo = TESTED_MEDIA_INFO,
mediaSource = aMediaSource(),
thumbnailSource = null,
canShowInfo = canShowInfo,
),
navigator = mediaViewerNavigator,
dataSource = MediaViewerDataSource(
mode = mode,
dispatcher = testCoroutineDispatchers().computation,
galleryDataSource = mediaGalleryDataSource,
mediaLoader = matrixMediaLoader,
localMediaFactory = localMediaFactory,
systemClock = FakeSystemClock(),
pagerKeysHandler = PagerKeysHandler(),
),
room = room,
localMediaActions = localMediaActions,
)
}
}
internal fun TestScope.createMediaViewerPresenter(
localMediaFactory: LocalMediaFactory,
eventId: EventId? = null,
mode: MediaViewerEntryPoint.MediaViewerMode = MediaViewerEntryPoint.MediaViewerMode.SingleMedia,
matrixMediaLoader: FakeMatrixMediaLoader = FakeMatrixMediaLoader(),
localMediaActions: FakeLocalMediaActions = FakeLocalMediaActions(),
mediaGalleryDataSource: MediaGalleryDataSource = FakeMediaGalleryDataSource(
startLambda = { },
),
canShowInfo: Boolean = true,
mediaViewerNavigator: MediaViewerNavigator = FakeMediaViewerNavigator(),
room: JoinedRoom = FakeJoinedRoom(
liveTimeline = FakeTimeline(),
),
): MediaViewerPresenter {
return MediaViewerPresenter(
inputs = createMediaViewerEntryPointParams(
eventId = eventId,
mode = mode,
canShowInfo = canShowInfo,
),
navigator = mediaViewerNavigator,
dataSource = MediaViewerDataSource(
mode = mode,
dispatcher = testCoroutineDispatchers().computation,
galleryDataSource = mediaGalleryDataSource,
mediaLoader = matrixMediaLoader,
localMediaFactory = localMediaFactory,
systemClock = FakeSystemClock(),
pagerKeysHandler = PagerKeysHandler(),
),
room = room,
localMediaActions = localMediaActions,
)
}
internal fun createMediaViewerEntryPointParams(
eventId: EventId? = null,
mode: MediaViewerEntryPoint.MediaViewerMode = MediaViewerEntryPoint.MediaViewerMode.SingleMedia,
canShowInfo: Boolean = true,
) = MediaViewerEntryPoint.Params(
mode = mode,
eventId = eventId,
mediaInfo = TESTED_MEDIA_INFO,
mediaSource = aMediaSource(),
thumbnailSource = null,
canShowInfo = canShowInfo,
)

View file

@ -168,7 +168,7 @@ class SingleMediaGalleryDataSourceTest {
assertThat(resultData.fileItems).isEmpty()
}
private fun aMediaViewerEntryPointParams(
internal fun aMediaViewerEntryPointParams(
mediaInfo: MediaInfo,
) = MediaViewerEntryPoint.Params(
mode = MediaViewerEntryPoint.MediaViewerMode.SingleMedia,