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