1 /*********************************************************************** 2 * COPYRIGHT: 3 * Copyright (c) 1997-2009, International Business Machines Corporation 4 * and others. All Rights Reserved. 5 ***********************************************************************/ 6 7 #include "unicode/utypes.h" 8 9 #if !UCONFIG_NO_FORMATTING 10 11 #include "msfmrgts.h" 12 13 #include "unicode/format.h" 14 #include "unicode/decimfmt.h" 15 #include "unicode/locid.h" 16 #include "unicode/msgfmt.h" 17 #include "unicode/numfmt.h" 18 #include "unicode/choicfmt.h" 19 #include "unicode/gregocal.h" 20 #include "putilimp.h" 21 22 // ***************************************************************************** 23 // class MessageFormatRegressionTest 24 // ***************************************************************************** 25 26 #define CASE(id,test) case id: name = #test; if (exec) { logln(#test "---"); logln((UnicodeString)""); test(); } break; 27 28 void 29 MessageFormatRegressionTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ ) 30 { 31 // if (exec) logln((UnicodeString)"TestSuite MessageFormatRegressionTest"); 32 switch (index) { 33 CASE(0,Test4074764) 34 CASE(1,Test4058973) 35 CASE(2,Test4031438) 36 CASE(3,Test4052223) 37 CASE(4,Test4104976) 38 CASE(5,Test4106659) 39 CASE(6,Test4106660) 40 CASE(7,Test4111739) 41 CASE(8,Test4114743) 42 CASE(9,Test4116444) 43 CASE(10,Test4114739) 44 CASE(11,Test4113018) 45 CASE(12,Test4106661) 46 CASE(13,Test4094906) 47 CASE(14,Test4118592) 48 CASE(15,Test4118594) 49 CASE(16,Test4105380) 50 CASE(17,Test4120552) 51 CASE(18,Test4142938) 52 CASE(19,TestChoicePatternQuote) 53 CASE(20,Test4112104) 54 55 default: name = ""; break; 56 } 57 } 58 59 UBool 60 MessageFormatRegressionTest::failure(UErrorCode status, const char* msg, UBool possibleDataError) 61 { 62 if(U_FAILURE(status)) { 63 if (possibleDataError) { 64 dataerrln(UnicodeString("FAIL: ") + msg + " failed, error " + u_errorName(status)); 65 } else { 66 errln(UnicodeString("FAIL: ") + msg + " failed, error " + u_errorName(status)); 67 } 68 return TRUE; 69 } 70 71 return FALSE; 72 } 73 74 /* @bug 4074764 75 * Null exception when formatting pattern with MessageFormat 76 * with no parameters. 77 */ 78 void MessageFormatRegressionTest::Test4074764() { 79 UnicodeString pattern [] = { 80 "Message without param", 81 "Message with param:{0}", 82 "Longer Message with param {0}" 83 }; 84 //difference between the two param strings are that 85 //in the first one, the param position is within the 86 //length of the string without param while it is not so 87 //in the other case. 88 89 UErrorCode status = U_ZERO_ERROR; 90 MessageFormat *messageFormatter = new MessageFormat("", status); 91 92 failure(status, "couldn't create MessageFormat"); 93 94 //try { 95 //Apply pattern with param and print the result 96 messageFormatter->applyPattern(pattern[1], status); 97 failure(status, "messageFormat->applyPattern"); 98 //Object[] params = {new UnicodeString("BUG"), new Date()}; 99 Formattable params [] = { 100 Formattable(UnicodeString("BUG")), 101 Formattable(0, Formattable::kIsDate) 102 }; 103 UnicodeString tempBuffer; 104 FieldPosition pos(FieldPosition::DONT_CARE); 105 tempBuffer = messageFormatter->format(params, 2, tempBuffer, pos, status); 106 if( tempBuffer != "Message with param:BUG" || failure(status, "messageFormat->format")) 107 errln("MessageFormat with one param test failed."); 108 logln("Formatted with one extra param : " + tempBuffer); 109 110 //Apply pattern without param and print the result 111 messageFormatter->applyPattern(pattern[0], status); 112 failure(status, "messageFormatter->applyPattern"); 113 114 // {sfb} how much does this apply in C++? 115 // do we want to verify that the Formattable* array is not NULL, 116 // or is that the user's responsibility? 117 // additionally, what should be the item count? 118 // for bug testing purposes, assume that something was set to 119 // NULL by mistake, and that the length should be non-zero 120 121 //tempBuffer = messageFormatter->format(NULL, 1, tempBuffer, FieldPosition(FieldPosition::DONT_CARE), status); 122 tempBuffer.remove(); 123 tempBuffer = messageFormatter->format(NULL, 0, tempBuffer, pos, status); 124 125 if( tempBuffer != "Message without param" || failure(status, "messageFormat->format")) 126 errln("MessageFormat with no param test failed."); 127 logln("Formatted with no params : " + tempBuffer); 128 129 tempBuffer.remove(); 130 tempBuffer = messageFormatter->format(params, 2, tempBuffer, pos, status); 131 if (tempBuffer != "Message without param" || failure(status, "messageFormat->format")) 132 errln("Formatted with arguments > subsitution failed. result = " + tempBuffer); 133 logln("Formatted with extra params : " + tempBuffer); 134 //This statement gives an exception while formatting... 135 //If we use pattern[1] for the message with param, 136 //we get an NullPointerException in MessageFormat.java(617) 137 //If we use pattern[2] for the message with param, 138 //we get an StringArrayIndexOutOfBoundsException in MessageFormat.java(614) 139 //Both are due to maxOffset not being reset to -1 140 //in applyPattern() when the pattern does not 141 //contain any param. 142 /*} catch (Exception foo) { 143 errln("Exception when formatting with no params."); 144 }*/ 145 146 delete messageFormatter; 147 } 148 149 /* @bug 4058973 150 * MessageFormat.toPattern has weird rounding behavior. 151 */ 152 void MessageFormatRegressionTest::Test4058973() 153 { 154 UErrorCode status = U_ZERO_ERROR; 155 MessageFormat *fmt = new MessageFormat("{0,choice,0#no files|1#one file|1< {0,number,integer} files}", status); 156 failure(status, "new MessageFormat"); 157 158 UnicodeString pat; 159 pat = fmt->toPattern(pat); 160 UnicodeString exp("{0,choice,0#no files|1#one file|1< {0,number,integer} files}"); 161 if (pat != exp) { 162 errln("MessageFormat.toPattern failed"); 163 errln("Exp: " + exp); 164 errln("Got: " + pat); 165 } 166 167 delete fmt; 168 } 169 /* @bug 4031438 170 * More robust message formats. 171 */ 172 void MessageFormatRegressionTest::Test4031438() 173 { 174 UErrorCode status = U_ZERO_ERROR; 175 176 UnicodeString pattern1("Impossible {1} has occurred -- status code is {0} and message is {2}."); 177 UnicodeString pattern2("Double '' Quotes {0} test and quoted '{1}' test plus 'other {2} stuff'."); 178 179 MessageFormat *messageFormatter = new MessageFormat("", status); 180 failure(status, "new MessageFormat"); 181 182 const UBool possibleDataError = TRUE; 183 184 //try { 185 logln("Apply with pattern : " + pattern1); 186 messageFormatter->applyPattern(pattern1, status); 187 failure(status, "messageFormat->applyPattern"); 188 //Object[] params = {new Integer(7)}; 189 Formattable params []= { 190 Formattable((int32_t)7) 191 }; 192 UnicodeString tempBuffer; 193 FieldPosition pos(FieldPosition::DONT_CARE); 194 tempBuffer = messageFormatter->format(params, 1, tempBuffer, pos, status); 195 if(tempBuffer != "Impossible {1} has occurred -- status code is 7 and message is {2}." || failure(status, "MessageFormat::format")) 196 dataerrln("Tests arguments < substitution failed"); 197 logln("Formatted with 7 : " + tempBuffer); 198 ParsePosition pp(0); 199 int32_t count = 0; 200 Formattable *objs = messageFormatter->parse(tempBuffer, pp, count); 201 //if(objs[7/*params.length*/] != NULL) 202 // errln("Parse failed with more than expected arguments"); 203 204 NumberFormat *fmt = 0; 205 UnicodeString temp, temp1; 206 207 for (int i = 0; i < count; i++) { 208 209 // convert to string if not already 210 Formattable obj = objs[i]; 211 temp.remove(); 212 if(obj.getType() == Formattable::kString) 213 temp = obj.getString(temp); 214 else { 215 fmt = NumberFormat::createInstance(status); 216 switch (obj.getType()) { 217 case Formattable::kLong: fmt->format(obj.getLong(), temp); break; 218 case Formattable::kInt64: fmt->format(obj.getInt64(), temp); break; 219 case Formattable::kDouble: fmt->format(obj.getDouble(), temp); break; 220 default: break; 221 } 222 } 223 224 // convert to string if not already 225 Formattable obj1 = params[i]; 226 temp1.remove(); 227 if(obj1.getType() == Formattable::kString) 228 temp1 = obj1.getString(temp1); 229 else { 230 fmt = NumberFormat::createInstance(status); 231 switch (obj1.getType()) { 232 case Formattable::kLong: fmt->format(obj1.getLong(), temp1); break; 233 case Formattable::kInt64: fmt->format(obj1.getInt64(), temp1); break; 234 case Formattable::kDouble: fmt->format(obj1.getDouble(), temp1); break; 235 default: break; 236 } 237 } 238 239 //if (objs[i] != NULL && objs[i].getString(temp1) != params[i].getString(temp2)) { 240 if (temp != temp1) { 241 errln("Parse failed on object " + objs[i].getString(temp1) + " at index : " + i); 242 } 243 } 244 245 delete fmt; 246 delete [] objs; 247 248 // {sfb} does this apply? no way to really pass a null Formattable, 249 // only a null array 250 251 /*tempBuffer = messageFormatter->format(null, tempBuffer, FieldPosition(FieldPosition::DONT_CARE), status); 252 if (tempBuffer != "Impossible {1} has occurred -- status code is {0} and message is {2}." || failure(status, "messageFormat->format")) 253 errln("Tests with no arguments failed"); 254 logln("Formatted with null : " + tempBuffer);*/ 255 logln("Apply with pattern : " + pattern2); 256 messageFormatter->applyPattern(pattern2, status); 257 failure(status, "messageFormatter->applyPattern", possibleDataError); 258 tempBuffer.remove(); 259 tempBuffer = messageFormatter->format(params, 1, tempBuffer, pos, status); 260 if (tempBuffer != "Double ' Quotes 7 test and quoted {1} test plus other {2} stuff.") 261 dataerrln("quote format test (w/ params) failed. - %s", u_errorName(status)); 262 logln("Formatted with params : " + tempBuffer); 263 264 /*tempBuffer = messageFormatter->format(null); 265 if (!tempBuffer.equals("Double ' Quotes {0} test and quoted {1} test plus other {2} stuff.")) 266 errln("quote format test (w/ null) failed."); 267 logln("Formatted with null : " + tempBuffer); 268 logln("toPattern : " + messageFormatter.toPattern());*/ 269 /*} catch (Exception foo) { 270 errln("Exception when formatting in bug 4031438. "+foo.getMessage()); 271 }*/ 272 delete messageFormatter; 273 } 274 275 void MessageFormatRegressionTest::Test4052223() 276 { 277 278 ParsePosition pos(0); 279 if (pos.getErrorIndex() != -1) { 280 errln("ParsePosition.getErrorIndex initialization failed."); 281 } 282 283 UErrorCode status = U_ZERO_ERROR; 284 MessageFormat *fmt = new MessageFormat("There are {0} apples growing on the {1} tree.", status); 285 failure(status, "new MessageFormat"); 286 UnicodeString str("There is one apple growing on the peach tree."); 287 288 int32_t count = 0; 289 fmt->parse(str, pos, count); 290 291 logln(UnicodeString("unparsable string , should fail at ") + pos.getErrorIndex()); 292 if (pos.getErrorIndex() == -1) 293 errln("Bug 4052223 failed : parsing string " + str); 294 pos.setErrorIndex(4); 295 if (pos.getErrorIndex() != 4) 296 errln(UnicodeString("setErrorIndex failed, got ") + pos.getErrorIndex() + " instead of 4"); 297 298 ChoiceFormat *f = new ChoiceFormat( 299 "-1#are negative|0#are no or fraction|1#is one|1.0<is 1+|2#are two|2<are more than 2.", status); 300 failure(status, "new ChoiceFormat"); 301 pos.setIndex(0); 302 pos.setErrorIndex(-1); 303 Formattable obj; 304 f->parse("are negative", obj, pos); 305 if (pos.getErrorIndex() != -1 && obj.getDouble() == -1.0) 306 errln(UnicodeString("Parse with \"are negative\" failed, at ") + pos.getErrorIndex()); 307 pos.setIndex(0); 308 pos.setErrorIndex(-1); 309 f->parse("are no or fraction ", obj, pos); 310 if (pos.getErrorIndex() != -1 && obj.getDouble() == 0.0) 311 errln(UnicodeString("Parse with \"are no or fraction\" failed, at ") + pos.getErrorIndex()); 312 pos.setIndex(0); 313 pos.setErrorIndex(-1); 314 f->parse("go postal", obj, pos); 315 if (pos.getErrorIndex() == -1 && ! uprv_isNaN(obj.getDouble())) 316 errln(UnicodeString("Parse with \"go postal\" failed, at ") + pos.getErrorIndex()); 317 318 delete fmt; 319 delete f; 320 } 321 /* @bug 4104976 322 * ChoiceFormat.equals(null) throws NullPointerException 323 */ 324 325 // {sfb} not really applicable in C++?? (kind of silly) 326 327 void MessageFormatRegressionTest::Test4104976() 328 { 329 double limits [] = {1, 20}; 330 UnicodeString formats [] = { 331 UnicodeString("xyz"), 332 UnicodeString("abc") 333 }; 334 int32_t formats_length = (int32_t)(sizeof(formats)/sizeof(formats[0])); 335 UErrorCode status = U_ZERO_ERROR; 336 ChoiceFormat *cf = new ChoiceFormat(limits, formats, formats_length); 337 failure(status, "new ChoiceFormat"); 338 //try { 339 log("Compares to null is always false, returned : "); 340 logln(cf == NULL ? "TRUE" : "FALSE"); 341 /*} catch (Exception foo) { 342 errln("ChoiceFormat.equals(null) throws exception."); 343 }*/ 344 345 delete cf; 346 } 347 348 /* @bug 4106659 349 * ChoiceFormat.ctor(double[], String[]) doesn't check 350 * whether lengths of input arrays are equal. 351 */ 352 353 // {sfb} again, not really applicable in C++ 354 355 void MessageFormatRegressionTest::Test4106659() 356 { 357 /* 358 double limits [] = { 359 1, 2, 3 360 }; 361 UnicodeString formats [] = { 362 "one", "two" 363 }; 364 ChoiceFormat *cf = NULL; 365 //try { 366 // cf = new ChoiceFormat(limits, formats, 3); 367 //} catch (Exception foo) { 368 // logln("ChoiceFormat constructor should check for the array lengths"); 369 // cf = null; 370 //} 371 //if (cf != null) 372 // errln(cf->format(5)); 373 // 374 delete cf; 375 */ 376 } 377 378 /* @bug 4106660 379 * ChoiceFormat.ctor(double[], String[]) allows unordered double array. 380 * This is not a bug, added javadoc to emphasize the use of limit 381 * array must be in ascending order. 382 */ 383 void MessageFormatRegressionTest::Test4106660() 384 { 385 double limits [] = {3, 1, 2}; 386 UnicodeString formats [] = { 387 UnicodeString("Three"), 388 UnicodeString("One"), 389 UnicodeString("Two") 390 }; 391 ChoiceFormat *cf = new ChoiceFormat(limits, formats, 3); 392 double d = 5.0; 393 UnicodeString str; 394 FieldPosition pos(FieldPosition::DONT_CARE); 395 str = cf->format(d, str, pos); 396 if (str != "Two") 397 errln( (UnicodeString) "format(" + d + ") = " + str); 398 399 delete cf; 400 } 401 402 /* @bug 4111739 403 * MessageFormat is incorrectly serialized/deserialized. 404 */ 405 406 // {sfb} doesn't apply in C++ 407 408 void MessageFormatRegressionTest::Test4111739() 409 { 410 /*MessageFormat format1 = null; 411 MessageFormat format2 = null; 412 ObjectOutputStream ostream = null; 413 ByteArrayOutputStream baos = null; 414 ObjectInputStream istream = null; 415 416 try { 417 baos = new ByteArrayOutputStream(); 418 ostream = new ObjectOutputStream(baos); 419 } catch(IOException e) { 420 errln("Unexpected exception : " + e.getMessage()); 421 return; 422 } 423 424 try { 425 format1 = new MessageFormat("pattern{0}"); 426 ostream.writeObject(format1); 427 ostream.flush(); 428 429 byte bytes[] = baos.toByteArray(); 430 431 istream = new ObjectInputStream(new ByteArrayInputStream(bytes)); 432 format2 = (MessageFormat)istream.readObject(); 433 } catch(Exception e) { 434 errln("Unexpected exception : " + e.getMessage()); 435 } 436 437 if (!format1.equals(format2)) { 438 errln("MessageFormats before and after serialization are not" + 439 " equal\nformat1 = " + format1 + "(" + format1.toPattern() + ")\nformat2 = " + 440 format2 + "(" + format2.toPattern() + ")"); 441 } else { 442 logln("Serialization for MessageFormat is OK."); 443 }*/ 444 } 445 /* @bug 4114743 446 * MessageFormat.applyPattern allows illegal patterns. 447 */ 448 void MessageFormatRegressionTest::Test4114743() 449 { 450 UnicodeString originalPattern("initial pattern"); 451 UErrorCode status = U_ZERO_ERROR; 452 MessageFormat *mf = new MessageFormat(originalPattern, status); 453 failure(status, "new MessageFormat"); 454 //try { 455 UnicodeString illegalPattern("ab { '}' de"); 456 mf->applyPattern(illegalPattern, status); 457 if( ! U_FAILURE(status)) 458 errln("illegal pattern: \"" + illegalPattern + "\""); 459 /*} catch (IllegalArgumentException foo) { 460 if (!originalPattern.equals(mf.toPattern())) 461 errln("pattern after: \"" + mf.toPattern() + "\""); 462 }*/ 463 delete mf; 464 } 465 466 /* @bug 4116444 467 * MessageFormat.parse has different behavior in case of null. 468 */ 469 void MessageFormatRegressionTest::Test4116444() 470 { 471 UnicodeString patterns [] = { 472 (UnicodeString)"", 473 (UnicodeString)"one", 474 (UnicodeString) "{0,date,short}" 475 }; 476 477 UErrorCode status = U_ZERO_ERROR; 478 MessageFormat *mf = new MessageFormat("", status); 479 failure(status, "new MessageFormat"); 480 481 for (int i = 0; i < 3; i++) { 482 UnicodeString pattern = patterns[i]; 483 mf->applyPattern(pattern, status); 484 failure(status, "mf->applyPattern", TRUE); 485 486 //try { 487 int32_t count = 0; 488 ParsePosition pp(0); 489 Formattable *array = mf->parse(UnicodeString(""), pp, count); 490 logln("pattern: \"" + pattern + "\""); 491 log(" parsedObjects: "); 492 if (array != NULL) { 493 log("{"); 494 for (int j = 0; j < count; j++) { 495 //if (array[j] != null) 496 UnicodeString dummy; 497 err("\"" + array[j].getString(dummy) + "\""); 498 //else 499 // log("null"); 500 if (j < count- 1) 501 log(","); 502 } 503 log("}") ; 504 delete[] array; 505 } else { 506 log("null"); 507 } 508 logln(""); 509 /*} catch (Exception e) { 510 errln("pattern: \"" + pattern + "\""); 511 errln(" Exception: " + e.getMessage()); 512 }*/ 513 } 514 515 delete mf; 516 } 517 /* @bug 4114739 (FIX and add javadoc) 518 * MessageFormat.format has undocumented behavior about empty format objects. 519 */ 520 521 // {sfb} doesn't apply in C++? 522 void MessageFormatRegressionTest::Test4114739() 523 { 524 525 UErrorCode status = U_ZERO_ERROR; 526 MessageFormat *mf = new MessageFormat("<{0}>", status); 527 failure(status, "new MessageFormat"); 528 529 Formattable *objs1 = NULL; 530 //Formattable objs2 [] = {}; 531 //Formattable *objs3 [] = {NULL}; 532 //try { 533 UnicodeString pat; 534 UnicodeString res; 535 logln("pattern: \"" + mf->toPattern(pat) + "\""); 536 log("format(null) : "); 537 FieldPosition pos(FieldPosition::DONT_CARE); 538 logln("\"" + mf->format(objs1, 0, res, pos, status) + "\""); 539 failure(status, "mf->format"); 540 /*log("format({}) : "); 541 logln("\"" + mf->format(objs2, 0, res, FieldPosition(FieldPosition::DONT_CARE), status) + "\""); 542 failure(status, "mf->format"); 543 log("format({null}) :"); 544 logln("\"" + mf->format(objs3, 0, res, FieldPosition(FieldPosition::DONT_CARE), status) + "\""); 545 failure(status, "mf->format");*/ 546 /*} catch (Exception e) { 547 errln("Exception thrown for null argument tests."); 548 }*/ 549 550 delete mf; 551 } 552 553 /* @bug 4113018 554 * MessageFormat.applyPattern works wrong with illegal patterns. 555 */ 556 void MessageFormatRegressionTest::Test4113018() 557 { 558 UnicodeString originalPattern("initial pattern"); 559 UErrorCode status = U_ZERO_ERROR; 560 MessageFormat *mf = new MessageFormat(originalPattern, status); 561 failure(status, "new messageFormat"); 562 UnicodeString illegalPattern("format: {0, xxxYYY}"); 563 UnicodeString pat; 564 logln("pattern before: \"" + mf->toPattern(pat) + "\""); 565 logln("illegal pattern: \"" + illegalPattern + "\""); 566 //try { 567 mf->applyPattern(illegalPattern, status); 568 if( ! U_FAILURE(status)) 569 errln("Should have thrown IllegalArgumentException for pattern : " + illegalPattern); 570 /*} catch (IllegalArgumentException e) { 571 if (!originalPattern.equals(mf.toPattern())) 572 errln("pattern after: \"" + mf.toPattern() + "\""); 573 }*/ 574 delete mf; 575 } 576 577 /* @bug 4106661 578 * ChoiceFormat is silent about the pattern usage in javadoc. 579 */ 580 void MessageFormatRegressionTest::Test4106661() 581 { 582 UErrorCode status = U_ZERO_ERROR; 583 ChoiceFormat *fmt = new ChoiceFormat( 584 "-1#are negative| 0#are no or fraction | 1#is one |1.0<is 1+ |2#are two |2<are more than 2.", status); 585 failure(status, "new ChoiceFormat"); 586 UnicodeString pat; 587 logln("Formatter Pattern : " + fmt->toPattern(pat)); 588 589 FieldPosition bogus(FieldPosition::DONT_CARE); 590 UnicodeString str; 591 592 // Will this work for -inf? 593 logln("Format with -INF : " + fmt->format(Formattable(-uprv_getInfinity()), str, bogus, status)); 594 failure(status, "fmt->format"); 595 str.remove(); 596 logln("Format with -1.0 : " + fmt->format(Formattable(-1.0), str, bogus, status)); 597 failure(status, "fmt->format"); 598 str.remove(); 599 logln("Format with -1.0 : " + fmt->format(Formattable(-1.0), str, bogus, status)); 600 failure(status, "fmt->format"); 601 str.remove(); 602 logln("Format with 0 : " + fmt->format(Formattable((int32_t)0), str, bogus, status)); 603 failure(status, "fmt->format"); 604 str.remove(); 605 logln("Format with 0.9 : " + fmt->format(Formattable(0.9), str, bogus, status)); 606 failure(status, "fmt->format"); 607 str.remove(); 608 logln("Format with 1.0 : " + fmt->format(Formattable(1.0), str, bogus, status)); 609 failure(status, "fmt->format"); 610 str.remove(); 611 logln("Format with 1.5 : " + fmt->format(Formattable(1.5), str, bogus, status)); 612 failure(status, "fmt->format"); 613 str.remove(); 614 logln("Format with 2 : " + fmt->format(Formattable((int32_t)2), str, bogus, status)); 615 failure(status, "fmt->format"); 616 str.remove(); 617 logln("Format with 2.1 : " + fmt->format(Formattable(2.1), str, bogus, status)); 618 failure(status, "fmt->format"); 619 str.remove(); 620 logln("Format with NaN : " + fmt->format(Formattable(uprv_getNaN()), str, bogus, status)); 621 failure(status, "fmt->format"); 622 str.remove(); 623 logln("Format with +INF : " + fmt->format(Formattable(uprv_getInfinity()), str, bogus, status)); 624 failure(status, "fmt->format"); 625 626 delete fmt; 627 } 628 629 /* @bug 4094906 630 * ChoiceFormat should accept \u221E as eq. to INF. 631 */ 632 void MessageFormatRegressionTest::Test4094906() 633 { 634 UErrorCode status = U_ZERO_ERROR; 635 UnicodeString pattern("-"); 636 pattern += (UChar) 0x221E; 637 pattern += "<are negative|0<are no or fraction|1#is one|1<is 1+|"; 638 pattern += (UChar) 0x221E; 639 pattern += "<are many."; 640 641 ChoiceFormat *fmt = new ChoiceFormat(pattern, status); 642 failure(status, "new ChoiceFormat"); 643 UnicodeString pat; 644 if (fmt->toPattern(pat) != pattern) { 645 errln( (UnicodeString) "Formatter Pattern : " + pat); 646 errln( (UnicodeString) "Expected Pattern : " + pattern); 647 } 648 FieldPosition bogus(FieldPosition::DONT_CARE); 649 UnicodeString str; 650 651 // Will this work for -inf? 652 logln("Format with -INF : " + fmt->format(Formattable(-uprv_getInfinity()), str, bogus, status)); 653 failure(status, "fmt->format"); 654 str.remove(); 655 logln("Format with -1.0 : " + fmt->format(Formattable(-1.0), str, bogus, status)); 656 failure(status, "fmt->format"); 657 str.remove(); 658 logln("Format with -1.0 : " + fmt->format(Formattable(-1.0), str, bogus, status)); 659 failure(status, "fmt->format"); 660 str.remove(); 661 logln("Format with 0 : " + fmt->format(Formattable((int32_t)0), str, bogus, status)); 662 failure(status, "fmt->format"); 663 str.remove(); 664 logln("Format with 0.9 : " + fmt->format(Formattable(0.9), str, bogus, status)); 665 failure(status, "fmt->format"); 666 str.remove(); 667 logln("Format with 1.0 : " + fmt->format(Formattable(1.0), str, bogus, status)); 668 failure(status, "fmt->format"); 669 str.remove(); 670 logln("Format with 1.5 : " + fmt->format(Formattable(1.5), str, bogus, status)); 671 failure(status, "fmt->format"); 672 str.remove(); 673 logln("Format with 2 : " + fmt->format(Formattable((int32_t)2), str, bogus, status)); 674 failure(status, "fmt->format"); 675 str.remove(); 676 logln("Format with 2.1 : " + fmt->format(Formattable(2.1), str, bogus, status)); 677 failure(status, "fmt->format"); 678 str.remove(); 679 logln("Format with NaN : " + fmt->format(Formattable(uprv_getNaN()), str, bogus, status)); 680 failure(status, "fmt->format"); 681 str.remove(); 682 logln("Format with +INF : " + fmt->format(Formattable(uprv_getInfinity()), str, bogus, status)); 683 failure(status, "fmt->format"); 684 685 delete fmt; 686 } 687 688 /* @bug 4118592 689 * MessageFormat.parse fails with ChoiceFormat. 690 */ 691 void MessageFormatRegressionTest::Test4118592() 692 { 693 UErrorCode status = U_ZERO_ERROR; 694 MessageFormat *mf = new MessageFormat("", status); 695 failure(status, "new messageFormat"); 696 UnicodeString pattern("{0,choice,1#YES|2#NO}"); 697 UnicodeString prefix(""); 698 Formattable *objs = 0; 699 700 for (int i = 0; i < 5; i++) { 701 UnicodeString formatted; 702 formatted = prefix + "YES"; 703 mf->applyPattern(prefix + pattern, status); 704 failure(status, "mf->applyPattern"); 705 prefix += "x"; 706 //Object[] objs = mf.parse(formatted, new ParsePosition(0)); 707 int32_t count = 0; 708 ParsePosition pp(0); 709 objs = mf->parse(formatted, pp, count); 710 UnicodeString pat; 711 logln(UnicodeString("") + i + ". pattern :\"" + mf->toPattern(pat) + "\""); 712 log(" \"" + formatted + "\" parsed as "); 713 if (objs == NULL) 714 logln(" null"); 715 else { 716 UnicodeString temp; 717 if(objs[0].getType() == Formattable::kString) 718 logln((UnicodeString)" " + objs[0].getString(temp)); 719 else 720 logln((UnicodeString)" " + (objs[0].getType() == Formattable::kLong ? objs[0].getLong() : objs[0].getDouble())); 721 delete[] objs; 722 723 } 724 } 725 726 delete mf; 727 } 728 /* @bug 4118594 729 * MessageFormat.parse fails for some patterns. 730 */ 731 void MessageFormatRegressionTest::Test4118594() 732 { 733 UErrorCode status = U_ZERO_ERROR; 734 const UBool possibleDataError = TRUE; 735 MessageFormat *mf = new MessageFormat("{0}, {0}, {0}", status); 736 failure(status, "new MessageFormat"); 737 UnicodeString forParsing("x, y, z"); 738 //Object[] objs = mf.parse(forParsing, new ParsePosition(0)); 739 int32_t count = 0; 740 ParsePosition pp(0); 741 Formattable *objs = mf->parse(forParsing, pp, count); 742 UnicodeString pat; 743 logln("pattern: \"" + mf->toPattern(pat) + "\""); 744 logln("text for parsing: \"" + forParsing + "\""); 745 UnicodeString str; 746 if (objs[0].getString(str) != "z") 747 errln("argument0: \"" + objs[0].getString(str) + "\""); 748 mf->applyPattern("{0,number,#.##}, {0,number,#.#}", status); 749 failure(status, "mf->applyPattern", possibleDataError); 750 //Object[] oldobjs = {new Double(3.1415)}; 751 Formattable oldobjs [] = {Formattable(3.1415)}; 752 UnicodeString result; 753 FieldPosition pos(FieldPosition::DONT_CARE); 754 result = mf->format( oldobjs, 1, result, pos, status ); 755 failure(status, "mf->format", possibleDataError); 756 pat.remove(); 757 logln("pattern: \"" + mf->toPattern(pat) + "\""); 758 logln("text for parsing: \"" + result + "\""); 759 // result now equals "3.14, 3.1" 760 if (result != "3.14, 3.1") 761 dataerrln("result = " + result + " - " + u_errorName(status)); 762 //Object[] newobjs = mf.parse(result, new ParsePosition(0)); 763 int32_t count1 = 0; 764 pp.setIndex(0); 765 Formattable *newobjs = mf->parse(result, pp, count1); 766 // newobjs now equals {new Double(3.1)} 767 if (newobjs == NULL) { 768 dataerrln("Error calling MessageFormat::parse"); 769 } else { 770 if (newobjs[0].getDouble() != 3.1) 771 errln( UnicodeString("newobjs[0] = ") + newobjs[0].getDouble()); 772 } 773 774 delete [] objs; 775 delete [] newobjs; 776 delete mf; 777 } 778 /* @bug 4105380 779 * When using ChoiceFormat, MessageFormat is not good for I18n. 780 */ 781 void MessageFormatRegressionTest::Test4105380() 782 { 783 UnicodeString patternText1("The disk \"{1}\" contains {0}."); 784 UnicodeString patternText2("There are {0} on the disk \"{1}\""); 785 UErrorCode status = U_ZERO_ERROR; 786 const UBool possibleDataError = TRUE; 787 MessageFormat *form1 = new MessageFormat(patternText1, status); 788 failure(status, "new MessageFormat"); 789 MessageFormat *form2 = new MessageFormat(patternText2, status); 790 failure(status, "new MessageFormat"); 791 double filelimits [] = {0,1,2}; 792 UnicodeString filepart [] = { 793 (UnicodeString)"no files", 794 (UnicodeString)"one file", 795 (UnicodeString)"{0,number} files" 796 }; 797 ChoiceFormat *fileform = new ChoiceFormat(filelimits, filepart, 3); 798 form1->setFormat(1, *fileform); 799 form2->setFormat(0, *fileform); 800 //Object[] testArgs = {new Long(12373), "MyDisk"}; 801 Formattable testArgs [] = { 802 Formattable((int32_t)12373), 803 Formattable((UnicodeString)"MyDisk") 804 }; 805 806 FieldPosition bogus(FieldPosition::DONT_CARE); 807 808 UnicodeString result; 809 logln(form1->format(testArgs, 2, result, bogus, status)); 810 failure(status, "form1->format", possibleDataError); 811 result.remove(); 812 logln(form2->format(testArgs, 2, result, bogus, status)); 813 failure(status, "form1->format", possibleDataError); 814 815 delete form1; 816 delete form2; 817 delete fileform; 818 } 819 /* @bug 4120552 820 * MessageFormat.parse incorrectly sets errorIndex. 821 */ 822 void MessageFormatRegressionTest::Test4120552() 823 { 824 UErrorCode status = U_ZERO_ERROR; 825 MessageFormat *mf = new MessageFormat("pattern", status); 826 failure(status, "new MessageFormat"); 827 UnicodeString texts[] = { 828 (UnicodeString)"pattern", 829 (UnicodeString)"pat", 830 (UnicodeString)"1234" 831 }; 832 UnicodeString pat; 833 logln("pattern: \"" + mf->toPattern(pat) + "\""); 834 for (int i = 0; i < 3; i++) { 835 ParsePosition pp(0); 836 //Object[] objs = mf.parse(texts[i], pp); 837 int32_t count = 0; 838 Formattable *objs = mf->parse(texts[i], pp, count); 839 log(" text for parsing: \"" + texts[i] + "\""); 840 if (objs == NULL) { 841 logln(" (incorrectly formatted string)"); 842 if (pp.getErrorIndex() == -1) 843 errln(UnicodeString("Incorrect error index: ") + pp.getErrorIndex()); 844 } else { 845 logln(" (correctly formatted string)"); 846 delete[] objs; 847 } 848 } 849 delete mf; 850 } 851 852 /** 853 * @bug 4142938 854 * MessageFormat handles single quotes in pattern wrong. 855 * This is actually a problem in ChoiceFormat; it doesn't 856 * understand single quotes. 857 */ 858 void MessageFormatRegressionTest::Test4142938() 859 { 860 UnicodeString pat = CharsToUnicodeString("''Vous'' {0,choice,0#n''|1#}avez s\\u00E9lectionn\\u00E9 " 861 "{0,choice,0#aucun|1#{0}} client{0,choice,0#s|1#|2#s} " 862 "personnel{0,choice,0#s|1#|2#s}."); 863 UErrorCode status = U_ZERO_ERROR; 864 MessageFormat *mf = new MessageFormat(pat, status); 865 failure(status, "new MessageFormat"); 866 867 UnicodeString PREFIX [] = { 868 CharsToUnicodeString("'Vous' n'avez s\\u00E9lectionn\\u00E9 aucun clients personnels."), 869 CharsToUnicodeString("'Vous' avez s\\u00E9lectionn\\u00E9 "), 870 CharsToUnicodeString("'Vous' avez s\\u00E9lectionn\\u00E9 ") 871 }; 872 UnicodeString SUFFIX [] = { 873 UnicodeString(), 874 UNICODE_STRING(" client personnel.", 18), 875 UNICODE_STRING(" clients personnels.", 20) 876 }; 877 878 for (int i=0; i<3; i++) { 879 UnicodeString out; 880 //out = mf->format(new Object[]{new Integer(i)}); 881 Formattable objs [] = { 882 Formattable((int32_t)i) 883 }; 884 FieldPosition pos(FieldPosition::DONT_CARE); 885 out = mf->format(objs, 1, out, pos, status); 886 if (!failure(status, "mf->format", TRUE)) { 887 if (SUFFIX[i] == "") { 888 if (out != PREFIX[i]) 889 errln((UnicodeString)"" + i + ": Got \"" + out + "\"; Want \"" + PREFIX[i] + "\""); 890 } 891 else { 892 if (!out.startsWith(PREFIX[i]) || 893 !out.endsWith(SUFFIX[i])) 894 errln((UnicodeString)"" + i + ": Got \"" + out + "\"; Want \"" + PREFIX[i] + "\"...\"" + 895 SUFFIX[i] + "\""); 896 } 897 } 898 } 899 900 delete mf; 901 } 902 903 /** 904 * @bug 4142938 905 * Test the applyPattern and toPattern handling of single quotes 906 * by ChoiceFormat. (This is in here because this was a bug reported 907 * against MessageFormat.) The single quote is used to quote the 908 * pattern characters '|', '#', '<', and '\u2264'. Two quotes in a row 909 * is a quote literal. 910 */ 911 void MessageFormatRegressionTest::TestChoicePatternQuote() 912 { 913 UnicodeString DATA [] = { 914 // Pattern 0 value 1 value 915 // {sfb} hacked - changed \u2264 to = (copied from Character Map) 916 (UnicodeString)"0#can''t|1#can", (UnicodeString)"can't", (UnicodeString)"can", 917 (UnicodeString)"0#'pound(#)=''#'''|1#xyz", (UnicodeString)"pound(#)='#'", (UnicodeString)"xyz", 918 (UnicodeString)"0#'1<2 | 1=1'|1#''", (UnicodeString)"1<2 | 1=1", (UnicodeString)"'", 919 }; 920 for (int i=0; i<9; i+=3) { 921 //try { 922 UErrorCode status = U_ZERO_ERROR; 923 ChoiceFormat *cf = new ChoiceFormat(DATA[i], status); 924 failure(status, "new ChoiceFormat"); 925 for (int j=0; j<=1; ++j) { 926 UnicodeString out; 927 FieldPosition pos(FieldPosition::DONT_CARE); 928 out = cf->format((double)j, out, pos); 929 if (out != DATA[i+1+j]) 930 errln("Fail: Pattern \"" + DATA[i] + "\" x "+j+" -> " + 931 out + "; want \"" + DATA[i+1+j] + '"'); 932 } 933 UnicodeString pat; 934 pat = cf->toPattern(pat); 935 UnicodeString pat2; 936 ChoiceFormat *cf2 = new ChoiceFormat(pat, status); 937 pat2 = cf2->toPattern(pat2); 938 if (pat != pat2) 939 errln("Fail: Pattern \"" + DATA[i] + "\" x toPattern -> \"" + pat + '"'); 940 else 941 logln("Ok: Pattern \"" + DATA[i] + "\" x toPattern -> \"" + pat + '"'); 942 /*} 943 catch (IllegalArgumentException e) { 944 errln("Fail: Pattern \"" + DATA[i] + "\" -> " + e); 945 }*/ 946 947 delete cf; 948 delete cf2; 949 } 950 } 951 952 /** 953 * @bug 4112104 954 * MessageFormat.equals(null) throws a NullPointerException. The JLS states 955 * that it should return false. 956 */ 957 void MessageFormatRegressionTest::Test4112104() 958 { 959 UErrorCode status = U_ZERO_ERROR; 960 MessageFormat *format = new MessageFormat("", status); 961 failure(status, "new MessageFormat"); 962 //try { 963 // This should NOT throw an exception 964 if (format == NULL) { 965 // It also should return false 966 errln("MessageFormat.equals(null) returns false"); 967 } 968 /*} 969 catch (NullPointerException e) { 970 errln("MessageFormat.equals(null) throws " + e); 971 }*/ 972 delete format; 973 } 974 975 #endif /* #if !UCONFIG_NO_FORMATTING */ 976