1 /******************************************************************** 2 * COPYRIGHT: 3 * Copyright (c) 1997-2011, International Business Machines Corporation and 4 * others. All Rights Reserved. 5 ********************************************************************/ 6 /******************************************************************************** 7 * 8 * File CNUMTST.C 9 * 10 * Madhu Katragadda Creation 11 * 12 * Modification History: 13 * 14 * Date Name Description 15 * 06/24/99 helena Integrated Alan's NF enhancements and Java2 bug fixes 16 * 07/15/99 helena Ported to HPUX 10/11 CC. 17 ********************************************************************************* 18 */ 19 20 /* C API TEST FOR NUMBER FORMAT */ 21 22 #include "unicode/utypes.h" 23 24 #if !UCONFIG_NO_FORMATTING 25 26 #include "unicode/uloc.h" 27 #include "unicode/umisc.h" 28 #include "unicode/unum.h" 29 #include "unicode/ustring.h" 30 31 #include "cintltst.h" 32 #include "cnumtst.h" 33 #include "cmemory.h" 34 #include "putilimp.h" 35 36 #define LENGTH(arr) (sizeof(arr)/sizeof(arr[0])) 37 38 void addNumForTest(TestNode** root); 39 static void TestTextAttributeCrash(void); 40 static void TestNBSPInPattern(void); 41 static void TestInt64Parse(void); 42 static void TestParseCurrency(void); 43 44 #define TESTCASE(x) addTest(root, &x, "tsformat/cnumtst/" #x) 45 46 void addNumForTest(TestNode** root) 47 { 48 TESTCASE(TestNumberFormat); 49 TESTCASE(TestSpelloutNumberParse); 50 TESTCASE(TestSignificantDigits); 51 TESTCASE(TestSigDigRounding); 52 TESTCASE(TestNumberFormatPadding); 53 TESTCASE(TestInt64Format); 54 TESTCASE(TestNonExistentCurrency); 55 TESTCASE(TestCurrencyRegression); 56 TESTCASE(TestTextAttributeCrash); 57 TESTCASE(TestRBNFFormat); 58 TESTCASE(TestNBSPInPattern); 59 TESTCASE(TestInt64Parse); 60 TESTCASE(TestParseZero); 61 TESTCASE(TestParseCurrency); 62 } 63 64 /** copy src to dst with unicode-escapes for values < 0x20 and > 0x7e, null terminate if possible */ 65 static int32_t ustrToAstr(const UChar* src, int32_t srcLength, char* dst, int32_t dstLength) { 66 static const char hex[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; 67 68 char *p = dst; 69 const char *e = p + dstLength; 70 if (srcLength < 0) { 71 const UChar* s = src; 72 while (*s) { 73 ++s; 74 } 75 srcLength = (int32_t)(s - src); 76 } 77 while (p < e && --srcLength >= 0) { 78 UChar c = *src++; 79 if (c == 0xd || c == 0xa || c == 0x9 || (c>= 0x20 && c <= 0x7e)) { 80 *p++ = (char) c & 0x7f; 81 } else if (e - p >= 6) { 82 *p++ = '\\'; 83 *p++ = 'u'; 84 *p++ = hex[(c >> 12) & 0xf]; 85 *p++ = hex[(c >> 8) & 0xf]; 86 *p++ = hex[(c >> 4) & 0xf]; 87 *p++ = hex[c & 0xf]; 88 } else { 89 break; 90 } 91 } 92 if (p < e) { 93 *p = 0; 94 } 95 return (int32_t)(p - dst); 96 } 97 98 /* test Parse int 64 */ 99 100 static void TestInt64Parse() 101 { 102 103 UErrorCode st = U_ZERO_ERROR; 104 UErrorCode* status = &st; 105 106 const char* st1 = "009223372036854775808"; 107 const int size = 21; 108 UChar text[21]; 109 110 111 UNumberFormat* nf; 112 113 int64_t a; 114 115 u_charsToUChars(st1, text, size); 116 nf = unum_open(UNUM_DEFAULT, NULL, -1, NULL, NULL, status); 117 118 if(U_FAILURE(*status)) 119 { 120 log_data_err("Error in unum_open() %s \n", myErrorName(*status)); 121 return; 122 } 123 124 log_verbose("About to test unum_parseInt64() with out of range number\n"); 125 126 a = unum_parseInt64(nf, text, size, 0, status); 127 128 129 if(!U_FAILURE(*status)) 130 { 131 log_err("Error in unum_parseInt64(): %s \n", myErrorName(*status)); 132 } 133 else 134 { 135 log_verbose("unum_parseInt64() successful\n"); 136 } 137 138 unum_close(nf); 139 return; 140 } 141 142 /* test Number Format API */ 143 static void TestNumberFormat() 144 { 145 UChar *result=NULL; 146 UChar temp1[512]; 147 UChar temp2[512]; 148 149 UChar temp[5]; 150 151 UChar prefix[5]; 152 UChar suffix[5]; 153 UChar symbol[20]; 154 int32_t resultlength; 155 int32_t resultlengthneeded; 156 int32_t parsepos; 157 double d1 = -1.0; 158 int32_t l1; 159 double d = -10456.37; 160 double a = 1234.56, a1 = 1235.0; 161 int32_t l = 100000000; 162 UFieldPosition pos1; 163 UFieldPosition pos2; 164 int32_t numlocales; 165 int32_t i; 166 167 UNumberFormatAttribute attr; 168 UNumberFormatSymbol symType = UNUM_DECIMAL_SEPARATOR_SYMBOL; 169 int32_t newvalue; 170 UErrorCode status=U_ZERO_ERROR; 171 UNumberFormatStyle style= UNUM_DEFAULT; 172 UNumberFormat *pattern; 173 UNumberFormat *def, *fr, *cur_def, *cur_fr, *per_def, *per_fr, 174 *cur_frpattern, *myclone, *spellout_def; 175 176 /* Testing unum_open() with various Numberformat styles and locales*/ 177 status = U_ZERO_ERROR; 178 log_verbose("Testing unum_open() with default style and locale\n"); 179 def=unum_open(style, NULL,0,NULL, NULL,&status); 180 181 /* Might as well pack it in now if we can't even get a default NumberFormat... */ 182 if(U_FAILURE(status)) 183 { 184 log_data_err("Error in creating default NumberFormat using unum_open(): %s (Are you missing data?)\n", myErrorName(status)); 185 return; 186 } 187 188 log_verbose("\nTesting unum_open() with french locale and default style(decimal)\n"); 189 fr=unum_open(style,NULL,0, "fr_FR",NULL, &status); 190 if(U_FAILURE(status)) 191 log_err("Error: could not create NumberFormat (french): %s\n", myErrorName(status)); 192 193 log_verbose("\nTesting unum_open(currency,NULL,status)\n"); 194 style=UNUM_CURRENCY; 195 /* Can't hardcode the result to assume the default locale is "en_US". */ 196 cur_def=unum_open(style, NULL,0,"en_US", NULL, &status); 197 if(U_FAILURE(status)) 198 log_err("Error: could not create NumberFormat using \n unum_open(currency, NULL, &status) %s\n", 199 myErrorName(status) ); 200 201 log_verbose("\nTesting unum_open(currency, frenchlocale, status)\n"); 202 cur_fr=unum_open(style,NULL,0, "fr_FR", NULL, &status); 203 if(U_FAILURE(status)) 204 log_err("Error: could not create NumberFormat using unum_open(currency, french, &status): %s\n", 205 myErrorName(status)); 206 207 log_verbose("\nTesting unum_open(percent, NULL, status)\n"); 208 style=UNUM_PERCENT; 209 per_def=unum_open(style,NULL,0, NULL,NULL, &status); 210 if(U_FAILURE(status)) 211 log_err("Error: could not create NumberFormat using unum_open(percent, NULL, &status): %s\n", myErrorName(status)); 212 213 log_verbose("\nTesting unum_open(percent,frenchlocale, status)\n"); 214 per_fr=unum_open(style, NULL,0,"fr_FR", NULL,&status); 215 if(U_FAILURE(status)) 216 log_err("Error: could not create NumberFormat using unum_open(percent, french, &status): %s\n", myErrorName(status)); 217 218 log_verbose("\nTesting unum_open(spellout, NULL, status)"); 219 style=UNUM_SPELLOUT; 220 spellout_def=unum_open(style, NULL, 0, "en_US", NULL, &status); 221 if(U_FAILURE(status)) 222 log_err("Error: could not create NumberFormat using unum_open(spellout, NULL, &status): %s\n", myErrorName(status)); 223 224 /* Testing unum_clone(..) */ 225 log_verbose("\nTesting unum_clone(fmt, status)"); 226 status = U_ZERO_ERROR; 227 myclone = unum_clone(def,&status); 228 if(U_FAILURE(status)) 229 log_err("Error: could not clone unum_clone(def, &status): %s\n", myErrorName(status)); 230 else 231 { 232 log_verbose("unum_clone() successful\n"); 233 } 234 235 /*Testing unum_getAvailable() and unum_countAvailable()*/ 236 log_verbose("\nTesting getAvailableLocales and countAvailable()\n"); 237 numlocales=unum_countAvailable(); 238 if(numlocales < 0) 239 log_err("error in countAvailable"); 240 else{ 241 log_verbose("unum_countAvialable() successful\n"); 242 log_verbose("The no: of locales where number formattting is applicable is %d\n", numlocales); 243 } 244 for(i=0;i<numlocales;i++) 245 { 246 log_verbose("%s\n", unum_getAvailable(i)); 247 if (unum_getAvailable(i) == 0) 248 log_err("No locale for which number formatting patterns are applicable\n"); 249 else 250 log_verbose("A locale %s for which number formatting patterns are applicable\n",unum_getAvailable(i)); 251 } 252 253 254 /*Testing unum_format() and unum_formatdouble()*/ 255 u_uastrcpy(temp1, "$100,000,000.00"); 256 257 log_verbose("\nTesting unum_format() \n"); 258 resultlength=0; 259 pos1.field = 0; /* Integer Section */ 260 resultlengthneeded=unum_format(cur_def, l, NULL, resultlength, &pos1, &status); 261 if(status==U_BUFFER_OVERFLOW_ERROR) 262 { 263 status=U_ZERO_ERROR; 264 resultlength=resultlengthneeded+1; 265 result=(UChar*)malloc(sizeof(UChar) * resultlength); 266 /* for (i = 0; i < 100000; i++) */ 267 { 268 unum_format(cur_def, l, result, resultlength, &pos1, &status); 269 } 270 } 271 272 if(U_FAILURE(status)) 273 { 274 log_err("Error in formatting using unum_format(.....): %s\n", myErrorName(status) ); 275 } 276 if(u_strcmp(result, temp1)==0) 277 log_verbose("Pass: Number formatting using unum_format() successful\n"); 278 else 279 log_err("Fail: Error in number Formatting using unum_format()\n"); 280 if(pos1.beginIndex == 1 && pos1.endIndex == 12) 281 log_verbose("Pass: Complete number formatting using unum_format() successful\n"); 282 else 283 log_err("Fail: Error in complete number Formatting using unum_format()\nGot: b=%d end=%d\nExpected: b=1 end=12\n", 284 pos1.beginIndex, pos1.endIndex); 285 286 free(result); 287 result = 0; 288 289 log_verbose("\nTesting unum_formatDouble()\n"); 290 u_uastrcpy(temp1, "($10,456.37)"); 291 resultlength=0; 292 pos2.field = 1; /* Fractional Section */ 293 resultlengthneeded=unum_formatDouble(cur_def, d, NULL, resultlength, &pos2, &status); 294 if(status==U_BUFFER_OVERFLOW_ERROR) 295 { 296 status=U_ZERO_ERROR; 297 resultlength=resultlengthneeded+1; 298 result=(UChar*)malloc(sizeof(UChar) * resultlength); 299 /* for (i = 0; i < 100000; i++) */ 300 { 301 unum_formatDouble(cur_def, d, result, resultlength, &pos2, &status); 302 } 303 } 304 if(U_FAILURE(status)) 305 { 306 log_err("Error in formatting using unum_formatDouble(.....): %s\n", myErrorName(status)); 307 } 308 if(result && u_strcmp(result, temp1)==0) 309 log_verbose("Pass: Number Formatting using unum_formatDouble() Successful\n"); 310 else 311 log_err("FAIL: Error in number formatting using unum_formatDouble()\n"); 312 if(pos2.beginIndex == 9 && pos2.endIndex == 11) 313 log_verbose("Pass: Complete number formatting using unum_format() successful\n"); 314 else 315 log_err("Fail: Error in complete number Formatting using unum_formatDouble()\nGot: b=%d end=%d\nExpected: b=9 end=11", 316 pos1.beginIndex, pos1.endIndex); 317 318 319 /* Testing unum_parse() and unum_parseDouble() */ 320 log_verbose("\nTesting unum_parseDouble()\n"); 321 /* for (i = 0; i < 100000; i++)*/ 322 if (result != NULL) 323 { 324 parsepos=0; 325 d1=unum_parseDouble(cur_def, result, u_strlen(result), &parsepos, &status); 326 } 327 else { 328 log_err("result is NULL\n"); 329 } 330 if(U_FAILURE(status)) 331 { 332 log_err("parse failed. The error is : %s\n", myErrorName(status)); 333 } 334 335 if(d1!=d) 336 log_err("Fail: Error in parsing\n"); 337 else 338 log_verbose("Pass: parsing successful\n"); 339 if (result) 340 free(result); 341 result = 0; 342 343 344 /* Testing unum_formatDoubleCurrency / unum_parseDoubleCurrency */ 345 log_verbose("\nTesting unum_formatDoubleCurrency\n"); 346 u_uastrcpy(temp1, "Y1,235"); 347 temp1[0] = 0xA5; /* Yen sign */ 348 u_uastrcpy(temp, "JPY"); 349 resultlength=0; 350 pos2.field = 0; /* integer part */ 351 resultlengthneeded=unum_formatDoubleCurrency(cur_def, a, temp, NULL, resultlength, &pos2, &status); 352 if (status==U_BUFFER_OVERFLOW_ERROR) { 353 status=U_ZERO_ERROR; 354 resultlength=resultlengthneeded+1; 355 result=(UChar*)malloc(sizeof(UChar) * resultlength); 356 unum_formatDoubleCurrency(cur_def, a, temp, result, resultlength, &pos2, &status); 357 } 358 if (U_FAILURE(status)) { 359 log_err("Error in formatting using unum_formatDouble(.....): %s\n", myErrorName(status)); 360 } 361 if (result && u_strcmp(result, temp1)==0) { 362 log_verbose("Pass: Number Formatting using unum_formatDouble() Successful\n"); 363 } else { 364 log_err("FAIL: Error in number formatting using unum_formatDouble()\n"); 365 } 366 if (pos2.beginIndex == 1 && pos2.endIndex == 6) { 367 log_verbose("Pass: Complete number formatting using unum_format() successful\n"); 368 } else { 369 log_err("Fail: Error in complete number Formatting using unum_formatDouble()\nGot: b=%d end=%d\nExpected: b=1 end=6\n", 370 pos1.beginIndex, pos1.endIndex); 371 } 372 373 log_verbose("\nTesting unum_parseDoubleCurrency\n"); 374 parsepos=0; 375 if (result == NULL) { 376 log_err("result is NULL\n"); 377 } 378 else { 379 d1=unum_parseDoubleCurrency(cur_def, result, u_strlen(result), &parsepos, temp2, &status); 380 if (U_FAILURE(status)) { 381 log_err("parse failed. The error is : %s\n", myErrorName(status)); 382 } 383 /* Note: a==1234.56, but on parse expect a1=1235.0 */ 384 if (d1!=a1) { 385 log_err("Fail: Error in parsing currency, got %f, expected %f\n", d1, a1); 386 } else { 387 log_verbose("Pass: parsed currency ammount successfully\n"); 388 } 389 if (u_strcmp(temp2, temp)==0) { 390 log_verbose("Pass: parsed correct currency\n"); 391 } else { 392 log_err("Fail: parsed incorrect currency\n"); 393 } 394 } 395 396 free(result); 397 result = 0; 398 399 400 /* performance testing */ 401 u_uastrcpy(temp1, "$462.12345"); 402 resultlength=u_strlen(temp1); 403 /* for (i = 0; i < 100000; i++) */ 404 { 405 parsepos=0; 406 d1=unum_parseDouble(cur_def, temp1, resultlength, &parsepos, &status); 407 } 408 if(U_FAILURE(status)) 409 { 410 log_err("parse failed. The error is : %s\n", myErrorName(status)); 411 } 412 413 /* 414 * Note: "for strict standard conformance all operations and constants are now supposed to be 415 evaluated in precision of long double". So, we assign a1 before comparing to a double. Bug #7932. 416 */ 417 a1 = 462.12345; 418 419 if(d1!=a1) 420 log_err("Fail: Error in parsing\n"); 421 else 422 log_verbose("Pass: parsing successful\n"); 423 424 free(result); 425 426 u_uastrcpy(temp1, "($10,456.3E1])"); 427 parsepos=0; 428 d1=unum_parseDouble(cur_def, temp1, u_strlen(temp1), &parsepos, &status); 429 if(U_SUCCESS(status)) 430 { 431 log_err("Error in unum_parseDouble(..., %s, ...): %s\n", temp1, myErrorName(status)); 432 } 433 434 435 log_verbose("\nTesting unum_format()\n"); 436 status=U_ZERO_ERROR; 437 resultlength=0; 438 parsepos=0; 439 resultlengthneeded=unum_format(per_fr, l, NULL, resultlength, &pos1, &status); 440 if(status==U_BUFFER_OVERFLOW_ERROR) 441 { 442 status=U_ZERO_ERROR; 443 resultlength=resultlengthneeded+1; 444 result=(UChar*)malloc(sizeof(UChar) * resultlength); 445 /* for (i = 0; i < 100000; i++)*/ 446 { 447 unum_format(per_fr, l, result, resultlength, &pos1, &status); 448 } 449 } 450 if(U_FAILURE(status)) 451 { 452 log_err("Error in formatting using unum_format(.....): %s\n", myErrorName(status)); 453 } 454 455 456 log_verbose("\nTesting unum_parse()\n"); 457 /* for (i = 0; i < 100000; i++) */ 458 { 459 parsepos=0; 460 l1=unum_parse(per_fr, result, u_strlen(result), &parsepos, &status); 461 } 462 if(U_FAILURE(status)) 463 { 464 log_err("parse failed. The error is : %s\n", myErrorName(status)); 465 } 466 467 if(l1!=l) 468 log_err("Fail: Error in parsing\n"); 469 else 470 log_verbose("Pass: parsing successful\n"); 471 472 free(result); 473 474 /* create a number format using unum_openPattern(....)*/ 475 log_verbose("\nTesting unum_openPattern()\n"); 476 u_uastrcpy(temp1, "#,##0.0#;(#,##0.0#)"); 477 pattern=unum_open(UNUM_IGNORE,temp1, u_strlen(temp1), NULL, NULL,&status); 478 if(U_FAILURE(status)) 479 { 480 log_err("error in unum_openPattern(): %s\n", myErrorName(status) );; 481 } 482 else 483 log_verbose("Pass: unum_openPattern() works fine\n"); 484 485 /*test for unum_toPattern()*/ 486 log_verbose("\nTesting unum_toPattern()\n"); 487 resultlength=0; 488 resultlengthneeded=unum_toPattern(pattern, FALSE, NULL, resultlength, &status); 489 if(status==U_BUFFER_OVERFLOW_ERROR) 490 { 491 status=U_ZERO_ERROR; 492 resultlength=resultlengthneeded+1; 493 result=(UChar*)malloc(sizeof(UChar) * resultlength); 494 unum_toPattern(pattern, FALSE, result, resultlength, &status); 495 } 496 if(U_FAILURE(status)) 497 { 498 log_err("error in extracting the pattern from UNumberFormat: %s\n", myErrorName(status)); 499 } 500 else 501 { 502 if(u_strcmp(result, temp1)!=0) 503 log_err("FAIL: Error in extracting the pattern using unum_toPattern()\n"); 504 else 505 log_verbose("Pass: extracted the pattern correctly using unum_toPattern()\n"); 506 free(result); 507 } 508 509 /*Testing unum_getSymbols() and unum_setSymbols()*/ 510 log_verbose("\nTesting unum_getSymbols and unum_setSymbols()\n"); 511 /*when we try to change the symbols of french to default we need to apply the pattern as well to fetch correct results */ 512 resultlength=0; 513 resultlengthneeded=unum_toPattern(cur_def, FALSE, NULL, resultlength, &status); 514 if(status==U_BUFFER_OVERFLOW_ERROR) 515 { 516 status=U_ZERO_ERROR; 517 resultlength=resultlengthneeded+1; 518 result=(UChar*)malloc(sizeof(UChar) * resultlength); 519 unum_toPattern(cur_def, FALSE, result, resultlength, &status); 520 } 521 if(U_FAILURE(status)) 522 { 523 log_err("error in extracting the pattern from UNumberFormat: %s\n", myErrorName(status)); 524 } 525 526 status=U_ZERO_ERROR; 527 cur_frpattern=unum_open(UNUM_IGNORE,result, u_strlen(result), "fr_FR",NULL, &status); 528 if(U_FAILURE(status)) 529 { 530 log_err("error in unum_openPattern(): %s\n", myErrorName(status)); 531 } 532 533 free(result); 534 535 /*getting the symbols of cur_def */ 536 /*set the symbols of cur_frpattern to cur_def */ 537 for (symType = UNUM_DECIMAL_SEPARATOR_SYMBOL; symType < UNUM_FORMAT_SYMBOL_COUNT; symType++) { 538 status=U_ZERO_ERROR; 539 unum_getSymbol(cur_def, symType, temp1, sizeof(temp1), &status); 540 unum_setSymbol(cur_frpattern, symType, temp1, -1, &status); 541 if(U_FAILURE(status)) 542 { 543 log_err("Error in get/set symbols: %s\n", myErrorName(status)); 544 } 545 } 546 547 /*format to check the result */ 548 resultlength=0; 549 resultlengthneeded=unum_format(cur_def, l, NULL, resultlength, &pos1, &status); 550 if(status==U_BUFFER_OVERFLOW_ERROR) 551 { 552 status=U_ZERO_ERROR; 553 resultlength=resultlengthneeded+1; 554 result=(UChar*)malloc(sizeof(UChar) * resultlength); 555 unum_format(cur_def, l, result, resultlength, &pos1, &status); 556 } 557 if(U_FAILURE(status)) 558 { 559 log_err("Error in formatting using unum_format(.....): %s\n", myErrorName(status)); 560 } 561 562 if(U_FAILURE(status)){ 563 log_err("Fail: error in unum_setSymbols: %s\n", myErrorName(status)); 564 } 565 unum_applyPattern(cur_frpattern, FALSE, result, u_strlen(result),NULL,NULL); 566 567 for (symType = UNUM_DECIMAL_SEPARATOR_SYMBOL; symType < UNUM_FORMAT_SYMBOL_COUNT; symType++) { 568 status=U_ZERO_ERROR; 569 unum_getSymbol(cur_def, symType, temp1, sizeof(temp1), &status); 570 unum_getSymbol(cur_frpattern, symType, temp2, sizeof(temp2), &status); 571 if(U_FAILURE(status) || u_strcmp(temp1, temp2) != 0) 572 { 573 log_err("Fail: error in getting symbols\n"); 574 } 575 else 576 log_verbose("Pass: get and set symbols successful\n"); 577 } 578 579 /*format and check with the previous result */ 580 581 resultlength=0; 582 resultlengthneeded=unum_format(cur_frpattern, l, NULL, resultlength, &pos1, &status); 583 if(status==U_BUFFER_OVERFLOW_ERROR) 584 { 585 status=U_ZERO_ERROR; 586 resultlength=resultlengthneeded+1; 587 unum_format(cur_frpattern, l, temp1, resultlength, &pos1, &status); 588 } 589 if(U_FAILURE(status)) 590 { 591 log_err("Error in formatting using unum_format(.....): %s\n", myErrorName(status)); 592 } 593 /* TODO: 594 * This test fails because we have not called unum_applyPattern(). 595 * Currently, such an applyPattern() does not exist on the C API, and 596 * we have jitterbug 411 for it. 597 * Since it is close to the 1.5 release, I (markus) am disabling this test just 598 * for this release (I added the test itself only last week). 599 * For the next release, we need to fix this. 600 * Then, remove the uprv_strcmp("1.5", ...) and this comment, and the include "cstring.h" at the beginning of this file. 601 */ 602 if(u_strcmp(result, temp1) != 0) { 603 log_err("Formatting failed after setting symbols. result=%s temp1=%s\n", result, temp1); 604 } 605 606 607 /*----------- */ 608 609 free(result); 610 611 /* Testing unum_get/setSymbol() */ 612 for(i = 0; i < UNUM_FORMAT_SYMBOL_COUNT; ++i) { 613 symbol[0] = (UChar)(0x41 + i); 614 symbol[1] = (UChar)(0x61 + i); 615 unum_setSymbol(cur_frpattern, (UNumberFormatSymbol)i, symbol, 2, &status); 616 if(U_FAILURE(status)) { 617 log_err("Error from unum_setSymbol(%d): %s\n", i, myErrorName(status)); 618 return; 619 } 620 } 621 for(i = 0; i < UNUM_FORMAT_SYMBOL_COUNT; ++i) { 622 resultlength = unum_getSymbol(cur_frpattern, (UNumberFormatSymbol)i, symbol, sizeof(symbol)/U_SIZEOF_UCHAR, &status); 623 if(U_FAILURE(status)) { 624 log_err("Error from unum_getSymbol(%d): %s\n", i, myErrorName(status)); 625 return; 626 } 627 if(resultlength != 2 || symbol[0] != 0x41 + i || symbol[1] != 0x61 + i) { 628 log_err("Failure in unum_getSymbol(%d): got unexpected symbol\n", i); 629 } 630 } 631 /*try getting from a bogus symbol*/ 632 unum_getSymbol(cur_frpattern, (UNumberFormatSymbol)i, symbol, sizeof(symbol)/U_SIZEOF_UCHAR, &status); 633 if(U_SUCCESS(status)){ 634 log_err("Error : Expected U_ILLEGAL_ARGUMENT_ERROR for bogus symbol"); 635 } 636 if(U_FAILURE(status)){ 637 if(status != U_ILLEGAL_ARGUMENT_ERROR){ 638 log_err("Error: Expected U_ILLEGAL_ARGUMENT_ERROR for bogus symbol, Got %s\n", myErrorName(status)); 639 } 640 } 641 status=U_ZERO_ERROR; 642 643 /* Testing unum_getTextAttribute() and unum_setTextAttribute()*/ 644 log_verbose("\nTesting getting and setting text attributes\n"); 645 resultlength=5; 646 unum_getTextAttribute(cur_fr, UNUM_NEGATIVE_SUFFIX, temp, resultlength, &status); 647 if(U_FAILURE(status)) 648 { 649 log_err("Failure in gettting the Text attributes of number format: %s\n", myErrorName(status)); 650 } 651 unum_setTextAttribute(cur_def, UNUM_NEGATIVE_SUFFIX, temp, u_strlen(temp), &status); 652 if(U_FAILURE(status)) 653 { 654 log_err("Failure in gettting the Text attributes of number format: %s\n", myErrorName(status)); 655 } 656 unum_getTextAttribute(cur_def, UNUM_NEGATIVE_SUFFIX, suffix, resultlength, &status); 657 if(U_FAILURE(status)) 658 { 659 log_err("Failure in gettting the Text attributes of number format: %s\n", myErrorName(status)); 660 } 661 if(u_strcmp(suffix,temp)!=0) 662 log_err("Fail:Error in setTextAttribute or getTextAttribute in setting and getting suffix\n"); 663 else 664 log_verbose("Pass: setting and getting suffix works fine\n"); 665 /*set it back to normal */ 666 u_uastrcpy(temp,"$"); 667 unum_setTextAttribute(cur_def, UNUM_NEGATIVE_SUFFIX, temp, u_strlen(temp), &status); 668 669 /*checking some more text setter conditions */ 670 u_uastrcpy(prefix, "+"); 671 unum_setTextAttribute(def, UNUM_POSITIVE_PREFIX, prefix, u_strlen(prefix) , &status); 672 if(U_FAILURE(status)) 673 { 674 log_err("error in setting the text attributes : %s\n", myErrorName(status)); 675 } 676 unum_getTextAttribute(def, UNUM_POSITIVE_PREFIX, temp, resultlength, &status); 677 if(U_FAILURE(status)) 678 { 679 log_err("error in getting the text attributes : %s\n", myErrorName(status)); 680 } 681 682 if(u_strcmp(prefix, temp)!=0) 683 log_err("ERROR: get and setTextAttributes with positive prefix failed\n"); 684 else 685 log_verbose("Pass: get and setTextAttributes with positive prefix works fine\n"); 686 687 u_uastrcpy(prefix, "+"); 688 unum_setTextAttribute(def, UNUM_NEGATIVE_PREFIX, prefix, u_strlen(prefix), &status); 689 if(U_FAILURE(status)) 690 { 691 log_err("error in setting the text attributes : %s\n", myErrorName(status)); 692 } 693 unum_getTextAttribute(def, UNUM_NEGATIVE_PREFIX, temp, resultlength, &status); 694 if(U_FAILURE(status)) 695 { 696 log_err("error in getting the text attributes : %s\n", myErrorName(status)); 697 } 698 if(u_strcmp(prefix, temp)!=0) 699 log_err("ERROR: get and setTextAttributes with negative prefix failed\n"); 700 else 701 log_verbose("Pass: get and setTextAttributes with negative prefix works fine\n"); 702 703 u_uastrcpy(suffix, "+"); 704 unum_setTextAttribute(def, UNUM_NEGATIVE_SUFFIX, suffix, u_strlen(suffix) , &status); 705 if(U_FAILURE(status)) 706 { 707 log_err("error in setting the text attributes: %s\n", myErrorName(status)); 708 } 709 710 unum_getTextAttribute(def, UNUM_NEGATIVE_SUFFIX, temp, resultlength, &status); 711 if(U_FAILURE(status)) 712 { 713 log_err("error in getting the text attributes : %s\n", myErrorName(status)); 714 } 715 if(u_strcmp(suffix, temp)!=0) 716 log_err("ERROR: get and setTextAttributes with negative suffix failed\n"); 717 else 718 log_verbose("Pass: get and settextAttributes with negative suffix works fine\n"); 719 720 u_uastrcpy(suffix, "++"); 721 unum_setTextAttribute(def, UNUM_POSITIVE_SUFFIX, suffix, u_strlen(suffix) , &status); 722 if(U_FAILURE(status)) 723 { 724 log_err("error in setting the text attributes: %s\n", myErrorName(status)); 725 } 726 727 unum_getTextAttribute(def, UNUM_POSITIVE_SUFFIX, temp, resultlength, &status); 728 if(U_FAILURE(status)) 729 { 730 log_err("error in getting the text attributes : %s\n", myErrorName(status)); 731 } 732 if(u_strcmp(suffix, temp)!=0) 733 log_err("ERROR: get and setTextAttributes with negative suffix failed\n"); 734 else 735 log_verbose("Pass: get and settextAttributes with negative suffix works fine\n"); 736 737 /*Testing unum_getAttribute and unum_setAttribute() */ 738 log_verbose("\nTesting get and set Attributes\n"); 739 attr=UNUM_GROUPING_SIZE; 740 newvalue=unum_getAttribute(def, attr); 741 newvalue=2; 742 unum_setAttribute(def, attr, newvalue); 743 if(unum_getAttribute(def,attr)!=2) 744 log_err("Fail: error in setting and getting attributes for UNUM_GROUPING_SIZE\n"); 745 else 746 log_verbose("Pass: setting and getting attributes for UNUM_GROUPING_SIZE works fine\n"); 747 748 attr=UNUM_MULTIPLIER; 749 newvalue=unum_getAttribute(def, attr); 750 newvalue=8; 751 unum_setAttribute(def, attr, newvalue); 752 if(unum_getAttribute(def,attr) != 8) 753 log_err("error in setting and getting attributes for UNUM_MULTIPLIER\n"); 754 else 755 log_verbose("Pass:setting and getting attributes for UNUM_MULTIPLIER works fine\n"); 756 757 attr=UNUM_SECONDARY_GROUPING_SIZE; 758 newvalue=unum_getAttribute(def, attr); 759 newvalue=2; 760 unum_setAttribute(def, attr, newvalue); 761 if(unum_getAttribute(def,attr) != 2) 762 log_err("error in setting and getting attributes for UNUM_SECONDARY_GROUPING_SIZE\n"); 763 else 764 log_verbose("Pass:setting and getting attributes for UNUM_SECONDARY_GROUPING_SIZE works fine\n"); 765 766 /*testing set and get Attributes extensively */ 767 log_verbose("\nTesting get and set attributes extensively\n"); 768 for(attr=UNUM_PARSE_INT_ONLY; attr<= UNUM_PADDING_POSITION; attr=(UNumberFormatAttribute)((int32_t)attr + 1) ) 769 { 770 newvalue=unum_getAttribute(fr, attr); 771 unum_setAttribute(def, attr, newvalue); 772 if(unum_getAttribute(def,attr)!=unum_getAttribute(fr, attr)) 773 log_err("error in setting and getting attributes\n"); 774 else 775 log_verbose("Pass: attributes set and retrieved successfully\n"); 776 } 777 778 /*testing spellout format to make sure we can use it successfully.*/ 779 log_verbose("\nTesting spellout format\n"); 780 if (spellout_def) 781 { 782 static const int32_t values[] = { 0, -5, 105, 1005, 105050 }; 783 for (i = 0; i < LENGTH(values); ++i) { 784 UChar buffer[128]; 785 int32_t len; 786 int32_t value = values[i]; 787 status = U_ZERO_ERROR; 788 len = unum_format(spellout_def, value, buffer, LENGTH(buffer), NULL, &status); 789 if(U_FAILURE(status)) { 790 log_err("Error in formatting using unum_format(spellout_fmt, ...): %s\n", myErrorName(status)); 791 } else { 792 int32_t pp = 0; 793 int32_t parseResult; 794 char logbuf[256]; 795 ustrToAstr(buffer, len, logbuf, LENGTH(logbuf)); 796 log_verbose("formatted %d as '%s', length: %d\n", value, logbuf, len); 797 798 parseResult = unum_parse(spellout_def, buffer, len, &pp, &status); 799 if (U_FAILURE(status)) { 800 log_err("Error in parsing using unum_format(spellout_fmt, ...): %s\n", myErrorName(status)); 801 } else if (parseResult != value) { 802 log_err("unum_format result %d != value %d\n", parseResult, value); 803 } 804 } 805 } 806 } 807 else { 808 log_err("Spellout format is unavailable\n"); 809 } 810 811 { /* Test for ticket #7079 */ 812 UNumberFormat* dec_en; 813 UChar groupingSep[] = { 0 }; 814 UChar numPercent[] = { 0x0031, 0x0032, 0x0025, 0 }; /* "12%" */ 815 double parseResult = 0.0; 816 817 status=U_ZERO_ERROR; 818 dec_en = unum_open(UNUM_DECIMAL, NULL, 0, "en_US", NULL, &status); 819 unum_setAttribute(dec_en, UNUM_LENIENT_PARSE, 0); 820 unum_setSymbol(dec_en, UNUM_GROUPING_SEPARATOR_SYMBOL, groupingSep, 0, &status); 821 parseResult = unum_parseDouble(dec_en, numPercent, -1, NULL, &status); 822 /* Without the fix in #7079, the above call will hang */ 823 if ( U_FAILURE(status) || parseResult != 12.0 ) { 824 log_err("unum_parseDouble with empty groupingSep: status %s, parseResult %f not 12.0\n", 825 myErrorName(status), parseResult); 826 } else { 827 log_verbose("unum_parseDouble with empty groupingSep: no hang, OK\n"); 828 } 829 unum_close(dec_en); 830 } 831 832 { /* Test parse & format of big decimals. Use a number with too many digits to fit in a double, 833 to verify that it is taking the pure decimal path. */ 834 UNumberFormat *fmt; 835 const char *bdpattern = "#,##0.#########"; 836 const char *numInitial = "12345678900987654321.1234567896"; 837 const char *numFormatted = "12,345,678,900,987,654,321.12345679"; 838 const char *parseExpected = "12345678900987654321.12345679"; 839 int32_t resultSize = 0; 840 int32_t parsePos = 0; /* Output parameter for Parse operations. */ 841 #define DESTCAPACITY 100 842 UChar dest[DESTCAPACITY]; 843 char desta[DESTCAPACITY]; 844 UFieldPosition fieldPos = {0}; 845 846 /* Format */ 847 848 status = U_ZERO_ERROR; 849 u_uastrcpy(dest, bdpattern); 850 fmt = unum_open(UNUM_PATTERN_DECIMAL, dest, -1, "en", NULL /*parseError*/, &status); 851 if (U_FAILURE(status)) log_err("File %s, Line %d, status = %s\n", __FILE__, __LINE__, u_errorName(status)); 852 853 resultSize = unum_formatDecimal(fmt, numInitial, -1, dest, DESTCAPACITY, NULL, &status); 854 if (U_FAILURE(status)) { 855 log_err("File %s, Line %d, status = %s\n", __FILE__, __LINE__, u_errorName(status)); 856 } 857 u_austrncpy(desta, dest, DESTCAPACITY); 858 if (strcmp(numFormatted, desta) != 0) { 859 log_err("File %s, Line %d, (expected, acutal) = (\"%s\", \"%s\")\n", 860 __FILE__, __LINE__, numFormatted, desta); 861 } 862 if (strlen(numFormatted) != resultSize) { 863 log_err("File %s, Line %d, (expected, actual) = (%d, %d)\n", 864 __FILE__, __LINE__, strlen(numFormatted), resultSize); 865 } 866 867 /* Format with a FieldPosition parameter */ 868 869 fieldPos.field = 2; /* Ticket 8034 - need enum constants for the field values. */ 870 /* 2 = kDecimalSeparatorField */ 871 resultSize = unum_formatDecimal(fmt, numInitial, -1, dest, DESTCAPACITY, &fieldPos, &status); 872 if (U_FAILURE(status)) { 873 log_err("File %s, Line %d, status = %s\n", __FILE__, __LINE__, u_errorName(status)); 874 } 875 u_austrncpy(desta, dest, DESTCAPACITY); 876 if (strcmp(numFormatted, desta) != 0) { 877 log_err("File %s, Line %d, (expected, acutal) = (\"%s\", \"%s\")\n", 878 __FILE__, __LINE__, numFormatted, desta); 879 } 880 if (fieldPos.beginIndex != 26) { /* index of "." in formatted number */ 881 log_err("File %s, Line %d, (expected, acutal) = (%d, %d)\n", 882 __FILE__, __LINE__, 0, fieldPos.beginIndex); 883 } 884 if (fieldPos.endIndex != 27) { 885 log_err("File %s, Line %d, (expected, acutal) = (%d, %d)\n", 886 __FILE__, __LINE__, 0, fieldPos.endIndex); 887 } 888 889 /* Parse */ 890 891 status = U_ZERO_ERROR; 892 u_uastrcpy(dest, numFormatted); /* Parse the expected output of the formatting test */ 893 resultSize = unum_parseDecimal(fmt, dest, -1, NULL, desta, DESTCAPACITY, &status); 894 if (U_FAILURE(status)) { 895 log_err("File %s, Line %d, status = %s\n", __FILE__, __LINE__, u_errorName(status)); 896 } 897 if (strcmp(parseExpected, desta) != 0) { 898 log_err("File %s, Line %d, (expected, actual) = (\"%s\", \"%s\")\n", 899 __FILE__, __LINE__, parseExpected, desta); 900 } 901 if (strlen(parseExpected) != resultSize) { 902 log_err("File %s, Line %d, (expected, actual) = (%d, %d)\n", 903 __FILE__, __LINE__, strlen(parseExpected), resultSize); 904 } 905 906 /* Parse with a parsePos parameter */ 907 908 status = U_ZERO_ERROR; 909 u_uastrcpy(dest, numFormatted); /* Parse the expected output of the formatting test */ 910 parsePos = 3; /* 12,345,678,900,987,654,321.12345679 */ 911 /* start parsing at the the third char */ 912 resultSize = unum_parseDecimal(fmt, dest, -1, &parsePos, desta, DESTCAPACITY, &status); 913 if (U_FAILURE(status)) { 914 log_err("File %s, Line %d, status = %s\n", __FILE__, __LINE__, u_errorName(status)); 915 } 916 if (strcmp(parseExpected+2, desta) != 0) { /* "345678900987654321.12345679" */ 917 log_err("File %s, Line %d, (expected, actual) = (\"%s\", \"%s\")\n", 918 __FILE__, __LINE__, parseExpected+2, desta); 919 } 920 if (strlen(numFormatted) != parsePos) { 921 log_err("File %s, Line %d, parsePos (expected, actual) = (\"%d\", \"%d\")\n", 922 __FILE__, __LINE__, strlen(parseExpected), parsePos); 923 } 924 925 unum_close(fmt); 926 } 927 928 status = U_ZERO_ERROR; 929 /* Test invalid symbol argument */ 930 { 931 int32_t badsymbolLarge = UNUM_FORMAT_SYMBOL_COUNT + 1; 932 int32_t badsymbolSmall = -1; 933 UChar value[10]; 934 int32_t valueLength = 10; 935 UNumberFormat *fmt = unum_open(UNUM_DEFAULT, NULL, 0, NULL, NULL, &status); 936 if (U_FAILURE(status)) { 937 log_err("File %s, Line %d, status = %s\n", __FILE__, __LINE__, u_errorName(status)); 938 } else { 939 unum_getSymbol(fmt, (UNumberFormatSymbol)badsymbolLarge, NULL, 0, &status); 940 if (U_SUCCESS(status)) log_err("unum_getSymbol()'s status should be ILLEGAL_ARGUMENT with invalid symbol (> UNUM_FORMAT_SYMBOL_COUNT) argument\n"); 941 942 status = U_ZERO_ERROR; 943 unum_getSymbol(fmt, (UNumberFormatSymbol)badsymbolSmall, NULL, 0, &status); 944 if (U_SUCCESS(status)) log_err("unum_getSymbol()'s status should be ILLEGAL_ARGUMENT with invalid symbol (less than 0) argument\n"); 945 946 status = U_ZERO_ERROR; 947 unum_setSymbol(fmt, (UNumberFormatSymbol)badsymbolLarge, value, valueLength, &status); 948 if (U_SUCCESS(status)) log_err("unum_setSymbol()'s status should be ILLEGAL_ARGUMENT with invalid symbol (> UNUM_FORMAT_SYMBOL_COUNT) argument\n"); 949 950 status = U_ZERO_ERROR; 951 unum_setSymbol(fmt, (UNumberFormatSymbol)badsymbolSmall, value, valueLength, &status); 952 if (U_SUCCESS(status)) log_err("unum_setSymbol()'s status should be ILLEGAL_ARGUMENT with invalid symbol (less than 0) argument\n"); 953 954 unum_close(fmt); 955 } 956 } 957 958 959 /*closing the NumberFormat() using unum_close(UNumberFormat*)")*/ 960 unum_close(def); 961 unum_close(fr); 962 unum_close(cur_def); 963 unum_close(cur_fr); 964 unum_close(per_def); 965 unum_close(per_fr); 966 unum_close(spellout_def); 967 unum_close(pattern); 968 unum_close(cur_frpattern); 969 unum_close(myclone); 970 971 } 972 973 static void TestParseZero(void) 974 { 975 UErrorCode errorCode = U_ZERO_ERROR; 976 UChar input[] = {0x30, 0}; /* Input text is decimal '0' */ 977 UChar pat[] = {0x0023,0x003b,0x0023,0}; /* {'#', ';', '#', 0}; */ 978 double dbl; 979 980 #if 0 981 UNumberFormat* unum = unum_open( UNUM_DECIMAL /*or UNUM_DEFAULT*/, NULL, -1, NULL, NULL, &errorCode); 982 #else 983 UNumberFormat* unum = unum_open( UNUM_PATTERN_DECIMAL /*needs pattern*/, pat, -1, NULL, NULL, &errorCode); 984 #endif 985 986 dbl = unum_parseDouble( unum, input, -1 /*u_strlen(input)*/, 0 /* 0 = start */, &errorCode ); 987 if (U_FAILURE(errorCode)) { 988 log_data_err("Result - %s\n", u_errorName(errorCode)); 989 } else { 990 log_verbose("Double: %f\n", dbl); 991 } 992 unum_close(unum); 993 } 994 995 static const UChar dollars2Sym[] = { 0x24,0x32,0x2E,0x30,0x30,0 }; /* $2.00 */ 996 static const UChar dollars4Sym[] = { 0x24,0x34,0 }; /* $4 */ 997 static const UChar dollars9Sym[] = { 0x39,0xA0,0x24,0 }; /* 9 $ */ 998 static const UChar pounds3Sym[] = { 0xA3,0x33,0x2E,0x30,0x30,0 }; /* [POUND]3.00 */ 999 static const UChar pounds5Sym[] = { 0xA3,0x35,0 }; /* [POUND]5 */ 1000 static const UChar pounds7Sym[] = { 0x37,0xA0,0xA3,0 }; /* 7 [POUND] */ 1001 static const UChar euros4Sym[] = { 0x34,0x2C,0x30,0x30,0xA0,0x20AC,0 }; /* 4,00 [EURO] */ 1002 static const UChar euros6Sym[] = { 0x36,0xA0,0x20AC,0 }; /* 6 [EURO] */ 1003 static const UChar euros8Sym[] = { 0x20AC,0x38,0 }; /* [EURO]8 */ 1004 static const UChar dollars4PluEn[] = { 0x34,0x20,0x55,0x53,0x20,0x64,0x6F,0x6C,0x6C,0x61,0x72,0x73,0 }; /* 4 US dollars*/ 1005 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 */ 1006 static const UChar euros8PluEn[] = { 0x38,0x20,0x65,0x75,0x72,0x6F,0x73,0 }; /* 8 euros*/ 1007 static const UChar euros6PluFr[] = { 0x36,0x20,0x65,0x75,0x72,0x6F,0x73,0 }; /* 6 euros*/ 1008 1009 typedef struct { 1010 const char * locale; 1011 const char * descrip; 1012 const UChar * currStr; 1013 const UChar * plurStr; 1014 UErrorCode parsDoubExpectErr; 1015 int32_t parsDoubExpectPos; 1016 double parsDoubExpectVal; 1017 UErrorCode parsCurrExpectErr; 1018 int32_t parsCurrExpectPos; 1019 double parsCurrExpectVal; 1020 const char * parsCurrExpectCurr; 1021 } ParseCurrencyItem; 1022 1023 static const ParseCurrencyItem parseCurrencyItems[] = { 1024 { "en_US", "dollars2", dollars2Sym, NULL, U_ZERO_ERROR, 5, 2.0, U_ZERO_ERROR, 5, 2.0, "USD" }, 1025 { "en_US", "dollars4", dollars4Sym, dollars4PluEn, U_ZERO_ERROR, 2, 4.0, U_ZERO_ERROR, 2, 4.0, "USD" }, 1026 { "en_US", "dollars9", dollars9Sym, NULL, U_PARSE_ERROR, 1, 0.0, U_PARSE_ERROR, 1, 0.0, "" }, 1027 { "en_US", "pounds3", pounds3Sym, NULL, U_PARSE_ERROR, 0, 0.0, U_ZERO_ERROR, 5, 3.0, "GBP" }, 1028 { "en_US", "pounds5", pounds5Sym, pounds5PluEn, U_PARSE_ERROR, 0, 0.0, U_ZERO_ERROR, 2, 5.0, "GBP" }, 1029 { "en_US", "pounds7", pounds7Sym, NULL, U_PARSE_ERROR, 1, 0.0, U_PARSE_ERROR, 1, 0.0, "" }, 1030 { "en_US", "euros8", euros8Sym, euros8PluEn, U_PARSE_ERROR, 0, 0.0, U_ZERO_ERROR, 2, 8.0, "EUR" }, 1031 1032 { "en_GB", "pounds3", pounds3Sym, NULL, U_ZERO_ERROR, 5, 3.0, U_ZERO_ERROR, 5, 3.0, "GBP" }, 1033 { "en_GB", "pounds5", pounds5Sym, pounds5PluEn, U_ZERO_ERROR, 2, 5.0, U_ZERO_ERROR, 2, 5.0, "GBP" }, 1034 { "en_GB", "pounds7", pounds7Sym, NULL, U_PARSE_ERROR, 1, 0.0, U_PARSE_ERROR, 1, 0.0, "" }, 1035 { "en_GB", "euros4", euros4Sym, NULL, U_PARSE_ERROR, 4, 0.0, U_PARSE_ERROR, 4, 0.0, "" }, 1036 { "en_GB", "euros6", euros6Sym, NULL, U_PARSE_ERROR, 1, 0.0, U_PARSE_ERROR, 1, 0.0, "" }, 1037 { "en_GB", "euros8", euros8Sym, euros8PluEn, U_PARSE_ERROR, 0, 0.0, U_ZERO_ERROR, 2, 8.0, "EUR" }, 1038 { "en_GB", "dollars4", dollars4Sym, dollars4PluEn, U_PARSE_ERROR, 0, 0.0, U_ZERO_ERROR, 2, 4.0, "USD" }, 1039 1040 { "fr_FR", "euros4", euros4Sym, NULL, U_ZERO_ERROR, 6, 4.0, U_ZERO_ERROR, 6, 4.0, "EUR" }, 1041 { "fr_FR", "euros6", euros6Sym, euros6PluFr, U_ZERO_ERROR, 3, 6.0, U_ZERO_ERROR, 3, 6.0, "EUR" }, 1042 { "fr_FR", "euros8", euros8Sym, NULL, U_PARSE_ERROR, 0, 0.0, U_PARSE_ERROR, 0, 0.0, "" }, 1043 { "fr_FR", "dollars2", dollars2Sym, NULL, U_PARSE_ERROR, 0, 0.0, U_PARSE_ERROR, 0, 0.0, "" }, 1044 { "fr_FR", "dollars4", dollars4Sym, NULL, U_PARSE_ERROR, 0, 0.0, U_PARSE_ERROR, 0, 0.0, "" }, 1045 1046 { NULL, NULL, NULL, NULL, 0, 0, 0.0, 0, 0, 0.0, NULL } 1047 }; 1048 1049 static void TestParseCurrency() 1050 { 1051 const ParseCurrencyItem * itemPtr; 1052 for (itemPtr = parseCurrencyItems; itemPtr->locale != NULL; ++itemPtr) { 1053 UNumberFormat* unum; 1054 UErrorCode status; 1055 double parseVal; 1056 int32_t parsePos; 1057 UChar parseCurr[4]; 1058 char parseCurrB[4]; 1059 1060 status = U_ZERO_ERROR; 1061 unum = unum_open(UNUM_CURRENCY, NULL, 0, itemPtr->locale, NULL, &status); 1062 if (U_SUCCESS(status)) { 1063 status = U_ZERO_ERROR; 1064 parsePos = 0; 1065 parseVal = unum_parseDouble(unum, itemPtr->currStr, -1, &parsePos, &status); 1066 if (status != itemPtr->parsDoubExpectErr || parsePos != itemPtr->parsDoubExpectPos || parseVal != itemPtr->parsDoubExpectVal) { 1067 log_err("UNUM_CURRENCY parseDouble %s/%s, expect %s pos %d val %.1f, get %s pos %d val %.1f\n", 1068 itemPtr->locale, itemPtr->descrip, 1069 u_errorName(itemPtr->parsDoubExpectErr), itemPtr->parsDoubExpectPos, itemPtr->parsDoubExpectVal, 1070 u_errorName(status), parsePos, parseVal ); 1071 } 1072 status = U_ZERO_ERROR; 1073 parsePos = 0; 1074 parseCurr[0] = 0; 1075 parseVal = unum_parseDoubleCurrency(unum, itemPtr->currStr, -1, &parsePos, parseCurr, &status); 1076 u_austrncpy(parseCurrB, parseCurr, 4); 1077 if (status != itemPtr->parsCurrExpectErr || parsePos != itemPtr->parsCurrExpectPos || parseVal != itemPtr->parsCurrExpectVal || 1078 strncmp(parseCurrB, itemPtr->parsCurrExpectCurr, 4) != 0) { 1079 log_err("UNUM_CURRENCY parseDoubleCurrency %s/%s, expect %s pos %d val %.1f cur %s, get %s pos %d val %.1f cur %s\n", 1080 itemPtr->locale, itemPtr->descrip, 1081 u_errorName(itemPtr->parsCurrExpectErr), itemPtr->parsCurrExpectPos, itemPtr->parsCurrExpectVal, itemPtr->parsCurrExpectCurr, 1082 u_errorName(status), parsePos, parseVal, parseCurrB ); 1083 } 1084 unum_close(unum); 1085 } else { 1086 log_data_err("unexpected error in unum_open UNUM_CURRENCY for locale %s: '%s'\n", itemPtr->locale, u_errorName(status)); 1087 } 1088 1089 #if 0 1090 /* Hmm, for UNUM_CURRENCY_PLURAL, currently unum_open always sets U_UNSUPPORTED_ERROR, save this test until it is supported */ 1091 if (itemPtr->plurStr != NULL) { 1092 status = U_ZERO_ERROR; 1093 unum = unum_open(UNUM_CURRENCY_PLURAL, NULL, 0, itemPtr->locale, NULL, &status); 1094 if (U_SUCCESS(status)) { 1095 status = U_ZERO_ERROR; 1096 parsePos = 0; 1097 parseVal = unum_parseDouble(unum, itemPtr->plurStr, -1, &parsePos, &status); 1098 if (status != itemPtr->parsDoubExpectErr || parseVal != itemPtr->parsDoubExpectVal) { 1099 log_err("UNUM_CURRENCY parseDouble %s/%s, expect %s val %.1f, get %s val %.1f\n", 1100 itemPtr->locale, itemPtr->descrip, 1101 u_errorName(itemPtr->parsDoubExpectErr), itemPtr->parsDoubExpectVal, 1102 u_errorName(status), parseVal ); 1103 } 1104 status = U_ZERO_ERROR; 1105 parsePos = 0; 1106 parseCurr[0] = 0; 1107 parseVal = unum_parseDoubleCurrency(unum, itemPtr->plurStr, -1, &parsePos, parseCurr, &status); 1108 u_austrncpy(parseCurrB, parseCurr, 4); 1109 if (status != itemPtr->parsCurrExpectErr || parseVal != itemPtr->parsCurrExpectVal || 1110 strncmp(parseCurrB, itemPtr->parsCurrExpectCurr, 4) != 0) { 1111 log_err("UNUM_CURRENCY parseDoubleCurrency %s/%s, expect %s val %.1f cur %s, get %s val %.1f cur %s\n", 1112 itemPtr->locale, itemPtr->descrip, 1113 u_errorName(itemPtr->parsCurrExpectErr), itemPtr->parsCurrExpectVal, itemPtr->parsCurrExpectCurr, 1114 u_errorName(status), parseVal, parseCurrB ); 1115 } 1116 unum_close(unum); 1117 } else { 1118 log_data_err("unexpected error in unum_open UNUM_CURRENCY_PLURAL for locale %s: '%s'\n", itemPtr->locale, u_errorName(status)); 1119 } 1120 } 1121 #endif 1122 } 1123 } 1124 1125 typedef struct { 1126 const char * testname; 1127 const char * locale; 1128 const UChar * source; 1129 int32_t startPos; 1130 int32_t value; 1131 int32_t endPos; 1132 UErrorCode status; 1133 } SpelloutParseTest; 1134 1135 static const UChar ustr_en0[] = {0x7A, 0x65, 0x72, 0x6F, 0}; /* zero */ 1136 static const UChar ustr_123[] = {0x31, 0x32, 0x33, 0}; /* 123 */ 1137 static const UChar ustr_en123[] = {0x6f, 0x6e, 0x65, 0x20, 0x68, 0x75, 0x6e, 0x64, 0x72, 0x65, 0x64, 1138 0x20, 0x74, 0x77, 0x65, 0x6e, 0x74, 0x79, 1139 0x2d, 0x74, 0x68, 0x72, 0x65, 0x65, 0}; /* one hundred twenty-three */ 1140 static const UChar ustr_fr123[] = {0x63, 0x65, 0x6e, 0x74, 0x2d, 0x76, 0x69, 0x6e, 0x67, 0x74, 0x2d, 1141 0x74, 0x72, 0x6f, 0x69, 0x73, 0}; /* cent-vingt-trois */ 1142 static const UChar ustr_ja123[] = {0x767e, 0x4e8c, 0x5341, 0x4e09, 0}; /* kanji 100(+)2(*)10(+)3 */ 1143 1144 static const SpelloutParseTest spelloutParseTests[] = { 1145 /* name loc src start val end status */ 1146 { "en0", "en", ustr_en0, 0, 0, 4, U_ZERO_ERROR }, 1147 { "en0", "en", ustr_en0, 2, 0, 2, U_PARSE_ERROR }, 1148 { "en0", "ja", ustr_en0, 0, 0, 0, U_PARSE_ERROR }, 1149 { "123", "en", ustr_123, 0, 123, 3, U_ZERO_ERROR }, 1150 { "en123", "en", ustr_en123, 0, 123, 24, U_ZERO_ERROR }, 1151 { "en123", "en", ustr_en123, 12, 23, 24, U_ZERO_ERROR }, 1152 { "en123", "fr", ustr_en123, 16, 0, 16, U_PARSE_ERROR }, 1153 { "fr123", "fr", ustr_fr123, 0, 123, 16, U_ZERO_ERROR }, 1154 { "fr123", "fr", ustr_fr123, 5, 23, 16, U_ZERO_ERROR }, 1155 { "fr123", "en", ustr_fr123, 0, 0, 0, U_PARSE_ERROR }, 1156 { "ja123", "ja", ustr_ja123, 0, 123, 4, U_ZERO_ERROR }, 1157 { "ja123", "ja", ustr_ja123, 1, 23, 4, U_ZERO_ERROR }, 1158 { "ja123", "fr", ustr_ja123, 0, 0, 0, U_PARSE_ERROR }, 1159 { NULL, NULL, NULL, 0, 0, 0, 0 } /* terminator */ 1160 }; 1161 1162 static void TestSpelloutNumberParse() 1163 { 1164 const SpelloutParseTest * testPtr; 1165 for (testPtr = spelloutParseTests; testPtr->testname != NULL; ++testPtr) { 1166 UErrorCode status = U_ZERO_ERROR; 1167 int32_t value, position = testPtr->startPos; 1168 UNumberFormat *nf = unum_open(UNUM_SPELLOUT, NULL, 0, testPtr->locale, NULL, &status); 1169 if (U_FAILURE(status)) { 1170 log_err_status(status, "unum_open fails for UNUM_SPELLOUT with locale %s, status %s\n", testPtr->locale, myErrorName(status)); 1171 continue; 1172 } 1173 value = unum_parse(nf, testPtr->source, -1, &position, &status); 1174 if ( value != testPtr->value || position != testPtr->endPos || status != testPtr->status ) { 1175 log_err("unum_parse SPELLOUT, locale %s, testname %s, startPos %d: for value / endPos / status, expected %d / %d / %s, got %d / %d / %s\n", 1176 testPtr->locale, testPtr->testname, testPtr->startPos, 1177 testPtr->value, testPtr->endPos, myErrorName(testPtr->status), 1178 value, position, myErrorName(status) ); 1179 } 1180 unum_close(nf); 1181 } 1182 } 1183 1184 static void TestSignificantDigits() 1185 { 1186 UChar temp[128]; 1187 int32_t resultlengthneeded; 1188 int32_t resultlength; 1189 UErrorCode status = U_ZERO_ERROR; 1190 UChar *result = NULL; 1191 UNumberFormat* fmt; 1192 double d = 123456.789; 1193 1194 u_uastrcpy(temp, "###0.0#"); 1195 fmt=unum_open(UNUM_IGNORE, temp, -1, NULL, NULL,&status); 1196 if (U_FAILURE(status)) { 1197 log_data_err("got unexpected error for unum_open: '%s'\n", u_errorName(status)); 1198 return; 1199 } 1200 unum_setAttribute(fmt, UNUM_SIGNIFICANT_DIGITS_USED, TRUE); 1201 unum_setAttribute(fmt, UNUM_MAX_SIGNIFICANT_DIGITS, 6); 1202 1203 u_uastrcpy(temp, "123457"); 1204 resultlength=0; 1205 resultlengthneeded=unum_formatDouble(fmt, d, NULL, resultlength, NULL, &status); 1206 if(status==U_BUFFER_OVERFLOW_ERROR) 1207 { 1208 status=U_ZERO_ERROR; 1209 resultlength=resultlengthneeded+1; 1210 result=(UChar*)malloc(sizeof(UChar) * resultlength); 1211 unum_formatDouble(fmt, d, result, resultlength, NULL, &status); 1212 } 1213 if(U_FAILURE(status)) 1214 { 1215 log_err("Error in formatting using unum_formatDouble(.....): %s\n", myErrorName(status)); 1216 return; 1217 } 1218 if(u_strcmp(result, temp)==0) 1219 log_verbose("Pass: Number Formatting using unum_formatDouble() Successful\n"); 1220 else 1221 log_err("FAIL: Error in number formatting using unum_formatDouble()\n"); 1222 free(result); 1223 unum_close(fmt); 1224 } 1225 1226 static void TestSigDigRounding() 1227 { 1228 UErrorCode status = U_ZERO_ERROR; 1229 UChar expected[128]; 1230 UChar result[128]; 1231 char temp1[128]; 1232 char temp2[128]; 1233 UNumberFormat* fmt; 1234 double d = 123.4; 1235 1236 fmt=unum_open(UNUM_DECIMAL, NULL, 0, NULL /* "en_US"*/, NULL, &status); 1237 if (U_FAILURE(status)) { 1238 log_data_err("got unexpected error for unum_open: '%s'\n", u_errorName(status)); 1239 return; 1240 } 1241 unum_setAttribute(fmt, UNUM_LENIENT_PARSE, FALSE); 1242 unum_setAttribute(fmt, UNUM_SIGNIFICANT_DIGITS_USED, TRUE); 1243 unum_setAttribute(fmt, UNUM_MAX_SIGNIFICANT_DIGITS, 2); 1244 /* unum_setAttribute(fmt, UNUM_MAX_FRACTION_DIGITS, 0); */ 1245 1246 unum_setAttribute(fmt, UNUM_ROUNDING_MODE, UNUM_ROUND_UP); 1247 unum_setDoubleAttribute(fmt, UNUM_ROUNDING_INCREMENT, 20.0); 1248 1249 (void)unum_formatDouble(fmt, d, result, sizeof(result) / sizeof(result[0]), NULL, &status); 1250 if(U_FAILURE(status)) 1251 { 1252 log_err("Error in formatting using unum_formatDouble(.....): %s\n", myErrorName(status)); 1253 return; 1254 } 1255 1256 u_uastrcpy(expected, "140"); 1257 if(u_strcmp(result, expected)!=0) 1258 log_err("FAIL: Error in unum_formatDouble result %s instead of %s\n", u_austrcpy(temp1, result), u_austrcpy(temp2, expected) ); 1259 1260 unum_close(fmt); 1261 } 1262 1263 static void TestNumberFormatPadding() 1264 { 1265 UChar *result=NULL; 1266 UChar temp1[512]; 1267 1268 UErrorCode status=U_ZERO_ERROR; 1269 int32_t resultlength; 1270 int32_t resultlengthneeded; 1271 UNumberFormat *pattern; 1272 double d1; 1273 double d = -10456.37; 1274 UFieldPosition pos1; 1275 int32_t parsepos; 1276 1277 /* create a number format using unum_openPattern(....)*/ 1278 log_verbose("\nTesting unum_openPattern() with padding\n"); 1279 u_uastrcpy(temp1, "*#,##0.0#*;(#,##0.0#)"); 1280 status=U_ZERO_ERROR; 1281 pattern=unum_open(UNUM_IGNORE,temp1, u_strlen(temp1), NULL, NULL,&status); 1282 if(U_SUCCESS(status)) 1283 { 1284 log_err("error in unum_openPattern(%s): %s\n", temp1, myErrorName(status) ); 1285 } 1286 else 1287 { 1288 unum_close(pattern); 1289 } 1290 1291 /* u_uastrcpy(temp1, "*x#,###,###,##0.0#;(*x#,###,###,##0.0#)"); */ 1292 u_uastrcpy(temp1, "*x#,###,###,##0.0#;*x(###,###,##0.0#)"); 1293 status=U_ZERO_ERROR; 1294 pattern=unum_open(UNUM_IGNORE,temp1, u_strlen(temp1), "en_US",NULL, &status); 1295 if(U_FAILURE(status)) 1296 { 1297 log_err_status(status, "error in padding unum_openPattern(%s): %s\n", temp1, myErrorName(status) );; 1298 } 1299 else { 1300 log_verbose("Pass: padding unum_openPattern() works fine\n"); 1301 1302 /*test for unum_toPattern()*/ 1303 log_verbose("\nTesting padding unum_toPattern()\n"); 1304 resultlength=0; 1305 resultlengthneeded=unum_toPattern(pattern, FALSE, NULL, resultlength, &status); 1306 if(status==U_BUFFER_OVERFLOW_ERROR) 1307 { 1308 status=U_ZERO_ERROR; 1309 resultlength=resultlengthneeded+1; 1310 result=(UChar*)malloc(sizeof(UChar) * resultlength); 1311 unum_toPattern(pattern, FALSE, result, resultlength, &status); 1312 } 1313 if(U_FAILURE(status)) 1314 { 1315 log_err("error in extracting the padding pattern from UNumberFormat: %s\n", myErrorName(status)); 1316 } 1317 else 1318 { 1319 if(u_strcmp(result, temp1)!=0) 1320 log_err("FAIL: Error in extracting the padding pattern using unum_toPattern()\n"); 1321 else 1322 log_verbose("Pass: extracted the padding pattern correctly using unum_toPattern()\n"); 1323 free(result); 1324 } 1325 /* u_uastrcpy(temp1, "(xxxxxxx10,456.37)"); */ 1326 u_uastrcpy(temp1, "xxxxx(10,456.37)"); 1327 resultlength=0; 1328 pos1.field = 1; /* Fraction field */ 1329 resultlengthneeded=unum_formatDouble(pattern, d, NULL, resultlength, &pos1, &status); 1330 if(status==U_BUFFER_OVERFLOW_ERROR) 1331 { 1332 status=U_ZERO_ERROR; 1333 resultlength=resultlengthneeded+1; 1334 result=(UChar*)malloc(sizeof(UChar) * resultlength); 1335 unum_formatDouble(pattern, d, result, resultlength, NULL, &status); 1336 } 1337 if(U_FAILURE(status)) 1338 { 1339 log_err("Error in formatting using unum_formatDouble(.....) with padding : %s\n", myErrorName(status)); 1340 } 1341 else 1342 { 1343 if(u_strcmp(result, temp1)==0) 1344 log_verbose("Pass: Number Formatting using unum_formatDouble() padding Successful\n"); 1345 else 1346 log_data_err("FAIL: Error in number formatting using unum_formatDouble() with padding\n"); 1347 if(pos1.beginIndex == 13 && pos1.endIndex == 15) 1348 log_verbose("Pass: Complete number formatting using unum_formatDouble() successful\n"); 1349 else 1350 log_err("Fail: Error in complete number Formatting using unum_formatDouble()\nGot: b=%d end=%d\nExpected: b=13 end=15\n", 1351 pos1.beginIndex, pos1.endIndex); 1352 1353 1354 /* Testing unum_parse() and unum_parseDouble() */ 1355 log_verbose("\nTesting padding unum_parseDouble()\n"); 1356 parsepos=0; 1357 d1=unum_parseDouble(pattern, result, u_strlen(result), &parsepos, &status); 1358 if(U_FAILURE(status)) 1359 { 1360 log_err("padding parse failed. The error is : %s\n", myErrorName(status)); 1361 } 1362 1363 if(d1!=d) 1364 log_err("Fail: Error in padding parsing\n"); 1365 else 1366 log_verbose("Pass: padding parsing successful\n"); 1367 free(result); 1368 } 1369 } 1370 1371 unum_close(pattern); 1372 } 1373 1374 static UBool 1375 withinErr(double a, double b, double err) { 1376 return uprv_fabs(a - b) < uprv_fabs(a * err); 1377 } 1378 1379 static void TestInt64Format() { 1380 UChar temp1[512]; 1381 UChar result[512]; 1382 UNumberFormat *fmt; 1383 UErrorCode status = U_ZERO_ERROR; 1384 const double doubleInt64Max = (double)U_INT64_MAX; 1385 const double doubleInt64Min = (double)U_INT64_MIN; 1386 const double doubleBig = 10.0 * (double)U_INT64_MAX; 1387 int32_t val32; 1388 int64_t val64; 1389 double valDouble; 1390 int32_t parsepos; 1391 1392 /* create a number format using unum_openPattern(....) */ 1393 log_verbose("\nTesting Int64Format\n"); 1394 u_uastrcpy(temp1, "#.#E0"); 1395 fmt = unum_open(UNUM_IGNORE, temp1, u_strlen(temp1), NULL, NULL, &status); 1396 if(U_FAILURE(status)) { 1397 log_data_err("error in unum_openPattern() - %s\n", myErrorName(status)); 1398 } else { 1399 unum_setAttribute(fmt, UNUM_MAX_FRACTION_DIGITS, 20); 1400 unum_formatInt64(fmt, U_INT64_MAX, result, 512, NULL, &status); 1401 if (U_FAILURE(status)) { 1402 log_err("error in unum_format(): %s\n", myErrorName(status)); 1403 } else { 1404 log_verbose("format int64max: '%s'\n", result); 1405 parsepos = 0; 1406 val32 = unum_parse(fmt, result, u_strlen(result), &parsepos, &status); 1407 if (status != U_INVALID_FORMAT_ERROR) { 1408 log_err("parse didn't report error: %s\n", myErrorName(status)); 1409 } else if (val32 != INT32_MAX) { 1410 log_err("parse didn't pin return value, got: %d\n", val32); 1411 } 1412 1413 status = U_ZERO_ERROR; 1414 parsepos = 0; 1415 val64 = unum_parseInt64(fmt, result, u_strlen(result), &parsepos, &status); 1416 if (U_FAILURE(status)) { 1417 log_err("parseInt64 returned error: %s\n", myErrorName(status)); 1418 } else if (val64 != U_INT64_MAX) { 1419 log_err("parseInt64 returned incorrect value, got: %ld\n", val64); 1420 } 1421 1422 status = U_ZERO_ERROR; 1423 parsepos = 0; 1424 valDouble = unum_parseDouble(fmt, result, u_strlen(result), &parsepos, &status); 1425 if (U_FAILURE(status)) { 1426 log_err("parseDouble returned error: %s\n", myErrorName(status)); 1427 } else if (valDouble != doubleInt64Max) { 1428 log_err("parseDouble returned incorrect value, got: %g\n", valDouble); 1429 } 1430 } 1431 1432 unum_formatInt64(fmt, U_INT64_MIN, result, 512, NULL, &status); 1433 if (U_FAILURE(status)) { 1434 log_err("error in unum_format(): %s\n", myErrorName(status)); 1435 } else { 1436 log_verbose("format int64min: '%s'\n", result); 1437 parsepos = 0; 1438 val32 = unum_parse(fmt, result, u_strlen(result), &parsepos, &status); 1439 if (status != U_INVALID_FORMAT_ERROR) { 1440 log_err("parse didn't report error: %s\n", myErrorName(status)); 1441 } else if (val32 != INT32_MIN) { 1442 log_err("parse didn't pin return value, got: %d\n", val32); 1443 } 1444 1445 status = U_ZERO_ERROR; 1446 parsepos = 0; 1447 val64 = unum_parseInt64(fmt, result, u_strlen(result), &parsepos, &status); 1448 if (U_FAILURE(status)) { 1449 log_err("parseInt64 returned error: %s\n", myErrorName(status)); 1450 } else if (val64 != U_INT64_MIN) { 1451 log_err("parseInt64 returned incorrect value, got: %ld\n", val64); 1452 } 1453 1454 status = U_ZERO_ERROR; 1455 parsepos = 0; 1456 valDouble = unum_parseDouble(fmt, result, u_strlen(result), &parsepos, &status); 1457 if (U_FAILURE(status)) { 1458 log_err("parseDouble returned error: %s\n", myErrorName(status)); 1459 } else if (valDouble != doubleInt64Min) { 1460 log_err("parseDouble returned incorrect value, got: %g\n", valDouble); 1461 } 1462 } 1463 1464 unum_formatDouble(fmt, doubleBig, result, 512, NULL, &status); 1465 if (U_FAILURE(status)) { 1466 log_err("error in unum_format(): %s\n", myErrorName(status)); 1467 } else { 1468 log_verbose("format doubleBig: '%s'\n", result); 1469 parsepos = 0; 1470 val32 = unum_parse(fmt, result, u_strlen(result), &parsepos, &status); 1471 if (status != U_INVALID_FORMAT_ERROR) { 1472 log_err("parse didn't report error: %s\n", myErrorName(status)); 1473 } else if (val32 != INT32_MAX) { 1474 log_err("parse didn't pin return value, got: %d\n", val32); 1475 } 1476 1477 status = U_ZERO_ERROR; 1478 parsepos = 0; 1479 val64 = unum_parseInt64(fmt, result, u_strlen(result), &parsepos, &status); 1480 if (status != U_INVALID_FORMAT_ERROR) { 1481 log_err("parseInt64 didn't report error error: %s\n", myErrorName(status)); 1482 } else if (val64 != U_INT64_MAX) { 1483 log_err("parseInt64 returned incorrect value, got: %ld\n", val64); 1484 } 1485 1486 status = U_ZERO_ERROR; 1487 parsepos = 0; 1488 valDouble = unum_parseDouble(fmt, result, u_strlen(result), &parsepos, &status); 1489 if (U_FAILURE(status)) { 1490 log_err("parseDouble returned error: %s\n", myErrorName(status)); 1491 } else if (!withinErr(valDouble, doubleBig, 1e-15)) { 1492 log_err("parseDouble returned incorrect value, got: %g\n", valDouble); 1493 } 1494 } 1495 1496 u_uastrcpy(result, "5.06e-27"); 1497 parsepos = 0; 1498 valDouble = unum_parseDouble(fmt, result, u_strlen(result), &parsepos, &status); 1499 if (U_FAILURE(status)) { 1500 log_err("parseDouble() returned error: %s\n", myErrorName(status)); 1501 } else if (!withinErr(valDouble, 5.06e-27, 1e-15)) { 1502 log_err("parseDouble() returned incorrect value, got: %g\n", valDouble); 1503 } 1504 } 1505 unum_close(fmt); 1506 } 1507 1508 1509 static void test_fmt(UNumberFormat* fmt, UBool isDecimal) { 1510 char temp[512]; 1511 UChar buffer[512]; 1512 int32_t BUFSIZE = sizeof(buffer)/sizeof(buffer[0]); 1513 double vals[] = { 1514 -.2, 0, .2, 5.5, 15.2, 250, 123456789 1515 }; 1516 int i; 1517 1518 for (i = 0; i < sizeof(vals)/sizeof(vals[0]); ++i) { 1519 UErrorCode status = U_ZERO_ERROR; 1520 unum_formatDouble(fmt, vals[i], buffer, BUFSIZE, NULL, &status); 1521 if (U_FAILURE(status)) { 1522 log_err("failed to format: %g, returned %s\n", vals[i], u_errorName(status)); 1523 } else { 1524 u_austrcpy(temp, buffer); 1525 log_verbose("formatting %g returned '%s'\n", vals[i], temp); 1526 } 1527 } 1528 1529 /* check APIs now */ 1530 { 1531 UErrorCode status = U_ZERO_ERROR; 1532 UParseError perr; 1533 u_uastrcpy(buffer, "#,##0.0#"); 1534 unum_applyPattern(fmt, FALSE, buffer, -1, &perr, &status); 1535 if (isDecimal ? U_FAILURE(status) : (status != U_UNSUPPORTED_ERROR)) { 1536 log_err("got unexpected error for applyPattern: '%s'\n", u_errorName(status)); 1537 } 1538 } 1539 1540 { 1541 int isLenient = unum_getAttribute(fmt, UNUM_LENIENT_PARSE); 1542 log_verbose("lenient: 0x%x\n", isLenient); 1543 if (isLenient != FALSE) { 1544 log_err("didn't expect lenient value: %d\n", isLenient); 1545 } 1546 1547 unum_setAttribute(fmt, UNUM_LENIENT_PARSE, TRUE); 1548 isLenient = unum_getAttribute(fmt, UNUM_LENIENT_PARSE); 1549 if (isLenient != TRUE) { 1550 log_err("didn't expect lenient value after set: %d\n", isLenient); 1551 } 1552 } 1553 1554 { 1555 double val2; 1556 double val = unum_getDoubleAttribute(fmt, UNUM_LENIENT_PARSE); 1557 if (val != -1) { 1558 log_err("didn't expect double attribute\n"); 1559 } 1560 val = unum_getDoubleAttribute(fmt, UNUM_ROUNDING_INCREMENT); 1561 if ((val == -1) == isDecimal) { 1562 log_err("didn't expect -1 rounding increment\n"); 1563 } 1564 unum_setDoubleAttribute(fmt, UNUM_ROUNDING_INCREMENT, val+.5); 1565 val2 = unum_getDoubleAttribute(fmt, UNUM_ROUNDING_INCREMENT); 1566 if (isDecimal && (val2 - val != .5)) { 1567 log_err("set rounding increment had no effect on decimal format"); 1568 } 1569 } 1570 1571 { 1572 UErrorCode status = U_ZERO_ERROR; 1573 int len = unum_getTextAttribute(fmt, UNUM_DEFAULT_RULESET, buffer, BUFSIZE, &status); 1574 if (isDecimal ? (status != U_UNSUPPORTED_ERROR) : U_FAILURE(status)) { 1575 log_err("got unexpected error for get default ruleset: '%s'\n", u_errorName(status)); 1576 } 1577 if (U_SUCCESS(status)) { 1578 u_austrcpy(temp, buffer); 1579 log_verbose("default ruleset: '%s'\n", temp); 1580 } 1581 1582 status = U_ZERO_ERROR; 1583 len = unum_getTextAttribute(fmt, UNUM_PUBLIC_RULESETS, buffer, BUFSIZE, &status); 1584 if (isDecimal ? (status != U_UNSUPPORTED_ERROR) : U_FAILURE(status)) { 1585 log_err("got unexpected error for get public rulesets: '%s'\n", u_errorName(status)); 1586 } 1587 if (U_SUCCESS(status)) { 1588 u_austrcpy(temp, buffer); 1589 log_verbose("public rulesets: '%s'\n", temp); 1590 1591 /* set the default ruleset to the first one found, and retry */ 1592 1593 if (len > 0) { 1594 for (i = 0; i < len && temp[i] != ';'; ++i){}; 1595 if (i < len) { 1596 buffer[i] = 0; 1597 unum_setTextAttribute(fmt, UNUM_DEFAULT_RULESET, buffer, -1, &status); 1598 if (U_FAILURE(status)) { 1599 log_err("unexpected error setting default ruleset: '%s'\n", u_errorName(status)); 1600 } else { 1601 int len2 = unum_getTextAttribute(fmt, UNUM_DEFAULT_RULESET, buffer, BUFSIZE, &status); 1602 if (U_FAILURE(status)) { 1603 log_err("could not fetch default ruleset: '%s'\n", u_errorName(status)); 1604 } else if (len2 != i) { 1605 u_austrcpy(temp, buffer); 1606 log_err("unexpected ruleset len: %d ex: %d val: %s\n", len2, i, temp); 1607 } else { 1608 for (i = 0; i < sizeof(vals)/sizeof(vals[0]); ++i) { 1609 status = U_ZERO_ERROR; 1610 unum_formatDouble(fmt, vals[i], buffer, BUFSIZE, NULL, &status); 1611 if (U_FAILURE(status)) { 1612 log_err("failed to format: %g, returned %s\n", vals[i], u_errorName(status)); 1613 } else { 1614 u_austrcpy(temp, buffer); 1615 log_verbose("formatting %g returned '%s'\n", vals[i], temp); 1616 } 1617 } 1618 } 1619 } 1620 } 1621 } 1622 } 1623 } 1624 1625 { 1626 UErrorCode status = U_ZERO_ERROR; 1627 unum_toPattern(fmt, FALSE, buffer, BUFSIZE, &status); 1628 if (U_SUCCESS(status)) { 1629 u_austrcpy(temp, buffer); 1630 log_verbose("pattern: '%s'\n", temp); 1631 } else if (status != U_BUFFER_OVERFLOW_ERROR) { 1632 log_err("toPattern failed unexpectedly: %s\n", u_errorName(status)); 1633 } else { 1634 log_verbose("pattern too long to display\n"); 1635 } 1636 } 1637 1638 { 1639 UErrorCode status = U_ZERO_ERROR; 1640 int len = unum_getSymbol(fmt, UNUM_CURRENCY_SYMBOL, buffer, BUFSIZE, &status); 1641 if (isDecimal ? U_FAILURE(status) : (status != U_UNSUPPORTED_ERROR)) { 1642 log_err("unexpected error getting symbol: '%s'\n", u_errorName(status)); 1643 } 1644 1645 unum_setSymbol(fmt, UNUM_CURRENCY_SYMBOL, buffer, len, &status); 1646 if (isDecimal ? U_FAILURE(status) : (status != U_UNSUPPORTED_ERROR)) { 1647 log_err("unexpected error setting symbol: '%s'\n", u_errorName(status)); 1648 } 1649 } 1650 } 1651 1652 static void TestNonExistentCurrency() { 1653 UNumberFormat *format; 1654 UErrorCode status = U_ZERO_ERROR; 1655 UChar currencySymbol[8]; 1656 static const UChar QQQ[] = {0x51, 0x51, 0x51, 0}; 1657 1658 /* Get a non-existent currency and make sure it returns the correct currency code. */ 1659 format = unum_open(UNUM_CURRENCY, NULL, 0, "th_TH@currency=QQQ", NULL, &status); 1660 if (format == NULL || U_FAILURE(status)) { 1661 log_data_err("unum_open did not return expected result for non-existent requested currency: '%s' (Are you missing data?)\n", u_errorName(status)); 1662 } 1663 else { 1664 unum_getSymbol(format, 1665 UNUM_CURRENCY_SYMBOL, 1666 currencySymbol, 1667 sizeof(currencySymbol)/sizeof(currencySymbol[0]), 1668 &status); 1669 if (u_strcmp(currencySymbol, QQQ) != 0) { 1670 log_err("unum_open set the currency to QQQ\n"); 1671 } 1672 } 1673 unum_close(format); 1674 } 1675 1676 static void TestRBNFFormat() { 1677 UErrorCode status; 1678 UParseError perr; 1679 UChar pat[1024]; 1680 UChar tempUChars[512]; 1681 UNumberFormat *formats[5]; 1682 int COUNT = sizeof(formats)/sizeof(formats[0]); 1683 int i; 1684 1685 for (i = 0; i < COUNT; ++i) { 1686 formats[i] = 0; 1687 } 1688 1689 /* instantiation */ 1690 status = U_ZERO_ERROR; 1691 u_uastrcpy(pat, "#,##0.0#;(#,##0.0#)"); 1692 formats[0] = unum_open(UNUM_PATTERN_DECIMAL, pat, -1, "en_US", &perr, &status); 1693 if (U_FAILURE(status)) { 1694 log_err_status(status, "unable to open decimal pattern -> %s\n", u_errorName(status)); 1695 return; 1696 } 1697 1698 status = U_ZERO_ERROR; 1699 formats[1] = unum_open(UNUM_SPELLOUT, NULL, 0, "en_US", &perr, &status); 1700 if (U_FAILURE(status)) { 1701 log_err_status(status, "unable to open spellout -> %s\n", u_errorName(status)); 1702 return; 1703 } 1704 1705 status = U_ZERO_ERROR; 1706 formats[2] = unum_open(UNUM_ORDINAL, NULL, 0, "en_US", &perr, &status); 1707 if (U_FAILURE(status)) { 1708 log_err_status(status, "unable to open ordinal -> %s\n", u_errorName(status)); 1709 return; 1710 } 1711 1712 status = U_ZERO_ERROR; 1713 formats[3] = unum_open(UNUM_DURATION, NULL, 0, "en_US", &perr, &status); 1714 if (U_FAILURE(status)) { 1715 log_err_status(status, "unable to open duration %s\n", u_errorName(status)); 1716 return; 1717 } 1718 1719 status = U_ZERO_ERROR; 1720 u_uastrcpy(pat, 1721 "%standard:\n" 1722 "-x: minus >>;\n" 1723 "x.x: << point >>;\n" 1724 "zero; one; two; three; four; five; six; seven; eight; nine;\n" 1725 "ten; eleven; twelve; thirteen; fourteen; fifteen; sixteen;\n" 1726 "seventeen; eighteen; nineteen;\n" 1727 "20: twenty[->>];\n" 1728 "30: thirty[->>];\n" 1729 "40: forty[->>];\n" 1730 "50: fifty[->>];\n" 1731 "60: sixty[->>];\n" 1732 "70: seventy[->>];\n" 1733 "80: eighty[->>];\n" 1734 "90: ninety[->>];\n" 1735 "100: =#,##0=;\n"); 1736 u_uastrcpy(tempUChars, 1737 "%simple:\n" 1738 "=%standard=;\n" 1739 "20: twenty[ and change];\n" 1740 "30: thirty[ and change];\n" 1741 "40: forty[ and change];\n" 1742 "50: fifty[ and change];\n" 1743 "60: sixty[ and change];\n" 1744 "70: seventy[ and change];\n" 1745 "80: eighty[ and change];\n" 1746 "90: ninety[ and change];\n" 1747 "100: =#,##0=;\n" 1748 "%bogus:\n" 1749 "0.x: tiny;\n" 1750 "x.x: << point something;\n" 1751 "=%standard=;\n" 1752 "20: some reasonable number;\n" 1753 "100: some substantial number;\n" 1754 "100,000,000: some huge number;\n"); 1755 /* This is to get around some compiler warnings about char * string length. */ 1756 u_strcat(pat, tempUChars); 1757 formats[4] = unum_open(UNUM_PATTERN_RULEBASED, pat, -1, "en_US", &perr, &status); 1758 if (U_FAILURE(status)) { 1759 log_err_status(status, "unable to open rulebased pattern -> %s\n", u_errorName(status)); 1760 } 1761 if (U_FAILURE(status)) { 1762 log_err_status(status, "Something failed with %s\n", u_errorName(status)); 1763 return; 1764 } 1765 1766 for (i = 0; i < COUNT; ++i) { 1767 log_verbose("\n\ntesting format %d\n", i); 1768 test_fmt(formats[i], (UBool)(i == 0)); 1769 } 1770 1771 #define FORMAT_BUF_CAPACITY 64 1772 { 1773 UChar fmtbuf[FORMAT_BUF_CAPACITY]; 1774 int32_t len; 1775 double nanvalue = uprv_getNaN(); 1776 status = U_ZERO_ERROR; 1777 len = unum_formatDouble(formats[1], nanvalue, fmtbuf, FORMAT_BUF_CAPACITY, NULL, &status); 1778 if (U_FAILURE(status)) { 1779 log_err_status(status, "unum_formatDouble NAN failed with %s\n", u_errorName(status)); 1780 } else { 1781 UChar nansym[] = { 0x4E, 0x61, 0x4E, 0 }; /* NaN */ 1782 if ( len != 3 || u_strcmp(fmtbuf, nansym) != 0 ) { 1783 log_err("unum_formatDouble NAN produced wrong answer for en_US\n"); 1784 } 1785 } 1786 } 1787 1788 for (i = 0; i < COUNT; ++i) { 1789 unum_close(formats[i]); 1790 } 1791 } 1792 1793 static void TestCurrencyRegression(void) { 1794 /* 1795 I've found a case where unum_parseDoubleCurrency is not doing what I 1796 expect. The value I pass in is $1234567890q123460000.00 and this 1797 returns with a status of zero error & a parse pos of 22 (I would 1798 expect a parse error at position 11). 1799 1800 I stepped into DecimalFormat::subparse() and it looks like it parses 1801 the first 10 digits and then stops parsing at the q but doesn't set an 1802 error. Then later in DecimalFormat::parse() the value gets crammed 1803 into a long (which greatly truncates the value). 1804 1805 This is very problematic for me 'cause I try to remove chars that are 1806 invalid but this allows my users to enter bad chars and truncates 1807 their data! 1808 */ 1809 1810 UChar buf[1024]; 1811 UChar currency[8]; 1812 char acurrency[16]; 1813 double d; 1814 UNumberFormat *cur; 1815 int32_t pos; 1816 UErrorCode status = U_ZERO_ERROR; 1817 const int32_t expected = 11; 1818 1819 currency[0]=0; 1820 u_uastrcpy(buf, "$1234567890q643210000.00"); 1821 cur = unum_open(UNUM_CURRENCY, NULL,0,"en_US", NULL, &status); 1822 1823 if(U_FAILURE(status)) { 1824 log_data_err("unum_open failed: %s (Are you missing data?)\n", u_errorName(status)); 1825 return; 1826 } 1827 1828 status = U_ZERO_ERROR; /* so we can test it later. */ 1829 pos = 0; 1830 1831 d = unum_parseDoubleCurrency(cur, 1832 buf, 1833 -1, 1834 &pos, /* 0 = start */ 1835 currency, 1836 &status); 1837 1838 u_austrcpy(acurrency, currency); 1839 1840 if(U_FAILURE(status) || (pos != expected)) { 1841 log_err("unum_parseDoubleCurrency should have failed with pos %d, but gave: value %.9f, err %s, pos=%d, currency [%s]\n", 1842 expected, d, u_errorName(status), pos, acurrency); 1843 } else { 1844 log_verbose("unum_parseDoubleCurrency failed, value %.9f err %s, pos %d, currency [%s]\n", d, u_errorName(status), pos, acurrency); 1845 } 1846 1847 unum_close(cur); 1848 } 1849 1850 static void TestTextAttributeCrash(void) { 1851 UChar ubuffer[64] = {0x0049,0x004E,0x0052,0}; 1852 static const UChar expectedNeg[] = {0x0049,0x004E,0x0052,0x0031,0x0032,0x0033,0x0034,0x002E,0x0035,0}; 1853 static const UChar expectedPos[] = {0x0031,0x0032,0x0033,0x0034,0x002E,0x0035,0}; 1854 int32_t used; 1855 UErrorCode status = U_ZERO_ERROR; 1856 UNumberFormat *nf = unum_open(UNUM_CURRENCY, NULL, 0, "en_US", NULL, &status); 1857 if (U_FAILURE(status)) { 1858 log_data_err("FAILED 1 -> %s (Are you missing data?)\n", u_errorName(status)); 1859 return; 1860 } 1861 unum_setTextAttribute(nf, UNUM_CURRENCY_CODE, ubuffer, 3, &status); 1862 /* 1863 * the usual negative prefix and suffix seem to be '($' and ')' at this point 1864 * also crashes if UNUM_NEGATIVE_SUFFIX is substituted for UNUM_NEGATIVE_PREFIX here 1865 */ 1866 used = unum_getTextAttribute(nf, UNUM_NEGATIVE_PREFIX, ubuffer, 64, &status); 1867 unum_setTextAttribute(nf, UNUM_NEGATIVE_PREFIX, ubuffer, used, &status); 1868 if (U_FAILURE(status)) { 1869 log_err("FAILED 2\n"); exit(1); 1870 } 1871 log_verbose("attempting to format...\n"); 1872 used = unum_formatDouble(nf, -1234.5, ubuffer, 64, NULL, &status); 1873 if (U_FAILURE(status) || 64 < used) { 1874 log_err("Failed formatting %s\n", u_errorName(status)); 1875 return; 1876 } 1877 if (u_strcmp(expectedNeg, ubuffer) == 0) { 1878 log_err("Didn't get expected negative result\n"); 1879 } 1880 used = unum_formatDouble(nf, 1234.5, ubuffer, 64, NULL, &status); 1881 if (U_FAILURE(status) || 64 < used) { 1882 log_err("Failed formatting %s\n", u_errorName(status)); 1883 return; 1884 } 1885 if (u_strcmp(expectedPos, ubuffer) == 0) { 1886 log_err("Didn't get expected positive result\n"); 1887 } 1888 unum_close(nf); 1889 } 1890 1891 static void TestNBSPPatternRtNum(const char *testcase, UNumberFormat *nf, double myNumber) { 1892 UErrorCode status = U_ZERO_ERROR; 1893 UChar myString[20]; 1894 char tmpbuf[200]; 1895 double aNumber = -1.0; 1896 unum_formatDouble(nf, myNumber, myString, 20, NULL, &status); 1897 log_verbose("%s: formatted %.2f into %s\n", testcase, myNumber, u_austrcpy(tmpbuf, myString)); 1898 if(U_FAILURE(status)) { 1899 log_err("%s: failed format of %.2g with %s\n", testcase, myNumber, u_errorName(status)); 1900 return; 1901 } 1902 aNumber = unum_parse(nf, myString, -1, NULL, &status); 1903 if(U_FAILURE(status)) { 1904 log_err("%s: failed parse with %s\n", testcase, u_errorName(status)); 1905 return; 1906 } 1907 if(uprv_fabs(aNumber-myNumber)>.001) { 1908 log_err("FAIL: %s: formatted %.2f, parsed into %.2f\n", testcase, myNumber, aNumber); 1909 } else { 1910 log_verbose("PASS: %s: formatted %.2f, parsed into %.2f\n", testcase, myNumber, aNumber); 1911 } 1912 } 1913 1914 static void TestNBSPPatternRT(const char *testcase, UNumberFormat *nf) { 1915 TestNBSPPatternRtNum(testcase, nf, 12345.); 1916 TestNBSPPatternRtNum(testcase, nf, -12345.); 1917 } 1918 1919 static void TestNBSPInPattern(void) { 1920 UErrorCode status = U_ZERO_ERROR; 1921 UNumberFormat* nf = NULL; 1922 const char *testcase; 1923 1924 1925 testcase="ar_AE UNUM_CURRENCY"; 1926 nf = unum_open(UNUM_CURRENCY, NULL, -1, "ar_AE", NULL, &status); 1927 if(U_FAILURE(status) || nf == NULL) { 1928 log_data_err("%s: unum_open failed with %s (Are you missing data?)\n", testcase, u_errorName(status)); 1929 return; 1930 } 1931 TestNBSPPatternRT(testcase, nf); 1932 1933 /* if we don't have CLDR 1.6 data, bring out the problem anyways */ 1934 { 1935 #define SPECIAL_PATTERN "\\u00A4\\u00A4'\\u062f.\\u0625.\\u200f\\u00a0'###0.00" 1936 UChar pat[200]; 1937 testcase = "ar_AE special pattern: " SPECIAL_PATTERN; 1938 u_unescape(SPECIAL_PATTERN, pat, sizeof(pat)/sizeof(pat[0])); 1939 unum_applyPattern(nf, FALSE, pat, -1, NULL, &status); 1940 if(U_FAILURE(status)) { 1941 log_err("%s: unum_applyPattern failed with %s\n", testcase, u_errorName(status)); 1942 } else { 1943 TestNBSPPatternRT(testcase, nf); 1944 } 1945 #undef SPECIAL_PATTERN 1946 } 1947 unum_close(nf); status = U_ZERO_ERROR; 1948 1949 testcase="ar_AE UNUM_DECIMAL"; 1950 nf = unum_open(UNUM_DECIMAL, NULL, -1, "ar_AE", NULL, &status); 1951 if(U_FAILURE(status)) { 1952 log_err("%s: unum_open failed with %s\n", testcase, u_errorName(status)); 1953 } 1954 TestNBSPPatternRT(testcase, nf); 1955 unum_close(nf); status = U_ZERO_ERROR; 1956 1957 testcase="ar_AE UNUM_PERCENT"; 1958 nf = unum_open(UNUM_PERCENT, NULL, -1, "ar_AE", NULL, &status); 1959 if(U_FAILURE(status)) { 1960 log_err("%s: unum_open failed with %s\n", testcase, u_errorName(status)); 1961 } 1962 TestNBSPPatternRT(testcase, nf); 1963 unum_close(nf); status = U_ZERO_ERROR; 1964 1965 1966 1967 } 1968 1969 #endif /* #if !UCONFIG_NO_FORMATTING */ 1970