]> git.saurik.com Git - apple/icu.git/blobdiff - icuSources/test/intltest/itrbnf.cpp
ICU-57149.0.1.tar.gz
[apple/icu.git] / icuSources / test / intltest / itrbnf.cpp
index 44ff350170718cc9a0f4557d9ca172ced9bf1cbd..ce731928a80648300df613fb95073ca2a2fdd7e7 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *******************************************************************************
- * Copyright (C) 1996-2010, International Business Machines Corporation and    *
- * others. All Rights Reserved.                                                *
+ * Copyright (C) 1996-2016, International Business Machines Corporation and
+ * others. All Rights Reserved.
  *******************************************************************************
  */
 
 #include "unicode/ustring.h"
 #include "unicode/decimfmt.h"
 #include "unicode/udata.h"
+#include "cmemory.h"
+#include "putilimp.h"
 #include "testutil.h"
 
-//#include "llong.h"
-
 #include <string.h>
 
 // import com.ibm.text.RuleBasedNumberFormat;
@@ -66,6 +66,11 @@ void IntlTestRBNF::runIndexedTest(int32_t index, UBool exec, const char* &name,
         TESTCASE(16, TestHebrewFraction);
         TESTCASE(17, TestPortugueseSpellout);
         TESTCASE(18, TestMultiplierSubstitution);
+        TESTCASE(19, TestSetDecimalFormatSymbols);
+        TESTCASE(20, TestPluralRules);
+        TESTCASE(21, TestMultiplePluralRules);
+        TESTCASE(22, TestInfinityNaN);
+        TESTCASE(23, TestVariableDecimalPoint);
 #else
         TESTCASE(0, TestRBNFDisabled);
 #endif
@@ -383,6 +388,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(
@@ -468,7 +539,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
     }
 }
 
@@ -931,7 +1002,7 @@ void IntlTestRBNF::TestLLong()
             &NEG_TWO_TO_32X5, &TWO_TO_32, &NEG_FIVE
         };
         const int TUPLE_WIDTH = 3;
-        const int TUPLE_COUNT = (int)(sizeof(tuples)/sizeof(tuples[0]))/TUPLE_WIDTH;
+        const int TUPLE_COUNT = UPRV_LENGTHOF(tuples)/TUPLE_WIDTH;
         for (int i = 0; i < TUPLE_COUNT; ++i) {
             const llong lhs = *tuples[i*TUPLE_WIDTH+0];
             const llong rhs = *tuples[i*TUPLE_WIDTH+1];
@@ -1011,7 +1082,7 @@ void IntlTestRBNF::TestLLong()
             &BIG_FIVEp1, &FIVE, &ONE
         };
         const int TUPLE_WIDTH = 3;
-        const int TUPLE_COUNT = (int)(sizeof(tuples)/sizeof(tuples[0]))/TUPLE_WIDTH;
+        const int TUPLE_COUNT = UPRV_LENGTHOF(tuples)/TUPLE_WIDTH;
         for (int i = 0; i < TUPLE_COUNT; ++i) {
             const llong lhs = *tuples[i*TUPLE_WIDTH+0];
             const llong rhs = *tuples[i*TUPLE_WIDTH+1];
@@ -1291,20 +1362,20 @@ IntlTestRBNF::TestFrenchSpellout()
             { "80", "quatre-vingts" },
             { "88", "quatre-vingt-huit" },
             { "100", "cent" },
-            { "106", "cent-six" },
-            { "127", "cent-vingt-sept" },
-            { "200", "deux-cents" },
-            { "579", "cinq-cent-soixante-dix-neuf" },
+            { "106", "cent six" },
+            { "127", "cent vingt-sept" },
+            { "200", "deux cents" },
+            { "579", "cinq cent soixante-dix-neuf" },
             { "1,000", "mille" },
-            { "1,123", "mille-cent-vingt-trois" },
-            { "1,594", "mille-cinq-cent-quatre-vingt-quatorze" },
-            { "2,000", "deux-mille" },
-            { "3,004", "trois-mille-quatre" },
-            { "4,567", "quatre-mille-cinq-cent-soixante-sept" },
-            { "15,943", "quinze-mille-neuf-cent-quarante-trois" },
-            { "2,345,678", "deux millions trois-cent-quarante-cinq-mille-six-cent-soixante-dix-huit" },
+            { "1,123", "mille cent vingt-trois" },
+            { "1,594", "mille cinq cent quatre-vingt-quatorze" },
+            { "2,000", "deux mille" },
+            { "3,004", "trois mille quatre" },
+            { "4,567", "quatre mille cinq cent soixante-sept" },
+            { "15,943", "quinze mille neuf cent quarante-trois" },
+            { "2,345,678", "deux millions trois cent quarante-cinq mille six cent soixante-dix-huit" },
             { "-36", "moins trente-six" },
-            { "234.567", "deux-cent-trente-quatre virgule cinq six sept" },
+            { "234.567", "deux cent trente-quatre virgule cinq six sept" },
             { NULL, NULL}
         };
         
