Stronger lambda error (#4771)

* Make sure lambdaError() make the test fail in all circumstances.

* Fix existing errors on tests.

* Uniformize the way we are creating class under test.

* Cleanup

* Fix typo

* Fix failing test after rebase.
This commit is contained in:
Benoit Marty 2025-05-27 17:32:09 +02:00 committed by GitHub
parent c86154d120
commit cf17d93580
19 changed files with 289 additions and 279 deletions

View file

@ -30,7 +30,7 @@ import io.element.android.libraries.matrix.test.room.FakeBaseRoom
import io.element.android.libraries.matrix.test.room.FakeJoinedRoom import io.element.android.libraries.matrix.test.room.FakeJoinedRoom
import io.element.android.services.appnavstate.api.ActiveRoomsHolder import io.element.android.services.appnavstate.api.ActiveRoomsHolder
import io.element.android.services.appnavstate.test.FakeAppNavigationStateService import io.element.android.services.appnavstate.test.FakeAppNavigationStateService
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import org.junit.Rule import org.junit.Rule
import org.junit.Test import org.junit.Test
@ -98,19 +98,18 @@ class JoinedRoomLoadedFlowNodeTest {
} }
} }
private fun createJoinedRoomLoadedFlowNode( private fun TestScope.createJoinedRoomLoadedFlowNode(
plugins: List<Plugin>, plugins: List<Plugin>,
messagesEntryPoint: MessagesEntryPoint = FakeMessagesEntryPoint(), messagesEntryPoint: MessagesEntryPoint = FakeMessagesEntryPoint(),
roomDetailsEntryPoint: RoomDetailsEntryPoint = FakeRoomDetailsEntryPoint(), roomDetailsEntryPoint: RoomDetailsEntryPoint = FakeRoomDetailsEntryPoint(),
activeRoomsHolder: ActiveRoomsHolder = ActiveRoomsHolder(), activeRoomsHolder: ActiveRoomsHolder = ActiveRoomsHolder(),
coroutineScope: CoroutineScope,
) = JoinedRoomLoadedFlowNode( ) = JoinedRoomLoadedFlowNode(
buildContext = BuildContext.root(savedStateMap = null), buildContext = BuildContext.root(savedStateMap = null),
plugins = plugins, plugins = plugins,
messagesEntryPoint = messagesEntryPoint, messagesEntryPoint = messagesEntryPoint,
roomDetailsEntryPoint = roomDetailsEntryPoint, roomDetailsEntryPoint = roomDetailsEntryPoint,
appNavigationStateService = FakeAppNavigationStateService(), appNavigationStateService = FakeAppNavigationStateService(),
appCoroutineScope = coroutineScope, appCoroutineScope = this,
roomComponentFactory = FakeRoomComponentFactory(), roomComponentFactory = FakeRoomComponentFactory(),
matrixClient = FakeMatrixClient(), matrixClient = FakeMatrixClient(),
activeRoomsHolder = activeRoomsHolder, activeRoomsHolder = activeRoomsHolder,
@ -125,7 +124,6 @@ class JoinedRoomLoadedFlowNodeTest {
val roomFlowNode = createJoinedRoomLoadedFlowNode( val roomFlowNode = createJoinedRoomLoadedFlowNode(
plugins = listOf(inputs), plugins = listOf(inputs),
messagesEntryPoint = fakeMessagesEntryPoint, messagesEntryPoint = fakeMessagesEntryPoint,
coroutineScope = this
) )
// WHEN // WHEN
val roomFlowNodeTestHelper = roomFlowNode.parentNodeTestHelper() val roomFlowNodeTestHelper = roomFlowNode.parentNodeTestHelper()
@ -148,7 +146,6 @@ class JoinedRoomLoadedFlowNodeTest {
plugins = listOf(inputs), plugins = listOf(inputs),
messagesEntryPoint = fakeMessagesEntryPoint, messagesEntryPoint = fakeMessagesEntryPoint,
roomDetailsEntryPoint = fakeRoomDetailsEntryPoint, roomDetailsEntryPoint = fakeRoomDetailsEntryPoint,
coroutineScope = this
) )
val roomFlowNodeTestHelper = roomFlowNode.parentNodeTestHelper() val roomFlowNodeTestHelper = roomFlowNode.parentNodeTestHelper()
// WHEN // WHEN
@ -171,7 +168,6 @@ class JoinedRoomLoadedFlowNodeTest {
plugins = listOf(inputs), plugins = listOf(inputs),
messagesEntryPoint = fakeMessagesEntryPoint, messagesEntryPoint = fakeMessagesEntryPoint,
roomDetailsEntryPoint = fakeRoomDetailsEntryPoint, roomDetailsEntryPoint = fakeRoomDetailsEntryPoint,
coroutineScope = this,
activeRoomsHolder = activeRoomsHolder, activeRoomsHolder = activeRoomsHolder,
) )
@ -197,7 +193,6 @@ class JoinedRoomLoadedFlowNodeTest {
plugins = listOf(inputs), plugins = listOf(inputs),
messagesEntryPoint = fakeMessagesEntryPoint, messagesEntryPoint = fakeMessagesEntryPoint,
roomDetailsEntryPoint = fakeRoomDetailsEntryPoint, roomDetailsEntryPoint = fakeRoomDetailsEntryPoint,
coroutineScope = this,
activeRoomsHolder = activeRoomsHolder, activeRoomsHolder = activeRoomsHolder,
) )
val roomFlowNodeTestHelper = roomFlowNode.parentNodeTestHelper() val roomFlowNodeTestHelper = roomFlowNode.parentNodeTestHelper()

View file

