/*
* Copyright ( c ) 2003 , 2020 , Oracle and / or its affiliates . All rights reserved .
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER .
*
* This code is free software ; you can redistribute it and / or modify it
* under the terms of the GNU General Public License version 2 only , as
* published by the Free Software Foundation .
*
* This code is distributed in the hope that it will be useful , but WITHOUT
* ANY WARRANTY ; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE . See the GNU General Public License
* version 2 for more details ( a copy is included in the LICENSE file that
* accompanied this code ) .
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work ; if not , write to the Free Software Foundation ,
* Inc . , 51 Franklin St , Fifth Floor , Boston , MA 02110 - 1301 USA .
*
* Please contact Oracle , 500 Oracle Parkway , Redwood Shores , CA 94065 USA
* or visit www . oracle . com if you need additional information or have any
* questions .
*/
/*
*
* @ test
* @ bug 4533872 4915683 4985217 5017280 6937112
* @ summary Unit tests for supplementary character support ( JSR - 204 )
*/
import java.util.HexFormat;
public class Supplementary {
public static void main(String[] args) {
test1(); // Test for codePointAt(int index)
test2(); // Test for codePointBefore(int index)
test3(); // Test for reverse()
test4(); // Test for appendCodePoint(int codePoint)
test5(); // Test for codePointCount(int beginIndex, int endIndex)
test6(); // Test for offsetByCodePoints(int index, int offset)
}
/* Text strings which are used as input data.
* The comment above each text string means the index of each 16 - bit char
* for convenience .
*/
static final String[] input = {
/* 111 1 111111 22222
0123 4 5678 9 012 3 456789 01234 */
"abc\uD800\uDC00def\uD800\uD800ab\uD800\uDC00cdefa\uDC00bcdef" ,
/* 1 1111 1111 1 222
0 12345 6789 0 1234 5678 9 012 */
"\uD800defg\uD800hij\uD800\uDC00klm\uDC00nop\uDC00\uD800rt\uDC00" ,
/* 11 1 1111 1 112 222
0 12345 6 78901 2 3456 7 890 123 */
"\uDC00abcd\uDBFF\uDFFFefgh\uD800\uDC009ik\uDC00\uDC00lm\uDC00no\uD800" ,
/* 111 111111 1 22 2
0 1 2345 678 9 012 345678 9 01 2 */
"\uD800\uDC00!#$\uD800%&\uD800\uDC00;+\uDC00<>;=^\uDC00\\@\uD800\uDC00" ,
// includes an undefined supplementary character in Unicode 4.0.0
/* 1 11 1 1111 1
0 1 2345 6 789 0 12 3 4567 8 */
"\uDB40\uDE00abc\uDE01\uDB40de\uDB40\uDE02f\uDB40\uDE03ghi\uDB40\uDE02" ,
};
/* Expected results for:
* test1 ( ) : for codePointAt ( )
*
* Each character in each array is the golden data for each text string
* in the above input data . For example , the first data in each array is
* for the first input string .
*/
static final int [][] golden1 = {
{'a' , 0 xD800, 0 xDC00, 0 x10000, 0 xE0200}, // codePointAt(0)
{0 xD800, 0 x10000, 'g' , 0 xDC00, 0 xE0202}, // codePointAt(9)
{'f' , 0 xDC00, 0 xD800, 0 xDC00, 0 xDE02}, // codePointAt(length-1)
};
/*
* Test for codePointAt ( int index ) method
*/
static void test1() {
for (int i = 0 ; i < input.length; i++) {
StringBuffer sb = new StringBuffer(input[i]);
/*
* Normal case
*/
testCodePoint(At, sb, 0 , golden1[0 ][i]);
testCodePoint(At, sb, 9 , golden1[1 ][i]);
testCodePoint(At, sb, sb.length()-1 , golden1[2 ][i]);
/*
* Abnormal case - verify that an exception is thrown .
*/
testCodePoint(At, sb, -1 );
testCodePoint(At, sb, sb.length());
}
}
/* Expected results for:
* test2 ( ) : for codePointBefore ( )
*
* Each character in each array is the golden data for each text string
* in the above input data . For example , the first data in each array is
* for the first input string .
*/
static final int [][] golden2 = {
{'a' , 0 xD800, 0 xDC00, 0 xD800, 0 xDB40}, // codePointBefore(1)
{0 xD800, 'l' , 0 x10000, 0 xDC00, 0 xDB40}, // codePointBefore(13)
{'f' , 0 xDC00, 0 xD800, 0 x10000, 0 xE0202}, // codePointBefore(length)
};
/*
* Test for codePointBefore ( int index ) method
*/
static void test2() {
for (int i = 0 ; i < input.length; i++) {
StringBuffer sb = new StringBuffer(input[i]);
/*
* Normal case
*/
testCodePoint(Before, sb, 1 , golden2[0 ][i]);
testCodePoint(Before, sb, 13 , golden2[1 ][i]);
testCodePoint(Before, sb, sb.length(), golden2[2 ][i]);
/*
* Abnormal case - verify that an exception is thrown .
*/
testCodePoint(Before, sb, 0 );
testCodePoint(Before, sb, sb.length()+1 );
}
}
/* Expected results for:
* test3 ( ) : for reverse ( )
*
* Unlike golden1 and golden2 , each array is the golden data for each text
* string in the above input data . For example , the first array is for
* the first input string .
*/
static final String[] golden3 = {
"fedcb\uDC00afedc\uD800\uDC00ba\uD800\uD800fed\uD800\uDC00cba" ,
"\uDC00tr\uD800\uDC00pon\uDC00mlk\uD800\uDC00jih\uD800gfed\uD800" ,
"\uD800on\uDC00ml\uDC00\uDC00ki9\uD800\uDC00hgfe\uDBFF\uDFFFdcba\uDC00" ,
"\uD800\uDC00@\\\uDC00^=;><\uDC00+;\uD800\uDC00&%\uD800$#!\uD800\uDC00" ,
// includes an undefined supplementary character in Unicode 4.0.0
"\uDB40\uDE02ihg\uDB40\uDE03f\uDB40\uDE02ed\uDB40\uDE01cba\uDB40\uDE00" ,
};
// Additional input data & expected result for test3()
static final String[][] testdata1 = {
{"a\uD800\uDC00" , "\uD800\uDC00a" },
{"a\uDC00\uD800" , "\uD800\uDC00a" },
{"\uD800\uDC00a" , "a\uD800\uDC00" },
{"\uDC00\uD800a" , "a\uD800\uDC00" },
{"\uDC00\uD800\uD801" , "\uD801\uD800\uDC00" },
{"\uDC00\uD800\uDC01" , "\uD800\uDC01\uDC00" },
{"\uD801\uD800\uDC00" , "\uD800\uDC00\uD801" },
{"\uD800\uDC01\uDC00" , "\uDC00\uD800\uDC01" },
{"\uD800\uDC00\uDC01\uD801" , "\uD801\uDC01\uD800\uDC00" },
};
/*
* Test for reverse ( ) method
*/
static void test3() {
for (int i = 0 ; i < input.length; i++) {
StringBuffer sb = new StringBuffer(input[i]).reverse();
check(!golden3[i].equals(new String(sb)),
"reverse() for <" + toHexString(input[i]) + ">" ,
sb, golden3[i]);
}
for (int i = 0 ; i < testdata1.length; i++) {
StringBuffer sb = new StringBuffer(testdata1[i][0 ]).reverse();
check(!testdata1[i][1 ].equals(new String(sb)),
"reverse() for <" + toHexString(testdata1[i][0 ]) + ">" ,
sb, testdata1[i][1 ]);
}
}
/**
* Test for appendCodePoint ( ) method
*/
static void test4() {
for (int i = 0 ; i < input.length; i++) {
String s = input[i];
StringBuffer sb = new StringBuffer();
int c;
for (int j = 0 ; j < s.length(); j += Character.charCount(c)) {
c = s.codePointAt(j);
StringBuffer rsb = sb.appendCodePoint(c);
check(sb != rsb, "appendCodePoint returned a wrong object" );
int sbc = sb.codePointAt(j);
check(sbc != c, "appendCodePoint(j) != c" , sbc, c);
}
check(!s.equals(sb.toString()),
"appendCodePoint() produced a wrong result with input[" +i+"]" );
}
// test exception
testAppendCodePoint(-1 , IllegalArgumentException.class );
testAppendCodePoint(Character.MAX_CODE_POINT+1 , IllegalArgumentException.class );
}
/**
* Test codePointCount ( int , int )
*
* This test case assumes that
* Character . codePointCount ( CharSequence , int , int ) works
* correctly .
*/
static void test5() {
for (int i = 0 ; i < input.length; i++) {
String s = input[i];
StringBuffer sb = new StringBuffer(s);
int length = sb.length();
for (int j = 0 ; j <= length; j++) {
int result = sb.codePointCount(j, length);
int expected = Character.codePointCount(sb, j, length);
check(result != expected, "codePointCount(input[" +i+"], " +j+", " +length+")" ,
result, expected);
}
for (int j = length; j >= 0 ; j--) {
int result = sb.codePointCount(0 , j);
int expected = Character.codePointCount(sb, 0 , j);
check(result != expected, "codePointCount(input[" +i+"], 0, " +j+")" ,
result, expected);
}
// test exceptions
testCodePointCount(null , 0 , 0 , NullPointerException.class );
testCodePointCount(sb, -1 , length, IndexOutOfBoundsException.class );
testCodePointCount(sb, 0 , length+1 , IndexOutOfBoundsException.class );
testCodePointCount(sb, length, length-1 , IndexOutOfBoundsException.class );
}
}
/**
* Test offsetByCodePoints ( int , int )
*
* This test case assumes that
* Character . codePointCount ( CharSequence , int , int ) works
* correctly .
*/
static void test6() {
for (int i = 0 ; i < input.length; i++) {
String s = input[i];
StringBuffer sb = new StringBuffer(s);
int length = s.length();
for (int j = 0 ; j <= length; j++) {
int nCodePoints = Character.codePointCount(sb, j, length);
int result = sb.offsetByCodePoints(j, nCodePoints);
check(result != length,
"offsetByCodePoints(input[" +i+"], " +j+", " +nCodePoints+")" ,
result, length);
result = sb.offsetByCodePoints(length, -nCodePoints);
int expected = j;
if (j > 0 && j < length) {
int cp = sb.codePointBefore(j+1 );
if (Character.isSupplementaryCodePoint(cp)) {
expected--;
}
}
check(result != expected,
"offsetByCodePoints(input[" +i+"], " +j+", " +(-nCodePoints)+")" ,
result, expected);
}
for (int j = length; j >= 0 ; j--) {
int nCodePoints = Character.codePointCount(sb, 0 , j);
int result = sb.offsetByCodePoints(0 , nCodePoints);
int expected = j;
if (j > 0 && j < length) {
int cp = sb.codePointAt(j-1 );
if (Character.isSupplementaryCodePoint(cp)) {
expected++;
}
}
check(result != expected,
"offsetByCodePoints(input[" +i+"], 0, " +nCodePoints+")" ,
result, expected);
result = sb.offsetByCodePoints(j, -nCodePoints);
check(result != 0 ,
"offsetBycodePoints(input[" +i+"], " +j+", " +(-nCodePoints)+")" ,
result, 0 );
}
// test exceptions
testOffsetByCodePoints(null , 0 , 0 , NullPointerException.class );
testOffsetByCodePoints(sb, -1 , length, IndexOutOfBoundsException.class );
testOffsetByCodePoints(sb, 0 , length+1 , IndexOutOfBoundsException.class );
testOffsetByCodePoints(sb, 1 , -2 , IndexOutOfBoundsException.class );
testOffsetByCodePoints(sb, length, length-1 , IndexOutOfBoundsException.class );
testOffsetByCodePoints(sb, length, -(length+1 ), IndexOutOfBoundsException.class );
}
}
static final boolean At = true , Before = false ;
static void testCodePoint(boolean isAt, StringBuffer sb, int index, int expected) {
int c = isAt ? sb.codePointAt(index) : sb.codePointBefore(index);
check(c != expected,
"codePoint" + (isAt ? "At" : "Before" ) + "(" + index + ") for <"
+ sb + ">" , c, expected);
}
static void testCodePoint(boolean isAt, StringBuffer sb, int index) {
boolean exceptionOccurred = false ;
try {
int c = isAt ? sb.codePointAt(index) : sb.codePointBefore(index);
}
catch (StringIndexOutOfBoundsException e) {
exceptionOccurred = true ;
}
check(!exceptionOccurred,
"codePoint" + (isAt ? "At" : "Before" ) + "(" + index + ") for <"
+ sb + "> should throw StringIndexOutOfBoundsPointerException." );
}
static void testAppendCodePoint(int codePoint, Class expectedException) {
try {
new StringBuffer().appendCodePoint(codePoint);
} catch (Exception e) {
if (expectedException.isInstance(e)) {
return ;
}
throw new RuntimeException("Error: Unexpected exception" , e);
}
check(true , "appendCodePoint(" + toHexString(codePoint) + ") didn't throw "
+ expectedException.getName());
}
static void testCodePointCount(StringBuffer sb, int beginIndex, int endIndex,
Class expectedException) {
try {
int n = sb.codePointCount(beginIndex, endIndex);
} catch (Exception e) {
if (expectedException.isInstance(e)) {
return ;
}
throw new RuntimeException("Error: Unexpected exception" , e);
}
check(true , "codePointCount() didn't throw " + expectedException.getName());
}
static void testOffsetByCodePoints(StringBuffer sb, int index, int offset,
Class expectedException) {
try {
int n = sb.offsetByCodePoints(index, offset);
} catch (Exception e) {
if (expectedException.isInstance(e)) {
return ;
}
throw new RuntimeException("Error: Unexpected exception" , e);
}
check(true , "offsetByCodePoints() didn't throw " + expectedException.getName());
}
static void check(boolean err, String msg) {
if (err) {
throw new RuntimeException("Error: " + msg);
}
}
static void check(boolean err, String s, int got, int expected) {
if (err) {
throw new RuntimeException("Error: " + s
+ " returned an unexpected value. got "
+ toHexString(got)
+ ", expected "
+ toHexString(expected));
}
}
static void check(boolean err, String s, StringBuffer got, String expected) {
if (err) {
throw new RuntimeException("Error: " + s
+ " returned an unexpected value. got <"
+ toHexString(new String(got))
+ ">, expected <"
+ toHexString(expected)
+ ">" );
}
}
private static String toHexString(int c) {
return "0x" + Integer.toHexString(c);
}
private static String toHexString(String s) {
HexFormat format = HexFormat.of();
StringBuilder sb = new StringBuilder();
for (int i = 0 ; i < s.length(); i++) {
char c = s.charAt(i);
sb.append(" 0x" );
sb.append(format.toHexDigits(c));
}
sb.append(' ' );
return sb.toString();
}
}
Messung V0.5 in Prozent C=94 H=79 G=86
¤ Dauer der Verarbeitung: 0.4 Sekunden
(vorverarbeitet am 2026-10-11)
¤
*© Formatika GbR, Deutschland