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