X-Git-Url: https://git.saurik.com/apple/icu.git/blobdiff_plain/374ca955a76ecab1204ca8bfa63ff9238d998416..ef6cf650f4a75c3f97de06b51fa104f2069b9ea2:/icuSources/test/intltest/numfmtst.cpp?ds=sidebyside diff --git a/icuSources/test/intltest/numfmtst.cpp b/icuSources/test/intltest/numfmtst.cpp index e6bf04c2..d877f3e4 100644 --- a/icuSources/test/intltest/numfmtst.cpp +++ b/icuSources/test/intltest/numfmtst.cpp @@ -1,6 +1,6 @@ /******************************************************************** - * COPYRIGHT: - * Copyright (c) 1997-2004, International Business Machines Corporation and + * COPYRIGHT: + * Copyright (c) 1997-2016, International Business Machines Corporation and * others. All Rights Reserved. ********************************************************************/ /* Modification History: @@ -15,6 +15,7 @@ #include "numfmtst.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" @@ -24,63 +25,563 @@ #include "tokiter.h" #include "charstr.h" #include "putilimp.h" +#include "winnmtst.h" #include #include +#include +#include "cmemory.h" +#include "cstring.h" +#include "unicode/numsys.h" +#include "fmtableimp.h" +#include "numberformattesttuple.h" +#include "datadrivennumberformattestsuite.h" +#include "unicode/msgfmt.h" + +class NumberFormatTestDataDriven : public DataDrivenNumberFormatTestSuite { +protected: +UBool isFormatPass( + const NumberFormatTestTuple &tuple, + UnicodeString &appendErrorMessage, + UErrorCode &status); +UBool isToPatternPass( + const NumberFormatTestTuple &tuple, + UnicodeString &appendErrorMessage, + UErrorCode &status); +UBool isParsePass( + const NumberFormatTestTuple &tuple, + UnicodeString &appendErrorMessage, + UErrorCode &status); +UBool isParseCurrencyPass( + const NumberFormatTestTuple &tuple, + UnicodeString &appendErrorMessage, + UErrorCode &status); +}; + +static DigitList &strToDigitList( + const UnicodeString &str, + DigitList &digitList, + UErrorCode &status) { + if (U_FAILURE(status)) { + return digitList; + } + if (str == "NaN") { + digitList.set(uprv_getNaN()); + return digitList; + } + if (str == "-Inf") { + digitList.set(-1*uprv_getInfinity()); + return digitList; + } + if (str == "Inf") { + digitList.set(uprv_getInfinity()); + return digitList; + } + CharString formatValue; + formatValue.appendInvariantChars(str, status); + digitList.set(StringPiece(formatValue.data()), status, 0); + return digitList; +} + +static UnicodeString &format( + const DecimalFormat &fmt, + const DigitList &digitList, + UnicodeString &appendTo, + UErrorCode &status) { + if (U_FAILURE(status)) { + return appendTo; + } + FieldPosition fpos(FieldPosition::DONT_CARE); + return fmt.format(digitList, appendTo, fpos, status); +} + +template +static UnicodeString &format( + const DecimalFormat &fmt, + T value, + UnicodeString &appendTo, + UErrorCode &status) { + if (U_FAILURE(status)) { + return appendTo; + } + FieldPosition fpos(FieldPosition::DONT_CARE); + return fmt.format(value, appendTo, fpos, status); +} + +static void adjustDecimalFormat( + const NumberFormatTestTuple &tuple, + DecimalFormat &fmt, + UnicodeString &appendErrorMessage) { + if (tuple.minIntegerDigitsFlag) { + fmt.setMinimumIntegerDigits(tuple.minIntegerDigits); + } + if (tuple.maxIntegerDigitsFlag) { + fmt.setMaximumIntegerDigits(tuple.maxIntegerDigits); + } + if (tuple.minFractionDigitsFlag) { + fmt.setMinimumFractionDigits(tuple.minFractionDigits); + } + if (tuple.maxFractionDigitsFlag) { + fmt.setMaximumFractionDigits(tuple.maxFractionDigits); + } + if (tuple.currencyFlag) { + UErrorCode status = U_ZERO_ERROR; + UnicodeString currency(tuple.currency); + const UChar *terminatedCurrency = currency.getTerminatedBuffer(); + fmt.setCurrency(terminatedCurrency, status); + if (U_FAILURE(status)) { + appendErrorMessage.append("Error setting currency."); + } + } + if (tuple.minGroupingDigitsFlag) { + fmt.setMinimumGroupingDigits(tuple.minGroupingDigits); + } + if (tuple.useSigDigitsFlag) { + fmt.setSignificantDigitsUsed(tuple.useSigDigits != 0); + } + if (tuple.minSigDigitsFlag) { + fmt.setMinimumSignificantDigits(tuple.minSigDigits); + } + if (tuple.maxSigDigitsFlag) { + fmt.setMaximumSignificantDigits(tuple.maxSigDigits); + } + if (tuple.useGroupingFlag) { + fmt.setGroupingUsed(tuple.useGrouping != 0); + } + if (tuple.multiplierFlag) { + fmt.setMultiplier(tuple.multiplier); + } + if (tuple.roundingIncrementFlag) { + fmt.setRoundingIncrement(tuple.roundingIncrement); + } + if (tuple.formatWidthFlag) { + fmt.setFormatWidth(tuple.formatWidth); + } + if (tuple.padCharacterFlag) { + fmt.setPadCharacter(tuple.padCharacter); + } + if (tuple.useScientificFlag) { + fmt.setScientificNotation(tuple.useScientific != 0); + } + if (tuple.groupingFlag) { + fmt.setGroupingSize(tuple.grouping); + } + if (tuple.grouping2Flag) { + fmt.setSecondaryGroupingSize(tuple.grouping2); + } + if (tuple.roundingModeFlag) { + fmt.setRoundingMode(tuple.roundingMode); + } + if (tuple.currencyUsageFlag) { + UErrorCode status = U_ZERO_ERROR; + fmt.setCurrencyUsage(tuple.currencyUsage, &status); + if (U_FAILURE(status)) { + appendErrorMessage.append("CurrencyUsage: error setting."); + } + } + if (tuple.minimumExponentDigitsFlag) { + fmt.setMinimumExponentDigits(tuple.minimumExponentDigits); + } + if (tuple.exponentSignAlwaysShownFlag) { + fmt.setExponentSignAlwaysShown(tuple.exponentSignAlwaysShown != 0); + } + if (tuple.decimalSeparatorAlwaysShownFlag) { + fmt.setDecimalSeparatorAlwaysShown( + tuple.decimalSeparatorAlwaysShown != 0); + } + if (tuple.padPositionFlag) { + fmt.setPadPosition(tuple.padPosition); + } + if (tuple.positivePrefixFlag) { + fmt.setPositivePrefix(tuple.positivePrefix); + } + if (tuple.positiveSuffixFlag) { + fmt.setPositiveSuffix(tuple.positiveSuffix); + } + if (tuple.negativePrefixFlag) { + fmt.setNegativePrefix(tuple.negativePrefix); + } + if (tuple.negativeSuffixFlag) { + fmt.setNegativeSuffix(tuple.negativeSuffix); + } + if (tuple.localizedPatternFlag) { + UErrorCode status = U_ZERO_ERROR; + fmt.applyLocalizedPattern(tuple.localizedPattern, status); + if (U_FAILURE(status)) { + appendErrorMessage.append("Error setting localized pattern."); + } + } + fmt.setLenient(NFTT_GET_FIELD(tuple, lenient, 1) != 0); + if (tuple.parseIntegerOnlyFlag) { + fmt.setParseIntegerOnly(tuple.parseIntegerOnly != 0); + } + if (tuple.decimalPatternMatchRequiredFlag) { + fmt.setDecimalPatternMatchRequired( + tuple.decimalPatternMatchRequired != 0); + } + if (tuple.parseNoExponentFlag) { + UErrorCode status = U_ZERO_ERROR; + fmt.setAttribute( + UNUM_PARSE_NO_EXPONENT, + tuple.parseNoExponent, + status); + if (U_FAILURE(status)) { + appendErrorMessage.append("Error setting parse no exponent flag."); + } + } +} + +static DecimalFormat *newDecimalFormat( + const Locale &locale, + const UnicodeString &pattern, + UErrorCode &status) { + if (U_FAILURE(status)) { + return NULL; + } + LocalPointer symbols( + new DecimalFormatSymbols(locale, status), status); + if (U_FAILURE(status)) { + return NULL; + } + UParseError perror; + LocalPointer result(new DecimalFormat( + pattern, symbols.getAlias(), perror, status), status); + if (!result.isNull()) { + symbols.orphan(); + } + if (U_FAILURE(status)) { + return NULL; + } + return result.orphan(); +} + +static DecimalFormat *newDecimalFormat( + const NumberFormatTestTuple &tuple, + UErrorCode &status) { + if (U_FAILURE(status)) { + return NULL; + } + Locale en("en"); + return newDecimalFormat( + NFTT_GET_FIELD(tuple, locale, en), + NFTT_GET_FIELD(tuple, pattern, "0"), + status); +} + +UBool NumberFormatTestDataDriven::isFormatPass( + const NumberFormatTestTuple &tuple, + UnicodeString &appendErrorMessage, + UErrorCode &status) { + if (U_FAILURE(status)) { + return FALSE; + } + LocalPointer fmtPtr(newDecimalFormat(tuple, status)); + if (U_FAILURE(status)) { + appendErrorMessage.append("Error creating DecimalFormat."); + return FALSE; + } + adjustDecimalFormat(tuple, *fmtPtr, appendErrorMessage); + if (appendErrorMessage.length() > 0) { + return FALSE; + } + DigitList digitList; + strToDigitList(tuple.format, digitList, status); + { + UnicodeString appendTo; + format(*fmtPtr, digitList, appendTo, status); + if (U_FAILURE(status)) { + appendErrorMessage.append("Error formatting."); + return FALSE; + } + if (appendTo != tuple.output) { + appendErrorMessage.append( + UnicodeString("Expected: ") + tuple.output + ", got: " + appendTo); + return FALSE; + } + } + double doubleVal = digitList.getDouble(); + { + UnicodeString appendTo; + format(*fmtPtr, doubleVal, appendTo, status); + if (U_FAILURE(status)) { + appendErrorMessage.append("Error formatting."); + return FALSE; + } + if (appendTo != tuple.output) { + appendErrorMessage.append( + UnicodeString("double Expected: ") + tuple.output + ", got: " + appendTo); + return FALSE; + } + } + if (!uprv_isNaN(doubleVal) && !uprv_isInfinite(doubleVal) && doubleVal == uprv_floor(doubleVal)) { + int64_t intVal = digitList.getInt64(); + { + UnicodeString appendTo; + format(*fmtPtr, intVal, appendTo, status); + if (U_FAILURE(status)) { + appendErrorMessage.append("Error formatting."); + return FALSE; + } + if (appendTo != tuple.output) { + appendErrorMessage.append( + UnicodeString("int64 Expected: ") + tuple.output + ", got: " + appendTo); + return FALSE; + } + } + } + return TRUE; +} + +UBool NumberFormatTestDataDriven::isToPatternPass( + const NumberFormatTestTuple &tuple, + UnicodeString &appendErrorMessage, + UErrorCode &status) { + if (U_FAILURE(status)) { + return FALSE; + } + LocalPointer fmtPtr(newDecimalFormat(tuple, status)); + if (U_FAILURE(status)) { + appendErrorMessage.append("Error creating DecimalFormat."); + return FALSE; + } + adjustDecimalFormat(tuple, *fmtPtr, appendErrorMessage); + if (appendErrorMessage.length() > 0) { + return FALSE; + } + if (tuple.toPatternFlag) { + UnicodeString actual; + fmtPtr->toPattern(actual); + if (actual != tuple.toPattern) { + appendErrorMessage.append( + UnicodeString("Expected: ") + tuple.toPattern + ", got: " + actual + ". "); + } + } + if (tuple.toLocalizedPatternFlag) { + UnicodeString actual; + fmtPtr->toLocalizedPattern(actual); + if (actual != tuple.toLocalizedPattern) { + appendErrorMessage.append( + UnicodeString("Expected: ") + tuple.toLocalizedPattern + ", got: " + actual + ". "); + } + } + return appendErrorMessage.length() == 0; +} + +UBool NumberFormatTestDataDriven::isParsePass( + const NumberFormatTestTuple &tuple, + UnicodeString &appendErrorMessage, + UErrorCode &status) { + if (U_FAILURE(status)) { + return FALSE; + } + LocalPointer fmtPtr(newDecimalFormat(tuple, status)); + if (U_FAILURE(status)) { + appendErrorMessage.append("Error creating DecimalFormat."); + return FALSE; + } + adjustDecimalFormat(tuple, *fmtPtr, appendErrorMessage); + if (appendErrorMessage.length() > 0) { + return FALSE; + } + Formattable result; + ParsePosition ppos; + fmtPtr->parse(tuple.parse, result, ppos); + if (ppos.getIndex() == 0) { + if (tuple.output != "fail") { + appendErrorMessage.append("Parse failed but was expected to succeed."); + return FALSE; + } + return TRUE; + } + UnicodeString resultStr(UnicodeString::fromUTF8(result.getDecimalNumber(status))); + if (tuple.output == "fail") { + appendErrorMessage.append(UnicodeString("Parse succeeded: ") + resultStr + ", but was expected to fail."); + return FALSE; + } + DigitList expected; + strToDigitList(tuple.output, expected, status); + if (U_FAILURE(status)) { + appendErrorMessage.append("Error parsing."); + return FALSE; + } + if (expected != *result.getDigitList()) { + appendErrorMessage.append( + UnicodeString("Expected: ") + tuple.output + ", got: " + resultStr + ". "); + return FALSE; + } + return TRUE; +} + +UBool NumberFormatTestDataDriven::isParseCurrencyPass( + const NumberFormatTestTuple &tuple, + UnicodeString &appendErrorMessage, + UErrorCode &status) { + if (U_FAILURE(status)) { + return FALSE; + } + LocalPointer fmtPtr(newDecimalFormat(tuple, status)); + if (U_FAILURE(status)) { + appendErrorMessage.append("Error creating DecimalFormat."); + return FALSE; + } + adjustDecimalFormat(tuple, *fmtPtr, appendErrorMessage); + if (appendErrorMessage.length() > 0) { + return FALSE; + } + ParsePosition ppos; + LocalPointer currAmt( + fmtPtr->parseCurrency(tuple.parse, ppos)); + if (ppos.getIndex() == 0) { + if (tuple.output != "fail") { + appendErrorMessage.append("Parse failed but was expected to succeed."); + return FALSE; + } + return TRUE; + } + UnicodeString currStr(currAmt->getISOCurrency()); + Formattable resultFormattable(currAmt->getNumber()); + UnicodeString resultStr(UnicodeString::fromUTF8(resultFormattable.getDecimalNumber(status))); + if (tuple.output == "fail") { + appendErrorMessage.append(UnicodeString("Parse succeeded: ") + resultStr + ", but was expected to fail."); + return FALSE; + } + DigitList expected; + strToDigitList(tuple.output, expected, status); + if (U_FAILURE(status)) { + appendErrorMessage.append("Error parsing."); + return FALSE; + } + if (expected != *currAmt->getNumber().getDigitList()) { + appendErrorMessage.append( + UnicodeString("Expected: ") + tuple.output + ", got: " + resultStr + ". "); + return FALSE; + } + if (currStr != tuple.outputCurrency) { + appendErrorMessage.append(UnicodeString( + "Expected currency: ") + tuple.outputCurrency + ", got: " + currStr + ". "); + return FALSE; + } + return TRUE; +} + +//#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); - - 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(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(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(TestNumberFormatTestTuple); + TESTCASE_AUTO(TestDataDriven); + TESTCASE_AUTO(TestDoubleLimit11439); + TESTCASE_AUTO(TestFastPathConsistent11524); + TESTCASE_AUTO(TestGetAffixes); + TESTCASE_AUTO(TestToPatternScientific11648); + TESTCASE_AUTO(TestBenchmark); + TESTCASE_AUTO(TestCtorApplyPatternDifference); + TESTCASE_AUTO(TestFractionalDigitsForCurrency); + TESTCASE_AUTO(TestFormatCurrencyPlural); + TESTCASE_AUTO(Test11868); + TESTCASE_AUTO(Test10727_RoundingZero); + TESTCASE_AUTO(Test11376_getAndSetPositivePrefix); + TESTCASE_AUTO(Test11475_signRecognition); + TESTCASE_AUTO(Test11640_getAffixes); + TESTCASE_AUTO(Test11649_toPatternWithMultiCurrency); + TESTCASE_AUTO_END; } - + // ------------------------------------- // Test API (increase code coverage) @@ -91,7 +592,7 @@ NumberFormatTest::TestAPI(void) 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); @@ -110,20 +611,73 @@ NumberFormatTest::TestAPI(void) status = U_ZERO_ERROR; } - delete test; + result.remove(); + int64_t ll = 12; + test->format(ll, result); + if (result != "12.00"){ + errln("format int64_t error"); + } + + ParsePosition ppos; + LocalPointer 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; } } +class StubNumberFormat :public NumberFormat{ +public: + StubNumberFormat(){}; + virtual UnicodeString& format(double ,UnicodeString& appendTo,FieldPosition& ) const { + return appendTo; + } + virtual UnicodeString& format(int32_t ,UnicodeString& appendTo,FieldPosition& ) const { + return appendTo.append((UChar)0x0033); + } + virtual UnicodeString& format(int64_t number,UnicodeString& appendTo,FieldPosition& pos) const { + return NumberFormat::format(number, appendTo, pos); + } + virtual UnicodeString& format(const Formattable& , UnicodeString& appendTo, FieldPosition& , UErrorCode& ) const { + return appendTo; + } + virtual void parse(const UnicodeString& , + Formattable& , + ParsePosition& ) const {} + virtual void parse( const UnicodeString& , + Formattable& , + UErrorCode& ) const {} + virtual UClassID getDynamicClassID(void) const { + static char classID = 0; + return (UClassID)&classID; + } + virtual Format* clone() const {return NULL;} +}; + +void +NumberFormatTest::TestCoverage(void){ + StubNumberFormat stub; + UnicodeString agent("agent"); + FieldPosition pos; + int64_t num = 4; + if (stub.format(num, agent, pos) != UnicodeString("agent3")){ + errln("NumberFormat::format(int64, UnicodString&, FieldPosition&) should delegate to (int32, ,)"); + }; +} + // Test various patterns void NumberFormatTest::TestPatterns(void) { 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])); + int32_t pat_length = UPRV_LENGTHOF(pat); const char* newpat[] = { "#0.#", "#0.", "#.0", "#" }; const char* num[] = { "0", "0.", ".0", "0" }; for (int32_t i=0; i 300 double val[] = { 0.01234, 123456789, 1.23e300, -3.141592653e-271 }; - int32_t val_length = (int32_t)(sizeof(val) / sizeof(val[0])); + int32_t val_length = UPRV_LENGTHOF(val); const char* valFormat[] = { // 0.####E0 @@ -211,7 +767,7 @@ NumberFormatTest::TestExponential(void) }; #elif DBL_MAX_10_EXP > 70 double val[] = { 0.01234, 123456789, 1.23e70, -3.141592653e-71 }; - int32_t val_length = sizeof(val) / sizeof(val[0]); + int32_t val_length = UPRV_LENGTHOF(val); char* valFormat[] = { // 0.####E0 @@ -240,7 +796,7 @@ NumberFormatTest::TestExponential(void) #endif int32_t lval[] = { 0, -1, 1, 123456789 }; - int32_t lval_length = (int32_t)(sizeof(lval) / sizeof(lval[0])); + int32_t lval_length = UPRV_LENGTHOF(lval); const char* lvalFormat[] = { // 0.####E0 @@ -284,7 +840,7 @@ NumberFormatTest::TestExponential(void) 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 @@ -365,7 +921,7 @@ NumberFormatTest::TestScientific2() { delete fmt; } -void +void NumberFormatTest::TestScientificGrouping() { // jb 2552 UErrorCode status = U_ZERO_ERROR; @@ -380,7 +936,7 @@ NumberFormatTest::TestScientificGrouping() { } } -static void setFromString(DigitList& dl, const char* str) { +/*static void setFromString(DigitList& dl, const char* str) { char c; UBool decimalSet = FALSE; dl.clear(); @@ -399,12 +955,16 @@ static void setFromString(DigitList& dl, const char* str) { 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"); @@ -417,7 +977,7 @@ NumberFormatTest::TestInt64() { } // also test digitlist - int64_t int64max = U_INT64_MAX; +/* int64_t int64max = U_INT64_MAX; int64_t int64min = U_INT64_MIN; const char* int64maxstr = "9223372036854775807"; const char* int64minstr = "-9223372036854775808"; @@ -478,7 +1038,7 @@ NumberFormatTest::TestInt64() { if (dl.fitsIntoInt64(FALSE)) { errln(fail + "-(" + int64minstr + ") didn't fit"); } - } + }*/ } // ------------------------------------- @@ -490,15 +1050,20 @@ NumberFormatTest::TestQuotes(void) 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; @@ -508,7 +1073,7 @@ NumberFormatTest::TestQuotes(void) ((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; @@ -525,6 +1090,11 @@ NumberFormatTest::TestCurrencySign(void) 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"); @@ -533,11 +1103,11 @@ NumberFormatTest::TestCurrencySign(void) 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" @@ -550,16 +1120,16 @@ NumberFormatTest::TestCurrencySign(void) ((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))); } @@ -583,19 +1153,22 @@ NumberFormatTest::escape(UnicodeString& s) 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."} + {"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. @@ -605,35 +1178,41 @@ NumberFormatTest::TestCurrency(void) { UErrorCode status = U_ZERO_ERROR; NumberFormat* currencyFmt = NumberFormat::createCurrencyInstance(Locale::getCanadaFrench(), status); + if (U_FAILURE(status)) { + dataerrln("Error calling NumberFormat::createCurrencyInstance()"); + return; + } + UnicodeString s; currencyFmt->format(1.50, s); logln((UnicodeString)"Un pauvre ici a..........." + s); - if (!(s=="1,50 $")) - errln((UnicodeString)"FAIL: Expected 1,50 $"); + if (!(s==CharsToUnicodeString("1,50\\u00A0$"))) + errln((UnicodeString)"FAIL: Expected 1,50$"); delete currencyFmt; s.truncate(0); char loc[256]={0}; 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,50DM"); delete currencyFmt; s.truncate(0); len = uloc_canonicalize("fr_FR_PREEURO", loc, 256, &status); currencyFmt = NumberFormat::createCurrencyInstance(Locale(loc), status); currencyFmt->format(1.50, s); logln((UnicodeString)"Un pauvre en France a....." + s); - if (!(s=="1,50 F")) - errln((UnicodeString)"FAIL: Expected 1,50 F"); + if (!(s==CharsToUnicodeString("1,50\\u00A0F"))) + errln((UnicodeString)"FAIL: Expected 1,50F"); delete currencyFmt; if (U_FAILURE(status)) errln((UnicodeString)"FAIL: Status " + (int32_t)status); - - 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}; @@ -645,8 +1224,8 @@ NumberFormatTest::TestCurrency(void) } 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)){ @@ -655,7 +1234,7 @@ NumberFormatTest::TestCurrency(void) delete currencyFmt; } } - + // ------------------------------------- /** @@ -663,17 +1242,17 @@ NumberFormatTest::TestCurrency(void) */ 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(), @@ -683,7 +1262,7 @@ void NumberFormatTest::TestCurrencyObject() { 1234.56, CharsToUnicodeString("\\u00A51,235")); // Yen expectCurrency(*fmt, Locale("fr", "CH", ""), - 1234.56, "SwF1,234.55"); // 0.05 rounding + 1234.56, "CHF1,234.56"); // no more 0.05 rounding here, see cldrbug 5548 expectCurrency(*fmt, Locale::getUS(), 1234.56, "$1,234.56"); @@ -696,24 +1275,24 @@ void NumberFormatTest::TestCurrencyObject() { 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; } - + // ------------------------------------- /** @@ -731,60 +1310,313 @@ NumberFormatTest::TestParse(void) 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", + "\\u20105" +}; + +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 proper rounding by the format method. + * Test lenient parsing. */ void -NumberFormatTest::TestRounding487(void) +NumberFormatTest::TestLenientParse(void) { UErrorCode status = U_ZERO_ERROR; - NumberFormat *nf = NumberFormat::createInstance(status); - roundingTest(*nf, 0.00159999, 4, "0.0016"); - roundingTest(*nf, 0.00995, 4, "0.01"); + DecimalFormat *format = new DecimalFormat("(#,##0)", status); + Formattable n; - roundingTest(*nf, 12.3995, 3, "12.4"); + 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]); - roundingTest(*nf, 12.4999, 0, "12"); - roundingTest(*nf, - 19.5, 0, "-20"); - delete nf; - if (U_FAILURE(status)) errln((UnicodeString)"FAIL: Status " + (int32_t)status); -} + format->parse(testCase, n, status); + logln((UnicodeString)"parse(" + testCase + ") = " + n.getLong()); -/** - * Test the functioning of the secondary grouping value. - */ -void NumberFormatTest::TestSecondaryGrouping(void) { - UErrorCode status = U_ZERO_ERROR; - DecimalFormatSymbols US(Locale::getUS(), status); - CHECK(status, "DecimalFormatSymbols ct"); + if (U_FAILURE(status) || n.getType() != Formattable::kLong || + n.getLong() != 1) { + errln((UnicodeString)"Lenient parse failed for \"" + (UnicodeString) lenientAffixTestCases[t] + (UnicodeString) "\""); + status = U_ZERO_ERROR; + } + } + delete format; + } - DecimalFormat f("#,##,###", US, status); - CHECK(status, "DecimalFormat ct"); + 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) "\""); + 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) "\""); + status = U_ZERO_ERROR; + } + } + delete mFormat; + } + + NumberFormat *cFormat = NumberFormat::createInstance(en_US, UNUM_CURRENCY, status); - expect2(f, (int32_t)123456789L, "12,34,56,789"); - expectPat(f, "#,##,###"); - f.applyPattern("#,###", status); - CHECK(status, "applyPattern"); + 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]); - f.setSecondaryGroupingSize(4); - expect2(f, (int32_t)123456789L, "12,3456,789"); - expectPat(f, "#,####,###"); - NumberFormat *g = NumberFormat::createInstance(Locale("hi", "IN"), status); - CHECK(status, "createInstance(hi_IN)"); + cFormat->parse(testCase, n, status); + logln((UnicodeString)"parse(" + testCase + ") = " + n.getLong()); - UnicodeString out; - int32_t l = (int32_t)1876543210L; - g->format(l, out); - delete g; + if (U_FAILURE(status) ||n.getType() != Formattable::kLong || + n.getLong() != 1000) { + errln((UnicodeString)"Lenient parse failed for \"" + (UnicodeString) lenientCurrencyTestCases[t] + (UnicodeString) "\""); + status = U_ZERO_ERROR; + } + } + + for (int32_t t = 0; t < 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) "\""); + 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) "\""); + 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) "\""); + 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) "\""); + } + + 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) "\""); + status = U_ZERO_ERROR; + } + } + + delete nFormat; + } +} + +// ------------------------------------- + +/** + * Test proper rounding by the format method. + */ +void +NumberFormatTest::TestRounding487(void) +{ + UErrorCode status = U_ZERO_ERROR; + NumberFormat *nf = NumberFormat::createInstance(status); + if (U_FAILURE(status)) { + dataerrln("Error calling NumberFormat::createInstance()"); + return; + } + + roundingTest(*nf, 0.00159999, 4, "0.0016"); + roundingTest(*nf, 0.00995, 4, "0.01"); + + roundingTest(*nf, 12.3995, 3, "12.4"); + + roundingTest(*nf, 12.4999, 0, "12"); + roundingTest(*nf, - 19.5, 0, "-20"); + delete nf; + if (U_FAILURE(status)) errln((UnicodeString)"FAIL: Status " + (int32_t)status); +} + +/** + * Test the functioning of the secondary grouping value. + */ +void NumberFormatTest::TestSecondaryGrouping(void) { + UErrorCode status = U_ZERO_ERROR; + DecimalFormatSymbols US(Locale::getUS(), status); + CHECK(status, "DecimalFormatSymbols ct"); + + DecimalFormat f("#,##,###", US, status); + CHECK(status, "DecimalFormat ct"); + + expect2(f, (int32_t)123456789L, "12,34,56,789"); + expectPat(f, "#,##,###"); + f.applyPattern("#,###", status); + CHECK(status, "applyPattern"); + + f.setSecondaryGroupingSize(4); + expect2(f, (int32_t)123456789L, "12,3456,789"); + expectPat(f, "#,####,###"); + NumberFormat *g = NumberFormat::createInstance(Locale("hi", "IN"), status); + CHECK_DATA(status, "createInstance(hi_IN)"); + + UnicodeString out; + int32_t l = (int32_t)1876543210L; + g->format(l, out); + delete g; // expect "1,87,65,43,210", but with Hindi digits // 01234567890123 UBool ok = TRUE; @@ -826,7 +1658,7 @@ void NumberFormatTest::TestWhiteSpaceParsing(void) { 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; } int32_t n = 1234; @@ -838,25 +1670,27 @@ void NumberFormatTest::TestWhiteSpaceParsing(void) { * 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) { @@ -894,7 +1728,7 @@ void NumberFormatTest::TestScientific(void) { // Test pattern round-trip const char* PAT[] = { "#E0", "0.####E0", "00.000E00", "##0.####E000", "0.###E0;[0.###E0]" }; - int32_t PAT_length = (int32_t)(sizeof(PAT) / sizeof(PAT[0])); + int32_t PAT_length = UPRV_LENGTHOF(PAT); int32_t DIGITS[] = { // min int, max int, min frac, max frac 0, 1, 0, 0, // "#E0" @@ -938,8 +1772,8 @@ void NumberFormatTest::TestScientific(void) { // 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); @@ -985,16 +1819,16 @@ void NumberFormatTest::TestScientific(void) { 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", } ); @@ -1189,7 +2023,7 @@ void NumberFormatTest::TestPatterns2(void) { DecimalFormat fmt("#", US, status); CHECK(status, "DecimalFormat constructor"); - + UChar hat = 0x005E; /*^*/ expectPad(fmt, "*^#", DecimalFormat::kPadBeforePrefix, 1, hat); @@ -1280,7 +2114,13 @@ 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; @@ -1290,7 +2130,7 @@ void NumberFormatTest::TestSurrogateSupport(void) { custom.setSymbol(DecimalFormatSymbols::kZeroDigitSymbol, (UChar)0x30); custom.setSymbol(DecimalFormatSymbols::kCurrencySymbol, "units of money"); custom.setSymbol(DecimalFormatSymbols::kMonetarySeparatorSymbol, "money separator"); - patternStr = "0.00 \\u00A4' in your bank account'"; + patternStr = UNICODE_STRING_SIMPLE("0.00 \\u00A4' in your bank account'"); patternStr = patternStr.unescape(); expStr = UnicodeString(" minus 20money separator00 units of money in your bank account", ""); status = U_ZERO_ERROR; @@ -1330,8 +2170,8 @@ void NumberFormatTest::TestCurrencyPatterns(void) { } // Make sure EURO currency formats have exactly 2 fraction digits - if (nf->getDynamicClassID() == DecimalFormat::getStaticClassID()) { - DecimalFormat* df = (DecimalFormat*) nf; + DecimalFormat* df = dynamic_cast(nf); + if (df != NULL) { if (u_strcmp(EUR, df->getCurrency()) == 0) { if (min != 2 || max != 2) { UnicodeString a; @@ -1358,13 +2198,13 @@ void NumberFormatTest::TestRegCurrency(void) { 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"); @@ -1374,38 +2214,38 @@ void NumberFormatTest::TestRegCurrency(void) { 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"); @@ -1418,58 +2258,199 @@ void NumberFormatTest::TestCurrencyNames(void) { // Do a basic check of getName() // USD { "US$", "US Dollar" } // 04/04/1792- UErrorCode ec = U_ZERO_ERROR; - static const UChar USD[] = {85, 83, 68, 0}; /*USD*/ + static const UChar USD[] = {0x55, 0x53, 0x44, 0}; /*USD*/ + static const UChar USX[] = {0x55, 0x53, 0x58, 0}; /*USX*/ + static const UChar CAD[] = {0x43, 0x41, 0x44, 0}; /*CAD*/ + static const UChar ITL[] = {0x49, 0x54, 0x4C, 0}; /*ITL*/ UBool isChoiceFormat; int32_t len; + 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$"), + UnicodeString("$"), UnicodeString(ucurr_getName(USD, "en", UCURR_SYMBOL_NAME, - &isChoiceFormat, &len, &ec))); + &isChoiceFormat, &len, &ec)), + possibleDataError); assertEquals("USD.getName(LONG_NAME)", UnicodeString("US Dollar"), UnicodeString(ucurr_getName(USD, "en", UCURR_LONG_NAME, - &isChoiceFormat, &len, &ec))); + &isChoiceFormat, &len, &ec)), + possibleDataError); + assertEquals("CAD.getName(SYMBOL_NAME)", + UnicodeString("CA$"), + UnicodeString(ucurr_getName(CAD, "en", + UCURR_SYMBOL_NAME, + &isChoiceFormat, &len, &ec)), + possibleDataError); + assertEquals("CAD.getName(SYMBOL_NAME)", + UnicodeString("$"), + UnicodeString(ucurr_getName(CAD, "en_CA", + UCURR_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(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. + ucurr_getName(CAD, "es_ES", UCURR_LONG_NAME, &isChoiceFormat, + &len, &ec); + 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 (ti default)", + U_USING_DEFAULT_WARNING == ec, TRUE); + + // Test that a default warning is being returned when falling back to root. JB 4536. + ucurr_getName(ITL, "cy", UCURR_LONG_NAME, &isChoiceFormat, + &len, &ec); + assertTrue("ucurr_getName (cy default to root)", + U_USING_DEFAULT_WARNING == ec, TRUE); + // TODO add more tests later } -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); +void NumberFormatTest::TestCurrencyUnit(void){ + UErrorCode ec = U_ZERO_ERROR; + static const UChar USD[] = {85, 83, 68, 0}; /*USD*/ + static const UChar BAD[] = {63, 63, 63, 0}; /*???*/ + static const UChar BAD2[] = {63, 63, 65, 0}; /*???*/ + CurrencyUnit cu(USD, ec); + assertSuccess("CurrencyUnit", ec); - intlCurrencySymbol.append((UChar)0xa4); + const UChar * r = cu.getISOCurrency(); // who is the buffer owner ? + assertEquals("getISOCurrency()", USD, r); - 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."); + CurrencyUnit cu2(cu); + if (!(cu2 == cu)){ + errln("CurrencyUnit copy constructed object should be same"); } - if (strcmp(mySymbols.getLocale().getName(), locBad.getName()) != 0) { - errln("DecimalFormatSymbols does not have the right locale."); + + CurrencyUnit * cu3 = (CurrencyUnit *)cu.clone(); + 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."); } - int symbolEnum = (int)DecimalFormatSymbols::kDecimalSeparatorSymbol; - for (; symbolEnum < (int)DecimalFormatSymbols::kFormatSymbolCount; symbolEnum++) { - logln(UnicodeString("DecimalFormatSymbols[") + symbolEnum + UnicodeString("] = ") - + prettify(mySymbols.getSymbol((DecimalFormatSymbols::ENumberFormatSymbol)symbolEnum))); + bad = bad2; + if (bad != bad2) { + errln("Currency unit assignment should be the same."); + } + delete cu3; +} - if (mySymbols.getSymbol((DecimalFormatSymbols::ENumberFormatSymbol)symbolEnum).length() == 0 - && symbolEnum != (int)DecimalFormatSymbols::kGroupingSeparatorSymbol) - { - errln("DecimalFormatSymbols has an empty string at index %d.", symbolEnum); +void NumberFormatTest::TestCurrencyAmount(void){ + UErrorCode ec = U_ZERO_ERROR; + static const UChar USD[] = {85, 83, 68, 0}; /*USD*/ + CurrencyAmount ca(9, USD, ec); + assertSuccess("CurrencyAmount", ec); + + CurrencyAmount ca2(ca); + if (!(ca2 == ca)){ + errln("CurrencyAmount copy constructed object should be same"); + } + + ca2=ca; + if (!(ca2 == ca)){ + errln("CurrencyAmount assigned object should be same"); + } + + CurrencyAmount *ca3 = (CurrencyAmount *)ca.clone(); + if (!(*ca3 == ca)){ + errln("CurrencyAmount cloned object should be same"); + } + delete ca3; +} + +void NumberFormatTest::TestSymbolsWithBadLocale(void) { + Locale locDefault; + 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); + 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()); } /** @@ -1481,7 +2462,7 @@ void NumberFormatTest::TestAdoptDecimalFormatSymbols(void) { 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; } @@ -1498,7 +2479,7 @@ void NumberFormatTest::TestAdoptDecimalFormatSymbols(void) { 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); @@ -1515,7 +2496,7 @@ void NumberFormatTest::TestAdoptDecimalFormatSymbols(void) { 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); @@ -1529,7 +2510,7 @@ void NumberFormatTest::TestAdoptDecimalFormatSymbols(void) { errln("Fail: DecimalFormat constructor"); return; } - + DecimalFormatSymbols sym2(Locale::getUS(), ec); if (U_FAILURE(ec)) { errln("Fail: DecimalFormatSymbols constructor"); @@ -1543,7 +2524,7 @@ void NumberFormatTest::TestAdoptDecimalFormatSymbols(void) { 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"); } } @@ -1554,7 +2535,7 @@ void NumberFormatTest::TestPerMill() { if (!assertSuccess("DecimalFormat ct", ec)) return; assertEquals("0.4857 x ###.###\\u2030", ctou("485.7\\u2030"), fmt.format(0.4857, str)); - + DecimalFormatSymbols sym(Locale::getUS(), ec); sym.setSymbol(DecimalFormatSymbols::kPerMillSymbol, ctou("m")); DecimalFormat fmt2("", sym, ec); @@ -1588,7 +2569,7 @@ void NumberFormatTest::TestIllegalPatterns() { 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)); } @@ -1647,7 +2628,7 @@ void NumberFormatTest::TestCases() { UErrorCode ec = U_ZERO_ERROR; TextFile reader("NumberFormatTestCases.txt", "UTF8", ec); if (U_FAILURE(ec)) { - errln("FAIL: Couldn't open NumberFormatTestCases.txt"); + dataerrln("Couldn't open NumberFormatTestCases.txt"); return; } TokenIterator tokens(&reader); @@ -1672,11 +2653,15 @@ void NumberFormatTest::TestCases() { delete ref; ref = new DecimalFormat(tok, new DecimalFormatSymbols(Locale::getUS(), ec), ec); + if (U_FAILURE(ec)) { + dataerrln("Error constructing DecimalFormat"); + goto error; + } break; case 1: // loc= 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: @@ -1721,7 +2706,7 @@ void NumberFormatTest::TestCases() { assertSuccess("parse", ec); assertEquals(where + "\"" + pat + "\".parse(\"" + str + "\")", n, m); - } + } } // p: else { @@ -1743,7 +2728,8 @@ void NumberFormatTest::TestCases() { 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; @@ -1752,6 +2738,12 @@ void NumberFormatTest::TestCases() { if (!tokens.next(tok, ec)) goto error; continue; } + } else if (mfmt == NULL) { + errln("FAIL: " + where + "Loc \"" + mloc + "\": skip case using previous locale, no valid MeasureFormat"); + if (!tokens.next(tok, ec)) goto error; + if (!tokens.next(tok, ec)) goto error; + if (!tokens.next(tok, ec)) goto error; + continue; } // fpc: if (!tokens.next(currAmt, ec)) goto error; @@ -1766,10 +2758,13 @@ void NumberFormatTest::TestCases() { 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; @@ -1832,7 +2827,7 @@ void NumberFormatTest::TestCases() { 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: @@ -1855,7 +2850,7 @@ UBool NumberFormatTest::equalValue(const Formattable& a, const Formattable& b) { 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) { @@ -1873,6 +2868,12 @@ UBool NumberFormatTest::equalValue(const Formattable& a, const Formattable& b) { 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); @@ -1882,8 +2883,8 @@ void NumberFormatTest::expect2(NumberFormat& fmt, const Formattable& n, const Un 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); } @@ -1895,7 +2896,7 @@ void NumberFormatTest::expect(NumberFormat& fmt, const UnicodeString& str, const 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; @@ -1905,12 +2906,65 @@ void NumberFormatTest::expect(NumberFormat& fmt, const UnicodeString& str, const 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; @@ -1931,7 +2985,7 @@ void NumberFormatTest::expect(NumberFormat& fmt, const Formattable& n, 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; @@ -1943,19 +2997,19 @@ void NumberFormatTest::expect(NumberFormat& fmt, const Formattable& n, } } } 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; } @@ -1972,6 +3026,7 @@ void NumberFormatTest::expectCurrency(NumberFormat& nf, const Locale& locale, assertSuccess("ucurr_forLocale", ec); fmt.setCurrency(curr, ec); assertSuccess("DecimalFormat::setCurrency", ec); + fmt.setCurrency(curr); //Deprecated variant, for coverage only } UnicodeString s; fmt.format(value, s); @@ -1979,7 +3034,7 @@ void NumberFormatTest::expectCurrency(NumberFormat& nf, const Locale& locale, // 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)) { @@ -2046,4 +3101,5658 @@ void NumberFormatTest::expectPad(DecimalFormat& fmt, const UnicodeString& pat, } } +// This test is flaky b/c the symbols for CNY and JPY are equivalent in this locale - FIXME +void NumberFormatTest::TestCompatibleCurrencies() { +/* + static const UChar JPY[] = {0x4A, 0x50, 0x59, 0}; + static const UChar CNY[] = {0x43, 0x4E, 0x59, 0}; + UErrorCode status = U_ZERO_ERROR; + LocalPointer fmt( + NumberFormat::createCurrencyInstance(Locale::getUS(), status)); + if (U_FAILURE(status)) { + errln("Could not create number format instance."); + return; + } + logln("%s:%d - testing parse of halfwidth yen sign\n", __FILE__, __LINE__); + expectParseCurrency(*fmt, JPY, 1235, "\\u00A51,235"); + logln("%s:%d - testing parse of fullwidth yen sign\n", __FILE__, __LINE__); + expectParseCurrency(*fmt, JPY, 1235, "\\uFFE51,235"); + logln("%s:%d - testing parse of halfwidth yen sign\n", __FILE__, __LINE__); + expectParseCurrency(*fmt, CNY, 1235, "CN\\u00A51,235"); + + LocalPointer fmtTW( + NumberFormat::createCurrencyInstance(Locale::getTaiwan(), status)); + + logln("%s:%d - testing parse of halfwidth yen sign in TW\n", __FILE__, __LINE__); + expectParseCurrency(*fmtTW, CNY, 1235, "\\u00A51,235"); + logln("%s:%d - testing parse of fullwidth yen sign in TW\n", __FILE__, __LINE__); + expectParseCurrency(*fmtTW, CNY, 1235, "\\uFFE51,235"); + + LocalPointer fmtJP( + NumberFormat::createCurrencyInstance(Locale::getJapan(), status)); + + logln("%s:%d - testing parse of halfwidth yen sign in JP\n", __FILE__, __LINE__); + expectParseCurrency(*fmtJP, JPY, 1235, "\\u00A51,235"); + logln("%s:%d - testing parse of fullwidth yen sign in JP\n", __FILE__, __LINE__); + expectParseCurrency(*fmtJP, JPY, 1235, "\\uFFE51,235"); + + // more.. +*/ +} + +void NumberFormatTest::expectParseCurrency(const NumberFormat &fmt, const UChar* currency, double amount, const char *text) { + ParsePosition ppos; + UnicodeString utext = ctou(text); + LocalPointer currencyAmount(fmt.parseCurrency(utext, ppos)); + if (!ppos.getIndex()) { + errln(UnicodeString("Parse of ") + utext + " should have succeeded."); + return; + } + UErrorCode status = U_ZERO_ERROR; + + char theInfo[100]; + sprintf(theInfo, "For locale %s, string \"%s\", currency ", + fmt.getLocale(ULOC_ACTUAL_LOCALE, status).getBaseName(), + text); + u_austrcpy(theInfo+uprv_strlen(theInfo), currency); + + char theOperation[100]; + + uprv_strcpy(theOperation, theInfo); + uprv_strcat(theOperation, ", check amount:"); + assertTrue(theOperation, amount == currencyAmount->getNumber().getDouble(status)); + + uprv_strcpy(theOperation, theInfo); + uprv_strcat(theOperation, ", check currency:"); + assertEquals(theOperation, currency, currencyAmount->getISOCurrency()); +} + + +void NumberFormatTest::TestJB3832(){ + const char* localeID = "pt_PT@currency=PTE"; + Locale loc(localeID); + UErrorCode status = U_ZERO_ERROR; + UnicodeString expected(CharsToUnicodeString("1,150$50\\u00A0\\u200B")); // per cldrbug 7670 + UnicodeString s; + NumberFormat* currencyFmt = NumberFormat::createCurrencyInstance(loc, status); + if(U_FAILURE(status)){ + 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 + + UnicodeString( " for locale: ")+ UnicodeString(localeID) ); + } + if (U_FAILURE(status)){ + errln("FAIL: Status %s", u_errorName(status)); + } + delete currencyFmt; +} + +void NumberFormatTest::TestHost() +{ +#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 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 Relative 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() +{ + // This test is here to increase code coverage. + UErrorCode status = U_ZERO_ERROR; + MeasureFormat *cloneObj; + UnicodeString str; + Formattable toFormat, result; + static const UChar ISO_CODE[4] = {0x0047, 0x0042, 0x0050, 0}; + + Locale saveDefaultLocale = Locale::getDefault(); + Locale::setDefault( Locale::getUK(), status ); + if (U_FAILURE(status)) { + errln("couldn't set default Locale!"); + return; + } + + MeasureFormat *measureObj = MeasureFormat::createCurrencyFormat(status); + Locale::setDefault( saveDefaultLocale, status ); + if (U_FAILURE(status)){ + dataerrln("FAIL: Status %s", u_errorName(status)); + return; + } + cloneObj = (MeasureFormat *)measureObj->clone(); + if (cloneObj == NULL) { + errln("Clone doesn't work"); + return; + } + toFormat.adoptObject(new CurrencyAmount(1234.56, ISO_CODE, status)); + measureObj->format(toFormat, str, status); + measureObj->parseObject(str, result, status); + if (U_FAILURE(status)){ + errln("FAIL: Status %s", u_errorName(status)); + } + if (result != toFormat) { + errln("measureObj does not round trip. Formatted string was \"" + str + "\" Got: " + toString(result) + " Expected: " + toString(toFormat)); + } + status = U_ZERO_ERROR; + str.truncate(0); + cloneObj->format(toFormat, str, status); + cloneObj->parseObject(str, result, status); + if (U_FAILURE(status)){ + errln("FAIL: Status %s", u_errorName(status)); + } + if (result != toFormat) { + errln("Clone does not round trip. Formatted string was \"" + str + "\" Got: " + toString(result) + " Expected: " + toString(toFormat)); + } + if (*measureObj != *cloneObj) { + errln("Cloned object is not equal to the original object"); + } + delete measureObj; + delete cloneObj; + + status = U_USELESS_COLLATOR_ERROR; + if (MeasureFormat::createCurrencyFormat(status) != NULL) { + errln("createCurrencyFormat should have returned NULL."); + } +} + +/* Port of ICU4J rounding test. */ +void NumberFormatTest::TestRounding() { + UErrorCode status = U_ZERO_ERROR; + DecimalFormat *df = (DecimalFormat*)NumberFormat::createCurrencyInstance(Locale::getEnglish(), status); + + if (U_FAILURE(status)) { + 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;modesetRoundingMode((DecimalFormat::ERoundingMode)mode); + for (int increment=0; increment<6; increment++) { + double base=testValues[j]; + double rInc=roundingIncrements[increment]; + checkRounding(df, base, 20, rInc); + rInc=1.000000000/rInc; + checkRounding(df, base, 20, rInc); + } + } + } + delete df; +} + +void NumberFormatTest::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); + 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", "\\uFFE51,234.56", "CNY1,234.56", "\\u4EBA\\u6C11\\u5E011,234.56"}, + {"zh_CN", "\\u00A4#,##0.00;(\\u00A4#,##0.00)", "-1234.56", "(\\uFFE51,234.56)", "(CNY1,234.56)", "(\\u4EBA\\u6C11\\u5E011,234.56)"}, + {"zh_CN", "\\u00A4#,##0.00;(\\u00A4#,##0.00)", "1", "\\uFFE51.00", "CNY1.00", "\\u4EBA\\u6C11\\u5E011.00"} + }; + + const UChar doubleCurrencySign[] = {0xA4, 0xA4, 0}; + UnicodeString doubleCurrencyStr(doubleCurrencySign); + const UChar tripleCurrencySign[] = {0xA4, 0xA4, 0xA4, 0}; + UnicodeString tripleCurrencyStr(tripleCurrencySign); + + for (uint32_t i=0; iformat(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" + }; + 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(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; +} + + +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"}, + }; + 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); + 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", "\\uFFE51.00", "CNY1.00", "1.00\\u4EBA\\u6C11\\u5E01"}, + {"zh_CN", "1234.56", "CNY", "\\uFFE51,234.56", "CNY1,234.56", "1,234.56\\u4EBA\\u6C11\\u5E01"}, + {"ru_RU", "1", "RUB", "1,00\\u00A0\\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; isetCurrency(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. + 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", "USD1.00", "1.00 US dollar"}, + {"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", "\\u200e\\u062f\\u0644\\u0627\\u0631 \\u0627\\u0645\\u0631\\u06cc\\u06a9\\u0627\\u06f1\\u066b\\u06f0\\u06f0"}, + {"he_IL", "1", "USD", "1.00\\u00a0$", "1.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\\u010dki dolar"}, + {"id_ID", "1", "USD", "US$1,00", "USD1,00", "1,00 Dolar Amerika Serikat"}, + {"it_IT", "1", "USD", "1,00\\u00a0US$", "1,00\\u00a0USD", "1,00 Dollaro Statunitense"}, + {"ko_KR", "1", "USD", "US$1.00", "USD1.00", "1.00 \\ubbf8\\uad6d \\ub2ec\\ub7ec"}, + {"ja_JP", "1", "USD", "$1.00", "USD1.00", "1.00\\u7c73\\u30c9\\u30eb"}, + {"zh_CN", "1", "CNY", "\\uFFE51.00", "CNY01.00", "1.00\\u4EBA\\u6C11\\u5E01"}, + {"zh_TW", "1", "CNY", "CN\\u00A51.00", "CNY1.00", "1.00 \\u4eba\\u6c11\\u5e63"}, + {"zh_Hant", "1", "CNY", "CN\\u00A51.00", "CNY1.00", "1.00 \\u4eba\\u6c11\\u5e63"}, + {"zh_Hant", "1", "JPY", "\\u00A51.00", "JPY1.00", "1.00 \\u65e5\\u5713"}, + {"ja_JP", "1", "JPY", "\\uFFE51.00", "JPY1.00", "1.00\\u65e5\\u672c\\u5186"}, + {"ja_JP", "1", "JPY", "\\u00A51.00", "JPY1.00", "1.00\\u65e5\\u672c\\u5186"}, + {"ru_RU", "1", "RUB", "1,00\\u00A0\\u20BD", "1,00\\u00A0RUB", "1,00 \\u0420\\u043E\\u0441\\u0441\\u0438\\u0439\\u0441\\u043A\\u0438\\u0439 \\u0440\\u0443\\u0431\\u043B\\u044C"} + }; + 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. + 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 New Ruble (1994\\u20131999)1.00", + "Belarusian Ruble1.00", + "Belarusian new ruble (1994\\u20131999)1.00", + "Belarusian new 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 Republic Koruna1.00", + "Czech Republic koruna1.00", + "Czech Republic 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 sheqel1.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 Sheqel1.00", + "Israeli New Sheqels1.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 Nuevo Sol1.00", + "Peruvian Sol (1863\\u20131965)1.00", + "Peruvian inti1.00", + "Peruvian intis1.00", + "Peruvian nuevo sol1.00", + "Peruvian nuevos soles1.00", + "Peruvian sol (1863\\u20131965)1.00", + "Peruvian soles (1863\\u20131965)1.00", + "Philippine Peso1.00", + "Philippine peso1.00", + "Philippine pesos1.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 New Ruble (1994\\u20131999) random", + "1.00 Belarusian Ruble random", + "1.00 Belarusian new ruble (1994\\u20131999) random", + "1.00 Belarusian new 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 Republic Koruna random", + "1.00 Czech Republic koruna random", + "1.00 Czech Republic 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 sheqel 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 Sheqel random", + "1.00 Israeli new sheqels 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 Nuevo Sol random", + "1.00 Peruvian Sol (1863\\u20131965) random", + "1.00 Peruvian inti random", + "1.00 Peruvian intis random", + "1.00 Peruvian nuevo sol random", + "1.00 Peruvian nuevos soles random", + "1.00 Peruvian sol (1863\\u20131965) random", + "1.00 Peruvian soles (1863\\u20131965) random", + "1.00 Philippine Peso random", + "1.00 Philippine peso random", + "1.00 Philippine pesos 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 New 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 currAmt(numFmt->parseCurrency(formatted, parsePos)); + if (parsePos.getIndex() > 0) { + double doubleVal = currAmt->getNumber().getDouble(status); + if ( doubleVal != 1.0 ) { + errln("Parsed as currency value other than 1.0: " + formatted + " -> " + doubleVal); + } + } else { + errln("Failed to parse as currency: " + formatted); + } + } else { + dataerrln("Unable to create NumberFormat. - %s", u_errorName(status)); + delete numFmt; + break; + } + delete numFmt; + } + + for (uint32_t i=0; i 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) {if (U_FAILURE(status)) errln("file %s, line %d: status: %s", \ + __FILE__, __LINE__, u_errorName(status));} +#define ASSERT_EQUALS(expected, actual) {if ((expected) != (actual)) \ + errln("file %s, line %d: %s != %s", __FILE__, __LINE__, #expected, #actual);} + +static UBool operator != (const char *s1, UnicodeString &s2) { + // This function lets ASSERT_EQUALS("literal", UnicodeString) work. + UnicodeString us1(s1); + return us1 != s2; +} + +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); + //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)); + 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)); + 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)); + 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, strcmp("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 = new DecimalFormatSymbols(Locale::getDefault(), status); + if(U_FAILURE(status)) { + dataerrln((UnicodeString)"ERROR: Could not create DecimalFormatSymbols (Default)"); + return; + } + + // create format instance + status = U_ZERO_ERROR; + DecimalFormat fmt("#####", symbols, status); + if(U_FAILURE(status)) { + errln((UnicodeString)"ERROR: Could not create DecimalFormat (pattern, symbols*)"); + } + + // parse the text + fmt.parse("5.06e-27", result, parsePos); + if(result.getType() != Formattable::kDouble && + result.getDouble() != 5.06E-27 && + parsePos.getIndex() != 8 + ) + { + errln("ERROR: parse failed - expected 5.06E-27, 8 - returned %d, %i", + result.getDouble(), parsePos.getIndex()); + } +} + +void NumberFormatTest::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); +} + +#include "dcfmtimp.h" + +void NumberFormatTest::TestFormatFastpaths() { +#if UCONFIG_FORMAT_FASTPATHS_49 + logln("Sizeof DecimalFormat = %d, Sizeof DecimalFormatInternal=%d, UNUM_DECIMALFORMAT_INTERNAL_SIZE=%d\n", + sizeof(DecimalFormat), sizeof(DecimalFormatInternal), UNUM_DECIMALFORMAT_INTERNAL_SIZE); + if(UNUM_DECIMALFORMAT_INTERNAL_SIZE < sizeof(DecimalFormatInternal)) { + errln("Error: sizeof(DecimalFormatInternal)=%d but UNUM_DECIMALFORMAT_INTERNAL_SIZE is only %d. Increase the #define?\n", sizeof(DecimalFormatInternal), UNUM_DECIMALFORMAT_INTERNAL_SIZE); + } else if(UNUM_DECIMALFORMAT_INTERNAL_SIZE > (sizeof(DecimalFormatInternal)+16)) { + infoln("Note: sizeof(DecimalFormatInternal)=%d but UNUM_DECIMALFORMAT_INTERNAL_SIZE is %d. Decrease the #define? sizeof(DecimalFormat)=%d\n", sizeof(DecimalFormatInternal), UNUM_DECIMALFORMAT_INTERNAL_SIZE, sizeof(DecimalFormat)); + } +#else + infoln("NOTE: UCONFIG_FORMAT_FASTPATHS not set, test skipped."); +#endif + + // get some additional case + { + UErrorCode status=U_ZERO_ERROR; + DecimalFormat df(UnicodeString("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) { + errcheckln(status, "FAIL: expected '"+expect+"' got '"+result+"' status "+UnicodeString(u_errorName(status),"")); + } else { + logln("OK: got expected '"+result+"' status "+UnicodeString(u_errorName(status),"")); + } + } + } + { + 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; // -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) { + errcheckln(status, "FAIL: expected '"+expect+"' got '"+result+"' status "+UnicodeString(u_errorName(status),"")+" on -9223372036854775808"); + } else { + logln("OK: got expected '"+result+"' status "+UnicodeString(u_errorName(status),"")+" on -9223372036854775808"); + } + } + } + { + 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_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) { + errcheckln(status, "FAIL: expected '"+expect+"' got '"+result+"' status "+UnicodeString(u_errorName(status),"")+" on U_INT64_MAX"); + } 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) { + errcheckln(status, "FAIL: expected '"+expect+"' got '"+result+"' status "+UnicodeString(u_errorName(status),"")+" on 0"); + } 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) { + errcheckln(status, "FAIL: expected '"+expect+"' got '"+result+"' status "+UnicodeString(u_errorName(status),"")+" on -9223372036854775807"); + } else { + logln("OK: got expected '"+result+"' status "+UnicodeString(u_errorName(status),"")+" on -9223372036854775807"); + } + } + } +} + + +void NumberFormatTest::TestFormattableSize(void) { + 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(FmtStackData)=%d, UNUM_INTERNAL_STACKARRAY_SIZE=%d\n", + sizeof(FmtStackData), UNUM_INTERNAL_STACKARRAY_SIZE); + } +} + +UBool NumberFormatTest::testFormattableAsUFormattable(const char *file, int line, Formattable &f) { + UnicodeString fileLine = UnicodeString(file)+UnicodeString(":")+line+UnicodeString(": "); + + UFormattable *u = f.toUFormattable(); + logln(); + if (u == NULL) { + errln("%s:%d: Error: f.toUFormattable() retuned NULL."); + return FALSE; + } + logln("%s:%d: comparing Formattable with UFormattable", file, line); + logln(fileLine + toString(f)); + + UErrorCode status = U_ZERO_ERROR; + UErrorCode valueStatus = U_ZERO_ERROR; + UFormattableType expectUType = UFMT_COUNT; // invalid + + UBool triedExact = FALSE; // did we attempt an exact comparison? + UBool exactMatch = FALSE; // was the exact comparison true? + + switch( f.getType() ) { + case Formattable::kDate: + expectUType = UFMT_DATE; + exactMatch = (f.getDate()==ufmt_getDate(u, &valueStatus)); + triedExact = TRUE; + break; + case Formattable::kDouble: + expectUType = UFMT_DOUBLE; + exactMatch = (f.getDouble()==ufmt_getDouble(u, &valueStatus)); + triedExact = TRUE; + break; + case Formattable::kLong: + expectUType = UFMT_LONG; + exactMatch = (f.getLong()==ufmt_getLong(u, &valueStatus)); + triedExact = TRUE; + break; + case Formattable::kString: + expectUType = UFMT_STRING; + { + UnicodeString str; + f.getString(str); + int32_t len; + const UChar* uch = ufmt_getUChars(u, &len, &valueStatus); + if(U_SUCCESS(valueStatus)) { + UnicodeString str2(uch, len); + assertTrue("UChar* NULL-terminated", uch[len]==0); + exactMatch = (str == str2); + } + triedExact = TRUE; + } + break; + case Formattable::kArray: + expectUType = UFMT_ARRAY; + triedExact = TRUE; + { + int32_t count = ufmt_getArrayLength(u, &valueStatus); + int32_t count2; + const Formattable *array2 = f.getArray(count2); + exactMatch = assertEquals(fileLine + " array count", count, count2); + + if(exactMatch) { + for(int i=0;U_SUCCESS(valueStatus) && i numberFormat(static_cast( + NumberFormat::createInstance(locale, status))); + CHECK_DATA(status,"NumberFormat::createInstance") + + numberFormat->setSignificantDigitsUsed(TRUE); + numberFormat->setMinimumSignificantDigits(3); + numberFormat->setMaximumSignificantDigits(5); + numberFormat->setGroupingUsed(false); + + UnicodeString result; + UnicodeString expectedResult; + for (unsigned int i = 0; i < UPRV_LENGTHOF(input); ++i) { + numberFormat->format(input[i], result); + UnicodeString expectedResult(expected[i]); + if (result != expectedResult) { + errln((UnicodeString)"Expected: '" + expectedResult + "' got '" + result); + } + result.remove(); + } +} + +void NumberFormatTest::TestShowZero() { + UErrorCode status = U_ZERO_ERROR; + Locale locale("en_US"); + LocalPointer numberFormat(static_cast( + NumberFormat::createInstance(locale, status))); + CHECK_DATA(status, "NumberFormat::createInstance") + + numberFormat->setSignificantDigitsUsed(TRUE); + numberFormat->setMaximumSignificantDigits(3); + + UnicodeString result; + numberFormat->format(0.0, result); + if (result != "0") { + errln((UnicodeString)"Expected: 0, got " + result); + } +} + +void NumberFormatTest::TestBug9936() { + UErrorCode status = U_ZERO_ERROR; + Locale locale("en_US"); + LocalPointer numberFormat(static_cast( + NumberFormat::createInstance(locale, status))); + if (U_FAILURE(status)) { + dataerrln("File %s, Line %d: status = %s.\n", __FILE__, __LINE__, u_errorName(status)); + return; + } + + if (numberFormat->areSignificantDigitsUsed() == TRUE) { + errln("File %s, Line %d: areSignificantDigitsUsed() was TRUE, expected FALSE.\n", __FILE__, __LINE__); + } + numberFormat->setSignificantDigitsUsed(TRUE); + if (numberFormat->areSignificantDigitsUsed() == FALSE) { + errln("File %s, Line %d: areSignificantDigitsUsed() was FALSE, expected TRUE.\n", __FILE__, __LINE__); + } + + numberFormat->setSignificantDigitsUsed(FALSE); + if (numberFormat->areSignificantDigitsUsed() == TRUE) { + errln("File %s, Line %d: areSignificantDigitsUsed() was TRUE, expected FALSE.\n", __FILE__, __LINE__); + } + + numberFormat->setMinimumSignificantDigits(3); + if (numberFormat->areSignificantDigitsUsed() == FALSE) { + errln("File %s, Line %d: areSignificantDigitsUsed() was FALSE, expected TRUE.\n", __FILE__, __LINE__); + } + + numberFormat->setSignificantDigitsUsed(FALSE); + numberFormat->setMaximumSignificantDigits(6); + if (numberFormat->areSignificantDigitsUsed() == FALSE) { + errln("File %s, Line %d: areSignificantDigitsUsed() was FALSE, expected TRUE.\n", __FILE__, __LINE__); + } + +} + +void NumberFormatTest::TestParseNegativeWithFaLocale() { + UErrorCode status = U_ZERO_ERROR; + DecimalFormat *test = (DecimalFormat *) NumberFormat::createInstance("fa", status); + CHECK_DATA(status, "NumberFormat::createInstance") + test->setLenient(TRUE); + Formattable af; + ParsePosition ppos; + UnicodeString value("\\u200e-0,5"); + value = value.unescape(); + test->parse(value, af, ppos); + if (ppos.getIndex() == 0) { + errln("Expected -0,5 to parse for Farsi."); + } + delete test; +} + +void NumberFormatTest::TestParseNegativeWithAlternateMinusSign() { + UErrorCode status = U_ZERO_ERROR; + DecimalFormat *test = (DecimalFormat *) NumberFormat::createInstance("en", status); + CHECK_DATA(status, "NumberFormat::createInstance") + test->setLenient(TRUE); + Formattable af; + ParsePosition ppos; + UnicodeString value("\\u208B0.5"); + value = value.unescape(); + test->parse(value, af, ppos); + if (ppos.getIndex() == 0) { + errln(UnicodeString("Expected ") + value + UnicodeString(" to parse.")); + } + delete test; +} + +void NumberFormatTest::TestCustomCurrencySignAndSeparator() { + UErrorCode status = U_ZERO_ERROR; + DecimalFormatSymbols custom(Locale::getUS(), status); + CHECK(status, "DecimalFormatSymbols constructor"); + + custom.setSymbol(DecimalFormatSymbols::kCurrencySymbol, "*"); + custom.setSymbol(DecimalFormatSymbols::kMonetaryGroupingSeparatorSymbol, "^"); + custom.setSymbol(DecimalFormatSymbols::kMonetarySeparatorSymbol, ":"); + + UnicodeString pat(" #,##0.00"); + pat.insert(0, (UChar)0x00A4); + + DecimalFormat fmt(pat, custom, status); + CHECK(status, "DecimalFormat constructor"); + + UnicodeString numstr("* 1^234:56"); + expect2(fmt, (Formattable)((double)1234.56), numstr); +} + +typedef struct { + const char * locale; + UBool lenient; + UnicodeString numString; + double value; +} SignsAndMarksItem; + + +void NumberFormatTest::TestParseSignsAndMarks() { + const SignsAndMarksItem items[] = { + // locale lenient numString value + { "en", FALSE, CharsToUnicodeString("12"), 12 }, + { "en", TRUE, CharsToUnicodeString("12"), 12 }, + { "en", FALSE, CharsToUnicodeString("-23"), -23 }, + { "en", TRUE, CharsToUnicodeString("-23"), -23 }, + { "en", TRUE, CharsToUnicodeString("- 23"), -23 }, + { "en", FALSE, CharsToUnicodeString("\\u200E-23"), -23 }, + { "en", TRUE, CharsToUnicodeString("\\u200E-23"), -23 }, + { "en", TRUE, CharsToUnicodeString("\\u200E- 23"), -23 }, + + { "en@numbers=arab", FALSE, CharsToUnicodeString("\\u0663\\u0664"), 34 }, + { "en@numbers=arab", TRUE, CharsToUnicodeString("\\u0663\\u0664"), 34 }, + { "en@numbers=arab", FALSE, CharsToUnicodeString("-\\u0664\\u0665"), -45 }, + { "en@numbers=arab", TRUE, CharsToUnicodeString("-\\u0664\\u0665"), -45 }, + { "en@numbers=arab", TRUE, CharsToUnicodeString("- \\u0664\\u0665"), -45 }, + { "en@numbers=arab", FALSE, CharsToUnicodeString("\\u200F-\\u0664\\u0665"), -45 }, + { "en@numbers=arab", TRUE, CharsToUnicodeString("\\u200F-\\u0664\\u0665"), -45 }, + { "en@numbers=arab", TRUE, CharsToUnicodeString("\\u200F- \\u0664\\u0665"), -45 }, + + { "en@numbers=arabext", FALSE, CharsToUnicodeString("\\u06F5\\u06F6"), 56 }, + { "en@numbers=arabext", TRUE, CharsToUnicodeString("\\u06F5\\u06F6"), 56 }, + { "en@numbers=arabext", FALSE, CharsToUnicodeString("-\\u06F6\\u06F7"), -67 }, + { "en@numbers=arabext", TRUE, CharsToUnicodeString("-\\u06F6\\u06F7"), -67 }, + { "en@numbers=arabext", TRUE, CharsToUnicodeString("- \\u06F6\\u06F7"), -67 }, + { "en@numbers=arabext", FALSE, CharsToUnicodeString("\\u200E-\\u200E\\u06F6\\u06F7"), -67 }, + { "en@numbers=arabext", TRUE, CharsToUnicodeString("\\u200E-\\u200E\\u06F6\\u06F7"), -67 }, + { "en@numbers=arabext", TRUE, CharsToUnicodeString("\\u200E-\\u200E \\u06F6\\u06F7"), -67 }, + + { "he", FALSE, CharsToUnicodeString("12"), 12 }, + { "he", TRUE, CharsToUnicodeString("12"), 12 }, + { "he", FALSE, CharsToUnicodeString("-23"), -23 }, + { "he", TRUE, CharsToUnicodeString("-23"), -23 }, + { "he", TRUE, CharsToUnicodeString("- 23"), -23 }, + { "he", FALSE, CharsToUnicodeString("\\u200E-23"), -23 }, + { "he", TRUE, CharsToUnicodeString("\\u200E-23"), -23 }, + { "he", TRUE, CharsToUnicodeString("\\u200E- 23"), -23 }, + + { "ar", FALSE, CharsToUnicodeString("\\u0663\\u0664"), 34 }, + { "ar", TRUE, CharsToUnicodeString("\\u0663\\u0664"), 34 }, + { "ar", FALSE, CharsToUnicodeString("-\\u0664\\u0665"), -45 }, + { "ar", TRUE, CharsToUnicodeString("-\\u0664\\u0665"), -45 }, + { "ar", TRUE, CharsToUnicodeString("- \\u0664\\u0665"), -45 }, + { "ar", FALSE, CharsToUnicodeString("\\u200F-\\u0664\\u0665"), -45 }, + { "ar", TRUE, CharsToUnicodeString("\\u200F-\\u0664\\u0665"), -45 }, + { "ar", TRUE, CharsToUnicodeString("\\u200F- \\u0664\\u0665"), -45 }, + + { "ar_MA", FALSE, CharsToUnicodeString("12"), 12 }, + { "ar_MA", TRUE, CharsToUnicodeString("12"), 12 }, + { "ar_MA", FALSE, CharsToUnicodeString("-23"), -23 }, + { "ar_MA", TRUE, CharsToUnicodeString("-23"), -23 }, + { "ar_MA", TRUE, CharsToUnicodeString("- 23"), -23 }, + { "ar_MA", FALSE, CharsToUnicodeString("\\u200E-23"), -23 }, + { "ar_MA", TRUE, CharsToUnicodeString("\\u200E-23"), -23 }, + { "ar_MA", TRUE, CharsToUnicodeString("\\u200E- 23"), -23 }, + + { "fa", FALSE, CharsToUnicodeString("\\u06F5\\u06F6"), 56 }, + { "fa", TRUE, CharsToUnicodeString("\\u06F5\\u06F6"), 56 }, + { "fa", FALSE, CharsToUnicodeString("\\u2212\\u06F6\\u06F7"), -67 }, + { "fa", TRUE, CharsToUnicodeString("\\u2212\\u06F6\\u06F7"), -67 }, + { "fa", TRUE, CharsToUnicodeString("\\u2212 \\u06F6\\u06F7"), -67 }, + { "fa", FALSE, CharsToUnicodeString("\\u200E\\u2212\\u200E\\u06F6\\u06F7"), -67 }, + { "fa", TRUE, CharsToUnicodeString("\\u200E\\u2212\\u200E\\u06F6\\u06F7"), -67 }, + { "fa", TRUE, CharsToUnicodeString("\\u200E\\u2212\\u200E \\u06F6\\u06F7"), -67 }, + + { "ps", FALSE, CharsToUnicodeString("\\u06F5\\u06F6"), 56 }, + { "ps", TRUE, CharsToUnicodeString("\\u06F5\\u06F6"), 56 }, + { "ps", FALSE, CharsToUnicodeString("-\\u06F6\\u06F7"), -67 }, + { "ps", TRUE, CharsToUnicodeString("-\\u06F6\\u06F7"), -67 }, + { "ps", TRUE, CharsToUnicodeString("- \\u06F6\\u06F7"), -67 }, + { "ps", FALSE, CharsToUnicodeString("\\u200E-\\u200E\\u06F6\\u06F7"), -67 }, + { "ps", TRUE, CharsToUnicodeString("\\u200E-\\u200E\\u06F6\\u06F7"), -67 }, + { "ps", TRUE, CharsToUnicodeString("\\u200E-\\u200E \\u06F6\\u06F7"), -67 }, + { "ps", FALSE, CharsToUnicodeString("-\\u200E\\u06F6\\u06F7"), -67 }, + { "ps", TRUE, CharsToUnicodeString("-\\u200E\\u06F6\\u06F7"), -67 }, + { "ps", TRUE, CharsToUnicodeString("-\\u200E \\u06F6\\u06F7"), -67 }, + // terminator + { NULL, 0, UnicodeString(""), 0 }, + }; + + const SignsAndMarksItem * itemPtr; + for (itemPtr = items; itemPtr->locale != NULL; itemPtr++ ) { + UErrorCode status = U_ZERO_ERROR; + NumberFormat *numfmt = NumberFormat::createInstance(Locale(itemPtr->locale), status); + if (U_SUCCESS(status)) { + numfmt->setLenient(itemPtr->lenient); + Formattable fmtobj; + ParsePosition ppos; + numfmt->parse(itemPtr->numString, fmtobj, ppos); + if (ppos.getIndex() == itemPtr->numString.length()) { + double parsedValue = fmtobj.getDouble(status); + if (U_FAILURE(status) || parsedValue != itemPtr->value) { + errln((UnicodeString)"FAIL: locale " + itemPtr->locale + ", lenient " + itemPtr->lenient + ", parse of \"" + itemPtr->numString + "\" gives value " + parsedValue); + } + } else { + errln((UnicodeString)"FAIL: locale " + itemPtr->locale + ", lenient " + itemPtr->lenient + ", parse of \"" + itemPtr->numString + "\" gives position " + ppos.getIndex()); + } + } else { + dataerrln("FAIL: NumberFormat::createInstance for locale % gives error %s", itemPtr->locale, u_errorName(status)); + } + delete numfmt; + } +} + +typedef struct { + DecimalFormat::ERoundingMode mode; + double value; + UnicodeString expected; +} Test10419Data; + + +// Tests that rounding works right when fractional digits is set to 0. +void NumberFormatTest::Test10419RoundingWith0FractionDigits() { + const Test10419Data items[] = { + { DecimalFormat::kRoundCeiling, 1.488, "2"}, + { DecimalFormat::kRoundDown, 1.588, "1"}, + { DecimalFormat::kRoundFloor, 1.888, "1"}, + { DecimalFormat::kRoundHalfDown, 1.5, "1"}, + { DecimalFormat::kRoundHalfEven, 2.5, "2"}, + { DecimalFormat::kRoundHalfUp, 2.5, "3"}, + { DecimalFormat::kRoundUp, 1.5, "2"}, + }; + UErrorCode status = U_ZERO_ERROR; + LocalPointer decfmt((DecimalFormat *) NumberFormat::createInstance(Locale("en_US"), status)); + if (U_FAILURE(status)) { + dataerrln("Failure creating DecimalFormat %s", u_errorName(status)); + return; + } + for (int32_t i = 0; i < UPRV_LENGTHOF(items); ++i) { + decfmt->setRoundingMode(items[i].mode); + decfmt->setMaximumFractionDigits(0); + UnicodeString actual; + if (items[i].expected != decfmt->format(items[i].value, actual)) { + errln("Expected " + items[i].expected + ", got " + actual); + } + } +} + +void NumberFormatTest::Test10468ApplyPattern() { + // Padding char of fmt is now 'a' + UErrorCode status = U_ZERO_ERROR; + DecimalFormat fmt("'I''ll'*a###.##", status); + + if (U_FAILURE(status)) { + errcheckln(status, "DecimalFormat constructor failed - %s", u_errorName(status)); + return; + } + + if (fmt.getPadCharacterString() != UnicodeString("a")) { + errln("Padding character should be 'a'."); + return; + } + + // 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. + if (fmt.getPadCharacterString() != UnicodeString(" ")) { + errln("applyPattern did not clear padding character."); + } +} + +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("Formt creation", status)) { + return; + } + UnicodeString out; + fmt.format(-0.0, out); + assertEquals("format", "-0.00E0", out); +} + +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) { + char buffer[256]; + sprintf( + buffer, + "For %s value %f, expected ", + descriptions[i], + values[j]); + errln(UnicodeString(buffer) + currentExpected + ", got " + actual); + } + } + } +} + +void NumberFormatTest::TestAccountingCurrency() { + UErrorCode status = U_ZERO_ERROR; + UNumberFormatStyle style = UNUM_CURRENCY_ACCOUNTING; + + expect(NumberFormat::createInstance("en_US", style, status), + (Formattable)1234.5, "$1,234.50", TRUE, status); + expect(NumberFormat::createInstance("en_US", style, status), + (Formattable)-1234.5, "($1,234.50)", TRUE, status); + expect(NumberFormat::createInstance("en_US", style, status), + (Formattable)0, "$0.00", TRUE, status); + expect(NumberFormat::createInstance("en_US", style, status), + (Formattable)-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)-23456.7, UnicodeString("-23.456,70\\u00A0\\u20AC").unescape(), TRUE, status); +} + +// for #5186 +void NumberFormatTest::TestEquality() { + UErrorCode status = U_ZERO_ERROR; + DecimalFormatSymbols* symbols = new DecimalFormatSymbols(Locale("root"), status); + if (U_FAILURE(status)) { + dataerrln("Fail: can't create DecimalFormatSymbols for root"); + return; + } + UnicodeString pattern("#,##0.###"); + DecimalFormat* fmtBase = new DecimalFormat(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; + + delete fmtBase; +} + +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", UnicodeString("PKR124"), original); + + // test the getter here + UCurrencyUsage curUsage = fmt->getCurrencyUsage(); + assertEquals("Test usage getter - standard", curUsage, 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", curUsage, UCURR_USAGE_CASH); + + UnicodeString cash_currency; + fmt->format(agent,cash_currency); + assertEquals("Test Currency Usage 2", UnicodeString("PKR124"), cash_currency); + 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", UnicodeString("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", UnicodeString("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", UnicodeString("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", UnicodeString("PKR124"), PKR_changed); + delete fmt; + } +} + +void NumberFormatTest::TestNumberFormatTestTuple() { + NumberFormatTestTuple tuple; + UErrorCode status = U_ZERO_ERROR; + + tuple.setField( + NumberFormatTestTuple::getFieldByName("locale"), + "en", + status); + tuple.setField( + NumberFormatTestTuple::getFieldByName("pattern"), + "#,##0.00", + status); + tuple.setField( + NumberFormatTestTuple::getFieldByName("minIntegerDigits"), + "-10", + status); + if (!assertSuccess("", status)) { + return; + } + + // only what we set should be set. + assertEquals("", "en", tuple.locale.getName()); + assertEquals("", "#,##0.00", tuple.pattern); + assertEquals("", -10, tuple.minIntegerDigits); + assertTrue("", tuple.localeFlag); + assertTrue("", tuple.patternFlag); + assertTrue("", tuple.minIntegerDigitsFlag); + assertFalse("", tuple.formatFlag); + + UnicodeString appendTo; + assertEquals( + "", + "{locale: en, pattern: #,##0.00, minIntegerDigits: -10}", + tuple.toString(appendTo)); + + tuple.clear(); + appendTo.remove(); + assertEquals( + "", + "{}", + tuple.toString(appendTo)); + tuple.setField( + NumberFormatTestTuple::getFieldByName("aBadFieldName"), + "someValue", + status); + if (status != U_ILLEGAL_ARGUMENT_ERROR) { + errln("Expected U_ILLEGAL_ARGUMENT_ERROR"); + } + status = U_ZERO_ERROR; + tuple.setField( + NumberFormatTestTuple::getFieldByName("minIntegerDigits"), + "someBadValue", + status); + if (status != U_ILLEGAL_ARGUMENT_ERROR) { + errln("Expected U_ILLEGAL_ARGUMENT_ERROR"); + } +} + +void +NumberFormatTest::TestDataDriven() { + NumberFormatTestDataDriven dd; + dd.setCaller(this); + dd.run("numberformattestspecification.txt", FALSE); +} + + +// 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 = 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 = 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::TestFastPathConsistent11524() { + UErrorCode status = U_ZERO_ERROR; + NumberFormat *fmt = NumberFormat::createInstance("en", status); + if (U_FAILURE(status) || fmt == NULL) { + dataerrln("Failed call to NumberFormat::createInstance() - %s", u_errorName(status)); + return; + } + fmt->setMaximumIntegerDigits(INT32_MIN); + UnicodeString appendTo; + assertEquals("", "0", fmt->format(123, appendTo)); + appendTo.remove(); + assertEquals("", "0", fmt->format(12345, appendTo)); + delete fmt; +} + +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(0); + 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(0); + 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(0); + clock_t start = clock(); + for (int32_t i = 0; i < 1000000; ++i) { + UnicodeString appendTo; + fmt.formatMeasures( + &measureC, 1, appendTo, fpos, status); + } + errln("Took %f", (double) (clock() - start) / CLOCKS_PER_SEC); + assertSuccess("", status); +*/ +} + +void NumberFormatTest::TestFractionalDigitsForCurrency() { + UErrorCode status = U_ZERO_ERROR; + LocalPointer fmt(NumberFormat::createCurrencyInstance("en", status)); + if (U_FAILURE(status)) { + dataerrln("Error creating NumberFormat - %s", u_errorName(status)); + return; + } + UChar JPY[] = {0x4A, 0x50, 0x59, 0x0}; + fmt->setCurrency(JPY, status); + if (!assertSuccess("", status)) { + return; + } + assertEquals("", 0, fmt->getMaximumFractionDigits()); +} + + +void NumberFormatTest::TestFormatCurrencyPlural() { + UErrorCode status = U_ZERO_ERROR; + Locale locale = Locale::createCanonical("en_US"); + NumberFormat *fmt = NumberFormat::createInstance(locale, UNUM_CURRENCY_PLURAL, status); + if (U_FAILURE(status)) { + dataerrln("Error creating NumberFormat - %s", u_errorName(status)); + return; + } + UnicodeString formattedNum; + fmt->format(11234.567, formattedNum, NULL, status); + assertEquals("", "11,234.57 US dollars", formattedNum); + delete fmt; +} + +void NumberFormatTest::TestCtorApplyPatternDifference() { + UErrorCode status = U_ZERO_ERROR; + DecimalFormatSymbols sym("en_US", status); + UnicodeString pattern("\\u00a40"); + DecimalFormat fmt(pattern.unescape(), sym, status); + if (U_FAILURE(status)) { + dataerrln("Error creating DecimalFormat - %s", u_errorName(status)); + return; + } + UnicodeString result; + assertEquals( + "ctor favors precision of currency", + "$5.00", + fmt.format(5, result)); + result.remove(); + fmt.applyPattern(pattern.unescape(), status); + assertEquals( + "applyPattern favors precision of pattern", + "$5", + fmt.format(5, result)); +} + +void NumberFormatTest::Test11868() { + double posAmt = 34.567; + double negAmt = -9876.543; + + Locale selectedLocale("en_US"); + UErrorCode status = U_ZERO_ERROR; + + UnicodeString result; + FieldPosition fpCurr(UNUM_CURRENCY_FIELD); + LocalPointer fmt( + NumberFormat::createInstance( + selectedLocale, UNUM_CURRENCY_PLURAL, status)); + if (!assertSuccess("Format creation", status)) { + return; + } + fmt->format(posAmt, result, fpCurr, status); + assertEquals("", "34.57 US dollars", result); + assertEquals("begin index", 6, fpCurr.getBeginIndex()); + assertEquals("end index", 16, fpCurr.getEndIndex()); + + // Test field position iterator + { + NumberFormatTest_Attributes attributes[] = { + {UNUM_INTEGER_FIELD, 0, 2}, + {UNUM_DECIMAL_SEPARATOR_FIELD, 2, 3}, + {UNUM_FRACTION_FIELD, 3, 5}, + {UNUM_CURRENCY_FIELD, 6, 16}, + {0, -1, 0}}; + UnicodeString result; + FieldPositionIterator iter; + fmt->format(posAmt, result, &iter, status); + assertEquals("", "34.57 US dollars", result); + verifyFieldPositionIterator(attributes, iter); + } + + result.remove(); + fmt->format(negAmt, result, fpCurr, status); + assertEquals("", "-9,876.54 US dollars", result); + assertEquals("begin index", 10, fpCurr.getBeginIndex()); + assertEquals("end index", 20, fpCurr.getEndIndex()); + + // Test field position iterator + { + NumberFormatTest_Attributes attributes[] = { + {UNUM_SIGN_FIELD, 0, 1}, + {UNUM_GROUPING_SEPARATOR_FIELD, 2, 3}, + {UNUM_INTEGER_FIELD, 1, 6}, + {UNUM_DECIMAL_SEPARATOR_FIELD, 6, 7}, + {UNUM_FRACTION_FIELD, 7, 9}, + {UNUM_CURRENCY_FIELD, 10, 20}, + {0, -1, 0}}; + UnicodeString result; + FieldPositionIterator iter; + fmt->format(negAmt, result, &iter, status); + assertEquals("", "-9,876.54 US dollars", result); + verifyFieldPositionIterator(attributes, iter); + } +} + +void NumberFormatTest::Test10727_RoundingZero() { + DigitList d; + d.set(-0.0); + assertFalse("", d.isPositive()); + d.round(3); + assertFalse("", d.isPositive()); +} + +void NumberFormatTest::Test11376_getAndSetPositivePrefix() { + { + const UChar USD[] = {0x55, 0x53, 0x44, 0x0}; + UErrorCode status = U_ZERO_ERROR; + LocalPointer fmt( + NumberFormat::createCurrencyInstance("en", status)); + if (!assertSuccess("", status)) { + return; + } + DecimalFormat *dfmt = (DecimalFormat *) fmt.getAlias(); + dfmt->setCurrency(USD); + UnicodeString result; + + // This line should be a no-op. I am setting the positive prefix + // to be the same thing it was before. + dfmt->setPositivePrefix(dfmt->getPositivePrefix(result)); + + UnicodeString appendTo; + assertEquals("", "$3.78", dfmt->format(3.78, appendTo, status)); + assertSuccess("", status); + } + { + const UChar USD[] = {0x55, 0x53, 0x44, 0x0}; + UErrorCode status = U_ZERO_ERROR; + LocalPointer fmt( + NumberFormat::createInstance("en", UNUM_CURRENCY_PLURAL, status)); + if (!assertSuccess("", status)) { + return; + } + DecimalFormat *dfmt = (DecimalFormat *) fmt.getAlias(); + UnicodeString result; + UnicodeString tripleIntlCurrency(" \\u00a4\\u00a4\\u00a4"); + tripleIntlCurrency = tripleIntlCurrency.unescape(); + assertEquals("", tripleIntlCurrency, dfmt->getPositiveSuffix(result)); + 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::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::checkExceptionIssue11735() { + UErrorCode status; + Locale enLocale("en"); + DecimalFormatSymbols symbols(enLocale, status); + + if (U_FAILURE(status)) { + errln((UnicodeString) + "Fail: Construct DecimalFormatSymbols"); + } + + DecimalFormat fmt("0", symbols, status); + if (U_FAILURE(status)) { + errln((UnicodeString) + "Fail: Construct DecimalFormat formatter"); + } + + ParsePosition ppos(0); + fmt.parseCurrency("53.45", ppos); // NPE thrown here in ICU4J. + assertEquals("Issue11735 ppos", 0, ppos.getIndex()); +} + #endif /* #if !UCONFIG_NO_FORMATTING */