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