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