X-Git-Url: https://git.saurik.com/apple/icu.git/blobdiff_plain/374ca955a76ecab1204ca8bfa63ff9238d998416..48b980fed3435926e0b3a8d72ecb58be703a1c7a:/icuSources/test/intltest/numfmtst.cpp diff --git a/icuSources/test/intltest/numfmtst.cpp b/icuSources/test/intltest/numfmtst.cpp index e6bf04c2..1ac9e1be 100644 --- a/icuSources/test/intltest/numfmtst.cpp +++ b/icuSources/test/intltest/numfmtst.cpp @@ -1,6 +1,6 @@ /******************************************************************** * COPYRIGHT: - * Copyright (c) 1997-2004, International Business Machines Corporation and + * Copyright (c) 1997-2008, International Business Machines Corporation and * others. All Rights Reserved. ********************************************************************/ /* Modification History: @@ -24,8 +24,11 @@ #include "tokiter.h" #include "charstr.h" #include "putilimp.h" +#include "winnmtst.h" #include #include +#include +#include "cstring.h" static const UChar EUR[] = {69,85,82,0}; // "EUR" @@ -60,22 +63,34 @@ void NumberFormatTest::runIndexedTest( int32_t index, UBool exec, const char* &n CASE(14,TestCurrencyObject); CASE(15,TestCurrencyPatterns); - CASE(16,TestDigitList); - CASE(17,TestWhiteSpaceParsing); - CASE(18,TestComplexCurrency); - CASE(19,TestRegCurrency); - CASE(20,TestSymbolsWithBadLocale); - CASE(21,TestAdoptDecimalFormatSymbols); - - CASE(22,TestScientific2); - CASE(23,TestScientificGrouping); - CASE(24,TestInt64); - - CASE(25,TestPerMill); - CASE(26,TestIllegalPatterns); - CASE(27,TestCases); - - CASE(28,TestCurrencyNames); + //CASE(16,TestDigitList); + CASE(16,TestWhiteSpaceParsing); + CASE(17,TestComplexCurrency); + CASE(18,TestRegCurrency); + CASE(19,TestSymbolsWithBadLocale); + CASE(20,TestAdoptDecimalFormatSymbols); + + CASE(21,TestScientific2); + CASE(22,TestScientificGrouping); + CASE(23,TestInt64); + + CASE(24,TestPerMill); + CASE(25,TestIllegalPatterns); + CASE(26,TestCases); + + CASE(27,TestCurrencyNames); + CASE(28,TestCurrencyAmount); + CASE(29,TestCurrencyUnit); + CASE(30,TestCoverage); + CASE(31,TestJB3832); + CASE(32,TestHost); + CASE(33,TestHostClone); + CASE(34,TestCurrencyFormat); + CASE(35,TestRounding); + CASE(36,TestNonpositiveMultiplier); + + CASE(37,TestLenientParse); + CASE(38,TestSpaceParsing); default: name = ""; break; } @@ -110,10 +125,56 @@ NumberFormatTest::TestAPI(void) status = U_ZERO_ERROR; } + result.remove(); + int64_t ll = 12; + test->format(ll, result); + if (result != "12.00"){ + errln("format int64_t error"); + } + delete test; } } +class StubNumberForamt :public NumberFormat{ +public: + StubNumberForamt(){}; + virtual UnicodeString& format(double ,UnicodeString& appendTo,FieldPosition& ) const { + return appendTo; + } + virtual UnicodeString& format(int32_t ,UnicodeString& appendTo,FieldPosition& ) const { + return appendTo.append((UChar)0x0033); + } + virtual UnicodeString& format(int64_t number,UnicodeString& appendTo,FieldPosition& pos) const { + return NumberFormat::format(number, appendTo, pos); + } + virtual UnicodeString& format(const Formattable& , UnicodeString& appendTo, FieldPosition& , UErrorCode& ) const { + return appendTo; + } + virtual void parse(const UnicodeString& , + Formattable& , + ParsePosition& ) const {} + virtual void parse( const UnicodeString& , + Formattable& , + UErrorCode& ) const {} + virtual UClassID getDynamicClassID(void) const { + static char classID = 0; + return (UClassID)&classID; + } + virtual Format* clone() const {return NULL;} +}; + +void +NumberFormatTest::TestCoverage(void){ + StubNumberForamt stub; + UnicodeString agent("agent"); + FieldPosition pos; + int64_t num = 4; + if (stub.format(num, agent, pos) != UnicodeString("agent3")){ + errln("NumberFormat::format(int64, UnicodString&, FieldPosition&) should delegate to (int32, ,)"); + }; +} + // Test various patterns void NumberFormatTest::TestPatterns(void) @@ -146,15 +207,16 @@ NumberFormatTest::TestPatterns(void) } } +/* +icu_2_4::DigitList::operator== 0 0 2 icuuc24d.dll digitlst.cpp Doug +icu_2_4::DigitList::append 0 0 4 icuin24d.dll digitlst.h Doug +icu_2_4::DigitList::operator!= 0 0 1 icuuc24d.dll digitlst.h Doug +*/ +/* void NumberFormatTest::TestDigitList(void) { // API coverage for DigitList - /* - icu_2_4::DigitList::operator== 0 0 2 icuuc24d.dll digitlst.cpp Doug - icu_2_4::DigitList::append 0 0 4 icuin24d.dll digitlst.h Doug - icu_2_4::DigitList::operator!= 0 0 1 icuuc24d.dll digitlst.h Doug - */ DigitList list1; list1.append('1'); list1.fDecimalAt = 1; @@ -167,6 +229,7 @@ NumberFormatTest::TestDigitList(void) errln("digitlist append, operator== or set failed "); } } +*/ // ------------------------------------- @@ -380,7 +443,7 @@ NumberFormatTest::TestScientificGrouping() { } } -static void setFromString(DigitList& dl, const char* str) { +/*static void setFromString(DigitList& dl, const char* str) { char c; UBool decimalSet = FALSE; dl.clear(); @@ -399,7 +462,7 @@ static void setFromString(DigitList& dl, const char* str) { if (!decimalSet) { dl.fDecimalAt = dl.fCount; } -} +}*/ void NumberFormatTest::TestInt64() { @@ -417,7 +480,7 @@ NumberFormatTest::TestInt64() { } // also test digitlist - int64_t int64max = U_INT64_MAX; +/* int64_t int64max = U_INT64_MAX; int64_t int64min = U_INT64_MIN; const char* int64maxstr = "9223372036854775807"; const char* int64minstr = "-9223372036854775808"; @@ -478,7 +541,7 @@ NumberFormatTest::TestInt64() { if (dl.fitsIntoInt64(FALSE)) { errln(fail + "-(" + int64minstr + ") didn't fit"); } - } + }*/ } // ------------------------------------- @@ -587,15 +650,16 @@ NumberFormatTest::escape(UnicodeString& s) // ------------------------------------- static const char* testCases[][2]= { /* locale ID */ /* expected */ - {"ca_ES_PREEURO", "\\u20A7 1.150" }, - {"de_LU_PREEURO", "1,150 F" }, - {"el_GR_PREEURO", "1.150,50 \\u0394\\u03C1\\u03C7" }, - {"en_BE_PREEURO", "1.150,50 BF" }, - {"es_ES_PREEURO", "1.150 \\u20A7" }, - {"eu_ES_PREEURO", "\\u20A7 1.150" }, - {"gl_ES_PREEURO", "\\u20A7 1.150" }, - {"it_IT_PREEURO", "\\u20A4 1.150" }, - {"pt_PT_PREEURO", "1,150$50 Esc."} + {"ca_ES_PREEURO", "1.150\\u00A0\\u20A7" }, + {"de_LU_PREEURO", "1,150\\u00A0F" }, + {"el_GR_PREEURO", "1.150,50\\u00A0\\u0394\\u03C1\\u03C7" }, + {"en_BE_PREEURO", "1.150,50\\u00A0BF" }, + {"es_ES_PREEURO", "\\u20A7\\u00A01.150" }, + {"eu_ES_PREEURO", "1.150\\u00A0\\u20A7" }, + {"gl_ES_PREEURO", "1.150\\u00A0\\u20A7" }, + {"it_IT_PREEURO", "\\u20A4\\u00A01.150" }, + {"pt_PT_PREEURO", "1,150$50\\u00A0Esc."}, + {"en_US@currency=JPY", "\\u00A51,150"} }; /** * Test localized currency patterns. @@ -605,10 +669,15 @@ NumberFormatTest::TestCurrency(void) { UErrorCode status = U_ZERO_ERROR; NumberFormat* currencyFmt = NumberFormat::createCurrencyInstance(Locale::getCanadaFrench(), status); + if (U_FAILURE(status)) { + dataerrln("Error calling NumberFormat::createCurrencyInstance()"); + return; + } + UnicodeString s; currencyFmt->format(1.50, s); logln((UnicodeString)"Un pauvre ici a..........." + s); - if (!(s=="1,50 $")) - errln((UnicodeString)"FAIL: Expected 1,50 $"); + if (!(s==CharsToUnicodeString("1,50\\u00A0$"))) + errln((UnicodeString)"FAIL: Expected 1,50$"); delete currencyFmt; s.truncate(0); char loc[256]={0}; @@ -616,16 +685,16 @@ NumberFormatTest::TestCurrency(void) currencyFmt = NumberFormat::createCurrencyInstance(Locale(loc),status); currencyFmt->format(1.50, s); logln((UnicodeString)"Un pauvre en Allemagne a.." + s); - if (!(s=="1,50 DM")) - errln((UnicodeString)"FAIL: Expected 1,50 DM"); + if (!(s==CharsToUnicodeString("1,50\\u00A0DM"))) + errln((UnicodeString)"FAIL: Expected 1,50DM"); delete currencyFmt; s.truncate(0); len = uloc_canonicalize("fr_FR_PREEURO", loc, 256, &status); currencyFmt = NumberFormat::createCurrencyInstance(Locale(loc), status); currencyFmt->format(1.50, s); logln((UnicodeString)"Un pauvre en France a....." + s); - if (!(s=="1,50 F")) - errln((UnicodeString)"FAIL: Expected 1,50 F"); + if (!(s==CharsToUnicodeString("1,50\\u00A0F"))) + errln((UnicodeString)"FAIL: Expected 1,50F"); delete currencyFmt; if (U_FAILURE(status)) errln((UnicodeString)"FAIL: Status " + (int32_t)status); @@ -633,7 +702,7 @@ NumberFormatTest::TestCurrency(void) for(int i=0; i < (int)(sizeof(testCases)/sizeof(testCases[i])); i++){ status = U_ZERO_ERROR; const char *localeID = testCases[i][0]; - UnicodeString expected(testCases[i][1]); + UnicodeString expected(testCases[i][1], -1, US_INV); expected = expected.unescape(); s.truncate(0); char loc[256]={0}; @@ -683,7 +752,7 @@ void NumberFormatTest::TestCurrencyObject() { 1234.56, CharsToUnicodeString("\\u00A51,235")); // Yen expectCurrency(*fmt, Locale("fr", "CH", ""), - 1234.56, "SwF1,234.55"); // 0.05 rounding + 1234.56, "Fr.1,234.55"); // 0.05 rounding expectCurrency(*fmt, Locale::getUS(), 1234.56, "$1,234.56"); @@ -700,13 +769,13 @@ void NumberFormatTest::TestCurrencyObject() { expectCurrency(*fmt, null, 1234.56, CharsToUnicodeString("1 234,56 \\u20AC")); expectCurrency(*fmt, Locale::getJapan(), - 1234.56, CharsToUnicodeString("1 235 \\u00A5")); // Yen + 1234.56, CharsToUnicodeString("1 235 \\u00A5JP")); // Yen expectCurrency(*fmt, Locale("fr", "CH", ""), 1234.56, "1 234,55 sFr."); // 0.05 rounding expectCurrency(*fmt, Locale::getUS(), - 1234.56, "1 234,56 $"); + 1234.56, "1 234,56 $US"); expectCurrency(*fmt, Locale::getFrance(), 1234.56, CharsToUnicodeString("1 234,56 \\u20AC")); // Euro @@ -726,7 +795,9 @@ NumberFormatTest::TestParse(void) UnicodeString arg("0"); DecimalFormat* format = new DecimalFormat("00", status); //try { - Formattable n; format->parse(arg, n, status); + Formattable n; + + format->parse(arg, n, status); logln((UnicodeString)"parse(" + arg + ") = " + n.getLong()); if (n.getType() != Formattable::kLong || n.getLong() != 0) errln((UnicodeString)"FAIL: Expected 0"); @@ -740,6 +811,238 @@ NumberFormatTest::TestParse(void) // ------------------------------------- +static const char *lenientAffixTestCases[] = { + "(1)", + "( 1)", + "(1 )", + "( 1 )" +}; + +static const char *lenientMinusTestCases[] = { + "-5", + "\\u22125", + "\\u20105" +}; + +static const char *lenientCurrencyTestCases[] = { + "$1,000", + "$ 1,000", + "$1000", + "$ 1000", + "$1 000.00", + "$ 1 000.00", + "$ 1\\u00A0000.00", + "1000.00" +}; + +static const char *lenientNegativeCurrencyTestCases[] = { + "($1,000)", + "($ 1,000)", + "($1000)", + "($ 1000)", + "($1 000.00)", + "($ 1 000.00)", + "( $ 1,000.00 )", + "($ 1\\u00A0000.00)", + "(1000.00)" +}; + +static const char *lenientPercentTestCases[] = { + "25%", + " 25%", + " 25 %", + "25 %", + "25\\u00A0%", + "25" +}; + +static const char *lenientNegativePercentTestCases[] = { + "-25%", + " -25%", + " - 25%", + "- 25 %", + " - 25 %", + "-25 %", + "-25\\u00A0%", + "-25", + "- 25" +}; + +static const char *strictFailureTestCases[] = { + " 1000", +#if 0 + "10,00", + "1,000,.0" +#endif +}; + +#define ARRAY_SIZE(array) ((int32_t) (sizeof (array) / sizeof(array[0]))) + +/** + * Test lenient parsing. + */ +void +NumberFormatTest::TestLenientParse(void) +{ + UErrorCode status = U_ZERO_ERROR; + DecimalFormat *format = new DecimalFormat("(#,##0)", status); + Formattable n; + + format->setParseStrict(FALSE); + for (int32_t t = 0; t < ARRAY_SIZE (lenientAffixTestCases); t += 1) { + UnicodeString testCase = ctou(lenientAffixTestCases[t]); + + format->parse(testCase, n, status); + logln((UnicodeString)"parse(" + testCase + ") = " + n.getLong()); + + if (U_FAILURE(status) || n.getType() != Formattable::kLong || + n.getLong() != 1) { + errln((UnicodeString)"Lenient parse failed for \"" + (UnicodeString) lenientAffixTestCases[t] + (UnicodeString) "\""); + status = U_ZERO_ERROR; + } + } + + delete format; + + Locale en_US("en_US"); + Locale sv_SE("sv_SE"); + + NumberFormat *mFormat = NumberFormat::createInstance(sv_SE, status); + + mFormat->setParseStrict(FALSE); + for (int32_t t = 0; t < ARRAY_SIZE(lenientMinusTestCases); t += 1) { + UnicodeString testCase = ctou(lenientMinusTestCases[t]); + + mFormat->parse(testCase, n, status); + logln((UnicodeString)"parse(" + testCase + ") = " + n.getLong()); + + if (U_FAILURE(status) || n.getType() != Formattable::kLong || n.getLong() != -5) { + errln((UnicodeString)"Lenient parse failed for \"" + (UnicodeString) lenientMinusTestCases[t] + (UnicodeString) "\""); + status = U_ZERO_ERROR; + } + } + + delete mFormat; + + mFormat = NumberFormat::createInstance(en_US, status); + + mFormat->setParseStrict(FALSE); + for (int32_t t = 0; t < ARRAY_SIZE(lenientMinusTestCases); t += 1) { + UnicodeString testCase = ctou(lenientMinusTestCases[t]); + + mFormat->parse(testCase, n, status); + logln((UnicodeString)"parse(" + testCase + ") = " + n.getLong()); + + if (U_FAILURE(status) || n.getType() != Formattable::kLong || n.getLong() != -5) { + errln((UnicodeString)"Lenient parse failed for \"" + (UnicodeString) lenientMinusTestCases[t] + (UnicodeString) "\""); + status = U_ZERO_ERROR; + } + } + + delete mFormat; + + NumberFormat *cFormat = NumberFormat::createCurrencyInstance(en_US, status); + + cFormat->setParseStrict(FALSE); + for (int32_t t = 0; t < ARRAY_SIZE (lenientCurrencyTestCases); t += 1) { + UnicodeString testCase = ctou(lenientCurrencyTestCases[t]); + + cFormat->parse(testCase, n, status); + logln((UnicodeString)"parse(" + testCase + ") = " + n.getLong()); + + if (U_FAILURE(status) ||n.getType() != Formattable::kLong || + n.getLong() != 1000) { + errln((UnicodeString)"Lenient parse failed for \"" + (UnicodeString) lenientCurrencyTestCases[t] + (UnicodeString) "\""); + status = U_ZERO_ERROR; + } + } + + for (int32_t t = 0; t < ARRAY_SIZE (lenientNegativeCurrencyTestCases); t += 1) { + UnicodeString testCase = ctou(lenientNegativeCurrencyTestCases[t]); + ParsePosition pos(0); + + cFormat->parse(testCase, n, /*status*/pos); + logln((UnicodeString)"parse(" + testCase + ") = " + n.getLong()); + + if (/*U_FAILURE(status)*/pos.getErrorIndex() >= 0 ||n.getType() != Formattable::kLong || + n.getLong() != -1000) { + errln((UnicodeString)"Lenient parse failed for \"" + (UnicodeString) lenientNegativeCurrencyTestCases[t] + (UnicodeString) "\" parse position = " + + pos.getIndex() + ", " + pos.getErrorIndex()); + status = U_ZERO_ERROR; + } + } + + delete cFormat; + + NumberFormat *pFormat = NumberFormat::createPercentInstance(en_US, status); + + pFormat->setParseStrict(FALSE); + for (int32_t t = 0; t < ARRAY_SIZE (lenientPercentTestCases); t += 1) { + UnicodeString testCase = ctou(lenientPercentTestCases[t]); + + pFormat->parse(testCase, n, status); + logln((UnicodeString)"parse(" + testCase + ") = " + n.getDouble()); + + if (U_FAILURE(status) ||n.getType() != Formattable::kDouble || + n.getDouble() != 0.25) { + errln((UnicodeString)"Lenient parse failed for \"" + (UnicodeString) lenientPercentTestCases[t] + (UnicodeString) "\""); + status = U_ZERO_ERROR; + } + } + + for (int32_t t = 0; t < ARRAY_SIZE (lenientNegativePercentTestCases); t += 1) { + UnicodeString testCase = ctou(lenientNegativePercentTestCases[t]); + + pFormat->parse(testCase, n, status); + logln((UnicodeString)"parse(" + testCase + ") = " + n.getDouble()); + + if (U_FAILURE(status) ||n.getType() != Formattable::kDouble || + n.getDouble() != -0.25) { + errln((UnicodeString)"Lenient parse failed for \"" + (UnicodeString) lenientNegativePercentTestCases[t] + (UnicodeString) "\""); + status = U_ZERO_ERROR; + } + } + + delete pFormat; + + // Test cases that should fail with a strict parse and pass with a + // lenient parse. + NumberFormat *nFormat = NumberFormat::createInstance(en_US, status); + + // first, make sure that they fail with a strict parse + for (int32_t t = 0; t < ARRAY_SIZE(strictFailureTestCases); t += 1) { + UnicodeString testCase = ctou(strictFailureTestCases[t]); + + nFormat->parse(testCase, n, status); + logln((UnicodeString)"parse(" + testCase + ") = " + n.getLong()); + + if (! U_FAILURE(status)) { + errln((UnicodeString)"Strict Parse succeeded for \"" + (UnicodeString) strictFailureTestCases[t] + (UnicodeString) "\""); + } + + status = U_ZERO_ERROR; + } + + // then, make sure that they pass with a lenient parse + nFormat->setParseStrict(FALSE); + for (int32_t t = 0; t < ARRAY_SIZE(strictFailureTestCases); t += 1) { + UnicodeString testCase = ctou(strictFailureTestCases[t]); + + nFormat->parse(testCase, n, status); + logln((UnicodeString)"parse(" + testCase + ") = " + n.getLong()); + + if (U_FAILURE(status) ||n.getType() != Formattable::kLong || + n.getLong() != 1000) { + errln((UnicodeString)"Lenient parse failed for \"" + (UnicodeString) strictFailureTestCases[t] + (UnicodeString) "\""); + status = U_ZERO_ERROR; + } + } + + delete nFormat; +} + +// ------------------------------------- + /** * Test proper rounding by the format method. */ @@ -748,6 +1051,11 @@ NumberFormatTest::TestRounding487(void) { UErrorCode status = U_ZERO_ERROR; NumberFormat *nf = NumberFormat::createInstance(status); + if (U_FAILURE(status)) { + dataerrln("Error calling NumberFormat::createInstance()"); + return; + } + roundingTest(*nf, 0.00159999, 4, "0.0016"); roundingTest(*nf, 0.00995, 4, "0.01"); @@ -836,21 +1144,22 @@ void NumberFormatTest::TestWhiteSpaceParsing(void) { /** * Test currencies whose display name is a ChoiceFormat. + * Less useful now that INR is no longer a choice format! See cldrbug 1961 ! */ void NumberFormatTest::TestComplexCurrency() { UErrorCode ec = U_ZERO_ERROR; - Locale loc("en", "IN", ""); + Locale loc("kn", "IN", ""); NumberFormat* fmt = NumberFormat::createCurrencyInstance(loc, ec); if (U_SUCCESS(ec)) { - expect2(*fmt, 1.0, "Re. 1.00"); + expect2(*fmt, 1.0, CharsToUnicodeString("Rs.\\u00A01.00")); // Use .00392625 because that's 2^-8. Any value less than 0.005 is fine. - expect(*fmt, 1.00390625, "Re. 1.00"); // tricky - expect2(*fmt, 12345678.0, "Rs. 1,23,45,678.00"); - expect2(*fmt, 0.5, "Rs. 0.50"); - expect2(*fmt, -1.0, "-Re. 1.00"); - expect2(*fmt, -10.0, "-Rs. 10.00"); + expect(*fmt, 1.00390625, CharsToUnicodeString("Rs.\\u00A01.00")); // tricky + expect2(*fmt, 12345678.0, CharsToUnicodeString("Rs.\\u00A01,23,45,678.00")); + expect2(*fmt, 0.5, CharsToUnicodeString("Rs.\\u00A00.50")); + expect2(*fmt, -1.0, CharsToUnicodeString("-Rs.\\u00A01.00")); + expect2(*fmt, -10.0, CharsToUnicodeString("-Rs.\\u00A010.00")); } else { - errln("FAIL: getCurrencyInstance(en_IN)"); + errln("FAIL: getCurrencyInstance(kn_IN)"); } delete fmt; } @@ -1290,7 +1599,7 @@ void NumberFormatTest::TestSurrogateSupport(void) { custom.setSymbol(DecimalFormatSymbols::kZeroDigitSymbol, (UChar)0x30); custom.setSymbol(DecimalFormatSymbols::kCurrencySymbol, "units of money"); custom.setSymbol(DecimalFormatSymbols::kMonetarySeparatorSymbol, "money separator"); - patternStr = "0.00 \\u00A4' in your bank account'"; + patternStr = UNICODE_STRING_SIMPLE("0.00 \\u00A4' in your bank account'"); patternStr = patternStr.unescape(); expStr = UnicodeString(" minus 20money separator00 units of money in your bank account", ""); status = U_ZERO_ERROR; @@ -1418,13 +1727,16 @@ void NumberFormatTest::TestCurrencyNames(void) { // Do a basic check of getName() // USD { "US$", "US Dollar" } // 04/04/1792- UErrorCode ec = U_ZERO_ERROR; - static const UChar USD[] = {85, 83, 68, 0}; /*USD*/ + static const UChar USD[] = {0x55, 0x53, 0x44, 0}; /*USD*/ + static const UChar USX[] = {0x55, 0x53, 0x58, 0}; /*USX*/ + static const UChar CAD[] = {0x43, 0x41, 0x44, 0}; /*CAD*/ + static const UChar ITL[] = {0x49, 0x54, 0x4C, 0}; /*ITL*/ UBool isChoiceFormat; int32_t len; // Warning: HARD-CODED LOCALE DATA in this test. If it fails, CHECK // THE LOCALE DATA before diving into the code. assertEquals("USD.getName(SYMBOL_NAME)", - UnicodeString("US$"), + UnicodeString("$"), UnicodeString(ucurr_getName(USD, "en", UCURR_SYMBOL_NAME, &isChoiceFormat, &len, &ec))); @@ -1433,11 +1745,109 @@ void NumberFormatTest::TestCurrencyNames(void) { UnicodeString(ucurr_getName(USD, "en", UCURR_LONG_NAME, &isChoiceFormat, &len, &ec))); + assertEquals("CAD.getName(SYMBOL_NAME)", + UnicodeString("CA$"), + UnicodeString(ucurr_getName(CAD, "en", + UCURR_SYMBOL_NAME, + &isChoiceFormat, &len, &ec))); + assertEquals("CAD.getName(SYMBOL_NAME)", + UnicodeString("$"), + UnicodeString(ucurr_getName(CAD, "en_CA", + UCURR_SYMBOL_NAME, + &isChoiceFormat, &len, &ec))); + assertEquals("USD.getName(SYMBOL_NAME)", + UnicodeString("US$"), + UnicodeString(ucurr_getName(USD, "en_AU", + UCURR_SYMBOL_NAME, + &isChoiceFormat, &len, &ec))); + assertEquals("CAD.getName(SYMBOL_NAME)", + UnicodeString("CA$"), + UnicodeString(ucurr_getName(CAD, "en_AU", + UCURR_SYMBOL_NAME, + &isChoiceFormat, &len, &ec))); + assertEquals("USX.getName(LONG_NAME)", + UnicodeString("USX"), + UnicodeString(ucurr_getName(USX, "en_US", + UCURR_LONG_NAME, + &isChoiceFormat, &len, &ec))); assertSuccess("ucurr_getName", ec); + ec = U_ZERO_ERROR; + + // Test that a default or fallback warning is being returned. JB 4239. + ucurr_getName(CAD, "es_ES", UCURR_LONG_NAME, &isChoiceFormat, + &len, &ec); + assertTrue("ucurr_getName (fallback)", + U_USING_FALLBACK_WARNING == ec, TRUE); + + ucurr_getName(CAD, "zh_TW", UCURR_LONG_NAME, &isChoiceFormat, + &len, &ec); + assertTrue("ucurr_getName (fallback)", + U_USING_FALLBACK_WARNING == ec, TRUE); + + ucurr_getName(CAD, "en_US", UCURR_LONG_NAME, &isChoiceFormat, + &len, &ec); + assertTrue("ucurr_getName (default)", + U_USING_DEFAULT_WARNING == ec, TRUE); + + ucurr_getName(CAD, "vi", UCURR_LONG_NAME, &isChoiceFormat, + &len, &ec); + assertTrue("ucurr_getName (default)", + U_USING_DEFAULT_WARNING == ec, TRUE); + + // Test that a default warning is being returned when falling back to root. JB 4536. + ucurr_getName(ITL, "cy", UCURR_LONG_NAME, &isChoiceFormat, + &len, &ec); + assertTrue("ucurr_getName (default to root)", + U_USING_DEFAULT_WARNING == ec, TRUE); + // TODO add more tests later } +void NumberFormatTest::TestCurrencyUnit(void){ + UErrorCode ec = U_ZERO_ERROR; + static const UChar USD[] = {85, 83, 68, 0}; /*USD*/ + CurrencyUnit cu(USD, ec); + assertSuccess("CurrencyUnit", ec); + + const UChar * r = cu.getISOCurrency(); // who is the buffer owner ? + assertEquals("getISOCurrency()", USD, r); + + CurrencyUnit cu2(cu); + if (!(cu2 == cu)){ + errln("CurrencyUnit copy constructed object should be same"); + } + + CurrencyUnit * cu3 = (CurrencyUnit *)cu.clone(); + if (!(*cu3 == cu)){ + errln("CurrencyUnit cloned object should be same"); + } + delete cu3; +} + +void NumberFormatTest::TestCurrencyAmount(void){ + UErrorCode ec = U_ZERO_ERROR; + static const UChar USD[] = {85, 83, 68, 0}; /*USD*/ + CurrencyAmount ca(9, USD, ec); + assertSuccess("CurrencyAmount", ec); + + CurrencyAmount ca2(ca); + if (!(ca2 == ca)){ + errln("CurrencyAmount copy constructed object should be same"); + } + + ca2=ca; + if (!(ca2 == ca)){ + errln("CurrencyAmount assigned object should be same"); + } + + CurrencyAmount *ca3 = (CurrencyAmount *)ca.clone(); + if (!(*ca3 == ca)){ + errln("CurrencyAmount cloned object should be same"); + } + delete ca3; +} + void NumberFormatTest::TestSymbolsWithBadLocale(void) { Locale locDefault; Locale locBad("x-crazy_ZZ_MY_SPECIAL_ADMINISTRATION_REGION_NEEDS_A_SPECIAL_VARIANT_WITH_A_REALLY_REALLY_REALLY_REALLY_REALLY_REALLY_REALLY_LONG_NAME"); @@ -1462,7 +1872,8 @@ void NumberFormatTest::TestSymbolsWithBadLocale(void) { + prettify(mySymbols.getSymbol((DecimalFormatSymbols::ENumberFormatSymbol)symbolEnum))); if (mySymbols.getSymbol((DecimalFormatSymbols::ENumberFormatSymbol)symbolEnum).length() == 0 - && symbolEnum != (int)DecimalFormatSymbols::kGroupingSeparatorSymbol) + && symbolEnum != (int)DecimalFormatSymbols::kGroupingSeparatorSymbol + && symbolEnum != (int)DecimalFormatSymbols::kMonetaryGroupingSeparatorSymbol) { errln("DecimalFormatSymbols has an empty string at index %d.", symbolEnum); } @@ -1647,7 +2058,7 @@ void NumberFormatTest::TestCases() { UErrorCode ec = U_ZERO_ERROR; TextFile reader("NumberFormatTestCases.txt", "UTF8", ec); if (U_FAILURE(ec)) { - errln("FAIL: Couldn't open NumberFormatTestCases.txt"); + dataerrln("[DATA] Couldn't open NumberFormatTestCases.txt"); return; } TokenIterator tokens(&reader); @@ -1672,6 +2083,10 @@ void NumberFormatTest::TestCases() { delete ref; ref = new DecimalFormat(tok, new DecimalFormatSymbols(Locale::getUS(), ec), ec); + if (U_FAILURE(ec)) { + dataerrln("Error constructing DecimalFormat"); + goto error; + } break; case 1: // loc= @@ -1972,6 +2387,7 @@ void NumberFormatTest::expectCurrency(NumberFormat& nf, const Locale& locale, assertSuccess("ucurr_forLocale", ec); fmt.setCurrency(curr, ec); assertSuccess("DecimalFormat::setCurrency", ec); + fmt.setCurrency(curr); //Deprecated variant, for coverage only } UnicodeString s; fmt.format(value, s); @@ -2045,5 +2461,304 @@ void NumberFormatTest::expectPad(DecimalFormat& fmt, const UnicodeString& pat, ", expected " + pos + " " + width + " " + pad); } } +void NumberFormatTest::TestJB3832(){ + const char* localeID = "pt_PT@currency=PTE"; + Locale loc(localeID); + UErrorCode status = U_ZERO_ERROR; + UnicodeString expected(CharsToUnicodeString("1,150$50\\u00A0Esc.")); + UnicodeString s; + NumberFormat* currencyFmt = NumberFormat::createCurrencyInstance(loc, status); + if(U_FAILURE(status)){ + errln("Could not create currency formatter for locale %s", localeID); + return; + } + currencyFmt->format(1150.50, s); + if(s!=expected){ + errln(UnicodeString("FAIL: Expected: ")+expected + + UnicodeString(" Got: ") + s + + UnicodeString( " for locale: ")+ UnicodeString(localeID) ); + } + if (U_FAILURE(status)){ + errln("FAIL: Status %s", u_errorName(status)); + } + delete currencyFmt; +} + +void NumberFormatTest::TestHost() +{ +#ifdef U_WINDOWS + Win32NumberTest::testLocales(this); +#endif +} + +void NumberFormatTest::TestHostClone() +{ + /* + Verify that a cloned formatter gives the same results + and is useable after the original has been deleted. + */ + // This is mainly important on Windows. + UErrorCode status = U_ZERO_ERROR; + Locale loc("en_US@compat=host"); + UDate now = Calendar::getNow(); + NumberFormat *full = NumberFormat::createInstance(loc, status); + if (full == NULL || U_FAILURE(status)) { + errln("FAIL: Can't create Relative date instance"); + return; + } + UnicodeString result1; + full->format(now, result1, status); + Format *fullClone = full->clone(); + delete full; + full = NULL; + + UnicodeString result2; + fullClone->format(now, result2, status); + if (U_FAILURE(status)) { + errln("FAIL: format failure."); + } + if (result1 != result2) { + errln("FAIL: Clone returned different result from non-clone."); + } + delete fullClone; +} + +void NumberFormatTest::TestCurrencyFormat() +{ + // This test is here to increase code coverage. + UErrorCode status = U_ZERO_ERROR; + MeasureFormat *cloneObj; + UnicodeString str; + Formattable toFormat, result; + static const UChar ISO_CODE[4] = {0x0047, 0x0042, 0x0050, 0}; + + Locale saveDefaultLocale = Locale::getDefault(); + Locale::setDefault( Locale::getUK(), status ); + if (U_FAILURE(status)) { + errln("couldn't set default Locale!"); + return; + } + + MeasureFormat *measureObj = MeasureFormat::createCurrencyFormat(status); + Locale::setDefault( saveDefaultLocale, status ); + if (U_FAILURE(status)){ + errln("FAIL: Status %s", u_errorName(status)); + return; + } + cloneObj = (MeasureFormat *)measureObj->clone(); + if (cloneObj == NULL) { + errln("Clone doesn't work"); + return; + } + toFormat.adoptObject(new CurrencyAmount(1234.56, ISO_CODE, status)); + measureObj->format(toFormat, str, status); + measureObj->parseObject(str, result, status); + if (U_FAILURE(status)){ + errln("FAIL: Status %s", u_errorName(status)); + } + if (result != toFormat) { + errln("measureObj does not round trip. Formatted string was \"" + str + "\" Got: " + toString(result) + " Expected: " + toString(toFormat)); + } + status = U_ZERO_ERROR; + str.truncate(0); + cloneObj->format(toFormat, str, status); + cloneObj->parseObject(str, result, status); + if (U_FAILURE(status)){ + errln("FAIL: Status %s", u_errorName(status)); + } + if (result != toFormat) { + errln("Clone does not round trip. Formatted string was \"" + str + "\" Got: " + toString(result) + " Expected: " + toString(toFormat)); + } + if (*measureObj != *cloneObj) { + errln("Cloned object is not equal to the original object"); + } + delete measureObj; + delete cloneObj; + + status = U_USELESS_COLLATOR_ERROR; + if (MeasureFormat::createCurrencyFormat(status) != NULL) { + errln("createCurrencyFormat should have returned NULL."); + } +} + +/* Port of ICU4J rounding test. */ +void NumberFormatTest::TestRounding() { + UErrorCode status = U_ZERO_ERROR; + DecimalFormat *df = (DecimalFormat*)NumberFormat::createCurrencyInstance(Locale::getEnglish(), status); + + if (U_FAILURE(status)) { + errln("Unable to create decimal formatter."); + return; + } + + int roundingIncrements[]={1, 2, 5, 20, 50, 100}; + int testValues[]={0, 300}; + + for (int j=0; j<2; j++) { + for (int mode=DecimalFormat::kRoundUp;modesetRoundingMode((DecimalFormat::ERoundingMode)mode); + for (int increment=0; increment<6; increment++) { + double base=testValues[j]; + double rInc=roundingIncrements[increment]; + checkRounding(df, base, 20, rInc); + rInc=1.000000000/rInc; + checkRounding(df, base, 20, rInc); + } + } + } + delete df; +} + +void NumberFormatTest::checkRounding(DecimalFormat* df, double base, int iterations, double increment) { + df->setRoundingIncrement(increment); + double lastParsed=INT32_MIN; //Intger.MIN_VALUE + for (int i=-iterations; i<=iterations;i++) { + double iValue=base+(increment*(i*0.1)); + double smallIncrement=0.00000001; + if (iValue!=0) { + smallIncrement*=iValue; + } + //we not only test the value, but some values in a small range around it + lastParsed=checkRound(df, iValue-smallIncrement, lastParsed); + lastParsed=checkRound(df, iValue, lastParsed); + lastParsed=checkRound(df, iValue+smallIncrement, lastParsed); + } +} + +double NumberFormatTest::checkRound(DecimalFormat* df, double iValue, double lastParsed) { + UErrorCode status=U_ZERO_ERROR; + UnicodeString formattedDecimal; + double parsed; + Formattable result; + df->format(iValue, formattedDecimal, status); + + if (U_FAILURE(status)) { + errln("Error formatting number."); + } + + df->parse(formattedDecimal, result, status); + + if (U_FAILURE(status)) { + errln("Error parsing number."); + } + + parsed=result.getDouble(); + + if (lastParsed>parsed) { + errln("Rounding wrong direction! %d > %d", lastParsed, parsed); + } + + return lastParsed; +} + +void NumberFormatTest::TestNonpositiveMultiplier() { + UErrorCode status = U_ZERO_ERROR; + DecimalFormatSymbols US(Locale::getUS(), status); + CHECK(status, "DecimalFormatSymbols constructor"); + DecimalFormat df(UnicodeString("0"), US, status); + CHECK(status, "DecimalFormat(0)"); + + // test zero multiplier + + int32_t mult = df.getMultiplier(); + df.setMultiplier(0); + if (df.getMultiplier() != mult) { + errln("DecimalFormat.setMultiplier(0) did not ignore its zero input"); + } + + // test negative multiplier + + df.setMultiplier(-1); + if (df.getMultiplier() != -1) { + errln("DecimalFormat.setMultiplier(-1) ignored its negative input"); + return; + } + + expect(df, "1122.123", -1122.123); + expect(df, "-1122.123", 1122.123); + expect(df, "1.2", -1.2); + expect(df, "-1.2", 1.2); + + // TODO: change all the following int64_t tests once BigInteger is ported + // (right now the big numbers get turned into doubles and lose tons of accuracy) + static const char* posOutOfRange = "9223372036854780000"; + static const char* negOutOfRange = "-9223372036854780000"; + + expect(df, U_INT64_MIN, posOutOfRange); + expect(df, U_INT64_MIN+1, "9223372036854775807"); + expect(df, (int64_t)-123, "123"); + expect(df, (int64_t)123, "-123"); + expect(df, U_INT64_MAX-1, "-9223372036854775806"); + expect(df, U_INT64_MAX, "-9223372036854775807"); + + df.setMultiplier(-2); + expect(df, -(U_INT64_MIN/2)-1, "-9223372036854775806"); + expect(df, -(U_INT64_MIN/2), "-9223372036854775808"); + expect(df, -(U_INT64_MIN/2)+1, negOutOfRange); + + df.setMultiplier(-7); + expect(df, -(U_INT64_MAX/7)-1, posOutOfRange); + expect(df, -(U_INT64_MAX/7), "9223372036854775807"); + expect(df, -(U_INT64_MAX/7)+1, "9223372036854775800"); + + // TODO: uncomment (and fix up) all the following int64_t tests once BigInteger is ported + // (right now the big numbers get turned into doubles and lose tons of accuracy) + //expect2(df, U_INT64_MAX, Int64ToUnicodeString(-U_INT64_MAX)); + //expect2(df, U_INT64_MIN, UnicodeString(Int64ToUnicodeString(U_INT64_MIN), 1)); + //expect2(df, U_INT64_MAX / 2, Int64ToUnicodeString(-(U_INT64_MAX / 2))); + //expect2(df, U_INT64_MIN / 2, Int64ToUnicodeString(-(U_INT64_MIN / 2))); + + // TODO: uncomment (and fix up) once BigDecimal is ported and DecimalFormat can handle it + //expect2(df, BigDecimal.valueOf(Long.MAX_VALUE), BigDecimal.valueOf(Long.MAX_VALUE).negate().toString()); + //expect2(df, BigDecimal.valueOf(Long.MIN_VALUE), BigDecimal.valueOf(Long.MIN_VALUE).negate().toString()); + //expect2(df, java.math.BigDecimal.valueOf(Long.MAX_VALUE), java.math.BigDecimal.valueOf(Long.MAX_VALUE).negate().toString()); + //expect2(df, java.math.BigDecimal.valueOf(Long.MIN_VALUE), java.math.BigDecimal.valueOf(Long.MIN_VALUE).negate().toString()); +} + +void +NumberFormatTest::TestSpaceParsing() { + // the data are: + // the string to be parsed, parsed position, parsed error index + const char* DATA[][3] = { + {"$124", "4", "-1"}, + {"$124 $124", "4", "-1"}, + {"$124 ", "4", "-1"}, + {"$ 124 ", "5", "-1"}, + {"$\\u00A0124 ", "5", "-1"}, + {" $ 124 ", "6", "-1"}, + //{"124$", "4", "-1"}, // TODO: need to handle trailing currency correctly + {"124$", "3", "-1"}, + //{"124 $", "5", "-1"}, // TODO: OK or not, need currency spacing rule + {"124 $", "3", "-1"}, + }; + + UErrorCode status = U_ZERO_ERROR; + Locale locale("en_US"); + NumberFormat* foo = NumberFormat::createCurrencyInstance(locale, status); + if (U_FAILURE(status)) { + delete foo; + return; + } + + foo->setParseStrict(FALSE); + for (uint32_t i = 0; i < sizeof(DATA)/sizeof(DATA[0]); ++i) { + ParsePosition parsePosition(0); + UnicodeString stringToBeParsed = ctou(DATA[i][0]); + int parsedPosition = atoi(DATA[i][1]); + int errorIndex = atoi(DATA[i][2]); + Formattable result; + foo->parse(stringToBeParsed, result, parsePosition); + if (parsePosition.getIndex() != parsedPosition || + parsePosition.getErrorIndex() != errorIndex) { + errln("FAILED parse " + stringToBeParsed + "; wrong position, expected: (" + parsedPosition + ", " + errorIndex + "); got (" + parsePosition.getIndex() + ", " + parsePosition.getErrorIndex() + ")"); + } + if (parsePosition.getErrorIndex() == -1 && + result.getType() == Formattable::kLong && + result.getLong() != 124) { + errln("FAILED parse " + stringToBeParsed + "; wrong number, expect: 124, got " + result.getLong()); + } + } + delete foo; +} #endif /* #if !UCONFIG_NO_FORMATTING */