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