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