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-2016, International Business Machines Corporation and 6 * others. All Rights Reserved. 7 ********************************************************************/ 8 /******************************************************************************** 9 * 10 * File CNUMTST.C 11 * 12 * Madhu Katragadda Creation 13 * 14 * Modification History: 15 * 16 * Date Name Description 17 * 06/24/99 helena Integrated Alan's NF enhancements and Java2 bug fixes 18 * 07/15/99 helena Ported to HPUX 10/11 CC. 19 ********************************************************************************* 20 */ 21 22 /* C API TEST FOR NUMBER FORMAT */ 23 24 #include "unicode/utypes.h" 25 26 #if !UCONFIG_NO_FORMATTING 27 28 #include "unicode/uloc.h" 29 #include "unicode/umisc.h" 30 #include "unicode/unum.h" 31 #include "unicode/unumsys.h" 32 #include "unicode/ustring.h" 33 #include "unicode/udisplaycontext.h" 34 35 #include "cintltst.h" 36 #include "cnumtst.h" 37 #include "cmemory.h" 38 #include "cstring.h" 39 #include "putilimp.h" 40 #include <stdio.h> 41 #include <stdlib.h> 42 43 static const char *tagAssert(const char *f, int32_t l, const char *msg) { 44 static char _fileline[1000]; 45 sprintf(_fileline, "%s:%d: ASSERT_TRUE(%s)", f, l, msg); 46 return _fileline; 47 } 48 49 #define ASSERT_TRUE(x) assertTrue(tagAssert(__FILE__, __LINE__, #x), (x)) 50 51 void addNumForTest(TestNode** root); 52 static void TestTextAttributeCrash(void); 53 static void TestNBSPInPattern(void); 54 static void TestInt64Parse(void); 55 static void TestParseCurrency(void); 56 static void TestMaxInt(void); 57 static void TestNoExponent(void); 58 static void TestUFormattable(void); 59 static void TestUNumberingSystem(void); 60 static void TestCurrencyIsoPluralFormat(void); 61 static void TestContext(void); 62 static void TestCurrencyUsage(void); 63 static void TestCurrFmtNegSameAsPositive(void); 64 static void TestVariousStylesAndAttributes(void); 65 static void TestParseCurrPatternWithDecStyle(void); 66 static void TestFormatForFields(void); 67 static void TestRBNFRounding(void); 68 69 #define TESTCASE(x) addTest(root, &x, "tsformat/cnumtst/" #x) 70 71 void addNumForTest(TestNode** root) 72 { 73 TESTCASE(TestNumberFormat); 74 TESTCASE(TestSpelloutNumberParse); 75 TESTCASE(TestSignificantDigits); 76 TESTCASE(TestSigDigRounding); 77 TESTCASE(TestNumberFormatPadding); 78 TESTCASE(TestInt64Format); 79 TESTCASE(TestNonExistentCurrency); 80 TESTCASE(TestCurrencyRegression); 81 TESTCASE(TestTextAttributeCrash); 82 TESTCASE(TestRBNFFormat); 83 TESTCASE(TestRBNFRounding); 84 TESTCASE(TestNBSPInPattern); 85 TESTCASE(TestInt64Parse); 86 TESTCASE(TestParseZero); 87 TESTCASE(TestParseCurrency); 88 TESTCASE(TestCloneWithRBNF); 89 TESTCASE(TestMaxInt); 90 TESTCASE(TestNoExponent); 91 TESTCASE(TestUFormattable); 92 TESTCASE(TestUNumberingSystem); 93 TESTCASE(TestCurrencyIsoPluralFormat); 94 TESTCASE(TestContext); 95 TESTCASE(TestCurrencyUsage); 96 TESTCASE(TestCurrFmtNegSameAsPositive); 97 TESTCASE(TestVariousStylesAndAttributes); 98 TESTCASE(TestParseCurrPatternWithDecStyle); 99 TESTCASE(TestFormatForFields); 100 } 101 102 /* test Parse int 64 */ 103 104 static void TestInt64Parse() 105 { 106 107 UErrorCode st = U_ZERO_ERROR; 108 UErrorCode* status = &st; 109 110 const char* st1 = "009223372036854775808"; 111 const int size = 21; 112 UChar text[21]; 113 114 115 UNumberFormat* nf; 116 117 int64_t a; 118 119 u_charsToUChars(st1, text, size); 120 nf = unum_open(UNUM_DEFAULT, NULL, -1, NULL, NULL, status); 121 122 if(U_FAILURE(*status)) 123 { 124 log_data_err("Error in unum_open() %s \n", myErrorName(*status)); 125 return; 126 } 127 128 log_verbose("About to test unum_parseInt64() with out of range number\n"); 129 130 a = unum_parseInt64(nf, text, size, 0, status); 131 (void)a; /* Suppress set but not used warning. */ 132 133 134 if(!U_FAILURE(*status)) 135 { 136 log_err("Error in unum_parseInt64(): %s \n", myErrorName(*status)); 137 } 138 else 139 { 140 log_verbose("unum_parseInt64() successful\n"); 141 } 142 143 unum_close(nf); 144 return; 145 } 146 147 /* test Number Format API */ 148 static void TestNumberFormat() 149 { 150 UChar *result=NULL; 151 UChar temp1[512]; 152 UChar temp2[512]; 153 154 UChar temp[5]; 155 156 UChar prefix[5]; 157 UChar suffix[5]; 158 UChar symbol[20]; 159 int32_t resultlength; 160 int32_t resultlengthneeded; 161 int32_t parsepos; 162 double d1 = -1.0; 163 int32_t l1; 164 double d = -10456.37; 165 double a = 1234.56, a1 = 1235.0; 166 int32_t l = 100000000; 167 UFieldPosition pos1; 168 UFieldPosition pos2; 169 int32_t numlocales; 170 int32_t i; 171 172 UNumberFormatAttribute attr; 173 UNumberFormatSymbol symType = UNUM_DECIMAL_SEPARATOR_SYMBOL; 174 int32_t newvalue; 175 UErrorCode status=U_ZERO_ERROR; 176 UNumberFormatStyle style= UNUM_DEFAULT; 177 UNumberFormat *pattern; 178 UNumberFormat *def, *fr, *cur_def, *cur_fr, *per_def, *per_fr, 179 *cur_frpattern, *myclone, *spellout_def; 180 181 /* Testing unum_open() with various Numberformat styles and locales*/ 182 status = U_ZERO_ERROR; 183 log_verbose("Testing unum_open() with default style and locale\n"); 184 def=unum_open(style, NULL,0,NULL, NULL,&status); 185 186 /* Might as well pack it in now if we can't even get a default NumberFormat... */ 187 if(U_FAILURE(status)) 188 { 189 log_data_err("Error in creating default NumberFormat using unum_open(): %s (Are you missing data?)\n", myErrorName(status)); 190 return; 191 } 192 193 log_verbose("\nTesting unum_open() with french locale and default style(decimal)\n"); 194 fr=unum_open(style,NULL,0, "fr_FR",NULL, &status); 195 if(U_FAILURE(status)) 196 log_err("Error: could not create NumberFormat (french): %s\n", myErrorName(status)); 197 198 log_verbose("\nTesting unum_open(currency,NULL,status)\n"); 199 style=UNUM_CURRENCY; 200 /* Can't hardcode the result to assume the default locale is "en_US". */ 201 cur_def=unum_open(style, NULL,0,"en_US", NULL, &status); 202 if(U_FAILURE(status)) 203 log_err("Error: could not create NumberFormat using \n unum_open(currency, NULL, &status) %s\n", 204 myErrorName(status) ); 205 206 log_verbose("\nTesting unum_open(currency, frenchlocale, status)\n"); 207 cur_fr=unum_open(style,NULL,0, "fr_FR", NULL, &status); 208 if(U_FAILURE(status)) 209 log_err("Error: could not create NumberFormat using unum_open(currency, french, &status): %s\n", 210 myErrorName(status)); 211 212 log_verbose("\nTesting unum_open(percent, NULL, status)\n"); 213 style=UNUM_PERCENT; 214 per_def=unum_open(style,NULL,0, NULL,NULL, &status); 215 if(U_FAILURE(status)) 216 log_err("Error: could not create NumberFormat using unum_open(percent, NULL, &status): %s\n", myErrorName(status)); 217 218 log_verbose("\nTesting unum_open(percent,frenchlocale, status)\n"); 219 per_fr=unum_open(style, NULL,0,"fr_FR", NULL,&status); 220 if(U_FAILURE(status)) 221 log_err("Error: could not create NumberFormat using unum_open(percent, french, &status): %s\n", myErrorName(status)); 222 223 log_verbose("\nTesting unum_open(spellout, NULL, status)"); 224 style=UNUM_SPELLOUT; 225 spellout_def=unum_open(style, NULL, 0, "en_US", NULL, &status); 226 if(U_FAILURE(status)) 227 log_err("Error: could not create NumberFormat using unum_open(spellout, NULL, &status): %s\n", myErrorName(status)); 228 229 /* Testing unum_clone(..) */ 230 log_verbose("\nTesting unum_clone(fmt, status)"); 231 status = U_ZERO_ERROR; 232 myclone = unum_clone(def,&status); 233 if(U_FAILURE(status)) 234 log_err("Error: could not clone unum_clone(def, &status): %s\n", myErrorName(status)); 235 else 236 { 237 log_verbose("unum_clone() successful\n"); 238 } 239 240 /*Testing unum_getAvailable() and unum_countAvailable()*/ 241 log_verbose("\nTesting getAvailableLocales and countAvailable()\n"); 242 numlocales=unum_countAvailable(); 243 if(numlocales < 0) 244 log_err("error in countAvailable"); 245 else{ 246 log_verbose("unum_countAvialable() successful\n"); 247 log_verbose("The no: of locales where number formattting is applicable is %d\n", numlocales); 248 } 249 for(i=0;i<numlocales;i++) 250 { 251 log_verbose("%s\n", unum_getAvailable(i)); 252 if (unum_getAvailable(i) == 0) 253 log_err("No locale for which number formatting patterns are applicable\n"); 254 else 255 log_verbose("A locale %s for which number formatting patterns are applicable\n",unum_getAvailable(i)); 256 } 257 258 259 /*Testing unum_format() and unum_formatdouble()*/ 260 u_uastrcpy(temp1, "$100,000,000.00"); 261 262 log_verbose("\nTesting unum_format() \n"); 263 resultlength=0; 264 pos1.field = UNUM_INTEGER_FIELD; 265 resultlengthneeded=unum_format(cur_def, l, NULL, resultlength, &pos1, &status); 266 if(status==U_BUFFER_OVERFLOW_ERROR) 267 { 268 status=U_ZERO_ERROR; 269 resultlength=resultlengthneeded+1; 270 result=(UChar*)malloc(sizeof(UChar) * resultlength); 271 /* for (i = 0; i < 100000; i++) */ 272 { 273 unum_format(cur_def, l, result, resultlength, &pos1, &status); 274 } 275 } 276 277 if(U_FAILURE(status)) 278 { 279 log_err("Error in formatting using unum_format(.....): %s\n", myErrorName(status) ); 280 } 281 if(u_strcmp(result, temp1)==0) 282 log_verbose("Pass: Number formatting using unum_format() successful\n"); 283 else 284 log_err("Fail: Error in number Formatting using unum_format()\n"); 285 if(pos1.beginIndex == 1 && pos1.endIndex == 12) 286 log_verbose("Pass: Complete number formatting using unum_format() successful\n"); 287 else 288 log_err("Fail: Error in complete number Formatting using unum_format()\nGot: b=%d end=%d\nExpected: b=1 end=12\n", 289 pos1.beginIndex, pos1.endIndex); 290 291 free(result); 292 result = 0; 293 294 log_verbose("\nTesting unum_formatDouble()\n"); 295 u_uastrcpy(temp1, "-$10,456.37"); 296 resultlength=0; 297 pos2.field = UNUM_FRACTION_FIELD; 298 resultlengthneeded=unum_formatDouble(cur_def, d, NULL, resultlength, &pos2, &status); 299 if(status==U_BUFFER_OVERFLOW_ERROR) 300 { 301 status=U_ZERO_ERROR; 302 resultlength=resultlengthneeded+1; 303 result=(UChar*)malloc(sizeof(UChar) * resultlength); 304 /* for (i = 0; i < 100000; i++) */ 305 { 306 unum_formatDouble(cur_def, d, result, resultlength, &pos2, &status); 307 } 308 } 309 if(U_FAILURE(status)) 310 { 311 log_err("Error in formatting using unum_formatDouble(.....): %s\n", myErrorName(status)); 312 } 313 if(result && u_strcmp(result, temp1)==0) 314 log_verbose("Pass: Number Formatting using unum_formatDouble() Successful\n"); 315 else { 316 log_err("FAIL: Error in number formatting using unum_formatDouble() - got '%s' expected '%s'\n", 317 aescstrdup(result, -1), aescstrdup(temp1, -1)); 318 } 319 if(pos2.beginIndex == 9 && pos2.endIndex == 11) 320 log_verbose("Pass: Complete number formatting using unum_format() successful\n"); 321 else 322 log_err("Fail: Error in complete number Formatting using unum_formatDouble()\nGot: b=%d end=%d\nExpected: b=9 end=11", 323 pos1.beginIndex, pos1.endIndex); 324 325 326 /* Testing unum_parse() and unum_parseDouble() */ 327 log_verbose("\nTesting unum_parseDouble()\n"); 328 /* for (i = 0; i < 100000; i++)*/ 329 parsepos=0; 330 if (result != NULL) { 331 d1=unum_parseDouble(cur_def, result, u_strlen(result), &parsepos, &status); 332 } else { 333 log_err("result is NULL\n"); 334 } 335 if(U_FAILURE(status)) { 336 log_err("parse of '%s' failed. Parsepos=%d. The error is : %s\n", aescstrdup(result,u_strlen(result)),parsepos, myErrorName(status)); 337 } 338 339 if(d1!=d) 340 log_err("Fail: Error in parsing\n"); 341 else 342 log_verbose("Pass: parsing successful\n"); 343 if (result) 344 free(result); 345 result = 0; 346 347 status = U_ZERO_ERROR; 348 /* Testing unum_formatDoubleCurrency / unum_parseDoubleCurrency */ 349 log_verbose("\nTesting unum_formatDoubleCurrency\n"); 350 u_uastrcpy(temp1, "Y1,235"); 351 temp1[0] = 0xA5; /* Yen sign */ 352 u_uastrcpy(temp, "JPY"); 353 resultlength=0; 354 pos2.field = UNUM_INTEGER_FIELD; 355 resultlengthneeded=unum_formatDoubleCurrency(cur_def, a, temp, NULL, resultlength, &pos2, &status); 356 if (status==U_BUFFER_OVERFLOW_ERROR) { 357 status=U_ZERO_ERROR; 358 resultlength=resultlengthneeded+1; 359 result=(UChar*)malloc(sizeof(UChar) * resultlength); 360 unum_formatDoubleCurrency(cur_def, a, temp, result, resultlength, &pos2, &status); 361 } 362 if (U_FAILURE(status)) { 363 log_err("Error in formatting using unum_formatDoubleCurrency(.....): %s\n", myErrorName(status)); 364 } 365 if (result && u_strcmp(result, temp1)==0) { 366 log_verbose("Pass: Number Formatting using unum_formatDoubleCurrency() Successful\n"); 367 } else { 368 log_err("FAIL: Error in number formatting using unum_formatDoubleCurrency() - got '%s' expected '%s'\n", 369 aescstrdup(result, -1), aescstrdup(temp1, -1)); 370 } 371 if (pos2.beginIndex == 1 && pos2.endIndex == 6) { 372 log_verbose("Pass: Complete number formatting using unum_format() successful\n"); 373 } else { 374 log_err("Fail: Error in complete number Formatting using unum_formatDouble()\nGot: b=%d end=%d\nExpected: b=1 end=6\n", 375 pos1.beginIndex, pos1.endIndex); 376 } 377 378 log_verbose("\nTesting unum_parseDoubleCurrency\n"); 379 parsepos=0; 380 if (result == NULL) { 381 log_err("result is NULL\n"); 382 } 383 else { 384 d1=unum_parseDoubleCurrency(cur_def, result, u_strlen(result), &parsepos, temp2, &status); 385 if (U_FAILURE(status)) { 386 log_err("parseDoubleCurrency '%s' failed. The error is : %s\n", aescstrdup(result, u_strlen(result)), myErrorName(status)); 387 } 388 /* Note: a==1234.56, but on parse expect a1=1235.0 */ 389 if (d1!=a1) { 390 log_err("Fail: Error in parsing currency, got %f, expected %f\n", d1, a1); 391 } else { 392 log_verbose("Pass: parsed currency amount successfully\n"); 393 } 394 if (u_strcmp(temp2, temp)==0) { 395 log_verbose("Pass: parsed correct currency\n"); 396 } else { 397 log_err("Fail: parsed incorrect currency\n"); 398 } 399 } 400 status = U_ZERO_ERROR; /* reset */ 401 402 free(result); 403 result = 0; 404 405 406 /* performance testing */ 407 u_uastrcpy(temp1, "$462.12345"); 408 resultlength=u_strlen(temp1); 409 /* for (i = 0; i < 100000; i++) */ 410 { 411 parsepos=0; 412 d1=unum_parseDouble(cur_def, temp1, resultlength, &parsepos, &status); 413 } 414 if(U_FAILURE(status)) 415 { 416 log_err("parseDouble('%s') failed. The error is : %s\n", aescstrdup(temp1, resultlength), myErrorName(status)); 417 } 418 419 /* 420 * Note: "for strict standard conformance all operations and constants are now supposed to be 421 evaluated in precision of long double". So, we assign a1 before comparing to a double. Bug #7932. 422 */ 423 a1 = 462.12345; 424 425 if(d1!=a1) 426 log_err("Fail: Error in parsing\n"); 427 else 428 log_verbose("Pass: parsing successful\n"); 429 430 free(result); 431 432 u_uastrcpy(temp1, "($10,456.3E1])"); 433 parsepos=0; 434 d1=unum_parseDouble(cur_def, temp1, u_strlen(temp1), &parsepos, &status); 435 if(U_SUCCESS(status)) 436 { 437 log_err("Error in unum_parseDouble(..., %s, ...): %s\n", temp1, myErrorName(status)); 438 } 439 440 441 log_verbose("\nTesting unum_format()\n"); 442 status=U_ZERO_ERROR; 443 resultlength=0; 444 parsepos=0; 445 resultlengthneeded=unum_format(per_fr, l, NULL, resultlength, &pos1, &status); 446 if(status==U_BUFFER_OVERFLOW_ERROR) 447 { 448 status=U_ZERO_ERROR; 449 resultlength=resultlengthneeded+1; 450 result=(UChar*)malloc(sizeof(UChar) * resultlength); 451 /* for (i = 0; i < 100000; i++)*/ 452 { 453 unum_format(per_fr, l, result, resultlength, &pos1, &status); 454 } 455 } 456 if(U_FAILURE(status)) 457 { 458 log_err("Error in formatting using unum_format(.....): %s\n", myErrorName(status)); 459 } 460 461 462 log_verbose("\nTesting unum_parse()\n"); 463 /* for (i = 0; i < 100000; i++) */ 464 { 465 parsepos=0; 466 l1=unum_parse(per_fr, result, u_strlen(result), &parsepos, &status); 467 } 468 if(U_FAILURE(status)) 469 { 470 log_err("parse failed. The error is : %s\n", myErrorName(status)); 471 } 472 473 if(l1!=l) 474 log_err("Fail: Error in parsing\n"); 475 else 476 log_verbose("Pass: parsing successful\n"); 477 478 free(result); 479 480 /* create a number format using unum_openPattern(....)*/ 481 log_verbose("\nTesting unum_openPattern()\n"); 482 u_uastrcpy(temp1, "#,##0.0#;(#,##0.0#)"); 483 pattern=unum_open(UNUM_IGNORE,temp1, u_strlen(temp1), NULL, NULL,&status); 484 if(U_FAILURE(status)) 485 { 486 log_err("error in unum_openPattern(): %s\n", myErrorName(status) );; 487 } 488 else 489 log_verbose("Pass: unum_openPattern() works fine\n"); 490 491 /*test for unum_toPattern()*/ 492 log_verbose("\nTesting unum_toPattern()\n"); 493 resultlength=0; 494 resultlengthneeded=unum_toPattern(pattern, FALSE, NULL, resultlength, &status); 495 if(status==U_BUFFER_OVERFLOW_ERROR) 496 { 497 status=U_ZERO_ERROR; 498 resultlength=resultlengthneeded+1; 499 result=(UChar*)malloc(sizeof(UChar) * resultlength); 500 unum_toPattern(pattern, FALSE, result, resultlength, &status); 501 } 502 if(U_FAILURE(status)) 503 { 504 log_err("error in extracting the pattern from UNumberFormat: %s\n", myErrorName(status)); 505 } 506 else 507 { 508 if(u_strcmp(result, temp1)!=0) 509 log_err("FAIL: Error in extracting the pattern using unum_toPattern()\n"); 510 else 511 log_verbose("Pass: extracted the pattern correctly using unum_toPattern()\n"); 512 free(result); 513 } 514 515 /*Testing unum_getSymbols() and unum_setSymbols()*/ 516 log_verbose("\nTesting unum_getSymbols and unum_setSymbols()\n"); 517 /*when we try to change the symbols of french to default we need to apply the pattern as well to fetch correct results */ 518 resultlength=0; 519 resultlengthneeded=unum_toPattern(cur_def, FALSE, NULL, resultlength, &status); 520 if(status==U_BUFFER_OVERFLOW_ERROR) 521 { 522 status=U_ZERO_ERROR; 523 resultlength=resultlengthneeded+1; 524 result=(UChar*)malloc(sizeof(UChar) * resultlength); 525 unum_toPattern(cur_def, FALSE, result, resultlength, &status); 526 } 527 if(U_FAILURE(status)) 528 { 529 log_err("error in extracting the pattern from UNumberFormat: %s\n", myErrorName(status)); 530 } 531 532 status=U_ZERO_ERROR; 533 cur_frpattern=unum_open(UNUM_IGNORE,result, u_strlen(result), "fr_FR",NULL, &status); 534 if(U_FAILURE(status)) 535 { 536 log_err("error in unum_openPattern(): %s\n", myErrorName(status)); 537 } 538 539 free(result); 540 541 /*getting the symbols of cur_def */ 542 /*set the symbols of cur_frpattern to cur_def */ 543 for (symType = UNUM_DECIMAL_SEPARATOR_SYMBOL; symType < UNUM_FORMAT_SYMBOL_COUNT; symType++) { 544 status=U_ZERO_ERROR; 545 unum_getSymbol(cur_def, symType, temp1, sizeof(temp1), &status); 546 unum_setSymbol(cur_frpattern, symType, temp1, -1, &status); 547 if(U_FAILURE(status)) 548 { 549 log_err("Error in get/set symbols: %s\n", myErrorName(status)); 550 } 551 } 552 553 /*format to check the result */ 554 resultlength=0; 555 resultlengthneeded=unum_format(cur_def, l, NULL, resultlength, &pos1, &status); 556 if(status==U_BUFFER_OVERFLOW_ERROR) 557 { 558 status=U_ZERO_ERROR; 559 resultlength=resultlengthneeded+1; 560 result=(UChar*)malloc(sizeof(UChar) * resultlength); 561 unum_format(cur_def, l, result, resultlength, &pos1, &status); 562 } 563 if(U_FAILURE(status)) 564 { 565 log_err("Error in formatting using unum_format(.....): %s\n", myErrorName(status)); 566 } 567 568 if(U_FAILURE(status)){ 569 log_err("Fail: error in unum_setSymbols: %s\n", myErrorName(status)); 570 } 571 unum_applyPattern(cur_frpattern, FALSE, result, u_strlen(result),NULL,NULL); 572 573 for (symType = UNUM_DECIMAL_SEPARATOR_SYMBOL; symType < UNUM_FORMAT_SYMBOL_COUNT; symType++) { 574 status=U_ZERO_ERROR; 575 unum_getSymbol(cur_def, symType, temp1, sizeof(temp1), &status); 576 unum_getSymbol(cur_frpattern, symType, temp2, sizeof(temp2), &status); 577 if(U_FAILURE(status) || u_strcmp(temp1, temp2) != 0) 578 { 579 log_err("Fail: error in getting symbols\n"); 580 } 581 else 582 log_verbose("Pass: get and set symbols successful\n"); 583 } 584 585 /*format and check with the previous result */ 586 587 resultlength=0; 588 resultlengthneeded=unum_format(cur_frpattern, l, NULL, resultlength, &pos1, &status); 589 if(status==U_BUFFER_OVERFLOW_ERROR) 590 { 591 status=U_ZERO_ERROR; 592 resultlength=resultlengthneeded+1; 593 unum_format(cur_frpattern, l, temp1, resultlength, &pos1, &status); 594 } 595 if(U_FAILURE(status)) 596 { 597 log_err("Error in formatting using unum_format(.....): %s\n", myErrorName(status)); 598 } 599 /* TODO: 600 * This test fails because we have not called unum_applyPattern(). 601 * Currently, such an applyPattern() does not exist on the C API, and 602 * we have jitterbug 411 for it. 603 * Since it is close to the 1.5 release, I (markus) am disabling this test just 604 * for this release (I added the test itself only last week). 605 * For the next release, we need to fix this. 606 * Then, remove the uprv_strcmp("1.5", ...) and this comment, and the include "cstring.h" at the beginning of this file. 607 */ 608 if(u_strcmp(result, temp1) != 0) { 609 log_err("Formatting failed after setting symbols. result=%s temp1=%s\n", result, temp1); 610 } 611 612 613 /*----------- */ 614 615 free(result); 616 617 /* Testing unum_get/setSymbol() */ 618 for(i = 0; i < UNUM_FORMAT_SYMBOL_COUNT; ++i) { 619 symbol[0] = (UChar)(0x41 + i); 620 symbol[1] = (UChar)(0x61 + i); 621 unum_setSymbol(cur_frpattern, (UNumberFormatSymbol)i, symbol, 2, &status); 622 if(U_FAILURE(status)) { 623 log_err("Error from unum_setSymbol(%d): %s\n", i, myErrorName(status)); 624 return; 625 } 626 } 627 for(i = 0; i < UNUM_FORMAT_SYMBOL_COUNT; ++i) { 628 resultlength = unum_getSymbol(cur_frpattern, (UNumberFormatSymbol)i, symbol, UPRV_LENGTHOF(symbol), &status); 629 if(U_FAILURE(status)) { 630 log_err("Error from unum_getSymbol(%d): %s\n", i, myErrorName(status)); 631 return; 632 } 633 if(resultlength != 2 || symbol[0] != 0x41 + i || symbol[1] != 0x61 + i) { 634 log_err("Failure in unum_getSymbol(%d): got unexpected symbol\n", i); 635 } 636 } 637 /*try getting from a bogus symbol*/ 638 unum_getSymbol(cur_frpattern, (UNumberFormatSymbol)i, symbol, UPRV_LENGTHOF(symbol), &status); 639 if(U_SUCCESS(status)){ 640 log_err("Error : Expected U_ILLEGAL_ARGUMENT_ERROR for bogus symbol"); 641 } 642 if(U_FAILURE(status)){ 643 if(status != U_ILLEGAL_ARGUMENT_ERROR){ 644 log_err("Error: Expected U_ILLEGAL_ARGUMENT_ERROR for bogus symbol, Got %s\n", myErrorName(status)); 645 } 646 } 647 status=U_ZERO_ERROR; 648 649 /* Testing unum_getTextAttribute() and unum_setTextAttribute()*/ 650 log_verbose("\nTesting getting and setting text attributes\n"); 651 resultlength=5; 652 unum_getTextAttribute(cur_fr, UNUM_NEGATIVE_SUFFIX, temp, resultlength, &status); 653 if(U_FAILURE(status)) 654 { 655 log_err("Failure in gettting the Text attributes of number format: %s\n", myErrorName(status)); 656 } 657 unum_setTextAttribute(cur_def, UNUM_NEGATIVE_SUFFIX, temp, u_strlen(temp), &status); 658 if(U_FAILURE(status)) 659 { 660 log_err("Failure in gettting the Text attributes of number format: %s\n", myErrorName(status)); 661 } 662 unum_getTextAttribute(cur_def, UNUM_NEGATIVE_SUFFIX, suffix, resultlength, &status); 663 if(U_FAILURE(status)) 664 { 665 log_err("Failure in gettting the Text attributes of number format: %s\n", myErrorName(status)); 666 } 667 if(u_strcmp(suffix,temp)!=0) 668 log_err("Fail:Error in setTextAttribute or getTextAttribute in setting and getting suffix\n"); 669 else 670 log_verbose("Pass: setting and getting suffix works fine\n"); 671 /*set it back to normal */ 672 u_uastrcpy(temp,"$"); 673 unum_setTextAttribute(cur_def, UNUM_NEGATIVE_SUFFIX, temp, u_strlen(temp), &status); 674 675 /*checking some more text setter conditions */ 676 u_uastrcpy(prefix, "+"); 677 unum_setTextAttribute(def, UNUM_POSITIVE_PREFIX, prefix, u_strlen(prefix) , &status); 678 if(U_FAILURE(status)) 679 { 680 log_err("error in setting the text attributes : %s\n", myErrorName(status)); 681 } 682 unum_getTextAttribute(def, UNUM_POSITIVE_PREFIX, temp, resultlength, &status); 683 if(U_FAILURE(status)) 684 { 685 log_err("error in getting the text attributes : %s\n", myErrorName(status)); 686 } 687 688 if(u_strcmp(prefix, temp)!=0) 689 log_err("ERROR: get and setTextAttributes with positive prefix failed\n"); 690 else 691 log_verbose("Pass: get and setTextAttributes with positive prefix works fine\n"); 692 693 u_uastrcpy(prefix, "+"); 694 unum_setTextAttribute(def, UNUM_NEGATIVE_PREFIX, prefix, u_strlen(prefix), &status); 695 if(U_FAILURE(status)) 696 { 697 log_err("error in setting the text attributes : %s\n", myErrorName(status)); 698 } 699 unum_getTextAttribute(def, UNUM_NEGATIVE_PREFIX, temp, resultlength, &status); 700 if(U_FAILURE(status)) 701 { 702 log_err("error in getting the text attributes : %s\n", myErrorName(status)); 703 } 704 if(u_strcmp(prefix, temp)!=0) 705 log_err("ERROR: get and setTextAttributes with negative prefix failed\n"); 706 else 707 log_verbose("Pass: get and setTextAttributes with negative prefix works fine\n"); 708 709 u_uastrcpy(suffix, "+"); 710 unum_setTextAttribute(def, UNUM_NEGATIVE_SUFFIX, suffix, u_strlen(suffix) , &status); 711 if(U_FAILURE(status)) 712 { 713 log_err("error in setting the text attributes: %s\n", myErrorName(status)); 714 } 715 716 unum_getTextAttribute(def, UNUM_NEGATIVE_SUFFIX, temp, resultlength, &status); 717 if(U_FAILURE(status)) 718 { 719 log_err("error in getting the text attributes : %s\n", myErrorName(status)); 720 } 721 if(u_strcmp(suffix, temp)!=0) 722 log_err("ERROR: get and setTextAttributes with negative suffix failed\n"); 723 else 724 log_verbose("Pass: get and settextAttributes with negative suffix works fine\n"); 725 726 u_uastrcpy(suffix, "++"); 727 unum_setTextAttribute(def, UNUM_POSITIVE_SUFFIX, suffix, u_strlen(suffix) , &status); 728 if(U_FAILURE(status)) 729 { 730 log_err("error in setting the text attributes: %s\n", myErrorName(status)); 731 } 732 733 unum_getTextAttribute(def, UNUM_POSITIVE_SUFFIX, temp, resultlength, &status); 734 if(U_FAILURE(status)) 735 { 736 log_err("error in getting the text attributes : %s\n", myErrorName(status)); 737 } 738 if(u_strcmp(suffix, temp)!=0) 739 log_err("ERROR: get and setTextAttributes with negative suffix failed\n"); 740 else 741 log_verbose("Pass: get and settextAttributes with negative suffix works fine\n"); 742 743 /*Testing unum_getAttribute and unum_setAttribute() */ 744 log_verbose("\nTesting get and set Attributes\n"); 745 attr=UNUM_GROUPING_SIZE; 746 newvalue=unum_getAttribute(def, attr); 747 newvalue=2; 748 unum_setAttribute(def, attr, newvalue); 749 if(unum_getAttribute(def,attr)!=2) 750 log_err("Fail: error in setting and getting attributes for UNUM_GROUPING_SIZE\n"); 751 else 752 log_verbose("Pass: setting and getting attributes for UNUM_GROUPING_SIZE works fine\n"); 753 754 attr=UNUM_MULTIPLIER; 755 newvalue=unum_getAttribute(def, attr); 756 newvalue=8; 757 unum_setAttribute(def, attr, newvalue); 758 if(unum_getAttribute(def,attr) != 8) 759 log_err("error in setting and getting attributes for UNUM_MULTIPLIER\n"); 760 else 761 log_verbose("Pass:setting and getting attributes for UNUM_MULTIPLIER works fine\n"); 762 763 attr=UNUM_SECONDARY_GROUPING_SIZE; 764 newvalue=unum_getAttribute(def, attr); 765 newvalue=2; 766 unum_setAttribute(def, attr, newvalue); 767 if(unum_getAttribute(def,attr) != 2) 768 log_err("error in setting and getting attributes for UNUM_SECONDARY_GROUPING_SIZE\n"); 769 else 770 log_verbose("Pass:setting and getting attributes for UNUM_SECONDARY_GROUPING_SIZE works fine\n"); 771 772 /*testing set and get Attributes extensively */ 773 log_verbose("\nTesting get and set attributes extensively\n"); 774 for(attr=UNUM_PARSE_INT_ONLY; attr<= UNUM_PADDING_POSITION; attr=(UNumberFormatAttribute)((int32_t)attr + 1) ) 775 { 776 newvalue=unum_getAttribute(fr, attr); 777 unum_setAttribute(def, attr, newvalue); 778 if(unum_getAttribute(def,attr)!=unum_getAttribute(fr, attr)) 779 log_err("error in setting and getting attributes\n"); 780 else 781 log_verbose("Pass: attributes set and retrieved successfully\n"); 782 } 783 784 /*testing spellout format to make sure we can use it successfully.*/ 785 log_verbose("\nTesting spellout format\n"); 786 if (spellout_def) 787 { 788 static const int32_t values[] = { 0, -5, 105, 1005, 105050 }; 789 for (i = 0; i < UPRV_LENGTHOF(values); ++i) { 790 UChar buffer[128]; 791 int32_t len; 792 int32_t value = values[i]; 793 status = U_ZERO_ERROR; 794 len = unum_format(spellout_def, value, buffer, UPRV_LENGTHOF(buffer), NULL, &status); 795 if(U_FAILURE(status)) { 796 log_err("Error in formatting using unum_format(spellout_fmt, ...): %s\n", myErrorName(status)); 797 } else { 798 int32_t pp = 0; 799 int32_t parseResult; 800 /*ustrToAstr(buffer, len, logbuf, UPRV_LENGTHOF(logbuf));*/ 801 log_verbose("formatted %d as '%s', length: %d\n", value, aescstrdup(buffer, len), len); 802 803 parseResult = unum_parse(spellout_def, buffer, len, &pp, &status); 804 if (U_FAILURE(status)) { 805 log_err("Error in parsing using unum_format(spellout_fmt, ...): %s\n", myErrorName(status)); 806 } else if (parseResult != value) { 807 log_err("unum_format result %d != value %d\n", parseResult, value); 808 } 809 } 810 } 811 } 812 else { 813 log_err("Spellout format is unavailable\n"); 814 } 815 816 { /* Test for ticket #7079 */ 817 UNumberFormat* dec_en; 818 UChar groupingSep[] = { 0 }; 819 UChar numPercent[] = { 0x0031, 0x0032, 0x0025, 0 }; /* "12%" */ 820 double parseResult = 0.0; 821 822 status=U_ZERO_ERROR; 823 dec_en = unum_open(UNUM_DECIMAL, NULL, 0, "en_US", NULL, &status); 824 unum_setAttribute(dec_en, UNUM_LENIENT_PARSE, 0); 825 unum_setSymbol(dec_en, UNUM_GROUPING_SEPARATOR_SYMBOL, groupingSep, 0, &status); 826 parseResult = unum_parseDouble(dec_en, numPercent, -1, NULL, &status); 827 /* Without the fix in #7079, the above call will hang */ 828 if ( U_FAILURE(status) || parseResult != 12.0 ) { 829 log_err("unum_parseDouble with empty groupingSep: status %s, parseResult %f not 12.0\n", 830 myErrorName(status), parseResult); 831 } else { 832 log_verbose("unum_parseDouble with empty groupingSep: no hang, OK\n"); 833 } 834 unum_close(dec_en); 835 } 836 837 { /* Test parse & format of big decimals. Use a number with too many digits to fit in a double, 838 to verify that it is taking the pure decimal path. */ 839 UNumberFormat *fmt; 840 const char *bdpattern = "#,##0.#########"; 841 const char *numInitial = "12345678900987654321.1234567896"; 842 const char *numFormatted = "12,345,678,900,987,654,321.12345679"; 843 const char *parseExpected = "12345678900987654321.12345679"; 844 int32_t resultSize = 0; 845 int32_t parsePos = 0; /* Output parameter for Parse operations. */ 846 #define DESTCAPACITY 100 847 UChar dest[DESTCAPACITY]; 848 char desta[DESTCAPACITY]; 849 UFieldPosition fieldPos = {0}; 850 851 /* Format */ 852 853 status = U_ZERO_ERROR; 854 u_uastrcpy(dest, bdpattern); 855 fmt = unum_open(UNUM_PATTERN_DECIMAL, dest, -1, "en", NULL /*parseError*/, &status); 856 if (U_FAILURE(status)) log_err("File %s, Line %d, status = %s\n", __FILE__, __LINE__, u_errorName(status)); 857 858 resultSize = unum_formatDecimal(fmt, numInitial, -1, dest, DESTCAPACITY, NULL, &status); 859 if (U_FAILURE(status)) { 860 log_err("File %s, Line %d, status = %s\n", __FILE__, __LINE__, u_errorName(status)); 861 } 862 u_austrncpy(desta, dest, DESTCAPACITY); 863 if (strcmp(numFormatted, desta) != 0) { 864 log_err("File %s, Line %d, (expected, acutal) = (\"%s\", \"%s\")\n", 865 __FILE__, __LINE__, numFormatted, desta); 866 } 867 if (strlen(numFormatted) != resultSize) { 868 log_err("File %s, Line %d, (expected, actual) = (%d, %d)\n", 869 __FILE__, __LINE__, strlen(numFormatted), resultSize); 870 } 871 872 /* Format with a FieldPosition parameter */ 873 874 fieldPos.field = UNUM_DECIMAL_SEPARATOR_FIELD; 875 resultSize = unum_formatDecimal(fmt, numInitial, -1, dest, DESTCAPACITY, &fieldPos, &status); 876 if (U_FAILURE(status)) { 877 log_err("File %s, Line %d, status = %s\n", __FILE__, __LINE__, u_errorName(status)); 878 } 879 u_austrncpy(desta, dest, DESTCAPACITY); 880 if (strcmp(numFormatted, desta) != 0) { 881 log_err("File %s, Line %d, (expected, acutal) = (\"%s\", \"%s\")\n", 882 __FILE__, __LINE__, numFormatted, desta); 883 } 884 if (fieldPos.beginIndex != 26) { /* index of "." in formatted number */ 885 log_err("File %s, Line %d, (expected, acutal) = (%d, %d)\n", 886 __FILE__, __LINE__, 0, fieldPos.beginIndex); 887 } 888 if (fieldPos.endIndex != 27) { 889 log_err("File %s, Line %d, (expected, acutal) = (%d, %d)\n", 890 __FILE__, __LINE__, 0, fieldPos.endIndex); 891 } 892 893 /* Parse */ 894 895 status = U_ZERO_ERROR; 896 u_uastrcpy(dest, numFormatted); /* Parse the expected output of the formatting test */ 897 resultSize = unum_parseDecimal(fmt, dest, -1, NULL, desta, DESTCAPACITY, &status); 898 if (U_FAILURE(status)) { 899 log_err("File %s, Line %d, status = %s\n", __FILE__, __LINE__, u_errorName(status)); 900 } 901 if (strcmp(parseExpected, desta) != 0) { 902 log_err("File %s, Line %d, (expected, actual) = (\"%s\", \"%s\")\n", 903 __FILE__, __LINE__, parseExpected, desta); 904 } 905 if (strlen(parseExpected) != resultSize) { 906 log_err("File %s, Line %d, (expected, actual) = (%d, %d)\n", 907 __FILE__, __LINE__, strlen(parseExpected), resultSize); 908 } 909 910 /* Parse with a parsePos parameter */ 911 912 status = U_ZERO_ERROR; 913 u_uastrcpy(dest, numFormatted); /* Parse the expected output of the formatting test */ 914 parsePos = 3; /* 12,345,678,900,987,654,321.12345679 */ 915 /* start parsing at the the third char */ 916 resultSize = unum_parseDecimal(fmt, dest, -1, &parsePos, desta, DESTCAPACITY, &status); 917 if (U_FAILURE(status)) { 918 log_err("File %s, Line %d, status = %s\n", __FILE__, __LINE__, u_errorName(status)); 919 } 920 if (strcmp(parseExpected+2, desta) != 0) { /* "345678900987654321.12345679" */ 921 log_err("File %s, Line %d, (expected, actual) = (\"%s\", \"%s\")\n", 922 __FILE__, __LINE__, parseExpected+2, desta); 923 } 924 if (strlen(numFormatted) != parsePos) { 925 log_err("File %s, Line %d, parsePos (expected, actual) = (\"%d\", \"%d\")\n", 926 __FILE__, __LINE__, strlen(parseExpected), parsePos); 927 } 928 929 unum_close(fmt); 930 } 931 932 status = U_ZERO_ERROR; 933 /* Test invalid symbol argument */ 934 { 935 int32_t badsymbolLarge = UNUM_FORMAT_SYMBOL_COUNT + 1; 936 int32_t badsymbolSmall = -1; 937 UChar value[10]; 938 int32_t valueLength = 10; 939 UNumberFormat *fmt = unum_open(UNUM_DEFAULT, NULL, 0, NULL, NULL, &status); 940 if (U_FAILURE(status)) { 941 log_err("File %s, Line %d, status = %s\n", __FILE__, __LINE__, u_errorName(status)); 942 } else { 943 unum_getSymbol(fmt, (UNumberFormatSymbol)badsymbolLarge, NULL, 0, &status); 944 if (U_SUCCESS(status)) log_err("unum_getSymbol()'s status should be ILLEGAL_ARGUMENT with invalid symbol (> UNUM_FORMAT_SYMBOL_COUNT) argument\n"); 945 946 status = U_ZERO_ERROR; 947 unum_getSymbol(fmt, (UNumberFormatSymbol)badsymbolSmall, NULL, 0, &status); 948 if (U_SUCCESS(status)) log_err("unum_getSymbol()'s status should be ILLEGAL_ARGUMENT with invalid symbol (less than 0) argument\n"); 949 950 status = U_ZERO_ERROR; 951 unum_setSymbol(fmt, (UNumberFormatSymbol)badsymbolLarge, value, valueLength, &status); 952 if (U_SUCCESS(status)) log_err("unum_setSymbol()'s status should be ILLEGAL_ARGUMENT with invalid symbol (> UNUM_FORMAT_SYMBOL_COUNT) argument\n"); 953 954 status = U_ZERO_ERROR; 955 unum_setSymbol(fmt, (UNumberFormatSymbol)badsymbolSmall, value, valueLength, &status); 956 if (U_SUCCESS(status)) log_err("unum_setSymbol()'s status should be ILLEGAL_ARGUMENT with invalid symbol (less than 0) argument\n"); 957 958 unum_close(fmt); 959 } 960 } 961 962 963 /*closing the NumberFormat() using unum_close(UNumberFormat*)")*/ 964 unum_close(def); 965 unum_close(fr); 966 unum_close(cur_def); 967 unum_close(cur_fr); 968 unum_close(per_def); 969 unum_close(per_fr); 970 unum_close(spellout_def); 971 unum_close(pattern); 972 unum_close(cur_frpattern); 973 unum_close(myclone); 974 975 } 976 977 static void TestParseZero(void) 978 { 979 UErrorCode errorCode = U_ZERO_ERROR; 980 UChar input[] = {0x30, 0}; /* Input text is decimal '0' */ 981 UChar pat[] = {0x0023,0x003b,0x0023,0}; /* {'#', ';', '#', 0}; */ 982 double dbl; 983 984 #if 0 985 UNumberFormat* unum = unum_open( UNUM_DECIMAL /*or UNUM_DEFAULT*/, NULL, -1, NULL, NULL, &errorCode); 986 #else 987 UNumberFormat* unum = unum_open( UNUM_PATTERN_DECIMAL /*needs pattern*/, pat, -1, NULL, NULL, &errorCode); 988 #endif 989 990 dbl = unum_parseDouble( unum, input, -1 /*u_strlen(input)*/, 0 /* 0 = start */, &errorCode ); 991 if (U_FAILURE(errorCode)) { 992 log_data_err("Result - %s\n", u_errorName(errorCode)); 993 } else { 994 log_verbose("Double: %f\n", dbl); 995 } 996 unum_close(unum); 997 } 998 999 static const UChar dollars2Sym[] = { 0x24,0x32,0x2E,0x30,0x30,0 }; /* $2.00 */ 1000 static const UChar dollars4Sym[] = { 0x24,0x34,0 }; /* $4 */ 1001 static const UChar dollarsUS4Sym[] = { 0x55,0x53,0x24,0x34,0 }; /* US$4 */ 1002 static const UChar dollars9Sym[] = { 0x39,0xA0,0x24,0 }; /* 9 $ */ 1003 static const UChar pounds3Sym[] = { 0xA3,0x33,0x2E,0x30,0x30,0 }; /* [POUND]3.00 */ 1004 static const UChar pounds5Sym[] = { 0xA3,0x35,0 }; /* [POUND]5 */ 1005 static const UChar pounds7Sym[] = { 0x37,0xA0,0xA3,0 }; /* 7 [POUND] */ 1006 static const UChar euros4Sym[] = { 0x34,0x2C,0x30,0x30,0xA0,0x20AC,0 }; /* 4,00 [EURO] */ 1007 static const UChar euros6Sym[] = { 0x36,0xA0,0x20AC,0 }; /* 6 [EURO] */ 1008 static const UChar euros8Sym[] = { 0x20AC,0x38,0 }; /* [EURO]8 */ 1009 static const UChar dollars4PluEn[] = { 0x34,0x20,0x55,0x53,0x20,0x64,0x6F,0x6C,0x6C,0x61,0x72,0x73,0 }; /* 4 US dollars*/ 1010 static const UChar pounds5PluEn[] = { 0x35,0x20,0x42,0x72,0x69,0x74,0x69,0x73,0x68,0x20,0x70,0x6F,0x75,0x6E,0x64,0x73,0x20,0x73,0x74,0x65,0x72,0x6C,0x69,0x6E,0x67,0 }; /* 5 British pounds sterling */ 1011 static const UChar euros8PluEn[] = { 0x38,0x20,0x65,0x75,0x72,0x6F,0x73,0 }; /* 8 euros*/ 1012 static const UChar euros6PluFr[] = { 0x36,0x20,0x65,0x75,0x72,0x6F,0x73,0 }; /* 6 euros*/ 1013 1014 typedef struct { 1015 const char * locale; 1016 const char * descrip; 1017 const UChar * currStr; 1018 const UChar * plurStr; 1019 UErrorCode parsDoubExpectErr; 1020 int32_t parsDoubExpectPos; 1021 double parsDoubExpectVal; 1022 UErrorCode parsCurrExpectErr; 1023 int32_t parsCurrExpectPos; 1024 double parsCurrExpectVal; 1025 const char * parsCurrExpectCurr; 1026 } ParseCurrencyItem; 1027 1028 static const ParseCurrencyItem parseCurrencyItems[] = { 1029 { "en_US", "dollars2", dollars2Sym, NULL, U_ZERO_ERROR, 5, 2.0, U_ZERO_ERROR, 5, 2.0, "USD" }, 1030 { "en_US", "dollars4", dollars4Sym, dollars4PluEn, U_ZERO_ERROR, 2, 4.0, U_ZERO_ERROR, 2, 4.0, "USD" }, 1031 { "en_US", "dollars9", dollars9Sym, NULL, U_PARSE_ERROR, 1, 0.0, U_PARSE_ERROR, 1, 0.0, "" }, 1032 { "en_US", "pounds3", pounds3Sym, NULL, U_PARSE_ERROR, 0, 0.0, U_ZERO_ERROR, 5, 3.0, "GBP" }, 1033 { "en_US", "pounds5", pounds5Sym, pounds5PluEn, U_PARSE_ERROR, 0, 0.0, U_ZERO_ERROR, 2, 5.0, "GBP" }, 1034 { "en_US", "pounds7", pounds7Sym, NULL, U_PARSE_ERROR, 1, 0.0, U_PARSE_ERROR, 1, 0.0, "" }, 1035 { "en_US", "euros8", euros8Sym, euros8PluEn, U_PARSE_ERROR, 0, 0.0, U_ZERO_ERROR, 2, 8.0, "EUR" }, 1036 1037 { "en_GB", "pounds3", pounds3Sym, NULL, U_ZERO_ERROR, 5, 3.0, U_ZERO_ERROR, 5, 3.0, "GBP" }, 1038 { "en_GB", "pounds5", pounds5Sym, pounds5PluEn, U_ZERO_ERROR, 2, 5.0, U_ZERO_ERROR, 2, 5.0, "GBP" }, 1039 { "en_GB", "pounds7", pounds7Sym, NULL, U_PARSE_ERROR, 1, 0.0, U_PARSE_ERROR, 1, 0.0, "" }, 1040 { "en_GB", "euros4", euros4Sym, NULL, U_PARSE_ERROR, 4, 0.0, U_PARSE_ERROR, 4, 0.0, "" }, 1041 { "en_GB", "euros6", euros6Sym, NULL, U_PARSE_ERROR, 1, 0.0, U_PARSE_ERROR, 1, 0.0, "" }, 1042 { "en_GB", "euros8", euros8Sym, euros8PluEn, U_PARSE_ERROR, 0, 0.0, U_ZERO_ERROR, 2, 8.0, "EUR" }, 1043 { "en_GB", "dollars4", dollarsUS4Sym, dollars4PluEn, U_PARSE_ERROR, 0, 0.0, U_ZERO_ERROR, 4, 4.0, "USD" }, 1044 1045 { "fr_FR", "euros4", euros4Sym, NULL, U_ZERO_ERROR, 6, 4.0, U_ZERO_ERROR, 6, 4.0, "EUR" }, 1046 { "fr_FR", "euros6", euros6Sym, euros6PluFr, U_ZERO_ERROR, 3, 6.0, U_ZERO_ERROR, 3, 6.0, "EUR" }, 1047 { "fr_FR", "euros8", euros8Sym, NULL, U_PARSE_ERROR, 0, 0.0, U_PARSE_ERROR, 0, 0.0, "" }, 1048 { "fr_FR", "dollars2", dollars2Sym, NULL, U_PARSE_ERROR, 0, 0.0, U_PARSE_ERROR, 0, 0.0, "" }, 1049 { "fr_FR", "dollars4", dollars4Sym, NULL, U_PARSE_ERROR, 0, 0.0, U_PARSE_ERROR, 0, 0.0, "" }, 1050 1051 { NULL, NULL, NULL, NULL, 0, 0, 0.0, 0, 0, 0.0, NULL } 1052 }; 1053 1054 static void TestParseCurrency() 1055 { 1056 const ParseCurrencyItem * itemPtr; 1057 for (itemPtr = parseCurrencyItems; itemPtr->locale != NULL; ++itemPtr) { 1058 UNumberFormat* unum; 1059 UErrorCode status; 1060 double parseVal; 1061 int32_t parsePos; 1062 UChar parseCurr[4]; 1063 char parseCurrB[4]; 1064 1065 status = U_ZERO_ERROR; 1066 unum = unum_open(UNUM_CURRENCY, NULL, 0, itemPtr->locale, NULL, &status); 1067 if (U_SUCCESS(status)) { 1068 const UChar * currStr = itemPtr->currStr; 1069 int32_t currExpectPos = itemPtr->parsCurrExpectPos; 1070 status = U_ZERO_ERROR; 1071 parsePos = 0; 1072 parseVal = unum_parseDouble(unum, currStr, -1, &parsePos, &status); 1073 if (status != itemPtr->parsDoubExpectErr || parsePos != itemPtr->parsDoubExpectPos || parseVal != itemPtr->parsDoubExpectVal) { 1074 log_err("UNUM_CURRENCY parseDouble %s/%s, expect %s pos %d val %.1f, get %s pos %d val %.1f\n", 1075 itemPtr->locale, itemPtr->descrip, 1076 u_errorName(itemPtr->parsDoubExpectErr), itemPtr->parsDoubExpectPos, itemPtr->parsDoubExpectVal, 1077 u_errorName(status), parsePos, parseVal ); 1078 } 1079 status = U_ZERO_ERROR; 1080 parsePos = 0; 1081 parseCurr[0] = 0; 1082 parseVal = unum_parseDoubleCurrency(unum, currStr, -1, &parsePos, parseCurr, &status); 1083 u_austrncpy(parseCurrB, parseCurr, 4); 1084 if (status != itemPtr->parsCurrExpectErr || parsePos != currExpectPos || parseVal != itemPtr->parsCurrExpectVal || 1085 strncmp(parseCurrB, itemPtr->parsCurrExpectCurr, 4) != 0) { 1086 log_err("UNUM_CURRENCY parseDoubleCurrency %s/%s, expect %s pos %d val %.1f cur %s, get %s pos %d val %.1f cur %s\n", 1087 itemPtr->locale, itemPtr->descrip, 1088 u_errorName(itemPtr->parsCurrExpectErr), currExpectPos, itemPtr->parsCurrExpectVal, itemPtr->parsCurrExpectCurr, 1089 u_errorName(status), parsePos, parseVal, parseCurrB ); 1090 } 1091 unum_close(unum); 1092 } else { 1093 log_data_err("unexpected error in unum_open UNUM_CURRENCY for locale %s: '%s'\n", itemPtr->locale, u_errorName(status)); 1094 } 1095 1096 if (itemPtr->plurStr != NULL) { 1097 status = U_ZERO_ERROR; 1098 unum = unum_open(UNUM_CURRENCY_PLURAL, NULL, 0, itemPtr->locale, NULL, &status); 1099 if (U_SUCCESS(status)) { 1100 status = U_ZERO_ERROR; 1101 parsePos = 0; 1102 parseVal = unum_parseDouble(unum, itemPtr->plurStr, -1, &parsePos, &status); 1103 if (status != itemPtr->parsDoubExpectErr || parseVal != itemPtr->parsDoubExpectVal) { 1104 log_err("UNUM_CURRENCY parseDouble %s/%s, expect %s val %.1f, get %s val %.1f\n", 1105 itemPtr->locale, itemPtr->descrip, 1106 u_errorName(itemPtr->parsDoubExpectErr), itemPtr->parsDoubExpectVal, 1107 u_errorName(status), parseVal ); 1108 } 1109 status = U_ZERO_ERROR; 1110 parsePos = 0; 1111 parseCurr[0] = 0; 1112 parseVal = unum_parseDoubleCurrency(unum, itemPtr->plurStr, -1, &parsePos, parseCurr, &status); 1113 u_austrncpy(parseCurrB, parseCurr, 4); 1114 if (status != itemPtr->parsCurrExpectErr || parseVal != itemPtr->parsCurrExpectVal || 1115 strncmp(parseCurrB, itemPtr->parsCurrExpectCurr, 4) != 0) { 1116 log_err("UNUM_CURRENCY parseDoubleCurrency %s/%s, expect %s val %.1f cur %s, get %s val %.1f cur %s\n", 1117 itemPtr->locale, itemPtr->descrip, 1118 u_errorName(itemPtr->parsCurrExpectErr), itemPtr->parsCurrExpectVal, itemPtr->parsCurrExpectCurr, 1119 u_errorName(status), parseVal, parseCurrB ); 1120 } 1121 unum_close(unum); 1122 } else { 1123 log_data_err("unexpected error in unum_open UNUM_CURRENCY_PLURAL for locale %s: '%s'\n", itemPtr->locale, u_errorName(status)); 1124 } 1125 } 1126 } 1127 } 1128 1129 typedef struct { 1130 const char * testname; 1131 const char * locale; 1132 const UChar * source; 1133 int32_t startPos; 1134 int32_t value; 1135 int32_t endPos; 1136 UErrorCode status; 1137 } SpelloutParseTest; 1138 1139 static const UChar ustr_en0[] = {0x7A, 0x65, 0x72, 0x6F, 0}; /* zero */ 1140 static const UChar ustr_123[] = {0x31, 0x32, 0x33, 0}; /* 123 */ 1141 static const UChar ustr_en123[] = {0x6f, 0x6e, 0x65, 0x20, 0x68, 0x75, 0x6e, 0x64, 0x72, 0x65, 0x64, 1142 0x20, 0x74, 0x77, 0x65, 0x6e, 0x74, 0x79, 1143 0x2d, 0x74, 0x68, 0x72, 0x65, 0x65, 0}; /* one hundred twenty-three */ 1144 static const UChar ustr_fr123[] = {0x63, 0x65, 0x6e, 0x74, 0x20, 0x76, 0x69, 0x6e, 0x67, 0x74, 0x2d, 1145 0x74, 0x72, 0x6f, 0x69, 0x73, 0}; /* cent vingt-trois */ 1146 static const UChar ustr_ja123[] = {0x767e, 0x4e8c, 0x5341, 0x4e09, 0}; /* kanji 100(+)2(*)10(+)3 */ 1147 1148 static const SpelloutParseTest spelloutParseTests[] = { 1149 /* name loc src start val end status */ 1150 { "en0", "en", ustr_en0, 0, 0, 4, U_ZERO_ERROR }, 1151 { "en0", "en", ustr_en0, 2, 0, 2, U_PARSE_ERROR }, 1152 { "en0", "ja", ustr_en0, 0, 0, 0, U_PARSE_ERROR }, 1153 { "123", "en", ustr_123, 0, 123, 3, U_ZERO_ERROR }, 1154 { "en123", "en", ustr_en123, 0, 123, 24, U_ZERO_ERROR }, 1155 { "en123", "en", ustr_en123, 12, 23, 24, U_ZERO_ERROR }, 1156 { "en123", "fr", ustr_en123, 16, 0, 16, U_PARSE_ERROR }, 1157 { "fr123", "fr", ustr_fr123, 0, 123, 16, U_ZERO_ERROR }, 1158 { "fr123", "fr", ustr_fr123, 5, 23, 16, U_ZERO_ERROR }, 1159 { "fr123", "en", ustr_fr123, 0, 0, 0, U_PARSE_ERROR }, 1160 { "ja123", "ja", ustr_ja123, 0, 123, 4, U_ZERO_ERROR }, 1161 { "ja123", "ja", ustr_ja123, 1, 23, 4, U_ZERO_ERROR }, 1162 { "ja123", "fr", ustr_ja123, 0, 0, 0, U_PARSE_ERROR }, 1163 { NULL, NULL, NULL, 0, 0, 0, 0 } /* terminator */ 1164 }; 1165 1166 static void TestSpelloutNumberParse() 1167 { 1168 const SpelloutParseTest * testPtr; 1169 for (testPtr = spelloutParseTests; testPtr->testname != NULL; ++testPtr) { 1170 UErrorCode status = U_ZERO_ERROR; 1171 int32_t value, position = testPtr->startPos; 1172 UNumberFormat *nf = unum_open(UNUM_SPELLOUT, NULL, 0, testPtr->locale, NULL, &status); 1173 if (U_FAILURE(status)) { 1174 log_err_status(status, "unum_open fails for UNUM_SPELLOUT with locale %s, status %s\n", testPtr->locale, myErrorName(status)); 1175 continue; 1176 } 1177 status = U_ZERO_ERROR; 1178 value = unum_parse(nf, testPtr->source, -1, &position, &status); 1179 if ( value != testPtr->value || position != testPtr->endPos || status != testPtr->status ) { 1180 log_err("unum_parse SPELLOUT, locale %s, testname %s, startPos %d: for value / endPos / status, expected %d / %d / %s, got %d / %d / %s\n", 1181 testPtr->locale, testPtr->testname, testPtr->startPos, 1182 testPtr->value, testPtr->endPos, myErrorName(testPtr->status), 1183 value, position, myErrorName(status) ); 1184 } 1185 unum_close(nf); 1186 } 1187 } 1188 1189 static void TestSignificantDigits() 1190 { 1191 UChar temp[128]; 1192 int32_t resultlengthneeded; 1193 int32_t resultlength; 1194 UErrorCode status = U_ZERO_ERROR; 1195 UChar *result = NULL; 1196 UNumberFormat* fmt; 1197 double d = 123456.789; 1198 1199 u_uastrcpy(temp, "###0.0#"); 1200 fmt=unum_open(UNUM_IGNORE, temp, -1, NULL, NULL,&status); 1201 if (U_FAILURE(status)) { 1202 log_data_err("got unexpected error for unum_open: '%s'\n", u_errorName(status)); 1203 return; 1204 } 1205 unum_setAttribute(fmt, UNUM_SIGNIFICANT_DIGITS_USED, TRUE); 1206 unum_setAttribute(fmt, UNUM_MAX_SIGNIFICANT_DIGITS, 6); 1207 1208 u_uastrcpy(temp, "123457"); 1209 resultlength=0; 1210 resultlengthneeded=unum_formatDouble(fmt, d, NULL, resultlength, NULL, &status); 1211 if(status==U_BUFFER_OVERFLOW_ERROR) 1212 { 1213 status=U_ZERO_ERROR; 1214 resultlength=resultlengthneeded+1; 1215 result=(UChar*)malloc(sizeof(UChar) * resultlength); 1216 unum_formatDouble(fmt, d, result, resultlength, NULL, &status); 1217 } 1218 if(U_FAILURE(status)) 1219 { 1220 log_err("Error in formatting using unum_formatDouble(.....): %s\n", myErrorName(status)); 1221 return; 1222 } 1223 if(u_strcmp(result, temp)==0) 1224 log_verbose("Pass: Number Formatting using unum_formatDouble() Successful\n"); 1225 else 1226 log_err("FAIL: Error in number formatting using unum_formatDouble()\n"); 1227 free(result); 1228 unum_close(fmt); 1229 } 1230 1231 static void TestSigDigRounding() 1232 { 1233 UErrorCode status = U_ZERO_ERROR; 1234 UChar expected[128]; 1235 UChar result[128]; 1236 char temp1[128]; 1237 char temp2[128]; 1238 UNumberFormat* fmt; 1239 double d = 123.4; 1240 1241 fmt=unum_open(UNUM_DECIMAL, NULL, 0, NULL /* "en_US"*/, NULL, &status); 1242 if (U_FAILURE(status)) { 1243 log_data_err("got unexpected error for unum_open: '%s'\n", u_errorName(status)); 1244 return; 1245 } 1246 unum_setAttribute(fmt, UNUM_LENIENT_PARSE, FALSE); 1247 unum_setAttribute(fmt, UNUM_SIGNIFICANT_DIGITS_USED, TRUE); 1248 unum_setAttribute(fmt, UNUM_MAX_SIGNIFICANT_DIGITS, 2); 1249 /* unum_setAttribute(fmt, UNUM_MAX_FRACTION_DIGITS, 0); */ 1250 1251 unum_setAttribute(fmt, UNUM_ROUNDING_MODE, UNUM_ROUND_UP); 1252 unum_setDoubleAttribute(fmt, UNUM_ROUNDING_INCREMENT, 20.0); 1253 1254 (void)unum_formatDouble(fmt, d, result, UPRV_LENGTHOF(result), NULL, &status); 1255 if(U_FAILURE(status)) 1256 { 1257 log_err("Error in formatting using unum_formatDouble(.....): %s\n", myErrorName(status)); 1258 return; 1259 } 1260 1261 u_uastrcpy(expected, "140"); 1262 if(u_strcmp(result, expected)!=0) 1263 log_err("FAIL: Error in unum_formatDouble result %s instead of %s\n", u_austrcpy(temp1, result), u_austrcpy(temp2, expected) ); 1264 1265 unum_close(fmt); 1266 } 1267 1268 static void TestNumberFormatPadding() 1269 { 1270 UChar *result=NULL; 1271 UChar temp1[512]; 1272 1273 UErrorCode status=U_ZERO_ERROR; 1274 int32_t resultlength; 1275 int32_t resultlengthneeded; 1276 UNumberFormat *pattern; 1277 double d1; 1278 double d = -10456.37; 1279 UFieldPosition pos1; 1280 int32_t parsepos; 1281 1282 /* create a number format using unum_openPattern(....)*/ 1283 log_verbose("\nTesting unum_openPattern() with padding\n"); 1284 u_uastrcpy(temp1, "*#,##0.0#*;(#,##0.0#)"); 1285 status=U_ZERO_ERROR; 1286 pattern=unum_open(UNUM_IGNORE,temp1, u_strlen(temp1), NULL, NULL,&status); 1287 if(U_SUCCESS(status)) 1288 { 1289 log_err("error in unum_openPattern(%s): %s\n", temp1, myErrorName(status) ); 1290 } 1291 else 1292 { 1293 unum_close(pattern); 1294 } 1295 1296 /* u_uastrcpy(temp1, "*x#,###,###,##0.0#;(*x#,###,###,##0.0#)"); */ 1297 u_uastrcpy(temp1, "*x#,###,###,##0.0#;*x(###,###,##0.0#)"); 1298 status=U_ZERO_ERROR; 1299 pattern=unum_open(UNUM_IGNORE,temp1, u_strlen(temp1), "en_US",NULL, &status); 1300 if(U_FAILURE(status)) 1301 { 1302 log_err_status(status, "error in padding unum_openPattern(%s): %s\n", temp1, myErrorName(status) );; 1303 } 1304 else { 1305 log_verbose("Pass: padding unum_openPattern() works fine\n"); 1306 1307 /*test for unum_toPattern()*/ 1308 log_verbose("\nTesting padding unum_toPattern()\n"); 1309 resultlength=0; 1310 resultlengthneeded=unum_toPattern(pattern, FALSE, NULL, resultlength, &status); 1311 if(status==U_BUFFER_OVERFLOW_ERROR) 1312 { 1313 status=U_ZERO_ERROR; 1314 resultlength=resultlengthneeded+1; 1315 result=(UChar*)malloc(sizeof(UChar) * resultlength); 1316 unum_toPattern(pattern, FALSE, result, resultlength, &status); 1317 } 1318 if(U_FAILURE(status)) 1319 { 1320 log_err("error in extracting the padding pattern from UNumberFormat: %s\n", myErrorName(status)); 1321 } 1322 else 1323 { 1324 if(u_strcmp(result, temp1)!=0) 1325 log_err("FAIL: Error in extracting the padding pattern using unum_toPattern()\n"); 1326 else 1327 log_verbose("Pass: extracted the padding pattern correctly using unum_toPattern()\n"); 1328 free(result); 1329 } 1330 /* u_uastrcpy(temp1, "(xxxxxxx10,456.37)"); */ 1331 u_uastrcpy(temp1, "xxxxx(10,456.37)"); 1332 resultlength=0; 1333 pos1.field = UNUM_FRACTION_FIELD; 1334 resultlengthneeded=unum_formatDouble(pattern, d, NULL, resultlength, &pos1, &status); 1335 if(status==U_BUFFER_OVERFLOW_ERROR) 1336 { 1337 status=U_ZERO_ERROR; 1338 resultlength=resultlengthneeded+1; 1339 result=(UChar*)malloc(sizeof(UChar) * resultlength); 1340 unum_formatDouble(pattern, d, result, resultlength, NULL, &status); 1341 } 1342 if(U_FAILURE(status)) 1343 { 1344 log_err("Error in formatting using unum_formatDouble(.....) with padding : %s\n", myErrorName(status)); 1345 } 1346 else 1347 { 1348 if(u_strcmp(result, temp1)==0) 1349 log_verbose("Pass: Number Formatting using unum_formatDouble() padding Successful\n"); 1350 else 1351 log_data_err("FAIL: Error in number formatting using unum_formatDouble() with padding\n"); 1352 if(pos1.beginIndex == 13 && pos1.endIndex == 15) 1353 log_verbose("Pass: Complete number formatting using unum_formatDouble() successful\n"); 1354 else 1355 log_err("Fail: Error in complete number Formatting using unum_formatDouble()\nGot: b=%d end=%d\nExpected: b=13 end=15\n", 1356 pos1.beginIndex, pos1.endIndex); 1357 1358 1359 /* Testing unum_parse() and unum_parseDouble() */ 1360 log_verbose("\nTesting padding unum_parseDouble()\n"); 1361 parsepos=0; 1362 d1=unum_parseDouble(pattern, result, u_strlen(result), &parsepos, &status); 1363 if(U_FAILURE(status)) 1364 { 1365 log_err("padding parse failed. The error is : %s\n", myErrorName(status)); 1366 } 1367 1368 if(d1!=d) 1369 log_err("Fail: Error in padding parsing\n"); 1370 else 1371 log_verbose("Pass: padding parsing successful\n"); 1372 free(result); 1373 } 1374 } 1375 1376 unum_close(pattern); 1377 } 1378 1379 static UBool 1380 withinErr(double a, double b, double err) { 1381 return uprv_fabs(a - b) < uprv_fabs(a * err); 1382 } 1383 1384 static void TestInt64Format() { 1385 UChar temp1[512]; 1386 UChar result[512]; 1387 UNumberFormat *fmt; 1388 UErrorCode status = U_ZERO_ERROR; 1389 const double doubleInt64Max = (double)U_INT64_MAX; 1390 const double doubleInt64Min = (double)U_INT64_MIN; 1391 const double doubleBig = 10.0 * (double)U_INT64_MAX; 1392 int32_t val32; 1393 int64_t val64; 1394 double valDouble; 1395 int32_t parsepos; 1396 1397 /* create a number format using unum_openPattern(....) */ 1398 log_verbose("\nTesting Int64Format\n"); 1399 u_uastrcpy(temp1, "#.#E0"); 1400 fmt = unum_open(UNUM_IGNORE, temp1, u_strlen(temp1), "en_US", NULL, &status); 1401 if(U_FAILURE(status)) { 1402 log_data_err("error in unum_openPattern() - %s\n", myErrorName(status)); 1403 } else { 1404 unum_setAttribute(fmt, UNUM_MAX_FRACTION_DIGITS, 20); 1405 unum_formatInt64(fmt, U_INT64_MAX, result, 512, NULL, &status); 1406 if (U_FAILURE(status)) { 1407 log_err("error in unum_format(): %s\n", myErrorName(status)); 1408 } else { 1409 log_verbose("format int64max: '%s'\n", result); 1410 parsepos = 0; 1411 val32 = unum_parse(fmt, result, u_strlen(result), &parsepos, &status); 1412 if (status != U_INVALID_FORMAT_ERROR) { 1413 log_err("parse didn't report error: %s\n", myErrorName(status)); 1414 } else if (val32 != INT32_MAX) { 1415 log_err("parse didn't pin return value, got: %d\n", val32); 1416 } 1417 1418 status = U_ZERO_ERROR; 1419 parsepos = 0; 1420 val64 = unum_parseInt64(fmt, result, u_strlen(result), &parsepos, &status); 1421 if (U_FAILURE(status)) { 1422 log_err("parseInt64 returned error: %s\n", myErrorName(status)); 1423 } else if (val64 != U_INT64_MAX) { 1424 log_err("parseInt64 returned incorrect value, got: %ld\n", val64); 1425 } 1426 1427 status = U_ZERO_ERROR; 1428 parsepos = 0; 1429 valDouble = unum_parseDouble(fmt, result, u_strlen(result), &parsepos, &status); 1430 if (U_FAILURE(status)) { 1431 log_err("parseDouble returned error: %s\n", myErrorName(status)); 1432 } else if (valDouble != doubleInt64Max) { 1433 log_err("parseDouble returned incorrect value, got: %g\n", valDouble); 1434 } 1435 } 1436 1437 unum_formatInt64(fmt, U_INT64_MIN, result, 512, NULL, &status); 1438 if (U_FAILURE(status)) { 1439 log_err("error in unum_format(): %s\n", myErrorName(status)); 1440 } else { 1441 log_verbose("format int64min: '%s'\n", result); 1442 parsepos = 0; 1443 val32 = unum_parse(fmt, result, u_strlen(result), &parsepos, &status); 1444 if (status != U_INVALID_FORMAT_ERROR) { 1445 log_err("parse didn't report error: %s\n", myErrorName(status)); 1446 } else if (val32 != INT32_MIN) { 1447 log_err("parse didn't pin return value, got: %d\n", val32); 1448 } 1449 1450 status = U_ZERO_ERROR; 1451 parsepos = 0; 1452 val64 = unum_parseInt64(fmt, result, u_strlen(result), &parsepos, &status); 1453 if (U_FAILURE(status)) { 1454 log_err("parseInt64 returned error: %s\n", myErrorName(status)); 1455 } else if (val64 != U_INT64_MIN) { 1456 log_err("parseInt64 returned incorrect value, got: %ld\n", val64); 1457 } 1458 1459 status = U_ZERO_ERROR; 1460 parsepos = 0; 1461 valDouble = unum_parseDouble(fmt, result, u_strlen(result), &parsepos, &status); 1462 if (U_FAILURE(status)) { 1463 log_err("parseDouble returned error: %s\n", myErrorName(status)); 1464 } else if (valDouble != doubleInt64Min) { 1465 log_err("parseDouble returned incorrect value, got: %g\n", valDouble); 1466 } 1467 } 1468 1469 unum_formatDouble(fmt, doubleBig, result, 512, NULL, &status); 1470 if (U_FAILURE(status)) { 1471 log_err("error in unum_format(): %s\n", myErrorName(status)); 1472 } else { 1473 log_verbose("format doubleBig: '%s'\n", result); 1474 parsepos = 0; 1475 val32 = unum_parse(fmt, result, u_strlen(result), &parsepos, &status); 1476 if (status != U_INVALID_FORMAT_ERROR) { 1477 log_err("parse didn't report error: %s\n", myErrorName(status)); 1478 } else if (val32 != INT32_MAX) { 1479 log_err("parse didn't pin return value, got: %d\n", val32); 1480 } 1481 1482 status = U_ZERO_ERROR; 1483 parsepos = 0; 1484 val64 = unum_parseInt64(fmt, result, u_strlen(result), &parsepos, &status); 1485 if (status != U_INVALID_FORMAT_ERROR) { 1486 log_err("parseInt64 didn't report error error: %s\n", myErrorName(status)); 1487 } else if (val64 != U_INT64_MAX) { 1488 log_err("parseInt64 returned incorrect value, got: %ld\n", val64); 1489 } 1490 1491 status = U_ZERO_ERROR; 1492 parsepos = 0; 1493 valDouble = unum_parseDouble(fmt, result, u_strlen(result), &parsepos, &status); 1494 if (U_FAILURE(status)) { 1495 log_err("parseDouble returned error: %s\n", myErrorName(status)); 1496 } else if (!withinErr(valDouble, doubleBig, 1e-15)) { 1497 log_err("parseDouble returned incorrect value, got: %g\n", valDouble); 1498 } 1499 } 1500 1501 u_uastrcpy(result, "5.06e-27"); 1502 parsepos = 0; 1503 valDouble = unum_parseDouble(fmt, result, u_strlen(result), &parsepos, &status); 1504 if (U_FAILURE(status)) { 1505 log_err("parseDouble() returned error: %s\n", myErrorName(status)); 1506 } else if (!withinErr(valDouble, 5.06e-27, 1e-15)) { 1507 log_err("parseDouble() returned incorrect value, got: %g\n", valDouble); 1508 } 1509 } 1510 unum_close(fmt); 1511 } 1512 1513 1514 static void test_fmt(UNumberFormat* fmt, UBool isDecimal) { 1515 char temp[512]; 1516 UChar buffer[512]; 1517 int32_t BUFSIZE = UPRV_LENGTHOF(buffer); 1518 double vals[] = { 1519 -.2, 0, .2, 5.5, 15.2, 250, 123456789 1520 }; 1521 int i; 1522 1523 for (i = 0; i < UPRV_LENGTHOF(vals); ++i) { 1524 UErrorCode status = U_ZERO_ERROR; 1525 unum_formatDouble(fmt, vals[i], buffer, BUFSIZE, NULL, &status); 1526 if (U_FAILURE(status)) { 1527 log_err("failed to format: %g, returned %s\n", vals[i], u_errorName(status)); 1528 } else { 1529 u_austrcpy(temp, buffer); 1530 log_verbose("formatting %g returned '%s'\n", vals[i], temp); 1531 } 1532 } 1533 1534 /* check APIs now */ 1535 { 1536 UErrorCode status = U_ZERO_ERROR; 1537 UParseError perr; 1538 u_uastrcpy(buffer, "#,##0.0#"); 1539 unum_applyPattern(fmt, FALSE, buffer, -1, &perr, &status); 1540 if (isDecimal ? U_FAILURE(status) : (status != U_UNSUPPORTED_ERROR)) { 1541 log_err("got unexpected error for applyPattern: '%s'\n", u_errorName(status)); 1542 } 1543 } 1544 1545 { 1546 int isLenient = unum_getAttribute(fmt, UNUM_LENIENT_PARSE); 1547 log_verbose("lenient: 0x%x\n", isLenient); 1548 if (isLenient != FALSE) { 1549 log_err("didn't expect lenient value: %d\n", isLenient); 1550 } 1551 1552 unum_setAttribute(fmt, UNUM_LENIENT_PARSE, TRUE); 1553 isLenient = unum_getAttribute(fmt, UNUM_LENIENT_PARSE); 1554 if (isLenient != TRUE) { 1555 log_err("didn't expect lenient value after set: %d\n", isLenient); 1556 } 1557 } 1558 1559 { 1560 double val2; 1561 double val = unum_getDoubleAttribute(fmt, UNUM_LENIENT_PARSE); 1562 if (val != -1) { 1563 log_err("didn't expect double attribute\n"); 1564 } 1565 val = unum_getDoubleAttribute(fmt, UNUM_ROUNDING_INCREMENT); 1566 if ((val == -1) == isDecimal) { 1567 log_err("didn't expect -1 rounding increment\n"); 1568 } 1569 unum_setDoubleAttribute(fmt, UNUM_ROUNDING_INCREMENT, val+.5); 1570 val2 = unum_getDoubleAttribute(fmt, UNUM_ROUNDING_INCREMENT); 1571 if (isDecimal && (val2 - val != .5)) { 1572 log_err("set rounding increment had no effect on decimal format"); 1573 } 1574 } 1575 1576 { 1577 UErrorCode status = U_ZERO_ERROR; 1578 int len = unum_getTextAttribute(fmt, UNUM_DEFAULT_RULESET, buffer, BUFSIZE, &status); 1579 if (isDecimal ? (status != U_UNSUPPORTED_ERROR) : U_FAILURE(status)) { 1580 log_err("got unexpected error for get default ruleset: '%s'\n", u_errorName(status)); 1581 } 1582 if (U_SUCCESS(status)) { 1583 u_austrcpy(temp, buffer); 1584 log_verbose("default ruleset: '%s'\n", temp); 1585 } 1586 1587 status = U_ZERO_ERROR; 1588 len = unum_getTextAttribute(fmt, UNUM_PUBLIC_RULESETS, buffer, BUFSIZE, &status); 1589 if (isDecimal ? (status != U_UNSUPPORTED_ERROR) : U_FAILURE(status)) { 1590 log_err("got unexpected error for get public rulesets: '%s'\n", u_errorName(status)); 1591 } 1592 if (U_SUCCESS(status)) { 1593 u_austrcpy(temp, buffer); 1594 log_verbose("public rulesets: '%s'\n", temp); 1595 1596 /* set the default ruleset to the first one found, and retry */ 1597 1598 if (len > 0) { 1599 for (i = 0; i < len && temp[i] != ';'; ++i){}; 1600 if (i < len) { 1601 buffer[i] = 0; 1602 unum_setTextAttribute(fmt, UNUM_DEFAULT_RULESET, buffer, -1, &status); 1603 if (U_FAILURE(status)) { 1604 log_err("unexpected error setting default ruleset: '%s'\n", u_errorName(status)); 1605 } else { 1606 int len2 = unum_getTextAttribute(fmt, UNUM_DEFAULT_RULESET, buffer, BUFSIZE, &status); 1607 if (U_FAILURE(status)) { 1608 log_err("could not fetch default ruleset: '%s'\n", u_errorName(status)); 1609 } else if (len2 != i) { 1610 u_austrcpy(temp, buffer); 1611 log_err("unexpected ruleset len: %d ex: %d val: %s\n", len2, i, temp); 1612 } else { 1613 for (i = 0; i < UPRV_LENGTHOF(vals); ++i) { 1614 status = U_ZERO_ERROR; 1615 unum_formatDouble(fmt, vals[i], buffer, BUFSIZE, NULL, &status); 1616 if (U_FAILURE(status)) { 1617 log_err("failed to format: %g, returned %s\n", vals[i], u_errorName(status)); 1618 } else { 1619 u_austrcpy(temp, buffer); 1620 log_verbose("formatting %g returned '%s'\n", vals[i], temp); 1621 } 1622 } 1623 } 1624 } 1625 } 1626 } 1627 } 1628 } 1629 1630 { 1631 UErrorCode status = U_ZERO_ERROR; 1632 unum_toPattern(fmt, FALSE, buffer, BUFSIZE, &status); 1633 if (U_SUCCESS(status)) { 1634 u_austrcpy(temp, buffer); 1635 log_verbose("pattern: '%s'\n", temp); 1636 } else if (status != U_BUFFER_OVERFLOW_ERROR) { 1637 log_err("toPattern failed unexpectedly: %s\n", u_errorName(status)); 1638 } else { 1639 log_verbose("pattern too long to display\n"); 1640 } 1641 } 1642 1643 { 1644 UErrorCode status = U_ZERO_ERROR; 1645 int len = unum_getSymbol(fmt, UNUM_CURRENCY_SYMBOL, buffer, BUFSIZE, &status); 1646 if (isDecimal ? U_FAILURE(status) : (status != U_UNSUPPORTED_ERROR)) { 1647 log_err("unexpected error getting symbol: '%s'\n", u_errorName(status)); 1648 } 1649 1650 unum_setSymbol(fmt, UNUM_CURRENCY_SYMBOL, buffer, len, &status); 1651 if (isDecimal ? U_FAILURE(status) : (status != U_UNSUPPORTED_ERROR)) { 1652 log_err("unexpected error setting symbol: '%s'\n", u_errorName(status)); 1653 } 1654 } 1655 } 1656 1657 static void TestNonExistentCurrency() { 1658 UNumberFormat *format; 1659 UErrorCode status = U_ZERO_ERROR; 1660 UChar currencySymbol[8]; 1661 static const UChar QQQ[] = {0x51, 0x51, 0x51, 0}; 1662 1663 /* Get a non-existent currency and make sure it returns the correct currency code. */ 1664 format = unum_open(UNUM_CURRENCY, NULL, 0, "th_TH@currency=QQQ", NULL, &status); 1665 if (format == NULL || U_FAILURE(status)) { 1666 log_data_err("unum_open did not return expected result for non-existent requested currency: '%s' (Are you missing data?)\n", u_errorName(status)); 1667 } 1668 else { 1669 unum_getSymbol(format, 1670 UNUM_CURRENCY_SYMBOL, 1671 currencySymbol, 1672 UPRV_LENGTHOF(currencySymbol), 1673 &status); 1674 if (u_strcmp(currencySymbol, QQQ) != 0) { 1675 log_err("unum_open set the currency to QQQ\n"); 1676 } 1677 } 1678 unum_close(format); 1679 } 1680 1681 static void TestRBNFFormat() { 1682 UErrorCode status; 1683 UParseError perr; 1684 UChar pat[1024]; 1685 UChar tempUChars[512]; 1686 UNumberFormat *formats[5]; 1687 int COUNT = UPRV_LENGTHOF(formats); 1688 int i; 1689 1690 for (i = 0; i < COUNT; ++i) { 1691 formats[i] = 0; 1692 } 1693 1694 /* instantiation */ 1695 status = U_ZERO_ERROR; 1696 u_uastrcpy(pat, "#,##0.0#;(#,##0.0#)"); 1697 formats[0] = unum_open(UNUM_PATTERN_DECIMAL, pat, -1, "en_US", &perr, &status); 1698 if (U_FAILURE(status)) { 1699 log_err_status(status, "unable to open decimal pattern -> %s\n", u_errorName(status)); 1700 return; 1701 } 1702 1703 status = U_ZERO_ERROR; 1704 formats[1] = unum_open(UNUM_SPELLOUT, NULL, 0, "en_US", &perr, &status); 1705 if (U_FAILURE(status)) { 1706 log_err_status(status, "unable to open spellout -> %s\n", u_errorName(status)); 1707 return; 1708 } 1709 1710 status = U_ZERO_ERROR; 1711 formats[2] = unum_open(UNUM_ORDINAL, NULL, 0, "en_US", &perr, &status); 1712 if (U_FAILURE(status)) { 1713 log_err_status(status, "unable to open ordinal -> %s\n", u_errorName(status)); 1714 return; 1715 } 1716 1717 status = U_ZERO_ERROR; 1718 formats[3] = unum_open(UNUM_DURATION, NULL, 0, "en_US", &perr, &status); 1719 if (U_FAILURE(status)) { 1720 log_err_status(status, "unable to open duration %s\n", u_errorName(status)); 1721 return; 1722 } 1723 1724 status = U_ZERO_ERROR; 1725 u_uastrcpy(pat, 1726 "%standard:\n" 1727 "-x: minus >>;\n" 1728 "x.x: << point >>;\n" 1729 "zero; one; two; three; four; five; six; seven; eight; nine;\n" 1730 "ten; eleven; twelve; thirteen; fourteen; fifteen; sixteen;\n" 1731 "seventeen; eighteen; nineteen;\n" 1732 "20: twenty[->>];\n" 1733 "30: thirty[->>];\n" 1734 "40: forty[->>];\n" 1735 "50: fifty[->>];\n" 1736 "60: sixty[->>];\n" 1737 "70: seventy[->>];\n" 1738 "80: eighty[->>];\n" 1739 "90: ninety[->>];\n" 1740 "100: =#,##0=;\n"); 1741 u_uastrcpy(tempUChars, 1742 "%simple:\n" 1743 "=%standard=;\n" 1744 "20: twenty[ and change];\n" 1745 "30: thirty[ and change];\n" 1746 "40: forty[ and change];\n" 1747 "50: fifty[ and change];\n" 1748 "60: sixty[ and change];\n" 1749 "70: seventy[ and change];\n" 1750 "80: eighty[ and change];\n" 1751 "90: ninety[ and change];\n" 1752 "100: =#,##0=;\n" 1753 "%bogus:\n" 1754 "0.x: tiny;\n" 1755 "x.x: << point something;\n" 1756 "=%standard=;\n" 1757 "20: some reasonable number;\n" 1758 "100: some substantial number;\n" 1759 "100,000,000: some huge number;\n"); 1760 /* This is to get around some compiler warnings about char * string length. */ 1761 u_strcat(pat, tempUChars); 1762 formats[4] = unum_open(UNUM_PATTERN_RULEBASED, pat, -1, "en_US", &perr, &status); 1763 if (U_FAILURE(status)) { 1764 log_err_status(status, "unable to open rulebased pattern -> %s\n", u_errorName(status)); 1765 } 1766 if (U_FAILURE(status)) { 1767 log_err_status(status, "Something failed with %s\n", u_errorName(status)); 1768 return; 1769 } 1770 1771 for (i = 0; i < COUNT; ++i) { 1772 log_verbose("\n\ntesting format %d\n", i); 1773 test_fmt(formats[i], (UBool)(i == 0)); 1774 } 1775 1776 #define FORMAT_BUF_CAPACITY 64 1777 { 1778 UChar fmtbuf[FORMAT_BUF_CAPACITY]; 1779 int32_t len; 1780 double nanvalue = uprv_getNaN(); 1781 status = U_ZERO_ERROR; 1782 len = unum_formatDouble(formats[1], nanvalue, fmtbuf, FORMAT_BUF_CAPACITY, NULL, &status); 1783 if (U_FAILURE(status)) { 1784 log_err_status(status, "unum_formatDouble NAN failed with %s\n", u_errorName(status)); 1785 } else { 1786 UChar nansym[] = { 0x4E, 0x61, 0x4E, 0 }; /* NaN */ 1787 if ( len != 3 || u_strcmp(fmtbuf, nansym) != 0 ) { 1788 log_err("unum_formatDouble NAN produced wrong answer for en_US\n"); 1789 } 1790 } 1791 } 1792 1793 for (i = 0; i < COUNT; ++i) { 1794 unum_close(formats[i]); 1795 } 1796 } 1797 1798 static void TestRBNFRounding() { 1799 UChar fmtbuf[FORMAT_BUF_CAPACITY]; 1800 UChar expectedBuf[FORMAT_BUF_CAPACITY]; 1801 int32_t len; 1802 UErrorCode status = U_ZERO_ERROR; 1803 UNumberFormat* fmt = unum_open(UNUM_SPELLOUT, NULL, 0, "en_US", NULL, &status); 1804 if (U_FAILURE(status)) { 1805 log_err_status(status, "unable to open spellout -> %s\n", u_errorName(status)); 1806 return; 1807 } 1808 len = unum_formatDouble(fmt, 10.123456789, fmtbuf, FORMAT_BUF_CAPACITY, NULL, &status); 1809 if (U_FAILURE(status)) { 1810 log_err_status(status, "unum_formatDouble 10.123456789 failed with %s\n", u_errorName(status)); 1811 } 1812 u_uastrcpy(expectedBuf, "ten point one two three four five six seven eight nine"); 1813 if (u_strcmp(expectedBuf, fmtbuf) != 0) { 1814 log_err("Wrong result for unrounded value\n"); 1815 } 1816 unum_setAttribute(fmt, UNUM_MAX_FRACTION_DIGITS, 3); 1817 if (unum_getAttribute(fmt, UNUM_MAX_FRACTION_DIGITS) != 3) { 1818 log_err("UNUM_MAX_FRACTION_DIGITS was incorrectly ignored -> %d\n", unum_getAttribute(fmt, UNUM_MAX_FRACTION_DIGITS)); 1819 } 1820 if (unum_getAttribute(fmt, UNUM_ROUNDING_MODE) != UNUM_ROUND_UNNECESSARY) { 1821 log_err("UNUM_ROUNDING_MODE was set -> %d\n", unum_getAttribute(fmt, UNUM_ROUNDING_MODE)); 1822 } 1823 unum_setAttribute(fmt, UNUM_ROUNDING_MODE, UNUM_ROUND_HALFUP); 1824 if (unum_getAttribute(fmt, UNUM_ROUNDING_MODE) != UNUM_ROUND_HALFUP) { 1825 log_err("UNUM_ROUNDING_MODE was not set -> %d\n", unum_getAttribute(fmt, UNUM_ROUNDING_MODE)); 1826 } 1827 len = unum_formatDouble(fmt, 10.123456789, fmtbuf, FORMAT_BUF_CAPACITY, NULL, &status); 1828 if (U_FAILURE(status)) { 1829 log_err_status(status, "unum_formatDouble 10.123456789 failed with %s\n", u_errorName(status)); 1830 } 1831 u_uastrcpy(expectedBuf, "ten point one two three"); 1832 if (u_strcmp(expectedBuf, fmtbuf) != 0) { 1833 char temp[512]; 1834 u_austrcpy(temp, fmtbuf); 1835 log_err("Wrong result for rounded value. Got: %s\n", temp); 1836 } 1837 unum_close(fmt); 1838 } 1839 1840 static void TestCurrencyRegression(void) { 1841 /* 1842 I've found a case where unum_parseDoubleCurrency is not doing what I 1843 expect. The value I pass in is $1234567890q123460000.00 and this 1844 returns with a status of zero error & a parse pos of 22 (I would 1845 expect a parse error at position 11). 1846 1847 I stepped into DecimalFormat::subparse() and it looks like it parses 1848 the first 10 digits and then stops parsing at the q but doesn't set an 1849 error. Then later in DecimalFormat::parse() the value gets crammed 1850 into a long (which greatly truncates the value). 1851 1852 This is very problematic for me 'cause I try to remove chars that are 1853 invalid but this allows my users to enter bad chars and truncates 1854 their data! 1855 */ 1856 1857 UChar buf[1024]; 1858 UChar currency[8]; 1859 char acurrency[16]; 1860 double d; 1861 UNumberFormat *cur; 1862 int32_t pos; 1863 UErrorCode status = U_ZERO_ERROR; 1864 const int32_t expected = 11; 1865 1866 currency[0]=0; 1867 u_uastrcpy(buf, "$1234567890q643210000.00"); 1868 cur = unum_open(UNUM_CURRENCY, NULL,0,"en_US", NULL, &status); 1869 1870 if(U_FAILURE(status)) { 1871 log_data_err("unum_open failed: %s (Are you missing data?)\n", u_errorName(status)); 1872 return; 1873 } 1874 1875 status = U_ZERO_ERROR; /* so we can test it later. */ 1876 pos = 0; 1877 1878 d = unum_parseDoubleCurrency(cur, 1879 buf, 1880 -1, 1881 &pos, /* 0 = start */ 1882 currency, 1883 &status); 1884 1885 u_austrcpy(acurrency, currency); 1886 1887 if(U_FAILURE(status) || (pos != expected)) { 1888 log_err("unum_parseDoubleCurrency should have failed with pos %d, but gave: value %.9f, err %s, pos=%d, currency [%s]\n", 1889 expected, d, u_errorName(status), pos, acurrency); 1890 } else { 1891 log_verbose("unum_parseDoubleCurrency failed, value %.9f err %s, pos %d, currency [%s]\n", d, u_errorName(status), pos, acurrency); 1892 } 1893 1894 unum_close(cur); 1895 } 1896 1897 static void TestTextAttributeCrash(void) { 1898 UChar ubuffer[64] = {0x0049,0x004E,0x0052,0}; 1899 static const UChar expectedNeg[] = {0x0049,0x004E,0x0052,0x0031,0x0032,0x0033,0x0034,0x002E,0x0035,0}; 1900 static const UChar expectedPos[] = {0x0031,0x0032,0x0033,0x0034,0x002E,0x0035,0}; 1901 int32_t used; 1902 UErrorCode status = U_ZERO_ERROR; 1903 UNumberFormat *nf = unum_open(UNUM_CURRENCY, NULL, 0, "en_US", NULL, &status); 1904 if (U_FAILURE(status)) { 1905 log_data_err("FAILED 1 -> %s (Are you missing data?)\n", u_errorName(status)); 1906 return; 1907 } 1908 unum_setTextAttribute(nf, UNUM_CURRENCY_CODE, ubuffer, 3, &status); 1909 /* 1910 * the usual negative prefix and suffix seem to be '($' and ')' at this point 1911 * also crashes if UNUM_NEGATIVE_SUFFIX is substituted for UNUM_NEGATIVE_PREFIX here 1912 */ 1913 used = unum_getTextAttribute(nf, UNUM_NEGATIVE_PREFIX, ubuffer, 64, &status); 1914 unum_setTextAttribute(nf, UNUM_NEGATIVE_PREFIX, ubuffer, used, &status); 1915 if (U_FAILURE(status)) { 1916 log_err("FAILED 2\n"); exit(1); 1917 } 1918 log_verbose("attempting to format...\n"); 1919 used = unum_formatDouble(nf, -1234.5, ubuffer, 64, NULL, &status); 1920 if (U_FAILURE(status) || 64 < used) { 1921 log_err("Failed formatting %s\n", u_errorName(status)); 1922 return; 1923 } 1924 if (u_strcmp(expectedNeg, ubuffer) == 0) { 1925 log_err("Didn't get expected negative result\n"); 1926 } 1927 used = unum_formatDouble(nf, 1234.5, ubuffer, 64, NULL, &status); 1928 if (U_FAILURE(status) || 64 < used) { 1929 log_err("Failed formatting %s\n", u_errorName(status)); 1930 return; 1931 } 1932 if (u_strcmp(expectedPos, ubuffer) == 0) { 1933 log_err("Didn't get expected positive result\n"); 1934 } 1935 unum_close(nf); 1936 } 1937 1938 static void TestNBSPPatternRtNum(const char *testcase, int line, UNumberFormat *nf, double myNumber) { 1939 UErrorCode status = U_ZERO_ERROR; 1940 UChar myString[20]; 1941 char tmpbuf[200]; 1942 double aNumber = -1.0; 1943 unum_formatDouble(nf, myNumber, myString, 20, NULL, &status); 1944 log_verbose("%s:%d: formatted %.2f into %s\n", testcase, line, myNumber, u_austrcpy(tmpbuf, myString)); 1945 if(U_FAILURE(status)) { 1946 log_err("%s:%d: failed format of %.2g with %s\n", testcase, line, myNumber, u_errorName(status)); 1947 return; 1948 } 1949 aNumber = unum_parse(nf, myString, -1, NULL, &status); 1950 if(U_FAILURE(status)) { 1951 log_err("%s:%d: failed parse with %s\n", testcase, line, u_errorName(status)); 1952 return; 1953 } 1954 if(uprv_fabs(aNumber-myNumber)>.001) { 1955 log_err("FAIL: %s:%d formatted %.2f, parsed into %.2f\n", testcase, line, myNumber, aNumber); 1956 } else { 1957 log_verbose("PASS: %s:%d formatted %.2f, parsed into %.2f\n", testcase, line, myNumber, aNumber); 1958 } 1959 } 1960 1961 static void TestNBSPPatternRT(const char *testcase, UNumberFormat *nf) { 1962 TestNBSPPatternRtNum(testcase, __LINE__, nf, 12345.); 1963 TestNBSPPatternRtNum(testcase, __LINE__, nf, -12345.); 1964 } 1965 1966 static void TestNBSPInPattern(void) { 1967 UErrorCode status = U_ZERO_ERROR; 1968 UNumberFormat* nf = NULL; 1969 const char *testcase; 1970 1971 1972 testcase="ar_AE UNUM_CURRENCY"; 1973 nf = unum_open(UNUM_CURRENCY, NULL, -1, "ar_AE", NULL, &status); 1974 if(U_FAILURE(status) || nf == NULL) { 1975 log_data_err("%s:%d: %s: unum_open failed with %s (Are you missing data?)\n", __FILE__, __LINE__, testcase, u_errorName(status)); 1976 return; 1977 } 1978 TestNBSPPatternRT(testcase, nf); 1979 1980 /* if we don't have CLDR 1.6 data, bring out the problem anyways */ 1981 { 1982 #define SPECIAL_PATTERN "\\u00A4\\u00A4'\\u062f.\\u0625.\\u200f\\u00a0'###0.00" 1983 UChar pat[200]; 1984 testcase = "ar_AE special pattern: " SPECIAL_PATTERN; 1985 u_unescape(SPECIAL_PATTERN, pat, UPRV_LENGTHOF(pat)); 1986 unum_applyPattern(nf, FALSE, pat, -1, NULL, &status); 1987 if(U_FAILURE(status)) { 1988 log_err("%s: unum_applyPattern failed with %s\n", testcase, u_errorName(status)); 1989 } else { 1990 TestNBSPPatternRT(testcase, nf); 1991 } 1992 #undef SPECIAL_PATTERN 1993 } 1994 unum_close(nf); status = U_ZERO_ERROR; 1995 1996 testcase="ar_AE UNUM_DECIMAL"; 1997 nf = unum_open(UNUM_DECIMAL, NULL, -1, "ar_AE", NULL, &status); 1998 if(U_FAILURE(status)) { 1999 log_err("%s: unum_open failed with %s\n", testcase, u_errorName(status)); 2000 } 2001 TestNBSPPatternRT(testcase, nf); 2002 unum_close(nf); status = U_ZERO_ERROR; 2003 2004 testcase="ar_AE UNUM_PERCENT"; 2005 nf = unum_open(UNUM_PERCENT, NULL, -1, "ar_AE", NULL, &status); 2006 if(U_FAILURE(status)) { 2007 log_err("%s: unum_open failed with %s\n", testcase, u_errorName(status)); 2008 } 2009 TestNBSPPatternRT(testcase, nf); 2010 unum_close(nf); status = U_ZERO_ERROR; 2011 2012 2013 2014 } 2015 static void TestCloneWithRBNF(void) { 2016 UChar pattern[1024]; 2017 UChar pat2[512]; 2018 UErrorCode status = U_ZERO_ERROR; 2019 UChar buffer[256]; 2020 UChar buffer_cloned[256]; 2021 char temp1[256]; 2022 char temp2[256]; 2023 UNumberFormat *pform_cloned; 2024 UNumberFormat *pform; 2025 2026 u_uastrcpy(pattern, 2027 "%main:\n" 2028 "0.x: >%%millis-only>;\n" 2029 "x.0: <%%duration<;\n" 2030 "x.x: <%%durationwithmillis<>%%millis-added>;\n" 2031 "-x: ->>;%%millis-only:\n" 2032 "1000: 00:00.<%%millis<;\n" 2033 "%%millis-added:\n" 2034 "1000: .<%%millis<;\n" 2035 "%%millis:\n" 2036 "0: =000=;\n" 2037 "%%duration:\n" 2038 "0: =%%seconds-only=;\n" 2039 "60: =%%min-sec=;\n" 2040 "3600: =%%hr-min-sec=;\n" 2041 "86400/86400: <%%ddaayyss<[, >>];\n" 2042 "%%durationwithmillis:\n" 2043 "0: =%%seconds-only=;\n" 2044 "60: =%%min-sec=;\n" 2045 "3600: =%%hr-min-sec=;\n" 2046 "86400/86400: <%%ddaayyss<, >>;\n"); 2047 u_uastrcpy(pat2, 2048 "%%seconds-only:\n" 2049 "0: 0:00:=00=;\n" 2050 "%%min-sec:\n" 2051 "0: :=00=;\n" 2052 "0/60: 0:<00<>>;\n" 2053 "%%hr-min-sec:\n" 2054 "0: :=00=;\n" 2055 "60/60: <00<>>;\n" 2056 "3600/60: <0<:>>>;\n" 2057 "%%ddaayyss:\n" 2058 "0 days;\n" 2059 "1 day;\n" 2060 "=0= days;"); 2061 2062 /* This is to get around some compiler warnings about char * string length. */ 2063 u_strcat(pattern, pat2); 2064 2065 pform = unum_open(UNUM_PATTERN_RULEBASED, pattern, -1, "en_US", NULL, &status); 2066 unum_formatDouble(pform, 3600, buffer, 256, NULL, &status); 2067 2068 pform_cloned = unum_clone(pform,&status); 2069 unum_formatDouble(pform_cloned, 3600, buffer_cloned, 256, NULL, &status); 2070 2071 unum_close(pform); 2072 unum_close(pform_cloned); 2073 2074 if (u_strcmp(buffer,buffer_cloned)) { 2075 log_data_err("Result from cloned formatter not identical to the original. Original: %s Cloned: %s - (Are you missing data?)",u_austrcpy(temp1, buffer),u_austrcpy(temp2,buffer_cloned)); 2076 } 2077 } 2078 2079 2080 static void TestNoExponent(void) { 2081 UErrorCode status = U_ZERO_ERROR; 2082 UChar str[100]; 2083 const char *cstr; 2084 UNumberFormat *fmt; 2085 int32_t pos; 2086 int32_t expect = 0; 2087 int32_t num; 2088 2089 fmt = unum_open(UNUM_DECIMAL, NULL, -1, "en_US", NULL, &status); 2090 2091 if(U_FAILURE(status) || fmt == NULL) { 2092 log_data_err("%s:%d: unum_open failed with %s (Are you missing data?)\n", __FILE__, __LINE__, u_errorName(status)); 2093 return; 2094 } 2095 2096 cstr = "10E6"; 2097 u_uastrcpy(str, cstr); 2098 expect = 10000000; 2099 pos = 0; 2100 num = unum_parse(fmt, str, -1, &pos, &status); 2101 ASSERT_TRUE(pos==4); 2102 if(U_FAILURE(status)) { 2103 log_data_err("%s:%d: unum_parse failed with %s for %s (Are you missing data?)\n", __FILE__, __LINE__, u_errorName(status), cstr); 2104 } else if(expect!=num) { 2105 log_data_err("%s:%d: unum_parse failed, got %d expected %d for '%s'(Are you missing data?)\n", __FILE__, __LINE__, num, expect, cstr); 2106 } else { 2107 log_verbose("%s:%d: unum_parse returned %d for '%s'\n", __FILE__, __LINE__, num, cstr); 2108 } 2109 2110 ASSERT_TRUE(unum_getAttribute(fmt, UNUM_PARSE_NO_EXPONENT)==0); 2111 2112 unum_setAttribute(fmt, UNUM_PARSE_NO_EXPONENT, 1); /* no error code */ 2113 log_verbose("set UNUM_PARSE_NO_EXPONENT\n"); 2114 2115 ASSERT_TRUE(unum_getAttribute(fmt, UNUM_PARSE_NO_EXPONENT)==1); 2116 2117 pos = 0; 2118 expect=10; 2119 num = unum_parse(fmt, str, -1, &pos, &status); 2120 if(num==10000000) { 2121 log_err("%s:%d: FAIL: unum_parse should have returned 10, not 10000000 on %s after UNUM_PARSE_NO_EXPONENT\n", __FILE__, __LINE__, cstr); 2122 } else if(num==expect) { 2123 log_verbose("%s:%d: unum_parse gave %d for %s - good.\n", __FILE__, __LINE__, num, cstr); 2124 } 2125 ASSERT_TRUE(pos==2); 2126 2127 status = U_ZERO_ERROR; 2128 2129 unum_close(fmt); 2130 2131 /* ok, now try scientific */ 2132 fmt = unum_open(UNUM_SCIENTIFIC, NULL, -1, "en_US", NULL, &status); 2133 assertSuccess("unum_open(UNUM_SCIENTIFIC, ...)", &status); 2134 2135 ASSERT_TRUE(unum_getAttribute(fmt, UNUM_PARSE_NO_EXPONENT)==0); 2136 2137 cstr = "10E6"; 2138 u_uastrcpy(str, cstr); 2139 expect = 10000000; 2140 pos = 0; 2141 num = unum_parse(fmt, str, -1, &pos, &status); 2142 ASSERT_TRUE(pos==4); 2143 if(U_FAILURE(status)) { 2144 log_data_err("%s:%d: unum_parse failed with %s for %s (Are you missing data?)\n", __FILE__, __LINE__, u_errorName(status), cstr); 2145 } else if(expect!=num) { 2146 log_data_err("%s:%d: unum_parse failed, got %d expected %d for '%s'(Are you missing data?)\n", __FILE__, __LINE__, num, expect, cstr); 2147 } else { 2148 log_verbose("%s:%d: unum_parse returned %d for '%s'\n", __FILE__, __LINE__, num, cstr); 2149 } 2150 2151 unum_setAttribute(fmt, UNUM_PARSE_NO_EXPONENT, 1); /* no error code */ 2152 log_verbose("set UNUM_PARSE_NO_EXPONENT\n"); 2153 2154 ASSERT_TRUE(unum_getAttribute(fmt, UNUM_PARSE_NO_EXPONENT)==1); 2155 2156 2157 cstr = "10E6"; 2158 u_uastrcpy(str, cstr); 2159 expect = 10000000; 2160 pos = 0; 2161 num = unum_parse(fmt, str, -1, &pos, &status); 2162 ASSERT_TRUE(pos==4); 2163 if(U_FAILURE(status)) { 2164 log_data_err("%s:%d: unum_parse failed with %s for %s (Are you missing data?)\n", __FILE__, __LINE__, u_errorName(status), cstr); 2165 } else if(expect!=num) { 2166 log_data_err("%s:%d: unum_parse failed, got %d expected %d for '%s'(Are you missing data?)\n", __FILE__, __LINE__, num, expect, cstr); 2167 } else { 2168 log_verbose("%s:%d: unum_parse returned %d for '%s'\n", __FILE__, __LINE__, num, cstr); 2169 } 2170 2171 unum_close(fmt); 2172 } 2173 2174 static void TestMaxInt(void) { 2175 UErrorCode status = U_ZERO_ERROR; 2176 UChar pattern_hash[] = { 0x23, 0x00 }; /* "#" */ 2177 UChar result1[1024] = { 0 }, result2[1024] = { 0 }; 2178 int32_t len1, len2; 2179 UChar expect[] = { 0x0039, 0x0037, 0 }; 2180 UNumberFormat *fmt = unum_open( 2181 UNUM_PATTERN_DECIMAL, /* style */ 2182 &pattern_hash[0], /* pattern */ 2183 u_strlen(pattern_hash), /* patternLength */ 2184 0, 2185 0, /* parseErr */ 2186 &status); 2187 if(U_FAILURE(status) || fmt == NULL) { 2188 log_data_err("%s:%d: %s: unum_open failed with %s (Are you missing data?)\n", __FILE__, __LINE__, "TestMaxInt", u_errorName(status)); 2189 return; 2190 } 2191 2192 unum_setAttribute(fmt, UNUM_MAX_INTEGER_DIGITS, 2); 2193 2194 status = U_ZERO_ERROR; 2195 /* #1 */ 2196 len1 = unum_formatInt64(fmt, 1997, result1, 1024, NULL, &status); 2197 result1[len1]=0; 2198 if(U_FAILURE(status) || u_strcmp(expect, result1)) { 2199 log_err("unum_formatInt64 Expected %s but got %s status %s\n", austrdup(expect), austrdup(result1), u_errorName(status)); 2200 } 2201 2202 status = U_ZERO_ERROR; 2203 /* #2 */ 2204 len2 = unum_formatDouble(fmt, 1997.0, result2, 1024, NULL, &status); 2205 result2[len2]=0; 2206 if(U_FAILURE(status) || u_strcmp(expect, result2)) { 2207 log_err("unum_formatDouble Expected %s but got %s status %s\n", austrdup(expect), austrdup(result2), u_errorName(status)); 2208 } 2209 2210 2211 2212 /* test UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS */ 2213 ASSERT_TRUE(unum_getAttribute(fmt, UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS)==0); 2214 2215 unum_setAttribute(fmt, UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS, 1); 2216 /* test UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS */ 2217 ASSERT_TRUE(unum_getAttribute(fmt, UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS)==1); 2218 2219 status = U_ZERO_ERROR; 2220 /* max int digits still '2' */ 2221 len1 = unum_formatInt64(fmt, 1997, result1, 1024, NULL, &status); 2222 ASSERT_TRUE(status==U_ILLEGAL_ARGUMENT_ERROR); 2223 status = U_ZERO_ERROR; 2224 2225 /* But, formatting 97->'97' works fine. */ 2226 2227 /* #1 */ 2228 len1 = unum_formatInt64(fmt, 97, result1, 1024, NULL, &status); 2229 result1[len1]=0; 2230 if(U_FAILURE(status) || u_strcmp(expect, result1)) { 2231 log_err("unum_formatInt64 Expected %s but got %s status %s\n", austrdup(expect), austrdup(result1), u_errorName(status)); 2232 } 2233 2234 status = U_ZERO_ERROR; 2235 /* #2 */ 2236 len2 = unum_formatDouble(fmt, 97.0, result2, 1024, NULL, &status); 2237 result2[len2]=0; 2238 if(U_FAILURE(status) || u_strcmp(expect, result2)) { 2239 log_err("unum_formatDouble Expected %s but got %s status %s\n", austrdup(expect), austrdup(result2), u_errorName(status)); 2240 } 2241 2242 2243 unum_close(fmt); 2244 } 2245 2246 static void TestUFormattable(void) { 2247 UChar out2k[2048]; 2248 // simple test for API docs 2249 { 2250 UErrorCode status = U_ZERO_ERROR; 2251 UNumberFormat *unum = unum_open(UNUM_DEFAULT, NULL, -1, "en_US_POSIX", NULL, &status); 2252 if(assertSuccessCheck("calling unum_open()", &status, TRUE)) { 2253 //! [unum_parseToUFormattable] 2254 const UChar str[] = { 0x0031, 0x0032, 0x0033, 0x0000 }; /* 123 */ 2255 int32_t result = 0; 2256 UFormattable *ufmt = ufmt_open(&status); 2257 unum_parseToUFormattable(unum, ufmt, str, -1, NULL, &status); 2258 if (ufmt_isNumeric(ufmt)) { 2259 result = ufmt_getLong(ufmt, &status); /* == 123 */ 2260 } /* else { ... } */ 2261 ufmt_close(ufmt); 2262 //! [unum_parseToUFormattable] 2263 assertTrue("result == 123", (result == 123)); 2264 } 2265 unum_close(unum); 2266 } 2267 // test with explicitly created ufmt_open 2268 { 2269 UChar buffer[2048]; 2270 UErrorCode status = U_ZERO_ERROR; 2271 UFormattable *ufmt; 2272 UNumberFormat *unum; 2273 const char *pattern = ""; 2274 2275 ufmt = ufmt_open(&status); 2276 unum = unum_open(UNUM_DEFAULT, NULL, -1, "en_US_POSIX", NULL, &status); 2277 if(assertSuccessCheck("calling ufmt_open() || unum_open()", &status, TRUE)) { 2278 2279 pattern = "31337"; 2280 log_verbose("-- pattern: %s\n", pattern); 2281 u_uastrcpy(buffer, pattern); 2282 unum_parseToUFormattable(unum, ufmt, buffer, -1, NULL, &status); 2283 if(assertSuccess("unum_parseToUFormattable(31337)", &status)) { 2284 assertTrue("ufmt_getLong()=31337", ufmt_getLong(ufmt, &status) == 31337); 2285 assertTrue("ufmt_getType()=UFMT_LONG", ufmt_getType(ufmt, &status) == UFMT_LONG); 2286 log_verbose("long = %d\n", ufmt_getLong(ufmt, &status)); 2287 assertSuccess("ufmt_getLong()", &status); 2288 } 2289 unum_formatUFormattable(unum, ufmt, out2k, 2048, NULL, &status); 2290 if(assertSuccess("unum_formatUFormattable(31337)", &status)) { 2291 assertEquals("unum_formatUFormattable r/t", austrdup(buffer), austrdup(out2k)); 2292 } 2293 2294 pattern = "3.14159"; 2295 log_verbose("-- pattern: %s\n", pattern); 2296 u_uastrcpy(buffer, pattern); 2297 unum_parseToUFormattable(unum, ufmt, buffer, -1, NULL, &status); 2298 if(assertSuccess("unum_parseToUFormattable(3.14159)", &status)) { 2299 assertTrue("ufmt_getDouble()==3.14159", withinErr(ufmt_getDouble(ufmt, &status), 3.14159, 1e-15)); 2300 assertSuccess("ufmt_getDouble()", &status); 2301 assertTrue("ufmt_getType()=UFMT_DOUBLE", ufmt_getType(ufmt, &status) == UFMT_DOUBLE); 2302 log_verbose("double = %g\n", ufmt_getDouble(ufmt, &status)); 2303 } 2304 unum_formatUFormattable(unum, ufmt, out2k, 2048, NULL, &status); 2305 if(assertSuccess("unum_formatUFormattable(3.14159)", &status)) { 2306 assertEquals("unum_formatUFormattable r/t", austrdup(buffer), austrdup(out2k)); 2307 } 2308 } 2309 ufmt_close(ufmt); 2310 unum_close(unum); 2311 } 2312 2313 // test with auto-generated ufmt 2314 { 2315 UChar buffer[2048]; 2316 UErrorCode status = U_ZERO_ERROR; 2317 UFormattable *ufmt = NULL; 2318 UNumberFormat *unum; 2319 const char *pattern = "73476730924573500000000"; // weight of the moon, kg 2320 2321 log_verbose("-- pattern: %s (testing auto-opened UFormattable)\n", pattern); 2322 u_uastrcpy(buffer, pattern); 2323 2324 unum = unum_open(UNUM_DEFAULT, NULL, -1, "en_US_POSIX", NULL, &status); 2325 if(assertSuccessCheck("calling unum_open()", &status, TRUE)) { 2326 2327 ufmt = unum_parseToUFormattable(unum, NULL, /* will be ufmt_open()'ed for us */ 2328 buffer, -1, NULL, &status); 2329 if(assertSuccess("unum_parseToUFormattable(weight of the moon)", &status)) { 2330 log_verbose("new formattable allocated at %p\n", (void*)ufmt); 2331 assertTrue("ufmt_isNumeric() TRUE", ufmt_isNumeric(ufmt)); 2332 unum_formatUFormattable(unum, ufmt, out2k, 2048, NULL, &status); 2333 if(assertSuccess("unum_formatUFormattable(3.14159)", &status)) { 2334 assertEquals("unum_formatUFormattable r/t", austrdup(buffer), austrdup(out2k)); 2335 } 2336 2337 log_verbose("double: %g\n", ufmt_getDouble(ufmt, &status)); 2338 assertSuccess("ufmt_getDouble()", &status); 2339 2340 log_verbose("long: %ld\n", ufmt_getLong(ufmt, &status)); 2341 assertTrue("failure on ufmt_getLong() for huge number:", U_FAILURE(status)); 2342 // status is now a failure due to ufmt_getLong() above. 2343 // the intltest does extensive r/t testing of Formattable vs. UFormattable. 2344 } 2345 } 2346 2347 unum_close(unum); 2348 ufmt_close(ufmt); // was implicitly opened for us by the first unum_parseToUFormattable() 2349 } 2350 } 2351 2352 typedef struct { 2353 const char* locale; 2354 const char* numsys; 2355 int32_t radix; 2356 UBool isAlgorithmic; 2357 const UChar* description; 2358 } NumSysTestItem; 2359 2360 2361 static const UChar latnDesc[] = {0x0030,0x0031,0x0032,0x0033,0x0034,0x0035,0x0036,0x0037,0x0038,0x0039,0}; // 0123456789 2362 static const UChar romanDesc[] = {0x25,0x72,0x6F,0x6D,0x61,0x6E,0x2D,0x75,0x70,0x70,0x65,0x72,0}; // %roman-upper 2363 static const UChar arabDesc[] = {0x0660,0x0661,0x0662,0x0663,0x0664,0x0665,0x0666,0x0667,0x0668,0x0669,0}; // 2364 static const UChar arabextDesc[] = {0x06F0,0x06F1,0x06F2,0x06F3,0x06F4,0x06F5,0x06F6,0x06F7,0x06F8,0x06F9,0}; // 2365 static const UChar hanidecDesc[] = {0x3007,0x4E00,0x4E8C,0x4E09,0x56DB,0x4E94,0x516D,0x4E03,0x516B,0x4E5D,0}; // 2366 static const UChar hantDesc[] = {0x7A,0x68,0x5F,0x48,0x61,0x6E,0x74,0x2F,0x53,0x70,0x65,0x6C,0x6C,0x6F,0x75,0x74, 2367 0x52,0x75,0x6C,0x65,0x73,0x2F,0x25,0x73,0x70,0x65,0x6C,0x6C,0x6F,0x75,0x74,0x2D, 2368 0x63,0x61,0x72,0x64,0x69,0x6E,0x61,0x6C,0}; // zh_Hant/SpelloutRules/%spellout-cardinal 2369 2370 static const NumSysTestItem numSysTestItems[] = { 2371 //locale numsys radix isAlgo description 2372 { "en", "latn", 10, FALSE, latnDesc }, 2373 { "en@numbers=roman", "roman", 10, TRUE, romanDesc }, 2374 { "en@numbers=finance", "latn", 10, FALSE, latnDesc }, 2375 { "ar", "arab", 10, FALSE, arabDesc }, 2376 { "fa", "arabext", 10, FALSE, arabextDesc }, 2377 { "zh_Hans@numbers=hanidec", "hanidec", 10, FALSE, hanidecDesc }, 2378 { "zh_Hant@numbers=traditional", "hant", 10, TRUE, hantDesc }, 2379 { NULL, NULL, 0, FALSE, NULL }, 2380 }; 2381 enum { kNumSysDescripBufMax = 64 }; 2382 2383 static void TestUNumberingSystem(void) { 2384 const NumSysTestItem * itemPtr; 2385 UNumberingSystem * unumsys; 2386 UEnumeration * uenum; 2387 const char * numsys; 2388 UErrorCode status; 2389 2390 for (itemPtr = numSysTestItems; itemPtr->locale != NULL; itemPtr++) { 2391 status = U_ZERO_ERROR; 2392 unumsys = unumsys_open(itemPtr->locale, &status); 2393 if ( U_SUCCESS(status) ) { 2394 UChar ubuf[kNumSysDescripBufMax]; 2395 int32_t ulen, radix = unumsys_getRadix(unumsys); 2396 UBool isAlgorithmic = unumsys_isAlgorithmic(unumsys); 2397 numsys = unumsys_getName(unumsys); 2398 if ( uprv_strcmp(numsys, itemPtr->numsys) != 0 || radix != itemPtr->radix || !isAlgorithmic != !itemPtr->isAlgorithmic ) { 2399 log_data_err("unumsys name/radix/isAlgorithmic for locale %s, expected %s/%d/%d, got %s/%d/%d\n", 2400 itemPtr->locale, itemPtr->numsys, itemPtr->radix, itemPtr->isAlgorithmic, numsys, radix, isAlgorithmic); 2401 } 2402 ulen = unumsys_getDescription(unumsys, ubuf, kNumSysDescripBufMax, &status); 2403 (void)ulen; // Suppress variable not used warning. 2404 if ( U_FAILURE(status) || u_strcmp(ubuf, itemPtr->description) != 0 ) { 2405 log_data_err("unumsys description for locale %s, description unexpected and/or status %\n", myErrorName(status)); 2406 } 2407 unumsys_close(unumsys); 2408 } else { 2409 log_data_err("unumsys_open for locale %s fails with status %s\n", itemPtr->locale, myErrorName(status)); 2410 } 2411 } 2412 2413 status = U_ZERO_ERROR; 2414 uenum = unumsys_openAvailableNames(&status); 2415 if ( U_SUCCESS(status) ) { 2416 int32_t numsysCount = 0; 2417 // sanity check for a couple of number systems that must be in the enumeration 2418 UBool foundLatn = FALSE; 2419 UBool foundArab = FALSE; 2420 while ( (numsys = uenum_next(uenum, NULL, &status)) != NULL && U_SUCCESS(status) ) { 2421 status = U_ZERO_ERROR; 2422 unumsys = unumsys_openByName(numsys, &status); 2423 if ( U_SUCCESS(status) ) { 2424 numsysCount++; 2425 if ( uprv_strcmp(numsys, "latn") ) foundLatn = TRUE; 2426 if ( uprv_strcmp(numsys, "arab") ) foundArab = TRUE; 2427 unumsys_close(unumsys); 2428 } else { 2429 log_err("unumsys_openAvailableNames includes %s but unumsys_openByName on it fails with status %s\n", 2430 numsys, myErrorName(status)); 2431 } 2432 } 2433 uenum_close(uenum); 2434 if ( numsysCount < 40 || !foundLatn || !foundArab ) { 2435 log_err("unumsys_openAvailableNames results incomplete: numsysCount %d, foundLatn %d, foundArab %d\n", 2436 numsysCount, foundLatn, foundArab); 2437 } 2438 } else { 2439 log_data_err("unumsys_openAvailableNames fails with status %s\n", myErrorName(status)); 2440 } 2441 } 2442 2443 /* plain-C version of test in numfmtst.cpp */ 2444 enum { kUBufMax = 64 }; 2445 static void TestCurrencyIsoPluralFormat(void) { 2446 static const char* DATA[][8] = { 2447 // the data are: 2448 // locale, 2449 // currency amount to be formatted, 2450 // currency ISO code to be formatted, 2451 // format result using CURRENCYSTYLE, 2452 // format result using CURRENCY_STANDARD, 2453 // format result using CURRENCY_ACCOUNTING, 2454 // format result using ISOCURRENCYSTYLE, 2455 // format result using PLURALCURRENCYSTYLE, 2456 2457 // locale amount ISOcode CURRENCYSTYLE CURRENCY_STANDARD CURRENCY_ACCOUNTING ISOCURRENCYSTYLE PLURALCURRENCYSTYLE 2458 {"en_US", "1", "USD", "$1.00", "$1.00", "$1.00", "USD1.00", "1.00 US dollars"}, 2459 {"en_US", "1234.56", "USD", "$1,234.56", "$1,234.56", "$1,234.56", "USD1,234.56", "1,234.56 US dollars"}, 2460 {"en_US@cf=account", "1234.56", "USD", "$1,234.56", "$1,234.56", "$1,234.56", "USD1,234.56", "1,234.56 US dollars"}, 2461 {"en_US", "-1234.56", "USD", "-$1,234.56", "-$1,234.56", "($1,234.56)", "-USD1,234.56", "-1,234.56 US dollars"}, 2462 {"en_US@cf=account", "-1234.56", "USD", "($1,234.56)", "-$1,234.56", "($1,234.56)", "-USD1,234.56", "-1,234.56 US dollars"}, 2463 {"en_US@cf=standard", "-1234.56", "USD", "-$1,234.56", "-$1,234.56", "($1,234.56)", "-USD1,234.56", "-1,234.56 US dollars"}, 2464 {"zh_CN", "1", "USD", "US$1.00", "US$1.00", "US$1.00", "USD1.00", "1.00\\u7F8E\\u5143"}, 2465 {"zh_CN", "-1", "USD", "-US$1.00", "-US$1.00", "(US$1.00)", "-USD1.00", "-1.00\\u7F8E\\u5143"}, 2466 {"zh_CN@cf=account", "-1", "USD", "(US$1.00)", "-US$1.00", "(US$1.00)", "-USD1.00", "-1.00\\u7F8E\\u5143"}, 2467 {"zh_CN@cf=standard", "-1", "USD", "-US$1.00", "-US$1.00", "(US$1.00)", "-USD1.00", "-1.00\\u7F8E\\u5143"}, 2468 {"zh_CN", "1234.56", "USD", "US$1,234.56", "US$1,234.56", "US$1,234.56", "USD1,234.56", "1,234.56\\u7F8E\\u5143"}, 2469 // {"zh_CN", "1", "CHY", "CHY1.00", "CHY1.00", "CHY1.00", "CHY1.00", "1.00 CHY"}, // wrong ISO code 2470 // {"zh_CN", "1234.56", "CHY", "CHY1,234.56", "CHY1,234.56", "CHY1,234.56", "CHY1,234.56", "1,234.56 CHY"}, // wrong ISO code 2471 {"zh_CN", "1", "CNY", "\\uFFE51.00", "\\uFFE51.00", "\\uFFE51.00", "CNY1.00", "1.00\\u4EBA\\u6C11\\u5E01"}, 2472 {"zh_CN", "1234.56", "CNY", "\\uFFE51,234.56", "\\uFFE51,234.56", "\\uFFE51,234.56", "CNY1,234.56", "1,234.56\\u4EBA\\u6C11\\u5E01"}, 2473 {"ru_RU", "1", "RUB", "1,00\\u00A0\\u20BD", "1,00\\u00A0\\u20BD", "1,00\\u00A0\\u20BD", "1,00\\u00A0RUB", "1,00 \\u0440\\u043E\\u0441\\u0441\\u0438\\u0439\\u0441\\u043A\\u043E\\u0433\\u043E " 2474 "\\u0440\\u0443\\u0431\\u043B\\u044F"}, 2475 {"ru_RU", "2", "RUB", "2,00\\u00A0\\u20BD", "2,00\\u00A0\\u20BD", "2,00\\u00A0\\u20BD", "2,00\\u00A0RUB", "2,00 \\u0440\\u043E\\u0441\\u0441\\u0438\\u0439\\u0441\\u043A\\u043E\\u0433\\u043E " 2476 "\\u0440\\u0443\\u0431\\u043B\\u044F"}, 2477 {"ru_RU", "5", "RUB", "5,00\\u00A0\\u20BD", "5,00\\u00A0\\u20BD", "5,00\\u00A0\\u20BD", "5,00\\u00A0RUB", "5,00 \\u0440\\u043E\\u0441\\u0441\\u0438\\u0439\\u0441\\u043A\\u043E\\u0433\\u043E " 2478 "\\u0440\\u0443\\u0431\\u043B\\u044F"}, 2479 // test locale without currency information 2480 {"root", "-1.23", "USD", "-US$\\u00A01.23", "-US$\\u00A01.23", "-US$\\u00A01.23", "-USD\\u00A01.23", "-1.23 USD"}, 2481 {"root@cf=account", "-1.23", "USD", "-US$\\u00A01.23", "-US$\\u00A01.23", "-US$\\u00A01.23", "-USD\\u00A01.23", "-1.23 USD"}, 2482 // test choice format 2483 {"es_AR", "1", "INR", "INR\\u00A01,00", "INR\\u00A01,00", "INR\\u00A01,00", "INR\\u00A01,00", "1,00 rupia india"}, 2484 }; 2485 static const UNumberFormatStyle currencyStyles[] = { 2486 UNUM_CURRENCY, 2487 UNUM_CURRENCY_STANDARD, 2488 UNUM_CURRENCY_ACCOUNTING, 2489 UNUM_CURRENCY_ISO, 2490 UNUM_CURRENCY_PLURAL 2491 }; 2492 2493 int32_t i, sIndex; 2494 2495 for (i=0; i<UPRV_LENGTHOF(DATA); ++i) { 2496 const char* localeString = DATA[i][0]; 2497 double numberToBeFormat = atof(DATA[i][1]); 2498 const char* currencyISOCode = DATA[i][2]; 2499 for (sIndex = 0; sIndex < UPRV_LENGTHOF(currencyStyles); ++sIndex) { 2500 UNumberFormatStyle style = currencyStyles[sIndex]; 2501 UErrorCode status = U_ZERO_ERROR; 2502 UChar currencyCode[4]; 2503 UChar ubufResult[kUBufMax]; 2504 UChar ubufExpected[kUBufMax]; 2505 int32_t ulenRes; 2506 2507 UNumberFormat* unumFmt = unum_open(style, NULL, 0, localeString, NULL, &status); 2508 if (U_FAILURE(status)) { 2509 log_data_err("FAIL: unum_open, locale %s, style %d - %s\n", localeString, (int)style, myErrorName(status)); 2510 continue; 2511 } 2512 u_charsToUChars(currencyISOCode, currencyCode, 4); 2513 unum_setTextAttribute(unumFmt, UNUM_CURRENCY_CODE, currencyCode, 3, &status); 2514 if (U_FAILURE(status)) { 2515 log_err("FAIL: unum_setTextAttribute, locale %s, UNUM_CURRENCY_CODE %s\n", localeString, currencyISOCode); 2516 } 2517 ulenRes = unum_formatDouble(unumFmt, numberToBeFormat, ubufResult, kUBufMax, NULL, &status); 2518 if (U_FAILURE(status)) { 2519 log_err("FAIL: unum_formatDouble, locale %s, UNUM_CURRENCY_CODE %s - %s\n", localeString, currencyISOCode, myErrorName(status)); 2520 } else { 2521 int32_t ulenExp = u_unescape(DATA[i][3 + sIndex], ubufExpected, kUBufMax); 2522 if (ulenRes != ulenExp || u_strncmp(ubufResult, ubufExpected, ulenExp) != 0) { 2523 log_err("FAIL: unum_formatDouble, locale %s, UNUM_CURRENCY_CODE %s, expected %s, got something else\n", 2524 localeString, currencyISOCode, DATA[i][3 + sIndex]); 2525 } 2526 } 2527 unum_close(unumFmt); 2528 } 2529 } 2530 } 2531 2532 typedef struct { 2533 const char * locale; 2534 UNumberFormatStyle style; 2535 UDisplayContext context; 2536 const char * expectedResult; 2537 } TestContextItem; 2538 2539 /* currently no locales have contextTransforms data for "symbol" type */ 2540 static const TestContextItem tcItems[] = { /* results for 123.45 */ 2541 { "sv", UNUM_SPELLOUT, UDISPCTX_CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE, "ett\\u00ADhundra\\u00ADtjugo\\u00ADtre komma fyra fem" }, 2542 { "sv", UNUM_SPELLOUT, UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE, "Ett\\u00ADhundra\\u00ADtjugo\\u00ADtre komma fyra fem" }, 2543 { "sv", UNUM_SPELLOUT, UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU, "ett\\u00ADhundra\\u00ADtjugo\\u00ADtre komma fyra fem" }, 2544 { "sv", UNUM_SPELLOUT, UDISPCTX_CAPITALIZATION_FOR_STANDALONE, "ett\\u00ADhundra\\u00ADtjugo\\u00ADtre komma fyra fem" }, 2545 { "en", UNUM_SPELLOUT, UDISPCTX_CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE, "one hundred twenty-three point four five" }, 2546 { "en", UNUM_SPELLOUT, UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE, "One hundred twenty-three point four five" }, 2547 { "en", UNUM_SPELLOUT, UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU, "One hundred twenty-three point four five" }, 2548 { "en", UNUM_SPELLOUT, UDISPCTX_CAPITALIZATION_FOR_STANDALONE, "One hundred twenty-three point four five" }, 2549 { NULL, (UNumberFormatStyle)0, (UDisplayContext)0, NULL } 2550 }; 2551 2552 static void TestContext(void) { 2553 UErrorCode status = U_ZERO_ERROR; 2554 const TestContextItem* itemPtr; 2555 2556 UNumberFormat *unum = unum_open(UNUM_SPELLOUT, NULL, 0, "en", NULL, &status); 2557 if ( U_SUCCESS(status) ) { 2558 UDisplayContext context = unum_getContext(unum, UDISPCTX_TYPE_CAPITALIZATION, &status); 2559 if ( U_FAILURE(status) || context != UDISPCTX_CAPITALIZATION_NONE) { 2560 log_err("FAIL: Initial unum_getContext is not UDISPCTX_CAPITALIZATION_NONE\n"); 2561 status = U_ZERO_ERROR; 2562 } 2563 unum_setContext(unum, UDISPCTX_CAPITALIZATION_FOR_STANDALONE, &status); 2564 context = unum_getContext(unum, UDISPCTX_TYPE_CAPITALIZATION, &status); 2565 if ( U_FAILURE(status) || context != UDISPCTX_CAPITALIZATION_FOR_STANDALONE) { 2566 log_err("FAIL: unum_getContext does not return the value set, UDISPCTX_CAPITALIZATION_FOR_STANDALONE\n"); 2567 } 2568 unum_close(unum); 2569 } else { 2570 log_data_err("unum_open UNUM_SPELLOUT for en fails with status %s\n", myErrorName(status)); 2571 } 2572 #if !UCONFIG_NO_NORMALIZATION && !UCONFIG_NO_BREAK_ITERATION 2573 for (itemPtr = tcItems; itemPtr->locale != NULL; itemPtr++) { 2574 UChar ubufResult[kUBufMax]; 2575 int32_t ulenRes; 2576 2577 status = U_ZERO_ERROR; 2578 unum = unum_open(itemPtr->style, NULL, 0, itemPtr->locale, NULL, &status); 2579 if (U_FAILURE(status)) { 2580 log_data_err("FAIL: unum_open, locale %s, style %d - %s\n", 2581 itemPtr->locale, (int)itemPtr->style, myErrorName(status)); 2582 continue; 2583 } 2584 unum_setContext(unum, itemPtr->context, &status); 2585 ulenRes = unum_formatDouble(unum, 123.45, ubufResult, kUBufMax, NULL, &status); 2586 if (U_FAILURE(status)) { 2587 log_err("FAIL: unum_formatDouble, locale %s, style %d, context %d - %s\n", 2588 itemPtr->locale, (int)itemPtr->style, (int)itemPtr->context, myErrorName(status)); 2589 } else { 2590 UChar ubufExpected[kUBufMax]; 2591 int32_t ulenExp = u_unescape(itemPtr->expectedResult, ubufExpected, kUBufMax); 2592 if (ulenRes != ulenExp || u_strncmp(ubufResult, ubufExpected, ulenExp) != 0) { 2593 char bbuf[kUBufMax*2]; 2594 u_austrncpy(bbuf, ubufResult, sizeof(bbuf)); 2595 log_err("FAIL: unum_formatDouble, locale %s, style %d, context %d, expected %d:\"%s\", got %d:\"%s\"\n", 2596 itemPtr->locale, (int)itemPtr->style, (int)itemPtr->context, ulenExp, 2597 itemPtr->expectedResult, ulenRes, bbuf); 2598 } 2599 } 2600 unum_close(unum); 2601 } 2602 #endif /* #if !UCONFIG_NO_NORMALIZATION && !UCONFIG_NO_BREAK_ITERATION */ 2603 } 2604 2605 static void TestCurrencyUsage(void) { 2606 static const char* DATA[][2] = { 2607 /* the data are: 2608 * currency ISO code to be formatted, 2609 * format result using CURRENCYSTYLE with CASH purpose,- 2610 * Note that as of CLDR 26:- 2611 * - TWD switches from 0 decimals to 2; PKR still has 0, so change test to that 2612 * - CAD rounds to .05 2613 */ 2614 2615 {"PKR", "PKR124"}, 2616 {"CAD", "CA$123.55"}, 2617 {"USD", "$123.57"} 2618 }; 2619 2620 // 1st time for getter/setter, 2nd for factory method 2621 int32_t i; 2622 for(i=0; i<2; i++){ 2623 const char* localeString = "en_US"; 2624 double numberToBeFormat = 123.567; 2625 UNumberFormat* unumFmt; 2626 UNumberFormatStyle style = UNUM_CURRENCY; 2627 UErrorCode status = U_ZERO_ERROR; 2628 int32_t j; 2629 2630 if(i == 1){ // change for factory method 2631 style = UNUM_CASH_CURRENCY; 2632 } 2633 2634 unumFmt = unum_open(style, NULL, 0, localeString, NULL, &status); 2635 if (U_FAILURE(status)) { 2636 log_data_err("FAIL: unum_open, locale %s, style %d - %s\n", 2637 localeString, (int)style, myErrorName(status)); 2638 continue; 2639 } 2640 2641 if(i == 0){ // this is for the getter/setter 2642 if(unum_getAttribute(unumFmt, UNUM_CURRENCY_USAGE) != UCURR_USAGE_STANDARD) { 2643 log_err("FAIL: currency usage attribute is not UNUM_CURRENCY_STANDARD\n"); 2644 } 2645 2646 unum_setAttribute(unumFmt, UNUM_CURRENCY_USAGE, UCURR_USAGE_CASH); 2647 } 2648 2649 if(unum_getAttribute(unumFmt, UNUM_CURRENCY_USAGE) != UCURR_USAGE_CASH) { 2650 log_err("FAIL: currency usage attribute is not UNUM_CURRENCY_CASH\n"); 2651 } 2652 2653 for (j=0; j<UPRV_LENGTHOF(DATA); ++j) { 2654 UChar expect[64]; 2655 int32_t expectLen; 2656 UChar currencyCode[4]; 2657 UChar result[64]; 2658 int32_t resultLen; 2659 UFieldPosition pos = {0}; 2660 2661 u_charsToUChars(DATA[j][0], currencyCode, 3); 2662 expectLen = u_unescape(DATA[j][1], expect, UPRV_LENGTHOF(expect)); 2663 2664 unum_setTextAttribute(unumFmt, UNUM_CURRENCY_CODE, currencyCode, 3, &status); 2665 assertSuccess("num_setTextAttribute()", &status); 2666 2667 resultLen = unum_formatDouble(unumFmt, numberToBeFormat, result, UPRV_LENGTHOF(result), 2668 &pos, &status); 2669 assertSuccess("num_formatDouble()", &status); 2670 2671 if(resultLen != expectLen || u_strcmp(result, expect) != 0) { 2672 log_err("Fail: Error in Number Format Currency Purpose using unum_setAttribute() expected: %s, got %s\n", 2673 aescstrdup(expect, expectLen), aescstrdup(result, resultLen)); 2674 } 2675 2676 } 2677 2678 unum_close(unumFmt); 2679 } 2680 } 2681 2682 static UChar currFmtNegSameAsPos[] = /* "\u00A4#,##0.00;\u00A4#,##0.00" */ 2683 {0xA4,0x23,0x2C,0x23,0x23,0x30,0x2E,0x30,0x30,0x3B,0xA4,0x23,0x2C,0x23,0x23,0x30,0x2E,0x30,0x30,0}; 2684 2685 static UChar currFmtToPatExpected[] = /* "\u00A4#,##0.00" */ 2686 {0xA4,0x23,0x2C,0x23,0x23,0x30,0x2E,0x30,0x30,0}; 2687 2688 static UChar currFmtResultExpected[] = /* "$100.00" */ 2689 {0x24,0x31,0x30,0x30,0x2E,0x30,0x30,0}; 2690 2691 static UChar emptyString[] = {0}; 2692 2693 enum { kUBufSize = 64, kBBufSize = 128 }; 2694 2695 static void TestCurrFmtNegSameAsPositive(void) { 2696 UErrorCode status = U_ZERO_ERROR; 2697 UNumberFormat* unumfmt = unum_open(UNUM_CURRENCY, NULL, 0, "en_US", NULL, &status); 2698 if ( U_SUCCESS(status) ) { 2699 unum_applyPattern(unumfmt, FALSE, currFmtNegSameAsPos, -1, NULL, &status); 2700 if (U_SUCCESS(status)) { 2701 UChar ubuf[kUBufSize]; 2702 int32_t ulen = unum_toPattern(unumfmt, FALSE, ubuf, kUBufSize, &status); 2703 if (U_FAILURE(status)) { 2704 log_err("unum_toPattern fails with status %s\n", myErrorName(status)); 2705 } else if (u_strcmp(ubuf, currFmtToPatExpected) != 0) { 2706 log_err("unum_toPattern result wrong, expected %s, got %s\n", aescstrdup(currFmtToPatExpected,-1), aescstrdup(ubuf,ulen)); 2707 } 2708 unum_setSymbol(unumfmt, UNUM_MINUS_SIGN_SYMBOL, emptyString, 0, &status); 2709 if (U_SUCCESS(status)) { 2710 ulen = unum_formatDouble(unumfmt, -100.0, ubuf, kUBufSize, NULL, &status); 2711 if (U_FAILURE(status)) { 2712 log_err("unum_formatDouble fails with status %s\n", myErrorName(status)); 2713 } else if (u_strcmp(ubuf, currFmtResultExpected) != 0) { 2714 log_err("unum_formatDouble result wrong, expected %s, got %s\n", aescstrdup(currFmtResultExpected,-1), aescstrdup(ubuf,ulen)); 2715 } 2716 } else { 2717 log_err("unum_setSymbol fails with status %s\n", myErrorName(status)); 2718 } 2719 } else { 2720 log_err("unum_applyPattern fails with status %s\n", myErrorName(status)); 2721 } 2722 unum_close(unumfmt); 2723 } else { 2724 log_data_err("unum_open UNUM_CURRENCY for en_US fails with status %s\n", myErrorName(status)); 2725 } 2726 } 2727 2728 2729 typedef struct { 2730 double value; 2731 const char *expected; 2732 } ValueAndExpectedString; 2733 2734 static const ValueAndExpectedString enShort[] = { 2735 {0.0, "0"}, 2736 {0.17, "0.17"}, 2737 {1.0, "1"}, 2738 {1234.0, "1.23K"}, 2739 {12345.0, "12.3K"}, 2740 {123456.0, "123K"}, 2741 {1234567.0, "1.23M"}, 2742 {12345678.0, "12.3M"}, 2743 {123456789.0, "123M"}, 2744 {1.23456789E9, "1.23B"}, 2745 {1.23456789E10, "12.3B"}, 2746 {1.23456789E11, "123B"}, 2747 {1.23456789E12, "1.23T"}, 2748 {1.23456789E13, "12.3T"}, 2749 {1.23456789E14, "123T"}, 2750 {1.23456789E15, "1230T"}, 2751 {0.0, NULL} 2752 }; 2753 2754 static const ValueAndExpectedString enShortMax2[] = { 2755 {0.0, "0"}, 2756 {0.17, "0.17"}, 2757 {1.0, "1"}, 2758 {1234.0, "1.2K"}, 2759 {12345.0, "12K"}, 2760 {123456.0, "120K"}, 2761 {1234567.0, "1.2M"}, 2762 {12345678.0, "12M"}, 2763 {123456789.0, "120M"}, 2764 {1.23456789E9, "1.2B"}, 2765 {1.23456789E10, "12B"}, 2766 {1.23456789E11, "120B"}, 2767 {1.23456789E12, "1.2T"}, 2768 {1.23456789E13, "12T"}, 2769 {1.23456789E14, "120T"}, 2770 {1.23456789E15, "1200T"}, 2771 {0.0, NULL} 2772 }; 2773 2774 static const ValueAndExpectedString enShortMax5[] = { 2775 {0.0, "0"}, 2776 {0.17, "0.17"}, 2777 {1.0, "1"}, 2778 {1234.0, "1.234K"}, 2779 {12345.0, "12.345K"}, 2780 {123456.0, "123.46K"}, 2781 {1234567.0, "1.2346M"}, 2782 {12345678.0, "12.346M"}, 2783 {123456789.0, "123.46M"}, 2784 {1.23456789E9, "1.2346B"}, 2785 {1.23456789E10, "12.346B"}, 2786 {1.23456789E11, "123.46B"}, 2787 {1.23456789E12, "1.2346T"}, 2788 {1.23456789E13, "12.346T"}, 2789 {1.23456789E14, "123.46T"}, 2790 {1.23456789E15, "1234.6T"}, 2791 {0.0, NULL} 2792 }; 2793 2794 static const ValueAndExpectedString enShortMin3[] = { 2795 {0.0, "0.00"}, 2796 {0.17, "0.170"}, 2797 {1.0, "1.00"}, 2798 {1234.0, "1.23K"}, 2799 {12345.0, "12.3K"}, 2800 {123456.0, "123K"}, 2801 {1234567.0, "1.23M"}, 2802 {12345678.0, "12.3M"}, 2803 {123456789.0, "123M"}, 2804 {1.23456789E9, "1.23B"}, 2805 {1.23456789E10, "12.3B"}, 2806 {1.23456789E11, "123B"}, 2807 {1.23456789E12, "1.23T"}, 2808 {1.23456789E13, "12.3T"}, 2809 {1.23456789E14, "123T"}, 2810 {1.23456789E15, "1230T"}, 2811 {0.0, NULL} 2812 }; 2813 2814 static const ValueAndExpectedString jaShortMax2[] = { 2815 {1234.0, "1200"}, 2816 {12345.0, "1.2\\u4E07"}, 2817 {123456.0, "12\\u4E07"}, 2818 {1234567.0, "120\\u4E07"}, 2819 {12345678.0, "1200\\u4E07"}, 2820 {123456789.0, "1.2\\u5104"}, 2821 {1.23456789E9, "12\\u5104"}, 2822 {1.23456789E10, "120\\u5104"}, 2823 {1.23456789E11, "1200\\u5104"}, 2824 {1.23456789E12, "1.2\\u5146"}, 2825 {1.23456789E13, "12\\u5146"}, 2826 {1.23456789E14, "120\\u5146"}, 2827 {0.0, NULL} 2828 }; 2829 2830 static const ValueAndExpectedString srLongMax2[] = { 2831 {1234.0, "1,2 \\u0445\\u0438\\u0459\\u0430\\u0434\\u0435"}, // 10^3 few 2832 {12345.0, "12 \\u0445\\u0438\\u0459\\u0430\\u0434\\u0430"}, // 10^3 other 2833 {21789.0, "22 \\u0445\\u0438\\u0459\\u0430\\u0434\\u0435"}, // 10^3 few 2834 {123456.0, "120 \\u0445\\u0438\\u0459\\u0430\\u0434\\u0430"}, // 10^3 other 2835 {999999.0, "1 \\u043C\\u0438\\u043B\\u0438\\u043E\\u043D"}, // 10^6 one 2836 {1234567.0, "1,2 \\u043C\\u0438\\u043B\\u0438\\u043E\\u043D\\u0430"}, // 10^6 few 2837 {12345678.0, "12 \\u043C\\u0438\\u043B\\u0438\\u043E\\u043D\\u0430"}, // 10^6 other 2838 {123456789.0, "120 \\u043C\\u0438\\u043B\\u0438\\u043E\\u043D\\u0430"}, // 10^6 other 2839 {1.23456789E9, "1,2 \\u043C\\u0438\\u043B\\u0438\\u0458\\u0430\\u0440\\u0434\\u0435"}, // 10^9 few 2840 {1.23456789E10, "12 \\u043C\\u0438\\u043B\\u0438\\u0458\\u0430\\u0440\\u0434\\u0438"}, // 10^9 other 2841 {2.08901234E10, "21 \\u043C\\u0438\\u043B\\u0438\\u0458\\u0430\\u0440\\u0434\\u0430"}, // 10^9 one 2842 {2.18901234E10, "22 \\u043C\\u0438\\u043B\\u0438\\u0458\\u0430\\u0440\\u0434\\u0435"}, // 10^9 few 2843 {1.23456789E11, "120 \\u043C\\u0438\\u043B\\u0438\\u0458\\u0430\\u0440\\u0434\\u0438"}, // 10^9 other 2844 {-1234.0, "-1,2 \\u0445\\u0438\\u0459\\u0430\\u0434\\u0435"}, 2845 {-12345.0, "-12 \\u0445\\u0438\\u0459\\u0430\\u0434\\u0430"}, 2846 {-21789.0, "-22 \\u0445\\u0438\\u0459\\u0430\\u0434\\u0435"}, 2847 {-123456.0, "-120 \\u0445\\u0438\\u0459\\u0430\\u0434\\u0430"}, 2848 {-999999.0, "-1 \\u043C\\u0438\\u043B\\u0438\\u043E\\u043D"}, 2849 {-1234567.0, "-1,2 \\u043C\\u0438\\u043B\\u0438\\u043E\\u043D\\u0430"}, 2850 {-12345678.0, "-12 \\u043C\\u0438\\u043B\\u0438\\u043E\\u043D\\u0430"}, 2851 {-123456789.0, "-120 \\u043C\\u0438\\u043B\\u0438\\u043E\\u043D\\u0430"}, 2852 {-1.23456789E9, "-1,2 \\u043C\\u0438\\u043B\\u0438\\u0458\\u0430\\u0440\\u0434\\u0435"}, 2853 {-1.23456789E10, "-12 \\u043C\\u0438\\u043B\\u0438\\u0458\\u0430\\u0440\\u0434\\u0438"}, 2854 {-2.08901234E10, "-21 \\u043C\\u0438\\u043B\\u0438\\u0458\\u0430\\u0440\\u0434\\u0430"}, 2855 {-2.18901234E10, "-22 \\u043C\\u0438\\u043B\\u0438\\u0458\\u0430\\u0440\\u0434\\u0435"}, 2856 {-1.23456789E11, "-120 \\u043C\\u0438\\u043B\\u0438\\u0458\\u0430\\u0440\\u0434\\u0438"}, 2857 {0.0, NULL} 2858 }; 2859 2860 typedef struct { 2861 const char * locale; 2862 UNumberFormatStyle style; 2863 int32_t attribute; // UNumberFormatAttribute, or -1 for none 2864 int32_t attrValue; // 2865 const ValueAndExpectedString * veItems; 2866 } LocStyleAttributeTest; 2867 2868 static const LocStyleAttributeTest lsaTests[] = { 2869 { "en", UNUM_DECIMAL_COMPACT_SHORT, -1, 0, enShort }, 2870 { "en", UNUM_DECIMAL_COMPACT_SHORT, UNUM_MAX_SIGNIFICANT_DIGITS, 2, enShortMax2 }, 2871 { "en", UNUM_DECIMAL_COMPACT_SHORT, UNUM_MAX_SIGNIFICANT_DIGITS, 5, enShortMax5 }, 2872 { "en", UNUM_DECIMAL_COMPACT_SHORT, UNUM_MIN_SIGNIFICANT_DIGITS, 3, enShortMin3 }, 2873 { "ja", UNUM_DECIMAL_COMPACT_SHORT, UNUM_MAX_SIGNIFICANT_DIGITS, 2, jaShortMax2 }, 2874 { "sr", UNUM_DECIMAL_COMPACT_LONG, UNUM_MAX_SIGNIFICANT_DIGITS, 2, srLongMax2 }, 2875 { NULL, (UNumberFormatStyle)0, -1, 0, NULL } 2876 }; 2877 2878 static void TestVariousStylesAndAttributes(void) { 2879 const LocStyleAttributeTest * lsaTestPtr; 2880 for (lsaTestPtr = lsaTests; lsaTestPtr->locale != NULL; lsaTestPtr++) { 2881 UErrorCode status = U_ZERO_ERROR; 2882 UNumberFormat * unum = unum_open(lsaTestPtr->style, NULL, 0, lsaTestPtr->locale, NULL, &status); 2883 if ( U_FAILURE(status) ) { 2884 log_data_err("FAIL: unum_open style %d, locale %s: error %s\n", (int)lsaTestPtr->style, lsaTestPtr->locale, u_errorName(status)); 2885 } else { 2886 const ValueAndExpectedString * veItemPtr; 2887 if (lsaTestPtr->attribute >= 0) { 2888 unum_setAttribute(unum, (UNumberFormatAttribute)lsaTestPtr->attribute, lsaTestPtr->attrValue); 2889 } 2890 for (veItemPtr = lsaTestPtr->veItems; veItemPtr->expected != NULL; veItemPtr++) { 2891 UChar uexp[kUBufSize]; 2892 UChar uget[kUBufSize]; 2893 int32_t uexplen, ugetlen; 2894 2895 status = U_ZERO_ERROR; 2896 uexplen = u_unescape(veItemPtr->expected, uexp, kUBufSize); 2897 ugetlen = unum_formatDouble(unum, veItemPtr->value, uget, kUBufSize, NULL, &status); 2898 if ( U_FAILURE(status) ) { 2899 log_err("FAIL: unum_formatDouble style %d, locale %s, attr %d, value %.2f: error %s\n", 2900 (int)lsaTestPtr->style, lsaTestPtr->locale, lsaTestPtr->attribute, veItemPtr->value, u_errorName(status)); 2901 } else if (ugetlen != uexplen || u_strncmp(uget, uexp, uexplen) != 0) { 2902 char bexp[kBBufSize]; 2903 char bget[kBBufSize]; 2904 u_strToUTF8(bexp, kBBufSize, NULL, uexp, uexplen, &status); 2905 u_strToUTF8(bget, kBBufSize, NULL, uget, ugetlen, &status); 2906 log_err("FAIL: unum_formatDouble style %d, locale %s, attr %d, value %.2f: expect \"%s\", get \"%s\"\n", 2907 (int)lsaTestPtr->style, lsaTestPtr->locale, lsaTestPtr->attribute, veItemPtr->value, bexp, bget); 2908 } 2909 } 2910 unum_close(unum); 2911 } 2912 } 2913 } 2914 2915 static const UChar currpat[] = { 0xA4,0x23,0x2C,0x23,0x23,0x30,0x2E,0x30,0x30,0}; 2916 static const UChar parsetxt[] = { 0x78,0x30,0x79,0x24,0 }; /* x0y$ */ 2917 2918 static void TestParseCurrPatternWithDecStyle() { 2919 UErrorCode status = U_ZERO_ERROR; 2920 UNumberFormat *unumfmt = unum_open(UNUM_DECIMAL, NULL, 0, "en_US", NULL, &status); 2921 if (U_FAILURE(status)) { 2922 log_data_err("unum_open DECIMAL failed for en_US: %s (Are you missing data?)\n", u_errorName(status)); 2923 } else { 2924 unum_applyPattern(unumfmt, FALSE, currpat, -1, NULL, &status); 2925 if (U_FAILURE(status)) { 2926 log_err_status(status, "unum_applyPattern failed: %s\n", u_errorName(status)); 2927 } else { 2928 int32_t pos = 0; 2929 double value = unum_parseDouble(unumfmt, parsetxt, -1, &pos, &status); 2930 if (U_SUCCESS(status)) { 2931 log_err_status(status, "unum_parseDouble expected to fail but got status %s, value %f\n", u_errorName(status), value); 2932 } 2933 } 2934 unum_close(unumfmt); 2935 } 2936 } 2937 2938 /* 2939 * Ticket #12684 2940 * Test unum_formatDoubleForFields (and UFieldPositionIterator) 2941 */ 2942 2943 typedef struct { 2944 int32_t field; 2945 int32_t beginPos; 2946 int32_t endPos; 2947 } FieldsData; 2948 2949 typedef struct { 2950 const char * locale; 2951 UNumberFormatStyle style; 2952 double value; 2953 const FieldsData * expectedFields; 2954 } FormatForFieldsItem; 2955 2956 static const UChar patNoFields[] = { 0x0027, 0x0078, 0x0027, 0 }; /* "'x'", for UNUM_PATTERN_DECIMAL */ 2957 2958 2959 /* "en_US", UNUM_CURRENCY, 123456.0 : "#,##0.00" => "$123,456.00" */ 2960 static const FieldsData fields_en_CURR[] = { 2961 { UNUM_CURRENCY_FIELD /*7*/, 0, 1 }, 2962 { UNUM_GROUPING_SEPARATOR_FIELD /*6*/, 4, 5 }, 2963 { UNUM_INTEGER_FIELD /*0*/, 1, 8 }, 2964 { UNUM_DECIMAL_SEPARATOR_FIELD /*2*/, 8, 9 }, 2965 { UNUM_FRACTION_FIELD /*1*/, 9, 11 }, 2966 { -1, -1, -1 }, 2967 }; 2968 /* "en_US", UNUM_PERCENT, -34 : "#,##0%" => "-34%" */ 2969 static const FieldsData fields_en_PRCT[] = { 2970 { UNUM_SIGN_FIELD /*10*/, 0, 1 }, 2971 { UNUM_INTEGER_FIELD /*0*/, 1, 3 }, 2972 { UNUM_PERCENT_FIELD /*8*/, 3, 4 }, 2973 { -1, -1, -1 }, 2974 }; 2975 /* "fr_FR", UNUM_CURRENCY, 123456.0 : "#,##0.00" => "123,456.00 " */ 2976 static const FieldsData fields_fr_CURR[] = { 2977 { UNUM_GROUPING_SEPARATOR_FIELD /*6*/, 3, 4 }, 2978 { UNUM_INTEGER_FIELD /*0*/, 0, 7 }, 2979 { UNUM_DECIMAL_SEPARATOR_FIELD /*2*/, 7, 8 }, 2980 { UNUM_FRACTION_FIELD /*1*/, 8, 10 }, 2981 { UNUM_CURRENCY_FIELD /*7*/, 11, 12 }, 2982 { -1, -1, -1 }, 2983 }; 2984 /* "en_US", UNUM_PATTERN_DECIMAL, 12.0 : "'x'" => "x12" */ 2985 static const FieldsData fields_en_PATN[] = { 2986 { UNUM_INTEGER_FIELD /*0*/, 1, 3 }, 2987 { -1, -1, -1 }, 2988 }; 2989 2990 static const FormatForFieldsItem fffItems[] = { 2991 { "en_US", UNUM_CURRENCY_STANDARD, 123456.0, fields_en_CURR }, 2992 { "en_US", UNUM_PERCENT, -0.34, fields_en_PRCT }, 2993 { "fr_FR", UNUM_CURRENCY_STANDARD, 123456.0, fields_fr_CURR }, 2994 { "en_US", UNUM_PATTERN_DECIMAL, 12.0, fields_en_PATN }, 2995 { NULL, (UNumberFormatStyle)0, 0, NULL }, 2996 }; 2997 2998 static void TestFormatForFields(void) { 2999 UErrorCode status = U_ZERO_ERROR; 3000 UFieldPositionIterator* fpositer = ufieldpositer_open(&status); 3001 if ( U_FAILURE(status) ) { 3002 log_err("ufieldpositer_open fails, status %s\n", u_errorName(status)); 3003 } else { 3004 const FormatForFieldsItem * itemPtr; 3005 for (itemPtr = fffItems; itemPtr->locale != NULL; itemPtr++) { 3006 UNumberFormat* unum; 3007 status = U_ZERO_ERROR; 3008 unum = (itemPtr->style == UNUM_PATTERN_DECIMAL)? 3009 unum_open(itemPtr->style, patNoFields, -1, itemPtr->locale, NULL, &status): 3010 unum_open(itemPtr->style, NULL, 0, itemPtr->locale, NULL, &status); 3011 if ( U_FAILURE(status) ) { 3012 log_data_err("unum_open fails for locale %s, style %d: status %s (Are you missing data?)\n", itemPtr->locale, itemPtr->style, u_errorName(status)); 3013 } else { 3014 UChar ubuf[kUBufSize]; 3015 int32_t ulen = unum_formatDoubleForFields(unum, itemPtr->value, ubuf, kUBufSize, fpositer, &status); 3016 if ( U_FAILURE(status) ) { 3017 log_err("unum_formatDoubleForFields fails for locale %s, style %d: status %s\n", itemPtr->locale, itemPtr->style, u_errorName(status)); 3018 } else { 3019 const FieldsData * fptr; 3020 int32_t field, beginPos, endPos; 3021 for (fptr = itemPtr->expectedFields; TRUE; fptr++) { 3022 field = ufieldpositer_next(fpositer, &beginPos, &endPos); 3023 if (field != fptr->field || (field >= 0 && (beginPos != fptr->beginPos || endPos != fptr->endPos))) { 3024 if (fptr->field >= 0) { 3025 log_err("unum_formatDoubleForFields for locale %s as \"%s\"; expect field %d range %d-%d, get field %d range %d-%d\n", 3026 itemPtr->locale, aescstrdup(ubuf, ulen), fptr->field, fptr->beginPos, fptr->endPos, field, beginPos, endPos); 3027 } else { 3028 log_err("unum_formatDoubleForFields for locale %s as \"%s\"; expect field < 0, get field %d range %d-%d\n", 3029 itemPtr->locale, aescstrdup(ubuf, ulen), field, beginPos, endPos); 3030 } 3031 break; 3032 } 3033 if (field < 0) { 3034 break; 3035 } 3036 } 3037 } 3038 unum_close(unum); 3039 } 3040 } 3041 ufieldpositer_close(fpositer); 3042 } 3043 } 3044 3045 #endif /* #if !UCONFIG_NO_FORMATTING */ 3046