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