Skip to content

Commit

Permalink
fix: markdown link crash (#2116)
Browse files Browse the repository at this point in the history
Co-authored-by: Jakub Żerko <iot.zerko@gmail.com>
  • Loading branch information
github-actions[bot] and Garzas committed Aug 21, 2023
1 parent 65fc8c7 commit 36ff8db
Show file tree
Hide file tree
Showing 3 changed files with 120 additions and 8 deletions.
103 changes: 103 additions & 0 deletions app/src/androidTest/java/com/wire/android/LinkSpannableStringTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
/*
* Wire
* Copyright (C) 2023 Wire Swiss GmbH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://www.gnu.org/licenses/.
*/
package com.wire.android

import android.text.style.URLSpan
import android.text.util.Linkify
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.wire.android.ui.common.LinkSpannableString
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith

@RunWith(AndroidJUnit4::class)
class LinkSpannableStringTest {

lateinit var linkSpannableString: LinkSpannableString

@Before
fun setUp() {
linkSpannableString = LinkSpannableString("Hello, world!")
}

@Test
fun givenValidIndices_whenSetSpanIsCalled_thenSpanIsSet() {
// Given
val start = 0
val end = 5

// When
linkSpannableString.setSpan(URLSpan("http://example.com"), start, end, 0)

// Then
assert(linkSpannableString.getSpans(start, end, URLSpan::class.java).isNotEmpty())
}

@Test
fun givenInvalidStartIndex_whenSetSpanIsCalled_thenSpanIsNotSet() {
// Given
val start = -1
val end = 5

// When
linkSpannableString.setSpan(URLSpan("http://example.com"), start, end, 0)

// Then
assert(linkSpannableString.getSpans(start, end, URLSpan::class.java).isEmpty())
}

@Test
fun givenInvalidEndIndex_whenSetSpanIsCalled_thenSpanIsNotSet() {
// Given
val start = 0
val end = 20

// When
linkSpannableString.setSpan(URLSpan("http://example.com"), start, end, 0)

// Then
assert(linkSpannableString.getSpans(start, end, URLSpan::class.java).isEmpty())
}

@Test
fun givenASetSpan_whenRemoveSpanIsCalled_thenSpanIsRemoved() {
// Given
val urlSpan = URLSpan("http://example.com")
linkSpannableString.setSpan(urlSpan, 0, 5, 0)

// When
linkSpannableString.removeSpan(urlSpan)

// Then
assert(linkSpannableString.getSpans(0, 5, URLSpan::class.java).isEmpty())
}

@Test
fun givenATextWithLink_whenGetLinkInfosIsCalled_thenLinkInfoIsReturned() {
// Given
val text = "Visit http://example.com for more info."
val mask = Linkify.WEB_URLS

// When
val linkInfos = LinkSpannableString.getLinkInfos(text, mask)

// Then
assert(linkInfos.size == 1)
assert(linkInfos[0].url == "http://example.com")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextDecoration
import androidx.compose.ui.text.style.TextOverflow
import com.wire.android.appLogger

@Composable
fun ClickableText(
Expand Down Expand Up @@ -137,7 +138,11 @@ class LinkSpannableString(source: CharSequence) : SpannableString(source) {
}

override fun setSpan(what: Any?, start: Int, end: Int, flags: Int) {
super.setSpan(what, start, end, flags)
spanList.add(Data(what, start, end))
if (start >= 0 && end <= this.length && start <= end) {
super.setSpan(what, start, end, flags)
spanList.add(Data(what, start, end))
} else {
appLogger.e("[LinkSpannableString] Invalid span indices: start=$start, end=$end, length=$length")
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ import org.commonmark.node.SoftLineBreak
import org.commonmark.node.StrongEmphasis
import org.commonmark.node.Text
import org.commonmark.node.ThematicBreak
import kotlin.math.max
import kotlin.math.min
import org.commonmark.node.Text as nodeText

@Composable
Expand Down Expand Up @@ -192,7 +194,7 @@ fun inlineChildren(
return updatedMentions
}

@Suppress("LongMethod")
@Suppress("LongMethod", "ComplexMethod")
fun appendLinksAndMentions(
annotatedString: AnnotatedString.Builder,
string: String,
Expand Down Expand Up @@ -233,22 +235,24 @@ fun appendLinksAndMentions(
append(stringBuilder)
with(nodeData.colorScheme) {
linkInfos.forEach {
if (it.end - it.start <= 0) {
val safeStart = max(it.start, 0)
val safeEnd = min(it.end, length - 1)
if (safeStart > safeEnd) {
return@forEach
}
addStyle(
style = SpanStyle(
color = primary,
textDecoration = TextDecoration.Underline
),
start = it.start,
end = it.end
start = safeStart,
end = safeEnd
)
addStringAnnotation(
tag = TAG_URL,
annotation = it.url,
start = it.start,
end = it.end
start = safeStart,
end = safeEnd
)
}

Expand Down

0 comments on commit 36ff8db

Please sign in to comment.