J. Duke | 319a3b9 | 2007-12-01 00:00:00 +0000 | [diff] [blame^] | 1 | /* |
| 2 | * Copyright 2003-2004 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, |
| 20 | * CA 95054 USA or visit www.sun.com if you need additional information or |
| 21 | * have any questions. |
| 22 | */ |
| 23 | |
| 24 | /* |
| 25 | * |
| 26 | * @test |
| 27 | * @bug 4533872 4915683 4985217 5017280 |
| 28 | * @summary Unit tests for supplementary character support (JSR-204) |
| 29 | */ |
| 30 | |
| 31 | public 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 supprementary characters 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 supprementary characters 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 | } |