]> git.saurik.com Git - apple/icu.git/blame - icuSources/test/intltest/numbertest_range.cpp
ICU-66108.tar.gz
[apple/icu.git] / icuSources / test / intltest / numbertest_range.cpp
CommitLineData
3d1f044b
A
1// © 2018 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 "numbertest.h"
9#include "unicode/numberrangeformatter.h"
10
11#include <cmath>
12#include <numparse_affixes.h>
13
14// Horrible workaround for the lack of a status code in the constructor...
15// (Also affects numbertest_api.cpp)
16UErrorCode globalNumberRangeFormatterTestStatus = U_ZERO_ERROR;
17
18NumberRangeFormatterTest::NumberRangeFormatterTest()
19 : NumberRangeFormatterTest(globalNumberRangeFormatterTestStatus) {
20}
21
22NumberRangeFormatterTest::NumberRangeFormatterTest(UErrorCode& status)
23 : USD(u"USD", status),
24 GBP(u"GBP", status),
25 PTE(u"PTE", status) {
26
27 // Check for error on the first MeasureUnit in case there is no data
28 LocalPointer<MeasureUnit> unit(MeasureUnit::createMeter(status));
29 if (U_FAILURE(status)) {
30 dataerrln("%s %d status = %s", __FILE__, __LINE__, u_errorName(status));
31 return;
32 }
33 METER = *unit;
34
35 KILOMETER = *LocalPointer<MeasureUnit>(MeasureUnit::createKilometer(status));
36 FAHRENHEIT = *LocalPointer<MeasureUnit>(MeasureUnit::createFahrenheit(status));
37 KELVIN = *LocalPointer<MeasureUnit>(MeasureUnit::createKelvin(status));
38}
39
40void NumberRangeFormatterTest::runIndexedTest(int32_t index, UBool exec, const char*& name, char*) {
41 if (exec) {
42 logln("TestSuite NumberRangeFormatterTest: ");
43 }
44 TESTCASE_AUTO_BEGIN;
45 TESTCASE_AUTO(testSanity);
46 TESTCASE_AUTO(testBasic);
47 TESTCASE_AUTO(testCollapse);
48 TESTCASE_AUTO(testIdentity);
49 TESTCASE_AUTO(testDifferentFormatters);
50 TESTCASE_AUTO(testPlurals);
51 TESTCASE_AUTO(testFieldPositions);
52 TESTCASE_AUTO(testCopyMove);
53 TESTCASE_AUTO(toObject);
54 TESTCASE_AUTO_END;
55}
56
57void NumberRangeFormatterTest::testSanity() {
58 IcuTestErrorCode status(*this, "testSanity");
59 LocalizedNumberRangeFormatter lnrf1 = NumberRangeFormatter::withLocale("en-us");
60 LocalizedNumberRangeFormatter lnrf2 = NumberRangeFormatter::with().locale("en-us");
61 assertEquals("Formatters should have same behavior 1",
62 lnrf1.formatFormattableRange(4, 6, status).toString(status),
63 lnrf2.formatFormattableRange(4, 6, status).toString(status));
64}
65
66void NumberRangeFormatterTest::testBasic() {
67 assertFormatRange(
68 u"Basic",
69 NumberRangeFormatter::with(),
70 Locale("en-us"),
71 u"1–5",
72 u"~5",
73 u"~5",
74 u"0–3",
75 u"~0",
76 u"3–3,000",
77 u"3,000–5,000",
78 u"4,999–5,001",
79 u"~5,000",
80 u"5,000–5,000,000");
81
82 assertFormatRange(
83 u"Basic with units",
84 NumberRangeFormatter::with()
85 .numberFormatterBoth(NumberFormatter::with().unit(METER)),
86 Locale("en-us"),
87 u"1–5 m",
88 u"~5 m",
89 u"~5 m",
90 u"0–3 m",
91 u"~0 m",
92 u"3–3,000 m",
93 u"3,000–5,000 m",
94 u"4,999–5,001 m",
95 u"~5,000 m",
96 u"5,000–5,000,000 m");
97
98 assertFormatRange(
99 u"Basic with different units",
100 NumberRangeFormatter::with()
101 .numberFormatterFirst(NumberFormatter::with().unit(METER))
102 .numberFormatterSecond(NumberFormatter::with().unit(KILOMETER)),
103 Locale("en-us"),
104 u"1 m – 5 km",
105 u"5 m – 5 km",
106 u"5 m – 5 km",
107 u"0 m – 3 km",
108 u"0 m – 0 km",
109 u"3 m – 3,000 km",
110 u"3,000 m – 5,000 km",
111 u"4,999 m – 5,001 km",
112 u"5,000 m – 5,000 km",
113 u"5,000 m – 5,000,000 km");
114
115 assertFormatRange(
116 u"Basic long unit",
117 NumberRangeFormatter::with()
118 .numberFormatterBoth(NumberFormatter::with().unit(METER).unitWidth(UNUM_UNIT_WIDTH_FULL_NAME)),
119 Locale("en-us"),
120 u"1–5 meters",
121 u"~5 meters",
122 u"~5 meters",
123 u"0–3 meters",
124 u"~0 meters",
125 u"3–3,000 meters",
126 u"3,000–5,000 meters",
127 u"4,999–5,001 meters",
128 u"~5,000 meters",
129 u"5,000–5,000,000 meters");
130
131 assertFormatRange(
132 u"Non-English locale and unit",
133 NumberRangeFormatter::with()
134 .numberFormatterBoth(NumberFormatter::with().unit(FAHRENHEIT).unitWidth(UNUM_UNIT_WIDTH_FULL_NAME)),
135 Locale("fr-FR"),
136 u"1–5\u00A0degrés Fahrenheit",
137 u"≈5\u00A0degrés Fahrenheit",
138 u"≈5\u00A0degrés Fahrenheit",
139 u"0–3\u00A0degrés Fahrenheit",
140 u"≈0\u00A0degré Fahrenheit",
141 u"3–3\u202F000\u00A0degrés Fahrenheit",
142 u"3\u202F000–5\u202F000\u00A0degrés Fahrenheit",
143 u"4\u202F999–5\u202F001\u00A0degrés Fahrenheit",
144 u"≈5\u202F000\u00A0degrés Fahrenheit",
145 u"5\u202F000–5\u202F000\u202F000\u00A0degrés Fahrenheit");
146
147 assertFormatRange(
148 u"Locale with custom range separator",
149 NumberRangeFormatter::with(),
150 Locale("ja"),
151 u"1~5",
152 u"約 5",
153 u"約 5",
154 u"0~3",
155 u"約 0",
156 u"3~3,000",
157 u"3,000~5,000",
158 u"4,999~5,001",
159 u"約 5,000",
160 u"5,000~5,000,000");
161
162 assertFormatRange(
163 u"Locale that already has spaces around range separator",
164 NumberRangeFormatter::with()
165 .collapse(UNUM_RANGE_COLLAPSE_NONE)
166 .numberFormatterBoth(NumberFormatter::with().unit(KELVIN)),
167 Locale("hr"),
168 u"1 K – 5 K",
169 u"~5 K",
170 u"~5 K",
171 u"0 K – 3 K",
172 u"~0 K",
173 u"3 K – 3.000 K",
174 u"3.000 K – 5.000 K",
175 u"4.999 K – 5.001 K",
176 u"~5.000 K",
177 u"5.000 K – 5.000.000 K");
178
179 assertFormatRange(
180 u"Locale with custom numbering system and no plural ranges data",
181 NumberRangeFormatter::with(),
182 Locale("shn@numbers=beng"),
183 // 012459 = ০১৩৪৫৯
184 u"১–৫",
185 u"~৫",
186 u"~৫",
187 u"০–৩",
188 u"~০",
189 u"৩–৩,০০০",
190 u"৩,০০০–৫,০০০",
191 u"৪,৯৯৯–৫,০০১",
192 u"~৫,০০০",
193 u"৫,০০০–৫,০০০,০০০");
194
195 assertFormatRange(
196 u"Portuguese currency",
197 NumberRangeFormatter::with()
198 .numberFormatterBoth(NumberFormatter::with().unit(PTE)),
199 Locale("pt-PT"),
200 u"1$00 - 5$00 \u200B",
201 u"~5$00 \u200B",
202 u"~5$00 \u200B",
203 u"0$00 - 3$00 \u200B",
204 u"~0$00 \u200B",
205 u"3$00 - 3000$00 \u200B",
206 u"3000$00 - 5000$00 \u200B",
207 u"4999$00 - 5001$00 \u200B",
208 u"~5000$00 \u200B",
209 u"5000$00 - 5,000,000$00 \u200B");
210}
211
212void NumberRangeFormatterTest::testCollapse() {
213 assertFormatRange(
214 u"Default collapse on currency (default rounding)",
215 NumberRangeFormatter::with()
216 .numberFormatterBoth(NumberFormatter::with().unit(USD)),
217 Locale("en-us"),
218 u"$1.00 – $5.00",
219 u"~$5.00",
220 u"~$5.00",
221 u"$0.00 – $3.00",
222 u"~$0.00",
223 u"$3.00 – $3,000.00",
224 u"$3,000.00 – $5,000.00",
225 u"$4,999.00 – $5,001.00",
226 u"~$5,000.00",
227 u"$5,000.00 – $5,000,000.00");
228
229 assertFormatRange(
230 u"Default collapse on currency",
231 NumberRangeFormatter::with()
232 .numberFormatterBoth(NumberFormatter::with().unit(USD).precision(Precision::integer())),
233 Locale("en-us"),
234 u"$1 – $5",
235 u"~$5",
236 u"~$5",
237 u"$0 – $3",
238 u"~$0",
239 u"$3 – $3,000",
240 u"$3,000 – $5,000",
241 u"$4,999 – $5,001",
242 u"~$5,000",
243 u"$5,000 – $5,000,000");
244
245 assertFormatRange(
246 u"No collapse on currency",
247 NumberRangeFormatter::with()
248 .collapse(UNUM_RANGE_COLLAPSE_NONE)
249 .numberFormatterBoth(NumberFormatter::with().unit(USD).precision(Precision::integer())),
250 Locale("en-us"),
251 u"$1 – $5",
252 u"~$5",
253 u"~$5",
254 u"$0 – $3",
255 u"~$0",
256 u"$3 – $3,000",
257 u"$3,000 – $5,000",
258 u"$4,999 – $5,001",
259 u"~$5,000",
260 u"$5,000 – $5,000,000");
261
262 assertFormatRange(
263 u"Unit collapse on currency",
264 NumberRangeFormatter::with()
265 .collapse(UNUM_RANGE_COLLAPSE_UNIT)
266 .numberFormatterBoth(NumberFormatter::with().unit(USD).precision(Precision::integer())),
267 Locale("en-us"),
268 u"$1–5",
269 u"~$5",
270 u"~$5",
271 u"$0–3",
272 u"~$0",
273 u"$3–3,000",
274 u"$3,000–5,000",
275 u"$4,999–5,001",
276 u"~$5,000",
277 u"$5,000–5,000,000");
278
279 assertFormatRange(
280 u"All collapse on currency",
281 NumberRangeFormatter::with()
282 .collapse(UNUM_RANGE_COLLAPSE_ALL)
283 .numberFormatterBoth(NumberFormatter::with().unit(USD).precision(Precision::integer())),
284 Locale("en-us"),
285 u"$1–5",
286 u"~$5",
287 u"~$5",
288 u"$0–3",
289 u"~$0",
290 u"$3–3,000",
291 u"$3,000–5,000",
292 u"$4,999–5,001",
293 u"~$5,000",
294 u"$5,000–5,000,000");
295
296 assertFormatRange(
297 u"Default collapse on currency ISO code",
298 NumberRangeFormatter::with()
299 .numberFormatterBoth(NumberFormatter::with()
300 .unit(GBP)
301 .unitWidth(UNUM_UNIT_WIDTH_ISO_CODE)
302 .precision(Precision::integer())),
303 Locale("en-us"),
304 u"GBP 1–5",
305 u"~GBP 5", // TODO: Fix this at some point
306 u"~GBP 5",
307 u"GBP 0–3",
308 u"~GBP 0",
309 u"GBP 3–3,000",
310 u"GBP 3,000–5,000",
311 u"GBP 4,999–5,001",
312 u"~GBP 5,000",
313 u"GBP 5,000–5,000,000");
314
315 assertFormatRange(
316 u"No collapse on currency ISO code",
317 NumberRangeFormatter::with()
318 .collapse(UNUM_RANGE_COLLAPSE_NONE)
319 .numberFormatterBoth(NumberFormatter::with()
320 .unit(GBP)
321 .unitWidth(UNUM_UNIT_WIDTH_ISO_CODE)
322 .precision(Precision::integer())),
323 Locale("en-us"),
324 u"GBP 1 – GBP 5",
325 u"~GBP 5", // TODO: Fix this at some point
326 u"~GBP 5",
327 u"GBP 0 – GBP 3",
328 u"~GBP 0",
329 u"GBP 3 – GBP 3,000",
330 u"GBP 3,000 – GBP 5,000",
331 u"GBP 4,999 – GBP 5,001",
332 u"~GBP 5,000",
333 u"GBP 5,000 – GBP 5,000,000");
334
335 assertFormatRange(
336 u"Unit collapse on currency ISO code",
337 NumberRangeFormatter::with()
338 .collapse(UNUM_RANGE_COLLAPSE_UNIT)
339 .numberFormatterBoth(NumberFormatter::with()
340 .unit(GBP)
341 .unitWidth(UNUM_UNIT_WIDTH_ISO_CODE)
342 .precision(Precision::integer())),
343 Locale("en-us"),
344 u"GBP 1–5",
345 u"~GBP 5", // TODO: Fix this at some point
346 u"~GBP 5",
347 u"GBP 0–3",
348 u"~GBP 0",
349 u"GBP 3–3,000",
350 u"GBP 3,000–5,000",
351 u"GBP 4,999–5,001",
352 u"~GBP 5,000",
353 u"GBP 5,000–5,000,000");
354
355 assertFormatRange(
356 u"All collapse on currency ISO code",
357 NumberRangeFormatter::with()
358 .collapse(UNUM_RANGE_COLLAPSE_ALL)
359 .numberFormatterBoth(NumberFormatter::with()
360 .unit(GBP)
361 .unitWidth(UNUM_UNIT_WIDTH_ISO_CODE)
362 .precision(Precision::integer())),
363 Locale("en-us"),
364 u"GBP 1–5",
365 u"~GBP 5", // TODO: Fix this at some point
366 u"~GBP 5",
367 u"GBP 0–3",
368 u"~GBP 0",
369 u"GBP 3–3,000",
370 u"GBP 3,000–5,000",
371 u"GBP 4,999–5,001",
372 u"~GBP 5,000",
373 u"GBP 5,000–5,000,000");
374
375 // Default collapse on measurement unit is in testBasic()
376
377 assertFormatRange(
378 u"No collapse on measurement unit",
379 NumberRangeFormatter::with()
380 .collapse(UNUM_RANGE_COLLAPSE_NONE)
381 .numberFormatterBoth(NumberFormatter::with().unit(METER)),
382 Locale("en-us"),
383 u"1 m – 5 m",
384 u"~5 m",
385 u"~5 m",
386 u"0 m – 3 m",
387 u"~0 m",
388 u"3 m – 3,000 m",
389 u"3,000 m – 5,000 m",
390 u"4,999 m – 5,001 m",
391 u"~5,000 m",
392 u"5,000 m – 5,000,000 m");
393
394 assertFormatRange(
395 u"Unit collapse on measurement unit",
396 NumberRangeFormatter::with()
397 .collapse(UNUM_RANGE_COLLAPSE_UNIT)
398 .numberFormatterBoth(NumberFormatter::with().unit(METER)),
399 Locale("en-us"),
400 u"1–5 m",
401 u"~5 m",
402 u"~5 m",
403 u"0–3 m",
404 u"~0 m",
405 u"3–3,000 m",
406 u"3,000–5,000 m",
407 u"4,999–5,001 m",
408 u"~5,000 m",
409 u"5,000–5,000,000 m");
410
411 assertFormatRange(
412 u"All collapse on measurement unit",
413 NumberRangeFormatter::with()
414 .collapse(UNUM_RANGE_COLLAPSE_ALL)
415 .numberFormatterBoth(NumberFormatter::with().unit(METER)),
416 Locale("en-us"),
417 u"1–5 m",
418 u"~5 m",
419 u"~5 m",
420 u"0–3 m",
421 u"~0 m",
422 u"3–3,000 m",
423 u"3,000–5,000 m",
424 u"4,999–5,001 m",
425 u"~5,000 m",
426 u"5,000–5,000,000 m");
427
428 assertFormatRange(
429 u"Default collapse, long-form compact notation",
430 NumberRangeFormatter::with()
431 .numberFormatterBoth(NumberFormatter::with().notation(Notation::compactLong())),
432 Locale("de-CH"),
433 u"1–5",
434 u"≈5",
435 u"≈5",
436 u"0–3",
437 u"≈0",
438 u"3–3 Tausend",
439 u"3–5 Tausend",
440 u"≈5 Tausend",
441 u"≈5 Tausend",
442 u"5 Tausend – 5 Millionen");
443
444 assertFormatRange(
445 u"Unit collapse, long-form compact notation",
446 NumberRangeFormatter::with()
447 .collapse(UNUM_RANGE_COLLAPSE_UNIT)
448 .numberFormatterBoth(NumberFormatter::with().notation(Notation::compactLong())),
449 Locale("de-CH"),
450 u"1–5",
451 u"≈5",
452 u"≈5",
453 u"0–3",
454 u"≈0",
455 u"3–3 Tausend",
456 u"3 Tausend – 5 Tausend",
457 u"≈5 Tausend",
458 u"≈5 Tausend",
459 u"5 Tausend – 5 Millionen");
460
461 assertFormatRange(
462 u"Default collapse on measurement unit with compact-short notation",
463 NumberRangeFormatter::with()
464 .numberFormatterBoth(NumberFormatter::with().notation(Notation::compactShort()).unit(METER)),
465 Locale("en-us"),
466 u"1–5 m",
467 u"~5 m",
468 u"~5 m",
469 u"0–3 m",
470 u"~0 m",
471 u"3–3K m",
472 u"3K – 5K m",
473 u"~5K m",
474 u"~5K m",
475 u"5K – 5M m");
476
477 assertFormatRange(
478 u"No collapse on measurement unit with compact-short notation",
479 NumberRangeFormatter::with()
480 .collapse(UNUM_RANGE_COLLAPSE_NONE)
481 .numberFormatterBoth(NumberFormatter::with().notation(Notation::compactShort()).unit(METER)),
482 Locale("en-us"),
483 u"1 m – 5 m",
484 u"~5 m",
485 u"~5 m",
486 u"0 m – 3 m",
487 u"~0 m",
488 u"3 m – 3K m",
489 u"3K m – 5K m",
490 u"~5K m",
491 u"~5K m",
492 u"5K m – 5M m");
493
494 assertFormatRange(
495 u"Unit collapse on measurement unit with compact-short notation",
496 NumberRangeFormatter::with()
497 .collapse(UNUM_RANGE_COLLAPSE_UNIT)
498 .numberFormatterBoth(NumberFormatter::with().notation(Notation::compactShort()).unit(METER)),
499 Locale("en-us"),
500 u"1–5 m",
501 u"~5 m",
502 u"~5 m",
503 u"0–3 m",
504 u"~0 m",
505 u"3–3K m",
506 u"3K – 5K m",
507 u"~5K m",
508 u"~5K m",
509 u"5K – 5M m");
510
511 assertFormatRange(
512 u"All collapse on measurement unit with compact-short notation",
513 NumberRangeFormatter::with()
514 .collapse(UNUM_RANGE_COLLAPSE_ALL)
515 .numberFormatterBoth(NumberFormatter::with().notation(Notation::compactShort()).unit(METER)),
516 Locale("en-us"),
517 u"1–5 m",
518 u"~5 m",
519 u"~5 m",
520 u"0–3 m",
521 u"~0 m",
522 u"3–3K m",
523 u"3–5K m", // this one is the key use case for ALL
524 u"~5K m",
525 u"~5K m",
526 u"5K – 5M m");
527
528 assertFormatRange(
529 u"No collapse on scientific notation",
530 NumberRangeFormatter::with()
531 .collapse(UNUM_RANGE_COLLAPSE_NONE)
532 .numberFormatterBoth(NumberFormatter::with().notation(Notation::scientific())),
533 Locale("en-us"),
534 u"1E0 – 5E0",
535 u"~5E0",
536 u"~5E0",
537 u"0E0 – 3E0",
538 u"~0E0",
539 u"3E0 – 3E3",
540 u"3E3 – 5E3",
541 u"4.999E3 – 5.001E3",
542 u"~5E3",
543 u"5E3 – 5E6");
544
545 assertFormatRange(
546 u"All collapse on scientific notation",
547 NumberRangeFormatter::with()
548 .collapse(UNUM_RANGE_COLLAPSE_ALL)
549 .numberFormatterBoth(NumberFormatter::with().notation(Notation::scientific())),
550 Locale("en-us"),
551 u"1–5E0",
552 u"~5E0",
553 u"~5E0",
554 u"0–3E0",
555 u"~0E0",
556 u"3E0 – 3E3",
557 u"3–5E3",
558 u"4.999–5.001E3",
559 u"~5E3",
560 u"5E3 – 5E6");
561
562 // TODO: Test compact currency?
563 // The code is not smart enough to differentiate the notation from the unit.
564}
565
566void NumberRangeFormatterTest::testIdentity() {
567 assertFormatRange(
568 u"Identity fallback Range",
569 NumberRangeFormatter::with().identityFallback(UNUM_IDENTITY_FALLBACK_RANGE),
570 Locale("en-us"),
571 u"1–5",
572 u"5–5",
573 u"5–5",
574 u"0–3",
575 u"0–0",
576 u"3–3,000",
577 u"3,000–5,000",
578 u"4,999–5,001",
579 u"5,000–5,000",
580 u"5,000–5,000,000");
581
582 assertFormatRange(
583 u"Identity fallback Approximately or Single Value",
584 NumberRangeFormatter::with().identityFallback(UNUM_IDENTITY_FALLBACK_APPROXIMATELY_OR_SINGLE_VALUE),
585 Locale("en-us"),
586 u"1–5",
587 u"~5",
588 u"5",
589 u"0–3",
590 u"0",
591 u"3–3,000",
592 u"3,000–5,000",
593 u"4,999–5,001",
594 u"5,000",
595 u"5,000–5,000,000");
596
597 assertFormatRange(
598 u"Identity fallback Single Value",
599 NumberRangeFormatter::with().identityFallback(UNUM_IDENTITY_FALLBACK_SINGLE_VALUE),
600 Locale("en-us"),
601 u"1–5",
602 u"5",
603 u"5",
604 u"0–3",
605 u"0",
606 u"3–3,000",
607 u"3,000–5,000",
608 u"4,999–5,001",
609 u"5,000",
610 u"5,000–5,000,000");
611
612 assertFormatRange(
613 u"Identity fallback Approximately or Single Value with compact notation",
614 NumberRangeFormatter::with()
615 .identityFallback(UNUM_IDENTITY_FALLBACK_APPROXIMATELY_OR_SINGLE_VALUE)
616 .numberFormatterBoth(NumberFormatter::with().notation(Notation::compactShort())),
617 Locale("en-us"),
618 u"1–5",
619 u"~5",
620 u"5",
621 u"0–3",
622 u"0",
623 u"3–3K",
624 u"3K – 5K",
625 u"~5K",
626 u"5K",
627 u"5K – 5M");
628
629 assertFormatRange(
630 u"Approximately in middle of unit string",
631 NumberRangeFormatter::with().numberFormatterBoth(
632 NumberFormatter::with().unit(FAHRENHEIT).unitWidth(UNUM_UNIT_WIDTH_FULL_NAME)),
633 Locale("zh-Hant"),
634 u"華氏1-5度",
635 u"華氏~5度",
636 u"華氏~5度",
637 u"華氏0-3度",
638 u"華氏~0度",
639 u"華氏3-3,000度",
640 u"華氏3,000-5,000度",
641 u"華氏4,999-5,001度",
642 u"華氏~5,000度",
643 u"華氏5,000-5,000,000度");
644}
645
646void NumberRangeFormatterTest::testDifferentFormatters() {
647 assertFormatRange(
648 u"Different rounding rules",
649 NumberRangeFormatter::with()
650 .numberFormatterFirst(NumberFormatter::with().precision(Precision::integer()))
651 .numberFormatterSecond(NumberFormatter::with().precision(Precision::fixedSignificantDigits(2))),
652 Locale("en-us"),
653 u"1–5.0",
654 u"5–5.0",
655 u"5–5.0",
656 u"0–3.0",
657 u"0–0.0",
658 u"3–3,000",
659 u"3,000–5,000",
660 u"4,999–5,000",
661 u"5,000–5,000", // TODO: Should this one be ~5,000?
662 u"5,000–5,000,000");
663}
664
665void NumberRangeFormatterTest::testPlurals() {
666 IcuTestErrorCode status(*this, "testPlurals");
667
668 // Locale sl has interesting plural forms:
669 // GBP{
670 // one{"britanski funt"}
671 // two{"britanska funta"}
672 // few{"britanski funti"}
673 // other{"britanskih funtov"}
674 // }
675 Locale locale("sl");
676
677 UnlocalizedNumberFormatter unf = NumberFormatter::with()
678 .unit(GBP)
679 .unitWidth(UNUM_UNIT_WIDTH_FULL_NAME)
680 .precision(Precision::integer());
681 LocalizedNumberFormatter lnf = unf.locale(locale);
682
683 // For comparison, run the non-range version of the formatter
684 assertEquals(Int64ToUnicodeString(1), u"1 britanski funt", lnf.formatDouble(1, status).toString(status));
685 assertEquals(Int64ToUnicodeString(2), u"2 britanska funta", lnf.formatDouble(2, status).toString(status));
686 assertEquals(Int64ToUnicodeString(3), u"3 britanski funti", lnf.formatDouble(3, status).toString(status));
687 assertEquals(Int64ToUnicodeString(5), u"5 britanskih funtov", lnf.formatDouble(5, status).toString(status));
688 if (status.errIfFailureAndReset()) { return; }
689
690 LocalizedNumberRangeFormatter lnrf = NumberRangeFormatter::with()
691 .numberFormatterBoth(unf)
692 .identityFallback(UNUM_IDENTITY_FALLBACK_RANGE)
693 .locale(locale);
694
695 struct TestCase {
696 double first;
697 double second;
698 const char16_t* expected;
699 } cases[] = {
700 {1, 1, u"1–1 britanski funti"}, // one + one -> few
701 {1, 2, u"1–2 britanska funta"}, // one + two -> two
702 {1, 3, u"1–3 britanski funti"}, // one + few -> few
703 {1, 5, u"1–5 britanskih funtov"}, // one + other -> other
704 {2, 1, u"2–1 britanski funti"}, // two + one -> few
705 {2, 2, u"2–2 britanska funta"}, // two + two -> two
706 {2, 3, u"2–3 britanski funti"}, // two + few -> few
707 {2, 5, u"2–5 britanskih funtov"}, // two + other -> other
708 {3, 1, u"3–1 britanski funti"}, // few + one -> few
709 {3, 2, u"3–2 britanska funta"}, // few + two -> two
710 {3, 3, u"3–3 britanski funti"}, // few + few -> few
711 {3, 5, u"3–5 britanskih funtov"}, // few + other -> other
712 {5, 1, u"5–1 britanski funti"}, // other + one -> few
713 {5, 2, u"5–2 britanska funta"}, // other + two -> two
714 {5, 3, u"5–3 britanski funti"}, // other + few -> few
715 {5, 5, u"5–5 britanskih funtov"}, // other + other -> other
716 };
717 for (auto& cas : cases) {
718 UnicodeString message = Int64ToUnicodeString(static_cast<int64_t>(cas.first));
719 message += u" ";
720 message += Int64ToUnicodeString(static_cast<int64_t>(cas.second));
721 status.setScope(message);
722 UnicodeString actual = lnrf.formatFormattableRange(cas.first, cas.second, status).toString(status);
723 assertEquals(message, cas.expected, actual);
724 status.errIfFailureAndReset();
725 }
726}
727
728void NumberRangeFormatterTest::testFieldPositions() {
729 {
730 const char16_t* message = u"Field position test 1";
731 const char16_t* expectedString = u"3K – 5K m";
732 FormattedNumberRange result = assertFormattedRangeEquals(
733 message,
734 NumberRangeFormatter::with()
735 .numberFormatterBoth(NumberFormatter::with()
736 .unit(METER)
737 .notation(Notation::compactShort()))
738 .locale("en-us"),
739 3000,
740 5000,
741 expectedString);
742 static const UFieldPosition expectedFieldPositions[] = {
743 // field, begin index, end index
744 {UNUM_INTEGER_FIELD, 0, 1},
745 {UNUM_COMPACT_FIELD, 1, 2},
746 {UNUM_INTEGER_FIELD, 5, 6},
747 {UNUM_COMPACT_FIELD, 6, 7},
748 {UNUM_MEASURE_UNIT_FIELD, 8, 9}};
749 checkFormattedValue(
750 message,
751 result,
752 expectedString,
753 UFIELD_CATEGORY_NUMBER,
754 expectedFieldPositions,
755 UPRV_LENGTHOF(expectedFieldPositions));
756 }
757
758 {
759 const char16_t* message = u"Field position test 2";
760 const char16_t* expectedString = u"87,654,321–98,765,432";
761 FormattedNumberRange result = assertFormattedRangeEquals(
762 message,
763 NumberRangeFormatter::withLocale("en-us"),
764 87654321,
765 98765432,
766 expectedString);
767 static const UFieldPosition expectedFieldPositions[] = {
768 // field, begin index, end index
769 {UNUM_GROUPING_SEPARATOR_FIELD, 2, 3},
770 {UNUM_GROUPING_SEPARATOR_FIELD, 6, 7},
771 {UNUM_INTEGER_FIELD, 0, 10},
772 {UNUM_GROUPING_SEPARATOR_FIELD, 13, 14},
773 {UNUM_GROUPING_SEPARATOR_FIELD, 17, 18},
774 {UNUM_INTEGER_FIELD, 11, 21}};
775 checkFormattedValue(
776 message,
777 result,
778 expectedString,
779 UFIELD_CATEGORY_NUMBER,
780 expectedFieldPositions,
781 UPRV_LENGTHOF(expectedFieldPositions));
782 }
783}
784
785void NumberRangeFormatterTest::testCopyMove() {
786 IcuTestErrorCode status(*this, "testCopyMove");
787
788 // Default constructors
789 LocalizedNumberRangeFormatter l1;
790 assertEquals("Initial behavior", u"1–5", l1.formatFormattableRange(1, 5, status).toString(status));
791 if (status.errDataIfFailureAndReset()) { return; }
792
793 // Setup
794 l1 = NumberRangeFormatter::withLocale("fr-FR")
795 .numberFormatterBoth(NumberFormatter::with().unit(USD));
796 assertEquals("Currency behavior", u"1,00–5,00 $US", l1.formatFormattableRange(1, 5, status).toString(status));
797
798 // Copy constructor
799 LocalizedNumberRangeFormatter l2 = l1;
800 assertEquals("Copy constructor", u"1,00–5,00 $US", l2.formatFormattableRange(1, 5, status).toString(status));
801
802 // Move constructor
803 LocalizedNumberRangeFormatter l3 = std::move(l1);
804 assertEquals("Move constructor", u"1,00–5,00 $US", l3.formatFormattableRange(1, 5, status).toString(status));
805
806 // Reset objects for assignment tests
807 l1 = NumberRangeFormatter::withLocale("en-us");
808 l2 = NumberRangeFormatter::withLocale("en-us");
809 assertEquals("Rest behavior, l1", u"1–5", l1.formatFormattableRange(1, 5, status).toString(status));
810 assertEquals("Rest behavior, l2", u"1–5", l2.formatFormattableRange(1, 5, status).toString(status));
811
812 // Copy assignment
813 l1 = l3;
814 assertEquals("Copy constructor", u"1,00–5,00 $US", l1.formatFormattableRange(1, 5, status).toString(status));
815
816 // Move assignment
817 l2 = std::move(l3);
818 assertEquals("Copy constructor", u"1,00–5,00 $US", l2.formatFormattableRange(1, 5, status).toString(status));
819
820 // FormattedNumberRange
821 FormattedNumberRange result = l1.formatFormattableRange(1, 5, status);
822 assertEquals("FormattedNumberRange move constructor", u"1,00–5,00 $US", result.toString(status));
823 result = l1.formatFormattableRange(3, 6, status);
824 assertEquals("FormattedNumberRange move assignment", u"3,00–6,00 $US", result.toString(status));
825}
826
827void NumberRangeFormatterTest::toObject() {
828 IcuTestErrorCode status(*this, "toObject");
829
830 // const lvalue version
831 {
832 LocalizedNumberRangeFormatter lnf = NumberRangeFormatter::withLocale("en");
833 LocalPointer<LocalizedNumberRangeFormatter> lnf2(lnf.clone());
834 assertFalse("should create successfully, const lvalue", lnf2.isNull());
835 assertEquals("object API test, const lvalue", u"5–7",
836 lnf2->formatFormattableRange(5, 7, status).toString(status));
837 }
838
839 // rvalue reference version
840 {
841 LocalPointer<LocalizedNumberRangeFormatter> lnf(
842 NumberRangeFormatter::withLocale("en").clone());
843 assertFalse("should create successfully, rvalue reference", lnf.isNull());
844 assertEquals("object API test, rvalue reference", u"5–7",
845 lnf->formatFormattableRange(5, 7, status).toString(status));
846 }
847
848 // to std::unique_ptr via assignment
849 {
850 std::unique_ptr<LocalizedNumberRangeFormatter> lnf =
851 NumberRangeFormatter::withLocale("en").clone();
852 assertTrue("should create successfully, unique_ptr B", static_cast<bool>(lnf));
853 assertEquals("object API test, unique_ptr B", u"5–7",
854 lnf->formatFormattableRange(5, 7, status).toString(status));
855 }
856
857 // make sure no memory leaks
858 {
859 NumberRangeFormatter::with().clone();
860 }
861}
862
863void NumberRangeFormatterTest::assertFormatRange(
864 const char16_t* message,
865 const UnlocalizedNumberRangeFormatter& f,
866 Locale locale,
867 const char16_t* expected_10_50,
868 const char16_t* expected_49_51,
869 const char16_t* expected_50_50,
870 const char16_t* expected_00_30,
871 const char16_t* expected_00_00,
872 const char16_t* expected_30_3K,
873 const char16_t* expected_30K_50K,
874 const char16_t* expected_49K_51K,
875 const char16_t* expected_50K_50K,
876 const char16_t* expected_50K_50M) {
877 LocalizedNumberRangeFormatter l = f.locale(locale);
878 assertFormattedRangeEquals(message, l, 1, 5, expected_10_50);
879 assertFormattedRangeEquals(message, l, 4.9999999, 5.0000001, expected_49_51);
880 assertFormattedRangeEquals(message, l, 5, 5, expected_50_50);
881 assertFormattedRangeEquals(message, l, 0, 3, expected_00_30);
882 assertFormattedRangeEquals(message, l, 0, 0, expected_00_00);
883 assertFormattedRangeEquals(message, l, 3, 3000, expected_30_3K);
884 assertFormattedRangeEquals(message, l, 3000, 5000, expected_30K_50K);
885 assertFormattedRangeEquals(message, l, 4999, 5001, expected_49K_51K);
886 assertFormattedRangeEquals(message, l, 5000, 5000, expected_50K_50K);
887 assertFormattedRangeEquals(message, l, 5e3, 5e6, expected_50K_50M);
888}
889
890FormattedNumberRange NumberRangeFormatterTest::assertFormattedRangeEquals(
891 const char16_t* message,
892 const LocalizedNumberRangeFormatter& l,
893 double first,
894 double second,
895 const char16_t* expected) {
896 IcuTestErrorCode status(*this, "assertFormattedRangeEquals");
897 UnicodeString fullMessage = UnicodeString(message) + u": " + DoubleToUnicodeString(first) + u", " + DoubleToUnicodeString(second);
898 status.setScope(fullMessage);
899 FormattedNumberRange fnr = l.formatFormattableRange(first, second, status);
900 UnicodeString actual = fnr.toString(status);
901 assertEquals(fullMessage, expected, actual);
902 return fnr;
903}
904
905
906#endif