From 97b749e2b2917b495f3415bfd09cdecf5b45a427 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 21 Aug 2024 17:59:01 +0200 Subject: [PATCH] Add test on MentionSuggestionsProcessor and simplify the class. --- .../mentions/MentionSuggestionsProcessor.kt | 46 ++- .../MentionSuggestionsProcessorTest.kt | 270 ++++++++++++++++++ 2 files changed, 290 insertions(+), 26 deletions(-) create mode 100644 features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/mentions/MentionSuggestionsProcessorTest.kt diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/mentions/MentionSuggestionsProcessor.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/mentions/MentionSuggestionsProcessor.kt index cc82337c9e..50282ce688 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/mentions/MentionSuggestionsProcessor.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/mentions/MentionSuggestionsProcessor.kt @@ -48,35 +48,29 @@ class MentionSuggestionsProcessor @Inject constructor() { currentUserId: UserId, canSendRoomMention: suspend () -> Boolean, ): List { - val members = roomMembersState.roomMembers() - return when { - members.isNullOrEmpty() || suggestion == null -> { + suggestion ?: return emptyList() + return when (suggestion.type) { + SuggestionType.Mention -> { + // Replace suggestions + val members = roomMembersState.roomMembers() + val matchingMembers = getMemberSuggestions( + query = suggestion.text, + roomMembers = members, + currentUserId = currentUserId, + canSendRoomMention = canSendRoomMention() + ) + matchingMembers + } + SuggestionType.Room -> { + roomAliasSuggestions + .filter { it.roomAlias.value.contains(suggestion.text, ignoreCase = true) } + .map { ResolvedSuggestion.Alias(it.roomAlias, it.roomSummary) } + } + SuggestionType.Command, + is SuggestionType.Custom -> { // Clear suggestions emptyList() } - else -> { - when (suggestion.type) { - SuggestionType.Mention -> { - // Replace suggestions - val matchingMembers = getMemberSuggestions( - query = suggestion.text, - roomMembers = members, - currentUserId = currentUserId, - canSendRoomMention = canSendRoomMention() - ) - matchingMembers - } - SuggestionType.Room -> { - roomAliasSuggestions - .filter { it.roomAlias.value.contains(suggestion.text, ignoreCase = true) } - .map { ResolvedSuggestion.Alias(it.roomAlias, it.roomSummary) } - } - else -> { - // Clear suggestions - emptyList() - } - } - } } } diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/mentions/MentionSuggestionsProcessorTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/mentions/MentionSuggestionsProcessorTest.kt new file mode 100644 index 0000000000..78e3c44e25 --- /dev/null +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/mentions/MentionSuggestionsProcessorTest.kt @@ -0,0 +1,270 @@ +/* + * Copyright (c) 2024 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.element.android.features.messages.impl.mentions + +import com.google.common.truth.Truth.assertThat +import io.element.android.features.messages.impl.messagecomposer.RoomAliasSuggestion +import io.element.android.libraries.matrix.api.core.UserId +import io.element.android.libraries.matrix.api.room.MatrixRoomMembersState +import io.element.android.libraries.matrix.api.room.RoomMembershipState +import io.element.android.libraries.matrix.test.A_ROOM_ALIAS +import io.element.android.libraries.matrix.test.A_USER_ID +import io.element.android.libraries.matrix.test.A_USER_ID_2 +import io.element.android.libraries.matrix.test.room.aRoomMember +import io.element.android.libraries.matrix.test.room.aRoomSummary +import io.element.android.libraries.textcomposer.mentions.ResolvedSuggestion +import io.element.android.libraries.textcomposer.model.Suggestion +import io.element.android.libraries.textcomposer.model.SuggestionType +import kotlinx.collections.immutable.persistentListOf +import kotlinx.coroutines.test.runTest +import org.junit.Test + +class MentionSuggestionsProcessorTest { + private fun aMentionSuggestion(text: String) = Suggestion(0, 1, SuggestionType.Mention, text) + private fun aRoomSuggestion(text: String) = Suggestion(0, 1, SuggestionType.Room, text) + private val aCommandSuggestion = Suggestion(0, 1, SuggestionType.Command, "") + private val aCustomSuggestion = Suggestion(0, 1, SuggestionType.Custom("*"), "") + + private val mentionSuggestionsProcessor = MentionSuggestionsProcessor() + + @Test + fun `processing null suggestion will return empty suggestion`() = runTest { + val result = mentionSuggestionsProcessor.process( + suggestion = null, + roomMembersState = MatrixRoomMembersState.Ready(persistentListOf(aRoomMember())), + roomAliasSuggestions = emptyList(), + currentUserId = A_USER_ID, + canSendRoomMention = { true }, + ) + assertThat(result).isEmpty() + } + + @Test + fun `processing Command will return empty suggestion`() = runTest { + val result = mentionSuggestionsProcessor.process( + suggestion = aCommandSuggestion, + roomMembersState = MatrixRoomMembersState.Ready(persistentListOf(aRoomMember())), + roomAliasSuggestions = emptyList(), + currentUserId = A_USER_ID, + canSendRoomMention = { true }, + ) + assertThat(result).isEmpty() + } + + @Test + fun `processing Custom will return empty suggestion`() = runTest { + val result = mentionSuggestionsProcessor.process( + suggestion = aCustomSuggestion, + roomMembersState = MatrixRoomMembersState.Ready(persistentListOf(aRoomMember())), + roomAliasSuggestions = emptyList(), + currentUserId = A_USER_ID, + canSendRoomMention = { true }, + ) + assertThat(result).isEmpty() + } + + @Test + fun `processing Mention suggestion with not loaded members will return empty suggestion`() = runTest { + val result = mentionSuggestionsProcessor.process( + suggestion = aMentionSuggestion(""), + roomMembersState = MatrixRoomMembersState.Unknown, + roomAliasSuggestions = emptyList(), + currentUserId = A_USER_ID, + canSendRoomMention = { true }, + ) + assertThat(result).isEmpty() + } + + @Test + fun `processing Mention suggestion with no members will return empty suggestion`() = runTest { + val result = mentionSuggestionsProcessor.process( + suggestion = aMentionSuggestion(""), + roomMembersState = MatrixRoomMembersState.Ready(persistentListOf()), + roomAliasSuggestions = emptyList(), + currentUserId = A_USER_ID, + canSendRoomMention = { true }, + ) + assertThat(result).isEmpty() + } + + @Test + fun `processing Room suggestion with no aliases will return empty suggestion`() = runTest { + val result = mentionSuggestionsProcessor.process( + suggestion = aRoomSuggestion(""), + roomMembersState = MatrixRoomMembersState.Ready(persistentListOf()), + roomAliasSuggestions = emptyList(), + currentUserId = A_USER_ID, + canSendRoomMention = { true }, + ) + assertThat(result).isEmpty() + } + + @Test + fun `processing Room suggestion with aliases ignoring cases will return a suggestion`() = runTest { + val aRoomSummary = aRoomSummary(canonicalAlias = A_ROOM_ALIAS) + val result = mentionSuggestionsProcessor.process( + suggestion = aRoomSuggestion("ALI"), + roomMembersState = MatrixRoomMembersState.Ready(persistentListOf()), + roomAliasSuggestions = listOf(RoomAliasSuggestion(A_ROOM_ALIAS, aRoomSummary)), + currentUserId = A_USER_ID, + canSendRoomMention = { true }, + ) + assertThat(result).isEqualTo( + listOf( + ResolvedSuggestion.Alias(A_ROOM_ALIAS, aRoomSummary) + ) + ) + } + + @Test + fun `processing Room suggestion with aliases will return a suggestion`() = runTest { + val aRoomSummary = aRoomSummary(canonicalAlias = A_ROOM_ALIAS) + val result = mentionSuggestionsProcessor.process( + suggestion = aRoomSuggestion("ali"), + roomMembersState = MatrixRoomMembersState.Ready(persistentListOf()), + roomAliasSuggestions = listOf(RoomAliasSuggestion(A_ROOM_ALIAS, aRoomSummary)), + currentUserId = A_USER_ID, + canSendRoomMention = { true }, + ) + assertThat(result).isEqualTo( + listOf( + ResolvedSuggestion.Alias(A_ROOM_ALIAS, aRoomSummary) + ) + ) + } + + @Test + fun `processing Room suggestion with aliases not found will return no suggestions`() = runTest { + val aRoomSummary = aRoomSummary(canonicalAlias = A_ROOM_ALIAS) + val result = mentionSuggestionsProcessor.process( + suggestion = aRoomSuggestion("tot"), + roomMembersState = MatrixRoomMembersState.Ready(persistentListOf()), + roomAliasSuggestions = listOf(RoomAliasSuggestion(A_ROOM_ALIAS, aRoomSummary)), + currentUserId = A_USER_ID, + canSendRoomMention = { true }, + ) + assertThat(result).isEmpty() + } + + @Test + fun `processing Mention suggestion with return matching matrix Id`() = runTest { + val aRoomMember = aRoomMember(userId = UserId("@alice:server.org"), displayName = null) + val result = mentionSuggestionsProcessor.process( + suggestion = aMentionSuggestion("ali"), + roomMembersState = MatrixRoomMembersState.Ready(persistentListOf(aRoomMember)), + roomAliasSuggestions = emptyList(), + currentUserId = A_USER_ID_2, + canSendRoomMention = { true }, + ) + assertThat(result).isEqualTo( + listOf( + ResolvedSuggestion.Member(aRoomMember) + ) + ) + } + + @Test + fun `processing Mention suggestion with not return the current user`() = runTest { + val aRoomMember = aRoomMember(userId = UserId("@alice:server.org"), displayName = null) + val result = mentionSuggestionsProcessor.process( + suggestion = aMentionSuggestion("ali"), + roomMembersState = MatrixRoomMembersState.Ready(persistentListOf(aRoomMember)), + roomAliasSuggestions = emptyList(), + currentUserId = UserId("@alice:server.org"), + canSendRoomMention = { true }, + ) + assertThat(result).isEmpty() + } + + @Test + fun `processing Mention suggestion with return empty list if there is no matches`() = runTest { + val aRoomMember = aRoomMember(userId = UserId("@alice:server.org"), displayName = "alice") + val result = mentionSuggestionsProcessor.process( + suggestion = aMentionSuggestion("bo"), + roomMembersState = MatrixRoomMembersState.Ready(persistentListOf(aRoomMember)), + roomAliasSuggestions = emptyList(), + currentUserId = A_USER_ID_2, + canSendRoomMention = { true }, + ) + assertThat(result).isEmpty() + } + + @Test + fun `processing Mention suggestion with not return not joined member`() = runTest { + val aRoomMember = aRoomMember(userId = UserId("@alice:server.org"), membership = RoomMembershipState.INVITE) + val result = mentionSuggestionsProcessor.process( + suggestion = aMentionSuggestion("ali"), + roomMembersState = MatrixRoomMembersState.Ready(persistentListOf(aRoomMember)), + roomAliasSuggestions = emptyList(), + currentUserId = A_USER_ID_2, + canSendRoomMention = { true }, + ) + assertThat(result).isEmpty() + } + + @Test + fun `processing Mention suggestion with return matching display name`() = runTest { + val aRoomMember = aRoomMember(userId = UserId("@alice:server.org"), displayName = "bob") + val result = mentionSuggestionsProcessor.process( + suggestion = aMentionSuggestion("bo"), + roomMembersState = MatrixRoomMembersState.Ready(persistentListOf(aRoomMember)), + roomAliasSuggestions = emptyList(), + currentUserId = A_USER_ID_2, + canSendRoomMention = { true }, + ) + assertThat(result).isEqualTo( + listOf( + ResolvedSuggestion.Member(aRoomMember) + ) + ) + } + + @Test + fun `processing Mention suggestion with return matching display name and room if allowed`() = runTest { + val aRoomMember = aRoomMember(userId = UserId("@alice:server.org"), displayName = "ro") + val result = mentionSuggestionsProcessor.process( + suggestion = aMentionSuggestion("ro"), + roomMembersState = MatrixRoomMembersState.Ready(persistentListOf(aRoomMember)), + roomAliasSuggestions = emptyList(), + currentUserId = A_USER_ID_2, + canSendRoomMention = { true }, + ) + assertThat(result).isEqualTo( + listOf( + ResolvedSuggestion.AtRoom, + ResolvedSuggestion.Member(aRoomMember), + ) + ) + } + + @Test + fun `processing Mention suggestion with return matching display name but not room if not allowed`() = runTest { + val aRoomMember = aRoomMember(userId = UserId("@alice:server.org"), displayName = "ro") + val result = mentionSuggestionsProcessor.process( + suggestion = aMentionSuggestion("ro"), + roomMembersState = MatrixRoomMembersState.Ready(persistentListOf(aRoomMember)), + roomAliasSuggestions = emptyList(), + currentUserId = A_USER_ID_2, + canSendRoomMention = { false }, + ) + assertThat(result).isEqualTo( + listOf( + ResolvedSuggestion.Member(aRoomMember), + ) + ) + } +}