2018-05-16 19:14:26 +02:00
package com.keylesspalace.tusky
import android.text.Spannable
import com.keylesspalace.tusky.util.highlightSpans
2018-11-16 13:31:03 +01:00
import org.junit.Assert
2018-05-16 19:14:26 +02:00
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.Parameterized
class SpanUtilsTest {
@Test
fun matchesMixedSpans ( ) {
2019-02-05 19:55:28 +01:00
val input = " one #one two dat://tw.wo?no=yes three @three four https://fo.ur/meh?foo=bar&wat=@at#hmm five #five ipfs://si.xx/?pick=up#sticks seven @seven "
2018-05-16 19:14:26 +02:00
val inputSpannable = FakeSpannable ( input )
highlightSpans ( inputSpannable , 0xffffff )
val spans = inputSpannable . spans
2019-02-05 19:55:28 +01:00
Assert . assertEquals ( 7 , spans . size )
2018-05-16 19:14:26 +02:00
}
@Test
fun doesntMergeAdjacentURLs ( ) {
val firstURL = " http://first.thing "
val secondURL = " https://second.thing "
2018-11-16 13:31:03 +01:00
val inputSpannable = FakeSpannable ( " $firstURL $secondURL " )
2018-05-16 19:14:26 +02:00
highlightSpans ( inputSpannable , 0xffffff )
val spans = inputSpannable . spans
Assert . assertEquals ( 2 , spans . size )
Assert . assertEquals ( firstURL . length , spans [ 0 ] . end - spans [ 0 ] . start )
Assert . assertEquals ( secondURL . length , spans [ 1 ] . end - spans [ 1 ] . start )
}
@RunWith ( Parameterized :: class )
class MatchingTests ( private val thingToHighlight : String ) {
companion object {
@Parameterized . Parameters ( name = " {0} " )
@JvmStatic
fun data ( ) : Iterable < Any > {
return listOf (
" @mention " ,
" #tag " ,
2019-02-05 19:55:28 +01:00
" dat://thr.ee/meh?foo=bar&wat=@at#hmm " ,
" ssb://thr.ee/meh?foo=bar&wat=@at#hmm " ,
" ipfs://thr.ee/meh?foo=bar&wat=@at#hmm " ,
2018-05-16 19:14:26 +02:00
" https://thr.ee/meh?foo=bar&wat=@at#hmm " ,
" http://thr.ee/meh?foo=bar&wat=@at#hmm "
)
}
}
@Test
fun matchesSpanAtStart ( ) {
val inputSpannable = FakeSpannable ( thingToHighlight )
highlightSpans ( inputSpannable , 0xffffff )
val spans = inputSpannable . spans
Assert . assertEquals ( 1 , spans . size )
Assert . assertEquals ( thingToHighlight . length , spans [ 0 ] . end - spans [ 0 ] . start )
}
@Test
fun matchesSpanNotAtStart ( ) {
2018-11-16 13:31:03 +01:00
val inputSpannable = FakeSpannable ( " $thingToHighlight " )
2018-05-16 19:14:26 +02:00
highlightSpans ( inputSpannable , 0xffffff )
val spans = inputSpannable . spans
Assert . assertEquals ( 1 , spans . size )
Assert . assertEquals ( thingToHighlight . length , spans [ 0 ] . end - spans [ 0 ] . start )
}
@Test
fun doesNotMatchSpanEmbeddedInText ( ) {
2019-02-05 19:55:28 +01:00
val inputSpannable = FakeSpannable ( " __ ${thingToHighlight} __ " )
2018-05-16 19:14:26 +02:00
highlightSpans ( inputSpannable , 0xffffff )
val spans = inputSpannable . spans
Assert . assertTrue ( spans . isEmpty ( ) )
}
@Test
fun doesNotMatchSpanEmbeddedInAnotherSpan ( ) {
val inputSpannable = FakeSpannable ( " @aa ${thingToHighlight} aa " )
highlightSpans ( inputSpannable , 0xffffff )
val spans = inputSpannable . spans
Assert . assertEquals ( 1 , spans . size )
2019-02-05 19:55:28 +01:00
Assert . assertEquals ( 0 , spans [ 0 ] . start )
2018-05-16 19:14:26 +02:00
}
@Test
fun spansDoNotOverlap ( ) {
val begin = " @begin "
val end = " #end "
2018-11-16 13:31:03 +01:00
val inputSpannable = FakeSpannable ( " $begin $thingToHighlight $end " )
2018-05-16 19:14:26 +02:00
highlightSpans ( inputSpannable , 0xffffff )
val spans = inputSpannable . spans
Assert . assertEquals ( 3 , spans . size )
2018-11-16 13:31:03 +01:00
val middleSpan = spans . single { span -> span . start > 0 && span . end < inputSpannable . lastIndex }
2018-05-16 19:14:26 +02:00
Assert . assertEquals ( begin . length + 1 , middleSpan . start )
Assert . assertEquals ( inputSpannable . length - end . length - 1 , middleSpan . end )
}
}
class FakeSpannable ( private val text : String ) : Spannable {
val spans = mutableListOf < BoundedSpan > ( )
override fun setSpan ( what : Any ? , start : Int , end : Int , flags : Int ) {
spans . add ( BoundedSpan ( what , start , end ) )
}
override fun < T : Any ? > getSpans ( start : Int , end : Int , type : Class < T > ? ) : Array < T > {
val matching = if ( type == null ) {
ArrayList < T > ( )
} else {
2018-11-16 13:31:03 +01:00
spans . filter { it . start >= start && it . end <= end && type . isAssignableFrom ( it . span ?. javaClass ) }
. map { it -> it . span }
2018-05-16 19:14:26 +02:00
. let { ArrayList ( it ) }
}
return matching . toArray ( ) as Array < T >
}
override fun removeSpan ( what : Any ? ) {
2018-11-16 13:31:03 +01:00
spans . removeIf { span -> span . span == what }
2018-05-16 19:14:26 +02:00
}
override fun toString ( ) : String {
return text
}
override val length : Int
get ( ) = text . length
class BoundedSpan ( val span : Any ? , val start : Int , val end : Int )
override fun nextSpanTransition ( start : Int , limit : Int , type : Class < * > ? ) : Int {
throw NotImplementedError ( )
}
override fun getSpanEnd ( tag : Any ? ) : Int {
throw NotImplementedError ( )
}
override fun getSpanFlags ( tag : Any ? ) : Int {
throw NotImplementedError ( )
}
override fun get ( index : Int ) : Char {
throw NotImplementedError ( )
}
override fun subSequence ( startIndex : Int , endIndex : Int ) : CharSequence {
throw NotImplementedError ( )
}
override fun getSpanStart ( tag : Any ? ) : Int {
throw NotImplementedError ( )
}
}
}