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