@@ -1336,20 +1407,20 @@ static const char* const swissFrenchTestData[][2] = {
     { "80", "huitante" },
     { "88", "huitante-huit" },
     { "100", "cent" },
-    { "106", "cent-six" },
-    { "127", "cent-vingt-sept" },
-    { "200", "deux-cents" },
-    { "579", "cinq-cent-septante-neuf" },
+    { "106", "cent six" },
+    { "127", "cent vingt-sept" },
+    { "200", "deux cents" },
+    { "579", "cinq cent septante-neuf" },
     { "1,000", "mille" },
-    { "1,123", "mille-cent-vingt-trois" },
-    { "1,594", "mille-cinq-cent-nonante-quatre" },
-    { "2,000", "deux-mille" },
-    { "3,004", "trois-mille-quatre" },
-    { "4,567", "quatre-mille-cinq-cent-soixante-sept" },
-    { "15,943", "quinze-mille-neuf-cent-quarante-trois" },
-    { "2,345,678", "deux millions trois-cent-quarante-cinq-mille-six-cent-septante-huit" },
+    { "1,123", "mille cent vingt-trois" },
+    { "1,594", "mille cinq cent nonante-quatre" },
+    { "2,000", "deux mille" },
+    { "3,004", "trois mille quatre" },
+    { "4,567", "quatre mille cinq cent soixante-sept" },
+    { "15,943", "quinze mille neuf cent quarante-trois" },
+    { "2,345,678", "deux millions trois cent quarante-cinq mille six cent septante-huit" },
     { "-36", "moins trente-six" },
-    { "234.567", "deux-cent-trente-quatre virgule cinq six sept" },
+    { "234.567", "deux cent trente-quatre virgule cinq six sept" },
     { NULL, NULL}
 };
 
