TextUtilsTest.java revision 1a44d5dcabc18cd5ef111f732ccff91683a1a093
1/* 2 * Copyright (C) 2008 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 17package android.text; 18 19import android.graphics.Paint; 20import android.test.suitebuilder.annotation.LargeTest; 21import android.test.suitebuilder.annotation.SmallTest; 22import android.text.Spannable; 23import android.text.SpannableString; 24import android.text.Spanned; 25import android.text.SpannedString; 26import android.text.TextPaint; 27import android.text.TextUtils; 28import android.text.style.StyleSpan; 29import android.test.MoreAsserts; 30 31import com.android.common.Rfc822Validator; 32import com.google.android.collect.Lists; 33import com.google.android.collect.Maps; 34 35import junit.framework.TestCase; 36 37import java.util.List; 38import java.util.Map; 39 40/** 41 * TextUtilsTest tests {@link TextUtils}. 42 */ 43public class TextUtilsTest extends TestCase { 44 45 @SmallTest 46 public void testBasic() throws Exception { 47 assertEquals("", TextUtils.concat()); 48 assertEquals("foo", TextUtils.concat("foo")); 49 assertEquals("foobar", TextUtils.concat("foo", "bar")); 50 assertEquals("foobarbaz", TextUtils.concat("foo", "bar", "baz")); 51 52 SpannableString foo = new SpannableString("foo"); 53 foo.setSpan("foo", 1, 2, Spannable.SPAN_EXCLUSIVE_INCLUSIVE); 54 55 SpannableString bar = new SpannableString("bar"); 56 bar.setSpan("bar", 1, 2, Spannable.SPAN_EXCLUSIVE_INCLUSIVE); 57 58 SpannableString baz = new SpannableString("baz"); 59 baz.setSpan("baz", 1, 2, Spannable.SPAN_EXCLUSIVE_INCLUSIVE); 60 61 assertEquals("foo", TextUtils.concat(foo).toString()); 62 assertEquals("foobar", TextUtils.concat(foo, bar).toString()); 63 assertEquals("foobarbaz", TextUtils.concat(foo, bar, baz).toString()); 64 65 assertEquals(1, ((Spanned) TextUtils.concat(foo)).getSpanStart("foo")); 66 67 assertEquals(1, ((Spanned) TextUtils.concat(foo, bar)).getSpanStart("foo")); 68 assertEquals(4, ((Spanned) TextUtils.concat(foo, bar)).getSpanStart("bar")); 69 70 assertEquals(1, ((Spanned) TextUtils.concat(foo, bar, baz)).getSpanStart("foo")); 71 assertEquals(4, ((Spanned) TextUtils.concat(foo, bar, baz)).getSpanStart("bar")); 72 assertEquals(7, ((Spanned) TextUtils.concat(foo, bar, baz)).getSpanStart("baz")); 73 74 assertTrue(TextUtils.concat("foo", "bar") instanceof String); 75 assertTrue(TextUtils.concat(foo, bar) instanceof SpannedString); 76 } 77 78 @SmallTest 79 public void testTemplateString() throws Exception { 80 CharSequence result; 81 82 result = TextUtils.expandTemplate("This is a ^1 of the ^2 broadcast ^3.", 83 "test", "emergency", "system"); 84 assertEquals("This is a test of the emergency broadcast system.", 85 result.toString()); 86 87 result = TextUtils.expandTemplate("^^^1^^^2^3^a^1^^b^^^c", 88 "one", "two", "three"); 89 assertEquals("^one^twothree^aone^b^^c", 90 result.toString()); 91 92 result = TextUtils.expandTemplate("^"); 93 assertEquals("^", result.toString()); 94 95 result = TextUtils.expandTemplate("^^"); 96 assertEquals("^", result.toString()); 97 98 result = TextUtils.expandTemplate("^^^"); 99 assertEquals("^^", result.toString()); 100 101 result = TextUtils.expandTemplate("shorter ^1 values ^2.", "a", ""); 102 assertEquals("shorter a values .", result.toString()); 103 104 try { 105 TextUtils.expandTemplate("Only ^1 value given, but ^2 used.", "foo"); 106 fail(); 107 } catch (IllegalArgumentException e) { 108 } 109 110 try { 111 TextUtils.expandTemplate("^1 value given, and ^0 used.", "foo"); 112 fail(); 113 } catch (IllegalArgumentException e) { 114 } 115 116 result = TextUtils.expandTemplate("^1 value given, and ^9 used.", 117 "one", "two", "three", "four", "five", 118 "six", "seven", "eight", "nine"); 119 assertEquals("one value given, and nine used.", result.toString()); 120 121 try { 122 TextUtils.expandTemplate("^1 value given, and ^10 used.", 123 "one", "two", "three", "four", "five", 124 "six", "seven", "eight", "nine", "ten"); 125 fail(); 126 } catch (IllegalArgumentException e) { 127 } 128 129 // putting carets in the values: expansion is not recursive. 130 131 result = TextUtils.expandTemplate("^2", "foo", "^^"); 132 assertEquals("^^", result.toString()); 133 134 result = TextUtils.expandTemplate("^^2", "foo", "1"); 135 assertEquals("^2", result.toString()); 136 137 result = TextUtils.expandTemplate("^1", "value with ^2 in it", "foo"); 138 assertEquals("value with ^2 in it", result.toString()); 139 } 140 141 /** Fail unless text+spans contains a span 'spanName' with the given start and end. */ 142 private void checkContains(Spanned text, String[] spans, String spanName, 143 int start, int end) throws Exception { 144 for (String i: spans) { 145 if (i.equals(spanName)) { 146 assertEquals(start, text.getSpanStart(i)); 147 assertEquals(end, text.getSpanEnd(i)); 148 return; 149 } 150 } 151 fail(); 152 } 153 154 @SmallTest 155 public void testTemplateSpan() throws Exception { 156 SpannableString template; 157 Spanned result; 158 String[] spans; 159 160 // ordinary replacement 161 162 template = new SpannableString("a^1b"); 163 template.setSpan("before", 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); 164 template.setSpan("during", 1, 3, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); 165 template.setSpan("after", 3, 4, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); 166 template.setSpan("during+after", 1, 4, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); 167 168 result = (Spanned) TextUtils.expandTemplate(template, "foo"); 169 assertEquals(5, result.length()); 170 spans = result.getSpans(0, result.length(), String.class); 171 172 // value is one character longer, so span endpoints should change. 173 assertEquals(4, spans.length); 174 checkContains(result, spans, "before", 0, 1); 175 checkContains(result, spans, "during", 1, 4); 176 checkContains(result, spans, "after", 4, 5); 177 checkContains(result, spans, "during+after", 1, 5); 178 179 180 // replacement with empty string 181 182 result = (Spanned) TextUtils.expandTemplate(template, ""); 183 assertEquals(2, result.length()); 184 spans = result.getSpans(0, result.length(), String.class); 185 186 // the "during" span should disappear. 187 assertEquals(3, spans.length); 188 checkContains(result, spans, "before", 0, 1); 189 checkContains(result, spans, "after", 1, 2); 190 checkContains(result, spans, "during+after", 1, 2); 191 } 192 193 @SmallTest 194 public void testStringSplitterSimple() { 195 stringSplitterTestHelper("a,b,cde", new String[] {"a", "b", "cde"}); 196 } 197 198 @SmallTest 199 public void testStringSplitterEmpty() { 200 stringSplitterTestHelper("", new String[] {}); 201 } 202 203 @SmallTest 204 public void testStringSplitterWithLeadingEmptyString() { 205 stringSplitterTestHelper(",a,b,cde", new String[] {"", "a", "b", "cde"}); 206 } 207 208 @SmallTest 209 public void testStringSplitterWithInternalEmptyString() { 210 stringSplitterTestHelper("a,b,,cde", new String[] {"a", "b", "", "cde"}); 211 } 212 213 @SmallTest 214 public void testStringSplitterWithTrailingEmptyString() { 215 // A single trailing emtpy string should be ignored. 216 stringSplitterTestHelper("a,b,cde,", new String[] {"a", "b", "cde"}); 217 } 218 219 private void stringSplitterTestHelper(String string, String[] expectedStrings) { 220 TextUtils.StringSplitter splitter = new TextUtils.SimpleStringSplitter(','); 221 splitter.setString(string); 222 List<String> strings = Lists.newArrayList(); 223 for (String s : splitter) { 224 strings.add(s); 225 } 226 MoreAsserts.assertEquals(expectedStrings, strings.toArray(new String[]{})); 227 } 228 229 @SmallTest 230 public void testTrim() { 231 String[] strings = { "abc", " abc", " abc", "abc ", "abc ", 232 " abc ", " abc ", "\nabc\n", "\nabc", "abc\n" }; 233 234 for (String s : strings) { 235 assertEquals(s.trim().length(), TextUtils.getTrimmedLength(s)); 236 } 237 } 238 239 //============================================================================================== 240 // Email validator 241 //============================================================================================== 242 243 @SmallTest 244 public void testEmailValidator() { 245 Rfc822Validator validator = new Rfc822Validator("gmail.com"); 246 String[] validEmails = new String[] { 247 "a@b.com", "a@b.fr", "a+b@c.com", "a@b.info", 248 }; 249 250 for (String email : validEmails) { 251 assertTrue(email + " should be a valid email address", validator.isValid(email)); 252 } 253 254 String[] invalidEmails = new String[] { 255 "a", "a@b", "a b", "a@b.12" 256 }; 257 258 for (String email : invalidEmails) { 259 assertFalse(email + " should not be a valid email address", validator.isValid(email)); 260 } 261 262 Map<String, String> fixes = Maps.newHashMap(); 263 fixes.put("a", "<a@gmail.com>"); 264 fixes.put("a b", "<ab@gmail.com>"); 265 fixes.put("a@b", "<a@b>"); 266 267 for (Map.Entry<String, String> e : fixes.entrySet()) { 268 assertEquals(e.getValue(), validator.fixText(e.getKey()).toString()); 269 } 270 } 271 272 @LargeTest 273 public void testEllipsize() { 274 CharSequence s1 = "The quick brown fox jumps over \u00FEhe lazy dog."; 275 CharSequence s2 = new Wrapper(s1); 276 Spannable s3 = new SpannableString(s1); 277 s3.setSpan(new StyleSpan(0), 5, 10, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); 278 TextPaint p = new TextPaint(); 279 p.setFlags(p.getFlags() & ~p.DEV_KERN_TEXT_FLAG); 280 281 for (int i = 0; i < 100; i++) { 282 for (int j = 0; j < 3; j++) { 283 TextUtils.TruncateAt kind = null; 284 285 switch (j) { 286 case 0: 287 kind = TextUtils.TruncateAt.START; 288 break; 289 290 case 1: 291 kind = TextUtils.TruncateAt.END; 292 break; 293 294 case 2: 295 kind = TextUtils.TruncateAt.MIDDLE; 296 break; 297 } 298 299 String out1 = TextUtils.ellipsize(s1, p, i, kind).toString(); 300 String out2 = TextUtils.ellipsize(s2, p, i, kind).toString(); 301 String out3 = TextUtils.ellipsize(s3, p, i, kind).toString(); 302 303 String keep1 = TextUtils.ellipsize(s1, p, i, kind, true, null).toString(); 304 String keep2 = TextUtils.ellipsize(s2, p, i, kind, true, null).toString(); 305 String keep3 = TextUtils.ellipsize(s3, p, i, kind, true, null).toString(); 306 307 String trim1 = keep1.replace("\uFEFF", ""); 308 309 // Are all normal output strings identical? 310 assertEquals("wid " + i + " pass " + j, out1, out2); 311 assertEquals("wid " + i + " pass " + j, out2, out3); 312 313 // Are preserved output strings identical? 314 assertEquals("wid " + i + " pass " + j, keep1, keep2); 315 assertEquals("wid " + i + " pass " + j, keep2, keep3); 316 317 // Does trimming padding from preserved yield normal? 318 assertEquals("wid " + i + " pass " + j, out1, trim1); 319 320 // Did preserved output strings preserve length? 321 assertEquals("wid " + i + " pass " + j, keep1.length(), s1.length()); 322 323 // Does the output string actually fit in the space? 324 assertTrue("wid " + i + " pass " + j, p.measureText(out1) <= i); 325 326 // Is the padded output the same width as trimmed output? 327 assertTrue("wid " + i + " pass " + j, p.measureText(keep1) == p.measureText(out1)); 328 } 329 } 330 } 331 332 /** 333 * CharSequence wrapper for testing the cases where text is copied into 334 * a char array instead of working from a String or a Spanned. 335 */ 336 private static class Wrapper implements CharSequence { 337 private CharSequence mString; 338 339 public Wrapper(CharSequence s) { 340 mString = s; 341 } 342 343 public int length() { 344 return mString.length(); 345 } 346 347 public char charAt(int off) { 348 return mString.charAt(off); 349 } 350 351 public String toString() { 352 return mString.toString(); 353 } 354 355 public CharSequence subSequence(int start, int end) { 356 return new Wrapper(mString.subSequence(start, end)); 357 } 358 } 359} 360