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