blob: fe77028a44f59c3ec0e76ff4544a0184bc08c237 [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.number.AffixUtils;
import com.ibm.icu.impl.number.AffixUtils.SymbolProvider;
import com.ibm.icu.impl.number.NumberStringBuilder;
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, 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.unescapedCodePointCount(input, DEFAULT_SYMBOL_PROVIDER);
assertEquals("Unescaped length on <" + input + ">", output.length(), ulength);
}
}
@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));
}
};
NumberStringBuilder sb = new NumberStringBuilder();
for (String[] cas : cases) {
String input = cas[0];
String expected = cas[1];
sb.clear();
AffixUtils.unescape(input, sb, 0, provider);
assertEquals("With symbol provider on <" + input + ">", expected, sb.toString());
}
// Test insertion position
sb.clear();
sb.append("abcdefg", null);
AffixUtils.unescape("-+%", sb, 4, provider);
assertEquals("Symbol provider into middle", "abcd123efg", sb.toString());
}
private static String unescapeWithDefaults(String input) {
NumberStringBuilder nsb = new NumberStringBuilder();
int length = AffixUtils.unescape(input, nsb, 0, DEFAULT_SYMBOL_PROVIDER);
assertEquals("Return value of unescape", nsb.length(), length);
return nsb.toString();
}
}