Adding tests for SpannableBuilder
This commit is contained in:
parent
7a1b76af66
commit
cb917e7391
@ -163,11 +163,46 @@ public class SpannableBuilder implements Appendable, CharSequence {
|
||||
*/
|
||||
@Override
|
||||
public CharSequence subSequence(int start, int end) {
|
||||
// todo: NB, we do not copy spans here... we should I think
|
||||
// the thing to deal with: implement own `getSpans` method to mimic _native_ SpannableStringBuilder
|
||||
// behaviour. For example originally it will return all spans that at least _overlap_ with specified
|
||||
// range... which can be confusing
|
||||
return builder.subSequence(start, end);
|
||||
|
||||
final CharSequence out;
|
||||
|
||||
// @since 2.0.1 we copy spans to resulting subSequence
|
||||
final List<Span> spans = getSpans(start, end);
|
||||
if (spans.isEmpty()) {
|
||||
out = builder.subSequence(start, end);
|
||||
} else {
|
||||
|
||||
// we should not be SpannableStringBuilderReversed here
|
||||
final SpannableStringBuilder builder = new SpannableStringBuilder(this.builder.subSequence(start, end));
|
||||
|
||||
final int length = builder.length();
|
||||
|
||||
int s;
|
||||
int e;
|
||||
|
||||
for (Span span : spans) {
|
||||
|
||||
// we should limit start/end to resulting subSequence length
|
||||
//
|
||||
// for example, originally it was 5-7 and range 5-7 requested
|
||||
// span should have 0-2
|
||||
//
|
||||
// if a span was fully including resulting subSequence it's start and
|
||||
// end must be within 0..length bounds
|
||||
s = Math.max(0, span.start - start);
|
||||
e = Math.max(length, s + (span.end - span.start));
|
||||
|
||||
builder.setSpan(
|
||||
span.what,
|
||||
s,
|
||||
e,
|
||||
span.flags
|
||||
);
|
||||
}
|
||||
out = builder;
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -263,7 +298,7 @@ public class SpannableBuilder implements Appendable, CharSequence {
|
||||
/**
|
||||
* Simple method to create a SpannableStringBuilder, which is created anyway. Unlike {@link #text()}
|
||||
* method which returns the same SpannableStringBuilder there is no need to cast the resulting
|
||||
* CharSequence
|
||||
* CharSequence and makes the thing more explicit
|
||||
*
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@ -338,10 +373,10 @@ public class SpannableBuilder implements Appendable, CharSequence {
|
||||
*/
|
||||
public static class Span {
|
||||
|
||||
final Object what;
|
||||
int start;
|
||||
int end;
|
||||
final int flags;
|
||||
public final Object what;
|
||||
public int start;
|
||||
public int end;
|
||||
public final int flags;
|
||||
|
||||
Span(@NonNull Object what, int start, int end, int flags) {
|
||||
this.what = what;
|
||||
@ -355,7 +390,6 @@ public class SpannableBuilder implements Appendable, CharSequence {
|
||||
* @since 2.0.1 made inner class of {@link SpannableBuilder}, initially added in 1.0.1
|
||||
*/
|
||||
static class SpannableStringBuilderReversed extends SpannableStringBuilder {
|
||||
|
||||
SpannableStringBuilderReversed(CharSequence text) {
|
||||
super(text);
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
package ru.noties.markwon;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import android.text.SpannableStringBuilder;
|
||||
import android.text.Spanned;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@ -18,6 +20,7 @@ import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static ru.noties.markwon.SpannableBuilder.isPositionValid;
|
||||
import static ru.noties.markwon.SpannableBuilder.setSpans;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@Config(manifest = Config.NONE)
|
||||
@ -65,11 +68,6 @@ public class SpannableBuilderTest {
|
||||
}
|
||||
}
|
||||
|
||||
// @Test
|
||||
// public void set_spans_position_invalid() {
|
||||
// // will be silently ignored
|
||||
// }
|
||||
|
||||
@Test
|
||||
public void get_spans() {
|
||||
|
||||
@ -165,6 +163,173 @@ public class SpannableBuilderTest {
|
||||
.toList();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void set_spans_position_invalid() {
|
||||
// if supplied position is invalid, no spans should be added
|
||||
|
||||
builder.append('0');
|
||||
|
||||
assertTrue(builder.getSpans(0, builder.length()).isEmpty());
|
||||
|
||||
setSpans(builder, new Object(), -1, -1);
|
||||
|
||||
assertTrue(builder.getSpans(0, builder.length()).isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void set_spans_single() {
|
||||
// single span as `spans` argument correctly added
|
||||
|
||||
builder.append('0');
|
||||
|
||||
assertTrue(builder.getSpans(0, builder.length()).isEmpty());
|
||||
|
||||
final Object span = new Object();
|
||||
setSpans(builder, span, 0, 1);
|
||||
|
||||
final List<SpannableBuilder.Span> spans = builder.getSpans(0, builder.length());
|
||||
assertEquals(1, spans.size());
|
||||
assertEquals(span, spans.get(0).what);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void set_spans_array_detected() {
|
||||
// if supplied `spans` argument is an array -> it should be expanded
|
||||
|
||||
builder.append('0');
|
||||
|
||||
assertTrue(builder.getSpans(0, builder.length()).isEmpty());
|
||||
|
||||
final Object[] spans = {
|
||||
new Object(),
|
||||
new Object(),
|
||||
new Object()
|
||||
};
|
||||
|
||||
setSpans(builder, spans, 0, 1);
|
||||
|
||||
final List<SpannableBuilder.Span> actual = builder.getSpans(0, builder.length());
|
||||
assertEquals(spans.length, actual.size());
|
||||
|
||||
for (int i = 0, length = spans.length; i < length; i++) {
|
||||
assertEquals(spans[i], actual.get(i).what);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void set_spans_array_of_arrays() {
|
||||
// if array of arrays is supplied -> it won't be expanded to single elements
|
||||
|
||||
builder.append('0');
|
||||
|
||||
assertTrue(builder.getSpans(0, builder.length()).isEmpty());
|
||||
|
||||
final Object[] spans = {
|
||||
new Object[]{
|
||||
new Object(), new Object()
|
||||
},
|
||||
new Object[]{
|
||||
new Object(), new Object(), new Object()
|
||||
}
|
||||
};
|
||||
|
||||
setSpans(builder, spans, 0, 1);
|
||||
|
||||
final List<SpannableBuilder.Span> actual = builder.getSpans(0, builder.length());
|
||||
assertEquals(2, actual.size());
|
||||
|
||||
for (int i = 0, length = spans.length; i < length; i++) {
|
||||
assertEquals(spans[i], actual.get(i).what);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void set_spans_null() {
|
||||
// if `spans` argument is null, then nothing will be added
|
||||
|
||||
builder.append('0');
|
||||
|
||||
assertTrue(builder.getSpans(0, builder.length()).isEmpty());
|
||||
|
||||
setSpans(builder, null, 0, builder.length());
|
||||
|
||||
assertTrue(builder.getSpans(0, builder.length()).isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void spans_reversed() {
|
||||
// resulting SpannableStringBuilder should have spans reversed
|
||||
|
||||
final Object[] spans = {
|
||||
0,
|
||||
1,
|
||||
2
|
||||
};
|
||||
|
||||
for (Object span : spans) {
|
||||
builder.append(span.toString(), span);
|
||||
}
|
||||
|
||||
final SpannableStringBuilder spannableStringBuilder = builder.spannableStringBuilder();
|
||||
final Object[] actual = spannableStringBuilder.getSpans(0, builder.length(), Object.class);
|
||||
|
||||
for (int start = 0, length = spans.length, end = length - 1; start < length; start++, end--) {
|
||||
assertEquals(spans[start], actual[end]);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void append_spanned_normal() {
|
||||
// #append is called with regular Spanned content -> spans should be added in reverse
|
||||
|
||||
final SpannableStringBuilder ssb = new SpannableStringBuilder();
|
||||
for (int i = 0; i < 3; i++) {
|
||||
ssb.append(String.valueOf(i));
|
||||
ssb.setSpan(i, i, i + 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
}
|
||||
|
||||
assertTrue(builder.getSpans(0, builder.length()).isEmpty());
|
||||
|
||||
builder.append(ssb);
|
||||
|
||||
assertEquals("012", builder.toString());
|
||||
|
||||
// this one would return normal order as spans are reversed here
|
||||
// final List<SpannableBuilder.Span> spans = builder.getSpans(0, builder.length());
|
||||
|
||||
final SpannableStringBuilder spannableStringBuilder = builder.spannableStringBuilder();
|
||||
final Object[] spans = spannableStringBuilder.getSpans(0, builder.length(), Object.class);
|
||||
assertEquals(3, spans.length);
|
||||
|
||||
for (int i = 0, length = spans.length; i < length; i++) {
|
||||
assertEquals(length - 1 - i, spans[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void append_spanned_reversed() {
|
||||
// #append is called with reversed spanned content -> spans should be added as-are
|
||||
|
||||
final SpannableBuilder spannableBuilder = new SpannableBuilder();
|
||||
for (int i = 0; i < 3; i++) {
|
||||
spannableBuilder.append(String.valueOf(i), i);
|
||||
}
|
||||
|
||||
assertTrue(builder.getSpans(0, builder.length()).isEmpty());
|
||||
|
||||
builder.append(spannableBuilder.spannableStringBuilder());
|
||||
|
||||
final SpannableStringBuilder spannableStringBuilder = builder.spannableStringBuilder();
|
||||
final Object[] spans = spannableStringBuilder.getSpans(0, spannableStringBuilder.length(), Object.class);
|
||||
assertEquals(3, spans.length);
|
||||
|
||||
for (int i = 0, length = spans.length; i < length; i++) {
|
||||
// in the end order should be as we expect in order to properly render it
|
||||
// (no matter if reversed is used or not)
|
||||
assertEquals(length - 1 - i, spans[i]);
|
||||
}
|
||||
}
|
||||
|
||||
private static class Position {
|
||||
|
||||
@NonNull
|
||||
|
Loading…
x
Reference in New Issue
Block a user