diff --git a/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/DefaultEventItemFactoryTest.kt b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/DefaultEventItemFactoryTest.kt new file mode 100644 index 0000000000..0fe977ff8a --- /dev/null +++ b/libraries/mediaviewer/impl/src/test/kotlin/io/element/android/libraries/mediaviewer/impl/gallery/DefaultEventItemFactoryTest.kt @@ -0,0 +1,410 @@ +/* + * Copyright 2024 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only + * Please see LICENSE in the repository root for full details. + */ + +package io.element.android.libraries.mediaviewer.impl.gallery + +import com.google.common.truth.Truth.assertThat +import io.element.android.libraries.androidutils.filesize.FakeFileSizeFormatter +import io.element.android.libraries.core.mimetype.MimeTypes +import io.element.android.libraries.matrix.api.media.AudioDetails +import io.element.android.libraries.matrix.api.media.AudioInfo +import io.element.android.libraries.matrix.api.media.FileInfo +import io.element.android.libraries.matrix.api.media.ImageInfo +import io.element.android.libraries.matrix.api.media.MediaSource +import io.element.android.libraries.matrix.api.media.VideoInfo +import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem +import io.element.android.libraries.matrix.api.timeline.item.event.AudioMessageType +import io.element.android.libraries.matrix.api.timeline.item.event.CallNotifyContent +import io.element.android.libraries.matrix.api.timeline.item.event.EmoteMessageType +import io.element.android.libraries.matrix.api.timeline.item.event.FailedToParseMessageLikeContent +import io.element.android.libraries.matrix.api.timeline.item.event.FailedToParseStateContent +import io.element.android.libraries.matrix.api.timeline.item.event.FileMessageType +import io.element.android.libraries.matrix.api.timeline.item.event.ImageMessageType +import io.element.android.libraries.matrix.api.timeline.item.event.LegacyCallInviteContent +import io.element.android.libraries.matrix.api.timeline.item.event.LocationMessageType +import io.element.android.libraries.matrix.api.timeline.item.event.NoticeMessageType +import io.element.android.libraries.matrix.api.timeline.item.event.OtherMessageType +import io.element.android.libraries.matrix.api.timeline.item.event.OtherState +import io.element.android.libraries.matrix.api.timeline.item.event.RedactedContent +import io.element.android.libraries.matrix.api.timeline.item.event.RoomMembershipContent +import io.element.android.libraries.matrix.api.timeline.item.event.StateContent +import io.element.android.libraries.matrix.api.timeline.item.event.StickerMessageType +import io.element.android.libraries.matrix.api.timeline.item.event.TextMessageType +import io.element.android.libraries.matrix.api.timeline.item.event.UnableToDecryptContent +import io.element.android.libraries.matrix.api.timeline.item.event.UnknownContent +import io.element.android.libraries.matrix.api.timeline.item.event.VideoMessageType +import io.element.android.libraries.matrix.api.timeline.item.event.VoiceMessageType +import io.element.android.libraries.matrix.test.AN_EVENT_ID +import io.element.android.libraries.matrix.test.A_UNIQUE_ID +import io.element.android.libraries.matrix.test.A_USER_ID +import io.element.android.libraries.matrix.test.timeline.aMessageContent +import io.element.android.libraries.matrix.test.timeline.aPollContent +import io.element.android.libraries.matrix.test.timeline.aProfileChangeMessageContent +import io.element.android.libraries.matrix.test.timeline.aStickerContent +import io.element.android.libraries.matrix.test.timeline.anEventTimelineItem +import io.element.android.libraries.mediaviewer.api.MediaInfo +import io.element.android.libraries.mediaviewer.test.util.FileExtensionExtractorWithoutValidation +import kotlinx.collections.immutable.persistentListOf +import org.junit.Test +import kotlin.time.Duration.Companion.seconds + +class DefaultEventItemFactoryTest { + @Test + fun `create check all null cases`() { + val factory = createDefaultEventItemFactory() + val contents = listOf( + CallNotifyContent, + FailedToParseMessageLikeContent("", ""), + FailedToParseStateContent("", "", ""), + LegacyCallInviteContent, + aPollContent(), + aProfileChangeMessageContent(), + RedactedContent, + RoomMembershipContent( + userId = A_USER_ID, + userDisplayName = null, + change = null, + ), + StateContent("", OtherState.RoomCreate), + aStickerContent( + info = ImageInfo( + width = null, + height = null, + mimetype = null, + size = null, + thumbnailInfo = null, + thumbnailSource = null, + blurhash = null, + ), + mediaSource = MediaSource("") + ), + UnableToDecryptContent(UnableToDecryptContent.Data.Unknown), + UnknownContent, + ) + contents.forEach { + val result = factory.create( + MatrixTimelineItem.Event( + uniqueId = A_UNIQUE_ID, + event = anEventTimelineItem( + content = it + ) + ) + ) + assertThat(result).isNull() + } + } + + @Test + fun `create MessageContent check all null cases`() { + val factory = createDefaultEventItemFactory() + val messageTypes = listOf( + EmoteMessageType("", null), + NoticeMessageType("", null), + OtherMessageType("", ""), + LocationMessageType("", "", null), + TextMessageType("", null) + ) + messageTypes.forEach { + val result = factory.create( + MatrixTimelineItem.Event( + uniqueId = A_UNIQUE_ID, + event = anEventTimelineItem( + content = aMessageContent( + messageType = it + ) + ) + ) + ) + assertThat(result).isNull() + } + } + + @Test + fun `create for FileMessageType`() { + val factory = createDefaultEventItemFactory() + val result = factory.create( + MatrixTimelineItem.Event( + uniqueId = A_UNIQUE_ID, + event = anEventTimelineItem( + content = aMessageContent( + messageType = FileMessageType( + filename = "filename.apk", + caption = "caption", + formattedCaption = null, + source = MediaSource(""), + info = FileInfo( + mimetype = MimeTypes.Apk, + size = 123L, + thumbnailInfo = null, + thumbnailSource = null, + ) + ) + ) + ) + ) + ) + assertThat(result).isEqualTo( + MediaItem.File( + id = A_UNIQUE_ID, + eventId = AN_EVENT_ID, + mediaInfo = MediaInfo( + mimeType = MimeTypes.Apk, + filename = "filename.apk", + caption = "caption", + formattedFileSize = "123 Bytes", + fileExtension = "apk", + senderId = A_USER_ID, + senderName = "alice", + senderAvatar = null, + dateSent = "1 Jan 1970", + ), + mediaSource = MediaSource(""), + ) + ) + } + + @Test + fun `create for ImageMessageType`() { + val factory = createDefaultEventItemFactory() + val result = factory.create( + MatrixTimelineItem.Event( + uniqueId = A_UNIQUE_ID, + event = anEventTimelineItem( + content = aMessageContent( + messageType = ImageMessageType( + filename = "filename.jpg", + caption = "caption", + formattedCaption = null, + source = MediaSource(""), + info = ImageInfo( + mimetype = MimeTypes.Jpeg, + size = 123L, + thumbnailInfo = null, + thumbnailSource = null, + height = 1L, + width = 2L, + blurhash = null, + ) + ) + ) + ) + ) + ) + assertThat(result).isEqualTo( + MediaItem.Image( + id = A_UNIQUE_ID, + eventId = AN_EVENT_ID, + mediaInfo = MediaInfo( + mimeType = MimeTypes.Jpeg, + filename = "filename.jpg", + caption = "caption", + formattedFileSize = "123 Bytes", + fileExtension = "jpg", + senderId = A_USER_ID, + senderName = "alice", + senderAvatar = null, + dateSent = "1 Jan 1970", + ), + mediaSource = MediaSource(""), + thumbnailSource = null, + ) + ) + } + + @Test + fun `create for AudioMessageType`() { + val factory = createDefaultEventItemFactory() + val result = factory.create( + MatrixTimelineItem.Event( + uniqueId = A_UNIQUE_ID, + event = anEventTimelineItem( + content = aMessageContent( + messageType = AudioMessageType( + filename = "filename.mp3", + caption = "caption", + formattedCaption = null, + source = MediaSource(""), + info = AudioInfo( + mimetype = MimeTypes.Mp3, + size = 123L, + duration = 456.seconds, + ) + ) + ) + ) + ) + ) + assertThat(result).isEqualTo( + MediaItem.File( + id = A_UNIQUE_ID, + eventId = AN_EVENT_ID, + mediaInfo = MediaInfo( + mimeType = MimeTypes.Mp3, + filename = "filename.mp3", + caption = "caption", + formattedFileSize = "123 Bytes", + fileExtension = "mp3", + senderId = A_USER_ID, + senderName = "alice", + senderAvatar = null, + dateSent = "1 Jan 1970", + ), + mediaSource = MediaSource(""), + ) + ) + } + + @Test + fun `create for VideoMessageType`() { + val factory = createDefaultEventItemFactory() + val result = factory.create( + MatrixTimelineItem.Event( + uniqueId = A_UNIQUE_ID, + event = anEventTimelineItem( + content = aMessageContent( + messageType = VideoMessageType( + filename = "filename.mp4", + caption = "caption", + formattedCaption = null, + source = MediaSource(""), + info = VideoInfo( + mimetype = MimeTypes.Mp4, + size = 123L, + thumbnailInfo = null, + duration = 123.seconds, + height = 1L, + width = 2L, + thumbnailSource = null, + blurhash = null + ) + ) + ) + ) + ) + ) + assertThat(result).isEqualTo( + MediaItem.Video( + id = A_UNIQUE_ID, + eventId = AN_EVENT_ID, + mediaInfo = MediaInfo( + mimeType = MimeTypes.Mp4, + filename = "filename.mp4", + caption = "caption", + formattedFileSize = "123 Bytes", + fileExtension = "mp4", + senderId = A_USER_ID, + senderName = "alice", + senderAvatar = null, + dateSent = "1 Jan 1970", + ), + mediaSource = MediaSource(""), + thumbnailSource = null, + duration = "2:03", + ) + ) + } + + @Test + fun `create for VoiceMessageType`() { + val factory = createDefaultEventItemFactory() + val result = factory.create( + MatrixTimelineItem.Event( + uniqueId = A_UNIQUE_ID, + event = anEventTimelineItem( + content = aMessageContent( + messageType = VoiceMessageType( + filename = "filename.ogg", + caption = "caption", + formattedCaption = null, + source = MediaSource(""), + info = AudioInfo( + mimetype = MimeTypes.Ogg, + size = 123L, + duration = 456.seconds, + ), + details = AudioDetails( + duration = 456.seconds, + waveform = persistentListOf(), + ) + ) + ) + ) + ) + ) + assertThat(result).isEqualTo( + MediaItem.File( + id = A_UNIQUE_ID, + eventId = AN_EVENT_ID, + mediaInfo = MediaInfo( + mimeType = MimeTypes.Ogg, + filename = "filename.ogg", + caption = "caption", + formattedFileSize = "123 Bytes", + fileExtension = "ogg", + senderId = A_USER_ID, + senderName = "alice", + senderAvatar = null, + dateSent = "1 Jan 1970", + ), + mediaSource = MediaSource(""), + ) + ) + } + + @Test + fun `create for StickerMessageType`() { + val factory = createDefaultEventItemFactory() + val result = factory.create( + MatrixTimelineItem.Event( + uniqueId = A_UNIQUE_ID, + event = anEventTimelineItem( + content = aMessageContent( + messageType = StickerMessageType( + filename = "filename.gif", + caption = "caption", + formattedCaption = null, + source = MediaSource(""), + info = ImageInfo( + mimetype = MimeTypes.Gif, + size = 123L, + thumbnailInfo = null, + thumbnailSource = null, + height = 1L, + width = 2L, + blurhash = null, + ) + ) + ) + ) + ) + ) + assertThat(result).isEqualTo( + MediaItem.Image( + id = A_UNIQUE_ID, + eventId = AN_EVENT_ID, + mediaInfo = MediaInfo( + mimeType = MimeTypes.Gif, + filename = "filename.gif", + caption = "caption", + formattedFileSize = "123 Bytes", + fileExtension = "gif", + senderId = A_USER_ID, + senderName = "alice", + senderAvatar = null, + dateSent = "1 Jan 1970", + ), + mediaSource = MediaSource(""), + thumbnailSource = null, + ) + ) + } +} + +private fun createDefaultEventItemFactory() = DefaultEventItemFactory( + fileSizeFormatter = FakeFileSizeFormatter(), + fileExtensionExtractor = FileExtensionExtractorWithoutValidation(), +)