blob: d494c5d03b6315eb9683b2828102a8c9f416a0b4 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
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
Neal Nguyen1a44d5d2010-01-13 10:42:43 -080017package android.text;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080018
Gilles Debunne1e3ac182011-03-08 14:22:34 -080019import com.google.android.collect.Lists;
20
21import android.test.MoreAsserts;
Martin Wallgrencee20512011-04-07 14:45:43 +020022import android.os.Parcel;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080023import android.test.suitebuilder.annotation.LargeTest;
24import android.test.suitebuilder.annotation.SmallTest;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080025import android.text.style.StyleSpan;
The Android Open Source Projectee7e6a72010-06-03 09:03:58 -070026import android.text.util.Rfc822Token;
27import android.text.util.Rfc822Tokenizer;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080028
Gilles Debunne1e3ac182011-03-08 14:22:34 -080029import java.util.ArrayList;
30import java.util.List;
Paul Westbrook7762d932009-12-11 14:13:48 -080031
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080032import junit.framework.TestCase;
33
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080034/**
35 * TextUtilsTest tests {@link TextUtils}.
36 */
37public class TextUtilsTest extends TestCase {
38
39 @SmallTest
40 public void testBasic() throws Exception {
41 assertEquals("", TextUtils.concat());
42 assertEquals("foo", TextUtils.concat("foo"));
43 assertEquals("foobar", TextUtils.concat("foo", "bar"));
44 assertEquals("foobarbaz", TextUtils.concat("foo", "bar", "baz"));
45
46 SpannableString foo = new SpannableString("foo");
47 foo.setSpan("foo", 1, 2, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
48
49 SpannableString bar = new SpannableString("bar");
50 bar.setSpan("bar", 1, 2, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
51
52 SpannableString baz = new SpannableString("baz");
53 baz.setSpan("baz", 1, 2, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
54
55 assertEquals("foo", TextUtils.concat(foo).toString());
56 assertEquals("foobar", TextUtils.concat(foo, bar).toString());
57 assertEquals("foobarbaz", TextUtils.concat(foo, bar, baz).toString());
58
59 assertEquals(1, ((Spanned) TextUtils.concat(foo)).getSpanStart("foo"));
60
61 assertEquals(1, ((Spanned) TextUtils.concat(foo, bar)).getSpanStart("foo"));
62 assertEquals(4, ((Spanned) TextUtils.concat(foo, bar)).getSpanStart("bar"));
63
64 assertEquals(1, ((Spanned) TextUtils.concat(foo, bar, baz)).getSpanStart("foo"));
65 assertEquals(4, ((Spanned) TextUtils.concat(foo, bar, baz)).getSpanStart("bar"));
66 assertEquals(7, ((Spanned) TextUtils.concat(foo, bar, baz)).getSpanStart("baz"));
67
68 assertTrue(TextUtils.concat("foo", "bar") instanceof String);
69 assertTrue(TextUtils.concat(foo, bar) instanceof SpannedString);
70 }
71
72 @SmallTest
73 public void testTemplateString() throws Exception {
74 CharSequence result;
75
76 result = TextUtils.expandTemplate("This is a ^1 of the ^2 broadcast ^3.",
77 "test", "emergency", "system");
78 assertEquals("This is a test of the emergency broadcast system.",
79 result.toString());
80
81 result = TextUtils.expandTemplate("^^^1^^^2^3^a^1^^b^^^c",
82 "one", "two", "three");
83 assertEquals("^one^twothree^aone^b^^c",
84 result.toString());
85
86 result = TextUtils.expandTemplate("^");
87 assertEquals("^", result.toString());
88
89 result = TextUtils.expandTemplate("^^");
90 assertEquals("^", result.toString());
91
92 result = TextUtils.expandTemplate("^^^");
93 assertEquals("^^", result.toString());
94
95 result = TextUtils.expandTemplate("shorter ^1 values ^2.", "a", "");
96 assertEquals("shorter a values .", result.toString());
97
98 try {
99 TextUtils.expandTemplate("Only ^1 value given, but ^2 used.", "foo");
100 fail();
101 } catch (IllegalArgumentException e) {
102 }
103
104 try {
105 TextUtils.expandTemplate("^1 value given, and ^0 used.", "foo");
106 fail();
107 } catch (IllegalArgumentException e) {
108 }
109
110 result = TextUtils.expandTemplate("^1 value given, and ^9 used.",
111 "one", "two", "three", "four", "five",
112 "six", "seven", "eight", "nine");
113 assertEquals("one value given, and nine used.", result.toString());
114
115 try {
116 TextUtils.expandTemplate("^1 value given, and ^10 used.",
117 "one", "two", "three", "four", "five",
118 "six", "seven", "eight", "nine", "ten");
119 fail();
120 } catch (IllegalArgumentException e) {
121 }
122
123 // putting carets in the values: expansion is not recursive.
124
125 result = TextUtils.expandTemplate("^2", "foo", "^^");
126 assertEquals("^^", result.toString());
127
128 result = TextUtils.expandTemplate("^^2", "foo", "1");
129 assertEquals("^2", result.toString());
130
131 result = TextUtils.expandTemplate("^1", "value with ^2 in it", "foo");
132 assertEquals("value with ^2 in it", result.toString());
133 }
134
135 /** Fail unless text+spans contains a span 'spanName' with the given start and end. */
136 private void checkContains(Spanned text, String[] spans, String spanName,
137 int start, int end) throws Exception {
138 for (String i: spans) {
139 if (i.equals(spanName)) {
140 assertEquals(start, text.getSpanStart(i));
141 assertEquals(end, text.getSpanEnd(i));
142 return;
143 }
144 }
145 fail();
146 }
147
148 @SmallTest
149 public void testTemplateSpan() throws Exception {
150 SpannableString template;
151 Spanned result;
152 String[] spans;
153
154 // ordinary replacement
155
156 template = new SpannableString("a^1b");
157 template.setSpan("before", 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
158 template.setSpan("during", 1, 3, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
159 template.setSpan("after", 3, 4, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
160 template.setSpan("during+after", 1, 4, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
161
162 result = (Spanned) TextUtils.expandTemplate(template, "foo");
163 assertEquals(5, result.length());
164 spans = result.getSpans(0, result.length(), String.class);
165
166 // value is one character longer, so span endpoints should change.
167 assertEquals(4, spans.length);
168 checkContains(result, spans, "before", 0, 1);
169 checkContains(result, spans, "during", 1, 4);
170 checkContains(result, spans, "after", 4, 5);
171 checkContains(result, spans, "during+after", 1, 5);
172
173
174 // replacement with empty string
175
176 result = (Spanned) TextUtils.expandTemplate(template, "");
177 assertEquals(2, result.length());
178 spans = result.getSpans(0, result.length(), String.class);
179
180 // the "during" span should disappear.
181 assertEquals(3, spans.length);
182 checkContains(result, spans, "before", 0, 1);
183 checkContains(result, spans, "after", 1, 2);
184 checkContains(result, spans, "during+after", 1, 2);
185 }
186
187 @SmallTest
188 public void testStringSplitterSimple() {
189 stringSplitterTestHelper("a,b,cde", new String[] {"a", "b", "cde"});
190 }
191
192 @SmallTest
193 public void testStringSplitterEmpty() {
194 stringSplitterTestHelper("", new String[] {});
195 }
196
197 @SmallTest
198 public void testStringSplitterWithLeadingEmptyString() {
199 stringSplitterTestHelper(",a,b,cde", new String[] {"", "a", "b", "cde"});
200 }
201
202 @SmallTest
203 public void testStringSplitterWithInternalEmptyString() {
204 stringSplitterTestHelper("a,b,,cde", new String[] {"a", "b", "", "cde"});
205 }
206
207 @SmallTest
208 public void testStringSplitterWithTrailingEmptyString() {
209 // A single trailing emtpy string should be ignored.
210 stringSplitterTestHelper("a,b,cde,", new String[] {"a", "b", "cde"});
211 }
212
213 private void stringSplitterTestHelper(String string, String[] expectedStrings) {
214 TextUtils.StringSplitter splitter = new TextUtils.SimpleStringSplitter(',');
215 splitter.setString(string);
216 List<String> strings = Lists.newArrayList();
217 for (String s : splitter) {
218 strings.add(s);
219 }
220 MoreAsserts.assertEquals(expectedStrings, strings.toArray(new String[]{}));
221 }
222
223 @SmallTest
224 public void testTrim() {
225 String[] strings = { "abc", " abc", " abc", "abc ", "abc ",
226 " abc ", " abc ", "\nabc\n", "\nabc", "abc\n" };
227
228 for (String s : strings) {
229 assertEquals(s.trim().length(), TextUtils.getTrimmedLength(s));
230 }
231 }
232
The Android Open Source Projectee7e6a72010-06-03 09:03:58 -0700233 @SmallTest
234 public void testRfc822TokenizerFullAddress() {
235 Rfc822Token[] tokens = Rfc822Tokenizer.tokenize("Foo Bar (something) <foo@google.com>");
236 assertNotNull(tokens);
237 assertEquals(1, tokens.length);
238 assertEquals("foo@google.com", tokens[0].getAddress());
239 assertEquals("Foo Bar", tokens[0].getName());
240 assertEquals("something",tokens[0].getComment());
241 }
242
243 @SmallTest
244 public void testRfc822TokenizeItemWithError() {
245 Rfc822Token[] tokens = Rfc822Tokenizer.tokenize("\"Foo Bar\\");
246 assertNotNull(tokens);
247 assertEquals(1, tokens.length);
248 assertEquals("Foo Bar", tokens[0].getAddress());
249 }
250
Mattias Niklewski114f98a2011-01-18 14:27:23 +0100251 @SmallTest
252 public void testRfc822FindToken() {
253 Rfc822Tokenizer tokenizer = new Rfc822Tokenizer();
254 // 0 1 2 3 4
255 // 0 1234 56789012345678901234 5678 90123456789012345
256 String address = "\"Foo\" <foo@google.com>, \"Bar\" <bar@google.com>";
257 assertEquals(0, tokenizer.findTokenStart(address, 21));
258 assertEquals(22, tokenizer.findTokenEnd(address, 21));
259 assertEquals(24, tokenizer.findTokenStart(address, 25));
260 assertEquals(46, tokenizer.findTokenEnd(address, 25));
261 }
262
263 @SmallTest
264 public void testRfc822FindTokenWithError() {
265 assertEquals(9, new Rfc822Tokenizer().findTokenEnd("\"Foo Bar\\", 0));
266 }
267
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800268 @LargeTest
269 public void testEllipsize() {
270 CharSequence s1 = "The quick brown fox jumps over \u00FEhe lazy dog.";
271 CharSequence s2 = new Wrapper(s1);
272 Spannable s3 = new SpannableString(s1);
273 s3.setSpan(new StyleSpan(0), 5, 10, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
274 TextPaint p = new TextPaint();
Eric Fischer1f0dac32009-07-01 18:03:09 -0700275 p.setFlags(p.getFlags() & ~p.DEV_KERN_TEXT_FLAG);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800276
277 for (int i = 0; i < 100; i++) {
278 for (int j = 0; j < 3; j++) {
279 TextUtils.TruncateAt kind = null;
280
281 switch (j) {
282 case 0:
283 kind = TextUtils.TruncateAt.START;
284 break;
285
286 case 1:
287 kind = TextUtils.TruncateAt.END;
288 break;
289
290 case 2:
291 kind = TextUtils.TruncateAt.MIDDLE;
292 break;
293 }
294
295 String out1 = TextUtils.ellipsize(s1, p, i, kind).toString();
296 String out2 = TextUtils.ellipsize(s2, p, i, kind).toString();
297 String out3 = TextUtils.ellipsize(s3, p, i, kind).toString();
298
299 String keep1 = TextUtils.ellipsize(s1, p, i, kind, true, null).toString();
300 String keep2 = TextUtils.ellipsize(s2, p, i, kind, true, null).toString();
301 String keep3 = TextUtils.ellipsize(s3, p, i, kind, true, null).toString();
302
303 String trim1 = keep1.replace("\uFEFF", "");
304
305 // Are all normal output strings identical?
306 assertEquals("wid " + i + " pass " + j, out1, out2);
307 assertEquals("wid " + i + " pass " + j, out2, out3);
308
309 // Are preserved output strings identical?
310 assertEquals("wid " + i + " pass " + j, keep1, keep2);
311 assertEquals("wid " + i + " pass " + j, keep2, keep3);
312
313 // Does trimming padding from preserved yield normal?
314 assertEquals("wid " + i + " pass " + j, out1, trim1);
315
316 // Did preserved output strings preserve length?
317 assertEquals("wid " + i + " pass " + j, keep1.length(), s1.length());
318
319 // Does the output string actually fit in the space?
320 assertTrue("wid " + i + " pass " + j, p.measureText(out1) <= i);
321
322 // Is the padded output the same width as trimmed output?
323 assertTrue("wid " + i + " pass " + j, p.measureText(keep1) == p.measureText(out1));
324 }
325 }
326 }
327
Brad Fitzpatrick11fe1812010-09-10 16:07:52 -0700328 @SmallTest
329 public void testDelimitedStringContains() {
330 assertFalse(TextUtils.delimitedStringContains("", ',', null));
331 assertFalse(TextUtils.delimitedStringContains(null, ',', ""));
332 // Whole match
333 assertTrue(TextUtils.delimitedStringContains("gps", ',', "gps"));
334 // At beginning.
335 assertTrue(TextUtils.delimitedStringContains("gps,gpsx,network,mock", ',', "gps"));
336 assertTrue(TextUtils.delimitedStringContains("gps,network,mock", ',', "gps"));
337 // In middle, both without, before & after a false match.
338 assertTrue(TextUtils.delimitedStringContains("network,gps,mock", ',', "gps"));
339 assertTrue(TextUtils.delimitedStringContains("network,gps,gpsx,mock", ',', "gps"));
340 assertTrue(TextUtils.delimitedStringContains("network,gpsx,gps,mock", ',', "gps"));
341 // At the end.
342 assertTrue(TextUtils.delimitedStringContains("network,mock,gps", ',', "gps"));
343 assertTrue(TextUtils.delimitedStringContains("network,mock,gpsx,gps", ',', "gps"));
344 // Not present (but with a false match)
345 assertFalse(TextUtils.delimitedStringContains("network,mock,gpsx", ',', "gps"));
346 }
347
Martin Wallgrencee20512011-04-07 14:45:43 +0200348 @SmallTest
349 public void testCharSequenceCreator() {
350 Parcel p = Parcel.obtain();
351 TextUtils.writeToParcel(null, p, 0);
352 CharSequence text = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(p);
353 assertNull("null CharSequence should generate null from parcel", text);
354 p = Parcel.obtain();
355 TextUtils.writeToParcel("test", p, 0);
356 text = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(p);
357 assertEquals("conversion to/from parcel failed", "test", text);
358 }
359
360 @SmallTest
361 public void testCharSequenceCreatorNull() {
362 Parcel p;
363 CharSequence text;
364 p = Parcel.obtain();
365 TextUtils.writeToParcel(null, p, 0);
366 p.setDataPosition(0);
367 text = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(p);
368 assertNull("null CharSequence should generate null from parcel", text);
369 }
370
371 @SmallTest
372 public void testCharSequenceCreatorSpannable() {
373 Parcel p;
374 CharSequence text;
375 p = Parcel.obtain();
376 TextUtils.writeToParcel(new SpannableString("test"), p, 0);
377 p.setDataPosition(0);
378 text = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(p);
379 assertEquals("conversion to/from parcel failed", "test", text.toString());
380 }
381
382 @SmallTest
383 public void testCharSequenceCreatorString() {
384 Parcel p;
385 CharSequence text;
386 p = Parcel.obtain();
387 TextUtils.writeToParcel("test", p, 0);
388 p.setDataPosition(0);
389 text = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(p);
390 assertEquals("conversion to/from parcel failed", "test", text.toString());
391 }
392
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800393 /**
394 * CharSequence wrapper for testing the cases where text is copied into
395 * a char array instead of working from a String or a Spanned.
396 */
397 private static class Wrapper implements CharSequence {
398 private CharSequence mString;
399
400 public Wrapper(CharSequence s) {
401 mString = s;
402 }
403
404 public int length() {
405 return mString.length();
406 }
407
408 public char charAt(int off) {
409 return mString.charAt(off);
410 }
411
Gilles Debunne1e3ac182011-03-08 14:22:34 -0800412 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800413 public String toString() {
414 return mString.toString();
415 }
416
417 public CharSequence subSequence(int start, int end) {
418 return new Wrapper(mString.subSequence(start, end));
419 }
420 }
Gilles Debunne1e3ac182011-03-08 14:22:34 -0800421
422 @LargeTest
423 public void testRemoveEmptySpans() {
424 MockSpanned spanned = new MockSpanned();
425
426 spanned.test();
427 spanned.addSpan().test();
428 spanned.addSpan().test();
429 spanned.addSpan().test();
430 spanned.addEmptySpan().test();
431 spanned.addSpan().test();
432 spanned.addEmptySpan().test();
433 spanned.addEmptySpan().test();
434 spanned.addSpan().test();
435
436 spanned.clear();
437 spanned.addEmptySpan().test();
438 spanned.addEmptySpan().test();
439 spanned.addEmptySpan().test();
440 spanned.addSpan().test();
441 spanned.addEmptySpan().test();
442 spanned.addSpan().test();
443
444 spanned.clear();
445 spanned.addSpan().test();
446 spanned.addEmptySpan().test();
447 spanned.addSpan().test();
448 spanned.addEmptySpan().test();
449 spanned.addSpan().test();
450 spanned.addSpan().test();
451 }
452
453 protected static class MockSpanned implements Spanned {
454
455 private List<Object> allSpans = new ArrayList<Object>();
456 private List<Object> nonEmptySpans = new ArrayList<Object>();
457
458 public void clear() {
459 allSpans.clear();
460 nonEmptySpans.clear();
461 }
462
463 public MockSpanned addSpan() {
464 Object o = new Object();
465 allSpans.add(o);
466 nonEmptySpans.add(o);
467 return this;
468 }
469
470 public MockSpanned addEmptySpan() {
471 Object o = new Object();
472 allSpans.add(o);
473 return this;
474 }
475
476 public void test() {
477 Object[] nonEmpty = TextUtils.removeEmptySpans(allSpans.toArray(), this, Object.class);
478 assertEquals("Mismatched array size", nonEmptySpans.size(), nonEmpty.length);
479 for (int i=0; i<nonEmpty.length; i++) {
480 assertEquals("Span differ", nonEmptySpans.get(i), nonEmpty[i]);
481 }
482 }
483
484 public char charAt(int arg0) {
485 return 0;
486 }
487
488 public int length() {
489 return 0;
490 }
491
492 public CharSequence subSequence(int arg0, int arg1) {
493 return null;
494 }
495
496 @Override
497 public <T> T[] getSpans(int start, int end, Class<T> type) {
498 return null;
499 }
500
501 @Override
502 public int getSpanStart(Object tag) {
503 return 0;
504 }
505
506 @Override
507 public int getSpanEnd(Object tag) {
508 return nonEmptySpans.contains(tag) ? 1 : 0;
509 }
510
511 @Override
512 public int getSpanFlags(Object tag) {
513 return 0;
514 }
515
516 @Override
517 public int nextSpanTransition(int start, int limit, Class type) {
518 return 0;
519 }
520 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800521}