1 /*
2  * Copyright (c) 2018, 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  * @test
26  * @bug 4533872 4985214 4985217 4993841 5017268 5017280
27  * @summary Unit tests for supplementary character support (JSR-204)
28  * @compile Supplementary.java
29  * @run main/timeout=600 Supplementary
30  */
31 
32 public class Supplementary {
33     private static final char MIN_HIGH = '\uD800';
34     private static final char MAX_HIGH = '\uDBFF';
35     private static final char MIN_LOW = MAX_HIGH + 1;
36     private static final char MAX_LOW = '\uDFFF';
37     private static final int MIN_CODE_POINT = 0x000000;
38     private static final int MIN_SUPPLEMENTARY = 0x010000;
39     private static final int MAX_SUPPLEMENTARY = 0x10ffff;
40 
main(String[] args)41     public static void main(String[] args) {
42         // Do not change the order of test method calls since there
43         // are some interdependencies.
44 
45         testConstants();
46 
47         test00();
48 
49         // Store all Unicode code points, except for surrogate code
50         // points, in cu[] through the loops below. Then, use the data
51         // for code point/code unit conversion and other tests later.
52         char[] cu = new char[(MAX_SUPPLEMENTARY+1) * 2];
53         int length = test01(cu);
54 
55         String str = new String(cu, 0, length);
56         cu = null;
57         test02(str);
58         test03(str.toCharArray());
59         test04(str);
60         test05(str);
61 
62         // Test for toString(int)
63         test06();
64 
65         // Test unpaired surrogates
66         testUnpaired();
67 
68         // Test exceptions
69         testExceptions00();
70         testExceptions01(str);
71         testExceptions02(str.toCharArray());
72     }
73 
testConstants()74     static void testConstants() {
75         if (Character.MIN_HIGH_SURROGATE != MIN_HIGH) {
76             constantError("MIN_HIGH_SURROGATE", Character.MIN_HIGH_SURROGATE, MIN_HIGH);
77         }
78         if (Character.MAX_HIGH_SURROGATE != MAX_HIGH) {
79             constantError("MAX_HIGH_SURROGATE", Character.MAX_HIGH_SURROGATE, MAX_HIGH);
80         }
81         if (Character.MIN_LOW_SURROGATE != MIN_LOW) {
82             constantError("MIN_LOW_SURROGATE", Character.MIN_LOW_SURROGATE, MIN_LOW);
83         }
84         if (Character.MAX_LOW_SURROGATE != MAX_LOW) {
85             constantError("MAX_LOW_SURROGATE", Character.MAX_LOW_SURROGATE, MAX_LOW);
86         }
87         if (Character.MIN_SURROGATE != MIN_HIGH) {
88             constantError("MIN_SURROGATE", Character.MIN_SURROGATE, MIN_HIGH);
89         }
90         if (Character.MAX_SURROGATE != MAX_LOW) {
91             constantError("MAX_SURROGATE", Character.MAX_SURROGATE, MAX_LOW);
92         }
93         if (Character.MIN_SUPPLEMENTARY_CODE_POINT != MIN_SUPPLEMENTARY) {
94             constantError("MIN_SUPPLEMENTARY_CODE_POINT",
95                           Character.MIN_SUPPLEMENTARY_CODE_POINT, MIN_SUPPLEMENTARY);
96         }
97         if (Character.MIN_CODE_POINT != MIN_CODE_POINT) {
98             constantError("MIN_CODE_POINT", Character.MIN_CODE_POINT, MIN_CODE_POINT);
99         }
100         if (Character.MAX_CODE_POINT != MAX_SUPPLEMENTARY) {
101             constantError("MAX_CODE_POINT", Character.MAX_CODE_POINT, MAX_SUPPLEMENTARY);
102         }
103     }
104 
constantError(String name, int value, int expectedValue)105     static void constantError(String name, int value, int expectedValue) {
106         throw new RuntimeException("Character." + name + " has a wrong value: got "
107                                    + toHexString(value)
108                                    + ", expected " + toHexString(expectedValue));
109     }
110 
111     /*
112      * Test isValidCodePoint(int)
113      *      isSupplementaryCodePoint(int)
114      *      charCount(int)
115      */
test00()116     static void test00() {
117         for (int cp = -MAX_SUPPLEMENTARY; cp <= MAX_SUPPLEMENTARY*2; cp++) {
118             boolean isValid = cp >= 0 && cp <= MAX_SUPPLEMENTARY;
119             if (Character.isValidCodePoint(cp) != isValid) {
120                 throw new RuntimeException("isValidCodePoint failed with "
121                                            + toHexString(cp));
122             }
123             boolean isSupplementary = cp >= MIN_SUPPLEMENTARY && cp <= MAX_SUPPLEMENTARY;
124             if (Character.isSupplementaryCodePoint(cp) != isSupplementary) {
125                 throw new RuntimeException("isSupplementaryCodePoint failed with "
126                                            + toHexString(cp));
127             }
128             int len = Character.charCount(cp);
129             if (isValid) {
130                 if ((isSupplementary && len != 2)
131                     || (!isSupplementary && len != 1)) {
132                     throw new RuntimeException("wrong character length "+len+" for "
133                                                + toHexString(cp));
134                 }
135             } else if (len != 1 && len != 2) {
136                 throw new RuntimeException("wrong character length "+len+" for "
137                                            + toHexString(cp));
138             }
139         }
140     }
141 
142     /**
143      * Test toChar(int)
144      *      toChar(int, char[], int)
145      *      isHighSurrogate(char)
146      *      isLowSurrogate(char)
147      *      isSurrogatePair(int, int)
148      *
149      * While testing those methods, this method generates all Unicode
150      * code points (except for surrogate code points) and store them
151      * in cu.
152      *
153      * @return the number of code units generated in cu
154      */
test01(char[] cu)155     static int test01(char[] cu) {
156         int index = 0;
157         // Test toChar(int)
158         //      toChar(int, char[], int)
159         //      isHighSurrogate(char)
160         //      isLowSurrogate(char)
161         // with BMP code points
162         for (int i = 0; i <= Character.MAX_VALUE; i++) {
163             char[] u = Character.toChars(i);
164             if (u.length != 1 || u[0] != i) {
165                 throw new RuntimeException("wrong toChars(int) result for BMP: "
166                                            + toHexString("u", u));
167             }
168             int n = Character.toChars(i, cu, index);
169             if (n != 1 || cu[index] != i) {
170                 throw new RuntimeException("wrong toChars(int, char[], int) result for BMP:"
171                                            + " len=" + n
172                                            + ", cu["+index+"]="+toHexString(cu[index]));
173             }
174             boolean isHigh = i >= MIN_HIGH && i <= MAX_HIGH;
175             if (Character.isHighSurrogate((char) i) != isHigh) {
176                 throw new RuntimeException("wrong high-surrogate test for "
177                                            + toHexString(i));
178             }
179             boolean isLow = i >= MIN_LOW && i <= MAX_LOW;
180             if (Character.isLowSurrogate((char)i) != isLow) {
181                 throw new RuntimeException("wrong low-surrogate test for "
182                                            + toHexString(i));
183             }
184             if (!isHigh && !isLow) {
185                 index++;
186             }
187         }
188 
189         // Test isSurrogatePair with all surrogate pairs
190         // Test toChars(int)
191         //      toChars(int, char[], int)
192         // with all supplementary characters
193         int supplementary = MIN_SUPPLEMENTARY;
194         for (int i = Character.MAX_VALUE/2; i <= Character.MAX_VALUE; i++) {
195             char hi = (char) i;
196             boolean isHigh = Character.isHighSurrogate(hi);
197 
198             for (int j = Character.MAX_VALUE/2; j <= Character.MAX_VALUE; j++) {
199                 char lo = (char) j;
200                 boolean isLow = Character.isLowSurrogate(lo);
201                 boolean isSurrogatePair = isHigh && isLow;
202                 if (Character.isSurrogatePair(hi, lo) != isSurrogatePair) {
203                     throw new RuntimeException("wrong surrogate pair test for hi="
204                                                + toHexString(hi)
205                                                + ", lo="+toHexString(lo));
206                 }
207                 if (isSurrogatePair) {
208                     int cp = Character.toCodePoint(hi, lo);
209                     if (cp != supplementary) {
210                         throw new RuntimeException("wrong code point: got "
211                                                    + toHexString(cp)
212                                                    + ", expected="
213                                                    + toHexString(supplementary));
214                     }
215                     char[] u = Character.toChars(cp);
216                     if (u.length != 2 || u[0] != hi || u[1] != lo) {
217                         throw new RuntimeException("wrong toChars(int) result for supplementary: "+
218                                                    toHexString("u", u));
219                     }
220                     int n = Character.toChars(cp, cu, index);
221                     if (n != 2 || cu[index] != hi || cu[index+1] != lo) {
222                         throw new RuntimeException("wrong toChars(int, char[], int) result "
223                                            + "for supplementary: len=" + n
224                                            + ", cu["+index+"]=" + toHexString(cu[index])
225                                            + ", cu["+(index+1)+"]=" + toHexString(cu[index+1]));
226                     }
227                     index += n;
228                     supplementary++;
229                 }
230             }
231         }
232         if (supplementary != MAX_SUPPLEMENTARY + 1) {
233             throw new RuntimeException("wrong supplementary count (supplementary="
234                                        + toHexString(supplementary)+")");
235         }
236 
237         int nCodeUnits = Character.MAX_VALUE + 1 - (MAX_LOW - MIN_HIGH + 1)
238                          + ((MAX_SUPPLEMENTARY - MIN_SUPPLEMENTARY + 1) * 2);
239         if (index != nCodeUnits) {
240             throw new RuntimeException("wrong number of code units: " + index
241                                        + ", expected " + nCodeUnits);
242         }
243         return index;
244     }
245 
246     /**
247      * Test codePointAt(CharSequence, int)
248      *      codePointBefore(CharSequence, int)
249      */
test02(CharSequence cs)250     static void test02(CharSequence cs) {
251         int cp = 0;
252         int ch;
253         for (int i = 0; i < cs.length(); i += Character.charCount(ch)) {
254             ch = Character.codePointAt(cs, i);
255             if (ch != cp) {
256                 throw new RuntimeException("wrong codePointAt(CharSequence, "+i+") value: got "
257                                            + toHexString(ch)
258                                            + ", expected "+toHexString(cp));
259             }
260             cp++;
261             // Skip surrogates
262             if (cp == MIN_HIGH) {
263                 cp = MAX_LOW + 1;
264             }
265         }
266 
267         cp--;
268         for (int i = cs.length(); i > 0; i -= Character.charCount(ch)) {
269             ch = Character.codePointBefore(cs, i);
270             if (ch != cp) {
271                 throw new RuntimeException("codePointBefore(CharSequence, "+i+") returned "
272                                            + toHexString(ch)
273                                            + ", expected " + toHexString(cp));
274             }
275             cp--;
276             // Skip surrogates
277             if (cp == MAX_LOW) {
278                 cp = MIN_HIGH - 1;
279             }
280         }
281     }
282 
283     /**
284      * Test codePointAt(char[], int)
285      *      codePointAt(char[], int, int)
286      *      codePointBefore(char[], int)
287      *      codePointBefore(char[], int, int)
288      */
test03(char[] a)289     static void test03(char[] a) {
290         int cp = 0;
291         int ch;
292         for (int i = 0; i < a.length; i += Character.charCount(ch)) {
293             ch = Character.codePointAt(a, i);
294             if (ch != cp) {
295                 throw new RuntimeException("codePointAt(char[], "+i+") returned "
296                                            + toHexString(ch)
297                                            + ", expected "+toHexString(cp));
298             }
299             int x = Character.codePointAt(a, i, i+1);
300             if (x != a[i]) {
301                 throw new RuntimeException(String.format(
302                                  "codePointAt(char[], %d, %d) returned 0x%04x, expected 0x%04x\n",
303                                  i, i+1, x, (int)a[i]));
304             }
305             cp++;
306             // Skip surrogates
307             if (cp == MIN_HIGH) {
308                 cp = MAX_LOW + 1;
309             }
310         }
311 
312         cp--;
313         for (int i = a.length; i > 0; i -= Character.charCount(ch)) {
314             ch = Character.codePointBefore(a, i);
315             if (ch != cp) {
316                 throw new RuntimeException("codePointBefore(char[], "+i+") returned "
317                                            + toHexString(ch)
318                                            + ", expected " + toHexString(cp));
319             }
320             int x = Character.codePointBefore(a, i, i-1);
321             if (x != a[i-1]) {
322                 throw new RuntimeException(String.format(
323                                  "codePointAt(char[], %d, %d) returned 0x%04x, expected 0x%04x\n",
324                                  i, i-1, x, (int)a[i-1]));
325             }
326             cp--;
327             // Skip surrogates
328             if (cp == MAX_LOW) {
329                 cp = MIN_HIGH - 1;
330             }
331         }
332     }
333 
334     /**
335      * Test codePointCount(CharSequence, int, int)
336      *      codePointCount(char[], int, int, int, int)
337      */
test04(String str)338     static void test04(String str) {
339         int length = str.length();
340         char[] a = str.toCharArray();
341 
342         for (int i = 0; i <= length; i += 99, length -= 29999) {
343             int n = Character.codePointCount(str, i, length);
344             int m = codePointCount(str.substring(i, length));
345             checkCodePointCount(str, n, m);
346             n = Character.codePointCount(a, i, length - i);
347             checkCodePointCount(a, n, m);
348         }
349 
350         // test special cases
351         length = str.length();
352         int n = Character.codePointCount(str, 0, 0);
353         checkCodePointCount(str, n, 0);
354         n = Character.codePointCount(str, length, length);
355         checkCodePointCount(str, n, 0);
356         n = Character.codePointCount(a, 0, 0);
357         checkCodePointCount(a, n, 0);
358         n = Character.codePointCount(a, length, 0);
359         checkCodePointCount(a, n, 0);
360     }
361 
362     // This method assumes that Character.codePointAt() and
363     // Character.charCount() work correctly.
codePointCount(CharSequence seq)364     private static int codePointCount(CharSequence seq) {
365         int n = 0, len;
366         for (int i = 0; i < seq.length(); i += len) {
367             int codepoint = Character.codePointAt(seq, i);
368             n++;
369             len = Character.charCount(codepoint);
370         }
371         return n;
372     }
373 
checkCodePointCount(Object data, int n, int expected)374     private static void checkCodePointCount(Object data, int n, int expected) {
375         String type = getType(data);
376         if (n != expected) {
377             throw new RuntimeException("codePointCount(" + type + "...) returned " + n
378                                        + ", expected " + expected);
379         }
380     }
381 
382     /**
383      * Test offsetByCodePoints(CharSequence, int, int)
384      *      offsetByCodePoints(char[], int, int, int, int)
385      *
386      * This test case assumes that Character.codePointCount()s work
387      * correctly.
388      */
test05(String str)389     static void test05(String str) {
390         int length = str.length();
391         char[] a = str.toCharArray();
392 
393         for (int i = 0; i <= length; i += 99, length -= 29999) {
394             int nCodePoints = Character.codePointCount(a, i, length - i);
395             int index;
396 
397             // offsetByCodePoints(CharSequence, int, int)
398 
399             int expectedHighIndex = length;
400             // For forward CharSequence scan, we need to adjust the
401             // expected index in case the last char in the text range
402             // is a high surrogate and forms a valid supplementary
403             // code point with the next char.
404             if (length < a.length) {
405                 int cp = Character.codePointAt(a, length - 1);
406                 if (Character.isSupplementaryCodePoint(cp)) {
407                     expectedHighIndex++;
408                 }
409             }
410             index = Character.offsetByCodePoints(str, i, nCodePoints);
411             checkNewIndex(str, nCodePoints, index, expectedHighIndex);
412             int expectedLowIndex = i;
413             if (i > 0) {
414                 int cp = Character.codePointBefore(a, i + 1);
415                 if (Character.isSupplementaryCodePoint(cp)) {
416                     expectedLowIndex--;
417                 }
418             }
419             index = Character.offsetByCodePoints(str, length, -nCodePoints);
420             checkNewIndex(str, -nCodePoints, index, expectedLowIndex);
421 
422             // offsetByCodePoints(char[], int, int, int, int)
423 
424             int start = Math.max(0, i-1);
425             int limit = Math.min(a.length, length+1);
426             index = Character.offsetByCodePoints(a, start, limit - start,
427                                                  i, nCodePoints);
428             checkNewIndex(a, nCodePoints, index, expectedHighIndex);
429             if (length != expectedHighIndex) {
430                 index = Character.offsetByCodePoints(a, start, length - start,
431                                                      i, nCodePoints);
432                 checkNewIndex(a, nCodePoints, index, length);
433             }
434             index = Character.offsetByCodePoints(a, start, limit - start,
435                                                  length, -nCodePoints);
436             checkNewIndex(a, -nCodePoints, index, expectedLowIndex);
437             if (i != expectedLowIndex) {
438                 index = Character.offsetByCodePoints(a, i, limit - i,
439                                                      length, -nCodePoints);
440                 checkNewIndex(a, -nCodePoints, index, i);
441             }
442         }
443 
444         // test special cases for 0-length text ranges.
445         length = str.length();
446         int index = Character.offsetByCodePoints(str, 0, 0);
447         checkNewIndex(str, 0, index, 0);
448         index = Character.offsetByCodePoints(str, length, 0);
449         checkNewIndex(str, 0, index, length);
450         index = Character.offsetByCodePoints(a, 0, 0, 0, 0);
451         checkNewIndex(a, 0, index, 0);
452         index = Character.offsetByCodePoints(a, 0, length, 0, 0);
453         checkNewIndex(a, 0, index, 0);
454         index = Character.offsetByCodePoints(a, 0, length, length, 0);
455         checkNewIndex(a, 0, index, length);
456         index = Character.offsetByCodePoints(a, length, 0, length, 0);
457         checkNewIndex(a, 0, index, length);
458     }
459 
460     /**
461      * Test toString(int)
462      *
463      * This test case assumes that Character.toChars()/String(char[]) work
464      * correctly.
465      */
test06()466     static void test06() {
467         for (int cp = Character.MIN_CODE_POINT; cp <= Character.MAX_CODE_POINT; cp++) {
468             String result = Character.toString(cp);
469             String expected = new String(Character.toChars(cp));
470             if (!result.equals(expected)) {
471                 throw new RuntimeException("Wrong string is created. code point: " +
472                     cp + ", result: " + result + ", expected: " + expected);
473             }
474         }
475     }
476 
checkNewIndex(Object data, int offset, int result, int expected)477     private static void checkNewIndex(Object data, int offset, int result, int expected) {
478         String type = getType(data);
479         String offsetType = (offset > 0) ? "positive" : (offset < 0) ? "negative" : "0";
480         if (result != expected) {
481             throw new RuntimeException("offsetByCodePoints(" + type + ", ...) ["
482                                        + offsetType + " offset]"
483                                        + " returned " + result
484                                        + ", expected " + expected);
485         }
486     }
487 
488     // Test codePointAt(CharSequence, int)
489     //      codePointBefore(CharSequence, int)
490     //      codePointAt(char[], int)
491     //      codePointBefore(char[], int)
492     //      toChar(int)
493     //      toChar(int, char[], int)
494     // with unpaired surrogates
testUnpaired()495     static void testUnpaired() {
496         testCodePoint("\uD800", new int[] { 0xD800 });
497         testCodePoint("\uDC00", new int[] { 0xDC00 });
498         testCodePoint("a\uD800", new int[] { 'a', 0xD800 });
499         testCodePoint("a\uDC00", new int[] { 'a', 0xDC00 });
500         testCodePoint("\uD800a", new int[] { 0xD800, 'a' });
501         testCodePoint("\uDBFFa", new int[] { 0xDBFF, 'a' });
502         testCodePoint("a\uD800\uD801", new int[] { 'a', 0xD800, 0xD801 });
503         testCodePoint("a\uD800x\uDC00", new int[] { 'a', 0xD800, 'x', 0xDC00 });
504         testCodePoint("\uDC00\uD800", new int[] { 0xDC00, 0xD800 });
505         testCodePoint("\uD800\uDC00\uDC00", new int[] { 0x10000, 0xDC00 });
506         testCodePoint("\uD800\uD800\uDC00", new int[] { 0xD800, 0x10000 });
507         testCodePoint("\uD800\uD800\uD800\uD800\uDC00\uDC00\uDC00\uDC00",
508                       new int[] { 0xD800, 0xD800, 0xD800, 0x10000, 0xDC00, 0xDC00, 0xDC00});
509     }
510 
testCodePoint(String str, int[] codepoints)511     static void testCodePoint(String str, int[] codepoints) {
512         int c;
513         // Test Character.codePointAt/Before(CharSequence, int)
514         int j = 0;
515         for (int i = 0; i < str.length(); i += Character.charCount(c)) {
516             c = Character.codePointAt(str, i);
517             if (c != codepoints[j++]) {
518                 throw new RuntimeException("codePointAt(CharSequence, " + i + ") returned "
519                                            + toHexString(c)
520                                            + ", expected " + toHexString(codepoints[j-1]));
521             }
522         }
523         if (j != codepoints.length) {
524             throw new RuntimeException("j != codepoints.length after codePointAt(CharSequence, int)"
525                                        + " (j=" + j + ")"
526                                        + ", expected: " + codepoints.length);
527         }
528 
529         j = codepoints.length;
530         for (int i = str.length(); i > 0 ; i -= Character.charCount(c)) {
531             c = Character.codePointBefore(str, i);
532             if (c != codepoints[--j]) {
533                 throw new RuntimeException("codePointBefore(CharSequence, " + i + ") returned "
534                                            + toHexString(c)
535                                            + ", expected " + toHexString(codepoints[j]));
536             }
537         }
538         if (j != 0) {
539             throw new RuntimeException("j != 0 after codePointBefore(CharSequence, int)"
540                                        + " (j=" + j + ")");
541         }
542 
543         // Test Character.codePointAt/Before(char[], int)
544         char[] a = str.toCharArray();
545         j = 0;
546         for (int i = 0; i < a.length; i += Character.charCount(c)) {
547             c = Character.codePointAt(a, i);
548             if (c != codepoints[j++]) {
549                 throw new RuntimeException("codePointAt(char[], " + i + ") returned "
550                                            + toHexString(c)
551                                            + ", expected " + toHexString(codepoints[j-1]));
552             }
553         }
554         if (j != codepoints.length) {
555             throw new RuntimeException("j != codepoints.length after codePointAt(char[], int)"
556                                        + " (j=" + j + ")"
557                                        + ", expected: " + codepoints.length);
558         }
559 
560         j = codepoints.length;
561         for (int i = a.length; i > 0 ; i -= Character.charCount(c)) {
562             c = Character.codePointBefore(a, i);
563             if (c != codepoints[--j]) {
564                 throw new RuntimeException("codePointBefore(char[], " + i + ") returned "
565                                            + toHexString(c)
566                                            + ", expected " + toHexString(codepoints[j]));
567             }
568         }
569         if (j != 0) {
570             throw new RuntimeException("j != 0 after codePointBefore(char[], int)"
571                                        + " (j=" + j + ")");
572         }
573 
574         // Test toChar(int)
575         j = 0;
576         for (int i = 0; i < codepoints.length; i++) {
577             a = Character.toChars(codepoints[i]);
578             for (int k = 0; k < a.length; k++) {
579                 if (str.charAt(j++) != a[k]) {
580                     throw new RuntimeException("toChars(int) returned " + toHexString("result", a)
581                                                + " from codepoint=" + toHexString(codepoints[i]));
582                 }
583             }
584         }
585 
586         // Test toChars(int, char[], int)
587         a = new char[codepoints.length * 2];
588         j = 0;
589         for (int i = 0; i < codepoints.length; i++) {
590             int n = Character.toChars(codepoints[i], a, j);
591             j += n;
592         }
593         String s = new String(a, 0, j);
594         if (!str.equals(s)) {
595             throw new RuntimeException("toChars(int, char[], int) returned "
596                                        + toHexString("dst", s.toCharArray())
597                                        + ", expected " + toHexString("data", str.toCharArray()));
598         }
599     }
600 
601     // Test toChar(int)
602     //      toChar(int, char[], int)
603     //      toString(int)
604     // for exceptions
testExceptions00()605     static void testExceptions00() {
606         callToChars1(-1, IllegalArgumentException.class);
607         callToChars1(MAX_SUPPLEMENTARY + 1, IllegalArgumentException.class);
608 
609         callToChars3(MAX_SUPPLEMENTARY, null, 0, NullPointerException.class);
610         callToChars3(-MIN_SUPPLEMENTARY,    new char[2], 0, IllegalArgumentException.class);
611         callToChars3(MAX_SUPPLEMENTARY + 1, new char[2], 0, IllegalArgumentException.class);
612         callToChars3('A', new char[0],  0, IndexOutOfBoundsException.class);
613         callToChars3('A', new char[1], -1, IndexOutOfBoundsException.class);
614         callToChars3('A', new char[1],  1, IndexOutOfBoundsException.class);
615         callToChars3(MIN_SUPPLEMENTARY, new char[0],  0, IndexOutOfBoundsException.class);
616         callToChars3(MIN_SUPPLEMENTARY, new char[1],  0, IndexOutOfBoundsException.class);
617         callToChars3(MIN_SUPPLEMENTARY, new char[2], -1, IndexOutOfBoundsException.class);
618         callToChars3(MIN_SUPPLEMENTARY, new char[2],  1, IndexOutOfBoundsException.class);
619 
620         callToString(Character.MIN_CODE_POINT - 1, IllegalArgumentException.class);
621         callToString(Character.MAX_CODE_POINT + 1, IllegalArgumentException.class);
622     }
623 
624     static final boolean At = true, Before = false;
625 
626     /**
627      * Test codePointAt(CharSequence, int)
628      *      codePointBefore(CharSequence, int)
629      *      codePointCount(CharSequence, int, int)
630      *      offsetByCodePoints(CharSequence, int, int)
631      * for exceptions
632      */
testExceptions01(CharSequence cs)633     static void testExceptions01(CharSequence cs) {
634         CharSequence nullSeq = null;
635         // codePointAt
636         callCodePoint(At, nullSeq, 0, NullPointerException.class);
637         callCodePoint(At, cs, -1, IndexOutOfBoundsException.class);
638         callCodePoint(At, cs, cs.length(), IndexOutOfBoundsException.class);
639         callCodePoint(At, cs, cs.length()*3, IndexOutOfBoundsException.class);
640 
641         // codePointBefore
642         callCodePoint(Before, nullSeq, 0, NullPointerException.class);
643         callCodePoint(Before, cs, -1, IndexOutOfBoundsException.class);
644         callCodePoint(Before, cs, 0, IndexOutOfBoundsException.class);
645         callCodePoint(Before, cs, cs.length()+1, IndexOutOfBoundsException.class);
646 
647         // codePointCount
648         callCodePointCount(nullSeq, 0, 0, NullPointerException.class);
649         callCodePointCount(cs, -1, 1, IndexOutOfBoundsException.class);
650         callCodePointCount(cs, 0, cs.length()+1, IndexOutOfBoundsException.class);
651         callCodePointCount(cs, 3, 1, IndexOutOfBoundsException.class);
652 
653         // offsetByCodePoints
654         callOffsetByCodePoints(nullSeq, 0, 0, NullPointerException.class);
655         callOffsetByCodePoints(cs, -1, 1, IndexOutOfBoundsException.class);
656         callOffsetByCodePoints(cs, cs.length()+1, 1, IndexOutOfBoundsException.class);
657         callOffsetByCodePoints(cs, 0, cs.length()*2, IndexOutOfBoundsException.class);
658         callOffsetByCodePoints(cs, cs.length(), 1, IndexOutOfBoundsException.class);
659         callOffsetByCodePoints(cs, 0, -1, IndexOutOfBoundsException.class);
660         callOffsetByCodePoints(cs, cs.length(), -cs.length()*2,
661                                IndexOutOfBoundsException.class);
662         callOffsetByCodePoints(cs, cs.length(), Integer.MIN_VALUE,
663                                IndexOutOfBoundsException.class);
664         callOffsetByCodePoints(cs, 0, Integer.MAX_VALUE, IndexOutOfBoundsException.class);
665     }
666 
667     /**
668      * Test codePointAt(char[], int)
669      *      codePointAt(char[], int, int)
670      *      codePointBefore(char[], int)
671      *      codePointBefore(char[], int, int)
672      *      codePointCount(char[], int, int)
673      *      offsetByCodePoints(char[], int, int, int, int)
674      * for exceptions
675      */
testExceptions02(char[] a)676     static void testExceptions02(char[] a) {
677         char[] nullArray = null;
678         callCodePoint(At, nullArray, 0, NullPointerException.class);
679         callCodePoint(At, a, -1, IndexOutOfBoundsException.class);
680         callCodePoint(At, a, a.length, IndexOutOfBoundsException.class);
681         callCodePoint(At, a, a.length*3, IndexOutOfBoundsException.class);
682         callCodePoint(Before, nullArray, 0, NullPointerException.class);
683         callCodePoint(Before, a, -1, IndexOutOfBoundsException.class);
684         callCodePoint(Before, a, 0, IndexOutOfBoundsException.class);
685         callCodePoint(Before, a, a.length+1, IndexOutOfBoundsException.class);
686 
687         // tests for the methods with limit
688         callCodePoint(At, nullArray, 0, 1, NullPointerException.class);
689         callCodePoint(At, a, 0, -1, IndexOutOfBoundsException.class);
690         callCodePoint(At, a, 0, 0, IndexOutOfBoundsException.class);
691         callCodePoint(At, a, 0, a.length+1, IndexOutOfBoundsException.class);
692         callCodePoint(At, a, 2, 1, IndexOutOfBoundsException.class);
693         callCodePoint(At, a, -1, 1, IndexOutOfBoundsException.class);
694         callCodePoint(At, a, a.length, 1, IndexOutOfBoundsException.class);
695         callCodePoint(At, a, a.length*3, 1, IndexOutOfBoundsException.class);
696         callCodePoint(Before, nullArray, 1, 0, NullPointerException.class);
697         callCodePoint(Before, a, 2, -1, IndexOutOfBoundsException.class);
698         callCodePoint(Before, a, 2, 2, IndexOutOfBoundsException.class);
699         callCodePoint(Before, a, 2, 3, IndexOutOfBoundsException.class);
700         callCodePoint(Before, a, 2, a.length, IndexOutOfBoundsException.class);
701         callCodePoint(Before, a, -1, -1, IndexOutOfBoundsException.class);
702         callCodePoint(Before, a, 0, 0, IndexOutOfBoundsException.class);
703         callCodePoint(Before, a, a.length+1, a.length-1, IndexOutOfBoundsException.class);
704 
705         // codePointCount
706         callCodePointCount(nullArray, 0, 0, NullPointerException.class);
707         callCodePointCount(a, -1, 1, IndexOutOfBoundsException.class);
708         callCodePointCount(a, 0, -1, IndexOutOfBoundsException.class);
709         callCodePointCount(a, 0, a.length+1, IndexOutOfBoundsException.class);
710         callCodePointCount(a, 1, a.length, IndexOutOfBoundsException.class);
711         callCodePointCount(a, a.length, 1, IndexOutOfBoundsException.class);
712         callCodePointCount(a, a.length+1, -1, IndexOutOfBoundsException.class);
713 
714         // offsetByCodePoints
715         callOffsetByCodePoints(nullArray, 0, 0, 0, 0,  NullPointerException.class);
716         callOffsetByCodePoints(a, -1, a.length, 1, 1, IndexOutOfBoundsException.class);
717         callOffsetByCodePoints(a, 0, a.length+1, 1, 1, IndexOutOfBoundsException.class);
718         callOffsetByCodePoints(a, 10, a.length, 1, 1, IndexOutOfBoundsException.class);
719         callOffsetByCodePoints(a, 10, a.length-10, 1, 1, IndexOutOfBoundsException.class);
720         callOffsetByCodePoints(a, 10, 10, 21, 1, IndexOutOfBoundsException.class);
721         callOffsetByCodePoints(a, 20, -10, 15, 1, IndexOutOfBoundsException.class);
722         callOffsetByCodePoints(a, 10, 10, 15, 20, IndexOutOfBoundsException.class);
723         callOffsetByCodePoints(a, 10, 10, 15, -20, IndexOutOfBoundsException.class);
724         callOffsetByCodePoints(a, 0, a.length, -1, 1, IndexOutOfBoundsException.class);
725         callOffsetByCodePoints(a, 0, a.length, a.length+1, 1, IndexOutOfBoundsException.class);
726         callOffsetByCodePoints(a, 0, a.length, 0, a.length*2, IndexOutOfBoundsException.class);
727         callOffsetByCodePoints(a, 0, a.length, a.length, 1, IndexOutOfBoundsException.class);
728         callOffsetByCodePoints(a, 0, a.length, 0, -1, IndexOutOfBoundsException.class);
729         callOffsetByCodePoints(a, 0, a.length, a.length, -a.length*2,
730                                IndexOutOfBoundsException.class);
731         callOffsetByCodePoints(a, 0, a.length, a.length, Integer.MIN_VALUE,
732                                IndexOutOfBoundsException.class);
733         callOffsetByCodePoints(a, 0, a.length, 0, Integer.MAX_VALUE,
734                                IndexOutOfBoundsException.class);
735     }
736 
737     /**
738      * Test the 1-arg toChars(int) for exceptions
739      */
callToChars1(int codePoint, Class expectedException)740     private static void callToChars1(int codePoint, Class expectedException) {
741         try {
742             char[] a = Character.toChars(codePoint);
743         } catch (Exception e) {
744             if (expectedException.isInstance(e)) {
745                 return;
746             }
747             throw new RuntimeException("Unspecified exception", e);
748         }
749         throw new RuntimeException("toChars(int) didn't throw " + expectedException.getName());
750     }
751 
752     /**
753      * Test the 3-arg toChars(int, char[], int) for exceptions
754      */
callToChars3(int codePoint, char[] dst, int index, Class expectedException)755     private static void callToChars3(int codePoint, char[] dst, int index,
756                                      Class expectedException) {
757         try {
758             int n = Character.toChars(codePoint, dst, index);
759         } catch (Exception e) {
760             if (expectedException.isInstance(e)) {
761                 return;
762             }
763             throw new RuntimeException("Unspecified exception", e);
764         }
765         throw new RuntimeException("toChars(int,char[],int) didn't throw "
766                                    + expectedException.getName());
767     }
768 
callCodePoint(boolean isAt, CharSequence cs, int index, Class expectedException)769     private static void callCodePoint(boolean isAt, CharSequence cs, int index,
770                                       Class expectedException) {
771         try {
772             int c = isAt ? Character.codePointAt(cs, index)
773                          : Character.codePointBefore(cs, index);
774         } catch (Exception e) {
775             if (expectedException.isInstance(e)) {
776                 return;
777             }
778             throw new RuntimeException("Unspecified exception", e);
779         }
780         throw new RuntimeException("codePoint" + (isAt ? "At" : "Before")
781                                    + " didn't throw " + expectedException.getName());
782     }
783 
callCodePoint(boolean isAt, char[] a, int index, Class expectedException)784     private static void callCodePoint(boolean isAt, char[] a, int index,
785                                       Class expectedException) {
786         try {
787             int c = isAt ? Character.codePointAt(a, index)
788                          : Character.codePointBefore(a, index);
789         } catch (Exception e) {
790             if (expectedException.isInstance(e)) {
791                 return;
792             }
793             throw new RuntimeException("Unspecified exception", e);
794         }
795         throw new RuntimeException("codePoint" + (isAt ? "At" : "Before")
796                                    + " didn't throw " + expectedException.getName());
797     }
798 
callCodePoint(boolean isAt, char[] a, int index, int limit, Class expectedException)799     private static void callCodePoint(boolean isAt, char[] a, int index, int limit,
800                                       Class expectedException) {
801         try {
802             int c = isAt ? Character.codePointAt(a, index, limit)
803                          : Character.codePointBefore(a, index, limit);
804         } catch (Exception e) {
805             if (expectedException.isInstance(e)) {
806                 return;
807             }
808             throw new RuntimeException("Unspecified exception", e);
809         }
810         throw new RuntimeException("codePoint" + (isAt ? "At" : "Before")
811                                    + " didn't throw " + expectedException.getName());
812     }
813 
callCodePointCount(Object data, int beginIndex, int endIndex, Class expectedException)814     private static void callCodePointCount(Object data, int beginIndex, int endIndex,
815                                            Class expectedException) {
816         String type = getType(data);
817         try {
818             int n = (data instanceof CharSequence) ?
819                   Character.codePointCount((CharSequence) data, beginIndex, endIndex)
820                 : Character.codePointCount((char[]) data, beginIndex, endIndex);
821         } catch (Exception e) {
822             if (expectedException.isInstance(e)) {
823                 return;
824             }
825             throw new RuntimeException("Unspecified exception", e);
826         }
827         throw new RuntimeException("codePointCount(" + type + "...) didn't throw "
828                                    + expectedException.getName());
829     }
830 
callOffsetByCodePoints(CharSequence seq, int index, int offset, Class expectedException)831     private static void callOffsetByCodePoints(CharSequence seq, int index, int offset,
832                                                Class expectedException) {
833         try {
834             int n = Character.offsetByCodePoints(seq, index, offset);
835         } catch (Exception e) {
836             if (expectedException.isInstance(e)) {
837                 return;
838             }
839             throw new RuntimeException("Unspecified exception", e);
840         }
841         throw new RuntimeException("offsetCodePointCounts(CharSequnce...) didn't throw "
842                                    + expectedException.getName());
843     }
844 
845 
callOffsetByCodePoints(char[] a, int start, int count, int index, int offset, Class expectedException)846     private static void callOffsetByCodePoints(char[] a, int start, int count,
847                                                int index, int offset,
848                                                Class expectedException) {
849         try {
850             int n = Character.offsetByCodePoints(a, start, count, index, offset);
851         } catch (Exception e) {
852             if (expectedException.isInstance(e)) {
853                 return;
854             }
855             throw new RuntimeException("Unspecified exception", e);
856         }
857         throw new RuntimeException("offsetCodePointCounts(char[]...) didn't throw "
858                                    + expectedException.getName());
859     }
860 
callToString(int codePoint, Class expectedException)861     private static void callToString(int codePoint, Class expectedException) {
862         try {
863             String s = Character.toString(codePoint);
864         } catch (Exception e) {
865             if (expectedException.isInstance(e)) {
866                 return;
867             }
868             throw new RuntimeException("Unspecified exception", e);
869         }
870         throw new RuntimeException("toString(int) didn't throw "
871                                    + expectedException.getName());
872     }
873 
getType(Object data)874     private static String getType(Object data) {
875         return (data instanceof CharSequence) ? "CharSequence" : "char[]";
876     }
877 
toHexString(int c)878     private static String toHexString(int c) {
879         return "0x" + Integer.toHexString(c);
880     }
881 
toHexString(String name, char[] a)882     private static String toHexString(String name, char[] a) {
883         StringBuffer sb = new StringBuffer();
884         for (int i = 0; i < a.length; i++) {
885             if (i > 0) {
886                 sb.append(", ");
887             }
888             sb.append(name).append('[').append(i).append("]=");
889             sb.append(toHexString(a[i]));
890         }
891         return sb.toString();
892     }
893 }
894