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