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