Browse Source

Merge pull request #591 from vector-im/feature/bma/noDelayInTests

No delay in tests
other/julioromano/inlineasync2
Benoit Marty 1 year ago committed by GitHub
parent
commit
97923af7d8
  1. 4
      features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenterTests.kt
  2. 7
      features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootPresenterTests.kt
  3. 21
      features/invitelist/impl/src/test/kotlin/io/element/android/features/invitelist/impl/InviteListPresenterTests.kt
  4. 7
      features/logout/impl/src/test/kotlin/io/element/android/features/logout/impl/LogoutPreferencePresenterTest.kt
  5. 11
      features/messages/impl/src/test/kotlin/io/element/android/features/messages/MessagesPresenterTest.kt
  6. 4
      features/messages/impl/src/test/kotlin/io/element/android/features/messages/attachments/AttachmentsPreviewPresenterTest.kt
  7. 11
      features/messages/impl/src/test/kotlin/io/element/android/features/messages/media/FakeLocalMediaActions.kt
  8. 10
      features/messages/impl/src/test/kotlin/io/element/android/features/messages/media/viewer/MediaViewerPresenterTest.kt
  9. 7
      features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/RoomDetailsPresenterTests.kt
  10. 25
      features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/edit/RoomDetailsEditPresenterTest.kt
  11. 50
      features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersPresenterTest.kt
  12. 7
      features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/members/RoomMemberListPresenterTests.kt
  13. 18
      features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/members/details/RoomMemberDetailsPresenterTests.kt
  14. 4
      features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/DefaultInviteStateDataSourceTest.kt
  15. 20
      features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/RoomListPresenterTests.kt
  16. 1
      libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/FakeMatrixClient.kt
  17. 2
      libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/TestData.kt
  18. 22
      libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/auth/FakeAuthenticationService.kt
  19. 18
      libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/media/FakeMediaLoader.kt
  20. 49
      libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeMatrixRoom.kt
  21. 1
      libraries/mediaupload/test/build.gradle.kts
  22. 5
      libraries/mediaupload/test/src/main/kotlin/io/element/android/libraries/mediaupload/test/FakeMediaPreProcessor.kt
  23. 2
      samples/minimal/src/main/kotlin/io/element/android/samples/minimal/RoomListScreen.kt
  24. 28
      tests/testutils/src/main/kotlin/io/element/android/tests/testutils/LongTask.kt
  25. 15
      tests/testutils/src/main/kotlin/io/element/android/tests/testutils/TestCoroutineDispatchers.kt

4
features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenterTests.kt

@ -21,7 +21,6 @@ import app.cash.molecule.RecompositionClock
import app.cash.molecule.moleculeFlow import app.cash.molecule.moleculeFlow
import app.cash.turbine.test import app.cash.turbine.test
import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertThat
import io.element.android.libraries.matrix.ui.media.AvatarAction
import io.element.android.features.createroom.impl.CreateRoomConfig import io.element.android.features.createroom.impl.CreateRoomConfig
import io.element.android.features.createroom.impl.CreateRoomDataStore import io.element.android.features.createroom.impl.CreateRoomDataStore
import io.element.android.features.createroom.impl.userlist.UserListDataStore import io.element.android.features.createroom.impl.userlist.UserListDataStore
@ -33,6 +32,7 @@ import io.element.android.libraries.matrix.test.A_ROOM_NAME
import io.element.android.libraries.matrix.test.A_THROWABLE import io.element.android.libraries.matrix.test.A_THROWABLE
import io.element.android.libraries.matrix.test.FakeMatrixClient import io.element.android.libraries.matrix.test.FakeMatrixClient
import io.element.android.libraries.matrix.ui.components.aMatrixUser import io.element.android.libraries.matrix.ui.components.aMatrixUser
import io.element.android.libraries.matrix.ui.media.AvatarAction
import io.element.android.libraries.mediapickers.test.FakePickerProvider import io.element.android.libraries.mediapickers.test.FakePickerProvider
import io.element.android.libraries.mediaupload.api.MediaUploadInfo import io.element.android.libraries.mediaupload.api.MediaUploadInfo
import io.element.android.libraries.mediaupload.test.FakeMediaPreProcessor import io.element.android.libraries.mediaupload.test.FakeMediaPreProcessor
@ -226,6 +226,7 @@ class ConfigureRoomPresenterTests {
val initialState = awaitItem() val initialState = awaitItem()
initialState.eventSink(ConfigureRoomEvents.CreateRoom(initialState.config)) initialState.eventSink(ConfigureRoomEvents.CreateRoom(initialState.config))
assertThat(awaitItem().createRoomAction).isInstanceOf(Async.Loading::class.java)
val stateAfterCreateRoom = awaitItem() val stateAfterCreateRoom = awaitItem()
assertThat(stateAfterCreateRoom.createRoomAction).isInstanceOf(Async.Failure::class.java) assertThat(stateAfterCreateRoom.createRoomAction).isInstanceOf(Async.Failure::class.java)
@ -234,7 +235,6 @@ class ConfigureRoomPresenterTests {
assertThat(awaitItem().createRoomAction).isInstanceOf(Async.Uninitialized::class.java) assertThat(awaitItem().createRoomAction).isInstanceOf(Async.Uninitialized::class.java)
assertThat(awaitItem().createRoomAction).isInstanceOf(Async.Loading::class.java) assertThat(awaitItem().createRoomAction).isInstanceOf(Async.Loading::class.java)
assertThat(awaitItem().createRoomAction).isInstanceOf(Async.Success::class.java) assertThat(awaitItem().createRoomAction).isInstanceOf(Async.Success::class.java)
} }
} }

7
features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootPresenterTests.kt

@ -49,7 +49,12 @@ class CreateRoomRootPresenterTests {
fakeUserListPresenter = FakeUserListPresenter() fakeUserListPresenter = FakeUserListPresenter()
fakeMatrixClient = FakeMatrixClient() fakeMatrixClient = FakeMatrixClient()
userRepository = FakeUserRepository() userRepository = FakeUserRepository()
presenter = CreateRoomRootPresenter(FakeUserListPresenterFactory(fakeUserListPresenter), userRepository, UserListDataStore(), fakeMatrixClient) presenter = CreateRoomRootPresenter(
presenterFactory = FakeUserListPresenterFactory(fakeUserListPresenter),
userRepository = userRepository,
userListDataStore = UserListDataStore(),
matrixClient = fakeMatrixClient
)
} }
@Test @Test

21
features/invitelist/impl/src/test/kotlin/io/element/android/features/invitelist/impl/InviteListPresenterTests.kt

