• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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