@@ -1379,25 +1450,25 @@ static const char* const belgianFrenchTestData[][2] = {
     { "71", "septante-et-un" },
     { "73", "septante-trois" },
     { "80", "quatre-vingts" },
-    { "88", "quatre-vingt-huit" },
+    { "88", "quatre-vingt huit" },
     { "90", "nonante" },
     { "91", "nonante-et-un" },
     { "95", "nonante-cinq" },
     { "100", "cent" },
-    { "106", "cent-six" },
-    { "127", "cent-vingt-sept" },
-    { "200", "deux-cents" },
-    { "579", "cinq-cent-septante-neuf" },
+    { "106", "cent six" },
+    { "127", "cent vingt-sept" },
+    { "200", "deux cents" },
+    { "579", "cinq cent septante-neuf" },
     { "1,000", "mille" },
-    { "1,123", "mille-cent-vingt-trois" },
-    { "1,594", "mille-cinq-cent-nonante-quatre" },
-    { "2,000", "deux-mille" },
-    { "3,004", "trois-mille-quatre" },
-    { "4,567", "quatre-mille-cinq-cent-soixante-sept" },
-    { "15,943", "quinze-mille-neuf-cent-quarante-trois" },
-    { "2,345,678", "deux millions trois-cent-quarante-cinq-mille-six-cent-septante-huit" },
+    { "1,123", "mille cent vingt-trois" },
+    { "1,594", "mille cinq cent nonante-quatre" },
+    { "2,000", "deux mille" },
+    { "3,004", "trois mille quatre" },
+    { "4,567", "quatre mille cinq cent soixante-sept" },
+    { "15,943", "quinze mille neuf cent quarante-trois" },
+    { "2,345,678", "deux millions trois cent quarante-cinq mille six cent septante-huit" },
     { "-36", "moins trente-six" },
-    { "234.567", "deux-cent-trente-quatre virgule cinq six sept" },
+    { "234.567", "deux cent trente-quatre virgule cinq six sept" },
     { NULL, NULL}
 };
 
@@ -1437,7 +1508,7 @@ IntlTestRBNF::TestItalianSpellout()
             { "73", "settanta\\u00ADtr\\u00E9" },
             { "88", "ottant\\u00ADotto" },
             { "100", "cento" },
-            { "101", "cent\\u00ADuno" },
+            { "101", "cento\\u00ADuno" },
             { "103", "cento\\u00ADtr\\u00E9" },
             { "106", "cento\\u00ADsei" },
             { "108", "cent\\u00ADotto" },
@@ -1482,7 +1553,7 @@ IntlTestRBNF::TestPortugueseSpellout()
             { "108", "cento e oito" },
             { "127", "cento e vinte e sete" },
             { "181", "cento e oitenta e um" },
-            { "200", "duzcentos" },
+            { "200", "duzentos" },
             { "579", "quinhentos e setenta e nove" },
             { "1,000", "mil" },
             { "2,000", "dois mil" },
@@ -1490,7 +1561,7 @@ IntlTestRBNF::TestPortugueseSpellout()
             { "4,567", "quatro mil e quinhentos e sessenta e sete" },
             { "15,943", "quinze mil e novecentos e quarenta e tr\\u00EAs" },
             { "-36", "menos trinta e seis" },
-            { "234.567", "duzcentos e trinta e quatro v\\u00EDrgula cinco seis sete" },
+            { "234.567", "duzentos e trinta e quatro v\\u00EDrgula cinco seis sete" },
             { NULL, NULL}
         };
         
@@ -1604,21 +1675,21 @@ IntlTestRBNF::TestSwedishSpellout()
         doTest(formatter, testDataDefault, TRUE);
 
           static const char* testDataNeutrum[][2] = {
-              { "101", "ett\\u00adhundra\\u00aden" },
-              { "1,001", "ettusen en" },
-              { "1,101", "ettusen ett\\u00adhundra\\u00aden" },
-              { "10,001", "tio\\u00adtusen en" },
-              { "21,001", "tjugo\\u00aden\\u00adtusen en" },
+              { "101", "ett\\u00adhundra\\u00adett" },
+              { "1,001", "et\\u00adtusen ett" },
+              { "1,101", "et\\u00adtusen ett\\u00adhundra\\u00adett" },
+              { "10,001", "tio\\u00adtusen ett" },
+              { "21,001", "tjugo\\u00adet\\u00adtusen ett" },
               { NULL, NULL }
           };
   
-          formatter->setDefaultRuleSet("%spellout-cardinal-neutre", status);
+          formatter->setDefaultRuleSet("%spellout-cardinal-neuter", status);
           if (U_SUCCESS(status)) {
-          logln("        testing spellout-cardinal-neutre rules");
+          logln("        testing spellout-cardinal-neuter rules");
           doTest(formatter, testDataNeutrum, TRUE);
           }
           else {
-          errln("Can't test spellout-cardinal-neutre rules");
+          errln("Can't test spellout-cardinal-neuter rules");
           }
 
         static const char* testDataYear[][2] = {
@@ -1633,6 +1704,7 @@ IntlTestRBNF::TestSwedishSpellout()
             { NULL, NULL }
         };
 
