1 /*
   2  * Copyright (c) 2015, 2019, 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 8077559 8221430
  34  * @summary Tests Compact String. This test is testing StringBuffer
  35  *          behavior related to Compact String.
  36  * @run testng/othervm -XX:+CompactStrings CompactStringBuffer
  37  * @run testng/othervm -XX:-CompactStrings CompactStringBuffer
  38  */
  39 
  40 public class CompactStringBuffer {
  41 
  42     /*
  43      * Tests for "A"
  44      */
  45     @Test
  46     public void testCompactStringBufferForLatinA() {
  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 StringBuffer(ORIGIN).append(new char[] { '\uFF21' }),
  53                 "A\uFF21");
  54         check(new StringBuffer(ORIGIN).append(new StringBuffer("\uFF21")),
  55                 "A\uFF21");
  56         check(new StringBuffer(ORIGIN).append("\uFF21"), "A\uFF21");
  57         check(new StringBuffer(ORIGIN).append(new StringBuffer("\uFF21")),
  58                 "A\uFF21");
  59         check(new StringBuffer(ORIGIN).delete(0, 1), "");
  60         check(new StringBuffer(ORIGIN).delete(0, 0), "A");
  61         check(new StringBuffer(ORIGIN).deleteCharAt(0), "");
  62         assertEquals(new StringBuffer(ORIGIN).indexOf("A", 0), 0);
  63         assertEquals(new StringBuffer(ORIGIN).indexOf("\uFF21", 0), -1);
  64         assertEquals(new StringBuffer(ORIGIN).indexOf("", 0), 0);
  65         assertEquals(new StringBuffer(ORIGIN).insert(1, "\uD801\uDC00")
  66                 .indexOf("A", 0), 0);
  67         assertEquals(new StringBuffer(ORIGIN).insert(0, "\uD801\uDC00")
  68                 .indexOf("A", 0), 2);
  69         check(new StringBuffer(ORIGIN).insert(0, new char[] {}), "A");
  70         check(new StringBuffer(ORIGIN).insert(1, new char[] { '\uFF21' }),
  71                 "A\uFF21");
  72         check(new StringBuffer(ORIGIN).insert(0, new char[] { '\uFF21' }),
  73                 "\uFF21A");
  74         check(new StringBuffer(ORIGIN).insert(0, new StringBuffer("\uFF21")),
  75                 "\uFF21A");
  76         check(new StringBuffer(ORIGIN).insert(1, new StringBuffer("\uFF21")),
  77                 "A\uFF21");
  78         check(new StringBuffer(ORIGIN).insert(0, ""), "A");
  79         check(new StringBuffer(ORIGIN).insert(0, "\uFF21"), "\uFF21A");
  80         check(new StringBuffer(ORIGIN).insert(1, "\uFF21"), "A\uFF21");
  81         assertEquals(new StringBuffer(ORIGIN).lastIndexOf("A"), 0);
  82         assertEquals(new StringBuffer(ORIGIN).lastIndexOf("\uFF21"), -1);
  83         assertEquals(new StringBuffer(ORIGIN).lastIndexOf(""), 1);
  84         check(new StringBuffer(ORIGIN).replace(0, 0, "\uFF21"), "\uFF21A");
  85         check(new StringBuffer(ORIGIN).replace(0, 1, "\uFF21"), "\uFF21");
  86         checkSetCharAt(new StringBuffer(ORIGIN), 0, '\uFF21', "\uFF21");
  87         checkSetLength(new StringBuffer(ORIGIN), 0, "");
  88         checkSetLength(new StringBuffer(ORIGIN), 1, "A");
  89         check(new StringBuffer(ORIGIN).substring(0), "A");
  90         check(new StringBuffer(ORIGIN).substring(1), "");
  91     }
  92 
  93     /*
  94      * Tests for "\uFF21"
  95      */
  96     @Test
  97     public void testCompactStringBufferForNonLatinA() {
  98         final String ORIGIN = "\uFF21";
  99         check(new StringBuffer(ORIGIN).append(new char[] { 'A' }), "\uFF21A");
 100         check(new StringBuffer(ORIGIN).append(new StringBuffer("A")), "\uFF21A");
 101         check(new StringBuffer(ORIGIN).append("A"), "\uFF21A");
 102         check(new StringBuffer(ORIGIN).append(new StringBuffer("A")), "\uFF21A");
 103         check(new StringBuffer(ORIGIN).delete(0, 1), "");
 104         check(new StringBuffer(ORIGIN).delete(0, 0), "\uFF21");
 105         check(new StringBuffer(ORIGIN).deleteCharAt(0), "");
 106         assertEquals(new StringBuffer(ORIGIN).indexOf("A", 0), -1);
 107         assertEquals(new StringBuffer(ORIGIN).indexOf("\uFF21", 0), 0);
 108         assertEquals(new StringBuffer(ORIGIN).indexOf("", 0), 0);
 109         check(new StringBuffer(ORIGIN).insert(0, new char[] {}), "\uFF21");
 110         check(new StringBuffer(ORIGIN).insert(1, new char[] { 'A' }), "\uFF21A");
 111         check(new StringBuffer(ORIGIN).insert(0, new char[] { 'A' }), "A\uFF21");
 112         check(new StringBuffer(ORIGIN).insert(0, new StringBuffer("A")),
 113                 "A\uFF21");
 114         check(new StringBuffer(ORIGIN).insert(1, new StringBuffer("A")),
 115                 "\uFF21A");
 116         check(new StringBuffer(ORIGIN).insert(0, ""), "\uFF21");
 117         check(new StringBuffer(ORIGIN).insert(0, "A"), "A\uFF21");
 118         check(new StringBuffer(ORIGIN).insert(1, "A"), "\uFF21A");
 119         assertEquals(new StringBuffer(ORIGIN).lastIndexOf("A"), -1);
 120         assertEquals(new StringBuffer(ORIGIN).lastIndexOf("\uFF21"), 0);
 121         assertEquals(new StringBuffer(ORIGIN).lastIndexOf(""), 1);
 122         check(new StringBuffer(ORIGIN).replace(0, 0, "A"), "A\uFF21");
 123         check(new StringBuffer(ORIGIN).replace(0, 1, "A"), "A");
 124         checkSetCharAt(new StringBuffer(ORIGIN), 0, 'A', "A");
 125         checkSetLength(new StringBuffer(ORIGIN), 0, "");
 126         checkSetLength(new StringBuffer(ORIGIN), 1, "\uFF21");
 127         check(new StringBuffer(ORIGIN).substring(0), "\uFF21");
 128         check(new StringBuffer(ORIGIN).substring(1), "");
 129     }
 130 
 131     /*
 132      * Tests for "\uFF21A"
 133      */
 134     @Test
 135     public void testCompactStringBufferForMixedA1() {
 136         final String ORIGIN = "\uFF21A";
 137         check(new StringBuffer(ORIGIN).delete(0, 1), "A");
 138         check(new StringBuffer(ORIGIN).delete(1, 2), "\uFF21");
 139         check(new StringBuffer(ORIGIN).deleteCharAt(1), "\uFF21");
 140         check(new StringBuffer(ORIGIN).deleteCharAt(0), "A");
 141         assertEquals(new StringBuffer(ORIGIN).indexOf("A", 0), 1);
 142         assertEquals(new StringBuffer(ORIGIN).indexOf("\uFF21", 0), 0);
 143         assertEquals(new StringBuffer(ORIGIN).indexOf("", 0), 0);
 144         check(new StringBuffer(ORIGIN).insert(1, new char[] { 'A' }), "\uFF21AA");
 145         check(new StringBuffer(ORIGIN).insert(0, new char[] { '\uFF21' }),
 146                 "\uFF21\uFF21A");
 147         assertEquals(new StringBuffer(ORIGIN).lastIndexOf("A"), 1);
 148         assertEquals(new StringBuffer(ORIGIN).lastIndexOf("\uFF21"), 0);
 149         assertEquals(new StringBuffer(ORIGIN).lastIndexOf(""), 2);
 150         check(new StringBuffer(ORIGIN).replace(0, 0, "A"), "A\uFF21A");
 151         check(new StringBuffer(ORIGIN).replace(0, 1, "A"), "AA");
 152         checkSetCharAt(new StringBuffer(ORIGIN), 0, 'A', "AA");
 153         checkSetLength(new StringBuffer(ORIGIN), 0, "");
 154         checkSetLength(new StringBuffer(ORIGIN), 1, "\uFF21");
 155         check(new StringBuffer(ORIGIN).substring(0), "\uFF21A");
 156         check(new StringBuffer(ORIGIN).substring(1), "A");
 157     }
 158 
 159     /*
 160      * Tests for "A\uFF21"
 161      */
 162     @Test
 163     public void testCompactStringBufferForMixedA2() {
 164         final String ORIGIN = "A\uFF21";
 165         check(new StringBuffer(ORIGIN).replace(1, 2, "A"), "AA");
 166         checkSetLength(new StringBuffer(ORIGIN), 1, "A");
 167         check(new StringBuffer(ORIGIN).substring(0), "A\uFF21");
 168         check(new StringBuffer(ORIGIN).substring(1), "\uFF21");
 169         check(new StringBuffer(ORIGIN).substring(0, 1), "A");
 170     }
 171 
 172     /*
 173      * Tests for "\uFF21A\uFF21A\uFF21A\uFF21A\uFF21A"
 174      */
 175     @Test
 176     public void testCompactStringBufferForDuplicatedMixedA1() {
 177         final String ORIGIN = "\uFF21A\uFF21A\uFF21A\uFF21A\uFF21A";
 178         checkSetLength(new StringBuffer(ORIGIN), 1, "\uFF21");
 179         assertEquals(new StringBuffer(ORIGIN).indexOf("A", 5), 5);
 180         assertEquals(new StringBuffer(ORIGIN).indexOf("\uFF21", 5), 6);
 181         assertEquals(new StringBuffer(ORIGIN).lastIndexOf("A"), 9);
 182         assertEquals(new StringBuffer(ORIGIN).lastIndexOf("\uFF21"), 8);
 183         assertEquals(new StringBuffer(ORIGIN).lastIndexOf(""), 10);
 184         check(new StringBuffer(ORIGIN).substring(9), "A");
 185         check(new StringBuffer(ORIGIN).substring(8), "\uFF21A");
 186     }
 187 
 188     /*
 189      * Tests for "A\uFF21A\uFF21A\uFF21A\uFF21A\uFF21"
 190      */
 191     @Test
 192     public void testCompactStringBufferForDuplicatedMixedA2() {
 193         final String ORIGIN = "A\uFF21A\uFF21A\uFF21A\uFF21A\uFF21";
 194         checkSetLength(new StringBuffer(ORIGIN), 1, "A");
 195         assertEquals(new StringBuffer(ORIGIN).indexOf("A", 5), 6);
 196         assertEquals(new StringBuffer(ORIGIN).indexOf("\uFF21", 5), 5);
 197         assertEquals(new StringBuffer(ORIGIN).lastIndexOf("A"), 8);
 198         assertEquals(new StringBuffer(ORIGIN).lastIndexOf("\uFF21"), 9);
 199         check(new StringBuffer(ORIGIN).substring(9), "\uFF21");
 200         check(new StringBuffer(ORIGIN).substring(8), "A\uFF21");
 201     }
 202 
 203     /*
 204      * Tests for "\uD801\uDC00\uD801\uDC01"
 205      */
 206     @Test
 207     public void testCompactStringForSupplementaryCodePoint() {
 208         final String ORIGIN = "\uD801\uDC00\uD801\uDC01";
 209         check(new StringBuffer(ORIGIN).append("A"), "\uD801\uDC00\uD801\uDC01A");
 210         check(new StringBuffer(ORIGIN).append("\uFF21"),
 211                 "\uD801\uDC00\uD801\uDC01\uFF21");
 212         check(new StringBuffer(ORIGIN).appendCodePoint('A'),
 213                 "\uD801\uDC00\uD801\uDC01A");
 214         check(new StringBuffer(ORIGIN).appendCodePoint('\uFF21'),
 215                 "\uD801\uDC00\uD801\uDC01\uFF21");
 216         assertEquals(new StringBuffer(ORIGIN).charAt(0), '\uD801');
 217         assertEquals(new StringBuffer(ORIGIN).codePointAt(0),
 218                 Character.codePointAt(ORIGIN, 0));
 219         assertEquals(new StringBuffer(ORIGIN).codePointAt(1),
 220                 Character.codePointAt(ORIGIN, 1));
 221         assertEquals(new StringBuffer(ORIGIN).codePointBefore(2),
 222                 Character.codePointAt(ORIGIN, 0));
 223         assertEquals(new StringBuffer(ORIGIN).codePointCount(1, 3), 2);
 224         check(new StringBuffer(ORIGIN).delete(0, 2), "\uD801\uDC01");
 225         check(new StringBuffer(ORIGIN).delete(0, 3), "\uDC01");
 226         check(new StringBuffer(ORIGIN).deleteCharAt(1), "\uD801\uD801\uDC01");
 227         checkGetChars(new StringBuffer(ORIGIN), 0, 3, new char[] { '\uD801',
 228                 '\uDC00', '\uD801' });
 229         assertEquals(new StringBuffer(ORIGIN).indexOf("\uD801\uDC01"), 2);
 230         assertEquals(new StringBuffer(ORIGIN).indexOf("\uDC01"), 3);
 231         assertEquals(new StringBuffer(ORIGIN).indexOf("\uFF21"), -1);
 232         assertEquals(new StringBuffer(ORIGIN).indexOf("A"), -1);
 233         check(new StringBuffer(ORIGIN).insert(0, "\uFF21"),
 234                 "\uFF21\uD801\uDC00\uD801\uDC01");
 235         check(new StringBuffer(ORIGIN).insert(1, "\uFF21"),
 236                 "\uD801\uFF21\uDC00\uD801\uDC01");
 237         check(new StringBuffer(ORIGIN).insert(1, "A"),
 238                 "\uD801A\uDC00\uD801\uDC01");
 239         assertEquals(new StringBuffer(ORIGIN).lastIndexOf("\uDC00\uD801"), 1);
 240         assertEquals(new StringBuffer(ORIGIN).lastIndexOf("\uD801"), 2);
 241         assertEquals(new StringBuffer(ORIGIN).lastIndexOf("\uFF21"), -1);
 242         assertEquals(new StringBuffer(ORIGIN).lastIndexOf("A"), -1);
 243         assertEquals(new StringBuffer(ORIGIN).length(), 4);
 244         assertEquals(new StringBuffer(ORIGIN).offsetByCodePoints(1, 1), 2);
 245         assertEquals(new StringBuffer(ORIGIN).offsetByCodePoints(0, 1), 2);
 246         check(new StringBuffer(ORIGIN).replace(0, 2, "A"), "A\uD801\uDC01");
 247         check(new StringBuffer(ORIGIN).replace(0, 3, "A"), "A\uDC01");
 248         check(new StringBuffer(ORIGIN).replace(0, 2, "\uFF21"),
 249                 "\uFF21\uD801\uDC01");
 250         check(new StringBuffer(ORIGIN).replace(0, 3, "\uFF21"), "\uFF21\uDC01");
 251         check(new StringBuffer(ORIGIN).reverse(), "\uD801\uDC01\uD801\uDC00");
 252         checkSetCharAt(new StringBuffer(ORIGIN), 1, '\uDC01',
 253                 "\uD801\uDC01\uD801\uDC01");
 254         checkSetCharAt(new StringBuffer(ORIGIN), 1, 'A', "\uD801A\uD801\uDC01");
 255         checkSetLength(new StringBuffer(ORIGIN), 2, "\uD801\uDC00");
 256         checkSetLength(new StringBuffer(ORIGIN), 3, "\uD801\uDC00\uD801");
 257         check(new StringBuffer(ORIGIN).substring(1, 3), "\uDC00\uD801");
 258     }
 259 
 260     /*
 261      * Tests for "A\uD801\uDC00\uFF21"
 262      */
 263     @Test
 264     public void testCompactStringForSupplementaryCodePointMixed1() {
 265         final String ORIGIN = "A\uD801\uDC00\uFF21";
 266         assertEquals(new StringBuffer(ORIGIN).codePointBefore(3),
 267                 Character.codePointAt(ORIGIN, 1));
 268         assertEquals(new StringBuffer(ORIGIN).codePointBefore(2), '\uD801');
 269         assertEquals(new StringBuffer(ORIGIN).codePointBefore(1), 'A');
 270         assertEquals(new StringBuffer(ORIGIN).codePointCount(0, 3), 2);
 271         assertEquals(new StringBuffer(ORIGIN).codePointCount(0, 4), 3);
 272         check(new StringBuffer(ORIGIN).delete(0, 1), "\uD801\uDC00\uFF21");
 273         check(new StringBuffer(ORIGIN).delete(0, 1).delete(2, 3), "\uD801\uDC00");
 274         check(new StringBuffer(ORIGIN).deleteCharAt(3).deleteCharAt(0),
 275                 "\uD801\uDC00");
 276         assertEquals(new StringBuffer(ORIGIN).indexOf("\uFF21"), 3);
 277         assertEquals(new StringBuffer(ORIGIN).indexOf("A"), 0);
 278         assertEquals(new StringBuffer(ORIGIN).lastIndexOf("\uFF21"), 3);
 279         assertEquals(new StringBuffer(ORIGIN).lastIndexOf("A"), 0);
 280         assertEquals(new StringBuffer(ORIGIN).offsetByCodePoints(0, 1), 1);
 281         assertEquals(new StringBuffer(ORIGIN).offsetByCodePoints(1, 1), 3);
 282         check(new StringBuffer(ORIGIN).replace(1, 3, "A"), "AA\uFF21");
 283         check(new StringBuffer(ORIGIN).replace(1, 4, "A"), "AA");
 284         check(new StringBuffer(ORIGIN).replace(1, 4, ""), "A");
 285         check(new StringBuffer(ORIGIN).reverse(), "\uFF21\uD801\uDC00A");
 286         checkSetLength(new StringBuffer(ORIGIN), 1, "A");
 287         check(new StringBuffer(ORIGIN).substring(0, 1), "A");
 288     }
 289 
 290     /*
 291      * Tests for "\uD801\uDC00\uFF21A"
 292      */
 293     @Test
 294     public void testCompactStringForSupplementaryCodePointMixed2() {
 295         final String ORIGIN = "\uD801\uDC00\uFF21A";
 296         assertEquals(new StringBuffer(ORIGIN).codePointBefore(3),
 297                 Character.codePointAt(ORIGIN, 2));
 298         assertEquals(new StringBuffer(ORIGIN).codePointBefore(2),
 299                 Character.codePointAt(ORIGIN, 0));
 300         assertEquals(new StringBuffer(ORIGIN).codePointBefore(1), '\uD801');
 301         assertEquals(new StringBuffer(ORIGIN).codePointCount(0, 3), 2);
 302         assertEquals(new StringBuffer(ORIGIN).codePointCount(0, 4), 3);
 303         check(new StringBuffer(ORIGIN).delete(0, 2), "\uFF21A");
 304         check(new StringBuffer(ORIGIN).delete(0, 3), "A");
 305         check(new StringBuffer(ORIGIN).deleteCharAt(0).deleteCharAt(0)
 306                 .deleteCharAt(0), "A");
 307         assertEquals(new StringBuffer(ORIGIN).indexOf("A"), 3);
 308         assertEquals(new StringBuffer(ORIGIN).delete(0, 3).indexOf("A"), 0);
 309         assertEquals(new StringBuffer(ORIGIN).replace(0, 3, "B").indexOf("A"),
 310                 1);
 311         assertEquals(new StringBuffer(ORIGIN).substring(3, 4).indexOf("A"), 0);
 312         assertEquals(new StringBuffer(ORIGIN).offsetByCodePoints(1, 1), 2);
 313         assertEquals(new StringBuffer(ORIGIN).offsetByCodePoints(0, 1), 2);
 314         assertEquals(new StringBuffer(ORIGIN).offsetByCodePoints(2, 1), 3);
 315         check(new StringBuffer(ORIGIN).replace(0, 3, "B"), "BA");
 316         check(new StringBuffer(ORIGIN).reverse(), "A\uFF21\uD801\uDC00");
 317     }
 318 
 319     /*
 320      * Tests for "\uD801A\uDC00\uFF21"
 321      */
 322     @Test
 323     public void testCompactStringForSupplementaryCodePointMixed3() {
 324         final String ORIGIN = "\uD801A\uDC00\uFF21";
 325         assertEquals(new StringBuffer(ORIGIN).codePointAt(1), 'A');
 326         assertEquals(new StringBuffer(ORIGIN).codePointAt(3), '\uFF21');
 327         assertEquals(new StringBuffer(ORIGIN).codePointBefore(1), '\uD801');
 328         assertEquals(new StringBuffer(ORIGIN).codePointBefore(2), 'A');
 329         assertEquals(new StringBuffer(ORIGIN).codePointBefore(3), '\uDC00');
 330         assertEquals(new StringBuffer(ORIGIN).codePointCount(0, 3), 3);
 331         assertEquals(new StringBuffer(ORIGIN).codePointCount(1, 3), 2);
 332         assertEquals(new StringBuffer(ORIGIN).delete(0, 1).delete(1, 3)
 333                 .indexOf("A"), 0);
 334         assertEquals(
 335                 new StringBuffer(ORIGIN).replace(0, 1, "B").replace(2, 4, "C")
 336                         .indexOf("A"), 1);
 337         assertEquals(new StringBuffer(ORIGIN).substring(1, 4).substring(0, 1)
 338                 .indexOf("A"), 0);
 339         assertEquals(new StringBuffer(ORIGIN).offsetByCodePoints(0, 1), 1);
 340         assertEquals(new StringBuffer(ORIGIN).offsetByCodePoints(1, 1), 2);
 341         assertEquals(new StringBuffer(ORIGIN).offsetByCodePoints(2, 1), 3);
 342         check(new StringBuffer(ORIGIN).reverse(), "\uFF21\uDC00A\uD801");
 343     }
 344 
 345     /*
 346      * Tests for "A\uDC01\uFF21\uD801"
 347      */
 348     @Test
 349     public void testCompactStringForSupplementaryCodePointMixed4() {
 350         final String ORIGIN = "A\uDC01\uFF21\uD801";
 351         assertEquals(new StringBuffer(ORIGIN).codePointAt(1), '\uDC01');
 352         assertEquals(new StringBuffer(ORIGIN).codePointAt(3), '\uD801');
 353         assertEquals(new StringBuffer(ORIGIN).codePointBefore(1), 'A');
 354         assertEquals(new StringBuffer(ORIGIN).codePointBefore(2), '\uDC01');
 355         assertEquals(new StringBuffer(ORIGIN).codePointBefore(3), '\uFF21');
 356         assertEquals(new StringBuffer(ORIGIN).codePointCount(0, 3), 3);
 357         assertEquals(new StringBuffer(ORIGIN).codePointCount(1, 3), 2);
 358         assertEquals(new StringBuffer(ORIGIN).delete(1, 4).indexOf("A"), 0);
 359         assertEquals(new StringBuffer(ORIGIN).replace(1, 4, "B").indexOf("A"),
 360                 0);
 361         assertEquals(new StringBuffer(ORIGIN).substring(0, 1).indexOf("A"), 0);
 362         assertEquals(new StringBuffer(ORIGIN).offsetByCodePoints(0, 1), 1);
 363         assertEquals(new StringBuffer(ORIGIN).offsetByCodePoints(1, 1), 2);
 364         assertEquals(new StringBuffer(ORIGIN).offsetByCodePoints(2, 1), 3);
 365         check(new StringBuffer(ORIGIN).reverse(), "\uD801\uFF21\uDC01A");
 366     }
 367 
 368     @Test
 369     public void testCompactStringMisc() {
 370         String ascii = "abcdefgh";
 371         String asciiMixed = "abc" + "\u4e00\u4e01\u4e02" + "fgh";
 372         String bmp = "\u4e00\u4e01\u4e02\u4e03\u4e04\u4e05\u4e06\u4e07\u4e08";
 373         String bmpMixed = "\u4e00\u4e01\u4e02" + "ABC" + "\u4e06\u4e07\u4e08";
 374 
 375         check(new StringBuffer().append(ascii).delete(0, 20).toString(),
 376               "");
 377         check(new StringBuffer().append(ascii).delete(3, 20).toString(),
 378               "abc");
 379         check(new StringBuffer().append(ascii).delete(3, 6).toString(),
 380               "abcgh");
 381         check(new StringBuffer().append(ascii).deleteCharAt(0).toString(),
 382               "bcdefgh");
 383         check(new StringBuffer().append(ascii).deleteCharAt(3).toString(),
 384               "abcefgh");
 385         check(new StringBuffer().append(asciiMixed).delete(3, 6).toString(),
 386               "abcfgh");
 387         check(new StringBuffer().append(asciiMixed).deleteCharAt(3).toString(),
 388               "abc\u4e01\u4e02fgh");
 389         check(new StringBuffer().append(asciiMixed).deleteCharAt(3)
 390                                                    .deleteCharAt(3)
 391                                                    .deleteCharAt(3).toString(),
 392               "abcfgh");
 393         check(new StringBuffer().append(bmp).delete(0, 20).toString(),
 394               "");
 395         check(new StringBuffer().append(bmp).delete(3, 20).toString(),
 396               "\u4e00\u4e01\u4e02");
 397         check(new StringBuffer().append(bmp).delete(3, 6).toString(),
 398               "\u4e00\u4e01\u4e02\u4e06\u4e07\u4e08");
 399         check(new StringBuffer().append(bmp).deleteCharAt(0).toString(),
 400               "\u4e01\u4e02\u4e03\u4e04\u4e05\u4e06\u4e07\u4e08");
 401         check(new StringBuffer().append(bmp).deleteCharAt(3).toString(),
 402               "\u4e00\u4e01\u4e02\u4e04\u4e05\u4e06\u4e07\u4e08");
 403         check(new StringBuffer().append(bmpMixed).delete(3, 6).toString(),
 404               "\u4e00\u4e01\u4e02\u4e06\u4e07\u4e08");
 405 
 406         ////////////////////////////////////////////////////////////////////
 407         check(new StringBuffer().append(ascii).replace(3, 6, "AB").toString(),
 408               "abcABgh");
 409         check(new StringBuffer().append(asciiMixed).replace(3, 6, "AB").toString(),
 410               "abcABfgh");
 411         check(new StringBuffer().append(bmp).replace(3, 6, "AB").toString(),
 412               "\u4e00\u4e01\u4e02AB\u4e06\u4e07\u4e08");
 413 
 414         check(new StringBuffer().append(bmpMixed).replace(3, 6, "").toString(),
 415               "\u4e00\u4e01\u4e02\u4e06\u4e07\u4e08");
 416 
 417         check(new StringBuffer().append(ascii).replace(3, 6, "\u4e01\u4e02").toString(),
 418               "abc\u4e01\u4e02gh");
 419 
 420         ////////////////////////////////////////////////////////////////////
 421         check(new StringBuffer().append(ascii).insert(3, "").toString(),
 422               "abcdefgh");
 423         check(new StringBuffer().append(ascii).insert(3, "AB").toString(),
 424               "abcABdefgh");
 425         check(new StringBuffer().append(ascii).insert(3, "\u4e01\u4e02").toString(),
 426               "abc\u4e01\u4e02defgh");
 427 
 428         check(new StringBuffer().append(asciiMixed).insert(0, 'A').toString(),
 429               "Aabc\u4e00\u4e01\u4e02fgh");
 430         check(new StringBuffer().append(asciiMixed).insert(3, "A").toString(),
 431               "abcA\u4e00\u4e01\u4e02fgh");
 432 
 433         check(new StringBuffer().append(ascii).insert(3, 1234567).toString(),
 434               "abc1234567defgh");
 435         check(new StringBuffer().append(bmp).insert(3, 1234567).toString(),
 436               "\u4e00\u4e01\u4e021234567\u4e03\u4e04\u4e05\u4e06\u4e07\u4e08");
 437 
 438         ////////////////////////////////////////////////////////////////////
 439         check(new StringBuffer().append(ascii).append(1.23456).toString(),
 440               "abcdefgh1.23456");
 441         check(new StringBuffer().append(bmp).append(1.23456).toString(),
 442               "\u4e00\u4e01\u4e02\u4e03\u4e04\u4e05\u4e06\u4e07\u4e081.23456");
 443 
 444         ////////////////////////////////////////////////////////////////////
 445         check(new StringBuffer((CharSequence)new StringBuffer(ascii)).toString(),
 446               ascii);
 447         check(new StringBuffer((CharSequence)new StringBuffer(asciiMixed)).toString(),
 448               asciiMixed);
 449     }
 450 
 451     private void checkGetChars(StringBuffer sb, int srcBegin, int srcEnd,
 452             char expected[]) {
 453         char[] dst = new char[srcEnd - srcBegin];
 454         sb.getChars(srcBegin, srcEnd, dst, 0);
 455         assertTrue(Arrays.equals(dst, expected));
 456     }
 457 
 458     private void checkSetCharAt(StringBuffer sb, int index, char ch,
 459             String expected) {
 460         sb.setCharAt(index, ch);
 461         check(sb, expected);
 462     }
 463 
 464     private void checkSetLength(StringBuffer sb, int newLength, String expected) {
 465         sb.setLength(newLength);
 466         check(sb, expected);
 467     }
 468 
 469     private void check(StringBuffer sb, String expected) {
 470         check(sb.toString(), expected);
 471     }
 472 
 473     private void check(String str, String expected) {
 474         assertTrue(str.equals(expected), String.format(
 475                 "Get (%s) but expect (%s), ", escapeNonASCIIs(str),
 476                 escapeNonASCIIs(expected)));
 477     }
 478 
 479     /*
 480      * Escape non-ASCII characters since not all systems support them.
 481      */
 482     private String escapeNonASCIIs(String str) {
 483         StringBuilder sb = new StringBuilder();
 484         for (int i = 0; i < str.length(); i++) {
 485             char c = str.charAt(i);
 486             if (c > 0x7F) {
 487                 sb.append("\\u").append(Integer.toHexString((int) c));
 488             } else {
 489                 sb.append(c);
 490             }
 491         }
 492         return sb.toString();
 493     }
 494 }