Index: source/test/intltest/itrbnf.cpp |
diff --git a/source/test/intltest/itrbnf.cpp b/source/test/intltest/itrbnf.cpp |
index fcd6cbf149fb554e00df5feaf171c1a66cd5a338..8b27d94fc66ceaf0ea75cbe982b242503ef96ee0 100644 |
--- a/source/test/intltest/itrbnf.cpp |
+++ b/source/test/intltest/itrbnf.cpp |
@@ -1,6 +1,6 @@ |
/* |
******************************************************************************* |
- * Copyright (C) 1996-2014, International Business Machines Corporation and * |
+ * Copyright (C) 1996-2015, International Business Machines Corporation and * |
* others. All Rights Reserved. * |
******************************************************************************* |
*/ |
@@ -19,6 +19,7 @@ |
#include "unicode/ustring.h" |
#include "unicode/decimfmt.h" |
#include "unicode/udata.h" |
+#include "putilimp.h" |
#include "testutil.h" |
#include <string.h> |
@@ -66,6 +67,9 @@ void IntlTestRBNF::runIndexedTest(int32_t index, UBool exec, const char* &name, |
TESTCASE(18, TestMultiplierSubstitution); |
TESTCASE(19, TestSetDecimalFormatSymbols); |
TESTCASE(20, TestPluralRules); |
+ TESTCASE(21, TestMultiplePluralRules); |
+ TESTCASE(22, TestInfinityNaN); |
+ TESTCASE(23, TestVariableDecimalPoint); |
#else |
TESTCASE(0, TestRBNFDisabled); |
#endif |
@@ -341,6 +345,72 @@ IntlTestRBNF::TestAPI() { |
delete formatter; |
} |
+/** |
+ * Perform a simple spot check on the parsing going into an infinite loop for alternate rules. |
+ */ |
+void IntlTestRBNF::TestMultiplePluralRules() { |
+ // This is trying to model the feminine form, but don't worry about the details too much. |
+ // We're trying to test the plural rules where there are different prefixes. |
+ UnicodeString rules("%spellout-cardinal-feminine-genitive:" |
+ "0: zero;" |
+ "1: ono;" |
+ "2: two;" |
+ "1000: << $(cardinal,one{thousand}few{thousanF}other{thousanO})$[ >>];" |
+ "%spellout-cardinal-feminine:" |
+ "x.x: [<< $(cardinal,one{singleton}other{plurality})$ ]>%%fractions>;" |
+ "0: zero;" |
+ "1: one;" |
+ "2: two;" |
+ "1000: << $(cardinal,one{thousand}few{thousanF}other{thousanO})$[ >>];" |
+ "%%fractions:" |
+ "10: <%spellout-cardinal-feminine< $(cardinal,one{oneth}other{tenth})$;" |
+ "100: <%spellout-cardinal-feminine< $(cardinal,one{1hundredth}other{hundredth})$;"); |
+ UErrorCode status = U_ZERO_ERROR; |
+ UParseError pError; |
+ RuleBasedNumberFormat formatter(rules, Locale("ru"), pError, status); |
+ Formattable result; |
+ UnicodeString resultStr; |
+ FieldPosition pos; |
+ |
+ if (U_FAILURE(status)) { |
+ dataerrln("Unable to create formatter - %s", u_errorName(status)); |
+ return; |
+ } |
+ |
+ formatter.parse(formatter.format(1000.0, resultStr, pos, status), result, status); |
+ if (1000 != result.getLong() || resultStr != UNICODE_STRING_SIMPLE("one thousand")) { |
+ errln("RuleBasedNumberFormat did not return the correct value. Got: %d", result.getLong()); |
+ errln(resultStr); |
+ } |
+ resultStr.remove(); |
+ formatter.parse(formatter.format(1000.0, UnicodeString("%spellout-cardinal-feminine-genitive"), resultStr, pos, status), result, status); |
+ if (1000 != result.getLong() || resultStr != UNICODE_STRING_SIMPLE("ono thousand")) { |
+ errln("RuleBasedNumberFormat(cardinal-feminine-genitive) did not return the correct value. Got: %d", result.getLong()); |
+ errln(resultStr); |
+ } |
+ resultStr.remove(); |
+ formatter.parse(formatter.format(1000.0, UnicodeString("%spellout-cardinal-feminine"), resultStr, pos, status), result, status); |
+ if (1000 != result.getLong() || resultStr != UNICODE_STRING_SIMPLE("one thousand")) { |
+ errln("RuleBasedNumberFormat(spellout-cardinal-feminine) did not return the correct value. Got: %d", result.getLong()); |
+ errln(resultStr); |
+ } |
+ static const char* const testData[][2] = { |
+ { "0", "zero" }, |
+ { "1", "one" }, |
+ { "2", "two" }, |
+ { "0.1", "one oneth" }, |
+ { "0.2", "two tenth" }, |
+ { "1.1", "one singleton one oneth" }, |
+ { "1.2", "one singleton two tenth" }, |
+ { "2.1", "two plurality one oneth" }, |
+ { "2.2", "two plurality two tenth" }, |
+ { "0.01", "one 1hundredth" }, |
+ { "0.02", "two hundredth" }, |
+ { NULL, NULL } |
+ }; |
+ doTest(&formatter, testData, TRUE); |
+} |
+ |
void IntlTestRBNF::TestFractionalRuleSet() |
{ |
UnicodeString fracRules( |
@@ -426,7 +496,7 @@ void IntlTestRBNF::TestFractionalRuleSet() |
{ "1.2856", "1 2/7" }, |
{ NULL, NULL } |
}; |
- doTest(&formatter, testData, FALSE); // exact values aren't parsable from fractions |
+ doTest(&formatter, testData, FALSE); // exact values aren't parsable from fractions |
} |
} |
@@ -2060,6 +2130,93 @@ void IntlTestRBNF::TestPluralRules() { |
} |
+void IntlTestRBNF::TestInfinityNaN() { |
+ UErrorCode status = U_ZERO_ERROR; |
+ UParseError parseError; |
+ UnicodeString enRules("%default:" |
+ "-x: minus >>;" |
+ "Inf: infinite;" |
+ "NaN: not a number;" |
+ "0: =#,##0=;"); |
+ RuleBasedNumberFormat enFormatter(enRules, Locale::getEnglish(), parseError, status); |
+ const char * const enTestData[][2] = { |
+ {"1", "1"}, |
+ {"\\u221E", "infinite"}, |
+ {"-\\u221E", "minus infinite"}, |
+ {"NaN", "not a number"}, |
+ { NULL, NULL } |
+ }; |
+ if (U_FAILURE(status)) { |
+ dataerrln("Unable to create RuleBasedNumberFormat - " + UnicodeString(u_errorName(status))); |
+ return; |
+ } |
+ |
+ doTest(&enFormatter, enTestData, true); |
+ |
+ // Test the default behavior when the rules are undefined. |
+ UnicodeString enRules2("%default:" |
+ "-x: ->>;" |
+ "0: =#,##0=;"); |
+ RuleBasedNumberFormat enFormatter2(enRules2, Locale::getEnglish(), parseError, status); |
+ if (U_FAILURE(status)) { |
+ errln("Unable to create RuleBasedNumberFormat - " + UnicodeString(u_errorName(status))); |
+ return; |
+ } |
+ const char * const enDefaultTestData[][2] = { |
+ {"1", "1"}, |
+ {"\\u221E", "\\u221E"}, |
+ {"-\\u221E", "-\\u221E"}, |
+ {"NaN", "NaN"}, |
+ { NULL, NULL } |
+ }; |
+ |
+ doTest(&enFormatter2, enDefaultTestData, true); |
+} |
+ |
+void IntlTestRBNF::TestVariableDecimalPoint() { |
+ UErrorCode status = U_ZERO_ERROR; |
+ UParseError parseError; |
+ UnicodeString enRules("%spellout-numbering:" |
+ "-x: minus >>;" |
+ "x.x: << point >>;" |
+ "x,x: << comma >>;" |
+ "0.x: xpoint >>;" |
+ "0,x: xcomma >>;" |
+ "0: zero;" |
+ "1: one;" |
+ "2: two;" |
+ "3: three;" |
+ "4: four;" |
+ "5: five;" |
+ "6: six;" |
+ "7: seven;" |
+ "8: eight;" |
+ "9: nine;"); |
+ RuleBasedNumberFormat enFormatter(enRules, Locale::getEnglish(), parseError, status); |
+ const char * const enTestPointData[][2] = { |
+ {"1.1", "one point one"}, |
+ {"1.23", "one point two three"}, |
+ {"0.4", "xpoint four"}, |
+ { NULL, NULL } |
+ }; |
+ if (U_FAILURE(status)) { |
+ dataerrln("Unable to create RuleBasedNumberFormat - " + UnicodeString(u_errorName(status))); |
+ return; |
+ } |
+ doTest(&enFormatter, enTestPointData, true); |
+ |
+ DecimalFormatSymbols decimalFormatSymbols(Locale::getEnglish(), status); |
+ decimalFormatSymbols.setSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol, UNICODE_STRING_SIMPLE(",")); |
+ enFormatter.setDecimalFormatSymbols(decimalFormatSymbols); |
+ const char * const enTestCommaData[][2] = { |
+ {"1.1", "one comma one"}, |
+ {"1.23", "one comma two three"}, |
+ {"0.4", "xcomma four"}, |
+ { NULL, NULL } |
+ }; |
+ doTest(&enFormatter, enTestCommaData, true); |
+} |
+ |
void |
IntlTestRBNF::doTest(RuleBasedNumberFormat* formatter, const char* const testData[][2], UBool testParsing) |
{ |
@@ -2078,7 +2235,8 @@ IntlTestRBNF::doTest(RuleBasedNumberFormat* formatter, const char* const testDat |
log("[%i] %s = ", i, numString); |
Formattable expectedNumber; |
- decFmt.parse(numString, expectedNumber, status); |
+ UnicodeString escapedNumString = UnicodeString(numString, -1, US_INV).unescape(); |
+ decFmt.parse(escapedNumString, expectedNumber, status); |
if (U_FAILURE(status)) { |
errln("FAIL: decFmt could not parse %s", numString); |
break; |
@@ -2115,7 +2273,9 @@ IntlTestRBNF::doTest(RuleBasedNumberFormat* formatter, const char* const testDat |
errln(msg); |
break; |
} else { |
- if (parsedNumber != expectedNumber) { |
+ if (parsedNumber != expectedNumber |
+ && (!uprv_isNaN(parsedNumber.getDouble()) || !uprv_isNaN(expectedNumber.getDouble()))) |
+ { |
UnicodeString msg = "FAIL: parse failed for "; |
msg.append(actualString); |
msg.append(", expected "); |