ICU-3931 Merged with trunk r27250 from branch kirtig r27251 - Added SelectFormat

X-SVN-Rev: 27252
This commit is contained in:
Kirti Velankar 2010-01-13 02:20:05 +00:00
parent 56c2ba6a9c
commit d1df3c60de
8 changed files with 1069 additions and 97 deletions

2
.gitattributes vendored
View file

@ -131,6 +131,8 @@ icu4j/main/tests/core/.settings/org.eclipse.jdt.core.prefs -text
icu4j/main/tests/core/manifest.stub -text
icu4j/main/tests/core/src/com/ibm/icu/dev/data/rbbi/english.dict -text
icu4j/main/tests/core/src/com/ibm/icu/dev/data/thai6.ucs -text
icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/SelectFormatAPITest.java -text
icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/SelectFormatUnitTest.java -text
icu4j/main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_3.6/com.ibm.icu.impl.OlsonTimeZone.dat -text
icu4j/main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_3.6/com.ibm.icu.impl.TimeZoneAdapter.dat -text
icu4j/main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_3.6/com.ibm.icu.math.BigDecimal.dat -text

View file

@ -288,6 +288,10 @@ import com.ibm.icu.util.ULocale;
* <td><code>plural</code>
* <td><i>SubformatPattern</i>
* <td><code>new PluralFormat(subformatPattern)</code>
* <tr>
* <td><code>select</code>
* <td><i>SubformatPattern</i>
* <td><code>new SelectFormat(subformatPattern)</code>
* </table>
* <p>
*
@ -407,6 +411,8 @@ import com.ibm.icu.util.ULocale;
* @see NumberFormat
* @see DecimalFormat
* @see ChoiceFormat
* @see PluralFormat
* @see SelectFormat
* @author Mark Davis
* @stable ICU 3.0
*/
@ -665,21 +671,16 @@ public class MessageFormat extends UFormat implements BaseFormat<Object,StringBu
} else if (formats[i] instanceof ChoiceFormat) {
result.append(",choice,"
+ ((ChoiceFormat) formats[i]).toPattern());
} else if (formats[i] instanceof PluralFormat) {
String pat = ((PluralFormat)formats[i]).toPattern();
// TODO: PluralFormat doesn't do the single quote thing, just reapply
if (pat.indexOf('\'') != 0) {
StringBuffer buf = new StringBuffer();
for (int j = 0; j < pat.length(); ++j) {
char ch = pat.charAt(j);
if (ch == '\'') {
buf.append(ch); // double it
}
buf.append(ch);
}
pat = buf.toString();
}
result.append(",plural," + pat);
} else if (formats[i] instanceof PluralFormat ){
String pat = ((PluralFormat)formats[i]).toPattern();
// TODO: PluralFormat does not do the single quote thing, just reapply
pat = duplicateSingleQuotes(pat);
result.append(",plural," + pat);
} else if (formats[i] instanceof SelectFormat) {
String pat = ((SelectFormat)formats[i]).toPattern();
//TODO: SelectFormat does not do the single quote thing, just reapply
pat = duplicateSingleQuotes(pat);
result.append(",select," + pat);
} else {
//result.append(", unknown");
}
@ -689,6 +690,25 @@ public class MessageFormat extends UFormat implements BaseFormat<Object,StringBu
return result.toString();
}
/**
* Double every single quote
*/
private String duplicateSingleQuotes(String pat){
String result = pat;
if (pat.indexOf('\'') != 0) {
StringBuffer buf = new StringBuffer();
for (int j = 0; j < pat.length(); ++j) {
char ch = pat.charAt(j);
if (ch == '\'') {
buf.append(ch); // double it
}
buf.append(ch);
}
result = buf.toString();
}
return result;
}
/**
* Sets the formats to use for the values passed into
* <code>format</code> methods or returned from <code>parse</code>
@ -1716,7 +1736,8 @@ public class MessageFormat extends UFormat implements BaseFormat<Object,StringBu
} else if (formats[i] != null) {
subFormatter = formats[i];
if (subFormatter instanceof ChoiceFormat
|| subFormatter instanceof PluralFormat) {
|| subFormatter instanceof PluralFormat
|| subFormatter instanceof SelectFormat) {
arg = formats[i].format(obj);
// TODO: This should be made more robust.
// Does this work with '{' in quotes?
@ -1820,7 +1841,7 @@ public class MessageFormat extends UFormat implements BaseFormat<Object,StringBu
private static final String[] typeList =
{"", "number", "date", "time", "choice", "spellout", "ordinal",
"duration", "plural"};
"duration", "plural", "select" };
private static final int
TYPE_EMPTY = 0,
TYPE_NUMBER = 1,
@ -1830,7 +1851,8 @@ public class MessageFormat extends UFormat implements BaseFormat<Object,StringBu
TYPE_SPELLOUT = 5,
TYPE_ORDINAL = 6,
TYPE_DURATION = 7,
TYPE_PLURAL = 8;
TYPE_PLURAL = 8,
TYPE_SELECT = 9;
private static final String[] modifierList =
{"", "currency", "percent", "integer"};
@ -1912,7 +1934,8 @@ public class MessageFormat extends UFormat implements BaseFormat<Object,StringBu
// now get the format
Format newFormat = null;
switch (findKeyword(segments[2].toString(), typeList)) {
int subformatType = findKeyword(segments[2].toString(), typeList);
switch (subformatType){
case TYPE_EMPTY:
break;
case TYPE_NUMBER:
@ -2036,10 +2059,11 @@ public class MessageFormat extends UFormat implements BaseFormat<Object,StringBu
}
break;
case TYPE_PLURAL:
case TYPE_SELECT:
{
// PluralFormat does not handle quotes.
// PluralFormat and SelectFormat does not handle quotes.
// Remove quotes.
// TODO: Should PluralFormat handle quotes?
// TODO: Should PluralFormat and SelectFormat handle quotes?
StringBuffer unquotedPattern = new StringBuffer();
String quotedPattern = segments[3].toString();
boolean inQuote = false;
@ -2058,9 +2082,13 @@ public class MessageFormat extends UFormat implements BaseFormat<Object,StringBu
}
}
PluralFormat pls = new PluralFormat(ulocale,
if( subformatType == TYPE_PLURAL){
PluralFormat pls = new PluralFormat(ulocale,
unquotedPattern.toString());
newFormat = pls;
newFormat = pls;
}else{
newFormat = new SelectFormat( unquotedPattern.toString());
}
}
break;
default:

View file

@ -1,15 +1,20 @@
/*
********************************************************************************
* Copyright (C) 2009, Yahoo! Inc., International Business Machines Corporation *
* and others. All Rights Reserved. *
********************************************************************************
*******************************************************************************
* Copyright (c) 2004-2010, International Business Machines
* Corporation and others. All Rights Reserved.
* Copyright (C) 2009 , Yahoo! Inc.
*******************************************************************************
*/
package com.ibm.icu.text;
import java.text.FieldPosition;
import java.text.Format;
import java.text.FieldPosition;
import java.text.ParsePosition;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import com.ibm.icu.impl.UCharacterProperty;
/**
* <p><code>SelectFormat</code> supports the creation of internationalized
@ -21,7 +26,7 @@ import java.text.ParsePosition;
*
* <h4>Using <code>SelectFormat</code> for Gender Agreement</h4>
*
* <p>The main use case for the select format is gender based inflection.
* <p>The main use case for the select format is gender based inflection.
* When names or nouns are inserted into sentences, their gender can affect pronouns,
* verb forms, articles, and adjectives. Special care needs to be
* taken for the case where the gender cannot be determined.
@ -34,16 +39,16 @@ import java.text.ParsePosition;
* The gender only affects pronouns: "he", "she", "it", "they".
*
* <li>German differs from English in that the gender of nouns is rather
* arbitrary, even for nouns referring to people ("M&auml;dchen", girl, is neutral).
* arbitrary, even for nouns referring to people ("M\\u00E4dchen", girl, is neutral).
* The gender affects pronouns ("er", "sie", "es"), articles ("der", "die",
* "das"), and adjective forms ("guter Mann", "gute Frau", "gutes M&auml;dchen").
* "das"), and adjective forms ("guter Mann", "gute Frau", "gutes M\\u00E4dchen").
*
* <li>French has only two genders; as in German the gender of nouns
* is rather arbitrary &#8211; for sun and moon, the genders
* is rather arbitrary for sun and moon, the genders
* are the opposite of those in German. The gender affects
* pronouns ("il", "elle"), articles ("le", "la"),
* adjective forms ("bon", "bonne"), and sometimes
* verb forms ("all&eacute;", "all&eacute;e").
* verb forms ("all\\u00E9", "all\\u00E9e").
*
* <li>Polish distinguishes five genders (or noun classes),
* human masculine, animate non-human masculine, inanimate masculine,
@ -84,7 +89,7 @@ import java.text.ParsePosition;
* <p>The sentence pattern for French, where the gender of the person affects
* the form of the participle, uses a select format based on argument 1:</p>
*
* <pre>{0} est {1, select, female {all&eacute;e} other {all&eacute;}} &agrave; {2}.</pre>
* <pre>{0} est {1, select, female {all\\u00E9e} other {all\\u00E9}} \\u00E0 {2}.</pre>
*
* <p>Patterns can be nested, so that it's possible to handle interactions of
* number and gender where necessary. For example, if the above sentence should
@ -94,9 +99,9 @@ import java.text.ParsePosition;
* argument 3 the city name):</p>
*
* <pre>{0} {1, plural,
* one {est {2, select, female {all&eacute;e} other {all&eacute;}}}
* other {sont {2, select, female {all&eacute;es} other {all&eacute;s}}}
* }&agrave; {3}.</pre>
* one {est {2, select, female {all\\u00E9e} other {all\\u00E9}}}
* other {sont {2, select, female {all\\u00E9es} other {all\\u00E9s}}}
* }\\u00E9 {3}.</pre>
*
* <h4>Patterns and Their Interpretation</h4>
*
@ -135,42 +140,138 @@ import java.text.ParsePosition;
* <p>Example:
* <pre>
* MessageFormat msgFmt = new MessageFormat("{0} est " +
* "{1, select, female {all&eacute;e} other {all&eacute;}} &agrave; Paris.",
* "{1, select, female {all\\u00E9e} other {all\\u00E9}} \\u00E0 Paris.",
* new ULocale("fr"));
* Object args[] = {"Kirti","female"};
* System.out.println(msgFmt.format(args));
* </pre>
* Produces the output:
* <pre>
* Kirti est all&eacute;e &agrave; Paris.
* Produces the output:<br/>
* <code>Input is Kirti,female and result is: Kirti est all\\u00E9e \\u00E0 Paris.</code>
* </pre>
*
*
* @draft ICU 4.4
* @provisional This API might change or be removed in a future release.
*/
public class SelectFormat extends Format {
private static final long serialVersionUID = 1L;
public class SelectFormat extends Format{
// Generated by serialver from JDK 1.5
static final long serialVersionUID = 1L;
/*
* The applied pattern string.
*/
private String pattern = null;
/*
* The format messages for each select case. It is a mapping:
* <code>String</code>(select case keyword) --&gt; <code>String</code>
* (message for this select case).
*/
private Map<String, String> parsedValues = null;
/**
* Common name for the default select form. This name is returned
* for values to which no other form in the rule applies. It
* can additionally be assigned rules of its own.
* @draft ICU 4.4
*/
public static final String KEYWORD_OTHER = "other";
/*
* The types of character classifications
*/
public enum CharacterClass {
T_START_KEYWORD, T_CONTINUE_KEYWORD, T_LEFT_BRACE,
T_RIGHT_BRACE, T_SPACE, T_OTHER
};
/*
* The different states needed in state machine
* in applyPattern method.
*/
public enum State {
START_STATE, KEYWORD_STATE,
PAST_KEYWORD_STATE, PHRASE_STATE
};
/**
* Creates a new <code>SelectFormat</code>
*
* @draft ICU 4.4
* @provisional This API might change or be removed in a future release.
*/
public SelectFormat() {
throw new UnsupportedOperationException("Constructor SelectFormat() is not implemented yet.");
init();
}
/**
* Creates a new <code>SelectFormat</code> for a given pattern string.
*
* @param pattern the pattern for this <code>SelectFormat</code>.
* @draft ICU 4.4
* @provisional This API might change or be removed in a future release.
*/
public SelectFormat(String pattern) {
throw new UnsupportedOperationException("Constructor SelectFormat(String) is not implemented yet.");
init();
applyPattern(pattern);
}
/*
* Initializes the <code>SelectFormat</code> object.
* Postcondition:<br/>
* <code>parsedValues</code>: is <code>null</code><br/>
* <code>pattern</code>: is <code>null</code><br/>
*/
private void init() {
parsedValues = null;
pattern = null;
}
/**
* Classifies the characters
*/
private boolean checkValidKeyword(String argKeyword) {
int len = argKeyword.length();
if (len < 1) {
return false;
};
if (classifyCharacter(argKeyword.charAt(0)) != CharacterClass.T_START_KEYWORD) {
return false;
};
for (int i = 1; i < len; i++) {
CharacterClass type = classifyCharacter(argKeyword.charAt(i));
if (type != CharacterClass.T_START_KEYWORD &&
type != CharacterClass.T_CONTINUE_KEYWORD) {
return false;
};
};
return true;
}
/**
* Classifies the characters
*/
private CharacterClass classifyCharacter(char ch) {
if ((ch >= 'A') && (ch <= 'Z')) {
return CharacterClass.T_START_KEYWORD;
}
if ((ch >= 'a') && (ch <= 'z')) {
return CharacterClass.T_START_KEYWORD;
}
if ((ch >= '0') && (ch <= '9')) {
return CharacterClass.T_CONTINUE_KEYWORD;
}
switch (ch) {
case '{':
return CharacterClass.T_LEFT_BRACE;
case '}':
return CharacterClass.T_RIGHT_BRACE;
case ' ':
case '\t':
return CharacterClass.T_SPACE;
case '-':
case '_':
return CharacterClass.T_CONTINUE_KEYWORD;
default :
return CharacterClass.T_OTHER;
}
}
/**
@ -178,11 +279,133 @@ public class SelectFormat extends Format {
* Patterns and their interpretation are specified in the class description.
*
* @param pattern the pattern for this select format.
* @throws IllegalArgumentException
* @draft ICU 4.4
* @provisional This API might change or be removed in a future release.
*/
public void applyPattern(String pattern) {
throw new UnsupportedOperationException("SelectFormat.applyPattern(String) is not implemented yet.");
parsedValues = null;
this.pattern = pattern;
//Initialization
StringBuffer keyword = new StringBuffer();
StringBuffer phrase = new StringBuffer();
int braceCount = 0;
parsedValues = new HashMap<String, String>();
//Process the state machine
State state = State.START_STATE;
for (int i = 0; i < pattern.length(); i++ ){
//Get the character and check its type
char ch = pattern.charAt(i);
CharacterClass type = classifyCharacter(ch);
//Process the state machine
switch (state) {
//At the start of pattern
case START_STATE:
switch (type) {
case T_SPACE:
break ;
case T_START_KEYWORD:
state = State.KEYWORD_STATE;
keyword.append(ch);
break ;
//If anything else is encountered, it's a syntax error
default :
parsingFailure("Pattern syntax error.");
}//end of switch(type)
break ;
//Handle the keyword state
case KEYWORD_STATE:
switch (type) {
case T_SPACE:
state = State.PAST_KEYWORD_STATE;
break ;
case T_START_KEYWORD:
case T_CONTINUE_KEYWORD:
keyword.append(ch);
break ;
case T_LEFT_BRACE:
state = State.PHRASE_STATE;
break ;
//If anything else is encountered, it's a syntax error
default :
parsingFailure("Pattern syntax error.");
}//end of switch(type)
break ;
//Handle the pastkeyword state
case PAST_KEYWORD_STATE:
switch (type) {
case T_SPACE:
break ;
case T_LEFT_BRACE:
state = State.PHRASE_STATE;
break ;
//If anything else is encountered, it's a syntax error
default :
parsingFailure("Pattern syntax error.");
}//end of switch(type)
break ;
//Handle the phrase state
case PHRASE_STATE:
switch (type) {
case T_LEFT_BRACE:
braceCount++;
phrase.append(ch);
break ;
case T_RIGHT_BRACE:
//Matching keyword, phrase pair found
if (braceCount == 0){
//Check validity of keyword
if (parsedValues.get(keyword.toString()) != null) {
parsingFailure("Duplicate keyword error.");
}
if (keyword.length() == 0) {
parsingFailure("Pattern syntax error.");
}
//Store the keyword, phrase pair in hashTable
parsedValues.put( keyword.toString(), phrase.toString());
//Reinitialize
keyword.setLength(0);
phrase.setLength(0);
state = State.START_STATE;
}
if (braceCount > 0){
braceCount-- ;
phrase.append(ch);
}
break ;
default :
phrase.append(ch);
}//end of switch(type)
break ;
//Handle the default case of switch(state)
default :
parsingFailure("Pattern syntax error.");
}//end of switch(state)
}
//Check if the state machine is back to START_STATE
if ( state != State.START_STATE){
parsingFailure("Pattern syntax error.");
}
//Check if "other" keyword is present
if ( !checkSufficientDefinition() ) {
parsingFailure("Pattern syntax error. "
+ "Value for case \"" + KEYWORD_OTHER
+ "\" was not defined. ");
}
return ;
}
/**
@ -190,99 +413,142 @@ public class SelectFormat extends Format {
*
* @return the pattern string
* @draft ICU 4.4
* @provisional This API might change or be removed in a future release.
*/
public String toPattern() {
throw new UnsupportedOperationException("SelectFormat.toPattern() is not implemented yet.");
return pattern;
}
/**
* Formats a select message for a given keyword.
* Selects the phrase for the given keyword.
*
* @param keyword a keyword for which the select message should be formatted.
* @return the string containing the formatted select message.
* @throws IllegalArgumentException
* @draft ICU 4.4
* @provisional This API might change or be removed in a future release.
*/
public final String format(String keyword) {
throw new UnsupportedOperationException("SelectFormat.format(String) is not implemented yet.");
//Check for the validity of the keyword
if( !checkValidKeyword(keyword) ){
throw new IllegalArgumentException("Invalid formatting argument.");
}
// If no pattern was applied, throw an exception
if (parsedValues == null) {
throw new IllegalStateException("Invalid format error.");
}
// Get appropriate format pattern.
String selectedPattern = parsedValues.get(keyword);
if (selectedPattern == null) { // Fallback to others.
selectedPattern = parsedValues.get(KEYWORD_OTHER);
}
return selectedPattern;
}
/**
* Formats a select message for a given keyword and appends the formatted
* message to the given <code>StringBuffer</code>.
*
* Selects the phrase for the given keyword.
* and appends the formatted message to the given <code>StringBuffer</code>.
* @param keyword a keyword for which the select message should be formatted.
* @param toAppendTo the formatted message will be appended to this
* <code>StringBuffer</code>.
* @param pos will be ignored by this method.
* @throws IllegalArgumentException
* @return the string buffer passed in as toAppendTo, with formatted text
* appended.
* @draft ICU 4.4
* @provisional This API might change or be removed in a future release.
*/
public StringBuffer format(Object keyword, StringBuffer toAppendTo,
FieldPosition pos) {
throw new UnsupportedOperationException("SelectFormat.format( Object, StringBuffer,FieldPosition) is not implemented yet.");
if (keyword instanceof String) {
toAppendTo.append(format( (String)keyword));
}else{
throw new IllegalArgumentException("'" + keyword + "' is not a String");
}
return toAppendTo;
}
/**
* This method is not yet supported by <code>SelectFormat</code>.
*
* @param source the string to be parsed.
* @param pos defines the position where parsing is to begin,
* and upon return, the position where parsing left off. If the position
* has not changed upon return, then parsing failed.
* @return nothing because this method is not yet implemented.
* @throws UnsupportedOperationException
* @draft ICU 4.4
* @provisional This API might change or be removed in a future release.
*/
public Object parseObject(String source, ParsePosition pos) {
throw new UnsupportedOperationException();
}
/*
* Checks if the applied pattern provided enough information,
* i.e., if the attribute <code>parsedValues</code> stores enough
* information for select formatting.
* Will be called at the end of pattern parsing.
*/
private boolean checkSufficientDefinition() {
// Check that at least the default rule is defined.
return parsedValues.get(KEYWORD_OTHER) != null;
}
/*
* Helper method that resets the <code>SelectFormat</code> object and throws
* an <code>IllegalArgumentException</code> with a given error text.
* @param errorText the error text of the exception message.
* @throws IllegalArgumentException will always be thrown by this method.
*/
private void parsingFailure(String errorText) {
// Set SelectFormat to a valid state.
init();
throw new IllegalArgumentException(errorText);
}
/**
* {@inheritDoc}
*
* @draft ICU 4.4
* @provisional This API might change or be removed in a future release.
*/
public boolean equals(Object rhs) {
throw new UnsupportedOperationException("SelectFormat.equals(Object) is not implemented yet.");
return rhs instanceof SelectFormat && this.equals((SelectFormat) rhs);
}
/**
* Returns true if this equals the provided <code>SelectFormat<code>.
*
* @param rhs the SelectFormat to compare against
* @return true if this equals <code>rhs</code>
* @return true if this equals rhs
* @draft ICU 4.4
* @provisional This API might change or be removed in a future release.
*/
public boolean equals(SelectFormat rhs) {
throw new UnsupportedOperationException("SelectFormat.equals(SelectFormat) is not implemented yet.");
if( parsedValues == null && rhs.parsedValues == null){
return true;
}
if( parsedValues != null && rhs.parsedValues != null){
return parsedValues.equals(rhs.parsedValues);
}
return false;
}
/**
* {@inheritDoc}
*
* @draft ICU 4.4
* @provisional This API might change or be removed in a future release.
*/
public int hashCode() {
throw new UnsupportedOperationException("SelectFormat.hashCode() is not implemented yet.");
if( parsedValues!=null){
return parsedValues.hashCode();
}
return 0;
}
/**
* Returns a string representation of the object
*
* @return a text representation of the format object.
* The result string includes the class name and
* the pattern string returned by <code>toPattern()</code>.
* @draft ICU 4.4
* @provisional This API might change or be removed in a future release.
*/
public String toString() {
throw new UnsupportedOperationException("SelectFormat.toString() is not implemented yet.");
StringBuffer buf = new StringBuffer();
buf.append("pattern='" + pattern + "'");
return buf.toString();
}
}

View file

@ -0,0 +1,299 @@
/*
*******************************************************************************
* Copyright (c) 2004-2010, International Business Machines
* Corporation and others. All Rights Reserved.
* Copyright (C) 2010 , Yahoo! Inc.
*******************************************************************************
*/
package com.ibm.icu.dev.test.format;
import com.ibm.icu.dev.test.TestFmwk;
import com.ibm.icu.impl.Utility;
import com.ibm.icu.text.SelectFormat;
import java.text.FieldPosition;
import java.text.ParsePosition;
import java.util.HashMap;
import java.util.Map;
/**
* @author kirtig
* This class tests the API functionality of the SelectFormat
*/
public class SelectFormatAPITest extends TestFmwk {
static final String SIMPLE_PATTERN = "feminine {feminineVerbValue} other{otherVerbValue}";
public static void main(String[] args) throws Exception {
new SelectFormatAPITest().run(args);
}
/**
* API tests for constructors
*/
public void TestConstructors() {
log("Inside TestConstructors");
//Default constructor
try {
SelectFormat selFmt = new SelectFormat();
assertNotNull("Error: TestConstructors - SelectFormat object constructed "
+ "with default constructor is null" , selFmt );
} catch (Exception e){
errln("Exception encountered in TestConstructors while creating a default constructor");
}
//Constructor with argument - a pattern
try {
SelectFormat selFmt = new SelectFormat(SIMPLE_PATTERN);
assertNotNull("Error: TestConstructors - SelectFormat object constructed "
+ "with argument constructor is null" , selFmt );
} catch (Exception e){
errln("Exception encountered in TestConstructors while creating a constructor with argument");
}
}
/**
* API tests for equals() method
*/
public void TestEquals() {
log("Inside TestEquals");
SelectFormat selFmt1 = null;
SelectFormat selFmt3 = null;
//Check equality for Default constructed SelectFormats
try {
selFmt1 = new SelectFormat();
SelectFormat selFmt2 = new SelectFormat();
assertTrue("Equals test failed while checking equality for "
+ "default constructed SelectFormats ."
, selFmt1.equals(selFmt2) );
} catch (Exception e){
errln("Exception encountered in TestEquals 1 " + e.getMessage());
}
//Check equality for pattern constructed SelectFormats
try {
selFmt3 = new SelectFormat(SIMPLE_PATTERN);
SelectFormat selFmt4 = new SelectFormat(SIMPLE_PATTERN);
assertTrue("Equals test failed while checking equality for "
+ "pattern constructed SelectFormats ."
, selFmt3.equals(selFmt4) );
} catch (Exception e){
errln("Exception encountered in TestEquals 2 " + e.getMessage());
}
//Check equality for 2 objects
try {
Object selFmt5 = new SelectFormat();
Object selFmt6 = new SelectFormat(SIMPLE_PATTERN);
assertTrue("Equals test failed while checking equality for object 1."
, selFmt1.equals(selFmt5) );
assertTrue("Equals test failed while checking equality for object 2."
, selFmt3.equals(selFmt6) );
} catch (Exception e){
errln("Exception encountered in TestEquals 3" + e.getMessage());
}
}
/**
* API tests for applyPattern() method
*/
public void TestApplyPatternToPattern() {
log("Inside TestApplyPatternToPattern");
SelectFormat selFmt = null;
String pattern = "masculine{masculineVerbValue} other{otherVerbValue}";
//Check toPattern for Default constructed SelectFormat
try {
selFmt = new SelectFormat();
selFmt.applyPattern(pattern);
assertEquals("Failed in applyPattern,toPattern 1 with unexpected output"
, pattern, selFmt.toPattern() );
} catch (Exception e){
errln("Exception encountered in TestApplyPatternToPattern 1");
}
//Check toPattern for pattern constructed SelectFormat
try {
selFmt = new SelectFormat(SIMPLE_PATTERN);
selFmt.applyPattern(pattern);
assertEquals("Failed in applyPattern,toPattern 2 with unexpected output"
, pattern, selFmt.toPattern() );
} catch (Exception e){
errln("Exception encountered in TestApplyPatternToPattern 2");
}
}
/**
* API tests for toString() method
*/
public void TestToString(){
log("Inside TestToString");
SelectFormat selFmt = null;
//Check toString for Default constructed SelectFormat
try {
selFmt = new SelectFormat();
String expected = "pattern='null'";
assertEquals("Failed in TestToString with unexpected output 1"
, expected, selFmt.toString() );
} catch (Exception e){
errln("Exception encountered in TestToString 1");
}
//Check toString for pattern constructed SelectFormat
try {
selFmt = new SelectFormat(SIMPLE_PATTERN);
String expected = "pattern='feminine {feminineVerbValue} other{otherVerbValue}'";
assertEquals("Failed in TestToString with unexpected output 2"
, expected, selFmt.toString() );
} catch (Exception e){
errln("Exception encountered in TestToString 2");
}
}
/**
* API tests for hashCode() method
*/
public void TestHashCode(){
log("Inside TestHashCode");
SelectFormat selFmt = null;
SelectFormat selFmt1 = null;
SelectFormat selFmt2 = null;
//Check hashCode for Default constructed SelectFormat
try {
selFmt = new SelectFormat();
selFmt1 = new SelectFormat();
selFmt2 = new SelectFormat(SIMPLE_PATTERN);
assertEquals("Failed in TestHashCode 1 with unexpected output"
, selFmt.hashCode(), selFmt1.hashCode() );
assertNotEquals("Failed in TestHashCode 2 with unexpected output"
, selFmt.hashCode(), selFmt2.hashCode() );
} catch (Exception e){
errln("Exception encountered in TestHashCode 3 with message : "
+ e.getMessage());
}
//Check hashCode for pattern constructed SelectFormat
try {
selFmt = new SelectFormat(SIMPLE_PATTERN);
selFmt1 = new SelectFormat(SIMPLE_PATTERN);
selFmt2 = new SelectFormat();
assertEquals("Failed in TestHashCode 4 with unexpected output"
, selFmt.hashCode(), selFmt1.hashCode() );
assertNotEquals("Failed in TestHashCode 5 with unexpected output"
, selFmt.hashCode(), selFmt2.hashCode() );
} catch (Exception e){
errln("Exception encountered in TestHashCode 6 with message : "
+ e.getMessage());
}
}
/**
* API tests for toPattern() method
*/
public void TestToPattern(){
log("Inside TestToPattern");
SelectFormat selFmt = null;
//Check toPattern for Default constructed SelectFormat
try {
selFmt = new SelectFormat();
assertEquals("Failed in TestToPattern 1 with unexpected output"
, null, selFmt.toPattern() );
} catch (Exception e){
errln("Exception encountered in TestToPattern 1 with message : "
+ e.getMessage());
}
//Check toPattern for pattern constructed SelectFormat
try {
selFmt = new SelectFormat(SIMPLE_PATTERN);
assertEquals("Failed in TestToPattern 2 with unexpected output"
, SIMPLE_PATTERN, selFmt.toPattern() );
} catch (Exception e){
errln("Exception encountered in TestToPattern 2 with message : "
+ e.getMessage());
}
}
/**
* API tests for format() method
*/
public void TestFormat(){
log("Inside TestFormat");
//Check format for pattern constructed object
try {
SelectFormat selFmt1 = new SelectFormat(SIMPLE_PATTERN);
String expected = "feminineVerbValue";
assertEquals("Failed in TestFormat with unexpected output 1"
, expected
, selFmt1.format("feminine") );
} catch (Exception e){
errln("Exception encountered in TestFormat 3: " + e.getMessage() );
}
//Check format with appendTo for pattern constructed object
try {
SelectFormat selFmt1 = new SelectFormat(SIMPLE_PATTERN);
StringBuffer expected = new StringBuffer("AppendHere-otherVerbValue");
StringBuffer strBuf = new StringBuffer("AppendHere-");
assertEquals("Failed in TestFormat with unexpected output 2"
, expected.toString()
, (selFmt1.format("other",strBuf, new FieldPosition(0))).toString() );
} catch (Exception e){
errln("Exception encountered in TestFormat 2: " + e.getMessage() );
}
//Check format for Default constructed object
SelectFormat selFmt1 = new SelectFormat();
try {
selFmt1.format("feminine");
fail("Failed in TestFormat 3 as did not receive the expected IllegalStateException.");
} catch (IllegalStateException e){
String expected = "Invalid format error.";
assertEquals("Failed in TestFormat 3 with unexpected excpetion message"
, expected , e.getMessage() );
} catch (Exception e){
fail("Failed in TestFormat 3 with exception as " + e.getMessage());
}
//Check format with appendTo for Default constructed object
try {
StringBuffer strBuf = new StringBuffer("AppendHere-");
selFmt1.format("other",strBuf, new FieldPosition(0));
fail("Failed in TestFormat 4 as did not receive the expected IllegalStateException.");
} catch (IllegalStateException e){
String expected = "Invalid format error.";
assertEquals("Failed in TestFormat 4 with unexpected excpetion message"
, expected , e.getMessage() );
} catch (Exception e){
fail("Failed in TestFormat 4 with exception as " + e.getMessage());
}
}
/**
* API tests for parseObject() method
*/
public void TestParseObject(){
log("Inside TestToPattern");
System.out.println("Inside TestToPattern");
//Check parseObject for Default constructed SelectFormat
try {
SelectFormat selFmt = new SelectFormat();
selFmt.parseObject("feminine", new ParsePosition(0) );
fail("Failed in TestParseObject - UnsupportedOperationException not received");
} catch (UnsupportedOperationException e){
//Expect this Exception
} catch (Exception e){
errln("Exception encountered in TestParseObject with message : "
+ e.getMessage());
}
}
}

View file

@ -0,0 +1,191 @@
/*
*******************************************************************************
* Copyright (c) 2004-2010, International Business Machines
* Corporation and others. All Rights Reserved.
* Copyright (C) 2010 , Yahoo! Inc.
*******************************************************************************
*/
package com.ibm.icu.dev.test.format;
import com.ibm.icu.dev.test.TestFmwk;
import com.ibm.icu.impl.Utility;
import com.ibm.icu.text.SelectFormat;
import java.text.FieldPosition;
import java.util.HashMap;
import java.util.Map;
/**
* @author kirtig
* This class does the unit testing for the SelectFormat
*/
public class SelectFormatUnitTest extends TestFmwk {
static final String SIMPLE_PATTERN = "feminine {feminineVerbValue} other{otherVerbValue}";
static final int SELECT_PATTERN_DATA = 4 ;
static final int SELECT_SYNTAX_DATA = 10 ;
public static void main(String[] args) throws Exception {
new SelectFormatUnitTest().run(args);
}
/**
* Unit tests for pattern syntax
*/
public void TestPatternSyntax() {
log("Inside TestPatternSyntax");
System.out.println("\nInside TestPatternSyntax");
String checkSyntaxData[] = {
"odd{foo} odd{bar} other{foobar}",
"odd{foo} other{bar} other{foobar}",
"odd{foo}",
"1odd{foo} other{bar}",
"odd{foo},other{bar}",
"od d{foo} other{bar}",
"odd{foo}{foobar}other{foo}",
"odd{foo1}other{foo2}}",
"odd{foo1}other{{foo2}",
"odd{fo{o1}other{foo2}}"
};
String expectedErrorMsgs[] = {
"Duplicate keyword error.",
"Duplicate keyword error.",
"Pattern syntax error. Value for case \"other\" was not defined. ",
"Pattern syntax error.",
"Pattern syntax error.",
"Pattern syntax error.",
"Pattern syntax error.",
"Pattern syntax error.",
"Pattern syntax error.",
"Pattern syntax error. Value for case \"other\" was not defined. ",
};
//Test SelectFormat pattern syntax
try {
SelectFormat selFmt = new SelectFormat();
for (int i=0; i<SELECT_SYNTAX_DATA; ++i) {
try {
selFmt.applyPattern(checkSyntaxData[i]);
errln("\nERROR: Unexpected result - SelectFormat Unit Test failed "
+ "to detect syntax error with pattern: "+checkSyntaxData[i]);
} catch (IllegalArgumentException e){
assertEquals("Error:TestPatternSyntax failed with unexpected"
+ " error message for pattern: " + checkSyntaxData[i] ,
expectedErrorMsgs[i], e.getMessage() );
continue;
}
}
} catch (Exception e){
errln("Exception encountered in TestPatternSyntax ");
}
}
/**
* Unit tests for invalid keywords
*/
public void TestInvalidKeyword() {
//Test formatting with invalid keyword
log("Inside TestInvalidKeyword");
System.out.println("\nInside TestInvalidKeyword");
String keywords[] = {
"9Keyword-_", //Starts with a digit
"-Keyword-_", //Starts with a hyphen
"_Keyword-_", //Starts with an underscore
"\\u00E9Keyword-_", //Starts with non-ASCII character
"Key*word-_", //Contains a sepial character not allowed
"*Keyword-_" //Starts with a sepial character not allowed
};
String expected = "Invalid formatting argument.";
SelectFormat selFmt = new SelectFormat(SIMPLE_PATTERN);
for (int i = 0; i< 6; i++ ){
try {
selFmt.format( keywords[i]);
fail("Error:TestInvalidKeyword failed to detect invalid keyword "
+ "for keyword: " + keywords[i] );
} catch (IllegalArgumentException e){
assertEquals("Error:TestInvalidKeyword failed with unexpected "
+"error message for keyword: " + keywords[i]
, expected , e.getMessage() );
continue;
} catch (Exception e){
errln("ERROR:TestInvalidKeyword failed with an invalid keyword: "
+ keywords[i] + " with exception: " + e.getMessage() );
}
}
}
/**
* API tests for applyPattern and format
*/
public void TestApplyFormat() {
//Test applying and formatting with various pattern
log("Inside TestApplyFormat");
System.out.println("\nInside TestApplyFormat");
String patternTestData[] = {
"fem {femValue} other{even}",
"other{odd or even}",
"odd{The number {0, number, integer} is odd.}other{The number {0, number, integer} is even.}",
"odd{The number {1} is odd}other{The number {1} is even}"
};
String formatArgs[] = {
"fem",
"other",
"odd"
};
String expFormatResult[][] = {
{
"femValue",
"even",
"even",
},
{
"odd or even",
"odd or even",
"odd or even",
},
{
"The number {0, number, integer} is even.",
"The number {0, number, integer} is even.",
"The number {0, number, integer} is odd.",
},
{
"The number {1} is even",
"The number {1} is even",
"The number {1} is odd",
}
};
log("SelectFormat Unit test: Testing applyPattern() and format() ...");
SelectFormat selFmt = null;
try {
selFmt = new SelectFormat();
} catch (Exception e){
errln("Exception encountered in TestApplyFormat ");
}
for (int i=0; i<SELECT_PATTERN_DATA; ++i) {
try {
selFmt.applyPattern(patternTestData[i]);
} catch (Exception e){
errln("ERROR: SelectFormat Unit Test failed to apply pattern- "
+ patternTestData[i] );
continue;
}
//Format with the keyword array
for (int j=0; j<3; j++) {
assertEquals("ERROR: SelectFormat Unit test failed in format() with unexpected result", selFmt.format(formatArgs[j]) ,expFormatResult[i][j] );
}
}
}
}

View file

@ -1,7 +1,8 @@
/*
*******************************************************************************
* Copyright (C) 1996-2009, International Business Machines Corporation and *
* others. All Rights Reserved. *
* Copyright (c) 2004-2010, International Business Machines
* Corporation and others. All Rights Reserved.
* Copyright (C) 2010 , Yahoo! Inc.
*******************************************************************************
*/
package com.ibm.icu.dev.test.format;
@ -25,10 +26,11 @@ public class TestAll extends TestGroup {
"TestAll$DateFormat",
"TestAll$DateIntervalFormat",
"TestAll$TimeUnitFormat",
"TestAll$MessageFormat",
"TestAll$PluralFormat",
"com.ibm.icu.dev.test.format.BigNumberFormatTest",
"DataDrivenFormatTest"
"DataDrivenFormatTest",
"TestAll$PluralFormat",
"TestAll$MessageFormat",
"TestAll$SelectFormat"
},
"Formatting Tests");
}
@ -106,6 +108,15 @@ public class TestAll extends TestGroup {
}
}
public static class SelectFormat extends TestGroup {
public SelectFormat() {
super(new String[] {
"SelectFormatUnitTest",
"SelectFormatAPITest",
});
}
}
public static class MessageFormat extends TestGroup {
public MessageFormat() {
super(new String[] {

View file

@ -1,6 +1,6 @@
/*
**********************************************************************
* Copyright (c) 2004-2009, International Business Machines
* Copyright (c) 2004-2010, International Business Machines
* Corporation and others. All Rights Reserved.
**********************************************************************
* Author: Alan Liu
@ -1324,6 +1324,174 @@ public class TestMessageFormat extends com.ibm.icu.dev.test.TestFmwk {
}
}
/**
* This tests SelectFormats used inside MessageFormats.
*/
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
*/
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
public void TestNullArgs() {

View file

@ -1,11 +1,10 @@
/*
*******************************************************************************
* Copyright (C) 1996-2009, International Business Machines Corporation and *
* others. All Rights Reserved. *
* Copyright (c) 2004-2010, International Business Machines
* Corporation and others. All Rights Reserved.
*******************************************************************************
*
*/
package com.ibm.icu.dev.test.serializable;
import java.text.AttributedCharacterIterator;
@ -25,6 +24,7 @@ import com.ibm.icu.text.DecimalFormat;
import com.ibm.icu.text.DecimalFormatSymbols;
import com.ibm.icu.text.DurationFormat;
import com.ibm.icu.text.MessageFormat;
import com.ibm.icu.text.SelectFormat;
import com.ibm.icu.text.NumberFormat;
import com.ibm.icu.text.PluralFormat;
import com.ibm.icu.text.PluralRules;
@ -2087,6 +2087,23 @@ public class FormatTests
}
}
public static class SelectFormatHandler implements SerializableTest.Handler {
public Object[] getTestObjects() {
SelectFormat[] selfmts = {new SelectFormat("keyword{phrase} other{otherPhrase}")};
return selfmts;
}
public boolean hasSameBehavior(Object a, Object b) {
SelectFormat sfa = (SelectFormat) a;
SelectFormat sfb = (SelectFormat) b;
String argument = "keyword";
return sfa.format(argument) != sfb.format(argument);
}
}
public static class PluralFormatHandler implements SerializableTest.Handler {
public Object[] getTestObjects() {
Locale[] locales = { Locale.US }; // main test is in plural rules handler
@ -2153,16 +2170,6 @@ public class FormatTests
}
}
public static class SelectFormatHandler implements SerializableTest.Handler {
// TODO - add real test case here!
public Object[] getTestObjects() {
return new Object[] { new TimeUnitFormat().setLocale(ULocale.ENGLISH) };
}
public boolean hasSameBehavior(Object a, Object b) {
return true;
}
}
public static void main(String[] args)
{
// nothing needed...