1 /* 2 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 /* 25 * 26 * @test 27 * @bug 4533872 4915683 4985217 5017280 6937112 28 * @summary Unit tests for supplementary character support (JSR-204) 29 */ 30 31 package test.java.lang.StringBuffer; 32 33 import org.testng.annotations.Test; 34 35 public class Supplementary { 36 // Android-changed: Add @Test annotation and remove empty arguments. 37 // public static void main(String[] args) { 38 @Test main()39 public static void main() { 40 test1(); // Test for codePointAt(int index) 41 test2(); // Test for codePointBefore(int index) 42 test3(); // Test for reverse() 43 test4(); // Test for appendCodePoint(int codePoint) 44 test5(); // Test for codePointCount(int beginIndex, int endIndex) 45 test6(); // Test for offsetByCodePoints(int index, int offset) 46 } 47 48 /* Text strings which are used as input data. 49 * The comment above each text string means the index of each 16-bit char 50 * for convenience. 51 */ 52 static final String[] input = { 53 /* 111 1 111111 22222 54 0123 4 5678 9 012 3 456789 01234 */ 55 "abc\uD800\uDC00def\uD800\uD800ab\uD800\uDC00cdefa\uDC00bcdef", 56 /* 1 1111 1111 1 222 57 0 12345 6789 0 1234 5678 9 012 */ 58 "\uD800defg\uD800hij\uD800\uDC00klm\uDC00nop\uDC00\uD800rt\uDC00", 59 /* 11 1 1111 1 112 222 60 0 12345 6 78901 2 3456 7 890 123 */ 61 "\uDC00abcd\uDBFF\uDFFFefgh\uD800\uDC009ik\uDC00\uDC00lm\uDC00no\uD800", 62 /* 111 111111 1 22 2 63 0 1 2345 678 9 012 345678 9 01 2 */ 64 "\uD800\uDC00!#$\uD800%&\uD800\uDC00;+\uDC00<>;=^\uDC00\\@\uD800\uDC00", 65 66 // includes an undefined supplementary character in Unicode 4.0.0 67 /* 1 11 1 1111 1 68 0 1 2345 6 789 0 12 3 4567 8 */ 69 "\uDB40\uDE00abc\uDE01\uDB40de\uDB40\uDE02f\uDB40\uDE03ghi\uDB40\uDE02", 70 }; 71 72 73 /* Expected results for: 74 * test1(): for codePointAt() 75 * 76 * Each character in each array is the golden data for each text string 77 * in the above input data. For example, the first data in each array is 78 * for the first input string. 79 */ 80 static final int[][] golden1 = { 81 {'a', 0xD800, 0xDC00, 0x10000, 0xE0200}, // codePointAt(0) 82 {0xD800, 0x10000, 'g', 0xDC00, 0xE0202}, // codePointAt(9) 83 {'f', 0xDC00, 0xD800, 0xDC00, 0xDE02}, // codePointAt(length-1) 84 }; 85 86 /* 87 * Test for codePointAt(int index) method 88 */ test1()89 static void test1() { 90 91 for (int i = 0; i < input.length; i++) { 92 StringBuffer sb = new StringBuffer(input[i]); 93 94 /* 95 * Normal case 96 */ 97 testCodePoint(At, sb, 0, golden1[0][i]); 98 testCodePoint(At, sb, 9, golden1[1][i]); 99 testCodePoint(At, sb, sb.length()-1, golden1[2][i]); 100 101 /* 102 * Abnormal case - verify that an exception is thrown. 103 */ 104 testCodePoint(At, sb, -1); 105 testCodePoint(At, sb, sb.length()); 106 } 107 } 108 109 110 /* Expected results for: 111 * test2(): for codePointBefore() 112 * 113 * Each character in each array is the golden data for each text string 114 * in the above input data. For example, the first data in each array is 115 * for the first input string. 116 */ 117 static final int[][] golden2 = { 118 {'a', 0xD800, 0xDC00, 0xD800, 0xDB40}, // codePointBefore(1) 119 {0xD800, 'l', 0x10000, 0xDC00, 0xDB40}, // codePointBefore(13) 120 {'f', 0xDC00, 0xD800, 0x10000, 0xE0202}, // codePointBefore(length) 121 }; 122 123 /* 124 * Test for codePointBefore(int index) method 125 */ test2()126 static void test2() { 127 128 for (int i = 0; i < input.length; i++) { 129 StringBuffer sb = new StringBuffer(input[i]); 130 131 /* 132 * Normal case 133 */ 134 testCodePoint(Before, sb, 1, golden2[0][i]); 135 testCodePoint(Before, sb, 13, golden2[1][i]); 136 testCodePoint(Before, sb, sb.length(), golden2[2][i]); 137 138 /* 139 * Abnormal case - verify that an exception is thrown. 140 */ 141 testCodePoint(Before, sb, 0); 142 testCodePoint(Before, sb, sb.length()+1); 143 } 144 } 145 146 147 /* Expected results for: 148 * test3(): for reverse() 149 * 150 * Unlike golden1 and golden2, each array is the golden data for each text 151 * string in the above input data. For example, the first array is for 152 * the first input string. 153 */ 154 static final String[] golden3 = { 155 "fedcb\uDC00afedc\uD800\uDC00ba\uD800\uD800fed\uD800\uDC00cba", 156 "\uDC00tr\uD800\uDC00pon\uDC00mlk\uD800\uDC00jih\uD800gfed\uD800", 157 "\uD800on\uDC00ml\uDC00\uDC00ki9\uD800\uDC00hgfe\uDBFF\uDFFFdcba\uDC00", 158 "\uD800\uDC00@\\\uDC00^=;><\uDC00+;\uD800\uDC00&%\uD800$#!\uD800\uDC00", 159 160 // includes an undefined supplementary character in Unicode 4.0.0 161 "\uDB40\uDE02ihg\uDB40\uDE03f\uDB40\uDE02ed\uDB40\uDE01cba\uDB40\uDE00", 162 }; 163 164 // Additional input data & expected result for test3() 165 static final String[][] testdata1 = { 166 {"a\uD800\uDC00", "\uD800\uDC00a"}, 167 {"a\uDC00\uD800", "\uD800\uDC00a"}, 168 {"\uD800\uDC00a", "a\uD800\uDC00"}, 169 {"\uDC00\uD800a", "a\uD800\uDC00"}, 170 {"\uDC00\uD800\uD801", "\uD801\uD800\uDC00"}, 171 {"\uDC00\uD800\uDC01", "\uD800\uDC01\uDC00"}, 172 {"\uD801\uD800\uDC00", "\uD800\uDC00\uD801"}, 173 {"\uD800\uDC01\uDC00", "\uDC00\uD800\uDC01"}, 174 {"\uD800\uDC00\uDC01\uD801", "\uD801\uDC01\uD800\uDC00"}, 175 }; 176 177 /* 178 * Test for reverse() method 179 */ test3()180 static void test3() { 181 for (int i = 0; i < input.length; i++) { 182 StringBuffer sb = new StringBuffer(input[i]).reverse(); 183 184 check(!golden3[i].equals(new String(sb)), 185 "reverse() for <" + toHexString(input[i]) + ">", 186 sb, golden3[i]); 187 } 188 189 for (int i = 0; i < testdata1.length; i++) { 190 StringBuffer sb = new StringBuffer(testdata1[i][0]).reverse(); 191 192 check(!testdata1[i][1].equals(new String(sb)), 193 "reverse() for <" + toHexString(testdata1[i][0]) + ">", 194 sb, testdata1[i][1]); 195 } 196 } 197 198 /** 199 * Test for appendCodePoint() method 200 */ test4()201 static void test4() { 202 for (int i = 0; i < input.length; i++) { 203 String s = input[i]; 204 StringBuffer sb = new StringBuffer(); 205 int c; 206 for (int j = 0; j < s.length(); j += Character.charCount(c)) { 207 c = s.codePointAt(j); 208 StringBuffer rsb = sb.appendCodePoint(c); 209 check(sb != rsb, "appendCodePoint returned a wrong object"); 210 int sbc = sb.codePointAt(j); 211 check(sbc != c, "appendCodePoint(j) != c", sbc, c); 212 } 213 check(!s.equals(sb.toString()), 214 "appendCodePoint() produced a wrong result with input["+i+"]"); 215 } 216 217 // test exception 218 testAppendCodePoint(-1, IllegalArgumentException.class); 219 testAppendCodePoint(Character.MAX_CODE_POINT+1, IllegalArgumentException.class); 220 } 221 222 /** 223 * Test codePointCount(int, int) 224 * 225 * This test case assumes that 226 * Character.codePointCount(CharSequence, int, int) works 227 * correctly. 228 */ test5()229 static void test5() { 230 for (int i = 0; i < input.length; i++) { 231 String s = input[i]; 232 StringBuffer sb = new StringBuffer(s); 233 int length = sb.length(); 234 for (int j = 0; j <= length; j++) { 235 int result = sb.codePointCount(j, length); 236 int expected = Character.codePointCount(sb, j, length); 237 check(result != expected, "codePointCount(input["+i+"], "+j+", "+length+")", 238 result, expected); 239 } 240 for (int j = length; j >= 0; j--) { 241 int result = sb.codePointCount(0, j); 242 int expected = Character.codePointCount(sb, 0, j); 243 check(result != expected, "codePointCount(input["+i+"], 0, "+j+")", 244 result, expected); 245 } 246 247 // test exceptions 248 testCodePointCount(null, 0, 0, NullPointerException.class); 249 testCodePointCount(sb, -1, length, IndexOutOfBoundsException.class); 250 testCodePointCount(sb, 0, length+1, IndexOutOfBoundsException.class); 251 testCodePointCount(sb, length, length-1, IndexOutOfBoundsException.class); 252 } 253 } 254 255 /** 256 * Test offsetByCodePoints(int, int) 257 * 258 * This test case assumes that 259 * Character.codePointCount(CharSequence, int, int) works 260 * correctly. 261 */ test6()262 static void test6() { 263 for (int i = 0; i < input.length; i++) { 264 String s = input[i]; 265 StringBuffer sb = new StringBuffer(s); 266 int length = s.length(); 267 for (int j = 0; j <= length; j++) { 268 int nCodePoints = Character.codePointCount(sb, j, length); 269 int result = sb.offsetByCodePoints(j, nCodePoints); 270 check(result != length, 271 "offsetByCodePoints(input["+i+"], "+j+", "+nCodePoints+")", 272 result, length); 273 result = sb.offsetByCodePoints(length, -nCodePoints); 274 int expected = j; 275 if (j > 0 && j < length) { 276 int cp = sb.codePointBefore(j+1); 277 if (Character.isSupplementaryCodePoint(cp)) { 278 expected--; 279 } 280 } 281 check(result != expected, 282 "offsetByCodePoints(input["+i+"], "+j+", "+(-nCodePoints)+")", 283 result, expected); 284 } 285 for (int j = length; j >= 0; j--) { 286 int nCodePoints = Character.codePointCount(sb, 0, j); 287 int result = sb.offsetByCodePoints(0, nCodePoints); 288 int expected = j; 289 if (j > 0 && j < length) { 290 int cp = sb.codePointAt(j-1); 291 if (Character.isSupplementaryCodePoint(cp)) { 292 expected++; 293 } 294 } 295 check(result != expected, 296 "offsetByCodePoints(input["+i+"], 0, "+nCodePoints+")", 297 result, expected); 298 result = sb.offsetByCodePoints(j, -nCodePoints); 299 check(result != 0, 300 "offsetBycodePoints(input["+i+"], "+j+", "+(-nCodePoints)+")", 301 result, 0); 302 } 303 304 // test exceptions 305 testOffsetByCodePoints(null, 0, 0, NullPointerException.class); 306 testOffsetByCodePoints(sb, -1, length, IndexOutOfBoundsException.class); 307 testOffsetByCodePoints(sb, 0, length+1, IndexOutOfBoundsException.class); 308 testOffsetByCodePoints(sb, 1, -2, IndexOutOfBoundsException.class); 309 testOffsetByCodePoints(sb, length, length-1, IndexOutOfBoundsException.class); 310 testOffsetByCodePoints(sb, length, -(length+1), IndexOutOfBoundsException.class); 311 } 312 } 313 314 315 static final boolean At = true, Before = false; 316 testCodePoint(boolean isAt, StringBuffer sb, int index, int expected)317 static void testCodePoint(boolean isAt, StringBuffer sb, int index, int expected) { 318 int c = isAt ? sb.codePointAt(index) : sb.codePointBefore(index); 319 320 check(c != expected, 321 "codePoint" + (isAt ? "At" : "Before") + "(" + index + ") for <" 322 + sb + ">", c, expected); 323 } 324 testCodePoint(boolean isAt, StringBuffer sb, int index)325 static void testCodePoint(boolean isAt, StringBuffer sb, int index) { 326 boolean exceptionOccurred = false; 327 328 try { 329 int c = isAt ? sb.codePointAt(index) : sb.codePointBefore(index); 330 } 331 catch (StringIndexOutOfBoundsException e) { 332 exceptionOccurred = true; 333 } 334 check(!exceptionOccurred, 335 "codePoint" + (isAt ? "At" : "Before") + "(" + index + ") for <" 336 + sb + "> should throw StringIndexOutOfBoundsPointerException."); 337 } 338 testAppendCodePoint(int codePoint, Class expectedException)339 static void testAppendCodePoint(int codePoint, Class expectedException) { 340 try { 341 new StringBuffer().appendCodePoint(codePoint); 342 } catch (Exception e) { 343 if (expectedException.isInstance(e)) { 344 return; 345 } 346 throw new RuntimeException("Error: Unexpected exception", e); 347 } 348 check(true, "appendCodePoint(" + toHexString(codePoint) + ") didn't throw " 349 + expectedException.getName()); 350 } 351 testCodePointCount(StringBuffer sb, int beginIndex, int endIndex, Class expectedException)352 static void testCodePointCount(StringBuffer sb, int beginIndex, int endIndex, 353 Class expectedException) { 354 try { 355 int n = sb.codePointCount(beginIndex, endIndex); 356 } catch (Exception e) { 357 if (expectedException.isInstance(e)) { 358 return; 359 } 360 throw new RuntimeException("Error: Unexpected exception", e); 361 } 362 check(true, "codePointCount() didn't throw " + expectedException.getName()); 363 } 364 testOffsetByCodePoints(StringBuffer sb, int index, int offset, Class expectedException)365 static void testOffsetByCodePoints(StringBuffer sb, int index, int offset, 366 Class expectedException) { 367 try { 368 int n = sb.offsetByCodePoints(index, offset); 369 } catch (Exception e) { 370 if (expectedException.isInstance(e)) { 371 return; 372 } 373 throw new RuntimeException("Error: Unexpected exception", e); 374 } 375 check(true, "offsetByCodePoints() didn't throw " + expectedException.getName()); 376 } 377 check(boolean err, String msg)378 static void check(boolean err, String msg) { 379 if (err) { 380 throw new RuntimeException("Error: " + msg); 381 } 382 } 383 check(boolean err, String s, int got, int expected)384 static void check(boolean err, String s, int got, int expected) { 385 if (err) { 386 throw new RuntimeException("Error: " + s 387 + " returned an unexpected value. got " 388 + toHexString(got) 389 + ", expected " 390 + toHexString(expected)); 391 } 392 } 393 check(boolean err, String s, StringBuffer got, String expected)394 static void check(boolean err, String s, StringBuffer got, String expected) { 395 if (err) { 396 throw new RuntimeException("Error: " + s 397 + " returned an unexpected value. got <" 398 + toHexString(new String(got)) 399 + ">, expected <" 400 + toHexString(expected) 401 + ">"); 402 } 403 } 404 toHexString(int c)405 private static String toHexString(int c) { 406 return "0x" + Integer.toHexString(c); 407 } 408 toHexString(String s)409 private static String toHexString(String s) { 410 StringBuffer sb = new StringBuffer(); 411 for (int i = 0; i < s.length(); i++) { 412 char c = s.charAt(i); 413 414 sb.append(" 0x"); 415 if (c < 0x10) sb.append('0'); 416 if (c < 0x100) sb.append('0'); 417 if (c < 0x1000) sb.append('0'); 418 sb.append(Integer.toHexString(c)); 419 } 420 sb.append(' '); 421 return sb.toString(); 422 } 423 } 424