]>
Commit | Line | Data |
---|---|---|
0f5d89e8 A |
1 | // © 2017 and later: Unicode, Inc. and others. |
2 | // License & terms of use: http://www.unicode.org/copyright.html | |
3 | ||
4 | #include "unicode/utypes.h" | |
5 | ||
6 | #if !UCONFIG_NO_FORMATTING | |
7 | ||
8 | #include "charstr.h" | |
9 | #include <cstdarg> | |
10 | #include <cmath> | |
3d1f044b | 11 | #include <memory> |
0f5d89e8 A |
12 | #include "unicode/unum.h" |
13 | #include "unicode/numberformatter.h" | |
14 | #include "number_asformat.h" | |
15 | #include "number_types.h" | |
16 | #include "number_utils.h" | |
17 | #include "numbertest.h" | |
18 | #include "unicode/utypes.h" | |
19 | ||
20 | // Horrible workaround for the lack of a status code in the constructor... | |
3d1f044b | 21 | // (Also affects numbertest_range.cpp) |
0f5d89e8 A |
22 | UErrorCode globalNumberFormatterApiTestStatus = U_ZERO_ERROR; |
23 | ||
24 | NumberFormatterApiTest::NumberFormatterApiTest() | |
25 | : NumberFormatterApiTest(globalNumberFormatterApiTestStatus) { | |
26 | } | |
27 | ||
28 | NumberFormatterApiTest::NumberFormatterApiTest(UErrorCode& status) | |
29 | : USD(u"USD", status), | |
30 | GBP(u"GBP", status), | |
31 | CZK(u"CZK", status), | |
32 | CAD(u"CAD", status), | |
33 | ESP(u"ESP", status), | |
34 | PTE(u"PTE", status), | |
3d1f044b | 35 | RON(u"RON", status), |
0f5d89e8 A |
36 | FRENCH_SYMBOLS(Locale::getFrench(), status), |
37 | SWISS_SYMBOLS(Locale("de-CH"), status), | |
38 | MYANMAR_SYMBOLS(Locale("my"), status) { | |
39 | ||
40 | // Check for error on the first MeasureUnit in case there is no data | |
41 | LocalPointer<MeasureUnit> unit(MeasureUnit::createMeter(status)); | |
42 | if (U_FAILURE(status)) { | |
43 | dataerrln("%s %d status = %s", __FILE__, __LINE__, u_errorName(status)); | |
44 | return; | |
45 | } | |
46 | METER = *unit; | |
47 | ||
48 | DAY = *LocalPointer<MeasureUnit>(MeasureUnit::createDay(status)); | |
49 | SQUARE_METER = *LocalPointer<MeasureUnit>(MeasureUnit::createSquareMeter(status)); | |
50 | FAHRENHEIT = *LocalPointer<MeasureUnit>(MeasureUnit::createFahrenheit(status)); | |
51 | SECOND = *LocalPointer<MeasureUnit>(MeasureUnit::createSecond(status)); | |
52 | POUND = *LocalPointer<MeasureUnit>(MeasureUnit::createPound(status)); | |
53 | SQUARE_MILE = *LocalPointer<MeasureUnit>(MeasureUnit::createSquareMile(status)); | |
54 | JOULE = *LocalPointer<MeasureUnit>(MeasureUnit::createJoule(status)); | |
55 | FURLONG = *LocalPointer<MeasureUnit>(MeasureUnit::createFurlong(status)); | |
56 | KELVIN = *LocalPointer<MeasureUnit>(MeasureUnit::createKelvin(status)); | |
57 | ||
58 | MATHSANB = *LocalPointer<NumberingSystem>(NumberingSystem::createInstanceByName("mathsanb", status)); | |
59 | LATN = *LocalPointer<NumberingSystem>(NumberingSystem::createInstanceByName("latn", status)); | |
60 | } | |
61 | ||
62 | void NumberFormatterApiTest::runIndexedTest(int32_t index, UBool exec, const char*& name, char*) { | |
63 | if (exec) { | |
64 | logln("TestSuite NumberFormatterApiTest: "); | |
65 | } | |
66 | TESTCASE_AUTO_BEGIN; | |
67 | TESTCASE_AUTO(notationSimple); | |
68 | TESTCASE_AUTO(notationScientific); | |
69 | TESTCASE_AUTO(notationCompact); | |
70 | TESTCASE_AUTO(unitMeasure); | |
71 | TESTCASE_AUTO(unitCompoundMeasure); | |
72 | TESTCASE_AUTO(unitCurrency); | |
73 | TESTCASE_AUTO(unitPercent); | |
3d1f044b A |
74 | if (!quick) { |
75 | // Slow test: run in exhaustive mode only | |
76 | TESTCASE_AUTO(percentParity); | |
77 | } | |
0f5d89e8 A |
78 | TESTCASE_AUTO(roundingFraction); |
79 | TESTCASE_AUTO(roundingFigures); | |
80 | TESTCASE_AUTO(roundingFractionFigures); | |
81 | TESTCASE_AUTO(roundingOther); | |
82 | TESTCASE_AUTO(grouping); | |
83 | TESTCASE_AUTO(padding); | |
84 | TESTCASE_AUTO(integerWidth); | |
85 | TESTCASE_AUTO(symbols); | |
86 | // TODO: Add this method if currency symbols override support is added. | |
87 | //TESTCASE_AUTO(symbolsOverride); | |
88 | TESTCASE_AUTO(sign); | |
89 | TESTCASE_AUTO(decimal); | |
90 | TESTCASE_AUTO(scale); | |
91 | TESTCASE_AUTO(locale); | |
92 | TESTCASE_AUTO(formatTypes); | |
3d1f044b A |
93 | TESTCASE_AUTO(fieldPositionLogic); |
94 | TESTCASE_AUTO(fieldPositionCoverage); | |
0f5d89e8 A |
95 | TESTCASE_AUTO(toFormat); |
96 | TESTCASE_AUTO(errors); | |
3d1f044b A |
97 | if (!quick) { |
98 | // Slow test: run in exhaustive mode only | |
99 | // (somewhat slow to check all permutations of settings) | |
100 | TESTCASE_AUTO(validRanges); | |
101 | } | |
0f5d89e8 A |
102 | TESTCASE_AUTO(copyMove); |
103 | TESTCASE_AUTO(localPointerCAPI); | |
3d1f044b | 104 | TESTCASE_AUTO(toObject); |
0f5d89e8 A |
105 | TESTCASE_AUTO_END; |
106 | } | |
107 | ||
108 | void NumberFormatterApiTest::notationSimple() { | |
109 | assertFormatDescending( | |
110 | u"Basic", | |
111 | u"", | |
112 | NumberFormatter::with(), | |
113 | Locale::getEnglish(), | |
114 | u"87,650", | |
115 | u"8,765", | |
116 | u"876.5", | |
117 | u"87.65", | |
118 | u"8.765", | |
119 | u"0.8765", | |
120 | u"0.08765", | |
121 | u"0.008765", | |
122 | u"0"); | |
123 | ||
124 | assertFormatDescendingBig( | |
125 | u"Big Simple", | |
126 | u"notation-simple", | |
127 | NumberFormatter::with().notation(Notation::simple()), | |
128 | Locale::getEnglish(), | |
129 | u"87,650,000", | |
130 | u"8,765,000", | |
131 | u"876,500", | |
132 | u"87,650", | |
133 | u"8,765", | |
134 | u"876.5", | |
135 | u"87.65", | |
136 | u"8.765", | |
137 | u"0"); | |
138 | ||
139 | assertFormatSingle( | |
140 | u"Basic with Negative Sign", | |
141 | u"", | |
142 | NumberFormatter::with(), | |
143 | Locale::getEnglish(), | |
144 | -9876543.21, | |
145 | u"-9,876,543.21"); | |
146 | } | |
147 | ||
148 | ||
149 | void NumberFormatterApiTest::notationScientific() { | |
150 | assertFormatDescending( | |
151 | u"Scientific", | |
152 | u"scientific", | |
153 | NumberFormatter::with().notation(Notation::scientific()), | |
154 | Locale::getEnglish(), | |
155 | u"8.765E4", | |
156 | u"8.765E3", | |
157 | u"8.765E2", | |
158 | u"8.765E1", | |
159 | u"8.765E0", | |
160 | u"8.765E-1", | |
161 | u"8.765E-2", | |
162 | u"8.765E-3", | |
163 | u"0E0"); | |
164 | ||
165 | assertFormatDescending( | |
166 | u"Engineering", | |
167 | u"engineering", | |
168 | NumberFormatter::with().notation(Notation::engineering()), | |
169 | Locale::getEnglish(), | |
170 | u"87.65E3", | |
171 | u"8.765E3", | |
172 | u"876.5E0", | |
173 | u"87.65E0", | |
174 | u"8.765E0", | |
175 | u"876.5E-3", | |
176 | u"87.65E-3", | |
177 | u"8.765E-3", | |
178 | u"0E0"); | |
179 | ||
180 | assertFormatDescending( | |
181 | u"Scientific sign always shown", | |
182 | u"scientific/sign-always", | |
183 | NumberFormatter::with().notation( | |
184 | Notation::scientific().withExponentSignDisplay(UNumberSignDisplay::UNUM_SIGN_ALWAYS)), | |
185 | Locale::getEnglish(), | |
186 | u"8.765E+4", | |
187 | u"8.765E+3", | |
188 | u"8.765E+2", | |
189 | u"8.765E+1", | |
190 | u"8.765E+0", | |
191 | u"8.765E-1", | |
192 | u"8.765E-2", | |
193 | u"8.765E-3", | |
194 | u"0E+0"); | |
195 | ||
196 | assertFormatDescending( | |
197 | u"Scientific min exponent digits", | |
198 | u"scientific/+ee", | |
199 | NumberFormatter::with().notation(Notation::scientific().withMinExponentDigits(2)), | |
200 | Locale::getEnglish(), | |
201 | u"8.765E04", | |
202 | u"8.765E03", | |
203 | u"8.765E02", | |
204 | u"8.765E01", | |
205 | u"8.765E00", | |
206 | u"8.765E-01", | |
207 | u"8.765E-02", | |
208 | u"8.765E-03", | |
209 | u"0E00"); | |
210 | ||
211 | assertFormatSingle( | |
212 | u"Scientific Negative", | |
213 | u"scientific", | |
214 | NumberFormatter::with().notation(Notation::scientific()), | |
215 | Locale::getEnglish(), | |
216 | -1000000, | |
217 | u"-1E6"); | |
218 | } | |
219 | ||
220 | void NumberFormatterApiTest::notationCompact() { | |
221 | assertFormatDescending( | |
222 | u"Compact Short", | |
223 | u"compact-short", | |
224 | NumberFormatter::with().notation(Notation::compactShort()), | |
225 | Locale::getEnglish(), | |
226 | u"88K", | |
227 | u"8.8K", | |
228 | u"876", | |
229 | u"88", | |
230 | u"8.8", | |
231 | u"0.88", | |
232 | u"0.088", | |
233 | u"0.0088", | |
234 | u"0"); | |
235 | ||
236 | assertFormatDescending( | |
237 | u"Compact Long", | |
238 | u"compact-long", | |
239 | NumberFormatter::with().notation(Notation::compactLong()), | |
240 | Locale::getEnglish(), | |
241 | u"88 thousand", | |
242 | u"8.8 thousand", | |
243 | u"876", | |
244 | u"88", | |
245 | u"8.8", | |
246 | u"0.88", | |
247 | u"0.088", | |
248 | u"0.0088", | |
249 | u"0"); | |
250 | ||
251 | assertFormatDescending( | |
252 | u"Compact Short Currency", | |
253 | u"compact-short currency/USD", | |
254 | NumberFormatter::with().notation(Notation::compactShort()).unit(USD), | |
255 | Locale::getEnglish(), | |
256 | u"$88K", | |
257 | u"$8.8K", | |
258 | u"$876", | |
259 | u"$88", | |
260 | u"$8.8", | |
261 | u"$0.88", | |
262 | u"$0.088", | |
263 | u"$0.0088", | |
264 | u"$0"); | |
265 | ||
266 | assertFormatDescending( | |
267 | u"Compact Short with ISO Currency", | |
268 | u"compact-short currency/USD unit-width-iso-code", | |
269 | NumberFormatter::with().notation(Notation::compactShort()) | |
270 | .unit(USD) | |
271 | .unitWidth(UNumberUnitWidth::UNUM_UNIT_WIDTH_ISO_CODE), | |
272 | Locale::getEnglish(), | |
273 | u"USD 88K", | |
274 | u"USD 8.8K", | |
275 | u"USD 876", | |
276 | u"USD 88", | |
277 | u"USD 8.8", | |
278 | u"USD 0.88", | |
279 | u"USD 0.088", | |
280 | u"USD 0.0088", | |
281 | u"USD 0"); | |
282 | ||
283 | assertFormatDescending( | |
284 | u"Compact Short with Long Name Currency", | |
285 | u"compact-short currency/USD unit-width-full-name", | |
286 | NumberFormatter::with().notation(Notation::compactShort()) | |
287 | .unit(USD) | |
288 | .unitWidth(UNumberUnitWidth::UNUM_UNIT_WIDTH_FULL_NAME), | |
289 | Locale::getEnglish(), | |
290 | u"88K US dollars", | |
291 | u"8.8K US dollars", | |
292 | u"876 US dollars", | |
293 | u"88 US dollars", | |
294 | u"8.8 US dollars", | |
295 | u"0.88 US dollars", | |
296 | u"0.088 US dollars", | |
297 | u"0.0088 US dollars", | |
298 | u"0 US dollars"); | |
299 | ||
300 | // Note: Most locales don't have compact long currency, so this currently falls back to short. | |
301 | // This test case should be fixed when proper compact long currency patterns are added. | |
302 | assertFormatDescending( | |
303 | u"Compact Long Currency", | |
304 | u"compact-long currency/USD", | |
305 | NumberFormatter::with().notation(Notation::compactLong()).unit(USD), | |
306 | Locale::getEnglish(), | |
307 | u"$88K", // should be something like "$88 thousand" | |
308 | u"$8.8K", | |
309 | u"$876", | |
310 | u"$88", | |
311 | u"$8.8", | |
312 | u"$0.88", | |
313 | u"$0.088", | |
314 | u"$0.0088", | |
315 | u"$0"); | |
316 | ||
317 | // Note: Most locales don't have compact long currency, so this currently falls back to short. | |
318 | // This test case should be fixed when proper compact long currency patterns are added. | |
319 | assertFormatDescending( | |
320 | u"Compact Long with ISO Currency", | |
321 | u"compact-long currency/USD unit-width-iso-code", | |
322 | NumberFormatter::with().notation(Notation::compactLong()) | |
323 | .unit(USD) | |
324 | .unitWidth(UNumberUnitWidth::UNUM_UNIT_WIDTH_ISO_CODE), | |
325 | Locale::getEnglish(), | |
326 | u"USD 88K", // should be something like "USD 88 thousand" | |
327 | u"USD 8.8K", | |
328 | u"USD 876", | |
329 | u"USD 88", | |
330 | u"USD 8.8", | |
331 | u"USD 0.88", | |
332 | u"USD 0.088", | |
333 | u"USD 0.0088", | |
334 | u"USD 0"); | |
335 | ||
336 | // TODO: This behavior could be improved and should be revisited. | |
337 | assertFormatDescending( | |
338 | u"Compact Long with Long Name Currency", | |
339 | u"compact-long currency/USD unit-width-full-name", | |
340 | NumberFormatter::with().notation(Notation::compactLong()) | |
341 | .unit(USD) | |
342 | .unitWidth(UNumberUnitWidth::UNUM_UNIT_WIDTH_FULL_NAME), | |
343 | Locale::getEnglish(), | |
344 | u"88 thousand US dollars", | |
345 | u"8.8 thousand US dollars", | |
346 | u"876 US dollars", | |
347 | u"88 US dollars", | |
348 | u"8.8 US dollars", | |
349 | u"0.88 US dollars", | |
350 | u"0.088 US dollars", | |
351 | u"0.0088 US dollars", | |
352 | u"0 US dollars"); | |
353 | ||
354 | assertFormatSingle( | |
355 | u"Compact Plural One", | |
356 | u"compact-long", | |
357 | NumberFormatter::with().notation(Notation::compactLong()), | |
358 | Locale::createFromName("es"), | |
359 | 1000000, | |
360 | u"1 millón"); | |
361 | ||
362 | assertFormatSingle( | |
363 | u"Compact Plural Other", | |
364 | u"compact-long", | |
365 | NumberFormatter::with().notation(Notation::compactLong()), | |
366 | Locale::createFromName("es"), | |
367 | 2000000, | |
368 | u"2 millones"); | |
369 | ||
370 | assertFormatSingle( | |
371 | u"Compact with Negative Sign", | |
372 | u"compact-short", | |
373 | NumberFormatter::with().notation(Notation::compactShort()), | |
374 | Locale::getEnglish(), | |
375 | -9876543.21, | |
376 | u"-9.9M"); | |
377 | ||
378 | assertFormatSingle( | |
379 | u"Compact Rounding", | |
380 | u"compact-short", | |
381 | NumberFormatter::with().notation(Notation::compactShort()), | |
382 | Locale::getEnglish(), | |
383 | 990000, | |
384 | u"990K"); | |
385 | ||
386 | assertFormatSingle( | |
387 | u"Compact Rounding", | |
388 | u"compact-short", | |
389 | NumberFormatter::with().notation(Notation::compactShort()), | |
390 | Locale::getEnglish(), | |
391 | 999000, | |
392 | u"999K"); | |
393 | ||
394 | assertFormatSingle( | |
395 | u"Compact Rounding", | |
396 | u"compact-short", | |
397 | NumberFormatter::with().notation(Notation::compactShort()), | |
398 | Locale::getEnglish(), | |
399 | 999900, | |
400 | u"1M"); | |
401 | ||
402 | assertFormatSingle( | |
403 | u"Compact Rounding", | |
404 | u"compact-short", | |
405 | NumberFormatter::with().notation(Notation::compactShort()), | |
406 | Locale::getEnglish(), | |
407 | 9900000, | |
408 | u"9.9M"); | |
409 | ||
410 | assertFormatSingle( | |
411 | u"Compact Rounding", | |
412 | u"compact-short", | |
413 | NumberFormatter::with().notation(Notation::compactShort()), | |
414 | Locale::getEnglish(), | |
415 | 9990000, | |
416 | u"10M"); | |
417 | ||
3d1f044b A |
418 | assertFormatSingle( |
419 | u"Compact in zh-Hant-HK", | |
420 | u"compact-short", | |
421 | NumberFormatter::with().notation(Notation::compactShort()), | |
422 | Locale("zh-Hant-HK"), | |
423 | 1e7, | |
424 | u"10M"); | |
425 | ||
426 | assertFormatSingle( | |
427 | u"Compact in zh-Hant", | |
428 | u"compact-short", | |
429 | NumberFormatter::with().notation(Notation::compactShort()), | |
430 | Locale("zh-Hant"), | |
431 | 1e7, | |
432 | u"1000\u842C"); | |
433 | ||
0f5d89e8 A |
434 | // NOTE: There is no API for compact custom data in C++ |
435 | // and thus no "Compact Somali No Figure" test | |
436 | } | |
437 | ||
438 | void NumberFormatterApiTest::unitMeasure() { | |
439 | assertFormatDescending( | |
440 | u"Meters Short and unit() method", | |
441 | u"measure-unit/length-meter", | |
3d1f044b | 442 | NumberFormatter::with().unit(MeasureUnit::getMeter()), |
0f5d89e8 A |
443 | Locale::getEnglish(), |
444 | u"87,650 m", | |
445 | u"8,765 m", | |
446 | u"876.5 m", | |
447 | u"87.65 m", | |
448 | u"8.765 m", | |
449 | u"0.8765 m", | |
450 | u"0.08765 m", | |
451 | u"0.008765 m", | |
452 | u"0 m"); | |
453 | ||
454 | assertFormatDescending( | |
455 | u"Meters Long and adoptUnit() method", | |
456 | u"measure-unit/length-meter unit-width-full-name", | |
457 | NumberFormatter::with().adoptUnit(new MeasureUnit(METER)) | |
458 | .unitWidth(UNumberUnitWidth::UNUM_UNIT_WIDTH_FULL_NAME), | |
459 | Locale::getEnglish(), | |
460 | u"87,650 meters", | |
461 | u"8,765 meters", | |
462 | u"876.5 meters", | |
463 | u"87.65 meters", | |
464 | u"8.765 meters", | |
465 | u"0.8765 meters", | |
466 | u"0.08765 meters", | |
467 | u"0.008765 meters", | |
468 | u"0 meters"); | |
469 | ||
470 | assertFormatDescending( | |
471 | u"Compact Meters Long", | |
472 | u"compact-long measure-unit/length-meter unit-width-full-name", | |
473 | NumberFormatter::with().notation(Notation::compactLong()) | |
474 | .unit(METER) | |
475 | .unitWidth(UNumberUnitWidth::UNUM_UNIT_WIDTH_FULL_NAME), | |
476 | Locale::getEnglish(), | |
477 | u"88 thousand meters", | |
478 | u"8.8 thousand meters", | |
479 | u"876 meters", | |
480 | u"88 meters", | |
481 | u"8.8 meters", | |
482 | u"0.88 meters", | |
483 | u"0.088 meters", | |
484 | u"0.0088 meters", | |
485 | u"0 meters"); | |
486 | ||
487 | // TODO: Implement Measure in C++ | |
488 | // assertFormatSingleMeasure( | |
489 | // u"Meters with Measure Input", | |
490 | // NumberFormatter::with().unitWidth(UNumberUnitWidth::UNUM_UNIT_WIDTH_FULL_NAME), | |
491 | // Locale::getEnglish(), | |
492 | // new Measure(5.43, new MeasureUnit(METER)), | |
493 | // u"5.43 meters"); | |
494 | ||
495 | // TODO: Implement Measure in C++ | |
496 | // assertFormatSingleMeasure( | |
497 | // u"Measure format method takes precedence over fluent chain", | |
498 | // NumberFormatter::with().unit(METER), | |
499 | // Locale::getEnglish(), | |
500 | // new Measure(5.43, USD), | |
501 | // u"$5.43"); | |
502 | ||
503 | assertFormatSingle( | |
504 | u"Meters with Negative Sign", | |
505 | u"measure-unit/length-meter", | |
506 | NumberFormatter::with().unit(METER), | |
507 | Locale::getEnglish(), | |
508 | -9876543.21, | |
509 | u"-9,876,543.21 m"); | |
510 | ||
511 | // The locale string "सान" appears only in brx.txt: | |
512 | assertFormatSingle( | |
513 | u"Interesting Data Fallback 1", | |
514 | u"measure-unit/duration-day unit-width-full-name", | |
515 | NumberFormatter::with().unit(DAY).unitWidth(UNumberUnitWidth::UNUM_UNIT_WIDTH_FULL_NAME), | |
516 | Locale::createFromName("brx"), | |
517 | 5.43, | |
518 | u"5.43 सान"); | |
519 | ||
520 | // Requires following the alias from unitsNarrow to unitsShort: | |
521 | assertFormatSingle( | |
522 | u"Interesting Data Fallback 2", | |
523 | u"measure-unit/duration-day unit-width-narrow", | |
524 | NumberFormatter::with().unit(DAY).unitWidth(UNumberUnitWidth::UNUM_UNIT_WIDTH_NARROW), | |
525 | Locale::createFromName("brx"), | |
526 | 5.43, | |
527 | u"5.43 d"); | |
528 | ||
529 | // en_001.txt has a unitsNarrow/area/square-meter table, but table does not contain the OTHER unit, | |
530 | // requiring fallback to the root. | |
531 | assertFormatSingle( | |
532 | u"Interesting Data Fallback 3", | |
533 | u"measure-unit/area-square-meter unit-width-narrow", | |
534 | NumberFormatter::with().unit(SQUARE_METER).unitWidth(UNumberUnitWidth::UNUM_UNIT_WIDTH_NARROW), | |
535 | Locale::createFromName("en-GB"), | |
536 | 5.43, | |
537 | u"5.43 m²"); | |
538 | ||
3d1f044b A |
539 | // Try accessing a narrow unit directly from root. |
540 | assertFormatSingle( | |
541 | u"Interesting Data Fallback 4", | |
542 | u"measure-unit/area-square-meter unit-width-narrow", | |
543 | NumberFormatter::with().unit(SQUARE_METER).unitWidth(UNumberUnitWidth::UNUM_UNIT_WIDTH_NARROW), | |
544 | Locale::createFromName("root"), | |
545 | 5.43, | |
546 | u"5.43 m²"); | |
547 | ||
0f5d89e8 A |
548 | // es_US has "{0}°" for unitsNarrow/temperature/FAHRENHEIT. |
549 | // NOTE: This example is in the documentation. | |
550 | assertFormatSingle( | |
551 | u"Difference between Narrow and Short (Narrow Version)", | |
552 | u"measure-unit/temperature-fahrenheit unit-width-narrow", | |
553 | NumberFormatter::with().unit(FAHRENHEIT).unitWidth(UNUM_UNIT_WIDTH_NARROW), | |
554 | Locale("es-US"), | |
555 | 5.43, | |
556 | u"5.43°"); | |
557 | ||
558 | assertFormatSingle( | |
559 | u"Difference between Narrow and Short (Short Version)", | |
560 | u"measure-unit/temperature-fahrenheit unit-width-short", | |
561 | NumberFormatter::with().unit(FAHRENHEIT).unitWidth(UNUM_UNIT_WIDTH_SHORT), | |
562 | Locale("es-US"), | |
563 | 5.43, | |
564 | u"5.43°F"); | |
565 | ||
566 | assertFormatSingle( | |
567 | u"MeasureUnit form without {0} in CLDR pattern", | |
568 | u"measure-unit/temperature-kelvin unit-width-full-name", | |
569 | NumberFormatter::with().unit(KELVIN).unitWidth(UNumberUnitWidth::UNUM_UNIT_WIDTH_FULL_NAME), | |
570 | Locale("es-MX"), | |
571 | 1, | |
572 | u"kelvin"); | |
573 | ||
574 | assertFormatSingle( | |
575 | u"MeasureUnit form without {0} in CLDR pattern and wide base form", | |
576 | u"measure-unit/temperature-kelvin .00000000000000000000 unit-width-full-name", | |
577 | NumberFormatter::with().precision(Precision::fixedFraction(20)) | |
578 | .unit(KELVIN) | |
579 | .unitWidth(UNumberUnitWidth::UNUM_UNIT_WIDTH_FULL_NAME), | |
580 | Locale("es-MX"), | |
581 | 1, | |
582 | u"kelvin"); | |
3d1f044b A |
583 | |
584 | assertFormatSingle( | |
585 | u"Person unit not in short form", | |
586 | u"measure-unit/duration-year-person unit-width-full-name", | |
587 | NumberFormatter::with().unit(MeasureUnit::getYearPerson()) | |
588 | .unitWidth(UNumberUnitWidth::UNUM_UNIT_WIDTH_FULL_NAME), | |
589 | Locale("es-MX"), | |
590 | 5, | |
591 | u"5 a\u00F1os"); | |
0f5d89e8 A |
592 | } |
593 | ||
594 | void NumberFormatterApiTest::unitCompoundMeasure() { | |
595 | assertFormatDescending( | |
596 | u"Meters Per Second Short (unit that simplifies) and perUnit method", | |
597 | u"measure-unit/length-meter per-measure-unit/duration-second", | |
598 | NumberFormatter::with().unit(METER).perUnit(SECOND), | |
599 | Locale::getEnglish(), | |
600 | u"87,650 m/s", | |
601 | u"8,765 m/s", | |
602 | u"876.5 m/s", | |
603 | u"87.65 m/s", | |
604 | u"8.765 m/s", | |
605 | u"0.8765 m/s", | |
606 | u"0.08765 m/s", | |
607 | u"0.008765 m/s", | |
608 | u"0 m/s"); | |
609 | ||
610 | assertFormatDescending( | |
611 | u"Pounds Per Square Mile Short (secondary unit has per-format) and adoptPerUnit method", | |
612 | u"measure-unit/mass-pound per-measure-unit/area-square-mile", | |
613 | NumberFormatter::with().unit(POUND).adoptPerUnit(new MeasureUnit(SQUARE_MILE)), | |
614 | Locale::getEnglish(), | |
615 | u"87,650 lb/mi²", | |
616 | u"8,765 lb/mi²", | |
617 | u"876.5 lb/mi²", | |
618 | u"87.65 lb/mi²", | |
619 | u"8.765 lb/mi²", | |
620 | u"0.8765 lb/mi²", | |
621 | u"0.08765 lb/mi²", | |
622 | u"0.008765 lb/mi²", | |
623 | u"0 lb/mi²"); | |
624 | ||
625 | assertFormatDescending( | |
626 | u"Joules Per Furlong Short (unit with no simplifications or special patterns)", | |
627 | u"measure-unit/energy-joule per-measure-unit/length-furlong", | |
628 | NumberFormatter::with().unit(JOULE).perUnit(FURLONG), | |
629 | Locale::getEnglish(), | |
630 | u"87,650 J/fur", | |
631 | u"8,765 J/fur", | |
632 | u"876.5 J/fur", | |
633 | u"87.65 J/fur", | |
634 | u"8.765 J/fur", | |
635 | u"0.8765 J/fur", | |
636 | u"0.08765 J/fur", | |
637 | u"0.008765 J/fur", | |
638 | u"0 J/fur"); | |
639 | } | |
640 | ||
641 | void NumberFormatterApiTest::unitCurrency() { | |
642 | assertFormatDescending( | |
643 | u"Currency", | |
644 | u"currency/GBP", | |
645 | NumberFormatter::with().unit(GBP), | |
646 | Locale::getEnglish(), | |
647 | u"£87,650.00", | |
648 | u"£8,765.00", | |
649 | u"£876.50", | |
650 | u"£87.65", | |
651 | u"£8.76", | |
652 | u"£0.88", | |
653 | u"£0.09", | |
654 | u"£0.01", | |
655 | u"£0.00"); | |
656 | ||
657 | assertFormatDescending( | |
658 | u"Currency ISO", | |
659 | u"currency/GBP unit-width-iso-code", | |
660 | NumberFormatter::with().unit(GBP).unitWidth(UNumberUnitWidth::UNUM_UNIT_WIDTH_ISO_CODE), | |
661 | Locale::getEnglish(), | |
662 | u"GBP 87,650.00", | |
663 | u"GBP 8,765.00", | |
664 | u"GBP 876.50", | |
665 | u"GBP 87.65", | |
666 | u"GBP 8.76", | |
667 | u"GBP 0.88", | |
668 | u"GBP 0.09", | |
669 | u"GBP 0.01", | |
670 | u"GBP 0.00"); | |
671 | ||
672 | assertFormatDescending( | |
673 | u"Currency Long Name", | |
674 | u"currency/GBP unit-width-full-name", | |
675 | NumberFormatter::with().unit(GBP).unitWidth(UNumberUnitWidth::UNUM_UNIT_WIDTH_FULL_NAME), | |
676 | Locale::getEnglish(), | |
677 | u"87,650.00 British pounds", | |
678 | u"8,765.00 British pounds", | |
679 | u"876.50 British pounds", | |
680 | u"87.65 British pounds", | |
681 | u"8.76 British pounds", | |
682 | u"0.88 British pounds", | |
683 | u"0.09 British pounds", | |
684 | u"0.01 British pounds", | |
685 | u"0.00 British pounds"); | |
686 | ||
687 | assertFormatDescending( | |
688 | u"Currency Hidden", | |
689 | u"currency/GBP unit-width-hidden", | |
690 | NumberFormatter::with().unit(GBP).unitWidth(UNUM_UNIT_WIDTH_HIDDEN), | |
691 | Locale::getEnglish(), | |
692 | u"87,650.00", | |
693 | u"8,765.00", | |
694 | u"876.50", | |
695 | u"87.65", | |
696 | u"8.76", | |
697 | u"0.88", | |
698 | u"0.09", | |
699 | u"0.01", | |
700 | u"0.00"); | |
701 | ||
702 | // TODO: Implement Measure in C++ | |
703 | // assertFormatSingleMeasure( | |
704 | // u"Currency with CurrencyAmount Input", | |
705 | // NumberFormatter::with(), | |
706 | // Locale::getEnglish(), | |
707 | // new CurrencyAmount(5.43, GBP), | |
708 | // u"£5.43"); | |
709 | ||
710 | // TODO: Enable this test when DecimalFormat wrapper is done. | |
711 | // assertFormatSingle( | |
712 | // u"Currency Long Name from Pattern Syntax", NumberFormatter.fromDecimalFormat( | |
713 | // PatternStringParser.parseToProperties("0 ¤¤¤"), | |
714 | // DecimalFormatSymbols.getInstance(Locale::getEnglish()), | |
715 | // null).unit(GBP), Locale::getEnglish(), 1234567.89, u"1234568 British pounds"); | |
716 | ||
717 | assertFormatSingle( | |
718 | u"Currency with Negative Sign", | |
719 | u"currency/GBP", | |
720 | NumberFormatter::with().unit(GBP), | |
721 | Locale::getEnglish(), | |
722 | -9876543.21, | |
723 | u"-£9,876,543.21"); | |
724 | ||
725 | // The full currency symbol is not shown in NARROW format. | |
726 | // NOTE: This example is in the documentation. | |
727 | assertFormatSingle( | |
728 | u"Currency Difference between Narrow and Short (Narrow Version)", | |
729 | u"currency/USD unit-width-narrow", | |
730 | NumberFormatter::with().unit(USD).unitWidth(UNUM_UNIT_WIDTH_NARROW), | |
731 | Locale("en-CA"), | |
732 | 5.43, | |
733 | u"$5.43"); | |
734 | ||
735 | assertFormatSingle( | |
736 | u"Currency Difference between Narrow and Short (Short Version)", | |
737 | u"currency/USD unit-width-short", | |
738 | NumberFormatter::with().unit(USD).unitWidth(UNUM_UNIT_WIDTH_SHORT), | |
739 | Locale("en-CA"), | |
740 | 5.43, | |
741 | u"US$5.43"); | |
742 | ||
743 | assertFormatSingle( | |
744 | u"Currency-dependent format (Control)", | |
745 | u"currency/USD unit-width-short", | |
746 | NumberFormatter::with().unit(USD).unitWidth(UNUM_UNIT_WIDTH_SHORT), | |
747 | Locale("ca"), | |
748 | 444444.55, | |
749 | u"444.444,55 USD"); | |
750 | ||
751 | assertFormatSingle( | |
752 | u"Currency-dependent format (Test)", | |
753 | u"currency/ESP unit-width-short", | |
754 | NumberFormatter::with().unit(ESP).unitWidth(UNUM_UNIT_WIDTH_SHORT), | |
755 | Locale("ca"), | |
756 | 444444.55, | |
757 | u"₧ 444.445"); | |
758 | ||
759 | assertFormatSingle( | |
760 | u"Currency-dependent symbols (Control)", | |
761 | u"currency/USD unit-width-short", | |
762 | NumberFormatter::with().unit(USD).unitWidth(UNUM_UNIT_WIDTH_SHORT), | |
763 | Locale("pt-PT"), | |
764 | 444444.55, | |
765 | u"444 444,55 US$"); | |
766 | ||
767 | // NOTE: This is a bit of a hack on CLDR's part. They set the currency symbol to U+200B (zero- | |
768 | // width space), and they set the decimal separator to the $ symbol. | |
769 | assertFormatSingle( | |
770 | u"Currency-dependent symbols (Test Short)", | |
771 | u"currency/PTE unit-width-short", | |
772 | NumberFormatter::with().unit(PTE).unitWidth(UNUM_UNIT_WIDTH_SHORT), | |
773 | Locale("pt-PT"), | |
774 | 444444.55, | |
775 | u"444,444$55 \u200B"); | |
776 | ||
777 | assertFormatSingle( | |
778 | u"Currency-dependent symbols (Test Narrow)", | |
779 | u"currency/PTE unit-width-narrow", | |
780 | NumberFormatter::with().unit(PTE).unitWidth(UNUM_UNIT_WIDTH_NARROW), | |
781 | Locale("pt-PT"), | |
782 | 444444.55, | |
3d1f044b | 783 | u"444,444$55 \u200B"); |
0f5d89e8 A |
784 | |
785 | assertFormatSingle( | |
786 | u"Currency-dependent symbols (Test ISO Code)", | |
787 | u"currency/PTE unit-width-iso-code", | |
788 | NumberFormatter::with().unit(PTE).unitWidth(UNUM_UNIT_WIDTH_ISO_CODE), | |
789 | Locale("pt-PT"), | |
790 | 444444.55, | |
791 | u"444,444$55 PTE"); | |
3d1f044b A |
792 | |
793 | assertFormatSingle( | |
794 | u"Plural form depending on visible digits (ICU-20499)", | |
795 | u"currency/RON unit-width-full-name", | |
796 | NumberFormatter::with().unit(RON).unitWidth(UNUM_UNIT_WIDTH_FULL_NAME), | |
797 | Locale("ro-RO"), | |
798 | 24, | |
799 | u"24,00 lei românești"); | |
0f5d89e8 A |
800 | } |
801 | ||
802 | void NumberFormatterApiTest::unitPercent() { | |
803 | assertFormatDescending( | |
804 | u"Percent", | |
805 | u"percent", | |
806 | NumberFormatter::with().unit(NoUnit::percent()), | |
807 | Locale::getEnglish(), | |
808 | u"87,650%", | |
809 | u"8,765%", | |
810 | u"876.5%", | |
811 | u"87.65%", | |
812 | u"8.765%", | |
813 | u"0.8765%", | |
814 | u"0.08765%", | |
815 | u"0.008765%", | |
816 | u"0%"); | |
817 | ||
818 | assertFormatDescending( | |
819 | u"Permille", | |
820 | u"permille", | |
821 | NumberFormatter::with().unit(NoUnit::permille()), | |
822 | Locale::getEnglish(), | |
823 | u"87,650‰", | |
824 | u"8,765‰", | |
825 | u"876.5‰", | |
826 | u"87.65‰", | |
827 | u"8.765‰", | |
828 | u"0.8765‰", | |
829 | u"0.08765‰", | |
830 | u"0.008765‰", | |
831 | u"0‰"); | |
832 | ||
833 | assertFormatSingle( | |
834 | u"NoUnit Base", | |
835 | u"base-unit", | |
836 | NumberFormatter::with().unit(NoUnit::base()), | |
837 | Locale::getEnglish(), | |
838 | 51423, | |
839 | u"51,423"); | |
840 | ||
841 | assertFormatSingle( | |
842 | u"Percent with Negative Sign", | |
843 | u"percent", | |
844 | NumberFormatter::with().unit(NoUnit::percent()), | |
845 | Locale::getEnglish(), | |
846 | -98.7654321, | |
847 | u"-98.765432%"); | |
848 | } | |
849 | ||
3d1f044b A |
850 | void NumberFormatterApiTest::percentParity() { |
851 | IcuTestErrorCode status(*this, "percentParity"); | |
852 | UnlocalizedNumberFormatter uNoUnitPercent = NumberFormatter::with().unit(NoUnit::percent()); | |
853 | UnlocalizedNumberFormatter uNoUnitPermille = NumberFormatter::with().unit(NoUnit::permille()); | |
854 | UnlocalizedNumberFormatter uMeasurePercent = NumberFormatter::with().unit(MeasureUnit::getPercent()); | |
855 | UnlocalizedNumberFormatter uMeasurePermille = NumberFormatter::with().unit(MeasureUnit::getPermille()); | |
856 | ||
857 | int32_t localeCount; | |
858 | auto locales = Locale::getAvailableLocales(localeCount); | |
859 | for (int32_t i=0; i<localeCount; i++) { | |
860 | auto& locale = locales[i]; | |
861 | UnicodeString sNoUnitPercent = uNoUnitPercent.locale(locale) | |
862 | .formatDouble(50, status).toString(status); | |
863 | UnicodeString sNoUnitPermille = uNoUnitPermille.locale(locale) | |
864 | .formatDouble(50, status).toString(status); | |
865 | UnicodeString sMeasurePercent = uMeasurePercent.locale(locale) | |
866 | .formatDouble(50, status).toString(status); | |
867 | UnicodeString sMeasurePermille = uMeasurePermille.locale(locale) | |
868 | .formatDouble(50, status).toString(status); | |
869 | ||
870 | assertEquals(u"Percent, locale " + UnicodeString(locale.getName()), | |
871 | sNoUnitPercent, sMeasurePercent); | |
872 | assertEquals(u"Permille, locale " + UnicodeString(locale.getName()), | |
873 | sNoUnitPermille, sMeasurePermille); | |
874 | } | |
875 | } | |
876 | ||
0f5d89e8 A |
877 | void NumberFormatterApiTest::roundingFraction() { |
878 | assertFormatDescending( | |
879 | u"Integer", | |
880 | u"precision-integer", | |
881 | NumberFormatter::with().precision(Precision::integer()), | |
882 | Locale::getEnglish(), | |
883 | u"87,650", | |
884 | u"8,765", | |
885 | u"876", | |
886 | u"88", | |
887 | u"9", | |
888 | u"1", | |
889 | u"0", | |
890 | u"0", | |
891 | u"0"); | |
892 | ||
893 | assertFormatDescending( | |
894 | u"Fixed Fraction", | |
895 | u".000", | |
896 | NumberFormatter::with().precision(Precision::fixedFraction(3)), | |
897 | Locale::getEnglish(), | |
898 | u"87,650.000", | |
899 | u"8,765.000", | |
900 | u"876.500", | |
901 | u"87.650", | |
902 | u"8.765", | |
903 | u"0.876", | |
904 | u"0.088", | |
905 | u"0.009", | |
906 | u"0.000"); | |
907 | ||
908 | assertFormatDescending( | |
909 | u"Min Fraction", | |
910 | u".0+", | |
911 | NumberFormatter::with().precision(Precision::minFraction(1)), | |
912 | Locale::getEnglish(), | |
913 | u"87,650.0", | |
914 | u"8,765.0", | |
915 | u"876.5", | |
916 | u"87.65", | |
917 | u"8.765", | |
918 | u"0.8765", | |
919 | u"0.08765", | |
920 | u"0.008765", | |
921 | u"0.0"); | |
922 | ||
923 | assertFormatDescending( | |
924 | u"Max Fraction", | |
925 | u".#", | |
926 | NumberFormatter::with().precision(Precision::maxFraction(1)), | |
927 | Locale::getEnglish(), | |
928 | u"87,650", | |
929 | u"8,765", | |
930 | u"876.5", | |
931 | u"87.6", | |
932 | u"8.8", | |
933 | u"0.9", | |
934 | u"0.1", | |
935 | u"0", | |
936 | u"0"); | |
937 | ||
938 | assertFormatDescending( | |
939 | u"Min/Max Fraction", | |
940 | u".0##", | |
941 | NumberFormatter::with().precision(Precision::minMaxFraction(1, 3)), | |
942 | Locale::getEnglish(), | |
943 | u"87,650.0", | |
944 | u"8,765.0", | |
945 | u"876.5", | |
946 | u"87.65", | |
947 | u"8.765", | |
948 | u"0.876", | |
949 | u"0.088", | |
950 | u"0.009", | |
951 | u"0.0"); | |
952 | } | |
953 | ||
954 | void NumberFormatterApiTest::roundingFigures() { | |
955 | assertFormatSingle( | |
956 | u"Fixed Significant", | |
957 | u"@@@", | |
958 | NumberFormatter::with().precision(Precision::fixedSignificantDigits(3)), | |
959 | Locale::getEnglish(), | |
960 | -98, | |
961 | u"-98.0"); | |
962 | ||
963 | assertFormatSingle( | |
964 | u"Fixed Significant Rounding", | |
965 | u"@@@", | |
966 | NumberFormatter::with().precision(Precision::fixedSignificantDigits(3)), | |
967 | Locale::getEnglish(), | |
968 | -98.7654321, | |
969 | u"-98.8"); | |
970 | ||
971 | assertFormatSingle( | |
972 | u"Fixed Significant Zero", | |
973 | u"@@@", | |
974 | NumberFormatter::with().precision(Precision::fixedSignificantDigits(3)), | |
975 | Locale::getEnglish(), | |
976 | 0, | |
977 | u"0.00"); | |
978 | ||
979 | assertFormatSingle( | |
980 | u"Min Significant", | |
981 | u"@@+", | |
982 | NumberFormatter::with().precision(Precision::minSignificantDigits(2)), | |
983 | Locale::getEnglish(), | |
984 | -9, | |
985 | u"-9.0"); | |
986 | ||
987 | assertFormatSingle( | |
988 | u"Max Significant", | |
989 | u"@###", | |
990 | NumberFormatter::with().precision(Precision::maxSignificantDigits(4)), | |
991 | Locale::getEnglish(), | |
992 | 98.7654321, | |
993 | u"98.77"); | |
994 | ||
995 | assertFormatSingle( | |
996 | u"Min/Max Significant", | |
997 | u"@@@#", | |
998 | NumberFormatter::with().precision(Precision::minMaxSignificantDigits(3, 4)), | |
999 | Locale::getEnglish(), | |
1000 | 9.99999, | |
1001 | u"10.0"); | |
1002 | ||
1003 | assertFormatSingle( | |
1004 | u"Fixed Significant on zero with lots of integer width", | |
1005 | u"@ integer-width/+000", | |
1006 | NumberFormatter::with().precision(Precision::fixedSignificantDigits(1)) | |
1007 | .integerWidth(IntegerWidth::zeroFillTo(3)), | |
1008 | Locale::getEnglish(), | |
1009 | 0, | |
1010 | "000"); | |
1011 | ||
1012 | assertFormatSingle( | |
1013 | u"Fixed Significant on zero with zero integer width", | |
1014 | u"@ integer-width/+", | |
1015 | NumberFormatter::with().precision(Precision::fixedSignificantDigits(1)) | |
1016 | .integerWidth(IntegerWidth::zeroFillTo(0)), | |
1017 | Locale::getEnglish(), | |
1018 | 0, | |
1019 | "0"); | |
1020 | } | |
1021 | ||
1022 | void NumberFormatterApiTest::roundingFractionFigures() { | |
1023 | assertFormatDescending( | |
1024 | u"Basic Significant", // for comparison | |
1025 | u"@#", | |
1026 | NumberFormatter::with().precision(Precision::maxSignificantDigits(2)), | |
1027 | Locale::getEnglish(), | |
1028 | u"88,000", | |
1029 | u"8,800", | |
1030 | u"880", | |
1031 | u"88", | |
1032 | u"8.8", | |
1033 | u"0.88", | |
1034 | u"0.088", | |
1035 | u"0.0088", | |
1036 | u"0"); | |
1037 | ||
1038 | assertFormatDescending( | |
1039 | u"FracSig minMaxFrac minSig", | |
1040 | u".0#/@@@+", | |
1041 | NumberFormatter::with().precision(Precision::minMaxFraction(1, 2).withMinDigits(3)), | |
1042 | Locale::getEnglish(), | |
1043 | u"87,650.0", | |
1044 | u"8,765.0", | |
1045 | u"876.5", | |
1046 | u"87.65", | |
1047 | u"8.76", | |
1048 | u"0.876", // minSig beats maxFrac | |
1049 | u"0.0876", // minSig beats maxFrac | |
1050 | u"0.00876", // minSig beats maxFrac | |
1051 | u"0.0"); | |
1052 | ||
1053 | assertFormatDescending( | |
1054 | u"FracSig minMaxFrac maxSig A", | |
1055 | u".0##/@#", | |
1056 | NumberFormatter::with().precision(Precision::minMaxFraction(1, 3).withMaxDigits(2)), | |
1057 | Locale::getEnglish(), | |
1058 | u"88,000.0", // maxSig beats maxFrac | |
1059 | u"8,800.0", // maxSig beats maxFrac | |
1060 | u"880.0", // maxSig beats maxFrac | |
1061 | u"88.0", // maxSig beats maxFrac | |
1062 | u"8.8", // maxSig beats maxFrac | |
1063 | u"0.88", // maxSig beats maxFrac | |
1064 | u"0.088", | |
1065 | u"0.009", | |
1066 | u"0.0"); | |
1067 | ||
1068 | assertFormatDescending( | |
1069 | u"FracSig minMaxFrac maxSig B", | |
1070 | u".00/@#", | |
1071 | NumberFormatter::with().precision(Precision::fixedFraction(2).withMaxDigits(2)), | |
1072 | Locale::getEnglish(), | |
1073 | u"88,000.00", // maxSig beats maxFrac | |
1074 | u"8,800.00", // maxSig beats maxFrac | |
1075 | u"880.00", // maxSig beats maxFrac | |
1076 | u"88.00", // maxSig beats maxFrac | |
1077 | u"8.80", // maxSig beats maxFrac | |
1078 | u"0.88", | |
1079 | u"0.09", | |
1080 | u"0.01", | |
1081 | u"0.00"); | |
1082 | ||
1083 | assertFormatSingle( | |
1084 | u"FracSig with trailing zeros A", | |
1085 | u".00/@@@+", | |
1086 | NumberFormatter::with().precision(Precision::fixedFraction(2).withMinDigits(3)), | |
1087 | Locale::getEnglish(), | |
1088 | 0.1, | |
1089 | u"0.10"); | |
1090 | ||
1091 | assertFormatSingle( | |
1092 | u"FracSig with trailing zeros B", | |
1093 | u".00/@@@+", | |
1094 | NumberFormatter::with().precision(Precision::fixedFraction(2).withMinDigits(3)), | |
1095 | Locale::getEnglish(), | |
1096 | 0.0999999, | |
1097 | u"0.10"); | |
1098 | } | |
1099 | ||
1100 | void NumberFormatterApiTest::roundingOther() { | |
1101 | assertFormatDescending( | |
1102 | u"Rounding None", | |
1103 | u"precision-unlimited", | |
1104 | NumberFormatter::with().precision(Precision::unlimited()), | |
1105 | Locale::getEnglish(), | |
1106 | u"87,650", | |
1107 | u"8,765", | |
1108 | u"876.5", | |
1109 | u"87.65", | |
1110 | u"8.765", | |
1111 | u"0.8765", | |
1112 | u"0.08765", | |
1113 | u"0.008765", | |
1114 | u"0"); | |
1115 | ||
1116 | assertFormatDescending( | |
1117 | u"Increment", | |
1118 | u"precision-increment/0.5", | |
1119 | NumberFormatter::with().precision(Precision::increment(0.5).withMinFraction(1)), | |
1120 | Locale::getEnglish(), | |
1121 | u"87,650.0", | |
1122 | u"8,765.0", | |
1123 | u"876.5", | |
1124 | u"87.5", | |
1125 | u"9.0", | |
1126 | u"1.0", | |
1127 | u"0.0", | |
1128 | u"0.0", | |
1129 | u"0.0"); | |
1130 | ||
1131 | assertFormatDescending( | |
1132 | u"Increment with Min Fraction", | |
1133 | u"precision-increment/0.50", | |
1134 | NumberFormatter::with().precision(Precision::increment(0.5).withMinFraction(2)), | |
1135 | Locale::getEnglish(), | |
1136 | u"87,650.00", | |
1137 | u"8,765.00", | |
1138 | u"876.50", | |
1139 | u"87.50", | |
1140 | u"9.00", | |
1141 | u"1.00", | |
1142 | u"0.00", | |
1143 | u"0.00", | |
1144 | u"0.00"); | |
1145 | ||
3d1f044b A |
1146 | assertFormatDescending( |
1147 | u"Strange Increment", | |
1148 | u"precision-increment/3.140", | |
1149 | NumberFormatter::with().precision(Precision::increment(3.14).withMinFraction(3)), | |
1150 | Locale::getEnglish(), | |
1151 | u"87,649.960", | |
1152 | u"8,763.740", | |
1153 | u"876.060", | |
1154 | u"87.920", | |
1155 | u"9.420", | |
1156 | u"0.000", | |
1157 | u"0.000", | |
1158 | u"0.000", | |
1159 | u"0.000"); | |
1160 | ||
1161 | assertFormatDescending( | |
1162 | u"Increment Resolving to Power of 10", | |
1163 | u"precision-increment/0.010", | |
1164 | NumberFormatter::with().precision(Precision::increment(0.01).withMinFraction(3)), | |
1165 | Locale::getEnglish(), | |
1166 | u"87,650.000", | |
1167 | u"8,765.000", | |
1168 | u"876.500", | |
1169 | u"87.650", | |
1170 | u"8.760", | |
1171 | u"0.880", | |
1172 | u"0.090", | |
1173 | u"0.010", | |
1174 | u"0.000"); | |
1175 | ||
0f5d89e8 A |
1176 | assertFormatDescending( |
1177 | u"Currency Standard", | |
1178 | u"currency/CZK precision-currency-standard", | |
1179 | NumberFormatter::with().precision(Precision::currency(UCurrencyUsage::UCURR_USAGE_STANDARD)) | |
1180 | .unit(CZK), | |
1181 | Locale::getEnglish(), | |
1182 | u"CZK 87,650.00", | |
1183 | u"CZK 8,765.00", | |
1184 | u"CZK 876.50", | |
1185 | u"CZK 87.65", | |
1186 | u"CZK 8.76", | |
1187 | u"CZK 0.88", | |
1188 | u"CZK 0.09", | |
1189 | u"CZK 0.01", | |
1190 | u"CZK 0.00"); | |
1191 | ||
1192 | assertFormatDescending( | |
1193 | u"Currency Cash", | |
1194 | u"currency/CZK precision-currency-cash", | |
1195 | NumberFormatter::with().precision(Precision::currency(UCurrencyUsage::UCURR_USAGE_CASH)) | |
1196 | .unit(CZK), | |
1197 | Locale::getEnglish(), | |
1198 | u"CZK 87,650", | |
1199 | u"CZK 8,765", | |
1200 | u"CZK 876", | |
1201 | u"CZK 88", | |
1202 | u"CZK 9", | |
1203 | u"CZK 1", | |
1204 | u"CZK 0", | |
1205 | u"CZK 0", | |
1206 | u"CZK 0"); | |
1207 | ||
1208 | assertFormatDescending( | |
1209 | u"Currency Cash with Nickel Rounding", | |
1210 | u"currency/CAD precision-currency-cash", | |
1211 | NumberFormatter::with().precision(Precision::currency(UCurrencyUsage::UCURR_USAGE_CASH)) | |
1212 | .unit(CAD), | |
1213 | Locale::getEnglish(), | |
1214 | u"CA$87,650.00", | |
1215 | u"CA$8,765.00", | |
1216 | u"CA$876.50", | |
1217 | u"CA$87.65", | |
1218 | u"CA$8.75", | |
1219 | u"CA$0.90", | |
1220 | u"CA$0.10", | |
1221 | u"CA$0.00", | |
1222 | u"CA$0.00"); | |
1223 | ||
1224 | assertFormatDescending( | |
1225 | u"Currency not in top-level fluent chain", | |
1226 | u"precision-integer", // calling .withCurrency() applies currency rounding rules immediately | |
1227 | NumberFormatter::with().precision( | |
1228 | Precision::currency(UCurrencyUsage::UCURR_USAGE_CASH).withCurrency(CZK)), | |
1229 | Locale::getEnglish(), | |
1230 | u"87,650", | |
1231 | u"8,765", | |
1232 | u"876", | |
1233 | u"88", | |
1234 | u"9", | |
1235 | u"1", | |
1236 | u"0", | |
1237 | u"0", | |
1238 | u"0"); | |
1239 | ||
1240 | // NOTE: Other tests cover the behavior of the other rounding modes. | |
1241 | assertFormatDescending( | |
1242 | u"Rounding Mode CEILING", | |
1243 | u"precision-integer rounding-mode-ceiling", | |
1244 | NumberFormatter::with().precision(Precision::integer()).roundingMode(UNUM_ROUND_CEILING), | |
1245 | Locale::getEnglish(), | |
1246 | u"87,650", | |
1247 | u"8,765", | |
1248 | u"877", | |
1249 | u"88", | |
1250 | u"9", | |
1251 | u"1", | |
1252 | u"1", | |
1253 | u"1", | |
1254 | u"0"); | |
1255 | } | |
1256 | ||
1257 | void NumberFormatterApiTest::grouping() { | |
1258 | assertFormatDescendingBig( | |
1259 | u"Western Grouping", | |
1260 | u"group-auto", | |
1261 | NumberFormatter::with().grouping(UNUM_GROUPING_AUTO), | |
1262 | Locale::getEnglish(), | |
1263 | u"87,650,000", | |
1264 | u"8,765,000", | |
1265 | u"876,500", | |
1266 | u"87,650", | |
1267 | u"8,765", | |
1268 | u"876.5", | |
1269 | u"87.65", | |
1270 | u"8.765", | |
1271 | u"0"); | |
1272 | ||
1273 | assertFormatDescendingBig( | |
1274 | u"Indic Grouping", | |
1275 | u"group-auto", | |
1276 | NumberFormatter::with().grouping(UNUM_GROUPING_AUTO), | |
1277 | Locale("en-IN"), | |
1278 | u"8,76,50,000", | |
1279 | u"87,65,000", | |
1280 | u"8,76,500", | |
1281 | u"87,650", | |
1282 | u"8,765", | |
1283 | u"876.5", | |
1284 | u"87.65", | |
1285 | u"8.765", | |
1286 | u"0"); | |
1287 | ||
1288 | assertFormatDescendingBig( | |
1289 | u"Western Grouping, Min 2", | |
1290 | u"group-min2", | |
1291 | NumberFormatter::with().grouping(UNUM_GROUPING_MIN2), | |
1292 | Locale::getEnglish(), | |
1293 | u"87,650,000", | |
1294 | u"8,765,000", | |
1295 | u"876,500", | |
1296 | u"87,650", | |
1297 | u"8765", | |
1298 | u"876.5", | |
1299 | u"87.65", | |
1300 | u"8.765", | |
1301 | u"0"); | |
1302 | ||
1303 | assertFormatDescendingBig( | |
1304 | u"Indic Grouping, Min 2", | |
1305 | u"group-min2", | |
1306 | NumberFormatter::with().grouping(UNUM_GROUPING_MIN2), | |
1307 | Locale("en-IN"), | |
1308 | u"8,76,50,000", | |
1309 | u"87,65,000", | |
1310 | u"8,76,500", | |
1311 | u"87,650", | |
1312 | u"8765", | |
1313 | u"876.5", | |
1314 | u"87.65", | |
1315 | u"8.765", | |
1316 | u"0"); | |
1317 | ||
1318 | assertFormatDescendingBig( | |
1319 | u"No Grouping", | |
1320 | u"group-off", | |
1321 | NumberFormatter::with().grouping(UNUM_GROUPING_OFF), | |
1322 | Locale("en-IN"), | |
1323 | u"87650000", | |
1324 | u"8765000", | |
1325 | u"876500", | |
1326 | u"87650", | |
1327 | u"8765", | |
1328 | u"876.5", | |
1329 | u"87.65", | |
1330 | u"8.765", | |
1331 | u"0"); | |
1332 | ||
1333 | assertFormatDescendingBig( | |
1334 | u"Indic locale with THOUSANDS grouping", | |
1335 | u"group-thousands", | |
1336 | NumberFormatter::with().grouping(UNUM_GROUPING_THOUSANDS), | |
1337 | Locale("en-IN"), | |
1338 | u"87,650,000", | |
1339 | u"8,765,000", | |
1340 | u"876,500", | |
1341 | u"87,650", | |
1342 | u"8,765", | |
1343 | u"876.5", | |
1344 | u"87.65", | |
1345 | u"8.765", | |
1346 | u"0"); | |
1347 | ||
1a147d09 A |
1348 | // NOTE: Hungarian was interesting because it had minimumGroupingDigits=4 in locale data. |
1349 | // Open source has fixed Hungarian to have minimumGroupingDigits=1 and changed this test to | |
1350 | // use Polish with minimumGroupingDigits=2. However for now we keep the test using Hungarian | |
1351 | // to verify the change. | |
0f5d89e8 A |
1352 | assertFormatDescendingBig( |
1353 | u"Hungarian Grouping", | |
1354 | u"group-auto", | |
1355 | NumberFormatter::with().grouping(UNUM_GROUPING_AUTO), | |
1356 | Locale("hu"), | |
1357 | u"87 650 000", | |
1358 | u"8 765 000", | |
1a147d09 A |
1359 | u"876 500", |
1360 | u"87 650", | |
1361 | u"8 765", | |
0f5d89e8 A |
1362 | u"876,5", |
1363 | u"87,65", | |
1364 | u"8,765", | |
1365 | u"0"); | |
1366 | ||
1367 | assertFormatDescendingBig( | |
1368 | u"Hungarian Grouping, Min 2", | |
1369 | u"group-min2", | |
1370 | NumberFormatter::with().grouping(UNUM_GROUPING_MIN2), | |
1371 | Locale("hu"), | |
1372 | u"87 650 000", | |
1373 | u"8 765 000", | |
1a147d09 A |
1374 | u"876 500", |
1375 | u"87 650", | |
0f5d89e8 A |
1376 | u"8765", |
1377 | u"876,5", | |
1378 | u"87,65", | |
1379 | u"8,765", | |
1380 | u"0"); | |
1381 | ||
1382 | assertFormatDescendingBig( | |
1383 | u"Hungarian Grouping, Always", | |
1384 | u"group-on-aligned", | |
1385 | NumberFormatter::with().grouping(UNUM_GROUPING_ON_ALIGNED), | |
1386 | Locale("hu"), | |
1387 | u"87 650 000", | |
1388 | u"8 765 000", | |
1389 | u"876 500", | |
1390 | u"87 650", | |
1391 | u"8 765", | |
1392 | u"876,5", | |
1393 | u"87,65", | |
1394 | u"8,765", | |
1395 | u"0"); | |
1396 | ||
1397 | // NOTE: Bulgarian is interesting because it has no grouping in the default currency format. | |
1398 | // If this test breaks due to data changes, find another locale that has no default grouping. | |
1399 | assertFormatDescendingBig( | |
1400 | u"Bulgarian Currency Grouping", | |
1401 | u"currency/USD group-auto", | |
1402 | NumberFormatter::with().grouping(UNUM_GROUPING_AUTO).unit(USD), | |
1403 | Locale("bg"), | |
1404 | u"87650000,00 щ.д.", | |
1405 | u"8765000,00 щ.д.", | |
1406 | u"876500,00 щ.д.", | |
1407 | u"87650,00 щ.д.", | |
1408 | u"8765,00 щ.д.", | |
1409 | u"876,50 щ.д.", | |
1410 | u"87,65 щ.д.", | |
1411 | u"8,76 щ.д.", | |
1412 | u"0,00 щ.д."); | |
1413 | ||
1414 | assertFormatDescendingBig( | |
1415 | u"Bulgarian Currency Grouping, Always", | |
1416 | u"currency/USD group-on-aligned", | |
1417 | NumberFormatter::with().grouping(UNUM_GROUPING_ON_ALIGNED).unit(USD), | |
1418 | Locale("bg"), | |
1419 | u"87 650 000,00 щ.д.", | |
1420 | u"8 765 000,00 щ.д.", | |
1421 | u"876 500,00 щ.д.", | |
1422 | u"87 650,00 щ.д.", | |
1423 | u"8 765,00 щ.д.", | |
1424 | u"876,50 щ.д.", | |
1425 | u"87,65 щ.д.", | |
1426 | u"8,76 щ.д.", | |
1427 | u"0,00 щ.д."); | |
1428 | ||
1429 | MacroProps macros; | |
1430 | macros.grouper = Grouper(4, 1, 3, UNUM_GROUPING_COUNT); | |
1431 | assertFormatDescendingBig( | |
1432 | u"Custom Grouping via Internal API", | |
1433 | nullptr, | |
1434 | NumberFormatter::with().macros(macros), | |
1435 | Locale::getEnglish(), | |
1436 | u"8,7,6,5,0000", | |
1437 | u"8,7,6,5000", | |
1438 | u"876500", | |
1439 | u"87650", | |
1440 | u"8765", | |
1441 | u"876.5", | |
1442 | u"87.65", | |
1443 | u"8.765", | |
1444 | u"0"); | |
1445 | } | |
1446 | ||
1447 | void NumberFormatterApiTest::padding() { | |
1448 | assertFormatDescending( | |
1449 | u"Padding", | |
1450 | nullptr, | |
1451 | NumberFormatter::with().padding(Padder::none()), | |
1452 | Locale::getEnglish(), | |
1453 | u"87,650", | |
1454 | u"8,765", | |
1455 | u"876.5", | |
1456 | u"87.65", | |
1457 | u"8.765", | |
1458 | u"0.8765", | |
1459 | u"0.08765", | |
1460 | u"0.008765", | |
1461 | u"0"); | |
1462 | ||
1463 | assertFormatDescending( | |
1464 | u"Padding", | |
1465 | nullptr, | |
1466 | NumberFormatter::with().padding( | |
1467 | Padder::codePoints( | |
1468 | '*', 8, PadPosition::UNUM_PAD_AFTER_PREFIX)), | |
1469 | Locale::getEnglish(), | |
1470 | u"**87,650", | |
1471 | u"***8,765", | |
1472 | u"***876.5", | |
1473 | u"***87.65", | |
1474 | u"***8.765", | |
1475 | u"**0.8765", | |
1476 | u"*0.08765", | |
1477 | u"0.008765", | |
1478 | u"*******0"); | |
1479 | ||
1480 | assertFormatDescending( | |
1481 | u"Padding with code points", | |
1482 | nullptr, | |
1483 | NumberFormatter::with().padding( | |
1484 | Padder::codePoints( | |
1485 | 0x101E4, 8, PadPosition::UNUM_PAD_AFTER_PREFIX)), | |
1486 | Locale::getEnglish(), | |
1487 | u"𐇤𐇤87,650", | |
1488 | u"𐇤𐇤𐇤8,765", | |
1489 | u"𐇤𐇤𐇤876.5", | |
1490 | u"𐇤𐇤𐇤87.65", | |
1491 | u"𐇤𐇤𐇤8.765", | |
1492 | u"𐇤𐇤0.8765", | |
1493 | u"𐇤0.08765", | |
1494 | u"0.008765", | |
1495 | u"𐇤𐇤𐇤𐇤𐇤𐇤𐇤0"); | |
1496 | ||
1497 | assertFormatDescending( | |
1498 | u"Padding with wide digits", | |
1499 | nullptr, | |
1500 | NumberFormatter::with().padding( | |
1501 | Padder::codePoints( | |
1502 | '*', 8, PadPosition::UNUM_PAD_AFTER_PREFIX)) | |
1503 | .adoptSymbols(new NumberingSystem(MATHSANB)), | |
1504 | Locale::getEnglish(), | |
1505 | u"**𝟴𝟳,𝟲𝟱𝟬", | |
1506 | u"***𝟴,𝟳𝟲𝟱", | |
1507 | u"***𝟴𝟳𝟲.𝟱", | |
1508 | u"***𝟴𝟳.𝟲𝟱", | |
1509 | u"***𝟴.𝟳𝟲𝟱", | |
1510 | u"**𝟬.𝟴𝟳𝟲𝟱", | |
1511 | u"*𝟬.𝟬𝟴𝟳𝟲𝟱", | |
1512 | u"𝟬.𝟬𝟬𝟴𝟳𝟲𝟱", | |
1513 | u"*******𝟬"); | |
1514 | ||
1515 | assertFormatDescending( | |
1516 | u"Padding with currency spacing", | |
1517 | nullptr, | |
1518 | NumberFormatter::with().padding( | |
1519 | Padder::codePoints( | |
1520 | '*', 10, PadPosition::UNUM_PAD_AFTER_PREFIX)) | |
1521 | .unit(GBP) | |
1522 | .unitWidth(UNumberUnitWidth::UNUM_UNIT_WIDTH_ISO_CODE), | |
1523 | Locale::getEnglish(), | |
1524 | u"GBP 87,650.00", | |
1525 | u"GBP 8,765.00", | |
1526 | u"GBP*876.50", | |
1527 | u"GBP**87.65", | |
1528 | u"GBP***8.76", | |
1529 | u"GBP***0.88", | |
1530 | u"GBP***0.09", | |
1531 | u"GBP***0.01", | |
1532 | u"GBP***0.00"); | |
1533 | ||
1534 | assertFormatSingle( | |
1535 | u"Pad Before Prefix", | |
1536 | nullptr, | |
1537 | NumberFormatter::with().padding( | |
1538 | Padder::codePoints( | |
1539 | '*', 8, PadPosition::UNUM_PAD_BEFORE_PREFIX)), | |
1540 | Locale::getEnglish(), | |
1541 | -88.88, | |
1542 | u"**-88.88"); | |
1543 | ||
1544 | assertFormatSingle( | |
1545 | u"Pad After Prefix", | |
1546 | nullptr, | |
1547 | NumberFormatter::with().padding( | |
1548 | Padder::codePoints( | |
1549 | '*', 8, PadPosition::UNUM_PAD_AFTER_PREFIX)), | |
1550 | Locale::getEnglish(), | |
1551 | -88.88, | |
1552 | u"-**88.88"); | |
1553 | ||
1554 | assertFormatSingle( | |
1555 | u"Pad Before Suffix", | |
1556 | nullptr, | |
1557 | NumberFormatter::with().padding( | |
1558 | Padder::codePoints( | |
1559 | '*', 8, PadPosition::UNUM_PAD_BEFORE_SUFFIX)).unit(NoUnit::percent()), | |
1560 | Locale::getEnglish(), | |
1561 | 88.88, | |
1562 | u"88.88**%"); | |
1563 | ||
1564 | assertFormatSingle( | |
1565 | u"Pad After Suffix", | |
1566 | nullptr, | |
1567 | NumberFormatter::with().padding( | |
1568 | Padder::codePoints( | |
1569 | '*', 8, PadPosition::UNUM_PAD_AFTER_SUFFIX)).unit(NoUnit::percent()), | |
1570 | Locale::getEnglish(), | |
1571 | 88.88, | |
1572 | u"88.88%**"); | |
1573 | ||
1574 | assertFormatSingle( | |
1575 | u"Currency Spacing with Zero Digit Padding Broken", | |
1576 | nullptr, | |
1577 | NumberFormatter::with().padding( | |
1578 | Padder::codePoints( | |
1579 | '0', 12, PadPosition::UNUM_PAD_AFTER_PREFIX)) | |
1580 | .unit(GBP) | |
1581 | .unitWidth(UNumberUnitWidth::UNUM_UNIT_WIDTH_ISO_CODE), | |
1582 | Locale::getEnglish(), | |
1583 | 514.23, | |
1584 | u"GBP 000514.23"); // TODO: This is broken; it renders too wide (13 instead of 12). | |
1585 | } | |
1586 | ||
1587 | void NumberFormatterApiTest::integerWidth() { | |
1588 | assertFormatDescending( | |
1589 | u"Integer Width Default", | |
1590 | u"integer-width/+0", | |
1591 | NumberFormatter::with().integerWidth(IntegerWidth::zeroFillTo(1)), | |
1592 | Locale::getEnglish(), | |
1593 | u"87,650", | |
1594 | u"8,765", | |
1595 | u"876.5", | |
1596 | u"87.65", | |
1597 | u"8.765", | |
1598 | u"0.8765", | |
1599 | u"0.08765", | |
1600 | u"0.008765", | |
1601 | u"0"); | |
1602 | ||
1603 | assertFormatDescending( | |
1604 | u"Integer Width Zero Fill 0", | |
1605 | u"integer-width/+", | |
1606 | NumberFormatter::with().integerWidth(IntegerWidth::zeroFillTo(0)), | |
1607 | Locale::getEnglish(), | |
1608 | u"87,650", | |
1609 | u"8,765", | |
1610 | u"876.5", | |
1611 | u"87.65", | |
1612 | u"8.765", | |
1613 | u".8765", | |
1614 | u".08765", | |
1615 | u".008765", | |
1616 | u""); // TODO: Avoid the empty string here? | |
1617 | ||
1618 | assertFormatDescending( | |
1619 | u"Integer Width Zero Fill 3", | |
1620 | u"integer-width/+000", | |
1621 | NumberFormatter::with().integerWidth(IntegerWidth::zeroFillTo(3)), | |
1622 | Locale::getEnglish(), | |
1623 | u"87,650", | |
1624 | u"8,765", | |
1625 | u"876.5", | |
1626 | u"087.65", | |
1627 | u"008.765", | |
1628 | u"000.8765", | |
1629 | u"000.08765", | |
1630 | u"000.008765", | |
1631 | u"000"); | |
1632 | ||
1633 | assertFormatDescending( | |
1634 | u"Integer Width Max 3", | |
1635 | u"integer-width/##0", | |
1636 | NumberFormatter::with().integerWidth(IntegerWidth::zeroFillTo(1).truncateAt(3)), | |
1637 | Locale::getEnglish(), | |
1638 | u"650", | |
1639 | u"765", | |
1640 | u"876.5", | |
1641 | u"87.65", | |
1642 | u"8.765", | |
1643 | u"0.8765", | |
1644 | u"0.08765", | |
1645 | u"0.008765", | |
1646 | u"0"); | |
1647 | ||
1648 | assertFormatDescending( | |
1649 | u"Integer Width Fixed 2", | |
1650 | u"integer-width/00", | |
1651 | NumberFormatter::with().integerWidth(IntegerWidth::zeroFillTo(2).truncateAt(2)), | |
1652 | Locale::getEnglish(), | |
1653 | u"50", | |
1654 | u"65", | |
1655 | u"76.5", | |
1656 | u"87.65", | |
1657 | u"08.765", | |
1658 | u"00.8765", | |
1659 | u"00.08765", | |
1660 | u"00.008765", | |
1661 | u"00"); | |
3d1f044b A |
1662 | |
1663 | assertFormatSingle( | |
1664 | u"Integer Width Remove All A", | |
1665 | u"integer-width/00", | |
1666 | NumberFormatter::with().integerWidth(IntegerWidth::zeroFillTo(2).truncateAt(2)), | |
1667 | "en", | |
1668 | 2500, | |
1669 | u"00"); | |
1670 | ||
1671 | assertFormatSingle( | |
1672 | u"Integer Width Remove All B", | |
1673 | u"integer-width/00", | |
1674 | NumberFormatter::with().integerWidth(IntegerWidth::zeroFillTo(2).truncateAt(2)), | |
1675 | "en", | |
1676 | 25000, | |
1677 | u"00"); | |
1678 | ||
1679 | assertFormatSingle( | |
1680 | u"Integer Width Remove All B, Bytes Mode", | |
1681 | u"integer-width/00", | |
1682 | NumberFormatter::with().integerWidth(IntegerWidth::zeroFillTo(2).truncateAt(2)), | |
1683 | "en", | |
1684 | // Note: this double produces all 17 significant digits | |
1685 | 10000000000000002000.0, | |
1686 | u"00"); | |
0f5d89e8 A |
1687 | } |
1688 | ||
1689 | void NumberFormatterApiTest::symbols() { | |
1690 | assertFormatDescending( | |
1691 | u"French Symbols with Japanese Data 1", | |
1692 | nullptr, | |
1693 | NumberFormatter::with().symbols(FRENCH_SYMBOLS), | |
1694 | Locale::getJapan(), | |
3d1f044b A |
1695 | u"87\u202F650", |
1696 | u"8\u202F765", | |
0f5d89e8 A |
1697 | u"876,5", |
1698 | u"87,65", | |
1699 | u"8,765", | |
1700 | u"0,8765", | |
1701 | u"0,08765", | |
1702 | u"0,008765", | |
1703 | u"0"); | |
1704 | ||
1705 | assertFormatSingle( | |
1706 | u"French Symbols with Japanese Data 2", | |
1707 | nullptr, | |
1708 | NumberFormatter::with().notation(Notation::compactShort()).symbols(FRENCH_SYMBOLS), | |
1709 | Locale::getJapan(), | |
1710 | 12345, | |
1711 | u"1,2\u4E07"); | |
1712 | ||
1713 | assertFormatDescending( | |
1714 | u"Latin Numbering System with Arabic Data", | |
1715 | u"currency/USD latin", | |
1716 | NumberFormatter::with().adoptSymbols(new NumberingSystem(LATN)).unit(USD), | |
1717 | Locale("ar"), | |
1718 | u"US$ 87,650.00", | |
1719 | u"US$ 8,765.00", | |
1720 | u"US$ 876.50", | |
1721 | u"US$ 87.65", | |
1722 | u"US$ 8.76", | |
1723 | u"US$ 0.88", | |
1724 | u"US$ 0.09", | |
1725 | u"US$ 0.01", | |
1726 | u"US$ 0.00"); | |
1727 | ||
1728 | assertFormatDescending( | |
1729 | u"Math Numbering System with French Data", | |
1730 | u"numbering-system/mathsanb", | |
1731 | NumberFormatter::with().adoptSymbols(new NumberingSystem(MATHSANB)), | |
1732 | Locale::getFrench(), | |
3d1f044b A |
1733 | u"𝟴𝟳\u202F𝟲𝟱𝟬", |
1734 | u"𝟴\u202F𝟳𝟲𝟱", | |
0f5d89e8 A |
1735 | u"𝟴𝟳𝟲,𝟱", |
1736 | u"𝟴𝟳,𝟲𝟱", | |
1737 | u"𝟴,𝟳𝟲𝟱", | |
1738 | u"𝟬,𝟴𝟳𝟲𝟱", | |
1739 | u"𝟬,𝟬𝟴𝟳𝟲𝟱", | |
1740 | u"𝟬,𝟬𝟬𝟴𝟳𝟲𝟱", | |
1741 | u"𝟬"); | |
1742 | ||
1743 | assertFormatSingle( | |
1744 | u"Swiss Symbols (used in documentation)", | |
1745 | nullptr, | |
1746 | NumberFormatter::with().symbols(SWISS_SYMBOLS), | |
1747 | Locale::getEnglish(), | |
1748 | 12345.67, | |
1749 | u"12’345.67"); | |
1750 | ||
1751 | assertFormatSingle( | |
1752 | u"Myanmar Symbols (used in documentation)", | |
1753 | nullptr, | |
1754 | NumberFormatter::with().symbols(MYANMAR_SYMBOLS), | |
1755 | Locale::getEnglish(), | |
1756 | 12345.67, | |
1757 | u"\u1041\u1042,\u1043\u1044\u1045.\u1046\u1047"); | |
1758 | ||
1759 | // NOTE: Locale ar puts ¤ after the number in NS arab but before the number in NS latn. | |
1760 | ||
1761 | assertFormatSingle( | |
1762 | u"Currency symbol should precede number in ar with NS latn", | |
1763 | u"currency/USD latin", | |
1764 | NumberFormatter::with().adoptSymbols(new NumberingSystem(LATN)).unit(USD), | |
1765 | Locale("ar"), | |
1766 | 12345.67, | |
1767 | u"US$ 12,345.67"); | |
1768 | ||
1769 | assertFormatSingle( | |
1770 | u"Currency symbol should precede number in ar@numbers=latn", | |
1771 | u"currency/USD", | |
1772 | NumberFormatter::with().unit(USD), | |
1773 | Locale("ar@numbers=latn"), | |
1774 | 12345.67, | |
1775 | u"US$ 12,345.67"); | |
1776 | ||
1777 | assertFormatSingle( | |
1778 | u"Currency symbol should follow number in ar-EG with NS arab", | |
1779 | u"currency/USD", | |
1780 | NumberFormatter::with().unit(USD), | |
1781 | Locale("ar-EG"), | |
1782 | 12345.67, | |
1783 | u"١٢٬٣٤٥٫٦٧ US$"); | |
1784 | ||
1785 | assertFormatSingle( | |
1786 | u"Currency symbol should follow number in ar@numbers=arab", | |
1787 | u"currency/USD", | |
1788 | NumberFormatter::with().unit(USD), | |
1789 | Locale("ar@numbers=arab"), | |
1790 | 12345.67, | |
1791 | u"١٢٬٣٤٥٫٦٧ US$"); | |
1792 | ||
1793 | assertFormatSingle( | |
1794 | u"NumberingSystem in API should win over @numbers keyword", | |
1795 | u"currency/USD latin", | |
1796 | NumberFormatter::with().adoptSymbols(new NumberingSystem(LATN)).unit(USD), | |
1797 | Locale("ar@numbers=arab"), | |
1798 | 12345.67, | |
1799 | u"US$ 12,345.67"); | |
1800 | ||
1801 | UErrorCode status = U_ZERO_ERROR; | |
1802 | assertEquals( | |
1803 | "NumberingSystem in API should win over @numbers keyword in reverse order", | |
1804 | u"US$ 12,345.67", | |
1805 | NumberFormatter::withLocale(Locale("ar@numbers=arab")).adoptSymbols(new NumberingSystem(LATN)) | |
1806 | .unit(USD) | |
1807 | .formatDouble(12345.67, status) | |
3d1f044b | 1808 | .toString(status)); |
0f5d89e8 A |
1809 | |
1810 | DecimalFormatSymbols symbols = SWISS_SYMBOLS; | |
1811 | UnlocalizedNumberFormatter f = NumberFormatter::with().symbols(symbols); | |
1812 | symbols.setSymbol(DecimalFormatSymbols::ENumberFormatSymbol::kGroupingSeparatorSymbol, u"!", status); | |
1813 | assertFormatSingle( | |
1814 | u"Symbols object should be copied", nullptr, f, Locale::getEnglish(), 12345.67, u"12’345.67"); | |
1815 | ||
1816 | assertFormatSingle( | |
1817 | u"The last symbols setter wins", | |
1818 | u"latin", | |
1819 | NumberFormatter::with().symbols(symbols).adoptSymbols(new NumberingSystem(LATN)), | |
1820 | Locale::getEnglish(), | |
1821 | 12345.67, | |
1822 | u"12,345.67"); | |
1823 | ||
1824 | assertFormatSingle( | |
1825 | u"The last symbols setter wins", | |
1826 | nullptr, | |
1827 | NumberFormatter::with().adoptSymbols(new NumberingSystem(LATN)).symbols(symbols), | |
1828 | Locale::getEnglish(), | |
1829 | 12345.67, | |
1830 | u"12!345.67"); | |
1831 | } | |
1832 | ||
1833 | // TODO: Enable if/when currency symbol override is added. | |
1834 | //void NumberFormatterTest::symbolsOverride() { | |
1835 | // DecimalFormatSymbols dfs = DecimalFormatSymbols.getInstance(Locale::getEnglish()); | |
1836 | // dfs.setCurrencySymbol("@"); | |
1837 | // dfs.setInternationalCurrencySymbol("foo"); | |
1838 | // assertFormatSingle( | |
1839 | // u"Custom Short Currency Symbol", | |
1840 | // NumberFormatter::with().unit(Currency.getInstance("XXX")).symbols(dfs), | |
1841 | // Locale::getEnglish(), | |
1842 | // 12.3, | |
1843 | // u"@ 12.30"); | |
1844 | //} | |
1845 | ||
1846 | void NumberFormatterApiTest::sign() { | |
1847 | assertFormatSingle( | |
1848 | u"Sign Auto Positive", | |
1849 | u"sign-auto", | |
1850 | NumberFormatter::with().sign(UNumberSignDisplay::UNUM_SIGN_AUTO), | |
1851 | Locale::getEnglish(), | |
1852 | 444444, | |
1853 | u"444,444"); | |
1854 | ||
1855 | assertFormatSingle( | |
1856 | u"Sign Auto Negative", | |
1857 | u"sign-auto", | |
1858 | NumberFormatter::with().sign(UNumberSignDisplay::UNUM_SIGN_AUTO), | |
1859 | Locale::getEnglish(), | |
1860 | -444444, | |
1861 | u"-444,444"); | |
1862 | ||
1863 | assertFormatSingle( | |
1864 | u"Sign Auto Zero", | |
1865 | u"sign-auto", | |
1866 | NumberFormatter::with().sign(UNumberSignDisplay::UNUM_SIGN_AUTO), | |
1867 | Locale::getEnglish(), | |
1868 | 0, | |
1869 | u"0"); | |
1870 | ||
1871 | assertFormatSingle( | |
1872 | u"Sign Always Positive", | |
1873 | u"sign-always", | |
1874 | NumberFormatter::with().sign(UNumberSignDisplay::UNUM_SIGN_ALWAYS), | |
1875 | Locale::getEnglish(), | |
1876 | 444444, | |
1877 | u"+444,444"); | |
1878 | ||
1879 | assertFormatSingle( | |
1880 | u"Sign Always Negative", | |
1881 | u"sign-always", | |
1882 | NumberFormatter::with().sign(UNumberSignDisplay::UNUM_SIGN_ALWAYS), | |
1883 | Locale::getEnglish(), | |
1884 | -444444, | |
1885 | u"-444,444"); | |
1886 | ||
1887 | assertFormatSingle( | |
1888 | u"Sign Always Zero", | |
1889 | u"sign-always", | |
1890 | NumberFormatter::with().sign(UNumberSignDisplay::UNUM_SIGN_ALWAYS), | |
1891 | Locale::getEnglish(), | |
1892 | 0, | |
1893 | u"+0"); | |
1894 | ||
1895 | assertFormatSingle( | |
1896 | u"Sign Never Positive", | |
1897 | u"sign-never", | |
1898 | NumberFormatter::with().sign(UNumberSignDisplay::UNUM_SIGN_NEVER), | |
1899 | Locale::getEnglish(), | |
1900 | 444444, | |
1901 | u"444,444"); | |
1902 | ||
1903 | assertFormatSingle( | |
1904 | u"Sign Never Negative", | |
1905 | u"sign-never", | |
1906 | NumberFormatter::with().sign(UNumberSignDisplay::UNUM_SIGN_NEVER), | |
1907 | Locale::getEnglish(), | |
1908 | -444444, | |
1909 | u"444,444"); | |
1910 | ||
1911 | assertFormatSingle( | |
1912 | u"Sign Never Zero", | |
1913 | u"sign-never", | |
1914 | NumberFormatter::with().sign(UNumberSignDisplay::UNUM_SIGN_NEVER), | |
1915 | Locale::getEnglish(), | |
1916 | 0, | |
1917 | u"0"); | |
1918 | ||
1919 | assertFormatSingle( | |
1920 | u"Sign Accounting Positive", | |
1921 | u"currency/USD sign-accounting", | |
1922 | NumberFormatter::with().sign(UNumberSignDisplay::UNUM_SIGN_ACCOUNTING).unit(USD), | |
1923 | Locale::getEnglish(), | |
1924 | 444444, | |
1925 | u"$444,444.00"); | |
1926 | ||
1927 | assertFormatSingle( | |
1928 | u"Sign Accounting Negative", | |
1929 | u"currency/USD sign-accounting", | |
1930 | NumberFormatter::with().sign(UNumberSignDisplay::UNUM_SIGN_ACCOUNTING).unit(USD), | |
1931 | Locale::getEnglish(), | |
1932 | -444444, | |
1933 | u"($444,444.00)"); | |
1934 | ||
1935 | assertFormatSingle( | |
1936 | u"Sign Accounting Zero", | |
1937 | u"currency/USD sign-accounting", | |
1938 | NumberFormatter::with().sign(UNumberSignDisplay::UNUM_SIGN_ACCOUNTING).unit(USD), | |
1939 | Locale::getEnglish(), | |
1940 | 0, | |
1941 | u"$0.00"); | |
1942 | ||
1943 | assertFormatSingle( | |
1944 | u"Sign Accounting-Always Positive", | |
1945 | u"currency/USD sign-accounting-always", | |
1946 | NumberFormatter::with().sign(UNumberSignDisplay::UNUM_SIGN_ACCOUNTING_ALWAYS).unit(USD), | |
1947 | Locale::getEnglish(), | |
1948 | 444444, | |
1949 | u"+$444,444.00"); | |
1950 | ||
1951 | assertFormatSingle( | |
1952 | u"Sign Accounting-Always Negative", | |
1953 | u"currency/USD sign-accounting-always", | |
1954 | NumberFormatter::with().sign(UNumberSignDisplay::UNUM_SIGN_ACCOUNTING_ALWAYS).unit(USD), | |
1955 | Locale::getEnglish(), | |
1956 | -444444, | |
1957 | u"($444,444.00)"); | |
1958 | ||
1959 | assertFormatSingle( | |
1960 | u"Sign Accounting-Always Zero", | |
1961 | u"currency/USD sign-accounting-always", | |
1962 | NumberFormatter::with().sign(UNumberSignDisplay::UNUM_SIGN_ACCOUNTING_ALWAYS).unit(USD), | |
1963 | Locale::getEnglish(), | |
1964 | 0, | |
1965 | u"+$0.00"); | |
1966 | ||
1967 | assertFormatSingle( | |
1968 | u"Sign Except-Zero Positive", | |
1969 | u"sign-except-zero", | |
1970 | NumberFormatter::with().sign(UNumberSignDisplay::UNUM_SIGN_EXCEPT_ZERO), | |
1971 | Locale::getEnglish(), | |
1972 | 444444, | |
1973 | u"+444,444"); | |
1974 | ||
1975 | assertFormatSingle( | |
1976 | u"Sign Except-Zero Negative", | |
1977 | u"sign-except-zero", | |
1978 | NumberFormatter::with().sign(UNumberSignDisplay::UNUM_SIGN_EXCEPT_ZERO), | |
1979 | Locale::getEnglish(), | |
1980 | -444444, | |
1981 | u"-444,444"); | |
1982 | ||
1983 | assertFormatSingle( | |
1984 | u"Sign Except-Zero Zero", | |
1985 | u"sign-except-zero", | |
1986 | NumberFormatter::with().sign(UNumberSignDisplay::UNUM_SIGN_EXCEPT_ZERO), | |
1987 | Locale::getEnglish(), | |
1988 | 0, | |
1989 | u"0"); | |
1990 | ||
1991 | assertFormatSingle( | |
1992 | u"Sign Accounting-Except-Zero Positive", | |
1993 | u"currency/USD sign-accounting-except-zero", | |
1994 | NumberFormatter::with().sign(UNumberSignDisplay::UNUM_SIGN_ACCOUNTING_EXCEPT_ZERO).unit(USD), | |
1995 | Locale::getEnglish(), | |
1996 | 444444, | |
1997 | u"+$444,444.00"); | |
1998 | ||
1999 | assertFormatSingle( | |
2000 | u"Sign Accounting-Except-Zero Negative", | |
2001 | u"currency/USD sign-accounting-except-zero", | |
2002 | NumberFormatter::with().sign(UNumberSignDisplay::UNUM_SIGN_ACCOUNTING_EXCEPT_ZERO).unit(USD), | |
2003 | Locale::getEnglish(), | |
2004 | -444444, | |
2005 | u"($444,444.00)"); | |
2006 | ||
2007 | assertFormatSingle( | |
2008 | u"Sign Accounting-Except-Zero Zero", | |
2009 | u"currency/USD sign-accounting-except-zero", | |
2010 | NumberFormatter::with().sign(UNumberSignDisplay::UNUM_SIGN_ACCOUNTING_EXCEPT_ZERO).unit(USD), | |
2011 | Locale::getEnglish(), | |
2012 | 0, | |
2013 | u"$0.00"); | |
2014 | ||
2015 | assertFormatSingle( | |
2016 | u"Sign Accounting Negative Hidden", | |
2017 | u"currency/USD unit-width-hidden sign-accounting", | |
3d1f044b A |
2018 | NumberFormatter::with() |
2019 | .sign(UNumberSignDisplay::UNUM_SIGN_ACCOUNTING) | |
0f5d89e8 A |
2020 | .unit(USD) |
2021 | .unitWidth(UNUM_UNIT_WIDTH_HIDDEN), | |
2022 | Locale::getEnglish(), | |
2023 | -444444, | |
2024 | u"(444,444.00)"); | |
3d1f044b A |
2025 | |
2026 | assertFormatSingle( | |
2027 | u"Sign Accounting Negative Narrow", | |
2028 | u"currency/USD unit-width-narrow sign-accounting", | |
2029 | NumberFormatter::with() | |
2030 | .sign(UNumberSignDisplay::UNUM_SIGN_ACCOUNTING) | |
2031 | .unit(USD) | |
2032 | .unitWidth(UNUM_UNIT_WIDTH_NARROW), | |
2033 | Locale::getCanada(), | |
2034 | -444444, | |
2035 | u"($444,444.00)"); | |
2036 | ||
2037 | assertFormatSingle( | |
2038 | u"Sign Accounting Negative Short", | |
2039 | u"currency/USD sign-accounting", | |
2040 | NumberFormatter::with() | |
2041 | .sign(UNumberSignDisplay::UNUM_SIGN_ACCOUNTING) | |
2042 | .unit(USD) | |
2043 | .unitWidth(UNUM_UNIT_WIDTH_SHORT), | |
2044 | Locale::getCanada(), | |
2045 | -444444, | |
2046 | u"(US$444,444.00)"); | |
2047 | ||
2048 | assertFormatSingle( | |
2049 | u"Sign Accounting Negative Iso Code", | |
2050 | u"currency/USD unit-width-iso-code sign-accounting", | |
2051 | NumberFormatter::with() | |
2052 | .sign(UNumberSignDisplay::UNUM_SIGN_ACCOUNTING) | |
2053 | .unit(USD) | |
2054 | .unitWidth(UNUM_UNIT_WIDTH_ISO_CODE), | |
2055 | Locale::getCanada(), | |
2056 | -444444, | |
2057 | u"(USD 444,444.00)"); | |
2058 | ||
2059 | // Note: CLDR does not provide an accounting pattern for long name currency. | |
2060 | // We fall back to normal currency format. This may change in the future. | |
2061 | assertFormatSingle( | |
2062 | u"Sign Accounting Negative Full Name", | |
2063 | u"currency/USD unit-width-full-name sign-accounting", | |
2064 | NumberFormatter::with() | |
2065 | .sign(UNumberSignDisplay::UNUM_SIGN_ACCOUNTING) | |
2066 | .unit(USD) | |
2067 | .unitWidth(UNUM_UNIT_WIDTH_FULL_NAME), | |
2068 | Locale::getCanada(), | |
2069 | -444444, | |
2070 | u"-444,444.00 US dollars"); | |
0f5d89e8 A |
2071 | } |
2072 | ||
2073 | void NumberFormatterApiTest::decimal() { | |
2074 | assertFormatDescending( | |
2075 | u"Decimal Default", | |
2076 | u"decimal-auto", | |
2077 | NumberFormatter::with().decimal(UNumberDecimalSeparatorDisplay::UNUM_DECIMAL_SEPARATOR_AUTO), | |
2078 | Locale::getEnglish(), | |
2079 | u"87,650", | |
2080 | u"8,765", | |
2081 | u"876.5", | |
2082 | u"87.65", | |
2083 | u"8.765", | |
2084 | u"0.8765", | |
2085 | u"0.08765", | |
2086 | u"0.008765", | |
2087 | u"0"); | |
2088 | ||
2089 | assertFormatDescending( | |
2090 | u"Decimal Always Shown", | |
2091 | u"decimal-always", | |
2092 | NumberFormatter::with().decimal(UNumberDecimalSeparatorDisplay::UNUM_DECIMAL_SEPARATOR_ALWAYS), | |
2093 | Locale::getEnglish(), | |
2094 | u"87,650.", | |
2095 | u"8,765.", | |
2096 | u"876.5", | |
2097 | u"87.65", | |
2098 | u"8.765", | |
2099 | u"0.8765", | |
2100 | u"0.08765", | |
2101 | u"0.008765", | |
2102 | u"0."); | |
2103 | } | |
2104 | ||
2105 | void NumberFormatterApiTest::scale() { | |
2106 | assertFormatDescending( | |
2107 | u"Multiplier None", | |
2108 | u"scale/1", | |
2109 | NumberFormatter::with().scale(Scale::none()), | |
2110 | Locale::getEnglish(), | |
2111 | u"87,650", | |
2112 | u"8,765", | |
2113 | u"876.5", | |
2114 | u"87.65", | |
2115 | u"8.765", | |
2116 | u"0.8765", | |
2117 | u"0.08765", | |
2118 | u"0.008765", | |
2119 | u"0"); | |
2120 | ||
2121 | assertFormatDescending( | |
2122 | u"Multiplier Power of Ten", | |
2123 | u"scale/1000000", | |
2124 | NumberFormatter::with().scale(Scale::powerOfTen(6)), | |
2125 | Locale::getEnglish(), | |
2126 | u"87,650,000,000", | |
2127 | u"8,765,000,000", | |
2128 | u"876,500,000", | |
2129 | u"87,650,000", | |
2130 | u"8,765,000", | |
2131 | u"876,500", | |
2132 | u"87,650", | |
2133 | u"8,765", | |
2134 | u"0"); | |
2135 | ||
2136 | assertFormatDescending( | |
2137 | u"Multiplier Arbitrary Double", | |
2138 | u"scale/5.2", | |
2139 | NumberFormatter::with().scale(Scale::byDouble(5.2)), | |
2140 | Locale::getEnglish(), | |
2141 | u"455,780", | |
2142 | u"45,578", | |
2143 | u"4,557.8", | |
2144 | u"455.78", | |
2145 | u"45.578", | |
2146 | u"4.5578", | |
2147 | u"0.45578", | |
2148 | u"0.045578", | |
2149 | u"0"); | |
2150 | ||
2151 | assertFormatDescending( | |
2152 | u"Multiplier Arbitrary BigDecimal", | |
2153 | u"scale/5.2", | |
2154 | NumberFormatter::with().scale(Scale::byDecimal({"5.2", -1})), | |
2155 | Locale::getEnglish(), | |
2156 | u"455,780", | |
2157 | u"45,578", | |
2158 | u"4,557.8", | |
2159 | u"455.78", | |
2160 | u"45.578", | |
2161 | u"4.5578", | |
2162 | u"0.45578", | |
2163 | u"0.045578", | |
2164 | u"0"); | |
2165 | ||
2166 | assertFormatDescending( | |
2167 | u"Multiplier Arbitrary Double And Power Of Ten", | |
2168 | u"scale/5200", | |
2169 | NumberFormatter::with().scale(Scale::byDoubleAndPowerOfTen(5.2, 3)), | |
2170 | Locale::getEnglish(), | |
2171 | u"455,780,000", | |
2172 | u"45,578,000", | |
2173 | u"4,557,800", | |
2174 | u"455,780", | |
2175 | u"45,578", | |
2176 | u"4,557.8", | |
2177 | u"455.78", | |
2178 | u"45.578", | |
2179 | u"0"); | |
2180 | ||
2181 | assertFormatDescending( | |
2182 | u"Multiplier Zero", | |
2183 | u"scale/0", | |
2184 | NumberFormatter::with().scale(Scale::byDouble(0)), | |
2185 | Locale::getEnglish(), | |
2186 | u"0", | |
2187 | u"0", | |
2188 | u"0", | |
2189 | u"0", | |
2190 | u"0", | |
2191 | u"0", | |
2192 | u"0", | |
2193 | u"0", | |
2194 | u"0"); | |
2195 | ||
2196 | assertFormatSingle( | |
2197 | u"Multiplier Skeleton Scientific Notation and Percent", | |
2198 | u"percent scale/1E2", | |
2199 | NumberFormatter::with().unit(NoUnit::percent()).scale(Scale::powerOfTen(2)), | |
2200 | Locale::getEnglish(), | |
2201 | 0.5, | |
2202 | u"50%"); | |
2203 | ||
2204 | assertFormatSingle( | |
2205 | u"Negative Multiplier", | |
2206 | u"scale/-5.2", | |
2207 | NumberFormatter::with().scale(Scale::byDouble(-5.2)), | |
2208 | Locale::getEnglish(), | |
2209 | 2, | |
2210 | u"-10.4"); | |
2211 | ||
2212 | assertFormatSingle( | |
2213 | u"Negative One Multiplier", | |
2214 | u"scale/-1", | |
2215 | NumberFormatter::with().scale(Scale::byDouble(-1)), | |
2216 | Locale::getEnglish(), | |
2217 | 444444, | |
2218 | u"-444,444"); | |
2219 | ||
2220 | assertFormatSingle( | |
2221 | u"Two-Type Multiplier with Overlap", | |
2222 | u"scale/10000", | |
2223 | NumberFormatter::with().scale(Scale::byDoubleAndPowerOfTen(100, 2)), | |
2224 | Locale::getEnglish(), | |
2225 | 2, | |
2226 | u"20,000"); | |
2227 | } | |
2228 | ||
2229 | void NumberFormatterApiTest::locale() { | |
2230 | // Coverage for the locale setters. | |
2231 | UErrorCode status = U_ZERO_ERROR; | |
2232 | UnicodeString actual = NumberFormatter::withLocale(Locale::getFrench()).formatInt(1234, status) | |
3d1f044b A |
2233 | .toString(status); |
2234 | assertEquals("Locale withLocale()", u"1\u202f234", actual); | |
0f5d89e8 A |
2235 | } |
2236 | ||
2237 | void NumberFormatterApiTest::formatTypes() { | |
2238 | UErrorCode status = U_ZERO_ERROR; | |
2239 | LocalizedNumberFormatter formatter = NumberFormatter::withLocale(Locale::getEnglish()); | |
2240 | ||
2241 | // Double | |
3d1f044b | 2242 | assertEquals("Format double", "514.23", formatter.formatDouble(514.23, status).toString(status)); |
0f5d89e8 A |
2243 | |
2244 | // Int64 | |
3d1f044b | 2245 | assertEquals("Format int64", "51,423", formatter.formatDouble(51423L, status).toString(status)); |
0f5d89e8 A |
2246 | |
2247 | // decNumber | |
3d1f044b | 2248 | UnicodeString actual = formatter.formatDecimal("98765432123456789E1", status).toString(status); |
0f5d89e8 A |
2249 | assertEquals("Format decNumber", u"987,654,321,234,567,890", actual); |
2250 | ||
2251 | // Also test proper DecimalQuantity bytes storage when all digits are in the fraction. | |
2252 | // The number needs to have exactly 40 digits, which is the size of the default buffer. | |
2253 | // (issue discovered by the address sanitizer in C++) | |
2254 | static const char* str = "0.009876543210987654321098765432109876543211"; | |
3d1f044b | 2255 | actual = formatter.precision(Precision::unlimited()).formatDecimal(str, status).toString(status); |
0f5d89e8 A |
2256 | assertEquals("Format decNumber to 40 digits", str, actual); |
2257 | } | |
2258 | ||
3d1f044b A |
2259 | void NumberFormatterApiTest::fieldPositionLogic() { |
2260 | IcuTestErrorCode status(*this, "fieldPositionLogic"); | |
2261 | ||
2262 | const char16_t* message = u"Field position logic test"; | |
2263 | ||
2264 | FormattedNumber fmtd = assertFormatSingle( | |
2265 | message, | |
2266 | u"", | |
2267 | NumberFormatter::with(), | |
2268 | Locale::getEnglish(), | |
2269 | -9876543210.12, | |
2270 | u"-9,876,543,210.12"); | |
0f5d89e8 A |
2271 | |
2272 | static const UFieldPosition expectedFieldPositions[] = { | |
2273 | // field, begin index, end index | |
2274 | {UNUM_SIGN_FIELD, 0, 1}, | |
2275 | {UNUM_GROUPING_SEPARATOR_FIELD, 2, 3}, | |
2276 | {UNUM_GROUPING_SEPARATOR_FIELD, 6, 7}, | |
2277 | {UNUM_GROUPING_SEPARATOR_FIELD, 10, 11}, | |
2278 | {UNUM_INTEGER_FIELD, 1, 14}, | |
2279 | {UNUM_DECIMAL_SEPARATOR_FIELD, 14, 15}, | |
2280 | {UNUM_FRACTION_FIELD, 15, 17}}; | |
2281 | ||
3d1f044b A |
2282 | assertNumberFieldPositions( |
2283 | message, | |
2284 | fmtd, | |
2285 | expectedFieldPositions, | |
2286 | UPRV_LENGTHOF(expectedFieldPositions)); | |
0f5d89e8 A |
2287 | |
2288 | // Test the iteration functionality of nextFieldPosition | |
3d1f044b A |
2289 | FieldPosition actual = {UNUM_GROUPING_SEPARATOR_FIELD}; |
2290 | int32_t i = 1; | |
0f5d89e8 A |
2291 | while (fmtd.nextFieldPosition(actual, status)) { |
2292 | UFieldPosition expected = expectedFieldPositions[i++]; | |
2293 | assertEquals( | |
2294 | UnicodeString(u"Next for grouping, field, case #") + Int64ToUnicodeString(i), | |
2295 | expected.field, | |
2296 | actual.getField()); | |
2297 | assertEquals( | |
2298 | UnicodeString(u"Next for grouping, begin index, case #") + Int64ToUnicodeString(i), | |
2299 | expected.beginIndex, | |
2300 | actual.getBeginIndex()); | |
2301 | assertEquals( | |
2302 | UnicodeString(u"Next for grouping, end index, case #") + Int64ToUnicodeString(i), | |
2303 | expected.endIndex, | |
2304 | actual.getEndIndex()); | |
2305 | } | |
2306 | assertEquals(u"Should have seen all grouping separators", 4, i); | |
2307 | ||
2308 | // Make sure strings without fraction do not contain fraction field | |
2309 | actual = {UNUM_FRACTION_FIELD}; | |
2310 | fmtd = NumberFormatter::withLocale("en").formatInt(5, status); | |
2311 | assertFalse(u"No fraction part in an integer", fmtd.nextFieldPosition(actual, status)); | |
2312 | } | |
2313 | ||
3d1f044b A |
2314 | void NumberFormatterApiTest::fieldPositionCoverage() { |
2315 | IcuTestErrorCode status(*this, "fieldPositionCoverage"); | |
2316 | ||
2317 | { | |
2318 | const char16_t* message = u"Measure unit field position basic"; | |
2319 | FormattedNumber result = assertFormatSingle( | |
2320 | message, | |
2321 | u"measure-unit/temperature-fahrenheit", | |
2322 | NumberFormatter::with().unit(FAHRENHEIT), | |
2323 | Locale::getEnglish(), | |
2324 | 68, | |
2325 | u"68°F"); | |
2326 | static const UFieldPosition expectedFieldPositions[] = { | |
2327 | // field, begin index, end index | |
2328 | {UNUM_INTEGER_FIELD, 0, 2}, | |
2329 | {UNUM_MEASURE_UNIT_FIELD, 2, 4}}; | |
2330 | assertNumberFieldPositions( | |
2331 | message, | |
2332 | result, | |
2333 | expectedFieldPositions, | |
2334 | UPRV_LENGTHOF(expectedFieldPositions)); | |
2335 | } | |
2336 | ||
2337 | { | |
2338 | const char16_t* message = u"Measure unit field position with compound unit"; | |
2339 | FormattedNumber result = assertFormatSingle( | |
2340 | message, | |
2341 | u"measure-unit/temperature-fahrenheit per-measure-unit/duration-day", | |
2342 | NumberFormatter::with().unit(FAHRENHEIT).perUnit(DAY), | |
2343 | Locale::getEnglish(), | |
2344 | 68, | |
2345 | u"68°F/d"); | |
2346 | static const UFieldPosition expectedFieldPositions[] = { | |
2347 | // field, begin index, end index | |
2348 | {UNUM_INTEGER_FIELD, 0, 2}, | |
2349 | // coverage for old enum: | |
2350 | {DecimalFormat::kMeasureUnitField, 2, 6}}; | |
2351 | assertNumberFieldPositions( | |
2352 | message, | |
2353 | result, | |
2354 | expectedFieldPositions, | |
2355 | UPRV_LENGTHOF(expectedFieldPositions)); | |
2356 | } | |
2357 | ||
2358 | { | |
2359 | const char16_t* message = u"Measure unit field position with spaces"; | |
2360 | FormattedNumber result = assertFormatSingle( | |
2361 | message, | |
2362 | u"measure-unit/length-meter unit-width-full-name", | |
2363 | NumberFormatter::with().unit(METER).unitWidth(UNUM_UNIT_WIDTH_FULL_NAME), | |
2364 | Locale::getEnglish(), | |
2365 | 68, | |
2366 | u"68 meters"); | |
2367 | static const UFieldPosition expectedFieldPositions[] = { | |
2368 | // field, begin index, end index | |
2369 | {UNUM_INTEGER_FIELD, 0, 2}, | |
2370 | // note: field starts after the space | |
2371 | {UNUM_MEASURE_UNIT_FIELD, 3, 9}}; | |
2372 | assertNumberFieldPositions( | |
2373 | message, | |
2374 | result, | |
2375 | expectedFieldPositions, | |
2376 | UPRV_LENGTHOF(expectedFieldPositions)); | |
2377 | } | |
2378 | ||
2379 | { | |
2380 | const char16_t* message = u"Measure unit field position with prefix and suffix"; | |
2381 | FormattedNumber result = assertFormatSingle( | |
2382 | message, | |
2383 | u"measure-unit/length-meter per-measure-unit/duration-second unit-width-full-name", | |
2384 | NumberFormatter::with().unit(METER).perUnit(SECOND).unitWidth(UNUM_UNIT_WIDTH_FULL_NAME), | |
2385 | "ky", // locale with the interesting data | |
2386 | 68, | |
2387 | u"секундасына 68 метр"); | |
2388 | static const UFieldPosition expectedFieldPositions[] = { | |
2389 | // field, begin index, end index | |
2390 | {UNUM_MEASURE_UNIT_FIELD, 0, 11}, | |
2391 | {UNUM_INTEGER_FIELD, 12, 14}, | |
2392 | {UNUM_MEASURE_UNIT_FIELD, 15, 19}}; | |
2393 | assertNumberFieldPositions( | |
2394 | message, | |
2395 | result, | |
2396 | expectedFieldPositions, | |
2397 | UPRV_LENGTHOF(expectedFieldPositions)); | |
2398 | } | |
2399 | ||
2400 | { | |
2401 | const char16_t* message = u"Measure unit field position with inner spaces"; | |
2402 | FormattedNumber result = assertFormatSingle( | |
2403 | message, | |
2404 | u"measure-unit/temperature-fahrenheit unit-width-full-name", | |
2405 | NumberFormatter::with().unit(FAHRENHEIT).unitWidth(UNUM_UNIT_WIDTH_FULL_NAME), | |
2406 | "vi", // locale with the interesting data | |
2407 | 68, | |
2408 | u"68 độ F"); | |
2409 | static const UFieldPosition expectedFieldPositions[] = { | |
2410 | // field, begin index, end index | |
2411 | {UNUM_INTEGER_FIELD, 0, 2}, | |
2412 | // Should trim leading/trailing spaces, but not inner spaces: | |
2413 | {UNUM_MEASURE_UNIT_FIELD, 3, 7}}; | |
2414 | assertNumberFieldPositions( | |
2415 | message, | |
2416 | result, | |
2417 | expectedFieldPositions, | |
2418 | UPRV_LENGTHOF(expectedFieldPositions)); | |
2419 | } | |
2420 | ||
2421 | { | |
2422 | // Data: other{"{0} K"} == "\u200E{0} K" | |
2423 | // If that data changes, try to find another example of a non-empty unit prefix/suffix | |
2424 | // that is also all ignorables (whitespace and bidi control marks). | |
2425 | const char16_t* message = u"Measure unit field position with fully ignorable prefix"; | |
2426 | FormattedNumber result = assertFormatSingle( | |
2427 | message, | |
2428 | u"measure-unit/temperature-kelvin", | |
2429 | NumberFormatter::with().unit(KELVIN), | |
2430 | "fa", // locale with the interesting data | |
2431 | 68, | |
2432 | u"۶۸ K"); | |
2433 | static const UFieldPosition expectedFieldPositions[] = { | |
2434 | // field, begin index, end index | |
2435 | {UNUM_INTEGER_FIELD, 1, 3}, | |
2436 | {UNUM_MEASURE_UNIT_FIELD, 4, 5}}; | |
2437 | assertNumberFieldPositions( | |
2438 | message, | |
2439 | result, | |
2440 | expectedFieldPositions, | |
2441 | UPRV_LENGTHOF(expectedFieldPositions)); | |
2442 | } | |
2443 | ||
2444 | { | |
2445 | const char16_t* message = u"Compact field basic"; | |
2446 | FormattedNumber result = assertFormatSingle( | |
2447 | message, | |
2448 | u"compact-short", | |
2449 | NumberFormatter::with().notation(Notation::compactShort()), | |
2450 | Locale::getUS(), | |
2451 | 65000, | |
2452 | u"65K"); | |
2453 | static const UFieldPosition expectedFieldPositions[] = { | |
2454 | // field, begin index, end index | |
2455 | {UNUM_INTEGER_FIELD, 0, 2}, | |
2456 | {UNUM_COMPACT_FIELD, 2, 3}}; | |
2457 | assertNumberFieldPositions( | |
2458 | message, | |
2459 | result, | |
2460 | expectedFieldPositions, | |
2461 | UPRV_LENGTHOF(expectedFieldPositions)); | |
2462 | } | |
2463 | ||
2464 | { | |
2465 | const char16_t* message = u"Compact field with spaces"; | |
2466 | FormattedNumber result = assertFormatSingle( | |
2467 | message, | |
2468 | u"compact-long", | |
2469 | NumberFormatter::with().notation(Notation::compactLong()), | |
2470 | Locale::getUS(), | |
2471 | 65000, | |
2472 | u"65 thousand"); | |
2473 | static const UFieldPosition expectedFieldPositions[] = { | |
2474 | // field, begin index, end index | |
2475 | {UNUM_INTEGER_FIELD, 0, 2}, | |
2476 | {UNUM_COMPACT_FIELD, 3, 11}}; | |
2477 | assertNumberFieldPositions( | |
2478 | message, | |
2479 | result, | |
2480 | expectedFieldPositions, | |
2481 | UPRV_LENGTHOF(expectedFieldPositions)); | |
2482 | } | |
2483 | ||
2484 | { | |
2485 | const char16_t* message = u"Compact field with inner space"; | |
2486 | FormattedNumber result = assertFormatSingle( | |
2487 | message, | |
2488 | u"compact-long", | |
2489 | NumberFormatter::with().notation(Notation::compactLong()), | |
2490 | "fil", // locale with interesting data | |
2491 | 6000, | |
2492 | u"6 na libo"); | |
2493 | static const UFieldPosition expectedFieldPositions[] = { | |
2494 | // field, begin index, end index | |
2495 | {UNUM_INTEGER_FIELD, 0, 1}, | |
2496 | {UNUM_COMPACT_FIELD, 2, 9}}; | |
2497 | assertNumberFieldPositions( | |
2498 | message, | |
2499 | result, | |
2500 | expectedFieldPositions, | |
2501 | UPRV_LENGTHOF(expectedFieldPositions)); | |
2502 | } | |
2503 | ||
2504 | { | |
2505 | const char16_t* message = u"Compact field with bidi mark"; | |
2506 | FormattedNumber result = assertFormatSingle( | |
2507 | message, | |
2508 | u"compact-long", | |
2509 | NumberFormatter::with().notation(Notation::compactLong()), | |
2510 | "he", // locale with interesting data | |
2511 | 6000, | |
2512 | u"\u200F6 אלף"); | |
2513 | static const UFieldPosition expectedFieldPositions[] = { | |
2514 | // field, begin index, end index | |
2515 | {UNUM_INTEGER_FIELD, 1, 2}, | |
2516 | {UNUM_COMPACT_FIELD, 3, 6}}; | |
2517 | assertNumberFieldPositions( | |
2518 | message, | |
2519 | result, | |
2520 | expectedFieldPositions, | |
2521 | UPRV_LENGTHOF(expectedFieldPositions)); | |
2522 | } | |
2523 | ||
2524 | { | |
2525 | const char16_t* message = u"Compact with currency fields"; | |
2526 | FormattedNumber result = assertFormatSingle( | |
2527 | message, | |
2528 | u"compact-short currency/USD", | |
2529 | NumberFormatter::with().notation(Notation::compactShort()).unit(USD), | |
2530 | "sr_Latn", // locale with interesting data | |
2531 | 65000, | |
2532 | u"65 hilj. US$"); | |
2533 | static const UFieldPosition expectedFieldPositions[] = { | |
2534 | // field, begin index, end index | |
2535 | {UNUM_INTEGER_FIELD, 0, 2}, | |
2536 | {UNUM_COMPACT_FIELD, 3, 8}, | |
2537 | {UNUM_CURRENCY_FIELD, 9, 12}}; | |
2538 | assertNumberFieldPositions( | |
2539 | message, | |
2540 | result, | |
2541 | expectedFieldPositions, | |
2542 | UPRV_LENGTHOF(expectedFieldPositions)); | |
2543 | } | |
2544 | ||
2545 | { | |
2546 | const char16_t* message = u"Currency long name fields"; | |
2547 | FormattedNumber result = assertFormatSingle( | |
2548 | message, | |
2549 | u"currency/USD unit-width-full-name", | |
2550 | NumberFormatter::with().unit(USD) | |
2551 | .unitWidth(UNumberUnitWidth::UNUM_UNIT_WIDTH_FULL_NAME), | |
2552 | "en", | |
2553 | 12345, | |
2554 | u"12,345.00 US dollars"); | |
2555 | static const UFieldPosition expectedFieldPositions[] = { | |
2556 | // field, begin index, end index | |
2557 | {UNUM_GROUPING_SEPARATOR_FIELD, 2, 3}, | |
2558 | {UNUM_INTEGER_FIELD, 0, 6}, | |
2559 | {UNUM_DECIMAL_SEPARATOR_FIELD, 6, 7}, | |
2560 | {UNUM_FRACTION_FIELD, 7, 9}, | |
2561 | {UNUM_CURRENCY_FIELD, 10, 20}}; | |
2562 | assertNumberFieldPositions( | |
2563 | message, | |
2564 | result, | |
2565 | expectedFieldPositions, | |
2566 | UPRV_LENGTHOF(expectedFieldPositions)); | |
2567 | } | |
2568 | ||
2569 | { | |
2570 | const char16_t* message = u"Compact with measure unit fields"; | |
2571 | FormattedNumber result = assertFormatSingle( | |
2572 | message, | |
2573 | u"compact-long measure-unit/length-meter unit-width-full-name", | |
2574 | NumberFormatter::with().notation(Notation::compactLong()) | |
2575 | .unit(METER) | |
2576 | .unitWidth(UNUM_UNIT_WIDTH_FULL_NAME), | |
2577 | Locale::getUS(), | |
2578 | 65000, | |
2579 | u"65 thousand meters"); | |
2580 | static const UFieldPosition expectedFieldPositions[] = { | |
2581 | // field, begin index, end index | |
2582 | {UNUM_INTEGER_FIELD, 0, 2}, | |
2583 | {UNUM_COMPACT_FIELD, 3, 11}, | |
2584 | {UNUM_MEASURE_UNIT_FIELD, 12, 18}}; | |
2585 | assertNumberFieldPositions( | |
2586 | message, | |
2587 | result, | |
2588 | expectedFieldPositions, | |
2589 | UPRV_LENGTHOF(expectedFieldPositions)); | |
2590 | } | |
2591 | } | |
2592 | ||
0f5d89e8 A |
2593 | void NumberFormatterApiTest::toFormat() { |
2594 | IcuTestErrorCode status(*this, "icuFormat"); | |
2595 | LocalizedNumberFormatter lnf = NumberFormatter::withLocale("fr") | |
2596 | .precision(Precision::fixedFraction(3)); | |
2597 | LocalPointer<Format> format(lnf.toFormat(status), status); | |
2598 | FieldPosition fpos(UNUM_DECIMAL_SEPARATOR_FIELD); | |
2599 | UnicodeString sb; | |
2600 | format->format(514.23, sb, fpos, status); | |
2601 | assertEquals("Should correctly format number", u"514,230", sb); | |
2602 | assertEquals("Should find decimal separator", 3, fpos.getBeginIndex()); | |
2603 | assertEquals("Should find end of decimal separator", 4, fpos.getEndIndex()); | |
2604 | assertEquals( | |
2605 | "ICU Format should round-trip", | |
2606 | lnf.toSkeleton(status), | |
2607 | dynamic_cast<LocalizedNumberFormatterAsFormat*>(format.getAlias())->getNumberFormatter() | |
2608 | .toSkeleton(status)); | |
2609 | ||
2610 | FieldPositionIterator fpi1; | |
2611 | lnf.formatDouble(514.23, status).getAllFieldPositions(fpi1, status); | |
2612 | FieldPositionIterator fpi2; | |
2613 | format->format(514.23, sb.remove(), &fpi2, status); | |
2614 | assertTrue("Should produce same field position iterator", fpi1 == fpi2); | |
2615 | } | |
2616 | ||
2617 | void NumberFormatterApiTest::errors() { | |
2618 | LocalizedNumberFormatter lnf = NumberFormatter::withLocale(Locale::getEnglish()).precision( | |
2619 | Precision::fixedFraction( | |
2620 | -1)); | |
2621 | ||
2622 | // formatInt | |
2623 | UErrorCode status = U_ZERO_ERROR; | |
2624 | FormattedNumber fn = lnf.formatInt(1, status); | |
2625 | assertEquals( | |
2626 | "Should fail in formatInt method with error code for rounding", | |
2627 | U_NUMBER_ARG_OUTOFBOUNDS_ERROR, | |
2628 | status); | |
2629 | ||
2630 | // formatDouble | |
2631 | status = U_ZERO_ERROR; | |
2632 | fn = lnf.formatDouble(1.0, status); | |
2633 | assertEquals( | |
2634 | "Should fail in formatDouble method with error code for rounding", | |
2635 | U_NUMBER_ARG_OUTOFBOUNDS_ERROR, | |
2636 | status); | |
2637 | ||
2638 | // formatDecimal (decimal error) | |
2639 | status = U_ZERO_ERROR; | |
2640 | fn = NumberFormatter::withLocale("en").formatDecimal("1x2", status); | |
2641 | assertEquals( | |
2642 | "Should fail in formatDecimal method with error code for decimal number syntax", | |
2643 | U_DECIMAL_NUMBER_SYNTAX_ERROR, | |
2644 | status); | |
2645 | ||
2646 | // formatDecimal (setting error) | |
2647 | status = U_ZERO_ERROR; | |
2648 | fn = lnf.formatDecimal("1.0", status); | |
2649 | assertEquals( | |
2650 | "Should fail in formatDecimal method with error code for rounding", | |
2651 | U_NUMBER_ARG_OUTOFBOUNDS_ERROR, | |
2652 | status); | |
2653 | ||
2654 | // Skeleton string | |
2655 | status = U_ZERO_ERROR; | |
2656 | UnicodeString output = lnf.toSkeleton(status); | |
2657 | assertEquals( | |
2658 | "Should fail on toSkeleton terminal method with correct error code", | |
2659 | U_NUMBER_ARG_OUTOFBOUNDS_ERROR, | |
2660 | status); | |
2661 | assertTrue( | |
2662 | "Terminal toSkeleton on error object should be bogus", | |
2663 | output.isBogus()); | |
2664 | ||
2665 | // FieldPosition | |
2666 | status = U_ZERO_ERROR; | |
2667 | FieldPosition fp; | |
3d1f044b | 2668 | fn.nextFieldPosition(fp, status); |
0f5d89e8 A |
2669 | assertEquals( |
2670 | "Should fail on FieldPosition terminal method with correct error code", | |
2671 | U_NUMBER_ARG_OUTOFBOUNDS_ERROR, | |
2672 | status); | |
2673 | ||
2674 | // FieldPositionIterator | |
2675 | status = U_ZERO_ERROR; | |
2676 | FieldPositionIterator fpi; | |
3d1f044b | 2677 | fn.getAllFieldPositions(fpi, status); |
0f5d89e8 A |
2678 | assertEquals( |
2679 | "Should fail on FieldPositoinIterator terminal method with correct error code", | |
2680 | U_NUMBER_ARG_OUTOFBOUNDS_ERROR, | |
2681 | status); | |
2682 | ||
2683 | // Appendable | |
2684 | status = U_ZERO_ERROR; | |
2685 | UnicodeStringAppendable appendable(output.remove()); | |
2686 | fn.appendTo(appendable, status); | |
2687 | assertEquals( | |
2688 | "Should fail on Appendable terminal method with correct error code", | |
2689 | U_NUMBER_ARG_OUTOFBOUNDS_ERROR, | |
2690 | status); | |
2691 | ||
2692 | // UnicodeString | |
2693 | status = U_ZERO_ERROR; | |
2694 | output = fn.toString(status); | |
2695 | assertEquals( | |
2696 | "Should fail on UnicodeString terminal method with correct error code", | |
2697 | U_NUMBER_ARG_OUTOFBOUNDS_ERROR, | |
2698 | status); | |
2699 | assertTrue( | |
2700 | "Terminal UnicodeString on error object should be bogus", | |
2701 | output.isBogus()); | |
2702 | ||
2703 | // CopyErrorTo | |
2704 | status = U_ZERO_ERROR; | |
2705 | lnf.copyErrorTo(status); | |
2706 | assertEquals( | |
2707 | "Should fail since rounder is not legal with correct error code", | |
2708 | U_NUMBER_ARG_OUTOFBOUNDS_ERROR, | |
2709 | status); | |
2710 | } | |
2711 | ||
2712 | void NumberFormatterApiTest::validRanges() { | |
2713 | ||
2714 | #define EXPECTED_MAX_INT_FRAC_SIG 999 | |
2715 | ||
2716 | #define VALID_RANGE_ASSERT(status, method, lowerBound, argument) { \ | |
2717 | UErrorCode expectedStatus = ((lowerBound <= argument) && (argument <= EXPECTED_MAX_INT_FRAC_SIG)) \ | |
2718 | ? U_ZERO_ERROR \ | |
2719 | : U_NUMBER_ARG_OUTOFBOUNDS_ERROR; \ | |
2720 | assertEquals( \ | |
2721 | UnicodeString(u"Incorrect status for " #method " on input ") \ | |
2722 | + Int64ToUnicodeString(argument), \ | |
2723 | expectedStatus, \ | |
2724 | status); \ | |
2725 | } | |
2726 | ||
2727 | #define VALID_RANGE_ONEARG(setting, method, lowerBound) { \ | |
2728 | for (int32_t argument = -2; argument <= EXPECTED_MAX_INT_FRAC_SIG + 2; argument++) { \ | |
2729 | UErrorCode status = U_ZERO_ERROR; \ | |
2730 | NumberFormatter::with().setting(method(argument)).copyErrorTo(status); \ | |
2731 | VALID_RANGE_ASSERT(status, method, lowerBound, argument); \ | |
2732 | } \ | |
2733 | } | |
2734 | ||
2735 | #define VALID_RANGE_TWOARGS(setting, method, lowerBound) { \ | |
2736 | for (int32_t argument = -2; argument <= EXPECTED_MAX_INT_FRAC_SIG + 2; argument++) { \ | |
2737 | UErrorCode status = U_ZERO_ERROR; \ | |
2738 | /* Pass EXPECTED_MAX_INT_FRAC_SIG as the second argument so arg1 <= arg2 in expected cases */ \ | |
2739 | NumberFormatter::with().setting(method(argument, EXPECTED_MAX_INT_FRAC_SIG)).copyErrorTo(status); \ | |
2740 | VALID_RANGE_ASSERT(status, method, lowerBound, argument); \ | |
2741 | status = U_ZERO_ERROR; \ | |
2742 | /* Pass lowerBound as the first argument so arg1 <= arg2 in expected cases */ \ | |
2743 | NumberFormatter::with().setting(method(lowerBound, argument)).copyErrorTo(status); \ | |
2744 | VALID_RANGE_ASSERT(status, method, lowerBound, argument); \ | |
2745 | /* Check that first argument must be less than or equal to second argument */ \ | |
2746 | NumberFormatter::with().setting(method(argument, argument - 1)).copyErrorTo(status); \ | |
2747 | assertEquals("Incorrect status for " #method " on max < min input", \ | |
2748 | U_NUMBER_ARG_OUTOFBOUNDS_ERROR, \ | |
2749 | status); \ | |
2750 | } \ | |
2751 | } | |
2752 | ||
3d1f044b A |
2753 | VALID_RANGE_ONEARG(precision, Precision::fixedFraction, 0); |
2754 | VALID_RANGE_ONEARG(precision, Precision::minFraction, 0); | |
2755 | VALID_RANGE_ONEARG(precision, Precision::maxFraction, 0); | |
2756 | VALID_RANGE_TWOARGS(precision, Precision::minMaxFraction, 0); | |
2757 | VALID_RANGE_ONEARG(precision, Precision::fixedSignificantDigits, 1); | |
2758 | VALID_RANGE_ONEARG(precision, Precision::minSignificantDigits, 1); | |
2759 | VALID_RANGE_ONEARG(precision, Precision::maxSignificantDigits, 1); | |
2760 | VALID_RANGE_TWOARGS(precision, Precision::minMaxSignificantDigits, 1); | |
2761 | VALID_RANGE_ONEARG(precision, Precision::fixedFraction(1).withMinDigits, 1); | |
2762 | VALID_RANGE_ONEARG(precision, Precision::fixedFraction(1).withMaxDigits, 1); | |
0f5d89e8 A |
2763 | VALID_RANGE_ONEARG(notation, Notation::scientific().withMinExponentDigits, 1); |
2764 | VALID_RANGE_ONEARG(integerWidth, IntegerWidth::zeroFillTo, 0); | |
2765 | VALID_RANGE_ONEARG(integerWidth, IntegerWidth::zeroFillTo(0).truncateAt, -1); | |
2766 | } | |
2767 | ||
2768 | void NumberFormatterApiTest::copyMove() { | |
2769 | IcuTestErrorCode status(*this, "copyMove"); | |
2770 | ||
2771 | // Default constructors | |
2772 | LocalizedNumberFormatter l1; | |
3d1f044b | 2773 | assertEquals("Initial behavior", u"10", l1.formatInt(10, status).toString(status), true); |
0f5d89e8 A |
2774 | if (status.errDataIfFailureAndReset()) { return; } |
2775 | assertEquals("Initial call count", 1, l1.getCallCount()); | |
2776 | assertTrue("Initial compiled", l1.getCompiled() == nullptr); | |
2777 | ||
2778 | // Setup | |
2779 | l1 = NumberFormatter::withLocale("en").unit(NoUnit::percent()).threshold(3); | |
3d1f044b | 2780 | assertEquals("Initial behavior", u"10%", l1.formatInt(10, status).toString(status)); |
0f5d89e8 A |
2781 | assertEquals("Initial call count", 1, l1.getCallCount()); |
2782 | assertTrue("Initial compiled", l1.getCompiled() == nullptr); | |
2783 | l1.formatInt(123, status); | |
2784 | assertEquals("Still not compiled", 2, l1.getCallCount()); | |
2785 | assertTrue("Still not compiled", l1.getCompiled() == nullptr); | |
2786 | l1.formatInt(123, status); | |
3d1f044b | 2787 | assertEquals("Compiled", u"10%", l1.formatInt(10, status).toString(status)); |
0f5d89e8 A |
2788 | assertEquals("Compiled", INT32_MIN, l1.getCallCount()); |
2789 | assertTrue("Compiled", l1.getCompiled() != nullptr); | |
2790 | ||
2791 | // Copy constructor | |
2792 | LocalizedNumberFormatter l2 = l1; | |
3d1f044b | 2793 | assertEquals("[constructor] Copy behavior", u"10%", l2.formatInt(10, status).toString(status)); |
0f5d89e8 A |
2794 | assertEquals("[constructor] Copy should not have compiled state", 1, l2.getCallCount()); |
2795 | assertTrue("[constructor] Copy should not have compiled state", l2.getCompiled() == nullptr); | |
2796 | ||
2797 | // Move constructor | |
2798 | LocalizedNumberFormatter l3 = std::move(l1); | |
3d1f044b | 2799 | assertEquals("[constructor] Move behavior", u"10%", l3.formatInt(10, status).toString(status)); |
0f5d89e8 A |
2800 | assertEquals("[constructor] Move *should* have compiled state", INT32_MIN, l3.getCallCount()); |
2801 | assertTrue("[constructor] Move *should* have compiled state", l3.getCompiled() != nullptr); | |
2802 | assertEquals("[constructor] Source should be reset after move", 0, l1.getCallCount()); | |
2803 | assertTrue("[constructor] Source should be reset after move", l1.getCompiled() == nullptr); | |
2804 | ||
2805 | // Reset l1 and l2 to check for macro-props copying for behavior testing | |
3d1f044b | 2806 | // Make the test more interesting: also warm them up with a compiled formatter. |
0f5d89e8 | 2807 | l1 = NumberFormatter::withLocale("en"); |
3d1f044b A |
2808 | l1.formatInt(1, status); |
2809 | l1.formatInt(1, status); | |
2810 | l1.formatInt(1, status); | |
0f5d89e8 | 2811 | l2 = NumberFormatter::withLocale("en"); |
3d1f044b A |
2812 | l2.formatInt(1, status); |
2813 | l2.formatInt(1, status); | |
2814 | l2.formatInt(1, status); | |
0f5d89e8 A |
2815 | |
2816 | // Copy assignment | |
2817 | l1 = l3; | |
3d1f044b | 2818 | assertEquals("[assignment] Copy behavior", u"10%", l1.formatInt(10, status).toString(status)); |
0f5d89e8 A |
2819 | assertEquals("[assignment] Copy should not have compiled state", 1, l1.getCallCount()); |
2820 | assertTrue("[assignment] Copy should not have compiled state", l1.getCompiled() == nullptr); | |
2821 | ||
2822 | // Move assignment | |
2823 | l2 = std::move(l3); | |
3d1f044b | 2824 | assertEquals("[assignment] Move behavior", u"10%", l2.formatInt(10, status).toString(status)); |
0f5d89e8 A |
2825 | assertEquals("[assignment] Move *should* have compiled state", INT32_MIN, l2.getCallCount()); |
2826 | assertTrue("[assignment] Move *should* have compiled state", l2.getCompiled() != nullptr); | |
2827 | assertEquals("[assignment] Source should be reset after move", 0, l3.getCallCount()); | |
2828 | assertTrue("[assignment] Source should be reset after move", l3.getCompiled() == nullptr); | |
2829 | ||
2830 | // Coverage tests for UnlocalizedNumberFormatter | |
2831 | UnlocalizedNumberFormatter u1; | |
3d1f044b | 2832 | assertEquals("Default behavior", u"10", u1.locale("en").formatInt(10, status).toString(status)); |
0f5d89e8 | 2833 | u1 = u1.unit(NoUnit::percent()); |
3d1f044b | 2834 | assertEquals("Copy assignment", u"10%", u1.locale("en").formatInt(10, status).toString(status)); |
0f5d89e8 | 2835 | UnlocalizedNumberFormatter u2 = u1; |
3d1f044b | 2836 | assertEquals("Copy constructor", u"10%", u2.locale("en").formatInt(10, status).toString(status)); |
0f5d89e8 | 2837 | UnlocalizedNumberFormatter u3 = std::move(u1); |
3d1f044b | 2838 | assertEquals("Move constructor", u"10%", u3.locale("en").formatInt(10, status).toString(status)); |
0f5d89e8 A |
2839 | u1 = NumberFormatter::with(); |
2840 | u1 = std::move(u2); | |
3d1f044b | 2841 | assertEquals("Move assignment", u"10%", u1.locale("en").formatInt(10, status).toString(status)); |
0f5d89e8 A |
2842 | |
2843 | // FormattedNumber move operators | |
2844 | FormattedNumber result = l1.formatInt(10, status); | |
3d1f044b | 2845 | assertEquals("FormattedNumber move constructor", u"10%", result.toString(status)); |
0f5d89e8 | 2846 | result = l1.formatInt(20, status); |
3d1f044b | 2847 | assertEquals("FormattedNumber move assignment", u"20%", result.toString(status)); |
0f5d89e8 A |
2848 | } |
2849 | ||
2850 | void NumberFormatterApiTest::localPointerCAPI() { | |
2851 | // NOTE: This is also the sample code in unumberformatter.h | |
2852 | UErrorCode ec = U_ZERO_ERROR; | |
2853 | ||
2854 | // Setup: | |
2855 | LocalUNumberFormatterPointer uformatter(unumf_openForSkeletonAndLocale(u"percent", -1, "en", &ec)); | |
2856 | LocalUFormattedNumberPointer uresult(unumf_openResult(&ec)); | |
2857 | if (!assertSuccess("", ec, true, __FILE__, __LINE__)) { return; } | |
2858 | ||
2859 | // Format a decimal number: | |
2860 | unumf_formatDecimal(uformatter.getAlias(), "9.87E-3", -1, uresult.getAlias(), &ec); | |
2861 | if (!assertSuccess("", ec, true, __FILE__, __LINE__)) { return; } | |
2862 | ||
2863 | // Get the location of the percent sign: | |
2864 | UFieldPosition ufpos = {UNUM_PERCENT_FIELD, 0, 0}; | |
2865 | unumf_resultNextFieldPosition(uresult.getAlias(), &ufpos, &ec); | |
2866 | assertEquals("Percent sign location within '0.00987%'", 7, ufpos.beginIndex); | |
2867 | assertEquals("Percent sign location within '0.00987%'", 8, ufpos.endIndex); | |
2868 | ||
2869 | // No need to do any cleanup since we are using LocalPointer. | |
2870 | } | |
2871 | ||
3d1f044b A |
2872 | void NumberFormatterApiTest::toObject() { |
2873 | IcuTestErrorCode status(*this, "toObject"); | |
2874 | ||
2875 | // const lvalue version | |
2876 | { | |
2877 | LocalizedNumberFormatter lnf = NumberFormatter::withLocale("en") | |
2878 | .precision(Precision::fixedFraction(2)); | |
2879 | LocalPointer<LocalizedNumberFormatter> lnf2(lnf.clone()); | |
2880 | assertFalse("should create successfully, const lvalue", lnf2.isNull()); | |
2881 | assertEquals("object API test, const lvalue", u"1,000.00", | |
2882 | lnf2->formatDouble(1000, status).toString(status)); | |
2883 | } | |
2884 | ||
2885 | // rvalue reference version | |
2886 | { | |
2887 | LocalPointer<LocalizedNumberFormatter> lnf( | |
2888 | NumberFormatter::withLocale("en") | |
2889 | .precision(Precision::fixedFraction(2)) | |
2890 | .clone()); | |
2891 | assertFalse("should create successfully, rvalue reference", lnf.isNull()); | |
2892 | assertEquals("object API test, rvalue reference", u"1,000.00", | |
2893 | lnf->formatDouble(1000, status).toString(status)); | |
2894 | } | |
2895 | ||
2896 | // to std::unique_ptr via constructor | |
2897 | { | |
2898 | std::unique_ptr<LocalizedNumberFormatter> lnf( | |
2899 | NumberFormatter::withLocale("en") | |
2900 | .precision(Precision::fixedFraction(2)) | |
2901 | .clone()); | |
2902 | assertTrue("should create successfully, unique_ptr", static_cast<bool>(lnf)); | |
2903 | assertEquals("object API test, unique_ptr", u"1,000.00", | |
2904 | lnf->formatDouble(1000, status).toString(status)); | |
2905 | } | |
2906 | ||
2907 | // to std::unique_ptr via assignment | |
2908 | { | |
2909 | std::unique_ptr<LocalizedNumberFormatter> lnf = | |
2910 | NumberFormatter::withLocale("en") | |
2911 | .precision(Precision::fixedFraction(2)) | |
2912 | .clone(); | |
2913 | assertTrue("should create successfully, unique_ptr B", static_cast<bool>(lnf)); | |
2914 | assertEquals("object API test, unique_ptr B", u"1,000.00", | |
2915 | lnf->formatDouble(1000, status).toString(status)); | |
2916 | } | |
2917 | ||
2918 | // to LocalPointer via assignment | |
2919 | { | |
2920 | LocalPointer<UnlocalizedNumberFormatter> f = | |
2921 | NumberFormatter::with().clone(); | |
2922 | } | |
2923 | ||
2924 | // make sure no memory leaks | |
2925 | { | |
2926 | NumberFormatter::with().clone(); | |
2927 | } | |
2928 | } | |
2929 | ||
0f5d89e8 A |
2930 | |
2931 | void NumberFormatterApiTest::assertFormatDescending(const char16_t* umessage, const char16_t* uskeleton, | |
2932 | const UnlocalizedNumberFormatter& f, Locale locale, | |
2933 | ...) { | |
2934 | va_list args; | |
2935 | va_start(args, locale); | |
2936 | UnicodeString message(TRUE, umessage, -1); | |
2937 | static double inputs[] = {87650, 8765, 876.5, 87.65, 8.765, 0.8765, 0.08765, 0.008765, 0}; | |
2938 | const LocalizedNumberFormatter l1 = f.threshold(0).locale(locale); // no self-regulation | |
2939 | const LocalizedNumberFormatter l2 = f.threshold(1).locale(locale); // all self-regulation | |
2940 | IcuTestErrorCode status(*this, "assertFormatDescending"); | |
2941 | status.setScope(message); | |
2942 | UnicodeString expecteds[10]; | |
2943 | for (int16_t i = 0; i < 9; i++) { | |
2944 | char16_t caseNumber = u'0' + i; | |
2945 | double d = inputs[i]; | |
2946 | UnicodeString expected = va_arg(args, const char16_t*); | |
2947 | expecteds[i] = expected; | |
3d1f044b | 2948 | UnicodeString actual1 = l1.formatDouble(d, status).toString(status); |
0f5d89e8 A |
2949 | assertSuccess(message + u": Unsafe Path: " + caseNumber, status); |
2950 | assertEquals(message + u": Unsafe Path: " + caseNumber, expected, actual1); | |
3d1f044b | 2951 | UnicodeString actual2 = l2.formatDouble(d, status).toString(status); |
0f5d89e8 A |
2952 | assertSuccess(message + u": Safe Path: " + caseNumber, status); |
2953 | assertEquals(message + u": Safe Path: " + caseNumber, expected, actual2); | |
2954 | } | |
2955 | if (uskeleton != nullptr) { // if null, skeleton is declared as undefined. | |
2956 | UnicodeString skeleton(TRUE, uskeleton, -1); | |
2957 | // Only compare normalized skeletons: the tests need not provide the normalized forms. | |
2958 | // Use the normalized form to construct the testing formatter to guarantee no loss of info. | |
2959 | UnicodeString normalized = NumberFormatter::forSkeleton(skeleton, status).toSkeleton(status); | |
2960 | assertEquals(message + ": Skeleton:", normalized, f.toSkeleton(status)); | |
2961 | LocalizedNumberFormatter l3 = NumberFormatter::forSkeleton(normalized, status).locale(locale); | |
2962 | for (int32_t i = 0; i < 9; i++) { | |
2963 | double d = inputs[i]; | |
3d1f044b | 2964 | UnicodeString actual3 = l3.formatDouble(d, status).toString(status); |
0f5d89e8 A |
2965 | assertEquals(message + ": Skeleton Path: '" + normalized + "': " + d, expecteds[i], actual3); |
2966 | } | |
2967 | } else { | |
2968 | assertUndefinedSkeleton(f); | |
2969 | } | |
2970 | } | |
2971 | ||
2972 | void NumberFormatterApiTest::assertFormatDescendingBig(const char16_t* umessage, const char16_t* uskeleton, | |
2973 | const UnlocalizedNumberFormatter& f, Locale locale, | |
2974 | ...) { | |
2975 | va_list args; | |
2976 | va_start(args, locale); | |
2977 | UnicodeString message(TRUE, umessage, -1); | |
2978 | static double inputs[] = {87650000, 8765000, 876500, 87650, 8765, 876.5, 87.65, 8.765, 0}; | |
2979 | const LocalizedNumberFormatter l1 = f.threshold(0).locale(locale); // no self-regulation | |
2980 | const LocalizedNumberFormatter l2 = f.threshold(1).locale(locale); // all self-regulation | |
2981 | IcuTestErrorCode status(*this, "assertFormatDescendingBig"); | |
2982 | status.setScope(message); | |
2983 | UnicodeString expecteds[10]; | |
2984 | for (int16_t i = 0; i < 9; i++) { | |
2985 | char16_t caseNumber = u'0' + i; | |
2986 | double d = inputs[i]; | |
2987 | UnicodeString expected = va_arg(args, const char16_t*); | |
2988 | expecteds[i] = expected; | |
3d1f044b | 2989 | UnicodeString actual1 = l1.formatDouble(d, status).toString(status); |
0f5d89e8 A |
2990 | assertSuccess(message + u": Unsafe Path: " + caseNumber, status); |
2991 | assertEquals(message + u": Unsafe Path: " + caseNumber, expected, actual1); | |
3d1f044b | 2992 | UnicodeString actual2 = l2.formatDouble(d, status).toString(status); |
0f5d89e8 A |
2993 | assertSuccess(message + u": Safe Path: " + caseNumber, status); |
2994 | assertEquals(message + u": Safe Path: " + caseNumber, expected, actual2); | |
2995 | } | |
2996 | if (uskeleton != nullptr) { // if null, skeleton is declared as undefined. | |
2997 | UnicodeString skeleton(TRUE, uskeleton, -1); | |
2998 | // Only compare normalized skeletons: the tests need not provide the normalized forms. | |
2999 | // Use the normalized form to construct the testing formatter to guarantee no loss of info. | |
3000 | UnicodeString normalized = NumberFormatter::forSkeleton(skeleton, status).toSkeleton(status); | |
3001 | assertEquals(message + ": Skeleton:", normalized, f.toSkeleton(status)); | |
3002 | LocalizedNumberFormatter l3 = NumberFormatter::forSkeleton(normalized, status).locale(locale); | |
3003 | for (int32_t i = 0; i < 9; i++) { | |
3004 | double d = inputs[i]; | |
3d1f044b | 3005 | UnicodeString actual3 = l3.formatDouble(d, status).toString(status); |
0f5d89e8 A |
3006 | assertEquals(message + ": Skeleton Path: '" + normalized + "': " + d, expecteds[i], actual3); |
3007 | } | |
3008 | } else { | |
3009 | assertUndefinedSkeleton(f); | |
3010 | } | |
3011 | } | |
3012 | ||
3d1f044b A |
3013 | FormattedNumber |
3014 | NumberFormatterApiTest::assertFormatSingle(const char16_t* umessage, const char16_t* uskeleton, | |
3015 | const UnlocalizedNumberFormatter& f, Locale locale, | |
3016 | double input, const UnicodeString& expected) { | |
0f5d89e8 A |
3017 | UnicodeString message(TRUE, umessage, -1); |
3018 | const LocalizedNumberFormatter l1 = f.threshold(0).locale(locale); // no self-regulation | |
3019 | const LocalizedNumberFormatter l2 = f.threshold(1).locale(locale); // all self-regulation | |
3020 | IcuTestErrorCode status(*this, "assertFormatSingle"); | |
3021 | status.setScope(message); | |
3d1f044b A |
3022 | FormattedNumber result1 = l1.formatDouble(input, status); |
3023 | UnicodeString actual1 = result1.toString(status); | |
0f5d89e8 A |
3024 | assertSuccess(message + u": Unsafe Path", status); |
3025 | assertEquals(message + u": Unsafe Path", expected, actual1); | |
3d1f044b | 3026 | UnicodeString actual2 = l2.formatDouble(input, status).toString(status); |
0f5d89e8 A |
3027 | assertSuccess(message + u": Safe Path", status); |
3028 | assertEquals(message + u": Safe Path", expected, actual2); | |
3029 | if (uskeleton != nullptr) { // if null, skeleton is declared as undefined. | |
3030 | UnicodeString skeleton(TRUE, uskeleton, -1); | |
3031 | // Only compare normalized skeletons: the tests need not provide the normalized forms. | |
3032 | // Use the normalized form to construct the testing formatter to ensure no loss of info. | |
3033 | UnicodeString normalized = NumberFormatter::forSkeleton(skeleton, status).toSkeleton(status); | |
3034 | assertEquals(message + ": Skeleton:", normalized, f.toSkeleton(status)); | |
3035 | LocalizedNumberFormatter l3 = NumberFormatter::forSkeleton(normalized, status).locale(locale); | |
3d1f044b | 3036 | UnicodeString actual3 = l3.formatDouble(input, status).toString(status); |
0f5d89e8 A |
3037 | assertEquals(message + ": Skeleton Path: '" + normalized + "': " + input, expected, actual3); |
3038 | } else { | |
3039 | assertUndefinedSkeleton(f); | |
3040 | } | |
3d1f044b | 3041 | return result1; |
0f5d89e8 A |
3042 | } |
3043 | ||
3044 | void NumberFormatterApiTest::assertUndefinedSkeleton(const UnlocalizedNumberFormatter& f) { | |
3045 | UErrorCode status = U_ZERO_ERROR; | |
3046 | UnicodeString skeleton = f.toSkeleton(status); | |
3047 | assertEquals( | |
3048 | u"Expect toSkeleton to fail, but passed, producing: " + skeleton, | |
3049 | U_UNSUPPORTED_ERROR, | |
3050 | status); | |
3051 | } | |
3052 | ||
3d1f044b A |
3053 | void NumberFormatterApiTest::assertNumberFieldPositions( |
3054 | const char16_t* message, const FormattedNumber& formattedNumber, | |
3055 | const UFieldPosition* expectedFieldPositions, int32_t length) { | |
3056 | IcuTestErrorCode status(*this, "assertNumberFieldPositions"); | |
3057 | ||
3058 | // Check FormattedValue functions | |
3059 | checkFormattedValue( | |
3060 | message, | |
3061 | static_cast<const FormattedValue&>(formattedNumber), | |
3062 | formattedNumber.toString(status), | |
3063 | UFIELD_CATEGORY_NUMBER, | |
3064 | expectedFieldPositions, | |
3065 | length); | |
3066 | ||
3067 | // Check FormattedNumber-specific functions | |
3068 | UnicodeString baseMessage = UnicodeString(message) + u": " + formattedNumber.toString(status) + u": "; | |
3069 | FieldPositionIterator fpi; | |
3070 | formattedNumber.getAllFieldPositions(fpi, status); | |
3071 | int32_t i = 0; | |
3072 | FieldPosition actual; | |
3073 | while (fpi.next(actual)) { | |
3074 | UFieldPosition expected = expectedFieldPositions[i++]; | |
3075 | assertEquals( | |
3076 | baseMessage + UnicodeString(u"Field, case #") + Int64ToUnicodeString(i), | |
3077 | expected.field, | |
3078 | actual.getField()); | |
3079 | assertEquals( | |
3080 | baseMessage + UnicodeString(u"Iterator, begin, case #") + Int64ToUnicodeString(i), | |
3081 | expected.beginIndex, | |
3082 | actual.getBeginIndex()); | |
3083 | assertEquals( | |
3084 | baseMessage + UnicodeString(u"Iterator, end, case #") + Int64ToUnicodeString(i), | |
3085 | expected.endIndex, | |
3086 | actual.getEndIndex()); | |
3087 | ||
3088 | // Check for the first location of the field | |
3089 | FieldPosition actual2(expected.field); | |
3090 | // Fast-forward the field to skip previous occurrences of the field: | |
3091 | actual2.setBeginIndex(expected.beginIndex); | |
3092 | actual2.setEndIndex(expected.beginIndex); | |
3093 | UBool found = formattedNumber.nextFieldPosition(actual2, status); | |
3094 | assertEquals( | |
3095 | baseMessage + UnicodeString(u"Next, found first, case #") + Int64ToUnicodeString(i), | |
3096 | (UBool) TRUE, | |
3097 | found); | |
3098 | assertEquals( | |
3099 | baseMessage + UnicodeString(u"Next, begin, case #") + Int64ToUnicodeString(i), | |
3100 | expected.beginIndex, | |
3101 | actual2.getBeginIndex()); | |
3102 | assertEquals( | |
3103 | baseMessage + UnicodeString(u"Next, end, case #") + Int64ToUnicodeString(i), | |
3104 | expected.endIndex, | |
3105 | actual2.getEndIndex()); | |
3106 | ||
3107 | // The next position should be empty unless the field occurs again | |
3108 | UBool occursAgain = false; | |
3109 | for (int32_t j=i; j<length; j++) { | |
3110 | if (expectedFieldPositions[j].field == expected.field) { | |
3111 | occursAgain = true; | |
3112 | break; | |
3113 | } | |
3114 | } | |
3115 | if (!occursAgain) { | |
3116 | found = formattedNumber.nextFieldPosition(actual2, status); | |
3117 | assertEquals( | |
3118 | baseMessage + UnicodeString(u"Next, found second, case #") + Int64ToUnicodeString(i), | |
3119 | (UBool) FALSE, | |
3120 | found); | |
3121 | } | |
3122 | } | |
3123 | assertEquals(baseMessage + u"Should have seen every field position", length, i); | |
3124 | } | |
3125 | ||
3126 | ||
0f5d89e8 | 3127 | #endif /* #if !UCONFIG_NO_FORMATTING */ |