@ -40,11 +40,7 @@ import io.element.android.tests.testutils.lambda.lambdaRecorder
import io.element.android.tests.testutils.lambda.value import io.element.android.tests.testutils.lambda.value
import io.mockk.mockk import io.mockk.mockk
import io.mockk.verify import io.mockk.verify
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.cancel
import kotlinx.coroutines.launch
import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.advanceTimeBy import kotlinx.coroutines.test.advanceTimeBy
import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runCurrent
@ -63,30 +59,28 @@ class DefaultActiveCallManagerTest {
fun `registerIncomingCall - sets the incoming call as active`() = runTest { fun `registerIncomingCall - sets the incoming call as active`() = runTest {
setupShadowPowerManager() setupShadowPowerManager()
val notificationManagerCompat = mockk<NotificationManagerCompat>(relaxed = true) val notificationManagerCompat = mockk<NotificationManagerCompat>(relaxed = true)
inCancellableScope { val manager = createActiveCallManager(notificationManagerCompat = notificationManagerCompat)
val manager = createActiveCallManager(notificationManagerCompat = notificationManagerCompat)
assertThat(manager.activeWakeLock?.isHeld).isFalse() assertThat(manager.activeWakeLock?.isHeld).isFalse()
assertThat(manager.activeCall.value).isNull() assertThat(manager.activeCall.value).isNull()
val callNotificationData = aCallNotificationData() val callNotificationData = aCallNotificationData()
manager.registerIncomingCall(callNotificationData) manager.registerIncomingCall(callNotificationData)
assertThat(manager.activeCall.value).isEqualTo( assertThat(manager.activeCall.value).isEqualTo(
ActiveCall( ActiveCall(
callType = CallType.RoomCall( callType = CallType.RoomCall(
sessionId = callNotificationData.sessionId, sessionId = callNotificationData.sessionId,
roomId = callNotificationData.roomId, roomId = callNotificationData.roomId,
), ),
callState = CallState.Ringing(callNotificationData) callState = CallState.Ringing(callNotificationData)
)
) )
)
runCurrent() runCurrent()
assertThat(manager.activeWakeLock?.isHeld).isTrue() assertThat(manager.activeWakeLock?.isHeld).isTrue()
verify { notificationManagerCompat.notify(notificationId, any()) } verify { notificationManagerCompat.notify(notificationId, any()) }
}
} }
@OptIn(ExperimentalCoroutinesApi::class) @OptIn(ExperimentalCoroutinesApi::class)
@ -94,42 +88,38 @@ class DefaultActiveCallManagerTest {
fun `registerIncomingCall - when there is an already active call adds missed call notification`() = runTest { fun `registerIncomingCall - when there is an already active call adds missed call notification`() = runTest {
val addMissedCallNotificationLambda = lambdaRecorder<SessionId, RoomId, EventId, Unit> { _, _, _ -> } val addMissedCallNotificationLambda = lambdaRecorder<SessionId, RoomId, EventId, Unit> { _, _, _ -> }
val onMissedCallNotificationHandler = FakeOnMissedCallNotificationHandler(addMissedCallNotificationLambda = addMissedCallNotificationLambda) val onMissedCallNotificationHandler = FakeOnMissedCallNotificationHandler(addMissedCallNotificationLambda = addMissedCallNotificationLambda)
inCancellableScope { val manager = createActiveCallManager(
val manager = createActiveCallManager( onMissedCallNotificationHandler = onMissedCallNotificationHandler,
onMissedCallNotificationHandler = onMissedCallNotificationHandler, )
)
// Register existing call // Register existing call
val callNotificationData = aCallNotificationData() val callNotificationData = aCallNotificationData()
manager.registerIncomingCall(callNotificationData) manager.registerIncomingCall(callNotificationData)
val activeCall = manager.activeCall.value val activeCall = manager.activeCall.value
// Now add a new call // Now add a new call
manager.registerIncomingCall(aCallNotificationData(roomId = A_ROOM_ID_2)) manager.registerIncomingCall(aCallNotificationData(roomId = A_ROOM_ID_2))
assertThat(manager.activeCall.value).isEqualTo(activeCall) assertThat(manager.activeCall.value).isEqualTo(activeCall)
assertThat((manager.activeCall.value?.callType as? CallType.RoomCall)?.roomId).isNotEqualTo(A_ROOM_ID_2) assertThat((manager.activeCall.value?.callType as? CallType.RoomCall)?.roomId).isNotEqualTo(A_ROOM_ID_2)
advanceTimeBy(1) advanceTimeBy(1)
addMissedCallNotificationLambda.assertions() addMissedCallNotificationLambda.assertions()
.isCalledOnce() .isCalledOnce()
.with(value(A_SESSION_ID), value(A_ROOM_ID_2), value(AN_EVENT_ID)) .with(value(A_SESSION_ID), value(A_ROOM_ID_2), value(AN_EVENT_ID))
}
} }
@Test @Test
fun `incomingCallTimedOut - when there isn't an active call does nothing`() = runTest { fun `incomingCallTimedOut - when there isn't an active call does nothing`() = runTest {
val addMissedCallNotificationLambda = lambdaRecorder<SessionId, RoomId, EventId, Unit> { _, _, _ -> } val addMissedCallNotificationLambda = lambdaRecorder<SessionId, RoomId, EventId, Unit> { _, _, _ -> }
inCancellableScope { val manager = createActiveCallManager(
val manager = createActiveCallManager( onMissedCallNotificationHandler = FakeOnMissedCallNotificationHandler(addMissedCallNotificationLambda = addMissedCallNotificationLambda)
onMissedCallNotificationHandler = FakeOnMissedCallNotificationHandler(addMissedCallNotificationLambda = addMissedCallNotificationLambda) )
)
manager.incomingCallTimedOut(displayMissedCallNotification = true) manager.incomingCallTimedOut(displayMissedCallNotification = true)
addMissedCallNotificationLambda.assertions().isNeverCalled() addMissedCallNotificationLambda.assertions().isNeverCalled()
}
} }
@OptIn(ExperimentalCoroutinesApi::class) @OptIn(ExperimentalCoroutinesApi::class)
@ -138,90 +128,80 @@ class DefaultActiveCallManagerTest {
setupShadowPowerManager() setupShadowPowerManager()
val notificationManagerCompat = mockk<NotificationManagerCompat>(relaxed = true) val notificationManagerCompat = mockk<NotificationManagerCompat>(relaxed = true)
val addMissedCallNotificationLambda = lambdaRecorder<SessionId, RoomId, EventId, Unit> { _, _, _ -> } val addMissedCallNotificationLambda = lambdaRecorder<SessionId, RoomId, EventId, Unit> { _, _, _ -> }
inCancellableScope { val manager = createActiveCallManager(
val manager = createActiveCallManager( onMissedCallNotificationHandler = FakeOnMissedCallNotificationHandler(addMissedCallNotificationLambda = addMissedCallNotificationLambda),
onMissedCallNotificationHandler = FakeOnMissedCallNotificationHandler(addMissedCallNotificationLambda = addMissedCallNotificationLambda), notificationManagerCompat = notificationManagerCompat,
notificationManagerCompat = notificationManagerCompat, )
)
manager.registerIncomingCall(aCallNotificationData()) manager.registerIncomingCall(aCallNotificationData())
assertThat(manager.activeCall.value).isNotNull() assertThat(manager.activeCall.value).isNotNull()
assertThat(manager.activeWakeLock?.isHeld).isTrue() assertThat(manager.activeWakeLock?.isHeld).isTrue()
manager.incomingCallTimedOut(displayMissedCallNotification = true) manager.incomingCallTimedOut(displayMissedCallNotification = true)
advanceTimeBy(1) advanceTimeBy(1)
assertThat(manager.activeCall.value).isNull() assertThat(manager.activeCall.value).isNull()
assertThat(manager.activeWakeLock?.isHeld).isFalse() assertThat(manager.activeWakeLock?.isHeld).isFalse()
addMissedCallNotificationLambda.assertions().isCalledOnce() addMissedCallNotificationLambda.assertions().isCalledOnce()
verify { notificationManagerCompat.cancel(notificationId) } verify { notificationManagerCompat.cancel(notificationId) }
}
} }
@Test @Test
fun `hungUpCall - removes existing call if the CallType matches`() = runTest { fun `hungUpCall - removes existing call if the CallType matches`() = runTest {
setupShadowPowerManager() setupShadowPowerManager()
val notificationManagerCompat = mockk<NotificationManagerCompat>(relaxed = true) val notificationManagerCompat = mockk<NotificationManagerCompat>(relaxed = true)
// Create a cancellable coroutine scope to cancel the test when needed val manager = createActiveCallManager(notificationManagerCompat = notificationManagerCompat)
inCancellableScope {
val manager = createActiveCallManager(notificationManagerCompat = notificationManagerCompat)
val notificationData = aCallNotificationData() val notificationData = aCallNotificationData()
manager.registerIncomingCall(notificationData) manager.registerIncomingCall(notificationData)
assertThat(manager.activeCall.value).isNotNull() assertThat(manager.activeCall.value).isNotNull()
assertThat(manager.activeWakeLock?.isHeld).isTrue() assertThat(manager.activeWakeLock?.isHeld).isTrue()
manager.hungUpCall(CallType.RoomCall(notificationData.sessionId, notificationData.roomId)) manager.hungUpCall(CallType.RoomCall(notificationData.sessionId, notificationData.roomId))
assertThat(manager.activeCall.value).isNull() assertThat(manager.activeCall.value).isNull()
assertThat(manager.activeWakeLock?.isHeld).isFalse() assertThat(manager.activeWakeLock?.isHeld).isFalse()
verify { notificationManagerCompat.cancel(notificationId) } verify { notificationManagerCompat.cancel(notificationId) }
}
} }
@Test @Test
fun `hungUpCall - does nothing if the CallType doesn't match`() = runTest { fun `hungUpCall - does nothing if the CallType doesn't match`() = runTest {
setupShadowPowerManager() setupShadowPowerManager()
val notificationManagerCompat = mockk<NotificationManagerCompat>(relaxed = true) val notificationManagerCompat = mockk<NotificationManagerCompat>(relaxed = true)
// Create a cancellable coroutine scope to cancel the test when needed val manager = createActiveCallManager(notificationManagerCompat = notificationManagerCompat)
inCancellableScope {
val manager = createActiveCallManager(notificationManagerCompat = notificationManagerCompat)
manager.registerIncomingCall(aCallNotificationData()) manager.registerIncomingCall(aCallNotificationData())
assertThat(manager.activeCall.value).isNotNull() assertThat(manager.activeCall.value).isNotNull()
assertThat(manager.activeWakeLock?.isHeld).isTrue() assertThat(manager.activeWakeLock?.isHeld).isTrue()
manager.hungUpCall(CallType.ExternalUrl("https://example.com")) manager.hungUpCall(CallType.ExternalUrl("https://example.com"))
assertThat(manager.activeCall.value).isNotNull() assertThat(manager.activeCall.value).isNotNull()
assertThat(manager.activeWakeLock?.isHeld).isTrue() assertThat(manager.activeWakeLock?.isHeld).isTrue()
verify(exactly = 0) { notificationManagerCompat.cancel(notificationId) } verify(exactly = 0) { notificationManagerCompat.cancel(notificationId) }
}
} }
@OptIn(ExperimentalCoroutinesApi::class) @OptIn(ExperimentalCoroutinesApi::class)
@Test @Test
fun `joinedCall - register an ongoing call and tries sending the call notify event`() = runTest { fun `joinedCall - register an ongoing call and tries sending the call notify event`() = runTest {
val notificationManagerCompat = mockk<NotificationManagerCompat>(relaxed = true) val notificationManagerCompat = mockk<NotificationManagerCompat>(relaxed = true)
inCancellableScope { val manager = createActiveCallManager(notificationManagerCompat = notificationManagerCompat)
val manager = createActiveCallManager(notificationManagerCompat = notificationManagerCompat) assertThat(manager.activeCall.value).isNull()
assertThat(manager.activeCall.value).isNull()
manager.joinedCall(CallType.RoomCall(A_SESSION_ID, A_ROOM_ID)) manager.joinedCall(CallType.RoomCall(A_SESSION_ID, A_ROOM_ID))
assertThat(manager.activeCall.value).isEqualTo( assertThat(manager.activeCall.value).isEqualTo(
ActiveCall( ActiveCall(
callType = CallType.RoomCall( callType = CallType.RoomCall(
sessionId = A_SESSION_ID, sessionId = A_SESSION_ID,
roomId = A_ROOM_ID, roomId = A_ROOM_ID,
), ),
callState = CallState.InCall, callState = CallState.InCall,
)
) )
)
runCurrent() runCurrent()
verify { notificationManagerCompat.cancel(notificationId) } verify { notificationManagerCompat.cancel(notificationId) }
}
} }
@OptIn(ExperimentalCoroutinesApi::class) @OptIn(ExperimentalCoroutinesApi::class)
@ -233,22 +213,19 @@ class DefaultActiveCallManagerTest {
val client = FakeMatrixClient().apply { val client = FakeMatrixClient().apply {
givenGetRoomResult(A_ROOM_ID, room) givenGetRoomResult(A_ROOM_ID, room)
} }
// Create a cancellable coroutine scope to cancel the test when needed val matrixClientProvider = FakeMatrixClientProvider(getClient = { Result.success(client) })
inCancellableScope { val manager = createActiveCallManager(matrixClientProvider = matrixClientProvider)
val matrixClientProvider = FakeMatrixClientProvider(getClient = { Result.success(client) })
val manager = createActiveCallManager(matrixClientProvider = matrixClientProvider)
manager.registerIncomingCall(aCallNotificationData()) manager.registerIncomingCall(aCallNotificationData())
// Call is active (the other user join the call) // Call is active (the other user join the call)
room.givenRoomInfo(aRoomInfo(hasRoomCall = true)) room.givenRoomInfo(aRoomInfo(hasRoomCall = true))
advanceTimeBy(1) advanceTimeBy(1)
// Call is cancelled (the other user left the call) // Call is cancelled (the other user left the call)
room.givenRoomInfo(aRoomInfo(hasRoomCall = false)) room.givenRoomInfo(aRoomInfo(hasRoomCall = false))
advanceTimeBy(1) advanceTimeBy(1)
assertThat(manager.activeCall.value).isNull() assertThat(manager.activeCall.value).isNull()
}
} }
@OptIn(ExperimentalCoroutinesApi::class) @OptIn(ExperimentalCoroutinesApi::class)
@ -260,44 +237,34 @@ class DefaultActiveCallManagerTest {
val client = FakeMatrixClient().apply { val client = FakeMatrixClient().apply {
givenGetRoomResult(A_ROOM_ID, room) givenGetRoomResult(A_ROOM_ID, room)
} }
// Create a cancellable coroutine scope to cancel the test when needed val matrixClientProvider = FakeMatrixClientProvider(getClient = { Result.failure(IllegalStateException("Matrix client not found")) })
inCancellableScope { val manager = createActiveCallManager(matrixClientProvider = matrixClientProvider)
val matrixClientProvider = FakeMatrixClientProvider(getClient = { Result.failure(IllegalStateException("Matrix client not found")) })
val manager = createActiveCallManager(matrixClientProvider = matrixClientProvider)
// No matrix client // No matrix client
manager.registerIncomingCall(aCallNotificationData()) manager.registerIncomingCall(aCallNotificationData())
room.givenRoomInfo(aRoomInfo(hasRoomCall = true)) room.givenRoomInfo(aRoomInfo(hasRoomCall = true))
advanceTimeBy(1) advanceTimeBy(1)
room.givenRoomInfo(aRoomInfo(hasRoomCall = false)) room.givenRoomInfo(aRoomInfo(hasRoomCall = false))
advanceTimeBy(1) advanceTimeBy(1)
// The call should still be active // The call should still be active
assertThat(manager.activeCall.value).isNotNull() assertThat(manager.activeCall.value).isNotNull()
// No room // No room
client.givenGetRoomResult(A_ROOM_ID, null) client.givenGetRoomResult(A_ROOM_ID, null)
matrixClientProvider.getClient = { Result.success(client) } matrixClientProvider.getClient = { Result.success(client) }
manager.registerIncomingCall(aCallNotificationData()) manager.registerIncomingCall(aCallNotificationData())
room.givenRoomInfo(aRoomInfo(hasRoomCall = true)) room.givenRoomInfo(aRoomInfo(hasRoomCall = true))
advanceTimeBy(1) advanceTimeBy(1)
room.givenRoomInfo(aRoomInfo(hasRoomCall = false)) room.givenRoomInfo(aRoomInfo(hasRoomCall = false))
advanceTimeBy(1) advanceTimeBy(1)
// The call should still be active // The call should still be active
assertThat(manager.activeCall.value).isNotNull() assertThat(manager.activeCall.value).isNotNull()
}
}
private fun TestScope.inCancellableScope(block: suspend CoroutineScope.() -> Unit) {
launch(SupervisorJob()) {
block()
cancel()
}
} }
private fun setupShadowPowerManager() { private fun setupShadowPowerManager() {
@ -306,14 +273,13 @@ class DefaultActiveCallManagerTest {
} }
} }
private fun CoroutineScope.createActiveCallManager( private fun TestScope.createActiveCallManager(
matrixClientProvider: FakeMatrixClientProvider = FakeMatrixClientProvider(), matrixClientProvider: FakeMatrixClientProvider = FakeMatrixClientProvider(),
onMissedCallNotificationHandler: FakeOnMissedCallNotificationHandler = FakeOnMissedCallNotificationHandler(), onMissedCallNotificationHandler: FakeOnMissedCallNotificationHandler = FakeOnMissedCallNotificationHandler(),
notificationManagerCompat: NotificationManagerCompat = mockk(relaxed = true), notificationManagerCompat: NotificationManagerCompat = mockk(relaxed = true),
coroutineScope: CoroutineScope = this,
) = DefaultActiveCallManager( ) = DefaultActiveCallManager(
context = InstrumentationRegistry.getInstrumentation().targetContext, context = InstrumentationRegistry.getInstrumentation().targetContext,
coroutineScope = coroutineScope, coroutineScope = backgroundScope,
onMissedCallNotificationHandler = onMissedCallNotificationHandler, onMissedCallNotificationHandler = onMissedCallNotificationHandler,
ringingCallNotificationCreator = RingingCallNotificationCreator( ringingCallNotificationCreator = RingingCallNotificationCreator(
context = InstrumentationRegistry.getInstrumentation().targetContext, context = InstrumentationRegistry.getInstrumentation().targetContext,

View file

@ -87,13 +87,19 @@ class DefaultCallWidgetProviderTest {
} }
val activeRoomsHolder = ActiveRoomsHolder().apply { val activeRoomsHolder = ActiveRoomsHolder().apply {
// A current active room with the same room id // A current active room with the same room id
addRoom(FakeJoinedRoom(baseRoom = FakeBaseRoom(roomId = A_ROOM_ID))) addRoom(
FakeJoinedRoom(
baseRoom = FakeBaseRoom(roomId = A_ROOM_ID),
generateWidgetWebViewUrlResult = { _, _, _, _ -> Result.success("url") },
getWidgetDriverResult = { Result.success(FakeMatrixWidgetDriver()) },
)
)
} }
val provider = createProvider( val provider = createProvider(
matrixClientProvider = FakeMatrixClientProvider { Result.success(client) }, matrixClientProvider = FakeMatrixClientProvider { Result.success(client) },
activeRoomsHolder = activeRoomsHolder activeRoomsHolder = activeRoomsHolder
) )
assertThat(provider.getWidget(A_SESSION_ID, A_ROOM_ID, "clientId", "languageTag", "theme").isFailure).isTrue() assertThat(provider.getWidget(A_SESSION_ID, A_ROOM_ID, "clientId", "languageTag", "theme").isSuccess).isTrue()
} }
@Test @Test

View file

@ -20,14 +20,14 @@ import io.element.android.features.lockscreen.impl.storage.LockScreenStore
import io.element.android.tests.testutils.awaitLastSequentialItem import io.element.android.tests.testutils.awaitLastSequentialItem
import io.element.android.tests.testutils.consumeItemsUntilPredicate import io.element.android.tests.testutils.consumeItemsUntilPredicate
import io.element.android.tests.testutils.test import io.element.android.tests.testutils.test
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import org.junit.Test import org.junit.Test
class LockScreenSettingsPresenterTest { class LockScreenSettingsPresenterTest {
@Test @Test
fun `present - remove pin option is hidden when mandatory`() = runTest { fun `present - remove pin option is hidden when mandatory`() = runTest {
val presenter = createLockScreenSettingsPresenter(this, lockScreenConfig = aLockScreenConfig(isPinMandatory = true)) val presenter = createLockScreenSettingsPresenter(lockScreenConfig = aLockScreenConfig(isPinMandatory = true))
presenter.test { presenter.test {
awaitItem().also { state -> awaitItem().also { state ->
assertThat(state.showRemovePinOption).isFalse() assertThat(state.showRemovePinOption).isFalse()
@ -37,7 +37,7 @@ class LockScreenSettingsPresenterTest {
@Test @Test
fun `present - remove pin flow`() = runTest { fun `present - remove pin flow`() = runTest {
val presenter = createLockScreenSettingsPresenter(this) val presenter = createLockScreenSettingsPresenter()
presenter.test { presenter.test {
consumeItemsUntilPredicate { state -> consumeItemsUntilPredicate { state ->
state.showRemovePinOption state.showRemovePinOption
@ -71,7 +71,6 @@ class LockScreenSettingsPresenterTest {
isDeviceSecured = true, isDeviceSecured = true,
) )
val presenter = createLockScreenSettingsPresenter( val presenter = createLockScreenSettingsPresenter(
coroutineScope = this,
biometricAuthenticatorManager = fakeBiometricAuthenticatorManager biometricAuthenticatorManager = fakeBiometricAuthenticatorManager
) )
presenter.test { presenter.test {
@ -88,7 +87,6 @@ class LockScreenSettingsPresenterTest {
} }
) )
val presenter = createLockScreenSettingsPresenter( val presenter = createLockScreenSettingsPresenter(
coroutineScope = this,
biometricAuthenticatorManager = fakeBiometricAuthenticatorManager biometricAuthenticatorManager = fakeBiometricAuthenticatorManager
) )
presenter.test { presenter.test {
@ -110,7 +108,6 @@ class LockScreenSettingsPresenterTest {
} }
) )
val presenter = createLockScreenSettingsPresenter( val presenter = createLockScreenSettingsPresenter(
coroutineScope = this,
biometricAuthenticatorManager = fakeBiometricAuthenticatorManager biometricAuthenticatorManager = fakeBiometricAuthenticatorManager
) )
presenter.test { presenter.test {
@ -130,7 +127,6 @@ class LockScreenSettingsPresenterTest {
) )
val lockScreenStore = InMemoryLockScreenStore() val lockScreenStore = InMemoryLockScreenStore()
val presenter = createLockScreenSettingsPresenter( val presenter = createLockScreenSettingsPresenter(
coroutineScope = this,
lockScreenStore = lockScreenStore, lockScreenStore = lockScreenStore,
biometricAuthenticatorManager = fakeBiometricAuthenticatorManager biometricAuthenticatorManager = fakeBiometricAuthenticatorManager
) )
@ -148,8 +144,7 @@ class LockScreenSettingsPresenterTest {
} }
} }
private suspend fun createLockScreenSettingsPresenter( private suspend fun TestScope.createLockScreenSettingsPresenter(
coroutineScope: CoroutineScope,
lockScreenConfig: LockScreenConfig = aLockScreenConfig(), lockScreenConfig: LockScreenConfig = aLockScreenConfig(),
biometricAuthenticatorManager: BiometricAuthenticatorManager = FakeBiometricAuthenticatorManager(), biometricAuthenticatorManager: BiometricAuthenticatorManager = FakeBiometricAuthenticatorManager(),
lockScreenStore: LockScreenStore = InMemoryLockScreenStore(), lockScreenStore: LockScreenStore = InMemoryLockScreenStore(),
@ -160,7 +155,7 @@ class LockScreenSettingsPresenterTest {
return LockScreenSettingsPresenter( return LockScreenSettingsPresenter(
lockScreenStore = lockScreenStore, lockScreenStore = lockScreenStore,
pinCodeManager = pinCodeManager, pinCodeManager = pinCodeManager,
coroutineScope = coroutineScope, coroutineScope = this,
lockScreenConfig = lockScreenConfig, lockScreenConfig = lockScreenConfig,
biometricAuthenticatorManager = biometricAuthenticatorManager, biometricAuthenticatorManager = biometricAuthenticatorManager,
) )

View file

@ -24,7 +24,7 @@ import io.element.android.libraries.architecture.AsyncAction
import io.element.android.libraries.architecture.AsyncData import io.element.android.libraries.architecture.AsyncData
import io.element.android.tests.testutils.lambda.assert import io.element.android.tests.testutils.lambda.assert
import io.element.android.tests.testutils.lambda.lambdaRecorder import io.element.android.tests.testutils.lambda.lambdaRecorder
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import org.junit.Test import org.junit.Test
@ -34,7 +34,7 @@ class PinUnlockPresenterTest {
@Test @Test
fun `present - success verify flow`() = runTest { fun `present - success verify flow`() = runTest {
val presenter = createPinUnlockPresenter(this) val presenter = createPinUnlockPresenter()
moleculeFlow(RecompositionMode.Immediate) { moleculeFlow(RecompositionMode.Immediate) {
presenter.present() presenter.present()
}.test { }.test {
@ -71,7 +71,7 @@ class PinUnlockPresenterTest {
@Test @Test
fun `present - failure verify flow`() = runTest { fun `present - failure verify flow`() = runTest {
val presenter = createPinUnlockPresenter(this) val presenter = createPinUnlockPresenter()
moleculeFlow(RecompositionMode.Immediate) { moleculeFlow(RecompositionMode.Immediate) {
presenter.present() presenter.present()
}.test { }.test {
@ -100,7 +100,7 @@ class PinUnlockPresenterTest {
fun `present - forgot pin flow`() = runTest { fun `present - forgot pin flow`() = runTest {
val signOutLambda = lambdaRecorder<Boolean, Unit> {} val signOutLambda = lambdaRecorder<Boolean, Unit> {}
val signOut = FakeLogoutUseCase(signOutLambda) val signOut = FakeLogoutUseCase(signOutLambda)
val presenter = createPinUnlockPresenter(this, logoutUseCase = signOut) val presenter = createPinUnlockPresenter(logoutUseCase = signOut)
moleculeFlow(RecompositionMode.Immediate) { moleculeFlow(RecompositionMode.Immediate) {
presenter.present() presenter.present()
}.test { }.test {
@ -135,8 +135,7 @@ class PinUnlockPresenterTest {
dataOrNull()?.assertText(text) dataOrNull()?.assertText(text)
} }
private suspend fun createPinUnlockPresenter( private suspend fun TestScope.createPinUnlockPresenter(
scope: CoroutineScope,
biometricAuthenticatorManager: BiometricAuthenticatorManager = FakeBiometricAuthenticatorManager(), biometricAuthenticatorManager: BiometricAuthenticatorManager = FakeBiometricAuthenticatorManager(),
callback: PinCodeManager.Callback = DefaultPinCodeManagerCallback(), callback: PinCodeManager.Callback = DefaultPinCodeManagerCallback(),
logoutUseCase: FakeLogoutUseCase = FakeLogoutUseCase(logoutLambda = { "" }), logoutUseCase: FakeLogoutUseCase = FakeLogoutUseCase(logoutLambda = { "" }),
@ -149,7 +148,7 @@ class PinUnlockPresenterTest {
pinCodeManager = pinCodeManager, pinCodeManager = pinCodeManager,
biometricAuthenticatorManager = biometricAuthenticatorManager, biometricAuthenticatorManager = biometricAuthenticatorManager,
logoutUseCase = logoutUseCase, logoutUseCase = logoutUseCase,
coroutineScope = scope, coroutineScope = this,
pinUnlockHelper = PinUnlockHelper(biometricAuthenticatorManager, pinCodeManager), pinUnlockHelper = PinUnlockHelper(biometricAuthenticatorManager, pinCodeManager),
) )
} }

View file

@ -513,7 +513,17 @@ class AttachmentsPreviewPresenterTest {
@Test @Test
fun `present - dismissing the progress dialog stops media upload with media queue`() = runTest { fun `present - dismissing the progress dialog stops media upload with media queue`() = runTest {
val onDoneListenerResult = lambdaRecorder<Unit> {} val onDoneListenerResult = lambdaRecorder<Unit> {}
val presenter = createAttachmentsPreviewPresenter(mediaUploadOnSendQueueEnabled = true, onDoneListener = onDoneListenerResult) val presenter = createAttachmentsPreviewPresenter(
room = FakeJoinedRoom(
liveTimeline = FakeTimeline().apply {
sendFileLambda = { _, _, _, _, _, _ ->
Result.success(FakeMediaUploadHandler())
}
}
),
mediaUploadOnSendQueueEnabled = true,
onDoneListener = onDoneListenerResult,
)
moleculeFlow(RecompositionMode.Immediate) { moleculeFlow(RecompositionMode.Immediate) {
presenter.present() presenter.present()
}.test { }.test {

View file

@ -21,7 +21,7 @@ import io.element.android.libraries.matrix.test.timeline.FakeTimeline
import io.element.android.libraries.matrix.test.timeline.LiveTimelineProvider import io.element.android.libraries.matrix.test.timeline.LiveTimelineProvider
import io.element.android.tests.testutils.WarmUpRule import io.element.android.tests.testutils.WarmUpRule
import io.element.android.tests.testutils.lambda.lambdaRecorder import io.element.android.tests.testutils.lambda.lambdaRecorder
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import org.junit.Rule import org.junit.Rule
import org.junit.Test import org.junit.Test
@ -91,13 +91,12 @@ class ForwardMessagesPresenterTest {
} }
} }
private fun CoroutineScope.aForwardMessagesPresenter( private fun TestScope.aForwardMessagesPresenter(
eventId: EventId = AN_EVENT_ID, eventId: EventId = AN_EVENT_ID,
fakeRoom: FakeJoinedRoom = FakeJoinedRoom(), fakeRoom: FakeJoinedRoom = FakeJoinedRoom(),
coroutineScope: CoroutineScope = this,
) = ForwardMessagesPresenter( ) = ForwardMessagesPresenter(
eventId = eventId.value, eventId = eventId.value,
timelineProvider = LiveTimelineProvider(fakeRoom), timelineProvider = LiveTimelineProvider(fakeRoom),
appCoroutineScope = coroutineScope, appCoroutineScope = this,
) )
} }

View file

@ -63,6 +63,7 @@ import io.element.android.libraries.matrix.test.A_USER_ID
import io.element.android.libraries.matrix.test.A_USER_ID_2 import io.element.android.libraries.matrix.test.A_USER_ID_2
import io.element.android.libraries.matrix.test.A_USER_ID_3 import io.element.android.libraries.matrix.test.A_USER_ID_3
import io.element.android.libraries.matrix.test.A_USER_ID_4 import io.element.android.libraries.matrix.test.A_USER_ID_4
import io.element.android.libraries.matrix.test.media.FakeMediaUploadHandler
import io.element.android.libraries.matrix.test.permalink.FakePermalinkBuilder import io.element.android.libraries.matrix.test.permalink.FakePermalinkBuilder
import io.element.android.libraries.matrix.test.permalink.FakePermalinkParser import io.element.android.libraries.matrix.test.permalink.FakePermalinkParser
import io.element.android.libraries.matrix.test.room.FakeBaseRoom import io.element.android.libraries.matrix.test.room.FakeBaseRoom
@ -101,8 +102,8 @@ import io.element.android.tests.testutils.waitForPredicate
import io.mockk.mockk import io.mockk.mockk
import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.persistentListOf
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.advanceUntilIdle import kotlinx.coroutines.test.advanceUntilIdle
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import org.junit.Rule import org.junit.Rule
@ -132,7 +133,7 @@ class MessageComposerPresenterTest {
@Test @Test
fun `present - initial state`() = runTest { fun `present - initial state`() = runTest {
val presenter = createPresenter(this) val presenter = createPresenter()
moleculeFlow(RecompositionMode.Immediate) { moleculeFlow(RecompositionMode.Immediate) {
presenter.present() presenter.present()
}.test { }.test {
@ -147,7 +148,7 @@ class MessageComposerPresenterTest {
@Test @Test
fun `present - toggle fullscreen`() = runTest { fun `present - toggle fullscreen`() = runTest {
val presenter = createPresenter(this) val presenter = createPresenter()
moleculeFlow(RecompositionMode.Immediate) { moleculeFlow(RecompositionMode.Immediate) {
presenter.present() presenter.present()
}.test { }.test {
@ -163,7 +164,7 @@ class MessageComposerPresenterTest {
@Test @Test
fun `present - change message`() = runTest { fun `present - change message`() = runTest {
val presenter = createPresenter(this) val presenter = createPresenter()
moleculeFlow(RecompositionMode.Immediate) { moleculeFlow(RecompositionMode.Immediate) {
presenter.present() presenter.present()
}.test { }.test {
@ -186,7 +187,6 @@ class MessageComposerPresenterTest {
this.saveDraftLambda = updateDraftLambda this.saveDraftLambda = updateDraftLambda
} }
val presenter = createPresenter( val presenter = createPresenter(
coroutineScope = this,
draftService = draftService, draftService = draftService,
) )
moleculeFlow(RecompositionMode.Immediate) { moleculeFlow(RecompositionMode.Immediate) {
@ -229,7 +229,6 @@ class MessageComposerPresenterTest {
this.saveDraftLambda = updateDraftLambda this.saveDraftLambda = updateDraftLambda
} }
val presenter = createPresenter( val presenter = createPresenter(
coroutineScope = this,
draftService = draftService, draftService = draftService,
) )
moleculeFlow(RecompositionMode.Immediate) { moleculeFlow(RecompositionMode.Immediate) {
@ -273,7 +272,6 @@ class MessageComposerPresenterTest {
typingNoticeResult = { Result.success(Unit) } typingNoticeResult = { Result.success(Unit) }
) )
val presenter = createPresenter( val presenter = createPresenter(
coroutineScope = this,
room = joinedRoom, room = joinedRoom,
isRichTextEditorEnabled = false, isRichTextEditorEnabled = false,
) )
@ -314,7 +312,6 @@ class MessageComposerPresenterTest {
this.saveDraftLambda = updateDraftLambda this.saveDraftLambda = updateDraftLambda
} }
val presenter = createPresenter( val presenter = createPresenter(
coroutineScope = this,
draftService = draftService, draftService = draftService,
) )
moleculeFlow(RecompositionMode.Immediate) { moleculeFlow(RecompositionMode.Immediate) {
@ -346,7 +343,7 @@ class MessageComposerPresenterTest {
@Test @Test
fun `present - change mode to reply`() = runTest { fun `present - change mode to reply`() = runTest {
val presenter = createPresenter(this) val presenter = createPresenter()
moleculeFlow(RecompositionMode.Immediate) { moleculeFlow(RecompositionMode.Immediate) {
presenter.present() presenter.present()
}.test { }.test {
@ -362,7 +359,7 @@ class MessageComposerPresenterTest {
@Test @Test
fun `present - cancel reply`() = runTest { fun `present - cancel reply`() = runTest {
val presenter = createPresenter(this) val presenter = createPresenter()
moleculeFlow(RecompositionMode.Immediate) { moleculeFlow(RecompositionMode.Immediate) {
presenter.present() presenter.present()
}.test { }.test {
@ -382,7 +379,6 @@ class MessageComposerPresenterTest {
@Test @Test
fun `present - send message with rich text enabled`() = runTest { fun `present - send message with rich text enabled`() = runTest {
val presenter = createPresenter( val presenter = createPresenter(
coroutineScope = this,
room = FakeJoinedRoom( room = FakeJoinedRoom(
liveTimeline = FakeTimeline().apply { liveTimeline = FakeTimeline().apply {
sendMessageLambda = { _, _, _ -> Result.success(Unit) } sendMessageLambda = { _, _, _ -> Result.success(Unit) }
@ -417,7 +413,6 @@ class MessageComposerPresenterTest {
fun `present - send message with plain text enabled`() = runTest { fun `present - send message with plain text enabled`() = runTest {
val permalinkBuilder = FakePermalinkBuilder(permalinkForUserLambda = { Result.success("") }) val permalinkBuilder = FakePermalinkBuilder(permalinkForUserLambda = { Result.success("") })
val presenter = createPresenter( val presenter = createPresenter(
coroutineScope = this,
isRichTextEditorEnabled = false, isRichTextEditorEnabled = false,
room = FakeJoinedRoom( room = FakeJoinedRoom(
liveTimeline = FakeTimeline().apply { liveTimeline = FakeTimeline().apply {
@ -464,7 +459,6 @@ class MessageComposerPresenterTest {
typingNoticeResult = { Result.success(Unit) } typingNoticeResult = { Result.success(Unit) }
) )
val presenter = createPresenter( val presenter = createPresenter(
this,
joinedRoom, joinedRoom,
) )
moleculeFlow(RecompositionMode.Immediate) { moleculeFlow(RecompositionMode.Immediate) {
@ -520,7 +514,6 @@ class MessageComposerPresenterTest {
editMessageLambda = roomEditMessageLambda, editMessageLambda = roomEditMessageLambda,
) )
val presenter = createPresenter( val presenter = createPresenter(
this,
joinedRoom, joinedRoom,
) )
moleculeFlow(RecompositionMode.Immediate) { moleculeFlow(RecompositionMode.Immediate) {
@ -576,7 +569,6 @@ class MessageComposerPresenterTest {
typingNoticeResult = { Result.success(Unit) }, typingNoticeResult = { Result.success(Unit) },
) )
val presenter = createPresenter( val presenter = createPresenter(
this,
joinedRoom, joinedRoom,
) )
moleculeFlow(RecompositionMode.Immediate) { moleculeFlow(RecompositionMode.Immediate) {
@ -628,7 +620,6 @@ class MessageComposerPresenterTest {
typingNoticeResult = { Result.success(Unit) } typingNoticeResult = { Result.success(Unit) }
) )
val presenter = createPresenter( val presenter = createPresenter(
this,
joinedRoom, joinedRoom,
) )
moleculeFlow(RecompositionMode.Immediate) { moleculeFlow(RecompositionMode.Immediate) {
@ -666,7 +657,7 @@ class MessageComposerPresenterTest {
@Test @Test
fun `present - Open attachments menu`() = runTest { fun `present - Open attachments menu`() = runTest {
val presenter = createPresenter(this) val presenter = createPresenter()
moleculeFlow(RecompositionMode.Immediate) { moleculeFlow(RecompositionMode.Immediate) {
presenter.present() presenter.present()
}.test { }.test {
@ -679,7 +670,7 @@ class MessageComposerPresenterTest {
@Test @Test
fun `present - Dismiss attachments menu`() = runTest { fun `present - Dismiss attachments menu`() = runTest {
val presenter = createPresenter(this) val presenter = createPresenter()
moleculeFlow(RecompositionMode.Immediate) { moleculeFlow(RecompositionMode.Immediate) {
presenter.present() presenter.present()
}.test { }.test {
@ -702,7 +693,6 @@ class MessageComposerPresenterTest {
onPreviewAttachmentLambda = onPreviewAttachmentLambda onPreviewAttachmentLambda = onPreviewAttachmentLambda
) )
val presenter = createPresenter( val presenter = createPresenter(
coroutineScope = this,
room = room, room = room,
navigator = navigator, navigator = navigator,
) )
@ -743,7 +733,6 @@ class MessageComposerPresenterTest {
onPreviewAttachmentLambda = onPreviewAttachmentLambda onPreviewAttachmentLambda = onPreviewAttachmentLambda
) )
val presenter = createPresenter( val presenter = createPresenter(
coroutineScope = this,
room = room, room = room,
navigator = navigator, navigator = navigator,
) )
@ -777,7 +766,7 @@ class MessageComposerPresenterTest {
@Test @Test
fun `present - Pick media from gallery & cancel does nothing`() = runTest { fun `present - Pick media from gallery & cancel does nothing`() = runTest {
val presenter = createPresenter(this) val presenter = createPresenter()
with(pickerProvider) { with(pickerProvider) {
givenResult(null) // Simulate a user canceling the flow givenResult(null) // Simulate a user canceling the flow
givenMimeType(MimeTypes.Images) givenMimeType(MimeTypes.Images)
@ -801,7 +790,6 @@ class MessageComposerPresenterTest {
onPreviewAttachmentLambda = onPreviewAttachmentLambda onPreviewAttachmentLambda = onPreviewAttachmentLambda
) )
val presenter = createPresenter( val presenter = createPresenter(
coroutineScope = this,
room = room, room = room,
navigator = navigator, navigator = navigator,
) )
@ -819,7 +807,7 @@ class MessageComposerPresenterTest {
val room = FakeJoinedRoom( val room = FakeJoinedRoom(
typingNoticeResult = { Result.success(Unit) } typingNoticeResult = { Result.success(Unit) }
) )
val presenter = createPresenter(this, room = room) val presenter = createPresenter(room = room)
moleculeFlow(RecompositionMode.Immediate) { moleculeFlow(RecompositionMode.Immediate) {
presenter.present() presenter.present()
}.test { }.test {
@ -838,7 +826,7 @@ class MessageComposerPresenterTest {
val room = FakeJoinedRoom( val room = FakeJoinedRoom(
typingNoticeResult = { Result.success(Unit) } typingNoticeResult = { Result.success(Unit) }
) )
val presenter = createPresenter(this, room = room) val presenter = createPresenter(room = room)
moleculeFlow(RecompositionMode.Immediate) { moleculeFlow(RecompositionMode.Immediate) {
presenter.present() presenter.present()
}.test { }.test {
@ -863,7 +851,6 @@ class MessageComposerPresenterTest {
onPreviewAttachmentLambda = onPreviewAttachmentLambda onPreviewAttachmentLambda = onPreviewAttachmentLambda
) )
val presenter = createPresenter( val presenter = createPresenter(
coroutineScope = this,
room = room, room = room,
permissionPresenter = permissionPresenter, permissionPresenter = permissionPresenter,
navigator = navigator, navigator = navigator,
@ -888,7 +875,6 @@ class MessageComposerPresenterTest {
onPreviewAttachmentLambda = onPreviewAttachmentLambda onPreviewAttachmentLambda = onPreviewAttachmentLambda
) )
val presenter = createPresenter( val presenter = createPresenter(
coroutineScope = this,
room = room, room = room,
permissionPresenter = permissionPresenter, permissionPresenter = permissionPresenter,
navigator = navigator, navigator = navigator,
@ -915,7 +901,6 @@ class MessageComposerPresenterTest {
onPreviewAttachmentLambda = onPreviewAttachmentLambda onPreviewAttachmentLambda = onPreviewAttachmentLambda
) )
val presenter = createPresenter( val presenter = createPresenter(
coroutineScope = this,
room = room, room = room,
permissionPresenter = permissionPresenter, permissionPresenter = permissionPresenter,
navigator = navigator, navigator = navigator,
@ -940,7 +925,6 @@ class MessageComposerPresenterTest {
onPreviewAttachmentLambda = onPreviewAttachmentLambda onPreviewAttachmentLambda = onPreviewAttachmentLambda
) )
val presenter = createPresenter( val presenter = createPresenter(
coroutineScope = this,
room = room, room = room,
permissionPresenter = permissionPresenter, permissionPresenter = permissionPresenter,
navigator = navigator, navigator = navigator,
@ -961,7 +945,7 @@ class MessageComposerPresenterTest {
@Test @Test
fun `present - errors are tracked`() = runTest { fun `present - errors are tracked`() = runTest {
val testException = Exception("Test error") val testException = Exception("Test error")
val presenter = createPresenter(this) val presenter = createPresenter()
moleculeFlow(RecompositionMode.Immediate) { moleculeFlow(RecompositionMode.Immediate) {
presenter.present() presenter.present()
}.test { }.test {
@ -973,7 +957,7 @@ class MessageComposerPresenterTest {
@Test @Test
fun `present - ToggleTextFormatting toggles text formatting`() = runTest { fun `present - ToggleTextFormatting toggles text formatting`() = runTest {
val presenter = createPresenter(this, isRichTextEditorEnabled = false) val presenter = createPresenter(isRichTextEditorEnabled = false)
moleculeFlow(RecompositionMode.Immediate) { moleculeFlow(RecompositionMode.Immediate) {
presenter.present() presenter.present()
}.test { }.test {
@ -1017,7 +1001,7 @@ class MessageComposerPresenterTest {
) )
givenRoomInfo(aRoomInfo(isDirect = false)) givenRoomInfo(aRoomInfo(isDirect = false))
} }
val presenter = createPresenter(this, room) val presenter = createPresenter(room)
moleculeFlow(RecompositionMode.Immediate) { moleculeFlow(RecompositionMode.Immediate) {
presenter.present() presenter.present()
}.test { }.test {
@ -1078,7 +1062,7 @@ class MessageComposerPresenterTest {
) )
) )
} }
val presenter = createPresenter(this, room) val presenter = createPresenter(room)
moleculeFlow(RecompositionMode.Immediate) { moleculeFlow(RecompositionMode.Immediate) {
presenter.present() presenter.present()
}.test { }.test {
@ -1094,7 +1078,6 @@ class MessageComposerPresenterTest {
fun `present - InsertSuggestion`() = runTest { fun `present - InsertSuggestion`() = runTest {
val presenter = createPresenter( val presenter = createPresenter(
coroutineScope = this,
permalinkBuilder = FakePermalinkBuilder( permalinkBuilder = FakePermalinkBuilder(
permalinkForUserLambda = { permalinkForUserLambda = {
Result.success("https://matrix.to/#/${A_USER_ID_2.value}") Result.success("https://matrix.to/#/${A_USER_ID_2.value}")
@ -1134,7 +1117,7 @@ class MessageComposerPresenterTest {
liveTimeline = timeline, liveTimeline = timeline,
typingNoticeResult = { Result.success(Unit) } typingNoticeResult = { Result.success(Unit) }
) )
val presenter = createPresenter(room = room, coroutineScope = this) val presenter = createPresenter(room = room)
moleculeFlow(RecompositionMode.Immediate) { moleculeFlow(RecompositionMode.Immediate) {
presenter.present() presenter.present()
}.test { }.test {
@ -1197,7 +1180,16 @@ class MessageComposerPresenterTest {
@Test @Test
fun `present - send uri`() = runTest { fun `present - send uri`() = runTest {
val presenter = createPresenter(this) val presenter = createPresenter(
room = FakeJoinedRoom(
typingNoticeResult = { Result.success(Unit) },
liveTimeline = FakeTimeline().apply {
sendFileLambda = { _, _, _, _, _, _ ->
Result.success(FakeMediaUploadHandler())
}
}
),
)
moleculeFlow(RecompositionMode.Immediate) { moleculeFlow(RecompositionMode.Immediate) {
val state = presenter.present() val state = presenter.present()
remember(state, state.textEditorState.messageHtml()) { state } remember(state, state.textEditorState.messageHtml()) { state }
@ -1214,7 +1206,7 @@ class MessageComposerPresenterTest {
val room = FakeJoinedRoom( val room = FakeJoinedRoom(
typingNoticeResult = typingNoticeResult, typingNoticeResult = typingNoticeResult,
) )
val presenter = createPresenter(room = room, coroutineScope = this) val presenter = createPresenter(room = room)
moleculeFlow(RecompositionMode.Immediate) { moleculeFlow(RecompositionMode.Immediate) {
presenter.present() presenter.present()
}.test { }.test {
@ -1240,7 +1232,7 @@ class MessageComposerPresenterTest {
val store = InMemorySessionPreferencesStore( val store = InMemorySessionPreferencesStore(
isSendTypingNotificationsEnabled = false isSendTypingNotificationsEnabled = false
) )
val presenter = createPresenter(room = room, sessionPreferencesStore = store, coroutineScope = this) val presenter = createPresenter(room = room, sessionPreferencesStore = store)
moleculeFlow(RecompositionMode.Immediate) { moleculeFlow(RecompositionMode.Immediate) {
presenter.present() presenter.present()
}.test { }.test {
@ -1258,7 +1250,7 @@ class MessageComposerPresenterTest {
val composerDraftService = FakeComposerDraftService().apply { val composerDraftService = FakeComposerDraftService().apply {
this.loadDraftLambda = loadDraftLambda this.loadDraftLambda = loadDraftLambda
} }
val presenter = createPresenter(draftService = composerDraftService, coroutineScope = this) val presenter = createPresenter(draftService = composerDraftService)
moleculeFlow(RecompositionMode.Immediate) { moleculeFlow(RecompositionMode.Immediate) {
presenter.present() presenter.present()
}.test { }.test {
@ -1283,7 +1275,6 @@ class MessageComposerPresenterTest {
val presenter = createPresenter( val presenter = createPresenter(
draftService = composerDraftService, draftService = composerDraftService,
permalinkBuilder = permalinkBuilder, permalinkBuilder = permalinkBuilder,
coroutineScope = this
) )
moleculeFlow(RecompositionMode.Immediate) { moleculeFlow(RecompositionMode.Immediate) {
presenter.present() presenter.present()
@ -1317,7 +1308,6 @@ class MessageComposerPresenterTest {
val presenter = createPresenter( val presenter = createPresenter(
draftService = composerDraftService, draftService = composerDraftService,
permalinkBuilder = permalinkBuilder, permalinkBuilder = permalinkBuilder,
coroutineScope = this
) )
moleculeFlow(RecompositionMode.Immediate) { moleculeFlow(RecompositionMode.Immediate) {
presenter.present() presenter.present()
@ -1351,7 +1341,6 @@ class MessageComposerPresenterTest {
val presenter = createPresenter( val presenter = createPresenter(
draftService = composerDraftService, draftService = composerDraftService,
permalinkBuilder = permalinkBuilder, permalinkBuilder = permalinkBuilder,
coroutineScope = this
) )
moleculeFlow(RecompositionMode.Immediate) { moleculeFlow(RecompositionMode.Immediate) {
presenter.present() presenter.present()
@ -1398,7 +1387,6 @@ class MessageComposerPresenterTest {
room = room, room = room,
draftService = composerDraftService, draftService = composerDraftService,
permalinkBuilder = permalinkBuilder, permalinkBuilder = permalinkBuilder,
coroutineScope = this
) )
moleculeFlow(RecompositionMode.Immediate) { moleculeFlow(RecompositionMode.Immediate) {
presenter.present() presenter.present()
@ -1428,7 +1416,7 @@ class MessageComposerPresenterTest {
val composerDraftService = FakeComposerDraftService().apply { val composerDraftService = FakeComposerDraftService().apply {
this.saveDraftLambda = saveDraftLambda this.saveDraftLambda = saveDraftLambda
} }
val presenter = createPresenter(draftService = composerDraftService, coroutineScope = this) val presenter = createPresenter(draftService = composerDraftService)
moleculeFlow(RecompositionMode.Immediate) { moleculeFlow(RecompositionMode.Immediate) {
presenter.present() presenter.present()
}.test { }.test {
@ -1452,7 +1440,6 @@ class MessageComposerPresenterTest {
isRichTextEditorEnabled = false, isRichTextEditorEnabled = false,
draftService = composerDraftService, draftService = composerDraftService,
permalinkBuilder = permalinkBuilder, permalinkBuilder = permalinkBuilder,
coroutineScope = this
) )
moleculeFlow(RecompositionMode.Immediate) { moleculeFlow(RecompositionMode.Immediate) {
val state = presenter.present() val state = presenter.present()
@ -1528,18 +1515,17 @@ class MessageComposerPresenterTest {
return normalState return normalState
} }
private fun createPresenter( private fun TestScope.createPresenter(
coroutineScope: CoroutineScope,
room: JoinedRoom = FakeJoinedRoom( room: JoinedRoom = FakeJoinedRoom(
typingNoticeResult = { Result.success(Unit) } typingNoticeResult = { Result.success(Unit) }
), ),
navigator: MessagesNavigator = FakeMessagesNavigator(), navigator: MessagesNavigator = FakeMessagesNavigator(),
pickerProvider: PickerProvider = this.pickerProvider, pickerProvider: PickerProvider = this@MessageComposerPresenterTest.pickerProvider,
featureFlagService: FeatureFlagService = this.featureFlagService, featureFlagService: FeatureFlagService = this@MessageComposerPresenterTest.featureFlagService,
locationService: LocationService = FakeLocationService(true), locationService: LocationService = FakeLocationService(true),
sessionPreferencesStore: SessionPreferencesStore = InMemorySessionPreferencesStore(), sessionPreferencesStore: SessionPreferencesStore = InMemorySessionPreferencesStore(),
mediaPreProcessor: MediaPreProcessor = this.mediaPreProcessor, mediaPreProcessor: MediaPreProcessor = this@MessageComposerPresenterTest.mediaPreProcessor,
snackbarDispatcher: SnackbarDispatcher = this.snackbarDispatcher, snackbarDispatcher: SnackbarDispatcher = this@MessageComposerPresenterTest.snackbarDispatcher,
permissionPresenter: PermissionsPresenter = FakePermissionsPresenter(), permissionPresenter: PermissionsPresenter = FakePermissionsPresenter(),
permalinkBuilder: PermalinkBuilder = FakePermalinkBuilder(), permalinkBuilder: PermalinkBuilder = FakePermalinkBuilder(),
permalinkParser: PermalinkParser = FakePermalinkParser(), permalinkParser: PermalinkParser = FakePermalinkParser(),
@ -1553,7 +1539,7 @@ class MessageComposerPresenterTest {
draftService: ComposerDraftService = FakeComposerDraftService(), draftService: ComposerDraftService = FakeComposerDraftService(),
) = MessageComposerPresenter( ) = MessageComposerPresenter(
navigator = navigator, navigator = navigator,
appCoroutineScope = coroutineScope, appCoroutineScope = this,
room = room, room = room,
mediaPickerProvider = pickerProvider, mediaPickerProvider = pickerProvider,
featureFlagService = featureFlagService, featureFlagService = featureFlagService,

View file

@ -32,7 +32,6 @@ import io.element.android.tests.testutils.WarmUpRule
import io.element.android.tests.testutils.lambda.assert import io.element.android.tests.testutils.lambda.assert
import io.element.android.tests.testutils.lambda.lambdaRecorder import io.element.android.tests.testutils.lambda.lambdaRecorder
import io.element.android.tests.testutils.testCoroutineDispatchers import io.element.android.tests.testutils.testCoroutineDispatchers
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.getAndUpdate import kotlinx.coroutines.flow.getAndUpdate
@ -155,7 +154,6 @@ class PollHistoryPresenterTest {
private fun TestScope.createPollHistoryPresenter( private fun TestScope.createPollHistoryPresenter(
room: FakeJoinedRoom = FakeJoinedRoom(), room: FakeJoinedRoom = FakeJoinedRoom(),
appCoroutineScope: CoroutineScope = this,
endPollAction: EndPollAction = FakeEndPollAction(), endPollAction: EndPollAction = FakeEndPollAction(),
sendPollResponseAction: SendPollResponseAction = FakeSendPollResponseAction(), sendPollResponseAction: SendPollResponseAction = FakeSendPollResponseAction(),
pollHistoryItemFactory: PollHistoryItemsFactory = PollHistoryItemsFactory( pollHistoryItemFactory: PollHistoryItemsFactory = PollHistoryItemsFactory(
@ -165,7 +163,7 @@ class PollHistoryPresenterTest {
), ),
): PollHistoryPresenter { ): PollHistoryPresenter {
return PollHistoryPresenter( return PollHistoryPresenter(
appCoroutineScope = appCoroutineScope, appCoroutineScope = this,
sendPollResponseAction = sendPollResponseAction, sendPollResponseAction = sendPollResponseAction,
endPollAction = endPollAction, endPollAction = endPollAction,
pollHistoryItemFactory = pollHistoryItemFactory, pollHistoryItemFactory = pollHistoryItemFactory,

View file

@ -36,6 +36,7 @@ import io.element.android.libraries.matrix.test.A_ROOM_NAME
import io.element.android.libraries.matrix.test.A_ROOM_TOPIC import io.element.android.libraries.matrix.test.A_ROOM_TOPIC
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.A_USER_ID_2 import io.element.android.libraries.matrix.test.A_USER_ID_2
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.encryption.FakeEncryptionService import io.element.android.libraries.matrix.test.encryption.FakeEncryptionService
import io.element.android.libraries.matrix.test.notificationsettings.FakeNotificationSettingsService import io.element.android.libraries.matrix.test.notificationsettings.FakeNotificationSettingsService
@ -241,6 +242,8 @@ class RoomDetailsPresenterTest {
fun `present - initial state when user can not invite others to room`() = runTest { fun `present - initial state when user can not invite others to room`() = runTest {
val room = aJoinedRoom( val room = aJoinedRoom(
canInviteResult = { Result.success(false) }, canInviteResult = { Result.success(false) },
canKickResult = { Result.success(false) },
canBanResult = { Result.success(false) },
canUserJoinCallResult = { Result.success(true) }, canUserJoinCallResult = { Result.success(true) },
canSendStateResult = { _, _ -> Result.success(true) }, canSendStateResult = { _, _ -> Result.success(true) },
) )
@ -277,6 +280,8 @@ class RoomDetailsPresenterTest {
else -> Result.failure(Throwable("Whelp")) else -> Result.failure(Throwable("Whelp"))
} }
}, },
canBanResult = { Result.success(false) },
canKickResult = { Result.success(false) },
canInviteResult = { Result.success(false) }, canInviteResult = { Result.success(false) },
canUserJoinCallResult = { Result.success(true) }, canUserJoinCallResult = { Result.success(true) },
) )
@ -304,6 +309,8 @@ class RoomDetailsPresenterTest {
else -> Result.failure(Throwable("Whelp")) else -> Result.failure(Throwable("Whelp"))
} }
}, },
canKickResult = { Result.success(false) },
canBanResult = { Result.success(false) },
canInviteResult = { Result.success(false) }, canInviteResult = { Result.success(false) },
canUserJoinCallResult = { Result.success(true) }, canUserJoinCallResult = { Result.success(true) },
getUpdatedMemberResult = { userId -> getUpdatedMemberResult = { userId ->
@ -353,6 +360,8 @@ class RoomDetailsPresenterTest {
else -> Result.failure(Throwable("Whelp")) else -> Result.failure(Throwable("Whelp"))
} }
}, },
userDisplayNameResult = { Result.success(A_USER_NAME) },
userAvatarUrlResult = { Result.success(AN_AVATAR_URL) },
canInviteResult = { Result.success(true) }, canInviteResult = { Result.success(true) },
canUserJoinCallResult = { Result.success(true) }, canUserJoinCallResult = { Result.success(true) },
getUpdatedMemberResult = { userId -> getUpdatedMemberResult = { userId ->
@ -397,6 +406,12 @@ class RoomDetailsPresenterTest {
else -> Result.failure(Throwable("Whelp")) else -> Result.failure(Throwable("Whelp"))
} }
}, },
canKickResult = {
Result.success(false)
},
canBanResult = {
Result.success(false)
},
canInviteResult = { canInviteResult = {
Result.success(false) Result.success(false)
}, },
@ -424,6 +439,12 @@ class RoomDetailsPresenterTest {
else -> Result.failure(Throwable("Whelp")) else -> Result.failure(Throwable("Whelp"))
} }
}, },
canBanResult = {
Result.success(false)
},
canKickResult = {
Result.success(false)
},
canInviteResult = { canInviteResult = {
Result.success(false) Result.success(false)
}, },
@ -450,6 +471,12 @@ class RoomDetailsPresenterTest {
else -> Result.failure(Throwable("Whelp")) else -> Result.failure(Throwable("Whelp"))
} }
}, },
canKickResult = {
Result.success(false)
},
canBanResult = {
Result.success(false)
},
canInviteResult = { canInviteResult = {
Result.success(false) Result.success(false)
}, },
@ -476,6 +503,12 @@ class RoomDetailsPresenterTest {
else -> Result.failure(Throwable("Whelp")) else -> Result.failure(Throwable("Whelp"))
} }
}, },
canKickResult = {
Result.success(false)
},
canBanResult = {
Result.success(false)
},
canInviteResult = { canInviteResult = {
Result.success(false) Result.success(false)
}, },

View file

@ -16,6 +16,7 @@ import io.element.android.libraries.matrix.api.core.RoomAlias
import io.element.android.libraries.matrix.api.room.JoinedRoom import io.element.android.libraries.matrix.api.room.JoinedRoom
import io.element.android.libraries.matrix.api.room.alias.ResolvedRoomAlias import io.element.android.libraries.matrix.api.room.alias.ResolvedRoomAlias
import io.element.android.libraries.matrix.api.room.alias.RoomAliasHelper import io.element.android.libraries.matrix.api.room.alias.RoomAliasHelper
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.FakeMatrixClient import io.element.android.libraries.matrix.test.FakeMatrixClient
import io.element.android.libraries.matrix.test.room.FakeJoinedRoom import io.element.android.libraries.matrix.test.room.FakeJoinedRoom
@ -289,7 +290,14 @@ class EditBaseRoomAddressPresenterTest {
val navigator = FakeSecurityAndPrivacyNavigator( val navigator = FakeSecurityAndPrivacyNavigator(
closeEditRoomAddressLambda = closeEditAddressLambda closeEditRoomAddressLambda = closeEditAddressLambda
) )
val presenter = createEditRoomAddressPresenter(navigator = navigator) val presenter = createEditRoomAddressPresenter(
navigator = navigator,
room = FakeJoinedRoom(
publishRoomAliasInRoomDirectoryResult = {
Result.failure(AN_EXCEPTION)
},
)
)
presenter.test { presenter.test {
with(awaitItem()) { with(awaitItem()) {
eventSink(EditRoomAddressEvents.RoomAddressChanged("valid")) eventSink(EditRoomAddressEvents.RoomAddressChanged("valid"))
@ -313,7 +321,13 @@ class EditBaseRoomAddressPresenterTest {
@Test @Test
fun `present - dismiss error`() = runTest { fun `present - dismiss error`() = runTest {
val presenter = createEditRoomAddressPresenter() val presenter = createEditRoomAddressPresenter(
room = FakeJoinedRoom(
publishRoomAliasInRoomDirectoryResult = {
Result.failure(AN_EXCEPTION)
},
)
)
presenter.test { presenter.test {
with(awaitItem()) { with(awaitItem()) {
eventSink(EditRoomAddressEvents.Save) eventSink(EditRoomAddressEvents.Save)

View file

@ -17,7 +17,6 @@ import io.element.android.libraries.matrix.test.encryption.FakeEncryptionService
import io.element.android.libraries.matrix.test.encryption.FakeIdentityPasswordResetHandle import io.element.android.libraries.matrix.test.encryption.FakeIdentityPasswordResetHandle
import io.element.android.libraries.matrix.test.verification.FakeSessionVerificationService import io.element.android.libraries.matrix.test.verification.FakeSessionVerificationService
import io.element.android.tests.testutils.lambda.lambdaRecorder import io.element.android.tests.testutils.lambda.lambdaRecorder
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.advanceUntilIdle import kotlinx.coroutines.test.advanceUntilIdle
@ -132,11 +131,10 @@ class ResetIdentityFlowManagerTest {
private fun TestScope.createFlowManager( private fun TestScope.createFlowManager(
encryptionService: FakeEncryptionService = FakeEncryptionService(), encryptionService: FakeEncryptionService = FakeEncryptionService(),
client: FakeMatrixClient = FakeMatrixClient(encryptionService = encryptionService), client: FakeMatrixClient = FakeMatrixClient(encryptionService = encryptionService),
sessionCoroutineScope: CoroutineScope = this,
sessionVerificationService: FakeSessionVerificationService = FakeSessionVerificationService(), sessionVerificationService: FakeSessionVerificationService = FakeSessionVerificationService(),
) = ResetIdentityFlowManager( ) = ResetIdentityFlowManager(
matrixClient = client, matrixClient = client,
sessionCoroutineScope = sessionCoroutineScope, sessionCoroutineScope = this,
sessionVerificationService = sessionVerificationService, sessionVerificationService = sessionVerificationService,
) )
} }

View file

@ -15,7 +15,6 @@ import io.element.android.libraries.matrix.test.A_DEVICE_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.room.aRoomInfo import io.element.android.libraries.matrix.test.room.aRoomInfo
import io.element.android.tests.testutils.testCoroutineDispatchers import io.element.android.tests.testutils.testCoroutineDispatchers
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.isActive import kotlinx.coroutines.isActive
import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
@ -24,18 +23,13 @@ import org.junit.Test
class RustBaseRoomTest { class RustBaseRoomTest {
@Test @Test
fun `RustBaseRoom should cancel the room coroutine scope when it is destroyed`() = runTest { fun `RustBaseRoom should cancel the room coroutine scope when it is destroyed`() = runTest {
val rustBaseRoom = createRustBaseRoom( val rustBaseRoom = createRustBaseRoom()
// Not using backgroundScope here, but the test scope
sessionCoroutineScope = this
)
assertThat(rustBaseRoom.roomCoroutineScope.isActive).isTrue() assertThat(rustBaseRoom.roomCoroutineScope.isActive).isTrue()
rustBaseRoom.destroy() rustBaseRoom.destroy()
assertThat(rustBaseRoom.roomCoroutineScope.isActive).isFalse() assertThat(rustBaseRoom.roomCoroutineScope.isActive).isFalse()
} }
private fun TestScope.createRustBaseRoom( private fun TestScope.createRustBaseRoom(): RustBaseRoom {
sessionCoroutineScope: CoroutineScope,
): RustBaseRoom {
val dispatchers = testCoroutineDispatchers() val dispatchers = testCoroutineDispatchers()
return RustBaseRoom( return RustBaseRoom(
sessionId = A_SESSION_ID, sessionId = A_SESSION_ID,
@ -47,7 +41,8 @@ class RustBaseRoomTest {
dispatchers = dispatchers, dispatchers = dispatchers,
), ),
roomMembershipObserver = RoomMembershipObserver(), roomMembershipObserver = RoomMembershipObserver(),
sessionCoroutineScope = sessionCoroutineScope, // Not using backgroundScope here, but the test scope
sessionCoroutineScope = this,
roomInfoMapper = RoomInfoMapper(), roomInfoMapper = RoomInfoMapper(),
initialRoomInfo = aRoomInfo(), initialRoomInfo = aRoomInfo(),
) )

View file

@ -13,7 +13,6 @@ import io.element.android.libraries.matrix.api.roomdirectory.RoomDirectoryList
import io.element.android.libraries.matrix.impl.fixtures.factories.aRustRoomDescription import io.element.android.libraries.matrix.impl.fixtures.factories.aRustRoomDescription
import io.element.android.libraries.matrix.impl.fixtures.fakes.FakeRustRoomDirectorySearch import io.element.android.libraries.matrix.impl.fixtures.fakes.FakeRustRoomDirectorySearch
import io.element.android.libraries.matrix.test.A_ROOM_ID_2 import io.element.android.libraries.matrix.test.A_ROOM_ID_2
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.StandardTestDispatcher import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.TestScope
@ -31,7 +30,6 @@ class RustBaseRoomDirectoryListTest {
val mapper = RoomDescriptionMapper() val mapper = RoomDescriptionMapper()
val sut = createRustRoomDirectoryList( val sut = createRustRoomDirectoryList(
roomDirectorySearch = roomDirectorySearch, roomDirectorySearch = roomDirectorySearch,
scope = backgroundScope,
) )
// Let the mxCallback be ready // Let the mxCallback be ready
runCurrent() runCurrent()
@ -81,10 +79,9 @@ class RustBaseRoomDirectoryListTest {
private fun TestScope.createRustRoomDirectoryList( private fun TestScope.createRustRoomDirectoryList(
roomDirectorySearch: RoomDirectorySearch = FakeRustRoomDirectorySearch(), roomDirectorySearch: RoomDirectorySearch = FakeRustRoomDirectorySearch(),
scope: CoroutineScope,
) = RustRoomDirectoryList( ) = RustRoomDirectoryList(
inner = roomDirectorySearch, inner = roomDirectorySearch,
coroutineScope = scope, coroutineScope = backgroundScope,
coroutineContext = StandardTestDispatcher(testScheduler), coroutineContext = StandardTestDispatcher(testScheduler),
) )
} }

View file

@ -12,7 +12,6 @@ import io.element.android.libraries.matrix.api.roomlist.RoomListService
import io.element.android.libraries.matrix.impl.fixtures.fakes.FakeRustRoomListService import io.element.android.libraries.matrix.impl.fixtures.fakes.FakeRustRoomListService
import io.element.android.libraries.matrix.impl.room.RoomSyncSubscriber import io.element.android.libraries.matrix.impl.room.RoomSyncSubscriber
import io.element.android.tests.testutils.testCoroutineDispatchers import io.element.android.tests.testutils.testCoroutineDispatchers
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.StandardTestDispatcher import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.TestScope
@ -28,7 +27,6 @@ class RustBaseRoomListServiceTest {
fun `syncIndicator should emit the expected values`() = runTest { fun `syncIndicator should emit the expected values`() = runTest {
val roomListService = FakeRustRoomListService() val roomListService = FakeRustRoomListService()
val sut = createRustRoomListService( val sut = createRustRoomListService(
sessionCoroutineScope = backgroundScope,
roomListService = roomListService, roomListService = roomListService,
) )
// Give time for mxCallback to setup // Give time for mxCallback to setup
@ -44,18 +42,17 @@ class RustBaseRoomListServiceTest {
} }
private fun TestScope.createRustRoomListService( private fun TestScope.createRustRoomListService(
sessionCoroutineScope: CoroutineScope,
roomListService: RustRoomListService = FakeRustRoomListService(), roomListService: RustRoomListService = FakeRustRoomListService(),
) = RustRoomListService( ) = RustRoomListService(
innerRoomListService = roomListService, innerRoomListService = roomListService,
sessionDispatcher = StandardTestDispatcher(testScheduler), sessionDispatcher = StandardTestDispatcher(testScheduler),
roomListFactory = RoomListFactory( roomListFactory = RoomListFactory(
innerRoomListService = roomListService, innerRoomListService = roomListService,
sessionCoroutineScope = sessionCoroutineScope, sessionCoroutineScope = backgroundScope,
), ),
roomSyncSubscriber = RoomSyncSubscriber( roomSyncSubscriber = RoomSyncSubscriber(
roomListService = roomListService, roomListService = roomListService,
dispatchers = testCoroutineDispatchers(), dispatchers = testCoroutineDispatchers(),
), ),
sessionCoroutineScope = sessionCoroutineScope, sessionCoroutineScope = backgroundScope,
) )

View file

@ -17,7 +17,6 @@ import io.element.android.libraries.matrix.impl.fixtures.fakes.FakeRustTimelineI
import io.element.android.tests.testutils.lambda.lambdaError import io.element.android.tests.testutils.lambda.lambdaError
import io.element.android.tests.testutils.lambda.lambdaRecorder import io.element.android.tests.testutils.lambda.lambdaRecorder
import kotlinx.coroutines.CompletableDeferred import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
@ -38,7 +37,6 @@ class TimelineItemsSubscriberTest {
MutableSharedFlow(replay = 1, extraBufferCapacity = Int.MAX_VALUE) MutableSharedFlow(replay = 1, extraBufferCapacity = Int.MAX_VALUE)
val timeline = FakeRustTimeline() val timeline = FakeRustTimeline()
val timelineItemsSubscriber = createTimelineItemsSubscriber( val timelineItemsSubscriber = createTimelineItemsSubscriber(
coroutineScope = backgroundScope,
timeline = timeline, timeline = timeline,
timelineItems = timelineItems, timelineItems = timelineItems,
) )
@ -59,7 +57,6 @@ class TimelineItemsSubscriberTest {
MutableSharedFlow(replay = 1, extraBufferCapacity = Int.MAX_VALUE) MutableSharedFlow(replay = 1, extraBufferCapacity = Int.MAX_VALUE)
val timeline = FakeRustTimeline() val timeline = FakeRustTimeline()
val timelineItemsSubscriber = createTimelineItemsSubscriber( val timelineItemsSubscriber = createTimelineItemsSubscriber(
coroutineScope = backgroundScope,
timeline = timeline, timeline = timeline,
timelineItems = timelineItems, timelineItems = timelineItems,
) )
@ -81,7 +78,6 @@ class TimelineItemsSubscriberTest {
val timeline = FakeRustTimeline() val timeline = FakeRustTimeline()
val onNewSyncedEventRecorder = lambdaRecorder<Unit> { } val onNewSyncedEventRecorder = lambdaRecorder<Unit> { }
val timelineItemsSubscriber = createTimelineItemsSubscriber( val timelineItemsSubscriber = createTimelineItemsSubscriber(
coroutineScope = backgroundScope,
timeline = timeline, timeline = timeline,
timelineItems = timelineItems, timelineItems = timelineItems,
onNewSyncedEvent = onNewSyncedEventRecorder, onNewSyncedEvent = onNewSyncedEventRecorder,
@ -109,9 +105,7 @@ class TimelineItemsSubscriberTest {
@Test @Test
fun `multiple subscriptions does not have side effect`() = runTest { fun `multiple subscriptions does not have side effect`() = runTest {
val timelineItemsSubscriber = createTimelineItemsSubscriber( val timelineItemsSubscriber = createTimelineItemsSubscriber()
coroutineScope = backgroundScope,
)
timelineItemsSubscriber.subscribeIfNeeded() timelineItemsSubscriber.subscribeIfNeeded()
timelineItemsSubscriber.subscribeIfNeeded() timelineItemsSubscriber.subscribeIfNeeded()
timelineItemsSubscriber.unsubscribeIfNeeded() timelineItemsSubscriber.unsubscribeIfNeeded()
@ -120,7 +114,6 @@ class TimelineItemsSubscriberTest {
} }
private fun TestScope.createTimelineItemsSubscriber( private fun TestScope.createTimelineItemsSubscriber(
coroutineScope: CoroutineScope,
timeline: Timeline = FakeRustTimeline(), timeline: Timeline = FakeRustTimeline(),
timelineItems: MutableSharedFlow<List<MatrixTimelineItem>> = MutableSharedFlow(replay = 1, extraBufferCapacity = Int.MAX_VALUE), timelineItems: MutableSharedFlow<List<MatrixTimelineItem>> = MutableSharedFlow(replay = 1, extraBufferCapacity = Int.MAX_VALUE),
initLatch: CompletableDeferred<Unit> = CompletableDeferred(), initLatch: CompletableDeferred<Unit> = CompletableDeferred(),
@ -128,7 +121,7 @@ private fun TestScope.createTimelineItemsSubscriber(
onNewSyncedEvent: () -> Unit = { lambdaError() }, onNewSyncedEvent: () -> Unit = { lambdaError() },
): TimelineItemsSubscriber { ): TimelineItemsSubscriber {
return TimelineItemsSubscriber( return TimelineItemsSubscriber(
timelineCoroutineScope = coroutineScope, timelineCoroutineScope = backgroundScope,
dispatcher = StandardTestDispatcher(testScheduler), dispatcher = StandardTestDispatcher(testScheduler),
timeline = timeline, timeline = timeline,
timelineDiffProcessor = createMatrixTimelineDiffProcessor(timelineItems), timelineDiffProcessor = createMatrixTimelineDiffProcessor(timelineItems),

View file

@ -37,7 +37,24 @@ class MediaSenderTest {
@Test @Test
fun `given an attachment when sending it the preprocessor always runs`() = runTest { fun `given an attachment when sending it the preprocessor always runs`() = runTest {
val preProcessor = FakeMediaPreProcessor() val preProcessor = FakeMediaPreProcessor()
val sender = createMediaSender(preProcessor) val sender = createMediaSender(
preProcessor = preProcessor,
room = FakeJoinedRoom(
liveTimeline = FakeTimeline().apply {
sendFileLambda = lambdaRecorder<
File,
FileInfo,
String?,
String?,
ProgressCallback?,
ReplyParameters?,
Result<FakeMediaUploadHandler>,
> { _, _, _, _, _, _ ->
Result.success(FakeMediaUploadHandler())
}
},
)
)
val uri = Uri.parse("content://image.jpg") val uri = Uri.parse("content://image.jpg")
sender.sendMedia(uri = uri, mimeType = MimeTypes.Jpeg) sender.sendMedia(uri = uri, mimeType = MimeTypes.Jpeg)

View file

@ -23,8 +23,8 @@ import io.element.android.services.appnavstate.test.A_SESSION_OWNER
import io.element.android.services.appnavstate.test.A_SPACE_OWNER import io.element.android.services.appnavstate.test.A_SPACE_OWNER
import io.element.android.services.appnavstate.test.A_THREAD_OWNER import io.element.android.services.appnavstate.test.A_THREAD_OWNER
import io.element.android.services.appnavstate.test.FakeAppForegroundStateService import io.element.android.services.appnavstate.test.FakeAppForegroundStateService
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.first
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import org.junit.Test import org.junit.Test
@ -52,7 +52,7 @@ class DefaultNavigationStateServiceTest {
@Test @Test
fun testNavigation() = runTest { fun testNavigation() = runTest {
val service = createStateService(backgroundScope) val service = createStateService()
assertThat(service.appNavigationState.first().navigationState).isEqualTo(navigationStateRoot) assertThat(service.appNavigationState.first().navigationState).isEqualTo(navigationStateRoot)
service.onNavigateToSession(A_SESSION_OWNER, A_SESSION_ID) service.onNavigateToSession(A_SESSION_OWNER, A_SESSION_ID)
assertThat(service.appNavigationState.first().navigationState).isEqualTo(navigationStateSession) assertThat(service.appNavigationState.first().navigationState).isEqualTo(navigationStateSession)
@ -75,14 +75,14 @@ class DefaultNavigationStateServiceTest {
@Test @Test
fun testFailure() = runTest { fun testFailure() = runTest {
val service = createStateService(backgroundScope) val service = createStateService()
service.onNavigateToSpace(A_SPACE_OWNER, A_SPACE_ID) service.onNavigateToSpace(A_SPACE_OWNER, A_SPACE_ID)
assertThat(service.appNavigationState.value.navigationState).isEqualTo(NavigationState.Root) assertThat(service.appNavigationState.value.navigationState).isEqualTo(NavigationState.Root)
} }
@Test @Test
fun testOnNavigateToThread() = runTest { fun testOnNavigateToThread() = runTest {
val service = createStateService(backgroundScope) val service = createStateService()
// From root (no effect) // From root (no effect)
service.onNavigateToThread(A_THREAD_OWNER, A_THREAD_ID) service.onNavigateToThread(A_THREAD_OWNER, A_THREAD_ID)
assertThat(service.appNavigationState.first().navigationState).isEqualTo(navigationStateRoot) assertThat(service.appNavigationState.first().navigationState).isEqualTo(navigationStateRoot)
@ -111,7 +111,7 @@ class DefaultNavigationStateServiceTest {
@Test @Test
fun testOnNavigateToRoom() = runTest { fun testOnNavigateToRoom() = runTest {
val service = createStateService(backgroundScope) val service = createStateService()
// From root (no effect) // From root (no effect)
service.onNavigateToRoom(A_ROOM_OWNER, A_ROOM_ID) service.onNavigateToRoom(A_ROOM_OWNER, A_ROOM_ID)
assertThat(service.appNavigationState.first().navigationState).isEqualTo(navigationStateRoot) assertThat(service.appNavigationState.first().navigationState).isEqualTo(navigationStateRoot)
@ -140,7 +140,7 @@ class DefaultNavigationStateServiceTest {
@Test @Test
fun testOnNavigateToSpace() = runTest { fun testOnNavigateToSpace() = runTest {
val service = createStateService(backgroundScope) val service = createStateService()
// From root (no effect) // From root (no effect)
service.onNavigateToSpace(A_SPACE_OWNER, A_SPACE_ID) service.onNavigateToSpace(A_SPACE_OWNER, A_SPACE_ID)
assertThat(service.appNavigationState.first().navigationState).isEqualTo(navigationStateRoot) assertThat(service.appNavigationState.first().navigationState).isEqualTo(navigationStateRoot)
@ -169,7 +169,7 @@ class DefaultNavigationStateServiceTest {
@Test @Test
fun testOnNavigateToSession() = runTest { fun testOnNavigateToSession() = runTest {
val service = createStateService(backgroundScope) val service = createStateService()
// From root // From root
service.onNavigateToSession(A_SESSION_OWNER, A_SESSION_ID) service.onNavigateToSession(A_SESSION_OWNER, A_SESSION_ID)
assertThat(service.appNavigationState.first().navigationState).isEqualTo(navigationStateSession) assertThat(service.appNavigationState.first().navigationState).isEqualTo(navigationStateSession)
@ -198,7 +198,7 @@ class DefaultNavigationStateServiceTest {
@Test @Test
fun testOnLeavingThread() = runTest { fun testOnLeavingThread() = runTest {
val service = createStateService(backgroundScope) val service = createStateService()
// From root (no effect) // From root (no effect)
service.onLeavingThread(A_THREAD_OWNER) service.onLeavingThread(A_THREAD_OWNER)
assertThat(service.appNavigationState.first().navigationState).isEqualTo(navigationStateRoot) assertThat(service.appNavigationState.first().navigationState).isEqualTo(navigationStateRoot)
@ -226,7 +226,7 @@ class DefaultNavigationStateServiceTest {
@Test @Test
fun testOnLeavingRoom() = runTest { fun testOnLeavingRoom() = runTest {
val service = createStateService(backgroundScope) val service = createStateService()
// From root (no effect) // From root (no effect)
service.onLeavingRoom(A_ROOM_OWNER) service.onLeavingRoom(A_ROOM_OWNER)
assertThat(service.appNavigationState.first().navigationState).isEqualTo(navigationStateRoot) assertThat(service.appNavigationState.first().navigationState).isEqualTo(navigationStateRoot)
@ -254,7 +254,7 @@ class DefaultNavigationStateServiceTest {
@Test @Test
fun testOnLeavingSpace() = runTest { fun testOnLeavingSpace() = runTest {
val service = createStateService(backgroundScope) val service = createStateService()
// From root (no effect) // From root (no effect)
service.onLeavingSpace(A_SPACE_OWNER) service.onLeavingSpace(A_SPACE_OWNER)
assertThat(service.appNavigationState.first().navigationState).isEqualTo(navigationStateRoot) assertThat(service.appNavigationState.first().navigationState).isEqualTo(navigationStateRoot)
@ -282,7 +282,7 @@ class DefaultNavigationStateServiceTest {
@Test @Test
fun testOnLeavingSession() = runTest { fun testOnLeavingSession() = runTest {
val service = createStateService(backgroundScope) val service = createStateService()
// From root // From root
service.onLeavingSession(A_SESSION_OWNER) service.onLeavingSession(A_SESSION_OWNER)
assertThat(service.appNavigationState.first().navigationState).isEqualTo(navigationStateRoot) assertThat(service.appNavigationState.first().navigationState).isEqualTo(navigationStateRoot)
@ -332,7 +332,8 @@ class DefaultNavigationStateServiceTest {
onNavigateToThread(A_THREAD_OWNER, A_THREAD_ID) onNavigateToThread(A_THREAD_OWNER, A_THREAD_ID)
} }
private fun createStateService( private fun TestScope.createStateService() = DefaultAppNavigationStateService(
coroutineScope: CoroutineScope appForegroundStateService = FakeAppForegroundStateService(),
) = DefaultAppNavigationStateService(FakeAppForegroundStateService(), coroutineScope) coroutineScope = backgroundScope,
)
} }

View file

@ -7,8 +7,19 @@
package io.element.android.tests.testutils.lambda package io.element.android.tests.testutils.lambda
import kotlin.system.exitProcess
fun lambdaError( fun lambdaError(
message: String = "This lambda should never be called." message: String = "This lambda should never be called."
): Nothing { ): Nothing {
throw AssertionError(message) // Throwing an exception here is not enough, it can be caught.
// Instead exit the process to make sure the test fails.
// The error will be:
// "Could not stop all services."
// In this case, put a breakpoint here and run the test in debug mode to identify which lambda is failing.
System.err.println(message)
Thread.currentThread().stackTrace.forEach {
System.err.println(it)
}
exitProcess(1)
} }