1 /* 2 * Copyright (C) 2010 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 libcore.java.lang; 18 19 import java.nio.ByteBuffer; 20 import java.nio.CharBuffer; 21 import java.nio.ReadOnlyBufferException; 22 import java.nio.charset.Charset; 23 import java.nio.charset.CharsetDecoder; 24 import java.nio.charset.CharsetEncoder; 25 import java.nio.charset.CoderResult; 26 import java.nio.charset.CodingErrorAction; 27 import java.util.Arrays; 28 import java.util.Locale; 29 import junit.framework.TestCase; 30 31 public class StringTest extends TestCase { 32 public void testIsEmpty() { 33 assertTrue("".isEmpty()); 34 assertFalse("x".isEmpty()); 35 } 36 37 // The evil decoder keeps hold of the CharBuffer it wrote to. 38 private static final class EvilCharsetDecoder extends CharsetDecoder { 39 private static char[] chars; 40 public EvilCharsetDecoder(Charset cs) { 41 super(cs, 1.0f, 1.0f); 42 } 43 protected CoderResult decodeLoop(ByteBuffer in, CharBuffer out) { 44 chars = out.array(); 45 int inLength = in.remaining(); 46 for (int i = 0; i < inLength; ++i) { 47 in.put((byte) 'X'); 48 out.put('Y'); 49 } 50 return CoderResult.UNDERFLOW; 51 } 52 public static void corrupt() { 53 for (int i = 0; i < chars.length; ++i) { 54 chars[i] = '$'; 55 } 56 } 57 } 58 59 // The evil encoder tries to write to the CharBuffer it was given to 60 // read from. 61 private static final class EvilCharsetEncoder extends CharsetEncoder { 62 public EvilCharsetEncoder(Charset cs) { 63 super(cs, 1.0f, 1.0f); 64 } 65 protected CoderResult encodeLoop(CharBuffer in, ByteBuffer out) { 66 int inLength = in.remaining(); 67 for (int i = 0; i < inLength; ++i) { 68 in.put('x'); 69 out.put((byte) 'y'); 70 } 71 return CoderResult.UNDERFLOW; 72 } 73 } 74 75 private static final Charset EVIL_CHARSET = new Charset("evil", null) { 76 public boolean contains(Charset charset) { return false; } 77 public CharsetEncoder newEncoder() { return new EvilCharsetEncoder(this); } 78 public CharsetDecoder newDecoder() { return new EvilCharsetDecoder(this); } 79 }; 80 81 public void testGetBytes_MaliciousCharset() { 82 try { 83 String s = "hi"; 84 // Check that our encoder can't write to the input CharBuffer 85 // it was given. 86 s.getBytes(EVIL_CHARSET); 87 fail(); // We shouldn't have got here! 88 } catch (ReadOnlyBufferException expected) { 89 // We caught you trying to be naughty! 90 } 91 } 92 93 public void testString_BII() throws Exception { 94 byte[] bytes = "xa\u0666bx".getBytes("UTF-8"); 95 assertEquals("a\u0666b", new String(bytes, 1, bytes.length - 2)); 96 } 97 98 public void testString_BIIString() throws Exception { 99 byte[] bytes = "xa\u0666bx".getBytes("UTF-8"); 100 assertEquals("a\u0666b", new String(bytes, 1, bytes.length - 2, "UTF-8")); 101 } 102 103 public void testString_BIICharset() throws Exception { 104 byte[] bytes = "xa\u0666bx".getBytes("UTF-8"); 105 assertEquals("a\u0666b", new String(bytes, 1, bytes.length - 2, Charset.forName("UTF-8"))); 106 } 107 108 public void testString_BCharset() throws Exception { 109 byte[] bytes = "a\u0666b".getBytes("UTF-8"); 110 assertEquals("a\u0666b", new String(bytes, Charset.forName("UTF-8"))); 111 } 112 113 public void testStringFromCharset_MaliciousCharset() { 114 Charset cs = EVIL_CHARSET; 115 byte[] bytes = new byte[] {(byte) 'h', (byte) 'i'}; 116 final String result = new String(bytes, cs); 117 assertEquals("YY", result); // (Our decoder always outputs 'Y's.) 118 // Check that even if the decoder messes with the output CharBuffer 119 // after we've created a string from it, it doesn't affect the string. 120 EvilCharsetDecoder.corrupt(); 121 assertEquals("YY", result); 122 } 123 124 public void test_getBytes_bad() throws Exception { 125 // Check that we use '?' as the replacement byte for invalid characters. 126 assertEquals("[97, 63, 98]", Arrays.toString("a\u0666b".getBytes("US-ASCII"))); 127 assertEquals("[97, 63, 98]", Arrays.toString("a\u0666b".getBytes(Charset.forName("US-ASCII")))); 128 } 129 130 public void test_getBytes_UTF_8() { 131 // We have a fast path implementation of String.getBytes for UTF-8. 132 Charset cs = Charset.forName("UTF-8"); 133 134 // Test the empty string. 135 assertEquals("[]", Arrays.toString("".getBytes(cs))); 136 137 // Test one-byte characters. 138 assertEquals("[0]", Arrays.toString("\u0000".getBytes(cs))); 139 assertEquals("[127]", Arrays.toString("\u007f".getBytes(cs))); 140 assertEquals("[104, 105]", Arrays.toString("hi".getBytes(cs))); 141 142 // Test two-byte characters. 143 assertEquals("[-62, -128]", Arrays.toString("\u0080".getBytes(cs))); 144 assertEquals("[-39, -90]", Arrays.toString("\u0666".getBytes(cs))); 145 assertEquals("[-33, -65]", Arrays.toString("\u07ff".getBytes(cs))); 146 assertEquals("[104, -39, -90, 105]", Arrays.toString("h\u0666i".getBytes(cs))); 147 148 // Test three-byte characters. 149 assertEquals("[-32, -96, -128]", Arrays.toString("\u0800".getBytes(cs))); 150 assertEquals("[-31, -120, -76]", Arrays.toString("\u1234".getBytes(cs))); 151 assertEquals("[-17, -65, -65]", Arrays.toString("\uffff".getBytes(cs))); 152 assertEquals("[104, -31, -120, -76, 105]", Arrays.toString("h\u1234i".getBytes(cs))); 153 154 // Test supplementary characters. 155 // Minimum supplementary character: U+10000 156 assertEquals("[-16, -112, -128, -128]", Arrays.toString("\ud800\udc00".getBytes(cs))); 157 // Random supplementary character: U+10381 Ugaritic letter beta 158 assertEquals("[-16, -112, -114, -127]", Arrays.toString("\ud800\udf81".getBytes(cs))); 159 // Maximum supplementary character: U+10FFFF 160 assertEquals("[-12, -113, -65, -65]", Arrays.toString("\udbff\udfff".getBytes(cs))); 161 // A high surrogate at end of string is an error replaced with '?'. 162 assertEquals("[104, 63]", Arrays.toString("h\ud800".getBytes(cs))); 163 // A high surrogate not followed by a low surrogate is an error replaced with '?'. 164 assertEquals("[104, 63, 105]", Arrays.toString("h\ud800i".getBytes(cs))); 165 } 166 167 public void test_new_String_bad() throws Exception { 168 // Check that we use U+FFFD as the replacement string for invalid bytes. 169 assertEquals("a\ufffdb", new String(new byte[] { 97, -2, 98 }, "US-ASCII")); 170 assertEquals("a\ufffdb", new String(new byte[] { 97, -2, 98 }, Charset.forName("US-ASCII"))); 171 } 172 173 /** 174 175 * Test that strings interned manually and then later loaded as literals 176 * maintain reference equality. http://b/3098960 177 */ 178 public void testInternBeforeLiteralIsLoaded() throws Exception{ 179 String programmatic = Arrays.asList("5058", "9962", "1563", "5744").toString().intern(); 180 String literal = (String) Class.forName("libcore.java.lang.StringTest$HasLiteral") 181 .getDeclaredField("literal").get(null); 182 assertEquals(System.identityHashCode(programmatic), System.identityHashCode(literal)); 183 assertSame(programmatic, literal); 184 } 185 186 static class HasLiteral { 187 static String literal = "[5058, 9962, 1563, 5744]"; 188 } 189 190 private static final String COMBINING_DOT_ABOVE = "\u0307"; 191 private static final String LATIN_CAPITAL_I = "I"; 192 private static final String LATIN_CAPITAL_I_WITH_DOT_ABOVE = "\u0130"; 193 private static final String LATIN_SMALL_I = "i"; 194 private static final String LATIN_SMALL_DOTLESS_I = "\u0131"; 195 196 private static final String[] LATIN_I_VARIANTS = { 197 LATIN_SMALL_I, 198 LATIN_SMALL_DOTLESS_I, 199 LATIN_CAPITAL_I, 200 LATIN_CAPITAL_I_WITH_DOT_ABOVE, 201 }; 202 203 public void testCaseMapping_tr_TR() { 204 Locale tr_TR = new Locale("tr", "TR"); 205 assertEquals(LATIN_SMALL_I, LATIN_SMALL_I.toLowerCase(tr_TR)); 206 assertEquals(LATIN_SMALL_I, LATIN_CAPITAL_I_WITH_DOT_ABOVE.toLowerCase(tr_TR)); 207 assertEquals(LATIN_SMALL_DOTLESS_I, LATIN_SMALL_DOTLESS_I.toLowerCase(tr_TR)); 208 209 assertEquals(LATIN_CAPITAL_I, LATIN_CAPITAL_I.toUpperCase(tr_TR)); 210 assertEquals(LATIN_CAPITAL_I_WITH_DOT_ABOVE, LATIN_CAPITAL_I_WITH_DOT_ABOVE.toUpperCase(tr_TR)); 211 assertEquals(LATIN_CAPITAL_I_WITH_DOT_ABOVE, LATIN_SMALL_I.toUpperCase(tr_TR)); 212 213 assertEquals(LATIN_CAPITAL_I, LATIN_SMALL_DOTLESS_I.toUpperCase(tr_TR)); 214 assertEquals(LATIN_SMALL_DOTLESS_I, LATIN_CAPITAL_I.toLowerCase(tr_TR)); 215 } 216 217 public void testCaseMapping_en_US() { 218 Locale en_US = new Locale("en", "US"); 219 assertEquals(LATIN_CAPITAL_I, LATIN_SMALL_I.toUpperCase(en_US)); 220 assertEquals(LATIN_CAPITAL_I, LATIN_CAPITAL_I.toUpperCase(en_US)); 221 assertEquals(LATIN_CAPITAL_I_WITH_DOT_ABOVE, LATIN_CAPITAL_I_WITH_DOT_ABOVE.toUpperCase(en_US)); 222 223 assertEquals(LATIN_SMALL_I, LATIN_SMALL_I.toLowerCase(en_US)); 224 assertEquals(LATIN_SMALL_I, LATIN_CAPITAL_I.toLowerCase(en_US)); 225 assertEquals(LATIN_SMALL_DOTLESS_I, LATIN_SMALL_DOTLESS_I.toLowerCase(en_US)); 226 227 assertEquals(LATIN_CAPITAL_I, LATIN_SMALL_DOTLESS_I.toUpperCase(en_US)); 228 // http://b/3325799: the RI fails this because it's using an obsolete version of the Unicode rules. 229 // Android correctly preserves canonical equivalence. (See the separate test for tr_TR.) 230 assertEquals(LATIN_SMALL_I + COMBINING_DOT_ABOVE, LATIN_CAPITAL_I_WITH_DOT_ABOVE.toLowerCase(en_US)); 231 } 232 233 public void testCaseMapping_el() { 234 Locale el_GR = new Locale("el", "GR"); 235 assertEquals(" O ", " o ".toUpperCase(el_GR)); 236 assertEquals(" O ", " o ".toUpperCase(el_GR)); 237 assertEquals(" O ", " o ".toUpperCase(el_GR)); 238 239 Locale en_US = new Locale("en", "US"); 240 assertEquals(" O ", " o ".toUpperCase(en_US)); 241 } 242 243 public void testEqualsIgnoreCase_tr_TR() { 244 testEqualsIgnoreCase(new Locale("tr", "TR")); 245 } 246 247 public void testEqualsIgnoreCase_en_US() { 248 testEqualsIgnoreCase(new Locale("en", "US")); 249 } 250 251 /** 252 * String.equalsIgnoreCase should not depend on the locale. 253 */ 254 private void testEqualsIgnoreCase(Locale locale) { 255 Locale defaultLocale = Locale.getDefault(); 256 Locale.setDefault(locale); 257 try { 258 for (String a : LATIN_I_VARIANTS) { 259 for (String b : LATIN_I_VARIANTS) { 260 if (!a.equalsIgnoreCase(b)) { 261 fail("Expected " + a + " to equal " + b + " in " + locale); 262 } 263 } 264 } 265 } finally { 266 Locale.setDefault(defaultLocale); 267 } 268 } 269 270 public void testRegionMatches_ignoreCase_en_US() { 271 testRegionMatches_ignoreCase(new Locale("en", "US")); 272 } 273 274 public void testRegionMatches_ignoreCase_tr_TR() { 275 testRegionMatches_ignoreCase(new Locale("tr", "TR")); 276 } 277 278 private void testRegionMatches_ignoreCase(Locale locale) { 279 Locale defaultLocale = Locale.getDefault(); 280 Locale.setDefault(locale); 281 try { 282 for (String a : LATIN_I_VARIANTS) { 283 for (String b : LATIN_I_VARIANTS) { 284 if (!a.regionMatches(true, 0, b, 0, b.length())) { 285 fail("Expected " + a + " to equal " + b + " in " + locale); 286 } 287 } 288 } 289 } finally { 290 Locale.setDefault(defaultLocale); 291 } 292 } 293 294 // http://code.google.com/p/android/issues/detail?id=15266 295 public void test_replaceAll() throws Exception { 296 assertEquals("project_Id", "projectId".replaceAll("(?!^)(\\p{Upper})(?!$)", "_$1")); 297 } 298 299 // https://code.google.com/p/android/issues/detail?id=23831 300 public void test_23831() throws Exception { 301 byte[] bytes = { (byte) 0xf5, (byte) 0xa9, (byte) 0xea, (byte) 0x21 }; 302 String expected = "\ufffd\ufffd\u0021"; 303 304 // Since we use icu4c for CharsetDecoder... 305 CharsetDecoder decoder = Charset.forName("UTF-8").newDecoder(); 306 decoder.onMalformedInput(CodingErrorAction.REPLACE); 307 assertEquals(expected, decoder.decode(ByteBuffer.wrap(bytes)).toString()); 308 309 // Our fast-path code in String should behave the same... 310 assertEquals(expected, new String(bytes, "UTF-8")); 311 } 312 313 // https://code.google.com/p/android/issues/detail?id=55129 314 public void test_55129() throws Exception { 315 assertEquals("-h-e-l-l-o- -w-o-r-l-d-", "hello world".replace("", "-")); 316 assertEquals("-w-o-r-l-d-", "hello world".substring(6).replace("", "-")); 317 assertEquals("-*-w-*-o-*-r-*-l-*-d-*-", "hello world".substring(6).replace("", "-*-")); 318 319 // Replace on an empty string with an empty target should insert the pattern 320 // precisely once. 321 assertEquals("", "".replace("", "")); 322 assertEquals("food", "".replace("", "food")); 323 } 324 325 public void test_replace() { 326 // Replace on an empty string is a no-op. 327 assertEquals("", "".replace("foo", "bar")); 328 // Replace on a string which doesn't contain the target sequence is a no-op. 329 assertEquals("baz", "baz".replace("foo", "bar")); 330 // Test that we iterate forward on the string. 331 assertEquals("mmmba", "bababa".replace("baba", "mmm")); 332 // Test replacements at the end of the string. 333 assertEquals("foodie", "foolish".replace("lish", "die")); 334 // Test a string that has multiple replacements. 335 assertEquals("hahahaha", "kkkk".replace("k", "ha")); 336 } 337 338 public void test_String_getBytes() throws Exception { 339 // http://b/11571917 340 assertEquals("[-126, -96]", Arrays.toString("".getBytes("Shift_JIS"))); 341 assertEquals("[-126, -87]", Arrays.toString("".getBytes("Shift_JIS"))); 342 assertEquals("[-105, 67]", Arrays.toString("".getBytes("Shift_JIS"))); 343 assertEquals("[36]", Arrays.toString("$".getBytes("Shift_JIS"))); 344 assertEquals("[-29, -127, -117]", Arrays.toString("".getBytes("UTF-8"))); 345 346 // http://b/11639117 347 assertEquals("[-79, -72, -70, -48]", Arrays.toString("".getBytes("EUC-KR"))); 348 349 350 // https://code.google.com/p/android/issues/detail?id=63188 351 assertEquals("[-77, -10, -64, -76, -63, -53]", Arrays.toString("".getBytes("gbk"))); 352 assertEquals("[-77, -10, -64, -76]", Arrays.toString("".getBytes("gbk"))); 353 assertEquals("[-77, -10]", Arrays.toString("".getBytes("gbk"))); 354 } 355 356 public void test_compareTo() throws Exception { 357 // For strings where a character differs, the result is 358 // the difference between the characters. 359 assertEquals(-1, "a".compareTo("b")); 360 assertEquals(-2, "a".compareTo("c")); 361 assertEquals(1, "b".compareTo("a")); 362 assertEquals(2, "c".compareTo("a")); 363 364 // For strings where the characters match up to the length of the shorter, 365 // the result is the difference between the strings' lengths. 366 assertEquals(0, "a".compareTo("a")); 367 assertEquals(-1, "a".compareTo("aa")); 368 assertEquals(-1, "a".compareTo("az")); 369 assertEquals(-2, "a".compareTo("aaa")); 370 assertEquals(-2, "a".compareTo("azz")); 371 assertEquals(-3, "a".compareTo("aaaa")); 372 assertEquals(-3, "a".compareTo("azzz")); 373 assertEquals(0, "a".compareTo("a")); 374 assertEquals(1, "aa".compareTo("a")); 375 assertEquals(1, "az".compareTo("a")); 376 assertEquals(2, "aaa".compareTo("a")); 377 assertEquals(2, "azz".compareTo("a")); 378 assertEquals(3, "aaaa".compareTo("a")); 379 assertEquals(3, "azzz".compareTo("a")); 380 } 381 382 public void test_compareToIgnoreCase() throws Exception { 383 // For strings where a character differs, the result is 384 // the difference between the characters. 385 assertEquals(-1, "a".compareToIgnoreCase("b")); 386 assertEquals(-1, "a".compareToIgnoreCase("B")); 387 assertEquals(-2, "a".compareToIgnoreCase("c")); 388 assertEquals(-2, "a".compareToIgnoreCase("C")); 389 assertEquals(1, "b".compareToIgnoreCase("a")); 390 assertEquals(1, "B".compareToIgnoreCase("a")); 391 assertEquals(2, "c".compareToIgnoreCase("a")); 392 assertEquals(2, "C".compareToIgnoreCase("a")); 393 394 // For strings where the characters match up to the length of the shorter, 395 // the result is the difference between the strings' lengths. 396 assertEquals(0, "a".compareToIgnoreCase("a")); 397 assertEquals(0, "a".compareToIgnoreCase("A")); 398 assertEquals(0, "A".compareToIgnoreCase("a")); 399 assertEquals(0, "A".compareToIgnoreCase("A")); 400 assertEquals(-1, "a".compareToIgnoreCase("aa")); 401 assertEquals(-1, "a".compareToIgnoreCase("aA")); 402 assertEquals(-1, "a".compareToIgnoreCase("Aa")); 403 assertEquals(-1, "a".compareToIgnoreCase("az")); 404 assertEquals(-1, "a".compareToIgnoreCase("aZ")); 405 assertEquals(-2, "a".compareToIgnoreCase("aaa")); 406 assertEquals(-2, "a".compareToIgnoreCase("AAA")); 407 assertEquals(-2, "a".compareToIgnoreCase("azz")); 408 assertEquals(-2, "a".compareToIgnoreCase("AZZ")); 409 assertEquals(-3, "a".compareToIgnoreCase("aaaa")); 410 assertEquals(-3, "a".compareToIgnoreCase("AAAA")); 411 assertEquals(-3, "a".compareToIgnoreCase("azzz")); 412 assertEquals(-3, "a".compareToIgnoreCase("AZZZ")); 413 assertEquals(1, "aa".compareToIgnoreCase("a")); 414 assertEquals(1, "aA".compareToIgnoreCase("a")); 415 assertEquals(1, "Aa".compareToIgnoreCase("a")); 416 assertEquals(1, "az".compareToIgnoreCase("a")); 417 assertEquals(2, "aaa".compareToIgnoreCase("a")); 418 assertEquals(2, "azz".compareToIgnoreCase("a")); 419 assertEquals(3, "aaaa".compareToIgnoreCase("a")); 420 assertEquals(3, "azzz".compareToIgnoreCase("a")); 421 } 422 423 // http://b/25943996 424 public void testSplit_trailingSeparators() { 425 String[] splits = "test\0message\0\0\0\0\0\0".split("\0", -1); 426 assertEquals("test", splits[0]); 427 assertEquals("message", splits[1]); 428 assertEquals("", splits[2]); 429 assertEquals("", splits[3]); 430 assertEquals("", splits[4]); 431 assertEquals("", splits[5]); 432 assertEquals("", splits[6]); 433 assertEquals("", splits[7]); 434 } 435 436 // http://b/26126818 437 public void testCodePointCount() { 438 String hello = "Hello, fools"; 439 440 assertEquals(5, hello.codePointCount(0, 5)); 441 assertEquals(7, hello.codePointCount(5, 12)); 442 assertEquals(2, hello.codePointCount(10, 12)); 443 } 444 445 // http://b/26444984 446 public void testGetCharsOverflow() { 447 int srcBegin = Integer.MAX_VALUE; //2147483647 448 int srcEnd = srcBegin + 10; //-2147483639 449 try { 450 // The output array size must be larger than |srcEnd - srcBegin|. 451 "yes".getChars(srcBegin, srcEnd, new char[256], 0); 452 fail(); 453 } catch (StringIndexOutOfBoundsException expected) { 454 } 455 } 456 457 // http://b/28998511 458 public void testGetCharsBoundsChecks() { 459 // This is the explicit case from the bug: dstBegin == srcEnd - srcBegin 460 assertGetCharsThrowsAIOOBException("abcd", 0, 4, new char[0], -4); 461 462 // Some valid cases. 463 char[] dst = new char[1]; 464 "abcd".getChars(0, 1, dst, 0); 465 assertEquals('a', dst[0]); 466 "abcd".getChars(3, 4, dst, 0); 467 assertEquals('d', dst[0]); 468 dst = new char[4]; 469 "abcd".getChars(0, 4, dst, 0); 470 assertTrue(Arrays.equals("abcd".toCharArray(), dst)); 471 472 // Zero length src. 473 "abcd".getChars(0, 0, new char[0], 0); // dstBegin == 0 is ok if copying zero chars 474 "abcd".getChars(0, 0, new char[1], 1); // dstBegin == 1 is ok if copying zero chars 475 "".getChars(0, 0, new char[0], 0); 476 "abcd".getChars(1, 1, new char[1], 0); 477 "abcd".getChars(1, 1, new char[1], 1); 478 479 // Valid src args, invalid dst args. 480 assertGetCharsThrowsAIOOBException("abcd", 3, 4, new char[1], 1); // Out of range dstBegin 481 assertGetCharsThrowsAIOOBException("abcd", 0, 4, new char[3], 0); // Small dst 482 assertGetCharsThrowsAIOOBException("abcd", 0, 4, new char[4], -1); // Negative dstBegin 483 484 // dstBegin + (srcEnd - srcBegin) -> integer overflow OR dstBegin >= dst.length 485 assertGetCharsThrowsAIOOBException("abcd", 0, 4, new char[4], Integer.MAX_VALUE - 1); 486 487 // Invalid src args, valid dst args. 488 assertGetCharsThrowsSIOOBException("abcd", 2, 1, new char[4], 0); // srcBegin > srcEnd 489 assertGetCharsThrowsSIOOBException("abcd", -1, 3, new char[4], 0); // Negative srcBegin 490 assertGetCharsThrowsSIOOBException("abcd", 0, 5, new char[4], 0); // Out of range srcEnd 491 assertGetCharsThrowsSIOOBException("abcd", 0, -1, new char[4], 0); // Negative srcEnd 492 493 // Valid src args, invalid dst args. 494 assertGetCharsThrowsAIOOBException("abcd", 0, 4, new char[4], 1); // Bad dstBegin 495 496 // Zero length src copy, invalid dst args. 497 assertGetCharsThrowsAIOOBException("abcd", 0, 0, new char[4], -1); // Negative dstBegin 498 assertGetCharsThrowsAIOOBException("abcd", 0, 0, new char[0], 1); // Out of range dstBegin 499 assertGetCharsThrowsAIOOBException("abcd", 0, 0, new char[1], 2); // Out of range dstBegin 500 assertGetCharsThrowsAIOOBException("abcd", 0, 0, new char[4], 5); // Out of range dstBegin 501 } 502 503 private static void assertGetCharsThrowsAIOOBException(String s, int srcBegin, int srcEnd, 504 char[] dst, int dstBegin) { 505 try { 506 s.getChars(srcBegin, srcEnd, dst, dstBegin); 507 fail(); 508 } catch (ArrayIndexOutOfBoundsException expected) { 509 } 510 } 511 512 private static void assertGetCharsThrowsSIOOBException(String s, int srcBegin, int srcEnd, 513 char[] dst, int dstBegin) { 514 try { 515 s.getChars(srcBegin, srcEnd, dst, dstBegin); 516 fail(); 517 } catch (StringIndexOutOfBoundsException expected) { 518 } 519 } 520 521 public void testChars() { 522 String s = "Hello\n\tworld"; 523 int[] expected = new int[s.length()]; 524 for (int i = 0; i < s.length(); ++i) { 525 expected[i] = (int) s.charAt(i); 526 } 527 assertTrue(Arrays.equals(expected, s.chars().toArray())); 528 529 // Surrogate code point 530 char high = '\uD83D', low = '\uDE02'; 531 String surrogateCP = new String(new char[]{high, low, low}); 532 assertTrue(Arrays.equals(new int[]{high, low, low}, surrogateCP.chars().toArray())); 533 } 534 535 public void testCodePoints() { 536 String s = "Hello\n\tworld"; 537 int[] expected = new int[s.length()]; 538 for (int i = 0; i < s.length(); ++i) { 539 expected[i] = (int) s.charAt(i); 540 } 541 assertTrue(Arrays.equals(expected, s.codePoints().toArray())); 542 543 // Surrogate code point 544 char high = '\uD83D', low = '\uDE02'; 545 String surrogateCP = new String(new char[]{high, low, low, '0'}); 546 assertEquals(Character.toCodePoint(high, low), surrogateCP.codePoints().toArray()[0]); 547 assertEquals((int) low, surrogateCP.codePoints().toArray()[1]); // Unmatched surrogate. 548 assertEquals((int) '0', surrogateCP.codePoints().toArray()[2]); 549 } 550 } 551