1 // 2016 and later: Unicode, Inc. and others. 2 // License & terms of use: http://www.unicode.org/copyright.html#License 3 /* 4 ********************************************************************** 5 * Copyright (c) 2005-2011, International Business Machines 6 * Corporation and others. All Rights Reserved. 7 ********************************************************************** 8 * Author: Alan Liu 9 * Created: April 12, 2004 10 * Since: ICU 3.0 11 ********************************************************************** 12 */ 13 /** 14 * MessageRegressionTest.java 15 * 16 * @test 1.29 01/03/12 17 * @bug 4031438 4058973 4074764 4094906 4104976 4105380 4106659 4106660 4106661 18 * 4111739 4112104 4113018 4114739 4114743 4116444 4118592 4118594 4120552 19 * 4142938 4169959 4232154 4293229 20 * @summary Regression tests for MessageFormat and associated classes 21 */ 22 /* 23 (C) Copyright Taligent, Inc. 1996 - All Rights Reserved 24 (C) Copyright IBM Corp. 1996 - All Rights Reserved 25 26 The original version of this source code and documentation is copyrighted and 27 owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These materials are 28 provided under terms of a License Agreement between Taligent and Sun. This 29 technology is protected by multiple US and International patents. This notice and 30 attribution to Taligent may not be removed. 31 Taligent is a registered trademark of Taligent, Inc. 32 */ 33 package com.ibm.icu.dev.test.format; 34 35 import java.io.ByteArrayInputStream; 36 import java.io.ByteArrayOutputStream; 37 import java.io.IOException; 38 import java.io.ObjectInputStream; 39 import java.io.ObjectOutputStream; 40 import java.text.ChoiceFormat; 41 import java.text.ParsePosition; 42 import java.util.Date; 43 import java.util.HashMap; 44 import java.util.Iterator; 45 import java.util.Locale; 46 import java.util.Map; 47 48 import org.junit.Test; 49 import org.junit.runner.RunWith; 50 import org.junit.runners.JUnit4; 51 52 import com.ibm.icu.dev.test.TestFmwk; 53 import com.ibm.icu.text.MessageFormat; 54 import com.ibm.icu.text.NumberFormat; 55 import com.ibm.icu.util.ULocale; 56 57 @RunWith(JUnit4.class) 58 public class MessageRegressionTest extends TestFmwk { 59 /* @bug 4074764 60 * Null exception when formatting pattern with MessageFormat 61 * with no parameters. 62 */ 63 @Test 64 public void Test4074764() { 65 String[] pattern = {"Message without param", 66 "Message with param:{0}", 67 "Longer Message with param {0}"}; 68 //difference between the two param strings are that 69 //in the first one, the param position is within the 70 //length of the string without param while it is not so 71 //in the other case. 72 73 MessageFormat messageFormatter = new MessageFormat(""); 74 75 try { 76 //Apply pattern with param and print the result 77 messageFormatter.applyPattern(pattern[1]); 78 Object[] paramArray = {new String("BUG"), new Date()}; 79 String tempBuffer = messageFormatter.format(paramArray); 80 if (!tempBuffer.equals("Message with param:BUG")) 81 errln("MessageFormat with one param test failed."); 82 logln("Formatted with one extra param : " + tempBuffer); 83 84 //Apply pattern without param and print the result 85 messageFormatter.applyPattern(pattern[0]); 86 tempBuffer = messageFormatter.format(null); 87 if (!tempBuffer.equals("Message without param")) 88 errln("MessageFormat with no param test failed."); 89 logln("Formatted with no params : " + tempBuffer); 90 91 tempBuffer = messageFormatter.format(paramArray); 92 if (!tempBuffer.equals("Message without param")) 93 errln("Formatted with arguments > subsitution failed. result = " + tempBuffer.toString()); 94 logln("Formatted with extra params : " + tempBuffer); 95 //This statement gives an exception while formatting... 96 //If we use pattern[1] for the message with param, 97 //we get an NullPointerException in MessageFormat.java(617) 98 //If we use pattern[2] for the message with param, 99 //we get an StringArrayIndexOutOfBoundsException in MessageFormat.java(614) 100 //Both are due to maxOffset not being reset to -1 101 //in applyPattern() when the pattern does not 102 //contain any param. 103 } catch (Exception foo) { 104 errln("Exception when formatting with no params."); 105 } 106 } 107 108 /* @bug 4058973 109 * MessageFormat.toPattern has weird rounding behavior. 110 * 111 * ICU 4.8: This test is commented out because toPattern() has been changed to return 112 * the original pattern string, rather than reconstituting a new (equivalent) one. 113 * This trivially eliminates issues with rounding or any other pattern string differences. 114 */ 115 /*public void Test4058973() { 116 117 MessageFormat fmt = new MessageFormat("{0,choice,0#no files|1#one file|1< {0,number,integer} files}"); 118 String pat = fmt.toPattern(); 119 if (!pat.equals("{0,choice,0.0#no files|1.0#one file|1.0< {0,number,integer} files}")) { 120 errln("MessageFormat.toPattern failed"); 121 } 122 }*/ 123 /* @bug 4031438 124 * More robust message formats. 125 */ 126 @Test 127 public void Test4031438() { 128 String pattern1 = "Impossible {1} has occurred -- status code is {0} and message is {2}."; 129 String pattern2 = "Double '' Quotes {0} test and quoted '{1}' test plus 'other {2} stuff'."; 130 131 MessageFormat messageFormatter = new MessageFormat(""); 132 133 try { 134 logln("Apply with pattern : " + pattern1); 135 messageFormatter.applyPattern(pattern1); 136 Object[] paramArray = {new Integer(7)}; 137 String tempBuffer = messageFormatter.format(paramArray); 138 if (!tempBuffer.equals("Impossible {1} has occurred -- status code is 7 and message is {2}.")) 139 errln("Tests arguments < substitution failed"); 140 logln("Formatted with 7 : " + tempBuffer); 141 ParsePosition status = new ParsePosition(0); 142 Object[] objs = messageFormatter.parse(tempBuffer, status); 143 if (objs[paramArray.length] != null) 144 errln("Parse failed with more than expected arguments"); 145 for (int i = 0; i < objs.length; i++) { 146 if (objs[i] != null && !objs[i].toString().equals(paramArray[i].toString())) { 147 errln("Parse failed on object " + objs[i] + " at index : " + i); 148 } 149 } 150 tempBuffer = messageFormatter.format(null); 151 if (!tempBuffer.equals("Impossible {1} has occurred -- status code is {0} and message is {2}.")) 152 errln("Tests with no arguments failed"); 153 logln("Formatted with null : " + tempBuffer); 154 logln("Apply with pattern : " + pattern2); 155 messageFormatter.applyPattern(pattern2); 156 tempBuffer = messageFormatter.format(paramArray); 157 if (!tempBuffer.equals("Double ' Quotes 7 test and quoted {1} test plus 'other {2} stuff'.")) 158 errln("quote format test (w/ params) failed."); 159 logln("Formatted with params : " + tempBuffer); 160 tempBuffer = messageFormatter.format(null); 161 if (!tempBuffer.equals("Double ' Quotes {0} test and quoted {1} test plus 'other {2} stuff'.")) 162 errln("quote format test (w/ null) failed."); 163 logln("Formatted with null : " + tempBuffer); 164 logln("toPattern : " + messageFormatter.toPattern()); 165 } catch (Exception foo) { 166 warnln("Exception when formatting in bug 4031438. "+foo.getMessage()); 167 } 168 } 169 @Test 170 public void Test4052223() 171 { 172 ParsePosition pos = new ParsePosition(0); 173 if (pos.getErrorIndex() != -1) { 174 errln("ParsePosition.getErrorIndex initialization failed."); 175 } 176 MessageFormat fmt = new MessageFormat("There are {0} apples growing on the {1} tree."); 177 String str = new String("There is one apple growing on the peach tree."); 178 Object[] objs = fmt.parse(str, pos); 179 logln("unparsable string , should fail at " + pos.getErrorIndex()); 180 if (pos.getErrorIndex() == -1) 181 errln("Bug 4052223 failed : parsing string " + str); 182 pos.setErrorIndex(4); 183 if (pos.getErrorIndex() != 4) 184 errln("setErrorIndex failed, got " + pos.getErrorIndex() + " instead of 4"); 185 186 if (objs != null) { 187 errln("objs should be null"); 188 } 189 ChoiceFormat f = new ChoiceFormat( 190 "-1#are negative|0#are no or fraction|1#is one|1.0<is 1+|2#are two|2<are more than 2."); 191 pos.setIndex(0); pos.setErrorIndex(-1); 192 Number obj = f.parse("are negative", pos); 193 if (pos.getErrorIndex() != -1 && obj.doubleValue() == -1.0) 194 errln("Parse with \"are negative\" failed, at " + pos.getErrorIndex()); 195 pos.setIndex(0); pos.setErrorIndex(-1); 196 obj = f.parse("are no or fraction ", pos); 197 if (pos.getErrorIndex() != -1 && obj.doubleValue() == 0.0) 198 errln("Parse with \"are no or fraction\" failed, at " + pos.getErrorIndex()); 199 pos.setIndex(0); pos.setErrorIndex(-1); 200 obj = f.parse("go postal", pos); 201 if (pos.getErrorIndex() == -1 && !Double.isNaN(obj.doubleValue())) 202 errln("Parse with \"go postal\" failed, at " + pos.getErrorIndex()); 203 } 204 /* @bug 4104976 205 * ChoiceFormat.equals(null) throws NullPointerException 206 */ 207 @Test 208 public void Test4104976() 209 { 210 double[] limits = {1, 20}; 211 String[] formats = {"xyz", "abc"}; 212 ChoiceFormat cf = new ChoiceFormat(limits, formats); 213 try { 214 log("Compares to null is always false, returned : "); 215 logln(cf.equals(null) ? "TRUE" : "FALSE"); 216 } catch (Exception foo) { 217 errln("ChoiceFormat.equals(null) throws exception."); 218 } 219 } 220 /* @bug 4106659 221 * ChoiceFormat.ctor(double[], String[]) doesn't check 222 * whether lengths of input arrays are equal. 223 */ 224 @Test 225 public void Test4106659() 226 { 227 double[] limits = {1, 2, 3}; 228 String[] formats = {"one", "two"}; 229 ChoiceFormat cf = null; 230 try { 231 cf = new ChoiceFormat(limits, formats); 232 } catch (Exception foo) { 233 logln("ChoiceFormat constructor should check for the array lengths"); 234 cf = null; 235 } 236 if (cf != null) errln(cf.format(5)); 237 } 238 239 /* @bug 4106660 240 * ChoiceFormat.ctor(double[], String[]) allows unordered double array. 241 * This is not a bug, added javadoc to emphasize the use of limit 242 * array must be in ascending order. 243 */ 244 @Test 245 public void Test4106660() 246 { 247 double[] limits = {3, 1, 2}; 248 String[] formats = {"Three", "One", "Two"}; 249 ChoiceFormat cf = new ChoiceFormat(limits, formats); 250 double d = 5.0; 251 String str = cf.format(d); 252 if (!str.equals("Two")) 253 errln("format(" + d + ") = " + cf.format(d)); 254 } 255 256 /* @bug 4111739 257 * MessageFormat is incorrectly serialized/deserialized. 258 */ 259 @Test 260 public void Test4111739() 261 { 262 MessageFormat format1 = null; 263 MessageFormat format2 = null; 264 ObjectOutputStream ostream = null; 265 ByteArrayOutputStream baos = null; 266 ObjectInputStream istream = null; 267 268 try { 269 baos = new ByteArrayOutputStream(); 270 ostream = new ObjectOutputStream(baos); 271 } catch(IOException e) { 272 errln("Unexpected exception : " + e.getMessage()); 273 return; 274 } 275 276 try { 277 format1 = new MessageFormat("pattern{0}"); 278 ostream.writeObject(format1); 279 ostream.flush(); 280 281 byte bytes[] = baos.toByteArray(); 282 283 istream = new ObjectInputStream(new ByteArrayInputStream(bytes)); 284 format2 = (MessageFormat)istream.readObject(); 285 } catch(Exception e) { 286 errln("Unexpected exception : " + e.getMessage()); 287 } 288 289 if (!format1.equals(format2)) { 290 errln("MessageFormats before and after serialization are not" + 291 " equal\nformat1 = " + format1 + "(" + format1.toPattern() + ")\nformat2 = " + 292 format2 + "(" + format2.toPattern() + ")"); 293 } else { 294 logln("Serialization for MessageFormat is OK."); 295 } 296 } 297 /* @bug 4114743 298 * MessageFormat.applyPattern allows illegal patterns. 299 */ 300 @Test 301 public void Test4114743() 302 { 303 String originalPattern = "initial pattern"; 304 MessageFormat mf = new MessageFormat(originalPattern); 305 String illegalPattern = "ab { '}' de"; 306 try { 307 mf.applyPattern(illegalPattern); 308 errln("illegal pattern: \"" + illegalPattern + "\""); 309 } catch (IllegalArgumentException foo) { 310 if (illegalPattern.equals(mf.toPattern())) 311 errln("pattern after: \"" + mf.toPattern() + "\""); 312 } 313 } 314 315 /* @bug 4116444 316 * MessageFormat.parse has different behavior in case of null. 317 */ 318 @Test 319 public void Test4116444() 320 { 321 String[] patterns = {"", "one", "{0,date,short}"}; 322 MessageFormat mf = new MessageFormat(""); 323 324 for (int i = 0; i < patterns.length; i++) { 325 String pattern = patterns[i]; 326 mf.applyPattern(pattern); 327 try { 328 Object[] array = mf.parse(null, new ParsePosition(0)); 329 logln("pattern: \"" + pattern + "\""); 330 log(" parsedObjects: "); 331 if (array != null) { 332 log("{"); 333 for (int j = 0; j < array.length; j++) { 334 if (array[j] != null) 335 err("\"" + array[j].toString() + "\""); 336 else 337 log("null"); 338 if (j < array.length - 1) log(","); 339 } 340 log("}") ; 341 } else { 342 log("null"); 343 } 344 logln(""); 345 } catch (Exception e) { 346 errln("pattern: \"" + pattern + "\""); 347 errln(" Exception: " + e.getMessage()); 348 } 349 } 350 351 } 352 /* @bug 4114739 (FIX and add javadoc) 353 * MessageFormat.format has undocumented behavior about empty format objects. 354 */ 355 @Test 356 public void Test4114739() 357 { 358 359 MessageFormat mf = new MessageFormat("<{0}>"); 360 Object[] objs1 = null; 361 Object[] objs2 = {}; 362 Object[] objs3 = {null}; 363 try { 364 logln("pattern: \"" + mf.toPattern() + "\""); 365 log("format(null) : "); 366 logln("\"" + mf.format(objs1) + "\""); 367 log("format({}) : "); 368 logln("\"" + mf.format(objs2) + "\""); 369 log("format({null}) :"); 370 logln("\"" + mf.format(objs3) + "\""); 371 } catch (Exception e) { 372 errln("Exception thrown for null argument tests."); 373 } 374 } 375 376 /* @bug 4113018 377 * MessageFormat.applyPattern works wrong with illegal patterns. 378 */ 379 @Test 380 public void Test4113018() 381 { 382 String originalPattern = "initial pattern"; 383 MessageFormat mf = new MessageFormat(originalPattern); 384 String illegalPattern = "format: {0, xxxYYY}"; 385 logln("pattern before: \"" + mf.toPattern() + "\""); 386 logln("illegal pattern: \"" + illegalPattern + "\""); 387 try { 388 mf.applyPattern(illegalPattern); 389 errln("Should have thrown IllegalArgumentException for pattern : " + illegalPattern); 390 } catch (IllegalArgumentException e) { 391 if (illegalPattern.equals(mf.toPattern())) 392 errln("pattern after: \"" + mf.toPattern() + "\""); 393 } 394 } 395 /* @bug 4106661 396 * ChoiceFormat is silent about the pattern usage in javadoc. 397 */ 398 @Test 399 public void Test4106661() 400 { 401 ChoiceFormat fmt = new ChoiceFormat( 402 "-1#are negative| 0#are no or fraction | 1#is one |1.0<is 1+ |2#are two |2<are more than 2."); 403 logln("Formatter Pattern : " + fmt.toPattern()); 404 405 logln("Format with -INF : " + fmt.format(Double.NEGATIVE_INFINITY)); 406 logln("Format with -1.0 : " + fmt.format(-1.0)); 407 logln("Format with 0 : " + fmt.format(0)); 408 logln("Format with 0.9 : " + fmt.format(0.9)); 409 logln("Format with 1.0 : " + fmt.format(1)); 410 logln("Format with 1.5 : " + fmt.format(1.5)); 411 logln("Format with 2 : " + fmt.format(2)); 412 logln("Format with 2.1 : " + fmt.format(2.1)); 413 logln("Format with NaN : " + fmt.format(Double.NaN)); 414 logln("Format with +INF : " + fmt.format(Double.POSITIVE_INFINITY)); 415 } 416 /* @bug 4094906 417 * ChoiceFormat should accept \u221E as eq. to INF. 418 */ 419 @Test 420 public void Test4094906() 421 { 422 ChoiceFormat fmt = new ChoiceFormat( 423 "-\u221E<are negative|0<are no or fraction|1#is one|1.0<is 1+|\u221E<are many."); 424 if (!fmt.toPattern().startsWith("-\u221E<are negative|0.0<are no or fraction|1.0#is one|1.0<is 1+|\u221E<are many.")) 425 errln("Formatter Pattern : " + fmt.toPattern()); 426 logln("Format with -INF : " + fmt.format(Double.NEGATIVE_INFINITY)); 427 logln("Format with -1.0 : " + fmt.format(-1.0)); 428 logln("Format with 0 : " + fmt.format(0)); 429 logln("Format with 0.9 : " + fmt.format(0.9)); 430 logln("Format with 1.0 : " + fmt.format(1)); 431 logln("Format with 1.5 : " + fmt.format(1.5)); 432 logln("Format with 2 : " + fmt.format(2)); 433 logln("Format with +INF : " + fmt.format(Double.POSITIVE_INFINITY)); 434 } 435 436 /* @bug 4118592 437 * MessageFormat.parse fails with ChoiceFormat. 438 */ 439 @Test 440 public void Test4118592() 441 { 442 MessageFormat mf = new MessageFormat(""); 443 String pattern = "{0,choice,1#YES|2#NO}"; 444 String prefix = ""; 445 for (int i = 0; i < 5; i++) { 446 String formatted = prefix + "YES"; 447 mf.applyPattern(prefix + pattern); 448 prefix += "x"; 449 Object[] objs = mf.parse(formatted, new ParsePosition(0)); 450 logln(i + ". pattern :\"" + mf.toPattern() + "\""); 451 log(" \"" + formatted + "\" parsed as "); 452 if (objs == null) logln(" null"); 453 else logln(" " + objs[0]); 454 } 455 } 456 /* @bug 4118594 457 * MessageFormat.parse fails for some patterns. 458 */ 459 @Test 460 public void Test4118594() 461 { 462 MessageFormat mf = new MessageFormat("{0}, {0}, {0}"); 463 String forParsing = "x, y, z"; 464 Object[] objs = mf.parse(forParsing, new ParsePosition(0)); 465 logln("pattern: \"" + mf.toPattern() + "\""); 466 logln("text for parsing: \"" + forParsing + "\""); 467 if (!objs[0].toString().equals("z")) 468 errln("argument0: \"" + objs[0] + "\""); 469 mf.setLocale(Locale.US); 470 mf.applyPattern("{0,number,#.##}, {0,number,#.#}"); 471 Object[] oldobjs = {new Double(3.1415)}; 472 String result = mf.format( oldobjs ); 473 logln("pattern: \"" + mf.toPattern() + "\""); 474 logln("text for parsing: \"" + result + "\""); 475 // result now equals "3.14, 3.1" 476 if (!result.equals("3.14, 3.1")) 477 errln("result = " + result); 478 Object[] newobjs = mf.parse(result, new ParsePosition(0)); 479 // newobjs now equals {new Double(3.1)} 480 if (((Number)newobjs[0]).doubleValue() != 3.1) // was (Double) [alan] 481 errln( "newobjs[0] = " + newobjs[0]); 482 } 483 /* @bug 4105380 484 * When using ChoiceFormat, MessageFormat is not good for I18n. 485 */ 486 @Test 487 public void Test4105380() 488 { 489 String patternText1 = "The disk \"{1}\" contains {0}."; 490 String patternText2 = "There are {0} on the disk \"{1}\""; 491 MessageFormat form1 = new MessageFormat(patternText1); 492 MessageFormat form2 = new MessageFormat(patternText2); 493 double[] filelimits = {0,1,2}; 494 String[] filepart = {"no files","one file","{0,number} files"}; 495 ChoiceFormat fileform = new ChoiceFormat(filelimits, filepart); 496 form1.setFormat(1, fileform); 497 form2.setFormat(0, fileform); 498 Object[] testArgs = {new Long(12373), "MyDisk"}; 499 logln(form1.format(testArgs)); 500 logln(form2.format(testArgs)); 501 } 502 /* @bug 4120552 503 * MessageFormat.parse incorrectly sets errorIndex. 504 */ 505 @Test 506 public void Test4120552() 507 { 508 MessageFormat mf = new MessageFormat("pattern"); 509 String texts[] = {"pattern", "pat", "1234"}; 510 logln("pattern: \"" + mf.toPattern() + "\""); 511 for (int i = 0; i < texts.length; i++) { 512 ParsePosition pp = new ParsePosition(0); 513 Object[] objs = mf.parse(texts[i], pp); 514 log(" text for parsing: \"" + texts[i] + "\""); 515 if (objs == null) { 516 logln(" (incorrectly formatted string)"); 517 if (pp.getErrorIndex() == -1) 518 errln("Incorrect error index: " + pp.getErrorIndex()); 519 } else { 520 logln(" (correctly formatted string)"); 521 } 522 } 523 } 524 525 /** 526 * @bug 4142938 527 * MessageFormat handles single quotes in pattern wrong. 528 * This is actually a problem in ChoiceFormat; it doesn't 529 * understand single quotes. 530 */ 531 @Test 532 public void Test4142938() { 533 String pat = "''Vous'' {0,choice,0#n''|1#}avez s\u00E9lectionne\u00E9 " + 534 "{0,choice,0#aucun|1#{0}} client{0,choice,0#s|1#|2#s} " + 535 "personnel{0,choice,0#s|1#|2#s}."; 536 MessageFormat mf = new MessageFormat(pat); 537 538 String[] PREFIX = { 539 "'Vous' n'avez s\u00E9lectionne\u00E9 aucun clients personnels.", 540 "'Vous' avez s\u00E9lectionne\u00E9 ", 541 "'Vous' avez s\u00E9lectionne\u00E9 " 542 }; 543 String[] SUFFIX = { 544 null, 545 " client personnel.", 546 " clients personnels." 547 }; 548 549 for (int i=0; i<3; i++) { 550 String out = mf.format(new Object[]{new Integer(i)}); 551 if (SUFFIX[i] == null) { 552 if (!out.equals(PREFIX[i])) 553 errln("" + i + ": Got \"" + out + "\"; Want \"" + PREFIX[i] + "\""); 554 } 555 else { 556 if (!out.startsWith(PREFIX[i]) || 557 !out.endsWith(SUFFIX[i])) 558 errln("" + i + ": Got \"" + out + "\"; Want \"" + PREFIX[i] + "\"...\"" + 559 SUFFIX[i] + "\""); 560 } 561 } 562 } 563 564 /** 565 * @bug 4142938 566 * Test the applyPattern and toPattern handling of single quotes 567 * by ChoiceFormat. (This is in here because this was a bug reported 568 * against MessageFormat.) The single quote is used to quote the 569 * pattern characters '|', '#', '<', and '\u2264'. Two quotes in a row 570 * is a quote literal. 571 */ 572 @Test 573 public void TestChoicePatternQuote() { 574 String[] DATA = { 575 // Pattern 0 value 1 value 576 "0#can''t|1#can", "can't", "can", 577 "0#'pound(#)=''#'''|1#xyz", "pound(#)='#'", "xyz", 578 "0#'1<2 | 1\u22641'|1#''", "1<2 | 1\u22641", "'", 579 }; 580 for (int i=0; i<DATA.length; i+=3) { 581 try { 582 ChoiceFormat cf = new ChoiceFormat(DATA[i]); 583 for (int j=0; j<=1; ++j) { 584 String out = cf.format(j); 585 if (!out.equals(DATA[i+1+j])) 586 errln("Fail: Pattern \"" + DATA[i] + "\" x "+j+" -> " + 587 out + "; want \"" + DATA[i+1+j] + '"'); 588 } 589 String pat = cf.toPattern(); 590 String pat2 = new ChoiceFormat(pat).toPattern(); 591 if (!pat.equals(pat2)) 592 errln("Fail: Pattern \"" + DATA[i] + "\" x toPattern -> \"" + pat + '"'); 593 else 594 logln("Ok: Pattern \"" + DATA[i] + "\" x toPattern -> \"" + pat + '"'); 595 } 596 catch (IllegalArgumentException e) { 597 errln("Fail: Pattern \"" + DATA[i] + "\" -> " + e); 598 } 599 } 600 } 601 602 /** 603 * @bug 4112104 604 * MessageFormat.equals(null) throws a NullPointerException. The JLS states 605 * that it should return false. 606 */ 607 @Test 608 public void Test4112104() { 609 MessageFormat format = new MessageFormat(""); 610 try { 611 // This should NOT throw an exception 612 if (format.equals(null)) { 613 // It also should return false 614 errln("MessageFormat.equals(null) returns false"); 615 } 616 } 617 catch (NullPointerException e) { 618 errln("MessageFormat.equals(null) throws " + e); 619 } 620 } 621 622 /** 623 * @bug 4169959 624 * MessageFormat does not format null objects. CANNOT REPRODUCE THIS BUG. 625 */ 626 @Test 627 public void Test4169959() { 628 // This works 629 logln(MessageFormat.format("This will {0}", new Object[]{"work"})); 630 631 // This fails 632 logln(MessageFormat.format("This will {0}", new Object[]{ null })); 633 } 634 635 @Test 636 public void test4232154() { 637 boolean gotException = false; 638 try { 639 new MessageFormat("The date is {0:date}"); 640 } catch (Exception e) { 641 gotException = true; 642 if (!(e instanceof IllegalArgumentException)) { 643 throw new RuntimeException("got wrong exception type"); 644 } 645 if ("argument number too large at ".equals(e.getMessage())) { 646 throw new RuntimeException("got wrong exception message"); 647 } 648 } 649 if (!gotException) { 650 throw new RuntimeException("didn't get exception for invalid input"); 651 } 652 } 653 654 @Test 655 public void test4293229() { 656 MessageFormat format = new MessageFormat("'''{'0}'' '''{0}'''"); 657 Object[] args = { null }; 658 String expected = "'{0}' '{0}'"; 659 String result = format.format(args); 660 if (!result.equals(expected)) { 661 throw new RuntimeException("wrong format result - expected \"" + 662 expected + "\", got \"" + result + "\""); 663 } 664 } 665 666 // This test basically ensures that the tests defined above also work with 667 // valid named arguments. 668 @Test 669 public void testBugTestsWithNamesArguments() { 670 671 { // Taken from Test4031438(). 672 String pattern1 = "Impossible {arg1} has occurred -- status code is {arg0} and message is {arg2}."; 673 String pattern2 = "Double '' Quotes {ARG_ZERO} test and quoted '{ARG_ONE}' test plus 'other {ARG_TWO} stuff'."; 674 675 MessageFormat messageFormatter = new MessageFormat(""); 676 677 try { 678 logln("Apply with pattern : " + pattern1); 679 messageFormatter.applyPattern(pattern1); 680 HashMap paramsMap = new HashMap(); 681 paramsMap.put("arg0", new Integer(7)); 682 String tempBuffer = messageFormatter.format(paramsMap); 683 if (!tempBuffer.equals("Impossible {arg1} has occurred -- status code is 7 and message is {arg2}.")) 684 errln("Tests arguments < substitution failed"); 685 logln("Formatted with 7 : " + tempBuffer); 686 ParsePosition status = new ParsePosition(0); 687 Map objs = messageFormatter.parseToMap(tempBuffer, status); 688 if (objs.get("arg1") != null || objs.get("arg2") != null) 689 errln("Parse failed with more than expected arguments"); 690 for (Iterator keyIter = objs.keySet().iterator(); 691 keyIter.hasNext();) { 692 String key = (String) keyIter.next(); 693 if (objs.get(key) != null && !objs.get(key).toString().equals(paramsMap.get(key).toString())) { 694 errln("Parse failed on object " + objs.get(key) + " with argument name : " + key ); 695 } 696 } 697 tempBuffer = messageFormatter.format(null); 698 if (!tempBuffer.equals("Impossible {arg1} has occurred -- status code is {arg0} and message is {arg2}.")) 699 errln("Tests with no arguments failed"); 700 logln("Formatted with null : " + tempBuffer); 701 logln("Apply with pattern : " + pattern2); 702 messageFormatter.applyPattern(pattern2); 703 paramsMap.clear(); 704 paramsMap.put("ARG_ZERO", new Integer(7)); 705 tempBuffer = messageFormatter.format(paramsMap); 706 if (!tempBuffer.equals("Double ' Quotes 7 test and quoted {ARG_ONE} test plus 'other {ARG_TWO} stuff'.")) 707 errln("quote format test (w/ params) failed."); 708 logln("Formatted with params : " + tempBuffer); 709 tempBuffer = messageFormatter.format(null); 710 if (!tempBuffer.equals("Double ' Quotes {ARG_ZERO} test and quoted {ARG_ONE} test plus 'other {ARG_TWO} stuff'.")) 711 errln("quote format test (w/ null) failed."); 712 logln("Formatted with null : " + tempBuffer); 713 logln("toPattern : " + messageFormatter.toPattern()); 714 } catch (Exception foo) { 715 warnln("Exception when formatting in bug 4031438. "+foo.getMessage()); 716 } 717 }{ // Taken from Test4052223(). 718 ParsePosition pos = new ParsePosition(0); 719 if (pos.getErrorIndex() != -1) { 720 errln("ParsePosition.getErrorIndex initialization failed."); 721 } 722 MessageFormat fmt = new MessageFormat("There are {numberOfApples} apples growing on the {whatKindOfTree} tree."); 723 String str = new String("There is one apple growing on the peach tree."); 724 Map objs = fmt.parseToMap(str, pos); 725 logln("unparsable string , should fail at " + pos.getErrorIndex()); 726 if (pos.getErrorIndex() == -1) 727 errln("Bug 4052223 failed : parsing string " + str); 728 pos.setErrorIndex(4); 729 if (pos.getErrorIndex() != 4) 730 errln("setErrorIndex failed, got " + pos.getErrorIndex() + " instead of 4"); 731 if (objs != null) 732 errln("unparsable string, should return null"); 733 }{ // Taken from Test4111739(). 734 MessageFormat format1 = null; 735 MessageFormat format2 = null; 736 ObjectOutputStream ostream = null; 737 ByteArrayOutputStream baos = null; 738 ObjectInputStream istream = null; 739 740 try { 741 baos = new ByteArrayOutputStream(); 742 ostream = new ObjectOutputStream(baos); 743 } catch(IOException e) { 744 errln("Unexpected exception : " + e.getMessage()); 745 return; 746 } 747 748 try { 749 format1 = new MessageFormat("pattern{argument}"); 750 ostream.writeObject(format1); 751 ostream.flush(); 752 753 byte bytes[] = baos.toByteArray(); 754 755 istream = new ObjectInputStream(new ByteArrayInputStream(bytes)); 756 format2 = (MessageFormat)istream.readObject(); 757 } catch(Exception e) { 758 errln("Unexpected exception : " + e.getMessage()); 759 } 760 761 if (!format1.equals(format2)) { 762 errln("MessageFormats before and after serialization are not" + 763 " equal\nformat1 = " + format1 + "(" + format1.toPattern() + ")\nformat2 = " + 764 format2 + "(" + format2.toPattern() + ")"); 765 } else { 766 logln("Serialization for MessageFormat is OK."); 767 } 768 }{ // Taken from Test4116444(). 769 String[] patterns = {"", "one", "{namedArgument,date,short}"}; 770 MessageFormat mf = new MessageFormat(""); 771 772 for (int i = 0; i < patterns.length; i++) { 773 String pattern = patterns[i]; 774 mf.applyPattern(pattern); 775 try { 776 Map objs = mf.parseToMap(null, new ParsePosition(0)); 777 logln("pattern: \"" + pattern + "\""); 778 log(" parsedObjects: "); 779 if (objs != null) { 780 log("{"); 781 for (Iterator keyIter = objs.keySet().iterator(); 782 keyIter.hasNext();) { 783 String key = (String)keyIter.next(); 784 if (objs.get(key) != null) { 785 err("\"" + objs.get(key).toString() + "\""); 786 } else { 787 log("null"); 788 } 789 if (keyIter.hasNext()) { 790 log(","); 791 } 792 } 793 log("}") ; 794 } else { 795 log("null"); 796 } 797 logln(""); 798 } catch (Exception e) { 799 errln("pattern: \"" + pattern + "\""); 800 errln(" Exception: " + e.getMessage()); 801 } 802 } 803 }{ // Taken from Test4114739(). 804 MessageFormat mf = new MessageFormat("<{arg}>"); 805 Map objs1 = null; 806 Map objs2 = new HashMap(); 807 Map objs3 = new HashMap(); 808 objs3.put("arg", null); 809 try { 810 logln("pattern: \"" + mf.toPattern() + "\""); 811 log("format(null) : "); 812 logln("\"" + mf.format(objs1) + "\""); 813 log("format({}) : "); 814 logln("\"" + mf.format(objs2) + "\""); 815 log("format({null}) :"); 816 logln("\"" + mf.format(objs3) + "\""); 817 } catch (Exception e) { 818 errln("Exception thrown for null argument tests."); 819 } 820 }{ // Taken from Test4118594(). 821 String argName = "something_stupid"; 822 MessageFormat mf = new MessageFormat("{"+ argName + "}, {" + argName + "}, {" + argName + "}"); 823 String forParsing = "x, y, z"; 824 Map objs = mf.parseToMap(forParsing, new ParsePosition(0)); 825 logln("pattern: \"" + mf.toPattern() + "\""); 826 logln("text for parsing: \"" + forParsing + "\""); 827 if (!objs.get(argName).toString().equals("z")) 828 errln("argument0: \"" + objs.get(argName) + "\""); 829 mf.setLocale(Locale.US); 830 mf.applyPattern("{" + argName + ",number,#.##}, {" + argName + ",number,#.#}"); 831 Map oldobjs = new HashMap(); 832 oldobjs.put(argName, new Double(3.1415)); 833 String result = mf.format( oldobjs ); 834 logln("pattern: \"" + mf.toPattern() + "\""); 835 logln("text for parsing: \"" + result + "\""); 836 // result now equals "3.14, 3.1" 837 if (!result.equals("3.14, 3.1")) 838 errln("result = " + result); 839 Map newobjs = mf.parseToMap(result, new ParsePosition(0)); 840 // newobjs now equals {new Double(3.1)} 841 if (((Number)newobjs.get(argName)).doubleValue() != 3.1) // was (Double) [alan] 842 errln( "newobjs.get(argName) = " + newobjs.get(argName)); 843 }{ // Taken from Test4105380(). 844 String patternText1 = "The disk \"{diskName}\" contains {numberOfFiles}."; 845 String patternText2 = "There are {numberOfFiles} on the disk \"{diskName}\""; 846 MessageFormat form1 = new MessageFormat(patternText1); 847 MessageFormat form2 = new MessageFormat(patternText2); 848 double[] filelimits = {0,1,2}; 849 String[] filepart = {"no files","one file","{numberOfFiles,number} files"}; 850 ChoiceFormat fileform = new ChoiceFormat(filelimits, filepart); 851 form1.setFormat(1, fileform); 852 form2.setFormat(0, fileform); 853 Map testArgs = new HashMap(); 854 testArgs.put("diskName", "MyDisk"); 855 testArgs.put("numberOfFiles", new Long(12373)); 856 logln(form1.format(testArgs)); 857 logln(form2.format(testArgs)); 858 }{ // Taken from test4293229(). 859 MessageFormat format = new MessageFormat("'''{'myNamedArgument}'' '''{myNamedArgument}'''"); 860 Map args = new HashMap(); 861 String expected = "'{myNamedArgument}' '{myNamedArgument}'"; 862 String result = format.format(args); 863 if (!result.equals(expected)) { 864 throw new RuntimeException("wrong format result - expected \"" + 865 expected + "\", got \"" + result + "\""); 866 } 867 } 868 } 869 870 private MessageFormat serializeAndDeserialize(MessageFormat original) { 871 try { 872 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 873 ObjectOutputStream ostream = new ObjectOutputStream(baos); 874 ostream.writeObject(original); 875 ostream.flush(); 876 byte bytes[] = baos.toByteArray(); 877 878 ObjectInputStream istream = new ObjectInputStream(new ByteArrayInputStream(bytes)); 879 MessageFormat reconstituted = (MessageFormat)istream.readObject(); 880 return reconstituted; 881 } catch(IOException e) { 882 throw new RuntimeException(e); 883 } catch (ClassNotFoundException e) { 884 throw new RuntimeException(e); 885 } 886 } 887 888 @Test 889 public void TestSerialization() { 890 MessageFormat format1 = null; 891 MessageFormat format2 = null; 892 893 format1 = new MessageFormat("", ULocale.GERMAN); 894 format2 = serializeAndDeserialize(format1); 895 assertEquals("MessageFormats (empty pattern) before and after serialization are not equal", format1, format2); 896 897 format1.applyPattern("ab{1}cd{0,number}ef{3,date}gh"); 898 format1.setFormat(2, null); 899 format1.setFormatByArgumentIndex(1, NumberFormat.getInstance(ULocale.ENGLISH)); 900 format2 = serializeAndDeserialize(format1); 901 assertEquals("MessageFormats (with custom formats) before and after serialization are not equal", format1, format2); 902 assertEquals( 903 "MessageFormat (with custom formats) does not "+ 904 "format correctly after serialization", 905 "ab3.3cd4,4ef***gh", 906 format2.format(new Object[] { 4.4, 3.3, "+++", "***" })); 907 } 908 } 909