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
	 Dimitry Ivanov
						Dimitry Ivanov