@ -32,12 +32,11 @@ import io.element.android.libraries.matrix.test.AN_AVATAR_URL
import io.element.android.libraries.matrix.test.A_ROOM_ID import io.element.android.libraries.matrix.test.A_ROOM_ID
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.libraries.matrix.test.A_ROOM_NAME import io.element.android.libraries.matrix.test.A_ROOM_NAME
import io.element.android.libraries.matrix.test.A_SESSION_ID
import io.element.android.libraries.matrix.test.A_USER_ID import io.element.android.libraries.matrix.test.A_USER_ID
import io.element.android.libraries.matrix.test.A_USER_NAME import io.element.android.libraries.matrix.test.A_USER_NAME
import io.element.android.libraries.matrix.test.FakeMatrixClient import io.element.android.libraries.matrix.test.FakeMatrixClient
import io.element.android.libraries.matrix.test.room.FakeMatrixRoom
import io.element.android.libraries.matrix.test.room.FakeRoomSummaryDataSource import io.element.android.libraries.matrix.test.room.FakeRoomSummaryDataSource
import io.element.android.libraries.matrix.test.room.FakeMatrixRoom
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import org.junit.Test import org.junit.Test
@ -48,7 +47,6 @@ class InviteListPresenterTests {
val invitesDataSource = FakeRoomSummaryDataSource() val invitesDataSource = FakeRoomSummaryDataSource()
val presenter = InviteListPresenter( val presenter = InviteListPresenter(
FakeMatrixClient( FakeMatrixClient(
sessionId = A_SESSION_ID,
invitesDataSource = invitesDataSource, invitesDataSource = invitesDataSource,
), ),
FakeSeenInvitesStore(), FakeSeenInvitesStore(),
@ -73,7 +71,6 @@ class InviteListPresenterTests {
val invitesDataSource = FakeRoomSummaryDataSource().withDirectChatInvitation() val invitesDataSource = FakeRoomSummaryDataSource().withDirectChatInvitation()
val presenter = InviteListPresenter( val presenter = InviteListPresenter(
FakeMatrixClient( FakeMatrixClient(
sessionId = A_SESSION_ID,
invitesDataSource = invitesDataSource, invitesDataSource = invitesDataSource,
), ),
FakeSeenInvitesStore(), FakeSeenInvitesStore(),
@ -100,10 +97,8 @@ class InviteListPresenterTests {
@Test @Test
fun `present - includes sender details for room invites`() = runTest { fun `present - includes sender details for room invites`() = runTest {
val invitesDataSource = FakeRoomSummaryDataSource().withRoomInvitation() val invitesDataSource = FakeRoomSummaryDataSource().withRoomInvitation()
val presenter = InviteListPresenter( val presenter = InviteListPresenter(
FakeMatrixClient( FakeMatrixClient(
sessionId = A_SESSION_ID,
invitesDataSource = invitesDataSource, invitesDataSource = invitesDataSource,
), ),
FakeSeenInvitesStore(), FakeSeenInvitesStore(),
@ -128,10 +123,8 @@ class InviteListPresenterTests {
@Test @Test
fun `present - shows confirm dialog for declining direct chat invites`() = runTest { fun `present - shows confirm dialog for declining direct chat invites`() = runTest {
val invitesDataSource = FakeRoomSummaryDataSource().withDirectChatInvitation() val invitesDataSource = FakeRoomSummaryDataSource().withDirectChatInvitation()
val presenter = InviteListPresenter( val presenter = InviteListPresenter(
FakeMatrixClient( FakeMatrixClient(
sessionId = A_SESSION_ID,
invitesDataSource = invitesDataSource, invitesDataSource = invitesDataSource,
), ),
FakeSeenInvitesStore(), FakeSeenInvitesStore(),
@ -154,10 +147,8 @@ class InviteListPresenterTests {
@Test @Test
fun `present - shows confirm dialog for declining room invites`() = runTest { fun `present - shows confirm dialog for declining room invites`() = runTest {
val invitesDataSource = FakeRoomSummaryDataSource().withRoomInvitation() val invitesDataSource = FakeRoomSummaryDataSource().withRoomInvitation()
val presenter = InviteListPresenter( val presenter = InviteListPresenter(
FakeMatrixClient( FakeMatrixClient(
sessionId = A_SESSION_ID,
invitesDataSource = invitesDataSource, invitesDataSource = invitesDataSource,
), ),
FakeSeenInvitesStore(), FakeSeenInvitesStore(),
@ -180,10 +171,8 @@ class InviteListPresenterTests {
@Test @Test
fun `present - hides confirm dialog when cancelling`() = runTest { fun `present - hides confirm dialog when cancelling`() = runTest {
val invitesDataSource = FakeRoomSummaryDataSource().withRoomInvitation() val invitesDataSource = FakeRoomSummaryDataSource().withRoomInvitation()
val presenter = InviteListPresenter( val presenter = InviteListPresenter(
FakeMatrixClient( FakeMatrixClient(
sessionId = A_SESSION_ID,
invitesDataSource = invitesDataSource, invitesDataSource = invitesDataSource,
), ),
FakeSeenInvitesStore(), FakeSeenInvitesStore(),
@ -207,7 +196,6 @@ class InviteListPresenterTests {
fun `present - declines invite after confirming`() = runTest { fun `present - declines invite after confirming`() = runTest {
val invitesDataSource = FakeRoomSummaryDataSource().withRoomInvitation() val invitesDataSource = FakeRoomSummaryDataSource().withRoomInvitation()
val client = FakeMatrixClient( val client = FakeMatrixClient(
sessionId = A_SESSION_ID,
invitesDataSource = invitesDataSource, invitesDataSource = invitesDataSource,
) )
val room = FakeMatrixRoom() val room = FakeMatrixRoom()
@ -234,7 +222,6 @@ class InviteListPresenterTests {
fun `present - declines invite after confirming and sets state on error`() = runTest { fun `present - declines invite after confirming and sets state on error`() = runTest {
val invitesDataSource = FakeRoomSummaryDataSource().withRoomInvitation() val invitesDataSource = FakeRoomSummaryDataSource().withRoomInvitation()
val client = FakeMatrixClient( val client = FakeMatrixClient(
sessionId = A_SESSION_ID,
invitesDataSource = invitesDataSource, invitesDataSource = invitesDataSource,
) )
val room = FakeMatrixRoom() val room = FakeMatrixRoom()
@ -266,7 +253,6 @@ class InviteListPresenterTests {
fun `present - dismisses declining error state`() = runTest { fun `present - dismisses declining error state`() = runTest {
val invitesDataSource = FakeRoomSummaryDataSource().withRoomInvitation() val invitesDataSource = FakeRoomSummaryDataSource().withRoomInvitation()
val client = FakeMatrixClient( val client = FakeMatrixClient(
sessionId = A_SESSION_ID,
invitesDataSource = invitesDataSource, invitesDataSource = invitesDataSource,
) )
val room = FakeMatrixRoom() val room = FakeMatrixRoom()
@ -299,7 +285,6 @@ class InviteListPresenterTests {
fun `present - accepts invites and sets state on success`() = runTest { fun `present - accepts invites and sets state on success`() = runTest {
val invitesDataSource = FakeRoomSummaryDataSource().withRoomInvitation() val invitesDataSource = FakeRoomSummaryDataSource().withRoomInvitation()
val client = FakeMatrixClient( val client = FakeMatrixClient(
sessionId = A_SESSION_ID,
invitesDataSource = invitesDataSource, invitesDataSource = invitesDataSource,
) )
val room = FakeMatrixRoom() val room = FakeMatrixRoom()
@ -323,7 +308,6 @@ class InviteListPresenterTests {
fun `present - accepts invites and sets state on error`() = runTest { fun `present - accepts invites and sets state on error`() = runTest {
val invitesDataSource = FakeRoomSummaryDataSource().withRoomInvitation() val invitesDataSource = FakeRoomSummaryDataSource().withRoomInvitation()
val client = FakeMatrixClient( val client = FakeMatrixClient(
sessionId = A_SESSION_ID,
invitesDataSource = invitesDataSource, invitesDataSource = invitesDataSource,
) )
val room = FakeMatrixRoom() val room = FakeMatrixRoom()
@ -349,7 +333,6 @@ class InviteListPresenterTests {
fun `present - dismisses accepting error state`() = runTest { fun `present - dismisses accepting error state`() = runTest {
val invitesDataSource = FakeRoomSummaryDataSource().withRoomInvitation() val invitesDataSource = FakeRoomSummaryDataSource().withRoomInvitation()
val client = FakeMatrixClient( val client = FakeMatrixClient(
sessionId = A_SESSION_ID,
invitesDataSource = invitesDataSource, invitesDataSource = invitesDataSource,
) )
val room = FakeMatrixRoom() val room = FakeMatrixRoom()
@ -379,7 +362,6 @@ class InviteListPresenterTests {
val store = FakeSeenInvitesStore() val store = FakeSeenInvitesStore()
val presenter = InviteListPresenter( val presenter = InviteListPresenter(
FakeMatrixClient( FakeMatrixClient(
sessionId = A_SESSION_ID,
invitesDataSource = invitesDataSource, invitesDataSource = invitesDataSource,
), ),
store, store,
@ -416,7 +398,6 @@ class InviteListPresenterTests {
store.publishRoomIds(setOf(A_ROOM_ID)) store.publishRoomIds(setOf(A_ROOM_ID))
val presenter = InviteListPresenter( val presenter = InviteListPresenter(
FakeMatrixClient( FakeMatrixClient(
sessionId = A_SESSION_ID,
invitesDataSource = invitesDataSource, invitesDataSource = invitesDataSource,
), ),
store, store,

7
features/logout/impl/src/test/kotlin/io/element/android/features/logout/impl/LogoutPreferencePresenterTest.kt

@ -23,7 +23,6 @@ import com.google.common.truth.Truth.assertThat
import io.element.android.features.logout.api.LogoutPreferenceEvents import io.element.android.features.logout.api.LogoutPreferenceEvents
import io.element.android.features.logout.api.LogoutPreferenceState import io.element.android.features.logout.api.LogoutPreferenceState
import io.element.android.libraries.architecture.Async import io.element.android.libraries.architecture.Async
import io.element.android.libraries.matrix.test.A_SESSION_ID
import io.element.android.libraries.matrix.test.A_THROWABLE import io.element.android.libraries.matrix.test.A_THROWABLE
import io.element.android.libraries.matrix.test.FakeMatrixClient import io.element.android.libraries.matrix.test.FakeMatrixClient
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
@ -33,7 +32,7 @@ class LogoutPreferencePresenterTest {
@Test @Test
fun `present - initial state`() = runTest { fun `present - initial state`() = runTest {
val presenter = DefaultLogoutPreferencePresenter( val presenter = DefaultLogoutPreferencePresenter(
FakeMatrixClient(A_SESSION_ID), FakeMatrixClient(),
) )
moleculeFlow(RecompositionClock.Immediate) { moleculeFlow(RecompositionClock.Immediate) {
presenter.present() presenter.present()
@ -46,7 +45,7 @@ class LogoutPreferencePresenterTest {
@Test @Test
fun `present - logout`() = runTest { fun `present - logout`() = runTest {
val presenter = DefaultLogoutPreferencePresenter( val presenter = DefaultLogoutPreferencePresenter(
FakeMatrixClient(A_SESSION_ID), FakeMatrixClient(),
) )
moleculeFlow(RecompositionClock.Immediate) { moleculeFlow(RecompositionClock.Immediate) {
presenter.present() presenter.present()
@ -62,7 +61,7 @@ class LogoutPreferencePresenterTest {
@Test @Test
fun `present - logout with error`() = runTest { fun `present - logout with error`() = runTest {
val matrixClient = FakeMatrixClient(A_SESSION_ID) val matrixClient = FakeMatrixClient()
val presenter = DefaultLogoutPreferencePresenter( val presenter = DefaultLogoutPreferencePresenter(
matrixClient, matrixClient,
) )

11
features/messages/impl/src/test/kotlin/io/element/android/features/messages/MessagesPresenterTest.kt

@ -38,6 +38,7 @@ import io.element.android.features.messages.impl.timeline.model.event.TimelineIt
import io.element.android.features.messages.media.FakeLocalMediaFactory import io.element.android.features.messages.media.FakeLocalMediaFactory
import io.element.android.features.messages.utils.messagesummary.FakeMessageSummaryFormatter import io.element.android.features.messages.utils.messagesummary.FakeMessageSummaryFormatter
import io.element.android.features.networkmonitor.test.FakeNetworkMonitor import io.element.android.features.networkmonitor.test.FakeNetworkMonitor
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
import io.element.android.libraries.core.meta.BuildMeta import io.element.android.libraries.core.meta.BuildMeta
import io.element.android.libraries.core.meta.BuildType import io.element.android.libraries.core.meta.BuildType
import io.element.android.libraries.core.mimetype.MimeTypes import io.element.android.libraries.core.mimetype.MimeTypes
@ -56,7 +57,6 @@ import io.element.android.libraries.textcomposer.MessageComposerMode
import io.element.android.tests.testutils.testCoroutineDispatchers import io.element.android.tests.testutils.testCoroutineDispatchers
import io.mockk.mockk import io.mockk.mockk
import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.advanceUntilIdle
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import org.junit.Test import org.junit.Test
@ -78,8 +78,9 @@ class MessagesPresenterTest {
@Test @Test
fun `present - handle sending a reaction`() = runTest { fun `present - handle sending a reaction`() = runTest {
val coroutineDispatchers = testCoroutineDispatchers(useUnconfinedTestDispatcher = true)
val room = FakeMatrixRoom() val room = FakeMatrixRoom()
val presenter = createMessagePresenter(matrixRoom = room) val presenter = createMessagePresenter(matrixRoom = room, coroutineDispatchers = coroutineDispatchers)
moleculeFlow(RecompositionClock.Immediate) { moleculeFlow(RecompositionClock.Immediate) {
presenter.present() presenter.present()
}.test { }.test {
@ -264,8 +265,9 @@ class MessagesPresenterTest {
@Test @Test
fun `present - handle action redact`() = runTest { fun `present - handle action redact`() = runTest {
val coroutineDispatchers = testCoroutineDispatchers(useUnconfinedTestDispatcher = true)
val matrixRoom = FakeMatrixRoom() val matrixRoom = FakeMatrixRoom()
val presenter = createMessagePresenter(matrixRoom) val presenter = createMessagePresenter(matrixRoom = matrixRoom, coroutineDispatchers = coroutineDispatchers)
moleculeFlow(RecompositionClock.Immediate) { moleculeFlow(RecompositionClock.Immediate) {
presenter.present() presenter.present()
}.test { }.test {
@ -317,6 +319,7 @@ class MessagesPresenterTest {
} }
private fun TestScope.createMessagePresenter( private fun TestScope.createMessagePresenter(
coroutineDispatchers: CoroutineDispatchers = testCoroutineDispatchers(),
matrixRoom: MatrixRoom = FakeMatrixRoom() matrixRoom: MatrixRoom = FakeMatrixRoom()
): MessagesPresenter { ): MessagesPresenter {
val messageComposerPresenter = MessageComposerPresenter( val messageComposerPresenter = MessageComposerPresenter(
@ -358,7 +361,7 @@ class MessagesPresenterTest {
networkMonitor = FakeNetworkMonitor(), networkMonitor = FakeNetworkMonitor(),
snackbarDispatcher = SnackbarDispatcher(), snackbarDispatcher = SnackbarDispatcher(),
messageSummaryFormatter = FakeMessageSummaryFormatter(), messageSummaryFormatter = FakeMessageSummaryFormatter(),
dispatchers = testCoroutineDispatchers(), dispatchers = coroutineDispatchers,
) )
} }
} }

4
features/messages/impl/src/test/kotlin/io/element/android/features/messages/attachments/AttachmentsPreviewPresenterTest.kt

@ -19,7 +19,6 @@
package io.element.android.features.messages.attachments package io.element.android.features.messages.attachments
import android.net.Uri import android.net.Uri
import androidx.media3.common.MimeTypes
import app.cash.molecule.RecompositionClock import app.cash.molecule.RecompositionClock
import app.cash.molecule.moleculeFlow import app.cash.molecule.moleculeFlow
import app.cash.turbine.test import app.cash.turbine.test
@ -31,7 +30,6 @@ import io.element.android.features.messages.impl.attachments.preview.Attachments
import io.element.android.features.messages.impl.media.local.LocalMedia import io.element.android.features.messages.impl.media.local.LocalMedia
import io.element.android.libraries.architecture.Async import io.element.android.libraries.architecture.Async
import io.element.android.libraries.matrix.api.room.MatrixRoom import io.element.android.libraries.matrix.api.room.MatrixRoom
import io.element.android.libraries.matrix.test.FAKE_DELAY_IN_MS
import io.element.android.libraries.matrix.test.room.FakeMatrixRoom import io.element.android.libraries.matrix.test.room.FakeMatrixRoom
import io.element.android.libraries.mediaupload.api.MediaPreProcessor import io.element.android.libraries.mediaupload.api.MediaPreProcessor
import io.element.android.libraries.mediaupload.api.MediaSender import io.element.android.libraries.mediaupload.api.MediaSender
@ -58,7 +56,6 @@ class AttachmentsPreviewPresenterTest {
initialState.eventSink(AttachmentsPreviewEvents.SendAttachment) initialState.eventSink(AttachmentsPreviewEvents.SendAttachment)
val loadingState = awaitItem() val loadingState = awaitItem()
assertThat(loadingState.sendActionState).isEqualTo(Async.Loading<Unit>()) assertThat(loadingState.sendActionState).isEqualTo(Async.Loading<Unit>())
testScheduler.advanceTimeBy(FAKE_DELAY_IN_MS)
val successState = awaitItem() val successState = awaitItem()
assertThat(successState.sendActionState).isEqualTo(Async.Success(Unit)) assertThat(successState.sendActionState).isEqualTo(Async.Success(Unit))
assertThat(room.sendMediaCount).isEqualTo(1) assertThat(room.sendMediaCount).isEqualTo(1)
@ -79,7 +76,6 @@ class AttachmentsPreviewPresenterTest {
initialState.eventSink(AttachmentsPreviewEvents.SendAttachment) initialState.eventSink(AttachmentsPreviewEvents.SendAttachment)
val loadingState = awaitItem() val loadingState = awaitItem()
assertThat(loadingState.sendActionState).isEqualTo(Async.Loading<Unit>()) assertThat(loadingState.sendActionState).isEqualTo(Async.Loading<Unit>())
testScheduler.advanceTimeBy(FAKE_DELAY_IN_MS)
val failureState = awaitItem() val failureState = awaitItem()
assertThat(failureState.sendActionState).isEqualTo(Async.Failure<Unit>(failure)) assertThat(failureState.sendActionState).isEqualTo(Async.Failure<Unit>(failure))
assertThat(room.sendMediaCount).isEqualTo(0) assertThat(room.sendMediaCount).isEqualTo(0)

11
features/messages/impl/src/test/kotlin/io/element/android/features/messages/media/FakeLocalMediaActions.kt

@ -19,10 +19,9 @@ package io.element.android.features.messages.media
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import io.element.android.features.messages.impl.media.local.LocalMedia import io.element.android.features.messages.impl.media.local.LocalMedia
import io.element.android.features.messages.impl.media.local.LocalMediaActions import io.element.android.features.messages.impl.media.local.LocalMediaActions
import io.element.android.libraries.core.coroutine.CoroutineDispatchers import io.element.android.tests.testutils.simulateLongTask
import kotlinx.coroutines.withContext
class FakeLocalMediaActions(private val coroutineDispatchers: CoroutineDispatchers) : LocalMediaActions { class FakeLocalMediaActions : LocalMediaActions {
var shouldFail = false var shouldFail = false
@ -31,7 +30,7 @@ class FakeLocalMediaActions(private val coroutineDispatchers: CoroutineDispatche
//NOOP //NOOP
} }
override suspend fun saveOnDisk(localMedia: LocalMedia): Result<Unit> = withContext(coroutineDispatchers.io) { override suspend fun saveOnDisk(localMedia: LocalMedia): Result<Unit> = simulateLongTask {
if (shouldFail) { if (shouldFail) {
Result.failure(RuntimeException()) Result.failure(RuntimeException())
} else { } else {
@ -39,7 +38,7 @@ class FakeLocalMediaActions(private val coroutineDispatchers: CoroutineDispatche
} }
} }
override suspend fun share(localMedia: LocalMedia): Result<Unit> = withContext(coroutineDispatchers.io) { override suspend fun share(localMedia: LocalMedia): Result<Unit> = simulateLongTask {
if (shouldFail) { if (shouldFail) {
Result.failure(RuntimeException()) Result.failure(RuntimeException())
} else { } else {
@ -47,7 +46,7 @@ class FakeLocalMediaActions(private val coroutineDispatchers: CoroutineDispatche
} }
} }
override suspend fun open(localMedia: LocalMedia): Result<Unit> = withContext(coroutineDispatchers.io) { override suspend fun open(localMedia: LocalMedia): Result<Unit> = simulateLongTask {
if (shouldFail) { if (shouldFail) {
Result.failure(RuntimeException()) Result.failure(RuntimeException())
} else { } else {

10
features/messages/impl/src/test/kotlin/io/element/android/features/messages/media/viewer/MediaViewerPresenterTest.kt

@ -33,7 +33,6 @@ import io.element.android.libraries.architecture.Async
import io.element.android.libraries.designsystem.utils.SnackbarDispatcher import io.element.android.libraries.designsystem.utils.SnackbarDispatcher
import io.element.android.libraries.matrix.test.media.FakeMediaLoader import io.element.android.libraries.matrix.test.media.FakeMediaLoader
import io.element.android.libraries.matrix.test.media.aMediaSource import io.element.android.libraries.matrix.test.media.aMediaSource
import io.element.android.tests.testutils.testCoroutineDispatchers
import io.mockk.mockk import io.mockk.mockk
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
@ -48,9 +47,8 @@ class MediaViewerPresenterTest {
@Test @Test
fun `present - download media success scenario`() = runTest { fun `present - download media success scenario`() = runTest {
val coroutineDispatchers = testCoroutineDispatchers(useUnconfinedTestDispatcher = false)
val mediaLoader = FakeMediaLoader() val mediaLoader = FakeMediaLoader()
val mediaActions = FakeLocalMediaActions(coroutineDispatchers) val mediaActions = FakeLocalMediaActions()
val presenter = aMediaViewerPresenter(mediaLoader, mediaActions) val presenter = aMediaViewerPresenter(mediaLoader, mediaActions)
moleculeFlow(RecompositionClock.Immediate) { moleculeFlow(RecompositionClock.Immediate) {
presenter.present() presenter.present()
@ -69,9 +67,8 @@ class MediaViewerPresenterTest {
@Test @Test
fun `present - check all actions `() = runTest { fun `present - check all actions `() = runTest {
val coroutineDispatchers = testCoroutineDispatchers(useUnconfinedTestDispatcher = false)
val mediaLoader = FakeMediaLoader() val mediaLoader = FakeMediaLoader()
val mediaActions = FakeLocalMediaActions(coroutineDispatchers) val mediaActions = FakeLocalMediaActions()
val presenter = aMediaViewerPresenter(mediaLoader, mediaActions) val presenter = aMediaViewerPresenter(mediaLoader, mediaActions)
moleculeFlow(RecompositionClock.Immediate) { moleculeFlow(RecompositionClock.Immediate) {
presenter.present() presenter.present()
@ -118,9 +115,8 @@ class MediaViewerPresenterTest {
@Test @Test
fun `present - download media failure then retry with success scenario`() = runTest { fun `present - download media failure then retry with success scenario`() = runTest {
val coroutineDispatchers = testCoroutineDispatchers(useUnconfinedTestDispatcher = false)
val mediaLoader = FakeMediaLoader() val mediaLoader = FakeMediaLoader()
val mediaActions = FakeLocalMediaActions(coroutineDispatchers) val mediaActions = FakeLocalMediaActions()
val presenter = aMediaViewerPresenter(mediaLoader, mediaActions) val presenter = aMediaViewerPresenter(mediaLoader, mediaActions)
moleculeFlow(RecompositionClock.Immediate) { moleculeFlow(RecompositionClock.Immediate) {
presenter.present() presenter.present()

7
features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/RoomDetailsPresenterTests.kt

@ -27,7 +27,6 @@ import io.element.android.features.roomdetails.impl.RoomTopicState
import io.element.android.features.roomdetails.impl.members.aRoomMember import io.element.android.features.roomdetails.impl.members.aRoomMember
import io.element.android.features.roomdetails.impl.members.details.RoomMemberDetailsPresenter import io.element.android.features.roomdetails.impl.members.details.RoomMemberDetailsPresenter
import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.core.SessionId
import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.api.room.MatrixRoom import io.element.android.libraries.matrix.api.room.MatrixRoom
import io.element.android.libraries.matrix.api.room.MatrixRoomMembersState import io.element.android.libraries.matrix.api.room.MatrixRoomMembersState
@ -48,7 +47,7 @@ class RoomDetailsPresenterTests {
private fun aRoomDetailsPresenter(room: MatrixRoom): RoomDetailsPresenter { private fun aRoomDetailsPresenter(room: MatrixRoom): RoomDetailsPresenter {
val roomMemberDetailsPresenterFactory = object : RoomMemberDetailsPresenter.Factory { val roomMemberDetailsPresenterFactory = object : RoomMemberDetailsPresenter.Factory {
override fun create(roomMemberId: UserId): RoomMemberDetailsPresenter { override fun create(roomMemberId: UserId): RoomMemberDetailsPresenter {
return RoomMemberDetailsPresenter(aMatrixClient(), room, roomMemberId) return RoomMemberDetailsPresenter(FakeMatrixClient(), room, roomMemberId)
} }
} }
return RoomDetailsPresenter(room, roomMemberDetailsPresenterFactory, LeaveRoomPresenterFake()) return RoomDetailsPresenter(room, roomMemberDetailsPresenterFactory, LeaveRoomPresenterFake())
@ -250,10 +249,6 @@ class RoomDetailsPresenterTests {
} }
} }
fun aMatrixClient(
sessionId: SessionId = A_SESSION_ID,
) = FakeMatrixClient(sessionId = sessionId)
fun aMatrixRoom( fun aMatrixRoom(
roomId: RoomId = A_ROOM_ID, roomId: RoomId = A_ROOM_ID,
name: String? = A_ROOM_NAME, name: String? = A_ROOM_NAME,

25
features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/edit/RoomDetailsEditPresenterTest.kt

@ -105,7 +105,8 @@ class RoomDetailsEditPresenterTest {
val room = aMatrixRoom(avatarUrl = AN_AVATAR_URL).apply { val room = aMatrixRoom(avatarUrl = AN_AVATAR_URL).apply {
givenCanSendStateResult(StateEventType.ROOM_NAME, Result.success(true)) givenCanSendStateResult(StateEventType.ROOM_NAME, Result.success(true))
givenCanSendStateResult(StateEventType.ROOM_AVATAR, Result.success(false)) givenCanSendStateResult(StateEventType.ROOM_AVATAR, Result.success(false))
givenCanSendStateResult(StateEventType.ROOM_TOPIC, Result.failure(Throwable("Oops"))) } givenCanSendStateResult(StateEventType.ROOM_TOPIC, Result.failure(Throwable("Oops")))
}
val presenter = aRoomDetailsEditPresenter(room) val presenter = aRoomDetailsEditPresenter(room)
moleculeFlow(RecompositionClock.Immediate) { moleculeFlow(RecompositionClock.Immediate) {
@ -381,7 +382,7 @@ class RoomDetailsEditPresenterTest {
initialState.eventSink(RoomDetailsEditEvents.UpdateRoomTopic("New topic")) initialState.eventSink(RoomDetailsEditEvents.UpdateRoomTopic("New topic"))
initialState.eventSink(RoomDetailsEditEvents.HandleAvatarAction(AvatarAction.Remove)) initialState.eventSink(RoomDetailsEditEvents.HandleAvatarAction(AvatarAction.Remove))
initialState.eventSink(RoomDetailsEditEvents.Save) initialState.eventSink(RoomDetailsEditEvents.Save)
skipItems(5)
assertThat(room.newName).isEqualTo("New name") assertThat(room.newName).isEqualTo("New name")
assertThat(room.newTopic).isEqualTo("New topic") assertThat(room.newTopic).isEqualTo("New topic")
assertThat(room.newAvatarData).isNull() assertThat(room.newAvatarData).isNull()
@ -476,7 +477,7 @@ class RoomDetailsEditPresenterTest {
initialState.eventSink(RoomDetailsEditEvents.HandleAvatarAction(AvatarAction.ChoosePhoto)) initialState.eventSink(RoomDetailsEditEvents.HandleAvatarAction(AvatarAction.ChoosePhoto))
initialState.eventSink(RoomDetailsEditEvents.Save) initialState.eventSink(RoomDetailsEditEvents.Save)
skipItems(2) skipItems(3)
assertThat(room.newName).isNull() assertThat(room.newName).isNull()
assertThat(room.newTopic).isNull() assertThat(room.newTopic).isNull()
@ -501,7 +502,7 @@ class RoomDetailsEditPresenterTest {
initialState.eventSink(RoomDetailsEditEvents.HandleAvatarAction(AvatarAction.ChoosePhoto)) initialState.eventSink(RoomDetailsEditEvents.HandleAvatarAction(AvatarAction.ChoosePhoto))
initialState.eventSink(RoomDetailsEditEvents.Save) initialState.eventSink(RoomDetailsEditEvents.Save)
skipItems(1) skipItems(2)
assertThat(room.newName).isNull() assertThat(room.newName).isNull()
assertThat(room.newTopic).isNull() assertThat(room.newTopic).isNull()
@ -567,7 +568,7 @@ class RoomDetailsEditPresenterTest {
initialState.eventSink(RoomDetailsEditEvents.UpdateRoomTopic("foo")) initialState.eventSink(RoomDetailsEditEvents.UpdateRoomTopic("foo"))
initialState.eventSink(RoomDetailsEditEvents.Save) initialState.eventSink(RoomDetailsEditEvents.Save)
skipItems(1) skipItems(2)
assertThat(awaitItem().saveAction).isInstanceOf(Async.Failure::class.java) assertThat(awaitItem().saveAction).isInstanceOf(Async.Failure::class.java)
@ -588,6 +589,7 @@ class RoomDetailsEditPresenterTest {
initialState.eventSink(RoomDetailsEditEvents.Save) initialState.eventSink(RoomDetailsEditEvents.Save)
skipItems(1) skipItems(1)
assertThat(awaitItem().saveAction).isInstanceOf(Async.Loading::class.java)
assertThat(awaitItem().saveAction).isInstanceOf(Async.Failure::class.java) assertThat(awaitItem().saveAction).isInstanceOf(Async.Failure::class.java)
} }
} }
@ -599,14 +601,17 @@ class RoomDetailsEditPresenterTest {
} }
fakePickerProvider.givenResult(anotherAvatarUri) fakePickerProvider.givenResult(anotherAvatarUri)
fakeMediaPreProcessor.givenResult(Result.success(MediaUploadInfo.AnyFile( fakeMediaPreProcessor.givenResult(
file = processedFile, Result.success(
info = mockk(), MediaUploadInfo.AnyFile(
))) file = processedFile,
info = mockk(),
)
)
)
} }
companion object { companion object {
private const val ANOTHER_AVATAR_URL = "example://camera/foo.jpg" private const val ANOTHER_AVATAR_URL = "example://camera/foo.jpg"
} }
} }

50
features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersPresenterTest.kt

@ -93,9 +93,8 @@ internal class RoomInviteMembersPresenterTest {
val presenter = RoomInviteMembersPresenter( val presenter = RoomInviteMembersPresenter(
userRepository = repository, userRepository = repository,
roomMemberListDataSource = createDataSource(FakeMatrixRoom()), roomMemberListDataSource = createDataSource(FakeMatrixRoom()),
coroutineDispatchers = testCoroutineDispatchers() coroutineDispatchers = testCoroutineDispatchers(useUnconfinedTestDispatcher = true)
) )
moleculeFlow(RecompositionClock.Immediate) { moleculeFlow(RecompositionClock.Immediate) {
presenter.present() presenter.present()
}.test { }.test {
@ -120,9 +119,8 @@ internal class RoomInviteMembersPresenterTest {
val presenter = RoomInviteMembersPresenter( val presenter = RoomInviteMembersPresenter(
userRepository = repository, userRepository = repository,
roomMemberListDataSource = createDataSource(FakeMatrixRoom()), roomMemberListDataSource = createDataSource(FakeMatrixRoom()),
coroutineDispatchers = testCoroutineDispatchers() coroutineDispatchers = testCoroutineDispatchers(useUnconfinedTestDispatcher = true)
) )
moleculeFlow(RecompositionClock.Immediate) { moleculeFlow(RecompositionClock.Immediate) {
presenter.present() presenter.present()
}.test { }.test {
@ -157,17 +155,24 @@ internal class RoomInviteMembersPresenterTest {
val invitedUser = userList[1] val invitedUser = userList[1]
val repository = FakeUserRepository() val repository = FakeUserRepository()
val coroutineDispatchers = testCoroutineDispatchers(useUnconfinedTestDispatcher = true)
val presenter = RoomInviteMembersPresenter( val presenter = RoomInviteMembersPresenter(
userRepository = repository, userRepository = repository,
roomMemberListDataSource = createDataSource(FakeMatrixRoom().apply { roomMemberListDataSource = createDataSource(
givenRoomMembersState(MatrixRoomMembersState.Ready(listOf( matrixRoom = FakeMatrixRoom().apply {
aRoomMember(userId = joinedUser.userId, membership = RoomMembershipState.JOIN), givenRoomMembersState(
aRoomMember(userId = invitedUser.userId, membership = RoomMembershipState.INVITE), MatrixRoomMembersState.Ready(
))) listOf(
}), aRoomMember(userId = joinedUser.userId, membership = RoomMembershipState.JOIN),
coroutineDispatchers = testCoroutineDispatchers() aRoomMember(userId = invitedUser.userId, membership = RoomMembershipState.INVITE),
)
)
)
},
coroutineDispatchers = coroutineDispatchers,
),
coroutineDispatchers = coroutineDispatchers
) )
moleculeFlow(RecompositionClock.Immediate) { moleculeFlow(RecompositionClock.Immediate) {
presenter.present() presenter.present()
}.test { }.test {
@ -215,12 +220,16 @@ internal class RoomInviteMembersPresenterTest {
val presenter = RoomInviteMembersPresenter( val presenter = RoomInviteMembersPresenter(
userRepository = repository, userRepository = repository,
roomMemberListDataSource = createDataSource(FakeMatrixRoom().apply { roomMemberListDataSource = createDataSource(FakeMatrixRoom().apply {
givenRoomMembersState(MatrixRoomMembersState.Ready(listOf( givenRoomMembersState(
aRoomMember(userId = joinedUser.userId, membership = RoomMembershipState.JOIN), MatrixRoomMembersState.Ready(
aRoomMember(userId = invitedUser.userId, membership = RoomMembershipState.INVITE), listOf(
))) aRoomMember(userId = joinedUser.userId, membership = RoomMembershipState.JOIN),
aRoomMember(userId = invitedUser.userId, membership = RoomMembershipState.INVITE),
)
)
)
}), }),
coroutineDispatchers = testCoroutineDispatchers() coroutineDispatchers = testCoroutineDispatchers(useUnconfinedTestDispatcher = true)
) )
moleculeFlow(RecompositionClock.Immediate) { moleculeFlow(RecompositionClock.Immediate) {
@ -287,9 +296,8 @@ internal class RoomInviteMembersPresenterTest {
val presenter = RoomInviteMembersPresenter( val presenter = RoomInviteMembersPresenter(
userRepository = repository, userRepository = repository,
roomMemberListDataSource = createDataSource(FakeMatrixRoom()), roomMemberListDataSource = createDataSource(FakeMatrixRoom()),
coroutineDispatchers = testCoroutineDispatchers() coroutineDispatchers = testCoroutineDispatchers(useUnconfinedTestDispatcher = true)
) )
moleculeFlow(RecompositionClock.Immediate) { moleculeFlow(RecompositionClock.Immediate) {
presenter.present() presenter.present()
}.test { }.test {
@ -323,16 +331,14 @@ internal class RoomInviteMembersPresenterTest {
} }
} }
@Test @Test
fun `present - toggling a user updates existing search results`() = runTest { fun `present - toggling a user updates existing search results`() = runTest {
val repository = FakeUserRepository() val repository = FakeUserRepository()
val presenter = RoomInviteMembersPresenter( val presenter = RoomInviteMembersPresenter(
userRepository = repository, userRepository = repository,
roomMemberListDataSource = createDataSource(FakeMatrixRoom()), roomMemberListDataSource = createDataSource(FakeMatrixRoom()),
coroutineDispatchers = testCoroutineDispatchers() coroutineDispatchers = testCoroutineDispatchers(useUnconfinedTestDispatcher = true)
) )
moleculeFlow(RecompositionClock.Immediate) { moleculeFlow(RecompositionClock.Immediate) {
presenter.present() presenter.present()
}.test { }.test {

7
features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/members/RoomMemberListPresenterTests.kt

@ -20,7 +20,6 @@ import app.cash.molecule.RecompositionClock
import app.cash.molecule.moleculeFlow import app.cash.molecule.moleculeFlow
import app.cash.turbine.test import app.cash.turbine.test
import com.google.common.truth.Truth import com.google.common.truth.Truth
import io.element.android.features.roomdetails.aMatrixRoom
import io.element.android.features.roomdetails.impl.members.RoomMemberListDataSource import io.element.android.features.roomdetails.impl.members.RoomMemberListDataSource
import io.element.android.features.roomdetails.impl.members.RoomMemberListEvents import io.element.android.features.roomdetails.impl.members.RoomMemberListEvents
import io.element.android.features.roomdetails.impl.members.RoomMemberListPresenter import io.element.android.features.roomdetails.impl.members.RoomMemberListPresenter
@ -167,7 +166,7 @@ class RoomMemberListPresenterTests {
@ExperimentalCoroutinesApi @ExperimentalCoroutinesApi
private fun TestScope.createDataSource( private fun TestScope.createDataSource(
matrixRoom: MatrixRoom = aMatrixRoom().apply { matrixRoom: MatrixRoom = FakeMatrixRoom().apply {
givenRoomMembersState(MatrixRoomMembersState.Ready(aRoomMemberList())) givenRoomMembersState(MatrixRoomMembersState.Ready(aRoomMemberList()))
}, },
coroutineDispatchers: CoroutineDispatchers = testCoroutineDispatchers() coroutineDispatchers: CoroutineDispatchers = testCoroutineDispatchers()
@ -175,7 +174,7 @@ private fun TestScope.createDataSource(
@ExperimentalCoroutinesApi @ExperimentalCoroutinesApi
private fun TestScope.createPresenter( private fun TestScope.createPresenter(
coroutineDispatchers: CoroutineDispatchers = testCoroutineDispatchers(useUnconfinedTestDispatcher = true),
matrixRoom: MatrixRoom = FakeMatrixRoom(), matrixRoom: MatrixRoom = FakeMatrixRoom(),
roomMemberListDataSource: RoomMemberListDataSource = createDataSource(), roomMemberListDataSource: RoomMemberListDataSource = createDataSource(coroutineDispatchers = coroutineDispatchers),
coroutineDispatchers: CoroutineDispatchers = testCoroutineDispatchers()
) = RoomMemberListPresenter(matrixRoom, roomMemberListDataSource, coroutineDispatchers) ) = RoomMemberListPresenter(matrixRoom, roomMemberListDataSource, coroutineDispatchers)

18
features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/members/details/RoomMemberDetailsPresenterTests.kt

@ -20,13 +20,13 @@ import app.cash.molecule.RecompositionClock
import app.cash.molecule.moleculeFlow import app.cash.molecule.moleculeFlow
import app.cash.turbine.test import app.cash.turbine.test
import com.google.common.truth.Truth import com.google.common.truth.Truth
import io.element.android.features.roomdetails.aMatrixClient
import io.element.android.features.roomdetails.aMatrixRoom import io.element.android.features.roomdetails.aMatrixRoom
import io.element.android.features.roomdetails.impl.members.aRoomMember import io.element.android.features.roomdetails.impl.members.aRoomMember
import io.element.android.features.roomdetails.impl.members.details.RoomMemberDetailsEvents import io.element.android.features.roomdetails.impl.members.details.RoomMemberDetailsEvents
import io.element.android.features.roomdetails.impl.members.details.RoomMemberDetailsPresenter import io.element.android.features.roomdetails.impl.members.details.RoomMemberDetailsPresenter
import io.element.android.features.roomdetails.impl.members.details.RoomMemberDetailsState import io.element.android.features.roomdetails.impl.members.details.RoomMemberDetailsState
import io.element.android.libraries.matrix.api.room.MatrixRoomMembersState import io.element.android.libraries.matrix.api.room.MatrixRoomMembersState
import io.element.android.libraries.matrix.test.FakeMatrixClient
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import org.junit.Test import org.junit.Test
@ -34,8 +34,6 @@ import org.junit.Test
@ExperimentalCoroutinesApi @ExperimentalCoroutinesApi
class RoomMemberDetailsPresenterTests { class RoomMemberDetailsPresenterTests {
private val matrixClient = aMatrixClient()
@Test @Test
fun `present - returns the room member's data, then updates it if needed`() = runTest { fun `present - returns the room member's data, then updates it if needed`() = runTest {
val roomMember = aRoomMember(displayName = "Alice") val roomMember = aRoomMember(displayName = "Alice")
@ -44,7 +42,7 @@ class RoomMemberDetailsPresenterTests {
givenUserAvatarUrlResult(Result.success("A custom avatar")) givenUserAvatarUrlResult(Result.success("A custom avatar"))
givenRoomMembersState(MatrixRoomMembersState.Ready(listOf(roomMember))) givenRoomMembersState(MatrixRoomMembersState.Ready(listOf(roomMember)))
} }
val presenter = RoomMemberDetailsPresenter(matrixClient, room, roomMember.userId) val presenter = RoomMemberDetailsPresenter(FakeMatrixClient(), room, roomMember.userId)
moleculeFlow(RecompositionClock.Immediate) { moleculeFlow(RecompositionClock.Immediate) {
presenter.present() presenter.present()
}.test { }.test {
@ -53,7 +51,7 @@ class RoomMemberDetailsPresenterTests {
Truth.assertThat(initialState.userName).isEqualTo(roomMember.displayName) Truth.assertThat(initialState.userName).isEqualTo(roomMember.displayName)
Truth.assertThat(initialState.avatarUrl).isEqualTo(roomMember.avatarUrl) Truth.assertThat(initialState.avatarUrl).isEqualTo(roomMember.avatarUrl)
Truth.assertThat(initialState.isBlocked).isEqualTo(roomMember.isIgnored) Truth.assertThat(initialState.isBlocked).isEqualTo(roomMember.isIgnored)
skipItems(1)
val loadedState = awaitItem() val loadedState = awaitItem()
Truth.assertThat(loadedState.userName).isEqualTo("A custom name") Truth.assertThat(loadedState.userName).isEqualTo("A custom name")
Truth.assertThat(loadedState.avatarUrl).isEqualTo("A custom avatar") Truth.assertThat(loadedState.avatarUrl).isEqualTo("A custom avatar")
@ -68,7 +66,7 @@ class RoomMemberDetailsPresenterTests {
givenUserAvatarUrlResult(Result.failure(Throwable())) givenUserAvatarUrlResult(Result.failure(Throwable()))
givenRoomMembersState(MatrixRoomMembersState.Ready(listOf(roomMember))) givenRoomMembersState(MatrixRoomMembersState.Ready(listOf(roomMember)))
} }
val presenter = RoomMemberDetailsPresenter(matrixClient, room, roomMember.userId) val presenter = RoomMemberDetailsPresenter(FakeMatrixClient(), room, roomMember.userId)
moleculeFlow(RecompositionClock.Immediate) { moleculeFlow(RecompositionClock.Immediate) {
presenter.present() presenter.present()
}.test { }.test {
@ -88,7 +86,7 @@ class RoomMemberDetailsPresenterTests {
givenUserAvatarUrlResult(Result.success(null)) givenUserAvatarUrlResult(Result.success(null))
givenRoomMembersState(MatrixRoomMembersState.Ready(listOf(roomMember))) givenRoomMembersState(MatrixRoomMembersState.Ready(listOf(roomMember)))
} }
val presenter =RoomMemberDetailsPresenter(matrixClient, room, roomMember.userId) val presenter = RoomMemberDetailsPresenter(FakeMatrixClient(), room, roomMember.userId)
moleculeFlow(RecompositionClock.Immediate) { moleculeFlow(RecompositionClock.Immediate) {
presenter.present() presenter.present()
}.test { }.test {
@ -104,7 +102,7 @@ class RoomMemberDetailsPresenterTests {
fun `present - BlockUser needing confirmation displays confirmation dialog`() = runTest { fun `present - BlockUser needing confirmation displays confirmation dialog`() = runTest {
val room = aMatrixRoom() val room = aMatrixRoom()
val roomMember = aRoomMember() val roomMember = aRoomMember()
val presenter =RoomMemberDetailsPresenter(matrixClient, room, roomMember.userId) val presenter = RoomMemberDetailsPresenter(FakeMatrixClient(), room, roomMember.userId)
moleculeFlow(RecompositionClock.Immediate) { moleculeFlow(RecompositionClock.Immediate) {
presenter.present() presenter.present()
}.test { }.test {
@ -125,7 +123,7 @@ class RoomMemberDetailsPresenterTests {
fun `present - BlockUser and UnblockUser without confirmation change the 'blocked' state`() = runTest { fun `present - BlockUser and UnblockUser without confirmation change the 'blocked' state`() = runTest {
val room = aMatrixRoom() val room = aMatrixRoom()
val roomMember = aRoomMember() val roomMember = aRoomMember()
val presenter =RoomMemberDetailsPresenter(matrixClient, room, roomMember.userId) val presenter = RoomMemberDetailsPresenter(FakeMatrixClient(), room, roomMember.userId)
moleculeFlow(RecompositionClock.Immediate) { moleculeFlow(RecompositionClock.Immediate) {
presenter.present() presenter.present()
}.test { }.test {
@ -142,7 +140,7 @@ class RoomMemberDetailsPresenterTests {
fun `present - UnblockUser needing confirmation displays confirmation dialog`() = runTest { fun `present - UnblockUser needing confirmation displays confirmation dialog`() = runTest {
val room = aMatrixRoom() val room = aMatrixRoom()
val roomMember = aRoomMember() val roomMember = aRoomMember()
val presenter =RoomMemberDetailsPresenter(matrixClient, room, roomMember.userId) val presenter = RoomMemberDetailsPresenter(FakeMatrixClient(), room, roomMember.userId)
moleculeFlow(RecompositionClock.Immediate) { moleculeFlow(RecompositionClock.Immediate) {
presenter.present() presenter.present()
}.test { }.test {

4
features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/DefaultInviteStateDataSourceTest.kt

@ -69,7 +69,7 @@ internal class DefaultInviteStateDataSourceTest {
val client = FakeMatrixClient(invitesDataSource = matrixDataSource) val client = FakeMatrixClient(invitesDataSource = matrixDataSource)
val seenStore = FakeSeenInvitesStore() val seenStore = FakeSeenInvitesStore()
seenStore.publishRoomIds(setOf(A_ROOM_ID)) seenStore.publishRoomIds(setOf(A_ROOM_ID))
val dataSource = DefaultInviteStateDataSource(client, seenStore, testCoroutineDispatchers()) val dataSource = DefaultInviteStateDataSource(client, seenStore, testCoroutineDispatchers(useUnconfinedTestDispatcher = true))
moleculeFlow(RecompositionClock.Immediate) { moleculeFlow(RecompositionClock.Immediate) {
dataSource.inviteState() dataSource.inviteState()
@ -86,7 +86,7 @@ internal class DefaultInviteStateDataSourceTest {
val client = FakeMatrixClient(invitesDataSource = matrixDataSource) val client = FakeMatrixClient(invitesDataSource = matrixDataSource)
val seenStore = FakeSeenInvitesStore() val seenStore = FakeSeenInvitesStore()
seenStore.publishRoomIds(setOf(A_ROOM_ID)) seenStore.publishRoomIds(setOf(A_ROOM_ID))
val dataSource = DefaultInviteStateDataSource(client, seenStore, testCoroutineDispatchers()) val dataSource = DefaultInviteStateDataSource(client, seenStore, testCoroutineDispatchers(useUnconfinedTestDispatcher = true))
moleculeFlow(RecompositionClock.Immediate) { moleculeFlow(RecompositionClock.Immediate) {
dataSource.inviteState() dataSource.inviteState()

20
features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/RoomListPresenterTests.kt

@ -35,7 +35,6 @@ import io.element.android.libraries.matrix.test.AN_AVATAR_URL
import io.element.android.libraries.matrix.test.AN_EXCEPTION import io.element.android.libraries.matrix.test.AN_EXCEPTION
import io.element.android.libraries.matrix.test.A_ROOM_ID import io.element.android.libraries.matrix.test.A_ROOM_ID
import io.element.android.libraries.matrix.test.A_ROOM_NAME import io.element.android.libraries.matrix.test.A_ROOM_NAME
import io.element.android.libraries.matrix.test.A_SESSION_ID
import io.element.android.libraries.matrix.test.A_USER_ID import io.element.android.libraries.matrix.test.A_USER_ID
import io.element.android.libraries.matrix.test.A_USER_NAME import io.element.android.libraries.matrix.test.A_USER_NAME
import io.element.android.libraries.matrix.test.FakeMatrixClient import io.element.android.libraries.matrix.test.FakeMatrixClient
@ -51,7 +50,7 @@ class RoomListPresenterTests {
@Test @Test
fun `present - should start with no user and then load user with success`() = runTest { fun `present - should start with no user and then load user with success`() = runTest {
val presenter = RoomListPresenter( val presenter = RoomListPresenter(
FakeMatrixClient(A_SESSION_ID), FakeMatrixClient(),
createDateFormatter(), createDateFormatter(),
FakeRoomLastMessageFormatter(), FakeRoomLastMessageFormatter(),
FakeSessionVerificationService(), FakeSessionVerificationService(),
@ -77,7 +76,6 @@ class RoomListPresenterTests {
fun `present - should start with no user and then load user with error`() = runTest { fun `present - should start with no user and then load user with error`() = runTest {
val presenter = RoomListPresenter( val presenter = RoomListPresenter(
FakeMatrixClient( FakeMatrixClient(
A_SESSION_ID,
userDisplayName = Result.failure(AN_EXCEPTION), userDisplayName = Result.failure(AN_EXCEPTION),
userAvatarURLString = Result.failure(AN_EXCEPTION), userAvatarURLString = Result.failure(AN_EXCEPTION),
), ),
@ -102,7 +100,7 @@ class RoomListPresenterTests {
@Test @Test
fun `present - should filter room with success`() = runTest { fun `present - should filter room with success`() = runTest {
val presenter = RoomListPresenter( val presenter = RoomListPresenter(
FakeMatrixClient(A_SESSION_ID), FakeMatrixClient(),
createDateFormatter(), createDateFormatter(),
FakeRoomLastMessageFormatter(), FakeRoomLastMessageFormatter(),
FakeSessionVerificationService(), FakeSessionVerificationService(),
@ -130,7 +128,6 @@ class RoomListPresenterTests {
val roomSummaryDataSource = FakeRoomSummaryDataSource() val roomSummaryDataSource = FakeRoomSummaryDataSource()
val presenter = RoomListPresenter( val presenter = RoomListPresenter(
FakeMatrixClient( FakeMatrixClient(
sessionId = A_SESSION_ID,
roomSummaryDataSource = roomSummaryDataSource roomSummaryDataSource = roomSummaryDataSource
), ),
createDateFormatter(), createDateFormatter(),
@ -163,7 +160,6 @@ class RoomListPresenterTests {
val roomSummaryDataSource = FakeRoomSummaryDataSource() val roomSummaryDataSource = FakeRoomSummaryDataSource()
val presenter = RoomListPresenter( val presenter = RoomListPresenter(
FakeMatrixClient( FakeMatrixClient(
sessionId = A_SESSION_ID,
roomSummaryDataSource = roomSummaryDataSource roomSummaryDataSource = roomSummaryDataSource
), ),
createDateFormatter(), createDateFormatter(),
@ -202,7 +198,6 @@ class RoomListPresenterTests {
val roomSummaryDataSource = FakeRoomSummaryDataSource() val roomSummaryDataSource = FakeRoomSummaryDataSource()
val presenter = RoomListPresenter( val presenter = RoomListPresenter(
FakeMatrixClient( FakeMatrixClient(
sessionId = A_SESSION_ID,
roomSummaryDataSource = roomSummaryDataSource roomSummaryDataSource = roomSummaryDataSource
), ),
createDateFormatter(), createDateFormatter(),
@ -251,7 +246,6 @@ class RoomListPresenterTests {
val roomSummaryDataSource = FakeRoomSummaryDataSource() val roomSummaryDataSource = FakeRoomSummaryDataSource()
val presenter = RoomListPresenter( val presenter = RoomListPresenter(
FakeMatrixClient( FakeMatrixClient(
sessionId = A_SESSION_ID,
roomSummaryDataSource = roomSummaryDataSource roomSummaryDataSource = roomSummaryDataSource
), ),
createDateFormatter(), createDateFormatter(),
@ -280,9 +274,7 @@ class RoomListPresenterTests {
fun `present - sets invite state`() = runTest { fun `present - sets invite state`() = runTest {
val inviteStateFlow = MutableStateFlow(InvitesState.NoInvites) val inviteStateFlow = MutableStateFlow(InvitesState.NoInvites)
val presenter = RoomListPresenter( val presenter = RoomListPresenter(
FakeMatrixClient( FakeMatrixClient(),
sessionId = A_SESSION_ID,
),
createDateFormatter(), createDateFormatter(),
FakeRoomLastMessageFormatter(), FakeRoomLastMessageFormatter(),
FakeSessionVerificationService(), FakeSessionVerificationService(),
@ -312,7 +304,7 @@ class RoomListPresenterTests {
@Test @Test
fun `present - show context menu`() = runTest { fun `present - show context menu`() = runTest {
val presenter = RoomListPresenter( val presenter = RoomListPresenter(
FakeMatrixClient(A_SESSION_ID), FakeMatrixClient(),
createDateFormatter(), createDateFormatter(),
FakeRoomLastMessageFormatter(), FakeRoomLastMessageFormatter(),
FakeSessionVerificationService(), FakeSessionVerificationService(),
@ -339,7 +331,7 @@ class RoomListPresenterTests {
@Test @Test
fun `present - hide context menu`() = runTest { fun `present - hide context menu`() = runTest {
val presenter = RoomListPresenter( val presenter = RoomListPresenter(
FakeMatrixClient(A_SESSION_ID), FakeMatrixClient(),
createDateFormatter(), createDateFormatter(),
FakeRoomLastMessageFormatter(), FakeRoomLastMessageFormatter(),
FakeSessionVerificationService(), FakeSessionVerificationService(),
@ -371,7 +363,7 @@ class RoomListPresenterTests {
fun `present - leave room calls into leave room presenter`() = runTest { fun `present - leave room calls into leave room presenter`() = runTest {
val leaveRoomPresenter = LeaveRoomPresenterFake() val leaveRoomPresenter = LeaveRoomPresenterFake()
val presenter = RoomListPresenter( val presenter = RoomListPresenter(
FakeMatrixClient(A_SESSION_ID), FakeMatrixClient(),
createDateFormatter(), createDateFormatter(),
FakeRoomLastMessageFormatter(), FakeRoomLastMessageFormatter(),
FakeSessionVerificationService(), FakeSessionVerificationService(),

1
libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/FakeMatrixClient.kt

@ -16,7 +16,6 @@
package io.element.android.libraries.matrix.test package io.element.android.libraries.matrix.test
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
import io.element.android.libraries.matrix.api.MatrixClient import io.element.android.libraries.matrix.api.MatrixClient
import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.core.SessionId import io.element.android.libraries.matrix.api.core.SessionId

2
libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/TestData.kt

@ -55,8 +55,6 @@ const val AN_AVATAR_URL = "mxc://data"
const val A_FAILURE_REASON = "There has been a failure" const val A_FAILURE_REASON = "There has been a failure"
const val FAKE_DELAY_IN_MS = 100L
val A_THROWABLE = Throwable(A_FAILURE_REASON) val A_THROWABLE = Throwable(A_FAILURE_REASON)
val AN_EXCEPTION = Exception(A_FAILURE_REASON) val AN_EXCEPTION = Exception(A_FAILURE_REASON)

22
libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/auth/FakeAuthenticationService.kt

@ -22,8 +22,7 @@ import io.element.android.libraries.matrix.api.auth.MatrixHomeServerDetails
import io.element.android.libraries.matrix.api.auth.OidcDetails import io.element.android.libraries.matrix.api.auth.OidcDetails
import io.element.android.libraries.matrix.api.core.SessionId import io.element.android.libraries.matrix.api.core.SessionId
import io.element.android.libraries.matrix.test.A_USER_ID import io.element.android.libraries.matrix.test.A_USER_ID
import io.element.android.libraries.matrix.test.FAKE_DELAY_IN_MS import io.element.android.tests.testutils.simulateLongTask
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
@ -58,27 +57,24 @@ class FakeAuthenticationService : MatrixAuthenticationService {
this.homeserver.value = homeserver this.homeserver.value = homeserver
} }
override suspend fun setHomeserver(homeserver: String): Result<Unit> { override suspend fun setHomeserver(homeserver: String): Result<Unit> = simulateLongTask {
delay(FAKE_DELAY_IN_MS) changeServerError?.let { Result.failure(it) } ?: Result.success(Unit)
return changeServerError?.let { Result.failure(it) } ?: Result.success(Unit)
} }
override suspend fun login(username: String, password: String): Result<SessionId> { override suspend fun login(username: String, password: String): Result<SessionId> = simulateLongTask {
delay(FAKE_DELAY_IN_MS) loginError?.let { Result.failure(it) } ?: Result.success(A_USER_ID)
return loginError?.let { Result.failure(it) } ?: Result.success(A_USER_ID)
} }
override suspend fun getOidcUrl(): Result<OidcDetails> { override suspend fun getOidcUrl(): Result<OidcDetails> = simulateLongTask {
return oidcError?.let { Result.failure(it) } ?: Result.success(A_OIDC_DATA) oidcError?.let { Result.failure(it) } ?: Result.success(A_OIDC_DATA)
} }
override suspend fun cancelOidcLogin(): Result<Unit> { override suspend fun cancelOidcLogin(): Result<Unit> {
return oidcCancelError?.let { Result.failure(it) } ?: Result.success(Unit) return oidcCancelError?.let { Result.failure(it) } ?: Result.success(Unit)
} }
override suspend fun loginWithOidc(callbackUrl: String): Result<SessionId> { override suspend fun loginWithOidc(callbackUrl: String): Result<SessionId> = simulateLongTask {
delay(FAKE_DELAY_IN_MS) loginError?.let { Result.failure(it) } ?: Result.success(A_USER_ID)
return loginError?.let { Result.failure(it) } ?: Result.success(A_USER_ID)
} }
fun givenOidcError(throwable: Throwable?) { fun givenOidcError(throwable: Throwable?) {

18
libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/media/FakeMediaLoader.kt

@ -19,34 +19,30 @@ package io.element.android.libraries.matrix.test.media
import io.element.android.libraries.matrix.api.media.MatrixMediaLoader import io.element.android.libraries.matrix.api.media.MatrixMediaLoader
import io.element.android.libraries.matrix.api.media.MediaFile import io.element.android.libraries.matrix.api.media.MediaFile
import io.element.android.libraries.matrix.api.media.MediaSource import io.element.android.libraries.matrix.api.media.MediaSource
import io.element.android.libraries.matrix.test.FAKE_DELAY_IN_MS import io.element.android.tests.testutils.simulateLongTask
import kotlinx.coroutines.delay
class FakeMediaLoader : MatrixMediaLoader { class FakeMediaLoader : MatrixMediaLoader {
var shouldFail = false var shouldFail = false
override suspend fun loadMediaContent(source: MediaSource): Result<ByteArray> { override suspend fun loadMediaContent(source: MediaSource): Result<ByteArray> = simulateLongTask {
delay(FAKE_DELAY_IN_MS) if (shouldFail) {
return if (shouldFail) {
Result.failure(RuntimeException()) Result.failure(RuntimeException())
} else { } else {
Result.success(ByteArray(0)) Result.success(ByteArray(0))
} }
} }
override suspend fun loadMediaThumbnail(source: MediaSource, width: Long, height: Long): Result<ByteArray> { override suspend fun loadMediaThumbnail(source: MediaSource, width: Long, height: Long): Result<ByteArray> = simulateLongTask {
delay(FAKE_DELAY_IN_MS) if (shouldFail) {
return if (shouldFail) {
Result.failure(RuntimeException()) Result.failure(RuntimeException())
} else { } else {
Result.success(ByteArray(0)) Result.success(ByteArray(0))
} }
} }
override suspend fun downloadMediaFile(source: MediaSource, mimeType: String?, body: String?): Result<MediaFile> { override suspend fun downloadMediaFile(source: MediaSource, mimeType: String?, body: String?): Result<MediaFile> = simulateLongTask {
delay(FAKE_DELAY_IN_MS) if (shouldFail) {
return if (shouldFail) {
Result.failure(RuntimeException()) Result.failure(RuntimeException())
} else { } else {
Result.success(FakeMediaFile("")) Result.success(FakeMediaFile(""))

49
libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeMatrixRoom.kt

@ -30,9 +30,8 @@ import io.element.android.libraries.matrix.api.room.StateEventType
import io.element.android.libraries.matrix.api.timeline.MatrixTimeline import io.element.android.libraries.matrix.api.timeline.MatrixTimeline
import io.element.android.libraries.matrix.test.A_ROOM_ID import io.element.android.libraries.matrix.test.A_ROOM_ID
import io.element.android.libraries.matrix.test.A_SESSION_ID import io.element.android.libraries.matrix.test.A_SESSION_ID
import io.element.android.libraries.matrix.test.FAKE_DELAY_IN_MS
import io.element.android.libraries.matrix.test.timeline.FakeMatrixTimeline import io.element.android.libraries.matrix.test.timeline.FakeMatrixTimeline
import kotlinx.coroutines.delay import io.element.android.tests.testutils.simulateLongTask
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.emptyFlow import kotlinx.coroutines.flow.emptyFlow
@ -111,8 +110,8 @@ class FakeMatrixRoom(
override val membersStateFlow: MutableStateFlow<MatrixRoomMembersState> = MutableStateFlow(MatrixRoomMembersState.Unknown) override val membersStateFlow: MutableStateFlow<MatrixRoomMembersState> = MutableStateFlow(MatrixRoomMembersState.Unknown)
override suspend fun updateMembers(): Result<Unit> { override suspend fun updateMembers(): Result<Unit> = simulateLongTask {
return updateMembersResult updateMembersResult
} }
override fun syncUpdateFlow(): Flow<Long> { override fun syncUpdateFlow(): Flow<Long> {
@ -123,17 +122,16 @@ class FakeMatrixRoom(
return matrixTimeline return matrixTimeline
} }
override suspend fun userDisplayName(userId: UserId): Result<String?> { override suspend fun userDisplayName(userId: UserId): Result<String?> = simulateLongTask {
return userDisplayNameResult userDisplayNameResult
} }
override suspend fun userAvatarUrl(userId: UserId): Result<String?> { override suspend fun userAvatarUrl(userId: UserId): Result<String?> = simulateLongTask {
return userAvatarUrlResult userAvatarUrlResult
} }
override suspend fun sendMessage(message: String): Result<Unit> { override suspend fun sendMessage(message: String): Result<Unit> = simulateLongTask {
delay(FAKE_DELAY_IN_MS) Result.success(Unit)
return Result.success(Unit)
} }
override suspend fun sendReaction(emoji: String, eventId: EventId): Result<Unit> { override suspend fun sendReaction(emoji: String, eventId: EventId): Result<Unit> {
@ -156,7 +154,6 @@ class FakeMatrixRoom(
override suspend fun editMessage(originalEventId: EventId, message: String): Result<Unit> { override suspend fun editMessage(originalEventId: EventId, message: String): Result<Unit> {
editMessageParameter = message editMessageParameter = message
delay(FAKE_DELAY_IN_MS)
return Result.success(Unit) return Result.success(Unit)
} }
@ -165,7 +162,6 @@ class FakeMatrixRoom(
override suspend fun replyMessage(eventId: EventId, message: String): Result<Unit> { override suspend fun replyMessage(eventId: EventId, message: String): Result<Unit> {
replyMessageParameter = message replyMessageParameter = message
delay(FAKE_DELAY_IN_MS)
return Result.success(Unit) return Result.success(Unit)
} }
@ -174,11 +170,11 @@ class FakeMatrixRoom(
override suspend fun redactEvent(eventId: EventId, reason: String?): Result<Unit> { override suspend fun redactEvent(eventId: EventId, reason: String?): Result<Unit> {
redactEventEventIdParam = eventId redactEventEventIdParam = eventId
delay(FAKE_DELAY_IN_MS)
return Result.success(Unit) return Result.success(Unit)
} }
override suspend fun leave(): Result<Unit> = leaveRoomError?.let { Result.failure(it) } ?: Result.success(Unit) override suspend fun leave(): Result<Unit> = leaveRoomError?.let { Result.failure(it) } ?: Result.success(Unit)
override suspend fun acceptInvitation(): Result<Unit> { override suspend fun acceptInvitation(): Result<Unit> {
isInviteAccepted = true isInviteAccepted = true
return acceptInviteResult return acceptInviteResult
@ -189,9 +185,9 @@ class FakeMatrixRoom(
return rejectInviteResult return rejectInviteResult
} }
override suspend fun inviteUserById(id: UserId): Result<Unit> { override suspend fun inviteUserById(id: UserId): Result<Unit> = simulateLongTask {
invitedUserId = id invitedUserId = id
return inviteUserResult inviteUserResult
} }
override suspend fun canInvite(): Result<Boolean> { override suspend fun canInvite(): Result<Boolean> {
@ -210,31 +206,30 @@ class FakeMatrixRoom(
override suspend fun sendFile(file: File, fileInfo: FileInfo): Result<Unit> = fakeSendMedia() override suspend fun sendFile(file: File, fileInfo: FileInfo): Result<Unit> = fakeSendMedia()
private suspend fun fakeSendMedia(): Result<Unit> { private suspend fun fakeSendMedia(): Result<Unit> = simulateLongTask {
delay(FAKE_DELAY_IN_MS) sendMediaResult.onSuccess {
return sendMediaResult.onSuccess {
sendMediaCount++ sendMediaCount++
} }
} }
override suspend fun updateAvatar(mimeType: String, data: ByteArray): Result<Unit> { override suspend fun updateAvatar(mimeType: String, data: ByteArray): Result<Unit> = simulateLongTask {
newAvatarData = data newAvatarData = data
return updateAvatarResult updateAvatarResult
} }
override suspend fun removeAvatar(): Result<Unit> { override suspend fun removeAvatar(): Result<Unit> = simulateLongTask {
removedAvatar = true removedAvatar = true
return removeAvatarResult removeAvatarResult
} }
override suspend fun setName(name: String): Result<Unit> { override suspend fun setName(name: String): Result<Unit> = simulateLongTask {
newName = name newName = name
return setNameResult setNameResult
} }
override suspend fun setTopic(topic: String): Result<Unit> { override suspend fun setTopic(topic: String): Result<Unit> = simulateLongTask {
newTopic = topic newTopic = topic
return setTopicResult setTopicResult
} }
override fun close() = Unit override fun close() = Unit

1
libraries/mediaupload/test/build.gradle.kts

@ -24,4 +24,5 @@ android {
dependencies { dependencies {
api(projects.libraries.mediaupload.api) api(projects.libraries.mediaupload.api)
implementation(projects.tests.testutils)
} }

5
libraries/mediaupload/test/src/main/kotlin/io/element/android/libraries/mediaupload/test/FakeMediaPreProcessor.kt

@ -20,6 +20,7 @@ import android.net.Uri
import io.element.android.libraries.matrix.api.media.FileInfo import io.element.android.libraries.matrix.api.media.FileInfo
import io.element.android.libraries.mediaupload.api.MediaPreProcessor import io.element.android.libraries.mediaupload.api.MediaPreProcessor
import io.element.android.libraries.mediaupload.api.MediaUploadInfo import io.element.android.libraries.mediaupload.api.MediaUploadInfo
import io.element.android.tests.testutils.simulateLongTask
import java.io.File import java.io.File
class FakeMediaPreProcessor : MediaPreProcessor { class FakeMediaPreProcessor : MediaPreProcessor {
@ -41,7 +42,9 @@ class FakeMediaPreProcessor : MediaPreProcessor {
mimeType: String, mimeType: String,
deleteOriginal: Boolean, deleteOriginal: Boolean,
compressIfPossible: Boolean compressIfPossible: Boolean
): Result<MediaUploadInfo> = result ): Result<MediaUploadInfo> = simulateLongTask {
result
}
fun givenResult(value: Result<MediaUploadInfo>) { fun givenResult(value: Result<MediaUploadInfo>) {
this.result = value this.result = value

2
samples/minimal/src/main/kotlin/io/element/android/samples/minimal/RoomListScreen.kt

@ -71,7 +71,7 @@ class RoomListScreen(
networkMonitor = NetworkMonitorImpl(context), networkMonitor = NetworkMonitorImpl(context),
snackbarDispatcher = SnackbarDispatcher(), snackbarDispatcher = SnackbarDispatcher(),
inviteStateDataSource = DefaultInviteStateDataSource(matrixClient, DefaultSeenInvitesStore(context), coroutineDispatchers), inviteStateDataSource = DefaultInviteStateDataSource(matrixClient, DefaultSeenInvitesStore(context), coroutineDispatchers),
leaveRoomPresenter = LeaveRoomPresenterImpl(matrixClient, RoomMembershipObserver() ,coroutineDispatchers) leaveRoomPresenter = LeaveRoomPresenterImpl(matrixClient, RoomMembershipObserver(), coroutineDispatchers)
) )
@Composable @Composable

28
tests/testutils/src/main/kotlin/io/element/android/tests/testutils/LongTask.kt

@ -0,0 +1,28 @@
/*
* Copyright (c) 2023 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.element.android.tests.testutils
import kotlinx.coroutines.delay
/**
* Workaround for https://github.com/cashapp/molecule/issues/249.
* This functions should be removed/deprecated right after we find a proper fix.
*/
suspend inline fun <T> simulateLongTask(lambda: () -> T): T {
delay(1)
return lambda()
}

15
tests/testutils/src/main/kotlin/io/element/android/tests/testutils/TestCoroutineDispatchers.kt

@ -31,19 +31,18 @@ import kotlinx.coroutines.test.UnconfinedTestDispatcher
* If false, use [StandardTestDispatcher] for all dispatchers. * If false, use [StandardTestDispatcher] for all dispatchers.
*/ */
fun TestScope.testCoroutineDispatchers( fun TestScope.testCoroutineDispatchers(
useUnconfinedTestDispatcher: Boolean = true, useUnconfinedTestDispatcher: Boolean = false,
): CoroutineDispatchers = when (useUnconfinedTestDispatcher) { ): CoroutineDispatchers = when (useUnconfinedTestDispatcher) {
false -> CoroutineDispatchers(
io = StandardTestDispatcher(testScheduler),
computation = StandardTestDispatcher(testScheduler),
main = StandardTestDispatcher(testScheduler),
diffUpdateDispatcher = StandardTestDispatcher(testScheduler),
)
true -> CoroutineDispatchers( true -> CoroutineDispatchers(
io = UnconfinedTestDispatcher(testScheduler), io = UnconfinedTestDispatcher(testScheduler),
computation = UnconfinedTestDispatcher(testScheduler), computation = UnconfinedTestDispatcher(testScheduler),
main = UnconfinedTestDispatcher(testScheduler), main = UnconfinedTestDispatcher(testScheduler),
diffUpdateDispatcher = UnconfinedTestDispatcher(testScheduler), diffUpdateDispatcher = UnconfinedTestDispatcher(testScheduler),
) )
false -> CoroutineDispatchers(
io = StandardTestDispatcher(testScheduler),
computation = StandardTestDispatcher(testScheduler),
main = StandardTestDispatcher(testScheduler),
diffUpdateDispatcher = StandardTestDispatcher(testScheduler),
)
} }

Loading…
Cancel
Save