1 /*
  2  * Copyright (c) 1997, 2023, 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 8187551
 29  * @summary Regression tests for MessageFormat and associated classes
 30  * @library /java/text/testlib
 31  * @run junit 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 import org.junit.jupiter.api.Test;
 57 
 58 import static org.junit.jupiter.api.Assertions.fail;
 59 
 60 public class MessageRegression {
 61 
 62     /* @bug 4074764
 63      * Null exception when formatting pattern with MessageFormat
 64      * with no parameters.
 65      */
 66     @Test
 67     public void Test4074764() {
 68         String[] pattern = {"Message without param",
 69         "Message with param:{0}",
 70         "Longer Message with param {0}"};
 71         //difference between the two param strings are that
 72         //in the first one, the param position is within the
 73         //length of the string without param while it is not so
 74         //in the other case.
 75 
 76         MessageFormat messageFormatter = new MessageFormat("");
 77 
 78         try {
 79             //Apply pattern with param and print the result
 80             messageFormatter.applyPattern(pattern[1]);
 81             Object[] params = {new String("BUG"), new Date()};
 82             String tempBuffer = messageFormatter.format(params);
 83             if (!tempBuffer.equals("Message with param:BUG"))
 84                 fail("MessageFormat with one param test failed.");
 85             System.out.println("Formatted with one extra param : " + tempBuffer);
 86 
 87             //Apply pattern without param and print the result
 88             messageFormatter.applyPattern(pattern[0]);
 89             tempBuffer = messageFormatter.format(null);
 90             if (!tempBuffer.equals("Message without param"))
 91                 fail("MessageFormat with no param test failed.");
 92             System.out.println("Formatted with no params : " + tempBuffer);
 93 
 94              tempBuffer = messageFormatter.format(params);
 95              if (!tempBuffer.equals("Message without param"))
 96                 fail("Formatted with arguments > subsitution failed. result = " + tempBuffer.toString());
 97              System.out.println("Formatted with extra params : " + tempBuffer);
 98             //This statement gives an exception while formatting...
 99             //If we use pattern[1] for the message with param,
100             //we get an NullPointerException in MessageFormat.java(617)
101             //If we use pattern[2] for the message with param,
102             //we get an StringArrayIndexOutOfBoundsException in MessageFormat.java(614)
103             //Both are due to maxOffset not being reset to -1
104             //in applyPattern() when the pattern does not
105             //contain any param.
106         } catch (Exception foo) {
107             fail("Exception when formatting with no params.");
108         }
109     }
110 
111     /* @bug 4058973
112      * MessageFormat.toPattern has weird rounding behavior.
113      */
114     @Test
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             fail("MessageFormat.toPattern failed");
121         }
122     }
123     /* @bug 4031438
124      * More robust message formats.
125      */
126     @Test
127     public void Test4031438() {
128         Locale locale = Locale.getDefault();
129         if (!TestUtils.usesAsciiDigits(locale)) {
130             System.out.println("Skipping this test because locale is " + locale);
131             return;
132         }
133 
134         String pattern1 = "Impossible {1} has occurred -- status code is {0} and message is {2}.";
135         String pattern2 = "Double '' Quotes {0} test and quoted '{1}' test plus 'other {2} stuff'.";
136 
137         MessageFormat messageFormatter = new MessageFormat("");
138 
139         try {
140             System.out.println("Apply with pattern : " + pattern1);
141             messageFormatter.applyPattern(pattern1);
142             Object[] params = {7};
143             String tempBuffer = messageFormatter.format(params);
144             if (!tempBuffer.equals("Impossible {1} has occurred -- status code is 7 and message is {2}."))
145                 fail("Tests arguments < substitution failed. Formatted text=" +
146                       "<" + tempBuffer + ">");
147             System.out.println("Formatted with 7 : " + tempBuffer);
148             ParsePosition status = new ParsePosition(0);
149             Object[] objs = messageFormatter.parse(tempBuffer, status);
150             if (objs[params.length] != null)
151                 fail("Parse failed with more than expected arguments");
152             for (int i = 0; i < objs.length; i++) {
153                 if (objs[i] != null && !objs[i].toString().equals(params[i].toString())) {
154                     fail("Parse failed on object " + objs[i] + " at index : " + i);
155                 }
156             }
157             tempBuffer = messageFormatter.format(null);
158             if (!tempBuffer.equals("Impossible {1} has occurred -- status code is {0} and message is {2}."))
159                 fail("Tests with no arguments failed");
160             System.out.println("Formatted with null : " + tempBuffer);
161             System.out.println("Apply with pattern : " + pattern2);
162             messageFormatter.applyPattern(pattern2);
163             tempBuffer = messageFormatter.format(params);
164             if (!tempBuffer.equals("Double ' Quotes 7 test and quoted {1} test plus other {2} stuff."))
165                 fail("quote format test (w/ params) failed.");
166             System.out.println("Formatted with params : " + tempBuffer);
167             tempBuffer = messageFormatter.format(null);
168             if (!tempBuffer.equals("Double ' Quotes {0} test and quoted {1} test plus other {2} stuff."))
169                 fail("quote format test (w/ null) failed.");
170             System.out.println("Formatted with null : " + tempBuffer);
171             System.out.println("toPattern : " + messageFormatter.toPattern());
172         } catch (Exception foo) {
173             fail("Exception when formatting in bug 4031438. "+foo.getMessage());
174         }
175     }
176     @Test
177     public void Test4052223()
178     {
179         ParsePosition pos = new ParsePosition(0);
180         if (pos.getErrorIndex() != -1) {
181             fail("ParsePosition.getErrorIndex initialization failed.");
182         }
183         MessageFormat fmt = new MessageFormat("There are {0} apples growing on the {1} tree.");
184         String str = new String("There is one apple growing on the peach tree.");
185         Object[] objs = fmt.parse(str, pos);
186         System.out.println("unparsable string , should fail at " + pos.getErrorIndex());
187         if (pos.getErrorIndex() == -1)
188             fail("Bug 4052223 failed : parsing string " + str);
189         pos.setErrorIndex(4);
190         if (pos.getErrorIndex() != 4)
191             fail("setErrorIndex failed, got " + pos.getErrorIndex() + " instead of 4");
192         ChoiceFormat f = new ChoiceFormat(
193             "-1#are negative|0#are no or fraction|1#is one|1.0<is 1+|2#are two|2<are more than 2.");
194         pos.setIndex(0); pos.setErrorIndex(-1);
195         Number obj = f.parse("are negative", pos);
196         if (pos.getErrorIndex() != -1 && obj.doubleValue() == -1.0)
197             fail("Parse with \"are negative\" failed, at " + pos.getErrorIndex());
198         pos.setIndex(0); pos.setErrorIndex(-1);
199         obj = f.parse("are no or fraction ", pos);
200         if (pos.getErrorIndex() != -1 && obj.doubleValue() == 0.0)
201             fail("Parse with \"are no or fraction\" failed, at " + pos.getErrorIndex());
202         pos.setIndex(0); pos.setErrorIndex(-1);
203         obj = f.parse("go postal", pos);
204         if (pos.getErrorIndex() == -1 && !Double.isNaN(obj.doubleValue()))
205             fail("Parse with \"go postal\" failed, at " + pos.getErrorIndex());
206     }
207     /* @bug 4104976
208      * ChoiceFormat.equals(null) throws NullPointerException
209      */
210     @Test
211     public void Test4104976()
212     {
213         double[] limits = {1, 20};
214         String[] formats = {"xyz", "abc"};
215         ChoiceFormat cf = new ChoiceFormat(limits, formats);
216         try {
217             System.out.println("Compares to null is always false, returned : ");
218             System.out.println(cf.equals(null) ? "TRUE" : "FALSE");
219         } catch (Exception foo) {
220             fail("ChoiceFormat.equals(null) throws exception.");
221         }
222     }
223     /* @bug 4106659
224      * ChoiceFormat.ctor(double[], String[]) doesn't check
225      * whether lengths of input arrays are equal.
226      */
227     @Test
228     public void Test4106659()
229     {
230         double[] limits = {1, 2, 3};
231         String[] formats = {"one", "two"};
232         ChoiceFormat cf = null;
233         try {
234             cf = new ChoiceFormat(limits, formats);
235         } catch (Exception foo) {
236             System.out.println("ChoiceFormat constructor should check for the array lengths");
237             cf = null;
238         }
239         if (cf != null) fail(cf.format(5));
240     }
241 
242     /* @bug 4106660
243      * ChoiceFormat.ctor(double[], String[]) allows unordered double array.
244      * This is not a bug, added javadoc to emphasize the use of limit
245      * array must be in ascending order.
246      */
247     @Test
248     public void Test4106660()
249     {
250         double[] limits = {3, 1, 2};
251         String[] formats = {"Three", "One", "Two"};
252         ChoiceFormat cf = new ChoiceFormat(limits, formats);
253         double d = 5.0;
254         String str = cf.format(d);
255         if (!str.equals("Two"))
256             fail("format(" + d + ") = " + cf.format(d));
257     }
258 
259     /* @bug 4111739
260      * MessageFormat is incorrectly serialized/deserialized.
261      */
262     @Test
263     public void Test4111739()
264     {
265         MessageFormat format1 = null;
266         MessageFormat format2 = null;
267         ObjectOutputStream ostream = null;
268         ByteArrayOutputStream baos = null;
269         ObjectInputStream istream = null;
270 
271         try {
272             baos = new ByteArrayOutputStream();
273             ostream = new ObjectOutputStream(baos);
274         } catch(IOException e) {
275             fail("Unexpected exception : " + e.getMessage());
276             return;
277         }
278 
279         try {
280             format1 = new MessageFormat("pattern{0}");
281             ostream.writeObject(format1);
282             ostream.flush();
283 
284             byte bytes[] = baos.toByteArray();
285 
286             istream = new ObjectInputStream(new ByteArrayInputStream(bytes));
287             format2 = (MessageFormat)istream.readObject();
288         } catch(Exception e) {
289             fail("Unexpected exception : " + e.getMessage());
290         }
291 
292         if (!format1.equals(format2)) {
293             fail("MessageFormats before and after serialization are not" +
294                 " equal\nformat1 = " + format1 + "(" + format1.toPattern() + ")\nformat2 = " +
295                 format2 + "(" + format2.toPattern() + ")");
296         } else {
297             System.out.println("Serialization for MessageFormat is OK.");
298         }
299     }
300     /* @bug 4114743
301      * MessageFormat.applyPattern allows illegal patterns.
302      */
303     @Test
304     public void Test4114743()
305     {
306         String originalPattern = "initial pattern";
307         MessageFormat mf = new MessageFormat(originalPattern);
308         try {
309             String illegalPattern = "ab { '}' de";
310             mf.applyPattern(illegalPattern);
311             fail("illegal pattern: \"" + illegalPattern + "\"");
312         } catch (IllegalArgumentException foo) {
313             if (!originalPattern.equals(mf.toPattern()))
314                 fail("pattern after: \"" + mf.toPattern() + "\"");
315         }
316     }
317 
318     /* @bug 4116444
319      * MessageFormat.parse has different behavior in case of null.
320      */
321     @Test
322     public void Test4116444()
323     {
324         String[] patterns = {"", "one", "{0,date,short}"};
325         MessageFormat mf = new MessageFormat("");
326 
327         for (int i = 0; i < patterns.length; i++) {
328             String pattern = patterns[i];
329             mf.applyPattern(pattern);
330             try {
331                 Object[] array = mf.parse(null, new ParsePosition(0));
332                 System.out.println("pattern: \"" + pattern + "\"");
333                 System.out.println(" parsedObjects: ");
334                 if (array != null) {
335                     System.out.println("{");
336                     for (int j = 0; j < array.length; j++) {
337                         if (array[j] != null)
338                             fail("\"" + array[j].toString() + "\"");
339                         else
340                             System.out.println("null");
341                         if (j < array.length - 1) System.out.println(",");
342                     }
343                     System.out.println("}") ;
344                 } else {
345                     System.out.println("null");
346                 }
347                 System.out.println("");
348             } catch (Exception e) {
349                 fail("pattern: \"" + pattern + "\"");
350                 fail("  Exception: " + e.getMessage());
351             }
352         }
353 
354     }
355     /* @bug 4114739 (FIX and add javadoc)
356      * MessageFormat.format has undocumented behavior about empty format objects.
357      */
358     @Test
359     public void Test4114739()
360     {
361 
362         MessageFormat mf = new MessageFormat("<{0}>");
363         Object[] objs1 = null;
364         Object[] objs2 = {};
365         Object[] objs3 = {null};
366         try {
367             System.out.println("pattern: \"" + mf.toPattern() + "\"");
368             System.out.println("format(null) : ");
369             System.out.println("\"" + mf.format(objs1) + "\"");
370             System.out.println("format({})   : ");
371             System.out.println("\"" + mf.format(objs2) + "\"");
372             System.out.println("format({null}) :");
373             System.out.println("\"" + mf.format(objs3) + "\"");
374         } catch (Exception e) {
375             fail("Exception thrown for null argument tests.");
376         }
377     }
378 
379     /* @bug 4113018
380      * MessageFormat.applyPattern works wrong with illegal patterns.
381      */
382     @Test
383     public void Test4113018()
384     {
385         String originalPattern = "initial pattern";
386         MessageFormat mf = new MessageFormat(originalPattern);
387         String illegalPattern = "format: {0, xxxYYY}";
388         System.out.println("pattern before: \"" + mf.toPattern() + "\"");
389         System.out.println("illegal pattern: \"" + illegalPattern + "\"");
390         try {
391             mf.applyPattern(illegalPattern);
392             fail("Should have thrown IllegalArgumentException for pattern : " + illegalPattern);
393         } catch (IllegalArgumentException e) {
394             if (!originalPattern.equals(mf.toPattern()))
395                 fail("pattern after: \"" + mf.toPattern() + "\"");
396         }
397     }
398     /* @bug 4106661
399      * ChoiceFormat is silent about the pattern usage in javadoc.
400      */
401     @Test
402     public void Test4106661()
403     {
404         ChoiceFormat fmt = new ChoiceFormat(
405           "-1#are negative| 0#are no or fraction | 1#is one |1.0<is 1+ |2#are two |2<are more than 2.");
406         System.out.println("Formatter Pattern : " + fmt.toPattern());
407 
408         System.out.println("Format with -INF : " + fmt.format(Double.NEGATIVE_INFINITY));
409         System.out.println("Format with -1.0 : " + fmt.format(-1.0));
410         System.out.println("Format with 0 : " + fmt.format(0));
411         System.out.println("Format with 0.9 : " + fmt.format(0.9));
412         System.out.println("Format with 1.0 : " + fmt.format(1));
413         System.out.println("Format with 1.5 : " + fmt.format(1.5));
414         System.out.println("Format with 2 : " + fmt.format(2));
415         System.out.println("Format with 2.1 : " + fmt.format(2.1));
416         System.out.println("Format with NaN : " + fmt.format(Double.NaN));
417         System.out.println("Format with +INF : " + fmt.format(Double.POSITIVE_INFINITY));
418     }
419     /* @bug 4094906
420      * ChoiceFormat should accept \u221E as eq. to INF.
421      */
422     @Test
423     public void Test4094906()
424     {
425         ChoiceFormat fmt = new ChoiceFormat(
426           "-\u221E<are negative|0<are no or fraction|1#is one|1.0<is 1+|\u221E<are many.");
427         if (!fmt.toPattern().startsWith("-\u221E<are negative|0.0<are no or fraction|1.0#is one|1.0<is 1+|\u221E<are many."))
428             fail("Formatter Pattern : " + fmt.toPattern());
429         System.out.println("Format with -INF : " + fmt.format(Double.NEGATIVE_INFINITY));
430         System.out.println("Format with -1.0 : " + fmt.format(-1.0));
431         System.out.println("Format with 0 : " + fmt.format(0));
432         System.out.println("Format with 0.9 : " + fmt.format(0.9));
433         System.out.println("Format with 1.0 : " + fmt.format(1));
434         System.out.println("Format with 1.5 : " + fmt.format(1.5));
435         System.out.println("Format with 2 : " + fmt.format(2));
436         System.out.println("Format with +INF : " + fmt.format(Double.POSITIVE_INFINITY));
437     }
438 
439     /* @bug 4118592
440      * MessageFormat.parse fails with ChoiceFormat.
441      */
442     @Test
443     public void Test4118592()
444     {
445         MessageFormat mf = new MessageFormat("");
446         String pattern = "{0,choice,1#YES|2#NO}";
447         String prefix = "";
448         for (int i = 0; i < 5; i++) {
449             String formatted = prefix + "YES";
450             mf.applyPattern(prefix + pattern);
451             prefix += "x";
452             Object[] objs = mf.parse(formatted, new ParsePosition(0));
453             System.out.println(i + ". pattern :\"" + mf.toPattern() + "\"");
454             System.out.println(" \"" + formatted + "\" parsed as ");
455             if (objs == null) System.out.println("  null");
456             else System.out.println("  " + objs[0]);
457         }
458     }
459     /* @bug 4118594
460      * MessageFormat.parse fails for some patterns.
461      */
462     @Test
463     public void Test4118594()
464     {
465         MessageFormat mf = new MessageFormat("{0}, {0}, {0}");
466         String forParsing = "x, y, z";
467         Object[] objs = mf.parse(forParsing, new ParsePosition(0));
468         System.out.println("pattern: \"" + mf.toPattern() + "\"");
469         System.out.println("text for parsing: \"" + forParsing + "\"");
470         if (!objs[0].toString().equals("z"))
471             fail("argument0: \"" + objs[0] + "\"");
472         mf.setLocale(Locale.US);
473         mf.applyPattern("{0,number,#.##}, {0,number,#.#}");
474         Object[] oldobjs = {3.1415};
475         String result = mf.format( oldobjs );
476         System.out.println("pattern: \"" + mf.toPattern() + "\"");
477         System.out.println("text for parsing: \"" + result + "\"");
478         // result now equals "3.14, 3.1"
479         if (!result.equals("3.14, 3.1"))
480             fail("result = " + result);
481         Object[] newobjs = mf.parse(result, new ParsePosition(0));
482         // newobjs now equals {new Double(3.1)}
483         if (((Double)newobjs[0]).doubleValue() != 3.1)
484             fail( "newobjs[0] = " + newobjs[0]);
485     }
486     /* @bug 4105380
487      * When using ChoiceFormat, MessageFormat is not good for I18n.
488      */
489     @Test
490     public void Test4105380()
491     {
492         String patternText1 = "The disk \"{1}\" contains {0}.";
493         String patternText2 = "There are {0} on the disk \"{1}\"";
494         MessageFormat form1 = new MessageFormat(patternText1);
495         MessageFormat form2 = new MessageFormat(patternText2);
496         double[] filelimits = {0,1,2};
497         String[] filepart = {"no files","one file","{0,number} files"};
498         ChoiceFormat fileform = new ChoiceFormat(filelimits, filepart);
499         form1.setFormat(1, fileform);
500         form2.setFormat(0, fileform);
501         Object[] testArgs = {12373L, "MyDisk"};
502         System.out.println(form1.format(testArgs));
503         System.out.println(form2.format(testArgs));
504     }
505     /* @bug 4120552
506      * MessageFormat.parse incorrectly sets errorIndex.
507      */
508     @Test
509     public void Test4120552()
510     {
511         MessageFormat mf = new MessageFormat("pattern");
512         String texts[] = {"pattern", "pat", "1234"};
513         System.out.println("pattern: \"" + mf.toPattern() + "\"");
514         for (int i = 0; i < texts.length; i++) {
515             ParsePosition pp = new ParsePosition(0);
516             Object[] objs = mf.parse(texts[i], pp);
517             System.out.println("  text for parsing: \"" + texts[i] + "\"");
518             if (objs == null) {
519                 System.out.println("  (incorrectly formatted string)");
520                 if (pp.getErrorIndex() == -1)
521                     fail("Incorrect error index: " + pp.getErrorIndex());
522             } else {
523                 System.out.println("  (correctly formatted string)");
524             }
525         }
526     }
527 
528     /**
529      * @bug 4142938
530      * MessageFormat handles single quotes in pattern wrong.
531      * This is actually a problem in ChoiceFormat; it doesn't
532      * understand single quotes.
533      */
534     @Test
535     public void Test4142938() {
536         String pat = "''Vous'' {0,choice,0#n''|1#}avez s\u00E9lectionne\u00E9 " +
537             "{0,choice,0#aucun|1#{0}} client{0,choice,0#s|1#|2#s} " +
538             "personnel{0,choice,0#s|1#|2#s}.";
539         MessageFormat mf = new MessageFormat(pat);
540 
541         String[] PREFIX = {
542             "'Vous' n'avez s\u00E9lectionne\u00E9 aucun clients personnels.",
543             "'Vous' avez s\u00E9lectionne\u00E9 ",
544             "'Vous' avez s\u00E9lectionne\u00E9 "
545         };
546         String[] SUFFIX = {
547             null,
548             " client personnel.",
549             " clients personnels."
550         };
551 
552         for (int i=0; i<3; i++) {
553             String out = mf.format(new Object[]{i});
554             if (SUFFIX[i] == null) {
555                 if (!out.equals(PREFIX[i]))
556                     fail("" + i + ": Got \"" + out + "\"; Want \"" + PREFIX[i] + "\"");
557             }
558             else {
559                 if (!out.startsWith(PREFIX[i]) ||
560                     !out.endsWith(SUFFIX[i]))
561                     fail("" + i + ": Got \"" + out + "\"; Want \"" + PREFIX[i] + "\"...\"" +
562                           SUFFIX[i] + "\"");
563             }
564         }
565     }
566 
567     /**
568      * @bug 4142938
569      * Test the applyPattern and toPattern handling of single quotes
570      * by ChoiceFormat.  (This is in here because this was a bug reported
571      * against MessageFormat.)  The single quote is used to quote the
572      * pattern characters '|', '#', '<', and '\u2264'.  Two quotes in a row
573      * is a quote literal.
574      */
575     @Test
576     public void TestChoicePatternQuote() {
577         String[] DATA = {
578             // Pattern                  0 value           1 value
579             "0#can''t|1#can",           "can't",          "can",
580             "0#'pound(#)=''#'''|1#xyz", "pound(#)='#'",   "xyz",
581             "0#'1<2 | 1\u22641'|1#''",  "1<2 | 1\u22641", "'",
582         };
583         for (int i=0; i<DATA.length; i+=3) {
584             try {
585                 ChoiceFormat cf = new ChoiceFormat(DATA[i]);
586                 for (int j=0; j<=1; ++j) {
587                     String out = cf.format(j);
588                     if (!out.equals(DATA[i+1+j]))
589                         fail("Fail: Pattern \"" + DATA[i] + "\" x "+j+" -> " +
590                               out + "; want \"" + DATA[i+1+j] + '"');
591                 }
592                 String pat = cf.toPattern();
593                 String pat2 = new ChoiceFormat(pat).toPattern();
594                 if (!pat.equals(pat2))
595                     fail("Fail: Pattern \"" + DATA[i] + "\" x toPattern -> \"" + pat + '"');
596                 else
597                     System.out.println("Ok: Pattern \"" + DATA[i] + "\" x toPattern -> \"" + pat + '"');
598             }
599             catch (IllegalArgumentException e) {
600                 fail("Fail: Pattern \"" + DATA[i] + "\" -> " + e);
601             }
602         }
603     }
604 
605     /**
606      * @bug 4112104
607      * MessageFormat.equals(null) throws a NullPointerException.  The JLS states
608      * that it should return false.
609      */
610     @Test
611     public void Test4112104() {
612         MessageFormat format = new MessageFormat("");
613         try {
614             // This should NOT throw an exception
615             if (format.equals(null)) {
616                 // It also should return false
617                 fail("MessageFormat.equals(null) returns false");
618             }
619         }
620         catch (NullPointerException e) {
621             fail("MessageFormat.equals(null) throws " + e);
622         }
623     }
624 
625     /**
626      * @bug 4169959
627      * MessageFormat does not format null objects. CANNOT REPRODUCE THIS BUG.
628      */
629     @Test
630     public void Test4169959() {
631         // This works
632         System.out.println(MessageFormat.format( "This will {0}", "work"));
633 
634         // This fails
635         System.out.println(MessageFormat.format( "This will {0}",
636                                     new Object[]{ null } ) );
637     }
638 
639     @Test
640     public void test4232154() {
641         boolean gotException = false;
642         try {
643             MessageFormat format = new MessageFormat("The date is {0:date}");
644         } catch (Exception e) {
645             gotException = true;
646             if (!(e instanceof IllegalArgumentException)) {
647                 throw new RuntimeException("got wrong exception type");
648             }
649             if ("argument number too large at ".equals(e.getMessage())) {
650                 throw new RuntimeException("got wrong exception message");
651             }
652         }
653         if (!gotException) {
654             throw new RuntimeException("didn't get exception for invalid input");
655         }
656     }
657 
658     @Test
659     public void test4293229() {
660         MessageFormat format = new MessageFormat("'''{'0}'' '''{0}'''");
661         Object[] args = { null };
662         String expected = "'{0}' '{0}'";
663         String result = format.format(args);
664         if (!result.equals(expected)) {
665             throw new RuntimeException("wrong format result - expected \"" +
666                     expected + "\", got \"" + result + "\"");
667         }
668     }
669 
670     /**
671      * @bug 8187551
672      * test MessageFormat.setFormat() method to throw AIOOBE on invalid index.
673      */
674     @Test
675     public void test8187551() {
676         //invalid cases ("pattern", "invalid format element index")
677         String[][] invalidCases = {{"The disk \"{1}\" contains {0}.", "2"},
678                 {"The disk \"{1}\" contains {0}.", "9"},
679                 {"On {1}, there are {0} and {2} folders", "3"}};
680 
681         //invalid cases (must throw exception)
682         Arrays.stream(invalidCases).forEach(entry -> messageSetFormat(entry[0],
683                 Integer.valueOf(entry[1])));
684     }
685 
686     // test MessageFormat.setFormat() method for the given pattern and
687     // format element index
688     private void messageSetFormat(String pattern, int elemIndex) {
689         MessageFormat form = new MessageFormat(pattern);
690 
691         double[] fileLimits = {0, 1, 2};
692         String[] filePart = {"no files", "one file", "{0,number} files"};
693         ChoiceFormat fileForm = new ChoiceFormat(fileLimits, filePart);
694 
695         boolean AIOOBEThrown = false;
696         try {
697             form.setFormat(elemIndex, fileForm);
698         } catch (ArrayIndexOutOfBoundsException ex) {
699             AIOOBEThrown = true;
700         }
701 
702         if (!AIOOBEThrown) {
703             throw new RuntimeException("[FAILED: Must throw" +
704                     " ArrayIndexOutOfBoundsException for" +
705                     " invalid index " + elemIndex + " used in" +
706                     " MessageFormat.setFormat(index, format)]");
707         }
708     }
709 
710 }