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