diff --git a/changelog.d/7530.sdk b/changelog.d/7530.sdk
new file mode 100644
index 0000000000..4cea35f44b
--- /dev/null
+++ b/changelog.d/7530.sdk
@@ -0,0 +1 @@
+Fix a bug that caused messages with no formatted text to be quoted as "null".
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/LocalEchoEventFactory.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/LocalEchoEventFactory.kt
index 7d8605c2bd..55ba78c2a5 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/LocalEchoEventFactory.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/LocalEchoEventFactory.kt
@@ -804,20 +804,12 @@ internal class LocalEchoEventFactory @Inject constructor(
additionalContent: Content? = null,
): Event {
val messageContent = quotedEvent.getLastMessageContent()
- val textMsg = if (messageContent is MessageContentWithFormattedBody) {
- messageContent.formattedBody
- } else {
- messageContent?.body
- }
- val quoteText = legacyRiotQuoteText(textMsg, text)
- val quoteFormattedText = "
$textMsg
$formattedText"
-
+ val formattedQuotedText = (messageContent as? MessageContentWithFormattedBody)?.formattedBody
+ val textContent = createQuoteTextContent(messageContent?.body, formattedQuotedText, text, formattedText, autoMarkdown)
return if (rootThreadEventId != null) {
createMessageEvent(
roomId,
- markdownParser
- .parse(quoteText, force = true, advanced = autoMarkdown).copy(formattedText = quoteFormattedText)
- .toThreadTextContent(
+ textContent.toThreadTextContent(
rootThreadEventId = rootThreadEventId,
latestThreadEventId = localEchoRepository.getLatestThreadEvent(rootThreadEventId),
msgType = MessageType.MSGTYPE_TEXT
@@ -827,31 +819,54 @@ internal class LocalEchoEventFactory @Inject constructor(
} else {
createFormattedTextEvent(
roomId,
- markdownParser.parse(quoteText, force = true, advanced = autoMarkdown).copy(formattedText = quoteFormattedText),
+ textContent,
MessageType.MSGTYPE_TEXT,
additionalContent,
)
}
}
- private fun legacyRiotQuoteText(quotedText: String?, myText: String): String {
- val messageParagraphs = quotedText?.split("\n\n".toRegex())?.dropLastWhile { it.isEmpty() }?.toTypedArray()
- return buildString {
- if (messageParagraphs != null) {
- for (i in messageParagraphs.indices) {
- if (messageParagraphs[i].isNotBlank()) {
- append("> ")
- append(messageParagraphs[i])
- }
+ private fun createQuoteTextContent(
+ quotedText: String?,
+ formattedQuotedText: String?,
+ text: String,
+ formattedText: String?,
+ autoMarkdown: Boolean
+ ): TextContent {
+ val currentFormattedText = formattedText ?: if (autoMarkdown) {
+ val parsed = markdownParser.parse(text, force = true, advanced = true)
+ // If formattedText == text, formattedText is returned as null
+ parsed.formattedText ?: parsed.text
+ } else {
+ text
+ }
+ val processedFormattedQuotedText = formattedQuotedText ?: quotedText
- if (i != messageParagraphs.lastIndex) {
- append("\n\n")
- }
+ val plainTextBody = buildString {
+ val plainMessageParagraphs = quotedText?.split("\n\n".toRegex())?.dropLastWhile { it.isEmpty() }?.toTypedArray().orEmpty()
+ plainMessageParagraphs.forEachIndexed { index, paragraph ->
+ if (paragraph.isNotBlank()) {
+ append("> ")
+ append(paragraph)
+ }
+
+ if (index != plainMessageParagraphs.lastIndex) {
+ append("\n\n")
}
}
append("\n\n")
- append(myText)
+ append(text)
}
+ val formattedTextBody = buildString {
+ if (!processedFormattedQuotedText.isNullOrBlank()) {
+ append("")
+ append(processedFormattedQuotedText)
+ append("
")
+ }
+ append("
")
+ append(currentFormattedText)
+ }
+ return TextContent(plainTextBody, formattedTextBody)
}
companion object {
diff --git a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/session/room/send/LocalEchoEventFactoryTests.kt b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/session/room/send/LocalEchoEventFactoryTests.kt
new file mode 100644
index 0000000000..b30428e5e1
--- /dev/null
+++ b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/session/room/send/LocalEchoEventFactoryTests.kt
@@ -0,0 +1,241 @@
+/*
+ * Copyright (c) 2022 The Matrix.org Foundation C.I.C.
+ *
+ * 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 org.matrix.android.sdk.internal.session.room.send
+
+import org.amshove.kluent.internal.assertEquals
+import org.junit.Before
+import org.junit.Test
+import org.matrix.android.sdk.api.session.events.model.Event
+import org.matrix.android.sdk.api.session.events.model.EventType
+import org.matrix.android.sdk.api.session.events.model.toContent
+import org.matrix.android.sdk.api.session.events.model.toModel
+import org.matrix.android.sdk.api.session.room.model.EditAggregatedSummary
+import org.matrix.android.sdk.api.session.room.model.EventAnnotationsSummary
+import org.matrix.android.sdk.api.session.room.model.message.MessageContent
+import org.matrix.android.sdk.api.session.room.model.message.MessageContentWithFormattedBody
+import org.matrix.android.sdk.api.session.room.sender.SenderInfo
+import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
+import org.matrix.android.sdk.api.util.TextContent
+import org.matrix.android.sdk.test.fakes.FakeClock
+import org.matrix.android.sdk.test.fakes.FakeContext
+import org.matrix.android.sdk.test.fakes.internal.session.content.FakeThumbnailExtractor
+import org.matrix.android.sdk.test.fakes.internal.session.permalinks.FakePermalinkFactory
+import org.matrix.android.sdk.test.fakes.internal.session.room.send.FakeLocalEchoRepository
+import org.matrix.android.sdk.test.fakes.internal.session.room.send.FakeMarkdownParser
+import org.matrix.android.sdk.test.fakes.internal.session.room.send.FakeWaveFormSanitizer
+import org.matrix.android.sdk.test.fakes.internal.session.room.send.pills.FakeTextPillsUtils
+
+@Suppress("MaxLineLength")
+class LocalEchoEventFactoryTests {
+
+ companion object {
+ internal const val A_USER_ID_1 = "@user_1:matrix.org"
+ internal const val A_ROOM_ID = "!sUeOGZKsBValPTUMax:matrix.org"
+ internal const val AN_EVENT_ID = "\$vApgexcL8Vfh-WxYKsFKCDooo67ttbjm3TiVKXaWijU"
+ internal const val AN_EPOCH = 1655210176L
+
+ val A_START_EVENT = Event(
+ type = EventType.STATE_ROOM_CREATE,
+ eventId = AN_EVENT_ID,
+ originServerTs = 1652435922563,
+ senderId = A_USER_ID_1,
+ roomId = A_ROOM_ID
+ )
+ }
+
+ private val fakeContext = FakeContext()
+ private val fakeMarkdownParser = FakeMarkdownParser()
+ private val fakeTextPillsUtils = FakeTextPillsUtils()
+ private val fakeThumbnailExtractor = FakeThumbnailExtractor()
+ private val fakeWaveFormSanitizer = FakeWaveFormSanitizer()
+ private val fakeLocalEchoRepository = FakeLocalEchoRepository()
+ private val fakePermalinkFactory = FakePermalinkFactory()
+ private val fakeClock = FakeClock()
+
+ private val localEchoEventFactory = LocalEchoEventFactory(
+ context = fakeContext.instance,
+ userId = A_USER_ID_1,
+ markdownParser = fakeMarkdownParser.instance,
+ textPillsUtils = fakeTextPillsUtils.instance,
+ thumbnailExtractor = fakeThumbnailExtractor.instance,
+ waveformSanitizer = fakeWaveFormSanitizer.instance,
+ localEchoRepository = fakeLocalEchoRepository.instance,
+ permalinkFactory = fakePermalinkFactory.instance,
+ clock = fakeClock
+ )
+
+ @Before
+ fun setup() {
+ fakeClock.givenEpoch(AN_EPOCH)
+ fakeMarkdownParser.givenBoldMarkdown()
+ }
+
+ @Test
+ fun `given a null quotedText, when a quote event is created, then the result message should only contain the new text after new lines`() {
+ val event = createTimelineEvent(null, null)
+ val quotedContent = localEchoEventFactory.createQuotedTextEvent(
+ roomId = A_ROOM_ID,
+ quotedEvent = event,
+ text = "Text",
+ formattedText = null,
+ autoMarkdown = false,
+ rootThreadEventId = null,
+ additionalContent = null,
+ ).content.toModel()
+ assertEquals("\n\nText", quotedContent?.body)
+ assertEquals("
Text", (quotedContent as? MessageContentWithFormattedBody)?.formattedBody)
+ }
+
+ @Test
+ fun `given a plain text quoted message, when a quote event is created, then the result message should contain both the quoted and new text`() {
+ val event = createTimelineEvent("Quoted", null)
+ val quotedContent = localEchoEventFactory.createQuotedTextEvent(
+ roomId = A_ROOM_ID,
+ quotedEvent = event,
+ text = "Text",
+ formattedText = null,
+ autoMarkdown = false,
+ rootThreadEventId = null,
+ additionalContent = null,
+ ).content.toModel()
+ assertEquals("> Quoted\n\nText", quotedContent?.body)
+ assertEquals("Quoted
Text", (quotedContent as? MessageContentWithFormattedBody)?.formattedBody)
+ }
+
+ @Test
+ fun `given a formatted text quoted message, when a quote event is created, then the result message should contain both the formatted quote and new text`() {
+ val event = createTimelineEvent("Quoted", "Quoted")
+ val quotedContent = localEchoEventFactory.createQuotedTextEvent(
+ roomId = A_ROOM_ID,
+ quotedEvent = event,
+ text = "Text",
+ formattedText = null,
+ autoMarkdown = false,
+ rootThreadEventId = null,
+ additionalContent = null,
+ ).content.toModel()
+ // This still uses the plain text version
+ assertEquals("> Quoted\n\nText", quotedContent?.body)
+ // This one has the formatted one
+ assertEquals("Quoted
Text", (quotedContent as? MessageContentWithFormattedBody)?.formattedBody)
+ }
+
+ @Test
+ fun `given formatted text quoted message and new message, when a quote event is created, then the result message should contain both the formatted quote and new formatted text`() {
+ val event = createTimelineEvent("Quoted", "Quoted")
+ val quotedContent = localEchoEventFactory.createQuotedTextEvent(
+ roomId = A_ROOM_ID,
+ quotedEvent = event,
+ text = "Text",
+ formattedText = "Formatted text",
+ autoMarkdown = false,
+ rootThreadEventId = null,
+ additionalContent = null,
+ ).content.toModel()
+ // This still uses the plain text version
+ assertEquals("> Quoted\n\nText", quotedContent?.body)
+ // This one has the formatted one
+ assertEquals(
+ "Quoted
Formatted text",
+ (quotedContent as? MessageContentWithFormattedBody)?.formattedBody
+ )
+ }
+
+ @Test
+ fun `given formatted text quoted message and new message with autoMarkdown, when a quote event is created, then the result message should contain both the formatted quote and new formatted text, not the markdown processed text`() {
+ val event = createTimelineEvent("Quoted", "Quoted")
+ val quotedContent = localEchoEventFactory.createQuotedTextEvent(
+ roomId = A_ROOM_ID,
+ quotedEvent = event,
+ text = "Text",
+ formattedText = "Formatted text",
+ autoMarkdown = true,
+ rootThreadEventId = null,
+ additionalContent = null,
+ ).content.toModel()
+ // This still uses the plain text version
+ assertEquals("> Quoted\n\nText", quotedContent?.body)
+ // This one has the formatted one
+ assertEquals(
+ "Quoted
Formatted text",
+ (quotedContent as? MessageContentWithFormattedBody)?.formattedBody
+ )
+ }
+
+ @Test
+ fun `given a formatted text quoted message and a new message with autoMarkdown, when a quote event is created, then the result message should contain both the formatted quote and new processed formatted text`() {
+ val event = createTimelineEvent("Quoted", "Quoted")
+ val quotedContent = localEchoEventFactory.createQuotedTextEvent(
+ roomId = A_ROOM_ID,
+ quotedEvent = event,
+ text = "**Text**",
+ formattedText = null,
+ autoMarkdown = true,
+ rootThreadEventId = null,
+ additionalContent = null,
+ ).content.toModel()
+ // This still uses the markdown text version
+ assertEquals("> Quoted\n\n**Text**", quotedContent?.body)
+ // This one has the formatted one
+ assertEquals(
+ "Quoted
Text",
+ (quotedContent as? MessageContentWithFormattedBody)?.formattedBody
+ )
+ }
+
+ @Test
+ fun `given a plain text quoted message and a new message with autoMarkdown, when a quote event is created, then the result message should the plain text quote and new processed formatted text`() {
+ val event = createTimelineEvent("Quoted", null)
+ val quotedContent = localEchoEventFactory.createQuotedTextEvent(
+ roomId = A_ROOM_ID,
+ quotedEvent = event,
+ text = "**Text**",
+ formattedText = null,
+ autoMarkdown = true,
+ rootThreadEventId = null,
+ additionalContent = null,
+ ).content.toModel()
+ // This still uses the markdown text version
+ assertEquals("> Quoted\n\n**Text**", quotedContent?.body)
+ // This one has the formatted one
+ assertEquals(
+ "Quoted
Text",
+ (quotedContent as? MessageContentWithFormattedBody)?.formattedBody
+ )
+ }
+
+ private fun createTimelineEvent(quotedText: String?, formattedQuotedText: String?): TimelineEvent {
+ val textContent = quotedText?.let {
+ TextContent(
+ quotedText,
+ formattedQuotedText
+ ).toMessageTextContent().toContent()
+ }
+ return TimelineEvent(
+ root = A_START_EVENT,
+ localId = 1234,
+ eventId = AN_EVENT_ID,
+ displayIndex = 0,
+ senderInfo = SenderInfo(A_USER_ID_1, A_USER_ID_1, true, null),
+ annotations = if (textContent != null) {
+ EventAnnotationsSummary(
+ editSummary = EditAggregatedSummary(latestContent = textContent, emptyList(), emptyList())
+ )
+ } else null
+ )
+ }
+}
diff --git a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/FakeClipboardManager.kt b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/FakeClipboardManager.kt
new file mode 100644
index 0000000000..bce8b41aa9
--- /dev/null
+++ b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/FakeClipboardManager.kt
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2022 The Matrix.org Foundation C.I.C.
+ *
+ * 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 org.matrix.android.sdk.test.fakes
+
+import android.content.ClipData
+import android.content.ClipboardManager
+import io.mockk.every
+import io.mockk.just
+import io.mockk.mockk
+import io.mockk.runs
+import io.mockk.verify
+
+class FakeClipboardManager {
+ val instance = mockk()
+
+ fun givenSetPrimaryClip() {
+ every { instance.setPrimaryClip(any()) } just runs
+ }
+
+ fun verifySetPrimaryClip(clipData: ClipData) {
+ verify { instance.setPrimaryClip(clipData) }
+ }
+}
diff --git a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/FakeConnectivityManager.kt b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/FakeConnectivityManager.kt
new file mode 100644
index 0000000000..5c3a245c51
--- /dev/null
+++ b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/FakeConnectivityManager.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2022 The Matrix.org Foundation C.I.C
+ *
+ * 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 org.matrix.android.sdk.test.fakes
+
+import android.net.ConnectivityManager
+import android.net.Network
+import android.net.NetworkCapabilities
+import io.mockk.every
+import io.mockk.mockk
+
+class FakeConnectivityManager {
+ val instance = mockk()
+
+ fun givenNoActiveConnection() {
+ every { instance.activeNetwork } returns null
+ }
+
+ fun givenHasActiveConnection() {
+ val network = mockk()
+ every { instance.activeNetwork } returns network
+
+ val networkCapabilities = FakeNetworkCapabilities()
+ networkCapabilities.givenTransports(
+ NetworkCapabilities.TRANSPORT_CELLULAR,
+ NetworkCapabilities.TRANSPORT_WIFI,
+ NetworkCapabilities.TRANSPORT_VPN
+ )
+ every { instance.getNetworkCapabilities(network) } returns networkCapabilities.instance
+ }
+}
diff --git a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/FakeContext.kt b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/FakeContext.kt
new file mode 100644
index 0000000000..966c6a1bb2
--- /dev/null
+++ b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/FakeContext.kt
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2022 The Matrix.org Foundation C.I.C.
+ *
+ * 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 org.matrix.android.sdk.test.fakes
+
+import android.content.ClipboardManager
+import android.content.ContentResolver
+import android.content.Context
+import android.content.Intent
+import android.net.ConnectivityManager
+import android.net.Uri
+import android.os.ParcelFileDescriptor
+import io.mockk.every
+import io.mockk.just
+import io.mockk.mockk
+import io.mockk.runs
+import java.io.OutputStream
+
+class FakeContext(
+ private val contentResolver: ContentResolver = mockk()
+) {
+
+ val instance = mockk()
+
+ init {
+ every { instance.contentResolver } returns contentResolver
+ every { instance.applicationContext } returns instance
+ }
+
+ fun givenFileDescriptor(uri: Uri, mode: String, factory: () -> ParcelFileDescriptor?) {
+ val fileDescriptor = factory()
+ every { contentResolver.openFileDescriptor(uri, mode, null) } returns fileDescriptor
+ }
+
+ fun givenSafeOutputStreamFor(uri: Uri): OutputStream {
+ val outputStream = mockk(relaxed = true)
+ every { contentResolver.openOutputStream(uri, "wt") } returns outputStream
+ return outputStream
+ }
+
+ fun givenMissingSafeOutputStreamFor(uri: Uri) {
+ every { contentResolver.openOutputStream(uri, "wt") } returns null
+ }
+
+ fun givenNoConnection() {
+ val connectivityManager = FakeConnectivityManager()
+ connectivityManager.givenNoActiveConnection()
+ givenService(Context.CONNECTIVITY_SERVICE, ConnectivityManager::class.java, connectivityManager.instance)
+ }
+
+ fun givenService(name: String, klass: Class, service: T) {
+ every { instance.getSystemService(name) } returns service
+ every { instance.getSystemService(klass) } returns service
+ }
+
+ fun givenHasConnection() {
+ val connectivityManager = FakeConnectivityManager()
+ connectivityManager.givenHasActiveConnection()
+ givenService(Context.CONNECTIVITY_SERVICE, ConnectivityManager::class.java, connectivityManager.instance)
+ }
+
+ fun givenStartActivity(intent: Intent) {
+ every { instance.startActivity(intent) } just runs
+ }
+
+ fun givenClipboardManager(): FakeClipboardManager {
+ val fakeClipboardManager = FakeClipboardManager()
+ givenService(Context.CLIPBOARD_SERVICE, ClipboardManager::class.java, fakeClipboardManager.instance)
+ return fakeClipboardManager
+ }
+}
diff --git a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/FakeNetworkCapabilities.kt b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/FakeNetworkCapabilities.kt
new file mode 100644
index 0000000000..c630b94d47
--- /dev/null
+++ b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/FakeNetworkCapabilities.kt
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2022 The Matrix.org Foundation C.I.C.
+ *
+ * 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 org.matrix.android.sdk.test.fakes
+
+import android.net.NetworkCapabilities
+import io.mockk.every
+import io.mockk.mockk
+
+class FakeNetworkCapabilities {
+ val instance = mockk()
+
+ fun givenTransports(vararg type: Int) {
+ every { instance.hasTransport(any()) } answers {
+ val input = it.invocation.args.first() as Int
+ type.contains(input)
+ }
+ }
+}
diff --git a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/internal/session/content/FakeThumbnailExtractor.kt b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/internal/session/content/FakeThumbnailExtractor.kt
new file mode 100644
index 0000000000..b541d24161
--- /dev/null
+++ b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/internal/session/content/FakeThumbnailExtractor.kt
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2022 The Matrix.org Foundation C.I.C.
+ *
+ * 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 org.matrix.android.sdk.test.fakes.internal.session.content
+
+import io.mockk.mockk
+import org.matrix.android.sdk.internal.session.content.ThumbnailExtractor
+
+class FakeThumbnailExtractor {
+ internal val instance = mockk()
+}
diff --git a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/internal/session/permalinks/FakePermalinkFactory.kt b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/internal/session/permalinks/FakePermalinkFactory.kt
new file mode 100644
index 0000000000..3d7e85424e
--- /dev/null
+++ b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/internal/session/permalinks/FakePermalinkFactory.kt
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2022 The Matrix.org Foundation C.I.C.
+ *
+ * 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 org.matrix.android.sdk.test.fakes.internal.session.permalinks
+
+import io.mockk.mockk
+import org.matrix.android.sdk.internal.session.permalinks.PermalinkFactory
+
+class FakePermalinkFactory {
+ internal val instance = mockk()
+}
diff --git a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/internal/session/room/send/FakeLocalEchoRepository.kt b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/internal/session/room/send/FakeLocalEchoRepository.kt
new file mode 100644
index 0000000000..b10d13824b
--- /dev/null
+++ b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/internal/session/room/send/FakeLocalEchoRepository.kt
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2022 The Matrix.org Foundation C.I.C.
+ *
+ * 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 org.matrix.android.sdk.test.fakes.internal.session.room.send
+
+import io.mockk.mockk
+import org.matrix.android.sdk.internal.session.room.send.LocalEchoRepository
+
+class FakeLocalEchoRepository {
+ internal val instance = mockk()
+}
diff --git a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/internal/session/room/send/FakeMarkdownParser.kt b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/internal/session/room/send/FakeMarkdownParser.kt
new file mode 100644
index 0000000000..a27c9284e7
--- /dev/null
+++ b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/internal/session/room/send/FakeMarkdownParser.kt
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2022 The Matrix.org Foundation C.I.C.
+ *
+ * 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 org.matrix.android.sdk.test.fakes.internal.session.room.send
+
+import io.mockk.every
+import io.mockk.mockk
+import org.matrix.android.sdk.api.util.TextContent
+import org.matrix.android.sdk.internal.session.room.send.MarkdownParser
+
+class FakeMarkdownParser {
+ internal val instance = mockk()
+ fun givenBoldMarkdown() {
+ every { instance.parse(any(), any(), any()) } answers {
+ val text = arg(0)
+ TextContent(text, "${text.replace("*", "")}")
+ }
+ }
+}
diff --git a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/internal/session/room/send/FakeWaveFormSanitizer.kt b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/internal/session/room/send/FakeWaveFormSanitizer.kt
new file mode 100644
index 0000000000..052ddf7831
--- /dev/null
+++ b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/internal/session/room/send/FakeWaveFormSanitizer.kt
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2022 The Matrix.org Foundation C.I.C.
+ *
+ * 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 org.matrix.android.sdk.test.fakes.internal.session.room.send
+
+import io.mockk.mockk
+import org.matrix.android.sdk.internal.session.room.send.WaveFormSanitizer
+
+class FakeWaveFormSanitizer {
+ internal val instance = mockk()
+}
diff --git a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/internal/session/room/send/pills/FakeTextPillsUtils.kt b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/internal/session/room/send/pills/FakeTextPillsUtils.kt
new file mode 100644
index 0000000000..0d783d6628
--- /dev/null
+++ b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/test/fakes/internal/session/room/send/pills/FakeTextPillsUtils.kt
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2022 The Matrix.org Foundation C.I.C.
+ *
+ * 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 org.matrix.android.sdk.test.fakes.internal.session.room.send.pills
+
+import io.mockk.mockk
+import org.matrix.android.sdk.internal.session.room.send.pills.TextPillsUtils
+
+class FakeTextPillsUtils {
+ internal val instance = mockk()
+}