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