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