| // © 2016 and later: Unicode, Inc. and others. |
| // License & terms of use: http://www.unicode.org/copyright.html#License |
| /* |
| ********************************************************************** |
| * Copyright (c) 2004-2016, 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.Iterator; |
| import java.util.Locale; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.TreeMap; |
| |
| import org.junit.Test; |
| import org.junit.runner.RunWith; |
| import org.junit.runners.JUnit4; |
| |
| import com.ibm.icu.dev.test.TestFmwk; |
| 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.MessagePattern; |
| import com.ibm.icu.text.NumberFormat; |
| import com.ibm.icu.text.SimpleDateFormat; |
| import com.ibm.icu.text.UFormat; |
| import com.ibm.icu.util.Calendar; |
| import com.ibm.icu.util.GregorianCalendar; |
| import com.ibm.icu.util.TimeZone; |
| import com.ibm.icu.util.ULocale; |
| |
| @RunWith(JUnit4.class) |
| public class TestMessageFormat extends TestFmwk { |
| @Test |
| 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(FieldPosition_DONT_CARE); |
| 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."); |
| } |
| } |
| } |
| |
| @Test |
| 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)); |
| } |
| |
| @Test |
| 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<are {0, number} files} on disk {1}. "; |
| logln("The input pattern : " + pattern); |
| try { |
| MessageFormat fmt = new MessageFormat(pattern); |
| assertEquals("toPattern", pattern, fmt.toPattern()); |
| } catch (IllegalArgumentException e) { |
| errln("MessageFormat pattern creation failed."); |
| } |
| } |
| |
| @Test |
| public void TestPattern() // aka PatternTest() |
| { |
| Object testArgs[] = { |
| new Double(1), new Double(3456), |
| "Disk", new Date(1000000000L) |
| }; |
| String testCases[] = { |
| "Quotes '', '{', 'a' {0} '{0}'", |
| "Quotes '', '{', 'a' {0,number} '{0}'", |
| "'{'1,number,'#',##} {1,number,'#',##}", |
| "There are {1} files on {2} at {3}.", |
| "On {2}, there are {1} files, with {0,number,currency}.", |
| "'{1,number,percent}', {1,number,percent},", |
| "'{1,date,full}', {1,date,full},", |
| "'{3,date,full}', {3,date,full},", |
| "'{1,number,#,##}' {1,number,#,##}", |
| }; |
| |
| // ICU 4.8 returns the original pattern (testCases) |
| // rather than toPattern() reconstituting a new, equivalent pattern string (testResultPatterns). |
| /*String testResultPatterns[] = { |
| "Quotes '', '{', a {0} '{'0}", |
| "Quotes '', '{', a {0,number} '{'0}", |
| "'{'1,number,#,##} {1,number,'#'#,##}", |
| "There are {1} files on {2} at {3}.", |
| "On {2}, there are {1} files, with {0,number,currency}.", |
| "'{'1,number,percent}, {1,number,percent},", |
| "'{'1,date,full}, {1,date,full},", |
| "'{'3,date,full}, {3,date,full},", |
| "'{'1,number,#,##} {1,number,#,##}" |
| };*/ |
| |
| String testResultStrings[] = { |
| "Quotes ', {, 'a' 1 {0}", |
| "Quotes ', {, 'a' 1 {0}", |
| "{1,number,'#',##} #34,56", |
| "There are 3,456 files on Disk at 1/12/70, 5:46 AM.", |
| "On Disk, there are 3,456 files, with $1.00.", |
| "{1,number,percent}, 345,600%,", |
| "{1,date,full}, Wednesday, December 31, 1969,", |
| "{3,date,full}, Monday, January 12, 1970,", |
| "{1,number,#,##} 34,56" |
| }; |
| |
| for (int i = 0; i < 9; ++i) { |
| //it_out << "\nPat in: " << testCases[i]); |
| |
| //String buffer; |
| MessageFormat form = null; |
| try { |
| form = new MessageFormat(testCases[i], Locale.US); |
| } catch (IllegalArgumentException e1) { |
| errln("MessageFormat for " + testCases[i] + " creation failed."); |
| continue; |
| } |
| // ICU 4.8 returns the original pattern (testCases) |
| // rather than toPattern() reconstituting a new, equivalent pattern string (testResultPatterns). |
| // assertEquals("\"" + testCases[i] + "\".toPattern()", testResultPatterns[i], form.toPattern()); |
| assertEquals("\"" + testCases[i] + "\".toPattern()", testCases[i], form.toPattern()); |
| // Note: An alternative test would be to build MessagePattern objects for |
| // both the input and output patterns and compare them, taking SKIP_SYNTAX etc. |
| // into account. |
| // (Too much trouble...) |
| |
| //it_out << "Pat out: " << form.toPattern(buffer)); |
| StringBuffer result = new StringBuffer(); |
| FieldPosition fieldpos = new FieldPosition(FieldPosition_DONT_CARE); |
| form.format(testArgs, result, fieldpos); |
| assertEquals("format", testResultStrings[i], result.toString()); |
| |
| //it_out << "Result: " << result); |
| // /* TODO: Look at this test and see if this is still a valid test */ |
| // logln("---------------- test parse ----------------"); |
| // |
| // int count = 4; |
| // form.toPattern(buffer); |
| // logln("MSG pattern for parse: " + buffer); |
| // |
| // int parseCount = 0; |
| // Formattable* values = form.parse(result, parseCount, success); |
| // if (U_FAILURE(success)) { |
| // errln("MessageFormat failed test #5"); |
| // logln(String("MessageFormat failed test #5 with error code ")+(int)success); |
| // } else if (parseCount != count) { |
| // errln("MSG count not %d as expected. Got %d", count, parseCount); |
| // } |
| // UBool failed = FALSE; |
| // for (int j = 0; j < parseCount; ++j) { |
| // if (values == 0 || testArgs[j] != values[j]) { |
| // errln(((String)"MSG testargs[") + j + "]: " + toString(testArgs[j])); |
| // errln(((String)"MSG values[") + j + "] : " + toString(values[j])); |
| // failed = TRUE; |
| // } |
| // } |
| // if (failed) |
| // errln("MessageFormat failed test #6"); |
| } |
| } |
| |
| @Test |
| public void TestSample() // aka sample() |
| { |
| MessageFormat form = null; |
| StringBuffer buffer2 = new StringBuffer(); |
| try { |
| form = new MessageFormat("There are {0} files on {1}"); |
| } catch (IllegalArgumentException e1) { |
| errln("Sample message format creation failed."); |
| return; |
| } |
| Object testArgs1[] = { "abc", "def" }; |
| FieldPosition fieldpos = new FieldPosition(FieldPosition_DONT_CARE); |
| assertEquals("format", |
| "There are abc files on def", |
| form.format(testArgs1, buffer2, fieldpos).toString()); |
| } |
| |
| @Test |
| public void TestStaticFormat() |
| { |
| Object arguments[] = { |
| new Integer(7), |
| new Date(871068000000L), |
| "a disturbance in the Force" |
| }; |
| |
| assertEquals("format", |
| "At 12:20:00 PM on Aug 8, 1997, there was a disturbance in the Force on planet 7.", |
| MessageFormat.format("At {1,time} on {1,date}, there was {2} on planet {0,number,integer}.", |
| arguments)); |
| } |
| |
| static final int FieldPosition_DONT_CARE = -1; |
| |
| @Test |
| public void TestSimpleFormat() |
| { |
| Object testArgs1[] = {new Integer(0), "MyDisk"}; |
| Object testArgs2[] = {new Integer(1), "MyDisk"}; |
| Object testArgs3[] = {new Integer(12), "MyDisk"}; |
| |
| MessageFormat form = new MessageFormat( |
| "The disk \"{1}\" contains {0} file(s)."); |
| |
| StringBuffer string = new StringBuffer(); |
| FieldPosition ignore = new FieldPosition(FieldPosition_DONT_CARE); |
| form.format(testArgs1, string, ignore); |
| assertEquals("format", |
| "The disk \"MyDisk\" contains 0 file(s).", |
| string.toString()); |
| |
| string.setLength(0); |
| form.format(testArgs2, string, ignore); |
| assertEquals("format", |
| "The disk \"MyDisk\" contains 1 file(s).", |
| string.toString()); |
| |
| string.setLength(0); |
| form.format(testArgs3, string, ignore); |
| assertEquals("format", |
| "The disk \"MyDisk\" contains 12 file(s).", |
| string.toString()); |
| } |
| |
| @Test |
| public void TestMsgFormatChoice() |
| { |
| MessageFormat form = new MessageFormat("The disk \"{1}\" contains {0}."); |
| double filelimits[] = {0,1,2}; |
| String filepart[] = {"no files","one file","{0,number} files"}; |
| ChoiceFormat fileform = new ChoiceFormat(filelimits, filepart); |
| form.setFormat(1, fileform); // NOT zero, see below |
| |
| FieldPosition ignore = new FieldPosition(FieldPosition_DONT_CARE); |
| StringBuffer string = new StringBuffer(); |
| Object testArgs1[] = {new Integer(0), "MyDisk"}; |
| form.format(testArgs1, string, ignore); |
| assertEquals("format#1", |
| "The disk \"MyDisk\" contains no files.", |
| string.toString()); |
| |
| string.setLength(0); |
| Object testArgs2[] = {new Integer(1), "MyDisk"}; |
| form.format(testArgs2, string, ignore); |
| assertEquals("format#2", |
| "The disk \"MyDisk\" contains one file.", |
| string.toString()); |
| |
| string.setLength(0); |
| Object testArgs3[] = {new Integer(1273), "MyDisk"}; |
| form.format(testArgs3, string, ignore); |
| assertEquals("format#3", |
| "The disk \"MyDisk\" contains 1,273 files.", |
| string.toString()); |
| } |
| |
| //--------------------------------- |
| // API Tests |
| //--------------------------------- |
| |
| @Test |
| public void TestClone() |
| { |
| MessageFormat x = new MessageFormat("There are {0} files on {1}"); |
| MessageFormat z = new MessageFormat("There are {0} files on {1} created"); |
| MessageFormat y = null; |
| y = (MessageFormat)x.clone(); |
| if (x.equals(y) && |
| !x.equals(z) && |
| !y.equals(z) ) |
| logln("First test (operator ==): Passed!"); |
| else { |
| errln("First test (operator ==): Failed!"); |
| } |
| if ((x.equals(y) && y.equals(x)) && |
| (!x.equals(z) && !z.equals(x)) && |
| (!y.equals(z) && !z.equals(y)) ) |
| logln("Second test (equals): Passed!"); |
| else { |
| errln("Second test (equals): Failed!"); |
| } |
| |
| } |
| |
| @Test |
| public void TestEquals() |
| { |
| MessageFormat x = new MessageFormat("There are {0} files on {1}"); |
| MessageFormat y = new MessageFormat("There are {0} files on {1}"); |
| if (!x.equals(y)) { |
| errln("First test (operator ==): Failed!"); |
| } |
| |
| } |
| |
| @Test |
| public void TestNotEquals() |
| { |
| MessageFormat x = new MessageFormat("There are {0} files on {1}"); |
| MessageFormat y = new MessageFormat("There are {0} files on {1}"); |
| y.setLocale(Locale.FRENCH); |
| if (x.equals(y)) { |
| errln("First test (operator !=): Failed!"); |
| } |
| y = new MessageFormat("There are {0} files on {1}"); |
| y.applyPattern("There are {0} files on {1} the disk"); |
| if (x.equals(y)) { |
| errln("Second test (operator !=): Failed!"); |
| } |
| } |
| |
| @Test |
| public void TestHashCode() |
| { |
| ULocale save = ULocale.getDefault(); |
| ULocale.setDefault(ULocale.US); |
| |
| MessageFormat x = new MessageFormat("There are {0} files on {1}"); |
| MessageFormat z = new MessageFormat("There are {0} files on {1}"); |
| MessageFormat y = null; |
| y = (MessageFormat)x.clone(); |
| if (x.hashCode() != y.hashCode()) |
| errln("FAIL: identical objects have different hashcodes"); |
| if (x.hashCode() != z.hashCode()) |
| errln("FAIL: identical objects have different hashcodes"); |
| |
| /* These are not errors |
| y.setLocale(ULocale.FRENCH); |
| if (x.hashCode() == y.hashCode()) |
| errln("FAIL: different objects have same hashcodes. Locale ignored"); |
| |
| z.applyPattern("There are {0} files on {1} the disk"); |
| if (x.hashCode() == z.hashCode()) |
| errln("FAIL: different objects have same hashcodes. Pattern ignored"); |
| */ |
| |
| ULocale.setDefault(save); |
| } |
| |
| @Test |
| public void TestSetLocale() |
| { |
| Object arguments[] = { |
| new Double(456.83), |
| new Date(871068000000L), |
| "deposit" |
| }; |
| |
| StringBuffer result = new StringBuffer(); |
| |
| //String formatStr = "At {1,time} on {1,date}, you made a {2} of {0,number,currency}."; |
| String formatStr = "At <time> on {1,date}, you made a {2} of {0,number,currency}."; |
| // {sfb} to get $, would need Locale::US, not Locale::ENGLISH |
| // Just use unlocalized currency symbol. |
| // ICU 62: use the unknown currency symbol XXX. |
| //String compareStrEng = "At <time> on Aug 8, 1997, you made a deposit of $456.83."; |
| String compareStrEng = "At <time> on Aug 8, 1997, you made a deposit of "; |
| compareStrEng += "\u00a4"; |
| compareStrEng += "456.83."; |
| // {sfb} to get DM, would need Locale::GERMANY, not Locale::GERMAN |
| // Just use unlocalized currency symbol. |
| //String compareStrGer = "At <time> on 08.08.1997, you made a deposit of 456,83 DM."; |
| String compareStrGer = "At <time> on 08.08.1997, you made a deposit of "; |
| compareStrGer += "456,83\u00a0"; |
| compareStrGer += "XXX"; |
| compareStrGer += "."; |
| |
| MessageFormat msg = new MessageFormat(formatStr, Locale.ENGLISH); |
| result.setLength(0); |
| FieldPosition pos = new FieldPosition(FieldPosition_DONT_CARE); |
| result = msg.format( |
| arguments, |
| result, |
| pos); |
| assertEquals("format", compareStrEng, result.toString()); |
| |
| msg.setLocale(Locale.ENGLISH); |
| assertEquals("getLocale", Locale.ENGLISH, msg.getLocale()); |
| |
| msg.setLocale(Locale.GERMAN); |
| assertEquals("getLocale", Locale.GERMAN, msg.getLocale()); |
| |
| msg.applyPattern(formatStr); |
| result.setLength(0); |
| result = msg.format( |
| arguments, |
| result, |
| pos); |
| assertEquals("format", compareStrGer, result.toString()); |
| |
| //Cover getULocale() |
| logln("Testing set/get ULocale ..."); |
| msg.setLocale(ULocale.ENGLISH); |
| assertEquals("getULocale", ULocale.ENGLISH, msg.getULocale()); |
| |
| msg.setLocale(ULocale.GERMAN); |
| assertEquals("getULocale", ULocale.GERMAN, msg.getULocale()); |
| |
| msg.applyPattern(formatStr); |
| result.setLength(0); |
| result = msg.format( |
| arguments, |
| result, |
| pos); |
| assertEquals("format", compareStrGer, result.toString()); |
| } |
| |
| @SuppressWarnings("static-access") |
| @Test |
| public void TestFormat() |
| { |
| final Object ft_arr[] = |
| { |
| new Date(871068000000L) |
| }; |
| |
| StringBuffer result = new StringBuffer(); |
| |
| //String formatStr = "At {1,time} on {1,date}, you made a {2} of {0,number,currency}."; |
| String formatStr = "On {0,date}, it began."; |
| String compareStr = "On Aug 8, 1997, it began."; |
| |
| MessageFormat msg = new MessageFormat(formatStr); |
| FieldPosition fp = new FieldPosition(FieldPosition_DONT_CARE); |
| |
| try { |
| msg.format(new Date(871068000000L), |
| result, |
| fp); |
| errln("*** MSG format without expected error code."); |
| } catch (Exception e1) { |
| } |
| |
| result.setLength(0); |
| result = msg.format( |
| ft_arr, |
| result, |
| fp); |
| assertEquals("format", compareStr, result.toString()); |
| |
| Map<String,Object> map = new HashMap<String,Object>(); |
| try{ |
| msg.format("", map); |
| } catch(Exception e){ |
| errln("MessageFormat.format(String,Map) was not suppose to return " + |
| "an exception."); |
| } |
| } |
| |
| @Test |
| 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] |
| */ |
| @Test |
| 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()); |
| // ICU 4.8 does not support toPattern() when there are custom formats (from setFormat() etc.). |
| // assertEquals("msg.toPattern()", formatStr, msg.toPattern()); |
| try { |
| msg.toPattern(); |
| errln("msg.setFormat().toPattern() does not throw an IllegalStateException"); |
| } catch(IllegalStateException e) { |
| // ok |
| } |
| |
| 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()); |
| // ICU 4.8 does not support toPattern() when there are custom formats (from setFormat() etc.). |
| // 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()); |
| // ICU 4.8 does not support toPattern() when there are custom formats (from setFormat() etc.). |
| // 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. |
| */ |
| @Test |
| 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 |
| @Test |
| 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 (ParseException e) { |
| errln("parse of '" + result + "' returned exception: " |
| + e.getMessage() + " " + e.getErrorOffset()); |
| } |
| } |
| } |
| } |
| } |
| |
| @Test |
| public void TestSetGetFormats() |
| { |
| Object arguments[] = { |
| new Double(456.83), |
| new Date(871068000000L), |
| "deposit" |
| }; |
| |
| StringBuffer result = new StringBuffer(); |
| |
| String formatStr = "At <time> on {1,date}, you made a {2} of {0,number,currency}."; |
| // original expected format result |
| String compareStr = "At <time> on Aug 8, 1997, you made a deposit of $456.83."; |
| // the date being German-style, but the currency being English-style |
| String compareStr2 = "At <time> on 08.08.1997, you made a deposit of "; |
| compareStr2 += "\u00A4"; |
| compareStr2 += "456.83."; |
| // both date and currency formats are German-style |
| String compareStr3 = "At <time> on 08.08.1997, you made a deposit of "; |
| compareStr3 += "456,83\u00a0"; |
| compareStr3 += "XXX"; |
| compareStr3 += "."; |
| |
| MessageFormat msg = new MessageFormat(formatStr, ULocale.US); |
| result.setLength(0); |
| FieldPosition pos = new FieldPosition(FieldPosition_DONT_CARE); |
| result = msg.format( |
| arguments, |
| result, |
| pos); |
| assertEquals("format", compareStr, result.toString()); |
| |
| // constructs a Format array with a English-style Currency formatter |
| // and a German-style Date formatter |
| // might not meaningful, just for testing setFormatsByArgIndex |
| Format[] fmts = new Format[] { |
| NumberFormat.getCurrencyInstance(ULocale.ENGLISH), |
| DateFormat.getDateInstance(DateFormat.DEFAULT, ULocale.GERMAN) |
| }; |
| |
| msg.setFormatsByArgumentIndex(fmts); |
| result.setLength(0); |
| pos = new FieldPosition(FieldPosition_DONT_CARE); |
| result = msg.format( |
| arguments, |
| result, |
| pos); |
| assertEquals("format", compareStr2, result.toString()); |
| |
| // Construct a German-style Currency formatter, replace the corresponding one |
| // Thus both formatters should format objects with German-style |
| Format newFmt = NumberFormat.getCurrencyInstance(ULocale.GERMAN); |
| msg.setFormatByArgumentIndex(0, newFmt); |
| result.setLength(0); |
| pos = new FieldPosition(FieldPosition_DONT_CARE); |
| result = msg.format( |
| arguments, |
| result, |
| pos); |
| assertEquals("format", compareStr3, result.toString()); |
| |
| // verify getFormatsByArgumentIndex |
| // you should got three formats by that |
| // - DecimalFormat locale: de |
| // - SimpleDateFormat locale: de |
| // - null |
| Format[] fmts2 = msg.getFormatsByArgumentIndex(); |
| assertEquals("1st subformmater: Format Class", "com.ibm.icu.text.DecimalFormat", fmts2[0].getClass().getName()); |
| assertEquals("1st subformmater: its Locale", ULocale.GERMAN, ((UFormat)fmts2[0]).getLocale(ULocale.VALID_LOCALE)); |
| assertEquals("2nd subformatter: Format Class", "com.ibm.icu.text.SimpleDateFormat", fmts2[1].getClass().getName()); |
| assertEquals("2nd subformmater: its Locale", ULocale.GERMAN, ((UFormat)fmts2[1]).getLocale(ULocale.VALID_LOCALE)); |
| assertTrue("The third subFormatter is null", null == fmts2[2]); |
| } |
| |
| // Test the fix pattern api |
| @Test |
| public void TestAutoQuoteApostrophe() { |
| final String[] patterns = { // new pattern, expected pattern |
| "'", "''", |
| "''", "''", |
| "'{", "'{'", |
| "' {", "'' {", |
| "'a", "''a", |
| "'{'a", "'{'a", |
| "'{a'", "'{a'", |
| "'{}", "'{}'", |
| "{'", "{'", |
| "{'a", "{'a", |
| "{'a{}'a}'a", "{'a{}'a}''a", |
| "'}'", "'}'", |
| "'} '{'}'", "'} '{'}''", |
| "'} {{{''", "'} {{{'''", |
| }; |
| for (int i = 0; i < patterns.length; i += 2) { |
| assertEquals("[" + (i/2) + "] \"" + patterns[i] + "\"", patterns[i+1], MessageFormat.autoQuoteApostrophe(patterns[i])); |
| } |
| } |
| |
| // This tests passing named arguments instead of numbers to format(). |
| @Test |
| public void testFormatNamedArguments() { |
| Map arguments = new HashMap(); |
| arguments.put("startDate", new Date(871068000000L)); |
| |
| StringBuffer result = new StringBuffer(); |
| |
| String formatStr = "On {startDate,date}, it began."; |
| String compareStr = "On Aug 8, 1997, it began."; |
| |
| MessageFormat msg = new MessageFormat(formatStr); |
| FieldPosition fp = new FieldPosition(FieldPosition_DONT_CARE); |
| |
| try { |
| msg.format(arguments.get("startDate"), result, fp); |
| errln("*** MSG format without expected error code."); |
| } catch (Exception e1) { |
| } |
| |
| result.setLength(0); |
| result = msg.format( |
| arguments, |
| result, |
| fp); |
| assertEquals("format", compareStr, result.toString()); |
| } |
| |
| // This tests parsing formatted messages with named arguments instead of |
| // numbers. |
| @Test |
| public void testParseNamedArguments() { |
| String msgFormatString = "{foo} =sep= {bar}"; |
| MessageFormat msg = new MessageFormat(msgFormatString); |
| String source = "abc =sep= def"; |
| |
| try { |
| Map fmt_map = msg.parseToMap(source); |
| if (fmt_map.keySet().size() != 2) { |
| errln("*** MSG parse (ustring, count, err) count err."); |
| } else { |
| assertEquals("parse()[0]", "abc", fmt_map.get("foo")); |
| assertEquals("parse()[1]", "def", fmt_map.get("bar")); |
| } |
| } catch (ParseException e1) { |
| errln("*** MSG parse (ustring, count, err) error."); |
| } |
| |
| ParsePosition pp = new ParsePosition(0); |
| Map fmt_map = msg.parseToMap(source, pp); |
| if (pp.getIndex()==0 || fmt_map==null) { |
| errln("*** MSG parse (ustring, parsepos., count) error."); |
| } else { |
| if (fmt_map.keySet().size() != 2) { |
| errln("*** MSG parse (ustring, parsepos., count) count err."); |
| } else { |
| assertEquals("parse()[0]", "abc", fmt_map.get("foo")); |
| assertEquals("parse()[1]", "def", fmt_map.get("bar")); |
| } |
| } |
| |
| pp.setIndex(0); |
| |
| Map fmta = (Map) msg.parseObject( source, pp ); |
| if (pp.getIndex() == 0) { |
| errln("*** MSG parse (ustring, Object, parsepos ) error."); |
| } else { |
| if (fmta.keySet().size() != 2) { |
| errln("*** MSG parse (ustring, count, err) count err."); |
| } else { |
| assertEquals("parse()[0]", "abc", fmta.get("foo")); |
| assertEquals("parse()[1]", "def", fmta.get("bar")); |
| } |
| } |
| } |
| |
| // Ensure that methods designed for numeric arguments only, will throw |
| // an exception when called on MessageFormat objects created with |
| // named arguments. |
| @Test |
| public void testNumericOnlyMethods() { |
| MessageFormat msg = new MessageFormat("Number of files: {numfiles}"); |
| boolean gotException = false; |
| try { |
| Format fmts[] = {new DecimalFormat()}; |
| msg.setFormatsByArgumentIndex(fmts); |
| } catch (IllegalArgumentException e) { |
| gotException = true; |
| } |
| if (!gotException) { |
| errln("MessageFormat.setFormatsByArgumentIndex() should throw an " + |
| "IllegalArgumentException when called on formats with " + |
| "named arguments but did not!"); |
| } |
| |
| gotException = false; |
| try { |
| msg.setFormatByArgumentIndex(0, new DecimalFormat()); |
| } catch (IllegalArgumentException e) { |
| gotException = true; |
| } |
| if (!gotException) { |
| errln("MessageFormat.setFormatByArgumentIndex() should throw an " + |
| "IllegalArgumentException when called on formats with " + |
| "named arguments but did not!"); |
| } |
| |
| gotException = false; |
| try { |
| msg.getFormatsByArgumentIndex(); |
| } catch (IllegalArgumentException e) { |
| gotException = true; |
| } |
| if (!gotException) { |
| errln("MessageFormat.getFormatsByArgumentIndex() should throw an " + |
| "IllegalArgumentException when called on formats with " + |
| "named arguments but did not!"); |
| } |
| |
| gotException = false; |
| try { |
| Object args[] = {new Long(42)}; |
| msg.format(args, new StringBuffer(), new FieldPosition(FieldPosition_DONT_CARE)); |
| } catch (IllegalArgumentException e) { |
| gotException = true; |
| } |
| if (!gotException) { |
| errln("MessageFormat.format(Object[], StringBuffer, FieldPosition) " + |
| "should throw an IllegalArgumentException when called on " + |
| "formats with named arguments but did not!"); |
| } |
| |
| gotException = false; |
| try { |
| Object args[] = {new Long(42)}; |
| msg.format((Object) args, new StringBuffer(), new FieldPosition(FieldPosition_DONT_CARE)); |
| } catch (IllegalArgumentException e) { |
| gotException = true; |
| } |
| if (!gotException) { |
| errln("MessageFormat.format(Object, StringBuffer, FieldPosition) " + |
| "should throw an IllegalArgumentException when called with " + |
| "non-Map object as argument on formats with named " + |
| "arguments but did not!"); |
| } |
| |
| gotException = false; |
| try { |
| msg.parse("Number of files: 5", new ParsePosition(0)); |
| } catch (IllegalArgumentException e) { |
| gotException = true; |
| } |
| if (!gotException) { |
| errln("MessageFormat.parse(String, ParsePosition) " + |
| "should throw an IllegalArgumentException when called with " + |
| "non-Map object as argument on formats with named " + |
| "arguments but did not!"); |
| } |
| |
| gotException = false; |
| try { |
| msg.parse("Number of files: 5"); |
| } catch (IllegalArgumentException e) { |
| gotException = true; |
| } catch (ParseException e) { |
| errln("Wrong exception thrown."); |
| } |
| if (!gotException) { |
| errln("MessageFormat.parse(String) " + |
| "should throw an IllegalArgumentException when called with " + |
| "non-Map object as argument on formats with named " + |
| "arguments but did not!"); |
| } |
| } |
| |
| @Test |
| public void testNamedArguments() { |
| // ICU 4.8 allows mixing named and numbered arguments. |
| assertTrue( |
| "has some named arguments", |
| new MessageFormat("Number of files in folder {0}: {numfiles}").usesNamedArguments()); |
| assertTrue( |
| "has some named arguments", |
| new MessageFormat("Number of files in folder {folder}: {1}").usesNamedArguments()); |
| |
| // Test named arguments. |
| MessageFormat mf = new MessageFormat("Number of files in folder {folder}: {numfiles}"); |
| if (!mf.usesNamedArguments()) { |
| errln("message format 1 should have used named arguments"); |
| } |
| mf = new MessageFormat("Wavelength: {\u028EValue\uFF14}"); |
| if (!mf.usesNamedArguments()) { |
| errln("message format 2 should have used named arguments"); |
| } |
| |
| // Test argument names with invalid start characters. |
| // Modified: ICU 4.8 allows all characters except for Pattern_White_Space and Pattern_Syntax. |
| try { |
| new MessageFormat("Wavelength: {^\u028EValue\uFF14}"); |
| errln("Creating a MessageFormat with invalid argument names " + |
| "should throw an IllegalArgumentException but did not!"); |
| } catch (IllegalArgumentException e) {} |
| |
| try { |
| new MessageFormat("Wavelength: {\uFE45\u028EValue}"); |
| errln("Creating a MessageFormat with invalid argument names " + |
| "should throw an IllegalArgumentException but did not!"); |
| } catch (IllegalArgumentException e) {} |
| |
| // Test argument names with invalid continue characters. |
| // Modified: ICU 4.8 allows all characters except for Pattern_White_Space and Pattern_Syntax. |
| try { |
| new MessageFormat("Wavelength: {Value@\uFF14}"); |
| errln("Creating a MessageFormat with invalid argument names " + |
| "should throw an IllegalArgumentException but did not!"); |
| } catch (IllegalArgumentException e) {} |
| |
| try { |
| new MessageFormat("Wavelength: {Value(\uFF14)}"); |
| errln("Creating a MessageFormat with invalid argument names " + |
| "should throw an IllegalArgumentException but did not!"); |
| } catch (IllegalArgumentException e) {} |
| } |
| |
| @Test |
| public void testNumericFormatWithMap() { |
| MessageFormat mf = new MessageFormat("X:{2} Y:{1}"); |
| if (mf.usesNamedArguments()) { |
| errln("should not use named arguments"); |
| } |
| |
| Map map12 = new HashMap(); |
| map12.put("1", "one"); |
| map12.put("2", "two"); |
| |
| String target = "X:two Y:one"; |
| String result = mf.format(map12); |
| if (!target.equals(result)) { |
| errln("expected '" + target + "' but got '" + result + "'"); |
| } |
| |
| try { |
| Map mapResult = mf.parseToMap(target); |
| if (!map12.equals(mapResult)) { |
| errln("expected " + map12 + " but got " + mapResult); |
| } |
| } catch (ParseException e) { |
| errln("unexpected exception: " + e.getMessage()); |
| } |
| |
| Map map10 = new HashMap(); |
| map10.put("1", "one"); |
| map10.put("0", "zero"); |
| target = "X:{2} Y:one"; |
| result = mf.format(map10); |
| if (!target.equals(result)) { |
| errln("expected '" + target + "' but got '" + result + "'"); |
| } |
| |
| DateFormat dateFormat = DateFormat.getDateInstance(DateFormat.MEDIUM); |
| DateFormat timeFormat = DateFormat.getTimeInstance(DateFormat.MEDIUM); |
| Map fmtMap = new HashMap(); |
| fmtMap.put("1", dateFormat); |
| fmtMap.put("2", timeFormat); |
| mf.setFormatsByArgumentName(fmtMap); |
| Date date = new Date(661439820000L); |
| |
| try { |
| result = mf.format(map12); // should fail, wrong argument type |
| fail("expected exception but got '" + result + "'"); |
| } catch (IllegalArgumentException e) { |
| // expect this |
| } |
| |
| Map argMap = new HashMap(); |
| argMap.put("1", date); |
| argMap.put("2", date); |
| target = "X:5:17:00 AM Y:Dec 17, 1990"; |
| result = mf.format(argMap); |
| if (!target.equals(result)) { |
| errln("expected '" + target + "' but got '" + result + "'"); |
| } |
| } |
| |
| // This tests nested Formats inside PluralFormat. |
| @Test |
| public void testNestedFormatsInPluralFormat() { |
| try { |
| MessageFormat msgFmt = new MessageFormat( |
| "{0, plural, one {{0, number,C''est #,##0.0# fichier}} " + |
| "other {Ce sont # fichiers}} dans la liste.", |
| new ULocale("fr")); |
| Object objArray[] = {new Long(0)}; |
| HashMap objMap = new HashMap(); |
| objMap.put("argument", objArray[0]); |
| String result = msgFmt.format(objArray); |
| if (!result.equals("C'est 0,0 fichier dans la liste.")) { |
| errln("PluralFormat produced wrong message string."); |
| } |
| } catch (Exception e) { |
| e.printStackTrace(); |
| throw new RuntimeException(e.getMessage()); |
| } |
| } |
| |
| // This tests PluralFormats used inside MessageFormats. |
| @Test |
| public void testPluralFormat() { |
| { |
| MessageFormat mfNum = new MessageFormat( |
| "{0, plural, one{C''est # fichier} other " + |
| "{Ce sont # fichiers}} dans la liste.", |
| new ULocale("fr")); |
| MessageFormat mfAlpha = new MessageFormat( |
| "{argument, plural, one{C''est # fichier} other {Ce " + |
| "sont # fichiers}} dans la liste.", |
| new ULocale("fr")); |
| Object objArray[] = {new Long(0)}; |
| HashMap objMap = new HashMap(); |
| objMap.put("argument", objArray[0]); |
| String result = mfNum.format(objArray); |
| if (!result.equals(mfAlpha.format(objMap))) { |
| errln("PluralFormat's output differs when using named " + |
| "arguments instead of numbers!"); |
| } |
| if (!result.equals("C'est 0 fichier dans la liste.")) { |
| errln("PluralFormat produced wrong message string."); |
| } |
| } |
| { |
| MessageFormat mfNum = new MessageFormat ( |
| "There {0, plural, one{is # zavod}few{are {0, " + |
| "number,###.0} zavoda} other{are # zavodov}} in the " + |
| "directory.", |
| new ULocale("uk")); |
| MessageFormat mfAlpha = new MessageFormat ( |
| "There {argument, plural, one{is # zavod}few{" + |
| "are {argument, number,###.0} zavoda} other{are # " + |
| "zavodov}} in the directory.", |
| new ULocale("uk")); |
| Object objArray[] = {new Long(4)}; |
| HashMap objMap = new HashMap(); |
| objMap.put("argument", objArray[0]); |
| String result = mfNum.format(objArray); |
| if (!result.equals(mfAlpha.format(objMap))) { |
| errln("PluralFormat's output differs when using named " + |
| "arguments instead of numbers!"); |
| } |
| if (!result.equals("There are 4,0 zavoda in the directory.")) { |
| errln("PluralFormat produced wrong message string."); |
| } |
| } |
| } |
| |
| @Test |
| public void testApostropheInPluralAndSelect() { |
| MessageFormat fmt = new MessageFormat( |
| "abc_{0,plural,other{#'#'#'{'#''}}_def_{1,select,other{sel'}'ect''}}_xyz", |
| Locale.ENGLISH); |
| String expected = "abc_3#3{3'_def_sel}ect'_xyz"; |
| String result = fmt.format(new Object[] { 3, "x" }); |
| if (!result.equals(expected)) { |
| errln("MessageFormat with apostrophes in plural/select arguments failed:\n" + |
| "Expected "+expected+"\n" + |
| "Got "+result); |
| } |
| } |
| |
| // Test toPattern when there is a PluralFormat |
| @Test |
| public void testPluralFormatToPattern() { |
| String[] patterns = { |
| "Beware of vicious {0, plural, one {hamster} other {hamsters}}.", |
| "{0, plural, one {{0, number,C''''est #,##0.0# fichier}} other {Ce sont # fichiers}} dans la liste.", |
| "{0, plural, one {C''est # fichier} other {Ce sont # fichiers}} dans la liste.", |
| }; |
| |
| for (int i = 0; i < patterns.length; ++i) { |
| String pattern = patterns[i]; |
| MessageFormat mf = new MessageFormat(pattern); |
| MessageFormat mf2 = new MessageFormat(mf.toPattern()); |
| if (!mf.equals(mf2)) { |
| errln("message formats not equal for pattern:\n*** '" + pattern + "'\n*** '" + |
| mf.toPattern() + "'"); |
| } |
| } |
| } |
| |
| /** |
| * This tests SelectFormats used inside MessageFormats. |
| */ |
| @Test |
| public void testSelectFormat() { |
| String pattern = null; |
| MessageFormat msgFmt = null ; |
| |
| //Create the MessageFormat with simple French pattern |
| pattern = "{0} est {1, select, female {all\\u00E9e} other {all\\u00E9}} \\u00E0 Paris."; |
| msgFmt = new MessageFormat(pattern); |
| assertNotNull( "ERROR:Failure in constructing with simple French pattern", msgFmt); |
| |
| //Format |
| Object testArgs[][] ={ |
| {"Kirti","female"} , |
| {"Victor","other"} , |
| {"Ash","unknown"} , |
| }; |
| String exp[] = { |
| "Kirti est all\\u00E9e \\u00E0 Paris." , |
| "Victor est all\\u00E9 \\u00E0 Paris.", |
| "Ash est all\\u00E9 \\u00E0 Paris." |
| }; |
| for ( int i=0; i< 3; i++){ |
| assertEquals("ERROR:Failure in format with simple French Pattern" , |
| exp[i] , msgFmt.format(testArgs[i]) ); |
| } |
| |
| //Create the MessageFormat with Quoted French Pattern |
| pattern = "{0} est {1, select, female {all\\u00E9e c''est} other {all\\u00E9 c''est}} \\u00E0 Paris."; |
| msgFmt = new MessageFormat(pattern); |
| assertNotNull( "ERROR:Failure in constructing with quoted French pattern", msgFmt); |
| |
| //Format |
| Object testArgs1[][] ={ |
| {"Kirti","female"} , |
| {"Victor","other"} , |
| {"Ash","male"} , |
| }; |
| String exp1[] = { |
| "Kirti est all\\u00E9e c'est \\u00E0 Paris." , |
| "Victor est all\\u00E9 c'est \\u00E0 Paris.", |
| "Ash est all\\u00E9 c'est \\u00E0 Paris." |
| }; |
| for ( int i=0; i< 3; i++){ |
| assertEquals("ERROR:Failure in format with quoted French Pattern" , |
| exp1[i] , msgFmt.format(testArgs1[i]) ); |
| } |
| |
| //Nested patterns with plural, number ,choice ,select format etc. |
| //Select Format with embedded number format |
| pattern = "{0} est {1, select, female {{2,number,integer} all\\u00E9e} other {all\\u00E9}} \\u00E0 Paris."; |
| msgFmt = new MessageFormat(pattern); |
| assertNotNull( "ERROR:Failure in constructing with nested pattern 1", msgFmt); |
| |
| //Format |
| Object testArgs3[][] ={ |
| {"Kirti", "female", 6} , |
| {"Kirti", "female", 100.100} , |
| {"Kirti", "other", 6} , |
| }; |
| String exp3[] = { |
| "Kirti est 6 all\\u00E9e \\u00E0 Paris." , |
| "Kirti est 100 all\\u00E9e \\u00E0 Paris.", |
| "Kirti est all\\u00E9 \\u00E0 Paris." |
| }; |
| |
| for ( int i=0; i< 3; i++){ |
| assertEquals("ERROR:Failure in format with nested Pattern 1" , |
| exp3[i] , msgFmt.format(testArgs3[i]) ); |
| } |
| |
| //Plural format with embedded select format |
| 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."; |
| msgFmt = new MessageFormat(pattern); |
| assertNotNull( "ERROR:Failure in constructing with nested pattern 2", msgFmt); |
| |
| //Format |
| Object testArgs4[][] ={ |
| {"Kirti",6,"female"}, |
| {"Kirti",1,"female"}, |
| {"Ash",1,"other"}, |
| {"Ash",5,"other"}, |
| }; |
| String exp4[] = { |
| "Kirti sont all\\u00E9es \\u00E0 Paris." , |
| "Kirti est all\\u00E9e \\u00E0 Paris.", |
| "Ash est all\\u00E9 \\u00E0 Paris.", |
| "Ash sont all\\u00E9s \\u00E0 Paris." |
| }; |
| for ( int i=0; i< 4; i++){ |
| assertEquals("ERROR:Failure in format with nested Pattern 2" , |
| exp4[i] , msgFmt.format(testArgs4[i]) ); |
| } |
| |
| //Select, plural, and number formats heavily nested |
| 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."; |
| msgFmt = new MessageFormat(pattern); |
| assertNotNull( "ERROR:Failure in constructing with nested pattern 3", msgFmt); |
| |
| //Format |
| Object testArgs5[][] ={ |
| {"Kirti","other",1,"other"}, |
| {"Kirti","other",6,"other"}, |
| {"Kirti","other",1,"female"}, |
| {"Kirti","other",3,"female"}, |
| {"Kirti","female",1,"female"}, |
| {"Kirti","female",5,"female"}, |
| {"Kirti","female",1,"other"}, |
| {"Kirti","female",5,"other"}, |
| {"Kirti","mixed",1,"mixed"}, |
| {"Kirti","mixed",1,"other"}, |
| {"Kirti","female",1,"mixed"}, |
| {"Kirti","mixed",5,"mixed"}, |
| {"Kirti","mixed",5,"other"}, |
| {"Kirti","female",5,"mixed"}, |
| }; |
| String exp5[] = { |
| "Kirti und sein Freund gingen nach Paris." , |
| "Kirti und seine 6 Freunde gingen nach Paris." , |
| "Kirti und seine Freundin gingen nach Paris.", |
| "Kirti und seine 3 Freundinnen gingen nach Paris.", |
| "Kirti und ihre Freundin gingen nach Paris.", |
| "Kirti und ihre 5 Freundinnen gingen nach Paris.", |
| "Kirti und ihr Freund gingen nach Paris.", |
| "Kirti und ihre 5 Freunde gingen nach Paris.", |
| "Kirti und sein Freund gingen nach Paris.", |
| "Kirti und sein Freund gingen nach Paris.", |
| "Kirti und ihr Freund gingen nach Paris.", |
| "Kirti und seine 5 Freunde gingen nach Paris." , |
| "Kirti und seine 5 Freunde gingen nach Paris." , |
| "Kirti und ihre 5 Freunde gingen nach Paris." |
| }; |
| //Format |
| for ( int i=0; i< 14; i++){ |
| assertEquals("ERROR:Failure in format with nested Pattern 3" , |
| exp5[i] , msgFmt.format(testArgs5[i]) ); |
| } |
| } |
| |
| /** |
| * Test toPattern when there is a SelectFormat |
| */ |
| @Test |
| public void testSelectFormatToPattern() { |
| String[] patterns = { |
| //Pattern with some text at start and at end |
| "{0} est {1,select, female {all\\u00E9e} other {all\\u00E9}} \\u00E0 Paris.", |
| //Pattern with some text at start |
| "{0} est {1,select, female {all\\u00E9e} other {all\\u00E9}}", |
| //Pattern with some text at end |
| "{1, select,female {all\\u00E9e} other {all\\u00E9}} \\u00E0 Paris.", |
| //Pattern with no text at any end |
| "{1, select,female {all\\u00E9e} other {all\\u00E9}}.", |
| //Quoted French pattern |
| "{0} est {1,select, female {all\\u00E9e c''est} other {all\\u00E9 c''est}} \\u00E0 Paris.", |
| }; |
| |
| for (int i = 0; i < patterns.length; ++i) { |
| String pattern = patterns[i]; |
| MessageFormat mf = new MessageFormat(pattern); |
| MessageFormat mf2 = new MessageFormat(mf.toPattern()); |
| if (!mf.equals(mf2)) { |
| errln("message formats not equal for pattern:\n*** '" |
| + pattern + "'\n*** '" + mf.toPattern() + "'"); |
| } |
| } |
| } |
| |
| // Test case for null arguments. |
| // Ticket#6361 |
| @Test |
| public void TestNullArgs() { |
| MessageFormat msgfmt = new MessageFormat("{0} - {1}"); |
| Object[][] TEST_CASES = { |
| {null, "{0} - {1}"}, |
| {new Object[] {null}, "null - {1}"}, |
| {new Object[] {null, null}, "null - null"}, |
| {new Object[] {"one"}, "one - {1}"}, |
| {new Object[] {"one", null}, "one - null"}, |
| {new Object[] {null, "two"}, "null - two"}, |
| }; |
| |
| for (int i = 0; i < TEST_CASES.length; i++) { |
| String text = msgfmt.format(TEST_CASES[i][0]); |
| if (!text.equals(TEST_CASES[i][1])) { |
| errln("FAIL: Returned[" + text + "] Expected[" + TEST_CASES[i][1] + "]"); |
| } |
| } |
| } |
| |
| @Test |
| public void TestSetFormat() { |
| MessageFormat ms = new MessageFormat("{number} {date}", ULocale.ENGLISH); |
| final DecimalFormat decimalFormat = new DecimalFormat("000.000", DecimalFormatSymbols.getInstance(ULocale.ENGLISH)); |
| ms.setFormatByArgumentName("number", decimalFormat); |
| final SimpleDateFormat dateFormat = new SimpleDateFormat("'year:'yy 'month:'MM 'day:'dd"); |
| dateFormat.setTimeZone(TimeZone.getTimeZone("Etc/GMT")); |
| ms.setFormatByArgumentName("date", dateFormat); |
| Map map = new HashMap(); |
| map.put("number", new Integer(1234)); |
| map.put("date", new Date(0,0,0)); |
| String result = ms.format(map); |
| assertEquals("setFormatByArgumentName", "1234.000 year:99 month:12 day:31", result); |
| Set formatNames = ms.getArgumentNames(); |
| assertEquals("Format Names match", formatNames, map.keySet()); |
| assertEquals("Decimal", decimalFormat, ms.getFormatByArgumentName("number")); |
| assertEquals("Date", dateFormat, ms.getFormatByArgumentName("date")); |
| } |
| |
| // Test case for formatToCharacterIterator |
| @Test |
| public void TestFormatToCharacterIterator() { |
| MessageFormat[] msgfmts = { |
| new MessageFormat( |
| "The {3,ordinal} folder ''{0}'' contains {2,number} file(s), created at {1,time} on {1,date}."), |
| new MessageFormat( |
| "The {arg3,ordinal} folder ''{arg0}'' contains {arg2,number} file(s), created at {arg1,time} on {arg1,date}."), // same |
| // as |
| // above, |
| // but |
| // named |
| // args |
| new MessageFormat("The folder contains {0}.") }; |
| |
| double filelimits[] = { 0, 1, 2 }; |
| String filepart[] = { "no files", "one file", "{0,number} files" }; |
| ChoiceFormat fileform = new ChoiceFormat(filelimits, filepart); |
| msgfmts[2].setFormat(0, fileform); |
| |
| Object[] args0 = new Object[] { "tmp", new Date(1184777888000L), new Integer(15), new Integer(2) }; |
| |
| HashMap args1 = new HashMap(); |
| args1.put("arg0", "tmp"); |
| args1.put("arg1", new Date(1184777888000L)); |
| args1.put("arg2", new Integer(15)); |
| args1.put("arg3", new Integer(2)); |
| |
| Object[] args2 = new Object[] { new Integer(34) }; |
| |
| Object[] args = { args0, args1, args2 }; |
| |
| String[] expectedStrings = { |
| "The 2nd folder 'tmp' contains 15 file(s), created at 9:58:08 AM on Jul 18, 2007.", |
| "The 2nd folder 'tmp' contains 15 file(s), created at 9:58:08 AM on Jul 18, 2007.", |
| "The folder contains 34 files." }; |
| |
| AttributedString[] expectedAttributedStrings = { new AttributedString(expectedStrings[0]), |
| new AttributedString(expectedStrings[1]), new AttributedString(expectedStrings[2]) }; |
| |
| // Add expected attributes to the expectedAttributedStrings[0] |
| expectedAttributedStrings[0].addAttribute(MessageFormat.Field.ARGUMENT, new Integer(3), 4, 7); |
| expectedAttributedStrings[0].addAttribute(MessageFormat.Field.ARGUMENT, new Integer(0), 16, 19); |
| expectedAttributedStrings[0].addAttribute(MessageFormat.Field.ARGUMENT, new Integer(2), 30, 32); |
| expectedAttributedStrings[0].addAttribute(NumberFormat.Field.INTEGER, NumberFormat.Field.INTEGER, 30, 32); |
| expectedAttributedStrings[0].addAttribute(MessageFormat.Field.ARGUMENT, new Integer(1), 53, 63); |
| expectedAttributedStrings[0].addAttribute(DateFormat.Field.HOUR1, DateFormat.Field.HOUR1, 53, 54); |
| //expectedAttributedStrings[0].addAttribute(DateFormat.Field.TIME_SEPARATOR, DateFormat.Field.TIME_SEPARATOR, 54, 55); |
| expectedAttributedStrings[0].addAttribute(DateFormat.Field.MINUTE, DateFormat.Field.MINUTE, 55, 57); |
| //expectedAttributedStrings[0].addAttribute(DateFormat.Field.TIME_SEPARATOR, DateFormat.Field.TIME_SEPARATOR, 57, 58); |
| expectedAttributedStrings[0].addAttribute(DateFormat.Field.SECOND, DateFormat.Field.SECOND, 58, 60); |
| expectedAttributedStrings[0].addAttribute(DateFormat.Field.AM_PM, DateFormat.Field.AM_PM, 61, 63); |
| expectedAttributedStrings[0].addAttribute(MessageFormat.Field.ARGUMENT, new Integer(1), 67, 79); |
| expectedAttributedStrings[0].addAttribute(DateFormat.Field.MONTH, DateFormat.Field.MONTH, 67, 70); |
| expectedAttributedStrings[0].addAttribute(DateFormat.Field.DAY_OF_MONTH, DateFormat.Field.DAY_OF_MONTH, 71, 73); |
| expectedAttributedStrings[0].addAttribute(DateFormat.Field.YEAR, DateFormat.Field.YEAR, 75, 79); |
| |
| // Add expected attributes to the expectedAttributedStrings[1] |
| expectedAttributedStrings[1].addAttribute(MessageFormat.Field.ARGUMENT, "arg3", 4, 7); |
| expectedAttributedStrings[1].addAttribute(MessageFormat.Field.ARGUMENT, "arg0", 16, 19); |
| expectedAttributedStrings[1].addAttribute(MessageFormat.Field.ARGUMENT, "arg2", 30, 32); |
| expectedAttributedStrings[1].addAttribute(NumberFormat.Field.INTEGER, NumberFormat.Field.INTEGER, 30, 32); |
| expectedAttributedStrings[1].addAttribute(MessageFormat.Field.ARGUMENT, "arg1", 53, 63); |
| expectedAttributedStrings[1].addAttribute(DateFormat.Field.HOUR1, DateFormat.Field.HOUR1, 53, 54); |
| //expectedAttributedStrings[1].addAttribute(DateFormat.Field.TIME_SEPARATOR, DateFormat.Field.TIME_SEPARATOR, 54, 55); |
| expectedAttributedStrings[1].addAttribute(DateFormat.Field.MINUTE, DateFormat.Field.MINUTE, 55, 57); |
| //expectedAttributedStrings[1].addAttribute(DateFormat.Field.TIME_SEPARATOR, DateFormat.Field.TIME_SEPARATOR, 57, 58); |
| expectedAttributedStrings[1].addAttribute(DateFormat.Field.SECOND, DateFormat.Field.SECOND, 58, 60); |
| expectedAttributedStrings[1].addAttribute(DateFormat.Field.AM_PM, DateFormat.Field.AM_PM, 61, 63); |
| expectedAttributedStrings[1].addAttribute(MessageFormat.Field.ARGUMENT, "arg1", 67, 79); |
| expectedAttributedStrings[1].addAttribute(DateFormat.Field.MONTH, DateFormat.Field.MONTH, 67, 70); |
| expectedAttributedStrings[1].addAttribute(DateFormat.Field.DAY_OF_MONTH, DateFormat.Field.DAY_OF_MONTH, 71, 73); |
| expectedAttributedStrings[1].addAttribute(DateFormat.Field.YEAR, DateFormat.Field.YEAR, 75, 79); |
| |
| // Add expected attributes to the expectedAttributedStrings[2] |
| expectedAttributedStrings[2].addAttribute(MessageFormat.Field.ARGUMENT, new Integer(0), 20, 28); |
| expectedAttributedStrings[2].addAttribute(NumberFormat.Field.INTEGER, NumberFormat.Field.INTEGER, 20, 22); |
| |
| for (int i = 0; i < msgfmts.length; i++) { |
| AttributedCharacterIterator acit = msgfmts[i].formatToCharacterIterator(args[i]); |
| AttributedCharacterIterator expectedAcit = expectedAttributedStrings[i].getIterator(); |
| |
| // Check available attributes |
| Set attrSet = acit.getAllAttributeKeys(); |
| Set expectedAttrSet = expectedAcit.getAllAttributeKeys(); |
| if (attrSet.size() != expectedAttrSet.size()) { |
| errln("FAIL: Number of attribute keys is " + attrSet.size() + " expected: " + expectedAttrSet.size()); |
| } |
| Iterator attrIterator = attrSet.iterator(); |
| while (attrIterator.hasNext()) { |
| AttributedCharacterIterator.Attribute attr = (AttributedCharacterIterator.Attribute) attrIterator |
| .next(); |
| if (!expectedAttrSet.contains(attr)) { |
| errln("FAIL: The attribute " + attr + " is not expected."); |
| } |
| } |
| |
| StringBuffer buf = new StringBuffer(); |
| int index = acit.getBeginIndex(); |
| int end = acit.getEndIndex(); |
| int indexExp = expectedAcit.getBeginIndex(); |
| int expectedLen = expectedAcit.getEndIndex() - indexExp; |
| if (end - index != expectedLen) { |
| errln("FAIL: Length of the result attributed string is " + (end - index) + " expected: " + expectedLen); |
| } else { |
| // Check attributes associated with each character |
| while (index < end) { |
| char c = acit.setIndex(index); |
| buf.append(c); |
| expectedAcit.setIndex(indexExp); |
| |
| Map attrs = acit.getAttributes(); |
| Map attrsExp = expectedAcit.getAttributes(); |
| if (attrs.size() != attrsExp.size()) { |
| errln("FAIL: Number of attributes associated with index " + index + " is " + attrs.size() |
| + " expected: " + attrsExp.size()); |
| } else { |
| // Check all attributes at the index |
| Iterator entryIterator = attrsExp.entrySet().iterator(); |
| while (entryIterator.hasNext()) { |
| Map.Entry entry = (Map.Entry) entryIterator.next(); |
| if (attrs.containsKey(entry.getKey())) { |
| Object value = attrs.get(entry.getKey()); |
| assertEquals("Attribute value at index " + index, entry.getValue(), value); |
| } else { |
| errln("FAIL: Attribute " + entry.getKey() + " is missing at index " + index); |
| } |
| } |
| } |
| index++; |
| indexExp++; |
| } |
| assertEquals("AttributedString contents", expectedStrings[i], buf.toString()); |
| } |
| } |
| |
| // Tests when "if (arguments == null)" is true |
| try { |
| MessageFormat mf = new MessageFormat(""); |
| mf.formatToCharacterIterator(null); |
| errln("MessageFormat.formatToCharacterIterator(Object) was suppose " |
| + "to return an exception when null is passed."); |
| } catch (Exception e) { |
| } |
| } |
| |
| /* |
| * Tests the method public Format getFormatByArgumentName(String argumentName) |
| */ |
| @Test |
| public void TestGetFormatByArgumentName() { |
| MessageFormat mf = new MessageFormat(""); |
| if (mf.getFormatByArgumentName("") != null) { |
| errln("MessageFormat.getFormatByArgumentName(String) was suppose " |
| + "to return an null if argumentName was not found."); |
| } |
| } |
| |
| public String getPatternAndSkipSyntax(MessagePattern pattern) { |
| StringBuilder sb = new StringBuilder(pattern.getPatternString()); |
| int count = pattern.countParts(); |
| for (int i = count; i > 0;) { |
| MessagePattern.Part part = pattern.getPart(--i); |
| if (part.getType() == MessagePattern.Part.Type.SKIP_SYNTAX) { |
| sb.delete(part.getIndex(), part.getLimit()); |
| } |
| } |
| return sb.toString(); |
| } |
| |
| @Test |
| public void TestApostropheMode() { |
| MessagePattern ado_mp = new MessagePattern(MessagePattern.ApostropheMode.DOUBLE_OPTIONAL); |
| MessagePattern adr_mp = new MessagePattern(MessagePattern.ApostropheMode.DOUBLE_REQUIRED); |
| assertEquals("wrong value", |
| MessagePattern.ApostropheMode.DOUBLE_OPTIONAL, |
| ado_mp.getApostropheMode()); |
| assertEquals("wrong value", |
| MessagePattern.ApostropheMode.DOUBLE_REQUIRED, |
| adr_mp.getApostropheMode()); |
| assertNotEquals("MessagePatterns with different ApostropheMode (no pattern)", ado_mp, adr_mp); |
| assertNotEquals("MessagePatterns with different ApostropheMode (a)", |
| ado_mp.parse("a"), adr_mp.parse("a")); |
| |
| String[] tuples = new String[] { |
| // Desired output |
| // DOUBLE_OPTIONAL pattern |
| // DOUBLE_REQUIRED pattern (null=same as DOUBLE_OPTIONAL) |
| "I see {many}", "I see '{many}'", null, |
| "I said {'Wow!'}", "I said '{''Wow!''}'", null, |
| "I dont know", "I dont know", "I don't know", |
| "I don't know", "I don't know", "I don''t know", |
| "I don't know", "I don''t know", "I don''t know", |
| }; |
| for (int i = 0; i < tuples.length; i += 3) { |
| String desired = tuples[i]; |
| String ado_pattern = tuples[i + 1]; |
| assertEquals("DOUBLE_OPTIONAL failure", desired, |
| getPatternAndSkipSyntax(ado_mp.parse(ado_pattern))); |
| String adr_pattern = tuples[i + 2]; |
| if (adr_pattern == null) { |
| adr_pattern = ado_pattern; |
| } |
| assertEquals("DOUBLE_REQUIRED failure", desired, |
| getPatternAndSkipSyntax(adr_mp.parse(adr_pattern))); |
| } |
| } |
| |
| // Compare behavior of JDK and ICU's DOUBLE_REQUIRED compatibility mode. |
| @Test |
| public void TestCompatibleApostrophe() { |
| // Message with choice argument which does not contain another argument. |
| // The JDK performs only one apostrophe-quoting pass on this pattern. |
| String pattern = "ab{0,choice,0#1'2''3'''4''''.}yz"; |
| java.text.MessageFormat jdkMsg = |
| new java.text.MessageFormat(pattern, Locale.ENGLISH); |
| |
| MessageFormat compMsg = new MessageFormat("", Locale.ENGLISH); |
| compMsg.applyPattern(pattern, MessagePattern.ApostropheMode.DOUBLE_REQUIRED); |
| assertEquals("wrong value", |
| MessagePattern.ApostropheMode.DOUBLE_REQUIRED, |
| compMsg.getApostropheMode()); |
| |
| MessageFormat icuMsg = new MessageFormat("", Locale.ENGLISH); |
| icuMsg.applyPattern(pattern, MessagePattern.ApostropheMode.DOUBLE_OPTIONAL); |
| assertEquals("wrong value", |
| MessagePattern.ApostropheMode.DOUBLE_OPTIONAL, |
| icuMsg.getApostropheMode()); |
| |
| Object[] zero0 = new Object[] { 0 }; |
| assertEquals("unexpected JDK MessageFormat apostrophe behavior", |
| "ab12'3'4''.yz", |
| jdkMsg.format(zero0)); |
| assertEquals("incompatible ICU MessageFormat compatibility-apostrophe behavior", |
| "ab12'3'4''.yz", |
| compMsg.format(zero0)); |
| assertEquals("unexpected ICU MessageFormat double-apostrophe-optional behavior", |
| "ab1'2'3''4''.yz", |
| icuMsg.format(zero0)); |
| |
| // Message with choice argument which contains a nested simple argument. |
| // The JDK performs two apostrophe-quoting passes. |
| pattern = "ab{0,choice,0#1'2''3'''4''''.{0,number,'#x'}}yz"; |
| jdkMsg.applyPattern(pattern); |
| compMsg.applyPattern(pattern); |
| icuMsg.applyPattern(pattern); |
| assertEquals("unexpected JDK MessageFormat apostrophe behavior", |
| "ab1234'.0xyz", |
| jdkMsg.format(zero0)); |
| assertEquals("incompatible ICU MessageFormat compatibility-apostrophe behavior", |
| "ab1234'.0xyz", |
| compMsg.format(zero0)); |
| assertEquals("unexpected ICU MessageFormat double-apostrophe-optional behavior", |
| "ab1'2'3''4''.#x0yz", |
| icuMsg.format(zero0)); |
| |
| // Message with choice argument which contains a nested choice argument. |
| // The JDK fails to parse this pattern. |
| // jdkMsg.applyPattern("cd{0,choice,0#ef{0,choice,0#1'2''3'''4''''.}uv}wx"); |
| // For lack of comparison, we do not test ICU with this pattern. |
| |
| // The JDK ChoiceFormat itself always performs one apostrophe-quoting pass. |
| ChoiceFormat choice = new ChoiceFormat("0#1'2''3'''4''''."); |
| assertEquals("unexpected JDK ChoiceFormat apostrophe behavior", |
| "12'3'4''.", |
| choice.format(0)); |
| choice.applyPattern("0#1'2''3'''4''''.{0,number,'#x'}"); |
| assertEquals("unexpected JDK ChoiceFormat apostrophe behavior", |
| "12'3'4''.{0,number,#x}", |
| choice.format(0)); |
| } |
| |
| @Test |
| public void TestTrimArgumentName() { |
| // ICU 4.8 allows and ignores white space around argument names and numbers. |
| MessageFormat m = new MessageFormat("a { 0 , number , '#,#'#.0 } z", Locale.ENGLISH); |
| assertEquals("trim-numbered-arg format() failed", "a #,#2.0 z", m.format(new Object[] { 2 })); |
| |
| m.applyPattern("x { _oOo_ , number , integer } y"); |
| Map<String, Object> map = new HashMap<String, Object>(); |
| map.put("_oOo_", new Integer(3)); |
| StringBuffer result = new StringBuffer(); |
| assertEquals("trim-named-arg format() failed", "x 3 y", |
| m.format(map, result, new FieldPosition(FieldPosition_DONT_CARE)).toString()); |
| } |
| |
| @Test |
| public void TestSelectOrdinal() { |
| // Test plural & ordinal together, |
| // to make sure that we get the correct cached PluralSelector for each. |
| MessageFormat m = new MessageFormat( |
| "{0,plural,one{1 file}other{# files}}, " + |
| "{0,selectordinal,one{#st file}two{#nd file}few{#rd file}other{#th file}}", |
| ULocale.ENGLISH); |
| Object[] args = new Object[] { 21 }; |
| FieldPosition ignore = null; |
| StringBuffer result = new StringBuffer(); |
| assertEquals("plural-and-ordinal format(21)", "21 files, 21st file", |
| m.format(args, result, ignore).toString()); |
| |
| args[0] = 2; |
| result.delete(0, result.length()); |
| assertEquals("plural-and-ordinal format(2) failed", "2 files, 2nd file", |
| m.format(args, result, ignore).toString()); |
| |
| args[0] = 1; |
| result.delete(0, result.length()); |
| assertEquals("plural-and-ordinal format(1) failed", "1 file, 1st file", |
| m.format(args, result, ignore).toString()); |
| |
| args[0] = 3; |
| result.delete(0, result.length()); |
| assertEquals("plural-and-ordinal format(3) failed", "3 files, 3rd file", |
| m.format(args, result, ignore).toString()); |
| } |
| |
| @Test |
| public void TestDecimals() { |
| // Simple number replacement. |
| MessageFormat m = new MessageFormat( |
| "{0,plural,one{one meter}other{# meters}}", |
| ULocale.ENGLISH); |
| Object[] args = new Object[] { 1 }; |
| FieldPosition ignore = null; |
| StringBuffer result = new StringBuffer(); |
| assertEquals("simple format(1)", "one meter", |
| m.format(args, result, ignore).toString()); |
| |
| args[0] = 1.5; |
| result.delete(0, result.length()); |
| assertEquals("simple format(1.5)", "1.5 meters", |
| m.format(args, result, ignore).toString()); |
| |
| // Simple but explicit. |
| MessageFormat m0 = new MessageFormat( |
| "{0,plural,one{one meter}other{{0} meters}}", |
| ULocale.ENGLISH); |
| args[0] = 1; |
| result.delete(0, result.length()); |
| assertEquals("explicit format(1)", "one meter", |
| m0.format(args, result, ignore).toString()); |
| |
| args[0] = 1.5; |
| result.delete(0, result.length()); |
| assertEquals("explicit format(1.5)", "1.5 meters", |
| m0.format(args, result, ignore).toString()); |
| |
| // With offset and specific simple format with optional decimals. |
| MessageFormat m1 = new MessageFormat( |
| "{0,plural,offset:1 one{another meter}other{{0,number,00.#} meters}}", |
| ULocale.ENGLISH); |
| args[0] = 1; |
| result.delete(0, result.length()); |
| assertEquals("offset format(1)", "01 meters", |
| m1.format(args, result, ignore).toString()); |
| |
| args[0] = 2; |
| result.delete(0, result.length()); |
| assertEquals("offset format(1)", "another meter", |
| m1.format(args, result, ignore).toString()); |
| |
| args[0] = 2.5; |
| result.delete(0, result.length()); |
| assertEquals("offset format(1)", "02.5 meters", |
| m1.format(args, result, ignore).toString()); |
| |
| // With offset and specific simple format with forced decimals. |
| MessageFormat m2 = new MessageFormat( |
| "{0,plural,offset:1 one{another meter}other{{0,number,0.0} meters}}", |
| ULocale.ENGLISH); |
| args[0] = 1; |
| result.delete(0, result.length()); |
| assertEquals("offset-decimals format(1)", "1.0 meters", |
| m2.format(args, result, ignore).toString()); |
| |
| args[0] = 2; |
| result.delete(0, result.length()); |
| assertEquals("offset-decimals format(1)", "2.0 meters", |
| m2.format(args, result, ignore).toString()); |
| |
| args[0] = 2.5; |
| result.delete(0, result.length()); |
| assertEquals("offset-decimals format(1)", "2.5 meters", |
| m2.format(args, result, ignore).toString()); |
| } |
| |
| @Test |
| public void TestArgIsPrefixOfAnother() { |
| // Ticket #11952 |
| MessageFormat mf1 = new MessageFormat( |
| "{0,select,a{A}ab{AB}abc{ABC}other{?}}", ULocale.ENGLISH); |
| assertEquals("a", "A", mf1.format(new Object[] { "a" })); |
| assertEquals("ab", "AB", mf1.format(new Object[] { "ab" })); |
| assertEquals("abc", "ABC", mf1.format(new Object[] { "abc" })); |
| |
| // Ticket #12172 |
| MessageFormat mf2 = new MessageFormat("{a} {aa} {aaa}", ULocale.ENGLISH); |
| Map<String, Object> args = new TreeMap<String, Object>(); |
| args.put("a", "A"); |
| args.put("aa", "AB"); |
| args.put("aaa", "ABC"); |
| assertEquals("a aa aaa", "A AB ABC", mf2.format(args, new StringBuffer(), null).toString()); |
| |
| // Ticket #12172 |
| MessageFormat mf3 = new MessageFormat("{aa} {aaa}", ULocale.ENGLISH); |
| assertEquals("aa aaa", "AB ABC", mf3.format(args, new StringBuffer(), null).toString()); |
| } |
| |
| @Test |
| public void TestMessagePatternAutoQuoteApostropheDeep() { |
| // Example input & output taken from API docs. |
| MessagePattern pattern = new MessagePattern( |
| "I don't '{know}' {gender,select,female{h''er}other{h'im}}."); |
| assertEquals("autoQuoteApostropheDeep()", |
| "I don''t '{know}' {gender,select,female{h''er}other{h''im}}.", |
| pattern.autoQuoteApostropheDeep()); |
| } |
| |
| @Test |
| public void TestMessagePatternFreezable() { |
| MessagePattern pattern = new MessagePattern(); |
| assertFalse("just constructed, not yet frozen", pattern.isFrozen()); |
| pattern.parse("fee"); |
| assertTrue("parsed, not empty", pattern.countParts() > 0); |
| pattern.freeze(); |
| assertTrue("just frozen", pattern.isFrozen()); |
| try { |
| pattern.parse("fi"); |
| fail("MessagePattern.freeze().parse() did not fail"); |
| } catch (Exception expected) { |
| } |
| assertEquals("frozen+parse: no change", "fee", pattern.autoQuoteApostropheDeep()); |
| MessagePattern thawed = pattern.cloneAsThawed(); |
| assertFalse("thawed", thawed.isFrozen()); |
| assertTrue("still frozen", pattern.isFrozen()); |
| assertTrue("frozen!=thawed", pattern != thawed); |
| thawed.parse("fo"); |
| assertEquals("thawed+parse", "fo", thawed.autoQuoteApostropheDeep()); |
| } |
| |
| @Test |
| public void TestMessagePatternNamedAndNumberedArguments() { |
| MessagePattern pattern = new MessagePattern(); |
| pattern.parse("fee"); |
| assertFalse("fee no named args", pattern.hasNamedArguments()); |
| assertFalse("fee no numbered args", pattern.hasNumberedArguments()); |
| pattern.parse("fi {0}"); |
| assertFalse("fi {0} no named args", pattern.hasNamedArguments()); |
| assertTrue("fi {0} has numbered args", pattern.hasNumberedArguments()); |
| pattern.parse("fo {name}"); |
| assertTrue("fo {name} has named args", pattern.hasNamedArguments()); |
| assertFalse("fo {name} no numbered args", pattern.hasNumberedArguments()); |
| pattern.parse("fum {0} {name}"); |
| assertTrue("fum {0} {name} has named args", pattern.hasNamedArguments()); |
| assertTrue("fum {0} {name} no numbered args", pattern.hasNumberedArguments()); |
| } |
| |
| @Test |
| public void TestMessagePatternPartCoverage() { |
| MessagePattern pattern = new MessagePattern("ab{17}c"); |
| assertEquals("msg start { arg number } msg limit", 5, pattern.countParts()); |
| MessagePattern.Part arg = pattern.getPart(2); |
| assertEquals("arg number", MessagePattern.Part.Type.ARG_NUMBER, arg.getType()); |
| assertEquals("arg number start", 3, arg.getIndex()); |
| assertEquals("arg number length", 2, arg.getLength()); |
| assertEquals("arg number limit", 5, arg.getLimit()); |
| assertEquals("arg number 17", 17, arg.getValue()); |
| } |
| |
| @Test |
| public void TestMessagePatternParseChoiceStyle() { |
| // This would be tested by ChoiceFormat if ICU4J had its own version of that, |
| // like ICU4C does. |
| // Instead, there is only java.text.ChoiceFormat. |
| // Most of the implementation gets covered by testing with a MessageFormat |
| // that contains a nested ChoiceFormat pattern, |
| // but that does not call this public API method. |
| MessagePattern pattern = new MessagePattern(); |
| // Example string from java.text.ChoiceFormat class docs. |
| pattern.parseChoiceStyle( |
| "-1#is negative| 0#is zero or fraction | 1#is one |" + |
| "1.0<is 1+ |2#is two |2<is more than 2."); |
| // Only simple API coverage. The parser implementation is tested via MessageFormat. |
| assertTrue("many parts", pattern.countParts() > 10); |
| } |
| |
| // This is mostly a code coverage test with verification minimized to what can be plausibly assumed: different |
| // hash values for distinctly different objects. |
| @Test |
| public void TestDateFormatHashCode() { |
| DateFormat testDF1 = DateFormat.getDateInstance(DateFormat.DEFAULT, ULocale.GERMAN); |
| DateFormat testDF2 = DateFormat.getDateInstance(DateFormat.DEFAULT, ULocale.FRENCH); |
| |
| int actualHashResult1 = testDF1.hashCode(); |
| int actualHashResult2 = testDF2.hashCode(); |
| assertNotEquals("DateFormat hashCode() test: really the same hashcode?", actualHashResult1, actualHashResult2); |
| } |
| |
| @Test |
| public void TestMessageFormatNumberSkeleton() { |
| Object[][] cases = new Object[][] { |
| { "{0,number,::percent}", ULocale.ENGLISH, 50, "50%" }, |
| { "{0,number,::percent scale/100}", ULocale.ENGLISH, 0.5, "50%" }, |
| { "{0,number, :: percent scale/100 }", ULocale.ENGLISH, 0.5, "50%" }, |
| { "{0,number,::currency/USD}", ULocale.ENGLISH, 23, "$23.00" }, |
| { "{0,number,::precision-integer}", ULocale.ENGLISH, 514.23, "514" }, |
| { "{0,number,::.000}", ULocale.ENGLISH, 514.23, "514.230" }, |
| { "{0,number,::.}", ULocale.ENGLISH, 514.23, "514" }, |
| { "{0,number,::}", ULocale.FRENCH, 514.23, "514,23" }, |
| { "Cost: {0,number,::currency/EUR}.", ULocale.ENGLISH, 4.3, "Cost: €4.30." }, |
| { "{0,number,'::'0.00}", ULocale.ENGLISH, 50, "::50.00" }, // pattern literal |
| }; |
| |
| for (Object[] cas : cases) { |
| String messagePattern = (String) cas[0]; |
| ULocale locale = (ULocale) cas[1]; |
| Number arg = (Number) cas[2]; |
| String expected = (String) cas[3]; |
| |
| MessageFormat msgf = new MessageFormat(messagePattern, locale); |
| StringBuffer sb = new StringBuffer(); |
| FieldPosition fpos = new FieldPosition(FieldPosition_DONT_CARE); |
| msgf.format(new Object[] { arg }, sb, fpos); |
| |
| assertEquals(messagePattern, expected, sb.toString()); |
| } |
| } |
| |
| private static void doTheRealDateTimeSkeletonTesting(Date date, String messagePattern, ULocale locale, String expected) { |
| |
| MessageFormat msgf = new MessageFormat(messagePattern, locale); |
| StringBuffer sb = new StringBuffer(); |
| FieldPosition fpos = new FieldPosition(FieldPosition_DONT_CARE); |
| msgf.format(new Object[] { date }, sb, fpos); |
| |
| assertEquals(messagePattern, expected, sb.toString()); |
| } |
| |
| @Test |
| public void TestMessageFormatDateSkeleton() { |
| Date date = new GregorianCalendar(2021, Calendar.NOVEMBER, 23, 16, 42, 55).getTime(); |
| |
| doTheRealDateTimeSkeletonTesting(date, "{0,date,::MMMMd}", ULocale.ENGLISH, "November 23"); |
| doTheRealDateTimeSkeletonTesting(date, "{0,date,::yMMMMdjm}", ULocale.ENGLISH, "November 23, 2021, 4:42 PM"); |
| doTheRealDateTimeSkeletonTesting(date, "{0,date, :: yMMMMd }", ULocale.ENGLISH, "November 23, 2021"); |
| doTheRealDateTimeSkeletonTesting(date, "{0,date,::yMMMMd}", ULocale.FRENCH, "23 novembre 2021"); |
| doTheRealDateTimeSkeletonTesting(date, "Expiration: {0,date,::yMMM}!", ULocale.ENGLISH, "Expiration: Nov 2021!"); |
| doTheRealDateTimeSkeletonTesting(date, "{0,date,'::'yMMMMd}", ULocale.ENGLISH, "::2021November23"); // pattern literal |
| } |
| |
| @Test |
| public void TestMessageFormatTimeSkeleton() { |
| Date date = new GregorianCalendar(2021, Calendar.NOVEMBER, 23, 16, 42, 55).getTime(); |
| |
| doTheRealDateTimeSkeletonTesting(date, "{0,time,::MMMMd}", ULocale.ENGLISH, "November 23"); |
| doTheRealDateTimeSkeletonTesting(date, "{0,time,::yMMMMdjm}", ULocale.ENGLISH, "November 23, 2021, 4:42 PM"); |
| doTheRealDateTimeSkeletonTesting(date, "{0,time, :: yMMMMd }", ULocale.ENGLISH, "November 23, 2021"); |
| doTheRealDateTimeSkeletonTesting(date, "{0,time,::yMMMMd}", ULocale.FRENCH, "23 novembre 2021"); |
| doTheRealDateTimeSkeletonTesting(date, "Expiration: {0,time,::yMMM}!", ULocale.ENGLISH, "Expiration: Nov 2021!"); |
| doTheRealDateTimeSkeletonTesting(date, "{0,time,'::'yMMMMd}", ULocale.ENGLISH, "::2021November23"); // pattern literal |
| } |
| } |