OLD | NEW |
1 // © 2017 and later: Unicode, Inc. and others. | 1 // © 2017 and later: Unicode, Inc. and others. |
2 // License & terms of use: http://www.unicode.org/copyright.html#License | 2 // License & terms of use: http://www.unicode.org/copyright.html#License |
3 package com.ibm.icu.dev.test.number; | 3 package com.ibm.icu.dev.test.number; |
4 | 4 |
5 import static org.junit.Assert.assertEquals; | 5 import static org.junit.Assert.assertEquals; |
6 import static org.junit.Assert.fail; | 6 import static org.junit.Assert.fail; |
7 | 7 |
8 import org.junit.Test; | 8 import org.junit.Test; |
9 | 9 |
10 import com.ibm.icu.impl.number.AffixUtils; | 10 import com.ibm.icu.impl.number.AffixUtils; |
11 import com.ibm.icu.impl.number.AffixUtils.SymbolProvider; | 11 import com.ibm.icu.impl.number.AffixUtils.SymbolProvider; |
12 import com.ibm.icu.impl.number.NumberStringBuilder; | 12 import com.ibm.icu.impl.number.NumberStringBuilder; |
| 13 import com.ibm.icu.text.UnicodeSet; |
13 | 14 |
14 public class AffixUtilsTest { | 15 public class AffixUtilsTest { |
15 | 16 |
16 private static final SymbolProvider DEFAULT_SYMBOL_PROVIDER = | 17 private static final SymbolProvider DEFAULT_SYMBOL_PROVIDER = new SymbolProv
ider() { |
17 new SymbolProvider() { | 18 @Override |
18 @Override | 19 public CharSequence getSymbol(int type) { |
19 public CharSequence getSymbol(int type) { | |
20 // Use interesting symbols where possible. The symbols are from ar_S
A but are hard-coded | 20 // Use interesting symbols where possible. The symbols are from ar_S
A but are hard-coded |
21 // here to make the test independent of locale data changes. | 21 // here to make the test independent of locale data changes. |
22 switch (type) { | 22 switch (type) { |
23 case AffixUtils.TYPE_MINUS_SIGN: | 23 case AffixUtils.TYPE_MINUS_SIGN: |
24 return "−"; | 24 return "−"; |
25 case AffixUtils.TYPE_PLUS_SIGN: | 25 case AffixUtils.TYPE_PLUS_SIGN: |
26 return "\u061C+"; | 26 return "\u061C+"; |
27 case AffixUtils.TYPE_PERCENT: | 27 case AffixUtils.TYPE_PERCENT: |
28 return "٪\u061C"; | 28 return "٪\u061C"; |
29 case AffixUtils.TYPE_PERMILLE: | 29 case AffixUtils.TYPE_PERMILLE: |
30 return "؉"; | 30 return "؉"; |
31 case AffixUtils.TYPE_CURRENCY_SINGLE: | 31 case AffixUtils.TYPE_CURRENCY_SINGLE: |
32 return "$"; | 32 return "$"; |
33 case AffixUtils.TYPE_CURRENCY_DOUBLE: | 33 case AffixUtils.TYPE_CURRENCY_DOUBLE: |
34 return "XXX"; | 34 return "XXX"; |
35 case AffixUtils.TYPE_CURRENCY_TRIPLE: | 35 case AffixUtils.TYPE_CURRENCY_TRIPLE: |
36 return "long name"; | 36 return "long name"; |
37 case AffixUtils.TYPE_CURRENCY_QUAD: | 37 case AffixUtils.TYPE_CURRENCY_QUAD: |
38 return "\uFFFD"; | 38 return "\uFFFD"; |
39 case AffixUtils.TYPE_CURRENCY_QUINT: | 39 case AffixUtils.TYPE_CURRENCY_QUINT: |
40 return "@"; | 40 return "@"; |
41 case AffixUtils.TYPE_CURRENCY_OVERFLOW: | 41 case AffixUtils.TYPE_CURRENCY_OVERFLOW: |
42 return "\uFFFD"; | 42 return "\uFFFD"; |
43 default: | 43 default: |
44 throw new AssertionError(); | 44 throw new AssertionError(); |
45 } | 45 } |
46 } | 46 } |
| 47 }; |
| 48 |
| 49 @Test |
| 50 public void testEscape() { |
| 51 Object[][] cases = { |
| 52 { "", "" }, |
| 53 { "abc", "abc" }, |
| 54 { "-", "'-'" }, |
| 55 { "-!", "'-'!" }, |
| 56 { "−", "−" }, |
| 57 { "---", "'---'" }, |
| 58 { "-%-", "'-%-'" }, |
| 59 { "'", "''" }, |
| 60 { "-'", "'-'''" }, |
| 61 { "-'-", "'-''-'" }, |
| 62 { "a-'-", "a'-''-'" } }; |
| 63 |
| 64 StringBuilder sb = new StringBuilder(); |
| 65 for (Object[] cas : cases) { |
| 66 String input = (String) cas[0]; |
| 67 String expected = (String) cas[1]; |
| 68 sb.setLength(0); |
| 69 AffixUtils.escape(input, sb); |
| 70 assertEquals(expected, sb.toString()); |
| 71 } |
| 72 } |
| 73 |
| 74 @Test |
| 75 public void testUnescape() { |
| 76 Object[][] cases = { |
| 77 { "", false, 0, "" }, |
| 78 { "abc", false, 3, "abc" }, |
| 79 { "-", false, 1, "−" }, |
| 80 { "-!", false, 2, "−!" }, |
| 81 { "+", false, 1, "\u061C+" }, |
| 82 { "+!", false, 2, "\u061C+!" }, |
| 83 { "‰", false, 1, "؉" }, |
| 84 { "‰!", false, 2, "؉!" }, |
| 85 { "-x", false, 2, "−x" }, |
| 86 { "'-'x", false, 2, "-x" }, |
| 87 { "'--''-'-x", false, 6, "--'-−x" }, |
| 88 { "''", false, 1, "'" }, |
| 89 { "''''", false, 2, "''" }, |
| 90 { "''''''", false, 3, "'''" }, |
| 91 { "''x''", false, 3, "'x'" }, |
| 92 { "¤", true, 1, "$" }, |
| 93 { "¤¤", true, 2, "XXX" }, |
| 94 { "¤¤¤", true, 3, "long name" }, |
| 95 { "¤¤¤¤", true, 4, "\uFFFD" }, |
| 96 { "¤¤¤¤¤", true, 5, "@" }, |
| 97 { "¤¤¤¤¤¤", true, 6, "\uFFFD" }, |
| 98 { "¤¤¤a¤¤¤¤", true, 8, "long namea\uFFFD" }, |
| 99 { "a¤¤¤¤b¤¤¤¤¤c", true, 12, "a\uFFFDb@c" }, |
| 100 { "¤!", true, 2, "$!" }, |
| 101 { "¤¤!", true, 3, "XXX!" }, |
| 102 { "¤¤¤!", true, 4, "long name!" }, |
| 103 { "-¤¤", true, 3, "−XXX" }, |
| 104 { "¤¤-", true, 3, "XXX−" }, |
| 105 { "'¤'", false, 1, "¤" }, |
| 106 { "%", false, 1, "٪\u061C" }, |
| 107 { "'%'", false, 1, "%" }, |
| 108 { "¤'-'%", true, 3, "$-٪\u061C" }, |
| 109 { "#0#@#*#;#", false, 9, "#0#@#*#;#" } }; |
| 110 |
| 111 for (Object[] cas : cases) { |
| 112 String input = (String) cas[0]; |
| 113 boolean curr = (Boolean) cas[1]; |
| 114 int length = (Integer) cas[2]; |
| 115 String output = (String) cas[3]; |
| 116 |
| 117 assertEquals("Currency on <" + input + ">", curr, AffixUtils.hasCurr
encySymbols(input)); |
| 118 assertEquals("Length on <" + input + ">", length, AffixUtils.estimat
eLength(input)); |
| 119 |
| 120 String actual = unescapeWithDefaults(input); |
| 121 assertEquals("Output on <" + input + ">", output, actual); |
| 122 |
| 123 int ulength = AffixUtils.unescapedCodePointCount(input, DEFAULT_SYMB
OL_PROVIDER); |
| 124 assertEquals("Unescaped length on <" + input + ">", output.length(),
ulength); |
| 125 } |
| 126 } |
| 127 |
| 128 @Test |
| 129 public void testContainsReplaceType() { |
| 130 Object[][] cases = { |
| 131 { "", false, "" }, |
| 132 { "-", true, "+" }, |
| 133 { "-a", true, "+a" }, |
| 134 { "a-", true, "a+" }, |
| 135 { "a-b", true, "a+b" }, |
| 136 { "--", true, "++" }, |
| 137 { "x", false, "x" } }; |
| 138 |
| 139 for (Object[] cas : cases) { |
| 140 String input = (String) cas[0]; |
| 141 boolean hasMinusSign = (Boolean) cas[1]; |
| 142 String output = (String) cas[2]; |
| 143 |
| 144 assertEquals("Contains on input " + input, |
| 145 hasMinusSign, |
| 146 AffixUtils.containsType(input, AffixUtils.TYPE_MINUS_SIGN)); |
| 147 assertEquals("Replace on input" + input, |
| 148 output, |
| 149 AffixUtils.replaceType(input, AffixUtils.TYPE_MINUS_SIGN, '+
')); |
| 150 } |
| 151 } |
| 152 |
| 153 @Test |
| 154 public void testInvalid() { |
| 155 String[] invalidExamples = { "'", "x'", "'x", "'x''", "''x'" }; |
| 156 |
| 157 for (String str : invalidExamples) { |
| 158 try { |
| 159 AffixUtils.hasCurrencySymbols(str); |
| 160 fail("No exception was thrown on an invalid string"); |
| 161 } catch (IllegalArgumentException e) { |
| 162 // OK |
| 163 } |
| 164 try { |
| 165 AffixUtils.estimateLength(str); |
| 166 fail("No exception was thrown on an invalid string"); |
| 167 } catch (IllegalArgumentException e) { |
| 168 // OK |
| 169 } |
| 170 try { |
| 171 unescapeWithDefaults(str); |
| 172 fail("No exception was thrown on an invalid string"); |
| 173 } catch (IllegalArgumentException e) { |
| 174 // OK |
| 175 } |
| 176 } |
| 177 } |
| 178 |
| 179 @Test |
| 180 public void testUnescapeWithSymbolProvider() { |
| 181 String[][] cases = { |
| 182 { "", "" }, |
| 183 { "-", "1" }, |
| 184 { "'-'", "-" }, |
| 185 { "- + % ‰ ¤ ¤¤ ¤¤¤ ¤¤¤¤ ¤¤¤¤¤", "1 2 3 4 5 6 7 8 9" }, |
| 186 { "'¤¤¤¤¤¤'", "¤¤¤¤¤¤" }, |
| 187 { "¤¤¤¤¤¤", "\uFFFD" } }; |
| 188 |
| 189 SymbolProvider provider = new SymbolProvider() { |
| 190 @Override |
| 191 public CharSequence getSymbol(int type) { |
| 192 return Integer.toString(Math.abs(type)); |
| 193 } |
47 }; | 194 }; |
48 | 195 |
49 @Test | 196 NumberStringBuilder sb = new NumberStringBuilder(); |
50 public void testEscape() { | 197 for (String[] cas : cases) { |
51 Object[][] cases = { | 198 String input = cas[0]; |
52 {"", ""}, | 199 String expected = cas[1]; |
53 {"abc", "abc"}, | 200 sb.clear(); |
54 {"-", "'-'"}, | 201 AffixUtils.unescape(input, sb, 0, provider); |
55 {"-!", "'-'!"}, | 202 assertEquals("With symbol provider on <" + input + ">", expected, sb
.toString()); |
56 {"−", "−"}, | 203 } |
57 {"---", "'---'"}, | 204 |
58 {"-%-", "'-%-'"}, | 205 // Test insertion position |
59 {"'", "''"}, | 206 sb.clear(); |
60 {"-'", "'-'''"}, | 207 sb.append("abcdefg", null); |
61 {"-'-", "'-''-'"}, | 208 AffixUtils.unescape("-+%", sb, 4, provider); |
62 {"a-'-", "a'-''-'"} | 209 assertEquals("Symbol provider into middle", "abcd123efg", sb.toString())
; |
63 }; | 210 } |
64 | 211 |
65 StringBuilder sb = new StringBuilder(); | 212 @Test |
66 for (Object[] cas : cases) { | 213 public void testWithoutSymbolsOrIgnorables() { |
67 String input = (String) cas[0]; | 214 String[][] cases = { |
68 String expected = (String) cas[1]; | 215 { "", "" }, |
69 sb.setLength(0); | 216 { "-", "" }, |
70 AffixUtils.escape(input, sb); | 217 { " ", "" }, |
71 assertEquals(expected, sb.toString()); | 218 { "'-'", "-" }, |
72 } | 219 { " a + b ", "a b" }, |
73 } | 220 { "-a+b%c‰d¤e¤¤f¤¤¤g¤¤¤¤h¤¤¤¤¤i", "abcdefghi" }, }; |
74 | 221 |
75 @Test | 222 UnicodeSet ignorables = new UnicodeSet("[:whitespace:]"); |
76 public void testUnescape() { | 223 StringBuilder sb = new StringBuilder(); |
77 Object[][] cases = { | 224 for (String[] cas : cases) { |
78 {"", false, 0, ""}, | 225 String input = cas[0]; |
79 {"abc", false, 3, "abc"}, | 226 String expected = cas[1]; |
80 {"-", false, 1, "−"}, | 227 sb.setLength(0); |
81 {"-!", false, 2, "−!"}, | 228 AffixUtils.trimSymbolsAndIgnorables(input, ignorables, sb); |
82 {"+", false, 1, "\u061C+"}, | 229 assertEquals("Removing symbols from: " + input, expected, sb.toStrin
g()); |
83 {"+!", false, 2, "\u061C+!"}, | 230 } |
84 {"‰", false, 1, "؉"}, | 231 } |
85 {"‰!", false, 2, "؉!"}, | 232 |
86 {"-x", false, 2, "−x"}, | 233 private static String unescapeWithDefaults(String input) { |
87 {"'-'x", false, 2, "-x"}, | 234 NumberStringBuilder nsb = new NumberStringBuilder(); |
88 {"'--''-'-x", false, 6, "--'-−x"}, | 235 int length = AffixUtils.unescape(input, nsb, 0, DEFAULT_SYMBOL_PROVIDER)
; |
89 {"''", false, 1, "'"}, | 236 assertEquals("Return value of unescape", nsb.length(), length); |
90 {"''''", false, 2, "''"}, | 237 return nsb.toString(); |
91 {"''''''", false, 3, "'''"}, | 238 } |
92 {"''x''", false, 3, "'x'"}, | |
93 {"¤", true, 1, "$"}, | |
94 {"¤¤", true, 2, "XXX"}, | |
95 {"¤¤¤", true, 3, "long name"}, | |
96 {"¤¤¤¤", true, 4, "\uFFFD"}, | |
97 {"¤¤¤¤¤", true, 5, "@"}, | |
98 {"¤¤¤¤¤¤", true, 6, "\uFFFD"}, | |
99 {"¤¤¤a¤¤¤¤", true, 8, "long namea\uFFFD"}, | |
100 {"a¤¤¤¤b¤¤¤¤¤c", true, 12, "a\uFFFDb@c"}, | |
101 {"¤!", true, 2, "$!"}, | |
102 {"¤¤!", true, 3, "XXX!"}, | |
103 {"¤¤¤!", true, 4, "long name!"}, | |
104 {"-¤¤", true, 3, "−XXX"}, | |
105 {"¤¤-", true, 3, "XXX−"}, | |
106 {"'¤'", false, 1, "¤"}, | |
107 {"%", false, 1, "٪\u061C"}, | |
108 {"'%'", false, 1, "%"}, | |
109 {"¤'-'%", true, 3, "$-٪\u061C"}, | |
110 {"#0#@#*#;#", false, 9, "#0#@#*#;#"} | |
111 }; | |
112 | |
113 for (Object[] cas : cases) { | |
114 String input = (String) cas[0]; | |
115 boolean curr = (Boolean) cas[1]; | |
116 int length = (Integer) cas[2]; | |
117 String output = (String) cas[3]; | |
118 | |
119 assertEquals( | |
120 "Currency on <" + input + ">", curr, AffixUtils.hasCurrencySymbols(inp
ut)); | |
121 assertEquals("Length on <" + input + ">", length, AffixUtils.estimateLengt
h(input)); | |
122 | |
123 String actual = unescapeWithDefaults(input); | |
124 assertEquals("Output on <" + input + ">", output, actual); | |
125 | |
126 int ulength = AffixUtils.unescapedCodePointCount(input, DEFAULT_SYMBOL_PRO
VIDER); | |
127 assertEquals("Unescaped length on <" + input + ">", output.length(), uleng
th); | |
128 } | |
129 } | |
130 | |
131 @Test | |
132 public void testContainsReplaceType() { | |
133 Object[][] cases = { | |
134 {"", false, ""}, | |
135 {"-", true, "+"}, | |
136 {"-a", true, "+a"}, | |
137 {"a-", true, "a+"}, | |
138 {"a-b", true, "a+b"}, | |
139 {"--", true, "++"}, | |
140 {"x", false, "x"} | |
141 }; | |
142 | |
143 for (Object[] cas : cases) { | |
144 String input = (String) cas[0]; | |
145 boolean hasMinusSign = (Boolean) cas[1]; | |
146 String output = (String) cas[2]; | |
147 | |
148 assertEquals( | |
149 "Contains on input " + input, | |
150 hasMinusSign, | |
151 AffixUtils.containsType(input, AffixUtils.TYPE_MINUS_SIGN)); | |
152 assertEquals( | |
153 "Replace on input" + input, | |
154 output, | |
155 AffixUtils.replaceType(input, AffixUtils.TYPE_MINUS_SIGN, '+')); | |
156 } | |
157 } | |
158 | |
159 @Test | |
160 public void testInvalid() { | |
161 String[] invalidExamples = {"'", "x'", "'x", "'x''", "''x'"}; | |
162 | |
163 for (String str : invalidExamples) { | |
164 try { | |
165 AffixUtils.hasCurrencySymbols(str); | |
166 fail("No exception was thrown on an invalid string"); | |
167 } catch (IllegalArgumentException e) { | |
168 // OK | |
169 } | |
170 try { | |
171 AffixUtils.estimateLength(str); | |
172 fail("No exception was thrown on an invalid string"); | |
173 } catch (IllegalArgumentException e) { | |
174 // OK | |
175 } | |
176 try { | |
177 unescapeWithDefaults(str); | |
178 fail("No exception was thrown on an invalid string"); | |
179 } catch (IllegalArgumentException e) { | |
180 // OK | |
181 } | |
182 } | |
183 } | |
184 | |
185 @Test | |
186 public void testUnescapeWithSymbolProvider() { | |
187 String[][] cases = { | |
188 {"", ""}, | |
189 {"-", "1"}, | |
190 {"'-'", "-"}, | |
191 {"- + % ‰ ¤ ¤¤ ¤¤¤ ¤¤¤¤ ¤¤¤¤¤", "1 2 3 4 5 6 7 8 9"}, | |
192 {"'¤¤¤¤¤¤'", "¤¤¤¤¤¤"}, | |
193 {"¤¤¤¤¤¤", "\uFFFD"} | |
194 }; | |
195 | |
196 SymbolProvider provider = | |
197 new SymbolProvider() { | |
198 @Override | |
199 public CharSequence getSymbol(int type) { | |
200 return Integer.toString(Math.abs(type)); | |
201 } | |
202 }; | |
203 | |
204 NumberStringBuilder sb = new NumberStringBuilder(); | |
205 for (String[] cas : cases) { | |
206 String input = cas[0]; | |
207 String expected = cas[1]; | |
208 sb.clear(); | |
209 AffixUtils.unescape(input, sb, 0, provider); | |
210 assertEquals("With symbol provider on <" + input + ">", expected, sb.toStr
ing()); | |
211 } | |
212 | |
213 // Test insertion position | |
214 sb.clear(); | |
215 sb.append("abcdefg", null); | |
216 AffixUtils.unescape("-+%", sb, 4, provider); | |
217 assertEquals("Symbol provider into middle", "abcd123efg", sb.toString()); | |
218 } | |
219 | |
220 private static String unescapeWithDefaults(String input) { | |
221 NumberStringBuilder nsb = new NumberStringBuilder(); | |
222 int length = AffixUtils.unescape(input, nsb, 0, DEFAULT_SYMBOL_PROVIDER); | |
223 assertEquals("Return value of unescape", nsb.length(), length); | |
224 return nsb.toString(); | |
225 } | |
226 } | 239 } |
OLD | NEW |