// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/********************************************************************
 * COPYRIGHT:
 * Copyright (c) 1997-2016, International Business Machines Corporation and
 * others. All Rights Reserved.
 ********************************************************************/
/* Modification History:
*   Date        Name        Description
*   07/15/99    helena      Ported to HPUX 10/11 CC.
*/

#include "unicode/utypes.h"

#if !UCONFIG_NO_FORMATTING

#include "numfmtst.h"
#include "unicode/currpinf.h"
#include "unicode/dcfmtsym.h"
#include "unicode/decimfmt.h"
#include "unicode/localpointer.h"
#include "unicode/ucurr.h"
#include "unicode/ustring.h"
#include "unicode/measfmt.h"
#include "unicode/curramt.h"
#include "unicode/strenum.h"
#include "textfile.h"
#include "tokiter.h"
#include "charstr.h"
#include "cstr.h"
#include "putilimp.h"
#include "winnmtst.h"
#include <cmath>
#include <float.h>
#include <string.h>
#include <stdlib.h>
#include "cmemory.h"
#include "cstring.h"
#include "unicode/numsys.h"
#include "fmtableimp.h"
#include "numberformattesttuple.h"
#include "unicode/msgfmt.h"
#include "number_decimalquantity.h"
#include "unicode/numberformatter.h"

#if (U_PLATFORM == U_PF_AIX) || (U_PLATFORM == U_PF_OS390)
// These should not be macros. If they are,
// replace them with std::isnan and std::isinf
#if defined(isnan)
#undef isnan
namespace std {
 bool isnan(double x) {
   return _isnan(x);
 }
}
#endif
#if defined(isinf)
#undef isinf
namespace std {
 bool isinf(double x) {
   return _isinf(x);
 }
}
#endif
#endif

using icu::number::impl::DecimalQuantity;
using namespace icu::number;

//#define NUMFMTST_CACHE_DEBUG 1
#include "stdio.h" /* for sprintf */
// #include "iostream"   // for cout

//#define NUMFMTST_DEBUG 1

static const UChar EUR[] = {69,85,82,0}; // "EUR"
static const UChar ISO_CURRENCY_USD[] = {0x55, 0x53, 0x44, 0}; // "USD"


// *****************************************************************************
// class NumberFormatTest
// *****************************************************************************

#define 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*/ )
{
  TESTCASE_AUTO_BEGIN;
  TESTCASE_AUTO(TestCurrencySign);
  TESTCASE_AUTO(TestCurrency);
  TESTCASE_AUTO(TestParse);
  TESTCASE_AUTO(TestRounding487);
  TESTCASE_AUTO(TestQuotes);
  TESTCASE_AUTO(TestExponential);
  TESTCASE_AUTO(TestPatterns);

  // Upgrade to alphaWorks - liu 5/99
  TESTCASE_AUTO(TestExponent);
  TESTCASE_AUTO(TestScientific);
  TESTCASE_AUTO(TestPad);
  TESTCASE_AUTO(TestPatterns2);
  TESTCASE_AUTO(TestSecondaryGrouping);
  TESTCASE_AUTO(TestSurrogateSupport);
  TESTCASE_AUTO(TestAPI);

  TESTCASE_AUTO(TestCurrencyObject);
  TESTCASE_AUTO(TestCurrencyPatterns);
  //TESTCASE_AUTO(TestDigitList);
  TESTCASE_AUTO(TestWhiteSpaceParsing);
  TESTCASE_AUTO(TestComplexCurrency);  // This test removed because CLDR no longer uses choice formats in currency symbols.
  TESTCASE_AUTO(TestRegCurrency);
  TESTCASE_AUTO(TestSymbolsWithBadLocale);
  TESTCASE_AUTO(TestAdoptDecimalFormatSymbols);

  TESTCASE_AUTO(TestScientific2);
  TESTCASE_AUTO(TestScientificGrouping);
  TESTCASE_AUTO(TestInt64);

  TESTCASE_AUTO(TestPerMill);
  TESTCASE_AUTO(TestIllegalPatterns);
  TESTCASE_AUTO(TestCases);

  TESTCASE_AUTO(TestCurrencyNames);
  TESTCASE_AUTO(TestCurrencyAmount);
  TESTCASE_AUTO(TestCurrencyUnit);
  TESTCASE_AUTO(TestCoverage);
  TESTCASE_AUTO(TestLocalizedPatternSymbolCoverage);
  TESTCASE_AUTO(TestJB3832);
  TESTCASE_AUTO(TestHost);
  TESTCASE_AUTO(TestHostClone);
  TESTCASE_AUTO(TestCurrencyFormat);
  TESTCASE_AUTO(TestRounding);
  TESTCASE_AUTO(TestNonpositiveMultiplier);
  TESTCASE_AUTO(TestNumberingSystems);
  TESTCASE_AUTO(TestSpaceParsing);
  TESTCASE_AUTO(TestMultiCurrencySign);
  TESTCASE_AUTO(TestCurrencyFormatForMixParsing);
  TESTCASE_AUTO(TestMismatchedCurrencyFormatFail);
  TESTCASE_AUTO(TestDecimalFormatCurrencyParse);
  TESTCASE_AUTO(TestCurrencyIsoPluralFormat);
  TESTCASE_AUTO(TestCurrencyParsing);
  TESTCASE_AUTO(TestParseCurrencyInUCurr);
  TESTCASE_AUTO(TestFormatAttributes);
  TESTCASE_AUTO(TestFieldPositionIterator);
  TESTCASE_AUTO(TestDecimal);
  TESTCASE_AUTO(TestCurrencyFractionDigits);
  TESTCASE_AUTO(TestExponentParse);
  TESTCASE_AUTO(TestExplicitParents);
  TESTCASE_AUTO(TestLenientParse);
  TESTCASE_AUTO(TestAvailableNumberingSystems);
  TESTCASE_AUTO(TestRoundingPattern);
  TESTCASE_AUTO(Test9087);
  TESTCASE_AUTO(TestFormatFastpaths);
  TESTCASE_AUTO(TestFormattableSize);
  TESTCASE_AUTO(TestUFormattable);
  TESTCASE_AUTO(TestSignificantDigits);
  TESTCASE_AUTO(TestShowZero);
  TESTCASE_AUTO(TestCompatibleCurrencies);
  TESTCASE_AUTO(TestBug9936);
  TESTCASE_AUTO(TestParseNegativeWithFaLocale);
  TESTCASE_AUTO(TestParseNegativeWithAlternateMinusSign);
  TESTCASE_AUTO(TestCustomCurrencySignAndSeparator);
  TESTCASE_AUTO(TestParseSignsAndMarks);
  TESTCASE_AUTO(Test10419RoundingWith0FractionDigits);
  TESTCASE_AUTO(Test10468ApplyPattern);
  TESTCASE_AUTO(TestRoundingScientific10542);
  TESTCASE_AUTO(TestZeroScientific10547);
  TESTCASE_AUTO(TestAccountingCurrency);
  TESTCASE_AUTO(TestEquality);
  TESTCASE_AUTO(TestCurrencyUsage);
  TESTCASE_AUTO(TestDoubleLimit11439);
  TESTCASE_AUTO(TestGetAffixes);
  TESTCASE_AUTO(TestToPatternScientific11648);
  TESTCASE_AUTO(TestBenchmark);
  TESTCASE_AUTO(TestCtorApplyPatternDifference);
  TESTCASE_AUTO(TestFractionalDigitsForCurrency);
  TESTCASE_AUTO(TestFormatCurrencyPlural);
  TESTCASE_AUTO(Test11868);
  TESTCASE_AUTO(Test11739_ParseLongCurrency);
  TESTCASE_AUTO(Test13035_MultiCodePointPaddingInPattern);
  TESTCASE_AUTO(Test13737_ParseScientificStrict);
  TESTCASE_AUTO(Test10727_RoundingZero);
  TESTCASE_AUTO(Test11376_getAndSetPositivePrefix);
  TESTCASE_AUTO(Test11475_signRecognition);
  TESTCASE_AUTO(Test11640_getAffixes);
  TESTCASE_AUTO(Test11649_toPatternWithMultiCurrency);
  TESTCASE_AUTO(Test13327_numberingSystemBufferOverflow);
  TESTCASE_AUTO(Test13391_chakmaParsing);
  TESTCASE_AUTO(Test11735_ExceptionIssue);
  TESTCASE_AUTO(Test11035_FormatCurrencyAmount);
  TESTCASE_AUTO(Test11318_DoubleConversion);
  TESTCASE_AUTO(TestParsePercentRegression);
  TESTCASE_AUTO(TestMultiplierWithScale);
  TESTCASE_AUTO(TestFastFormatInt32);
  TESTCASE_AUTO(Test11646_Equality);
  TESTCASE_AUTO(TestParseNaN);
  TESTCASE_AUTO(Test11897_LocalizedPatternSeparator);
  TESTCASE_AUTO(Test13055_PercentageRounding);
  TESTCASE_AUTO(Test11839);
  TESTCASE_AUTO(Test10354);
  TESTCASE_AUTO(Test11645_ApplyPatternEquality);
  TESTCASE_AUTO(Test12567);
  TESTCASE_AUTO(Test11626_CustomizeCurrencyPluralInfo);
  TESTCASE_AUTO(Test13056_GroupingSize);
  TESTCASE_AUTO(Test11025_CurrencyPadding);
  TESTCASE_AUTO(Test11648_ExpDecFormatMalPattern);
  TESTCASE_AUTO(Test11649_DecFmtCurrencies);
  TESTCASE_AUTO(Test13148_ParseGroupingSeparators);
  TESTCASE_AUTO(Test12753_PatternDecimalPoint);
  TESTCASE_AUTO(Test11647_PatternCurrencySymbols);
  TESTCASE_AUTO(Test11913_BigDecimal);
  TESTCASE_AUTO(Test11020_RoundingInScientificNotation);
  TESTCASE_AUTO(Test11640_TripleCurrencySymbol);
  TESTCASE_AUTO(Test13763_FieldPositionIteratorOffset);
  TESTCASE_AUTO(Test13777_ParseLongNameNonCurrencyMode);
  TESTCASE_AUTO(Test13804_EmptyStringsWhenParsing);
  TESTCASE_AUTO(Test13840_ParseLongStringCrash);
  TESTCASE_AUTO_END;
}

// -------------------------------------

// Test API (increase code coverage)
void
NumberFormatTest::TestAPI(void)
{
  logln("Test API");
  UErrorCode status = U_ZERO_ERROR;
  NumberFormat *test = NumberFormat::createInstance("root", status);
  if(U_FAILURE(status)) {
    dataerrln("unable to create format object - %s", u_errorName(status));
  }
  if(test != NULL) {
    test->setMinimumIntegerDigits(10);
    test->setMaximumIntegerDigits(1);

    test->setMinimumFractionDigits(10);
    test->setMaximumFractionDigits(1);

    UnicodeString result;
    FieldPosition pos;
    Formattable bla("Paja Patak"); // Donald Duck for non Serbian speakers
    test->format(bla, result, pos, status);
    if(U_SUCCESS(status)) {
      errln("Yuck... Formatted a duck... As a number!");
    } else {
      status = U_ZERO_ERROR;
    }

    result.remove();
    int64_t ll = 12;
    test->format(ll, result);
    assertEquals("format int64_t error", u"2.0", result);

    test->setMinimumIntegerDigits(4);
    test->setMinimumFractionDigits(4);

    result.remove();
    test->format(ll, result);
    assertEquals("format int64_t error", u"0,012.0000", result);

    ParsePosition ppos;
    LocalPointer<CurrencyAmount> currAmt(test->parseCurrency("",ppos));
    // old test for (U_FAILURE(status)) was bogus here, method does not set status!
    if (ppos.getIndex()) {
        errln("Parsed empty string as currency");
    }

    delete test;
  }
}

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, ,)");
    };
}

void NumberFormatTest::TestLocalizedPatternSymbolCoverage() {
    IcuTestErrorCode errorCode(*this, "TestLocalizedPatternSymbolCoverage");
    // Ticket #12961: DecimalFormat::toLocalizedPattern() is not working as designed.
    DecimalFormatSymbols dfs(errorCode);
    dfs.setSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol, u'⁖');
    dfs.setSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol, u'⁘');
    dfs.setSymbol(DecimalFormatSymbols::kPatternSeparatorSymbol, u'⁙');
    dfs.setSymbol(DecimalFormatSymbols::kDigitSymbol, u'▰');
    dfs.setSymbol(DecimalFormatSymbols::kZeroDigitSymbol, u'໐');
    dfs.setSymbol(DecimalFormatSymbols::kSignificantDigitSymbol, u'⁕');
    dfs.setSymbol(DecimalFormatSymbols::kPlusSignSymbol, u'†');
    dfs.setSymbol(DecimalFormatSymbols::kMinusSignSymbol, u'‡');
    dfs.setSymbol(DecimalFormatSymbols::kPercentSymbol, u'⁜');
    dfs.setSymbol(DecimalFormatSymbols::kPerMillSymbol, u'‱');
    dfs.setSymbol(DecimalFormatSymbols::kExponentialSymbol, u"⁑⁑"); // tests multi-char sequence
    dfs.setSymbol(DecimalFormatSymbols::kPadEscapeSymbol, u'⁂');

    {
        UnicodeString standardPattern(u"#,##0.05+%;#,##0.05-%");
        UnicodeString localizedPattern(u"▰⁖▰▰໐⁘໐໕†⁜⁙▰⁖▰▰໐⁘໐໕‡⁜");

        DecimalFormat df1("#", new DecimalFormatSymbols(dfs), errorCode);
        df1.applyPattern(standardPattern, errorCode);
        DecimalFormat df2("#", new DecimalFormatSymbols(dfs), errorCode);
        df2.applyLocalizedPattern(localizedPattern, errorCode);
        assertTrue("DecimalFormat instances should be equal", df1 == df2);
        UnicodeString p2;
        assertEquals("toPattern should match on localizedPattern instance",
                standardPattern, df2.toPattern(p2));
        UnicodeString lp1;
        assertEquals("toLocalizedPattern should match on standardPattern instance",
                localizedPattern, df1.toLocalizedPattern(lp1));
    }

    {
        UnicodeString standardPattern(u"* @@@E0‰");
        UnicodeString localizedPattern(u"⁂ ⁕⁕⁕⁑⁑໐‱");

        DecimalFormat df1("#", new DecimalFormatSymbols(dfs), errorCode);
        df1.applyPattern(standardPattern, errorCode);
        DecimalFormat df2("#", new DecimalFormatSymbols(dfs), errorCode);
        df2.applyLocalizedPattern(localizedPattern, errorCode);
        assertTrue("DecimalFormat instances should be equal", df1 == df2);
        UnicodeString p2;
        assertEquals("toPattern should match on localizedPattern instance",
                standardPattern, df2.toPattern(p2));
        UnicodeString lp1;
        assertEquals("toLocalizedPattern should match on standardPattern instance",
                localizedPattern, df1.toLocalizedPattern(lp1));
    }
}

// Test various patterns
void
NumberFormatTest::TestPatterns(void)
{
    UErrorCode status = U_ZERO_ERROR;
    DecimalFormatSymbols sym(Locale::getUS(), status);
    if (U_FAILURE(status)) { errcheckln(status, "FAIL: Could not construct DecimalFormatSymbols - %s", u_errorName(status)); return; }

    const char* pat[]    = { "#.#", "#.", ".#", "#" };
    int32_t pat_length = UPRV_LENGTHOF(pat);
    const char* newpat[] = { "0.#", "0.", "#.0", "0" };
    const char* num[]    = { "0",   "0.", ".0", "0" };
    for (int32_t i=0; i<pat_length; ++i)
    {
        status = U_ZERO_ERROR;
        DecimalFormat fmt(pat[i], sym, status);
        if (U_FAILURE(status)) { errln((UnicodeString)"FAIL: DecimalFormat constructor failed for " + pat[i]); continue; }
        UnicodeString newp; fmt.toPattern(newp);
        if (!(newp == newpat[i]))
            errln((UnicodeString)"FAIL: Pattern " + pat[i] + " should transmute to " + newpat[i] +
                  "; " + newp + " seen instead");

        UnicodeString s; (*(NumberFormat*)&fmt).format((int32_t)0, s);
        if (!(s == num[i]))
        {
            errln((UnicodeString)"FAIL: Pattern " + pat[i] + " should format zero as " + num[i] +
                  "; " + s + " seen instead");
            logln((UnicodeString)"Min integer digits = " + fmt.getMinimumIntegerDigits());
        }
    }
}

/*
icu_2_4::DigitList::operator== 0 0 2 icuuc24d.dll digitlst.cpp Doug
icu_2_4::DigitList::append 0 0 4 icuin24d.dll digitlst.h Doug
icu_2_4::DigitList::operator!= 0 0 1 icuuc24d.dll digitlst.h Doug
*/
/*
void
NumberFormatTest::TestDigitList(void)
{
  // API coverage for DigitList
  DigitList list1;
  list1.append('1');
  list1.fDecimalAt = 1;
  DigitList list2;
  list2.set((int32_t)1);
  if (list1 != list2) {
    errln("digitlist append, operator!= or set failed ");
  }
  if (!(list1 == list2)) {
    errln("digitlist append, operator== or set failed ");
  }
}
*/

// -------------------------------------

// Test exponential pattern
void
NumberFormatTest::TestExponential(void)
{
    UErrorCode status = U_ZERO_ERROR;
    DecimalFormatSymbols sym(Locale::getUS(), status);
    if (U_FAILURE(status)) { errcheckln(status, "FAIL: Bad status returned by DecimalFormatSymbols ct - %s", u_errorName(status)); return; }
    const char* pat[] = { "0.####E0", "00.000E00", "##0.######E000", "0.###E0;[0.###E0]"  };
    int32_t pat_length = UPRV_LENGTHOF(pat);

// The following #if statements allow this test to be built and run on
// platforms that do not have standard IEEE numerics.  For example,
// S/390 doubles have an exponent range of -78 to +75.  For the
// following #if statements to work, float.h must define
// DBL_MAX_10_EXP to be a compile-time constant.

// This section may be expanded as needed.

#if DBL_MAX_10_EXP > 300
    double val[] = { 0.01234, 123456789, 1.23e300, -3.141592653e-271 };
    int32_t val_length = UPRV_LENGTHOF(val);
    const char* valFormat[] =
    {
        // 0.####E0
        "1.234E-2", "1.2346E8", "1.23E300", "-3.1416E-271",
        // 00.000E00
        "12.340E-03", "12.346E07", "12.300E299", "-31.416E-272",
        // ##0.######E000
        "12.34E-003", "123.4568E006", "1.23E300", "-314.1593E-273",
        // 0.###E0;[0.###E0]
        "1.234E-2", "1.235E8", "1.23E300", "[3.142E-271]"
    };
    double valParse[] =
    {
        0.01234, 123460000, 1.23E300, -3.1416E-271,
        0.01234, 123460000, 1.23E300, -3.1416E-271,
        0.01234, 123456800, 1.23E300, -3.141593E-271,
        0.01234, 123500000, 1.23E300, -3.142E-271,
    };
#elif DBL_MAX_10_EXP > 70
    double val[] = { 0.01234, 123456789, 1.23e70, -3.141592653e-71 };
    int32_t val_length = UPRV_LENGTHOF(val);
    char* valFormat[] =
    {
        // 0.####E0
        "1.234E-2", "1.2346E8", "1.23E70", "-3.1416E-71",
        // 00.000E00
        "12.340E-03", "12.346E07", "12.300E69", "-31.416E-72",
        // ##0.######E000
        "12.34E-003", "123.4568E006", "12.3E069", "-31.41593E-072",
        // 0.###E0;[0.###E0]
        "1.234E-2", "1.235E8", "1.23E70", "[3.142E-71]"
    };
    double valParse[] =
    {
        0.01234, 123460000, 1.23E70, -3.1416E-71,
        0.01234, 123460000, 1.23E70, -3.1416E-71,
        0.01234, 123456800, 1.23E70, -3.141593E-71,
        0.01234, 123500000, 1.23E70, -3.142E-71,
    };
#else
    // Don't test double conversion
    double* val = 0;
    int32_t val_length = 0;
    char** valFormat = 0;
    double* valParse = 0;
    logln("Warning: Skipping double conversion tests");
#endif

    int32_t lval[] = { 0, -1, 1, 123456789 };
    int32_t lval_length = UPRV_LENGTHOF(lval);
    const char* lvalFormat[] =
    {
        // 0.####E0
        "0E0", "-1E0", "1E0", "1.2346E8",
        // 00.000E00
        "00.000E00", "-10.000E-01", "10.000E-01", "12.346E07",
        // ##0.######E000
        "0E000", "-1E000", "1E000", "123.4568E006",
        // 0.###E0;[0.###E0]
        "0E0", "[1E0]", "1E0", "1.235E8"
    };
    int32_t lvalParse[] =
    {
        0, -1, 1, 123460000,
        0, -1, 1, 123460000,
        0, -1, 1, 123456800,
        0, -1, 1, 123500000,
    };
    int32_t ival = 0, ilval = 0;
    for (int32_t p=0; p<pat_length; ++p)
    {
        DecimalFormat fmt(pat[p], sym, status);
        if (U_FAILURE(status)) { errln("FAIL: Bad status returned by DecimalFormat ct"); continue; }
        UnicodeString pattern;
        logln((UnicodeString)"Pattern \"" + pat[p] + "\" -toPattern-> \"" +
          fmt.toPattern(pattern) + "\"");
        int32_t v;
        for (v=0; v<val_length; ++v)
        {
            UnicodeString s; (*(NumberFormat*)&fmt).format(val[v], s);
            logln((UnicodeString)" " + val[v] + " -format-> " + s);
            if (s != valFormat[v+ival])
                errln((UnicodeString)"FAIL: Expected " + valFormat[v+ival]);

            ParsePosition pos(0);
            Formattable af;
            fmt.parse(s, af, pos);
            double a;
            UBool useEpsilon = FALSE;
            if (af.getType() == Formattable::kLong)
                a = af.getLong();
            else if (af.getType() == Formattable::kDouble) {
                a = af.getDouble();
#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
                //| FAIL: Expected -3.141599999999999e-271
                // To compensate, we use an epsilon-based equality
                // test on S/390 only.  We don't want to do this in
                // general because it's less exacting.
                useEpsilon = TRUE;
#endif
            }
            else {
                errln(UnicodeString("FAIL: Non-numeric Formattable returned: ") + pattern + " " + s);
                continue;
            }
            if (pos.getIndex() == s.length())
            {
                logln((UnicodeString)"  -parse-> " + a);
                // Use epsilon comparison as necessary
                if ((useEpsilon &&
                    (uprv_fabs(a - valParse[v+ival]) / a > (2*DBL_EPSILON))) ||
                    (!useEpsilon && a != valParse[v+ival]))
                {
                    errln((UnicodeString)"FAIL: Expected " + valParse[v+ival] + " but got " + a
                        + " on input " + s);
                }
            }
            else {
                errln((UnicodeString)"FAIL: Partial parse (" + pos.getIndex() + " chars) -> " + a);
                errln((UnicodeString)"  should be (" + s.length() + " chars) -> " + valParse[v+ival]);
            }
        }
        for (v=0; v<lval_length; ++v)
        {
            UnicodeString s;
            (*(NumberFormat*)&fmt).format(lval[v], s);
            logln((UnicodeString)" " + lval[v] + "L -format-> " + s);
            if (s != lvalFormat[v+ilval])
                errln((UnicodeString)"ERROR: Expected " + lvalFormat[v+ilval] + " Got: " + s);

            ParsePosition pos(0);
            Formattable af;
            fmt.parse(s, af, pos);
            if (af.getType() == Formattable::kLong ||
                af.getType() == Formattable::kInt64) {
                UErrorCode status = U_ZERO_ERROR;
                int32_t a = af.getLong(status);
                if (pos.getIndex() == s.length())
                {
                    logln((UnicodeString)"  -parse-> " + a);
                    if (a != lvalParse[v+ilval])
                        errln((UnicodeString)"FAIL: Expected " + lvalParse[v+ilval] + " but got " + a);
                }
                else
                    errln((UnicodeString)"FAIL: Partial parse (" + pos.getIndex() + " chars) -> " + a);
            }
            else
                errln((UnicodeString)"FAIL: Non-long Formattable returned for " + s
                    + " Double: " + af.getDouble()
                    + ", Long: " + af.getLong());
        }
        ival += val_length;
        ilval += lval_length;
    }
}

void
NumberFormatTest::TestScientific2() {
    // jb 2552
    UErrorCode status = U_ZERO_ERROR;
    DecimalFormat* fmt = (DecimalFormat*)NumberFormat::createCurrencyInstance("en_US", status);
    if (U_SUCCESS(status)) {
        double num = 12.34;
        expect(*fmt, num, "$12.34");
        fmt->setScientificNotation(TRUE);
        expect(*fmt, num, "$1.23E1");
        fmt->setScientificNotation(FALSE);
        expect(*fmt, num, "$12.34");
    }
    delete fmt;
}

void
NumberFormatTest::TestScientificGrouping() {
    // jb 2552
    UErrorCode status = U_ZERO_ERROR;
    DecimalFormat fmt("##0.00E0",status);
    if (assertSuccess("", status, true, __FILE__, __LINE__)) {
        expect(fmt, .01234, "12.3E-3");
        expect(fmt, .1234, "123E-3");
        expect(fmt, 1.234, "1.23E0");
        expect(fmt, 12.34, "12.3E0");
        expect(fmt, 123.4, "123E0");
        expect(fmt, 1234., "1.23E3");
    }
}

/*static void setFromString(DigitList& dl, const char* str) {
    char c;
    UBool decimalSet = FALSE;
    dl.clear();
    while ((c = *str++)) {
        if (c == '-') {
            dl.fIsPositive = FALSE;
        } else if (c == '+') {
            dl.fIsPositive = TRUE;
        } else if (c == '.') {
            dl.fDecimalAt = dl.fCount;
            decimalSet = TRUE;
        } else {
            dl.append(c);
        }
    }
    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");
        expect(fmt, (Formattable)(int64_t)-1, "-1E0");
        expect(fmt, (Formattable)(int64_t)1, "1E0");
        expect(fmt, (Formattable)(int64_t)2147483647, "2.147483647E9");
        expect(fmt, (Formattable)((int64_t)-2147483647-1), "-2.147483648E9");
        expect(fmt, (Formattable)(int64_t)U_INT64_MAX, "9.223372036854775807E18");
        expect(fmt, (Formattable)(int64_t)U_INT64_MIN, "-9.223372036854775808E18");
    }

    // also test digitlist
/*    int64_t int64max = U_INT64_MAX;
    int64_t int64min = U_INT64_MIN;
    const char* int64maxstr = "9223372036854775807";
    const char* int64minstr = "-9223372036854775808";
    UnicodeString fail("fail: ");

    // test max int64 value
    DigitList dl;
    setFromString(dl, int64maxstr);
    {
        if (!dl.fitsIntoInt64(FALSE)) {
            errln(fail + int64maxstr + " didn't fit");
        }
        int64_t int64Value = dl.getInt64();
        if (int64Value != int64max) {
            errln(fail + int64maxstr);
        }
        dl.set(int64Value);
        int64Value = dl.getInt64();
        if (int64Value != int64max) {
            errln(fail + int64maxstr);
        }
    }
    // test negative of max int64 value (1 shy of min int64 value)
    dl.fIsPositive = FALSE;
    {
        if (!dl.fitsIntoInt64(FALSE)) {
            errln(fail + "-" + int64maxstr + " didn't fit");
        }
        int64_t int64Value = dl.getInt64();
        if (int64Value != -int64max) {
            errln(fail + "-" + int64maxstr);
        }
        dl.set(int64Value);
        int64Value = dl.getInt64();
        if (int64Value != -int64max) {
            errln(fail + "-" + int64maxstr);
        }
    }
    // test min int64 value
    setFromString(dl, int64minstr);
    {
        if (!dl.fitsIntoInt64(FALSE)) {
            errln(fail + "-" + int64minstr + " didn't fit");
        }
        int64_t int64Value = dl.getInt64();
        if (int64Value != int64min) {
            errln(fail + int64minstr);
        }
        dl.set(int64Value);
        int64Value = dl.getInt64();
        if (int64Value != int64min) {
            errln(fail + int64minstr);
        }
    }
    // test negative of min int 64 value (1 more than max int64 value)
    dl.fIsPositive = TRUE; // won't fit
    {
        if (dl.fitsIntoInt64(FALSE)) {
            errln(fail + "-(" + int64minstr + ") didn't fit");
        }
    }*/
}

// -------------------------------------

// Test the handling of quotes
void
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;
    ((NumberFormat*)fmt)->format((int32_t)123, s);
    logln((UnicodeString)"Pattern \"" + *pat + "\"");
    logln((UnicodeString)" Format 123 -> " + escape(s));
    if (!(s=="afo'ob123"))
        errln((UnicodeString)"FAIL: Expected afo'ob123");

    s.truncate(0);
    delete fmt;
    delete pat;

    pat = new UnicodeString("a''b#");
    fmt = new DecimalFormat(*pat, *sym, status);
    ((NumberFormat*)fmt)->format((int32_t)123, s);
    logln((UnicodeString)"Pattern \"" + *pat + "\"");
    logln((UnicodeString)" Format 123 -> " + escape(s));
    if (!(s=="a'b123"))
        errln((UnicodeString)"FAIL: Expected a'b123");
    delete fmt;
    delete pat;
    delete sym;
}

/**
 * Test the handling of the currency symbol in patterns.
 */
void
NumberFormatTest::TestCurrencySign(void)
{
    UErrorCode status = U_ZERO_ERROR;
    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");
    DecimalFormat *fmt = new DecimalFormat(pat, *sym, status);
    UnicodeString s; ((NumberFormat*)fmt)->format(1234.56, s);
    pat.truncate(0);
    logln((UnicodeString)"Pattern \"" + fmt->toPattern(pat) + "\"");
    logln((UnicodeString)" Format " + 1234.56 + " -> " + escape(s));
    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") dataerrln((UnicodeString)"FAIL: Expected -$1,234.56");
    delete fmt;
    pat.truncate(0);
    // "\xA4\xA4 #,##0.00;\xA4\xA4 -#,##0.00"
    pat.append(currency).append(currency).
        append(" #,##0.00;").
        append(currency).append(currency).
        append(" -#,##0.00");
    fmt = new DecimalFormat(pat, *sym, status);
    s.truncate(0);
    ((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") 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") dataerrln((UnicodeString)"FAIL: Expected USD -1,234.56");
    delete fmt;
    delete sym;
    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))); }

UnicodeString&
NumberFormatTest::escape(UnicodeString& s)
{
    UnicodeString buf;
    for (int32_t i=0; i<s.length(); ++i)
    {
        UChar c = s[(int32_t)i];
        if (c <= (UChar)0x7F) buf += c;
        else {
            buf += (UChar)0x5c; buf += (UChar)0x55;
            buf += toHexString((c & 0xF000) >> 12);
            buf += toHexString((c & 0x0F00) >> 8);
            buf += toHexString((c & 0x00F0) >> 4);
            buf += toHexString(c & 0x000F);
        }
    }
    return (s = buf);
}


// -------------------------------------
static const char* testCases[][2]= {
     /* locale ID */  /* expected */
    {"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.
 */
void
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==CharsToUnicodeString("1,50\\u00A0$")))
        errln((UnicodeString)"FAIL: Expected 1,50<nbsp>$ but got " + s);
    delete currencyFmt;
    s.truncate(0);
    char loc[256]={0};
    int len = uloc_canonicalize("de_DE_PREEURO", loc, 256, &status);
    (void)len;  // Suppress unused variable warning.
    currencyFmt = NumberFormat::createCurrencyInstance(Locale(loc),status);
    currencyFmt->format(1.50, s);
    logln((UnicodeString)"Un pauvre en Allemagne a.." + s);
    if (!(s==CharsToUnicodeString("1,50\\u00A0DM")))
        errln((UnicodeString)"FAIL: Expected 1,50<nbsp>DM but got " + s);
    delete currencyFmt;
    s.truncate(0);
    len = uloc_canonicalize("fr_FR_PREEURO", loc, 256, &status);
    currencyFmt = NumberFormat::createCurrencyInstance(Locale(loc), status);
    currencyFmt->format(1.50, s);
    logln((UnicodeString)"Un pauvre en France a....." + s);
    if (!(s==CharsToUnicodeString("1,50\\u00A0F")))
        errln((UnicodeString)"FAIL: Expected 1,50<nbsp>F");
    delete currencyFmt;
    if (U_FAILURE(status))
        errln((UnicodeString)"FAIL: Status " + (int32_t)status);

    for(int i=0; i < UPRV_LENGTHOF(testCases); i++){
        status = U_ZERO_ERROR;
        const char *localeID = testCases[i][0];
        UnicodeString expected(testCases[i][1], -1, US_INV);
        expected = expected.unescape();
        s.truncate(0);
        char loc[256]={0};
        uloc_canonicalize(localeID, loc, 256, &status);
        currencyFmt = NumberFormat::createCurrencyInstance(Locale(loc), status);
        if(U_FAILURE(status)){
            errln("Could not create currency formatter for locale %s",localeID);
            continue;
        }
        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((UnicodeString)"FAIL: Status " + (int32_t)status);
        }
        delete currencyFmt;
    }
}

// -------------------------------------

/**
 * Test the Currency object handling, new as of ICU 2.2.
 */
void NumberFormatTest::TestCurrencyObject() {
    UErrorCode ec = U_ZERO_ERROR;
    NumberFormat* fmt =
        NumberFormat::createCurrencyInstance(Locale::getUS(), ec);

    if (U_FAILURE(ec)) {
        dataerrln("FAIL: getCurrencyInstance(US) - %s", u_errorName(ec));
        delete fmt;
        return;
    }

    Locale null("", "", "");

    expectCurrency(*fmt, null, 1234.56, "$1,234.56");

    expectCurrency(*fmt, Locale::getFrance(),
                   1234.56, CharsToUnicodeString("\\u20AC1,234.56")); // Euro

    expectCurrency(*fmt, Locale::getJapan(),
                   1234.56, CharsToUnicodeString("\\u00A51,235")); // Yen

    expectCurrency(*fmt, Locale("fr", "CH", ""),
                   1234.56, "CHF 1,234.56"); // no more 0.05 rounding here, see cldrbug 5548

    expectCurrency(*fmt, Locale::getUS(),
                   1234.56, "$1,234.56");

    delete fmt;
    fmt = NumberFormat::createCurrencyInstance(Locale::getFrance(), ec);

    if (U_FAILURE(ec)) {
        errln("FAIL: getCurrencyInstance(FRANCE)");
        delete fmt;
        return;
    }

    expectCurrency(*fmt, null, 1234.56, CharsToUnicodeString("1 234,56 \\u20AC"));

    expectCurrency(*fmt, Locale::getJapan(),
                   1234.56, CharsToUnicodeString("1 235 JPY")); // Yen

    expectCurrency(*fmt, Locale("fr", "CH", ""),
                   1234.56, "1 234,56 CHF"); // no more 0.05 rounding here, see cldrbug 5548

    expectCurrency(*fmt, Locale::getUS(),
                   1234.56, "1 234,56 $US");

    expectCurrency(*fmt, Locale::getFrance(),
                   1234.56, CharsToUnicodeString("1 234,56 \\u20AC")); // Euro

    delete fmt;
}

// -------------------------------------

/**
 * Do rudimentary testing of parsing.
 */
void
NumberFormatTest::TestParse(void)
{
    UErrorCode status = U_ZERO_ERROR;
    UnicodeString arg("0");
    DecimalFormat* format = new DecimalFormat("00", status);
    //try {
        Formattable n; format->parse(arg, n, status);
        logln((UnicodeString)"parse(" + arg + ") = " + n.getLong());
        if (n.getType() != Formattable::kLong ||
            n.getLong() != 0) errln((UnicodeString)"FAIL: Expected 0");
    delete format;
    if (U_FAILURE(status)) errcheckln(status, (UnicodeString)"FAIL: Status " + u_errorName(status));
    //}
    //catch(Exception e) {
    //    errln((UnicodeString)"Exception caught: " + e);
    //}
}

// -------------------------------------

static const char *lenientAffixTestCases[] = {
        "(1)",
        "( 1)",
        "(1 )",
        "( 1 )"
};

static const char *lenientMinusTestCases[] = {
    "-5",
    "\\u22125",
    "\\u27965"
};

static const char *lenientCurrencyTestCases[] = {
        "$1,000",
        "$ 1,000",
        "$1000",
        "$ 1000",
        "$1 000.00",
        "$ 1 000.00",
        "$ 1\\u00A0000.00",
        "1000.00"
};

// changed from () to - per cldrbug 5674
static const char *lenientNegativeCurrencyTestCases[] = {
        "-$1,000",
        "-$ 1,000",
        "-$1000",
        "-$ 1000",
        "-$1 000.00",
        "-$ 1 000.00",
        "- $ 1,000.00 ",
        "-$ 1\\u00A0000.00",
        "-1000.00"
};

static const char *lenientPercentTestCases[] = {
        "25%",
        " 25%",
        " 25 %",
    	"25 %",
		"25\\u00A0%",
		"25"
};

static const char *lenientNegativePercentTestCases[] = {
		"-25%",
		" -25%",
		" - 25%",
		"- 25 %",
		" - 25 %",
		"-25 %",
		"-25\\u00A0%",
		"-25",
		"- 25"
};

static const char *strictFailureTestCases[] = {
		" 1000",
		"10,00",
		"1,000,.0"
};

/**
 * Test lenient parsing.
 */
void
NumberFormatTest::TestLenientParse(void)
{
    UErrorCode status = U_ZERO_ERROR;
    DecimalFormat *format = new DecimalFormat("(#,##0)", status);
    Formattable n;

    if (format == NULL || U_FAILURE(status)) {
        dataerrln("Unable to create DecimalFormat (#,##0) - %s", u_errorName(status));
    } else {
        format->setLenient(TRUE);
        for (int32_t t = 0; t < UPRV_LENGTHOF (lenientAffixTestCases); t += 1) {
        	UnicodeString testCase = ctou(lenientAffixTestCases[t]);

            format->parse(testCase, n, status);
            logln((UnicodeString)"parse(" + testCase + ") = " + n.getLong());

            if (U_FAILURE(status) || n.getType() != Formattable::kLong ||
            	n.getLong() != 1) {
            	dataerrln((UnicodeString)"Lenient parse failed for \"" + (UnicodeString) lenientAffixTestCases[t]
                      + (UnicodeString) "\"; error code = " + u_errorName(status));
            	status = U_ZERO_ERROR;
            }
       }
       delete format;
    }

    Locale en_US("en_US");
    Locale sv_SE("sv_SE");

    NumberFormat *mFormat = NumberFormat::createInstance(sv_SE, UNUM_DECIMAL, status);

    if (mFormat == NULL || U_FAILURE(status)) {
        dataerrln("Unable to create NumberFormat (sv_SE, UNUM_DECIMAL) - %s", u_errorName(status));
    } else {
        mFormat->setLenient(TRUE);
        for (int32_t t = 0; t < UPRV_LENGTHOF(lenientMinusTestCases); t += 1) {
            UnicodeString testCase = ctou(lenientMinusTestCases[t]);

            mFormat->parse(testCase, n, status);
            logln((UnicodeString)"parse(" + testCase + ") = " + n.getLong());

            if (U_FAILURE(status) || n.getType() != Formattable::kLong || n.getLong() != -5) {
                errln((UnicodeString)"Lenient parse failed for \"" + (UnicodeString) lenientMinusTestCases[t]
                      + (UnicodeString) "\"; error code = " + u_errorName(status));
                status = U_ZERO_ERROR;
            }
        }
        delete mFormat;
    }

    mFormat = NumberFormat::createInstance(en_US, UNUM_DECIMAL, status);

    if (mFormat == NULL || U_FAILURE(status)) {
        dataerrln("Unable to create NumberFormat (en_US, UNUM_DECIMAL) - %s", u_errorName(status));
    } else {
        mFormat->setLenient(TRUE);
        for (int32_t t = 0; t < UPRV_LENGTHOF(lenientMinusTestCases); t += 1) {
            UnicodeString testCase = ctou(lenientMinusTestCases[t]);

            mFormat->parse(testCase, n, status);
            logln((UnicodeString)"parse(" + testCase + ") = " + n.getLong());

            if (U_FAILURE(status) || n.getType() != Formattable::kLong || n.getLong() != -5) {
                errln((UnicodeString)"Lenient parse failed for \"" + (UnicodeString) lenientMinusTestCases[t]
                      + (UnicodeString) "\"; error code = " + u_errorName(status));
                status = U_ZERO_ERROR;
            }
        }
        delete mFormat;
    }

    NumberFormat *cFormat = NumberFormat::createInstance(en_US, UNUM_CURRENCY, status);

    if (cFormat == NULL || U_FAILURE(status)) {
        dataerrln("Unable to create NumberFormat (en_US, UNUM_CURRENCY) - %s", u_errorName(status));
    } else {
        cFormat->setLenient(TRUE);
        for (int32_t t = 0; t < UPRV_LENGTHOF (lenientCurrencyTestCases); t += 1) {
        	UnicodeString testCase = ctou(lenientCurrencyTestCases[t]);

            cFormat->parse(testCase, n, status);
            logln((UnicodeString)"parse(" + testCase + ") = " + n.getLong());

            if (U_FAILURE(status) ||n.getType() != Formattable::kLong ||
            	n.getLong() != 1000) {
            	errln((UnicodeString)"Lenient parse failed for \"" + (UnicodeString) lenientCurrencyTestCases[t]
                      + (UnicodeString) "\"; error code = " + u_errorName(status));
            	status = U_ZERO_ERROR;
            }
        }

        for (int32_t t = 0; t < UPRV_LENGTHOF (lenientNegativeCurrencyTestCases); t += 1) {
        	UnicodeString testCase = ctou(lenientNegativeCurrencyTestCases[t]);

            cFormat->parse(testCase, n, status);
            logln((UnicodeString)"parse(" + testCase + ") = " + n.getLong());

            if (U_FAILURE(status) ||n.getType() != Formattable::kLong ||
            	n.getLong() != -1000) {
            	errln((UnicodeString)"Lenient parse failed for \"" + (UnicodeString) lenientNegativeCurrencyTestCases[t]
                      + (UnicodeString) "\"; error code = " + u_errorName(status));
            	status = U_ZERO_ERROR;
            }
        }

        delete cFormat;
    }

    NumberFormat *pFormat = NumberFormat::createPercentInstance(en_US, status);

    if (pFormat == NULL || U_FAILURE(status)) {
        dataerrln("Unable to create NumberFormat::createPercentInstance (en_US) - %s", u_errorName(status));
    } else {
        pFormat->setLenient(TRUE);
        for (int32_t t = 0; t < UPRV_LENGTHOF (lenientPercentTestCases); t += 1) {
        	UnicodeString testCase = ctou(lenientPercentTestCases[t]);

        	pFormat->parse(testCase, n, status);
            logln((UnicodeString)"parse(" + testCase + ") = " + n.getDouble());

            if (U_FAILURE(status) ||n.getType() != Formattable::kDouble ||
            	n.getDouble() != 0.25) {
            	errln((UnicodeString)"Lenient parse failed for \"" + (UnicodeString) lenientPercentTestCases[t]
                      + (UnicodeString) "\"; error code = " + u_errorName(status)
                      + "; got: " + n.getDouble(status));
            	status = U_ZERO_ERROR;
            }
        }

        for (int32_t t = 0; t < UPRV_LENGTHOF (lenientNegativePercentTestCases); t += 1) {
        	UnicodeString testCase = ctou(lenientNegativePercentTestCases[t]);

        	pFormat->parse(testCase, n, status);
            logln((UnicodeString)"parse(" + testCase + ") = " + n.getDouble());

            if (U_FAILURE(status) ||n.getType() != Formattable::kDouble ||
            	n.getDouble() != -0.25) {
            	errln((UnicodeString)"Lenient parse failed for \"" + (UnicodeString) lenientNegativePercentTestCases[t]
                      + (UnicodeString) "\"; error code = " + u_errorName(status)
                      + "; got: " + n.getDouble(status));
            	status = U_ZERO_ERROR;
            }
        }

        delete pFormat;
    }

   // Test cases that should fail with a strict parse and pass with a
   // lenient parse.
   NumberFormat *nFormat = NumberFormat::createInstance(en_US, status);

   if (nFormat == NULL || U_FAILURE(status)) {
       dataerrln("Unable to create NumberFormat (en_US) - %s", u_errorName(status));
   } else {
       // first, make sure that they fail with a strict parse
       for (int32_t t = 0; t < UPRV_LENGTHOF(strictFailureTestCases); t += 1) {
	       UnicodeString testCase = ctou(strictFailureTestCases[t]);

	       nFormat->parse(testCase, n, status);
	       logln((UnicodeString)"parse(" + testCase + ") = " + n.getLong());

	       if (! U_FAILURE(status)) {
		       errln((UnicodeString)"Strict Parse succeeded for \"" + (UnicodeString) strictFailureTestCases[t]
                     + (UnicodeString) "\"; error code = " + u_errorName(status));
	       }

	       status = U_ZERO_ERROR;
       }

       // then, make sure that they pass with a lenient parse
       nFormat->setLenient(TRUE);
       for (int32_t t = 0; t < UPRV_LENGTHOF(strictFailureTestCases); t += 1) {
	       UnicodeString testCase = ctou(strictFailureTestCases[t]);

	       nFormat->parse(testCase, n, status);
	       logln((UnicodeString)"parse(" + testCase + ") = " + n.getLong());

	       if (U_FAILURE(status) ||n.getType() != Formattable::kLong ||
	            	n.getLong() != 1000) {
		       errln((UnicodeString)"Lenient parse failed for \"" + (UnicodeString) strictFailureTestCases[t]
                     + (UnicodeString) "\"; error code = " + u_errorName(status));
		       status = U_ZERO_ERROR;
	       }
       }

       delete nFormat;
   }
}

// -------------------------------------

/**
 * 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, "#,##,##0");
    f.applyPattern("#,###", status);
    CHECK(status, "applyPattern");

    f.setSecondaryGroupingSize(4);
    expect2(f, (int32_t)123456789L, "12,3456,789");
    expectPat(f, "#,####,##0");
    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;
    if (out.length() != 14) {
        ok = FALSE;
    } else {
        for (int32_t i=0; i<out.length(); ++i) {
            UBool expectGroup = FALSE;
            switch (i) {
            case 1:
            case 4:
            case 7:
            case 10:
                expectGroup = TRUE;
                break;
            }
            // Later -- fix this to get the actual grouping
            // character from the resource bundle.
            UBool isGroup = (out.charAt(i) == 0x002C);
            if (isGroup != expectGroup) {
                ok = FALSE;
                break;
            }
        }
    }
    if (!ok) {
        errln((UnicodeString)"FAIL  Expected " + l +
              " x hi_IN -> \"1,87,65,43,210\" (with Hindi digits), got \"" +
              escape(out) + "\"");
    } else {
        logln((UnicodeString)"Ok    " + l +
              " x hi_IN -> \"" +
              escape(out) + "\"");
    }
}

void NumberFormatTest::TestWhiteSpaceParsing(void) {
    UErrorCode ec = U_ZERO_ERROR;
    DecimalFormatSymbols US(Locale::getUS(), ec);
    DecimalFormat fmt("a  b#0c  ", US, ec);
    if (U_FAILURE(ec)) {
        errcheckln(ec, "FAIL: Constructor - %s", u_errorName(ec));
        return;
    }
    // From ICU 62, flexible whitespace needs lenient mode
    fmt.setLenient(TRUE);
    int32_t n = 1234;
    expect(fmt, "a b1234c ", n);
    expect(fmt, "a   b1234c   ", n);
}

/**
 * Test currencies whose display name is a ChoiceFormat.
 */
void NumberFormatTest::TestComplexCurrency() {

//    UErrorCode ec = U_ZERO_ERROR;
//    Locale loc("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)
{
    nf.setMaximumFractionDigits(maxFractionDigits);
    UnicodeString out; nf.format(x, out);
    logln((UnicodeString)"" + x + " formats with " + maxFractionDigits + " fractional digits to " + out);
    if (!(out==expected)) errln((UnicodeString)"FAIL: Expected " + expected);
}

/**
 * Upgrade to alphaWorks
 */
void NumberFormatTest::TestExponent(void) {
    UErrorCode status = U_ZERO_ERROR;
    DecimalFormatSymbols US(Locale::getUS(), status);
    CHECK(status, "DecimalFormatSymbols constructor");
    DecimalFormat fmt1(UnicodeString("0.###E0"), US, status);
    CHECK(status, "DecimalFormat(0.###E0)");
    DecimalFormat fmt2(UnicodeString("0.###E+0"), US, status);
    CHECK(status, "DecimalFormat(0.###E+0)");
    int32_t n = 1234;
    expect2(fmt1, n, "1.234E3");
    expect2(fmt2, n, "1.234E+3");
    expect(fmt1, "1.234E+3", n); // Either format should parse "E+3"
}

/**
 * Upgrade to alphaWorks
 */
void NumberFormatTest::TestScientific(void) {
    UErrorCode status = U_ZERO_ERROR;
    DecimalFormatSymbols US(Locale::getUS(), status);
    CHECK(status, "DecimalFormatSymbols constructor");

    // Test pattern round-trip
    const char* PAT[] = { "#E0", "0.####E0", "00.000E00", "##0.####E000",
                          "0.###E0;[0.###E0]" };
    int32_t PAT_length = UPRV_LENGTHOF(PAT);
    int32_t DIGITS[] = {
        // min int, max int, min frac, max frac
        1, 1, 0, 0, // "#E0"
        1, 1, 0, 4, // "0.####E0"
        2, 2, 3, 3, // "00.000E00"
        1, 3, 0, 4, // "##0.####E000"
        1, 1, 0, 3, // "0.###E0;[0.###E0]"
    };
    for (int32_t i=0; i<PAT_length; ++i) {
        UnicodeString pat(PAT[i]);
        DecimalFormat df(pat, US, status);
        CHECK(status, "DecimalFormat constructor");
        UnicodeString pat2;
        df.toPattern(pat2);
        if (pat == pat2) {
            logln(UnicodeString("Ok   Pattern rt \"") +
                  pat + "\" -> \"" +
                  pat2 + "\"");
        } else {
            errln(UnicodeString("FAIL Pattern rt \"") +
                  pat + "\" -> \"" +
                  pat2 + "\"");
        }
        // Make sure digit counts match what we expect
        if (df.getMinimumIntegerDigits() != DIGITS[4*i] ||
            df.getMaximumIntegerDigits() != DIGITS[4*i+1] ||
            df.getMinimumFractionDigits() != DIGITS[4*i+2] ||
            df.getMaximumFractionDigits() != DIGITS[4*i+3]) {
            errln(UnicodeString("FAIL \"" + pat +
                                "\" min/max int; min/max frac = ") +
                  df.getMinimumIntegerDigits() + "/" +
                  df.getMaximumIntegerDigits() + ";" +
                  df.getMinimumFractionDigits() + "/" +
                  df.getMaximumFractionDigits() + ", expect " +
                  DIGITS[4*i] + "/" +
                  DIGITS[4*i+1] + ";" +
                  DIGITS[4*i+2] + "/" +
                  DIGITS[4*i+3]);
        }
    }


    // 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
    // scientific format.
    Locale def = Locale::getDefault();
    Locale::setDefault(Locale::getUS(), status);
    expect2(NumberFormat::createScientificInstance(status),
           12345.678901,
           "1.2345678901E4", status);
    Locale::setDefault(def, status);

    expect2(new DecimalFormat("#E0", US, status),
           12345.0,
           "1.2345E4", status);
    expect(new DecimalFormat("0E0", US, status),
           12345.0,
           "1E4", status);
    expect2(NumberFormat::createScientificInstance(Locale::getUS(), status),
           12345.678901,
           "1.2345678901E4", status);
    expect(new DecimalFormat("##0.###E0", US, status),
           12345.0,
           "12.34E3", status);
    expect(new DecimalFormat("##0.###E0", US, status),
           12345.00001,
           "12.35E3", status);
    expect2(new DecimalFormat("##0.####E0", US, status),
           (int32_t) 12345,
           "12.345E3", status);
    expect2(NumberFormat::createScientificInstance(Locale::getFrance(), status),
           12345.678901,
           "1,2345678901E4", status);
    expect(new DecimalFormat("##0.####E0", US, status),
           789.12345e-9,
           "789.12E-9", status);
    expect2(new DecimalFormat("##0.####E0", US, status),
           780.e-9,
           "780E-9", status);
    expect(new DecimalFormat(".###E0", US, status),
           45678.0,
           ".457E5", status);
    expect2(new DecimalFormat(".###E0", US, status),
           (int32_t) 0,
           ".0E0", status);
    /*
    expect(new DecimalFormat[] { new DecimalFormat("#E0", US),
                                 new DecimalFormat("##E0", US),
                                 new DecimalFormat("####E0", US),
                                 new DecimalFormat("0E0", US),
                                 new DecimalFormat("00E0", US),
                                 new DecimalFormat("000E0", US),
                               },
           new Long(45678000),
           new String[] { "4.5678E7",
                          "45.678E6",
                          "4567.8E4",
                          "5E7",
                          "46E6",
                          "457E5",
                        }
           );
    !
    ! Unroll this test into individual tests below...
    !
    */
    expect2(new DecimalFormat("#E0", US, status),
           (int32_t) 45678000, "4.5678E7", status);
    expect2(new DecimalFormat("##E0", US, status),
           (int32_t) 45678000, "45.678E6", status);
    expect2(new DecimalFormat("####E0", US, status),
           (int32_t) 45678000, "4567.8E4", status);
    expect(new DecimalFormat("0E0", US, status),
           (int32_t) 45678000, "5E7", status);
    expect(new DecimalFormat("00E0", US, status),
           (int32_t) 45678000, "46E6", status);
    expect(new DecimalFormat("000E0", US, status),
           (int32_t) 45678000, "457E5", status);
    /*
    expect(new DecimalFormat("###E0", US, status),
           new Object[] { new Double(0.0000123), "12.3E-6",
                          new Double(0.000123), "123E-6",
                          new Double(0.00123), "1.23E-3",
                          new Double(0.0123), "12.3E-3",
                          new Double(0.123), "123E-3",
                          new Double(1.23), "1.23E0",
                          new Double(12.3), "12.3E0",
                          new Double(123), "123E0",
                          new Double(1230), "1.23E3",
                         });
    !
    ! Unroll this test into individual tests below...
    !
    */
    expect2(new DecimalFormat("###E0", US, status),
           0.0000123, "12.3E-6", status);
    expect2(new DecimalFormat("###E0", US, status),
           0.000123, "123E-6", status);
    expect2(new DecimalFormat("###E0", US, status),
           0.00123, "1.23E-3", status);
    expect2(new DecimalFormat("###E0", US, status),
           0.0123, "12.3E-3", status);
    expect2(new DecimalFormat("###E0", US, status),
           0.123, "123E-3", status);
    expect2(new DecimalFormat("###E0", US, status),
           1.23, "1.23E0", status);
    expect2(new DecimalFormat("###E0", US, status),
           12.3, "12.3E0", status);
    expect2(new DecimalFormat("###E0", US, status),
           123.0, "123E0", status);
    expect2(new DecimalFormat("###E0", US, status),
           1230.0, "1.23E3", status);
    /*
    expect(new DecimalFormat("0.#E+00", US, status),
           new Object[] { new Double(0.00012), "1.2E-04",
                          new Long(12000),     "1.2E+04",
                         });
    !
    ! Unroll this test into individual tests below...
    !
    */
    expect2(new DecimalFormat("0.#E+00", US, status),
           0.00012, "1.2E-04", status);
    expect2(new DecimalFormat("0.#E+00", US, status),
           (int32_t) 12000, "1.2E+04", status);
}

/**
 * Upgrade to alphaWorks
 */
void NumberFormatTest::TestPad(void) {
    UErrorCode status = U_ZERO_ERROR;
    DecimalFormatSymbols US(Locale::getUS(), status);
    CHECK(status, "DecimalFormatSymbols constructor");

    expect2(new DecimalFormat("*^##.##", US, status),
           int32_t(0), "^^^^0", status);
    expect2(new DecimalFormat("*^##.##", US, status),
           -1.3, "^-1.3", status);
    expect2(new DecimalFormat("##0.0####E0*_ 'g-m/s^2'", US, status),
           int32_t(0), "0.0E0______ g-m/s^2", status);
    expect(new DecimalFormat("##0.0####E0*_ 'g-m/s^2'", US, status),
           1.0/3, "333.333E-3_ g-m/s^2", status);
    expect2(new DecimalFormat("##0.0####*_ 'g-m/s^2'", US, status),
           int32_t(0), "0.0______ g-m/s^2", status);
    expect(new DecimalFormat("##0.0####*_ 'g-m/s^2'", US, status),
           1.0/3, "0.33333__ g-m/s^2", status);

    // Test padding before a sign
    const char *formatStr = "*x#,###,###,##0.0#;*x(###,###,##0.0#)";
    expect2(new DecimalFormat(formatStr, US, status),
           int32_t(-10),  "xxxxxxxxxx(10.0)", status);
    expect2(new DecimalFormat(formatStr, US, status),
           int32_t(-1000),"xxxxxxx(1,000.0)", status);
    expect2(new DecimalFormat(formatStr, US, status),
           int32_t(-1000000),"xxx(1,000,000.0)", status);
    expect2(new DecimalFormat(formatStr, US, status),
           -100.37,       "xxxxxxxx(100.37)", status);
    expect2(new DecimalFormat(formatStr, US, status),
           -10456.37,     "xxxxx(10,456.37)", status);
    expect2(new DecimalFormat(formatStr, US, status),
           -1120456.37,   "xx(1,120,456.37)", status);
    expect2(new DecimalFormat(formatStr, US, status),
           -112045600.37, "(112,045,600.37)", status);
    expect2(new DecimalFormat(formatStr, US, status),
           -1252045600.37,"(1,252,045,600.37)", status);

    expect2(new DecimalFormat(formatStr, US, status),
           int32_t(10),  "xxxxxxxxxxxx10.0", status);
    expect2(new DecimalFormat(formatStr, US, status),
           int32_t(1000),"xxxxxxxxx1,000.0", status);
    expect2(new DecimalFormat(formatStr, US, status),
           int32_t(1000000),"xxxxx1,000,000.0", status);
    expect2(new DecimalFormat(formatStr, US, status),
           100.37,       "xxxxxxxxxx100.37", status);
    expect2(new DecimalFormat(formatStr, US, status),
           10456.37,     "xxxxxxx10,456.37", status);
    expect2(new DecimalFormat(formatStr, US, status),
           1120456.37,   "xxxx1,120,456.37", status);
    expect2(new DecimalFormat(formatStr, US, status),
           112045600.37, "xx112,045,600.37", status);
    expect2(new DecimalFormat(formatStr, US, status),
           10252045600.37,"10,252,045,600.37", status);


    // Test padding between a sign and a number
    const char *formatStr2 = "#,###,###,##0.0#*x;(###,###,##0.0#*x)";
    expect2(new DecimalFormat(formatStr2, US, status),
           int32_t(-10),  "(10.0xxxxxxxxxx)", status);
    expect2(new DecimalFormat(formatStr2, US, status),
           int32_t(-1000),"(1,000.0xxxxxxx)", status);
    expect2(new DecimalFormat(formatStr2, US, status),
           int32_t(-1000000),"(1,000,000.0xxx)", status);
    expect2(new DecimalFormat(formatStr2, US, status),
           -100.37,       "(100.37xxxxxxxx)", status);
    expect2(new DecimalFormat(formatStr2, US, status),
           -10456.37,     "(10,456.37xxxxx)", status);
    expect2(new DecimalFormat(formatStr2, US, status),
           -1120456.37,   "(1,120,456.37xx)", status);
    expect2(new DecimalFormat(formatStr2, US, status),
           -112045600.37, "(112,045,600.37)", status);
    expect2(new DecimalFormat(formatStr2, US, status),
           -1252045600.37,"(1,252,045,600.37)", status);

    expect2(new DecimalFormat(formatStr2, US, status),
           int32_t(10),  "10.0xxxxxxxxxxxx", status);
    expect2(new DecimalFormat(formatStr2, US, status),
           int32_t(1000),"1,000.0xxxxxxxxx", status);
    expect2(new DecimalFormat(formatStr2, US, status),
           int32_t(1000000),"1,000,000.0xxxxx", status);
    expect2(new DecimalFormat(formatStr2, US, status),
           100.37,       "100.37xxxxxxxxxx", status);
    expect2(new DecimalFormat(formatStr2, US, status),
           10456.37,     "10,456.37xxxxxxx", status);
    expect2(new DecimalFormat(formatStr2, US, status),
           1120456.37,   "1,120,456.37xxxx", status);
    expect2(new DecimalFormat(formatStr2, US, status),
           112045600.37, "112,045,600.37xx", status);
    expect2(new DecimalFormat(formatStr2, US, status),
           10252045600.37,"10,252,045,600.37", status);

    //testing the setPadCharacter(UnicodeString) and getPadCharacterString()
    DecimalFormat fmt("#", US, status);
    CHECK(status, "DecimalFormat constructor");
    UnicodeString padString("P");
    fmt.setPadCharacter(padString);
    expectPad(fmt, "*P##.##", DecimalFormat::kPadBeforePrefix, 5, padString);
    fmt.setPadCharacter((UnicodeString)"^");
    expectPad(fmt, "*^#", DecimalFormat::kPadBeforePrefix, 1, (UnicodeString)"^");
    //commented untill implementation is complete
  /*  fmt.setPadCharacter((UnicodeString)"^^^");
    expectPad(fmt, "*^^^#", DecimalFormat::kPadBeforePrefix, 3, (UnicodeString)"^^^");
    padString.remove();
    padString.append((UChar)0x0061);
    padString.append((UChar)0x0302);
    fmt.setPadCharacter(padString);
    UChar patternChars[]={0x002a, 0x0061, 0x0302, 0x0061, 0x0302, 0x0023, 0x0000};
    UnicodeString pattern(patternChars);
    expectPad(fmt, pattern , DecimalFormat::kPadBeforePrefix, 4, padString);
 */

}

/**
 * Upgrade to alphaWorks
 */
void NumberFormatTest::TestPatterns2(void) {
    UErrorCode status = U_ZERO_ERROR;
    DecimalFormatSymbols US(Locale::getUS(), status);
    CHECK(status, "DecimalFormatSymbols constructor");

    DecimalFormat fmt("#", US, status);
    CHECK(status, "DecimalFormat constructor");

    UChar hat = 0x005E; /*^*/

    expectPad(fmt, "*^#", DecimalFormat::kPadBeforePrefix, 1, hat);
    expectPad(fmt, "$*^#", DecimalFormat::kPadAfterPrefix, 2, hat);
    expectPad(fmt, "#*^", DecimalFormat::kPadBeforeSuffix, 1, hat);
    expectPad(fmt, "#$*^", DecimalFormat::kPadAfterSuffix, 2, hat);
    expectPad(fmt, "$*^$#", ILLEGAL);
    expectPad(fmt, "#$*^$", ILLEGAL);
    expectPad(fmt, "'pre'#,##0*x'post'", DecimalFormat::kPadBeforeSuffix,
              12, (UChar)0x0078 /*x*/);
    expectPad(fmt, "''#0*x", DecimalFormat::kPadBeforeSuffix,
              3, (UChar)0x0078 /*x*/);
    expectPad(fmt, "'I''ll'*a###.##", DecimalFormat::kPadAfterPrefix,
              10, (UChar)0x0061 /*a*/);

    fmt.applyPattern("AA#,##0.00ZZ", status);
    CHECK(status, "applyPattern");
    fmt.setPadCharacter(hat);

    fmt.setFormatWidth(10);

    fmt.setPadPosition(DecimalFormat::kPadBeforePrefix);
    expectPat(fmt, "*^AA#,##0.00ZZ");

    fmt.setPadPosition(DecimalFormat::kPadBeforeSuffix);
    expectPat(fmt, "AA#,##0.00*^ZZ");

    fmt.setPadPosition(DecimalFormat::kPadAfterSuffix);
    expectPat(fmt, "AA#,##0.00ZZ*^");

    //            12  3456789012
    UnicodeString exp("AA*^#,##0.00ZZ", "");
    fmt.setFormatWidth(12);
    fmt.setPadPosition(DecimalFormat::kPadAfterPrefix);
    expectPat(fmt, exp);

    fmt.setFormatWidth(13);
    //              12  34567890123
    expectPat(fmt, "AA*^##,##0.00ZZ");

    fmt.setFormatWidth(14);
    //              12  345678901234
    expectPat(fmt, "AA*^###,##0.00ZZ");

    fmt.setFormatWidth(15);
    //              12  3456789012345
    expectPat(fmt, "AA*^####,##0.00ZZ"); // This is the interesting case

    fmt.setFormatWidth(16);
    //              12  34567890123456
    expectPat(fmt, "AA*^#####,##0.00ZZ");
}

void NumberFormatTest::TestSurrogateSupport(void) {
    UErrorCode status = U_ZERO_ERROR;
    DecimalFormatSymbols custom(Locale::getUS(), status);
    CHECK(status, "DecimalFormatSymbols constructor");

    custom.setSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol, "decimal");
    custom.setSymbol(DecimalFormatSymbols::kPlusSignSymbol, "plus");
    custom.setSymbol(DecimalFormatSymbols::kMinusSignSymbol, " minus ");
    custom.setSymbol(DecimalFormatSymbols::kExponentialSymbol, "exponent");

    UnicodeString patternStr("*\\U00010000##.##", "");
    patternStr = patternStr.unescape();
    UnicodeString expStr("\\U00010000\\U00010000\\U00010000\\U000100000", "");
    expStr = expStr.unescape();
    expect2(new DecimalFormat(patternStr, custom, status),
           int32_t(0), expStr, status);

    status = U_ZERO_ERROR;
    expect2(new DecimalFormat("*^##.##", custom, status),
           int32_t(0), "^^^^0", status);
    status = U_ZERO_ERROR;
    expect2(new DecimalFormat("##.##", custom, status),
           -1.3, " minus 1decimal3", status);
    status = U_ZERO_ERROR;
    expect2(new DecimalFormat("##0.0####E0 'g-m/s^2'", custom, status),
           int32_t(0), "0decimal0exponent0 g-m/s^2", status);
    status = U_ZERO_ERROR;
    expect(new DecimalFormat("##0.0####E0 'g-m/s^2'", custom, status),
           1.0/3, "333decimal333exponent minus 3 g-m/s^2", status);
    status = U_ZERO_ERROR;
    expect2(new DecimalFormat("##0.0#### 'g-m/s^2'", custom, status),
           int32_t(0), "0decimal0 g-m/s^2", status);
    status = U_ZERO_ERROR;
    expect(new DecimalFormat("##0.0#### 'g-m/s^2'", custom, status),
           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;
    expect2(new DecimalFormat("##0.000", custom, status),
           1.25, expStr, status);

    custom.setSymbol(DecimalFormatSymbols::kZeroDigitSymbol, (UChar)0x30);
    custom.setSymbol(DecimalFormatSymbols::kCurrencySymbol, "units of money");
    custom.setSymbol(DecimalFormatSymbols::kMonetarySeparatorSymbol, "money separator");
    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;
    expect2(new DecimalFormat(patternStr, custom, status),
           int32_t(-20), expStr, status);

    custom.setSymbol(DecimalFormatSymbols::kPercentSymbol, "percent");
    patternStr = "'You''ve lost ' -0.00 %' of your money today'";
    patternStr = patternStr.unescape();
    expStr = UnicodeString(" minus You've lost   minus 2000decimal00 percent of your money today", "");
    status = U_ZERO_ERROR;
    expect2(new DecimalFormat(patternStr, custom, status),
           int32_t(-20), expStr, status);
}

void NumberFormatTest::TestCurrencyPatterns(void) {
    int32_t i, locCount;
    const Locale* locs = NumberFormat::getAvailableLocales(locCount);
    for (i=0; i<locCount; ++i) {
        UErrorCode ec = U_ZERO_ERROR;
        NumberFormat* nf = NumberFormat::createCurrencyInstance(locs[i], ec);
        if (U_FAILURE(ec)) {
            errln("FAIL: Can't create NumberFormat(%s) - %s", locs[i].getName(), u_errorName(ec));
        } else {
            // Make sure currency formats do not have a variable number
            // of fraction digits
            int32_t min = nf->getMinimumFractionDigits();
            int32_t max = nf->getMaximumFractionDigits();
            if (min != max) {
                UnicodeString a, b;
                nf->format(1.0, a);
                nf->format(1.125, b);
                errln((UnicodeString)"FAIL: " + locs[i].getName() +
                      " min fraction digits != max fraction digits; "
                      "x 1.0 => " + escape(a) +
                      "; x 1.125 => " + escape(b));
            }

            // Make sure EURO currency formats have exactly 2 fraction digits
            DecimalFormat* df = dynamic_cast<DecimalFormat*>(nf);
            if (df != NULL) {
                if (u_strcmp(EUR, df->getCurrency()) == 0) {
                    if (min != 2 || max != 2) {
                        UnicodeString a;
                        nf->format(1.0, a);
                        errln((UnicodeString)"FAIL: " + locs[i].getName() +
                              " is a EURO format but it does not have 2 fraction digits; "
                              "x 1.0 => " +
                              escape(a));
                    }
                }
            }
        }
        delete nf;
    }
}

void NumberFormatTest::TestRegCurrency(void) {
#if !UCONFIG_NO_SERVICE
    UErrorCode status = U_ZERO_ERROR;
    UChar USD[4];
    ucurr_forLocale("en_US", USD, 4, &status);
    UChar YEN[4];
    ucurr_forLocale("ja_JP", YEN, 4, &status);
    UChar TMP[4];
    static const UChar QQQ[] = {0x51, 0x51, 0x51, 0};
    if(U_FAILURE(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");
    }

    ucurr_forLocale("en_US_EURO", TMP, 4, &status);
    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);
    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");
    }
    status = U_ZERO_ERROR; // reset
#endif
}

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[] = {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, en)",
                 UnicodeString("$"),
                 UnicodeString(ucurr_getName(USD, "en",
                                             UCURR_SYMBOL_NAME,
                                             &isChoiceFormat, &len, &ec)),
                                             possibleDataError);
    assertEquals("USD.getName(NARROW_SYMBOL_NAME, en)",
                 UnicodeString("$"),
                 UnicodeString(ucurr_getName(USD, "en",
                                             UCURR_NARROW_SYMBOL_NAME,
                                             &isChoiceFormat, &len, &ec)),
                                             possibleDataError);
    assertEquals("USD.getName(LONG_NAME, en)",
                 UnicodeString("US Dollar"),
                 UnicodeString(ucurr_getName(USD, "en",
                                             UCURR_LONG_NAME,
                                             &isChoiceFormat, &len, &ec)),
                                             possibleDataError);
    assertEquals("CAD.getName(SYMBOL_NAME, en)",
                 UnicodeString("CA$"),
                 UnicodeString(ucurr_getName(CAD, "en",
                                             UCURR_SYMBOL_NAME,
                                             &isChoiceFormat, &len, &ec)),
                                             possibleDataError);
    assertEquals("CAD.getName(NARROW_SYMBOL_NAME, en)",
                 UnicodeString("$"),
                 UnicodeString(ucurr_getName(CAD, "en",
                                             UCURR_NARROW_SYMBOL_NAME,
                                             &isChoiceFormat, &len, &ec)),
                                             possibleDataError);
    assertEquals("CAD.getName(SYMBOL_NAME, en_CA)",
                 UnicodeString("$"),
                 UnicodeString(ucurr_getName(CAD, "en_CA",
                                             UCURR_SYMBOL_NAME,
                                             &isChoiceFormat, &len, &ec)),
                                             possibleDataError);
    assertEquals("USD.getName(SYMBOL_NAME, en_CA)",
                 UnicodeString("US$"),
                 UnicodeString(ucurr_getName(USD, "en_CA",
                                             UCURR_SYMBOL_NAME,
                                             &isChoiceFormat, &len, &ec)),
                                             possibleDataError);
    assertEquals("USD.getName(NARROW_SYMBOL_NAME, en_CA)",
                 UnicodeString("$"),
                 UnicodeString(ucurr_getName(USD, "en_CA",
                                             UCURR_NARROW_SYMBOL_NAME,
                                             &isChoiceFormat, &len, &ec)),
                                             possibleDataError);
    assertEquals("USD.getName(SYMBOL_NAME) in en_NZ",
                 UnicodeString("US$"),
                 UnicodeString(ucurr_getName(USD, "en_NZ",
                                             UCURR_SYMBOL_NAME,
                                             &isChoiceFormat, &len, &ec)),
                                             possibleDataError);
    assertEquals("CAD.getName(SYMBOL_NAME)",
                 UnicodeString("CA$"),
                 UnicodeString(ucurr_getName(CAD, "en_NZ",
                                             UCURR_SYMBOL_NAME,
                                             &isChoiceFormat, &len, &ec)),
                                             possibleDataError);
    assertEquals("USX.getName(SYMBOL_NAME)",
                 UnicodeString("USX"),
                 UnicodeString(ucurr_getName(USX, "en_US",
                                             UCURR_SYMBOL_NAME,
                                             &isChoiceFormat, &len, &ec)),
                                             possibleDataError);
    assertEquals("USX.getName(NARROW_SYMBOL_NAME)",
                 UnicodeString("USX"),
                 UnicodeString(ucurr_getName(USX, "en_US",
                                             UCURR_NARROW_SYMBOL_NAME,
                                             &isChoiceFormat, &len, &ec)),
                                             possibleDataError);
    assertEquals("USX.getName(LONG_NAME)",
                 UnicodeString("USX"),
                 UnicodeString(ucurr_getName(USX, "en_US",
                                             UCURR_LONG_NAME,
                                             &isChoiceFormat, &len, &ec)),
                                             possibleDataError);
    assertSuccess("ucurr_getName", ec);

    ec = U_ZERO_ERROR;

    // Test that a default or fallback warning is being returned. JB 4239.
    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::TestCurrencyUnit(void){
    UErrorCode ec = U_ZERO_ERROR;
    static const UChar USD[]  = u"USD";
    static const char USD8[]  =  "USD";
    static const UChar BAD[]  = u"???";
    static const UChar BAD2[] = u"??A";
    static const UChar XXX[]  = u"XXX";
    static const char XXX8[]  =  "XXX";
    CurrencyUnit cu(USD, ec);
    assertSuccess("CurrencyUnit", ec);

    assertEquals("getISOCurrency()", USD, cu.getISOCurrency());
    assertEquals("getSubtype()", USD8, cu.getSubtype());

    CurrencyUnit cu2(cu);
    if (!(cu2 == cu)){
        errln("CurrencyUnit copy constructed object should be same");
    }

    CurrencyUnit * cu3 = (CurrencyUnit *)cu.clone();
    if (!(*cu3 == cu)){
        errln("CurrencyUnit cloned object should be same");
    }
    CurrencyUnit bad(BAD, ec);
    assertSuccess("CurrencyUnit", ec);
    if (cu.getIndex() == bad.getIndex()) {
        errln("Indexes of different currencies should differ.");
    }
    CurrencyUnit bad2(BAD2, ec);
    assertSuccess("CurrencyUnit", ec);
    if (bad2.getIndex() != bad.getIndex()) {
        errln("Indexes of unrecognized currencies should be the same.");
    }
    if (bad == bad2) {
        errln("Different unrecognized currencies should not be equal.");
    }
    bad = bad2;
    if (bad != bad2) {
        errln("Currency unit assignment should be the same.");
    }
    delete cu3;

    // Test default constructor
    CurrencyUnit def;
    assertEquals("Default currency", XXX, def.getISOCurrency());
    assertEquals("Default currency as subtype", XXX8, def.getSubtype());

    // Test slicing
    MeasureUnit sliced1 = cu;
    MeasureUnit sliced2 = cu;
    assertEquals("Subtype after slicing 1", USD8, sliced1.getSubtype());
    assertEquals("Subtype after slicing 2", USD8, sliced2.getSubtype());
    CurrencyUnit restored1(sliced1, ec);
    CurrencyUnit restored2(sliced2, ec);
    assertSuccess("Restoring from MeasureUnit", ec);
    assertEquals("Subtype after restoring 1", USD8, restored1.getSubtype());
    assertEquals("Subtype after restoring 2", USD8, restored2.getSubtype());
    assertEquals("ISO Code after restoring 1", USD, restored1.getISOCurrency());
    assertEquals("ISO Code after restoring 2", USD, restored2.getISOCurrency());

    // Test copy constructor failure
    LocalPointer<MeasureUnit> meter(MeasureUnit::createMeter(ec));
    assertSuccess("Creating meter", ec);
    CurrencyUnit failure(*meter, ec);
    assertEquals("Copying from meter should fail", ec, U_ILLEGAL_ARGUMENT_ERROR);
    assertEquals("Copying should not give uninitialized ISO code", u"", failure.getISOCurrency());
}

void NumberFormatTest::TestCurrencyAmount(void){
    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);
        TEST_ASSERT_TRUE(!locBad.isBogus());
        UErrorCode status = U_ZERO_ERROR;
        UnicodeString intlCurrencySymbol((UChar)0xa4);

        intlCurrencySymbol.append((UChar)0xa4);

        logln("Current locale is %s", Locale::getDefault().getName());
        Locale::setDefault(locBad, status);
        logln("Current locale is %s", Locale::getDefault().getName());
        DecimalFormatSymbols mySymbols(status);
        if (status != U_USING_DEFAULT_WARNING) {
            errln("DecimalFormatSymbols should return U_USING_DEFAULT_WARNING.");
        }
        if (strcmp(mySymbols.getLocale().getName(), locBad.getName()) != 0) {
            errln("DecimalFormatSymbols does not have the right locale.", locBad.getName());
        }
        int symbolEnum = (int)DecimalFormatSymbols::kDecimalSeparatorSymbol;
        for (; symbolEnum < (int)DecimalFormatSymbols::kFormatSymbolCount; symbolEnum++) {
            UnicodeString symbolString = mySymbols.getSymbol((DecimalFormatSymbols::ENumberFormatSymbol)symbolEnum);
            logln(UnicodeString("DecimalFormatSymbols[") + symbolEnum + UnicodeString("] = ") + prettify(symbolString));
            if (symbolString.length() == 0
                && symbolEnum != (int)DecimalFormatSymbols::kGroupingSeparatorSymbol
                && symbolEnum != (int)DecimalFormatSymbols::kMonetaryGroupingSeparatorSymbol)
            {
                errln("DecimalFormatSymbols has an empty string at index %d.", symbolEnum);
            }
        }

        status = U_ZERO_ERROR;
        Locale::setDefault(locDefault, status);
        logln("Current locale is %s", Locale::getDefault().getName());
    }
}

/**
 * Check that adoptDecimalFormatSymbols and setDecimalFormatSymbols
 * behave the same, except for memory ownership semantics. (No
 * version of this test on Java, since Java has only one method.)
 */
void NumberFormatTest::TestAdoptDecimalFormatSymbols(void) {
    UErrorCode ec = U_ZERO_ERROR;
    DecimalFormatSymbols *sym = new DecimalFormatSymbols(Locale::getUS(), ec);
    if (U_FAILURE(ec)) {
        errcheckln(ec, "Fail: DecimalFormatSymbols constructor - %s", u_errorName(ec));
        delete sym;
        return;
    }
    UnicodeString pat(" #,##0.00");
    pat.insert(0, (UChar)0x00A4);
    DecimalFormat fmt(pat, sym, ec);
    if (U_FAILURE(ec)) {
        errln("Fail: DecimalFormat constructor");
        return;
    }

    UnicodeString str;
    fmt.format(2350.75, str);
    if (str == "$ 2,350.75") {
        logln(str);
    } else {
        dataerrln("Fail: " + str + ", expected $ 2,350.75");
    }

    sym = new DecimalFormatSymbols(Locale::getUS(), ec);
    if (U_FAILURE(ec)) {
        errln("Fail: DecimalFormatSymbols constructor");
        delete sym;
        return;
    }
    sym->setSymbol(DecimalFormatSymbols::kCurrencySymbol, "Q");
    fmt.adoptDecimalFormatSymbols(sym);

    str.truncate(0);
    fmt.format(2350.75, str);
    if (str == "Q 2,350.75") {
        logln(str);
    } else {
        dataerrln("Fail: adoptDecimalFormatSymbols -> " + str + ", expected Q 2,350.75");
    }

    sym = new DecimalFormatSymbols(Locale::getUS(), ec);
    if (U_FAILURE(ec)) {
        errln("Fail: DecimalFormatSymbols constructor");
        delete sym;
        return;
    }
    DecimalFormat fmt2(pat, sym, ec);
    if (U_FAILURE(ec)) {
        errln("Fail: DecimalFormat constructor");
        return;
    }

    DecimalFormatSymbols sym2(Locale::getUS(), ec);
    if (U_FAILURE(ec)) {
        errln("Fail: DecimalFormatSymbols constructor");
        return;
    }
    sym2.setSymbol(DecimalFormatSymbols::kCurrencySymbol, "Q");
    fmt2.setDecimalFormatSymbols(sym2);

    str.truncate(0);
    fmt2.format(2350.75, str);
    if (str == "Q 2,350.75") {
        logln(str);
    } else {
        dataerrln("Fail: setDecimalFormatSymbols -> " + str + ", expected Q 2,350.75");
    }
}

void NumberFormatTest::TestPerMill() {
    UErrorCode ec = U_ZERO_ERROR;
    UnicodeString str;
    DecimalFormat fmt(ctou("###.###\\u2030"), ec);
    if (!assertSuccess("DecimalFormat ct", ec)) return;
    assertEquals("0.4857 x ###.###\\u2030",
                 ctou("485.7\\u2030"), fmt.format(0.4857, str), true);

    DecimalFormatSymbols sym(Locale::getUS(), ec);
    if (!assertSuccess("", ec, true, __FILE__, __LINE__)) {
        return;
    }
    sym.setSymbol(DecimalFormatSymbols::kPerMillSymbol, ctou("m"));
    DecimalFormat fmt2("", sym, ec);
    if (!assertSuccess("", ec, true, __FILE__, __LINE__)) {
        return;
    }
    fmt2.applyLocalizedPattern("###.###m", ec);
    if (!assertSuccess("setup", ec)) return;
    str.truncate(0);
    assertEquals("0.4857 x ###.###m",
                 "485.7m", fmt2.format(0.4857, str));
}

/**
 * Generic test for patterns that should be legal/illegal.
 */
void NumberFormatTest::TestIllegalPatterns() {
    // Test cases:
    // Prefix with "-:" for illegal patterns
    // Prefix with "+:" for legal patterns
    const char* DATA[] = {
        // Unquoted special characters in the suffix are illegal
        "-:000.000|###",
        "+:000.000'|###'",
        0
    };
    for (int32_t i=0; DATA[i]; ++i) {
        const char* pat=DATA[i];
        UBool valid = (*pat) == '+';
        pat += 2;
        UErrorCode ec = U_ZERO_ERROR;
        DecimalFormat fmt(pat, ec); // locale doesn't matter here
        if (U_SUCCESS(ec) == valid) {
            logln("Ok: pattern \"%s\": %s",
                  pat, u_errorName(ec));
        } else {
            errcheckln(ec, "FAIL: pattern \"%s\" should have %s; got %s",
                  pat, (valid?"succeeded":"failed"),
                  u_errorName(ec));
        }
    }
}

//----------------------------------------------------------------------

static const char* KEYWORDS[] = {
    /*0*/ "ref=", // <reference pattern to parse numbers>
    /*1*/ "loc=", // <locale for formats>
    /*2*/ "f:",   // <pattern or '-'> <number> <exp. string>
    /*3*/ "fp:",  // <pattern or '-'> <number> <exp. string> <exp. number>
    /*4*/ "rt:",  // <pattern or '-'> <(exp.) number> <(exp.) string>
    /*5*/ "p:",   // <pattern or '-'> <string> <exp. number>
    /*6*/ "perr:", // <pattern or '-'> <invalid string>
    /*7*/ "pat:", // <pattern or '-'> <exp. toPattern or '-' or 'err'>
    /*8*/ "fpc:", // <pattern or '-'> <curr.amt> <exp. string> <exp. curr.amt>
    0
};

/**
 * Return an integer representing the next token from this
 * iterator.  The integer will be an index into the given list, or
 * -1 if there are no more tokens, or -2 if the token is not on
 * the list.
 */
static int32_t keywordIndex(const UnicodeString& tok) {
    for (int32_t i=0; KEYWORDS[i]!=0; ++i) {
        if (tok==KEYWORDS[i]) {
            return i;
        }
    }
    return -1;
}

/**
 * Parse a CurrencyAmount using the given NumberFormat, with
 * the 'delim' character separating the number and the currency.
 */
static void parseCurrencyAmount(const UnicodeString& str,
                                const NumberFormat& fmt,
                                UChar delim,
                                Formattable& result,
                                UErrorCode& ec) {
    UnicodeString num, cur;
    int32_t i = str.indexOf(delim);
    str.extractBetween(0, i, num);
    str.extractBetween(i+1, INT32_MAX, cur);
    Formattable n;
    fmt.parse(num, n, ec);
    result.adoptObject(new CurrencyAmount(n, cur.getTerminatedBuffer(), ec));
}

void NumberFormatTest::TestCases() {
    UErrorCode ec = U_ZERO_ERROR;
    TextFile reader("NumberFormatTestCases.txt", "UTF8", ec);
    if (U_FAILURE(ec)) {
        dataerrln("Couldn't open NumberFormatTestCases.txt");
        return;
    }
    TokenIterator tokens(&reader);

    Locale loc("en", "US", "");
    DecimalFormat *ref = 0, *fmt = 0;
    MeasureFormat *mfmt = 0;
    UnicodeString pat, tok, mloc, str, out, where, currAmt;
    Formattable n;

    for (;;) {
        ec = U_ZERO_ERROR;
        if (!tokens.next(tok, ec)) {
            break;
        }
        where = UnicodeString("(") + tokens.getLineNumber() + ") ";
        int32_t cmd = keywordIndex(tok);
        switch (cmd) {
        case 0:
            // ref= <reference pattern>
            if (!tokens.next(tok, ec)) goto error;
            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= <locale>
            if (!tokens.next(tok, ec)) goto error;
            loc = Locale::createFromName(CharString().appendInvariantChars(tok, ec).data());
            break;
        case 2: // f:
        case 3: // fp:
        case 4: // rt:
        case 5: // p:
            if (!tokens.next(tok, ec)) goto error;
            if (tok != "-") {
                pat = tok;
                delete fmt;
                fmt = new DecimalFormat(pat, new DecimalFormatSymbols(loc, ec), ec);
                if (U_FAILURE(ec)) {
                    errln("FAIL: " + where + "Pattern \"" + pat + "\": " + u_errorName(ec));
                    ec = U_ZERO_ERROR;
                    if (!tokens.next(tok, ec)) goto error;
                    if (!tokens.next(tok, ec)) goto error;
                    if (cmd == 3) {
                        if (!tokens.next(tok, ec)) goto error;
                    }
                    continue;
                }
            }
            if (cmd == 2 || cmd == 3 || cmd == 4) {
                // f: <pattern or '-'> <number> <exp. string>
                // fp: <pattern or '-'> <number> <exp. string> <exp. number>
                // rt: <pattern or '-'> <number> <string>
                UnicodeString num;
                if (!tokens.next(num, ec)) goto error;
                if (!tokens.next(str, ec)) goto error;
                ref->parse(num, n, ec);
                assertSuccess("parse", ec);
                assertEquals(where + "\"" + pat + "\".format(" + num + ")",
                             str, fmt->format(n, out.remove(), ec));
                assertSuccess("format", ec);
                if (cmd == 3) { // fp:
                    if (!tokens.next(num, ec)) goto error;
                    ref->parse(num, n, ec);
                    assertSuccess("parse", ec);
                }
                if (cmd != 2) { // != f:
                    Formattable m;
                    fmt->parse(str, m, ec);
                    assertSuccess("parse", ec);
                    assertEquals(where + "\"" + pat + "\".parse(\"" + str + "\")",
                                 n, m);
                }
            }
            // p: <pattern or '-'> <string to parse> <exp. number>
            else {
                UnicodeString expstr;
                if (!tokens.next(str, ec)) goto error;
                if (!tokens.next(expstr, ec)) goto error;
                Formattable exp, n;
                ref->parse(expstr, exp, ec);
                assertSuccess("parse", ec);
                fmt->parse(str, n, ec);
                assertSuccess("parse", ec);
                assertEquals(where + "\"" + pat + "\".parse(\"" + str + "\")",
                             exp, n);
            }
            break;
        case 8: // fpc:
            if (!tokens.next(tok, ec)) goto error;
            if (tok != "-") {
                mloc = tok;
                delete mfmt;
                mfmt = MeasureFormat::createCurrencyFormat(
                    Locale::createFromName(
                        CharString().appendInvariantChars(mloc, ec).data()), ec);
                if (U_FAILURE(ec)) {
                    errln("FAIL: " + where + "Loc \"" + mloc + "\": " + u_errorName(ec));
                    ec = U_ZERO_ERROR;
                    if (!tokens.next(tok, ec)) goto error;
                    if (!tokens.next(tok, ec)) goto error;
                    if (!tokens.next(tok, ec)) goto error;
                    continue;
                }
            } else if (mfmt == NULL) {
                errln("FAIL: " + where + "Loc \"" + mloc + "\": skip case using previous locale, no valid MeasureFormat");
                if (!tokens.next(tok, ec)) goto error;
                if (!tokens.next(tok, ec)) goto error;
                if (!tokens.next(tok, ec)) goto error;
                continue;
            }
            // fpc: <loc or '-'> <curr.amt> <exp. string> <exp. curr.amt>
            if (!tokens.next(currAmt, ec)) goto error;
            if (!tokens.next(str, ec)) goto error;
            parseCurrencyAmount(currAmt, *ref, (UChar)0x2F/*'/'*/, n, ec);
            if (assertSuccess("parseCurrencyAmount", ec)) {
                assertEquals(where + "getCurrencyFormat(" + mloc + ").format(" + currAmt + ")",
                             str, mfmt->format(n, out.remove(), ec));
                assertSuccess("format", ec);
            }
            if (!tokens.next(currAmt, ec)) goto error;
            parseCurrencyAmount(currAmt, *ref, (UChar)0x2F/*'/'*/, n, ec);
            if (assertSuccess("parseCurrencyAmount", ec)) {
                Formattable m;

                mfmt->parseObject(str, m, ec);
                if (assertSuccess("parseCurrency", ec)) {
                    assertEquals(where + "getCurrencyFormat(" + mloc + ").parse(\"" + str + "\")",
                                 n, m);
                } else {
                    errln("FAIL: source " + str);
                }
            }
            break;
        case 6:
            // perr: <pattern or '-'> <invalid string>
            errln("FAIL: Under construction");
            goto done;
        case 7: {
            // pat: <pattern> <exp. toPattern, or '-' or 'err'>
            UnicodeString testpat;
            UnicodeString exppat;
            if (!tokens.next(testpat, ec)) goto error;
            if (!tokens.next(exppat, ec)) goto error;
            UBool err = exppat == "err";
            UBool existingPat = FALSE;
            if (testpat == "-") {
                if (err) {
                    errln("FAIL: " + where + "Invalid command \"pat: - err\"");
                    continue;
                }
                existingPat = TRUE;
                testpat = pat;
            }
            if (exppat == "-") exppat = testpat;
            DecimalFormat* f = 0;
            UErrorCode ec2 = U_ZERO_ERROR;
            if (existingPat) {
                f = fmt;
            } else {
                f = new DecimalFormat(testpat, ec2);
            }
            if (U_SUCCESS(ec2)) {
                if (err) {
                    errln("FAIL: " + where + "Invalid pattern \"" + testpat +
                          "\" was accepted");
                } else {
                    UnicodeString pat2;
                    assertEquals(where + "\"" + testpat + "\".toPattern()",
                                 exppat, f->toPattern(pat2));
                }
            } else {
                if (err) {
                    logln("Ok: " + where + "Invalid pattern \"" + testpat +
                          "\" failed: " + u_errorName(ec2));
                } else {
                    errln("FAIL: " + where + "Valid pattern \"" + testpat +
                          "\" failed: " + u_errorName(ec2));
                }
            }
            if (!existingPat) delete f;
            } break;
        case -1:
            errln("FAIL: " + where + "Unknown command \"" + tok + "\"");
            goto done;
        }
    }
    goto done;

 error:
    if (U_SUCCESS(ec)) {
        errln("FAIL: Unexpected EOF");
    } else {
        errcheckln(ec, "FAIL: " + where + "Unexpected " + u_errorName(ec));
    }

 done:
    delete mfmt;
    delete fmt;
    delete ref;
}


//----------------------------------------------------------------------
// Support methods
//----------------------------------------------------------------------

UBool NumberFormatTest::equalValue(const Formattable& a, const Formattable& b) {
    if (a.getType() == b.getType()) {
        return a == b;
    }

    if (a.getType() == Formattable::kLong) {
        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
        }
    } else if (a.getType() == Formattable::kDouble) {
        if (b.getType() == Formattable::kLong) {
            return a.getDouble() == (double) b.getLong();
        } else if (b.getType() == Formattable::kInt64) {
            return a.getDouble() == (double)b.getInt64();
        }
    } else if (a.getType() == Formattable::kInt64) {
        if (b.getType() == Formattable::kLong) {
                return a.getInt64() == (int64_t)b.getLong();
        } else if (b.getType() == Formattable::kDouble) {
            return a.getInt64() == (int64_t)b.getDouble();
        }
    }
    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);
    expect(fmt, str, n);
}

void NumberFormatTest::expect2(NumberFormat* fmt, const Formattable& n,
                               const UnicodeString& exp,
                               UErrorCode status) {
    if (fmt == NULL || U_FAILURE(status)) {
        dataerrln("FAIL: NumberFormat constructor");
    } else {
        expect2(*fmt, n, exp);
    }
    delete fmt;
}

void NumberFormatTest::expect(NumberFormat& fmt, const UnicodeString& str, const Formattable& n) {
    UErrorCode status = U_ZERO_ERROR;
    Formattable num;
    fmt.parse(str, num, status);
    if (U_FAILURE(status)) {
        dataerrln(UnicodeString("FAIL: Parse failed for \"") + str + "\" - " + u_errorName(status));
        return;
    }
    UnicodeString pat;
    ((DecimalFormat*) &fmt)->toPattern(pat);
    if (equalValue(num, n)) {
        logln(UnicodeString("Ok   \"") + str + "\" x " +
              pat + " = " +
              toString(num));
    } else {
        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;
    FieldPosition pos;
    UErrorCode status = U_ZERO_ERROR;
    fmt.format(n, saw, pos, status);
    CHECK(status, "NumberFormat::format");
    UnicodeString pat;
    ((DecimalFormat*) &fmt)->toPattern(pat);
    if (saw == exp) {
        logln(UnicodeString("Ok   ") + toString(n) + " x " +
              escape(pat) + " = \"" +
              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 + "\" - " + u_errorName(status));
                return;
            }
            UnicodeString saw2;
            fmt.format(n2, saw2, pos, status);
            CHECK(status, "NumberFormat::format");
            if (saw2 != exp) {
                errln((UnicodeString)"FAIL \"" + exp + "\" => " + toString(n2) +
                      " => \"" + saw2 + "\"");
            }
        }
    } else {
        dataerrln(UnicodeString("FAIL ") + toString(n) + " x " +
              escape(pat) + " = \"" +
              escape(saw) + "\", expected \"" + exp + "\"");
    }
}

void NumberFormatTest::expect(NumberFormat* fmt, const Formattable& n,
                              const UnicodeString& exp, UBool rt,
                              UErrorCode status) {
    if (fmt == NULL || U_FAILURE(status)) {
        dataerrln("FAIL: NumberFormat constructor");
    } else {
        expect(*fmt, n, exp, rt);
    }
    delete fmt;
}

void NumberFormatTest::expectCurrency(NumberFormat& nf, const Locale& locale,
                                      double value, const UnicodeString& string) {
    UErrorCode ec = U_ZERO_ERROR;
    DecimalFormat& fmt = * (DecimalFormat*) &nf;
    const UChar DEFAULT_CURR[] = {45/*-*/,0};
    UChar curr[4];
    u_strcpy(curr, DEFAULT_CURR);
    if (*locale.getLanguage() != 0) {
        ucurr_forLocale(locale.getName(), curr, 4, &ec);
        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);
    s.findAndReplace((UChar32)0x00A0, (UChar32)0x0020);

    // Default display of the number yields "1234.5599999999999"
    // instead of "1234.56".  Use a formatter to fix this.
    NumberFormat* f =
        NumberFormat::createInstance(Locale::getUS(), ec);
    UnicodeString v;
    if (U_FAILURE(ec)) {
        // Oops; bad formatter.  Use default op+= display.
        v = (UnicodeString)"" + value;
    } else {
        f->setMaximumFractionDigits(4);
        f->setGroupingUsed(FALSE);
        f->format(value, v);
    }
    delete f;

    if (s == string) {
        logln((UnicodeString)"Ok: " + v + " x " + curr + " => " + prettify(s));
    } else {
        errln((UnicodeString)"FAIL: " + v + " x " + curr + " => " + prettify(s) +
              ", expected " + prettify(string));
    }
}

void NumberFormatTest::expectPat(DecimalFormat& fmt, const UnicodeString& exp) {
    UnicodeString pat;
    fmt.toPattern(pat);
    if (pat == exp) {
        logln(UnicodeString("Ok   \"") + pat + "\"");
    } else {
        errln(UnicodeString("FAIL \"") + pat + "\", expected \"" + exp + "\"");
    }
}

void NumberFormatTest::expectPad(DecimalFormat& fmt, const UnicodeString& pat,
                                 int32_t pos) {
    expectPad(fmt, pat, pos, 0, (UnicodeString)"");
}
void NumberFormatTest::expectPad(DecimalFormat& fmt, const UnicodeString& pat,
                                 int32_t pos, int32_t width, UChar pad) {
    expectPad(fmt, pat, pos, width, UnicodeString(pad));
}
void NumberFormatTest::expectPad(DecimalFormat& fmt, const UnicodeString& pat,
                                 int32_t pos, int32_t width, const UnicodeString& pad) {
    int32_t apos = 0, awidth = 0;
    UnicodeString apadStr;
    UErrorCode status = U_ZERO_ERROR;
    fmt.applyPattern(pat, status);
    if (U_SUCCESS(status)) {
        apos = fmt.getPadPosition();
        awidth = fmt.getFormatWidth();
        apadStr=fmt.getPadCharacterString();
    } else {
        apos = -1;
        awidth = width;
        apadStr = pad;
    }
    if (apos == pos && awidth == width && apadStr == pad) {
        UnicodeString infoStr;
        if (pos == ILLEGAL) {
            infoStr = UnicodeString(" width=", "") + awidth + UnicodeString(" pad=", "") + apadStr;
        }
        logln(UnicodeString("Ok   \"") + pat + "\" pos=" + apos + infoStr);
    } else {
        errln(UnicodeString("FAIL \"") + pat + "\" pos=" + apos +
              " width=" + awidth + " pad=" + apadStr +
              ", expected " + pos + " " + width + " " + pad);
    }
}

// This test is flaky b/c the symbols for CNY and JPY are equivalent in this locale  - FIXME
void NumberFormatTest::TestCompatibleCurrencies() {
/*
    static const UChar JPY[] = {0x4A, 0x50, 0x59, 0};
    static const UChar CNY[] = {0x43, 0x4E, 0x59, 0};
    UErrorCode status = U_ZERO_ERROR;
    LocalPointer<NumberFormat> fmt(
        NumberFormat::createCurrencyInstance(Locale::getUS(), status));
    if (U_FAILURE(status)) {
        errln("Could not create number format instance.");
        return;
    }
    logln("%s:%d - testing parse of halfwidth yen sign\n", __FILE__, __LINE__);
    expectParseCurrency(*fmt, JPY, 1235,  "\\u00A51,235");
    logln("%s:%d - testing parse of fullwidth yen sign\n", __FILE__, __LINE__);
    expectParseCurrency(*fmt, JPY, 1235,  "\\uFFE51,235");
    logln("%s:%d - testing parse of halfwidth yen sign\n", __FILE__, __LINE__);
    expectParseCurrency(*fmt, CNY, 1235,  "CN\\u00A51,235");

    LocalPointer<NumberFormat> fmtTW(
        NumberFormat::createCurrencyInstance(Locale::getTaiwan(), status));

    logln("%s:%d - testing parse of halfwidth yen sign in TW\n", __FILE__, __LINE__);
    expectParseCurrency(*fmtTW, CNY, 1235,  "\\u00A51,235");
    logln("%s:%d - testing parse of fullwidth yen sign in TW\n", __FILE__, __LINE__);
    expectParseCurrency(*fmtTW, CNY, 1235,  "\\uFFE51,235");

    LocalPointer<NumberFormat> fmtJP(
        NumberFormat::createCurrencyInstance(Locale::getJapan(), status));

    logln("%s:%d - testing parse of halfwidth yen sign in JP\n", __FILE__, __LINE__);
    expectParseCurrency(*fmtJP, JPY, 1235,  "\\u00A51,235");
    logln("%s:%d - testing parse of fullwidth yen sign in JP\n", __FILE__, __LINE__);
    expectParseCurrency(*fmtJP, JPY, 1235,  "\\uFFE51,235");

    // more..
*/
}

void NumberFormatTest::expectParseCurrency(const NumberFormat &fmt, const UChar* currency, double amount, const char *text) {
    ParsePosition ppos;
    UnicodeString utext = ctou(text);
    LocalPointer<CurrencyAmount> currencyAmount(fmt.parseCurrency(utext, ppos));
    if (!ppos.getIndex()) {
        errln(UnicodeString("Parse of ") + utext + " should have succeeded.");
        return;
    }
    UErrorCode status = U_ZERO_ERROR;

    char theInfo[100];
    sprintf(theInfo, "For locale %s, string \"%s\", currency ",
            fmt.getLocale(ULOC_ACTUAL_LOCALE, status).getBaseName(),
            text);
    u_austrcpy(theInfo+uprv_strlen(theInfo), currency);

    char theOperation[100];

    uprv_strcpy(theOperation, theInfo);
    uprv_strcat(theOperation, ", check amount:");
    assertTrue(theOperation, amount ==  currencyAmount->getNumber().getDouble(status));

    uprv_strcpy(theOperation, theInfo);
    uprv_strcat(theOperation, ", check currency:");
    assertEquals(theOperation, currency, currencyAmount->getISOCurrency());
}


void NumberFormatTest::TestJB3832(){
    const char* localeID = "pt_PT@currency=PTE";
    Locale loc(localeID);
    UErrorCode status = U_ZERO_ERROR;
    UnicodeString expected(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<NumberFormat> full(NumberFormat::createInstance(loc, k, status));
        if (!NumberFormat::isStyleSupported(k)) {
            if (status != U_UNSUPPORTED_ERROR) {
                errln("FAIL: expected style %d to be unsupported - %s",
                      k, u_errorName(status));
            }
            continue;
        }
        if (full.isNull() || U_FAILURE(status)) {
            dataerrln("FAIL: Can't create number instance of style %d for host - %s",
                      k, u_errorName(status));
            return;
        }
        UnicodeString result1;
        Formattable number(10.00);
        full->format(number, result1, status);
        if (U_FAILURE(status)) {
            errln("FAIL: Can't format for host");
            return;
        }
        Formattable formattable;
        full->parse(result1, formattable, status);
        if (U_FAILURE(status)) {
            errln("FAIL: Can't parse for host");
            return;
        }
    }
}

void NumberFormatTest::TestHostClone()
{
    /*
    Verify that a cloned formatter gives the same results
    and is useable after the original has been deleted.
    */
    // This is mainly important on Windows.
    UErrorCode status = U_ZERO_ERROR;
    Locale loc("en_US@compat=host");
    UDate now = Calendar::getNow();
    NumberFormat *full = NumberFormat::createInstance(loc, status);
    if (full == NULL || U_FAILURE(status)) {
        dataerrln("FAIL: Can't create NumberFormat date instance - %s", u_errorName(status));
        return;
    }
    UnicodeString result1;
    full->format(now, result1, status);
    Format *fullClone = full->clone();
    delete full;
    full = NULL;

    UnicodeString result2;
    fullClone->format(now, result2, status);
    if (U_FAILURE(status)) {
        errln("FAIL: format failure.");
    }
    if (result1 != result2) {
        errln("FAIL: Clone returned different result from non-clone.");
    }
    delete fullClone;
}

void NumberFormatTest::TestCurrencyFormat()
{
    // 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;mode<DecimalFormat::kRoundHalfEven;mode++) {
            df->setRoundingMode((DecimalFormat::ERoundingMode)mode);
            for (int increment=0; increment<6; increment++) {
                double base=testValues[j];
                double rInc=roundingIncrements[increment];
                checkRounding(df, base, 20, rInc);
                rInc=1.000000000/rInc;
                checkRounding(df, base, 20, rInc);
            }
        }
    }
    delete df;
}

void NumberFormatTest::TestRoundingPattern() {
    UErrorCode status = U_ZERO_ERROR;
    struct {
        UnicodeString  pattern;
        double        testCase;
        UnicodeString expected;
    } tests[] = {
            { (UnicodeString)"##0.65", 1.234, (UnicodeString)"1.30" },
            { (UnicodeString)"#50",    1230,  (UnicodeString)"1250" }
    };
    int32_t numOfTests = UPRV_LENGTHOF(tests);
    UnicodeString result;

    DecimalFormat *df = (DecimalFormat*)NumberFormat::createCurrencyInstance(Locale::getEnglish(), status);
    if (U_FAILURE(status)) {
        dataerrln("Unable to create decimal formatter. - %s", u_errorName(status));
        return;
    }

    for (int32_t i = 0; i < numOfTests; i++) {
        result.remove();

        df->applyPattern(tests[i].pattern, status);
        if (U_FAILURE(status)) {
            errln("Unable to apply pattern to decimal formatter. - %s", u_errorName(status));
        }

        df->format(tests[i].testCase, result);

        if (result != tests[i].expected) {
            errln("String Pattern Rounding Test Failed: Pattern: \"" + tests[i].pattern + "\" Number: " + tests[i].testCase + " - Got: " + result + " Expected: " + tests[i].expected);
        }
    }

    delete df;
}

void NumberFormatTest::checkRounding(DecimalFormat* df, double base, int iterations, double increment) {
    df->setRoundingIncrement(increment);
    double lastParsed=INT32_MIN; //Intger.MIN_VALUE
    for (int i=-iterations; i<=iterations;i++) {
        double iValue=base+(increment*(i*0.1));
        double smallIncrement=0.00000001;
        if (iValue!=0) {
            smallIncrement*=iValue;
        }
        //we not only test the value, but some values in a small range around it
        lastParsed=checkRound(df, iValue-smallIncrement, lastParsed);
        lastParsed=checkRound(df, iValue, lastParsed);
        lastParsed=checkRound(df, iValue+smallIncrement, lastParsed);
    }
}

double NumberFormatTest::checkRound(DecimalFormat* df, double iValue, double lastParsed) {
    UErrorCode status=U_ZERO_ERROR;
    UnicodeString formattedDecimal;
    double parsed;
    Formattable result;
    df->format(iValue, formattedDecimal, status);

    if (U_FAILURE(status)) {
        errln("Error formatting number.");
    }

    df->parse(formattedDecimal, result, status);

    if (U_FAILURE(status)) {
        errln("Error parsing number.");
    }

    parsed=result.getDouble();

    if (lastParsed>parsed) {
        errln("Rounding wrong direction! %d > %d", lastParsed, parsed);
    }

    return lastParsed;
}

void NumberFormatTest::TestNonpositiveMultiplier() {
    UErrorCode status = U_ZERO_ERROR;
    DecimalFormatSymbols US(Locale::getUS(), status);
    CHECK(status, "DecimalFormatSymbols constructor");
    DecimalFormat df(UnicodeString("0"), US, status);
    CHECK(status, "DecimalFormat(0)");

    // test zero multiplier

    int32_t mult = df.getMultiplier();
    df.setMultiplier(0);
    if (df.getMultiplier() != mult) {
        errln("DecimalFormat.setMultiplier(0) did not ignore its zero input");
    }

    // test negative multiplier

    df.setMultiplier(-1);
    if (df.getMultiplier() != -1) {
        errln("DecimalFormat.setMultiplier(-1) ignored its negative input");
        return;
    }

    expect(df, "1122.123", -1122.123);
    expect(df, "-1122.123", 1122.123);
    expect(df, "1.2", -1.2);
    expect(df, "-1.2", 1.2);

    // Note:  the tests with the final parameter of FALSE will not round trip.
    //        The initial numeric value will format correctly, after the multiplier.
    //        Parsing the formatted text will be out-of-range for an int64, however.
    //        The expect() function could be modified to detect this and fall back
    //        to looking at the decimal parsed value, but it doesn't.
    expect(df, U_INT64_MIN,    "9223372036854775808", FALSE);
    expect(df, U_INT64_MIN+1,  "9223372036854775807");
    expect(df, (int64_t)-123,                  "123");
    expect(df, (int64_t)123,                  "-123");
    expect(df, U_INT64_MAX-1, "-9223372036854775806");
    expect(df, U_INT64_MAX,   "-9223372036854775807");

    df.setMultiplier(-2);
    expect(df, -(U_INT64_MIN/2)-1, "-9223372036854775806");
    expect(df, -(U_INT64_MIN/2),   "-9223372036854775808");
    expect(df, -(U_INT64_MIN/2)+1, "-9223372036854775810", FALSE);

    df.setMultiplier(-7);
    expect(df, -(U_INT64_MAX/7)-1, "9223372036854775814", FALSE);
    expect(df, -(U_INT64_MAX/7),   "9223372036854775807");
    expect(df, -(U_INT64_MAX/7)+1, "9223372036854775800");

    // TODO: uncomment (and fix up) all the following int64_t tests once BigInteger is ported
    // (right now the big numbers get turned into doubles and lose tons of accuracy)
    //expect2(df, U_INT64_MAX, Int64ToUnicodeString(-U_INT64_MAX));
    //expect2(df, U_INT64_MIN, UnicodeString(Int64ToUnicodeString(U_INT64_MIN), 1));
    //expect2(df, U_INT64_MAX / 2, Int64ToUnicodeString(-(U_INT64_MAX / 2)));
    //expect2(df, U_INT64_MIN / 2, Int64ToUnicodeString(-(U_INT64_MIN / 2)));

    // TODO: uncomment (and fix up) once BigDecimal is ported and DecimalFormat can handle it
    //expect2(df, BigDecimal.valueOf(Long.MAX_VALUE), BigDecimal.valueOf(Long.MAX_VALUE).negate().toString());
    //expect2(df, BigDecimal.valueOf(Long.MIN_VALUE), BigDecimal.valueOf(Long.MIN_VALUE).negate().toString());
    //expect2(df, java.math.BigDecimal.valueOf(Long.MAX_VALUE), java.math.BigDecimal.valueOf(Long.MAX_VALUE).negate().toString());
    //expect2(df, java.math.BigDecimal.valueOf(Long.MIN_VALUE), java.math.BigDecimal.valueOf(Long.MIN_VALUE).negate().toString());
}

typedef struct {
    const char * stringToParse;
    int          parsedPos;
    int          errorIndex;
    UBool        lenient;
} TestSpaceParsingItem;

void
NumberFormatTest::TestSpaceParsing() {
    // the data are:
    // the string to be parsed, parsed position, parsed error index
    const TestSpaceParsingItem DATA[] = {
        {"$124",           4, -1, FALSE},
        {"$124 $124",      4, -1, FALSE},
        {"$124 ",          4, -1, FALSE},
        {"$ 124 ",         0,  1, FALSE},
        {"$\\u00A0124 ",   5, -1, FALSE},
        {" $ 124 ",        0,  0, FALSE},
        {"124$",           0,  4, FALSE},
        {"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},
        {"124$",           4, -1, TRUE},
        {"124 $",          5, -1, TRUE},
        {"124 $",          5, -1, TRUE},
    };
    UErrorCode status = U_ZERO_ERROR;
    Locale locale("en_US");
    NumberFormat* foo = NumberFormat::createCurrencyInstance(locale, status);

    if (U_FAILURE(status)) {
        delete foo;
        return;
    }
    for (uint32_t i = 0; i < UPRV_LENGTHOF(DATA); ++i) {
        ParsePosition parsePosition(0);
        UnicodeString stringToBeParsed = ctou(DATA[i].stringToParse);
        int parsedPosition = DATA[i].parsedPos;
        int errorIndex = DATA[i].errorIndex;
        foo->setLenient(DATA[i].lenient);
        Formattable result;
        foo->parse(stringToBeParsed, result, parsePosition);
        logln("Parsing: " + stringToBeParsed);
        if (parsePosition.getIndex() != parsedPosition ||
            parsePosition.getErrorIndex() != errorIndex) {
            errln("FAILED parse " + stringToBeParsed + "; lenient: " + DATA[i].lenient + "; wrong position, expected: (" + parsedPosition + ", " + errorIndex + "); got (" + parsePosition.getIndex() + ", " + parsePosition.getErrorIndex() + ")");
        }
        if (parsePosition.getErrorIndex() == -1 &&
            result.getType() == Formattable::kLong &&
            result.getLong() != 124) {
            errln("FAILED parse " + stringToBeParsed + "; wrong number, expect: 124, got " + result.getLong());
        }
    }
    delete foo;
}

/**
 * Test using various numbering systems and numbering system keyword.
 */
typedef struct {
    const char *localeName;
    double      value;
    UBool        isRBNF;
    const char *expectedResult;
} TestNumberingSystemItem;

void NumberFormatTest::TestNumberingSystems() {

    const TestNumberingSystemItem DATA[] = {
        { "en_US@numbers=thai", 1234.567, FALSE, "\\u0E51,\\u0E52\\u0E53\\u0E54.\\u0E55\\u0E56\\u0E57" },
        { "en_US@numbers=hebr", 5678.0, TRUE, "\\u05D4\\u05F3\\u05EA\\u05E8\\u05E2\\u05F4\\u05D7" },
        { "en_US@numbers=arabext", 1234.567, FALSE, "\\u06F1\\u066c\\u06F2\\u06F3\\u06F4\\u066b\\u06F5\\u06F6\\u06F7" },
        { "ar_EG", 1234.567, FALSE, "\\u0661\\u066C\\u0662\\u0663\\u0664\\u066b\\u0665\\u0666\\u0667" },
        { "th_TH@numbers=traditional", 1234.567, FALSE, "\\u0E51,\\u0E52\\u0E53\\u0E54.\\u0E55\\u0E56\\u0E57" }, // fall back to native per TR35
        { "ar_MA", 1234.567, FALSE, "1.234,567" },
        { "en_US@numbers=hanidec", 1234.567, FALSE, "\\u4e00,\\u4e8c\\u4e09\\u56db.\\u4e94\\u516d\\u4e03" },
        { "ta_IN@numbers=native", 1234.567, FALSE, "\\u0BE7,\\u0BE8\\u0BE9\\u0BEA.\\u0BEB\\u0BEC\\u0BED" },
        { "ta_IN@numbers=traditional", 1235.0, TRUE, "\\u0BF2\\u0BE8\\u0BF1\\u0BE9\\u0BF0\\u0BEB" },
        { "ta_IN@numbers=finance", 1234.567, FALSE, "1,234.567" }, // fall back to default per TR35
        { "zh_TW@numbers=native", 1234.567, FALSE, "\\u4e00,\\u4e8c\\u4e09\\u56db.\\u4e94\\u516d\\u4e03" },
        { "zh_TW@numbers=traditional", 1234.567, TRUE, "\\u4E00\\u5343\\u4E8C\\u767E\\u4E09\\u5341\\u56DB\\u9EDE\\u4E94\\u516D\\u4E03" },
        { "zh_TW@numbers=finance", 1234.567, TRUE, "\\u58F9\\u4EDF\\u8CB3\\u4F70\\u53C3\\u62FE\\u8086\\u9EDE\\u4F0D\\u9678\\u67D2" },
        { NULL, 0, FALSE, NULL }
    };

    UErrorCode ec;

    const TestNumberingSystemItem *item;
    for (item = DATA; item->localeName != NULL; item++) {
        ec = U_ZERO_ERROR;
        Locale loc = Locale::createFromName(item->localeName);

        NumberFormat *origFmt = NumberFormat::createInstance(loc,ec);
        if (U_FAILURE(ec)) {
            dataerrln("FAIL: getInstance(%s) - %s", item->localeName, u_errorName(ec));
            continue;
        }
        // Clone to test ticket #10682
        NumberFormat *fmt = (NumberFormat *) origFmt->clone();
        delete origFmt;


        if (item->isRBNF) {
            expect3(*fmt,item->value,CharsToUnicodeString(item->expectedResult));
        } else {
            expect2(*fmt,item->value,CharsToUnicodeString(item->expectedResult));
        }
        delete fmt;
    }


    // Test bogus keyword value
    ec = U_ZERO_ERROR;
    Locale loc4 = Locale::createFromName("en_US@numbers=foobar");
    NumberFormat* fmt4= NumberFormat::createInstance(loc4, ec);
    if ( ec != U_UNSUPPORTED_ERROR ) {
        errln("FAIL: getInstance(en_US@numbers=foobar) should have returned U_UNSUPPORTED_ERROR");
        delete fmt4;
    }

    ec = U_ZERO_ERROR;
    NumberingSystem *ns = NumberingSystem::createInstance(ec);
    if (U_FAILURE(ec)) {
        dataerrln("FAIL: NumberingSystem::createInstance(ec); - %s", u_errorName(ec));
    }

    if ( ns != NULL ) {
        ns->getDynamicClassID();
        ns->getStaticClassID();
    } else {
        errln("FAIL: getInstance() returned NULL.");
    }

    NumberingSystem *ns1 = new NumberingSystem(*ns);
    if (ns1 == NULL) {
        errln("FAIL: NumberSystem copy constructor returned NULL.");
    }

    delete ns1;
    delete ns;

}


void
NumberFormatTest::TestMultiCurrencySign() {
    const char* DATA[][6] = {
        // the fields in the following test are:
        // locale,
        // currency pattern (with negative pattern),
        // currency number to be formatted,
        // currency format using currency symbol name, such as "$" for USD,
        // currency format using currency ISO name, such as "USD",
        // currency format using plural name, such as "US dollars".
        // for US locale
        {"en_US", "\\u00A4#,##0.00;-\\u00A4#,##0.00", "1234.56", "$1,234.56", "USD\\u00A01,234.56", "US dollars\\u00A01,234.56"},
        {"en_US", "\\u00A4#,##0.00;-\\u00A4#,##0.00", "-1234.56", "-$1,234.56", "-USD\\u00A01,234.56", "-US dollars\\u00A01,234.56"},
        {"en_US", "\\u00A4#,##0.00;-\\u00A4#,##0.00", "1", "$1.00", "USD\\u00A01.00", "US dollars\\u00A01.00"},
        // for CHINA locale
        {"zh_CN", "\\u00A4#,##0.00;(\\u00A4#,##0.00)", "1234.56", "\\uFFE51,234.56", "CNY\\u00A01,234.56", "\\u4EBA\\u6C11\\u5E01\\u00A01,234.56"},
        {"zh_CN", "\\u00A4#,##0.00;(\\u00A4#,##0.00)", "-1234.56", "(\\uFFE51,234.56)", "(CNY\\u00A01,234.56)", "(\\u4EBA\\u6C11\\u5E01\\u00A01,234.56)"},
        {"zh_CN", "\\u00A4#,##0.00;(\\u00A4#,##0.00)", "1", "\\uFFE51.00", "CNY\\u00A01.00", "\\u4EBA\\u6C11\\u5E01\\u00A01.00"}
    };

    const UChar doubleCurrencySign[] = {0xA4, 0xA4, 0};
    UnicodeString doubleCurrencyStr(doubleCurrencySign);
    const UChar tripleCurrencySign[] = {0xA4, 0xA4, 0xA4, 0};
    UnicodeString tripleCurrencyStr(tripleCurrencySign);

    for (uint32_t i=0; i<UPRV_LENGTHOF(DATA); ++i) {
        const char* locale = DATA[i][0];
        UnicodeString pat = ctou(DATA[i][1]);
        double numberToBeFormat = atof(DATA[i][2]);
        UErrorCode status = U_ZERO_ERROR;
        DecimalFormatSymbols* sym = new DecimalFormatSymbols(Locale(locale), status);
        if (U_FAILURE(status)) {
            delete sym;
            continue;
        }
        for (int j=1; j<=3; ++j) {
            // j represents the number of currency sign in the pattern.
            if (j == 2) {
                pat = pat.findAndReplace(ctou("\\u00A4"), doubleCurrencyStr);
            } else if (j == 3) {
                pat = pat.findAndReplace(ctou("\\u00A4\\u00A4"), tripleCurrencyStr);
            }

            DecimalFormat* fmt = new DecimalFormat(pat, new DecimalFormatSymbols(*sym), status);
            if (U_FAILURE(status)) {
                errln("FAILED init DecimalFormat ");
                delete fmt;
                continue;
            }
            UnicodeString s;
            ((NumberFormat*) fmt)->format(numberToBeFormat, s);
            // DATA[i][3] is the currency format result using a
            // single currency sign.
            // DATA[i][4] is the currency format result using
            // double currency sign.
            // DATA[i][5] is the currency format result using
            // triple currency sign.
            // DATA[i][j+2] is the currency format result using
            // 'j' number of currency sign.
            UnicodeString currencyFormatResult = ctou(DATA[i][2+j]);
            if (s.compare(currencyFormatResult)) {
                errln("FAIL format: Expected " + currencyFormatResult + "; Got " + s);
            }
            // mix style parsing
            for (int k=3; k<=5; ++k) {
              // DATA[i][3] is the currency format result using a
              // single currency sign.
              // DATA[i][4] is the currency format result using
              // double currency sign.
              // DATA[i][5] is the currency format result using
              // triple currency sign.
              UnicodeString oneCurrencyFormat = ctou(DATA[i][k]);
              UErrorCode status = U_ZERO_ERROR;
              Formattable parseRes;
              fmt->parse(oneCurrencyFormat, parseRes, status);
              if (U_FAILURE(status) ||
                  (parseRes.getType() == Formattable::kDouble &&
                   parseRes.getDouble() != numberToBeFormat) ||
                  (parseRes.getType() == Formattable::kLong &&
                   parseRes.getLong() != numberToBeFormat)) {
                  errln("FAILED parse " + oneCurrencyFormat + "; (i, j, k): " +
                        i + ", " + j + ", " + k);
              }
            }
            delete fmt;
        }
        delete sym;
    }
}


void
NumberFormatTest::TestCurrencyFormatForMixParsing() {
    UErrorCode status = U_ZERO_ERROR;
    MeasureFormat* curFmt = MeasureFormat::createCurrencyFormat(Locale("en_US"), status);
    if (U_FAILURE(status)) {
        delete curFmt;
        return;
    }
    const char* formats[] = {
        "$1,234.56",  // string to be parsed
        "USD1,234.56",
        "US dollars1,234.56",
        // "1,234.56 US dollars" // Fails in 62 because currency format is not compatible with pattern.
    };
    const CurrencyAmount* curramt = NULL;
    for (uint32_t i = 0; i < UPRV_LENGTHOF(formats); ++i) {
        UnicodeString stringToBeParsed = ctou(formats[i]);
        logln(UnicodeString("stringToBeParsed: ") + stringToBeParsed);
        Formattable result;
        UErrorCode status = U_ZERO_ERROR;
        curFmt->parseObject(stringToBeParsed, result, status);
        if (U_FAILURE(status)) {
          errln("FAIL: measure format parsing: '%s' ec: %s", formats[i], u_errorName(status));
        } else if (result.getType() != Formattable::kObject ||
            (curramt = dynamic_cast<const CurrencyAmount*>(result.getObject())) == NULL ||
            curramt->getNumber().getDouble() != 1234.56 ||
            UnicodeString(curramt->getISOCurrency()).compare(ISO_CURRENCY_USD)
        ) {
            errln("FAIL: getCurrencyFormat of default locale (en_US) failed roundtripping the number ");
            if (curramt->getNumber().getDouble() != 1234.56) {
                errln((UnicodeString)"wong number, expect: 1234.56" + ", got: " + curramt->getNumber().getDouble());
            }
            if (curramt->getISOCurrency() != ISO_CURRENCY_USD) {
                errln((UnicodeString)"wong currency, expect: USD" + ", got: " + curramt->getISOCurrency());
            }
        }
    }
    delete curFmt;
}


/** Starting in ICU 62, strict mode is actually strict with currency formats. */
void NumberFormatTest::TestMismatchedCurrencyFormatFail() {
    IcuTestErrorCode status(*this, "TestMismatchedCurrencyFormatFail");
    LocalPointer<DecimalFormat> df(
            dynamic_cast<DecimalFormat*>(DecimalFormat::createCurrencyInstance("en", status)), status);
    if (!assertSuccess("createCurrencyInstance() failed.", status, true, __FILE__, __LINE__)) {return;}
    UnicodeString pattern;
    assertEquals("Test assumes that currency sign is at the beginning",
            u"\u00A4#,##0.00",
            df->toPattern(pattern));
    // Should round-trip on the correct currency format:
    expect2(*df, 1.23, u"XXX\u00A01.23");
    df->setCurrency(u"EUR", status);
    expect2(*df, 1.23, u"\u20AC1.23");
    // Should parse with currency in the wrong place in lenient mode
    df->setLenient(TRUE);
    expect(*df, u"1.23\u20AC", 1.23);
    expectParseCurrency(*df, u"EUR", 1.23, "1.23\\u20AC");
    // Should NOT parse with currency in the wrong place in STRICT mode
    df->setLenient(FALSE);
    {
        Formattable result;
        ErrorCode failStatus;
        df->parse(u"1.23\u20AC", result, failStatus);
        assertEquals("Should fail to parse", U_INVALID_FORMAT_ERROR, failStatus);
    }
    {
        ParsePosition ppos;
        df->parseCurrency(u"1.23\u20AC", ppos);
        assertEquals("Should fail to parse currency", 0, ppos.getIndex());
    }
}


void
NumberFormatTest::TestDecimalFormatCurrencyParse() {
    // Locale.US
    UErrorCode status = U_ZERO_ERROR;
    DecimalFormatSymbols* sym = new DecimalFormatSymbols(Locale("en_US"), status);
    if (U_FAILURE(status)) {
        delete sym;
        return;
    }
    UnicodeString pat;
    UChar currency = 0x00A4;
    // "\xA4#,##0.00;-\xA4#,##0.00"
    pat.append(currency).append(currency).append(currency).append("#,##0.00;-").append(currency).append(currency).append(currency).append("#,##0.00");
    DecimalFormat* fmt = new DecimalFormat(pat, sym, status);
    if (U_FAILURE(status)) {
        delete fmt;
        errln("failed to new DecimalFormat in TestDecimalFormatCurrencyParse");
        return;
    }
    const char* DATA[][2] = {
        // the data are:
        // string to be parsed, the parsed result (number)
        {"$1.00", "1"},
        {"USD1.00", "1"},
        {"1.00 US dollar", "1"},
        {"$1,234.56", "1234.56"},
        {"USD1,234.56", "1234.56"},
        {"1,234.56 US dollar", "1234.56"},
    };
    // NOTE: ICU 62 requires that the currency format match the pattern in strict mode.
    fmt->setLenient(TRUE);
    for (uint32_t i = 0; i < UPRV_LENGTHOF(DATA); ++i) {
        UnicodeString stringToBeParsed = ctou(DATA[i][0]);
        double parsedResult = atof(DATA[i][1]);
        UErrorCode status = U_ZERO_ERROR;
        Formattable result;
        fmt->parse(stringToBeParsed, result, status);
        logln((UnicodeString)"Input: " + stringToBeParsed + "; output: " + result.getDouble(status));
        if (U_FAILURE(status) ||
            (result.getType() == Formattable::kDouble &&
            result.getDouble() != parsedResult) ||
            (result.getType() == Formattable::kLong &&
            result.getLong() != parsedResult)) {
            errln((UnicodeString)"FAIL parse: Expected " + parsedResult);
        }
    }
    delete fmt;
}


void
NumberFormatTest::TestCurrencyIsoPluralFormat() {
    static const char* DATA[][6] = {
        // the data are:
        // locale,
        // currency amount to be formatted,
        // currency ISO code to be formatted,
        // format result using CURRENCYSTYLE,
        // format result using ISOCURRENCYSTYLE,
        // format result using PLURALCURRENCYSTYLE,

        {"en_US", "1", "USD", "$1.00", "USD\\u00A01.00", "1.00 US dollars"},
        {"en_US", "1234.56", "USD", "$1,234.56", "USD\\u00A01,234.56", "1,234.56 US dollars"},
        {"en_US", "-1234.56", "USD", "-$1,234.56", "-USD\\u00A01,234.56", "-1,234.56 US dollars"},
        {"zh_CN", "1", "USD", "US$1.00", "USD\\u00A01.00", "1.00\\u00A0\\u7F8E\\u5143"},
        {"zh_CN", "1234.56", "USD", "US$1,234.56", "USD\\u00A01,234.56", "1,234.56\\u00A0\\u7F8E\\u5143"},
        {"zh_CN", "1", "CNY", "\\uFFE51.00", "CNY\\u00A01.00", "1.00\\u00A0\\u4EBA\\u6C11\\u5E01"},
        {"zh_CN", "1234.56", "CNY", "\\uFFE51,234.56", "CNY\\u00A01,234.56", "1,234.56\\u00A0\\u4EBA\\u6C11\\u5E01"},
        {"ru_RU", "1", "RUB", "1,00\\u00A0\\u20BD", "1,00\\u00A0RUB", "1,00 \\u0440\\u043E\\u0441\\u0441\\u0438\\u0439\\u0441\\u043A\\u043E\\u0433\\u043E \\u0440\\u0443\\u0431\\u043B\\u044F"},
        {"ru_RU", "2", "RUB", "2,00\\u00A0\\u20BD", "2,00\\u00A0RUB", "2,00 \\u0440\\u043E\\u0441\\u0441\\u0438\\u0439\\u0441\\u043A\\u043E\\u0433\\u043E \\u0440\\u0443\\u0431\\u043B\\u044F"},
        {"ru_RU", "5", "RUB", "5,00\\u00A0\\u20BD", "5,00\\u00A0RUB", "5,00 \\u0440\\u043E\\u0441\\u0441\\u0438\\u0439\\u0441\\u043A\\u043E\\u0433\\u043E \\u0440\\u0443\\u0431\\u043B\\u044F"},
        // test locale without currency information
        {"root", "-1.23", "USD", "-US$\\u00A01.23", "-USD\\u00A01.23", "-1.23 USD"},
        // test choice format
        {"es_AR", "1", "INR", "INR\\u00A01,00", "INR\\u00A01,00", "1,00 rupia india"},
    };
    static const UNumberFormatStyle currencyStyles[] = {
        UNUM_CURRENCY,
        UNUM_CURRENCY_ISO,
        UNUM_CURRENCY_PLURAL
    };

    for (int32_t i=0; i<UPRV_LENGTHOF(DATA); ++i) {
      const char* localeString = DATA[i][0];
      double numberToBeFormat = atof(DATA[i][1]);
      const char* currencyISOCode = DATA[i][2];
      logln(UnicodeString(u"Locale: ") + localeString + "; amount: " + numberToBeFormat);
      Locale locale(localeString);
      for (int32_t kIndex = 0; kIndex < UPRV_LENGTHOF(currencyStyles); ++kIndex) {
        UNumberFormatStyle k = currencyStyles[kIndex];
        logln(UnicodeString(u"UNumberFormatStyle: ") + k);
        UErrorCode status = U_ZERO_ERROR;
        NumberFormat* numFmt = NumberFormat::createInstance(locale, k, status);
        if (U_FAILURE(status)) {
            delete numFmt;
            dataerrln((UnicodeString)"can not create instance, locale:" + localeString + ", style: " + k + " - " + u_errorName(status));
            continue;
        }
        UChar currencyCode[4];
        u_charsToUChars(currencyISOCode, currencyCode, 4);
        numFmt->setCurrency(currencyCode, status);
        if (U_FAILURE(status)) {
            delete numFmt;
            errln((UnicodeString)"can not set currency:" + currencyISOCode);
            continue;
        }

        UnicodeString strBuf;
        numFmt->format(numberToBeFormat, strBuf);
        int resultDataIndex = 3 + kIndex;
        // DATA[i][resultDataIndex] is the currency format result
        // using 'k' currency style.
        UnicodeString formatResult = ctou(DATA[i][resultDataIndex]);
        if (strBuf.compare(formatResult)) {
            errln("FAIL: Expected " + formatResult + " actual: " + strBuf);
        }
        // test parsing, and test parsing for all currency formats.
        // NOTE: ICU 62 requires that the currency format match the pattern in strict mode.
        numFmt->setLenient(TRUE);
        for (int j = 3; j < 6; ++j) {
            // DATA[i][3] is the currency format result using
            // CURRENCYSTYLE formatter.
            // DATA[i][4] is the currency format result using
            // ISOCURRENCYSTYLE formatter.
            // DATA[i][5] is the currency format result using
            // PLURALCURRENCYSTYLE formatter.
            UnicodeString oneCurrencyFormatResult = ctou(DATA[i][j]);
            UErrorCode status = U_ZERO_ERROR;
            Formattable parseResult;
            numFmt->parse(oneCurrencyFormatResult, parseResult, status);
            if (U_FAILURE(status) ||
                (parseResult.getType() == Formattable::kDouble &&
                 parseResult.getDouble() != numberToBeFormat) ||
                (parseResult.getType() == Formattable::kLong &&
                 parseResult.getLong() != numberToBeFormat)) {
                errln((UnicodeString)"FAIL: getCurrencyFormat of locale " +
                      localeString + " failed roundtripping the number");
                if (parseResult.getType() == Formattable::kDouble) {
                    errln((UnicodeString)"expected: " + numberToBeFormat + "; actual: " +parseResult.getDouble());
                } else {
                    errln((UnicodeString)"expected: " + numberToBeFormat + "; actual: " +parseResult.getLong());
                }
            }
        }
        delete numFmt;
      }
    }
}

void
NumberFormatTest::TestCurrencyParsing() {
    static const char* DATA[][6] = {
        // the data are:
        // locale,
        // currency amount to be formatted,
        // currency ISO code to be formatted,
        // format result using CURRENCYSTYLE,
        // format result using ISOCURRENCYSTYLE,
        // format result using PLURALCURRENCYSTYLE,
        {"en_US", "1", "USD", "$1.00", "USD\\u00A01.00", "1.00 US dollars"},
        {"pa_IN", "1", "USD", "US$\\u00A01.00", "USD\\u00A01.00", "1.00 \\u0a2f\\u0a42.\\u0a10\\u0a38. \\u0a21\\u0a3e\\u0a32\\u0a30"},
        {"es_AR", "1", "USD", "US$\\u00A01,00", "USD\\u00A01,00", "1,00 d\\u00f3lar estadounidense"},
        {"ar_EG", "1", "USD", "\\u0661\\u066b\\u0660\\u0660\\u00a0US$", "\\u0661\\u066b\\u0660\\u0660\\u00a0USD", "\\u0661\\u066b\\u0660\\u0660 \\u062f\\u0648\\u0644\\u0627\\u0631 \\u0623\\u0645\\u0631\\u064a\\u0643\\u064a"},
        {"fa_CA", "1", "USD", "\\u200e$\\u06f1\\u066b\\u06f0\\u06f0", "\\u200eUSD\\u06f1\\u066b\\u06f0\\u06f0", "\\u06f1\\u066b\\u06f0\\u06f0 \\u062f\\u0644\\u0627\\u0631 \\u0627\\u0645\\u0631\\u06cc\\u06a9\\u0627"},
        {"he_IL", "1", "USD", "\\u200f1.00\\u00a0$", "\\u200f1.00\\u00a0USD", "1.00 \\u05d3\\u05d5\\u05dc\\u05e8 \\u05d0\\u05de\\u05e8\\u05d9\\u05e7\\u05d0\\u05d9"},
        {"hr_HR", "1", "USD", "1,00\\u00a0USD", "1,00\\u00a0USD", "1,00 ameri\\u010Dkih dolara"},
        {"id_ID", "1", "USD", "US$\\u00A01,00", "USD\\u00A01,00", "1,00 Dolar Amerika Serikat"},
        {"it_IT", "1", "USD", "1,00\\u00a0USD", "1,00\\u00a0USD", "1,00 dollari statunitensi"},
        {"ko_KR", "1", "USD", "US$\\u00A01.00", "USD\\u00A01.00", "1.00 \\ubbf8\\uad6d \\ub2ec\\ub7ec"},
        {"ja_JP", "1", "USD", "$1.00", "USD\\u00A01.00", "1.00\\u00A0\\u7c73\\u30c9\\u30eb"},
        {"zh_CN", "1", "CNY", "\\uFFE51.00", "CNY\\u00A001.00", "1.00\\u00A0\\u4EBA\\u6C11\\u5E01"},
        {"zh_TW", "1", "CNY", "CN\\u00A51.00", "CNY\\u00A01.00", "1.00 \\u4eba\\u6c11\\u5e63"},
        {"zh_Hant", "1", "CNY", "CN\\u00A51.00", "CNY\\u00A01.00", "1.00 \\u4eba\\u6c11\\u5e63"},
        {"zh_Hant", "1", "JPY", "\\u00A51.00", "JPY\\u00A01.00", "1 \\u65E5\\u5713"},
        {"ja_JP", "1", "JPY", "\\uFFE51.00", "JPY\\u00A01.00", "1\\u00A0\\u5186"},
        // ICU 62 requires #parseCurrency() to recognize variants when parsing
        // {"ja_JP", "1", "JPY", "\\u00A51.00", "JPY\\u00A01.00", "1\\u00A0\\u5186"},
        {"ru_RU", "1", "RUB", "1,00\\u00A0\\u00A0\\u20BD", "1,00\\u00A0\\u00A0RUB", "1,00 \\u0440\\u043E\\u0441\\u0441\\u0438\\u0439\\u0441\\u043A\\u043E\\u0433\\u043E \\u0440\\u0443\\u0431\\u043B\\u044F"}
    };
    static const UNumberFormatStyle currencyStyles[] = {
        UNUM_CURRENCY,
        UNUM_CURRENCY_ISO,
        UNUM_CURRENCY_PLURAL
    };
    static const char* currencyStyleNames[] = {
      "UNUM_CURRENCY",
      "UNUM_CURRENCY_ISO",
      "UNUM_CURRENCY_PLURAL"
    };

#ifdef NUMFMTST_CACHE_DEBUG
int deadloop = 0;
for (;;) {
    printf("loop: %d\n", deadloop++);
#endif
    for (uint32_t i=0; i< UPRV_LENGTHOF(DATA); ++i) {  /* i = test case #  - should be i=0*/
      for (int32_t kIndex = 2; kIndex < UPRV_LENGTHOF(currencyStyles); ++kIndex) {
        UNumberFormatStyle k = currencyStyles[kIndex]; /* k = style */
        const char* localeString = DATA[i][0];
        double numberToBeFormat = atof(DATA[i][1]);
        const char* currencyISOCode = DATA[i][2];
        Locale locale(localeString);
        UErrorCode status = U_ZERO_ERROR;
        NumberFormat* numFmt = NumberFormat::createInstance(locale, k, status);
        logln("#%d NumberFormat(%s, %s) Currency=%s\n",
              i, localeString, currencyStyleNames[kIndex],
              currencyISOCode);

        if (U_FAILURE(status)) {
            delete numFmt;
            dataerrln((UnicodeString)"can not create instance, locale:" + localeString + ", style: " + k + " - " + u_errorName(status));
            continue;
        }
        UChar currencyCode[4];
        u_charsToUChars(currencyISOCode, currencyCode, 4);
        numFmt->setCurrency(currencyCode, status);
        if (U_FAILURE(status)) {
            delete numFmt;
            errln((UnicodeString)"can not set currency:" + currencyISOCode);
            continue;
        }

        UnicodeString strBuf;
        numFmt->format(numberToBeFormat, strBuf);
        int resultDataIndex = 3 + kIndex;
        // DATA[i][resultDataIndex] is the currency format result
        // using 'k' currency style.
        UnicodeString formatResult = ctou(DATA[i][resultDataIndex]);
        if (strBuf.compare(formatResult)) {
            errln("FAIL: Expected " + formatResult + " actual: " + strBuf);
        }
        // test parsing, and test parsing for all currency formats.
        // NOTE: ICU 62 requires that the currency format match the pattern in strict mode.
        numFmt->setLenient(TRUE);
        for (int j = 3; j < 6; ++j) {
            // DATA[i][3] is the currency format result using
            // CURRENCYSTYLE formatter.
            // DATA[i][4] is the currency format result using
            // ISOCURRENCYSTYLE formatter.
            // DATA[i][5] is the currency format result using
            // PLURALCURRENCYSTYLE formatter.
            UnicodeString oneCurrencyFormatResult = ctou(DATA[i][j]);
            UErrorCode status = U_ZERO_ERROR;
            Formattable parseResult;
            logln("parse(%s)", DATA[i][j]);
            numFmt->parse(oneCurrencyFormatResult, parseResult, status);
            if (U_FAILURE(status) ||
                (parseResult.getType() == Formattable::kDouble &&
                 parseResult.getDouble() != numberToBeFormat) ||
                (parseResult.getType() == Formattable::kLong &&
                 parseResult.getLong() != numberToBeFormat)) {
                errln((UnicodeString)"FAIL: NumberFormat(" + localeString +", " + currencyStyleNames[kIndex] +
                      "), Currency="+currencyISOCode+", parse("+DATA[i][j]+") returned error " + (UnicodeString)u_errorName(status)+".  Testcase: data[" + i + "][" + currencyStyleNames[j-3] +"="+j+"]");
                if (parseResult.getType() == Formattable::kDouble) {
                    errln((UnicodeString)"expected: " + numberToBeFormat + "; actual (double): " +parseResult.getDouble());
                } else {
                    errln((UnicodeString)"expected: " + numberToBeFormat + "; actual (long): " +parseResult.getLong());
                }
                errln((UnicodeString)" round-trip would be: " + strBuf);
            }
        }
        delete numFmt;
      }
    }
#ifdef NUMFMTST_CACHE_DEBUG
}
#endif
}


void
NumberFormatTest::TestParseCurrencyInUCurr() {
    const char* DATA[] = {
        "1.00 US DOLLAR",  // case in-sensitive
        "$1.00",
        "USD1.00",
        "US dollar1.00",
        "US dollars1.00",
        "$1.00",
        "A$1.00",
        "ADP1.00",
        "ADP1.00",
        "AED1.00",
        "AED1.00",
        "AFA1.00",
        "AFA1.00",
        "AFN1.00",
        "ALL1.00",
        "AMD1.00",
        "ANG1.00",
        "AOA1.00",
        "AOK1.00",
        "AOK1.00",
        "AON1.00",
        "AON1.00",
        "AOR1.00",
        "AOR1.00",
        "ARS1.00",
        "ARA1.00",
        "ARA1.00",
        "ARP1.00",
        "ARP1.00",
        "ARS1.00",
        "ATS1.00",
        "ATS1.00",
        "AUD1.00",
        "AWG1.00",
        "AZM1.00",
        "AZM1.00",
        "AZN1.00",
        "Afghan Afghani (1927\\u20132002)1.00",
        "Afghan afghani (1927\\u20132002)1.00",
        "Afghan Afghani1.00",
        "Afghan Afghanis1.00",
        "Albanian Lek1.00",
        "Albanian lek1.00",
        "Albanian lek\\u00eb1.00",
        "Algerian Dinar1.00",
        "Algerian dinar1.00",
        "Algerian dinars1.00",
        "Andorran Peseta1.00",
        "Andorran peseta1.00",
        "Andorran pesetas1.00",
        "Angolan Kwanza (1977\\u20131991)1.00",
        "Angolan Readjusted Kwanza (1995\\u20131999)1.00",
        "Angolan Kwanza1.00",
        "Angolan New Kwanza (1990\\u20132000)1.00",
        "Angolan kwanza (1977\\u20131991)1.00",
        "Angolan readjusted kwanza (1995\\u20131999)1.00",
        "Angolan kwanza1.00",
        "Angolan kwanzas (1977\\u20131991)1.00",
        "Angolan readjusted kwanzas (1995\\u20131999)1.00",
        "Angolan kwanzas1.00",
        "Angolan new kwanza (1990\\u20132000)1.00",
        "Angolan new kwanzas (1990\\u20132000)1.00",
        "Argentine Austral1.00",
        "Argentine Peso (1983\\u20131985)1.00",
        "Argentine Peso1.00",
        "Argentine austral1.00",
        "Argentine australs1.00",
        "Argentine peso (1983\\u20131985)1.00",
        "Argentine peso1.00",
        "Argentine pesos (1983\\u20131985)1.00",
        "Argentine pesos1.00",
        "Armenian Dram1.00",
        "Armenian dram1.00",
        "Armenian drams1.00",
        "Aruban Florin1.00",
        "Aruban florin1.00",
        "Australian Dollar1.00",
        "Australian dollar1.00",
        "Australian dollars1.00",
        "Austrian Schilling1.00",
        "Austrian schilling1.00",
        "Austrian schillings1.00",
        "Azerbaijani Manat (1993\\u20132006)1.00",
        "Azerbaijani Manat1.00",
        "Azerbaijani manat (1993\\u20132006)1.00",
        "Azerbaijani manat1.00",
        "Azerbaijani manats (1993\\u20132006)1.00",
        "Azerbaijani manats1.00",
        "BAD1.00",
        "BAD1.00",
        "BAM1.00",
        "BBD1.00",
        "BDT1.00",
        "BEC1.00",
        "BEC1.00",
        "BEF1.00",
        "BEL1.00",
        "BEL1.00",
        "BGL1.00",
        "BGN1.00",
        "BGN1.00",
        "BHD1.00",
        "BIF1.00",
        "BMD1.00",
        "BND1.00",
        "BOB1.00",
        "BOP1.00",
        "BOP1.00",
        "BOV1.00",
        "BOV1.00",
        "BRB1.00",
        "BRB1.00",
        "BRC1.00",
        "BRC1.00",
        "BRE1.00",
        "BRE1.00",
        "BRL1.00",
        "BRN1.00",
        "BRN1.00",
        "BRR1.00",
        "BRR1.00",
        "BSD1.00",
        "BSD1.00",
        "BTN1.00",
        "BUK1.00",
        "BUK1.00",
        "BWP1.00",
        "BYB1.00",
        "BYB1.00",
        "BYR1.00",
        "BZD1.00",
        "Bahamian Dollar1.00",
        "Bahamian dollar1.00",
        "Bahamian dollars1.00",
        "Bahraini Dinar1.00",
        "Bahraini dinar1.00",
        "Bahraini dinars1.00",
        "Bangladeshi Taka1.00",
        "Bangladeshi taka1.00",
        "Bangladeshi takas1.00",
        "Barbadian Dollar1.00",
        "Barbadian dollar1.00",
        "Barbadian dollars1.00",
        "Belarusian Ruble (1994\\u20131999)1.00",
        "Belarusian Ruble1.00",
        "Belarusian ruble (1994\\u20131999)1.00",
        "Belarusian rubles (1994\\u20131999)1.00",
        "Belarusian ruble1.00",
        "Belarusian rubles1.00",
        "Belgian Franc (convertible)1.00",
        "Belgian Franc (financial)1.00",
        "Belgian Franc1.00",
        "Belgian franc (convertible)1.00",
        "Belgian franc (financial)1.00",
        "Belgian franc1.00",
        "Belgian francs (convertible)1.00",
        "Belgian francs (financial)1.00",
        "Belgian francs1.00",
        "Belize Dollar1.00",
        "Belize dollar1.00",
        "Belize dollars1.00",
        "Bermudan Dollar1.00",
        "Bermudan dollar1.00",
        "Bermudan dollars1.00",
        "Bhutanese Ngultrum1.00",
        "Bhutanese ngultrum1.00",
        "Bhutanese ngultrums1.00",
        "Bolivian Mvdol1.00",
        "Bolivian Peso1.00",
        "Bolivian mvdol1.00",
        "Bolivian mvdols1.00",
        "Bolivian peso1.00",
        "Bolivian pesos1.00",
        "Bolivian Boliviano1.00",
        "Bolivian Boliviano1.00",
        "Bolivian Bolivianos1.00",
        "Bosnia-Herzegovina Convertible Mark1.00",
        "Bosnia-Herzegovina Dinar (1992\\u20131994)1.00",
        "Bosnia-Herzegovina convertible mark1.00",
        "Bosnia-Herzegovina convertible marks1.00",
        "Bosnia-Herzegovina dinar (1992\\u20131994)1.00",
        "Bosnia-Herzegovina dinars (1992\\u20131994)1.00",
        "Botswanan Pula1.00",
        "Botswanan pula1.00",
        "Botswanan pulas1.00",
        "Brazilian New Cruzado (1989\\u20131990)1.00",
        "Brazilian Cruzado (1986\\u20131989)1.00",
        "Brazilian Cruzeiro (1990\\u20131993)1.00",
        "Brazilian New Cruzeiro (1967\\u20131986)1.00",
        "Brazilian Cruzeiro (1993\\u20131994)1.00",
        "Brazilian Real1.00",
        "Brazilian new cruzado (1989\\u20131990)1.00",
        "Brazilian new cruzados (1989\\u20131990)1.00",
        "Brazilian cruzado (1986\\u20131989)1.00",
        "Brazilian cruzados (1986\\u20131989)1.00",
        "Brazilian cruzeiro (1990\\u20131993)1.00",
        "Brazilian new cruzeiro (1967\\u20131986)1.00",
        "Brazilian cruzeiro (1993\\u20131994)1.00",
        "Brazilian cruzeiros (1990\\u20131993)1.00",
        "Brazilian new cruzeiros (1967\\u20131986)1.00",
        "Brazilian cruzeiros (1993\\u20131994)1.00",
        "Brazilian real1.00",
        "Brazilian reals1.00",
        "British Pound1.00",
        "British pound1.00",
        "British pounds1.00",
        "Brunei Dollar1.00",
        "Brunei dollar1.00",
        "Brunei dollars1.00",
        "Bulgarian Hard Lev1.00",
        "Bulgarian Lev1.00",
        "Bulgarian Leva1.00",
        "Bulgarian hard lev1.00",
        "Bulgarian hard leva1.00",
        "Bulgarian lev1.00",
        "Burmese Kyat1.00",
        "Burmese kyat1.00",
        "Burmese kyats1.00",
        "Burundian Franc1.00",
        "Burundian franc1.00",
        "Burundian francs1.00",
        "CA$1.00",
        "CAD1.00",
        "CDF1.00",
        "CDF1.00",
        "West African CFA Franc1.00",
        "Central African CFA Franc1.00",
        "West African CFA franc1.00",
        "Central African CFA franc1.00",
        "West African CFA francs1.00",
        "Central African CFA francs1.00",
        "CFP Franc1.00",
        "CFP franc1.00",
        "CFP francs1.00",
        "CFPF1.00",
        "CHE1.00",
        "CHE1.00",
        "CHF1.00",
        "CHW1.00",
        "CHW1.00",
        "CLF1.00",
        "CLF1.00",
        "CLP1.00",
        "CNY1.00",
        "COP1.00",
        "COU1.00",
        "COU1.00",
        "CRC1.00",
        "CSD1.00",
        "CSD1.00",
        "CSK1.00",
        "CSK1.00",
        "CUP1.00",
        "CUP1.00",
        "CVE1.00",
        "CYP1.00",
        "CZK1.00",
        "Cambodian Riel1.00",
        "Cambodian riel1.00",
        "Cambodian riels1.00",
        "Canadian Dollar1.00",
        "Canadian dollar1.00",
        "Canadian dollars1.00",
        "Cape Verdean Escudo1.00",
        "Cape Verdean escudo1.00",
        "Cape Verdean escudos1.00",
        "Cayman Islands Dollar1.00",
        "Cayman Islands dollar1.00",
        "Cayman Islands dollars1.00",
        "Chilean Peso1.00",
        "Chilean Unit of Account (UF)1.00",
        "Chilean peso1.00",
        "Chilean pesos1.00",
        "Chilean unit of account (UF)1.00",
        "Chilean units of account (UF)1.00",
        "Chinese Yuan1.00",
        "Chinese yuan1.00",
        "Colombian Peso1.00",
        "Colombian peso1.00",
        "Colombian pesos1.00",
        "Comorian Franc1.00",
        "Comorian franc1.00",
        "Comorian francs1.00",
        "Congolese Franc1.00",
        "Congolese franc1.00",
        "Congolese francs1.00",
        "Costa Rican Col\\u00f3n1.00",
        "Costa Rican col\\u00f3n1.00",
        "Costa Rican col\\u00f3ns1.00",
        "Croatian Dinar1.00",
        "Croatian Kuna1.00",
        "Croatian dinar1.00",
        "Croatian dinars1.00",
        "Croatian kuna1.00",
        "Croatian kunas1.00",
        "Cuban Peso1.00",
        "Cuban peso1.00",
        "Cuban pesos1.00",
        "Cypriot Pound1.00",
        "Cypriot pound1.00",
        "Cypriot pounds1.00",
        "Czech Koruna1.00",
        "Czech koruna1.00",
        "Czech korunas1.00",
        "Czechoslovak Hard Koruna1.00",
        "Czechoslovak hard koruna1.00",
        "Czechoslovak hard korunas1.00",
        "DDM1.00",
        "DDM1.00",
        "DEM1.00",
        "DEM1.00",
        "DJF1.00",
        "DKK1.00",
        "DOP1.00",
        "DZD1.00",
        "Danish Krone1.00",
        "Danish krone1.00",
        "Danish kroner1.00",
        "German Mark1.00",
        "German mark1.00",
        "German marks1.00",
        "Djiboutian Franc1.00",
        "Djiboutian franc1.00",
        "Djiboutian francs1.00",
        "Dominican Peso1.00",
        "Dominican peso1.00",
        "Dominican pesos1.00",
        "EC$1.00",
        "ECS1.00",
        "ECS1.00",
        "ECV1.00",
        "ECV1.00",
        "EEK1.00",
        "EEK1.00",
        "EGP1.00",
        "EGP1.00",
        "ERN1.00",
        "ERN1.00",
        "ESA1.00",
        "ESA1.00",
        "ESB1.00",
        "ESB1.00",
        "ESP1.00",
        "ETB1.00",
        "EUR1.00",
        "East Caribbean Dollar1.00",
        "East Caribbean dollar1.00",
        "East Caribbean dollars1.00",
        "East German Mark1.00",
        "East German mark1.00",
        "East German marks1.00",
        "Ecuadorian Sucre1.00",
        "Ecuadorian Unit of Constant Value1.00",
        "Ecuadorian sucre1.00",
        "Ecuadorian sucres1.00",
        "Ecuadorian unit of constant value1.00",
        "Ecuadorian units of constant value1.00",
        "Egyptian Pound1.00",
        "Egyptian pound1.00",
        "Egyptian pounds1.00",
        "Salvadoran Col\\u00f3n1.00",
        "Salvadoran col\\u00f3n1.00",
        "Salvadoran colones1.00",
        "Equatorial Guinean Ekwele1.00",
        "Equatorial Guinean ekwele1.00",
        "Eritrean Nakfa1.00",
        "Eritrean nakfa1.00",
        "Eritrean nakfas1.00",
        "Estonian Kroon1.00",
        "Estonian kroon1.00",
        "Estonian kroons1.00",
        "Ethiopian Birr1.00",
        "Ethiopian birr1.00",
        "Ethiopian birrs1.00",
        "Euro1.00",
        "European Composite Unit1.00",
        "European Currency Unit1.00",
        "European Monetary Unit1.00",
        "European Unit of Account (XBC)1.00",
        "European Unit of Account (XBD)1.00",
        "European composite unit1.00",
        "European composite units1.00",
        "European currency unit1.00",
        "European currency units1.00",
        "European monetary unit1.00",
        "European monetary units1.00",
        "European unit of account (XBC)1.00",
        "European unit of account (XBD)1.00",
        "European units of account (XBC)1.00",
        "European units of account (XBD)1.00",
        "FIM1.00",
        "FIM1.00",
        "FJD1.00",
        "FKP1.00",
        "FKP1.00",
        "FRF1.00",
        "FRF1.00",
        "Falkland Islands Pound1.00",
        "Falkland Islands pound1.00",
        "Falkland Islands pounds1.00",
        "Fijian Dollar1.00",
        "Fijian dollar1.00",
        "Fijian dollars1.00",
        "Finnish Markka1.00",
        "Finnish markka1.00",
        "Finnish markkas1.00",
        "CHF1.00",
        "French Franc1.00",
        "French Gold Franc1.00",
        "French UIC-Franc1.00",
        "French UIC-franc1.00",
        "French UIC-francs1.00",
        "French franc1.00",
        "French francs1.00",
        "French gold franc1.00",
        "French gold francs1.00",
        "GBP1.00",
        "GEK1.00",
        "GEK1.00",
        "GEL1.00",
        "GHC1.00",
        "GHC1.00",
        "GHS1.00",
        "GIP1.00",
        "GIP1.00",
        "GMD1.00",
        "GMD1.00",
        "GNF1.00",
        "GNS1.00",
        "GNS1.00",
        "GQE1.00",
        "GQE1.00",
        "GRD1.00",
        "GRD1.00",
        "GTQ1.00",
        "GWE1.00",
        "GWE1.00",
        "GWP1.00",
        "GWP1.00",
        "GYD1.00",
        "Gambian Dalasi1.00",
        "Gambian dalasi1.00",
        "Gambian dalasis1.00",
        "Georgian Kupon Larit1.00",
        "Georgian Lari1.00",
        "Georgian kupon larit1.00",
        "Georgian kupon larits1.00",
        "Georgian lari1.00",
        "Georgian laris1.00",
        "Ghanaian Cedi (1979\\u20132007)1.00",
        "Ghanaian Cedi1.00",
        "Ghanaian cedi (1979\\u20132007)1.00",
        "Ghanaian cedi1.00",
        "Ghanaian cedis (1979\\u20132007)1.00",
        "Ghanaian cedis1.00",
        "Gibraltar Pound1.00",
        "Gibraltar pound1.00",
        "Gibraltar pounds1.00",
        "Gold1.00",
        "Gold1.00",
        "Greek Drachma1.00",
        "Greek drachma1.00",
        "Greek drachmas1.00",
        "Guatemalan Quetzal1.00",
        "Guatemalan quetzal1.00",
        "Guatemalan quetzals1.00",
        "Guinean Franc1.00",
        "Guinean Syli1.00",
        "Guinean franc1.00",
        "Guinean francs1.00",
        "Guinean syli1.00",
        "Guinean sylis1.00",
        "Guinea-Bissau Peso1.00",
        "Guinea-Bissau peso1.00",
        "Guinea-Bissau pesos1.00",
        "Guyanaese Dollar1.00",
        "Guyanaese dollar1.00",
        "Guyanaese dollars1.00",
        "HK$1.00",
        "HKD1.00",
        "HNL1.00",
        "HRD1.00",
        "HRD1.00",
        "HRK1.00",
        "HRK1.00",
        "HTG1.00",
        "HTG1.00",
        "HUF1.00",
        "Haitian Gourde1.00",
        "Haitian gourde1.00",
        "Haitian gourdes1.00",
        "Honduran Lempira1.00",
        "Honduran lempira1.00",
        "Honduran lempiras1.00",
        "Hong Kong Dollar1.00",
        "Hong Kong dollar1.00",
        "Hong Kong dollars1.00",
        "Hungarian Forint1.00",
        "Hungarian forint1.00",
        "Hungarian forints1.00",
        "IDR1.00",
        "IEP1.00",
        "ILP1.00",
        "ILP1.00",
        "ILS1.00",
        "INR1.00",
        "IQD1.00",
        "IRR1.00",
        "ISK1.00",
        "ISK1.00",
        "ITL1.00",
        "Icelandic Kr\\u00f3na1.00",
        "Icelandic kr\\u00f3na1.00",
        "Icelandic kr\\u00f3nur1.00",
        "Indian Rupee1.00",
        "Indian rupee1.00",
        "Indian rupees1.00",
        "Indonesian Rupiah1.00",
        "Indonesian rupiah1.00",
        "Indonesian rupiahs1.00",
        "Iranian Rial1.00",
        "Iranian rial1.00",
        "Iranian rials1.00",
        "Iraqi Dinar1.00",
        "Iraqi dinar1.00",
        "Iraqi dinars1.00",
        "Irish Pound1.00",
        "Irish pound1.00",
        "Irish pounds1.00",
        "Israeli Pound1.00",
        "Israeli new shekel1.00",
        "Israeli pound1.00",
        "Israeli pounds1.00",
        "Italian Lira1.00",
        "Italian lira1.00",
        "Italian liras1.00",
        "JMD1.00",
        "JOD1.00",
        "JPY1.00",
        "Jamaican Dollar1.00",
        "Jamaican dollar1.00",
        "Jamaican dollars1.00",
        "Japanese Yen1.00",
        "Japanese yen1.00",
        "Jordanian Dinar1.00",
        "Jordanian dinar1.00",
        "Jordanian dinars1.00",
        "KES1.00",
        "KGS1.00",
        "KHR1.00",
        "KMF1.00",
        "KPW1.00",
        "KPW1.00",
        "KRW1.00",
        "KWD1.00",
        "KYD1.00",
        "KYD1.00",
        "KZT1.00",
        "Kazakhstani Tenge1.00",
        "Kazakhstani tenge1.00",
        "Kazakhstani tenges1.00",
        "Kenyan Shilling1.00",
        "Kenyan shilling1.00",
        "Kenyan shillings1.00",
        "Kuwaiti Dinar1.00",
        "Kuwaiti dinar1.00",
        "Kuwaiti dinars1.00",
        "Kyrgystani Som1.00",
        "Kyrgystani som1.00",
        "Kyrgystani soms1.00",
        "HNL1.00",
        "LAK1.00",
        "LAK1.00",
        "LBP1.00",
        "LKR1.00",
        "LRD1.00",
        "LRD1.00",
        "LSL1.00",
        "LTL1.00",
        "LTL1.00",
        "LTT1.00",
        "LTT1.00",
        "LUC1.00",
        "LUC1.00",
        "LUF1.00",
        "LUF1.00",
        "LUL1.00",
        "LUL1.00",
        "LVL1.00",
        "LVL1.00",
        "LVR1.00",
        "LVR1.00",
        "LYD1.00",
        "Laotian Kip1.00",
        "Laotian kip1.00",
        "Laotian kips1.00",
        "Latvian Lats1.00",
        "Latvian Ruble1.00",
        "Latvian lats1.00",
        "Latvian lati1.00",
        "Latvian ruble1.00",
        "Latvian rubles1.00",
        "Lebanese Pound1.00",
        "Lebanese pound1.00",
        "Lebanese pounds1.00",
        "Lesotho Loti1.00",
        "Lesotho loti1.00",
        "Lesotho lotis1.00",
        "Liberian Dollar1.00",
        "Liberian dollar1.00",
        "Liberian dollars1.00",
        "Libyan Dinar1.00",
        "Libyan dinar1.00",
        "Libyan dinars1.00",
        "Lithuanian Litas1.00",
        "Lithuanian Talonas1.00",
        "Lithuanian litas1.00",
        "Lithuanian litai1.00",
        "Lithuanian talonas1.00",
        "Lithuanian talonases1.00",
        "Luxembourgian Convertible Franc1.00",
        "Luxembourg Financial Franc1.00",
        "Luxembourgian Franc1.00",
        "Luxembourgian convertible franc1.00",
        "Luxembourgian convertible francs1.00",
        "Luxembourg financial franc1.00",
        "Luxembourg financial francs1.00",
        "Luxembourgian franc1.00",
        "Luxembourgian francs1.00",
        "MAD1.00",
        "MAD1.00",
        "MAF1.00",
        "MAF1.00",
        "MDL1.00",
        "MDL1.00",
        "MX$1.00",
        "MGA1.00",
        "MGA1.00",
        "MGF1.00",
        "MGF1.00",
        "MKD1.00",
        "MLF1.00",
        "MLF1.00",
        "MMK1.00",
        "MMK1.00",
        "MNT1.00",
        "MOP1.00",
        "MOP1.00",
        "MRO1.00",
        "MTL1.00",
        "MTP1.00",
        "MTP1.00",
        "MUR1.00",
        "MUR1.00",
        "MVR1.00",
        "MVR1.00",
        "MWK1.00",
        "MXN1.00",
        "MXP1.00",
        "MXP1.00",
        "MXV1.00",
        "MXV1.00",
        "MYR1.00",
        "MZE1.00",
        "MZE1.00",
        "MZM1.00",
        "MZN1.00",
        "Macanese Pataca1.00",
        "Macanese pataca1.00",
        "Macanese patacas1.00",
        "Macedonian Denar1.00",
        "Macedonian denar1.00",
        "Macedonian denari1.00",
        "Malagasy Ariaries1.00",
        "Malagasy Ariary1.00",
        "Malagasy Ariary1.00",
        "Malagasy Franc1.00",
        "Malagasy franc1.00",
        "Malagasy francs1.00",
        "Malawian Kwacha1.00",
        "Malawian Kwacha1.00",
        "Malawian Kwachas1.00",
        "Malaysian Ringgit1.00",
        "Malaysian ringgit1.00",
        "Malaysian ringgits1.00",
        "Maldivian Rufiyaa1.00",
        "Maldivian rufiyaa1.00",
        "Maldivian rufiyaas1.00",
        "Malian Franc1.00",
        "Malian franc1.00",
        "Malian francs1.00",
        "Maltese Lira1.00",
        "Maltese Pound1.00",
        "Maltese lira1.00",
        "Maltese lira1.00",
        "Maltese pound1.00",
        "Maltese pounds1.00",
        "Mauritanian Ouguiya1.00",
        "Mauritanian ouguiya1.00",
        "Mauritanian ouguiyas1.00",
        "Mauritian Rupee1.00",
        "Mauritian rupee1.00",
        "Mauritian rupees1.00",
        "Mexican Peso1.00",
        "Mexican Silver Peso (1861\\u20131992)1.00",
        "Mexican Investment Unit1.00",
        "Mexican peso1.00",
        "Mexican pesos1.00",
        "Mexican silver peso (1861\\u20131992)1.00",
        "Mexican silver pesos (1861\\u20131992)1.00",
        "Mexican investment unit1.00",
        "Mexican investment units1.00",
        "Moldovan Leu1.00",
        "Moldovan leu1.00",
        "Moldovan lei1.00",
        "Mongolian Tugrik1.00",
        "Mongolian tugrik1.00",
        "Mongolian tugriks1.00",
        "Moroccan Dirham1.00",
        "Moroccan Franc1.00",
        "Moroccan dirham1.00",
        "Moroccan dirhams1.00",
        "Moroccan franc1.00",
        "Moroccan francs1.00",
        "Mozambican Escudo1.00",
        "Mozambican Metical1.00",
        "Mozambican escudo1.00",
        "Mozambican escudos1.00",
        "Mozambican metical1.00",
        "Mozambican meticals1.00",
        "Myanmar Kyat1.00",
        "Myanmar kyat1.00",
        "Myanmar kyats1.00",
        "NAD1.00",
        "NGN1.00",
        "NIC1.00",
        "NIO1.00",
        "NIO1.00",
        "NLG1.00",
        "NLG1.00",
        "NOK1.00",
        "NPR1.00",
        "NT$1.00",
        "NZ$1.00",
        "NZD1.00",
        "Namibian Dollar1.00",
        "Namibian dollar1.00",
        "Namibian dollars1.00",
        "Nepalese Rupee1.00",
        "Nepalese rupee1.00",
        "Nepalese rupees1.00",
        "Netherlands Antillean Guilder1.00",
        "Netherlands Antillean guilder1.00",
        "Netherlands Antillean guilders1.00",
        "Dutch Guilder1.00",
        "Dutch guilder1.00",
        "Dutch guilders1.00",
        "Israeli New Shekel1.00",
        "Israeli New Shekels1.00",
        "New Zealand Dollar1.00",
        "New Zealand dollar1.00",
        "New Zealand dollars1.00",
        "Nicaraguan C\\u00f3rdoba1.00",
        "Nicaraguan C\\u00f3rdoba (1988\\u20131991)1.00",
        "Nicaraguan c\\u00f3rdoba1.00",
        "Nicaraguan c\\u00f3rdobas1.00",
        "Nicaraguan c\\u00f3rdoba (1988\\u20131991)1.00",
        "Nicaraguan c\\u00f3rdobas (1988\\u20131991)1.00",
        "Nigerian Naira1.00",
        "Nigerian naira1.00",
        "Nigerian nairas1.00",
        "North Korean Won1.00",
        "North Korean won1.00",
        "North Korean won1.00",
        "Norwegian Krone1.00",
        "Norwegian krone1.00",
        "Norwegian kroner1.00",
        "OMR1.00",
        "Mozambican Metical (1980\\u20132006)1.00",
        "Mozambican metical (1980\\u20132006)1.00",
        "Mozambican meticals (1980\\u20132006)1.00",
        "Romanian Lei (1952\\u20132006)1.00",
        "Romanian Leu (1952\\u20132006)1.00",
        "Romanian leu (1952\\u20132006)1.00",
        "Serbian Dinar (2002\\u20132006)1.00",
        "Serbian dinar (2002\\u20132006)1.00",
        "Serbian dinars (2002\\u20132006)1.00",
        "Sudanese Dinar (1992\\u20132007)1.00",
        "Sudanese Pound (1957\\u20131998)1.00",
        "Sudanese dinar (1992\\u20132007)1.00",
        "Sudanese dinars (1992\\u20132007)1.00",
        "Sudanese pound (1957\\u20131998)1.00",
        "Sudanese pounds (1957\\u20131998)1.00",
        "Turkish Lira (1922\\u20132005)1.00",
        "Turkish Lira (1922\\u20132005)1.00",
        "Omani Rial1.00",
        "Omani rial1.00",
        "Omani rials1.00",
        "PAB1.00",
        "PAB1.00",
        "PEI1.00",
        "PEI1.00",
        "PEN1.00",
        "PEN1.00",
        "PES1.00",
        "PES1.00",
        "PGK1.00",
        "PGK1.00",
        "PHP1.00",
        "PKR1.00",
        "PLN1.00",
        "PLZ1.00",
        "PLZ1.00",
        "PTE1.00",
        "PTE1.00",
        "PYG1.00",
        "Pakistani Rupee1.00",
        "Pakistani rupee1.00",
        "Pakistani rupees1.00",
        "Palladium1.00",
        "Palladium1.00",
        "Panamanian Balboa1.00",
        "Panamanian balboa1.00",
        "Panamanian balboas1.00",
        "Papua New Guinean Kina1.00",
        "Papua New Guinean kina1.00",
        "Papua New Guinean kina1.00",
        "Paraguayan Guarani1.00",
        "Paraguayan guarani1.00",
        "Paraguayan guaranis1.00",
        "Peruvian Inti1.00",
        "Peruvian Sol1.00",
        "Peruvian Sol (1863\\u20131965)1.00",
        "Peruvian inti1.00",
        "Peruvian intis1.00",
        "Peruvian sol1.00",
        "Peruvian soles1.00",
        "Peruvian sol (1863\\u20131965)1.00",
        "Peruvian soles (1863\\u20131965)1.00",
        "Philippine Piso1.00",
        "Philippine piso1.00",
        "Philippine pisos1.00",
        "Platinum1.00",
        "Platinum1.00",
        "Polish Zloty (1950\\u20131995)1.00",
        "Polish Zloty1.00",
        "Polish zlotys1.00",
        "Polish zloty (PLZ)1.00",
        "Polish zloty1.00",
        "Polish zlotys (PLZ)1.00",
        "Portuguese Escudo1.00",
        "Portuguese Guinea Escudo1.00",
        "Portuguese Guinea escudo1.00",
        "Portuguese Guinea escudos1.00",
        "Portuguese escudo1.00",
        "Portuguese escudos1.00",
        "GTQ1.00",
        "QAR1.00",
        "Qatari Rial1.00",
        "Qatari rial1.00",
        "Qatari rials1.00",
        "RHD1.00",
        "RHD1.00",
        "RINET Funds1.00",
        "RINET Funds1.00",
        "CN\\u00a51.00",
        "ROL1.00",
        "ROL1.00",
        "RON1.00",
        "RON1.00",
        "RSD1.00",
        "RSD1.00",
        "RUB1.00",
        "RUR1.00",
        "RUR1.00",
        "RWF1.00",
        "RWF1.00",
        "Rhodesian Dollar1.00",
        "Rhodesian dollar1.00",
        "Rhodesian dollars1.00",
        "Romanian Leu1.00",
        "Romanian lei1.00",
        "Romanian leu1.00",
        "Russian Ruble (1991\\u20131998)1.00",
        "Russian Ruble1.00",
        "Russian ruble (1991\\u20131998)1.00",
        "Russian ruble1.00",
        "Russian rubles (1991\\u20131998)1.00",
        "Russian rubles1.00",
        "Rwandan Franc1.00",
        "Rwandan franc1.00",
        "Rwandan francs1.00",
        "SAR1.00",
        "SBD1.00",
        "SCR1.00",
        "SDD1.00",
        "SDD1.00",
        "SDG1.00",
        "SDG1.00",
        "SDP1.00",
        "SDP1.00",
        "SEK1.00",
        "SGD1.00",
        "SHP1.00",
        "SHP1.00",
        "SIT1.00",
        "SIT1.00",
        "SKK1.00",
        "SLL1.00",
        "SLL1.00",
        "SOS1.00",
        "SRD1.00",
        "SRD1.00",
        "SRG1.00",
        "STD1.00",
        "SUR1.00",
        "SUR1.00",
        "SVC1.00",
        "SVC1.00",
        "SYP1.00",
        "SZL1.00",
        "St. Helena Pound1.00",
        "St. Helena pound1.00",
        "St. Helena pounds1.00",
        "S\\u00e3o Tom\\u00e9 & Pr\\u00edncipe Dobra1.00",
        "S\\u00e3o Tom\\u00e9 & Pr\\u00edncipe dobra1.00",
        "S\\u00e3o Tom\\u00e9 & Pr\\u00edncipe dobras1.00",
        "Saudi Riyal1.00",
        "Saudi riyal1.00",
        "Saudi riyals1.00",
        "Serbian Dinar1.00",
        "Serbian dinar1.00",
        "Serbian dinars1.00",
        "Seychellois Rupee1.00",
        "Seychellois rupee1.00",
        "Seychellois rupees1.00",
        "Sierra Leonean Leone1.00",
        "Sierra Leonean leone1.00",
        "Sierra Leonean leones1.00",
        "Silver1.00",
        "Silver1.00",
        "Singapore Dollar1.00",
        "Singapore dollar1.00",
        "Singapore dollars1.00",
        "Slovak Koruna1.00",
        "Slovak koruna1.00",
        "Slovak korunas1.00",
        "Slovenian Tolar1.00",
        "Slovenian tolar1.00",
        "Slovenian tolars1.00",
        "Solomon Islands Dollar1.00",
        "Solomon Islands dollar1.00",
        "Solomon Islands dollars1.00",
        "Somali Shilling1.00",
        "Somali shilling1.00",
        "Somali shillings1.00",
        "South African Rand (financial)1.00",
        "South African Rand1.00",
        "South African rand (financial)1.00",
        "South African rand1.00",
        "South African rands (financial)1.00",
        "South African rand1.00",
        "South Korean Won1.00",
        "South Korean won1.00",
        "South Korean won1.00",
        "Soviet Rouble1.00",
        "Soviet rouble1.00",
        "Soviet roubles1.00",
        "Spanish Peseta (A account)1.00",
        "Spanish Peseta (convertible account)1.00",
        "Spanish Peseta1.00",
        "Spanish peseta (A account)1.00",
        "Spanish peseta (convertible account)1.00",
        "Spanish peseta1.00",
        "Spanish pesetas (A account)1.00",
        "Spanish pesetas (convertible account)1.00",
        "Spanish pesetas1.00",
        "Special Drawing Rights1.00",
        "Sri Lankan Rupee1.00",
        "Sri Lankan rupee1.00",
        "Sri Lankan rupees1.00",
        "Sudanese Pound1.00",
        "Sudanese pound1.00",
        "Sudanese pounds1.00",
        "Surinamese Dollar1.00",
        "Surinamese dollar1.00",
        "Surinamese dollars1.00",
        "Surinamese Guilder1.00",
        "Surinamese guilder1.00",
        "Surinamese guilders1.00",
        "Swazi Lilangeni1.00",
        "Swazi lilangeni1.00",
        "Swazi emalangeni1.00",
        "Swedish Krona1.00",
        "Swedish krona1.00",
        "Swedish kronor1.00",
        "Swiss Franc1.00",
        "Swiss franc1.00",
        "Swiss francs1.00",
        "Syrian Pound1.00",
        "Syrian pound1.00",
        "Syrian pounds1.00",
        "THB1.00",
        "TJR1.00",
        "TJR1.00",
        "TJS1.00",
        "TJS1.00",
        "TMM1.00",
        "TMM1.00",
        "TND1.00",
        "TND1.00",
        "TOP1.00",
        "TPE1.00",
        "TPE1.00",
        "TRL1.00",
        "TRY1.00",
        "TRY1.00",
        "TTD1.00",
        "TWD1.00",
        "TZS1.00",
        "New Taiwan Dollar1.00",
        "New Taiwan dollar1.00",
        "New Taiwan dollars1.00",
        "Tajikistani Ruble1.00",
        "Tajikistani Somoni1.00",
        "Tajikistani ruble1.00",
        "Tajikistani rubles1.00",
        "Tajikistani somoni1.00",
        "Tajikistani somonis1.00",
        "Tanzanian Shilling1.00",
        "Tanzanian shilling1.00",
        "Tanzanian shillings1.00",
        "Testing Currency Code1.00",
        "Testing Currency Code1.00",
        "Thai Baht1.00",
        "Thai baht1.00",
        "Thai baht1.00",
        "Timorese Escudo1.00",
        "Timorese escudo1.00",
        "Timorese escudos1.00",
        "Tongan Pa\\u02bbanga1.00",
        "Tongan pa\\u02bbanga1.00",
        "Tongan pa\\u02bbanga1.00",
        "Trinidad & Tobago Dollar1.00",
        "Trinidad & Tobago dollar1.00",
        "Trinidad & Tobago dollars1.00",
        "Tunisian Dinar1.00",
        "Tunisian dinar1.00",
        "Tunisian dinars1.00",
        "Turkish Lira1.00",
        "Turkish Lira1.00",
        "Turkish lira1.00",
        "Turkmenistani Manat1.00",
        "Turkmenistani manat1.00",
        "Turkmenistani manat1.00",
        "UAE dirham1.00",
        "UAE dirhams1.00",
        "UAH1.00",
        "UAK1.00",
        "UAK1.00",
        "UGS1.00",
        "UGS1.00",
        "UGX1.00",
        "US Dollar (Next day)1.00",
        "US Dollar (Same day)1.00",
        "US Dollar1.00",
        "US dollar (next day)1.00",
        "US dollar (same day)1.00",
        "US dollar1.00",
        "US dollars (next day)1.00",
        "US dollars (same day)1.00",
        "US dollars1.00",
        "USD1.00",
        "USN1.00",
        "USN1.00",
        "USS1.00",
        "USS1.00",
        "UYI1.00",
        "UYI1.00",
        "UYP1.00",
        "UYP1.00",
        "UYU1.00",
        "UZS1.00",
        "UZS1.00",
        "Ugandan Shilling (1966\\u20131987)1.00",
        "Ugandan Shilling1.00",
        "Ugandan shilling (1966\\u20131987)1.00",
        "Ugandan shilling1.00",
        "Ugandan shillings (1966\\u20131987)1.00",
        "Ugandan shillings1.00",
        "Ukrainian Hryvnia1.00",
        "Ukrainian Karbovanets1.00",
        "Ukrainian hryvnia1.00",
        "Ukrainian hryvnias1.00",
        "Ukrainian karbovanets1.00",
        "Ukrainian karbovantsiv1.00",
        "Colombian Real Value Unit1.00",
        "United Arab Emirates Dirham1.00",
        "Unknown Currency1.00",
        "Uruguayan Peso (1975\\u20131993)1.00",
        "Uruguayan Peso1.00",
        "Uruguayan Peso (Indexed Units)1.00",
        "Uruguayan peso (1975\\u20131993)1.00",
        "Uruguayan peso (indexed units)1.00",
        "Uruguayan peso1.00",
        "Uruguayan pesos (1975\\u20131993)1.00",
        "Uruguayan pesos (indexed units)1.00",
        "Uruguayan pesos1.00",
        "Uzbekistani Som1.00",
        "Uzbekistani som1.00",
        "Uzbekistani som1.00",
        "VEB1.00",
        "VEF1.00",
        "VND1.00",
        "VUV1.00",
        "Vanuatu Vatu1.00",
        "Vanuatu vatu1.00",
        "Vanuatu vatus1.00",
        "Venezuelan Bol\\u00edvar1.00",
        "Venezuelan Bol\\u00edvar (1871\\u20132008)1.00",
        "Venezuelan bol\\u00edvar1.00",
        "Venezuelan bol\\u00edvars1.00",
        "Venezuelan bol\\u00edvar (1871\\u20132008)1.00",
        "Venezuelan bol\\u00edvars (1871\\u20132008)1.00",
        "Vietnamese Dong1.00",
        "Vietnamese dong1.00",
        "Vietnamese dong1.00",
        "WIR Euro1.00",
        "WIR Franc1.00",
        "WIR euro1.00",
        "WIR euros1.00",
        "WIR franc1.00",
        "WIR francs1.00",
        "WST1.00",
        "WST1.00",
        "Samoan Tala1.00",
        "Samoan tala1.00",
        "Samoan tala1.00",
        "XAF1.00",
        "XAF1.00",
        "XAG1.00",
        "XAG1.00",
        "XAU1.00",
        "XAU1.00",
        "XBA1.00",
        "XBA1.00",
        "XBB1.00",
        "XBB1.00",
        "XBC1.00",
        "XBC1.00",
        "XBD1.00",
        "XBD1.00",
        "XCD1.00",
        "XDR1.00",
        "XDR1.00",
        "XEU1.00",
        "XEU1.00",
        "XFO1.00",
        "XFO1.00",
        "XFU1.00",
        "XFU1.00",
        "XOF1.00",
        "XOF1.00",
        "XPD1.00",
        "XPD1.00",
        "XPF1.00",
        "XPT1.00",
        "XPT1.00",
        "XRE1.00",
        "XRE1.00",
        "XTS1.00",
        "XTS1.00",
        "XXX1.00",
        "XXX1.00",
        "YDD1.00",
        "YDD1.00",
        "YER1.00",
        "YUD1.00",
        "YUD1.00",
        "YUM1.00",
        "YUM1.00",
        "YUN1.00",
        "YUN1.00",
        "Yemeni Dinar1.00",
        "Yemeni Rial1.00",
        "Yemeni dinar1.00",
        "Yemeni dinars1.00",
        "Yemeni rial1.00",
        "Yemeni rials1.00",
        "Yugoslavian Convertible Dinar (1990\\u20131992)1.00",
        "Yugoslavian Hard Dinar (1966\\u20131990)1.00",
        "Yugoslavian New Dinar (1994\\u20132002)1.00",
        "Yugoslavian convertible dinar (1990\\u20131992)1.00",
        "Yugoslavian convertible dinars (1990\\u20131992)1.00",
        "Yugoslavian hard dinar (1966\\u20131990)1.00",
        "Yugoslavian hard dinars (1966\\u20131990)1.00",
        "Yugoslavian new dinar (1994\\u20132002)1.00",
        "Yugoslavian new dinars (1994\\u20132002)1.00",
        "ZAL1.00",
        "ZAL1.00",
        "ZAR1.00",
        "ZMK1.00",
        "ZMK1.00",
        "ZRN1.00",
        "ZRN1.00",
        "ZRZ1.00",
        "ZRZ1.00",
        "ZWD1.00",
        "Zairean New Zaire (1993\\u20131998)1.00",
        "Zairean Zaire (1971\\u20131993)1.00",
        "Zairean new zaire (1993\\u20131998)1.00",
        "Zairean new zaires (1993\\u20131998)1.00",
        "Zairean zaire (1971\\u20131993)1.00",
        "Zairean zaires (1971\\u20131993)1.00",
        "Zambian Kwacha1.00",
        "Zambian kwacha1.00",
        "Zambian kwachas1.00",
        "Zimbabwean Dollar (1980\\u20132008)1.00",
        "Zimbabwean dollar (1980\\u20132008)1.00",
        "Zimbabwean dollars (1980\\u20132008)1.00",
        "euro1.00",
        "euros1.00",
        "Turkish lira (1922\\u20132005)1.00",
        "special drawing rights1.00",
        "Colombian real value unit1.00",
        "Colombian real value units1.00",
        "unknown currency1.00",
        "\\u00a31.00",
        "\\u00a51.00",
        "\\u20ab1.00",
        "\\u20aa1.00",
        "\\u20ac1.00",
        "\\u20b91.00",
        //
        // Following has extra text, should be parsed correctly too
        "$1.00 random",
        "USD1.00 random",
        "1.00 US dollar random",
        "1.00 US dollars random",
        "1.00 Afghan Afghani random",
        "1.00 Afghan Afghani random",
        "1.00 Afghan Afghanis (1927\\u20131992) random",
        "1.00 Afghan Afghanis random",
        "1.00 Albanian Lek random",
        "1.00 Albanian lek random",
        "1.00 Albanian lek\\u00eb random",
        "1.00 Algerian Dinar random",
        "1.00 Algerian dinar random",
        "1.00 Algerian dinars random",
        "1.00 Andorran Peseta random",
        "1.00 Andorran peseta random",
        "1.00 Andorran pesetas random",
        "1.00 Angolan Kwanza (1977\\u20131990) random",
        "1.00 Angolan Readjusted Kwanza (1995\\u20131999) random",
        "1.00 Angolan Kwanza random",
        "1.00 Angolan New Kwanza (1990\\u20132000) random",
        "1.00 Angolan kwanza (1977\\u20131991) random",
        "1.00 Angolan readjusted kwanza (1995\\u20131999) random",
        "1.00 Angolan kwanza random",
        "1.00 Angolan kwanzas (1977\\u20131991) random",
        "1.00 Angolan readjusted kwanzas (1995\\u20131999) random",
        "1.00 Angolan kwanzas random",
        "1.00 Angolan new kwanza (1990\\u20132000) random",
        "1.00 Angolan new kwanzas (1990\\u20132000) random",
        "1.00 Argentine Austral random",
        "1.00 Argentine Peso (1983\\u20131985) random",
        "1.00 Argentine Peso random",
        "1.00 Argentine austral random",
        "1.00 Argentine australs random",
        "1.00 Argentine peso (1983\\u20131985) random",
        "1.00 Argentine peso random",
        "1.00 Argentine pesos (1983\\u20131985) random",
        "1.00 Argentine pesos random",
        "1.00 Armenian Dram random",
        "1.00 Armenian dram random",
        "1.00 Armenian drams random",
        "1.00 Aruban Florin random",
        "1.00 Aruban florin random",
        "1.00 Australian Dollar random",
        "1.00 Australian dollar random",
        "1.00 Australian dollars random",
        "1.00 Austrian Schilling random",
        "1.00 Austrian schilling random",
        "1.00 Austrian schillings random",
        "1.00 Azerbaijani Manat (1993\\u20132006) random",
        "1.00 Azerbaijani Manat random",
        "1.00 Azerbaijani manat (1993\\u20132006) random",
        "1.00 Azerbaijani manat random",
        "1.00 Azerbaijani manats (1993\\u20132006) random",
        "1.00 Azerbaijani manats random",
        "1.00 Bahamian Dollar random",
        "1.00 Bahamian dollar random",
        "1.00 Bahamian dollars random",
        "1.00 Bahraini Dinar random",
        "1.00 Bahraini dinar random",
        "1.00 Bahraini dinars random",
        "1.00 Bangladeshi Taka random",
        "1.00 Bangladeshi taka random",
        "1.00 Bangladeshi takas random",
        "1.00 Barbadian Dollar random",
        "1.00 Barbadian dollar random",
        "1.00 Barbadian dollars random",
        "1.00 Belarusian Ruble (1994\\u20131999) random",
        "1.00 Belarusian Ruble random",
        "1.00 Belarusian ruble (1994\\u20131999) random",
        "1.00 Belarusian rubles (1994\\u20131999) random",
        "1.00 Belarusian ruble random",
        "1.00 Belarusian rubles random",
        "1.00 Belgian Franc (convertible) random",
        "1.00 Belgian Franc (financial) random",
        "1.00 Belgian Franc random",
        "1.00 Belgian franc (convertible) random",
        "1.00 Belgian franc (financial) random",
        "1.00 Belgian franc random",
        "1.00 Belgian francs (convertible) random",
        "1.00 Belgian francs (financial) random",
        "1.00 Belgian francs random",
        "1.00 Belize Dollar random",
        "1.00 Belize dollar random",
        "1.00 Belize dollars random",
        "1.00 Bermudan Dollar random",
        "1.00 Bermudan dollar random",
        "1.00 Bermudan dollars random",
        "1.00 Bhutanese Ngultrum random",
        "1.00 Bhutanese ngultrum random",
        "1.00 Bhutanese ngultrums random",
        "1.00 Bolivian Mvdol random",
        "1.00 Bolivian Peso random",
        "1.00 Bolivian mvdol random",
        "1.00 Bolivian mvdols random",
        "1.00 Bolivian peso random",
        "1.00 Bolivian pesos random",
        "1.00 Bolivian Boliviano random",
        "1.00 Bolivian Boliviano random",
        "1.00 Bolivian Bolivianos random",
        "1.00 Bosnia-Herzegovina Convertible Mark random",
        "1.00 Bosnia-Herzegovina Dinar (1992\\u20131994) random",
        "1.00 Bosnia-Herzegovina convertible mark random",
        "1.00 Bosnia-Herzegovina convertible marks random",
        "1.00 Bosnia-Herzegovina dinar (1992\\u20131994) random",
        "1.00 Bosnia-Herzegovina dinars (1992\\u20131994) random",
        "1.00 Botswanan Pula random",
        "1.00 Botswanan pula random",
        "1.00 Botswanan pulas random",
        "1.00 Brazilian New Cruzado (1989\\u20131990) random",
        "1.00 Brazilian Cruzado (1986\\u20131989) random",
        "1.00 Brazilian Cruzeiro (1990\\u20131993) random",
        "1.00 Brazilian New Cruzeiro (1967\\u20131986) random",
        "1.00 Brazilian Cruzeiro (1993\\u20131994) random",
        "1.00 Brazilian Real random",
        "1.00 Brazilian new cruzado (1989\\u20131990) random",
        "1.00 Brazilian new cruzados (1989\\u20131990) random",
        "1.00 Brazilian cruzado (1986\\u20131989) random",
        "1.00 Brazilian cruzados (1986\\u20131989) random",
        "1.00 Brazilian cruzeiro (1990\\u20131993) random",
        "1.00 Brazilian new cruzeiro (1967\\u20131986) random",
        "1.00 Brazilian cruzeiro (1993\\u20131994) random",
        "1.00 Brazilian cruzeiros (1990\\u20131993) random",
        "1.00 Brazilian new cruzeiros (1967\\u20131986) random",
        "1.00 Brazilian cruzeiros (1993\\u20131994) random",
        "1.00 Brazilian real random",
        "1.00 Brazilian reals random",
        "1.00 British Pound random",
        "1.00 British pound random",
        "1.00 British pounds random",
        "1.00 Brunei Dollar random",
        "1.00 Brunei dollar random",
        "1.00 Brunei dollars random",
        "1.00 Bulgarian Hard Lev random",
        "1.00 Bulgarian Lev random",
        "1.00 Bulgarian Leva random",
        "1.00 Bulgarian hard lev random",
        "1.00 Bulgarian hard leva random",
        "1.00 Bulgarian lev random",
        "1.00 Burmese Kyat random",
        "1.00 Burmese kyat random",
        "1.00 Burmese kyats random",
        "1.00 Burundian Franc random",
        "1.00 Burundian franc random",
        "1.00 Burundian francs random",
        "1.00 Cambodian Riel random",
        "1.00 Cambodian riel random",
        "1.00 Cambodian riels random",
        "1.00 Canadian Dollar random",
        "1.00 Canadian dollar random",
        "1.00 Canadian dollars random",
        "1.00 Cape Verdean Escudo random",
        "1.00 Cape Verdean escudo random",
        "1.00 Cape Verdean escudos random",
        "1.00 Cayman Islands Dollar random",
        "1.00 Cayman Islands dollar random",
        "1.00 Cayman Islands dollars random",
        "1.00 Chilean Peso random",
        "1.00 Chilean Unit of Account (UF) random",
        "1.00 Chilean peso random",
        "1.00 Chilean pesos random",
        "1.00 Chilean unit of account (UF) random",
        "1.00 Chilean units of account (UF) random",
        "1.00 Chinese Yuan random",
        "1.00 Chinese yuan random",
        "1.00 Colombian Peso random",
        "1.00 Colombian peso random",
        "1.00 Colombian pesos random",
        "1.00 Comorian Franc random",
        "1.00 Comorian franc random",
        "1.00 Comorian francs random",
        "1.00 Congolese Franc Congolais random",
        "1.00 Congolese franc Congolais random",
        "1.00 Congolese francs Congolais random",
        "1.00 Costa Rican Col\\u00f3n random",
        "1.00 Costa Rican col\\u00f3n random",
        "1.00 Costa Rican col\\u00f3ns random",
        "1.00 Croatian Dinar random",
        "1.00 Croatian Kuna random",
        "1.00 Croatian dinar random",
        "1.00 Croatian dinars random",
        "1.00 Croatian kuna random",
        "1.00 Croatian kunas random",
        "1.00 Cuban Peso random",
        "1.00 Cuban peso random",
        "1.00 Cuban pesos random",
        "1.00 Cypriot Pound random",
        "1.00 Cypriot pound random",
        "1.00 Cypriot pounds random",
        "1.00 Czech Koruna random",
        "1.00 Czech koruna random",
        "1.00 Czech korunas random",
        "1.00 Czechoslovak Hard Koruna random",
        "1.00 Czechoslovak hard koruna random",
        "1.00 Czechoslovak hard korunas random",
        "1.00 Danish Krone random",
        "1.00 Danish krone random",
        "1.00 Danish kroner random",
        "1.00 German Mark random",
        "1.00 German mark random",
        "1.00 German marks random",
        "1.00 Djiboutian Franc random",
        "1.00 Djiboutian franc random",
        "1.00 Djiboutian francs random",
        "1.00 Dominican Peso random",
        "1.00 Dominican peso random",
        "1.00 Dominican pesos random",
        "1.00 East Caribbean Dollar random",
        "1.00 East Caribbean dollar random",
        "1.00 East Caribbean dollars random",
        "1.00 East German Mark random",
        "1.00 East German mark random",
        "1.00 East German marks random",
        "1.00 Ecuadorian Sucre random",
        "1.00 Ecuadorian Unit of Constant Value random",
        "1.00 Ecuadorian sucre random",
        "1.00 Ecuadorian sucres random",
        "1.00 Ecuadorian unit of constant value random",
        "1.00 Ecuadorian units of constant value random",
        "1.00 Egyptian Pound random",
        "1.00 Egyptian pound random",
        "1.00 Egyptian pounds random",
        "1.00 Salvadoran Col\\u00f3n random",
        "1.00 Salvadoran col\\u00f3n random",
        "1.00 Salvadoran colones random",
        "1.00 Equatorial Guinean Ekwele random",
        "1.00 Equatorial Guinean ekwele random",
        "1.00 Eritrean Nakfa random",
        "1.00 Eritrean nakfa random",
        "1.00 Eritrean nakfas random",
        "1.00 Estonian Kroon random",
        "1.00 Estonian kroon random",
        "1.00 Estonian kroons random",
        "1.00 Ethiopian Birr random",
        "1.00 Ethiopian birr random",
        "1.00 Ethiopian birrs random",
        "1.00 European Composite Unit random",
        "1.00 European Currency Unit random",
        "1.00 European Monetary Unit random",
        "1.00 European Unit of Account (XBC) random",
        "1.00 European Unit of Account (XBD) random",
        "1.00 European composite unit random",
        "1.00 European composite units random",
        "1.00 European currency unit random",
        "1.00 European currency units random",
        "1.00 European monetary unit random",
        "1.00 European monetary units random",
        "1.00 European unit of account (XBC) random",
        "1.00 European unit of account (XBD) random",
        "1.00 European units of account (XBC) random",
        "1.00 European units of account (XBD) random",
        "1.00 Falkland Islands Pound random",
        "1.00 Falkland Islands pound random",
        "1.00 Falkland Islands pounds random",
        "1.00 Fijian Dollar random",
        "1.00 Fijian dollar random",
        "1.00 Fijian dollars random",
        "1.00 Finnish Markka random",
        "1.00 Finnish markka random",
        "1.00 Finnish markkas random",
        "1.00 French Franc random",
        "1.00 French Gold Franc random",
        "1.00 French UIC-Franc random",
        "1.00 French UIC-franc random",
        "1.00 French UIC-francs random",
        "1.00 French franc random",
        "1.00 French francs random",
        "1.00 French gold franc random",
        "1.00 French gold francs random",
        "1.00 Gambian Dalasi random",
        "1.00 Gambian dalasi random",
        "1.00 Gambian dalasis random",
        "1.00 Georgian Kupon Larit random",
        "1.00 Georgian Lari random",
        "1.00 Georgian kupon larit random",
        "1.00 Georgian kupon larits random",
        "1.00 Georgian lari random",
        "1.00 Georgian laris random",
        "1.00 Ghanaian Cedi (1979\\u20132007) random",
        "1.00 Ghanaian Cedi random",
        "1.00 Ghanaian cedi (1979\\u20132007) random",
        "1.00 Ghanaian cedi random",
        "1.00 Ghanaian cedis (1979\\u20132007) random",
        "1.00 Ghanaian cedis random",
        "1.00 Gibraltar Pound random",
        "1.00 Gibraltar pound random",
        "1.00 Gibraltar pounds random",
        "1.00 Gold random",
        "1.00 Gold random",
        "1.00 Greek Drachma random",
        "1.00 Greek drachma random",
        "1.00 Greek drachmas random",
        "1.00 Guatemalan Quetzal random",
        "1.00 Guatemalan quetzal random",
        "1.00 Guatemalan quetzals random",
        "1.00 Guinean Franc random",
        "1.00 Guinean Syli random",
        "1.00 Guinean franc random",
        "1.00 Guinean francs random",
        "1.00 Guinean syli random",
        "1.00 Guinean sylis random",
        "1.00 Guinea-Bissau Peso random",
        "1.00 Guinea-Bissau peso random",
        "1.00 Guinea-Bissau pesos random",
        "1.00 Guyanaese Dollar random",
        "1.00 Guyanaese dollar random",
        "1.00 Guyanaese dollars random",
        "1.00 Haitian Gourde random",
        "1.00 Haitian gourde random",
        "1.00 Haitian gourdes random",
        "1.00 Honduran Lempira random",
        "1.00 Honduran lempira random",
        "1.00 Honduran lempiras random",
        "1.00 Hong Kong Dollar random",
        "1.00 Hong Kong dollar random",
        "1.00 Hong Kong dollars random",
        "1.00 Hungarian Forint random",
        "1.00 Hungarian forint random",
        "1.00 Hungarian forints random",
        "1.00 Icelandic Kr\\u00f3na random",
        "1.00 Icelandic kr\\u00f3na random",
        "1.00 Icelandic kr\\u00f3nur random",
        "1.00 Indian Rupee random",
        "1.00 Indian rupee random",
        "1.00 Indian rupees random",
        "1.00 Indonesian Rupiah random",
        "1.00 Indonesian rupiah random",
        "1.00 Indonesian rupiahs random",
        "1.00 Iranian Rial random",
        "1.00 Iranian rial random",
        "1.00 Iranian rials random",
        "1.00 Iraqi Dinar random",
        "1.00 Iraqi dinar random",
        "1.00 Iraqi dinars random",
        "1.00 Irish Pound random",
        "1.00 Irish pound random",
        "1.00 Irish pounds random",
        "1.00 Israeli Pound random",
        "1.00 Israeli new shekel random",
        "1.00 Israeli pound random",
        "1.00 Israeli pounds random",
        "1.00 Italian Lira random",
        "1.00 Italian lira random",
        "1.00 Italian liras random",
        "1.00 Jamaican Dollar random",
        "1.00 Jamaican dollar random",
        "1.00 Jamaican dollars random",
        "1.00 Japanese Yen random",
        "1.00 Japanese yen random",
        "1.00 Jordanian Dinar random",
        "1.00 Jordanian dinar random",
        "1.00 Jordanian dinars random",
        "1.00 Kazakhstani Tenge random",
        "1.00 Kazakhstani tenge random",
        "1.00 Kazakhstani tenges random",
        "1.00 Kenyan Shilling random",
        "1.00 Kenyan shilling random",
        "1.00 Kenyan shillings random",
        "1.00 Kuwaiti Dinar random",
        "1.00 Kuwaiti dinar random",
        "1.00 Kuwaiti dinars random",
        "1.00 Kyrgystani Som random",
        "1.00 Kyrgystani som random",
        "1.00 Kyrgystani soms random",
        "1.00 Laotian Kip random",
        "1.00 Laotian kip random",
        "1.00 Laotian kips random",
        "1.00 Latvian Lats random",
        "1.00 Latvian Ruble random",
        "1.00 Latvian lats random",
        "1.00 Latvian lati random",
        "1.00 Latvian ruble random",
        "1.00 Latvian rubles random",
        "1.00 Lebanese Pound random",
        "1.00 Lebanese pound random",
        "1.00 Lebanese pounds random",
        "1.00 Lesotho Loti random",
        "1.00 Lesotho loti random",
        "1.00 Lesotho lotis random",
        "1.00 Liberian Dollar random",
        "1.00 Liberian dollar random",
        "1.00 Liberian dollars random",
        "1.00 Libyan Dinar random",
        "1.00 Libyan dinar random",
        "1.00 Libyan dinars random",
        "1.00 Lithuanian Litas random",
        "1.00 Lithuanian Talonas random",
        "1.00 Lithuanian litas random",
        "1.00 Lithuanian litai random",
        "1.00 Lithuanian talonas random",
        "1.00 Lithuanian talonases random",
        "1.00 Luxembourgian Convertible Franc random",
        "1.00 Luxembourg Financial Franc random",
        "1.00 Luxembourgian Franc random",
        "1.00 Luxembourgian convertible franc random",
        "1.00 Luxembourgian convertible francs random",
        "1.00 Luxembourg financial franc random",
        "1.00 Luxembourg financial francs random",
        "1.00 Luxembourgian franc random",
        "1.00 Luxembourgian francs random",
        "1.00 Macanese Pataca random",
        "1.00 Macanese pataca random",
        "1.00 Macanese patacas random",
        "1.00 Macedonian Denar random",
        "1.00 Macedonian denar random",
        "1.00 Macedonian denari random",
        "1.00 Malagasy Ariaries random",
        "1.00 Malagasy Ariary random",
        "1.00 Malagasy Ariary random",
        "1.00 Malagasy Franc random",
        "1.00 Malagasy franc random",
        "1.00 Malagasy francs random",
        "1.00 Malawian Kwacha random",
        "1.00 Malawian Kwacha random",
        "1.00 Malawian Kwachas random",
        "1.00 Malaysian Ringgit random",
        "1.00 Malaysian ringgit random",
        "1.00 Malaysian ringgits random",
        "1.00 Maldivian Rufiyaa random",
        "1.00 Maldivian rufiyaa random",
        "1.00 Maldivian rufiyaas random",
        "1.00 Malian Franc random",
        "1.00 Malian franc random",
        "1.00 Malian francs random",
        "1.00 Maltese Lira random",
        "1.00 Maltese Pound random",
        "1.00 Maltese lira random",
        "1.00 Maltese liras random",
        "1.00 Maltese pound random",
        "1.00 Maltese pounds random",
        "1.00 Mauritanian Ouguiya random",
        "1.00 Mauritanian ouguiya random",
        "1.00 Mauritanian ouguiyas random",
        "1.00 Mauritian Rupee random",
        "1.00 Mauritian rupee random",
        "1.00 Mauritian rupees random",
        "1.00 Mexican Peso random",
        "1.00 Mexican Silver Peso (1861\\u20131992) random",
        "1.00 Mexican Investment Unit random",
        "1.00 Mexican peso random",
        "1.00 Mexican pesos random",
        "1.00 Mexican silver peso (1861\\u20131992) random",
        "1.00 Mexican silver pesos (1861\\u20131992) random",
        "1.00 Mexican investment unit random",
        "1.00 Mexican investment units random",
        "1.00 Moldovan Leu random",
        "1.00 Moldovan leu random",
        "1.00 Moldovan lei random",
        "1.00 Mongolian Tugrik random",
        "1.00 Mongolian tugrik random",
        "1.00 Mongolian tugriks random",
        "1.00 Moroccan Dirham random",
        "1.00 Moroccan Franc random",
        "1.00 Moroccan dirham random",
        "1.00 Moroccan dirhams random",
        "1.00 Moroccan franc random",
        "1.00 Moroccan francs random",
        "1.00 Mozambican Escudo random",
        "1.00 Mozambican Metical random",
        "1.00 Mozambican escudo random",
        "1.00 Mozambican escudos random",
        "1.00 Mozambican metical random",
        "1.00 Mozambican meticals random",
        "1.00 Myanmar Kyat random",
        "1.00 Myanmar kyat random",
        "1.00 Myanmar kyats random",
        "1.00 Namibian Dollar random",
        "1.00 Namibian dollar random",
        "1.00 Namibian dollars random",
        "1.00 Nepalese Rupee random",
        "1.00 Nepalese rupee random",
        "1.00 Nepalese rupees random",
        "1.00 Netherlands Antillean Guilder random",
        "1.00 Netherlands Antillean guilder random",
        "1.00 Netherlands Antillean guilders random",
        "1.00 Dutch Guilder random",
        "1.00 Dutch guilder random",
        "1.00 Dutch guilders random",
        "1.00 Israeli New Shekel random",
        "1.00 Israeli new shekels random",
        "1.00 New Zealand Dollar random",
        "1.00 New Zealand dollar random",
        "1.00 New Zealand dollars random",
        "1.00 Nicaraguan C\\u00f3rdoba random",
        "1.00 Nicaraguan C\\u00f3rdoba (1988\\u20131991) random",
        "1.00 Nicaraguan c\\u00f3rdoba random",
        "1.00 Nicaraguan c\\u00f3rdoba random",
        "1.00 Nicaraguan c\\u00f3rdoba (1988\\u20131991) random",
        "1.00 Nicaraguan c\\u00f3rdobas (1988\\u20131991) random",
        "1.00 Nigerian Naira random",
        "1.00 Nigerian naira random",
        "1.00 Nigerian nairas random",
        "1.00 North Korean Won random",
        "1.00 North Korean won random",
        "1.00 North Korean won random",
        "1.00 Norwegian Krone random",
        "1.00 Norwegian krone random",
        "1.00 Norwegian kroner random",
        "1.00 Mozambican Metical (1980\\u20132006) random",
        "1.00 Mozambican metical (1980\\u20132006) random",
        "1.00 Mozambican meticals (1980\\u20132006) random",
        "1.00 Romanian Lei (1952\\u20132006) random",
        "1.00 Romanian Leu (1952\\u20132006) random",
        "1.00 Romanian leu (1952\\u20132006) random",
        "1.00 Serbian Dinar (2002\\u20132006) random",
        "1.00 Serbian dinar (2002\\u20132006) random",
        "1.00 Serbian dinars (2002\\u20132006) random",
        "1.00 Sudanese Dinar (1992\\u20132007) random",
        "1.00 Sudanese Pound (1957\\u20131998) random",
        "1.00 Sudanese dinar (1992\\u20132007) random",
        "1.00 Sudanese dinars (1992\\u20132007) random",
        "1.00 Sudanese pound (1957\\u20131998) random",
        "1.00 Sudanese pounds (1957\\u20131998) random",
        "1.00 Turkish Lira (1922\\u20132005) random",
        "1.00 Turkish Lira (1922\\u20132005) random",
        "1.00 Omani Rial random",
        "1.00 Omani rial random",
        "1.00 Omani rials random",
        "1.00 Pakistani Rupee random",
        "1.00 Pakistani rupee random",
        "1.00 Pakistani rupees random",
        "1.00 Palladium random",
        "1.00 Palladium random",
        "1.00 Panamanian Balboa random",
        "1.00 Panamanian balboa random",
        "1.00 Panamanian balboas random",
        "1.00 Papua New Guinean Kina random",
        "1.00 Papua New Guinean kina random",
        "1.00 Papua New Guinean kina random",
        "1.00 Paraguayan Guarani random",
        "1.00 Paraguayan guarani random",
        "1.00 Paraguayan guaranis random",
        "1.00 Peruvian Inti random",
        "1.00 Peruvian Sol random",
        "1.00 Peruvian Sol (1863\\u20131965) random",
        "1.00 Peruvian inti random",
        "1.00 Peruvian intis random",
        "1.00 Peruvian sol random",
        "1.00 Peruvian soles random",
        "1.00 Peruvian sol (1863\\u20131965) random",
        "1.00 Peruvian soles (1863\\u20131965) random",
        "1.00 Philippine Piso random",
        "1.00 Philippine piso random",
        "1.00 Philippine pisos random",
        "1.00 Platinum random",
        "1.00 Platinum random",
        "1.00 Polish Zloty (1950\\u20131995) random",
        "1.00 Polish Zloty random",
        "1.00 Polish zlotys random",
        "1.00 Polish zloty (PLZ) random",
        "1.00 Polish zloty random",
        "1.00 Polish zlotys (PLZ) random",
        "1.00 Portuguese Escudo random",
        "1.00 Portuguese Guinea Escudo random",
        "1.00 Portuguese Guinea escudo random",
        "1.00 Portuguese Guinea escudos random",
        "1.00 Portuguese escudo random",
        "1.00 Portuguese escudos random",
        "1.00 Qatari Rial random",
        "1.00 Qatari rial random",
        "1.00 Qatari rials random",
        "1.00 RINET Funds random",
        "1.00 RINET Funds random",
        "1.00 Rhodesian Dollar random",
        "1.00 Rhodesian dollar random",
        "1.00 Rhodesian dollars random",
        "1.00 Romanian Leu random",
        "1.00 Romanian lei random",
        "1.00 Romanian leu random",
        "1.00 Russian Ruble (1991\\u20131998) random",
        "1.00 Russian Ruble random",
        "1.00 Russian ruble (1991\\u20131998) random",
        "1.00 Russian ruble random",
        "1.00 Russian rubles (1991\\u20131998) random",
        "1.00 Russian rubles random",
        "1.00 Rwandan Franc random",
        "1.00 Rwandan franc random",
        "1.00 Rwandan francs random",
        "1.00 St. Helena Pound random",
        "1.00 St. Helena pound random",
        "1.00 St. Helena pounds random",
        "1.00 S\\u00e3o Tom\\u00e9 & Pr\\u00edncipe Dobra random",
        "1.00 S\\u00e3o Tom\\u00e9 & Pr\\u00edncipe dobra random",
        "1.00 S\\u00e3o Tom\\u00e9 & Pr\\u00edncipe dobras random",
        "1.00 Saudi Riyal random",
        "1.00 Saudi riyal random",
        "1.00 Saudi riyals random",
        "1.00 Serbian Dinar random",
        "1.00 Serbian dinar random",
        "1.00 Serbian dinars random",
        "1.00 Seychellois Rupee random",
        "1.00 Seychellois rupee random",
        "1.00 Seychellois rupees random",
        "1.00 Sierra Leonean Leone random",
        "1.00 Sierra Leonean leone random",
        "1.00 Sierra Leonean leones random",
        "1.00 Singapore Dollar random",
        "1.00 Singapore dollar random",
        "1.00 Singapore dollars random",
        "1.00 Slovak Koruna random",
        "1.00 Slovak koruna random",
        "1.00 Slovak korunas random",
        "1.00 Slovenian Tolar random",
        "1.00 Slovenian tolar random",
        "1.00 Slovenian tolars random",
        "1.00 Solomon Islands Dollar random",
        "1.00 Solomon Islands dollar random",
        "1.00 Solomon Islands dollars random",
        "1.00 Somali Shilling random",
        "1.00 Somali shilling random",
        "1.00 Somali shillings random",
        "1.00 South African Rand (financial) random",
        "1.00 South African Rand random",
        "1.00 South African rand (financial) random",
        "1.00 South African rand random",
        "1.00 South African rands (financial) random",
        "1.00 South African rand random",
        "1.00 South Korean Won random",
        "1.00 South Korean won random",
        "1.00 South Korean won random",
        "1.00 Soviet Rouble random",
        "1.00 Soviet rouble random",
        "1.00 Soviet roubles random",
        "1.00 Spanish Peseta (A account) random",
        "1.00 Spanish Peseta (convertible account) random",
        "1.00 Spanish Peseta random",
        "1.00 Spanish peseta (A account) random",
        "1.00 Spanish peseta (convertible account) random",
        "1.00 Spanish peseta random",
        "1.00 Spanish pesetas (A account) random",
        "1.00 Spanish pesetas (convertible account) random",
        "1.00 Spanish pesetas random",
        "1.00 Special Drawing Rights random",
        "1.00 Sri Lankan Rupee random",
        "1.00 Sri Lankan rupee random",
        "1.00 Sri Lankan rupees random",
        "1.00 Sudanese Pound random",
        "1.00 Sudanese pound random",
        "1.00 Sudanese pounds random",
        "1.00 Surinamese Dollar random",
        "1.00 Surinamese dollar random",
        "1.00 Surinamese dollars random",
        "1.00 Surinamese Guilder random",
        "1.00 Surinamese guilder random",
        "1.00 Surinamese guilders random",
        "1.00 Swazi Lilangeni random",
        "1.00 Swazi lilangeni random",
        "1.00 Swazi emalangeni random",
        "1.00 Swedish Krona random",
        "1.00 Swedish krona random",
        "1.00 Swedish kronor random",
        "1.00 Swiss Franc random",
        "1.00 Swiss franc random",
        "1.00 Swiss francs random",
        "1.00 Syrian Pound random",
        "1.00 Syrian pound random",
        "1.00 Syrian pounds random",
        "1.00 New Taiwan Dollar random",
        "1.00 New Taiwan dollar random",
        "1.00 New Taiwan dollars random",
        "1.00 Tajikistani Ruble random",
        "1.00 Tajikistani Somoni random",
        "1.00 Tajikistani ruble random",
        "1.00 Tajikistani rubles random",
        "1.00 Tajikistani somoni random",
        "1.00 Tajikistani somonis random",
        "1.00 Tanzanian Shilling random",
        "1.00 Tanzanian shilling random",
        "1.00 Tanzanian shillings random",
        "1.00 Testing Currency Code random",
        "1.00 Testing Currency Code random",
        "1.00 Thai Baht random",
        "1.00 Thai baht random",
        "1.00 Thai baht random",
        "1.00 Timorese Escudo random",
        "1.00 Timorese escudo random",
        "1.00 Timorese escudos random",
        "1.00 Trinidad & Tobago Dollar random",
        "1.00 Trinidad & Tobago dollar random",
        "1.00 Trinidad & Tobago dollars random",
        "1.00 Tunisian Dinar random",
        "1.00 Tunisian dinar random",
        "1.00 Tunisian dinars random",
        "1.00 Turkish Lira random",
        "1.00 Turkish Lira random",
        "1.00 Turkish lira random",
        "1.00 Turkmenistani Manat random",
        "1.00 Turkmenistani manat random",
        "1.00 Turkmenistani manat random",
        "1.00 US Dollar (Next day) random",
        "1.00 US Dollar (Same day) random",
        "1.00 US Dollar random",
        "1.00 US dollar (next day) random",
        "1.00 US dollar (same day) random",
        "1.00 US dollar random",
        "1.00 US dollars (next day) random",
        "1.00 US dollars (same day) random",
        "1.00 US dollars random",
        "1.00 Ugandan Shilling (1966\\u20131987) random",
        "1.00 Ugandan Shilling random",
        "1.00 Ugandan shilling (1966\\u20131987) random",
        "1.00 Ugandan shilling random",
        "1.00 Ugandan shillings (1966\\u20131987) random",
        "1.00 Ugandan shillings random",
        "1.00 Ukrainian Hryvnia random",
        "1.00 Ukrainian Karbovanets random",
        "1.00 Ukrainian hryvnia random",
        "1.00 Ukrainian hryvnias random",
        "1.00 Ukrainian karbovanets random",
        "1.00 Ukrainian karbovantsiv random",
        "1.00 Colombian Real Value Unit random",
        "1.00 United Arab Emirates Dirham random",
        "1.00 Unknown Currency random",
        "1.00 Uruguayan Peso (1975\\u20131993) random",
        "1.00 Uruguayan Peso random",
        "1.00 Uruguayan Peso (Indexed Units) random",
        "1.00 Uruguayan peso (1975\\u20131993) random",
        "1.00 Uruguayan peso (indexed units) random",
        "1.00 Uruguayan peso random",
        "1.00 Uruguayan pesos (1975\\u20131993) random",
        "1.00 Uruguayan pesos (indexed units) random",
        "1.00 Uzbekistani Som random",
        "1.00 Uzbekistani som random",
        "1.00 Uzbekistani som random",
        "1.00 Vanuatu Vatu random",
        "1.00 Vanuatu vatu random",
        "1.00 Vanuatu vatus random",
        "1.00 Venezuelan Bol\\u00edvar random",
        "1.00 Venezuelan Bol\\u00edvar (1871\\u20132008) random",
        "1.00 Venezuelan bol\\u00edvar random",
        "1.00 Venezuelan bol\\u00edvars random",
        "1.00 Venezuelan bol\\u00edvar (1871\\u20132008) random",
        "1.00 Venezuelan bol\\u00edvars (1871\\u20132008) random",
        "1.00 Vietnamese Dong random",
        "1.00 Vietnamese dong random",
        "1.00 Vietnamese dong random",
        "1.00 WIR Euro random",
        "1.00 WIR Franc random",
        "1.00 WIR euro random",
        "1.00 WIR euros random",
        "1.00 WIR franc random",
        "1.00 WIR francs random",
        "1.00 Samoan Tala random",
        "1.00 Samoan tala random",
        "1.00 Samoan tala random",
        "1.00 Yemeni Dinar random",
        "1.00 Yemeni Rial random",
        "1.00 Yemeni dinar random",
        "1.00 Yemeni dinars random",
        "1.00 Yemeni rial random",
        "1.00 Yemeni rials random",
        "1.00 Yugoslavian Convertible Dinar (1990\\u20131992) random",
        "1.00 Yugoslavian Hard Dinar (1966\\u20131990) random",
        "1.00 Yugoslavian New Dinar (1994\\u20132002) random",
        "1.00 Yugoslavian convertible dinar (1990\\u20131992) random",
        "1.00 Yugoslavian convertible dinars (1990\\u20131992) random",
        "1.00 Yugoslavian hard dinar (1966\\u20131990) random",
        "1.00 Yugoslavian hard dinars (1966\\u20131990) random",
        "1.00 Yugoslavian new dinar (1994\\u20132002) random",
        "1.00 Yugoslavian new dinars (1994\\u20132002) random",
        "1.00 Zairean New Zaire (1993\\u20131998) random",
        "1.00 Zairean Zaire (1971\\u20131993) random",
        "1.00 Zairean new zaire (1993\\u20131998) random",
        "1.00 Zairean new zaires (1993\\u20131998) random",
        "1.00 Zairean zaire (1971\\u20131993) random",
        "1.00 Zairean zaires (1971\\u20131993) random",
        "1.00 Zambian Kwacha random",
        "1.00 Zambian kwacha random",
        "1.00 Zambian kwachas random",
        "1.00 Zimbabwean Dollar (1980\\u20132008) random",
        "1.00 Zimbabwean dollar (1980\\u20132008) random",
        "1.00 Zimbabwean dollars (1980\\u20132008) random",
        "1.00 euro random",
        "1.00 euros random",
        "1.00 Turkish lira (1922\\u20132005) random",
        "1.00 special drawing rights random",
        "1.00 Colombian real value unit random",
        "1.00 Colombian real value units random",
        "1.00 unknown currency random",
    };

    const char* WRONG_DATA[] = {
        // Following are missing one last char in the currency name
        "usd1.00", // case sensitive
        "1.00 Nicaraguan Cordob",
        "1.00 Namibian Dolla",
        "1.00 Namibian dolla",
        "1.00 Nepalese Rupe",
        "1.00 Nepalese rupe",
        "1.00 Netherlands Antillean Guilde",
        "1.00 Netherlands Antillean guilde",
        "1.00 Dutch Guilde",
        "1.00 Dutch guilde",
        "1.00 Israeli New Sheqe",
        "1.00 New Zealand Dolla",
        "1.00 New Zealand dolla",
        "1.00 Nicaraguan cordob",
        "1.00 Nigerian Nair",
        "1.00 Nigerian nair",
        "1.00 North Korean Wo",
        "1.00 North Korean wo",
        "1.00 Norwegian Kron",
        "1.00 Norwegian kron",
        "1.00 US dolla",
        "1.00",
        "A1.00",
        "AD1.00",
        "AE1.00",
        "AF1.00",
        "AL1.00",
        "AM1.00",
        "AN1.00",
        "AO1.00",
        "AR1.00",
        "AT1.00",
        "AU1.00",
        "AW1.00",
        "AZ1.00",
        "Afghan Afghan1.00",
        "Afghan Afghani (1927\\u201320021.00",
        "Afl1.00",
        "Albanian Le1.00",
        "Algerian Dina1.00",
        "Andorran Peset1.00",
        "Angolan Kwanz1.00",
        "Angolan Kwanza (1977\\u201319901.00",
        "Angolan Readjusted Kwanza (1995\\u201319991.00",
        "Angolan New Kwanza (1990\\u201320001.00",
        "Argentine Austra1.00",
        "Argentine Pes1.00",
        "Argentine Peso (1983\\u201319851.00",
        "Armenian Dra1.00",
        "Aruban Flori1.00",
        "Australian Dolla1.00",
        "Austrian Schillin1.00",
        "Azerbaijani Mana1.00",
        "Azerbaijani Manat (1993\\u201320061.00",
        "B1.00",
        "BA1.00",
        "BB1.00",
        "BE1.00",
        "BG1.00",
        "BH1.00",
        "BI1.00",
        "BM1.00",
        "BN1.00",
        "BO1.00",
        "BR1.00",
        "BS1.00",
        "BT1.00",
        "BU1.00",
        "BW1.00",
        "BY1.00",
        "BZ1.00",
        "Bahamian Dolla1.00",
        "Bahraini Dina1.00",
        "Bangladeshi Tak1.00",
        "Barbadian Dolla1.00",
        "Bds1.00",
        "Belarusian Ruble (1994\\u201319991.00",
        "Belarusian Rubl1.00",
        "Belgian Fran1.00",
        "Belgian Franc (convertible1.00",
        "Belgian Franc (financial1.00",
        "Belize Dolla1.00",
        "Bermudan Dolla1.00",
        "Bhutanese Ngultru1.00",
        "Bolivian Mvdo1.00",
        "Bolivian Pes1.00",
        "Bolivian Bolivian1.00",
        "Bosnia-Herzegovina Convertible Mar1.00",
        "Bosnia-Herzegovina Dina1.00",
        "Botswanan Pul1.00",
        "Brazilian Cruzad1.00",
        "Brazilian Cruzado Nov1.00",
        "Brazilian Cruzeir1.00",
        "Brazilian Cruzeiro (1990\\u201319931.00",
        "Brazilian New Cruzeiro (1967\\u201319861.00",
        "Brazilian Rea1.00",
        "British Pound Sterlin1.00",
        "Brunei Dolla1.00",
        "Bulgarian Hard Le1.00",
        "Bulgarian Le1.00",
        "Burmese Kya1.00",
        "Burundian Fran1.00",
        "C1.00",
        "CA1.00",
        "CD1.00",
        "CFP Fran1.00",
        "CFP1.00",
        "CH1.00",
        "CL1.00",
        "CN1.00",
        "CO1.00",
        "CS1.00",
        "CU1.00",
        "CV1.00",
        "CY1.00",
        "CZ1.00",
        "Cambodian Rie1.00",
        "Canadian Dolla1.00",
        "Cape Verdean Escud1.00",
        "Cayman Islands Dolla1.00",
        "Chilean Pes1.00",
        "Chilean Unit of Accoun1.00",
        "Chinese Yua1.00",
        "Colombian Pes1.00",
        "Comoro Fran1.00",
        "Congolese Fran1.00",
        "Costa Rican Col\\u00f31.00",
        "Croatian Dina1.00",
        "Croatian Kun1.00",
        "Cuban Pes1.00",
        "Cypriot Poun1.00",
        "Czech Republic Korun1.00",
        "Czechoslovak Hard Korun1.00",
        "D1.00",
        "DD1.00",
        "DE1.00",
        "DJ1.00",
        "DK1.00",
        "DO1.00",
        "DZ1.00",
        "Danish Kron1.00",
        "German Mar1.00",
        "Djiboutian Fran1.00",
        "Dk1.00",
        "Dominican Pes1.00",
        "EC1.00",
        "EE1.00",
        "EG1.00",
        "EQ1.00",
        "ER1.00",
        "ES1.00",
        "ET1.00",
        "EU1.00",
        "East Caribbean Dolla1.00",
        "East German Ostmar1.00",
        "Ecuadorian Sucr1.00",
        "Ecuadorian Unit of Constant Valu1.00",
        "Egyptian Poun1.00",
        "Ekwel1.00",
        "Salvadoran Col\\u00f31.00",
        "Equatorial Guinean Ekwel1.00",
        "Eritrean Nakf1.00",
        "Es1.00",
        "Estonian Kroo1.00",
        "Ethiopian Bir1.00",
        "Eur1.00",
        "European Composite Uni1.00",
        "European Currency Uni1.00",
        "European Monetary Uni1.00",
        "European Unit of Account (XBC1.00",
        "European Unit of Account (XBD1.00",
        "F1.00",
        "FB1.00",
        "FI1.00",
        "FJ1.00",
        "FK1.00",
        "FR1.00",
        "Falkland Islands Poun1.00",
        "Fd1.00",
        "Fijian Dolla1.00",
        "Finnish Markk1.00",
        "Fr1.00",
        "French Fran1.00",
        "French Gold Fran1.00",
        "French UIC-Fran1.00",
        "G1.00",
        "GB1.00",
        "GE1.00",
        "GH1.00",
        "GI1.00",
        "GM1.00",
        "GN1.00",
        "GQ1.00",
        "GR1.00",
        "GT1.00",
        "GW1.00",
        "GY1.00",
        "Gambian Dalas1.00",
        "Georgian Kupon Lari1.00",
        "Georgian Lar1.00",
        "Ghanaian Ced1.00",
        "Ghanaian Cedi (1979\\u201320071.00",
        "Gibraltar Poun1.00",
        "Gol1.00",
        "Greek Drachm1.00",
        "Guatemalan Quetza1.00",
        "Guinean Fran1.00",
        "Guinean Syl1.00",
        "Guinea-Bissau Pes1.00",
        "Guyanaese Dolla1.00",
        "HK1.00",
        "HN1.00",
        "HR1.00",
        "HT1.00",
        "HU1.00",
        "Haitian Gourd1.00",
        "Honduran Lempir1.00",
        "Hong Kong Dolla1.00",
        "Hungarian Forin1.00",
        "I1.00",
        "IE1.00",
        "IL1.00",
        "IN1.00",
        "IQ1.00",
        "IR1.00",
        "IS1.00",
        "IT1.00",
        "Icelandic Kron1.00",
        "Indian Rupe1.00",
        "Indonesian Rupia1.00",
        "Iranian Ria1.00",
        "Iraqi Dina1.00",
        "Irish Poun1.00",
        "Israeli Poun1.00",
        "Italian Lir1.00",
        "J1.00",
        "JM1.00",
        "JO1.00",
        "JP1.00",
        "Jamaican Dolla1.00",
        "Japanese Ye1.00",
        "Jordanian Dina1.00",
        "K S1.00",
        "K1.00",
        "KE1.00",
        "KG1.00",
        "KH1.00",
        "KP1.00",
        "KR1.00",
        "KW1.00",
        "KY1.00",
        "KZ1.00",
        "Kazakhstani Teng1.00",
        "Kenyan Shillin1.00",
        "Kuwaiti Dina1.00",
        "Kyrgystani So1.00",
        "LA1.00",
        "LB1.00",
        "LK1.00",
        "LR1.00",
        "LT1.00",
        "LU1.00",
        "LV1.00",
        "LY1.00",
        "Laotian Ki1.00",
        "Latvian Lat1.00",
        "Latvian Rubl1.00",
        "Lebanese Poun1.00",
        "Lesotho Lot1.00",
        "Liberian Dolla1.00",
        "Libyan Dina1.00",
        "Lithuanian Lit1.00",
        "Lithuanian Talona1.00",
        "Luxembourgian Convertible Fran1.00",
        "Luxembourg Financial Fran1.00",
        "Luxembourgian Fran1.00",
        "MA1.00",
        "MD1.00",
        "MDe1.00",
        "MEX1.00",
        "MG1.00",
        "ML1.00",
        "MM1.00",
        "MN1.00",
        "MO1.00",
        "MR1.00",
        "MT1.00",
        "MU1.00",
        "MV1.00",
        "MW1.00",
        "MX1.00",
        "MY1.00",
        "MZ1.00",
        "Macanese Patac1.00",
        "Macedonian Dena1.00",
        "Malagasy Ariar1.00",
        "Malagasy Fran1.00",
        "Malawian Kwach1.00",
        "Malaysian Ringgi1.00",
        "Maldivian Rufiya1.00",
        "Malian Fran1.00",
        "Malot1.00",
        "Maltese Lir1.00",
        "Maltese Poun1.00",
        "Mauritanian Ouguiy1.00",
        "Mauritian Rupe1.00",
        "Mexican Pes1.00",
        "Mexican Silver Peso (1861\\u201319921.00",
        "Mexican Investment Uni1.00",
        "Moldovan Le1.00",
        "Mongolian Tugri1.00",
        "Moroccan Dirha1.00",
        "Moroccan Fran1.00",
        "Mozambican Escud1.00",
        "Mozambican Metica1.00",
        "Myanmar Kya1.00",
        "N1.00",
        "NA1.00",
        "NAf1.00",
        "NG1.00",
        "NI1.00",
        "NK1.00",
        "NL1.00",
        "NO1.00",
        "NP1.00",
        "NT1.00",
        "Namibian Dolla1.00",
        "Nepalese Rupe1.00",
        "Netherlands Antillean Guilde1.00",
        "Dutch Guilde1.00",
        "Israeli New Sheqe1.00",
        "New Zealand Dolla1.00",
        "Nicaraguan C\\u00f3rdoba (1988\\u201319911.00",
        "Nicaraguan C\\u00f3rdob1.00",
        "Nigerian Nair1.00",
        "North Korean Wo1.00",
        "Norwegian Kron1.00",
        "Nr1.00",
        "OM1.00",
        "Old Mozambican Metica1.00",
        "Romanian Leu (1952\\u201320061.00",
        "Serbian Dinar (2002\\u201320061.00",
        "Sudanese Dinar (1992\\u201320071.00",
        "Sudanese Pound (1957\\u201319981.00",
        "Turkish Lira (1922\\u201320051.00",
        "Omani Ria1.00",
        "PA1.00",
        "PE1.00",
        "PG1.00",
        "PH1.00",
        "PK1.00",
        "PL1.00",
        "PT1.00",
        "PY1.00",
        "Pakistani Rupe1.00",
        "Palladiu1.00",
        "Panamanian Balbo1.00",
        "Papua New Guinean Kin1.00",
        "Paraguayan Guaran1.00",
        "Peruvian Int1.00",
        "Peruvian Sol (1863\\u201319651.00",
        "Peruvian Sol Nuev1.00",
        "Philippine Pes1.00",
        "Platinu1.00",
        "Polish Zlot1.00",
        "Polish Zloty (1950\\u201319951.00",
        "Portuguese Escud1.00",
        "Portuguese Guinea Escud1.00",
        "Pr1.00",
        "QA1.00",
        "Qatari Ria1.00",
        "RD1.00",
        "RH1.00",
        "RINET Fund1.00",
        "RS1.00",
        "RU1.00",
        "RW1.00",
        "Rb1.00",
        "Rhodesian Dolla1.00",
        "Romanian Le1.00",
        "Russian Rubl1.00",
        "Russian Ruble (1991\\u201319981.00",
        "Rwandan Fran1.00",
        "S1.00",
        "SA1.00",
        "SB1.00",
        "SC1.00",
        "SD1.00",
        "SE1.00",
        "SG1.00",
        "SH1.00",
        "SI1.00",
        "SK1.00",
        "SL R1.00",
        "SL1.00",
        "SO1.00",
        "ST1.00",
        "SU1.00",
        "SV1.00",
        "SY1.00",
        "SZ1.00",
        "St. Helena Poun1.00",
        "S\\u00e3o Tom\\u00e9 & Pr\\u00edncipe Dobr1.00",
        "Saudi Riya1.00",
        "Serbian Dina1.00",
        "Seychellois Rupe1.00",
        "Sh1.00",
        "Sierra Leonean Leon1.00",
        "Silve1.00",
        "Singapore Dolla1.00",
        "Slovak Korun1.00",
        "Slovenian Tola1.00",
        "Solomon Islands Dolla1.00",
        "Somali Shillin1.00",
        "South African Ran1.00",
        "South African Rand (financial1.00",
        "South Korean Wo1.00",
        "Soviet Roubl1.00",
        "Spanish Peset1.00",
        "Spanish Peseta (A account1.00",
        "Spanish Peseta (convertible account1.00",
        "Special Drawing Right1.00",
        "Sri Lankan Rupe1.00",
        "Sudanese Poun1.00",
        "Surinamese Dolla1.00",
        "Surinamese Guilde1.00",
        "Swazi Lilangen1.00",
        "Swedish Kron1.00",
        "Swiss Fran1.00",
        "Syrian Poun1.00",
        "T S1.00",
        "TH1.00",
        "TJ1.00",
        "TM1.00",
        "TN1.00",
        "TO1.00",
        "TP1.00",
        "TR1.00",
        "TT1.00",
        "TW1.00",
        "TZ1.00",
        "New Taiwan Dolla1.00",
        "Tajikistani Rubl1.00",
        "Tajikistani Somon1.00",
        "Tanzanian Shillin1.00",
        "Testing Currency Cod1.00",
        "Thai Bah1.00",
        "Timorese Escud1.00",
        "Tongan Pa\\u20bbang1.00",
        "Trinidad & Tobago Dolla1.00",
        "Tunisian Dina1.00",
        "Turkish Lir1.00",
        "Turkmenistani Mana1.00",
        "U S1.00",
        "U1.00",
        "UA1.00",
        "UG1.00",
        "US Dolla1.00",
        "US Dollar (Next day1.00",
        "US Dollar (Same day1.00",
        "US1.00",
        "UY1.00",
        "UZ1.00",
        "Ugandan Shillin1.00",
        "Ugandan Shilling (1966\\u201319871.00",
        "Ukrainian Hryvni1.00",
        "Ukrainian Karbovanet1.00",
        "Colombian Real Value Uni1.00",
        "United Arab Emirates Dirha1.00",
        "Unknown Currenc1.00",
        "Ur1.00",
        "Uruguay Peso (1975\\u201319931.00",
        "Uruguay Peso Uruguay1.00",
        "Uruguay Peso (Indexed Units1.00",
        "Uzbekistani So1.00",
        "V1.00",
        "VE1.00",
        "VN1.00",
        "VU1.00",
        "Vanuatu Vat1.00",
        "Venezuelan Bol\\u00edva1.00",
        "Venezuelan Bol\\u00edvar Fuert1.00",
        "Vietnamese Don1.00",
        "West African CFA Fran1.00",
        "Central African CFA Fran1.00",
        "WIR Eur1.00",
        "WIR Fran1.00",
        "WS1.00",
        "Samoa Tal1.00",
        "XA1.00",
        "XB1.00",
        "XC1.00",
        "XD1.00",
        "XE1.00",
        "XF1.00",
        "XO1.00",
        "XP1.00",
        "XR1.00",
        "XT1.00",
        "XX1.00",
        "YD1.00",
        "YE1.00",
        "YU1.00",
        "Yemeni Dina1.00",
        "Yemeni Ria1.00",
        "Yugoslavian Convertible Dina1.00",
        "Yugoslavian Hard Dinar (1966\\u201319901.00",
        "Yugoslavian New Dina1.00",
        "Z1.00",
        "ZA1.00",
        "ZM1.00",
        "ZR1.00",
        "ZW1.00",
        "Zairean New Zaire (1993\\u201319981.00",
        "Zairean Zair1.00",
        "Zambian Kwach1.00",
        "Zimbabwean Dollar (1980\\u201320081.00",
        "dra1.00",
        "lar1.00",
        "le1.00",
        "man1.00",
        "so1.00",
    };

    Locale locale("en_US");
    for (uint32_t i=0; i<UPRV_LENGTHOF(DATA); ++i) {
        UnicodeString formatted = ctou(DATA[i]);
        UErrorCode status = U_ZERO_ERROR;
        LocalPointer<NumberFormat> numFmt(NumberFormat::createInstance(locale, UNUM_CURRENCY, status), status);
        if (!assertSuccess("", status, true, __FILE__, __LINE__)) {
            return;
        }
        // NOTE: ICU 62 requires that the currency format match the pattern in strict mode.
        numFmt->setLenient(TRUE);
        ParsePosition parsePos;
        LocalPointer<CurrencyAmount> currAmt(numFmt->parseCurrency(formatted, parsePos));
        if (parsePos.getIndex() > 0) {
            double doubleVal = currAmt->getNumber().getDouble(status);
            if ( doubleVal != 1.0 ) {
                errln("Parsed as currency value other than 1.0: " + formatted + " -> " + doubleVal);
            }
        } else {
            errln("Failed to parse as currency: " + formatted);
        }
    }

    for (uint32_t i=0; i<UPRV_LENGTHOF(WRONG_DATA); ++i) {
      UnicodeString formatted = ctou(WRONG_DATA[i]);
      UErrorCode status = U_ZERO_ERROR;
      NumberFormat* numFmt = NumberFormat::createInstance(locale, UNUM_CURRENCY, status);
      if (numFmt != NULL && U_SUCCESS(status)) {
          ParsePosition parsePos;
          LocalPointer<CurrencyAmount> currAmt(numFmt->parseCurrency(formatted, parsePos));
          if (parsePos.getIndex() > 0) {
              double doubleVal = currAmt->getNumber().getDouble(status);
              errln("Parsed as currency, should not have: " + formatted + " -> " + doubleVal);
          }
      } else {
          dataerrln("Unable to create NumberFormat. - %s", u_errorName(status));
          delete numFmt;
          break;
      }
      delete numFmt;
    }
}

const char* attrString(int32_t);

// UnicodeString s;
//  std::string ss;
//  std::cout << s.toUTF8String(ss)
void NumberFormatTest::expectPositions(FieldPositionIterator& iter, int32_t *values, int32_t tupleCount,
                                       const UnicodeString& str)  {
  UBool found[10];
  FieldPosition fp;

  if (tupleCount > 10) {
    assertTrue("internal error, tupleCount too large", FALSE);
  } else {
    for (int i = 0; i < tupleCount; ++i) {
      found[i] = FALSE;
    }
  }

  logln(str);
  while (iter.next(fp)) {
    UBool ok = FALSE;
    int32_t id = fp.getField();
    int32_t start = fp.getBeginIndex();
    int32_t limit = fp.getEndIndex();

    // is there a logln using printf?
    char buf[128];
    sprintf(buf, "%24s %3d %3d %3d", attrString(id), id, start, limit);
    logln(buf);

    for (int i = 0; i < tupleCount; ++i) {
      if (found[i]) {
        continue;
      }
      if (values[i*3] == id &&
          values[i*3+1] == start &&
          values[i*3+2] == limit) {
        found[i] = ok = TRUE;
        break;
      }
    }

    assertTrue((UnicodeString)"found [" + id + "," + start + "," + limit + "]", ok);
  }

  // check that all were found
  UBool ok = TRUE;
  for (int i = 0; i < tupleCount; ++i) {
    if (!found[i]) {
      ok = FALSE;
      assertTrue((UnicodeString) "missing [" + values[i*3] + "," + values[i*3+1] + "," + values[i*3+2] + "]", found[i]);
    }
  }
  assertTrue("no expected values were missing", ok);
}

void NumberFormatTest::expectPosition(FieldPosition& pos, int32_t id, int32_t start, int32_t limit,
                                       const UnicodeString& str)  {
  logln(str);
  assertTrue((UnicodeString)"id " + id + " == " + pos.getField(), id == pos.getField());
  assertTrue((UnicodeString)"begin " + start + " == " + pos.getBeginIndex(), start == pos.getBeginIndex());
  assertTrue((UnicodeString)"end " + limit + " == " + pos.getEndIndex(), limit == pos.getEndIndex());
}

void NumberFormatTest::TestFieldPositionIterator() {
  // bug 7372
  UErrorCode status = U_ZERO_ERROR;
  FieldPositionIterator iter1;
  FieldPositionIterator iter2;
  FieldPosition pos;

  DecimalFormat *decFmt = (DecimalFormat *) NumberFormat::createInstance(status);
  if (failure(status, "NumberFormat::createInstance", TRUE)) return;

  double num = 1234.56;
  UnicodeString str1;
  UnicodeString str2;

  assertTrue((UnicodeString)"self==", iter1 == iter1);
  assertTrue((UnicodeString)"iter1==iter2", iter1 == iter2);

  decFmt->format(num, str1, &iter1, status);
  assertTrue((UnicodeString)"iter1 != iter2", iter1 != iter2);
  decFmt->format(num, str2, &iter2, status);
  assertTrue((UnicodeString)"iter1 == iter2 (2)", iter1 == iter2);
  iter1.next(pos);
  assertTrue((UnicodeString)"iter1 != iter2 (2)", iter1 != iter2);
  iter2.next(pos);
  assertTrue((UnicodeString)"iter1 == iter2 (3)", iter1 == iter2);

  // should format ok with no iterator
  str2.remove();
  decFmt->format(num, str2, NULL, status);
  assertEquals("null fpiter", str1, str2);

  delete decFmt;
}

void NumberFormatTest::TestFormatAttributes() {
  Locale locale("en_US");
  UErrorCode status = U_ZERO_ERROR;
  DecimalFormat *decFmt = (DecimalFormat *) NumberFormat::createInstance(locale, UNUM_CURRENCY, status);
    if (failure(status, "NumberFormat::createInstance", TRUE)) return;
  double val = 12345.67;

  {
    int32_t expected[] = {
      UNUM_CURRENCY_FIELD, 0, 1,
      UNUM_GROUPING_SEPARATOR_FIELD, 3, 4,
      UNUM_INTEGER_FIELD, 1, 7,
      UNUM_DECIMAL_SEPARATOR_FIELD, 7, 8,
      UNUM_FRACTION_FIELD, 8, 10,
    };
    int32_t tupleCount = UPRV_LENGTHOF(expected)/3;

    FieldPositionIterator posIter;
    UnicodeString result;
    decFmt->format(val, result, &posIter, status);
    expectPositions(posIter, expected, tupleCount, result);
  }
  {
    FieldPosition fp(UNUM_INTEGER_FIELD);
    UnicodeString result;
    decFmt->format(val, result, fp);
    expectPosition(fp, UNUM_INTEGER_FIELD, 1, 7, result);
  }
  {
    FieldPosition fp(UNUM_FRACTION_FIELD);
    UnicodeString result;
    decFmt->format(val, result, fp);
    expectPosition(fp, UNUM_FRACTION_FIELD, 8, 10, result);
  }
  delete decFmt;

  decFmt = (DecimalFormat *) NumberFormat::createInstance(locale, UNUM_SCIENTIFIC, status);
  val = -0.0000123;
  {
    int32_t expected[] = {
      UNUM_SIGN_FIELD, 0, 1,
      UNUM_INTEGER_FIELD, 1, 2,
      UNUM_DECIMAL_SEPARATOR_FIELD, 2, 3,
      UNUM_FRACTION_FIELD, 3, 5,
      UNUM_EXPONENT_SYMBOL_FIELD, 5, 6,
      UNUM_EXPONENT_SIGN_FIELD, 6, 7,
      UNUM_EXPONENT_FIELD, 7, 8
    };
    int32_t tupleCount = UPRV_LENGTHOF(expected)/3;

    FieldPositionIterator posIter;
    UnicodeString result;
    decFmt->format(val, result, &posIter, status);
    expectPositions(posIter, expected, tupleCount, result);
  }
  {
    FieldPosition fp(UNUM_INTEGER_FIELD);
    UnicodeString result;
    decFmt->format(val, result, fp);
    expectPosition(fp, UNUM_INTEGER_FIELD, 1, 2, result);
  }
  {
    FieldPosition fp(UNUM_FRACTION_FIELD);
    UnicodeString result;
    decFmt->format(val, result, fp);
    expectPosition(fp, UNUM_FRACTION_FIELD, 3, 5, result);
  }
  delete decFmt;

  fflush(stderr);
}

const char* attrString(int32_t attrId) {
  switch (attrId) {
    case UNUM_INTEGER_FIELD: return "integer";
    case UNUM_FRACTION_FIELD: return "fraction";
    case UNUM_DECIMAL_SEPARATOR_FIELD: return "decimal separator";
    case UNUM_EXPONENT_SYMBOL_FIELD: return "exponent symbol";
    case UNUM_EXPONENT_SIGN_FIELD: return "exponent sign";
    case UNUM_EXPONENT_FIELD: return "exponent";
    case UNUM_GROUPING_SEPARATOR_FIELD: return "grouping separator";
    case UNUM_CURRENCY_FIELD: return "currency";
    case UNUM_PERCENT_FIELD: return "percent";
    case UNUM_PERMILL_FIELD: return "permille";
    case UNUM_SIGN_FIELD: return "sign";
    default: return "";
  }
}

//
//   Test formatting & parsing of big decimals.
//      API test, not a comprehensive test.
//      See DecimalFormatTest/DataDrivenTests
//
#define ASSERT_SUCCESS(status) { \
    assertSuccess(UnicodeString("file ") + __FILE__ + ", line " + __LINE__, (status)); \
}
#define ASSERT_EQUALS(expected, actual) { \
    assertEquals(UnicodeString("file ") + __FILE__ + ", line " + __LINE__, (expected), (actual)); \
}

void NumberFormatTest::TestDecimal() {
    {
        UErrorCode  status = U_ZERO_ERROR;
        Formattable f("12.345678999987654321E666", status);
        ASSERT_SUCCESS(status);
        StringPiece s = f.getDecimalNumber(status);
        ASSERT_SUCCESS(status);
        ASSERT_EQUALS("1.2345678999987654321E+667", s.data());
        //printf("%s\n", s.data());
    }

    {
        UErrorCode status = U_ZERO_ERROR;
        Formattable f1("this is not a number", status);
        ASSERT_EQUALS(U_DECIMAL_NUMBER_SYNTAX_ERROR, status);
    }

    {
        UErrorCode status = U_ZERO_ERROR;
        Formattable f;
        f.setDecimalNumber("123.45", status);
        ASSERT_SUCCESS(status);
        ASSERT_EQUALS( Formattable::kDouble, f.getType());
        ASSERT_EQUALS(123.45, f.getDouble());
        ASSERT_EQUALS(123.45, f.getDouble(status));
        ASSERT_SUCCESS(status);
        ASSERT_EQUALS("123.45", f.getDecimalNumber(status).data());
        ASSERT_SUCCESS(status);

        f.setDecimalNumber("4.5678E7", status);
        int32_t n;
        n = f.getLong();
        ASSERT_EQUALS(45678000, n);

        status = U_ZERO_ERROR;
        f.setDecimalNumber("-123", status);
        ASSERT_SUCCESS(status);
        ASSERT_EQUALS( Formattable::kLong, f.getType());
        ASSERT_EQUALS(-123, f.getLong());
        ASSERT_EQUALS(-123, f.getLong(status));
        ASSERT_SUCCESS(status);
        ASSERT_EQUALS("-123", f.getDecimalNumber(status).data());
        ASSERT_SUCCESS(status);

        status = U_ZERO_ERROR;
        f.setDecimalNumber("1234567890123", status);  // Number too big for 32 bits
        ASSERT_SUCCESS(status);
        ASSERT_EQUALS( Formattable::kInt64, f.getType());
        ASSERT_EQUALS(1234567890123LL, f.getInt64());
        ASSERT_EQUALS(1234567890123LL, f.getInt64(status));
        ASSERT_SUCCESS(status);
        ASSERT_EQUALS("1.234567890123E+12", f.getDecimalNumber(status).data());
        ASSERT_SUCCESS(status);
    }

    {
        UErrorCode status = U_ZERO_ERROR;
        NumberFormat *fmtr = NumberFormat::createInstance(Locale::getUS(), UNUM_DECIMAL, status);
        if (U_FAILURE(status) || fmtr == NULL) {
            dataerrln("Unable to create NumberFormat");
        } else {
            UnicodeString formattedResult;
            StringPiece num("244444444444444444444444444444444444446.4");
            fmtr->format(num, formattedResult, NULL, status);
            ASSERT_SUCCESS(status);
            ASSERT_EQUALS("244,444,444,444,444,444,444,444,444,444,444,444,446.4", formattedResult);
            //std::string ss; std::cout << formattedResult.toUTF8String(ss);
            delete fmtr;
        }
    }

    {
        // Check formatting a DigitList.  DigitList is internal, but this is
        // a critical interface that must work.
        UErrorCode status = U_ZERO_ERROR;
        NumberFormat *fmtr = NumberFormat::createInstance(Locale::getUS(), UNUM_DECIMAL, status);
        if (U_FAILURE(status) || fmtr == NULL) {
            dataerrln("Unable to create NumberFormat");
        } else {
            UnicodeString formattedResult;
            DecimalQuantity dl;
            StringPiece num("123.4566666666666666666666666666666666621E+40");
            dl.setToDecNumber(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.setToDecNumber(num, status);
            FieldPosition pos(NumberFormat::FRACTION_FIELD);
            ASSERT_SUCCESS(status);
            formattedResult.remove();
            fmtr->format(dl, formattedResult, pos, status);
            ASSERT_SUCCESS(status);
            ASSERT_EQUALS("666.666", formattedResult);
            ASSERT_EQUALS(4, pos.getBeginIndex());
            ASSERT_EQUALS(7, pos.getEndIndex());
            delete fmtr;
        }
    }

    {
        // Check a parse with a formatter with a multiplier.
        UErrorCode status = U_ZERO_ERROR;
        NumberFormat *fmtr = NumberFormat::createInstance(Locale::getUS(), UNUM_PERCENT, status);
        if (U_FAILURE(status) || fmtr == NULL) {
            dataerrln("Unable to create NumberFormat");
        } else {
            UnicodeString input = "1.84%";
            Formattable result;
            fmtr->parse(input, result, status);
            ASSERT_SUCCESS(status);
            ASSERT_EQUALS("0.0184", result.getDecimalNumber(status).data());
            //std::cout << result.getDecimalNumber(status).data();
            delete fmtr;
        }
    }

#if U_PLATFORM != U_PF_CYGWIN || defined(CYGWINMSVC)
    /*
     * This test fails on Cygwin (1.7.16) using GCC because of a rounding issue with strtod().
     * See #9463
     */
    {
        // Check that a parse returns a decimal number with full accuracy
        UErrorCode status = U_ZERO_ERROR;
        NumberFormat *fmtr = NumberFormat::createInstance(Locale::getUS(), UNUM_DECIMAL, status);
        if (U_FAILURE(status) || fmtr == NULL) {
            dataerrln("Unable to create NumberFormat");
        } else {
            UnicodeString input = "1.002200044400088880000070000";
            Formattable result;
            fmtr->parse(input, result, status);
            ASSERT_SUCCESS(status);
            ASSERT_EQUALS(0, strcmp("1.00220004440008888000007", result.getDecimalNumber(status).data()));
            ASSERT_EQUALS(1.00220004440008888,   result.getDouble());
            //std::cout << result.getDecimalNumber(status).data();
            delete fmtr;
        }
    }
#endif

}

void NumberFormatTest::TestCurrencyFractionDigits() {
    UErrorCode status = U_ZERO_ERROR;
    UnicodeString text1, text2;
    double value = 99.12345;

    // Create currenct instance
    NumberFormat* fmt = NumberFormat::createCurrencyInstance("ja_JP", status);
    if (U_FAILURE(status) || fmt == NULL) {
        dataerrln("Unable to create NumberFormat");
    } else {
        fmt->format(value, text1);

        // Reset the same currency and format the test value again
        fmt->setCurrency(fmt->getCurrency(), status);
        ASSERT_SUCCESS(status);
        fmt->format(value, text2);

        if (text1 != text2) {
            errln((UnicodeString)"NumberFormat::format() should return the same result - text1="
                + text1 + " text2=" + text2);
        }
    }
    delete fmt;
}

void NumberFormatTest::TestExponentParse() {

    UErrorCode status = U_ZERO_ERROR;
    Formattable result;
    ParsePosition parsePos(0);

    // set the exponent symbol
    status = U_ZERO_ERROR;
    DecimalFormatSymbols symbols(Locale::getDefault(), status);
    if(U_FAILURE(status)) {
        dataerrln((UnicodeString)"ERROR: Could not create DecimalFormatSymbols (Default)");
        return;
    }

    // create format instance
    status = U_ZERO_ERROR;
    DecimalFormat fmt(u"#####", symbols, status);
    if(U_FAILURE(status)) {
        errln((UnicodeString)"ERROR: Could not create DecimalFormat (pattern, symbols*)");
    }

    // parse the text
    fmt.parse("5.06e-27", result, parsePos);
    if(result.getType() != Formattable::kDouble &&
       result.getDouble() != 5.06E-27 &&
       parsePos.getIndex() != 8
       )
    {
        errln("ERROR: parse failed - expected 5.06E-27, 8  - returned %d, %i",
              result.getDouble(), parsePos.getIndex());
    }
}

void NumberFormatTest::TestExplicitParents() {

    /* Test that number formats are properly inherited from es_419 */
    /* These could be subject to change if the CLDR data changes */
    static const char* parentLocaleTests[][2]= {
    /* locale ID */  /* expected */
    {"es_CO", "1.250,75" },
    {"es_ES", "1.250,75" },
    {"es_GQ", "1.250,75" },
    {"es_MX", "1,250.75" },
    {"es_US", "1,250.75" },
    {"es_VE", "1.250,75" },
    };

    UnicodeString s;

    for(int i=0; i < UPRV_LENGTHOF(parentLocaleTests); i++){
        UErrorCode status = U_ZERO_ERROR;
        const char *localeID = parentLocaleTests[i][0];
        UnicodeString expected(parentLocaleTests[i][1], -1, US_INV);
        expected = expected.unescape();
        char loc[256]={0};
        uloc_canonicalize(localeID, loc, 256, &status);
        NumberFormat *fmt= NumberFormat::createInstance(Locale(loc), status);
        if(U_FAILURE(status)){
            dataerrln("Could not create number formatter for locale %s - %s",localeID, u_errorName(status));
            continue;
        }
        s.remove();
        fmt->format(1250.75, s);
        if(s!=expected){
            errln(UnicodeString("FAIL: Expected: ")+expected
                    + UnicodeString(" Got: ") + s
                    + UnicodeString( " for locale: ")+ UnicodeString(localeID) );
        }
        if (U_FAILURE(status)){
            errln((UnicodeString)"FAIL: Status " + (int32_t)status);
        }
        delete fmt;
    }

}

/**
 * Test available numbering systems API.
 */
void NumberFormatTest::TestAvailableNumberingSystems() {
    UErrorCode status = U_ZERO_ERROR;
    StringEnumeration *availableNumberingSystems = NumberingSystem::getAvailableNames(status);
    CHECK_DATA(status, "NumberingSystem::getAvailableNames()")

    int32_t nsCount = availableNumberingSystems->count(status);
    if ( nsCount < 74 ) {
        errln("FAIL: Didn't get as many numbering systems as we had hoped for. Need at least 74, got %d",nsCount);
    }

    /* A relatively simple test of the API.  We call getAvailableNames() and cycle through */
    /* each name returned, attempting to create a numbering system based on that name and  */
    /* verifying that the name returned from the resulting numbering system is the same    */
    /* one that we initially thought.                                                      */

    int32_t len;
    for ( int32_t i = 0 ; i < nsCount ; i++ ) {
        const char *nsname = availableNumberingSystems->next(&len,status);
        NumberingSystem* ns = NumberingSystem::createInstanceByName(nsname,status);
        logln("OK for ns = %s",nsname);
        if ( uprv_strcmp(nsname,ns->getName()) ) {
            errln("FAIL: Numbering system name didn't match for name = %s\n",nsname);
        }

        delete ns;
    }

    delete availableNumberingSystems;
}

void
NumberFormatTest::Test9087(void)
{
    U_STRING_DECL(pattern,"#",1);
    U_STRING_INIT(pattern,"#",1);

    U_STRING_DECL(infstr,"INF",3);
    U_STRING_INIT(infstr,"INF",3);

    U_STRING_DECL(nanstr,"NAN",3);
    U_STRING_INIT(nanstr,"NAN",3);

    UChar outputbuf[50] = {0};
    UErrorCode status = U_ZERO_ERROR;
    UNumberFormat* fmt = unum_open(UNUM_PATTERN_DECIMAL,pattern,1,NULL,NULL,&status);
    if ( U_FAILURE(status) ) {
        dataerrln("FAIL: error in unum_open() - %s", u_errorName(status));
        return;
    }

    unum_setSymbol(fmt,UNUM_INFINITY_SYMBOL,infstr,3,&status);
    unum_setSymbol(fmt,UNUM_NAN_SYMBOL,nanstr,3,&status);
    if ( U_FAILURE(status) ) {
        errln("FAIL: error setting symbols");
    }

    double inf = uprv_getInfinity();

    unum_setAttribute(fmt,UNUM_ROUNDING_MODE,UNUM_ROUND_HALFEVEN);
    unum_setDoubleAttribute(fmt,UNUM_ROUNDING_INCREMENT,0);

    UFieldPosition position = { 0, 0, 0};
    unum_formatDouble(fmt,inf,outputbuf,50,&position,&status);

    if ( u_strcmp(infstr, outputbuf)) {
        errln((UnicodeString)"FAIL: unexpected result for infinity - expected " + infstr + " got " + outputbuf);
    }

    unum_close(fmt);
}

void NumberFormatTest::TestFormatFastpaths() {
    // get some additional case
    {
        UErrorCode status=U_ZERO_ERROR;
        DecimalFormat df(UnicodeString(u"0000"),status);
        if (U_FAILURE(status)) {
            dataerrln("Error creating DecimalFormat - %s", u_errorName(status));
        } else {
            int64_t long_number = 1;
            UnicodeString expect = "0001";
            UnicodeString result;
            FieldPosition pos;
            df.format(long_number, result, pos);
            if(U_FAILURE(status)||expect!=result) {
                dataerrln("%s:%d FAIL: expected '%s' got '%s' status %s",
                          __FILE__, __LINE__, CStr(expect)(), CStr(result)(), u_errorName(status));
             } else {
                logln("OK:  got expected '"+result+"' status "+UnicodeString(u_errorName(status),""));
            }
        }
    }
    {
        UErrorCode status=U_ZERO_ERROR;
        DecimalFormat df(UnicodeString(u"0000000000000000000"),status);
        if (U_FAILURE(status)) {
            dataerrln("Error creating DecimalFormat - %s", u_errorName(status));
        } else {
            int64_t long_number = U_INT64_MIN; // -9223372036854775808L;
            // uint8_t bits[8];
            // memcpy(bits,&long_number,8);
            // for(int i=0;i<8;i++) {
            //   logln("bits: %02X", (unsigned int)bits[i]);
            // }
            UnicodeString expect = "-9223372036854775808";
            UnicodeString result;
            FieldPosition pos;
            df.format(long_number, result, pos);
            if(U_FAILURE(status)||expect!=result) {
                dataerrln("%s:%d FAIL: expected '%s' got '%s' status %s on -9223372036854775808",
                          __FILE__, __LINE__, CStr(expect)(), CStr(result)(), u_errorName(status));
            } else {
                logln("OK:  got expected '"+result+"' status "+UnicodeString(u_errorName(status),"")+" on -9223372036854775808");
            }
        }
    }
    {
        UErrorCode status=U_ZERO_ERROR;
        DecimalFormat df(UnicodeString(u"0000000000000000000"),status);
        if (U_FAILURE(status)) {
            dataerrln("Error creating DecimalFormat - %s", u_errorName(status));
        } else {
            int64_t long_number = U_INT64_MAX; // -9223372036854775808L;
            // uint8_t bits[8];
            // memcpy(bits,&long_number,8);
            // for(int i=0;i<8;i++) {
            //   logln("bits: %02X", (unsigned int)bits[i]);
            // }
            UnicodeString expect = "9223372036854775807";
            UnicodeString result;
            FieldPosition pos;
            df.format(long_number, result, pos);
            if(U_FAILURE(status)||expect!=result) {
                dataerrln("%s:%d FAIL: expected '%s' got '%s' status %s on U_INT64_MAX",
                          __FILE__, __LINE__, CStr(expect)(), CStr(result)(), u_errorName(status));
            } else {
                logln("OK:  got expected '"+result+"' status "+UnicodeString(u_errorName(status),"")+" on U_INT64_MAX");
            }
        }
    }
    {
        UErrorCode status=U_ZERO_ERROR;
        DecimalFormat df(UnicodeString("0000000000000000000",""),status);
        if (U_FAILURE(status)) {
            dataerrln("Error creating DecimalFormat - %s", u_errorName(status));
        } else {
            int64_t long_number = 0;
            // uint8_t bits[8];
            // memcpy(bits,&long_number,8);
            // for(int i=0;i<8;i++) {
            //   logln("bits: %02X", (unsigned int)bits[i]);
            // }
            UnicodeString expect = "0000000000000000000";
            UnicodeString result;
            FieldPosition pos;
            df.format(long_number, result, pos);
            if(U_FAILURE(status)||expect!=result) {
                dataerrln("%s:%d FAIL: expected '%s' got '%s' status %s on 0",
                          __FILE__, __LINE__, CStr(expect)(), CStr(result)(), u_errorName(status));
            } else {
                logln("OK:  got expected '"+result+"' status "+UnicodeString(u_errorName(status),"")+" on 0");
            }
        }
    }
    {
        UErrorCode status=U_ZERO_ERROR;
        DecimalFormat df(UnicodeString("0000000000000000000",""),status);
        if (U_FAILURE(status)) {
            dataerrln("Error creating DecimalFormat - %s", u_errorName(status));
        } else {
            int64_t long_number = U_INT64_MIN + 1;
            UnicodeString expect = "-9223372036854775807";
            UnicodeString result;
            FieldPosition pos;
            df.format(long_number, result, pos);
            if(U_FAILURE(status)||expect!=result) {
                dataerrln("%s:%d FAIL: expected '%s' got '%s' status %s on -9223372036854775807",
                          __FILE__, __LINE__, CStr(expect)(), CStr(result)(), u_errorName(status));
            } else {
                logln("OK:  got expected '"+result+"' status "+UnicodeString(u_errorName(status),"")+" on -9223372036854775807");
            }
        }
    }
}


void NumberFormatTest::TestFormattableSize(void) {
  if(sizeof(Formattable) > 112) {
    errln("Error: sizeof(Formattable)=%d, 112=%d\n",
          sizeof(Formattable), 112);
  } else if(sizeof(Formattable) < 112) {
    logln("Warning: sizeof(Formattable)=%d, 112=%d\n",
        sizeof(Formattable), 112);
  } else {
    logln("sizeof(Formattable)=%d, 112=%d\n",
        sizeof(Formattable), 112);
  }
}

UBool NumberFormatTest::testFormattableAsUFormattable(const char *file, int line, Formattable &f) {
  UnicodeString fileLine = UnicodeString(file)+UnicodeString(":")+line+UnicodeString(": ");

  UFormattable *u = f.toUFormattable();
  logln();
  if (u == NULL) {
    errln("%s:%d: Error: f.toUFormattable() retuned NULL.");
    return FALSE;
  }
  logln("%s:%d: comparing Formattable with UFormattable", file, line);
  logln(fileLine + toString(f));

  UErrorCode status = U_ZERO_ERROR;
  UErrorCode valueStatus = U_ZERO_ERROR;
  UFormattableType expectUType = UFMT_COUNT; // invalid

  UBool triedExact = FALSE; // did we attempt an exact comparison?
  UBool exactMatch = FALSE; // was the exact comparison true?

  switch( f.getType() ) {
  case Formattable::kDate:
    expectUType = UFMT_DATE;
    exactMatch = (f.getDate()==ufmt_getDate(u, &valueStatus));
    triedExact = TRUE;
    break;
  case Formattable::kDouble:
    expectUType = UFMT_DOUBLE;
    exactMatch = (f.getDouble()==ufmt_getDouble(u, &valueStatus));
    triedExact = TRUE;
    break;
  case Formattable::kLong:
    expectUType = UFMT_LONG;
    exactMatch = (f.getLong()==ufmt_getLong(u, &valueStatus));
    triedExact = TRUE;
    break;
  case Formattable::kString:
    expectUType = UFMT_STRING;
    {
      UnicodeString str;
      f.getString(str);
      int32_t len;
      const UChar* uch = ufmt_getUChars(u, &len, &valueStatus);
      if(U_SUCCESS(valueStatus)) {
        UnicodeString str2(uch, len);
        assertTrue("UChar* NULL-terminated", uch[len]==0);
        exactMatch = (str == str2);
      }
      triedExact = TRUE;
    }
    break;
  case Formattable::kArray:
    expectUType = UFMT_ARRAY;
    triedExact = TRUE;
    {
      int32_t count = ufmt_getArrayLength(u, &valueStatus);
      int32_t count2;
      const Formattable *array2 = f.getArray(count2);
      exactMatch = assertEquals(fileLine + " array count", count, count2);

      if(exactMatch) {
        for(int i=0;U_SUCCESS(valueStatus) && i<count;i++) {
          UFormattable *uu = ufmt_getArrayItemByIndex(u, i, &valueStatus);
          if(*Formattable::fromUFormattable(uu) != (array2[i])) {
            errln("%s:%d: operator== did not match at index[%d] - %p vs %p", file, line, i,
                  (const void*)Formattable::fromUFormattable(uu), (const void*)&(array2[i]));
            exactMatch = FALSE;
          } else {
            if(!testFormattableAsUFormattable("(sub item)",i,*Formattable::fromUFormattable(uu))) {
              exactMatch = FALSE;
            }
          }
        }
      }
    }
    break;
  case Formattable::kInt64:
    expectUType = UFMT_INT64;
    exactMatch = (f.getInt64()==ufmt_getInt64(u, &valueStatus));
    triedExact = TRUE;
    break;
  case Formattable::kObject:
    expectUType = UFMT_OBJECT;
    exactMatch = (f.getObject()==ufmt_getObject(u, &valueStatus));
    triedExact = TRUE;
    break;
  }
  UFormattableType uType = ufmt_getType(u, &status);

  if(U_FAILURE(status)) {
    errln("%s:%d: Error calling ufmt_getType - %s", file, line, u_errorName(status));
    return FALSE;
  }

  if(uType != expectUType) {
    errln("%s:%d: got type (%d) expected (%d) from ufmt_getType", file, line, (int) uType, (int) expectUType);
  }

  if(triedExact) {
    if(U_FAILURE(valueStatus)) {
      errln("%s:%d: got err %s trying to ufmt_get...() for exact match check", file, line, u_errorName(valueStatus));
    } else if(!exactMatch) {
     errln("%s:%d: failed exact match for the Formattable type", file, line);
    } else {
      logln("%s:%d: exact match OK", file, line);
    }
  } else {
    logln("%s:%d: note, did not attempt exact match for this formattable type", file, line);
  }

  if( assertEquals(fileLine + " isNumeric()", f.isNumeric(), ufmt_isNumeric(u))
      && f.isNumeric()) {
    UErrorCode convStatus = U_ZERO_ERROR;

    if(uType != UFMT_INT64) { // may fail to compare
      assertTrue(fileLine + " as doubles ==", f.getDouble(convStatus)==ufmt_getDouble(u, &convStatus));
    }

    if( assertSuccess(fileLine + " (numeric conversion status)", convStatus) ) {
      StringPiece fDecNum = f.getDecimalNumber(convStatus);
#if 1
      int32_t len;
      const char *decNumChars = ufmt_getDecNumChars(u, &len, &convStatus);
#else
      // copy version
      char decNumChars[200];
      int32_t len = ufmt_getDecNumChars(u, decNumChars, 200, &convStatus);
#endif

      if( assertSuccess(fileLine + " (decNumbers conversion)", convStatus) ) {
        logln(fileLine + decNumChars);
        assertEquals(fileLine + " decNumChars length==", len, fDecNum.length());
        assertEquals(fileLine + " decNumChars digits", decNumChars, fDecNum.data());
      }

      UErrorCode int64ConversionF = U_ZERO_ERROR;
      int64_t l = f.getInt64(int64ConversionF);
      UErrorCode int64ConversionU = U_ZERO_ERROR;
      int64_t r = ufmt_getInt64(u, &int64ConversionU);

      if( (l==r)
          && ( uType != UFMT_INT64 ) // int64 better not overflow
          && (U_INVALID_FORMAT_ERROR==int64ConversionU)
          && (U_INVALID_FORMAT_ERROR==int64ConversionF) ) {
        logln("%s:%d: OK: 64 bit overflow", file, line);
      } else {
        assertEquals(fileLine + " as int64 ==", l, r);
        assertSuccess(fileLine + " Formattable.getnt64()", int64ConversionF);
        assertSuccess(fileLine + " ufmt_getInt64()", int64ConversionU);
      }
    }
  }
  return exactMatch || !triedExact;
}

void NumberFormatTest::TestUFormattable(void) {
  {
    // test that a default formattable is equal to Formattable()
    UErrorCode status = U_ZERO_ERROR;
    LocalUFormattablePointer defaultUFormattable(ufmt_open(&status));
    assertSuccess("calling umt_open", status);
    Formattable defaultFormattable;
    assertTrue((UnicodeString)"comparing ufmt_open() with Formattable()",
               (defaultFormattable
                == *(Formattable::fromUFormattable(defaultUFormattable.getAlias()))));
    assertTrue((UnicodeString)"comparing ufmt_open() with Formattable()",
               (defaultFormattable
                == *(Formattable::fromUFormattable(defaultUFormattable.getAlias()))));
    assertTrue((UnicodeString)"comparing Formattable() round tripped through UFormattable",
               (defaultFormattable
                == *(Formattable::fromUFormattable(defaultFormattable.toUFormattable()))));
    assertTrue((UnicodeString)"comparing &Formattable() round tripped through UFormattable",
               ((&defaultFormattable)
                == Formattable::fromUFormattable(defaultFormattable.toUFormattable())));
    assertFalse((UnicodeString)"comparing &Formattable() with ufmt_open()",
               ((&defaultFormattable)
                == Formattable::fromUFormattable(defaultUFormattable.getAlias())));
    testFormattableAsUFormattable(__FILE__, __LINE__, defaultFormattable);
  }
  // test some random Formattables
  {
    Formattable f(ucal_getNow(), Formattable::kIsDate);
    testFormattableAsUFormattable(__FILE__, __LINE__,  f);
  }
  {
    Formattable f((double)1.61803398874989484820); // golden ratio
    testFormattableAsUFormattable(__FILE__, __LINE__,  f);
  }
  {
    Formattable f((int64_t)80994231587905127LL); // weight of the moon, in kilotons http://solarsystem.nasa.gov/planets/profile.cfm?Display=Facts&Object=Moon
    testFormattableAsUFormattable(__FILE__, __LINE__,  f);
  }
  {
    Formattable f((int32_t)4); // random number, source: http://www.xkcd.com/221/
    testFormattableAsUFormattable(__FILE__, __LINE__,  f);
  }
  {
    Formattable f("Hello world."); // should be invariant?
    testFormattableAsUFormattable(__FILE__, __LINE__,  f);
  }
  {
    UErrorCode status2 = U_ZERO_ERROR;
    Formattable f(StringPiece("73476730924573500000000.0"), status2); // weight of the moon, kg
    assertSuccess("Constructing a StringPiece", status2);
    testFormattableAsUFormattable(__FILE__, __LINE__,  f);
  }
  {
    UErrorCode status2 = U_ZERO_ERROR;
    UObject *obj = new Locale();
    Formattable f(obj);
    assertSuccess("Constructing a Formattable from a default constructed Locale()", status2);
    testFormattableAsUFormattable(__FILE__, __LINE__,  f);
  }
  {
    const Formattable array[] = {
      Formattable(ucal_getNow(), Formattable::kIsDate),
      Formattable((int32_t)4),
      Formattable((double)1.234),
    };

    Formattable fa(array, 3);
    testFormattableAsUFormattable(__FILE__, __LINE__, fa);
  }
}

void NumberFormatTest::TestSignificantDigits(void) {
  double input[] = {
        0, 0,
        0.1, -0.1,
        123, -123,
        12345, -12345,
        123.45, -123.45,
        123.44501, -123.44501,
        0.001234, -0.001234,
        0.00000000123, -0.00000000123,
        0.0000000000000000000123, -0.0000000000000000000123,
        1.2, -1.2,
        0.0000000012344501, -0.0000000012344501,
        123445.01, -123445.01,
        12344501000000000000000000000000000.0, -12344501000000000000000000000000000.0,
    };
    const char* expected[] = {
        "0.00", "0.00",
        "0.100", "-0.100",
        "123", "-123",
        "12345", "-12345",
        "123.45", "-123.45",
        "123.45", "-123.45",
        "0.001234", "-0.001234",
        "0.00000000123", "-0.00000000123",
        "0.0000000000000000000123", "-0.0000000000000000000123",
        "1.20", "-1.20",
        "0.0000000012345", "-0.0000000012345",
        "123450", "-123450",
        "12345000000000000000000000000000000", "-12345000000000000000000000000000000",
    };

    UErrorCode status = U_ZERO_ERROR;
    Locale locale("en_US");
    LocalPointer<DecimalFormat> numberFormat(static_cast<DecimalFormat*>(
            NumberFormat::createInstance(locale, status)));
    CHECK_DATA(status,"NumberFormat::createInstance")

    numberFormat->setSignificantDigitsUsed(TRUE);
    numberFormat->setMinimumSignificantDigits(3);
    numberFormat->setMaximumSignificantDigits(5);
    numberFormat->setGroupingUsed(false);

    UnicodeString result;
    UnicodeString expectedResult;
    for (unsigned int i = 0; i < UPRV_LENGTHOF(input); ++i) {
        numberFormat->format(input[i], result);
        UnicodeString expectedResult(expected[i]);
        if (result != expectedResult) {
          errln((UnicodeString)"Expected: '" + expectedResult + "' got '" + result);
        }
        result.remove();
    }
}

void NumberFormatTest::TestShowZero() {
    UErrorCode status = U_ZERO_ERROR;
    Locale locale("en_US");
    LocalPointer<DecimalFormat> numberFormat(static_cast<DecimalFormat*>(
            NumberFormat::createInstance(locale, status)));
    CHECK_DATA(status, "NumberFormat::createInstance")

    numberFormat->setSignificantDigitsUsed(TRUE);
    numberFormat->setMaximumSignificantDigits(3);

    UnicodeString result;
    numberFormat->format(0.0, result);
    if (result != "0") {
        errln((UnicodeString)"Expected: 0, got " + result);
    }
}

void NumberFormatTest::TestBug9936() {
    UErrorCode status = U_ZERO_ERROR;
    Locale locale("en_US");
    LocalPointer<DecimalFormat> numberFormat(static_cast<DecimalFormat*>(
            NumberFormat::createInstance(locale, status)));
    if (U_FAILURE(status)) {
        dataerrln("File %s, Line %d: status = %s.\n", __FILE__, __LINE__, u_errorName(status));
        return;
    }

    if (numberFormat->areSignificantDigitsUsed() == TRUE) {
        errln("File %s, Line %d: areSignificantDigitsUsed() was TRUE, expected FALSE.\n", __FILE__, __LINE__);
    }
    numberFormat->setSignificantDigitsUsed(TRUE);
    if (numberFormat->areSignificantDigitsUsed() == FALSE) {
        errln("File %s, Line %d: areSignificantDigitsUsed() was FALSE, expected TRUE.\n", __FILE__, __LINE__);
    }

    numberFormat->setSignificantDigitsUsed(FALSE);
    if (numberFormat->areSignificantDigitsUsed() == TRUE) {
        errln("File %s, Line %d: areSignificantDigitsUsed() was TRUE, expected FALSE.\n", __FILE__, __LINE__);
    }

    numberFormat->setMinimumSignificantDigits(3);
    if (numberFormat->areSignificantDigitsUsed() == FALSE) {
        errln("File %s, Line %d: areSignificantDigitsUsed() was FALSE, expected TRUE.\n", __FILE__, __LINE__);
    }

    numberFormat->setSignificantDigitsUsed(FALSE);
    numberFormat->setMaximumSignificantDigits(6);
    if (numberFormat->areSignificantDigitsUsed() == FALSE) {
        errln("File %s, Line %d: areSignificantDigitsUsed() was FALSE, expected TRUE.\n", __FILE__, __LINE__);
    }

}

void NumberFormatTest::TestParseNegativeWithFaLocale() {
    UErrorCode status = U_ZERO_ERROR;
    DecimalFormat *test = (DecimalFormat *) NumberFormat::createInstance("fa", status);
    CHECK_DATA(status, "NumberFormat::createInstance")
    test->setLenient(TRUE);
    Formattable af;
    ParsePosition ppos;
    UnicodeString value("\\u200e-0,5");
    value = value.unescape();
    test->parse(value, af, ppos);
    if (ppos.getIndex() == 0) {
        errln("Expected -0,5 to parse for Farsi.");
    }
    delete test;
}

void NumberFormatTest::TestParseNegativeWithAlternateMinusSign() {
    UErrorCode status = U_ZERO_ERROR;
    DecimalFormat *test = (DecimalFormat *) NumberFormat::createInstance("en", status);
    CHECK_DATA(status, "NumberFormat::createInstance")
    test->setLenient(TRUE);
    Formattable af;
    ParsePosition ppos;
    UnicodeString value("\\u208B0.5");
    value = value.unescape();
    test->parse(value, af, ppos);
    if (ppos.getIndex() == 0) {
        errln(UnicodeString("Expected ") + value + UnicodeString(" to parse."));
    }
    delete test;
}

void NumberFormatTest::TestCustomCurrencySignAndSeparator() {
    UErrorCode status = U_ZERO_ERROR;
    DecimalFormatSymbols custom(Locale::getUS(), status);
    CHECK(status, "DecimalFormatSymbols constructor");

    custom.setSymbol(DecimalFormatSymbols::kCurrencySymbol, "*");
    custom.setSymbol(DecimalFormatSymbols::kMonetaryGroupingSeparatorSymbol, "^");
    custom.setSymbol(DecimalFormatSymbols::kMonetarySeparatorSymbol, ":");

    UnicodeString pat(" #,##0.00");
    pat.insert(0, (UChar)0x00A4);

    DecimalFormat fmt(pat, custom, status);
    CHECK(status, "DecimalFormat constructor");

    UnicodeString numstr("* 1^234:56");
    expect2(fmt, (Formattable)((double)1234.56), numstr);
}

typedef struct {
    const char *   locale;
    UBool          lenient;
    UnicodeString  numString;
    double         value;
} SignsAndMarksItem;


void NumberFormatTest::TestParseSignsAndMarks() {
    const SignsAndMarksItem items[] = {
        // locale               lenient numString                                                       value
        { "en",                 FALSE,  CharsToUnicodeString("12"),                                      12 },
        { "en",                 TRUE,   CharsToUnicodeString("12"),                                      12 },
        { "en",                 FALSE,  CharsToUnicodeString("-23"),                                    -23 },
        { "en",                 TRUE,   CharsToUnicodeString("-23"),                                    -23 },
        { "en",                 TRUE,   CharsToUnicodeString("- 23"),                                   -23 },
        { "en",                 FALSE,  CharsToUnicodeString("\\u200E-23"),                             -23 },
        { "en",                 TRUE,   CharsToUnicodeString("\\u200E-23"),                             -23 },
        { "en",                 TRUE,   CharsToUnicodeString("\\u200E- 23"),                            -23 },

        { "en@numbers=arab",    FALSE,  CharsToUnicodeString("\\u0663\\u0664"),                          34 },
        { "en@numbers=arab",    TRUE,   CharsToUnicodeString("\\u0663\\u0664"),                          34 },
        { "en@numbers=arab",    FALSE,  CharsToUnicodeString("-\\u0664\\u0665"),                        -45 },
        { "en@numbers=arab",    TRUE,   CharsToUnicodeString("-\\u0664\\u0665"),                        -45 },
        { "en@numbers=arab",    TRUE,   CharsToUnicodeString("- \\u0664\\u0665"),                       -45 },
        { "en@numbers=arab",    FALSE,  CharsToUnicodeString("\\u200F-\\u0664\\u0665"),                 -45 },
        { "en@numbers=arab",    TRUE,   CharsToUnicodeString("\\u200F-\\u0664\\u0665"),                 -45 },
        { "en@numbers=arab",    TRUE,   CharsToUnicodeString("\\u200F- \\u0664\\u0665"),                -45 },

        { "en@numbers=arabext", FALSE,  CharsToUnicodeString("\\u06F5\\u06F6"),                          56 },
        { "en@numbers=arabext", TRUE,   CharsToUnicodeString("\\u06F5\\u06F6"),                          56 },
        { "en@numbers=arabext", FALSE,  CharsToUnicodeString("-\\u06F6\\u06F7"),                        -67 },
        { "en@numbers=arabext", TRUE,   CharsToUnicodeString("-\\u06F6\\u06F7"),                        -67 },
        { "en@numbers=arabext", TRUE,   CharsToUnicodeString("- \\u06F6\\u06F7"),                       -67 },
        { "en@numbers=arabext", FALSE,  CharsToUnicodeString("\\u200E-\\u200E\\u06F6\\u06F7"),          -67 },
        { "en@numbers=arabext", TRUE,   CharsToUnicodeString("\\u200E-\\u200E\\u06F6\\u06F7"),          -67 },
        { "en@numbers=arabext", TRUE,   CharsToUnicodeString("\\u200E-\\u200E \\u06F6\\u06F7"),         -67 },

        { "he",                 FALSE,  CharsToUnicodeString("12"),                                      12 },
        { "he",                 TRUE,   CharsToUnicodeString("12"),                                      12 },
        { "he",                 FALSE,  CharsToUnicodeString("-23"),                                    -23 },
        { "he",                 TRUE,   CharsToUnicodeString("-23"),                                    -23 },
        { "he",                 TRUE,   CharsToUnicodeString("- 23"),                                   -23 },
        { "he",                 FALSE,  CharsToUnicodeString("\\u200E-23"),                             -23 },
        { "he",                 TRUE,   CharsToUnicodeString("\\u200E-23"),                             -23 },
        { "he",                 TRUE,   CharsToUnicodeString("\\u200E- 23"),                            -23 },

        { "ar",                 FALSE,  CharsToUnicodeString("\\u0663\\u0664"),                          34 },
        { "ar",                 TRUE,   CharsToUnicodeString("\\u0663\\u0664"),                          34 },
        { "ar",                 FALSE,  CharsToUnicodeString("-\\u0664\\u0665"),                        -45 },
        { "ar",                 TRUE,   CharsToUnicodeString("-\\u0664\\u0665"),                        -45 },
        { "ar",                 TRUE,   CharsToUnicodeString("- \\u0664\\u0665"),                       -45 },
        { "ar",                 FALSE,  CharsToUnicodeString("\\u200F-\\u0664\\u0665"),                 -45 },
        { "ar",                 TRUE,   CharsToUnicodeString("\\u200F-\\u0664\\u0665"),                 -45 },
        { "ar",                 TRUE,   CharsToUnicodeString("\\u200F- \\u0664\\u0665"),                -45 },

        { "ar_MA",              FALSE,  CharsToUnicodeString("12"),                                      12 },
        { "ar_MA",              TRUE,   CharsToUnicodeString("12"),                                      12 },
        { "ar_MA",              FALSE,  CharsToUnicodeString("-23"),                                    -23 },
        { "ar_MA",              TRUE,   CharsToUnicodeString("-23"),                                    -23 },
        { "ar_MA",              TRUE,   CharsToUnicodeString("- 23"),                                   -23 },
        { "ar_MA",              FALSE,  CharsToUnicodeString("\\u200E-23"),                             -23 },
        { "ar_MA",              TRUE,   CharsToUnicodeString("\\u200E-23"),                             -23 },
        { "ar_MA",              TRUE,   CharsToUnicodeString("\\u200E- 23"),                            -23 },

        { "fa",                 FALSE,  CharsToUnicodeString("\\u06F5\\u06F6"),                          56 },
        { "fa",                 TRUE,   CharsToUnicodeString("\\u06F5\\u06F6"),                          56 },
        { "fa",                 FALSE,  CharsToUnicodeString("\\u2212\\u06F6\\u06F7"),                  -67 },
        { "fa",                 TRUE,   CharsToUnicodeString("\\u2212\\u06F6\\u06F7"),                  -67 },
        { "fa",                 TRUE,   CharsToUnicodeString("\\u2212 \\u06F6\\u06F7"),                 -67 },
        { "fa",                 FALSE,  CharsToUnicodeString("\\u200E\\u2212\\u200E\\u06F6\\u06F7"),    -67 },
        { "fa",                 TRUE,   CharsToUnicodeString("\\u200E\\u2212\\u200E\\u06F6\\u06F7"),    -67 },
        { "fa",                 TRUE,   CharsToUnicodeString("\\u200E\\u2212\\u200E \\u06F6\\u06F7"),   -67 },

        { "ps",                 FALSE,  CharsToUnicodeString("\\u06F5\\u06F6"),                          56 },
        { "ps",                 TRUE,   CharsToUnicodeString("\\u06F5\\u06F6"),                          56 },
        { "ps",                 FALSE,  CharsToUnicodeString("-\\u06F6\\u06F7"),                        -67 },
        { "ps",                 TRUE,   CharsToUnicodeString("-\\u06F6\\u06F7"),                        -67 },
        { "ps",                 TRUE,   CharsToUnicodeString("- \\u06F6\\u06F7"),                       -67 },
        { "ps",                 FALSE,  CharsToUnicodeString("\\u200E-\\u200E\\u06F6\\u06F7"),          -67 },
        { "ps",                 TRUE,   CharsToUnicodeString("\\u200E-\\u200E\\u06F6\\u06F7"),          -67 },
        { "ps",                 TRUE,   CharsToUnicodeString("\\u200E-\\u200E \\u06F6\\u06F7"),         -67 },
        { "ps",                 FALSE,  CharsToUnicodeString("-\\u200E\\u06F6\\u06F7"),                 -67 },
        { "ps",                 TRUE,   CharsToUnicodeString("-\\u200E\\u06F6\\u06F7"),                 -67 },
        { "ps",                 TRUE,   CharsToUnicodeString("-\\u200E \\u06F6\\u06F7"),                -67 },
        // terminator
        { NULL,                 0,      UnicodeString(""),                                                0 },
    };

    const SignsAndMarksItem * itemPtr;
    for (itemPtr = items; itemPtr->locale != NULL; itemPtr++ ) {
        UErrorCode status = U_ZERO_ERROR;
        NumberFormat *numfmt = NumberFormat::createInstance(Locale(itemPtr->locale), status);
        if (U_SUCCESS(status)) {
            numfmt->setLenient(itemPtr->lenient);
            Formattable fmtobj;
            ParsePosition ppos;
            numfmt->parse(itemPtr->numString, fmtobj, ppos);
            if (ppos.getIndex() == itemPtr->numString.length()) {
                double parsedValue = fmtobj.getDouble(status);
                if (U_FAILURE(status) || parsedValue != itemPtr->value) {
                    errln((UnicodeString)"FAIL: locale " + itemPtr->locale + ", lenient " + itemPtr->lenient + ", parse of \"" + itemPtr->numString + "\" gives value " + parsedValue);
                }
            } else {
                errln((UnicodeString)"FAIL: locale " + itemPtr->locale + ", lenient " + itemPtr->lenient + ", parse of \"" + itemPtr->numString + "\" gives position " + ppos.getIndex());
            }
        } else {
            dataerrln("FAIL: NumberFormat::createInstance for locale % gives error %s", itemPtr->locale, u_errorName(status));
        }
        delete numfmt;
    }
}

typedef struct {
  DecimalFormat::ERoundingMode mode;
  double value;
  UnicodeString expected;
} Test10419Data;


// Tests that rounding works right when fractional digits is set to 0.
void NumberFormatTest::Test10419RoundingWith0FractionDigits() {
    const Test10419Data items[] = {
        { DecimalFormat::kRoundCeiling, 1.488,  "2"},
        { DecimalFormat::kRoundDown, 1.588,  "1"},
        { DecimalFormat::kRoundFloor, 1.888,  "1"},
        { DecimalFormat::kRoundHalfDown, 1.5,  "1"},
        { DecimalFormat::kRoundHalfEven, 2.5,  "2"},
        { DecimalFormat::kRoundHalfUp, 2.5,  "3"},
        { DecimalFormat::kRoundUp, 1.5,  "2"},
    };
    UErrorCode status = U_ZERO_ERROR;
    LocalPointer<DecimalFormat> decfmt((DecimalFormat *) NumberFormat::createInstance(Locale("en_US"), status));
    if (U_FAILURE(status)) {
        dataerrln("Failure creating DecimalFormat %s", u_errorName(status));
        return;
    }
    for (int32_t i = 0; i < UPRV_LENGTHOF(items); ++i) {
        decfmt->setRoundingMode(items[i].mode);
        decfmt->setMaximumFractionDigits(0);
        UnicodeString actual;
        if (items[i].expected != decfmt->format(items[i].value, actual)) {
            errln("Expected " + items[i].expected + ", got " + actual);
        }
    }
}

void NumberFormatTest::Test10468ApplyPattern() {
    // Padding char of fmt is now 'a'
    UErrorCode status = U_ZERO_ERROR;
    DecimalFormat fmt("'I''ll'*a###.##", status);

    if (U_FAILURE(status)) {
        errcheckln(status, "DecimalFormat constructor failed - %s", u_errorName(status));
        return;
    }

    assertEquals("Padding character should be 'a'.", u"a", fmt.getPadCharacterString());

    // Padding char of fmt ought to be '*' since that is the default and no
    // explicit padding char is specified in the new pattern.
    fmt.applyPattern("AA#,##0.00ZZ", status);

    // Oops this still prints 'a' even though we changed the pattern.
    assertEquals("applyPattern did not clear padding character.", u" ", fmt.getPadCharacterString());
}

void NumberFormatTest::TestRoundingScientific10542() {
    UErrorCode status = U_ZERO_ERROR;
    DecimalFormat format("0.00E0", status);
    if (U_FAILURE(status)) {
        errcheckln(status, "DecimalFormat constructor failed - %s", u_errorName(status));
        return;
    }

    DecimalFormat::ERoundingMode roundingModes[] = {
            DecimalFormat::kRoundCeiling,
            DecimalFormat::kRoundDown,
            DecimalFormat::kRoundFloor,
            DecimalFormat::kRoundHalfDown,
            DecimalFormat::kRoundHalfEven,
            DecimalFormat::kRoundHalfUp,
            DecimalFormat::kRoundUp};
    const char *descriptions[] = {
            "Round Ceiling",
            "Round Down",
            "Round Floor",
            "Round half down",
            "Round half even",
            "Round half up",
            "Round up"};

    {
        double values[] = {-0.003006, -0.003005, -0.003004, 0.003014, 0.003015, 0.003016};
        // The order of these expected values correspond to the order of roundingModes and the order of values.
        const char *expected[] = {
                "-3.00E-3", "-3.00E-3", "-3.00E-3", "3.02E-3", "3.02E-3", "3.02E-3",
                "-3.00E-3", "-3.00E-3", "-3.00E-3", "3.01E-3", "3.01E-3", "3.01E-3",
                "-3.01E-3", "-3.01E-3", "-3.01E-3", "3.01E-3", "3.01E-3", "3.01E-3",
                "-3.01E-3", "-3.00E-3", "-3.00E-3", "3.01E-3", "3.01E-3", "3.02E-3",
                "-3.01E-3", "-3.00E-3", "-3.00E-3", "3.01E-3", "3.02E-3", "3.02E-3",
                "-3.01E-3", "-3.01E-3", "-3.00E-3", "3.01E-3", "3.02E-3", "3.02E-3",
                "-3.01E-3", "-3.01E-3", "-3.01E-3", "3.02E-3", "3.02E-3", "3.02E-3"};
        verifyRounding(
                format,
                values,
                expected,
                roundingModes,
                descriptions,
                UPRV_LENGTHOF(values),
                UPRV_LENGTHOF(roundingModes));
    }
    {
        double values[] = {-3006.0, -3005, -3004, 3014, 3015, 3016};
        // The order of these expected values correspond to the order of roundingModes and the order of values.
        const char *expected[] = {
                "-3.00E3", "-3.00E3", "-3.00E3", "3.02E3", "3.02E3", "3.02E3",
                "-3.00E3", "-3.00E3", "-3.00E3", "3.01E3", "3.01E3", "3.01E3",
                "-3.01E3", "-3.01E3", "-3.01E3", "3.01E3", "3.01E3", "3.01E3",
                "-3.01E3", "-3.00E3", "-3.00E3", "3.01E3", "3.01E3", "3.02E3",
                "-3.01E3", "-3.00E3", "-3.00E3", "3.01E3", "3.02E3", "3.02E3",
                "-3.01E3", "-3.01E3", "-3.00E3", "3.01E3", "3.02E3", "3.02E3",
                "-3.01E3", "-3.01E3", "-3.01E3", "3.02E3", "3.02E3", "3.02E3"};
        verifyRounding(
                format,
                values,
                expected,
                roundingModes,
                descriptions,
                UPRV_LENGTHOF(values),
                UPRV_LENGTHOF(roundingModes));
    }
/* Commented out for now until we decide how rounding to zero should work, +0 vs. -0
    {
        double values[] = {0.0, -0.0};
        // The order of these expected values correspond to the order of roundingModes and the order of values.
        const char *expected[] = {
                "0.00E0", "-0.00E0",
                "0.00E0", "-0.00E0",
                "0.00E0", "-0.00E0",
                "0.00E0", "-0.00E0",
                "0.00E0", "-0.00E0",
                "0.00E0", "-0.00E0",
                "0.00E0", "-0.00E0"};
        verifyRounding(
                format,
                values,
                expected,
                roundingModes,
                descriptions,
                UPRV_LENGTHOF(values),
                UPRV_LENGTHOF(roundingModes));
    }
*/
    {

        double values[] = {1e25, 1e25 + 1e15, 1e25 - 1e15};
        // The order of these expected values correspond to the order of roundingModes and the order of values.
        const char *expected[] = {
                "1.00E25", "1.01E25", "1.00E25",
                "1.00E25", "1.00E25", "9.99E24",
                "1.00E25", "1.00E25", "9.99E24",
                "1.00E25", "1.00E25", "1.00E25",
                "1.00E25", "1.00E25", "1.00E25",
                "1.00E25", "1.00E25", "1.00E25",
                "1.00E25", "1.01E25", "1.00E25"};
        verifyRounding(
                format,
                values,
                expected,
                roundingModes,
                descriptions,
                UPRV_LENGTHOF(values),
                UPRV_LENGTHOF(roundingModes));
        }
    {
        double values[] = {-1e25, -1e25 + 1e15, -1e25 - 1e15};
        // The order of these expected values correspond to the order of roundingModes and the order of values.
        const char *expected[] = {
                "-1.00E25", "-9.99E24", "-1.00E25",
                "-1.00E25", "-9.99E24", "-1.00E25",
                "-1.00E25", "-1.00E25", "-1.01E25",
                "-1.00E25", "-1.00E25", "-1.00E25",
                "-1.00E25", "-1.00E25", "-1.00E25",
                "-1.00E25", "-1.00E25", "-1.00E25",
                "-1.00E25", "-1.00E25", "-1.01E25"};
        verifyRounding(
                format,
                values,
                expected,
                roundingModes,
                descriptions,
                UPRV_LENGTHOF(values),
                UPRV_LENGTHOF(roundingModes));
        }
    {
        double values[] = {1e-25, 1e-25 + 1e-35, 1e-25 - 1e-35};
        // The order of these expected values correspond to the order of roundingModes and the order of values.
        const char *expected[] = {
                "1.00E-25", "1.01E-25", "1.00E-25",
                "1.00E-25", "1.00E-25", "9.99E-26",
                "1.00E-25", "1.00E-25", "9.99E-26",
                "1.00E-25", "1.00E-25", "1.00E-25",
                "1.00E-25", "1.00E-25", "1.00E-25",
                "1.00E-25", "1.00E-25", "1.00E-25",
                "1.00E-25", "1.01E-25", "1.00E-25"};
        verifyRounding(
                format,
                values,
                expected,
                roundingModes,
                descriptions,
                UPRV_LENGTHOF(values),
                UPRV_LENGTHOF(roundingModes));
        }
    {
        double values[] = {-1e-25, -1e-25 + 1e-35, -1e-25 - 1e-35};
        // The order of these expected values correspond to the order of roundingModes and the order of values.
        const char *expected[] = {
                "-1.00E-25", "-9.99E-26", "-1.00E-25",
                "-1.00E-25", "-9.99E-26", "-1.00E-25",
                "-1.00E-25", "-1.00E-25", "-1.01E-25",
                "-1.00E-25", "-1.00E-25", "-1.00E-25",
                "-1.00E-25", "-1.00E-25", "-1.00E-25",
                "-1.00E-25", "-1.00E-25", "-1.00E-25",
                "-1.00E-25", "-1.00E-25", "-1.01E-25"};
        verifyRounding(
                format,
                values,
                expected,
                roundingModes,
                descriptions,
                UPRV_LENGTHOF(values),
                UPRV_LENGTHOF(roundingModes));
    }
}

void NumberFormatTest::TestZeroScientific10547() {
    UErrorCode status = U_ZERO_ERROR;
    DecimalFormat fmt("0.00E0", status);
    if (!assertSuccess("Format creation", status)) {
        return;
    }
    UnicodeString out;
    fmt.format(-0.0, out);
    assertEquals("format", "-0.00E0", out, true);
}

void NumberFormatTest::verifyRounding(
        DecimalFormat& format,
        const double *values,
        const char * const *expected,
        const DecimalFormat::ERoundingMode *roundingModes,
        const char * const *descriptions,
        int32_t valueSize,
        int32_t roundingModeSize) {
    for (int32_t i = 0; i < roundingModeSize; ++i) {
        format.setRoundingMode(roundingModes[i]);
        for (int32_t j = 0; j < valueSize; j++) {
            UnicodeString currentExpected(expected[i * valueSize + j]);
            currentExpected = currentExpected.unescape();
            UnicodeString actual;
            format.format(values[j], actual);
            if (currentExpected != actual) {
                dataerrln("For %s value %f, expected '%s', got '%s'",
                          descriptions[i], values[j], CStr(currentExpected)(), CStr(actual)());
            }
        }
    }
}

void NumberFormatTest::TestAccountingCurrency() {
    UErrorCode status = U_ZERO_ERROR;
    UNumberFormatStyle style = UNUM_CURRENCY_ACCOUNTING;

    expect(NumberFormat::createInstance("en_US", style, status),
        (Formattable)(double)1234.5, "$1,234.50", TRUE, status);
    expect(NumberFormat::createInstance("en_US", style, status),
        (Formattable)(double)-1234.5, "($1,234.50)", TRUE, status);
    expect(NumberFormat::createInstance("en_US", style, status),
        (Formattable)(double)0, "$0.00", TRUE, status);
    expect(NumberFormat::createInstance("en_US", style, status),
        (Formattable)(double)-0.2, "($0.20)", TRUE, status);
    expect(NumberFormat::createInstance("ja_JP", style, status),
        (Formattable)(double)10000, UnicodeString("\\uFFE510,000").unescape(), TRUE, status);
    expect(NumberFormat::createInstance("ja_JP", style, status),
        (Formattable)(double)-1000.5, UnicodeString("(\\uFFE51,000)").unescape(), FALSE, status);
    expect(NumberFormat::createInstance("de_DE", style, status),
        (Formattable)(double)-23456.7, UnicodeString("-23.456,70\\u00A0\\u20AC").unescape(), TRUE, status);
}

// for #5186
void NumberFormatTest::TestEquality() {
    UErrorCode status = U_ZERO_ERROR;
    DecimalFormatSymbols symbols(Locale("root"), status);
    if (U_FAILURE(status)) {
    	dataerrln("Fail: can't create DecimalFormatSymbols for root");
    	return;
    }
    UnicodeString pattern("#,##0.###");
    DecimalFormat fmtBase(pattern, symbols, status);
    if (U_FAILURE(status)) {
    	dataerrln("Fail: can't create DecimalFormat using root symbols");
    	return;
    }

    DecimalFormat* fmtClone = (DecimalFormat*)fmtBase.clone();
    fmtClone->setFormatWidth(fmtBase.getFormatWidth() + 32);
    if (*fmtClone == fmtBase) {
        errln("Error: DecimalFormat == does not distinguish objects that differ only in FormatWidth");
    }
    delete fmtClone;
}

void NumberFormatTest::TestCurrencyUsage() {
    double agent = 123.567;

    UErrorCode status;
    DecimalFormat *fmt;

    // compare the Currency and Currency Cash Digits
    // Note that as of CLDR 26:
    // * TWD switches from 0 decimals to 2; PKR still has 0, so change test to that
    // * CAD rounds to .05 in cash mode only
    // 1st time for getter/setter, 2nd time for factory method
    Locale enUS_PKR("en_US@currency=PKR");

    for(int i=0; i<2; i++){
        status = U_ZERO_ERROR;
        if(i == 0){
            fmt = (DecimalFormat *) NumberFormat::createInstance(enUS_PKR, UNUM_CURRENCY, status);
            if (assertSuccess("en_US@currency=PKR/CURRENCY", status, TRUE) == FALSE) {
                continue;
            }

            UnicodeString original;
            fmt->format(agent,original);
            assertEquals("Test Currency Usage 1", u"PKR\u00A0124", original);

            // test the getter here
            UCurrencyUsage curUsage = fmt->getCurrencyUsage();
            assertEquals("Test usage getter - standard", (int32_t)curUsage, (int32_t)UCURR_USAGE_STANDARD);

            fmt->setCurrencyUsage(UCURR_USAGE_CASH, &status);
        }else{
            fmt = (DecimalFormat *) NumberFormat::createInstance(enUS_PKR, UNUM_CASH_CURRENCY, status);
            if (assertSuccess("en_US@currency=PKR/CASH", status, TRUE) == FALSE) {
                continue;
            }
        }

        // must be usage = cash
        UCurrencyUsage curUsage = fmt->getCurrencyUsage();
        assertEquals("Test usage getter - cash", (int32_t)curUsage, (int32_t)UCURR_USAGE_CASH);

        UnicodeString cash_currency;
        fmt->format(agent,cash_currency);
        assertEquals("Test Currency Usage 2", u"PKR\u00A0124", 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", u"CA$123.57", original_rounding);
            fmt->setCurrencyUsage(UCURR_USAGE_CASH, &status);
        }else{
            fmt = (DecimalFormat *) NumberFormat::createInstance(enUS_CAD, UNUM_CASH_CURRENCY, status);
            if (assertSuccess("en_US@currency=CAD/CASH", status, TRUE) == FALSE) {
                continue;
            }
        }

        UnicodeString cash_rounding_currency;
        fmt->format(agent, cash_rounding_currency);
        assertEquals("Test Currency Usage 4", u"CA$123.55", cash_rounding_currency);
        delete fmt;
    }

    // Test the currency change
    // 1st time for getter/setter, 2nd time for factory method
    const UChar CUR_PKR[] = {0x50, 0x4B, 0x52, 0};
    for(int i=0; i<2; i++){
        status = U_ZERO_ERROR;
        if(i == 0){
            fmt = (DecimalFormat *) NumberFormat::createInstance(enUS_CAD, UNUM_CURRENCY, status);
            if (assertSuccess("en_US@currency=CAD/CURRENCY", status, TRUE) == FALSE) {
                continue;
            }
            fmt->setCurrencyUsage(UCURR_USAGE_CASH, &status);
        }else{
            fmt = (DecimalFormat *) NumberFormat::createInstance(enUS_CAD, UNUM_CASH_CURRENCY, status);
            if (assertSuccess("en_US@currency=CAD/CASH", status, TRUE) == FALSE) {
                continue;
            }
        }

        UnicodeString cur_original;
        fmt->setCurrencyUsage(UCURR_USAGE_STANDARD, &status);
        fmt->format(agent, cur_original);
        assertEquals("Test Currency Usage 5", u"CA$123.57", cur_original);

        fmt->setCurrency(CUR_PKR, status);
        assertSuccess("Set currency to PKR", status);

        UnicodeString PKR_changed;
        fmt->format(agent, PKR_changed);
        assertEquals("Test Currency Usage 6", u"PKR\u00A0124", PKR_changed);
        delete fmt;
    }
}


// Check the constant MAX_INT64_IN_DOUBLE.
// The value should convert to a double with no loss of precision.
// A failure may indicate a platform with a different double format, requiring
// a revision to the constant.
//
// Note that this is actually hard to test, because the language standard gives
//  compilers considerable flexibility to do unexpected things with rounding and
//  with overflow in simple int to/from float conversions. Some compilers will completely optimize
//  away a simple round-trip conversion from int64_t -> double -> int64_t.

void NumberFormatTest::TestDoubleLimit11439() {
    char  buf[50];
    for (int64_t num = MAX_INT64_IN_DOUBLE-10; num<=MAX_INT64_IN_DOUBLE; num++) {
        sprintf(buf, "%lld", (long long)num);
        double fNum = 0.0;
        sscanf(buf, "%lf", &fNum);
        int64_t rtNum = static_cast<int64_t>(fNum);
        if (num != rtNum) {
            errln("%s:%d MAX_INT64_IN_DOUBLE test, %lld did not round trip. Got %lld", __FILE__, __LINE__, (long long)num, (long long)rtNum);
            return;
        }
    }
    for (int64_t num = -MAX_INT64_IN_DOUBLE+10; num>=-MAX_INT64_IN_DOUBLE; num--) {
        sprintf(buf, "%lld", (long long)num);
        double fNum = 0.0;
        sscanf(buf, "%lf", &fNum);
        int64_t rtNum = static_cast<int64_t>(fNum);
        if (num != rtNum) {
            errln("%s:%d MAX_INT64_IN_DOUBLE test, %lld did not round trip. Got %lld", __FILE__, __LINE__, (long long)num, (long long)rtNum);
            return;
        }
    }
}

void NumberFormatTest::TestGetAffixes() {
    UErrorCode status = U_ZERO_ERROR;
    DecimalFormatSymbols sym("en_US", status);
    UnicodeString pattern("\\u00a4\\u00a4\\u00a4 0.00 %\\u00a4\\u00a4");
    pattern = pattern.unescape();
    DecimalFormat fmt(pattern, sym, status);
    if (U_FAILURE(status)) {
        dataerrln("Error creating DecimalFormat - %s", u_errorName(status));
        return;
    }
    UnicodeString affixStr;
    assertEquals("", "US dollars ", fmt.getPositivePrefix(affixStr));
    assertEquals("", " %USD", fmt.getPositiveSuffix(affixStr));
    assertEquals("", "-US dollars ", fmt.getNegativePrefix(affixStr));
    assertEquals("", " %USD", fmt.getNegativeSuffix(affixStr));

    // Test equality with affixes. set affix methods can't capture special
    // characters which is why equality should fail.
    {
        DecimalFormat fmtCopy(fmt);
        assertTrue("", fmt == fmtCopy);
        UnicodeString someAffix;
        fmtCopy.setPositivePrefix(fmtCopy.getPositivePrefix(someAffix));
        assertTrue("", fmt != fmtCopy);
    }
    {
        DecimalFormat fmtCopy(fmt);
        assertTrue("", fmt == fmtCopy);
        UnicodeString someAffix;
        fmtCopy.setPositiveSuffix(fmtCopy.getPositiveSuffix(someAffix));
        assertTrue("", fmt != fmtCopy);
    }
    {
        DecimalFormat fmtCopy(fmt);
        assertTrue("", fmt == fmtCopy);
        UnicodeString someAffix;
        fmtCopy.setNegativePrefix(fmtCopy.getNegativePrefix(someAffix));
        assertTrue("", fmt != fmtCopy);
    }
    {
        DecimalFormat fmtCopy(fmt);
        assertTrue("", fmt == fmtCopy);
        UnicodeString someAffix;
        fmtCopy.setNegativeSuffix(fmtCopy.getNegativeSuffix(someAffix));
        assertTrue("", fmt != fmtCopy);
    }
    fmt.setPositivePrefix("Don't");
    fmt.setPositiveSuffix("do");
    UnicodeString someAffix("be''eet\\u00a4\\u00a4\\u00a4 it.");
    someAffix = someAffix.unescape();
    fmt.setNegativePrefix(someAffix);
    fmt.setNegativeSuffix("%");
    assertEquals("", "Don't", fmt.getPositivePrefix(affixStr));
    assertEquals("", "do", fmt.getPositiveSuffix(affixStr));
    assertEquals("", someAffix, fmt.getNegativePrefix(affixStr));
    assertEquals("", "%", fmt.getNegativeSuffix(affixStr));
}

void NumberFormatTest::TestToPatternScientific11648() {
    UErrorCode status = U_ZERO_ERROR;
    Locale en("en");
    DecimalFormatSymbols sym(en, status);
    DecimalFormat fmt("0.00", sym, status);
    if (U_FAILURE(status)) {
        dataerrln("Error creating DecimalFormat - %s", u_errorName(status));
        return;
    }
    fmt.setScientificNotation(TRUE);
    UnicodeString pattern;
    assertEquals("", "0.00E0", fmt.toPattern(pattern));
    DecimalFormat fmt2(pattern, sym, status);
    assertSuccess("", status);
}

void NumberFormatTest::TestBenchmark() {
/*
    UErrorCode status = U_ZERO_ERROR;
    Locale en("en");
    DecimalFormatSymbols sym(en, status);
    DecimalFormat fmt("0.0000000", new DecimalFormatSymbols(sym), status);
//    DecimalFormat fmt("0.00000E0", new DecimalFormatSymbols(sym), status);
//    DecimalFormat fmt("0", new DecimalFormatSymbols(sym), status);
    FieldPosition fpos(FieldPosition::DONT_CARE);
    clock_t start = clock();
    for (int32_t i = 0; i < 1000000; ++i) {
        UnicodeString append;
        fmt.format(3.0, append, fpos, status);
//        fmt.format(4.6692016, append, fpos, status);
//        fmt.format(1234567.8901, append, fpos, status);
//        fmt.format(2.99792458E8, append, fpos, status);
//        fmt.format(31, append);
    }
    errln("Took %f", (double) (clock() - start) / CLOCKS_PER_SEC);
    assertSuccess("", status);

    UErrorCode status = U_ZERO_ERROR;
    MessageFormat fmt("{0, plural, one {I have # friend.} other {I have # friends.}}", status);
    FieldPosition fpos(FieldPosition::DONT_CARE);
    Formattable one(1.0);
    Formattable three(3.0);
    clock_t start = clock();
    for (int32_t i = 0; i < 500000; ++i) {
        UnicodeString append;
        fmt.format(&one, 1, append, fpos, status);
        UnicodeString append2;
        fmt.format(&three, 1, append2, fpos, status);
    }
    errln("Took %f", (double) (clock() - start) / CLOCKS_PER_SEC);
    assertSuccess("", status);

    UErrorCode status = U_ZERO_ERROR;
    Locale en("en");
    Measure measureC(23, MeasureUnit::createCelsius(status), status);
    MeasureFormat fmt(en, UMEASFMT_WIDTH_WIDE, status);
    FieldPosition fpos(FieldPosition::DONT_CARE);
    clock_t start = clock();
    for (int32_t i = 0; i < 1000000; ++i) {
        UnicodeString appendTo;
        fmt.formatMeasures(
                &measureC, 1, appendTo, fpos, status);
    }
    errln("Took %f", (double) (clock() - start) / CLOCKS_PER_SEC);
    assertSuccess("", status);
*/
}

void NumberFormatTest::TestFractionalDigitsForCurrency() {
    UErrorCode status = U_ZERO_ERROR;
    LocalPointer<NumberFormat> fmt(NumberFormat::createCurrencyInstance("en", status));
    if (U_FAILURE(status)) {
        dataerrln("Error creating NumberFormat - %s", u_errorName(status));
        return;
    }
    UChar JPY[] = {0x4A, 0x50, 0x59, 0x0};
    fmt->setCurrency(JPY, status);
    if (!assertSuccess("", status)) {
        return;
    }
    assertEquals("", 0, fmt->getMaximumFractionDigits());
}


void NumberFormatTest::TestFormatCurrencyPlural() {
    UErrorCode status = U_ZERO_ERROR;
    Locale locale = Locale::createCanonical("en_US");
    NumberFormat *fmt = NumberFormat::createInstance(locale, UNUM_CURRENCY_PLURAL, status);
    if (U_FAILURE(status)) {
        dataerrln("Error creating NumberFormat - %s", u_errorName(status));
        return;
    }
   UnicodeString formattedNum;
   fmt->format(11234.567, formattedNum, NULL, status);
   assertEquals("", "11,234.57 US dollars", formattedNum);
   delete fmt;
}

void NumberFormatTest::TestCtorApplyPatternDifference() {
    UErrorCode status = U_ZERO_ERROR;
    DecimalFormatSymbols sym("en_US", status);
    UnicodeString pattern("\\u00a40");
    DecimalFormat fmt(pattern.unescape(), sym, status);
    if (U_FAILURE(status)) {
        dataerrln("Error creating DecimalFormat - %s", u_errorName(status));
        return;
    }
    UnicodeString result;
    assertEquals(
            "ctor favors precision of currency",
            "$5.00",
            fmt.format((double)5, result));
    result.remove();
    fmt.applyPattern(pattern.unescape(), status);
    assertEquals(
            "applyPattern favors precision of pattern",
            "$5",
            fmt.format((double)5, result));
}

void NumberFormatTest::Test11868() {
    double posAmt = 34.567;
    double negAmt = -9876.543;

    Locale selectedLocale("en_US");
    UErrorCode status = U_ZERO_ERROR;

    UnicodeString result;
    FieldPosition fpCurr(UNUM_CURRENCY_FIELD);
    LocalPointer<NumberFormat> fmt(
            NumberFormat::createInstance(
                    selectedLocale, UNUM_CURRENCY_PLURAL, status));
    if (!assertSuccess("Format creation", status)) {
        return;
    }
    fmt->format(posAmt, result, fpCurr, status);
    assertEquals("", "34.57 US dollars", result);
    assertEquals("begin index", 6, fpCurr.getBeginIndex());
    assertEquals("end index", 16, fpCurr.getEndIndex());

    // Test field position iterator
    {
        NumberFormatTest_Attributes attributes[] = {
                {UNUM_INTEGER_FIELD, 0, 2},
                {UNUM_DECIMAL_SEPARATOR_FIELD, 2, 3},
                {UNUM_FRACTION_FIELD, 3, 5},
                {UNUM_CURRENCY_FIELD, 6, 16},
                {0, -1, 0}};
        UnicodeString result;
        FieldPositionIterator iter;
        fmt->format(posAmt, result, &iter, status);
        assertEquals("", "34.57 US dollars", result);
        verifyFieldPositionIterator(attributes, iter);
    }

    result.remove();
    fmt->format(negAmt, result, fpCurr, status);
    assertEquals("", "-9,876.54 US dollars", result);
    assertEquals("begin index", 10, fpCurr.getBeginIndex());
    assertEquals("end index", 20, fpCurr.getEndIndex());

    // Test field position iterator
    {
        NumberFormatTest_Attributes attributes[] = {
                {UNUM_SIGN_FIELD, 0, 1},
                {UNUM_GROUPING_SEPARATOR_FIELD, 2, 3},
                {UNUM_INTEGER_FIELD, 1, 6},
                {UNUM_DECIMAL_SEPARATOR_FIELD, 6, 7},
                {UNUM_FRACTION_FIELD, 7, 9},
                {UNUM_CURRENCY_FIELD, 10, 20},
                {0, -1, 0}};
        UnicodeString result;
        FieldPositionIterator iter;
        fmt->format(negAmt, result, &iter, status);
        assertEquals("", "-9,876.54 US dollars", result);
        verifyFieldPositionIterator(attributes, iter);
    }
}

void NumberFormatTest::Test10727_RoundingZero() {
    IcuTestErrorCode status(*this, "Test10727_RoundingZero");
    DecimalQuantity dq;
    dq.setToDouble(-0.0);
    assertTrue("", dq.isNegative());
    dq.roundToMagnitude(0, UNUM_ROUND_HALFEVEN, status);
    assertTrue("", dq.isNegative());
}

void NumberFormatTest::Test11739_ParseLongCurrency() {
    IcuTestErrorCode status(*this, "Test11739_ParseLongCurrency");
    LocalPointer<NumberFormat> nf(NumberFormat::createCurrencyInstance("sr_BA", status));
    if (status.errDataIfFailureAndReset()) { return; }
    ((DecimalFormat*) nf.getAlias())->applyPattern(u"#,##0.0 ¤¤¤", status);
    ParsePosition ppos(0);
    LocalPointer<CurrencyAmount> result(nf->parseCurrency(u"1.500 амерички долар", ppos));
    assertEquals("Should parse to 1500 USD", -1, ppos.getErrorIndex());
    assertEquals("Should parse to 1500 USD", 1500LL, result->getNumber().getInt64(status));
    assertEquals("Should parse to 1500 USD", u"USD", result->getISOCurrency());
}

void NumberFormatTest::Test13035_MultiCodePointPaddingInPattern() {
    IcuTestErrorCode status(*this, "Test13035_MultiCodePointPaddingInPattern");
    DecimalFormat df(u"a*'நி'###0b", status);
    if (!assertSuccess("", status, true, __FILE__, __LINE__)) { return; }
    UnicodeString result;
    df.format(12, result.remove());
    // TODO(13034): Re-enable this test when support is added in ICU4C.
    //assertEquals("Multi-codepoint padding should not be split", u"aநிநி12b", result);
    df = DecimalFormat(u"a*\U0001F601###0b", status);
    if (!assertSuccess("", status, true, __FILE__, __LINE__)) { return; }
    result = df.format(12, result.remove());
    assertEquals("Single-codepoint padding should not be split", u"a\U0001F601\U0001F60112b", result, true);
    df = DecimalFormat(u"a*''###0b", status);
    if (!assertSuccess("", status, true, __FILE__, __LINE__)) { return; }
    result = df.format(12, result.remove());
    assertEquals("Quote should be escapable in padding syntax", "a''12b", result, true);
}

void NumberFormatTest::Test13737_ParseScientificStrict() {
    IcuTestErrorCode status(*this, "Test13737_ParseScientificStrict");
    LocalPointer<NumberFormat> df(NumberFormat::createScientificInstance("en", status), status);
    if (!assertSuccess("", status, true, __FILE__, __LINE__)) {return;}
    df->setLenient(FALSE);
    // Parse Test
    expect(*df, u"1.2", 1.2);
}

void NumberFormatTest::Test11376_getAndSetPositivePrefix() {
    {
        const UChar USD[] = {0x55, 0x53, 0x44, 0x0};
        UErrorCode status = U_ZERO_ERROR;
        LocalPointer<NumberFormat> fmt(
                NumberFormat::createCurrencyInstance("en", status));
        if (!assertSuccess("", status)) {
            return;
        }
        DecimalFormat *dfmt = (DecimalFormat *) fmt.getAlias();
        dfmt->setCurrency(USD);
        UnicodeString result;

        // This line should be a no-op. I am setting the positive prefix
        // to be the same thing it was before.
        dfmt->setPositivePrefix(dfmt->getPositivePrefix(result));

        UnicodeString appendTo;
        assertEquals("", "$3.78", dfmt->format(3.78, appendTo, status));
        assertSuccess("", status);
    }
    {
        const UChar USD[] = {0x55, 0x53, 0x44, 0x0};
        UErrorCode status = U_ZERO_ERROR;
        LocalPointer<NumberFormat> fmt(
                NumberFormat::createInstance("en", UNUM_CURRENCY_PLURAL, status));
        if (!assertSuccess("", status)) {
            return;
        }
        DecimalFormat *dfmt = (DecimalFormat *) fmt.getAlias();
        UnicodeString result;
        assertEquals("", u" (unknown currency)", 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::Test13327_numberingSystemBufferOverflow() {
    UErrorCode status = U_ZERO_ERROR;
    for (int runId = 0; runId < 2; runId++) {
        // Construct a locale string with a very long "numbers" value.
        // The first time, make the value length exactly equal to ULOC_KEYWORDS_CAPACITY.
        // The second time, make it exceed ULOC_KEYWORDS_CAPACITY.
        int extraLength = (runId == 0) ? 0 : 5;

        CharString localeId("en@numbers=", status);
        for (int i = 0; i < ULOC_KEYWORDS_CAPACITY + extraLength; i++) {
            localeId.append('x', status);
        }
        assertSuccess("Constructing locale string", status);
        Locale locale(localeId.data());

        LocalPointer<NumberingSystem> ns(NumberingSystem::createInstance(locale, status));
        assertFalse("Should not be null", ns.getAlias() == nullptr);
        assertSuccess("Should create with no error", status);
    }
}

void NumberFormatTest::Test13391_chakmaParsing() {
    UErrorCode status = U_ZERO_ERROR;
    LocalPointer<DecimalFormat> df(dynamic_cast<DecimalFormat*>(
        NumberFormat::createInstance(Locale("ccp"), status)));
    if (df == nullptr) {
        dataerrln("%s %d Chakma df is null",  __FILE__, __LINE__);
        return;
    }
    const UChar* expected = u"\U00011137\U00011138,\U00011139\U0001113A\U0001113B";
    UnicodeString actual;
    df->format(12345, actual, status);
    assertSuccess("Should not fail when formatting in ccp", status);
    assertEquals("Should produce expected output in ccp", expected, actual);

    Formattable result;
    df->parse(expected, result, status);
    assertSuccess("Should not fail when parsing in ccp", status);
    assertEquals("Should parse to 12345 in ccp", 12345, result);

    const UChar* expectedScientific = u"\U00011137.\U00011139E\U00011138";
    UnicodeString actualScientific;
    df.adoptInstead(static_cast<DecimalFormat*>(
        NumberFormat::createScientificInstance(Locale("ccp"), status)));
    df->format(130, actualScientific, status);
    assertSuccess("Should not fail when formatting scientific in ccp", status);
    assertEquals("Should produce expected scientific output in ccp",
        expectedScientific, actualScientific);

    Formattable resultScientific;
    df->parse(expectedScientific, resultScientific, status);
    assertSuccess("Should not fail when parsing scientific in ccp", status);
    assertEquals("Should parse scientific to 130 in ccp", 130, resultScientific);
}


void NumberFormatTest::verifyFieldPositionIterator(
        NumberFormatTest_Attributes *expected, FieldPositionIterator &iter) {
    int32_t idx = 0;
    FieldPosition fp;
    while (iter.next(fp)) {
        if (expected[idx].spos == -1) {
            errln("Iterator should have ended. got %d", fp.getField());
            return;
        }
        assertEquals("id", expected[idx].id, fp.getField());
        assertEquals("start", expected[idx].spos, fp.getBeginIndex());
        assertEquals("end", expected[idx].epos, fp.getEndIndex());
        ++idx;
    }
    if (expected[idx].spos != -1) {
        errln("Premature end of iterator. expected %d", expected[idx].id);
    }
}

void NumberFormatTest::Test11735_ExceptionIssue() {
    IcuTestErrorCode status(*this, "Test11735_ExceptionIssue");
    Locale enLocale("en");
    DecimalFormatSymbols symbols(enLocale, status);
    if (status.isSuccess()) {
        DecimalFormat fmt("0", symbols, status);
        assertSuccess("Fail: Construct DecimalFormat formatter", status, true, __FILE__, __LINE__);
        ParsePosition ppos(0);
        fmt.parseCurrency("53.45", ppos);  // NPE thrown here in ICU4J.
        assertEquals("Issue11735 ppos", 0, ppos.getIndex());
    }
}

void NumberFormatTest::Test11035_FormatCurrencyAmount() {
    UErrorCode status = U_ZERO_ERROR;
    double amount = 12345.67;
    const char16_t* expected = u"12,345$67 ​";

    // Test two ways to set a currency via API

    Locale loc1 = Locale("pt_PT");
    LocalPointer<NumberFormat> fmt1(NumberFormat::createCurrencyInstance("loc1", status),
                                    status);
    if (U_FAILURE(status)) {
      dataerrln("%s %d NumberFormat instance fmt1 is null",  __FILE__, __LINE__);
      return;
    }
    fmt1->setCurrency(u"PTE", status);
    assertSuccess("Setting currency on fmt1", status);
    UnicodeString actualSetCurrency;
    fmt1->format(amount, actualSetCurrency);

    Locale loc2 = Locale("pt_PT@currency=PTE");
    LocalPointer<NumberFormat> fmt2(NumberFormat::createCurrencyInstance(loc2, status));
    assertSuccess("Creating fmt2", status);
    UnicodeString actualLocaleString;
    fmt2->format(amount, actualLocaleString);

    // TODO: The following test will fail until DecimalFormat wraps NumberFormatter.
    if (!logKnownIssue("13574")) {
        assertEquals("Custom Currency Pattern, Set Currency", expected, actualSetCurrency);
    }
}

void NumberFormatTest::Test11318_DoubleConversion() {
    IcuTestErrorCode status(*this, "Test11318_DoubleConversion");
    LocalPointer<NumberFormat> nf(NumberFormat::createInstance("en", status), status);
    if (U_FAILURE(status)) {
      dataerrln("%s %d Error in NumberFormat instance creation",  __FILE__, __LINE__);
      return;
    }
    nf->setMaximumFractionDigits(40);
    nf->setMaximumIntegerDigits(40);
    UnicodeString appendTo;
    nf->format(999999999999999.9, appendTo);
    assertEquals("Should render all digits", u"999,999,999,999,999.9", appendTo);
}

void NumberFormatTest::TestParsePercentRegression() {
    IcuTestErrorCode status(*this, "TestParsePercentRegression");
    LocalPointer<DecimalFormat> df1((DecimalFormat*) NumberFormat::createInstance("en", status), status);
    LocalPointer<DecimalFormat> df2((DecimalFormat*) NumberFormat::createPercentInstance("en", status), status);
    if (status.isFailure()) {return; }
    df1->setLenient(TRUE);
    df2->setLenient(TRUE);

    {
        ParsePosition ppos;
        Formattable result;
        df1->parse("50%", result, ppos);
        assertEquals("df1 should accept a number but not the percent sign", 2, ppos.getIndex());
        assertEquals("df1 should return the number as 50", 50.0, result.getDouble(status));
    }
    {
        ParsePosition ppos;
        Formattable result;
        df2->parse("50%", result, ppos);
        assertEquals("df2 should accept the percent sign", 3, ppos.getIndex());
        assertEquals("df2 should return the number as 0.5", 0.5, result.getDouble(status));
    }
    {
        ParsePosition ppos;
        Formattable result;
        df2->parse("50", result, ppos);
        assertEquals("df2 should return the number as 0.5 even though the percent sign is missing",
                0.5,
                result.getDouble(status));
    }
}

void NumberFormatTest::TestMultiplierWithScale() {
    IcuTestErrorCode status(*this, "TestMultiplierWithScale");

    // Test magnitude combined with multiplier, as shown in API docs
    DecimalFormat df("0", {"en", status}, status);
    if (status.isSuccess()) {
        df.setMultiplier(5);
        df.setMultiplierScale(-1);
        expect2(df, 100, u"50"); // round-trip test
    }
}

void NumberFormatTest::TestFastFormatInt32() {
    IcuTestErrorCode status(*this, "TestFastFormatInt32");

    // The two simplest formatters, old API and new API.
    // Old API should use the fastpath for ints.
    LocalizedNumberFormatter lnf = NumberFormatter::withLocale("en");
    LocalPointer<NumberFormat> df(NumberFormat::createInstance("en", status), status);
    if (!assertSuccess("", status, true, __FILE__, __LINE__)) {return;}

    double nums[] = {
            0.0,
            -0.0,
            NAN,
            INFINITY,
            0.1,
            1.0,
            1.1,
            2.0,
            3.0,
            9.0,
            10.0,
            99.0,
            100.0,
            999.0,
            1000.0,
            9999.0,
            10000.0,
            99999.0,
            100000.0,
            999999.0,
            1000000.0,
            static_cast<double>(INT32_MAX) - 1,
            static_cast<double>(INT32_MAX),
            static_cast<double>(INT32_MAX) + 1,
            static_cast<double>(INT32_MIN) - 1,
            static_cast<double>(INT32_MIN),
            static_cast<double>(INT32_MIN) + 1};

    for (auto num : nums) {
        UnicodeString expected = lnf.formatDouble(num, status).toString();
        UnicodeString actual;
        df->format(num, actual);
        assertEquals(UnicodeString("d = ") + num, expected, actual);
    }
}

void NumberFormatTest::Test11646_Equality() {
    UErrorCode status = U_ZERO_ERROR;
    DecimalFormatSymbols symbols(Locale::getEnglish(), status);
    UnicodeString pattern(u"\u00a4\u00a4\u00a4 0.00 %\u00a4\u00a4");
    DecimalFormat fmt(pattern, symbols, status);
    if (!assertSuccess("", status)) return;

    // Test equality with affixes. set affix methods can't capture special
    // characters which is why equality should fail.
    {
        DecimalFormat fmtCopy(fmt);
        assertTrue("", fmt == fmtCopy);
        UnicodeString positivePrefix;
        fmtCopy.setPositivePrefix(fmtCopy.getPositivePrefix(positivePrefix));
        assertFalse("", fmt == fmtCopy);
    }
    {
        DecimalFormat fmtCopy = DecimalFormat(fmt);
        assertTrue("", fmt == fmtCopy);
        UnicodeString positivePrefix;
        fmtCopy.setPositiveSuffix(fmtCopy.getPositiveSuffix(positivePrefix));
        assertFalse("", fmt == fmtCopy);
    }
    {
        DecimalFormat fmtCopy(fmt);
        assertTrue("", fmt == fmtCopy);
        UnicodeString negativePrefix;
        fmtCopy.setNegativePrefix(fmtCopy.getNegativePrefix(negativePrefix));
        assertFalse("", fmt == fmtCopy);
    }
    {
        DecimalFormat fmtCopy(fmt);
        assertTrue("", fmt == fmtCopy);
        UnicodeString negativePrefix;
        fmtCopy.setNegativeSuffix(fmtCopy.getNegativeSuffix(negativePrefix));
        assertFalse("", fmt == fmtCopy);
    }
}

void NumberFormatTest::TestParseNaN() {
    IcuTestErrorCode status(*this, "TestParseNaN");

    DecimalFormat df("0", { "en", status }, status);
    if (!assertSuccess("", status, true, __FILE__, __LINE__)) { return; }
    Formattable parseResult;
    df.parse(u"NaN", parseResult, status);
    assertEquals("NaN should parse successfully", NAN, parseResult.getDouble());
    assertFalse("Result NaN should be positive", std::signbit(parseResult.getDouble()));
    UnicodeString formatResult;
    df.format(parseResult.getDouble(), formatResult);
    assertEquals("NaN should round-trip", u"NaN", formatResult);
}

void NumberFormatTest::Test11897_LocalizedPatternSeparator() {
    IcuTestErrorCode status(*this, "Test11897_LocalizedPatternSeparator");

    // In a locale with a different <list> symbol, like arabic,
    // kPatternSeparatorSymbol should still be ';'
    {
        DecimalFormatSymbols dfs("ar", status);
        assertEquals("pattern separator symbol should be ;",
                u";",
                dfs.getSymbol(DecimalFormatSymbols::kPatternSeparatorSymbol));
    }

    // However, the custom symbol should be used in localized notation
    // when set manually via API
    {
        DecimalFormatSymbols dfs("en", status);
        dfs.setSymbol(DecimalFormatSymbols::kPatternSeparatorSymbol, u"!", FALSE);
        DecimalFormat df(u"0", dfs, status);
        if (!assertSuccess("", status, true, __FILE__, __LINE__)) { return; }
        df.applyPattern("a0;b0", status); // should not throw
        UnicodeString result;
        assertEquals("should apply the normal pattern",
                df.getNegativePrefix(result.remove()),
                "b");
        df.applyLocalizedPattern(u"c0!d0", status); // should not throw
        assertEquals("should apply the localized pattern",
                df.getNegativePrefix(result.remove()),
                "d");
    }
}

void NumberFormatTest::Test13055_PercentageRounding() {
  IcuTestErrorCode status(*this, "PercentageRounding");
  UnicodeString actual;
  LocalPointer<NumberFormat>pFormat(NumberFormat::createPercentInstance("en_US", status));
  if (U_FAILURE(status)) {
      dataerrln("Failure creating DecimalFormat %s", u_errorName(status));
      return;
  }
  pFormat->setMaximumFractionDigits(0);
  pFormat->setRoundingMode(DecimalFormat::kRoundHalfEven);
  pFormat->format(2.155, actual);
  assertEquals("Should round percent toward even number", "216%", actual);
}
  
void NumberFormatTest::Test11839() {
    IcuTestErrorCode errorCode(*this, "Test11839");
    // Ticket #11839: DecimalFormat does not respect custom plus sign
    LocalPointer<DecimalFormatSymbols> dfs(new DecimalFormatSymbols(Locale::getEnglish(), errorCode), errorCode);
    if (!assertSuccess("", errorCode, true, __FILE__, __LINE__)) { return; }
    dfs->setSymbol(DecimalFormatSymbols::kMinusSignSymbol, u"a∸");
    dfs->setSymbol(DecimalFormatSymbols::kPlusSignSymbol, u"b∔"); //  ∔  U+2214 DOT PLUS
    DecimalFormat df(u"0.00+;0.00-", dfs.orphan(), errorCode);
    UnicodeString result;
    df.format(-1.234, result, errorCode);
    assertEquals("Locale-specific minus sign should be used", u"1.23a∸", result);
    df.format(1.234, result.remove(), errorCode);
    assertEquals("Locale-specific plus sign should be used", u"1.23b∔", result);
    // Test round-trip with parse
    expect2(df, -456, u"456.00a∸");
    expect2(df, 456, u"456.00b∔");
}

void NumberFormatTest::Test10354() {
    IcuTestErrorCode errorCode(*this, "Test10354");
    // Ticket #10354: invalid FieldPositionIterator when formatting with empty NaN
    DecimalFormatSymbols dfs(errorCode);
    UnicodeString empty;
    dfs.setSymbol(DecimalFormatSymbols::kNaNSymbol, empty);
    DecimalFormat df(errorCode);
    df.setDecimalFormatSymbols(dfs);
    UnicodeString result;
    FieldPositionIterator positions;
    df.format(NAN, result, &positions, errorCode);
    errorCode.errIfFailureAndReset("DecimalFormat.format(NAN, FieldPositionIterator) failed");
    FieldPosition fp;
    while (positions.next(fp)) {
        // Should not loop forever
    }
}

void NumberFormatTest::Test11645_ApplyPatternEquality() {
    IcuTestErrorCode status(*this, "Test11645_ApplyPatternEquality");
    const char16_t* pattern = u"#,##0.0#";
    LocalPointer<DecimalFormat> fmt((DecimalFormat*) NumberFormat::createInstance(status), status);
    if (!assertSuccess("", status, true, __FILE__, __LINE__)) { return; }
    fmt->applyPattern(pattern, status);
    LocalPointer<DecimalFormat> fmtCopy;

    static const int32_t newMultiplier = 37;
    fmtCopy.adoptInstead(new DecimalFormat(*fmt));
    assertFalse("Value before setter", fmtCopy->getMultiplier() == newMultiplier);
    fmtCopy->setMultiplier(newMultiplier);
    assertEquals("Value after setter", fmtCopy->getMultiplier(), newMultiplier);
    fmtCopy->applyPattern(pattern, status);
    assertEquals("Value after applyPattern", fmtCopy->getMultiplier(), newMultiplier);
    assertFalse("multiplier", *fmt == *fmtCopy);

    static const NumberFormat::ERoundingMode newRoundingMode = NumberFormat::ERoundingMode::kRoundCeiling;
    fmtCopy.adoptInstead(new DecimalFormat(*fmt));
    assertFalse("Value before setter", fmtCopy->getRoundingMode() == newRoundingMode);
    fmtCopy->setRoundingMode(newRoundingMode);
    assertEquals("Value after setter", fmtCopy->getRoundingMode(), newRoundingMode);
    fmtCopy->applyPattern(pattern, status);
    assertEquals("Value after applyPattern", fmtCopy->getRoundingMode(), newRoundingMode);
    assertFalse("roundingMode", *fmt == *fmtCopy);

    static const char16_t *const newCurrency = u"EAT";
    fmtCopy.adoptInstead(new DecimalFormat(*fmt));
    assertFalse("Value before setter", fmtCopy->getCurrency() == newCurrency);
    fmtCopy->setCurrency(newCurrency);
    assertEquals("Value after setter", fmtCopy->getCurrency(), newCurrency);
    fmtCopy->applyPattern(pattern, status);
    assertEquals("Value after applyPattern", fmtCopy->getCurrency(), newCurrency);
    assertFalse("currency", *fmt == *fmtCopy);

    static const UCurrencyUsage newCurrencyUsage = UCurrencyUsage::UCURR_USAGE_CASH;
    fmtCopy.adoptInstead(new DecimalFormat(*fmt));
    assertFalse("Value before setter", fmtCopy->getCurrencyUsage() == newCurrencyUsage);
    fmtCopy->setCurrencyUsage(newCurrencyUsage, status);
    assertEquals("Value after setter", fmtCopy->getCurrencyUsage(), newCurrencyUsage);
    fmtCopy->applyPattern(pattern, status);
    assertEquals("Value after applyPattern", fmtCopy->getCurrencyUsage(), newCurrencyUsage);
    assertFalse("currencyUsage", *fmt == *fmtCopy);
}

void NumberFormatTest::Test12567() {
    IcuTestErrorCode errorCode(*this, "Test12567");
    // Ticket #12567: DecimalFormat.equals() may not be symmetric
    LocalPointer<DecimalFormat> df1((DecimalFormat *)
        NumberFormat::createInstance(Locale::getUS(), UNUM_CURRENCY, errorCode));
    LocalPointer<DecimalFormat> df2((DecimalFormat *)
        NumberFormat::createInstance(Locale::getUS(), UNUM_DECIMAL, errorCode));
    if (!assertSuccess("", errorCode, true, __FILE__, __LINE__)) { return; }
    // NOTE: CurrencyPluralInfo equality not tested in C++ because its operator== is not defined.
    df1->applyPattern(u"0.00", errorCode);
    df2->applyPattern(u"0.00", errorCode);
    assertTrue("df1 == df2", *df1 == *df2);
    assertTrue("df2 == df1", *df2 == *df1);
    df2->setPositivePrefix(u"abc");
    assertTrue("df1 != df2", *df1 != *df2);
    assertTrue("df2 != df1", *df2 != *df1);
}

void NumberFormatTest::Test11626_CustomizeCurrencyPluralInfo() {
    IcuTestErrorCode errorCode(*this, "Test11626_CustomizeCurrencyPluralInfo");
    // Ticket #11626: No unit test demonstrating how to use CurrencyPluralInfo to
    // change formatting spelled out currencies
    // Use locale sr because it has interesting plural rules.
    Locale locale("sr");
    LocalPointer<DecimalFormatSymbols> symbols(new DecimalFormatSymbols(locale, errorCode), errorCode);
    CurrencyPluralInfo info(locale, errorCode);
    if (!assertSuccess("", errorCode, true, __FILE__, __LINE__)) { return; }
    info.setCurrencyPluralPattern(u"one", u"0 qwerty", errorCode);
    info.setCurrencyPluralPattern(u"few", u"0 dvorak", errorCode);
    DecimalFormat df(u"#", symbols.orphan(), UNUM_CURRENCY_PLURAL, errorCode);
    df.setCurrencyPluralInfo(info);
    df.setCurrency(u"USD");
    df.setMaximumFractionDigits(0);

    UnicodeString result;
    assertEquals("Plural one", u"1 qwerty", df.format(1, result, errorCode));
    assertEquals("Plural few", u"3 dvorak", df.format(3, result.remove(), errorCode));
    assertEquals("Plural other", u"99 америчких долара", df.format(99, result.remove(), errorCode));

    info.setPluralRules(u"few: n is 1; one: n in 2..4", errorCode);
    df.setCurrencyPluralInfo(info);
    assertEquals("Plural one", u"1 dvorak", df.format(1, result.remove(), errorCode));
    assertEquals("Plural few", u"3 qwerty", df.format(3, result.remove(), errorCode));
    assertEquals("Plural other", u"99 америчких долара", df.format(99, result.remove(), errorCode));
}

void NumberFormatTest::Test13056_GroupingSize() {
    UErrorCode status = U_ZERO_ERROR;
    DecimalFormat df(u"#,##0", status);
    if (!assertSuccess("", status)) return;
    assertEquals("Primary grouping should return 3", 3, df.getGroupingSize());
    assertEquals("Secondary grouping should return 0", 0, df.getSecondaryGroupingSize());
    df.setSecondaryGroupingSize(3);
    assertEquals("Primary grouping should still return 3", 3, df.getGroupingSize());
    assertEquals("Secondary grouping should round-trip", 3, df.getSecondaryGroupingSize());
    df.setGroupingSize(4);
    assertEquals("Primary grouping should return 4", 4, df.getGroupingSize());
    assertEquals("Secondary should remember explicit setting and return 3", 3, df.getSecondaryGroupingSize());
}


void NumberFormatTest::Test11025_CurrencyPadding() {
    UErrorCode status = U_ZERO_ERROR;
    UnicodeString pattern(u"¤¤ **####0.00");
    DecimalFormatSymbols sym(Locale::getFrance(), status);
    if (!assertSuccess("", status)) return;
    DecimalFormat fmt(pattern, sym, status);
    if (!assertSuccess("", status)) return;
    UnicodeString result;
    fmt.format(433.0, result);
    assertEquals("Number should be padded to 11 characters", "EUR *433,00", result);
}

void NumberFormatTest::Test11648_ExpDecFormatMalPattern() {
    UErrorCode status = U_ZERO_ERROR;

    DecimalFormat fmt("0.00", {"en", status}, status);
    if (!assertSuccess("", status, true, __FILE__, __LINE__)) { return; }
    fmt.setScientificNotation(TRUE);
    UnicodeString pattern;

    assertEquals("A valid scientific notation pattern should be produced",
            "0.00E0",
            fmt.toPattern(pattern));

    DecimalFormat fmt2(pattern, status);
    assertSuccess("", status);
}

void NumberFormatTest::Test11649_DecFmtCurrencies() {
    IcuTestErrorCode status(*this, "Test11649_DecFmtCurrencies");
    UnicodeString pattern("\\u00a4\\u00a4\\u00a4 0.00");
    pattern = pattern.unescape();
    DecimalFormat fmt(pattern, status);
    if (!assertSuccess("", status, true, __FILE__, __LINE__)) { return; }
    static const UChar USD[] = u"USD";
    fmt.setCurrency(USD);
    UnicodeString appendTo;

    assertEquals("", "US dollars 12.34", fmt.format(12.34, appendTo));
    UnicodeString topattern;

    assertEquals("", pattern, fmt.toPattern(topattern));
    DecimalFormat fmt2(topattern, status);
    fmt2.setCurrency(USD);

    appendTo.remove();
    assertEquals("", "US dollars 12.34", fmt2.format(12.34, appendTo));
}

void NumberFormatTest::Test13148_ParseGroupingSeparators() {
  IcuTestErrorCode status(*this, "Test13148");
  LocalPointer<DecimalFormat> fmt(
      (DecimalFormat*)NumberFormat::createInstance("en-ZA", status), status);
  if (!assertSuccess("", status, true, __FILE__, __LINE__)) { return; }

  DecimalFormatSymbols symbols = *fmt->getDecimalFormatSymbols();

  symbols.setSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol, u'.');
  symbols.setSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol, u',');
  fmt->setDecimalFormatSymbols(symbols);
  Formattable number;
  fmt->parse(u"300,000", number, status);
  assertEquals("Should parse as 300000", 300000LL, number.getInt64(status));
}

void NumberFormatTest::Test12753_PatternDecimalPoint() {
    UErrorCode status = U_ZERO_ERROR;
    DecimalFormatSymbols symbols(Locale::getUS(), status);
    symbols.setSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol, u"*", false);
    DecimalFormat df(u"0.00", symbols, status);
    if (!assertSuccess("", status)) return;
    df.setDecimalPatternMatchRequired(true);
    Formattable result;
    df.parse(u"123",result, status);
    assertEquals("Parsing integer succeeded even though setDecimalPatternMatchRequired was set",
                 U_INVALID_FORMAT_ERROR, status);
    }

 void NumberFormatTest::Test11647_PatternCurrencySymbols() {
    UErrorCode status = U_ZERO_ERROR;
    DecimalFormat df(status);
    df.applyPattern(u"¤¤¤¤#", status);
    if (!assertSuccess("", status)) return;
    UnicodeString actual;
    df.format(123, actual);
    assertEquals("Should replace 4 currency signs with U+FFFD", u"\uFFFD123", actual);
}

void NumberFormatTest::Test11913_BigDecimal() {
    UErrorCode status = U_ZERO_ERROR;
    LocalPointer<NumberFormat> df(NumberFormat::createInstance(Locale::getEnglish(), status), status);
    if (!assertSuccess("", status)) return;
    UnicodeString result;
    df->format(StringPiece("1.23456789E400"), result, nullptr, status);
    assertSuccess("", status);
    assertEquals("Should format more than 309 digits", u"12,345,678", UnicodeString(result, 0, 10));
    assertEquals("Should format more than 309 digits", 534, result.length());
}

void NumberFormatTest::Test11020_RoundingInScientificNotation() {
    UErrorCode status = U_ZERO_ERROR;
    DecimalFormatSymbols sym(Locale::getFrance(), status);
    DecimalFormat fmt(u"0.05E0", sym, status);
    if (!assertSuccess("", status, true, __FILE__, __LINE__)) { return; }
    assertSuccess("", status);
    UnicodeString result;
    fmt.format(12301.2, result);
    assertEquals("Rounding increment should be applied after magnitude scaling", u"1,25E4", result);
}

void NumberFormatTest::Test11640_TripleCurrencySymbol() {
    IcuTestErrorCode status(*this, "Test11640_TripleCurrencySymbol");
    UnicodeString actual;
    DecimalFormat dFormat(u"¤¤¤ 0", status);
    if (U_FAILURE(status)) {
        dataerrln("Failure creating DecimalFormat %s", u_errorName(status));
        return;
    }
    dFormat.setCurrency(u"USD");
    UnicodeString result;
    dFormat.getPositivePrefix(result);
    assertEquals("Triple-currency should give long name on getPositivePrefix",
                "US dollars ", result);
}


void NumberFormatTest::Test13763_FieldPositionIteratorOffset() {
    IcuTestErrorCode status(*this, "Test13763_FieldPositionIteratorOffset");
    FieldPositionIterator fpi;
    UnicodeString result(u"foo\U0001F4FBbar"); // 8 code units
    LocalPointer<NumberFormat> nf(NumberFormat::createInstance("en", status), status);
    if (!assertSuccess("", status, true, __FILE__, __LINE__)) { return; }
    nf->format(5142.3, result, &fpi, status);

    int32_t expected[] = {
      UNUM_GROUPING_SEPARATOR_FIELD, 9, 10,
      UNUM_INTEGER_FIELD, 8, 13,
      UNUM_DECIMAL_SEPARATOR_FIELD, 13, 14,
      UNUM_FRACTION_FIELD, 14, 15,
    };
    int32_t tupleCount = UPRV_LENGTHOF(expected)/3;
    expectPositions(fpi, expected, tupleCount, result);
}

void NumberFormatTest::Test13777_ParseLongNameNonCurrencyMode() {
    IcuTestErrorCode status(*this, "Test13777_ParseLongNameNonCurrencyMode");

    LocalPointer<NumberFormat> df(
        NumberFormat::createInstance("en-us", UNumberFormatStyle::UNUM_CURRENCY_PLURAL, status), status);
    if (!assertSuccess("", status, true, __FILE__, __LINE__)) { return; }
    expect2(*df, 1.5, u"1.50 US dollars");
}

void NumberFormatTest::Test13804_EmptyStringsWhenParsing() {
    IcuTestErrorCode status(*this, "Test13804_EmptyStringsWhenParsing");

    DecimalFormatSymbols dfs("en", status);
    if (status.errIfFailureAndReset()) {
        return;
    }
    dfs.setSymbol(DecimalFormatSymbols::kCurrencySymbol, u"", FALSE);
    dfs.setSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol, u"", FALSE);
    dfs.setSymbol(DecimalFormatSymbols::kZeroDigitSymbol, u"", FALSE);
    dfs.setSymbol(DecimalFormatSymbols::kOneDigitSymbol, u"", FALSE);
    dfs.setSymbol(DecimalFormatSymbols::kTwoDigitSymbol, u"", FALSE);
    dfs.setSymbol(DecimalFormatSymbols::kThreeDigitSymbol, u"", FALSE);
    dfs.setSymbol(DecimalFormatSymbols::kFourDigitSymbol, u"", FALSE);
    dfs.setSymbol(DecimalFormatSymbols::kFiveDigitSymbol, u"", FALSE);
    dfs.setSymbol(DecimalFormatSymbols::kSixDigitSymbol, u"", FALSE);
    dfs.setSymbol(DecimalFormatSymbols::kSevenDigitSymbol, u"", FALSE);
    dfs.setSymbol(DecimalFormatSymbols::kEightDigitSymbol, u"", FALSE);
    dfs.setSymbol(DecimalFormatSymbols::kNineDigitSymbol, u"", FALSE);
    dfs.setSymbol(DecimalFormatSymbols::kExponentMultiplicationSymbol, u"", FALSE);
    dfs.setSymbol(DecimalFormatSymbols::kExponentialSymbol, u"", FALSE);
    dfs.setSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol, u"", FALSE);
    dfs.setSymbol(DecimalFormatSymbols::kInfinitySymbol, u"", FALSE);
    dfs.setSymbol(DecimalFormatSymbols::kIntlCurrencySymbol, u"", FALSE);
    dfs.setSymbol(DecimalFormatSymbols::kMinusSignSymbol, u"", FALSE);
    dfs.setSymbol(DecimalFormatSymbols::kMonetarySeparatorSymbol, u"", FALSE);
    dfs.setSymbol(DecimalFormatSymbols::kMonetaryGroupingSeparatorSymbol, u"", FALSE);
    dfs.setSymbol(DecimalFormatSymbols::kNaNSymbol, u"", FALSE);
    dfs.setPatternForCurrencySpacing(UNUM_CURRENCY_INSERT, FALSE, u"");
    dfs.setPatternForCurrencySpacing(UNUM_CURRENCY_INSERT, TRUE, u"");
    dfs.setSymbol(DecimalFormatSymbols::kPercentSymbol, u"", FALSE);
    dfs.setSymbol(DecimalFormatSymbols::kPerMillSymbol, u"", FALSE);
    dfs.setSymbol(DecimalFormatSymbols::kPlusSignSymbol, u"", FALSE);

    DecimalFormat df("0", dfs, status);
    if (status.errIfFailureAndReset()) {
        return;
    }
    df.setGroupingUsed(TRUE);
    df.setScientificNotation(TRUE);
    df.setLenient(TRUE); // enable all matchers
    {
        UnicodeString result;
        df.format(0, result); // should not crash or hit infinite loop
    }
    const char16_t* samples[] = {
            u"",
            u"123",
            u"$123",
            u"-",
            u"+",
            u"44%",
            u"1E+2.3"
    };
    for (auto& sample : samples) {
        logln(UnicodeString(u"Attempting parse on: ") + sample);
        status.setScope(sample);
        // We don't care about the results, only that we don't crash and don't loop.
        Formattable result;
        ParsePosition ppos(0);
        df.parse(sample, result, ppos);
        ppos = ParsePosition(0);
        LocalPointer<CurrencyAmount> curramt(df.parseCurrency(sample, ppos));
        status.errIfFailureAndReset();
    }

    // Test with a nonempty exponent separator symbol to cover more code
    dfs.setSymbol(DecimalFormatSymbols::kExponentialSymbol, u"E", FALSE);
    df.setDecimalFormatSymbols(dfs);
    {
        Formattable result;
        ParsePosition ppos(0);
        df.parse(u"1E+2.3", result, ppos);
    }
}

void NumberFormatTest::Test13840_ParseLongStringCrash() {
    IcuTestErrorCode status(*this, "Test13840_ParseLongStringCrash");

    LocalPointer<NumberFormat> nf(NumberFormat::createInstance("en", status), status);
    if (status.errIfFailureAndReset()) { return; }

    Formattable result;
    static const char16_t* bigString =
        u"111111111111111111111111111111111111111111111111111111111111111111111"
        u"111111111111111111111111111111111111111111111111111111111111111111111"
        u"111111111111111111111111111111111111111111111111111111111111111111111"
        u"111111111111111111111111111111111111111111111111111111111111111111111"
        u"111111111111111111111111111111111111111111111111111111111111111111111"
        u"111111111111111111111111111111111111111111111111111111111111111111111";
    nf->parse(bigString, result, status);

    // Normalize the input string:
    CharString expectedChars;
    expectedChars.appendInvariantChars(bigString, status);
    DecimalQuantity expectedDQ;
    expectedDQ.setToDecNumber(expectedChars.toStringPiece(), status);
    UnicodeString expectedUString = expectedDQ.toScientificString();

    // Get the output string:
    StringPiece actualChars = result.getDecimalNumber(status);
    UnicodeString actualUString = UnicodeString(actualChars.data(), actualChars.length(), US_INV);

    assertEquals("Should round-trip without crashing", expectedUString, actualUString);
}

#endif /* #if !UCONFIG_NO_FORMATTING */
