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 33void 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 */ 112void 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 // 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) "" + (int32_t) d + " formatted to " + res1); 229 230 res2 = pat.format(l, res2, pos2); 231 logln((UnicodeString) "" + (int32_t) 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) "" + (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 " + (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 " + (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): " + (int32_t) 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 " + (int8_t) 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 " + (double) 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 " + (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 " + (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 " + (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 458void 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 502void 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((DecimalFormat::ERoundingMode)mode); 527 if(pat.getRoundingMode() != (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(" + (double)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(" + (double)Roundingnumber1 + UnicodeString(",") + mode + UnicodeString(",false) with RoundingIncrement=1.0==>"); 543 verify(message, resultStr, result[i++]); 544 message.remove(); 545 resultStr.remove(); 546 } 547 548} 549void 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 558void 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 565void 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((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 595void 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 sprintf(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 666void 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 983void 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((int32_t)1234, fmt)); 995 df->setGroupingUsed(false); 996 fmt.remove(); 997 assertEquals("Format 1234", "1234", df->format((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((int32_t)1234, fmt)); 1002} 1003 1004void 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 1050void 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((int32_t)666, dest, nullptr, status); 1123 assertEquals(WHERE, U_INTERNAL_PROGRAM_ERROR, status); 1124 1125 status = U_INTERNAL_PROGRAM_ERROR; 1126 df->format((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 1155void 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 lnf->formatInt(1, status); 1383 lnf->formatDouble(1.0, status); 1384 lnf->formatDecimal("1", status); 1385 lnf->toFormat(status); 1386 lnf->toSkeleton(status); 1387 lnf->copyErrorTo(status); 1388 } 1389 1390 } 1391} 1392 1393#endif /* #if !UCONFIG_NO_FORMATTING */ 1394