blob: e778170b167f43830f7f360225c5937196d1fa40 [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.fail;
import org.junit.Test;
import com.ibm.icu.impl.FormattedStringBuilder;
import com.ibm.icu.impl.number.AffixUtils;
import com.ibm.icu.impl.number.AffixUtils.SymbolProvider;
import com.ibm.icu.text.UnicodeSet;
public class AffixUtilsTest {
private static final SymbolProvider DEFAULT_SYMBOL_PROVIDER = new SymbolProvider() {
@Override
public CharSequence getSymbol(int type) {
// Use interesting symbols where possible. The symbols are from ar_SA but are hard-coded
// here to make the test independent of locale data changes.
switch (type) {
case AffixUtils.TYPE_MINUS_SIGN:
return "−";
case AffixUtils.TYPE_PLUS_SIGN:
return "\u061C+";
case AffixUtils.TYPE_PERCENT:
return "٪\u061C";
case AffixUtils.TYPE_PERMILLE:
return "؉";
case AffixUtils.TYPE_CURRENCY_SINGLE:
return "$";
case AffixUtils.TYPE_CURRENCY_DOUBLE:
return "XXX";
case AffixUtils.TYPE_CURRENCY_TRIPLE:
return "long name";
case AffixUtils.TYPE_CURRENCY_QUAD:
return "\uFFFD";
case AffixUtils.TYPE_CURRENCY_QUINT:
return "@";
case AffixUtils.TYPE_CURRENCY_OVERFLOW:
return "\uFFFD";
default:
throw new AssertionError();
}
}
};
@Test
public void testEscape() {
Object[][] cases = {
{ "", "" },
{ "abc", "abc" },
{ "-", "'-'" },
{ "-!", "'-'!" },
{ "−", "−" },
{ "---", "'---'" },
{ "-%-", "'-%-'" },
{ "'", "''" },
{ "-'", "'-'''" },
{ "-'-", "'-''-'" },
{ "a-'-", "a'-''-'" } };
StringBuilder sb = new StringBuilder();
for (Object[] cas : cases) {
String input = (String) cas[0];
String expected = (String) cas[1];
sb.setLength(0);
AffixUtils.escape(input, sb);
assertEquals(expected, sb.toString());
}
}
@Test
public void testUnescape() {
Object[][] cases = {
{ "", false, 0, "" },
{ "abc", false, 3, "abc" },
{ "📺", false, 1, "📺" },
{ "-", false, 1, "−" },
{ "-!", false, 2, "−!" },
{ "+", false, 1, "\u061C+" },
{ "+!", false, 2, "\u061C+!" },
{ "‰", false, 1, "؉" },
{ "‰!", false, 2, "؉!" },
{ "-x", false, 2, "−x" },
{ "'-'x", false, 2, "-x" },
{ "'--''-'-x", false, 6, "--'-−x" },
{ "''", false, 1, "'" },
{ "''''", false, 2, "''" },
{ "''''''", false, 3, "'''" },
{ "''x''", false, 3, "'x'" },
{ "¤", true, 1, "$" },
{ "¤¤", true, 2, "XXX" },
{ "¤¤¤", true, 3, "long name" },
{ "¤¤¤¤", true, 4, "\uFFFD" },
{ "¤¤¤¤¤", true, 5, "@" },
{ "¤¤¤¤¤¤", true, 6, "\uFFFD" },
{ "¤¤¤a¤¤¤¤", true, 8, "long namea\uFFFD" },
{ "a¤¤¤¤b¤¤¤¤¤c", true, 12, "a\uFFFDb@c" },
{ "¤!", true, 2, "$!" },
{ "¤¤!", true, 3, "XXX!" },
{ "¤¤¤!", true, 4, "long name!" },
{ "-¤¤", true, 3, "−XXX" },
{ "¤¤-", true, 3, "XXX−" },
{ "'¤'", false, 1, "¤" },
{ "%", false, 1, "٪\u061C" },
{ "'%'", false, 1, "%" },
{ "¤'-'%", true, 3, "$-٪\u061C" },
{ "#0#@#*#;#", false, 9, "#0#@#*#;#" } };
for (Object[] cas : cases) {
String input = (String) cas[0];
boolean curr = (Boolean) cas[1];
int length = (Integer) cas[2];
String output = (String) cas[3];
assertEquals("Currency on <" + input + ">", curr, AffixUtils.hasCurrencySymbols(input));
assertEquals("Length on <" + input + ">", length, AffixUtils.estimateLength(input));
String actual = unescapeWithDefaults(input);
assertEquals("Output on <" + input + ">", output, actual);
int ulength = AffixUtils.unescapedCount(input, true, DEFAULT_SYMBOL_PROVIDER);
assertEquals("Unescaped length on <" + input + ">", output.length(), ulength);
int ucpcount = AffixUtils.unescapedCount(input, false, DEFAULT_SYMBOL_PROVIDER);
assertEquals("Unescaped length on <" + input + ">",
output.codePointCount(0, output.length()),
ucpcount);
}
}
@Test
public void testContainsReplaceType() {
Object[][] cases = {
{ "", false, "" },
{ "-", true, "+" },
{ "-a", true, "+a" },
{ "a-", true, "a+" },
{ "a-b", true, "a+b" },
{ "--", true, "++" },
{ "x", false, "x" } };
for (Object[] cas : cases) {
String input = (String) cas[0];
boolean hasMinusSign = (Boolean) cas[1];
String output = (String) cas[2];
assertEquals("Contains on input " + input,
hasMinusSign,
AffixUtils.containsType(input, AffixUtils.TYPE_MINUS_SIGN));
assertEquals("Replace on input" + input,
output,
AffixUtils.replaceType(input, AffixUtils.TYPE_MINUS_SIGN, '+'));
}
}
@Test
public void testInvalid() {
String[] invalidExamples = { "'", "x'", "'x", "'x''", "''x'" };
for (String str : invalidExamples) {
try {
AffixUtils.hasCurrencySymbols(str);
fail("No exception was thrown on an invalid string");
} catch (IllegalArgumentException e) {
// OK
}
try {
AffixUtils.estimateLength(str);
fail("No exception was thrown on an invalid string");
} catch (IllegalArgumentException e) {
// OK
}
try {
unescapeWithDefaults(str);
fail("No exception was thrown on an invalid string");
} catch (IllegalArgumentException e) {
// OK
}
}
}
@Test
public void testUnescapeWithSymbolProvider() {
String[][] cases = {
{ "", "" },
{ "-", "1" },
{ "'-'", "-" },
{ "- + % ‰ ¤ ¤¤ ¤¤¤ ¤¤¤¤ ¤¤¤¤¤", "1 2 3 4 5 6 7 8 9" },
{ "'¤¤¤¤¤¤'", "¤¤¤¤¤¤" },
{ "¤¤¤¤¤¤", "\uFFFD" } };
SymbolProvider provider = new SymbolProvider() {
@Override
public CharSequence getSymbol(int type) {
return Integer.toString(Math.abs(type));
}
};
FormattedStringBuilder sb = new FormattedStringBuilder();
for (String[] cas : cases) {
String input = cas[0];
String expected = cas[1];
sb.clear();
AffixUtils.unescape(input, sb, 0, provider, null);
assertEquals("With symbol provider on <" + input + ">", expected, sb.toString());
}
// Test insertion position
sb.clear();
sb.append("abcdefg", null);
AffixUtils.unescape("-+%", sb, 4, provider, null);
assertEquals("Symbol provider into middle", "abcd123efg", sb.toString());
}
@Test
public void testWithoutSymbolsOrIgnorables() {
Object[][] cases = {
{ "", true },
{ "-", true },
{ " ", true },
{ "'-'", false },
{ " a + b ", false },
{ "-a+b%c‰d¤e¤¤f¤¤¤g¤¤¤¤h¤¤¤¤¤i", false }, };
UnicodeSet ignorables = new UnicodeSet("[:whitespace:]");
for (Object[] cas : cases) {
String input = (String) cas[0];
boolean expected = (Boolean) cas[1];
assertEquals("Contains only symbols and ignorables: " + input,
expected,
AffixUtils.containsOnlySymbolsAndIgnorables(input, ignorables));
}
}
private static String unescapeWithDefaults(String input) {
FormattedStringBuilder nsb = new FormattedStringBuilder();
int length = AffixUtils.unescape(input, nsb, 0, DEFAULT_SYMBOL_PROVIDER, null);
assertEquals("Return value of unescape", nsb.length(), length);
return nsb.toString();
}
}