blob: 8d9814cd697c40420e4093ae0f2a642d85d252f9 [file] [log] [blame]
// © 2017 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html#License
package com.ibm.icu.dev.test.number;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
import java.text.FieldPosition;
import java.text.Format.Field;
import org.junit.Test;
import com.ibm.icu.impl.number.NumberStringBuilder;
import com.ibm.icu.text.NumberFormat;
/** @author sffc */
public class NumberStringBuilderTest {
private static final String[] EXAMPLE_STRINGS = {
"",
"xyz",
"The quick brown fox jumps over the lazy dog",
"😁",
"mixed 😇 and ASCII",
"with combining characters like 🇦🇧🇨🇩",
"A very very very very very very very very very very long string to force heap"
};
@Test
public void testInsertAppendCharSequence() {
StringBuilder sb1 = new StringBuilder();
NumberStringBuilder sb2 = new NumberStringBuilder();
for (String str : EXAMPLE_STRINGS) {
NumberStringBuilder sb3 = new NumberStringBuilder();
sb1.append(str);
sb2.append(str, null);
sb3.append(str, null);
assertCharSequenceEquals(sb1, sb2);
assertCharSequenceEquals(sb3, str);
StringBuilder sb4 = new StringBuilder();
NumberStringBuilder sb5 = new NumberStringBuilder();
sb4.append("😇");
sb4.append(str);
sb4.append("xx");
sb5.append("😇xx", null);
sb5.insert(2, str, null);
assertCharSequenceEquals(sb4, sb5);
int start = Math.min(1, str.length());
int end = Math.min(10, str.length());
sb4.insert(3, str, start, end);
sb5.insert(3, str, start, end, null);
assertCharSequenceEquals(sb4, sb5);
sb4.append(str.toCharArray());
sb5.append(str.toCharArray(), null);
assertCharSequenceEquals(sb4, sb5);
sb4.insert(4, str.toCharArray());
sb5.insert(4, str.toCharArray(), null);
assertCharSequenceEquals(sb4, sb5);
sb4.append(sb4.toString());
sb5.append(new NumberStringBuilder(sb5));
assertCharSequenceEquals(sb4, sb5);
}
}
@Test
public void testInsertAppendCodePoint() {
int[] cases = {0, 1, 60, 127, 128, 0x7fff, 0x8000, 0xffff, 0x10000, 0x1f000, 0x10ffff};
StringBuilder sb1 = new StringBuilder();
NumberStringBuilder sb2 = new NumberStringBuilder();
for (int cas : cases) {
NumberStringBuilder sb3 = new NumberStringBuilder();
sb1.appendCodePoint(cas);
sb2.appendCodePoint(cas, null);
sb3.appendCodePoint(cas, null);
assertCharSequenceEquals(sb1, sb2);
assertEquals(Character.codePointAt(sb3, 0), cas);
StringBuilder sb4 = new StringBuilder();
NumberStringBuilder sb5 = new NumberStringBuilder();
sb4.append("😇");
sb4.appendCodePoint(cas); // Java StringBuilder has no insertCodePoint()
sb4.append("xx");
sb5.append("😇xx", null);
sb5.insertCodePoint(2, cas, null);
assertCharSequenceEquals(sb4, sb5);
}
}
@Test
public void testCopy() {
for (String str : EXAMPLE_STRINGS) {
NumberStringBuilder sb1 = new NumberStringBuilder();
sb1.append(str, null);
NumberStringBuilder sb2 = new NumberStringBuilder(sb1);
assertCharSequenceEquals(sb1, sb2);
assertTrue(sb1.contentEquals(sb2));
sb1.append("12345", null);
assertNotEquals(sb1.length(), sb2.length());
assertFalse(sb1.contentEquals(sb2));
}
}
@Test
public void testFields() {
for (String str : EXAMPLE_STRINGS) {
NumberStringBuilder sb = new NumberStringBuilder();
sb.append(str, null);
sb.append(str, NumberFormat.Field.CURRENCY);
Field[] fields = sb.toFieldArray();
assertEquals(str.length() * 2, fields.length);
for (int i = 0; i < str.length(); i++) {
assertEquals(null, fields[i]);
assertEquals(null, sb.fieldAt(i));
assertEquals(NumberFormat.Field.CURRENCY, fields[i + str.length()]);
assertEquals(NumberFormat.Field.CURRENCY, sb.fieldAt(i + str.length()));
}
// Very basic FieldPosition test. More robust tests happen in NumberFormatTest.
// Let NumberFormatTest also take care of AttributedCharacterIterator material.
FieldPosition fp = new FieldPosition(NumberFormat.Field.CURRENCY);
sb.populateFieldPosition(fp, 0);
assertEquals(str.length(), fp.getBeginIndex());
assertEquals(str.length() * 2, fp.getEndIndex());
if (str.length() > 0) {
sb.insertCodePoint(2, 100, NumberFormat.Field.INTEGER);
fields = sb.toFieldArray();
assertEquals(str.length() * 2 + 1, fields.length);
assertEquals(fields[2], NumberFormat.Field.INTEGER);
}
sb.append(new NumberStringBuilder(sb));
sb.append(sb.toCharArray(), sb.toFieldArray());
int numNull = 0;
int numCurr = 0;
int numInt = 0;
Field[] oldFields = fields;
fields = sb.toFieldArray();
for (int i = 0; i < sb.length(); i++) {
assertEquals(oldFields[i % oldFields.length], fields[i]);
if (fields[i] == null) {
numNull++;
} else if (fields[i] == NumberFormat.Field.CURRENCY) {
numCurr++;
} else if (fields[i] == NumberFormat.Field.INTEGER) {
numInt++;
} else {
throw new AssertionError("Encountered unknown field in " + str);
}
}
assertEquals(str.length() * 4, numNull);
assertEquals(numNull, numCurr);
assertEquals(str.length() > 0 ? 4 : 0, numInt);
NumberStringBuilder sb2 = new NumberStringBuilder();
sb2.append(sb);
assertTrue(sb.contentEquals(sb2));
assertTrue(sb.contentEquals(sb2.toCharArray(), sb2.toFieldArray()));
sb2.insertCodePoint(0, 50, NumberFormat.Field.FRACTION);
assertTrue(!sb.contentEquals(sb2));
assertTrue(!sb.contentEquals(sb2.toCharArray(), sb2.toFieldArray()));
}
}
@Test
public void testUnlimitedCapacity() {
NumberStringBuilder builder = new NumberStringBuilder();
// The builder should never fail upon repeated appends.
for (int i = 0; i < 1000; i++) {
assertEquals(builder.length(), i);
builder.appendCodePoint('x', null);
assertEquals(builder.length(), i + 1);
}
}
@Test
public void testCodePoints() {
NumberStringBuilder nsb = new NumberStringBuilder();
assertEquals("First is -1 on empty string", -1, nsb.getFirstCodePoint());
assertEquals("Last is -1 on empty string", -1, nsb.getLastCodePoint());
assertEquals("Length is 0 on empty string", 0, nsb.codePointCount());
nsb.append("q", null);
assertEquals("First is q", 'q', nsb.getFirstCodePoint());
assertEquals("Last is q", 'q', nsb.getLastCodePoint());
assertEquals("0th is q", 'q', nsb.codePointAt(0));
assertEquals("Before 1st is q", 'q', nsb.codePointBefore(1));
assertEquals("Code point count is 1", 1, nsb.codePointCount());
// 🚀 is two char16s
nsb.append("🚀", null);
assertEquals("First is still q", 'q', nsb.getFirstCodePoint());
assertEquals("Last is space ship", 128640, nsb.getLastCodePoint());
assertEquals("1st is space ship", 128640, nsb.codePointAt(1));
assertEquals("Before 1st is q", 'q', nsb.codePointBefore(1));
assertEquals("Before 3rd is space ship", 128640, nsb.codePointBefore(3));
assertEquals("Code point count is 2", 2, nsb.codePointCount());
}
private static void assertCharSequenceEquals(CharSequence a, CharSequence b) {
assertEquals(a.toString(), b.toString());
assertEquals(a.length(), b.length());
for (int i = 0; i < a.length(); i++) {
assertEquals(a.charAt(i), b.charAt(i));
}
int start = Math.min(2, a.length());
int end = Math.min(12, a.length());
if (start != end) {
assertCharSequenceEquals(a.subSequence(start, end), b.subSequence(start, end));
}
}
}