/**
* Copyright (c) 2000-present Liferay, Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1 of the License, or (at your option)
* any later version.
*
* This library 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 Lesser General Public License for more
* details.
*/
package com.liferay.portal.kernel.util;
import com.liferay.portal.kernel.io.unsync.UnsyncByteArrayInputStream;
import com.liferay.portal.kernel.io.unsync.UnsyncByteArrayOutputStream;
import com.liferay.portal.kernel.test.ReflectionTestUtil;
import com.liferay.portal.kernel.test.rule.AggregateTestRule;
import com.liferay.portal.kernel.test.rule.CodeCoverageAssertor;
import com.liferay.portal.kernel.test.rule.NewEnv;
import com.liferay.portal.kernel.test.rule.NewEnvTestRule;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.StringWriter;
import java.lang.reflect.Field;
import org.junit.Assert;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
/**
* @author Shuyang Zhou
* @author Manuel de la Peña
*/
public class StringBundlerTest {
@ClassRule
@Rule
public static final AggregateTestRule aggregateTestRule =
new AggregateTestRule(
CodeCoverageAssertor.INSTANCE, NewEnvTestRule.INSTANCE);
@Test
public void testAppendBoolean() {
StringBundler sb = new StringBundler();
Assert.assertEquals(0, sb.length());
sb.append(true);
Assert.assertEquals(4, sb.length());
Assert.assertEquals("true", sb.toString());
sb.append(false);
Assert.assertEquals(9, sb.length());
Assert.assertEquals("truefalse", sb.toString());
assertArray(sb, "true", "false");
}
@Test
public void testAppendChar() {
StringBundler sb = new StringBundler();
Assert.assertEquals(0, sb.length());
sb.append('a');
Assert.assertEquals(1, sb.length());
Assert.assertEquals("a", sb.toString());
sb.append('b');
Assert.assertEquals(2, sb.length());
Assert.assertEquals("ab", sb.toString());
sb.append('c');
Assert.assertEquals(3, sb.length());
Assert.assertEquals("abc", sb.toString());
assertArray(sb, "a", "b", "c");
}
@Test
public void testAppendCharArray() {
StringBundler sb = new StringBundler();
Assert.assertEquals(0, sb.length());
sb.append(new char[] {'a', 'b'});
Assert.assertEquals(2, sb.length());
Assert.assertEquals("ab", sb.toString());
sb.append(new char[] {'c', 'd'});
Assert.assertEquals(4, sb.length());
Assert.assertEquals("abcd", sb.toString());
sb.append(new char[] {'e', 'f'});
Assert.assertEquals(6, sb.length());
Assert.assertEquals("abcdef", sb.toString());
assertArray(sb, "ab", "cd", "ef");
}
@Test
public void testAppendDouble() {
StringBundler sb = new StringBundler();
Assert.assertEquals(0, sb.length());
sb.append(1.0D);
Assert.assertEquals(3, sb.length());
Assert.assertEquals("1.0", sb.toString());
sb.append(2.1D);
Assert.assertEquals(6, sb.length());
Assert.assertEquals("1.02.1", sb.toString());
sb.append(3.2D);
Assert.assertEquals(9, sb.length());
Assert.assertEquals("1.02.13.2", sb.toString());
assertArray(sb, "1.0", "2.1", "3.2");
}
@Test
public void testAppendEmptyStringBundler() {
StringBundler sb = new StringBundler();
sb.append(new StringBundler());
Assert.assertEquals(0, sb.index());
}
@Test
public void testAppendFloat() {
StringBundler sb = new StringBundler();
Assert.assertEquals(0, sb.length());
sb.append(1.0F);
Assert.assertEquals(3, sb.length());
Assert.assertEquals("1.0", sb.toString());
sb.append(2.1F);
Assert.assertEquals(6, sb.length());
Assert.assertEquals("1.02.1", sb.toString());
sb.append(3.2F);
Assert.assertEquals(9, sb.length());
Assert.assertEquals("1.02.13.2", sb.toString());
assertArray(sb, "1.0", "2.1", "3.2");
}
@Test
public void testAppendInt() {
StringBundler sb = new StringBundler();
Assert.assertEquals(0, sb.length());
sb.append(1);
Assert.assertEquals(1, sb.length());
Assert.assertEquals("1", sb.toString());
sb.append(2);
Assert.assertEquals(2, sb.length());
Assert.assertEquals("12", sb.toString());
sb.append(3);
Assert.assertEquals(3, sb.length());
Assert.assertEquals("123", sb.toString());
assertArray(sb, "1", "2", "3");
}
@Test
public void testAppendLong() {
StringBundler sb = new StringBundler();
Assert.assertEquals(0, sb.length());
sb.append(1L);
Assert.assertEquals(1, sb.length());
Assert.assertEquals("1", sb.toString());
sb.append(2L);
Assert.assertEquals(2, sb.length());
Assert.assertEquals("12", sb.toString());
sb.append(3L);
Assert.assertEquals(3, sb.length());
Assert.assertEquals("123", sb.toString());
assertArray(sb, "1", "2", "3");
}
@Test
public void testAppendNullCharArray() {
StringBundler sb = new StringBundler();
sb.append((char[])null);
Assert.assertEquals(1, sb.index());
Assert.assertEquals("null", sb.stringAt(0));
}
@Test
public void testAppendNullObject() {
StringBundler sb = new StringBundler();
sb.append((Object)null);
Assert.assertEquals(1, sb.index());
Assert.assertEquals("null", sb.stringAt(0));
}
@Test
public void testAppendNullString() {
StringBundler sb = new StringBundler();
sb.append((String)null);
Assert.assertEquals(1, sb.index());
Assert.assertEquals(StringPool.NULL, sb.stringAt(0));
}
@Test
public void testAppendNullStringArray() {
StringBundler sb = new StringBundler();
sb.append((String[])null);
Assert.assertEquals(0, sb.index());
}
@Test
public void testAppendNullStringBundler() {
StringBundler sb = new StringBundler();
sb.append((StringBundler)null);
Assert.assertEquals(0, sb.index());
}
@Test
public void testAppendStringArrayWithGrowth() {
StringBundler sb = new StringBundler(2);
sb.append(new String[] {"test1", "test2", "test3"});
Assert.assertEquals(3, sb.index());
Assert.assertEquals(10, sb.capacity());
Assert.assertEquals("test1", sb.stringAt(0));
Assert.assertEquals("test2", sb.stringAt(1));
Assert.assertEquals("test3", sb.stringAt(2));
sb = new StringBundler(2);
sb.append(new String[] {"test1", "", "test3"});
Assert.assertEquals(2, sb.index());
Assert.assertEquals(10, sb.capacity());
Assert.assertEquals("test1", sb.stringAt(0));
Assert.assertEquals("test3", sb.stringAt(1));
sb = new StringBundler(2);
sb.append(new String[] {"test1", "test2", null});
Assert.assertEquals(2, sb.index());
Assert.assertEquals(10, sb.capacity());
Assert.assertEquals("test1", sb.stringAt(0));
Assert.assertEquals("test2", sb.stringAt(1));
}
@Test
public void testAppendStringArrayWithoutGrowth() {
StringBundler sb = new StringBundler();
sb.append(new String[] {"test1", "test2", "test3"});
Assert.assertEquals(3, sb.index());
Assert.assertEquals(16, sb.capacity());
Assert.assertEquals("test1", sb.stringAt(0));
Assert.assertEquals("test2", sb.stringAt(1));
Assert.assertEquals("test3", sb.stringAt(2));
sb = new StringBundler();
sb.append(new String[] {"test1", "", "test3"});
Assert.assertEquals(2, sb.index());
Assert.assertEquals(16, sb.capacity());
Assert.assertEquals("test1", sb.stringAt(0));
Assert.assertEquals("test3", sb.stringAt(1));
sb = new StringBundler();
sb.append(new String[] {"test1", "test2", null});
Assert.assertEquals(2, sb.index());
Assert.assertEquals(16, sb.capacity());
Assert.assertEquals("test1", sb.stringAt(0));
Assert.assertEquals("test2", sb.stringAt(1));
}
@Test
public void testAppendStringBundlerWithGrowth() {
StringBundler sb = new StringBundler(2);
StringBundler testSB = new StringBundler();
testSB.append("test1");
testSB.append("test2");
testSB.append("test3");
sb.append(testSB);
Assert.assertEquals(3, sb.index());
Assert.assertEquals(10, sb.capacity());
Assert.assertEquals("test3", sb.stringAt(2));
}
@Test
public void testAppendStringBundlerWithoutGrowth() {
StringBundler sb = new StringBundler();
StringBundler testSB = new StringBundler();
testSB.append("test1");
testSB.append("test2");
testSB.append("test3");
sb.append(testSB);
Assert.assertEquals(3, sb.index());
Assert.assertEquals(16, sb.capacity());
Assert.assertEquals("test3", sb.stringAt(2));
}
@Test
public void testAppendStringWithGrowth() {
StringBundler sb = new StringBundler(2);
sb.append("test1");
Assert.assertEquals(1, sb.index());
Assert.assertEquals(2, sb.capacity());
Assert.assertEquals("test1", sb.stringAt(0));
sb.append("test2");
Assert.assertEquals(2, sb.index());
Assert.assertEquals(2, sb.capacity());
Assert.assertEquals("test1", sb.stringAt(0));
Assert.assertEquals("test2", sb.stringAt(1));
sb.append("test3");
Assert.assertEquals(3, sb.index());
Assert.assertEquals(4, sb.capacity());
Assert.assertEquals("test1", sb.stringAt(0));
Assert.assertEquals("test2", sb.stringAt(1));
Assert.assertEquals("test3", sb.stringAt(2));
}
@Test
public void testAppendStringWithoutGrowing() {
StringBundler sb = new StringBundler();
sb.append("test1");
Assert.assertEquals(1, sb.index());
Assert.assertEquals(16, sb.capacity());
Assert.assertEquals("test1", sb.stringAt(0));
sb.append("test2");
Assert.assertEquals(2, sb.index());
Assert.assertEquals(16, sb.capacity());
Assert.assertEquals("test1", sb.stringAt(0));
Assert.assertEquals("test2", sb.stringAt(1));
sb.append("test3");
Assert.assertEquals(3, sb.index());
Assert.assertEquals(16, sb.capacity());
Assert.assertEquals("test1", sb.stringAt(0));
Assert.assertEquals("test2", sb.stringAt(1));
Assert.assertEquals("test3", sb.stringAt(2));
}
@Test
public void testConstructor() {
StringBundler sb = new StringBundler();
Assert.assertEquals(0, sb.index());
Assert.assertEquals(16, sb.capacity());
}
@Test
public void testConstructorWithCapacity() {
StringBundler sb = new StringBundler(32);
Assert.assertEquals(0, sb.index());
Assert.assertEquals(32, sb.capacity());
sb = new StringBundler(0);
Assert.assertEquals(0, sb.index());
Assert.assertEquals(16, sb.capacity());
}
@Test
public void testConstructorWithString() {
StringBundler sb = new StringBundler("test");
Assert.assertEquals(1, sb.index());
Assert.assertEquals("test", sb.stringAt(0));
Assert.assertEquals(16, sb.capacity());
}
@Test
public void testConstructorWithStringArray() {
StringBundler sb = new StringBundler(new String[] {"aa", "bb"});
Assert.assertEquals(2, sb.index());
Assert.assertEquals("aa", sb.stringAt(0));
Assert.assertEquals("bb", sb.stringAt(1));
Assert.assertEquals(2, sb.capacity());
}
@Test
public void testConstructorWithStringArrayEmpty() {
StringBundler sb = new StringBundler(new String[] {"", "bb"});
Assert.assertEquals(1, sb.index());
Assert.assertEquals("bb", sb.stringAt(0));
Assert.assertEquals(2, sb.capacity());
}
@Test
public void testConstructorWithStringArrayExtraSpace() {
StringBundler sb = new StringBundler(new String[] {"aa", "bb"}, 3);
Assert.assertEquals(2, sb.index());
Assert.assertEquals("aa", sb.stringAt(0));
Assert.assertEquals("bb", sb.stringAt(1));
Assert.assertEquals(5, sb.capacity());
}
@Test
public void testConstructorWithStringArrayExtraSpaceEmpty() {
StringBundler sb = new StringBundler(new String[] {"", "bb"}, 3);
Assert.assertEquals(1, sb.index());
Assert.assertEquals("bb", sb.stringAt(0));
Assert.assertEquals(5, sb.capacity());
}
@Test
public void testConstructorWithStringArrayExtraSpaceNull() {
StringBundler sb = new StringBundler(new String[] {"aa", null}, 3);
Assert.assertEquals(1, sb.index());
Assert.assertEquals("aa", sb.stringAt(0));
Assert.assertEquals(5, sb.capacity());
}
@Test
public void testConstructorWithStringArrayNull() {
StringBundler sb = new StringBundler(new String[] {"aa", null});
Assert.assertEquals(1, sb.index());
Assert.assertEquals("aa", sb.stringAt(0));
Assert.assertEquals(2, sb.capacity());
}
@Test
public void testEmptyString() {
StringBundler sb = new StringBundler();
sb.append(StringPool.BLANK);
Assert.assertEquals(0, sb.index());
}
@Test
public void testSerialization() throws Exception {
StringBundler sb = new StringBundler();
sb.append("test1");
sb.append("test2");
sb.append("test3");
UnsyncByteArrayOutputStream unsyncByteArrayOutputStream =
new UnsyncByteArrayOutputStream();
try (ObjectOutputStream objectOutputStream = new ObjectOutputStream(
unsyncByteArrayOutputStream)) {
objectOutputStream.writeObject(sb);
}
byte[] bytes = unsyncByteArrayOutputStream.toByteArray();
UnsyncByteArrayInputStream unsyncByteArrayInputStream =
new UnsyncByteArrayInputStream(bytes);
StringBundler cloneSB = null;
try (ObjectInputStream objectInputStream = new ObjectInputStream(
unsyncByteArrayInputStream)) {
cloneSB = (StringBundler)objectInputStream.readObject();
}
Assert.assertEquals(sb.capacity(), cloneSB.capacity());
Assert.assertEquals(sb.index(), cloneSB.index());
for (int i = 0; i < sb.index(); i++) {
Assert.assertEquals(sb.stringAt(i), cloneSB.stringAt(i));
}
}
@Test
public void testSetIndex() {
// Negative index
StringBundler sb = new StringBundler();
try {
sb.setIndex(-1);
Assert.fail();
}
catch (ArrayIndexOutOfBoundsException aioobe) {
}
// New index equals current index
sb = new StringBundler(4);
sb.append("test1");
sb.append("test2");
Assert.assertEquals(2, sb.index());
Assert.assertEquals("test1", sb.stringAt(0));
Assert.assertEquals("test2", sb.stringAt(1));
sb.setIndex(2);
Assert.assertEquals(2, sb.index());
Assert.assertEquals("test1", sb.stringAt(0));
Assert.assertEquals("test2", sb.stringAt(1));
// New index is larger than the current index but smaller than the array
// size
Assert.assertEquals(4, sb.capacity());
sb.setIndex(4);
Assert.assertEquals(4, sb.capacity());
Assert.assertEquals(4, sb.index());
Assert.assertEquals("test1", sb.stringAt(0));
Assert.assertEquals("test2", sb.stringAt(1));
Assert.assertEquals(StringPool.BLANK, sb.stringAt(2));
Assert.assertEquals(StringPool.BLANK, sb.stringAt(3));
// New index is larger than the current index and array size
sb.setIndex(6);
Assert.assertEquals(6, sb.capacity());
Assert.assertEquals(6, sb.index());
Assert.assertEquals("test1", sb.stringAt(0));
Assert.assertEquals("test2", sb.stringAt(1));
Assert.assertEquals(StringPool.BLANK, sb.stringAt(2));
Assert.assertEquals(StringPool.BLANK, sb.stringAt(3));
Assert.assertEquals(StringPool.BLANK, sb.stringAt(4));
Assert.assertEquals(StringPool.BLANK, sb.stringAt(5));
// New index is smaller than current index
sb.setIndex(1);
Assert.assertEquals(6, sb.capacity());
Assert.assertEquals(1, sb.index());
Assert.assertEquals("test1", sb.stringAt(0));
try {
Assert.assertEquals(null, sb.stringAt(1));
Assert.fail();
}
catch (ArrayIndexOutOfBoundsException aioobe) {
}
}
@Test
public void testSetStringAtAndStringAt() {
StringBundler sb = new StringBundler();
try {
sb.setStringAt(null, -1);
Assert.fail();
}
catch (ArrayIndexOutOfBoundsException aioobe) {
Assert.assertEquals(
"Array index out of range: -1", aioobe.getMessage());
}
try {
sb.setStringAt(null, 0);
Assert.fail();
}
catch (ArrayIndexOutOfBoundsException aioobe) {
Assert.assertEquals(
"Array index out of range: 0", aioobe.getMessage());
}
try {
sb.stringAt(-1);
Assert.fail();
}
catch (ArrayIndexOutOfBoundsException aioobe) {
Assert.assertEquals(
"Array index out of range: -1", aioobe.getMessage());
}
try {
sb.stringAt(0);
Assert.fail();
}
catch (ArrayIndexOutOfBoundsException aioobe) {
Assert.assertEquals(
"Array index out of range: 0", aioobe.getMessage());
}
sb.append("test1");
Assert.assertEquals("test1", sb.stringAt(0));
sb.setStringAt("test2", 0);
Assert.assertEquals("test2", sb.stringAt(0));
}
@Test
public void testToString() {
StringBundler sb = new StringBundler();
sb.append("test1");
sb.append("test2");
sb.append("test3");
Assert.assertEquals("test1test2test3", sb.toString());
// StringBuilder
sb.append("test4");
Assert.assertEquals("test1test2test3test4", sb.toString());
}
@Test
public void testToStringEmpty() {
StringBundler sb = new StringBundler();
Assert.assertEquals(StringPool.BLANK, sb.toString());
}
@NewEnv(type = NewEnv.Type.CLASSLOADER)
@Test
public void testToStringWithoutThreadLocalBufferMaxValueLimit() {
String propertyKey =
StringBundler.class.getName() + ".threadlocal.buffer.limit";
String propertyValue = System.getProperty(propertyKey);
System.setProperty(propertyKey, String.valueOf(Integer.MAX_VALUE));
testToStringWithoutThreadLocalBuffer(propertyKey, propertyValue);
}
@NewEnv(type = NewEnv.Type.CLASSLOADER)
@Test
public void testToStringWithoutThreadLocalBufferNoSetting() {
String propertyKey =
StringBundler.class.getName() + ".threadlocal.buffer.limit";
String propertyValue = System.getProperty(propertyKey);
System.clearProperty(propertyKey);
testToStringWithoutThreadLocalBuffer(propertyKey, propertyValue);
}
@NewEnv(type = NewEnv.Type.CLASSLOADER)
@Test
public void testToStringWithoutThreadLocalBufferZeroLimit() {
String propertyKey =
StringBundler.class.getName() + ".threadlocal.buffer.limit";
String propertyValue = System.getProperty(propertyKey);
System.setProperty(propertyKey, "0");
testToStringWithoutThreadLocalBuffer(propertyKey, propertyValue);
}
@NewEnv(type = NewEnv.Type.CLASSLOADER)
@Test
public void testToStringWithThreadLocalBuffer() throws Exception {
int threadLocalBufferLimit = 3;
String propertyKey =
StringBundler.class.getName() + ".threadlocal.buffer.limit";
String propertyValue = System.getProperty(propertyKey);
System.setProperty(propertyKey, String.valueOf(threadLocalBufferLimit));
try {
Assert.assertEquals(
Integer.valueOf(threadLocalBufferLimit),
ReflectionTestUtil.getFieldValue(
StringBundler.class, "_THREAD_LOCAL_BUFFER_LIMIT"));
ThreadLocal<Object> threadLocal = ReflectionTestUtil.getFieldValue(
StringBundler.class, "_unsafeStringBuilderThreadLocal");
Assert.assertNotNull(threadLocal);
threadLocal.remove();
StringBundler sb = new StringBundler();
sb.append("1");
sb.append("2");
sb.append("3");
sb.append("4");
Assert.assertEquals("1234", sb.toString());
Object unsafeStringBuilder = threadLocal.get();
Field countField = ReflectionTestUtil.getField(
unsafeStringBuilder.getClass(), "_count");
Assert.assertNotNull(unsafeStringBuilder);
Assert.assertEquals(4, countField.get(unsafeStringBuilder));
sb.append("5");
Assert.assertEquals("12345", sb.toString());
Assert.assertSame(unsafeStringBuilder, threadLocal.get());
Assert.assertEquals(5, countField.get(unsafeStringBuilder));
sb.append("6");
Assert.assertEquals("123456", sb.toString());
Assert.assertSame(unsafeStringBuilder, threadLocal.get());
Assert.assertEquals(6, countField.get(unsafeStringBuilder));
}
finally {
if (propertyValue == null) {
System.clearProperty(propertyKey);
}
else {
System.setProperty(propertyKey, propertyValue);
}
}
}
@NewEnv(type = NewEnv.Type.CLASSLOADER)
@Test
public void testUnsafeStringBuilderEnsureCapacity() {
int threadLocalBufferLimit = 10;
String propertyKey =
StringBundler.class.getName() + ".threadlocal.buffer.limit";
String propertyValue = System.getProperty(propertyKey);
System.setProperty(propertyKey, String.valueOf(threadLocalBufferLimit));
try {
Assert.assertEquals(
Integer.valueOf(threadLocalBufferLimit),
ReflectionTestUtil.getFieldValue(
StringBundler.class, "_THREAD_LOCAL_BUFFER_LIMIT"));
StringBundler sb = new StringBundler(4);
sb.append("test1");
sb.append("test2");
sb.append("test3");
Assert.assertEquals("test1test2test3", sb.toString());
sb.append("test4");
Assert.assertEquals("test1test2test3test4", sb.toString());
sb.setIndex(sb.index() - 1);
Assert.assertEquals("test1test2test3", sb.toString());
sb.append("test4test5test6test7test8test9test10");
Assert.assertEquals(
"test1test2test3test4test5test6test7test8test9test10",
sb.toString());
}
finally {
if (propertyValue == null) {
System.clearProperty(propertyKey);
}
else {
System.setProperty(propertyKey, propertyValue);
}
}
}
@Test
public void testWriteTo() throws IOException {
StringBundler sb = new StringBundler();
sb.append("test1");
sb.append("test2");
sb.append("test3");
sb.append("test4");
sb.append("test5");
StringWriter stringWriter = new StringWriter();
sb.writeTo(stringWriter);
Assert.assertEquals(
"test1test2test3test4test5", stringWriter.toString());
}
protected void assertArray(StringBundler sb, String... prefix) {
String[] strings = sb.getStrings();
for (int i = 0; i < prefix.length; i++) {
Assert.assertEquals(prefix[i], strings[i]);
}
for (int i = prefix.length; i < strings.length; i++) {
Assert.assertNull(strings[i]);
}
}
protected void testToStringWithoutThreadLocalBuffer(
String propertyKey, String propertyValue) {
try {
Assert.assertEquals(
Integer.valueOf(Integer.MAX_VALUE),
ReflectionTestUtil.getFieldValue(
StringBundler.class, "_THREAD_LOCAL_BUFFER_LIMIT"));
Assert.assertNull(
ReflectionTestUtil.getFieldValue(
StringBundler.class, "_unsafeStringBuilderThreadLocal"));
StringBundler sb = new StringBundler();
sb.append("1");
sb.append("2");
sb.append("3");
sb.append("4");
Assert.assertEquals("1234", sb.toString());
Assert.assertNull(
ReflectionTestUtil.getFieldValue(
StringBundler.class, "_unsafeStringBuilderThreadLocal"));
}
finally {
if (propertyValue != null) {
System.setProperty(propertyKey, propertyValue);
}
}
}
}