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