1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 /********************************************************************
5 * Copyright (c) 1997-2015, International Business Machines Corporation and
6 * others. All Rights Reserved.
7 ********************************************************************/
9 #include "unicode/utypes.h"
11 #if !UCONFIG_NO_FORMATTING
15 #include "unicode/currpinf.h"
16 #include "unicode/dcfmtsym.h"
17 #include "unicode/decimfmt.h"
18 #include "unicode/fmtable.h"
19 #include "unicode/localpointer.h"
20 #include "unicode/parseerr.h"
21 #include "unicode/stringpiece.h"
24 #include "plurrule_impl.h"
25 #include "number_decimalquantity.h"
29 // This is an API test, not a unit test. It doesn't test very many cases, and doesn't
30 // try to test the full functionality. It just calls each function in the class and
31 // verifies that it works on a basic level.
33 void IntlTestDecimalFormatAPI::runIndexedTest( int32_t index
, UBool exec
, const char* &name
, char* /*par*/ )
35 if (exec
) logln((UnicodeString
)"TestSuite DecimalFormatAPI");
37 case 0: name
= "DecimalFormat API test";
39 logln((UnicodeString
)"DecimalFormat API test---"); logln((UnicodeString
)"");
40 UErrorCode status
= U_ZERO_ERROR
;
42 Locale::setDefault(Locale::getEnglish(), status
);
43 if(U_FAILURE(status
)) {
44 errln((UnicodeString
)"ERROR: Could not set default locale, test may not give correct results");
47 Locale::setDefault(saveLocale
, status
);
50 case 1: name
= "Rounding test";
52 logln((UnicodeString
)"DecimalFormat Rounding test---");
53 testRounding(/*par*/);
56 case 2: name
= "Test6354";
58 logln((UnicodeString
)"DecimalFormat Rounding Increment test---");
59 testRoundingInc(/*par*/);
62 case 3: name
= "TestCurrencyPluralInfo";
64 logln((UnicodeString
)"CurrencyPluralInfo API test---");
65 TestCurrencyPluralInfo();
68 case 4: name
= "TestScale";
70 logln((UnicodeString
)"Scale test---");
74 case 5: name
= "TestFixedDecimal";
76 logln((UnicodeString
)"TestFixedDecimal ---");
80 case 6: name
= "TestBadFastpath";
82 logln((UnicodeString
)"TestBadFastpath ---");
86 case 7: name
= "TestRequiredDecimalPoint";
88 logln((UnicodeString
)"TestRequiredDecimalPoint ---");
89 TestRequiredDecimalPoint();
92 case 8: name
= "testErrorCode";
94 logln((UnicodeString
)"testErrorCode ---");
98 case 9: name
= "testInvalidObject";
100 logln((UnicodeString
) "testInvalidObject ---");
104 default: name
= ""; break;
109 * This test checks various generic API methods in DecimalFormat to achieve 100%
112 void IntlTestDecimalFormatAPI::testAPI(/*char *par*/)
114 UErrorCode status
= U_ZERO_ERROR
;
116 // ======= Test constructors
118 logln((UnicodeString
)"Testing DecimalFormat constructors");
120 DecimalFormat
def(status
);
121 if(U_FAILURE(status
)) {
122 errcheckln(status
, "ERROR: Could not create DecimalFormat (default) - %s", u_errorName(status
));
127 status
= U_ZERO_ERROR
;
128 DecimalFormat
noGrouping("###0.##", status
);
129 assertEquals("Grouping size should be 0 for no grouping.", 0, noGrouping
.getGroupingSize());
130 noGrouping
.setGroupingUsed(TRUE
);
131 assertEquals("Grouping size should still be 0.", 0, noGrouping
.getGroupingSize());
134 // bug 13442 comment 14
135 status
= U_ZERO_ERROR
;
137 DecimalFormat
df("0", {"en", status
}, status
);
138 UnicodeString result
;
139 assertEquals("pat 0: ", 0, df
.getGroupingSize());
140 assertEquals("pat 0: ", (UBool
) FALSE
, (UBool
) df
.isGroupingUsed());
141 df
.setGroupingUsed(false);
142 assertEquals("pat 0 then disabled: ", 0, df
.getGroupingSize());
143 assertEquals("pat 0 then disabled: ", u
"1111", df
.format(1111, result
.remove()));
144 df
.setGroupingUsed(true);
145 assertEquals("pat 0 then enabled: ", 0, df
.getGroupingSize());
146 assertEquals("pat 0 then enabled: ", u
"1111", df
.format(1111, result
.remove()));
149 DecimalFormat
df("#,##0", {"en", status
}, status
);
150 UnicodeString result
;
151 assertEquals("pat #,##0: ", 3, df
.getGroupingSize());
152 assertEquals("pat #,##0: ", (UBool
) TRUE
, (UBool
) df
.isGroupingUsed());
153 df
.setGroupingUsed(false);
154 assertEquals("pat #,##0 then disabled: ", 3, df
.getGroupingSize());
155 assertEquals("pat #,##0 then disabled: ", u
"1111", df
.format(1111, result
.remove()));
156 df
.setGroupingUsed(true);
157 assertEquals("pat #,##0 then enabled: ", 3, df
.getGroupingSize());
158 assertEquals("pat #,##0 then enabled: ", u
"1,111", df
.format(1111, result
.remove()));
160 // end bug 13442 comment 14
162 status
= U_ZERO_ERROR
;
163 const UnicodeString
pattern("#,##0.# FF");
164 DecimalFormat
pat(pattern
, status
);
165 if(U_FAILURE(status
)) {
166 errln((UnicodeString
)"ERROR: Could not create DecimalFormat (pattern)");
170 status
= U_ZERO_ERROR
;
171 DecimalFormatSymbols
*symbols
= new DecimalFormatSymbols(Locale::getFrench(), status
);
172 if(U_FAILURE(status
)) {
173 errln((UnicodeString
)"ERROR: Could not create DecimalFormatSymbols (French)");
177 status
= U_ZERO_ERROR
;
178 DecimalFormat
cust1(pattern
, symbols
, status
);
179 if(U_FAILURE(status
)) {
180 errln((UnicodeString
)"ERROR: Could not create DecimalFormat (pattern, symbols*)");
183 status
= U_ZERO_ERROR
;
184 DecimalFormat
cust2(pattern
, *symbols
, status
);
185 if(U_FAILURE(status
)) {
186 errln((UnicodeString
)"ERROR: Could not create DecimalFormat (pattern, symbols)");
189 DecimalFormat
copy(pat
);
191 // ======= Test clone(), assignment, and equality
193 logln((UnicodeString
)"Testing clone(), assignment and equality operators");
195 if( ! (copy
== pat
) || copy
!= pat
) {
196 errln((UnicodeString
)"ERROR: Copy constructor or == failed");
201 errln((UnicodeString
)"ERROR: Assignment (or !=) failed");
204 Format
*clone
= def
.clone();
205 if( ! (*clone
== def
) ) {
206 errln((UnicodeString
)"ERROR: Clone() failed");
210 // ======= Test various format() methods
212 logln((UnicodeString
)"Testing various format() methods");
214 double d
= -10456.0037;
215 int32_t l
= 100000000;
219 UnicodeString res1
, res2
, res3
, res4
;
220 FieldPosition
pos1(FieldPosition::DONT_CARE
), pos2(FieldPosition::DONT_CARE
), pos3(FieldPosition::DONT_CARE
), pos4(FieldPosition::DONT_CARE
);
222 res1
= def
.format(d
, res1
, pos1
);
223 logln( (UnicodeString
) "" + (int32_t) d
+ " formatted to " + res1
);
225 res2
= pat
.format(l
, res2
, pos2
);
226 logln((UnicodeString
) "" + (int32_t) l
+ " formatted to " + res2
);
228 status
= U_ZERO_ERROR
;
229 res3
= cust1
.format(fD
, res3
, pos3
, status
);
230 if(U_FAILURE(status
)) {
231 errln((UnicodeString
)"ERROR: format(Formattable [double]) failed");
233 logln((UnicodeString
) "" + (int32_t) fD
.getDouble() + " formatted to " + res3
);
235 status
= U_ZERO_ERROR
;
236 res4
= cust2
.format(fL
, res4
, pos4
, status
);
237 if(U_FAILURE(status
)) {
238 errln((UnicodeString
)"ERROR: format(Formattable [long]) failed");
240 logln((UnicodeString
) "" + fL
.getLong() + " formatted to " + res4
);
242 // ======= Test parse()
244 logln((UnicodeString
)"Testing parse()");
246 UnicodeString
text("-10,456.0037");
247 Formattable result1
, result2
;
248 ParsePosition
pos(0);
249 UnicodeString
patt("#,##0.#");
250 status
= U_ZERO_ERROR
;
251 pat
.applyPattern(patt
, status
);
252 if(U_FAILURE(status
)) {
253 errln((UnicodeString
)"ERROR: applyPattern() failed");
255 pat
.parse(text
, result1
, pos
);
256 if(result1
.getType() != Formattable::kDouble
&& result1
.getDouble() != d
) {
257 errln((UnicodeString
)"ERROR: Roundtrip failed (via parse()) for " + text
);
259 logln(text
+ " parsed into " + (int32_t) result1
.getDouble());
261 status
= U_ZERO_ERROR
;
262 pat
.parse(text
, result2
, status
);
263 if(U_FAILURE(status
)) {
264 errln((UnicodeString
)"ERROR: parse() failed");
266 if(result2
.getType() != Formattable::kDouble
&& result2
.getDouble() != d
) {
267 errln((UnicodeString
)"ERROR: Roundtrip failed (via parse()) for " + text
);
269 logln(text
+ " parsed into " + (int32_t) result2
.getDouble());
271 // ======= Test getters and setters
273 logln((UnicodeString
)"Testing getters and setters");
275 const DecimalFormatSymbols
*syms
= pat
.getDecimalFormatSymbols();
276 DecimalFormatSymbols
*newSyms
= new DecimalFormatSymbols(*syms
);
277 def
.setDecimalFormatSymbols(*newSyms
);
278 def
.adoptDecimalFormatSymbols(newSyms
); // don't use newSyms after this
279 if( *(pat
.getDecimalFormatSymbols()) != *(def
.getDecimalFormatSymbols())) {
280 errln((UnicodeString
)"ERROR: adopt or set DecimalFormatSymbols() failed");
283 UnicodeString posPrefix
;
284 pat
.setPositivePrefix("+");
285 posPrefix
= pat
.getPositivePrefix(posPrefix
);
286 logln((UnicodeString
)"Positive prefix (should be +): " + posPrefix
);
287 if(posPrefix
!= "+") {
288 errln((UnicodeString
)"ERROR: setPositivePrefix() failed");
291 UnicodeString negPrefix
;
292 pat
.setNegativePrefix("-");
293 negPrefix
= pat
.getNegativePrefix(negPrefix
);
294 logln((UnicodeString
)"Negative prefix (should be -): " + negPrefix
);
295 if(negPrefix
!= "-") {
296 errln((UnicodeString
)"ERROR: setNegativePrefix() failed");
299 UnicodeString posSuffix
;
300 pat
.setPositiveSuffix("_");
301 posSuffix
= pat
.getPositiveSuffix(posSuffix
);
302 logln((UnicodeString
)"Positive suffix (should be _): " + posSuffix
);
303 if(posSuffix
!= "_") {
304 errln((UnicodeString
)"ERROR: setPositiveSuffix() failed");
307 UnicodeString negSuffix
;
308 pat
.setNegativeSuffix("~");
309 negSuffix
= pat
.getNegativeSuffix(negSuffix
);
310 logln((UnicodeString
)"Negative suffix (should be ~): " + negSuffix
);
311 if(negSuffix
!= "~") {
312 errln((UnicodeString
)"ERROR: setNegativeSuffix() failed");
315 int32_t multiplier
= 0;
316 pat
.setMultiplier(8);
317 multiplier
= pat
.getMultiplier();
318 logln((UnicodeString
)"Multiplier (should be 8): " + multiplier
);
319 if(multiplier
!= 8) {
320 errln((UnicodeString
)"ERROR: setMultiplier() failed");
323 int32_t groupingSize
= 0;
324 pat
.setGroupingSize(2);
325 groupingSize
= pat
.getGroupingSize();
326 logln((UnicodeString
)"Grouping size (should be 2): " + (int32_t) groupingSize
);
327 if(groupingSize
!= 2) {
328 errln((UnicodeString
)"ERROR: setGroupingSize() failed");
331 pat
.setDecimalSeparatorAlwaysShown(TRUE
);
332 UBool tf
= pat
.isDecimalSeparatorAlwaysShown();
333 logln((UnicodeString
)"DecimalSeparatorIsAlwaysShown (should be TRUE) is " + (UnicodeString
) (tf
? "TRUE" : "FALSE"));
335 errln((UnicodeString
)"ERROR: setDecimalSeparatorAlwaysShown() failed");
337 // Added by Ken Liu testing set/isExponentSignAlwaysShown
338 pat
.setExponentSignAlwaysShown(TRUE
);
339 UBool esas
= pat
.isExponentSignAlwaysShown();
340 logln((UnicodeString
)"ExponentSignAlwaysShown (should be TRUE) is " + (UnicodeString
) (esas
? "TRUE" : "FALSE"));
342 errln((UnicodeString
)"ERROR: ExponentSignAlwaysShown() failed");
345 // Added by Ken Liu testing set/isScientificNotation
346 pat
.setScientificNotation(TRUE
);
347 UBool sn
= pat
.isScientificNotation();
348 logln((UnicodeString
)"isScientificNotation (should be TRUE) is " + (UnicodeString
) (sn
? "TRUE" : "FALSE"));
350 errln((UnicodeString
)"ERROR: setScientificNotation() failed");
353 // Added by Ken Liu testing set/getMinimumExponentDigits
354 int8_t MinimumExponentDigits
= 0;
355 pat
.setMinimumExponentDigits(2);
356 MinimumExponentDigits
= pat
.getMinimumExponentDigits();
357 logln((UnicodeString
)"MinimumExponentDigits (should be 2) is " + (int8_t) MinimumExponentDigits
);
358 if(MinimumExponentDigits
!= 2) {
359 errln((UnicodeString
)"ERROR: setMinimumExponentDigits() failed");
362 // Added by Ken Liu testing set/getRoundingIncrement
363 double RoundingIncrement
= 0.0;
364 pat
.setRoundingIncrement(2.0);
365 RoundingIncrement
= pat
.getRoundingIncrement();
366 logln((UnicodeString
)"RoundingIncrement (should be 2.0) is " + (double) RoundingIncrement
);
367 if(RoundingIncrement
!= 2.0) {
368 errln((UnicodeString
)"ERROR: setRoundingIncrement() failed");
370 //end of Ken's Adding
372 UnicodeString funkyPat
;
373 funkyPat
= pat
.toPattern(funkyPat
);
374 logln((UnicodeString
)"Pattern is " + funkyPat
);
376 UnicodeString locPat
;
377 locPat
= pat
.toLocalizedPattern(locPat
);
378 logln((UnicodeString
)"Localized pattern is " + locPat
);
380 // ======= Test applyPattern()
382 logln((UnicodeString
)"Testing applyPattern()");
383 pat
= DecimalFormat(status
); // reset
385 UnicodeString
p1("#,##0.0#;(#,##0.0#)");
386 logln((UnicodeString
)"Applying pattern " + p1
);
387 status
= U_ZERO_ERROR
;
388 pat
.applyPattern(p1
, status
);
389 if(U_FAILURE(status
)) {
390 errln((UnicodeString
)"ERROR: applyPattern() failed with " + (int32_t) status
);
393 s2
= pat
.toPattern(s2
);
394 logln((UnicodeString
)"Extracted pattern is " + s2
);
395 assertEquals("toPattern() result did not match pattern applied", p1
, s2
);
397 if(pat
.getSecondaryGroupingSize() != 0) {
398 errln("FAIL: Secondary Grouping Size should be 0, not %d\n", pat
.getSecondaryGroupingSize());
401 if(pat
.getGroupingSize() != 3) {
402 errln("FAIL: Primary Grouping Size should be 3, not %d\n", pat
.getGroupingSize());
405 UnicodeString
p2("#,##,##0.0# FF;(#,##,##0.0# FF)");
406 logln((UnicodeString
)"Applying pattern " + p2
);
407 status
= U_ZERO_ERROR
;
408 pat
.applyLocalizedPattern(p2
, status
);
409 if(U_FAILURE(status
)) {
410 errln((UnicodeString
)"ERROR: applyPattern() failed with " + (int32_t) status
);
413 s3
= pat
.toLocalizedPattern(s3
);
414 logln((UnicodeString
)"Extracted pattern is " + s3
);
415 assertEquals("toLocalizedPattern() result did not match pattern applied", p2
, s3
);
417 status
= U_ZERO_ERROR
;
419 pat
.applyLocalizedPattern(p2
, pe
, status
);
420 if(U_FAILURE(status
)) {
421 errln((UnicodeString
)"ERROR: applyPattern((with ParseError)) failed with " + (int32_t) status
);
424 s4
= pat
.toLocalizedPattern(s3
);
425 logln((UnicodeString
)"Extracted pattern is " + s4
);
426 assertEquals("toLocalizedPattern(with ParseErr) result did not match pattern applied", p2
, s4
);
428 if(pat
.getSecondaryGroupingSize() != 2) {
429 errln("FAIL: Secondary Grouping Size should be 2, not %d\n", pat
.getSecondaryGroupingSize());
432 if(pat
.getGroupingSize() != 3) {
433 errln("FAIL: Primary Grouping Size should be 3, not %d\n", pat
.getGroupingSize());
436 // ======= Test getStaticClassID()
438 logln((UnicodeString
)"Testing getStaticClassID()");
440 status
= U_ZERO_ERROR
;
441 NumberFormat
*test
= new DecimalFormat(status
);
442 if(U_FAILURE(status
)) {
443 errln((UnicodeString
)"ERROR: Couldn't create a DecimalFormat");
446 if(test
->getDynamicClassID() != DecimalFormat::getStaticClassID()) {
447 errln((UnicodeString
)"ERROR: getDynamicClassID() didn't return the expected value");
453 void IntlTestDecimalFormatAPI::TestCurrencyPluralInfo(){
454 UErrorCode status
= U_ZERO_ERROR
;
456 LocalPointer
<CurrencyPluralInfo
>cpi(new CurrencyPluralInfo(status
), status
);
457 if(U_FAILURE(status
)) {
458 errln((UnicodeString
)"ERROR: CurrencyPluralInfo(UErrorCode) could not be created");
462 CurrencyPluralInfo cpi1
= *cpi
;
464 if(cpi
->getDynamicClassID() != CurrencyPluralInfo::getStaticClassID()){
465 errln((UnicodeString
)"ERROR: CurrencyPluralInfo::getDynamicClassID() didn't return the expected value");
468 cpi
->setCurrencyPluralPattern("","",status
);
469 if(U_FAILURE(status
)) {
470 errln((UnicodeString
)"ERROR: CurrencyPluralInfo::setCurrencyPluralPattern");
473 cpi
->setLocale(Locale::getCanada(), status
);
474 if(U_FAILURE(status
)) {
475 errln((UnicodeString
)"ERROR: CurrencyPluralInfo::setLocale");
478 cpi
->setPluralRules("",status
);
479 if(U_FAILURE(status
)) {
480 errln((UnicodeString
)"ERROR: CurrencyPluralInfo::setPluralRules");
483 LocalPointer
<DecimalFormat
>df(new DecimalFormat(status
));
484 if(U_FAILURE(status
)) {
485 errcheckln(status
, "ERROR: Could not create DecimalFormat - %s", u_errorName(status
));
489 df
->adoptCurrencyPluralInfo(cpi
.orphan());
491 df
->getCurrencyPluralInfo();
493 df
->setCurrencyPluralInfo(cpi1
);
497 void IntlTestDecimalFormatAPI::testRounding(/*char *par*/)
499 UErrorCode status
= U_ZERO_ERROR
;
500 double Roundingnumber
= 2.55;
501 double Roundingnumber1
= -2.55;
502 //+2.55 results -2.55 results
503 double result
[]={ 3.0, -2.0, // kRoundCeiling 0,
504 2.0, -3.0, // kRoundFloor 1,
505 2.0, -2.0, // kRoundDown 2,
506 3.0, -3.0, // kRoundUp 3,
507 3.0, -3.0, // kRoundHalfEven 4,
508 3.0, -3.0, // kRoundHalfDown 5,
509 3.0, -3.0 // kRoundHalfUp 6
511 DecimalFormat
pat(status
);
512 if(U_FAILURE(status
)) {
513 errcheckln(status
, "ERROR: Could not create DecimalFormat (default) - %s", u_errorName(status
));
518 UnicodeString message
;
519 UnicodeString resultStr
;
520 for(mode
=0;mode
< 7;mode
++){
521 pat
.setRoundingMode((DecimalFormat::ERoundingMode
)mode
);
522 if(pat
.getRoundingMode() != (DecimalFormat::ERoundingMode
)mode
){
523 errln((UnicodeString
)"SetRoundingMode or GetRoundingMode failed for mode=" + mode
);
527 //for +2.55 with RoundingIncrement=1.0
528 pat
.setRoundingIncrement(1.0);
529 pat
.format(Roundingnumber
, resultStr
);
530 message
= (UnicodeString
)"round(" + (double)Roundingnumber
+ UnicodeString(",") + mode
+ UnicodeString(",FALSE) with RoundingIncrement=1.0==>");
531 verify(message
, resultStr
, result
[i
++]);
535 //for -2.55 with RoundingIncrement=1.0
536 pat
.format(Roundingnumber1
, resultStr
);
537 message
= (UnicodeString
)"round(" + (double)Roundingnumber1
+ UnicodeString(",") + mode
+ UnicodeString(",FALSE) with RoundingIncrement=1.0==>");
538 verify(message
, resultStr
, result
[i
++]);
544 void IntlTestDecimalFormatAPI::verify(const UnicodeString
& message
, const UnicodeString
& got
, double expected
){
545 logln((UnicodeString
)message
+ got
+ (UnicodeString
)" Expected : " + expected
);
546 UnicodeString
expectedStr("");
547 expectedStr
=expectedStr
+ expected
;
548 if(got
!= expectedStr
) {
549 errln((UnicodeString
)"ERROR: " + message
+ got
+ (UnicodeString
)" Expected : " + expectedStr
);
553 void IntlTestDecimalFormatAPI::verifyString(const UnicodeString
& message
, const UnicodeString
& got
, UnicodeString
& expected
){
554 logln((UnicodeString
)message
+ got
+ (UnicodeString
)" Expected : " + expected
);
555 if(got
!= expected
) {
556 errln((UnicodeString
)"ERROR: " + message
+ got
+ (UnicodeString
)" Expected : " + expected
);
560 void IntlTestDecimalFormatAPI::testRoundingInc(/*char *par*/)
562 UErrorCode status
= U_ZERO_ERROR
;
563 DecimalFormat
pat(UnicodeString("#,##0.00"),status
);
564 if(U_FAILURE(status
)) {
565 errcheckln(status
, "ERROR: Could not create DecimalFormat (default) - %s", u_errorName(status
));
569 // get default rounding increment
570 double roundingInc
= pat
.getRoundingIncrement();
571 if (roundingInc
!= 0.0) {
572 errln((UnicodeString
)"ERROR: Rounding increment not zero");
576 // With rounding now being handled by decNumber, we no longer
577 // set a rounding increment to enable non-default mode rounding,
578 // checking of which was the original point of this test.
580 // set rounding mode with zero increment. Rounding
581 // increment should not be set by this operation
582 pat
.setRoundingMode((DecimalFormat::ERoundingMode
)0);
583 roundingInc
= pat
.getRoundingIncrement();
584 if (roundingInc
!= 0.0) {
585 errln((UnicodeString
)"ERROR: Rounding increment not zero after setRoundingMode");
590 void IntlTestDecimalFormatAPI::TestScale()
592 typedef struct TestData
{
595 const char *expectedOutput
;
598 static TestData testData
[] = {
599 { 100.0, 3, "100,000" },
600 { 10034.0, -2, "100.34" },
601 { 0.86, -3, "0.0009" },
602 { -0.000455, 1, "-0%" },
603 { -0.000555, 1, "-1%" },
604 { 0.000455, 1, "0%" },
605 { 0.000555, 1, "1%" },
608 UErrorCode status
= U_ZERO_ERROR
;
609 DecimalFormat
pat(status
);
610 if(U_FAILURE(status
)) {
611 errcheckln(status
, "ERROR: Could not create DecimalFormat (default) - %s", u_errorName(status
));
615 UnicodeString message
;
616 UnicodeString resultStr
;
618 UnicodeString
percentPattern("#,##0%");
619 pat
.setMaximumFractionDigits(4);
621 for(int32_t i
=0; i
< UPRV_LENGTHOF(testData
); i
++) {
623 pat
.applyPattern(percentPattern
,status
);
625 // Test both the attribute and the setter
627 pat
.setAttribute(UNUM_SCALE
, testData
[i
].inputScale
,status
);
628 assertEquals("", testData
[i
].inputScale
, pat
.getMultiplierScale());
630 pat
.setMultiplierScale(testData
[i
].inputScale
);
631 assertEquals("", testData
[i
].inputScale
, pat
.getAttribute(UNUM_SCALE
, status
));
633 pat
.format(testData
[i
].inputValue
, resultStr
);
634 message
= UnicodeString("Unexpected output for ") + testData
[i
].inputValue
+ UnicodeString(" and scale ") +
635 testData
[i
].inputScale
+ UnicodeString(". Got: ");
636 exp
= testData
[i
].expectedOutput
;
637 verifyString(message
, resultStr
, exp
);
645 #define ASSERT_EQUAL(expect, actual) UPRV_BLOCK_MACRO_BEGIN { \
646 /* ICU-20080: Use temporary variables to avoid strange compiler behaviour \
647 (with the nice side-effect of avoiding repeated function calls too). */ \
648 auto lhs = (expect); \
649 auto rhs = (actual); \
651 sprintf(tmp, "(%g==%g)", (double)lhs, (double)rhs); \
652 assertTrue(tmp, (lhs==rhs), FALSE, TRUE, __FILE__, __LINE__); \
653 } UPRV_BLOCK_MACRO_END
655 #if defined(_MSC_VER)
656 // Ignore the noisy warning 4805 (comparisons between int and bool) in the function below as we use the ICU TRUE/FALSE macros
657 // which are int values, whereas some of the DecimalQuantity methods return C++ bools.
658 #pragma warning(push)
659 #pragma warning(disable: 4805)
661 void IntlTestDecimalFormatAPI::TestFixedDecimal() {
662 UErrorCode status
= U_ZERO_ERROR
;
664 LocalPointer
<DecimalFormat
> df(new DecimalFormat("###", status
), status
);
665 assertSuccess(WHERE
, status
);
666 if (status
== U_MISSING_RESOURCE_ERROR
) {
669 number::impl::DecimalQuantity fd
;
670 df
->formatToDecimalQuantity(44, fd
, status
);
671 assertSuccess(WHERE
, status
);
672 ASSERT_EQUAL(44, fd
.getPluralOperand(PLURAL_OPERAND_N
));
673 ASSERT_EQUAL(0, fd
.getPluralOperand(PLURAL_OPERAND_V
));
674 ASSERT_EQUAL(FALSE
, fd
.isNegative());
676 df
->formatToDecimalQuantity(-44, fd
, status
);
677 assertSuccess(WHERE
, status
);
678 ASSERT_EQUAL(44, fd
.getPluralOperand(PLURAL_OPERAND_N
));
679 ASSERT_EQUAL(0, fd
.getPluralOperand(PLURAL_OPERAND_V
));
680 ASSERT_EQUAL(TRUE
, fd
.isNegative());
682 df
.adoptInsteadAndCheckErrorCode(new DecimalFormat("###.00##", status
), status
);
683 assertSuccess(WHERE
, status
);
684 df
->formatToDecimalQuantity(123.456, fd
, status
);
685 assertSuccess(WHERE
, status
);
686 ASSERT_EQUAL(3, fd
.getPluralOperand(PLURAL_OPERAND_V
)); // v
687 ASSERT_EQUAL(456, fd
.getPluralOperand(PLURAL_OPERAND_F
)); // f
688 ASSERT_EQUAL(456, fd
.getPluralOperand(PLURAL_OPERAND_T
)); // t
689 ASSERT_EQUAL(123, fd
.getPluralOperand(PLURAL_OPERAND_I
)); // i
690 ASSERT_EQUAL(123.456, fd
.getPluralOperand(PLURAL_OPERAND_N
)); // n
691 ASSERT_EQUAL(FALSE
, fd
.hasIntegerValue());
692 ASSERT_EQUAL(FALSE
, fd
.isNegative());
694 df
->formatToDecimalQuantity(-123.456, fd
, status
);
695 assertSuccess(WHERE
, status
);
696 ASSERT_EQUAL(3, fd
.getPluralOperand(PLURAL_OPERAND_V
)); // v
697 ASSERT_EQUAL(456, fd
.getPluralOperand(PLURAL_OPERAND_F
)); // f
698 ASSERT_EQUAL(456, fd
.getPluralOperand(PLURAL_OPERAND_T
)); // t
699 ASSERT_EQUAL(123, fd
.getPluralOperand(PLURAL_OPERAND_I
)); // i
700 ASSERT_EQUAL(123.456, fd
.getPluralOperand(PLURAL_OPERAND_N
)); // n
701 ASSERT_EQUAL(FALSE
, fd
.hasIntegerValue());
702 ASSERT_EQUAL(TRUE
, fd
.isNegative());
704 // test max int digits
705 df
->setMaximumIntegerDigits(2);
706 df
->formatToDecimalQuantity(123.456, fd
, status
);
707 assertSuccess(WHERE
, status
);
708 ASSERT_EQUAL(3, fd
.getPluralOperand(PLURAL_OPERAND_V
)); // v
709 ASSERT_EQUAL(456, fd
.getPluralOperand(PLURAL_OPERAND_F
)); // f
710 ASSERT_EQUAL(456, fd
.getPluralOperand(PLURAL_OPERAND_T
)); // t
711 ASSERT_EQUAL(23, fd
.getPluralOperand(PLURAL_OPERAND_I
)); // i
712 ASSERT_EQUAL(23.456, fd
.getPluralOperand(PLURAL_OPERAND_N
)); // n
713 ASSERT_EQUAL(FALSE
, fd
.hasIntegerValue());
714 ASSERT_EQUAL(FALSE
, fd
.isNegative());
716 df
->formatToDecimalQuantity(-123.456, fd
, status
);
717 assertSuccess(WHERE
, status
);
718 ASSERT_EQUAL(3, fd
.getPluralOperand(PLURAL_OPERAND_V
)); // v
719 ASSERT_EQUAL(456, fd
.getPluralOperand(PLURAL_OPERAND_F
)); // f
720 ASSERT_EQUAL(456, fd
.getPluralOperand(PLURAL_OPERAND_T
)); // t
721 ASSERT_EQUAL(23, fd
.getPluralOperand(PLURAL_OPERAND_I
)); // i
722 ASSERT_EQUAL(23.456, fd
.getPluralOperand(PLURAL_OPERAND_N
)); // n
723 ASSERT_EQUAL(FALSE
, fd
.hasIntegerValue());
724 ASSERT_EQUAL(TRUE
, fd
.isNegative());
726 // test max fraction digits
727 df
->setMaximumIntegerDigits(2000000000);
728 df
->setMaximumFractionDigits(2);
729 df
->formatToDecimalQuantity(123.456, fd
, status
);
730 assertSuccess(WHERE
, status
);
731 ASSERT_EQUAL(2, fd
.getPluralOperand(PLURAL_OPERAND_V
)); // v
732 ASSERT_EQUAL(46, fd
.getPluralOperand(PLURAL_OPERAND_F
)); // f
733 ASSERT_EQUAL(46, fd
.getPluralOperand(PLURAL_OPERAND_T
)); // t
734 ASSERT_EQUAL(123, fd
.getPluralOperand(PLURAL_OPERAND_I
)); // i
735 ASSERT_EQUAL(123.46, fd
.getPluralOperand(PLURAL_OPERAND_N
)); // n
736 ASSERT_EQUAL(FALSE
, fd
.hasIntegerValue());
737 ASSERT_EQUAL(FALSE
, fd
.isNegative());
739 df
->formatToDecimalQuantity(-123.456, fd
, status
);
740 assertSuccess(WHERE
, status
);
741 ASSERT_EQUAL(2, fd
.getPluralOperand(PLURAL_OPERAND_V
)); // v
742 ASSERT_EQUAL(46, fd
.getPluralOperand(PLURAL_OPERAND_F
)); // f
743 ASSERT_EQUAL(46, fd
.getPluralOperand(PLURAL_OPERAND_T
)); // t
744 ASSERT_EQUAL(123, fd
.getPluralOperand(PLURAL_OPERAND_I
)); // i
745 ASSERT_EQUAL(123.46, fd
.getPluralOperand(PLURAL_OPERAND_N
)); // n
746 ASSERT_EQUAL(FALSE
, fd
.hasIntegerValue());
747 ASSERT_EQUAL(TRUE
, fd
.isNegative());
749 // test esoteric rounding
750 df
->setMaximumFractionDigits(6);
751 df
->setRoundingIncrement(7.3);
753 df
->formatToDecimalQuantity(30.0, fd
, status
);
754 assertSuccess(WHERE
, status
);
755 ASSERT_EQUAL(2, fd
.getPluralOperand(PLURAL_OPERAND_V
)); // v
756 ASSERT_EQUAL(20, fd
.getPluralOperand(PLURAL_OPERAND_F
)); // f
757 ASSERT_EQUAL(2, fd
.getPluralOperand(PLURAL_OPERAND_T
)); // t
758 ASSERT_EQUAL(29, fd
.getPluralOperand(PLURAL_OPERAND_I
)); // i
759 ASSERT_EQUAL(29.2, fd
.getPluralOperand(PLURAL_OPERAND_N
)); // n
760 ASSERT_EQUAL(FALSE
, fd
.hasIntegerValue());
761 ASSERT_EQUAL(FALSE
, fd
.isNegative());
763 df
->formatToDecimalQuantity(-30.0, fd
, status
);
764 assertSuccess(WHERE
, status
);
765 ASSERT_EQUAL(2, fd
.getPluralOperand(PLURAL_OPERAND_V
)); // v
766 ASSERT_EQUAL(20, fd
.getPluralOperand(PLURAL_OPERAND_F
)); // f
767 ASSERT_EQUAL(2, fd
.getPluralOperand(PLURAL_OPERAND_T
)); // t
768 ASSERT_EQUAL(29, fd
.getPluralOperand(PLURAL_OPERAND_I
)); // i
769 ASSERT_EQUAL(29.2, fd
.getPluralOperand(PLURAL_OPERAND_N
)); // n
770 ASSERT_EQUAL(FALSE
, fd
.hasIntegerValue());
771 ASSERT_EQUAL(TRUE
, fd
.isNegative());
773 df
.adoptInsteadAndCheckErrorCode(new DecimalFormat("###", status
), status
);
774 assertSuccess(WHERE
, status
);
775 df
->formatToDecimalQuantity(123.456, fd
, status
);
776 assertSuccess(WHERE
, status
);
777 ASSERT_EQUAL(0, fd
.getPluralOperand(PLURAL_OPERAND_V
));
778 ASSERT_EQUAL(0, fd
.getPluralOperand(PLURAL_OPERAND_F
));
779 ASSERT_EQUAL(0, fd
.getPluralOperand(PLURAL_OPERAND_T
));
780 ASSERT_EQUAL(123, fd
.getPluralOperand(PLURAL_OPERAND_I
));
781 ASSERT_EQUAL(TRUE
, fd
.hasIntegerValue());
782 ASSERT_EQUAL(FALSE
, fd
.isNegative());
784 df
.adoptInsteadAndCheckErrorCode(new DecimalFormat("###.0", status
), status
);
785 assertSuccess(WHERE
, status
);
786 df
->formatToDecimalQuantity(123.01, fd
, status
);
787 assertSuccess(WHERE
, status
);
788 ASSERT_EQUAL(1, fd
.getPluralOperand(PLURAL_OPERAND_V
));
789 ASSERT_EQUAL(0, fd
.getPluralOperand(PLURAL_OPERAND_F
));
790 ASSERT_EQUAL(0, fd
.getPluralOperand(PLURAL_OPERAND_T
));
791 ASSERT_EQUAL(123, fd
.getPluralOperand(PLURAL_OPERAND_I
));
792 ASSERT_EQUAL(TRUE
, fd
.hasIntegerValue());
793 ASSERT_EQUAL(FALSE
, fd
.isNegative());
795 df
.adoptInsteadAndCheckErrorCode(new DecimalFormat("###.0", status
), status
);
796 assertSuccess(WHERE
, status
);
797 df
->formatToDecimalQuantity(123.06, fd
, status
);
798 assertSuccess(WHERE
, status
);
799 ASSERT_EQUAL(1, fd
.getPluralOperand(PLURAL_OPERAND_V
));
800 ASSERT_EQUAL(1, fd
.getPluralOperand(PLURAL_OPERAND_F
));
801 ASSERT_EQUAL(1, fd
.getPluralOperand(PLURAL_OPERAND_T
));
802 ASSERT_EQUAL(123, fd
.getPluralOperand(PLURAL_OPERAND_I
));
803 ASSERT_EQUAL(FALSE
, fd
.hasIntegerValue());
804 ASSERT_EQUAL(FALSE
, fd
.isNegative());
806 df
.adoptInsteadAndCheckErrorCode(new DecimalFormat("@@@@@", status
), status
); // Significant Digits
807 assertSuccess(WHERE
, status
);
808 df
->formatToDecimalQuantity(123, fd
, status
);
809 assertSuccess(WHERE
, status
);
810 ASSERT_EQUAL(2, fd
.getPluralOperand(PLURAL_OPERAND_V
));
811 ASSERT_EQUAL(0, fd
.getPluralOperand(PLURAL_OPERAND_F
));
812 ASSERT_EQUAL(0, fd
.getPluralOperand(PLURAL_OPERAND_T
));
813 ASSERT_EQUAL(123, fd
.getPluralOperand(PLURAL_OPERAND_I
));
814 ASSERT_EQUAL(TRUE
, fd
.hasIntegerValue());
815 ASSERT_EQUAL(FALSE
, fd
.isNegative());
817 df
.adoptInsteadAndCheckErrorCode(new DecimalFormat("@@@@@", status
), status
); // Significant Digits
818 assertSuccess(WHERE
, status
);
819 df
->formatToDecimalQuantity(1.23, fd
, status
);
820 assertSuccess(WHERE
, status
);
821 ASSERT_EQUAL(4, fd
.getPluralOperand(PLURAL_OPERAND_V
));
822 ASSERT_EQUAL(2300, fd
.getPluralOperand(PLURAL_OPERAND_F
));
823 ASSERT_EQUAL(23, fd
.getPluralOperand(PLURAL_OPERAND_T
));
824 ASSERT_EQUAL(1, fd
.getPluralOperand(PLURAL_OPERAND_I
));
825 ASSERT_EQUAL(FALSE
, fd
.hasIntegerValue());
826 ASSERT_EQUAL(FALSE
, fd
.isNegative());
828 df
->formatToDecimalQuantity(uprv_getInfinity(), fd
, status
);
829 assertSuccess(WHERE
, status
);
830 ASSERT_EQUAL(TRUE
, fd
.isNaN() || fd
.isInfinite());
831 df
->formatToDecimalQuantity(0.0, fd
, status
);
832 ASSERT_EQUAL(FALSE
, fd
.isNaN() || fd
.isInfinite());
833 df
->formatToDecimalQuantity(uprv_getNaN(), fd
, status
);
834 ASSERT_EQUAL(TRUE
, fd
.isNaN() || fd
.isInfinite());
835 assertSuccess(WHERE
, status
);
837 // Test Big Decimal input.
838 // 22 digits before and after decimal, will exceed the precision of a double
839 // and force DecimalFormat::getFixedDecimal() to work with a digit list.
840 df
.adoptInsteadAndCheckErrorCode(
841 new DecimalFormat("#####################0.00####################", status
), status
);
842 assertSuccess(WHERE
, status
);
843 Formattable
fable("12.34", status
);
844 assertSuccess(WHERE
, status
);
845 df
->formatToDecimalQuantity(fable
, fd
, status
);
846 assertSuccess(WHERE
, status
);
847 ASSERT_EQUAL(2, fd
.getPluralOperand(PLURAL_OPERAND_V
));
848 ASSERT_EQUAL(34, fd
.getPluralOperand(PLURAL_OPERAND_F
));
849 ASSERT_EQUAL(34, fd
.getPluralOperand(PLURAL_OPERAND_T
));
850 ASSERT_EQUAL(12, fd
.getPluralOperand(PLURAL_OPERAND_I
));
851 ASSERT_EQUAL(FALSE
, fd
.hasIntegerValue());
852 ASSERT_EQUAL(FALSE
, fd
.isNegative());
854 fable
.setDecimalNumber("12.3456789012345678900123456789", status
);
855 assertSuccess(WHERE
, status
);
856 df
->formatToDecimalQuantity(fable
, fd
, status
);
857 assertSuccess(WHERE
, status
);
858 ASSERT_EQUAL(22, fd
.getPluralOperand(PLURAL_OPERAND_V
));
859 ASSERT_EQUAL(3456789012345678900LL, fd
.getPluralOperand(PLURAL_OPERAND_F
));
860 ASSERT_EQUAL(34567890123456789LL, fd
.getPluralOperand(PLURAL_OPERAND_T
));
861 ASSERT_EQUAL(12, fd
.getPluralOperand(PLURAL_OPERAND_I
));
862 ASSERT_EQUAL(FALSE
, fd
.hasIntegerValue());
863 ASSERT_EQUAL(FALSE
, fd
.isNegative());
865 // On field overflow, Integer part is truncated on the left, fraction part on the right.
866 fable
.setDecimalNumber("123456789012345678901234567890.123456789012345678901234567890", status
);
867 assertSuccess(WHERE
, status
);
868 df
->formatToDecimalQuantity(fable
, fd
, status
);
869 assertSuccess(WHERE
, status
);
870 ASSERT_EQUAL(22, fd
.getPluralOperand(PLURAL_OPERAND_V
));
871 ASSERT_EQUAL(1234567890123456789LL, fd
.getPluralOperand(PLURAL_OPERAND_F
));
872 ASSERT_EQUAL(1234567890123456789LL, fd
.getPluralOperand(PLURAL_OPERAND_T
));
873 ASSERT_EQUAL(345678901234567890LL, fd
.getPluralOperand(PLURAL_OPERAND_I
));
874 ASSERT_EQUAL(FALSE
, fd
.hasIntegerValue());
875 ASSERT_EQUAL(FALSE
, fd
.isNegative());
877 // Digits way to the right of the decimal but within the format's precision aren't truncated
878 fable
.setDecimalNumber("1.0000000000000000000012", status
);
879 assertSuccess(WHERE
, status
);
880 df
->formatToDecimalQuantity(fable
, fd
, status
);
881 assertSuccess(WHERE
, status
);
882 ASSERT_EQUAL(22, fd
.getPluralOperand(PLURAL_OPERAND_V
));
883 ASSERT_EQUAL(12, fd
.getPluralOperand(PLURAL_OPERAND_F
));
884 ASSERT_EQUAL(12, fd
.getPluralOperand(PLURAL_OPERAND_T
));
885 ASSERT_EQUAL(1, fd
.getPluralOperand(PLURAL_OPERAND_I
));
886 ASSERT_EQUAL(FALSE
, fd
.hasIntegerValue());
887 ASSERT_EQUAL(FALSE
, fd
.isNegative());
889 // Digits beyond the precision of the format are rounded away
890 fable
.setDecimalNumber("1.000000000000000000000012", status
);
891 assertSuccess(WHERE
, status
);
892 df
->formatToDecimalQuantity(fable
, fd
, status
);
893 assertSuccess(WHERE
, status
);
894 ASSERT_EQUAL(2, fd
.getPluralOperand(PLURAL_OPERAND_V
));
895 ASSERT_EQUAL(0, fd
.getPluralOperand(PLURAL_OPERAND_F
));
896 ASSERT_EQUAL(0, fd
.getPluralOperand(PLURAL_OPERAND_T
));
897 ASSERT_EQUAL(1, fd
.getPluralOperand(PLURAL_OPERAND_I
));
898 ASSERT_EQUAL(TRUE
, fd
.hasIntegerValue());
899 ASSERT_EQUAL(FALSE
, fd
.isNegative());
901 // Negative numbers come through
902 fable
.setDecimalNumber("-1.0000000000000000000012", status
);
903 assertSuccess(WHERE
, status
);
904 df
->formatToDecimalQuantity(fable
, fd
, status
);
905 assertSuccess(WHERE
, status
);
906 ASSERT_EQUAL(22, fd
.getPluralOperand(PLURAL_OPERAND_V
));
907 ASSERT_EQUAL(12, fd
.getPluralOperand(PLURAL_OPERAND_F
));
908 ASSERT_EQUAL(12, fd
.getPluralOperand(PLURAL_OPERAND_T
));
909 ASSERT_EQUAL(1, fd
.getPluralOperand(PLURAL_OPERAND_I
));
910 ASSERT_EQUAL(FALSE
, fd
.hasIntegerValue());
911 ASSERT_EQUAL(TRUE
, fd
.isNegative());
913 // MinFractionDigits from format larger than from number.
914 fable
.setDecimalNumber("1000000000000000000000.3", status
);
915 assertSuccess(WHERE
, status
);
916 df
->formatToDecimalQuantity(fable
, fd
, status
);
917 assertSuccess(WHERE
, status
);
918 ASSERT_EQUAL(2, fd
.getPluralOperand(PLURAL_OPERAND_V
));
919 ASSERT_EQUAL(30, fd
.getPluralOperand(PLURAL_OPERAND_F
));
920 ASSERT_EQUAL(3, fd
.getPluralOperand(PLURAL_OPERAND_T
));
921 ASSERT_EQUAL(0, fd
.getPluralOperand(PLURAL_OPERAND_I
));
922 ASSERT_EQUAL(FALSE
, fd
.hasIntegerValue());
923 ASSERT_EQUAL(FALSE
, fd
.isNegative());
925 fable
.setDecimalNumber("1000000000000000050000.3", status
);
926 assertSuccess(WHERE
, status
);
927 df
->formatToDecimalQuantity(fable
, fd
, status
);
928 assertSuccess(WHERE
, status
);
929 ASSERT_EQUAL(2, fd
.getPluralOperand(PLURAL_OPERAND_V
));
930 ASSERT_EQUAL(30, fd
.getPluralOperand(PLURAL_OPERAND_F
));
931 ASSERT_EQUAL(3, fd
.getPluralOperand(PLURAL_OPERAND_T
));
932 ASSERT_EQUAL(50000LL, fd
.getPluralOperand(PLURAL_OPERAND_I
));
933 ASSERT_EQUAL(FALSE
, fd
.hasIntegerValue());
934 ASSERT_EQUAL(FALSE
, fd
.isNegative());
936 // Test some int64_t values that are out of the range of a double
937 fable
.setInt64(4503599627370496LL);
938 assertSuccess(WHERE
, status
);
939 df
->formatToDecimalQuantity(fable
, fd
, status
);
940 assertSuccess(WHERE
, status
);
941 ASSERT_EQUAL(2, fd
.getPluralOperand(PLURAL_OPERAND_V
));
942 ASSERT_EQUAL(0, fd
.getPluralOperand(PLURAL_OPERAND_F
));
943 ASSERT_EQUAL(0, fd
.getPluralOperand(PLURAL_OPERAND_T
));
944 ASSERT_EQUAL(4503599627370496LL, fd
.getPluralOperand(PLURAL_OPERAND_I
));
945 ASSERT_EQUAL(TRUE
, fd
.hasIntegerValue());
946 ASSERT_EQUAL(FALSE
, fd
.isNegative());
948 fable
.setInt64(4503599627370497LL);
949 assertSuccess(WHERE
, status
);
950 df
->formatToDecimalQuantity(fable
, fd
, status
);
951 assertSuccess(WHERE
, status
);
952 ASSERT_EQUAL(2, fd
.getPluralOperand(PLURAL_OPERAND_V
));
953 ASSERT_EQUAL(0, fd
.getPluralOperand(PLURAL_OPERAND_F
));
954 ASSERT_EQUAL(0, fd
.getPluralOperand(PLURAL_OPERAND_T
));
955 ASSERT_EQUAL(4503599627370497LL, fd
.getPluralOperand(PLURAL_OPERAND_I
));
956 ASSERT_EQUAL(TRUE
, fd
.hasIntegerValue());
957 ASSERT_EQUAL(FALSE
, fd
.isNegative());
959 fable
.setInt64(9223372036854775807LL);
960 assertSuccess(WHERE
, status
);
961 df
->formatToDecimalQuantity(fable
, fd
, status
);
962 assertSuccess(WHERE
, status
);
963 ASSERT_EQUAL(2, fd
.getPluralOperand(PLURAL_OPERAND_V
));
964 ASSERT_EQUAL(0, fd
.getPluralOperand(PLURAL_OPERAND_F
));
965 ASSERT_EQUAL(0, fd
.getPluralOperand(PLURAL_OPERAND_T
));
966 // note: going through DigitList path to FixedDecimal, which is trimming
967 // int64_t fields to 18 digits. See ticket Ticket #10374
968 ASSERT_EQUAL(223372036854775807LL, fd
.getPluralOperand(PLURAL_OPERAND_I
));
969 ASSERT_EQUAL(TRUE
, fd
.hasIntegerValue());
970 ASSERT_EQUAL(FALSE
, fd
.isNegative());
973 #if defined(_MSC_VER)
974 // Re-enable 4805 warnings (comparisons between int and bool).
978 void IntlTestDecimalFormatAPI::TestBadFastpath() {
979 UErrorCode status
= U_ZERO_ERROR
;
981 LocalPointer
<DecimalFormat
> df(new DecimalFormat("###", status
), status
);
982 if (U_FAILURE(status
)) {
983 dataerrln("Error creating new DecimalFormat - %s", u_errorName(status
));
989 assertEquals("Format 1234", "1234", df
->format((int32_t)1234, fmt
));
990 df
->setGroupingUsed(FALSE
);
992 assertEquals("Format 1234", "1234", df
->format((int32_t)1234, fmt
));
993 df
->setGroupingUsed(TRUE
);
994 df
->setGroupingSize(3);
996 assertEquals("Format 1234 w/ grouping", "1,234", df
->format((int32_t)1234, fmt
));
999 void IntlTestDecimalFormatAPI::TestRequiredDecimalPoint() {
1000 UErrorCode status
= U_ZERO_ERROR
;
1001 UnicodeString
text("99");
1002 Formattable result1
;
1003 UnicodeString
pat1("##.0000");
1004 UnicodeString
pat2("00.0");
1006 LocalPointer
<DecimalFormat
> df(new DecimalFormat(pat1
, status
), status
);
1007 if (U_FAILURE(status
)) {
1008 dataerrln("Error creating new DecimalFormat - %s", u_errorName(status
));
1012 status
= U_ZERO_ERROR
;
1013 df
->applyPattern(pat1
, status
);
1014 if(U_FAILURE(status
)) {
1015 errln((UnicodeString
)"ERROR: applyPattern() failed");
1017 df
->parse(text
, result1
, status
);
1018 if(U_FAILURE(status
)) {
1019 errln((UnicodeString
)"ERROR: parse() failed");
1021 df
->setDecimalPatternMatchRequired(TRUE
);
1022 df
->parse(text
, result1
, status
);
1023 if(U_SUCCESS(status
)) {
1024 errln((UnicodeString
)"ERROR: unexpected parse()");
1028 status
= U_ZERO_ERROR
;
1029 df
->applyPattern(pat2
, status
);
1030 df
->setDecimalPatternMatchRequired(FALSE
);
1031 if(U_FAILURE(status
)) {
1032 errln((UnicodeString
)"ERROR: applyPattern(2) failed");
1034 df
->parse(text
, result1
, status
);
1035 if(U_FAILURE(status
)) {
1036 errln((UnicodeString
)"ERROR: parse(2) failed - " + u_errorName(status
));
1038 df
->setDecimalPatternMatchRequired(TRUE
);
1039 df
->parse(text
, result1
, status
);
1040 if(U_SUCCESS(status
)) {
1041 errln((UnicodeString
)"ERROR: unexpected parse(2)");
1045 void IntlTestDecimalFormatAPI::testErrorCode() {
1046 // Try each DecimalFormat constructor with an errorCode set on input,
1047 // Verify no crashes or leaks, and that the errorCode is not altered.
1049 UErrorCode status
= U_ZERO_ERROR
;
1050 const UnicodeString
pattern(u
"0.###E0");
1052 DecimalFormatSymbols
symbols(Locale::getUS(), status
);
1053 assertSuccess(WHERE
, status
);
1056 status
= U_INTERNAL_PROGRAM_ERROR
;
1057 DecimalFormat
df(status
);
1058 assertEquals(WHERE
, U_INTERNAL_PROGRAM_ERROR
, status
);
1061 status
= U_INTERNAL_PROGRAM_ERROR
;
1062 DecimalFormat
df(pattern
, status
);
1063 assertEquals(WHERE
, U_INTERNAL_PROGRAM_ERROR
, status
);
1066 status
= U_INTERNAL_PROGRAM_ERROR
;
1067 DecimalFormat
df(pattern
, new DecimalFormatSymbols(symbols
), status
);
1068 assertEquals(WHERE
, U_INTERNAL_PROGRAM_ERROR
, status
);
1071 status
= U_INTERNAL_PROGRAM_ERROR
;
1072 DecimalFormat
df(pattern
, new DecimalFormatSymbols(symbols
), UNUM_DECIMAL_COMPACT_LONG
, status
);
1073 assertEquals(WHERE
, U_INTERNAL_PROGRAM_ERROR
, status
);
1076 status
= U_INTERNAL_PROGRAM_ERROR
;
1077 DecimalFormat
df(pattern
, new DecimalFormatSymbols(symbols
), pe
, status
);
1078 assertEquals(WHERE
, U_INTERNAL_PROGRAM_ERROR
, status
);
1081 status
= U_INTERNAL_PROGRAM_ERROR
;
1082 DecimalFormat
df(pattern
, symbols
,status
);
1083 assertEquals(WHERE
, U_INTERNAL_PROGRAM_ERROR
, status
);
1086 // Try each DecimalFormat method with an error code parameter, verifying that
1087 // an input error is not altered, and that no segmentation faults occur.
1089 status
= U_INTERNAL_PROGRAM_ERROR
;
1090 DecimalFormat
dfBogus(status
);
1091 assertEquals(WHERE
, U_INTERNAL_PROGRAM_ERROR
, status
);
1093 status
= U_ZERO_ERROR
;
1094 DecimalFormat
dfGood(pattern
, new DecimalFormatSymbols(symbols
), status
);
1095 assertSuccess(WHERE
, status
);
1097 for (DecimalFormat
*df
: {&dfBogus
, &dfGood
}) {
1098 status
= U_INTERNAL_PROGRAM_ERROR
;
1099 df
->setAttribute(UNUM_PARSE_INT_ONLY
, 0, status
);
1100 assertEquals(WHERE
, U_INTERNAL_PROGRAM_ERROR
, status
);
1102 status
= U_INTERNAL_PROGRAM_ERROR
;
1103 df
->getAttribute(UNUM_MAX_FRACTION_DIGITS
, status
);
1104 assertEquals(WHERE
, U_INTERNAL_PROGRAM_ERROR
, status
);
1106 status
= U_INTERNAL_PROGRAM_ERROR
;
1109 df
->format(1.2, dest
, fp
, status
);
1110 assertEquals(WHERE
, U_INTERNAL_PROGRAM_ERROR
, status
);
1112 status
= U_INTERNAL_PROGRAM_ERROR
;
1113 df
->format(1.2, dest
, nullptr, status
);
1114 assertEquals(WHERE
, U_INTERNAL_PROGRAM_ERROR
, status
);
1116 status
= U_INTERNAL_PROGRAM_ERROR
;
1117 df
->format((int32_t)666, dest
, nullptr, status
);
1118 assertEquals(WHERE
, U_INTERNAL_PROGRAM_ERROR
, status
);
1120 status
= U_INTERNAL_PROGRAM_ERROR
;
1121 df
->format((int64_t)666, dest
, nullptr, status
);
1122 assertEquals(WHERE
, U_INTERNAL_PROGRAM_ERROR
, status
);
1124 status
= U_INTERNAL_PROGRAM_ERROR
;
1125 df
->format(StringPiece("3.1415926535897932384626"), dest
, nullptr, status
);
1126 assertEquals(WHERE
, U_INTERNAL_PROGRAM_ERROR
, status
);
1128 status
= U_INTERNAL_PROGRAM_ERROR
;
1129 df
->applyPattern(pattern
, status
);
1130 assertEquals(WHERE
, U_INTERNAL_PROGRAM_ERROR
, status
);
1132 status
= U_INTERNAL_PROGRAM_ERROR
;
1133 df
->applyLocalizedPattern(pattern
, pe
, status
);
1134 assertEquals(WHERE
, U_INTERNAL_PROGRAM_ERROR
, status
);
1136 status
= U_INTERNAL_PROGRAM_ERROR
;
1137 df
->applyLocalizedPattern(pattern
, status
);
1138 assertEquals(WHERE
, U_INTERNAL_PROGRAM_ERROR
, status
);
1140 status
= U_INTERNAL_PROGRAM_ERROR
;
1141 df
->setCurrency(u
"USD", status
);
1142 assertEquals(WHERE
, U_INTERNAL_PROGRAM_ERROR
, status
);
1144 status
= U_INTERNAL_PROGRAM_ERROR
;
1145 df
->setCurrencyUsage(UCURR_USAGE_CASH
, &status
);
1146 assertEquals(WHERE
, U_INTERNAL_PROGRAM_ERROR
, status
);
1150 void IntlTestDecimalFormatAPI::testInvalidObject() {
1152 UErrorCode status
= U_INTERNAL_PROGRAM_ERROR
;
1153 DecimalFormat
dfBogus(status
);
1154 assertEquals(WHERE
, U_INTERNAL_PROGRAM_ERROR
, status
);
1156 status
= U_ZERO_ERROR
;
1157 DecimalFormat
dfGood(status
);
1158 assertSuccess(WHERE
, status
);
1160 // An invalid object should not be equal to a valid object.
1161 // This also tests that no segmentation fault occurs in the comparison operator due
1162 // to any dangling/nullptr pointers. (ICU-20381).
1163 assertTrue(WHERE
, dfGood
!= dfBogus
);
1165 status
= U_MEMORY_ALLOCATION_ERROR
;
1166 DecimalFormat
dfBogus2(status
);
1167 assertEquals(WHERE
, U_MEMORY_ALLOCATION_ERROR
, status
);
1169 // Two invalid objects should not be equal.
1170 // (Also verify that nullptr isn't t dereferenced in the comparision operator.)
1171 assertTrue(WHERE
, dfBogus
!= dfBogus2
);
1173 // Verify the comparison operator works for two valid objects.
1174 status
= U_ZERO_ERROR
;
1175 DecimalFormat
dfGood2(status
);
1176 assertSuccess(WHERE
, status
);
1177 assertTrue(WHERE
, dfGood
== dfGood2
);
1179 // Verify that the assignment operator sets the object to an invalid state, and
1180 // that no segmentation fault occurs due to any dangling/nullptr pointers.
1181 status
= U_INTERNAL_PROGRAM_ERROR
;
1182 DecimalFormat dfAssignmentBogus
= DecimalFormat(status
);
1183 // Verify comparison for the assigned object.
1184 assertTrue(WHERE
, dfAssignmentBogus
!= dfGood
);
1185 assertTrue(WHERE
, dfAssignmentBogus
!= dfGood2
);
1186 assertTrue(WHERE
, dfAssignmentBogus
!= dfBogus
);
1188 // Verify that cloning our original invalid object gives nullptr.
1189 auto dfBogusClone
= dfBogus
.clone();
1190 assertTrue(WHERE
, dfBogusClone
== nullptr);
1191 // Verify that cloning our assigned invalid object gives nullptr.
1192 auto dfBogusClone2
= dfAssignmentBogus
.clone();
1193 assertTrue(WHERE
, dfBogusClone2
== nullptr);
1195 // Verify copy constructing from an invalid object is also invalid.
1196 DecimalFormat
dfCopy(dfBogus
);
1197 assertTrue(WHERE
, dfCopy
!= dfGood
);
1198 assertTrue(WHERE
, dfCopy
!= dfGood2
);
1199 assertTrue(WHERE
, dfCopy
!= dfBogus
);
1200 DecimalFormat dfCopyAssign
= dfBogus
;
1201 assertTrue(WHERE
, dfCopyAssign
!= dfGood
);
1202 assertTrue(WHERE
, dfCopyAssign
!= dfGood2
);
1203 assertTrue(WHERE
, dfCopyAssign
!= dfBogus
);
1204 auto dfBogusCopyClone1
= dfCopy
.clone();
1205 auto dfBogusCopyClone2
= dfCopyAssign
.clone();
1206 assertTrue(WHERE
, dfBogusCopyClone1
== nullptr);
1207 assertTrue(WHERE
, dfBogusCopyClone2
== nullptr);
1211 // Try each DecimalFormat class method that lacks an error code parameter, verifying
1212 // we don't crash (segmentation fault) on invalid objects.
1214 UErrorCode status
= U_ZERO_ERROR
;
1215 const UnicodeString
pattern(u
"0.###E0");
1217 DecimalFormatSymbols
symbols(Locale::getUS(), status
);
1218 assertSuccess(WHERE
, status
);
1219 CurrencyPluralInfo
currencyPI(status
);
1220 assertSuccess(WHERE
, status
);
1222 status
= U_INTERNAL_PROGRAM_ERROR
;
1223 DecimalFormat
dfBogus1(status
);
1224 assertEquals(WHERE
, U_INTERNAL_PROGRAM_ERROR
, status
);
1226 status
= U_INTERNAL_PROGRAM_ERROR
;
1227 DecimalFormat
dfBogus2(pattern
, status
);
1228 assertEquals(WHERE
, U_INTERNAL_PROGRAM_ERROR
, status
);
1230 status
= U_INTERNAL_PROGRAM_ERROR
;
1231 DecimalFormat
dfBogus3(pattern
, new DecimalFormatSymbols(symbols
), status
);
1232 assertEquals(WHERE
, U_INTERNAL_PROGRAM_ERROR
, status
);
1234 status
= U_INTERNAL_PROGRAM_ERROR
;
1235 DecimalFormat
dfBogus4(pattern
, new DecimalFormatSymbols(symbols
), UNumberFormatStyle::UNUM_CURRENCY
, status
);
1236 assertEquals(WHERE
, U_INTERNAL_PROGRAM_ERROR
, status
);
1238 status
= U_INTERNAL_PROGRAM_ERROR
;
1239 DecimalFormat
dfBogus5(pattern
, new DecimalFormatSymbols(symbols
), pe
, status
);
1240 assertEquals(WHERE
, U_INTERNAL_PROGRAM_ERROR
, status
);
1242 for (DecimalFormat
*df
: {&dfBogus1
, &dfBogus2
, &dfBogus3
, &dfBogus4
, &dfBogus5
})
1244 df
->setGroupingUsed(true);
1246 df
->setParseIntegerOnly(false);
1248 df
->setLenient(true);
1250 auto dfClone
= df
->clone();
1251 assertTrue(WHERE
, dfClone
== nullptr);
1255 df
->format(1.2, dest
, fp
);
1256 df
->format(static_cast<int32_t>(1234), dest
, fp
);
1257 df
->format(static_cast<int64_t>(1234), dest
, fp
);
1259 UnicodeString
text("-1,234.00");
1261 ParsePosition
pos(0);
1262 df
->parse(text
, result
, pos
);
1264 CurrencyAmount
* ca
= df
->parseCurrency(text
, pos
);
1265 assertTrue(WHERE
, ca
== nullptr);
1267 const DecimalFormatSymbols
* dfs
= df
->getDecimalFormatSymbols();
1268 assertTrue(WHERE
, dfs
== nullptr);
1270 df
->adoptDecimalFormatSymbols(nullptr);
1272 df
->setDecimalFormatSymbols(symbols
);
1274 const CurrencyPluralInfo
* cpi
= df
->getCurrencyPluralInfo();
1275 assertTrue(WHERE
, cpi
== nullptr);
1277 df
->adoptCurrencyPluralInfo(nullptr);
1279 df
->setCurrencyPluralInfo(currencyPI
);
1281 UnicodeString
prefix("-123");
1282 df
->getPositivePrefix(dest
);
1283 df
->setPositivePrefix(prefix
);
1284 df
->getNegativePrefix(dest
);
1285 df
->setNegativePrefix(prefix
);
1286 df
->getPositiveSuffix(dest
);
1287 df
->setPositiveSuffix(prefix
);
1288 df
->getNegativeSuffix(dest
);
1289 df
->setNegativeSuffix(prefix
);
1291 df
->isSignAlwaysShown();
1293 df
->setSignAlwaysShown(true);
1295 df
->getMultiplier();
1296 df
->setMultiplier(10);
1298 df
->getMultiplierScale();
1299 df
->setMultiplierScale(2);
1301 df
->getRoundingIncrement();
1302 df
->setRoundingIncrement(1.2);
1304 df
->getRoundingMode();
1305 df
->setRoundingMode(DecimalFormat::ERoundingMode::kRoundDown
);
1307 df
->getFormatWidth();
1308 df
->setFormatWidth(0);
1310 UnicodeString
pad(" ");
1311 df
->getPadCharacterString();
1312 df
->setPadCharacter(pad
);
1314 df
->getPadPosition();
1315 df
->setPadPosition(DecimalFormat::EPadPosition::kPadBeforePrefix
);
1317 df
->isScientificNotation();
1318 df
->setScientificNotation(false);
1320 df
->getMinimumExponentDigits();
1321 df
->setMinimumExponentDigits(1);
1323 df
->isExponentSignAlwaysShown();
1324 df
->setExponentSignAlwaysShown(true);
1326 df
->getGroupingSize();
1327 df
->setGroupingSize(3);
1329 df
->getSecondaryGroupingSize();
1330 df
->setSecondaryGroupingSize(-1);
1332 df
->getMinimumGroupingDigits();
1333 df
->setMinimumGroupingDigits(-1);
1335 df
->isDecimalSeparatorAlwaysShown();
1336 df
->setDecimalSeparatorAlwaysShown(true);
1338 df
->isDecimalPatternMatchRequired();
1339 df
->setDecimalPatternMatchRequired(false);
1341 df
->isParseNoExponent();
1342 df
->setParseNoExponent(true);
1344 df
->isParseCaseSensitive();
1345 df
->setParseCaseSensitive(false);
1347 df
->isFormatFailIfMoreThanMaxDigits();
1348 df
->setFormatFailIfMoreThanMaxDigits(true);
1350 df
->toPattern(dest
);
1351 df
->toLocalizedPattern(dest
);
1353 df
->setMaximumIntegerDigits(10);
1354 df
->setMinimumIntegerDigits(0);
1356 df
->setMaximumFractionDigits(2);
1357 df
->setMinimumFractionDigits(0);
1359 df
->getMinimumSignificantDigits();
1360 df
->setMinimumSignificantDigits(0);
1362 df
->getMaximumSignificantDigits();
1363 df
->setMaximumSignificantDigits(5);
1365 df
->areSignificantDigitsUsed();
1366 df
->setSignificantDigitsUsed(true);
1368 df
->setCurrency(u
"USD");
1370 df
->getCurrencyUsage();
1372 const number::LocalizedNumberFormatter
* lnf
= df
->toNumberFormatter(status
);
1373 assertEquals("toNumberFormatter should return nullptr",
1374 (int64_t) nullptr, (int64_t) lnf
);
1376 // Should not crash when chaining to error code enabled methods on the LNF
1377 lnf
->formatInt(1, status
);
1378 lnf
->formatDouble(1.0, status
);
1379 lnf
->formatDecimal("1", status
);
1380 lnf
->toFormat(status
);
1381 lnf
->toSkeleton(status
);
1382 lnf
->copyErrorTo(status
);
1388 #endif /* #if !UCONFIG_NO_FORMATTING */