+void NumberFormatTest::TestJB3832(){
+ const char* localeID = "pt_PT@currency=PTE";
+ Locale loc(localeID);
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString expected(CharsToUnicodeString("1,150$50\\u00A0Esc."));
+ UnicodeString s;
+ NumberFormat* currencyFmt = NumberFormat::createCurrencyInstance(loc, status);
+ if(U_FAILURE(status)){
+ errln("Could not create currency formatter for locale %s", localeID);
+ 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()
+{
+#ifdef U_WINDOWS
+ Win32NumberTest::testLocales(this);
+#endif
+}
+
+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)) {
+ errln("FAIL: Can't create Relative date instance");
+ 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)){
+ errln("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)) {
+ errln("Unable to create decimal formatter.");
+ 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::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);
+
+ // TODO: change all the following int64_t tests once BigInteger is ported
+ // (right now the big numbers get turned into doubles and lose tons of accuracy)
+ static const char* posOutOfRange = "9223372036854780000";
+ static const char* negOutOfRange = "-9223372036854780000";
+
+ expect(df, U_INT64_MIN, posOutOfRange);
+ 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, negOutOfRange);
+
+ df.setMultiplier(-7);
+ expect(df, -(U_INT64_MAX/7)-1, posOutOfRange);
+ 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());
+}
+
+void
+NumberFormatTest::TestSpaceParsing() {
+ // the data are:
+ // the string to be parsed, parsed position, parsed error index
+ const char* DATA[][3] = {
+ {"$124", "4", "-1"},
+ {"$124 $124", "4", "-1"},
+ {"$124 ", "4", "-1"},
+ {"$ 124 ", "5", "-1"},
+ {"$\\u00A0124 ", "5", "-1"},
+ {" $ 124 ", "6", "-1"},
+ //{"124$", "4", "-1"}, // TODO: need to handle trailing currency correctly
+ {"124$", "3", "-1"},
+ //{"124 $", "5", "-1"}, // TODO: OK or not, need currency spacing rule
+ {"124 $", "3", "-1"},
+ };
+
+ UErrorCode status = U_ZERO_ERROR;
+ Locale locale("en_US");
+ NumberFormat* foo = NumberFormat::createCurrencyInstance(locale, status);
+ if (U_FAILURE(status)) {
+ delete foo;
+ return;
+ }
+
+ foo->setParseStrict(FALSE);
+ for (uint32_t i = 0; i < sizeof(DATA)/sizeof(DATA[0]); ++i) {
+ ParsePosition parsePosition(0);
+ UnicodeString stringToBeParsed = ctou(DATA[i][0]);
+ int parsedPosition = atoi(DATA[i][1]);
+ int errorIndex = atoi(DATA[i][2]);
+ Formattable result;
+ foo->parse(stringToBeParsed, result, parsePosition);
+ if (parsePosition.getIndex() != parsedPosition ||
+ parsePosition.getErrorIndex() != errorIndex) {
+ errln("FAILED parse " + stringToBeParsed + "; 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;
+}