undefect. CWE-407 — 63 sites patched across 27 ecosystems
Authors: russell@unturf.com · brackishbert@gmail.com · foxhop.net · TimeHexOn.com Patches, unit tests, benchmarks, whitepaper, and outreach briefs. Public domain — no copyright claimed. Use freely.
This commit is contained in:
commit
0a580b313d
70422 changed files with 17213626 additions and 0 deletions
72
test/jdk/java/lang/StringBuilder/AppendStringBuffer.java
Normal file
72
test/jdk/java/lang/StringBuilder/AppendStringBuffer.java
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* Copyright (c) 2012, 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 6206780
|
||||
* @summary Test StringBuilder.append(StringBuffer);
|
||||
* @key randomness
|
||||
*/
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
public class AppendStringBuffer {
|
||||
private static Random generator = new Random();
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
for (int i=0; i<1000; i++) {
|
||||
StringBuffer sb1 = generateTestBuffer(10, 100);
|
||||
StringBuffer sb2 = generateTestBuffer(10, 100);
|
||||
StringBuffer sb3 = generateTestBuffer(10, 100);
|
||||
String s1 = sb1.toString();
|
||||
String s2 = sb2.toString();
|
||||
String s3 = sb3.toString();
|
||||
|
||||
String concatResult = new String(s1+s2+s3);
|
||||
|
||||
StringBuilder test = new StringBuilder();
|
||||
test.append(sb1);
|
||||
test.append(sb2);
|
||||
test.append(sb3);
|
||||
|
||||
if (!test.toString().equals(concatResult))
|
||||
throw new RuntimeException("StringBuffer.append failure");
|
||||
}
|
||||
}
|
||||
|
||||
private static int getRandomIndex(int constraint1, int constraint2) {
|
||||
int range = constraint2 - constraint1;
|
||||
int x = generator.nextInt(range);
|
||||
return constraint1 + x;
|
||||
}
|
||||
|
||||
private static StringBuffer generateTestBuffer(int min, int max) {
|
||||
StringBuffer aNewStringBuffer = new StringBuffer(120);
|
||||
int aNewLength = getRandomIndex(min, max);
|
||||
for(int y=0; y<aNewLength; y++) {
|
||||
int achar = generator.nextInt(30)+30;
|
||||
char test = (char)(achar);
|
||||
aNewStringBuffer.append(test);
|
||||
}
|
||||
return aNewStringBuffer;
|
||||
}
|
||||
}
|
||||
266
test/jdk/java/lang/StringBuilder/BuilderForwarding.java
Normal file
266
test/jdk/java/lang/StringBuilder/BuilderForwarding.java
Normal file
|
|
@ -0,0 +1,266 @@
|
|||
/*
|
||||
* Copyright (c) 2012, 2013, 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 6206780
|
||||
* @summary Test forwarding of methods to super in StringBuilder
|
||||
* @author Jim Gish <jim.gish@oracle.com>
|
||||
*/
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class BuilderForwarding {
|
||||
private static final String A_STRING_BUFFER_VAL = "aStringBuffer";
|
||||
private static final String A_STRING_BUILDER_VAL = "aStringBuilder";
|
||||
private static final String A_STRING_VAL = "aString";
|
||||
private static final String NON_EMPTY_VAL = "NonEmpty";
|
||||
|
||||
public BuilderForwarding() {
|
||||
System.out.println( "Starting BuilderForwarding");
|
||||
}
|
||||
|
||||
public static void main(String... args) {
|
||||
new BuilderForwarding().executeTestMethods();
|
||||
}
|
||||
|
||||
public void executeTestMethods() {
|
||||
appendCharSequence();
|
||||
indexOfString();
|
||||
indexOfStringIntNull();
|
||||
indexOfStringNull();
|
||||
indexOfStringint();
|
||||
insertintCharSequence();
|
||||
insertintObject();
|
||||
insertintboolean();
|
||||
insertintchar();
|
||||
insertintdouble();
|
||||
insertintfloat();
|
||||
insertintint();
|
||||
insertintlong();
|
||||
lastIndexOfString();
|
||||
lastIndexOfStringint();
|
||||
}
|
||||
|
||||
public void appendCharSequence() {
|
||||
// three different flavors of CharSequence
|
||||
CharSequence aString = A_STRING_VAL;
|
||||
CharSequence aStringBuilder = new StringBuilder(A_STRING_BUILDER_VAL);
|
||||
CharSequence aStringBuffer = new StringBuffer(A_STRING_BUFFER_VAL);
|
||||
|
||||
assertEquals( /*actual*/ new StringBuilder().append(aString).toString(), /*expected*/ A_STRING_VAL );
|
||||
assertEquals( new StringBuilder().append(aStringBuilder).toString(), A_STRING_BUILDER_VAL );
|
||||
assertEquals( new StringBuilder().append(aStringBuffer).toString(), A_STRING_BUFFER_VAL );
|
||||
|
||||
assertEquals( /*actual*/ new StringBuilder(NON_EMPTY_VAL).append(aString).toString(), NON_EMPTY_VAL+A_STRING_VAL );
|
||||
assertEquals( new StringBuilder(NON_EMPTY_VAL).append(aStringBuilder).toString(), NON_EMPTY_VAL+A_STRING_BUILDER_VAL );
|
||||
assertEquals( new StringBuilder(NON_EMPTY_VAL).append(aStringBuffer).toString(), NON_EMPTY_VAL+A_STRING_BUFFER_VAL );
|
||||
}
|
||||
|
||||
|
||||
public void indexOfString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
// should be NPE if null passed
|
||||
try {
|
||||
|
||||
sb.indexOf(null);
|
||||
throw new RuntimeException("Test failed: should have thrown NPE");
|
||||
|
||||
|
||||
} catch (NullPointerException npe) {
|
||||
// expected: passed
|
||||
} catch (Throwable t) {
|
||||
throw new RuntimeException("Test failed: should have thrown NPE. Instead threw "
|
||||
+ t);
|
||||
}
|
||||
sb = new StringBuilder("xyz");
|
||||
assertEquals( sb.indexOf("y"), 1 );
|
||||
assertEquals( sb.indexOf("not found"), -1 );
|
||||
}
|
||||
|
||||
|
||||
public void indexOfStringint() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
// should be NPE if null passed
|
||||
try {
|
||||
sb.indexOf(null,1);
|
||||
throw new RuntimeException("Test failed: should have thrown NPE");
|
||||
} catch (NullPointerException npe) {
|
||||
// expected: passed
|
||||
} catch (Throwable t) {
|
||||
throw new RuntimeException("Test failed: should have thrown NPE");
|
||||
}
|
||||
sb = new StringBuilder("xyyz");
|
||||
assertEquals( sb.indexOf("y",0), 1 );
|
||||
assertEquals( sb.indexOf("y",1), 1 );
|
||||
assertEquals( sb.indexOf("y",2), 2 );
|
||||
assertEquals( sb.indexOf("not found"), -1 );
|
||||
}
|
||||
|
||||
|
||||
public void indexOfStringIntNull() {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
// should be NPE if null passed
|
||||
try {
|
||||
sb.indexOf(null,1);
|
||||
throw new RuntimeException("Test failed: should have thrown NPE");
|
||||
} catch (NullPointerException npe) {
|
||||
// expected: passed
|
||||
} catch (Throwable t) {
|
||||
throw new RuntimeException("Test failed: should have thrown NPE. Instead threw "
|
||||
+ t);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void indexOfStringNull() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
// should be NPE if null passed
|
||||
try {
|
||||
sb.indexOf(null);
|
||||
throw new RuntimeException("Test failed: should have thrown NPE");
|
||||
} catch (NullPointerException npe) {
|
||||
// expected: passed
|
||||
} catch (Throwable t) {
|
||||
throw new RuntimeException("Test failed: should have thrown NPE. Instead threw "
|
||||
+ t);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void insertintboolean() {
|
||||
boolean b = true;
|
||||
StringBuilder sb = new StringBuilder("012345");
|
||||
assertEquals( sb.insert( 2, b).toString(), "01true2345");
|
||||
}
|
||||
|
||||
|
||||
public void insertintchar() {
|
||||
char c = 'C';
|
||||
StringBuilder sb = new StringBuilder("012345");
|
||||
assertEquals( sb.insert( 2, c ).toString(), "01C2345");
|
||||
}
|
||||
|
||||
|
||||
public void insertintCharSequence() {
|
||||
final String initString = "012345";
|
||||
// three different flavors of CharSequence
|
||||
CharSequence aString = A_STRING_VAL;
|
||||
CharSequence aStringBuilder = new StringBuilder(A_STRING_BUILDER_VAL);
|
||||
CharSequence aStringBuffer = new StringBuffer(A_STRING_BUFFER_VAL);
|
||||
|
||||
assertEquals( new StringBuilder(initString).insert(2, aString).toString(), "01"+A_STRING_VAL+"2345" );
|
||||
|
||||
assertEquals( new StringBuilder(initString).insert(2, aStringBuilder).toString(), "01"+A_STRING_BUILDER_VAL+"2345" );
|
||||
|
||||
assertEquals( new StringBuilder(initString).insert(2, aStringBuffer).toString(), "01"+A_STRING_BUFFER_VAL+"2345" );
|
||||
|
||||
try {
|
||||
new StringBuilder(initString).insert(7, aString);
|
||||
throw new RuntimeException("Test failed: should have thrown IndexOutOfBoundsException");
|
||||
} catch (IndexOutOfBoundsException soob) {
|
||||
// expected: passed
|
||||
} catch (Throwable t) {
|
||||
throw new RuntimeException("Test failed: should have thrown IndexOutOfBoundsException, but instead threw " + t.getMessage());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void insertintdouble() {
|
||||
double d = 99d;
|
||||
StringBuilder sb = new StringBuilder("012345");
|
||||
assertEquals( sb.insert( 2, d ).toString(), "0199.02345"); }
|
||||
|
||||
|
||||
public void insertintfloat() {
|
||||
float f = 99.0f;
|
||||
StringBuilder sb = new StringBuilder("012345");
|
||||
assertEquals( sb.insert( 2, f ).toString(), "0199.02345"); }
|
||||
|
||||
|
||||
public void insertintint() {
|
||||
int i = 99;
|
||||
StringBuilder sb = new StringBuilder("012345");
|
||||
assertEquals( sb.insert( 2, i ).toString(), "01992345");
|
||||
}
|
||||
|
||||
|
||||
public void insertintlong() {
|
||||
long l = 99;
|
||||
StringBuilder sb = new StringBuilder("012345");
|
||||
assertEquals( sb.insert( 2, l ).toString(), "01992345"); }
|
||||
|
||||
|
||||
public void insertintObject() {
|
||||
StringBuilder sb = new StringBuilder("012345");
|
||||
List<String> ls = new ArrayList<String>();
|
||||
ls.add("A"); ls.add("B");
|
||||
String lsString = ls.toString();
|
||||
assertEquals( sb.insert(2, ls).toString(), "01"+lsString+"2345");
|
||||
|
||||
try {
|
||||
sb.insert(sb.length()+1, ls);
|
||||
throw new RuntimeException("Test failed: should have thrown StringIndexOutOfBoundsException");
|
||||
} catch (StringIndexOutOfBoundsException soob) {
|
||||
// expected: passed
|
||||
} catch (Throwable t) {
|
||||
throw new RuntimeException("Test failed: should have thrown StringIndexOutOfBoundsException, but instead threw:"
|
||||
+ t);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void lastIndexOfString() {
|
||||
String xyz = "xyz";
|
||||
String xyz3 = "xyzxyzxyz";
|
||||
StringBuilder sb = new StringBuilder(xyz3);
|
||||
int pos = sb.lastIndexOf("xyz");
|
||||
assertEquals( pos, 2*xyz.length() );
|
||||
}
|
||||
|
||||
|
||||
public void lastIndexOfStringint() {
|
||||
StringBuilder sb = new StringBuilder("xyzxyzxyz");
|
||||
int pos = sb.lastIndexOf("xyz",5);
|
||||
assertEquals( pos, 3 );
|
||||
pos = sb.lastIndexOf("xyz", 6);
|
||||
assertEquals( pos, 6 );
|
||||
}
|
||||
|
||||
public void assertEquals( String actual, String expected) {
|
||||
if (!actual.equals( expected )) {
|
||||
throw new RuntimeException( "Test failed: actual = '" + actual +
|
||||
"', expected = '" + expected + "'");
|
||||
}
|
||||
}
|
||||
|
||||
public void assertEquals( int actual, int expected) {
|
||||
if (actual != expected) {
|
||||
throw new RuntimeException( "Test failed: actual = '" + actual +
|
||||
"', expected = '" + expected + "'");
|
||||
}
|
||||
}
|
||||
}
|
||||
182
test/jdk/java/lang/StringBuilder/Capacity.java
Normal file
182
test/jdk/java/lang/StringBuilder/Capacity.java
Normal file
|
|
@ -0,0 +1,182 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 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 8149330
|
||||
* @summary Basic set of tests of capacity management
|
||||
* @run testng Capacity
|
||||
*/
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.AbstractList;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.SplittableRandom;
|
||||
|
||||
import org.testng.annotations.Test;
|
||||
import org.testng.annotations.DataProvider;
|
||||
import static org.testng.Assert.*;
|
||||
|
||||
public class Capacity {
|
||||
static final int DEFAULT_CAPACITY = 16;
|
||||
|
||||
private static int newCapacity(int oldCapacity,
|
||||
int desiredCapacity)
|
||||
{
|
||||
return Math.max(oldCapacity * 2 + 2, desiredCapacity);
|
||||
}
|
||||
|
||||
private static int nextNewCapacity(int oldCapacity) {
|
||||
return newCapacity(oldCapacity, oldCapacity + 1);
|
||||
}
|
||||
|
||||
@Test(dataProvider = "singleChar")
|
||||
public void defaultCapacity(Character ch) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
assertEquals(sb.capacity(), DEFAULT_CAPACITY);
|
||||
for (int i = 0; i < DEFAULT_CAPACITY; i++) {
|
||||
sb.append(ch);
|
||||
assertEquals(sb.capacity(), DEFAULT_CAPACITY);
|
||||
}
|
||||
sb.append(ch);
|
||||
assertEquals(sb.capacity(), nextNewCapacity(DEFAULT_CAPACITY));
|
||||
}
|
||||
|
||||
@Test(dataProvider = "charCapacity")
|
||||
public void explicitCapacity(Character ch, int initCapacity) {
|
||||
StringBuilder sb = new StringBuilder(initCapacity);
|
||||
assertEquals(sb.capacity(), initCapacity);
|
||||
for (int i = 0; i < initCapacity; i++) {
|
||||
sb.append(ch);
|
||||
assertEquals(sb.capacity(), initCapacity);
|
||||
}
|
||||
sb.append(ch);
|
||||
assertEquals(sb.capacity(), nextNewCapacity(initCapacity));
|
||||
}
|
||||
|
||||
@Test(dataProvider = "singleChar")
|
||||
public void sbFromString(Character ch) {
|
||||
String s = "string " + ch;
|
||||
int expectedCapacity = s.length() + DEFAULT_CAPACITY;
|
||||
StringBuilder sb = new StringBuilder(s);
|
||||
assertEquals(sb.capacity(), expectedCapacity);
|
||||
for (int i = 0; i < DEFAULT_CAPACITY; i++) {
|
||||
sb.append(ch);
|
||||
assertEquals(sb.capacity(), expectedCapacity);
|
||||
}
|
||||
sb.append(ch);
|
||||
assertEquals(sb.capacity(), nextNewCapacity(expectedCapacity));
|
||||
}
|
||||
|
||||
@Test(dataProvider = "singleChar")
|
||||
public void sbFromCharSeq(Character ch) {
|
||||
CharSequence cs = new MyCharSeq("char seq " + ch);
|
||||
int expectedCapacity = cs.length() + DEFAULT_CAPACITY;
|
||||
StringBuilder sb = new StringBuilder(cs);
|
||||
assertEquals(sb.capacity(), expectedCapacity);
|
||||
for (int i = 0; i < DEFAULT_CAPACITY; i++) {
|
||||
sb.append(ch);
|
||||
assertEquals(sb.capacity(), expectedCapacity);
|
||||
}
|
||||
sb.append(ch);
|
||||
assertEquals(sb.capacity(), nextNewCapacity(expectedCapacity));
|
||||
}
|
||||
|
||||
@Test(dataProvider = "charCapacity")
|
||||
public void ensureCapacity(Character ch, int cap) {
|
||||
StringBuilder sb = new StringBuilder(0);
|
||||
assertEquals(sb.capacity(), 0);
|
||||
sb.ensureCapacity(cap); // only has effect if cap > 0
|
||||
int newCap = (cap == 0) ? 0 : newCapacity(0, cap);
|
||||
assertEquals(sb.capacity(), newCap);
|
||||
sb.ensureCapacity(newCap + 1);
|
||||
assertEquals(sb.capacity(), nextNewCapacity(newCap));
|
||||
sb.append(ch);
|
||||
assertEquals(sb.capacity(), nextNewCapacity(newCap));
|
||||
}
|
||||
|
||||
@Test(dataProvider = "negativeCapacity",
|
||||
expectedExceptions = NegativeArraySizeException.class)
|
||||
public void negativeInitialCapacity(int negCap) {
|
||||
StringBuilder sb = new StringBuilder(negCap);
|
||||
}
|
||||
|
||||
@Test(dataProvider = "negativeCapacity")
|
||||
public void ensureNegativeCapacity(int negCap) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.ensureCapacity(negCap);
|
||||
assertEquals(sb.capacity(), DEFAULT_CAPACITY);
|
||||
}
|
||||
|
||||
@Test(dataProvider = "charCapacity")
|
||||
public void trimToSize(Character ch, int cap) {
|
||||
StringBuilder sb = new StringBuilder(cap);
|
||||
int halfOfCap = cap / 2;
|
||||
for (int i = 0; i < halfOfCap; i++) {
|
||||
sb.append(ch);
|
||||
}
|
||||
sb.trimToSize();
|
||||
// according to the spec, capacity doesn't have to
|
||||
// become exactly the size
|
||||
assertTrue(sb.capacity() >= halfOfCap);
|
||||
}
|
||||
|
||||
@DataProvider
|
||||
public Object[][] singleChar() {
|
||||
return new Object[][] { {'J'}, {'\u042b'} };
|
||||
}
|
||||
|
||||
@DataProvider
|
||||
public Object[][] charCapacity() {
|
||||
return new Object[][] {
|
||||
{'J', 0},
|
||||
{'J', 1},
|
||||
{'J', 15},
|
||||
{'J', DEFAULT_CAPACITY},
|
||||
{'J', 1024},
|
||||
{'\u042b', 0},
|
||||
{'\u042b', 1},
|
||||
{'\u042b', 15},
|
||||
{'\u042b', DEFAULT_CAPACITY},
|
||||
{'\u042b', 1024},
|
||||
};
|
||||
}
|
||||
|
||||
@DataProvider
|
||||
public Object[][] negativeCapacity() {
|
||||
return new Object[][] { {-1}, {Integer.MIN_VALUE} };
|
||||
}
|
||||
|
||||
private static class MyCharSeq implements CharSequence {
|
||||
private CharSequence s;
|
||||
public MyCharSeq(CharSequence s) { this.s = s; }
|
||||
public char charAt(int i) { return s.charAt(i); }
|
||||
public int length() { return s.length(); }
|
||||
public CharSequence subSequence(int st, int e) {
|
||||
return s.subSequence(st, e);
|
||||
}
|
||||
public String toString() { return s.toString(); }
|
||||
}
|
||||
}
|
||||
84
test/jdk/java/lang/StringBuilder/CharAt.java
Normal file
84
test/jdk/java/lang/StringBuilder/CharAt.java
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* Copyright (c) 2021, 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 8271732
|
||||
* @summary Basic test that charAt throws IIOBE as expected for out of bounds indexes.
|
||||
* @run testng CharAt
|
||||
*/
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.testng.annotations.Test;
|
||||
import org.testng.annotations.DataProvider;
|
||||
import static org.testng.Assert.*;
|
||||
|
||||
public class CharAt {
|
||||
|
||||
/**
|
||||
* StringBuilder/-Buffer.charAt throws:
|
||||
* IndexOutOfBoundsException - if index is negative or greater than or equal to length().
|
||||
* the test inputs, expected to throw IndexOutOfBoundsException.
|
||||
*/
|
||||
@Test
|
||||
public void charAtIIOBE() {
|
||||
StringBuilder sb = new StringBuilder("test");
|
||||
StringBuffer sbuf = new StringBuffer("test");
|
||||
|
||||
StringBuilder sbUtf16 = new StringBuilder("\uFF34est"); // Fullwidth Latin Capital Letter T
|
||||
StringBuffer sbufUtf16 = new StringBuffer("\uFF34est");
|
||||
|
||||
List<Integer> outOfBoundsIndices = List.of(Integer.MIN_VALUE, -2, -1, 4, 5, Integer.MAX_VALUE);
|
||||
|
||||
for (int index : outOfBoundsIndices) {
|
||||
try {
|
||||
sb.charAt(index);
|
||||
fail("StringBuilder.charAt index: " + index + " does not throw IOOBE as expected");
|
||||
} catch (IndexOutOfBoundsException ex) {
|
||||
// OK
|
||||
}
|
||||
|
||||
try {
|
||||
sbUtf16.charAt(index);
|
||||
fail("StringBuilder.charAt index: " + index + " does not throw IOOBE as expected (UTF-16)");
|
||||
} catch (IndexOutOfBoundsException ex) {
|
||||
// OK
|
||||
}
|
||||
|
||||
try {
|
||||
sbuf.charAt(index);
|
||||
fail("StringBuffer.charAt index: " + index + " does not throw IOOBE as expected");
|
||||
} catch (IndexOutOfBoundsException ex) {
|
||||
// OK
|
||||
}
|
||||
|
||||
try {
|
||||
sbufUtf16.charAt(index);
|
||||
fail("StringBuffer.charAt index: " + index + " does not throw IOOBE as expected (UTF-16)");
|
||||
} catch (IndexOutOfBoundsException ex) {
|
||||
// OK
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
503
test/jdk/java/lang/StringBuilder/CompactStringBuilder.java
Normal file
503
test/jdk/java/lang/StringBuilder/CompactStringBuilder.java
Normal file
|
|
@ -0,0 +1,503 @@
|
|||
/*
|
||||
* Copyright (c) 2015, 2025, 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.
|
||||
*/
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import static org.testng.Assert.assertEquals;
|
||||
import static org.testng.Assert.assertTrue;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8054307 8077559 8351443
|
||||
* @summary Tests Compact String. This test is testing StringBuilder
|
||||
* behavior related to Compact String.
|
||||
* @run testng/othervm/timeout=480 -XX:+CompactStrings CompactStringBuilder
|
||||
* @run testng/othervm/timeout=480 -XX:-CompactStrings CompactStringBuilder
|
||||
* @run testng/othervm/timeout=480 -Xcomp CompactStringBuilder
|
||||
*/
|
||||
|
||||
public class CompactStringBuilder {
|
||||
|
||||
/*
|
||||
* Tests for "A"
|
||||
*/
|
||||
@Test
|
||||
public void testCompactStringBuilderForLatinA() {
|
||||
final String ORIGIN = "A";
|
||||
/*
|
||||
* Because right now ASCII is the default encoding parameter for source
|
||||
* code in JDK build environment, so we escape them. same as below.
|
||||
*/
|
||||
check(new StringBuilder(ORIGIN).append(new char[] { '\uFF21' }),
|
||||
"A\uFF21");
|
||||
check(new StringBuilder(ORIGIN).append(new StringBuffer("\uFF21")),
|
||||
"A\uFF21");
|
||||
check(new StringBuilder(ORIGIN).append("\uFF21"), "A\uFF21");
|
||||
check(new StringBuilder(ORIGIN).append(new char[] { 'a', 'b', 'c'}),
|
||||
"Aabc");
|
||||
check(new StringBuilder(ORIGIN).append(new char[] { 'a', 'b', 'c'}, 1, 2),
|
||||
"Abc");
|
||||
check(new StringBuilder(ORIGIN).append(new StringBuffer("\uFF21")),
|
||||
"A\uFF21");
|
||||
check(new StringBuilder(ORIGIN).delete(0, 1), "");
|
||||
check(new StringBuilder(ORIGIN).delete(0, 0), "A");
|
||||
check(new StringBuilder(ORIGIN).deleteCharAt(0), "");
|
||||
assertEquals(new StringBuilder(ORIGIN).indexOf("A", 0), 0);
|
||||
assertEquals(new StringBuilder(ORIGIN).indexOf("\uFF21", 0), -1);
|
||||
assertEquals(new StringBuilder(ORIGIN).indexOf("", 0), 0);
|
||||
assertEquals(new StringBuilder(ORIGIN).insert(1, "\uD801\uDC00")
|
||||
.indexOf("A", 0), 0);
|
||||
assertEquals(new StringBuilder(ORIGIN).insert(0, "\uD801\uDC00")
|
||||
.indexOf("A", 0), 2);
|
||||
check(new StringBuilder(ORIGIN).insert(0, new char[] {}), "A");
|
||||
check(new StringBuilder(ORIGIN).insert(1, new char[] { '\uFF21' }),
|
||||
"A\uFF21");
|
||||
check(new StringBuilder(ORIGIN).insert(0, new char[] { '\uFF21' }),
|
||||
"\uFF21A");
|
||||
check(new StringBuilder(ORIGIN).insert(0, new StringBuffer("\uFF21")),
|
||||
"\uFF21A");
|
||||
check(new StringBuilder(ORIGIN).insert(1, new StringBuffer("\uFF21")),
|
||||
"A\uFF21");
|
||||
check(new StringBuilder(ORIGIN).insert(0, ""), "A");
|
||||
check(new StringBuilder(ORIGIN).insert(0, "\uFF21"), "\uFF21A");
|
||||
check(new StringBuilder(ORIGIN).insert(1, "\uFF21"), "A\uFF21");
|
||||
assertEquals(new StringBuilder(ORIGIN).lastIndexOf("A"), 0);
|
||||
assertEquals(new StringBuilder(ORIGIN).lastIndexOf("\uFF21"), -1);
|
||||
assertEquals(new StringBuilder(ORIGIN).lastIndexOf(""), 1);
|
||||
check(new StringBuilder(ORIGIN).replace(0, 0, "\uFF21"), "\uFF21A");
|
||||
check(new StringBuilder(ORIGIN).replace(0, 1, "\uFF21"), "\uFF21");
|
||||
checkSetCharAt(new StringBuilder(ORIGIN), 0, '\uFF21', "\uFF21");
|
||||
checkSetLength(new StringBuilder(ORIGIN), 0, "");
|
||||
checkSetLength(new StringBuilder(ORIGIN), 1, "A");
|
||||
check(new StringBuilder(ORIGIN).substring(0), "A");
|
||||
check(new StringBuilder(ORIGIN).substring(1), "");
|
||||
}
|
||||
|
||||
/*
|
||||
* Tests for "\uFF21"
|
||||
*/
|
||||
@Test
|
||||
public void testCompactStringBuilderForNonLatinA() {
|
||||
final String ORIGIN = "\uFF21";
|
||||
check(new StringBuilder(ORIGIN).append(new char[] { 'A' }), "\uFF21A");
|
||||
check(new StringBuilder(ORIGIN).append(new StringBuffer("A")), "\uFF21A");
|
||||
check(new StringBuilder(ORIGIN).append("A"), "\uFF21A");
|
||||
check(new StringBuilder(ORIGIN).append(new StringBuffer("A")), "\uFF21A");
|
||||
check(new StringBuilder(ORIGIN).delete(0, 1), "");
|
||||
check(new StringBuilder(ORIGIN).delete(0, 0), "\uFF21");
|
||||
check(new StringBuilder(ORIGIN).deleteCharAt(0), "");
|
||||
assertEquals(new StringBuilder(ORIGIN).indexOf("A", 0), -1);
|
||||
assertEquals(new StringBuilder(ORIGIN).indexOf("\uFF21", 0), 0);
|
||||
assertEquals(new StringBuilder(ORIGIN).indexOf("", 0), 0);
|
||||
check(new StringBuilder(ORIGIN).insert(0, new char[] {}), "\uFF21");
|
||||
check(new StringBuilder(ORIGIN).insert(1, new char[] { 'A' }), "\uFF21A");
|
||||
check(new StringBuilder(ORIGIN).insert(0, new char[] { 'A' }), "A\uFF21");
|
||||
check(new StringBuilder(ORIGIN).insert(0, new StringBuffer("A")),
|
||||
"A\uFF21");
|
||||
check(new StringBuilder(ORIGIN).insert(1, new StringBuffer("A")),
|
||||
"\uFF21A");
|
||||
check(new StringBuilder(ORIGIN).insert(0, ""), "\uFF21");
|
||||
check(new StringBuilder(ORIGIN).insert(0, "A"), "A\uFF21");
|
||||
check(new StringBuilder(ORIGIN).insert(1, "A"), "\uFF21A");
|
||||
assertEquals(new StringBuilder(ORIGIN).lastIndexOf("A"), -1);
|
||||
assertEquals(new StringBuilder(ORIGIN).lastIndexOf("\uFF21"), 0);
|
||||
assertEquals(new StringBuilder(ORIGIN).lastIndexOf(""), 1);
|
||||
check(new StringBuilder(ORIGIN).replace(0, 0, "A"), "A\uFF21");
|
||||
check(new StringBuilder(ORIGIN).replace(0, 1, "A"), "A");
|
||||
checkSetCharAt(new StringBuilder(ORIGIN), 0, 'A', "A");
|
||||
checkSetLength(new StringBuilder(ORIGIN), 0, "");
|
||||
checkSetLength(new StringBuilder(ORIGIN), 1, "\uFF21");
|
||||
check(new StringBuilder(ORIGIN).substring(0), "\uFF21");
|
||||
check(new StringBuilder(ORIGIN).substring(1), "");
|
||||
}
|
||||
|
||||
/*
|
||||
* Tests for "\uFF21A"
|
||||
*/
|
||||
@Test
|
||||
public void testCompactStringBuilderForMixedA1() {
|
||||
final String ORIGIN = "\uFF21A";
|
||||
check(new StringBuilder(ORIGIN).delete(0, 1), "A");
|
||||
check(new StringBuilder(ORIGIN).delete(1, 2), "\uFF21");
|
||||
check(new StringBuilder(ORIGIN).deleteCharAt(1), "\uFF21");
|
||||
check(new StringBuilder(ORIGIN).deleteCharAt(0), "A");
|
||||
assertEquals(new StringBuilder(ORIGIN).indexOf("A", 0), 1);
|
||||
assertEquals(new StringBuilder(ORIGIN).indexOf("\uFF21", 0), 0);
|
||||
assertEquals(new StringBuilder(ORIGIN).indexOf("", 0), 0);
|
||||
check(new StringBuilder(ORIGIN).insert(1, new char[] { 'A' }),
|
||||
"\uFF21AA");
|
||||
check(new StringBuilder(ORIGIN).insert(0, new char[] { '\uFF21' }),
|
||||
"\uFF21\uFF21A");
|
||||
assertEquals(new StringBuilder(ORIGIN).lastIndexOf("A"), 1);
|
||||
assertEquals(new StringBuilder(ORIGIN).lastIndexOf("\uFF21"), 0);
|
||||
assertEquals(new StringBuilder(ORIGIN).lastIndexOf(""), 2);
|
||||
check(new StringBuilder(ORIGIN).replace(0, 0, "A"), "A\uFF21A");
|
||||
check(new StringBuilder(ORIGIN).replace(0, 1, "A"), "AA");
|
||||
checkSetCharAt(new StringBuilder(ORIGIN), 0, 'A', "AA");
|
||||
checkSetLength(new StringBuilder(ORIGIN), 0, "");
|
||||
checkSetLength(new StringBuilder(ORIGIN), 1, "\uFF21");
|
||||
check(new StringBuilder(ORIGIN).substring(0), "\uFF21A");
|
||||
check(new StringBuilder(ORIGIN).substring(1), "A");
|
||||
}
|
||||
|
||||
/*
|
||||
* Tests for "A\uFF21"
|
||||
*/
|
||||
@Test
|
||||
public void testCompactStringBuilderForMixedA2() {
|
||||
final String ORIGIN = "A\uFF21";
|
||||
check(new StringBuilder(ORIGIN).replace(1, 2, "A"), "AA");
|
||||
checkSetLength(new StringBuilder(ORIGIN), 1, "A");
|
||||
check(new StringBuilder(ORIGIN).substring(0), "A\uFF21");
|
||||
check(new StringBuilder(ORIGIN).substring(1), "\uFF21");
|
||||
check(new StringBuilder(ORIGIN).substring(0, 1), "A");
|
||||
}
|
||||
|
||||
/*
|
||||
* Tests for "\uFF21A\uFF21A\uFF21A\uFF21A\uFF21A"
|
||||
*/
|
||||
@Test
|
||||
public void testCompactStringBuilderForDuplicatedMixedA1() {
|
||||
final String ORIGIN = "\uFF21A\uFF21A\uFF21A\uFF21A\uFF21A";
|
||||
checkSetLength(new StringBuilder(ORIGIN), 1, "\uFF21");
|
||||
assertEquals(new StringBuilder(ORIGIN).indexOf("A", 5), 5);
|
||||
assertEquals(new StringBuilder(ORIGIN).indexOf("\uFF21", 5), 6);
|
||||
assertEquals(new StringBuilder(ORIGIN).lastIndexOf("A"), 9);
|
||||
assertEquals(new StringBuilder(ORIGIN).lastIndexOf("\uFF21"), 8);
|
||||
assertEquals(new StringBuilder(ORIGIN).lastIndexOf(""), 10);
|
||||
check(new StringBuilder(ORIGIN).substring(9), "A");
|
||||
check(new StringBuilder(ORIGIN).substring(8), "\uFF21A");
|
||||
}
|
||||
|
||||
/*
|
||||
* Tests for "A\uFF21A\uFF21A\uFF21A\uFF21A\uFF21"
|
||||
*/
|
||||
@Test
|
||||
public void testCompactStringBuilderForDuplicatedMixedA2() {
|
||||
final String ORIGIN = "A\uFF21A\uFF21A\uFF21A\uFF21A\uFF21";
|
||||
checkSetLength(new StringBuilder(ORIGIN), 1, "A");
|
||||
assertEquals(new StringBuilder(ORIGIN).indexOf("A", 5), 6);
|
||||
assertEquals(new StringBuilder(ORIGIN).indexOf("\uFF21", 5), 5);
|
||||
assertEquals(new StringBuilder(ORIGIN).lastIndexOf("A"), 8);
|
||||
assertEquals(new StringBuilder(ORIGIN).lastIndexOf("\uFF21"), 9);
|
||||
check(new StringBuilder(ORIGIN).substring(9), "\uFF21");
|
||||
check(new StringBuilder(ORIGIN).substring(8), "A\uFF21");
|
||||
}
|
||||
|
||||
/*
|
||||
* Tests for "\uD801\uDC00\uD801\uDC01"
|
||||
*/
|
||||
@Test
|
||||
public void testCompactStringForSupplementaryCodePoint() {
|
||||
final String ORIGIN = "\uD801\uDC00\uD801\uDC01";
|
||||
check(new StringBuilder(ORIGIN).append("A"), "\uD801\uDC00\uD801\uDC01A");
|
||||
check(new StringBuilder(ORIGIN).append("\uFF21"),
|
||||
"\uD801\uDC00\uD801\uDC01\uFF21");
|
||||
check(new StringBuilder(ORIGIN).appendCodePoint('A'),
|
||||
"\uD801\uDC00\uD801\uDC01A");
|
||||
check(new StringBuilder(ORIGIN).appendCodePoint('\uFF21'),
|
||||
"\uD801\uDC00\uD801\uDC01\uFF21");
|
||||
assertEquals(new StringBuilder(ORIGIN).charAt(0), '\uD801');
|
||||
assertEquals(new StringBuilder(ORIGIN).codePointAt(0),
|
||||
Character.codePointAt(ORIGIN, 0));
|
||||
assertEquals(new StringBuilder(ORIGIN).codePointAt(1),
|
||||
Character.codePointAt(ORIGIN, 1));
|
||||
assertEquals(new StringBuilder(ORIGIN).codePointBefore(2),
|
||||
Character.codePointAt(ORIGIN, 0));
|
||||
assertEquals(new StringBuilder(ORIGIN).codePointCount(1, 3), 2);
|
||||
check(new StringBuilder(ORIGIN).delete(0, 2), "\uD801\uDC01");
|
||||
check(new StringBuilder(ORIGIN).delete(0, 3), "\uDC01");
|
||||
check(new StringBuilder(ORIGIN).deleteCharAt(1), "\uD801\uD801\uDC01");
|
||||
checkGetChars(new StringBuilder(ORIGIN), 0, 3, new char[] { '\uD801',
|
||||
'\uDC00', '\uD801' });
|
||||
assertEquals(new StringBuilder(ORIGIN).indexOf("\uD801\uDC01"), 2);
|
||||
assertEquals(new StringBuilder(ORIGIN).indexOf("\uDC01"), 3);
|
||||
assertEquals(new StringBuilder(ORIGIN).indexOf("\uFF21"), -1);
|
||||
assertEquals(new StringBuilder(ORIGIN).indexOf("A"), -1);
|
||||
check(new StringBuilder(ORIGIN).insert(0, "\uFF21"),
|
||||
"\uFF21\uD801\uDC00\uD801\uDC01");
|
||||
check(new StringBuilder(ORIGIN).insert(1, "\uFF21"),
|
||||
"\uD801\uFF21\uDC00\uD801\uDC01");
|
||||
check(new StringBuilder(ORIGIN).insert(1, "A"),
|
||||
"\uD801A\uDC00\uD801\uDC01");
|
||||
assertEquals(new StringBuilder(ORIGIN).lastIndexOf("\uDC00\uD801"), 1);
|
||||
assertEquals(new StringBuilder(ORIGIN).lastIndexOf("\uD801"), 2);
|
||||
assertEquals(new StringBuilder(ORIGIN).lastIndexOf("\uFF21"), -1);
|
||||
assertEquals(new StringBuilder(ORIGIN).lastIndexOf("A"), -1);
|
||||
assertEquals(new StringBuilder(ORIGIN).length(), 4);
|
||||
assertEquals(new StringBuilder(ORIGIN).offsetByCodePoints(1, 1), 2);
|
||||
assertEquals(new StringBuilder(ORIGIN).offsetByCodePoints(0, 1), 2);
|
||||
check(new StringBuilder(ORIGIN).replace(0, 2, "A"), "A\uD801\uDC01");
|
||||
check(new StringBuilder(ORIGIN).replace(0, 3, "A"), "A\uDC01");
|
||||
check(new StringBuilder(ORIGIN).replace(0, 2, "\uFF21"),
|
||||
"\uFF21\uD801\uDC01");
|
||||
check(new StringBuilder(ORIGIN).replace(0, 3, "\uFF21"), "\uFF21\uDC01");
|
||||
check(new StringBuilder(ORIGIN).reverse(), "\uD801\uDC01\uD801\uDC00");
|
||||
checkSetCharAt(new StringBuilder(ORIGIN), 1, '\uDC01',
|
||||
"\uD801\uDC01\uD801\uDC01");
|
||||
checkSetCharAt(new StringBuilder(ORIGIN), 1, 'A', "\uD801A\uD801\uDC01");
|
||||
checkSetLength(new StringBuilder(ORIGIN), 2, "\uD801\uDC00");
|
||||
checkSetLength(new StringBuilder(ORIGIN), 3, "\uD801\uDC00\uD801");
|
||||
check(new StringBuilder(ORIGIN).substring(1, 3), "\uDC00\uD801");
|
||||
}
|
||||
|
||||
/*
|
||||
* Tests for "A\uD801\uDC00\uFF21"
|
||||
*/
|
||||
@Test
|
||||
public void testCompactStringForSupplementaryCodePointMixed1() {
|
||||
final String ORIGIN = "A\uD801\uDC00\uFF21";
|
||||
assertEquals(new StringBuilder(ORIGIN).codePointBefore(3),
|
||||
Character.codePointAt(ORIGIN, 1));
|
||||
assertEquals(new StringBuilder(ORIGIN).codePointBefore(2), '\uD801');
|
||||
assertEquals(new StringBuilder(ORIGIN).codePointBefore(1), 'A');
|
||||
assertEquals(new StringBuilder(ORIGIN).codePointCount(0, 3), 2);
|
||||
assertEquals(new StringBuilder(ORIGIN).codePointCount(0, 4), 3);
|
||||
check(new StringBuilder(ORIGIN).delete(0, 1), "\uD801\uDC00\uFF21");
|
||||
check(new StringBuilder(ORIGIN).delete(0, 1).delete(2, 3),
|
||||
"\uD801\uDC00");
|
||||
check(new StringBuilder(ORIGIN).deleteCharAt(3).deleteCharAt(0),
|
||||
"\uD801\uDC00");
|
||||
assertEquals(new StringBuilder(ORIGIN).indexOf("\uFF21"), 3);
|
||||
assertEquals(new StringBuilder(ORIGIN).indexOf("A"), 0);
|
||||
assertEquals(new StringBuilder(ORIGIN).lastIndexOf("\uFF21"), 3);
|
||||
assertEquals(new StringBuilder(ORIGIN).lastIndexOf("A"), 0);
|
||||
assertEquals(new StringBuilder(ORIGIN).offsetByCodePoints(0, 1), 1);
|
||||
assertEquals(new StringBuilder(ORIGIN).offsetByCodePoints(1, 1), 3);
|
||||
check(new StringBuilder(ORIGIN).replace(1, 3, "A"), "AA\uFF21");
|
||||
check(new StringBuilder(ORIGIN).replace(1, 4, "A"), "AA");
|
||||
check(new StringBuilder(ORIGIN).replace(1, 4, ""), "A");
|
||||
check(new StringBuilder(ORIGIN).reverse(), "\uFF21\uD801\uDC00A");
|
||||
checkSetLength(new StringBuilder(ORIGIN), 1, "A");
|
||||
check(new StringBuilder(ORIGIN).substring(0, 1), "A");
|
||||
}
|
||||
|
||||
/*
|
||||
* Tests for "\uD801\uDC00\uFF21A"
|
||||
*/
|
||||
@Test
|
||||
public void testCompactStringForSupplementaryCodePointMixed2() {
|
||||
final String ORIGIN = "\uD801\uDC00\uFF21A";
|
||||
assertEquals(new StringBuilder(ORIGIN).codePointBefore(3),
|
||||
Character.codePointAt(ORIGIN, 2));
|
||||
assertEquals(new StringBuilder(ORIGIN).codePointBefore(2),
|
||||
Character.codePointAt(ORIGIN, 0));
|
||||
assertEquals(new StringBuilder(ORIGIN).codePointBefore(1), '\uD801');
|
||||
assertEquals(new StringBuilder(ORIGIN).codePointCount(0, 3), 2);
|
||||
assertEquals(new StringBuilder(ORIGIN).codePointCount(0, 4), 3);
|
||||
check(new StringBuilder(ORIGIN).delete(0, 2), "\uFF21A");
|
||||
check(new StringBuilder(ORIGIN).delete(0, 3), "A");
|
||||
check(new StringBuilder(ORIGIN).deleteCharAt(0).deleteCharAt(0)
|
||||
.deleteCharAt(0), "A");
|
||||
assertEquals(new StringBuilder(ORIGIN).indexOf("A"), 3);
|
||||
assertEquals(new StringBuilder(ORIGIN).delete(0, 3).indexOf("A"), 0);
|
||||
assertEquals(new StringBuilder(ORIGIN).replace(0, 3, "B").indexOf("A"),
|
||||
1);
|
||||
assertEquals(new StringBuilder(ORIGIN).substring(3, 4).indexOf("A"), 0);
|
||||
assertEquals(new StringBuilder(ORIGIN).offsetByCodePoints(1, 1), 2);
|
||||
assertEquals(new StringBuilder(ORIGIN).offsetByCodePoints(0, 1), 2);
|
||||
assertEquals(new StringBuilder(ORIGIN).offsetByCodePoints(2, 1), 3);
|
||||
check(new StringBuilder(ORIGIN).replace(0, 3, "B"), "BA");
|
||||
check(new StringBuilder(ORIGIN).reverse(), "A\uFF21\uD801\uDC00");
|
||||
}
|
||||
|
||||
/*
|
||||
* Tests for "\uD801A\uDC00\uFF21"
|
||||
*/
|
||||
@Test
|
||||
public void testCompactStringForSupplementaryCodePointMixed3() {
|
||||
final String ORIGIN = "\uD801A\uDC00\uFF21";
|
||||
assertEquals(new StringBuilder(ORIGIN).codePointAt(1), 'A');
|
||||
assertEquals(new StringBuilder(ORIGIN).codePointAt(3), '\uFF21');
|
||||
assertEquals(new StringBuilder(ORIGIN).codePointBefore(1), '\uD801');
|
||||
assertEquals(new StringBuilder(ORIGIN).codePointBefore(2), 'A');
|
||||
assertEquals(new StringBuilder(ORIGIN).codePointBefore(3), '\uDC00');
|
||||
assertEquals(new StringBuilder(ORIGIN).codePointCount(0, 3), 3);
|
||||
assertEquals(new StringBuilder(ORIGIN).codePointCount(1, 3), 2);
|
||||
assertEquals(new StringBuilder(ORIGIN).delete(0, 1).delete(1, 3)
|
||||
.indexOf("A"), 0);
|
||||
assertEquals(
|
||||
new StringBuilder(ORIGIN).replace(0, 1, "B").replace(2, 4, "C")
|
||||
.indexOf("A"), 1);
|
||||
assertEquals(new StringBuilder(ORIGIN).substring(1, 4).substring(0, 1)
|
||||
.indexOf("A"), 0);
|
||||
assertEquals(new StringBuilder(ORIGIN).offsetByCodePoints(0, 1), 1);
|
||||
assertEquals(new StringBuilder(ORIGIN).offsetByCodePoints(1, 1), 2);
|
||||
assertEquals(new StringBuilder(ORIGIN).offsetByCodePoints(2, 1), 3);
|
||||
check(new StringBuilder(ORIGIN).reverse(), "\uFF21\uDC00A\uD801");
|
||||
}
|
||||
|
||||
/*
|
||||
* Tests for "A\uDC01\uFF21\uD801"
|
||||
*/
|
||||
@Test
|
||||
public void testCompactStringForSupplementaryCodePointMixed4() {
|
||||
final String ORIGIN = "A\uDC01\uFF21\uD801";
|
||||
assertEquals(new StringBuilder(ORIGIN).codePointAt(1), '\uDC01');
|
||||
assertEquals(new StringBuilder(ORIGIN).codePointAt(3), '\uD801');
|
||||
assertEquals(new StringBuilder(ORIGIN).codePointBefore(1), 'A');
|
||||
assertEquals(new StringBuilder(ORIGIN).codePointBefore(2), '\uDC01');
|
||||
assertEquals(new StringBuilder(ORIGIN).codePointBefore(3), '\uFF21');
|
||||
assertEquals(new StringBuilder(ORIGIN).codePointCount(0, 3), 3);
|
||||
assertEquals(new StringBuilder(ORIGIN).codePointCount(1, 3), 2);
|
||||
assertEquals(new StringBuilder(ORIGIN).delete(1, 4).indexOf("A"), 0);
|
||||
assertEquals(new StringBuilder(ORIGIN).replace(1, 4, "B").indexOf("A"),
|
||||
0);
|
||||
assertEquals(new StringBuilder(ORIGIN).substring(0, 1).indexOf("A"), 0);
|
||||
assertEquals(new StringBuilder(ORIGIN).offsetByCodePoints(0, 1), 1);
|
||||
assertEquals(new StringBuilder(ORIGIN).offsetByCodePoints(1, 1), 2);
|
||||
assertEquals(new StringBuilder(ORIGIN).offsetByCodePoints(2, 1), 3);
|
||||
check(new StringBuilder(ORIGIN).reverse(), "\uD801\uFF21\uDC01A");
|
||||
}
|
||||
|
||||
/*
|
||||
* Tests for maybeLatin1 attribute
|
||||
*/
|
||||
@Test
|
||||
public void testCompactStringForMaybeLatin1() {
|
||||
StringBuilder sb = new StringBuilder("A\uDC01");
|
||||
|
||||
sb.setLength(0); // maybeLatin1 become true
|
||||
check(sb, "");
|
||||
check(new StringBuilder(sb).append('A'), "A");
|
||||
check(new StringBuilder().append(sb), "");
|
||||
|
||||
sb = new StringBuilder("A\uDC01");
|
||||
sb.setCharAt(1, 'B'); // maybeLatin1 become true
|
||||
check(sb, "AB");
|
||||
check(new StringBuilder(sb).append('A'), "ABA");
|
||||
check(new StringBuilder().append(sb), "AB");
|
||||
|
||||
sb = new StringBuilder("A\uDC01");
|
||||
sb.deleteCharAt(1); // maybeLatin1 become true
|
||||
check(sb, "A");
|
||||
check(new StringBuilder(sb).append('B'), "AB");
|
||||
check(new StringBuilder().append(sb), "A");
|
||||
|
||||
sb = new StringBuilder("A\uDC01\uFF21\uD801");
|
||||
sb.delete(1, 4);
|
||||
check(sb, "A"); // maybeLatin1 become true
|
||||
check(new StringBuilder(sb).append('B'), "AB");
|
||||
check(new StringBuilder().append(sb), "A");
|
||||
|
||||
sb = new StringBuilder("A\uDC01\uFF21\uD801");
|
||||
sb.replace(1, 4, "B");
|
||||
check(sb, "AB"); // maybeLatin1 become true
|
||||
check(new StringBuilder(sb).append('A'), "ABA");
|
||||
check(new StringBuilder().append(sb), "AB");
|
||||
}
|
||||
|
||||
// Test cases to force expanding the capacity during replace.
|
||||
// Start with a known capacity and a known initial value that almost fills it.
|
||||
// Use both latin1 and utf16 initial values and replacement values.
|
||||
// Iterate through cases of SB.replace start and end values and various lengths of replacement.
|
||||
// The results are checked by composing the new string using concatenation of the segments.
|
||||
@Test
|
||||
public void testGrowingCapacityReplace() {
|
||||
final int INIT_CAPACITY = 8;
|
||||
final String[] INITIAL_CHARS = {"A", "\u0100"};
|
||||
final String[] REPLACEMENT_CHARS = {"B", "\u0101"};
|
||||
for (String INITIAL : INITIAL_CHARS) {
|
||||
for (String REPLACEMENT : REPLACEMENT_CHARS) {
|
||||
for (int initLen = INIT_CAPACITY - 1; initLen < INIT_CAPACITY + 2; initLen++) {
|
||||
final String orig = INITIAL.repeat(initLen);
|
||||
for (int start = INIT_CAPACITY - 4; start < orig.length(); start++) {
|
||||
for (int end = start; end < orig.length(); end++) {
|
||||
for (int insLen = 0; insLen < 2; insLen++) {
|
||||
final String repl = REPLACEMENT.repeat(insLen);
|
||||
var sb = new StringBuilder(INIT_CAPACITY)
|
||||
.append(orig);
|
||||
int capBefore = sb.capacity();
|
||||
sb.replace(start, end, repl);
|
||||
int capAfter = sb.capacity();
|
||||
String expected = genReplacementString(orig, start, end, repl);
|
||||
try {
|
||||
check(sb, expected);
|
||||
} catch (Throwable ex) {
|
||||
System.out.printf("repl: \"%s\", actual: %s, expected: %s%n", repl, sb, expected);
|
||||
System.out.printf(" insLen: %d, gap: %d, beforeLen: %d, afterLen: %d, capBefore: %d, capAfter: %d%n",
|
||||
insLen, (end - start), orig.length(), sb.length(),
|
||||
capBefore, capAfter);
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Construct the replacement string using string concat of the segments
|
||||
private static String genReplacementString(String orig, int start, int end, String repl) {
|
||||
return orig.substring(0, start) +
|
||||
repl +
|
||||
orig.substring(end, orig.length());
|
||||
}
|
||||
|
||||
private void checkGetChars(StringBuilder sb, int srcBegin, int srcEnd,
|
||||
char expected[]) {
|
||||
char[] dst = new char[srcEnd - srcBegin];
|
||||
sb.getChars(srcBegin, srcEnd, dst, 0);
|
||||
assertTrue(Arrays.equals(dst, expected));
|
||||
}
|
||||
|
||||
private void checkSetCharAt(StringBuilder sb, int index, char ch,
|
||||
String expected) {
|
||||
sb.setCharAt(index, ch);
|
||||
check(sb, expected);
|
||||
}
|
||||
|
||||
private void checkSetLength(StringBuilder sb, int newLength, String expected) {
|
||||
sb.setLength(newLength);
|
||||
check(sb, expected);
|
||||
}
|
||||
|
||||
private void check(StringBuilder sb, String expected) {
|
||||
check(sb.toString(), expected);
|
||||
}
|
||||
|
||||
private void check(String str, String expected) {
|
||||
assertTrue(str.equals(expected), String.format(
|
||||
"Get (%s) but expect (%s), ", escapeNonASCIIs(str),
|
||||
escapeNonASCIIs(expected)));
|
||||
}
|
||||
|
||||
/*
|
||||
* Escape non-ASCII characters since not all systems support them.
|
||||
*/
|
||||
private String escapeNonASCIIs(String str) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < str.length(); i++) {
|
||||
char c = str.charAt(i);
|
||||
if (c > 0x7F) {
|
||||
sb.append("\\u").append(Integer.toHexString((int) c));
|
||||
} else {
|
||||
sb.append(c);
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,141 @@
|
|||
/*
|
||||
* Copyright (c) 2015, 2017, 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.
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
|
||||
import org.testng.annotations.DataProvider;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import static jdk.test.lib.util.SerializationUtils.*;
|
||||
import static org.testng.Assert.*;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8077559
|
||||
* @library /test/lib
|
||||
* @build jdk.test.lib.util.SerializationUtils
|
||||
* @summary Tests Compact String. This one is testing StringBuilder serialization
|
||||
* among -XX:+CompactStrings/-XX:-CompactStrings/LegacyStringBuilder
|
||||
* @run testng/othervm -XX:+CompactStrings CompactStringBuilderSerialization
|
||||
* @run testng/othervm -XX:-CompactStrings CompactStringBuilderSerialization
|
||||
*/
|
||||
|
||||
public class CompactStringBuilderSerialization {
|
||||
@DataProvider
|
||||
public Object[][] provider() {
|
||||
return new Object[][] {
|
||||
// every byte array is serialized from corresponding StringBuffer object
|
||||
// by previous JDK(build 1.8.0_45-b14).
|
||||
new Object[] {
|
||||
new StringBuilder(""),
|
||||
new byte[] { -84, -19, 0, 5, 115, 114, 0, 23, 106, 97, 118, 97, 46, 108, 97, 110, 103, 46, 83, 116, 114, 105, 110, 103, 66, 117, 105,
|
||||
108, 100, 101, 114, 60, -43, -5, 20, 90, 76, 106, -53, 3, 0, 0, 120, 112, 119, 4, 0, 0, 0, 0, 117, 114, 0, 2, 91, 67, -80, 38,
|
||||
102, -80, -30, 93, -124, -84, 2, 0, 0, 120, 112, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 120 } },
|
||||
new Object[] {
|
||||
new StringBuilder("A"),
|
||||
new byte[] { -84, -19, 0, 5, 115, 114, 0, 23, 106, 97, 118, 97, 46, 108, 97, 110, 103, 46, 83, 116, 114, 105, 110, 103, 66, 117, 105,
|
||||
108, 100, 101, 114, 60, -43, -5, 20, 90, 76, 106, -53, 3, 0, 0, 120, 112, 119, 4, 0, 0, 0, 1, 117, 114, 0, 2, 91, 67, -80, 38,
|
||||
102, -80, -30, 93, -124, -84, 2, 0, 0, 120, 112, 0, 0, 0, 17, 0, 65, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 120 } },
|
||||
new Object[] {
|
||||
new StringBuilder("AB"),
|
||||
new byte[] { -84, -19, 0, 5, 115, 114, 0, 23, 106, 97, 118, 97, 46, 108, 97, 110, 103, 46, 83, 116, 114, 105, 110, 103, 66, 117, 105,
|
||||
108, 100, 101, 114, 60, -43, -5, 20, 90, 76, 106, -53, 3, 0, 0, 120, 112, 119, 4, 0, 0, 0, 2, 117, 114, 0, 2, 91, 67, -80, 38,
|
||||
102, -80, -30, 93, -124, -84, 2, 0, 0, 120, 112, 0, 0, 0, 18, 0, 65, 0, 66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 120 } },
|
||||
new Object[] {
|
||||
new StringBuilder("abcdefghijk"),
|
||||
new byte[] { -84, -19, 0, 5, 115, 114, 0, 23, 106, 97, 118, 97, 46, 108, 97, 110, 103, 46, 83, 116, 114, 105, 110, 103, 66, 117, 105,
|
||||
108, 100, 101, 114, 60, -43, -5, 20, 90, 76, 106, -53, 3, 0, 0, 120, 112, 119, 4, 0, 0, 0, 11, 117, 114, 0, 2, 91, 67, -80, 38,
|
||||
102, -80, -30, 93, -124, -84, 2, 0, 0, 120, 112, 0, 0, 0, 27, 0, 97, 0, 98, 0, 99, 0, 100, 0, 101, 0, 102, 0, 103, 0, 104, 0,
|
||||
105, 0, 106, 0, 107, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 120 } },
|
||||
new Object[] {
|
||||
new StringBuilder("\uff21"),
|
||||
new byte[] { -84, -19, 0, 5, 115, 114, 0, 23, 106, 97, 118, 97, 46, 108, 97, 110, 103, 46, 83, 116, 114, 105, 110, 103, 66, 117, 105,
|
||||
108, 100, 101, 114, 60, -43, -5, 20, 90, 76, 106, -53, 3, 0, 0, 120, 112, 119, 4, 0, 0, 0, 1, 117, 114, 0, 2, 91, 67, -80, 38,
|
||||
102, -80, -30, 93, -124, -84, 2, 0, 0, 120, 112, 0, 0, 0, 17, -1, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 120 } },
|
||||
new Object[] {
|
||||
new StringBuilder("\uff21\uff22"),
|
||||
new byte[] { -84, -19, 0, 5, 115, 114, 0, 23, 106, 97, 118, 97, 46, 108, 97, 110, 103, 46, 83, 116, 114, 105, 110, 103, 66, 117, 105,
|
||||
108, 100, 101, 114, 60, -43, -5, 20, 90, 76, 106, -53, 3, 0, 0, 120, 112, 119, 4, 0, 0, 0, 2, 117, 114, 0, 2, 91, 67, -80, 38,
|
||||
102, -80, -30, 93, -124, -84, 2, 0, 0, 120, 112, 0, 0, 0, 18, -1, 33, -1, 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 120 } },
|
||||
new Object[] {
|
||||
new StringBuilder("\uff21A\uff21A\uff21A\uff21A\uff21A"),
|
||||
new byte[] { -84, -19, 0, 5, 115, 114, 0, 23, 106, 97, 118, 97, 46, 108, 97, 110, 103, 46, 83, 116, 114, 105, 110, 103, 66, 117, 105,
|
||||
108, 100, 101, 114, 60, -43, -5, 20, 90, 76, 106, -53, 3, 0, 0, 120, 112, 119, 4, 0, 0, 0, 10, 117, 114, 0, 2, 91, 67, -80, 38,
|
||||
102, -80, -30, 93, -124, -84, 2, 0, 0, 120, 112, 0, 0, 0, 26, -1, 33, 0, 65, -1, 33, 0, 65, -1, 33, 0, 65, -1, 33, 0, 65, -1,
|
||||
33, 0, 65, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 120 } },
|
||||
new Object[] {
|
||||
new StringBuilder("A\uff21B\uff22C\uff23D\uff24E\uff25F\uff26G\uff27H\uff28"),
|
||||
new byte[] { -84, -19, 0, 5, 115, 114, 0, 23, 106, 97, 118, 97, 46, 108, 97, 110, 103, 46, 83, 116, 114, 105, 110, 103, 66, 117, 105,
|
||||
108, 100, 101, 114, 60, -43, -5, 20, 90, 76, 106, -53, 3, 0, 0, 120, 112, 119, 4, 0, 0, 0, 16, 117, 114, 0, 2, 91, 67, -80, 38,
|
||||
102, -80, -30, 93, -124, -84, 2, 0, 0, 120, 112, 0, 0, 0, 32, 0, 65, -1, 33, 0, 66, -1, 34, 0, 67, -1, 35, 0, 68, -1, 36, 0,
|
||||
69, -1, 37, 0, 70, -1, 38, 0, 71, -1, 39, 0, 72, -1, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 120 } },
|
||||
new Object[] {
|
||||
new StringBuilder("\uff21A\uff22B\uff23C\uff24D\uff25E\uff26F\uff27G\uff28H"),
|
||||
new byte[] { -84, -19, 0, 5, 115, 114, 0, 23, 106, 97, 118, 97, 46, 108, 97, 110, 103, 46, 83, 116, 114, 105, 110, 103, 66, 117, 105,
|
||||
108, 100, 101, 114, 60, -43, -5, 20, 90, 76, 106, -53, 3, 0, 0, 120, 112, 119, 4, 0, 0, 0, 16, 117, 114, 0, 2, 91, 67, -80, 38,
|
||||
102, -80, -30, 93, -124, -84, 2, 0, 0, 120, 112, 0, 0, 0, 32, -1, 33, 0, 65, -1, 34, 0, 66, -1, 35, 0, 67, -1, 36, 0, 68, -1,
|
||||
37, 0, 69, -1, 38, 0, 70, -1, 39, 0, 71, -1, 40, 0, 72, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 120 } },
|
||||
new Object[] {
|
||||
new StringBuilder("\ud801\udc00\ud801\udc01\uff21A"),
|
||||
new byte[] { -84, -19, 0, 5, 115, 114, 0, 23, 106, 97, 118, 97, 46, 108, 97, 110, 103, 46, 83, 116, 114, 105, 110, 103, 66, 117, 105,
|
||||
108, 100, 101, 114, 60, -43, -5, 20, 90, 76, 106, -53, 3, 0, 0, 120, 112, 119, 4, 0, 0, 0, 6, 117, 114, 0, 2, 91, 67, -80, 38,
|
||||
102, -80, -30, 93, -124, -84, 2, 0, 0, 120, 112, 0, 0, 0, 22, -40, 1, -36, 0, -40, 1, -36, 1, -1, 33, 0, 65, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 120 } },
|
||||
new Object[] {
|
||||
new StringBuilder("\uff21\uff22\uff21\uff22\uff21\uff22\uff21\uff22\uff21\uff22"),
|
||||
new byte[] { -84, -19, 0, 5, 115, 114, 0, 23, 106, 97, 118, 97, 46, 108, 97, 110, 103, 46, 83, 116, 114, 105, 110, 103, 66, 117, 105,
|
||||
108, 100, 101, 114, 60, -43, -5, 20, 90, 76, 106, -53, 3, 0, 0, 120, 112, 119, 4, 0, 0, 0, 10, 117, 114, 0, 2, 91, 67, -80, 38,
|
||||
102, -80, -30, 93, -124, -84, 2, 0, 0, 120, 112, 0, 0, 0, 26, -1, 33, -1, 34, -1, 33, -1, 34, -1, 33, -1, 34, -1, 33, -1, 34,
|
||||
-1, 33, -1, 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 120 } } };
|
||||
}
|
||||
|
||||
/*
|
||||
* Verify serialization works between Compact StringBuilder/Legacy StringBuilder
|
||||
*/
|
||||
@Test(dataProvider = "provider")
|
||||
public void test(StringBuilder sbContent, byte[] baInJDK8) throws Exception {
|
||||
// Serialize a StringBuilder object into byte array.
|
||||
byte[] ba = serialize(sbContent);
|
||||
assertEquals(ba, baInJDK8);
|
||||
// Deserialize a StringBuilder object from byte array which is generated by previous JDK(build 1.8.0_45-b14).
|
||||
Object obj = deserialize(ba);
|
||||
assertEquals(obj.getClass(), StringBuilder.class);
|
||||
assertTrue(equals((StringBuilder)obj, sbContent));
|
||||
}
|
||||
|
||||
boolean equals(StringBuilder sb, StringBuilder expected) {
|
||||
if(sb.length() == expected.length()
|
||||
&& sb.capacity() == expected.capacity()
|
||||
&& sb.toString().equals(expected.toString())) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
136
test/jdk/java/lang/StringBuilder/Comparison.java
Normal file
136
test/jdk/java/lang/StringBuilder/Comparison.java
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
/*
|
||||
* Copyright (c) 2018, 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.
|
||||
*/
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
import org.testng.Assert;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @bug 8137326
|
||||
* @summary Test to verify the Comparable implementation for the StringBuilder class.
|
||||
* @run testng Comparison
|
||||
*/
|
||||
public class Comparison {
|
||||
static char SEP = ':';
|
||||
|
||||
static String[][] books = {
|
||||
{"Biography", "Steve Jobs"},
|
||||
{"Biography", "Elon Musk: Tesla, SpaceX, and the Quest for a Fantastic Future"},
|
||||
{"Law", "Law 101: Everything You Need to Know About American Law, Fourth Edition"},
|
||||
{"Law", "The Tools of Argument: How the Best Lawyers Think, Argue, and Win"},
|
||||
{"History", "The History Book (Big Ideas Simply Explained)"},
|
||||
{"History", "A People's History of the United States"},
|
||||
};
|
||||
|
||||
/**
|
||||
* Verifies the Comparable implementation by comparing with two TreeSet that
|
||||
* contain either StringBuilder or String.
|
||||
*/
|
||||
@Test
|
||||
public void compareWithString() {
|
||||
Set<StringBuilder> sbSet = constructSBSet();
|
||||
Set<String> sSet = constructStringSet();
|
||||
Iterator<StringBuilder> iSB = sbSet.iterator();
|
||||
Iterator<String> iS = sSet.iterator();
|
||||
while (iSB.hasNext()) {
|
||||
String temp1 = iSB.next().toString();
|
||||
System.out.println(temp1);
|
||||
String temp2 = iS.next();
|
||||
System.out.println(temp2);
|
||||
|
||||
Assert.assertTrue(temp1.equals(temp2), "Comparing item by item");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares between StringBuilders
|
||||
*/
|
||||
@Test
|
||||
public void testCompare() {
|
||||
StringBuilder sb1 = generateTestBuffer(65, 70, 97, 102);
|
||||
StringBuilder sb2 = generateTestBuffer(65, 70, 97, 102);
|
||||
StringBuilder sb3 = generateTestBuffer(65, 71, 97, 103);
|
||||
|
||||
System.out.println(sb1.toString());
|
||||
System.out.println(sb2.toString());
|
||||
System.out.println(sb3.toString());
|
||||
Assert.assertTrue(sb1.compareTo(sb2) == 0, "Compare sb1 and sb2");
|
||||
Assert.assertFalse(sb1.compareTo(sb3) == 0, "Compare sb1 and sb3");
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that the comparison is from index 0 to length() - 1 of the two
|
||||
* character sequences.
|
||||
*/
|
||||
@Test
|
||||
public void testModifiedSequence() {
|
||||
StringBuilder sb1 = generateTestBuffer(65, 70, 97, 102);
|
||||
StringBuilder sb2 = generateTestBuffer(65, 70, 98, 103);
|
||||
|
||||
// contain different character sequences
|
||||
Assert.assertFalse(sb1.compareTo(sb2) == 0, "Compare the sequences before truncation");
|
||||
|
||||
// the first 5 characters however are the same
|
||||
sb1.setLength(5);
|
||||
sb2.setLength(5);
|
||||
|
||||
System.out.println(sb1.toString());
|
||||
System.out.println(sb2.toString());
|
||||
|
||||
Assert.assertTrue(sb1.compareTo(sb2) == 0, "Compare sb1 and sb2");
|
||||
Assert.assertTrue(sb1.toString().compareTo(sb2.toString()) == 0, "Compare strings of sb1 and sb2");
|
||||
}
|
||||
|
||||
private Set<String> constructStringSet() {
|
||||
Set<String> sSet = new TreeSet<>();
|
||||
for (String[] book : books) {
|
||||
sSet.add(book[0] + SEP + book[1]);
|
||||
}
|
||||
return sSet;
|
||||
}
|
||||
|
||||
private Set<StringBuilder> constructSBSet() {
|
||||
Set<StringBuilder> sbSet = new TreeSet<>();
|
||||
for (String[] book : books) {
|
||||
sbSet.add(new StringBuilder(book[0]).append(SEP).append(book[1]));
|
||||
}
|
||||
return sbSet;
|
||||
}
|
||||
|
||||
private static StringBuilder generateTestBuffer(int from1, int to1,
|
||||
int from2, int to2) {
|
||||
StringBuilder aBuffer = new StringBuilder(50);
|
||||
|
||||
for (int i = from1; i < to1; i++) {
|
||||
aBuffer.append((char)i);
|
||||
}
|
||||
for (int i = from2; i < to2; i++) {
|
||||
aBuffer.append((char)i);
|
||||
}
|
||||
return aBuffer;
|
||||
}
|
||||
}
|
||||
81
test/jdk/java/lang/StringBuilder/EnsureCapacity.java
Normal file
81
test/jdk/java/lang/StringBuilder/EnsureCapacity.java
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* Copyright (c) 2010, 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 6955504 6992121
|
||||
* @summary Test the StringBuilder.ensureCapacity() with negative minimumCapacity
|
||||
* and append() method with negative length input argument.
|
||||
* Also, test the StringBuffer class.
|
||||
*/
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Vector;
|
||||
|
||||
public class EnsureCapacity {
|
||||
public static void main(String[] args) {
|
||||
testStringBuilder();
|
||||
testStringBuffer();
|
||||
}
|
||||
|
||||
private static void checkCapacity(int before, int after) {
|
||||
if (before != after) {
|
||||
throw new RuntimeException("capacity is expected to be unchanged: " +
|
||||
"before=" + before + " after=" + after);
|
||||
}
|
||||
}
|
||||
|
||||
private static void testStringBuilder() {
|
||||
StringBuilder sb = new StringBuilder("abc");
|
||||
int cap = sb.capacity();
|
||||
|
||||
// test if negative minimumCapacity
|
||||
sb.ensureCapacity(Integer.MIN_VALUE);
|
||||
checkCapacity(cap, sb.capacity());
|
||||
|
||||
try {
|
||||
char[] str = {'a', 'b', 'c', 'd'};
|
||||
// test if negative length
|
||||
sb.append(str, 0, Integer.MIN_VALUE + 10);
|
||||
throw new RuntimeException("IndexOutOfBoundsException not thrown");
|
||||
} catch (IndexOutOfBoundsException ex) {
|
||||
}
|
||||
}
|
||||
|
||||
private static void testStringBuffer() {
|
||||
StringBuffer sb = new StringBuffer("abc");
|
||||
int cap = sb.capacity();
|
||||
|
||||
// test if negative minimumCapacity
|
||||
sb.ensureCapacity(Integer.MIN_VALUE);
|
||||
checkCapacity(cap, sb.capacity());
|
||||
|
||||
try {
|
||||
char[] str = {'a', 'b', 'c', 'd'};
|
||||
// test if negative length
|
||||
sb.append(str, 0, Integer.MIN_VALUE + 10);
|
||||
throw new RuntimeException("IndexOutOfBoundsException not thrown");
|
||||
} catch (IndexOutOfBoundsException ex) {
|
||||
}
|
||||
}
|
||||
}
|
||||
123
test/jdk/java/lang/StringBuilder/Exceptions.java
Normal file
123
test/jdk/java/lang/StringBuilder/Exceptions.java
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
/*
|
||||
* Copyright (c) 2005, 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 6248507
|
||||
* @summary Verify that exceptions are thrown as expected.
|
||||
*/
|
||||
|
||||
public class Exceptions {
|
||||
private static boolean ok = true;
|
||||
|
||||
private static void fail(Throwable ex, String s, Throwable got) {
|
||||
ok = false;
|
||||
System.err.println("expected "
|
||||
+ ex.getClass().getName() + ": " + ex.getMessage()
|
||||
+ " for " + s
|
||||
+ " got "
|
||||
+ got.getClass().getName() + ": " + got.getMessage()
|
||||
+ " - FAILED");
|
||||
}
|
||||
|
||||
private static void pass(String s) {
|
||||
System.out.println(s + " -- OK");
|
||||
}
|
||||
|
||||
private static void tryCatch(String s, Throwable ex, Runnable thunk) {
|
||||
Throwable t = null;
|
||||
try {
|
||||
thunk.run();
|
||||
} catch (Throwable x) {
|
||||
if (ex.getClass().isAssignableFrom(x.getClass()))
|
||||
t = x;
|
||||
else
|
||||
x.printStackTrace();
|
||||
}
|
||||
if ((t == null) && (ex != null))
|
||||
fail(ex, s, t);
|
||||
|
||||
String msg = (ex == null ? null : ex.getMessage());
|
||||
if ((msg != null) && !msg.equals(t.getMessage()))
|
||||
fail(ex, s, t);
|
||||
else
|
||||
pass(s);
|
||||
}
|
||||
|
||||
public static void main(String [] args) {
|
||||
System.out.println("StringBuilder()");
|
||||
tryCatch(" no args", null, new Runnable() {
|
||||
public void run() {
|
||||
new StringBuilder();
|
||||
}});
|
||||
|
||||
System.out.println("StringBuilder(int length)");
|
||||
tryCatch(" 1", null, new Runnable() {
|
||||
public void run() {
|
||||
new StringBuilder(1);
|
||||
}});
|
||||
tryCatch(" -1", new NegativeArraySizeException(), new Runnable() {
|
||||
public void run() {
|
||||
new StringBuilder(-1);
|
||||
}});
|
||||
|
||||
System.out.println("StringBuilder(String str)");
|
||||
tryCatch(" null", new NullPointerException(), new Runnable() {
|
||||
public void run() {
|
||||
new StringBuilder(null);
|
||||
}});
|
||||
tryCatch(" foo", null, new Runnable() {
|
||||
public void run() {
|
||||
new StringBuilder("foo");
|
||||
}});
|
||||
|
||||
System.out.println("StringBuilder.replace(int start, int end, String str)");
|
||||
tryCatch(" -1, 2, \" \"",
|
||||
new StringIndexOutOfBoundsException("Range [-1, 2) out of bounds for length 7"),
|
||||
new Runnable() {
|
||||
public void run() {
|
||||
StringBuilder sb = new StringBuilder("hilbert");
|
||||
sb.replace(-1, 2, " ");
|
||||
}});
|
||||
tryCatch(" 7, 8, \" \"",
|
||||
new StringIndexOutOfBoundsException("Range [7, 6) out of bounds for length 6"),
|
||||
new Runnable() {
|
||||
public void run() {
|
||||
StringBuilder sb = new StringBuilder("banach");
|
||||
sb.replace(7, 8, " ");
|
||||
}});
|
||||
tryCatch(" 2, 1, \" \"",
|
||||
new StringIndexOutOfBoundsException("Range [2, 1) out of bounds for length 7"),
|
||||
new Runnable() {
|
||||
public void run() {
|
||||
StringBuilder sb = new StringBuilder("riemann");
|
||||
sb.replace(2, 1, " ");
|
||||
}});
|
||||
|
||||
if (!ok) {
|
||||
throw new RuntimeException("Some tests FAILED");
|
||||
} else {
|
||||
System.out.println("All tests PASSED");
|
||||
}
|
||||
}
|
||||
}
|
||||
133
test/jdk/java/lang/StringBuilder/HugeCapacity.java
Normal file
133
test/jdk/java/lang/StringBuilder/HugeCapacity.java
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2025, 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.
|
||||
*/
|
||||
|
||||
import jdk.internal.util.ArraysSupport;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @bug 8149330 8218227 8351443
|
||||
* @summary Capacity should not get close to Integer.MAX_VALUE unless
|
||||
* necessary
|
||||
* @modules java.base/jdk.internal.util
|
||||
* @requires (sun.arch.data.model == "64" & os.maxMemory >= 8G)
|
||||
* @run main/othervm -Xms8G -Xmx8G -XX:-CompactStrings -Xlog:gc HugeCapacity false
|
||||
* @run main/othervm -Xms8G -Xmx8G -XX:+CompactStrings -Xlog:gc HugeCapacity true
|
||||
*/
|
||||
|
||||
public class HugeCapacity {
|
||||
private static int failures = 0;
|
||||
|
||||
public static void main(String[] args) {
|
||||
if (args.length == 0) {
|
||||
throw new IllegalArgumentException("Need the argument");
|
||||
}
|
||||
boolean isCompact = Boolean.parseBoolean(args[0]);
|
||||
|
||||
testLatin1(isCompact);
|
||||
testUtf16();
|
||||
testHugeInitialString();
|
||||
testHugeInitialCharSequence();
|
||||
testHugePlus(isCompact);
|
||||
if (failures > 0) {
|
||||
throw new RuntimeException(failures + " tests failed");
|
||||
}
|
||||
}
|
||||
|
||||
private static void testLatin1(boolean isCompact) {
|
||||
try {
|
||||
int divisor = isCompact ? 2 : 4;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.ensureCapacity(Integer.MAX_VALUE / divisor);
|
||||
sb.ensureCapacity(Integer.MAX_VALUE / divisor + 1);
|
||||
} catch (OutOfMemoryError oom) {
|
||||
oom.printStackTrace();
|
||||
failures++;
|
||||
}
|
||||
}
|
||||
|
||||
private static void testUtf16() {
|
||||
try {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append('\u042b');
|
||||
sb.ensureCapacity(Integer.MAX_VALUE / 4);
|
||||
sb.ensureCapacity(Integer.MAX_VALUE / 4 + 1);
|
||||
} catch (OutOfMemoryError oom) {
|
||||
oom.printStackTrace();
|
||||
failures++;
|
||||
}
|
||||
}
|
||||
|
||||
private static void testHugeInitialString() {
|
||||
try {
|
||||
String str = "Z".repeat(ArraysSupport.SOFT_MAX_ARRAY_LENGTH);
|
||||
StringBuilder sb = new StringBuilder(str);
|
||||
} catch (OutOfMemoryError ignore) {
|
||||
} catch (Throwable unexpected) {
|
||||
unexpected.printStackTrace();
|
||||
failures++;
|
||||
}
|
||||
}
|
||||
|
||||
private static void testHugeInitialCharSequence() {
|
||||
try {
|
||||
CharSequence seq = new MyHugeCharSeq();
|
||||
StringBuilder sb = new StringBuilder(seq);
|
||||
} catch (OutOfMemoryError ignore) {
|
||||
} catch (Throwable unexpected) {
|
||||
unexpected.printStackTrace();
|
||||
failures++;
|
||||
}
|
||||
}
|
||||
|
||||
private static class MyHugeCharSeq implements CharSequence {
|
||||
public char charAt(int i) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
public int length() { return Integer.MAX_VALUE; }
|
||||
public CharSequence subSequence(int st, int e) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
public String toString() { return ""; }
|
||||
}
|
||||
|
||||
// Test creating and appending the max size string for -XX:+CompactStrings and -XX:-CompactStrings
|
||||
private static void testHugePlus(boolean isCompact) {
|
||||
int repeatCount = (isCompact) ? Integer.MAX_VALUE / 2 - 1 : Integer.MAX_VALUE / 4 - 1;
|
||||
char[] chars = new char[repeatCount];
|
||||
char[] aChar = {'A', '\uff21'};
|
||||
for (char ch : aChar) {
|
||||
try {
|
||||
int size = (ch > 0xff) ? repeatCount / 2 : repeatCount;
|
||||
Arrays.fill(chars, 0, size, ch);
|
||||
StringBuilder b = new StringBuilder(0);
|
||||
b.append(chars, 0, size);
|
||||
b.append(chars, 0, size);
|
||||
} catch (Throwable unexpected) {
|
||||
unexpected.printStackTrace();
|
||||
failures++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
52
test/jdk/java/lang/StringBuilder/Insert.java
Normal file
52
test/jdk/java/lang/StringBuilder/Insert.java
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @bug 4914802 8257511
|
||||
* @summary Test StringBuilder.insert sanity tests
|
||||
* @run testng/othervm -XX:-CompactStrings Insert
|
||||
* @run testng/othervm -XX:+CompactStrings Insert
|
||||
*/
|
||||
@Test
|
||||
public class Insert {
|
||||
|
||||
public void insertFalse() {
|
||||
// Caused an infinite loop before 4914802
|
||||
StringBuilder sb = new StringBuilder();
|
||||
assertEquals("false", sb.insert(0, false).toString());
|
||||
}
|
||||
|
||||
public void insertOffset() {
|
||||
// 8254082 made the String variant cause an AIOOBE, fixed in 8257511
|
||||
assertEquals("efabc", new StringBuilder("abc").insert(0, "def", 1, 3).toString());
|
||||
assertEquals("efabc", new StringBuilder("abc").insert(0, new StringBuilder("def"), 1, 3).toString());
|
||||
// insert(I[CII) and insert(ILjava/lang/CharSequence;II) are inconsistently specified
|
||||
assertEquals("efabc", new StringBuilder("abc").insert(0, new char[] {'d', 'e', 'f'}, 1, 2).toString());
|
||||
}
|
||||
|
||||
}
|
||||
302
test/jdk/java/lang/StringBuilder/RacingSBThreads.java
Normal file
302
test/jdk/java/lang/StringBuilder/RacingSBThreads.java
Normal file
|
|
@ -0,0 +1,302 @@
|
|||
/*
|
||||
* Copyright (c) 2025, 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
|
||||
* @summary Test multi-threaded use of StringBuilder
|
||||
* @compile --release 8 RacingSBThreads.java
|
||||
* @run main/othervm -esa RacingSBThreads read
|
||||
* @run main/othervm -esa RacingSBThreads insert
|
||||
* @run main/othervm -esa RacingSBThreads append
|
||||
*/
|
||||
|
||||
import java.nio.CharBuffer;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.Arrays;
|
||||
import java.util.Locale;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
/**
|
||||
* Test racing accesses in StringBuilder.
|
||||
* Test source code should be compatible with JDK 8 to allow testing on older versions.
|
||||
*/
|
||||
public class RacingSBThreads {
|
||||
|
||||
private static final int TIMEOUT_SEC = 1; // Duration to run each test case
|
||||
private static final int N = 1_000_000; // static number of iterations for writes and modifies
|
||||
private static final int LEN = 100_000; // Length of initial SB
|
||||
|
||||
// Strings available to be used as the initial contents of a StringBuilder
|
||||
private static final String UTF16_CHARS = initString('\u1000', LEN);
|
||||
private static final String LATIN1_CHARS = initString('a', LEN);
|
||||
|
||||
// Cache jtreg timeout factor to allow test to be run as a standalone main()
|
||||
private static final double TIMEOUT_FACTOR = Double.parseDouble(System.getProperty("test.timeout.factor", "1.0"));
|
||||
|
||||
// Constant arguments available to be passed to StringBuilder operations
|
||||
private static final StringBuilder otherSB = new StringBuilder("ab\uFF21\uFF22");
|
||||
private static final StringBuilder otherLongerSB = new StringBuilder("abcde\uFF21\uFF22\uFF23\uFF24\uFF25");
|
||||
|
||||
// Create a String with a repeated character
|
||||
private static String initString(char c, int len) {
|
||||
char[] chars = new char[len];
|
||||
Arrays.fill(chars, c);
|
||||
return new String(chars);
|
||||
}
|
||||
|
||||
// Plain unsynchronized reference to a StringBuilder
|
||||
// Updated by the writer thread
|
||||
// Read by the reader thread
|
||||
private StringBuilder buf;
|
||||
|
||||
// The current stress test case
|
||||
private final StressKind stressKind;
|
||||
|
||||
// Count of faults, zero if no faults found
|
||||
private final AtomicInteger faultCount = new AtomicInteger(0);
|
||||
|
||||
/**
|
||||
* Run the stress cases indicated by command line arguments or run all cases.
|
||||
* Running each for TIMEOUT_SEC seconds or until a failure.
|
||||
* The timeout/test duration can be scaled by setting System property
|
||||
* `test.timeout.factor` to a double value, for example, `-Dtest.timeout.factor=2.0`
|
||||
* @param args command line arguments
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
Duration duration = Duration.ofSeconds((long)(TIMEOUT_SEC * TIMEOUT_FACTOR));
|
||||
|
||||
StressKind[] kinds = StressKind.values();
|
||||
if (args.length > 0) {
|
||||
// Parse explicitly supplied StressKind arguments
|
||||
try {
|
||||
kinds = Arrays.stream(args)
|
||||
.map((s) -> StressKind.valueOf(s.toUpperCase(Locale.ROOT)))
|
||||
.toArray(StressKind[]::new);
|
||||
} catch (Exception ex) {
|
||||
System.out.println("Invalid StressKind arguments: " + Arrays.toString(args));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Run each kind for the duration
|
||||
int totalFaults = 0;
|
||||
for (StressKind sk : kinds) {
|
||||
Instant end = Instant.now().plus(duration); // note clock time, not runtime
|
||||
while (Instant.now().isBefore(end)) {
|
||||
int faultCount = new RacingSBThreads(sk).stress();
|
||||
if (faultCount > 0) {
|
||||
System.out.printf("ERROR: Test case %s, %d faults%n", sk, faultCount);
|
||||
}
|
||||
totalFaults += faultCount;
|
||||
}
|
||||
}
|
||||
if (totalFaults > 0) {
|
||||
throw new AssertionError("Total faults: " + totalFaults);
|
||||
}
|
||||
}
|
||||
|
||||
// Enum of the various test cases with a lambda to invoke for each
|
||||
enum StressKind {
|
||||
/**
|
||||
* Reading characters should always be one of the known values being written to the destination
|
||||
*/
|
||||
READ(LATIN1_CHARS, (sb, chr) -> {
|
||||
char ch = sb.charAt(LEN * 4 / 5);
|
||||
if (ch != chr & ch != (chr & 0xff) & ch != chr >> 8) {
|
||||
throw new AssertionError("Unexpected characters in buffer: 0x" + Integer.toHexString(ch));
|
||||
}
|
||||
}),
|
||||
/**
|
||||
* Insert another StringBuilder; in the face of racy changes to the destination
|
||||
*/
|
||||
INSERT(LATIN1_CHARS, (sb, C) -> {
|
||||
sb.insert(sb.length() - 1, otherLongerSB, 0, otherLongerSB.length());
|
||||
}),
|
||||
/**
|
||||
* Appending a StringBuilder in the face of racy changes to the destination
|
||||
*/
|
||||
APPEND(LATIN1_CHARS, (sb, C) -> {
|
||||
sb.append(otherSB, 0, otherSB.length());
|
||||
}),
|
||||
;
|
||||
|
||||
private final BiConsumer<StringBuilder,Character> func;
|
||||
private final String sbInitString;
|
||||
|
||||
/**
|
||||
* Defines a test case.
|
||||
* @param sbInitString the initial contents of the StringBuilder; chooses the coder
|
||||
* @param func the test BiConsumer to apply to the StringBuilder
|
||||
*/
|
||||
private StressKind(String sbInitString, BiConsumer<StringBuilder,Character> func) {
|
||||
this.func = func;
|
||||
this.sbInitString = sbInitString;
|
||||
}
|
||||
}
|
||||
|
||||
public RacingSBThreads(StressKind stressKind) {
|
||||
this.stressKind = stressKind;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the stress case.
|
||||
* One thread continuously creates a StringBuilder and fills it before trimming it to zero.
|
||||
* The other thread performs the test case on the same StringBuilder (without any synchronization)
|
||||
* @return the count of faults
|
||||
*/
|
||||
private int stress() {
|
||||
PokeBuilder r = new PokeBuilder(this, N);
|
||||
Writer w = new Writer(this, N);
|
||||
|
||||
Thread writer = new Thread(w::createShrink);
|
||||
Thread reader = new Thread(r::readModify);
|
||||
writer.start();
|
||||
reader.start();
|
||||
join(reader);
|
||||
System.out.println(r);
|
||||
writer.interrupt();
|
||||
join(writer);
|
||||
System.out.println(w);
|
||||
return r.racing.faultCount.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for a thread to terminate.
|
||||
* @param thread a thread to wait for
|
||||
*/
|
||||
private void join(Thread thread) {
|
||||
do {
|
||||
try {
|
||||
thread.join();
|
||||
break;
|
||||
} catch (InterruptedException ie) {
|
||||
// ignore and retry
|
||||
}
|
||||
} while (true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Run a StressKind case in a loop keeping track of exceptions.
|
||||
* The StringBuilder under test is shared with the writer task without benefit of synchronization.
|
||||
*/
|
||||
private static class PokeBuilder {
|
||||
private final RacingSBThreads racing;
|
||||
private final int iterations;
|
||||
private int nulls;
|
||||
private int bounds;
|
||||
private int pokeCycles;
|
||||
private int bufChanges;
|
||||
|
||||
public PokeBuilder(RacingSBThreads racing, int iterations) {
|
||||
this.racing = racing;
|
||||
this.iterations = iterations;
|
||||
nulls = 0;
|
||||
bounds = 0;
|
||||
pokeCycles = 0;
|
||||
bufChanges = 0;
|
||||
}
|
||||
|
||||
// Repeatedly change the racy StringBuilder, ignoring and counting exceptions
|
||||
private void readModify() {
|
||||
System.out.println("Starting " + racing.stressKind);
|
||||
sleep(100);
|
||||
for (int i = 0; i < iterations; ++i) {
|
||||
pokeCycles++;
|
||||
StringBuilder sb = racing.buf; // read once
|
||||
try {
|
||||
if (sb.length() > Integer.MAX_VALUE / 4) {
|
||||
sb.setLength(Integer.MAX_VALUE / 4);
|
||||
}
|
||||
// Invoke the test case
|
||||
racing.stressKind.func.accept(sb, racing.stressKind.sbInitString.charAt(0));
|
||||
if (sb != racing.buf) {
|
||||
bufChanges++;
|
||||
}
|
||||
} catch (NullPointerException e) {
|
||||
++nulls;
|
||||
} catch (IndexOutOfBoundsException e) {
|
||||
++bounds;
|
||||
} catch (AssertionError ae) {
|
||||
racing.faultCount.incrementAndGet();
|
||||
throw ae;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void sleep(int i) {
|
||||
try {
|
||||
Thread.sleep(i);
|
||||
} catch (InterruptedException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return String.format("pokeCycles:%d, bounds:%d, bufChanges:%d, nulls=%d",
|
||||
pokeCycles, bounds, bufChanges, nulls);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Repeatedly create and append strings to a StringBuilder shared through fields of RacingSBThreads.
|
||||
* The StringBuilder is created new on each iteration and truncated at the end of each iteration.
|
||||
* Exceptions are counted and reported.
|
||||
*/
|
||||
private static class Writer {
|
||||
private final RacingSBThreads racing;
|
||||
private final int iterations;
|
||||
private int sumWriter;
|
||||
private int writeCycles;
|
||||
private int putBounds;
|
||||
|
||||
public Writer(RacingSBThreads racing, int iterations) {
|
||||
this.racing = racing;
|
||||
this.iterations = iterations;
|
||||
}
|
||||
|
||||
private void createShrink() {
|
||||
for (int i = 0; i < iterations; ++i) {
|
||||
if (i % 100_000 == 0) {
|
||||
if (Thread.interrupted()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
try {
|
||||
++writeCycles;
|
||||
racing.buf = new StringBuilder(racing.stressKind.sbInitString);
|
||||
racing.buf.append(UTF16_CHARS);
|
||||
sumWriter += racing.buf.length();
|
||||
racing.buf.setLength(0);
|
||||
racing.buf.trimToSize();
|
||||
} catch (Exception ex) {
|
||||
++putBounds;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return String.format("writeCycles:%d, bounds:%d, sumWriter=%d", writeCycles, putBounds, sumWriter);
|
||||
}
|
||||
}
|
||||
}
|
||||
337
test/jdk/java/lang/StringBuilder/StressSBTest.java
Normal file
337
test/jdk/java/lang/StringBuilder/StressSBTest.java
Normal file
|
|
@ -0,0 +1,337 @@
|
|||
/*
|
||||
* Copyright (c) 2025, 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 8351443
|
||||
* @summary Randomized test of StringBuilder
|
||||
* @run main StressSBTest
|
||||
*/
|
||||
|
||||
import java.lang.System.Logger;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.nio.CharBuffer;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
|
||||
public class StressSBTest {
|
||||
|
||||
// Logger for info and errors
|
||||
static final Logger LOG = System.getLogger("StressSBTest");
|
||||
// Number of concurrent platform threads
|
||||
private final static int N_THREADS = 11;
|
||||
// Base length of test run
|
||||
private final static Duration N_Duration = Duration.ofSeconds(2);
|
||||
// Cache jtreg timeout factor to allow test to be run as a standalone main()
|
||||
private static final double TIMEOUT_FACTOR =
|
||||
Double.parseDouble(System.getProperty("test.timeout.factor", "1.0"));
|
||||
|
||||
/**
|
||||
* Run the stress test with a fixed set of parameters.
|
||||
*
|
||||
* @param ignored
|
||||
*/
|
||||
public static void main(String[] ignored) {
|
||||
Duration duration = Duration.ofMillis((long) (N_Duration.toMillis() * TIMEOUT_FACTOR));
|
||||
new StressSBTest().stress(N_THREADS, duration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stress test using a number of platform threads for a duration.
|
||||
* Success is marked by a lack of exceptions.
|
||||
* Logging output indicates the number of operations performed by each thread
|
||||
*
|
||||
* @param numThreads the number of threads
|
||||
* @param duration a Duration, typically a few seconds
|
||||
*/
|
||||
public void stress(int numThreads, Duration duration) {
|
||||
StressOps stressOps = new StressOps();
|
||||
|
||||
final StringBuilder sb = new StringBuilder("abcdefghijklmnopqrstuvwxyz");
|
||||
// A single StringBuilder is used to exercise the API in the face of racy behavior
|
||||
List<Thread> threads = IntStream.range(0, numThreads).mapToObj(i -> {
|
||||
try {
|
||||
Thread t = Thread.ofPlatform().start(() -> stressOps.randomStress(sb, duration));
|
||||
LOG.log(Logger.Level.DEBUG, t);
|
||||
return t;
|
||||
} catch (Throwable t) {
|
||||
LOG.log(Logger.Level.ERROR, "Thread.ofPlatform", t);
|
||||
}
|
||||
return null;
|
||||
})
|
||||
.filter(t -> t != null)
|
||||
.toList();
|
||||
threads.forEach(t -> {
|
||||
try {
|
||||
t.join();
|
||||
} catch (InterruptedException ie) {
|
||||
// ignore
|
||||
}
|
||||
});
|
||||
LOG.log(Logger.Level.INFO, "Completed: threads: %d, duration: %s".formatted(numThreads, duration));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Methods and support for stress testing StringBuilder.
|
||||
*/
|
||||
private static class StressOps {
|
||||
|
||||
private static final Random randomGen = new Random();
|
||||
private static final StringBuilder stringBuilder = new StringBuilder("wxyz");
|
||||
private static final StringBuffer stringBuffer = new StringBuffer("wxyz");
|
||||
private static final CharBuffer charBuffer = CharBuffer.allocate(10).append("charBuffer");
|
||||
private static final char[] charArray = "xyz".toCharArray();
|
||||
private static final CharSequence charSequence = "now is the time";
|
||||
// Cache of mappings of all StringBuilder public instand methods mh -> Method
|
||||
private static Map<MethodHandle, Method> testMethodsCache;
|
||||
// Active map of SB methods mh -> Method
|
||||
private final Map<MethodHandle, Method> testMethods;
|
||||
|
||||
public StressOps() {
|
||||
if (testMethodsCache == null) {
|
||||
testMethodsCache = findTestMethods();
|
||||
}
|
||||
testMethods = testMethodsCache;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stress test randomizes methods acting on a StringBuilder.
|
||||
* Exceptions are logged but do no affect success/failure result.
|
||||
*
|
||||
* @param sb a StringBuilder
|
||||
* @param duration a Duration of time to stress
|
||||
*/
|
||||
public void randomStress(StringBuilder sb, Duration duration) {
|
||||
MethodHandle[] ops = testMethods.keySet().toArray(new MethodHandle[0]);
|
||||
int count = 0;
|
||||
int worked = 0;
|
||||
Instant end = Instant.now().plus(duration);
|
||||
while (Instant.now().isBefore(end)) {
|
||||
int j = randomGen.nextInt(ops.length);
|
||||
var mh = ops[j];
|
||||
String name = testMethods.get(mh).getName();
|
||||
MethodType mt = mh.type();
|
||||
try {
|
||||
count++;
|
||||
if (invokeByMethodNameAndType(name, mt, sb)) {
|
||||
worked++;
|
||||
}
|
||||
|
||||
} catch (Throwable t) {
|
||||
LOG.log(Logger.Level.DEBUG, "Exception testing " + name + mt, t);
|
||||
}
|
||||
}
|
||||
LOG.log(Logger.Level.INFO, "StringBuilder method calls: %d, successful: %d".formatted(count, worked));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@return Return a map of all the public instance methods of java.lang.StringBuilder
|
||||
* mapping MethodHandle to the Method}
|
||||
*/
|
||||
private Map<MethodHandle, Method> findTestMethods() {
|
||||
MethodHandles.Lookup lookup = MethodHandles.lookup();
|
||||
Method[] methods = StringBuilder.class.getDeclaredMethods();
|
||||
Map<MethodHandle, Method> map = new HashMap<>(methods.length);
|
||||
Arrays.stream(methods)
|
||||
.filter(m -> Modifier.isPublic(m.getModifiers()) &&
|
||||
!Modifier.isStatic(m.getModifiers()))
|
||||
.forEach(m -> {
|
||||
try {
|
||||
MethodHandle mh = lookup.unreflect(m);
|
||||
map.put(mh, m);
|
||||
} catch (IllegalAccessException iae) {
|
||||
LOG.log(Logger.Level.DEBUG, "AsbTest annotated method not accessible", iae);
|
||||
}
|
||||
});
|
||||
LOG.log(Logger.Level.DEBUG, "%d StringBuilder test methods".formatted(map.size()));
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoke the indicated method on the StringBuilder
|
||||
*
|
||||
* @param name the method name
|
||||
* @param mt the method type
|
||||
* @param sb a StringBuilder
|
||||
* @return true if the method returned a non-null result
|
||||
*/
|
||||
private boolean invokeByMethodNameAndType(String name, MethodType mt, StringBuilder sb) {
|
||||
String s = name + mt.toString();
|
||||
Object o = switch (s) {
|
||||
case "length(StringBuilder)int" -> sb.length();
|
||||
case "toString(StringBuilder)String" -> sb.toString();
|
||||
case "append(StringBuilder,StringBuffer)AbstractStringBuilder" ->
|
||||
sb.append(stringBuffer);
|
||||
case "append(StringBuilder,StringBuffer)StringBuilder" -> sb.append(stringBuffer);
|
||||
case "append(StringBuilder,CharSequence)AbstractStringBuilder" ->
|
||||
sb.append(charBuffer);
|
||||
case "append(StringBuilder,CharSequence)StringBuilder" -> sb.append(charBuffer);
|
||||
case "append(StringBuilder,CharSequence)Appendable" -> sb.append(charBuffer);
|
||||
case "append(StringBuilder,CharSequence,int,int)AbstractStringBuilder" ->
|
||||
sb.append("abc", 1, 2);
|
||||
case "append(StringBuilder,CharSequence,int,int)StringBuilder" ->
|
||||
sb.append("abc", 1, 2);
|
||||
case "append(StringBuilder,CharSequence,int,int)Appendable" ->
|
||||
sb.append("abc", 1, 2);
|
||||
case "append(StringBuilder,char[])AbstractStringBuilder" -> sb.append(charArray);
|
||||
case "append(StringBuilder,char[])StringBuilder" -> sb.append(charArray);
|
||||
case "append(StringBuilder,String)AbstractStringBuilder" -> sb.append("Abcdefg");
|
||||
case "append(StringBuilder,String)StringBuilder" -> sb.append("abcdefg");
|
||||
case "append(StringBuilder,Object)AbstractStringBuilder" -> new Object();
|
||||
case "append(StringBuilder,Object)StringBuilder" -> sb.append(new Object());
|
||||
case "append(StringBuilder,char)Appendable" -> sb.append('\uff21');
|
||||
case "append(StringBuilder,char)AbstractStringBuilder" -> sb.append('A');
|
||||
case "append(StringBuilder,char)StringBuilder" -> sb.append('B');
|
||||
case "append(StringBuilder,int)AbstractStringBuilder" -> sb.append(987654321);
|
||||
case "append(StringBuilder,int)StringBuilder" -> sb.append(987654321);
|
||||
case "append(StringBuilder,long)AbstractStringBuilder" ->
|
||||
sb.append(987654321987654321L);
|
||||
case "append(StringBuilder,long)StringBuilder" -> sb.append(987654321987654321L);
|
||||
case "append(StringBuilder,float)AbstractStringBuilder" -> sb.append(Math.PI);
|
||||
case "append(StringBuilder,float)StringBuilder" -> sb.append(Math.PI);
|
||||
case "append(StringBuilder,double)AbstractStringBuilder" -> sb.append(Math.TAU);
|
||||
case "append(StringBuilder,double)StringBuilder" -> sb.append(Math.TAU);
|
||||
case "append(StringBuilder,boolean)AbstractStringBuilder" -> sb.append(true);
|
||||
case "append(StringBuilder,boolean)StringBuilder" -> sb.append(false);
|
||||
case "append(StringBuilder,char[],int,int)AbstractStringBuilder" ->
|
||||
sb.append(charArray, 3, 4);
|
||||
case "append(StringBuilder,char[],int,int)StringBuilder" ->
|
||||
sb.append(charArray, 4, 3);
|
||||
case "reverse(StringBuilder)StringBuilder" -> sb.reverse();
|
||||
case "reverse(StringBuilder)AbstractStringBuilder" -> sb.reverse();
|
||||
case "getChars(StringBuilder,int,int,char[],int)void" -> {
|
||||
sb.getChars(2, 4, charArray, 3);
|
||||
yield sb;
|
||||
}
|
||||
case "compareTo(StringBuilder,Object)int" -> sb.compareTo(stringBuilder);
|
||||
case "compareTo(StringBuilder,StringBuilder)int" -> sb.compareTo(stringBuilder);
|
||||
case "indexOf(StringBuilder,String,int)int" -> sb.indexOf("A", 2);
|
||||
case "indexOf(StringBuilder,String)int" -> sb.indexOf("B");
|
||||
case "insert(StringBuilder,int,CharSequence)StringBuilder" ->
|
||||
sb.insert(2, charSequence);
|
||||
case "insert(StringBuilder,int,CharSequence)AbstractStringBuilder" ->
|
||||
sb.insert(2, charSequence);
|
||||
case "insert(StringBuilder,int,String)StringBuilder" -> sb.insert(2, "Now");
|
||||
case "insert(StringBuilder,int,String)AbstractStringBuilder" ->
|
||||
sb.insert(2, "Then");
|
||||
case "insert(StringBuilder,int,char[])StringBuilder" -> sb.insert(4, charArray);
|
||||
case "insert(StringBuilder,int,char[])AbstractStringBuilder" ->
|
||||
sb.insert(4, charArray);
|
||||
case "insert(StringBuilder,int,Object)AbstractStringBuilder" ->
|
||||
sb.insert(3, new Object());
|
||||
case "insert(StringBuilder,int,Object)StringBuilder" -> sb.insert(4, "RUST");
|
||||
case "insert(StringBuilder,int,char[],int,int)AbstractStringBuilder" ->
|
||||
sb.insert(2, charArray, 0, 4);
|
||||
case "insert(StringBuilder,int,char[],int,int)StringBuilder" ->
|
||||
sb.insert(2, charArray, 0, 4);
|
||||
case "insert(StringBuilder,int,int)StringBuilder" -> sb.insert(2, 46000);
|
||||
case "insert(StringBuilder,int,int)AbstractStringBuilder" -> sb.insert(3, 47000);
|
||||
case "insert(StringBuilder,int,double)StringBuilder" -> sb.insert(2, Math.PI);
|
||||
case "insert(StringBuilder,int,double)AbstractStringBuilder" ->
|
||||
sb.insert(2, Math.PI);
|
||||
case "insert(StringBuilder,int,float)StringBuilder" -> sb.insert(2, Math.TAU);
|
||||
case "insert(StringBuilder,int,float)AbstractStringBuilder" ->
|
||||
sb.insert(2, Math.TAU);
|
||||
case "insert(StringBuilder,int,long)StringBuilder" -> sb.insert(2, 42L);
|
||||
case "insert(StringBuilder,int,long)AbstractStringBuilder" -> sb.insert(2, 42L);
|
||||
case "insert(StringBuilder,int,char)StringBuilder" -> sb.insert(2, 'Z');
|
||||
case "insert(StringBuilder,int,char)AbstractStringBuilder" -> sb.insert(2, 'Z');
|
||||
case "insert(StringBuilder,int,boolean)StringBuilder" -> sb.insert(2, true);
|
||||
case "insert(StringBuilder,int,boolean)AbstractStringBuilder" ->
|
||||
sb.insert(3, false);
|
||||
case "insert(StringBuilder,int,CharSequence,int,int)StringBuilder" ->
|
||||
sb.insert(4, charSequence, 4, 5);
|
||||
case "insert(StringBuilder,int,CharSequence,int,int)AbstractStringBuilder" ->
|
||||
sb.insert(4, charSequence, 5, 4);
|
||||
case "charAt(StringBuilder,int)char" -> sb.charAt(5);
|
||||
case "codePointAt(StringBuilder,int)int" -> sb.codePointAt(4);
|
||||
case "codePointBefore(StringBuilder,int)int" -> sb.codePointBefore(3);
|
||||
case "codePointCount(StringBuilder,int,int)int" -> sb.codePointCount(3, 9);
|
||||
case "offsetByCodePoints(StringBuilder,int,int)int" -> sb.offsetByCodePoints(3, 7);
|
||||
case "lastIndexOf(StringBuilder,String,int)int" -> sb.lastIndexOf("A", 45);
|
||||
case "lastIndexOf(StringBuilder,String)int" -> sb.lastIndexOf("B");
|
||||
case "substring(StringBuilder,int)String" -> sb.substring(6);
|
||||
case "substring(StringBuilder,int,int)String" -> sb.substring(6, 9);
|
||||
case "replace(StringBuilder,int,int,String)StringBuilder" ->
|
||||
sb.replace(2, 5, "xyz");
|
||||
case "replace(StringBuilder,int,int,String)AbstractStringBuilder" ->
|
||||
sb.replace(2, 5, "XYZ");
|
||||
case "repeat(StringBuilder,CharSequence,int)StringBuilder" -> sb.repeat('Z', 6);
|
||||
case "repeat(StringBuilder,CharSequence,int)AbstractStringBuilder" ->
|
||||
sb.repeat('X', 42);
|
||||
case "repeat(StringBuilder,int,int)AbstractStringBuilder" -> sb.repeat(101, 25);
|
||||
case "repeat(StringBuilder,int,int)StringBuilder" -> sb.repeat(102, 24);
|
||||
case "codePoints(StringBuilder)IntStream" -> sb.codePoints().count();
|
||||
case "subSequence(StringBuilder,int,int)CharSequence" -> sb.subSequence(3, 9);
|
||||
case "chars(StringBuilder)IntStream" -> sb.chars().count();
|
||||
case "setLength(StringBuilder,int)void" -> {
|
||||
sb.setLength(45);
|
||||
yield 45;
|
||||
}
|
||||
case "capacity(StringBuilder)int" -> sb.capacity();
|
||||
case "ensureCapacity(StringBuilder,int)void" -> {
|
||||
sb.ensureCapacity(150);
|
||||
yield 150;
|
||||
}
|
||||
case "trimToSize(StringBuilder)void" -> {
|
||||
sb.trimToSize();
|
||||
yield sb.length();
|
||||
}
|
||||
case "setCharAt(StringBuilder,int,char)void" -> {
|
||||
sb.setCharAt(6, 'T');
|
||||
yield 'T';
|
||||
}
|
||||
case "appendCodePoint(StringBuilder,int)StringBuilder" ->
|
||||
sb.appendCodePoint(0xff21);
|
||||
case "appendCodePoint(StringBuilder,int)AbstractStringBuilder" ->
|
||||
sb.appendCodePoint(0xff21);
|
||||
case "delete(StringBuilder,int,int)StringBuilder" -> sb.delete(5, 20);
|
||||
case "delete(StringBuilder,int,int)AbstractStringBuilder" -> sb.delete(6, 21);
|
||||
case "deleteCharAt(StringBuilder,int)AbstractStringBuilder" -> sb.deleteCharAt(7);
|
||||
case "deleteCharAt(StringBuilder,int)StringBuilder" -> sb.deleteCharAt(8);
|
||||
case "equals(Object,Object)boolean" -> false;
|
||||
case "hashCode(Object)int" -> sb.hashCode();
|
||||
case "getClass(Object)Class" -> sb.getClass();
|
||||
case "isEmpty(CharSequence)boolean" -> null;
|
||||
default -> {
|
||||
System.out.println("not executing: " + s);
|
||||
yield null;
|
||||
}
|
||||
};
|
||||
return o != null;
|
||||
}
|
||||
}
|
||||
}
|
||||
207
test/jdk/java/lang/StringBuilder/StringBufferRepeat.java
Normal file
207
test/jdk/java/lang/StringBuilder/StringBufferRepeat.java
Normal file
|
|
@ -0,0 +1,207 @@
|
|||
/*
|
||||
* Copyright (c) 2023, 2024, 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.
|
||||
*/
|
||||
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @bug 8302323 8322512
|
||||
* @summary Test StringBuffer.repeat sanity tests
|
||||
* @run testng/othervm -XX:-CompactStrings StringBufferRepeat
|
||||
* @run testng/othervm -XX:+CompactStrings StringBufferRepeat
|
||||
*/
|
||||
@Test
|
||||
public class StringBufferRepeat {
|
||||
private static class MyChars implements CharSequence {
|
||||
private static final char[] DATA = new char[] { 'a', 'b', 'c' };
|
||||
|
||||
@Override
|
||||
public int length() {
|
||||
return DATA.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public char charAt(int index) {
|
||||
return DATA[index];
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence subSequence(int start, int end) {
|
||||
return new String(Arrays.copyOfRange(DATA, start, end));
|
||||
}
|
||||
}
|
||||
|
||||
private static final MyChars MYCHARS = new MyChars();
|
||||
|
||||
public void sanity() {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
// prime the StringBuffer
|
||||
sb.append("repeat");
|
||||
|
||||
// single character Latin1
|
||||
sb.repeat('1', 0);
|
||||
sb.repeat('2', 1);
|
||||
sb.repeat('3', 5);
|
||||
|
||||
// single string Latin1 (optimized)
|
||||
sb.repeat("1", 0);
|
||||
sb.repeat("2", 1);
|
||||
sb.repeat("3", 5);
|
||||
|
||||
// multi string Latin1
|
||||
sb.repeat("-1", 0);
|
||||
sb.repeat("-2", 1);
|
||||
sb.repeat("-3", 5);
|
||||
|
||||
// single character UTF16
|
||||
sb.repeat('\u2460', 0);
|
||||
sb.repeat('\u2461', 1);
|
||||
sb.repeat('\u2462', 5);
|
||||
|
||||
// single string UTF16 (optimized)
|
||||
sb.repeat("\u2460", 0);
|
||||
sb.repeat("\u2461", 1);
|
||||
sb.repeat("\u2462", 5);
|
||||
|
||||
// multi string UTF16
|
||||
|
||||
sb.repeat("-\u2460", 0);
|
||||
sb.repeat("-\u2461", 1);
|
||||
sb.repeat("-\u2462", 5);
|
||||
|
||||
// CharSequence
|
||||
sb.repeat(MYCHARS, 3);
|
||||
|
||||
// null
|
||||
sb.repeat((String)null, 0);
|
||||
sb.repeat((String)null, 1);
|
||||
sb.repeat((String)null, 5);
|
||||
sb.repeat((CharSequence)null, 0);
|
||||
sb.repeat((CharSequence)null, 1);
|
||||
sb.repeat((CharSequence)null, 5);
|
||||
|
||||
|
||||
String expected = "repeat233333233333-2-3-3-3-3-3\u2461\u2462\u2462\u2462\u2462\u2462\u2461\u2462\u2462\u2462\u2462\u2462-\u2461-\u2462-\u2462-\u2462-\u2462-\u2462abcabcabc" +
|
||||
"nullnullnullnullnullnullnullnullnullnullnullnull";
|
||||
assertEquals(expected, sb.toString());
|
||||
|
||||
// Codepoints
|
||||
|
||||
sb.setLength(0);
|
||||
|
||||
sb.repeat(0, 0);
|
||||
sb.repeat(0, 1);
|
||||
sb.repeat(0, 5);
|
||||
sb.repeat((int)' ', 0);
|
||||
sb.repeat((int)' ', 1);
|
||||
sb.repeat((int)' ', 5);
|
||||
sb.repeat(0x2460, 0);
|
||||
sb.repeat(0x2461, 1);
|
||||
sb.repeat(0x2462, 5);
|
||||
sb.repeat(0x10FFFF, 0);
|
||||
sb.repeat(0x10FFFF, 1);
|
||||
sb.repeat(0x10FFFF, 5);
|
||||
|
||||
expected = "\u0000\u0000\u0000\u0000\u0000\u0000\u0020\u0020\u0020\u0020\u0020\u0020\u2461\u2462\u2462\u2462\u2462\u2462\udbff\udfff\udbff\udfff\udbff\udfff\udbff\udfff\udbff\udfff\udbff\udfff";
|
||||
assertEquals(expected, sb.toString());
|
||||
|
||||
// toStringCache
|
||||
|
||||
sb.setLength(0);
|
||||
sb.toString();
|
||||
sb.repeat('*', 5);
|
||||
expected = "*****";
|
||||
assertEquals(sb.toString(), expected);
|
||||
sb.setLength(0);
|
||||
sb.toString();
|
||||
sb.repeat("*", 5);
|
||||
assertEquals(sb.toString(), expected);
|
||||
|
||||
|
||||
}
|
||||
|
||||
public void exceptions() {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
|
||||
try {
|
||||
sb.repeat(' ', Integer.MAX_VALUE);
|
||||
throw new RuntimeException("No OutOfMemoryError thrown");
|
||||
} catch (OutOfMemoryError | IndexOutOfBoundsException ex) {
|
||||
// Okay
|
||||
}
|
||||
|
||||
try {
|
||||
sb.repeat(" ", Integer.MAX_VALUE);
|
||||
throw new RuntimeException("No OutOfMemoryError thrown");
|
||||
} catch (OutOfMemoryError | IndexOutOfBoundsException ex) {
|
||||
// Okay
|
||||
}
|
||||
|
||||
try {
|
||||
sb.repeat(MYCHARS, Integer.MAX_VALUE);
|
||||
throw new RuntimeException("No OutOfMemoryError thrown");
|
||||
} catch (OutOfMemoryError | IndexOutOfBoundsException ex) {
|
||||
// Okay
|
||||
}
|
||||
|
||||
try {
|
||||
sb.repeat(' ', -1);
|
||||
throw new RuntimeException("No IllegalArgumentException thrown");
|
||||
} catch (IllegalArgumentException ex) {
|
||||
// Okay
|
||||
}
|
||||
|
||||
try {
|
||||
sb.repeat("abc", -1);
|
||||
throw new RuntimeException("No IllegalArgumentException thrown");
|
||||
} catch (IllegalArgumentException ex) {
|
||||
// Okay
|
||||
}
|
||||
|
||||
try {
|
||||
sb.repeat(MYCHARS, -1);
|
||||
throw new RuntimeException("No IllegalArgumentException thrown");
|
||||
} catch (IllegalArgumentException ex) {
|
||||
// Okay
|
||||
}
|
||||
|
||||
try {
|
||||
sb.repeat(0x10FFFF + 1, -1);
|
||||
throw new RuntimeException("No IllegalArgumentException thrown");
|
||||
} catch (IllegalArgumentException ex) {
|
||||
// Okay
|
||||
}
|
||||
|
||||
try {
|
||||
sb.repeat(-1, -1);
|
||||
throw new RuntimeException("No IllegalArgumentException thrown");
|
||||
} catch (IllegalArgumentException ex) {
|
||||
// Okay
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
194
test/jdk/java/lang/StringBuilder/StringBuilderRepeat.java
Normal file
194
test/jdk/java/lang/StringBuilder/StringBuilderRepeat.java
Normal file
|
|
@ -0,0 +1,194 @@
|
|||
/*
|
||||
* Copyright (c) 2023, 2025, 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.
|
||||
*/
|
||||
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @bug 8302323 8351443
|
||||
* @summary Test StringBuilder.repeat sanity tests
|
||||
* @run testng/othervm -XX:-CompactStrings StringBuilderRepeat
|
||||
* @run testng/othervm -XX:+CompactStrings StringBuilderRepeat
|
||||
*/
|
||||
@Test
|
||||
public class StringBuilderRepeat {
|
||||
private static class MyChars implements CharSequence {
|
||||
private static final char[] DATA = new char[] { 'a', 'b', 'c' };
|
||||
|
||||
@Override
|
||||
public int length() {
|
||||
return DATA.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public char charAt(int index) {
|
||||
return DATA[index];
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence subSequence(int start, int end) {
|
||||
return new String(Arrays.copyOfRange(DATA, start, end));
|
||||
}
|
||||
}
|
||||
|
||||
private static final MyChars MYCHARS = new MyChars();
|
||||
|
||||
public void sanity() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
// prime the StringBuilder
|
||||
sb.append("repeat");
|
||||
|
||||
// single character Latin1
|
||||
sb.repeat('1', 0);
|
||||
sb.repeat('2', 1);
|
||||
sb.repeat('3', 5);
|
||||
|
||||
// single string Latin1 (optimized)
|
||||
sb.repeat("1", 0);
|
||||
sb.repeat("2", 1);
|
||||
sb.repeat("3", 5);
|
||||
|
||||
// multi string Latin1
|
||||
sb.repeat("-1", 0);
|
||||
sb.repeat("-2", 1);
|
||||
sb.repeat("-3", 5);
|
||||
|
||||
// single character UTF16
|
||||
sb.repeat('\u2460', 0);
|
||||
sb.repeat('\u2461', 1);
|
||||
sb.repeat('\u2462', 5);
|
||||
|
||||
// single string UTF16 (optimized)
|
||||
sb.repeat("\u2460", 0);
|
||||
sb.repeat("\u2461", 1);
|
||||
sb.repeat("\u2462", 5);
|
||||
|
||||
// multi string UTF16
|
||||
|
||||
sb.repeat("-\u2460", 0);
|
||||
sb.repeat("-\u2461", 1);
|
||||
sb.repeat("-\u2462", 5);
|
||||
|
||||
// CharSequence
|
||||
sb.repeat(MYCHARS, 3);
|
||||
|
||||
// null
|
||||
sb.repeat((String)null, 0);
|
||||
sb.repeat((String)null, 1);
|
||||
sb.repeat((String)null, 5);
|
||||
sb.repeat((CharSequence)null, 0);
|
||||
sb.repeat((CharSequence)null, 1);
|
||||
sb.repeat((CharSequence)null, 5);
|
||||
|
||||
|
||||
String expected = "repeat233333233333-2-3-3-3-3-3\u2461\u2462\u2462\u2462\u2462\u2462\u2461\u2462\u2462\u2462\u2462\u2462-\u2461-\u2462-\u2462-\u2462-\u2462-\u2462abcabcabc" +
|
||||
"nullnullnullnullnullnullnullnullnullnullnullnull";
|
||||
assertEquals(sb.toString(), expected);
|
||||
|
||||
// Codepoints
|
||||
|
||||
sb.setLength(0);
|
||||
|
||||
sb.repeat(0, 0);
|
||||
sb.repeat(0, 1);
|
||||
sb.repeat(0, 5);
|
||||
sb.repeat((int)' ', 0);
|
||||
sb.repeat((int)' ', 1);
|
||||
sb.repeat((int)' ', 5);
|
||||
sb.repeat(0x2460, 0);
|
||||
sb.repeat(0x2461, 1);
|
||||
sb.repeat(0x2462, 5);
|
||||
sb.repeat(0x10FFFF, 0);
|
||||
sb.repeat(0x10FFFF, 1);
|
||||
sb.repeat(0x10FFFF, 5);
|
||||
|
||||
expected = "\u0000\u0000\u0000\u0000\u0000\u0000\u0020\u0020\u0020\u0020\u0020\u0020\u2461\u2462\u2462\u2462\u2462\u2462\udbff\udfff\udbff\udfff\udbff\udfff\udbff\udfff\udbff\udfff\udbff\udfff";
|
||||
assertEquals(sb.toString(), expected);
|
||||
|
||||
}
|
||||
|
||||
public void exceptions() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
try {
|
||||
sb.repeat(' ', Integer.MAX_VALUE);
|
||||
throw new RuntimeException("No OutOfMemoryError thrown");
|
||||
} catch (OutOfMemoryError | IndexOutOfBoundsException ex) {
|
||||
// Okay
|
||||
}
|
||||
|
||||
try {
|
||||
sb.repeat(" ", Integer.MAX_VALUE);
|
||||
throw new RuntimeException("No OutOfMemoryError thrown");
|
||||
} catch (OutOfMemoryError | IndexOutOfBoundsException ex) {
|
||||
// Okay
|
||||
}
|
||||
|
||||
try {
|
||||
sb.repeat(MYCHARS, Integer.MAX_VALUE);
|
||||
throw new RuntimeException("No OutOfMemoryError thrown");
|
||||
} catch (OutOfMemoryError | IndexOutOfBoundsException ex) {
|
||||
// Okay
|
||||
}
|
||||
|
||||
try {
|
||||
sb.repeat(' ', -1);
|
||||
throw new RuntimeException("No IllegalArgumentException thrown");
|
||||
} catch (IllegalArgumentException ex) {
|
||||
// Okay
|
||||
}
|
||||
|
||||
try {
|
||||
sb.repeat("abc", -1);
|
||||
throw new RuntimeException("No IllegalArgumentException thrown");
|
||||
} catch (IllegalArgumentException ex) {
|
||||
// Okay
|
||||
}
|
||||
|
||||
try {
|
||||
sb.repeat(MYCHARS, -1);
|
||||
throw new RuntimeException("No IllegalArgumentException thrown");
|
||||
} catch (IllegalArgumentException ex) {
|
||||
// Okay
|
||||
}
|
||||
|
||||
try {
|
||||
sb.repeat(0x10FFFF + 1, -1);
|
||||
throw new RuntimeException("No IllegalArgumentException thrown");
|
||||
} catch (IllegalArgumentException ex) {
|
||||
// Okay
|
||||
}
|
||||
|
||||
try {
|
||||
sb.repeat(-1, -1);
|
||||
throw new RuntimeException("No IllegalArgumentException thrown");
|
||||
} catch (IllegalArgumentException ex) {
|
||||
// Okay
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
431
test/jdk/java/lang/StringBuilder/Supplementary.java
Normal file
431
test/jdk/java/lang/StringBuilder/Supplementary.java
Normal file
|
|
@ -0,0 +1,431 @@
|
|||
/*
|
||||
* Copyright (c) 2003, 2013, 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
|
||||
* @summary Unit tests for supplementary character support (JSR-204)
|
||||
*/
|
||||
|
||||
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)
|
||||
testDontReadOutOfBoundsTrailingSurrogate();
|
||||
}
|
||||
|
||||
/* 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', 0xD800, 0xDC00, 0x10000, 0xE0200}, // codePointAt(0)
|
||||
{0xD800, 0x10000, 'g', 0xDC00, 0xE0202}, // codePointAt(9)
|
||||
{'f', 0xDC00, 0xD800, 0xDC00, 0xDE02}, // codePointAt(length-1)
|
||||
};
|
||||
|
||||
/*
|
||||
* Test for codePointAt(int index) method
|
||||
*/
|
||||
static void test1() {
|
||||
|
||||
for (int i = 0; i < input.length; i++) {
|
||||
StringBuilder sb = new StringBuilder(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', 0xD800, 0xDC00, 0xD800, 0xDB40}, // codePointBefore(1)
|
||||
{0xD800, 'l', 0x10000, 0xDC00, 0xDB40}, // codePointBefore(13)
|
||||
{'f', 0xDC00, 0xD800, 0x10000, 0xE0202}, // codePointBefore(length)
|
||||
};
|
||||
|
||||
/*
|
||||
* Test for codePointBefore(int index) method
|
||||
*/
|
||||
static void test2() {
|
||||
|
||||
for (int i = 0; i < input.length; i++) {
|
||||
StringBuilder sb = new StringBuilder(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++) {
|
||||
StringBuilder sb = new StringBuilder(input[i]).reverse();
|
||||
|
||||
check(!golden3[i].equals(sb.toString()),
|
||||
"reverse() for <" + toHexString(input[i]) + ">",
|
||||
sb, golden3[i]);
|
||||
}
|
||||
|
||||
for (int i = 0; i < testdata1.length; i++) {
|
||||
StringBuilder sb = new StringBuilder(testdata1[i][0]).reverse();
|
||||
|
||||
check(!testdata1[i][1].equals(sb.toString()),
|
||||
"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];
|
||||
StringBuilder sb = new StringBuilder();
|
||||
int c;
|
||||
for (int j = 0; j < s.length(); j += Character.charCount(c)) {
|
||||
c = s.codePointAt(j);
|
||||
StringBuilder 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];
|
||||
StringBuilder sb = new StringBuilder(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];
|
||||
StringBuilder sb = new StringBuilder(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 void testDontReadOutOfBoundsTrailingSurrogate() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
int suppl = Character.MIN_SUPPLEMENTARY_CODE_POINT;
|
||||
sb.appendCodePoint(suppl);
|
||||
check(sb.codePointAt(0) != (int) suppl,
|
||||
"codePointAt(0)", sb.codePointAt(0), suppl);
|
||||
check(sb.length() != 2, "sb.length()");
|
||||
sb.setLength(1);
|
||||
check(sb.length() != 1, "sb.length()");
|
||||
check(sb.codePointAt(0) != Character.highSurrogate(suppl),
|
||||
"codePointAt(0)",
|
||||
sb.codePointAt(0), Character.highSurrogate(suppl));
|
||||
}
|
||||
|
||||
static final boolean At = true, Before = false;
|
||||
|
||||
static void testCodePoint(boolean isAt, StringBuilder 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, StringBuilder 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 StringBuilder().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(StringBuilder 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(StringBuilder 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, StringBuilder got, String expected) {
|
||||
if (err) {
|
||||
throw new RuntimeException("Error: " + s
|
||||
+ " returned an unexpected value. got <"
|
||||
+ toHexString(got.toString())
|
||||
+ ">, expected <"
|
||||
+ toHexString(expected)
|
||||
+ ">");
|
||||
}
|
||||
}
|
||||
|
||||
private static String toHexString(int c) {
|
||||
return "0x" + Integer.toHexString(c);
|
||||
}
|
||||
|
||||
private static String toHexString(String s) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < s.length(); i++) {
|
||||
char c = s.charAt(i);
|
||||
|
||||
sb.append(" 0x");
|
||||
if (c < 0x10) sb.append('0');
|
||||
if (c < 0x100) sb.append('0');
|
||||
if (c < 0x1000) sb.append('0');
|
||||
sb.append(Integer.toHexString(c));
|
||||
}
|
||||
sb.append(' ');
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue