blob: 79619d9a49dbad0d588bfdaba809090ce9f9ae3f [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
Andrei Stingaceanue1a7d0d2017-04-24 16:53:17 +010019import static org.junit.Assert.assertEquals;
20import static org.junit.Assert.assertFalse;
21import static org.junit.Assert.assertNotNull;
22import static org.junit.Assert.assertNull;
Roozbeh Pournader205a9932017-06-08 00:23:42 -070023import static org.junit.Assert.assertSame;
Andrei Stingaceanue1a7d0d2017-04-24 16:53:17 +010024import static org.junit.Assert.assertTrue;
25import static org.junit.Assert.fail;
26
Martin Wallgrencee20512011-04-07 14:45:43 +020027import android.os.Parcel;
Siyamed Sinir68089c82016-06-29 16:55:35 -070028import android.support.test.filters.LargeTest;
29import android.support.test.filters.SmallTest;
Roozbeh Pournader205a9932017-06-08 00:23:42 -070030import android.support.test.runner.AndroidJUnit4;
Siyamed Sinir68089c82016-06-29 16:55:35 -070031import android.test.MoreAsserts;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080032import android.text.style.StyleSpan;
The Android Open Source Projectee7e6a72010-06-03 09:03:58 -070033import android.text.util.Rfc822Token;
34import android.text.util.Rfc822Tokenizer;
Roozbeh Pournader463b4822015-08-06 16:04:45 -070035import android.view.View;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080036
Roozbeh Pournader205a9932017-06-08 00:23:42 -070037import com.google.android.collect.Lists;
38
39import org.junit.Test;
40import org.junit.runner.RunWith;
41
Gilles Debunne1e3ac182011-03-08 14:22:34 -080042import java.util.ArrayList;
43import java.util.List;
Roozbeh Pournader463b4822015-08-06 16:04:45 -070044import java.util.Locale;
Paul Westbrook7762d932009-12-11 14:13:48 -080045
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080046/**
47 * TextUtilsTest tests {@link TextUtils}.
48 */
Andrei Stingaceanue1a7d0d2017-04-24 16:53:17 +010049@SmallTest
50@RunWith(AndroidJUnit4.class)
51public class TextUtilsTest {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080052
Andrei Stingaceanue1a7d0d2017-04-24 16:53:17 +010053 @Test
54 public void testBasic() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080055 assertEquals("", TextUtils.concat());
56 assertEquals("foo", TextUtils.concat("foo"));
57 assertEquals("foobar", TextUtils.concat("foo", "bar"));
58 assertEquals("foobarbaz", TextUtils.concat("foo", "bar", "baz"));
59
60 SpannableString foo = new SpannableString("foo");
61 foo.setSpan("foo", 1, 2, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
62
63 SpannableString bar = new SpannableString("bar");
64 bar.setSpan("bar", 1, 2, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
65
66 SpannableString baz = new SpannableString("baz");
67 baz.setSpan("baz", 1, 2, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
68
69 assertEquals("foo", TextUtils.concat(foo).toString());
70 assertEquals("foobar", TextUtils.concat(foo, bar).toString());
71 assertEquals("foobarbaz", TextUtils.concat(foo, bar, baz).toString());
72
73 assertEquals(1, ((Spanned) TextUtils.concat(foo)).getSpanStart("foo"));
74
75 assertEquals(1, ((Spanned) TextUtils.concat(foo, bar)).getSpanStart("foo"));
76 assertEquals(4, ((Spanned) TextUtils.concat(foo, bar)).getSpanStart("bar"));
77
78 assertEquals(1, ((Spanned) TextUtils.concat(foo, bar, baz)).getSpanStart("foo"));
79 assertEquals(4, ((Spanned) TextUtils.concat(foo, bar, baz)).getSpanStart("bar"));
80 assertEquals(7, ((Spanned) TextUtils.concat(foo, bar, baz)).getSpanStart("baz"));
81
82 assertTrue(TextUtils.concat("foo", "bar") instanceof String);
83 assertTrue(TextUtils.concat(foo, bar) instanceof SpannedString);
84 }
85
Andrei Stingaceanue1a7d0d2017-04-24 16:53:17 +010086 @Test
87 public void testTemplateString() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080088 CharSequence result;
89
90 result = TextUtils.expandTemplate("This is a ^1 of the ^2 broadcast ^3.",
91 "test", "emergency", "system");
92 assertEquals("This is a test of the emergency broadcast system.",
93 result.toString());
94
95 result = TextUtils.expandTemplate("^^^1^^^2^3^a^1^^b^^^c",
96 "one", "two", "three");
97 assertEquals("^one^twothree^aone^b^^c",
98 result.toString());
99
100 result = TextUtils.expandTemplate("^");
101 assertEquals("^", result.toString());
102
103 result = TextUtils.expandTemplate("^^");
104 assertEquals("^", result.toString());
105
106 result = TextUtils.expandTemplate("^^^");
107 assertEquals("^^", result.toString());
108
109 result = TextUtils.expandTemplate("shorter ^1 values ^2.", "a", "");
110 assertEquals("shorter a values .", result.toString());
111
112 try {
113 TextUtils.expandTemplate("Only ^1 value given, but ^2 used.", "foo");
114 fail();
115 } catch (IllegalArgumentException e) {
116 }
117
118 try {
119 TextUtils.expandTemplate("^1 value given, and ^0 used.", "foo");
120 fail();
121 } catch (IllegalArgumentException e) {
122 }
123
124 result = TextUtils.expandTemplate("^1 value given, and ^9 used.",
125 "one", "two", "three", "four", "five",
126 "six", "seven", "eight", "nine");
127 assertEquals("one value given, and nine used.", result.toString());
128
129 try {
130 TextUtils.expandTemplate("^1 value given, and ^10 used.",
131 "one", "two", "three", "four", "five",
132 "six", "seven", "eight", "nine", "ten");
133 fail();
134 } catch (IllegalArgumentException e) {
135 }
136
137 // putting carets in the values: expansion is not recursive.
138
139 result = TextUtils.expandTemplate("^2", "foo", "^^");
140 assertEquals("^^", result.toString());
141
142 result = TextUtils.expandTemplate("^^2", "foo", "1");
143 assertEquals("^2", result.toString());
144
145 result = TextUtils.expandTemplate("^1", "value with ^2 in it", "foo");
146 assertEquals("value with ^2 in it", result.toString());
147 }
148
149 /** Fail unless text+spans contains a span 'spanName' with the given start and end. */
150 private void checkContains(Spanned text, String[] spans, String spanName,
Andrei Stingaceanue1a7d0d2017-04-24 16:53:17 +0100151 int start, int end) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800152 for (String i: spans) {
153 if (i.equals(spanName)) {
154 assertEquals(start, text.getSpanStart(i));
155 assertEquals(end, text.getSpanEnd(i));
156 return;
157 }
158 }
159 fail();
160 }
161
Andrei Stingaceanue1a7d0d2017-04-24 16:53:17 +0100162 @Test
163 public void testTemplateSpan() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800164 SpannableString template;
165 Spanned result;
166 String[] spans;
167
168 // ordinary replacement
169
170 template = new SpannableString("a^1b");
171 template.setSpan("before", 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
172 template.setSpan("during", 1, 3, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
173 template.setSpan("after", 3, 4, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
174 template.setSpan("during+after", 1, 4, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
175
176 result = (Spanned) TextUtils.expandTemplate(template, "foo");
177 assertEquals(5, result.length());
178 spans = result.getSpans(0, result.length(), String.class);
179
180 // value is one character longer, so span endpoints should change.
181 assertEquals(4, spans.length);
182 checkContains(result, spans, "before", 0, 1);
183 checkContains(result, spans, "during", 1, 4);
184 checkContains(result, spans, "after", 4, 5);
185 checkContains(result, spans, "during+after", 1, 5);
186
187
188 // replacement with empty string
189
190 result = (Spanned) TextUtils.expandTemplate(template, "");
191 assertEquals(2, result.length());
192 spans = result.getSpans(0, result.length(), String.class);
193
194 // the "during" span should disappear.
195 assertEquals(3, spans.length);
196 checkContains(result, spans, "before", 0, 1);
197 checkContains(result, spans, "after", 1, 2);
198 checkContains(result, spans, "during+after", 1, 2);
199 }
200
Andrei Stingaceanue1a7d0d2017-04-24 16:53:17 +0100201 @Test
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800202 public void testStringSplitterSimple() {
203 stringSplitterTestHelper("a,b,cde", new String[] {"a", "b", "cde"});
204 }
205
Andrei Stingaceanue1a7d0d2017-04-24 16:53:17 +0100206 @Test
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800207 public void testStringSplitterEmpty() {
208 stringSplitterTestHelper("", new String[] {});
209 }
210
Andrei Stingaceanue1a7d0d2017-04-24 16:53:17 +0100211 @Test
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800212 public void testStringSplitterWithLeadingEmptyString() {
213 stringSplitterTestHelper(",a,b,cde", new String[] {"", "a", "b", "cde"});
214 }
215
Andrei Stingaceanue1a7d0d2017-04-24 16:53:17 +0100216 @Test
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800217 public void testStringSplitterWithInternalEmptyString() {
218 stringSplitterTestHelper("a,b,,cde", new String[] {"a", "b", "", "cde"});
219 }
220
Andrei Stingaceanue1a7d0d2017-04-24 16:53:17 +0100221 @Test
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800222 public void testStringSplitterWithTrailingEmptyString() {
223 // A single trailing emtpy string should be ignored.
224 stringSplitterTestHelper("a,b,cde,", new String[] {"a", "b", "cde"});
225 }
226
227 private void stringSplitterTestHelper(String string, String[] expectedStrings) {
228 TextUtils.StringSplitter splitter = new TextUtils.SimpleStringSplitter(',');
229 splitter.setString(string);
230 List<String> strings = Lists.newArrayList();
231 for (String s : splitter) {
232 strings.add(s);
233 }
234 MoreAsserts.assertEquals(expectedStrings, strings.toArray(new String[]{}));
235 }
236
Andrei Stingaceanue1a7d0d2017-04-24 16:53:17 +0100237 @Test
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800238 public void testTrim() {
239 String[] strings = { "abc", " abc", " abc", "abc ", "abc ",
240 " abc ", " abc ", "\nabc\n", "\nabc", "abc\n" };
241
242 for (String s : strings) {
243 assertEquals(s.trim().length(), TextUtils.getTrimmedLength(s));
244 }
245 }
246
Andrei Stingaceanue1a7d0d2017-04-24 16:53:17 +0100247 @Test
The Android Open Source Projectee7e6a72010-06-03 09:03:58 -0700248 public void testRfc822TokenizerFullAddress() {
249 Rfc822Token[] tokens = Rfc822Tokenizer.tokenize("Foo Bar (something) <foo@google.com>");
250 assertNotNull(tokens);
251 assertEquals(1, tokens.length);
252 assertEquals("foo@google.com", tokens[0].getAddress());
253 assertEquals("Foo Bar", tokens[0].getName());
254 assertEquals("something",tokens[0].getComment());
255 }
256
Andrei Stingaceanue1a7d0d2017-04-24 16:53:17 +0100257 @Test
The Android Open Source Projectee7e6a72010-06-03 09:03:58 -0700258 public void testRfc822TokenizeItemWithError() {
259 Rfc822Token[] tokens = Rfc822Tokenizer.tokenize("\"Foo Bar\\");
260 assertNotNull(tokens);
261 assertEquals(1, tokens.length);
262 assertEquals("Foo Bar", tokens[0].getAddress());
263 }
264
Andrei Stingaceanue1a7d0d2017-04-24 16:53:17 +0100265 @Test
Mattias Niklewski114f98a2011-01-18 14:27:23 +0100266 public void testRfc822FindToken() {
267 Rfc822Tokenizer tokenizer = new Rfc822Tokenizer();
268 // 0 1 2 3 4
269 // 0 1234 56789012345678901234 5678 90123456789012345
270 String address = "\"Foo\" <foo@google.com>, \"Bar\" <bar@google.com>";
271 assertEquals(0, tokenizer.findTokenStart(address, 21));
272 assertEquals(22, tokenizer.findTokenEnd(address, 21));
273 assertEquals(24, tokenizer.findTokenStart(address, 25));
274 assertEquals(46, tokenizer.findTokenEnd(address, 25));
275 }
276
Andrei Stingaceanue1a7d0d2017-04-24 16:53:17 +0100277 @Test
Mattias Niklewski114f98a2011-01-18 14:27:23 +0100278 public void testRfc822FindTokenWithError() {
279 assertEquals(9, new Rfc822Tokenizer().findTokenEnd("\"Foo Bar\\", 0));
280 }
281
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800282 @LargeTest
Andrei Stingaceanue1a7d0d2017-04-24 16:53:17 +0100283 @Test
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800284 public void testEllipsize() {
285 CharSequence s1 = "The quick brown fox jumps over \u00FEhe lazy dog.";
286 CharSequence s2 = new Wrapper(s1);
287 Spannable s3 = new SpannableString(s1);
288 s3.setSpan(new StyleSpan(0), 5, 10, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
289 TextPaint p = new TextPaint();
Eric Fischer1f0dac32009-07-01 18:03:09 -0700290 p.setFlags(p.getFlags() & ~p.DEV_KERN_TEXT_FLAG);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800291
292 for (int i = 0; i < 100; i++) {
293 for (int j = 0; j < 3; j++) {
294 TextUtils.TruncateAt kind = null;
295
296 switch (j) {
297 case 0:
298 kind = TextUtils.TruncateAt.START;
299 break;
300
301 case 1:
302 kind = TextUtils.TruncateAt.END;
303 break;
304
305 case 2:
306 kind = TextUtils.TruncateAt.MIDDLE;
307 break;
308 }
309
310 String out1 = TextUtils.ellipsize(s1, p, i, kind).toString();
311 String out2 = TextUtils.ellipsize(s2, p, i, kind).toString();
312 String out3 = TextUtils.ellipsize(s3, p, i, kind).toString();
313
314 String keep1 = TextUtils.ellipsize(s1, p, i, kind, true, null).toString();
315 String keep2 = TextUtils.ellipsize(s2, p, i, kind, true, null).toString();
316 String keep3 = TextUtils.ellipsize(s3, p, i, kind, true, null).toString();
317
318 String trim1 = keep1.replace("\uFEFF", "");
319
320 // Are all normal output strings identical?
321 assertEquals("wid " + i + " pass " + j, out1, out2);
322 assertEquals("wid " + i + " pass " + j, out2, out3);
323
324 // Are preserved output strings identical?
325 assertEquals("wid " + i + " pass " + j, keep1, keep2);
326 assertEquals("wid " + i + " pass " + j, keep2, keep3);
327
328 // Does trimming padding from preserved yield normal?
329 assertEquals("wid " + i + " pass " + j, out1, trim1);
330
331 // Did preserved output strings preserve length?
332 assertEquals("wid " + i + " pass " + j, keep1.length(), s1.length());
333
334 // Does the output string actually fit in the space?
335 assertTrue("wid " + i + " pass " + j, p.measureText(out1) <= i);
336
337 // Is the padded output the same width as trimmed output?
338 assertTrue("wid " + i + " pass " + j, p.measureText(keep1) == p.measureText(out1));
339 }
340 }
341 }
342
Andrei Stingaceanue1a7d0d2017-04-24 16:53:17 +0100343 @Test
Roozbeh Pournader9ea756f2017-07-25 11:20:29 -0700344 public void testEllipsize_multiCodepoint() {
345 final TextPaint paint = new TextPaint();
346 final float wordWidth = paint.measureText("MMMM");
347
348 // Establish the ground rules first, for single-codepoint cases.
349 final String ellipsis = "."; // one full stop character
350 assertEquals(
351 "MM.\uFEFF",
352 TextUtils.ellipsize("MMMM", paint, 0.7f * wordWidth,
353 TextUtils.TruncateAt.END, true /* preserve length */,
354 null /* no callback */, TextDirectionHeuristics.LTR,
355 ellipsis));
356 assertEquals(
357 "MM.",
358 TextUtils.ellipsize("MMMM", paint, 0.7f * wordWidth,
359 TextUtils.TruncateAt.END, false /* preserve length */,
360 null /* no callback */, TextDirectionHeuristics.LTR,
361 ellipsis));
362 assertEquals(
363 "M.",
364 TextUtils.ellipsize("MM", paint, 0.45f * wordWidth,
365 TextUtils.TruncateAt.END, true /* preserve length */,
366 null /* no callback */, TextDirectionHeuristics.LTR,
367 ellipsis));
368 assertEquals(
369 "M.",
370 TextUtils.ellipsize("MM", paint, 0.45f * wordWidth,
371 TextUtils.TruncateAt.END, false /* preserve length */,
372 null /* no callback */, TextDirectionHeuristics.LTR,
373 ellipsis));
374
375 // Now check the differences for multi-codepoint ellipsis.
376 final String longEllipsis = ".."; // two full stop characters
377 assertEquals(
378 "MM..",
379 TextUtils.ellipsize("MMMM", paint, 0.7f * wordWidth,
380 TextUtils.TruncateAt.END, true /* preserve length */,
381 null /* no callback */, TextDirectionHeuristics.LTR,
382 longEllipsis));
383 assertEquals(
384 "MM..",
385 TextUtils.ellipsize("MMMM", paint, 0.7f * wordWidth,
386 TextUtils.TruncateAt.END, false /* preserve length */,
387 null /* no callback */, TextDirectionHeuristics.LTR,
388 longEllipsis));
389 assertEquals(
390 "M\uFEFF",
391 TextUtils.ellipsize("MM", paint, 0.45f * wordWidth,
392 TextUtils.TruncateAt.END, true /* preserve length */,
393 null /* no callback */, TextDirectionHeuristics.LTR,
394 longEllipsis));
395 assertEquals(
396 "M..",
397 TextUtils.ellipsize("MM", paint, 0.45f * wordWidth,
398 TextUtils.TruncateAt.END, false /* preserve length */,
399 null /* no callback */, TextDirectionHeuristics.LTR,
400 longEllipsis));
401 }
402
403 @Test
Brad Fitzpatrick11fe1812010-09-10 16:07:52 -0700404 public void testDelimitedStringContains() {
405 assertFalse(TextUtils.delimitedStringContains("", ',', null));
406 assertFalse(TextUtils.delimitedStringContains(null, ',', ""));
407 // Whole match
408 assertTrue(TextUtils.delimitedStringContains("gps", ',', "gps"));
409 // At beginning.
410 assertTrue(TextUtils.delimitedStringContains("gps,gpsx,network,mock", ',', "gps"));
411 assertTrue(TextUtils.delimitedStringContains("gps,network,mock", ',', "gps"));
412 // In middle, both without, before & after a false match.
413 assertTrue(TextUtils.delimitedStringContains("network,gps,mock", ',', "gps"));
414 assertTrue(TextUtils.delimitedStringContains("network,gps,gpsx,mock", ',', "gps"));
415 assertTrue(TextUtils.delimitedStringContains("network,gpsx,gps,mock", ',', "gps"));
416 // At the end.
417 assertTrue(TextUtils.delimitedStringContains("network,mock,gps", ',', "gps"));
418 assertTrue(TextUtils.delimitedStringContains("network,mock,gpsx,gps", ',', "gps"));
419 // Not present (but with a false match)
420 assertFalse(TextUtils.delimitedStringContains("network,mock,gpsx", ',', "gps"));
421 }
422
Andrei Stingaceanue1a7d0d2017-04-24 16:53:17 +0100423 @Test
Martin Wallgrencee20512011-04-07 14:45:43 +0200424 public void testCharSequenceCreator() {
425 Parcel p = Parcel.obtain();
Roozbeh Pournaderc38d3902017-07-06 17:07:39 -0700426 CharSequence text;
427 try {
428 TextUtils.writeToParcel(null, p, 0);
429 text = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(p);
430 assertNull("null CharSequence should generate null from parcel", text);
431 } finally {
432 p.recycle();
433 }
Martin Wallgrencee20512011-04-07 14:45:43 +0200434 p = Parcel.obtain();
Roozbeh Pournaderc38d3902017-07-06 17:07:39 -0700435 try {
436 TextUtils.writeToParcel("test", p, 0);
437 p.setDataPosition(0);
438 text = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(p);
439 assertEquals("conversion to/from parcel failed", "test", text);
440 } finally {
441 p.recycle();
442 }
Martin Wallgrencee20512011-04-07 14:45:43 +0200443 }
444
Andrei Stingaceanue1a7d0d2017-04-24 16:53:17 +0100445 @Test
Martin Wallgrencee20512011-04-07 14:45:43 +0200446 public void testCharSequenceCreatorNull() {
447 Parcel p;
448 CharSequence text;
449 p = Parcel.obtain();
Roozbeh Pournaderc38d3902017-07-06 17:07:39 -0700450 try {
451 TextUtils.writeToParcel(null, p, 0);
452 p.setDataPosition(0);
453 text = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(p);
454 assertNull("null CharSequence should generate null from parcel", text);
455 } finally {
456 p.recycle();
457 }
Martin Wallgrencee20512011-04-07 14:45:43 +0200458 }
459
Andrei Stingaceanue1a7d0d2017-04-24 16:53:17 +0100460 @Test
Martin Wallgrencee20512011-04-07 14:45:43 +0200461 public void testCharSequenceCreatorSpannable() {
462 Parcel p;
463 CharSequence text;
464 p = Parcel.obtain();
Roozbeh Pournaderc38d3902017-07-06 17:07:39 -0700465 try {
466 TextUtils.writeToParcel(new SpannableString("test"), p, 0);
467 p.setDataPosition(0);
468 text = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(p);
469 assertEquals("conversion to/from parcel failed", "test", text.toString());
470 } finally {
471 p.recycle();
472 }
Martin Wallgrencee20512011-04-07 14:45:43 +0200473 }
474
Andrei Stingaceanue1a7d0d2017-04-24 16:53:17 +0100475 @Test
Martin Wallgrencee20512011-04-07 14:45:43 +0200476 public void testCharSequenceCreatorString() {
477 Parcel p;
478 CharSequence text;
479 p = Parcel.obtain();
Roozbeh Pournaderc38d3902017-07-06 17:07:39 -0700480 try {
481 TextUtils.writeToParcel("test", p, 0);
482 p.setDataPosition(0);
483 text = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(p);
484 assertEquals("conversion to/from parcel failed", "test", text.toString());
485 } finally {
486 p.recycle();
487 }
Martin Wallgrencee20512011-04-07 14:45:43 +0200488 }
489
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800490 /**
491 * CharSequence wrapper for testing the cases where text is copied into
492 * a char array instead of working from a String or a Spanned.
493 */
494 private static class Wrapper implements CharSequence {
495 private CharSequence mString;
496
497 public Wrapper(CharSequence s) {
498 mString = s;
499 }
500
Andrei Stingaceanue1a7d0d2017-04-24 16:53:17 +0100501 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800502 public int length() {
503 return mString.length();
504 }
505
Andrei Stingaceanue1a7d0d2017-04-24 16:53:17 +0100506 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800507 public char charAt(int off) {
508 return mString.charAt(off);
509 }
510
Gilles Debunne1e3ac182011-03-08 14:22:34 -0800511 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800512 public String toString() {
513 return mString.toString();
514 }
515
Andrei Stingaceanue1a7d0d2017-04-24 16:53:17 +0100516 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800517 public CharSequence subSequence(int start, int end) {
518 return new Wrapper(mString.subSequence(start, end));
519 }
520 }
Gilles Debunne1e3ac182011-03-08 14:22:34 -0800521
Andrei Stingaceanue1a7d0d2017-04-24 16:53:17 +0100522 @Test
Gilles Debunne1e3ac182011-03-08 14:22:34 -0800523 public void testRemoveEmptySpans() {
524 MockSpanned spanned = new MockSpanned();
525
526 spanned.test();
527 spanned.addSpan().test();
528 spanned.addSpan().test();
529 spanned.addSpan().test();
530 spanned.addEmptySpan().test();
531 spanned.addSpan().test();
532 spanned.addEmptySpan().test();
533 spanned.addEmptySpan().test();
534 spanned.addSpan().test();
535
536 spanned.clear();
537 spanned.addEmptySpan().test();
538 spanned.addEmptySpan().test();
539 spanned.addEmptySpan().test();
540 spanned.addSpan().test();
541 spanned.addEmptySpan().test();
542 spanned.addSpan().test();
543
544 spanned.clear();
545 spanned.addSpan().test();
546 spanned.addEmptySpan().test();
547 spanned.addSpan().test();
548 spanned.addEmptySpan().test();
549 spanned.addSpan().test();
550 spanned.addSpan().test();
551 }
552
553 protected static class MockSpanned implements Spanned {
554
555 private List<Object> allSpans = new ArrayList<Object>();
556 private List<Object> nonEmptySpans = new ArrayList<Object>();
557
558 public void clear() {
559 allSpans.clear();
560 nonEmptySpans.clear();
561 }
562
563 public MockSpanned addSpan() {
564 Object o = new Object();
565 allSpans.add(o);
566 nonEmptySpans.add(o);
567 return this;
568 }
569
570 public MockSpanned addEmptySpan() {
571 Object o = new Object();
572 allSpans.add(o);
573 return this;
574 }
575
576 public void test() {
577 Object[] nonEmpty = TextUtils.removeEmptySpans(allSpans.toArray(), this, Object.class);
578 assertEquals("Mismatched array size", nonEmptySpans.size(), nonEmpty.length);
579 for (int i=0; i<nonEmpty.length; i++) {
580 assertEquals("Span differ", nonEmptySpans.get(i), nonEmpty[i]);
581 }
582 }
583
Andrei Stingaceanue1a7d0d2017-04-24 16:53:17 +0100584 @Override
Gilles Debunne1e3ac182011-03-08 14:22:34 -0800585 public char charAt(int arg0) {
586 return 0;
587 }
588
Andrei Stingaceanue1a7d0d2017-04-24 16:53:17 +0100589 @Override
Gilles Debunne1e3ac182011-03-08 14:22:34 -0800590 public int length() {
591 return 0;
592 }
593
Andrei Stingaceanue1a7d0d2017-04-24 16:53:17 +0100594 @Override
Gilles Debunne1e3ac182011-03-08 14:22:34 -0800595 public CharSequence subSequence(int arg0, int arg1) {
596 return null;
597 }
598
599 @Override
600 public <T> T[] getSpans(int start, int end, Class<T> type) {
601 return null;
602 }
603
604 @Override
605 public int getSpanStart(Object tag) {
606 return 0;
607 }
608
609 @Override
610 public int getSpanEnd(Object tag) {
611 return nonEmptySpans.contains(tag) ? 1 : 0;
612 }
613
614 @Override
615 public int getSpanFlags(Object tag) {
616 return 0;
617 }
618
619 @Override
620 public int nextSpanTransition(int start, int limit, Class type) {
621 return 0;
622 }
623 }
Roozbeh Pournader463b4822015-08-06 16:04:45 -0700624
Andrei Stingaceanue1a7d0d2017-04-24 16:53:17 +0100625 @Test
Roozbeh Pournader463b4822015-08-06 16:04:45 -0700626 public void testGetLayoutDirectionFromLocale() {
627 assertEquals(View.LAYOUT_DIRECTION_LTR, TextUtils.getLayoutDirectionFromLocale(null));
628 assertEquals(View.LAYOUT_DIRECTION_LTR,
629 TextUtils.getLayoutDirectionFromLocale(Locale.ROOT));
630 assertEquals(View.LAYOUT_DIRECTION_LTR,
631 TextUtils.getLayoutDirectionFromLocale(Locale.forLanguageTag("en")));
632 assertEquals(View.LAYOUT_DIRECTION_LTR,
633 TextUtils.getLayoutDirectionFromLocale(Locale.forLanguageTag("en-US")));
634 assertEquals(View.LAYOUT_DIRECTION_LTR,
635 TextUtils.getLayoutDirectionFromLocale(Locale.forLanguageTag("az")));
636 assertEquals(View.LAYOUT_DIRECTION_LTR,
637 TextUtils.getLayoutDirectionFromLocale(Locale.forLanguageTag("az-AZ")));
638 assertEquals(View.LAYOUT_DIRECTION_LTR,
639 TextUtils.getLayoutDirectionFromLocale(Locale.forLanguageTag("az-Latn")));
640 assertEquals(View.LAYOUT_DIRECTION_LTR,
641 TextUtils.getLayoutDirectionFromLocale(Locale.forLanguageTag("en-EG")));
642 assertEquals(View.LAYOUT_DIRECTION_LTR,
643 TextUtils.getLayoutDirectionFromLocale(Locale.forLanguageTag("ar-Latn")));
644
645 assertEquals(View.LAYOUT_DIRECTION_RTL,
646 TextUtils.getLayoutDirectionFromLocale(Locale.forLanguageTag("ar")));
647 assertEquals(View.LAYOUT_DIRECTION_RTL,
648 TextUtils.getLayoutDirectionFromLocale(Locale.forLanguageTag("fa")));
649 assertEquals(View.LAYOUT_DIRECTION_RTL,
650 TextUtils.getLayoutDirectionFromLocale(Locale.forLanguageTag("he")));
651 assertEquals(View.LAYOUT_DIRECTION_RTL,
652 TextUtils.getLayoutDirectionFromLocale(Locale.forLanguageTag("iw")));
653 assertEquals(View.LAYOUT_DIRECTION_RTL,
654 TextUtils.getLayoutDirectionFromLocale(Locale.forLanguageTag("ur")));
655 assertEquals(View.LAYOUT_DIRECTION_RTL,
656 TextUtils.getLayoutDirectionFromLocale(Locale.forLanguageTag("dv")));
657 assertEquals(View.LAYOUT_DIRECTION_RTL,
658 TextUtils.getLayoutDirectionFromLocale(Locale.forLanguageTag("az-Arab")));
659 assertEquals(View.LAYOUT_DIRECTION_RTL,
660 TextUtils.getLayoutDirectionFromLocale(Locale.forLanguageTag("az-IR")));
661 assertEquals(View.LAYOUT_DIRECTION_RTL,
662 TextUtils.getLayoutDirectionFromLocale(Locale.forLanguageTag("fa-US")));
663 assertEquals(View.LAYOUT_DIRECTION_RTL,
664 TextUtils.getLayoutDirectionFromLocale(Locale.forLanguageTag("tr-Arab")));
665 }
Roozbeh Pournader205a9932017-06-08 00:23:42 -0700666
667 @Test
668 public void testToUpperCase() {
669 {
670 final CharSequence result = TextUtils.toUpperCase(null, "abc", false);
671 assertEquals(StringBuilder.class, result.getClass());
672 assertEquals("ABC", result.toString());
673 }
674 {
675 final SpannableString str = new SpannableString("abc");
676 Object span = new Object();
677 str.setSpan(span, 1, 2, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
678
679 final CharSequence result = TextUtils.toUpperCase(null, str, true /* copySpans */);
680 assertEquals(SpannableStringBuilder.class, result.getClass());
681 assertEquals("ABC", result.toString());
682 final Spanned spanned = (Spanned) result;
683 final Object[] resultSpans = spanned.getSpans(0, result.length(), Object.class);
684 assertEquals(1, resultSpans.length);
685 assertSame(span, resultSpans[0]);
686 assertEquals(1, spanned.getSpanStart(span));
687 assertEquals(2, spanned.getSpanEnd(span));
688 assertEquals(Spanned.SPAN_INCLUSIVE_INCLUSIVE, spanned.getSpanFlags(span));
689 }
690 {
691 final Locale turkish = new Locale("tr", "TR");
692 final CharSequence result = TextUtils.toUpperCase(turkish, "i", false);
693 assertEquals(StringBuilder.class, result.getClass());
694 assertEquals("İ", result.toString());
695 }
696 {
697 final String str = "ABC";
698 assertSame(str, TextUtils.toUpperCase(null, str, false));
699 }
700 {
701 final SpannableString str = new SpannableString("ABC");
702 str.setSpan(new Object(), 1, 2, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
703 assertSame(str, TextUtils.toUpperCase(null, str, true /* copySpans */));
704 }
705 }
706
707 // Copied from cts/tests/tests/widget/src/android/widget/cts/TextViewTest.java and modified
708 // for the TextUtils.toUpperCase method.
709 @Test
710 public void testToUpperCase_SpansArePreserved() {
711 final Locale greek = new Locale("el", "GR");
712 final String lowerString = "ι\u0301ριδα"; // ίριδα with first letter decomposed
713 final String upperString = "ΙΡΙΔΑ"; // uppercased
714 // expected lowercase to uppercase index map
715 final int[] indexMap = {0, 1, 1, 2, 3, 4, 5};
716 final int flags = Spanned.SPAN_INCLUSIVE_INCLUSIVE;
717
718 final Spannable source = new SpannableString(lowerString);
719 source.setSpan(new Object(), 0, 1, flags);
720 source.setSpan(new Object(), 1, 2, flags);
721 source.setSpan(new Object(), 2, 3, flags);
722 source.setSpan(new Object(), 3, 4, flags);
723 source.setSpan(new Object(), 4, 5, flags);
724 source.setSpan(new Object(), 5, 6, flags);
725 source.setSpan(new Object(), 0, 2, flags);
726 source.setSpan(new Object(), 1, 3, flags);
727 source.setSpan(new Object(), 2, 4, flags);
728 source.setSpan(new Object(), 0, 6, flags);
729 final Object[] sourceSpans = source.getSpans(0, source.length(), Object.class);
730
731 final CharSequence uppercase = TextUtils.toUpperCase(greek, source, true /* copySpans */);
732 assertEquals(SpannableStringBuilder.class, uppercase.getClass());
733 final Spanned result = (Spanned) uppercase;
734
735 assertEquals(upperString, result.toString());
736 final Object[] resultSpans = result.getSpans(0, result.length(), Object.class);
737 assertEquals(sourceSpans.length, resultSpans.length);
738 for (int i = 0; i < sourceSpans.length; i++) {
739 assertSame(sourceSpans[i], resultSpans[i]);
740 final Object span = sourceSpans[i];
741 assertEquals(indexMap[source.getSpanStart(span)], result.getSpanStart(span));
742 assertEquals(indexMap[source.getSpanEnd(span)], result.getSpanEnd(span));
743 assertEquals(source.getSpanFlags(span), result.getSpanFlags(span));
744 }
745 }
Siyamed Sinirce3b05a2017-07-18 18:54:31 -0700746
747 @Test
748 public void testTrimToSize() {
749 final String testString = "a\uD800\uDC00a";
750 assertEquals("Should return text as it is if size is longer than length",
751 testString, TextUtils.trimToSize(testString, 5));
752 assertEquals("Should return text as it is if size is equal to length",
753 testString, TextUtils.trimToSize(testString, 4));
754 assertEquals("Should trim text",
755 "a\uD800\uDC00", TextUtils.trimToSize(testString, 3));
756 assertEquals("Should trim surrogate pairs if size is in the middle of a pair",
757 "a", TextUtils.trimToSize(testString, 2));
758 assertEquals("Should trim text",
759 "a", TextUtils.trimToSize(testString, 1));
760 assertEquals("Should handle null",
761 null, TextUtils.trimToSize(null, 1));
762
763 assertEquals("Should trim high surrogate if invalid surrogate",
764 "a\uD800", TextUtils.trimToSize("a\uD800\uD800", 2));
765 assertEquals("Should trim low surrogate if invalid surrogate",
766 "a\uDC00", TextUtils.trimToSize("a\uDC00\uDC00", 2));
767 }
768
769 @Test(expected = IllegalArgumentException.class)
770 public void testTrimToSizeThrowsExceptionForNegativeSize() {
771 TextUtils.trimToSize("", -1);
772 }
773
774 @Test(expected = IllegalArgumentException.class)
775 public void testTrimToSizeThrowsExceptionForZeroSize() {
776 TextUtils.trimToSize("abc", 0);
777 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800778}