X-Git-Url: https://git.saurik.com/apple/icu.git/blobdiff_plain/4388f060552cc537e71e957d32f35e9d75a61233..249c4c5ea9376c24572daf9c2effa7484a282f14:/icuSources/test/intltest/numfmtst.cpp diff --git a/icuSources/test/intltest/numfmtst.cpp b/icuSources/test/intltest/numfmtst.cpp index 87730659..86c25e6b 100644 --- a/icuSources/test/intltest/numfmtst.cpp +++ b/icuSources/test/intltest/numfmtst.cpp @@ -1,6 +1,8 @@ +// © 2016 and later: Unicode, Inc. and others. +// License & terms of use: http://www.unicode.org/copyright.html /******************************************************************** * COPYRIGHT: - * Copyright (c) 1997-2012, International Business Machines Corporation and + * Copyright (c) 1997-2016, International Business Machines Corporation and * others. All Rights Reserved. ********************************************************************/ /* Modification History: @@ -13,6 +15,7 @@ #if !UCONFIG_NO_FORMATTING #include "numfmtst.h" +#include "unicode/currpinf.h" #include "unicode/dcfmtsym.h" #include "unicode/decimfmt.h" #include "unicode/localpointer.h" @@ -20,17 +23,49 @@ #include "unicode/ustring.h" #include "unicode/measfmt.h" #include "unicode/curramt.h" -#include "digitlst.h" +#include "unicode/strenum.h" #include "textfile.h" #include "tokiter.h" #include "charstr.h" +#include "cstr.h" #include "putilimp.h" #include "winnmtst.h" +#include #include #include #include +#include "cmemory.h" #include "cstring.h" #include "unicode/numsys.h" +#include "fmtableimp.h" +#include "numberformattesttuple.h" +#include "unicode/msgfmt.h" +#include "number_decimalquantity.h" +#include "unicode/numberformatter.h" + +#if (U_PLATFORM == U_PF_AIX) || (U_PLATFORM == U_PF_OS390) +// These should not be macros. If they are, +// replace them with std::isnan and std::isinf +#if defined(isnan) +#undef isnan +namespace std { + bool isnan(double x) { + return _isnan(x); + } +} +#endif +#if defined(isinf) +#undef isinf +namespace std { + bool isinf(double x) { + return _isinf(x); + } +} +#endif +#endif + +using icu::number::impl::DecimalQuantity; +using namespace icu::number; //#define NUMFMTST_CACHE_DEBUG 1 #include "stdio.h" /* for sprintf */ @@ -38,88 +73,149 @@ //#define NUMFMTST_DEBUG 1 -#define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof(array[0])) - static const UChar EUR[] = {69,85,82,0}; // "EUR" static const UChar ISO_CURRENCY_USD[] = {0x55, 0x53, 0x44, 0}; // "USD" + // ***************************************************************************** // class NumberFormatTest // ***************************************************************************** -#define CASE(id,test) case id: name = #test; if (exec) { logln(#test "---"); logln((UnicodeString)""); test(); } break - #define CHECK(status,str) if (U_FAILURE(status)) { errcheckln(status, UnicodeString("FAIL: ") + str + " - " + u_errorName(status)); return; } #define CHECK_DATA(status,str) if (U_FAILURE(status)) { dataerrln(UnicodeString("FAIL: ") + str + " - " + u_errorName(status)); return; } void NumberFormatTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ ) { - // if (exec) logln((UnicodeString)"TestSuite DateFormatTest"); - switch (index) { - CASE(0,TestCurrencySign); - CASE(1,TestCurrency); - CASE(2,TestParse); - CASE(3,TestRounding487); - CASE(4,TestQuotes); - CASE(5,TestExponential); - CASE(6,TestPatterns); - - // Upgrade to alphaWorks - liu 5/99 - CASE(7,TestExponent); - CASE(8,TestScientific); - CASE(9,TestPad); - CASE(10,TestPatterns2); - CASE(11,TestSecondaryGrouping); - CASE(12,TestSurrogateSupport); - CASE(13,TestAPI); - - CASE(14,TestCurrencyObject); - CASE(15,TestCurrencyPatterns); - //CASE(16,TestDigitList); - CASE(16,TestWhiteSpaceParsing); - CASE(17,TestComplexCurrency); // This test removed because CLDR no longer uses choice formats in currency symbols. - 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,TestNumberingSystems); - CASE(38,TestSpaceParsing); - CASE(39,TestMultiCurrencySign); - CASE(40,TestCurrencyFormatForMixParsing); - CASE(41,TestDecimalFormatCurrencyParse); - CASE(42,TestCurrencyIsoPluralFormat); - CASE(43,TestCurrencyParsing); - CASE(44,TestParseCurrencyInUCurr); - CASE(45,TestFormatAttributes); - CASE(46,TestFieldPositionIterator); - CASE(47,TestDecimal); - CASE(48,TestCurrencyFractionDigits); - CASE(49,TestExponentParse); - CASE(50,TestExplicitParents); - CASE(51,TestLenientParse); - CASE(52,TestAvailableNumberingSystems); - CASE(53,TestRoundingPattern); - CASE(54,Test9087); - default: name = ""; break; - } + TESTCASE_AUTO_BEGIN; + TESTCASE_AUTO(TestCurrencySign); + TESTCASE_AUTO(TestCurrency); + TESTCASE_AUTO(TestParse); + TESTCASE_AUTO(TestRounding487); + TESTCASE_AUTO(TestQuotes); + TESTCASE_AUTO(TestExponential); + TESTCASE_AUTO(TestPatterns); + + // Upgrade to alphaWorks - liu 5/99 + TESTCASE_AUTO(TestExponent); + TESTCASE_AUTO(TestScientific); + TESTCASE_AUTO(TestPad); + TESTCASE_AUTO(TestPatterns2); + TESTCASE_AUTO(TestSecondaryGrouping); + TESTCASE_AUTO(TestSurrogateSupport); + TESTCASE_AUTO(TestAPI); + + TESTCASE_AUTO(TestCurrencyObject); + TESTCASE_AUTO(TestCurrencyPatterns); + //TESTCASE_AUTO(TestDigitList); + TESTCASE_AUTO(TestWhiteSpaceParsing); + TESTCASE_AUTO(TestComplexCurrency); // This test removed because CLDR no longer uses choice formats in currency symbols. + TESTCASE_AUTO(TestRegCurrency); + TESTCASE_AUTO(TestSymbolsWithBadLocale); + TESTCASE_AUTO(TestAdoptDecimalFormatSymbols); + + TESTCASE_AUTO(TestScientific2); + TESTCASE_AUTO(TestScientificGrouping); + TESTCASE_AUTO(TestInt64); + + TESTCASE_AUTO(TestPerMill); + TESTCASE_AUTO(TestIllegalPatterns); + TESTCASE_AUTO(TestCases); + + TESTCASE_AUTO(TestCurrencyNames); + TESTCASE_AUTO(TestCurrencyAmount); + TESTCASE_AUTO(TestCurrencyUnit); + TESTCASE_AUTO(TestCoverage); + //TESTCASE_AUTO(TestLocalizedPatternSymbolCoverage); + TESTCASE_AUTO(TestJB3832); + TESTCASE_AUTO(TestHost); + TESTCASE_AUTO(TestHostClone); + TESTCASE_AUTO(TestCurrencyFormat); + TESTCASE_AUTO(TestRounding); + TESTCASE_AUTO(TestNonpositiveMultiplier); + TESTCASE_AUTO(TestNumberingSystems); + TESTCASE_AUTO(TestSpaceParsing); + TESTCASE_AUTO(TestMultiCurrencySign); + TESTCASE_AUTO(TestCurrencyFormatForMixParsing); + //TESTCASE_AUTO(TestMismatchedCurrencyFormatFail); + TESTCASE_AUTO(TestDecimalFormatCurrencyParse); + TESTCASE_AUTO(TestCurrencyIsoPluralFormat); + TESTCASE_AUTO(TestCurrencyParsing); + TESTCASE_AUTO(TestParseCurrencyInUCurr); + TESTCASE_AUTO(TestFormatAttributes); + TESTCASE_AUTO(TestFieldPositionIterator); + TESTCASE_AUTO(TestDecimal); + TESTCASE_AUTO(TestCurrencyFractionDigits); + TESTCASE_AUTO(TestExponentParse); + TESTCASE_AUTO(TestExplicitParents); + TESTCASE_AUTO(TestLenientParse); + TESTCASE_AUTO(TestAvailableNumberingSystems); + TESTCASE_AUTO(TestRoundingPattern); + TESTCASE_AUTO(Test9087); + TESTCASE_AUTO(TestFormatFastpaths); + TESTCASE_AUTO(TestFormattableSize); + TESTCASE_AUTO(TestUFormattable); + TESTCASE_AUTO(TestSignificantDigits); + TESTCASE_AUTO(TestShowZero); + TESTCASE_AUTO(TestCompatibleCurrencies); + TESTCASE_AUTO(TestBug9936); + TESTCASE_AUTO(TestParseNegativeWithFaLocale); + TESTCASE_AUTO(TestParseNegativeWithAlternateMinusSign); + TESTCASE_AUTO(TestCustomCurrencySignAndSeparator); + TESTCASE_AUTO(TestParseSignsAndMarks); + TESTCASE_AUTO(Test10419RoundingWith0FractionDigits); + TESTCASE_AUTO(Test10468ApplyPattern); + TESTCASE_AUTO(TestRoundingScientific10542); + TESTCASE_AUTO(TestZeroScientific10547); + TESTCASE_AUTO(TestAccountingCurrency); + TESTCASE_AUTO(TestEquality); + TESTCASE_AUTO(TestCurrencyUsage); + TESTCASE_AUTO(TestDoubleLimit11439); + TESTCASE_AUTO(TestGetAffixes); + TESTCASE_AUTO(TestToPatternScientific11648); + TESTCASE_AUTO(TestBenchmark); + TESTCASE_AUTO(TestCtorApplyPatternDifference); + TESTCASE_AUTO(TestFractionalDigitsForCurrency); + TESTCASE_AUTO(TestFormatCurrencyPlural); + TESTCASE_AUTO(Test11868); + TESTCASE_AUTO(Test11739_ParseLongCurrency); + //TESTCASE_AUTO(Test13035_MultiCodePointPaddingInPattern); + TESTCASE_AUTO(Test13737_ParseScientificStrict); + TESTCASE_AUTO(Test10727_RoundingZero); + TESTCASE_AUTO(Test11376_getAndSetPositivePrefix); + TESTCASE_AUTO(Test11475_signRecognition); + TESTCASE_AUTO(Test11640_getAffixes); + TESTCASE_AUTO(Test11649_toPatternWithMultiCurrency); + TESTCASE_AUTO(Test13327_numberingSystemBufferOverflow); + TESTCASE_AUTO(Test13391_chakmaParsing); + TESTCASE_AUTO(Test11735_ExceptionIssue); + TESTCASE_AUTO(Test11035_FormatCurrencyAmount); + TESTCASE_AUTO(Test11318_DoubleConversion); + TESTCASE_AUTO(TestParsePercentRegression); + TESTCASE_AUTO(TestMultiplierWithScale); + TESTCASE_AUTO(TestFastFormatInt32); + TESTCASE_AUTO(Test11646_Equality); + TESTCASE_AUTO(TestParseNaN); + TESTCASE_AUTO(Test11897_LocalizedPatternSeparator); + TESTCASE_AUTO(Test13055_PercentageRounding); + TESTCASE_AUTO(Test11839); + TESTCASE_AUTO(Test10354); + TESTCASE_AUTO(Test11645_ApplyPatternEquality); + TESTCASE_AUTO(Test12567); + TESTCASE_AUTO(Test11626_CustomizeCurrencyPluralInfo); + TESTCASE_AUTO(Test13056_GroupingSize); + TESTCASE_AUTO(Test11025_CurrencyPadding); + TESTCASE_AUTO(Test11648_ExpDecFormatMalPattern); + //TESTCASE_AUTO(Test11649_DecFmtCurrencies); + TESTCASE_AUTO(Test13148_ParseGroupingSeparators); + TESTCASE_AUTO(Test12753_PatternDecimalPoint); + TESTCASE_AUTO(Test11647_PatternCurrencySymbols); + TESTCASE_AUTO(Test11913_BigDecimal); + TESTCASE_AUTO(Test11020_RoundingInScientificNotation); + TESTCASE_AUTO(Test11640_TripleCurrencySymbol); + TESTCASE_AUTO(Test13763_FieldPositionIteratorOffset); + TESTCASE_AUTO(Test13777_ParseLongNameNonCurrencyMode); + TESTCASE_AUTO(Test13804_EmptyStringsWhenParsing); + TESTCASE_AUTO_END; } // ------------------------------------- @@ -136,10 +232,10 @@ NumberFormatTest::TestAPI(void) } if(test != NULL) { test->setMinimumIntegerDigits(10); - test->setMaximumIntegerDigits(2); + test->setMaximumIntegerDigits(1); test->setMinimumFractionDigits(10); - test->setMaximumFractionDigits(2); + test->setMaximumFractionDigits(1); UnicodeString result; FieldPosition pos; @@ -154,9 +250,14 @@ NumberFormatTest::TestAPI(void) result.remove(); int64_t ll = 12; test->format(ll, result); - if (result != "12.00"){ - errln("format int64_t error"); - } + assertEquals("format int64_t error", u"2.0", result); + + test->setMinimumIntegerDigits(4); + test->setMinimumFractionDigits(4); + + result.remove(); + test->format(ll, result); + assertEquals("format int64_t error", u"0,012.0000", result); ParsePosition ppos; LocalPointer currAmt(test->parseCurrency("",ppos)); @@ -169,9 +270,9 @@ NumberFormatTest::TestAPI(void) } } -class StubNumberForamt :public NumberFormat{ +class StubNumberFormat :public NumberFormat{ public: - StubNumberForamt(){}; + StubNumberFormat(){}; virtual UnicodeString& format(double ,UnicodeString& appendTo,FieldPosition& ) const { return appendTo; } @@ -199,7 +300,7 @@ public: void NumberFormatTest::TestCoverage(void){ - StubNumberForamt stub; + StubNumberFormat stub; UnicodeString agent("agent"); FieldPosition pos; int64_t num = 4; @@ -208,6 +309,58 @@ NumberFormatTest::TestCoverage(void){ }; } +void NumberFormatTest::TestLocalizedPatternSymbolCoverage() { + IcuTestErrorCode errorCode(*this, "TestLocalizedPatternSymbolCoverage"); + // Ticket #12961: DecimalFormat::toLocalizedPattern() is not working as designed. + DecimalFormatSymbols dfs(errorCode); + dfs.setSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol, u'⁖'); + dfs.setSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol, u'⁘'); + dfs.setSymbol(DecimalFormatSymbols::kPatternSeparatorSymbol, u'⁙'); + dfs.setSymbol(DecimalFormatSymbols::kDigitSymbol, u'▰'); + dfs.setSymbol(DecimalFormatSymbols::kZeroDigitSymbol, u'໐'); + dfs.setSymbol(DecimalFormatSymbols::kSignificantDigitSymbol, u'⁕'); + dfs.setSymbol(DecimalFormatSymbols::kPlusSignSymbol, u'†'); + dfs.setSymbol(DecimalFormatSymbols::kMinusSignSymbol, u'‡'); + dfs.setSymbol(DecimalFormatSymbols::kPercentSymbol, u'⁜'); + dfs.setSymbol(DecimalFormatSymbols::kPerMillSymbol, u'‱'); + dfs.setSymbol(DecimalFormatSymbols::kExponentialSymbol, u"⁑⁑"); // tests multi-char sequence + dfs.setSymbol(DecimalFormatSymbols::kPadEscapeSymbol, u'⁂'); + + { + UnicodeString standardPattern(u"#,##0.05+%;#,##0.05-%"); + UnicodeString localizedPattern(u"▰⁖▰▰໐⁘໐໕†⁜⁙▰⁖▰▰໐⁘໐໕‡⁜"); + + DecimalFormat df1("#", new DecimalFormatSymbols(dfs), errorCode); + df1.applyPattern(standardPattern, errorCode); + DecimalFormat df2("#", new DecimalFormatSymbols(dfs), errorCode); + df2.applyLocalizedPattern(localizedPattern, errorCode); + assertTrue("DecimalFormat instances should be equal", df1 == df2); + UnicodeString p2; + assertEquals("toPattern should match on localizedPattern instance", + standardPattern, df2.toPattern(p2)); + UnicodeString lp1; + assertEquals("toLocalizedPattern should match on standardPattern instance", + localizedPattern, df1.toLocalizedPattern(lp1)); + } + + { + UnicodeString standardPattern(u"* @@@E0‰"); + UnicodeString localizedPattern(u"⁂ ⁕⁕⁕⁑⁑໐‱"); + + DecimalFormat df1("#", new DecimalFormatSymbols(dfs), errorCode); + df1.applyPattern(standardPattern, errorCode); + DecimalFormat df2("#", new DecimalFormatSymbols(dfs), errorCode); + df2.applyLocalizedPattern(localizedPattern, errorCode); + assertTrue("DecimalFormat instances should be equal", df1 == df2); + UnicodeString p2; + assertEquals("toPattern should match on localizedPattern instance", + standardPattern, df2.toPattern(p2)); + UnicodeString lp1; + assertEquals("toLocalizedPattern should match on standardPattern instance", + localizedPattern, df1.toLocalizedPattern(lp1)); + } +} + // Test various patterns void NumberFormatTest::TestPatterns(void) @@ -217,8 +370,8 @@ NumberFormatTest::TestPatterns(void) if (U_FAILURE(status)) { errcheckln(status, "FAIL: Could not construct DecimalFormatSymbols - %s", u_errorName(status)); return; } const char* pat[] = { "#.#", "#.", ".#", "#" }; - int32_t pat_length = (int32_t)(sizeof(pat) / sizeof(pat[0])); - const char* newpat[] = { "#0.#", "#0.", "#.0", "#" }; + int32_t pat_length = UPRV_LENGTHOF(pat); + const char* newpat[] = { "#0.#", "#0.", "#.0", "#" }; // use ICU 61 behavior const char* num[] = { "0", "0.", ".0", "0" }; for (int32_t i=0; i 300 double val[] = { 0.01234, 123456789, 1.23e300, -3.141592653e-271 }; - int32_t val_length = (int32_t)(sizeof(val) / sizeof(val[0])); + int32_t val_length = UPRV_LENGTHOF(val); const char* valFormat[] = { // 0.####E0 @@ -307,7 +460,7 @@ NumberFormatTest::TestExponential(void) }; #elif DBL_MAX_10_EXP > 70 double val[] = { 0.01234, 123456789, 1.23e70, -3.141592653e-71 }; - int32_t val_length = sizeof(val) / sizeof(val[0]); + int32_t val_length = UPRV_LENGTHOF(val); char* valFormat[] = { // 0.####E0 @@ -336,7 +489,7 @@ NumberFormatTest::TestExponential(void) #endif int32_t lval[] = { 0, -1, 1, 123456789 }; - int32_t lval_length = (int32_t)(sizeof(lval) / sizeof(lval[0])); + int32_t lval_length = UPRV_LENGTHOF(lval); const char* lvalFormat[] = { // 0.####E0 @@ -392,7 +545,7 @@ NumberFormatTest::TestExponential(void) #endif } else { - errln((UnicodeString)"FAIL: Non-numeric Formattable returned"); + errln(UnicodeString("FAIL: Non-numeric Formattable returned: ") + pattern + " " + s); continue; } if (pos.getIndex() == s.length()) @@ -403,7 +556,8 @@ NumberFormatTest::TestExponential(void) (uprv_fabs(a - valParse[v+ival]) / a > (2*DBL_EPSILON))) || (!useEpsilon && a != valParse[v+ival])) { - errln((UnicodeString)"FAIL: Expected " + valParse[v+ival]); + errln((UnicodeString)"FAIL: Expected " + valParse[v+ival] + " but got " + a + + " on input " + s); } } else { @@ -430,7 +584,7 @@ NumberFormatTest::TestExponential(void) { logln((UnicodeString)" -parse-> " + a); if (a != lvalParse[v+ilval]) - errln((UnicodeString)"FAIL: Expected " + lvalParse[v+ilval]); + errln((UnicodeString)"FAIL: Expected " + lvalParse[v+ilval] + " but got " + a); } else errln((UnicodeString)"FAIL: Partial parse (" + pos.getIndex() + " chars) -> " + a); @@ -466,7 +620,7 @@ NumberFormatTest::TestScientificGrouping() { // jb 2552 UErrorCode status = U_ZERO_ERROR; DecimalFormat fmt("##0.00E0",status); - if (U_SUCCESS(status)) { + if (assertSuccess("", status, true, __FILE__, __LINE__)) { expect(fmt, .01234, "12.3E-3"); expect(fmt, .1234, "123E-3"); expect(fmt, 1.234, "1.23E0"); @@ -501,6 +655,10 @@ void NumberFormatTest::TestInt64() { UErrorCode status = U_ZERO_ERROR; DecimalFormat fmt("#.#E0",status); + if (U_FAILURE(status)) { + dataerrln("Error creating DecimalFormat - %s", u_errorName(status)); + return; + } fmt.setMaximumFractionDigits(20); if (U_SUCCESS(status)) { expect(fmt, (Formattable)(int64_t)0, "0E0"); @@ -693,15 +851,15 @@ NumberFormatTest::escape(UnicodeString& s) // ------------------------------------- static const char* testCases[][2]= { /* locale ID */ /* expected */ - {"ca_ES_PREEURO", "1.150\\u00A0\\u20A7" }, + {"ca_ES_PREEURO", "\\u20A7\\u00A01.150" }, {"de_LU_PREEURO", "1,150\\u00A0F" }, {"el_GR_PREEURO", "1.150,50\\u00A0\\u0394\\u03C1\\u03C7" }, {"en_BE_PREEURO", "1.150,50\\u00A0BEF" }, {"es_ES_PREEURO", "1.150\\u00A0\\u20A7" }, - {"eu_ES_PREEURO", "1.150\\u00A0\\u20A7" }, + {"eu_ES_PREEURO", "\\u20A7\\u00A01.150" }, {"gl_ES_PREEURO", "1.150\\u00A0\\u20A7" }, {"it_IT_PREEURO", "ITL\\u00A01.150" }, - {"pt_PT_PREEURO", "1,150$50\\u00A0Esc."}, + {"pt_PT_PREEURO", "1,150$50\\u00A0\\u200B"}, // per cldrbug 7670 {"en_US@currency=JPY", "\\u00A51,150"}, {"en_US@currency=jpy", "\\u00A51,150"}, {"en-US-u-cu-jpy", "\\u00A51,150"} @@ -722,16 +880,17 @@ NumberFormatTest::TestCurrency(void) UnicodeString s; currencyFmt->format(1.50, s); logln((UnicodeString)"Un pauvre ici a..........." + s); if (!(s==CharsToUnicodeString("1,50\\u00A0$"))) - errln((UnicodeString)"FAIL: Expected 1,50$"); + errln((UnicodeString)"FAIL: Expected 1,50$ but got " + s); delete currencyFmt; s.truncate(0); char loc[256]={0}; int len = uloc_canonicalize("de_DE_PREEURO", loc, 256, &status); + (void)len; // Suppress unused variable warning. currencyFmt = NumberFormat::createCurrencyInstance(Locale(loc),status); currencyFmt->format(1.50, s); logln((UnicodeString)"Un pauvre en Allemagne a.." + s); - if (!(s==CharsToUnicodeString("1,50\\u00A0DEM"))) - errln((UnicodeString)"FAIL: Expected 1,50DEM"); + if (!(s==CharsToUnicodeString("1,50\\u00A0DM"))) + errln((UnicodeString)"FAIL: Expected 1,50DM but got " + s); delete currencyFmt; s.truncate(0); len = uloc_canonicalize("fr_FR_PREEURO", loc, 256, &status); @@ -744,7 +903,7 @@ NumberFormatTest::TestCurrency(void) if (U_FAILURE(status)) errln((UnicodeString)"FAIL: Status " + (int32_t)status); - for(int i=0; i < (int)(sizeof(testCases)/sizeof(testCases[i])); i++){ + for(int i=0; i < UPRV_LENGTHOF(testCases); i++){ status = U_ZERO_ERROR; const char *localeID = testCases[i][0]; UnicodeString expected(testCases[i][1], -1, US_INV); @@ -797,7 +956,7 @@ void NumberFormatTest::TestCurrencyObject() { 1234.56, CharsToUnicodeString("\\u00A51,235")); // Yen expectCurrency(*fmt, Locale("fr", "CH", ""), - 1234.56, "CHF1,234.55"); // 0.05 rounding + 1234.56, "CHF1,234.56"); // no more 0.05 rounding here, see cldrbug 5548 // use ICU 61 behavior expectCurrency(*fmt, Locale::getUS(), 1234.56, "$1,234.56"); @@ -814,10 +973,10 @@ void NumberFormatTest::TestCurrencyObject() { expectCurrency(*fmt, null, 1234.56, CharsToUnicodeString("1 234,56 \\u20AC")); expectCurrency(*fmt, Locale::getJapan(), - 1234.56, CharsToUnicodeString("1 235 \\u00A5JP")); // Yen + 1234.56, CharsToUnicodeString("1 235 JPY")); // Yen expectCurrency(*fmt, Locale("fr", "CH", ""), - 1234.56, "1 234,55 CHF"); // 0.05 rounding + 1234.56, "1 234,56 CHF"); // no more 0.05 rounding here, see cldrbug 5548 expectCurrency(*fmt, Locale::getUS(), 1234.56, "1 234,56 $US"); @@ -864,7 +1023,7 @@ static const char *lenientAffixTestCases[] = { static const char *lenientMinusTestCases[] = { "-5", "\\u22125", - "\\u20105" + "\\u27965" }; static const char *lenientCurrencyTestCases[] = { @@ -878,16 +1037,17 @@ static const char *lenientCurrencyTestCases[] = { "1000.00" }; +// changed from () to - per cldrbug 5674 static const char *lenientNegativeCurrencyTestCases[] = { - "($1,000)", - "($ 1,000)", - "($1000)", - "($ 1000)", - "($1 000.00)", - "($ 1 000.00)", - "( $ 1,000.00 )", - "($ 1\\u00A0000.00)", - "(1000.00)" + "-$1,000", + "-$ 1,000", + "-$1000", + "-$ 1000", + "-$1 000.00", + "-$ 1 000.00", + "- $ 1,000.00 ", + "-$ 1\\u00A0000.00", + "-1000.00" }; static const char *lenientPercentTestCases[] = { @@ -917,8 +1077,6 @@ static const char *strictFailureTestCases[] = { "1,000,.0" }; -#define ARRAY_SIZE(array) ((int32_t) (sizeof (array) / sizeof(array[0]))) - /** * Test lenient parsing. */ @@ -933,7 +1091,7 @@ NumberFormatTest::TestLenientParse(void) dataerrln("Unable to create DecimalFormat (#,##0) - %s", u_errorName(status)); } else { format->setLenient(TRUE); - for (int32_t t = 0; t < ARRAY_SIZE (lenientAffixTestCases); t += 1) { + for (int32_t t = 0; t < UPRV_LENGTHOF (lenientAffixTestCases); t += 1) { UnicodeString testCase = ctou(lenientAffixTestCases[t]); format->parse(testCase, n, status); @@ -941,7 +1099,8 @@ NumberFormatTest::TestLenientParse(void) if (U_FAILURE(status) || n.getType() != Formattable::kLong || n.getLong() != 1) { - errln((UnicodeString)"Lenient parse failed for \"" + (UnicodeString) lenientAffixTestCases[t] + (UnicodeString) "\""); + dataerrln((UnicodeString)"Lenient parse failed for \"" + (UnicodeString) lenientAffixTestCases[t] + + (UnicodeString) "\"; error code = " + u_errorName(status)); status = U_ZERO_ERROR; } } @@ -950,54 +1109,56 @@ NumberFormatTest::TestLenientParse(void) Locale en_US("en_US"); Locale sv_SE("sv_SE"); - + NumberFormat *mFormat = NumberFormat::createInstance(sv_SE, UNUM_DECIMAL, status); - + if (mFormat == NULL || U_FAILURE(status)) { dataerrln("Unable to create NumberFormat (sv_SE, UNUM_DECIMAL) - %s", u_errorName(status)); } else { mFormat->setLenient(TRUE); - for (int32_t t = 0; t < ARRAY_SIZE(lenientMinusTestCases); t += 1) { + for (int32_t t = 0; t < UPRV_LENGTHOF(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) "\""); + errln((UnicodeString)"Lenient parse failed for \"" + (UnicodeString) lenientMinusTestCases[t] + + (UnicodeString) "\"; error code = " + u_errorName(status)); status = U_ZERO_ERROR; } } delete mFormat; } - + mFormat = NumberFormat::createInstance(en_US, UNUM_DECIMAL, status); - + if (mFormat == NULL || U_FAILURE(status)) { dataerrln("Unable to create NumberFormat (en_US, UNUM_DECIMAL) - %s", u_errorName(status)); } else { mFormat->setLenient(TRUE); - for (int32_t t = 0; t < ARRAY_SIZE(lenientMinusTestCases); t += 1) { + for (int32_t t = 0; t < UPRV_LENGTHOF(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) "\""); + errln((UnicodeString)"Lenient parse failed for \"" + (UnicodeString) lenientMinusTestCases[t] + + (UnicodeString) "\"; error code = " + u_errorName(status)); status = U_ZERO_ERROR; } } delete mFormat; } - + NumberFormat *cFormat = NumberFormat::createInstance(en_US, UNUM_CURRENCY, status); if (cFormat == NULL || U_FAILURE(status)) { dataerrln("Unable to create NumberFormat (en_US, UNUM_CURRENCY) - %s", u_errorName(status)); } else { cFormat->setLenient(TRUE); - for (int32_t t = 0; t < ARRAY_SIZE (lenientCurrencyTestCases); t += 1) { + for (int32_t t = 0; t < UPRV_LENGTHOF (lenientCurrencyTestCases); t += 1) { UnicodeString testCase = ctou(lenientCurrencyTestCases[t]); cFormat->parse(testCase, n, status); @@ -1005,12 +1166,13 @@ NumberFormatTest::TestLenientParse(void) if (U_FAILURE(status) ||n.getType() != Formattable::kLong || n.getLong() != 1000) { - errln((UnicodeString)"Lenient parse failed for \"" + (UnicodeString) lenientCurrencyTestCases[t] + (UnicodeString) "\""); + errln((UnicodeString)"Lenient parse failed for \"" + (UnicodeString) lenientCurrencyTestCases[t] + + (UnicodeString) "\"; error code = " + u_errorName(status)); status = U_ZERO_ERROR; } } - for (int32_t t = 0; t < ARRAY_SIZE (lenientNegativeCurrencyTestCases); t += 1) { + for (int32_t t = 0; t < UPRV_LENGTHOF (lenientNegativeCurrencyTestCases); t += 1) { UnicodeString testCase = ctou(lenientNegativeCurrencyTestCases[t]); cFormat->parse(testCase, n, status); @@ -1018,7 +1180,8 @@ NumberFormatTest::TestLenientParse(void) if (U_FAILURE(status) ||n.getType() != Formattable::kLong || n.getLong() != -1000) { - errln((UnicodeString)"Lenient parse failed for \"" + (UnicodeString) lenientNegativeCurrencyTestCases[t] + (UnicodeString) "\""); + errln((UnicodeString)"Lenient parse failed for \"" + (UnicodeString) lenientNegativeCurrencyTestCases[t] + + (UnicodeString) "\"; error code = " + u_errorName(status)); status = U_ZERO_ERROR; } } @@ -1032,7 +1195,7 @@ NumberFormatTest::TestLenientParse(void) dataerrln("Unable to create NumberFormat::createPercentInstance (en_US) - %s", u_errorName(status)); } else { pFormat->setLenient(TRUE); - for (int32_t t = 0; t < ARRAY_SIZE (lenientPercentTestCases); t += 1) { + for (int32_t t = 0; t < UPRV_LENGTHOF (lenientPercentTestCases); t += 1) { UnicodeString testCase = ctou(lenientPercentTestCases[t]); pFormat->parse(testCase, n, status); @@ -1040,12 +1203,14 @@ NumberFormatTest::TestLenientParse(void) if (U_FAILURE(status) ||n.getType() != Formattable::kDouble || n.getDouble() != 0.25) { - errln((UnicodeString)"Lenient parse failed for \"" + (UnicodeString) lenientPercentTestCases[t] + (UnicodeString) "\""); + errln((UnicodeString)"Lenient parse failed for \"" + (UnicodeString) lenientPercentTestCases[t] + + (UnicodeString) "\"; error code = " + u_errorName(status) + + "; got: " + n.getDouble(status)); status = U_ZERO_ERROR; } } - for (int32_t t = 0; t < ARRAY_SIZE (lenientNegativePercentTestCases); t += 1) { + for (int32_t t = 0; t < UPRV_LENGTHOF (lenientNegativePercentTestCases); t += 1) { UnicodeString testCase = ctou(lenientNegativePercentTestCases[t]); pFormat->parse(testCase, n, status); @@ -1053,7 +1218,9 @@ NumberFormatTest::TestLenientParse(void) if (U_FAILURE(status) ||n.getType() != Formattable::kDouble || n.getDouble() != -0.25) { - errln((UnicodeString)"Lenient parse failed for \"" + (UnicodeString) lenientNegativePercentTestCases[t] + (UnicodeString) "\""); + errln((UnicodeString)"Lenient parse failed for \"" + (UnicodeString) lenientNegativePercentTestCases[t] + + (UnicodeString) "\"; error code = " + u_errorName(status) + + "; got: " + n.getDouble(status)); status = U_ZERO_ERROR; } } @@ -1064,19 +1231,20 @@ NumberFormatTest::TestLenientParse(void) // Test cases that should fail with a strict parse and pass with a // lenient parse. NumberFormat *nFormat = NumberFormat::createInstance(en_US, status); - + if (nFormat == NULL || U_FAILURE(status)) { dataerrln("Unable to create NumberFormat (en_US) - %s", u_errorName(status)); - } else { + } else { // first, make sure that they fail with a strict parse - for (int32_t t = 0; t < ARRAY_SIZE(strictFailureTestCases); t += 1) { + for (int32_t t = 0; t < UPRV_LENGTHOF(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) "\""); + errln((UnicodeString)"Strict Parse succeeded for \"" + (UnicodeString) strictFailureTestCases[t] + + (UnicodeString) "\"; error code = " + u_errorName(status)); } status = U_ZERO_ERROR; @@ -1084,7 +1252,7 @@ NumberFormatTest::TestLenientParse(void) // then, make sure that they pass with a lenient parse nFormat->setLenient(TRUE); - for (int32_t t = 0; t < ARRAY_SIZE(strictFailureTestCases); t += 1) { + for (int32_t t = 0; t < UPRV_LENGTHOF(strictFailureTestCases); t += 1) { UnicodeString testCase = ctou(strictFailureTestCases[t]); nFormat->parse(testCase, n, status); @@ -1092,7 +1260,8 @@ NumberFormatTest::TestLenientParse(void) if (U_FAILURE(status) ||n.getType() != Formattable::kLong || n.getLong() != 1000) { - errln((UnicodeString)"Lenient parse failed for \"" + (UnicodeString) strictFailureTestCases[t] + (UnicodeString) "\""); + errln((UnicodeString)"Lenient parse failed for \"" + (UnicodeString) strictFailureTestCases[t] + + (UnicodeString) "\"; error code = " + u_errorName(status)); status = U_ZERO_ERROR; } } @@ -1139,13 +1308,13 @@ void NumberFormatTest::TestSecondaryGrouping(void) { CHECK(status, "DecimalFormat ct"); expect2(f, (int32_t)123456789L, "12,34,56,789"); - expectPat(f, "#,##,###"); + expectPat(f, "#,##,###"); // use ICU 61 behavior f.applyPattern("#,###", status); CHECK(status, "applyPattern"); f.setSecondaryGroupingSize(4); expect2(f, (int32_t)123456789L, "12,3456,789"); - expectPat(f, "#,####,###"); + expectPat(f, "#,####,###"); // use ICU 61 behavior NumberFormat *g = NumberFormat::createInstance(Locale("hi", "IN"), status); CHECK_DATA(status, "createInstance(hi_IN)"); @@ -1197,6 +1366,8 @@ void NumberFormatTest::TestWhiteSpaceParsing(void) { errcheckln(ec, "FAIL: Constructor - %s", u_errorName(ec)); return; } + // From ICU 62, flexible whitespace needs lenient mode + fmt.setLenient(TRUE); int32_t n = 1234; expect(fmt, "a b1234c ", n); expect(fmt, "a b1234c ", n); @@ -1264,10 +1435,10 @@ void NumberFormatTest::TestScientific(void) { // Test pattern round-trip const char* PAT[] = { "#E0", "0.####E0", "00.000E00", "##0.####E000", "0.###E0;[0.###E0]" }; - int32_t PAT_length = (int32_t)(sizeof(PAT) / sizeof(PAT[0])); + int32_t PAT_length = UPRV_LENGTHOF(PAT); int32_t DIGITS[] = { // min int, max int, min frac, max frac - 0, 1, 0, 0, // "#E0" + 0, 1, 0, 0, // "#E0" // expect ICU 61 behavior 1, 1, 0, 4, // "0.####E0" 2, 2, 3, 3, // "00.000E00" 1, 3, 0, 4, // "##0.####E000" @@ -1610,7 +1781,7 @@ void NumberFormatTest::TestPatterns2(void) { fmt.setFormatWidth(16); // 12 34567890123456 - expectPat(fmt, "AA*^#,###,##0.00ZZ"); + expectPat(fmt, "AA*^#,###,##0.00ZZ"); // use ICU 61 behavior } void NumberFormatTest::TestSurrogateSupport(void) { @@ -1803,42 +1974,78 @@ void NumberFormatTest::TestCurrencyNames(void) { const UBool possibleDataError = TRUE; // 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)", + assertEquals("USD.getName(SYMBOL_NAME, en)", UnicodeString("$"), UnicodeString(ucurr_getName(USD, "en", UCURR_SYMBOL_NAME, &isChoiceFormat, &len, &ec)), possibleDataError); - assertEquals("USD.getName(LONG_NAME)", + assertEquals("USD.getName(NARROW_SYMBOL_NAME, en)", + UnicodeString("$"), + UnicodeString(ucurr_getName(USD, "en", + UCURR_NARROW_SYMBOL_NAME, + &isChoiceFormat, &len, &ec)), + possibleDataError); + assertEquals("USD.getName(LONG_NAME, en)", UnicodeString("US Dollar"), UnicodeString(ucurr_getName(USD, "en", UCURR_LONG_NAME, &isChoiceFormat, &len, &ec)), possibleDataError); - assertEquals("CAD.getName(SYMBOL_NAME)", + assertEquals("CAD.getName(SYMBOL_NAME, en)", UnicodeString("CA$"), UnicodeString(ucurr_getName(CAD, "en", UCURR_SYMBOL_NAME, &isChoiceFormat, &len, &ec)), possibleDataError); - assertEquals("CAD.getName(SYMBOL_NAME)", + assertEquals("CAD.getName(NARROW_SYMBOL_NAME, en)", + UnicodeString("$"), + UnicodeString(ucurr_getName(CAD, "en", + UCURR_NARROW_SYMBOL_NAME, + &isChoiceFormat, &len, &ec)), + possibleDataError); + assertEquals("CAD.getName(SYMBOL_NAME, en_CA)", UnicodeString("$"), UnicodeString(ucurr_getName(CAD, "en_CA", UCURR_SYMBOL_NAME, &isChoiceFormat, &len, &ec)), possibleDataError); - assertEquals("USD.getName(SYMBOL_NAME) in en_AU", + assertEquals("USD.getName(SYMBOL_NAME, en_CA)", UnicodeString("US$"), - UnicodeString(ucurr_getName(USD, "en_AU", + UnicodeString(ucurr_getName(USD, "en_CA", + UCURR_SYMBOL_NAME, + &isChoiceFormat, &len, &ec)), + possibleDataError); + assertEquals("USD.getName(NARROW_SYMBOL_NAME, en_CA)", + UnicodeString("$"), + UnicodeString(ucurr_getName(USD, "en_CA", + UCURR_NARROW_SYMBOL_NAME, + &isChoiceFormat, &len, &ec)), + possibleDataError); + assertEquals("USD.getName(SYMBOL_NAME) in en_NZ", + UnicodeString("US$"), + UnicodeString(ucurr_getName(USD, "en_NZ", UCURR_SYMBOL_NAME, &isChoiceFormat, &len, &ec)), possibleDataError); assertEquals("CAD.getName(SYMBOL_NAME)", UnicodeString("CA$"), - UnicodeString(ucurr_getName(CAD, "en_AU", + UnicodeString(ucurr_getName(CAD, "en_NZ", + UCURR_SYMBOL_NAME, + &isChoiceFormat, &len, &ec)), + possibleDataError); + assertEquals("USX.getName(SYMBOL_NAME)", + UnicodeString("USX"), + UnicodeString(ucurr_getName(USX, "en_US", UCURR_SYMBOL_NAME, &isChoiceFormat, &len, &ec)), possibleDataError); + assertEquals("USX.getName(NARROW_SYMBOL_NAME)", + UnicodeString("USX"), + UnicodeString(ucurr_getName(USX, "en_US", + UCURR_NARROW_SYMBOL_NAME, + &isChoiceFormat, &len, &ec)), + possibleDataError); assertEquals("USX.getName(LONG_NAME)", UnicodeString("USX"), UnicodeString(ucurr_getName(USX, "en_US", @@ -1881,12 +2088,17 @@ void NumberFormatTest::TestCurrencyNames(void) { void NumberFormatTest::TestCurrencyUnit(void){ UErrorCode ec = U_ZERO_ERROR; - static const UChar USD[] = {85, 83, 68, 0}; /*USD*/ + static const UChar USD[] = u"USD"; + static const char USD8[] = "USD"; + static const UChar BAD[] = u"???"; + static const UChar BAD2[] = u"??A"; + static const UChar XXX[] = u"XXX"; + static const char XXX8[] = "XXX"; CurrencyUnit cu(USD, ec); assertSuccess("CurrencyUnit", ec); - const UChar * r = cu.getISOCurrency(); // who is the buffer owner ? - assertEquals("getISOCurrency()", USD, r); + assertEquals("getISOCurrency()", USD, cu.getISOCurrency()); + assertEquals("getSubtype()", USD8, cu.getSubtype()); CurrencyUnit cu2(cu); if (!(cu2 == cu)){ @@ -1897,7 +2109,49 @@ void NumberFormatTest::TestCurrencyUnit(void){ if (!(*cu3 == cu)){ errln("CurrencyUnit cloned object should be same"); } + CurrencyUnit bad(BAD, ec); + assertSuccess("CurrencyUnit", ec); + if (cu.getIndex() == bad.getIndex()) { + errln("Indexes of different currencies should differ."); + } + CurrencyUnit bad2(BAD2, ec); + assertSuccess("CurrencyUnit", ec); + if (bad2.getIndex() != bad.getIndex()) { + errln("Indexes of unrecognized currencies should be the same."); + } + if (bad == bad2) { + errln("Different unrecognized currencies should not be equal."); + } + bad = bad2; + if (bad != bad2) { + errln("Currency unit assignment should be the same."); + } delete cu3; + + // Test default constructor + CurrencyUnit def; + assertEquals("Default currency", XXX, def.getISOCurrency()); + assertEquals("Default currency as subtype", XXX8, def.getSubtype()); + + // Test slicing + MeasureUnit sliced1 = cu; + MeasureUnit sliced2 = cu; + assertEquals("Subtype after slicing 1", USD8, sliced1.getSubtype()); + assertEquals("Subtype after slicing 2", USD8, sliced2.getSubtype()); + CurrencyUnit restored1(sliced1, ec); + CurrencyUnit restored2(sliced2, ec); + assertSuccess("Restoring from MeasureUnit", ec); + assertEquals("Subtype after restoring 1", USD8, restored1.getSubtype()); + assertEquals("Subtype after restoring 2", USD8, restored2.getSubtype()); + assertEquals("ISO Code after restoring 1", USD, restored1.getISOCurrency()); + assertEquals("ISO Code after restoring 2", USD, restored2.getISOCurrency()); + + // Test copy constructor failure + LocalPointer meter(MeasureUnit::createMeter(ec)); + assertSuccess("Creating meter", ec); + CurrencyUnit failure(*meter, ec); + assertEquals("Copying from meter should fail", ec, U_ILLEGAL_ARGUMENT_ERROR); + assertEquals("Copying should not give uninitialized ISO code", u"", failure.getISOCurrency()); } void NumberFormatTest::TestCurrencyAmount(void){ @@ -1934,9 +2188,10 @@ void NumberFormatTest::TestSymbolsWithBadLocale(void) { }; // expect U_USING_DEFAULT_WARNING for both unsigned int i; - for (i = 0; i < sizeof(badLocales) / sizeof(char*); i++) { + for (i = 0; i < UPRV_LENGTHOF(badLocales); i++) { const char *localeName = badLocales[i]; Locale locBad(localeName); + TEST_ASSERT_TRUE(!locBad.isBogus()); UErrorCode status = U_ZERO_ERROR; UnicodeString intlCurrencySymbol((UChar)0xa4); @@ -2051,11 +2306,17 @@ void NumberFormatTest::TestPerMill() { DecimalFormat fmt(ctou("###.###\\u2030"), ec); if (!assertSuccess("DecimalFormat ct", ec)) return; assertEquals("0.4857 x ###.###\\u2030", - ctou("485.7\\u2030"), fmt.format(0.4857, str)); + ctou("485.7\\u2030"), fmt.format(0.4857, str), true); DecimalFormatSymbols sym(Locale::getUS(), ec); + if (!assertSuccess("", ec, true, __FILE__, __LINE__)) { + return; + } sym.setSymbol(DecimalFormatSymbols::kPerMillSymbol, ctou("m")); DecimalFormat fmt2("", sym, ec); + if (!assertSuccess("", ec, true, __FILE__, __LINE__)) { + return; + } fmt2.applyLocalizedPattern("###.###m", ec); if (!assertSuccess("setup", ec)) return; str.truncate(0); @@ -2255,6 +2516,12 @@ void NumberFormatTest::TestCases() { if (!tokens.next(tok, ec)) goto error; continue; } + } else if (mfmt == NULL) { + errln("FAIL: " + where + "Loc \"" + mloc + "\": skip case using previous locale, no valid MeasureFormat"); + if (!tokens.next(tok, ec)) goto error; + if (!tokens.next(tok, ec)) goto error; + if (!tokens.next(tok, ec)) goto error; + continue; } // fpc: if (!tokens.next(currAmt, ec)) goto error; @@ -2515,12 +2782,12 @@ void NumberFormatTest::expect(NumberFormat& fmt, const Formattable& n, } void NumberFormatTest::expect(NumberFormat* fmt, const Formattable& n, - const UnicodeString& exp, + const UnicodeString& exp, UBool rt, UErrorCode status) { if (fmt == NULL || U_FAILURE(status)) { dataerrln("FAIL: NumberFormat constructor"); } else { - expect(*fmt, n, exp); + expect(*fmt, n, exp, rt); } delete fmt; } @@ -2611,11 +2878,79 @@ void NumberFormatTest::expectPad(DecimalFormat& fmt, const UnicodeString& pat, ", expected " + pos + " " + width + " " + pad); } } + +// This test is flaky b/c the symbols for CNY and JPY are equivalent in this locale - FIXME +void NumberFormatTest::TestCompatibleCurrencies() { +/* + static const UChar JPY[] = {0x4A, 0x50, 0x59, 0}; + static const UChar CNY[] = {0x43, 0x4E, 0x59, 0}; + UErrorCode status = U_ZERO_ERROR; + LocalPointer fmt( + NumberFormat::createCurrencyInstance(Locale::getUS(), status)); + if (U_FAILURE(status)) { + errln("Could not create number format instance."); + return; + } + logln("%s:%d - testing parse of halfwidth yen sign\n", __FILE__, __LINE__); + expectParseCurrency(*fmt, JPY, 1235, "\\u00A51,235"); + logln("%s:%d - testing parse of fullwidth yen sign\n", __FILE__, __LINE__); + expectParseCurrency(*fmt, JPY, 1235, "\\uFFE51,235"); + logln("%s:%d - testing parse of halfwidth yen sign\n", __FILE__, __LINE__); + expectParseCurrency(*fmt, CNY, 1235, "CN\\u00A51,235"); + + LocalPointer fmtTW( + NumberFormat::createCurrencyInstance(Locale::getTaiwan(), status)); + + logln("%s:%d - testing parse of halfwidth yen sign in TW\n", __FILE__, __LINE__); + expectParseCurrency(*fmtTW, CNY, 1235, "\\u00A51,235"); + logln("%s:%d - testing parse of fullwidth yen sign in TW\n", __FILE__, __LINE__); + expectParseCurrency(*fmtTW, CNY, 1235, "\\uFFE51,235"); + + LocalPointer fmtJP( + NumberFormat::createCurrencyInstance(Locale::getJapan(), status)); + + logln("%s:%d - testing parse of halfwidth yen sign in JP\n", __FILE__, __LINE__); + expectParseCurrency(*fmtJP, JPY, 1235, "\\u00A51,235"); + logln("%s:%d - testing parse of fullwidth yen sign in JP\n", __FILE__, __LINE__); + expectParseCurrency(*fmtJP, JPY, 1235, "\\uFFE51,235"); + + // more.. +*/ +} + +void NumberFormatTest::expectParseCurrency(const NumberFormat &fmt, const UChar* currency, double amount, const char *text) { + ParsePosition ppos; + UnicodeString utext = ctou(text); + LocalPointer currencyAmount(fmt.parseCurrency(utext, ppos)); + if (!ppos.getIndex()) { + errln(UnicodeString("Parse of ") + utext + " should have succeeded."); + return; + } + UErrorCode status = U_ZERO_ERROR; + + char theInfo[100]; + sprintf(theInfo, "For locale %s, string \"%s\", currency ", + fmt.getLocale(ULOC_ACTUAL_LOCALE, status).getBaseName(), + text); + u_austrcpy(theInfo+uprv_strlen(theInfo), currency); + + char theOperation[100]; + + uprv_strcpy(theOperation, theInfo); + uprv_strcat(theOperation, ", check amount:"); + assertTrue(theOperation, amount == currencyAmount->getNumber().getDouble(status)); + + uprv_strcpy(theOperation, theInfo); + uprv_strcat(theOperation, ", check currency:"); + assertEquals(theOperation, currency, currencyAmount->getISOCurrency()); +} + + 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 expected(CharsToUnicodeString("1,150$50\\u00A0\\u200B")); // per cldrbug 7670 UnicodeString s; NumberFormat* currencyFmt = NumberFormat::createCurrencyInstance(loc, status); if(U_FAILURE(status)){ @@ -2684,7 +3019,7 @@ void NumberFormatTest::TestHostClone() UDate now = Calendar::getNow(); NumberFormat *full = NumberFormat::createInstance(loc, status); if (full == NULL || U_FAILURE(status)) { - dataerrln("FAIL: Can't create Relative date instance - %s", u_errorName(status)); + dataerrln("FAIL: Can't create NumberFormat date instance - %s", u_errorName(status)); return; } UnicodeString result1; @@ -2721,9 +3056,13 @@ void NumberFormatTest::TestCurrencyFormat() } MeasureFormat *measureObj = MeasureFormat::createCurrencyFormat(status); + if (U_FAILURE(status)){ + dataerrln("FAIL: MeasureFormat::createCurrencyFormat status %s", u_errorName(status)); + return; + } Locale::setDefault( saveDefaultLocale, status ); if (U_FAILURE(status)){ - dataerrln("FAIL: Status %s", u_errorName(status)); + dataerrln("FAIL: Locale::setDefault status %s", u_errorName(status)); return; } cloneObj = (MeasureFormat *)measureObj->clone(); @@ -2800,7 +3139,7 @@ void NumberFormatTest::TestRoundingPattern() { { (UnicodeString)"##0.65", 1.234, (UnicodeString)"1.30" }, { (UnicodeString)"#50", 1230, (UnicodeString)"1250" } }; - int32_t numOfTests = (sizeof(tests)/sizeof(tests[0])); + int32_t numOfTests = UPRV_LENGTHOF(tests); UnicodeString result; DecimalFormat *df = (DecimalFormat*)NumberFormat::createCurrencyInstance(Locale::getEnglish(), status); @@ -2976,7 +3315,7 @@ NumberFormatTest::TestSpaceParsing() { delete foo; return; } - for (uint32_t i = 0; i < sizeof(DATA)/sizeof(DATA[0]); ++i) { + for (uint32_t i = 0; i < UPRV_LENGTHOF(DATA); ++i) { ParsePosition parsePosition(0); UnicodeString stringToBeParsed = ctou(DATA[i].stringToParse); int parsedPosition = DATA[i].parsedPos; @@ -2984,6 +3323,7 @@ NumberFormatTest::TestSpaceParsing() { foo->setLenient(DATA[i].lenient); Formattable result; foo->parse(stringToBeParsed, result, parsePosition); + logln("Parsing: " + stringToBeParsed); if (parsePosition.getIndex() != parsedPosition || parsePosition.getErrorIndex() != errorIndex) { errln("FAILED parse " + stringToBeParsed + "; lenient: " + DATA[i].lenient + "; wrong position, expected: (" + parsedPosition + ", " + errorIndex + "); got (" + parsePosition.getIndex() + ", " + parsePosition.getErrorIndex() + ")"); @@ -3013,7 +3353,7 @@ void NumberFormatTest::TestNumberingSystems() { { "en_US@numbers=thai", 1234.567, FALSE, "\\u0E51,\\u0E52\\u0E53\\u0E54.\\u0E55\\u0E56\\u0E57" }, { "en_US@numbers=hebr", 5678.0, TRUE, "\\u05D4\\u05F3\\u05EA\\u05E8\\u05E2\\u05F4\\u05D7" }, { "en_US@numbers=arabext", 1234.567, FALSE, "\\u06F1\\u066c\\u06F2\\u06F3\\u06F4\\u066b\\u06F5\\u06F6\\u06F7" }, - { "ar_EG", 1234.567, FALSE, "\\u0661\\u0662\\u0663\\u0664\\u066b\\u0665\\u0666\\u0667" }, + { "ar_EG", 1234.567, FALSE, "\\u0661\\u066C\\u0662\\u0663\\u0664\\u066b\\u0665\\u0666\\u0667" }, { "th_TH@numbers=traditional", 1234.567, FALSE, "\\u0E51,\\u0E52\\u0E53\\u0E54.\\u0E55\\u0E56\\u0E57" }, // fall back to native per TR35 { "ar_MA", 1234.567, FALSE, "1.234,567" }, { "en_US@numbers=hanidec", 1234.567, FALSE, "\\u4e00,\\u4e8c\\u4e09\\u56db.\\u4e94\\u516d\\u4e03" }, @@ -3022,7 +3362,7 @@ void NumberFormatTest::TestNumberingSystems() { { "ta_IN@numbers=finance", 1234.567, FALSE, "1,234.567" }, // fall back to default per TR35 { "zh_TW@numbers=native", 1234.567, FALSE, "\\u4e00,\\u4e8c\\u4e09\\u56db.\\u4e94\\u516d\\u4e03" }, { "zh_TW@numbers=traditional", 1234.567, TRUE, "\\u4E00\\u5343\\u4E8C\\u767E\\u4E09\\u5341\\u56DB\\u9EDE\\u4E94\\u516D\\u4E03" }, - { "zh_TW@numbers=finance", 1234.567, TRUE, "\\u58F9\\u4EDF\\u8CB3\\u4F70\\u53C4\\u62FE\\u8086\\u9EDE\\u4F0D\\u9678\\u67D2" }, + { "zh_TW@numbers=finance", 1234.567, TRUE, "\\u58F9\\u4EDF\\u8CB3\\u4F70\\u53C3\\u62FE\\u8086\\u9EDE\\u4F0D\\u9678\\u67D2" }, { NULL, 0, FALSE, NULL } }; @@ -3032,13 +3372,17 @@ void NumberFormatTest::TestNumberingSystems() { for (item = DATA; item->localeName != NULL; item++) { ec = U_ZERO_ERROR; Locale loc = Locale::createFromName(item->localeName); - NumberFormat *fmt = NumberFormat::createInstance(loc,ec); + NumberFormat *origFmt = NumberFormat::createInstance(loc,ec); if (U_FAILURE(ec)) { dataerrln("FAIL: getInstance(%s) - %s", item->localeName, u_errorName(ec)); continue; } - + // Clone to test ticket #10682 + NumberFormat *fmt = (NumberFormat *) origFmt->clone(); + delete origFmt; + + if (item->isRBNF) { expect3(*fmt,item->value,CharsToUnicodeString(item->expectedResult)); } else { @@ -3094,11 +3438,11 @@ NumberFormatTest::TestMultiCurrencySign() { // for US locale {"en_US", "\\u00A4#,##0.00;-\\u00A4#,##0.00", "1234.56", "$1,234.56", "USD1,234.56", "US dollars1,234.56"}, {"en_US", "\\u00A4#,##0.00;-\\u00A4#,##0.00", "-1234.56", "-$1,234.56", "-USD1,234.56", "-US dollars1,234.56"}, - {"en_US", "\\u00A4#,##0.00;-\\u00A4#,##0.00", "1", "$1.00", "USD1.00", "US dollar1.00"}, + {"en_US", "\\u00A4#,##0.00;-\\u00A4#,##0.00", "1", "$1.00", "USD1.00", "US dollars1.00"}, // for CHINA locale - {"zh_CN", "\\u00A4#,##0.00;(\\u00A4#,##0.00)", "1234.56", "\\uFFE51,234.56", "CNY1,234.56", "\\u4EBA\\u6C11\\u5E011,234.56"}, - {"zh_CN", "\\u00A4#,##0.00;(\\u00A4#,##0.00)", "-1234.56", "(\\uFFE51,234.56)", "(CNY1,234.56)", "(\\u4EBA\\u6C11\\u5E011,234.56)"}, - {"zh_CN", "\\u00A4#,##0.00;(\\u00A4#,##0.00)", "1", "\\uFFE51.00", "CNY1.00", "\\u4EBA\\u6C11\\u5E011.00"} + {"zh_CN", "\\u00A4#,##0.00;(\\u00A4#,##0.00)", "1234.56", "\\u00A51,234.56", "CNY1,234.56", "\\u4EBA\\u6C11\\u5E011,234.56"}, + {"zh_CN", "\\u00A4#,##0.00;(\\u00A4#,##0.00)", "-1234.56", "(\\u00A51,234.56)", "(CNY1,234.56)", "(\\u4EBA\\u6C11\\u5E011,234.56)"}, + {"zh_CN", "\\u00A4#,##0.00;(\\u00A4#,##0.00)", "1", "\\u00A51.00", "CNY1.00", "\\u4EBA\\u6C11\\u5E011.00"} }; const UChar doubleCurrencySign[] = {0xA4, 0xA4, 0}; @@ -3106,7 +3450,7 @@ NumberFormatTest::TestMultiCurrencySign() { const UChar tripleCurrencySign[] = {0xA4, 0xA4, 0xA4, 0}; UnicodeString tripleCurrencyStr(tripleCurrencySign); - for (uint32_t i=0; i df( + dynamic_cast(DecimalFormat::createCurrencyInstance("en", status)), status); + if (!assertSuccess("createCurrencyInstance() failed.", status, true, __FILE__, __LINE__)) {return;} + UnicodeString pattern; + assertEquals("Test assumes that currency sign is at the beginning", + u"\u00A4#,##0.00", + df->toPattern(pattern)); + // Should round-trip on the correct currency format: + expect2(*df, 1.23, u"XXX\u00A01.23"); + df->setCurrency(u"EUR", status); + expect2(*df, 1.23, u"\u20AC1.23"); + // Should parse with currency in the wrong place in lenient mode + df->setLenient(TRUE); + expect(*df, u"1.23\u20AC", 1.23); + expectParseCurrency(*df, u"EUR", 1.23, "1.23\\u20AC"); + // Should NOT parse with currency in the wrong place in STRICT mode + df->setLenient(FALSE); + { + Formattable result; + ErrorCode failStatus; + df->parse(u"1.23\u20AC", result, failStatus); + assertEquals("Should fail to parse", U_INVALID_FORMAT_ERROR, failStatus); + } + { + ParsePosition ppos; + df->parseCurrency(u"1.23\u20AC", ppos); + assertEquals("Should fail to parse currency", 0, ppos.getIndex()); + } +} + + void NumberFormatTest::TestDecimalFormatCurrencyParse() { // Locale.US @@ -3242,12 +3620,15 @@ NumberFormatTest::TestDecimalFormatCurrencyParse() { {"USD1,234.56", "1234.56"}, {"1,234.56 US dollar", "1234.56"}, }; - for (uint32_t i = 0; i < sizeof(DATA)/sizeof(DATA[0]); ++i) { + // NOTE: ICU 62 requires that the currency format match the pattern in strict mode. + fmt->setLenient(TRUE); + for (uint32_t i = 0; i < UPRV_LENGTHOF(DATA); ++i) { UnicodeString stringToBeParsed = ctou(DATA[i][0]); double parsedResult = atof(DATA[i][1]); UErrorCode status = U_ZERO_ERROR; Formattable result; fmt->parse(stringToBeParsed, result, status); + logln((UnicodeString)"Input: " + stringToBeParsed + "; output: " + result.getDouble(status)); if (U_FAILURE(status) || (result.getType() == Formattable::kDouble && result.getDouble() != parsedResult) || @@ -3271,22 +3652,20 @@ NumberFormatTest::TestCurrencyIsoPluralFormat() { // format result using ISOCURRENCYSTYLE, // format result using PLURALCURRENCYSTYLE, - {"en_US", "1", "USD", "$1.00", "USD1.00", "1.00 US dollar"}, + {"en_US", "1", "USD", "$1.00", "USD1.00", "1.00 US dollars"}, {"en_US", "1234.56", "USD", "$1,234.56", "USD1,234.56", "1,234.56 US dollars"}, - {"en_US", "-1234.56", "USD", "($1,234.56)", "(USD1,234.56)", "-1,234.56 US dollars"}, - {"zh_CN", "1", "USD", "US$1.00", "USD1.00", "1.00 \\u7F8E\\u5143"}, - {"zh_CN", "1234.56", "USD", "US$1,234.56", "USD1,234.56", "1,234.56 \\u7F8E\\u5143"}, - // wrong ISO code {"zh_CN", "1", "CHY", "CHY1.00", "CHY1.00", "1.00 CHY"}, - // wrong ISO code {"zh_CN", "1234.56", "CHY", "CHY1,234.56", "CHY1,234.56", "1,234.56 CHY"}, - {"zh_CN", "1", "CNY", "\\uFFE51.00", "CNY1.00", "1.00 \\u4EBA\\u6C11\\u5E01"}, - {"zh_CN", "1234.56", "CNY", "\\uFFE51,234.56", "CNY1,234.56", "1,234.56 \\u4EBA\\u6C11\\u5E01"}, - {"ru_RU", "1", "RUB", "1,00\\u00A0\\u0440\\u0443\\u0431.", "1,00\\u00A0RUB", "1,00 \\u0440\\u043E\\u0441\\u0441\\u0438\\u0439\\u0441\\u043A\\u0438\\u0439 \\u0440\\u0443\\u0431\\u043B\\u044C"}, - {"ru_RU", "2", "RUB", "2,00\\u00A0\\u0440\\u0443\\u0431.", "2,00\\u00A0RUB", "2,00 \\u0440\\u043E\\u0441\\u0441\\u0438\\u0439\\u0441\\u043A\\u0438\\u0445 \\u0440\\u0443\\u0431\\u043B\\u044F"}, - {"ru_RU", "5", "RUB", "5,00\\u00A0\\u0440\\u0443\\u0431.", "5,00\\u00A0RUB", "5,00 \\u0440\\u043E\\u0441\\u0441\\u0438\\u0439\\u0441\\u043A\\u0438\\u0445 \\u0440\\u0443\\u0431\\u043B\\u0435\\u0439"}, + {"en_US", "-1234.56", "USD", "-$1,234.56", "-USD1,234.56", "-1,234.56 US dollars"}, + {"zh_CN", "1", "USD", "US$1.00", "USD1.00", "1.00\\u7F8E\\u5143"}, + {"zh_CN", "1234.56", "USD", "US$1,234.56", "USD1,234.56", "1,234.56\\u7F8E\\u5143"}, + {"zh_CN", "1", "CNY", "\\u00A51.00", "CNY1.00", "1.00\\u4EBA\\u6C11\\u5E01"}, + {"zh_CN", "1234.56", "CNY", "\\u00A51,234.56", "CNY1,234.56", "1,234.56\\u4EBA\\u6C11\\u5E01"}, + {"ru_RU", "1", "RUB", "1,00\\u00A0\\u20BD", "1,00\\u00A0RUB", "1,00 \\u0440\\u043E\\u0441\\u0441\\u0438\\u0439\\u0441\\u043A\\u043E\\u0433\\u043E \\u0440\\u0443\\u0431\\u043B\\u044F"}, + {"ru_RU", "2", "RUB", "2,00\\u00A0\\u20BD", "2,00\\u00A0RUB", "2,00 \\u0440\\u043E\\u0441\\u0441\\u0438\\u0439\\u0441\\u043A\\u043E\\u0433\\u043E \\u0440\\u0443\\u0431\\u043B\\u044F"}, + {"ru_RU", "5", "RUB", "5,00\\u00A0\\u20BD", "5,00\\u00A0RUB", "5,00 \\u0440\\u043E\\u0441\\u0441\\u0438\\u0439\\u0441\\u043A\\u043E\\u0433\\u043E \\u0440\\u0443\\u0431\\u043B\\u044F"}, // test locale without currency information {"root", "-1.23", "USD", "-US$\\u00A01.23", "-USD\\u00A01.23", "-1.23 USD"}, // test choice format - {"es_AR", "1", "INR", "\\u20B91,00", "INR1,00", "1,00 rupia india"}, + {"es_AR", "1", "INR", "INR\\u00A01,00", "INR\\u00A01,00", "1,00 rupia india"}, }; static const UNumberFormatStyle currencyStyles[] = { UNUM_CURRENCY, @@ -3294,13 +3673,15 @@ NumberFormatTest::TestCurrencyIsoPluralFormat() { UNUM_CURRENCY_PLURAL }; - for (int32_t i=0; isetLenient(TRUE); for (int j = 3; j < 6; ++j) { // DATA[i][3] is the currency format result using // CURRENCYSTYLE formatter. @@ -3367,41 +3750,55 @@ NumberFormatTest::TestCurrencyParsing() { // format result using CURRENCYSTYLE, // format result using ISOCURRENCYSTYLE, // format result using PLURALCURRENCYSTYLE, - {"en_US", "1", "USD", "$1.00", "USD1.00", "1.00 US dollar"}, - {"pa_IN", "1", "USD", "US$\\u00a0\\u0a67.\\u0a66\\u0a66", "USD\\u00a0\\u0a67.\\u0a66\\u0a66", "\\u0a67.\\u0a66\\u0a66 USD"}, - {"es_AR", "1", "USD", "US$1,00", "USD1,00", "1,00 d\\u00f3lar estadounidense"}, + {"en_US", "1", "USD", "$1.00", "USD\\u00A01.00", "1.00 US dollars"}, + {"pa_IN", "1", "USD", "US$\\u00A01.00", "USD\\u00A01.00", "1.00 \\u0a2f\\u0a42.\\u0a10\\u0a38. \\u0a21\\u0a3e\\u0a32\\u0a30"}, + {"es_AR", "1", "USD", "US$\\u00A01,00", "USD\\u00A01,00", "1,00 d\\u00f3lar estadounidense"}, {"ar_EG", "1", "USD", "\\u0661\\u066b\\u0660\\u0660\\u00a0US$", "\\u0661\\u066b\\u0660\\u0660\\u00a0USD", "\\u0661\\u066b\\u0660\\u0660 \\u062f\\u0648\\u0644\\u0627\\u0631 \\u0623\\u0645\\u0631\\u064a\\u0643\\u064a"}, - {"fa_CA", "1", "USD", "\\u06f1\\u066b\\u06f0\\u06f0\\u00a0US$", "\\u06f1\\u066b\\u06f0\\u06f0\\u00a0USD", "\\u06f1\\u066b\\u06f0\\u06f0\\u0020\\u062f\\u0644\\u0627\\u0631\\u0020\\u0627\\u0645\\u0631\\u06cc\\u06a9\\u0627"}, - {"he_IL", "1", "USD", "1.00\\u00a0US$", "1.00\\u00a0USD", "1.00 \\u05d3\\u05d5\\u05dc\\u05e8 \\u05d0\\u05de\\u05e8\\u05d9\\u05e7\\u05d0\\u05d9"}, - {"hr_HR", "1", "USD", "1,00\\u00a0$", "1,00\\u00a0USD", "1,00 Ameri\\u010dki dolar"}, - {"id_ID", "1", "USD", "US$1,00", "USD1,00", "1,00 Dolar Amerika Serikat"}, - {"it_IT", "1", "USD", "US$\\u00a01,00", "USD\\u00a01,00", "1,00 Dollaro Statunitense"}, - {"ko_KR", "1", "USD", "US$1.00", "USD1.00", "1.00 \\ubbf8\\uad6d \\ub2ec\\ub7ec"}, - {"ja_JP", "1", "USD", "$1.00", "USD1.00", "1.00 \\u7c73\\u30c9\\u30eb"}, - {"zh_CN", "1", "CNY", "\\uFFE51.00", "CNY1.00", "1.00 \\u4EBA\\u6C11\\u5E01"}, - {"zh_TW", "1", "CNY", "\\uFFE51.00", "CNY1.00", "1.00 \\u4eba\\u6c11\\u5e63"}, - {"ru_RU", "1", "RUB", "1,00\\u00A0\\u0440\\u0443\\u0431.", "1,00\\u00A0RUB", "1,00 \\u0420\\u043E\\u0441\\u0441\\u0438\\u0439\\u0441\\u043A\\u0438\\u0439 \\u0440\\u0443\\u0431\\u043B\\u044C"}, + {"fa_CA", "1", "USD", "\\u200e$\\u06f1\\u066b\\u06f0\\u06f0", "\\u200eUSD\\u06f1\\u066b\\u06f0\\u06f0", "\\u06f1\\u066b\\u06f0\\u06f0 \\u062f\\u0644\\u0627\\u0631 \\u0627\\u0645\\u0631\\u06cc\\u06a9\\u0627"}, + {"he_IL", "1", "USD", "\\u200f1.00\\u00a0$", "\\u200f1.00\\u00a0USD", "1.00 \\u05d3\\u05d5\\u05dc\\u05e8 \\u05d0\\u05de\\u05e8\\u05d9\\u05e7\\u05d0\\u05d9"}, + {"hr_HR", "1", "USD", "1,00\\u00a0USD", "1,00\\u00a0USD", "1,00 ameri\\u010Dkih dolara"}, + {"id_ID", "1", "USD", "US$\\u00A01,00", "USD\\u00A01,00", "1,00 Dolar Amerika Serikat"}, + {"it_IT", "1", "USD", "1,00\\u00a0USD", "1,00\\u00a0USD", "1,00 dollari statunitensi"}, + {"ko_KR", "1", "USD", "US$\\u00A01.00", "USD\\u00A01.00", "1.00 \\ubbf8\\uad6d \\ub2ec\\ub7ec"}, + {"ja_JP", "1", "USD", "$1.00", "USD\\u00A01.00", "1.00\\u7c73\\u30c9\\u30eb"}, + {"zh_CN", "1", "CNY", "\\uFFE51.00", "CNY\\u00A001.00", "1.00\\u4EBA\\u6C11\\u5E01"}, + {"zh_TW", "1", "CNY", "CN\\u00A51.00", "CNY\\u00A01.00", "1.00 \\u4eba\\u6c11\\u5e63"}, + {"zh_Hant", "1", "CNY", "CN\\u00A51.00", "CNY\\u00A01.00", "1.00 \\u4eba\\u6c11\\u5e63"}, + {"zh_Hant", "1", "JPY", "\\u00A51.00", "JPY\\u00A01.00", "1 \\u65E5\\u5713"}, + {"ja_JP", "1", "JPY", "\\uFFE51.00", "JPY\\u00A01.00", "1\\u5186"}, + // ICU 62 requires #parseCurrency() to recognize variants when parsing + // {"ja_JP", "1", "JPY", "\\u00A51.00", "JPY\\u00A01.00", "1\\u00A0\\u5186"}, + {"ru_RU", "1", "RUB", "1,00\\u00A0\\u00A0\\u20BD", "1,00\\u00A0\\u00A0RUB", "1,00 \\u0440\\u043E\\u0441\\u0441\\u0438\\u0439\\u0441\\u043A\\u043E\\u0433\\u043E \\u0440\\u0443\\u0431\\u043B\\u044F"} }; static const UNumberFormatStyle currencyStyles[] = { UNUM_CURRENCY, UNUM_CURRENCY_ISO, UNUM_CURRENCY_PLURAL }; + static const char* currencyStyleNames[] = { + "UNUM_CURRENCY", + "UNUM_CURRENCY_ISO", + "UNUM_CURRENCY_PLURAL" + }; #ifdef NUMFMTST_CACHE_DEBUG int deadloop = 0; for (;;) { printf("loop: %d\n", deadloop++); #endif - for (uint32_t i=0; iformat(numberToBeFormat, strBuf); int resultDataIndex = 3 + kIndex; @@ -3426,8 +3822,9 @@ for (;;) { if (strBuf.compare(formatResult)) { errln("FAIL: Expected " + formatResult + " actual: " + strBuf); } - */ // test parsing, and test parsing for all currency formats. + // NOTE: ICU 62 requires that the currency format match the pattern in strict mode. + numFmt->setLenient(TRUE); for (int j = 3; j < 6; ++j) { // DATA[i][3] is the currency format result using // CURRENCYSTYLE formatter. @@ -3438,20 +3835,21 @@ for (;;) { UnicodeString oneCurrencyFormatResult = ctou(DATA[i][j]); UErrorCode status = U_ZERO_ERROR; Formattable parseResult; + logln("parse(%s)", DATA[i][j]); numFmt->parse(oneCurrencyFormatResult, parseResult, status); if (U_FAILURE(status) || (parseResult.getType() == Formattable::kDouble && parseResult.getDouble() != numberToBeFormat) || (parseResult.getType() == Formattable::kLong && parseResult.getLong() != numberToBeFormat)) { - errln((UnicodeString)"FAIL: getCurrencyFormat of locale " + - localeString + " failed roundtripping the number" + - "(i,k,j): " + i + ", " + k + ", " + j); + errln((UnicodeString)"FAIL: NumberFormat(" + localeString +", " + currencyStyleNames[kIndex] + + "), Currency="+currencyISOCode+", parse("+DATA[i][j]+") returned error " + (UnicodeString)u_errorName(status)+". Testcase: data[" + i + "][" + currencyStyleNames[j-3] +"="+j+"]"); if (parseResult.getType() == Formattable::kDouble) { - errln((UnicodeString)"expected: " + numberToBeFormat + "; actual: " +parseResult.getDouble()); + errln((UnicodeString)"expected: " + numberToBeFormat + "; actual (double): " +parseResult.getDouble()); } else { - errln((UnicodeString)"expected: " + numberToBeFormat + "; actual: " +parseResult.getLong()); + errln((UnicodeString)"expected: " + numberToBeFormat + "; actual (long): " +parseResult.getLong()); } + errln((UnicodeString)" round-trip would be: " + strBuf); } } delete numFmt; @@ -3472,7 +3870,7 @@ NumberFormatTest::TestParseCurrencyInUCurr() { "US dollar1.00", "US dollars1.00", "$1.00", - "AU$1.00", + "A$1.00", "ADP1.00", "ADP1.00", "AED1.00", @@ -3503,8 +3901,8 @@ NumberFormatTest::TestParseCurrencyInUCurr() { "AZM1.00", "AZM1.00", "AZN1.00", - "Afghan Afghani (1927-2002)1.00", - "Afghan afghani (1927-2002)1.00", + "Afghan Afghani (1927\\u20132002)1.00", + "Afghan afghani (1927\\u20132002)1.00", "Afghan Afghani1.00", "Afghan Afghanis1.00", "Albanian Lek1.00", @@ -3516,26 +3914,26 @@ NumberFormatTest::TestParseCurrencyInUCurr() { "Andorran Peseta1.00", "Andorran peseta1.00", "Andorran pesetas1.00", - "Angolan Kwanza (1977-1991)1.00", - "Angolan Readjusted Kwanza (1995-1999)1.00", + "Angolan Kwanza (1977\\u20131991)1.00", + "Angolan Readjusted Kwanza (1995\\u20131999)1.00", "Angolan Kwanza1.00", - "Angolan New Kwanza (1990-2000)1.00", - "Angolan kwanza (1977-1991)1.00", - "Angolan readjusted kwanza (1995-1999)1.00", + "Angolan New Kwanza (1990\\u20132000)1.00", + "Angolan kwanza (1977\\u20131991)1.00", + "Angolan readjusted kwanza (1995\\u20131999)1.00", "Angolan kwanza1.00", - "Angolan kwanzas (1977-1991)1.00", - "Angolan readjusted kwanzas (1995-1999)1.00", + "Angolan kwanzas (1977\\u20131991)1.00", + "Angolan readjusted kwanzas (1995\\u20131999)1.00", "Angolan kwanzas1.00", - "Angolan new kwanza (1990-2000)1.00", - "Angolan new kwanzas (1990-2000)1.00", + "Angolan new kwanza (1990\\u20132000)1.00", + "Angolan new kwanzas (1990\\u20132000)1.00", "Argentine Austral1.00", - "Argentine Peso (1983-1985)1.00", + "Argentine Peso (1983\\u20131985)1.00", "Argentine Peso1.00", "Argentine austral1.00", "Argentine australs1.00", - "Argentine peso (1983-1985)1.00", + "Argentine peso (1983\\u20131985)1.00", "Argentine peso1.00", - "Argentine pesos (1983-1985)1.00", + "Argentine pesos (1983\\u20131985)1.00", "Argentine pesos1.00", "Armenian Dram1.00", "Armenian dram1.00", @@ -3548,11 +3946,11 @@ NumberFormatTest::TestParseCurrencyInUCurr() { "Austrian Schilling1.00", "Austrian schilling1.00", "Austrian schillings1.00", - "Azerbaijani Manat (1993-2006)1.00", + "Azerbaijani Manat (1993\\u20132006)1.00", "Azerbaijani Manat1.00", - "Azerbaijani manat (1993-2006)1.00", + "Azerbaijani manat (1993\\u20132006)1.00", "Azerbaijani manat1.00", - "Azerbaijani manats (1993-2006)1.00", + "Azerbaijani manats (1993\\u20132006)1.00", "Azerbaijani manats1.00", "BAD1.00", "BAD1.00", @@ -3609,10 +4007,10 @@ NumberFormatTest::TestParseCurrencyInUCurr() { "Barbadian Dollar1.00", "Barbadian dollar1.00", "Barbadian dollars1.00", - "Belarusian New Ruble (1994-1999)1.00", + "Belarusian Ruble (1994\\u20131999)1.00", "Belarusian Ruble1.00", - "Belarusian new ruble (1994-1999)1.00", - "Belarusian new rubles (1994-1999)1.00", + "Belarusian ruble (1994\\u20131999)1.00", + "Belarusian rubles (1994\\u20131999)1.00", "Belarusian ruble1.00", "Belarusian rubles1.00", "Belgian Franc (convertible)1.00", @@ -3643,35 +4041,35 @@ NumberFormatTest::TestParseCurrencyInUCurr() { "Bolivian Boliviano1.00", "Bolivian Bolivianos1.00", "Bosnia-Herzegovina Convertible Mark1.00", - "Bosnia-Herzegovina Dinar (1992-1994)1.00", + "Bosnia-Herzegovina Dinar (1992\\u20131994)1.00", "Bosnia-Herzegovina convertible mark1.00", "Bosnia-Herzegovina convertible marks1.00", - "Bosnia-Herzegovina dinar (1992-1994)1.00", - "Bosnia-Herzegovina dinars (1992-1994)1.00", + "Bosnia-Herzegovina dinar (1992\\u20131994)1.00", + "Bosnia-Herzegovina dinars (1992\\u20131994)1.00", "Botswanan Pula1.00", "Botswanan pula1.00", "Botswanan pulas1.00", - "Brazilian New Cruzado (1989-1990)1.00", - "Brazilian Cruzado (1986-1989)1.00", - "Brazilian Cruzeiro (1990-1993)1.00", - "Brazilian New Cruzeiro (1967-1986)1.00", - "Brazilian Cruzeiro (1993-1994)1.00", + "Brazilian New Cruzado (1989\\u20131990)1.00", + "Brazilian Cruzado (1986\\u20131989)1.00", + "Brazilian Cruzeiro (1990\\u20131993)1.00", + "Brazilian New Cruzeiro (1967\\u20131986)1.00", + "Brazilian Cruzeiro (1993\\u20131994)1.00", "Brazilian Real1.00", - "Brazilian new cruzado (1989-1990)1.00", - "Brazilian new cruzados (1989-1990)1.00", - "Brazilian cruzado (1986-1989)1.00", - "Brazilian cruzados (1986-1989)1.00", - "Brazilian cruzeiro (1990-1993)1.00", - "Brazilian new cruzeiro (1967-1986)1.00", - "Brazilian cruzeiro (1993-1994)1.00", - "Brazilian cruzeiros (1990-1993)1.00", - "Brazilian new cruzeiros (1967-1986)1.00", - "Brazilian cruzeiros (1993-1994)1.00", + "Brazilian new cruzado (1989\\u20131990)1.00", + "Brazilian new cruzados (1989\\u20131990)1.00", + "Brazilian cruzado (1986\\u20131989)1.00", + "Brazilian cruzados (1986\\u20131989)1.00", + "Brazilian cruzeiro (1990\\u20131993)1.00", + "Brazilian new cruzeiro (1967\\u20131986)1.00", + "Brazilian cruzeiro (1993\\u20131994)1.00", + "Brazilian cruzeiros (1990\\u20131993)1.00", + "Brazilian new cruzeiros (1967\\u20131986)1.00", + "Brazilian cruzeiros (1993\\u20131994)1.00", "Brazilian real1.00", "Brazilian reals1.00", - "British Pound Sterling1.00", - "British pound sterling1.00", - "British pounds sterling1.00", + "British Pound1.00", + "British pound1.00", + "British pounds1.00", "Brunei Dollar1.00", "Brunei dollar1.00", "Brunei dollars1.00", @@ -3691,12 +4089,12 @@ NumberFormatTest::TestParseCurrencyInUCurr() { "CAD1.00", "CDF1.00", "CDF1.00", - "CFA Franc BCEAO1.00", - "CFA Franc BEAC1.00", - "CFA franc BCEAO1.00", - "CFA franc BEAC1.00", - "CFA francs BCEAO1.00", - "CFA francs BEAC1.00", + "West African CFA Franc1.00", + "Central African CFA Franc1.00", + "West African CFA franc1.00", + "Central African CFA franc1.00", + "West African CFA francs1.00", + "Central African CFA francs1.00", "CFP Franc1.00", "CFP franc1.00", "CFP francs1.00", @@ -3767,9 +4165,9 @@ NumberFormatTest::TestParseCurrencyInUCurr() { "Cypriot Pound1.00", "Cypriot pound1.00", "Cypriot pounds1.00", - "Czech Republic Koruna1.00", - "Czech Republic koruna1.00", - "Czech Republic korunas1.00", + "Czech Koruna1.00", + "Czech koruna1.00", + "Czech korunas1.00", "Czechoslovak Hard Koruna1.00", "Czechoslovak hard koruna1.00", "Czechoslovak hard korunas1.00", @@ -3915,11 +4313,11 @@ NumberFormatTest::TestParseCurrencyInUCurr() { "Georgian kupon larits1.00", "Georgian lari1.00", "Georgian laris1.00", - "Ghanaian Cedi (1979-2007)1.00", + "Ghanaian Cedi (1979\\u20132007)1.00", "Ghanaian Cedi1.00", - "Ghanaian cedi (1979-2007)1.00", + "Ghanaian cedi (1979\\u20132007)1.00", "Ghanaian cedi1.00", - "Ghanaian cedis (1979-2007)1.00", + "Ghanaian cedis (1979\\u20132007)1.00", "Ghanaian cedis1.00", "Gibraltar Pound1.00", "Gibraltar pound1.00", @@ -3996,7 +4394,7 @@ NumberFormatTest::TestParseCurrencyInUCurr() { "Irish pound1.00", "Irish pounds1.00", "Israeli Pound1.00", - "Israeli new sheqel1.00", + "Israeli new shekel1.00", "Israeli pound1.00", "Israeli pounds1.00", "Italian Lira1.00", @@ -4170,12 +4568,12 @@ NumberFormatTest::TestParseCurrencyInUCurr() { "Mauritian rupee1.00", "Mauritian rupees1.00", "Mexican Peso1.00", - "Mexican Silver Peso (1861-1992)1.00", + "Mexican Silver Peso (1861\\u20131992)1.00", "Mexican Investment Unit1.00", "Mexican peso1.00", "Mexican pesos1.00", - "Mexican silver peso (1861-1992)1.00", - "Mexican silver pesos (1861-1992)1.00", + "Mexican silver peso (1861\\u20131992)1.00", + "Mexican silver pesos (1861\\u20131992)1.00", "Mexican investment unit1.00", "Mexican investment units1.00", "Moldovan Leu1.00", @@ -4196,9 +4594,9 @@ NumberFormatTest::TestParseCurrencyInUCurr() { "Mozambican escudos1.00", "Mozambican metical1.00", "Mozambican meticals1.00", - "Myanma Kyat1.00", - "Myanma kyat1.00", - "Myanma kyats1.00", + "Myanmar Kyat1.00", + "Myanmar kyat1.00", + "Myanmar kyats1.00", "NAD1.00", "NGN1.00", "NIC1.00", @@ -4223,17 +4621,17 @@ NumberFormatTest::TestParseCurrencyInUCurr() { "Dutch Guilder1.00", "Dutch guilder1.00", "Dutch guilders1.00", - "Israeli New Sheqel1.00", - "Israeli New Sheqels1.00", + "Israeli New Shekel1.00", + "Israeli New Shekels1.00", "New Zealand Dollar1.00", "New Zealand dollar1.00", "New Zealand dollars1.00", "Nicaraguan C\\u00f3rdoba1.00", - "Nicaraguan C\\u00f3rdoba (1988-1991)1.00", + "Nicaraguan C\\u00f3rdoba (1988\\u20131991)1.00", "Nicaraguan c\\u00f3rdoba1.00", "Nicaraguan c\\u00f3rdobas1.00", - "Nicaraguan c\\u00f3rdoba (1988-1991)1.00", - "Nicaraguan c\\u00f3rdobas (1988-1991)1.00", + "Nicaraguan c\\u00f3rdoba (1988\\u20131991)1.00", + "Nicaraguan c\\u00f3rdobas (1988\\u20131991)1.00", "Nigerian Naira1.00", "Nigerian naira1.00", "Nigerian nairas1.00", @@ -4244,23 +4642,23 @@ NumberFormatTest::TestParseCurrencyInUCurr() { "Norwegian krone1.00", "Norwegian kroner1.00", "OMR1.00", - "Mozambican Metical (1980-2006)1.00", - "Mozambican metical (1980-2006)1.00", - "Mozambican meticals (1980-2006)1.00", - "Romanian Lei (1952-2006)1.00", - "Romanian Leu (1952-2006)1.00", - "Romanian leu (1952-2006)1.00", - "Serbian Dinar (2002-2006)1.00", - "Serbian dinar (2002-2006)1.00", - "Serbian dinars (2002-2006)1.00", - "Sudanese Dinar (1992-2007)1.00", - "Sudanese Pound (1957-1998)1.00", - "Sudanese dinar (1992-2007)1.00", - "Sudanese dinars (1992-2007)1.00", - "Sudanese pound (1957-1998)1.00", - "Sudanese pounds (1957-1998)1.00", - "Turkish Lira (1922-2005)1.00", - "Turkish Lira (1922-2005)1.00", + "Mozambican Metical (1980\\u20132006)1.00", + "Mozambican metical (1980\\u20132006)1.00", + "Mozambican meticals (1980\\u20132006)1.00", + "Romanian Lei (1952\\u20132006)1.00", + "Romanian Leu (1952\\u20132006)1.00", + "Romanian leu (1952\\u20132006)1.00", + "Serbian Dinar (2002\\u20132006)1.00", + "Serbian dinar (2002\\u20132006)1.00", + "Serbian dinars (2002\\u20132006)1.00", + "Sudanese Dinar (1992\\u20132007)1.00", + "Sudanese Pound (1957\\u20131998)1.00", + "Sudanese dinar (1992\\u20132007)1.00", + "Sudanese dinars (1992\\u20132007)1.00", + "Sudanese pound (1957\\u20131998)1.00", + "Sudanese pounds (1957\\u20131998)1.00", + "Turkish Lira (1922\\u20132005)1.00", + "Turkish Lira (1922\\u20132005)1.00", "Omani Rial1.00", "Omani rial1.00", "Omani rials1.00", @@ -4297,20 +4695,20 @@ NumberFormatTest::TestParseCurrencyInUCurr() { "Paraguayan guarani1.00", "Paraguayan guaranis1.00", "Peruvian Inti1.00", - "Peruvian Nuevo Sol1.00", - "Peruvian Sol (1863-1965)1.00", + "Peruvian Sol1.00", + "Peruvian Sol (1863\\u20131965)1.00", "Peruvian inti1.00", "Peruvian intis1.00", - "Peruvian nuevo sol1.00", - "Peruvian nuevos soles1.00", - "Peruvian sol (1863-1965)1.00", - "Peruvian soles (1863-1965)1.00", - "Philippine Peso1.00", - "Philippine peso1.00", - "Philippine pesos1.00", + "Peruvian sol1.00", + "Peruvian soles1.00", + "Peruvian sol (1863\\u20131965)1.00", + "Peruvian soles (1863\\u20131965)1.00", + "Philippine Piso1.00", + "Philippine piso1.00", + "Philippine pisos1.00", "Platinum1.00", "Platinum1.00", - "Polish Zloty (1950-1995)1.00", + "Polish Zloty (1950\\u20131995)1.00", "Polish Zloty1.00", "Polish zlotys1.00", "Polish zloty (PLZ)1.00", @@ -4339,7 +4737,6 @@ NumberFormatTest::TestParseCurrencyInUCurr() { "RSD1.00", "RSD1.00", "RUB1.00", - "RUB1.00", "RUR1.00", "RUR1.00", "RWF1.00", @@ -4350,11 +4747,11 @@ NumberFormatTest::TestParseCurrencyInUCurr() { "Romanian Leu1.00", "Romanian lei1.00", "Romanian leu1.00", - "Russian Ruble (1991-1998)1.00", + "Russian Ruble (1991\\u20131998)1.00", "Russian Ruble1.00", - "Russian ruble (1991-1998)1.00", + "Russian ruble (1991\\u20131998)1.00", "Russian ruble1.00", - "Russian rubles (1991-1998)1.00", + "Russian rubles (1991\\u20131998)1.00", "Russian rubles1.00", "Rwandan Franc1.00", "Rwandan franc1.00", @@ -4388,12 +4785,12 @@ NumberFormatTest::TestParseCurrencyInUCurr() { "SVC1.00", "SYP1.00", "SZL1.00", - "Saint Helena Pound1.00", - "Saint Helena pound1.00", - "Saint Helena pounds1.00", - "S\\u00e3o Tom\\u00e9 and Pr\\u00edncipe Dobra1.00", - "S\\u00e3o Tom\\u00e9 and Pr\\u00edncipe dobra1.00", - "S\\u00e3o Tom\\u00e9 and Pr\\u00edncipe dobras1.00", + "St. Helena Pound1.00", + "St. Helena pound1.00", + "St. Helena pounds1.00", + "S\\u00e3o Tom\\u00e9 & Pr\\u00edncipe Dobra1.00", + "S\\u00e3o Tom\\u00e9 & Pr\\u00edncipe dobra1.00", + "S\\u00e3o Tom\\u00e9 & Pr\\u00edncipe dobras1.00", "Saudi Riyal1.00", "Saudi riyal1.00", "Saudi riyals1.00", @@ -4510,9 +4907,9 @@ NumberFormatTest::TestParseCurrencyInUCurr() { "Tongan Pa\\u02bbanga1.00", "Tongan pa\\u02bbanga1.00", "Tongan pa\\u02bbanga1.00", - "Trinidad and Tobago Dollar1.00", - "Trinidad and Tobago dollar1.00", - "Trinidad and Tobago dollars1.00", + "Trinidad & Tobago Dollar1.00", + "Trinidad & Tobago dollar1.00", + "Trinidad & Tobago dollars1.00", "Tunisian Dinar1.00", "Tunisian dinar1.00", "Tunisian dinars1.00", @@ -4551,11 +4948,11 @@ NumberFormatTest::TestParseCurrencyInUCurr() { "UYU1.00", "UZS1.00", "UZS1.00", - "Ugandan Shilling (1966-1987)1.00", + "Ugandan Shilling (1966\\u20131987)1.00", "Ugandan Shilling1.00", - "Ugandan shilling (1966-1987)1.00", + "Ugandan shilling (1966\\u20131987)1.00", "Ugandan shilling1.00", - "Ugandan shillings (1966-1987)1.00", + "Ugandan shillings (1966\\u20131987)1.00", "Ugandan shillings1.00", "Ukrainian Hryvnia1.00", "Ukrainian Karbovanets1.00", @@ -4566,18 +4963,18 @@ NumberFormatTest::TestParseCurrencyInUCurr() { "Colombian Real Value Unit1.00", "United Arab Emirates Dirham1.00", "Unknown Currency1.00", - "Uruguayan Peso (1975-1993)1.00", + "Uruguayan Peso (1975\\u20131993)1.00", "Uruguayan Peso1.00", "Uruguayan Peso (Indexed Units)1.00", - "Uruguayan peso (1975-1993)1.00", + "Uruguayan peso (1975\\u20131993)1.00", "Uruguayan peso (indexed units)1.00", "Uruguayan peso1.00", - "Uruguayan pesos (1975-1993)1.00", + "Uruguayan pesos (1975\\u20131993)1.00", "Uruguayan pesos (indexed units)1.00", "Uruguayan pesos1.00", - "Uzbekistan Som1.00", - "Uzbekistan som1.00", - "Uzbekistan som1.00", + "Uzbekistani Som1.00", + "Uzbekistani som1.00", + "Uzbekistani som1.00", "VEB1.00", "VEF1.00", "VND1.00", @@ -4586,11 +4983,11 @@ NumberFormatTest::TestParseCurrencyInUCurr() { "Vanuatu vatu1.00", "Vanuatu vatus1.00", "Venezuelan Bol\\u00edvar1.00", - "Venezuelan Bol\\u00edvar (1871-2008)1.00", + "Venezuelan Bol\\u00edvar (1871\\u20132008)1.00", "Venezuelan bol\\u00edvar1.00", "Venezuelan bol\\u00edvars1.00", - "Venezuelan bol\\u00edvar (1871-2008)1.00", - "Venezuelan bol\\u00edvars (1871-2008)1.00", + "Venezuelan bol\\u00edvar (1871\\u20132008)1.00", + "Venezuelan bol\\u00edvars (1871\\u20132008)1.00", "Vietnamese Dong1.00", "Vietnamese dong1.00", "Vietnamese dong1.00", @@ -4656,15 +5053,15 @@ NumberFormatTest::TestParseCurrencyInUCurr() { "Yemeni dinars1.00", "Yemeni rial1.00", "Yemeni rials1.00", - "Yugoslavian Convertible Dinar (1990-1992)1.00", - "Yugoslavian Hard Dinar (1966-1990)1.00", - "Yugoslavian New Dinar (1994-2002)1.00", - "Yugoslavian convertible dinar (1990-1992)1.00", - "Yugoslavian convertible dinars (1990-1992)1.00", - "Yugoslavian hard dinar (1966-1990)1.00", - "Yugoslavian hard dinars (1966-1990)1.00", - "Yugoslavian new dinar (1994-2002)1.00", - "Yugoslavian new dinars (1994-2002)1.00", + "Yugoslavian Convertible Dinar (1990\\u20131992)1.00", + "Yugoslavian Hard Dinar (1966\\u20131990)1.00", + "Yugoslavian New Dinar (1994\\u20132002)1.00", + "Yugoslavian convertible dinar (1990\\u20131992)1.00", + "Yugoslavian convertible dinars (1990\\u20131992)1.00", + "Yugoslavian hard dinar (1966\\u20131990)1.00", + "Yugoslavian hard dinars (1966\\u20131990)1.00", + "Yugoslavian new dinar (1994\\u20132002)1.00", + "Yugoslavian new dinars (1994\\u20132002)1.00", "ZAL1.00", "ZAL1.00", "ZAR1.00", @@ -4675,28 +5072,27 @@ NumberFormatTest::TestParseCurrencyInUCurr() { "ZRZ1.00", "ZRZ1.00", "ZWD1.00", - "Zairean New Zaire (1993-1998)1.00", - "Zairean Zaire (1971-1993)1.00", - "Zairean new zaire (1993-1998)1.00", - "Zairean new zaires (1993-1998)1.00", - "Zairean zaire (1971-1993)1.00", - "Zairean zaires (1971-1993)1.00", + "Zairean New Zaire (1993\\u20131998)1.00", + "Zairean Zaire (1971\\u20131993)1.00", + "Zairean new zaire (1993\\u20131998)1.00", + "Zairean new zaires (1993\\u20131998)1.00", + "Zairean zaire (1971\\u20131993)1.00", + "Zairean zaires (1971\\u20131993)1.00", "Zambian Kwacha1.00", "Zambian kwacha1.00", "Zambian kwachas1.00", - "Zimbabwean Dollar (1980-2008)1.00", - "Zimbabwean dollar (1980-2008)1.00", - "Zimbabwean dollars (1980-2008)1.00", + "Zimbabwean Dollar (1980\\u20132008)1.00", + "Zimbabwean dollar (1980\\u20132008)1.00", + "Zimbabwean dollars (1980\\u20132008)1.00", "euro1.00", "euros1.00", - "Turkish lira (1922-2005)1.00", + "Turkish lira (1922\\u20132005)1.00", "special drawing rights1.00", "Colombian real value unit1.00", "Colombian real value units1.00", "unknown currency1.00", "\\u00a31.00", "\\u00a51.00", - "\\u0e3f1.00", "\\u20ab1.00", "\\u20aa1.00", "\\u20ac1.00", @@ -4709,7 +5105,7 @@ NumberFormatTest::TestParseCurrencyInUCurr() { "1.00 US dollars random", "1.00 Afghan Afghani random", "1.00 Afghan Afghani random", - "1.00 Afghan Afghanis (1927-1992) random", + "1.00 Afghan Afghanis (1927\\u20131992) random", "1.00 Afghan Afghanis random", "1.00 Albanian Lek random", "1.00 Albanian lek random", @@ -4720,26 +5116,26 @@ NumberFormatTest::TestParseCurrencyInUCurr() { "1.00 Andorran Peseta random", "1.00 Andorran peseta random", "1.00 Andorran pesetas random", - "1.00 Angolan Kwanza (1977-1990) random", - "1.00 Angolan Readjusted Kwanza (1995-1999) random", + "1.00 Angolan Kwanza (1977\\u20131990) random", + "1.00 Angolan Readjusted Kwanza (1995\\u20131999) random", "1.00 Angolan Kwanza random", - "1.00 Angolan New Kwanza (1990-2000) random", - "1.00 Angolan kwanza (1977-1991) random", - "1.00 Angolan readjusted kwanza (1995-1999) random", + "1.00 Angolan New Kwanza (1990\\u20132000) random", + "1.00 Angolan kwanza (1977\\u20131991) random", + "1.00 Angolan readjusted kwanza (1995\\u20131999) random", "1.00 Angolan kwanza random", - "1.00 Angolan kwanzas (1977-1991) random", - "1.00 Angolan readjusted kwanzas (1995-1999) random", + "1.00 Angolan kwanzas (1977\\u20131991) random", + "1.00 Angolan readjusted kwanzas (1995\\u20131999) random", "1.00 Angolan kwanzas random", - "1.00 Angolan new kwanza (1990-2000) random", - "1.00 Angolan new kwanzas (1990-2000) random", + "1.00 Angolan new kwanza (1990\\u20132000) random", + "1.00 Angolan new kwanzas (1990\\u20132000) random", "1.00 Argentine Austral random", - "1.00 Argentine Peso (1983-1985) random", + "1.00 Argentine Peso (1983\\u20131985) random", "1.00 Argentine Peso random", "1.00 Argentine austral random", "1.00 Argentine australs random", - "1.00 Argentine peso (1983-1985) random", + "1.00 Argentine peso (1983\\u20131985) random", "1.00 Argentine peso random", - "1.00 Argentine pesos (1983-1985) random", + "1.00 Argentine pesos (1983\\u20131985) random", "1.00 Argentine pesos random", "1.00 Armenian Dram random", "1.00 Armenian dram random", @@ -4752,11 +5148,11 @@ NumberFormatTest::TestParseCurrencyInUCurr() { "1.00 Austrian Schilling random", "1.00 Austrian schilling random", "1.00 Austrian schillings random", - "1.00 Azerbaijani Manat (1993-2006) random", + "1.00 Azerbaijani Manat (1993\\u20132006) random", "1.00 Azerbaijani Manat random", - "1.00 Azerbaijani manat (1993-2006) random", + "1.00 Azerbaijani manat (1993\\u20132006) random", "1.00 Azerbaijani manat random", - "1.00 Azerbaijani manats (1993-2006) random", + "1.00 Azerbaijani manats (1993\\u20132006) random", "1.00 Azerbaijani manats random", "1.00 Bahamian Dollar random", "1.00 Bahamian dollar random", @@ -4770,10 +5166,10 @@ NumberFormatTest::TestParseCurrencyInUCurr() { "1.00 Barbadian Dollar random", "1.00 Barbadian dollar random", "1.00 Barbadian dollars random", - "1.00 Belarusian New Ruble (1994-1999) random", + "1.00 Belarusian Ruble (1994\\u20131999) random", "1.00 Belarusian Ruble random", - "1.00 Belarusian new ruble (1994-1999) random", - "1.00 Belarusian new rubles (1994-1999) random", + "1.00 Belarusian ruble (1994\\u20131999) random", + "1.00 Belarusian rubles (1994\\u20131999) random", "1.00 Belarusian ruble random", "1.00 Belarusian rubles random", "1.00 Belgian Franc (convertible) random", @@ -4804,35 +5200,35 @@ NumberFormatTest::TestParseCurrencyInUCurr() { "1.00 Bolivian Boliviano random", "1.00 Bolivian Bolivianos random", "1.00 Bosnia-Herzegovina Convertible Mark random", - "1.00 Bosnia-Herzegovina Dinar (1992-1994) random", + "1.00 Bosnia-Herzegovina Dinar (1992\\u20131994) random", "1.00 Bosnia-Herzegovina convertible mark random", "1.00 Bosnia-Herzegovina convertible marks random", - "1.00 Bosnia-Herzegovina dinar (1992-1994) random", - "1.00 Bosnia-Herzegovina dinars (1992-1994) random", + "1.00 Bosnia-Herzegovina dinar (1992\\u20131994) random", + "1.00 Bosnia-Herzegovina dinars (1992\\u20131994) random", "1.00 Botswanan Pula random", "1.00 Botswanan pula random", "1.00 Botswanan pulas random", - "1.00 Brazilian New Cruzado (1989-1990) random", - "1.00 Brazilian Cruzado (1986-1989) random", - "1.00 Brazilian Cruzeiro (1990-1993) random", - "1.00 Brazilian New Cruzeiro (1967-1986) random", - "1.00 Brazilian Cruzeiro (1993-1994) random", + "1.00 Brazilian New Cruzado (1989\\u20131990) random", + "1.00 Brazilian Cruzado (1986\\u20131989) random", + "1.00 Brazilian Cruzeiro (1990\\u20131993) random", + "1.00 Brazilian New Cruzeiro (1967\\u20131986) random", + "1.00 Brazilian Cruzeiro (1993\\u20131994) random", "1.00 Brazilian Real random", - "1.00 Brazilian new cruzado (1989-1990) random", - "1.00 Brazilian new cruzados (1989-1990) random", - "1.00 Brazilian cruzado (1986-1989) random", - "1.00 Brazilian cruzados (1986-1989) random", - "1.00 Brazilian cruzeiro (1990-1993) random", - "1.00 Brazilian new cruzeiro (1967-1986) random", - "1.00 Brazilian cruzeiro (1993-1994) random", - "1.00 Brazilian cruzeiros (1990-1993) random", - "1.00 Brazilian new cruzeiros (1967-1986) random", - "1.00 Brazilian cruzeiros (1993-1994) random", + "1.00 Brazilian new cruzado (1989\\u20131990) random", + "1.00 Brazilian new cruzados (1989\\u20131990) random", + "1.00 Brazilian cruzado (1986\\u20131989) random", + "1.00 Brazilian cruzados (1986\\u20131989) random", + "1.00 Brazilian cruzeiro (1990\\u20131993) random", + "1.00 Brazilian new cruzeiro (1967\\u20131986) random", + "1.00 Brazilian cruzeiro (1993\\u20131994) random", + "1.00 Brazilian cruzeiros (1990\\u20131993) random", + "1.00 Brazilian new cruzeiros (1967\\u20131986) random", + "1.00 Brazilian cruzeiros (1993\\u20131994) random", "1.00 Brazilian real random", "1.00 Brazilian reals random", - "1.00 British Pound Sterling random", - "1.00 British pound sterling random", - "1.00 British pounds sterling random", + "1.00 British Pound random", + "1.00 British pound random", + "1.00 British pounds random", "1.00 Brunei Dollar random", "1.00 Brunei dollar random", "1.00 Brunei dollars random", @@ -4892,9 +5288,9 @@ NumberFormatTest::TestParseCurrencyInUCurr() { "1.00 Cypriot Pound random", "1.00 Cypriot pound random", "1.00 Cypriot pounds random", - "1.00 Czech Republic Koruna random", - "1.00 Czech Republic koruna random", - "1.00 Czech Republic korunas random", + "1.00 Czech Koruna random", + "1.00 Czech koruna random", + "1.00 Czech korunas random", "1.00 Czechoslovak Hard Koruna random", "1.00 Czechoslovak hard koruna random", "1.00 Czechoslovak hard korunas random", @@ -4981,11 +5377,11 @@ NumberFormatTest::TestParseCurrencyInUCurr() { "1.00 Georgian kupon larits random", "1.00 Georgian lari random", "1.00 Georgian laris random", - "1.00 Ghanaian Cedi (1979-2007) random", + "1.00 Ghanaian Cedi (1979\\u20132007) random", "1.00 Ghanaian Cedi random", - "1.00 Ghanaian cedi (1979-2007) random", + "1.00 Ghanaian cedi (1979\\u20132007) random", "1.00 Ghanaian cedi random", - "1.00 Ghanaian cedis (1979-2007) random", + "1.00 Ghanaian cedis (1979\\u20132007) random", "1.00 Ghanaian cedis random", "1.00 Gibraltar Pound random", "1.00 Gibraltar pound random", @@ -5041,7 +5437,7 @@ NumberFormatTest::TestParseCurrencyInUCurr() { "1.00 Irish pound random", "1.00 Irish pounds random", "1.00 Israeli Pound random", - "1.00 Israeli new sheqel random", + "1.00 Israeli new shekel random", "1.00 Israeli pound random", "1.00 Israeli pounds random", "1.00 Italian Lira random", @@ -5140,12 +5536,12 @@ NumberFormatTest::TestParseCurrencyInUCurr() { "1.00 Mauritian rupee random", "1.00 Mauritian rupees random", "1.00 Mexican Peso random", - "1.00 Mexican Silver Peso (1861-1992) random", + "1.00 Mexican Silver Peso (1861\\u20131992) random", "1.00 Mexican Investment Unit random", "1.00 Mexican peso random", "1.00 Mexican pesos random", - "1.00 Mexican silver peso (1861-1992) random", - "1.00 Mexican silver pesos (1861-1992) random", + "1.00 Mexican silver peso (1861\\u20131992) random", + "1.00 Mexican silver pesos (1861\\u20131992) random", "1.00 Mexican investment unit random", "1.00 Mexican investment units random", "1.00 Moldovan Leu random", @@ -5166,9 +5562,9 @@ NumberFormatTest::TestParseCurrencyInUCurr() { "1.00 Mozambican escudos random", "1.00 Mozambican metical random", "1.00 Mozambican meticals random", - "1.00 Myanma Kyat random", - "1.00 Myanma kyat random", - "1.00 Myanma kyats random", + "1.00 Myanmar Kyat random", + "1.00 Myanmar kyat random", + "1.00 Myanmar kyats random", "1.00 Namibian Dollar random", "1.00 Namibian dollar random", "1.00 Namibian dollars random", @@ -5181,17 +5577,17 @@ NumberFormatTest::TestParseCurrencyInUCurr() { "1.00 Dutch Guilder random", "1.00 Dutch guilder random", "1.00 Dutch guilders random", - "1.00 Israeli New Sheqel random", - "1.00 Israeli new sheqels random", + "1.00 Israeli New Shekel random", + "1.00 Israeli new shekels random", "1.00 New Zealand Dollar random", "1.00 New Zealand dollar random", "1.00 New Zealand dollars random", "1.00 Nicaraguan C\\u00f3rdoba random", - "1.00 Nicaraguan C\\u00f3rdoba (1988-1991) random", + "1.00 Nicaraguan C\\u00f3rdoba (1988\\u20131991) random", "1.00 Nicaraguan c\\u00f3rdoba random", "1.00 Nicaraguan c\\u00f3rdoba random", - "1.00 Nicaraguan c\\u00f3rdoba (1988-1991) random", - "1.00 Nicaraguan c\\u00f3rdobas (1988-1991) random", + "1.00 Nicaraguan c\\u00f3rdoba (1988\\u20131991) random", + "1.00 Nicaraguan c\\u00f3rdobas (1988\\u20131991) random", "1.00 Nigerian Naira random", "1.00 Nigerian naira random", "1.00 Nigerian nairas random", @@ -5201,23 +5597,23 @@ NumberFormatTest::TestParseCurrencyInUCurr() { "1.00 Norwegian Krone random", "1.00 Norwegian krone random", "1.00 Norwegian kroner random", - "1.00 Mozambican Metical (1980-2006) random", - "1.00 Mozambican metical (1980-2006) random", - "1.00 Mozambican meticals (1980-2006) random", - "1.00 Romanian Lei (1952-2006) random", - "1.00 Romanian Leu (1952-2006) random", - "1.00 Romanian leu (1952-2006) random", - "1.00 Serbian Dinar (2002-2006) random", - "1.00 Serbian dinar (2002-2006) random", - "1.00 Serbian dinars (2002-2006) random", - "1.00 Sudanese Dinar (1992-2007) random", - "1.00 Sudanese Pound (1957-1998) random", - "1.00 Sudanese dinar (1992-2007) random", - "1.00 Sudanese dinars (1992-2007) random", - "1.00 Sudanese pound (1957-1998) random", - "1.00 Sudanese pounds (1957-1998) random", - "1.00 Turkish Lira (1922-2005) random", - "1.00 Turkish Lira (1922-2005) random", + "1.00 Mozambican Metical (1980\\u20132006) random", + "1.00 Mozambican metical (1980\\u20132006) random", + "1.00 Mozambican meticals (1980\\u20132006) random", + "1.00 Romanian Lei (1952\\u20132006) random", + "1.00 Romanian Leu (1952\\u20132006) random", + "1.00 Romanian leu (1952\\u20132006) random", + "1.00 Serbian Dinar (2002\\u20132006) random", + "1.00 Serbian dinar (2002\\u20132006) random", + "1.00 Serbian dinars (2002\\u20132006) random", + "1.00 Sudanese Dinar (1992\\u20132007) random", + "1.00 Sudanese Pound (1957\\u20131998) random", + "1.00 Sudanese dinar (1992\\u20132007) random", + "1.00 Sudanese dinars (1992\\u20132007) random", + "1.00 Sudanese pound (1957\\u20131998) random", + "1.00 Sudanese pounds (1957\\u20131998) random", + "1.00 Turkish Lira (1922\\u20132005) random", + "1.00 Turkish Lira (1922\\u20132005) random", "1.00 Omani Rial random", "1.00 Omani rial random", "1.00 Omani rials random", @@ -5236,20 +5632,20 @@ NumberFormatTest::TestParseCurrencyInUCurr() { "1.00 Paraguayan guarani random", "1.00 Paraguayan guaranis random", "1.00 Peruvian Inti random", - "1.00 Peruvian Nuevo Sol random", - "1.00 Peruvian Sol (1863-1965) random", + "1.00 Peruvian Sol random", + "1.00 Peruvian Sol (1863\\u20131965) random", "1.00 Peruvian inti random", "1.00 Peruvian intis random", - "1.00 Peruvian nuevo sol random", - "1.00 Peruvian nuevos soles random", - "1.00 Peruvian sol (1863-1965) random", - "1.00 Peruvian soles (1863-1965) random", - "1.00 Philippine Peso random", - "1.00 Philippine peso random", - "1.00 Philippine pesos random", + "1.00 Peruvian sol random", + "1.00 Peruvian soles random", + "1.00 Peruvian sol (1863\\u20131965) random", + "1.00 Peruvian soles (1863\\u20131965) random", + "1.00 Philippine Piso random", + "1.00 Philippine piso random", + "1.00 Philippine pisos random", "1.00 Platinum random", "1.00 Platinum random", - "1.00 Polish Zloty (1950-1995) random", + "1.00 Polish Zloty (1950\\u20131995) random", "1.00 Polish Zloty random", "1.00 Polish zlotys random", "1.00 Polish zloty (PLZ) random", @@ -5272,21 +5668,21 @@ NumberFormatTest::TestParseCurrencyInUCurr() { "1.00 Romanian Leu random", "1.00 Romanian lei random", "1.00 Romanian leu random", - "1.00 Russian Ruble (1991-1998) random", + "1.00 Russian Ruble (1991\\u20131998) random", "1.00 Russian Ruble random", - "1.00 Russian ruble (1991-1998) random", + "1.00 Russian ruble (1991\\u20131998) random", "1.00 Russian ruble random", - "1.00 Russian rubles (1991-1998) random", + "1.00 Russian rubles (1991\\u20131998) random", "1.00 Russian rubles random", "1.00 Rwandan Franc random", "1.00 Rwandan franc random", "1.00 Rwandan francs random", - "1.00 Saint Helena Pound random", - "1.00 Saint Helena pound random", - "1.00 Saint Helena pounds random", - "1.00 S\\u00e3o Tom\\u00e9 and Pr\\u00edncipe Dobra random", - "1.00 S\\u00e3o Tom\\u00e9 and Pr\\u00edncipe dobra random", - "1.00 S\\u00e3o Tom\\u00e9 and Pr\\u00edncipe dobras random", + "1.00 St. Helena Pound random", + "1.00 St. Helena pound random", + "1.00 St. Helena pounds random", + "1.00 S\\u00e3o Tom\\u00e9 & Pr\\u00edncipe Dobra random", + "1.00 S\\u00e3o Tom\\u00e9 & Pr\\u00edncipe dobra random", + "1.00 S\\u00e3o Tom\\u00e9 & Pr\\u00edncipe dobras random", "1.00 Saudi Riyal random", "1.00 Saudi riyal random", "1.00 Saudi riyals random", @@ -5380,9 +5776,9 @@ NumberFormatTest::TestParseCurrencyInUCurr() { "1.00 Timorese Escudo random", "1.00 Timorese escudo random", "1.00 Timorese escudos random", - "1.00 Trinidad and Tobago Dollar random", - "1.00 Trinidad and Tobago dollar random", - "1.00 Trinidad and Tobago dollars random", + "1.00 Trinidad & Tobago Dollar random", + "1.00 Trinidad & Tobago dollar random", + "1.00 Trinidad & Tobago dollars random", "1.00 Tunisian Dinar random", "1.00 Tunisian dinar random", "1.00 Tunisian dinars random", @@ -5401,11 +5797,11 @@ NumberFormatTest::TestParseCurrencyInUCurr() { "1.00 US dollars (next day) random", "1.00 US dollars (same day) random", "1.00 US dollars random", - "1.00 Ugandan Shilling (1966-1987) random", + "1.00 Ugandan Shilling (1966\\u20131987) random", "1.00 Ugandan Shilling random", - "1.00 Ugandan shilling (1966-1987) random", + "1.00 Ugandan shilling (1966\\u20131987) random", "1.00 Ugandan shilling random", - "1.00 Ugandan shillings (1966-1987) random", + "1.00 Ugandan shillings (1966\\u20131987) random", "1.00 Ugandan shillings random", "1.00 Ukrainian Hryvnia random", "1.00 Ukrainian Karbovanets random", @@ -5416,26 +5812,26 @@ NumberFormatTest::TestParseCurrencyInUCurr() { "1.00 Colombian Real Value Unit random", "1.00 United Arab Emirates Dirham random", "1.00 Unknown Currency random", - "1.00 Uruguayan Peso (1975-1993) random", + "1.00 Uruguayan Peso (1975\\u20131993) random", "1.00 Uruguayan Peso random", "1.00 Uruguayan Peso (Indexed Units) random", - "1.00 Uruguayan peso (1975-1993) random", + "1.00 Uruguayan peso (1975\\u20131993) random", "1.00 Uruguayan peso (indexed units) random", "1.00 Uruguayan peso random", - "1.00 Uruguayan pesos (1975-1993) random", + "1.00 Uruguayan pesos (1975\\u20131993) random", "1.00 Uruguayan pesos (indexed units) random", - "1.00 Uzbekistan Som random", - "1.00 Uzbekistan som random", - "1.00 Uzbekistan som random", + "1.00 Uzbekistani Som random", + "1.00 Uzbekistani som random", + "1.00 Uzbekistani som random", "1.00 Vanuatu Vatu random", "1.00 Vanuatu vatu random", "1.00 Vanuatu vatus random", "1.00 Venezuelan Bol\\u00edvar random", - "1.00 Venezuelan Bol\\u00edvar (1871-2008) random", + "1.00 Venezuelan Bol\\u00edvar (1871\\u20132008) random", "1.00 Venezuelan bol\\u00edvar random", "1.00 Venezuelan bol\\u00edvars random", - "1.00 Venezuelan bol\\u00edvar (1871-2008) random", - "1.00 Venezuelan bol\\u00edvars (1871-2008) random", + "1.00 Venezuelan bol\\u00edvar (1871\\u20132008) random", + "1.00 Venezuelan bol\\u00edvars (1871\\u20132008) random", "1.00 Vietnamese Dong random", "1.00 Vietnamese dong random", "1.00 Vietnamese dong random", @@ -5454,30 +5850,30 @@ NumberFormatTest::TestParseCurrencyInUCurr() { "1.00 Yemeni dinars random", "1.00 Yemeni rial random", "1.00 Yemeni rials random", - "1.00 Yugoslavian Convertible Dinar (1990-1992) random", - "1.00 Yugoslavian Hard Dinar (1966-1990) random", - "1.00 Yugoslavian New Dinar (1994-2002) random", - "1.00 Yugoslavian convertible dinar (1990-1992) random", - "1.00 Yugoslavian convertible dinars (1990-1992) random", - "1.00 Yugoslavian hard dinar (1966-1990) random", - "1.00 Yugoslavian hard dinars (1966-1990) random", - "1.00 Yugoslavian new dinar (1994-2002) random", - "1.00 Yugoslavian new dinars (1994-2002) random", - "1.00 Zairean New Zaire (1993-1998) random", - "1.00 Zairean Zaire (1971-1993) random", - "1.00 Zairean new zaire (1993-1998) random", - "1.00 Zairean new zaires (1993-1998) random", - "1.00 Zairean zaire (1971-1993) random", - "1.00 Zairean zaires (1971-1993) random", + "1.00 Yugoslavian Convertible Dinar (1990\\u20131992) random", + "1.00 Yugoslavian Hard Dinar (1966\\u20131990) random", + "1.00 Yugoslavian New Dinar (1994\\u20132002) random", + "1.00 Yugoslavian convertible dinar (1990\\u20131992) random", + "1.00 Yugoslavian convertible dinars (1990\\u20131992) random", + "1.00 Yugoslavian hard dinar (1966\\u20131990) random", + "1.00 Yugoslavian hard dinars (1966\\u20131990) random", + "1.00 Yugoslavian new dinar (1994\\u20132002) random", + "1.00 Yugoslavian new dinars (1994\\u20132002) random", + "1.00 Zairean New Zaire (1993\\u20131998) random", + "1.00 Zairean Zaire (1971\\u20131993) random", + "1.00 Zairean new zaire (1993\\u20131998) random", + "1.00 Zairean new zaires (1993\\u20131998) random", + "1.00 Zairean zaire (1971\\u20131993) random", + "1.00 Zairean zaires (1971\\u20131993) random", "1.00 Zambian Kwacha random", "1.00 Zambian kwacha random", "1.00 Zambian kwachas random", - "1.00 Zimbabwean Dollar (1980-2008) random", - "1.00 Zimbabwean dollar (1980-2008) random", - "1.00 Zimbabwean dollars (1980-2008) random", + "1.00 Zimbabwean Dollar (1980\\u20132008) random", + "1.00 Zimbabwean dollar (1980\\u20132008) random", + "1.00 Zimbabwean dollars (1980\\u20132008) random", "1.00 euro random", "1.00 euros random", - "1.00 Turkish lira (1922-2005) random", + "1.00 Turkish lira (1922\\u20132005) random", "1.00 special drawing rights random", "1.00 Colombian real value unit random", "1.00 Colombian real value units random", @@ -5522,24 +5918,24 @@ NumberFormatTest::TestParseCurrencyInUCurr() { "AW1.00", "AZ1.00", "Afghan Afghan1.00", - "Afghan Afghani (1927-20021.00", + "Afghan Afghani (1927\\u201320021.00", "Afl1.00", "Albanian Le1.00", "Algerian Dina1.00", "Andorran Peset1.00", "Angolan Kwanz1.00", - "Angolan Kwanza (1977-19901.00", - "Angolan Readjusted Kwanza (1995-19991.00", - "Angolan New Kwanza (1990-20001.00", + "Angolan Kwanza (1977\\u201319901.00", + "Angolan Readjusted Kwanza (1995\\u201319991.00", + "Angolan New Kwanza (1990\\u201320001.00", "Argentine Austra1.00", "Argentine Pes1.00", - "Argentine Peso (1983-19851.00", + "Argentine Peso (1983\\u201319851.00", "Armenian Dra1.00", "Aruban Flori1.00", "Australian Dolla1.00", "Austrian Schillin1.00", "Azerbaijani Mana1.00", - "Azerbaijani Manat (1993-20061.00", + "Azerbaijani Manat (1993\\u201320061.00", "B1.00", "BA1.00", "BB1.00", @@ -5562,7 +5958,7 @@ NumberFormatTest::TestParseCurrencyInUCurr() { "Bangladeshi Tak1.00", "Barbadian Dolla1.00", "Bds1.00", - "Belarusian New Ruble (1994-19991.00", + "Belarusian Ruble (1994\\u201319991.00", "Belarusian Rubl1.00", "Belgian Fran1.00", "Belgian Franc (convertible1.00", @@ -5579,8 +5975,8 @@ NumberFormatTest::TestParseCurrencyInUCurr() { "Brazilian Cruzad1.00", "Brazilian Cruzado Nov1.00", "Brazilian Cruzeir1.00", - "Brazilian Cruzeiro (1990-19931.00", - "Brazilian New Cruzeiro (1967-19861.00", + "Brazilian Cruzeiro (1990\\u201319931.00", + "Brazilian New Cruzeiro (1967\\u201319861.00", "Brazilian Rea1.00", "British Pound Sterlin1.00", "Brunei Dolla1.00", @@ -5591,8 +5987,6 @@ NumberFormatTest::TestParseCurrencyInUCurr() { "C1.00", "CA1.00", "CD1.00", - "CFA Franc BCEA1.00", - "CFA Franc BEA1.00", "CFP Fran1.00", "CFP1.00", "CH1.00", @@ -5689,7 +6083,7 @@ NumberFormatTest::TestParseCurrencyInUCurr() { "Georgian Kupon Lari1.00", "Georgian Lar1.00", "Ghanaian Ced1.00", - "Ghanaian Cedi (1979-20071.00", + "Ghanaian Cedi (1979\\u201320071.00", "Gibraltar Poun1.00", "Gol1.00", "Greek Drachm1.00", @@ -5795,7 +6189,7 @@ NumberFormatTest::TestParseCurrencyInUCurr() { "Mauritanian Ouguiy1.00", "Mauritian Rupe1.00", "Mexican Pes1.00", - "Mexican Silver Peso (1861-19921.00", + "Mexican Silver Peso (1861\\u201319921.00", "Mexican Investment Uni1.00", "Moldovan Le1.00", "Mongolian Tugri1.00", @@ -5803,7 +6197,7 @@ NumberFormatTest::TestParseCurrencyInUCurr() { "Moroccan Fran1.00", "Mozambican Escud1.00", "Mozambican Metica1.00", - "Myanma Kya1.00", + "Myanmar Kya1.00", "N1.00", "NA1.00", "NAf1.00", @@ -5820,7 +6214,7 @@ NumberFormatTest::TestParseCurrencyInUCurr() { "Dutch Guilde1.00", "Israeli New Sheqe1.00", "New Zealand Dolla1.00", - "Nicaraguan C\\u00f3rdoba (1988-19911.00", + "Nicaraguan C\\u00f3rdoba (1988\\u201319911.00", "Nicaraguan C\\u00f3rdob1.00", "Nigerian Nair1.00", "North Korean Wo1.00", @@ -5828,11 +6222,11 @@ NumberFormatTest::TestParseCurrencyInUCurr() { "Nr1.00", "OM1.00", "Old Mozambican Metica1.00", - "Romanian Leu (1952-20061.00", - "Serbian Dinar (2002-20061.00", - "Sudanese Dinar (1992-20071.00", - "Sudanese Pound (1957-19981.00", - "Turkish Lira (1922-20051.00", + "Romanian Leu (1952\\u201320061.00", + "Serbian Dinar (2002\\u201320061.00", + "Sudanese Dinar (1992\\u201320071.00", + "Sudanese Pound (1957\\u201319981.00", + "Turkish Lira (1922\\u201320051.00", "Omani Ria1.00", "PA1.00", "PE1.00", @@ -5848,12 +6242,12 @@ NumberFormatTest::TestParseCurrencyInUCurr() { "Papua New Guinean Kin1.00", "Paraguayan Guaran1.00", "Peruvian Int1.00", - "Peruvian Sol (1863-19651.00", + "Peruvian Sol (1863\\u201319651.00", "Peruvian Sol Nuev1.00", "Philippine Pes1.00", "Platinu1.00", "Polish Zlot1.00", - "Polish Zloty (1950-19951.00", + "Polish Zloty (1950\\u201319951.00", "Portuguese Escud1.00", "Portuguese Guinea Escud1.00", "Pr1.00", @@ -5869,7 +6263,7 @@ NumberFormatTest::TestParseCurrencyInUCurr() { "Rhodesian Dolla1.00", "Romanian Le1.00", "Russian Rubl1.00", - "Russian Ruble (1991-19981.00", + "Russian Ruble (1991\\u201319981.00", "Rwandan Fran1.00", "S1.00", "SA1.00", @@ -5889,8 +6283,8 @@ NumberFormatTest::TestParseCurrencyInUCurr() { "SV1.00", "SY1.00", "SZ1.00", - "Saint Helena Poun1.00", - "S\\u00e3o Tom\\u00e9 and Pr\\u00edncipe Dobr1.00", + "St. Helena Poun1.00", + "S\\u00e3o Tom\\u00e9 & Pr\\u00edncipe Dobr1.00", "Saudi Riya1.00", "Serbian Dina1.00", "Seychellois Rupe1.00", @@ -5937,7 +6331,7 @@ NumberFormatTest::TestParseCurrencyInUCurr() { "Thai Bah1.00", "Timorese Escud1.00", "Tongan Pa\\u20bbang1.00", - "Trinidad and Tobago Dolla1.00", + "Trinidad & Tobago Dolla1.00", "Tunisian Dina1.00", "Turkish Lir1.00", "Turkmenistani Mana1.00", @@ -5952,17 +6346,17 @@ NumberFormatTest::TestParseCurrencyInUCurr() { "UY1.00", "UZ1.00", "Ugandan Shillin1.00", - "Ugandan Shilling (1966-19871.00", + "Ugandan Shilling (1966\\u201319871.00", "Ukrainian Hryvni1.00", "Ukrainian Karbovanet1.00", "Colombian Real Value Uni1.00", "United Arab Emirates Dirha1.00", "Unknown Currenc1.00", "Ur1.00", - "Uruguay Peso (1975-19931.00", + "Uruguay Peso (1975\\u201319931.00", "Uruguay Peso Uruguay1.00", "Uruguay Peso (Indexed Units1.00", - "Uzbekistan So1.00", + "Uzbekistani So1.00", "V1.00", "VE1.00", "VN1.00", @@ -5971,6 +6365,8 @@ NumberFormatTest::TestParseCurrencyInUCurr() { "Venezuelan Bol\\u00edva1.00", "Venezuelan Bol\\u00edvar Fuert1.00", "Vietnamese Don1.00", + "West African CFA Fran1.00", + "Central African CFA Fran1.00", "WIR Eur1.00", "WIR Fran1.00", "WS1.00", @@ -5992,17 +6388,17 @@ NumberFormatTest::TestParseCurrencyInUCurr() { "Yemeni Dina1.00", "Yemeni Ria1.00", "Yugoslavian Convertible Dina1.00", - "Yugoslavian Hard Dinar (1966-19901.00", + "Yugoslavian Hard Dinar (1966\\u201319901.00", "Yugoslavian New Dina1.00", "Z1.00", "ZA1.00", "ZM1.00", "ZR1.00", "ZW1.00", - "Zairean New Zaire (1993-19981.00", + "Zairean New Zaire (1993\\u201319981.00", "Zairean Zair1.00", "Zambian Kwach1.00", - "Zimbabwean Dollar (1980-20081.00", + "Zimbabwean Dollar (1980\\u201320081.00", "dra1.00", "lar1.00", "le1.00", @@ -6011,30 +6407,28 @@ NumberFormatTest::TestParseCurrencyInUCurr() { }; Locale locale("en_US"); - for (uint32_t i=0; i currAmt(numFmt->parseCurrency(formatted, parsePos)); - if (parsePos.getIndex() > 0) { - double doubleVal = currAmt->getNumber().getDouble(status); - if ( doubleVal != 1.0 ) { - errln("Parsed as currency value other than 1.0: " + formatted + " -> " + doubleVal); - } - } else { - errln("Failed to parse as currency: " + formatted); - } - } else { - dataerrln("Unable to create NumberFormat. - %s", u_errorName(status)); - delete numFmt; - break; - } - delete numFmt; + for (uint32_t i=0; i numFmt(NumberFormat::createInstance(locale, UNUM_CURRENCY, status), status); + if (!assertSuccess("", status, true, __FILE__, __LINE__)) { + return; + } + // NOTE: ICU 62 requires that the currency format match the pattern in strict mode. + numFmt->setLenient(TRUE); + ParsePosition parsePos; + LocalPointer currAmt(numFmt->parseCurrency(formatted, parsePos)); + if (parsePos.getIndex() > 0) { + double doubleVal = currAmt->getNumber().getDouble(status); + if ( doubleVal != 1.0 ) { + errln("Parsed as currency value other than 1.0: " + formatted + " -> " + doubleVal); + } + } else { + errln("Failed to parse as currency: " + formatted); + } } - for (uint32_t i=0; iparse(input, result, status); ASSERT_SUCCESS(status); - ASSERT_EQUALS(0, strcmp("0.0184", result.getDecimalNumber(status).data())); + ASSERT_EQUALS("0.0184", result.getDecimalNumber(status).data()); //std::cout << result.getDecimalNumber(status).data(); delete fmtr; } } - + +#if U_PLATFORM != U_PF_CYGWIN || defined(CYGWINMSVC) + /* + * This test fails on Cygwin (1.7.16) using GCC because of a rounding issue with strtod(). + * See #9463 + */ { // Check that a parse returns a decimal number with full accuracy UErrorCode status = U_ZERO_ERROR; @@ -6394,6 +6789,7 @@ void NumberFormatTest::TestDecimal() { delete fmtr; } } +#endif } @@ -6418,42 +6814,42 @@ void NumberFormatTest::TestCurrencyFractionDigits() { errln((UnicodeString)"NumberFormat::format() should return the same result - text1=" + text1 + " text2=" + text2); } - delete fmt; } + delete fmt; } -void NumberFormatTest::TestExponentParse() { - - UErrorCode status = U_ZERO_ERROR; - Formattable result; - ParsePosition parsePos(0); - - // set the exponent symbol - status = U_ZERO_ERROR; - DecimalFormatSymbols *symbols = new DecimalFormatSymbols(Locale::getDefault(), status); - if(U_FAILURE(status)) { - dataerrln((UnicodeString)"ERROR: Could not create DecimalFormatSymbols (Default)"); - return; - } - - // create format instance - status = U_ZERO_ERROR; - DecimalFormat fmt("#####", symbols, status); - if(U_FAILURE(status)) { - errln((UnicodeString)"ERROR: Could not create DecimalFormat (pattern, symbols*)"); - } - - // parse the text - fmt.parse("5.06e-27", result, parsePos); - if(result.getType() != Formattable::kDouble && - result.getDouble() != 5.06E-27 && - parsePos.getIndex() != 8 - ) - { - errln("ERROR: parse failed - expected 5.06E-27, 8 - returned %d, %i", - result.getDouble(), parsePos.getIndex()); - } -} +void NumberFormatTest::TestExponentParse() { + + UErrorCode status = U_ZERO_ERROR; + Formattable result; + ParsePosition parsePos(0); + + // set the exponent symbol + status = U_ZERO_ERROR; + DecimalFormatSymbols symbols(Locale::getDefault(), status); + if(U_FAILURE(status)) { + dataerrln((UnicodeString)"ERROR: Could not create DecimalFormatSymbols (Default)"); + return; + } + + // create format instance + status = U_ZERO_ERROR; + DecimalFormat fmt(u"#####", symbols, status); + if(U_FAILURE(status)) { + errln((UnicodeString)"ERROR: Could not create DecimalFormat (pattern, symbols*)"); + } + + // parse the text + fmt.parse("5.06e-27", result, parsePos); + if(result.getType() != Formattable::kDouble && + result.getDouble() != 5.06E-27 && + parsePos.getIndex() != 8 + ) + { + errln("ERROR: parse failed - expected 5.06E-27, 8 - returned %d, %i", + result.getDouble(), parsePos.getIndex()); + } +} void NumberFormatTest::TestExplicitParents() { @@ -6462,7 +6858,6 @@ void NumberFormatTest::TestExplicitParents() { static const char* parentLocaleTests[][2]= { /* locale ID */ /* expected */ {"es_CO", "1.250,75" }, - {"es_CR", "1.250,75" }, {"es_ES", "1.250,75" }, {"es_GQ", "1.250,75" }, {"es_MX", "1,250.75" }, @@ -6472,7 +6867,7 @@ void NumberFormatTest::TestExplicitParents() { UnicodeString s; - for(int i=0; i < (int)(sizeof(parentLocaleTests)/sizeof(parentLocaleTests[i])); i++){ + for(int i=0; i < UPRV_LENGTHOF(parentLocaleTests); i++){ UErrorCode status = U_ZERO_ERROR; const char *localeID = parentLocaleTests[i][0]; UnicodeString expected(parentLocaleTests[i][1], -1, US_INV); @@ -6508,8 +6903,8 @@ void NumberFormatTest::TestAvailableNumberingSystems() { CHECK_DATA(status, "NumberingSystem::getAvailableNames()") int32_t nsCount = availableNumberingSystems->count(status); - if ( nsCount < 36 ) { - errln("FAIL: Didn't get as many numbering systems as we had hoped for. Need at least 36, got %d",nsCount); + if ( nsCount < 74 ) { + errln("FAIL: Didn't get as many numbering systems as we had hoped for. Need at least 74, got %d",nsCount); } /* A relatively simple test of the API. We call getAvailableNames() and cycle through */ @@ -6521,6 +6916,7 @@ void NumberFormatTest::TestAvailableNumberingSystems() { for ( int32_t i = 0 ; i < nsCount ; i++ ) { const char *nsname = availableNumberingSystems->next(&len,status); NumberingSystem* ns = NumberingSystem::createInstanceByName(nsname,status); + logln("OK for ns = %s",nsname); if ( uprv_strcmp(nsname,ns->getName()) ) { errln("FAIL: Numbering system name didn't match for name = %s\n",nsname); } @@ -6536,13 +6932,13 @@ NumberFormatTest::Test9087(void) { U_STRING_DECL(pattern,"#",1); U_STRING_INIT(pattern,"#",1); - + U_STRING_DECL(infstr,"INF",3); U_STRING_INIT(infstr,"INF",3); U_STRING_DECL(nanstr,"NAN",3); U_STRING_INIT(nanstr,"NAN",3); - + UChar outputbuf[50] = {0}; UErrorCode status = U_ZERO_ERROR; UNumberFormat* fmt = unum_open(UNUM_PATTERN_DECIMAL,pattern,1,NULL,NULL,&status); @@ -6564,11 +6960,2205 @@ NumberFormatTest::Test9087(void) UFieldPosition position = { 0, 0, 0}; unum_formatDouble(fmt,inf,outputbuf,50,&position,&status); - + if ( u_strcmp(infstr, outputbuf)) { errln((UnicodeString)"FAIL: unexpected result for infinity - expected " + infstr + " got " + outputbuf); } unum_close(fmt); } + +void NumberFormatTest::TestFormatFastpaths() { + // get some additional case + { + UErrorCode status=U_ZERO_ERROR; + DecimalFormat df(UnicodeString(u"0000"),status); + if (U_FAILURE(status)) { + dataerrln("Error creating DecimalFormat - %s", u_errorName(status)); + } else { + int64_t long_number = 1; + UnicodeString expect = "0001"; + UnicodeString result; + FieldPosition pos; + df.format(long_number, result, pos); + if(U_FAILURE(status)||expect!=result) { + dataerrln("%s:%d FAIL: expected '%s' got '%s' status %s", + __FILE__, __LINE__, CStr(expect)(), CStr(result)(), u_errorName(status)); + } else { + logln("OK: got expected '"+result+"' status "+UnicodeString(u_errorName(status),"")); + } + } + } + { + UErrorCode status=U_ZERO_ERROR; + DecimalFormat df(UnicodeString(u"0000000000000000000"),status); + if (U_FAILURE(status)) { + dataerrln("Error creating DecimalFormat - %s", u_errorName(status)); + } else { + int64_t long_number = U_INT64_MIN; // -9223372036854775808L; + // uint8_t bits[8]; + // memcpy(bits,&long_number,8); + // for(int i=0;i<8;i++) { + // logln("bits: %02X", (unsigned int)bits[i]); + // } + UnicodeString expect = "-9223372036854775808"; + UnicodeString result; + FieldPosition pos; + df.format(long_number, result, pos); + if(U_FAILURE(status)||expect!=result) { + dataerrln("%s:%d FAIL: expected '%s' got '%s' status %s on -9223372036854775808", + __FILE__, __LINE__, CStr(expect)(), CStr(result)(), u_errorName(status)); + } else { + logln("OK: got expected '"+result+"' status "+UnicodeString(u_errorName(status),"")+" on -9223372036854775808"); + } + } + } + { + UErrorCode status=U_ZERO_ERROR; + DecimalFormat df(UnicodeString(u"0000000000000000000"),status); + if (U_FAILURE(status)) { + dataerrln("Error creating DecimalFormat - %s", u_errorName(status)); + } else { + int64_t long_number = U_INT64_MAX; // -9223372036854775808L; + // uint8_t bits[8]; + // memcpy(bits,&long_number,8); + // for(int i=0;i<8;i++) { + // logln("bits: %02X", (unsigned int)bits[i]); + // } + UnicodeString expect = "9223372036854775807"; + UnicodeString result; + FieldPosition pos; + df.format(long_number, result, pos); + if(U_FAILURE(status)||expect!=result) { + dataerrln("%s:%d FAIL: expected '%s' got '%s' status %s on U_INT64_MAX", + __FILE__, __LINE__, CStr(expect)(), CStr(result)(), u_errorName(status)); + } else { + logln("OK: got expected '"+result+"' status "+UnicodeString(u_errorName(status),"")+" on U_INT64_MAX"); + } + } + } + { + UErrorCode status=U_ZERO_ERROR; + DecimalFormat df(UnicodeString("0000000000000000000",""),status); + if (U_FAILURE(status)) { + dataerrln("Error creating DecimalFormat - %s", u_errorName(status)); + } else { + int64_t long_number = 0; + // uint8_t bits[8]; + // memcpy(bits,&long_number,8); + // for(int i=0;i<8;i++) { + // logln("bits: %02X", (unsigned int)bits[i]); + // } + UnicodeString expect = "0000000000000000000"; + UnicodeString result; + FieldPosition pos; + df.format(long_number, result, pos); + if(U_FAILURE(status)||expect!=result) { + dataerrln("%s:%d FAIL: expected '%s' got '%s' status %s on 0", + __FILE__, __LINE__, CStr(expect)(), CStr(result)(), u_errorName(status)); + } else { + logln("OK: got expected '"+result+"' status "+UnicodeString(u_errorName(status),"")+" on 0"); + } + } + } + { + UErrorCode status=U_ZERO_ERROR; + DecimalFormat df(UnicodeString("0000000000000000000",""),status); + if (U_FAILURE(status)) { + dataerrln("Error creating DecimalFormat - %s", u_errorName(status)); + } else { + int64_t long_number = U_INT64_MIN + 1; + UnicodeString expect = "-9223372036854775807"; + UnicodeString result; + FieldPosition pos; + df.format(long_number, result, pos); + if(U_FAILURE(status)||expect!=result) { + dataerrln("%s:%d FAIL: expected '%s' got '%s' status %s on -9223372036854775807", + __FILE__, __LINE__, CStr(expect)(), CStr(result)(), u_errorName(status)); + } else { + logln("OK: got expected '"+result+"' status "+UnicodeString(u_errorName(status),"")+" on -9223372036854775807"); + } + } + } +} + + +void NumberFormatTest::TestFormattableSize(void) { // test ICU 61 behavior + if(sizeof(FmtStackData) > UNUM_INTERNAL_STACKARRAY_SIZE) { + errln("Error: sizeof(FmtStackData)=%d, UNUM_INTERNAL_STACKARRAY_SIZE=%d\n", + sizeof(FmtStackData), UNUM_INTERNAL_STACKARRAY_SIZE); + } else if(sizeof(FmtStackData) < UNUM_INTERNAL_STACKARRAY_SIZE) { + logln("Warning: sizeof(FmtStackData)=%d, UNUM_INTERNAL_STACKARRAY_SIZE=%d\n", + sizeof(FmtStackData), UNUM_INTERNAL_STACKARRAY_SIZE); + } else { + logln("sizeof(Formattable)=%d, 112=%d\n", + sizeof(Formattable), 112); + } +} + +UBool NumberFormatTest::testFormattableAsUFormattable(const char *file, int line, Formattable &f) { + UnicodeString fileLine = UnicodeString(file)+UnicodeString(":")+line+UnicodeString(": "); + + UFormattable *u = f.toUFormattable(); + logln(); + if (u == NULL) { + errln("%s:%d: Error: f.toUFormattable() retuned NULL."); + return FALSE; + } + logln("%s:%d: comparing Formattable with UFormattable", file, line); + logln(fileLine + toString(f)); + + UErrorCode status = U_ZERO_ERROR; + UErrorCode valueStatus = U_ZERO_ERROR; + UFormattableType expectUType = UFMT_COUNT; // invalid + + UBool triedExact = FALSE; // did we attempt an exact comparison? + UBool exactMatch = FALSE; // was the exact comparison true? + + switch( f.getType() ) { + case Formattable::kDate: + expectUType = UFMT_DATE; + exactMatch = (f.getDate()==ufmt_getDate(u, &valueStatus)); + triedExact = TRUE; + break; + case Formattable::kDouble: + expectUType = UFMT_DOUBLE; + exactMatch = (f.getDouble()==ufmt_getDouble(u, &valueStatus)); + triedExact = TRUE; + break; + case Formattable::kLong: + expectUType = UFMT_LONG; + exactMatch = (f.getLong()==ufmt_getLong(u, &valueStatus)); + triedExact = TRUE; + break; + case Formattable::kString: + expectUType = UFMT_STRING; + { + UnicodeString str; + f.getString(str); + int32_t len; + const UChar* uch = ufmt_getUChars(u, &len, &valueStatus); + if(U_SUCCESS(valueStatus)) { + UnicodeString str2(uch, len); + assertTrue("UChar* NULL-terminated", uch[len]==0); + exactMatch = (str == str2); + } + triedExact = TRUE; + } + break; + case Formattable::kArray: + expectUType = UFMT_ARRAY; + triedExact = TRUE; + { + int32_t count = ufmt_getArrayLength(u, &valueStatus); + int32_t count2; + const Formattable *array2 = f.getArray(count2); + exactMatch = assertEquals(fileLine + " array count", count, count2); + + if(exactMatch) { + for(int i=0;U_SUCCESS(valueStatus) && i numberFormat(static_cast( + NumberFormat::createInstance(locale, status))); + CHECK_DATA(status,"NumberFormat::createInstance") + + numberFormat->setSignificantDigitsUsed(TRUE); + numberFormat->setMinimumSignificantDigits(3); + numberFormat->setMaximumSignificantDigits(5); + numberFormat->setGroupingUsed(false); + + UnicodeString result; + UnicodeString expectedResult; + for (unsigned int i = 0; i < UPRV_LENGTHOF(input); ++i) { + numberFormat->format(input[i], result); + UnicodeString expectedResult(expected[i]); + if (result != expectedResult) { + errln((UnicodeString)"Expected: '" + expectedResult + "' got '" + result); + } + result.remove(); + } +} + +void NumberFormatTest::TestShowZero() { + UErrorCode status = U_ZERO_ERROR; + Locale locale("en_US"); + LocalPointer numberFormat(static_cast( + NumberFormat::createInstance(locale, status))); + CHECK_DATA(status, "NumberFormat::createInstance") + + numberFormat->setSignificantDigitsUsed(TRUE); + numberFormat->setMaximumSignificantDigits(3); + + UnicodeString result; + numberFormat->format(0.0, result); + if (result != "0") { + errln((UnicodeString)"Expected: 0, got " + result); + } +} + +void NumberFormatTest::TestBug9936() { + UErrorCode status = U_ZERO_ERROR; + Locale locale("en_US"); + LocalPointer numberFormat(static_cast( + NumberFormat::createInstance(locale, status))); + if (U_FAILURE(status)) { + dataerrln("File %s, Line %d: status = %s.\n", __FILE__, __LINE__, u_errorName(status)); + return; + } + + if (numberFormat->areSignificantDigitsUsed() == TRUE) { + errln("File %s, Line %d: areSignificantDigitsUsed() was TRUE, expected FALSE.\n", __FILE__, __LINE__); + } + numberFormat->setSignificantDigitsUsed(TRUE); + if (numberFormat->areSignificantDigitsUsed() == FALSE) { + errln("File %s, Line %d: areSignificantDigitsUsed() was FALSE, expected TRUE.\n", __FILE__, __LINE__); + } + + numberFormat->setSignificantDigitsUsed(FALSE); + if (numberFormat->areSignificantDigitsUsed() == TRUE) { + errln("File %s, Line %d: areSignificantDigitsUsed() was TRUE, expected FALSE.\n", __FILE__, __LINE__); + } + + numberFormat->setMinimumSignificantDigits(3); + if (numberFormat->areSignificantDigitsUsed() == FALSE) { + errln("File %s, Line %d: areSignificantDigitsUsed() was FALSE, expected TRUE.\n", __FILE__, __LINE__); + } + + numberFormat->setSignificantDigitsUsed(FALSE); + numberFormat->setMaximumSignificantDigits(6); + if (numberFormat->areSignificantDigitsUsed() == FALSE) { + errln("File %s, Line %d: areSignificantDigitsUsed() was FALSE, expected TRUE.\n", __FILE__, __LINE__); + } + +} + +void NumberFormatTest::TestParseNegativeWithFaLocale() { + UErrorCode status = U_ZERO_ERROR; + DecimalFormat *test = (DecimalFormat *) NumberFormat::createInstance("fa", status); + CHECK_DATA(status, "NumberFormat::createInstance") + test->setLenient(TRUE); + Formattable af; + ParsePosition ppos; + UnicodeString value("\\u200e-0,5"); + value = value.unescape(); + test->parse(value, af, ppos); + if (ppos.getIndex() == 0) { + errln("Expected -0,5 to parse for Farsi."); + } + delete test; +} + +void NumberFormatTest::TestParseNegativeWithAlternateMinusSign() { + UErrorCode status = U_ZERO_ERROR; + DecimalFormat *test = (DecimalFormat *) NumberFormat::createInstance("en", status); + CHECK_DATA(status, "NumberFormat::createInstance") + test->setLenient(TRUE); + Formattable af; + ParsePosition ppos; + UnicodeString value("\\u208B0.5"); + value = value.unescape(); + test->parse(value, af, ppos); + if (ppos.getIndex() == 0) { + errln(UnicodeString("Expected ") + value + UnicodeString(" to parse.")); + } + delete test; +} + +void NumberFormatTest::TestCustomCurrencySignAndSeparator() { + UErrorCode status = U_ZERO_ERROR; + DecimalFormatSymbols custom(Locale::getUS(), status); + CHECK(status, "DecimalFormatSymbols constructor"); + + custom.setSymbol(DecimalFormatSymbols::kCurrencySymbol, "*"); + custom.setSymbol(DecimalFormatSymbols::kMonetaryGroupingSeparatorSymbol, "^"); + custom.setSymbol(DecimalFormatSymbols::kMonetarySeparatorSymbol, ":"); + + UnicodeString pat(" #,##0.00"); + pat.insert(0, (UChar)0x00A4); + + DecimalFormat fmt(pat, custom, status); + CHECK(status, "DecimalFormat constructor"); + + UnicodeString numstr("* 1^234:56"); + expect2(fmt, (Formattable)((double)1234.56), numstr); +} + +typedef struct { + const char * locale; + UBool lenient; + UnicodeString numString; + double value; +} SignsAndMarksItem; + + +void NumberFormatTest::TestParseSignsAndMarks() { + const SignsAndMarksItem items[] = { + // locale lenient numString value + { "en", FALSE, CharsToUnicodeString("12"), 12 }, + { "en", TRUE, CharsToUnicodeString("12"), 12 }, + { "en", FALSE, CharsToUnicodeString("-23"), -23 }, + { "en", TRUE, CharsToUnicodeString("-23"), -23 }, + { "en", TRUE, CharsToUnicodeString("- 23"), -23 }, + { "en", FALSE, CharsToUnicodeString("\\u200E-23"), -23 }, + { "en", TRUE, CharsToUnicodeString("\\u200E-23"), -23 }, + { "en", TRUE, CharsToUnicodeString("\\u200E- 23"), -23 }, + + { "en@numbers=arab", FALSE, CharsToUnicodeString("\\u0663\\u0664"), 34 }, + { "en@numbers=arab", TRUE, CharsToUnicodeString("\\u0663\\u0664"), 34 }, + { "en@numbers=arab", FALSE, CharsToUnicodeString("-\\u0664\\u0665"), -45 }, + { "en@numbers=arab", TRUE, CharsToUnicodeString("-\\u0664\\u0665"), -45 }, + { "en@numbers=arab", TRUE, CharsToUnicodeString("- \\u0664\\u0665"), -45 }, + { "en@numbers=arab", FALSE, CharsToUnicodeString("\\u200F-\\u0664\\u0665"), -45 }, + { "en@numbers=arab", TRUE, CharsToUnicodeString("\\u200F-\\u0664\\u0665"), -45 }, + { "en@numbers=arab", TRUE, CharsToUnicodeString("\\u200F- \\u0664\\u0665"), -45 }, + + { "en@numbers=arabext", FALSE, CharsToUnicodeString("\\u06F5\\u06F6"), 56 }, + { "en@numbers=arabext", TRUE, CharsToUnicodeString("\\u06F5\\u06F6"), 56 }, + { "en@numbers=arabext", FALSE, CharsToUnicodeString("-\\u06F6\\u06F7"), -67 }, + { "en@numbers=arabext", TRUE, CharsToUnicodeString("-\\u06F6\\u06F7"), -67 }, + { "en@numbers=arabext", TRUE, CharsToUnicodeString("- \\u06F6\\u06F7"), -67 }, + { "en@numbers=arabext", FALSE, CharsToUnicodeString("\\u200E-\\u200E\\u06F6\\u06F7"), -67 }, + { "en@numbers=arabext", TRUE, CharsToUnicodeString("\\u200E-\\u200E\\u06F6\\u06F7"), -67 }, + { "en@numbers=arabext", TRUE, CharsToUnicodeString("\\u200E-\\u200E \\u06F6\\u06F7"), -67 }, + + { "he", FALSE, CharsToUnicodeString("12"), 12 }, + { "he", TRUE, CharsToUnicodeString("12"), 12 }, + { "he", FALSE, CharsToUnicodeString("-23"), -23 }, + { "he", TRUE, CharsToUnicodeString("-23"), -23 }, + { "he", TRUE, CharsToUnicodeString("- 23"), -23 }, + { "he", FALSE, CharsToUnicodeString("\\u200E-23"), -23 }, + { "he", TRUE, CharsToUnicodeString("\\u200E-23"), -23 }, + { "he", TRUE, CharsToUnicodeString("\\u200E- 23"), -23 }, + + { "ar", FALSE, CharsToUnicodeString("\\u0663\\u0664"), 34 }, + { "ar", TRUE, CharsToUnicodeString("\\u0663\\u0664"), 34 }, + { "ar", FALSE, CharsToUnicodeString("-\\u0664\\u0665"), -45 }, + { "ar", TRUE, CharsToUnicodeString("-\\u0664\\u0665"), -45 }, + { "ar", TRUE, CharsToUnicodeString("- \\u0664\\u0665"), -45 }, + { "ar", FALSE, CharsToUnicodeString("\\u200F-\\u0664\\u0665"), -45 }, + { "ar", TRUE, CharsToUnicodeString("\\u200F-\\u0664\\u0665"), -45 }, + { "ar", TRUE, CharsToUnicodeString("\\u200F- \\u0664\\u0665"), -45 }, + + { "ar_MA", FALSE, CharsToUnicodeString("12"), 12 }, + { "ar_MA", TRUE, CharsToUnicodeString("12"), 12 }, + { "ar_MA", FALSE, CharsToUnicodeString("-23"), -23 }, + { "ar_MA", TRUE, CharsToUnicodeString("-23"), -23 }, + { "ar_MA", TRUE, CharsToUnicodeString("- 23"), -23 }, + { "ar_MA", FALSE, CharsToUnicodeString("\\u200E-23"), -23 }, + { "ar_MA", TRUE, CharsToUnicodeString("\\u200E-23"), -23 }, + { "ar_MA", TRUE, CharsToUnicodeString("\\u200E- 23"), -23 }, + + { "fa", FALSE, CharsToUnicodeString("\\u06F5\\u06F6"), 56 }, + { "fa", TRUE, CharsToUnicodeString("\\u06F5\\u06F6"), 56 }, + { "fa", FALSE, CharsToUnicodeString("\\u2212\\u06F6\\u06F7"), -67 }, + { "fa", TRUE, CharsToUnicodeString("\\u2212\\u06F6\\u06F7"), -67 }, + { "fa", TRUE, CharsToUnicodeString("\\u2212 \\u06F6\\u06F7"), -67 }, + { "fa", FALSE, CharsToUnicodeString("\\u200E\\u2212\\u200E\\u06F6\\u06F7"), -67 }, + { "fa", TRUE, CharsToUnicodeString("\\u200E\\u2212\\u200E\\u06F6\\u06F7"), -67 }, + { "fa", TRUE, CharsToUnicodeString("\\u200E\\u2212\\u200E \\u06F6\\u06F7"), -67 }, + + { "ps", FALSE, CharsToUnicodeString("\\u06F5\\u06F6"), 56 }, + { "ps", TRUE, CharsToUnicodeString("\\u06F5\\u06F6"), 56 }, + { "ps", FALSE, CharsToUnicodeString("-\\u06F6\\u06F7"), -67 }, + { "ps", TRUE, CharsToUnicodeString("-\\u06F6\\u06F7"), -67 }, + { "ps", TRUE, CharsToUnicodeString("- \\u06F6\\u06F7"), -67 }, + { "ps", FALSE, CharsToUnicodeString("\\u200E-\\u200E\\u06F6\\u06F7"), -67 }, + { "ps", TRUE, CharsToUnicodeString("\\u200E-\\u200E\\u06F6\\u06F7"), -67 }, + { "ps", TRUE, CharsToUnicodeString("\\u200E-\\u200E \\u06F6\\u06F7"), -67 }, + { "ps", FALSE, CharsToUnicodeString("-\\u200E\\u06F6\\u06F7"), -67 }, + { "ps", TRUE, CharsToUnicodeString("-\\u200E\\u06F6\\u06F7"), -67 }, + { "ps", TRUE, CharsToUnicodeString("-\\u200E \\u06F6\\u06F7"), -67 }, + // terminator + { NULL, 0, UnicodeString(""), 0 }, + }; + + const SignsAndMarksItem * itemPtr; + for (itemPtr = items; itemPtr->locale != NULL; itemPtr++ ) { + UErrorCode status = U_ZERO_ERROR; + NumberFormat *numfmt = NumberFormat::createInstance(Locale(itemPtr->locale), status); + if (U_SUCCESS(status)) { + numfmt->setLenient(itemPtr->lenient); + Formattable fmtobj; + ParsePosition ppos; + numfmt->parse(itemPtr->numString, fmtobj, ppos); + if (ppos.getIndex() == itemPtr->numString.length()) { + double parsedValue = fmtobj.getDouble(status); + if (U_FAILURE(status) || parsedValue != itemPtr->value) { + errln((UnicodeString)"FAIL: locale " + itemPtr->locale + ", lenient " + itemPtr->lenient + ", parse of \"" + itemPtr->numString + "\" gives value " + parsedValue); + } + } else { + errln((UnicodeString)"FAIL: locale " + itemPtr->locale + ", lenient " + itemPtr->lenient + ", parse of \"" + itemPtr->numString + "\" gives position " + ppos.getIndex()); + } + } else { + dataerrln("FAIL: NumberFormat::createInstance for locale % gives error %s", itemPtr->locale, u_errorName(status)); + } + delete numfmt; + } +} + +typedef struct { + DecimalFormat::ERoundingMode mode; + double value; + UnicodeString expected; +} Test10419Data; + + +// Tests that rounding works right when fractional digits is set to 0. +void NumberFormatTest::Test10419RoundingWith0FractionDigits() { + const Test10419Data items[] = { + { DecimalFormat::kRoundCeiling, 1.488, "2"}, + { DecimalFormat::kRoundDown, 1.588, "1"}, + { DecimalFormat::kRoundFloor, 1.888, "1"}, + { DecimalFormat::kRoundHalfDown, 1.5, "1"}, + { DecimalFormat::kRoundHalfEven, 2.5, "2"}, + { DecimalFormat::kRoundHalfUp, 2.5, "3"}, + { DecimalFormat::kRoundUp, 1.5, "2"}, + }; + UErrorCode status = U_ZERO_ERROR; + LocalPointer decfmt((DecimalFormat *) NumberFormat::createInstance(Locale("en_US"), status)); + if (U_FAILURE(status)) { + dataerrln("Failure creating DecimalFormat %s", u_errorName(status)); + return; + } + for (int32_t i = 0; i < UPRV_LENGTHOF(items); ++i) { + decfmt->setRoundingMode(items[i].mode); + decfmt->setMaximumFractionDigits(0); + UnicodeString actual; + if (items[i].expected != decfmt->format(items[i].value, actual)) { + errln("Expected " + items[i].expected + ", got " + actual); + } + } +} + +void NumberFormatTest::Test10468ApplyPattern() { + // Padding char of fmt is now 'a' + UErrorCode status = U_ZERO_ERROR; + DecimalFormat fmt("'I''ll'*a###.##", status); + + if (U_FAILURE(status)) { + errcheckln(status, "DecimalFormat constructor failed - %s", u_errorName(status)); + return; + } + + assertEquals("Padding character should be 'a'.", u"a", fmt.getPadCharacterString()); + + // Padding char of fmt ought to be '*' since that is the default and no + // explicit padding char is specified in the new pattern. + fmt.applyPattern("AA#,##0.00ZZ", status); + + // Oops this still prints 'a' even though we changed the pattern. + assertEquals("applyPattern did not clear padding character.", u" ", fmt.getPadCharacterString()); +} + +void NumberFormatTest::TestRoundingScientific10542() { + UErrorCode status = U_ZERO_ERROR; + DecimalFormat format("0.00E0", status); + if (U_FAILURE(status)) { + errcheckln(status, "DecimalFormat constructor failed - %s", u_errorName(status)); + return; + } + + DecimalFormat::ERoundingMode roundingModes[] = { + DecimalFormat::kRoundCeiling, + DecimalFormat::kRoundDown, + DecimalFormat::kRoundFloor, + DecimalFormat::kRoundHalfDown, + DecimalFormat::kRoundHalfEven, + DecimalFormat::kRoundHalfUp, + DecimalFormat::kRoundUp}; + const char *descriptions[] = { + "Round Ceiling", + "Round Down", + "Round Floor", + "Round half down", + "Round half even", + "Round half up", + "Round up"}; + + { + double values[] = {-0.003006, -0.003005, -0.003004, 0.003014, 0.003015, 0.003016}; + // The order of these expected values correspond to the order of roundingModes and the order of values. + const char *expected[] = { + "-3.00E-3", "-3.00E-3", "-3.00E-3", "3.02E-3", "3.02E-3", "3.02E-3", + "-3.00E-3", "-3.00E-3", "-3.00E-3", "3.01E-3", "3.01E-3", "3.01E-3", + "-3.01E-3", "-3.01E-3", "-3.01E-3", "3.01E-3", "3.01E-3", "3.01E-3", + "-3.01E-3", "-3.00E-3", "-3.00E-3", "3.01E-3", "3.01E-3", "3.02E-3", + "-3.01E-3", "-3.00E-3", "-3.00E-3", "3.01E-3", "3.02E-3", "3.02E-3", + "-3.01E-3", "-3.01E-3", "-3.00E-3", "3.01E-3", "3.02E-3", "3.02E-3", + "-3.01E-3", "-3.01E-3", "-3.01E-3", "3.02E-3", "3.02E-3", "3.02E-3"}; + verifyRounding( + format, + values, + expected, + roundingModes, + descriptions, + UPRV_LENGTHOF(values), + UPRV_LENGTHOF(roundingModes)); + } + { + double values[] = {-3006.0, -3005, -3004, 3014, 3015, 3016}; + // The order of these expected values correspond to the order of roundingModes and the order of values. + const char *expected[] = { + "-3.00E3", "-3.00E3", "-3.00E3", "3.02E3", "3.02E3", "3.02E3", + "-3.00E3", "-3.00E3", "-3.00E3", "3.01E3", "3.01E3", "3.01E3", + "-3.01E3", "-3.01E3", "-3.01E3", "3.01E3", "3.01E3", "3.01E3", + "-3.01E3", "-3.00E3", "-3.00E3", "3.01E3", "3.01E3", "3.02E3", + "-3.01E3", "-3.00E3", "-3.00E3", "3.01E3", "3.02E3", "3.02E3", + "-3.01E3", "-3.01E3", "-3.00E3", "3.01E3", "3.02E3", "3.02E3", + "-3.01E3", "-3.01E3", "-3.01E3", "3.02E3", "3.02E3", "3.02E3"}; + verifyRounding( + format, + values, + expected, + roundingModes, + descriptions, + UPRV_LENGTHOF(values), + UPRV_LENGTHOF(roundingModes)); + } +/* Commented out for now until we decide how rounding to zero should work, +0 vs. -0 + { + double values[] = {0.0, -0.0}; + // The order of these expected values correspond to the order of roundingModes and the order of values. + const char *expected[] = { + "0.00E0", "-0.00E0", + "0.00E0", "-0.00E0", + "0.00E0", "-0.00E0", + "0.00E0", "-0.00E0", + "0.00E0", "-0.00E0", + "0.00E0", "-0.00E0", + "0.00E0", "-0.00E0"}; + verifyRounding( + format, + values, + expected, + roundingModes, + descriptions, + UPRV_LENGTHOF(values), + UPRV_LENGTHOF(roundingModes)); + } +*/ + { + + double values[] = {1e25, 1e25 + 1e15, 1e25 - 1e15}; + // The order of these expected values correspond to the order of roundingModes and the order of values. + const char *expected[] = { + "1.00E25", "1.01E25", "1.00E25", + "1.00E25", "1.00E25", "9.99E24", + "1.00E25", "1.00E25", "9.99E24", + "1.00E25", "1.00E25", "1.00E25", + "1.00E25", "1.00E25", "1.00E25", + "1.00E25", "1.00E25", "1.00E25", + "1.00E25", "1.01E25", "1.00E25"}; + verifyRounding( + format, + values, + expected, + roundingModes, + descriptions, + UPRV_LENGTHOF(values), + UPRV_LENGTHOF(roundingModes)); + } + { + double values[] = {-1e25, -1e25 + 1e15, -1e25 - 1e15}; + // The order of these expected values correspond to the order of roundingModes and the order of values. + const char *expected[] = { + "-1.00E25", "-9.99E24", "-1.00E25", + "-1.00E25", "-9.99E24", "-1.00E25", + "-1.00E25", "-1.00E25", "-1.01E25", + "-1.00E25", "-1.00E25", "-1.00E25", + "-1.00E25", "-1.00E25", "-1.00E25", + "-1.00E25", "-1.00E25", "-1.00E25", + "-1.00E25", "-1.00E25", "-1.01E25"}; + verifyRounding( + format, + values, + expected, + roundingModes, + descriptions, + UPRV_LENGTHOF(values), + UPRV_LENGTHOF(roundingModes)); + } + { + double values[] = {1e-25, 1e-25 + 1e-35, 1e-25 - 1e-35}; + // The order of these expected values correspond to the order of roundingModes and the order of values. + const char *expected[] = { + "1.00E-25", "1.01E-25", "1.00E-25", + "1.00E-25", "1.00E-25", "9.99E-26", + "1.00E-25", "1.00E-25", "9.99E-26", + "1.00E-25", "1.00E-25", "1.00E-25", + "1.00E-25", "1.00E-25", "1.00E-25", + "1.00E-25", "1.00E-25", "1.00E-25", + "1.00E-25", "1.01E-25", "1.00E-25"}; + verifyRounding( + format, + values, + expected, + roundingModes, + descriptions, + UPRV_LENGTHOF(values), + UPRV_LENGTHOF(roundingModes)); + } + { + double values[] = {-1e-25, -1e-25 + 1e-35, -1e-25 - 1e-35}; + // The order of these expected values correspond to the order of roundingModes and the order of values. + const char *expected[] = { + "-1.00E-25", "-9.99E-26", "-1.00E-25", + "-1.00E-25", "-9.99E-26", "-1.00E-25", + "-1.00E-25", "-1.00E-25", "-1.01E-25", + "-1.00E-25", "-1.00E-25", "-1.00E-25", + "-1.00E-25", "-1.00E-25", "-1.00E-25", + "-1.00E-25", "-1.00E-25", "-1.00E-25", + "-1.00E-25", "-1.00E-25", "-1.01E-25"}; + verifyRounding( + format, + values, + expected, + roundingModes, + descriptions, + UPRV_LENGTHOF(values), + UPRV_LENGTHOF(roundingModes)); + } +} + +void NumberFormatTest::TestZeroScientific10547() { + UErrorCode status = U_ZERO_ERROR; + DecimalFormat fmt("0.00E0", status); + if (!assertSuccess("Format creation", status)) { + return; + } + UnicodeString out; + fmt.format(-0.0, out); + assertEquals("format", "-0.00E0", out, true); +} + +void NumberFormatTest::verifyRounding( + DecimalFormat& format, + const double *values, + const char * const *expected, + const DecimalFormat::ERoundingMode *roundingModes, + const char * const *descriptions, + int32_t valueSize, + int32_t roundingModeSize) { + for (int32_t i = 0; i < roundingModeSize; ++i) { + format.setRoundingMode(roundingModes[i]); + for (int32_t j = 0; j < valueSize; j++) { + UnicodeString currentExpected(expected[i * valueSize + j]); + currentExpected = currentExpected.unescape(); + UnicodeString actual; + format.format(values[j], actual); + if (currentExpected != actual) { + dataerrln("For %s value %f, expected '%s', got '%s'", + descriptions[i], values[j], CStr(currentExpected)(), CStr(actual)()); + } + } + } +} + +void NumberFormatTest::TestAccountingCurrency() { + UErrorCode status = U_ZERO_ERROR; + UNumberFormatStyle style = UNUM_CURRENCY_ACCOUNTING; + + expect(NumberFormat::createInstance("en_US", style, status), + (Formattable)(double)1234.5, "$1,234.50", TRUE, status); + expect(NumberFormat::createInstance("en_US", style, status), + (Formattable)(double)-1234.5, "($1,234.50)", TRUE, status); + expect(NumberFormat::createInstance("en_US", style, status), + (Formattable)(double)0, "$0.00", TRUE, status); + expect(NumberFormat::createInstance("en_US", style, status), + (Formattable)(double)-0.2, "($0.20)", TRUE, status); + expect(NumberFormat::createInstance("ja_JP", style, status), + (Formattable)10000, UnicodeString("\\u00A510,000").unescape(), TRUE, status); + expect(NumberFormat::createInstance("ja_JP", style, status), + (Formattable)-1000.5, UnicodeString("(\\u00A51,000)").unescape(), FALSE, status); + expect(NumberFormat::createInstance("de_DE", style, status), + (Formattable)(double)-23456.7, UnicodeString("-23.456,70\\u00A0\\u20AC").unescape(), TRUE, status); +} + +// for #5186 +void NumberFormatTest::TestEquality() { + UErrorCode status = U_ZERO_ERROR; + DecimalFormatSymbols symbols(Locale("root"), status); + if (U_FAILURE(status)) { + dataerrln("Fail: can't create DecimalFormatSymbols for root"); + return; + } + UnicodeString pattern("#,##0.###"); + DecimalFormat fmtBase(pattern, symbols, status); + if (U_FAILURE(status)) { + dataerrln("Fail: can't create DecimalFormat using root symbols"); + return; + } + + DecimalFormat* fmtClone = (DecimalFormat*)fmtBase.clone(); + fmtClone->setFormatWidth(fmtBase.getFormatWidth() + 32); + if (*fmtClone == fmtBase) { + errln("Error: DecimalFormat == does not distinguish objects that differ only in FormatWidth"); + } + delete fmtClone; +} + +void NumberFormatTest::TestCurrencyUsage() { + double agent = 123.567; + + UErrorCode status; + DecimalFormat *fmt; + + // compare the Currency and Currency Cash Digits + // Note that as of CLDR 26: + // * TWD switches from 0 decimals to 2; PKR still has 0, so change test to that + // * CAD rounds to .05 in cash mode only + // 1st time for getter/setter, 2nd time for factory method + Locale enUS_PKR("en_US@currency=PKR"); + + for(int i=0; i<2; i++){ + status = U_ZERO_ERROR; + if(i == 0){ + fmt = (DecimalFormat *) NumberFormat::createInstance(enUS_PKR, UNUM_CURRENCY, status); + if (assertSuccess("en_US@currency=PKR/CURRENCY", status, TRUE) == FALSE) { + continue; + } + + UnicodeString original; + fmt->format(agent,original); + assertEquals("Test Currency Usage 1", u"PKR124", original); // use ICU 61 behavior + + // test the getter here + UCurrencyUsage curUsage = fmt->getCurrencyUsage(); + assertEquals("Test usage getter - standard", (int32_t)curUsage, (int32_t)UCURR_USAGE_STANDARD); + + fmt->setCurrencyUsage(UCURR_USAGE_CASH, &status); + }else{ + fmt = (DecimalFormat *) NumberFormat::createInstance(enUS_PKR, UNUM_CASH_CURRENCY, status); + if (assertSuccess("en_US@currency=PKR/CASH", status, TRUE) == FALSE) { + continue; + } + } + + // must be usage = cash + UCurrencyUsage curUsage = fmt->getCurrencyUsage(); + assertEquals("Test usage getter - cash", (int32_t)curUsage, (int32_t)UCURR_USAGE_CASH); + + UnicodeString cash_currency; + fmt->format(agent,cash_currency); + assertEquals("Test Currency Usage 2", u"PKR124", cash_currency); // use ICU 61 behavior + delete fmt; + } + + // compare the Currency and Currency Cash Rounding + // 1st time for getter/setter, 2nd time for factory method + Locale enUS_CAD("en_US@currency=CAD"); + for(int i=0; i<2; i++){ + status = U_ZERO_ERROR; + if(i == 0){ + fmt = (DecimalFormat *) NumberFormat::createInstance(enUS_CAD, UNUM_CURRENCY, status); + if (assertSuccess("en_US@currency=CAD/CURRENCY", status, TRUE) == FALSE) { + continue; + } + + UnicodeString original_rounding; + fmt->format(agent, original_rounding); + assertEquals("Test Currency Usage 3", u"CA$123.57", original_rounding); + fmt->setCurrencyUsage(UCURR_USAGE_CASH, &status); + }else{ + fmt = (DecimalFormat *) NumberFormat::createInstance(enUS_CAD, UNUM_CASH_CURRENCY, status); + if (assertSuccess("en_US@currency=CAD/CASH", status, TRUE) == FALSE) { + continue; + } + } + + UnicodeString cash_rounding_currency; + fmt->format(agent, cash_rounding_currency); + assertEquals("Test Currency Usage 4", u"CA$123.55", cash_rounding_currency); + delete fmt; + } + + // Test the currency change + // 1st time for getter/setter, 2nd time for factory method + const UChar CUR_PKR[] = {0x50, 0x4B, 0x52, 0}; + for(int i=0; i<2; i++){ + status = U_ZERO_ERROR; + if(i == 0){ + fmt = (DecimalFormat *) NumberFormat::createInstance(enUS_CAD, UNUM_CURRENCY, status); + if (assertSuccess("en_US@currency=CAD/CURRENCY", status, TRUE) == FALSE) { + continue; + } + fmt->setCurrencyUsage(UCURR_USAGE_CASH, &status); + }else{ + fmt = (DecimalFormat *) NumberFormat::createInstance(enUS_CAD, UNUM_CASH_CURRENCY, status); + if (assertSuccess("en_US@currency=CAD/CASH", status, TRUE) == FALSE) { + continue; + } + } + + UnicodeString cur_original; + fmt->setCurrencyUsage(UCURR_USAGE_STANDARD, &status); + fmt->format(agent, cur_original); + assertEquals("Test Currency Usage 5", u"CA$123.57", cur_original); + + fmt->setCurrency(CUR_PKR, status); + assertSuccess("Set currency to PKR", status); + + UnicodeString PKR_changed; + fmt->format(agent, PKR_changed); + assertEquals("Test Currency Usage 6", u"PKR124", PKR_changed); // use ICU 61 behavior + delete fmt; + } +} + + +// Check the constant MAX_INT64_IN_DOUBLE. +// The value should convert to a double with no loss of precision. +// A failure may indicate a platform with a different double format, requiring +// a revision to the constant. +// +// Note that this is actually hard to test, because the language standard gives +// compilers considerable flexibility to do unexpected things with rounding and +// with overflow in simple int to/from float conversions. Some compilers will completely optimize +// away a simple round-trip conversion from int64_t -> double -> int64_t. + +void NumberFormatTest::TestDoubleLimit11439() { + char buf[50]; + for (int64_t num = MAX_INT64_IN_DOUBLE-10; num<=MAX_INT64_IN_DOUBLE; num++) { + sprintf(buf, "%lld", (long long)num); + double fNum = 0.0; + sscanf(buf, "%lf", &fNum); + int64_t rtNum = static_cast(fNum); + if (num != rtNum) { + errln("%s:%d MAX_INT64_IN_DOUBLE test, %lld did not round trip. Got %lld", __FILE__, __LINE__, (long long)num, (long long)rtNum); + return; + } + } + for (int64_t num = -MAX_INT64_IN_DOUBLE+10; num>=-MAX_INT64_IN_DOUBLE; num--) { + sprintf(buf, "%lld", (long long)num); + double fNum = 0.0; + sscanf(buf, "%lf", &fNum); + int64_t rtNum = static_cast(fNum); + if (num != rtNum) { + errln("%s:%d MAX_INT64_IN_DOUBLE test, %lld did not round trip. Got %lld", __FILE__, __LINE__, (long long)num, (long long)rtNum); + return; + } + } +} + +void NumberFormatTest::TestGetAffixes() { + UErrorCode status = U_ZERO_ERROR; + DecimalFormatSymbols sym("en_US", status); + UnicodeString pattern("\\u00a4\\u00a4\\u00a4 0.00 %\\u00a4\\u00a4"); + pattern = pattern.unescape(); + DecimalFormat fmt(pattern, sym, status); + if (U_FAILURE(status)) { + dataerrln("Error creating DecimalFormat - %s", u_errorName(status)); + return; + } + UnicodeString affixStr; + assertEquals("", "US dollars ", fmt.getPositivePrefix(affixStr)); + assertEquals("", " %USD", fmt.getPositiveSuffix(affixStr)); + assertEquals("", "-US dollars ", fmt.getNegativePrefix(affixStr)); + assertEquals("", " %USD", fmt.getNegativeSuffix(affixStr)); + + // Test equality with affixes. set affix methods can't capture special + // characters which is why equality should fail. + { + DecimalFormat fmtCopy(fmt); + assertTrue("", fmt == fmtCopy); + UnicodeString someAffix; + fmtCopy.setPositivePrefix(fmtCopy.getPositivePrefix(someAffix)); + assertTrue("", fmt != fmtCopy); + } + { + DecimalFormat fmtCopy(fmt); + assertTrue("", fmt == fmtCopy); + UnicodeString someAffix; + fmtCopy.setPositiveSuffix(fmtCopy.getPositiveSuffix(someAffix)); + assertTrue("", fmt != fmtCopy); + } + { + DecimalFormat fmtCopy(fmt); + assertTrue("", fmt == fmtCopy); + UnicodeString someAffix; + fmtCopy.setNegativePrefix(fmtCopy.getNegativePrefix(someAffix)); + assertTrue("", fmt != fmtCopy); + } + { + DecimalFormat fmtCopy(fmt); + assertTrue("", fmt == fmtCopy); + UnicodeString someAffix; + fmtCopy.setNegativeSuffix(fmtCopy.getNegativeSuffix(someAffix)); + assertTrue("", fmt != fmtCopy); + } + fmt.setPositivePrefix("Don't"); + fmt.setPositiveSuffix("do"); + UnicodeString someAffix("be''eet\\u00a4\\u00a4\\u00a4 it."); + someAffix = someAffix.unescape(); + fmt.setNegativePrefix(someAffix); + fmt.setNegativeSuffix("%"); + assertEquals("", "Don't", fmt.getPositivePrefix(affixStr)); + assertEquals("", "do", fmt.getPositiveSuffix(affixStr)); + assertEquals("", someAffix, fmt.getNegativePrefix(affixStr)); + assertEquals("", "%", fmt.getNegativeSuffix(affixStr)); +} + +void NumberFormatTest::TestToPatternScientific11648() { + UErrorCode status = U_ZERO_ERROR; + Locale en("en"); + DecimalFormatSymbols sym(en, status); + DecimalFormat fmt("0.00", sym, status); + if (U_FAILURE(status)) { + dataerrln("Error creating DecimalFormat - %s", u_errorName(status)); + return; + } + fmt.setScientificNotation(TRUE); + UnicodeString pattern; + assertEquals("", "0.00E0", fmt.toPattern(pattern)); + DecimalFormat fmt2(pattern, sym, status); + assertSuccess("", status); +} + +void NumberFormatTest::TestBenchmark() { +/* + UErrorCode status = U_ZERO_ERROR; + Locale en("en"); + DecimalFormatSymbols sym(en, status); + DecimalFormat fmt("0.0000000", new DecimalFormatSymbols(sym), status); +// DecimalFormat fmt("0.00000E0", new DecimalFormatSymbols(sym), status); +// DecimalFormat fmt("0", new DecimalFormatSymbols(sym), status); + FieldPosition fpos(FieldPosition::DONT_CARE); + clock_t start = clock(); + for (int32_t i = 0; i < 1000000; ++i) { + UnicodeString append; + fmt.format(3.0, append, fpos, status); +// fmt.format(4.6692016, append, fpos, status); +// fmt.format(1234567.8901, append, fpos, status); +// fmt.format(2.99792458E8, append, fpos, status); +// fmt.format(31, append); + } + errln("Took %f", (double) (clock() - start) / CLOCKS_PER_SEC); + assertSuccess("", status); + + UErrorCode status = U_ZERO_ERROR; + MessageFormat fmt("{0, plural, one {I have # friend.} other {I have # friends.}}", status); + FieldPosition fpos(FieldPosition::DONT_CARE); + Formattable one(1.0); + Formattable three(3.0); + clock_t start = clock(); + for (int32_t i = 0; i < 500000; ++i) { + UnicodeString append; + fmt.format(&one, 1, append, fpos, status); + UnicodeString append2; + fmt.format(&three, 1, append2, fpos, status); + } + errln("Took %f", (double) (clock() - start) / CLOCKS_PER_SEC); + assertSuccess("", status); + + UErrorCode status = U_ZERO_ERROR; + Locale en("en"); + Measure measureC(23, MeasureUnit::createCelsius(status), status); + MeasureFormat fmt(en, UMEASFMT_WIDTH_WIDE, status); + FieldPosition fpos(FieldPosition::DONT_CARE); + clock_t start = clock(); + for (int32_t i = 0; i < 1000000; ++i) { + UnicodeString appendTo; + fmt.formatMeasures( + &measureC, 1, appendTo, fpos, status); + } + errln("Took %f", (double) (clock() - start) / CLOCKS_PER_SEC); + assertSuccess("", status); +*/ +} + +void NumberFormatTest::TestFractionalDigitsForCurrency() { + UErrorCode status = U_ZERO_ERROR; + LocalPointer fmt(NumberFormat::createCurrencyInstance("en", status)); + if (U_FAILURE(status)) { + dataerrln("Error creating NumberFormat - %s", u_errorName(status)); + return; + } + UChar JPY[] = {0x4A, 0x50, 0x59, 0x0}; + fmt->setCurrency(JPY, status); + if (!assertSuccess("", status)) { + return; + } + assertEquals("", 0, fmt->getMaximumFractionDigits()); +} + + +void NumberFormatTest::TestFormatCurrencyPlural() { + UErrorCode status = U_ZERO_ERROR; + Locale locale = Locale::createCanonical("en_US"); + NumberFormat *fmt = NumberFormat::createInstance(locale, UNUM_CURRENCY_PLURAL, status); + if (U_FAILURE(status)) { + dataerrln("Error creating NumberFormat - %s", u_errorName(status)); + return; + } + UnicodeString formattedNum; + fmt->format(11234.567, formattedNum, NULL, status); + assertEquals("", "11,234.57 US dollars", formattedNum); + delete fmt; +} + +void NumberFormatTest::TestCtorApplyPatternDifference() { + UErrorCode status = U_ZERO_ERROR; + DecimalFormatSymbols sym("en_US", status); + UnicodeString pattern("\\u00a40"); + DecimalFormat fmt(pattern.unescape(), sym, status); + if (U_FAILURE(status)) { + dataerrln("Error creating DecimalFormat - %s", u_errorName(status)); + return; + } + UnicodeString result; + assertEquals( + "ctor favors precision of currency", + "$5.00", + fmt.format((double)5, result)); + result.remove(); + fmt.applyPattern(pattern.unescape(), status); + assertEquals( + "applyPattern favors precision of pattern", + "$5", + fmt.format((double)5, result)); +} + +void NumberFormatTest::Test11868() { + double posAmt = 34.567; + double negAmt = -9876.543; + + Locale selectedLocale("en_US"); + UErrorCode status = U_ZERO_ERROR; + + UnicodeString result; + FieldPosition fpCurr(UNUM_CURRENCY_FIELD); + LocalPointer fmt( + NumberFormat::createInstance( + selectedLocale, UNUM_CURRENCY_PLURAL, status)); + if (!assertSuccess("Format creation", status)) { + return; + } + fmt->format(posAmt, result, fpCurr, status); + assertEquals("", "34.57 US dollars", result); + assertEquals("begin index", 6, fpCurr.getBeginIndex()); + assertEquals("end index", 16, fpCurr.getEndIndex()); + + // Test field position iterator + { + NumberFormatTest_Attributes attributes[] = { + {UNUM_INTEGER_FIELD, 0, 2}, + {UNUM_DECIMAL_SEPARATOR_FIELD, 2, 3}, + {UNUM_FRACTION_FIELD, 3, 5}, + {UNUM_CURRENCY_FIELD, 6, 16}, + {0, -1, 0}}; + UnicodeString result; + FieldPositionIterator iter; + fmt->format(posAmt, result, &iter, status); + assertEquals("", "34.57 US dollars", result); + verifyFieldPositionIterator(attributes, iter); + } + + result.remove(); + fmt->format(negAmt, result, fpCurr, status); + assertEquals("", "-9,876.54 US dollars", result); + assertEquals("begin index", 10, fpCurr.getBeginIndex()); + assertEquals("end index", 20, fpCurr.getEndIndex()); + + // Test field position iterator + { + NumberFormatTest_Attributes attributes[] = { + {UNUM_SIGN_FIELD, 0, 1}, + {UNUM_GROUPING_SEPARATOR_FIELD, 2, 3}, + {UNUM_INTEGER_FIELD, 1, 6}, + {UNUM_DECIMAL_SEPARATOR_FIELD, 6, 7}, + {UNUM_FRACTION_FIELD, 7, 9}, + {UNUM_CURRENCY_FIELD, 10, 20}, + {0, -1, 0}}; + UnicodeString result; + FieldPositionIterator iter; + fmt->format(negAmt, result, &iter, status); + assertEquals("", "-9,876.54 US dollars", result); + verifyFieldPositionIterator(attributes, iter); + } +} + +void NumberFormatTest::Test10727_RoundingZero() { + IcuTestErrorCode status(*this, "Test10727_RoundingZero"); + DecimalQuantity dq; + dq.setToDouble(-0.0); + assertTrue("", dq.isNegative()); + dq.roundToMagnitude(0, UNUM_ROUND_HALFEVEN, status); + assertTrue("", dq.isNegative()); +} + +void NumberFormatTest::Test11739_ParseLongCurrency() { + IcuTestErrorCode status(*this, "Test11739_ParseLongCurrency"); + LocalPointer nf(NumberFormat::createCurrencyInstance("sr_BA", status)); + if (status.errDataIfFailureAndReset()) { return; } + ((DecimalFormat*) nf.getAlias())->applyPattern(u"#,##0.0 ¤¤¤", status); + ParsePosition ppos(0); + LocalPointer result(nf->parseCurrency(u"1.500 амерички долар", ppos)); + assertEquals("Should parse to 1500 USD", -1, ppos.getErrorIndex()); + assertEquals("Should parse to 1500 USD", 1500LL, result->getNumber().getInt64(status)); + assertEquals("Should parse to 1500 USD", u"USD", result->getISOCurrency()); +} + +void NumberFormatTest::Test13035_MultiCodePointPaddingInPattern() { + IcuTestErrorCode status(*this, "Test13035_MultiCodePointPaddingInPattern"); + DecimalFormat df(u"a*'நி'###0b", status); + if (!assertSuccess("", status, true, __FILE__, __LINE__)) { return; } + UnicodeString result; + df.format(12, result.remove()); + // TODO(13034): Re-enable this test when support is added in ICU4C. + //assertEquals("Multi-codepoint padding should not be split", u"aநிநி12b", result); + df = DecimalFormat(u"a*\U0001F601###0b", status); + if (!assertSuccess("", status, true, __FILE__, __LINE__)) { return; } + result = df.format(12, result.remove()); + assertEquals("Single-codepoint padding should not be split", u"a\U0001F601\U0001F60112b", result, true); + df = DecimalFormat(u"a*''###0b", status); + if (!assertSuccess("", status, true, __FILE__, __LINE__)) { return; } + result = df.format(12, result.remove()); + assertEquals("Quote should be escapable in padding syntax", "a''12b", result, true); +} + +void NumberFormatTest::Test13737_ParseScientificStrict() { + IcuTestErrorCode status(*this, "Test13737_ParseScientificStrict"); + LocalPointer df(NumberFormat::createScientificInstance("en", status), status); + if (!assertSuccess("", status, true, __FILE__, __LINE__)) {return;} + df->setLenient(FALSE); + // Parse Test + expect(*df, u"1.2", 1.2); +} + +void NumberFormatTest::Test11376_getAndSetPositivePrefix() { + { + const UChar USD[] = {0x55, 0x53, 0x44, 0x0}; + UErrorCode status = U_ZERO_ERROR; + LocalPointer fmt( + NumberFormat::createCurrencyInstance("en", status)); + if (!assertSuccess("", status)) { + return; + } + DecimalFormat *dfmt = (DecimalFormat *) fmt.getAlias(); + dfmt->setCurrency(USD); + UnicodeString result; + + // This line should be a no-op. I am setting the positive prefix + // to be the same thing it was before. + dfmt->setPositivePrefix(dfmt->getPositivePrefix(result)); + + UnicodeString appendTo; + assertEquals("", "$3.78", dfmt->format(3.78, appendTo, status)); + assertSuccess("", status); + } + { + const UChar USD[] = {0x55, 0x53, 0x44, 0x0}; + UErrorCode status = U_ZERO_ERROR; + LocalPointer fmt( + NumberFormat::createInstance("en", UNUM_CURRENCY_PLURAL, status)); + if (!assertSuccess("", status)) { + return; + } + DecimalFormat *dfmt = (DecimalFormat *) fmt.getAlias(); + UnicodeString result; + UnicodeString tripleIntlCurrency(" \\u00a4\\u00a4\\u00a4"); + tripleIntlCurrency = tripleIntlCurrency.unescape(); + assertEquals("", tripleIntlCurrency, dfmt->getPositiveSuffix(result)); // use ICU 61 behavior + dfmt->setCurrency(USD); + + // getPositiveSuffix() always returns the suffix for the + // "other" plural category + assertEquals("", " US dollars", dfmt->getPositiveSuffix(result)); + UnicodeString appendTo; + assertEquals("", "3.78 US dollars", dfmt->format(3.78, appendTo, status)); + assertEquals("", " US dollars", dfmt->getPositiveSuffix(result)); + dfmt->setPositiveSuffix("booya"); + appendTo.remove(); + assertEquals("", "3.78booya", dfmt->format(3.78, appendTo, status)); + assertEquals("", "booya", dfmt->getPositiveSuffix(result)); + } +} + +void NumberFormatTest::Test11475_signRecognition() { + UErrorCode status = U_ZERO_ERROR; + DecimalFormatSymbols sym("en", status); + UnicodeString result; + { + DecimalFormat fmt("+0.00", sym, status); + if (!assertSuccess("", status)) { + return; + } + NumberFormatTest_Attributes attributes[] = { + {UNUM_SIGN_FIELD, 0, 1}, + {UNUM_INTEGER_FIELD, 1, 2}, + {UNUM_DECIMAL_SEPARATOR_FIELD, 2, 3}, + {UNUM_FRACTION_FIELD, 3, 5}, + {0, -1, 0}}; + UnicodeString result; + FieldPositionIterator iter; + fmt.format(2.3, result, &iter, status); + assertEquals("", "+2.30", result); + verifyFieldPositionIterator(attributes, iter); + } + { + DecimalFormat fmt("++0.00+;-(#)--", sym, status); + if (!assertSuccess("", status)) { + return; + } + { + NumberFormatTest_Attributes attributes[] = { + {UNUM_SIGN_FIELD, 0, 2}, + {UNUM_INTEGER_FIELD, 2, 3}, + {UNUM_DECIMAL_SEPARATOR_FIELD, 3, 4}, + {UNUM_FRACTION_FIELD, 4, 6}, + {UNUM_SIGN_FIELD, 6, 7}, + {0, -1, 0}}; + UnicodeString result; + FieldPositionIterator iter; + fmt.format(2.3, result, &iter, status); + assertEquals("", "++2.30+", result); + verifyFieldPositionIterator(attributes, iter); + } + { + NumberFormatTest_Attributes attributes[] = { + {UNUM_SIGN_FIELD, 0, 1}, + {UNUM_INTEGER_FIELD, 2, 3}, + {UNUM_DECIMAL_SEPARATOR_FIELD, 3, 4}, + {UNUM_FRACTION_FIELD, 4, 6}, + {UNUM_SIGN_FIELD, 7, 9}, + {0, -1, 0}}; + UnicodeString result; + FieldPositionIterator iter; + fmt.format(-2.3, result, &iter, status); + assertEquals("", "-(2.30)--", result); + verifyFieldPositionIterator(attributes, iter); + } + } +} + +void NumberFormatTest::Test11640_getAffixes() { + UErrorCode status = U_ZERO_ERROR; + DecimalFormatSymbols symbols("en_US", status); + if (!assertSuccess("", status)) { + return; + } + UnicodeString pattern("\\u00a4\\u00a4\\u00a4 0.00 %\\u00a4\\u00a4"); + pattern = pattern.unescape(); + DecimalFormat fmt(pattern, symbols, status); + if (!assertSuccess("", status)) { + return; + } + UnicodeString affixStr; + assertEquals("", "US dollars ", fmt.getPositivePrefix(affixStr)); + assertEquals("", " %USD", fmt.getPositiveSuffix(affixStr)); + assertEquals("", "-US dollars ", fmt.getNegativePrefix(affixStr)); + assertEquals("", " %USD", fmt.getNegativeSuffix(affixStr)); +} + +void NumberFormatTest::Test11649_toPatternWithMultiCurrency() { + UnicodeString pattern("\\u00a4\\u00a4\\u00a4 0.00"); + pattern = pattern.unescape(); + UErrorCode status = U_ZERO_ERROR; + DecimalFormat fmt(pattern, status); + if (!assertSuccess("", status)) { + return; + } + static UChar USD[] = {0x55, 0x53, 0x44, 0x0}; + fmt.setCurrency(USD); + UnicodeString appendTo; + + assertEquals("", "US dollars 12.34", fmt.format(12.34, appendTo)); + + UnicodeString topattern; + fmt.toPattern(topattern); + DecimalFormat fmt2(topattern, status); + if (!assertSuccess("", status)) { + return; + } + fmt2.setCurrency(USD); + + appendTo.remove(); + assertEquals("", "US dollars 12.34", fmt2.format(12.34, appendTo)); +} + +void NumberFormatTest::Test13327_numberingSystemBufferOverflow() { + UErrorCode status = U_ZERO_ERROR; + for (int runId = 0; runId < 2; runId++) { + // Construct a locale string with a very long "numbers" value. + // The first time, make the value length exactly equal to ULOC_KEYWORDS_CAPACITY. + // The second time, make it exceed ULOC_KEYWORDS_CAPACITY. + int extraLength = (runId == 0) ? 0 : 5; + + CharString localeId("en@numbers=", status); + for (int i = 0; i < ULOC_KEYWORDS_CAPACITY + extraLength; i++) { + localeId.append('x', status); + } + assertSuccess("Constructing locale string", status); + Locale locale(localeId.data()); + + LocalPointer ns(NumberingSystem::createInstance(locale, status)); + assertFalse("Should not be null", ns.getAlias() == nullptr); + assertSuccess("Should create with no error", status); + } +} + +void NumberFormatTest::Test13391_chakmaParsing() { + UErrorCode status = U_ZERO_ERROR; + LocalPointer df(dynamic_cast( + NumberFormat::createInstance(Locale("ccp"), status))); + if (df == nullptr) { + dataerrln("%s %d Chakma df is null", __FILE__, __LINE__); + return; + } + const UChar* expected = u"\U00011137\U00011138,\U00011139\U0001113A\U0001113B"; + UnicodeString actual; + df->format(12345, actual, status); + assertSuccess("Should not fail when formatting in ccp", status); + assertEquals("Should produce expected output in ccp", expected, actual); + + Formattable result; + df->parse(expected, result, status); + assertSuccess("Should not fail when parsing in ccp", status); + assertEquals("Should parse to 12345 in ccp", 12345, result); + + const UChar* expectedScientific = u"\U00011137.\U00011139E\U00011138"; + UnicodeString actualScientific; + df.adoptInstead(static_cast( + NumberFormat::createScientificInstance(Locale("ccp"), status))); + df->format(130, actualScientific, status); + assertSuccess("Should not fail when formatting scientific in ccp", status); + assertEquals("Should produce expected scientific output in ccp", + expectedScientific, actualScientific); + + Formattable resultScientific; + df->parse(expectedScientific, resultScientific, status); + assertSuccess("Should not fail when parsing scientific in ccp", status); + assertEquals("Should parse scientific to 130 in ccp", 130, resultScientific); +} + + +void NumberFormatTest::verifyFieldPositionIterator( + NumberFormatTest_Attributes *expected, FieldPositionIterator &iter) { + int32_t idx = 0; + FieldPosition fp; + while (iter.next(fp)) { + if (expected[idx].spos == -1) { + errln("Iterator should have ended. got %d", fp.getField()); + return; + } + assertEquals("id", expected[idx].id, fp.getField()); + assertEquals("start", expected[idx].spos, fp.getBeginIndex()); + assertEquals("end", expected[idx].epos, fp.getEndIndex()); + ++idx; + } + if (expected[idx].spos != -1) { + errln("Premature end of iterator. expected %d", expected[idx].id); + } +} + +void NumberFormatTest::Test11735_ExceptionIssue() { + IcuTestErrorCode status(*this, "Test11735_ExceptionIssue"); + Locale enLocale("en"); + DecimalFormatSymbols symbols(enLocale, status); + if (status.isSuccess()) { + DecimalFormat fmt("0", symbols, status); + assertSuccess("Fail: Construct DecimalFormat formatter", status, true, __FILE__, __LINE__); + ParsePosition ppos(0); + fmt.parseCurrency("53.45", ppos); // NPE thrown here in ICU4J. + assertEquals("Issue11735 ppos", 0, ppos.getIndex()); + } +} + +void NumberFormatTest::Test11035_FormatCurrencyAmount() { + UErrorCode status = U_ZERO_ERROR; + double amount = 12345.67; + const char16_t* expected = u"12,345$67 ​"; + + // Test two ways to set a currency via API + + Locale loc1 = Locale("pt_PT"); + LocalPointer fmt1(NumberFormat::createCurrencyInstance("loc1", status), + status); + if (U_FAILURE(status)) { + dataerrln("%s %d NumberFormat instance fmt1 is null", __FILE__, __LINE__); + return; + } + fmt1->setCurrency(u"PTE", status); + assertSuccess("Setting currency on fmt1", status); + UnicodeString actualSetCurrency; + fmt1->format(amount, actualSetCurrency); + + Locale loc2 = Locale("pt_PT@currency=PTE"); + LocalPointer fmt2(NumberFormat::createCurrencyInstance(loc2, status)); + assertSuccess("Creating fmt2", status); + UnicodeString actualLocaleString; + fmt2->format(amount, actualLocaleString); + + // TODO: The following test will fail until DecimalFormat wraps NumberFormatter. + if (!logKnownIssue("13574")) { + assertEquals("Custom Currency Pattern, Set Currency", expected, actualSetCurrency); + } +} + +void NumberFormatTest::Test11318_DoubleConversion() { + IcuTestErrorCode status(*this, "Test11318_DoubleConversion"); + LocalPointer nf(NumberFormat::createInstance("en", status), status); + if (U_FAILURE(status)) { + dataerrln("%s %d Error in NumberFormat instance creation", __FILE__, __LINE__); + return; + } + nf->setMaximumFractionDigits(40); + nf->setMaximumIntegerDigits(40); + DecimalFormat* df = dynamic_cast(nf.getAlias()); + if (df != NULL) { + UErrorCode status = U_ZERO_ERROR; + df->setAttribute(UNUM_FORMAT_WITH_FULL_PRECISION, TRUE, status); // Apple + } + UnicodeString appendTo; + nf->format(999999999999999.9, appendTo); + assertEquals("Should render all digits", u"999,999,999,999,999.9", appendTo); +} + +void NumberFormatTest::TestParsePercentRegression() { + IcuTestErrorCode status(*this, "TestParsePercentRegression"); + LocalPointer df1((DecimalFormat*) NumberFormat::createInstance("en", status), status); + LocalPointer df2((DecimalFormat*) NumberFormat::createPercentInstance("en", status), status); + if (status.isFailure()) {return; } + df1->setLenient(TRUE); + df2->setLenient(TRUE); + + { + ParsePosition ppos; + Formattable result; + df1->parse("50%", result, ppos); + assertEquals("df1 should accept a number but not the percent sign", 2, ppos.getIndex()); + assertEquals("df1 should return the number as 50", 50.0, result.getDouble(status)); + } + { + ParsePosition ppos; + Formattable result; + df2->parse("50%", result, ppos); + assertEquals("df2 should accept the percent sign", 3, ppos.getIndex()); + assertEquals("df2 should return the number as 0.5", 0.5, result.getDouble(status)); + } + { + ParsePosition ppos; + Formattable result; + df2->parse("50", result, ppos); + assertEquals("df2 should return the number as 0.5 even though the percent sign is missing", + 0.5, + result.getDouble(status)); + } +} + +void NumberFormatTest::TestMultiplierWithScale() { + // to be added +} + +void NumberFormatTest::TestFastFormatInt32() { + IcuTestErrorCode status(*this, "TestFastFormatInt32"); + + // The two simplest formatters, old API and new API. + // Old API should use the fastpath for ints. + LocalizedNumberFormatter lnf = NumberFormatter::withLocale("en"); + LocalPointer df(NumberFormat::createInstance("en", status), status); + if (!assertSuccess("", status, true, __FILE__, __LINE__)) {return;} + + double nums[] = { + 0.0, + -0.0, + NAN, + INFINITY, + 0.1, + 1.0, + 1.1, + 2.0, + 3.0, + 9.0, + 10.0, + 99.0, + 100.0, + 999.0, + 1000.0, + 9999.0, + 10000.0, + 99999.0, + 100000.0, + 999999.0, + 1000000.0, + static_cast(INT32_MAX) - 1, + static_cast(INT32_MAX), + static_cast(INT32_MAX) + 1, + static_cast(INT32_MIN) - 1, + static_cast(INT32_MIN), + static_cast(INT32_MIN) + 1}; + + for (auto num : nums) { + UnicodeString expected = lnf.formatDouble(num, status).toString(); + UnicodeString actual; + df->format(num, actual); + assertEquals(UnicodeString("d = ") + num, expected, actual); + } +} + +void NumberFormatTest::Test11646_Equality() { + UErrorCode status = U_ZERO_ERROR; + DecimalFormatSymbols symbols(Locale::getEnglish(), status); + UnicodeString pattern(u"\u00a4\u00a4\u00a4 0.00 %\u00a4\u00a4"); + DecimalFormat fmt(pattern, symbols, status); + if (!assertSuccess("", status)) return; + + // Test equality with affixes. set affix methods can't capture special + // characters which is why equality should fail. + { + DecimalFormat fmtCopy(fmt); + assertTrue("", fmt == fmtCopy); + UnicodeString positivePrefix; + fmtCopy.setPositivePrefix(fmtCopy.getPositivePrefix(positivePrefix)); + assertFalse("", fmt == fmtCopy); + } + { + DecimalFormat fmtCopy = DecimalFormat(fmt); + assertTrue("", fmt == fmtCopy); + UnicodeString positivePrefix; + fmtCopy.setPositiveSuffix(fmtCopy.getPositiveSuffix(positivePrefix)); + assertFalse("", fmt == fmtCopy); + } + { + DecimalFormat fmtCopy(fmt); + assertTrue("", fmt == fmtCopy); + UnicodeString negativePrefix; + fmtCopy.setNegativePrefix(fmtCopy.getNegativePrefix(negativePrefix)); + assertFalse("", fmt == fmtCopy); + } + { + DecimalFormat fmtCopy(fmt); + assertTrue("", fmt == fmtCopy); + UnicodeString negativePrefix; + fmtCopy.setNegativeSuffix(fmtCopy.getNegativeSuffix(negativePrefix)); + assertFalse("", fmt == fmtCopy); + } +} + +void NumberFormatTest::TestParseNaN() { + IcuTestErrorCode status(*this, "TestParseNaN"); + + DecimalFormat df("0", { "en", status }, status); + if (!assertSuccess("", status, true, __FILE__, __LINE__)) { return; } + Formattable parseResult; + df.parse(u"NaN", parseResult, status); + assertEquals("NaN should parse successfully", NAN, parseResult.getDouble()); + assertFalse("Result NaN should be positive", std::signbit(parseResult.getDouble())); + UnicodeString formatResult; + df.format(parseResult.getDouble(), formatResult); + assertEquals("NaN should round-trip", u"NaN", formatResult); +} + +void NumberFormatTest::Test11897_LocalizedPatternSeparator() { + IcuTestErrorCode status(*this, "Test11897_LocalizedPatternSeparator"); + + // In a locale with a different symbol, like arabic, + // kPatternSeparatorSymbol should still be ';' + { + DecimalFormatSymbols dfs("ar", status); + assertEquals("pattern separator symbol should be ;", + u";", + dfs.getSymbol(DecimalFormatSymbols::kPatternSeparatorSymbol)); + } + + // However, the custom symbol should be used in localized notation + // when set manually via API + { + DecimalFormatSymbols dfs("en", status); + dfs.setSymbol(DecimalFormatSymbols::kPatternSeparatorSymbol, u"!", FALSE); + DecimalFormat df(u"0", dfs, status); + if (!assertSuccess("", status, true, __FILE__, __LINE__)) { return; } + df.applyPattern("a0;b0", status); // should not throw + UnicodeString result; + assertEquals("should apply the normal pattern", + df.getNegativePrefix(result.remove()), + "b"); + df.applyLocalizedPattern(u"c0!d0", status); // should not throw + assertEquals("should apply the localized pattern", + df.getNegativePrefix(result.remove()), + "d"); + } +} + +void NumberFormatTest::Test13055_PercentageRounding() { + IcuTestErrorCode status(*this, "PercentageRounding"); + UnicodeString actual; + LocalPointerpFormat(NumberFormat::createPercentInstance("en_US", status)); + if (U_FAILURE(status)) { + dataerrln("Failure creating DecimalFormat %s", u_errorName(status)); + return; + } + pFormat->setMaximumFractionDigits(0); + pFormat->setRoundingMode(DecimalFormat::kRoundHalfEven); + pFormat->format(2.155, actual); + assertEquals("Should round percent toward even number", "216%", actual); +} + +void NumberFormatTest::Test11839() { + IcuTestErrorCode errorCode(*this, "Test11839"); + // Ticket #11839: DecimalFormat does not respect custom plus sign + LocalPointer dfs(new DecimalFormatSymbols(Locale::getEnglish(), errorCode), errorCode); + if (!assertSuccess("", errorCode, true, __FILE__, __LINE__)) { return; } + dfs->setSymbol(DecimalFormatSymbols::kMinusSignSymbol, u"a∸"); + dfs->setSymbol(DecimalFormatSymbols::kPlusSignSymbol, u"b∔"); // ∔ U+2214 DOT PLUS + DecimalFormat df(u"0.00+;0.00-", dfs.orphan(), errorCode); + UnicodeString result; + df.format(-1.234, result, errorCode); + assertEquals("Locale-specific minus sign should be used", u"1.23a∸", result); + df.format(1.234, result.remove(), errorCode); + assertEquals("Locale-specific plus sign should be used", u"1.23b∔", result); + // Test round-trip with parse + expect2(df, -456, u"456.00a∸"); + expect2(df, 456, u"456.00b∔"); +} + +void NumberFormatTest::Test10354() { + IcuTestErrorCode errorCode(*this, "Test10354"); + // Ticket #10354: invalid FieldPositionIterator when formatting with empty NaN + DecimalFormatSymbols dfs(errorCode); + UnicodeString empty; + dfs.setSymbol(DecimalFormatSymbols::kNaNSymbol, empty); + DecimalFormat df(errorCode); + df.setDecimalFormatSymbols(dfs); + UnicodeString result; + FieldPositionIterator positions; + df.format(NAN, result, &positions, errorCode); + errorCode.errIfFailureAndReset("DecimalFormat.format(NAN, FieldPositionIterator) failed"); + FieldPosition fp; + while (positions.next(fp)) { + // Should not loop forever + } +} + +void NumberFormatTest::Test11645_ApplyPatternEquality() { + IcuTestErrorCode status(*this, "Test11645_ApplyPatternEquality"); + const char16_t* pattern = u"#,##0.0#"; + LocalPointer fmt((DecimalFormat*) NumberFormat::createInstance(status), status); + if (!assertSuccess("", status, true, __FILE__, __LINE__)) { return; } + fmt->applyPattern(pattern, status); + LocalPointer fmtCopy; + + static const int32_t newMultiplier = 37; + fmtCopy.adoptInstead(new DecimalFormat(*fmt)); + assertFalse("Value before setter", fmtCopy->getMultiplier() == newMultiplier); + fmtCopy->setMultiplier(newMultiplier); + assertEquals("Value after setter", fmtCopy->getMultiplier(), newMultiplier); + fmtCopy->applyPattern(pattern, status); + //assertEquals("Value after applyPattern", fmtCopy->getMultiplier(), newMultiplier); + //assertFalse("multiplier", *fmt == *fmtCopy); + + static const NumberFormat::ERoundingMode newRoundingMode = NumberFormat::ERoundingMode::kRoundCeiling; + fmtCopy.adoptInstead(new DecimalFormat(*fmt)); + assertFalse("Value before setter", fmtCopy->getRoundingMode() == newRoundingMode); + fmtCopy->setRoundingMode(newRoundingMode); + assertEquals("Value after setter", fmtCopy->getRoundingMode(), newRoundingMode); + fmtCopy->applyPattern(pattern, status); + assertEquals("Value after applyPattern", fmtCopy->getRoundingMode(), newRoundingMode); + assertFalse("roundingMode", *fmt == *fmtCopy); + + static const char16_t *const newCurrency = u"EAT"; + fmtCopy.adoptInstead(new DecimalFormat(*fmt)); + assertFalse("Value before setter", fmtCopy->getCurrency() == newCurrency); + fmtCopy->setCurrency(newCurrency); + assertEquals("Value after setter", fmtCopy->getCurrency(), newCurrency); + fmtCopy->applyPattern(pattern, status); + assertEquals("Value after applyPattern", fmtCopy->getCurrency(), newCurrency); + assertFalse("currency", *fmt == *fmtCopy); + + static const UCurrencyUsage newCurrencyUsage = UCurrencyUsage::UCURR_USAGE_CASH; + fmtCopy.adoptInstead(new DecimalFormat(*fmt)); + assertFalse("Value before setter", fmtCopy->getCurrencyUsage() == newCurrencyUsage); + fmtCopy->setCurrencyUsage(newCurrencyUsage, status); + assertEquals("Value after setter", fmtCopy->getCurrencyUsage(), newCurrencyUsage); + fmtCopy->applyPattern(pattern, status); + assertEquals("Value after applyPattern", fmtCopy->getCurrencyUsage(), newCurrencyUsage); + assertFalse("currencyUsage", *fmt == *fmtCopy); +} + +void NumberFormatTest::Test12567() { + IcuTestErrorCode errorCode(*this, "Test12567"); + // Ticket #12567: DecimalFormat.equals() may not be symmetric + LocalPointer df1((DecimalFormat *) + NumberFormat::createInstance(Locale::getUS(), UNUM_CURRENCY, errorCode)); + LocalPointer df2((DecimalFormat *) + NumberFormat::createInstance(Locale::getUS(), UNUM_DECIMAL, errorCode)); + if (!assertSuccess("", errorCode, true, __FILE__, __LINE__)) { return; } + // NOTE: CurrencyPluralInfo equality not tested in C++ because its operator== is not defined. + df1->applyPattern(u"0.00", errorCode); + df2->applyPattern(u"0.00", errorCode); + //assertTrue("df1 == df2", *df1 == *df2); + //assertTrue("df2 == df1", *df2 == *df1); + df2->setPositivePrefix(u"abc"); + assertTrue("df1 != df2", *df1 != *df2); + assertTrue("df2 != df1", *df2 != *df1); +} + +void NumberFormatTest::Test11626_CustomizeCurrencyPluralInfo() { + IcuTestErrorCode errorCode(*this, "Test11626_CustomizeCurrencyPluralInfo"); + // Ticket #11626: No unit test demonstrating how to use CurrencyPluralInfo to + // change formatting spelled out currencies + // Use locale sr because it has interesting plural rules. + Locale locale("sr"); + LocalPointer symbols(new DecimalFormatSymbols(locale, errorCode), errorCode); + CurrencyPluralInfo info(locale, errorCode); + if (!assertSuccess("", errorCode, true, __FILE__, __LINE__)) { return; } + info.setCurrencyPluralPattern(u"one", u"0 qwerty", errorCode); + info.setCurrencyPluralPattern(u"few", u"0 dvorak", errorCode); + DecimalFormat df(u"#", symbols.orphan(), UNUM_CURRENCY_PLURAL, errorCode); + df.setCurrencyPluralInfo(info); + df.setCurrency(u"USD"); + df.setMaximumFractionDigits(0); + + UnicodeString result; + //assertEquals("Plural one", u"1 qwerty", df.format(1, result, errorCode)); + //assertEquals("Plural few", u"3 dvorak", df.format(3, result.remove(), errorCode)); + assertEquals("Plural other", u"99 америчких долара", df.format(99, result.remove(), errorCode)); + + info.setPluralRules(u"few: n is 1; one: n in 2..4", errorCode); + df.setCurrencyPluralInfo(info); + //assertEquals("Plural one", u"1 dvorak", df.format(1, result.remove(), errorCode)); + //assertEquals("Plural few", u"3 qwerty", df.format(3, result.remove(), errorCode)); + assertEquals("Plural other", u"99 америчких долара", df.format(99, result.remove(), errorCode)); +} + +void NumberFormatTest::Test13056_GroupingSize() { + UErrorCode status = U_ZERO_ERROR; + DecimalFormat df(u"#,##0", status); + if (!assertSuccess("", status)) return; + assertEquals("Primary grouping should return 3", 3, df.getGroupingSize()); + assertEquals("Secondary grouping should return 0", 0, df.getSecondaryGroupingSize()); + df.setSecondaryGroupingSize(3); + assertEquals("Primary grouping should still return 3", 3, df.getGroupingSize()); + assertEquals("Secondary grouping should round-trip", 3, df.getSecondaryGroupingSize()); + df.setGroupingSize(4); + assertEquals("Primary grouping should return 4", 4, df.getGroupingSize()); + assertEquals("Secondary should remember explicit setting and return 3", 3, df.getSecondaryGroupingSize()); +} + + +void NumberFormatTest::Test11025_CurrencyPadding() { + UErrorCode status = U_ZERO_ERROR; + UnicodeString pattern(u"¤¤ **####0.00"); + DecimalFormatSymbols sym(Locale::getFrance(), status); + if (!assertSuccess("", status)) return; + DecimalFormat fmt(pattern, sym, status); + if (!assertSuccess("", status)) return; + UnicodeString result; + fmt.format(433.0, result); + assertEquals("Number should be padded to 11 characters", "EUR *433,00", result); +} + +void NumberFormatTest::Test11648_ExpDecFormatMalPattern() { + UErrorCode status = U_ZERO_ERROR; + + DecimalFormat fmt("0.00", {"en", status}, status); + if (!assertSuccess("", status, true, __FILE__, __LINE__)) { return; } + fmt.setScientificNotation(TRUE); + UnicodeString pattern; + + assertEquals("A valid scientific notation pattern should be produced", + "0.00E0", + fmt.toPattern(pattern)); + + DecimalFormat fmt2(pattern, status); + assertSuccess("", status); +} + +void NumberFormatTest::Test11649_DecFmtCurrencies() { + IcuTestErrorCode status(*this, "Test11649_DecFmtCurrencies"); + UnicodeString pattern("\\u00a4\\u00a4\\u00a4 0.00"); + pattern = pattern.unescape(); + DecimalFormat fmt(pattern, status); + if (!assertSuccess("", status, true, __FILE__, __LINE__)) { return; } + static const UChar USD[] = u"USD"; + fmt.setCurrency(USD); + UnicodeString appendTo; + + assertEquals("", "US dollars 12.34", fmt.format(12.34, appendTo)); + UnicodeString topattern; + + // assertEquals("", pattern, fmt.toPattern(topattern)); + DecimalFormat fmt2(topattern, status); + fmt2.setCurrency(USD); + + appendTo.remove(); + assertEquals("", "US dollars 12.34", fmt2.format(12.34, appendTo)); +} + +void NumberFormatTest::Test13148_ParseGroupingSeparators() { + IcuTestErrorCode status(*this, "Test13148"); + LocalPointer fmt( + (DecimalFormat*)NumberFormat::createInstance("en-ZA", status), status); + if (!assertSuccess("", status, true, __FILE__, __LINE__)) { return; } + + DecimalFormatSymbols symbols = *fmt->getDecimalFormatSymbols(); + + symbols.setSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol, u'.'); + symbols.setSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol, u','); + fmt->setDecimalFormatSymbols(symbols); + Formattable number; + fmt->parse(u"300,000", number, status); + assertEquals("Should parse as 300000", 300000LL, number.getInt64(status)); +} + +void NumberFormatTest::Test12753_PatternDecimalPoint() { + UErrorCode status = U_ZERO_ERROR; + DecimalFormatSymbols symbols(Locale::getUS(), status); + symbols.setSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol, u"*", false); + DecimalFormat df(u"0.00", symbols, status); + if (!assertSuccess("", status)) return; + df.setDecimalPatternMatchRequired(true); + Formattable result; + df.parse(u"123",result, status); + assertEquals("Parsing integer succeeded even though setDecimalPatternMatchRequired was set", + U_INVALID_FORMAT_ERROR, status); + } + + void NumberFormatTest::Test11647_PatternCurrencySymbols() { + UErrorCode status = U_ZERO_ERROR; + DecimalFormat df(status); + df.applyPattern(u"¤¤¤¤#", status); + if (!assertSuccess("", status)) return; + UnicodeString actual; + df.format(123, actual); + //assertEquals("Should replace 4 currency signs with U+FFFD", u"\uFFFD123", actual); +} + +void NumberFormatTest::Test11913_BigDecimal() { + UErrorCode status = U_ZERO_ERROR; + LocalPointer df(NumberFormat::createInstance(Locale::getEnglish(), status), status); + if (!assertSuccess("", status)) return; + UnicodeString result; + df->format(StringPiece("1.23456789E400"), result, nullptr, status); + assertSuccess("", status); + assertEquals("Should format more than 309 digits", u"12,345,678", UnicodeString(result, 0, 10)); + assertEquals("Should format more than 309 digits", 534, result.length()); +} + +void NumberFormatTest::Test11020_RoundingInScientificNotation() { + UErrorCode status = U_ZERO_ERROR; + DecimalFormatSymbols sym(Locale::getFrance(), status); + DecimalFormat fmt(u"0.05E0", sym, status); + if (!assertSuccess("", status, true, __FILE__, __LINE__)) { return; } + assertSuccess("", status); + UnicodeString result; + fmt.format(12301.2, result); + assertEquals("Rounding increment should be applied after magnitude scaling", u"1,25E4", result); +} + +void NumberFormatTest::Test11640_TripleCurrencySymbol() { + IcuTestErrorCode status(*this, "Test11640_TripleCurrencySymbol"); + UnicodeString actual; + DecimalFormat dFormat(u"¤¤¤ 0", status); + if (U_FAILURE(status)) { + dataerrln("Failure creating DecimalFormat %s", u_errorName(status)); + return; + } + dFormat.setCurrency(u"USD"); + UnicodeString result; + dFormat.getPositivePrefix(result); + assertEquals("Triple-currency should give long name on getPositivePrefix", + "US dollars ", result); +} + + +void NumberFormatTest::Test13763_FieldPositionIteratorOffset() { + IcuTestErrorCode status(*this, "Test13763_FieldPositionIteratorOffset"); + FieldPositionIterator fpi; + UnicodeString result(u"foo\U0001F4FBbar"); // 8 code units + LocalPointer nf(NumberFormat::createInstance("en", status), status); + if (!assertSuccess("", status, true, __FILE__, __LINE__)) { return; } + nf->format(5142.3, result, &fpi, status); + + int32_t expected[] = { + UNUM_GROUPING_SEPARATOR_FIELD, 9, 10, + UNUM_INTEGER_FIELD, 8, 13, + UNUM_DECIMAL_SEPARATOR_FIELD, 13, 14, + UNUM_FRACTION_FIELD, 14, 15, + }; + int32_t tupleCount = UPRV_LENGTHOF(expected)/3; + expectPositions(fpi, expected, tupleCount, result); +} + +void NumberFormatTest::Test13777_ParseLongNameNonCurrencyMode() { + IcuTestErrorCode status(*this, "Test13777_ParseLongNameNonCurrencyMode"); + + LocalPointer df( + NumberFormat::createInstance("en-us", UNumberFormatStyle::UNUM_CURRENCY_PLURAL, status), status); + if (!assertSuccess("", status, true, __FILE__, __LINE__)) { return; } + expect2(*df, 1.5, u"1.50 US dollars"); +} + +void NumberFormatTest::Test13804_EmptyStringsWhenParsing() { + IcuTestErrorCode status(*this, "Test13804_EmptyStringsWhenParsing"); + + DecimalFormatSymbols dfs("en", status); + if (status.errIfFailureAndReset()) { + return; + } + dfs.setSymbol(DecimalFormatSymbols::kCurrencySymbol, u"", FALSE); + dfs.setSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol, u"", FALSE); + dfs.setSymbol(DecimalFormatSymbols::kZeroDigitSymbol, u"", FALSE); + dfs.setSymbol(DecimalFormatSymbols::kOneDigitSymbol, u"", FALSE); + dfs.setSymbol(DecimalFormatSymbols::kTwoDigitSymbol, u"", FALSE); + dfs.setSymbol(DecimalFormatSymbols::kThreeDigitSymbol, u"", FALSE); + dfs.setSymbol(DecimalFormatSymbols::kFourDigitSymbol, u"", FALSE); + dfs.setSymbol(DecimalFormatSymbols::kFiveDigitSymbol, u"", FALSE); + dfs.setSymbol(DecimalFormatSymbols::kSixDigitSymbol, u"", FALSE); + dfs.setSymbol(DecimalFormatSymbols::kSevenDigitSymbol, u"", FALSE); + dfs.setSymbol(DecimalFormatSymbols::kEightDigitSymbol, u"", FALSE); + dfs.setSymbol(DecimalFormatSymbols::kNineDigitSymbol, u"", FALSE); + dfs.setSymbol(DecimalFormatSymbols::kExponentMultiplicationSymbol, u"", FALSE); + dfs.setSymbol(DecimalFormatSymbols::kExponentialSymbol, u"", FALSE); + dfs.setSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol, u"", FALSE); + dfs.setSymbol(DecimalFormatSymbols::kInfinitySymbol, u"", FALSE); + dfs.setSymbol(DecimalFormatSymbols::kIntlCurrencySymbol, u"", FALSE); + dfs.setSymbol(DecimalFormatSymbols::kMinusSignSymbol, u"", FALSE); + dfs.setSymbol(DecimalFormatSymbols::kMonetarySeparatorSymbol, u"", FALSE); + dfs.setSymbol(DecimalFormatSymbols::kMonetaryGroupingSeparatorSymbol, u"", FALSE); + dfs.setSymbol(DecimalFormatSymbols::kNaNSymbol, u"", FALSE); + dfs.setPatternForCurrencySpacing(UNUM_CURRENCY_INSERT, FALSE, u""); + dfs.setPatternForCurrencySpacing(UNUM_CURRENCY_INSERT, TRUE, u""); + dfs.setSymbol(DecimalFormatSymbols::kPercentSymbol, u"", FALSE); + dfs.setSymbol(DecimalFormatSymbols::kPerMillSymbol, u"", FALSE); + dfs.setSymbol(DecimalFormatSymbols::kPlusSignSymbol, u"", FALSE); + + DecimalFormat df("0", dfs, status); + if (status.errIfFailureAndReset()) { + return; + } + df.setGroupingUsed(TRUE); + df.setScientificNotation(TRUE); + df.setLenient(TRUE); // enable all matchers + { + UnicodeString result; + df.format(0, result); // should not crash or hit infinite loop + } + const char16_t* samples[] = { + u"", + u"123", + u"$123", + u"-", + u"+", + u"44%", + u"1E+2.3" + }; + for (auto& sample : samples) { + logln(UnicodeString(u"Attempting parse on: ") + sample); + status.setScope(sample); + // We don't care about the results, only that we don't crash and don't loop. + Formattable result; + ParsePosition ppos(0); + df.parse(sample, result, ppos); + ppos = ParsePosition(0); + LocalPointer curramt(df.parseCurrency(sample, ppos)); + status.errIfFailureAndReset(); + } + + // Test with a nonempty exponent separator symbol to cover more code + dfs.setSymbol(DecimalFormatSymbols::kExponentialSymbol, u"E", FALSE); + df.setDecimalFormatSymbols(dfs); + { + Formattable result; + ParsePosition ppos(0); + df.parse(u"1E+2.3", result, ppos); + } +} + #endif /* #if !UCONFIG_NO_FORMATTING */