blob: 32337b17edd243a5e70b8c7be54bd87b9cc9a808 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
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
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 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 StringBuilder sb = new StringBuilder(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 StringBuilder sb = new StringBuilder(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 StringBuilder sb = new StringBuilder(input[i]).reverse();
177
178 check(!golden3[i].equals(sb.toString()),
179 "reverse() for <" + toHexString(input[i]) + ">",
180 sb, golden3[i]);
181 }
182
183 for (int i = 0; i < testdata1.length; i++) {
184 StringBuilder sb = new StringBuilder(testdata1[i][0]).reverse();
185
186 check(!testdata1[i][1].equals(sb.toString()),
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 StringBuilder sb = new StringBuilder();
199 int c;
200 for (int j = 0; j < s.length(); j += Character.charCount(c)) {
201 c = s.codePointAt(j);
202 StringBuilder 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 StringBuilder sb = new StringBuilder(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 StringBuilder sb = new StringBuilder(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, StringBuilder 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, StringBuilder 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 StringBuilder().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(StringBuilder 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(StringBuilder 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, StringBuilder got, String expected) {
389 if (err) {
390 throw new RuntimeException("Error: " + s
391 + " returned an unexpected value. got <"
392 + toHexString(got.toString())
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 StringBuilder sb = new StringBuilder();
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}