misc(power level) : update tests following api change

This commit is contained in:
ganfra
2025-12-09 20:50:31 +01:00
parent 29c1f33638
commit 5c8fd831e3
25 changed files with 475 additions and 637 deletions

View File

@@ -99,6 +99,7 @@ import timber.log.Timber
import kotlin.time.Duration.Companion.seconds import kotlin.time.Duration.Companion.seconds
import io.element.android.libraries.core.mimetype.MimeTypes.Any as AnyMimeTypes import io.element.android.libraries.core.mimetype.MimeTypes.Any as AnyMimeTypes
@Suppress("LargeClass")
@AssistedInject @AssistedInject
class MessageComposerPresenter( class MessageComposerPresenter(
@Assisted private val navigator: MessagesNavigator, @Assisted private val navigator: MessagesNavigator,
@@ -397,7 +398,7 @@ class MessageComposerPresenter(
val currentUserId = room.sessionId val currentUserId = room.sessionId
suspend fun canSendRoomMention(): Boolean { suspend fun canSendRoomMention(): Boolean {
val userCanSendAtRoom = room.roomPermissions().use(false){ perms -> val userCanSendAtRoom = room.roomPermissions().use(false) { perms ->
perms.canOwnUserTriggerRoomNotification() perms.canOwnUserTriggerRoomNotification()
} }
return !room.isDm() && userCanSendAtRoom return !room.isDm() && userCanSendAtRoom

View File

@@ -39,7 +39,6 @@ import io.element.android.features.poll.api.actions.EndPollAction
import io.element.android.features.poll.api.actions.SendPollResponseAction import io.element.android.features.poll.api.actions.SendPollResponseAction
import io.element.android.features.roomcall.api.RoomCallState import io.element.android.features.roomcall.api.RoomCallState
import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.architecture.Presenter
import io.element.android.libraries.core.bool.orFalse
import io.element.android.libraries.core.coroutine.CoroutineDispatchers import io.element.android.libraries.core.coroutine.CoroutineDispatchers
import io.element.android.libraries.di.annotations.SessionCoroutineScope import io.element.android.libraries.di.annotations.SessionCoroutineScope
import io.element.android.libraries.featureflag.api.FeatureFlagService import io.element.android.libraries.featureflag.api.FeatureFlagService
@@ -96,6 +95,7 @@ class TimelinePresenter(
private val analyticsService: AnalyticsService, private val analyticsService: AnalyticsService,
) : Presenter<TimelineState> { ) : Presenter<TimelineState> {
private val tag = "TimelinePresenter" private val tag = "TimelinePresenter"
@AssistedFactory @AssistedFactory
interface Factory { interface Factory {
fun create( fun create(

View File

@@ -64,6 +64,7 @@ import io.element.android.libraries.matrix.api.permalink.PermalinkParser
import io.element.android.libraries.matrix.api.room.MessageEventType import io.element.android.libraries.matrix.api.room.MessageEventType
import io.element.android.libraries.matrix.api.room.RoomMembersState import io.element.android.libraries.matrix.api.room.RoomMembersState
import io.element.android.libraries.matrix.api.room.RoomMembershipState import io.element.android.libraries.matrix.api.room.RoomMembershipState
import io.element.android.libraries.matrix.api.room.StateEventType
import io.element.android.libraries.matrix.api.room.tombstone.SuccessorRoom import io.element.android.libraries.matrix.api.room.tombstone.SuccessorRoom
import io.element.android.libraries.matrix.api.timeline.Timeline import io.element.android.libraries.matrix.api.timeline.Timeline
import io.element.android.libraries.matrix.api.timeline.item.TimelineItemDebugInfo import io.element.android.libraries.matrix.api.timeline.item.TimelineItemDebugInfo
@@ -86,6 +87,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.libraries.matrix.test.room.aRoomInfo import io.element.android.libraries.matrix.test.room.aRoomInfo
import io.element.android.libraries.matrix.test.room.aRoomMember import io.element.android.libraries.matrix.test.room.aRoomMember
import io.element.android.libraries.matrix.test.room.powerlevels.FakeRoomPermissions
import io.element.android.libraries.matrix.test.timeline.FakeTimeline import io.element.android.libraries.matrix.test.timeline.FakeTimeline
import io.element.android.libraries.matrix.test.timeline.aTimelineItemDebugInfo import io.element.android.libraries.matrix.test.timeline.aTimelineItemDebugInfo
import io.element.android.libraries.matrix.ui.messages.reply.InReplyToDetails import io.element.android.libraries.matrix.ui.messages.reply.InReplyToDetails
@@ -143,11 +145,7 @@ class MessagesPresenterTest {
fun `present - check that the room's unread flag is removed`() = runTest { fun `present - check that the room's unread flag is removed`() = runTest {
val room = FakeJoinedRoom( val room = FakeJoinedRoom(
baseRoom = FakeBaseRoom( baseRoom = FakeBaseRoom(
canUserSendMessageResult = { _, _ -> Result.success(true) }, roomPermissions = roomPermissions(),
canRedactOwnResult = { Result.success(true) },
canRedactOtherResult = { Result.success(true) },
canUserJoinCallResult = { Result.success(true) },
canUserPinUnpinResult = { Result.success(true) },
markAsReadResult = { lambdaError() } markAsReadResult = { lambdaError() }
), ),
typingNoticeResult = { Result.success(Unit) }, typingNoticeResult = { Result.success(Unit) },
@@ -173,11 +171,7 @@ class MessagesPresenterTest {
} }
val room = FakeJoinedRoom( val room = FakeJoinedRoom(
baseRoom = FakeBaseRoom( baseRoom = FakeBaseRoom(
canUserSendMessageResult = { _, _ -> Result.success(true) }, roomPermissions = roomPermissions(),
canRedactOwnResult = { Result.success(true) },
canRedactOtherResult = { Result.success(true) },
canUserJoinCallResult = { Result.success(true) },
canUserPinUnpinResult = { Result.success(true) },
), ),
liveTimeline = timeline, liveTimeline = timeline,
typingNoticeResult = { Result.success(Unit) }, typingNoticeResult = { Result.success(Unit) },
@@ -223,11 +217,7 @@ class MessagesPresenterTest {
} }
val room = FakeJoinedRoom( val room = FakeJoinedRoom(
baseRoom = FakeBaseRoom( baseRoom = FakeBaseRoom(
canUserSendMessageResult = { _, _ -> Result.success(true) }, roomPermissions = roomPermissions(),
canRedactOwnResult = { Result.success(true) },
canRedactOtherResult = { Result.success(true) },
canUserJoinCallResult = { Result.success(true) },
canUserPinUnpinResult = { Result.success(true) },
), ),
liveTimeline = timeline, liveTimeline = timeline,
typingNoticeResult = { Result.success(Unit) }, typingNoticeResult = { Result.success(Unit) },
@@ -288,11 +278,7 @@ class MessagesPresenterTest {
val event = aMessageEvent() val event = aMessageEvent()
val room = FakeJoinedRoom( val room = FakeJoinedRoom(
baseRoom = FakeBaseRoom( baseRoom = FakeBaseRoom(
canUserSendMessageResult = { _, _ -> Result.success(true) }, roomPermissions = roomPermissions(),
canRedactOwnResult = { Result.success(true) },
canRedactOtherResult = { Result.success(true) },
canUserJoinCallResult = { Result.success(true) },
canUserPinUnpinResult = { Result.success(true) },
eventPermalinkResult = { Result.success("a link") }, eventPermalinkResult = { Result.success("a link") },
), ),
typingNoticeResult = { Result.success(Unit) }, typingNoticeResult = { Result.success(Unit) },
@@ -514,11 +500,7 @@ class MessagesPresenterTest {
val liveTimeline = FakeTimeline() val liveTimeline = FakeTimeline()
val joinedRoom = FakeJoinedRoom( val joinedRoom = FakeJoinedRoom(
baseRoom = FakeBaseRoom( baseRoom = FakeBaseRoom(
canUserSendMessageResult = { _, _ -> Result.success(true) }, roomPermissions = roomPermissions(),
canRedactOwnResult = { Result.success(true) },
canRedactOtherResult = { Result.success(true) },
canUserJoinCallResult = { Result.success(true) },
canUserPinUnpinResult = { Result.success(true) },
), ),
liveTimeline = liveTimeline, liveTimeline = liveTimeline,
typingNoticeResult = { Result.success(Unit) }, typingNoticeResult = { Result.success(Unit) },
@@ -586,11 +568,7 @@ class MessagesPresenterTest {
fun `present - shows prompt to reinvite users in DM`() = runTest { fun `present - shows prompt to reinvite users in DM`() = runTest {
val room = FakeJoinedRoom( val room = FakeJoinedRoom(
baseRoom = FakeBaseRoom( baseRoom = FakeBaseRoom(
canUserSendMessageResult = { _, _ -> Result.success(true) }, roomPermissions = roomPermissions(),
canRedactOwnResult = { Result.success(true) },
canRedactOtherResult = { Result.success(true) },
canUserJoinCallResult = { Result.success(true) },
canUserPinUnpinResult = { Result.success(true) },
).apply { ).apply {
givenRoomInfo(aRoomInfo(isDirect = true, joinedMembersCount = 1, activeMembersCount = 1)) givenRoomInfo(aRoomInfo(isDirect = true, joinedMembersCount = 1, activeMembersCount = 1))
}, },
@@ -619,11 +597,7 @@ class MessagesPresenterTest {
fun `present - doesn't show reinvite prompt in non-direct room`() = runTest { fun `present - doesn't show reinvite prompt in non-direct room`() = runTest {
val room = FakeJoinedRoom( val room = FakeJoinedRoom(
baseRoom = FakeBaseRoom( baseRoom = FakeBaseRoom(
canUserSendMessageResult = { _, _ -> Result.success(true) }, roomPermissions = roomPermissions(),
canRedactOwnResult = { Result.success(true) },
canRedactOtherResult = { Result.success(true) },
canUserJoinCallResult = { Result.success(true) },
canUserPinUnpinResult = { Result.success(true) },
).apply { ).apply {
givenRoomInfo(aRoomInfo(isDirect = false, joinedMembersCount = 1, activeMembersCount = 1)) givenRoomInfo(aRoomInfo(isDirect = false, joinedMembersCount = 1, activeMembersCount = 1))
}, },
@@ -645,11 +619,7 @@ class MessagesPresenterTest {
fun `present - doesn't show reinvite prompt if other party is present`() = runTest { fun `present - doesn't show reinvite prompt if other party is present`() = runTest {
val room = FakeJoinedRoom( val room = FakeJoinedRoom(
baseRoom = FakeBaseRoom( baseRoom = FakeBaseRoom(
canUserSendMessageResult = { _, _ -> Result.success(true) }, roomPermissions = roomPermissions(),
canRedactOwnResult = { Result.success(true) },
canRedactOtherResult = { Result.success(true) },
canUserJoinCallResult = { Result.success(true) },
canUserPinUnpinResult = { Result.success(true) },
).apply { ).apply {
givenRoomInfo(aRoomInfo(isDirect = true, joinedMembersCount = 2, activeMembersCount = 2)) givenRoomInfo(aRoomInfo(isDirect = true, joinedMembersCount = 2, activeMembersCount = 2))
}, },
@@ -672,11 +642,7 @@ class MessagesPresenterTest {
val inviteUserResult = lambdaRecorder { _: UserId -> Result.success(Unit) } val inviteUserResult = lambdaRecorder { _: UserId -> Result.success(Unit) }
val room = FakeJoinedRoom( val room = FakeJoinedRoom(
baseRoom = FakeBaseRoom( baseRoom = FakeBaseRoom(
canUserSendMessageResult = { _, _ -> Result.success(true) }, roomPermissions = roomPermissions(),
canRedactOwnResult = { Result.success(true) },
canRedactOtherResult = { Result.success(true) },
canUserJoinCallResult = { Result.success(true) },
canUserPinUnpinResult = { Result.success(true) },
), ),
typingNoticeResult = { Result.success(Unit) }, typingNoticeResult = { Result.success(Unit) },
inviteUserResult = inviteUserResult, inviteUserResult = inviteUserResult,
@@ -707,11 +673,7 @@ class MessagesPresenterTest {
val inviteUserResult = lambdaRecorder { _: UserId -> Result.success(Unit) } val inviteUserResult = lambdaRecorder { _: UserId -> Result.success(Unit) }
val room = FakeJoinedRoom( val room = FakeJoinedRoom(
baseRoom = FakeBaseRoom( baseRoom = FakeBaseRoom(
canUserSendMessageResult = { _, _ -> Result.success(true) }, roomPermissions = roomPermissions(),
canRedactOwnResult = { Result.success(true) },
canRedactOtherResult = { Result.success(true) },
canUserJoinCallResult = { Result.success(true) },
canUserPinUnpinResult = { Result.success(true) },
), ),
typingNoticeResult = { Result.success(Unit) }, typingNoticeResult = { Result.success(Unit) },
inviteUserResult = inviteUserResult, inviteUserResult = inviteUserResult,
@@ -744,11 +706,7 @@ class MessagesPresenterTest {
fun `present - handle reinviting other user when memberlist is not ready`() = runTest { fun `present - handle reinviting other user when memberlist is not ready`() = runTest {
val room = FakeJoinedRoom( val room = FakeJoinedRoom(
baseRoom = FakeBaseRoom( baseRoom = FakeBaseRoom(
canUserSendMessageResult = { _, _ -> Result.success(true) }, roomPermissions = roomPermissions(),
canRedactOwnResult = { Result.success(true) },
canRedactOtherResult = { Result.success(true) },
canUserJoinCallResult = { Result.success(true) },
canUserPinUnpinResult = { Result.success(true) },
), ),
typingNoticeResult = { Result.success(Unit) }, typingNoticeResult = { Result.success(Unit) },
) )
@@ -769,11 +727,7 @@ class MessagesPresenterTest {
fun `present - handle reinviting other user when inviting fails`() = runTest { fun `present - handle reinviting other user when inviting fails`() = runTest {
val room = FakeJoinedRoom( val room = FakeJoinedRoom(
baseRoom = FakeBaseRoom( baseRoom = FakeBaseRoom(
canUserSendMessageResult = { _, _ -> Result.success(true) }, roomPermissions = roomPermissions(),
canRedactOwnResult = { Result.success(true) },
canRedactOtherResult = { Result.success(true) },
canUserJoinCallResult = { Result.success(true) },
canUserPinUnpinResult = { Result.success(true) },
), ),
typingNoticeResult = { Result.success(Unit) }, typingNoticeResult = { Result.success(Unit) },
inviteUserResult = { Result.failure(RuntimeException("Oops!")) }, inviteUserResult = { Result.failure(RuntimeException("Oops!")) },
@@ -807,17 +761,7 @@ class MessagesPresenterTest {
fun `present - permission to post`() = runTest { fun `present - permission to post`() = runTest {
val room = FakeJoinedRoom( val room = FakeJoinedRoom(
baseRoom = FakeBaseRoom( baseRoom = FakeBaseRoom(
canRedactOwnResult = { Result.success(true) }, roomPermissions = roomPermissions(),
canRedactOtherResult = { Result.success(true) },
canUserJoinCallResult = { Result.success(true) },
canUserPinUnpinResult = { Result.success(true) },
canUserSendMessageResult = { _, messageEventType ->
when (messageEventType) {
MessageEventType.RoomMessage -> Result.success(true)
MessageEventType.Reaction -> Result.success(true)
else -> lambdaError()
}
},
), ),
typingNoticeResult = { Result.success(Unit) }, typingNoticeResult = { Result.success(Unit) },
) )
@@ -833,17 +777,9 @@ class MessagesPresenterTest {
fun `present - no permission to post`() = runTest { fun `present - no permission to post`() = runTest {
val room = FakeJoinedRoom( val room = FakeJoinedRoom(
baseRoom = FakeBaseRoom( baseRoom = FakeBaseRoom(
canRedactOwnResult = { Result.success(true) }, roomPermissions = roomPermissions(
canRedactOtherResult = { Result.success(true) }, canSendMessage = false
canUserJoinCallResult = { Result.success(true) }, ),
canUserPinUnpinResult = { Result.success(true) },
canUserSendMessageResult = { _, messageEventType ->
when (messageEventType) {
MessageEventType.RoomMessage -> Result.success(false)
MessageEventType.Reaction -> Result.success(false)
else -> lambdaError()
}
},
), ),
typingNoticeResult = { Result.success(Unit) }, typingNoticeResult = { Result.success(Unit) },
) )
@@ -859,11 +795,9 @@ class MessagesPresenterTest {
fun `present - permission to redact own`() = runTest { fun `present - permission to redact own`() = runTest {
val joinedRoom = FakeJoinedRoom( val joinedRoom = FakeJoinedRoom(
baseRoom = FakeBaseRoom( baseRoom = FakeBaseRoom(
canRedactOwnResult = { Result.success(true) }, roomPermissions = roomPermissions(
canUserSendMessageResult = { _, _ -> Result.success(true) }, canRedactOther = false
canRedactOtherResult = { Result.success(false) }, ),
canUserJoinCallResult = { Result.success(true) },
canUserPinUnpinResult = { Result.success(true) },
), ),
typingNoticeResult = { Result.success(Unit) }, typingNoticeResult = { Result.success(Unit) },
) )
@@ -880,11 +814,9 @@ class MessagesPresenterTest {
fun `present - permission to redact other`() = runTest { fun `present - permission to redact other`() = runTest {
val joinedRoom = FakeJoinedRoom( val joinedRoom = FakeJoinedRoom(
baseRoom = FakeBaseRoom( baseRoom = FakeBaseRoom(
canRedactOtherResult = { Result.success(true) }, roomPermissions = roomPermissions(
canUserSendMessageResult = { _, _ -> Result.success(true) }, canRedactOwn = false
canRedactOwnResult = { Result.success(false) }, ),
canUserJoinCallResult = { Result.success(true) },
canUserPinUnpinResult = { Result.success(true) },
), ),
typingNoticeResult = { Result.success(Unit) }, typingNoticeResult = { Result.success(Unit) },
) )
@@ -929,11 +861,7 @@ class MessagesPresenterTest {
val timeline = FakeTimeline() val timeline = FakeTimeline()
val room = FakeJoinedRoom( val room = FakeJoinedRoom(
baseRoom = FakeBaseRoom( baseRoom = FakeBaseRoom(
canUserSendMessageResult = { _, _ -> Result.success(true) }, roomPermissions = roomPermissions(),
canRedactOwnResult = { Result.success(true) },
canRedactOtherResult = { Result.success(true) },
canUserJoinCallResult = { Result.success(true) },
canUserPinUnpinResult = { Result.success(true) },
), ),
liveTimeline = timeline, liveTimeline = timeline,
typingNoticeResult = { Result.success(Unit) }, typingNoticeResult = { Result.success(Unit) },
@@ -973,11 +901,7 @@ class MessagesPresenterTest {
val analyticsService = FakeAnalyticsService() val analyticsService = FakeAnalyticsService()
val room = FakeJoinedRoom( val room = FakeJoinedRoom(
baseRoom = FakeBaseRoom( baseRoom = FakeBaseRoom(
canUserSendMessageResult = { _, _ -> Result.success(true) }, roomPermissions = roomPermissions(),
canRedactOwnResult = { Result.success(true) },
canRedactOtherResult = { Result.success(true) },
canUserJoinCallResult = { Result.success(true) },
canUserPinUnpinResult = { Result.success(true) },
), ),
liveTimeline = timeline, liveTimeline = timeline,
typingNoticeResult = { Result.success(Unit) }, typingNoticeResult = { Result.success(Unit) },
@@ -1074,11 +998,7 @@ class MessagesPresenterTest {
} }
val room = FakeJoinedRoom( val room = FakeJoinedRoom(
baseRoom = FakeBaseRoom( baseRoom = FakeBaseRoom(
canUserSendMessageResult = { _, _ -> Result.success(true) }, roomPermissions = roomPermissions(),
canRedactOwnResult = { Result.success(true) },
canRedactOtherResult = { Result.success(true) },
canUserJoinCallResult = { Result.success(true) },
canUserPinUnpinResult = { Result.success(true) },
), ),
liveTimeline = timeline, liveTimeline = timeline,
typingNoticeResult = { Result.success(Unit) }, typingNoticeResult = { Result.success(Unit) },
@@ -1115,11 +1035,7 @@ class MessagesPresenterTest {
val successorReason = "This room has been moved to a new location" val successorReason = "This room has been moved to a new location"
val room = FakeJoinedRoom( val room = FakeJoinedRoom(
baseRoom = FakeBaseRoom( baseRoom = FakeBaseRoom(
canUserSendMessageResult = { _, _ -> Result.success(true) }, roomPermissions = roomPermissions(),
canRedactOwnResult = { Result.success(true) },
canRedactOtherResult = { Result.success(true) },
canUserJoinCallResult = { Result.success(true) },
canUserPinUnpinResult = { Result.success(true) },
initialRoomInfo = aRoomInfo( initialRoomInfo = aRoomInfo(
successorRoom = SuccessorRoom( successorRoom = SuccessorRoom(
roomId = successorRoomId, roomId = successorRoomId,
@@ -1143,11 +1059,7 @@ class MessagesPresenterTest {
fun `present - room without successor room has null successor info in state`() = runTest { fun `present - room without successor room has null successor info in state`() = runTest {
val room = FakeJoinedRoom( val room = FakeJoinedRoom(
baseRoom = FakeBaseRoom( baseRoom = FakeBaseRoom(
canUserSendMessageResult = { _, _ -> Result.success(true) }, roomPermissions = roomPermissions(),
canRedactOwnResult = { Result.success(true) },
canRedactOtherResult = { Result.success(true) },
canUserJoinCallResult = { Result.success(true) },
canUserPinUnpinResult = { Result.success(true) },
initialRoomInfo = aRoomInfo(successorRoom = null) initialRoomInfo = aRoomInfo(successorRoom = null)
), ),
typingNoticeResult = { Result.success(Unit) }, typingNoticeResult = { Result.success(Unit) },
@@ -1165,11 +1077,13 @@ class MessagesPresenterTest {
val room = FakeJoinedRoom( val room = FakeJoinedRoom(
baseRoom = FakeBaseRoom( baseRoom = FakeBaseRoom(
sessionId = A_SESSION_ID, sessionId = A_SESSION_ID,
canUserSendMessageResult = { _, _ -> Result.success(true) }, roomPermissions = FakeRoomPermissions(
canRedactOwnResult = { Result.success(true) }, canSendState = { true },
canRedactOtherResult = { Result.success(true) }, canSendMessage = { true },
canUserJoinCallResult = { Result.success(true) }, canRedactOther = true,
canUserPinUnpinResult = { Result.success(true) }, canRedactOwn = true,
canPinUnpin = true,
),
initialRoomInfo = aRoomInfo(isDirect = true, isEncrypted = true) initialRoomInfo = aRoomInfo(isDirect = true, isEncrypted = true)
).apply { ).apply {
givenRoomMembersState(RoomMembersState.Ready(persistentListOf(aRoomMember(userId = A_SESSION_ID), aRoomMember(userId = A_USER_ID_2)))) givenRoomMembersState(RoomMembersState.Ready(persistentListOf(aRoomMember(userId = A_SESSION_ID), aRoomMember(userId = A_USER_ID_2))))
@@ -1312,16 +1226,44 @@ class MessagesPresenterTest {
} }
} }
private fun roomPermissions(
canStartCall: Boolean = true,
canRedactOther: Boolean = true,
canRedactOwn: Boolean = true,
canSendMessage: Boolean = true,
canSendReaction: Boolean = true,
canPinUnpin: Boolean = true,
) = FakeRoomPermissions(
canSendState = { type ->
when (type) {
StateEventType.CALL_MEMBER -> canStartCall
else -> lambdaError()
}
},
canSendMessage = { type ->
when (type) {
MessageEventType.RoomMessage -> canSendMessage
MessageEventType.Reaction -> canSendReaction
else -> lambdaError()
}
},
canRedactOther = canRedactOther,
canRedactOwn = canRedactOwn,
canPinUnpin = canPinUnpin,
)
private fun TestScope.createMessagesPresenter( private fun TestScope.createMessagesPresenter(
coroutineDispatchers: CoroutineDispatchers = testCoroutineDispatchers(), coroutineDispatchers: CoroutineDispatchers = testCoroutineDispatchers(),
timeline: Timeline = FakeTimeline(), timeline: Timeline = FakeTimeline(),
joinedRoom: FakeJoinedRoom = FakeJoinedRoom( joinedRoom: FakeJoinedRoom = FakeJoinedRoom(
baseRoom = FakeBaseRoom( baseRoom = FakeBaseRoom(
canUserSendMessageResult = { _, _ -> Result.success(true) }, roomPermissions = FakeRoomPermissions(
canRedactOwnResult = { Result.success(true) }, canSendState = { true },
canRedactOtherResult = { Result.success(true) }, canSendMessage = { true },
canUserJoinCallResult = { Result.success(true) }, canRedactOther = true,
canUserPinUnpinResult = { Result.success(true) }, canRedactOwn = true,
canPinUnpin = true,
),
).apply { ).apply {
givenRoomInfo(aRoomInfo(id = roomId, name = "")) givenRoomInfo(aRoomInfo(id = roomId, name = ""))
}, },

View File

@@ -69,6 +69,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.libraries.matrix.test.room.aRoomInfo import io.element.android.libraries.matrix.test.room.aRoomInfo
import io.element.android.libraries.matrix.test.room.aRoomMember import io.element.android.libraries.matrix.test.room.aRoomMember
import io.element.android.libraries.matrix.test.room.powerlevels.FakeRoomPermissions
import io.element.android.libraries.matrix.test.timeline.FakeTimeline import io.element.android.libraries.matrix.test.timeline.FakeTimeline
import io.element.android.libraries.matrix.ui.messages.reply.InReplyToDetails import io.element.android.libraries.matrix.ui.messages.reply.InReplyToDetails
import io.element.android.libraries.mediapickers.api.PickerProvider import io.element.android.libraries.mediapickers.api.PickerProvider
@@ -991,9 +992,12 @@ class MessageComposerPresenterTest {
val invitedUser = aRoomMember(userId = A_USER_ID_3, membership = RoomMembershipState.INVITE) val invitedUser = aRoomMember(userId = A_USER_ID_3, membership = RoomMembershipState.INVITE)
val bob = aRoomMember(userId = A_USER_ID_2, membership = RoomMembershipState.JOIN) val bob = aRoomMember(userId = A_USER_ID_2, membership = RoomMembershipState.JOIN)
val david = aRoomMember(userId = A_USER_ID_4, displayName = "Dave", membership = RoomMembershipState.JOIN) val david = aRoomMember(userId = A_USER_ID_4, displayName = "Dave", membership = RoomMembershipState.JOIN)
var canUserTriggerRoomNotificationResult = true
val room = FakeJoinedRoom( val room = FakeJoinedRoom(
baseRoom = FakeBaseRoom(canUserTriggerRoomNotificationResult = { Result.success(canUserTriggerRoomNotificationResult) }), baseRoom = FakeBaseRoom(
roomPermissions = FakeRoomPermissions(
canTriggerRoomNotification = true,
)
),
typingNoticeResult = { Result.success(Unit) } typingNoticeResult = { Result.success(Unit) }
).apply { ).apply {
givenRoomMembersState( givenRoomMembersState(
@@ -1033,10 +1037,38 @@ class MessageComposerPresenterTest {
// If the suggestion isn't a mention, no suggestions are returned // If the suggestion isn't a mention, no suggestions are returned
initialState.eventSink(MessageComposerEvent.SuggestionReceived(Suggestion(0, 0, SuggestionType.Command, ""))) initialState.eventSink(MessageComposerEvent.SuggestionReceived(Suggestion(0, 0, SuggestionType.Command, "")))
assertThat(awaitItem().suggestions).isEmpty() assertThat(awaitItem().suggestions).isEmpty()
}
}
// If user has no permission to send `@room` mentions, `RoomMemberSuggestion.Room` is not returned @Test
canUserTriggerRoomNotificationResult = false fun `present - room mention suggestions no permission`() = runTest {
val currentUser = aRoomMember(userId = A_USER_ID, membership = RoomMembershipState.JOIN)
val invitedUser = aRoomMember(userId = A_USER_ID_3, membership = RoomMembershipState.INVITE)
val bob = aRoomMember(userId = A_USER_ID_2, membership = RoomMembershipState.JOIN)
val david = aRoomMember(userId = A_USER_ID_4, displayName = "Dave", membership = RoomMembershipState.JOIN)
val room = FakeJoinedRoom(
baseRoom = FakeBaseRoom(
roomPermissions = FakeRoomPermissions(
canTriggerRoomNotification = false,
)
),
typingNoticeResult = { Result.success(Unit) }
).apply {
givenRoomMembersState(
RoomMembersState.Ready(
persistentListOf(currentUser, invitedUser, bob, david),
)
)
givenRoomInfo(aRoomInfo(isDirect = false))
}
val presenter = createPresenter(room)
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
val initialState = awaitItem()
// An empty suggestion returns the joined members that are not the current user, but not the room
initialState.eventSink(MessageComposerEvent.SuggestionReceived(Suggestion(0, 0, SuggestionType.Mention, ""))) initialState.eventSink(MessageComposerEvent.SuggestionReceived(Suggestion(0, 0, SuggestionType.Mention, "")))
skipItems(1)
assertThat(awaitItem().suggestions) assertThat(awaitItem().suggestions)
.containsExactly(ResolvedSuggestion.Member(bob), ResolvedSuggestion.Member(david)) .containsExactly(ResolvedSuggestion.Member(bob), ResolvedSuggestion.Member(david))
} }
@@ -1049,7 +1081,9 @@ class MessageComposerPresenterTest {
val bob = aRoomMember(userId = A_USER_ID_2, membership = RoomMembershipState.JOIN) val bob = aRoomMember(userId = A_USER_ID_2, membership = RoomMembershipState.JOIN)
val david = aRoomMember(userId = A_USER_ID_4, displayName = "Dave", membership = RoomMembershipState.JOIN) val david = aRoomMember(userId = A_USER_ID_4, displayName = "Dave", membership = RoomMembershipState.JOIN)
val room = FakeJoinedRoom( val room = FakeJoinedRoom(
baseRoom = FakeBaseRoom(canUserTriggerRoomNotificationResult = { Result.success(true) }), baseRoom = FakeBaseRoom(
roomPermissions = FakeRoomPermissions(canTriggerRoomNotification = true),
),
typingNoticeResult = { Result.success(Unit) } typingNoticeResult = { Result.success(Unit) }
).apply { ).apply {
givenRoomMembersState( givenRoomMembersState(
@@ -1069,7 +1103,6 @@ class MessageComposerPresenterTest {
presenter.present() presenter.present()
}.test { }.test {
val initialState = awaitItem() val initialState = awaitItem()
// An empty suggestion returns the joined members that are not the current user, but not the room // An empty suggestion returns the joined members that are not the current user, but not the room
initialState.eventSink(MessageComposerEvent.SuggestionReceived(Suggestion(0, 0, SuggestionType.Mention, ""))) initialState.eventSink(MessageComposerEvent.SuggestionReceived(Suggestion(0, 0, SuggestionType.Mention, "")))
skipItems(1) skipItems(1)

View File

@@ -31,6 +31,7 @@ import io.element.android.libraries.matrix.test.A_UNIQUE_ID
import io.element.android.libraries.matrix.test.room.FakeBaseRoom 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.libraries.matrix.test.room.aRoomInfo import io.element.android.libraries.matrix.test.room.aRoomInfo
import io.element.android.libraries.matrix.test.room.powerlevels.FakeRoomPermissions
import io.element.android.libraries.matrix.test.sync.FakeSyncService import io.element.android.libraries.matrix.test.sync.FakeSyncService
import io.element.android.libraries.matrix.test.timeline.FakeTimeline import io.element.android.libraries.matrix.test.timeline.FakeTimeline
import io.element.android.libraries.matrix.test.timeline.aMessageContent import io.element.android.libraries.matrix.test.timeline.aMessageContent
@@ -55,9 +56,7 @@ class PinnedMessagesListPresenterTest {
fun `present - initial state`() = runTest { fun `present - initial state`() = runTest {
val room = FakeJoinedRoom( val room = FakeJoinedRoom(
baseRoom = FakeBaseRoom( baseRoom = FakeBaseRoom(
canRedactOwnResult = { Result.success(true) }, roomPermissions = roomPermissions(),
canRedactOtherResult = { Result.success(true) },
canUserPinUnpinResult = { Result.success(true) },
).apply { ).apply {
givenRoomInfo(aRoomInfo(pinnedEventIds = listOf(AN_EVENT_ID))) givenRoomInfo(aRoomInfo(pinnedEventIds = listOf(AN_EVENT_ID)))
} }
@@ -74,9 +73,7 @@ class PinnedMessagesListPresenterTest {
fun `present - timeline failure state`() = runTest { fun `present - timeline failure state`() = runTest {
val room = FakeJoinedRoom( val room = FakeJoinedRoom(
baseRoom = FakeBaseRoom( baseRoom = FakeBaseRoom(
canRedactOwnResult = { Result.success(true) }, roomPermissions = roomPermissions(),
canRedactOtherResult = { Result.success(true) },
canUserPinUnpinResult = { Result.success(true) },
).apply { ).apply {
givenRoomInfo(aRoomInfo(pinnedEventIds = listOf(AN_EVENT_ID))) givenRoomInfo(aRoomInfo(pinnedEventIds = listOf(AN_EVENT_ID)))
}, },
@@ -95,9 +92,7 @@ class PinnedMessagesListPresenterTest {
fun `present - empty state`() = runTest { fun `present - empty state`() = runTest {
val room = FakeJoinedRoom( val room = FakeJoinedRoom(
baseRoom = FakeBaseRoom( baseRoom = FakeBaseRoom(
canRedactOwnResult = { Result.success(true) }, roomPermissions = roomPermissions(),
canRedactOtherResult = { Result.success(true) },
canUserPinUnpinResult = { Result.success(true) },
).apply { ).apply {
givenRoomInfo(aRoomInfo(pinnedEventIds = listOf())) givenRoomInfo(aRoomInfo(pinnedEventIds = listOf()))
}, },
@@ -117,9 +112,7 @@ class PinnedMessagesListPresenterTest {
val pinnedEventsTimeline = createPinnedMessagesTimeline() val pinnedEventsTimeline = createPinnedMessagesTimeline()
val room = FakeJoinedRoom( val room = FakeJoinedRoom(
baseRoom = FakeBaseRoom( baseRoom = FakeBaseRoom(
canRedactOwnResult = { Result.success(true) }, roomPermissions = roomPermissions(),
canRedactOtherResult = { Result.success(true) },
canUserPinUnpinResult = { Result.success(true) },
).apply { ).apply {
givenRoomInfo(aRoomInfo(pinnedEventIds = listOf(AN_EVENT_ID))) givenRoomInfo(aRoomInfo(pinnedEventIds = listOf(AN_EVENT_ID)))
}, },
@@ -146,9 +139,7 @@ class PinnedMessagesListPresenterTest {
val analyticsService = FakeAnalyticsService() val analyticsService = FakeAnalyticsService()
val room = FakeJoinedRoom( val room = FakeJoinedRoom(
baseRoom = FakeBaseRoom( baseRoom = FakeBaseRoom(
canRedactOwnResult = { Result.success(true) }, roomPermissions = roomPermissions(),
canRedactOtherResult = { Result.success(true) },
canUserPinUnpinResult = { Result.success(true) },
).apply { ).apply {
givenRoomInfo(aRoomInfo(pinnedEventIds = listOf(AN_EVENT_ID))) givenRoomInfo(aRoomInfo(pinnedEventIds = listOf(AN_EVENT_ID)))
}, },
@@ -194,9 +185,7 @@ class PinnedMessagesListPresenterTest {
val pinnedEventsTimeline = createPinnedMessagesTimeline() val pinnedEventsTimeline = createPinnedMessagesTimeline()
val room = FakeJoinedRoom( val room = FakeJoinedRoom(
baseRoom = FakeBaseRoom( baseRoom = FakeBaseRoom(
canRedactOwnResult = { Result.success(true) }, roomPermissions = roomPermissions(),
canRedactOtherResult = { Result.success(true) },
canUserPinUnpinResult = { Result.success(true) },
).apply { ).apply {
givenRoomInfo(aRoomInfo(pinnedEventIds = listOf(AN_EVENT_ID))) givenRoomInfo(aRoomInfo(pinnedEventIds = listOf(AN_EVENT_ID)))
}, },
@@ -225,9 +214,7 @@ class PinnedMessagesListPresenterTest {
val pinnedEventsTimeline = createPinnedMessagesTimeline() val pinnedEventsTimeline = createPinnedMessagesTimeline()
val room = FakeJoinedRoom( val room = FakeJoinedRoom(
baseRoom = FakeBaseRoom( baseRoom = FakeBaseRoom(
canRedactOwnResult = { Result.success(true) }, roomPermissions = roomPermissions(),
canRedactOtherResult = { Result.success(true) },
canUserPinUnpinResult = { Result.success(true) },
).apply { ).apply {
givenRoomInfo(aRoomInfo(pinnedEventIds = listOf(AN_EVENT_ID))) givenRoomInfo(aRoomInfo(pinnedEventIds = listOf(AN_EVENT_ID)))
}, },
@@ -256,9 +243,7 @@ class PinnedMessagesListPresenterTest {
val pinnedEventsTimeline = createPinnedMessagesTimeline() val pinnedEventsTimeline = createPinnedMessagesTimeline()
val room = FakeJoinedRoom( val room = FakeJoinedRoom(
baseRoom = FakeBaseRoom( baseRoom = FakeBaseRoom(
canRedactOwnResult = { Result.success(true) }, roomPermissions = roomPermissions(),
canRedactOtherResult = { Result.success(true) },
canUserPinUnpinResult = { Result.success(true) },
).apply { ).apply {
givenRoomInfo(aRoomInfo(pinnedEventIds = listOf(AN_EVENT_ID))) givenRoomInfo(aRoomInfo(pinnedEventIds = listOf(AN_EVENT_ID)))
}, },
@@ -295,6 +280,16 @@ class PinnedMessagesListPresenterTest {
) )
} }
private fun roomPermissions(
canRedactOther: Boolean = true,
canRedactOwn: Boolean = true,
canPinUnpin: Boolean = true,
) = FakeRoomPermissions(
canRedactOther = canRedactOther,
canRedactOwn = canRedactOwn,
canPinUnpin = canPinUnpin,
)
private fun TestScope.createPinnedMessagesListPresenter( private fun TestScope.createPinnedMessagesListPresenter(
navigator: PinnedMessagesListNavigator = FakePinnedMessagesListNavigator(), navigator: PinnedMessagesListNavigator = FakePinnedMessagesListNavigator(),
room: JoinedRoom = FakeJoinedRoom(), room: JoinedRoom = FakeJoinedRoom(),

View File

@@ -8,8 +8,6 @@
package io.element.android.features.messages.impl.timeline package io.element.android.features.messages.impl.timeline
import app.cash.molecule.RecompositionMode
import app.cash.molecule.moleculeFlow
import app.cash.turbine.ReceiveTurbine import app.cash.turbine.ReceiveTurbine
import app.cash.turbine.test import app.cash.turbine.test
import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertThat
@@ -35,6 +33,7 @@ import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.core.ThreadId import io.element.android.libraries.matrix.api.core.ThreadId
import io.element.android.libraries.matrix.api.core.UniqueId import io.element.android.libraries.matrix.api.core.UniqueId
import io.element.android.libraries.matrix.api.core.asEventId import io.element.android.libraries.matrix.api.core.asEventId
import io.element.android.libraries.matrix.api.room.MessageEventType
import io.element.android.libraries.matrix.api.room.RoomMembersState import io.element.android.libraries.matrix.api.room.RoomMembersState
import io.element.android.libraries.matrix.api.room.tombstone.PredecessorRoom import io.element.android.libraries.matrix.api.room.tombstone.PredecessorRoom
import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem
@@ -55,6 +54,7 @@ import io.element.android.libraries.matrix.test.A_USER_ID
import io.element.android.libraries.matrix.test.room.FakeBaseRoom 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.libraries.matrix.test.room.aRoomMember import io.element.android.libraries.matrix.test.room.aRoomMember
import io.element.android.libraries.matrix.test.room.powerlevels.FakeRoomPermissions
import io.element.android.libraries.matrix.test.timeline.FakeTimeline import io.element.android.libraries.matrix.test.timeline.FakeTimeline
import io.element.android.libraries.matrix.test.timeline.aMessageContent import io.element.android.libraries.matrix.test.timeline.aMessageContent
import io.element.android.libraries.matrix.test.timeline.anEventTimelineItem import io.element.android.libraries.matrix.test.timeline.anEventTimelineItem
@@ -66,6 +66,7 @@ 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.lambda.any import io.element.android.tests.testutils.lambda.any
import io.element.android.tests.testutils.lambda.assert import io.element.android.tests.testutils.lambda.assert
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 io.element.android.tests.testutils.lambda.value import io.element.android.tests.testutils.lambda.value
import io.element.android.tests.testutils.test import io.element.android.tests.testutils.test
@@ -97,9 +98,7 @@ class TimelinePresenterTest {
@Test @Test
fun `present - initial state`() = runTest { fun `present - initial state`() = runTest {
val presenter = createTimelinePresenter() val presenter = createTimelinePresenter()
moleculeFlow(RecompositionMode.Immediate) { presenter.test {
presenter.present()
}.test {
val initialState = awaitFirstItem() val initialState = awaitFirstItem()
assertThat(initialState.timelineItems).isEmpty() assertThat(initialState.timelineItems).isEmpty()
assertThat(initialState.isLive).isTrue() assertThat(initialState.isLive).isTrue()
@@ -118,9 +117,7 @@ class TimelinePresenterTest {
this.paginateLambda = paginateLambda this.paginateLambda = paginateLambda
} }
val presenter = createTimelinePresenter(timeline = timeline) val presenter = createTimelinePresenter(timeline = timeline)
moleculeFlow(RecompositionMode.Immediate) { presenter.test {
presenter.present()
}.test {
val initialState = awaitItem() val initialState = awaitItem()
initialState.eventSink.invoke(TimelineEvents.LoadMore(Timeline.PaginationDirection.BACKWARDS)) initialState.eventSink.invoke(TimelineEvents.LoadMore(Timeline.PaginationDirection.BACKWARDS))
initialState.eventSink.invoke(TimelineEvents.LoadMore(Timeline.PaginationDirection.FORWARDS)) initialState.eventSink.invoke(TimelineEvents.LoadMore(Timeline.PaginationDirection.FORWARDS))
@@ -166,9 +163,6 @@ class TimelinePresenterTest {
) )
val room = FakeJoinedRoom( val room = FakeJoinedRoom(
liveTimeline = timeline, liveTimeline = timeline,
baseRoom = FakeBaseRoom(
canUserSendMessageResult = { _, _ -> Result.success(true) },
)
) )
val sessionPreferencesStore = InMemorySessionPreferencesStore(isSendPublicReadReceiptsEnabled = isSendPublicReadReceiptsEnabled) val sessionPreferencesStore = InMemorySessionPreferencesStore(isSendPublicReadReceiptsEnabled = isSendPublicReadReceiptsEnabled)
val presenter = createTimelinePresenter( val presenter = createTimelinePresenter(
@@ -176,9 +170,7 @@ class TimelinePresenterTest {
room = room, room = room,
sessionPreferencesStore = sessionPreferencesStore, sessionPreferencesStore = sessionPreferencesStore,
) )
moleculeFlow(RecompositionMode.Immediate) { presenter.test {
presenter.present()
}.test {
val initialState = awaitFirstItem() val initialState = awaitFirstItem()
initialState.eventSink.invoke(TimelineEvents.OnScrollFinished(0)) initialState.eventSink.invoke(TimelineEvents.OnScrollFinished(0))
runCurrent() runCurrent()
@@ -211,9 +203,7 @@ class TimelinePresenterTest {
this.sendReadReceiptLambda = sendReadReceiptsLambda this.sendReadReceiptLambda = sendReadReceiptsLambda
} }
val presenter = createTimelinePresenter(timeline) val presenter = createTimelinePresenter(timeline)
moleculeFlow(RecompositionMode.Immediate) { presenter.test {
presenter.present()
}.test {
skipItems(1) skipItems(1)
awaitItem().run { awaitItem().run {
eventSink.invoke(TimelineEvents.OnScrollFinished(1)) eventSink.invoke(TimelineEvents.OnScrollFinished(1))
@@ -252,9 +242,7 @@ class TimelinePresenterTest {
timeline = timeline, timeline = timeline,
sessionPreferencesStore = sessionPreferencesStore, sessionPreferencesStore = sessionPreferencesStore,
) )
moleculeFlow(RecompositionMode.Immediate) { presenter.test {
presenter.present()
}.test {
skipItems(1) skipItems(1)
awaitItem().run { awaitItem().run {
eventSink.invoke(TimelineEvents.OnScrollFinished(0)) eventSink.invoke(TimelineEvents.OnScrollFinished(0))
@@ -290,9 +278,7 @@ class TimelinePresenterTest {
this.sendReadReceiptLambda = sendReadReceiptsLambda this.sendReadReceiptLambda = sendReadReceiptsLambda
} }
val presenter = createTimelinePresenter(timeline) val presenter = createTimelinePresenter(timeline)
moleculeFlow(RecompositionMode.Immediate) { presenter.test {
presenter.present()
}.test {
skipItems(1) skipItems(1)
awaitItem().run { awaitItem().run {
eventSink.invoke(TimelineEvents.OnScrollFinished(1)) eventSink.invoke(TimelineEvents.OnScrollFinished(1))
@@ -320,9 +306,7 @@ class TimelinePresenterTest {
this.sendReadReceiptLambda = sendReadReceiptsLambda this.sendReadReceiptLambda = sendReadReceiptsLambda
} }
val presenter = createTimelinePresenter(timeline) val presenter = createTimelinePresenter(timeline)
moleculeFlow(RecompositionMode.Immediate) { presenter.test {
presenter.present()
}.test {
skipItems(1) skipItems(1)
val initialState = awaitFirstItem() val initialState = awaitFirstItem()
initialState.eventSink.invoke(TimelineEvents.OnScrollFinished(1)) initialState.eventSink.invoke(TimelineEvents.OnScrollFinished(1))
@@ -339,9 +323,7 @@ class TimelinePresenterTest {
markAsReadResult = { Result.success(Unit) }, markAsReadResult = { Result.success(Unit) },
) )
val presenter = createTimelinePresenter(timeline) val presenter = createTimelinePresenter(timeline)
moleculeFlow(RecompositionMode.Immediate) { presenter.test {
presenter.present()
}.test {
val initialState = awaitFirstItem() val initialState = awaitFirstItem()
assertThat(initialState.newEventState).isEqualTo(NewEventState.None) assertThat(initialState.newEventState).isEqualTo(NewEventState.None)
assertThat(initialState.timelineItems.size).isEqualTo(0) assertThat(initialState.timelineItems.size).isEqualTo(0)
@@ -390,9 +372,7 @@ class TimelinePresenterTest {
timelineItems = timelineItems, timelineItems = timelineItems,
) )
val presenter = createTimelinePresenter(timeline) val presenter = createTimelinePresenter(timeline)
moleculeFlow(RecompositionMode.Immediate) { presenter.test {
presenter.present()
}.test {
val initialState = awaitFirstItem() val initialState = awaitFirstItem()
assertThat(initialState.newEventState).isEqualTo(NewEventState.None) assertThat(initialState.newEventState).isEqualTo(NewEventState.None)
assertThat(initialState.timelineItems.size).isEqualTo(0) assertThat(initialState.timelineItems.size).isEqualTo(0)
@@ -446,9 +426,7 @@ class TimelinePresenterTest {
val presenter = createTimelinePresenter( val presenter = createTimelinePresenter(
sendPollResponseAction = sendPollResponseAction, sendPollResponseAction = sendPollResponseAction,
) )
moleculeFlow(RecompositionMode.Immediate) { presenter.test {
presenter.present()
}.test {
val initialState = awaitFirstItem() val initialState = awaitFirstItem()
initialState.eventSink.invoke(TimelineEvents.SelectPollAnswer(AN_EVENT_ID, "anAnswerId")) initialState.eventSink.invoke(TimelineEvents.SelectPollAnswer(AN_EVENT_ID, "anAnswerId"))
} }
@@ -462,9 +440,7 @@ class TimelinePresenterTest {
val presenter = createTimelinePresenter( val presenter = createTimelinePresenter(
endPollAction = endPollAction, endPollAction = endPollAction,
) )
moleculeFlow(RecompositionMode.Immediate) { presenter.test {
presenter.present()
}.test {
val initialState = awaitFirstItem() val initialState = awaitFirstItem()
initialState.eventSink.invoke(TimelineEvents.EndPoll(AN_EVENT_ID)) initialState.eventSink.invoke(TimelineEvents.EndPoll(AN_EVENT_ID))
} }
@@ -481,9 +457,7 @@ class TimelinePresenterTest {
val presenter = createTimelinePresenter( val presenter = createTimelinePresenter(
messagesNavigator = navigator, messagesNavigator = navigator,
) )
moleculeFlow(RecompositionMode.Immediate) { presenter.test {
presenter.present()
}.test {
awaitFirstItem().eventSink(TimelineEvents.EditPoll(AN_EVENT_ID)) awaitFirstItem().eventSink(TimelineEvents.EditPoll(AN_EVENT_ID))
onEditPollClickLambda.assertions().isCalledOnce().with(value(AN_EVENT_ID)) onEditPollClickLambda.assertions().isCalledOnce().with(value(AN_EVENT_ID))
} }
@@ -500,9 +474,7 @@ class TimelinePresenterTest {
), ),
redactedVoiceMessageManager = redactedVoiceMessageManager, redactedVoiceMessageManager = redactedVoiceMessageManager,
) )
moleculeFlow(RecompositionMode.Immediate) { presenter.test {
presenter.present()
}.test {
assertThat(redactedVoiceMessageManager.invocations.size).isEqualTo(0) assertThat(redactedVoiceMessageManager.invocations.size).isEqualTo(0)
skipItems(2) skipItems(2)
assertThat(redactedVoiceMessageManager.invocations.size).isEqualTo(1) assertThat(redactedVoiceMessageManager.invocations.size).isEqualTo(1)
@@ -528,16 +500,14 @@ class TimelinePresenterTest {
liveTimeline = liveTimeline, liveTimeline = liveTimeline,
createTimelineResult = { Result.success(detachedTimeline) }, createTimelineResult = { Result.success(detachedTimeline) },
baseRoom = FakeBaseRoom( baseRoom = FakeBaseRoom(
canUserSendMessageResult = { _, _ -> Result.success(true) }, roomPermissions = roomPermissions(),
threadRootIdForEventResult = { _ -> Result.success(null) }, threadRootIdForEventResult = { _ -> Result.success(null) },
), ),
) )
val presenter = createTimelinePresenter( val presenter = createTimelinePresenter(
room = room, room = room,
) )
moleculeFlow(RecompositionMode.Immediate) { presenter.test {
presenter.present()
}.test {
val initialState = awaitFirstItem() val initialState = awaitFirstItem()
initialState.eventSink.invoke(TimelineEvents.FocusOnEvent(AN_EVENT_ID)) initialState.eventSink.invoke(TimelineEvents.FocusOnEvent(AN_EVENT_ID))
awaitItem().also { state -> awaitItem().also { state ->
@@ -579,15 +549,13 @@ class TimelinePresenterTest {
) )
), ),
baseRoom = FakeBaseRoom( baseRoom = FakeBaseRoom(
canUserSendMessageResult = { _, _ -> Result.success(true) }, roomPermissions = roomPermissions(),
threadRootIdForEventResult = { Result.success(null) }, threadRootIdForEventResult = { Result.success(null) },
), ),
), ),
timelineItemIndexer = timelineItemIndexer, timelineItemIndexer = timelineItemIndexer,
) )
moleculeFlow(RecompositionMode.Immediate) { presenter.test {
presenter.present()
}.test {
val initialState = awaitFirstItem() val initialState = awaitFirstItem()
advanceUntilIdle() advanceUntilIdle()
@@ -619,14 +587,12 @@ class TimelinePresenterTest {
), ),
createTimelineResult = { Result.failure(RuntimeException("An error")) }, createTimelineResult = { Result.failure(RuntimeException("An error")) },
baseRoom = FakeBaseRoom( baseRoom = FakeBaseRoom(
canUserSendMessageResult = { _, _ -> Result.success(true) }, roomPermissions = roomPermissions(),
threadRootIdForEventResult = { _ -> Result.success(null) }, threadRootIdForEventResult = { _ -> Result.success(null) },
), ),
) )
) )
moleculeFlow(RecompositionMode.Immediate) { presenter.test {
presenter.present()
}.test {
val initialState = awaitFirstItem() val initialState = awaitFirstItem()
initialState.eventSink(TimelineEvents.FocusOnEvent(AN_EVENT_ID)) initialState.eventSink(TimelineEvents.FocusOnEvent(AN_EVENT_ID))
awaitItem().also { state -> awaitItem().also { state ->
@@ -668,7 +634,7 @@ class TimelinePresenterTest {
liveTimeline = liveTimeline, liveTimeline = liveTimeline,
createTimelineResult = { Result.success(detachedTimeline) }, createTimelineResult = { Result.success(detachedTimeline) },
baseRoom = FakeBaseRoom( baseRoom = FakeBaseRoom(
canUserSendMessageResult = { _, _ -> Result.success(true) }, roomPermissions = roomPermissions(),
threadRootIdForEventResult = { _ -> Result.success(threadId) }, threadRootIdForEventResult = { _ -> Result.success(threadId) },
), ),
) )
@@ -679,9 +645,7 @@ class TimelinePresenterTest {
timeline = liveTimeline, timeline = liveTimeline,
messagesNavigator = navigator, messagesNavigator = navigator,
) )
moleculeFlow(RecompositionMode.Immediate) { presenter.test {
presenter.present()
}.test {
val initialState = awaitFirstItem() val initialState = awaitFirstItem()
initialState.eventSink.invoke(TimelineEvents.FocusOnEvent(AN_EVENT_ID)) initialState.eventSink.invoke(TimelineEvents.FocusOnEvent(AN_EVENT_ID))
@@ -729,7 +693,7 @@ class TimelinePresenterTest {
liveTimeline = liveTimeline, liveTimeline = liveTimeline,
createTimelineResult = { Result.success(detachedTimeline) }, createTimelineResult = { Result.success(detachedTimeline) },
baseRoom = FakeBaseRoom( baseRoom = FakeBaseRoom(
canUserSendMessageResult = { _, _ -> Result.success(true) }, roomPermissions = roomPermissions(),
threadRootIdForEventResult = { _ -> Result.success(threadId) }, threadRootIdForEventResult = { _ -> Result.success(threadId) },
), ),
) )
@@ -740,9 +704,7 @@ class TimelinePresenterTest {
timeline = liveTimeline, timeline = liveTimeline,
messagesNavigator = navigator, messagesNavigator = navigator,
) )
moleculeFlow(RecompositionMode.Immediate) { presenter.test {
presenter.present()
}.test {
val initialState = awaitFirstItem() val initialState = awaitFirstItem()
initialState.eventSink.invoke(TimelineEvents.FocusOnEvent(AN_EVENT_ID)) initialState.eventSink.invoke(TimelineEvents.FocusOnEvent(AN_EVENT_ID))
@@ -785,7 +747,7 @@ class TimelinePresenterTest {
liveTimeline = liveTimeline, liveTimeline = liveTimeline,
createTimelineResult = { Result.success(detachedTimeline) }, createTimelineResult = { Result.success(detachedTimeline) },
baseRoom = FakeBaseRoom( baseRoom = FakeBaseRoom(
canUserSendMessageResult = { _, _ -> Result.success(true) }, roomPermissions = roomPermissions(),
// Use a different thread id // Use a different thread id
threadRootIdForEventResult = { _ -> Result.success(A_THREAD_ID_2) }, threadRootIdForEventResult = { _ -> Result.success(A_THREAD_ID_2) },
), ),
@@ -797,9 +759,7 @@ class TimelinePresenterTest {
timeline = liveTimeline, timeline = liveTimeline,
messagesNavigator = navigator, messagesNavigator = navigator,
) )
moleculeFlow(RecompositionMode.Immediate) { presenter.test {
presenter.present()
}.test {
val initialState = awaitFirstItem() val initialState = awaitFirstItem()
initialState.eventSink.invoke(TimelineEvents.FocusOnEvent(AN_EVENT_ID)) initialState.eventSink.invoke(TimelineEvents.FocusOnEvent(AN_EVENT_ID))
@@ -846,7 +806,7 @@ class TimelinePresenterTest {
liveTimeline = liveTimeline, liveTimeline = liveTimeline,
createTimelineResult = { Result.success(detachedTimeline) }, createTimelineResult = { Result.success(detachedTimeline) },
baseRoom = FakeBaseRoom( baseRoom = FakeBaseRoom(
canUserSendMessageResult = { _, _ -> Result.success(true) }, roomPermissions = roomPermissions(),
// The event is in the main timeline, not in a thread // The event is in the main timeline, not in a thread
threadRootIdForEventResult = { _ -> Result.success(null) }, threadRootIdForEventResult = { _ -> Result.success(null) },
), ),
@@ -858,9 +818,7 @@ class TimelinePresenterTest {
timeline = liveTimeline, timeline = liveTimeline,
messagesNavigator = navigator, messagesNavigator = navigator,
) )
moleculeFlow(RecompositionMode.Immediate) { presenter.test {
presenter.present()
}.test {
val initialState = awaitFirstItem() val initialState = awaitFirstItem()
initialState.eventSink.invoke(TimelineEvents.FocusOnEvent(AN_EVENT_ID)) initialState.eventSink.invoke(TimelineEvents.FocusOnEvent(AN_EVENT_ID))
@@ -891,9 +849,7 @@ class TimelinePresenterTest {
fun `present - show shield hide shield`() = runTest { fun `present - show shield hide shield`() = runTest {
val presenter = createTimelinePresenter() val presenter = createTimelinePresenter()
val shield = aCriticalShield() val shield = aCriticalShield()
moleculeFlow(RecompositionMode.Immediate) { presenter.test {
presenter.present()
}.test {
val initialState = awaitFirstItem() val initialState = awaitFirstItem()
assertThat(initialState.messageShield).isNull() assertThat(initialState.messageShield).isNull()
initialState.eventSink(TimelineEvents.ShowShieldDialog(shield)) initialState.eventSink(TimelineEvents.ShowShieldDialog(shield))
@@ -929,7 +885,9 @@ class TimelinePresenterTest {
) )
val room = FakeJoinedRoom( val room = FakeJoinedRoom(
liveTimeline = timeline, liveTimeline = timeline,
baseRoom = FakeBaseRoom(canUserSendMessageResult = { _, _ -> Result.success(true) }), baseRoom = FakeBaseRoom(
roomPermissions = roomPermissions(),
),
).apply { ).apply {
givenRoomMembersState(RoomMembersState.Unknown) givenRoomMembersState(RoomMembersState.Unknown)
} }
@@ -937,9 +895,7 @@ class TimelinePresenterTest {
val avatarUrl = "https://domain.com/avatar.jpg" val avatarUrl = "https://domain.com/avatar.jpg"
val presenter = createTimelinePresenter(timeline, room) val presenter = createTimelinePresenter(timeline, room)
moleculeFlow(RecompositionMode.Immediate) { presenter.test {
presenter.present()
}.test {
val initialState = consumeItemsUntilPredicate(30.seconds) { it.timelineItems.isNotEmpty() }.last() val initialState = consumeItemsUntilPredicate(30.seconds) { it.timelineItems.isNotEmpty() }.last()
val event = initialState.timelineItems.first() as TimelineItem.Event val event = initialState.timelineItems.first() as TimelineItem.Event
assertThat(event.senderAvatar.url).isNull() assertThat(event.senderAvatar.url).isNull()
@@ -963,15 +919,13 @@ class TimelinePresenterTest {
val room = FakeJoinedRoom( val room = FakeJoinedRoom(
baseRoom = FakeBaseRoom( baseRoom = FakeBaseRoom(
canUserSendMessageResult = { _, _ -> Result.success(true) }, roomPermissions = roomPermissions(),
predecessorRoomResult = { predecessorRoom } predecessorRoomResult = { predecessorRoom }
), ),
) )
val presenter = createTimelinePresenter(room = room) val presenter = createTimelinePresenter(room = room)
moleculeFlow(RecompositionMode.Immediate) { presenter.test {
presenter.present()
}.test {
val initialState = awaitFirstItem() val initialState = awaitFirstItem()
assertThat(initialState.timelineRoomInfo.predecessorRoom).isNotNull() assertThat(initialState.timelineRoomInfo.predecessorRoom).isNotNull()
assertThat(initialState.timelineRoomInfo.predecessorRoom?.roomId).isEqualTo(predecessorRoomId) assertThat(initialState.timelineRoomInfo.predecessorRoom?.roomId).isEqualTo(predecessorRoomId)
@@ -982,14 +936,12 @@ class TimelinePresenterTest {
fun `present - timeline room info no predecessor`() = runTest { fun `present - timeline room info no predecessor`() = runTest {
val room = FakeJoinedRoom( val room = FakeJoinedRoom(
baseRoom = FakeBaseRoom( baseRoom = FakeBaseRoom(
canUserSendMessageResult = { _, _ -> Result.success(true) }, roomPermissions = roomPermissions(),
predecessorRoomResult = { null } predecessorRoomResult = { null }
), ),
) )
val presenter = createTimelinePresenter(room = room) val presenter = createTimelinePresenter(room = room)
moleculeFlow(RecompositionMode.Immediate) { presenter.test {
presenter.present()
}.test {
val initialState = awaitFirstItem() val initialState = awaitFirstItem()
assertThat(initialState.timelineRoomInfo.predecessorRoom).isNull() assertThat(initialState.timelineRoomInfo.predecessorRoom).isNull()
} }
@@ -999,7 +951,7 @@ class TimelinePresenterTest {
fun `present - timeline event navigate to room`() = runTest { fun `present - timeline event navigate to room`() = runTest {
val room = FakeJoinedRoom( val room = FakeJoinedRoom(
baseRoom = FakeBaseRoom( baseRoom = FakeBaseRoom(
canUserSendMessageResult = { _, _ -> Result.success(true) }, roomPermissions = roomPermissions(),
), ),
) )
val onNavigateToRoomLambda = lambdaRecorder<RoomId, EventId?, List<String>, Unit> { _, _, _ -> } val onNavigateToRoomLambda = lambdaRecorder<RoomId, EventId?, List<String>, Unit> { _, _, _ -> }
@@ -1025,11 +977,32 @@ class TimelinePresenterTest {
return awaitItem() return awaitItem()
} }
private fun roomPermissions(
canRedactOther: Boolean = false,
canRedactOwn: Boolean = true,
canSendMessage: Boolean = true,
canSendReaction: Boolean = true,
canPinUnpin: Boolean = false,
) = FakeRoomPermissions(
canSendMessage = { type ->
when (type) {
MessageEventType.RoomMessage -> canSendMessage
MessageEventType.Reaction -> canSendReaction
else -> lambdaError()
}
},
canRedactOther = canRedactOther,
canRedactOwn = canRedactOwn,
canPinUnpin = canPinUnpin,
)
private fun TestScope.createTimelinePresenter( private fun TestScope.createTimelinePresenter(
timeline: Timeline = FakeTimeline(), timeline: Timeline = FakeTimeline(),
room: FakeJoinedRoom = FakeJoinedRoom( room: FakeJoinedRoom = FakeJoinedRoom(
liveTimeline = timeline, liveTimeline = timeline,
baseRoom = FakeBaseRoom(canUserSendMessageResult = { _, _ -> Result.success(true) }), baseRoom = FakeBaseRoom(
roomPermissions = roomPermissions(),
),
), ),
redactedVoiceMessageManager: RedactedVoiceMessageManager = FakeRedactedVoiceMessageManager(), redactedVoiceMessageManager: RedactedVoiceMessageManager = FakeRedactedVoiceMessageManager(),
messagesNavigator: FakeMessagesNavigator = FakeMessagesNavigator(), messagesNavigator: FakeMessagesNavigator = FakeMessagesNavigator(),

View File

@@ -15,9 +15,12 @@ import io.element.android.features.call.test.FakeCurrentCallService
import io.element.android.features.enterprise.test.FakeSessionEnterpriseService import io.element.android.features.enterprise.test.FakeSessionEnterpriseService
import io.element.android.features.roomcall.api.RoomCallState import io.element.android.features.roomcall.api.RoomCallState
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.StateEventType
import io.element.android.libraries.matrix.test.room.FakeBaseRoom 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.libraries.matrix.test.room.aRoomInfo import io.element.android.libraries.matrix.test.room.aRoomInfo
import io.element.android.libraries.matrix.test.room.powerlevels.FakeRoomPermissions
import io.element.android.tests.testutils.lambda.lambdaError
import io.element.android.tests.testutils.test import io.element.android.tests.testutils.test
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
@@ -28,7 +31,7 @@ class RoomCallStatePresenterTest {
fun `present - initial state`() = runTest { fun `present - initial state`() = runTest {
val room = FakeJoinedRoom( val room = FakeJoinedRoom(
baseRoom = FakeBaseRoom( baseRoom = FakeBaseRoom(
canUserJoinCallResult = { Result.success(false) }, roomPermissions = roomPermissions(false),
) )
) )
val presenter = createRoomCallStatePresenter(joinedRoom = room) val presenter = createRoomCallStatePresenter(joinedRoom = room)
@@ -47,7 +50,7 @@ class RoomCallStatePresenterTest {
fun `present - element call not available`() = runTest { fun `present - element call not available`() = runTest {
val room = FakeJoinedRoom( val room = FakeJoinedRoom(
baseRoom = FakeBaseRoom( baseRoom = FakeBaseRoom(
canUserJoinCallResult = { Result.success(false) }, roomPermissions = roomPermissions(false),
) )
) )
val presenter = createRoomCallStatePresenter( val presenter = createRoomCallStatePresenter(
@@ -66,7 +69,7 @@ class RoomCallStatePresenterTest {
fun `present - initial state - user can join call`() = runTest { fun `present - initial state - user can join call`() = runTest {
val room = FakeJoinedRoom( val room = FakeJoinedRoom(
baseRoom = FakeBaseRoom( baseRoom = FakeBaseRoom(
canUserJoinCallResult = { Result.success(true) }, roomPermissions = roomPermissions(true),
) )
) )
val presenter = createRoomCallStatePresenter(joinedRoom = room) val presenter = createRoomCallStatePresenter(joinedRoom = room)
@@ -85,7 +88,7 @@ class RoomCallStatePresenterTest {
fun `present - call is disabled if user cannot join it even if there is an ongoing call`() = runTest { fun `present - call is disabled if user cannot join it even if there is an ongoing call`() = runTest {
val room = FakeJoinedRoom( val room = FakeJoinedRoom(
baseRoom = FakeBaseRoom( baseRoom = FakeBaseRoom(
canUserJoinCallResult = { Result.success(false) }, roomPermissions = roomPermissions(false),
initialRoomInfo = aRoomInfo(hasRoomCall = true), initialRoomInfo = aRoomInfo(hasRoomCall = true),
) )
) )
@@ -106,7 +109,7 @@ class RoomCallStatePresenterTest {
fun `present - user has joined the call on another session`() = runTest { fun `present - user has joined the call on another session`() = runTest {
val room = FakeJoinedRoom( val room = FakeJoinedRoom(
baseRoom = FakeBaseRoom( baseRoom = FakeBaseRoom(
canUserJoinCallResult = { Result.success(true) }, roomPermissions = roomPermissions(true),
).apply { ).apply {
givenRoomInfo( givenRoomInfo(
aRoomInfo( aRoomInfo(
@@ -133,7 +136,7 @@ class RoomCallStatePresenterTest {
fun `present - user has joined the call locally`() = runTest { fun `present - user has joined the call locally`() = runTest {
val room = FakeJoinedRoom( val room = FakeJoinedRoom(
baseRoom = FakeBaseRoom( baseRoom = FakeBaseRoom(
canUserJoinCallResult = { Result.success(true) }, roomPermissions = roomPermissions(true),
).apply { ).apply {
givenRoomInfo( givenRoomInfo(
aRoomInfo( aRoomInfo(
@@ -163,7 +166,7 @@ class RoomCallStatePresenterTest {
fun `present - user leaves the call`() = runTest { fun `present - user leaves the call`() = runTest {
val room = FakeJoinedRoom( val room = FakeJoinedRoom(
baseRoom = FakeBaseRoom( baseRoom = FakeBaseRoom(
canUserJoinCallResult = { Result.success(true) }, roomPermissions = roomPermissions(true),
).apply { ).apply {
givenRoomInfo( givenRoomInfo(
aRoomInfo( aRoomInfo(
@@ -223,6 +226,17 @@ class RoomCallStatePresenterTest {
} }
} }
private fun roomPermissions(canJoinCall: Boolean): FakeRoomPermissions {
return FakeRoomPermissions(
canSendState = { stateEvent ->
when (stateEvent) {
StateEventType.CALL_MEMBER -> canJoinCall
else -> lambdaError()
}
}
)
}
private fun createRoomCallStatePresenter( private fun createRoomCallStatePresenter(
joinedRoom: JoinedRoom, joinedRoom: JoinedRoom,
currentCallService: CurrentCallService = FakeCurrentCallService(), currentCallService: CurrentCallService = FakeCurrentCallService(),

View File

@@ -13,8 +13,8 @@ import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.core.SessionId import io.element.android.libraries.matrix.api.core.SessionId
import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.api.room.RoomMember import io.element.android.libraries.matrix.api.room.RoomMember
import io.element.android.libraries.matrix.api.room.StateEventType
import io.element.android.libraries.matrix.api.room.join.JoinRule import io.element.android.libraries.matrix.api.room.join.JoinRule
import io.element.android.libraries.matrix.api.room.powerlevels.RoomPermissions
import io.element.android.libraries.matrix.test.AN_AVATAR_URL import io.element.android.libraries.matrix.test.AN_AVATAR_URL
import io.element.android.libraries.matrix.test.A_ROOM_ALIAS import io.element.android.libraries.matrix.test.A_ROOM_ALIAS
import io.element.android.libraries.matrix.test.A_ROOM_ID import io.element.android.libraries.matrix.test.A_ROOM_ID
@@ -25,6 +25,7 @@ import io.element.android.libraries.matrix.test.notificationsettings.FakeNotific
import io.element.android.libraries.matrix.test.room.FakeBaseRoom 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.libraries.matrix.test.room.aRoomInfo import io.element.android.libraries.matrix.test.room.aRoomInfo
import io.element.android.libraries.matrix.test.room.powerlevels.FakeRoomPermissions
import io.element.android.tests.testutils.lambda.lambdaError import io.element.android.tests.testutils.lambda.lambdaError
fun aRoom( fun aRoom(
@@ -35,6 +36,7 @@ fun aRoom(
topic: String? = A_ROOM_TOPIC, topic: String? = A_ROOM_TOPIC,
avatarUrl: String? = AN_AVATAR_URL, avatarUrl: String? = AN_AVATAR_URL,
canonicalAlias: RoomAlias? = A_ROOM_ALIAS, canonicalAlias: RoomAlias? = A_ROOM_ALIAS,
roomPermissions: RoomPermissions = FakeRoomPermissions(),
isEncrypted: Boolean = true, isEncrypted: Boolean = true,
isPublic: Boolean = true, isPublic: Boolean = true,
isDirect: Boolean = false, isDirect: Boolean = false,
@@ -42,29 +44,20 @@ fun aRoom(
activeMemberCount: Long = 1, activeMemberCount: Long = 1,
joinedMemberCount: Long = 1, joinedMemberCount: Long = 1,
invitedMemberCount: Long = 0, invitedMemberCount: Long = 0,
canInviteResult: (UserId) -> Result<Boolean> = { lambdaError() },
canBanResult: (UserId) -> Result<Boolean> = { lambdaError() },
canKickResult: (UserId) -> Result<Boolean> = { lambdaError() },
canSendStateResult: (UserId, StateEventType) -> Result<Boolean> = { _, _ -> lambdaError() },
userDisplayNameResult: (UserId) -> Result<String?> = { lambdaError() }, userDisplayNameResult: (UserId) -> Result<String?> = { lambdaError() },
userAvatarUrlResult: () -> Result<String?> = { lambdaError() }, userAvatarUrlResult: () -> Result<String?> = { lambdaError() },
canUserJoinCallResult: (UserId) -> Result<Boolean> = { lambdaError() },
getUpdatedMemberResult: (UserId) -> Result<RoomMember> = { lambdaError() }, getUpdatedMemberResult: (UserId) -> Result<RoomMember> = { lambdaError() },
userRoleResult: () -> Result<RoomMember.Role> = { lambdaError() }, userRoleResult: () -> Result<RoomMember.Role> = { lambdaError() },
setIsFavoriteResult: (Boolean) -> Result<Unit> = { lambdaError() }, setIsFavoriteResult: (Boolean) -> Result<Unit> = { lambdaError() },
) = FakeBaseRoom( ) = FakeBaseRoom(
sessionId = sessionId, sessionId = sessionId,
roomId = roomId, roomId = roomId,
canInviteResult = canInviteResult,
canBanResult = canBanResult,
canKickResult = canKickResult,
canSendStateResult = canSendStateResult,
userDisplayNameResult = userDisplayNameResult, userDisplayNameResult = userDisplayNameResult,
userAvatarUrlResult = userAvatarUrlResult, userAvatarUrlResult = userAvatarUrlResult,
canUserJoinCallResult = canUserJoinCallResult,
getUpdatedMemberResult = getUpdatedMemberResult, getUpdatedMemberResult = getUpdatedMemberResult,
userRoleResult = userRoleResult, userRoleResult = userRoleResult,
setIsFavoriteResult = setIsFavoriteResult, setIsFavoriteResult = setIsFavoriteResult,
roomPermissions = roomPermissions,
initialRoomInfo = aRoomInfo( initialRoomInfo = aRoomInfo(
name = displayName, name = displayName,
rawName = rawName, rawName = rawName,
@@ -89,6 +82,7 @@ fun aJoinedRoom(
topic: String? = A_ROOM_TOPIC, topic: String? = A_ROOM_TOPIC,
avatarUrl: String? = AN_AVATAR_URL, avatarUrl: String? = AN_AVATAR_URL,
canonicalAlias: RoomAlias? = A_ROOM_ALIAS, canonicalAlias: RoomAlias? = A_ROOM_ALIAS,
roomPermissions: RoomPermissions = FakeRoomPermissions(),
isEncrypted: Boolean = true, isEncrypted: Boolean = true,
isPublic: Boolean = true, isPublic: Boolean = true,
isDirect: Boolean = false, isDirect: Boolean = false,
@@ -97,17 +91,12 @@ fun aJoinedRoom(
joinedMemberCount: Long = 1, joinedMemberCount: Long = 1,
invitedMemberCount: Long = 0, invitedMemberCount: Long = 0,
notificationSettingsService: FakeNotificationSettingsService = FakeNotificationSettingsService(), notificationSettingsService: FakeNotificationSettingsService = FakeNotificationSettingsService(),
canInviteResult: (UserId) -> Result<Boolean> = { lambdaError() },
canBanResult: (UserId) -> Result<Boolean> = { lambdaError() },
canKickResult: (UserId) -> Result<Boolean> = { lambdaError() },
canSendStateResult: (UserId, StateEventType) -> Result<Boolean> = { _, _ -> lambdaError() },
userDisplayNameResult: (UserId) -> Result<String?> = { lambdaError() }, userDisplayNameResult: (UserId) -> Result<String?> = { lambdaError() },
userAvatarUrlResult: () -> Result<String?> = { lambdaError() }, userAvatarUrlResult: () -> Result<String?> = { lambdaError() },
setNameResult: (String) -> Result<Unit> = { lambdaError() }, setNameResult: (String) -> Result<Unit> = { lambdaError() },
setTopicResult: (String) -> Result<Unit> = { lambdaError() }, setTopicResult: (String) -> Result<Unit> = { lambdaError() },
updateAvatarResult: (String, ByteArray) -> Result<Unit> = { _, _ -> lambdaError() }, updateAvatarResult: (String, ByteArray) -> Result<Unit> = { _, _ -> lambdaError() },
removeAvatarResult: () -> Result<Unit> = { lambdaError() }, removeAvatarResult: () -> Result<Unit> = { lambdaError() },
canUserJoinCallResult: (UserId) -> Result<Boolean> = { lambdaError() },
getUpdatedMemberResult: (UserId) -> Result<RoomMember> = { lambdaError() }, getUpdatedMemberResult: (UserId) -> Result<RoomMember> = { lambdaError() },
userRoleResult: () -> Result<RoomMember.Role> = { lambdaError() }, userRoleResult: () -> Result<RoomMember.Role> = { lambdaError() },
kickUserResult: (UserId, String?) -> Result<Unit> = { _, _ -> lambdaError() }, kickUserResult: (UserId, String?) -> Result<Unit> = { _, _ -> lambdaError() },
@@ -132,13 +121,9 @@ fun aJoinedRoom(
baseRoom = aRoom( baseRoom = aRoom(
sessionId = sessionId, sessionId = sessionId,
roomId = roomId, roomId = roomId,
canInviteResult = canInviteResult, roomPermissions = roomPermissions,
canBanResult = canBanResult,
canKickResult = canKickResult,
canSendStateResult = canSendStateResult,
userDisplayNameResult = userDisplayNameResult, userDisplayNameResult = userDisplayNameResult,
userAvatarUrlResult = userAvatarUrlResult, userAvatarUrlResult = userAvatarUrlResult,
canUserJoinCallResult = canUserJoinCallResult,
getUpdatedMemberResult = getUpdatedMemberResult, getUpdatedMemberResult = getUpdatedMemberResult,
userRoleResult = userRoleResult, userRoleResult = userRoleResult,
setIsFavoriteResult = setIsFavoriteResult, setIsFavoriteResult = setIsFavoriteResult,

View File

@@ -30,6 +30,7 @@ import io.element.android.libraries.matrix.api.room.RoomMembersState
import io.element.android.libraries.matrix.api.room.RoomNotificationMode import io.element.android.libraries.matrix.api.room.RoomNotificationMode
import io.element.android.libraries.matrix.api.room.StateEventType import io.element.android.libraries.matrix.api.room.StateEventType
import io.element.android.libraries.matrix.api.room.join.JoinRule import io.element.android.libraries.matrix.api.room.join.JoinRule
import io.element.android.libraries.matrix.api.room.powerlevels.RoomPermissions
import io.element.android.libraries.matrix.test.AN_AVATAR_URL import io.element.android.libraries.matrix.test.AN_AVATAR_URL
import io.element.android.libraries.matrix.test.AN_EVENT_ID import io.element.android.libraries.matrix.test.AN_EVENT_ID
import io.element.android.libraries.matrix.test.A_ROOM_NAME import io.element.android.libraries.matrix.test.A_ROOM_NAME
@@ -41,6 +42,7 @@ 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
import io.element.android.libraries.matrix.test.room.aRoomInfo import io.element.android.libraries.matrix.test.room.aRoomInfo
import io.element.android.libraries.matrix.test.room.powerlevels.FakeRoomPermissions
import io.element.android.libraries.preferences.api.store.AppPreferencesStore import io.element.android.libraries.preferences.api.store.AppPreferencesStore
import io.element.android.libraries.preferences.test.InMemoryAppPreferencesStore import io.element.android.libraries.preferences.test.InMemoryAppPreferencesStore
import io.element.android.services.analytics.api.AnalyticsService import io.element.android.services.analytics.api.AnalyticsService
@@ -119,9 +121,7 @@ class RoomDetailsPresenterTest {
@Test @Test
fun `present - initial state is created from initial room info`() = runTest { fun `present - initial state is created from initial room info`() = runTest {
val room = aJoinedRoom( val room = aJoinedRoom(
canInviteResult = { Result.success(true) }, roomPermissions = roomPermissions(),
canUserJoinCallResult = { Result.success(true) },
canSendStateResult = { _, _ -> Result.success(true) },
) )
val presenter = createRoomDetailsPresenter(room) val presenter = createRoomDetailsPresenter(room)
presenter.testWithLifecycleOwner(lifecycleOwner = fakeLifecycleOwner) { presenter.testWithLifecycleOwner(lifecycleOwner = fakeLifecycleOwner) {
@@ -148,9 +148,7 @@ class RoomDetailsPresenterTest {
pinnedEventIds = listOf(AN_EVENT_ID), pinnedEventIds = listOf(AN_EVENT_ID),
) )
val room = aJoinedRoom( val room = aJoinedRoom(
canInviteResult = { Result.success(true) }, roomPermissions = roomPermissions(),
canUserJoinCallResult = { Result.success(true) },
canSendStateResult = { _, _ -> Result.success(true) },
).apply { ).apply {
givenRoomInfo(roomInfo) givenRoomInfo(roomInfo)
} }
@@ -170,9 +168,7 @@ class RoomDetailsPresenterTest {
fun `present - initial state with no room name`() = runTest { fun `present - initial state with no room name`() = runTest {
val room = aJoinedRoom( val room = aJoinedRoom(
displayName = "", displayName = "",
canInviteResult = { Result.success(true) }, roomPermissions = roomPermissions(),
canUserJoinCallResult = { Result.success(true) },
canSendStateResult = { _, _ -> Result.success(true) },
) )
val presenter = createRoomDetailsPresenter(room) val presenter = createRoomDetailsPresenter(room)
presenter.testWithLifecycleOwner(lifecycleOwner = fakeLifecycleOwner) { presenter.testWithLifecycleOwner(lifecycleOwner = fakeLifecycleOwner) {
@@ -188,9 +184,7 @@ class RoomDetailsPresenterTest {
val myRoomMember = aRoomMember(A_SESSION_ID) val myRoomMember = aRoomMember(A_SESSION_ID)
val otherRoomMember = aRoomMember(A_USER_ID_2) val otherRoomMember = aRoomMember(A_USER_ID_2)
val room = aJoinedRoom( val room = aJoinedRoom(
canInviteResult = { Result.success(true) }, roomPermissions = roomPermissions(),
canUserJoinCallResult = { Result.success(true) },
canSendStateResult = { _, _ -> Result.success(true) },
getUpdatedMemberResult = { userId -> getUpdatedMemberResult = { userId ->
when (userId) { when (userId) {
A_SESSION_ID -> Result.success(myRoomMember) A_SESSION_ID -> Result.success(myRoomMember)
@@ -225,9 +219,9 @@ class RoomDetailsPresenterTest {
@Test @Test
fun `present - initial state when user can invite others to room`() = runTest { fun `present - initial state when user can invite others to room`() = runTest {
val room = aJoinedRoom( val room = aJoinedRoom(
canInviteResult = { Result.success(true) }, roomPermissions = roomPermissions(
canUserJoinCallResult = { Result.success(true) }, canInvite = true,
canSendStateResult = { _, _ -> Result.success(true) }, ),
) )
val presenter = createRoomDetailsPresenter(room, dispatchers = testCoroutineDispatchers()) val presenter = createRoomDetailsPresenter(room, dispatchers = testCoroutineDispatchers())
presenter.testWithLifecycleOwner(lifecycleOwner = fakeLifecycleOwner) { presenter.testWithLifecycleOwner(lifecycleOwner = fakeLifecycleOwner) {
@@ -243,26 +237,9 @@ class RoomDetailsPresenterTest {
@Test @Test
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) }, roomPermissions = roomPermissions(
canKickResult = { Result.success(false) }, canInvite = false,
canBanResult = { Result.success(false) }, ),
canUserJoinCallResult = { Result.success(true) },
canSendStateResult = { _, _ -> Result.success(true) },
)
val presenter = createRoomDetailsPresenter(room)
presenter.testWithLifecycleOwner(lifecycleOwner = fakeLifecycleOwner) {
assertThat(awaitItem().canInvite).isFalse()
cancelAndIgnoreRemainingEvents()
}
}
@Test
fun `present - initial state when canInvite errors`() = runTest {
val room = aJoinedRoom(
canInviteResult = { Result.failure(RuntimeException("Whoops")) },
canUserJoinCallResult = { Result.success(true) },
canSendStateResult = { _, _ -> Result.success(true) },
) )
val presenter = createRoomDetailsPresenter(room) val presenter = createRoomDetailsPresenter(room)
presenter.testWithLifecycleOwner(lifecycleOwner = fakeLifecycleOwner) { presenter.testWithLifecycleOwner(lifecycleOwner = fakeLifecycleOwner) {
@@ -275,17 +252,11 @@ class RoomDetailsPresenterTest {
@Test @Test
fun `present - initial state when user can edit one attribute`() = runTest { fun `present - initial state when user can edit one attribute`() = runTest {
val room = aJoinedRoom( val room = aJoinedRoom(
canSendStateResult = { _, stateEventType -> roomPermissions = roomPermissions(
when (stateEventType) { canChangeName = true,
StateEventType.ROOM_TOPIC -> Result.success(true) canChangeTopic = false,
StateEventType.ROOM_NAME -> Result.success(false) canChangeAvatar = false,
else -> Result.failure(RuntimeException("Whelp")) ),
}
},
canBanResult = { Result.success(false) },
canKickResult = { Result.success(false) },
canInviteResult = { Result.success(false) },
canUserJoinCallResult = { Result.success(true) },
) )
val presenter = createRoomDetailsPresenter(room) val presenter = createRoomDetailsPresenter(room)
presenter.testWithLifecycleOwner(lifecycleOwner = fakeLifecycleOwner) { presenter.testWithLifecycleOwner(lifecycleOwner = fakeLifecycleOwner) {
@@ -303,18 +274,7 @@ class RoomDetailsPresenterTest {
val myRoomMember = aRoomMember(A_SESSION_ID) val myRoomMember = aRoomMember(A_SESSION_ID)
val otherRoomMember = aRoomMember(A_USER_ID_2) val otherRoomMember = aRoomMember(A_USER_ID_2)
val room = aJoinedRoom( val room = aJoinedRoom(
canSendStateResult = { _, stateEventType -> roomPermissions = roomPermissions(),
when (stateEventType) {
StateEventType.ROOM_TOPIC,
StateEventType.ROOM_NAME,
StateEventType.ROOM_AVATAR -> Result.success(true)
else -> Result.failure(RuntimeException("Whelp"))
}
},
canKickResult = { Result.success(false) },
canBanResult = { Result.success(false) },
canInviteResult = { Result.success(false) },
canUserJoinCallResult = { Result.success(true) },
getUpdatedMemberResult = { userId -> getUpdatedMemberResult = { userId ->
when (userId) { when (userId) {
A_SESSION_ID -> Result.success(myRoomMember) A_SESSION_ID -> Result.success(myRoomMember)
@@ -354,18 +314,9 @@ class RoomDetailsPresenterTest {
val room = aJoinedRoom( val room = aJoinedRoom(
isDirect = true, isDirect = true,
topic = null, topic = null,
canSendStateResult = { _, stateEventType -> roomPermissions = roomPermissions(),
when (stateEventType) {
StateEventType.ROOM_AVATAR,
StateEventType.ROOM_TOPIC,
StateEventType.ROOM_NAME -> Result.success(true)
else -> Result.failure(RuntimeException("Whelp"))
}
},
userDisplayNameResult = { Result.success(A_USER_NAME) }, userDisplayNameResult = { Result.success(A_USER_NAME) },
userAvatarUrlResult = { Result.success(AN_AVATAR_URL) }, userAvatarUrlResult = { Result.success(AN_AVATAR_URL) },
canInviteResult = { Result.success(true) },
canUserJoinCallResult = { Result.success(true) },
getUpdatedMemberResult = { userId -> getUpdatedMemberResult = { userId ->
when (userId) { when (userId) {
A_SESSION_ID -> Result.success(myRoomMember) A_SESSION_ID -> Result.success(myRoomMember)
@@ -400,24 +351,11 @@ class RoomDetailsPresenterTest {
@Test @Test
fun `present - initial state when user can edit all attributes`() = runTest { fun `present - initial state when user can edit all attributes`() = runTest {
val room = aJoinedRoom( val room = aJoinedRoom(
canSendStateResult = { _, stateEventType -> roomPermissions = roomPermissions(
when (stateEventType) { canChangeAvatar = true,
StateEventType.ROOM_TOPIC, canChangeName = true,
StateEventType.ROOM_NAME, canChangeTopic = true,
StateEventType.ROOM_AVATAR -> Result.success(true) ),
else -> Result.failure(RuntimeException("Whelp"))
}
},
canKickResult = {
Result.success(false)
},
canBanResult = {
Result.success(false)
},
canInviteResult = {
Result.success(false)
},
canUserJoinCallResult = { Result.success(true) },
) )
val presenter = createRoomDetailsPresenter(room) val presenter = createRoomDetailsPresenter(room)
presenter.testWithLifecycleOwner(lifecycleOwner = fakeLifecycleOwner) { presenter.testWithLifecycleOwner(lifecycleOwner = fakeLifecycleOwner) {
@@ -433,24 +371,11 @@ class RoomDetailsPresenterTest {
@Test @Test
fun `present - initial state when user can edit no attributes`() = runTest { fun `present - initial state when user can edit no attributes`() = runTest {
val room = aJoinedRoom( val room = aJoinedRoom(
canSendStateResult = { _, stateEventType -> roomPermissions = roomPermissions(
when (stateEventType) { canChangeAvatar = false,
StateEventType.ROOM_TOPIC, canChangeName = false,
StateEventType.ROOM_NAME, canChangeTopic = false,
StateEventType.ROOM_AVATAR -> Result.success(false) ),
else -> Result.failure(RuntimeException("Whelp"))
}
},
canBanResult = {
Result.success(false)
},
canKickResult = {
Result.success(false)
},
canInviteResult = {
Result.success(false)
},
canUserJoinCallResult = { Result.success(true) },
) )
val presenter = createRoomDetailsPresenter(room) val presenter = createRoomDetailsPresenter(room)
presenter.testWithLifecycleOwner(lifecycleOwner = fakeLifecycleOwner) { presenter.testWithLifecycleOwner(lifecycleOwner = fakeLifecycleOwner) {
@@ -465,24 +390,9 @@ class RoomDetailsPresenterTest {
fun `present - topic state is hidden when no topic and user has no permission`() = runTest { fun `present - topic state is hidden when no topic and user has no permission`() = runTest {
val room = aJoinedRoom( val room = aJoinedRoom(
topic = null, topic = null,
canSendStateResult = { _, stateEventType -> roomPermissions = roomPermissions(
when (stateEventType) { canChangeTopic = false
StateEventType.ROOM_AVATAR, ),
StateEventType.ROOM_NAME -> Result.success(true)
StateEventType.ROOM_TOPIC -> Result.success(false)
else -> Result.failure(RuntimeException("Whelp"))
}
},
canKickResult = {
Result.success(false)
},
canBanResult = {
Result.success(false)
},
canInviteResult = {
Result.success(false)
},
canUserJoinCallResult = { Result.success(true) },
) )
val presenter = createRoomDetailsPresenter(room) val presenter = createRoomDetailsPresenter(room)
presenter.testWithLifecycleOwner(lifecycleOwner = fakeLifecycleOwner) { presenter.testWithLifecycleOwner(lifecycleOwner = fakeLifecycleOwner) {
@@ -497,24 +407,7 @@ class RoomDetailsPresenterTest {
fun `present - topic state is 'can add topic' when no topic and user has permission`() = runTest { fun `present - topic state is 'can add topic' when no topic and user has permission`() = runTest {
val room = aJoinedRoom( val room = aJoinedRoom(
topic = null, topic = null,
canSendStateResult = { _, stateEventType -> roomPermissions = roomPermissions(),
when (stateEventType) {
StateEventType.ROOM_AVATAR,
StateEventType.ROOM_TOPIC,
StateEventType.ROOM_NAME -> Result.success(true)
else -> Result.failure(RuntimeException("Whelp"))
}
},
canKickResult = {
Result.success(false)
},
canBanResult = {
Result.success(false)
},
canInviteResult = {
Result.success(false)
},
canUserJoinCallResult = { Result.success(true) },
).apply { ).apply {
givenRoomInfo(aRoomInfo(topic = null)) givenRoomInfo(aRoomInfo(topic = null))
} }
@@ -534,9 +427,7 @@ class RoomDetailsPresenterTest {
fun `present - leave room event is passed on to leave room presenter`() = runTest { fun `present - leave room event is passed on to leave room presenter`() = runTest {
val leaveRoomEventRecorder = EventsRecorder<LeaveRoomEvent>() val leaveRoomEventRecorder = EventsRecorder<LeaveRoomEvent>()
val room = aJoinedRoom( val room = aJoinedRoom(
canInviteResult = { Result.success(true) }, roomPermissions = roomPermissions(),
canUserJoinCallResult = { Result.success(true) },
canSendStateResult = { _, _ -> Result.success(true) },
) )
val presenter = createRoomDetailsPresenter( val presenter = createRoomDetailsPresenter(
room = room, room = room,
@@ -555,9 +446,7 @@ class RoomDetailsPresenterTest {
val notificationSettingsService = FakeNotificationSettingsService() val notificationSettingsService = FakeNotificationSettingsService()
val room = aJoinedRoom( val room = aJoinedRoom(
notificationSettingsService = notificationSettingsService, notificationSettingsService = notificationSettingsService,
canInviteResult = { Result.success(true) }, roomPermissions = roomPermissions(),
canUserJoinCallResult = { Result.success(true) },
canSendStateResult = { _, _ -> Result.success(true) },
) )
val presenter = createRoomDetailsPresenter( val presenter = createRoomDetailsPresenter(
room = room, room = room,
@@ -584,9 +473,7 @@ class RoomDetailsPresenterTest {
FakeNotificationSettingsService(initialRoomMode = RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY) FakeNotificationSettingsService(initialRoomMode = RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY)
val room = aJoinedRoom( val room = aJoinedRoom(
notificationSettingsService = notificationSettingsService, notificationSettingsService = notificationSettingsService,
canInviteResult = { Result.success(true) }, roomPermissions = roomPermissions(),
canUserJoinCallResult = { Result.success(true) },
canSendStateResult = { _, _ -> Result.success(true) },
) )
val presenter = createRoomDetailsPresenter( val presenter = createRoomDetailsPresenter(
room = room, room = room,
@@ -612,9 +499,7 @@ class RoomDetailsPresenterTest {
) )
val room = aJoinedRoom( val room = aJoinedRoom(
notificationSettingsService = notificationSettingsService, notificationSettingsService = notificationSettingsService,
canInviteResult = { Result.success(true) }, roomPermissions = roomPermissions(),
canUserJoinCallResult = { Result.success(true) },
canSendStateResult = { _, _ -> Result.success(true) },
) )
val presenter = createRoomDetailsPresenter( val presenter = createRoomDetailsPresenter(
room = room, room = room,
@@ -637,9 +522,7 @@ class RoomDetailsPresenterTest {
val setIsFavoriteResult = lambdaRecorder<Boolean, Result<Unit>> { _ -> Result.success(Unit) } val setIsFavoriteResult = lambdaRecorder<Boolean, Result<Unit>> { _ -> Result.success(Unit) }
val room = aJoinedRoom( val room = aJoinedRoom(
setIsFavoriteResult = setIsFavoriteResult, setIsFavoriteResult = setIsFavoriteResult,
canInviteResult = { Result.success(true) }, roomPermissions = roomPermissions(),
canUserJoinCallResult = { Result.success(true) },
canSendStateResult = { _, _ -> Result.success(true) },
) )
val analyticsService = FakeAnalyticsService() val analyticsService = FakeAnalyticsService()
val presenter = val presenter =
@@ -665,9 +548,7 @@ class RoomDetailsPresenterTest {
@Test @Test
fun `present - changes in room info updates the is favorite flag`() = runTest { fun `present - changes in room info updates the is favorite flag`() = runTest {
val room = aJoinedRoom( val room = aJoinedRoom(
canInviteResult = { Result.success(true) }, roomPermissions = roomPermissions(),
canUserJoinCallResult = { Result.success(true) },
canSendStateResult = { _, _ -> Result.success(true) },
) )
val presenter = createRoomDetailsPresenter(room = room) val presenter = createRoomDetailsPresenter(room = room)
presenter.testWithLifecycleOwner(lifecycleOwner = fakeLifecycleOwner) { presenter.testWithLifecycleOwner(lifecycleOwner = fakeLifecycleOwner) {
@@ -686,9 +567,7 @@ class RoomDetailsPresenterTest {
@Test @Test
fun `present - show knock requests`() = runTest { fun `present - show knock requests`() = runTest {
val room = aJoinedRoom( val room = aJoinedRoom(
canInviteResult = { Result.success(true) }, roomPermissions = roomPermissions(),
canUserJoinCallResult = { Result.success(true) },
canSendStateResult = { _, _ -> Result.success(true) },
joinRule = JoinRule.Knock, joinRule = JoinRule.Knock,
) )
val featureFlagService = FakeFeatureFlagService( val featureFlagService = FakeFeatureFlagService(
@@ -712,9 +591,7 @@ class RoomDetailsPresenterTest {
@Test @Test
fun `present - show security and privacy`() = runTest { fun `present - show security and privacy`() = runTest {
val room = aJoinedRoom( val room = aJoinedRoom(
canInviteResult = { Result.success(true) }, roomPermissions = roomPermissions(),
canUserJoinCallResult = { Result.success(true) },
canSendStateResult = { _, _ -> Result.success(true) },
) )
val featureFlagService = FakeFeatureFlagService() val featureFlagService = FakeFeatureFlagService()
val presenter = createRoomDetailsPresenter(room = room, featureFlagService = featureFlagService) val presenter = createRoomDetailsPresenter(room = room, featureFlagService = featureFlagService)
@@ -729,9 +606,7 @@ class RoomDetailsPresenterTest {
@Test @Test
fun `present - show debug info`() = runTest { fun `present - show debug info`() = runTest {
val room = aJoinedRoom( val room = aJoinedRoom(
canInviteResult = { Result.success(true) }, roomPermissions = roomPermissions(),
canUserJoinCallResult = { Result.success(true) },
canSendStateResult = { _, _ -> Result.success(true) },
) )
val inMemoryAppPreferencesStore = InMemoryAppPreferencesStore( val inMemoryAppPreferencesStore = InMemoryAppPreferencesStore(
isDeveloperModeEnabled = true, isDeveloperModeEnabled = true,
@@ -744,4 +619,41 @@ class RoomDetailsPresenterTest {
} }
} }
} }
private fun roomPermissions(
canInvite: Boolean = true,
canKick: Boolean = true,
canBan: Boolean = true,
canRedactOther: Boolean = true,
canRedactOwn: Boolean = true,
canChangeRoomAccess: Boolean = true,
canChangeHistoryVisibility: Boolean = true,
canChangeEncryption: Boolean = true,
canChangeRoomVisibility: Boolean = true,
canChangeName: Boolean = true,
canChangeTopic: Boolean = true,
canChangeAvatar: Boolean = true,
canChangePowerLevels: Boolean = true,
): RoomPermissions {
return FakeRoomPermissions(
canInvite = canInvite,
canKick = canKick,
canBan = canBan,
canRedactOther = canRedactOther,
canRedactOwn = canRedactOwn,
canSendState = { eventType ->
when (eventType) {
StateEventType.ROOM_JOIN_RULES -> canChangeRoomAccess
StateEventType.ROOM_HISTORY_VISIBILITY -> canChangeHistoryVisibility
StateEventType.ROOM_ENCRYPTION -> canChangeEncryption
StateEventType.ROOM_CANONICAL_ALIAS -> canChangeRoomVisibility
StateEventType.ROOM_AVATAR -> canChangeAvatar
StateEventType.ROOM_NAME -> canChangeName
StateEventType.ROOM_TOPIC -> canChangeTopic
StateEventType.ROOM_POWER_LEVELS -> canChangePowerLevels
else -> lambdaError()
}
}
)
}
} }

View File

@@ -12,7 +12,6 @@ import com.google.common.truth.Truth.assertThat
import io.element.android.features.roommembermoderation.api.RoomMemberModerationState import io.element.android.features.roommembermoderation.api.RoomMemberModerationState
import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.architecture.Presenter
import io.element.android.libraries.core.coroutine.CoroutineDispatchers import io.element.android.libraries.core.coroutine.CoroutineDispatchers
import io.element.android.libraries.matrix.api.core.UserId
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.RoomMembersState import io.element.android.libraries.matrix.api.room.RoomMembersState
import io.element.android.libraries.matrix.api.room.RoomMembershipState import io.element.android.libraries.matrix.api.room.RoomMembershipState
@@ -20,6 +19,7 @@ import io.element.android.libraries.matrix.test.encryption.FakeEncryptionService
import io.element.android.libraries.matrix.test.room.FakeBaseRoom 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.libraries.matrix.test.room.aRoomInfo import io.element.android.libraries.matrix.test.room.aRoomInfo
import io.element.android.libraries.matrix.test.room.powerlevels.FakeRoomPermissions
import io.element.android.tests.testutils.WarmUpRule import io.element.android.tests.testutils.WarmUpRule
import io.element.android.tests.testutils.test import io.element.android.tests.testutils.test
import io.element.android.tests.testutils.testCoroutineDispatchers import io.element.android.tests.testutils.testCoroutineDispatchers
@@ -171,20 +171,7 @@ class RoomMemberListPresenterTest {
fun `present - asynchronously sets canInvite when user does not have correct power level`() = runTest { fun `present - asynchronously sets canInvite when user does not have correct power level`() = runTest {
val presenter = createPresenter( val presenter = createPresenter(
joinedRoom = createFakeJoinedRoom( joinedRoom = createFakeJoinedRoom(
canInviteResult = { Result.success(false) }, canInvite = false,
)
)
presenter.test {
val loadedState = awaitItem()
assertThat(loadedState.canInvite).isFalse()
}
}
@Test
fun `present - asynchronously sets canInvite when power level check fails`() = runTest {
val presenter = createPresenter(
joinedRoom = createFakeJoinedRoom(
canInviteResult = { Result.failure(RuntimeException("Eek")) },
) )
) )
presenter.test { presenter.test {
@@ -207,12 +194,14 @@ class RoomMemberListPresenterTest {
private fun createFakeJoinedRoom( private fun createFakeJoinedRoom(
updateMembersResult: () -> Unit = { }, updateMembersResult: () -> Unit = { },
canInviteResult: (UserId) -> Result<Boolean> = { Result.success(true) }, canInvite: Boolean = true,
): FakeJoinedRoom { ): FakeJoinedRoom {
return FakeJoinedRoom( return FakeJoinedRoom(
baseRoom = FakeBaseRoom( baseRoom = FakeBaseRoom(
updateMembersResult = updateMembersResult, updateMembersResult = updateMembersResult,
canInviteResult = canInviteResult, roomPermissions = FakeRoomPermissions(
canInvite = canInvite,
),
).apply { ).apply {
// Needed to avoid discarding the loaded members as a partial and invalid result // Needed to avoid discarding the loaded members as a partial and invalid result
givenRoomInfo(aRoomInfo(joinedMembersCount = 2)) givenRoomInfo(aRoomInfo(joinedMembersCount = 2))

View File

@@ -14,7 +14,7 @@ data class RoomDetailsEditPermissions(
val canEditName: Boolean, val canEditName: Boolean,
val canEditTopic: Boolean, val canEditTopic: Boolean,
val canEditAvatar: Boolean, val canEditAvatar: Boolean,
){ ) {
val hasAny = canEditName || val hasAny = canEditName ||
canEditTopic || canEditTopic ||
canEditAvatar canEditAvatar

View File

@@ -59,7 +59,6 @@ class RoomDetailsEditPresenter(
@Composable @Composable
override fun present(): RoomDetailsEditState { override fun present(): RoomDetailsEditState {
val cameraPermissionState = cameraPermissionPresenter.present() val cameraPermissionState = cameraPermissionPresenter.present()
val roomSyncUpdateFlow = room.syncUpdateFlow.collectAsState()
val roomInfo by room.roomInfoFlow.collectAsState() val roomInfo by room.roomInfoFlow.collectAsState()
val roomAvatarUri = roomInfo.avatarUrl val roomAvatarUri = roomInfo.avatarUrl
var roomAvatarUriEdited by rememberSaveable { mutableStateOf<String?>(null) } var roomAvatarUriEdited by rememberSaveable { mutableStateOf<String?>(null) }
@@ -94,7 +93,7 @@ class RoomDetailsEditPresenter(
} }
} }
val permissions by room.permissionsAsState(RoomDetailsEditPermissions.DEFAULT){perms -> val permissions by room.permissionsAsState(RoomDetailsEditPermissions.DEFAULT) { perms ->
perms.roomDetailsEditPermissions() perms.roomDetailsEditPermissions()
} }

View File

@@ -13,7 +13,6 @@ import com.google.common.truth.Truth.assertThat
import io.element.android.libraries.androidutils.file.TemporaryUriDeleter import io.element.android.libraries.androidutils.file.TemporaryUriDeleter
import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.architecture.AsyncAction
import io.element.android.libraries.core.mimetype.MimeTypes import io.element.android.libraries.core.mimetype.MimeTypes
import io.element.android.libraries.matrix.api.core.UserId
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.StateEventType import io.element.android.libraries.matrix.api.room.StateEventType
import io.element.android.libraries.matrix.test.AN_AVATAR_URL import io.element.android.libraries.matrix.test.AN_AVATAR_URL
@@ -23,6 +22,7 @@ import io.element.android.libraries.matrix.test.A_ROOM_TOPIC
import io.element.android.libraries.matrix.test.room.FakeBaseRoom 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.libraries.matrix.test.room.aRoomInfo import io.element.android.libraries.matrix.test.room.aRoomInfo
import io.element.android.libraries.matrix.test.room.powerlevels.FakeRoomPermissions
import io.element.android.libraries.matrix.ui.media.AvatarAction import io.element.android.libraries.matrix.ui.media.AvatarAction
import io.element.android.libraries.mediapickers.test.FakePickerProvider import io.element.android.libraries.mediapickers.test.FakePickerProvider
import io.element.android.libraries.mediaupload.api.MediaUploadInfo import io.element.android.libraries.mediaupload.api.MediaUploadInfo
@@ -102,7 +102,6 @@ class RoomDetailsEditPresenterTest {
avatarUrl = AN_AVATAR_URL, avatarUrl = AN_AVATAR_URL,
displayName = A_ROOM_NAME, displayName = A_ROOM_NAME,
rawName = A_ROOM_RAW_NAME, rawName = A_ROOM_RAW_NAME,
canSendStateResult = { _, _ -> Result.success(true) }
) )
val deleteCallback = lambdaRecorder<Uri?, Unit> {} val deleteCallback = lambdaRecorder<Uri?, Unit> {}
val presenter = createRoomDetailsEditPresenter( val presenter = createRoomDetailsEditPresenter(
@@ -127,17 +126,15 @@ class RoomDetailsEditPresenterTest {
@Test @Test
fun `present - sets canChangeName if user has permission`() = runTest { fun `present - sets canChangeName if user has permission`() = runTest {
val room = FakeJoinedRoom( val room = aJoinedRoom(
FakeBaseRoom( canSendState = { stateEventType ->
canSendStateResult = { _, stateEventType -> when (stateEventType) {
when (stateEventType) { StateEventType.ROOM_NAME -> true
StateEventType.ROOM_NAME -> Result.success(true) StateEventType.ROOM_AVATAR -> false
StateEventType.ROOM_AVATAR -> Result.success(false) StateEventType.ROOM_TOPIC -> false
StateEventType.ROOM_TOPIC -> Result.failure(RuntimeException("Oops")) else -> lambdaError()
else -> lambdaError() }
} }
},
)
) )
val deleteCallback = lambdaRecorder<Uri?, Unit> {} val deleteCallback = lambdaRecorder<Uri?, Unit> {}
val presenter = createRoomDetailsEditPresenter( val presenter = createRoomDetailsEditPresenter(
@@ -163,11 +160,11 @@ class RoomDetailsEditPresenterTest {
fun `present - sets canChangeAvatar if user has permission`() = runTest { fun `present - sets canChangeAvatar if user has permission`() = runTest {
val room = aJoinedRoom( val room = aJoinedRoom(
avatarUrl = AN_AVATAR_URL, avatarUrl = AN_AVATAR_URL,
canSendStateResult = { _, stateEventType -> canSendState = { stateEventType ->
when (stateEventType) { when (stateEventType) {
StateEventType.ROOM_NAME -> Result.success(false) StateEventType.ROOM_NAME -> false
StateEventType.ROOM_AVATAR -> Result.success(true) StateEventType.ROOM_AVATAR -> true
StateEventType.ROOM_TOPIC -> Result.failure(RuntimeException("Oops")) StateEventType.ROOM_TOPIC -> false
else -> lambdaError() else -> lambdaError()
} }
} }
@@ -195,11 +192,11 @@ class RoomDetailsEditPresenterTest {
fun `present - sets canChangeTopic if user has permission`() = runTest { fun `present - sets canChangeTopic if user has permission`() = runTest {
val room = aJoinedRoom( val room = aJoinedRoom(
avatarUrl = AN_AVATAR_URL, avatarUrl = AN_AVATAR_URL,
canSendStateResult = { _, stateEventType -> canSendState = { stateEventType ->
when (stateEventType) { when (stateEventType) {
StateEventType.ROOM_NAME -> Result.success(false) StateEventType.ROOM_NAME -> false
StateEventType.ROOM_AVATAR -> Result.failure(RuntimeException("Oops")) StateEventType.ROOM_AVATAR -> false
StateEventType.ROOM_TOPIC -> Result.success(true) StateEventType.ROOM_TOPIC -> true
else -> lambdaError() else -> lambdaError()
} }
} }
@@ -229,7 +226,6 @@ class RoomDetailsEditPresenterTest {
topic = "My topic", topic = "My topic",
displayName = "Name", displayName = "Name",
avatarUrl = AN_AVATAR_URL, avatarUrl = AN_AVATAR_URL,
canSendStateResult = { _, _ -> Result.success(true) }
) )
val deleteCallback = lambdaRecorder<Uri?, Unit> {} val deleteCallback = lambdaRecorder<Uri?, Unit> {}
val presenter = createRoomDetailsEditPresenter( val presenter = createRoomDetailsEditPresenter(
@@ -274,7 +270,6 @@ class RoomDetailsEditPresenterTest {
topic = "My topic", topic = "My topic",
displayName = "Name", displayName = "Name",
avatarUrl = AN_AVATAR_URL, avatarUrl = AN_AVATAR_URL,
canSendStateResult = { _, _ -> Result.success(true) }
) )
fakePickerProvider.givenResult(anotherAvatarUri) fakePickerProvider.givenResult(anotherAvatarUri)
val deleteCallback = lambdaRecorder<Uri?, Unit> {} val deleteCallback = lambdaRecorder<Uri?, Unit> {}
@@ -298,7 +293,6 @@ class RoomDetailsEditPresenterTest {
topic = "My topic", topic = "My topic",
displayName = "Name", displayName = "Name",
avatarUrl = AN_AVATAR_URL, avatarUrl = AN_AVATAR_URL,
canSendStateResult = { _, _ -> Result.success(true) }
) )
fakePickerProvider.givenResult(anotherAvatarUri) fakePickerProvider.givenResult(anotherAvatarUri)
val fakePermissionsPresenter = FakePermissionsPresenter() val fakePermissionsPresenter = FakePermissionsPresenter()
@@ -339,7 +333,6 @@ class RoomDetailsEditPresenterTest {
topic = "My topic", topic = "My topic",
displayName = "Name", displayName = "Name",
avatarUrl = AN_AVATAR_URL, avatarUrl = AN_AVATAR_URL,
canSendStateResult = { _, _ -> Result.success(true) }
) )
fakePickerProvider.givenResult(roomAvatarUri) fakePickerProvider.givenResult(roomAvatarUri)
val deleteCallback = lambdaRecorder<Uri?, Unit> {} val deleteCallback = lambdaRecorder<Uri?, Unit> {}
@@ -389,7 +382,6 @@ class RoomDetailsEditPresenterTest {
topic = null, topic = null,
displayName = "fallback", displayName = "fallback",
avatarUrl = null, avatarUrl = null,
canSendStateResult = { _, _ -> Result.success(true) }
) )
fakePickerProvider.givenResult(roomAvatarUri) fakePickerProvider.givenResult(roomAvatarUri)
val deleteCallback = lambdaRecorder<Uri?, Unit> {} val deleteCallback = lambdaRecorder<Uri?, Unit> {}
@@ -445,7 +437,6 @@ class RoomDetailsEditPresenterTest {
setNameResult = setNameResult, setNameResult = setNameResult,
setTopicResult = setTopicResult, setTopicResult = setTopicResult,
removeAvatarResult = removeAvatarResult, removeAvatarResult = removeAvatarResult,
canSendStateResult = { _, _ -> Result.success(true) }
) )
val deleteCallback = lambdaRecorder<Uri?, Unit> {} val deleteCallback = lambdaRecorder<Uri?, Unit> {}
val presenter = createRoomDetailsEditPresenter( val presenter = createRoomDetailsEditPresenter(
@@ -471,7 +462,6 @@ class RoomDetailsEditPresenterTest {
topic = "My topic", topic = "My topic",
displayName = "Name", displayName = "Name",
avatarUrl = AN_AVATAR_URL, avatarUrl = AN_AVATAR_URL,
canSendStateResult = { _, _ -> Result.success(true) }
) )
val deleteCallback = lambdaRecorder<Uri?, Unit> {} val deleteCallback = lambdaRecorder<Uri?, Unit> {}
val presenter = createRoomDetailsEditPresenter( val presenter = createRoomDetailsEditPresenter(
@@ -493,7 +483,6 @@ class RoomDetailsEditPresenterTest {
topic = null, topic = null,
displayName = "Name", displayName = "Name",
avatarUrl = AN_AVATAR_URL, avatarUrl = AN_AVATAR_URL,
canSendStateResult = { _, _ -> Result.success(true) }
) )
val deleteCallback = lambdaRecorder<Uri?, Unit> {} val deleteCallback = lambdaRecorder<Uri?, Unit> {}
val presenter = createRoomDetailsEditPresenter( val presenter = createRoomDetailsEditPresenter(
@@ -515,7 +504,6 @@ class RoomDetailsEditPresenterTest {
topic = "My topic", topic = "My topic",
displayName = "Name", displayName = "Name",
avatarUrl = AN_AVATAR_URL, avatarUrl = AN_AVATAR_URL,
canSendStateResult = { _, _ -> Result.success(true) }
) )
val deleteCallback = lambdaRecorder<Uri?, Unit> {} val deleteCallback = lambdaRecorder<Uri?, Unit> {}
val presenter = createRoomDetailsEditPresenter( val presenter = createRoomDetailsEditPresenter(
@@ -539,7 +527,6 @@ class RoomDetailsEditPresenterTest {
displayName = "Name", displayName = "Name",
avatarUrl = AN_AVATAR_URL, avatarUrl = AN_AVATAR_URL,
updateAvatarResult = updateAvatarResult, updateAvatarResult = updateAvatarResult,
canSendStateResult = { _, _ -> Result.success(true) }
) )
givenPickerReturnsFile() givenPickerReturnsFile()
val deleteCallback = lambdaRecorder<Uri?, Unit> {} val deleteCallback = lambdaRecorder<Uri?, Unit> {}
@@ -566,7 +553,6 @@ class RoomDetailsEditPresenterTest {
topic = "My topic", topic = "My topic",
displayName = "Name", displayName = "Name",
avatarUrl = AN_AVATAR_URL, avatarUrl = AN_AVATAR_URL,
canSendStateResult = { _, _ -> Result.success(true) }
) )
fakePickerProvider.givenResult(anotherAvatarUri) fakePickerProvider.givenResult(anotherAvatarUri)
fakeMediaPreProcessor.givenResult(Result.failure(RuntimeException("Oh no"))) fakeMediaPreProcessor.givenResult(Result.failure(RuntimeException("Oh no")))
@@ -591,7 +577,6 @@ class RoomDetailsEditPresenterTest {
displayName = "Name", displayName = "Name",
avatarUrl = AN_AVATAR_URL, avatarUrl = AN_AVATAR_URL,
setNameResult = { Result.failure(RuntimeException("!")) }, setNameResult = { Result.failure(RuntimeException("!")) },
canSendStateResult = { _, _ -> Result.success(true) }
) )
saveAndAssertFailure(room, RoomDetailsEditEvent.UpdateRoomName("New name"), deleteCallbackNumberOfInvocation = 1) saveAndAssertFailure(room, RoomDetailsEditEvent.UpdateRoomName("New name"), deleteCallbackNumberOfInvocation = 1)
} }
@@ -603,7 +588,6 @@ class RoomDetailsEditPresenterTest {
displayName = "Name", displayName = "Name",
avatarUrl = AN_AVATAR_URL, avatarUrl = AN_AVATAR_URL,
setTopicResult = { Result.failure(RuntimeException("!")) }, setTopicResult = { Result.failure(RuntimeException("!")) },
canSendStateResult = { _, _ -> Result.success(true) }
) )
saveAndAssertFailure(room, RoomDetailsEditEvent.UpdateRoomTopic("New topic"), deleteCallbackNumberOfInvocation = 1) saveAndAssertFailure(room, RoomDetailsEditEvent.UpdateRoomTopic("New topic"), deleteCallbackNumberOfInvocation = 1)
} }
@@ -615,7 +599,6 @@ class RoomDetailsEditPresenterTest {
displayName = "Name", displayName = "Name",
avatarUrl = AN_AVATAR_URL, avatarUrl = AN_AVATAR_URL,
removeAvatarResult = { Result.failure(RuntimeException("!")) }, removeAvatarResult = { Result.failure(RuntimeException("!")) },
canSendStateResult = { _, _ -> Result.success(true) }
) )
saveAndAssertFailure(room, RoomDetailsEditEvent.HandleAvatarAction(AvatarAction.Remove), deleteCallbackNumberOfInvocation = 2) saveAndAssertFailure(room, RoomDetailsEditEvent.HandleAvatarAction(AvatarAction.Remove), deleteCallbackNumberOfInvocation = 2)
} }
@@ -628,7 +611,6 @@ class RoomDetailsEditPresenterTest {
displayName = "Name", displayName = "Name",
avatarUrl = AN_AVATAR_URL, avatarUrl = AN_AVATAR_URL,
updateAvatarResult = { _, _ -> Result.failure(RuntimeException("!")) }, updateAvatarResult = { _, _ -> Result.failure(RuntimeException("!")) },
canSendStateResult = { _, _ -> Result.success(true) }
) )
saveAndAssertFailure(room, RoomDetailsEditEvent.HandleAvatarAction(AvatarAction.ChoosePhoto), deleteCallbackNumberOfInvocation = 2) saveAndAssertFailure(room, RoomDetailsEditEvent.HandleAvatarAction(AvatarAction.ChoosePhoto), deleteCallbackNumberOfInvocation = 2)
} }
@@ -641,7 +623,6 @@ class RoomDetailsEditPresenterTest {
displayName = "Name", displayName = "Name",
avatarUrl = AN_AVATAR_URL, avatarUrl = AN_AVATAR_URL,
setTopicResult = { Result.failure(RuntimeException("!")) }, setTopicResult = { Result.failure(RuntimeException("!")) },
canSendStateResult = { _, _ -> Result.success(true) }
) )
val deleteCallback = lambdaRecorder<Uri?, Unit> {} val deleteCallback = lambdaRecorder<Uri?, Unit> {}
val presenter = createRoomDetailsEditPresenter( val presenter = createRoomDetailsEditPresenter(
@@ -663,7 +644,6 @@ class RoomDetailsEditPresenterTest {
fun `present - leave without saving - cancel`() = runTest { fun `present - leave without saving - cancel`() = runTest {
val room = aJoinedRoom( val room = aJoinedRoom(
displayName = "Name", displayName = "Name",
canSendStateResult = { _, _ -> Result.success(true) }
) )
val deleteCallback = lambdaRecorder<Uri?, Unit> {} val deleteCallback = lambdaRecorder<Uri?, Unit> {}
val presenter = createRoomDetailsEditPresenter( val presenter = createRoomDetailsEditPresenter(
@@ -693,7 +673,6 @@ class RoomDetailsEditPresenterTest {
fun `present - leave no changes, no confirmation`() = runTest { fun `present - leave no changes, no confirmation`() = runTest {
val room = aJoinedRoom( val room = aJoinedRoom(
displayName = "Name", displayName = "Name",
canSendStateResult = { _, _ -> Result.success(true) }
) )
val presenter = createRoomDetailsEditPresenter( val presenter = createRoomDetailsEditPresenter(
room = room, room = room,
@@ -711,7 +690,7 @@ class RoomDetailsEditPresenterTest {
fun `present - leave without saving - confirm`() = runTest { fun `present - leave without saving - confirm`() = runTest {
val room = aJoinedRoom( val room = aJoinedRoom(
displayName = "Name", displayName = "Name",
canSendStateResult = { _, _ -> Result.success(true) } canSendState = { _ -> true }
) )
val presenter = createRoomDetailsEditPresenter( val presenter = createRoomDetailsEditPresenter(
room = room, room = room,
@@ -782,11 +761,13 @@ class RoomDetailsEditPresenterTest {
setTopicResult: (String) -> Result<Unit> = { Result.success(Unit) }, setTopicResult: (String) -> Result<Unit> = { Result.success(Unit) },
updateAvatarResult: (String, ByteArray) -> Result<Unit> = { _, _ -> Result.success(Unit) }, updateAvatarResult: (String, ByteArray) -> Result<Unit> = { _, _ -> Result.success(Unit) },
removeAvatarResult: () -> Result<Unit> = { Result.success(Unit) }, removeAvatarResult: () -> Result<Unit> = { Result.success(Unit) },
canSendStateResult: (UserId, StateEventType) -> Result<Boolean>, canSendState: (StateEventType) -> Boolean = { true },
): JoinedRoom { ): JoinedRoom {
return FakeJoinedRoom( return FakeJoinedRoom(
baseRoom = FakeBaseRoom( baseRoom = FakeBaseRoom(
canSendStateResult = canSendStateResult, roomPermissions = FakeRoomPermissions(
canSendState = canSendState,
),
initialRoomInfo = aRoomInfo( initialRoomInfo = aRoomInfo(
name = displayName, name = displayName,
topic = topic, topic = topic,

View File

@@ -25,6 +25,7 @@ import io.element.android.libraries.matrix.test.A_USER_ID
import io.element.android.libraries.matrix.test.room.FakeBaseRoom 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.libraries.matrix.test.room.aRoomMember import io.element.android.libraries.matrix.test.room.aRoomMember
import io.element.android.libraries.matrix.test.room.powerlevels.FakeRoomPermissions
import io.element.android.services.analytics.api.AnalyticsService import io.element.android.services.analytics.api.AnalyticsService
import io.element.android.services.analytics.test.FakeAnalyticsService import io.element.android.services.analytics.test.FakeAnalyticsService
import io.element.android.tests.testutils.WarmUpRule import io.element.android.tests.testutils.WarmUpRule
@@ -355,8 +356,10 @@ class RoomMemberModerationPresenterTest {
banUserResult = { _, _ -> banUserResult }, banUserResult = { _, _ -> banUserResult },
unBanUserResult = { _, _ -> unBanUserResult }, unBanUserResult = { _, _ -> unBanUserResult },
baseRoom = FakeBaseRoom( baseRoom = FakeBaseRoom(
canBanResult = { _ -> Result.success(canBan) }, roomPermissions = FakeRoomPermissions(
canKickResult = { _ -> Result.success(canKick) }, canBan = canBan,
canKick = canKick
),
userRoleResult = { Result.success(myUserRole) }, userRoleResult = { Result.success(myUserRole) },
updateMembersResult = { Result.success(Unit) } updateMembersResult = { Result.success(Unit) }
), ),

View File

@@ -67,7 +67,6 @@ class SecurityAndPrivacyPresenter(
}.collectAsState(false) }.collectAsState(false)
val saveAction = remember { mutableStateOf<AsyncAction<Unit>>(AsyncAction.Uninitialized) } val saveAction = remember { mutableStateOf<AsyncAction<Unit>>(AsyncAction.Uninitialized) }
val homeserverName = remember { matrixClient.userIdServerName() } val homeserverName = remember { matrixClient.userIdServerName() }
val syncUpdateFlow = room.syncUpdateFlow.collectAsState()
val roomInfo by room.roomInfoFlow.collectAsState() val roomInfo by room.roomInfoFlow.collectAsState()
val savedIsVisibleInRoomDirectory = remember { mutableStateOf<AsyncData<Boolean>>(AsyncData.Uninitialized) } val savedIsVisibleInRoomDirectory = remember { mutableStateOf<AsyncData<Boolean>>(AsyncData.Uninitialized) }

View File

@@ -18,15 +18,19 @@ import io.element.android.libraries.architecture.AsyncData
import io.element.android.libraries.featureflag.api.FeatureFlagService import io.element.android.libraries.featureflag.api.FeatureFlagService
import io.element.android.libraries.featureflag.api.FeatureFlags import io.element.android.libraries.featureflag.api.FeatureFlags
import io.element.android.libraries.featureflag.test.FakeFeatureFlagService import io.element.android.libraries.featureflag.test.FakeFeatureFlagService
import io.element.android.libraries.matrix.api.room.StateEventType
import io.element.android.libraries.matrix.api.room.history.RoomHistoryVisibility import io.element.android.libraries.matrix.api.room.history.RoomHistoryVisibility
import io.element.android.libraries.matrix.api.room.join.JoinRule import io.element.android.libraries.matrix.api.room.join.JoinRule
import io.element.android.libraries.matrix.api.room.powerlevels.RoomPermissions
import io.element.android.libraries.matrix.api.roomdirectory.RoomVisibility import io.element.android.libraries.matrix.api.roomdirectory.RoomVisibility
import io.element.android.libraries.matrix.test.A_ROOM_ALIAS import io.element.android.libraries.matrix.test.A_ROOM_ALIAS
import io.element.android.libraries.matrix.test.FakeMatrixClient import io.element.android.libraries.matrix.test.FakeMatrixClient
import io.element.android.libraries.matrix.test.room.FakeBaseRoom 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.libraries.matrix.test.room.aRoomInfo import io.element.android.libraries.matrix.test.room.aRoomInfo
import io.element.android.libraries.matrix.test.room.powerlevels.FakeRoomPermissions
import io.element.android.tests.testutils.lambda.assert import io.element.android.tests.testutils.lambda.assert
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 io.element.android.tests.testutils.test import io.element.android.tests.testutils.test
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
@@ -66,7 +70,7 @@ class SecurityAndPrivacyPresenterTest {
fun `present - room info change updates saved and edited settings`() = runTest { fun `present - room info change updates saved and edited settings`() = runTest {
val room = FakeJoinedRoom( val room = FakeJoinedRoom(
baseRoom = FakeBaseRoom( baseRoom = FakeBaseRoom(
canSendStateResult = { _, _ -> Result.success(true) }, roomPermissions = roomPermissions(),
initialRoomInfo = aRoomInfo( initialRoomInfo = aRoomInfo(
joinRule = JoinRule.Public, joinRule = JoinRule.Public,
historyVisibility = RoomHistoryVisibility.WorldReadable, historyVisibility = RoomHistoryVisibility.WorldReadable,
@@ -173,7 +177,7 @@ class SecurityAndPrivacyPresenterTest {
fun `present - room visibility loading and change`() = runTest { fun `present - room visibility loading and change`() = runTest {
val room = FakeJoinedRoom( val room = FakeJoinedRoom(
baseRoom = FakeBaseRoom( baseRoom = FakeBaseRoom(
canSendStateResult = { _, _ -> Result.success(true) }, roomPermissions = roomPermissions(),
getRoomVisibilityResult = { Result.success(RoomVisibility.Private) }, getRoomVisibilityResult = { Result.success(RoomVisibility.Private) },
initialRoomInfo = aRoomInfo(historyVisibility = RoomHistoryVisibility.Shared) initialRoomInfo = aRoomInfo(historyVisibility = RoomHistoryVisibility.Shared)
) )
@@ -222,7 +226,7 @@ class SecurityAndPrivacyPresenterTest {
val updateRoomHistoryVisibilityLambda = lambdaRecorder<RoomHistoryVisibility, Result<Unit>> { Result.success(Unit) } val updateRoomHistoryVisibilityLambda = lambdaRecorder<RoomHistoryVisibility, Result<Unit>> { Result.success(Unit) }
val room = FakeJoinedRoom( val room = FakeJoinedRoom(
baseRoom = FakeBaseRoom( baseRoom = FakeBaseRoom(
canSendStateResult = { _, _ -> Result.success(true) }, roomPermissions = roomPermissions(),
getRoomVisibilityResult = { Result.success(RoomVisibility.Private) }, getRoomVisibilityResult = { Result.success(RoomVisibility.Private) },
initialRoomInfo = aRoomInfo(joinRule = JoinRule.Invite, historyVisibility = RoomHistoryVisibility.Shared) initialRoomInfo = aRoomInfo(joinRule = JoinRule.Invite, historyVisibility = RoomHistoryVisibility.Shared)
), ),
@@ -272,8 +276,8 @@ class SecurityAndPrivacyPresenterTest {
isEncrypted = true, isEncrypted = true,
) )
) )
// Saved settings are updated 3 times to match the edited settings // Saved settings are updated 2 times to match the edited settings
skipItems(3) skipItems(2)
with(awaitItem()) { with(awaitItem()) {
assertThat(saveAction).isEqualTo(AsyncAction.Success(Unit)) assertThat(saveAction).isEqualTo(AsyncAction.Success(Unit))
assertThat(savedSettings).isEqualTo(editedSettings) assertThat(savedSettings).isEqualTo(editedSettings)
@@ -297,7 +301,7 @@ class SecurityAndPrivacyPresenterTest {
val updateRoomHistoryVisibilityLambda = lambdaRecorder<RoomHistoryVisibility, Result<Unit>> { Result.success(Unit) } val updateRoomHistoryVisibilityLambda = lambdaRecorder<RoomHistoryVisibility, Result<Unit>> { Result.success(Unit) }
val room = FakeJoinedRoom( val room = FakeJoinedRoom(
baseRoom = FakeBaseRoom( baseRoom = FakeBaseRoom(
canSendStateResult = { _, _ -> Result.success(true) }, roomPermissions = roomPermissions(),
getRoomVisibilityResult = { Result.success(RoomVisibility.Private) }, getRoomVisibilityResult = { Result.success(RoomVisibility.Private) },
initialRoomInfo = aRoomInfo(historyVisibility = RoomHistoryVisibility.Shared, joinRule = JoinRule.Private) initialRoomInfo = aRoomInfo(historyVisibility = RoomHistoryVisibility.Shared, joinRule = JoinRule.Private)
), ),
@@ -340,7 +344,7 @@ class SecurityAndPrivacyPresenterTest {
) )
) )
// Saved settings are updated 2 times to match the edited settings // Saved settings are updated 2 times to match the edited settings
skipItems(3) skipItems(2)
val state = awaitItem() val state = awaitItem()
with(state) { with(state) {
assertThat(saveAction).isInstanceOf(AsyncAction.Failure::class.java) assertThat(saveAction).isInstanceOf(AsyncAction.Failure::class.java)
@@ -374,11 +378,30 @@ class SecurityAndPrivacyPresenterTest {
} }
} }
private fun roomPermissions(
canChangeRoomAccess: Boolean = true,
canChangeHistoryVisibility: Boolean = true,
canChangeEncryption: Boolean = true,
canChangeRoomVisibility: Boolean = true,
): RoomPermissions {
return FakeRoomPermissions(
canSendState = { eventType ->
when (eventType) {
StateEventType.ROOM_JOIN_RULES -> canChangeRoomAccess
StateEventType.ROOM_HISTORY_VISIBILITY -> canChangeHistoryVisibility
StateEventType.ROOM_ENCRYPTION -> canChangeEncryption
StateEventType.ROOM_CANONICAL_ALIAS -> canChangeRoomVisibility
else -> lambdaError()
}
}
)
}
private fun createSecurityAndPrivacyPresenter( private fun createSecurityAndPrivacyPresenter(
serverName: String = "matrix.org", serverName: String = "matrix.org",
room: FakeJoinedRoom = FakeJoinedRoom( room: FakeJoinedRoom = FakeJoinedRoom(
baseRoom = FakeBaseRoom( baseRoom = FakeBaseRoom(
canSendStateResult = { _, _ -> Result.success(true) }, roomPermissions = roomPermissions(),
getRoomVisibilityResult = { Result.success(RoomVisibility.Private) }, getRoomVisibilityResult = { Result.success(RoomVisibility.Private) },
initialRoomInfo = aRoomInfo(historyVisibility = RoomHistoryVisibility.Shared, joinRule = JoinRule.Private) initialRoomInfo = aRoomInfo(historyVisibility = RoomHistoryVisibility.Shared, joinRule = JoinRule.Private)
), ),

View File

@@ -76,7 +76,7 @@ class UserProfilePresenter(
roomId roomId
?.let { client.getRoom(it) } ?.let { client.getRoom(it) }
?.use { room -> ?.use { room ->
room.roomPermissions().use(false){ perms -> perms.canCall()} room.roomPermissions().use(false) { perms -> perms.canCall() }
} }
.orFalse() .orFalse()
} }

View File

@@ -28,6 +28,7 @@ import io.element.android.libraries.matrix.api.MatrixClient
import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.api.encryption.identity.IdentityState import io.element.android.libraries.matrix.api.encryption.identity.IdentityState
import io.element.android.libraries.matrix.api.room.StateEventType
import io.element.android.libraries.matrix.api.user.MatrixUser import io.element.android.libraries.matrix.api.user.MatrixUser
import io.element.android.libraries.matrix.test.AN_EXCEPTION import io.element.android.libraries.matrix.test.AN_EXCEPTION
import io.element.android.libraries.matrix.test.A_ROOM_ID import io.element.android.libraries.matrix.test.A_ROOM_ID
@@ -36,9 +37,11 @@ import io.element.android.libraries.matrix.test.A_USER_ID_2
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.room.FakeBaseRoom import io.element.android.libraries.matrix.test.room.FakeBaseRoom
import io.element.android.libraries.matrix.test.room.powerlevels.FakeRoomPermissions
import io.element.android.libraries.matrix.ui.components.aMatrixUser import io.element.android.libraries.matrix.ui.components.aMatrixUser
import io.element.android.tests.testutils.WarmUpRule import io.element.android.tests.testutils.WarmUpRule
import io.element.android.tests.testutils.lambda.any import io.element.android.tests.testutils.lambda.any
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 io.element.android.tests.testutils.lambda.value import io.element.android.tests.testutils.lambda.value
import io.element.android.tests.testutils.test import io.element.android.tests.testutils.test
@@ -89,15 +92,7 @@ class UserProfilePresenterTest {
@Test @Test
fun `present - canCall is false when canUserJoinCall returns false`() { fun `present - canCall is false when canUserJoinCall returns false`() {
testCanCall( testCanCall(
canUserJoinCallResult = Result.success(false), canUserJoinCall = false,
expectedResult = false,
)
}
@Test
fun `present - canCall is false when canUserJoinCall fails`() {
testCanCall(
canUserJoinCallResult = Result.failure(AN_EXCEPTION),
expectedResult = false, expectedResult = false,
) )
} }
@@ -128,7 +123,7 @@ class UserProfilePresenterTest {
private fun testCanCall( private fun testCanCall(
isElementCallAvailable: Boolean = true, isElementCallAvailable: Boolean = true,
canUserJoinCallResult: Result<Boolean> = Result.success(true), canUserJoinCall: Boolean = true,
dmRoom: RoomId? = A_ROOM_ID, dmRoom: RoomId? = A_ROOM_ID,
canFindRoom: Boolean = true, canFindRoom: Boolean = true,
expectedResult: Boolean, expectedResult: Boolean,
@@ -136,7 +131,14 @@ class UserProfilePresenterTest {
checkThatRoomIsDestroyed: Boolean = false, checkThatRoomIsDestroyed: Boolean = false,
) = runTest { ) = runTest {
val room = FakeBaseRoom( val room = FakeBaseRoom(
canUserJoinCallResult = { canUserJoinCallResult }, roomPermissions = FakeRoomPermissions(
canSendState = { type ->
when (type) {
StateEventType.CALL_MEMBER -> canUserJoinCall
else -> lambdaError()
}
}
),
) )
val client = createFakeMatrixClient().apply { val client = createFakeMatrixClient().apply {
if (canFindRoom) { if (canFindRoom) {

View File

@@ -18,7 +18,6 @@ import io.element.android.libraries.matrix.api.room.StateEventType
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import timber.log.Timber
/** /**
* Provides information about the permissions of users in a room. * Provides information about the permissions of users in a room.
@@ -150,7 +149,15 @@ fun <T> Result<RoomPermissions>.use(default: T, block: (RoomPermissions) -> T):
fun <T> BaseRoom.permissionsFlow(default: T, block: (RoomPermissions) -> T): Flow<T> { fun <T> BaseRoom.permissionsFlow(default: T, block: (RoomPermissions) -> T): Flow<T> {
return roomInfoFlow return roomInfoFlow
.map { info -> info.roomPowerLevels } .map { info ->
// If the user is a privileged creator, we return a constant hashcode to avoid recomputing permissions
// each time the power levels change (as they have all permissions).
if (info.privilegedCreatorRole && info.creators.contains(sessionId)) {
Long.MAX_VALUE
} else {
info.roomPowerLevels?.hashCode() ?: 0L
}
}
.distinctUntilChanged() .distinctUntilChanged()
.map { .map {
roomPermissions().use(default, block) roomPermissions().use(default, block)
@@ -160,7 +167,6 @@ fun <T> BaseRoom.permissionsFlow(default: T, block: (RoomPermissions) -> T): Flo
@Composable @Composable
fun <T> BaseRoom.permissionsAsState(default: T, block: (RoomPermissions) -> T): State<T> { fun <T> BaseRoom.permissionsAsState(default: T, block: (RoomPermissions) -> T): State<T> {
return remember(this, default, block) { return remember(this, default, block) {
Timber.d("Computing permissionsAsState for room $roomId with default=$default")
permissionsFlow(default, block) permissionsFlow(default, block)
}.collectAsState(default) }.collectAsState(default)
} }

View File

@@ -18,12 +18,10 @@ import io.element.android.libraries.matrix.api.core.SessionId
import io.element.android.libraries.matrix.api.core.ThreadId import io.element.android.libraries.matrix.api.core.ThreadId
import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.api.room.BaseRoom import io.element.android.libraries.matrix.api.room.BaseRoom
import io.element.android.libraries.matrix.api.room.MessageEventType
import io.element.android.libraries.matrix.api.room.RoomInfo import io.element.android.libraries.matrix.api.room.RoomInfo
import io.element.android.libraries.matrix.api.room.RoomMember import io.element.android.libraries.matrix.api.room.RoomMember
import io.element.android.libraries.matrix.api.room.RoomMembersState import io.element.android.libraries.matrix.api.room.RoomMembersState
import io.element.android.libraries.matrix.api.room.RoomMembershipObserver import io.element.android.libraries.matrix.api.room.RoomMembershipObserver
import io.element.android.libraries.matrix.api.room.StateEventType
import io.element.android.libraries.matrix.api.room.draft.ComposerDraft import io.element.android.libraries.matrix.api.room.draft.ComposerDraft
import io.element.android.libraries.matrix.api.room.powerlevels.RoomPermissions import io.element.android.libraries.matrix.api.room.powerlevels.RoomPermissions
import io.element.android.libraries.matrix.api.room.powerlevels.RoomPowerLevelsValues import io.element.android.libraries.matrix.api.room.powerlevels.RoomPowerLevelsValues

View File

@@ -15,11 +15,9 @@ import io.element.android.libraries.matrix.api.core.SessionId
import io.element.android.libraries.matrix.api.core.ThreadId import io.element.android.libraries.matrix.api.core.ThreadId
import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.api.room.BaseRoom import io.element.android.libraries.matrix.api.room.BaseRoom
import io.element.android.libraries.matrix.api.room.MessageEventType
import io.element.android.libraries.matrix.api.room.RoomInfo import io.element.android.libraries.matrix.api.room.RoomInfo
import io.element.android.libraries.matrix.api.room.RoomMember import io.element.android.libraries.matrix.api.room.RoomMember
import io.element.android.libraries.matrix.api.room.RoomMembersState import io.element.android.libraries.matrix.api.room.RoomMembersState
import io.element.android.libraries.matrix.api.room.StateEventType
import io.element.android.libraries.matrix.api.room.draft.ComposerDraft import io.element.android.libraries.matrix.api.room.draft.ComposerDraft
import io.element.android.libraries.matrix.api.room.powerlevels.RoomPermissions import io.element.android.libraries.matrix.api.room.powerlevels.RoomPermissions
import io.element.android.libraries.matrix.api.room.powerlevels.RoomPowerLevelsValues import io.element.android.libraries.matrix.api.room.powerlevels.RoomPowerLevelsValues
@@ -42,6 +40,7 @@ class FakeBaseRoom(
override val sessionId: SessionId = A_SESSION_ID, override val sessionId: SessionId = A_SESSION_ID,
override val roomId: RoomId = A_ROOM_ID, override val roomId: RoomId = A_ROOM_ID,
initialRoomInfo: RoomInfo = aRoomInfo(), initialRoomInfo: RoomInfo = aRoomInfo(),
private val roomPermissions: RoomPermissions = FakeRoomPermissions(),
override val roomCoroutineScope: CoroutineScope = TestScope(), override val roomCoroutineScope: CoroutineScope = TestScope(),
private var roomPermalinkResult: () -> Result<String> = { lambdaError() }, private var roomPermalinkResult: () -> Result<String> = { lambdaError() },
private var eventPermalinkResult: (EventId) -> Result<String> = { lambdaError() }, private var eventPermalinkResult: (EventId) -> Result<String> = { lambdaError() },
@@ -50,17 +49,6 @@ class FakeBaseRoom(
private val userRoleResult: () -> Result<RoomMember.Role> = { lambdaError() }, private val userRoleResult: () -> Result<RoomMember.Role> = { lambdaError() },
private val getUpdatedMemberResult: (UserId) -> Result<RoomMember> = { lambdaError() }, private val getUpdatedMemberResult: (UserId) -> Result<RoomMember> = { lambdaError() },
private val joinRoomResult: () -> Result<Unit> = { lambdaError() }, private val joinRoomResult: () -> Result<Unit> = { lambdaError() },
private val roomPermissionsResult: () -> Result<RoomPermissions> = { Result.success(FakeRoomPermissions()) },
private val canInviteResult: (UserId) -> Result<Boolean> = { lambdaError() },
private val canKickResult: (UserId) -> Result<Boolean> = { lambdaError() },
private val canBanResult: (UserId) -> Result<Boolean> = { lambdaError() },
private val canRedactOwnResult: (UserId) -> Result<Boolean> = { lambdaError() },
private val canRedactOtherResult: (UserId) -> Result<Boolean> = { lambdaError() },
private val canSendStateResult: (UserId, StateEventType) -> Result<Boolean> = { _, _ -> lambdaError() },
private val canUserSendMessageResult: (UserId, MessageEventType) -> Result<Boolean> = { _, _ -> lambdaError() },
private val canUserTriggerRoomNotificationResult: (UserId) -> Result<Boolean> = { lambdaError() },
private val canUserJoinCallResult: (UserId) -> Result<Boolean> = { lambdaError() },
private val canUserPinUnpinResult: (UserId) -> Result<Boolean> = { lambdaError() },
private val setIsFavoriteResult: (Boolean) -> Result<Unit> = { lambdaError() }, private val setIsFavoriteResult: (Boolean) -> Result<Unit> = { lambdaError() },
private val markAsReadResult: (ReceiptType) -> Result<Unit> = { Result.success(Unit) }, private val markAsReadResult: (ReceiptType) -> Result<Unit> = { Result.success(Unit) },
private val powerLevelsResult: () -> Result<RoomPowerLevelsValues> = { lambdaError() }, private val powerLevelsResult: () -> Result<RoomPowerLevelsValues> = { lambdaError() },
@@ -133,7 +121,7 @@ class FakeBaseRoom(
} }
override suspend fun roomPermissions(): Result<RoomPermissions> { override suspend fun roomPermissions(): Result<RoomPermissions> {
return roomPermissionsResult() return Result.success(roomPermissions)
} }
override suspend fun getPermalink(): Result<String> { override suspend fun getPermalink(): Result<String> {
@@ -160,46 +148,6 @@ class FakeBaseRoom(
return forgetResult() return forgetResult()
} }
override suspend fun canUserBan(userId: UserId): Result<Boolean> {
return canBanResult(userId)
}
override suspend fun canUserKick(userId: UserId): Result<Boolean> {
return canKickResult(userId)
}
override suspend fun canUserInvite(userId: UserId): Result<Boolean> {
return canInviteResult(userId)
}
override suspend fun canUserRedactOwn(userId: UserId): Result<Boolean> {
return canRedactOwnResult(userId)
}
override suspend fun canUserRedactOther(userId: UserId): Result<Boolean> {
return canRedactOtherResult(userId)
}
override suspend fun canUserSendState(userId: UserId, type: StateEventType): Result<Boolean> {
return canSendStateResult(userId, type)
}
override suspend fun canUserSendMessage(userId: UserId, type: MessageEventType): Result<Boolean> {
return canUserSendMessageResult(userId, type)
}
override suspend fun canUserTriggerRoomNotification(userId: UserId): Result<Boolean> {
return canUserTriggerRoomNotificationResult(userId)
}
override suspend fun canUserJoinCall(userId: UserId): Result<Boolean> {
return canUserJoinCallResult(userId)
}
override suspend fun canUserPinUnpin(userId: UserId): Result<Boolean> {
return canUserPinUnpinResult(userId)
}
override suspend fun setIsFavorite(isFavorite: Boolean): Result<Unit> { override suspend fun setIsFavorite(isFavorite: Boolean): Result<Unit> {
return setIsFavoriteResult(isFavorite) return setIsFavoriteResult(isFavorite)
} }

View File

@@ -13,44 +13,44 @@ import io.element.android.libraries.matrix.api.room.StateEventType
import io.element.android.libraries.matrix.api.room.powerlevels.RoomPermissions import io.element.android.libraries.matrix.api.room.powerlevels.RoomPermissions
data class FakeRoomPermissions( data class FakeRoomPermissions(
val ownerCanBan: Boolean = false, private val canBan: Boolean = false,
val ownerCanInvite: Boolean = false, private val canInvite: Boolean = false,
val ownerCanKick: Boolean = false, private val canKick: Boolean = false,
val ownerCanPinUnpin: Boolean = false, private val canPinUnpin: Boolean = false,
val ownerCanRedactOther: Boolean = false, private val canRedactOther: Boolean = false,
val ownerCanRedactOwn: Boolean = false, private val canRedactOwn: Boolean = false,
val ownerCanTriggerRoomNotification: Boolean = false, private val canTriggerRoomNotification: Boolean = false,
val ownerCanSendMessage: (MessageEventType) -> Boolean = { false }, private val canSendMessage: (MessageEventType) -> Boolean = { false },
val ownerCanSendState: (StateEventType) -> Boolean = { false }, private val canSendState: (StateEventType) -> Boolean = { false },
val userCanBan: (UserId) -> Boolean = { false }, private val canUserBan: (UserId) -> Boolean = { false },
val userCanInvite: (UserId) -> Boolean = { false }, private val canUserInvite: (UserId) -> Boolean = { false },
val userCanKick: (UserId) -> Boolean = { false }, private val canUserKick: (UserId) -> Boolean = { false },
val userCanPinUnpin: (UserId) -> Boolean = { false }, private val canUserPinUnpin: (UserId) -> Boolean = { false },
val userCanRedactOther: (UserId) -> Boolean = { false }, private val canUserRedactOther: (UserId) -> Boolean = { false },
val userCanRedactOwn: (UserId) -> Boolean = { false }, private val canUserRedactOwn: (UserId) -> Boolean = { false },
val userCanTriggerRoomNotification: (UserId) -> Boolean = { false }, private val canUserTriggerRoomNotification: (UserId) -> Boolean = { false },
val userCanSendMessage: (UserId, MessageEventType) -> Boolean = { _, _ -> false }, private val canUserSendMessage: (UserId, MessageEventType) -> Boolean = { _, _ -> false },
val userCanSendState: (UserId, StateEventType) -> Boolean = { _, _ -> false }, private val canUserSendState: (UserId, StateEventType) -> Boolean = { _, _ -> false },
) : RoomPermissions { ) : RoomPermissions {
override fun canOwnUserBan(): Boolean = canBan
override fun canOwnUserInvite(): Boolean = canInvite
override fun canOwnUserKick(): Boolean = canKick
override fun canOwnUserPinUnpin(): Boolean = canPinUnpin
override fun canOwnUserRedactOther(): Boolean = canRedactOther
override fun canOwnUserRedactOwn(): Boolean = canRedactOwn
override fun canOwnUserSendMessage(message: MessageEventType): Boolean = canSendMessage(message)
override fun canOwnUserSendState(stateEvent: StateEventType): Boolean = canSendState(stateEvent)
override fun canOwnUserBan(): Boolean = ownerCanBan override fun canOwnUserTriggerRoomNotification(): Boolean = canTriggerRoomNotification
override fun canOwnUserInvite(): Boolean = ownerCanInvite override fun canUserBan(userId: UserId): Boolean = canUserBan(userId)
override fun canOwnUserKick(): Boolean = ownerCanKick override fun canUserInvite(userId: UserId): Boolean = canUserInvite(userId)
override fun canOwnUserPinUnpin(): Boolean = ownerCanPinUnpin override fun canUserKick(userId: UserId): Boolean = canUserKick(userId)
override fun canOwnUserRedactOther(): Boolean = ownerCanRedactOther override fun canUserPinUnpin(userId: UserId): Boolean = canUserPinUnpin(userId)
override fun canOwnUserRedactOwn(): Boolean = ownerCanRedactOwn override fun canUserRedactOther(userId: UserId): Boolean = canUserRedactOther(userId)
override fun canOwnUserSendMessage(message: MessageEventType): Boolean = ownerCanSendMessage(message) override fun canUserRedactOwn(userId: UserId): Boolean = canUserRedactOwn(userId)
override fun canOwnUserSendState(stateEvent: StateEventType): Boolean = ownerCanSendState(stateEvent) override fun canUserSendMessage(userId: UserId, message: MessageEventType): Boolean = canUserSendMessage(userId, message)
override fun canOwnUserTriggerRoomNotification(): Boolean = ownerCanTriggerRoomNotification override fun canUserSendState(userId: UserId, stateEvent: StateEventType): Boolean = canUserSendState(userId, stateEvent)
override fun canUserBan(userId: UserId): Boolean = userCanBan(userId) override fun canUserTriggerRoomNotification(userId: UserId): Boolean = canUserTriggerRoomNotification(userId)
override fun canUserInvite(userId: UserId): Boolean = userCanInvite(userId)
override fun canUserKick(userId: UserId): Boolean = userCanKick(userId)
override fun canUserPinUnpin(userId: UserId): Boolean = userCanPinUnpin(userId)
override fun canUserRedactOther(userId: UserId): Boolean = userCanRedactOther(userId)
override fun canUserRedactOwn(userId: UserId): Boolean = userCanRedactOwn(userId)
override fun canUserSendMessage(userId: UserId, message: MessageEventType): Boolean = userCanSendMessage(userId, message)
override fun canUserSendState(userId: UserId, stateEvent: StateEventType): Boolean = userCanSendState(userId, stateEvent)
override fun canUserTriggerRoomNotification(userId: UserId): Boolean = userCanTriggerRoomNotification(userId)
override fun close() { override fun close() {
// no-op for the fake // no-op for the fake

View File

@@ -207,7 +207,6 @@ class MediaGalleryPresenter(
CommonStrings.error_unknown CommonStrings.error_unknown
} }
} }
} }
private fun GroupedMediaItems?.find(eventId: EventId?): MediaItem.Event? { private fun GroupedMediaItems?.find(eventId: EventId?): MediaItem.Event? {

View File

@@ -25,6 +25,7 @@ import io.element.android.libraries.matrix.test.media.FakeMatrixMediaLoader
import io.element.android.libraries.matrix.test.room.FakeBaseRoom 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.libraries.matrix.test.room.aRoomInfo import io.element.android.libraries.matrix.test.room.aRoomInfo
import io.element.android.libraries.matrix.test.room.powerlevels.FakeRoomPermissions
import io.element.android.libraries.matrix.test.timeline.FakeTimeline import io.element.android.libraries.matrix.test.timeline.FakeTimeline
import io.element.android.libraries.mediaviewer.impl.datasource.FakeMediaGalleryDataSource import io.element.android.libraries.mediaviewer.impl.datasource.FakeMediaGalleryDataSource
import io.element.android.libraries.mediaviewer.impl.datasource.MediaGalleryDataSource import io.element.android.libraries.mediaviewer.impl.datasource.MediaGalleryDataSource
@@ -109,7 +110,9 @@ class MediaGalleryPresenterTest {
baseRoom = FakeBaseRoom( baseRoom = FakeBaseRoom(
sessionId = A_USER_ID, sessionId = A_USER_ID,
initialRoomInfo = aRoomInfo(name = A_ROOM_NAME), initialRoomInfo = aRoomInfo(name = A_ROOM_NAME),
canRedactOwnResult = { Result.success(canDeleteOwn) } roomPermissions = FakeRoomPermissions(
canRedactOwn = canDeleteOwn
),
), ),
) )
) )
@@ -153,7 +156,9 @@ class MediaGalleryPresenterTest {
baseRoom = FakeBaseRoom( baseRoom = FakeBaseRoom(
sessionId = A_USER_ID, sessionId = A_USER_ID,
initialRoomInfo = aRoomInfo(name = A_ROOM_NAME), initialRoomInfo = aRoomInfo(name = A_ROOM_NAME),
canRedactOtherResult = { Result.success(canDeleteOther) }, roomPermissions = FakeRoomPermissions(
canRedactOther = canDeleteOther
),
), ),
createTimelineResult = { Result.success(FakeTimeline()) } createTimelineResult = { Result.success(FakeTimeline()) }
) )
@@ -355,7 +360,9 @@ class MediaGalleryPresenterTest {
room = FakeJoinedRoom( room = FakeJoinedRoom(
createTimelineResult = { Result.success(FakeTimeline()) }, createTimelineResult = { Result.success(FakeTimeline()) },
baseRoom = FakeBaseRoom( baseRoom = FakeBaseRoom(
canRedactOwnResult = { Result.success(true) }, roomPermissions = FakeRoomPermissions(
canRedactOwn = true
),
), ),
), ),
navigator = navigator, navigator = navigator,
@@ -386,7 +393,9 @@ class MediaGalleryPresenterTest {
room = FakeJoinedRoom( room = FakeJoinedRoom(
createTimelineResult = { Result.success(FakeTimeline()) }, createTimelineResult = { Result.success(FakeTimeline()) },
baseRoom = FakeBaseRoom( baseRoom = FakeBaseRoom(
canRedactOwnResult = { Result.success(true) }, roomPermissions = FakeRoomPermissions(
canRedactOwn = true
),
), ),
), ),
navigator = navigator, navigator = navigator,

View File

@@ -27,6 +27,7 @@ import io.element.android.libraries.matrix.test.media.FakeMatrixMediaLoader
import io.element.android.libraries.matrix.test.media.aMediaSource import io.element.android.libraries.matrix.test.media.aMediaSource
import io.element.android.libraries.matrix.test.room.FakeBaseRoom 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.libraries.matrix.test.room.powerlevels.FakeRoomPermissions
import io.element.android.libraries.matrix.test.timeline.FakeTimeline import io.element.android.libraries.matrix.test.timeline.FakeTimeline
import io.element.android.libraries.mediaviewer.api.MediaViewerEntryPoint import io.element.android.libraries.mediaviewer.api.MediaViewerEntryPoint
import io.element.android.libraries.mediaviewer.api.anApkMediaInfo import io.element.android.libraries.mediaviewer.api.anApkMediaInfo
@@ -83,7 +84,9 @@ class MediaViewerPresenterTest {
localMediaFactory = localMediaFactory, localMediaFactory = localMediaFactory,
room = FakeJoinedRoom( room = FakeJoinedRoom(
baseRoom = FakeBaseRoom( baseRoom = FakeBaseRoom(
canRedactOwnResult = { Result.success(true) }, roomPermissions = FakeRoomPermissions(
canRedactOwn = true
),
) )
) )
) )
@@ -104,7 +107,9 @@ class MediaViewerPresenterTest {
canShowInfo = false, canShowInfo = false,
room = FakeJoinedRoom( room = FakeJoinedRoom(
baseRoom = FakeBaseRoom( baseRoom = FakeBaseRoom(
canRedactOwnResult = { Result.success(true) }, roomPermissions = FakeRoomPermissions(
canRedactOwn = true
),
) )
) )
) )
@@ -125,7 +130,9 @@ class MediaViewerPresenterTest {
eventId = AN_EVENT_ID, eventId = AN_EVENT_ID,
room = FakeJoinedRoom( room = FakeJoinedRoom(
baseRoom = FakeBaseRoom( baseRoom = FakeBaseRoom(
canRedactOwnResult = { Result.success(true) }, roomPermissions = FakeRoomPermissions(
canRedactOwn = true
),
) )
) )
) )
@@ -147,7 +154,9 @@ class MediaViewerPresenterTest {
room = FakeJoinedRoom( room = FakeJoinedRoom(
baseRoom = FakeBaseRoom( baseRoom = FakeBaseRoom(
sessionId = A_SESSION_ID_2, sessionId = A_SESSION_ID_2,
canRedactOtherResult = { Result.success(false) }, roomPermissions = FakeRoomPermissions(
canRedactOther = false
),
) )
) )
) )
@@ -236,7 +245,9 @@ class MediaViewerPresenterTest {
mediaGalleryDataSource = mediaGalleryDataSource, mediaGalleryDataSource = mediaGalleryDataSource,
room = FakeJoinedRoom( room = FakeJoinedRoom(
baseRoom = FakeBaseRoom( baseRoom = FakeBaseRoom(
canRedactOwnResult = { Result.success(true) }, roomPermissions = FakeRoomPermissions(
canRedactOwn = true
),
) )
) )
) )
@@ -460,7 +471,11 @@ class MediaViewerPresenterTest {
localMediaFactory = localMediaFactory, localMediaFactory = localMediaFactory,
room = FakeJoinedRoom( room = FakeJoinedRoom(
liveTimeline = timeline, liveTimeline = timeline,
baseRoom = FakeBaseRoom(canRedactOwnResult = { Result.success(true) }), baseRoom = FakeBaseRoom(
roomPermissions = FakeRoomPermissions(
canRedactOwn = true
),
),
), ),
mediaGalleryDataSource = mediaGalleryDataSource, mediaGalleryDataSource = mediaGalleryDataSource,
mediaViewerNavigator = FakeMediaViewerNavigator( mediaViewerNavigator = FakeMediaViewerNavigator(
@@ -769,7 +784,11 @@ class MediaViewerPresenterTest {
localMediaFactory = localMediaFactory, localMediaFactory = localMediaFactory,
mediaViewerNavigator = navigator, mediaViewerNavigator = navigator,
room = FakeJoinedRoom( room = FakeJoinedRoom(
baseRoom = FakeBaseRoom(canRedactOwnResult = { Result.success(true) }), baseRoom = FakeBaseRoom(
roomPermissions = FakeRoomPermissions(
canRedactOwn = true
),
),
) )
) )
presenter.test { presenter.test {
@@ -794,7 +813,11 @@ class MediaViewerPresenterTest {
localMediaFactory = localMediaFactory, localMediaFactory = localMediaFactory,
mediaViewerNavigator = navigator, mediaViewerNavigator = navigator,
room = FakeJoinedRoom( room = FakeJoinedRoom(
baseRoom = FakeBaseRoom(canRedactOwnResult = { Result.success(true) }), baseRoom = FakeBaseRoom(
roomPermissions = FakeRoomPermissions(
canRedactOwn = true
),
),
), ),
) )
presenter.test { presenter.test {
@@ -821,7 +844,11 @@ class MediaViewerPresenterTest {
localMediaFactory = localMediaFactory, localMediaFactory = localMediaFactory,
mediaViewerNavigator = navigator, mediaViewerNavigator = navigator,
room = FakeJoinedRoom( room = FakeJoinedRoom(
baseRoom = FakeBaseRoom(canRedactOwnResult = { Result.success(true) }), baseRoom = FakeBaseRoom(
roomPermissions = FakeRoomPermissions(
canRedactOwn = true
),
),
), ),
) )
presenter.test { presenter.test {