]> granicus.if.org Git - icu/blob - icu4c/source/test/intltest/numbertest_api.cpp
ICU-21349 calling .usage("") should unset the existing usage
[icu] / icu4c / source / test / intltest / numbertest_api.cpp
1 // © 2017 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3
4 #include "unicode/utypes.h"
5
6 #if !UCONFIG_NO_FORMATTING
7
8 #include "charstr.h"
9 #include <cstdarg>
10 #include <cmath>
11 #include <memory>
12 #include "unicode/unum.h"
13 #include "unicode/numberformatter.h"
14 #include "unicode/testlog.h"
15 #include "unicode/utypes.h"
16 #include "number_asformat.h"
17 #include "number_types.h"
18 #include "number_utils.h"
19 #include "number_utypes.h"
20 #include "number_microprops.h"
21 #include "numbertest.h"
22
23 using number::impl::UFormattedNumberData;
24
25 // Horrible workaround for the lack of a status code in the constructor...
26 // (Also affects numbertest_range.cpp)
27 UErrorCode globalNumberFormatterApiTestStatus = U_ZERO_ERROR;
28
29 NumberFormatterApiTest::NumberFormatterApiTest()
30         : NumberFormatterApiTest(globalNumberFormatterApiTestStatus) {
31 }
32
33 NumberFormatterApiTest::NumberFormatterApiTest(UErrorCode& status)
34         : USD(u"USD", status),
35           GBP(u"GBP", status),
36           CZK(u"CZK", status),
37           CAD(u"CAD", status),
38           ESP(u"ESP", status),
39           PTE(u"PTE", status),
40           RON(u"RON", status),
41           TWD(u"TWD", status),
42           TRY(u"TRY", status),
43           CNY(u"CNY", status),
44           FRENCH_SYMBOLS(Locale::getFrench(), status),
45           SWISS_SYMBOLS(Locale("de-CH"), status),
46           MYANMAR_SYMBOLS(Locale("my"), status) {
47
48     // Check for error on the first MeasureUnit in case there is no data
49     LocalPointer<MeasureUnit> unit(MeasureUnit::createMeter(status));
50     if (U_FAILURE(status)) {
51         dataerrln("%s %d status = %s", __FILE__, __LINE__, u_errorName(status));
52         return;
53     }
54     METER = *unit;
55
56     METER_PER_SECOND = *LocalPointer<MeasureUnit>(MeasureUnit::createMeterPerSecond(status));
57     DAY = *LocalPointer<MeasureUnit>(MeasureUnit::createDay(status));
58     SQUARE_METER = *LocalPointer<MeasureUnit>(MeasureUnit::createSquareMeter(status));
59     FAHRENHEIT = *LocalPointer<MeasureUnit>(MeasureUnit::createFahrenheit(status));
60     SECOND = *LocalPointer<MeasureUnit>(MeasureUnit::createSecond(status));
61     POUND = *LocalPointer<MeasureUnit>(MeasureUnit::createPound(status));
62     POUND_FORCE = *LocalPointer<MeasureUnit>(MeasureUnit::createPoundForce(status));
63     SQUARE_MILE = *LocalPointer<MeasureUnit>(MeasureUnit::createSquareMile(status));
64     SQUARE_INCH = *LocalPointer<MeasureUnit>(MeasureUnit::createSquareInch(status));
65     JOULE = *LocalPointer<MeasureUnit>(MeasureUnit::createJoule(status));
66     FURLONG = *LocalPointer<MeasureUnit>(MeasureUnit::createFurlong(status));
67     KELVIN = *LocalPointer<MeasureUnit>(MeasureUnit::createKelvin(status));
68
69     MATHSANB = *LocalPointer<NumberingSystem>(NumberingSystem::createInstanceByName("mathsanb", status));
70     LATN = *LocalPointer<NumberingSystem>(NumberingSystem::createInstanceByName("latn", status));
71 }
72
73 void NumberFormatterApiTest::runIndexedTest(int32_t index, UBool exec, const char*& name, char*) {
74     if (exec) {
75         logln("TestSuite NumberFormatterApiTest: ");
76     }
77     TESTCASE_AUTO_BEGIN;
78         TESTCASE_AUTO(notationSimple);
79         TESTCASE_AUTO(notationScientific);
80         TESTCASE_AUTO(notationCompact);
81         TESTCASE_AUTO(unitMeasure);
82         TESTCASE_AUTO(unitCompoundMeasure);
83         TESTCASE_AUTO(unitArbitraryMeasureUnits);
84         TESTCASE_AUTO(unitSkeletons);
85         TESTCASE_AUTO(unitUsage);
86         TESTCASE_AUTO(unitUsageErrorCodes);
87         TESTCASE_AUTO(unitUsageSkeletons);
88         TESTCASE_AUTO(unitCurrency);
89         TESTCASE_AUTO(unitInflections);
90         TESTCASE_AUTO(unitGender);
91         TESTCASE_AUTO(unitPercent);
92         if (!quick) {
93             // Slow test: run in exhaustive mode only
94             TESTCASE_AUTO(percentParity);
95         }
96         TESTCASE_AUTO(roundingFraction);
97         TESTCASE_AUTO(roundingFigures);
98         TESTCASE_AUTO(roundingFractionFigures);
99         TESTCASE_AUTO(roundingOther);
100         TESTCASE_AUTO(grouping);
101         TESTCASE_AUTO(padding);
102         TESTCASE_AUTO(integerWidth);
103         TESTCASE_AUTO(symbols);
104         // TODO: Add this method if currency symbols override support is added.
105         //TESTCASE_AUTO(symbolsOverride);
106         TESTCASE_AUTO(sign);
107         TESTCASE_AUTO(signNearZero);
108         TESTCASE_AUTO(signCoverage);
109         TESTCASE_AUTO(decimal);
110         TESTCASE_AUTO(scale);
111         TESTCASE_AUTO(locale);
112         TESTCASE_AUTO(skeletonUserGuideExamples);
113         TESTCASE_AUTO(formatTypes);
114         TESTCASE_AUTO(fieldPositionLogic);
115         TESTCASE_AUTO(fieldPositionCoverage);
116         TESTCASE_AUTO(toFormat);
117         TESTCASE_AUTO(errors);
118         if (!quick) {
119             // Slow test: run in exhaustive mode only
120             // (somewhat slow to check all permutations of settings)
121             TESTCASE_AUTO(validRanges);
122         }
123         TESTCASE_AUTO(copyMove);
124         TESTCASE_AUTO(localPointerCAPI);
125         TESTCASE_AUTO(toObject);
126         TESTCASE_AUTO(toDecimalNumber);
127         TESTCASE_AUTO(microPropsInternals);
128     TESTCASE_AUTO_END;
129 }
130
131 void NumberFormatterApiTest::notationSimple() {
132     assertFormatDescending(
133             u"Basic",
134             u"",
135             u"",
136             NumberFormatter::with(),
137             Locale::getEnglish(),
138             u"87,650",
139             u"8,765",
140             u"876.5",
141             u"87.65",
142             u"8.765",
143             u"0.8765",
144             u"0.08765",
145             u"0.008765",
146             u"0");
147
148     assertFormatDescendingBig(
149             u"Big Simple",
150             u"notation-simple",
151             u"",
152             NumberFormatter::with().notation(Notation::simple()),
153             Locale::getEnglish(),
154             u"87,650,000",
155             u"8,765,000",
156             u"876,500",
157             u"87,650",
158             u"8,765",
159             u"876.5",
160             u"87.65",
161             u"8.765",
162             u"0");
163
164     assertFormatSingle(
165             u"Basic with Negative Sign",
166             u"",
167             u"",
168             NumberFormatter::with(),
169             Locale::getEnglish(),
170             -9876543.21,
171             u"-9,876,543.21");
172 }
173
174
175 void NumberFormatterApiTest::notationScientific() {
176     assertFormatDescending(
177             u"Scientific",
178             u"scientific",
179             u"E0",
180             NumberFormatter::with().notation(Notation::scientific()),
181             Locale::getEnglish(),
182             u"8.765E4",
183             u"8.765E3",
184             u"8.765E2",
185             u"8.765E1",
186             u"8.765E0",
187             u"8.765E-1",
188             u"8.765E-2",
189             u"8.765E-3",
190             u"0E0");
191
192     assertFormatDescending(
193             u"Engineering",
194             u"engineering",
195             u"EE0",
196             NumberFormatter::with().notation(Notation::engineering()),
197             Locale::getEnglish(),
198             u"87.65E3",
199             u"8.765E3",
200             u"876.5E0",
201             u"87.65E0",
202             u"8.765E0",
203             u"876.5E-3",
204             u"87.65E-3",
205             u"8.765E-3",
206             u"0E0");
207
208     assertFormatDescending(
209             u"Scientific sign always shown",
210             u"scientific/sign-always",
211             u"E+!0",
212             NumberFormatter::with().notation(
213                     Notation::scientific().withExponentSignDisplay(UNumberSignDisplay::UNUM_SIGN_ALWAYS)),
214             Locale::getEnglish(),
215             u"8.765E+4",
216             u"8.765E+3",
217             u"8.765E+2",
218             u"8.765E+1",
219             u"8.765E+0",
220             u"8.765E-1",
221             u"8.765E-2",
222             u"8.765E-3",
223             u"0E+0");
224
225     assertFormatDescending(
226             u"Scientific min exponent digits",
227             u"scientific/*ee",
228             u"E00",
229             NumberFormatter::with().notation(Notation::scientific().withMinExponentDigits(2)),
230             Locale::getEnglish(),
231             u"8.765E04",
232             u"8.765E03",
233             u"8.765E02",
234             u"8.765E01",
235             u"8.765E00",
236             u"8.765E-01",
237             u"8.765E-02",
238             u"8.765E-03",
239             u"0E00");
240
241     assertFormatSingle(
242             u"Scientific Negative",
243             u"scientific",
244             u"E0",
245             NumberFormatter::with().notation(Notation::scientific()),
246             Locale::getEnglish(),
247             -1000000,
248             u"-1E6");
249
250     assertFormatSingle(
251             u"Scientific Infinity",
252             u"scientific",
253             u"E0",
254             NumberFormatter::with().notation(Notation::scientific()),
255             Locale::getEnglish(),
256             -uprv_getInfinity(),
257             u"-∞");
258
259     assertFormatSingle(
260             u"Scientific NaN",
261             u"scientific",
262             u"E0",
263             NumberFormatter::with().notation(Notation::scientific()),
264             Locale::getEnglish(),
265             uprv_getNaN(),
266             u"NaN");
267 }
268
269 void NumberFormatterApiTest::notationCompact() {
270     assertFormatDescending(
271             u"Compact Short",
272             u"compact-short",
273             u"K",
274             NumberFormatter::with().notation(Notation::compactShort()),
275             Locale::getEnglish(),
276             u"88K",
277             u"8.8K",
278             u"876",
279             u"88",
280             u"8.8",
281             u"0.88",
282             u"0.088",
283             u"0.0088",
284             u"0");
285
286     assertFormatDescending(
287             u"Compact Long",
288             u"compact-long",
289             u"KK",
290             NumberFormatter::with().notation(Notation::compactLong()),
291             Locale::getEnglish(),
292             u"88 thousand",
293             u"8.8 thousand",
294             u"876",
295             u"88",
296             u"8.8",
297             u"0.88",
298             u"0.088",
299             u"0.0088",
300             u"0");
301
302     assertFormatDescending(
303             u"Compact Short Currency",
304             u"compact-short currency/USD",
305             u"K currency/USD",
306             NumberFormatter::with().notation(Notation::compactShort()).unit(USD),
307             Locale::getEnglish(),
308             u"$88K",
309             u"$8.8K",
310             u"$876",
311             u"$88",
312             u"$8.8",
313             u"$0.88",
314             u"$0.088",
315             u"$0.0088",
316             u"$0");
317
318     assertFormatDescending(
319             u"Compact Short with ISO Currency",
320             u"compact-short currency/USD unit-width-iso-code",
321             u"K currency/USD unit-width-iso-code",
322             NumberFormatter::with().notation(Notation::compactShort())
323                     .unit(USD)
324                     .unitWidth(UNumberUnitWidth::UNUM_UNIT_WIDTH_ISO_CODE),
325             Locale::getEnglish(),
326             u"USD 88K",
327             u"USD 8.8K",
328             u"USD 876",
329             u"USD 88",
330             u"USD 8.8",
331             u"USD 0.88",
332             u"USD 0.088",
333             u"USD 0.0088",
334             u"USD 0");
335
336     assertFormatDescending(
337             u"Compact Short with Long Name Currency",
338             u"compact-short currency/USD unit-width-full-name",
339             u"K currency/USD unit-width-full-name",
340             NumberFormatter::with().notation(Notation::compactShort())
341                     .unit(USD)
342                     .unitWidth(UNumberUnitWidth::UNUM_UNIT_WIDTH_FULL_NAME),
343             Locale::getEnglish(),
344             u"88K US dollars",
345             u"8.8K US dollars",
346             u"876 US dollars",
347             u"88 US dollars",
348             u"8.8 US dollars",
349             u"0.88 US dollars",
350             u"0.088 US dollars",
351             u"0.0088 US dollars",
352             u"0 US dollars");
353
354     // Note: Most locales don't have compact long currency, so this currently falls back to short.
355     // This test case should be fixed when proper compact long currency patterns are added.
356     assertFormatDescending(
357             u"Compact Long Currency",
358             u"compact-long currency/USD",
359             u"KK currency/USD",
360             NumberFormatter::with().notation(Notation::compactLong()).unit(USD),
361             Locale::getEnglish(),
362             u"$88K", // should be something like "$88 thousand"
363             u"$8.8K",
364             u"$876",
365             u"$88",
366             u"$8.8",
367             u"$0.88",
368             u"$0.088",
369             u"$0.0088",
370             u"$0");
371
372     // Note: Most locales don't have compact long currency, so this currently falls back to short.
373     // This test case should be fixed when proper compact long currency patterns are added.
374     assertFormatDescending(
375             u"Compact Long with ISO Currency",
376             u"compact-long currency/USD unit-width-iso-code",
377             u"KK currency/USD unit-width-iso-code",
378             NumberFormatter::with().notation(Notation::compactLong())
379                     .unit(USD)
380                     .unitWidth(UNumberUnitWidth::UNUM_UNIT_WIDTH_ISO_CODE),
381             Locale::getEnglish(),
382             u"USD 88K", // should be something like "USD 88 thousand"
383             u"USD 8.8K",
384             u"USD 876",
385             u"USD 88",
386             u"USD 8.8",
387             u"USD 0.88",
388             u"USD 0.088",
389             u"USD 0.0088",
390             u"USD 0");
391
392     // TODO: This behavior could be improved and should be revisited.
393     assertFormatDescending(
394             u"Compact Long with Long Name Currency",
395             u"compact-long currency/USD unit-width-full-name",
396             u"KK currency/USD unit-width-full-name",
397             NumberFormatter::with().notation(Notation::compactLong())
398                     .unit(USD)
399                     .unitWidth(UNumberUnitWidth::UNUM_UNIT_WIDTH_FULL_NAME),
400             Locale::getEnglish(),
401             u"88 thousand US dollars",
402             u"8.8 thousand US dollars",
403             u"876 US dollars",
404             u"88 US dollars",
405             u"8.8 US dollars",
406             u"0.88 US dollars",
407             u"0.088 US dollars",
408             u"0.0088 US dollars",
409             u"0 US dollars");
410
411     assertFormatSingle(
412             u"Compact Plural One",
413             u"compact-long",
414             u"KK",
415             NumberFormatter::with().notation(Notation::compactLong()),
416             Locale::createFromName("es"),
417             1000000,
418             u"1 millón");
419
420     assertFormatSingle(
421             u"Compact Plural Other",
422             u"compact-long",
423             u"KK",
424             NumberFormatter::with().notation(Notation::compactLong()),
425             Locale::createFromName("es"),
426             2000000,
427             u"2 millones");
428
429     assertFormatSingle(
430             u"Compact with Negative Sign",
431             u"compact-short",
432             u"K",
433             NumberFormatter::with().notation(Notation::compactShort()),
434             Locale::getEnglish(),
435             -9876543.21,
436             u"-9.9M");
437
438     assertFormatSingle(
439             u"Compact Rounding",
440             u"compact-short",
441             u"K",
442             NumberFormatter::with().notation(Notation::compactShort()),
443             Locale::getEnglish(),
444             990000,
445             u"990K");
446
447     assertFormatSingle(
448             u"Compact Rounding",
449             u"compact-short",
450             u"K",
451             NumberFormatter::with().notation(Notation::compactShort()),
452             Locale::getEnglish(),
453             999000,
454             u"999K");
455
456     assertFormatSingle(
457             u"Compact Rounding",
458             u"compact-short",
459             u"K",
460             NumberFormatter::with().notation(Notation::compactShort()),
461             Locale::getEnglish(),
462             999900,
463             u"1M");
464
465     assertFormatSingle(
466             u"Compact Rounding",
467             u"compact-short",
468             u"K",
469             NumberFormatter::with().notation(Notation::compactShort()),
470             Locale::getEnglish(),
471             9900000,
472             u"9.9M");
473
474     assertFormatSingle(
475             u"Compact Rounding",
476             u"compact-short",
477             u"K",
478             NumberFormatter::with().notation(Notation::compactShort()),
479             Locale::getEnglish(),
480             9990000,
481             u"10M");
482
483     assertFormatSingle(
484             u"Compact in zh-Hant-HK",
485             u"compact-short",
486             u"K",
487             NumberFormatter::with().notation(Notation::compactShort()),
488             Locale("zh-Hant-HK"),
489             1e7,
490             u"10M");
491
492     assertFormatSingle(
493             u"Compact in zh-Hant",
494             u"compact-short",
495             u"K",
496             NumberFormatter::with().notation(Notation::compactShort()),
497             Locale("zh-Hant"),
498             1e7,
499             u"1000\u842C");
500
501     if (!logKnownIssue("21258", "StandardPlural cannot handle keywords 1, 0")) {
502         assertFormatSingle(
503                 u"Compact with plural form =1 (ICU-21258)",
504                 u"compact-long",
505                 u"K",
506                 NumberFormatter::with().notation(Notation::compactLong()),
507                 Locale("fr-FR"),
508                 1e3,
509                 u"mille");
510     }
511
512     assertFormatSingle(
513             u"Compact Infinity",
514             u"compact-short",
515             u"K",
516             NumberFormatter::with().notation(Notation::compactShort()),
517             Locale::getEnglish(),
518             -uprv_getInfinity(),
519             u"-∞");
520
521     assertFormatSingle(
522             u"Compact NaN",
523             u"compact-short",
524             u"K",
525             NumberFormatter::with().notation(Notation::compactShort()),
526             Locale::getEnglish(),
527             uprv_getNaN(),
528             u"NaN");
529
530     // NOTE: There is no API for compact custom data in C++
531     // and thus no "Compact Somali No Figure" test
532 }
533
534 void NumberFormatterApiTest::unitMeasure() {
535     IcuTestErrorCode status(*this, "unitMeasure()");
536
537     assertFormatDescending(
538             u"Meters Short and unit() method",
539             u"measure-unit/length-meter",
540             u"unit/meter",
541             NumberFormatter::with().unit(MeasureUnit::getMeter()),
542             Locale::getEnglish(),
543             u"87,650 m",
544             u"8,765 m",
545             u"876.5 m",
546             u"87.65 m",
547             u"8.765 m",
548             u"0.8765 m",
549             u"0.08765 m",
550             u"0.008765 m",
551             u"0 m");
552
553     assertFormatDescending(
554             u"Meters Long and adoptUnit() method",
555             u"measure-unit/length-meter unit-width-full-name",
556             u"unit/meter unit-width-full-name",
557             NumberFormatter::with().adoptUnit(new MeasureUnit(METER))
558                     .unitWidth(UNumberUnitWidth::UNUM_UNIT_WIDTH_FULL_NAME),
559             Locale::getEnglish(),
560             u"87,650 meters",
561             u"8,765 meters",
562             u"876.5 meters",
563             u"87.65 meters",
564             u"8.765 meters",
565             u"0.8765 meters",
566             u"0.08765 meters",
567             u"0.008765 meters",
568             u"0 meters");
569
570     assertFormatDescending(
571             u"Compact Meters Long",
572             u"compact-long measure-unit/length-meter unit-width-full-name",
573             u"KK unit/meter unit-width-full-name",
574             NumberFormatter::with().notation(Notation::compactLong())
575                     .unit(METER)
576                     .unitWidth(UNumberUnitWidth::UNUM_UNIT_WIDTH_FULL_NAME),
577             Locale::getEnglish(),
578             u"88 thousand meters",
579             u"8.8 thousand meters",
580             u"876 meters",
581             u"88 meters",
582             u"8.8 meters",
583             u"0.88 meters",
584             u"0.088 meters",
585             u"0.0088 meters",
586             u"0 meters");
587
588     assertFormatDescending(
589             u"Hectometers",
590             u"unit/hectometer",
591             u"unit/hectometer",
592             NumberFormatter::with().unit(MeasureUnit::forIdentifier("hectometer", status)),
593             Locale::getEnglish(),
594             u"87,650 hm",
595             u"8,765 hm",
596             u"876.5 hm",
597             u"87.65 hm",
598             u"8.765 hm",
599             u"0.8765 hm",
600             u"0.08765 hm",
601             u"0.008765 hm",
602             u"0 hm");
603
604 //    TODO: Implement Measure in C++
605 //    assertFormatSingleMeasure(
606 //            u"Meters with Measure Input",
607 //            NumberFormatter::with().unitWidth(UNumberUnitWidth::UNUM_UNIT_WIDTH_FULL_NAME),
608 //            Locale::getEnglish(),
609 //            new Measure(5.43, new MeasureUnit(METER)),
610 //            u"5.43 meters");
611
612 //    TODO: Implement Measure in C++
613 //    assertFormatSingleMeasure(
614 //            u"Measure format method takes precedence over fluent chain",
615 //            NumberFormatter::with().unit(METER),
616 //            Locale::getEnglish(),
617 //            new Measure(5.43, USD),
618 //            u"$5.43");
619
620     assertFormatSingle(
621             u"Meters with Negative Sign",
622             u"measure-unit/length-meter",
623             u"unit/meter",
624             NumberFormatter::with().unit(METER),
625             Locale::getEnglish(),
626             -9876543.21,
627             u"-9,876,543.21 m");
628
629     // The locale string "सान" appears only in brx.txt:
630     assertFormatSingle(
631             u"Interesting Data Fallback 1",
632             u"measure-unit/duration-day unit-width-full-name",
633             u"unit/day unit-width-full-name",
634             NumberFormatter::with().unit(DAY).unitWidth(UNumberUnitWidth::UNUM_UNIT_WIDTH_FULL_NAME),
635             Locale::createFromName("brx"),
636             5.43,
637             u"5.43 सान");
638
639     // Requires following the alias from unitsNarrow to unitsShort:
640     assertFormatSingle(
641             u"Interesting Data Fallback 2",
642             u"measure-unit/duration-day unit-width-narrow",
643             u"unit/day unit-width-narrow",
644             NumberFormatter::with().unit(DAY).unitWidth(UNumberUnitWidth::UNUM_UNIT_WIDTH_NARROW),
645             Locale::createFromName("brx"),
646             5.43,
647             u"5.43 d");
648
649     // en_001.txt has a unitsNarrow/area/square-meter table, but table does not contain the OTHER unit,
650     // requiring fallback to the root.
651     assertFormatSingle(
652             u"Interesting Data Fallback 3",
653             u"measure-unit/area-square-meter unit-width-narrow",
654             u"unit/square-meter unit-width-narrow",
655             NumberFormatter::with().unit(SQUARE_METER).unitWidth(UNumberUnitWidth::UNUM_UNIT_WIDTH_NARROW),
656             Locale::createFromName("en-GB"),
657             5.43,
658             u"5.43m²");
659
660     // Try accessing a narrow unit directly from root.
661     assertFormatSingle(
662             u"Interesting Data Fallback 4",
663             u"measure-unit/area-square-meter unit-width-narrow",
664             u"unit/square-meter unit-width-narrow",
665             NumberFormatter::with().unit(SQUARE_METER).unitWidth(UNumberUnitWidth::UNUM_UNIT_WIDTH_NARROW),
666             Locale::createFromName("root"),
667             5.43,
668             u"5.43 m²");
669
670     // es_US has "{0}°" for unitsNarrow/temperature/FAHRENHEIT.
671     // NOTE: This example is in the documentation.
672     assertFormatSingle(
673             u"Difference between Narrow and Short (Narrow Version)",
674             u"measure-unit/temperature-fahrenheit unit-width-narrow",
675             u"unit/fahrenheit unit-width-narrow",
676             NumberFormatter::with().unit(FAHRENHEIT).unitWidth(UNUM_UNIT_WIDTH_NARROW),
677             Locale("es-US"),
678             5.43,
679             u"5.43°");
680
681     assertFormatSingle(
682             u"Difference between Narrow and Short (Short Version)",
683             u"measure-unit/temperature-fahrenheit unit-width-short",
684             u"unit/fahrenheit unit-width-short",
685             NumberFormatter::with().unit(FAHRENHEIT).unitWidth(UNUM_UNIT_WIDTH_SHORT),
686             Locale("es-US"),
687             5.43,
688             u"5.43 °F");
689
690     assertFormatSingle(
691             u"MeasureUnit form without {0} in CLDR pattern",
692             u"measure-unit/temperature-kelvin unit-width-full-name",
693             u"unit/kelvin unit-width-full-name",
694             NumberFormatter::with().unit(KELVIN).unitWidth(UNumberUnitWidth::UNUM_UNIT_WIDTH_FULL_NAME),
695             Locale("es-MX"),
696             1,
697             u"kelvin");
698
699     assertFormatSingle(
700             u"MeasureUnit form without {0} in CLDR pattern and wide base form",
701             u"measure-unit/temperature-kelvin .00000000000000000000 unit-width-full-name",
702             u"unit/kelvin .00000000000000000000 unit-width-full-name",
703             NumberFormatter::with().precision(Precision::fixedFraction(20))
704                     .unit(KELVIN)
705                     .unitWidth(UNumberUnitWidth::UNUM_UNIT_WIDTH_FULL_NAME),
706             Locale("es-MX"),
707             1,
708             u"kelvin");
709
710     assertFormatSingle(
711             u"Person unit not in short form",
712             u"measure-unit/duration-year-person unit-width-full-name",
713             u"unit/year-person unit-width-full-name",
714             NumberFormatter::with().unit(MeasureUnit::getYearPerson())
715                     .unitWidth(UNumberUnitWidth::UNUM_UNIT_WIDTH_FULL_NAME),
716             Locale("es-MX"),
717             5,
718             u"5 a\u00F1os");
719
720     assertFormatSingle(
721             u"Hubble Constant - usually expressed in km/s/Mpc",
722             u"unit/kilometer-per-megaparsec-second",
723             u"unit/kilometer-per-megaparsec-second",
724             NumberFormatter::with().unit(MeasureUnit::forIdentifier("kilometer-per-second-per-megaparsec", status)),
725             Locale("en"),
726             74, // Approximate 2019-03-18 measurement
727             u"74 km/Mpc⋅sec");
728
729     assertFormatSingle(
730             u"Mixed unit",
731             u"unit/yard-and-foot-and-inch",
732             u"unit/yard-and-foot-and-inch",
733             NumberFormatter::with()
734                 .unit(MeasureUnit::forIdentifier("yard-and-foot-and-inch", status)),
735             Locale("en-US"),
736             3.65,
737             "3 yd, 1 ft, 11.4 in");
738
739     assertFormatSingle(
740             u"Mixed unit, Scientific",
741             u"unit/yard-and-foot-and-inch E0",
742             u"unit/yard-and-foot-and-inch E0",
743             NumberFormatter::with()
744                 .unit(MeasureUnit::forIdentifier("yard-and-foot-and-inch", status))
745                 .notation(Notation::scientific()),
746             Locale("en-US"),
747             3.65,
748             "3 yd, 1 ft, 1.14E1 in");
749
750     assertFormatSingle(
751             u"Mixed Unit (Narrow Version)",
752             u"unit/metric-ton-and-kilogram-and-gram unit-width-narrow",
753             u"unit/metric-ton-and-kilogram-and-gram unit-width-narrow",
754             NumberFormatter::with()
755                 .unit(MeasureUnit::forIdentifier("metric-ton-and-kilogram-and-gram", status))
756                 .unitWidth(UNUM_UNIT_WIDTH_NARROW),
757             Locale("en-US"),
758             4.28571,
759             u"4t 285kg 710g");
760
761     assertFormatSingle(
762             u"Mixed Unit (Short Version)",
763             u"unit/metric-ton-and-kilogram-and-gram unit-width-short",
764             u"unit/metric-ton-and-kilogram-and-gram unit-width-short",
765             NumberFormatter::with()
766                 .unit(MeasureUnit::forIdentifier("metric-ton-and-kilogram-and-gram", status))
767                 .unitWidth(UNUM_UNIT_WIDTH_SHORT),
768             Locale("en-US"),
769             4.28571,
770             u"4 t, 285 kg, 710 g");
771
772     assertFormatSingle(
773             u"Mixed Unit (Full Name Version)",
774             u"unit/metric-ton-and-kilogram-and-gram unit-width-full-name",
775             u"unit/metric-ton-and-kilogram-and-gram unit-width-full-name",
776             NumberFormatter::with()
777                 .unit(MeasureUnit::forIdentifier("metric-ton-and-kilogram-and-gram", status))
778                 .unitWidth(UNUM_UNIT_WIDTH_FULL_NAME),
779             Locale("en-US"),
780             4.28571,
781             u"4 metric tons, 285 kilograms, 710 grams");
782
783     assertFormatSingle(u"Mixed Unit (Not Sorted) [metric]",                               //
784                        u"unit/gram-and-kilogram unit-width-full-name",                    //
785                        u"unit/gram-and-kilogram unit-width-full-name",                    //
786                        NumberFormatter::with()                                            //
787                            .unit(MeasureUnit::forIdentifier("gram-and-kilogram", status)) //
788                            .unitWidth(UNUM_UNIT_WIDTH_FULL_NAME),                         //
789                        Locale("en-US"),                                                   //
790                        4.28571,                                                           //
791                        u"285.71 grams, 4 kilograms");                                     //
792
793     assertFormatSingle(u"Mixed Unit (Not Sorted) [imperial]",                                  //
794                        u"unit/inch-and-yard-and-foot unit-width-full-name",                    //
795                        u"unit/inch-and-yard-and-foot unit-width-full-name",                    //
796                        NumberFormatter::with()                                                 //
797                            .unit(MeasureUnit::forIdentifier("inch-and-yard-and-foot", status)) //
798                            .unitWidth(UNUM_UNIT_WIDTH_FULL_NAME),                              //
799                        Locale("en-US"),                                                        //
800                        4.28571,                                                                //
801                        u"10.28556 inches, 4 yards, 0 feet");                                   //
802
803     assertFormatSingle(u"Mixed Unit (Not Sorted) [imperial full]",                             //
804                        u"unit/inch-and-yard-and-foot unit-width-full-name",                    //
805                        u"unit/inch-and-yard-and-foot unit-width-full-name",                    //
806                        NumberFormatter::with()                                                 //
807                            .unit(MeasureUnit::forIdentifier("inch-and-yard-and-foot", status)) //
808                            .unitWidth(UNUM_UNIT_WIDTH_FULL_NAME),                              //
809                        Locale("en-US"),                                                        //
810                        4.38571,                                                                //
811                        u"1.88556 inches, 4 yards, 1 foot");                                    //
812
813     assertFormatSingle(u"Mixed Unit (Not Sorted) [imperial full integers]",                    //
814                        u"unit/inch-and-yard-and-foot @# unit-width-full-name",                 //
815                        u"unit/inch-and-yard-and-foot @# unit-width-full-name",                 //
816                        NumberFormatter::with()                                                 //
817                            .unit(MeasureUnit::forIdentifier("inch-and-yard-and-foot", status)) //
818                            .unitWidth(UNUM_UNIT_WIDTH_FULL_NAME)                               //
819                            .precision(Precision::maxSignificantDigits(2)),                     //
820                        Locale("en-US"),                                                        //
821                        4.36112,                                                                //
822                        u"1 inch, 4 yards, 1 foot");                                            //
823
824     assertFormatSingle(u"Mixed Unit (Not Sorted) [imperial full] with `And` in the end",       //
825                        u"unit/inch-and-yard-and-foot unit-width-full-name",                    //
826                        u"unit/inch-and-yard-and-foot unit-width-full-name",                    //
827                        NumberFormatter::with()                                                 //
828                            .unit(MeasureUnit::forIdentifier("inch-and-yard-and-foot", status)) //
829                            .unitWidth(UNUM_UNIT_WIDTH_FULL_NAME),                              //
830                        Locale("fr-FR"),                                                        //
831                        4.38571,                                                                //
832                        u"1,88556\u00A0pouce, 4\u00A0yards et 1\u00A0pied");                    //
833
834     assertFormatSingle(u"Mixed unit, Scientific [Not in Order]",                               //
835                        u"unit/foot-and-inch-and-yard E0",                                      //
836                        u"unit/foot-and-inch-and-yard E0",                                      //
837                        NumberFormatter::with()                                                 //
838                            .unit(MeasureUnit::forIdentifier("foot-and-inch-and-yard", status)) //
839                            .notation(Notation::scientific()),                                  //
840                        Locale("en-US"),                                                        //
841                        3.65,                                                                   //
842                        "1 ft, 1.14E1 in, 3 yd");                                               //
843
844     assertFormatSingle(
845             u"Testing  \"1 foot 12 inches\"",
846             u"unit/foot-and-inch @### unit-width-full-name",
847             u"unit/foot-and-inch @### unit-width-full-name",
848             NumberFormatter::with()
849                 .unit(MeasureUnit::forIdentifier("foot-and-inch", status))
850                 .precision(Precision::maxSignificantDigits(4))
851                 .unitWidth(UNUM_UNIT_WIDTH_FULL_NAME),
852             Locale("en-US"),
853             1.9999,
854             u"2 feet, 0 inches");
855
856     assertFormatSingle(
857             u"Negative numbers: temperature",
858             u"measure-unit/temperature-celsius",
859             u"unit/celsius",
860             NumberFormatter::with().unit(MeasureUnit::forIdentifier("celsius", status)),
861             Locale("nl-NL"),
862             -6.5,
863             u"-6,5°C");
864
865     assertFormatSingle(
866             u"Negative numbers: time",
867             u"unit/hour-and-minute-and-second",
868             u"unit/hour-and-minute-and-second",
869             NumberFormatter::with().unit(MeasureUnit::forIdentifier("hour-and-minute-and-second", status)),
870             Locale("de-DE"),
871             -1.24,
872             u"-1 Std., 14 Min. und 24 Sek.");
873
874     assertFormatSingle(
875             u"Zero out the unit field",
876             u"",
877             u"",
878             NumberFormatter::with().unit(KELVIN).unit(MeasureUnit()),
879             Locale("en"),
880             100,
881             u"100");
882
883     // TODO: desired behaviour for this "pathological" case?
884     // Since this is pointless, we don't test that its behaviour doesn't change.
885     // As of January 2021, the produced result has a missing sign: 23.5 Kelvin
886     // is "23 Kelvin and -272.65 degrees Celsius":
887 //     assertFormatSingle(
888 //             u"Meaningless: kelvin-and-celcius",
889 //             u"unit/kelvin-and-celsius",
890 //             u"unit/kelvin-and-celsius",
891 //             NumberFormatter::with().unit(MeasureUnit::forIdentifier("kelvin-and-celsius", status)),
892 //             Locale("en"),
893 //             23.5,
894 //             u"23 K, 272.65°C");
895
896     if (uprv_getNaN() != 0.0) {
897         assertFormatSingle(
898                 u"Measured -Inf",
899                 u"measure-unit/electric-ampere",
900                 u"unit/ampere",
901                 NumberFormatter::with().unit(MeasureUnit::getAmpere()),
902                 Locale("en"),
903                 -uprv_getInfinity(),
904                 u"-∞ A");
905
906         assertFormatSingle(
907                 u"Measured NaN",
908                 u"measure-unit/temperature-celsius",
909                 u"unit/celsius",
910                 NumberFormatter::with().unit(MeasureUnit::forIdentifier("celsius", status)),
911                 Locale("en"),
912                 uprv_getNaN(),
913                 u"NaN°C");
914     }
915 }
916
917 void NumberFormatterApiTest::unitCompoundMeasure() {
918     IcuTestErrorCode status(*this, "unitCompoundMeasure()");
919
920     assertFormatDescending(
921             u"Meters Per Second Short (unit that simplifies) and perUnit method",
922             u"measure-unit/length-meter per-measure-unit/duration-second",
923             u"unit/meter-per-second",
924             NumberFormatter::with().unit(METER).perUnit(SECOND),
925             Locale::getEnglish(),
926             u"87,650 m/s",
927             u"8,765 m/s",
928             u"876.5 m/s",
929             u"87.65 m/s",
930             u"8.765 m/s",
931             u"0.8765 m/s",
932             u"0.08765 m/s",
933             u"0.008765 m/s",
934             u"0 m/s");
935
936     assertFormatDescending(
937             u"Meters Per Second Short, built-in m/s",
938             u"measure-unit/speed-meter-per-second",
939             u"unit/meter-per-second",
940             NumberFormatter::with().unit(METER_PER_SECOND),
941             Locale::getEnglish(),
942             u"87,650 m/s",
943             u"8,765 m/s",
944             u"876.5 m/s",
945             u"87.65 m/s",
946             u"8.765 m/s",
947             u"0.8765 m/s",
948             u"0.08765 m/s",
949             u"0.008765 m/s",
950             u"0 m/s");
951
952     assertFormatDescending(
953             u"Pounds Per Square Mile Short (secondary unit has per-format) and adoptPerUnit method",
954             u"measure-unit/mass-pound per-measure-unit/area-square-mile",
955             u"unit/pound-per-square-mile",
956             NumberFormatter::with().unit(POUND).adoptPerUnit(new MeasureUnit(SQUARE_MILE)),
957             Locale::getEnglish(),
958             u"87,650 lb/mi²",
959             u"8,765 lb/mi²",
960             u"876.5 lb/mi²",
961             u"87.65 lb/mi²",
962             u"8.765 lb/mi²",
963             u"0.8765 lb/mi²",
964             u"0.08765 lb/mi²",
965             u"0.008765 lb/mi²",
966             u"0 lb/mi²");
967
968     assertFormatDescending(
969             u"Joules Per Furlong Short (unit with no simplifications or special patterns)",
970             u"measure-unit/energy-joule per-measure-unit/length-furlong",
971             u"unit/joule-per-furlong",
972             NumberFormatter::with().unit(JOULE).perUnit(FURLONG),
973             Locale::getEnglish(),
974             u"87,650 J/fur",
975             u"8,765 J/fur",
976             u"876.5 J/fur",
977             u"87.65 J/fur",
978             u"8.765 J/fur",
979             u"0.8765 J/fur",
980             u"0.08765 J/fur",
981             u"0.008765 J/fur",
982             u"0 J/fur");
983
984     assertFormatDescending(
985             u"Joules Per Furlong Short with unit identifier via API",
986             u"measure-unit/energy-joule per-measure-unit/length-furlong",
987             u"unit/joule-per-furlong",
988             NumberFormatter::with().unit(MeasureUnit::forIdentifier("joule-per-furlong", status)),
989             Locale::getEnglish(),
990             u"87,650 J/fur",
991             u"8,765 J/fur",
992             u"876.5 J/fur",
993             u"87.65 J/fur",
994             u"8.765 J/fur",
995             u"0.8765 J/fur",
996             u"0.08765 J/fur",
997             u"0.008765 J/fur",
998             u"0 J/fur");
999
1000     assertFormatDescending(
1001             u"Pounds per Square Inch: composed",
1002             u"measure-unit/force-pound-force per-measure-unit/area-square-inch",
1003             u"unit/pound-force-per-square-inch",
1004             NumberFormatter::with().unit(POUND_FORCE).perUnit(SQUARE_INCH),
1005             Locale::getEnglish(),
1006             u"87,650 psi",
1007             u"8,765 psi",
1008             u"876.5 psi",
1009             u"87.65 psi",
1010             u"8.765 psi",
1011             u"0.8765 psi",
1012             u"0.08765 psi",
1013             u"0.008765 psi",
1014             u"0 psi");
1015
1016     assertFormatDescending(
1017             u"Pounds per Square Inch: built-in",
1018             u"measure-unit/force-pound-force per-measure-unit/area-square-inch",
1019             u"unit/pound-force-per-square-inch",
1020             NumberFormatter::with().unit(MeasureUnit::getPoundPerSquareInch()),
1021             Locale::getEnglish(),
1022             u"87,650 psi",
1023             u"8,765 psi",
1024             u"876.5 psi",
1025             u"87.65 psi",
1026             u"8.765 psi",
1027             u"0.8765 psi",
1028             u"0.08765 psi",
1029             u"0.008765 psi",
1030             u"0 psi");
1031
1032     assertFormatSingle(
1033             u"m/s/s simplifies to m/s^2",
1034             u"measure-unit/speed-meter-per-second per-measure-unit/duration-second",
1035             u"unit/meter-per-square-second",
1036             NumberFormatter::with().unit(METER_PER_SECOND).perUnit(SECOND),
1037             Locale("en-GB"),
1038             2.4,
1039             u"2.4 m/s\u00B2");
1040
1041     assertFormatSingle(
1042             u"Negative numbers: acceleration",
1043             u"measure-unit/acceleration-meter-per-square-second",
1044             u"unit/meter-per-second-second",
1045             NumberFormatter::with().unit(MeasureUnit::forIdentifier("meter-per-pow2-second", status)),
1046             Locale("af-ZA"),
1047             -9.81,
1048             u"-9,81 m/s\u00B2");
1049
1050     // Testing the rejection of invalid specifications
1051
1052     // If .unit() is not given a built-in type, .perUnit() is not allowed
1053     // (because .unit is now flexible enough to handle compound units,
1054     // .perUnit() is supported for backward compatibility).
1055     LocalizedNumberFormatter nf = NumberFormatter::with()
1056              .unit(MeasureUnit::forIdentifier("furlong-pascal", status))
1057              .perUnit(METER)
1058              .locale("en-GB");
1059     status.assertSuccess(); // Error is only returned once we try to format.
1060     FormattedNumber num = nf.formatDouble(2.4, status);
1061     if (!status.expectErrorAndReset(U_UNSUPPORTED_ERROR)) {
1062         errln(UnicodeString("Expected failure for unit/furlong-pascal per-unit/length-meter, got: \"") +
1063               nf.formatDouble(2.4, status).toString(status) + "\".");
1064         status.assertSuccess();
1065     }
1066
1067     // .perUnit() may only be passed a built-in type, or something that combines
1068     // to a built-in type together with .unit().
1069     MeasureUnit SQUARE_SECOND = MeasureUnit::forIdentifier("square-second", status);
1070     nf = NumberFormatter::with().unit(FURLONG).perUnit(SQUARE_SECOND).locale("en-GB");
1071     status.assertSuccess(); // Error is only returned once we try to format.
1072     num = nf.formatDouble(2.4, status);
1073     if (!status.expectErrorAndReset(U_UNSUPPORTED_ERROR)) {
1074         errln(UnicodeString("Expected failure, got: \"") +
1075               nf.formatDouble(2.4, status).toString(status) + "\".");
1076         status.assertSuccess();
1077     }
1078     // As above, "square-second" is not a built-in type, however this time,
1079     // meter-per-square-second is a built-in type.
1080     assertFormatSingle(
1081             u"meter per square-second works as a composed unit",
1082             u"measure-unit/speed-meter-per-second per-measure-unit/duration-second",
1083             u"unit/meter-per-square-second",
1084             NumberFormatter::with().unit(METER).perUnit(SQUARE_SECOND),
1085             Locale("en-GB"),
1086             2.4,
1087             u"2.4 m/s\u00B2");
1088 }
1089
1090 void NumberFormatterApiTest::unitArbitraryMeasureUnits() {
1091     IcuTestErrorCode status(*this, "unitArbitraryMeasureUnits()");
1092
1093     // TODO: fix after data bug is resolved? See CLDR-14510.
1094 //     assertFormatSingle(
1095 //             u"Binary unit prefix: kibibyte",
1096 //             u"unit/kibibyte",
1097 //             u"unit/kibibyte",
1098 //             NumberFormatter::with().unit(MeasureUnit::forIdentifier("kibibyte", status)),
1099 //             Locale("en-GB"),
1100 //             2.4,
1101 //             u"2.4 KiB");
1102
1103     assertFormatSingle(
1104             u"Binary unit prefix: kibibyte full-name",
1105             u"unit/kibibyte unit-width-full-name",
1106             u"unit/kibibyte unit-width-full-name",
1107             NumberFormatter::with()
1108                 .unit(MeasureUnit::forIdentifier("kibibyte", status))
1109                 .unitWidth(UNUM_UNIT_WIDTH_FULL_NAME),
1110             Locale("en-GB"),
1111             2.4,
1112             u"2.4 kibibytes");
1113
1114     assertFormatSingle(
1115             u"Binary unit prefix: kibibyte full-name",
1116             u"unit/kibibyte unit-width-full-name",
1117             u"unit/kibibyte unit-width-full-name",
1118             NumberFormatter::with()
1119                 .unit(MeasureUnit::forIdentifier("kibibyte", status))
1120                 .unitWidth(UNUM_UNIT_WIDTH_FULL_NAME),
1121             Locale("de"),
1122             2.4,
1123             u"2,4 Kibibyte");
1124
1125     assertFormatSingle(
1126             u"Binary prefix for non-digital units: kibimeter",
1127             u"unit/kibimeter",
1128             u"unit/kibimeter",
1129             NumberFormatter::with()
1130                 .unit(MeasureUnit::forIdentifier("kibimeter", status)),
1131             Locale("en-GB"),
1132             2.4,
1133             u"2.4 Kim");
1134
1135     assertFormatSingle(
1136             u"SI prefix falling back to root: microohm",
1137             u"unit/microohm",
1138             u"unit/microohm",
1139             NumberFormatter::with()
1140                 .unit(MeasureUnit::forIdentifier("microohm", status)),
1141             Locale("de-CH"),
1142             2.4,
1143             u"2.4 μΩ");
1144
1145     assertFormatSingle(
1146             u"de-CH fallback to de: microohm unit-width-full-name",
1147             u"unit/microohm unit-width-full-name",
1148             u"unit/microohm unit-width-full-name",
1149             NumberFormatter::with()
1150                 .unit(MeasureUnit::forIdentifier("microohm", status))
1151                 .unitWidth(UNUM_UNIT_WIDTH_FULL_NAME),
1152             Locale("de-CH"),
1153             2.4,
1154             u"2.4\u00A0Mikroohm");
1155
1156     assertFormatSingle(
1157             u"No prefixes, 'times' pattern: joule-furlong",
1158             u"unit/joule-furlong",
1159             u"unit/joule-furlong",
1160             NumberFormatter::with()
1161                 .unit(MeasureUnit::forIdentifier("joule-furlong", status)),
1162             Locale("en"),
1163             2.4,
1164             u"2.4 J⋅fur");
1165
1166     assertFormatSingle(
1167             u"No numeratorUnitString: per-second",
1168             u"unit/per-second",
1169             u"unit/per-second",
1170             NumberFormatter::with()
1171                 .unit(MeasureUnit::forIdentifier("per-second", status)),
1172             Locale("de-CH"),
1173             2.4,
1174             u"2.4/s");
1175
1176     assertFormatSingle(
1177             u"No numeratorUnitString: per-second unit-width-full-name",
1178             u"unit/per-second unit-width-full-name",
1179             u"unit/per-second unit-width-full-name",
1180             NumberFormatter::with()
1181                 .unit(MeasureUnit::forIdentifier("per-second", status))
1182                 .unitWidth(UNUM_UNIT_WIDTH_FULL_NAME),
1183             Locale("de-CH"),
1184             2.4,
1185             u"2.4 pro Sekunde");
1186
1187     assertFormatSingle(
1188             u"Prefix in the denominator: nanogram-per-picobarrel",
1189             u"unit/nanogram-per-picobarrel",
1190             u"unit/nanogram-per-picobarrel",
1191             NumberFormatter::with()
1192                 .unit(MeasureUnit::forIdentifier("nanogram-per-picobarrel", status)),
1193             Locale("en-ZA"),
1194             2.4,
1195             u"2,4 ng/pbbl");
1196
1197     assertFormatSingle(
1198             u"Prefix in the denominator: nanogram-per-picobarrel unit-width-full-name",
1199             u"unit/nanogram-per-picobarrel unit-width-full-name",
1200             u"unit/nanogram-per-picobarrel unit-width-full-name",
1201             NumberFormatter::with()
1202                 .unit(MeasureUnit::forIdentifier("nanogram-per-picobarrel", status))
1203                 .unitWidth(UNUM_UNIT_WIDTH_FULL_NAME),
1204             Locale("en-ZA"),
1205             2.4,
1206             u"2,4 nanograms per picobarrel");
1207
1208     // Valid MeasureUnit, but unformattable, because we only have patterns for
1209     // pow2 and pow3 at this time:
1210     LocalizedNumberFormatter lnf = NumberFormatter::with()
1211               .unit(MeasureUnit::forIdentifier("pow4-mile", status))
1212               .unitWidth(UNUM_UNIT_WIDTH_FULL_NAME)
1213               .locale("en-ZA");
1214     lnf.formatInt(1, status);
1215     status.expectErrorAndReset(U_RESOURCE_TYPE_MISMATCH);
1216
1217     assertFormatSingle(
1218             u"kibijoule-foot-per-cubic-gigafurlong-square-second unit-width-full-name",
1219             u"unit/kibijoule-foot-per-cubic-gigafurlong-square-second unit-width-full-name",
1220             u"unit/kibijoule-foot-per-cubic-gigafurlong-square-second unit-width-full-name",
1221             NumberFormatter::with()
1222                 .unit(MeasureUnit::forIdentifier("kibijoule-foot-per-cubic-gigafurlong-square-second",
1223                                                  status))
1224                 .unitWidth(UNUM_UNIT_WIDTH_FULL_NAME),
1225             Locale("en-ZA"),
1226             2.4,
1227             u"2,4 kibijoule-feet per cubic gigafurlong-square second");
1228
1229     assertFormatSingle(
1230             u"kibijoule-foot-per-cubic-gigafurlong-square-second unit-width-full-name",
1231             u"unit/kibijoule-foot-per-cubic-gigafurlong-square-second unit-width-full-name",
1232             u"unit/kibijoule-foot-per-cubic-gigafurlong-square-second unit-width-full-name",
1233             NumberFormatter::with()
1234                 .unit(MeasureUnit::forIdentifier("kibijoule-foot-per-cubic-gigafurlong-square-second",
1235                                                  status))
1236                 .unitWidth(UNUM_UNIT_WIDTH_FULL_NAME),
1237             Locale("de-CH"),
1238             2.4,
1239             u"2.4\u00A0Kibijoule⋅Fuss pro Kubikgigafurlong⋅Quadratsekunde");
1240
1241     // TODO(ICU-21504): We want to be able to format this, but "100-kilometer"
1242     // is not yet supported when it's not part of liter-per-100-kilometer:
1243     lnf = NumberFormatter::with()
1244               .unit(MeasureUnit::forIdentifier("kilowatt-hour-per-100-kilometer", status))
1245               .unitWidth(UNUM_UNIT_WIDTH_FULL_NAME)
1246               .locale("en-ZA");
1247     lnf.formatInt(1, status);
1248     status.expectErrorAndReset(U_UNSUPPORTED_ERROR);
1249 }
1250
1251 // TODO: merge these tests into numbertest_skeletons.cpp instead of here:
1252 void NumberFormatterApiTest::unitSkeletons() {
1253     const struct TestCase {
1254         const char *msg;
1255         const char16_t *inputSkeleton;
1256         const char16_t *normalizedSkeleton;
1257     } cases[] = {
1258         {"old-form built-in compound unit",      //
1259          u"measure-unit/speed-meter-per-second", //
1260          u"unit/meter-per-second"},
1261
1262         {"old-form compound construction, converts to built-in",        //
1263          u"measure-unit/length-meter per-measure-unit/duration-second", //
1264          u"unit/meter-per-second"},
1265
1266         {"old-form compound construction which does not simplify to a built-in", //
1267          u"measure-unit/energy-joule per-measure-unit/length-meter",             //
1268          u"unit/joule-per-meter"},
1269
1270         {"old-form compound-compound ugliness resolves neatly",                   //
1271          u"measure-unit/speed-meter-per-second per-measure-unit/duration-second", //
1272          u"unit/meter-per-square-second"},
1273
1274         {"short-form built-in units stick with the built-in", //
1275          u"unit/meter-per-second",                            //
1276          u"unit/meter-per-second"},
1277
1278         {"short-form compound units stay as is", //
1279          u"unit/square-meter-per-square-meter",  //
1280          u"unit/square-meter-per-square-meter"},
1281
1282         {"short-form compound units stay as is", //
1283          u"unit/joule-per-furlong",              //
1284          u"unit/joule-per-furlong"},
1285
1286         {"short-form that doesn't consist of built-in units", //
1287          u"unit/hectometer-per-second",                       //
1288          u"unit/hectometer-per-second"},
1289
1290         {"short-form that doesn't consist of built-in units", //
1291          u"unit/meter-per-hectosecond",                       //
1292          u"unit/meter-per-hectosecond"},
1293
1294         {"percent compound skeletons handled correctly", //
1295          u"unit/percent-per-meter",                      //
1296          u"unit/percent-per-meter"},
1297
1298         {"permille compound skeletons handled correctly",                 //
1299          u"measure-unit/concentr-permille per-measure-unit/length-meter", //
1300          u"unit/permille-per-meter"},
1301
1302         {"percent simple unit is not actually considered a unit", //
1303          u"unit/percent",                                         //
1304          u"percent"},
1305
1306         {"permille simple unit is not actually considered a unit", //
1307          u"measure-unit/concentr-permille",                        //
1308          u"permille"},
1309
1310         {"Round-trip example from icu-units#35", //
1311          u"unit/kibijoule-per-furlong",          //
1312          u"unit/kibijoule-per-furlong"},
1313     };
1314     for (auto &cas : cases) {
1315         IcuTestErrorCode status(*this, cas.msg);
1316         auto nf = NumberFormatter::forSkeleton(cas.inputSkeleton, status);
1317         if (status.errIfFailureAndReset("NumberFormatter::forSkeleton failed")) {
1318             continue;
1319         }
1320         assertEquals(                                                       //
1321             UnicodeString(TRUE, cas.inputSkeleton, -1) + u" normalization", //
1322             cas.normalizedSkeleton,                                         //
1323             nf.toSkeleton(status));
1324         status.errIfFailureAndReset("NumberFormatter::toSkeleton failed");
1325     }
1326
1327     const struct FailCase {
1328         const char *msg;
1329         const char16_t *inputSkeleton;
1330         UErrorCode expectedForSkelStatus;
1331         UErrorCode expectedToSkelStatus;
1332     } failCases[] = {
1333         {"Parsing measure-unit/* results in failure if not built-in unit",
1334          u"measure-unit/hectometer",     //
1335          U_NUMBER_SKELETON_SYNTAX_ERROR, //
1336          U_ZERO_ERROR},
1337
1338         {"Parsing per-measure-unit/* results in failure if not built-in unit",
1339          u"measure-unit/meter per-measure-unit/hectosecond", //
1340          U_NUMBER_SKELETON_SYNTAX_ERROR,                     //
1341          U_ZERO_ERROR},
1342
1343         {"\"currency/EUR measure-unit/length-meter\" fails, conflicting skeleton.",
1344          u"currency/EUR measure-unit/length-meter", //
1345          U_NUMBER_SKELETON_SYNTAX_ERROR,            //
1346          U_ZERO_ERROR},
1347
1348         {"\"measure-unit/length-meter currency/EUR\" fails, conflicting skeleton.",
1349          u"measure-unit/length-meter currency/EUR", //
1350          U_NUMBER_SKELETON_SYNTAX_ERROR,            //
1351          U_ZERO_ERROR},
1352
1353         {"\"currency/EUR per-measure-unit/meter\" fails, conflicting skeleton.",
1354          u"currency/EUR per-measure-unit/length-meter", //
1355          U_NUMBER_SKELETON_SYNTAX_ERROR,                //
1356          U_ZERO_ERROR},
1357     };
1358     for (auto &cas : failCases) {
1359         IcuTestErrorCode status(*this, cas.msg);
1360         auto nf = NumberFormatter::forSkeleton(cas.inputSkeleton, status);
1361         if (status.expectErrorAndReset(cas.expectedForSkelStatus, cas.msg)) {
1362             continue;
1363         }
1364         nf.toSkeleton(status);
1365         status.expectErrorAndReset(cas.expectedToSkelStatus, cas.msg);
1366     }
1367
1368     IcuTestErrorCode status(*this, "unitSkeletons");
1369     assertEquals(                                //
1370         ".unit(METER_PER_SECOND) normalization", //
1371         u"unit/meter-per-second",                //
1372         NumberFormatter::with().unit(METER_PER_SECOND).toSkeleton(status));
1373     assertEquals(                                     //
1374         ".unit(METER).perUnit(SECOND) normalization", //
1375         u"unit/meter-per-second",
1376         NumberFormatter::with().unit(METER).perUnit(SECOND).toSkeleton(status));
1377     assertEquals(                                                                  //
1378         ".unit(MeasureUnit::forIdentifier(\"hectometer\", status)) normalization", //
1379         u"unit/hectometer",
1380         NumberFormatter::with()
1381             .unit(MeasureUnit::forIdentifier("hectometer", status))
1382             .toSkeleton(status));
1383     assertEquals(                                                                  //
1384         ".unit(MeasureUnit::forIdentifier(\"hectometer\", status)) normalization", //
1385         u"unit/meter-per-hectosecond",
1386         NumberFormatter::with()
1387             .unit(METER)
1388             .perUnit(MeasureUnit::forIdentifier("hectosecond", status))
1389             .toSkeleton(status));
1390
1391     status.assertSuccess();
1392     assertEquals(                                                //
1393         ".unit(CURRENCY) produces a currency/CURRENCY skeleton", //
1394         u"currency/GBP",                                         //
1395         NumberFormatter::with().unit(GBP).toSkeleton(status));
1396     status.assertSuccess();
1397     // .unit(CURRENCY).perUnit(ANYTHING) is not supported.
1398     NumberFormatter::with().unit(GBP).perUnit(METER).toSkeleton(status);
1399     status.expectErrorAndReset(U_UNSUPPORTED_ERROR);
1400 }
1401
1402 void NumberFormatterApiTest::unitUsage() {
1403     IcuTestErrorCode status(*this, "unitUsage()");
1404     UnlocalizedNumberFormatter unloc_formatter;
1405     LocalizedNumberFormatter formatter;
1406     FormattedNumber formattedNum;
1407     UnicodeString uTestCase;
1408
1409     status.assertSuccess();
1410     formattedNum =
1411         NumberFormatter::with().usage("road").locale(Locale::getEnglish()).formatInt(1, status);
1412     status.expectErrorAndReset(U_ILLEGAL_ARGUMENT_ERROR);
1413
1414     unloc_formatter = NumberFormatter::with().usage("road").unit(MeasureUnit::getMeter());
1415
1416     uTestCase = u"unitUsage() en-ZA road";
1417     formatter = unloc_formatter.locale("en-ZA");
1418     formattedNum = formatter.formatDouble(321, status);
1419     status.errIfFailureAndReset("unitUsage() en-ZA road formatDouble");
1420     assertTrue(
1421             uTestCase + u", got outputUnit: \"" + formattedNum.getOutputUnit(status).getIdentifier() + "\"",
1422             MeasureUnit::getMeter() == formattedNum.getOutputUnit(status));
1423     assertEquals(uTestCase, "300 m", formattedNum.toString(status));
1424     {
1425         static const UFieldPosition expectedFieldPositions[] = {
1426                 {UNUM_INTEGER_FIELD, 0, 3},
1427                 {UNUM_MEASURE_UNIT_FIELD, 4, 5}};
1428         assertNumberFieldPositions(
1429                 (uTestCase + u" field positions").getTerminatedBuffer(),
1430                 formattedNum,
1431                 expectedFieldPositions,
1432                 UPRV_LENGTHOF(expectedFieldPositions));
1433     }
1434     assertFormatDescendingBig(
1435             uTestCase.getTerminatedBuffer(),
1436             u"measure-unit/length-meter usage/road",
1437             u"unit/meter usage/road",
1438             unloc_formatter,
1439             Locale("en-ZA"),
1440             u"87\u00A0650 km",
1441             u"8\u00A0765 km",
1442             u"876 km", // 6.5 rounds down, 7.5 rounds up.
1443             u"88 km",
1444             u"8,8 km",
1445             u"900 m",
1446             u"90 m",
1447             u"9 m",
1448             u"0 m");
1449
1450     uTestCase = u"unitUsage() en-GB road";
1451     formatter = unloc_formatter.locale("en-GB");
1452     formattedNum = formatter.formatDouble(321, status);
1453     status.errIfFailureAndReset("unitUsage() en-GB road, formatDouble(...)");
1454     assertTrue(
1455             uTestCase + u", got outputUnit: \"" + formattedNum.getOutputUnit(status).getIdentifier() + "\"",
1456             MeasureUnit::getYard() == formattedNum.getOutputUnit(status));
1457     status.errIfFailureAndReset("unitUsage() en-GB road, getOutputUnit(...)");
1458     assertEquals(uTestCase, "350 yd", formattedNum.toString(status));
1459     status.errIfFailureAndReset("unitUsage() en-GB road, toString(...)");
1460     {
1461         static const UFieldPosition expectedFieldPositions[] = {
1462                 {UNUM_INTEGER_FIELD, 0, 3},
1463                 {UNUM_MEASURE_UNIT_FIELD, 4, 6}};
1464         assertNumberFieldPositions(
1465                 (uTestCase + u" field positions").getTerminatedBuffer(),
1466                 formattedNum,
1467                 expectedFieldPositions,
1468                 UPRV_LENGTHOF(expectedFieldPositions));
1469     }
1470     assertFormatDescendingBig(
1471             uTestCase.getTerminatedBuffer(),
1472             u"measure-unit/length-meter usage/road",
1473             u"unit/meter usage/road",
1474             unloc_formatter,
1475             Locale("en-GB"),
1476             u"54,463 mi",
1477             u"5,446 mi",
1478             u"545 mi",
1479             u"54 mi",
1480             u"5.4 mi",
1481             u"0.54 mi",
1482             u"100 yd",
1483             u"10 yd",
1484             u"0 yd");
1485
1486     uTestCase = u"unitUsage() en-US road";
1487     formatter = unloc_formatter.locale("en-US");
1488     formattedNum = formatter.formatDouble(321, status);
1489     status.errIfFailureAndReset("unitUsage() en-US road, formatDouble(...)");
1490     assertTrue(
1491             uTestCase + u", got outputUnit: \"" + formattedNum.getOutputUnit(status).getIdentifier() + "\"",
1492             MeasureUnit::getFoot() == formattedNum.getOutputUnit(status));
1493     status.errIfFailureAndReset("unitUsage() en-US road, getOutputUnit(...)");
1494     assertEquals(uTestCase, "1,050 ft", formattedNum.toString(status));
1495     status.errIfFailureAndReset("unitUsage() en-US road, toString(...)");
1496     {
1497         static const UFieldPosition expectedFieldPositions[] = {
1498                 {UNUM_GROUPING_SEPARATOR_FIELD, 1, 2},
1499                 {UNUM_INTEGER_FIELD, 0, 5},
1500                 {UNUM_MEASURE_UNIT_FIELD, 6, 8}};
1501         assertNumberFieldPositions(
1502                 (uTestCase + u" field positions").getTerminatedBuffer(),
1503                 formattedNum,
1504                 expectedFieldPositions,
1505                 UPRV_LENGTHOF(expectedFieldPositions));
1506     }
1507     assertFormatDescendingBig(
1508             uTestCase.getTerminatedBuffer(),
1509             u"measure-unit/length-meter usage/road",
1510             u"unit/meter usage/road",
1511             unloc_formatter,
1512             Locale("en-US"),
1513             u"54,463 mi",
1514             u"5,446 mi",
1515             u"545 mi",
1516             u"54 mi",
1517             u"5.4 mi",
1518             u"0.54 mi",
1519             u"300 ft",
1520             u"30 ft",
1521             u"0 ft");
1522
1523     unloc_formatter = NumberFormatter::with().usage("person").unit(MeasureUnit::getKilogram());
1524     uTestCase = u"unitUsage() en-GB person";
1525     formatter = unloc_formatter.locale("en-GB");
1526     formattedNum = formatter.formatDouble(80, status);
1527     status.errIfFailureAndReset("unitUsage() en-GB person formatDouble");
1528     assertTrue(
1529         uTestCase + ", got outputUnit: \"" + formattedNum.getOutputUnit(status).getIdentifier() + "\"",
1530         MeasureUnit::forIdentifier("stone-and-pound", status) == formattedNum.getOutputUnit(status));
1531     status.errIfFailureAndReset("unitUsage() en-GB person - formattedNum.getOutputUnit(status)");
1532     assertEquals(uTestCase, "12 st, 8.4 lb", formattedNum.toString(status));
1533     status.errIfFailureAndReset("unitUsage() en-GB person, toString(...)");
1534     {
1535         static const UFieldPosition expectedFieldPositions[] = {
1536                 // // Desired output: TODO(icu-units#67)
1537                 // {UNUM_INTEGER_FIELD, 0, 2},
1538                 // {UNUM_MEASURE_UNIT_FIELD, 3, 5},
1539                 // {ULISTFMT_LITERAL_FIELD, 5, 6},
1540                 // {UNUM_INTEGER_FIELD, 7, 8},
1541                 // {UNUM_DECIMAL_SEPARATOR_FIELD, 8, 9},
1542                 // {UNUM_FRACTION_FIELD, 9, 10},
1543                 // {UNUM_MEASURE_UNIT_FIELD, 11, 13}};
1544
1545                 // Current output: rather no fields than wrong fields
1546                 {UNUM_INTEGER_FIELD, 7, 8},
1547                 {UNUM_DECIMAL_SEPARATOR_FIELD, 8, 9},
1548                 {UNUM_FRACTION_FIELD, 9, 10},
1549                 };
1550         assertNumberFieldPositions(
1551                 (uTestCase + u" field positions").getTerminatedBuffer(),
1552                 formattedNum,
1553                 expectedFieldPositions,
1554                 UPRV_LENGTHOF(expectedFieldPositions));
1555     }
1556     assertFormatDescending(
1557             uTestCase.getTerminatedBuffer(),
1558             u"measure-unit/mass-kilogram usage/person",
1559             u"unit/kilogram usage/person",
1560             unloc_formatter,
1561             Locale("en-GB"),
1562             u"13,802 st, 7.2 lb",
1563             u"1,380 st, 3.5 lb",
1564             u"138 st, 0.35 lb",
1565             u"13 st, 11 lb",
1566             u"1 st, 5.3 lb",
1567             u"1 lb, 15 oz",
1568             u"0 lb, 3.1 oz",
1569             u"0 lb, 0.31 oz",
1570             u"0 lb, 0 oz");
1571
1572    assertFormatDescending(
1573             uTestCase.getTerminatedBuffer(),
1574             u"usage/person unit-width-narrow measure-unit/mass-kilogram",
1575             u"usage/person unit-width-narrow unit/kilogram",
1576             unloc_formatter.unitWidth(UNUM_UNIT_WIDTH_NARROW),
1577             Locale("en-GB"),
1578             u"13,802st 7.2lb",
1579             u"1,380st 3.5lb",
1580             u"138st 0.35lb",
1581             u"13st 11lb",
1582             u"1st 5.3lb",
1583             u"1lb 15oz",
1584             u"0lb 3.1oz",
1585             u"0lb 0.31oz",
1586             u"0lb 0oz");
1587
1588    assertFormatDescending(
1589             uTestCase.getTerminatedBuffer(),
1590             u"usage/person unit-width-short measure-unit/mass-kilogram",
1591             u"usage/person unit-width-short unit/kilogram",
1592             unloc_formatter.unitWidth(UNUM_UNIT_WIDTH_SHORT),
1593             Locale("en-GB"),
1594             u"13,802 st, 7.2 lb",
1595             u"1,380 st, 3.5 lb",
1596             u"138 st, 0.35 lb",
1597             u"13 st, 11 lb",
1598             u"1 st, 5.3 lb",
1599             u"1 lb, 15 oz",
1600             u"0 lb, 3.1 oz",
1601             u"0 lb, 0.31 oz",
1602             u"0 lb, 0 oz");
1603
1604    assertFormatDescending(
1605             uTestCase.getTerminatedBuffer(),
1606             u"usage/person unit-width-full-name measure-unit/mass-kilogram",
1607             u"usage/person unit-width-full-name unit/kilogram",
1608             unloc_formatter.unitWidth(UNUM_UNIT_WIDTH_FULL_NAME),
1609             Locale("en-GB"),
1610             u"13,802 stone, 7.2 pounds",
1611             u"1,380 stone, 3.5 pounds",
1612             u"138 stone, 0.35 pounds",
1613             u"13 stone, 11 pounds",
1614             u"1 stone, 5.3 pounds",
1615             u"1 pound, 15 ounces",
1616             u"0 pounds, 3.1 ounces",
1617             u"0 pounds, 0.31 ounces",
1618             u"0 pounds, 0 ounces");
1619
1620     assertFormatDescendingBig(
1621             u"Scientific notation with Usage: possible when using a reasonable Precision",
1622             u"scientific @### usage/default measure-unit/area-square-meter unit-width-full-name",
1623             u"scientific @### usage/default unit/square-meter unit-width-full-name",
1624             NumberFormatter::with()
1625                     .unit(SQUARE_METER)
1626                     .usage("default")
1627                     .notation(Notation::scientific())
1628                     .precision(Precision::minMaxSignificantDigits(1, 4))
1629                     .unitWidth(UNumberUnitWidth::UNUM_UNIT_WIDTH_FULL_NAME),
1630             Locale("en-ZA"),
1631             u"8,765E1 square kilometres",
1632             u"8,765E0 square kilometres",
1633             u"8,765E1 hectares",
1634             u"8,765E0 hectares",
1635             u"8,765E3 square metres",
1636             u"8,765E2 square metres",
1637             u"8,765E1 square metres",
1638             u"8,765E0 square metres",
1639             u"0E0 square centimetres");
1640
1641     assertFormatSingle(
1642             u"Negative Infinity with Unit Preferences",
1643             u"measure-unit/area-acre usage/default",
1644             u"unit/acre usage/default",
1645             NumberFormatter::with().unit(MeasureUnit::getAcre()).usage("default"),
1646             Locale::getEnglish(),
1647             -uprv_getInfinity(),
1648             u"-∞ km²");
1649
1650 //     // TODO(icu-units#131): do we care about NaN?
1651 //     // TODO: on some platforms with MSVC, "-NaN sec" is returned.
1652 //     assertFormatSingle(
1653 //             u"NaN with Unit Preferences",
1654 //             u"measure-unit/area-acre usage/default",
1655 //             u"unit/acre usage/default",
1656 //             NumberFormatter::with().unit(MeasureUnit::getAcre()).usage("default"),
1657 //             Locale::getEnglish(),
1658 //             uprv_getNaN(),
1659 //             u"NaN cm²");
1660
1661     assertFormatSingle(
1662             u"Negative numbers: minute-and-second",
1663             u"measure-unit/duration-second usage/media",
1664             u"unit/second usage/media",
1665             NumberFormatter::with().unit(SECOND).usage("media"),
1666             Locale("nl-NL"),
1667             -77.7,
1668             u"-1 min, 18 sec");
1669
1670     assertFormatSingle(
1671             u"Negative numbers: media seconds",
1672             u"measure-unit/duration-second usage/media",
1673             u"unit/second usage/media",
1674             NumberFormatter::with().unit(SECOND).usage("media"),
1675             Locale("nl-NL"),
1676             -2.7,
1677             u"-2,7 sec");
1678
1679 //     // TODO: on some platforms with MSVC, "-NaN sec" is returned.
1680 //     assertFormatSingle(
1681 //             u"NaN minute-and-second",
1682 //             u"measure-unit/duration-second usage/media",
1683 //             u"unit/second usage/media",
1684 //             NumberFormatter::with().unit(SECOND).usage("media"),
1685 //             Locale("nl-NL"),
1686 //             uprv_getNaN(),
1687 //             u"NaN sec");
1688
1689     assertFormatSingle(
1690             u"NaN meter-and-centimeter",
1691             u"measure-unit/length-meter usage/person-height",
1692             u"unit/meter usage/person-height",
1693             NumberFormatter::with().unit(METER).usage("person-height"),
1694             Locale("sv-SE"),
1695             uprv_getNaN(),
1696             u"0 m, NaN cm");
1697
1698     assertFormatSingle(
1699             u"Rounding Mode propagates: rounding down",
1700             u"usage/road measure-unit/length-centimeter rounding-mode-floor",
1701             u"usage/road unit/centimeter rounding-mode-floor",
1702             NumberFormatter::with()
1703                 .unit(MeasureUnit::forIdentifier("centimeter", status))
1704                 .usage("road")
1705                 .roundingMode(UNUM_ROUND_FLOOR),
1706             Locale("en-ZA"),
1707             34500,
1708             u"300 m");
1709
1710     assertFormatSingle(
1711             u"Rounding Mode propagates: rounding up",
1712             u"usage/road measure-unit/length-centimeter rounding-mode-ceiling",
1713             u"usage/road unit/centimeter rounding-mode-ceiling",
1714             NumberFormatter::with()
1715                 .unit(MeasureUnit::forIdentifier("centimeter", status))
1716                 .usage("road")
1717                 .roundingMode(UNUM_ROUND_CEILING),
1718             Locale("en-ZA"),
1719             30500,
1720             u"350 m");
1721
1722     // Test calling `.usage("")` should unset the existing usage.
1723     // First: without usage
1724     assertFormatSingle(u"Rounding Mode propagates: rounding up",
1725                        u"measure-unit/length-centimeter rounding-mode-ceiling",
1726                        u"unit/centimeter rounding-mode-ceiling",
1727                        NumberFormatter::with()
1728                            .unit(MeasureUnit::forIdentifier("centimeter", status))
1729                            .roundingMode(UNUM_ROUND_CEILING),
1730                        Locale("en-US"), //
1731                        3048,            //
1732                        u"3,048 cm");
1733
1734     // Second: with "road" usage
1735     assertFormatSingle(u"Rounding Mode propagates: rounding up",
1736                        u"usage/road measure-unit/length-centimeter rounding-mode-ceiling",
1737                        u"usage/road unit/centimeter rounding-mode-ceiling",
1738                        NumberFormatter::with()
1739                            .unit(MeasureUnit::forIdentifier("centimeter", status))
1740                            .usage("road")
1741                            .roundingMode(UNUM_ROUND_CEILING),
1742                        Locale("en-US"), //
1743                        3048,            //
1744                        u"100 ft");
1745
1746     // Third: with "road" usage, then the usage unsetted by calling .usage("")
1747     assertFormatSingle(u"Rounding Mode propagates: rounding up",
1748                        u"measure-unit/length-centimeter rounding-mode-ceiling",
1749                        u"unit/centimeter rounding-mode-ceiling",
1750                        NumberFormatter::with()
1751                            .unit(MeasureUnit::forIdentifier("centimeter", status))
1752                            .usage("road")
1753                            .roundingMode(UNUM_ROUND_CEILING)
1754                            .usage(""),  // unset
1755                        Locale("en-US"), //
1756                        3048,            //
1757                        u"3,048 cm");
1758
1759     // TODO(icu-units#38): improve unit testing coverage. E.g. add vehicle-fuel
1760     // triggering inversion conversion code. Test with 0 too, to see
1761     // divide-by-zero behaviour.
1762 }
1763
1764 void NumberFormatterApiTest::unitUsageErrorCodes() {
1765     IcuTestErrorCode status(*this, "unitUsageErrorCodes()");
1766     UnlocalizedNumberFormatter unloc_formatter;
1767
1768     unloc_formatter = NumberFormatter::forSkeleton(u"unit/foobar", status);
1769     // This gives an error, because foobar is an invalid unit:
1770     status.expectErrorAndReset(U_NUMBER_SKELETON_SYNTAX_ERROR);
1771
1772     unloc_formatter = NumberFormatter::forSkeleton(u"usage/foobar", status);
1773     // This does not give an error, because usage is not looked up yet.
1774     status.errIfFailureAndReset("Expected behaviour: no immediate error for invalid usage");
1775     unloc_formatter.locale("en-GB").formatInt(1, status);
1776     // Lacking a unit results in a failure. The skeleton is "incomplete", but we
1777     // support adding the unit via the fluent API, so it is not an error until
1778     // we build the formatting pipeline itself.
1779     status.expectErrorAndReset(U_ILLEGAL_ARGUMENT_ERROR);
1780     // Adding the unit as part of the fluent chain leads to success.
1781     unloc_formatter.unit(MeasureUnit::getMeter()).locale("en-GB").formatInt(1, status);
1782     status.assertSuccess();
1783
1784     // Setting unit to the "base dimensionless unit" is like clearing unit.
1785     unloc_formatter = NumberFormatter::with().unit(MeasureUnit()).usage("default");
1786     // This does not give an error, because usage-vs-unit isn't resolved yet.
1787     status.errIfFailureAndReset("Expected behaviour: no immediate error for invalid unit");
1788     unloc_formatter.locale("en-GB").formatInt(1, status);
1789     status.expectErrorAndReset(U_ILLEGAL_ARGUMENT_ERROR);
1790 }
1791
1792 // Tests for the "skeletons" field in unitPreferenceData, as well as precision
1793 // and notation overrides.
1794 void NumberFormatterApiTest::unitUsageSkeletons() {
1795     IcuTestErrorCode status(*this, "unitUsageSkeletons()");
1796
1797     assertFormatSingle(
1798             u"Default >300m road preference skeletons round to 50m",
1799             u"usage/road measure-unit/length-meter",
1800             u"usage/road unit/meter",
1801             NumberFormatter::with().unit(METER).usage("road"),
1802             Locale("en-ZA"),
1803             321,
1804             u"300 m");
1805
1806     assertFormatSingle(
1807             u"Precision can be overridden: override takes precedence",
1808             u"usage/road measure-unit/length-meter @#",
1809             u"usage/road unit/meter @#",
1810             NumberFormatter::with()
1811                 .unit(METER)
1812                 .usage("road")
1813                 .precision(Precision::maxSignificantDigits(2)),
1814             Locale("en-ZA"),
1815             321,
1816             u"320 m");
1817
1818     assertFormatSingle(
1819             u"Compact notation with Usage: bizarre, but possible (short)",
1820             u"compact-short usage/road measure-unit/length-meter",
1821             u"compact-short usage/road unit/meter",
1822             NumberFormatter::with()
1823                .unit(METER)
1824                .usage("road")
1825                .notation(Notation::compactShort()),
1826             Locale("en-ZA"),
1827             987654321,
1828             u"988K km");
1829
1830     assertFormatSingle(
1831             u"Compact notation with Usage: bizarre, but possible (short, precision override)",
1832             u"compact-short usage/road measure-unit/length-meter @#",
1833             u"compact-short usage/road unit/meter @#",
1834             NumberFormatter::with()
1835                 .unit(METER)
1836                 .usage("road")
1837                 .notation(Notation::compactShort())
1838                 .precision(Precision::maxSignificantDigits(2)),
1839             Locale("en-ZA"),
1840             987654321,
1841             u"990K km");
1842
1843     assertFormatSingle(
1844             u"Compact notation with Usage: unusual but possible (long)",
1845             u"compact-long usage/road measure-unit/length-meter @#",
1846             u"compact-long usage/road unit/meter @#",
1847             NumberFormatter::with()
1848                 .unit(METER)
1849                 .usage("road")
1850                 .notation(Notation::compactLong())
1851                 .precision(Precision::maxSignificantDigits(2)),
1852             Locale("en-ZA"),
1853             987654321,
1854             u"990 thousand km");
1855
1856     assertFormatSingle(
1857             u"Compact notation with Usage: unusual but possible (long, precision override)",
1858             u"compact-long usage/road measure-unit/length-meter @#",
1859             u"compact-long usage/road unit/meter @#",
1860             NumberFormatter::with()
1861                 .unit(METER)
1862                 .usage("road")
1863                 .notation(Notation::compactLong())
1864                 .precision(Precision::maxSignificantDigits(2)),
1865             Locale("en-ZA"),
1866             987654321,
1867             u"990 thousand km");
1868
1869     assertFormatSingle(
1870             u"Scientific notation, not recommended, requires precision override for road",
1871             u"scientific usage/road measure-unit/length-meter",
1872             u"scientific usage/road unit/meter",
1873             NumberFormatter::with().unit(METER).usage("road").notation(Notation::scientific()),
1874             Locale("en-ZA"),
1875             321.45,
1876             // Rounding to the nearest "50" is not exponent-adjusted in scientific notation:
1877             u"0E2 m");
1878
1879     assertFormatSingle(
1880             u"Scientific notation with Usage: possible when using a reasonable Precision",
1881             u"scientific usage/road measure-unit/length-meter @###",
1882             u"scientific usage/road unit/meter @###",
1883             NumberFormatter::with()
1884                 .unit(METER)
1885                 .usage("road")
1886                 .notation(Notation::scientific())
1887                 .precision(Precision::maxSignificantDigits(4)),
1888             Locale("en-ZA"),
1889             321.45, // 0.45 rounds down, 0.55 rounds up.
1890             u"3,214E2 m");
1891
1892     assertFormatSingle(
1893             u"Scientific notation with Usage: possible when using a reasonable Precision",
1894             u"scientific usage/default measure-unit/length-astronomical-unit unit-width-full-name",
1895             u"scientific usage/default unit/astronomical-unit unit-width-full-name",
1896             NumberFormatter::with()
1897                 .unit(MeasureUnit::forIdentifier("astronomical-unit", status))
1898                 .usage("default")
1899                 .notation(Notation::scientific())
1900                 .unitWidth(UNumberUnitWidth::UNUM_UNIT_WIDTH_FULL_NAME),
1901             Locale("en-ZA"),
1902             1e20,
1903             u"1,5E28 kilometres");
1904
1905     status.assertSuccess();
1906 }
1907
1908 void NumberFormatterApiTest::unitCurrency() {
1909     assertFormatDescending(
1910             u"Currency",
1911             u"currency/GBP",
1912             u"currency/GBP",
1913             NumberFormatter::with().unit(GBP),
1914             Locale::getEnglish(),
1915             u"£87,650.00",
1916             u"£8,765.00",
1917             u"£876.50",
1918             u"£87.65",
1919             u"£8.76",
1920             u"£0.88",
1921             u"£0.09",
1922             u"£0.01",
1923             u"£0.00");
1924
1925     assertFormatDescending(
1926             u"Currency ISO",
1927             u"currency/GBP unit-width-iso-code",
1928             u"currency/GBP unit-width-iso-code",
1929             NumberFormatter::with().unit(GBP).unitWidth(UNumberUnitWidth::UNUM_UNIT_WIDTH_ISO_CODE),
1930             Locale::getEnglish(),
1931             u"GBP 87,650.00",
1932             u"GBP 8,765.00",
1933             u"GBP 876.50",
1934             u"GBP 87.65",
1935             u"GBP 8.76",
1936             u"GBP 0.88",
1937             u"GBP 0.09",
1938             u"GBP 0.01",
1939             u"GBP 0.00");
1940
1941     assertFormatDescending(
1942             u"Currency Long Name",
1943             u"currency/GBP unit-width-full-name",
1944             u"currency/GBP unit-width-full-name",
1945             NumberFormatter::with().unit(GBP).unitWidth(UNumberUnitWidth::UNUM_UNIT_WIDTH_FULL_NAME),
1946             Locale::getEnglish(),
1947             u"87,650.00 British pounds",
1948             u"8,765.00 British pounds",
1949             u"876.50 British pounds",
1950             u"87.65 British pounds",
1951             u"8.76 British pounds",
1952             u"0.88 British pounds",
1953             u"0.09 British pounds",
1954             u"0.01 British pounds",
1955             u"0.00 British pounds");
1956
1957     assertFormatDescending(
1958             u"Currency Hidden",
1959             u"currency/GBP unit-width-hidden",
1960             u"currency/GBP unit-width-hidden",
1961             NumberFormatter::with().unit(GBP).unitWidth(UNUM_UNIT_WIDTH_HIDDEN),
1962             Locale::getEnglish(),
1963             u"87,650.00",
1964             u"8,765.00",
1965             u"876.50",
1966             u"87.65",
1967             u"8.76",
1968             u"0.88",
1969             u"0.09",
1970             u"0.01",
1971             u"0.00");
1972
1973 //    TODO: Implement Measure in C++
1974 //    assertFormatSingleMeasure(
1975 //            u"Currency with CurrencyAmount Input",
1976 //            NumberFormatter::with(),
1977 //            Locale::getEnglish(),
1978 //            new CurrencyAmount(5.43, GBP),
1979 //            u"£5.43");
1980
1981 //    TODO: Enable this test when DecimalFormat wrapper is done.
1982 //    assertFormatSingle(
1983 //            u"Currency Long Name from Pattern Syntax", NumberFormatter.fromDecimalFormat(
1984 //                    PatternStringParser.parseToProperties("0 ¤¤¤"),
1985 //                    DecimalFormatSymbols.getInstance(Locale::getEnglish()),
1986 //                    null).unit(GBP), Locale::getEnglish(), 1234567.89, u"1234568 British pounds");
1987
1988     assertFormatSingle(
1989             u"Currency with Negative Sign",
1990             u"currency/GBP",
1991             u"currency/GBP",
1992             NumberFormatter::with().unit(GBP),
1993             Locale::getEnglish(),
1994             -9876543.21,
1995             u"-£9,876,543.21");
1996
1997     // The full currency symbol is not shown in NARROW format.
1998     // NOTE: This example is in the documentation.
1999     assertFormatSingle(
2000             u"Currency Difference between Narrow and Short (Narrow Version)",
2001             u"currency/USD unit-width-narrow",
2002             u"currency/USD unit-width-narrow",
2003             NumberFormatter::with().unit(USD).unitWidth(UNUM_UNIT_WIDTH_NARROW),
2004             Locale("en-CA"),
2005             5.43,
2006             u"$5.43");
2007
2008     assertFormatSingle(
2009             u"Currency Difference between Narrow and Short (Short Version)",
2010             u"currency/USD unit-width-short",
2011             u"currency/USD unit-width-short",
2012             NumberFormatter::with().unit(USD).unitWidth(UNUM_UNIT_WIDTH_SHORT),
2013             Locale("en-CA"),
2014             5.43,
2015             u"US$5.43");
2016
2017     assertFormatSingle(
2018             u"Currency Difference between Formal and Short (Formal Version)",
2019             u"currency/TWD unit-width-formal",
2020             u"currency/TWD unit-width-formal",
2021             NumberFormatter::with().unit(TWD).unitWidth(UNUM_UNIT_WIDTH_FORMAL),
2022             Locale("zh-TW"),
2023             5.43,
2024             u"NT$5.43");
2025
2026     assertFormatSingle(
2027             u"Currency Difference between Formal and Short (Short Version)",
2028             u"currency/TWD unit-width-short",
2029             u"currency/TWD unit-width-short",
2030             NumberFormatter::with().unit(TWD).unitWidth(UNUM_UNIT_WIDTH_SHORT),
2031             Locale("zh-TW"),
2032             5.43,
2033             u"$5.43");
2034
2035     assertFormatSingle(
2036             u"Currency Difference between Variant and Short (Formal Version)",
2037             u"currency/TRY unit-width-variant",
2038             u"currency/TRY unit-width-variant",
2039             NumberFormatter::with().unit(TRY).unitWidth(UNUM_UNIT_WIDTH_VARIANT),
2040             Locale("tr-TR"),
2041             5.43,
2042             u"TL\u00A05,43");
2043
2044     assertFormatSingle(
2045             u"Currency Difference between Variant and Short (Short Version)",
2046             u"currency/TRY unit-width-short",
2047             u"currency/TRY unit-width-short",
2048             NumberFormatter::with().unit(TRY).unitWidth(UNUM_UNIT_WIDTH_SHORT),
2049             Locale("tr-TR"),
2050             5.43,
2051             u"₺5,43");
2052
2053     assertFormatSingle(
2054             u"Currency-dependent format (Control)",
2055             u"currency/USD unit-width-short",
2056             u"currency/USD unit-width-short",
2057             NumberFormatter::with().unit(USD).unitWidth(UNUM_UNIT_WIDTH_SHORT),
2058             Locale("ca"),
2059             444444.55,
2060             u"444.444,55 USD");
2061
2062     assertFormatSingle(
2063             u"Currency-dependent format (Test)",
2064             u"currency/ESP unit-width-short",
2065             u"currency/ESP unit-width-short",
2066             NumberFormatter::with().unit(ESP).unitWidth(UNUM_UNIT_WIDTH_SHORT),
2067             Locale("ca"),
2068             444444.55,
2069             u"₧ 444.445");
2070
2071     assertFormatSingle(
2072             u"Currency-dependent symbols (Control)",
2073             u"currency/USD unit-width-short",
2074             u"currency/USD unit-width-short",
2075             NumberFormatter::with().unit(USD).unitWidth(UNUM_UNIT_WIDTH_SHORT),
2076             Locale("pt-PT"),
2077             444444.55,
2078             u"444 444,55 US$");
2079
2080     // NOTE: This is a bit of a hack on CLDR's part. They set the currency symbol to U+200B (zero-
2081     // width space), and they set the decimal separator to the $ symbol.
2082     assertFormatSingle(
2083             u"Currency-dependent symbols (Test Short)",
2084             u"currency/PTE unit-width-short",
2085             u"currency/PTE unit-width-short",
2086             NumberFormatter::with().unit(PTE).unitWidth(UNUM_UNIT_WIDTH_SHORT),
2087             Locale("pt-PT"),
2088             444444.55,
2089             u"444,444$55 \u200B");
2090
2091     assertFormatSingle(
2092             u"Currency-dependent symbols (Test Narrow)",
2093             u"currency/PTE unit-width-narrow",
2094             u"currency/PTE unit-width-narrow",
2095             NumberFormatter::with().unit(PTE).unitWidth(UNUM_UNIT_WIDTH_NARROW),
2096             Locale("pt-PT"),
2097             444444.55,
2098             u"444,444$55 \u200B");
2099
2100     assertFormatSingle(
2101             u"Currency-dependent symbols (Test ISO Code)",
2102             u"currency/PTE unit-width-iso-code",
2103             u"currency/PTE unit-width-iso-code",
2104             NumberFormatter::with().unit(PTE).unitWidth(UNUM_UNIT_WIDTH_ISO_CODE),
2105             Locale("pt-PT"),
2106             444444.55,
2107             u"444,444$55 PTE");
2108
2109     assertFormatSingle(
2110             u"Plural form depending on visible digits (ICU-20499)",
2111             u"currency/RON unit-width-full-name",
2112             u"currency/RON unit-width-full-name",
2113             NumberFormatter::with().unit(RON).unitWidth(UNUM_UNIT_WIDTH_FULL_NAME),
2114             Locale("ro-RO"),
2115             24,
2116             u"24,00 lei românești");
2117
2118     assertFormatSingle(
2119             u"Currency spacing in suffix (ICU-20954)",
2120             u"currency/CNY",
2121             u"currency/CNY",
2122             NumberFormatter::with().unit(CNY),
2123             Locale("lu"),
2124             123.12,
2125             u"123,12 CN¥");
2126 }
2127
2128 void NumberFormatterApiTest::runUnitInflectionsTestCases(UnlocalizedNumberFormatter unf,
2129                                                          UnicodeString skeleton,
2130                                                          const UnitInflectionTestCase *cases,
2131                                                          int32_t numCases,
2132                                                          IcuTestErrorCode &status) {
2133     for (int32_t i = 0; i < numCases; i++) {
2134         UnitInflectionTestCase t = cases[i];
2135         status.assertSuccess();
2136         MeasureUnit mu = MeasureUnit::forIdentifier(t.unitIdentifier, status);
2137         if (status.errIfFailureAndReset("MeasureUnit::forIdentifier(\"%s\", ...) failed",
2138                                         t.unitIdentifier)) {
2139             continue;
2140         };
2141         UnicodeString skelString = UnicodeString("unit/") + t.unitIdentifier + u" " + skeleton;
2142         const UChar *skel;
2143         if (t.unitDisplayCase == nullptr || t.unitDisplayCase[0] == 0) {
2144             unf = unf.unit(mu).unitDisplayCase("");
2145             skel = skelString.getTerminatedBuffer();
2146         } else {
2147             unf = unf.unit(mu).unitDisplayCase(t.unitDisplayCase);
2148             // No skeleton support for unitDisplayCase yet.
2149             skel = nullptr;
2150         }
2151         assertFormatSingle((UnicodeString("Unit: \"") + t.unitIdentifier + ("\", \"") + skeleton +
2152                             u"\", locale=\"" + t.locale + u"\", case=\"" +
2153                             (t.unitDisplayCase ? t.unitDisplayCase : "") + u"\", value=" + t.value)
2154                                .getTerminatedBuffer(),
2155                            skel, skel, unf, Locale(t.locale), t.value, t.expected);
2156         status.assertSuccess();
2157     }
2158 }
2159
2160 void NumberFormatterApiTest::unitInflections() {
2161     IcuTestErrorCode status(*this, "unitInflections");
2162
2163     UnlocalizedNumberFormatter unf;
2164     const UChar *skeleton;
2165     {
2166         // Simple inflected form test - test case based on the example in CLDR's
2167         // grammaticalFeatures.xml
2168         unf = NumberFormatter::with().unitWidth(UNUM_UNIT_WIDTH_FULL_NAME);
2169         skeleton = u"unit-width-full-name";
2170         const UnitInflectionTestCase percentCases[] = {
2171             {"percent", "ru", nullptr, 10, u"10 процентов"},    // many
2172             {"percent", "ru", "genitive", 10, u"10 процентов"}, // many
2173             {"percent", "ru", nullptr, 33, u"33 процента"},     // few
2174             {"percent", "ru", "genitive", 33, u"33 процентов"}, // few
2175             {"percent", "ru", nullptr, 1, u"1 процент"},        // one
2176             {"percent", "ru", "genitive", 1, u"1 процента"},    // one
2177         };
2178         runUnitInflectionsTestCases(unf, skeleton, percentCases, UPRV_LENGTHOF(percentCases), status);
2179     }
2180     {
2181         // General testing of inflection rules
2182         unf = NumberFormatter::with().unitWidth(UNUM_UNIT_WIDTH_FULL_NAME);
2183         skeleton = u"unit-width-full-name";
2184         const UnitInflectionTestCase testCases[] = {
2185             // Check up on the basic values that the compound patterns below are
2186             // derived from:
2187             {"meter", "de", nullptr, 1, u"1 Meter"},
2188             {"meter", "de", "genitive", 1, u"1 Meters"},
2189             {"meter", "de", nullptr, 2, u"2 Meter"},
2190             {"meter", "de", "dative", 2, u"2 Metern"},
2191             {"mile", "de", nullptr, 1, u"1 Meile"},
2192             {"mile", "de", nullptr, 2, u"2 Meilen"},
2193             {"day", "de", nullptr, 1, u"1 Tag"},
2194             {"day", "de", "genitive", 1, u"1 Tages"},
2195             {"day", "de", nullptr, 2, u"2 Tage"},
2196             {"day", "de", "dative", 2, u"2 Tagen"},
2197             {"decade", "de", nullptr, 1, u"1\u00A0Jahrzehnt"},
2198             {"decade", "de", nullptr, 2, u"2\u00A0Jahrzehnte"},
2199
2200             // Testing de "per" rules:
2201             //   <deriveComponent feature="case" structure="per" value0="compound" value1="accusative"/>
2202             //   <deriveComponent feature="plural" structure="per" value0="compound" value1="one"/>
2203             // per-patterns use accusative, but since the accusative form
2204             // matches the nominative form, we're not effectively testing value1
2205             // in the "case & per" rule above.
2206
2207             // We have a perUnitPattern for "day" in de, so "per" rules are not
2208             // applied for these:
2209             {"meter-per-day", "de", nullptr, 1, u"1 Meter pro Tag"},
2210             {"meter-per-day", "de", "genitive", 1, u"1 Meters pro Tag"},
2211             {"meter-per-day", "de", nullptr, 2, u"2 Meter pro Tag"},
2212             {"meter-per-day", "de", "dative", 2, u"2 Metern pro Tag"},
2213
2214             // testing code path that falls back to "root" grammaticalFeatures
2215             // but does not inflect:
2216             {"meter-per-day", "af", nullptr, 1, u"1 meter per dag"},
2217             {"meter-per-day", "af", "dative", 1, u"1 meter per dag"},
2218
2219             // Decade does not have a perUnitPattern at this time (CLDR 39 / ICU
2220             // 69), so we can use it to test for selection of correct plural form.
2221             // - Note: fragile test cases, these cases will break when
2222             //   whitespace is more consistently applied.
2223             {"parsec-per-decade", "de", nullptr, 1, u"1\u00A0Parsec pro Jahrzehnt"},
2224             {"parsec-per-decade", "de", "genitive", 1, u"1 Parsec pro Jahrzehnt"},
2225             {"parsec-per-decade", "de", nullptr, 2, u"2\u00A0Parsec pro Jahrzehnt"},
2226             {"parsec-per-decade", "de", "dative", 2, u"2 Parsec pro Jahrzehnt"},
2227
2228             // Testing de "times", "power" and "prefix" rules:
2229             //
2230             //   <deriveComponent feature="plural" structure="times" value0="one"  value1="compound"/>
2231             //   <deriveComponent feature="case" structure="times" value0="nominative"  value1="compound"/>
2232             //
2233             //   <deriveComponent feature="plural" structure="prefix" value0="one"  value1="compound"/>
2234             //   <deriveComponent feature="case" structure="prefix" value0="nominative"  value1="compound"/>
2235             //
2236             // Prefixes in German don't change with plural or case, so these
2237             // tests can't test value0 of the following two rules:
2238             //   <deriveComponent feature="plural" structure="power" value0="one"  value1="compound"/>
2239             //   <deriveComponent feature="case" structure="power" value0="nominative"  value1="compound"/>
2240             {"square-decimeter-dekameter", "de", nullptr, 1, u"1 Quadratdezimeter⋅Dekameter"},
2241             {"square-decimeter-dekameter", "de", "genitive", 1, u"1 Quadratdezimeter⋅Dekameters"},
2242             {"square-decimeter-dekameter", "de", nullptr, 2, u"2 Quadratdezimeter⋅Dekameter"},
2243             {"square-decimeter-dekameter", "de", "dative", 2, u"2 Quadratdezimeter⋅Dekametern"},
2244             // Feminine "Meile" better demonstrates singular-vs-plural form:
2245             {"cubic-mile-dekamile", "de", nullptr, 1, u"1 Kubikmeile⋅Dekameile"},
2246             {"cubic-mile-dekamile", "de", nullptr, 2, u"2 Kubikmeile⋅Dekameilen"},
2247
2248             // French handles plural "times" and "power" structures differently:
2249             // plural form impacts all "numerator" units (denominator remains
2250             // singular like German), and "pow2" prefixes have different forms
2251             //   <deriveComponent feature="plural" structure="times" value0="compound"  value1="compound"/>
2252             //   <deriveComponent feature="plural" structure="power" value0="compound"  value1="compound"/>
2253             {"square-decimeter-square-second", "fr", nullptr, 1, u"1\u00A0décimètre carré-seconde carrée"},
2254             {"square-decimeter-square-second", "fr", nullptr, 2, u"2\u00A0décimètres carrés-secondes carrées"},
2255         };
2256         runUnitInflectionsTestCases(unf, skeleton, testCases, UPRV_LENGTHOF(testCases), status);
2257     }
2258     {
2259         // Testing inflection of mixed units:
2260         unf = NumberFormatter::with().unitWidth(UNUM_UNIT_WIDTH_FULL_NAME);
2261         skeleton = u"unit-width-full-name";
2262         const UnitInflectionTestCase testCases[] = {
2263             {"meter", "de", nullptr, 1, u"1 Meter"},
2264             {"meter", "de", "genitive", 1, u"1 Meters"},
2265             {"meter", "de", "dative", 2, u"2 Metern"},
2266             {"centimeter", "de", nullptr, 1, u"1 Zentimeter"},
2267             {"centimeter", "de", "genitive", 1, u"1 Zentimeters"},
2268             {"centimeter", "de", "dative", 10, u"10 Zentimetern"},
2269             // TODO(CLDR-14502): check that these inflections are correct, and
2270             // whether CLDR needs any rules for them (presumably CLDR spec
2271             // should mention it, if it's a consistent rule):
2272             {"meter-and-centimeter", "de", nullptr, 1.01, u"1 Meter, 1 Zentimeter"},
2273             {"meter-and-centimeter", "de", "genitive", 1.01, u"1 Meters, 1 Zentimeters"},
2274             {"meter-and-centimeter", "de", "genitive", 1.1, u"1 Meters, 10 Zentimeter"},
2275             {"meter-and-centimeter", "de", "dative", 1.1, u"1 Meter, 10 Zentimetern"},
2276             {"meter-and-centimeter", "de", "dative", 2.1, u"2 Metern, 10 Zentimetern"},
2277         };
2278         runUnitInflectionsTestCases(unf, skeleton, testCases, UPRV_LENGTHOF(testCases),
2279                                     status);
2280     }
2281     // TODO: add a usage case that selects between preferences with different
2282     // genders (e.g. year, month, day, hour).
2283     // TODO: look at "↑↑↑" cases: check that inheritance is done right.
2284 }
2285
2286 void NumberFormatterApiTest::unitGender() {
2287     IcuTestErrorCode status(*this, "unitGender");
2288
2289     const struct TestCase {
2290         const char *locale;
2291         const char *unitIdentifier;
2292         const char *expectedGender;
2293     } cases[] = {
2294         {"de", "meter", "masculine"},
2295         {"de", "second", "feminine"},
2296         {"de", "minute", "feminine"},
2297         {"de", "hour", "feminine"},
2298         {"de", "day", "masculine"},
2299         {"de", "year", "neuter"},
2300         {"fr", "meter", "masculine"},
2301         {"fr", "second", "feminine"},
2302         {"fr", "minute", "feminine"},
2303         {"fr", "hour", "feminine"},
2304         {"fr", "day", "masculine"},
2305         // grammaticalFeatures deriveCompound "per" rule takes the gender of the
2306         // numerator unit:
2307         {"de", "meter-per-hour", "masculine"},
2308         {"fr", "meter-per-hour", "masculine"},
2309         {"af", "meter-per-hour", ""}, // ungendered language
2310         // French "times" takes gender from first value, German takes the
2311         // second. Prefix and power does not have impact on gender for these
2312         // languages:
2313         {"de", "square-decimeter-square-second", "feminine"},
2314         {"fr", "square-decimeter-square-second", "masculine"},
2315         // TODO(ICU-21494): determine whether list genders behave as follows,
2316         // and implement proper getListGender support (covering more than just
2317         // two genders):
2318         // // gender rule for lists of people: de "neutral", fr "maleTaints"
2319         // {"de", "day-and-hour-and-minute", "neuter"},
2320         // {"de", "hour-and-minute", "feminine"},
2321         // {"fr", "day-and-hour-and-minute", "masculine"},
2322         // {"fr", "hour-and-minute", "feminine"},
2323     };
2324     LocalizedNumberFormatter formatter;
2325     FormattedNumber fn;
2326     for (const TestCase &t : cases) {
2327         formatter = NumberFormatter::with()
2328                         .unit(MeasureUnit::forIdentifier(t.unitIdentifier, status))
2329                         .locale(Locale(t.locale));
2330         fn = formatter.formatDouble(1.1, status);
2331         assertEquals(UnicodeString("Testing gender with default width, unit: ") + t.unitIdentifier +
2332                          ", locale: " + t.locale,
2333                      t.expectedGender, fn.getGender(status));
2334         status.assertSuccess();
2335
2336         formatter = NumberFormatter::with()
2337                         .unit(MeasureUnit::forIdentifier(t.unitIdentifier, status))
2338                         .unitWidth(UNUM_UNIT_WIDTH_FULL_NAME)
2339                         .locale(Locale(t.locale));
2340         fn = formatter.formatDouble(1.1, status);
2341         assertEquals(UnicodeString("Testing gender with UNUM_UNIT_WIDTH_FULL_NAME, unit: ") +
2342                          t.unitIdentifier + ", locale: " + t.locale,
2343                      t.expectedGender, fn.getGender(status));
2344         status.assertSuccess();
2345     }
2346
2347     // Make sure getGender does not return garbage for genderless languages
2348     formatter = NumberFormatter::with().locale(Locale::getEnglish());
2349     fn = formatter.formatDouble(1.1, status);
2350     status.assertSuccess();
2351     assertEquals("getGender for a genderless language", "", fn.getGender(status));
2352 }
2353
2354 void NumberFormatterApiTest::unitPercent() {
2355     assertFormatDescending(
2356             u"Percent",
2357             u"percent",
2358             u"%",
2359             NumberFormatter::with().unit(NoUnit::percent()),
2360             Locale::getEnglish(),
2361             u"87,650%",
2362             u"8,765%",
2363             u"876.5%",
2364             u"87.65%",
2365             u"8.765%",
2366             u"0.8765%",
2367             u"0.08765%",
2368             u"0.008765%",
2369             u"0%");
2370
2371     assertFormatDescending(
2372             u"Permille",
2373             u"permille",
2374             u"permille",
2375             NumberFormatter::with().unit(NoUnit::permille()),
2376             Locale::getEnglish(),
2377             u"87,650‰",
2378             u"8,765‰",
2379             u"876.5‰",
2380             u"87.65‰",
2381             u"8.765‰",
2382             u"0.8765‰",
2383             u"0.08765‰",
2384             u"0.008765‰",
2385             u"0‰");
2386
2387     assertFormatSingle(
2388             u"NoUnit Base",
2389             u"base-unit",
2390             u"",
2391             NumberFormatter::with().unit(NoUnit::base()),
2392             Locale::getEnglish(),
2393             51423,
2394             u"51,423");
2395
2396     assertFormatSingle(
2397             u"Percent with Negative Sign",
2398             u"percent",
2399             u"%",
2400             NumberFormatter::with().unit(NoUnit::percent()),
2401             Locale::getEnglish(),
2402             -98.7654321,
2403             u"-98.765432%");
2404
2405     // ICU-20923
2406     assertFormatDescendingBig(
2407             u"Compact Percent",
2408             u"compact-short percent",
2409             u"K %",
2410             NumberFormatter::with()
2411                     .notation(Notation::compactShort())
2412                     .unit(NoUnit::percent()),
2413             Locale::getEnglish(),
2414             u"88M%",
2415             u"8.8M%",
2416             u"876K%",
2417             u"88K%",
2418             u"8.8K%",
2419             u"876%",
2420             u"88%",
2421             u"8.8%",
2422             u"0%");
2423
2424     // ICU-20923
2425     assertFormatDescendingBig(
2426             u"Compact Percent with Scale",
2427             u"compact-short percent scale/100",
2428             u"K %x100",
2429             NumberFormatter::with()
2430                     .notation(Notation::compactShort())
2431                     .unit(NoUnit::percent())
2432                     .scale(Scale::powerOfTen(2)),
2433             Locale::getEnglish(),
2434             u"8.8B%",
2435             u"876M%",
2436             u"88M%",
2437             u"8.8M%",
2438             u"876K%",
2439             u"88K%",
2440             u"8.8K%",
2441             u"876%",
2442             u"0%");
2443
2444     // ICU-20923
2445     assertFormatDescendingBig(
2446             u"Compact Percent Long Name",
2447             u"compact-short percent unit-width-full-name",
2448             u"K % unit-width-full-name",
2449             NumberFormatter::with()
2450                     .notation(Notation::compactShort())
2451                     .unit(NoUnit::percent())
2452                     .unitWidth(UNUM_UNIT_WIDTH_FULL_NAME),
2453             Locale::getEnglish(),
2454             u"88M percent",
2455             u"8.8M percent",
2456             u"876K percent",
2457             u"88K percent",
2458             u"8.8K percent",
2459             u"876 percent",
2460             u"88 percent",
2461             u"8.8 percent",
2462             u"0 percent");
2463
2464     assertFormatSingle(
2465             u"Per Percent",
2466             u"measure-unit/length-meter per-measure-unit/concentr-percent unit-width-full-name",
2467             u"measure-unit/length-meter per-measure-unit/concentr-percent unit-width-full-name",
2468             NumberFormatter::with()
2469                     .unit(MeasureUnit::getMeter())
2470                     .perUnit(MeasureUnit::getPercent())
2471                     .unitWidth(UNUM_UNIT_WIDTH_FULL_NAME),
2472             Locale::getEnglish(),
2473             50,
2474             u"50 meters per percent");
2475 }
2476
2477 void NumberFormatterApiTest::percentParity() {
2478     IcuTestErrorCode status(*this, "percentParity");
2479     UnlocalizedNumberFormatter uNoUnitPercent = NumberFormatter::with().unit(NoUnit::percent());
2480     UnlocalizedNumberFormatter uNoUnitPermille = NumberFormatter::with().unit(NoUnit::permille());
2481     UnlocalizedNumberFormatter uMeasurePercent = NumberFormatter::with().unit(MeasureUnit::getPercent());
2482     UnlocalizedNumberFormatter uMeasurePermille = NumberFormatter::with().unit(MeasureUnit::getPermille());
2483
2484     int32_t localeCount;
2485     auto locales = Locale::getAvailableLocales(localeCount);
2486     for (int32_t i=0; i<localeCount; i++) {
2487         auto& locale = locales[i];
2488         UnicodeString sNoUnitPercent = uNoUnitPercent.locale(locale)
2489             .formatDouble(50, status).toString(status);
2490         UnicodeString sNoUnitPermille = uNoUnitPermille.locale(locale)
2491             .formatDouble(50, status).toString(status);
2492         UnicodeString sMeasurePercent = uMeasurePercent.locale(locale)
2493             .formatDouble(50, status).toString(status);
2494         UnicodeString sMeasurePermille = uMeasurePermille.locale(locale)
2495             .formatDouble(50, status).toString(status);
2496
2497         assertEquals(u"Percent, locale " + UnicodeString(locale.getName()),
2498             sNoUnitPercent, sMeasurePercent);
2499         assertEquals(u"Permille, locale " + UnicodeString(locale.getName()),
2500             sNoUnitPermille, sMeasurePermille);
2501     }
2502 }
2503
2504 void NumberFormatterApiTest::roundingFraction() {
2505     assertFormatDescending(
2506             u"Integer",
2507             u"precision-integer",
2508             u".",
2509             NumberFormatter::with().precision(Precision::integer()),
2510             Locale::getEnglish(),
2511             u"87,650",
2512             u"8,765",
2513             u"876",
2514             u"88",
2515             u"9",
2516             u"1",
2517             u"0",
2518             u"0",
2519             u"0");
2520
2521     assertFormatDescending(
2522             u"Fixed Fraction",
2523             u".000",
2524             u".000",
2525             NumberFormatter::with().precision(Precision::fixedFraction(3)),
2526             Locale::getEnglish(),
2527             u"87,650.000",
2528             u"8,765.000",
2529             u"876.500",
2530             u"87.650",
2531             u"8.765",
2532             u"0.876",
2533             u"0.088",
2534             u"0.009",
2535             u"0.000");
2536
2537     assertFormatDescending(
2538             u"Min Fraction",
2539             u".0*",
2540             u".0+",
2541             NumberFormatter::with().precision(Precision::minFraction(1)),
2542             Locale::getEnglish(),
2543             u"87,650.0",
2544             u"8,765.0",
2545             u"876.5",
2546             u"87.65",
2547             u"8.765",
2548             u"0.8765",
2549             u"0.08765",
2550             u"0.008765",
2551             u"0.0");
2552
2553     assertFormatDescending(
2554             u"Max Fraction",
2555             u".#",
2556             u".#",
2557             NumberFormatter::with().precision(Precision::maxFraction(1)),
2558             Locale::getEnglish(),
2559             u"87,650",
2560             u"8,765",
2561             u"876.5",
2562             u"87.6",
2563             u"8.8",
2564             u"0.9",
2565             u"0.1",
2566             u"0",
2567             u"0");
2568
2569     assertFormatDescending(
2570             u"Min/Max Fraction",
2571             u".0##",
2572             u".0##",
2573             NumberFormatter::with().precision(Precision::minMaxFraction(1, 3)),
2574             Locale::getEnglish(),
2575             u"87,650.0",
2576             u"8,765.0",
2577             u"876.5",
2578             u"87.65",
2579             u"8.765",
2580             u"0.876",
2581             u"0.088",
2582             u"0.009",
2583             u"0.0");
2584
2585     assertFormatSingle(
2586             u"Hide If Whole A",
2587             u".00/w",
2588             u".00/w",
2589             NumberFormatter::with().precision(Precision::fixedFraction(2)
2590                 .trailingZeroDisplay(UNUM_TRAILING_ZERO_HIDE_IF_WHOLE)),
2591             Locale::getEnglish(),
2592             1.2,
2593             "1.20");
2594
2595     assertFormatSingle(
2596             u"Hide If Whole B",
2597             u".00/w",
2598             u".00/w",
2599             NumberFormatter::with().precision(Precision::fixedFraction(2)
2600                 .trailingZeroDisplay(UNUM_TRAILING_ZERO_HIDE_IF_WHOLE)),
2601             Locale::getEnglish(),
2602             1,
2603             "1");
2604 }
2605
2606 void NumberFormatterApiTest::roundingFigures() {
2607     assertFormatSingle(
2608             u"Fixed Significant",
2609             u"@@@",
2610             u"@@@",
2611             NumberFormatter::with().precision(Precision::fixedSignificantDigits(3)),
2612             Locale::getEnglish(),
2613             -98,
2614             u"-98.0");
2615
2616     assertFormatSingle(
2617             u"Fixed Significant Rounding",
2618             u"@@@",
2619             u"@@@",
2620             NumberFormatter::with().precision(Precision::fixedSignificantDigits(3)),
2621             Locale::getEnglish(),
2622             -98.7654321,
2623             u"-98.8");
2624
2625     assertFormatSingle(
2626             u"Fixed Significant Zero",
2627             u"@@@",
2628             u"@@@",
2629             NumberFormatter::with().precision(Precision::fixedSignificantDigits(3)),
2630             Locale::getEnglish(),
2631             0,
2632             u"0.00");
2633
2634     assertFormatSingle(
2635             u"Min Significant",
2636             u"@@*",
2637             u"@@+",
2638             NumberFormatter::with().precision(Precision::minSignificantDigits(2)),
2639             Locale::getEnglish(),
2640             -9,
2641             u"-9.0");
2642
2643     assertFormatSingle(
2644             u"Max Significant",
2645             u"@###",
2646             u"@###",
2647             NumberFormatter::with().precision(Precision::maxSignificantDigits(4)),
2648             Locale::getEnglish(),
2649             98.7654321,
2650             u"98.77");
2651
2652     assertFormatSingle(
2653             u"Min/Max Significant",
2654             u"@@@#",
2655             u"@@@#",
2656             NumberFormatter::with().precision(Precision::minMaxSignificantDigits(3, 4)),
2657             Locale::getEnglish(),
2658             9.99999,
2659             u"10.0");
2660
2661     assertFormatSingle(
2662             u"Fixed Significant on zero with lots of integer width",
2663             u"@ integer-width/+000",
2664             u"@ 000",
2665             NumberFormatter::with().precision(Precision::fixedSignificantDigits(1))
2666                     .integerWidth(IntegerWidth::zeroFillTo(3)),
2667             Locale::getEnglish(),
2668             0,
2669             "000");
2670
2671     assertFormatSingle(
2672             u"Fixed Significant on zero with zero integer width",
2673             u"@ integer-width/*",
2674             u"@ integer-width/+",
2675             NumberFormatter::with().precision(Precision::fixedSignificantDigits(1))
2676                     .integerWidth(IntegerWidth::zeroFillTo(0)),
2677             Locale::getEnglish(),
2678             0,
2679             "0");
2680 }
2681
2682 void NumberFormatterApiTest::roundingFractionFigures() {
2683     assertFormatDescending(
2684             u"Basic Significant", // for comparison
2685             u"@#",
2686             u"@#",
2687             NumberFormatter::with().precision(Precision::maxSignificantDigits(2)),
2688             Locale::getEnglish(),
2689             u"88,000",
2690             u"8,800",
2691             u"880",
2692             u"88",
2693             u"8.8",
2694             u"0.88",
2695             u"0.088",
2696             u"0.0088",
2697             u"0");
2698
2699     assertFormatDescending(
2700             u"FracSig minMaxFrac minSig",
2701             u".0#/@@@*",
2702             u".0#/@@@+",
2703             NumberFormatter::with().precision(Precision::minMaxFraction(1, 2).withMinDigits(3)),
2704             Locale::getEnglish(),
2705             u"87,650.0",
2706             u"8,765.0",
2707             u"876.5",
2708             u"87.65",
2709             u"8.76",
2710             u"0.876", // minSig beats maxFrac
2711             u"0.0876", // minSig beats maxFrac
2712             u"0.00876", // minSig beats maxFrac
2713             u"0.0");
2714
2715     assertFormatDescending(
2716             u"FracSig minMaxFrac maxSig A",
2717             u".0##/@#",
2718             u".0##/@#",
2719             NumberFormatter::with().precision(Precision::minMaxFraction(1, 3).withMaxDigits(2)),
2720             Locale::getEnglish(),
2721             u"88,000.0", // maxSig beats maxFrac
2722             u"8,800.0", // maxSig beats maxFrac
2723             u"880.0", // maxSig beats maxFrac
2724             u"88.0", // maxSig beats maxFrac
2725             u"8.8", // maxSig beats maxFrac
2726             u"0.88", // maxSig beats maxFrac
2727             u"0.088",
2728             u"0.009",
2729             u"0.0");
2730
2731     assertFormatDescending(
2732             u"FracSig minMaxFrac maxSig B",
2733             u".00/@#",
2734             u".00/@#",
2735             NumberFormatter::with().precision(Precision::fixedFraction(2).withMaxDigits(2)),
2736             Locale::getEnglish(),
2737             u"88,000.00", // maxSig beats maxFrac
2738             u"8,800.00", // maxSig beats maxFrac
2739             u"880.00", // maxSig beats maxFrac
2740             u"88.00", // maxSig beats maxFrac
2741             u"8.80", // maxSig beats maxFrac
2742             u"0.88",
2743             u"0.09",
2744             u"0.01",
2745             u"0.00");
2746
2747     assertFormatSingle(
2748             u"FracSig with trailing zeros A",
2749             u".00/@@@*",
2750             u".00/@@@+",
2751             NumberFormatter::with().precision(Precision::fixedFraction(2).withMinDigits(3)),
2752             Locale::getEnglish(),
2753             0.1,
2754             u"0.10");
2755
2756     assertFormatSingle(
2757             u"FracSig with trailing zeros B",
2758             u".00/@@@*",
2759             u".00/@@@+",
2760             NumberFormatter::with().precision(Precision::fixedFraction(2).withMinDigits(3)),
2761             Locale::getEnglish(),
2762             0.0999999,
2763             u"0.10");
2764
2765     assertFormatDescending(
2766             u"FracSig withSignificantDigits RELAXED",
2767             u"precision-integer/@#r",
2768             u"./@#r",
2769             NumberFormatter::with().precision(Precision::maxFraction(0)
2770                 .withSignificantDigits(1, 2, UNUM_ROUNDING_PRIORITY_RELAXED)),
2771             Locale::getEnglish(),
2772             u"87,650",
2773             u"8,765",
2774             u"876",
2775             u"88",
2776             u"8.8",
2777             u"0.88",
2778             u"0.088",
2779             u"0.0088",
2780             u"0");
2781
2782     assertFormatDescending(
2783             u"FracSig withSignificantDigits STRICT",
2784             u"precision-integer/@#s",
2785             u"./@#",
2786             NumberFormatter::with().precision(Precision::maxFraction(0)
2787                 .withSignificantDigits(1, 2, UNUM_ROUNDING_PRIORITY_STRICT)),
2788             Locale::getEnglish(),
2789             u"88,000",
2790             u"8,800",
2791             u"880",
2792             u"88",
2793             u"9",
2794             u"1",
2795             u"0",
2796             u"0",
2797             u"0");
2798
2799     assertFormatSingle(
2800             u"FracSig withSignificantDigits Trailing Zeros RELAXED",
2801             u".0/@@@r",
2802             u".0/@@@r",
2803             NumberFormatter::with().precision(Precision::fixedFraction(1)
2804                 .withSignificantDigits(3, 3, UNUM_ROUNDING_PRIORITY_RELAXED)),
2805             Locale::getEnglish(),
2806             1,
2807             u"1.00");
2808
2809     // Trailing zeros are always retained:
2810     assertFormatSingle(
2811             u"FracSig withSignificantDigits Trailing Zeros STRICT",
2812             u".0/@@@s",
2813             u".0/@@@s",
2814             NumberFormatter::with().precision(Precision::fixedFraction(1)
2815                 .withSignificantDigits(3, 3, UNUM_ROUNDING_PRIORITY_STRICT)),
2816             Locale::getEnglish(),
2817             1,
2818             u"1.00");
2819
2820     assertFormatSingle(
2821             u"FracSig withSignificantDigits at rounding boundary",
2822             u"precision-integer/@@@s",
2823             u"./@@@s",
2824             NumberFormatter::with().precision(Precision::fixedFraction(0)
2825                     .withSignificantDigits(3, 3, UNUM_ROUNDING_PRIORITY_STRICT)),
2826             Locale::getEnglish(),
2827             9.99,
2828             u"10.0");
2829
2830     assertFormatSingle(
2831             u"FracSig with Trailing Zero Display",
2832             u".00/@@@*/w",
2833             u".00/@@@+/w",
2834             NumberFormatter::with().precision(Precision::fixedFraction(2).withMinDigits(3)
2835                 .trailingZeroDisplay(UNUM_TRAILING_ZERO_HIDE_IF_WHOLE)),
2836             Locale::getEnglish(),
2837             1,
2838             u"1");
2839 }
2840
2841 void NumberFormatterApiTest::roundingOther() {
2842     assertFormatDescending(
2843             u"Rounding None",
2844             u"precision-unlimited",
2845             u".+",
2846             NumberFormatter::with().precision(Precision::unlimited()),
2847             Locale::getEnglish(),
2848             u"87,650",
2849             u"8,765",
2850             u"876.5",
2851             u"87.65",
2852             u"8.765",
2853             u"0.8765",
2854             u"0.08765",
2855             u"0.008765",
2856             u"0");
2857
2858     assertFormatDescending(
2859             u"Increment",
2860             u"precision-increment/0.5",
2861             u"precision-increment/0.5",
2862             NumberFormatter::with().precision(Precision::increment(0.5).withMinFraction(1)),
2863             Locale::getEnglish(),
2864             u"87,650.0",
2865             u"8,765.0",
2866             u"876.5",
2867             u"87.5",
2868             u"9.0",
2869             u"1.0",
2870             u"0.0",
2871             u"0.0",
2872             u"0.0");
2873
2874     assertFormatDescending(
2875             u"Increment with Min Fraction",
2876             u"precision-increment/0.50",
2877             u"precision-increment/0.50",
2878             NumberFormatter::with().precision(Precision::increment(0.5).withMinFraction(2)),
2879             Locale::getEnglish(),
2880             u"87,650.00",
2881             u"8,765.00",
2882             u"876.50",
2883             u"87.50",
2884             u"9.00",
2885             u"1.00",
2886             u"0.00",
2887             u"0.00",
2888             u"0.00");
2889
2890     assertFormatDescending(
2891             u"Strange Increment",
2892             u"precision-increment/3.140",
2893             u"precision-increment/3.140",
2894             NumberFormatter::with().precision(Precision::increment(3.14).withMinFraction(3)),
2895             Locale::getEnglish(),
2896             u"87,649.960",
2897             u"8,763.740",
2898             u"876.060",
2899             u"87.920",
2900             u"9.420",
2901             u"0.000",
2902             u"0.000",
2903             u"0.000",
2904             u"0.000");
2905
2906     assertFormatDescending(
2907             u"Increment Resolving to Power of 10",
2908             u"precision-increment/0.010",
2909             u"precision-increment/0.010",
2910             NumberFormatter::with().precision(Precision::increment(0.01).withMinFraction(3)),
2911             Locale::getEnglish(),
2912             u"87,650.000",
2913             u"8,765.000",
2914             u"876.500",
2915             u"87.650",
2916             u"8.760",
2917             u"0.880",
2918             u"0.090",
2919             u"0.010",
2920             u"0.000");
2921
2922     assertFormatDescending(
2923             u"Currency Standard",
2924             u"currency/CZK precision-currency-standard",
2925             u"currency/CZK precision-currency-standard",
2926             NumberFormatter::with().precision(Precision::currency(UCurrencyUsage::UCURR_USAGE_STANDARD))
2927                     .unit(CZK),
2928             Locale::getEnglish(),
2929             u"CZK 87,650.00",
2930             u"CZK 8,765.00",
2931             u"CZK 876.50",
2932             u"CZK 87.65",
2933             u"CZK 8.76",
2934             u"CZK 0.88",
2935             u"CZK 0.09",
2936             u"CZK 0.01",
2937             u"CZK 0.00");
2938
2939     assertFormatDescending(
2940             u"Currency Cash",
2941             u"currency/CZK precision-currency-cash",
2942             u"currency/CZK precision-currency-cash",
2943             NumberFormatter::with().precision(Precision::currency(UCurrencyUsage::UCURR_USAGE_CASH))
2944                     .unit(CZK),
2945             Locale::getEnglish(),
2946             u"CZK 87,650",
2947             u"CZK 8,765",
2948             u"CZK 876",
2949             u"CZK 88",
2950             u"CZK 9",
2951             u"CZK 1",
2952             u"CZK 0",
2953             u"CZK 0",
2954             u"CZK 0");
2955
2956     assertFormatDescending(
2957             u"Currency Standard with Trailing Zero Display",
2958             u"currency/CZK precision-currency-standard/w",
2959             u"currency/CZK precision-currency-standard/w",
2960             NumberFormatter::with().precision(
2961                         Precision::currency(UCurrencyUsage::UCURR_USAGE_STANDARD)
2962                         .trailingZeroDisplay(UNUM_TRAILING_ZERO_HIDE_IF_WHOLE))
2963                     .unit(CZK),
2964             Locale::getEnglish(),
2965             u"CZK 87,650",
2966             u"CZK 8,765",
2967             u"CZK 876.50",
2968             u"CZK 87.65",
2969             u"CZK 8.76",
2970             u"CZK 0.88",
2971             u"CZK 0.09",
2972             u"CZK 0.01",
2973             u"CZK 0");
2974
2975     assertFormatDescending(
2976             u"Currency Cash with Nickel Rounding",
2977             u"currency/CAD precision-currency-cash",
2978             u"currency/CAD precision-currency-cash",
2979             NumberFormatter::with().precision(Precision::currency(UCurrencyUsage::UCURR_USAGE_CASH))
2980                     .unit(CAD),
2981             Locale::getEnglish(),
2982             u"CA$87,650.00",
2983             u"CA$8,765.00",
2984             u"CA$876.50",
2985             u"CA$87.65",
2986             u"CA$8.75",
2987             u"CA$0.90",
2988             u"CA$0.10",
2989             u"CA$0.00",
2990             u"CA$0.00");
2991
2992     assertFormatDescending(
2993             u"Currency not in top-level fluent chain",
2994             u"precision-integer", // calling .withCurrency() applies currency rounding rules immediately
2995             u".",
2996             NumberFormatter::with().precision(
2997                     Precision::currency(UCurrencyUsage::UCURR_USAGE_CASH).withCurrency(CZK)),
2998             Locale::getEnglish(),
2999             u"87,650",
3000             u"8,765",
3001             u"876",
3002             u"88",
3003             u"9",
3004             u"1",
3005             u"0",
3006             u"0",
3007             u"0");
3008
3009     // NOTE: Other tests cover the behavior of the other rounding modes.
3010     assertFormatDescending(
3011             u"Rounding Mode CEILING",
3012             u"precision-integer rounding-mode-ceiling",
3013             u". rounding-mode-ceiling",
3014             NumberFormatter::with().precision(Precision::integer()).roundingMode(UNUM_ROUND_CEILING),
3015             Locale::getEnglish(),
3016             u"87,650",
3017             u"8,765",
3018             u"877",
3019             u"88",
3020             u"9",
3021             u"1",
3022             u"1",
3023             u"1",
3024             u"0");
3025
3026     assertFormatSingle(
3027             u"ICU-20974 Double.MIN_NORMAL",
3028             u"scientific",
3029             u"E0",
3030             NumberFormatter::with().notation(Notation::scientific()),
3031             Locale::getEnglish(),
3032             DBL_MIN,
3033             u"2.225074E-308");
3034
3035 #ifndef DBL_TRUE_MIN
3036 #define DBL_TRUE_MIN 4.9E-324
3037 #endif
3038
3039     // Note: this behavior is intentionally different from Java; see
3040     // https://github.com/google/double-conversion/issues/126
3041     assertFormatSingle(
3042             u"ICU-20974 Double.MIN_VALUE",
3043             u"scientific",
3044             u"E0",
3045             NumberFormatter::with().notation(Notation::scientific()),
3046             Locale::getEnglish(),
3047             DBL_TRUE_MIN,
3048             u"5E-324");
3049 }
3050
3051 void NumberFormatterApiTest::grouping() {
3052     assertFormatDescendingBig(
3053             u"Western Grouping",
3054             u"group-auto",
3055             u"",
3056             NumberFormatter::with().grouping(UNUM_GROUPING_AUTO),
3057             Locale::getEnglish(),
3058             u"87,650,000",
3059             u"8,765,000",
3060             u"876,500",
3061             u"87,650",
3062             u"8,765",
3063             u"876.5",
3064             u"87.65",
3065             u"8.765",
3066             u"0");
3067
3068     assertFormatDescendingBig(
3069             u"Indic Grouping",
3070             u"group-auto",
3071             u"",
3072             NumberFormatter::with().grouping(UNUM_GROUPING_AUTO),
3073             Locale("en-IN"),
3074             u"8,76,50,000",
3075             u"87,65,000",
3076             u"8,76,500",
3077             u"87,650",
3078             u"8,765",
3079             u"876.5",
3080             u"87.65",
3081             u"8.765",
3082             u"0");
3083
3084     assertFormatDescendingBig(
3085             u"Western Grouping, Min 2",
3086             u"group-min2",
3087             u",?",
3088             NumberFormatter::with().grouping(UNUM_GROUPING_MIN2),
3089             Locale::getEnglish(),
3090             u"87,650,000",
3091             u"8,765,000",
3092             u"876,500",
3093             u"87,650",
3094             u"8765",
3095             u"876.5",
3096             u"87.65",
3097             u"8.765",
3098             u"0");
3099
3100     assertFormatDescendingBig(
3101             u"Indic Grouping, Min 2",
3102             u"group-min2",
3103             u",?",
3104             NumberFormatter::with().grouping(UNUM_GROUPING_MIN2),
3105             Locale("en-IN"),
3106             u"8,76,50,000",
3107             u"87,65,000",
3108             u"8,76,500",
3109             u"87,650",
3110             u"8765",
3111             u"876.5",
3112             u"87.65",
3113             u"8.765",
3114             u"0");
3115
3116     assertFormatDescendingBig(
3117             u"No Grouping",
3118             u"group-off",
3119             u",_",
3120             NumberFormatter::with().grouping(UNUM_GROUPING_OFF),
3121             Locale("en-IN"),
3122             u"87650000",
3123             u"8765000",
3124             u"876500",
3125             u"87650",
3126             u"8765",
3127             u"876.5",
3128             u"87.65",
3129             u"8.765",
3130             u"0");
3131
3132     assertFormatDescendingBig(
3133             u"Indic locale with THOUSANDS grouping",
3134             u"group-thousands",
3135             u"group-thousands",
3136             NumberFormatter::with().grouping(UNUM_GROUPING_THOUSANDS),
3137             Locale("en-IN"),
3138             u"87,650,000",
3139             u"8,765,000",
3140             u"876,500",
3141             u"87,650",
3142             u"8,765",
3143             u"876.5",
3144             u"87.65",
3145             u"8.765",
3146             u"0");
3147
3148     // NOTE: Polish is interesting because it has minimumGroupingDigits=2 in locale data
3149     // (Most locales have either 1 or 2)
3150     // If this test breaks due to data changes, find another locale that has minimumGroupingDigits.
3151     assertFormatDescendingBig(
3152             u"Polish Grouping",
3153             u"group-auto",
3154             u"",
3155             NumberFormatter::with().grouping(UNUM_GROUPING_AUTO),
3156             Locale("pl"),
3157             u"87 650 000",
3158             u"8 765 000",
3159             u"876 500",
3160             u"87 650",
3161             u"8765",
3162             u"876,5",
3163             u"87,65",
3164             u"8,765",
3165             u"0");
3166
3167     assertFormatDescendingBig(
3168             u"Polish Grouping, Min 2",
3169             u"group-min2",
3170             u",?",
3171             NumberFormatter::with().grouping(UNUM_GROUPING_MIN2),
3172             Locale("pl"),
3173             u"87 650 000",
3174             u"8 765 000",
3175             u"876 500",
3176             u"87 650",
3177             u"8765",
3178             u"876,5",
3179             u"87,65",
3180             u"8,765",
3181             u"0");
3182
3183     assertFormatDescendingBig(
3184             u"Polish Grouping, Always",
3185             u"group-on-aligned",
3186             u",!",
3187             NumberFormatter::with().grouping(UNUM_GROUPING_ON_ALIGNED),
3188             Locale("pl"),
3189             u"87 650 000",
3190             u"8 765 000",
3191             u"876 500",
3192             u"87 650",
3193             u"8 765",
3194             u"876,5",
3195             u"87,65",
3196             u"8,765",
3197             u"0");
3198
3199     // NOTE: Bulgarian is interesting because it has no grouping in the default currency format.
3200     // If this test breaks due to data changes, find another locale that has no default grouping.
3201     assertFormatDescendingBig(
3202             u"Bulgarian Currency Grouping",
3203             u"currency/USD group-auto",
3204             u"currency/USD",
3205             NumberFormatter::with().grouping(UNUM_GROUPING_AUTO).unit(USD),
3206             Locale("bg"),
3207             u"87650000,00 щ.д.",
3208             u"8765000,00 щ.д.",
3209             u"876500,00 щ.д.",
3210             u"87650,00 щ.д.",
3211             u"8765,00 щ.д.",
3212             u"876,50 щ.д.",
3213             u"87,65 щ.д.",
3214             u"8,76 щ.д.",
3215             u"0,00 щ.д.");
3216
3217     assertFormatDescendingBig(
3218             u"Bulgarian Currency Grouping, Always",
3219             u"currency/USD group-on-aligned",
3220             u"currency/USD ,!",
3221             NumberFormatter::with().grouping(UNUM_GROUPING_ON_ALIGNED).unit(USD),
3222             Locale("bg"),
3223             u"87 650 000,00 щ.д.",
3224             u"8 765 000,00 щ.д.",
3225             u"876 500,00 щ.д.",
3226             u"87 650,00 щ.д.",
3227             u"8 765,00 щ.д.",
3228             u"876,50 щ.д.",
3229             u"87,65 щ.д.",
3230             u"8,76 щ.д.",
3231             u"0,00 щ.д.");
3232
3233     MacroProps macros;
3234     macros.grouper = Grouper(4, 1, 3, UNUM_GROUPING_COUNT);
3235     assertFormatDescendingBig(
3236             u"Custom Grouping via Internal API",
3237             nullptr,
3238             nullptr,
3239             NumberFormatter::with().macros(macros),
3240             Locale::getEnglish(),
3241             u"8,7,6,5,0000",
3242             u"8,7,6,5000",
3243             u"876500",
3244             u"87650",
3245             u"8765",
3246             u"876.5",
3247             u"87.65",
3248             u"8.765",
3249             u"0");
3250 }
3251
3252 void NumberFormatterApiTest::padding() {
3253     assertFormatDescending(
3254             u"Padding",
3255             nullptr,
3256             nullptr,
3257             NumberFormatter::with().padding(Padder::none()),
3258             Locale::getEnglish(),
3259             u"87,650",
3260             u"8,765",
3261             u"876.5",
3262             u"87.65",
3263             u"8.765",
3264             u"0.8765",
3265             u"0.08765",
3266             u"0.008765",
3267             u"0");
3268
3269     assertFormatDescending(
3270             u"Padding",
3271             nullptr,
3272             nullptr,
3273             NumberFormatter::with().padding(
3274                     Padder::codePoints(
3275                             '*', 8, PadPosition::UNUM_PAD_AFTER_PREFIX)),
3276             Locale::getEnglish(),
3277             u"**87,650",
3278             u"***8,765",
3279             u"***876.5",
3280             u"***87.65",
3281             u"***8.765",
3282             u"**0.8765",
3283             u"*0.08765",
3284             u"0.008765",
3285             u"*******0");
3286
3287     assertFormatDescending(
3288             u"Padding with code points",
3289             nullptr,
3290             nullptr,
3291             NumberFormatter::with().padding(
3292                     Padder::codePoints(
3293                             0x101E4, 8, PadPosition::UNUM_PAD_AFTER_PREFIX)),
3294             Locale::getEnglish(),
3295             u"𐇤𐇤87,650",
3296             u"𐇤𐇤𐇤8,765",
3297             u"𐇤𐇤𐇤876.5",
3298             u"𐇤𐇤𐇤87.65",
3299             u"𐇤𐇤𐇤8.765",
3300             u"𐇤𐇤0.8765",
3301             u"𐇤0.08765",
3302             u"0.008765",
3303             u"𐇤𐇤𐇤𐇤𐇤𐇤𐇤0");
3304
3305     assertFormatDescending(
3306             u"Padding with wide digits",
3307             nullptr,
3308             nullptr,
3309             NumberFormatter::with().padding(
3310                             Padder::codePoints(
3311                                     '*', 8, PadPosition::UNUM_PAD_AFTER_PREFIX))
3312                     .adoptSymbols(new NumberingSystem(MATHSANB)),
3313             Locale::getEnglish(),
3314             u"**𝟴𝟳,𝟲𝟱𝟬",
3315             u"***𝟴,𝟳𝟲𝟱",
3316             u"***𝟴𝟳𝟲.𝟱",
3317             u"***𝟴𝟳.𝟲𝟱",
3318             u"***𝟴.𝟳𝟲𝟱",
3319             u"**𝟬.𝟴𝟳𝟲𝟱",
3320             u"*𝟬.𝟬𝟴𝟳𝟲𝟱",
3321             u"𝟬.𝟬𝟬𝟴𝟳𝟲𝟱",
3322             u"*******𝟬");
3323
3324     assertFormatDescending(
3325             u"Padding with currency spacing",
3326             nullptr,
3327             nullptr,
3328             NumberFormatter::with().padding(
3329                             Padder::codePoints(
3330                                     '*', 10, PadPosition::UNUM_PAD_AFTER_PREFIX))
3331                     .unit(GBP)
3332                     .unitWidth(UNumberUnitWidth::UNUM_UNIT_WIDTH_ISO_CODE),
3333             Locale::getEnglish(),
3334             u"GBP 87,650.00",
3335             u"GBP 8,765.00",
3336             u"GBP*876.50",
3337             u"GBP**87.65",
3338             u"GBP***8.76",
3339             u"GBP***0.88",
3340             u"GBP***0.09",
3341             u"GBP***0.01",
3342             u"GBP***0.00");
3343
3344     assertFormatSingle(
3345             u"Pad Before Prefix",
3346             nullptr,
3347             nullptr,
3348             NumberFormatter::with().padding(
3349                     Padder::codePoints(
3350                             '*', 8, PadPosition::UNUM_PAD_BEFORE_PREFIX)),
3351             Locale::getEnglish(),
3352             -88.88,
3353             u"**-88.88");
3354
3355     assertFormatSingle(
3356             u"Pad After Prefix",
3357             nullptr,
3358             nullptr,
3359             NumberFormatter::with().padding(
3360                     Padder::codePoints(
3361                             '*', 8, PadPosition::UNUM_PAD_AFTER_PREFIX)),
3362             Locale::getEnglish(),
3363             -88.88,
3364             u"-**88.88");
3365
3366     assertFormatSingle(
3367             u"Pad Before Suffix",
3368             nullptr,
3369             nullptr,
3370             NumberFormatter::with().padding(
3371                     Padder::codePoints(
3372                             '*', 8, PadPosition::UNUM_PAD_BEFORE_SUFFIX)).unit(NoUnit::percent()),
3373             Locale::getEnglish(),
3374             88.88,
3375             u"88.88**%");
3376
3377     assertFormatSingle(
3378             u"Pad After Suffix",
3379             nullptr,
3380             nullptr,
3381             NumberFormatter::with().padding(
3382                     Padder::codePoints(
3383                             '*', 8, PadPosition::UNUM_PAD_AFTER_SUFFIX)).unit(NoUnit::percent()),
3384             Locale::getEnglish(),
3385             88.88,
3386             u"88.88%**");
3387
3388     assertFormatSingle(
3389             u"Currency Spacing with Zero Digit Padding Broken",
3390             nullptr,
3391             nullptr,
3392             NumberFormatter::with().padding(
3393                             Padder::codePoints(
3394                                     '0', 12, PadPosition::UNUM_PAD_AFTER_PREFIX))
3395                     .unit(GBP)
3396                     .unitWidth(UNumberUnitWidth::UNUM_UNIT_WIDTH_ISO_CODE),
3397             Locale::getEnglish(),
3398             514.23,
3399             u"GBP 000514.23"); // TODO: This is broken; it renders too wide (13 instead of 12).
3400 }
3401
3402 void NumberFormatterApiTest::integerWidth() {
3403     assertFormatDescending(
3404             u"Integer Width Default",
3405             u"integer-width/+0",
3406             u"0",
3407             NumberFormatter::with().integerWidth(IntegerWidth::zeroFillTo(1)),
3408             Locale::getEnglish(),
3409             u"87,650",
3410             u"8,765",
3411             u"876.5",
3412             u"87.65",
3413             u"8.765",
3414             u"0.8765",
3415             u"0.08765",
3416             u"0.008765",
3417             u"0");
3418
3419     assertFormatDescending(
3420             u"Integer Width Zero Fill 0",
3421             u"integer-width/*",
3422             u"integer-width/+",
3423             NumberFormatter::with().integerWidth(IntegerWidth::zeroFillTo(0)),
3424             Locale::getEnglish(),
3425             u"87,650",
3426             u"8,765",
3427             u"876.5",
3428             u"87.65",
3429             u"8.765",
3430             u".8765",
3431             u".08765",
3432             u".008765",
3433             u"0");  // see ICU-20844
3434
3435     assertFormatDescending(
3436             u"Integer Width Zero Fill 3",
3437             u"integer-width/+000",
3438             u"000",
3439             NumberFormatter::with().integerWidth(IntegerWidth::zeroFillTo(3)),
3440             Locale::getEnglish(),
3441             u"87,650",
3442             u"8,765",
3443             u"876.5",
3444             u"087.65",
3445             u"008.765",
3446             u"000.8765",
3447             u"000.08765",
3448             u"000.008765",
3449             u"000");
3450
3451     assertFormatDescending(
3452             u"Integer Width Max 3",
3453             u"integer-width/##0",
3454             u"integer-width/##0",
3455             NumberFormatter::with().integerWidth(IntegerWidth::zeroFillTo(1).truncateAt(3)),
3456             Locale::getEnglish(),
3457             u"650",
3458             u"765",
3459             u"876.5",
3460             u"87.65",
3461             u"8.765",
3462             u"0.8765",
3463             u"0.08765",
3464             u"0.008765",
3465             u"0");
3466
3467     assertFormatDescending(
3468             u"Integer Width Fixed 2",
3469             u"integer-width/00",
3470             u"integer-width/00",
3471             NumberFormatter::with().integerWidth(IntegerWidth::zeroFillTo(2).truncateAt(2)),
3472             Locale::getEnglish(),
3473             u"50",
3474             u"65",
3475             u"76.5",
3476             u"87.65",
3477             u"08.765",
3478             u"00.8765",
3479             u"00.08765",
3480             u"00.008765",
3481             u"00");
3482
3483     assertFormatDescending(
3484             u"Integer Width Compact",
3485             u"compact-short integer-width/000",
3486             u"compact-short integer-width/000",
3487             NumberFormatter::with()
3488                 .notation(Notation::compactShort())
3489                 .integerWidth(IntegerWidth::zeroFillTo(3).truncateAt(3)),
3490             Locale::getEnglish(),
3491             u"088K",
3492             u"008.8K",
3493             u"876",
3494             u"088",
3495             u"008.8",
3496             u"000.88",
3497             u"000.088",
3498             u"000.0088",
3499             u"000");
3500
3501     assertFormatDescending(
3502             u"Integer Width Scientific",
3503             u"scientific integer-width/000",
3504             u"scientific integer-width/000",
3505             NumberFormatter::with()
3506                 .notation(Notation::scientific())
3507                 .integerWidth(IntegerWidth::zeroFillTo(3).truncateAt(3)),
3508             Locale::getEnglish(),
3509             u"008.765E4",
3510             u"008.765E3",
3511             u"008.765E2",
3512             u"008.765E1",
3513             u"008.765E0",
3514             u"008.765E-1",
3515             u"008.765E-2",
3516             u"008.765E-3",
3517             u"000E0");
3518
3519     assertFormatDescending(
3520             u"Integer Width Engineering",
3521             u"engineering integer-width/000",
3522             u"engineering integer-width/000",
3523             NumberFormatter::with()
3524                 .notation(Notation::engineering())
3525                 .integerWidth(IntegerWidth::zeroFillTo(3).truncateAt(3)),
3526             Locale::getEnglish(),
3527             u"087.65E3",
3528             u"008.765E3",
3529             u"876.5E0",
3530             u"087.65E0",
3531             u"008.765E0",
3532             u"876.5E-3",
3533             u"087.65E-3",
3534             u"008.765E-3",
3535             u"000E0");
3536
3537     assertFormatSingle(
3538             u"Integer Width Remove All A",
3539             u"integer-width/00",
3540             u"integer-width/00",
3541             NumberFormatter::with().integerWidth(IntegerWidth::zeroFillTo(2).truncateAt(2)),
3542             "en",
3543             2500,
3544             u"00");
3545
3546     assertFormatSingle(
3547             u"Integer Width Remove All B",
3548             u"integer-width/00",
3549             u"integer-width/00",
3550             NumberFormatter::with().integerWidth(IntegerWidth::zeroFillTo(2).truncateAt(2)),
3551             "en",
3552             25000,
3553             u"00");
3554
3555     assertFormatSingle(
3556             u"Integer Width Remove All B, Bytes Mode",
3557             u"integer-width/00",
3558             u"integer-width/00",
3559             NumberFormatter::with().integerWidth(IntegerWidth::zeroFillTo(2).truncateAt(2)),
3560             "en",
3561             // Note: this double produces all 17 significant digits
3562             10000000000000002000.0,
3563             u"00");
3564 }
3565
3566 void NumberFormatterApiTest::symbols() {
3567     assertFormatDescending(
3568             u"French Symbols with Japanese Data 1",
3569             nullptr,
3570             nullptr,
3571             NumberFormatter::with().symbols(FRENCH_SYMBOLS),
3572             Locale::getJapan(),
3573             u"87\u202F650",
3574             u"8\u202F765",
3575             u"876,5",
3576             u"87,65",
3577             u"8,765",
3578             u"0,8765",
3579             u"0,08765",
3580             u"0,008765",
3581             u"0");
3582
3583     assertFormatSingle(
3584             u"French Symbols with Japanese Data 2",
3585             nullptr,
3586             nullptr,
3587             NumberFormatter::with().notation(Notation::compactShort()).symbols(FRENCH_SYMBOLS),
3588             Locale::getJapan(),
3589             12345,
3590             u"1,2\u4E07");
3591
3592     assertFormatDescending(
3593             u"Latin Numbering System with Arabic Data",
3594             u"currency/USD latin",
3595             u"currency/USD latin",
3596             NumberFormatter::with().adoptSymbols(new NumberingSystem(LATN)).unit(USD),
3597             Locale("ar"),
3598             u"US$ 87,650.00",
3599             u"US$ 8,765.00",
3600             u"US$ 876.50",
3601             u"US$ 87.65",
3602             u"US$ 8.76",
3603             u"US$ 0.88",
3604             u"US$ 0.09",
3605             u"US$ 0.01",
3606             u"US$ 0.00");
3607
3608     assertFormatDescending(
3609             u"Math Numbering System with French Data",
3610             u"numbering-system/mathsanb",
3611             u"numbering-system/mathsanb",
3612             NumberFormatter::with().adoptSymbols(new NumberingSystem(MATHSANB)),
3613             Locale::getFrench(),
3614             u"𝟴𝟳\u202F𝟲𝟱𝟬",
3615             u"𝟴\u202F𝟳𝟲𝟱",
3616             u"𝟴𝟳𝟲,𝟱",
3617             u"𝟴𝟳,𝟲𝟱",
3618             u"𝟴,𝟳𝟲𝟱",
3619             u"𝟬,𝟴𝟳𝟲𝟱",
3620             u"𝟬,𝟬𝟴𝟳𝟲𝟱",
3621             u"𝟬,𝟬𝟬𝟴𝟳𝟲𝟱",
3622             u"𝟬");
3623
3624     assertFormatSingle(
3625             u"Swiss Symbols (used in documentation)",
3626             nullptr,
3627             nullptr,
3628             NumberFormatter::with().symbols(SWISS_SYMBOLS),
3629             Locale::getEnglish(),
3630             12345.67,
3631             u"12’345.67");
3632
3633     assertFormatSingle(
3634             u"Myanmar Symbols (used in documentation)",
3635             nullptr,
3636             nullptr,
3637             NumberFormatter::with().symbols(MYANMAR_SYMBOLS),
3638             Locale::getEnglish(),
3639             12345.67,
3640             u"\u1041\u1042,\u1043\u1044\u1045.\u1046\u1047");
3641
3642     // NOTE: Locale ar puts ¤ after the number in NS arab but before the number in NS latn.
3643
3644     assertFormatSingle(
3645             u"Currency symbol should precede number in ar with NS latn",
3646             u"currency/USD latin",
3647             u"currency/USD latin",
3648             NumberFormatter::with().adoptSymbols(new NumberingSystem(LATN)).unit(USD),
3649             Locale("ar"),
3650             12345.67,
3651             u"US$ 12,345.67");
3652
3653     assertFormatSingle(
3654             u"Currency symbol should precede number in ar@numbers=latn",
3655             u"currency/USD",
3656             u"currency/USD",
3657             NumberFormatter::with().unit(USD),
3658             Locale("ar@numbers=latn"),
3659             12345.67,
3660             u"US$ 12,345.67");
3661
3662     assertFormatSingle(
3663             u"Currency symbol should follow number in ar-EG with NS arab",
3664             u"currency/USD",
3665             u"currency/USD",
3666             NumberFormatter::with().unit(USD),
3667             Locale("ar-EG"),
3668             12345.67,
3669             u"١٢٬٣٤٥٫٦٧ US$");
3670
3671     assertFormatSingle(
3672             u"Currency symbol should follow number in ar@numbers=arab",
3673             u"currency/USD",
3674             u"currency/USD",
3675             NumberFormatter::with().unit(USD),
3676             Locale("ar@numbers=arab"),
3677             12345.67,
3678             u"١٢٬٣٤٥٫٦٧ US$");
3679
3680     assertFormatSingle(
3681             u"NumberingSystem in API should win over @numbers keyword",
3682             u"currency/USD latin",
3683             u"currency/USD latin",
3684             NumberFormatter::with().adoptSymbols(new NumberingSystem(LATN)).unit(USD),
3685             Locale("ar@numbers=arab"),
3686             12345.67,
3687             u"US$ 12,345.67");
3688
3689     UErrorCode status = U_ZERO_ERROR;
3690     assertEquals(
3691             "NumberingSystem in API should win over @numbers keyword in reverse order",
3692             u"US$ 12,345.67",
3693             NumberFormatter::withLocale(Locale("ar@numbers=arab")).adoptSymbols(new NumberingSystem(LATN))
3694                     .unit(USD)
3695                     .formatDouble(12345.67, status)
3696                     .toString(status));
3697
3698     DecimalFormatSymbols symbols = SWISS_SYMBOLS;
3699     UnlocalizedNumberFormatter f = NumberFormatter::with().symbols(symbols);
3700     symbols.setSymbol(DecimalFormatSymbols::ENumberFormatSymbol::kGroupingSeparatorSymbol, u"!", status);
3701     assertFormatSingle(
3702             u"Symbols object should be copied",
3703             nullptr,
3704             nullptr,
3705             f,
3706             Locale::getEnglish(),
3707             12345.67,
3708             u"12’345.67");
3709
3710     assertFormatSingle(
3711             u"The last symbols setter wins",
3712             u"latin",
3713             u"latin",
3714             NumberFormatter::with().symbols(symbols).adoptSymbols(new NumberingSystem(LATN)),
3715             Locale::getEnglish(),
3716             12345.67,
3717             u"12,345.67");
3718
3719     assertFormatSingle(
3720             u"The last symbols setter wins",
3721             nullptr,
3722             nullptr,
3723             NumberFormatter::with().adoptSymbols(new NumberingSystem(LATN)).symbols(symbols),
3724             Locale::getEnglish(),
3725             12345.67,
3726             u"12!345.67");
3727 }
3728
3729 // TODO: Enable if/when currency symbol override is added.
3730 //void NumberFormatterTest::symbolsOverride() {
3731 //    DecimalFormatSymbols dfs = DecimalFormatSymbols.getInstance(Locale::getEnglish());
3732 //    dfs.setCurrencySymbol("@");
3733 //    dfs.setInternationalCurrencySymbol("foo");
3734 //    assertFormatSingle(
3735 //            u"Custom Short Currency Symbol",
3736 //            NumberFormatter::with().unit(Currency.getInstance("XXX")).symbols(dfs),
3737 //            Locale::getEnglish(),
3738 //            12.3,
3739 //            u"@ 12.30");
3740 //}
3741
3742 void NumberFormatterApiTest::sign() {
3743     assertFormatSingle(
3744             u"Sign Auto Positive",
3745             u"sign-auto",
3746             u"",
3747             NumberFormatter::with().sign(UNumberSignDisplay::UNUM_SIGN_AUTO),
3748             Locale::getEnglish(),
3749             444444,
3750             u"444,444");
3751
3752     assertFormatSingle(
3753             u"Sign Auto Negative",
3754             u"sign-auto",
3755             u"",
3756             NumberFormatter::with().sign(UNumberSignDisplay::UNUM_SIGN_AUTO),
3757             Locale::getEnglish(),
3758             -444444,
3759             u"-444,444");
3760
3761     assertFormatSingle(
3762             u"Sign Auto Zero",
3763             u"sign-auto",
3764             u"",
3765             NumberFormatter::with().sign(UNumberSignDisplay::UNUM_SIGN_AUTO),
3766             Locale::getEnglish(),
3767             0,
3768             u"0");
3769
3770     assertFormatSingle(
3771             u"Sign Always Positive",
3772             u"sign-always",
3773             u"+!",
3774             NumberFormatter::with().sign(UNumberSignDisplay::UNUM_SIGN_ALWAYS),
3775             Locale::getEnglish(),
3776             444444,
3777             u"+444,444");
3778
3779     assertFormatSingle(
3780             u"Sign Always Negative",
3781             u"sign-always",
3782             u"+!",
3783             NumberFormatter::with().sign(UNumberSignDisplay::UNUM_SIGN_ALWAYS),
3784             Locale::getEnglish(),
3785             -444444,
3786             u"-444,444");
3787
3788     assertFormatSingle(
3789             u"Sign Always Zero",
3790             u"sign-always",
3791             u"+!",
3792             NumberFormatter::with().sign(UNumberSignDisplay::UNUM_SIGN_ALWAYS),
3793             Locale::getEnglish(),
3794             0,
3795             u"+0");
3796
3797     assertFormatSingle(
3798             u"Sign Never Positive",
3799             u"sign-never",
3800             u"+_",
3801             NumberFormatter::with().sign(UNumberSignDisplay::UNUM_SIGN_NEVER),
3802             Locale::getEnglish(),
3803             444444,
3804             u"444,444");
3805
3806     assertFormatSingle(
3807             u"Sign Never Negative",
3808             u"sign-never",
3809             u"+_",
3810             NumberFormatter::with().sign(UNumberSignDisplay::UNUM_SIGN_NEVER),
3811             Locale::getEnglish(),
3812             -444444,
3813             u"444,444");
3814
3815     assertFormatSingle(
3816             u"Sign Never Zero",
3817             u"sign-never",
3818             u"+_",
3819             NumberFormatter::with().sign(UNumberSignDisplay::UNUM_SIGN_NEVER),
3820             Locale::getEnglish(),
3821             0,
3822             u"0");
3823
3824     assertFormatSingle(
3825             u"Sign Accounting Positive",
3826             u"currency/USD sign-accounting",
3827             u"currency/USD ()",
3828             NumberFormatter::with().sign(UNumberSignDisplay::UNUM_SIGN_ACCOUNTING).unit(USD),
3829             Locale::getEnglish(),
3830             444444,
3831             u"$444,444.00");
3832
3833     assertFormatSingle(
3834             u"Sign Accounting Negative",
3835             u"currency/USD sign-accounting",
3836             u"currency/USD ()",
3837             NumberFormatter::with().sign(UNumberSignDisplay::UNUM_SIGN_ACCOUNTING).unit(USD),
3838             Locale::getEnglish(),
3839             -444444,
3840             u"($444,444.00)");
3841
3842     assertFormatSingle(
3843             u"Sign Accounting Zero",
3844             u"currency/USD sign-accounting",
3845             u"currency/USD ()",
3846             NumberFormatter::with().sign(UNumberSignDisplay::UNUM_SIGN_ACCOUNTING).unit(USD),
3847             Locale::getEnglish(),
3848             0,
3849             u"$0.00");
3850
3851     assertFormatSingle(
3852             u"Sign Accounting-Always Positive",
3853             u"currency/USD sign-accounting-always",
3854             u"currency/USD ()!",
3855             NumberFormatter::with().sign(UNumberSignDisplay::UNUM_SIGN_ACCOUNTING_ALWAYS).unit(USD),
3856             Locale::getEnglish(),
3857             444444,
3858             u"+$444,444.00");
3859
3860     assertFormatSingle(
3861             u"Sign Accounting-Always Negative",
3862             u"currency/USD sign-accounting-always",
3863             u"currency/USD ()!",
3864             NumberFormatter::with().sign(UNumberSignDisplay::UNUM_SIGN_ACCOUNTING_ALWAYS).unit(USD),
3865             Locale::getEnglish(),
3866             -444444,
3867             u"($444,444.00)");
3868
3869     assertFormatSingle(
3870             u"Sign Accounting-Always Zero",
3871             u"currency/USD sign-accounting-always",
3872             u"currency/USD ()!",
3873             NumberFormatter::with().sign(UNumberSignDisplay::UNUM_SIGN_ACCOUNTING_ALWAYS).unit(USD),
3874             Locale::getEnglish(),
3875             0,
3876             u"+$0.00");
3877
3878     assertFormatSingle(
3879             u"Sign Except-Zero Positive",
3880             u"sign-except-zero",
3881             u"+?",
3882             NumberFormatter::with().sign(UNumberSignDisplay::UNUM_SIGN_EXCEPT_ZERO),
3883             Locale::getEnglish(),
3884             444444,
3885             u"+444,444");
3886
3887     assertFormatSingle(
3888             u"Sign Except-Zero Negative",
3889             u"sign-except-zero",
3890             u"+?",
3891             NumberFormatter::with().sign(UNumberSignDisplay::UNUM_SIGN_EXCEPT_ZERO),
3892             Locale::getEnglish(),
3893             -444444,
3894             u"-444,444");
3895
3896     assertFormatSingle(
3897             u"Sign Except-Zero Zero",
3898             u"sign-except-zero",
3899             u"+?",
3900             NumberFormatter::with().sign(UNumberSignDisplay::UNUM_SIGN_EXCEPT_ZERO),
3901             Locale::getEnglish(),
3902             0,
3903             u"0");
3904
3905     assertFormatSingle(
3906             u"Sign Accounting-Except-Zero Positive",
3907             u"currency/USD sign-accounting-except-zero",
3908             u"currency/USD ()?",
3909             NumberFormatter::with().sign(UNumberSignDisplay::UNUM_SIGN_ACCOUNTING_EXCEPT_ZERO).unit(USD),
3910             Locale::getEnglish(),
3911             444444,
3912             u"+$444,444.00");
3913
3914     assertFormatSingle(
3915             u"Sign Accounting-Except-Zero Negative",
3916             u"currency/USD sign-accounting-except-zero",
3917             u"currency/USD ()?",
3918             NumberFormatter::with().sign(UNumberSignDisplay::UNUM_SIGN_ACCOUNTING_EXCEPT_ZERO).unit(USD),
3919             Locale::getEnglish(),
3920             -444444,
3921             u"($444,444.00)");
3922
3923     assertFormatSingle(
3924             u"Sign Accounting-Except-Zero Zero",
3925             u"currency/USD sign-accounting-except-zero",
3926             u"currency/USD ()?",
3927             NumberFormatter::with().sign(UNumberSignDisplay::UNUM_SIGN_ACCOUNTING_EXCEPT_ZERO).unit(USD),
3928             Locale::getEnglish(),
3929             0,
3930             u"$0.00");
3931
3932     assertFormatSingle(
3933             u"Sign Negative Positive",
3934             u"sign-negative",
3935             u"+-",
3936             NumberFormatter::with().sign(UNumberSignDisplay::UNUM_SIGN_NEGATIVE),
3937             Locale::getEnglish(),
3938             444444,
3939             u"444,444");
3940
3941     assertFormatSingle(
3942             u"Sign Negative Negative",
3943             u"sign-negative",
3944             u"+-",
3945             NumberFormatter::with().sign(UNumberSignDisplay::UNUM_SIGN_NEGATIVE),
3946             Locale::getEnglish(),
3947             -444444,
3948             u"-444,444");
3949
3950     assertFormatSingle(
3951             u"Sign Negative Negative Zero",
3952             u"sign-negative",
3953             u"+-",
3954             NumberFormatter::with().sign(UNumberSignDisplay::UNUM_SIGN_NEGATIVE),
3955             Locale::getEnglish(),
3956             -0.0000001,
3957             u"0");
3958
3959     assertFormatSingle(
3960             u"Sign Accounting-Negative Positive",
3961             u"currency/USD sign-accounting-negative",
3962             u"currency/USD ()-",
3963             NumberFormatter::with().sign(UNumberSignDisplay::UNUM_SIGN_ACCOUNTING_NEGATIVE).unit(USD),
3964             Locale::getEnglish(),
3965             444444,
3966             u"$444,444.00");
3967         
3968     assertFormatSingle(
3969             u"Sign Accounting-Negative Negative",
3970             u"currency/USD sign-accounting-negative",
3971             u"currency/USD ()-",
3972             NumberFormatter::with().sign(UNumberSignDisplay::UNUM_SIGN_ACCOUNTING_NEGATIVE).unit(USD),
3973             Locale::getEnglish(),
3974             -444444,
3975             "($444,444.00)");
3976
3977     assertFormatSingle(
3978             u"Sign Accounting-Negative Negative Zero",
3979             u"currency/USD sign-accounting-negative",
3980             u"currency/USD ()-",
3981             NumberFormatter::with().sign(UNumberSignDisplay::UNUM_SIGN_ACCOUNTING_NEGATIVE).unit(USD),
3982             Locale::getEnglish(),
3983             -0.0000001,
3984             u"$0.00");
3985
3986     assertFormatSingle(
3987             u"Sign Accounting Negative Hidden",
3988             u"currency/USD unit-width-hidden sign-accounting",
3989             u"currency/USD unit-width-hidden ()",
3990             NumberFormatter::with()
3991                     .sign(UNumberSignDisplay::UNUM_SIGN_ACCOUNTING)
3992                     .unit(USD)
3993                     .unitWidth(UNUM_UNIT_WIDTH_HIDDEN),
3994             Locale::getEnglish(),
3995             -444444,
3996             u"(444,444.00)");
3997
3998     assertFormatSingle(
3999             u"Sign Accounting Negative Narrow",
4000             u"currency/USD unit-width-narrow sign-accounting",
4001             u"currency/USD unit-width-narrow ()",
4002             NumberFormatter::with()
4003                 .sign(UNumberSignDisplay::UNUM_SIGN_ACCOUNTING)
4004                 .unit(USD)
4005                 .unitWidth(UNUM_UNIT_WIDTH_NARROW),
4006             Locale::getCanada(),
4007             -444444,
4008             u"($444,444.00)");
4009
4010     assertFormatSingle(
4011             u"Sign Accounting Negative Short",
4012             u"currency/USD sign-accounting",
4013             u"currency/USD ()",
4014             NumberFormatter::with()
4015                 .sign(UNumberSignDisplay::UNUM_SIGN_ACCOUNTING)
4016                 .unit(USD)
4017                 .unitWidth(UNUM_UNIT_WIDTH_SHORT),
4018             Locale::getCanada(),
4019             -444444,
4020             u"(US$444,444.00)");
4021
4022     assertFormatSingle(
4023             u"Sign Accounting Negative Iso Code",
4024             u"currency/USD unit-width-iso-code sign-accounting",
4025             u"currency/USD unit-width-iso-code ()",
4026             NumberFormatter::with()
4027                 .sign(UNumberSignDisplay::UNUM_SIGN_ACCOUNTING)
4028                 .unit(USD)
4029                 .unitWidth(UNUM_UNIT_WIDTH_ISO_CODE),
4030             Locale::getCanada(),
4031             -444444,
4032             u"(USD 444,444.00)");
4033
4034     // Note: CLDR does not provide an accounting pattern for long name currency.
4035     // We fall back to normal currency format. This may change in the future.
4036     assertFormatSingle(
4037             u"Sign Accounting Negative Full Name",
4038             u"currency/USD unit-width-full-name sign-accounting",
4039             u"currency/USD unit-width-full-name ()",
4040             NumberFormatter::with()
4041                 .sign(UNumberSignDisplay::UNUM_SIGN_ACCOUNTING)
4042                 .unit(USD)
4043                 .unitWidth(UNUM_UNIT_WIDTH_FULL_NAME),
4044             Locale::getCanada(),
4045             -444444,
4046             u"-444,444.00 US dollars");
4047 }
4048
4049 void NumberFormatterApiTest::signNearZero() {
4050     // https://unicode-org.atlassian.net/browse/ICU-20709
4051     IcuTestErrorCode status(*this, "signNearZero");
4052     const struct TestCase {
4053         UNumberSignDisplay sign;
4054         double input;
4055         const char16_t* expected;
4056     } cases[] = {
4057         { UNUM_SIGN_AUTO,  1.1, u"1" },
4058         { UNUM_SIGN_AUTO,  0.9, u"1" },
4059         { UNUM_SIGN_AUTO,  0.1, u"0" },
4060         { UNUM_SIGN_AUTO, -0.1, u"-0" }, // interesting case
4061         { UNUM_SIGN_AUTO, -0.9, u"-1" },
4062         { UNUM_SIGN_AUTO, -1.1, u"-1" },
4063         { UNUM_SIGN_ALWAYS,  1.1, u"+1" },
4064         { UNUM_SIGN_ALWAYS,  0.9, u"+1" },
4065         { UNUM_SIGN_ALWAYS,  0.1, u"+0" },
4066         { UNUM_SIGN_ALWAYS, -0.1, u"-0" },
4067         { UNUM_SIGN_ALWAYS, -0.9, u"-1" },
4068         { UNUM_SIGN_ALWAYS, -1.1, u"-1" },
4069         { UNUM_SIGN_EXCEPT_ZERO,  1.1, u"+1" },
4070         { UNUM_SIGN_EXCEPT_ZERO,  0.9, u"+1" },
4071         { UNUM_SIGN_EXCEPT_ZERO,  0.1, u"0" }, // interesting case
4072         { UNUM_SIGN_EXCEPT_ZERO, -0.1, u"0" }, // interesting case
4073         { UNUM_SIGN_EXCEPT_ZERO, -0.9, u"-1" },
4074         { UNUM_SIGN_EXCEPT_ZERO, -1.1, u"-1" },
4075         { UNUM_SIGN_NEGATIVE,  1.1, u"1" },
4076         { UNUM_SIGN_NEGATIVE,  0.9, u"1" },
4077         { UNUM_SIGN_NEGATIVE,  0.1, u"0" },
4078         { UNUM_SIGN_NEGATIVE, -0.1, u"0" }, // interesting case
4079         { UNUM_SIGN_NEGATIVE, -0.9, u"-1" },
4080         { UNUM_SIGN_NEGATIVE, -1.1, u"-1" },
4081     };
4082     for (auto& cas : cases) {
4083         auto sign = cas.sign;
4084         auto input = cas.input;
4085         auto expected = cas.expected;
4086         auto actual = NumberFormatter::with()
4087             .sign(sign)
4088             .precision(Precision::integer())
4089             .locale(Locale::getUS())
4090             .formatDouble(input, status)
4091             .toString(status);
4092         assertEquals(
4093             DoubleToUnicodeString(input) + " @ SignDisplay " + Int64ToUnicodeString(sign),
4094             expected, actual);
4095     }
4096 }
4097
4098 void NumberFormatterApiTest::signCoverage() {
4099     // https://unicode-org.atlassian.net/browse/ICU-20708
4100     IcuTestErrorCode status(*this, "signCoverage");
4101     const struct TestCase {
4102         UNumberSignDisplay sign;
4103         const char16_t* expectedStrings[8];
4104     } cases[] = {
4105         { UNUM_SIGN_AUTO, {        u"-∞", u"-1", u"-0",  u"0",  u"1",  u"∞",  u"NaN", u"-NaN" } },
4106         { UNUM_SIGN_ALWAYS, {      u"-∞", u"-1", u"-0", u"+0", u"+1", u"+∞", u"+NaN", u"-NaN" } },
4107         { UNUM_SIGN_NEVER, {        u"∞",  u"1",  u"0",  u"0",  u"1",  u"∞",  u"NaN",  u"NaN" } },
4108         { UNUM_SIGN_EXCEPT_ZERO, { u"-∞", u"-1",  u"0",  u"0", u"+1", u"+∞",  u"NaN",  u"NaN" } },
4109     };
4110     double negNaN = std::copysign(uprv_getNaN(), -0.0);
4111     const double inputs[] = {
4112         -uprv_getInfinity(), -1, -0.0, 0, 1, uprv_getInfinity(), uprv_getNaN(), negNaN
4113     };
4114     for (auto& cas : cases) {
4115         auto sign = cas.sign;
4116         for (int32_t i = 0; i < UPRV_LENGTHOF(inputs); i++) {
4117             auto input = inputs[i];
4118             auto expected = cas.expectedStrings[i];
4119             auto actual = NumberFormatter::with()
4120                 .sign(sign)
4121                 .locale(Locale::getUS())
4122                 .formatDouble(input, status)
4123                 .toString(status);
4124             assertEquals(
4125                 DoubleToUnicodeString(input) + " " + Int64ToUnicodeString(sign),
4126                 expected, actual);
4127         }
4128     }
4129 }
4130
4131 void NumberFormatterApiTest::decimal() {
4132     assertFormatDescending(
4133             u"Decimal Default",
4134             u"decimal-auto",
4135             u"",
4136             NumberFormatter::with().decimal(UNumberDecimalSeparatorDisplay::UNUM_DECIMAL_SEPARATOR_AUTO),
4137             Locale::getEnglish(),
4138             u"87,650",
4139             u"8,765",
4140             u"876.5",
4141             u"87.65",
4142             u"8.765",
4143             u"0.8765",
4144             u"0.08765",
4145             u"0.008765",
4146             u"0");
4147
4148     assertFormatDescending(
4149             u"Decimal Always Shown",
4150             u"decimal-always",
4151             u"decimal-always",
4152             NumberFormatter::with().decimal(UNumberDecimalSeparatorDisplay::UNUM_DECIMAL_SEPARATOR_ALWAYS),
4153             Locale::getEnglish(),
4154             u"87,650.",
4155             u"8,765.",
4156             u"876.5",
4157             u"87.65",
4158             u"8.765",
4159             u"0.8765",
4160             u"0.08765",
4161             u"0.008765",
4162             u"0.");
4163 }
4164
4165 void NumberFormatterApiTest::scale() {
4166     assertFormatDescending(
4167             u"Multiplier None",
4168             u"scale/1",
4169             u"",
4170             NumberFormatter::with().scale(Scale::none()),
4171             Locale::getEnglish(),
4172             u"87,650",
4173             u"8,765",
4174             u"876.5",
4175             u"87.65",
4176             u"8.765",
4177             u"0.8765",
4178             u"0.08765",
4179             u"0.008765",
4180             u"0");
4181
4182     assertFormatDescending(
4183             u"Multiplier Power of Ten",
4184             u"scale/1000000",
4185             u"scale/1E6",
4186             NumberFormatter::with().scale(Scale::powerOfTen(6)),
4187             Locale::getEnglish(),
4188             u"87,650,000,000",
4189             u"8,765,000,000",
4190             u"876,500,000",
4191             u"87,650,000",
4192             u"8,765,000",
4193             u"876,500",
4194             u"87,650",
4195             u"8,765",
4196             u"0");
4197
4198     assertFormatDescending(
4199             u"Multiplier Arbitrary Double",
4200             u"scale/5.2",
4201             u"scale/5.2",
4202             NumberFormatter::with().scale(Scale::byDouble(5.2)),
4203             Locale::getEnglish(),
4204             u"455,780",
4205             u"45,578",
4206             u"4,557.8",
4207             u"455.78",
4208             u"45.578",
4209             u"4.5578",
4210             u"0.45578",
4211             u"0.045578",
4212             u"0");
4213
4214     assertFormatDescending(
4215             u"Multiplier Arbitrary BigDecimal",
4216             u"scale/5.2",
4217             u"scale/5.2",
4218             NumberFormatter::with().scale(Scale::byDecimal({"5.2", -1})),
4219             Locale::getEnglish(),
4220             u"455,780",
4221             u"45,578",
4222             u"4,557.8",
4223             u"455.78",
4224             u"45.578",
4225             u"4.5578",
4226             u"0.45578",
4227             u"0.045578",
4228             u"0");
4229
4230     assertFormatDescending(
4231             u"Multiplier Arbitrary Double And Power Of Ten",
4232             u"scale/5200",
4233             u"scale/5200",
4234             NumberFormatter::with().scale(Scale::byDoubleAndPowerOfTen(5.2, 3)),
4235             Locale::getEnglish(),
4236             u"455,780,000",
4237             u"45,578,000",
4238             u"4,557,800",
4239             u"455,780",
4240             u"45,578",
4241             u"4,557.8",
4242             u"455.78",
4243             u"45.578",
4244             u"0");
4245
4246     assertFormatDescending(
4247             u"Multiplier Zero",
4248             u"scale/0",
4249             u"scale/0",
4250             NumberFormatter::with().scale(Scale::byDouble(0)),
4251             Locale::getEnglish(),
4252             u"0",
4253             u"0",
4254             u"0",
4255             u"0",
4256             u"0",
4257             u"0",
4258             u"0",
4259             u"0",
4260             u"0");
4261
4262     assertFormatSingle(
4263             u"Multiplier Skeleton Scientific Notation and Percent",
4264             u"percent scale/1E2",
4265             u"%x100",
4266             NumberFormatter::with().unit(NoUnit::percent()).scale(Scale::powerOfTen(2)),
4267             Locale::getEnglish(),
4268             0.5,
4269             u"50%");
4270
4271     assertFormatSingle(
4272             u"Negative Multiplier",
4273             u"scale/-5.2",
4274             u"scale/-5.2",
4275             NumberFormatter::with().scale(Scale::byDouble(-5.2)),
4276             Locale::getEnglish(),
4277             2,
4278             u"-10.4");
4279
4280     assertFormatSingle(
4281             u"Negative One Multiplier",
4282             u"scale/-1",
4283             u"scale/-1",
4284             NumberFormatter::with().scale(Scale::byDouble(-1)),
4285             Locale::getEnglish(),
4286             444444,
4287             u"-444,444");
4288
4289     assertFormatSingle(
4290             u"Two-Type Multiplier with Overlap",
4291             u"scale/10000",
4292             u"scale/1E4",
4293             NumberFormatter::with().scale(Scale::byDoubleAndPowerOfTen(100, 2)),
4294             Locale::getEnglish(),
4295             2,
4296             u"20,000");
4297 }
4298
4299 void NumberFormatterApiTest::locale() {
4300     // Coverage for the locale setters.
4301     UErrorCode status = U_ZERO_ERROR;
4302     UnicodeString actual = NumberFormatter::withLocale(Locale::getFrench()).formatInt(1234, status)
4303             .toString(status);
4304     assertEquals("Locale withLocale()", u"1\u202f234", actual);
4305 }
4306
4307 void NumberFormatterApiTest::skeletonUserGuideExamples() {
4308     IcuTestErrorCode status(*this, "skeletonUserGuideExamples");
4309
4310     // Test the skeleton examples in userguide/format_parse/numbers/skeletons.md
4311     struct TestCase {
4312         const char16_t* skeleton;
4313         const char16_t* conciseSkeleton;
4314         double input;
4315         const char16_t* expected;
4316     } cases[] = {
4317         {u"percent", u"%", 25, u"25%"},
4318         {u".00", u".00", 25, u"25.00"},
4319         {u"percent .00", u"% .00", 25, u"25.00%"},
4320         {u"scale/100", u"scale/100", 0.3, u"30"},
4321         {u"percent scale/100", u"%x100", 0.3, u"30%"},
4322         {u"measure-unit/length-meter", u"unit/meter", 5, u"5 m"},
4323         {u"measure-unit/length-meter unit-width-full-name", u"unit/meter unit-width-full-name", 5, u"5 meters"},
4324         {u"currency/CAD", u"currency/CAD", 10, u"CA$10.00"},
4325         {u"currency/CAD unit-width-narrow", u"currency/CAD unit-width-narrow", 10, u"$10.00"},
4326         {u"compact-short", u"K", 5000, u"5K"},
4327         {u"compact-long", u"KK", 5000, u"5 thousand"},
4328         {u"compact-short currency/CAD", u"K currency/CAD", 5000, u"CA$5K"},
4329         {u"", u"", 5000, u"5,000"},
4330         {u"group-min2", u",?", 5000, u"5000"},
4331         {u"group-min2", u",?", 15000, u"15,000"},
4332         {u"sign-always", u"+!", 60, u"+60"},
4333         {u"sign-always", u"+!", 0, u"+0"},
4334         {u"sign-except-zero", u"+?", 60, u"+60"},
4335         {u"sign-except-zero", u"+?", 0, u"0"},
4336         {u"sign-accounting currency/CAD", u"() currency/CAD", -40, u"(CA$40.00)"}
4337     };
4338
4339     for (const auto& cas : cases) {
4340         status.setScope(cas.skeleton);
4341         FormattedNumber actual = NumberFormatter::forSkeleton(cas.skeleton, status)
4342             .locale("en-US")
4343             .formatDouble(cas.input, status);
4344         assertEquals(cas.skeleton, cas.expected, actual.toTempString(status));
4345         status.errIfFailureAndReset();
4346         FormattedNumber actualConcise = NumberFormatter::forSkeleton(cas.conciseSkeleton, status)
4347             .locale("en-US")
4348             .formatDouble(cas.input, status);
4349         assertEquals(cas.conciseSkeleton, cas.expected, actualConcise.toTempString(status));
4350         status.errIfFailureAndReset();
4351     }
4352 }
4353
4354 void NumberFormatterApiTest::formatTypes() {
4355     UErrorCode status = U_ZERO_ERROR;
4356     LocalizedNumberFormatter formatter = NumberFormatter::withLocale(Locale::getEnglish());
4357
4358     // Double
4359     assertEquals("Format double", "514.23", formatter.formatDouble(514.23, status).toString(status));
4360
4361     // Int64
4362     assertEquals("Format int64", "51,423", formatter.formatDouble(51423L, status).toString(status));
4363
4364     // decNumber
4365     UnicodeString actual = formatter.formatDecimal("98765432123456789E1", status).toString(status);
4366     assertEquals("Format decNumber", u"987,654,321,234,567,890", actual);
4367
4368     // Also test proper DecimalQuantity bytes storage when all digits are in the fraction.
4369     // The number needs to have exactly 40 digits, which is the size of the default buffer.
4370     // (issue discovered by the address sanitizer in C++)
4371     static const char* str = "0.009876543210987654321098765432109876543211";
4372     actual = formatter.precision(Precision::unlimited()).formatDecimal(str, status).toString(status);
4373     assertEquals("Format decNumber to 40 digits", str, actual);
4374 }
4375
4376 void NumberFormatterApiTest::fieldPositionLogic() {
4377     IcuTestErrorCode status(*this, "fieldPositionLogic");
4378
4379     const char16_t* message = u"Field position logic test";
4380
4381     FormattedNumber fmtd = assertFormatSingle(
4382             message,
4383             u"",
4384             u"",
4385             NumberFormatter::with(),
4386             Locale::getEnglish(),
4387             -9876543210.12,
4388             u"-9,876,543,210.12");
4389
4390     static const UFieldPosition expectedFieldPositions[] = {
4391             // field, begin index, end index
4392             {UNUM_SIGN_FIELD, 0, 1},
4393             {UNUM_GROUPING_SEPARATOR_FIELD, 2, 3},
4394             {UNUM_GROUPING_SEPARATOR_FIELD, 6, 7},
4395             {UNUM_GROUPING_SEPARATOR_FIELD, 10, 11},
4396             {UNUM_INTEGER_FIELD, 1, 14},
4397             {UNUM_DECIMAL_SEPARATOR_FIELD, 14, 15},
4398             {UNUM_FRACTION_FIELD, 15, 17}};
4399
4400     assertNumberFieldPositions(
4401             message,
4402             fmtd,
4403             expectedFieldPositions,
4404             UPRV_LENGTHOF(expectedFieldPositions));
4405
4406     // Test the iteration functionality of nextFieldPosition
4407     ConstrainedFieldPosition actual;
4408     actual.constrainField(UFIELD_CATEGORY_NUMBER, UNUM_GROUPING_SEPARATOR_FIELD);
4409     int32_t i = 1;
4410     while (fmtd.nextPosition(actual, status)) {
4411         UFieldPosition expected = expectedFieldPositions[i++];
4412         assertEquals(
4413                 UnicodeString(u"Next for grouping, field, case #") + Int64ToUnicodeString(i),
4414                 expected.field,
4415                 actual.getField());
4416         assertEquals(
4417                 UnicodeString(u"Next for grouping, begin index, case #") + Int64ToUnicodeString(i),
4418                 expected.beginIndex,
4419                 actual.getStart());
4420         assertEquals(
4421                 UnicodeString(u"Next for grouping, end index, case #") + Int64ToUnicodeString(i),
4422                 expected.endIndex,
4423                 actual.getLimit());
4424     }
4425     assertEquals(u"Should have seen all grouping separators", 4, i);
4426
4427     // Make sure strings without fraction do not contain fraction field
4428     actual.reset();
4429     actual.constrainField(UFIELD_CATEGORY_NUMBER, UNUM_FRACTION_FIELD);
4430     fmtd = NumberFormatter::withLocale("en").formatInt(5, status);
4431     assertFalse(u"No fraction part in an integer", fmtd.nextPosition(actual, status));
4432 }
4433
4434 void NumberFormatterApiTest::fieldPositionCoverage() {
4435     IcuTestErrorCode status(*this, "fieldPositionCoverage");
4436
4437     {
4438         const char16_t* message = u"Measure unit field position basic";
4439         FormattedNumber result = assertFormatSingle(
4440                 message,
4441                 u"measure-unit/temperature-fahrenheit",
4442                 u"unit/fahrenheit",
4443                 NumberFormatter::with().unit(FAHRENHEIT),
4444                 Locale::getEnglish(),
4445                 68,
4446                 u"68°F");
4447         static const UFieldPosition expectedFieldPositions[] = {
4448                 // field, begin index, end index
4449                 {UNUM_INTEGER_FIELD, 0, 2},
4450                 {UNUM_MEASURE_UNIT_FIELD, 2, 4}};
4451         assertNumberFieldPositions(
4452                 message,
4453                 result,
4454                 expectedFieldPositions,
4455                 UPRV_LENGTHOF(expectedFieldPositions));
4456     }
4457
4458     {
4459         const char16_t* message = u"Measure unit field position with compound unit";
4460         FormattedNumber result = assertFormatSingle(
4461                 message,
4462                 u"measure-unit/temperature-fahrenheit per-measure-unit/duration-day",
4463                 u"unit/fahrenheit-per-day",
4464                 NumberFormatter::with().unit(FAHRENHEIT).perUnit(DAY),
4465                 Locale::getEnglish(),
4466                 68,
4467                 u"68°F/d");
4468         static const UFieldPosition expectedFieldPositions[] = {
4469                 // field, begin index, end index
4470                 {UNUM_INTEGER_FIELD, 0, 2},
4471                 // coverage for old enum:
4472                 {DecimalFormat::kMeasureUnitField, 2, 6}};
4473         assertNumberFieldPositions(
4474                 message,
4475                 result,
4476                 expectedFieldPositions,
4477                 UPRV_LENGTHOF(expectedFieldPositions));
4478     }
4479
4480     {
4481         const char16_t* message = u"Measure unit field position with spaces";
4482         FormattedNumber result = assertFormatSingle(
4483                 message,
4484                 u"measure-unit/length-meter unit-width-full-name",
4485                 u"unit/meter unit-width-full-name",
4486                 NumberFormatter::with().unit(METER).unitWidth(UNUM_UNIT_WIDTH_FULL_NAME),
4487                 Locale::getEnglish(),
4488                 68,
4489                 u"68 meters");
4490         static const UFieldPosition expectedFieldPositions[] = {
4491                 // field, begin index, end index
4492                 {UNUM_INTEGER_FIELD, 0, 2},
4493                 // note: field starts after the space
4494                 {UNUM_MEASURE_UNIT_FIELD, 3, 9}};
4495         assertNumberFieldPositions(
4496                 message,
4497                 result,
4498                 expectedFieldPositions,
4499                 UPRV_LENGTHOF(expectedFieldPositions));
4500     }
4501
4502     {
4503         const char16_t* message = u"Measure unit field position with prefix and suffix, composed m/s";
4504         FormattedNumber result = assertFormatSingle(
4505                 message,
4506                 u"measure-unit/length-meter per-measure-unit/duration-second unit-width-full-name",
4507                 u"measure-unit/length-meter per-measure-unit/duration-second unit-width-full-name",
4508                 NumberFormatter::with().unit(METER).perUnit(SECOND).unitWidth(UNUM_UNIT_WIDTH_FULL_NAME),
4509                 "ky", // locale with the interesting data
4510                 68,
4511                 u"секундасына 68 метр");
4512         static const UFieldPosition expectedFieldPositions[] = {
4513                 // field, begin index, end index
4514                 {UNUM_MEASURE_UNIT_FIELD, 0, 11},
4515                 {UNUM_INTEGER_FIELD, 12, 14},
4516                 {UNUM_MEASURE_UNIT_FIELD, 15, 19}};
4517         assertNumberFieldPositions(
4518                 message,
4519                 result,
4520                 expectedFieldPositions,
4521                 UPRV_LENGTHOF(expectedFieldPositions));
4522     }
4523
4524     {
4525         const char16_t* message = u"Measure unit field position with prefix and suffix, built-in m/s";
4526         FormattedNumber result = assertFormatSingle(
4527                 message,
4528                 u"measure-unit/speed-meter-per-second unit-width-full-name",
4529                 u"unit/meter-per-second unit-width-full-name",
4530                 NumberFormatter::with().unit(METER_PER_SECOND).unitWidth(UNUM_UNIT_WIDTH_FULL_NAME),
4531                 "ky", // locale with the interesting data
4532                 68,
4533                 u"секундасына 68 метр");
4534         static const UFieldPosition expectedFieldPositions[] = {
4535                 // field, begin index, end index
4536                 {UNUM_MEASURE_UNIT_FIELD, 0, 11},
4537                 {UNUM_INTEGER_FIELD, 12, 14},
4538                 {UNUM_MEASURE_UNIT_FIELD, 15, 19}};
4539         assertNumberFieldPositions(
4540                 message,
4541                 result,
4542                 expectedFieldPositions,
4543                 UPRV_LENGTHOF(expectedFieldPositions));
4544     }
4545
4546     {
4547         const char16_t* message = u"Measure unit field position with inner spaces";
4548         FormattedNumber result = assertFormatSingle(
4549                 message,
4550                 u"measure-unit/temperature-fahrenheit unit-width-full-name",
4551                 u"unit/fahrenheit unit-width-full-name",
4552                 NumberFormatter::with().unit(FAHRENHEIT).unitWidth(UNUM_UNIT_WIDTH_FULL_NAME),
4553                 "vi", // locale with the interesting data
4554                 68,
4555                 u"68 độ F");
4556         static const UFieldPosition expectedFieldPositions[] = {
4557                 // field, begin index, end index
4558                 {UNUM_INTEGER_FIELD, 0, 2},
4559                 // Should trim leading/trailing spaces, but not inner spaces:
4560                 {UNUM_MEASURE_UNIT_FIELD, 3, 7}};
4561         assertNumberFieldPositions(
4562                 message,
4563                 result,
4564                 expectedFieldPositions,
4565                 UPRV_LENGTHOF(expectedFieldPositions));
4566     }
4567
4568     {
4569         // Data: other{"‎{0} K"} == "\u200E{0} K"
4570         // If that data changes, try to find another example of a non-empty unit prefix/suffix
4571         // that is also all ignorables (whitespace and bidi control marks).
4572         const char16_t* message = u"Measure unit field position with fully ignorable prefix";
4573         FormattedNumber result = assertFormatSingle(
4574                 message,
4575                 u"measure-unit/temperature-kelvin",
4576                 u"unit/kelvin",
4577                 NumberFormatter::with().unit(KELVIN),
4578                 "fa", // locale with the interesting data
4579                 68,
4580                 u"‎۶۸ K");
4581         static const UFieldPosition expectedFieldPositions[] = {
4582                 // field, begin index, end index
4583                 {UNUM_INTEGER_FIELD, 1, 3},
4584                 {UNUM_MEASURE_UNIT_FIELD, 4, 5}};
4585         assertNumberFieldPositions(
4586                 message,
4587                 result,
4588                 expectedFieldPositions,
4589                 UPRV_LENGTHOF(expectedFieldPositions));
4590     }
4591
4592     {
4593         const char16_t* message = u"Compact field basic";
4594         FormattedNumber result = assertFormatSingle(
4595                 message,
4596                 u"compact-short",
4597                 u"K",
4598                 NumberFormatter::with().notation(Notation::compactShort()),
4599                 Locale::getUS(),
4600                 65000,
4601                 u"65K");
4602         static const UFieldPosition expectedFieldPositions[] = {
4603                 // field, begin index, end index
4604                 {UNUM_INTEGER_FIELD, 0, 2},
4605                 {UNUM_COMPACT_FIELD, 2, 3}};
4606         assertNumberFieldPositions(
4607                 message,
4608                 result,
4609                 expectedFieldPositions,
4610                 UPRV_LENGTHOF(expectedFieldPositions));
4611     }
4612
4613     {
4614         const char16_t* message = u"Compact field with spaces";
4615         FormattedNumber result = assertFormatSingle(
4616                 message,
4617                 u"compact-long",
4618                 u"KK",
4619                 NumberFormatter::with().notation(Notation::compactLong()),
4620                 Locale::getUS(),
4621                 65000,
4622                 u"65 thousand");
4623         static const UFieldPosition expectedFieldPositions[] = {
4624                 // field, begin index, end index
4625                 {UNUM_INTEGER_FIELD, 0, 2},
4626                 {UNUM_COMPACT_FIELD, 3, 11}};
4627         assertNumberFieldPositions(
4628                 message,
4629                 result,
4630                 expectedFieldPositions,
4631                 UPRV_LENGTHOF(expectedFieldPositions));
4632     }
4633
4634     {
4635         const char16_t* message = u"Compact field with inner space";
4636         FormattedNumber result = assertFormatSingle(
4637                 message,
4638                 u"compact-long",
4639                 u"KK",
4640                 NumberFormatter::with().notation(Notation::compactLong()),
4641                 "fil",  // locale with interesting data
4642                 6000,
4643                 u"6 na libo");
4644         static const UFieldPosition expectedFieldPositions[] = {
4645                 // field, begin index, end index
4646                 {UNUM_INTEGER_FIELD, 0, 1},
4647                 {UNUM_COMPACT_FIELD, 2, 9}};
4648         assertNumberFieldPositions(
4649                 message,
4650                 result,
4651                 expectedFieldPositions,
4652                 UPRV_LENGTHOF(expectedFieldPositions));
4653     }
4654
4655     {
4656         const char16_t* message = u"Compact field with bidi mark";
4657         FormattedNumber result = assertFormatSingle(
4658                 message,
4659                 u"compact-long",
4660                 u"KK",
4661                 NumberFormatter::with().notation(Notation::compactLong()),
4662                 "he",  // locale with interesting data
4663                 6000,
4664                 u"\u200F6 אלף");
4665         static const UFieldPosition expectedFieldPositions[] = {
4666                 // field, begin index, end index
4667                 {UNUM_INTEGER_FIELD, 1, 2},
4668                 {UNUM_COMPACT_FIELD, 3, 6}};
4669         assertNumberFieldPositions(
4670                 message,
4671                 result,
4672                 expectedFieldPositions,
4673                 UPRV_LENGTHOF(expectedFieldPositions));
4674     }
4675
4676     {
4677         const char16_t* message = u"Compact with currency fields";
4678         FormattedNumber result = assertFormatSingle(
4679                 message,
4680                 u"compact-short currency/USD",
4681                 u"K currency/USD",
4682                 NumberFormatter::with().notation(Notation::compactShort()).unit(USD),
4683                 "sr_Latn",  // locale with interesting data
4684                 65000,
4685                 u"65 hilj. US$");
4686         static const UFieldPosition expectedFieldPositions[] = {
4687                 // field, begin index, end index
4688                 {UNUM_INTEGER_FIELD, 0, 2},
4689                 {UNUM_COMPACT_FIELD, 3, 8},
4690                 {UNUM_CURRENCY_FIELD, 9, 12}};
4691         assertNumberFieldPositions(
4692                 message,
4693                 result,
4694                 expectedFieldPositions,
4695                 UPRV_LENGTHOF(expectedFieldPositions));
4696     }
4697
4698     {
4699         const char16_t* message = u"Currency long name fields";
4700         FormattedNumber result = assertFormatSingle(
4701                 message,
4702                 u"currency/USD unit-width-full-name",
4703                 u"currency/USD unit-width-full-name",
4704                 NumberFormatter::with().unit(USD)
4705                     .unitWidth(UNumberUnitWidth::UNUM_UNIT_WIDTH_FULL_NAME),
4706                 "en",
4707                 12345,
4708                 u"12,345.00 US dollars");
4709         static const UFieldPosition expectedFieldPositions[] = {
4710                 // field, begin index, end index
4711                 {UNUM_GROUPING_SEPARATOR_FIELD, 2, 3},
4712                 {UNUM_INTEGER_FIELD, 0, 6},
4713                 {UNUM_DECIMAL_SEPARATOR_FIELD, 6, 7},
4714                 {UNUM_FRACTION_FIELD, 7, 9},
4715                 {UNUM_CURRENCY_FIELD, 10, 20}};
4716         assertNumberFieldPositions(
4717                 message,
4718                 result,
4719                 expectedFieldPositions,
4720                 UPRV_LENGTHOF(expectedFieldPositions));
4721     }
4722
4723     {
4724         const char16_t* message = u"Compact with measure unit fields";
4725         FormattedNumber result = assertFormatSingle(
4726                 message,
4727                 u"compact-long measure-unit/length-meter unit-width-full-name",
4728                 u"KK unit/meter unit-width-full-name",
4729                 NumberFormatter::with().notation(Notation::compactLong())
4730                     .unit(METER)
4731                     .unitWidth(UNUM_UNIT_WIDTH_FULL_NAME),
4732                 Locale::getUS(),
4733                 65000,
4734                 u"65 thousand meters");
4735         static const UFieldPosition expectedFieldPositions[] = {
4736                 // field, begin index, end index
4737                 {UNUM_INTEGER_FIELD, 0, 2},
4738                 {UNUM_COMPACT_FIELD, 3, 11},
4739                 {UNUM_MEASURE_UNIT_FIELD, 12, 18}};
4740         assertNumberFieldPositions(
4741                 message,
4742                 result,
4743                 expectedFieldPositions,
4744                 UPRV_LENGTHOF(expectedFieldPositions));
4745     }
4746 }
4747
4748 void NumberFormatterApiTest::toFormat() {
4749     IcuTestErrorCode status(*this, "icuFormat");
4750     LocalizedNumberFormatter lnf = NumberFormatter::withLocale("fr")
4751             .precision(Precision::fixedFraction(3));
4752     LocalPointer<Format> format(lnf.toFormat(status), status);
4753     FieldPosition fpos(UNUM_DECIMAL_SEPARATOR_FIELD);
4754     UnicodeString sb;
4755     format->format(514.23, sb, fpos, status);
4756     assertEquals("Should correctly format number", u"514,230", sb);
4757     assertEquals("Should find decimal separator", 3, fpos.getBeginIndex());
4758     assertEquals("Should find end of decimal separator", 4, fpos.getEndIndex());
4759     assertEquals(
4760             "ICU Format should round-trip",
4761             lnf.toSkeleton(status),
4762             dynamic_cast<LocalizedNumberFormatterAsFormat*>(format.getAlias())->getNumberFormatter()
4763                     .toSkeleton(status));
4764
4765     UFormattedNumberData result;
4766     result.quantity.setToDouble(514.23);
4767     lnf.formatImpl(&result, status);
4768     FieldPositionIterator fpi1;
4769     {
4770         FieldPositionIteratorHandler fpih(&fpi1, status);
4771         result.getAllFieldPositions(fpih, status);
4772     }
4773
4774     FieldPositionIterator fpi2;
4775     format->format(514.23, sb.remove(), &fpi2, status);
4776
4777     assertTrue("Should produce same field position iterator", fpi1 == fpi2);
4778 }
4779
4780 void NumberFormatterApiTest::errors() {
4781     LocalizedNumberFormatter lnf = NumberFormatter::withLocale(Locale::getEnglish()).precision(
4782             Precision::fixedFraction(
4783                     -1));
4784
4785     // formatInt
4786     UErrorCode status = U_ZERO_ERROR;
4787     FormattedNumber fn = lnf.formatInt(1, status);
4788     assertEquals(
4789             "Should fail in formatInt method with error code for rounding",
4790             U_NUMBER_ARG_OUTOFBOUNDS_ERROR,
4791             status);
4792
4793     // formatDouble
4794     status = U_ZERO_ERROR;
4795     fn = lnf.formatDouble(1.0, status);
4796     assertEquals(
4797             "Should fail in formatDouble method with error code for rounding",
4798             U_NUMBER_ARG_OUTOFBOUNDS_ERROR,
4799             status);
4800
4801     // formatDecimal (decimal error)
4802     status = U_ZERO_ERROR;
4803     fn = NumberFormatter::withLocale("en").formatDecimal("1x2", status);
4804     assertEquals(
4805             "Should fail in formatDecimal method with error code for decimal number syntax",
4806             U_DECIMAL_NUMBER_SYNTAX_ERROR,
4807             status);
4808
4809     // formatDecimal (setting error)
4810     status = U_ZERO_ERROR;
4811     fn = lnf.formatDecimal("1.0", status);
4812     assertEquals(
4813             "Should fail in formatDecimal method with error code for rounding",
4814             U_NUMBER_ARG_OUTOFBOUNDS_ERROR,
4815             status);
4816
4817     // Skeleton string
4818     status = U_ZERO_ERROR;
4819     UnicodeString output = lnf.toSkeleton(status);
4820     assertEquals(
4821             "Should fail on toSkeleton terminal method with correct error code",
4822             U_NUMBER_ARG_OUTOFBOUNDS_ERROR,
4823             status);
4824     assertTrue(
4825             "Terminal toSkeleton on error object should be bogus",
4826             output.isBogus());
4827
4828     // FieldPosition (constrained category)
4829     status = U_ZERO_ERROR;
4830     ConstrainedFieldPosition fp;
4831     fp.constrainCategory(UFIELD_CATEGORY_NUMBER);
4832     fn.nextPosition(fp, status);
4833     assertEquals(
4834             "Should fail on FieldPosition terminal method with correct error code",
4835             U_NUMBER_ARG_OUTOFBOUNDS_ERROR,
4836             status);
4837
4838     // FieldPositionIterator (no constraints)
4839     status = U_ZERO_ERROR;
4840     fp.reset();
4841     fn.nextPosition(fp, status);
4842     assertEquals(
4843             "Should fail on FieldPositoinIterator terminal method with correct error code",
4844             U_NUMBER_ARG_OUTOFBOUNDS_ERROR,
4845             status);
4846
4847     // Appendable
4848     status = U_ZERO_ERROR;
4849     UnicodeStringAppendable appendable(output.remove());
4850     fn.appendTo(appendable, status);
4851     assertEquals(
4852             "Should fail on Appendable terminal method with correct error code",
4853             U_NUMBER_ARG_OUTOFBOUNDS_ERROR,
4854             status);
4855
4856     // UnicodeString
4857     status = U_ZERO_ERROR;
4858     output = fn.toString(status);
4859     assertEquals(
4860             "Should fail on UnicodeString terminal method with correct error code",
4861             U_NUMBER_ARG_OUTOFBOUNDS_ERROR,
4862             status);
4863     assertTrue(
4864             "Terminal UnicodeString on error object should be bogus",
4865             output.isBogus());
4866
4867     // CopyErrorTo
4868     status = U_ZERO_ERROR;
4869     lnf.copyErrorTo(status);
4870     assertEquals(
4871             "Should fail since rounder is not legal with correct error code",
4872             U_NUMBER_ARG_OUTOFBOUNDS_ERROR,
4873             status);
4874 }
4875
4876 void NumberFormatterApiTest::validRanges() {
4877
4878 #define EXPECTED_MAX_INT_FRAC_SIG 999
4879
4880 #define VALID_RANGE_ASSERT(status, method, lowerBound, argument) UPRV_BLOCK_MACRO_BEGIN { \
4881     UErrorCode expectedStatus = ((lowerBound <= argument) && (argument <= EXPECTED_MAX_INT_FRAC_SIG)) \
4882         ? U_ZERO_ERROR \
4883         : U_NUMBER_ARG_OUTOFBOUNDS_ERROR; \
4884     assertEquals( \
4885         UnicodeString(u"Incorrect status for " #method " on input ") \
4886             + Int64ToUnicodeString(argument), \
4887         expectedStatus, \
4888         status); \
4889 } UPRV_BLOCK_MACRO_END
4890
4891 #define VALID_RANGE_ONEARG(setting, method, lowerBound) UPRV_BLOCK_MACRO_BEGIN { \
4892     for (int32_t argument = -2; argument <= EXPECTED_MAX_INT_FRAC_SIG + 2; argument++) { \
4893         UErrorCode status = U_ZERO_ERROR; \
4894         NumberFormatter::with().setting(method(argument)).copyErrorTo(status); \
4895         VALID_RANGE_ASSERT(status, method, lowerBound, argument); \
4896     } \
4897 } UPRV_BLOCK_MACRO_END
4898
4899 #define VALID_RANGE_TWOARGS(setting, method, lowerBound) UPRV_BLOCK_MACRO_BEGIN { \
4900     for (int32_t argument = -2; argument <= EXPECTED_MAX_INT_FRAC_SIG + 2; argument++) { \
4901         UErrorCode status = U_ZERO_ERROR; \
4902         /* Pass EXPECTED_MAX_INT_FRAC_SIG as the second argument so arg1 <= arg2 in expected cases */ \
4903         NumberFormatter::with().setting(method(argument, EXPECTED_MAX_INT_FRAC_SIG)).copyErrorTo(status); \
4904         VALID_RANGE_ASSERT(status, method, lowerBound, argument); \
4905         status = U_ZERO_ERROR; \
4906         /* Pass lowerBound as the first argument so arg1 <= arg2 in expected cases */ \
4907         NumberFormatter::with().setting(method(lowerBound, argument)).copyErrorTo(status); \
4908         VALID_RANGE_ASSERT(status, method, lowerBound, argument); \
4909         /* Check that first argument must be less than or equal to second argument */ \
4910         NumberFormatter::with().setting(method(argument, argument - 1)).copyErrorTo(status); \
4911         assertEquals("Incorrect status for " #method " on max < min input", \
4912             U_NUMBER_ARG_OUTOFBOUNDS_ERROR, \
4913             status); \
4914     } \
4915 } UPRV_BLOCK_MACRO_END
4916
4917     VALID_RANGE_ONEARG(precision, Precision::fixedFraction, 0);
4918     VALID_RANGE_ONEARG(precision, Precision::minFraction, 0);
4919     VALID_RANGE_ONEARG(precision, Precision::maxFraction, 0);
4920     VALID_RANGE_TWOARGS(precision, Precision::minMaxFraction, 0);
4921     VALID_RANGE_ONEARG(precision, Precision::fixedSignificantDigits, 1);
4922     VALID_RANGE_ONEARG(precision, Precision::minSignificantDigits, 1);
4923     VALID_RANGE_ONEARG(precision, Precision::maxSignificantDigits, 1);
4924     VALID_RANGE_TWOARGS(precision, Precision::minMaxSignificantDigits, 1);
4925     VALID_RANGE_ONEARG(precision, Precision::fixedFraction(1).withMinDigits, 1);
4926     VALID_RANGE_ONEARG(precision, Precision::fixedFraction(1).withMaxDigits, 1);
4927     VALID_RANGE_ONEARG(notation, Notation::scientific().withMinExponentDigits, 1);
4928     VALID_RANGE_ONEARG(integerWidth, IntegerWidth::zeroFillTo, 0);
4929     VALID_RANGE_ONEARG(integerWidth, IntegerWidth::zeroFillTo(0).truncateAt, -1);
4930 }
4931
4932 void NumberFormatterApiTest::copyMove() {
4933     IcuTestErrorCode status(*this, "copyMove");
4934
4935     // Default constructors
4936     LocalizedNumberFormatter l1;
4937     assertEquals("Initial behavior", u"10", l1.formatInt(10, status).toString(status), true);
4938     if (status.errDataIfFailureAndReset()) { return; }
4939     assertEquals("Initial call count", 1, l1.getCallCount());
4940     assertTrue("Initial compiled", l1.getCompiled() == nullptr);
4941
4942     // Setup
4943     l1 = NumberFormatter::withLocale("en").unit(NoUnit::percent()).threshold(3);
4944     assertEquals("Initial behavior", u"10%", l1.formatInt(10, status).toString(status));
4945     assertEquals("Initial call count", 1, l1.getCallCount());
4946     assertTrue("Initial compiled", l1.getCompiled() == nullptr);
4947     l1.formatInt(123, status);
4948     assertEquals("Still not compiled", 2, l1.getCallCount());
4949     assertTrue("Still not compiled", l1.getCompiled() == nullptr);
4950     l1.formatInt(123, status);
4951     assertEquals("Compiled", u"10%", l1.formatInt(10, status).toString(status));
4952     assertEquals("Compiled", INT32_MIN, l1.getCallCount());
4953     assertTrue("Compiled", l1.getCompiled() != nullptr);
4954
4955     // Copy constructor
4956     LocalizedNumberFormatter l2 = l1;
4957     assertEquals("[constructor] Copy behavior", u"10%", l2.formatInt(10, status).toString(status));
4958     assertEquals("[constructor] Copy should not have compiled state", 1, l2.getCallCount());
4959     assertTrue("[constructor] Copy should not have compiled state", l2.getCompiled() == nullptr);
4960
4961     // Move constructor
4962     LocalizedNumberFormatter l3 = std::move(l1);
4963     assertEquals("[constructor] Move behavior", u"10%", l3.formatInt(10, status).toString(status));
4964     assertEquals("[constructor] Move *should* have compiled state", INT32_MIN, l3.getCallCount());
4965     assertTrue("[constructor] Move *should* have compiled state", l3.getCompiled() != nullptr);
4966     assertEquals("[constructor] Source should be reset after move", 0, l1.getCallCount());
4967     assertTrue("[constructor] Source should be reset after move", l1.getCompiled() == nullptr);
4968
4969     // Reset l1 and l2 to check for macro-props copying for behavior testing
4970     // Make the test more interesting: also warm them up with a compiled formatter.
4971     l1 = NumberFormatter::withLocale("en");
4972     l1.formatInt(1, status);
4973     l1.formatInt(1, status);
4974     l1.formatInt(1, status);
4975     l2 = NumberFormatter::withLocale("en");
4976     l2.formatInt(1, status);
4977     l2.formatInt(1, status);
4978     l2.formatInt(1, status);
4979
4980     // Copy assignment
4981     l1 = l3;
4982     assertEquals("[assignment] Copy behavior", u"10%", l1.formatInt(10, status).toString(status));
4983     assertEquals("[assignment] Copy should not have compiled state", 1, l1.getCallCount());
4984     assertTrue("[assignment] Copy should not have compiled state", l1.getCompiled() == nullptr);
4985
4986     // Move assignment
4987     l2 = std::move(l3);
4988     assertEquals("[assignment] Move behavior", u"10%", l2.formatInt(10, status).toString(status));
4989     assertEquals("[assignment] Move *should* have compiled state", INT32_MIN, l2.getCallCount());
4990     assertTrue("[assignment] Move *should* have compiled state", l2.getCompiled() != nullptr);
4991     assertEquals("[assignment] Source should be reset after move", 0, l3.getCallCount());
4992     assertTrue("[assignment] Source should be reset after move", l3.getCompiled() == nullptr);
4993
4994     // Coverage tests for UnlocalizedNumberFormatter
4995     UnlocalizedNumberFormatter u1;
4996     assertEquals("Default behavior", u"10", u1.locale("en").formatInt(10, status).toString(status));
4997     u1 = u1.unit(NoUnit::percent());
4998     assertEquals("Copy assignment", u"10%", u1.locale("en").formatInt(10, status).toString(status));
4999     UnlocalizedNumberFormatter u2 = u1;
5000     assertEquals("Copy constructor", u"10%", u2.locale("en").formatInt(10, status).toString(status));
5001     UnlocalizedNumberFormatter u3 = std::move(u1);
5002     assertEquals("Move constructor", u"10%", u3.locale("en").formatInt(10, status).toString(status));
5003     u1 = NumberFormatter::with();
5004     u1 = std::move(u2);
5005     assertEquals("Move assignment", u"10%", u1.locale("en").formatInt(10, status).toString(status));
5006
5007     // FormattedNumber move operators
5008     FormattedNumber result = l1.formatInt(10, status);
5009     assertEquals("FormattedNumber move constructor", u"10%", result.toString(status));
5010     result = l1.formatInt(20, status);
5011     assertEquals("FormattedNumber move assignment", u"20%", result.toString(status));
5012 }
5013
5014 void NumberFormatterApiTest::localPointerCAPI() {
5015     // NOTE: This is also the sample code in unumberformatter.h
5016     UErrorCode ec = U_ZERO_ERROR;
5017
5018     // Setup:
5019     LocalUNumberFormatterPointer uformatter(unumf_openForSkeletonAndLocale(u"percent", -1, "en", &ec));
5020     LocalUFormattedNumberPointer uresult(unumf_openResult(&ec));
5021     if (!assertSuccess("", ec, true, __FILE__, __LINE__)) { return; }
5022
5023     // Format a decimal number:
5024     unumf_formatDecimal(uformatter.getAlias(), "9.87E-3", -1, uresult.getAlias(), &ec);
5025     if (!assertSuccess("", ec, true, __FILE__, __LINE__)) { return; }
5026
5027     // Get the location of the percent sign:
5028     UFieldPosition ufpos = {UNUM_PERCENT_FIELD, 0, 0};
5029     unumf_resultNextFieldPosition(uresult.getAlias(), &ufpos, &ec);
5030     assertEquals("Percent sign location within '0.00987%'", 7, ufpos.beginIndex);
5031     assertEquals("Percent sign location within '0.00987%'", 8, ufpos.endIndex);
5032
5033     // No need to do any cleanup since we are using LocalPointer.
5034 }
5035
5036 void NumberFormatterApiTest::toObject() {
5037     IcuTestErrorCode status(*this, "toObject");
5038
5039     // const lvalue version
5040     {
5041         LocalizedNumberFormatter lnf = NumberFormatter::withLocale("en")
5042                 .precision(Precision::fixedFraction(2));
5043         LocalPointer<LocalizedNumberFormatter> lnf2(lnf.clone());
5044         assertFalse("should create successfully, const lvalue", lnf2.isNull());
5045         assertEquals("object API test, const lvalue", u"1,000.00",
5046             lnf2->formatDouble(1000, status).toString(status));
5047     }
5048
5049     // rvalue reference version
5050     {
5051         LocalPointer<LocalizedNumberFormatter> lnf(
5052             NumberFormatter::withLocale("en")
5053                 .precision(Precision::fixedFraction(2))
5054                 .clone());
5055         assertFalse("should create successfully, rvalue reference", lnf.isNull());
5056         assertEquals("object API test, rvalue reference", u"1,000.00",
5057             lnf->formatDouble(1000, status).toString(status));
5058     }
5059
5060     // to std::unique_ptr via constructor
5061     {
5062         std::unique_ptr<LocalizedNumberFormatter> lnf(
5063             NumberFormatter::withLocale("en")
5064                 .precision(Precision::fixedFraction(2))
5065                 .clone());
5066         assertTrue("should create successfully, unique_ptr", static_cast<bool>(lnf));
5067         assertEquals("object API test, unique_ptr", u"1,000.00",
5068             lnf->formatDouble(1000, status).toString(status));
5069     }
5070
5071     // to std::unique_ptr via assignment
5072     {
5073         std::unique_ptr<LocalizedNumberFormatter> lnf =
5074             NumberFormatter::withLocale("en")
5075                 .precision(Precision::fixedFraction(2))
5076                 .clone();
5077         assertTrue("should create successfully, unique_ptr B", static_cast<bool>(lnf));
5078         assertEquals("object API test, unique_ptr B", u"1,000.00",
5079             lnf->formatDouble(1000, status).toString(status));
5080     }
5081
5082     // to LocalPointer via assignment
5083     {
5084         LocalPointer<UnlocalizedNumberFormatter> f =
5085             NumberFormatter::with().clone();
5086     }
5087
5088     // make sure no memory leaks
5089     {
5090         NumberFormatter::with().clone();
5091     }
5092 }
5093
5094 void NumberFormatterApiTest::toDecimalNumber() {
5095     IcuTestErrorCode status(*this, "toDecimalNumber");
5096     FormattedNumber fn = NumberFormatter::withLocale("bn-BD")
5097         .scale(Scale::powerOfTen(2))
5098         .precision(Precision::maxSignificantDigits(5))
5099         .formatDouble(9.87654321e12, status);
5100     assertEquals("Should have expected localized string result",
5101         u"৯৮,৭৬,৫০,০০,০০,০০,০০০", fn.toString(status));
5102     assertEquals(u"Should have expected toDecimalNumber string result",
5103         "9.8765E+14", fn.toDecimalNumber<std::string>(status).c_str());
5104 }
5105
5106 void NumberFormatterApiTest::microPropsInternals() {
5107     // Verify copy construction and assignment operators.
5108     int64_t testValues[2] = {4, 61};
5109
5110     MicroProps mp;
5111     assertEquals("capacity", 2, mp.mixedMeasures.getCapacity());
5112     mp.mixedMeasures[0] = testValues[0];
5113     mp.mixedMeasures[1] = testValues[1];
5114     MicroProps copyConstructed(mp);
5115     MicroProps copyAssigned;
5116     int64_t *resizeResult = mp.mixedMeasures.resize(4, 4);
5117     assertTrue("Resize success", resizeResult != NULL);
5118     copyAssigned = mp;
5119
5120     assertTrue("MicroProps success status", U_SUCCESS(mp.mixedMeasures.status));
5121     assertTrue("Copy Constructed success status", U_SUCCESS(copyConstructed.mixedMeasures.status));
5122     assertTrue("Copy Assigned success status", U_SUCCESS(copyAssigned.mixedMeasures.status));
5123     assertEquals("Original values[0]", testValues[0], mp.mixedMeasures[0]);
5124     assertEquals("Original values[1]", testValues[1], mp.mixedMeasures[1]);
5125     assertEquals("Copy Constructed[0]", testValues[0], copyConstructed.mixedMeasures[0]);
5126     assertEquals("Copy Constructed[1]", testValues[1], copyConstructed.mixedMeasures[1]);
5127     assertEquals("Copy Assigned[0]", testValues[0], copyAssigned.mixedMeasures[0]);
5128     assertEquals("Copy Assigned[1]", testValues[1], copyAssigned.mixedMeasures[1]);
5129     assertEquals("Original capacity", 4, mp.mixedMeasures.getCapacity());
5130     assertEquals("Copy Constructed capacity", 2, copyConstructed.mixedMeasures.getCapacity());
5131     assertEquals("Copy Assigned capacity", 4, copyAssigned.mixedMeasures.getCapacity());
5132 }
5133
5134 /* For skeleton comparisons: this checks the toSkeleton output for `f` and for
5135  * `conciseSkeleton` against the normalized version of `uskeleton` - this does
5136  * not round-trip uskeleton itself.
5137  *
5138  * If `conciseSkeleton` starts with a "~", its round-trip check is skipped.
5139  *
5140  * If `uskeleton` is nullptr, toSkeleton is expected to return an
5141  * U_UNSUPPORTED_ERROR.
5142  */
5143 void NumberFormatterApiTest::assertFormatDescending(
5144         const char16_t* umessage,
5145         const char16_t* uskeleton,
5146         const char16_t* conciseSkeleton,
5147         const UnlocalizedNumberFormatter& f,
5148         Locale locale,
5149         ...) {
5150     va_list args;
5151     va_start(args, locale);
5152     UnicodeString message(TRUE, umessage, -1);
5153     static double inputs[] = {87650, 8765, 876.5, 87.65, 8.765, 0.8765, 0.08765, 0.008765, 0};
5154     const LocalizedNumberFormatter l1 = f.threshold(0).locale(locale); // no self-regulation
5155     const LocalizedNumberFormatter l2 = f.threshold(1).locale(locale); // all self-regulation
5156     IcuTestErrorCode status(*this, "assertFormatDescending");
5157     status.setScope(message);
5158     UnicodeString expecteds[10];
5159     for (int16_t i = 0; i < 9; i++) {
5160         char16_t caseNumber = u'0' + i;
5161         double d = inputs[i];
5162         UnicodeString expected = va_arg(args, const char16_t*);
5163         expecteds[i] = expected;
5164         UnicodeString actual1 = l1.formatDouble(d, status).toString(status);
5165         assertSuccess(message + u": Unsafe Path: " + caseNumber, status);
5166         assertEquals(message + u": Unsafe Path: " + caseNumber, expected, actual1);
5167         UnicodeString actual2 = l2.formatDouble(d, status).toString(status);
5168         assertSuccess(message + u": Safe Path: " + caseNumber, status);
5169         assertEquals(message + u": Safe Path: " + caseNumber, expected, actual2);
5170     }
5171     if (uskeleton != nullptr) { // if null, skeleton is declared as undefined.
5172         UnicodeString skeleton(TRUE, uskeleton, -1);
5173         // Only compare normalized skeletons: the tests need not provide the normalized forms.
5174         // Use the normalized form to construct the testing formatter to guarantee no loss of info.
5175         UnicodeString normalized = NumberFormatter::forSkeleton(skeleton, status).toSkeleton(status);
5176         assertEquals(message + ": Skeleton:", normalized, f.toSkeleton(status));
5177         LocalizedNumberFormatter l3 = NumberFormatter::forSkeleton(normalized, status).locale(locale);
5178         for (int32_t i = 0; i < 9; i++) {
5179             double d = inputs[i];
5180             UnicodeString actual3 = l3.formatDouble(d, status).toString(status);
5181             assertEquals(message + ": Skeleton Path: '" + normalized + "': " + d, expecteds[i], actual3);
5182         }
5183         // Concise skeletons should have same output, and usually round-trip to the normalized skeleton.
5184         // If the concise skeleton starts with '~', disable the round-trip check.
5185         bool shouldRoundTrip = true;
5186         if (conciseSkeleton[0] == u'~') {
5187             conciseSkeleton++;
5188             shouldRoundTrip = false;
5189         }
5190         LocalizedNumberFormatter l4 = NumberFormatter::forSkeleton(conciseSkeleton, status).locale(locale);
5191         if (shouldRoundTrip) {
5192             assertEquals(message + ": Concise Skeleton:", normalized, l4.toSkeleton(status));
5193         }
5194         for (int32_t i = 0; i < 9; i++) {
5195             double d = inputs[i];
5196             UnicodeString actual4 = l4.formatDouble(d, status).toString(status);
5197             assertEquals(message + ": Concise Skeleton Path: '" + normalized + "': " + d, expecteds[i], actual4);
5198         }
5199     } else {
5200         assertUndefinedSkeleton(f);
5201     }
5202 }
5203
5204 /* For skeleton comparisons: this checks the toSkeleton output for `f` and for
5205  * `conciseSkeleton` against the normalized version of `uskeleton` - this does
5206  * not round-trip uskeleton itself.
5207  *
5208  * If `conciseSkeleton` starts with a "~", its round-trip check is skipped.
5209  *
5210  * If `uskeleton` is nullptr, toSkeleton is expected to return an
5211  * U_UNSUPPORTED_ERROR.
5212  */
5213 void NumberFormatterApiTest::assertFormatDescendingBig(
5214         const char16_t* umessage,
5215         const char16_t* uskeleton,
5216         const char16_t* conciseSkeleton,
5217         const UnlocalizedNumberFormatter& f,
5218         Locale locale,
5219         ...) {
5220     va_list args;
5221     va_start(args, locale);
5222     UnicodeString message(TRUE, umessage, -1);
5223     static double inputs[] = {87650000, 8765000, 876500, 87650, 8765, 876.5, 87.65, 8.765, 0};
5224     const LocalizedNumberFormatter l1 = f.threshold(0).locale(locale); // no self-regulation
5225     const LocalizedNumberFormatter l2 = f.threshold(1).locale(locale); // all self-regulation
5226     IcuTestErrorCode status(*this, "assertFormatDescendingBig");
5227     status.setScope(message);
5228     UnicodeString expecteds[10];
5229     for (int16_t i = 0; i < 9; i++) {
5230         char16_t caseNumber = u'0' + i;
5231         double d = inputs[i];
5232         UnicodeString expected = va_arg(args, const char16_t*);
5233         expecteds[i] = expected;
5234         UnicodeString actual1 = l1.formatDouble(d, status).toString(status);
5235         assertSuccess(message + u": Unsafe Path: " + caseNumber, status);
5236         assertEquals(message + u": Unsafe Path: " + caseNumber, expected, actual1);
5237         UnicodeString actual2 = l2.formatDouble(d, status).toString(status);
5238         assertSuccess(message + u": Safe Path: " + caseNumber, status);
5239         assertEquals(message + u": Safe Path: " + caseNumber, expected, actual2);
5240     }
5241     if (uskeleton != nullptr) { // if null, skeleton is declared as undefined.
5242         UnicodeString skeleton(TRUE, uskeleton, -1);
5243         // Only compare normalized skeletons: the tests need not provide the normalized forms.
5244         // Use the normalized form to construct the testing formatter to guarantee no loss of info.
5245         UnicodeString normalized = NumberFormatter::forSkeleton(skeleton, status).toSkeleton(status);
5246         assertEquals(message + ": Skeleton:", normalized, f.toSkeleton(status));
5247         LocalizedNumberFormatter l3 = NumberFormatter::forSkeleton(normalized, status).locale(locale);
5248         for (int32_t i = 0; i < 9; i++) {
5249             double d = inputs[i];
5250             UnicodeString actual3 = l3.formatDouble(d, status).toString(status);
5251             assertEquals(message + ": Skeleton Path: '" + normalized + "': " + d, expecteds[i], actual3);
5252         }
5253         // Concise skeletons should have same output, and usually round-trip to the normalized skeleton.
5254         // If the concise skeleton starts with '~', disable the round-trip check.
5255         bool shouldRoundTrip = true;
5256         if (conciseSkeleton[0] == u'~') {
5257             conciseSkeleton++;
5258             shouldRoundTrip = false;
5259         }
5260         LocalizedNumberFormatter l4 = NumberFormatter::forSkeleton(conciseSkeleton, status).locale(locale);
5261         if (shouldRoundTrip) {
5262             assertEquals(message + ": Concise Skeleton:", normalized, l4.toSkeleton(status));
5263         }
5264         for (int32_t i = 0; i < 9; i++) {
5265             double d = inputs[i];
5266             UnicodeString actual4 = l4.formatDouble(d, status).toString(status);
5267             assertEquals(message + ": Concise Skeleton Path: '" + normalized + "': " + d, expecteds[i], actual4);
5268         }
5269     } else {
5270         assertUndefinedSkeleton(f);
5271     }
5272 }
5273
5274 /* For skeleton comparisons: this checks the toSkeleton output for `f` and for
5275  * `conciseSkeleton` against the normalized version of `uskeleton` - this does
5276  * not round-trip uskeleton itself.
5277  *
5278  * If `conciseSkeleton` starts with a "~", its round-trip check is skipped.
5279  *
5280  * If `uskeleton` is nullptr, toSkeleton is expected to return an
5281  * U_UNSUPPORTED_ERROR.
5282  */
5283 FormattedNumber
5284 NumberFormatterApiTest::assertFormatSingle(
5285         const char16_t* umessage,
5286         const char16_t* uskeleton,
5287         const char16_t* conciseSkeleton,
5288         const UnlocalizedNumberFormatter& f,
5289         Locale locale,
5290         double input,
5291         const UnicodeString& expected) {
5292     UnicodeString message(TRUE, umessage, -1);
5293     const LocalizedNumberFormatter l1 = f.threshold(0).locale(locale); // no self-regulation
5294     const LocalizedNumberFormatter l2 = f.threshold(1).locale(locale); // all self-regulation
5295     IcuTestErrorCode status(*this, "assertFormatSingle");
5296     status.setScope(message);
5297     FormattedNumber result1 = l1.formatDouble(input, status);
5298     UnicodeString actual1 = result1.toString(status);
5299     assertSuccess(message + u": Unsafe Path", status);
5300     assertEquals(message + u": Unsafe Path", expected, actual1);
5301     UnicodeString actual2 = l2.formatDouble(input, status).toString(status);
5302     assertSuccess(message + u": Safe Path", status);
5303     assertEquals(message + u": Safe Path", expected, actual2);
5304     if (uskeleton != nullptr) { // if null, skeleton is declared as undefined.
5305         UnicodeString skeleton(TRUE, uskeleton, -1);
5306         // Only compare normalized skeletons: the tests need not provide the normalized forms.
5307         // Use the normalized form to construct the testing formatter to ensure no loss of info.
5308         UnicodeString normalized = NumberFormatter::forSkeleton(skeleton, status).toSkeleton(status);
5309         assertEquals(message + ": Skeleton:", normalized, f.toSkeleton(status));
5310         LocalizedNumberFormatter l3 = NumberFormatter::forSkeleton(normalized, status).locale(locale);
5311         UnicodeString actual3 = l3.formatDouble(input, status).toString(status);
5312         assertEquals(message + ": Skeleton Path: '" + normalized + "': " + input, expected, actual3);
5313         // Concise skeletons should have same output, and usually round-trip to the normalized skeleton.
5314         // If the concise skeleton starts with '~', disable the round-trip check.
5315         bool shouldRoundTrip = true;
5316         if (conciseSkeleton[0] == u'~') {
5317             conciseSkeleton++;
5318             shouldRoundTrip = false;
5319         }
5320         LocalizedNumberFormatter l4 = NumberFormatter::forSkeleton(conciseSkeleton, status).locale(locale);
5321         if (shouldRoundTrip) {
5322             assertEquals(message + ": Concise Skeleton:", normalized, l4.toSkeleton(status));
5323         }
5324         UnicodeString actual4 = l4.formatDouble(input, status).toString(status);
5325         assertEquals(message + ": Concise Skeleton Path: '" + normalized + "': " + input, expected, actual4);
5326     } else {
5327         assertUndefinedSkeleton(f);
5328     }
5329     return result1;
5330 }
5331
5332 void NumberFormatterApiTest::assertUndefinedSkeleton(const UnlocalizedNumberFormatter& f) {
5333     UErrorCode status = U_ZERO_ERROR;
5334     UnicodeString skeleton = f.toSkeleton(status);
5335     assertEquals(
5336             u"Expect toSkeleton to fail, but passed, producing: " + skeleton,
5337             U_UNSUPPORTED_ERROR,
5338             status);
5339 }
5340
5341 void NumberFormatterApiTest::assertNumberFieldPositions(
5342         const char16_t* message,
5343         const FormattedNumber& formattedNumber,
5344         const UFieldPosition* expectedFieldPositions,
5345         int32_t length) {
5346     IcuTestErrorCode status(*this, "assertNumberFieldPositions");
5347
5348     // Check FormattedValue functions
5349     checkFormattedValue(
5350         message,
5351         static_cast<const FormattedValue&>(formattedNumber),
5352         formattedNumber.toString(status),
5353         UFIELD_CATEGORY_NUMBER,
5354         expectedFieldPositions,
5355         length);
5356 }
5357
5358
5359 #endif /* #if !UCONFIG_NO_FORMATTING */