From 27daadd6cad185c59d0b0b4e0d7aa4b2c4d4c115 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 23 Nov 2023 20:16:11 +0100 Subject: [PATCH] Add test for TimelineItemContentMessageFactory --- .../TimelineItemContentMessageFactoryTest.kt | 501 ++++++++++++++++++ 1 file changed, 501 insertions(+) create mode 100644 features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentMessageFactoryTest.kt diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentMessageFactoryTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentMessageFactoryTest.kt new file mode 100644 index 0000000000..e695107e10 --- /dev/null +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentMessageFactoryTest.kt @@ -0,0 +1,501 @@ +/* + * Copyright (c) 2023 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 + * + * http://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.timeline.factories.event + +import com.google.common.truth.Truth.assertThat +import io.element.android.features.location.api.Location +import io.element.android.features.messages.impl.timeline.model.event.TimelineItemAudioContent +import io.element.android.features.messages.impl.timeline.model.event.TimelineItemEmoteContent +import io.element.android.features.messages.impl.timeline.model.event.TimelineItemFileContent +import io.element.android.features.messages.impl.timeline.model.event.TimelineItemImageContent +import io.element.android.features.messages.impl.timeline.model.event.TimelineItemLocationContent +import io.element.android.features.messages.impl.timeline.model.event.TimelineItemNoticeContent +import io.element.android.features.messages.impl.timeline.model.event.TimelineItemTextContent +import io.element.android.features.messages.impl.timeline.model.event.TimelineItemVideoContent +import io.element.android.features.messages.impl.timeline.model.event.TimelineItemVoiceContent +import io.element.android.features.messages.impl.timeline.util.FileExtensionExtractorWithoutValidation +import io.element.android.libraries.androidutils.filesize.FakeFileSizeFormatter +import io.element.android.libraries.core.mimetype.MimeTypes +import io.element.android.libraries.featureflag.api.FeatureFlagService +import io.element.android.libraries.featureflag.api.FeatureFlags +import io.element.android.libraries.featureflag.test.FakeFeatureFlagService +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.ThumbnailInfo +import io.element.android.libraries.matrix.api.media.VideoInfo +import io.element.android.libraries.matrix.api.timeline.item.event.AudioMessageType +import io.element.android.libraries.matrix.api.timeline.item.event.EmoteMessageType +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.InReplyTo +import io.element.android.libraries.matrix.api.timeline.item.event.LocationMessageType +import io.element.android.libraries.matrix.api.timeline.item.event.MessageContent +import io.element.android.libraries.matrix.api.timeline.item.event.MessageType +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.TextMessageType +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.ui.components.A_BLUR_HASH +import kotlinx.collections.immutable.toImmutableList +import kotlinx.coroutines.test.runTest +import org.junit.Test +import java.time.Duration +import java.time.Duration.ofMinutes + +class TimelineItemContentMessageFactoryTest { + + @Test + fun `test create OtherMessageType`() = runTest { + val sut = createTimelineItemContentMessageFactory() + val result = sut.create( + content = createMessageContent(type = OtherMessageType(msgType = "a_type", body = "body")), + senderDisplayName = "Bob", + eventId = AN_EVENT_ID, + ) + val expected = TimelineItemTextContent( + body = "body", + htmlDocument = null, + plainText = "body", + isEdited = false, + ) + assertThat(result).isEqualTo(expected) + } + + @Test + fun `test create LocationMessageType not null`() = runTest { + val sut = createTimelineItemContentMessageFactory() + val result = sut.create( + content = createMessageContent(type = LocationMessageType("body", "geo:1,2", "description")), + senderDisplayName = "Bob", + eventId = AN_EVENT_ID, + ) + val expected = TimelineItemLocationContent( + body = "body", + location = Location(lat = 1.0, lon = 2.0, accuracy = 0.0F), + description = "description", + ) + assertThat(result).isEqualTo(expected) + } + + @Test + fun `test create LocationMessageType null`() = runTest { + val sut = createTimelineItemContentMessageFactory() + val result = sut.create( + content = createMessageContent(type = LocationMessageType("body", "", null)), + senderDisplayName = "Bob", + eventId = AN_EVENT_ID, + ) + val expected = TimelineItemTextContent( + body = "body", + htmlDocument = null, + plainText = "body", + isEdited = false, + ) + assertThat(result).isEqualTo(expected) + } + + @Test + fun `test create TextMessageType`() = runTest { + val sut = createTimelineItemContentMessageFactory() + val result = sut.create( + content = createMessageContent(type = TextMessageType("body", null)), + senderDisplayName = "Bob", + eventId = AN_EVENT_ID, + ) + val expected = TimelineItemTextContent( + body = "body", + htmlDocument = null, + plainText = "body", + isEdited = false, + ) + assertThat(result).isEqualTo(expected) + } + + @Test + fun `test create VideoMessageType`() = runTest { + val sut = createTimelineItemContentMessageFactory() + val result = sut.create( + content = createMessageContent(type = VideoMessageType("body", MediaSource("url"), null)), + senderDisplayName = "Bob", + eventId = AN_EVENT_ID, + ) + val expected = TimelineItemVideoContent( + body = "body", + duration = 0, + videoSource = MediaSource(url = "url", json = null), + thumbnailSource = null, + aspectRatio = null, + blurHash = null, + height = null, + width = null, + mimeType = "application/octet-stream", + formattedFileSize = "0 Bytes", + fileExtension = "", + ) + assertThat(result).isEqualTo(expected) + } + + @Test + fun `test create VideoMessageType with info`() = runTest { + val sut = createTimelineItemContentMessageFactory() + val result = sut.create( + content = createMessageContent( + type = VideoMessageType( + body = "body.mp4", + source = MediaSource("url"), + info = VideoInfo( + duration = ofMinutes(1), + height = 100, + width = 300, + mimetype = MimeTypes.Mp4, + size = 555, + thumbnailInfo = ThumbnailInfo( + height = 10L, + width = 5L, + mimetype = MimeTypes.Jpeg, + size = 111L, + ), + thumbnailSource = MediaSource("url_thumbnail"), + blurhash = A_BLUR_HASH, + ), + ) + ), + senderDisplayName = "Bob", + eventId = AN_EVENT_ID, + ) + val expected = TimelineItemVideoContent( + body = "body.mp4", + duration = 60_000, + videoSource = MediaSource(url = "url", json = null), + thumbnailSource = MediaSource("url_thumbnail"), + aspectRatio = 3f, + blurHash = A_BLUR_HASH, + height = 100, + width = 300, + mimeType = MimeTypes.Mp4, + formattedFileSize = "555 Bytes", + fileExtension = "mp4", + ) + assertThat(result).isEqualTo(expected) + } + + @Test + fun `test create AudioMessageType`() = runTest { + val sut = createTimelineItemContentMessageFactory() + val result = sut.create( + content = createMessageContent(type = AudioMessageType("body", MediaSource("url"), null)), + senderDisplayName = "Bob", + eventId = AN_EVENT_ID, + ) + val expected = TimelineItemAudioContent( + body = "body", + duration = Duration.ZERO, + mediaSource = MediaSource(url = "url", json = null), + mimeType = "application/octet-stream", + formattedFileSize = "0 Bytes", + fileExtension = "", + ) + assertThat(result).isEqualTo(expected) + } + + @Test + fun `test create AudioMessageType with info`() = runTest { + val sut = createTimelineItemContentMessageFactory() + val result = sut.create( + content = createMessageContent( + type = AudioMessageType( + body = "body.mp3", + source = MediaSource("url"), + info = AudioInfo( + duration = ofMinutes(1), + size = 123L, + mimetype = MimeTypes.Mp3, + ) + ) + ), + senderDisplayName = "Bob", + eventId = AN_EVENT_ID, + ) + val expected = TimelineItemAudioContent( + body = "body.mp3", + duration = ofMinutes(1), + mediaSource = MediaSource(url = "url", json = null), + mimeType = MimeTypes.Mp3, + formattedFileSize = "123 Bytes", + fileExtension = "mp3", + ) + assertThat(result).isEqualTo(expected) + } + + @Test + fun `test create VoiceMessageType`() = runTest { + val sut = createTimelineItemContentMessageFactory() + val result = sut.create( + content = createMessageContent(type = VoiceMessageType("body", MediaSource("url"), null, null)), + senderDisplayName = "Bob", + eventId = AN_EVENT_ID, + ) + val expected = TimelineItemVoiceContent( + eventId = AN_EVENT_ID, + body = "body", + duration = Duration.ZERO, + mediaSource = MediaSource(url = "url", json = null), + mimeType = "application/octet-stream", + waveform = emptyList().toImmutableList() + ) + assertThat(result).isEqualTo(expected) + } + + @Test + fun `test create VoiceMessageType with info`() = runTest { + val sut = createTimelineItemContentMessageFactory() + val result = sut.create( + content = createMessageContent( + type = VoiceMessageType( + body = "body.ogg", + source = MediaSource("url"), + info = AudioInfo( + duration = ofMinutes(1), + size = 123L, + mimetype = MimeTypes.Ogg, + ), + details = AudioDetails( + duration = ofMinutes(1), waveform = listOf(1f, 2f) + ), + ) + ), + senderDisplayName = "Bob", + eventId = AN_EVENT_ID, + ) + val expected = TimelineItemVoiceContent( + eventId = AN_EVENT_ID, + body = "body.ogg", + duration = ofMinutes(1), + mediaSource = MediaSource(url = "url", json = null), + mimeType = MimeTypes.Ogg, + waveform = listOf(1f, 2f).toImmutableList() + ) + assertThat(result).isEqualTo(expected) + } + + @Test + fun `test create VoiceMessageType feature disabled`() = runTest { + val sut = createTimelineItemContentMessageFactory( + featureFlagService = FakeFeatureFlagService( + initialState = mapOf( + FeatureFlags.VoiceMessages.key to false, + ) + ) + ) + val result = sut.create( + content = createMessageContent(type = VoiceMessageType("body", MediaSource("url"), null, null)), + senderDisplayName = "Bob", + eventId = AN_EVENT_ID, + ) + val expected = TimelineItemAudioContent( + body = "body", + duration = Duration.ZERO, + mediaSource = MediaSource(url = "url", json = null), + mimeType = "application/octet-stream", + formattedFileSize = "0 Bytes", + fileExtension = "" + ) + assertThat(result).isEqualTo(expected) + } + + @Test + fun `test create ImageMessageType`() = runTest { + val sut = createTimelineItemContentMessageFactory() + val result = sut.create( + content = createMessageContent(type = ImageMessageType("body", MediaSource("url"), null)), + senderDisplayName = "Bob", + eventId = AN_EVENT_ID, + ) + val expected = TimelineItemImageContent( + body = "body", + mediaSource = MediaSource(url = "url", json = null), + thumbnailSource = null, + formattedFileSize = "0 Bytes", + fileExtension = "", + mimeType = "application/octet-stream", + blurhash = null, + width = null, + height = null, + aspectRatio = null + ) + assertThat(result).isEqualTo(expected) + } + + @Test + fun `test create ImageMessageType with info`() = runTest { + val sut = createTimelineItemContentMessageFactory() + val result = sut.create( + content = createMessageContent( + type = ImageMessageType( + body = "body.jpg", + source = MediaSource("url"), + info = ImageInfo( + height = 10L, + width = 5L, + mimetype = MimeTypes.Jpeg, + size = 888L, + thumbnailInfo = ThumbnailInfo( + height = 10L, + width = 5L, + mimetype = MimeTypes.Jpeg, + size = 111L, + ), + thumbnailSource = MediaSource("url_thumbnail"), + blurhash = A_BLUR_HASH, + ) + ) + ), + senderDisplayName = "Bob", + eventId = AN_EVENT_ID, + ) + val expected = TimelineItemImageContent( + body = "body.jpg", + mediaSource = MediaSource(url = "url", json = null), + thumbnailSource = MediaSource("url_thumbnail"), + formattedFileSize = "888 Bytes", + fileExtension = "jpg", + mimeType = MimeTypes.Jpeg, + blurhash = A_BLUR_HASH, + width = 5, + height = 10, + aspectRatio = 0.5f, + ) + assertThat(result).isEqualTo(expected) + } + + @Test + fun `test create FileMessageType`() = runTest { + val sut = createTimelineItemContentMessageFactory() + val result = sut.create( + content = createMessageContent(type = FileMessageType("body", MediaSource("url"), null)), + senderDisplayName = "Bob", + eventId = AN_EVENT_ID, + ) + val expected = TimelineItemFileContent( + body = "body", + fileSource = MediaSource(url = "url", json = null), + thumbnailSource = null, + formattedFileSize = "0 Bytes", + fileExtension = "", + mimeType = "application/octet-stream" + ) + assertThat(result).isEqualTo(expected) + } + + @Test + fun `test create FileMessageType with info`() = runTest { + val sut = createTimelineItemContentMessageFactory() + val result = sut.create( + content = createMessageContent( + type = FileMessageType( + body = "body.pdf", + source = MediaSource("url"), + info = FileInfo( + mimetype = MimeTypes.Pdf, + size = 123L, + thumbnailInfo = ThumbnailInfo( + height = 10L, + width = 5L, + mimetype = MimeTypes.Jpeg, + size = 111L, + ), + thumbnailSource = MediaSource("url_thumbnail"), + ) + ) + ), + senderDisplayName = "Bob", + eventId = AN_EVENT_ID, + ) + val expected = TimelineItemFileContent( + body = "body.pdf", + fileSource = MediaSource(url = "url", json = null), + thumbnailSource = MediaSource("url_thumbnail"), + formattedFileSize = "123 Bytes", + fileExtension = "pdf", + mimeType = MimeTypes.Pdf + ) + assertThat(result).isEqualTo(expected) + } + + @Test + fun `test create NoticeMessageType`() = runTest { + val sut = createTimelineItemContentMessageFactory() + val result = sut.create( + content = createMessageContent(type = NoticeMessageType("body", null)), + senderDisplayName = "Bob", + eventId = AN_EVENT_ID, + ) + val expected = TimelineItemNoticeContent( + body = "body", + htmlDocument = null, + plainText = "body", + isEdited = false, + ) + assertThat(result).isEqualTo(expected) + } + + @Test + fun `test create EmoteMessageType`() = runTest { + val sut = createTimelineItemContentMessageFactory() + val result = sut.create( + content = createMessageContent(type = EmoteMessageType("body", null)), + senderDisplayName = "Bob", + eventId = AN_EVENT_ID, + ) + val expected = TimelineItemEmoteContent( + body = "* Bob body", + htmlDocument = null, + plainText = "* Bob body", + isEdited = false, + ) + assertThat(result).isEqualTo(expected) + } + + private fun createMessageContent( + body: String = "Body", + inReplyTo: InReplyTo? = null, + isEdited: Boolean = false, + isThreaded: Boolean = false, + type: MessageType, + ): MessageContent { + return MessageContent( + body = body, + inReplyTo = inReplyTo, + isEdited = isEdited, + isThreaded = isThreaded, + type = type, + ) + } + + private fun createTimelineItemContentMessageFactory( + featureFlagService: FeatureFlagService = FakeFeatureFlagService() + ) = TimelineItemContentMessageFactory( + fileSizeFormatter = FakeFileSizeFormatter(), + fileExtensionExtractor = FileExtensionExtractorWithoutValidation(), + featureFlagService = featureFlagService, + ) +}