1 /*
   2  * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 /*
  25  * @test
  26  * @bug 4031438 4058973 4074764 4094906 4104976 4105380 4106659 4106660 4106661
  27  * 4111739 4112104 4113018 4114739 4114743 4116444 4118592 4118594 4120552
  28  * 4142938 4169959 4232154 4293229
  29  * @summary Regression tests for MessageFormat and associated classes
  30  * @library /java/text/testlib
  31  * @run main MessageRegression
  32  */
  33 /*
  34 (C) Copyright Taligent, Inc. 1996 - All Rights Reserved
  35 (C) Copyright IBM Corp. 1996 - All Rights Reserved
  36 
  37   The original version of this source code and documentation is copyrighted and
  38 owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These materials are
  39 provided under terms of a License Agreement between Taligent and Sun. This
  40 technology is protected by multiple US and International patents. This notice and
  41 attribution to Taligent may not be removed.
  42   Taligent is a registered trademark of Taligent, Inc.
  43 */
  44 
  45 import java.text.*;
  46 import java.util.*;
  47 import java.io.IOException;
  48 import java.io.FileOutputStream;
  49 import java.io.FileInputStream;
  50 import java.io.ByteArrayInputStream;
  51 import java.io.ByteArrayOutputStream;
  52 import java.io.ObjectOutputStream;
  53 import java.io.ObjectInputStream;
  54 import java.io.Serializable;
  55 
  56 public class MessageRegression extends IntlTest {
  57 
  58     public static void main(String[] args) throws Exception {
  59         new MessageRegression().run(args);
  60     }
  61 
  62     /* @bug 4074764
  63      * Null exception when formatting pattern with MessageFormat
  64      * with no parameters.
  65      */
  66     public void Test4074764() {
  67         String[] pattern = {"Message without param",
  68         "Message with param:{0}",
  69         "Longer Message with param {0}"};
  70         //difference between the two param strings are that
  71         //in the first one, the param position is within the
  72         //length of the string without param while it is not so
  73         //in the other case.
  74 
  75         MessageFormat messageFormatter = new MessageFormat("");
  76 
  77         try {
  78             //Apply pattern with param and print the result
  79             messageFormatter.applyPattern(pattern[1]);
  80             Object[] params = {new String("BUG"), new Date()};
  81             String tempBuffer = messageFormatter.format(params);
  82             if (!tempBuffer.equals("Message with param:BUG"))
  83                 errln("MessageFormat with one param test failed.");
  84             logln("Formatted with one extra param : " + tempBuffer);
  85 
  86             //Apply pattern without param and print the result
  87             messageFormatter.applyPattern(pattern[0]);
  88             tempBuffer = messageFormatter.format(null);
  89             if (!tempBuffer.equals("Message without param"))
  90                 errln("MessageFormat with no param test failed.");
  91             logln("Formatted with no params : " + tempBuffer);
  92 
  93              tempBuffer = messageFormatter.format(params);
  94              if (!tempBuffer.equals("Message without param"))
  95                 errln("Formatted with arguments > subsitution failed. result = " + tempBuffer.toString());
  96              logln("Formatted with extra params : " + tempBuffer);
  97             //This statement gives an exception while formatting...
  98             //If we use pattern[1] for the message with param,
  99             //we get an NullPointerException in MessageFormat.java(617)
 100             //If we use pattern[2] for the message with param,
 101             //we get an StringArrayIndexOutOfBoundsException in MessageFormat.java(614)
 102             //Both are due to maxOffset not being reset to -1
 103             //in applyPattern() when the pattern does not
 104             //contain any param.
 105         } catch (Exception foo) {
 106             errln("Exception when formatting with no params.");
 107         }
 108     }
 109 
 110     /* @bug 4058973
 111      * MessageFormat.toPattern has weird rounding behavior.
 112      */
 113     public void Test4058973() {
 114 
 115         MessageFormat fmt = new MessageFormat("{0,choice,0#no files|1#one file|1< {0,number,integer} files}");
 116         String pat = fmt.toPattern();
 117         if (!pat.equals("{0,choice,0.0#no files|1.0#one file|1.0< {0,number,integer} files}")) {
 118             errln("MessageFormat.toPattern failed");
 119         }
 120     }
 121     /* @bug 4031438
 122      * More robust message formats.
 123      */
 124     public void Test4031438() {
 125         Locale locale = Locale.getDefault();
 126         if (!TestUtils.usesAsciiDigits(locale)) {
 127             logln("Skipping this test because locale is " + locale);
 128             return;
 129         }
 130 
 131         String pattern1 = "Impossible {1} has occurred -- status code is {0} and message is {2}.";
 132         String pattern2 = "Double '' Quotes {0} test and quoted '{1}' test plus 'other {2} stuff'.";
 133 
 134         MessageFormat messageFormatter = new MessageFormat("");
 135 
 136         try {
 137             logln("Apply with pattern : " + pattern1);
 138             messageFormatter.applyPattern(pattern1);
 139             Object[] params = {new Integer(7)};
 140             String tempBuffer = messageFormatter.format(params);
 141             if (!tempBuffer.equals("Impossible {1} has occurred -- status code is 7 and message is {2}."))
 142                 errln("Tests arguments < substitution failed. Formatted text=" +
 143                       "<" + tempBuffer + ">");
 144             logln("Formatted with 7 : " + tempBuffer);
 145             ParsePosition status = new ParsePosition(0);
 146             Object[] objs = messageFormatter.parse(tempBuffer, status);
 147             if (objs[params.length] != null)
 148                 errln("Parse failed with more than expected arguments");
 149             for (int i = 0; i < objs.length; i++) {
 150                 if (objs[i] != null && !objs[i].toString().equals(params[i].toString())) {
 151                     errln("Parse failed on object " + objs[i] + " at index : " + i);
 152                 }
 153             }
 154             tempBuffer = messageFormatter.format(null);
 155             if (!tempBuffer.equals("Impossible {1} has occurred -- status code is {0} and message is {2}."))
 156                 errln("Tests with no arguments failed");
 157             logln("Formatted with null : " + tempBuffer);
 158             logln("Apply with pattern : " + pattern2);
 159             messageFormatter.applyPattern(pattern2);
 160             tempBuffer = messageFormatter.format(params);
 161             if (!tempBuffer.equals("Double ' Quotes 7 test and quoted {1} test plus other {2} stuff."))
 162                 errln("quote format test (w/ params) failed.");
 163             logln("Formatted with params : " + tempBuffer);
 164             tempBuffer = messageFormatter.format(null);
 165             if (!tempBuffer.equals("Double ' Quotes {0} test and quoted {1} test plus other {2} stuff."))
 166                 errln("quote format test (w/ null) failed.");
 167             logln("Formatted with null : " + tempBuffer);
 168             logln("toPattern : " + messageFormatter.toPattern());
 169         } catch (Exception foo) {
 170             errln("Exception when formatting in bug 4031438. "+foo.getMessage());
 171         }
 172     }
 173     public void Test4052223()
 174     {
 175         ParsePosition pos = new ParsePosition(0);
 176         if (pos.getErrorIndex() != -1) {
 177             errln("ParsePosition.getErrorIndex initialization failed.");
 178         }
 179         MessageFormat fmt = new MessageFormat("There are {0} apples growing on the {1} tree.");
 180         String str = new String("There is one apple growing on the peach tree.");
 181         Object[] objs = fmt.parse(str, pos);
 182         logln("unparsable string , should fail at " + pos.getErrorIndex());
 183         if (pos.getErrorIndex() == -1)
 184             errln("Bug 4052223 failed : parsing string " + str);
 185         pos.setErrorIndex(4);
 186         if (pos.getErrorIndex() != 4)
 187             errln("setErrorIndex failed, got " + pos.getErrorIndex() + " instead of 4");
 188         ChoiceFormat f = new ChoiceFormat(
 189             "-1#are negative|0#are no or fraction|1#is one|1.0<is 1+|2#are two|2<are more than 2.");
 190         pos.setIndex(0); pos.setErrorIndex(-1);
 191         Number obj = f.parse("are negative", pos);
 192         if (pos.getErrorIndex() != -1 && obj.doubleValue() == -1.0)
 193             errln("Parse with \"are negative\" failed, at " + pos.getErrorIndex());
 194         pos.setIndex(0); pos.setErrorIndex(-1);
 195         obj = f.parse("are no or fraction ", pos);
 196         if (pos.getErrorIndex() != -1 && obj.doubleValue() == 0.0)
 197             errln("Parse with \"are no or fraction\" failed, at " + pos.getErrorIndex());
 198         pos.setIndex(0); pos.setErrorIndex(-1);
 199         obj = f.parse("go postal", pos);
 200         if (pos.getErrorIndex() == -1 && !Double.isNaN(obj.doubleValue()))
 201             errln("Parse with \"go postal\" failed, at " + pos.getErrorIndex());
 202     }
 203     /* @bug 4104976
 204      * ChoiceFormat.equals(null) throws NullPointerException
 205      */
 206     public void Test4104976()
 207     {
 208         double[] limits = {1, 20};
 209         String[] formats = {"xyz", "abc"};
 210         ChoiceFormat cf = new ChoiceFormat(limits, formats);
 211         try {
 212             log("Compares to null is always false, returned : ");
 213             logln(cf.equals(null) ? "TRUE" : "FALSE");
 214         } catch (Exception foo) {
 215             errln("ChoiceFormat.equals(null) throws exception.");
 216         }
 217     }
 218     /* @bug 4106659
 219      * ChoiceFormat.ctor(double[], String[]) doesn't check
 220      * whether lengths of input arrays are equal.
 221      */
 222     public void Test4106659()
 223     {
 224         double[] limits = {1, 2, 3};
 225         String[] formats = {"one", "two"};
 226         ChoiceFormat cf = null;
 227         try {
 228             cf = new ChoiceFormat(limits, formats);
 229         } catch (Exception foo) {
 230             logln("ChoiceFormat constructor should check for the array lengths");
 231             cf = null;
 232         }
 233         if (cf != null) errln(cf.format(5));
 234     }
 235 
 236     /* @bug 4106660
 237      * ChoiceFormat.ctor(double[], String[]) allows unordered double array.
 238      * This is not a bug, added javadoc to emphasize the use of limit
 239      * array must be in ascending order.
 240      */
 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     public void Test4111739()
 256     {
 257         MessageFormat format1 = null;
 258         MessageFormat format2 = null;
 259         ObjectOutputStream ostream = null;
 260         ByteArrayOutputStream baos = null;
 261         ObjectInputStream istream = null;
 262 
 263         try {
 264             baos = new ByteArrayOutputStream();
 265             ostream = new ObjectOutputStream(baos);
 266         } catch(IOException e) {
 267             errln("Unexpected exception : " + e.getMessage());
 268             return;
 269         }
 270 
 271         try {
 272             format1 = new MessageFormat("pattern{0}");
 273             ostream.writeObject(format1);
 274             ostream.flush();
 275 
 276             byte bytes[] = baos.toByteArray();
 277 
 278             istream = new ObjectInputStream(new ByteArrayInputStream(bytes));
 279             format2 = (MessageFormat)istream.readObject();
 280         } catch(Exception e) {
 281             errln("Unexpected exception : " + e.getMessage());
 282         }
 283 
 284         if (!format1.equals(format2)) {
 285             errln("MessageFormats before and after serialization are not" +
 286                 " equal\nformat1 = " + format1 + "(" + format1.toPattern() + ")\nformat2 = " +
 287                 format2 + "(" + format2.toPattern() + ")");
 288         } else {
 289             logln("Serialization for MessageFormat is OK.");
 290         }
 291     }
 292     /* @bug 4114743
 293      * MessageFormat.applyPattern allows illegal patterns.
 294      */
 295     public void Test4114743()
 296     {
 297         String originalPattern = "initial pattern";
 298         MessageFormat mf = new MessageFormat(originalPattern);
 299         try {
 300             String illegalPattern = "ab { '}' de";
 301             mf.applyPattern(illegalPattern);
 302             errln("illegal pattern: \"" + illegalPattern + "\"");
 303         } catch (IllegalArgumentException foo) {
 304             if (!originalPattern.equals(mf.toPattern()))
 305                 errln("pattern after: \"" + mf.toPattern() + "\"");
 306         }
 307     }
 308 
 309     /* @bug 4116444
 310      * MessageFormat.parse has different behavior in case of null.
 311      */
 312     public void Test4116444()
 313     {
 314         String[] patterns = {"", "one", "{0,date,short}"};
 315         MessageFormat mf = new MessageFormat("");
 316 
 317         for (int i = 0; i < patterns.length; i++) {
 318             String pattern = patterns[i];
 319             mf.applyPattern(pattern);
 320             try {
 321                 Object[] array = mf.parse(null, new ParsePosition(0));
 322                 logln("pattern: \"" + pattern + "\"");
 323                 log(" parsedObjects: ");
 324                 if (array != null) {
 325                     log("{");
 326                     for (int j = 0; j < array.length; j++) {
 327                         if (array[j] != null)
 328                             err("\"" + array[j].toString() + "\"");
 329                         else
 330                             log("null");
 331                         if (j < array.length - 1) log(",");
 332                     }
 333                     log("}") ;
 334                 } else {
 335                     log("null");
 336                 }
 337                 logln("");
 338             } catch (Exception e) {
 339                 errln("pattern: \"" + pattern + "\"");
 340                 errln("  Exception: " + e.getMessage());
 341             }
 342         }
 343 
 344     }
 345     /* @bug 4114739 (FIX and add javadoc)
 346      * MessageFormat.format has undocumented behavior about empty format objects.
 347      */
 348     public void Test4114739()
 349     {
 350 
 351         MessageFormat mf = new MessageFormat("<{0}>");
 352         Object[] objs1 = null;
 353         Object[] objs2 = {};
 354         Object[] objs3 = {null};
 355         try {
 356             logln("pattern: \"" + mf.toPattern() + "\"");
 357             log("format(null) : ");
 358             logln("\"" + mf.format(objs1) + "\"");
 359             log("format({})   : ");
 360             logln("\"" + mf.format(objs2) + "\"");
 361             log("format({null}) :");
 362             logln("\"" + mf.format(objs3) + "\"");
 363         } catch (Exception e) {
 364             errln("Exception thrown for null argument tests.");
 365         }
 366     }
 367 
 368     /* @bug 4113018
 369      * MessageFormat.applyPattern works wrong with illegal patterns.
 370      */
 371     public void Test4113018()
 372     {
 373         String originalPattern = "initial pattern";
 374         MessageFormat mf = new MessageFormat(originalPattern);
 375         String illegalPattern = "format: {0, xxxYYY}";
 376         logln("pattern before: \"" + mf.toPattern() + "\"");
 377         logln("illegal pattern: \"" + illegalPattern + "\"");
 378         try {
 379             mf.applyPattern(illegalPattern);
 380             errln("Should have thrown IllegalArgumentException for pattern : " + illegalPattern);
 381         } catch (IllegalArgumentException e) {
 382             if (!originalPattern.equals(mf.toPattern()))
 383                 errln("pattern after: \"" + mf.toPattern() + "\"");
 384         }
 385     }
 386     /* @bug 4106661
 387      * ChoiceFormat is silent about the pattern usage in javadoc.
 388      */
 389     public void Test4106661()
 390     {
 391         ChoiceFormat fmt = new ChoiceFormat(
 392           "-1#are negative| 0#are no or fraction | 1#is one |1.0<is 1+ |2#are two |2<are more than 2.");
 393         logln("Formatter Pattern : " + fmt.toPattern());
 394 
 395         logln("Format with -INF : " + fmt.format(Double.NEGATIVE_INFINITY));
 396         logln("Format with -1.0 : " + fmt.format(-1.0));
 397         logln("Format with 0 : " + fmt.format(0));
 398         logln("Format with 0.9 : " + fmt.format(0.9));
 399         logln("Format with 1.0 : " + fmt.format(1));
 400         logln("Format with 1.5 : " + fmt.format(1.5));
 401         logln("Format with 2 : " + fmt.format(2));
 402         logln("Format with 2.1 : " + fmt.format(2.1));
 403         logln("Format with NaN : " + fmt.format(Double.NaN));
 404         logln("Format with +INF : " + fmt.format(Double.POSITIVE_INFINITY));
 405     }
 406     /* @bug 4094906
 407      * ChoiceFormat should accept \u221E as eq. to INF.
 408      */
 409     public void Test4094906()
 410     {
 411         ChoiceFormat fmt = new ChoiceFormat(
 412           "-\u221E<are negative|0<are no or fraction|1#is one|1.0<is 1+|\u221E<are many.");
 413         if (!fmt.toPattern().startsWith("-\u221E<are negative|0.0<are no or fraction|1.0#is one|1.0<is 1+|\u221E<are many."))
 414             errln("Formatter Pattern : " + fmt.toPattern());
 415         logln("Format with -INF : " + fmt.format(Double.NEGATIVE_INFINITY));
 416         logln("Format with -1.0 : " + fmt.format(-1.0));
 417         logln("Format with 0 : " + fmt.format(0));
 418         logln("Format with 0.9 : " + fmt.format(0.9));
 419         logln("Format with 1.0 : " + fmt.format(1));
 420         logln("Format with 1.5 : " + fmt.format(1.5));
 421         logln("Format with 2 : " + fmt.format(2));
 422         logln("Format with +INF : " + fmt.format(Double.POSITIVE_INFINITY));
 423     }
 424 
 425     /* @bug 4118592
 426      * MessageFormat.parse fails with ChoiceFormat.
 427      */
 428     public void Test4118592()
 429     {
 430         MessageFormat mf = new MessageFormat("");
 431         String pattern = "{0,choice,1#YES|2#NO}";
 432         String prefix = "";
 433         for (int i = 0; i < 5; i++) {
 434             String formatted = prefix + "YES";
 435             mf.applyPattern(prefix + pattern);
 436             prefix += "x";
 437             Object[] objs = mf.parse(formatted, new ParsePosition(0));
 438             logln(i + ". pattern :\"" + mf.toPattern() + "\"");
 439             log(" \"" + formatted + "\" parsed as ");
 440             if (objs == null) logln("  null");
 441             else logln("  " + objs[0]);
 442         }
 443     }
 444     /* @bug 4118594
 445      * MessageFormat.parse fails for some patterns.
 446      */
 447     public void Test4118594()
 448     {
 449         MessageFormat mf = new MessageFormat("{0}, {0}, {0}");
 450         String forParsing = "x, y, z";
 451         Object[] objs = mf.parse(forParsing, new ParsePosition(0));
 452         logln("pattern: \"" + mf.toPattern() + "\"");
 453         logln("text for parsing: \"" + forParsing + "\"");
 454         if (!objs[0].toString().equals("z"))
 455             errln("argument0: \"" + objs[0] + "\"");
 456         mf.setLocale(Locale.US);
 457         mf.applyPattern("{0,number,#.##}, {0,number,#.#}");
 458         Object[] oldobjs = {new Double(3.1415)};
 459         String result = mf.format( oldobjs );
 460         logln("pattern: \"" + mf.toPattern() + "\"");
 461         logln("text for parsing: \"" + result + "\"");
 462         // result now equals "3.14, 3.1"
 463         if (!result.equals("3.14, 3.1"))
 464             errln("result = " + result);
 465         Object[] newobjs = mf.parse(result, new ParsePosition(0));
 466         // newobjs now equals {new Double(3.1)}
 467         if (((Double)newobjs[0]).doubleValue() != 3.1)
 468             errln( "newobjs[0] = " + newobjs[0]);
 469     }
 470     /* @bug 4105380
 471      * When using ChoiceFormat, MessageFormat is not good for I18n.
 472      */
 473     public void Test4105380()
 474     {
 475         String patternText1 = "The disk \"{1}\" contains {0}.";
 476         String patternText2 = "There are {0} on the disk \"{1}\"";
 477         MessageFormat form1 = new MessageFormat(patternText1);
 478         MessageFormat form2 = new MessageFormat(patternText2);
 479         double[] filelimits = {0,1,2};
 480         String[] filepart = {"no files","one file","{0,number} files"};
 481         ChoiceFormat fileform = new ChoiceFormat(filelimits, filepart);
 482         form1.setFormat(1, fileform);
 483         form2.setFormat(0, fileform);
 484         Object[] testArgs = {new Long(12373), "MyDisk"};
 485         logln(form1.format(testArgs));
 486         logln(form2.format(testArgs));
 487     }
 488     /* @bug 4120552
 489      * MessageFormat.parse incorrectly sets errorIndex.
 490      */
 491     public void Test4120552()
 492     {
 493         MessageFormat mf = new MessageFormat("pattern");
 494         String texts[] = {"pattern", "pat", "1234"};
 495         logln("pattern: \"" + mf.toPattern() + "\"");
 496         for (int i = 0; i < texts.length; i++) {
 497             ParsePosition pp = new ParsePosition(0);
 498             Object[] objs = mf.parse(texts[i], pp);
 499             log("  text for parsing: \"" + texts[i] + "\"");
 500             if (objs == null) {
 501                 logln("  (incorrectly formatted string)");
 502                 if (pp.getErrorIndex() == -1)
 503                     errln("Incorrect error index: " + pp.getErrorIndex());
 504             } else {
 505                 logln("  (correctly formatted string)");
 506             }
 507         }
 508     }
 509 
 510     /**
 511      * @bug 4142938
 512      * MessageFormat handles single quotes in pattern wrong.
 513      * This is actually a problem in ChoiceFormat; it doesn't
 514      * understand single quotes.
 515      */
 516     public void Test4142938() {
 517         String pat = "''Vous'' {0,choice,0#n''|1#}avez s\u00E9lectionne\u00E9 " +
 518             "{0,choice,0#aucun|1#{0}} client{0,choice,0#s|1#|2#s} " +
 519             "personnel{0,choice,0#s|1#|2#s}.";
 520         MessageFormat mf = new MessageFormat(pat);
 521 
 522         String[] PREFIX = {
 523             "'Vous' n'avez s\u00E9lectionne\u00E9 aucun clients personnels.",
 524             "'Vous' avez s\u00E9lectionne\u00E9 ",
 525             "'Vous' avez s\u00E9lectionne\u00E9 "
 526         };
 527         String[] SUFFIX = {
 528             null,
 529             " client personnel.",
 530             " clients personnels."
 531         };
 532 
 533         for (int i=0; i<3; i++) {
 534             String out = mf.format(new Object[]{new Integer(i)});
 535             if (SUFFIX[i] == null) {
 536                 if (!out.equals(PREFIX[i]))
 537                     errln("" + i + ": Got \"" + out + "\"; Want \"" + PREFIX[i] + "\"");
 538             }
 539             else {
 540                 if (!out.startsWith(PREFIX[i]) ||
 541                     !out.endsWith(SUFFIX[i]))
 542                     errln("" + i + ": Got \"" + out + "\"; Want \"" + PREFIX[i] + "\"...\"" +
 543                           SUFFIX[i] + "\"");
 544             }
 545         }
 546     }
 547 
 548     /**
 549      * @bug 4142938
 550      * Test the applyPattern and toPattern handling of single quotes
 551      * by ChoiceFormat.  (This is in here because this was a bug reported
 552      * against MessageFormat.)  The single quote is used to quote the
 553      * pattern characters '|', '#', '<', and '\u2264'.  Two quotes in a row
 554      * is a quote literal.
 555      */
 556     public void TestChoicePatternQuote() {
 557         String[] DATA = {
 558             // Pattern                  0 value           1 value
 559             "0#can''t|1#can",           "can't",          "can",
 560             "0#'pound(#)=''#'''|1#xyz", "pound(#)='#'",   "xyz",
 561             "0#'1<2 | 1\u22641'|1#''",  "1<2 | 1\u22641", "'",
 562         };
 563         for (int i=0; i<DATA.length; i+=3) {
 564             try {
 565                 ChoiceFormat cf = new ChoiceFormat(DATA[i]);
 566                 for (int j=0; j<=1; ++j) {
 567                     String out = cf.format(j);
 568                     if (!out.equals(DATA[i+1+j]))
 569                         errln("Fail: Pattern \"" + DATA[i] + "\" x "+j+" -> " +
 570                               out + "; want \"" + DATA[i+1+j] + '"');
 571                 }
 572                 String pat = cf.toPattern();
 573                 String pat2 = new ChoiceFormat(pat).toPattern();
 574                 if (!pat.equals(pat2))
 575                     errln("Fail: Pattern \"" + DATA[i] + "\" x toPattern -> \"" + pat + '"');
 576                 else
 577                     logln("Ok: Pattern \"" + DATA[i] + "\" x toPattern -> \"" + pat + '"');
 578             }
 579             catch (IllegalArgumentException e) {
 580                 errln("Fail: Pattern \"" + DATA[i] + "\" -> " + e);
 581             }
 582         }
 583     }
 584 
 585     /**
 586      * @bug 4112104
 587      * MessageFormat.equals(null) throws a NullPointerException.  The JLS states
 588      * that it should return false.
 589      */
 590     public void Test4112104() {
 591         MessageFormat format = new MessageFormat("");
 592         try {
 593             // This should NOT throw an exception
 594             if (format.equals(null)) {
 595                 // It also should return false
 596                 errln("MessageFormat.equals(null) returns false");
 597             }
 598         }
 599         catch (NullPointerException e) {
 600             errln("MessageFormat.equals(null) throws " + e);
 601         }
 602     }
 603 
 604     /**
 605      * @bug 4169959
 606      * MessageFormat does not format null objects. CANNOT REPRODUCE THIS BUG.
 607      */
 608     public void Test4169959() {
 609         // This works
 610         logln(MessageFormat.format( "This will {0}",
 611                                     new String[]{"work"} ) );
 612 
 613         // This fails
 614         logln(MessageFormat.format( "This will {0}",
 615                                     new Object[]{ null } ) );
 616     }
 617 
 618     public void test4232154() {
 619         boolean gotException = false;
 620         try {
 621             MessageFormat format = new MessageFormat("The date is {0:date}");
 622         } catch (Exception e) {
 623             gotException = true;
 624             if (!(e instanceof IllegalArgumentException)) {
 625                 throw new RuntimeException("got wrong exception type");
 626             }
 627             if ("argument number too large at ".equals(e.getMessage())) {
 628                 throw new RuntimeException("got wrong exception message");
 629             }
 630         }
 631         if (!gotException) {
 632             throw new RuntimeException("didn't get exception for invalid input");
 633         }
 634     }
 635 
 636     public void test4293229() {
 637         MessageFormat format = new MessageFormat("'''{'0}'' '''{0}'''");
 638         Object[] args = { null };
 639         String expected = "'{0}' '{0}'";
 640         String result = format.format(args);
 641         if (!result.equals(expected)) {
 642             throw new RuntimeException("wrong format result - expected \"" +
 643                     expected + "\", got \"" + result + "\"");
 644         }
 645     }
 646 }