+        status = U_ZERO_ERROR;
         formatter->setDefaultRuleSet("%spellout-numbering-year", status);
         if (U_SUCCESS(status)) {
             logln("testing year rules");
@@ -1780,9 +1852,9 @@ IntlTestRBNF::TestLocalizations(void)
                 "<<%main,>,<en, Main,>>", // comma before close angle ok
                 "<<%main>,<en, ',<>\" '>>", // quotes everything until next quote
                 "<<%main>,<'en', \"it's ok\">>", // double quotes work too
-                "  \n <\n  <\n  %main\n  >\n  , \t <\t   en\t  ,  \tfoo \t\t > \n\n >  \n ", // rule whitespace ok
+                "  \n <\n  <\n  %main\n  >\n  , \t <\t   en\t  ,  \tfoo \t\t > \n\n >  \n ", // Pattern_White_Space ok
            }; 
-            int32_t goodLocsLen = sizeof(goodLocs)/sizeof(goodLocs[0]);
+            int32_t goodLocsLen = UPRV_LENGTHOF(goodLocs);
 
             static const char* badLocs[] = {
                 " ", // non-zero length
@@ -1809,7 +1881,7 @@ IntlTestRBNF::TestLocalizations(void)
                 "<<%main>> x", // extra non-space text at end
 
             };
