+void IntlTestRBNF::TestPluralRules() {
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString enRules("%digits-ordinal:-x: ->>;0: =#,##0=$(ordinal,one{st}two{nd}few{rd}other{th})$;");
+ UParseError parseError;
+ RuleBasedNumberFormat enFormatter(enRules, Locale::getEnglish(), parseError, status);
+ if (U_FAILURE(status)) {
+ dataerrln("Unable to create RuleBasedNumberFormat - " + UnicodeString(u_errorName(status)));
+ return;
+ }
+ const char* const enTestData[][2] = {
+ { "1", "1st" },
+ { "2", "2nd" },
+ { "3", "3rd" },
+ { "4", "4th" },
+ { "11", "11th" },
+ { "12", "12th" },
+ { "13", "13th" },
+ { "14", "14th" },
+ { "21", "21st" },
+ { "22", "22nd" },
+ { "23", "23rd" },
+ { "24", "24th" },
+ { NULL, NULL }
+ };
+
+ doTest(&enFormatter, enTestData, TRUE);
+
+ // 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.
+ UnicodeString ruRules("%spellout-numbering:"
+ "-x: minus >>;"
+ "x.x: << point >>;"
+ "0: zero;"
+ "1: one;"
+ "2: two;"
+ "3: three;"
+ "4: four;"
+ "5: five;"
+ "6: six;"
+ "7: seven;"
+ "8: eight;"
+ "9: nine;"
+ "10: ten;"
+ "11: eleven;"
+ "12: twelve;"
+ "13: thirteen;"
+ "14: fourteen;"
+ "15: fifteen;"
+ "16: sixteen;"
+ "17: seventeen;"
+ "18: eighteen;"
+ "19: nineteen;"
+ "20: twenty[->>];"
+ "30: thirty[->>];"
+ "40: forty[->>];"
+ "50: fifty[->>];"
+ "60: sixty[->>];"
+ "70: seventy[->>];"
+ "80: eighty[->>];"
+ "90: ninety[->>];"
+ "100: hundred[ >>];"
+ "200: << hundred[ >>];"
+ "300: << hundreds[ >>];"
+ "500: << hundredss[ >>];"
+ "1000: << $(cardinal,one{thousand}few{thousands}other{thousandss})$[ >>];"
+ "1000000: << $(cardinal,one{million}few{millions}other{millionss})$[ >>];");
+ RuleBasedNumberFormat ruFormatter(ruRules, Locale("ru"), parseError, status);
+ const char* const ruTestData[][2] = {
+ { "1", "one" },
+ { "100", "hundred" },
+ { "125", "hundred twenty-five" },
+ { "399", "three hundreds ninety-nine" },
+ { "1,000", "one thousand" },
+ { "1,001", "one thousand one" },
+ { "2,000", "two thousands" },
+ { "2,001", "two thousands one" },
+ { "2,002", "two thousands two" },
+ { "3,333", "three thousands three hundreds thirty-three" },
+ { "5,000", "five thousandss" },
+ { "11,000", "eleven thousandss" },
+ { "21,000", "twenty-one thousand" },
+ { "22,000", "twenty-two thousands" },
+ { "25,001", "twenty-five thousandss one" },
+ { NULL, NULL }
+ };
+
+ if (U_FAILURE(status)) {
+ errln("Unable to create RuleBasedNumberFormat - " + UnicodeString(u_errorName(status)));
+ return;
+ }
+ doTest(&ruFormatter, ruTestData, TRUE);
+
+ // Make sure there are no divide by 0 errors.
+ UnicodeString result;
+ RuleBasedNumberFormat(ruRules, Locale("ru"), parseError, status).format((int32_t)21000, result);
+ if (result.compare(UNICODE_STRING_SIMPLE("twenty-one thousand")) != 0) {
+ errln("Got " + result + " for 21000");
+ }
+
+}
+
+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::TestLargeNumbers() {
+ UErrorCode status = U_ZERO_ERROR;
+ RuleBasedNumberFormat rbnf(URBNF_SPELLOUT, Locale::getEnglish(), status);
+
+ const char * const enTestFullData[][2] = {
+ {"-9007199254740991", "minus nine quadrillion seven trillion one hundred ninety-nine billion two hundred fifty-four million seven hundred forty thousand nine hundred ninety-one"}, // Maximum precision in both a double and a long
+ {"9007199254740991", "nine quadrillion seven trillion one hundred ninety-nine billion two hundred fifty-four million seven hundred forty thousand nine hundred ninety-one"}, // Maximum precision in both a double and a long
+ {"-9007199254740992", "minus nine quadrillion seven trillion one hundred ninety-nine billion two hundred fifty-four million seven hundred forty thousand nine hundred ninety-two"}, // Only precisely contained in a long
+ {"9007199254740992", "nine quadrillion seven trillion one hundred ninety-nine billion two hundred fifty-four million seven hundred forty thousand nine hundred ninety-two"}, // Only precisely contained in a long
+ {"9999999999999998", "nine quadrillion nine hundred ninety-nine trillion nine hundred ninety-nine billion nine hundred ninety-nine million nine hundred ninety-nine thousand nine hundred ninety-eight"},
+ {"9999999999999999", "nine quadrillion nine hundred ninety-nine trillion nine hundred ninety-nine billion nine hundred ninety-nine million nine hundred ninety-nine thousand nine hundred ninety-nine"},
+ {"999999999999999999", "nine hundred ninety-nine quadrillion nine hundred ninety-nine trillion nine hundred ninety-nine billion nine hundred ninety-nine million nine hundred ninety-nine thousand nine hundred ninety-nine"},
+ {"1000000000000000000", "1,000,000,000,000,000,000"}, // The rules don't go to 1 quintillion yet
+ {"-9223372036854775809", "-9,223,372,036,854,775,809"}, // We've gone beyond 64-bit precision
+ {"-9223372036854775808", "-9,223,372,036,854,775,808"}, // We've gone beyond +64-bit precision
+ {"-9223372036854775807", "minus 9,223,372,036,854,775,807"}, // Minimum 64-bit precision
+ {"-9223372036854775806", "minus 9,223,372,036,854,775,806"}, // Minimum 64-bit precision + 1
+ {"9223372036854774111", "9,223,372,036,854,774,111"}, // Below 64-bit precision
+ {"9223372036854774999", "9,223,372,036,854,774,999"}, // Below 64-bit precision
+ {"9223372036854775000", "9,223,372,036,854,775,000"}, // Below 64-bit precision
+ {"9223372036854775806", "9,223,372,036,854,775,806"}, // Maximum 64-bit precision - 1
+ {"9223372036854775807", "9,223,372,036,854,775,807"}, // Maximum 64-bit precision
+ {"9223372036854775808", "9,223,372,036,854,775,808"}, // We've gone beyond 64-bit precision. This can only be represented with BigDecimal.
+ { NULL, NULL }
+ };
+ doTest(&rbnf, enTestFullData, false);
+}
+
+void IntlTestRBNF::TestCompactDecimalFormatStyle() {
+ UErrorCode status = U_ZERO_ERROR;
+ UParseError parseError;
+ // This is not a common use case, but we're testing it anyway.
+ UnicodeString numberPattern("=###0.#####=;"
+ "1000: <###0.00< K;"
+ "1000000: <###0.00< M;"
+ "1000000000: <###0.00< B;"
+ "1000000000000: <###0.00< T;"
+ "1000000000000000: <###0.00< Q;");
+ RuleBasedNumberFormat rbnf(numberPattern, UnicodeString(), Locale::getEnglish(), parseError, status);
+
+ const char * const enTestFullData[][2] = {
+ {"1000", "1.00 K"},
+ {"1234", "1.23 K"},
+ {"999994", "999.99 K"},
+ {"999995", "1000.00 K"},
+ {"1000000", "1.00 M"},
+ {"1200000", "1.20 M"},
+ {"1200000000", "1.20 B"},
+ {"1200000000000", "1.20 T"},
+ {"1200000000000000", "1.20 Q"},
+ {"4503599627370495", "4.50 Q"},
+ {"4503599627370496", "4.50 Q"},
+ {"8990000000000000", "8.99 Q"},
+ {"9008000000000000", "9.00 Q"}, // Number doesn't precisely fit into a double
+ {"9456000000000000", "9.00 Q"}, // Number doesn't precisely fit into a double
+ {"10000000000000000", "10.00 Q"}, // Number doesn't precisely fit into a double
+ {"9223372036854775807", "9223.00 Q"}, // Maximum 64-bit precision
+ {"9223372036854775808", "9,223,372,036,854,775,808"}, // We've gone beyond 64-bit precision. This can only be represented with BigDecimal.
+ { NULL, NULL }
+ };
+ doTest(&rbnf, enTestFullData, false);
+}