From: Peter Edberg Date: Tue, 12 Jul 2011 03:22:59 +0000 (+0000) Subject: ICU-8583 Only parse arbitrary currency for calls that can return the found currency... X-Git-Tag: milestone-59-0-1~4662 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=f5ccf251ef1a03bb784d81d5c88400d467453e30;p=icu ICU-8583 Only parse arbitrary currency for calls that can return the found currency (e.g. parseCurrency) X-SVN-Rev: 30313 --- diff --git a/icu4c/source/i18n/decimfmt.cpp b/icu4c/source/i18n/decimfmt.cpp index fa671fcddcf..a9d7d17285c 100644 --- a/icu4c/source/i18n/decimfmt.cpp +++ b/icu4c/source/i18n/decimfmt.cpp @@ -2518,6 +2518,16 @@ int32_t DecimalFormat::compareComplexAffix(const UnicodeString& affixPat, if (U_SUCCESS(ec) && ppos.getIndex() != pos) { if (currency) { u_strcpy(currency, curr); + } else { + // The formatter is currency-style but the client has not requested + // the value of the parsed currency. In this case, if that value does + // not match the formatter's current value, then the parse fails. + UChar effectiveCurr[4]; + getEffectiveCurrency(effectiveCurr, ec); + if ( U_FAILURE(ec) || u_strncmp(curr,effectiveCurr,4) != 0 ) { + pos = -1; + continue; + } } pos = ppos.getIndex(); } else if (!isLenient()){ diff --git a/icu4c/source/test/cintltst/cnumtst.c b/icu4c/source/test/cintltst/cnumtst.c index cd371ca90be..73e484dc4f3 100644 --- a/icu4c/source/test/cintltst/cnumtst.c +++ b/icu4c/source/test/cintltst/cnumtst.c @@ -39,6 +39,7 @@ void addNumForTest(TestNode** root); static void TestTextAttributeCrash(void); static void TestNBSPInPattern(void); static void TestInt64Parse(void); +static void TestParseCurrency(void); #define TESTCASE(x) addTest(root, &x, "tsformat/cnumtst/" #x) @@ -57,6 +58,7 @@ void addNumForTest(TestNode** root) TESTCASE(TestNBSPInPattern); TESTCASE(TestInt64Parse); TESTCASE(TestParseZero); + TESTCASE(TestParseCurrency); } /** copy src to dst with unicode-escapes for values < 0x20 and > 0x7e, null terminate if possible */ @@ -990,6 +992,136 @@ static void TestParseZero(void) unum_close(unum); } +static const UChar dollars2Sym[] = { 0x24,0x32,0x2E,0x30,0x30,0 }; /* $2.00 */ +static const UChar dollars4Sym[] = { 0x24,0x34,0 }; /* $4 */ +static const UChar dollars9Sym[] = { 0x39,0xA0,0x24,0 }; /* 9 $ */ +static const UChar pounds3Sym[] = { 0xA3,0x33,0x2E,0x30,0x30,0 }; /* [POUND]3.00 */ +static const UChar pounds5Sym[] = { 0xA3,0x35,0 }; /* [POUND]5 */ +static const UChar pounds7Sym[] = { 0x37,0xA0,0xA3,0 }; /* 7 [POUND] */ +static const UChar euros4Sym[] = { 0x34,0x2C,0x30,0x30,0xA0,0x20AC,0 }; /* 4,00 [EURO] */ +static const UChar euros6Sym[] = { 0x36,0xA0,0x20AC,0 }; /* 6 [EURO] */ +static const UChar euros8Sym[] = { 0x20AC,0x38,0 }; /* [EURO]8 */ +static const UChar dollars4PluEn[] = { 0x34,0x20,0x55,0x53,0x20,0x64,0x6F,0x6C,0x6C,0x61,0x72,0x73,0 }; /* 4 US dollars*/ +static const UChar pounds5PluEn[] = { 0x35,0x20,0x42,0x72,0x69,0x74,0x69,0x73,0x68,0x20,0x70,0x6F,0x75,0x6E,0x64,0x73,0x20,0x73,0x74,0x65,0x72,0x6C,0x69,0x6E,0x67,0 }; /* 5 British pounds sterling */ +static const UChar euros8PluEn[] = { 0x38,0x20,0x65,0x75,0x72,0x6F,0x73,0 }; /* 8 euros*/ +static const UChar euros6PluFr[] = { 0x36,0x20,0x65,0x75,0x72,0x6F,0x73,0 }; /* 6 euros*/ + +typedef struct { + const char * locale; + const char * descrip; + const UChar * currStr; + const UChar * plurStr; + UErrorCode parsDoubExpectErr; + int32_t parsDoubExpectPos; + double parsDoubExpectVal; + UErrorCode parsCurrExpectErr; + int32_t parsCurrExpectPos; + double parsCurrExpectVal; + const char * parsCurrExpectCurr; +} ParseCurrencyItem; + +static const ParseCurrencyItem parseCurrencyItems[] = { + { "en_US", "dollars2", dollars2Sym, NULL, U_ZERO_ERROR, 5, 2.0, U_ZERO_ERROR, 5, 2.0, "USD" }, + { "en_US", "dollars4", dollars4Sym, dollars4PluEn, U_ZERO_ERROR, 2, 4.0, U_ZERO_ERROR, 2, 4.0, "USD" }, + { "en_US", "dollars9", dollars9Sym, NULL, U_PARSE_ERROR, 1, 0.0, U_PARSE_ERROR, 1, 0.0, "" }, + { "en_US", "pounds3", pounds3Sym, NULL, U_PARSE_ERROR, 0, 0.0, U_ZERO_ERROR, 5, 3.0, "GBP" }, + { "en_US", "pounds5", pounds5Sym, pounds5PluEn, U_PARSE_ERROR, 0, 0.0, U_ZERO_ERROR, 2, 5.0, "GBP" }, + { "en_US", "pounds7", pounds7Sym, NULL, U_PARSE_ERROR, 1, 0.0, U_PARSE_ERROR, 1, 0.0, "" }, + { "en_US", "euros8", euros8Sym, euros8PluEn, U_PARSE_ERROR, 0, 0.0, U_ZERO_ERROR, 2, 8.0, "EUR" }, + + { "en_GB", "pounds3", pounds3Sym, NULL, U_ZERO_ERROR, 5, 3.0, U_ZERO_ERROR, 5, 3.0, "GBP" }, + { "en_GB", "pounds5", pounds5Sym, pounds5PluEn, U_ZERO_ERROR, 2, 5.0, U_ZERO_ERROR, 2, 5.0, "GBP" }, + { "en_GB", "pounds7", pounds7Sym, NULL, U_PARSE_ERROR, 1, 0.0, U_PARSE_ERROR, 1, 0.0, "" }, + { "en_GB", "euros4", euros4Sym, NULL, U_PARSE_ERROR, 4, 0.0, U_PARSE_ERROR, 4, 0.0, "" }, + { "en_GB", "euros6", euros6Sym, NULL, U_PARSE_ERROR, 1, 0.0, U_PARSE_ERROR, 1, 0.0, "" }, + { "en_GB", "euros8", euros8Sym, euros8PluEn, U_PARSE_ERROR, 0, 0.0, U_ZERO_ERROR, 2, 8.0, "EUR" }, + { "en_GB", "dollars4", dollars4Sym, dollars4PluEn, U_PARSE_ERROR, 0, 0.0, U_ZERO_ERROR, 2, 4.0, "USD" }, + + { "fr_FR", "euros4", euros4Sym, NULL, U_ZERO_ERROR, 6, 4.0, U_ZERO_ERROR, 6, 4.0, "EUR" }, + { "fr_FR", "euros6", euros6Sym, euros6PluFr, U_ZERO_ERROR, 3, 6.0, U_ZERO_ERROR, 3, 6.0, "EUR" }, + { "fr_FR", "euros8", euros8Sym, NULL, U_PARSE_ERROR, 0, 0.0, U_PARSE_ERROR, 0, 0.0, "" }, + { "fr_FR", "dollars2", dollars2Sym, NULL, U_PARSE_ERROR, 0, 0.0, U_PARSE_ERROR, 0, 0.0, "" }, + { "fr_FR", "dollars4", dollars4Sym, NULL, U_PARSE_ERROR, 0, 0.0, U_PARSE_ERROR, 0, 0.0, "" }, + + { NULL, NULL, NULL, NULL, 0, 0, 0.0, 0, 0, 0.0, NULL } +}; + +static void TestParseCurrency() +{ + const ParseCurrencyItem * itemPtr; + for (itemPtr = parseCurrencyItems; itemPtr->locale != NULL; ++itemPtr) { + UNumberFormat* unum; + UErrorCode status; + double parseVal; + int32_t parsePos; + UChar parseCurr[4]; + char parseCurrB[4]; + + status = U_ZERO_ERROR; + unum = unum_open(UNUM_CURRENCY, NULL, 0, itemPtr->locale, NULL, &status); + if (U_SUCCESS(status)) { + status = U_ZERO_ERROR; + parsePos = 0; + parseVal = unum_parseDouble(unum, itemPtr->currStr, -1, &parsePos, &status); + if (status != itemPtr->parsDoubExpectErr || parsePos != itemPtr->parsDoubExpectPos || parseVal != itemPtr->parsDoubExpectVal) { + log_err("UNUM_CURRENCY parseDouble %s/%s, expect %s pos %d val %.1f, get %s pos %d val %.1f\n", + itemPtr->locale, itemPtr->descrip, + u_errorName(itemPtr->parsDoubExpectErr), itemPtr->parsDoubExpectPos, itemPtr->parsDoubExpectVal, + u_errorName(status), parsePos, parseVal ); + } + status = U_ZERO_ERROR; + parsePos = 0; + parseCurr[0] = 0; + parseVal = unum_parseDoubleCurrency(unum, itemPtr->currStr, -1, &parsePos, parseCurr, &status); + u_austrncpy(parseCurrB, parseCurr, 4); + if (status != itemPtr->parsCurrExpectErr || parsePos != itemPtr->parsCurrExpectPos || parseVal != itemPtr->parsCurrExpectVal || + strncmp(parseCurrB, itemPtr->parsCurrExpectCurr, 4) != 0) { + log_err("UNUM_CURRENCY parseDoubleCurrency %s/%s, expect %s pos %d val %.1f cur %s, get %s pos %d val %.1f cur %s\n", + itemPtr->locale, itemPtr->descrip, + u_errorName(itemPtr->parsCurrExpectErr), itemPtr->parsCurrExpectPos, itemPtr->parsCurrExpectVal, itemPtr->parsCurrExpectCurr, + u_errorName(status), parsePos, parseVal, parseCurrB ); + } + unum_close(unum); + } else { + log_data_err("unexpected error in unum_open UNUM_CURRENCY for locale %s: '%s'\n", itemPtr->locale, u_errorName(status)); + } + +#if 0 + /* Hmm, for UNUM_CURRENCY_PLURAL, currently unum_open always sets U_UNSUPPORTED_ERROR, save this test until it is supported */ + if (itemPtr->plurStr != NULL) { + status = U_ZERO_ERROR; + unum = unum_open(UNUM_CURRENCY_PLURAL, NULL, 0, itemPtr->locale, NULL, &status); + if (U_SUCCESS(status)) { + status = U_ZERO_ERROR; + parsePos = 0; + parseVal = unum_parseDouble(unum, itemPtr->plurStr, -1, &parsePos, &status); + if (status != itemPtr->parsDoubExpectErr || parseVal != itemPtr->parsDoubExpectVal) { + log_err("UNUM_CURRENCY parseDouble %s/%s, expect %s val %.1f, get %s val %.1f\n", + itemPtr->locale, itemPtr->descrip, + u_errorName(itemPtr->parsDoubExpectErr), itemPtr->parsDoubExpectVal, + u_errorName(status), parseVal ); + } + status = U_ZERO_ERROR; + parsePos = 0; + parseCurr[0] = 0; + parseVal = unum_parseDoubleCurrency(unum, itemPtr->plurStr, -1, &parsePos, parseCurr, &status); + u_austrncpy(parseCurrB, parseCurr, 4); + if (status != itemPtr->parsCurrExpectErr || parseVal != itemPtr->parsCurrExpectVal || + strncmp(parseCurrB, itemPtr->parsCurrExpectCurr, 4) != 0) { + log_err("UNUM_CURRENCY parseDoubleCurrency %s/%s, expect %s val %.1f cur %s, get %s val %.1f cur %s\n", + itemPtr->locale, itemPtr->descrip, + u_errorName(itemPtr->parsCurrExpectErr), itemPtr->parsCurrExpectVal, itemPtr->parsCurrExpectCurr, + u_errorName(status), parseVal, parseCurrB ); + } + unum_close(unum); + } else { + log_data_err("unexpected error in unum_open UNUM_CURRENCY_PLURAL for locale %s: '%s'\n", itemPtr->locale, u_errorName(status)); + } + } +#endif + } +} + typedef struct { const char * testname; const char * locale; diff --git a/icu4c/source/test/intltest/numfmtst.cpp b/icu4c/source/test/intltest/numfmtst.cpp index 598ae7aa22b..4dd664ca6f8 100644 --- a/icu4c/source/test/intltest/numfmtst.cpp +++ b/icu4c/source/test/intltest/numfmtst.cpp @@ -5964,10 +5964,11 @@ NumberFormatTest::TestParseCurrencyInUCurr() { UnicodeString formatted = ctou(DATA[i]); UErrorCode status = U_ZERO_ERROR; NumberFormat* numFmt = NumberFormat::createInstance(locale, UNUM_CURRENCY, status); - Formattable parseResult; if (numFmt != NULL && U_SUCCESS(status)) { - numFmt->parse(formatted, parseResult, status); - if (U_FAILURE(status) || + Formattable parseResult; + ParsePosition parsePos; + numFmt->parseCurrency(formatted, parseResult, parsePos); + if (parsePos.getIndex() == 0 || (parseResult.getType() == Formattable::kDouble && parseResult.getDouble() != 1.0)) { errln("wrong parsing, " + formatted); @@ -5985,10 +5986,11 @@ NumberFormatTest::TestParseCurrencyInUCurr() { UnicodeString formatted = ctou(WRONG_DATA[i]); UErrorCode status = U_ZERO_ERROR; NumberFormat* numFmt = NumberFormat::createInstance(locale, UNUM_CURRENCY, status); - Formattable parseResult; if (numFmt != NULL && U_SUCCESS(status)) { - numFmt->parse(formatted, parseResult, status); - if (!U_FAILURE(status) || + Formattable parseResult; + ParsePosition parsePos; + numFmt->parseCurrency(formatted, parseResult, parsePos); + if (parsePos.getIndex() > 0 || (parseResult.getType() == Formattable::kDouble && parseResult.getDouble() == 1.0)) { errln("parsed but should not be: " + formatted);