1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 /********************************************************************
4  * COPYRIGHT:
5  * Copyright (c) 1997-2015, International Business Machines Corporation and
6  * others. All Rights Reserved.
7  ********************************************************************/
8 
9 #include "unicode/utypes.h"
10 
11 #if !UCONFIG_NO_FORMATTING
12 
13 #include "dcfmapts.h"
14 
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"
22 
23 #include "putilimp.h"
24 #include "plurrule_impl.h"
25 #include "number_decimalquantity.h"
26 
27 #include <stdio.h>
28 
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.
32 
runIndexedTest(int32_t index,UBool exec,const char * & name,char *)33 void IntlTestDecimalFormatAPI::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
34 {
35     if (exec) logln((UnicodeString)"TestSuite DecimalFormatAPI");
36     switch (index) {
37         case 0: name = "DecimalFormat API test";
38                 if (exec) {
39                     logln((UnicodeString)"DecimalFormat API test---"); logln((UnicodeString)"");
40                     UErrorCode status = U_ZERO_ERROR;
41                     Locale saveLocale;
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");
45                     }
46                     testAPI(/*par*/);
47                     Locale::setDefault(saveLocale, status);
48                 }
49                 break;
50         case 1: name = "Rounding test";
51             if(exec) {
52                logln((UnicodeString)"DecimalFormat Rounding test---");
53                testRounding(/*par*/);
54             }
55             break;
56         case 2: name = "Test6354";
57             if(exec) {
58                logln((UnicodeString)"DecimalFormat Rounding Increment test---");
59                testRoundingInc(/*par*/);
60             }
61             break;
62         case 3: name = "TestCurrencyPluralInfo";
63             if(exec) {
64                logln((UnicodeString)"CurrencyPluralInfo API test---");
65                TestCurrencyPluralInfo();
66             }
67             break;
68         case 4: name = "TestScale";
69             if(exec) {
70                logln((UnicodeString)"Scale test---");
71                TestScale();
72             }
73             break;
74          case 5: name = "TestFixedDecimal";
75             if(exec) {
76                logln((UnicodeString)"TestFixedDecimal ---");
77                TestFixedDecimal();
78             }
79             break;
80          case 6: name = "TestBadFastpath";
81             if(exec) {
82                logln((UnicodeString)"TestBadFastpath ---");
83                TestBadFastpath();
84             }
85             break;
86          case 7: name = "TestRequiredDecimalPoint";
87             if(exec) {
88                logln((UnicodeString)"TestRequiredDecimalPoint ---");
89                TestRequiredDecimalPoint();
90             }
91             break;
92          case 8: name = "testErrorCode";
93             if(exec) {
94                logln((UnicodeString)"testErrorCode ---");
95                testErrorCode();
96             }
97             break;
98          case 9: name = "testInvalidObject";
99             if(exec) {
100                 logln((UnicodeString) "testInvalidObject ---");
101                 testInvalidObject();
102             }
103             break;
104        default: name = ""; break;
105     }
106 }
107 
108 /**
109  * This test checks various generic API methods in DecimalFormat to achieve 100%
110  * API coverage.
111  */
testAPI()112 void IntlTestDecimalFormatAPI::testAPI(/*char *par*/)
113 {
114     UErrorCode status = U_ZERO_ERROR;
115 
116 // ======= Test constructors
117 
118     logln((UnicodeString)"Testing DecimalFormat constructors");
119 
120     DecimalFormat def(status);
121     if(U_FAILURE(status)) {
122         errcheckln(status, "ERROR: Could not create DecimalFormat (default) - %s", u_errorName(status));
123         return;
124     }
125 
126     // bug 10864
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());
132     // end bug 10864
133 
134     // bug 13442 comment 14
135     status = U_ZERO_ERROR;
136     {
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()));
147     }
148     {
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()));
159     }
160     // end bug 13442 comment 14
161 
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)");
167         return;
168     }
169 
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)");
174         return;
175     }
176 
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*)");
181     }
182 
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)");
187     }
188 
189     DecimalFormat copy(pat);
190 
191 // ======= Test clone(), assignment, and equality
192 
193     logln((UnicodeString)"Testing clone(), assignment and equality operators");
194 
195     if( ! (copy == pat) || copy != pat) {
196         errln((UnicodeString)"ERROR: Copy constructor or == failed");
197     }
198 
199     copy = cust1;
200     if(copy != cust1) {
201         errln((UnicodeString)"ERROR: Assignment (or !=) failed");
202     }
203 
204     Format *clone = def.clone();
205     if( ! (*clone == def) ) {
206         errln((UnicodeString)"ERROR: Clone() failed");
207     }
208     delete clone;
209 
210 // ======= Test various format() methods
211 
212     logln((UnicodeString)"Testing various format() methods");
213 
214     double d = -10456.0037;
215     int32_t l = 100000000;
216     Formattable fD(d);
217     Formattable fL(l);
218 
219     UnicodeString res1, res2, res3, res4;
220     FieldPosition pos1(FieldPosition::DONT_CARE), pos2(FieldPosition::DONT_CARE), pos3(FieldPosition::DONT_CARE), pos4(FieldPosition::DONT_CARE);
221 
222     res1 = def.format(d, res1, pos1);
223     logln( (UnicodeString) "" + (int32_t) d + " formatted to " + res1);
224 
225     res2 = pat.format(l, res2, pos2);
226     logln((UnicodeString) "" + (int32_t) l + " formatted to " + res2);
227 
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");
232     }
233     logln((UnicodeString) "" + (int32_t) fD.getDouble() + " formatted to " + res3);
234 
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");
239     }
240     logln((UnicodeString) "" + fL.getLong() + " formatted to " + res4);
241 
242 // ======= Test parse()
243 
244     logln((UnicodeString)"Testing parse()");
245 
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");
254     }
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);
258     }
259     logln(text + " parsed into " + (int32_t) result1.getDouble());
260 
261     status = U_ZERO_ERROR;
262     pat.parse(text, result2, status);
263     if(U_FAILURE(status)) {
264         errln((UnicodeString)"ERROR: parse() failed");
265     }
266     if(result2.getType() != Formattable::kDouble && result2.getDouble() != d) {
267         errln((UnicodeString)"ERROR: Roundtrip failed (via parse()) for " + text);
268     }
269     logln(text + " parsed into " + (int32_t) result2.getDouble());
270 
271 // ======= Test getters and setters
272 
273     logln((UnicodeString)"Testing getters and setters");
274 
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");
281     }
282 
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");
289     }
290 
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");
297     }
298 
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");
305     }
306 
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");
313     }
314 
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");
321     }
322 
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");
329     }
330 
331     pat.setDecimalSeparatorAlwaysShown(TRUE);
332     UBool tf = pat.isDecimalSeparatorAlwaysShown();
333     logln((UnicodeString)"DecimalSeparatorIsAlwaysShown (should be TRUE) is " + (UnicodeString) (tf ? "TRUE" : "FALSE"));
334     if(tf != TRUE) {
335         errln((UnicodeString)"ERROR: setDecimalSeparatorAlwaysShown() failed");
336     }
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"));
341     if(esas != TRUE) {
342         errln((UnicodeString)"ERROR: ExponentSignAlwaysShown() failed");
343     }
344 
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"));
349     if(sn != TRUE) {
350         errln((UnicodeString)"ERROR: setScientificNotation() failed");
351     }
352 
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");
360     }
361 
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");
369     }
370     //end of Ken's Adding
371 
372     UnicodeString funkyPat;
373     funkyPat = pat.toPattern(funkyPat);
374     logln((UnicodeString)"Pattern is " + funkyPat);
375 
376     UnicodeString locPat;
377     locPat = pat.toLocalizedPattern(locPat);
378     logln((UnicodeString)"Localized pattern is " + locPat);
379 
380 // ======= Test applyPattern()
381 
382     logln((UnicodeString)"Testing applyPattern()");
383     pat = DecimalFormat(status); // reset
384 
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);
391     }
392     UnicodeString s2;
393     s2 = pat.toPattern(s2);
394     logln((UnicodeString)"Extracted pattern is " + s2);
395     assertEquals("toPattern() result did not match pattern applied", p1, s2);
396 
397     if(pat.getSecondaryGroupingSize() != 0) {
398         errln("FAIL: Secondary Grouping Size should be 0, not %d\n", pat.getSecondaryGroupingSize());
399     }
400 
401     if(pat.getGroupingSize() != 3) {
402         errln("FAIL: Primary Grouping Size should be 3, not %d\n", pat.getGroupingSize());
403     }
404 
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);
411     }
412     UnicodeString s3;
413     s3 = pat.toLocalizedPattern(s3);
414     logln((UnicodeString)"Extracted pattern is " + s3);
415     assertEquals("toLocalizedPattern() result did not match pattern applied", p2, s3);
416 
417     status = U_ZERO_ERROR;
418     UParseError pe;
419     pat.applyLocalizedPattern(p2, pe, status);
420     if(U_FAILURE(status)) {
421         errln((UnicodeString)"ERROR: applyPattern((with ParseError)) failed with " + (int32_t) status);
422     }
423     UnicodeString s4;
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);
427 
428     if(pat.getSecondaryGroupingSize() != 2) {
429         errln("FAIL: Secondary Grouping Size should be 2, not %d\n", pat.getSecondaryGroupingSize());
430     }
431 
432     if(pat.getGroupingSize() != 3) {
433         errln("FAIL: Primary Grouping Size should be 3, not %d\n", pat.getGroupingSize());
434     }
435 
436 // ======= Test getStaticClassID()
437 
438     logln((UnicodeString)"Testing getStaticClassID()");
439 
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");
444     }
445 
446     if(test->getDynamicClassID() != DecimalFormat::getStaticClassID()) {
447         errln((UnicodeString)"ERROR: getDynamicClassID() didn't return the expected value");
448     }
449 
450     delete test;
451 }
452 
TestCurrencyPluralInfo()453 void IntlTestDecimalFormatAPI::TestCurrencyPluralInfo(){
454     UErrorCode status = U_ZERO_ERROR;
455 
456     LocalPointer<CurrencyPluralInfo>cpi(new CurrencyPluralInfo(status), status);
457     if(U_FAILURE(status)) {
458         errln((UnicodeString)"ERROR: CurrencyPluralInfo(UErrorCode) could not be created");
459         return;
460     }
461 
462     CurrencyPluralInfo cpi1 = *cpi;
463 
464     if(cpi->getDynamicClassID() != CurrencyPluralInfo::getStaticClassID()){
465         errln((UnicodeString)"ERROR: CurrencyPluralInfo::getDynamicClassID() didn't return the expected value");
466     }
467 
468     cpi->setCurrencyPluralPattern("","",status);
469     if(U_FAILURE(status)) {
470         errln((UnicodeString)"ERROR: CurrencyPluralInfo::setCurrencyPluralPattern");
471     }
472 
473     cpi->setLocale(Locale::getCanada(), status);
474     if(U_FAILURE(status)) {
475         errln((UnicodeString)"ERROR: CurrencyPluralInfo::setLocale");
476     }
477 
478     cpi->setPluralRules("",status);
479     if(U_FAILURE(status)) {
480         errln((UnicodeString)"ERROR: CurrencyPluralInfo::setPluralRules");
481     }
482 
483     LocalPointer<DecimalFormat>df(new DecimalFormat(status));
484     if(U_FAILURE(status)) {
485         errcheckln(status, "ERROR: Could not create DecimalFormat - %s", u_errorName(status));
486         return;
487     }
488 
489     df->adoptCurrencyPluralInfo(cpi.orphan());
490 
491     df->getCurrencyPluralInfo();
492 
493     df->setCurrencyPluralInfo(cpi1);
494 
495 }
496 
testRounding()497 void IntlTestDecimalFormatAPI::testRounding(/*char *par*/)
498 {
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
510     };
511     DecimalFormat pat(status);
512     if(U_FAILURE(status)) {
513       errcheckln(status, "ERROR: Could not create DecimalFormat (default) - %s", u_errorName(status));
514       return;
515     }
516     uint16_t mode;
517     uint16_t i=0;
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);
524         }
525 
526 
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++]);
532         message.remove();
533         resultStr.remove();
534 
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++]);
539         message.remove();
540         resultStr.remove();
541     }
542 
543 }
verify(const UnicodeString & message,const UnicodeString & got,double expected)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);
550         }
551 }
552 
verifyString(const UnicodeString & message,const UnicodeString & got,UnicodeString & expected)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);
557         }
558 }
559 
testRoundingInc()560 void IntlTestDecimalFormatAPI::testRoundingInc(/*char *par*/)
561 {
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));
566       return;
567     }
568 
569     // get default rounding increment
570     double roundingInc = pat.getRoundingIncrement();
571     if (roundingInc != 0.0) {
572       errln((UnicodeString)"ERROR: Rounding increment not zero");
573       return;
574     }
575 
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.
579 
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");
586       return;
587     }
588 }
589 
TestScale()590 void IntlTestDecimalFormatAPI::TestScale()
591 {
592     typedef struct TestData {
593         double inputValue;
594         int inputScale;
595         const char *expectedOutput;
596     } TestData;
597 
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%" },
606     };
607 
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));
612       return;
613     }
614 
615     UnicodeString message;
616     UnicodeString resultStr;
617     UnicodeString exp;
618     UnicodeString percentPattern("#,##0%");
619     pat.setMaximumFractionDigits(4);
620 
621     for(int32_t i=0; i < UPRV_LENGTHOF(testData); i++) {
622         if ( i > 2 ) {
623             pat.applyPattern(percentPattern,status);
624         }
625         // Test both the attribute and the setter
626         if (i % 2 == 0) {
627             pat.setAttribute(UNUM_SCALE, testData[i].inputScale,status);
628             assertEquals("", testData[i].inputScale, pat.getMultiplierScale());
629         } else {
630             pat.setMultiplierScale(testData[i].inputScale);
631             assertEquals("", testData[i].inputScale, pat.getAttribute(UNUM_SCALE, status));
632         }
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);
638         message.remove();
639         resultStr.remove();
640         exp.remove();
641     }
642 }
643 
644 
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); \
650     char tmp[200]; \
651     sprintf(tmp, "(%g==%g)", (double)lhs, (double)rhs); \
652     assertTrue(tmp, (lhs==rhs), FALSE, TRUE, __FILE__, __LINE__); \
653 } UPRV_BLOCK_MACRO_END
654 
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)
660 #endif
TestFixedDecimal()661 void IntlTestDecimalFormatAPI::TestFixedDecimal() {
662     UErrorCode status = U_ZERO_ERROR;
663 
664     LocalPointer<DecimalFormat> df(new DecimalFormat("###", status), status);
665     assertSuccess(WHERE, status);
666     if (status == U_MISSING_RESOURCE_ERROR) {
667         return;
668     }
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());
675 
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());
681 
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());
693 
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());
703 
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());
715 
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());
725 
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());
738 
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());
748 
749     // test esoteric rounding
750     df->setMaximumFractionDigits(6);
751     df->setRoundingIncrement(7.3);
752 
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());
762 
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());
772 
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());
783 
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());
794 
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());
805 
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());
816 
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());
827 
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);
836 
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());
853 
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());
864 
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());
876 
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());
888 
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());
900 
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());
912 
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());
924 
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());
935 
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());
947 
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());
958 
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());
971 
972 }
973 #if defined(_MSC_VER)
974 // Re-enable 4805 warnings (comparisons between int and bool).
975 #pragma warning(pop)
976 #endif
977 
TestBadFastpath()978 void IntlTestDecimalFormatAPI::TestBadFastpath() {
979     UErrorCode status = U_ZERO_ERROR;
980 
981     LocalPointer<DecimalFormat> df(new DecimalFormat("###", status), status);
982     if (U_FAILURE(status)) {
983         dataerrln("Error creating new DecimalFormat - %s", u_errorName(status));
984         return;
985     }
986 
987     UnicodeString fmt;
988     fmt.remove();
989     assertEquals("Format 1234", "1234", df->format((int32_t)1234, fmt));
990     df->setGroupingUsed(FALSE);
991     fmt.remove();
992     assertEquals("Format 1234", "1234", df->format((int32_t)1234, fmt));
993     df->setGroupingUsed(TRUE);
994     df->setGroupingSize(3);
995     fmt.remove();
996     assertEquals("Format 1234 w/ grouping", "1,234", df->format((int32_t)1234, fmt));
997 }
998 
TestRequiredDecimalPoint()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");
1005 
1006     LocalPointer<DecimalFormat> df(new DecimalFormat(pat1, status), status);
1007     if (U_FAILURE(status)) {
1008         dataerrln("Error creating new DecimalFormat - %s", u_errorName(status));
1009         return;
1010     }
1011 
1012     status = U_ZERO_ERROR;
1013     df->applyPattern(pat1, status);
1014     if(U_FAILURE(status)) {
1015         errln((UnicodeString)"ERROR: applyPattern() failed");
1016     }
1017     df->parse(text, result1, status);
1018     if(U_FAILURE(status)) {
1019         errln((UnicodeString)"ERROR: parse() failed");
1020     }
1021     df->setDecimalPatternMatchRequired(TRUE);
1022     df->parse(text, result1, status);
1023     if(U_SUCCESS(status)) {
1024         errln((UnicodeString)"ERROR: unexpected parse()");
1025     }
1026 
1027 
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");
1033     }
1034     df->parse(text, result1, status);
1035     if(U_FAILURE(status)) {
1036         errln((UnicodeString)"ERROR: parse(2) failed - " + u_errorName(status));
1037     }
1038     df->setDecimalPatternMatchRequired(TRUE);
1039     df->parse(text, result1, status);
1040     if(U_SUCCESS(status)) {
1041         errln((UnicodeString)"ERROR: unexpected parse(2)");
1042     }
1043 }
1044 
testErrorCode()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.
1048 
1049     UErrorCode status = U_ZERO_ERROR;
1050     const UnicodeString pattern(u"0.###E0");
1051     UParseError pe;
1052     DecimalFormatSymbols symbols(Locale::getUS(), status);
1053     assertSuccess(WHERE, status);
1054 
1055     {
1056         status = U_INTERNAL_PROGRAM_ERROR;
1057         DecimalFormat df(status);
1058         assertEquals(WHERE, U_INTERNAL_PROGRAM_ERROR, status);
1059     }
1060     {
1061         status = U_INTERNAL_PROGRAM_ERROR;
1062         DecimalFormat df(pattern, status);
1063         assertEquals(WHERE, U_INTERNAL_PROGRAM_ERROR, status);
1064     }
1065     {
1066         status = U_INTERNAL_PROGRAM_ERROR;
1067         DecimalFormat df(pattern, new DecimalFormatSymbols(symbols), status);
1068         assertEquals(WHERE, U_INTERNAL_PROGRAM_ERROR, status);
1069     }
1070     {
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);
1074     }
1075     {
1076         status = U_INTERNAL_PROGRAM_ERROR;
1077         DecimalFormat df(pattern, new DecimalFormatSymbols(symbols), pe, status);
1078         assertEquals(WHERE, U_INTERNAL_PROGRAM_ERROR, status);
1079     }
1080     {
1081         status = U_INTERNAL_PROGRAM_ERROR;
1082         DecimalFormat df(pattern, symbols ,status);
1083         assertEquals(WHERE, U_INTERNAL_PROGRAM_ERROR, status);
1084     }
1085 
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.
1088 
1089     status = U_INTERNAL_PROGRAM_ERROR;
1090     DecimalFormat dfBogus(status);
1091     assertEquals(WHERE, U_INTERNAL_PROGRAM_ERROR, status);
1092 
1093     status = U_ZERO_ERROR;
1094     DecimalFormat dfGood(pattern, new DecimalFormatSymbols(symbols), status);
1095     assertSuccess(WHERE, status);
1096 
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);
1101 
1102         status = U_INTERNAL_PROGRAM_ERROR;
1103         df->getAttribute(UNUM_MAX_FRACTION_DIGITS, status);
1104         assertEquals(WHERE, U_INTERNAL_PROGRAM_ERROR, status);
1105 
1106         status = U_INTERNAL_PROGRAM_ERROR;
1107         UnicodeString dest;
1108         FieldPosition fp;
1109         df->format(1.2, dest, fp, status);
1110         assertEquals(WHERE, U_INTERNAL_PROGRAM_ERROR, status);
1111 
1112         status = U_INTERNAL_PROGRAM_ERROR;
1113         df->format(1.2, dest, nullptr, status);
1114         assertEquals(WHERE, U_INTERNAL_PROGRAM_ERROR, status);
1115 
1116         status = U_INTERNAL_PROGRAM_ERROR;
1117         df->format((int32_t)666, dest, nullptr, status);
1118         assertEquals(WHERE, U_INTERNAL_PROGRAM_ERROR, status);
1119 
1120         status = U_INTERNAL_PROGRAM_ERROR;
1121         df->format((int64_t)666, dest, nullptr, status);
1122         assertEquals(WHERE, U_INTERNAL_PROGRAM_ERROR, status);
1123 
1124         status = U_INTERNAL_PROGRAM_ERROR;
1125         df->format(StringPiece("3.1415926535897932384626"), dest, nullptr, status);
1126         assertEquals(WHERE, U_INTERNAL_PROGRAM_ERROR, status);
1127 
1128         status = U_INTERNAL_PROGRAM_ERROR;
1129         df->applyPattern(pattern, status);
1130         assertEquals(WHERE, U_INTERNAL_PROGRAM_ERROR, status);
1131 
1132         status = U_INTERNAL_PROGRAM_ERROR;
1133         df->applyLocalizedPattern(pattern, pe, status);
1134         assertEquals(WHERE, U_INTERNAL_PROGRAM_ERROR, status);
1135 
1136         status = U_INTERNAL_PROGRAM_ERROR;
1137         df->applyLocalizedPattern(pattern, status);
1138         assertEquals(WHERE, U_INTERNAL_PROGRAM_ERROR, status);
1139 
1140         status = U_INTERNAL_PROGRAM_ERROR;
1141         df->setCurrency(u"USD", status);
1142         assertEquals(WHERE, U_INTERNAL_PROGRAM_ERROR, status);
1143 
1144         status = U_INTERNAL_PROGRAM_ERROR;
1145         df->setCurrencyUsage(UCURR_USAGE_CASH, &status);
1146         assertEquals(WHERE, U_INTERNAL_PROGRAM_ERROR, status);
1147     }
1148 }
1149 
testInvalidObject()1150 void IntlTestDecimalFormatAPI::testInvalidObject() {
1151     {
1152         UErrorCode status = U_INTERNAL_PROGRAM_ERROR;
1153         DecimalFormat dfBogus(status);
1154         assertEquals(WHERE, U_INTERNAL_PROGRAM_ERROR, status);
1155 
1156         status = U_ZERO_ERROR;
1157         DecimalFormat dfGood(status);
1158         assertSuccess(WHERE, status);
1159 
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);
1164 
1165         status = U_MEMORY_ALLOCATION_ERROR;
1166         DecimalFormat dfBogus2(status);
1167         assertEquals(WHERE, U_MEMORY_ALLOCATION_ERROR, status);
1168 
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);
1172 
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);
1178 
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);
1187 
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);
1194 
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);
1208     }
1209 
1210     {
1211         // Try each DecimalFormat class method that lacks an error code parameter, verifying
1212         // we don't crash (segmentation fault) on invalid objects.
1213 
1214         UErrorCode status = U_ZERO_ERROR;
1215         const UnicodeString pattern(u"0.###E0");
1216         UParseError pe;
1217         DecimalFormatSymbols symbols(Locale::getUS(), status);
1218         assertSuccess(WHERE, status);
1219         CurrencyPluralInfo currencyPI(status);
1220         assertSuccess(WHERE, status);
1221 
1222         status = U_INTERNAL_PROGRAM_ERROR;
1223         DecimalFormat dfBogus1(status);
1224         assertEquals(WHERE, U_INTERNAL_PROGRAM_ERROR, status);
1225 
1226         status = U_INTERNAL_PROGRAM_ERROR;
1227         DecimalFormat dfBogus2(pattern, status);
1228         assertEquals(WHERE, U_INTERNAL_PROGRAM_ERROR, status);
1229 
1230         status = U_INTERNAL_PROGRAM_ERROR;
1231         DecimalFormat dfBogus3(pattern, new DecimalFormatSymbols(symbols), status);
1232         assertEquals(WHERE, U_INTERNAL_PROGRAM_ERROR, status);
1233 
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);
1237 
1238         status = U_INTERNAL_PROGRAM_ERROR;
1239         DecimalFormat dfBogus5(pattern, new DecimalFormatSymbols(symbols), pe, status);
1240         assertEquals(WHERE, U_INTERNAL_PROGRAM_ERROR, status);
1241 
1242         for (DecimalFormat *df : {&dfBogus1, &dfBogus2, &dfBogus3, &dfBogus4, &dfBogus5})
1243         {
1244             df->setGroupingUsed(true);
1245 
1246             df->setParseIntegerOnly(false);
1247 
1248             df->setLenient(true);
1249 
1250             auto dfClone = df->clone();
1251             assertTrue(WHERE, dfClone == nullptr);
1252 
1253             UnicodeString dest;
1254             FieldPosition fp;
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);
1258 
1259             UnicodeString text("-1,234.00");
1260             Formattable result;
1261             ParsePosition pos(0);
1262             df->parse(text, result, pos);
1263 
1264             CurrencyAmount* ca = df->parseCurrency(text, pos);
1265             assertTrue(WHERE, ca == nullptr);
1266 
1267             const DecimalFormatSymbols* dfs = df->getDecimalFormatSymbols();
1268             assertTrue(WHERE, dfs == nullptr);
1269 
1270             df->adoptDecimalFormatSymbols(nullptr);
1271 
1272             df->setDecimalFormatSymbols(symbols);
1273 
1274             const CurrencyPluralInfo* cpi = df->getCurrencyPluralInfo();
1275             assertTrue(WHERE, cpi == nullptr);
1276 
1277             df->adoptCurrencyPluralInfo(nullptr);
1278 
1279             df->setCurrencyPluralInfo(currencyPI);
1280 
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);
1290 
1291             df->isSignAlwaysShown();
1292 
1293             df->setSignAlwaysShown(true);
1294 
1295             df->getMultiplier();
1296             df->setMultiplier(10);
1297 
1298             df->getMultiplierScale();
1299             df->setMultiplierScale(2);
1300 
1301             df->getRoundingIncrement();
1302             df->setRoundingIncrement(1.2);
1303 
1304             df->getRoundingMode();
1305             df->setRoundingMode(DecimalFormat::ERoundingMode::kRoundDown);
1306 
1307             df->getFormatWidth();
1308             df->setFormatWidth(0);
1309 
1310             UnicodeString pad(" ");
1311             df->getPadCharacterString();
1312             df->setPadCharacter(pad);
1313 
1314             df->getPadPosition();
1315             df->setPadPosition(DecimalFormat::EPadPosition::kPadBeforePrefix);
1316 
1317             df->isScientificNotation();
1318             df->setScientificNotation(false);
1319 
1320             df->getMinimumExponentDigits();
1321             df->setMinimumExponentDigits(1);
1322 
1323             df->isExponentSignAlwaysShown();
1324             df->setExponentSignAlwaysShown(true);
1325 
1326             df->getGroupingSize();
1327             df->setGroupingSize(3);
1328 
1329             df->getSecondaryGroupingSize();
1330             df->setSecondaryGroupingSize(-1);
1331 
1332             df->getMinimumGroupingDigits();
1333             df->setMinimumGroupingDigits(-1);
1334 
1335             df->isDecimalSeparatorAlwaysShown();
1336             df->setDecimalSeparatorAlwaysShown(true);
1337 
1338             df->isDecimalPatternMatchRequired();
1339             df->setDecimalPatternMatchRequired(false);
1340 
1341             df->isParseNoExponent();
1342             df->setParseNoExponent(true);
1343 
1344             df->isParseCaseSensitive();
1345             df->setParseCaseSensitive(false);
1346 
1347             df->isFormatFailIfMoreThanMaxDigits();
1348             df->setFormatFailIfMoreThanMaxDigits(true);
1349 
1350             df->toPattern(dest);
1351             df->toLocalizedPattern(dest);
1352 
1353             df->setMaximumIntegerDigits(10);
1354             df->setMinimumIntegerDigits(0);
1355 
1356             df->setMaximumFractionDigits(2);
1357             df->setMinimumFractionDigits(0);
1358 
1359             df->getMinimumSignificantDigits();
1360             df->setMinimumSignificantDigits(0);
1361 
1362             df->getMaximumSignificantDigits();
1363             df->setMaximumSignificantDigits(5);
1364 
1365             df->areSignificantDigitsUsed();
1366             df->setSignificantDigitsUsed(true);
1367 
1368             df->setCurrency(u"USD");
1369 
1370             df->getCurrencyUsage();
1371 
1372             const number::LocalizedNumberFormatter* lnf = df->toNumberFormatter(status);
1373             assertEquals("toNumberFormatter should return nullptr",
1374                 (int64_t) nullptr, (int64_t) lnf);
1375 
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);
1383         }
1384 
1385     }
1386 }
1387 
1388 #endif /* #if !UCONFIG_NO_FORMATTING */
1389