Home | History | Annotate | Download | only in format
      1 /* GENERATED SOURCE. DO NOT MODIFY. */
      2 //  2016 and later: Unicode, Inc. and others.
      3 // License & terms of use: http://www.unicode.org/copyright.html#License
      4 /*
      5 **********************************************************************
      6 * Copyright (c) 2004-2016, International Business Machines
      7 * Corporation and others.  All Rights Reserved.
      8 **********************************************************************
      9 * Author: Alan Liu
     10 * Created: April 6, 2004
     11 * Since: ICU 3.0
     12 **********************************************************************
     13 */
     14 package android.icu.dev.test.format;
     15 
     16 import java.text.AttributedCharacterIterator;
     17 import java.text.AttributedString;
     18 import java.text.ChoiceFormat;
     19 import java.text.FieldPosition;
     20 import java.text.Format;
     21 import java.text.ParseException;
     22 import java.text.ParsePosition;
     23 import java.util.Date;
     24 import java.util.HashMap;
     25 import java.util.Iterator;
     26 import java.util.Locale;
     27 import java.util.Map;
     28 import java.util.Set;
     29 import java.util.TreeMap;
     30 
     31 import org.junit.Test;
     32 
     33 import android.icu.text.DateFormat;
     34 import android.icu.text.DecimalFormat;
     35 import android.icu.text.DecimalFormatSymbols;
     36 import android.icu.text.MessageFormat;
     37 import android.icu.text.MessagePattern;
     38 import android.icu.text.NumberFormat;
     39 import android.icu.text.SimpleDateFormat;
     40 import android.icu.text.UFormat;
     41 import android.icu.util.TimeZone;
     42 import android.icu.util.ULocale;
     43 
     44 public class TestMessageFormat extends android.icu.dev.test.TestFmwk {
     45     @Test
     46     public void TestBug3()
     47     {
     48         double myNumber = -123456;
     49         DecimalFormat form = null;
     50         Locale locale[] = {
     51             new Locale("ar", "", ""),
     52             new Locale("be", "", ""),
     53             new Locale("bg", "", ""),
     54             new Locale("ca", "", ""),
     55             new Locale("cs", "", ""),
     56             new Locale("da", "", ""),
     57             new Locale("de", "", ""),
     58             new Locale("de", "AT", ""),
     59             new Locale("de", "CH", ""),
     60             new Locale("el", "", ""),       // 10
     61             new Locale("en", "CA", ""),
     62             new Locale("en", "GB", ""),
     63             new Locale("en", "IE", ""),
     64             new Locale("en", "US", ""),
     65             new Locale("es", "", ""),
     66             new Locale("et", "", ""),
     67             new Locale("fi", "", ""),
     68             new Locale("fr", "", ""),
     69             new Locale("fr", "BE", ""),
     70             new Locale("fr", "CA", ""),     // 20
     71             new Locale("fr", "CH", ""),
     72             new Locale("he", "", ""),
     73             new Locale("hr", "", ""),
     74             new Locale("hu", "", ""),
     75             new Locale("is", "", ""),
     76             new Locale("it", "", ""),
     77             new Locale("it", "CH", ""),
     78             new Locale("ja", "", ""),
     79             new Locale("ko", "", ""),
     80             new Locale("lt", "", ""),       // 30
     81             new Locale("lv", "", ""),
     82             new Locale("mk", "", ""),
     83             new Locale("nl", "", ""),
     84             new Locale("nl", "BE", ""),
     85             new Locale("no", "", ""),
     86             new Locale("pl", "", ""),
     87             new Locale("pt", "", ""),
     88             new Locale("ro", "", ""),
     89             new Locale("ru", "", ""),
     90             new Locale("sh", "", ""),       // 40
     91             new Locale("sk", "", ""),
     92             new Locale("sl", "", ""),
     93             new Locale("sq", "", ""),
     94             new Locale("sr", "", ""),
     95             new Locale("sv", "", ""),
     96             new Locale("tr", "", ""),
     97             new Locale("uk", "", ""),
     98             new Locale("zh", "", ""),
     99             new Locale("zh", "TW", "")      // 49
    100         };
    101         StringBuffer buffer = new StringBuffer();
    102         ParsePosition parsePos = new ParsePosition(0);
    103         int i;
    104         for (i= 0; i < 49; i++) {
    105     //        form = (DecimalFormat)NumberFormat.getCurrencyInstance(locale[i]);
    106             form = (DecimalFormat)NumberFormat.getInstance(locale[i]);
    107             if (form == null) {
    108                 errln("Number format creation failed for " + locale[i].getDisplayName());
    109                 continue;
    110             }
    111             FieldPosition pos = new FieldPosition(0);
    112             buffer.setLength(0);
    113             form.format(myNumber, buffer, pos);
    114             parsePos.setIndex(0);
    115             Object result = form.parse(buffer.toString(), parsePos);
    116             logln(locale[i].getDisplayName() + " -> " + result);
    117             if (parsePos.getIndex() != buffer.length()) {
    118                 errln("Number format parse failed.");
    119             }
    120         }
    121     }
    122 
    123     @Test
    124     public void TestBug1()
    125     {
    126         final double limit[] = {0.0, 1.0, 2.0};
    127         final String formats[] = {"0.0<=Arg<1.0",
    128                                   "1.0<=Arg<2.0",
    129                                   "2.0<-Arg"};
    130         ChoiceFormat cf = new ChoiceFormat(limit, formats);
    131         assertEquals("ChoiceFormat.format", formats[1], cf.format(1));
    132     }
    133 
    134     @Test
    135     public void TestBug2()
    136     {
    137         // {sfb} use double format in pattern, so result will match (not strictly necessary)
    138         final String pattern = "There {0,choice,0.0#are no files|1.0#is one file|1.0<are {0, number} files} on disk {1}. ";
    139         logln("The input pattern : " + pattern);
    140         try {
    141             MessageFormat fmt = new MessageFormat(pattern);
    142             assertEquals("toPattern", pattern, fmt.toPattern());
    143         } catch (IllegalArgumentException e) {
    144             errln("MessageFormat pattern creation failed.");
    145         }
    146     }
    147 
    148     @Test
    149     public void TestPattern() // aka PatternTest()
    150     {
    151         Object testArgs[] = {
    152             new Double(1), new Double(3456),
    153             "Disk", new Date(1000000000L)
    154         };
    155         String testCases[] = {
    156            "Quotes '', '{', 'a' {0} '{0}'",
    157            "Quotes '', '{', 'a' {0,number} '{0}'",
    158            "'{'1,number,'#',##} {1,number,'#',##}",
    159            "There are {1} files on {2} at {3}.",
    160            "On {2}, there are {1} files, with {0,number,currency}.",
    161            "'{1,number,percent}', {1,number,percent},",
    162            "'{1,date,full}', {1,date,full},",
    163            "'{3,date,full}', {3,date,full},",
    164            "'{1,number,#,##}' {1,number,#,##}",
    165         };
    166 
    167         // ICU 4.8 returns the original pattern (testCases)
    168         // rather than toPattern() reconstituting a new, equivalent pattern string (testResultPatterns).
    169         /*String testResultPatterns[] = {
    170             "Quotes '', '{', a {0} '{'0}",
    171             "Quotes '', '{', a {0,number} '{'0}",
    172             "'{'1,number,#,##} {1,number,'#'#,##}",
    173             "There are {1} files on {2} at {3}.",
    174             "On {2}, there are {1} files, with {0,number,currency}.",
    175             "'{'1,number,percent}, {1,number,percent},",
    176             "'{'1,date,full}, {1,date,full},",
    177             "'{'3,date,full}, {3,date,full},",
    178             "'{'1,number,#,##} {1,number,#,##}"
    179         };*/
    180 
    181         String testResultStrings[] = {
    182             "Quotes ', {, 'a' 1 {0}",
    183             "Quotes ', {, 'a' 1 {0}",
    184             "{1,number,'#',##} #34,56",
    185             "There are 3,456 files on Disk at 1/12/70, 5:46 AM.",
    186             "On Disk, there are 3,456 files, with $1.00.",
    187             "{1,number,percent}, 345,600%,",
    188             "{1,date,full}, Wednesday, December 31, 1969,",
    189             "{3,date,full}, Monday, January 12, 1970,",
    190             "{1,number,#,##} 34,56"
    191         };
    192 
    193         for (int i = 0; i < 9; ++i) {
    194             //it_out << "\nPat in:  " << testCases[i]);
    195 
    196             //String buffer;
    197             MessageFormat form = null;
    198             try {
    199                 form = new MessageFormat(testCases[i], Locale.US);
    200             } catch (IllegalArgumentException e1) {
    201                 errln("MessageFormat for " + testCases[i] + " creation failed.");
    202                 continue;
    203             }
    204             // ICU 4.8 returns the original pattern (testCases)
    205             // rather than toPattern() reconstituting a new, equivalent pattern string (testResultPatterns).
    206             // assertEquals("\"" + testCases[i] + "\".toPattern()", testResultPatterns[i], form.toPattern());
    207             assertEquals("\"" + testCases[i] + "\".toPattern()", testCases[i], form.toPattern());
    208             // Note: An alternative test would be to build MessagePattern objects for
    209             // both the input and output patterns and compare them, taking SKIP_SYNTAX etc.
    210             // into account.
    211             // (Too much trouble...)
    212 
    213             //it_out << "Pat out: " << form.toPattern(buffer));
    214             StringBuffer result = new StringBuffer();
    215             FieldPosition fieldpos = new FieldPosition(0);
    216             form.format(testArgs, result, fieldpos);
    217             assertEquals("format", testResultStrings[i], result.toString());
    218 
    219             //it_out << "Result:  " << result);
    220     //        /* TODO: Look at this test and see if this is still a valid test */
    221     //        logln("---------------- test parse ----------------");
    222     //
    223     //        int count = 4;
    224     //        form.toPattern(buffer);
    225     //        logln("MSG pattern for parse: " + buffer);
    226     //
    227     //        int parseCount = 0;
    228     //        Formattable* values = form.parse(result, parseCount, success);
    229     //        if (U_FAILURE(success)) {
    230     //            errln("MessageFormat failed test #5");
    231     //            logln(String("MessageFormat failed test #5 with error code ")+(int)success);
    232     //        } else if (parseCount != count) {
    233     //            errln("MSG count not %d as expected. Got %d", count, parseCount);
    234     //        }
    235     //        UBool failed = FALSE;
    236     //        for (int j = 0; j < parseCount; ++j) {
    237     //             if (values == 0 || testArgs[j] != values[j]) {
    238     //                errln(((String)"MSG testargs[") + j + "]: " + toString(testArgs[j]));
    239     //                errln(((String)"MSG values[") + j + "]  : " + toString(values[j]));
    240     //                failed = TRUE;
    241     //             }
    242     //        }
    243     //        if (failed)
    244     //            errln("MessageFormat failed test #6");
    245         }
    246     }
    247 
    248     @Test
    249     public void TestSample() // aka sample()
    250     {
    251         MessageFormat form = null;
    252         StringBuffer buffer2 = new StringBuffer();
    253         try {
    254             form = new MessageFormat("There are {0} files on {1}");
    255         } catch (IllegalArgumentException e1) {
    256             errln("Sample message format creation failed.");
    257             return;
    258         }
    259         Object testArgs1[] = { "abc", "def" };
    260         FieldPosition fieldpos = new FieldPosition(0);
    261         assertEquals("format",
    262                      "There are abc files on def",
    263                      form.format(testArgs1, buffer2, fieldpos).toString());
    264     }
    265 
    266     @Test
    267     public void TestStaticFormat()
    268     {
    269         Object arguments[] = {
    270             new Integer(7),
    271             new Date(871068000000L),
    272             "a disturbance in the Force"
    273         };
    274 
    275         assertEquals("format",
    276             "At 12:20:00 PM on Aug 8, 1997, there was a disturbance in the Force on planet 7.",
    277             MessageFormat.format("At {1,time} on {1,date}, there was {2} on planet {0,number,integer}.",
    278                                  arguments));
    279     }
    280 
    281     static final int FieldPosition_DONT_CARE = -1;
    282 
    283     @Test
    284     public void TestSimpleFormat()
    285     {
    286         Object testArgs1[] = {new Integer(0), "MyDisk"};
    287         Object testArgs2[] = {new Integer(1), "MyDisk"};
    288         Object testArgs3[] = {new Integer(12), "MyDisk"};
    289 
    290         MessageFormat form = new MessageFormat(
    291             "The disk \"{1}\" contains {0} file(s).");
    292 
    293         StringBuffer string = new StringBuffer();
    294         FieldPosition ignore = new FieldPosition(FieldPosition_DONT_CARE);
    295         form.format(testArgs1, string, ignore);
    296         assertEquals("format",
    297                      "The disk \"MyDisk\" contains 0 file(s).",
    298                      string.toString());
    299 
    300         string.setLength(0);
    301         form.format(testArgs2, string, ignore);
    302         assertEquals("format",
    303                      "The disk \"MyDisk\" contains 1 file(s).",
    304                      string.toString());
    305 
    306         string.setLength(0);
    307         form.format(testArgs3, string, ignore);
    308         assertEquals("format",
    309                      "The disk \"MyDisk\" contains 12 file(s).",
    310                      string.toString());
    311     }
    312 
    313     @Test
    314     public void TestMsgFormatChoice()
    315     {
    316         MessageFormat form = new MessageFormat("The disk \"{1}\" contains {0}.");
    317         double filelimits[] = {0,1,2};
    318         String filepart[] = {"no files","one file","{0,number} files"};
    319         ChoiceFormat fileform = new ChoiceFormat(filelimits, filepart);
    320         form.setFormat(1, fileform); // NOT zero, see below
    321 
    322         FieldPosition ignore = new FieldPosition(FieldPosition_DONT_CARE);
    323         StringBuffer string = new StringBuffer();
    324         Object testArgs1[] = {new Integer(0), "MyDisk"};
    325         form.format(testArgs1, string, ignore);
    326         assertEquals("format#1",
    327                      "The disk \"MyDisk\" contains no files.",
    328                      string.toString());
    329 
    330         string.setLength(0);
    331         Object testArgs2[] = {new Integer(1), "MyDisk"};
    332         form.format(testArgs2, string, ignore);
    333         assertEquals("format#2",
    334                      "The disk \"MyDisk\" contains one file.",
    335                      string.toString());
    336 
    337         string.setLength(0);
    338         Object testArgs3[] = {new Integer(1273), "MyDisk"};
    339         form.format(testArgs3, string, ignore);
    340         assertEquals("format#3",
    341                      "The disk \"MyDisk\" contains 1,273 files.",
    342                      string.toString());
    343     }
    344 
    345     //---------------------------------
    346     //  API Tests
    347     //---------------------------------
    348 
    349     @Test
    350     public void TestClone()
    351     {
    352         MessageFormat x = new MessageFormat("There are {0} files on {1}");
    353         MessageFormat z = new MessageFormat("There are {0} files on {1} created");
    354         MessageFormat y = null;
    355         y = (MessageFormat)x.clone();
    356         if (x.equals(y) &&
    357             !x.equals(z) &&
    358             !y.equals(z) )
    359             logln("First test (operator ==): Passed!");
    360         else {
    361             errln("First test (operator ==): Failed!");
    362         }
    363         if ((x.equals(y) && y.equals(x)) &&
    364             (!x.equals(z) && !z.equals(x)) &&
    365             (!y.equals(z) && !z.equals(y)) )
    366             logln("Second test (equals): Passed!");
    367         else {
    368             errln("Second test (equals): Failed!");
    369         }
    370 
    371     }
    372 
    373     @Test
    374     public void TestEquals()
    375     {
    376         MessageFormat x = new MessageFormat("There are {0} files on {1}");
    377         MessageFormat y = new MessageFormat("There are {0} files on {1}");
    378         if (!x.equals(y)) {
    379             errln("First test (operator ==): Failed!");
    380         }
    381 
    382     }
    383 
    384     @Test
    385     public void TestNotEquals()
    386     {
    387         MessageFormat x = new MessageFormat("There are {0} files on {1}");
    388         MessageFormat y = new MessageFormat("There are {0} files on {1}");
    389         y.setLocale(Locale.FRENCH);
    390         if (x.equals(y)) {
    391             errln("First test (operator !=): Failed!");
    392         }
    393         y = new MessageFormat("There are {0} files on {1}");
    394         y.applyPattern("There are {0} files on {1} the disk");
    395         if (x.equals(y)) {
    396             errln("Second test (operator !=): Failed!");
    397         }
    398     }
    399 
    400     @Test
    401     public void TestHashCode()
    402     {
    403         ULocale save = ULocale.getDefault();
    404         ULocale.setDefault(ULocale.US);
    405 
    406         MessageFormat x = new MessageFormat("There are {0} files on {1}");
    407         MessageFormat z = new MessageFormat("There are {0} files on {1}");
    408         MessageFormat y = null;
    409         y = (MessageFormat)x.clone();
    410         if (x.hashCode() != y.hashCode())
    411             errln("FAIL: identical objects have different hashcodes");
    412         if (x.hashCode() != z.hashCode())
    413             errln("FAIL: identical objects have different hashcodes");
    414 
    415     /* These are not errors
    416         y.setLocale(ULocale.FRENCH);
    417         if (x.hashCode() == y.hashCode())
    418             errln("FAIL: different objects have same hashcodes. Locale ignored");
    419 
    420         z.applyPattern("There are {0} files on {1} the disk");
    421         if (x.hashCode() == z.hashCode())
    422             errln("FAIL: different objects have same hashcodes. Pattern ignored");
    423     */
    424 
    425         ULocale.setDefault(save);
    426     }
    427 
    428     @Test
    429     public void TestSetLocale()
    430     {
    431         Object arguments[] = {
    432             new Double(456.83),
    433             new Date(871068000000L),
    434             "deposit"
    435             };
    436 
    437         StringBuffer result = new StringBuffer();
    438 
    439         //String formatStr = "At {1,time} on {1,date}, you made a {2} of {0,number,currency}.";
    440         String formatStr = "At <time> on {1,date}, you made a {2} of {0,number,currency}.";
    441         // {sfb} to get $, would need Locale::US, not Locale::ENGLISH
    442         // Just use unlocalized currency symbol.
    443         //String compareStrEng = "At <time> on Aug 8, 1997, you made a deposit of $456.83.";
    444         String compareStrEng = "At <time> on Aug 8, 1997, you made a deposit of ";
    445         compareStrEng += '\u00a4';
    446         compareStrEng += "456.83.";
    447         // {sfb} to get DM, would need Locale::GERMANY, not Locale::GERMAN
    448         // Just use unlocalized currency symbol.
    449         //String compareStrGer = "At <time> on 08.08.1997, you made a deposit of 456,83 DM.";
    450         String compareStrGer = "At <time> on 08.08.1997, you made a deposit of ";
    451         compareStrGer += "456,83\u00a0";
    452         compareStrGer += '\u00a4';
    453         compareStrGer += ".";
    454 
    455         MessageFormat msg = new MessageFormat(formatStr, Locale.ENGLISH);
    456         result.setLength(0);
    457         FieldPosition pos = new FieldPosition(0);
    458         result = msg.format(
    459             arguments,
    460             result,
    461             pos);
    462         assertEquals("format", compareStrEng, result.toString());
    463 
    464         msg.setLocale(Locale.ENGLISH);
    465         assertEquals("getLocale", Locale.ENGLISH, msg.getLocale());
    466 
    467         msg.setLocale(Locale.GERMAN);
    468         assertEquals("getLocale", Locale.GERMAN, msg.getLocale());
    469 
    470         msg.applyPattern(formatStr);
    471         result.setLength(0);
    472         result = msg.format(
    473             arguments,
    474             result,
    475             pos);
    476         assertEquals("format", compareStrGer, result.toString());
    477 
    478         //Cover getULocale()
    479         logln("Testing set/get ULocale ...");
    480         msg.setLocale(ULocale.ENGLISH);
    481         assertEquals("getULocale", ULocale.ENGLISH, msg.getULocale());
    482 
    483         msg.setLocale(ULocale.GERMAN);
    484         assertEquals("getULocale", ULocale.GERMAN, msg.getULocale());
    485 
    486         msg.applyPattern(formatStr);
    487         result.setLength(0);
    488         result = msg.format(
    489             arguments,
    490             result,
    491             pos);
    492         assertEquals("format", compareStrGer, result.toString());
    493     }
    494 
    495     @SuppressWarnings("static-access")
    496     @Test
    497     public void TestFormat()
    498     {
    499         final Object ft_arr[] =
    500         {
    501             new Date(871068000000L)
    502         };
    503 
    504         StringBuffer result = new StringBuffer();
    505 
    506         //String formatStr = "At {1,time} on {1,date}, you made a {2} of {0,number,currency}.";
    507         String formatStr = "On {0,date}, it began.";
    508         String compareStr = "On Aug 8, 1997, it began.";
    509 
    510         MessageFormat msg = new MessageFormat(formatStr);
    511         FieldPosition fp = new FieldPosition(0);
    512 
    513         try {
    514             msg.format(new Date(871068000000L),
    515                        result,
    516                        fp);
    517             errln("*** MSG format without expected error code.");
    518         } catch (Exception e1) {
    519         }
    520 
    521         result.setLength(0);
    522         result = msg.format(
    523             ft_arr,
    524             result,
    525             fp);
    526         assertEquals("format", compareStr, result.toString());
    527 
    528         Map<String,Object> map = new HashMap<String,Object>();
    529         try{
    530             msg.format("", map);
    531         } catch(Exception e){
    532             errln("MessageFormat.format(String,Map) was not suppose to return " +
    533                     "an exception.");
    534         }
    535     }
    536 
    537     @Test
    538     public void TestParse()
    539     {
    540         String msgFormatString = "{0} =sep= {1}";
    541         MessageFormat msg = new MessageFormat(msgFormatString);
    542         String source = "abc =sep= def";
    543 
    544         try {
    545             Object[] fmt_arr = msg.parse(source);
    546             if (fmt_arr.length != 2) {
    547                 errln("*** MSG parse (ustring, count, err) count err.");
    548             } else {
    549                 // TODO: This if statement seems to be redundant. [tschumann]
    550                 if (fmt_arr.length != 2) {
    551                     errln("*** MSG parse (ustring, parsepos., count) count err.");
    552                 } else {
    553                     assertEquals("parse()[0]", "abc", fmt_arr[0]);
    554                     assertEquals("parse()[1]", "def", fmt_arr[1]);
    555                 }
    556             }
    557         } catch (ParseException e1) {
    558             errln("*** MSG parse (ustring, count, err) error.");
    559         }
    560 
    561         ParsePosition pp = new ParsePosition(0);
    562 
    563         Object[] fmt_arr = msg.parse(source, pp);
    564         if (pp.getIndex()==0 || fmt_arr==null) {
    565             errln("*** MSG parse (ustring, parsepos., count) error.");
    566         } else {
    567             if (fmt_arr.length != 2) {
    568                 errln("*** MSG parse (ustring, parsepos., count) count err.");
    569             } else {
    570                 assertEquals("parse()[0]", "abc", fmt_arr[0]);
    571                 assertEquals("parse()[1]", "def", fmt_arr[1]);
    572             }
    573         }
    574 
    575         pp.setIndex(0);
    576         Object[] fmta;
    577 
    578         fmta = (Object[]) msg.parseObject( source, pp );
    579         if (pp.getIndex() == 0) {
    580             errln("*** MSG parse (ustring, Object, parsepos ) error.");
    581         } else {
    582             if (fmta.length != 2) {
    583                 errln("*** MSG parse (ustring, count, err) count err.");
    584             } else {
    585                 // TODO: Don't we want to check fmta?
    586                 //       In this case this if statement would be redundant, too.
    587                 //       [tschumann]
    588                 if (fmt_arr.length != 2) {
    589                     errln("*** MSG parse (ustring, parsepos., count) count err.");
    590                 } else {
    591                     // TODO: Don't we want to check fmta? [tschumann]
    592                     assertEquals("parse()[0]", "abc", fmt_arr[0]);
    593                     assertEquals("parse()[1]", "def", fmt_arr[1]);
    594                 }
    595             }
    596         }
    597     }
    598 
    599     /**
    600      * Of course, in Java there is no adopt, but we retain the same
    601      * method name. [alan]
    602      */
    603     @Test
    604     public void TestAdopt()
    605     {
    606         String formatStr = "{0,date},{1},{2,number}";
    607         String formatStrChange = "{0,number},{1,number},{2,date}";
    608         MessageFormat msg = new MessageFormat(formatStr);
    609         MessageFormat msgCmp = new MessageFormat(formatStr);
    610         Format[] formats = msg.getFormats();
    611         Format[] formatsCmp = msgCmp.getFormats();
    612         Format[] formatsChg = null;
    613         Format[] formatsAct = null;
    614         Format a = null;
    615         Format b = null;
    616         Format[] formatsToAdopt = null;
    617 
    618         if (formats==null || formatsCmp==null || (formats.length <= 0) || (formats.length != formatsCmp.length)) {
    619             errln("Error getting Formats");
    620             return;
    621         }
    622 
    623         int i;
    624 
    625         for (i = 0; i < formats.length; i++) {
    626             a = formats[i];
    627             b = formatsCmp[i];
    628             if ((a != null) && (b != null)) {
    629                 if (!a.equals(b)) {
    630                     errln("a != b");
    631                     return;
    632                 }
    633             } else if ((a != null) || (b != null)) {
    634                 errln("(a != null) || (b != null)");
    635                 return;
    636             }
    637         }
    638 
    639         msg.applyPattern( formatStrChange ); //set msg formats to something different
    640         formatsChg = msg.getFormats(); // tested function
    641         if (formatsChg==null || (formatsChg.length != formats.length)) {
    642             errln("Error getting Formats");
    643             return;
    644         }
    645 
    646         boolean diff;
    647         diff = true;
    648         for (i = 0; i < formats.length; i++) {
    649             a = formatsChg[i];
    650             b = formatsCmp[i];
    651             if ((a != null) && (b != null)) {
    652                 if (a.equals(b)) {
    653                     logln("formatsChg == formatsCmp at index " + i);
    654                     diff = false;
    655                 }
    656             }
    657         }
    658         if (!diff) {
    659             errln("*** MSG getFormats diff err.");
    660             return;
    661         }
    662 
    663         logln("MSG getFormats tested.");
    664 
    665         msg.setFormats( formatsCmp ); //tested function
    666 
    667         formatsAct = msg.getFormats();
    668         if (formatsAct==null || (formatsAct.length <=0) || (formatsAct.length != formatsCmp.length)) {
    669             errln("Error getting Formats");
    670             return;
    671         }
    672 
    673         assertEquals("msgCmp.toPattern()", formatStr, msgCmp.toPattern());
    674         // ICU 4.8 does not support toPattern() when there are custom formats (from setFormat() etc.).
    675         // assertEquals("msg.toPattern()", formatStr, msg.toPattern());
    676         try {
    677             msg.toPattern();
    678             errln("msg.setFormat().toPattern() does not throw an IllegalStateException");
    679         } catch(IllegalStateException e) {
    680             // ok
    681         }
    682 
    683         for (i = 0; i < formatsAct.length; i++) {
    684             a = formatsAct[i];
    685             b = formatsCmp[i];
    686             if ((a != null) && (b != null)) {
    687                 if (!a.equals(b)) {
    688                     errln("formatsAct != formatsCmp at index " + i);
    689                     return;
    690                 }
    691             } else if ((a != null) || (b != null)) {
    692                 errln("(a != null) || (b != null)");
    693                 return;
    694             }
    695         }
    696         logln("MSG setFormats tested.");
    697 
    698         //----
    699 
    700         msg.applyPattern( formatStrChange ); //set msg formats to something different
    701 
    702         formatsToAdopt = new Format[formatsCmp.length];
    703         if (formatsToAdopt==null) {
    704             errln("memory allocation error");
    705             return;
    706         }
    707 
    708         for (i = 0; i < formatsCmp.length; i++) {
    709             if (formatsCmp[i] == null) {
    710                 formatsToAdopt[i] = null;
    711             } else {
    712                 formatsToAdopt[i] = (Format) formatsCmp[i].clone();
    713                 if (formatsToAdopt[i]==null) {
    714                     errln("Can't clone format at index " + i);
    715                     return;
    716                 }
    717             }
    718         }
    719         msg.setFormats( formatsToAdopt ); // function to test
    720 
    721         assertEquals("msgCmp.toPattern()", formatStr, msgCmp.toPattern());
    722         // ICU 4.8 does not support toPattern() when there are custom formats (from setFormat() etc.).
    723         // assertEquals("msg.toPattern()", formatStr, msg.toPattern());
    724 
    725         formatsAct = msg.getFormats();
    726         if (formatsAct==null || (formatsAct.length <=0) || (formatsAct.length != formatsCmp.length)) {
    727             errln("Error getting Formats");
    728             return;
    729         }
    730 
    731         for (i = 0; i < formatsAct.length; i++) {
    732             a = formatsAct[i];
    733             b = formatsCmp[i];
    734             if ((a != null) && (b != null)) {
    735                 if (!a.equals(b)) {
    736                     errln("a != b");
    737                     return;
    738                 }
    739             } else if ((a != null) || (b != null)) {
    740                 errln("(a != null) || (b != null)");
    741                 return;
    742             }
    743         }
    744         logln("MSG adoptFormats tested.");
    745 
    746         //---- adoptFormat
    747 
    748         msg.applyPattern( formatStrChange ); //set msg formats to something different
    749 
    750         formatsToAdopt = new Format[formatsCmp.length];
    751         if (formatsToAdopt==null) {
    752             errln("memory allocation error");
    753             return;
    754         }
    755 
    756         for (i = 0; i < formatsCmp.length; i++) {
    757             if (formatsCmp[i] == null) {
    758                 formatsToAdopt[i] = null;
    759             } else {
    760                 formatsToAdopt[i] = (Format) formatsCmp[i].clone();
    761                 if (formatsToAdopt[i]==null) {
    762                     errln("Can't clone format at index " + i);
    763                     return;
    764                 }
    765             }
    766         }
    767 
    768         for ( i = 0; i < formatsCmp.length; i++ ) {
    769             msg.setFormat( i, formatsToAdopt[i] ); // function to test
    770         }
    771 
    772         assertEquals("msgCmp.toPattern()", formatStr, msgCmp.toPattern());
    773         // ICU 4.8 does not support toPattern() when there are custom formats (from setFormat() etc.).
    774         // assertEquals("msg.toPattern()", formatStr, msg.toPattern());
    775 
    776         formatsAct = msg.getFormats();
    777         if (formatsAct==null || (formatsAct.length <=0) || (formatsAct.length != formatsCmp.length)) {
    778             errln("Error getting Formats");
    779             return;
    780         }
    781 
    782         for (i = 0; i < formatsAct.length; i++) {
    783             a = formatsAct[i];
    784             b = formatsCmp[i];
    785             if ((a != null) && (b != null)) {
    786                 if (!a.equals(b)) {
    787                     errln("a != b");
    788                     return;
    789                 }
    790             } else if ((a != null) || (b != null)) {
    791                 errln("(a != null) || (b != null)");
    792                 return;
    793             }
    794         }
    795         logln("MSG adoptFormat tested.");
    796     }
    797 
    798     /**
    799      * Verify that MessageFormat accomodates more than 10 arguments and
    800      * more than 10 subformats.
    801      */
    802     @Test
    803     public void TestUnlimitedArgsAndSubformats() {
    804         final String pattern =
    805             "On {0,date} (aka {0,date,short}, aka {0,date,long}) "+
    806             "at {0,time} (aka {0,time,short}, aka {0,time,long}) "+
    807             "there were {1,number} werjes "+
    808             "(a {3,number,percent} increase over {2,number}) "+
    809             "despite the {4}''s efforts "+
    810             "and to delight of {5}, {6}, {7}, {8}, {9}, and {10} {11}.";
    811         try {
    812             MessageFormat msg = new MessageFormat(pattern);
    813 
    814             final Object ARGS[] = {
    815                 new Date(10000000000000L),
    816                 new Integer(1303),
    817                 new Integer(1202),
    818                 new Double(1303.0/1202 - 1),
    819                 "Glimmung",
    820                 "the printers",
    821                 "Nick",
    822                 "his father",
    823                 "his mother",
    824                 "the spiddles",
    825                 "of course",
    826                 "Horace"
    827             };
    828 
    829             String expected =
    830                 "On Nov 20, 2286 (aka 11/20/86, aka November 20, 2286) "+
    831                 "at 9:46:40 AM (aka 9:46 AM, aka 9:46:40 AM PST) "+
    832                 "there were 1,303 werjes "+
    833                 "(a 8% increase over 1,202) "+
    834                 "despite the Glimmung's efforts "+
    835                 "and to delight of the printers, Nick, his father, "+
    836                 "his mother, the spiddles, and of course Horace.";
    837             assertEquals("format", expected, msg.format(ARGS));
    838         } catch (IllegalArgumentException e1) {
    839             errln("FAIL: constructor failed");
    840         }
    841     }
    842 
    843     // test RBNF extensions to message format
    844     @Test
    845     public void TestRBNF() {
    846         // WARNING: this depends on the RBNF formats for en_US
    847         Locale locale = Locale.US;
    848         String[] values = {
    849             // decimal values do not format completely for ordinal or duration, and
    850             // do not always parse, so do not include them
    851             "0", "1", "12", "100", "123", "1001", "123,456", "-17",
    852         };
    853         String[] formats = {
    854             "There are {0,spellout} files to search.",
    855             "There are {0,spellout,%simplified} files to search.",
    856             "The bogus spellout {0,spellout,%BOGUS} files behaves like the default.",
    857             "This is the {0,ordinal} file to search.", // TODO fix bug, ordinal does not parse
    858             "Searching this file will take {0,duration} to complete.",
    859             "Searching this file will take {0,duration,%with-words} to complete.",
    860         };
    861         final NumberFormat numFmt = NumberFormat.getInstance(locale);
    862         Object[] args = new Object[1];
    863         Number num = null;
    864         for (int i = 0; i < formats.length; ++i) {
    865             MessageFormat fmt = new MessageFormat(formats[i], locale);
    866             logln("Testing format pattern: '" + formats[i] + "'");
    867             for (int j = 0; j < values.length; ++j) {
    868                 try {
    869                     num = numFmt.parse(values[j]);
    870                 }
    871                 catch (Exception e) {
    872                     throw new IllegalStateException("failed to parse test argument");
    873                 }
    874                 args[0] = num;
    875                 String result = fmt.format(args);
    876                 logln("value: " + num + " --> " + result);
    877 
    878                 if (i != 3) { // TODO: fix this, for now skip ordinal parsing (format string at index 3)
    879                     try {
    880                         Object[] parsedArgs = fmt.parse(result);
    881                         if (parsedArgs.length != 1) {
    882                             errln("parse returned " + parsedArgs.length + " args");
    883                         } else if (!parsedArgs[0].equals(num)) {
    884                             errln("parsed argument " + parsedArgs[0] + " != " + num);
    885                         }
    886                     }
    887                     catch (Exception e) {
    888                         errln("parse of '" + result + " returned exception: " + e.getMessage());
    889                     }
    890                 }
    891             }
    892         }
    893     }
    894 
    895     @Test
    896     public void TestSetGetFormats()
    897     {
    898         Object arguments[] = {
    899             new Double(456.83),
    900             new Date(871068000000L),
    901             "deposit"
    902             };
    903 
    904         StringBuffer result = new StringBuffer();
    905 
    906         String formatStr = "At <time> on {1,date}, you made a {2} of {0,number,currency}.";
    907         // original expected format result
    908         String compareStr = "At <time> on Aug 8, 1997, you made a deposit of $456.83.";
    909         // the date being German-style, but the currency being English-style
    910         String compareStr2 = "At <time> on 08.08.1997, you made a deposit of ";
    911         compareStr2 += '\u00a4';
    912         compareStr2 += "456.83.";
    913         // both date and currency formats are German-style
    914         String compareStr3 = "At <time> on 08.08.1997, you made a deposit of ";
    915         compareStr3 += "456,83\u00a0";
    916         compareStr3 += '\u00a4';
    917         compareStr3 += ".";
    918 
    919         MessageFormat msg = new MessageFormat(formatStr, ULocale.US);
    920         result.setLength(0);
    921         FieldPosition pos = new FieldPosition(0);
    922         result = msg.format(
    923             arguments,
    924             result,
    925             pos);
    926         assertEquals("format", compareStr, result.toString());
    927 
    928         // constructs a Format array with a English-style Currency formatter
    929         //                            and a German-style Date formatter
    930         //      might not meaningful, just for testing setFormatsByArgIndex
    931         Format[] fmts = new Format[] {
    932             NumberFormat.getCurrencyInstance(ULocale.ENGLISH),
    933             DateFormat.getDateInstance(DateFormat.DEFAULT, ULocale.GERMAN)
    934             };
    935 
    936         msg.setFormatsByArgumentIndex(fmts);
    937         result.setLength(0);
    938         pos = new FieldPosition(0);
    939         result = msg.format(
    940             arguments,
    941             result,
    942             pos);
    943         assertEquals("format", compareStr2, result.toString());
    944 
    945         // Construct a German-style Currency formatter, replace the corresponding one
    946         // Thus both formatters should format objects with German-style
    947         Format newFmt = NumberFormat.getCurrencyInstance(ULocale.GERMAN);
    948         msg.setFormatByArgumentIndex(0, newFmt);
    949         result.setLength(0);
    950         pos = new FieldPosition(0);
    951         result = msg.format(
    952             arguments,
    953             result,
    954             pos);
    955         assertEquals("format", compareStr3, result.toString());
    956 
    957         // verify getFormatsByArgumentIndex
    958         //   you should got three formats by that
    959         //          - DecimalFormat     locale: de
    960         //          - SimpleDateFormat  locale: de
    961         //          - null
    962         Format[] fmts2 = msg.getFormatsByArgumentIndex();
    963         assertEquals("1st subformmater: Format Class", "android.icu.text.DecimalFormat", fmts2[0].getClass().getName());
    964         assertEquals("1st subformmater: its Locale", ULocale.GERMAN, ((UFormat)fmts2[0]).getLocale(ULocale.VALID_LOCALE));
    965         assertEquals("2nd subformatter: Format Class", "android.icu.text.SimpleDateFormat", fmts2[1].getClass().getName());
    966         assertEquals("2nd subformmater: its Locale", ULocale.GERMAN, ((UFormat)fmts2[1]).getLocale(ULocale.VALID_LOCALE));
    967         assertTrue("The third subFormatter is null", null == fmts2[2]);
    968     }
    969 
    970     // Test the fix pattern api
    971     @Test
    972     public void TestAutoQuoteApostrophe() {
    973         final String[] patterns = { // new pattern, expected pattern
    974             "'", "''",
    975             "''", "''",
    976             "'{", "'{'",
    977             "' {", "'' {",
    978             "'a", "''a",
    979             "'{'a", "'{'a",
    980             "'{a'", "'{a'",
    981             "'{}", "'{}'",
    982             "{'", "{'",
    983             "{'a", "{'a",
    984             "{'a{}'a}'a", "{'a{}'a}''a",
    985             "'}'", "'}'",
    986             "'} '{'}'", "'} '{'}''",
    987             "'} {{{''", "'} {{{'''",
    988         };
    989         for (int i = 0; i < patterns.length; i += 2) {
    990             assertEquals("[" + (i/2) + "] \"" + patterns[i] + "\"", patterns[i+1], MessageFormat.autoQuoteApostrophe(patterns[i]));
    991         }
    992     }
    993 
    994     // This tests passing named arguments instead of numbers to format().
    995     @Test
    996     public void testFormatNamedArguments() {
    997         Map arguments = new HashMap();
    998         arguments.put("startDate", new Date(871068000000L));
    999 
   1000         StringBuffer result = new StringBuffer();
   1001 
   1002         String formatStr = "On {startDate,date}, it began.";
   1003         String compareStr = "On Aug 8, 1997, it began.";
   1004 
   1005         MessageFormat msg = new MessageFormat(formatStr);
   1006         FieldPosition fp = new FieldPosition(0);
   1007 
   1008         try {
   1009             msg.format(arguments.get("startDate"), result, fp);
   1010             errln("*** MSG format without expected error code.");
   1011         } catch (Exception e1) {
   1012         }
   1013 
   1014         result.setLength(0);
   1015         result = msg.format(
   1016             arguments,
   1017             result,
   1018             fp);
   1019         assertEquals("format", compareStr, result.toString());
   1020     }
   1021 
   1022     // This tests parsing formatted messages with named arguments instead of
   1023     // numbers.
   1024     @Test
   1025     public void testParseNamedArguments() {
   1026         String msgFormatString = "{foo} =sep= {bar}";
   1027         MessageFormat msg = new MessageFormat(msgFormatString);
   1028         String source = "abc =sep= def";
   1029 
   1030         try {
   1031             Map fmt_map = msg.parseToMap(source);
   1032             if (fmt_map.keySet().size() != 2) {
   1033                 errln("*** MSG parse (ustring, count, err) count err.");
   1034             } else {
   1035                 assertEquals("parse()[0]", "abc", fmt_map.get("foo"));
   1036                 assertEquals("parse()[1]", "def", fmt_map.get("bar"));
   1037             }
   1038         } catch (ParseException e1) {
   1039             errln("*** MSG parse (ustring, count, err) error.");
   1040         }
   1041 
   1042         ParsePosition pp = new ParsePosition(0);
   1043         Map fmt_map = msg.parseToMap(source, pp);
   1044         if (pp.getIndex()==0 || fmt_map==null) {
   1045             errln("*** MSG parse (ustring, parsepos., count) error.");
   1046         } else {
   1047             if (fmt_map.keySet().size() != 2) {
   1048                 errln("*** MSG parse (ustring, parsepos., count) count err.");
   1049             } else {
   1050                 assertEquals("parse()[0]", "abc", fmt_map.get("foo"));
   1051                 assertEquals("parse()[1]", "def", fmt_map.get("bar"));
   1052             }
   1053         }
   1054 
   1055         pp.setIndex(0);
   1056 
   1057         Map fmta = (Map) msg.parseObject( source, pp );
   1058         if (pp.getIndex() == 0) {
   1059             errln("*** MSG parse (ustring, Object, parsepos ) error.");
   1060         } else {
   1061             if (fmta.keySet().size() != 2) {
   1062                 errln("*** MSG parse (ustring, count, err) count err.");
   1063             } else {
   1064                 assertEquals("parse()[0]", "abc", fmta.get("foo"));
   1065                 assertEquals("parse()[1]", "def", fmta.get("bar"));
   1066             }
   1067         }
   1068     }
   1069 
   1070     // Ensure that methods designed for numeric arguments only, will throw
   1071     // an exception when called on MessageFormat objects created with
   1072     // named arguments.
   1073     @Test
   1074     public void testNumericOnlyMethods() {
   1075         MessageFormat msg = new MessageFormat("Number of files: {numfiles}");
   1076         boolean gotException = false;
   1077         try {
   1078             Format fmts[] = {new DecimalFormat()};
   1079             msg.setFormatsByArgumentIndex(fmts);
   1080         } catch (IllegalArgumentException e) {
   1081             gotException = true;
   1082         }
   1083         if (!gotException) {
   1084             errln("MessageFormat.setFormatsByArgumentIndex() should throw an " +
   1085                   "IllegalArgumentException when called on formats with " +
   1086                   "named arguments but did not!");
   1087         }
   1088 
   1089         gotException = false;
   1090         try {
   1091             msg.setFormatByArgumentIndex(0, new DecimalFormat());
   1092         } catch (IllegalArgumentException e) {
   1093             gotException = true;
   1094         }
   1095         if (!gotException) {
   1096             errln("MessageFormat.setFormatByArgumentIndex() should throw an " +
   1097                   "IllegalArgumentException when called on formats with " +
   1098                   "named arguments but did not!");
   1099         }
   1100 
   1101         gotException = false;
   1102         try {
   1103             msg.getFormatsByArgumentIndex();
   1104         } catch (IllegalArgumentException e) {
   1105             gotException = true;
   1106         }
   1107         if (!gotException) {
   1108             errln("MessageFormat.getFormatsByArgumentIndex() should throw an " +
   1109                   "IllegalArgumentException when called on formats with " +
   1110                   "named arguments but did not!");
   1111         }
   1112 
   1113         gotException = false;
   1114         try {
   1115             Object args[] = {new Long(42)};
   1116             msg.format(args, new StringBuffer(), new FieldPosition(0));
   1117         } catch (IllegalArgumentException e) {
   1118             gotException = true;
   1119         }
   1120         if (!gotException) {
   1121             errln("MessageFormat.format(Object[], StringBuffer, FieldPosition) " +
   1122                   "should throw an IllegalArgumentException when called on " +
   1123                   "formats with named arguments but did not!");
   1124         }
   1125 
   1126         gotException = false;
   1127         try {
   1128             Object args[] = {new Long(42)};
   1129             msg.format((Object) args, new StringBuffer(), new FieldPosition(0));
   1130         } catch (IllegalArgumentException e) {
   1131             gotException = true;
   1132         }
   1133         if (!gotException) {
   1134             errln("MessageFormat.format(Object, StringBuffer, FieldPosition) " +
   1135                   "should throw an IllegalArgumentException when called with " +
   1136                   "non-Map object as argument on formats with named " +
   1137                   "arguments but did not!");
   1138         }
   1139 
   1140         gotException = false;
   1141         try {
   1142             msg.parse("Number of files: 5", new ParsePosition(0));
   1143         } catch (IllegalArgumentException e) {
   1144             gotException = true;
   1145         }
   1146         if (!gotException) {
   1147             errln("MessageFormat.parse(String, ParsePosition) " +
   1148                   "should throw an IllegalArgumentException when called with " +
   1149                   "non-Map object as argument on formats with named " +
   1150                   "arguments but did not!");
   1151         }
   1152 
   1153         gotException = false;
   1154         try {
   1155             msg.parse("Number of files: 5");
   1156         } catch (IllegalArgumentException e) {
   1157             gotException = true;
   1158         } catch (ParseException e) {
   1159             errln("Wrong exception thrown.");
   1160         }
   1161         if (!gotException) {
   1162             errln("MessageFormat.parse(String) " +
   1163                   "should throw an IllegalArgumentException when called with " +
   1164                   "non-Map object as argument on formats with named " +
   1165                   "arguments but did not!");
   1166         }
   1167     }
   1168 
   1169     @Test
   1170     public void testNamedArguments() {
   1171         // ICU 4.8 allows mixing named and numbered arguments.
   1172         assertTrue(
   1173                 "has some named arguments",
   1174                 new MessageFormat("Number of files in folder {0}: {numfiles}").usesNamedArguments());
   1175         assertTrue(
   1176                 "has some named arguments",
   1177                 new MessageFormat("Number of files in folder {folder}: {1}").usesNamedArguments());
   1178 
   1179         // Test named arguments.
   1180         MessageFormat mf = new MessageFormat("Number of files in folder {folder}: {numfiles}");
   1181         if (!mf.usesNamedArguments()) {
   1182             errln("message format 1 should have used named arguments");
   1183         }
   1184         mf = new MessageFormat("Wavelength:  {\u028EValue\uFF14}");
   1185         if (!mf.usesNamedArguments()) {
   1186             errln("message format 2 should have used named arguments");
   1187         }
   1188 
   1189         // Test argument names with invalid start characters.
   1190         // Modified: ICU 4.8 allows all characters except for Pattern_White_Space and Pattern_Syntax.
   1191         try {
   1192             new MessageFormat("Wavelength:  {^\u028EValue\uFF14}");
   1193             errln("Creating a MessageFormat with invalid argument names " +
   1194             "should throw an IllegalArgumentException but did not!");
   1195         } catch (IllegalArgumentException e) {}
   1196 
   1197         try {
   1198             new MessageFormat("Wavelength:  {\uFE45\u028EValue}");
   1199             errln("Creating a MessageFormat with invalid argument names " +
   1200             "should throw an IllegalArgumentException but did not!");
   1201         } catch (IllegalArgumentException e) {}
   1202 
   1203         // Test argument names with invalid continue characters.
   1204         // Modified: ICU 4.8 allows all characters except for Pattern_White_Space and Pattern_Syntax.
   1205         try {
   1206             new MessageFormat("Wavelength:  {Value@\uFF14}");
   1207             errln("Creating a MessageFormat with invalid argument names " +
   1208             "should throw an IllegalArgumentException but did not!");
   1209         } catch (IllegalArgumentException e) {}
   1210 
   1211         try {
   1212             new MessageFormat("Wavelength:  {Value(\uFF14)}");
   1213             errln("Creating a MessageFormat with invalid argument names " +
   1214             "should throw an IllegalArgumentException but did not!");
   1215         } catch (IllegalArgumentException e) {}
   1216     }
   1217 
   1218     @Test
   1219     public void testNumericFormatWithMap() {
   1220         MessageFormat mf = new MessageFormat("X:{2} Y:{1}");
   1221         if (mf.usesNamedArguments()) {
   1222             errln("should not use named arguments");
   1223         }
   1224 
   1225         Map map12 = new HashMap();
   1226         map12.put("1", "one");
   1227         map12.put("2", "two");
   1228 
   1229         String target = "X:two Y:one";
   1230         String result = mf.format(map12);
   1231         if (!target.equals(result)) {
   1232             errln("expected '" + target + "' but got '" + result + "'");
   1233         }
   1234 
   1235         try {
   1236             Map mapResult = mf.parseToMap(target);
   1237             if (!map12.equals(mapResult)) {
   1238                 errln("expected " + map12 + " but got " + mapResult);
   1239             }
   1240         } catch (ParseException e) {
   1241             errln("unexpected exception: " + e.getMessage());
   1242         }
   1243 
   1244         Map map10 = new HashMap();
   1245         map10.put("1", "one");
   1246         map10.put("0", "zero");
   1247         target = "X:{2} Y:one";
   1248         result = mf.format(map10);
   1249         if (!target.equals(result)) {
   1250             errln("expected '" + target + "' but got '" + result + "'");
   1251         }
   1252 
   1253         DateFormat dateFormat = DateFormat.getDateInstance(DateFormat.MEDIUM);
   1254         DateFormat timeFormat = DateFormat.getTimeInstance(DateFormat.MEDIUM);
   1255         Map fmtMap = new HashMap();
   1256         fmtMap.put("1", dateFormat);
   1257         fmtMap.put("2", timeFormat);
   1258         mf.setFormatsByArgumentName(fmtMap);
   1259         Date date = new Date(661439820000L);
   1260 
   1261         try {
   1262             result = mf.format(map12); // should fail, wrong argument type
   1263             fail("expected exception but got '" + result + "'");
   1264         } catch (IllegalArgumentException e) {
   1265             // expect this
   1266         }
   1267 
   1268         Map argMap = new HashMap();
   1269         argMap.put("1", date);
   1270         argMap.put("2", date);
   1271         target = "X:5:17:00 AM Y:Dec 17, 1990";
   1272         result = mf.format(argMap);
   1273         if (!target.equals(result)) {
   1274             errln("expected '" + target + "' but got '" + result + "'");
   1275         }
   1276     }
   1277 
   1278     // This tests nested Formats inside PluralFormat.
   1279     @Test
   1280     public void testNestedFormatsInPluralFormat() {
   1281         try {
   1282             MessageFormat msgFmt = new MessageFormat(
   1283                     "{0, plural, one {{0, number,C''est #,##0.0# fichier}} " +
   1284                     "other {Ce sont # fichiers}} dans la liste.",
   1285                     new ULocale("fr"));
   1286             Object objArray[] = {new Long(0)};
   1287             HashMap objMap = new HashMap();
   1288             objMap.put("argument", objArray[0]);
   1289             String result = msgFmt.format(objArray);
   1290             if (!result.equals("C'est 0,0 fichier dans la liste.")) {
   1291                 errln("PluralFormat produced wrong message string.");
   1292             }
   1293         } catch (Exception e) {
   1294             e.printStackTrace();
   1295             throw new RuntimeException(e.getMessage());
   1296         }
   1297     }
   1298 
   1299     // This tests PluralFormats used inside MessageFormats.
   1300     @Test
   1301     public void testPluralFormat() {
   1302         {
   1303             MessageFormat mfNum = new MessageFormat(
   1304                     "{0, plural, one{C''est # fichier} other " +
   1305                       "{Ce sont # fichiers}} dans la liste.",
   1306                     new ULocale("fr"));
   1307             MessageFormat mfAlpha = new MessageFormat(
   1308                     "{argument, plural, one{C''est # fichier} other {Ce " +
   1309                       "sont # fichiers}} dans la liste.",
   1310                     new ULocale("fr"));
   1311             Object objArray[] = {new Long(0)};
   1312             HashMap objMap = new HashMap();
   1313             objMap.put("argument", objArray[0]);
   1314             String result = mfNum.format(objArray);
   1315             if (!result.equals(mfAlpha.format(objMap))) {
   1316                 errln("PluralFormat's output differs when using named " +
   1317                         "arguments instead of numbers!");
   1318             }
   1319             if (!result.equals("C'est 0 fichier dans la liste.")) {
   1320                 errln("PluralFormat produced wrong message string.");
   1321             }
   1322         }
   1323         {
   1324             MessageFormat mfNum = new MessageFormat (
   1325                     "There {0, plural, one{is # zavod}few{are {0, " +
   1326                       "number,###.0} zavoda} other{are # zavodov}} in the " +
   1327                       "directory.",
   1328                     new ULocale("uk"));
   1329             MessageFormat mfAlpha = new MessageFormat (
   1330                     "There {argument, plural, one{is # zavod}few{" +
   1331                       "are {argument, number,###.0} zavoda} other{are # " +
   1332                       "zavodov}} in the directory.",
   1333                     new ULocale("uk"));
   1334             Object objArray[] = {new Long(4)};
   1335             HashMap objMap = new HashMap();
   1336             objMap.put("argument", objArray[0]);
   1337             String result = mfNum.format(objArray);
   1338             if (!result.equals(mfAlpha.format(objMap))) {
   1339                 errln("PluralFormat's output differs when using named " +
   1340                         "arguments instead of numbers!");
   1341             }
   1342             if (!result.equals("There are 4,0 zavoda in the directory.")) {
   1343                 errln("PluralFormat produced wrong message string.");
   1344             }
   1345         }
   1346     }
   1347 
   1348     @Test
   1349     public void testApostropheInPluralAndSelect() {
   1350         MessageFormat fmt = new MessageFormat(
   1351                 "abc_{0,plural,other{#'#'#'{'#''}}_def_{1,select,other{sel'}'ect''}}_xyz",
   1352                 Locale.ENGLISH);
   1353         String expected = "abc_3#3{3'_def_sel}ect'_xyz";
   1354         String result = fmt.format(new Object[] { 3, "x" });
   1355         if (!result.equals(expected)) {
   1356             errln("MessageFormat with apostrophes in plural/select arguments failed:\n" +
   1357                   "Expected "+expected+"\n" +
   1358                   "Got      "+result);
   1359         }
   1360     }
   1361 
   1362   // Test toPattern when there is a PluralFormat
   1363     @Test
   1364   public void testPluralFormatToPattern() {
   1365     String[] patterns = {
   1366       "Beware of vicious {0, plural, one {hamster} other {hamsters}}.",
   1367       "{0, plural, one {{0, number,C''''est #,##0.0# fichier}} other {Ce sont # fichiers}} dans la liste.",
   1368       "{0, plural, one {C''est # fichier} other {Ce sont # fichiers}} dans la liste.",
   1369     };
   1370 
   1371     for (int i = 0; i < patterns.length; ++i) {
   1372       String pattern = patterns[i];
   1373       MessageFormat mf = new MessageFormat(pattern);
   1374       MessageFormat mf2 = new MessageFormat(mf.toPattern());
   1375       if (!mf.equals(mf2)) {
   1376         errln("message formats not equal for pattern:\n*** '" + pattern + "'\n*** '" +
   1377               mf.toPattern() + "'");
   1378       }
   1379     }
   1380   }
   1381 
   1382     /**
   1383      * This tests SelectFormats used inside MessageFormats.
   1384      */
   1385     @Test
   1386     public void testSelectFormat() {
   1387         String pattern = null;
   1388         MessageFormat msgFmt = null ;
   1389 
   1390         //Create the MessageFormat with simple French pattern
   1391         pattern = "{0} est {1, select, female {all\\u00E9e} other {all\\u00E9}} \\u00E0 Paris.";
   1392         msgFmt = new MessageFormat(pattern);
   1393         assertNotNull( "ERROR:Failure in constructing with simple French pattern", msgFmt);
   1394 
   1395         //Format
   1396         Object testArgs[][] ={
   1397             {"Kirti","female"} ,
   1398             {"Victor","other"} ,
   1399             {"Ash","unknown"} ,
   1400         };
   1401         String exp[] = {
   1402             "Kirti est all\\u00E9e \\u00E0 Paris." ,
   1403             "Victor est all\\u00E9 \\u00E0 Paris.",
   1404             "Ash est all\\u00E9 \\u00E0 Paris."
   1405         };
   1406         for ( int i=0; i< 3; i++){
   1407             assertEquals("ERROR:Failure in format with simple French Pattern" ,
   1408                       exp[i] , msgFmt.format(testArgs[i]) );
   1409         }
   1410 
   1411         //Create the MessageFormat with Quoted French Pattern
   1412         pattern = "{0} est {1, select, female {all\\u00E9e c''est} other {all\\u00E9 c''est}} \\u00E0 Paris.";
   1413         msgFmt = new MessageFormat(pattern);
   1414         assertNotNull( "ERROR:Failure in constructing with quoted French pattern", msgFmt);
   1415 
   1416         //Format
   1417         Object testArgs1[][] ={
   1418             {"Kirti","female"} ,
   1419             {"Victor","other"} ,
   1420             {"Ash","male"} ,
   1421         };
   1422         String exp1[] = {
   1423             "Kirti est all\\u00E9e c'est \\u00E0 Paris." ,
   1424             "Victor est all\\u00E9 c'est \\u00E0 Paris.",
   1425             "Ash est all\\u00E9 c'est \\u00E0 Paris."
   1426         };
   1427         for ( int i=0; i< 3; i++){
   1428             assertEquals("ERROR:Failure in format with quoted French Pattern" ,
   1429                           exp1[i] , msgFmt.format(testArgs1[i]) );
   1430         }
   1431 
   1432         //Nested patterns with plural, number ,choice ,select format etc.
   1433         //Select Format with embedded number format
   1434         pattern = "{0} est {1, select, female {{2,number,integer} all\\u00E9e} other {all\\u00E9}} \\u00E0 Paris.";
   1435         msgFmt = new MessageFormat(pattern);
   1436         assertNotNull( "ERROR:Failure in constructing with nested pattern 1", msgFmt);
   1437 
   1438         //Format
   1439         Object testArgs3[][] ={
   1440             {"Kirti", "female", 6} ,
   1441             {"Kirti", "female", 100.100} ,
   1442             {"Kirti", "other", 6} ,
   1443         };
   1444         String exp3[] = {
   1445             "Kirti est 6 all\\u00E9e \\u00E0 Paris." ,
   1446             "Kirti est 100 all\\u00E9e \\u00E0 Paris.",
   1447             "Kirti est all\\u00E9 \\u00E0 Paris."
   1448         };
   1449 
   1450         for ( int i=0; i< 3; i++){
   1451             assertEquals("ERROR:Failure in format with nested Pattern 1" ,
   1452                           exp3[i] , msgFmt.format(testArgs3[i]) );
   1453         }
   1454 
   1455         //Plural format with embedded select format
   1456         pattern = "{0} {1, plural, one {est {2, select, female {all\\u00E9e} other {all\\u00E9}}} other {sont {2, select, female {all\\u00E9es} other {all\\u00E9s}}}} \\u00E0 Paris.";
   1457         msgFmt = new MessageFormat(pattern);
   1458         assertNotNull( "ERROR:Failure in constructing with nested pattern 2", msgFmt);
   1459 
   1460         //Format
   1461         Object testArgs4[][] ={
   1462             {"Kirti",6,"female"},
   1463             {"Kirti",1,"female"},
   1464             {"Ash",1,"other"},
   1465             {"Ash",5,"other"},
   1466         };
   1467         String exp4[] = {
   1468             "Kirti sont all\\u00E9es \\u00E0 Paris." ,
   1469             "Kirti est all\\u00E9e \\u00E0 Paris.",
   1470             "Ash est all\\u00E9 \\u00E0 Paris.",
   1471             "Ash sont all\\u00E9s \\u00E0 Paris."
   1472         };
   1473         for ( int i=0; i< 4; i++){
   1474             assertEquals("ERROR:Failure in format with nested Pattern 2" ,
   1475                           exp4[i] , msgFmt.format(testArgs4[i]) );
   1476         }
   1477 
   1478         //Select, plural, and number formats heavily nested
   1479         pattern = "{0} und {1, select, female {{2, plural, one {{3, select, female {ihre Freundin} other {ihr Freund}} } other {ihre {2, number, integer} {3, select, female {Freundinnen} other {Freunde}} } }} other{{2, plural, one {{3, select, female {seine Freundin} other {sein Freund}}} other {seine {2, number, integer} {3, select, female {Freundinnen} other {Freunde}}}}} } gingen nach Paris.";
   1480         msgFmt = new MessageFormat(pattern);
   1481         assertNotNull( "ERROR:Failure in constructing with nested pattern 3", msgFmt);
   1482 
   1483         //Format
   1484         Object testArgs5[][] ={
   1485             {"Kirti","other",1,"other"},
   1486             {"Kirti","other",6,"other"},
   1487             {"Kirti","other",1,"female"},
   1488             {"Kirti","other",3,"female"},
   1489             {"Kirti","female",1,"female"},
   1490             {"Kirti","female",5,"female"},
   1491             {"Kirti","female",1,"other"},
   1492             {"Kirti","female",5,"other"},
   1493             {"Kirti","mixed",1,"mixed"},
   1494             {"Kirti","mixed",1,"other"},
   1495             {"Kirti","female",1,"mixed"},
   1496             {"Kirti","mixed",5,"mixed"},
   1497             {"Kirti","mixed",5,"other"},
   1498             {"Kirti","female",5,"mixed"},
   1499         };
   1500         String exp5[] = {
   1501             "Kirti und sein Freund gingen nach Paris." ,
   1502             "Kirti und seine 6 Freunde gingen nach Paris." ,
   1503             "Kirti und seine Freundin gingen nach Paris.",
   1504             "Kirti und seine 3 Freundinnen gingen nach Paris.",
   1505             "Kirti und ihre Freundin  gingen nach Paris.",
   1506             "Kirti und ihre 5 Freundinnen  gingen nach Paris.",
   1507             "Kirti und ihr Freund  gingen nach Paris.",
   1508             "Kirti und ihre 5 Freunde  gingen nach Paris.",
   1509             "Kirti und sein Freund gingen nach Paris.",
   1510             "Kirti und sein Freund gingen nach Paris.",
   1511             "Kirti und ihr Freund  gingen nach Paris.",
   1512             "Kirti und seine 5 Freunde gingen nach Paris." ,
   1513             "Kirti und seine 5 Freunde gingen nach Paris." ,
   1514             "Kirti und ihre 5 Freunde  gingen nach Paris."
   1515         };
   1516         //Format
   1517         for ( int i=0; i< 14; i++){
   1518             assertEquals("ERROR:Failure in format with nested Pattern 3" ,
   1519                           exp5[i] , msgFmt.format(testArgs5[i]) );
   1520         }
   1521     }
   1522 
   1523     /**
   1524      * Test toPattern when there is a SelectFormat
   1525      */
   1526     @Test
   1527     public void testSelectFormatToPattern() {
   1528         String[] patterns = {
   1529           //Pattern with some text at start and at end
   1530           "{0} est {1,select, female {all\\u00E9e} other {all\\u00E9}} \\u00E0 Paris.",
   1531           //Pattern with some text at start
   1532           "{0} est {1,select, female {all\\u00E9e} other {all\\u00E9}}",
   1533           //Pattern with some text at end
   1534           "{1, select,female {all\\u00E9e} other {all\\u00E9}} \\u00E0 Paris.",
   1535           //Pattern with no text at any  end
   1536           "{1, select,female {all\\u00E9e} other {all\\u00E9}}.",
   1537           //Quoted French pattern
   1538           "{0} est {1,select, female {all\\u00E9e c''est} other {all\\u00E9 c''est}} \\u00E0 Paris.",
   1539         };
   1540 
   1541         for (int i = 0; i < patterns.length; ++i) {
   1542             String pattern = patterns[i];
   1543             MessageFormat mf = new MessageFormat(pattern);
   1544             MessageFormat mf2 = new MessageFormat(mf.toPattern());
   1545             if (!mf.equals(mf2)) {
   1546                 errln("message formats not equal for pattern:\n*** '"
   1547                      + pattern + "'\n*** '" + mf.toPattern() + "'");
   1548             }
   1549         }
   1550     }
   1551 
   1552     // Test case for null arguments.
   1553     // Ticket#6361
   1554     @Test
   1555     public void TestNullArgs() {
   1556         MessageFormat msgfmt = new MessageFormat("{0} - {1}");
   1557         Object[][] TEST_CASES = {
   1558             {null,                          "{0} - {1}"},
   1559             {new Object[] {null},           "null - {1}"},
   1560             {new Object[] {null, null},     "null - null"},
   1561             {new Object[] {"one"},          "one - {1}"},
   1562             {new Object[] {"one", null},    "one - null"},
   1563             {new Object[] {null, "two"},    "null - two"},
   1564         };
   1565 
   1566         for (int i = 0; i < TEST_CASES.length; i++) {
   1567             String text = msgfmt.format(TEST_CASES[i][0]);
   1568             if (!text.equals(TEST_CASES[i][1])) {
   1569                 errln("FAIL: Returned[" + text + "] Expected[" + TEST_CASES[i][1] + "]");
   1570             }
   1571         }
   1572     }
   1573 
   1574     @Test
   1575     public void TestSetFormat() {
   1576         MessageFormat ms = new MessageFormat("{number} {date}", ULocale.ENGLISH);
   1577         final DecimalFormat decimalFormat = new DecimalFormat("000.000", DecimalFormatSymbols.getInstance(ULocale.ENGLISH));
   1578         ms.setFormatByArgumentName("number", decimalFormat);
   1579         final SimpleDateFormat dateFormat = new SimpleDateFormat("'year:'yy 'month:'MM 'day:'dd");
   1580         dateFormat.setTimeZone(TimeZone.getTimeZone("Etc/GMT"));
   1581         ms.setFormatByArgumentName("date", dateFormat);
   1582         Map map = new HashMap();
   1583         map.put("number", new Integer(1234));
   1584         map.put("date", new Date(0,0,0));
   1585         String result = ms.format(map);
   1586         assertEquals("setFormatByArgumentName", "1234.000 year:99 month:12 day:31", result);
   1587         Set formatNames = ms.getArgumentNames();
   1588         assertEquals("Format Names match", formatNames, map.keySet());
   1589         assertEquals("Decimal", decimalFormat, ms.getFormatByArgumentName("number"));
   1590         assertEquals("Date", dateFormat, ms.getFormatByArgumentName("date"));
   1591     }
   1592 
   1593     // Test case for formatToCharacterIterator
   1594     @Test
   1595     public void TestFormatToCharacterIterator() {
   1596         MessageFormat[] msgfmts = {
   1597                 new MessageFormat(
   1598                         "The {3,ordinal} folder ''{0}'' contains {2,number} file(s), created at {1,time} on {1,date}."),
   1599                 new MessageFormat(
   1600                         "The {arg3,ordinal} folder ''{arg0}'' contains {arg2,number} file(s), created at {arg1,time} on {arg1,date}."), // same
   1601                                                                                                                                         // as
   1602                                                                                                                                         // above,
   1603                                                                                                                                         // but
   1604                                                                                                                                         // named
   1605                                                                                                                                         // args
   1606                 new MessageFormat("The folder contains {0}.") };
   1607 
   1608         double filelimits[] = { 0, 1, 2 };
   1609         String filepart[] = { "no files", "one file", "{0,number} files" };
   1610         ChoiceFormat fileform = new ChoiceFormat(filelimits, filepart);
   1611         msgfmts[2].setFormat(0, fileform);
   1612 
   1613         Object[] args0 = new Object[] { "tmp", new Date(1184777888000L), new Integer(15), new Integer(2) };
   1614 
   1615         HashMap args1 = new HashMap();
   1616         args1.put("arg0", "tmp");
   1617         args1.put("arg1", new Date(1184777888000L));
   1618         args1.put("arg2", new Integer(15));
   1619         args1.put("arg3", new Integer(2));
   1620 
   1621         Object[] args2 = new Object[] { new Integer(34) };
   1622 
   1623         Object[] args = { args0, args1, args2 };
   1624 
   1625         String[] expectedStrings = {
   1626                 "The 2nd folder 'tmp' contains 15 file(s), created at 9:58:08 AM on Jul 18, 2007.",
   1627                 "The 2nd folder 'tmp' contains 15 file(s), created at 9:58:08 AM on Jul 18, 2007.",
   1628                 "The folder contains 34 files." };
   1629 
   1630         AttributedString[] expectedAttributedStrings = { new AttributedString(expectedStrings[0]),
   1631                 new AttributedString(expectedStrings[1]), new AttributedString(expectedStrings[2]) };
   1632 
   1633         // Add expected attributes to the expectedAttributedStrings[0]
   1634         expectedAttributedStrings[0].addAttribute(MessageFormat.Field.ARGUMENT, new Integer(3), 4, 7);
   1635         expectedAttributedStrings[0].addAttribute(MessageFormat.Field.ARGUMENT, new Integer(0), 16, 19);
   1636         expectedAttributedStrings[0].addAttribute(MessageFormat.Field.ARGUMENT, new Integer(2), 30, 32);
   1637         expectedAttributedStrings[0].addAttribute(NumberFormat.Field.INTEGER, NumberFormat.Field.INTEGER, 30, 32);
   1638         expectedAttributedStrings[0].addAttribute(MessageFormat.Field.ARGUMENT, new Integer(1), 53, 63);
   1639         expectedAttributedStrings[0].addAttribute(DateFormat.Field.HOUR1, DateFormat.Field.HOUR1, 53, 54);
   1640         //expectedAttributedStrings[0].addAttribute(DateFormat.Field.TIME_SEPARATOR, DateFormat.Field.TIME_SEPARATOR, 54, 55);
   1641         expectedAttributedStrings[0].addAttribute(DateFormat.Field.MINUTE, DateFormat.Field.MINUTE, 55, 57);
   1642         //expectedAttributedStrings[0].addAttribute(DateFormat.Field.TIME_SEPARATOR, DateFormat.Field.TIME_SEPARATOR, 57, 58);
   1643         expectedAttributedStrings[0].addAttribute(DateFormat.Field.SECOND, DateFormat.Field.SECOND, 58, 60);
   1644         expectedAttributedStrings[0].addAttribute(DateFormat.Field.AM_PM, DateFormat.Field.AM_PM, 61, 63);
   1645         expectedAttributedStrings[0].addAttribute(MessageFormat.Field.ARGUMENT, new Integer(1), 67, 79);
   1646         expectedAttributedStrings[0].addAttribute(DateFormat.Field.MONTH, DateFormat.Field.MONTH, 67, 70);
   1647         expectedAttributedStrings[0].addAttribute(DateFormat.Field.DAY_OF_MONTH, DateFormat.Field.DAY_OF_MONTH, 71, 73);
   1648         expectedAttributedStrings[0].addAttribute(DateFormat.Field.YEAR, DateFormat.Field.YEAR, 75, 79);
   1649 
   1650         // Add expected attributes to the expectedAttributedStrings[1]
   1651         expectedAttributedStrings[1].addAttribute(MessageFormat.Field.ARGUMENT, "arg3", 4, 7);
   1652         expectedAttributedStrings[1].addAttribute(MessageFormat.Field.ARGUMENT, "arg0", 16, 19);
   1653         expectedAttributedStrings[1].addAttribute(MessageFormat.Field.ARGUMENT, "arg2", 30, 32);
   1654         expectedAttributedStrings[1].addAttribute(NumberFormat.Field.INTEGER, NumberFormat.Field.INTEGER, 30, 32);
   1655         expectedAttributedStrings[1].addAttribute(MessageFormat.Field.ARGUMENT, "arg1", 53, 63);
   1656         expectedAttributedStrings[1].addAttribute(DateFormat.Field.HOUR1, DateFormat.Field.HOUR1, 53, 54);
   1657         //expectedAttributedStrings[1].addAttribute(DateFormat.Field.TIME_SEPARATOR, DateFormat.Field.TIME_SEPARATOR, 54, 55);
   1658         expectedAttributedStrings[1].addAttribute(DateFormat.Field.MINUTE, DateFormat.Field.MINUTE, 55, 57);
   1659         //expectedAttributedStrings[1].addAttribute(DateFormat.Field.TIME_SEPARATOR, DateFormat.Field.TIME_SEPARATOR, 57, 58);
   1660         expectedAttributedStrings[1].addAttribute(DateFormat.Field.SECOND, DateFormat.Field.SECOND, 58, 60);
   1661         expectedAttributedStrings[1].addAttribute(DateFormat.Field.AM_PM, DateFormat.Field.AM_PM, 61, 63);
   1662         expectedAttributedStrings[1].addAttribute(MessageFormat.Field.ARGUMENT, "arg1", 67, 79);
   1663         expectedAttributedStrings[1].addAttribute(DateFormat.Field.MONTH, DateFormat.Field.MONTH, 67, 70);
   1664         expectedAttributedStrings[1].addAttribute(DateFormat.Field.DAY_OF_MONTH, DateFormat.Field.DAY_OF_MONTH, 71, 73);
   1665         expectedAttributedStrings[1].addAttribute(DateFormat.Field.YEAR, DateFormat.Field.YEAR, 75, 79);
   1666 
   1667         // Add expected attributes to the expectedAttributedStrings[2]
   1668         expectedAttributedStrings[2].addAttribute(MessageFormat.Field.ARGUMENT, new Integer(0), 20, 28);
   1669         expectedAttributedStrings[2].addAttribute(NumberFormat.Field.INTEGER, NumberFormat.Field.INTEGER, 20, 22);
   1670 
   1671         for (int i = 0; i < msgfmts.length; i++) {
   1672             AttributedCharacterIterator acit = msgfmts[i].formatToCharacterIterator(args[i]);
   1673             AttributedCharacterIterator expectedAcit = expectedAttributedStrings[i].getIterator();
   1674 
   1675             // Check available attributes
   1676             Set attrSet = acit.getAllAttributeKeys();
   1677             Set expectedAttrSet = expectedAcit.getAllAttributeKeys();
   1678             if (attrSet.size() != expectedAttrSet.size()) {
   1679                 errln("FAIL: Number of attribute keys is " + attrSet.size() + " expected: " + expectedAttrSet.size());
   1680             }
   1681             Iterator attrIterator = attrSet.iterator();
   1682             while (attrIterator.hasNext()) {
   1683                 AttributedCharacterIterator.Attribute attr = (AttributedCharacterIterator.Attribute) attrIterator
   1684                         .next();
   1685                 if (!expectedAttrSet.contains(attr)) {
   1686                     errln("FAIL: The attribute " + attr + " is not expected.");
   1687                 }
   1688             }
   1689 
   1690             StringBuffer buf = new StringBuffer();
   1691             int index = acit.getBeginIndex();
   1692             int end = acit.getEndIndex();
   1693             int indexExp = expectedAcit.getBeginIndex();
   1694             int expectedLen = expectedAcit.getEndIndex() - indexExp;
   1695             if (end - index != expectedLen) {
   1696                 errln("FAIL: Length of the result attributed string is " + (end - index) + " expected: " + expectedLen);
   1697             } else {
   1698                 // Check attributes associated with each character
   1699                 while (index < end) {
   1700                     char c = acit.setIndex(index);
   1701                     buf.append(c);
   1702                     expectedAcit.setIndex(indexExp);
   1703 
   1704                     Map attrs = acit.getAttributes();
   1705                     Map attrsExp = expectedAcit.getAttributes();
   1706                     if (attrs.size() != attrsExp.size()) {
   1707                         errln("FAIL: Number of attributes associated with index " + index + " is " + attrs.size()
   1708                                 + " expected: " + attrsExp.size());
   1709                     } else {
   1710                         // Check all attributes at the index
   1711                         Iterator entryIterator = attrsExp.entrySet().iterator();
   1712                         while (entryIterator.hasNext()) {
   1713                             Map.Entry entry = (Map.Entry) entryIterator.next();
   1714                             if (attrs.containsKey(entry.getKey())) {
   1715                                 Object value = attrs.get(entry.getKey());
   1716                                 assertEquals("Attribute value at index " + index, entry.getValue(), value);
   1717                             } else {
   1718                                 errln("FAIL: Attribute " + entry.getKey() + " is missing at index " + index);
   1719                             }
   1720                         }
   1721                     }
   1722                     index++;
   1723                     indexExp++;
   1724                 }
   1725                 assertEquals("AttributedString contents", expectedStrings[i], buf.toString());
   1726             }
   1727         }
   1728 
   1729         // Tests when "if (arguments == null)" is true
   1730         try {
   1731             MessageFormat mf = new MessageFormat("");
   1732             mf.formatToCharacterIterator(null);
   1733             errln("MessageFormat.formatToCharacterIterator(Object) was suppose "
   1734                     + "to return an exception when null is passed.");
   1735         } catch (Exception e) {
   1736         }
   1737     }
   1738 
   1739     /*
   1740      * Tests the method public Format getFormatByArgumentName(String argumentName)
   1741      */
   1742     @Test
   1743     public void TestGetFormatByArgumentName() {
   1744         MessageFormat mf = new MessageFormat("");
   1745         if (mf.getFormatByArgumentName("") != null) {
   1746             errln("MessageFormat.getFormatByArgumentName(String) was suppose "
   1747                     + "to return an null if argumentName was not found.");
   1748         }
   1749     }
   1750 
   1751     public String getPatternAndSkipSyntax(MessagePattern pattern) {
   1752         StringBuilder sb = new StringBuilder(pattern.getPatternString());
   1753         int count = pattern.countParts();
   1754         for (int i = count; i > 0;) {
   1755             MessagePattern.Part part = pattern.getPart(--i);
   1756             if (part.getType() == MessagePattern.Part.Type.SKIP_SYNTAX) {
   1757                 sb.delete(part.getIndex(), part.getLimit());
   1758             }
   1759         }
   1760         return sb.toString();
   1761     }
   1762 
   1763     @Test
   1764     public void TestApostropheMode() {
   1765         MessagePattern ado_mp = new MessagePattern(MessagePattern.ApostropheMode.DOUBLE_OPTIONAL);
   1766         MessagePattern adr_mp = new MessagePattern(MessagePattern.ApostropheMode.DOUBLE_REQUIRED);
   1767         assertEquals("wrong value",
   1768                 MessagePattern.ApostropheMode.DOUBLE_OPTIONAL,
   1769                 ado_mp.getApostropheMode());
   1770         assertEquals("wrong value",
   1771                 MessagePattern.ApostropheMode.DOUBLE_REQUIRED,
   1772                 adr_mp.getApostropheMode());
   1773         assertNotEquals("MessagePatterns with different ApostropheMode (no pattern)", ado_mp, adr_mp);
   1774         assertNotEquals("MessagePatterns with different ApostropheMode (a)",
   1775                 ado_mp.parse("a"), adr_mp.parse("a"));
   1776 
   1777         String[] tuples = new String[] {
   1778             // Desired output
   1779             // DOUBLE_OPTIONAL pattern
   1780             // DOUBLE_REQUIRED pattern (null=same as DOUBLE_OPTIONAL)
   1781             "I see {many}", "I see '{many}'", null,
   1782             "I said {'Wow!'}", "I said '{''Wow!''}'", null,
   1783             "I dont know", "I dont know", "I don't know",
   1784             "I don't know", "I don't know", "I don''t know",
   1785             "I don't know", "I don''t know", "I don''t know",
   1786         };
   1787         for (int i = 0; i < tuples.length; i += 3) {
   1788             String desired = tuples[i];
   1789             String ado_pattern = tuples[i + 1];
   1790             assertEquals("DOUBLE_OPTIONAL failure", desired,
   1791                     getPatternAndSkipSyntax(ado_mp.parse(ado_pattern)));
   1792             String adr_pattern = tuples[i + 2];
   1793             if (adr_pattern == null) {
   1794                 adr_pattern = ado_pattern;
   1795             }
   1796             assertEquals("DOUBLE_REQUIRED failure", desired,
   1797                     getPatternAndSkipSyntax(adr_mp.parse(adr_pattern)));
   1798         }
   1799     }
   1800 
   1801     // Compare behavior of JDK and ICU's DOUBLE_REQUIRED compatibility mode.
   1802     @Test
   1803     public void TestCompatibleApostrophe() {
   1804         // Message with choice argument which does not contain another argument.
   1805         // The JDK performs only one apostrophe-quoting pass on this pattern.
   1806         String pattern = "ab{0,choice,0#1'2''3'''4''''.}yz";
   1807         java.text.MessageFormat jdkMsg =
   1808             new java.text.MessageFormat(pattern, Locale.ENGLISH);
   1809 
   1810         MessageFormat compMsg = new MessageFormat("", Locale.ENGLISH);
   1811         compMsg.applyPattern(pattern, MessagePattern.ApostropheMode.DOUBLE_REQUIRED);
   1812         assertEquals("wrong value",
   1813                 MessagePattern.ApostropheMode.DOUBLE_REQUIRED,
   1814                 compMsg.getApostropheMode());
   1815 
   1816         MessageFormat icuMsg = new MessageFormat("", Locale.ENGLISH);
   1817         icuMsg.applyPattern(pattern, MessagePattern.ApostropheMode.DOUBLE_OPTIONAL);
   1818         assertEquals("wrong value",
   1819                 MessagePattern.ApostropheMode.DOUBLE_OPTIONAL,
   1820                 icuMsg.getApostropheMode());
   1821 
   1822         Object[] zero0 = new Object[] { 0 };
   1823         assertEquals("unexpected JDK MessageFormat apostrophe behavior",
   1824                 "ab12'3'4''.yz",
   1825                 jdkMsg.format(zero0));
   1826         assertEquals("incompatible ICU MessageFormat compatibility-apostrophe behavior",
   1827                 "ab12'3'4''.yz",
   1828                 compMsg.format(zero0));
   1829         assertEquals("unexpected ICU MessageFormat double-apostrophe-optional behavior",
   1830                 "ab1'2'3''4''.yz",
   1831                 icuMsg.format(zero0));
   1832 
   1833         // Message with choice argument which contains a nested simple argument.
   1834         // The JDK performs two apostrophe-quoting passes.
   1835         pattern = "ab{0,choice,0#1'2''3'''4''''.{0,number,'#x'}}yz";
   1836         jdkMsg.applyPattern(pattern);
   1837         compMsg.applyPattern(pattern);
   1838         icuMsg.applyPattern(pattern);
   1839         assertEquals("unexpected JDK MessageFormat apostrophe behavior",
   1840                 "ab1234'.0xyz",
   1841                 jdkMsg.format(zero0));
   1842         assertEquals("incompatible ICU MessageFormat compatibility-apostrophe behavior",
   1843                 "ab1234'.0xyz",
   1844                 compMsg.format(zero0));
   1845         assertEquals("unexpected ICU MessageFormat double-apostrophe-optional behavior",
   1846                 "ab1'2'3''4''.#x0yz",
   1847                 icuMsg.format(zero0));
   1848 
   1849         // Message with choice argument which contains a nested choice argument.
   1850         // The JDK fails to parse this pattern.
   1851         // jdkMsg.applyPattern("cd{0,choice,0#ef{0,choice,0#1'2''3'''4''''.}uv}wx");
   1852         // For lack of comparison, we do not test ICU with this pattern.
   1853 
   1854         // The JDK ChoiceFormat itself always performs one apostrophe-quoting pass.
   1855         ChoiceFormat choice = new ChoiceFormat("0#1'2''3'''4''''.");
   1856         assertEquals("unexpected JDK ChoiceFormat apostrophe behavior",
   1857                 "12'3'4''.",
   1858                 choice.format(0));
   1859         choice.applyPattern("0#1'2''3'''4''''.{0,number,'#x'}");
   1860         assertEquals("unexpected JDK ChoiceFormat apostrophe behavior",
   1861                 "12'3'4''.{0,number,#x}",
   1862                 choice.format(0));
   1863     }
   1864 
   1865     @Test
   1866     public void TestTrimArgumentName() {
   1867         // ICU 4.8 allows and ignores white space around argument names and numbers.
   1868         MessageFormat m = new MessageFormat("a { 0 , number , '#,#'#.0 } z", Locale.ENGLISH);
   1869         assertEquals("trim-numbered-arg format() failed", "a  #,#2.0  z", m.format(new Object[] { 2 }));
   1870 
   1871         m.applyPattern("x { _oOo_ , number , integer } y");
   1872         Map<String, Object> map = new HashMap<String, Object>();
   1873         map.put("_oOo_", new Integer(3));
   1874         StringBuffer result = new StringBuffer();
   1875         assertEquals("trim-named-arg format() failed", "x 3 y",
   1876                      m.format(map, result, new FieldPosition(0)).toString());
   1877     }
   1878 
   1879     @Test
   1880     public void TestSelectOrdinal() {
   1881         // Test plural & ordinal together,
   1882         // to make sure that we get the correct cached PluralSelector for each.
   1883         MessageFormat m = new MessageFormat(
   1884             "{0,plural,one{1 file}other{# files}}, " +
   1885             "{0,selectordinal,one{#st file}two{#nd file}few{#rd file}other{#th file}}",
   1886             ULocale.ENGLISH);
   1887         Object[] args = new Object[] { 21 };
   1888         FieldPosition ignore = null;
   1889         StringBuffer result = new StringBuffer();
   1890         assertEquals("plural-and-ordinal format(21)", "21 files, 21st file",
   1891                      m.format(args, result, ignore).toString());
   1892 
   1893         args[0] = 2;
   1894         result.delete(0, result.length());
   1895         assertEquals("plural-and-ordinal format(2) failed", "2 files, 2nd file",
   1896                      m.format(args, result, ignore).toString());
   1897 
   1898         args[0] = 1;
   1899         result.delete(0, result.length());
   1900         assertEquals("plural-and-ordinal format(1) failed", "1 file, 1st file",
   1901                      m.format(args, result, ignore).toString());
   1902 
   1903         args[0] = 3;
   1904         result.delete(0, result.length());
   1905         assertEquals("plural-and-ordinal format(3) failed", "3 files, 3rd file",
   1906                      m.format(args, result, ignore).toString());
   1907     }
   1908 
   1909     @Test
   1910     public void TestDecimals() {
   1911         // Simple number replacement.
   1912         MessageFormat m = new MessageFormat(
   1913                 "{0,plural,one{one meter}other{# meters}}",
   1914                 ULocale.ENGLISH);
   1915         Object[] args = new Object[] { 1 };
   1916         FieldPosition ignore = null;
   1917         StringBuffer result = new StringBuffer();
   1918         assertEquals("simple format(1)", "one meter",
   1919                 m.format(args, result, ignore).toString());
   1920 
   1921         args[0] = 1.5;
   1922         result.delete(0, result.length());
   1923         assertEquals("simple format(1.5)", "1.5 meters",
   1924                 m.format(args, result, ignore).toString());
   1925 
   1926         // Simple but explicit.
   1927         MessageFormat m0 = new MessageFormat(
   1928                 "{0,plural,one{one meter}other{{0} meters}}",
   1929                 ULocale.ENGLISH);
   1930         args[0] = 1;
   1931         result.delete(0, result.length());
   1932         assertEquals("explicit format(1)", "one meter",
   1933                 m0.format(args, result, ignore).toString());
   1934 
   1935         args[0] = 1.5;
   1936         result.delete(0, result.length());
   1937         assertEquals("explicit format(1.5)", "1.5 meters",
   1938                 m0.format(args, result, ignore).toString());
   1939 
   1940         // With offset and specific simple format with optional decimals.
   1941         MessageFormat m1 = new MessageFormat(
   1942                 "{0,plural,offset:1 one{another meter}other{{0,number,00.#} meters}}",
   1943                 ULocale.ENGLISH);
   1944         args[0] = 1;
   1945         result.delete(0, result.length());
   1946         assertEquals("offset format(1)", "01 meters",
   1947                 m1.format(args, result, ignore).toString());
   1948 
   1949         args[0] = 2;
   1950         result.delete(0, result.length());
   1951         assertEquals("offset format(1)", "another meter",
   1952                 m1.format(args, result, ignore).toString());
   1953 
   1954         args[0] = 2.5;
   1955         result.delete(0, result.length());
   1956         assertEquals("offset format(1)", "02.5 meters",
   1957                 m1.format(args, result, ignore).toString());
   1958 
   1959         // With offset and specific simple format with forced decimals.
   1960         MessageFormat m2 = new MessageFormat(
   1961                 "{0,plural,offset:1 one{another meter}other{{0,number,0.0} meters}}",
   1962                 ULocale.ENGLISH);
   1963         args[0] = 1;
   1964         result.delete(0, result.length());
   1965         assertEquals("offset-decimals format(1)", "1.0 meters",
   1966                 m2.format(args, result, ignore).toString());
   1967 
   1968         args[0] = 2;
   1969         result.delete(0, result.length());
   1970         assertEquals("offset-decimals format(1)", "2.0 meters",
   1971                 m2.format(args, result, ignore).toString());
   1972 
   1973         args[0] = 2.5;
   1974         result.delete(0, result.length());
   1975         assertEquals("offset-decimals format(1)", "2.5 meters",
   1976                 m2.format(args, result, ignore).toString());
   1977     }
   1978 
   1979     @Test
   1980     public void TestArgIsPrefixOfAnother() {
   1981         // Ticket #11952
   1982         MessageFormat mf1 = new MessageFormat(
   1983                 "{0,select,a{A}ab{AB}abc{ABC}other{?}}", ULocale.ENGLISH);
   1984         assertEquals("a", "A", mf1.format(new Object[] { "a" }));
   1985         assertEquals("ab", "AB", mf1.format(new Object[] { "ab" }));
   1986         assertEquals("abc", "ABC", mf1.format(new Object[] { "abc" }));
   1987 
   1988         // Ticket #12172
   1989         MessageFormat mf2 = new MessageFormat("{a} {aa} {aaa}", ULocale.ENGLISH);
   1990         Map<String, Object> args = new TreeMap<String, Object>();
   1991         args.put("a", "A");
   1992         args.put("aa", "AB");
   1993         args.put("aaa", "ABC");
   1994         assertEquals("a aa aaa", "A AB ABC", mf2.format(args, new StringBuffer(), null).toString());
   1995 
   1996         // Ticket #12172
   1997         MessageFormat mf3 = new MessageFormat("{aa} {aaa}", ULocale.ENGLISH);
   1998         assertEquals("aa aaa", "AB ABC", mf3.format(args, new StringBuffer(), null).toString());
   1999     }
   2000 
   2001     public void TestMessagePatternAutoQuoteApostropheDeep() {
   2002         // Example input & output taken from API docs.
   2003         MessagePattern pattern = new MessagePattern(
   2004                 "I don't '{know}' {gender,select,female{h''er}other{h'im}}.");
   2005         assertEquals("autoQuoteApostropheDeep()",
   2006                 "I don''t '{know}' {gender,select,female{h''er}other{h''im}}.",
   2007                 pattern.autoQuoteApostropheDeep());
   2008     }
   2009 
   2010     public void TestMessagePatternFreezable() {
   2011         MessagePattern pattern = new MessagePattern();
   2012         assertFalse("just constructed, not yet frozen", pattern.isFrozen());
   2013         pattern.parse("fee");
   2014         assertTrue("parsed, not empty", pattern.countParts() > 0);
   2015         pattern.freeze();
   2016         assertTrue("just frozen", pattern.isFrozen());
   2017         try {
   2018             pattern.parse("fi");
   2019             fail("MessagePattern.freeze().parse() did not fail");
   2020         } catch (Exception expected) {
   2021         }
   2022         assertEquals("frozen+parse: no change", "fee", pattern.autoQuoteApostropheDeep());
   2023         MessagePattern thawed = pattern.cloneAsThawed();
   2024         assertFalse("thawed", thawed.isFrozen());
   2025         assertTrue("still frozen", pattern.isFrozen());
   2026         assertTrue("frozen!=thawed", pattern != thawed);
   2027         thawed.parse("fo");
   2028         assertEquals("thawed+parse", "fo", thawed.autoQuoteApostropheDeep());
   2029     }
   2030 
   2031     public void TestMessagePatternNamedAndNumberedArguments() {
   2032         MessagePattern pattern = new MessagePattern();
   2033         pattern.parse("fee");
   2034         assertFalse("fee no named args", pattern.hasNamedArguments());
   2035         assertFalse("fee no numbered args", pattern.hasNumberedArguments());
   2036         pattern.parse("fi {0}");
   2037         assertFalse("fi {0} no named args", pattern.hasNamedArguments());
   2038         assertTrue("fi {0} has numbered args", pattern.hasNumberedArguments());
   2039         pattern.parse("fo {name}");
   2040         assertTrue("fo {name} has named args", pattern.hasNamedArguments());
   2041         assertFalse("fo {name} no numbered args", pattern.hasNumberedArguments());
   2042         pattern.parse("fum {0} {name}");
   2043         assertTrue("fum {0} {name} has named args", pattern.hasNamedArguments());
   2044         assertTrue("fum {0} {name} no numbered args", pattern.hasNumberedArguments());
   2045     }
   2046 
   2047     public void TestMessagePatternPartCoverage() {
   2048         MessagePattern pattern = new MessagePattern("ab{17}c");
   2049         assertEquals("msg start { arg number } msg limit", 5, pattern.countParts());
   2050         MessagePattern.Part arg = pattern.getPart(2);
   2051         assertEquals("arg number", MessagePattern.Part.Type.ARG_NUMBER, arg.getType());
   2052         assertEquals("arg number start", 3, arg.getIndex());
   2053         assertEquals("arg number length", 2, arg.getLength());
   2054         assertEquals("arg number limit", 5, arg.getLimit());
   2055         assertEquals("arg number 17", 17, arg.getValue());
   2056     }
   2057 
   2058     public void TestMessagePatternParseChoiceStyle() {
   2059         // This would be tested by ChoiceFormat if ICU4J had its own version of that,
   2060         // like ICU4C does.
   2061         // Instead, there is only java.text.ChoiceFormat.
   2062         // Most of the implementation gets covered by testing with a MessageFormat
   2063         // that contains a nested ChoiceFormat pattern,
   2064         // but that does not call this public API method.
   2065         MessagePattern pattern = new MessagePattern();
   2066         // Example string from java.text.ChoiceFormat class docs.
   2067         pattern.parseChoiceStyle(
   2068                 "-1#is negative| 0#is zero or fraction | 1#is one |" +
   2069                 "1.0<is 1+ |2#is two |2<is more than 2.");
   2070         // Only simple API coverage. The parser implementation is tested via MessageFormat.
   2071         assertTrue("many parts", pattern.countParts() > 10);
   2072     }
   2073 
   2074     public void TestDateFormatHashCode() {
   2075         DateFormat testDF = DateFormat.getDateInstance(DateFormat.DEFAULT, ULocale.GERMAN);
   2076         NumberFormat testNF = testDF.getNumberFormat();
   2077 
   2078         int expectedResult =
   2079                 testNF.getMaximumIntegerDigits() * 37 + testNF.getMaximumFractionDigits();
   2080         int actualHashResult = testDF.hashCode();
   2081         assertEquals("DateFormat hashCode", expectedResult, actualHashResult);
   2082     }
   2083 }
   2084