+// © 2016 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
/********************************************************************
- * COPYRIGHT:
- * Copyright (c) 1997-2006, International Business Machines Corporation and
+ * COPYRIGHT:
+ * Copyright (c) 1997-2016, International Business Machines Corporation and
* others. All Rights Reserved.
********************************************************************/
/* Modification History:
#if !UCONFIG_NO_FORMATTING
#include "numfmtst.h"
+#include "unicode/currpinf.h"
#include "unicode/dcfmtsym.h"
#include "unicode/decimfmt.h"
+#include "unicode/localpointer.h"
#include "unicode/ucurr.h"
#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 <cmath>
#include <float.h>
#include <string.h>
+#include <stdlib.h>
+#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 */
+// #include "iostream" // for cout
+
+//#define NUMFMTST_DEBUG 1
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)) { errln(UnicodeString("FAIL: ") + str); return; }
+#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(17,TestWhiteSpaceParsing);
- CASE(18,TestComplexCurrency);
- CASE(19,TestRegCurrency);
- CASE(20,TestSymbolsWithBadLocale);
- CASE(21,TestAdoptDecimalFormatSymbols);
-
- CASE(22,TestScientific2);
- CASE(23,TestScientificGrouping);
- CASE(24,TestInt64);
-
- CASE(25,TestPerMill);
- CASE(26,TestIllegalPatterns);
- CASE(27,TestCases);
-
- CASE(28,TestCurrencyNames);
- CASE(29,TestCurrencyAmount);
- CASE(30,TestCurrencyUnit);
- CASE(31,TestCoverage);
- CASE(32,TestJB3832);
- CASE(33,TestHost);
- CASE(34,TestCurrencyFormat);
- 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;
+}
+
// -------------------------------------
// Test API (increase code coverage)
UErrorCode status = U_ZERO_ERROR;
NumberFormat *test = NumberFormat::createInstance("root", status);
if(U_FAILURE(status)) {
- errln("unable to create format object");
+ dataerrln("unable to create format object - %s", u_errorName(status));
}
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;
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<CurrencyAmount> currAmt(test->parseCurrency("",ppos));
+ // old test for (U_FAILURE(status)) was bogus here, method does not set status!
+ if (ppos.getIndex()) {
+ errln("Parsed empty string as currency");
}
- delete test;
+ delete test;
}
}
-class StubNumberForamt :public NumberFormat{
+class StubNumberFormat :public NumberFormat{
public:
- StubNumberForamt(){};
+ StubNumberFormat(){};
virtual UnicodeString& format(double ,UnicodeString& appendTo,FieldPosition& ) const {
return appendTo;
}
UErrorCode& ) const {}
virtual UClassID getDynamicClassID(void) const {
static char classID = 0;
- return (UClassID)&classID;
+ return (UClassID)&classID;
}
virtual Format* clone() const {return NULL;}
};
-void
+void
NumberFormatTest::TestCoverage(void){
- StubNumberForamt stub;
+ StubNumberFormat stub;
UnicodeString agent("agent");
FieldPosition pos;
int64_t num = 4;
};
}
+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)
{
UErrorCode status = U_ZERO_ERROR;
DecimalFormatSymbols sym(Locale::getUS(), status);
- if (U_FAILURE(status)) { errln("FAIL: Could not construct DecimalFormatSymbols"); return; }
+ 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<pat_length; ++i)
{
}
}
-void
+/*
+icu_2_4::DigitList::operator== 0 0 2 icuuc24d.dll digitlst.cpp Doug
+icu_2_4::DigitList::append 0 0 4 icuin24d.dll digitlst.h Doug
+icu_2_4::DigitList::operator!= 0 0 1 icuuc24d.dll digitlst.h Doug
+*/
+/*
+void
NumberFormatTest::TestDigitList(void)
{
// API coverage for DigitList
- /*
- icu_2_4::DigitList::operator== 0 0 2 icuuc24d.dll digitlst.cpp Doug
- icu_2_4::DigitList::append 0 0 4 icuin24d.dll digitlst.h Doug
- icu_2_4::DigitList::operator!= 0 0 1 icuuc24d.dll digitlst.h Doug
- */
DigitList list1;
list1.append('1');
list1.fDecimalAt = 1;
errln("digitlist append, operator== or set failed ");
}
}
+*/
// -------------------------------------
{
UErrorCode status = U_ZERO_ERROR;
DecimalFormatSymbols sym(Locale::getUS(), status);
- if (U_FAILURE(status)) { errln("FAIL: Bad status returned by DecimalFormatSymbols ct"); return; }
+ if (U_FAILURE(status)) { errcheckln(status, "FAIL: Bad status returned by DecimalFormatSymbols ct - %s", u_errorName(status)); return; }
const char* pat[] = { "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);
// The following #if statements allow this test to be built and run on
// platforms that do not have standard IEEE numerics. For example,
#if DBL_MAX_10_EXP > 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
};
#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
#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
a = af.getLong();
else if (af.getType() == Formattable::kDouble) {
a = af.getDouble();
-#if defined(OS390) || defined(OS400)
+#if U_PF_OS390 <= U_PLATFORM && U_PLATFORM <= U_PF_OS400
// S/390 will show a failure like this:
//| -3.141592652999999e-271 -format-> -3.1416E-271
//| -parse-> -3.1416e-271
#endif
}
else {
- errln((UnicodeString)"FAIL: Non-numeric Formattable returned");
+ errln(UnicodeString("FAIL: Non-numeric Formattable returned: ") + pattern + " " + s);
continue;
}
if (pos.getIndex() == s.length())
(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 {
{
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);
delete fmt;
}
-void
+void
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");
}
}
-static void setFromString(DigitList& dl, const char* str) {
+/*static void setFromString(DigitList& dl, const char* str) {
char c;
UBool decimalSet = FALSE;
dl.clear();
if (!decimalSet) {
dl.fDecimalAt = dl.fCount;
}
-}
+}*/
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");
}
// also test digitlist
- int64_t int64max = U_INT64_MAX;
+/* int64_t int64max = U_INT64_MAX;
int64_t int64min = U_INT64_MIN;
const char* int64maxstr = "9223372036854775807";
const char* int64minstr = "-9223372036854775808";
if (dl.fitsIntoInt64(FALSE)) {
errln(fail + "-(" + int64minstr + ") didn't fit");
}
- }
+ }*/
}
// -------------------------------------
UErrorCode status = U_ZERO_ERROR;
UnicodeString *pat;
DecimalFormatSymbols *sym = new DecimalFormatSymbols(Locale::getUS(), status);
+ if (U_FAILURE(status)) {
+ errcheckln(status, "Fail to create DecimalFormatSymbols - %s", u_errorName(status));
+ delete sym;
+ return;
+ }
pat = new UnicodeString("a'fo''o'b#");
DecimalFormat *fmt = new DecimalFormat(*pat, *sym, status);
- UnicodeString s;
+ UnicodeString s;
((NumberFormat*)fmt)->format((int32_t)123, s);
logln((UnicodeString)"Pattern \"" + *pat + "\"");
logln((UnicodeString)" Format 123 -> " + escape(s));
- if (!(s=="afo'ob123"))
+ if (!(s=="afo'ob123"))
errln((UnicodeString)"FAIL: Expected afo'ob123");
-
+
s.truncate(0);
delete fmt;
delete pat;
((NumberFormat*)fmt)->format((int32_t)123, s);
logln((UnicodeString)"Pattern \"" + *pat + "\"");
logln((UnicodeString)" Format 123 -> " + escape(s));
- if (!(s=="a'b123"))
+ if (!(s=="a'b123"))
errln((UnicodeString)"FAIL: Expected a'b123");
delete fmt;
delete pat;
DecimalFormatSymbols* sym = new DecimalFormatSymbols(Locale::getUS(), status);
UnicodeString pat;
UChar currency = 0x00A4;
+ if (U_FAILURE(status)) {
+ errcheckln(status, "Fail to create DecimalFormatSymbols - %s", u_errorName(status));
+ delete sym;
+ return;
+ }
// "\xA4#,##0.00;-\xA4#,##0.00"
pat.append(currency).append("#,##0.00;-").
append(currency).append("#,##0.00");
pat.truncate(0);
logln((UnicodeString)"Pattern \"" + fmt->toPattern(pat) + "\"");
logln((UnicodeString)" Format " + 1234.56 + " -> " + escape(s));
- if (s != "$1,234.56") errln((UnicodeString)"FAIL: Expected $1,234.56");
+ if (s != "$1,234.56") dataerrln((UnicodeString)"FAIL: Expected $1,234.56");
s.truncate(0);
((NumberFormat*)fmt)->format(- 1234.56, s);
logln((UnicodeString)" Format " + (-1234.56) + " -> " + escape(s));
- if (s != "-$1,234.56") errln((UnicodeString)"FAIL: Expected -$1,234.56");
+ if (s != "-$1,234.56") dataerrln((UnicodeString)"FAIL: Expected -$1,234.56");
delete fmt;
pat.truncate(0);
// "\xA4\xA4 #,##0.00;\xA4\xA4 -#,##0.00"
((NumberFormat*)fmt)->format(1234.56, s);
logln((UnicodeString)"Pattern \"" + fmt->toPattern(pat) + "\"");
logln((UnicodeString)" Format " + 1234.56 + " -> " + escape(s));
- if (s != "USD 1,234.56") errln((UnicodeString)"FAIL: Expected USD 1,234.56");
+ if (s != "USD 1,234.56") dataerrln((UnicodeString)"FAIL: Expected USD 1,234.56");
s.truncate(0);
((NumberFormat*)fmt)->format(-1234.56, s);
logln((UnicodeString)" Format " + (-1234.56) + " -> " + escape(s));
- if (s != "USD -1,234.56") errln((UnicodeString)"FAIL: Expected USD -1,234.56");
+ if (s != "USD -1,234.56") dataerrln((UnicodeString)"FAIL: Expected USD -1,234.56");
delete fmt;
delete sym;
- if (U_FAILURE(status)) errln((UnicodeString)"FAIL: Status " + (int32_t)status);
+ if (U_FAILURE(status)) errln((UnicodeString)"FAIL: Status " + u_errorName(status));
}
-
+
// -------------------------------------
static UChar toHexString(int32_t i) { return (UChar)(i + (i < 10 ? 0x30 : (0x41 - 10))); }
return (s = buf);
}
-
+
// -------------------------------------
static const char* testCases[][2]= {
/* locale ID */ /* expected */
- {"ca_ES_PREEURO", "\\u20A7 1.150" },
- {"de_LU_PREEURO", "1,150 F" },
- {"el_GR_PREEURO", "1.150,50 \\u0394\\u03C1\\u03C7" },
- {"en_BE_PREEURO", "1.150,50 BF" },
- {"es_ES_PREEURO", "1.150 \\u20A7" },
- {"eu_ES_PREEURO", "\\u20A7 1.150" },
- {"gl_ES_PREEURO", "\\u20A7 1.150" },
- {"it_IT_PREEURO", "\\u20A4 1.150" },
- {"pt_PT_PREEURO", "1,150$50 Esc."},
- {"en_US@currency=JPY", "\\u00A51,150"}
+ {"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", "\\u20A7\\u00A01.150" },
+ {"gl_ES_PREEURO", "1.150\\u00A0\\u20A7" },
+ {"it_IT_PREEURO", "ITL\\u00A01.150" },
+ {"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"}
};
/**
* Test localized currency patterns.
UnicodeString s; currencyFmt->format(1.50, s);
logln((UnicodeString)"Un pauvre ici a..........." + s);
- if (!(s=="1,50 $"))
- errln((UnicodeString)"FAIL: Expected 1,50 $");
+ if (!(s==CharsToUnicodeString("1,50\\u00A0$")))
+ errln((UnicodeString)"FAIL: Expected 1,50<nbsp>$ 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=="1,50 DM"))
- errln((UnicodeString)"FAIL: Expected 1,50 DM");
+ if (!(s==CharsToUnicodeString("1,50\\u00A0DM")))
+ errln((UnicodeString)"FAIL: Expected 1,50<nbsp>DM but got " + s);
delete currencyFmt;
s.truncate(0);
len = uloc_canonicalize("fr_FR_PREEURO", loc, 256, &status);
currencyFmt = NumberFormat::createCurrencyInstance(Locale(loc), status);
currencyFmt->format(1.50, s);
logln((UnicodeString)"Un pauvre en France a....." + s);
- if (!(s=="1,50 F"))
- errln((UnicodeString)"FAIL: Expected 1,50 F");
+ if (!(s==CharsToUnicodeString("1,50\\u00A0F")))
+ errln((UnicodeString)"FAIL: Expected 1,50<nbsp>F");
delete currencyFmt;
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]);
+ UnicodeString expected(testCases[i][1], -1, US_INV);
expected = expected.unescape();
s.truncate(0);
char loc[256]={0};
}
currencyFmt->format(1150.50, s);
if(s!=expected){
- errln(UnicodeString("FAIL: Expected: ")+expected
- + UnicodeString(" Got: ") + s
+ errln(UnicodeString("FAIL: Expected: ")+expected
+ + UnicodeString(" Got: ") + s
+ UnicodeString( " for locale: ")+ UnicodeString(localeID) );
}
if (U_FAILURE(status)){
delete currencyFmt;
}
}
-
+
// -------------------------------------
/**
*/
void NumberFormatTest::TestCurrencyObject() {
UErrorCode ec = U_ZERO_ERROR;
- NumberFormat* fmt =
+ NumberFormat* fmt =
NumberFormat::createCurrencyInstance(Locale::getUS(), ec);
if (U_FAILURE(ec)) {
- errln("FAIL: getCurrencyInstance(US)");
+ dataerrln("FAIL: getCurrencyInstance(US) - %s", u_errorName(ec));
delete fmt;
return;
}
Locale null("", "", "");
-
+
expectCurrency(*fmt, null, 1234.56, "$1,234.56");
expectCurrency(*fmt, Locale::getFrance(),
1234.56, CharsToUnicodeString("\\u00A51,235")); // Yen
expectCurrency(*fmt, Locale("fr", "CH", ""),
- 1234.56, "SwF1,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");
delete fmt;
return;
}
-
+
expectCurrency(*fmt, null, 1234.56, CharsToUnicodeString("1 234,56 \\u20AC"));
expectCurrency(*fmt, Locale::getJapan(),
- 1234.56, CharsToUnicodeString("1 235 \\u00A5")); // Yen
+ 1234.56, CharsToUnicodeString("1 235 JPY")); // Yen
expectCurrency(*fmt, Locale("fr", "CH", ""),
- 1234.56, "1 234,55 sFr."); // 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 $");
+ 1234.56, "1 234,56 $US");
expectCurrency(*fmt, Locale::getFrance(),
1234.56, CharsToUnicodeString("1 234,56 \\u20AC")); // Euro
delete fmt;
}
-
+
// -------------------------------------
/**
if (n.getType() != Formattable::kLong ||
n.getLong() != 0) errln((UnicodeString)"FAIL: Expected 0");
delete format;
- if (U_FAILURE(status)) errln((UnicodeString)"FAIL: Status " + (int32_t)status);
+ if (U_FAILURE(status)) errcheckln(status, (UnicodeString)"FAIL: Status " + u_errorName(status));
//}
//catch(Exception e) {
// errln((UnicodeString)"Exception caught: " + e);
//}
}
-
+
+// -------------------------------------
+
+static const char *lenientAffixTestCases[] = {
+ "(1)",
+ "( 1)",
+ "(1 )",
+ "( 1 )"
+};
+
+static const char *lenientMinusTestCases[] = {
+ "-5",
+ "\\u22125",
+ "\\u27965"
+};
+
+static const char *lenientCurrencyTestCases[] = {
+ "$1,000",
+ "$ 1,000",
+ "$1000",
+ "$ 1000",
+ "$1 000.00",
+ "$ 1 000.00",
+ "$ 1\\u00A0000.00",
+ "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"
+};
+
+static const char *lenientPercentTestCases[] = {
+ "25%",
+ " 25%",
+ " 25 %",
+ "25 %",
+ "25\\u00A0%",
+ "25"
+};
+
+static const char *lenientNegativePercentTestCases[] = {
+ "-25%",
+ " -25%",
+ " - 25%",
+ "- 25 %",
+ " - 25 %",
+ "-25 %",
+ "-25\\u00A0%",
+ "-25",
+ "- 25"
+};
+
+static const char *strictFailureTestCases[] = {
+ " 1000",
+ "10,00",
+ "1,000,.0"
+};
+
+/**
+ * Test lenient parsing.
+ */
+void
+NumberFormatTest::TestLenientParse(void)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ DecimalFormat *format = new DecimalFormat("(#,##0)", status);
+ Formattable n;
+
+ if (format == NULL || U_FAILURE(status)) {
+ dataerrln("Unable to create DecimalFormat (#,##0) - %s", u_errorName(status));
+ } else {
+ format->setLenient(TRUE);
+ for (int32_t t = 0; t < UPRV_LENGTHOF (lenientAffixTestCases); t += 1) {
+ UnicodeString testCase = ctou(lenientAffixTestCases[t]);
+
+ format->parse(testCase, n, status);
+ logln((UnicodeString)"parse(" + testCase + ") = " + n.getLong());
+
+ if (U_FAILURE(status) || n.getType() != Formattable::kLong ||
+ n.getLong() != 1) {
+ dataerrln((UnicodeString)"Lenient parse failed for \"" + (UnicodeString) lenientAffixTestCases[t]
+ + (UnicodeString) "\"; error code = " + u_errorName(status));
+ status = U_ZERO_ERROR;
+ }
+ }
+ delete format;
+ }
+
+ 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 < 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) "\"; 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 < 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) "\"; 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 < UPRV_LENGTHOF (lenientCurrencyTestCases); t += 1) {
+ UnicodeString testCase = ctou(lenientCurrencyTestCases[t]);
+
+ cFormat->parse(testCase, n, status);
+ logln((UnicodeString)"parse(" + testCase + ") = " + n.getLong());
+
+ if (U_FAILURE(status) ||n.getType() != Formattable::kLong ||
+ n.getLong() != 1000) {
+ errln((UnicodeString)"Lenient parse failed for \"" + (UnicodeString) lenientCurrencyTestCases[t]
+ + (UnicodeString) "\"; error code = " + u_errorName(status));
+ status = U_ZERO_ERROR;
+ }
+ }
+
+ for (int32_t t = 0; t < UPRV_LENGTHOF (lenientNegativeCurrencyTestCases); t += 1) {
+ UnicodeString testCase = ctou(lenientNegativeCurrencyTestCases[t]);
+
+ cFormat->parse(testCase, n, status);
+ logln((UnicodeString)"parse(" + testCase + ") = " + n.getLong());
+
+ if (U_FAILURE(status) ||n.getType() != Formattable::kLong ||
+ n.getLong() != -1000) {
+ errln((UnicodeString)"Lenient parse failed for \"" + (UnicodeString) lenientNegativeCurrencyTestCases[t]
+ + (UnicodeString) "\"; error code = " + u_errorName(status));
+ status = U_ZERO_ERROR;
+ }
+ }
+
+ delete cFormat;
+ }
+
+ NumberFormat *pFormat = NumberFormat::createPercentInstance(en_US, status);
+
+ if (pFormat == NULL || U_FAILURE(status)) {
+ dataerrln("Unable to create NumberFormat::createPercentInstance (en_US) - %s", u_errorName(status));
+ } else {
+ pFormat->setLenient(TRUE);
+ for (int32_t t = 0; t < UPRV_LENGTHOF (lenientPercentTestCases); t += 1) {
+ UnicodeString testCase = ctou(lenientPercentTestCases[t]);
+
+ pFormat->parse(testCase, n, status);
+ logln((UnicodeString)"parse(" + testCase + ") = " + n.getDouble());
+
+ if (U_FAILURE(status) ||n.getType() != Formattable::kDouble ||
+ n.getDouble() != 0.25) {
+ errln((UnicodeString)"Lenient parse failed for \"" + (UnicodeString) lenientPercentTestCases[t]
+ + (UnicodeString) "\"; error code = " + u_errorName(status)
+ + "; got: " + n.getDouble(status));
+ status = U_ZERO_ERROR;
+ }
+ }
+
+ for (int32_t t = 0; t < UPRV_LENGTHOF (lenientNegativePercentTestCases); t += 1) {
+ UnicodeString testCase = ctou(lenientNegativePercentTestCases[t]);
+
+ pFormat->parse(testCase, n, status);
+ logln((UnicodeString)"parse(" + testCase + ") = " + n.getDouble());
+
+ if (U_FAILURE(status) ||n.getType() != Formattable::kDouble ||
+ n.getDouble() != -0.25) {
+ errln((UnicodeString)"Lenient parse failed for \"" + (UnicodeString) lenientNegativePercentTestCases[t]
+ + (UnicodeString) "\"; error code = " + u_errorName(status)
+ + "; got: " + n.getDouble(status));
+ status = U_ZERO_ERROR;
+ }
+ }
+
+ delete pFormat;
+ }
+
+ // Test cases that should fail with a strict parse and pass with a
+ // lenient parse.
+ NumberFormat *nFormat = NumberFormat::createInstance(en_US, status);
+
+ if (nFormat == NULL || U_FAILURE(status)) {
+ dataerrln("Unable to create NumberFormat (en_US) - %s", u_errorName(status));
+ } else {
+ // first, make sure that they fail with a strict parse
+ 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) "\"; error code = " + u_errorName(status));
+ }
+
+ status = U_ZERO_ERROR;
+ }
+
+ // then, make sure that they pass with a lenient parse
+ nFormat->setLenient(TRUE);
+ 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) ||n.getType() != Formattable::kLong ||
+ n.getLong() != 1000) {
+ errln((UnicodeString)"Lenient parse failed for \"" + (UnicodeString) strictFailureTestCases[t]
+ + (UnicodeString) "\"; error code = " + u_errorName(status));
+ status = U_ZERO_ERROR;
+ }
+ }
+
+ delete nFormat;
+ }
+}
+
// -------------------------------------
/**
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(status, "createInstance(hi_IN)");
+ CHECK_DATA(status, "createInstance(hi_IN)");
UnicodeString out;
int32_t l = (int32_t)1876543210L;
DecimalFormatSymbols US(Locale::getUS(), ec);
DecimalFormat fmt("a b#0c ", US, ec);
if (U_FAILURE(ec)) {
- errln("FAIL: Constructor");
+ 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);
* Test currencies whose display name is a ChoiceFormat.
*/
void NumberFormatTest::TestComplexCurrency() {
- UErrorCode ec = U_ZERO_ERROR;
- Locale loc("en", "IN", "");
- NumberFormat* fmt = NumberFormat::createCurrencyInstance(loc, ec);
- if (U_SUCCESS(ec)) {
- expect2(*fmt, 1.0, "Re. 1.00");
- // Use .00392625 because that's 2^-8. Any value less than 0.005 is fine.
- expect(*fmt, 1.00390625, "Re. 1.00"); // tricky
- expect2(*fmt, 12345678.0, "Rs. 1,23,45,678.00");
- expect2(*fmt, 0.5, "Rs. 0.50");
- expect2(*fmt, -1.0, "-Re. 1.00");
- expect2(*fmt, -10.0, "-Rs. 10.00");
- } else {
- errln("FAIL: getCurrencyInstance(en_IN)");
- }
- delete fmt;
+
+// UErrorCode ec = U_ZERO_ERROR;
+// Locale loc("kn", "IN", "");
+// NumberFormat* fmt = NumberFormat::createCurrencyInstance(loc, ec);
+// if (U_SUCCESS(ec)) {
+// expect2(*fmt, 1.0, CharsToUnicodeString("Re.\\u00A01.00"));
+// Use .00392625 because that's 2^-8. Any value less than 0.005 is fine.
+// expect(*fmt, 1.00390625, CharsToUnicodeString("Re.\\u00A01.00")); // tricky
+// expect2(*fmt, 12345678.0, CharsToUnicodeString("Rs.\\u00A01,23,45,678.00"));
+// expect2(*fmt, 0.5, CharsToUnicodeString("Rs.\\u00A00.50"));
+// expect2(*fmt, -1.0, CharsToUnicodeString("-Re.\\u00A01.00"));
+// expect2(*fmt, -10.0, CharsToUnicodeString("-Rs.\\u00A010.00"));
+// } else {
+// errln("FAIL: getCurrencyInstance(kn_IN)");
+// }
+// delete fmt;
+
}
-
+
// -------------------------------------
-
+
void
NumberFormatTest::roundingTest(NumberFormat& nf, double x, int32_t maxFractionDigits, const char* expected)
{
// 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"
// Test the constructor for default locale. We have to
- // manually set the default locale, as there is no
- // guarantee that the default locale has the same
+ // manually set the default locale, as there is no
+ // guarantee that the default locale has the same
// scientific format.
Locale def = Locale::getDefault();
Locale::setDefault(Locale::getUS(), status);
expect(new DecimalFormat[] { new DecimalFormat("#E0", US),
new DecimalFormat("##E0", US),
new DecimalFormat("####E0", US),
- new DecimalFormat("0E0", US),
- new DecimalFormat("00E0", US),
- new DecimalFormat("000E0", US),
+ new DecimalFormat("0E0", US),
+ new DecimalFormat("00E0", US),
+ new DecimalFormat("000E0", US),
},
new Long(45678000),
new String[] { "4.5678E7",
"45.678E6",
"4567.8E4",
"5E7",
- "46E6",
+ "46E6",
"457E5",
}
);
DecimalFormat fmt("#", US, status);
CHECK(status, "DecimalFormat constructor");
-
+
UChar hat = 0x005E; /*^*/
expectPad(fmt, "*^#", DecimalFormat::kPadBeforePrefix, 1, hat);
fmt.setFormatWidth(16);
// 12 34567890123456
- expectPat(fmt, "AA*^#,###,##0.00ZZ");
+ expectPat(fmt, "AA*^#,###,##0.00ZZ"); // use ICU 61 behavior
}
void NumberFormatTest::TestSurrogateSupport(void) {
1.0/3, "0decimal33333 g-m/s^2", status);
UnicodeString zero((UChar32)0x10000);
+ UnicodeString one((UChar32)0x10001);
+ UnicodeString two((UChar32)0x10002);
+ UnicodeString five((UChar32)0x10005);
custom.setSymbol(DecimalFormatSymbols::kZeroDigitSymbol, zero);
+ custom.setSymbol(DecimalFormatSymbols::kOneDigitSymbol, one);
+ custom.setSymbol(DecimalFormatSymbols::kTwoDigitSymbol, two);
+ custom.setSymbol(DecimalFormatSymbols::kFiveDigitSymbol, five);
expStr = UnicodeString("\\U00010001decimal\\U00010002\\U00010005\\U00010000", "");
expStr = expStr.unescape();
status = U_ZERO_ERROR;
custom.setSymbol(DecimalFormatSymbols::kZeroDigitSymbol, (UChar)0x30);
custom.setSymbol(DecimalFormatSymbols::kCurrencySymbol, "units of money");
custom.setSymbol(DecimalFormatSymbols::kMonetarySeparatorSymbol, "money separator");
- patternStr = "0.00 \\u00A4' in your bank account'";
+ patternStr = UNICODE_STRING_SIMPLE("0.00 \\u00A4' in your bank account'");
patternStr = patternStr.unescape();
expStr = UnicodeString(" minus 20money separator00 units of money in your bank account", "");
status = U_ZERO_ERROR;
}
// Make sure EURO currency formats have exactly 2 fraction digits
- if (nf->getDynamicClassID() == DecimalFormat::getStaticClassID()) {
- DecimalFormat* df = (DecimalFormat*) nf;
+ DecimalFormat* df = dynamic_cast<DecimalFormat*>(nf);
+ if (df != NULL) {
if (u_strcmp(EUR, df->getCurrency()) == 0) {
if (min != 2 || max != 2) {
UnicodeString a;
UChar TMP[4];
static const UChar QQQ[] = {0x51, 0x51, 0x51, 0};
if(U_FAILURE(status)) {
- errln("Unable to get currency for locale, error %s", u_errorName(status));
+ errcheckln(status, "Unable to get currency for locale, error %s", u_errorName(status));
return;
}
-
+
UCurrRegistryKey enkey = ucurr_register(YEN, "en_US", &status);
UCurrRegistryKey enUSEUROkey = ucurr_register(QQQ, "en_US_EURO", &status);
-
+
ucurr_forLocale("en_US", TMP, 4, &status);
if (u_strcmp(YEN, TMP) != 0) {
errln("FAIL: didn't return YEN registered for en_US");
if (u_strcmp(QQQ, TMP) != 0) {
errln("FAIL: didn't return QQQ for en_US_EURO");
}
-
+
int32_t fallbackLen = ucurr_forLocale("en_XX_BAR", TMP, 4, &status);
if (fallbackLen) {
errln("FAIL: tried to fallback en_XX_BAR");
}
status = U_ZERO_ERROR; // reset
-
+
if (!ucurr_unregister(enkey, &status)) {
errln("FAIL: couldn't unregister enkey");
}
- ucurr_forLocale("en_US", TMP, 4, &status);
+ ucurr_forLocale("en_US", TMP, 4, &status);
if (u_strcmp(USD, TMP) != 0) {
errln("FAIL: didn't return USD for en_US after unregister of en_US");
}
status = U_ZERO_ERROR; // reset
-
+
ucurr_forLocale("en_US_EURO", TMP, 4, &status);
if (u_strcmp(QQQ, TMP) != 0) {
errln("FAIL: didn't return QQQ for en_US_EURO after unregister of en_US");
}
-
+
ucurr_forLocale("en_US_BLAH", TMP, 4, &status);
if (u_strcmp(USD, TMP) != 0) {
errln("FAIL: could not find USD for en_US_BLAH after unregister of en");
}
status = U_ZERO_ERROR; // reset
-
+
if (!ucurr_unregister(enUSEUROkey, &status)) {
errln("FAIL: couldn't unregister enUSEUROkey");
}
-
+
ucurr_forLocale("en_US_EURO", TMP, 4, &status);
if (u_strcmp(EUR, TMP) != 0) {
errln("FAIL: didn't return EUR for en_US_EURO after unregister of en_US_EURO");
// Do a basic check of getName()
// USD { "US$", "US Dollar" } // 04/04/1792-
UErrorCode ec = U_ZERO_ERROR;
- static const UChar USD[] = {85, 83, 68, 0}; /*USD*/
+ static const UChar USD[] = {0x55, 0x53, 0x44, 0}; /*USD*/
+ static const UChar USX[] = {0x55, 0x53, 0x58, 0}; /*USX*/
static const UChar CAD[] = {0x43, 0x41, 0x44, 0}; /*CAD*/
static const UChar ITL[] = {0x49, 0x54, 0x4C, 0}; /*ITL*/
UBool isChoiceFormat;
int32_t len;
+ 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)",
- UnicodeString("US$"),
+ assertEquals("USD.getName(SYMBOL_NAME, en)",
+ UnicodeString("$"),
UnicodeString(ucurr_getName(USD, "en",
UCURR_SYMBOL_NAME,
- &isChoiceFormat, &len, &ec)));
- assertEquals("USD.getName(LONG_NAME)",
+ &isChoiceFormat, &len, &ec)),
+ possibleDataError);
+ 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)));
+ &isChoiceFormat, &len, &ec)),
+ possibleDataError);
+ assertEquals("CAD.getName(SYMBOL_NAME, en)",
+ UnicodeString("CA$"),
+ UnicodeString(ucurr_getName(CAD, "en",
+ UCURR_SYMBOL_NAME,
+ &isChoiceFormat, &len, &ec)),
+ possibleDataError);
+ 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, en_CA)",
+ UnicodeString("US$"),
+ 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_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",
+ UCURR_LONG_NAME,
+ &isChoiceFormat, &len, &ec)),
+ possibleDataError);
assertSuccess("ucurr_getName", ec);
-
+
+ ec = U_ZERO_ERROR;
+
// Test that a default or fallback warning is being returned. JB 4239.
- (void) ucurr_getName(CAD, "en_US", UCURR_LONG_NAME, &isChoiceFormat,
+ ucurr_getName(CAD, "es_ES", UCURR_LONG_NAME, &isChoiceFormat,
&len, &ec);
- assertTrue("ucurr_getName (fallback)",
- U_USING_FALLBACK_WARNING == ec, TRUE);
- (void) ucurr_getName(CAD, "vi", UCURR_LONG_NAME, &isChoiceFormat,
+ assertTrue("ucurr_getName (es_ES fallback)",
+ U_USING_FALLBACK_WARNING == ec, TRUE, possibleDataError);
+
+ ucurr_getName(CAD, "zh_TW", UCURR_LONG_NAME, &isChoiceFormat,
+ &len, &ec);
+ assertTrue("ucurr_getName (zh_TW fallback)",
+ U_USING_FALLBACK_WARNING == ec, TRUE, possibleDataError);
+
+ ucurr_getName(CAD, "en_US", UCURR_LONG_NAME, &isChoiceFormat,
+ &len, &ec);
+ assertTrue("ucurr_getName (en_US default)",
+ U_USING_DEFAULT_WARNING == ec || U_USING_FALLBACK_WARNING == ec, TRUE);
+
+ ucurr_getName(CAD, "ti", UCURR_LONG_NAME, &isChoiceFormat,
&len, &ec);
- assertTrue("ucurr_getName (default)",
+ assertTrue("ucurr_getName (ti default)",
U_USING_DEFAULT_WARNING == ec, TRUE);
-
+
// Test that a default warning is being returned when falling back to root. JB 4536.
- (void) ucurr_getName(ITL, "cy", UCURR_LONG_NAME, &isChoiceFormat,
+ ucurr_getName(ITL, "cy", UCURR_LONG_NAME, &isChoiceFormat,
&len, &ec);
- assertTrue("ucurr_getName (default to root)",
+ assertTrue("ucurr_getName (cy default to root)",
U_USING_DEFAULT_WARNING == ec, TRUE);
-
+
// TODO add more tests later
}
void NumberFormatTest::TestCurrencyUnit(void){
UErrorCode ec = U_ZERO_ERROR;
- static const UChar USD[] = {85, 83, 68, 0}; /*USD*/
+ 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)){
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<MeasureUnit> 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){
if (!(ca2 == ca)){
errln("CurrencyAmount assigned object should be same");
}
-
+
CurrencyAmount *ca3 = (CurrencyAmount *)ca.clone();
if (!(*ca3 == ca)){
errln("CurrencyAmount cloned object should be same");
void NumberFormatTest::TestSymbolsWithBadLocale(void) {
Locale locDefault;
- Locale locBad("x-crazy_ZZ_MY_SPECIAL_ADMINISTRATION_REGION_NEEDS_A_SPECIAL_VARIANT_WITH_A_REALLY_REALLY_REALLY_REALLY_REALLY_REALLY_REALLY_LONG_NAME");
- UErrorCode status = U_ZERO_ERROR;
- UnicodeString intlCurrencySymbol((UChar)0xa4);
-
- intlCurrencySymbol.append((UChar)0xa4);
-
- logln("Current locale is %s", Locale::getDefault().getName());
- Locale::setDefault(locBad, status);
- logln("Current locale is %s", Locale::getDefault().getName());
- DecimalFormatSymbols mySymbols(status);
- if (status != U_USING_FALLBACK_WARNING) {
- errln("DecimalFormatSymbols should returned U_USING_FALLBACK_WARNING.");
- }
- if (strcmp(mySymbols.getLocale().getName(), locBad.getName()) != 0) {
- errln("DecimalFormatSymbols does not have the right locale.");
- }
- int symbolEnum = (int)DecimalFormatSymbols::kDecimalSeparatorSymbol;
- for (; symbolEnum < (int)DecimalFormatSymbols::kFormatSymbolCount; symbolEnum++) {
- logln(UnicodeString("DecimalFormatSymbols[") + symbolEnum + UnicodeString("] = ")
- + prettify(mySymbols.getSymbol((DecimalFormatSymbols::ENumberFormatSymbol)symbolEnum)));
-
- if (mySymbols.getSymbol((DecimalFormatSymbols::ENumberFormatSymbol)symbolEnum).length() == 0
- && symbolEnum != (int)DecimalFormatSymbols::kGroupingSeparatorSymbol
- && symbolEnum != (int)DecimalFormatSymbols::kMonetaryGroupingSeparatorSymbol)
- {
- errln("DecimalFormatSymbols has an empty string at index %d.", symbolEnum);
+ static const char *badLocales[] = {
+ // length < ULOC_FULLNAME_CAPACITY
+ "x-crazy_ZZ_MY_SPECIAL_ADMINISTRATION_REGION_NEEDS_A_SPECIAL_VARIANT_WITH_A_REALLY_REALLY_REALLY_REALLY_REALLY_REALLY_REALLY_LONG_NAME",
+
+ // length > ULOC_FULLNAME_CAPACITY
+ "x-crazy_ZZ_MY_SPECIAL_ADMINISTRATION_REGION_NEEDS_A_SPECIAL_VARIANT_WITH_A_REALLY_REALLY_REALLY_REALLY_REALLY_REALLY_REALLY_REALLY_REALLY_REALLY_REALLY_LONG_NAME"
+ }; // expect U_USING_DEFAULT_WARNING for both
+
+ unsigned int 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);
+
+ intlCurrencySymbol.append((UChar)0xa4);
+
+ logln("Current locale is %s", Locale::getDefault().getName());
+ Locale::setDefault(locBad, status);
+ logln("Current locale is %s", Locale::getDefault().getName());
+ DecimalFormatSymbols mySymbols(status);
+ if (status != U_USING_DEFAULT_WARNING) {
+ errln("DecimalFormatSymbols should return U_USING_DEFAULT_WARNING.");
+ }
+ if (strcmp(mySymbols.getLocale().getName(), locBad.getName()) != 0) {
+ errln("DecimalFormatSymbols does not have the right locale.", locBad.getName());
}
+ int symbolEnum = (int)DecimalFormatSymbols::kDecimalSeparatorSymbol;
+ for (; symbolEnum < (int)DecimalFormatSymbols::kFormatSymbolCount; symbolEnum++) {
+ UnicodeString symbolString = mySymbols.getSymbol((DecimalFormatSymbols::ENumberFormatSymbol)symbolEnum);
+ logln(UnicodeString("DecimalFormatSymbols[") + symbolEnum + UnicodeString("] = ") + prettify(symbolString));
+ if (symbolString.length() == 0
+ && symbolEnum != (int)DecimalFormatSymbols::kGroupingSeparatorSymbol
+ && symbolEnum != (int)DecimalFormatSymbols::kMonetaryGroupingSeparatorSymbol)
+ {
+ errln("DecimalFormatSymbols has an empty string at index %d.", symbolEnum);
+ }
+ }
+
+ status = U_ZERO_ERROR;
+ Locale::setDefault(locDefault, status);
+ logln("Current locale is %s", Locale::getDefault().getName());
}
- status = U_ZERO_ERROR;
- Locale::setDefault(locDefault, status);
- logln("Current locale is %s", Locale::getDefault().getName());
}
/**
UErrorCode ec = U_ZERO_ERROR;
DecimalFormatSymbols *sym = new DecimalFormatSymbols(Locale::getUS(), ec);
if (U_FAILURE(ec)) {
- errln("Fail: DecimalFormatSymbols constructor");
+ errcheckln(ec, "Fail: DecimalFormatSymbols constructor - %s", u_errorName(ec));
delete sym;
return;
}
if (str == "$ 2,350.75") {
logln(str);
} else {
- errln("Fail: " + str + ", expected $ 2,350.75");
+ dataerrln("Fail: " + str + ", expected $ 2,350.75");
}
sym = new DecimalFormatSymbols(Locale::getUS(), ec);
if (str == "Q 2,350.75") {
logln(str);
} else {
- errln("Fail: adoptDecimalFormatSymbols -> " + str + ", expected Q 2,350.75");
+ dataerrln("Fail: adoptDecimalFormatSymbols -> " + str + ", expected Q 2,350.75");
}
sym = new DecimalFormatSymbols(Locale::getUS(), ec);
errln("Fail: DecimalFormat constructor");
return;
}
-
+
DecimalFormatSymbols sym2(Locale::getUS(), ec);
if (U_FAILURE(ec)) {
errln("Fail: DecimalFormatSymbols constructor");
if (str == "Q 2,350.75") {
logln(str);
} else {
- errln("Fail: setDecimalFormatSymbols -> " + str + ", expected Q 2,350.75");
+ dataerrln("Fail: setDecimalFormatSymbols -> " + str + ", expected Q 2,350.75");
}
}
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);
logln("Ok: pattern \"%s\": %s",
pat, u_errorName(ec));
} else {
- errln("FAIL: pattern \"%s\" should have %s; got %s",
+ errcheckln(ec, "FAIL: pattern \"%s\" should have %s; got %s",
pat, (valid?"succeeded":"failed"),
u_errorName(ec));
}
UErrorCode ec = U_ZERO_ERROR;
TextFile reader("NumberFormatTestCases.txt", "UTF8", ec);
if (U_FAILURE(ec)) {
- errln("FAIL: Couldn't open NumberFormatTestCases.txt");
+ dataerrln("Couldn't open NumberFormatTestCases.txt");
return;
}
TokenIterator tokens(&reader);
case 1:
// loc= <locale>
if (!tokens.next(tok, ec)) goto error;
- loc = Locale::createFromName(CharString(tok));
+ loc = Locale::createFromName(CharString().appendInvariantChars(tok, ec).data());
break;
case 2: // f:
case 3: // fp:
assertSuccess("parse", ec);
assertEquals(where + "\"" + pat + "\".parse(\"" + str + "\")",
n, m);
- }
+ }
}
// p: <pattern or '-'> <string to parse> <exp. number>
else {
mloc = tok;
delete mfmt;
mfmt = MeasureFormat::createCurrencyFormat(
- Locale::createFromName(CharString(mloc)), ec);
+ Locale::createFromName(
+ CharString().appendInvariantChars(mloc, ec).data()), ec);
if (U_FAILURE(ec)) {
errln("FAIL: " + where + "Loc \"" + mloc + "\": " + u_errorName(ec));
ec = U_ZERO_ERROR;
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: <loc or '-'> <curr.amt> <exp. string> <exp. curr.amt>
if (!tokens.next(currAmt, ec)) goto error;
parseCurrencyAmount(currAmt, *ref, (UChar)0x2F/*'/'*/, n, ec);
if (assertSuccess("parseCurrencyAmount", ec)) {
Formattable m;
+
mfmt->parseObject(str, m, ec);
if (assertSuccess("parseCurrency", ec)) {
assertEquals(where + "getCurrencyFormat(" + mloc + ").parse(\"" + str + "\")",
n, m);
+ } else {
+ errln("FAIL: source " + str);
}
}
break;
if (U_SUCCESS(ec)) {
errln("FAIL: Unexpected EOF");
} else {
- errln("FAIL: " + where + "Unexpected " + u_errorName(ec));
+ errcheckln(ec, "FAIL: " + where + "Unexpected " + u_errorName(ec));
}
done:
if (b.getType() == Formattable::kInt64) {
return a.getLong() == b.getLong();
} else if (b.getType() == Formattable::kDouble) {
- return (double) a.getLong() == b.getDouble(); // TODO check use of double instead of long
+ return (double) a.getLong() == b.getDouble(); // TODO check use of double instead of long
}
} else if (a.getType() == Formattable::kDouble) {
if (b.getType() == Formattable::kLong) {
return FALSE;
}
+void NumberFormatTest::expect3(NumberFormat& fmt, const Formattable& n, const UnicodeString& str) {
+ // Don't round-trip format test, since we explicitly do it
+ expect_rbnf(fmt, n, str, FALSE);
+ expect_rbnf(fmt, str, n);
+}
+
void NumberFormatTest::expect2(NumberFormat& fmt, const Formattable& n, const UnicodeString& str) {
// Don't round-trip format test, since we explicitly do it
expect(fmt, n, str, FALSE);
void NumberFormatTest::expect2(NumberFormat* fmt, const Formattable& n,
const UnicodeString& exp,
UErrorCode status) {
- if (U_FAILURE(status)) {
- errln("FAIL: NumberFormat constructor");
+ if (fmt == NULL || U_FAILURE(status)) {
+ dataerrln("FAIL: NumberFormat constructor");
} else {
expect2(*fmt, n, exp);
}
Formattable num;
fmt.parse(str, num, status);
if (U_FAILURE(status)) {
- errln(UnicodeString("FAIL: Parse failed for \"") + str + "\"");
+ dataerrln(UnicodeString("FAIL: Parse failed for \"") + str + "\" - " + u_errorName(status));
return;
}
UnicodeString pat;
pat + " = " +
toString(num));
} else {
- errln(UnicodeString("FAIL \"") + str + "\" x " +
+ dataerrln(UnicodeString("FAIL \"") + str + "\" x " +
pat + " = " +
toString(num) + ", expected " + toString(n));
}
}
+void NumberFormatTest::expect_rbnf(NumberFormat& fmt, const UnicodeString& str, const Formattable& n) {
+ UErrorCode status = U_ZERO_ERROR;
+ Formattable num;
+ fmt.parse(str, num, status);
+ if (U_FAILURE(status)) {
+ errln(UnicodeString("FAIL: Parse failed for \"") + str + "\"");
+ return;
+ }
+ if (equalValue(num, n)) {
+ logln(UnicodeString("Ok \"") + str + " = " +
+ toString(num));
+ } else {
+ errln(UnicodeString("FAIL \"") + str + " = " +
+ toString(num) + ", expected " + toString(n));
+ }
+}
+
+void NumberFormatTest::expect_rbnf(NumberFormat& fmt, const Formattable& n,
+ const UnicodeString& exp, UBool rt) {
+ UnicodeString saw;
+ FieldPosition pos;
+ UErrorCode status = U_ZERO_ERROR;
+ fmt.format(n, saw, pos, status);
+ CHECK(status, "NumberFormat::format");
+ if (saw == exp) {
+ logln(UnicodeString("Ok ") + toString(n) +
+ " = \"" +
+ escape(saw) + "\"");
+ // We should be able to round-trip the formatted string =>
+ // number => string (but not the other way around: number
+ // => string => number2, might have number2 != number):
+ if (rt) {
+ Formattable n2;
+ fmt.parse(exp, n2, status);
+ if (U_FAILURE(status)) {
+ errln(UnicodeString("FAIL: Parse failed for \"") + exp + "\"");
+ return;
+ }
+ UnicodeString saw2;
+ fmt.format(n2, saw2, pos, status);
+ CHECK(status, "NumberFormat::format");
+ if (saw2 != exp) {
+ errln((UnicodeString)"FAIL \"" + exp + "\" => " + toString(n2) +
+ " => \"" + saw2 + "\"");
+ }
+ }
+ } else {
+ errln(UnicodeString("FAIL ") + toString(n) +
+ " = \"" +
+ escape(saw) + "\", expected \"" + exp + "\"");
+ }
+}
+
void NumberFormatTest::expect(NumberFormat& fmt, const Formattable& n,
const UnicodeString& exp, UBool rt) {
UnicodeString saw;
Formattable n2;
fmt.parse(exp, n2, status);
if (U_FAILURE(status)) {
- errln(UnicodeString("FAIL: Parse failed for \"") + exp + "\"");
+ errln(UnicodeString("FAIL: Parse failed for \"") + exp + "\" - " + u_errorName(status));
return;
}
UnicodeString saw2;
}
}
} else {
- errln(UnicodeString("FAIL ") + toString(n) + " x " +
+ dataerrln(UnicodeString("FAIL ") + toString(n) + " x " +
escape(pat) + " = \"" +
escape(saw) + "\", expected \"" + exp + "\"");
}
}
void NumberFormatTest::expect(NumberFormat* fmt, const Formattable& n,
- const UnicodeString& exp,
+ const UnicodeString& exp, UBool rt,
UErrorCode status) {
- if (U_FAILURE(status)) {
- errln("FAIL: NumberFormat constructor");
+ if (fmt == NULL || U_FAILURE(status)) {
+ dataerrln("FAIL: NumberFormat constructor");
} else {
- expect(*fmt, n, exp);
+ expect(*fmt, n, exp, rt);
}
delete fmt;
}
// Default display of the number yields "1234.5599999999999"
// instead of "1234.56". Use a formatter to fix this.
- NumberFormat* f =
+ NumberFormat* f =
NumberFormat::createInstance(Locale::getUS(), ec);
UnicodeString v;
if (U_FAILURE(ec)) {
", expected " + pos + " " + width + " " + pad);
}
}
-void NumberFormatTest::TestJB3832(){
- const char* localeID = "pt_PT@currency=PTE";
- Locale loc(localeID);
+
+// 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<NumberFormat> 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<NumberFormat> 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<NumberFormat> 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> 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("1,150$50 Esc.");
+ UnicodeString expected(CharsToUnicodeString("1,150$50\\u00A0\\u200B")); // per cldrbug 7670
UnicodeString s;
NumberFormat* currencyFmt = NumberFormat::createCurrencyInstance(loc, status);
if(U_FAILURE(status)){
- errln("Could not create currency formatter for locale %s", localeID);
+ dataerrln("Could not create currency formatter for locale %s - %s", localeID, u_errorName(status));
return;
}
currencyFmt->format(1150.50, s);
if(s!=expected){
- errln(UnicodeString("FAIL: Expected: ")+expected
- + UnicodeString(" Got: ") + s
+ errln(UnicodeString("FAIL: Expected: ")+expected
+ + UnicodeString(" Got: ") + s
+ UnicodeString( " for locale: ")+ UnicodeString(localeID) );
}
if (U_FAILURE(status)){
void NumberFormatTest::TestHost()
{
-#ifdef U_WINDOWS
+#if U_PLATFORM_USES_ONLY_WIN32_API
Win32NumberTest::testLocales(this);
#endif
+ Locale loc("en_US@compat=host");
+ for (UNumberFormatStyle k = UNUM_DECIMAL;
+ k < UNUM_FORMAT_STYLE_COUNT; k = (UNumberFormatStyle)(k+1)) {
+ UErrorCode status = U_ZERO_ERROR;
+ LocalPointer<NumberFormat> full(NumberFormat::createInstance(loc, k, status));
+ if (!NumberFormat::isStyleSupported(k)) {
+ if (status != U_UNSUPPORTED_ERROR) {
+ errln("FAIL: expected style %d to be unsupported - %s",
+ k, u_errorName(status));
+ }
+ continue;
+ }
+ if (full.isNull() || U_FAILURE(status)) {
+ dataerrln("FAIL: Can't create number instance of style %d for host - %s",
+ k, u_errorName(status));
+ return;
+ }
+ UnicodeString result1;
+ Formattable number(10.00);
+ full->format(number, result1, status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: Can't format for host");
+ return;
+ }
+ Formattable formattable;
+ full->parse(result1, formattable, status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: Can't parse for host");
+ return;
+ }
+ }
+}
+
+void NumberFormatTest::TestHostClone()
+{
+ /*
+ Verify that a cloned formatter gives the same results
+ and is useable after the original has been deleted.
+ */
+ // This is mainly important on Windows.
+ UErrorCode status = U_ZERO_ERROR;
+ Locale loc("en_US@compat=host");
+ UDate now = Calendar::getNow();
+ NumberFormat *full = NumberFormat::createInstance(loc, status);
+ if (full == NULL || U_FAILURE(status)) {
+ dataerrln("FAIL: Can't create NumberFormat date instance - %s", u_errorName(status));
+ return;
+ }
+ UnicodeString result1;
+ full->format(now, result1, status);
+ Format *fullClone = full->clone();
+ delete full;
+ full = NULL;
+
+ UnicodeString result2;
+ fullClone->format(now, result2, status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: format failure.");
+ }
+ if (result1 != result2) {
+ errln("FAIL: Clone returned different result from non-clone.");
+ }
+ delete fullClone;
}
void NumberFormatTest::TestCurrencyFormat()
}
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)){
- errln("FAIL: Status %s", u_errorName(status));
+ dataerrln("FAIL: Locale::setDefault status %s", u_errorName(status));
return;
}
cloneObj = (MeasureFormat *)measureObj->clone();
if (result != toFormat) {
errln("Clone does not round trip. Formatted string was \"" + str + "\" Got: " + toString(result) + " Expected: " + toString(toFormat));
}
+ if (*measureObj != *cloneObj) {
+ errln("Cloned object is not equal to the original object");
+ }
delete measureObj;
delete cloneObj;
+ status = U_USELESS_COLLATOR_ERROR;
+ if (MeasureFormat::createCurrencyFormat(status) != NULL) {
+ errln("createCurrencyFormat should have returned NULL.");
+ }
+}
+
+/* Port of ICU4J rounding test. */
+void NumberFormatTest::TestRounding() {
+ UErrorCode status = U_ZERO_ERROR;
+ DecimalFormat *df = (DecimalFormat*)NumberFormat::createCurrencyInstance(Locale::getEnglish(), status);
+
+ if (U_FAILURE(status)) {
+ dataerrln("Unable to create decimal formatter. - %s", u_errorName(status));
+ return;
+ }
+
+ int roundingIncrements[]={1, 2, 5, 20, 50, 100};
+ int testValues[]={0, 300};
+
+ for (int j=0; j<2; j++) {
+ for (int mode=DecimalFormat::kRoundUp;mode<DecimalFormat::kRoundHalfEven;mode++) {
+ df->setRoundingMode((DecimalFormat::ERoundingMode)mode);
+ for (int increment=0; increment<6; increment++) {
+ double base=testValues[j];
+ double rInc=roundingIncrements[increment];
+ checkRounding(df, base, 20, rInc);
+ rInc=1.000000000/rInc;
+ checkRounding(df, base, 20, rInc);
+ }
+ }
+ }
+ delete df;
+}
+
+void NumberFormatTest::TestRoundingPattern() {
+ UErrorCode status = U_ZERO_ERROR;
+ struct {
+ UnicodeString pattern;
+ double testCase;
+ UnicodeString expected;
+ } tests[] = {
+ { (UnicodeString)"##0.65", 1.234, (UnicodeString)"1.30" },
+ { (UnicodeString)"#50", 1230, (UnicodeString)"1250" }
+ };
+ int32_t numOfTests = UPRV_LENGTHOF(tests);
+ UnicodeString result;
+
+ DecimalFormat *df = (DecimalFormat*)NumberFormat::createCurrencyInstance(Locale::getEnglish(), status);
+ if (U_FAILURE(status)) {
+ dataerrln("Unable to create decimal formatter. - %s", u_errorName(status));
+ return;
+ }
+
+ for (int32_t i = 0; i < numOfTests; i++) {
+ result.remove();
+
+ df->applyPattern(tests[i].pattern, status);
+ if (U_FAILURE(status)) {
+ errln("Unable to apply pattern to decimal formatter. - %s", u_errorName(status));
+ }
+
+ df->format(tests[i].testCase, result);
+
+ if (result != tests[i].expected) {
+ errln("String Pattern Rounding Test Failed: Pattern: \"" + tests[i].pattern + "\" Number: " + tests[i].testCase + " - Got: " + result + " Expected: " + tests[i].expected);
+ }
+ }
+
+ delete df;
+}
+
+void NumberFormatTest::checkRounding(DecimalFormat* df, double base, int iterations, double increment) {
+ df->setRoundingIncrement(increment);
+ double lastParsed=INT32_MIN; //Intger.MIN_VALUE
+ for (int i=-iterations; i<=iterations;i++) {
+ double iValue=base+(increment*(i*0.1));
+ double smallIncrement=0.00000001;
+ if (iValue!=0) {
+ smallIncrement*=iValue;
+ }
+ //we not only test the value, but some values in a small range around it
+ lastParsed=checkRound(df, iValue-smallIncrement, lastParsed);
+ lastParsed=checkRound(df, iValue, lastParsed);
+ lastParsed=checkRound(df, iValue+smallIncrement, lastParsed);
+ }
+}
+
+double NumberFormatTest::checkRound(DecimalFormat* df, double iValue, double lastParsed) {
+ UErrorCode status=U_ZERO_ERROR;
+ UnicodeString formattedDecimal;
+ double parsed;
+ Formattable result;
+ df->format(iValue, formattedDecimal, status);
+
+ if (U_FAILURE(status)) {
+ errln("Error formatting number.");
+ }
+
+ df->parse(formattedDecimal, result, status);
+
+ if (U_FAILURE(status)) {
+ errln("Error parsing number.");
+ }
+
+ parsed=result.getDouble();
+
+ if (lastParsed>parsed) {
+ errln("Rounding wrong direction! %d > %d", lastParsed, parsed);
+ }
+
+ return lastParsed;
+}
+
+void NumberFormatTest::TestNonpositiveMultiplier() {
+ UErrorCode status = U_ZERO_ERROR;
+ DecimalFormatSymbols US(Locale::getUS(), status);
+ CHECK(status, "DecimalFormatSymbols constructor");
+ DecimalFormat df(UnicodeString("0"), US, status);
+ CHECK(status, "DecimalFormat(0)");
+
+ // test zero multiplier
+
+ int32_t mult = df.getMultiplier();
+ df.setMultiplier(0);
+ if (df.getMultiplier() != mult) {
+ errln("DecimalFormat.setMultiplier(0) did not ignore its zero input");
+ }
+
+ // test negative multiplier
+
+ df.setMultiplier(-1);
+ if (df.getMultiplier() != -1) {
+ errln("DecimalFormat.setMultiplier(-1) ignored its negative input");
+ return;
+ }
+
+ expect(df, "1122.123", -1122.123);
+ expect(df, "-1122.123", 1122.123);
+ expect(df, "1.2", -1.2);
+ expect(df, "-1.2", 1.2);
+
+ // Note: the tests with the final parameter of FALSE will not round trip.
+ // The initial numeric value will format correctly, after the multiplier.
+ // Parsing the formatted text will be out-of-range for an int64, however.
+ // The expect() function could be modified to detect this and fall back
+ // to looking at the decimal parsed value, but it doesn't.
+ expect(df, U_INT64_MIN, "9223372036854775808", FALSE);
+ expect(df, U_INT64_MIN+1, "9223372036854775807");
+ expect(df, (int64_t)-123, "123");
+ expect(df, (int64_t)123, "-123");
+ expect(df, U_INT64_MAX-1, "-9223372036854775806");
+ expect(df, U_INT64_MAX, "-9223372036854775807");
+
+ df.setMultiplier(-2);
+ expect(df, -(U_INT64_MIN/2)-1, "-9223372036854775806");
+ expect(df, -(U_INT64_MIN/2), "-9223372036854775808");
+ expect(df, -(U_INT64_MIN/2)+1, "-9223372036854775810", FALSE);
+
+ df.setMultiplier(-7);
+ expect(df, -(U_INT64_MAX/7)-1, "9223372036854775814", FALSE);
+ expect(df, -(U_INT64_MAX/7), "9223372036854775807");
+ expect(df, -(U_INT64_MAX/7)+1, "9223372036854775800");
+
+ // TODO: uncomment (and fix up) all the following int64_t tests once BigInteger is ported
+ // (right now the big numbers get turned into doubles and lose tons of accuracy)
+ //expect2(df, U_INT64_MAX, Int64ToUnicodeString(-U_INT64_MAX));
+ //expect2(df, U_INT64_MIN, UnicodeString(Int64ToUnicodeString(U_INT64_MIN), 1));
+ //expect2(df, U_INT64_MAX / 2, Int64ToUnicodeString(-(U_INT64_MAX / 2)));
+ //expect2(df, U_INT64_MIN / 2, Int64ToUnicodeString(-(U_INT64_MIN / 2)));
+
+ // TODO: uncomment (and fix up) once BigDecimal is ported and DecimalFormat can handle it
+ //expect2(df, BigDecimal.valueOf(Long.MAX_VALUE), BigDecimal.valueOf(Long.MAX_VALUE).negate().toString());
+ //expect2(df, BigDecimal.valueOf(Long.MIN_VALUE), BigDecimal.valueOf(Long.MIN_VALUE).negate().toString());
+ //expect2(df, java.math.BigDecimal.valueOf(Long.MAX_VALUE), java.math.BigDecimal.valueOf(Long.MAX_VALUE).negate().toString());
+ //expect2(df, java.math.BigDecimal.valueOf(Long.MIN_VALUE), java.math.BigDecimal.valueOf(Long.MIN_VALUE).negate().toString());
+}
+
+typedef struct {
+ const char * stringToParse;
+ int parsedPos;
+ int errorIndex;
+ UBool lenient;
+} TestSpaceParsingItem;
+
+void
+NumberFormatTest::TestSpaceParsing() {
+ // the data are:
+ // the string to be parsed, parsed position, parsed error index
+ const TestSpaceParsingItem DATA[] = {
+ // TOTO: Update the following TODOs, some may be handled now
+ {"$124", 4, -1, FALSE},
+ {"$124 $124", 4, -1, FALSE},
+ {"$124 ", 4, -1, FALSE},
+ //{"$ 124 ", 5, -1, FALSE}, // TODO: need to handle space correctly
+ //{"$\\u00A0124 ", 5, -1, FALSE}, // TODO: need to handle space correctly
+ {"$ 124 ", 0, 1, FALSE}, // errorIndex used to be 0, now 1 (better)
+ {"$\\u00A0124 ", 5, -1, FALSE}, // errorIndex used to be 0, now 1 (better) *Apple change from open source*
+ {" $ 124 ", 0, 0, FALSE}, // TODO: need to handle space correctly
+ {"124$", 0, 3, FALSE}, // TODO: need to handle space correctly
+ // {"124 $", 5, -1, FALSE}, // TODO: OK or not, need currency spacing rule
+ {"124 $", 0, 3, FALSE},
+ {"$124", 4, -1, TRUE},
+ {"$124 $124", 4, -1, TRUE},
+ {"$124 ", 4, -1, TRUE},
+ {"$ 124 ", 5, -1, TRUE},
+ {"$\\u00A0124 ", 5, -1, TRUE},
+ {" $ 124 ", 6, -1, TRUE},
+ //{"124$", 4, -1, TRUE}, // TODO: need to handle trailing currency correctly
+ {"124$", 3, -1, TRUE},
+ //{"124 $", 5, -1, TRUE}, // TODO: OK or not, need currency spacing rule
+ {"124 $", 4, -1, TRUE},
+ };
+ UErrorCode status = U_ZERO_ERROR;
+ Locale locale("en_US");
+ NumberFormat* foo = NumberFormat::createCurrencyInstance(locale, status);
+
+ if (U_FAILURE(status)) {
+ delete foo;
+ return;
+ }
+ for (uint32_t i = 0; i < UPRV_LENGTHOF(DATA); ++i) {
+ ParsePosition parsePosition(0);
+ UnicodeString stringToBeParsed = ctou(DATA[i].stringToParse);
+ int parsedPosition = DATA[i].parsedPos;
+ int errorIndex = DATA[i].errorIndex;
+ 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() + ")");
+ }
+ if (parsePosition.getErrorIndex() == -1 &&
+ result.getType() == Formattable::kLong &&
+ result.getLong() != 124) {
+ errln("FAILED parse " + stringToBeParsed + "; wrong number, expect: 124, got " + result.getLong());
+ }
+ }
+ delete foo;
+}
+
+/**
+ * Test using various numbering systems and numbering system keyword.
+ */
+typedef struct {
+ const char *localeName;
+ double value;
+ UBool isRBNF;
+ const char *expectedResult;
+} TestNumberingSystemItem;
+
+void NumberFormatTest::TestNumberingSystems() {
+
+ const TestNumberingSystemItem DATA[] = {
+ { "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\\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" },
+ { "ta_IN@numbers=native", 1234.567, FALSE, "\\u0BE7,\\u0BE8\\u0BE9\\u0BEA.\\u0BEB\\u0BEC\\u0BED" },
+ { "ta_IN@numbers=traditional", 1235.0, TRUE, "\\u0BF2\\u0BE8\\u0BF1\\u0BE9\\u0BF0\\u0BEB" },
+ { "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\\u53C3\\u62FE\\u8086\\u9EDE\\u4F0D\\u9678\\u67D2" },
+ { NULL, 0, FALSE, NULL }
+ };
+
+ UErrorCode ec;
+
+ const TestNumberingSystemItem *item;
+ for (item = DATA; item->localeName != NULL; item++) {
+ ec = U_ZERO_ERROR;
+ Locale loc = Locale::createFromName(item->localeName);
+
+ 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 {
+ expect2(*fmt,item->value,CharsToUnicodeString(item->expectedResult));
+ }
+ delete fmt;
+ }
+
+
+ // Test bogus keyword value
+ ec = U_ZERO_ERROR;
+ Locale loc4 = Locale::createFromName("en_US@numbers=foobar");
+ NumberFormat* fmt4= NumberFormat::createInstance(loc4, ec);
+ if ( ec != U_UNSUPPORTED_ERROR ) {
+ errln("FAIL: getInstance(en_US@numbers=foobar) should have returned U_UNSUPPORTED_ERROR");
+ delete fmt4;
+ }
+
+ ec = U_ZERO_ERROR;
+ NumberingSystem *ns = NumberingSystem::createInstance(ec);
+ if (U_FAILURE(ec)) {
+ dataerrln("FAIL: NumberingSystem::createInstance(ec); - %s", u_errorName(ec));
+ }
+
+ if ( ns != NULL ) {
+ ns->getDynamicClassID();
+ ns->getStaticClassID();
+ } else {
+ errln("FAIL: getInstance() returned NULL.");
+ }
+
+ NumberingSystem *ns1 = new NumberingSystem(*ns);
+ if (ns1 == NULL) {
+ errln("FAIL: NumberSystem copy constructor returned NULL.");
+ }
+
+ delete ns1;
+ delete ns;
+
+}
+
+
+void
+NumberFormatTest::TestMultiCurrencySign() {
+ const char* DATA[][6] = {
+ // the fields in the following test are:
+ // locale,
+ // currency pattern (with negative pattern),
+ // currency number to be formatted,
+ // currency format using currency symbol name, such as "$" for USD,
+ // currency format using currency ISO name, such as "USD",
+ // currency format using plural name, such as "US dollars".
+ // 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 dollars1.00"},
+ // for CHINA locale
+ {"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};
+ UnicodeString doubleCurrencyStr(doubleCurrencySign);
+ const UChar tripleCurrencySign[] = {0xA4, 0xA4, 0xA4, 0};
+ UnicodeString tripleCurrencyStr(tripleCurrencySign);
+
+ for (uint32_t i=0; i<UPRV_LENGTHOF(DATA); ++i) {
+ const char* locale = DATA[i][0];
+ UnicodeString pat = ctou(DATA[i][1]);
+ double numberToBeFormat = atof(DATA[i][2]);
+ UErrorCode status = U_ZERO_ERROR;
+ DecimalFormatSymbols* sym = new DecimalFormatSymbols(Locale(locale), status);
+ if (U_FAILURE(status)) {
+ delete sym;
+ continue;
+ }
+ for (int j=1; j<=3; ++j) {
+ // j represents the number of currency sign in the pattern.
+ if (j == 2) {
+ pat = pat.findAndReplace(ctou("\\u00A4"), doubleCurrencyStr);
+ } else if (j == 3) {
+ pat = pat.findAndReplace(ctou("\\u00A4\\u00A4"), tripleCurrencyStr);
+ }
+
+ DecimalFormat* fmt = new DecimalFormat(pat, new DecimalFormatSymbols(*sym), status);
+ if (U_FAILURE(status)) {
+ errln("FAILED init DecimalFormat ");
+ delete fmt;
+ continue;
+ }
+ UnicodeString s;
+ ((NumberFormat*) fmt)->format(numberToBeFormat, s);
+ // DATA[i][3] is the currency format result using a
+ // single currency sign.
+ // DATA[i][4] is the currency format result using
+ // double currency sign.
+ // DATA[i][5] is the currency format result using
+ // triple currency sign.
+ // DATA[i][j+2] is the currency format result using
+ // 'j' number of currency sign.
+ UnicodeString currencyFormatResult = ctou(DATA[i][2+j]);
+ if (s.compare(currencyFormatResult)) {
+ errln("FAIL format: Expected " + currencyFormatResult + "; Got " + s);
+ }
+ // mix style parsing
+ for (int k=3; k<=5; ++k) {
+ // DATA[i][3] is the currency format result using a
+ // single currency sign.
+ // DATA[i][4] is the currency format result using
+ // double currency sign.
+ // DATA[i][5] is the currency format result using
+ // triple currency sign.
+ UnicodeString oneCurrencyFormat = ctou(DATA[i][k]);
+ UErrorCode status = U_ZERO_ERROR;
+ Formattable parseRes;
+ fmt->parse(oneCurrencyFormat, parseRes, status);
+ if (U_FAILURE(status) ||
+ (parseRes.getType() == Formattable::kDouble &&
+ parseRes.getDouble() != numberToBeFormat) ||
+ (parseRes.getType() == Formattable::kLong &&
+ parseRes.getLong() != numberToBeFormat)) {
+ errln("FAILED parse " + oneCurrencyFormat + "; (i, j, k): " +
+ i + ", " + j + ", " + k);
+ }
+ }
+ delete fmt;
+ }
+ delete sym;
+ }
+}
+
+
+void
+NumberFormatTest::TestCurrencyFormatForMixParsing() {
+ UErrorCode status = U_ZERO_ERROR;
+ MeasureFormat* curFmt = MeasureFormat::createCurrencyFormat(Locale("en_US"), status);
+ if (U_FAILURE(status)) {
+ delete curFmt;
+ return;
+ }
+ const char* formats[] = {
+ "$1,234.56", // string to be parsed
+ "USD1,234.56",
+ "US dollars1,234.56",
+ // "1,234.56 US dollars" // Fails in 62 because currency format is not compatible with pattern.
+ };
+ const CurrencyAmount* curramt = NULL;
+ for (uint32_t i = 0; i < UPRV_LENGTHOF(formats); ++i) {
+ UnicodeString stringToBeParsed = ctou(formats[i]);
+ logln(UnicodeString("stringToBeParsed: ") + stringToBeParsed);
+ Formattable result;
+ UErrorCode status = U_ZERO_ERROR;
+ curFmt->parseObject(stringToBeParsed, result, status);
+ if (U_FAILURE(status)) {
+ errln("FAIL: measure format parsing: '%s' ec: %s", formats[i], u_errorName(status));
+ } else if (result.getType() != Formattable::kObject ||
+ (curramt = dynamic_cast<const CurrencyAmount*>(result.getObject())) == NULL ||
+ curramt->getNumber().getDouble() != 1234.56 ||
+ UnicodeString(curramt->getISOCurrency()).compare(ISO_CURRENCY_USD)
+ ) {
+ errln("FAIL: getCurrencyFormat of default locale (en_US) failed roundtripping the number ");
+ if (curramt->getNumber().getDouble() != 1234.56) {
+ errln((UnicodeString)"wong number, expect: 1234.56" + ", got: " + curramt->getNumber().getDouble());
+ }
+ if (curramt->getISOCurrency() != ISO_CURRENCY_USD) {
+ errln((UnicodeString)"wong currency, expect: USD" + ", got: " + curramt->getISOCurrency());
+ }
+ }
+ }
+ delete curFmt;
+}
+
+
+/** Starting in ICU 62, strict mode is actually strict with currency formats. */
+void NumberFormatTest::TestMismatchedCurrencyFormatFail() {
+ IcuTestErrorCode status(*this, "TestMismatchedCurrencyFormatFail");
+ LocalPointer<DecimalFormat> df(
+ dynamic_cast<DecimalFormat*>(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
+ UErrorCode status = U_ZERO_ERROR;
+ DecimalFormatSymbols* sym = new DecimalFormatSymbols(Locale("en_US"), status);
+ if (U_FAILURE(status)) {
+ delete sym;
+ return;
+ }
+ UnicodeString pat;
+ UChar currency = 0x00A4;
+ // "\xA4#,##0.00;-\xA4#,##0.00"
+ pat.append(currency).append(currency).append(currency).append("#,##0.00;-").append(currency).append(currency).append(currency).append("#,##0.00");
+ DecimalFormat* fmt = new DecimalFormat(pat, sym, status);
+ if (U_FAILURE(status)) {
+ delete fmt;
+ errln("failed to new DecimalFormat in TestDecimalFormatCurrencyParse");
+ return;
+ }
+ const char* DATA[][2] = {
+ // the data are:
+ // string to be parsed, the parsed result (number)
+ {"$1.00", "1"},
+ {"USD1.00", "1"},
+ {"1.00 US dollar", "1"},
+ {"$1,234.56", "1234.56"},
+ {"USD1,234.56", "1234.56"},
+ {"1,234.56 US dollar", "1234.56"},
+ };
+ // 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) ||
+ (result.getType() == Formattable::kLong &&
+ result.getLong() != parsedResult)) {
+ errln((UnicodeString)"FAIL parse: Expected " + parsedResult);
+ }
+ }
+ delete fmt;
+}
+
+
+void
+NumberFormatTest::TestCurrencyIsoPluralFormat() {
+ static const char* DATA[][6] = {
+ // the data are:
+ // locale,
+ // currency amount to be formatted,
+ // currency ISO code to be formatted,
+ // format result using CURRENCYSTYLE,
+ // format result using ISOCURRENCYSTYLE,
+ // format result using PLURALCURRENCYSTYLE,
+
+ {"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"},
+ {"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", "INR\\u00A01,00", "INR\\u00A01,00", "1,00 rupia india"},
+ };
+ static const UNumberFormatStyle currencyStyles[] = {
+ UNUM_CURRENCY,
+ UNUM_CURRENCY_ISO,
+ UNUM_CURRENCY_PLURAL
+ };
+
+ for (int32_t i=0; i<UPRV_LENGTHOF(DATA); ++i) {
+ const char* localeString = DATA[i][0];
+ double numberToBeFormat = atof(DATA[i][1]);
+ const char* currencyISOCode = DATA[i][2];
+ logln(UnicodeString(u"Locale: ") + localeString + "; amount: " + numberToBeFormat);
+ Locale locale(localeString);
+ for (int32_t kIndex = 0; kIndex < UPRV_LENGTHOF(currencyStyles); ++kIndex) {
+ UNumberFormatStyle k = currencyStyles[kIndex];
+ logln(UnicodeString(u"UNumberFormatStyle: ") + k);
+ UErrorCode status = U_ZERO_ERROR;
+ NumberFormat* numFmt = NumberFormat::createInstance(locale, k, status);
+ if (U_FAILURE(status)) {
+ delete numFmt;
+ dataerrln((UnicodeString)"can not create instance, locale:" + localeString + ", style: " + k + " - " + u_errorName(status));
+ continue;
+ }
+ UChar currencyCode[4];
+ u_charsToUChars(currencyISOCode, currencyCode, 4);
+ numFmt->setCurrency(currencyCode, status);
+ if (U_FAILURE(status)) {
+ delete numFmt;
+ errln((UnicodeString)"can not set currency:" + currencyISOCode);
+ continue;
+ }
+
+ UnicodeString strBuf;
+ numFmt->format(numberToBeFormat, strBuf);
+ int resultDataIndex = 3 + kIndex;
+ // DATA[i][resultDataIndex] is the currency format result
+ // using 'k' currency style.
+ UnicodeString formatResult = ctou(DATA[i][resultDataIndex]);
+ 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.
+ // DATA[i][4] is the currency format result using
+ // ISOCURRENCYSTYLE formatter.
+ // DATA[i][5] is the currency format result using
+ // PLURALCURRENCYSTYLE formatter.
+ UnicodeString oneCurrencyFormatResult = ctou(DATA[i][j]);
+ UErrorCode status = U_ZERO_ERROR;
+ Formattable parseResult;
+ 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");
+ if (parseResult.getType() == Formattable::kDouble) {
+ errln((UnicodeString)"expected: " + numberToBeFormat + "; actual: " +parseResult.getDouble());
+ } else {
+ errln((UnicodeString)"expected: " + numberToBeFormat + "; actual: " +parseResult.getLong());
+ }
+ }
+ }
+ delete numFmt;
+ }
+ }
+}
+
+void
+NumberFormatTest::TestCurrencyParsing() {
+ static const char* DATA[][6] = {
+ // the data are:
+ // locale,
+ // currency amount to be formatted,
+ // currency ISO code to be formatted,
+ // format result using CURRENCYSTYLE,
+ // format result using ISOCURRENCYSTYLE,
+ // format result using PLURALCURRENCYSTYLE,
+ {"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", "\\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; i< UPRV_LENGTHOF(DATA); ++i) { /* i = test case # - should be i=0*/
+ for (int32_t kIndex = 2; kIndex < UPRV_LENGTHOF(currencyStyles); ++kIndex) {
+ UNumberFormatStyle k = currencyStyles[kIndex]; /* k = style */
+ const char* localeString = DATA[i][0];
+ double numberToBeFormat = atof(DATA[i][1]);
+ const char* currencyISOCode = DATA[i][2];
+ Locale locale(localeString);
+ UErrorCode status = U_ZERO_ERROR;
+ NumberFormat* numFmt = NumberFormat::createInstance(locale, k, status);
+ logln("#%d NumberFormat(%s, %s) Currency=%s\n",
+ i, localeString, currencyStyleNames[kIndex],
+ currencyISOCode);
+
+ if (U_FAILURE(status)) {
+ delete numFmt;
+ dataerrln((UnicodeString)"can not create instance, locale:" + localeString + ", style: " + k + " - " + u_errorName(status));
+ continue;
+ }
+ UChar currencyCode[4];
+ u_charsToUChars(currencyISOCode, currencyCode, 4);
+ numFmt->setCurrency(currencyCode, status);
+ if (U_FAILURE(status)) {
+ delete numFmt;
+ errln((UnicodeString)"can not set currency:" + currencyISOCode);
+ continue;
+ }
+
+ UnicodeString strBuf;
+ numFmt->format(numberToBeFormat, strBuf);
+ int resultDataIndex = 3 + kIndex;
+ // DATA[i][resultDataIndex] is the currency format result
+ // using 'k' currency style.
+ UnicodeString formatResult = ctou(DATA[i][resultDataIndex]);
+ 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.
+ // DATA[i][4] is the currency format result using
+ // ISOCURRENCYSTYLE formatter.
+ // DATA[i][5] is the currency format result using
+ // PLURALCURRENCYSTYLE formatter.
+ 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: 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 (double): " +parseResult.getDouble());
+ } else {
+ errln((UnicodeString)"expected: " + numberToBeFormat + "; actual (long): " +parseResult.getLong());
+ }
+ errln((UnicodeString)" round-trip would be: " + strBuf);
+ }
+ }
+ delete numFmt;
+ }
+ }
+#ifdef NUMFMTST_CACHE_DEBUG
+}
+#endif
+}
+
+
+void
+NumberFormatTest::TestParseCurrencyInUCurr() {
+ const char* DATA[] = {
+ "1.00 US DOLLAR", // case in-sensitive
+ "$1.00",
+ "USD1.00",
+ "US dollar1.00",
+ "US dollars1.00",
+ "$1.00",
+ "A$1.00",
+ "ADP1.00",
+ "ADP1.00",
+ "AED1.00",
+ "AED1.00",
+ "AFA1.00",
+ "AFA1.00",
+ "AFN1.00",
+ "ALL1.00",
+ "AMD1.00",
+ "ANG1.00",
+ "AOA1.00",
+ "AOK1.00",
+ "AOK1.00",
+ "AON1.00",
+ "AON1.00",
+ "AOR1.00",
+ "AOR1.00",
+ "ARS1.00",
+ "ARA1.00",
+ "ARA1.00",
+ "ARP1.00",
+ "ARP1.00",
+ "ARS1.00",
+ "ATS1.00",
+ "ATS1.00",
+ "AUD1.00",
+ "AWG1.00",
+ "AZM1.00",
+ "AZM1.00",
+ "AZN1.00",
+ "Afghan Afghani (1927\\u20132002)1.00",
+ "Afghan afghani (1927\\u20132002)1.00",
+ "Afghan Afghani1.00",
+ "Afghan Afghanis1.00",
+ "Albanian Lek1.00",
+ "Albanian lek1.00",
+ "Albanian lek\\u00eb1.00",
+ "Algerian Dinar1.00",
+ "Algerian dinar1.00",
+ "Algerian dinars1.00",
+ "Andorran Peseta1.00",
+ "Andorran peseta1.00",
+ "Andorran pesetas1.00",
+ "Angolan Kwanza (1977\\u20131991)1.00",
+ "Angolan Readjusted Kwanza (1995\\u20131999)1.00",
+ "Angolan Kwanza1.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\\u20131991)1.00",
+ "Angolan readjusted kwanzas (1995\\u20131999)1.00",
+ "Angolan kwanzas1.00",
+ "Angolan new kwanza (1990\\u20132000)1.00",
+ "Angolan new kwanzas (1990\\u20132000)1.00",
+ "Argentine Austral1.00",
+ "Argentine Peso (1983\\u20131985)1.00",
+ "Argentine Peso1.00",
+ "Argentine austral1.00",
+ "Argentine australs1.00",
+ "Argentine peso (1983\\u20131985)1.00",
+ "Argentine peso1.00",
+ "Argentine pesos (1983\\u20131985)1.00",
+ "Argentine pesos1.00",
+ "Armenian Dram1.00",
+ "Armenian dram1.00",
+ "Armenian drams1.00",
+ "Aruban Florin1.00",
+ "Aruban florin1.00",
+ "Australian Dollar1.00",
+ "Australian dollar1.00",
+ "Australian dollars1.00",
+ "Austrian Schilling1.00",
+ "Austrian schilling1.00",
+ "Austrian schillings1.00",
+ "Azerbaijani Manat (1993\\u20132006)1.00",
+ "Azerbaijani Manat1.00",
+ "Azerbaijani manat (1993\\u20132006)1.00",
+ "Azerbaijani manat1.00",
+ "Azerbaijani manats (1993\\u20132006)1.00",
+ "Azerbaijani manats1.00",
+ "BAD1.00",
+ "BAD1.00",
+ "BAM1.00",
+ "BBD1.00",
+ "BDT1.00",
+ "BEC1.00",
+ "BEC1.00",
+ "BEF1.00",
+ "BEL1.00",
+ "BEL1.00",
+ "BGL1.00",
+ "BGN1.00",
+ "BGN1.00",
+ "BHD1.00",
+ "BIF1.00",
+ "BMD1.00",
+ "BND1.00",
+ "BOB1.00",
+ "BOP1.00",
+ "BOP1.00",
+ "BOV1.00",
+ "BOV1.00",
+ "BRB1.00",
+ "BRB1.00",
+ "BRC1.00",
+ "BRC1.00",
+ "BRE1.00",
+ "BRE1.00",
+ "BRL1.00",
+ "BRN1.00",
+ "BRN1.00",
+ "BRR1.00",
+ "BRR1.00",
+ "BSD1.00",
+ "BSD1.00",
+ "BTN1.00",
+ "BUK1.00",
+ "BUK1.00",
+ "BWP1.00",
+ "BYB1.00",
+ "BYB1.00",
+ "BYR1.00",
+ "BZD1.00",
+ "Bahamian Dollar1.00",
+ "Bahamian dollar1.00",
+ "Bahamian dollars1.00",
+ "Bahraini Dinar1.00",
+ "Bahraini dinar1.00",
+ "Bahraini dinars1.00",
+ "Bangladeshi Taka1.00",
+ "Bangladeshi taka1.00",
+ "Bangladeshi takas1.00",
+ "Barbadian Dollar1.00",
+ "Barbadian dollar1.00",
+ "Barbadian dollars1.00",
+ "Belarusian Ruble (1994\\u20131999)1.00",
+ "Belarusian Ruble1.00",
+ "Belarusian ruble (1994\\u20131999)1.00",
+ "Belarusian rubles (1994\\u20131999)1.00",
+ "Belarusian ruble1.00",
+ "Belarusian rubles1.00",
+ "Belgian Franc (convertible)1.00",
+ "Belgian Franc (financial)1.00",
+ "Belgian Franc1.00",
+ "Belgian franc (convertible)1.00",
+ "Belgian franc (financial)1.00",
+ "Belgian franc1.00",
+ "Belgian francs (convertible)1.00",
+ "Belgian francs (financial)1.00",
+ "Belgian francs1.00",
+ "Belize Dollar1.00",
+ "Belize dollar1.00",
+ "Belize dollars1.00",
+ "Bermudan Dollar1.00",
+ "Bermudan dollar1.00",
+ "Bermudan dollars1.00",
+ "Bhutanese Ngultrum1.00",
+ "Bhutanese ngultrum1.00",
+ "Bhutanese ngultrums1.00",
+ "Bolivian Mvdol1.00",
+ "Bolivian Peso1.00",
+ "Bolivian mvdol1.00",
+ "Bolivian mvdols1.00",
+ "Bolivian peso1.00",
+ "Bolivian pesos1.00",
+ "Bolivian Boliviano1.00",
+ "Bolivian Boliviano1.00",
+ "Bolivian Bolivianos1.00",
+ "Bosnia-Herzegovina Convertible Mark1.00",
+ "Bosnia-Herzegovina Dinar (1992\\u20131994)1.00",
+ "Bosnia-Herzegovina convertible mark1.00",
+ "Bosnia-Herzegovina convertible marks1.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\\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\\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 Pound1.00",
+ "British pound1.00",
+ "British pounds1.00",
+ "Brunei Dollar1.00",
+ "Brunei dollar1.00",
+ "Brunei dollars1.00",
+ "Bulgarian Hard Lev1.00",
+ "Bulgarian Lev1.00",
+ "Bulgarian Leva1.00",
+ "Bulgarian hard lev1.00",
+ "Bulgarian hard leva1.00",
+ "Bulgarian lev1.00",
+ "Burmese Kyat1.00",
+ "Burmese kyat1.00",
+ "Burmese kyats1.00",
+ "Burundian Franc1.00",
+ "Burundian franc1.00",
+ "Burundian francs1.00",
+ "CA$1.00",
+ "CAD1.00",
+ "CDF1.00",
+ "CDF1.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",
+ "CFPF1.00",
+ "CHE1.00",
+ "CHE1.00",
+ "CHF1.00",
+ "CHW1.00",
+ "CHW1.00",
+ "CLF1.00",
+ "CLF1.00",
+ "CLP1.00",
+ "CNY1.00",
+ "COP1.00",
+ "COU1.00",
+ "COU1.00",
+ "CRC1.00",
+ "CSD1.00",
+ "CSD1.00",
+ "CSK1.00",
+ "CSK1.00",
+ "CUP1.00",
+ "CUP1.00",
+ "CVE1.00",
+ "CYP1.00",
+ "CZK1.00",
+ "Cambodian Riel1.00",
+ "Cambodian riel1.00",
+ "Cambodian riels1.00",
+ "Canadian Dollar1.00",
+ "Canadian dollar1.00",
+ "Canadian dollars1.00",
+ "Cape Verdean Escudo1.00",
+ "Cape Verdean escudo1.00",
+ "Cape Verdean escudos1.00",
+ "Cayman Islands Dollar1.00",
+ "Cayman Islands dollar1.00",
+ "Cayman Islands dollars1.00",
+ "Chilean Peso1.00",
+ "Chilean Unit of Account (UF)1.00",
+ "Chilean peso1.00",
+ "Chilean pesos1.00",
+ "Chilean unit of account (UF)1.00",
+ "Chilean units of account (UF)1.00",
+ "Chinese Yuan1.00",
+ "Chinese yuan1.00",
+ "Colombian Peso1.00",
+ "Colombian peso1.00",
+ "Colombian pesos1.00",
+ "Comorian Franc1.00",
+ "Comorian franc1.00",
+ "Comorian francs1.00",
+ "Congolese Franc1.00",
+ "Congolese franc1.00",
+ "Congolese francs1.00",
+ "Costa Rican Col\\u00f3n1.00",
+ "Costa Rican col\\u00f3n1.00",
+ "Costa Rican col\\u00f3ns1.00",
+ "Croatian Dinar1.00",
+ "Croatian Kuna1.00",
+ "Croatian dinar1.00",
+ "Croatian dinars1.00",
+ "Croatian kuna1.00",
+ "Croatian kunas1.00",
+ "Cuban Peso1.00",
+ "Cuban peso1.00",
+ "Cuban pesos1.00",
+ "Cypriot Pound1.00",
+ "Cypriot pound1.00",
+ "Cypriot pounds1.00",
+ "Czech Koruna1.00",
+ "Czech koruna1.00",
+ "Czech korunas1.00",
+ "Czechoslovak Hard Koruna1.00",
+ "Czechoslovak hard koruna1.00",
+ "Czechoslovak hard korunas1.00",
+ "DDM1.00",
+ "DDM1.00",
+ "DEM1.00",
+ "DEM1.00",
+ "DJF1.00",
+ "DKK1.00",
+ "DOP1.00",
+ "DZD1.00",
+ "Danish Krone1.00",
+ "Danish krone1.00",
+ "Danish kroner1.00",
+ "German Mark1.00",
+ "German mark1.00",
+ "German marks1.00",
+ "Djiboutian Franc1.00",
+ "Djiboutian franc1.00",
+ "Djiboutian francs1.00",
+ "Dominican Peso1.00",
+ "Dominican peso1.00",
+ "Dominican pesos1.00",
+ "EC$1.00",
+ "ECS1.00",
+ "ECS1.00",
+ "ECV1.00",
+ "ECV1.00",
+ "EEK1.00",
+ "EEK1.00",
+ "EGP1.00",
+ "EGP1.00",
+ "ERN1.00",
+ "ERN1.00",
+ "ESA1.00",
+ "ESA1.00",
+ "ESB1.00",
+ "ESB1.00",
+ "ESP1.00",
+ "ETB1.00",
+ "EUR1.00",
+ "East Caribbean Dollar1.00",
+ "East Caribbean dollar1.00",
+ "East Caribbean dollars1.00",
+ "East German Mark1.00",
+ "East German mark1.00",
+ "East German marks1.00",
+ "Ecuadorian Sucre1.00",
+ "Ecuadorian Unit of Constant Value1.00",
+ "Ecuadorian sucre1.00",
+ "Ecuadorian sucres1.00",
+ "Ecuadorian unit of constant value1.00",
+ "Ecuadorian units of constant value1.00",
+ "Egyptian Pound1.00",
+ "Egyptian pound1.00",
+ "Egyptian pounds1.00",
+ "Salvadoran Col\\u00f3n1.00",
+ "Salvadoran col\\u00f3n1.00",
+ "Salvadoran colones1.00",
+ "Equatorial Guinean Ekwele1.00",
+ "Equatorial Guinean ekwele1.00",
+ "Eritrean Nakfa1.00",
+ "Eritrean nakfa1.00",
+ "Eritrean nakfas1.00",
+ "Estonian Kroon1.00",
+ "Estonian kroon1.00",
+ "Estonian kroons1.00",
+ "Ethiopian Birr1.00",
+ "Ethiopian birr1.00",
+ "Ethiopian birrs1.00",
+ "Euro1.00",
+ "European Composite Unit1.00",
+ "European Currency Unit1.00",
+ "European Monetary Unit1.00",
+ "European Unit of Account (XBC)1.00",
+ "European Unit of Account (XBD)1.00",
+ "European composite unit1.00",
+ "European composite units1.00",
+ "European currency unit1.00",
+ "European currency units1.00",
+ "European monetary unit1.00",
+ "European monetary units1.00",
+ "European unit of account (XBC)1.00",
+ "European unit of account (XBD)1.00",
+ "European units of account (XBC)1.00",
+ "European units of account (XBD)1.00",
+ "FIM1.00",
+ "FIM1.00",
+ "FJD1.00",
+ "FKP1.00",
+ "FKP1.00",
+ "FRF1.00",
+ "FRF1.00",
+ "Falkland Islands Pound1.00",
+ "Falkland Islands pound1.00",
+ "Falkland Islands pounds1.00",
+ "Fijian Dollar1.00",
+ "Fijian dollar1.00",
+ "Fijian dollars1.00",
+ "Finnish Markka1.00",
+ "Finnish markka1.00",
+ "Finnish markkas1.00",
+ "CHF1.00",
+ "French Franc1.00",
+ "French Gold Franc1.00",
+ "French UIC-Franc1.00",
+ "French UIC-franc1.00",
+ "French UIC-francs1.00",
+ "French franc1.00",
+ "French francs1.00",
+ "French gold franc1.00",
+ "French gold francs1.00",
+ "GBP1.00",
+ "GEK1.00",
+ "GEK1.00",
+ "GEL1.00",
+ "GHC1.00",
+ "GHC1.00",
+ "GHS1.00",
+ "GIP1.00",
+ "GIP1.00",
+ "GMD1.00",
+ "GMD1.00",
+ "GNF1.00",
+ "GNS1.00",
+ "GNS1.00",
+ "GQE1.00",
+ "GQE1.00",
+ "GRD1.00",
+ "GRD1.00",
+ "GTQ1.00",
+ "GWE1.00",
+ "GWE1.00",
+ "GWP1.00",
+ "GWP1.00",
+ "GYD1.00",
+ "Gambian Dalasi1.00",
+ "Gambian dalasi1.00",
+ "Gambian dalasis1.00",
+ "Georgian Kupon Larit1.00",
+ "Georgian Lari1.00",
+ "Georgian kupon larit1.00",
+ "Georgian kupon larits1.00",
+ "Georgian lari1.00",
+ "Georgian laris1.00",
+ "Ghanaian Cedi (1979\\u20132007)1.00",
+ "Ghanaian Cedi1.00",
+ "Ghanaian cedi (1979\\u20132007)1.00",
+ "Ghanaian cedi1.00",
+ "Ghanaian cedis (1979\\u20132007)1.00",
+ "Ghanaian cedis1.00",
+ "Gibraltar Pound1.00",
+ "Gibraltar pound1.00",
+ "Gibraltar pounds1.00",
+ "Gold1.00",
+ "Gold1.00",
+ "Greek Drachma1.00",
+ "Greek drachma1.00",
+ "Greek drachmas1.00",
+ "Guatemalan Quetzal1.00",
+ "Guatemalan quetzal1.00",
+ "Guatemalan quetzals1.00",
+ "Guinean Franc1.00",
+ "Guinean Syli1.00",
+ "Guinean franc1.00",
+ "Guinean francs1.00",
+ "Guinean syli1.00",
+ "Guinean sylis1.00",
+ "Guinea-Bissau Peso1.00",
+ "Guinea-Bissau peso1.00",
+ "Guinea-Bissau pesos1.00",
+ "Guyanaese Dollar1.00",
+ "Guyanaese dollar1.00",
+ "Guyanaese dollars1.00",
+ "HK$1.00",
+ "HKD1.00",
+ "HNL1.00",
+ "HRD1.00",
+ "HRD1.00",
+ "HRK1.00",
+ "HRK1.00",
+ "HTG1.00",
+ "HTG1.00",
+ "HUF1.00",
+ "Haitian Gourde1.00",
+ "Haitian gourde1.00",
+ "Haitian gourdes1.00",
+ "Honduran Lempira1.00",
+ "Honduran lempira1.00",
+ "Honduran lempiras1.00",
+ "Hong Kong Dollar1.00",
+ "Hong Kong dollar1.00",
+ "Hong Kong dollars1.00",
+ "Hungarian Forint1.00",
+ "Hungarian forint1.00",
+ "Hungarian forints1.00",
+ "IDR1.00",
+ "IEP1.00",
+ "ILP1.00",
+ "ILP1.00",
+ "ILS1.00",
+ "INR1.00",
+ "IQD1.00",
+ "IRR1.00",
+ "ISK1.00",
+ "ISK1.00",
+ "ITL1.00",
+ "Icelandic Kr\\u00f3na1.00",
+ "Icelandic kr\\u00f3na1.00",
+ "Icelandic kr\\u00f3nur1.00",
+ "Indian Rupee1.00",
+ "Indian rupee1.00",
+ "Indian rupees1.00",
+ "Indonesian Rupiah1.00",
+ "Indonesian rupiah1.00",
+ "Indonesian rupiahs1.00",
+ "Iranian Rial1.00",
+ "Iranian rial1.00",
+ "Iranian rials1.00",
+ "Iraqi Dinar1.00",
+ "Iraqi dinar1.00",
+ "Iraqi dinars1.00",
+ "Irish Pound1.00",
+ "Irish pound1.00",
+ "Irish pounds1.00",
+ "Israeli Pound1.00",
+ "Israeli new shekel1.00",
+ "Israeli pound1.00",
+ "Israeli pounds1.00",
+ "Italian Lira1.00",
+ "Italian lira1.00",
+ "Italian liras1.00",
+ "JMD1.00",
+ "JOD1.00",
+ "JPY1.00",
+ "Jamaican Dollar1.00",
+ "Jamaican dollar1.00",
+ "Jamaican dollars1.00",
+ "Japanese Yen1.00",
+ "Japanese yen1.00",
+ "Jordanian Dinar1.00",
+ "Jordanian dinar1.00",
+ "Jordanian dinars1.00",
+ "KES1.00",
+ "KGS1.00",
+ "KHR1.00",
+ "KMF1.00",
+ "KPW1.00",
+ "KPW1.00",
+ "KRW1.00",
+ "KWD1.00",
+ "KYD1.00",
+ "KYD1.00",
+ "KZT1.00",
+ "Kazakhstani Tenge1.00",
+ "Kazakhstani tenge1.00",
+ "Kazakhstani tenges1.00",
+ "Kenyan Shilling1.00",
+ "Kenyan shilling1.00",
+ "Kenyan shillings1.00",
+ "Kuwaiti Dinar1.00",
+ "Kuwaiti dinar1.00",
+ "Kuwaiti dinars1.00",
+ "Kyrgystani Som1.00",
+ "Kyrgystani som1.00",
+ "Kyrgystani soms1.00",
+ "HNL1.00",
+ "LAK1.00",
+ "LAK1.00",
+ "LBP1.00",
+ "LKR1.00",
+ "LRD1.00",
+ "LRD1.00",
+ "LSL1.00",
+ "LTL1.00",
+ "LTL1.00",
+ "LTT1.00",
+ "LTT1.00",
+ "LUC1.00",
+ "LUC1.00",
+ "LUF1.00",
+ "LUF1.00",
+ "LUL1.00",
+ "LUL1.00",
+ "LVL1.00",
+ "LVL1.00",
+ "LVR1.00",
+ "LVR1.00",
+ "LYD1.00",
+ "Laotian Kip1.00",
+ "Laotian kip1.00",
+ "Laotian kips1.00",
+ "Latvian Lats1.00",
+ "Latvian Ruble1.00",
+ "Latvian lats1.00",
+ "Latvian lati1.00",
+ "Latvian ruble1.00",
+ "Latvian rubles1.00",
+ "Lebanese Pound1.00",
+ "Lebanese pound1.00",
+ "Lebanese pounds1.00",
+ "Lesotho Loti1.00",
+ "Lesotho loti1.00",
+ "Lesotho lotis1.00",
+ "Liberian Dollar1.00",
+ "Liberian dollar1.00",
+ "Liberian dollars1.00",
+ "Libyan Dinar1.00",
+ "Libyan dinar1.00",
+ "Libyan dinars1.00",
+ "Lithuanian Litas1.00",
+ "Lithuanian Talonas1.00",
+ "Lithuanian litas1.00",
+ "Lithuanian litai1.00",
+ "Lithuanian talonas1.00",
+ "Lithuanian talonases1.00",
+ "Luxembourgian Convertible Franc1.00",
+ "Luxembourg Financial Franc1.00",
+ "Luxembourgian Franc1.00",
+ "Luxembourgian convertible franc1.00",
+ "Luxembourgian convertible francs1.00",
+ "Luxembourg financial franc1.00",
+ "Luxembourg financial francs1.00",
+ "Luxembourgian franc1.00",
+ "Luxembourgian francs1.00",
+ "MAD1.00",
+ "MAD1.00",
+ "MAF1.00",
+ "MAF1.00",
+ "MDL1.00",
+ "MDL1.00",
+ "MX$1.00",
+ "MGA1.00",
+ "MGA1.00",
+ "MGF1.00",
+ "MGF1.00",
+ "MKD1.00",
+ "MLF1.00",
+ "MLF1.00",
+ "MMK1.00",
+ "MMK1.00",
+ "MNT1.00",
+ "MOP1.00",
+ "MOP1.00",
+ "MRO1.00",
+ "MTL1.00",
+ "MTP1.00",
+ "MTP1.00",
+ "MUR1.00",
+ "MUR1.00",
+ "MVR1.00",
+ "MVR1.00",
+ "MWK1.00",
+ "MXN1.00",
+ "MXP1.00",
+ "MXP1.00",
+ "MXV1.00",
+ "MXV1.00",
+ "MYR1.00",
+ "MZE1.00",
+ "MZE1.00",
+ "MZM1.00",
+ "MZN1.00",
+ "Macanese Pataca1.00",
+ "Macanese pataca1.00",
+ "Macanese patacas1.00",
+ "Macedonian Denar1.00",
+ "Macedonian denar1.00",
+ "Macedonian denari1.00",
+ "Malagasy Ariaries1.00",
+ "Malagasy Ariary1.00",
+ "Malagasy Ariary1.00",
+ "Malagasy Franc1.00",
+ "Malagasy franc1.00",
+ "Malagasy francs1.00",
+ "Malawian Kwacha1.00",
+ "Malawian Kwacha1.00",
+ "Malawian Kwachas1.00",
+ "Malaysian Ringgit1.00",
+ "Malaysian ringgit1.00",
+ "Malaysian ringgits1.00",
+ "Maldivian Rufiyaa1.00",
+ "Maldivian rufiyaa1.00",
+ "Maldivian rufiyaas1.00",
+ "Malian Franc1.00",
+ "Malian franc1.00",
+ "Malian francs1.00",
+ "Maltese Lira1.00",
+ "Maltese Pound1.00",
+ "Maltese lira1.00",
+ "Maltese lira1.00",
+ "Maltese pound1.00",
+ "Maltese pounds1.00",
+ "Mauritanian Ouguiya1.00",
+ "Mauritanian ouguiya1.00",
+ "Mauritanian ouguiyas1.00",
+ "Mauritian Rupee1.00",
+ "Mauritian rupee1.00",
+ "Mauritian rupees1.00",
+ "Mexican Peso1.00",
+ "Mexican Silver Peso (1861\\u20131992)1.00",
+ "Mexican Investment Unit1.00",
+ "Mexican peso1.00",
+ "Mexican pesos1.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",
+ "Moldovan leu1.00",
+ "Moldovan lei1.00",
+ "Mongolian Tugrik1.00",
+ "Mongolian tugrik1.00",
+ "Mongolian tugriks1.00",
+ "Moroccan Dirham1.00",
+ "Moroccan Franc1.00",
+ "Moroccan dirham1.00",
+ "Moroccan dirhams1.00",
+ "Moroccan franc1.00",
+ "Moroccan francs1.00",
+ "Mozambican Escudo1.00",
+ "Mozambican Metical1.00",
+ "Mozambican escudo1.00",
+ "Mozambican escudos1.00",
+ "Mozambican metical1.00",
+ "Mozambican meticals1.00",
+ "Myanmar Kyat1.00",
+ "Myanmar kyat1.00",
+ "Myanmar kyats1.00",
+ "NAD1.00",
+ "NGN1.00",
+ "NIC1.00",
+ "NIO1.00",
+ "NIO1.00",
+ "NLG1.00",
+ "NLG1.00",
+ "NOK1.00",
+ "NPR1.00",
+ "NT$1.00",
+ "NZ$1.00",
+ "NZD1.00",
+ "Namibian Dollar1.00",
+ "Namibian dollar1.00",
+ "Namibian dollars1.00",
+ "Nepalese Rupee1.00",
+ "Nepalese rupee1.00",
+ "Nepalese rupees1.00",
+ "Netherlands Antillean Guilder1.00",
+ "Netherlands Antillean guilder1.00",
+ "Netherlands Antillean guilders1.00",
+ "Dutch Guilder1.00",
+ "Dutch guilder1.00",
+ "Dutch guilders1.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\\u20131991)1.00",
+ "Nicaraguan c\\u00f3rdoba1.00",
+ "Nicaraguan c\\u00f3rdobas1.00",
+ "Nicaraguan c\\u00f3rdoba (1988\\u20131991)1.00",
+ "Nicaraguan c\\u00f3rdobas (1988\\u20131991)1.00",
+ "Nigerian Naira1.00",
+ "Nigerian naira1.00",
+ "Nigerian nairas1.00",
+ "North Korean Won1.00",
+ "North Korean won1.00",
+ "North Korean won1.00",
+ "Norwegian Krone1.00",
+ "Norwegian krone1.00",
+ "Norwegian kroner1.00",
+ "OMR1.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",
+ "PAB1.00",
+ "PAB1.00",
+ "PEI1.00",
+ "PEI1.00",
+ "PEN1.00",
+ "PEN1.00",
+ "PES1.00",
+ "PES1.00",
+ "PGK1.00",
+ "PGK1.00",
+ "PHP1.00",
+ "PKR1.00",
+ "PLN1.00",
+ "PLZ1.00",
+ "PLZ1.00",
+ "PTE1.00",
+ "PTE1.00",
+ "PYG1.00",
+ "Pakistani Rupee1.00",
+ "Pakistani rupee1.00",
+ "Pakistani rupees1.00",
+ "Palladium1.00",
+ "Palladium1.00",
+ "Panamanian Balboa1.00",
+ "Panamanian balboa1.00",
+ "Panamanian balboas1.00",
+ "Papua New Guinean Kina1.00",
+ "Papua New Guinean kina1.00",
+ "Papua New Guinean kina1.00",
+ "Paraguayan Guarani1.00",
+ "Paraguayan guarani1.00",
+ "Paraguayan guaranis1.00",
+ "Peruvian Inti1.00",
+ "Peruvian Sol1.00",
+ "Peruvian Sol (1863\\u20131965)1.00",
+ "Peruvian inti1.00",
+ "Peruvian intis1.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\\u20131995)1.00",
+ "Polish Zloty1.00",
+ "Polish zlotys1.00",
+ "Polish zloty (PLZ)1.00",
+ "Polish zloty1.00",
+ "Polish zlotys (PLZ)1.00",
+ "Portuguese Escudo1.00",
+ "Portuguese Guinea Escudo1.00",
+ "Portuguese Guinea escudo1.00",
+ "Portuguese Guinea escudos1.00",
+ "Portuguese escudo1.00",
+ "Portuguese escudos1.00",
+ "GTQ1.00",
+ "QAR1.00",
+ "Qatari Rial1.00",
+ "Qatari rial1.00",
+ "Qatari rials1.00",
+ "RHD1.00",
+ "RHD1.00",
+ "RINET Funds1.00",
+ "RINET Funds1.00",
+ "CN\\u00a51.00",
+ "ROL1.00",
+ "ROL1.00",
+ "RON1.00",
+ "RON1.00",
+ "RSD1.00",
+ "RSD1.00",
+ "RUB1.00",
+ "RUR1.00",
+ "RUR1.00",
+ "RWF1.00",
+ "RWF1.00",
+ "Rhodesian Dollar1.00",
+ "Rhodesian dollar1.00",
+ "Rhodesian dollars1.00",
+ "Romanian Leu1.00",
+ "Romanian lei1.00",
+ "Romanian leu1.00",
+ "Russian Ruble (1991\\u20131998)1.00",
+ "Russian Ruble1.00",
+ "Russian ruble (1991\\u20131998)1.00",
+ "Russian ruble1.00",
+ "Russian rubles (1991\\u20131998)1.00",
+ "Russian rubles1.00",
+ "Rwandan Franc1.00",
+ "Rwandan franc1.00",
+ "Rwandan francs1.00",
+ "SAR1.00",
+ "SBD1.00",
+ "SCR1.00",
+ "SDD1.00",
+ "SDD1.00",
+ "SDG1.00",
+ "SDG1.00",
+ "SDP1.00",
+ "SDP1.00",
+ "SEK1.00",
+ "SGD1.00",
+ "SHP1.00",
+ "SHP1.00",
+ "SIT1.00",
+ "SIT1.00",
+ "SKK1.00",
+ "SLL1.00",
+ "SLL1.00",
+ "SOS1.00",
+ "SRD1.00",
+ "SRD1.00",
+ "SRG1.00",
+ "STD1.00",
+ "SUR1.00",
+ "SUR1.00",
+ "SVC1.00",
+ "SVC1.00",
+ "SYP1.00",
+ "SZL1.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",
+ "Serbian Dinar1.00",
+ "Serbian dinar1.00",
+ "Serbian dinars1.00",
+ "Seychellois Rupee1.00",
+ "Seychellois rupee1.00",
+ "Seychellois rupees1.00",
+ "Sierra Leonean Leone1.00",
+ "Sierra Leonean leone1.00",
+ "Sierra Leonean leones1.00",
+ "Silver1.00",
+ "Silver1.00",
+ "Singapore Dollar1.00",
+ "Singapore dollar1.00",
+ "Singapore dollars1.00",
+ "Slovak Koruna1.00",
+ "Slovak koruna1.00",
+ "Slovak korunas1.00",
+ "Slovenian Tolar1.00",
+ "Slovenian tolar1.00",
+ "Slovenian tolars1.00",
+ "Solomon Islands Dollar1.00",
+ "Solomon Islands dollar1.00",
+ "Solomon Islands dollars1.00",
+ "Somali Shilling1.00",
+ "Somali shilling1.00",
+ "Somali shillings1.00",
+ "South African Rand (financial)1.00",
+ "South African Rand1.00",
+ "South African rand (financial)1.00",
+ "South African rand1.00",
+ "South African rands (financial)1.00",
+ "South African rand1.00",
+ "South Korean Won1.00",
+ "South Korean won1.00",
+ "South Korean won1.00",
+ "Soviet Rouble1.00",
+ "Soviet rouble1.00",
+ "Soviet roubles1.00",
+ "Spanish Peseta (A account)1.00",
+ "Spanish Peseta (convertible account)1.00",
+ "Spanish Peseta1.00",
+ "Spanish peseta (A account)1.00",
+ "Spanish peseta (convertible account)1.00",
+ "Spanish peseta1.00",
+ "Spanish pesetas (A account)1.00",
+ "Spanish pesetas (convertible account)1.00",
+ "Spanish pesetas1.00",
+ "Special Drawing Rights1.00",
+ "Sri Lankan Rupee1.00",
+ "Sri Lankan rupee1.00",
+ "Sri Lankan rupees1.00",
+ "Sudanese Pound1.00",
+ "Sudanese pound1.00",
+ "Sudanese pounds1.00",
+ "Surinamese Dollar1.00",
+ "Surinamese dollar1.00",
+ "Surinamese dollars1.00",
+ "Surinamese Guilder1.00",
+ "Surinamese guilder1.00",
+ "Surinamese guilders1.00",
+ "Swazi Lilangeni1.00",
+ "Swazi lilangeni1.00",
+ "Swazi emalangeni1.00",
+ "Swedish Krona1.00",
+ "Swedish krona1.00",
+ "Swedish kronor1.00",
+ "Swiss Franc1.00",
+ "Swiss franc1.00",
+ "Swiss francs1.00",
+ "Syrian Pound1.00",
+ "Syrian pound1.00",
+ "Syrian pounds1.00",
+ "THB1.00",
+ "TJR1.00",
+ "TJR1.00",
+ "TJS1.00",
+ "TJS1.00",
+ "TMM1.00",
+ "TMM1.00",
+ "TND1.00",
+ "TND1.00",
+ "TOP1.00",
+ "TPE1.00",
+ "TPE1.00",
+ "TRL1.00",
+ "TRY1.00",
+ "TRY1.00",
+ "TTD1.00",
+ "TWD1.00",
+ "TZS1.00",
+ "New Taiwan Dollar1.00",
+ "New Taiwan dollar1.00",
+ "New Taiwan dollars1.00",
+ "Tajikistani Ruble1.00",
+ "Tajikistani Somoni1.00",
+ "Tajikistani ruble1.00",
+ "Tajikistani rubles1.00",
+ "Tajikistani somoni1.00",
+ "Tajikistani somonis1.00",
+ "Tanzanian Shilling1.00",
+ "Tanzanian shilling1.00",
+ "Tanzanian shillings1.00",
+ "Testing Currency Code1.00",
+ "Testing Currency Code1.00",
+ "Thai Baht1.00",
+ "Thai baht1.00",
+ "Thai baht1.00",
+ "Timorese Escudo1.00",
+ "Timorese escudo1.00",
+ "Timorese escudos1.00",
+ "Tongan Pa\\u02bbanga1.00",
+ "Tongan pa\\u02bbanga1.00",
+ "Tongan pa\\u02bbanga1.00",
+ "Trinidad & Tobago Dollar1.00",
+ "Trinidad & Tobago dollar1.00",
+ "Trinidad & Tobago dollars1.00",
+ "Tunisian Dinar1.00",
+ "Tunisian dinar1.00",
+ "Tunisian dinars1.00",
+ "Turkish Lira1.00",
+ "Turkish Lira1.00",
+ "Turkish lira1.00",
+ "Turkmenistani Manat1.00",
+ "Turkmenistani manat1.00",
+ "Turkmenistani manat1.00",
+ "UAE dirham1.00",
+ "UAE dirhams1.00",
+ "UAH1.00",
+ "UAK1.00",
+ "UAK1.00",
+ "UGS1.00",
+ "UGS1.00",
+ "UGX1.00",
+ "US Dollar (Next day)1.00",
+ "US Dollar (Same day)1.00",
+ "US Dollar1.00",
+ "US dollar (next day)1.00",
+ "US dollar (same day)1.00",
+ "US dollar1.00",
+ "US dollars (next day)1.00",
+ "US dollars (same day)1.00",
+ "US dollars1.00",
+ "USD1.00",
+ "USN1.00",
+ "USN1.00",
+ "USS1.00",
+ "USS1.00",
+ "UYI1.00",
+ "UYI1.00",
+ "UYP1.00",
+ "UYP1.00",
+ "UYU1.00",
+ "UZS1.00",
+ "UZS1.00",
+ "Ugandan Shilling (1966\\u20131987)1.00",
+ "Ugandan Shilling1.00",
+ "Ugandan shilling (1966\\u20131987)1.00",
+ "Ugandan shilling1.00",
+ "Ugandan shillings (1966\\u20131987)1.00",
+ "Ugandan shillings1.00",
+ "Ukrainian Hryvnia1.00",
+ "Ukrainian Karbovanets1.00",
+ "Ukrainian hryvnia1.00",
+ "Ukrainian hryvnias1.00",
+ "Ukrainian karbovanets1.00",
+ "Ukrainian karbovantsiv1.00",
+ "Colombian Real Value Unit1.00",
+ "United Arab Emirates Dirham1.00",
+ "Unknown Currency1.00",
+ "Uruguayan Peso (1975\\u20131993)1.00",
+ "Uruguayan Peso1.00",
+ "Uruguayan Peso (Indexed Units)1.00",
+ "Uruguayan peso (1975\\u20131993)1.00",
+ "Uruguayan peso (indexed units)1.00",
+ "Uruguayan peso1.00",
+ "Uruguayan pesos (1975\\u20131993)1.00",
+ "Uruguayan pesos (indexed units)1.00",
+ "Uruguayan pesos1.00",
+ "Uzbekistani Som1.00",
+ "Uzbekistani som1.00",
+ "Uzbekistani som1.00",
+ "VEB1.00",
+ "VEF1.00",
+ "VND1.00",
+ "VUV1.00",
+ "Vanuatu Vatu1.00",
+ "Vanuatu vatu1.00",
+ "Vanuatu vatus1.00",
+ "Venezuelan Bol\\u00edvar1.00",
+ "Venezuelan Bol\\u00edvar (1871\\u20132008)1.00",
+ "Venezuelan bol\\u00edvar1.00",
+ "Venezuelan bol\\u00edvars1.00",
+ "Venezuelan bol\\u00edvar (1871\\u20132008)1.00",
+ "Venezuelan bol\\u00edvars (1871\\u20132008)1.00",
+ "Vietnamese Dong1.00",
+ "Vietnamese dong1.00",
+ "Vietnamese dong1.00",
+ "WIR Euro1.00",
+ "WIR Franc1.00",
+ "WIR euro1.00",
+ "WIR euros1.00",
+ "WIR franc1.00",
+ "WIR francs1.00",
+ "WST1.00",
+ "WST1.00",
+ "Samoan Tala1.00",
+ "Samoan tala1.00",
+ "Samoan tala1.00",
+ "XAF1.00",
+ "XAF1.00",
+ "XAG1.00",
+ "XAG1.00",
+ "XAU1.00",
+ "XAU1.00",
+ "XBA1.00",
+ "XBA1.00",
+ "XBB1.00",
+ "XBB1.00",
+ "XBC1.00",
+ "XBC1.00",
+ "XBD1.00",
+ "XBD1.00",
+ "XCD1.00",
+ "XDR1.00",
+ "XDR1.00",
+ "XEU1.00",
+ "XEU1.00",
+ "XFO1.00",
+ "XFO1.00",
+ "XFU1.00",
+ "XFU1.00",
+ "XOF1.00",
+ "XOF1.00",
+ "XPD1.00",
+ "XPD1.00",
+ "XPF1.00",
+ "XPT1.00",
+ "XPT1.00",
+ "XRE1.00",
+ "XRE1.00",
+ "XTS1.00",
+ "XTS1.00",
+ "XXX1.00",
+ "XXX1.00",
+ "YDD1.00",
+ "YDD1.00",
+ "YER1.00",
+ "YUD1.00",
+ "YUD1.00",
+ "YUM1.00",
+ "YUM1.00",
+ "YUN1.00",
+ "YUN1.00",
+ "Yemeni Dinar1.00",
+ "Yemeni Rial1.00",
+ "Yemeni dinar1.00",
+ "Yemeni dinars1.00",
+ "Yemeni rial1.00",
+ "Yemeni rials1.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",
+ "ZMK1.00",
+ "ZMK1.00",
+ "ZRN1.00",
+ "ZRN1.00",
+ "ZRZ1.00",
+ "ZRZ1.00",
+ "ZWD1.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\\u20132008)1.00",
+ "Zimbabwean dollar (1980\\u20132008)1.00",
+ "Zimbabwean dollars (1980\\u20132008)1.00",
+ "euro1.00",
+ "euros1.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",
+ "\\u20ab1.00",
+ "\\u20aa1.00",
+ "\\u20ac1.00",
+ "\\u20b91.00",
+ //
+ // Following has extra text, should be parsed correctly too
+ "$1.00 random",
+ "USD1.00 random",
+ "1.00 US dollar random",
+ "1.00 US dollars random",
+ "1.00 Afghan Afghani random",
+ "1.00 Afghan Afghani random",
+ "1.00 Afghan Afghanis (1927\\u20131992) random",
+ "1.00 Afghan Afghanis random",
+ "1.00 Albanian Lek random",
+ "1.00 Albanian lek random",
+ "1.00 Albanian lek\\u00eb random",
+ "1.00 Algerian Dinar random",
+ "1.00 Algerian dinar random",
+ "1.00 Algerian dinars random",
+ "1.00 Andorran Peseta random",
+ "1.00 Andorran peseta random",
+ "1.00 Andorran pesetas 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\\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\\u20131991) random",
+ "1.00 Angolan readjusted kwanzas (1995\\u20131999) random",
+ "1.00 Angolan kwanzas 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\\u20131985) random",
+ "1.00 Argentine Peso random",
+ "1.00 Argentine austral random",
+ "1.00 Argentine australs random",
+ "1.00 Argentine peso (1983\\u20131985) random",
+ "1.00 Argentine peso random",
+ "1.00 Argentine pesos (1983\\u20131985) random",
+ "1.00 Argentine pesos random",
+ "1.00 Armenian Dram random",
+ "1.00 Armenian dram random",
+ "1.00 Armenian drams random",
+ "1.00 Aruban Florin random",
+ "1.00 Aruban florin random",
+ "1.00 Australian Dollar random",
+ "1.00 Australian dollar random",
+ "1.00 Australian dollars random",
+ "1.00 Austrian Schilling random",
+ "1.00 Austrian schilling random",
+ "1.00 Austrian schillings random",
+ "1.00 Azerbaijani Manat (1993\\u20132006) random",
+ "1.00 Azerbaijani Manat random",
+ "1.00 Azerbaijani manat (1993\\u20132006) random",
+ "1.00 Azerbaijani manat random",
+ "1.00 Azerbaijani manats (1993\\u20132006) random",
+ "1.00 Azerbaijani manats random",
+ "1.00 Bahamian Dollar random",
+ "1.00 Bahamian dollar random",
+ "1.00 Bahamian dollars random",
+ "1.00 Bahraini Dinar random",
+ "1.00 Bahraini dinar random",
+ "1.00 Bahraini dinars random",
+ "1.00 Bangladeshi Taka random",
+ "1.00 Bangladeshi taka random",
+ "1.00 Bangladeshi takas random",
+ "1.00 Barbadian Dollar random",
+ "1.00 Barbadian dollar random",
+ "1.00 Barbadian dollars random",
+ "1.00 Belarusian Ruble (1994\\u20131999) random",
+ "1.00 Belarusian Ruble 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",
+ "1.00 Belgian Franc (financial) random",
+ "1.00 Belgian Franc random",
+ "1.00 Belgian franc (convertible) random",
+ "1.00 Belgian franc (financial) random",
+ "1.00 Belgian franc random",
+ "1.00 Belgian francs (convertible) random",
+ "1.00 Belgian francs (financial) random",
+ "1.00 Belgian francs random",
+ "1.00 Belize Dollar random",
+ "1.00 Belize dollar random",
+ "1.00 Belize dollars random",
+ "1.00 Bermudan Dollar random",
+ "1.00 Bermudan dollar random",
+ "1.00 Bermudan dollars random",
+ "1.00 Bhutanese Ngultrum random",
+ "1.00 Bhutanese ngultrum random",
+ "1.00 Bhutanese ngultrums random",
+ "1.00 Bolivian Mvdol random",
+ "1.00 Bolivian Peso random",
+ "1.00 Bolivian mvdol random",
+ "1.00 Bolivian mvdols random",
+ "1.00 Bolivian peso random",
+ "1.00 Bolivian pesos random",
+ "1.00 Bolivian Boliviano random",
+ "1.00 Bolivian Boliviano random",
+ "1.00 Bolivian Bolivianos random",
+ "1.00 Bosnia-Herzegovina Convertible Mark 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\\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\\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\\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 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",
+ "1.00 Bulgarian Hard Lev random",
+ "1.00 Bulgarian Lev random",
+ "1.00 Bulgarian Leva random",
+ "1.00 Bulgarian hard lev random",
+ "1.00 Bulgarian hard leva random",
+ "1.00 Bulgarian lev random",
+ "1.00 Burmese Kyat random",
+ "1.00 Burmese kyat random",
+ "1.00 Burmese kyats random",
+ "1.00 Burundian Franc random",
+ "1.00 Burundian franc random",
+ "1.00 Burundian francs random",
+ "1.00 Cambodian Riel random",
+ "1.00 Cambodian riel random",
+ "1.00 Cambodian riels random",
+ "1.00 Canadian Dollar random",
+ "1.00 Canadian dollar random",
+ "1.00 Canadian dollars random",
+ "1.00 Cape Verdean Escudo random",
+ "1.00 Cape Verdean escudo random",
+ "1.00 Cape Verdean escudos random",
+ "1.00 Cayman Islands Dollar random",
+ "1.00 Cayman Islands dollar random",
+ "1.00 Cayman Islands dollars random",
+ "1.00 Chilean Peso random",
+ "1.00 Chilean Unit of Account (UF) random",
+ "1.00 Chilean peso random",
+ "1.00 Chilean pesos random",
+ "1.00 Chilean unit of account (UF) random",
+ "1.00 Chilean units of account (UF) random",
+ "1.00 Chinese Yuan random",
+ "1.00 Chinese yuan random",
+ "1.00 Colombian Peso random",
+ "1.00 Colombian peso random",
+ "1.00 Colombian pesos random",
+ "1.00 Comorian Franc random",
+ "1.00 Comorian franc random",
+ "1.00 Comorian francs random",
+ "1.00 Congolese Franc Congolais random",
+ "1.00 Congolese franc Congolais random",
+ "1.00 Congolese francs Congolais random",
+ "1.00 Costa Rican Col\\u00f3n random",
+ "1.00 Costa Rican col\\u00f3n random",
+ "1.00 Costa Rican col\\u00f3ns random",
+ "1.00 Croatian Dinar random",
+ "1.00 Croatian Kuna random",
+ "1.00 Croatian dinar random",
+ "1.00 Croatian dinars random",
+ "1.00 Croatian kuna random",
+ "1.00 Croatian kunas random",
+ "1.00 Cuban Peso random",
+ "1.00 Cuban peso random",
+ "1.00 Cuban pesos random",
+ "1.00 Cypriot Pound random",
+ "1.00 Cypriot pound random",
+ "1.00 Cypriot pounds 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",
+ "1.00 Danish Krone random",
+ "1.00 Danish krone random",
+ "1.00 Danish kroner random",
+ "1.00 German Mark random",
+ "1.00 German mark random",
+ "1.00 German marks random",
+ "1.00 Djiboutian Franc random",
+ "1.00 Djiboutian franc random",
+ "1.00 Djiboutian francs random",
+ "1.00 Dominican Peso random",
+ "1.00 Dominican peso random",
+ "1.00 Dominican pesos random",
+ "1.00 East Caribbean Dollar random",
+ "1.00 East Caribbean dollar random",
+ "1.00 East Caribbean dollars random",
+ "1.00 East German Mark random",
+ "1.00 East German mark random",
+ "1.00 East German marks random",
+ "1.00 Ecuadorian Sucre random",
+ "1.00 Ecuadorian Unit of Constant Value random",
+ "1.00 Ecuadorian sucre random",
+ "1.00 Ecuadorian sucres random",
+ "1.00 Ecuadorian unit of constant value random",
+ "1.00 Ecuadorian units of constant value random",
+ "1.00 Egyptian Pound random",
+ "1.00 Egyptian pound random",
+ "1.00 Egyptian pounds random",
+ "1.00 Salvadoran Col\\u00f3n random",
+ "1.00 Salvadoran col\\u00f3n random",
+ "1.00 Salvadoran colones random",
+ "1.00 Equatorial Guinean Ekwele random",
+ "1.00 Equatorial Guinean ekwele random",
+ "1.00 Eritrean Nakfa random",
+ "1.00 Eritrean nakfa random",
+ "1.00 Eritrean nakfas random",
+ "1.00 Estonian Kroon random",
+ "1.00 Estonian kroon random",
+ "1.00 Estonian kroons random",
+ "1.00 Ethiopian Birr random",
+ "1.00 Ethiopian birr random",
+ "1.00 Ethiopian birrs random",
+ "1.00 European Composite Unit random",
+ "1.00 European Currency Unit random",
+ "1.00 European Monetary Unit random",
+ "1.00 European Unit of Account (XBC) random",
+ "1.00 European Unit of Account (XBD) random",
+ "1.00 European composite unit random",
+ "1.00 European composite units random",
+ "1.00 European currency unit random",
+ "1.00 European currency units random",
+ "1.00 European monetary unit random",
+ "1.00 European monetary units random",
+ "1.00 European unit of account (XBC) random",
+ "1.00 European unit of account (XBD) random",
+ "1.00 European units of account (XBC) random",
+ "1.00 European units of account (XBD) random",
+ "1.00 Falkland Islands Pound random",
+ "1.00 Falkland Islands pound random",
+ "1.00 Falkland Islands pounds random",
+ "1.00 Fijian Dollar random",
+ "1.00 Fijian dollar random",
+ "1.00 Fijian dollars random",
+ "1.00 Finnish Markka random",
+ "1.00 Finnish markka random",
+ "1.00 Finnish markkas random",
+ "1.00 French Franc random",
+ "1.00 French Gold Franc random",
+ "1.00 French UIC-Franc random",
+ "1.00 French UIC-franc random",
+ "1.00 French UIC-francs random",
+ "1.00 French franc random",
+ "1.00 French francs random",
+ "1.00 French gold franc random",
+ "1.00 French gold francs random",
+ "1.00 Gambian Dalasi random",
+ "1.00 Gambian dalasi random",
+ "1.00 Gambian dalasis random",
+ "1.00 Georgian Kupon Larit random",
+ "1.00 Georgian Lari random",
+ "1.00 Georgian kupon larit random",
+ "1.00 Georgian kupon larits random",
+ "1.00 Georgian lari random",
+ "1.00 Georgian laris random",
+ "1.00 Ghanaian Cedi (1979\\u20132007) random",
+ "1.00 Ghanaian Cedi random",
+ "1.00 Ghanaian cedi (1979\\u20132007) random",
+ "1.00 Ghanaian cedi random",
+ "1.00 Ghanaian cedis (1979\\u20132007) random",
+ "1.00 Ghanaian cedis random",
+ "1.00 Gibraltar Pound random",
+ "1.00 Gibraltar pound random",
+ "1.00 Gibraltar pounds random",
+ "1.00 Gold random",
+ "1.00 Gold random",
+ "1.00 Greek Drachma random",
+ "1.00 Greek drachma random",
+ "1.00 Greek drachmas random",
+ "1.00 Guatemalan Quetzal random",
+ "1.00 Guatemalan quetzal random",
+ "1.00 Guatemalan quetzals random",
+ "1.00 Guinean Franc random",
+ "1.00 Guinean Syli random",
+ "1.00 Guinean franc random",
+ "1.00 Guinean francs random",
+ "1.00 Guinean syli random",
+ "1.00 Guinean sylis random",
+ "1.00 Guinea-Bissau Peso random",
+ "1.00 Guinea-Bissau peso random",
+ "1.00 Guinea-Bissau pesos random",
+ "1.00 Guyanaese Dollar random",
+ "1.00 Guyanaese dollar random",
+ "1.00 Guyanaese dollars random",
+ "1.00 Haitian Gourde random",
+ "1.00 Haitian gourde random",
+ "1.00 Haitian gourdes random",
+ "1.00 Honduran Lempira random",
+ "1.00 Honduran lempira random",
+ "1.00 Honduran lempiras random",
+ "1.00 Hong Kong Dollar random",
+ "1.00 Hong Kong dollar random",
+ "1.00 Hong Kong dollars random",
+ "1.00 Hungarian Forint random",
+ "1.00 Hungarian forint random",
+ "1.00 Hungarian forints random",
+ "1.00 Icelandic Kr\\u00f3na random",
+ "1.00 Icelandic kr\\u00f3na random",
+ "1.00 Icelandic kr\\u00f3nur random",
+ "1.00 Indian Rupee random",
+ "1.00 Indian rupee random",
+ "1.00 Indian rupees random",
+ "1.00 Indonesian Rupiah random",
+ "1.00 Indonesian rupiah random",
+ "1.00 Indonesian rupiahs random",
+ "1.00 Iranian Rial random",
+ "1.00 Iranian rial random",
+ "1.00 Iranian rials random",
+ "1.00 Iraqi Dinar random",
+ "1.00 Iraqi dinar random",
+ "1.00 Iraqi dinars random",
+ "1.00 Irish Pound random",
+ "1.00 Irish pound random",
+ "1.00 Irish pounds random",
+ "1.00 Israeli Pound random",
+ "1.00 Israeli new shekel random",
+ "1.00 Israeli pound random",
+ "1.00 Israeli pounds random",
+ "1.00 Italian Lira random",
+ "1.00 Italian lira random",
+ "1.00 Italian liras random",
+ "1.00 Jamaican Dollar random",
+ "1.00 Jamaican dollar random",
+ "1.00 Jamaican dollars random",
+ "1.00 Japanese Yen random",
+ "1.00 Japanese yen random",
+ "1.00 Jordanian Dinar random",
+ "1.00 Jordanian dinar random",
+ "1.00 Jordanian dinars random",
+ "1.00 Kazakhstani Tenge random",
+ "1.00 Kazakhstani tenge random",
+ "1.00 Kazakhstani tenges random",
+ "1.00 Kenyan Shilling random",
+ "1.00 Kenyan shilling random",
+ "1.00 Kenyan shillings random",
+ "1.00 Kuwaiti Dinar random",
+ "1.00 Kuwaiti dinar random",
+ "1.00 Kuwaiti dinars random",
+ "1.00 Kyrgystani Som random",
+ "1.00 Kyrgystani som random",
+ "1.00 Kyrgystani soms random",
+ "1.00 Laotian Kip random",
+ "1.00 Laotian kip random",
+ "1.00 Laotian kips random",
+ "1.00 Latvian Lats random",
+ "1.00 Latvian Ruble random",
+ "1.00 Latvian lats random",
+ "1.00 Latvian lati random",
+ "1.00 Latvian ruble random",
+ "1.00 Latvian rubles random",
+ "1.00 Lebanese Pound random",
+ "1.00 Lebanese pound random",
+ "1.00 Lebanese pounds random",
+ "1.00 Lesotho Loti random",
+ "1.00 Lesotho loti random",
+ "1.00 Lesotho lotis random",
+ "1.00 Liberian Dollar random",
+ "1.00 Liberian dollar random",
+ "1.00 Liberian dollars random",
+ "1.00 Libyan Dinar random",
+ "1.00 Libyan dinar random",
+ "1.00 Libyan dinars random",
+ "1.00 Lithuanian Litas random",
+ "1.00 Lithuanian Talonas random",
+ "1.00 Lithuanian litas random",
+ "1.00 Lithuanian litai random",
+ "1.00 Lithuanian talonas random",
+ "1.00 Lithuanian talonases random",
+ "1.00 Luxembourgian Convertible Franc random",
+ "1.00 Luxembourg Financial Franc random",
+ "1.00 Luxembourgian Franc random",
+ "1.00 Luxembourgian convertible franc random",
+ "1.00 Luxembourgian convertible francs random",
+ "1.00 Luxembourg financial franc random",
+ "1.00 Luxembourg financial francs random",
+ "1.00 Luxembourgian franc random",
+ "1.00 Luxembourgian francs random",
+ "1.00 Macanese Pataca random",
+ "1.00 Macanese pataca random",
+ "1.00 Macanese patacas random",
+ "1.00 Macedonian Denar random",
+ "1.00 Macedonian denar random",
+ "1.00 Macedonian denari random",
+ "1.00 Malagasy Ariaries random",
+ "1.00 Malagasy Ariary random",
+ "1.00 Malagasy Ariary random",
+ "1.00 Malagasy Franc random",
+ "1.00 Malagasy franc random",
+ "1.00 Malagasy francs random",
+ "1.00 Malawian Kwacha random",
+ "1.00 Malawian Kwacha random",
+ "1.00 Malawian Kwachas random",
+ "1.00 Malaysian Ringgit random",
+ "1.00 Malaysian ringgit random",
+ "1.00 Malaysian ringgits random",
+ "1.00 Maldivian Rufiyaa random",
+ "1.00 Maldivian rufiyaa random",
+ "1.00 Maldivian rufiyaas random",
+ "1.00 Malian Franc random",
+ "1.00 Malian franc random",
+ "1.00 Malian francs random",
+ "1.00 Maltese Lira random",
+ "1.00 Maltese Pound random",
+ "1.00 Maltese lira random",
+ "1.00 Maltese liras random",
+ "1.00 Maltese pound random",
+ "1.00 Maltese pounds random",
+ "1.00 Mauritanian Ouguiya random",
+ "1.00 Mauritanian ouguiya random",
+ "1.00 Mauritanian ouguiyas random",
+ "1.00 Mauritian Rupee random",
+ "1.00 Mauritian rupee random",
+ "1.00 Mauritian rupees random",
+ "1.00 Mexican Peso 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\\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",
+ "1.00 Moldovan leu random",
+ "1.00 Moldovan lei random",
+ "1.00 Mongolian Tugrik random",
+ "1.00 Mongolian tugrik random",
+ "1.00 Mongolian tugriks random",
+ "1.00 Moroccan Dirham random",
+ "1.00 Moroccan Franc random",
+ "1.00 Moroccan dirham random",
+ "1.00 Moroccan dirhams random",
+ "1.00 Moroccan franc random",
+ "1.00 Moroccan francs random",
+ "1.00 Mozambican Escudo random",
+ "1.00 Mozambican Metical random",
+ "1.00 Mozambican escudo random",
+ "1.00 Mozambican escudos random",
+ "1.00 Mozambican metical random",
+ "1.00 Mozambican meticals 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",
+ "1.00 Nepalese Rupee random",
+ "1.00 Nepalese rupee random",
+ "1.00 Nepalese rupees random",
+ "1.00 Netherlands Antillean Guilder random",
+ "1.00 Netherlands Antillean guilder random",
+ "1.00 Netherlands Antillean guilders random",
+ "1.00 Dutch Guilder random",
+ "1.00 Dutch guilder random",
+ "1.00 Dutch guilders 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\\u20131991) random",
+ "1.00 Nicaraguan c\\u00f3rdoba random",
+ "1.00 Nicaraguan c\\u00f3rdoba 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",
+ "1.00 North Korean Won random",
+ "1.00 North Korean won random",
+ "1.00 North Korean won random",
+ "1.00 Norwegian Krone random",
+ "1.00 Norwegian krone random",
+ "1.00 Norwegian kroner 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",
+ "1.00 Pakistani Rupee random",
+ "1.00 Pakistani rupee random",
+ "1.00 Pakistani rupees random",
+ "1.00 Palladium random",
+ "1.00 Palladium random",
+ "1.00 Panamanian Balboa random",
+ "1.00 Panamanian balboa random",
+ "1.00 Panamanian balboas random",
+ "1.00 Papua New Guinean Kina random",
+ "1.00 Papua New Guinean kina random",
+ "1.00 Papua New Guinean kina random",
+ "1.00 Paraguayan Guarani random",
+ "1.00 Paraguayan guarani random",
+ "1.00 Paraguayan guaranis random",
+ "1.00 Peruvian Inti 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 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\\u20131995) random",
+ "1.00 Polish Zloty random",
+ "1.00 Polish zlotys random",
+ "1.00 Polish zloty (PLZ) random",
+ "1.00 Polish zloty random",
+ "1.00 Polish zlotys (PLZ) random",
+ "1.00 Portuguese Escudo random",
+ "1.00 Portuguese Guinea Escudo random",
+ "1.00 Portuguese Guinea escudo random",
+ "1.00 Portuguese Guinea escudos random",
+ "1.00 Portuguese escudo random",
+ "1.00 Portuguese escudos random",
+ "1.00 Qatari Rial random",
+ "1.00 Qatari rial random",
+ "1.00 Qatari rials random",
+ "1.00 RINET Funds random",
+ "1.00 RINET Funds random",
+ "1.00 Rhodesian Dollar random",
+ "1.00 Rhodesian dollar random",
+ "1.00 Rhodesian dollars random",
+ "1.00 Romanian Leu random",
+ "1.00 Romanian lei random",
+ "1.00 Romanian leu random",
+ "1.00 Russian Ruble (1991\\u20131998) random",
+ "1.00 Russian Ruble random",
+ "1.00 Russian ruble (1991\\u20131998) random",
+ "1.00 Russian ruble 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 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",
+ "1.00 Serbian Dinar random",
+ "1.00 Serbian dinar random",
+ "1.00 Serbian dinars random",
+ "1.00 Seychellois Rupee random",
+ "1.00 Seychellois rupee random",
+ "1.00 Seychellois rupees random",
+ "1.00 Sierra Leonean Leone random",
+ "1.00 Sierra Leonean leone random",
+ "1.00 Sierra Leonean leones random",
+ "1.00 Singapore Dollar random",
+ "1.00 Singapore dollar random",
+ "1.00 Singapore dollars random",
+ "1.00 Slovak Koruna random",
+ "1.00 Slovak koruna random",
+ "1.00 Slovak korunas random",
+ "1.00 Slovenian Tolar random",
+ "1.00 Slovenian tolar random",
+ "1.00 Slovenian tolars random",
+ "1.00 Solomon Islands Dollar random",
+ "1.00 Solomon Islands dollar random",
+ "1.00 Solomon Islands dollars random",
+ "1.00 Somali Shilling random",
+ "1.00 Somali shilling random",
+ "1.00 Somali shillings random",
+ "1.00 South African Rand (financial) random",
+ "1.00 South African Rand random",
+ "1.00 South African rand (financial) random",
+ "1.00 South African rand random",
+ "1.00 South African rands (financial) random",
+ "1.00 South African rand random",
+ "1.00 South Korean Won random",
+ "1.00 South Korean won random",
+ "1.00 South Korean won random",
+ "1.00 Soviet Rouble random",
+ "1.00 Soviet rouble random",
+ "1.00 Soviet roubles random",
+ "1.00 Spanish Peseta (A account) random",
+ "1.00 Spanish Peseta (convertible account) random",
+ "1.00 Spanish Peseta random",
+ "1.00 Spanish peseta (A account) random",
+ "1.00 Spanish peseta (convertible account) random",
+ "1.00 Spanish peseta random",
+ "1.00 Spanish pesetas (A account) random",
+ "1.00 Spanish pesetas (convertible account) random",
+ "1.00 Spanish pesetas random",
+ "1.00 Special Drawing Rights random",
+ "1.00 Sri Lankan Rupee random",
+ "1.00 Sri Lankan rupee random",
+ "1.00 Sri Lankan rupees random",
+ "1.00 Sudanese Pound random",
+ "1.00 Sudanese pound random",
+ "1.00 Sudanese pounds random",
+ "1.00 Surinamese Dollar random",
+ "1.00 Surinamese dollar random",
+ "1.00 Surinamese dollars random",
+ "1.00 Surinamese Guilder random",
+ "1.00 Surinamese guilder random",
+ "1.00 Surinamese guilders random",
+ "1.00 Swazi Lilangeni random",
+ "1.00 Swazi lilangeni random",
+ "1.00 Swazi emalangeni random",
+ "1.00 Swedish Krona random",
+ "1.00 Swedish krona random",
+ "1.00 Swedish kronor random",
+ "1.00 Swiss Franc random",
+ "1.00 Swiss franc random",
+ "1.00 Swiss francs random",
+ "1.00 Syrian Pound random",
+ "1.00 Syrian pound random",
+ "1.00 Syrian pounds random",
+ "1.00 New Taiwan Dollar random",
+ "1.00 New Taiwan dollar random",
+ "1.00 New Taiwan dollars random",
+ "1.00 Tajikistani Ruble random",
+ "1.00 Tajikistani Somoni random",
+ "1.00 Tajikistani ruble random",
+ "1.00 Tajikistani rubles random",
+ "1.00 Tajikistani somoni random",
+ "1.00 Tajikistani somonis random",
+ "1.00 Tanzanian Shilling random",
+ "1.00 Tanzanian shilling random",
+ "1.00 Tanzanian shillings random",
+ "1.00 Testing Currency Code random",
+ "1.00 Testing Currency Code random",
+ "1.00 Thai Baht random",
+ "1.00 Thai baht random",
+ "1.00 Thai baht random",
+ "1.00 Timorese Escudo random",
+ "1.00 Timorese escudo random",
+ "1.00 Timorese escudos 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",
+ "1.00 Turkish Lira random",
+ "1.00 Turkish Lira random",
+ "1.00 Turkish lira random",
+ "1.00 Turkmenistani Manat random",
+ "1.00 Turkmenistani manat random",
+ "1.00 Turkmenistani manat random",
+ "1.00 US Dollar (Next day) random",
+ "1.00 US Dollar (Same day) random",
+ "1.00 US Dollar random",
+ "1.00 US dollar (next day) random",
+ "1.00 US dollar (same day) random",
+ "1.00 US dollar random",
+ "1.00 US dollars (next day) random",
+ "1.00 US dollars (same day) random",
+ "1.00 US dollars random",
+ "1.00 Ugandan Shilling (1966\\u20131987) random",
+ "1.00 Ugandan Shilling random",
+ "1.00 Ugandan shilling (1966\\u20131987) random",
+ "1.00 Ugandan shilling random",
+ "1.00 Ugandan shillings (1966\\u20131987) random",
+ "1.00 Ugandan shillings random",
+ "1.00 Ukrainian Hryvnia random",
+ "1.00 Ukrainian Karbovanets random",
+ "1.00 Ukrainian hryvnia random",
+ "1.00 Ukrainian hryvnias random",
+ "1.00 Ukrainian karbovanets random",
+ "1.00 Ukrainian karbovantsiv random",
+ "1.00 Colombian Real Value Unit random",
+ "1.00 United Arab Emirates Dirham random",
+ "1.00 Unknown Currency 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\\u20131993) random",
+ "1.00 Uruguayan peso (indexed units) random",
+ "1.00 Uruguayan peso random",
+ "1.00 Uruguayan pesos (1975\\u20131993) random",
+ "1.00 Uruguayan pesos (indexed units) 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\\u20132008) random",
+ "1.00 Venezuelan bol\\u00edvar random",
+ "1.00 Venezuelan bol\\u00edvars 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",
+ "1.00 WIR Euro random",
+ "1.00 WIR Franc random",
+ "1.00 WIR euro random",
+ "1.00 WIR euros random",
+ "1.00 WIR franc random",
+ "1.00 WIR francs random",
+ "1.00 Samoan Tala random",
+ "1.00 Samoan tala random",
+ "1.00 Samoan tala random",
+ "1.00 Yemeni Dinar random",
+ "1.00 Yemeni Rial random",
+ "1.00 Yemeni dinar random",
+ "1.00 Yemeni dinars random",
+ "1.00 Yemeni rial random",
+ "1.00 Yemeni rials 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\\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\\u20132005) random",
+ "1.00 special drawing rights random",
+ "1.00 Colombian real value unit random",
+ "1.00 Colombian real value units random",
+ "1.00 unknown currency random",
+ };
+
+ const char* WRONG_DATA[] = {
+ // Following are missing one last char in the currency name
+ "usd1.00", // case sensitive
+ "1.00 Nicaraguan Cordob",
+ "1.00 Namibian Dolla",
+ "1.00 Namibian dolla",
+ "1.00 Nepalese Rupe",
+ "1.00 Nepalese rupe",
+ "1.00 Netherlands Antillean Guilde",
+ "1.00 Netherlands Antillean guilde",
+ "1.00 Dutch Guilde",
+ "1.00 Dutch guilde",
+ "1.00 Israeli New Sheqe",
+ "1.00 New Zealand Dolla",
+ "1.00 New Zealand dolla",
+ "1.00 Nicaraguan cordob",
+ "1.00 Nigerian Nair",
+ "1.00 Nigerian nair",
+ "1.00 North Korean Wo",
+ "1.00 North Korean wo",
+ "1.00 Norwegian Kron",
+ "1.00 Norwegian kron",
+ "1.00 US dolla",
+ "1.00",
+ "A1.00",
+ "AD1.00",
+ "AE1.00",
+ "AF1.00",
+ "AL1.00",
+ "AM1.00",
+ "AN1.00",
+ "AO1.00",
+ "AR1.00",
+ "AT1.00",
+ "AU1.00",
+ "AW1.00",
+ "AZ1.00",
+ "Afghan Afghan1.00",
+ "Afghan Afghani (1927\\u201320021.00",
+ "Afl1.00",
+ "Albanian Le1.00",
+ "Algerian Dina1.00",
+ "Andorran Peset1.00",
+ "Angolan Kwanz1.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\\u201319851.00",
+ "Armenian Dra1.00",
+ "Aruban Flori1.00",
+ "Australian Dolla1.00",
+ "Austrian Schillin1.00",
+ "Azerbaijani Mana1.00",
+ "Azerbaijani Manat (1993\\u201320061.00",
+ "B1.00",
+ "BA1.00",
+ "BB1.00",
+ "BE1.00",
+ "BG1.00",
+ "BH1.00",
+ "BI1.00",
+ "BM1.00",
+ "BN1.00",
+ "BO1.00",
+ "BR1.00",
+ "BS1.00",
+ "BT1.00",
+ "BU1.00",
+ "BW1.00",
+ "BY1.00",
+ "BZ1.00",
+ "Bahamian Dolla1.00",
+ "Bahraini Dina1.00",
+ "Bangladeshi Tak1.00",
+ "Barbadian Dolla1.00",
+ "Bds1.00",
+ "Belarusian Ruble (1994\\u201319991.00",
+ "Belarusian Rubl1.00",
+ "Belgian Fran1.00",
+ "Belgian Franc (convertible1.00",
+ "Belgian Franc (financial1.00",
+ "Belize Dolla1.00",
+ "Bermudan Dolla1.00",
+ "Bhutanese Ngultru1.00",
+ "Bolivian Mvdo1.00",
+ "Bolivian Pes1.00",
+ "Bolivian Bolivian1.00",
+ "Bosnia-Herzegovina Convertible Mar1.00",
+ "Bosnia-Herzegovina Dina1.00",
+ "Botswanan Pul1.00",
+ "Brazilian Cruzad1.00",
+ "Brazilian Cruzado Nov1.00",
+ "Brazilian Cruzeir1.00",
+ "Brazilian Cruzeiro (1990\\u201319931.00",
+ "Brazilian New Cruzeiro (1967\\u201319861.00",
+ "Brazilian Rea1.00",
+ "British Pound Sterlin1.00",
+ "Brunei Dolla1.00",
+ "Bulgarian Hard Le1.00",
+ "Bulgarian Le1.00",
+ "Burmese Kya1.00",
+ "Burundian Fran1.00",
+ "C1.00",
+ "CA1.00",
+ "CD1.00",
+ "CFP Fran1.00",
+ "CFP1.00",
+ "CH1.00",
+ "CL1.00",
+ "CN1.00",
+ "CO1.00",
+ "CS1.00",
+ "CU1.00",
+ "CV1.00",
+ "CY1.00",
+ "CZ1.00",
+ "Cambodian Rie1.00",
+ "Canadian Dolla1.00",
+ "Cape Verdean Escud1.00",
+ "Cayman Islands Dolla1.00",
+ "Chilean Pes1.00",
+ "Chilean Unit of Accoun1.00",
+ "Chinese Yua1.00",
+ "Colombian Pes1.00",
+ "Comoro Fran1.00",
+ "Congolese Fran1.00",
+ "Costa Rican Col\\u00f31.00",
+ "Croatian Dina1.00",
+ "Croatian Kun1.00",
+ "Cuban Pes1.00",
+ "Cypriot Poun1.00",
+ "Czech Republic Korun1.00",
+ "Czechoslovak Hard Korun1.00",
+ "D1.00",
+ "DD1.00",
+ "DE1.00",
+ "DJ1.00",
+ "DK1.00",
+ "DO1.00",
+ "DZ1.00",
+ "Danish Kron1.00",
+ "German Mar1.00",
+ "Djiboutian Fran1.00",
+ "Dk1.00",
+ "Dominican Pes1.00",
+ "EC1.00",
+ "EE1.00",
+ "EG1.00",
+ "EQ1.00",
+ "ER1.00",
+ "ES1.00",
+ "ET1.00",
+ "EU1.00",
+ "East Caribbean Dolla1.00",
+ "East German Ostmar1.00",
+ "Ecuadorian Sucr1.00",
+ "Ecuadorian Unit of Constant Valu1.00",
+ "Egyptian Poun1.00",
+ "Ekwel1.00",
+ "Salvadoran Col\\u00f31.00",
+ "Equatorial Guinean Ekwel1.00",
+ "Eritrean Nakf1.00",
+ "Es1.00",
+ "Estonian Kroo1.00",
+ "Ethiopian Bir1.00",
+ "Eur1.00",
+ "European Composite Uni1.00",
+ "European Currency Uni1.00",
+ "European Monetary Uni1.00",
+ "European Unit of Account (XBC1.00",
+ "European Unit of Account (XBD1.00",
+ "F1.00",
+ "FB1.00",
+ "FI1.00",
+ "FJ1.00",
+ "FK1.00",
+ "FR1.00",
+ "Falkland Islands Poun1.00",
+ "Fd1.00",
+ "Fijian Dolla1.00",
+ "Finnish Markk1.00",
+ "Fr1.00",
+ "French Fran1.00",
+ "French Gold Fran1.00",
+ "French UIC-Fran1.00",
+ "G1.00",
+ "GB1.00",
+ "GE1.00",
+ "GH1.00",
+ "GI1.00",
+ "GM1.00",
+ "GN1.00",
+ "GQ1.00",
+ "GR1.00",
+ "GT1.00",
+ "GW1.00",
+ "GY1.00",
+ "Gambian Dalas1.00",
+ "Georgian Kupon Lari1.00",
+ "Georgian Lar1.00",
+ "Ghanaian Ced1.00",
+ "Ghanaian Cedi (1979\\u201320071.00",
+ "Gibraltar Poun1.00",
+ "Gol1.00",
+ "Greek Drachm1.00",
+ "Guatemalan Quetza1.00",
+ "Guinean Fran1.00",
+ "Guinean Syl1.00",
+ "Guinea-Bissau Pes1.00",
+ "Guyanaese Dolla1.00",
+ "HK1.00",
+ "HN1.00",
+ "HR1.00",
+ "HT1.00",
+ "HU1.00",
+ "Haitian Gourd1.00",
+ "Honduran Lempir1.00",
+ "Hong Kong Dolla1.00",
+ "Hungarian Forin1.00",
+ "I1.00",
+ "IE1.00",
+ "IL1.00",
+ "IN1.00",
+ "IQ1.00",
+ "IR1.00",
+ "IS1.00",
+ "IT1.00",
+ "Icelandic Kron1.00",
+ "Indian Rupe1.00",
+ "Indonesian Rupia1.00",
+ "Iranian Ria1.00",
+ "Iraqi Dina1.00",
+ "Irish Poun1.00",
+ "Israeli Poun1.00",
+ "Italian Lir1.00",
+ "J1.00",
+ "JM1.00",
+ "JO1.00",
+ "JP1.00",
+ "Jamaican Dolla1.00",
+ "Japanese Ye1.00",
+ "Jordanian Dina1.00",
+ "K S1.00",
+ "K1.00",
+ "KE1.00",
+ "KG1.00",
+ "KH1.00",
+ "KP1.00",
+ "KR1.00",
+ "KW1.00",
+ "KY1.00",
+ "KZ1.00",
+ "Kazakhstani Teng1.00",
+ "Kenyan Shillin1.00",
+ "Kuwaiti Dina1.00",
+ "Kyrgystani So1.00",
+ "LA1.00",
+ "LB1.00",
+ "LK1.00",
+ "LR1.00",
+ "LT1.00",
+ "LU1.00",
+ "LV1.00",
+ "LY1.00",
+ "Laotian Ki1.00",
+ "Latvian Lat1.00",
+ "Latvian Rubl1.00",
+ "Lebanese Poun1.00",
+ "Lesotho Lot1.00",
+ "Liberian Dolla1.00",
+ "Libyan Dina1.00",
+ "Lithuanian Lit1.00",
+ "Lithuanian Talona1.00",
+ "Luxembourgian Convertible Fran1.00",
+ "Luxembourg Financial Fran1.00",
+ "Luxembourgian Fran1.00",
+ "MA1.00",
+ "MD1.00",
+ "MDe1.00",
+ "MEX1.00",
+ "MG1.00",
+ "ML1.00",
+ "MM1.00",
+ "MN1.00",
+ "MO1.00",
+ "MR1.00",
+ "MT1.00",
+ "MU1.00",
+ "MV1.00",
+ "MW1.00",
+ "MX1.00",
+ "MY1.00",
+ "MZ1.00",
+ "Macanese Patac1.00",
+ "Macedonian Dena1.00",
+ "Malagasy Ariar1.00",
+ "Malagasy Fran1.00",
+ "Malawian Kwach1.00",
+ "Malaysian Ringgi1.00",
+ "Maldivian Rufiya1.00",
+ "Malian Fran1.00",
+ "Malot1.00",
+ "Maltese Lir1.00",
+ "Maltese Poun1.00",
+ "Mauritanian Ouguiy1.00",
+ "Mauritian Rupe1.00",
+ "Mexican Pes1.00",
+ "Mexican Silver Peso (1861\\u201319921.00",
+ "Mexican Investment Uni1.00",
+ "Moldovan Le1.00",
+ "Mongolian Tugri1.00",
+ "Moroccan Dirha1.00",
+ "Moroccan Fran1.00",
+ "Mozambican Escud1.00",
+ "Mozambican Metica1.00",
+ "Myanmar Kya1.00",
+ "N1.00",
+ "NA1.00",
+ "NAf1.00",
+ "NG1.00",
+ "NI1.00",
+ "NK1.00",
+ "NL1.00",
+ "NO1.00",
+ "NP1.00",
+ "NT1.00",
+ "Namibian Dolla1.00",
+ "Nepalese Rupe1.00",
+ "Netherlands Antillean Guilde1.00",
+ "Dutch Guilde1.00",
+ "Israeli New Sheqe1.00",
+ "New Zealand Dolla1.00",
+ "Nicaraguan C\\u00f3rdoba (1988\\u201319911.00",
+ "Nicaraguan C\\u00f3rdob1.00",
+ "Nigerian Nair1.00",
+ "North Korean Wo1.00",
+ "Norwegian Kron1.00",
+ "Nr1.00",
+ "OM1.00",
+ "Old Mozambican Metica1.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",
+ "PG1.00",
+ "PH1.00",
+ "PK1.00",
+ "PL1.00",
+ "PT1.00",
+ "PY1.00",
+ "Pakistani Rupe1.00",
+ "Palladiu1.00",
+ "Panamanian Balbo1.00",
+ "Papua New Guinean Kin1.00",
+ "Paraguayan Guaran1.00",
+ "Peruvian Int1.00",
+ "Peruvian Sol (1863\\u201319651.00",
+ "Peruvian Sol Nuev1.00",
+ "Philippine Pes1.00",
+ "Platinu1.00",
+ "Polish Zlot1.00",
+ "Polish Zloty (1950\\u201319951.00",
+ "Portuguese Escud1.00",
+ "Portuguese Guinea Escud1.00",
+ "Pr1.00",
+ "QA1.00",
+ "Qatari Ria1.00",
+ "RD1.00",
+ "RH1.00",
+ "RINET Fund1.00",
+ "RS1.00",
+ "RU1.00",
+ "RW1.00",
+ "Rb1.00",
+ "Rhodesian Dolla1.00",
+ "Romanian Le1.00",
+ "Russian Rubl1.00",
+ "Russian Ruble (1991\\u201319981.00",
+ "Rwandan Fran1.00",
+ "S1.00",
+ "SA1.00",
+ "SB1.00",
+ "SC1.00",
+ "SD1.00",
+ "SE1.00",
+ "SG1.00",
+ "SH1.00",
+ "SI1.00",
+ "SK1.00",
+ "SL R1.00",
+ "SL1.00",
+ "SO1.00",
+ "ST1.00",
+ "SU1.00",
+ "SV1.00",
+ "SY1.00",
+ "SZ1.00",
+ "St. Helena Poun1.00",
+ "S\\u00e3o Tom\\u00e9 & Pr\\u00edncipe Dobr1.00",
+ "Saudi Riya1.00",
+ "Serbian Dina1.00",
+ "Seychellois Rupe1.00",
+ "Sh1.00",
+ "Sierra Leonean Leon1.00",
+ "Silve1.00",
+ "Singapore Dolla1.00",
+ "Slovak Korun1.00",
+ "Slovenian Tola1.00",
+ "Solomon Islands Dolla1.00",
+ "Somali Shillin1.00",
+ "South African Ran1.00",
+ "South African Rand (financial1.00",
+ "South Korean Wo1.00",
+ "Soviet Roubl1.00",
+ "Spanish Peset1.00",
+ "Spanish Peseta (A account1.00",
+ "Spanish Peseta (convertible account1.00",
+ "Special Drawing Right1.00",
+ "Sri Lankan Rupe1.00",
+ "Sudanese Poun1.00",
+ "Surinamese Dolla1.00",
+ "Surinamese Guilde1.00",
+ "Swazi Lilangen1.00",
+ "Swedish Kron1.00",
+ "Swiss Fran1.00",
+ "Syrian Poun1.00",
+ "T S1.00",
+ "TH1.00",
+ "TJ1.00",
+ "TM1.00",
+ "TN1.00",
+ "TO1.00",
+ "TP1.00",
+ "TR1.00",
+ "TT1.00",
+ "TW1.00",
+ "TZ1.00",
+ "New Taiwan Dolla1.00",
+ "Tajikistani Rubl1.00",
+ "Tajikistani Somon1.00",
+ "Tanzanian Shillin1.00",
+ "Testing Currency Cod1.00",
+ "Thai Bah1.00",
+ "Timorese Escud1.00",
+ "Tongan Pa\\u20bbang1.00",
+ "Trinidad & Tobago Dolla1.00",
+ "Tunisian Dina1.00",
+ "Turkish Lir1.00",
+ "Turkmenistani Mana1.00",
+ "U S1.00",
+ "U1.00",
+ "UA1.00",
+ "UG1.00",
+ "US Dolla1.00",
+ "US Dollar (Next day1.00",
+ "US Dollar (Same day1.00",
+ "US1.00",
+ "UY1.00",
+ "UZ1.00",
+ "Ugandan Shillin1.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\\u201319931.00",
+ "Uruguay Peso Uruguay1.00",
+ "Uruguay Peso (Indexed Units1.00",
+ "Uzbekistani So1.00",
+ "V1.00",
+ "VE1.00",
+ "VN1.00",
+ "VU1.00",
+ "Vanuatu Vat1.00",
+ "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",
+ "Samoa Tal1.00",
+ "XA1.00",
+ "XB1.00",
+ "XC1.00",
+ "XD1.00",
+ "XE1.00",
+ "XF1.00",
+ "XO1.00",
+ "XP1.00",
+ "XR1.00",
+ "XT1.00",
+ "XX1.00",
+ "YD1.00",
+ "YE1.00",
+ "YU1.00",
+ "Yemeni Dina1.00",
+ "Yemeni Ria1.00",
+ "Yugoslavian Convertible Dina1.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\\u201319981.00",
+ "Zairean Zair1.00",
+ "Zambian Kwach1.00",
+ "Zimbabwean Dollar (1980\\u201320081.00",
+ "dra1.00",
+ "lar1.00",
+ "le1.00",
+ "man1.00",
+ "so1.00",
+ };
+
+ Locale locale("en_US");
+ for (uint32_t i=0; i<UPRV_LENGTHOF(DATA); ++i) {
+ UnicodeString formatted = ctou(DATA[i]);
+ UErrorCode status = U_ZERO_ERROR;
+ LocalPointer<NumberFormat> 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<CurrencyAmount> 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; i<UPRV_LENGTHOF(WRONG_DATA); ++i) {
+ UnicodeString formatted = ctou(WRONG_DATA[i]);
+ UErrorCode status = U_ZERO_ERROR;
+ NumberFormat* numFmt = NumberFormat::createInstance(locale, UNUM_CURRENCY, status);
+ if (numFmt != NULL && U_SUCCESS(status)) {
+ ParsePosition parsePos;
+ LocalPointer<CurrencyAmount> currAmt(numFmt->parseCurrency(formatted, parsePos));
+ if (parsePos.getIndex() > 0) {
+ double doubleVal = currAmt->getNumber().getDouble(status);
+ errln("Parsed as currency, should not have: " + formatted + " -> " + doubleVal);
+ }
+ } else {
+ dataerrln("Unable to create NumberFormat. - %s", u_errorName(status));
+ delete numFmt;
+ break;
+ }
+ delete numFmt;
+ }
+}
+
+const char* attrString(int32_t);
+
+// UnicodeString s;
+// std::string ss;
+// std::cout << s.toUTF8String(ss)
+void NumberFormatTest::expectPositions(FieldPositionIterator& iter, int32_t *values, int32_t tupleCount,
+ const UnicodeString& str) {
+ UBool found[10];
+ FieldPosition fp;
+
+ if (tupleCount > 10) {
+ assertTrue("internal error, tupleCount too large", FALSE);
+ } else {
+ for (int i = 0; i < tupleCount; ++i) {
+ found[i] = FALSE;
+ }
+ }
+
+ logln(str);
+ while (iter.next(fp)) {
+ UBool ok = FALSE;
+ int32_t id = fp.getField();
+ int32_t start = fp.getBeginIndex();
+ int32_t limit = fp.getEndIndex();
+
+ // is there a logln using printf?
+ char buf[128];
+ sprintf(buf, "%24s %3d %3d %3d", attrString(id), id, start, limit);
+ logln(buf);
+
+ for (int i = 0; i < tupleCount; ++i) {
+ if (found[i]) {
+ continue;
+ }
+ if (values[i*3] == id &&
+ values[i*3+1] == start &&
+ values[i*3+2] == limit) {
+ found[i] = ok = TRUE;
+ break;
+ }
+ }
+
+ assertTrue((UnicodeString)"found [" + id + "," + start + "," + limit + "]", ok);
+ }
+
+ // check that all were found
+ UBool ok = TRUE;
+ for (int i = 0; i < tupleCount; ++i) {
+ if (!found[i]) {
+ ok = FALSE;
+ assertTrue((UnicodeString) "missing [" + values[i*3] + "," + values[i*3+1] + "," + values[i*3+2] + "]", found[i]);
+ }
+ }
+ assertTrue("no expected values were missing", ok);
+}
+
+void NumberFormatTest::expectPosition(FieldPosition& pos, int32_t id, int32_t start, int32_t limit,
+ const UnicodeString& str) {
+ logln(str);
+ assertTrue((UnicodeString)"id " + id + " == " + pos.getField(), id == pos.getField());
+ assertTrue((UnicodeString)"begin " + start + " == " + pos.getBeginIndex(), start == pos.getBeginIndex());
+ assertTrue((UnicodeString)"end " + limit + " == " + pos.getEndIndex(), limit == pos.getEndIndex());
+}
+
+void NumberFormatTest::TestFieldPositionIterator() {
+ // bug 7372
+ UErrorCode status = U_ZERO_ERROR;
+ FieldPositionIterator iter1;
+ FieldPositionIterator iter2;
+ FieldPosition pos;
+
+ DecimalFormat *decFmt = (DecimalFormat *) NumberFormat::createInstance(status);
+ if (failure(status, "NumberFormat::createInstance", TRUE)) return;
+
+ double num = 1234.56;
+ UnicodeString str1;
+ UnicodeString str2;
+
+ assertTrue((UnicodeString)"self==", iter1 == iter1);
+ assertTrue((UnicodeString)"iter1==iter2", iter1 == iter2);
+
+ decFmt->format(num, str1, &iter1, status);
+ assertTrue((UnicodeString)"iter1 != iter2", iter1 != iter2);
+ decFmt->format(num, str2, &iter2, status);
+ assertTrue((UnicodeString)"iter1 == iter2 (2)", iter1 == iter2);
+ iter1.next(pos);
+ assertTrue((UnicodeString)"iter1 != iter2 (2)", iter1 != iter2);
+ iter2.next(pos);
+ assertTrue((UnicodeString)"iter1 == iter2 (3)", iter1 == iter2);
+
+ // should format ok with no iterator
+ str2.remove();
+ decFmt->format(num, str2, NULL, status);
+ assertEquals("null fpiter", str1, str2);
+
+ delete decFmt;
+}
+
+void NumberFormatTest::TestFormatAttributes() {
+ Locale locale("en_US");
+ UErrorCode status = U_ZERO_ERROR;
+ DecimalFormat *decFmt = (DecimalFormat *) NumberFormat::createInstance(locale, UNUM_CURRENCY, status);
+ if (failure(status, "NumberFormat::createInstance", TRUE)) return;
+ double val = 12345.67;
+
+ {
+ int32_t expected[] = {
+ UNUM_CURRENCY_FIELD, 0, 1,
+ UNUM_GROUPING_SEPARATOR_FIELD, 3, 4,
+ UNUM_INTEGER_FIELD, 1, 7,
+ UNUM_DECIMAL_SEPARATOR_FIELD, 7, 8,
+ UNUM_FRACTION_FIELD, 8, 10,
+ };
+ int32_t tupleCount = UPRV_LENGTHOF(expected)/3;
+
+ FieldPositionIterator posIter;
+ UnicodeString result;
+ decFmt->format(val, result, &posIter, status);
+ expectPositions(posIter, expected, tupleCount, result);
+ }
+ {
+ FieldPosition fp(UNUM_INTEGER_FIELD);
+ UnicodeString result;
+ decFmt->format(val, result, fp);
+ expectPosition(fp, UNUM_INTEGER_FIELD, 1, 7, result);
+ }
+ {
+ FieldPosition fp(UNUM_FRACTION_FIELD);
+ UnicodeString result;
+ decFmt->format(val, result, fp);
+ expectPosition(fp, UNUM_FRACTION_FIELD, 8, 10, result);
+ }
+ delete decFmt;
+
+ decFmt = (DecimalFormat *) NumberFormat::createInstance(locale, UNUM_SCIENTIFIC, status);
+ val = -0.0000123;
+ {
+ int32_t expected[] = {
+ UNUM_SIGN_FIELD, 0, 1,
+ UNUM_INTEGER_FIELD, 1, 2,
+ UNUM_DECIMAL_SEPARATOR_FIELD, 2, 3,
+ UNUM_FRACTION_FIELD, 3, 5,
+ UNUM_EXPONENT_SYMBOL_FIELD, 5, 6,
+ UNUM_EXPONENT_SIGN_FIELD, 6, 7,
+ UNUM_EXPONENT_FIELD, 7, 8
+ };
+ int32_t tupleCount = UPRV_LENGTHOF(expected)/3;
+
+ FieldPositionIterator posIter;
+ UnicodeString result;
+ decFmt->format(val, result, &posIter, status);
+ expectPositions(posIter, expected, tupleCount, result);
+ }
+ {
+ FieldPosition fp(UNUM_INTEGER_FIELD);
+ UnicodeString result;
+ decFmt->format(val, result, fp);
+ expectPosition(fp, UNUM_INTEGER_FIELD, 1, 2, result);
+ }
+ {
+ FieldPosition fp(UNUM_FRACTION_FIELD);
+ UnicodeString result;
+ decFmt->format(val, result, fp);
+ expectPosition(fp, UNUM_FRACTION_FIELD, 3, 5, result);
+ }
+ delete decFmt;
+
+ fflush(stderr);
+}
+
+const char* attrString(int32_t attrId) {
+ switch (attrId) {
+ case UNUM_INTEGER_FIELD: return "integer";
+ case UNUM_FRACTION_FIELD: return "fraction";
+ case UNUM_DECIMAL_SEPARATOR_FIELD: return "decimal separator";
+ case UNUM_EXPONENT_SYMBOL_FIELD: return "exponent symbol";
+ case UNUM_EXPONENT_SIGN_FIELD: return "exponent sign";
+ case UNUM_EXPONENT_FIELD: return "exponent";
+ case UNUM_GROUPING_SEPARATOR_FIELD: return "grouping separator";
+ case UNUM_CURRENCY_FIELD: return "currency";
+ case UNUM_PERCENT_FIELD: return "percent";
+ case UNUM_PERMILL_FIELD: return "permille";
+ case UNUM_SIGN_FIELD: return "sign";
+ default: return "";
+ }
+}
+
+//
+// Test formatting & parsing of big decimals.
+// API test, not a comprehensive test.
+// See DecimalFormatTest/DataDrivenTests
+//
+#define ASSERT_SUCCESS(status) { \
+ assertSuccess(UnicodeString("file ") + __FILE__ + ", line " + __LINE__, (status)); \
+}
+#define ASSERT_EQUALS(expected, actual) { \
+ assertEquals(UnicodeString("file ") + __FILE__ + ", line " + __LINE__, (expected), (actual)); \
+}
+
+void NumberFormatTest::TestDecimal() {
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ Formattable f("12.345678999987654321E666", status);
+ ASSERT_SUCCESS(status);
+ StringPiece s = f.getDecimalNumber(status);
+ ASSERT_SUCCESS(status);
+ ASSERT_EQUALS("1.2345678999987654321E+667", s.data());
+ //printf("%s\n", s.data());
+ }
+
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ Formattable f1("this is not a number", status);
+ ASSERT_EQUALS(U_DECIMAL_NUMBER_SYNTAX_ERROR, status);
+ }
+
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ Formattable f;
+ f.setDecimalNumber("123.45", status);
+ ASSERT_SUCCESS(status);
+ ASSERT_EQUALS( Formattable::kDouble, f.getType());
+ ASSERT_EQUALS(123.45, f.getDouble());
+ ASSERT_EQUALS(123.45, f.getDouble(status));
+ ASSERT_SUCCESS(status);
+ ASSERT_EQUALS("123.45", f.getDecimalNumber(status).data());
+ ASSERT_SUCCESS(status);
+
+ f.setDecimalNumber("4.5678E7", status);
+ int32_t n;
+ n = f.getLong();
+ ASSERT_EQUALS(45678000, n);
+
+ status = U_ZERO_ERROR;
+ f.setDecimalNumber("-123", status);
+ ASSERT_SUCCESS(status);
+ ASSERT_EQUALS( Formattable::kLong, f.getType());
+ ASSERT_EQUALS(-123, f.getLong());
+ ASSERT_EQUALS(-123, f.getLong(status));
+ ASSERT_SUCCESS(status);
+ ASSERT_EQUALS("-123", f.getDecimalNumber(status).data());
+ ASSERT_SUCCESS(status);
+
+ status = U_ZERO_ERROR;
+ f.setDecimalNumber("1234567890123", status); // Number too big for 32 bits
+ ASSERT_SUCCESS(status);
+ ASSERT_EQUALS( Formattable::kInt64, f.getType());
+ ASSERT_EQUALS(1234567890123LL, f.getInt64());
+ ASSERT_EQUALS(1234567890123LL, f.getInt64(status));
+ ASSERT_SUCCESS(status);
+ ASSERT_EQUALS("1234567890123", f.getDecimalNumber(status).data());
+ ASSERT_SUCCESS(status);
+ }
+
+ {
+ UErrorCode status = U_ZERO_ERROR;
+ NumberFormat *fmtr = NumberFormat::createInstance(Locale::getUS(), UNUM_DECIMAL, status);
+ if (U_FAILURE(status) || fmtr == NULL) {
+ dataerrln("Unable to create NumberFormat");
+ } else {
+ UnicodeString formattedResult;
+ StringPiece num("244444444444444444444444444444444444446.4");
+ fmtr->format(num, formattedResult, NULL, status);
+ ASSERT_SUCCESS(status);
+ ASSERT_EQUALS("244,444,444,444,444,444,444,444,444,444,444,444,446.4", formattedResult);
+ //std::string ss; std::cout << formattedResult.toUTF8String(ss);
+ delete fmtr;
+ }
+ }
+
+ {
+ // Check formatting a DigitList. DigitList is internal, but this is
+ // a critical interface that must work.
+ UErrorCode status = U_ZERO_ERROR;
+ NumberFormat *fmtr = NumberFormat::createInstance(Locale::getUS(), UNUM_DECIMAL, status);
+ if (U_FAILURE(status) || fmtr == NULL) {
+ dataerrln("Unable to create NumberFormat");
+ } else {
+ UnicodeString formattedResult;
+ DigitList dl;
+ StringPiece num("123.4566666666666666666666666666666666621E+40");
+ dl.set(num, status);
+ ASSERT_SUCCESS(status);
+ fmtr->format(dl, formattedResult, NULL, status);
+ ASSERT_SUCCESS(status);
+ ASSERT_EQUALS("1,234,566,666,666,666,666,666,666,666,666,666,666,621,000", formattedResult);
+
+ status = U_ZERO_ERROR;
+ num.set("666.666");
+ dl.set(num, status);
+ FieldPosition pos(NumberFormat::FRACTION_FIELD);
+ ASSERT_SUCCESS(status);
+ formattedResult.remove();
+ fmtr->format(dl, formattedResult, pos, status);
+ ASSERT_SUCCESS(status);
+ ASSERT_EQUALS("666.666", formattedResult);
+ ASSERT_EQUALS(4, pos.getBeginIndex());
+ ASSERT_EQUALS(7, pos.getEndIndex());
+ delete fmtr;
+ }
+ }
+
+ {
+ // Check a parse with a formatter with a multiplier.
+ UErrorCode status = U_ZERO_ERROR;
+ NumberFormat *fmtr = NumberFormat::createInstance(Locale::getUS(), UNUM_PERCENT, status);
+ if (U_FAILURE(status) || fmtr == NULL) {
+ dataerrln("Unable to create NumberFormat");
+ } else {
+ UnicodeString input = "1.84%";
+ Formattable result;
+ fmtr->parse(input, result, status);
+ ASSERT_SUCCESS(status);
+ 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;
+ NumberFormat *fmtr = NumberFormat::createInstance(Locale::getUS(), UNUM_DECIMAL, status);
+ if (U_FAILURE(status) || fmtr == NULL) {
+ dataerrln("Unable to create NumberFormat");
+ } else {
+ UnicodeString input = "1.002200044400088880000070000";
+ Formattable result;
+ fmtr->parse(input, result, status);
+ ASSERT_SUCCESS(status);
+ ASSERT_EQUALS(0, strcmp("1.00220004440008888000007", result.getDecimalNumber(status).data()));
+ ASSERT_EQUALS(1.00220004440008888, result.getDouble());
+ //std::cout << result.getDecimalNumber(status).data();
+ delete fmtr;
+ }
+ }
+#endif
+
+}
+
+void NumberFormatTest::TestCurrencyFractionDigits() {
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString text1, text2;
+ double value = 99.12345;
+
+ // Create currenct instance
+ NumberFormat* fmt = NumberFormat::createCurrencyInstance("ja_JP", status);
+ if (U_FAILURE(status) || fmt == NULL) {
+ dataerrln("Unable to create NumberFormat");
+ } else {
+ fmt->format(value, text1);
+
+ // Reset the same currency and format the test value again
+ fmt->setCurrency(fmt->getCurrency(), status);
+ ASSERT_SUCCESS(status);
+ fmt->format(value, text2);
+
+ if (text1 != text2) {
+ errln((UnicodeString)"NumberFormat::format() should return the same result - text1="
+ + text1 + " text2=" + text2);
+ }
+ }
+ 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(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() {
+
+ /* Test that number formats are properly inherited from es_419 */
+ /* These could be subject to change if the CLDR data changes */
+ static const char* parentLocaleTests[][2]= {
+ /* locale ID */ /* expected */
+ {"es_CO", "1.250,75" },
+ {"es_ES", "1.250,75" },
+ {"es_GQ", "1.250,75" },
+ {"es_MX", "1,250.75" },
+ {"es_US", "1,250.75" },
+ {"es_VE", "1.250,75" },
+ };
+
+ UnicodeString s;
+
+ 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);
+ expected = expected.unescape();
+ char loc[256]={0};
+ uloc_canonicalize(localeID, loc, 256, &status);
+ NumberFormat *fmt= NumberFormat::createInstance(Locale(loc), status);
+ if(U_FAILURE(status)){
+ dataerrln("Could not create number formatter for locale %s - %s",localeID, u_errorName(status));
+ continue;
+ }
+ s.remove();
+ fmt->format(1250.75, s);
+ if(s!=expected){
+ errln(UnicodeString("FAIL: Expected: ")+expected
+ + UnicodeString(" Got: ") + s
+ + UnicodeString( " for locale: ")+ UnicodeString(localeID) );
+ }
+ if (U_FAILURE(status)){
+ errln((UnicodeString)"FAIL: Status " + (int32_t)status);
+ }
+ delete fmt;
+ }
+
+}
+
+/**
+ * Test available numbering systems API.
+ */
+void NumberFormatTest::TestAvailableNumberingSystems() {
+ UErrorCode status = U_ZERO_ERROR;
+ StringEnumeration *availableNumberingSystems = NumberingSystem::getAvailableNames(status);
+ CHECK_DATA(status, "NumberingSystem::getAvailableNames()")
+
+ int32_t nsCount = availableNumberingSystems->count(status);
+ 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 */
+ /* each name returned, attempting to create a numbering system based on that name and */
+ /* verifying that the name returned from the resulting numbering system is the same */
+ /* one that we initially thought. */
+
+ int32_t len;
+ 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);
+ }
+
+ delete ns;
+ }
+
+ delete availableNumberingSystems;
+}
+
+void
+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);
+ if ( U_FAILURE(status) ) {
+ dataerrln("FAIL: error in unum_open() - %s", u_errorName(status));
+ return;
+ }
+
+ unum_setSymbol(fmt,UNUM_INFINITY_SYMBOL,infstr,3,&status);
+ unum_setSymbol(fmt,UNUM_NAN_SYMBOL,nanstr,3,&status);
+ if ( U_FAILURE(status) ) {
+ errln("FAIL: error setting symbols");
+ }
+
+ double inf = uprv_getInfinity();
+
+ unum_setAttribute(fmt,UNUM_ROUNDING_MODE,UNUM_ROUND_HALFEVEN);
+ unum_setDoubleAttribute(fmt,UNUM_ROUNDING_INCREMENT,0);
+
+ 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<count;i++) {
+ UFormattable *uu = ufmt_getArrayItemByIndex(u, i, &valueStatus);
+ if(*Formattable::fromUFormattable(uu) != (array2[i])) {
+ errln("%s:%d: operator== did not match at index[%d] - %p vs %p", file, line, i,
+ (const void*)Formattable::fromUFormattable(uu), (const void*)&(array2[i]));
+ exactMatch = FALSE;
+ } else {
+ if(!testFormattableAsUFormattable("(sub item)",i,*Formattable::fromUFormattable(uu))) {
+ exactMatch = FALSE;
+ }
+ }
+ }
+ }
+ }
+ break;
+ case Formattable::kInt64:
+ expectUType = UFMT_INT64;
+ exactMatch = (f.getInt64()==ufmt_getInt64(u, &valueStatus));
+ triedExact = TRUE;
+ break;
+ case Formattable::kObject:
+ expectUType = UFMT_OBJECT;
+ exactMatch = (f.getObject()==ufmt_getObject(u, &valueStatus));
+ triedExact = TRUE;
+ break;
+ }
+ UFormattableType uType = ufmt_getType(u, &status);
+
+ if(U_FAILURE(status)) {
+ errln("%s:%d: Error calling ufmt_getType - %s", file, line, u_errorName(status));
+ return FALSE;
+ }
+
+ if(uType != expectUType) {
+ errln("%s:%d: got type (%d) expected (%d) from ufmt_getType", file, line, (int) uType, (int) expectUType);
+ }
+
+ if(triedExact) {
+ if(U_FAILURE(valueStatus)) {
+ errln("%s:%d: got err %s trying to ufmt_get...() for exact match check", file, line, u_errorName(valueStatus));
+ } else if(!exactMatch) {
+ errln("%s:%d: failed exact match for the Formattable type", file, line);
+ } else {
+ logln("%s:%d: exact match OK", file, line);
+ }
+ } else {
+ logln("%s:%d: note, did not attempt exact match for this formattable type", file, line);
+ }
+
+ if( assertEquals(fileLine + " isNumeric()", f.isNumeric(), ufmt_isNumeric(u))
+ && f.isNumeric()) {
+ UErrorCode convStatus = U_ZERO_ERROR;
+
+ if(uType != UFMT_INT64) { // may fail to compare
+ assertTrue(fileLine + " as doubles ==", f.getDouble(convStatus)==ufmt_getDouble(u, &convStatus));
+ }
+
+ if( assertSuccess(fileLine + " (numeric conversion status)", convStatus) ) {
+ StringPiece fDecNum = f.getDecimalNumber(convStatus);
+#if 1
+ int32_t len;
+ const char *decNumChars = ufmt_getDecNumChars(u, &len, &convStatus);
+#else
+ // copy version
+ char decNumChars[200];
+ int32_t len = ufmt_getDecNumChars(u, decNumChars, 200, &convStatus);
+#endif
+
+ if( assertSuccess(fileLine + " (decNumbers conversion)", convStatus) ) {
+ logln(fileLine + decNumChars);
+ assertEquals(fileLine + " decNumChars length==", len, fDecNum.length());
+ assertEquals(fileLine + " decNumChars digits", decNumChars, fDecNum.data());
+ }
+
+ UErrorCode int64ConversionF = U_ZERO_ERROR;
+ int64_t l = f.getInt64(int64ConversionF);
+ UErrorCode int64ConversionU = U_ZERO_ERROR;
+ int64_t r = ufmt_getInt64(u, &int64ConversionU);
+
+ if( (l==r)
+ && ( uType != UFMT_INT64 ) // int64 better not overflow
+ && (U_INVALID_FORMAT_ERROR==int64ConversionU)
+ && (U_INVALID_FORMAT_ERROR==int64ConversionF) ) {
+ logln("%s:%d: OK: 64 bit overflow", file, line);
+ } else {
+ assertEquals(fileLine + " as int64 ==", l, r);
+ assertSuccess(fileLine + " Formattable.getnt64()", int64ConversionF);
+ assertSuccess(fileLine + " ufmt_getInt64()", int64ConversionU);
+ }
+ }
+ }
+ return exactMatch || !triedExact;
+}
+
+void NumberFormatTest::TestUFormattable(void) {
+ {
+ // test that a default formattable is equal to Formattable()
+ UErrorCode status = U_ZERO_ERROR;
+ LocalUFormattablePointer defaultUFormattable(ufmt_open(&status));
+ assertSuccess("calling umt_open", status);
+ Formattable defaultFormattable;
+ assertTrue((UnicodeString)"comparing ufmt_open() with Formattable()",
+ (defaultFormattable
+ == *(Formattable::fromUFormattable(defaultUFormattable.getAlias()))));
+ assertTrue((UnicodeString)"comparing ufmt_open() with Formattable()",
+ (defaultFormattable
+ == *(Formattable::fromUFormattable(defaultUFormattable.getAlias()))));
+ assertTrue((UnicodeString)"comparing Formattable() round tripped through UFormattable",
+ (defaultFormattable
+ == *(Formattable::fromUFormattable(defaultFormattable.toUFormattable()))));
+ assertTrue((UnicodeString)"comparing &Formattable() round tripped through UFormattable",
+ ((&defaultFormattable)
+ == Formattable::fromUFormattable(defaultFormattable.toUFormattable())));
+ assertFalse((UnicodeString)"comparing &Formattable() with ufmt_open()",
+ ((&defaultFormattable)
+ == Formattable::fromUFormattable(defaultUFormattable.getAlias())));
+ testFormattableAsUFormattable(__FILE__, __LINE__, defaultFormattable);
+ }
+ // test some random Formattables
+ {
+ Formattable f(ucal_getNow(), Formattable::kIsDate);
+ testFormattableAsUFormattable(__FILE__, __LINE__, f);
+ }
+ {
+ Formattable f((double)1.61803398874989484820); // golden ratio
+ testFormattableAsUFormattable(__FILE__, __LINE__, f);
+ }
+ {
+ Formattable f((int64_t)80994231587905127LL); // weight of the moon, in kilotons http://solarsystem.nasa.gov/planets/profile.cfm?Display=Facts&Object=Moon
+ testFormattableAsUFormattable(__FILE__, __LINE__, f);
+ }
+ {
+ Formattable f((int32_t)4); // random number, source: http://www.xkcd.com/221/
+ testFormattableAsUFormattable(__FILE__, __LINE__, f);
+ }
+ {
+ Formattable f("Hello world."); // should be invariant?
+ testFormattableAsUFormattable(__FILE__, __LINE__, f);
+ }
+ {
+ UErrorCode status2 = U_ZERO_ERROR;
+ Formattable f(StringPiece("73476730924573500000000.0"), status2); // weight of the moon, kg
+ assertSuccess("Constructing a StringPiece", status2);
+ testFormattableAsUFormattable(__FILE__, __LINE__, f);
+ }
+ {
+ UErrorCode status2 = U_ZERO_ERROR;
+ UObject *obj = new Locale();
+ Formattable f(obj);
+ assertSuccess("Constructing a Formattable from a default constructed Locale()", status2);
+ testFormattableAsUFormattable(__FILE__, __LINE__, f);
+ }
+ {
+ const Formattable array[] = {
+ Formattable(ucal_getNow(), Formattable::kIsDate),
+ Formattable((int32_t)4),
+ Formattable((double)1.234),
+ };
+
+ Formattable fa(array, 3);
+ testFormattableAsUFormattable(__FILE__, __LINE__, fa);
+ }
+}
+
+void NumberFormatTest::TestSignificantDigits(void) {
+ double input[] = {
+ 0, 0,
+ 0.1, -0.1,
+ 123, -123,
+ 12345, -12345,
+ 123.45, -123.45,
+ 123.44501, -123.44501,
+ 0.001234, -0.001234,
+ 0.00000000123, -0.00000000123,
+ 0.0000000000000000000123, -0.0000000000000000000123,
+ 1.2, -1.2,
+ 0.0000000012344501, -0.0000000012344501,
+ 123445.01, -123445.01,
+ 12344501000000000000000000000000000.0, -12344501000000000000000000000000000.0,
+ };
+ const char* expected[] = {
+ "0.00", "0.00",
+ "0.100", "-0.100",
+ "123", "-123",
+ "12345", "-12345",
+ "123.45", "-123.45",
+ "123.45", "-123.45",
+ "0.001234", "-0.001234",
+ "0.00000000123", "-0.00000000123",
+ "0.0000000000000000000123", "-0.0000000000000000000123",
+ "1.20", "-1.20",
+ "0.0000000012345", "-0.0000000012345",
+ "123450", "-123450",
+ "12345000000000000000000000000000000", "-12345000000000000000000000000000000",
+ };
+
+ UErrorCode status = U_ZERO_ERROR;
+ Locale locale("en_US");
+ LocalPointer<DecimalFormat> numberFormat(static_cast<DecimalFormat*>(
+ 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<DecimalFormat> numberFormat(static_cast<DecimalFormat*>(
+ 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<DecimalFormat> numberFormat(static_cast<DecimalFormat*>(
+ 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<DecimalFormat> 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<int64_t>(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<int64_t>(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<NumberFormat> 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<NumberFormat> 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<NumberFormat> nf(NumberFormat::createCurrencyInstance("sr_BA", status));
+ if (status.errDataIfFailureAndReset()) { return; }
+ ((DecimalFormat*) nf.getAlias())->applyPattern(u"#,##0.0 ¤¤¤", status);
+ ParsePosition ppos(0);
+ LocalPointer<CurrencyAmount> 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<NumberFormat> 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<NumberFormat> 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<NumberFormat> 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<NumberingSystem> 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<DecimalFormat> df(dynamic_cast<DecimalFormat*>(
+ 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<DecimalFormat*>(
+ 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<NumberFormat> 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<NumberFormat> 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<NumberFormat> 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<DecimalFormat*>(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<DecimalFormat> df1((DecimalFormat*) NumberFormat::createInstance("en", status), status);
+ LocalPointer<DecimalFormat> 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<NumberFormat> 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<double>(INT32_MAX) - 1,
+ static_cast<double>(INT32_MAX),
+ static_cast<double>(INT32_MAX) + 1,
+ static_cast<double>(INT32_MIN) - 1,
+ static_cast<double>(INT32_MIN),
+ static_cast<double>(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 <list> 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;
+ LocalPointer<NumberFormat>pFormat(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<DecimalFormatSymbols> 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<DecimalFormat> fmt((DecimalFormat*) NumberFormat::createInstance(status), status);
+ if (!assertSuccess("", status, true, __FILE__, __LINE__)) { return; }
+ fmt->applyPattern(pattern, status);
+ LocalPointer<DecimalFormat> 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<DecimalFormat> df1((DecimalFormat *)
+ NumberFormat::createInstance(Locale::getUS(), UNUM_CURRENCY, errorCode));
+ LocalPointer<DecimalFormat> 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<DecimalFormatSymbols> 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<DecimalFormat> 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<NumberFormat> 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<NumberFormat> 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<NumberFormat> 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<CurrencyAmount> 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 */