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