1 /*
   2  * Copyright (c) 2015, 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 import java.util.Arrays;
  25 
  26 import org.testng.annotations.Test;
  27 
  28 import static org.testng.Assert.assertEquals;
  29 import static org.testng.Assert.assertTrue;
  30 
  31 /*
  32  * @test
  33  * @bug 8054307 8077559
  34  * @summary Tests Compact String. This test is testing StringBuilder
  35  *          behavior related to Compact String.
  36  * @run testng/othervm -XX:+CompactStrings CompactStringBuilder
  37  * @run testng/othervm -XX:-CompactStrings CompactStringBuilder
  38  */
  39 
  40 public class CompactStringBuilder {
  41 
  42     /*
  43      * Tests for "A"
  44      */
  45     @Test
  46     public void testCompactStringBuilderForLatinA() {
  47         final String ORIGIN = "A";
  48         /*
  49          * Because right now ASCII is the default encoding parameter for source
  50          * code in JDK build environment, so we escape them. same as below.
  51          */
  52         check(new StringBuilder(ORIGIN).append(new char[] { '\uFF21' }),
  53                 "A\uFF21");
  54         check(new StringBuilder(ORIGIN).append(new StringBuffer("\uFF21")),
  55                 "A\uFF21");
  56         check(new StringBuilder(ORIGIN).append("\uFF21"), "A\uFF21");
  57         check(new StringBuilder(ORIGIN).append(new StringBuffer("\uFF21")),
  58                 "A\uFF21");
  59         check(new StringBuilder(ORIGIN).delete(0, 1), "");
  60         check(new StringBuilder(ORIGIN).delete(0, 0), "A");
  61         check(new StringBuilder(ORIGIN).deleteCharAt(0), "");
  62         assertEquals(new StringBuilder(ORIGIN).indexOf("A", 0), 0);
  63         assertEquals(new StringBuilder(ORIGIN).indexOf("\uFF21", 0), -1);
  64         assertEquals(new StringBuilder(ORIGIN).indexOf("", 0), 0);
  65         assertEquals(new StringBuilder(ORIGIN).insert(1, "\uD801\uDC00")
  66                 .indexOf("A", 0), 0);
  67         assertEquals(new StringBuilder(ORIGIN).insert(0, "\uD801\uDC00")
  68                 .indexOf("A", 0), 2);
  69         check(new StringBuilder(ORIGIN).insert(0, new char[] {}), "A");
  70         check(new StringBuilder(ORIGIN).insert(1, new char[] { '\uFF21' }),
  71                 "A\uFF21");
  72         check(new StringBuilder(ORIGIN).insert(0, new char[] { '\uFF21' }),
  73                 "\uFF21A");
  74         check(new StringBuilder(ORIGIN).insert(0, new StringBuffer("\uFF21")),
  75                 "\uFF21A");
  76         check(new StringBuilder(ORIGIN).insert(1, new StringBuffer("\uFF21")),
  77                 "A\uFF21");
  78         check(new StringBuilder(ORIGIN).insert(0, ""), "A");
  79         check(new StringBuilder(ORIGIN).insert(0, "\uFF21"), "\uFF21A");
  80         check(new StringBuilder(ORIGIN).insert(1, "\uFF21"), "A\uFF21");
  81         assertEquals(new StringBuilder(ORIGIN).lastIndexOf("A"), 0);
  82         assertEquals(new StringBuilder(ORIGIN).lastIndexOf("\uFF21"), -1);
  83         assertEquals(new StringBuilder(ORIGIN).lastIndexOf(""), 1);
  84         check(new StringBuilder(ORIGIN).replace(0, 0, "\uFF21"), "\uFF21A");
  85         check(new StringBuilder(ORIGIN).replace(0, 1, "\uFF21"), "\uFF21");
  86         checkSetCharAt(new StringBuilder(ORIGIN), 0, '\uFF21', "\uFF21");
  87         checkSetLength(new StringBuilder(ORIGIN), 0, "");
  88         checkSetLength(new StringBuilder(ORIGIN), 1, "A");
  89         check(new StringBuilder(ORIGIN).substring(0), "A");
  90         check(new StringBuilder(ORIGIN).substring(1), "");
  91     }
  92 
  93     /*
  94      * Tests for "\uFF21"
  95      */
  96     @Test
  97     public void testCompactStringBuilderForNonLatinA() {
  98         final String ORIGIN = "\uFF21";
  99         check(new StringBuilder(ORIGIN).append(new char[] { 'A' }), "\uFF21A");
 100         check(new StringBuilder(ORIGIN).append(new StringBuffer("A")), "\uFF21A");
 101         check(new StringBuilder(ORIGIN).append("A"), "\uFF21A");
 102         check(new StringBuilder(ORIGIN).append(new StringBuffer("A")), "\uFF21A");
 103         check(new StringBuilder(ORIGIN).delete(0, 1), "");
 104         check(new StringBuilder(ORIGIN).delete(0, 0), "\uFF21");
 105         check(new StringBuilder(ORIGIN).deleteCharAt(0), "");
 106         assertEquals(new StringBuilder(ORIGIN).indexOf("A", 0), -1);
 107         assertEquals(new StringBuilder(ORIGIN).indexOf("\uFF21", 0), 0);
 108         assertEquals(new StringBuilder(ORIGIN).indexOf("", 0), 0);
 109         check(new StringBuilder(ORIGIN).insert(0, new char[] {}), "\uFF21");
 110         check(new StringBuilder(ORIGIN).insert(1, new char[] { 'A' }), "\uFF21A");
 111         check(new StringBuilder(ORIGIN).insert(0, new char[] { 'A' }), "A\uFF21");
 112         check(new StringBuilder(ORIGIN).insert(0, new StringBuffer("A")),
 113                 "A\uFF21");
 114         check(new StringBuilder(ORIGIN).insert(1, new StringBuffer("A")),
 115                 "\uFF21A");
 116         check(new StringBuilder(ORIGIN).insert(0, ""), "\uFF21");
 117         check(new StringBuilder(ORIGIN).insert(0, "A"), "A\uFF21");
 118         check(new StringBuilder(ORIGIN).insert(1, "A"), "\uFF21A");
 119         assertEquals(new StringBuilder(ORIGIN).lastIndexOf("A"), -1);
 120         assertEquals(new StringBuilder(ORIGIN).lastIndexOf("\uFF21"), 0);
 121         assertEquals(new StringBuilder(ORIGIN).lastIndexOf(""), 1);
 122         check(new StringBuilder(ORIGIN).replace(0, 0, "A"), "A\uFF21");
 123         check(new StringBuilder(ORIGIN).replace(0, 1, "A"), "A");
 124         checkSetCharAt(new StringBuilder(ORIGIN), 0, 'A', "A");
 125         checkSetLength(new StringBuilder(ORIGIN), 0, "");
 126         checkSetLength(new StringBuilder(ORIGIN), 1, "\uFF21");
 127         check(new StringBuilder(ORIGIN).substring(0), "\uFF21");
 128         check(new StringBuilder(ORIGIN).substring(1), "");
 129     }
 130 
 131     /*
 132      * Tests for "\uFF21A"
 133      */
 134     @Test
 135     public void testCompactStringBuilderForMixedA1() {
 136         final String ORIGIN = "\uFF21A";
 137         check(new StringBuilder(ORIGIN).delete(0, 1), "A");
 138         check(new StringBuilder(ORIGIN).delete(1, 2), "\uFF21");
 139         check(new StringBuilder(ORIGIN).deleteCharAt(1), "\uFF21");
 140         check(new StringBuilder(ORIGIN).deleteCharAt(0), "A");
 141         assertEquals(new StringBuilder(ORIGIN).indexOf("A", 0), 1);
 142         assertEquals(new StringBuilder(ORIGIN).indexOf("\uFF21", 0), 0);
 143         assertEquals(new StringBuilder(ORIGIN).indexOf("", 0), 0);
 144         check(new StringBuilder(ORIGIN).insert(1, new char[] { 'A' }),
 145                 "\uFF21AA");
 146         check(new StringBuilder(ORIGIN).insert(0, new char[] { '\uFF21' }),
 147                 "\uFF21\uFF21A");
 148         assertEquals(new StringBuilder(ORIGIN).lastIndexOf("A"), 1);
 149         assertEquals(new StringBuilder(ORIGIN).lastIndexOf("\uFF21"), 0);
 150         assertEquals(new StringBuilder(ORIGIN).lastIndexOf(""), 2);
 151         check(new StringBuilder(ORIGIN).replace(0, 0, "A"), "A\uFF21A");
 152         check(new StringBuilder(ORIGIN).replace(0, 1, "A"), "AA");
 153         checkSetCharAt(new StringBuilder(ORIGIN), 0, 'A', "AA");
 154         checkSetLength(new StringBuilder(ORIGIN), 0, "");
 155         checkSetLength(new StringBuilder(ORIGIN), 1, "\uFF21");
 156         check(new StringBuilder(ORIGIN).substring(0), "\uFF21A");
 157         check(new StringBuilder(ORIGIN).substring(1), "A");
 158     }
 159 
 160     /*
 161      * Tests for "A\uFF21"
 162      */
 163     @Test
 164     public void testCompactStringBuilderForMixedA2() {
 165         final String ORIGIN = "A\uFF21";
 166         check(new StringBuilder(ORIGIN).replace(1, 2, "A"), "AA");
 167         checkSetLength(new StringBuilder(ORIGIN), 1, "A");
 168         check(new StringBuilder(ORIGIN).substring(0), "A\uFF21");
 169         check(new StringBuilder(ORIGIN).substring(1), "\uFF21");
 170         check(new StringBuilder(ORIGIN).substring(0, 1), "A");
 171     }
 172 
 173     /*
 174      * Tests for "\uFF21A\uFF21A\uFF21A\uFF21A\uFF21A"
 175      */
 176     @Test
 177     public void testCompactStringBuilderForDuplicatedMixedA1() {
 178         final String ORIGIN = "\uFF21A\uFF21A\uFF21A\uFF21A\uFF21A";
 179         checkSetLength(new StringBuilder(ORIGIN), 1, "\uFF21");
 180         assertEquals(new StringBuilder(ORIGIN).indexOf("A", 5), 5);
 181         assertEquals(new StringBuilder(ORIGIN).indexOf("\uFF21", 5), 6);
 182         assertEquals(new StringBuilder(ORIGIN).lastIndexOf("A"), 9);
 183         assertEquals(new StringBuilder(ORIGIN).lastIndexOf("\uFF21"), 8);
 184         assertEquals(new StringBuilder(ORIGIN).lastIndexOf(""), 10);
 185         check(new StringBuilder(ORIGIN).substring(9), "A");
 186         check(new StringBuilder(ORIGIN).substring(8), "\uFF21A");
 187     }
 188 
 189     /*
 190      * Tests for "A\uFF21A\uFF21A\uFF21A\uFF21A\uFF21"
 191      */
 192     @Test
 193     public void testCompactStringBuilderForDuplicatedMixedA2() {
 194         final String ORIGIN = "A\uFF21A\uFF21A\uFF21A\uFF21A\uFF21";
 195         checkSetLength(new StringBuilder(ORIGIN), 1, "A");
 196         assertEquals(new StringBuilder(ORIGIN).indexOf("A", 5), 6);
 197         assertEquals(new StringBuilder(ORIGIN).indexOf("\uFF21", 5), 5);
 198         assertEquals(new StringBuilder(ORIGIN).lastIndexOf("A"), 8);
 199         assertEquals(new StringBuilder(ORIGIN).lastIndexOf("\uFF21"), 9);
 200         check(new StringBuilder(ORIGIN).substring(9), "\uFF21");
 201         check(new StringBuilder(ORIGIN).substring(8), "A\uFF21");
 202     }
 203 
 204     /*
 205      * Tests for "\uD801\uDC00\uD801\uDC01"
 206      */
 207     @Test
 208     public void testCompactStringForSupplementaryCodePoint() {
 209         final String ORIGIN = "\uD801\uDC00\uD801\uDC01";
 210         check(new StringBuilder(ORIGIN).append("A"), "\uD801\uDC00\uD801\uDC01A");
 211         check(new StringBuilder(ORIGIN).append("\uFF21"),
 212                 "\uD801\uDC00\uD801\uDC01\uFF21");
 213         check(new StringBuilder(ORIGIN).appendCodePoint('A'),
 214                 "\uD801\uDC00\uD801\uDC01A");
 215         check(new StringBuilder(ORIGIN).appendCodePoint('\uFF21'),
 216                 "\uD801\uDC00\uD801\uDC01\uFF21");
 217         assertEquals(new StringBuilder(ORIGIN).charAt(0), '\uD801');
 218         assertEquals(new StringBuilder(ORIGIN).codePointAt(0),
 219                 Character.codePointAt(ORIGIN, 0));
 220         assertEquals(new StringBuilder(ORIGIN).codePointAt(1),
 221                 Character.codePointAt(ORIGIN, 1));
 222         assertEquals(new StringBuilder(ORIGIN).codePointBefore(2),
 223                 Character.codePointAt(ORIGIN, 0));
 224         assertEquals(new StringBuilder(ORIGIN).codePointCount(1, 3), 2);
 225         check(new StringBuilder(ORIGIN).delete(0, 2), "\uD801\uDC01");
 226         check(new StringBuilder(ORIGIN).delete(0, 3), "\uDC01");
 227         check(new StringBuilder(ORIGIN).deleteCharAt(1), "\uD801\uD801\uDC01");
 228         checkGetChars(new StringBuilder(ORIGIN), 0, 3, new char[] { '\uD801',
 229                 '\uDC00', '\uD801' });
 230         assertEquals(new StringBuilder(ORIGIN).indexOf("\uD801\uDC01"), 2);
 231         assertEquals(new StringBuilder(ORIGIN).indexOf("\uDC01"), 3);
 232         assertEquals(new StringBuilder(ORIGIN).indexOf("\uFF21"), -1);
 233         assertEquals(new StringBuilder(ORIGIN).indexOf("A"), -1);
 234         check(new StringBuilder(ORIGIN).insert(0, "\uFF21"),
 235                 "\uFF21\uD801\uDC00\uD801\uDC01");
 236         check(new StringBuilder(ORIGIN).insert(1, "\uFF21"),
 237                 "\uD801\uFF21\uDC00\uD801\uDC01");
 238         check(new StringBuilder(ORIGIN).insert(1, "A"),
 239                 "\uD801A\uDC00\uD801\uDC01");
 240         assertEquals(new StringBuilder(ORIGIN).lastIndexOf("\uDC00\uD801"), 1);
 241         assertEquals(new StringBuilder(ORIGIN).lastIndexOf("\uD801"), 2);
 242         assertEquals(new StringBuilder(ORIGIN).lastIndexOf("\uFF21"), -1);
 243         assertEquals(new StringBuilder(ORIGIN).lastIndexOf("A"), -1);
 244         assertEquals(new StringBuilder(ORIGIN).length(), 4);
 245         assertEquals(new StringBuilder(ORIGIN).offsetByCodePoints(1, 1), 2);
 246         assertEquals(new StringBuilder(ORIGIN).offsetByCodePoints(0, 1), 2);
 247         check(new StringBuilder(ORIGIN).replace(0, 2, "A"), "A\uD801\uDC01");
 248         check(new StringBuilder(ORIGIN).replace(0, 3, "A"), "A\uDC01");
 249         check(new StringBuilder(ORIGIN).replace(0, 2, "\uFF21"),
 250                 "\uFF21\uD801\uDC01");
 251         check(new StringBuilder(ORIGIN).replace(0, 3, "\uFF21"), "\uFF21\uDC01");
 252         check(new StringBuilder(ORIGIN).reverse(), "\uD801\uDC01\uD801\uDC00");
 253         checkSetCharAt(new StringBuilder(ORIGIN), 1, '\uDC01',
 254                 "\uD801\uDC01\uD801\uDC01");
 255         checkSetCharAt(new StringBuilder(ORIGIN), 1, 'A', "\uD801A\uD801\uDC01");
 256         checkSetLength(new StringBuilder(ORIGIN), 2, "\uD801\uDC00");
 257         checkSetLength(new StringBuilder(ORIGIN), 3, "\uD801\uDC00\uD801");
 258         check(new StringBuilder(ORIGIN).substring(1, 3), "\uDC00\uD801");
 259     }
 260 
 261     /*
 262      * Tests for "A\uD801\uDC00\uFF21"
 263      */
 264     @Test
 265     public void testCompactStringForSupplementaryCodePointMixed1() {
 266         final String ORIGIN = "A\uD801\uDC00\uFF21";
 267         assertEquals(new StringBuilder(ORIGIN).codePointBefore(3),
 268                 Character.codePointAt(ORIGIN, 1));
 269         assertEquals(new StringBuilder(ORIGIN).codePointBefore(2), '\uD801');
 270         assertEquals(new StringBuilder(ORIGIN).codePointBefore(1), 'A');
 271         assertEquals(new StringBuilder(ORIGIN).codePointCount(0, 3), 2);
 272         assertEquals(new StringBuilder(ORIGIN).codePointCount(0, 4), 3);
 273         check(new StringBuilder(ORIGIN).delete(0, 1), "\uD801\uDC00\uFF21");
 274         check(new StringBuilder(ORIGIN).delete(0, 1).delete(2, 3),
 275                 "\uD801\uDC00");
 276         check(new StringBuilder(ORIGIN).deleteCharAt(3).deleteCharAt(0),
 277                 "\uD801\uDC00");
 278         assertEquals(new StringBuilder(ORIGIN).indexOf("\uFF21"), 3);
 279         assertEquals(new StringBuilder(ORIGIN).indexOf("A"), 0);
 280         assertEquals(new StringBuilder(ORIGIN).lastIndexOf("\uFF21"), 3);
 281         assertEquals(new StringBuilder(ORIGIN).lastIndexOf("A"), 0);
 282         assertEquals(new StringBuilder(ORIGIN).offsetByCodePoints(0, 1), 1);
 283         assertEquals(new StringBuilder(ORIGIN).offsetByCodePoints(1, 1), 3);
 284         check(new StringBuilder(ORIGIN).replace(1, 3, "A"), "AA\uFF21");
 285         check(new StringBuilder(ORIGIN).replace(1, 4, "A"), "AA");
 286         check(new StringBuilder(ORIGIN).replace(1, 4, ""), "A");
 287         check(new StringBuilder(ORIGIN).reverse(), "\uFF21\uD801\uDC00A");
 288         checkSetLength(new StringBuilder(ORIGIN), 1, "A");
 289         check(new StringBuilder(ORIGIN).substring(0, 1), "A");
 290     }
 291 
 292     /*
 293      * Tests for "\uD801\uDC00\uFF21A"
 294      */
 295     @Test
 296     public void testCompactStringForSupplementaryCodePointMixed2() {
 297         final String ORIGIN = "\uD801\uDC00\uFF21A";
 298         assertEquals(new StringBuilder(ORIGIN).codePointBefore(3),
 299                 Character.codePointAt(ORIGIN, 2));
 300         assertEquals(new StringBuilder(ORIGIN).codePointBefore(2),
 301                 Character.codePointAt(ORIGIN, 0));
 302         assertEquals(new StringBuilder(ORIGIN).codePointBefore(1), '\uD801');
 303         assertEquals(new StringBuilder(ORIGIN).codePointCount(0, 3), 2);
 304         assertEquals(new StringBuilder(ORIGIN).codePointCount(0, 4), 3);
 305         check(new StringBuilder(ORIGIN).delete(0, 2), "\uFF21A");
 306         check(new StringBuilder(ORIGIN).delete(0, 3), "A");
 307         check(new StringBuilder(ORIGIN).deleteCharAt(0).deleteCharAt(0)
 308                 .deleteCharAt(0), "A");
 309         assertEquals(new StringBuilder(ORIGIN).indexOf("A"), 3);
 310         assertEquals(new StringBuilder(ORIGIN).delete(0, 3).indexOf("A"), 0);
 311         assertEquals(new StringBuilder(ORIGIN).replace(0, 3, "B").indexOf("A"),
 312                 1);
 313         assertEquals(new StringBuilder(ORIGIN).substring(3, 4).indexOf("A"), 0);
 314         assertEquals(new StringBuilder(ORIGIN).offsetByCodePoints(1, 1), 2);
 315         assertEquals(new StringBuilder(ORIGIN).offsetByCodePoints(0, 1), 2);
 316         assertEquals(new StringBuilder(ORIGIN).offsetByCodePoints(2, 1), 3);
 317         check(new StringBuilder(ORIGIN).replace(0, 3, "B"), "BA");
 318         check(new StringBuilder(ORIGIN).reverse(), "A\uFF21\uD801\uDC00");
 319     }
 320 
 321     /*
 322      * Tests for "\uD801A\uDC00\uFF21"
 323      */
 324     @Test
 325     public void testCompactStringForSupplementaryCodePointMixed3() {
 326         final String ORIGIN = "\uD801A\uDC00\uFF21";
 327         assertEquals(new StringBuilder(ORIGIN).codePointAt(1), 'A');
 328         assertEquals(new StringBuilder(ORIGIN).codePointAt(3), '\uFF21');
 329         assertEquals(new StringBuilder(ORIGIN).codePointBefore(1), '\uD801');
 330         assertEquals(new StringBuilder(ORIGIN).codePointBefore(2), 'A');
 331         assertEquals(new StringBuilder(ORIGIN).codePointBefore(3), '\uDC00');
 332         assertEquals(new StringBuilder(ORIGIN).codePointCount(0, 3), 3);
 333         assertEquals(new StringBuilder(ORIGIN).codePointCount(1, 3), 2);
 334         assertEquals(new StringBuilder(ORIGIN).delete(0, 1).delete(1, 3)
 335                 .indexOf("A"), 0);
 336         assertEquals(
 337                 new StringBuilder(ORIGIN).replace(0, 1, "B").replace(2, 4, "C")
 338                         .indexOf("A"), 1);
 339         assertEquals(new StringBuilder(ORIGIN).substring(1, 4).substring(0, 1)
 340                 .indexOf("A"), 0);
 341         assertEquals(new StringBuilder(ORIGIN).offsetByCodePoints(0, 1), 1);
 342         assertEquals(new StringBuilder(ORIGIN).offsetByCodePoints(1, 1), 2);
 343         assertEquals(new StringBuilder(ORIGIN).offsetByCodePoints(2, 1), 3);
 344         check(new StringBuilder(ORIGIN).reverse(), "\uFF21\uDC00A\uD801");
 345     }
 346 
 347     /*
 348      * Tests for "A\uDC01\uFF21\uD801"
 349      */
 350     @Test
 351     public void testCompactStringForSupplementaryCodePointMixed4() {
 352         final String ORIGIN = "A\uDC01\uFF21\uD801";
 353         assertEquals(new StringBuilder(ORIGIN).codePointAt(1), '\uDC01');
 354         assertEquals(new StringBuilder(ORIGIN).codePointAt(3), '\uD801');
 355         assertEquals(new StringBuilder(ORIGIN).codePointBefore(1), 'A');
 356         assertEquals(new StringBuilder(ORIGIN).codePointBefore(2), '\uDC01');
 357         assertEquals(new StringBuilder(ORIGIN).codePointBefore(3), '\uFF21');
 358         assertEquals(new StringBuilder(ORIGIN).codePointCount(0, 3), 3);
 359         assertEquals(new StringBuilder(ORIGIN).codePointCount(1, 3), 2);
 360         assertEquals(new StringBuilder(ORIGIN).delete(1, 4).indexOf("A"), 0);
 361         assertEquals(new StringBuilder(ORIGIN).replace(1, 4, "B").indexOf("A"),
 362                 0);
 363         assertEquals(new StringBuilder(ORIGIN).substring(0, 1).indexOf("A"), 0);
 364         assertEquals(new StringBuilder(ORIGIN).offsetByCodePoints(0, 1), 1);
 365         assertEquals(new StringBuilder(ORIGIN).offsetByCodePoints(1, 1), 2);
 366         assertEquals(new StringBuilder(ORIGIN).offsetByCodePoints(2, 1), 3);
 367         check(new StringBuilder(ORIGIN).reverse(), "\uD801\uFF21\uDC01A");
 368     }
 369 
 370     private void checkGetChars(StringBuilder sb, int srcBegin, int srcEnd,
 371             char expected[]) {
 372         char[] dst = new char[srcEnd - srcBegin];
 373         sb.getChars(srcBegin, srcEnd, dst, 0);
 374         assertTrue(Arrays.equals(dst, expected));
 375     }
 376 
 377     private void checkSetCharAt(StringBuilder sb, int index, char ch,
 378             String expected) {
 379         sb.setCharAt(index, ch);
 380         check(sb, expected);
 381     }
 382 
 383     private void checkSetLength(StringBuilder sb, int newLength, String expected) {
 384         sb.setLength(newLength);
 385         check(sb, expected);
 386     }
 387 
 388     private void check(StringBuilder sb, String expected) {
 389         check(sb.toString(), expected);
 390     }
 391 
 392     private void check(String str, String expected) {
 393         assertTrue(str.equals(expected), String.format(
 394                 "Get (%s) but expect (%s), ", escapeNonASCIIs(str),
 395                 escapeNonASCIIs(expected)));
 396     }
 397 
 398     /*
 399      * Because right now system default charset in JPRT environment is only
 400      * guaranteed to support ASCII characters in log, so we escape them.
 401      */
 402     private String escapeNonASCIIs(String str) {
 403         StringBuilder sb = new StringBuilder();
 404         for (int i = 0; i < str.length(); i++) {
 405             char c = str.charAt(i);
 406             if (c > 0x7F) {
 407                 sb.append("\\u").append(Integer.toHexString((int) c));
 408             } else {
 409                 sb.append(c);
 410             }
 411         }
 412         return sb.toString();
 413     }
 414 }