]> git.saurik.com Git - apple/icu.git/blob - icuSources/test/intltest/numbertest_api.cpp
8d6fe87fd07e7c1314180c0df30a91c49f0d06d4
[apple/icu.git] / icuSources / test / intltest / numbertest_api.cpp
1 // © 2017 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3
4 #include "unicode/utypes.h"
5
6 #if !UCONFIG_NO_FORMATTING
7
8 #include "charstr.h"
9 #include <cstdarg>
10 #include <cmath>
11 #include <memory>
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...
21 // (Also affects numbertest_range.cpp)
22 UErrorCode globalNumberFormatterApiTestStatus = U_ZERO_ERROR;
23
24 NumberFormatterApiTest::NumberFormatterApiTest()
25 : NumberFormatterApiTest(globalNumberFormatterApiTestStatus) {
26 }
27
28 NumberFormatterApiTest::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),
35 RON(u"RON", status),
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
62 void 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);
74 if (!quick) {
75 // Slow test: run in exhaustive mode only
76 TESTCASE_AUTO(percentParity);
77 }
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);
93 TESTCASE_AUTO(fieldPositionLogic);
94 TESTCASE_AUTO(fieldPositionCoverage);
95 TESTCASE_AUTO(toFormat);
96 TESTCASE_AUTO(errors);
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 }
102 TESTCASE_AUTO(copyMove);
103 TESTCASE_AUTO(localPointerCAPI);
104 TESTCASE_AUTO(toObject);
105 TESTCASE_AUTO_END;
106 }
107
108 void 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
149 void 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
220 void 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
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
434 // NOTE: There is no API for compact custom data in C++
435 // and thus no "Compact Somali No Figure" test
436 }
437
438 void NumberFormatterApiTest::unitMeasure() {
439 assertFormatDescending(
440 u"Meters Short and unit() method",
441 u"measure-unit/length-meter",
442 NumberFormatter::with().unit(MeasureUnit::getMeter()),
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
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
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");
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");
592 }
593
594 void 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
641 void 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,
783 u"444,444$55 \u200B");
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");
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");
800 }
801
802 void 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
850 void 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
877 void 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
954 void 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
1022 void 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
1100 void 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
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
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
1257 void 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
1348 // NOTE: Hungarian is interesting because it has minimumGroupingDigits=4 in locale data
1349 // If this test breaks due to data changes, find another locale that has minimumGroupingDigits.
1350 assertFormatDescendingBig(
1351 u"Hungarian Grouping",
1352 u"group-auto",
1353 NumberFormatter::with().grouping(UNUM_GROUPING_AUTO),
1354 Locale("hu"),
1355 u"87 650 000",
1356 u"8 765 000",
1357 u"876500",
1358 u"87650",
1359 u"8765",
1360 u"876,5",
1361 u"87,65",
1362 u"8,765",
1363 u"0");
1364
1365 assertFormatDescendingBig(
1366 u"Hungarian Grouping, Min 2",
1367 u"group-min2",
1368 NumberFormatter::with().grouping(UNUM_GROUPING_MIN2),
1369 Locale("hu"),
1370 u"87 650 000",
1371 u"8 765 000",
1372 u"876500",
1373 u"87650",
1374 u"8765",
1375 u"876,5",
1376 u"87,65",
1377 u"8,765",
1378 u"0");
1379
1380 assertFormatDescendingBig(
1381 u"Hungarian Grouping, Always",
1382 u"group-on-aligned",
1383 NumberFormatter::with().grouping(UNUM_GROUPING_ON_ALIGNED),
1384 Locale("hu"),
1385 u"87 650 000",
1386 u"8 765 000",
1387 u"876 500",
1388 u"87 650",
1389 u"8 765",
1390 u"876,5",
1391 u"87,65",
1392 u"8,765",
1393 u"0");
1394
1395 // NOTE: Bulgarian is interesting because it has no grouping in the default currency format.
1396 // If this test breaks due to data changes, find another locale that has no default grouping.
1397 assertFormatDescendingBig(
1398 u"Bulgarian Currency Grouping",
1399 u"currency/USD group-auto",
1400 NumberFormatter::with().grouping(UNUM_GROUPING_AUTO).unit(USD),
1401 Locale("bg"),
1402 u"87650000,00 щ.д.",
1403 u"8765000,00 щ.д.",
1404 u"876500,00 щ.д.",
1405 u"87650,00 щ.д.",
1406 u"8765,00 щ.д.",
1407 u"876,50 щ.д.",
1408 u"87,65 щ.д.",
1409 u"8,76 щ.д.",
1410 u"0,00 щ.д.");
1411
1412 assertFormatDescendingBig(
1413 u"Bulgarian Currency Grouping, Always",
1414 u"currency/USD group-on-aligned",
1415 NumberFormatter::with().grouping(UNUM_GROUPING_ON_ALIGNED).unit(USD),
1416 Locale("bg"),
1417 u"87 650 000,00 щ.д.",
1418 u"8 765 000,00 щ.д.",
1419 u"876 500,00 щ.д.",
1420 u"87 650,00 щ.д.",
1421 u"8 765,00 щ.д.",
1422 u"876,50 щ.д.",
1423 u"87,65 щ.д.",
1424 u"8,76 щ.д.",
1425 u"0,00 щ.д.");
1426
1427 MacroProps macros;
1428 macros.grouper = Grouper(4, 1, 3, UNUM_GROUPING_COUNT);
1429 assertFormatDescendingBig(
1430 u"Custom Grouping via Internal API",
1431 nullptr,
1432 NumberFormatter::with().macros(macros),
1433 Locale::getEnglish(),
1434 u"8,7,6,5,0000",
1435 u"8,7,6,5000",
1436 u"876500",
1437 u"87650",
1438 u"8765",
1439 u"876.5",
1440 u"87.65",
1441 u"8.765",
1442 u"0");
1443 }
1444
1445 void NumberFormatterApiTest::padding() {
1446 assertFormatDescending(
1447 u"Padding",
1448 nullptr,
1449 NumberFormatter::with().padding(Padder::none()),
1450 Locale::getEnglish(),
1451 u"87,650",
1452 u"8,765",
1453 u"876.5",
1454 u"87.65",
1455 u"8.765",
1456 u"0.8765",
1457 u"0.08765",
1458 u"0.008765",
1459 u"0");
1460
1461 assertFormatDescending(
1462 u"Padding",
1463 nullptr,
1464 NumberFormatter::with().padding(
1465 Padder::codePoints(
1466 '*', 8, PadPosition::UNUM_PAD_AFTER_PREFIX)),
1467 Locale::getEnglish(),
1468 u"**87,650",
1469 u"***8,765",
1470 u"***876.5",
1471 u"***87.65",
1472 u"***8.765",
1473 u"**0.8765",
1474 u"*0.08765",
1475 u"0.008765",
1476 u"*******0");
1477
1478 assertFormatDescending(
1479 u"Padding with code points",
1480 nullptr,
1481 NumberFormatter::with().padding(
1482 Padder::codePoints(
1483 0x101E4, 8, PadPosition::UNUM_PAD_AFTER_PREFIX)),
1484 Locale::getEnglish(),
1485 u"𐇤𐇤87,650",
1486 u"𐇤𐇤𐇤8,765",
1487 u"𐇤𐇤𐇤876.5",
1488 u"𐇤𐇤𐇤87.65",
1489 u"𐇤𐇤𐇤8.765",
1490 u"𐇤𐇤0.8765",
1491 u"𐇤0.08765",
1492 u"0.008765",
1493 u"𐇤𐇤𐇤𐇤𐇤𐇤𐇤0");
1494
1495 assertFormatDescending(
1496 u"Padding with wide digits",
1497 nullptr,
1498 NumberFormatter::with().padding(
1499 Padder::codePoints(
1500 '*', 8, PadPosition::UNUM_PAD_AFTER_PREFIX))
1501 .adoptSymbols(new NumberingSystem(MATHSANB)),
1502 Locale::getEnglish(),
1503 u"**𝟴𝟳,𝟲𝟱𝟬",
1504 u"***𝟴,𝟳𝟲𝟱",
1505 u"***𝟴𝟳𝟲.𝟱",
1506 u"***𝟴𝟳.𝟲𝟱",
1507 u"***𝟴.𝟳𝟲𝟱",
1508 u"**𝟬.𝟴𝟳𝟲𝟱",
1509 u"*𝟬.𝟬𝟴𝟳𝟲𝟱",
1510 u"𝟬.𝟬𝟬𝟴𝟳𝟲𝟱",
1511 u"*******𝟬");
1512
1513 assertFormatDescending(
1514 u"Padding with currency spacing",
1515 nullptr,
1516 NumberFormatter::with().padding(
1517 Padder::codePoints(
1518 '*', 10, PadPosition::UNUM_PAD_AFTER_PREFIX))
1519 .unit(GBP)
1520 .unitWidth(UNumberUnitWidth::UNUM_UNIT_WIDTH_ISO_CODE),
1521 Locale::getEnglish(),
1522 u"GBP 87,650.00",
1523 u"GBP 8,765.00",
1524 u"GBP*876.50",
1525 u"GBP**87.65",
1526 u"GBP***8.76",
1527 u"GBP***0.88",
1528 u"GBP***0.09",
1529 u"GBP***0.01",
1530 u"GBP***0.00");
1531
1532 assertFormatSingle(
1533 u"Pad Before Prefix",
1534 nullptr,
1535 NumberFormatter::with().padding(
1536 Padder::codePoints(
1537 '*', 8, PadPosition::UNUM_PAD_BEFORE_PREFIX)),
1538 Locale::getEnglish(),
1539 -88.88,
1540 u"**-88.88");
1541
1542 assertFormatSingle(
1543 u"Pad After Prefix",
1544 nullptr,
1545 NumberFormatter::with().padding(
1546 Padder::codePoints(
1547 '*', 8, PadPosition::UNUM_PAD_AFTER_PREFIX)),
1548 Locale::getEnglish(),
1549 -88.88,
1550 u"-**88.88");
1551
1552 assertFormatSingle(
1553 u"Pad Before Suffix",
1554 nullptr,
1555 NumberFormatter::with().padding(
1556 Padder::codePoints(
1557 '*', 8, PadPosition::UNUM_PAD_BEFORE_SUFFIX)).unit(NoUnit::percent()),
1558 Locale::getEnglish(),
1559 88.88,
1560 u"88.88**%");
1561
1562 assertFormatSingle(
1563 u"Pad After Suffix",
1564 nullptr,
1565 NumberFormatter::with().padding(
1566 Padder::codePoints(
1567 '*', 8, PadPosition::UNUM_PAD_AFTER_SUFFIX)).unit(NoUnit::percent()),
1568 Locale::getEnglish(),
1569 88.88,
1570 u"88.88%**");
1571
1572 assertFormatSingle(
1573 u"Currency Spacing with Zero Digit Padding Broken",
1574 nullptr,
1575 NumberFormatter::with().padding(
1576 Padder::codePoints(
1577 '0', 12, PadPosition::UNUM_PAD_AFTER_PREFIX))
1578 .unit(GBP)
1579 .unitWidth(UNumberUnitWidth::UNUM_UNIT_WIDTH_ISO_CODE),
1580 Locale::getEnglish(),
1581 514.23,
1582 u"GBP 000514.23"); // TODO: This is broken; it renders too wide (13 instead of 12).
1583 }
1584
1585 void NumberFormatterApiTest::integerWidth() {
1586 assertFormatDescending(
1587 u"Integer Width Default",
1588 u"integer-width/+0",
1589 NumberFormatter::with().integerWidth(IntegerWidth::zeroFillTo(1)),
1590 Locale::getEnglish(),
1591 u"87,650",
1592 u"8,765",
1593 u"876.5",
1594 u"87.65",
1595 u"8.765",
1596 u"0.8765",
1597 u"0.08765",
1598 u"0.008765",
1599 u"0");
1600
1601 assertFormatDescending(
1602 u"Integer Width Zero Fill 0",
1603 u"integer-width/+",
1604 NumberFormatter::with().integerWidth(IntegerWidth::zeroFillTo(0)),
1605 Locale::getEnglish(),
1606 u"87,650",
1607 u"8,765",
1608 u"876.5",
1609 u"87.65",
1610 u"8.765",
1611 u".8765",
1612 u".08765",
1613 u".008765",
1614 u""); // TODO: Avoid the empty string here?
1615
1616 assertFormatDescending(
1617 u"Integer Width Zero Fill 3",
1618 u"integer-width/+000",
1619 NumberFormatter::with().integerWidth(IntegerWidth::zeroFillTo(3)),
1620 Locale::getEnglish(),
1621 u"87,650",
1622 u"8,765",
1623 u"876.5",
1624 u"087.65",
1625 u"008.765",
1626 u"000.8765",
1627 u"000.08765",
1628 u"000.008765",
1629 u"000");
1630
1631 assertFormatDescending(
1632 u"Integer Width Max 3",
1633 u"integer-width/##0",
1634 NumberFormatter::with().integerWidth(IntegerWidth::zeroFillTo(1).truncateAt(3)),
1635 Locale::getEnglish(),
1636 u"650",
1637 u"765",
1638 u"876.5",
1639 u"87.65",
1640 u"8.765",
1641 u"0.8765",
1642 u"0.08765",
1643 u"0.008765",
1644 u"0");
1645
1646 assertFormatDescending(
1647 u"Integer Width Fixed 2",
1648 u"integer-width/00",
1649 NumberFormatter::with().integerWidth(IntegerWidth::zeroFillTo(2).truncateAt(2)),
1650 Locale::getEnglish(),
1651 u"50",
1652 u"65",
1653 u"76.5",
1654 u"87.65",
1655 u"08.765",
1656 u"00.8765",
1657 u"00.08765",
1658 u"00.008765",
1659 u"00");
1660
1661 assertFormatSingle(
1662 u"Integer Width Remove All A",
1663 u"integer-width/00",
1664 NumberFormatter::with().integerWidth(IntegerWidth::zeroFillTo(2).truncateAt(2)),
1665 "en",
1666 2500,
1667 u"00");
1668
1669 assertFormatSingle(
1670 u"Integer Width Remove All B",
1671 u"integer-width/00",
1672 NumberFormatter::with().integerWidth(IntegerWidth::zeroFillTo(2).truncateAt(2)),
1673 "en",
1674 25000,
1675 u"00");
1676
1677 assertFormatSingle(
1678 u"Integer Width Remove All B, Bytes Mode",
1679 u"integer-width/00",
1680 NumberFormatter::with().integerWidth(IntegerWidth::zeroFillTo(2).truncateAt(2)),
1681 "en",
1682 // Note: this double produces all 17 significant digits
1683 10000000000000002000.0,
1684 u"00");
1685 }
1686
1687 void NumberFormatterApiTest::symbols() {
1688 assertFormatDescending(
1689 u"French Symbols with Japanese Data 1",
1690 nullptr,
1691 NumberFormatter::with().symbols(FRENCH_SYMBOLS),
1692 Locale::getJapan(),
1693 u"87\u202F650",
1694 u"8\u202F765",
1695 u"876,5",
1696 u"87,65",
1697 u"8,765",
1698 u"0,8765",
1699 u"0,08765",
1700 u"0,008765",
1701 u"0");
1702
1703 assertFormatSingle(
1704 u"French Symbols with Japanese Data 2",
1705 nullptr,
1706 NumberFormatter::with().notation(Notation::compactShort()).symbols(FRENCH_SYMBOLS),
1707 Locale::getJapan(),
1708 12345,
1709 u"1,2\u4E07");
1710
1711 assertFormatDescending(
1712 u"Latin Numbering System with Arabic Data",
1713 u"currency/USD latin",
1714 NumberFormatter::with().adoptSymbols(new NumberingSystem(LATN)).unit(USD),
1715 Locale("ar"),
1716 u"US$ 87,650.00",
1717 u"US$ 8,765.00",
1718 u"US$ 876.50",
1719 u"US$ 87.65",
1720 u"US$ 8.76",
1721 u"US$ 0.88",
1722 u"US$ 0.09",
1723 u"US$ 0.01",
1724 u"US$ 0.00");
1725
1726 assertFormatDescending(
1727 u"Math Numbering System with French Data",
1728 u"numbering-system/mathsanb",
1729 NumberFormatter::with().adoptSymbols(new NumberingSystem(MATHSANB)),
1730 Locale::getFrench(),
1731 u"𝟴𝟳\u202F𝟲𝟱𝟬",
1732 u"𝟴\u202F𝟳𝟲𝟱",
1733 u"𝟴𝟳𝟲,𝟱",
1734 u"𝟴𝟳,𝟲𝟱",
1735 u"𝟴,𝟳𝟲𝟱",
1736 u"𝟬,𝟴𝟳𝟲𝟱",
1737 u"𝟬,𝟬𝟴𝟳𝟲𝟱",
1738 u"𝟬,𝟬𝟬𝟴𝟳𝟲𝟱",
1739 u"𝟬");
1740
1741 assertFormatSingle(
1742 u"Swiss Symbols (used in documentation)",
1743 nullptr,
1744 NumberFormatter::with().symbols(SWISS_SYMBOLS),
1745 Locale::getEnglish(),
1746 12345.67,
1747 u"12’345.67");
1748
1749 assertFormatSingle(
1750 u"Myanmar Symbols (used in documentation)",
1751 nullptr,
1752 NumberFormatter::with().symbols(MYANMAR_SYMBOLS),
1753 Locale::getEnglish(),
1754 12345.67,
1755 u"\u1041\u1042,\u1043\u1044\u1045.\u1046\u1047");
1756
1757 // NOTE: Locale ar puts ¤ after the number in NS arab but before the number in NS latn.
1758
1759 assertFormatSingle(
1760 u"Currency symbol should precede number in ar with NS latn",
1761 u"currency/USD latin",
1762 NumberFormatter::with().adoptSymbols(new NumberingSystem(LATN)).unit(USD),
1763 Locale("ar"),
1764 12345.67,
1765 u"US$ 12,345.67");
1766
1767 assertFormatSingle(
1768 u"Currency symbol should precede number in ar@numbers=latn",
1769 u"currency/USD",
1770 NumberFormatter::with().unit(USD),
1771 Locale("ar@numbers=latn"),
1772 12345.67,
1773 u"US$ 12,345.67");
1774
1775 assertFormatSingle(
1776 u"Currency symbol should follow number in ar-EG with NS arab",
1777 u"currency/USD",
1778 NumberFormatter::with().unit(USD),
1779 Locale("ar-EG"),
1780 12345.67,
1781 u"١٢٬٣٤٥٫٦٧ US$");
1782
1783 assertFormatSingle(
1784 u"Currency symbol should follow number in ar@numbers=arab",
1785 u"currency/USD",
1786 NumberFormatter::with().unit(USD),
1787 Locale("ar@numbers=arab"),
1788 12345.67,
1789 u"١٢٬٣٤٥٫٦٧ US$");
1790
1791 assertFormatSingle(
1792 u"NumberingSystem in API should win over @numbers keyword",
1793 u"currency/USD latin",
1794 NumberFormatter::with().adoptSymbols(new NumberingSystem(LATN)).unit(USD),
1795 Locale("ar@numbers=arab"),
1796 12345.67,
1797 u"US$ 12,345.67");
1798
1799 UErrorCode status = U_ZERO_ERROR;
1800 assertEquals(
1801 "NumberingSystem in API should win over @numbers keyword in reverse order",
1802 u"US$ 12,345.67",
1803 NumberFormatter::withLocale(Locale("ar@numbers=arab")).adoptSymbols(new NumberingSystem(LATN))
1804 .unit(USD)
1805 .formatDouble(12345.67, status)
1806 .toString(status));
1807
1808 DecimalFormatSymbols symbols = SWISS_SYMBOLS;
1809 UnlocalizedNumberFormatter f = NumberFormatter::with().symbols(symbols);
1810 symbols.setSymbol(DecimalFormatSymbols::ENumberFormatSymbol::kGroupingSeparatorSymbol, u"!", status);
1811 assertFormatSingle(
1812 u"Symbols object should be copied", nullptr, f, Locale::getEnglish(), 12345.67, u"12’345.67");
1813
1814 assertFormatSingle(
1815 u"The last symbols setter wins",
1816 u"latin",
1817 NumberFormatter::with().symbols(symbols).adoptSymbols(new NumberingSystem(LATN)),
1818 Locale::getEnglish(),
1819 12345.67,
1820 u"12,345.67");
1821
1822 assertFormatSingle(
1823 u"The last symbols setter wins",
1824 nullptr,
1825 NumberFormatter::with().adoptSymbols(new NumberingSystem(LATN)).symbols(symbols),
1826 Locale::getEnglish(),
1827 12345.67,
1828 u"12!345.67");
1829 }
1830
1831 // TODO: Enable if/when currency symbol override is added.
1832 //void NumberFormatterTest::symbolsOverride() {
1833 // DecimalFormatSymbols dfs = DecimalFormatSymbols.getInstance(Locale::getEnglish());
1834 // dfs.setCurrencySymbol("@");
1835 // dfs.setInternationalCurrencySymbol("foo");
1836 // assertFormatSingle(
1837 // u"Custom Short Currency Symbol",
1838 // NumberFormatter::with().unit(Currency.getInstance("XXX")).symbols(dfs),
1839 // Locale::getEnglish(),
1840 // 12.3,
1841 // u"@ 12.30");
1842 //}
1843
1844 void NumberFormatterApiTest::sign() {
1845 assertFormatSingle(
1846 u"Sign Auto Positive",
1847 u"sign-auto",
1848 NumberFormatter::with().sign(UNumberSignDisplay::UNUM_SIGN_AUTO),
1849 Locale::getEnglish(),
1850 444444,
1851 u"444,444");
1852
1853 assertFormatSingle(
1854 u"Sign Auto Negative",
1855 u"sign-auto",
1856 NumberFormatter::with().sign(UNumberSignDisplay::UNUM_SIGN_AUTO),
1857 Locale::getEnglish(),
1858 -444444,
1859 u"-444,444");
1860
1861 assertFormatSingle(
1862 u"Sign Auto Zero",
1863 u"sign-auto",
1864 NumberFormatter::with().sign(UNumberSignDisplay::UNUM_SIGN_AUTO),
1865 Locale::getEnglish(),
1866 0,
1867 u"0");
1868
1869 assertFormatSingle(
1870 u"Sign Always Positive",
1871 u"sign-always",
1872 NumberFormatter::with().sign(UNumberSignDisplay::UNUM_SIGN_ALWAYS),
1873 Locale::getEnglish(),
1874 444444,
1875 u"+444,444");
1876
1877 assertFormatSingle(
1878 u"Sign Always Negative",
1879 u"sign-always",
1880 NumberFormatter::with().sign(UNumberSignDisplay::UNUM_SIGN_ALWAYS),
1881 Locale::getEnglish(),
1882 -444444,
1883 u"-444,444");
1884
1885 assertFormatSingle(
1886 u"Sign Always Zero",
1887 u"sign-always",
1888 NumberFormatter::with().sign(UNumberSignDisplay::UNUM_SIGN_ALWAYS),
1889 Locale::getEnglish(),
1890 0,
1891 u"+0");
1892
1893 assertFormatSingle(
1894 u"Sign Never Positive",
1895 u"sign-never",
1896 NumberFormatter::with().sign(UNumberSignDisplay::UNUM_SIGN_NEVER),
1897 Locale::getEnglish(),
1898 444444,
1899 u"444,444");
1900
1901 assertFormatSingle(
1902 u"Sign Never Negative",
1903 u"sign-never",
1904 NumberFormatter::with().sign(UNumberSignDisplay::UNUM_SIGN_NEVER),
1905 Locale::getEnglish(),
1906 -444444,
1907 u"444,444");
1908
1909 assertFormatSingle(
1910 u"Sign Never Zero",
1911 u"sign-never",
1912 NumberFormatter::with().sign(UNumberSignDisplay::UNUM_SIGN_NEVER),
1913 Locale::getEnglish(),
1914 0,
1915 u"0");
1916
1917 assertFormatSingle(
1918 u"Sign Accounting Positive",
1919 u"currency/USD sign-accounting",
1920 NumberFormatter::with().sign(UNumberSignDisplay::UNUM_SIGN_ACCOUNTING).unit(USD),
1921 Locale::getEnglish(),
1922 444444,
1923 u"$444,444.00");
1924
1925 assertFormatSingle(
1926 u"Sign Accounting Negative",
1927 u"currency/USD sign-accounting",
1928 NumberFormatter::with().sign(UNumberSignDisplay::UNUM_SIGN_ACCOUNTING).unit(USD),
1929 Locale::getEnglish(),
1930 -444444,
1931 u"($444,444.00)");
1932
1933 assertFormatSingle(
1934 u"Sign Accounting Zero",
1935 u"currency/USD sign-accounting",
1936 NumberFormatter::with().sign(UNumberSignDisplay::UNUM_SIGN_ACCOUNTING).unit(USD),
1937 Locale::getEnglish(),
1938 0,
1939 u"$0.00");
1940
1941 assertFormatSingle(
1942 u"Sign Accounting-Always Positive",
1943 u"currency/USD sign-accounting-always",
1944 NumberFormatter::with().sign(UNumberSignDisplay::UNUM_SIGN_ACCOUNTING_ALWAYS).unit(USD),
1945 Locale::getEnglish(),
1946 444444,
1947 u"+$444,444.00");
1948
1949 assertFormatSingle(
1950 u"Sign Accounting-Always Negative",
1951 u"currency/USD sign-accounting-always",
1952 NumberFormatter::with().sign(UNumberSignDisplay::UNUM_SIGN_ACCOUNTING_ALWAYS).unit(USD),
1953 Locale::getEnglish(),
1954 -444444,
1955 u"($444,444.00)");
1956
1957 assertFormatSingle(
1958 u"Sign Accounting-Always Zero",
1959 u"currency/USD sign-accounting-always",
1960 NumberFormatter::with().sign(UNumberSignDisplay::UNUM_SIGN_ACCOUNTING_ALWAYS).unit(USD),
1961 Locale::getEnglish(),
1962 0,
1963 u"+$0.00");
1964
1965 assertFormatSingle(
1966 u"Sign Except-Zero Positive",
1967 u"sign-except-zero",
1968 NumberFormatter::with().sign(UNumberSignDisplay::UNUM_SIGN_EXCEPT_ZERO),
1969 Locale::getEnglish(),
1970 444444,
1971 u"+444,444");
1972
1973 assertFormatSingle(
1974 u"Sign Except-Zero Negative",
1975 u"sign-except-zero",
1976 NumberFormatter::with().sign(UNumberSignDisplay::UNUM_SIGN_EXCEPT_ZERO),
1977 Locale::getEnglish(),
1978 -444444,
1979 u"-444,444");
1980
1981 assertFormatSingle(
1982 u"Sign Except-Zero Zero",
1983 u"sign-except-zero",
1984 NumberFormatter::with().sign(UNumberSignDisplay::UNUM_SIGN_EXCEPT_ZERO),
1985 Locale::getEnglish(),
1986 0,
1987 u"0");
1988
1989 assertFormatSingle(
1990 u"Sign Accounting-Except-Zero Positive",
1991 u"currency/USD sign-accounting-except-zero",
1992 NumberFormatter::with().sign(UNumberSignDisplay::UNUM_SIGN_ACCOUNTING_EXCEPT_ZERO).unit(USD),
1993 Locale::getEnglish(),
1994 444444,
1995 u"+$444,444.00");
1996
1997 assertFormatSingle(
1998 u"Sign Accounting-Except-Zero Negative",
1999 u"currency/USD sign-accounting-except-zero",
2000 NumberFormatter::with().sign(UNumberSignDisplay::UNUM_SIGN_ACCOUNTING_EXCEPT_ZERO).unit(USD),
2001 Locale::getEnglish(),
2002 -444444,
2003 u"($444,444.00)");
2004
2005 assertFormatSingle(
2006 u"Sign Accounting-Except-Zero Zero",
2007 u"currency/USD sign-accounting-except-zero",
2008 NumberFormatter::with().sign(UNumberSignDisplay::UNUM_SIGN_ACCOUNTING_EXCEPT_ZERO).unit(USD),
2009 Locale::getEnglish(),
2010 0,
2011 u"$0.00");
2012
2013 assertFormatSingle(
2014 u"Sign Accounting Negative Hidden",
2015 u"currency/USD unit-width-hidden sign-accounting",
2016 NumberFormatter::with()
2017 .sign(UNumberSignDisplay::UNUM_SIGN_ACCOUNTING)
2018 .unit(USD)
2019 .unitWidth(UNUM_UNIT_WIDTH_HIDDEN),
2020 Locale::getEnglish(),
2021 -444444,
2022 u"(444,444.00)");
2023
2024 assertFormatSingle(
2025 u"Sign Accounting Negative Narrow",
2026 u"currency/USD unit-width-narrow sign-accounting",
2027 NumberFormatter::with()
2028 .sign(UNumberSignDisplay::UNUM_SIGN_ACCOUNTING)
2029 .unit(USD)
2030 .unitWidth(UNUM_UNIT_WIDTH_NARROW),
2031 Locale::getCanada(),
2032 -444444,
2033 u"($444,444.00)");
2034
2035 assertFormatSingle(
2036 u"Sign Accounting Negative Short",
2037 u"currency/USD sign-accounting",
2038 NumberFormatter::with()
2039 .sign(UNumberSignDisplay::UNUM_SIGN_ACCOUNTING)
2040 .unit(USD)
2041 .unitWidth(UNUM_UNIT_WIDTH_SHORT),
2042 Locale::getCanada(),
2043 -444444,
2044 u"(US$444,444.00)");
2045
2046 assertFormatSingle(
2047 u"Sign Accounting Negative Iso Code",
2048 u"currency/USD unit-width-iso-code sign-accounting",
2049 NumberFormatter::with()
2050 .sign(UNumberSignDisplay::UNUM_SIGN_ACCOUNTING)
2051 .unit(USD)
2052 .unitWidth(UNUM_UNIT_WIDTH_ISO_CODE),
2053 Locale::getCanada(),
2054 -444444,
2055 u"(USD 444,444.00)");
2056
2057 // Note: CLDR does not provide an accounting pattern for long name currency.
2058 // We fall back to normal currency format. This may change in the future.
2059 assertFormatSingle(
2060 u"Sign Accounting Negative Full Name",
2061 u"currency/USD unit-width-full-name sign-accounting",
2062 NumberFormatter::with()
2063 .sign(UNumberSignDisplay::UNUM_SIGN_ACCOUNTING)
2064 .unit(USD)
2065 .unitWidth(UNUM_UNIT_WIDTH_FULL_NAME),
2066 Locale::getCanada(),
2067 -444444,
2068 u"-444,444.00 US dollars");
2069 }
2070
2071 void NumberFormatterApiTest::decimal() {
2072 assertFormatDescending(
2073 u"Decimal Default",
2074 u"decimal-auto",
2075 NumberFormatter::with().decimal(UNumberDecimalSeparatorDisplay::UNUM_DECIMAL_SEPARATOR_AUTO),
2076 Locale::getEnglish(),
2077 u"87,650",
2078 u"8,765",
2079 u"876.5",
2080 u"87.65",
2081 u"8.765",
2082 u"0.8765",
2083 u"0.08765",
2084 u"0.008765",
2085 u"0");
2086
2087 assertFormatDescending(
2088 u"Decimal Always Shown",
2089 u"decimal-always",
2090 NumberFormatter::with().decimal(UNumberDecimalSeparatorDisplay::UNUM_DECIMAL_SEPARATOR_ALWAYS),
2091 Locale::getEnglish(),
2092 u"87,650.",
2093 u"8,765.",
2094 u"876.5",
2095 u"87.65",
2096 u"8.765",
2097 u"0.8765",
2098 u"0.08765",
2099 u"0.008765",
2100 u"0.");
2101 }
2102
2103 void NumberFormatterApiTest::scale() {
2104 assertFormatDescending(
2105 u"Multiplier None",
2106 u"scale/1",
2107 NumberFormatter::with().scale(Scale::none()),
2108 Locale::getEnglish(),
2109 u"87,650",
2110 u"8,765",
2111 u"876.5",
2112 u"87.65",
2113 u"8.765",
2114 u"0.8765",
2115 u"0.08765",
2116 u"0.008765",
2117 u"0");
2118
2119 assertFormatDescending(
2120 u"Multiplier Power of Ten",
2121 u"scale/1000000",
2122 NumberFormatter::with().scale(Scale::powerOfTen(6)),
2123 Locale::getEnglish(),
2124 u"87,650,000,000",
2125 u"8,765,000,000",
2126 u"876,500,000",
2127 u"87,650,000",
2128 u"8,765,000",
2129 u"876,500",
2130 u"87,650",
2131 u"8,765",
2132 u"0");
2133
2134 assertFormatDescending(
2135 u"Multiplier Arbitrary Double",
2136 u"scale/5.2",
2137 NumberFormatter::with().scale(Scale::byDouble(5.2)),
2138 Locale::getEnglish(),
2139 u"455,780",
2140 u"45,578",
2141 u"4,557.8",
2142 u"455.78",
2143 u"45.578",
2144 u"4.5578",
2145 u"0.45578",
2146 u"0.045578",
2147 u"0");
2148
2149 assertFormatDescending(
2150 u"Multiplier Arbitrary BigDecimal",
2151 u"scale/5.2",
2152 NumberFormatter::with().scale(Scale::byDecimal({"5.2", -1})),
2153 Locale::getEnglish(),
2154 u"455,780",
2155 u"45,578",
2156 u"4,557.8",
2157 u"455.78",
2158 u"45.578",
2159 u"4.5578",
2160 u"0.45578",
2161 u"0.045578",
2162 u"0");
2163
2164 assertFormatDescending(
2165 u"Multiplier Arbitrary Double And Power Of Ten",
2166 u"scale/5200",
2167 NumberFormatter::with().scale(Scale::byDoubleAndPowerOfTen(5.2, 3)),
2168 Locale::getEnglish(),
2169 u"455,780,000",
2170 u"45,578,000",
2171 u"4,557,800",
2172 u"455,780",
2173 u"45,578",
2174 u"4,557.8",
2175 u"455.78",
2176 u"45.578",
2177 u"0");
2178
2179 assertFormatDescending(
2180 u"Multiplier Zero",
2181 u"scale/0",
2182 NumberFormatter::with().scale(Scale::byDouble(0)),
2183 Locale::getEnglish(),
2184 u"0",
2185 u"0",
2186 u"0",
2187 u"0",
2188 u"0",
2189 u"0",
2190 u"0",
2191 u"0",
2192 u"0");
2193
2194 assertFormatSingle(
2195 u"Multiplier Skeleton Scientific Notation and Percent",
2196 u"percent scale/1E2",
2197 NumberFormatter::with().unit(NoUnit::percent()).scale(Scale::powerOfTen(2)),
2198 Locale::getEnglish(),
2199 0.5,
2200 u"50%");
2201
2202 assertFormatSingle(
2203 u"Negative Multiplier",
2204 u"scale/-5.2",
2205 NumberFormatter::with().scale(Scale::byDouble(-5.2)),
2206 Locale::getEnglish(),
2207 2,
2208 u"-10.4");
2209
2210 assertFormatSingle(
2211 u"Negative One Multiplier",
2212 u"scale/-1",
2213 NumberFormatter::with().scale(Scale::byDouble(-1)),
2214 Locale::getEnglish(),
2215 444444,
2216 u"-444,444");
2217
2218 assertFormatSingle(
2219 u"Two-Type Multiplier with Overlap",
2220 u"scale/10000",
2221 NumberFormatter::with().scale(Scale::byDoubleAndPowerOfTen(100, 2)),
2222 Locale::getEnglish(),
2223 2,
2224 u"20,000");
2225 }
2226
2227 void NumberFormatterApiTest::locale() {
2228 // Coverage for the locale setters.
2229 UErrorCode status = U_ZERO_ERROR;
2230 UnicodeString actual = NumberFormatter::withLocale(Locale::getFrench()).formatInt(1234, status)
2231 .toString(status);
2232 assertEquals("Locale withLocale()", u"1\u202f234", actual);
2233 }
2234
2235 void NumberFormatterApiTest::formatTypes() {
2236 UErrorCode status = U_ZERO_ERROR;
2237 LocalizedNumberFormatter formatter = NumberFormatter::withLocale(Locale::getEnglish());
2238
2239 // Double
2240 assertEquals("Format double", "514.23", formatter.formatDouble(514.23, status).toString(status));
2241
2242 // Int64
2243 assertEquals("Format int64", "51,423", formatter.formatDouble(51423L, status).toString(status));
2244
2245 // decNumber
2246 UnicodeString actual = formatter.formatDecimal("98765432123456789E1", status).toString(status);
2247 assertEquals("Format decNumber", u"987,654,321,234,567,890", actual);
2248
2249 // Also test proper DecimalQuantity bytes storage when all digits are in the fraction.
2250 // The number needs to have exactly 40 digits, which is the size of the default buffer.
2251 // (issue discovered by the address sanitizer in C++)
2252 static const char* str = "0.009876543210987654321098765432109876543211";
2253 actual = formatter.precision(Precision::unlimited()).formatDecimal(str, status).toString(status);
2254 assertEquals("Format decNumber to 40 digits", str, actual);
2255 }
2256
2257 void NumberFormatterApiTest::fieldPositionLogic() {
2258 IcuTestErrorCode status(*this, "fieldPositionLogic");
2259
2260 const char16_t* message = u"Field position logic test";
2261
2262 FormattedNumber fmtd = assertFormatSingle(
2263 message,
2264 u"",
2265 NumberFormatter::with(),
2266 Locale::getEnglish(),
2267 -9876543210.12,
2268 u"-9,876,543,210.12");
2269
2270 static const UFieldPosition expectedFieldPositions[] = {
2271 // field, begin index, end index
2272 {UNUM_SIGN_FIELD, 0, 1},
2273 {UNUM_GROUPING_SEPARATOR_FIELD, 2, 3},
2274 {UNUM_GROUPING_SEPARATOR_FIELD, 6, 7},
2275 {UNUM_GROUPING_SEPARATOR_FIELD, 10, 11},
2276 {UNUM_INTEGER_FIELD, 1, 14},
2277 {UNUM_DECIMAL_SEPARATOR_FIELD, 14, 15},
2278 {UNUM_FRACTION_FIELD, 15, 17}};
2279
2280 assertNumberFieldPositions(
2281 message,
2282 fmtd,
2283 expectedFieldPositions,
2284 UPRV_LENGTHOF(expectedFieldPositions));
2285
2286 // Test the iteration functionality of nextFieldPosition
2287 FieldPosition actual = {UNUM_GROUPING_SEPARATOR_FIELD};
2288 int32_t i = 1;
2289 while (fmtd.nextFieldPosition(actual, status)) {
2290 UFieldPosition expected = expectedFieldPositions[i++];
2291 assertEquals(
2292 UnicodeString(u"Next for grouping, field, case #") + Int64ToUnicodeString(i),
2293 expected.field,
2294 actual.getField());
2295 assertEquals(
2296 UnicodeString(u"Next for grouping, begin index, case #") + Int64ToUnicodeString(i),
2297 expected.beginIndex,
2298 actual.getBeginIndex());
2299 assertEquals(
2300 UnicodeString(u"Next for grouping, end index, case #") + Int64ToUnicodeString(i),
2301 expected.endIndex,
2302 actual.getEndIndex());
2303 }
2304 assertEquals(u"Should have seen all grouping separators", 4, i);
2305
2306 // Make sure strings without fraction do not contain fraction field
2307 actual = {UNUM_FRACTION_FIELD};
2308 fmtd = NumberFormatter::withLocale("en").formatInt(5, status);
2309 assertFalse(u"No fraction part in an integer", fmtd.nextFieldPosition(actual, status));
2310 }
2311
2312 void NumberFormatterApiTest::fieldPositionCoverage() {
2313 IcuTestErrorCode status(*this, "fieldPositionCoverage");
2314
2315 {
2316 const char16_t* message = u"Measure unit field position basic";
2317 FormattedNumber result = assertFormatSingle(
2318 message,
2319 u"measure-unit/temperature-fahrenheit",
2320 NumberFormatter::with().unit(FAHRENHEIT),
2321 Locale::getEnglish(),
2322 68,
2323 u"68°F");
2324 static const UFieldPosition expectedFieldPositions[] = {
2325 // field, begin index, end index
2326 {UNUM_INTEGER_FIELD, 0, 2},
2327 {UNUM_MEASURE_UNIT_FIELD, 2, 4}};
2328 assertNumberFieldPositions(
2329 message,
2330 result,
2331 expectedFieldPositions,
2332 UPRV_LENGTHOF(expectedFieldPositions));
2333 }
2334
2335 {
2336 const char16_t* message = u"Measure unit field position with compound unit";
2337 FormattedNumber result = assertFormatSingle(
2338 message,
2339 u"measure-unit/temperature-fahrenheit per-measure-unit/duration-day",
2340 NumberFormatter::with().unit(FAHRENHEIT).perUnit(DAY),
2341 Locale::getEnglish(),
2342 68,
2343 u"68°F/d");
2344 static const UFieldPosition expectedFieldPositions[] = {
2345 // field, begin index, end index
2346 {UNUM_INTEGER_FIELD, 0, 2},
2347 // coverage for old enum:
2348 {DecimalFormat::kMeasureUnitField, 2, 6}};
2349 assertNumberFieldPositions(
2350 message,
2351 result,
2352 expectedFieldPositions,
2353 UPRV_LENGTHOF(expectedFieldPositions));
2354 }
2355
2356 {
2357 const char16_t* message = u"Measure unit field position with spaces";
2358 FormattedNumber result = assertFormatSingle(
2359 message,
2360 u"measure-unit/length-meter unit-width-full-name",
2361 NumberFormatter::with().unit(METER).unitWidth(UNUM_UNIT_WIDTH_FULL_NAME),
2362 Locale::getEnglish(),
2363 68,
2364 u"68 meters");
2365 static const UFieldPosition expectedFieldPositions[] = {
2366 // field, begin index, end index
2367 {UNUM_INTEGER_FIELD, 0, 2},
2368 // note: field starts after the space
2369 {UNUM_MEASURE_UNIT_FIELD, 3, 9}};
2370 assertNumberFieldPositions(
2371 message,
2372 result,
2373 expectedFieldPositions,
2374 UPRV_LENGTHOF(expectedFieldPositions));
2375 }
2376
2377 {
2378 const char16_t* message = u"Measure unit field position with prefix and suffix";
2379 FormattedNumber result = assertFormatSingle(
2380 message,
2381 u"measure-unit/length-meter per-measure-unit/duration-second unit-width-full-name",
2382 NumberFormatter::with().unit(METER).perUnit(SECOND).unitWidth(UNUM_UNIT_WIDTH_FULL_NAME),
2383 "ky", // locale with the interesting data
2384 68,
2385 u"секундасына 68 метр");
2386 static const UFieldPosition expectedFieldPositions[] = {
2387 // field, begin index, end index
2388 {UNUM_MEASURE_UNIT_FIELD, 0, 11},
2389 {UNUM_INTEGER_FIELD, 12, 14},
2390 {UNUM_MEASURE_UNIT_FIELD, 15, 19}};
2391 assertNumberFieldPositions(
2392 message,
2393 result,
2394 expectedFieldPositions,
2395 UPRV_LENGTHOF(expectedFieldPositions));
2396 }
2397
2398 {
2399 const char16_t* message = u"Measure unit field position with inner spaces";
2400 FormattedNumber result = assertFormatSingle(
2401 message,
2402 u"measure-unit/temperature-fahrenheit unit-width-full-name",
2403 NumberFormatter::with().unit(FAHRENHEIT).unitWidth(UNUM_UNIT_WIDTH_FULL_NAME),
2404 "vi", // locale with the interesting data
2405 68,
2406 u"68 độ F");
2407 static const UFieldPosition expectedFieldPositions[] = {
2408 // field, begin index, end index
2409 {UNUM_INTEGER_FIELD, 0, 2},
2410 // Should trim leading/trailing spaces, but not inner spaces:
2411 {UNUM_MEASURE_UNIT_FIELD, 3, 7}};
2412 assertNumberFieldPositions(
2413 message,
2414 result,
2415 expectedFieldPositions,
2416 UPRV_LENGTHOF(expectedFieldPositions));
2417 }
2418
2419 {
2420 // Data: other{"‎{0} K"} == "\u200E{0} K"
2421 // If that data changes, try to find another example of a non-empty unit prefix/suffix
2422 // that is also all ignorables (whitespace and bidi control marks).
2423 const char16_t* message = u"Measure unit field position with fully ignorable prefix";
2424 FormattedNumber result = assertFormatSingle(
2425 message,
2426 u"measure-unit/temperature-kelvin",
2427 NumberFormatter::with().unit(KELVIN),
2428 "fa", // locale with the interesting data
2429 68,
2430 u"‎۶۸ K");
2431 static const UFieldPosition expectedFieldPositions[] = {
2432 // field, begin index, end index
2433 {UNUM_INTEGER_FIELD, 1, 3},
2434 {UNUM_MEASURE_UNIT_FIELD, 4, 5}};
2435 assertNumberFieldPositions(
2436 message,
2437 result,
2438 expectedFieldPositions,
2439 UPRV_LENGTHOF(expectedFieldPositions));
2440 }
2441
2442 {
2443 const char16_t* message = u"Compact field basic";
2444 FormattedNumber result = assertFormatSingle(
2445 message,
2446 u"compact-short",
2447 NumberFormatter::with().notation(Notation::compactShort()),
2448 Locale::getUS(),
2449 65000,
2450 u"65K");
2451 static const UFieldPosition expectedFieldPositions[] = {
2452 // field, begin index, end index
2453 {UNUM_INTEGER_FIELD, 0, 2},
2454 {UNUM_COMPACT_FIELD, 2, 3}};
2455 assertNumberFieldPositions(
2456 message,
2457 result,
2458 expectedFieldPositions,
2459 UPRV_LENGTHOF(expectedFieldPositions));
2460 }
2461
2462 {
2463 const char16_t* message = u"Compact field with spaces";
2464 FormattedNumber result = assertFormatSingle(
2465 message,
2466 u"compact-long",
2467 NumberFormatter::with().notation(Notation::compactLong()),
2468 Locale::getUS(),
2469 65000,
2470 u"65 thousand");
2471 static const UFieldPosition expectedFieldPositions[] = {
2472 // field, begin index, end index
2473 {UNUM_INTEGER_FIELD, 0, 2},
2474 {UNUM_COMPACT_FIELD, 3, 11}};
2475 assertNumberFieldPositions(
2476 message,
2477 result,
2478 expectedFieldPositions,
2479 UPRV_LENGTHOF(expectedFieldPositions));
2480 }
2481
2482 {
2483 const char16_t* message = u"Compact field with inner space";
2484 FormattedNumber result = assertFormatSingle(
2485 message,
2486 u"compact-long",
2487 NumberFormatter::with().notation(Notation::compactLong()),
2488 "fil", // locale with interesting data
2489 6000,
2490 u"6 na libo");
2491 static const UFieldPosition expectedFieldPositions[] = {
2492 // field, begin index, end index
2493 {UNUM_INTEGER_FIELD, 0, 1},
2494 {UNUM_COMPACT_FIELD, 2, 9}};
2495 assertNumberFieldPositions(
2496 message,
2497 result,
2498 expectedFieldPositions,
2499 UPRV_LENGTHOF(expectedFieldPositions));
2500 }
2501
2502 {
2503 const char16_t* message = u"Compact field with bidi mark";
2504 FormattedNumber result = assertFormatSingle(
2505 message,
2506 u"compact-long",
2507 NumberFormatter::with().notation(Notation::compactLong()),
2508 "he", // locale with interesting data
2509 6000,
2510 u"\u200F6 אלף");
2511 static const UFieldPosition expectedFieldPositions[] = {
2512 // field, begin index, end index
2513 {UNUM_INTEGER_FIELD, 1, 2},
2514 {UNUM_COMPACT_FIELD, 3, 6}};
2515 assertNumberFieldPositions(
2516 message,
2517 result,
2518 expectedFieldPositions,
2519 UPRV_LENGTHOF(expectedFieldPositions));
2520 }
2521
2522 {
2523 const char16_t* message = u"Compact with currency fields";
2524 FormattedNumber result = assertFormatSingle(
2525 message,
2526 u"compact-short currency/USD",
2527 NumberFormatter::with().notation(Notation::compactShort()).unit(USD),
2528 "sr_Latn", // locale with interesting data
2529 65000,
2530 u"65 hilj. US$");
2531 static const UFieldPosition expectedFieldPositions[] = {
2532 // field, begin index, end index
2533 {UNUM_INTEGER_FIELD, 0, 2},
2534 {UNUM_COMPACT_FIELD, 3, 8},
2535 {UNUM_CURRENCY_FIELD, 9, 12}};
2536 assertNumberFieldPositions(
2537 message,
2538 result,
2539 expectedFieldPositions,
2540 UPRV_LENGTHOF(expectedFieldPositions));
2541 }
2542
2543 {
2544 const char16_t* message = u"Currency long name fields";
2545 FormattedNumber result = assertFormatSingle(
2546 message,
2547 u"currency/USD unit-width-full-name",
2548 NumberFormatter::with().unit(USD)
2549 .unitWidth(UNumberUnitWidth::UNUM_UNIT_WIDTH_FULL_NAME),
2550 "en",
2551 12345,
2552 u"12,345.00 US dollars");
2553 static const UFieldPosition expectedFieldPositions[] = {
2554 // field, begin index, end index
2555 {UNUM_GROUPING_SEPARATOR_FIELD, 2, 3},
2556 {UNUM_INTEGER_FIELD, 0, 6},
2557 {UNUM_DECIMAL_SEPARATOR_FIELD, 6, 7},
2558 {UNUM_FRACTION_FIELD, 7, 9},
2559 {UNUM_CURRENCY_FIELD, 10, 20}};
2560 assertNumberFieldPositions(
2561 message,
2562 result,
2563 expectedFieldPositions,
2564 UPRV_LENGTHOF(expectedFieldPositions));
2565 }
2566
2567 {
2568 const char16_t* message = u"Compact with measure unit fields";
2569 FormattedNumber result = assertFormatSingle(
2570 message,
2571 u"compact-long measure-unit/length-meter unit-width-full-name",
2572 NumberFormatter::with().notation(Notation::compactLong())
2573 .unit(METER)
2574 .unitWidth(UNUM_UNIT_WIDTH_FULL_NAME),
2575 Locale::getUS(),
2576 65000,
2577 u"65 thousand meters");
2578 static const UFieldPosition expectedFieldPositions[] = {
2579 // field, begin index, end index
2580 {UNUM_INTEGER_FIELD, 0, 2},
2581 {UNUM_COMPACT_FIELD, 3, 11},
2582 {UNUM_MEASURE_UNIT_FIELD, 12, 18}};
2583 assertNumberFieldPositions(
2584 message,
2585 result,
2586 expectedFieldPositions,
2587 UPRV_LENGTHOF(expectedFieldPositions));
2588 }
2589 }
2590
2591 void NumberFormatterApiTest::toFormat() {
2592 IcuTestErrorCode status(*this, "icuFormat");
2593 LocalizedNumberFormatter lnf = NumberFormatter::withLocale("fr")
2594 .precision(Precision::fixedFraction(3));
2595 LocalPointer<Format> format(lnf.toFormat(status), status);
2596 FieldPosition fpos(UNUM_DECIMAL_SEPARATOR_FIELD);
2597 UnicodeString sb;
2598 format->format(514.23, sb, fpos, status);
2599 assertEquals("Should correctly format number", u"514,230", sb);
2600 assertEquals("Should find decimal separator", 3, fpos.getBeginIndex());
2601 assertEquals("Should find end of decimal separator", 4, fpos.getEndIndex());
2602 assertEquals(
2603 "ICU Format should round-trip",
2604 lnf.toSkeleton(status),
2605 dynamic_cast<LocalizedNumberFormatterAsFormat*>(format.getAlias())->getNumberFormatter()
2606 .toSkeleton(status));
2607
2608 FieldPositionIterator fpi1;
2609 lnf.formatDouble(514.23, status).getAllFieldPositions(fpi1, status);
2610 FieldPositionIterator fpi2;
2611 format->format(514.23, sb.remove(), &fpi2, status);
2612 assertTrue("Should produce same field position iterator", fpi1 == fpi2);
2613 }
2614
2615 void NumberFormatterApiTest::errors() {
2616 LocalizedNumberFormatter lnf = NumberFormatter::withLocale(Locale::getEnglish()).precision(
2617 Precision::fixedFraction(
2618 -1));
2619
2620 // formatInt
2621 UErrorCode status = U_ZERO_ERROR;
2622 FormattedNumber fn = lnf.formatInt(1, status);
2623 assertEquals(
2624 "Should fail in formatInt method with error code for rounding",
2625 U_NUMBER_ARG_OUTOFBOUNDS_ERROR,
2626 status);
2627
2628 // formatDouble
2629 status = U_ZERO_ERROR;
2630 fn = lnf.formatDouble(1.0, status);
2631 assertEquals(
2632 "Should fail in formatDouble method with error code for rounding",
2633 U_NUMBER_ARG_OUTOFBOUNDS_ERROR,
2634 status);
2635
2636 // formatDecimal (decimal error)
2637 status = U_ZERO_ERROR;
2638 fn = NumberFormatter::withLocale("en").formatDecimal("1x2", status);
2639 assertEquals(
2640 "Should fail in formatDecimal method with error code for decimal number syntax",
2641 U_DECIMAL_NUMBER_SYNTAX_ERROR,
2642 status);
2643
2644 // formatDecimal (setting error)
2645 status = U_ZERO_ERROR;
2646 fn = lnf.formatDecimal("1.0", status);
2647 assertEquals(
2648 "Should fail in formatDecimal method with error code for rounding",
2649 U_NUMBER_ARG_OUTOFBOUNDS_ERROR,
2650 status);
2651
2652 // Skeleton string
2653 status = U_ZERO_ERROR;
2654 UnicodeString output = lnf.toSkeleton(status);
2655 assertEquals(
2656 "Should fail on toSkeleton terminal method with correct error code",
2657 U_NUMBER_ARG_OUTOFBOUNDS_ERROR,
2658 status);
2659 assertTrue(
2660 "Terminal toSkeleton on error object should be bogus",
2661 output.isBogus());
2662
2663 // FieldPosition
2664 status = U_ZERO_ERROR;
2665 FieldPosition fp;
2666 fn.nextFieldPosition(fp, status);
2667 assertEquals(
2668 "Should fail on FieldPosition terminal method with correct error code",
2669 U_NUMBER_ARG_OUTOFBOUNDS_ERROR,
2670 status);
2671
2672 // FieldPositionIterator
2673 status = U_ZERO_ERROR;
2674 FieldPositionIterator fpi;
2675 fn.getAllFieldPositions(fpi, status);
2676 assertEquals(
2677 "Should fail on FieldPositoinIterator terminal method with correct error code",
2678 U_NUMBER_ARG_OUTOFBOUNDS_ERROR,
2679 status);
2680
2681 // Appendable
2682 status = U_ZERO_ERROR;
2683 UnicodeStringAppendable appendable(output.remove());
2684 fn.appendTo(appendable, status);
2685 assertEquals(
2686 "Should fail on Appendable terminal method with correct error code",
2687 U_NUMBER_ARG_OUTOFBOUNDS_ERROR,
2688 status);
2689
2690 // UnicodeString
2691 status = U_ZERO_ERROR;
2692 output = fn.toString(status);
2693 assertEquals(
2694 "Should fail on UnicodeString terminal method with correct error code",
2695 U_NUMBER_ARG_OUTOFBOUNDS_ERROR,
2696 status);
2697 assertTrue(
2698 "Terminal UnicodeString on error object should be bogus",
2699 output.isBogus());
2700
2701 // CopyErrorTo
2702 status = U_ZERO_ERROR;
2703 lnf.copyErrorTo(status);
2704 assertEquals(
2705 "Should fail since rounder is not legal with correct error code",
2706 U_NUMBER_ARG_OUTOFBOUNDS_ERROR,
2707 status);
2708 }
2709
2710 void NumberFormatterApiTest::validRanges() {
2711
2712 #define EXPECTED_MAX_INT_FRAC_SIG 999
2713
2714 #define VALID_RANGE_ASSERT(status, method, lowerBound, argument) { \
2715 UErrorCode expectedStatus = ((lowerBound <= argument) && (argument <= EXPECTED_MAX_INT_FRAC_SIG)) \
2716 ? U_ZERO_ERROR \
2717 : U_NUMBER_ARG_OUTOFBOUNDS_ERROR; \
2718 assertEquals( \
2719 UnicodeString(u"Incorrect status for " #method " on input ") \
2720 + Int64ToUnicodeString(argument), \
2721 expectedStatus, \
2722 status); \
2723 }
2724
2725 #define VALID_RANGE_ONEARG(setting, method, lowerBound) { \
2726 for (int32_t argument = -2; argument <= EXPECTED_MAX_INT_FRAC_SIG + 2; argument++) { \
2727 UErrorCode status = U_ZERO_ERROR; \
2728 NumberFormatter::with().setting(method(argument)).copyErrorTo(status); \
2729 VALID_RANGE_ASSERT(status, method, lowerBound, argument); \
2730 } \
2731 }
2732
2733 #define VALID_RANGE_TWOARGS(setting, method, lowerBound) { \
2734 for (int32_t argument = -2; argument <= EXPECTED_MAX_INT_FRAC_SIG + 2; argument++) { \
2735 UErrorCode status = U_ZERO_ERROR; \
2736 /* Pass EXPECTED_MAX_INT_FRAC_SIG as the second argument so arg1 <= arg2 in expected cases */ \
2737 NumberFormatter::with().setting(method(argument, EXPECTED_MAX_INT_FRAC_SIG)).copyErrorTo(status); \
2738 VALID_RANGE_ASSERT(status, method, lowerBound, argument); \
2739 status = U_ZERO_ERROR; \
2740 /* Pass lowerBound as the first argument so arg1 <= arg2 in expected cases */ \
2741 NumberFormatter::with().setting(method(lowerBound, argument)).copyErrorTo(status); \
2742 VALID_RANGE_ASSERT(status, method, lowerBound, argument); \
2743 /* Check that first argument must be less than or equal to second argument */ \
2744 NumberFormatter::with().setting(method(argument, argument - 1)).copyErrorTo(status); \
2745 assertEquals("Incorrect status for " #method " on max < min input", \
2746 U_NUMBER_ARG_OUTOFBOUNDS_ERROR, \
2747 status); \
2748 } \
2749 }
2750
2751 VALID_RANGE_ONEARG(precision, Precision::fixedFraction, 0);
2752 VALID_RANGE_ONEARG(precision, Precision::minFraction, 0);
2753 VALID_RANGE_ONEARG(precision, Precision::maxFraction, 0);
2754 VALID_RANGE_TWOARGS(precision, Precision::minMaxFraction, 0);
2755 VALID_RANGE_ONEARG(precision, Precision::fixedSignificantDigits, 1);
2756 VALID_RANGE_ONEARG(precision, Precision::minSignificantDigits, 1);
2757 VALID_RANGE_ONEARG(precision, Precision::maxSignificantDigits, 1);
2758 VALID_RANGE_TWOARGS(precision, Precision::minMaxSignificantDigits, 1);
2759 VALID_RANGE_ONEARG(precision, Precision::fixedFraction(1).withMinDigits, 1);
2760 VALID_RANGE_ONEARG(precision, Precision::fixedFraction(1).withMaxDigits, 1);
2761 VALID_RANGE_ONEARG(notation, Notation::scientific().withMinExponentDigits, 1);
2762 VALID_RANGE_ONEARG(integerWidth, IntegerWidth::zeroFillTo, 0);
2763 VALID_RANGE_ONEARG(integerWidth, IntegerWidth::zeroFillTo(0).truncateAt, -1);
2764 }
2765
2766 void NumberFormatterApiTest::copyMove() {
2767 IcuTestErrorCode status(*this, "copyMove");
2768
2769 // Default constructors
2770 LocalizedNumberFormatter l1;
2771 assertEquals("Initial behavior", u"10", l1.formatInt(10, status).toString(status), true);
2772 if (status.errDataIfFailureAndReset()) { return; }
2773 assertEquals("Initial call count", 1, l1.getCallCount());
2774 assertTrue("Initial compiled", l1.getCompiled() == nullptr);
2775
2776 // Setup
2777 l1 = NumberFormatter::withLocale("en").unit(NoUnit::percent()).threshold(3);
2778 assertEquals("Initial behavior", u"10%", l1.formatInt(10, status).toString(status));
2779 assertEquals("Initial call count", 1, l1.getCallCount());
2780 assertTrue("Initial compiled", l1.getCompiled() == nullptr);
2781 l1.formatInt(123, status);
2782 assertEquals("Still not compiled", 2, l1.getCallCount());
2783 assertTrue("Still not compiled", l1.getCompiled() == nullptr);
2784 l1.formatInt(123, status);
2785 assertEquals("Compiled", u"10%", l1.formatInt(10, status).toString(status));
2786 assertEquals("Compiled", INT32_MIN, l1.getCallCount());
2787 assertTrue("Compiled", l1.getCompiled() != nullptr);
2788
2789 // Copy constructor
2790 LocalizedNumberFormatter l2 = l1;
2791 assertEquals("[constructor] Copy behavior", u"10%", l2.formatInt(10, status).toString(status));
2792 assertEquals("[constructor] Copy should not have compiled state", 1, l2.getCallCount());
2793 assertTrue("[constructor] Copy should not have compiled state", l2.getCompiled() == nullptr);
2794
2795 // Move constructor
2796 LocalizedNumberFormatter l3 = std::move(l1);
2797 assertEquals("[constructor] Move behavior", u"10%", l3.formatInt(10, status).toString(status));
2798 assertEquals("[constructor] Move *should* have compiled state", INT32_MIN, l3.getCallCount());
2799 assertTrue("[constructor] Move *should* have compiled state", l3.getCompiled() != nullptr);
2800 assertEquals("[constructor] Source should be reset after move", 0, l1.getCallCount());
2801 assertTrue("[constructor] Source should be reset after move", l1.getCompiled() == nullptr);
2802
2803 // Reset l1 and l2 to check for macro-props copying for behavior testing
2804 // Make the test more interesting: also warm them up with a compiled formatter.
2805 l1 = NumberFormatter::withLocale("en");
2806 l1.formatInt(1, status);
2807 l1.formatInt(1, status);
2808 l1.formatInt(1, status);
2809 l2 = NumberFormatter::withLocale("en");
2810 l2.formatInt(1, status);
2811 l2.formatInt(1, status);
2812 l2.formatInt(1, status);
2813
2814 // Copy assignment
2815 l1 = l3;
2816 assertEquals("[assignment] Copy behavior", u"10%", l1.formatInt(10, status).toString(status));
2817 assertEquals("[assignment] Copy should not have compiled state", 1, l1.getCallCount());
2818 assertTrue("[assignment] Copy should not have compiled state", l1.getCompiled() == nullptr);
2819
2820 // Move assignment
2821 l2 = std::move(l3);
2822 assertEquals("[assignment] Move behavior", u"10%", l2.formatInt(10, status).toString(status));
2823 assertEquals("[assignment] Move *should* have compiled state", INT32_MIN, l2.getCallCount());
2824 assertTrue("[assignment] Move *should* have compiled state", l2.getCompiled() != nullptr);
2825 assertEquals("[assignment] Source should be reset after move", 0, l3.getCallCount());
2826 assertTrue("[assignment] Source should be reset after move", l3.getCompiled() == nullptr);
2827
2828 // Coverage tests for UnlocalizedNumberFormatter
2829 UnlocalizedNumberFormatter u1;
2830 assertEquals("Default behavior", u"10", u1.locale("en").formatInt(10, status).toString(status));
2831 u1 = u1.unit(NoUnit::percent());
2832 assertEquals("Copy assignment", u"10%", u1.locale("en").formatInt(10, status).toString(status));
2833 UnlocalizedNumberFormatter u2 = u1;
2834 assertEquals("Copy constructor", u"10%", u2.locale("en").formatInt(10, status).toString(status));
2835 UnlocalizedNumberFormatter u3 = std::move(u1);
2836 assertEquals("Move constructor", u"10%", u3.locale("en").formatInt(10, status).toString(status));
2837 u1 = NumberFormatter::with();
2838 u1 = std::move(u2);
2839 assertEquals("Move assignment", u"10%", u1.locale("en").formatInt(10, status).toString(status));
2840
2841 // FormattedNumber move operators
2842 FormattedNumber result = l1.formatInt(10, status);
2843 assertEquals("FormattedNumber move constructor", u"10%", result.toString(status));
2844 result = l1.formatInt(20, status);
2845 assertEquals("FormattedNumber move assignment", u"20%", result.toString(status));
2846 }
2847
2848 void NumberFormatterApiTest::localPointerCAPI() {
2849 // NOTE: This is also the sample code in unumberformatter.h
2850 UErrorCode ec = U_ZERO_ERROR;
2851
2852 // Setup:
2853 LocalUNumberFormatterPointer uformatter(unumf_openForSkeletonAndLocale(u"percent", -1, "en", &ec));
2854 LocalUFormattedNumberPointer uresult(unumf_openResult(&ec));
2855 if (!assertSuccess("", ec, true, __FILE__, __LINE__)) { return; }
2856
2857 // Format a decimal number:
2858 unumf_formatDecimal(uformatter.getAlias(), "9.87E-3", -1, uresult.getAlias(), &ec);
2859 if (!assertSuccess("", ec, true, __FILE__, __LINE__)) { return; }
2860
2861 // Get the location of the percent sign:
2862 UFieldPosition ufpos = {UNUM_PERCENT_FIELD, 0, 0};
2863 unumf_resultNextFieldPosition(uresult.getAlias(), &ufpos, &ec);
2864 assertEquals("Percent sign location within '0.00987%'", 7, ufpos.beginIndex);
2865 assertEquals("Percent sign location within '0.00987%'", 8, ufpos.endIndex);
2866
2867 // No need to do any cleanup since we are using LocalPointer.
2868 }
2869
2870 void NumberFormatterApiTest::toObject() {
2871 IcuTestErrorCode status(*this, "toObject");
2872
2873 // const lvalue version
2874 {
2875 LocalizedNumberFormatter lnf = NumberFormatter::withLocale("en")
2876 .precision(Precision::fixedFraction(2));
2877 LocalPointer<LocalizedNumberFormatter> lnf2(lnf.clone());
2878 assertFalse("should create successfully, const lvalue", lnf2.isNull());
2879 assertEquals("object API test, const lvalue", u"1,000.00",
2880 lnf2->formatDouble(1000, status).toString(status));
2881 }
2882
2883 // rvalue reference version
2884 {
2885 LocalPointer<LocalizedNumberFormatter> lnf(
2886 NumberFormatter::withLocale("en")
2887 .precision(Precision::fixedFraction(2))
2888 .clone());
2889 assertFalse("should create successfully, rvalue reference", lnf.isNull());
2890 assertEquals("object API test, rvalue reference", u"1,000.00",
2891 lnf->formatDouble(1000, status).toString(status));
2892 }
2893
2894 // to std::unique_ptr via constructor
2895 {
2896 std::unique_ptr<LocalizedNumberFormatter> lnf(
2897 NumberFormatter::withLocale("en")
2898 .precision(Precision::fixedFraction(2))
2899 .clone());
2900 assertTrue("should create successfully, unique_ptr", static_cast<bool>(lnf));
2901 assertEquals("object API test, unique_ptr", u"1,000.00",
2902 lnf->formatDouble(1000, status).toString(status));
2903 }
2904
2905 // to std::unique_ptr via assignment
2906 {
2907 std::unique_ptr<LocalizedNumberFormatter> lnf =
2908 NumberFormatter::withLocale("en")
2909 .precision(Precision::fixedFraction(2))
2910 .clone();
2911 assertTrue("should create successfully, unique_ptr B", static_cast<bool>(lnf));
2912 assertEquals("object API test, unique_ptr B", u"1,000.00",
2913 lnf->formatDouble(1000, status).toString(status));
2914 }
2915
2916 // to LocalPointer via assignment
2917 {
2918 LocalPointer<UnlocalizedNumberFormatter> f =
2919 NumberFormatter::with().clone();
2920 }
2921
2922 // make sure no memory leaks
2923 {
2924 NumberFormatter::with().clone();
2925 }
2926 }
2927
2928
2929 void NumberFormatterApiTest::assertFormatDescending(const char16_t* umessage, const char16_t* uskeleton,
2930 const UnlocalizedNumberFormatter& f, Locale locale,
2931 ...) {
2932 va_list args;
2933 va_start(args, locale);
2934 UnicodeString message(TRUE, umessage, -1);
2935 static double inputs[] = {87650, 8765, 876.5, 87.65, 8.765, 0.8765, 0.08765, 0.008765, 0};
2936 const LocalizedNumberFormatter l1 = f.threshold(0).locale(locale); // no self-regulation
2937 const LocalizedNumberFormatter l2 = f.threshold(1).locale(locale); // all self-regulation
2938 IcuTestErrorCode status(*this, "assertFormatDescending");
2939 status.setScope(message);
2940 UnicodeString expecteds[10];
2941 for (int16_t i = 0; i < 9; i++) {
2942 char16_t caseNumber = u'0' + i;
2943 double d = inputs[i];
2944 UnicodeString expected = va_arg(args, const char16_t*);
2945 expecteds[i] = expected;
2946 UnicodeString actual1 = l1.formatDouble(d, status).toString(status);
2947 assertSuccess(message + u": Unsafe Path: " + caseNumber, status);
2948 assertEquals(message + u": Unsafe Path: " + caseNumber, expected, actual1);
2949 UnicodeString actual2 = l2.formatDouble(d, status).toString(status);
2950 assertSuccess(message + u": Safe Path: " + caseNumber, status);
2951 assertEquals(message + u": Safe Path: " + caseNumber, expected, actual2);
2952 }
2953 if (uskeleton != nullptr) { // if null, skeleton is declared as undefined.
2954 UnicodeString skeleton(TRUE, uskeleton, -1);
2955 // Only compare normalized skeletons: the tests need not provide the normalized forms.
2956 // Use the normalized form to construct the testing formatter to guarantee no loss of info.
2957 UnicodeString normalized = NumberFormatter::forSkeleton(skeleton, status).toSkeleton(status);
2958 assertEquals(message + ": Skeleton:", normalized, f.toSkeleton(status));
2959 LocalizedNumberFormatter l3 = NumberFormatter::forSkeleton(normalized, status).locale(locale);
2960 for (int32_t i = 0; i < 9; i++) {
2961 double d = inputs[i];
2962 UnicodeString actual3 = l3.formatDouble(d, status).toString(status);
2963 assertEquals(message + ": Skeleton Path: '" + normalized + "': " + d, expecteds[i], actual3);
2964 }
2965 } else {
2966 assertUndefinedSkeleton(f);
2967 }
2968 }
2969
2970 void NumberFormatterApiTest::assertFormatDescendingBig(const char16_t* umessage, const char16_t* uskeleton,
2971 const UnlocalizedNumberFormatter& f, Locale locale,
2972 ...) {
2973 va_list args;
2974 va_start(args, locale);
2975 UnicodeString message(TRUE, umessage, -1);
2976 static double inputs[] = {87650000, 8765000, 876500, 87650, 8765, 876.5, 87.65, 8.765, 0};
2977 const LocalizedNumberFormatter l1 = f.threshold(0).locale(locale); // no self-regulation
2978 const LocalizedNumberFormatter l2 = f.threshold(1).locale(locale); // all self-regulation
2979 IcuTestErrorCode status(*this, "assertFormatDescendingBig");
2980 status.setScope(message);
2981 UnicodeString expecteds[10];
2982 for (int16_t i = 0; i < 9; i++) {
2983 char16_t caseNumber = u'0' + i;
2984 double d = inputs[i];
2985 UnicodeString expected = va_arg(args, const char16_t*);
2986 expecteds[i] = expected;
2987 UnicodeString actual1 = l1.formatDouble(d, status).toString(status);
2988 assertSuccess(message + u": Unsafe Path: " + caseNumber, status);
2989 assertEquals(message + u": Unsafe Path: " + caseNumber, expected, actual1);
2990 UnicodeString actual2 = l2.formatDouble(d, status).toString(status);
2991 assertSuccess(message + u": Safe Path: " + caseNumber, status);
2992 assertEquals(message + u": Safe Path: " + caseNumber, expected, actual2);
2993 }
2994 if (uskeleton != nullptr) { // if null, skeleton is declared as undefined.
2995 UnicodeString skeleton(TRUE, uskeleton, -1);
2996 // Only compare normalized skeletons: the tests need not provide the normalized forms.
2997 // Use the normalized form to construct the testing formatter to guarantee no loss of info.
2998 UnicodeString normalized = NumberFormatter::forSkeleton(skeleton, status).toSkeleton(status);
2999 assertEquals(message + ": Skeleton:", normalized, f.toSkeleton(status));
3000 LocalizedNumberFormatter l3 = NumberFormatter::forSkeleton(normalized, status).locale(locale);
3001 for (int32_t i = 0; i < 9; i++) {
3002 double d = inputs[i];
3003 UnicodeString actual3 = l3.formatDouble(d, status).toString(status);
3004 assertEquals(message + ": Skeleton Path: '" + normalized + "': " + d, expecteds[i], actual3);
3005 }
3006 } else {
3007 assertUndefinedSkeleton(f);
3008 }
3009 }
3010
3011 FormattedNumber
3012 NumberFormatterApiTest::assertFormatSingle(const char16_t* umessage, const char16_t* uskeleton,
3013 const UnlocalizedNumberFormatter& f, Locale locale,
3014 double input, const UnicodeString& expected) {
3015 UnicodeString message(TRUE, umessage, -1);
3016 const LocalizedNumberFormatter l1 = f.threshold(0).locale(locale); // no self-regulation
3017 const LocalizedNumberFormatter l2 = f.threshold(1).locale(locale); // all self-regulation
3018 IcuTestErrorCode status(*this, "assertFormatSingle");
3019 status.setScope(message);
3020 FormattedNumber result1 = l1.formatDouble(input, status);
3021 UnicodeString actual1 = result1.toString(status);
3022 assertSuccess(message + u": Unsafe Path", status);
3023 assertEquals(message + u": Unsafe Path", expected, actual1);
3024 UnicodeString actual2 = l2.formatDouble(input, status).toString(status);
3025 assertSuccess(message + u": Safe Path", status);
3026 assertEquals(message + u": Safe Path", expected, actual2);
3027 if (uskeleton != nullptr) { // if null, skeleton is declared as undefined.
3028 UnicodeString skeleton(TRUE, uskeleton, -1);
3029 // Only compare normalized skeletons: the tests need not provide the normalized forms.
3030 // Use the normalized form to construct the testing formatter to ensure no loss of info.
3031 UnicodeString normalized = NumberFormatter::forSkeleton(skeleton, status).toSkeleton(status);
3032 assertEquals(message + ": Skeleton:", normalized, f.toSkeleton(status));
3033 LocalizedNumberFormatter l3 = NumberFormatter::forSkeleton(normalized, status).locale(locale);
3034 UnicodeString actual3 = l3.formatDouble(input, status).toString(status);
3035 assertEquals(message + ": Skeleton Path: '" + normalized + "': " + input, expected, actual3);
3036 } else {
3037 assertUndefinedSkeleton(f);
3038 }
3039 return result1;
3040 }
3041
3042 void NumberFormatterApiTest::assertUndefinedSkeleton(const UnlocalizedNumberFormatter& f) {
3043 UErrorCode status = U_ZERO_ERROR;
3044 UnicodeString skeleton = f.toSkeleton(status);
3045 assertEquals(
3046 u"Expect toSkeleton to fail, but passed, producing: " + skeleton,
3047 U_UNSUPPORTED_ERROR,
3048 status);
3049 }
3050
3051 void NumberFormatterApiTest::assertNumberFieldPositions(
3052 const char16_t* message, const FormattedNumber& formattedNumber,
3053 const UFieldPosition* expectedFieldPositions, int32_t length) {
3054 IcuTestErrorCode status(*this, "assertNumberFieldPositions");
3055
3056 // Check FormattedValue functions
3057 checkFormattedValue(
3058 message,
3059 static_cast<const FormattedValue&>(formattedNumber),
3060 formattedNumber.toString(status),
3061 UFIELD_CATEGORY_NUMBER,
3062 expectedFieldPositions,
3063 length);
3064
3065 // Check FormattedNumber-specific functions
3066 UnicodeString baseMessage = UnicodeString(message) + u": " + formattedNumber.toString(status) + u": ";
3067 FieldPositionIterator fpi;
3068 formattedNumber.getAllFieldPositions(fpi, status);
3069 int32_t i = 0;
3070 FieldPosition actual;
3071 while (fpi.next(actual)) {
3072 UFieldPosition expected = expectedFieldPositions[i++];
3073 assertEquals(
3074 baseMessage + UnicodeString(u"Field, case #") + Int64ToUnicodeString(i),
3075 expected.field,
3076 actual.getField());
3077 assertEquals(
3078 baseMessage + UnicodeString(u"Iterator, begin, case #") + Int64ToUnicodeString(i),
3079 expected.beginIndex,
3080 actual.getBeginIndex());
3081 assertEquals(
3082 baseMessage + UnicodeString(u"Iterator, end, case #") + Int64ToUnicodeString(i),
3083 expected.endIndex,
3084 actual.getEndIndex());
3085
3086 // Check for the first location of the field
3087 FieldPosition actual2(expected.field);
3088 // Fast-forward the field to skip previous occurrences of the field:
3089 actual2.setBeginIndex(expected.beginIndex);
3090 actual2.setEndIndex(expected.beginIndex);
3091 UBool found = formattedNumber.nextFieldPosition(actual2, status);
3092 assertEquals(
3093 baseMessage + UnicodeString(u"Next, found first, case #") + Int64ToUnicodeString(i),
3094 (UBool) TRUE,
3095 found);
3096 assertEquals(
3097 baseMessage + UnicodeString(u"Next, begin, case #") + Int64ToUnicodeString(i),
3098 expected.beginIndex,
3099 actual2.getBeginIndex());
3100 assertEquals(
3101 baseMessage + UnicodeString(u"Next, end, case #") + Int64ToUnicodeString(i),
3102 expected.endIndex,
3103 actual2.getEndIndex());
3104
3105 // The next position should be empty unless the field occurs again
3106 UBool occursAgain = false;
3107 for (int32_t j=i; j<length; j++) {
3108 if (expectedFieldPositions[j].field == expected.field) {
3109 occursAgain = true;
3110 break;
3111 }
3112 }
3113 if (!occursAgain) {
3114 found = formattedNumber.nextFieldPosition(actual2, status);
3115 assertEquals(
3116 baseMessage + UnicodeString(u"Next, found second, case #") + Int64ToUnicodeString(i),
3117 (UBool) FALSE,
3118 found);
3119 }
3120 }
3121 assertEquals(baseMessage + u"Should have seen every field position", length, i);
3122 }
3123
3124
3125 #endif /* #if !UCONFIG_NO_FORMATTING */