/* ********************************************************************** * Copyright (c) 2004-2010, International Business Machines * Corporation and others. All Rights Reserved. ********************************************************************** * Author: Alan Liu * Created: April 6, 2004 * Since: ICU 3.0 ********************************************************************** */ package com.ibm.icu.dev.test.format; import java.text.AttributedCharacterIterator; import java.text.AttributedString; import java.text.ChoiceFormat; import java.text.FieldPosition; import java.text.Format; import java.text.ParseException; import java.text.ParsePosition; import java.util.Date; import java.util.HashMap; import java.util.Hashtable; import java.util.Iterator; import java.util.Locale; import java.util.Map; import java.util.Set; import com.ibm.icu.text.DateFormat; import com.ibm.icu.text.DecimalFormat; import com.ibm.icu.text.DecimalFormatSymbols; import com.ibm.icu.text.MessageFormat; import com.ibm.icu.text.NumberFormat; import com.ibm.icu.text.SimpleDateFormat; import com.ibm.icu.text.UFormat; import com.ibm.icu.util.TimeZone; import com.ibm.icu.util.ULocale; public class TestMessageFormat extends com.ibm.icu.dev.test.TestFmwk { public static void main(String[] args) throws Exception { new TestMessageFormat().run(args); } public void TestBug3() { double myNumber = -123456; DecimalFormat form = null; Locale locale[] = { new Locale("ar", "", ""), new Locale("be", "", ""), new Locale("bg", "", ""), new Locale("ca", "", ""), new Locale("cs", "", ""), new Locale("da", "", ""), new Locale("de", "", ""), new Locale("de", "AT", ""), new Locale("de", "CH", ""), new Locale("el", "", ""), // 10 new Locale("en", "CA", ""), new Locale("en", "GB", ""), new Locale("en", "IE", ""), new Locale("en", "US", ""), new Locale("es", "", ""), new Locale("et", "", ""), new Locale("fi", "", ""), new Locale("fr", "", ""), new Locale("fr", "BE", ""), new Locale("fr", "CA", ""), // 20 new Locale("fr", "CH", ""), new Locale("he", "", ""), new Locale("hr", "", ""), new Locale("hu", "", ""), new Locale("is", "", ""), new Locale("it", "", ""), new Locale("it", "CH", ""), new Locale("ja", "", ""), new Locale("ko", "", ""), new Locale("lt", "", ""), // 30 new Locale("lv", "", ""), new Locale("mk", "", ""), new Locale("nl", "", ""), new Locale("nl", "BE", ""), new Locale("no", "", ""), new Locale("pl", "", ""), new Locale("pt", "", ""), new Locale("ro", "", ""), new Locale("ru", "", ""), new Locale("sh", "", ""), // 40 new Locale("sk", "", ""), new Locale("sl", "", ""), new Locale("sq", "", ""), new Locale("sr", "", ""), new Locale("sv", "", ""), new Locale("tr", "", ""), new Locale("uk", "", ""), new Locale("zh", "", ""), new Locale("zh", "TW", "") // 49 }; StringBuffer buffer = new StringBuffer(); ParsePosition parsePos = new ParsePosition(0); int i; for (i= 0; i < 49; i++) { // form = (DecimalFormat)NumberFormat.getCurrencyInstance(locale[i]); form = (DecimalFormat)NumberFormat.getInstance(locale[i]); if (form == null) { errln("Number format creation failed for " + locale[i].getDisplayName()); continue; } FieldPosition pos = new FieldPosition(0); buffer.setLength(0); form.format(myNumber, buffer, pos); parsePos.setIndex(0); Object result = form.parse(buffer.toString(), parsePos); logln(locale[i].getDisplayName() + " -> " + result); if (parsePos.getIndex() != buffer.length()) { errln("Number format parse failed."); } } } public void TestBug1() { final double limit[] = {0.0, 1.0, 2.0}; final String formats[] = {"0.0<=Arg<1.0", "1.0<=Arg<2.0", "2.0<-Arg"}; ChoiceFormat cf = new ChoiceFormat(limit, formats); assertEquals("ChoiceFormat.format", formats[1], cf.format(1)); } public void TestBug2() { // {sfb} use double format in pattern, so result will match (not strictly necessary) final String pattern = "There {0,choice,0.0#are no files|1.0#is one file|1.0 map = new Hashtable(); try{ msg.format("", map); } catch(Exception e){ errln("MessageFormat.format(String,Map) was not suppose to return " + "an exception."); } } public void TestParse() { String msgFormatString = "{0} =sep= {1}"; MessageFormat msg = new MessageFormat(msgFormatString); String source = "abc =sep= def"; try { Object[] fmt_arr = msg.parse(source); if (fmt_arr.length != 2) { errln("*** MSG parse (ustring, count, err) count err."); } else { // TODO: This if statement seems to be redundant. [tschumann] if (fmt_arr.length != 2) { errln("*** MSG parse (ustring, parsepos., count) count err."); } else { assertEquals("parse()[0]", "abc", fmt_arr[0]); assertEquals("parse()[1]", "def", fmt_arr[1]); } } } catch (ParseException e1) { errln("*** MSG parse (ustring, count, err) error."); } ParsePosition pp = new ParsePosition(0); Object[] fmt_arr = msg.parse(source, pp); if (pp.getIndex()==0 || fmt_arr==null) { errln("*** MSG parse (ustring, parsepos., count) error."); } else { if (fmt_arr.length != 2) { errln("*** MSG parse (ustring, parsepos., count) count err."); } else { assertEquals("parse()[0]", "abc", fmt_arr[0]); assertEquals("parse()[1]", "def", fmt_arr[1]); } } pp.setIndex(0); Object[] fmta; fmta = (Object[]) msg.parseObject( source, pp ); if (pp.getIndex() == 0) { errln("*** MSG parse (ustring, Object, parsepos ) error."); } else { if (fmta.length != 2) { errln("*** MSG parse (ustring, count, err) count err."); } else { // TODO: Don't we want to check fmta? // In this case this if statement would be redundant, too. // [tschumann] if (fmt_arr.length != 2) { errln("*** MSG parse (ustring, parsepos., count) count err."); } else { // TODO: Don't we want to check fmta? [tschumann] assertEquals("parse()[0]", "abc", fmt_arr[0]); assertEquals("parse()[1]", "def", fmt_arr[1]); } } } } /** * Of course, in Java there is no adopt, but we retain the same * method name. [alan] */ public void TestAdopt() { String formatStr = "{0,date},{1},{2,number}"; String formatStrChange = "{0,number},{1,number},{2,date}"; MessageFormat msg = new MessageFormat(formatStr); MessageFormat msgCmp = new MessageFormat(formatStr); Format[] formats = msg.getFormats(); Format[] formatsCmp = msgCmp.getFormats(); Format[] formatsChg = null; Format[] formatsAct = null; Format a = null; Format b = null; Format[] formatsToAdopt = null; if (formats==null || formatsCmp==null || (formats.length <= 0) || (formats.length != formatsCmp.length)) { errln("Error getting Formats"); return; } int i; for (i = 0; i < formats.length; i++) { a = formats[i]; b = formatsCmp[i]; if ((a != null) && (b != null)) { if (!a.equals(b)) { errln("a != b"); return; } } else if ((a != null) || (b != null)) { errln("(a != null) || (b != null)"); return; } } msg.applyPattern( formatStrChange ); //set msg formats to something different formatsChg = msg.getFormats(); // tested function if (formatsChg==null || (formatsChg.length != formats.length)) { errln("Error getting Formats"); return; } boolean diff; diff = true; for (i = 0; i < formats.length; i++) { a = formatsChg[i]; b = formatsCmp[i]; if ((a != null) && (b != null)) { if (a.equals(b)) { logln("formatsChg == formatsCmp at index " + i); diff = false; } } } if (!diff) { errln("*** MSG getFormats diff err."); return; } logln("MSG getFormats tested."); msg.setFormats( formatsCmp ); //tested function formatsAct = msg.getFormats(); if (formatsAct==null || (formatsAct.length <=0) || (formatsAct.length != formatsCmp.length)) { errln("Error getting Formats"); return; } assertEquals("msgCmp.toPattern()", formatStr, msgCmp.toPattern()); assertEquals("msg.toPattern()", formatStr, msg.toPattern()); for (i = 0; i < formatsAct.length; i++) { a = formatsAct[i]; b = formatsCmp[i]; if ((a != null) && (b != null)) { if (!a.equals(b)) { errln("formatsAct != formatsCmp at index " + i); return; } } else if ((a != null) || (b != null)) { errln("(a != null) || (b != null)"); return; } } logln("MSG setFormats tested."); //---- msg.applyPattern( formatStrChange ); //set msg formats to something different formatsToAdopt = new Format[formatsCmp.length]; if (formatsToAdopt==null) { errln("memory allocation error"); return; } for (i = 0; i < formatsCmp.length; i++) { if (formatsCmp[i] == null) { formatsToAdopt[i] = null; } else { formatsToAdopt[i] = (Format) formatsCmp[i].clone(); if (formatsToAdopt[i]==null) { errln("Can't clone format at index " + i); return; } } } msg.setFormats( formatsToAdopt ); // function to test assertEquals("msgCmp.toPattern()", formatStr, msgCmp.toPattern()); assertEquals("msg.toPattern()", formatStr, msg.toPattern()); formatsAct = msg.getFormats(); if (formatsAct==null || (formatsAct.length <=0) || (formatsAct.length != formatsCmp.length)) { errln("Error getting Formats"); return; } for (i = 0; i < formatsAct.length; i++) { a = formatsAct[i]; b = formatsCmp[i]; if ((a != null) && (b != null)) { if (!a.equals(b)) { errln("a != b"); return; } } else if ((a != null) || (b != null)) { errln("(a != null) || (b != null)"); return; } } logln("MSG adoptFormats tested."); //---- adoptFormat msg.applyPattern( formatStrChange ); //set msg formats to something different formatsToAdopt = new Format[formatsCmp.length]; if (formatsToAdopt==null) { errln("memory allocation error"); return; } for (i = 0; i < formatsCmp.length; i++) { if (formatsCmp[i] == null) { formatsToAdopt[i] = null; } else { formatsToAdopt[i] = (Format) formatsCmp[i].clone(); if (formatsToAdopt[i]==null) { errln("Can't clone format at index " + i); return; } } } for ( i = 0; i < formatsCmp.length; i++ ) { msg.setFormat( i, formatsToAdopt[i] ); // function to test } assertEquals("msgCmp.toPattern()", formatStr, msgCmp.toPattern()); assertEquals("msg.toPattern()", formatStr, msg.toPattern()); formatsAct = msg.getFormats(); if (formatsAct==null || (formatsAct.length <=0) || (formatsAct.length != formatsCmp.length)) { errln("Error getting Formats"); return; } for (i = 0; i < formatsAct.length; i++) { a = formatsAct[i]; b = formatsCmp[i]; if ((a != null) && (b != null)) { if (!a.equals(b)) { errln("a != b"); return; } } else if ((a != null) || (b != null)) { errln("(a != null) || (b != null)"); return; } } logln("MSG adoptFormat tested."); } /** * Verify that MessageFormat accomodates more than 10 arguments and * more than 10 subformats. */ public void TestUnlimitedArgsAndSubformats() { final String pattern = "On {0,date} (aka {0,date,short}, aka {0,date,long}) "+ "at {0,time} (aka {0,time,short}, aka {0,time,long}) "+ "there were {1,number} werjes "+ "(a {3,number,percent} increase over {2,number}) "+ "despite the {4}''s efforts "+ "and to delight of {5}, {6}, {7}, {8}, {9}, and {10} {11}."; try { MessageFormat msg = new MessageFormat(pattern); final Object ARGS[] = { new Date(10000000000000L), new Integer(1303), new Integer(1202), new Double(1303.0/1202 - 1), "Glimmung", "the printers", "Nick", "his father", "his mother", "the spiddles", "of course", "Horace" }; String expected = "On Nov 20, 2286 (aka 11/20/86, aka November 20, 2286) "+ "at 9:46:40 AM (aka 9:46 AM, aka 9:46:40 AM PST) "+ "there were 1,303 werjes "+ "(a 8% increase over 1,202) "+ "despite the Glimmung's efforts "+ "and to delight of the printers, Nick, his father, "+ "his mother, the spiddles, and of course Horace."; assertEquals("format", expected, msg.format(ARGS)); } catch (IllegalArgumentException e1) { errln("FAIL: constructor failed"); } } // test RBNF extensions to message format public void TestRBNF() { // WARNING: this depends on the RBNF formats for en_US Locale locale = Locale.US; String[] values = { // decimal values do not format completely for ordinal or duration, and // do not always parse, so do not include them "0", "1", "12", "100", "123", "1001", "123,456", "-17", }; String[] formats = { "There are {0,spellout} files to search.", "There are {0,spellout,%simplified} files to search.", "The bogus spellout {0,spellout,%BOGUS} files behaves like the default.", "This is the {0,ordinal} file to search.", // TODO fix bug, ordinal does not parse "Searching this file will take {0,duration} to complete.", "Searching this file will take {0,duration,%with-words} to complete.", }; final NumberFormat numFmt = NumberFormat.getInstance(locale); Object[] args = new Object[1]; Number num = null; for (int i = 0; i < formats.length; ++i) { MessageFormat fmt = new MessageFormat(formats[i], locale); logln("Testing format pattern: '" + formats[i] + "'"); for (int j = 0; j < values.length; ++j) { try { num = numFmt.parse(values[j]); } catch (Exception e) { throw new IllegalStateException("failed to parse test argument"); } args[0] = num; String result = fmt.format(args); logln("value: " + num + " --> " + result); if (i != 3) { // TODO: fix this, for now skip ordinal parsing (format string at index 3) try { Object[] parsedArgs = fmt.parse(result); if (parsedArgs.length != 1) { errln("parse returned " + parsedArgs.length + " args"); } else if (!parsedArgs[0].equals(num)) { errln("parsed argument " + parsedArgs[0] + " != " + num); } } catch (Exception e) { errln("parse of '" + result + " returned exception: " + e.getMessage()); } } } } } public void TestSetGetFormats() { Object arguments[] = { new Double(456.83), new Date(871068000000L), "deposit" }; StringBuffer result = new StringBuffer(); String formatStr = "At