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