-            int32_t badLocsLen = sizeof(badLocs)/sizeof(badLocs[0]);
+            int32_t badLocsLen = UPRV_LENGTHOF(badLocs);
 
             for (i = 0; i < goodLocsLen; ++i) {
                 logln("[%d] '%s'", i, goodLocs[i]);
@@ -1839,79 +1911,88 @@ IntlTestRBNF::TestAllLocales()
 {
     const char* names[] = {
         " (spellout) ",
-        " (ordinal)  ",
-        " (duration) "
+        " (ordinal)  "
+        // " (duration) " // This is English only, and it's not really supported in CLDR anymore.
     };
     double numbers[] = {45.678, 1, 2, 10, 11, 100, 110, 200, 1000, 1111, -1111};
 
-    // RBNF parse is extremely slow when lenient option is enabled.
-    // For non-exhaustive mode, we only test a few locales.
-    const char* parseLocales[] = {"en_US", "nl_NL", "be", NULL};
-
-
     int32_t count = 0;
     const Locale* locales = Locale::getAvailableLocales(count);
     for (int i = 0; i < count; ++i) {
         const Locale* loc = &locales[i];
-        UBool testParse = TRUE;
-        if (quick) {
-            testParse = FALSE;
-            for (int k = 0; parseLocales[k] != NULL; k++) {
-                if (strcmp(loc->getLanguage(), parseLocales[k]) == 0) {
-                    testParse = TRUE;
-                    break;
-                }
-            }
-        }
 
-        for (int j = 0; j < 3; ++j) {
+        for (int j = 0; j < 2; ++j) {
             UErrorCode status = U_ZERO_ERROR;
             RuleBasedNumberFormat* f = new RuleBasedNumberFormat((URBNFRuleSetTag)j, *loc, status);
+
+            if (status == U_USING_DEFAULT_WARNING || status == U_USING_FALLBACK_WARNING) {
+                // Skip it.
+                delete f;
+                break;
+            }
             if (U_FAILURE(status)) {
                 errln(UnicodeString(loc->getName()) + names[j]
                     + "ERROR could not instantiate -> " + u_errorName(status));
                 continue;
             }
 #if !UCONFIG_NO_COLLATION
-            for (unsigned int numidx = 0; numidx < sizeof(numbers)/sizeof(double); numidx++) {
+            for (unsigned int numidx = 0; numidx < UPRV_LENGTHOF(numbers); numidx++) {
                 double n = numbers[numidx];
                 UnicodeString str;
                 f->format(n, str);
 
-                logln(UnicodeString(loc->getName()) + names[j]
-                    + "success: " + n + " -> " + str);
+                if (verbose) {
+                    logln(UnicodeString(loc->getName()) + names[j]
+                        + "success: " + n + " -> " + str);
+                }
 
-                if (testParse) {
-                    // We do not validate the result in this test case,
-                    // because there are cases which do not round trip by design.
-                    Formattable num;
+                // We do not validate the result in this test case,
+                // because there are cases which do not round trip by design.
+                Formattable num;
 
-                    // regular parse
-                    status = U_ZERO_ERROR;
-                    f->setLenient(FALSE);
-                    f->parse(str, num, status);
-                    if (U_FAILURE(status)) {
-                        //TODO: We need to fix parse problems - see #6895 / #6896
-                        if (status == U_INVALID_FORMAT_ERROR) {
-                            logln(UnicodeString(loc->getName()) + names[j]
-                                + "WARNING could not parse '" + str + "' -> " + u_errorName(status));
-                        } else {
-                             errln(UnicodeString(loc->getName()) + names[j]
-                                + "ERROR could not parse '" + str + "' -> " + u_errorName(status));
-                       }
+                // regular parse
+                status = U_ZERO_ERROR;
+                f->setLenient(FALSE);
+                f->parse(str, num, status);
+                if (U_FAILURE(status)) {
+                    errln(UnicodeString(loc->getName()) + names[j]
+                        + "ERROR could not parse '" + str + "' -> " + u_errorName(status));
+                }
+                // We only check the spellout. The behavior is undefined for numbers < 1 and fractional numbers.
+                if (j == 0) {
+                    if (num.getType() == Formattable::kLong && num.getLong() != n) {
+                        errln(UnicodeString(loc->getName()) + names[j]
+                            + UnicodeString("ERROR could not roundtrip ") + n
+                            + UnicodeString(" -> ") + str + UnicodeString(" -> ") + num.getLong());
                     }
+                    else if (num.getType() == Formattable::kDouble && (int64_t)(num.getDouble() * 1000) != (int64_t)(n*1000)) {
+                        // The epsilon difference is too high.
+                        errln(UnicodeString(loc->getName()) + names[j]
+                            + UnicodeString("ERROR could not roundtrip ") + n
+                            + UnicodeString(" -> ") + str + UnicodeString(" -> ") + num.getDouble());
+                    }
+                }
+                if (!quick && !logKnownIssue("9503") ) {
                     // lenient parse
                     status = U_ZERO_ERROR;
                     f->setLenient(TRUE);
                     f->parse(str, num, status);
                     if (U_FAILURE(status)) {
-                        //TODO: We need to fix parse problems - see #6895 / #6896
-                        if (status == U_INVALID_FORMAT_ERROR) {
-                            logln(UnicodeString(loc->getName()) + names[j]
-                                + "WARNING could not parse(lenient) '" + str + "' -> " + u_errorName(status));
-                        } else {
+                        errln(UnicodeString(loc->getName()) + names[j]
+                            + "ERROR could not parse(lenient) '" + str + "' -> " + u_errorName(status));
+                    }
+                    // We only check the spellout. The behavior is undefined for numbers < 1 and fractional numbers.
+                    if (j == 0) {
+                        if (num.getType() == Formattable::kLong && num.getLong() != n) {
+                            errln(UnicodeString(loc->getName()) + names[j]
+                                + UnicodeString("ERROR could not roundtrip ") + n
+                                + UnicodeString(" -> ") + str + UnicodeString(" -> ") + num.getLong());
+                        }
+                        else if (num.getType() == Formattable::kDouble && (int64_t)(num.getDouble() * 1000) != (int64_t)(n*1000)) {
+                            // The epsilon difference is too high.
                             errln(UnicodeString(loc->getName()) + names[j]
-                                + "ERROR could not parse(lenient) '" + str + "' -> " + u_errorName(status));
+                                + UnicodeString("ERROR could not roundtrip ") + n
+                                + UnicodeString(" -> ") + str + UnicodeString(" -> ") + num.getDouble());
                         }
                     }
                 }
@@ -1924,27 +2005,257 @@ IntlTestRBNF::TestAllLocales()
 
 void 
 IntlTestRBNF::TestMultiplierSubstitution(void) {
-  UnicodeString rules("=#,##0=;1,000,000: <##0.###< million;");
-  UErrorCode status = U_ZERO_ERROR;
-  UParseError parse_error;
-  RuleBasedNumberFormat *rbnf = 
-    new RuleBasedNumberFormat(rules, Locale::getUS(), parse_error, status);
-  if (U_SUCCESS(status)) {
-    UnicodeString res;
-    FieldPosition pos;
-    double n = 1234000.0;
-    rbnf->format(n, res, pos);
-    delete rbnf;
-
-    UnicodeString expected = UNICODE_STRING_SIMPLE("1.234 million");
-    if (expected != res) {
-      UnicodeString msg = "Expected: ";
-      msg.append(expected);
-      msg.append(" but got ");
-      msg.append(res);
-      errln(msg);
+    UnicodeString rules("=#,##0=;1,000,000: <##0.###< million;");
+    UErrorCode status = U_ZERO_ERROR;
+    UParseError parse_error;
+    RuleBasedNumberFormat *rbnf = 
+        new RuleBasedNumberFormat(rules, Locale::getUS(), parse_error, status);
+    if (U_SUCCESS(status)) {
+        UnicodeString res;
+        FieldPosition pos;
+        double n = 1234000.0;
+        rbnf->format(n, res, pos);
+        delete rbnf;
+
+        UnicodeString expected(UNICODE_STRING_SIMPLE("1.234 million"));
+        if (expected != res) {
+            UnicodeString msg = "Expected: ";
+            msg.append(expected);
+            msg.append(" but got ");
+            msg.append(res);
+            errln(msg);
+        }
     }
-  }
+}
+
+void
+IntlTestRBNF::TestSetDecimalFormatSymbols() {
+    UErrorCode status = U_ZERO_ERROR;
+
+    RuleBasedNumberFormat rbnf(URBNF_ORDINAL, Locale::getEnglish(), status);
+    if (U_FAILURE(status)) {
+        dataerrln("Unable to create RuleBasedNumberFormat - " + UnicodeString(u_errorName(status)));
+        return;
+    }
+
+    DecimalFormatSymbols dfs(Locale::getEnglish(), status);
+    if (U_FAILURE(status)) {
+        errln("Unable to create DecimalFormatSymbols - " + UnicodeString(u_errorName(status)));
+        return;
+    }
+
+    UnicodeString expected[] = {
+            UnicodeString("1,001st"),
+            UnicodeString("1&001st")
+    };
+
+    double number = 1001;
+
+    UnicodeString result;
+
+    rbnf.format(number, result);
+    if (result != expected[0]) {
+        errln("Format Error - Got: " + result + " Expected: " + expected[0]);
+    }
+
+    result.remove();
+
+    /* Set new symbol for testing */
+    dfs.setSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol, UnicodeString("&"), TRUE);
+    rbnf.setDecimalFormatSymbols(dfs);
+
+    rbnf.format(number, result);
+    if (result != expected[1]) {
+        errln("Format Error - Got: " + result + " Expected: " + expected[1]);
+    }
+}
+
+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(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 
@@ -1965,7 +2276,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;
@@ -2002,7 +2314,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 ");