1 /* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.inputmethod.latin.utils; 18 19 import static org.junit.Assert.assertEquals; 20 import static org.junit.Assert.assertTrue; 21 22 import android.content.Context; 23 import android.text.SpannableString; 24 import android.text.SpannableStringBuilder; 25 import android.text.Spanned; 26 import android.text.SpannedString; 27 import android.text.style.SuggestionSpan; 28 import android.text.style.URLSpan; 29 30 import androidx.test.InstrumentationRegistry; 31 import androidx.test.filters.SmallTest; 32 import androidx.test.runner.AndroidJUnit4; 33 34 import org.junit.Test; 35 import org.junit.runner.RunWith; 36 37 @SmallTest 38 @RunWith(AndroidJUnit4.class) 39 public class SpannableStringUtilsTests { 40 getContext()41 private Context getContext() { 42 return InstrumentationRegistry.getTargetContext(); 43 } 44 45 @Test testConcatWithSuggestionSpansOnly()46 public void testConcatWithSuggestionSpansOnly() { 47 SpannableStringBuilder s = new SpannableStringBuilder("test string\ntest string\n" 48 + "test string\ntest string\ntest string\ntest string\ntest string\ntest string\n" 49 + "test string\ntest string\n"); 50 final int N = 10; 51 for (int i = 0; i < N; ++i) { 52 // Put a PARAGRAPH-flagged span that should not be found in the result. 53 s.setSpan(new SuggestionSpan(getContext(), 54 new String[] {"" + i}, Spanned.SPAN_PARAGRAPH), 55 i * 12, i * 12 + 12, Spanned.SPAN_PARAGRAPH); 56 // Put a normal suggestion span that should be found in the result. 57 s.setSpan(new SuggestionSpan(getContext(), new String[] {"" + i}, 0), i, i * 2, 0); 58 // Put a URL span than should not be found in the result. 59 s.setSpan(new URLSpan("http://a"), i, i * 2, 0); 60 } 61 62 final CharSequence a = s.subSequence(0, 15); 63 final CharSequence b = s.subSequence(15, s.length()); 64 final Spanned result = 65 (Spanned)SpannableStringUtils.concatWithNonParagraphSuggestionSpansOnly(a, b); 66 67 Object[] spans = result.getSpans(0, result.length(), SuggestionSpan.class); 68 for (int i = 0; i < spans.length; i++) { 69 final int flags = result.getSpanFlags(spans[i]); 70 assertEquals("Should not find a span with PARAGRAPH flag", 71 flags & Spanned.SPAN_PARAGRAPH, 0); 72 assertTrue("Should be a SuggestionSpan", spans[i] instanceof SuggestionSpan); 73 } 74 } 75 assertSpanCount(final int expectedCount, final CharSequence cs)76 private static void assertSpanCount(final int expectedCount, final CharSequence cs) { 77 final int actualCount; 78 if (cs instanceof Spanned) { 79 final Spanned spanned = (Spanned) cs; 80 actualCount = spanned.getSpans(0, spanned.length(), Object.class).length; 81 } else { 82 actualCount = 0; 83 } 84 assertEquals(expectedCount, actualCount); 85 } 86 assertSpan(final CharSequence cs, final Object expectedSpan, final int expectedStart, final int expectedEnd, final int expectedFlags)87 private static void assertSpan(final CharSequence cs, final Object expectedSpan, 88 final int expectedStart, final int expectedEnd, final int expectedFlags) { 89 assertTrue(cs instanceof Spanned); 90 final Spanned spanned = (Spanned) cs; 91 final Object[] actualSpans = spanned.getSpans(0, spanned.length(), Object.class); 92 for (Object actualSpan : actualSpans) { 93 if (actualSpan == expectedSpan) { 94 final int actualStart = spanned.getSpanStart(actualSpan); 95 final int actualEnd = spanned.getSpanEnd(actualSpan); 96 final int actualFlags = spanned.getSpanFlags(actualSpan); 97 assertEquals(expectedStart, actualStart); 98 assertEquals(expectedEnd, actualEnd); 99 assertEquals(expectedFlags, actualFlags); 100 return; 101 } 102 } 103 assertTrue(false); 104 } 105 106 @Test testSplitCharSequenceWithSpan()107 public void testSplitCharSequenceWithSpan() { 108 // text: " a bcd efg hij " 109 // span1: ^^^^^^^ 110 // span2: ^^^^^ 111 // span3: ^ 112 final SpannableString spannableString = new SpannableString(" a bcd efg hij "); 113 final Object span1 = new Object(); 114 final Object span2 = new Object(); 115 final Object span3 = new Object(); 116 final int SPAN1_FLAGS = Spanned.SPAN_EXCLUSIVE_EXCLUSIVE; 117 final int SPAN2_FLAGS = Spanned.SPAN_EXCLUSIVE_INCLUSIVE; 118 final int SPAN3_FLAGS = Spanned.SPAN_INCLUSIVE_INCLUSIVE; 119 spannableString.setSpan(span1, 0, 7, SPAN1_FLAGS); 120 spannableString.setSpan(span2, 0, 5, SPAN2_FLAGS); 121 spannableString.setSpan(span3, 12, 13, SPAN3_FLAGS); 122 final CharSequence[] charSequencesFromSpanned = SpannableStringUtils.split( 123 spannableString, " ", true /* preserveTrailingEmptySegmengs */); 124 final CharSequence[] charSequencesFromString = SpannableStringUtils.split( 125 spannableString.toString(), " ", true /* preserveTrailingEmptySegmengs */); 126 127 128 assertEquals(7, charSequencesFromString.length); 129 assertEquals(7, charSequencesFromSpanned.length); 130 131 // text: "" 132 // span1: ^ 133 // span2: ^ 134 // span3: 135 assertEquals("", charSequencesFromString[0].toString()); 136 assertSpanCount(0, charSequencesFromString[0]); 137 assertEquals("", charSequencesFromSpanned[0].toString()); 138 assertSpanCount(2, charSequencesFromSpanned[0]); 139 assertSpan(charSequencesFromSpanned[0], span1, 0, 0, SPAN1_FLAGS); 140 assertSpan(charSequencesFromSpanned[0], span2, 0, 0, SPAN2_FLAGS); 141 142 // text: "a" 143 // span1: ^ 144 // span2: ^ 145 // span3: 146 assertEquals("a", charSequencesFromString[1].toString()); 147 assertSpanCount(0, charSequencesFromString[1]); 148 assertEquals("a", charSequencesFromSpanned[1].toString()); 149 assertSpanCount(2, charSequencesFromSpanned[1]); 150 assertSpan(charSequencesFromSpanned[1], span1, 0, 1, SPAN1_FLAGS); 151 assertSpan(charSequencesFromSpanned[1], span2, 0, 1, SPAN2_FLAGS); 152 153 // text: "bcd" 154 // span1: ^^^ 155 // span2: ^^ 156 // span3: 157 assertEquals("bcd", charSequencesFromString[2].toString()); 158 assertSpanCount(0, charSequencesFromString[2]); 159 assertEquals("bcd", charSequencesFromSpanned[2].toString()); 160 assertSpanCount(2, charSequencesFromSpanned[2]); 161 assertSpan(charSequencesFromSpanned[2], span1, 0, 3, SPAN1_FLAGS); 162 assertSpan(charSequencesFromSpanned[2], span2, 0, 2, SPAN2_FLAGS); 163 164 // text: "efg" 165 // span1: 166 // span2: 167 // span3: 168 assertEquals("efg", charSequencesFromString[3].toString()); 169 assertSpanCount(0, charSequencesFromString[3]); 170 assertEquals("efg", charSequencesFromSpanned[3].toString()); 171 assertSpanCount(0, charSequencesFromSpanned[3]); 172 173 // text: "hij" 174 // span1: 175 // span2: 176 // span3: ^ 177 assertEquals("hij", charSequencesFromString[4].toString()); 178 assertSpanCount(0, charSequencesFromString[4]); 179 assertEquals("hij", charSequencesFromSpanned[4].toString()); 180 assertSpanCount(1, charSequencesFromSpanned[4]); 181 assertSpan(charSequencesFromSpanned[4], span3, 1, 2, SPAN3_FLAGS); 182 183 // text: "" 184 // span1: 185 // span2: 186 // span3: 187 assertEquals("", charSequencesFromString[5].toString()); 188 assertSpanCount(0, charSequencesFromString[5]); 189 assertEquals("", charSequencesFromSpanned[5].toString()); 190 assertSpanCount(0, charSequencesFromSpanned[5]); 191 192 // text: "" 193 // span1: 194 // span2: 195 // span3: 196 assertEquals("", charSequencesFromString[6].toString()); 197 assertSpanCount(0, charSequencesFromString[6]); 198 assertEquals("", charSequencesFromSpanned[6].toString()); 199 assertSpanCount(0, charSequencesFromSpanned[6]); 200 } 201 202 @Test testSplitCharSequencePreserveTrailingEmptySegmengs()203 public void testSplitCharSequencePreserveTrailingEmptySegmengs() { 204 assertEquals(1, SpannableStringUtils.split("", " ", 205 false /* preserveTrailingEmptySegmengs */).length); 206 assertEquals(1, SpannableStringUtils.split(new SpannedString(""), " ", 207 false /* preserveTrailingEmptySegmengs */).length); 208 209 assertEquals(1, SpannableStringUtils.split("", " ", 210 true /* preserveTrailingEmptySegmengs */).length); 211 assertEquals(1, SpannableStringUtils.split(new SpannedString(""), " ", 212 true /* preserveTrailingEmptySegmengs */).length); 213 214 assertEquals(0, SpannableStringUtils.split(" ", " ", 215 false /* preserveTrailingEmptySegmengs */).length); 216 assertEquals(0, SpannableStringUtils.split(new SpannedString(" "), " ", 217 false /* preserveTrailingEmptySegmengs */).length); 218 219 assertEquals(2, SpannableStringUtils.split(" ", " ", 220 true /* preserveTrailingEmptySegmengs */).length); 221 assertEquals(2, SpannableStringUtils.split(new SpannedString(" "), " ", 222 true /* preserveTrailingEmptySegmengs */).length); 223 224 assertEquals(3, SpannableStringUtils.split("a b c ", " ", 225 false /* preserveTrailingEmptySegmengs */).length); 226 assertEquals(3, SpannableStringUtils.split(new SpannedString("a b c "), " ", 227 false /* preserveTrailingEmptySegmengs */).length); 228 229 assertEquals(5, SpannableStringUtils.split("a b c ", " ", 230 true /* preserveTrailingEmptySegmengs */).length); 231 assertEquals(5, SpannableStringUtils.split(new SpannedString("a b c "), " ", 232 true /* preserveTrailingEmptySegmengs */).length); 233 234 assertEquals(6, SpannableStringUtils.split("a b ", " ", 235 false /* preserveTrailingEmptySegmengs */).length); 236 assertEquals(6, SpannableStringUtils.split(new SpannedString("a b "), " ", 237 false /* preserveTrailingEmptySegmengs */).length); 238 239 assertEquals(7, SpannableStringUtils.split("a b ", " ", 240 true /* preserveTrailingEmptySegmengs */).length); 241 assertEquals(7, SpannableStringUtils.split(new SpannedString("a b "), " ", 242 true /* preserveTrailingEmptySegmengs */).length); 243 } 244 } 245