• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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: ", static_cast<UBool>(false), 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: ", static_cast<UBool>(true), 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     // NOTE: The test where you pass "symbols" as a pointer has to come second-- the DecimalFormat
184     // object is _adopting_ this object, meaning it's unavailable for use by this test (e.g.,
185     // to pass to another DecimalFormat) after the call to the DecimalFormat constructor.
186     // The call above, where we're passing it by reference, doesn't take ownership of the
187     // symbols object, so we can reuse it here.
188     status = U_ZERO_ERROR;
189     DecimalFormat cust2(pattern, symbols, status);
190     if(U_FAILURE(status)) {
191         errln(UnicodeString("ERROR: Could not create DecimalFormat (pattern, symbols*)"));
192     }
193 
194     DecimalFormat copy(pat);
195 
196 // ======= Test clone(), assignment, and equality
197 
198     logln(UnicodeString("Testing clone(), assignment and equality operators"));
199 
200     if( ! (copy == pat) || copy != pat) {
201         errln(UnicodeString("ERROR: Copy constructor or == failed"));
202     }
203 
204     copy = cust1;
205     if(copy != cust1) {
206         errln(UnicodeString("ERROR: Assignment (or !=) failed"));
207     }
208 
209     Format *clone = def.clone();
210     if( ! (*clone == def) ) {
211         errln(UnicodeString("ERROR: Clone() failed"));
212     }
213     delete clone;
214 
215 // ======= Test various format() methods
216 
217     logln(UnicodeString("Testing various format() methods"));
218 
219     double d = -10456.0037;
220     int32_t l = 100000000;
221     Formattable fD(d);
222     Formattable fL(l);
223 
224     UnicodeString res1, res2, res3, res4;
225     FieldPosition pos1(FieldPosition::DONT_CARE), pos2(FieldPosition::DONT_CARE), pos3(FieldPosition::DONT_CARE), pos4(FieldPosition::DONT_CARE);
226 
227     res1 = def.format(d, res1, pos1);
228     logln(UnicodeString("") + static_cast<int32_t>(d) + " formatted to " + res1);
229 
230     res2 = pat.format(l, res2, pos2);
231     logln(UnicodeString("") + l + " formatted to " + res2);
232 
233     status = U_ZERO_ERROR;
234     res3 = cust1.format(fD, res3, pos3, status);
235     if(U_FAILURE(status)) {
236         errln(UnicodeString("ERROR: format(Formattable [double]) failed"));
237     }
238     logln(UnicodeString("") + static_cast<int32_t>(fD.getDouble()) + " formatted to " + res3);
239 
240     status = U_ZERO_ERROR;
241     res4 = cust2.format(fL, res4, pos4, status);
242     if(U_FAILURE(status)) {
243         errln(UnicodeString("ERROR: format(Formattable [long]) failed"));
244     }
245     logln(UnicodeString("") + fL.getLong() + " formatted to " + res4);
246 
247 // ======= Test parse()
248 
249     logln(UnicodeString("Testing parse()"));
250 
251     UnicodeString text("-10,456.0037");
252     Formattable result1, result2;
253     ParsePosition pos(0);
254     UnicodeString patt("#,##0.#");
255     status = U_ZERO_ERROR;
256     pat.applyPattern(patt, status);
257     if(U_FAILURE(status)) {
258         errln(UnicodeString("ERROR: applyPattern() failed"));
259     }
260     pat.parse(text, result1, pos);
261     if(result1.getType() != Formattable::kDouble && result1.getDouble() != d) {
262         errln(UnicodeString("ERROR: Roundtrip failed (via parse()) for ") + text);
263     }
264     logln(text + " parsed into " + static_cast<int32_t>(result1.getDouble()));
265 
266     status = U_ZERO_ERROR;
267     pat.parse(text, result2, status);
268     if(U_FAILURE(status)) {
269         errln(UnicodeString("ERROR: parse() failed"));
270     }
271     if(result2.getType() != Formattable::kDouble && result2.getDouble() != d) {
272         errln(UnicodeString("ERROR: Roundtrip failed (via parse()) for ") + text);
273     }
274     logln(text + " parsed into " + static_cast<int32_t>(result2.getDouble()));
275 
276 // ======= Test getters and setters
277 
278     logln(UnicodeString("Testing getters and setters"));
279 
280     const DecimalFormatSymbols *syms = pat.getDecimalFormatSymbols();
281     DecimalFormatSymbols *newSyms = new DecimalFormatSymbols(*syms);
282     def.setDecimalFormatSymbols(*newSyms);
283     def.adoptDecimalFormatSymbols(newSyms); // don't use newSyms after this
284     if( *(pat.getDecimalFormatSymbols()) != *(def.getDecimalFormatSymbols())) {
285         errln(UnicodeString("ERROR: adopt or set DecimalFormatSymbols() failed"));
286     }
287 
288     UnicodeString posPrefix;
289     pat.setPositivePrefix("+");
290     posPrefix = pat.getPositivePrefix(posPrefix);
291     logln(UnicodeString("Positive prefix (should be +): ") + posPrefix);
292     if(posPrefix != "+") {
293         errln(UnicodeString("ERROR: setPositivePrefix() failed"));
294     }
295 
296     UnicodeString negPrefix;
297     pat.setNegativePrefix("-");
298     negPrefix = pat.getNegativePrefix(negPrefix);
299     logln(UnicodeString("Negative prefix (should be -): ") + negPrefix);
300     if(negPrefix != "-") {
301         errln(UnicodeString("ERROR: setNegativePrefix() failed"));
302     }
303 
304     UnicodeString posSuffix;
305     pat.setPositiveSuffix("_");
306     posSuffix = pat.getPositiveSuffix(posSuffix);
307     logln(UnicodeString("Positive suffix (should be _): ") + posSuffix);
308     if(posSuffix != "_") {
309         errln(UnicodeString("ERROR: setPositiveSuffix() failed"));
310     }
311 
312     UnicodeString negSuffix;
313     pat.setNegativeSuffix("~");
314     negSuffix = pat.getNegativeSuffix(negSuffix);
315     logln(UnicodeString("Negative suffix (should be ~): ") + negSuffix);
316     if(negSuffix != "~") {
317         errln(UnicodeString("ERROR: setNegativeSuffix() failed"));
318     }
319 
320     int32_t multiplier = 0;
321     pat.setMultiplier(8);
322     multiplier = pat.getMultiplier();
323     logln(UnicodeString("Multiplier (should be 8): ") + multiplier);
324     if(multiplier != 8) {
325         errln(UnicodeString("ERROR: setMultiplier() failed"));
326     }
327 
328     int32_t groupingSize = 0;
329     pat.setGroupingSize(2);
330     groupingSize = pat.getGroupingSize();
331     logln(UnicodeString("Grouping size (should be 2): ") + groupingSize);
332     if(groupingSize != 2) {
333         errln(UnicodeString("ERROR: setGroupingSize() failed"));
334     }
335 
336     pat.setDecimalSeparatorAlwaysShown(true);
337     UBool tf = pat.isDecimalSeparatorAlwaysShown();
338     logln(UnicodeString("DecimalSeparatorIsAlwaysShown (should be true) is ") + UnicodeString(tf ? "true" : "false"));
339     if(tf != true) {
340         errln(UnicodeString("ERROR: setDecimalSeparatorAlwaysShown() failed"));
341     }
342     // Added by Ken Liu testing set/isExponentSignAlwaysShown
343     pat.setExponentSignAlwaysShown(true);
344     UBool esas = pat.isExponentSignAlwaysShown();
345     logln(UnicodeString("ExponentSignAlwaysShown (should be true) is ") + UnicodeString(esas ? "true" : "false"));
346     if(esas != true) {
347         errln(UnicodeString("ERROR: ExponentSignAlwaysShown() failed"));
348     }
349 
350     // Added by Ken Liu testing set/isScientificNotation
351     pat.setScientificNotation(true);
352     UBool sn = pat.isScientificNotation();
353     logln(UnicodeString("isScientificNotation (should be true) is ") + UnicodeString(sn ? "true" : "false"));
354     if(sn != true) {
355         errln(UnicodeString("ERROR: setScientificNotation() failed"));
356     }
357 
358     // Added by Ken Liu testing set/getMinimumExponentDigits
359     int8_t MinimumExponentDigits = 0;
360     pat.setMinimumExponentDigits(2);
361     MinimumExponentDigits = pat.getMinimumExponentDigits();
362     logln(UnicodeString("MinimumExponentDigits (should be 2) is ") + MinimumExponentDigits);
363     if(MinimumExponentDigits != 2) {
364         errln(UnicodeString("ERROR: setMinimumExponentDigits() failed"));
365     }
366 
367     // Added by Ken Liu testing set/getRoundingIncrement
368     double RoundingIncrement = 0.0;
369     pat.setRoundingIncrement(2.0);
370     RoundingIncrement = pat.getRoundingIncrement();
371     logln(UnicodeString("RoundingIncrement (should be 2.0) is ") + RoundingIncrement);
372     if(RoundingIncrement != 2.0) {
373         errln(UnicodeString("ERROR: setRoundingIncrement() failed"));
374     }
375     //end of Ken's Adding
376 
377     UnicodeString funkyPat;
378     funkyPat = pat.toPattern(funkyPat);
379     logln(UnicodeString("Pattern is ") + funkyPat);
380 
381     UnicodeString locPat;
382     locPat = pat.toLocalizedPattern(locPat);
383     logln(UnicodeString("Localized pattern is ") + locPat);
384 
385 // ======= Test applyPattern()
386 
387     logln(UnicodeString("Testing applyPattern()"));
388     pat = DecimalFormat(status); // reset
389 
390     UnicodeString p1("#,##0.0#;(#,##0.0#)");
391     logln(UnicodeString("Applying pattern ") + p1);
392     status = U_ZERO_ERROR;
393     pat.applyPattern(p1, status);
394     if(U_FAILURE(status)) {
395         errln(UnicodeString("ERROR: applyPattern() failed with ") + static_cast<int32_t>(status));
396     }
397     UnicodeString s2;
398     s2 = pat.toPattern(s2);
399     logln(UnicodeString("Extracted pattern is ") + s2);
400     assertEquals("toPattern() result did not match pattern applied", p1, s2);
401 
402     if(pat.getSecondaryGroupingSize() != 0) {
403         errln("FAIL: Secondary Grouping Size should be 0, not %d\n", pat.getSecondaryGroupingSize());
404     }
405 
406     if(pat.getGroupingSize() != 3) {
407         errln("FAIL: Primary Grouping Size should be 3, not %d\n", pat.getGroupingSize());
408     }
409 
410     UnicodeString p2("#,##,##0.0# FF;(#,##,##0.0# FF)");
411     logln(UnicodeString("Applying pattern ") + p2);
412     status = U_ZERO_ERROR;
413     pat.applyLocalizedPattern(p2, status);
414     if(U_FAILURE(status)) {
415         errln(UnicodeString("ERROR: applyPattern() failed with ") + static_cast<int32_t>(status));
416     }
417     UnicodeString s3;
418     s3 = pat.toLocalizedPattern(s3);
419     logln(UnicodeString("Extracted pattern is ") + s3);
420     assertEquals("toLocalizedPattern() result did not match pattern applied", p2, s3);
421 
422     status = U_ZERO_ERROR;
423     UParseError pe;
424     pat.applyLocalizedPattern(p2, pe, status);
425     if(U_FAILURE(status)) {
426         errln(UnicodeString("ERROR: applyPattern((with ParseError)) failed with ") + static_cast<int32_t>(status));
427     }
428     UnicodeString s4;
429     s4 = pat.toLocalizedPattern(s3);
430     logln(UnicodeString("Extracted pattern is ") + s4);
431     assertEquals("toLocalizedPattern(with ParseErr) result did not match pattern applied", p2, s4);
432 
433     if(pat.getSecondaryGroupingSize() != 2) {
434         errln("FAIL: Secondary Grouping Size should be 2, not %d\n", pat.getSecondaryGroupingSize());
435     }
436 
437     if(pat.getGroupingSize() != 3) {
438         errln("FAIL: Primary Grouping Size should be 3, not %d\n", pat.getGroupingSize());
439     }
440 
441 // ======= Test getStaticClassID()
442 
443     logln(UnicodeString("Testing getStaticClassID()"));
444 
445     status = U_ZERO_ERROR;
446     NumberFormat *test = new DecimalFormat(status);
447     if(U_FAILURE(status)) {
448         errln(UnicodeString("ERROR: Couldn't create a DecimalFormat"));
449     }
450 
451     if(test->getDynamicClassID() != DecimalFormat::getStaticClassID()) {
452         errln(UnicodeString("ERROR: getDynamicClassID() didn't return the expected value"));
453     }
454 
455     delete test;
456 }
457 
TestCurrencyPluralInfo()458 void IntlTestDecimalFormatAPI::TestCurrencyPluralInfo(){
459     UErrorCode status = U_ZERO_ERROR;
460 
461     LocalPointer<CurrencyPluralInfo>cpi(new CurrencyPluralInfo(status), status);
462     if(U_FAILURE(status)) {
463         errln(UnicodeString("ERROR: CurrencyPluralInfo(UErrorCode) could not be created"));
464         return;
465     }
466 
467     CurrencyPluralInfo cpi1 = *cpi;
468 
469     if(cpi->getDynamicClassID() != CurrencyPluralInfo::getStaticClassID()){
470         errln(UnicodeString("ERROR: CurrencyPluralInfo::getDynamicClassID() didn't return the expected value"));
471     }
472 
473     cpi->setCurrencyPluralPattern("","",status);
474     if(U_FAILURE(status)) {
475         errln(UnicodeString("ERROR: CurrencyPluralInfo::setCurrencyPluralPattern"));
476     }
477 
478     cpi->setLocale(Locale::getCanada(), status);
479     if(U_FAILURE(status)) {
480         errln(UnicodeString("ERROR: CurrencyPluralInfo::setLocale"));
481     }
482 
483     cpi->setPluralRules("",status);
484     if(U_FAILURE(status)) {
485         errln(UnicodeString("ERROR: CurrencyPluralInfo::setPluralRules"));
486     }
487 
488     LocalPointer<DecimalFormat>df(new DecimalFormat(status));
489     if(U_FAILURE(status)) {
490         errcheckln(status, "ERROR: Could not create DecimalFormat - %s", u_errorName(status));
491         return;
492     }
493 
494     df->adoptCurrencyPluralInfo(cpi.orphan());
495 
496     df->getCurrencyPluralInfo();
497 
498     df->setCurrencyPluralInfo(cpi1);
499 
500 }
501 
testRounding()502 void IntlTestDecimalFormatAPI::testRounding(/*char *par*/)
503 {
504     UErrorCode status = U_ZERO_ERROR;
505     double Roundingnumber = 2.55;
506     double Roundingnumber1 = -2.55;
507                       //+2.55 results   -2.55 results
508     double result[]={   3.0,            -2.0,    //  kRoundCeiling  0,
509                         2.0,            -3.0,    //  kRoundFloor    1,
510                         2.0,            -2.0,    //  kRoundDown     2,
511                         3.0,            -3.0,    //  kRoundUp       3,
512                         3.0,            -3.0,    //  kRoundHalfEven 4,
513                         3.0,            -3.0,    //  kRoundHalfDown 5,
514                         3.0,            -3.0     //  kRoundHalfUp   6
515     };
516     DecimalFormat pat(status);
517     if(U_FAILURE(status)) {
518       errcheckln(status, "ERROR: Could not create DecimalFormat (default) - %s", u_errorName(status));
519       return;
520     }
521     uint16_t mode;
522     uint16_t i=0;
523     UnicodeString message;
524     UnicodeString resultStr;
525     for(mode=0;mode < 7;mode++){
526         pat.setRoundingMode(static_cast<DecimalFormat::ERoundingMode>(mode));
527         if (pat.getRoundingMode() != static_cast<DecimalFormat::ERoundingMode>(mode)) {
528             errln(UnicodeString("SetRoundingMode or GetRoundingMode failed for mode=") + mode);
529         }
530 
531 
532         //for +2.55 with RoundingIncrement=1.0
533         pat.setRoundingIncrement(1.0);
534         pat.format(Roundingnumber, resultStr);
535         message = UnicodeString("round(") + Roundingnumber + UnicodeString(",") + mode + UnicodeString(",false) with RoundingIncrement=1.0==>");
536         verify(message, resultStr, result[i++]);
537         message.remove();
538         resultStr.remove();
539 
540         //for -2.55 with RoundingIncrement=1.0
541         pat.format(Roundingnumber1, resultStr);
542         message = UnicodeString("round(") + Roundingnumber1 + UnicodeString(",") + mode + UnicodeString(",false) with RoundingIncrement=1.0==>");
543         verify(message, resultStr, result[i++]);
544         message.remove();
545         resultStr.remove();
546     }
547 
548 }
verify(const UnicodeString & message,const UnicodeString & got,double expected)549 void IntlTestDecimalFormatAPI::verify(const UnicodeString& message, const UnicodeString& got, double expected){
550     logln(UnicodeString(message) + got + UnicodeString(" Expected : ") + expected);
551     UnicodeString expectedStr("");
552     expectedStr=expectedStr + expected;
553     if(got != expectedStr ) {
554             errln(UnicodeString("ERROR: ") + message + got + UnicodeString("  Expected : ") + expectedStr);
555         }
556 }
557 
verifyString(const UnicodeString & message,const UnicodeString & got,UnicodeString & expected)558 void IntlTestDecimalFormatAPI::verifyString(const UnicodeString& message, const UnicodeString& got, UnicodeString& expected){
559     logln(UnicodeString(message) + got + UnicodeString(" Expected : ") + expected);
560     if(got != expected ) {
561             errln(UnicodeString("ERROR: ") + message + got + UnicodeString("  Expected : ") + expected);
562         }
563 }
564 
testRoundingInc()565 void IntlTestDecimalFormatAPI::testRoundingInc(/*char *par*/)
566 {
567     UErrorCode status = U_ZERO_ERROR;
568     DecimalFormat pat(UnicodeString("#,##0.00"),status);
569     if(U_FAILURE(status)) {
570       errcheckln(status, "ERROR: Could not create DecimalFormat (default) - %s", u_errorName(status));
571       return;
572     }
573 
574     // get default rounding increment
575     double roundingInc = pat.getRoundingIncrement();
576     if (roundingInc != 0.0) {
577       errln(UnicodeString("ERROR: Rounding increment not zero"));
578       return;
579     }
580 
581     // With rounding now being handled by decNumber, we no longer
582     // set a rounding increment to enable non-default mode rounding,
583     // checking of which was the original point of this test.
584 
585     // set rounding mode with zero increment.  Rounding
586     // increment should not be set by this operation
587     pat.setRoundingMode(static_cast<DecimalFormat::ERoundingMode>(0));
588     roundingInc = pat.getRoundingIncrement();
589     if (roundingInc != 0.0) {
590       errln(UnicodeString("ERROR: Rounding increment not zero after setRoundingMode"));
591       return;
592     }
593 }
594 
TestScale()595 void IntlTestDecimalFormatAPI::TestScale()
596 {
597     typedef struct TestData {
598         double inputValue;
599         int inputScale;
600         const char *expectedOutput;
601     } TestData;
602 
603     static TestData testData[] = {
604         { 100.0, 3,  "100,000" },
605         { 10034.0, -2, "100.34" },
606         { 0.86, -3, "0.0009" },
607         { -0.000455, 1, "-0%" },
608         { -0.000555, 1, "-1%" },
609         { 0.000455, 1, "0%" },
610         { 0.000555, 1, "1%" },
611     };
612 
613     UErrorCode status = U_ZERO_ERROR;
614     DecimalFormat pat(status);
615     if(U_FAILURE(status)) {
616       errcheckln(status, "ERROR: Could not create DecimalFormat (default) - %s", u_errorName(status));
617       return;
618     }
619 
620     UnicodeString message;
621     UnicodeString resultStr;
622     UnicodeString exp;
623     UnicodeString percentPattern("#,##0%");
624     pat.setMaximumFractionDigits(4);
625 
626     for(int32_t i=0; i < UPRV_LENGTHOF(testData); i++) {
627         if ( i > 2 ) {
628             pat.applyPattern(percentPattern,status);
629         }
630         // Test both the attribute and the setter
631         if (i % 2 == 0) {
632             pat.setAttribute(UNUM_SCALE, testData[i].inputScale,status);
633             assertEquals("", testData[i].inputScale, pat.getMultiplierScale());
634         } else {
635             pat.setMultiplierScale(testData[i].inputScale);
636             assertEquals("", testData[i].inputScale, pat.getAttribute(UNUM_SCALE, status));
637         }
638         pat.format(testData[i].inputValue, resultStr);
639         message = UnicodeString("Unexpected output for ") + testData[i].inputValue + UnicodeString(" and scale ") +
640                   testData[i].inputScale + UnicodeString(". Got: ");
641         exp = testData[i].expectedOutput;
642         verifyString(message, resultStr, exp);
643         message.remove();
644         resultStr.remove();
645         exp.remove();
646     }
647 }
648 
649 
650 #define ASSERT_EQUAL(expect, actual) UPRV_BLOCK_MACRO_BEGIN { \
651     /* ICU-20080: Use temporary variables to avoid strange compiler behaviour \
652        (with the nice side-effect of avoiding repeated function calls too). */ \
653     auto lhs = (expect); \
654     auto rhs = (actual); \
655     char tmp[200]; \
656     snprintf(tmp, sizeof(tmp), "(%g==%g)", (double)lhs, (double)rhs); \
657     assertTrue(tmp, (lhs==rhs), false, true, __FILE__, __LINE__); \
658 } UPRV_BLOCK_MACRO_END
659 
660 #if defined(_MSC_VER)
661 // Ignore the noisy warning 4805 (comparisons between int and bool) in the function below as we use the ICU true/false macros
662 // which are int values, whereas some of the DecimalQuantity methods return C++ bools.
663 #pragma warning(push)
664 #pragma warning(disable: 4805)
665 #endif
TestFixedDecimal()666 void IntlTestDecimalFormatAPI::TestFixedDecimal() {
667     UErrorCode status = U_ZERO_ERROR;
668 
669     LocalPointer<DecimalFormat> df(new DecimalFormat("###", status), status);
670     assertSuccess(WHERE, status);
671     if (status == U_MISSING_RESOURCE_ERROR) {
672         return;
673     }
674     number::impl::DecimalQuantity fd;
675     df->formatToDecimalQuantity(44, fd, status);
676     assertSuccess(WHERE, status);
677     ASSERT_EQUAL(44, fd.getPluralOperand(PLURAL_OPERAND_N));
678     ASSERT_EQUAL(0, fd.getPluralOperand(PLURAL_OPERAND_V));
679     ASSERT_EQUAL(false, fd.isNegative());
680 
681     df->formatToDecimalQuantity(-44, fd, status);
682     assertSuccess(WHERE, status);
683     ASSERT_EQUAL(44, fd.getPluralOperand(PLURAL_OPERAND_N));
684     ASSERT_EQUAL(0, fd.getPluralOperand(PLURAL_OPERAND_V));
685     ASSERT_EQUAL(true, fd.isNegative());
686 
687     df.adoptInsteadAndCheckErrorCode(new DecimalFormat("###.00##", status), status);
688     assertSuccess(WHERE, status);
689     df->formatToDecimalQuantity(123.456, fd, status);
690     assertSuccess(WHERE, status);
691     ASSERT_EQUAL(3, fd.getPluralOperand(PLURAL_OPERAND_V)); // v
692     ASSERT_EQUAL(456, fd.getPluralOperand(PLURAL_OPERAND_F)); // f
693     ASSERT_EQUAL(456, fd.getPluralOperand(PLURAL_OPERAND_T)); // t
694     ASSERT_EQUAL(123, fd.getPluralOperand(PLURAL_OPERAND_I)); // i
695     ASSERT_EQUAL(123.456, fd.getPluralOperand(PLURAL_OPERAND_N)); // n
696     ASSERT_EQUAL(false, fd.hasIntegerValue());
697     ASSERT_EQUAL(false, fd.isNegative());
698 
699     df->formatToDecimalQuantity(-123.456, fd, status);
700     assertSuccess(WHERE, status);
701     ASSERT_EQUAL(3, fd.getPluralOperand(PLURAL_OPERAND_V)); // v
702     ASSERT_EQUAL(456, fd.getPluralOperand(PLURAL_OPERAND_F)); // f
703     ASSERT_EQUAL(456, fd.getPluralOperand(PLURAL_OPERAND_T)); // t
704     ASSERT_EQUAL(123, fd.getPluralOperand(PLURAL_OPERAND_I)); // i
705     ASSERT_EQUAL(123.456, fd.getPluralOperand(PLURAL_OPERAND_N)); // n
706     ASSERT_EQUAL(false, fd.hasIntegerValue());
707     ASSERT_EQUAL(true, fd.isNegative());
708 
709     // test max int digits
710     df->setMaximumIntegerDigits(2);
711     df->formatToDecimalQuantity(123.456, fd, status);
712     assertSuccess(WHERE, status);
713     ASSERT_EQUAL(3, fd.getPluralOperand(PLURAL_OPERAND_V)); // v
714     ASSERT_EQUAL(456, fd.getPluralOperand(PLURAL_OPERAND_F)); // f
715     ASSERT_EQUAL(456, fd.getPluralOperand(PLURAL_OPERAND_T)); // t
716     ASSERT_EQUAL(23, fd.getPluralOperand(PLURAL_OPERAND_I)); // i
717     ASSERT_EQUAL(23.456, fd.getPluralOperand(PLURAL_OPERAND_N)); // n
718     ASSERT_EQUAL(false, fd.hasIntegerValue());
719     ASSERT_EQUAL(false, fd.isNegative());
720 
721     df->formatToDecimalQuantity(-123.456, fd, status);
722     assertSuccess(WHERE, status);
723     ASSERT_EQUAL(3, fd.getPluralOperand(PLURAL_OPERAND_V)); // v
724     ASSERT_EQUAL(456, fd.getPluralOperand(PLURAL_OPERAND_F)); // f
725     ASSERT_EQUAL(456, fd.getPluralOperand(PLURAL_OPERAND_T)); // t
726     ASSERT_EQUAL(23, fd.getPluralOperand(PLURAL_OPERAND_I)); // i
727     ASSERT_EQUAL(23.456, fd.getPluralOperand(PLURAL_OPERAND_N)); // n
728     ASSERT_EQUAL(false, fd.hasIntegerValue());
729     ASSERT_EQUAL(true, fd.isNegative());
730 
731     // test max fraction digits
732     df->setMaximumIntegerDigits(2000000000);
733     df->setMaximumFractionDigits(2);
734     df->formatToDecimalQuantity(123.456, fd, status);
735     assertSuccess(WHERE, status);
736     ASSERT_EQUAL(2, fd.getPluralOperand(PLURAL_OPERAND_V)); // v
737     ASSERT_EQUAL(46, fd.getPluralOperand(PLURAL_OPERAND_F)); // f
738     ASSERT_EQUAL(46, fd.getPluralOperand(PLURAL_OPERAND_T)); // t
739     ASSERT_EQUAL(123, fd.getPluralOperand(PLURAL_OPERAND_I)); // i
740     ASSERT_EQUAL(123.46, fd.getPluralOperand(PLURAL_OPERAND_N)); // n
741     ASSERT_EQUAL(false, fd.hasIntegerValue());
742     ASSERT_EQUAL(false, fd.isNegative());
743 
744     df->formatToDecimalQuantity(-123.456, fd, status);
745     assertSuccess(WHERE, status);
746     ASSERT_EQUAL(2, fd.getPluralOperand(PLURAL_OPERAND_V)); // v
747     ASSERT_EQUAL(46, fd.getPluralOperand(PLURAL_OPERAND_F)); // f
748     ASSERT_EQUAL(46, fd.getPluralOperand(PLURAL_OPERAND_T)); // t
749     ASSERT_EQUAL(123, fd.getPluralOperand(PLURAL_OPERAND_I)); // i
750     ASSERT_EQUAL(123.46, fd.getPluralOperand(PLURAL_OPERAND_N)); // n
751     ASSERT_EQUAL(false, fd.hasIntegerValue());
752     ASSERT_EQUAL(true, fd.isNegative());
753 
754     // test esoteric rounding
755     df->setMaximumFractionDigits(6);
756     df->setRoundingIncrement(7.3);
757 
758     df->formatToDecimalQuantity(30.0, fd, status);
759     assertSuccess(WHERE, status);
760     ASSERT_EQUAL(2, fd.getPluralOperand(PLURAL_OPERAND_V)); // v
761     ASSERT_EQUAL(20, fd.getPluralOperand(PLURAL_OPERAND_F)); // f
762     ASSERT_EQUAL(2, fd.getPluralOperand(PLURAL_OPERAND_T)); // t
763     ASSERT_EQUAL(29, fd.getPluralOperand(PLURAL_OPERAND_I)); // i
764     ASSERT_EQUAL(29.2, fd.getPluralOperand(PLURAL_OPERAND_N)); // n
765     ASSERT_EQUAL(false, fd.hasIntegerValue());
766     ASSERT_EQUAL(false, fd.isNegative());
767 
768     df->formatToDecimalQuantity(-30.0, fd, status);
769     assertSuccess(WHERE, status);
770     ASSERT_EQUAL(2, fd.getPluralOperand(PLURAL_OPERAND_V)); // v
771     ASSERT_EQUAL(20, fd.getPluralOperand(PLURAL_OPERAND_F)); // f
772     ASSERT_EQUAL(2, fd.getPluralOperand(PLURAL_OPERAND_T)); // t
773     ASSERT_EQUAL(29, fd.getPluralOperand(PLURAL_OPERAND_I)); // i
774     ASSERT_EQUAL(29.2, fd.getPluralOperand(PLURAL_OPERAND_N)); // n
775     ASSERT_EQUAL(false, fd.hasIntegerValue());
776     ASSERT_EQUAL(true, fd.isNegative());
777 
778     df.adoptInsteadAndCheckErrorCode(new DecimalFormat("###", status), status);
779     assertSuccess(WHERE, status);
780     df->formatToDecimalQuantity(123.456, fd, status);
781     assertSuccess(WHERE, status);
782     ASSERT_EQUAL(0, fd.getPluralOperand(PLURAL_OPERAND_V));
783     ASSERT_EQUAL(0, fd.getPluralOperand(PLURAL_OPERAND_F));
784     ASSERT_EQUAL(0, fd.getPluralOperand(PLURAL_OPERAND_T));
785     ASSERT_EQUAL(123, fd.getPluralOperand(PLURAL_OPERAND_I));
786     ASSERT_EQUAL(true, fd.hasIntegerValue());
787     ASSERT_EQUAL(false, fd.isNegative());
788 
789     df.adoptInsteadAndCheckErrorCode(new DecimalFormat("###.0", status), status);
790     assertSuccess(WHERE, status);
791     df->formatToDecimalQuantity(123.01, fd, status);
792     assertSuccess(WHERE, status);
793     ASSERT_EQUAL(1, fd.getPluralOperand(PLURAL_OPERAND_V));
794     ASSERT_EQUAL(0, fd.getPluralOperand(PLURAL_OPERAND_F));
795     ASSERT_EQUAL(0, fd.getPluralOperand(PLURAL_OPERAND_T));
796     ASSERT_EQUAL(123, fd.getPluralOperand(PLURAL_OPERAND_I));
797     ASSERT_EQUAL(true, fd.hasIntegerValue());
798     ASSERT_EQUAL(false, fd.isNegative());
799 
800     df.adoptInsteadAndCheckErrorCode(new DecimalFormat("###.0", status), status);
801     assertSuccess(WHERE, status);
802     df->formatToDecimalQuantity(123.06, fd, status);
803     assertSuccess(WHERE, status);
804     ASSERT_EQUAL(1, fd.getPluralOperand(PLURAL_OPERAND_V));
805     ASSERT_EQUAL(1, fd.getPluralOperand(PLURAL_OPERAND_F));
806     ASSERT_EQUAL(1, fd.getPluralOperand(PLURAL_OPERAND_T));
807     ASSERT_EQUAL(123, fd.getPluralOperand(PLURAL_OPERAND_I));
808     ASSERT_EQUAL(false, fd.hasIntegerValue());
809     ASSERT_EQUAL(false, fd.isNegative());
810 
811     df.adoptInsteadAndCheckErrorCode(new DecimalFormat("@@@@@", status), status);  // Significant Digits
812     assertSuccess(WHERE, status);
813     df->formatToDecimalQuantity(123, fd, status);
814     assertSuccess(WHERE, status);
815     ASSERT_EQUAL(2, fd.getPluralOperand(PLURAL_OPERAND_V));
816     ASSERT_EQUAL(0, fd.getPluralOperand(PLURAL_OPERAND_F));
817     ASSERT_EQUAL(0, fd.getPluralOperand(PLURAL_OPERAND_T));
818     ASSERT_EQUAL(123, fd.getPluralOperand(PLURAL_OPERAND_I));
819     ASSERT_EQUAL(true, fd.hasIntegerValue());
820     ASSERT_EQUAL(false, fd.isNegative());
821 
822     df.adoptInsteadAndCheckErrorCode(new DecimalFormat("@@@@@", status), status);  // Significant Digits
823     assertSuccess(WHERE, status);
824     df->formatToDecimalQuantity(1.23, fd, status);
825     assertSuccess(WHERE, status);
826     ASSERT_EQUAL(4, fd.getPluralOperand(PLURAL_OPERAND_V));
827     ASSERT_EQUAL(2300, fd.getPluralOperand(PLURAL_OPERAND_F));
828     ASSERT_EQUAL(23, fd.getPluralOperand(PLURAL_OPERAND_T));
829     ASSERT_EQUAL(1, fd.getPluralOperand(PLURAL_OPERAND_I));
830     ASSERT_EQUAL(false, fd.hasIntegerValue());
831     ASSERT_EQUAL(false, fd.isNegative());
832 
833     df->formatToDecimalQuantity(uprv_getInfinity(), fd, status);
834     assertSuccess(WHERE, status);
835     ASSERT_EQUAL(true, fd.isNaN() || fd.isInfinite());
836     df->formatToDecimalQuantity(0.0, fd, status);
837     ASSERT_EQUAL(false, fd.isNaN() || fd.isInfinite());
838     df->formatToDecimalQuantity(uprv_getNaN(), fd, status);
839     ASSERT_EQUAL(true, fd.isNaN() || fd.isInfinite());
840     assertSuccess(WHERE, status);
841 
842     // Test Big Decimal input.
843     // 22 digits before and after decimal, will exceed the precision of a double
844     //    and force DecimalFormat::getFixedDecimal() to work with a digit list.
845     df.adoptInsteadAndCheckErrorCode(
846         new DecimalFormat("#####################0.00####################", status), status);
847     assertSuccess(WHERE, status);
848     Formattable fable("12.34", status);
849     assertSuccess(WHERE, status);
850     df->formatToDecimalQuantity(fable, fd, status);
851     assertSuccess(WHERE, status);
852     ASSERT_EQUAL(2, fd.getPluralOperand(PLURAL_OPERAND_V));
853     ASSERT_EQUAL(34, fd.getPluralOperand(PLURAL_OPERAND_F));
854     ASSERT_EQUAL(34, fd.getPluralOperand(PLURAL_OPERAND_T));
855     ASSERT_EQUAL(12, fd.getPluralOperand(PLURAL_OPERAND_I));
856     ASSERT_EQUAL(false, fd.hasIntegerValue());
857     ASSERT_EQUAL(false, fd.isNegative());
858 
859     fable.setDecimalNumber("12.3456789012345678900123456789", status);
860     assertSuccess(WHERE, status);
861     df->formatToDecimalQuantity(fable, fd, status);
862     assertSuccess(WHERE, status);
863     ASSERT_EQUAL(22, fd.getPluralOperand(PLURAL_OPERAND_V));
864     ASSERT_EQUAL(3456789012345678900LL, fd.getPluralOperand(PLURAL_OPERAND_F));
865     ASSERT_EQUAL(34567890123456789LL, fd.getPluralOperand(PLURAL_OPERAND_T));
866     ASSERT_EQUAL(12, fd.getPluralOperand(PLURAL_OPERAND_I));
867     ASSERT_EQUAL(false, fd.hasIntegerValue());
868     ASSERT_EQUAL(false, fd.isNegative());
869 
870     // On field overflow, Integer part is truncated on the left, fraction part on the right.
871     fable.setDecimalNumber("123456789012345678901234567890.123456789012345678901234567890", status);
872     assertSuccess(WHERE, status);
873     df->formatToDecimalQuantity(fable, fd, status);
874     assertSuccess(WHERE, status);
875     ASSERT_EQUAL(22, fd.getPluralOperand(PLURAL_OPERAND_V));
876     ASSERT_EQUAL(1234567890123456789LL, fd.getPluralOperand(PLURAL_OPERAND_F));
877     ASSERT_EQUAL(1234567890123456789LL, fd.getPluralOperand(PLURAL_OPERAND_T));
878     ASSERT_EQUAL(345678901234567890LL, fd.getPluralOperand(PLURAL_OPERAND_I));
879     ASSERT_EQUAL(false, fd.hasIntegerValue());
880     ASSERT_EQUAL(false, fd.isNegative());
881 
882     // Digits way to the right of the decimal but within the format's precision aren't truncated
883     fable.setDecimalNumber("1.0000000000000000000012", status);
884     assertSuccess(WHERE, status);
885     df->formatToDecimalQuantity(fable, fd, status);
886     assertSuccess(WHERE, status);
887     ASSERT_EQUAL(22, fd.getPluralOperand(PLURAL_OPERAND_V));
888     ASSERT_EQUAL(12, fd.getPluralOperand(PLURAL_OPERAND_F));
889     ASSERT_EQUAL(12, fd.getPluralOperand(PLURAL_OPERAND_T));
890     ASSERT_EQUAL(1, fd.getPluralOperand(PLURAL_OPERAND_I));
891     ASSERT_EQUAL(false, fd.hasIntegerValue());
892     ASSERT_EQUAL(false, fd.isNegative());
893 
894     // Digits beyond the precision of the format are rounded away
895     fable.setDecimalNumber("1.000000000000000000000012", status);
896     assertSuccess(WHERE, status);
897     df->formatToDecimalQuantity(fable, fd, status);
898     assertSuccess(WHERE, status);
899     ASSERT_EQUAL(2, fd.getPluralOperand(PLURAL_OPERAND_V));
900     ASSERT_EQUAL(0, fd.getPluralOperand(PLURAL_OPERAND_F));
901     ASSERT_EQUAL(0, fd.getPluralOperand(PLURAL_OPERAND_T));
902     ASSERT_EQUAL(1, fd.getPluralOperand(PLURAL_OPERAND_I));
903     ASSERT_EQUAL(true, fd.hasIntegerValue());
904     ASSERT_EQUAL(false, fd.isNegative());
905 
906     // Negative numbers come through
907     fable.setDecimalNumber("-1.0000000000000000000012", status);
908     assertSuccess(WHERE, status);
909     df->formatToDecimalQuantity(fable, fd, status);
910     assertSuccess(WHERE, status);
911     ASSERT_EQUAL(22, fd.getPluralOperand(PLURAL_OPERAND_V));
912     ASSERT_EQUAL(12, fd.getPluralOperand(PLURAL_OPERAND_F));
913     ASSERT_EQUAL(12, fd.getPluralOperand(PLURAL_OPERAND_T));
914     ASSERT_EQUAL(1, fd.getPluralOperand(PLURAL_OPERAND_I));
915     ASSERT_EQUAL(false, fd.hasIntegerValue());
916     ASSERT_EQUAL(true, fd.isNegative());
917 
918     // MinFractionDigits from format larger than from number.
919     fable.setDecimalNumber("1000000000000000000000.3", status);
920     assertSuccess(WHERE, status);
921     df->formatToDecimalQuantity(fable, fd, status);
922     assertSuccess(WHERE, status);
923     ASSERT_EQUAL(2, fd.getPluralOperand(PLURAL_OPERAND_V));
924     ASSERT_EQUAL(30, fd.getPluralOperand(PLURAL_OPERAND_F));
925     ASSERT_EQUAL(3, fd.getPluralOperand(PLURAL_OPERAND_T));
926     ASSERT_EQUAL(0, fd.getPluralOperand(PLURAL_OPERAND_I));
927     ASSERT_EQUAL(false, fd.hasIntegerValue());
928     ASSERT_EQUAL(false, fd.isNegative());
929 
930     fable.setDecimalNumber("1000000000000000050000.3", status);
931     assertSuccess(WHERE, status);
932     df->formatToDecimalQuantity(fable, fd, status);
933     assertSuccess(WHERE, status);
934     ASSERT_EQUAL(2, fd.getPluralOperand(PLURAL_OPERAND_V));
935     ASSERT_EQUAL(30, fd.getPluralOperand(PLURAL_OPERAND_F));
936     ASSERT_EQUAL(3, fd.getPluralOperand(PLURAL_OPERAND_T));
937     ASSERT_EQUAL(50000LL, fd.getPluralOperand(PLURAL_OPERAND_I));
938     ASSERT_EQUAL(false, fd.hasIntegerValue());
939     ASSERT_EQUAL(false, fd.isNegative());
940 
941     // Test some int64_t values that are out of the range of a double
942     fable.setInt64(4503599627370496LL);
943     assertSuccess(WHERE, status);
944     df->formatToDecimalQuantity(fable, fd, status);
945     assertSuccess(WHERE, status);
946     ASSERT_EQUAL(2, fd.getPluralOperand(PLURAL_OPERAND_V));
947     ASSERT_EQUAL(0, fd.getPluralOperand(PLURAL_OPERAND_F));
948     ASSERT_EQUAL(0, fd.getPluralOperand(PLURAL_OPERAND_T));
949     ASSERT_EQUAL(4503599627370496LL, fd.getPluralOperand(PLURAL_OPERAND_I));
950     ASSERT_EQUAL(true, fd.hasIntegerValue());
951     ASSERT_EQUAL(false, fd.isNegative());
952 
953     fable.setInt64(4503599627370497LL);
954     assertSuccess(WHERE, status);
955     df->formatToDecimalQuantity(fable, fd, status);
956     assertSuccess(WHERE, status);
957     ASSERT_EQUAL(2, fd.getPluralOperand(PLURAL_OPERAND_V));
958     ASSERT_EQUAL(0, fd.getPluralOperand(PLURAL_OPERAND_F));
959     ASSERT_EQUAL(0, fd.getPluralOperand(PLURAL_OPERAND_T));
960     ASSERT_EQUAL(4503599627370497LL, fd.getPluralOperand(PLURAL_OPERAND_I));
961     ASSERT_EQUAL(true, fd.hasIntegerValue());
962     ASSERT_EQUAL(false, fd.isNegative());
963 
964     fable.setInt64(9223372036854775807LL);
965     assertSuccess(WHERE, status);
966     df->formatToDecimalQuantity(fable, fd, status);
967     assertSuccess(WHERE, status);
968     ASSERT_EQUAL(2, fd.getPluralOperand(PLURAL_OPERAND_V));
969     ASSERT_EQUAL(0, fd.getPluralOperand(PLURAL_OPERAND_F));
970     ASSERT_EQUAL(0, fd.getPluralOperand(PLURAL_OPERAND_T));
971     // note: going through DigitList path to FixedDecimal, which is trimming
972     //       int64_t fields to 18 digits. See ticket Ticket #10374
973     ASSERT_EQUAL(223372036854775807LL, fd.getPluralOperand(PLURAL_OPERAND_I));
974     ASSERT_EQUAL(true, fd.hasIntegerValue());
975     ASSERT_EQUAL(false, fd.isNegative());
976 
977 }
978 #if defined(_MSC_VER)
979 // Re-enable 4805 warnings (comparisons between int and bool).
980 #pragma warning(pop)
981 #endif
982 
TestBadFastpath()983 void IntlTestDecimalFormatAPI::TestBadFastpath() {
984     UErrorCode status = U_ZERO_ERROR;
985 
986     LocalPointer<DecimalFormat> df(new DecimalFormat("###", status), status);
987     if (U_FAILURE(status)) {
988         dataerrln("Error creating new DecimalFormat - %s", u_errorName(status));
989         return;
990     }
991 
992     UnicodeString fmt;
993     fmt.remove();
994     assertEquals("Format 1234", "1234", df->format(static_cast<int32_t>(1234), fmt));
995     df->setGroupingUsed(false);
996     fmt.remove();
997     assertEquals("Format 1234", "1234", df->format(static_cast<int32_t>(1234), fmt));
998     df->setGroupingUsed(true);
999     df->setGroupingSize(3);
1000     fmt.remove();
1001     assertEquals("Format 1234 w/ grouping", "1,234", df->format(static_cast<int32_t>(1234), fmt));
1002 }
1003 
TestRequiredDecimalPoint()1004 void IntlTestDecimalFormatAPI::TestRequiredDecimalPoint() {
1005     UErrorCode status = U_ZERO_ERROR;
1006     UnicodeString text("99");
1007     Formattable result1;
1008     UnicodeString pat1("##.0000");
1009     UnicodeString pat2("00.0");
1010 
1011     LocalPointer<DecimalFormat> df(new DecimalFormat(pat1, status), status);
1012     if (U_FAILURE(status)) {
1013         dataerrln("Error creating new DecimalFormat - %s", u_errorName(status));
1014         return;
1015     }
1016 
1017     status = U_ZERO_ERROR;
1018     df->applyPattern(pat1, status);
1019     if(U_FAILURE(status)) {
1020         errln(UnicodeString("ERROR: applyPattern() failed"));
1021     }
1022     df->parse(text, result1, status);
1023     if(U_FAILURE(status)) {
1024         errln(UnicodeString("ERROR: parse() failed"));
1025     }
1026     df->setDecimalPatternMatchRequired(true);
1027     df->parse(text, result1, status);
1028     if(U_SUCCESS(status)) {
1029         errln(UnicodeString("ERROR: unexpected parse()"));
1030     }
1031 
1032 
1033     status = U_ZERO_ERROR;
1034     df->applyPattern(pat2, status);
1035     df->setDecimalPatternMatchRequired(false);
1036     if(U_FAILURE(status)) {
1037         errln(UnicodeString("ERROR: applyPattern(2) failed"));
1038     }
1039     df->parse(text, result1, status);
1040     if(U_FAILURE(status)) {
1041         errln(UnicodeString("ERROR: parse(2) failed - ") + u_errorName(status));
1042     }
1043     df->setDecimalPatternMatchRequired(true);
1044     df->parse(text, result1, status);
1045     if(U_SUCCESS(status)) {
1046         errln(UnicodeString("ERROR: unexpected parse(2)"));
1047     }
1048 }
1049 
testErrorCode()1050 void IntlTestDecimalFormatAPI::testErrorCode() {
1051     // Try each DecimalFormat constructor with an errorCode set on input,
1052     // Verify no crashes or leaks, and that the errorCode is not altered.
1053 
1054     UErrorCode status = U_ZERO_ERROR;
1055     const UnicodeString pattern(u"0.###E0");
1056     UParseError pe;
1057     DecimalFormatSymbols symbols(Locale::getUS(), status);
1058     assertSuccess(WHERE, status);
1059 
1060     {
1061         status = U_INTERNAL_PROGRAM_ERROR;
1062         DecimalFormat df(status);
1063         assertEquals(WHERE, U_INTERNAL_PROGRAM_ERROR, status);
1064     }
1065     {
1066         status = U_INTERNAL_PROGRAM_ERROR;
1067         DecimalFormat df(pattern, status);
1068         assertEquals(WHERE, U_INTERNAL_PROGRAM_ERROR, status);
1069     }
1070     {
1071         status = U_INTERNAL_PROGRAM_ERROR;
1072         DecimalFormat df(pattern, new DecimalFormatSymbols(symbols), status);
1073         assertEquals(WHERE, U_INTERNAL_PROGRAM_ERROR, status);
1074     }
1075     {
1076         status = U_INTERNAL_PROGRAM_ERROR;
1077         DecimalFormat df(pattern, new DecimalFormatSymbols(symbols), UNUM_DECIMAL_COMPACT_LONG, status);
1078         assertEquals(WHERE, U_INTERNAL_PROGRAM_ERROR, status);
1079     }
1080     {
1081         status = U_INTERNAL_PROGRAM_ERROR;
1082         DecimalFormat df(pattern, new DecimalFormatSymbols(symbols), pe, status);
1083         assertEquals(WHERE, U_INTERNAL_PROGRAM_ERROR, status);
1084     }
1085     {
1086         status = U_INTERNAL_PROGRAM_ERROR;
1087         DecimalFormat df(pattern, symbols ,status);
1088         assertEquals(WHERE, U_INTERNAL_PROGRAM_ERROR, status);
1089     }
1090 
1091     // Try each DecimalFormat method with an error code parameter, verifying that
1092     //  an input error is not altered, and that no segmentation faults occur.
1093 
1094     status = U_INTERNAL_PROGRAM_ERROR;
1095     DecimalFormat dfBogus(status);
1096     assertEquals(WHERE, U_INTERNAL_PROGRAM_ERROR, status);
1097 
1098     status = U_ZERO_ERROR;
1099     DecimalFormat dfGood(pattern, new DecimalFormatSymbols(symbols), status);
1100     assertSuccess(WHERE, status);
1101 
1102     for (DecimalFormat *df: {&dfBogus, &dfGood}) {
1103         status = U_INTERNAL_PROGRAM_ERROR;
1104         df->setAttribute(UNUM_PARSE_INT_ONLY, 0, status);
1105         assertEquals(WHERE, U_INTERNAL_PROGRAM_ERROR, status);
1106 
1107         status = U_INTERNAL_PROGRAM_ERROR;
1108         df->getAttribute(UNUM_MAX_FRACTION_DIGITS, status);
1109         assertEquals(WHERE, U_INTERNAL_PROGRAM_ERROR, status);
1110 
1111         status = U_INTERNAL_PROGRAM_ERROR;
1112         UnicodeString dest;
1113         FieldPosition fp;
1114         df->format(1.2, dest, fp, status);
1115         assertEquals(WHERE, U_INTERNAL_PROGRAM_ERROR, status);
1116 
1117         status = U_INTERNAL_PROGRAM_ERROR;
1118         df->format(1.2, dest, nullptr, status);
1119         assertEquals(WHERE, U_INTERNAL_PROGRAM_ERROR, status);
1120 
1121         status = U_INTERNAL_PROGRAM_ERROR;
1122         df->format(static_cast<int32_t>(666), dest, nullptr, status);
1123         assertEquals(WHERE, U_INTERNAL_PROGRAM_ERROR, status);
1124 
1125         status = U_INTERNAL_PROGRAM_ERROR;
1126         df->format(static_cast<int64_t>(666), dest, nullptr, status);
1127         assertEquals(WHERE, U_INTERNAL_PROGRAM_ERROR, status);
1128 
1129         status = U_INTERNAL_PROGRAM_ERROR;
1130         df->format(StringPiece("3.1415926535897932384626"), dest, nullptr, status);
1131         assertEquals(WHERE, U_INTERNAL_PROGRAM_ERROR, status);
1132 
1133         status = U_INTERNAL_PROGRAM_ERROR;
1134         df->applyPattern(pattern, status);
1135         assertEquals(WHERE, U_INTERNAL_PROGRAM_ERROR, status);
1136 
1137         status = U_INTERNAL_PROGRAM_ERROR;
1138         df->applyLocalizedPattern(pattern, pe, status);
1139         assertEquals(WHERE, U_INTERNAL_PROGRAM_ERROR, status);
1140 
1141         status = U_INTERNAL_PROGRAM_ERROR;
1142         df->applyLocalizedPattern(pattern, status);
1143         assertEquals(WHERE, U_INTERNAL_PROGRAM_ERROR, status);
1144 
1145         status = U_INTERNAL_PROGRAM_ERROR;
1146         df->setCurrency(u"USD", status);
1147         assertEquals(WHERE, U_INTERNAL_PROGRAM_ERROR, status);
1148 
1149         status = U_INTERNAL_PROGRAM_ERROR;
1150         df->setCurrencyUsage(UCURR_USAGE_CASH, &status);
1151         assertEquals(WHERE, U_INTERNAL_PROGRAM_ERROR, status);
1152     }
1153 }
1154 
testInvalidObject()1155 void IntlTestDecimalFormatAPI::testInvalidObject() {
1156     {
1157         UErrorCode status = U_INTERNAL_PROGRAM_ERROR;
1158         DecimalFormat dfBogus(status);
1159         assertEquals(WHERE, U_INTERNAL_PROGRAM_ERROR, status);
1160 
1161         status = U_ZERO_ERROR;
1162         DecimalFormat dfGood(status);
1163         assertSuccess(WHERE, status);
1164 
1165         // An invalid object should not be equal to a valid object.
1166         // This also tests that no segmentation fault occurs in the comparison operator due
1167         // to any dangling/nullptr pointers. (ICU-20381).
1168         assertTrue(WHERE, dfGood != dfBogus);
1169 
1170         status = U_MEMORY_ALLOCATION_ERROR;
1171         DecimalFormat dfBogus2(status);
1172         assertEquals(WHERE, U_MEMORY_ALLOCATION_ERROR, status);
1173 
1174         // Two invalid objects should not be equal.
1175         // (Also verify that nullptr isn't t dereferenced in the comparison operator.)
1176         assertTrue(WHERE, dfBogus != dfBogus2);
1177 
1178         // Verify the comparison operator works for two valid objects.
1179         status = U_ZERO_ERROR;
1180         DecimalFormat dfGood2(status);
1181         assertSuccess(WHERE, status);
1182         assertTrue(WHERE, dfGood == dfGood2);
1183 
1184         // Verify that the assignment operator sets the object to an invalid state, and
1185         // that no segmentation fault occurs due to any dangling/nullptr pointers.
1186         status = U_INTERNAL_PROGRAM_ERROR;
1187         DecimalFormat dfAssignmentBogus = DecimalFormat(status);
1188         // Verify comparison for the assigned object.
1189         assertTrue(WHERE, dfAssignmentBogus != dfGood);
1190         assertTrue(WHERE, dfAssignmentBogus != dfGood2);
1191         assertTrue(WHERE, dfAssignmentBogus != dfBogus);
1192 
1193         // Verify that cloning our original invalid object gives nullptr.
1194         auto* dfBogusClone = dfBogus.clone();
1195         assertTrue(WHERE,  dfBogusClone == nullptr);
1196         // Verify that cloning our assigned invalid object gives nullptr.
1197         auto* dfBogusClone2 = dfAssignmentBogus.clone();
1198         assertTrue(WHERE, dfBogusClone2 == nullptr);
1199 
1200         // Verify copy constructing from an invalid object is also invalid.
1201         DecimalFormat dfCopy(dfBogus);
1202         assertTrue(WHERE, dfCopy != dfGood);
1203         assertTrue(WHERE, dfCopy != dfGood2);
1204         assertTrue(WHERE, dfCopy != dfBogus);
1205         DecimalFormat dfCopyAssign = dfBogus;
1206         assertTrue(WHERE, dfCopyAssign != dfGood);
1207         assertTrue(WHERE, dfCopyAssign != dfGood2);
1208         assertTrue(WHERE, dfCopyAssign != dfBogus);
1209         auto* dfBogusCopyClone1 = dfCopy.clone();
1210         auto* dfBogusCopyClone2 = dfCopyAssign.clone();
1211         assertTrue(WHERE, dfBogusCopyClone1 == nullptr);
1212         assertTrue(WHERE, dfBogusCopyClone2 == nullptr);
1213     }
1214 
1215     {
1216         // Try each DecimalFormat class method that lacks an error code parameter, verifying
1217         // we don't crash (segmentation fault) on invalid objects.
1218 
1219         UErrorCode status = U_ZERO_ERROR;
1220         const UnicodeString pattern(u"0.###E0");
1221         UParseError pe;
1222         DecimalFormatSymbols symbols(Locale::getUS(), status);
1223         assertSuccess(WHERE, status);
1224         CurrencyPluralInfo currencyPI(status);
1225         assertSuccess(WHERE, status);
1226 
1227         status = U_INTERNAL_PROGRAM_ERROR;
1228         DecimalFormat dfBogus1(status);
1229         assertEquals(WHERE, U_INTERNAL_PROGRAM_ERROR, status);
1230 
1231         status = U_INTERNAL_PROGRAM_ERROR;
1232         DecimalFormat dfBogus2(pattern, status);
1233         assertEquals(WHERE, U_INTERNAL_PROGRAM_ERROR, status);
1234 
1235         status = U_INTERNAL_PROGRAM_ERROR;
1236         DecimalFormat dfBogus3(pattern, new DecimalFormatSymbols(symbols), status);
1237         assertEquals(WHERE, U_INTERNAL_PROGRAM_ERROR, status);
1238 
1239         status = U_INTERNAL_PROGRAM_ERROR;
1240         DecimalFormat dfBogus4(pattern, new DecimalFormatSymbols(symbols), UNumberFormatStyle::UNUM_CURRENCY, status);
1241         assertEquals(WHERE, U_INTERNAL_PROGRAM_ERROR, status);
1242 
1243         status = U_INTERNAL_PROGRAM_ERROR;
1244         DecimalFormat dfBogus5(pattern, new DecimalFormatSymbols(symbols), pe, status);
1245         assertEquals(WHERE, U_INTERNAL_PROGRAM_ERROR, status);
1246 
1247         for (DecimalFormat *df : {&dfBogus1, &dfBogus2, &dfBogus3, &dfBogus4, &dfBogus5})
1248         {
1249             df->setGroupingUsed(true);
1250 
1251             df->setParseIntegerOnly(false);
1252 
1253             df->setLenient(true);
1254 
1255             auto* dfClone = df->clone();
1256             assertTrue(WHERE, dfClone == nullptr);
1257 
1258             UnicodeString dest;
1259             FieldPosition fp;
1260             df->format(1.2, dest, fp);
1261             df->format(static_cast<int32_t>(1234), dest, fp);
1262             df->format(static_cast<int64_t>(1234), dest, fp);
1263 
1264             UnicodeString text("-1,234.00");
1265             Formattable result;
1266             ParsePosition pos(0);
1267             df->parse(text, result, pos);
1268 
1269             CurrencyAmount* ca = df->parseCurrency(text, pos);
1270             assertTrue(WHERE, ca == nullptr);
1271 
1272             const DecimalFormatSymbols* dfs = df->getDecimalFormatSymbols();
1273             assertTrue(WHERE, dfs == nullptr);
1274 
1275             df->adoptDecimalFormatSymbols(nullptr);
1276 
1277             df->setDecimalFormatSymbols(symbols);
1278 
1279             const CurrencyPluralInfo* cpi = df->getCurrencyPluralInfo();
1280             assertTrue(WHERE, cpi == nullptr);
1281 
1282             df->adoptCurrencyPluralInfo(nullptr);
1283 
1284             df->setCurrencyPluralInfo(currencyPI);
1285 
1286             UnicodeString prefix("-123");
1287             df->getPositivePrefix(dest);
1288             df->setPositivePrefix(prefix);
1289             df->getNegativePrefix(dest);
1290             df->setNegativePrefix(prefix);
1291             df->getPositiveSuffix(dest);
1292             df->setPositiveSuffix(prefix);
1293             df->getNegativeSuffix(dest);
1294             df->setNegativeSuffix(prefix);
1295 
1296             df->isSignAlwaysShown();
1297 
1298             df->setSignAlwaysShown(true);
1299 
1300             df->getMultiplier();
1301             df->setMultiplier(10);
1302 
1303             df->getMultiplierScale();
1304             df->setMultiplierScale(2);
1305 
1306             df->getRoundingIncrement();
1307             df->setRoundingIncrement(1.2);
1308 
1309             df->getRoundingMode();
1310             df->setRoundingMode(DecimalFormat::ERoundingMode::kRoundDown);
1311 
1312             df->getFormatWidth();
1313             df->setFormatWidth(0);
1314 
1315             UnicodeString pad(" ");
1316             df->getPadCharacterString();
1317             df->setPadCharacter(pad);
1318 
1319             df->getPadPosition();
1320             df->setPadPosition(DecimalFormat::EPadPosition::kPadBeforePrefix);
1321 
1322             df->isScientificNotation();
1323             df->setScientificNotation(false);
1324 
1325             df->getMinimumExponentDigits();
1326             df->setMinimumExponentDigits(1);
1327 
1328             df->isExponentSignAlwaysShown();
1329             df->setExponentSignAlwaysShown(true);
1330 
1331             df->getGroupingSize();
1332             df->setGroupingSize(3);
1333 
1334             df->getSecondaryGroupingSize();
1335             df->setSecondaryGroupingSize(-1);
1336 
1337             df->getMinimumGroupingDigits();
1338             df->setMinimumGroupingDigits(-1);
1339 
1340             df->isDecimalSeparatorAlwaysShown();
1341             df->setDecimalSeparatorAlwaysShown(true);
1342 
1343             df->isDecimalPatternMatchRequired();
1344             df->setDecimalPatternMatchRequired(false);
1345 
1346             df->isParseNoExponent();
1347             df->setParseNoExponent(true);
1348 
1349             df->isParseCaseSensitive();
1350             df->setParseCaseSensitive(false);
1351 
1352             df->isFormatFailIfMoreThanMaxDigits();
1353             df->setFormatFailIfMoreThanMaxDigits(true);
1354 
1355             df->toPattern(dest);
1356             df->toLocalizedPattern(dest);
1357 
1358             df->setMaximumIntegerDigits(10);
1359             df->setMinimumIntegerDigits(0);
1360 
1361             df->setMaximumFractionDigits(2);
1362             df->setMinimumFractionDigits(0);
1363 
1364             df->getMinimumSignificantDigits();
1365             df->setMinimumSignificantDigits(0);
1366 
1367             df->getMaximumSignificantDigits();
1368             df->setMaximumSignificantDigits(5);
1369 
1370             df->areSignificantDigitsUsed();
1371             df->setSignificantDigitsUsed(true);
1372 
1373             df->setCurrency(u"USD");
1374 
1375             df->getCurrencyUsage();
1376 
1377             const number::LocalizedNumberFormatter* lnf = df->toNumberFormatter(status);
1378             assertEquals("toNumberFormatter should return nullptr",
1379                 (int64_t) nullptr, (int64_t) lnf);
1380 
1381             // Should not crash when chaining to error code enabled methods on the LNF
1382 #if !defined(__clang__)
1383 // ubsan does not like the following. I have not yet find a good way to do run
1384 // time check of ubsan, so I just skip the following test on clang for now
1385             lnf->formatInt(1, status);
1386             lnf->formatDouble(1.0, status);
1387             lnf->formatDecimal("1", status);
1388             lnf->toFormat(status);
1389             lnf->toSkeleton(status);
1390             lnf->copyErrorTo(status);
1391 #endif
1392         }
1393 
1394     }
1395 }
1396 
1397 #endif /* #if !UCONFIG_NO_FORMATTING */
1398