OLD | NEW |
1 /* | 1 /* |
2 ******************************************************************************* | 2 ******************************************************************************* |
3 * Copyright (C) 1996-2013, International Business Machines Corporation and * | 3 * Copyright (C) 1996-2014, International Business Machines Corporation and * |
4 * others. All Rights Reserved. * | 4 * others. All Rights Reserved. * |
5 ******************************************************************************* | 5 ******************************************************************************* |
6 */ | 6 */ |
7 | 7 |
8 #include "unicode/utypes.h" | 8 #include "unicode/utypes.h" |
9 | 9 |
10 #if !UCONFIG_NO_FORMATTING | 10 #if !UCONFIG_NO_FORMATTING |
11 | 11 |
12 #include "itrbnf.h" | 12 #include "itrbnf.h" |
13 | 13 |
14 #include "unicode/umachine.h" | 14 #include "unicode/umachine.h" |
15 | 15 |
16 #include "unicode/tblcoll.h" | 16 #include "unicode/tblcoll.h" |
17 #include "unicode/coleitr.h" | 17 #include "unicode/coleitr.h" |
18 #include "unicode/ures.h" | 18 #include "unicode/ures.h" |
19 #include "unicode/ustring.h" | 19 #include "unicode/ustring.h" |
20 #include "unicode/decimfmt.h" | 20 #include "unicode/decimfmt.h" |
21 #include "unicode/udata.h" | 21 #include "unicode/udata.h" |
22 #include "testutil.h" | 22 #include "testutil.h" |
23 | 23 |
24 //#include "llong.h" | |
25 | |
26 #include <string.h> | 24 #include <string.h> |
27 | 25 |
28 // import com.ibm.text.RuleBasedNumberFormat; | 26 // import com.ibm.text.RuleBasedNumberFormat; |
29 // import com.ibm.test.TestFmwk; | 27 // import com.ibm.test.TestFmwk; |
30 | 28 |
31 // import java.util.Locale; | 29 // import java.util.Locale; |
32 // import java.text.NumberFormat; | 30 // import java.text.NumberFormat; |
33 | 31 |
34 // current macro not in icu1.8.1 | 32 // current macro not in icu1.8.1 |
35 #define TESTCASE(id,test) \ | 33 #define TESTCASE(id,test) \ |
(...skipping 24 matching lines...) Expand all Loading... |
60 TESTCASE(10, TestFractionalRuleSet); | 58 TESTCASE(10, TestFractionalRuleSet); |
61 TESTCASE(11, TestSwedishSpellout); | 59 TESTCASE(11, TestSwedishSpellout); |
62 TESTCASE(12, TestBelgianFrenchSpellout); | 60 TESTCASE(12, TestBelgianFrenchSpellout); |
63 TESTCASE(13, TestSmallValues); | 61 TESTCASE(13, TestSmallValues); |
64 TESTCASE(14, TestLocalizations); | 62 TESTCASE(14, TestLocalizations); |
65 TESTCASE(15, TestAllLocales); | 63 TESTCASE(15, TestAllLocales); |
66 TESTCASE(16, TestHebrewFraction); | 64 TESTCASE(16, TestHebrewFraction); |
67 TESTCASE(17, TestPortugueseSpellout); | 65 TESTCASE(17, TestPortugueseSpellout); |
68 TESTCASE(18, TestMultiplierSubstitution); | 66 TESTCASE(18, TestMultiplierSubstitution); |
69 TESTCASE(19, TestSetDecimalFormatSymbols); | 67 TESTCASE(19, TestSetDecimalFormatSymbols); |
| 68 TESTCASE(20, TestPluralRules); |
70 #else | 69 #else |
71 TESTCASE(0, TestRBNFDisabled); | 70 TESTCASE(0, TestRBNFDisabled); |
72 #endif | 71 #endif |
73 default: | 72 default: |
74 name = ""; | 73 name = ""; |
75 break; | 74 break; |
76 } | 75 } |
77 } | 76 } |
78 | 77 |
79 #if U_HAVE_RBNF | 78 #if U_HAVE_RBNF |
(...skipping 1714 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1794 } | 1793 } |
1795 } | 1794 } |
1796 } | 1795 } |
1797 } | 1796 } |
1798 | 1797 |
1799 void | 1798 void |
1800 IntlTestRBNF::TestAllLocales() | 1799 IntlTestRBNF::TestAllLocales() |
1801 { | 1800 { |
1802 const char* names[] = { | 1801 const char* names[] = { |
1803 " (spellout) ", | 1802 " (spellout) ", |
1804 " (ordinal) ", | 1803 " (ordinal) " |
1805 " (duration) " | 1804 // " (duration) " // This is English only, and it's not really supported
in CLDR anymore. |
1806 }; | 1805 }; |
1807 double numbers[] = {45.678, 1, 2, 10, 11, 100, 110, 200, 1000, 1111, -1111}; | 1806 double numbers[] = {45.678, 1, 2, 10, 11, 100, 110, 200, 1000, 1111, -1111}; |
1808 | 1807 |
1809 // RBNF parse is extremely slow when lenient option is enabled. | |
1810 // For non-exhaustive mode, we only test a few locales. | |
1811 const char* parseLocales[] = {"en_US", "nl_NL", "be", NULL}; | |
1812 | |
1813 | |
1814 int32_t count = 0; | 1808 int32_t count = 0; |
1815 const Locale* locales = Locale::getAvailableLocales(count); | 1809 const Locale* locales = Locale::getAvailableLocales(count); |
1816 for (int i = 0; i < count; ++i) { | 1810 for (int i = 0; i < count; ++i) { |
1817 const Locale* loc = &locales[i]; | 1811 const Locale* loc = &locales[i]; |
1818 UBool testParse = TRUE; | |
1819 if (quick) { | |
1820 testParse = FALSE; | |
1821 for (int k = 0; parseLocales[k] != NULL; k++) { | |
1822 if (strcmp(loc->getLanguage(), parseLocales[k]) == 0) { | |
1823 testParse = TRUE; | |
1824 break; | |
1825 } | |
1826 } | |
1827 } | |
1828 | 1812 |
1829 for (int j = 0; j < 3; ++j) { | 1813 for (int j = 0; j < 2; ++j) { |
1830 UErrorCode status = U_ZERO_ERROR; | 1814 UErrorCode status = U_ZERO_ERROR; |
1831 RuleBasedNumberFormat* f = new RuleBasedNumberFormat((URBNFRuleSetTa
g)j, *loc, status); | 1815 RuleBasedNumberFormat* f = new RuleBasedNumberFormat((URBNFRuleSetTa
g)j, *loc, status); |
| 1816 |
| 1817 if (status == U_USING_DEFAULT_WARNING || status == U_USING_FALLBACK_
WARNING) { |
| 1818 // Skip it. |
| 1819 delete f; |
| 1820 break; |
| 1821 } |
1832 if (U_FAILURE(status)) { | 1822 if (U_FAILURE(status)) { |
1833 errln(UnicodeString(loc->getName()) + names[j] | 1823 errln(UnicodeString(loc->getName()) + names[j] |
1834 + "ERROR could not instantiate -> " + u_errorName(status)); | 1824 + "ERROR could not instantiate -> " + u_errorName(status)); |
1835 continue; | 1825 continue; |
1836 } | 1826 } |
1837 #if !UCONFIG_NO_COLLATION | 1827 #if !UCONFIG_NO_COLLATION |
1838 for (unsigned int numidx = 0; numidx < sizeof(numbers)/sizeof(double
); numidx++) { | 1828 for (unsigned int numidx = 0; numidx < sizeof(numbers)/sizeof(double
); numidx++) { |
1839 double n = numbers[numidx]; | 1829 double n = numbers[numidx]; |
1840 UnicodeString str; | 1830 UnicodeString str; |
1841 f->format(n, str); | 1831 f->format(n, str); |
1842 | 1832 |
1843 logln(UnicodeString(loc->getName()) + names[j] | 1833 if (verbose) { |
1844 + "success: " + n + " -> " + str); | 1834 logln(UnicodeString(loc->getName()) + names[j] |
| 1835 + "success: " + n + " -> " + str); |
| 1836 } |
1845 | 1837 |
1846 if (testParse) { | 1838 // We do not validate the result in this test case, |
1847 // We do not validate the result in this test case, | 1839 // because there are cases which do not round trip by design. |
1848 // because there are cases which do not round trip by design
. | 1840 Formattable num; |
1849 Formattable num; | |
1850 | 1841 |
1851 // regular parse | 1842 // regular parse |
1852 status = U_ZERO_ERROR; | 1843 status = U_ZERO_ERROR; |
1853 f->setLenient(FALSE); | 1844 f->setLenient(FALSE); |
1854 f->parse(str, num, status); | 1845 f->parse(str, num, status); |
1855 if (U_FAILURE(status)) { | 1846 if (U_FAILURE(status)) { |
1856 //TODO: We need to fix parse problems - see #6895 / #689
6 | 1847 errln(UnicodeString(loc->getName()) + names[j] |
1857 if (status == U_INVALID_FORMAT_ERROR) { | 1848 + "ERROR could not parse '" + str + "' -> " + u_errorNam
e(status)); |
1858 logln(UnicodeString(loc->getName()) + names[j] | 1849 } |
1859 + "WARNING could not parse '" + str + "' -> " +
u_errorName(status)); | 1850 // We only check the spellout. The behavior is undefined for num
bers < 1 and fractional numbers. |
1860 } else { | 1851 if (j == 0) { |
1861 errln(UnicodeString(loc->getName()) + names[j] | 1852 if (num.getType() == Formattable::kLong && num.getLong() !=
n) { |
1862 + "ERROR could not parse '" + str + "' -> " + u_
errorName(status)); | 1853 errln(UnicodeString(loc->getName()) + names[j] |
1863 } | 1854 + UnicodeString("ERROR could not roundtrip ") + n |
| 1855 + UnicodeString(" -> ") + str + UnicodeString(" -> "
) + num.getLong()); |
1864 } | 1856 } |
| 1857 else if (num.getType() == Formattable::kDouble && (int64_t)(
num.getDouble() * 1000) != (int64_t)(n*1000)) { |
| 1858 // The epsilon difference is too high. |
| 1859 errln(UnicodeString(loc->getName()) + names[j] |
| 1860 + UnicodeString("ERROR could not roundtrip ") + n |
| 1861 + UnicodeString(" -> ") + str + UnicodeString(" -> "
) + num.getDouble()); |
| 1862 } |
| 1863 } |
| 1864 if (!quick && !logKnownIssue("9503") ) { |
1865 // lenient parse | 1865 // lenient parse |
1866 status = U_ZERO_ERROR; | 1866 status = U_ZERO_ERROR; |
1867 f->setLenient(TRUE); | 1867 f->setLenient(TRUE); |
1868 f->parse(str, num, status); | 1868 f->parse(str, num, status); |
1869 if (U_FAILURE(status)) { | 1869 if (U_FAILURE(status)) { |
1870 //TODO: We need to fix parse problems - see #6895 / #689
6 | 1870 errln(UnicodeString(loc->getName()) + names[j] |
1871 if (status == U_INVALID_FORMAT_ERROR) { | 1871 + "ERROR could not parse(lenient) '" + str + "' -> "
+ u_errorName(status)); |
1872 logln(UnicodeString(loc->getName()) + names[j] | 1872 } |
1873 + "WARNING could not parse(lenient) '" + str + "
' -> " + u_errorName(status)); | 1873 // We only check the spellout. The behavior is undefined for
numbers < 1 and fractional numbers. |
1874 } else { | 1874 if (j == 0) { |
| 1875 if (num.getType() == Formattable::kLong && num.getLong()
!= n) { |
1875 errln(UnicodeString(loc->getName()) + names[j] | 1876 errln(UnicodeString(loc->getName()) + names[j] |
1876 + "ERROR could not parse(lenient) '" + str + "'
-> " + u_errorName(status)); | 1877 + UnicodeString("ERROR could not roundtrip ") +
n |
| 1878 + UnicodeString(" -> ") + str + UnicodeString("
-> ") + num.getLong()); |
| 1879 } |
| 1880 else if (num.getType() == Formattable::kDouble && (int64
_t)(num.getDouble() * 1000) != (int64_t)(n*1000)) { |
| 1881 // The epsilon difference is too high. |
| 1882 errln(UnicodeString(loc->getName()) + names[j] |
| 1883 + UnicodeString("ERROR could not roundtrip ") +
n |
| 1884 + UnicodeString(" -> ") + str + UnicodeString("
-> ") + num.getDouble()); |
1877 } | 1885 } |
1878 } | 1886 } |
1879 } | 1887 } |
1880 } | 1888 } |
1881 #endif | 1889 #endif |
1882 delete f; | 1890 delete f; |
1883 } | 1891 } |
1884 } | 1892 } |
1885 } | 1893 } |
1886 | 1894 |
1887 void | 1895 void |
1888 IntlTestRBNF::TestMultiplierSubstitution(void) { | 1896 IntlTestRBNF::TestMultiplierSubstitution(void) { |
1889 UnicodeString rules("=#,##0=;1,000,000: <##0.###< million;"); | 1897 UnicodeString rules("=#,##0=;1,000,000: <##0.###< million;"); |
1890 UErrorCode status = U_ZERO_ERROR; | 1898 UErrorCode status = U_ZERO_ERROR; |
1891 UParseError parse_error; | 1899 UParseError parse_error; |
1892 RuleBasedNumberFormat *rbnf = | 1900 RuleBasedNumberFormat *rbnf = |
1893 new RuleBasedNumberFormat(rules, Locale::getUS(), parse_error, status); | 1901 new RuleBasedNumberFormat(rules, Locale::getUS(), parse_error, status); |
1894 if (U_SUCCESS(status)) { | 1902 if (U_SUCCESS(status)) { |
1895 UnicodeString res; | 1903 UnicodeString res; |
1896 FieldPosition pos; | 1904 FieldPosition pos; |
1897 double n = 1234000.0; | 1905 double n = 1234000.0; |
1898 rbnf->format(n, res, pos); | 1906 rbnf->format(n, res, pos); |
1899 delete rbnf; | 1907 delete rbnf; |
1900 | 1908 |
1901 UnicodeString expected = UNICODE_STRING_SIMPLE("1.234 million"); | 1909 UnicodeString expected(UNICODE_STRING_SIMPLE("1.234 million")); |
1902 if (expected != res) { | 1910 if (expected != res) { |
1903 UnicodeString msg = "Expected: "; | 1911 UnicodeString msg = "Expected: "; |
1904 msg.append(expected); | 1912 msg.append(expected); |
1905 msg.append(" but got "); | 1913 msg.append(" but got "); |
1906 msg.append(res); | 1914 msg.append(res); |
1907 errln(msg); | 1915 errln(msg); |
| 1916 } |
1908 } | 1917 } |
1909 } | |
1910 } | 1918 } |
1911 | 1919 |
1912 void | 1920 void |
1913 IntlTestRBNF::TestSetDecimalFormatSymbols() { | 1921 IntlTestRBNF::TestSetDecimalFormatSymbols() { |
1914 UErrorCode status = U_ZERO_ERROR; | 1922 UErrorCode status = U_ZERO_ERROR; |
1915 | 1923 |
1916 RuleBasedNumberFormat rbnf(URBNF_ORDINAL, Locale::getEnglish(), status); | 1924 RuleBasedNumberFormat rbnf(URBNF_ORDINAL, Locale::getEnglish(), status); |
1917 if (U_FAILURE(status)) { | 1925 if (U_FAILURE(status)) { |
1918 dataerrln("Unable to create RuleBasedNumberFormat - " + UnicodeString(u_
errorName(status))); | 1926 dataerrln("Unable to create RuleBasedNumberFormat - " + UnicodeString(u_
errorName(status))); |
1919 return; | 1927 return; |
(...skipping 24 matching lines...) Expand all Loading... |
1944 /* Set new symbol for testing */ | 1952 /* Set new symbol for testing */ |
1945 dfs.setSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol, UnicodeString(
"&"), TRUE); | 1953 dfs.setSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol, UnicodeString(
"&"), TRUE); |
1946 rbnf.setDecimalFormatSymbols(dfs); | 1954 rbnf.setDecimalFormatSymbols(dfs); |
1947 | 1955 |
1948 rbnf.format(number, result); | 1956 rbnf.format(number, result); |
1949 if (result != expected[1]) { | 1957 if (result != expected[1]) { |
1950 errln("Format Error - Got: " + result + " Expected: " + expected[1]); | 1958 errln("Format Error - Got: " + result + " Expected: " + expected[1]); |
1951 } | 1959 } |
1952 } | 1960 } |
1953 | 1961 |
| 1962 void IntlTestRBNF::TestPluralRules() { |
| 1963 UErrorCode status = U_ZERO_ERROR; |
| 1964 UnicodeString enRules("%digits-ordinal:-x: ->>;0: =#,##0=$(ordinal,one{st}tw
o{nd}few{rd}other{th})$;"); |
| 1965 UParseError parseError; |
| 1966 RuleBasedNumberFormat enFormatter(enRules, Locale::getEnglish(), parseError,
status); |
| 1967 if (U_FAILURE(status)) { |
| 1968 dataerrln("Unable to create RuleBasedNumberFormat - " + UnicodeString(u_
errorName(status))); |
| 1969 return; |
| 1970 } |
| 1971 const char* const enTestData[][2] = { |
| 1972 { "1", "1st" }, |
| 1973 { "2", "2nd" }, |
| 1974 { "3", "3rd" }, |
| 1975 { "4", "4th" }, |
| 1976 { "11", "11th" }, |
| 1977 { "12", "12th" }, |
| 1978 { "13", "13th" }, |
| 1979 { "14", "14th" }, |
| 1980 { "21", "21st" }, |
| 1981 { "22", "22nd" }, |
| 1982 { "23", "23rd" }, |
| 1983 { "24", "24th" }, |
| 1984 { NULL, NULL } |
| 1985 }; |
| 1986 |
| 1987 doTest(&enFormatter, enTestData, TRUE); |
| 1988 |
| 1989 // This is trying to model the feminine form, but don't worry about the deta
ils too much. |
| 1990 // We're trying to test the plural rules. |
| 1991 UnicodeString ruRules("%spellout-numbering:" |
| 1992 "-x: minus >>;" |
| 1993 "x.x: << point >>;" |
| 1994 "0: zero;" |
| 1995 "1: one;" |
| 1996 "2: two;" |
| 1997 "3: three;" |
| 1998 "4: four;" |
| 1999 "5: five;" |
| 2000 "6: six;" |
| 2001 "7: seven;" |
| 2002 "8: eight;" |
| 2003 "9: nine;" |
| 2004 "10: ten;" |
| 2005 "11: eleven;" |
| 2006 "12: twelve;" |
| 2007 "13: thirteen;" |
| 2008 "14: fourteen;" |
| 2009 "15: fifteen;" |
| 2010 "16: sixteen;" |
| 2011 "17: seventeen;" |
| 2012 "18: eighteen;" |
| 2013 "19: nineteen;" |
| 2014 "20: twenty[->>];" |
| 2015 "30: thirty[->>];" |
| 2016 "40: forty[->>];" |
| 2017 "50: fifty[->>];" |
| 2018 "60: sixty[->>];" |
| 2019 "70: seventy[->>];" |
| 2020 "80: eighty[->>];" |
| 2021 "90: ninety[->>];" |
| 2022 "100: hundred[ >>];" |
| 2023 "200: << hundred[ >>];" |
| 2024 "300: << hundreds[ >>];" |
| 2025 "500: << hundredss[ >>];" |
| 2026 "1000: << $(cardinal,one{thousand}few{thousands}other{thousandss})$[
>>];" |
| 2027 "1000000: << $(cardinal,one{million}few{millions}other{millionss})$[
>>];"); |
| 2028 RuleBasedNumberFormat ruFormatter(ruRules, Locale("ru"), parseError, status)
; |
| 2029 const char* const ruTestData[][2] = { |
| 2030 { "1", "one" }, |
| 2031 { "100", "hundred" }, |
| 2032 { "125", "hundred twenty-five" }, |
| 2033 { "399", "three hundreds ninety-nine" }, |
| 2034 { "1,000", "one thousand" }, |
| 2035 { "1,001", "one thousand one" }, |
| 2036 { "2,000", "two thousands" }, |
| 2037 { "2,001", "two thousands one" }, |
| 2038 { "2,002", "two thousands two" }, |
| 2039 { "3,333", "three thousands three hundreds thirty-three" }, |
| 2040 { "5,000", "five thousandss" }, |
| 2041 { "11,000", "eleven thousandss" }, |
| 2042 { "21,000", "twenty-one thousand" }, |
| 2043 { "22,000", "twenty-two thousands" }, |
| 2044 { "25,001", "twenty-five thousandss one" }, |
| 2045 { NULL, NULL } |
| 2046 }; |
| 2047 |
| 2048 if (U_FAILURE(status)) { |
| 2049 errln("Unable to create RuleBasedNumberFormat - " + UnicodeString(u_erro
rName(status))); |
| 2050 return; |
| 2051 } |
| 2052 doTest(&ruFormatter, ruTestData, TRUE); |
| 2053 |
| 2054 // Make sure there are no divide by 0 errors. |
| 2055 UnicodeString result; |
| 2056 RuleBasedNumberFormat(ruRules, Locale("ru"), parseError, status).format(2100
0, result); |
| 2057 if (result.compare(UNICODE_STRING_SIMPLE("twenty-one thousand")) != 0) { |
| 2058 errln("Got " + result + " for 21000"); |
| 2059 } |
| 2060 |
| 2061 } |
1954 | 2062 |
1955 void | 2063 void |
1956 IntlTestRBNF::doTest(RuleBasedNumberFormat* formatter, const char* const testDat
a[][2], UBool testParsing) | 2064 IntlTestRBNF::doTest(RuleBasedNumberFormat* formatter, const char* const testDat
a[][2], UBool testParsing) |
1957 { | 2065 { |
1958 // man, error reporting would be easier with printf-style syntax for unicode s
tring and formattable | 2066 // man, error reporting would be easier with printf-style syntax for unicode s
tring and formattable |
1959 | 2067 |
1960 UErrorCode status = U_ZERO_ERROR; | 2068 UErrorCode status = U_ZERO_ERROR; |
1961 DecimalFormatSymbols dfs("en", status); | 2069 DecimalFormatSymbols dfs("en", status); |
1962 // NumberFormat* decFmt = NumberFormat::createInstance(Locale::getUS(), stat
us); | 2070 // NumberFormat* decFmt = NumberFormat::createInstance(Locale::getUS(), stat
us); |
1963 DecimalFormat decFmt("#,###.################", dfs, status); | 2071 DecimalFormat decFmt("#,###.################", dfs, status); |
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2089 | 2197 |
2090 void | 2198 void |
2091 IntlTestRBNF::TestRBNFDisabled() { | 2199 IntlTestRBNF::TestRBNFDisabled() { |
2092 errln("*** RBNF currently disabled on this platform ***\n"); | 2200 errln("*** RBNF currently disabled on this platform ***\n"); |
2093 } | 2201 } |
2094 | 2202 |
2095 /* U_HAVE_RBNF */ | 2203 /* U_HAVE_RBNF */ |
2096 #endif | 2204 #endif |
2097 | 2205 |
2098 #endif /* #if !UCONFIG_NO_FORMATTING */ | 2206 #endif /* #if !UCONFIG_NO_FORMATTING */ |
OLD | NEW |