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