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 5b9da3c41b
commit 4572419ed2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
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.services.appnavstate.api.ActiveRoomsHolder
import io.element.android.services.appnavstate.test.FakeAppNavigationStateService
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runTest
import org.junit.Rule
import org.junit.Test
@ -98,19 +98,18 @@ class JoinedRoomLoadedFlowNodeTest {
}
}
private fun createJoinedRoomLoadedFlowNode(
private fun TestScope.createJoinedRoomLoadedFlowNode(
plugins: List<Plugin>,
messagesEntryPoint: MessagesEntryPoint = FakeMessagesEntryPoint(),
roomDetailsEntryPoint: RoomDetailsEntryPoint = FakeRoomDetailsEntryPoint(),
activeRoomsHolder: ActiveRoomsHolder = ActiveRoomsHolder(),
coroutineScope: CoroutineScope,
) = JoinedRoomLoadedFlowNode(
buildContext = BuildContext.root(savedStateMap = null),
plugins = plugins,
messagesEntryPoint = messagesEntryPoint,
roomDetailsEntryPoint = roomDetailsEntryPoint,
appNavigationStateService = FakeAppNavigationStateService(),
appCoroutineScope = coroutineScope,
appCoroutineScope = this,
roomComponentFactory = FakeRoomComponentFactory(),
matrixClient = FakeMatrixClient(),
activeRoomsHolder = activeRoomsHolder,
@ -125,7 +124,6 @@ class JoinedRoomLoadedFlowNodeTest {
val roomFlowNode = createJoinedRoomLoadedFlowNode(
plugins = listOf(inputs),
messagesEntryPoint = fakeMessagesEntryPoint,
coroutineScope = this
)
// WHEN
val roomFlowNodeTestHelper = roomFlowNode.parentNodeTestHelper()
@ -148,7 +146,6 @@ class JoinedRoomLoadedFlowNodeTest {
plugins = listOf(inputs),
messagesEntryPoint = fakeMessagesEntryPoint,
roomDetailsEntryPoint = fakeRoomDetailsEntryPoint,
coroutineScope = this
)
val roomFlowNodeTestHelper = roomFlowNode.parentNodeTestHelper()
// WHEN
@ -171,7 +168,6 @@ class JoinedRoomLoadedFlowNodeTest {
plugins = listOf(inputs),
messagesEntryPoint = fakeMessagesEntryPoint,
roomDetailsEntryPoint = fakeRoomDetailsEntryPoint,
coroutineScope = this,
activeRoomsHolder = activeRoomsHolder,
)
@ -197,7 +193,6 @@ class JoinedRoomLoadedFlowNodeTest {
plugins = listOf(inputs),
messagesEntryPoint = fakeMessagesEntryPoint,
roomDetailsEntryPoint = fakeRoomDetailsEntryPoint,
coroutineScope = this,
activeRoomsHolder = activeRoomsHolder,
)
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.mockk.mockk
import io.mockk.verify
import kotlinx.coroutines.CoroutineScope
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.advanceTimeBy
import kotlinx.coroutines.test.runCurrent
@ -63,30 +59,28 @@ class DefaultActiveCallManagerTest {
fun `registerIncomingCall - sets the incoming call as active`() = runTest {
setupShadowPowerManager()
val notificationManagerCompat = mockk<NotificationManagerCompat>(relaxed = true)
inCancellableScope {
val manager = createActiveCallManager(notificationManagerCompat = notificationManagerCompat)
val manager = createActiveCallManager(notificationManagerCompat = notificationManagerCompat)
assertThat(manager.activeWakeLock?.isHeld).isFalse()
assertThat(manager.activeCall.value).isNull()
assertThat(manager.activeWakeLock?.isHeld).isFalse()
assertThat(manager.activeCall.value).isNull()
val callNotificationData = aCallNotificationData()
manager.registerIncomingCall(callNotificationData)
val callNotificationData = aCallNotificationData()
manager.registerIncomingCall(callNotificationData)
assertThat(manager.activeCall.value).isEqualTo(
ActiveCall(
callType = CallType.RoomCall(
sessionId = callNotificationData.sessionId,
roomId = callNotificationData.roomId,
),
callState = CallState.Ringing(callNotificationData)
)
assertThat(manager.activeCall.value).isEqualTo(
ActiveCall(
callType = CallType.RoomCall(
sessionId = callNotificationData.sessionId,
roomId = callNotificationData.roomId,
),
callState = CallState.Ringing(callNotificationData)
)
)
runCurrent()
runCurrent()
assertThat(manager.activeWakeLock?.isHeld).isTrue()
verify { notificationManagerCompat.notify(notificationId, any()) }
}
assertThat(manager.activeWakeLock?.isHeld).isTrue()
verify { notificationManagerCompat.notify(notificationId, any()) }
}
@OptIn(ExperimentalCoroutinesApi::class)
@ -94,42 +88,38 @@ class DefaultActiveCallManagerTest {
fun `registerIncomingCall - when there is an already active call adds missed call notification`() = runTest {
val addMissedCallNotificationLambda = lambdaRecorder<SessionId, RoomId, EventId, Unit> { _, _, _ -> }
val onMissedCallNotificationHandler = FakeOnMissedCallNotificationHandler(addMissedCallNotificationLambda = addMissedCallNotificationLambda)
inCancellableScope {
val manager = createActiveCallManager(
onMissedCallNotificationHandler = onMissedCallNotificationHandler,
)
val manager = createActiveCallManager(
onMissedCallNotificationHandler = onMissedCallNotificationHandler,
)
// Register existing call
val callNotificationData = aCallNotificationData()
manager.registerIncomingCall(callNotificationData)
val activeCall = manager.activeCall.value
// Register existing call
val callNotificationData = aCallNotificationData()
manager.registerIncomingCall(callNotificationData)
val activeCall = manager.activeCall.value
// Now add a new call
manager.registerIncomingCall(aCallNotificationData(roomId = A_ROOM_ID_2))
// Now add a new call
manager.registerIncomingCall(aCallNotificationData(roomId = A_ROOM_ID_2))
assertThat(manager.activeCall.value).isEqualTo(activeCall)
assertThat((manager.activeCall.value?.callType as? CallType.RoomCall)?.roomId).isNotEqualTo(A_ROOM_ID_2)
assertThat(manager.activeCall.value).isEqualTo(activeCall)
assertThat((manager.activeCall.value?.callType as? CallType.RoomCall)?.roomId).isNotEqualTo(A_ROOM_ID_2)
advanceTimeBy(1)
advanceTimeBy(1)
addMissedCallNotificationLambda.assertions()
.isCalledOnce()
.with(value(A_SESSION_ID), value(A_ROOM_ID_2), value(AN_EVENT_ID))
}
addMissedCallNotificationLambda.assertions()
.isCalledOnce()
.with(value(A_SESSION_ID), value(A_ROOM_ID_2), value(AN_EVENT_ID))
}
@Test
fun `incomingCallTimedOut - when there isn't an active call does nothing`() = runTest {
val addMissedCallNotificationLambda = lambdaRecorder<SessionId, RoomId, EventId, Unit> { _, _, _ -> }
inCancellableScope {
val manager = createActiveCallManager(
onMissedCallNotificationHandler = FakeOnMissedCallNotificationHandler(addMissedCallNotificationLambda = addMissedCallNotificationLambda)
)
val manager = createActiveCallManager(
onMissedCallNotificationHandler = FakeOnMissedCallNotificationHandler(addMissedCallNotificationLambda = addMissedCallNotificationLambda)
)
manager.incomingCallTimedOut(displayMissedCallNotification = true)
manager.incomingCallTimedOut(displayMissedCallNotification = true)
addMissedCallNotificationLambda.assertions().isNeverCalled()
}
addMissedCallNotificationLambda.assertions().isNeverCalled()
}
@OptIn(ExperimentalCoroutinesApi::class)
@ -138,90 +128,80 @@ class DefaultActiveCallManagerTest {
setupShadowPowerManager()
val notificationManagerCompat = mockk<NotificationManagerCompat>(relaxed = true)
val addMissedCallNotificationLambda = lambdaRecorder<SessionId, RoomId, EventId, Unit> { _, _, _ -> }
inCancellableScope {
val manager = createActiveCallManager(
onMissedCallNotificationHandler = FakeOnMissedCallNotificationHandler(addMissedCallNotificationLambda = addMissedCallNotificationLambda),
notificationManagerCompat = notificationManagerCompat,
)
val manager = createActiveCallManager(
onMissedCallNotificationHandler = FakeOnMissedCallNotificationHandler(addMissedCallNotificationLambda = addMissedCallNotificationLambda),
notificationManagerCompat = notificationManagerCompat,
)
manager.registerIncomingCall(aCallNotificationData())
assertThat(manager.activeCall.value).isNotNull()
assertThat(manager.activeWakeLock?.isHeld).isTrue()
manager.registerIncomingCall(aCallNotificationData())
assertThat(manager.activeCall.value).isNotNull()
assertThat(manager.activeWakeLock?.isHeld).isTrue()
manager.incomingCallTimedOut(displayMissedCallNotification = true)
advanceTimeBy(1)
manager.incomingCallTimedOut(displayMissedCallNotification = true)
advanceTimeBy(1)
assertThat(manager.activeCall.value).isNull()
assertThat(manager.activeWakeLock?.isHeld).isFalse()
addMissedCallNotificationLambda.assertions().isCalledOnce()
verify { notificationManagerCompat.cancel(notificationId) }
}
assertThat(manager.activeCall.value).isNull()
assertThat(manager.activeWakeLock?.isHeld).isFalse()
addMissedCallNotificationLambda.assertions().isCalledOnce()
verify { notificationManagerCompat.cancel(notificationId) }
}
@Test
fun `hungUpCall - removes existing call if the CallType matches`() = runTest {
setupShadowPowerManager()
val notificationManagerCompat = mockk<NotificationManagerCompat>(relaxed = true)
// Create a cancellable coroutine scope to cancel the test when needed
inCancellableScope {
val manager = createActiveCallManager(notificationManagerCompat = notificationManagerCompat)
val manager = createActiveCallManager(notificationManagerCompat = notificationManagerCompat)
val notificationData = aCallNotificationData()
manager.registerIncomingCall(notificationData)
assertThat(manager.activeCall.value).isNotNull()
assertThat(manager.activeWakeLock?.isHeld).isTrue()
val notificationData = aCallNotificationData()
manager.registerIncomingCall(notificationData)
assertThat(manager.activeCall.value).isNotNull()
assertThat(manager.activeWakeLock?.isHeld).isTrue()
manager.hungUpCall(CallType.RoomCall(notificationData.sessionId, notificationData.roomId))
assertThat(manager.activeCall.value).isNull()
assertThat(manager.activeWakeLock?.isHeld).isFalse()
manager.hungUpCall(CallType.RoomCall(notificationData.sessionId, notificationData.roomId))
assertThat(manager.activeCall.value).isNull()
assertThat(manager.activeWakeLock?.isHeld).isFalse()
verify { notificationManagerCompat.cancel(notificationId) }
}
verify { notificationManagerCompat.cancel(notificationId) }
}
@Test
fun `hungUpCall - does nothing if the CallType doesn't match`() = runTest {
setupShadowPowerManager()
val notificationManagerCompat = mockk<NotificationManagerCompat>(relaxed = true)
// Create a cancellable coroutine scope to cancel the test when needed
inCancellableScope {
val manager = createActiveCallManager(notificationManagerCompat = notificationManagerCompat)
val manager = createActiveCallManager(notificationManagerCompat = notificationManagerCompat)
manager.registerIncomingCall(aCallNotificationData())
assertThat(manager.activeCall.value).isNotNull()
assertThat(manager.activeWakeLock?.isHeld).isTrue()
manager.registerIncomingCall(aCallNotificationData())
assertThat(manager.activeCall.value).isNotNull()
assertThat(manager.activeWakeLock?.isHeld).isTrue()
manager.hungUpCall(CallType.ExternalUrl("https://example.com"))
assertThat(manager.activeCall.value).isNotNull()
assertThat(manager.activeWakeLock?.isHeld).isTrue()
manager.hungUpCall(CallType.ExternalUrl("https://example.com"))
assertThat(manager.activeCall.value).isNotNull()
assertThat(manager.activeWakeLock?.isHeld).isTrue()
verify(exactly = 0) { notificationManagerCompat.cancel(notificationId) }
}
verify(exactly = 0) { notificationManagerCompat.cancel(notificationId) }
}
@OptIn(ExperimentalCoroutinesApi::class)
@Test
fun `joinedCall - register an ongoing call and tries sending the call notify event`() = runTest {
val notificationManagerCompat = mockk<NotificationManagerCompat>(relaxed = true)
inCancellableScope {
val manager = createActiveCallManager(notificationManagerCompat = notificationManagerCompat)
assertThat(manager.activeCall.value).isNull()
val manager = createActiveCallManager(notificationManagerCompat = notificationManagerCompat)
assertThat(manager.activeCall.value).isNull()
manager.joinedCall(CallType.RoomCall(A_SESSION_ID, A_ROOM_ID))
assertThat(manager.activeCall.value).isEqualTo(
ActiveCall(
callType = CallType.RoomCall(
sessionId = A_SESSION_ID,
roomId = A_ROOM_ID,
),
callState = CallState.InCall,
)
manager.joinedCall(CallType.RoomCall(A_SESSION_ID, A_ROOM_ID))
assertThat(manager.activeCall.value).isEqualTo(
ActiveCall(
callType = CallType.RoomCall(
sessionId = A_SESSION_ID,
roomId = A_ROOM_ID,
),
callState = CallState.InCall,
)
)
runCurrent()
runCurrent()
verify { notificationManagerCompat.cancel(notificationId) }
}
verify { notificationManagerCompat.cancel(notificationId) }
}
@OptIn(ExperimentalCoroutinesApi::class)
@ -233,22 +213,19 @@ class DefaultActiveCallManagerTest {
val client = FakeMatrixClient().apply {
givenGetRoomResult(A_ROOM_ID, room)
}
// Create a cancellable coroutine scope to cancel the test when needed
inCancellableScope {
val matrixClientProvider = FakeMatrixClientProvider(getClient = { Result.success(client) })
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)
room.givenRoomInfo(aRoomInfo(hasRoomCall = true))
advanceTimeBy(1)
// Call is cancelled (the other user left the call)
room.givenRoomInfo(aRoomInfo(hasRoomCall = false))
advanceTimeBy(1)
// Call is active (the other user join the call)
room.givenRoomInfo(aRoomInfo(hasRoomCall = true))
advanceTimeBy(1)
// Call is cancelled (the other user left the call)
room.givenRoomInfo(aRoomInfo(hasRoomCall = false))
advanceTimeBy(1)
assertThat(manager.activeCall.value).isNull()
}
assertThat(manager.activeCall.value).isNull()
}
@OptIn(ExperimentalCoroutinesApi::class)
@ -260,44 +237,34 @@ class DefaultActiveCallManagerTest {
val client = FakeMatrixClient().apply {
givenGetRoomResult(A_ROOM_ID, room)
}
// Create a cancellable coroutine scope to cancel the test when needed
inCancellableScope {
val matrixClientProvider = FakeMatrixClientProvider(getClient = { Result.failure(IllegalStateException("Matrix client not found")) })
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))
advanceTimeBy(1)
room.givenRoomInfo(aRoomInfo(hasRoomCall = false))
advanceTimeBy(1)
room.givenRoomInfo(aRoomInfo(hasRoomCall = true))
advanceTimeBy(1)
room.givenRoomInfo(aRoomInfo(hasRoomCall = false))
advanceTimeBy(1)
// The call should still be active
assertThat(manager.activeCall.value).isNotNull()
// The call should still be active
assertThat(manager.activeCall.value).isNotNull()
// No room
client.givenGetRoomResult(A_ROOM_ID, null)
matrixClientProvider.getClient = { Result.success(client) }
// No room
client.givenGetRoomResult(A_ROOM_ID, null)
matrixClientProvider.getClient = { Result.success(client) }
manager.registerIncomingCall(aCallNotificationData())
manager.registerIncomingCall(aCallNotificationData())
room.givenRoomInfo(aRoomInfo(hasRoomCall = true))
advanceTimeBy(1)
room.givenRoomInfo(aRoomInfo(hasRoomCall = false))
advanceTimeBy(1)
room.givenRoomInfo(aRoomInfo(hasRoomCall = true))
advanceTimeBy(1)
room.givenRoomInfo(aRoomInfo(hasRoomCall = false))
advanceTimeBy(1)
// The call should still be active
assertThat(manager.activeCall.value).isNotNull()
}
}
private fun TestScope.inCancellableScope(block: suspend CoroutineScope.() -> Unit) {
launch(SupervisorJob()) {
block()
cancel()
}
// The call should still be active
assertThat(manager.activeCall.value).isNotNull()
}
private fun setupShadowPowerManager() {
@ -306,14 +273,13 @@ class DefaultActiveCallManagerTest {
}
}
private fun CoroutineScope.createActiveCallManager(
private fun TestScope.createActiveCallManager(
matrixClientProvider: FakeMatrixClientProvider = FakeMatrixClientProvider(),
onMissedCallNotificationHandler: FakeOnMissedCallNotificationHandler = FakeOnMissedCallNotificationHandler(),
notificationManagerCompat: NotificationManagerCompat = mockk(relaxed = true),
coroutineScope: CoroutineScope = this,
) = DefaultActiveCallManager(
context = InstrumentationRegistry.getInstrumentation().targetContext,
coroutineScope = coroutineScope,
coroutineScope = backgroundScope,
onMissedCallNotificationHandler = onMissedCallNotificationHandler,
ringingCallNotificationCreator = RingingCallNotificationCreator(
context = InstrumentationRegistry.getInstrumentation().targetContext,

View file

@ -87,13 +87,19 @@ class DefaultCallWidgetProviderTest {
}
val activeRoomsHolder = ActiveRoomsHolder().apply {
// 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(
matrixClientProvider = FakeMatrixClientProvider { Result.success(client) },
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

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.consumeItemsUntilPredicate
import io.element.android.tests.testutils.test
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runTest
import org.junit.Test
class LockScreenSettingsPresenterTest {
@Test
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 {
awaitItem().also { state ->
assertThat(state.showRemovePinOption).isFalse()
@ -37,7 +37,7 @@ class LockScreenSettingsPresenterTest {
@Test
fun `present - remove pin flow`() = runTest {
val presenter = createLockScreenSettingsPresenter(this)
val presenter = createLockScreenSettingsPresenter()
presenter.test {
consumeItemsUntilPredicate { state ->
state.showRemovePinOption
@ -71,7 +71,6 @@ class LockScreenSettingsPresenterTest {
isDeviceSecured = true,
)
val presenter = createLockScreenSettingsPresenter(
coroutineScope = this,
biometricAuthenticatorManager = fakeBiometricAuthenticatorManager
)
presenter.test {
@ -88,7 +87,6 @@ class LockScreenSettingsPresenterTest {
}
)
val presenter = createLockScreenSettingsPresenter(
coroutineScope = this,
biometricAuthenticatorManager = fakeBiometricAuthenticatorManager
)
presenter.test {
@ -110,7 +108,6 @@ class LockScreenSettingsPresenterTest {
}
)
val presenter = createLockScreenSettingsPresenter(
coroutineScope = this,
biometricAuthenticatorManager = fakeBiometricAuthenticatorManager
)
presenter.test {
@ -130,7 +127,6 @@ class LockScreenSettingsPresenterTest {
)
val lockScreenStore = InMemoryLockScreenStore()
val presenter = createLockScreenSettingsPresenter(
coroutineScope = this,
lockScreenStore = lockScreenStore,
biometricAuthenticatorManager = fakeBiometricAuthenticatorManager
)
@ -148,8 +144,7 @@ class LockScreenSettingsPresenterTest {
}
}
private suspend fun createLockScreenSettingsPresenter(
coroutineScope: CoroutineScope,
private suspend fun TestScope.createLockScreenSettingsPresenter(
lockScreenConfig: LockScreenConfig = aLockScreenConfig(),
biometricAuthenticatorManager: BiometricAuthenticatorManager = FakeBiometricAuthenticatorManager(),
lockScreenStore: LockScreenStore = InMemoryLockScreenStore(),
@ -160,7 +155,7 @@ class LockScreenSettingsPresenterTest {
return LockScreenSettingsPresenter(
lockScreenStore = lockScreenStore,
pinCodeManager = pinCodeManager,
coroutineScope = coroutineScope,
coroutineScope = this,
lockScreenConfig = lockScreenConfig,
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.tests.testutils.lambda.assert
import io.element.android.tests.testutils.lambda.lambdaRecorder
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runTest
import org.junit.Test
@ -34,7 +34,7 @@ class PinUnlockPresenterTest {
@Test
fun `present - success verify flow`() = runTest {
val presenter = createPinUnlockPresenter(this)
val presenter = createPinUnlockPresenter()
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
@ -71,7 +71,7 @@ class PinUnlockPresenterTest {
@Test
fun `present - failure verify flow`() = runTest {
val presenter = createPinUnlockPresenter(this)
val presenter = createPinUnlockPresenter()
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
@ -100,7 +100,7 @@ class PinUnlockPresenterTest {
fun `present - forgot pin flow`() = runTest {
val signOutLambda = lambdaRecorder<Boolean, Unit> {}
val signOut = FakeLogoutUseCase(signOutLambda)
val presenter = createPinUnlockPresenter(this, logoutUseCase = signOut)
val presenter = createPinUnlockPresenter(logoutUseCase = signOut)
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
@ -135,8 +135,7 @@ class PinUnlockPresenterTest {
dataOrNull()?.assertText(text)
}
private suspend fun createPinUnlockPresenter(
scope: CoroutineScope,
private suspend fun TestScope.createPinUnlockPresenter(
biometricAuthenticatorManager: BiometricAuthenticatorManager = FakeBiometricAuthenticatorManager(),
callback: PinCodeManager.Callback = DefaultPinCodeManagerCallback(),
logoutUseCase: FakeLogoutUseCase = FakeLogoutUseCase(logoutLambda = { "" }),
@ -149,7 +148,7 @@ class PinUnlockPresenterTest {
pinCodeManager = pinCodeManager,
biometricAuthenticatorManager = biometricAuthenticatorManager,
logoutUseCase = logoutUseCase,
coroutineScope = scope,
coroutineScope = this,
pinUnlockHelper = PinUnlockHelper(biometricAuthenticatorManager, pinCodeManager),
)
}

View file

@ -513,7 +513,17 @@ class AttachmentsPreviewPresenterTest {
@Test
fun `present - dismissing the progress dialog stops media upload with media queue`() = runTest {
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) {
presenter.present()
}.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.tests.testutils.WarmUpRule
import io.element.android.tests.testutils.lambda.lambdaRecorder
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runTest
import org.junit.Rule
import org.junit.Test
@ -91,13 +91,12 @@ class ForwardMessagesPresenterTest {
}
}
private fun CoroutineScope.aForwardMessagesPresenter(
private fun TestScope.aForwardMessagesPresenter(
eventId: EventId = AN_EVENT_ID,
fakeRoom: FakeJoinedRoom = FakeJoinedRoom(),
coroutineScope: CoroutineScope = this,
) = ForwardMessagesPresenter(
eventId = eventId.value,
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_3
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.FakePermalinkParser
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 kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.advanceUntilIdle
import kotlinx.coroutines.test.runTest
import org.junit.Rule
@ -132,7 +133,7 @@ class MessageComposerPresenterTest {
@Test
fun `present - initial state`() = runTest {
val presenter = createPresenter(this)
val presenter = createPresenter()
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
@ -147,7 +148,7 @@ class MessageComposerPresenterTest {
@Test
fun `present - toggle fullscreen`() = runTest {
val presenter = createPresenter(this)
val presenter = createPresenter()
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
@ -163,7 +164,7 @@ class MessageComposerPresenterTest {
@Test
fun `present - change message`() = runTest {
val presenter = createPresenter(this)
val presenter = createPresenter()
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
@ -186,7 +187,6 @@ class MessageComposerPresenterTest {
this.saveDraftLambda = updateDraftLambda
}
val presenter = createPresenter(
coroutineScope = this,
draftService = draftService,
)
moleculeFlow(RecompositionMode.Immediate) {
@ -229,7 +229,6 @@ class MessageComposerPresenterTest {
this.saveDraftLambda = updateDraftLambda
}
val presenter = createPresenter(
coroutineScope = this,
draftService = draftService,
)
moleculeFlow(RecompositionMode.Immediate) {
@ -273,7 +272,6 @@ class MessageComposerPresenterTest {
typingNoticeResult = { Result.success(Unit) }
)
val presenter = createPresenter(
coroutineScope = this,
room = joinedRoom,
isRichTextEditorEnabled = false,
)
@ -314,7 +312,6 @@ class MessageComposerPresenterTest {
this.saveDraftLambda = updateDraftLambda
}
val presenter = createPresenter(
coroutineScope = this,
draftService = draftService,
)
moleculeFlow(RecompositionMode.Immediate) {
@ -346,7 +343,7 @@ class MessageComposerPresenterTest {
@Test
fun `present - change mode to reply`() = runTest {
val presenter = createPresenter(this)
val presenter = createPresenter()
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
@ -362,7 +359,7 @@ class MessageComposerPresenterTest {
@Test
fun `present - cancel reply`() = runTest {
val presenter = createPresenter(this)
val presenter = createPresenter()
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
@ -382,7 +379,6 @@ class MessageComposerPresenterTest {
@Test
fun `present - send message with rich text enabled`() = runTest {
val presenter = createPresenter(
coroutineScope = this,
room = FakeJoinedRoom(
liveTimeline = FakeTimeline().apply {
sendMessageLambda = { _, _, _ -> Result.success(Unit) }
@ -417,7 +413,6 @@ class MessageComposerPresenterTest {
fun `present - send message with plain text enabled`() = runTest {
val permalinkBuilder = FakePermalinkBuilder(permalinkForUserLambda = { Result.success("") })
val presenter = createPresenter(
coroutineScope = this,
isRichTextEditorEnabled = false,
room = FakeJoinedRoom(
liveTimeline = FakeTimeline().apply {
@ -464,7 +459,6 @@ class MessageComposerPresenterTest {
typingNoticeResult = { Result.success(Unit) }
)
val presenter = createPresenter(
this,
joinedRoom,
)
moleculeFlow(RecompositionMode.Immediate) {
@ -520,7 +514,6 @@ class MessageComposerPresenterTest {
editMessageLambda = roomEditMessageLambda,
)
val presenter = createPresenter(
this,
joinedRoom,
)
moleculeFlow(RecompositionMode.Immediate) {
@ -576,7 +569,6 @@ class MessageComposerPresenterTest {
typingNoticeResult = { Result.success(Unit) },
)
val presenter = createPresenter(
this,
joinedRoom,
)
moleculeFlow(RecompositionMode.Immediate) {
@ -628,7 +620,6 @@ class MessageComposerPresenterTest {
typingNoticeResult = { Result.success(Unit) }
)
val presenter = createPresenter(
this,
joinedRoom,
)
moleculeFlow(RecompositionMode.Immediate) {
@ -666,7 +657,7 @@ class MessageComposerPresenterTest {
@Test
fun `present - Open attachments menu`() = runTest {
val presenter = createPresenter(this)
val presenter = createPresenter()
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
@ -679,7 +670,7 @@ class MessageComposerPresenterTest {
@Test
fun `present - Dismiss attachments menu`() = runTest {
val presenter = createPresenter(this)
val presenter = createPresenter()
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
@ -702,7 +693,6 @@ class MessageComposerPresenterTest {
onPreviewAttachmentLambda = onPreviewAttachmentLambda
)
val presenter = createPresenter(
coroutineScope = this,
room = room,
navigator = navigator,
)
@ -743,7 +733,6 @@ class MessageComposerPresenterTest {
onPreviewAttachmentLambda = onPreviewAttachmentLambda
)
val presenter = createPresenter(
coroutineScope = this,
room = room,
navigator = navigator,
)
@ -777,7 +766,7 @@ class MessageComposerPresenterTest {
@Test
fun `present - Pick media from gallery & cancel does nothing`() = runTest {
val presenter = createPresenter(this)
val presenter = createPresenter()
with(pickerProvider) {
givenResult(null) // Simulate a user canceling the flow
givenMimeType(MimeTypes.Images)
@ -801,7 +790,6 @@ class MessageComposerPresenterTest {
onPreviewAttachmentLambda = onPreviewAttachmentLambda
)
val presenter = createPresenter(
coroutineScope = this,
room = room,
navigator = navigator,
)
@ -819,7 +807,7 @@ class MessageComposerPresenterTest {
val room = FakeJoinedRoom(
typingNoticeResult = { Result.success(Unit) }
)
val presenter = createPresenter(this, room = room)
val presenter = createPresenter(room = room)
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
@ -838,7 +826,7 @@ class MessageComposerPresenterTest {
val room = FakeJoinedRoom(
typingNoticeResult = { Result.success(Unit) }
)
val presenter = createPresenter(this, room = room)
val presenter = createPresenter(room = room)
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
@ -863,7 +851,6 @@ class MessageComposerPresenterTest {
onPreviewAttachmentLambda = onPreviewAttachmentLambda
)
val presenter = createPresenter(
coroutineScope = this,
room = room,
permissionPresenter = permissionPresenter,
navigator = navigator,
@ -888,7 +875,6 @@ class MessageComposerPresenterTest {
onPreviewAttachmentLambda = onPreviewAttachmentLambda
)
val presenter = createPresenter(
coroutineScope = this,
room = room,
permissionPresenter = permissionPresenter,
navigator = navigator,
@ -915,7 +901,6 @@ class MessageComposerPresenterTest {
onPreviewAttachmentLambda = onPreviewAttachmentLambda
)
val presenter = createPresenter(
coroutineScope = this,
room = room,
permissionPresenter = permissionPresenter,
navigator = navigator,
@ -940,7 +925,6 @@ class MessageComposerPresenterTest {
onPreviewAttachmentLambda = onPreviewAttachmentLambda
)
val presenter = createPresenter(
coroutineScope = this,
room = room,
permissionPresenter = permissionPresenter,
navigator = navigator,
@ -961,7 +945,7 @@ class MessageComposerPresenterTest {
@Test
fun `present - errors are tracked`() = runTest {
val testException = Exception("Test error")
val presenter = createPresenter(this)
val presenter = createPresenter()
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
@ -973,7 +957,7 @@ class MessageComposerPresenterTest {
@Test
fun `present - ToggleTextFormatting toggles text formatting`() = runTest {
val presenter = createPresenter(this, isRichTextEditorEnabled = false)
val presenter = createPresenter(isRichTextEditorEnabled = false)
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
@ -1017,7 +1001,7 @@ class MessageComposerPresenterTest {
)
givenRoomInfo(aRoomInfo(isDirect = false))
}
val presenter = createPresenter(this, room)
val presenter = createPresenter(room)
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
@ -1078,7 +1062,7 @@ class MessageComposerPresenterTest {
)
)
}
val presenter = createPresenter(this, room)
val presenter = createPresenter(room)
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
@ -1094,7 +1078,6 @@ class MessageComposerPresenterTest {
fun `present - InsertSuggestion`() = runTest {
val presenter = createPresenter(
coroutineScope = this,
permalinkBuilder = FakePermalinkBuilder(
permalinkForUserLambda = {
Result.success("https://matrix.to/#/${A_USER_ID_2.value}")
@ -1134,7 +1117,7 @@ class MessageComposerPresenterTest {
liveTimeline = timeline,
typingNoticeResult = { Result.success(Unit) }
)
val presenter = createPresenter(room = room, coroutineScope = this)
val presenter = createPresenter(room = room)
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
@ -1197,7 +1180,16 @@ class MessageComposerPresenterTest {
@Test
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) {
val state = presenter.present()
remember(state, state.textEditorState.messageHtml()) { state }
@ -1214,7 +1206,7 @@ class MessageComposerPresenterTest {
val room = FakeJoinedRoom(
typingNoticeResult = typingNoticeResult,
)
val presenter = createPresenter(room = room, coroutineScope = this)
val presenter = createPresenter(room = room)
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
@ -1240,7 +1232,7 @@ class MessageComposerPresenterTest {
val store = InMemorySessionPreferencesStore(
isSendTypingNotificationsEnabled = false
)
val presenter = createPresenter(room = room, sessionPreferencesStore = store, coroutineScope = this)
val presenter = createPresenter(room = room, sessionPreferencesStore = store)
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
@ -1258,7 +1250,7 @@ class MessageComposerPresenterTest {
val composerDraftService = FakeComposerDraftService().apply {
this.loadDraftLambda = loadDraftLambda
}
val presenter = createPresenter(draftService = composerDraftService, coroutineScope = this)
val presenter = createPresenter(draftService = composerDraftService)
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
@ -1283,7 +1275,6 @@ class MessageComposerPresenterTest {
val presenter = createPresenter(
draftService = composerDraftService,
permalinkBuilder = permalinkBuilder,
coroutineScope = this
)
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
@ -1317,7 +1308,6 @@ class MessageComposerPresenterTest {
val presenter = createPresenter(
draftService = composerDraftService,
permalinkBuilder = permalinkBuilder,
coroutineScope = this
)
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
@ -1351,7 +1341,6 @@ class MessageComposerPresenterTest {
val presenter = createPresenter(
draftService = composerDraftService,
permalinkBuilder = permalinkBuilder,
coroutineScope = this
)
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
@ -1398,7 +1387,6 @@ class MessageComposerPresenterTest {
room = room,
draftService = composerDraftService,
permalinkBuilder = permalinkBuilder,
coroutineScope = this
)
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
@ -1428,7 +1416,7 @@ class MessageComposerPresenterTest {
val composerDraftService = FakeComposerDraftService().apply {
this.saveDraftLambda = saveDraftLambda
}
val presenter = createPresenter(draftService = composerDraftService, coroutineScope = this)
val presenter = createPresenter(draftService = composerDraftService)
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
@ -1452,7 +1440,6 @@ class MessageComposerPresenterTest {
isRichTextEditorEnabled = false,
draftService = composerDraftService,
permalinkBuilder = permalinkBuilder,
coroutineScope = this
)
moleculeFlow(RecompositionMode.Immediate) {
val state = presenter.present()
@ -1528,18 +1515,17 @@ class MessageComposerPresenterTest {
return normalState
}
private fun createPresenter(
coroutineScope: CoroutineScope,
private fun TestScope.createPresenter(
room: JoinedRoom = FakeJoinedRoom(
typingNoticeResult = { Result.success(Unit) }
),
navigator: MessagesNavigator = FakeMessagesNavigator(),
pickerProvider: PickerProvider = this.pickerProvider,
featureFlagService: FeatureFlagService = this.featureFlagService,
pickerProvider: PickerProvider = this@MessageComposerPresenterTest.pickerProvider,
featureFlagService: FeatureFlagService = this@MessageComposerPresenterTest.featureFlagService,
locationService: LocationService = FakeLocationService(true),
sessionPreferencesStore: SessionPreferencesStore = InMemorySessionPreferencesStore(),
mediaPreProcessor: MediaPreProcessor = this.mediaPreProcessor,
snackbarDispatcher: SnackbarDispatcher = this.snackbarDispatcher,
mediaPreProcessor: MediaPreProcessor = this@MessageComposerPresenterTest.mediaPreProcessor,
snackbarDispatcher: SnackbarDispatcher = this@MessageComposerPresenterTest.snackbarDispatcher,
permissionPresenter: PermissionsPresenter = FakePermissionsPresenter(),
permalinkBuilder: PermalinkBuilder = FakePermalinkBuilder(),
permalinkParser: PermalinkParser = FakePermalinkParser(),
@ -1553,7 +1539,7 @@ class MessageComposerPresenterTest {
draftService: ComposerDraftService = FakeComposerDraftService(),
) = MessageComposerPresenter(
navigator = navigator,
appCoroutineScope = coroutineScope,
appCoroutineScope = this,
room = room,
mediaPickerProvider = pickerProvider,
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.lambdaRecorder
import io.element.android.tests.testutils.testCoroutineDispatchers
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.getAndUpdate
@ -155,7 +154,6 @@ class PollHistoryPresenterTest {
private fun TestScope.createPollHistoryPresenter(
room: FakeJoinedRoom = FakeJoinedRoom(),
appCoroutineScope: CoroutineScope = this,
endPollAction: EndPollAction = FakeEndPollAction(),
sendPollResponseAction: SendPollResponseAction = FakeSendPollResponseAction(),
pollHistoryItemFactory: PollHistoryItemsFactory = PollHistoryItemsFactory(
@ -165,7 +163,7 @@ class PollHistoryPresenterTest {
),
): PollHistoryPresenter {
return PollHistoryPresenter(
appCoroutineScope = appCoroutineScope,
appCoroutineScope = this,
sendPollResponseAction = sendPollResponseAction,
endPollAction = endPollAction,
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_SESSION_ID
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.encryption.FakeEncryptionService
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 {
val room = aJoinedRoom(
canInviteResult = { Result.success(false) },
canKickResult = { Result.success(false) },
canBanResult = { Result.success(false) },
canUserJoinCallResult = { Result.success(true) },
canSendStateResult = { _, _ -> Result.success(true) },
)
@ -277,6 +280,8 @@ class RoomDetailsPresenterTest {
else -> Result.failure(Throwable("Whelp"))
}
},
canBanResult = { Result.success(false) },
canKickResult = { Result.success(false) },
canInviteResult = { Result.success(false) },
canUserJoinCallResult = { Result.success(true) },
)
@ -304,6 +309,8 @@ class RoomDetailsPresenterTest {
else -> Result.failure(Throwable("Whelp"))
}
},
canKickResult = { Result.success(false) },
canBanResult = { Result.success(false) },
canInviteResult = { Result.success(false) },
canUserJoinCallResult = { Result.success(true) },
getUpdatedMemberResult = { userId ->
@ -353,6 +360,8 @@ class RoomDetailsPresenterTest {
else -> Result.failure(Throwable("Whelp"))
}
},
userDisplayNameResult = { Result.success(A_USER_NAME) },
userAvatarUrlResult = { Result.success(AN_AVATAR_URL) },
canInviteResult = { Result.success(true) },
canUserJoinCallResult = { Result.success(true) },
getUpdatedMemberResult = { userId ->
@ -397,6 +406,12 @@ class RoomDetailsPresenterTest {
else -> Result.failure(Throwable("Whelp"))
}
},
canKickResult = {
Result.success(false)
},
canBanResult = {
Result.success(false)
},
canInviteResult = {
Result.success(false)
},
@ -424,6 +439,12 @@ class RoomDetailsPresenterTest {
else -> Result.failure(Throwable("Whelp"))
}
},
canBanResult = {
Result.success(false)
},
canKickResult = {
Result.success(false)
},
canInviteResult = {
Result.success(false)
},
@ -450,6 +471,12 @@ class RoomDetailsPresenterTest {
else -> Result.failure(Throwable("Whelp"))
}
},
canKickResult = {
Result.success(false)
},
canBanResult = {
Result.success(false)
},
canInviteResult = {
Result.success(false)
},
@ -476,6 +503,12 @@ class RoomDetailsPresenterTest {
else -> Result.failure(Throwable("Whelp"))
}
},
canKickResult = {
Result.success(false)
},
canBanResult = {
Result.success(false)
},
canInviteResult = {
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.alias.ResolvedRoomAlias
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.FakeMatrixClient
import io.element.android.libraries.matrix.test.room.FakeJoinedRoom
@ -289,7 +290,14 @@ class EditBaseRoomAddressPresenterTest {
val navigator = FakeSecurityAndPrivacyNavigator(
closeEditRoomAddressLambda = closeEditAddressLambda
)
val presenter = createEditRoomAddressPresenter(navigator = navigator)
val presenter = createEditRoomAddressPresenter(
navigator = navigator,
room = FakeJoinedRoom(
publishRoomAliasInRoomDirectoryResult = {
Result.failure(AN_EXCEPTION)
},
)
)
presenter.test {
with(awaitItem()) {
eventSink(EditRoomAddressEvents.RoomAddressChanged("valid"))
@ -313,7 +321,13 @@ class EditBaseRoomAddressPresenterTest {
@Test
fun `present - dismiss error`() = runTest {
val presenter = createEditRoomAddressPresenter()
val presenter = createEditRoomAddressPresenter(
room = FakeJoinedRoom(
publishRoomAliasInRoomDirectoryResult = {
Result.failure(AN_EXCEPTION)
},
)
)
presenter.test {
with(awaitItem()) {
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.verification.FakeSessionVerificationService
import io.element.android.tests.testutils.lambda.lambdaRecorder
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.advanceUntilIdle
@ -132,11 +131,10 @@ class ResetIdentityFlowManagerTest {
private fun TestScope.createFlowManager(
encryptionService: FakeEncryptionService = FakeEncryptionService(),
client: FakeMatrixClient = FakeMatrixClient(encryptionService = encryptionService),
sessionCoroutineScope: CoroutineScope = this,
sessionVerificationService: FakeSessionVerificationService = FakeSessionVerificationService(),
) = ResetIdentityFlowManager(
matrixClient = client,
sessionCoroutineScope = sessionCoroutineScope,
sessionCoroutineScope = this,
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.room.aRoomInfo
import io.element.android.tests.testutils.testCoroutineDispatchers
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.isActive
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runTest
@ -24,18 +23,13 @@ import org.junit.Test
class RustBaseRoomTest {
@Test
fun `RustBaseRoom should cancel the room coroutine scope when it is destroyed`() = runTest {
val rustBaseRoom = createRustBaseRoom(
// Not using backgroundScope here, but the test scope
sessionCoroutineScope = this
)
val rustBaseRoom = createRustBaseRoom()
assertThat(rustBaseRoom.roomCoroutineScope.isActive).isTrue()
rustBaseRoom.destroy()
assertThat(rustBaseRoom.roomCoroutineScope.isActive).isFalse()
}
private fun TestScope.createRustBaseRoom(
sessionCoroutineScope: CoroutineScope,
): RustBaseRoom {
private fun TestScope.createRustBaseRoom(): RustBaseRoom {
val dispatchers = testCoroutineDispatchers()
return RustBaseRoom(
sessionId = A_SESSION_ID,
@ -47,7 +41,8 @@ class RustBaseRoomTest {
dispatchers = dispatchers,
),
roomMembershipObserver = RoomMembershipObserver(),
sessionCoroutineScope = sessionCoroutineScope,
// Not using backgroundScope here, but the test scope
sessionCoroutineScope = this,
roomInfoMapper = RoomInfoMapper(),
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.fakes.FakeRustRoomDirectorySearch
import io.element.android.libraries.matrix.test.A_ROOM_ID_2
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.TestScope
@ -31,7 +30,6 @@ class RustBaseRoomDirectoryListTest {
val mapper = RoomDescriptionMapper()
val sut = createRustRoomDirectoryList(
roomDirectorySearch = roomDirectorySearch,
scope = backgroundScope,
)
// Let the mxCallback be ready
runCurrent()
@ -81,10 +79,9 @@ class RustBaseRoomDirectoryListTest {
private fun TestScope.createRustRoomDirectoryList(
roomDirectorySearch: RoomDirectorySearch = FakeRustRoomDirectorySearch(),
scope: CoroutineScope,
) = RustRoomDirectoryList(
inner = roomDirectorySearch,
coroutineScope = scope,
coroutineScope = backgroundScope,
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.room.RoomSyncSubscriber
import io.element.android.tests.testutils.testCoroutineDispatchers
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.TestScope
@ -28,7 +27,6 @@ class RustBaseRoomListServiceTest {
fun `syncIndicator should emit the expected values`() = runTest {
val roomListService = FakeRustRoomListService()
val sut = createRustRoomListService(
sessionCoroutineScope = backgroundScope,
roomListService = roomListService,
)
// Give time for mxCallback to setup
@ -44,18 +42,17 @@ class RustBaseRoomListServiceTest {
}
private fun TestScope.createRustRoomListService(
sessionCoroutineScope: CoroutineScope,
roomListService: RustRoomListService = FakeRustRoomListService(),
) = RustRoomListService(
innerRoomListService = roomListService,
sessionDispatcher = StandardTestDispatcher(testScheduler),
roomListFactory = RoomListFactory(
innerRoomListService = roomListService,
sessionCoroutineScope = sessionCoroutineScope,
sessionCoroutineScope = backgroundScope,
),
roomSyncSubscriber = RoomSyncSubscriber(
roomListService = roomListService,
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.lambdaRecorder
import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
@ -38,7 +37,6 @@ class TimelineItemsSubscriberTest {
MutableSharedFlow(replay = 1, extraBufferCapacity = Int.MAX_VALUE)
val timeline = FakeRustTimeline()
val timelineItemsSubscriber = createTimelineItemsSubscriber(
coroutineScope = backgroundScope,
timeline = timeline,
timelineItems = timelineItems,
)
@ -59,7 +57,6 @@ class TimelineItemsSubscriberTest {
MutableSharedFlow(replay = 1, extraBufferCapacity = Int.MAX_VALUE)
val timeline = FakeRustTimeline()
val timelineItemsSubscriber = createTimelineItemsSubscriber(
coroutineScope = backgroundScope,
timeline = timeline,
timelineItems = timelineItems,
)
@ -81,7 +78,6 @@ class TimelineItemsSubscriberTest {
val timeline = FakeRustTimeline()
val onNewSyncedEventRecorder = lambdaRecorder<Unit> { }
val timelineItemsSubscriber = createTimelineItemsSubscriber(
coroutineScope = backgroundScope,
timeline = timeline,
timelineItems = timelineItems,
onNewSyncedEvent = onNewSyncedEventRecorder,
@ -109,9 +105,7 @@ class TimelineItemsSubscriberTest {
@Test
fun `multiple subscriptions does not have side effect`() = runTest {
val timelineItemsSubscriber = createTimelineItemsSubscriber(
coroutineScope = backgroundScope,
)
val timelineItemsSubscriber = createTimelineItemsSubscriber()
timelineItemsSubscriber.subscribeIfNeeded()
timelineItemsSubscriber.subscribeIfNeeded()
timelineItemsSubscriber.unsubscribeIfNeeded()
@ -120,7 +114,6 @@ class TimelineItemsSubscriberTest {
}
private fun TestScope.createTimelineItemsSubscriber(
coroutineScope: CoroutineScope,
timeline: Timeline = FakeRustTimeline(),
timelineItems: MutableSharedFlow<List<MatrixTimelineItem>> = MutableSharedFlow(replay = 1, extraBufferCapacity = Int.MAX_VALUE),
initLatch: CompletableDeferred<Unit> = CompletableDeferred(),
@ -128,7 +121,7 @@ private fun TestScope.createTimelineItemsSubscriber(
onNewSyncedEvent: () -> Unit = { lambdaError() },
): TimelineItemsSubscriber {
return TimelineItemsSubscriber(
timelineCoroutineScope = coroutineScope,
timelineCoroutineScope = backgroundScope,
dispatcher = StandardTestDispatcher(testScheduler),
timeline = timeline,
timelineDiffProcessor = createMatrixTimelineDiffProcessor(timelineItems),

View file

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

View file

@ -7,8 +7,19 @@
package io.element.android.tests.testutils.lambda
import kotlin.system.exitProcess
fun lambdaError(
message: String = "This lambda should never be called."
): 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)
}