]> granicus.if.org Git - icu/commitdiff
ICU-13634 A variety of mostly minor changes to fix assorted unit test failures in...
authorShane Carr <shane@unicode.org>
Tue, 17 Apr 2018 08:05:20 +0000 (08:05 +0000)
committerShane Carr <shane@unicode.org>
Tue, 17 Apr 2018 08:05:20 +0000 (08:05 +0000)
X-SVN-Rev: 41236

27 files changed:
icu4c/source/i18n/decimfmt.cpp
icu4c/source/i18n/fmtable.cpp
icu4c/source/i18n/number_decimalquantity.cpp
icu4c/source/i18n/number_decimalquantity.h
icu4c/source/i18n/number_decimfmtprops.cpp
icu4c/source/i18n/number_decimfmtprops.h
icu4c/source/i18n/numparse_decimal.cpp
icu4c/source/i18n/numparse_impl.cpp
icu4c/source/i18n/numparse_impl.h
icu4c/source/i18n/numparse_parsednumber.cpp
icu4c/source/i18n/numparse_scientific.cpp
icu4c/source/i18n/numparse_types.h
icu4c/source/test/intltest/numbertest_decimalquantity.cpp
icu4c/source/test/intltest/numbertest_parse.cpp
icu4c/source/test/intltest/numrgts.cpp
icu4c/source/test/intltest/tmsgfmt.cpp
icu4c/source/test/intltest/tsdcfmsy.cpp
icu4j/main/classes/core/src/com/ibm/icu/impl/number/DecimalFormatProperties.java
icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/NumberParserImpl.java
icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/ParsedNumber.java
icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/ParsingUtils.java
icu4j/main/classes/core/src/com/ibm/icu/impl/number/parse/ScientificMatcher.java
icu4j/main/classes/core/src/com/ibm/icu/number/NumberPropertyMapper.java
icu4j/main/classes/core/src/com/ibm/icu/text/DecimalFormat.java
icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/NumberFormatDataDrivenTest.java
icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/NumberRegressionTests.java
icu4j/main/tests/core/src/com/ibm/icu/dev/test/number/NumberParserTest.java

index f95b8112310d5bcf199a63a13ca357e84178d054..5a625675c115cdae0b8af9578fd47b7a9ea678fd 100644 (file)
@@ -512,7 +512,7 @@ void DecimalFormat::parse(const UnicodeString& text, Formattable& output,
     // TODO: Do we need to check for fProperties->parseAllInput (UCONFIG_HAVE_PARSEALLINPUT) here?
     if (result.success()) {
         parsePosition.setIndex(result.charEnd);
-        result.populateFormattable(output);
+        result.populateFormattable(output, fParser->getParseFlags());
     } else {
         parsePosition.setErrorIndex(startIndex + result.charEnd);
     }
@@ -533,7 +533,7 @@ CurrencyAmount* DecimalFormat::parseCurrency(const UnicodeString& text, ParsePos
     if (result.success()) {
         parsePosition.setIndex(result.charEnd);
         Formattable formattable;
-        result.populateFormattable(formattable);
+        result.populateFormattable(formattable, fParser->getParseFlags());
         return new CurrencyAmount(formattable, result.currencyCode, status);
     } else {
         parsePosition.setErrorIndex(startIndex + result.charEnd);
index 299adfa2449e836bd3ede058990820446d2d3139..dd465a60e0fd4ac4a1044d2ef06646c6dfc75a15 100644 (file)
@@ -462,12 +462,12 @@ Formattable::getInt64(UErrorCode& status) const
             status = U_INVALID_FORMAT_ERROR;
             return U_INT64_MIN;
         } else if (fabs(fValue.fDouble) > U_DOUBLE_MAX_EXACT_INT && fDecimalQuantity != NULL) {
-            if (fDecimalQuantity->fitsInLong()) {
+            if (fDecimalQuantity->fitsInLong(true)) {
                 return fDecimalQuantity->toLong();
-            } else if (fDecimalQuantity->isNegative()) {
-                return U_INT64_MIN;
             } else {
-                return U_INT64_MAX;
+                // Unexpected
+                status = U_INVALID_FORMAT_ERROR;
+                return fDecimalQuantity->isNegative() ? U_INT64_MIN : U_INT64_MAX;
             }
         } else {
             return (int64_t)fValue.fDouble;
index 0fa6dada975686061b758a53063c34a5bb49a991..77597022883b4c6be21b4e005b3cbd1390e2f96d 100644 (file)
@@ -173,9 +173,11 @@ void DecimalQuantity::roundToIncrement(double roundingIncrement, RoundingMode ro
     roundToInfinity();
     double temp = toDouble();
     temp /= roundingIncrement;
-    setToDouble(temp);
-    roundToMagnitude(0, roundingMode, status);
-    temp = toDouble();
+    // Use another DecimalQuantity to perform the actual rounding...
+    DecimalQuantity dq;
+    dq.setToDouble(temp);
+    dq.roundToMagnitude(0, roundingMode, status);
+    temp = dq.toDouble();
     temp *= roundingIncrement;
     setToDouble(temp);
     // Since we reset the value to a double, we need to specify the rounding boundary
@@ -498,8 +500,7 @@ int64_t DecimalQuantity::toLong(bool truncateIfOverflow) const {
     // NOTE: Call sites should be guarded by fitsInLong(), like this:
     // if (dq.fitsInLong()) { /* use dq.toLong() */ } else { /* use some fallback */ }
     // Fallback behavior upon truncateIfOverflow is to truncate at 17 digits.
-    U_ASSERT(truncateIfOverflow || fitsInLong());
-    int64_t result = 0L;
+    uint64_t result = 0L;
     int32_t upperMagnitude = std::min(scale + precision, lOptPos) - 1;
     if (truncateIfOverflow) {
         upperMagnitude = std::min(upperMagnitude, 17);
@@ -508,7 +509,7 @@ int64_t DecimalQuantity::toLong(bool truncateIfOverflow) const {
         result = result * 10 + getDigitPos(magnitude - scale);
     }
     if (isNegative()) {
-        result = -result;
+        return -result;
     }
     return result;
 }
@@ -532,11 +533,11 @@ uint64_t DecimalQuantity::toFractionLong(bool includeTrailingZeros) const {
     return result;
 }
 
-bool DecimalQuantity::fitsInLong() const {
+bool DecimalQuantity::fitsInLong(bool ignoreFraction) const {
     if (isZero()) {
         return true;
     }
-    if (scale < 0) {
+    if (scale < 0 && !ignoreFraction) {
         return false;
     }
     int magnitude = getMagnitude();
index f440544a7b0f497794fd37017555ee7a08805c85..2a7ea8be44821aa1dbc33d8f50cd6bc61ed44f07 100644 (file)
@@ -150,8 +150,9 @@ class U_I18N_API DecimalQuantity : public IFixedDecimal, public UMemory {
 
     /**
      * Returns whether or not a Long can fully represent the value stored in this DecimalQuantity.
+     * @param ignoreFraction if true, silently ignore digits after the decimal place.
      */
-    bool fitsInLong() const;
+    bool fitsInLong(bool ignoreFraction = false) const;
 
     /** @return The value contained in this {@link DecimalQuantity} approximated as a double. */
     double toDouble() const;
index 412a04d8f35af506835e055b4b2a2b6d6d41a51a..10a9eb00293af662878c732cdc371759a88f77b0 100644 (file)
@@ -25,7 +25,7 @@ void DecimalFormatProperties::clear() {
     exponentSignAlwaysShown = false;
     formatWidth = -1;
     groupingSize = -1;
-    groupingUsed = false;
+    groupingUsed = true;
     magnitudeMultiplier = 0;
     maximumFractionDigits = -1;
     maximumIntegerDigits = -1;
index 2cac011c7d6f903e7a0a274a0d0a887b6d2fbb43..8e823a80067a5031e4d755bfc1568c3a8ecb0ad2 100644 (file)
@@ -119,7 +119,7 @@ struct U_I18N_API DecimalFormatProperties {
     bool parseIntegerOnly;
     NullableValue<ParseMode> parseMode;
     bool parseNoExponent;
-    bool parseToBigDecimal;
+    bool parseToBigDecimal; // TODO: Not needed in ICU4C?
     UNumberFormatAttributeValue parseAllInput; // ICU4C-only
     //PluralRules pluralRules;
     UnicodeString positivePrefix;
index 28a67d85bacc108172ef85fce15cef71a7faed4c..f3f17b636314eb9cf532e74e61282c0bb049410c 100644 (file)
@@ -254,6 +254,12 @@ bool DecimalMatcher::match(StringSegment& segment, ParsedNumber& result, int8_t
         break;
     }
 
+    // Back up if there was a trailing grouping separator
+    if (backupOffset != -1) {
+        segment.setOffset(backupOffset);
+        hasPartialPrefix = true; // redundant with `groupingOverlap == segment.length()`
+    }
+
     // Check the final grouping for validity
     if (requireGroupingMatch && !seenDecimal && seenGrouping && afterFirstGrouping &&
         groupedDigitCount != grouping1) {
index 547ba6b55ddc17db8ff855f676323a8e33b4b7dd..a9ccbbc88c461ae80b97554ff56fed4a5bac1631 100644 (file)
@@ -232,6 +232,10 @@ void NumberParserImpl::freeze() {
     fFrozen = true;
 }
 
+parse_flags_t NumberParserImpl::getParseFlags() const {
+    return fParseFlags;
+}
+
 void NumberParserImpl::parse(const UnicodeString& input, bool greedy, ParsedNumber& result,
                              UErrorCode& status) const {
     return parse(input, 0, greedy, result, status);
index 748b9415ecb80398146fd03484c4ede3c64f7472..f6688c1e214b75785185e85616de4f45c01e08ef 100644 (file)
@@ -42,6 +42,8 @@ class NumberParserImpl : public MutableMatcherCollection {
 
     void freeze();
 
+    parse_flags_t getParseFlags() const;
+
     void parse(const UnicodeString& input, bool greedy, ParsedNumber& result, UErrorCode& status) const;
 
     void parse(const UnicodeString& input, int32_t start, bool greedy, ParsedNumber& result,
index f97219eed8294e5f90903a899736efe08bf64596..7adfb5ca56541c9f3d45bb823f7c1dd494ac5ac7 100644 (file)
@@ -78,9 +78,10 @@ double ParsedNumber::getDouble() const {
     }
 }
 
-void ParsedNumber::populateFormattable(Formattable& output) const {
+void ParsedNumber::populateFormattable(Formattable& output, parse_flags_t parseFlags) const {
     bool sawNaN = 0 != (flags & FLAG_NAN);
     bool sawInfinity = 0 != (flags & FLAG_INFINITY);
+    bool integerOnly = 0 != (parseFlags & PARSE_FLAG_INTEGER_ONLY);
 
     // Check for NaN, infinity, and -0.0
     if (sawNaN) {
@@ -97,7 +98,7 @@ void ParsedNumber::populateFormattable(Formattable& output) const {
         }
     }
     U_ASSERT(!quantity.bogus);
-    if (quantity.isZero() && quantity.isNegative()) {
+    if (quantity.isZero() && quantity.isNegative() && !integerOnly) {
         output.setDouble(-0.0);
         return;
     }
index 849eab6837233056c512e37d57686f266579d4f2..bbf7738f99a02dbd89e232add531696316263ddf 100644 (file)
@@ -52,9 +52,7 @@ ScientificMatcher::ScientificMatcher(const DecimalFormatSymbols& dfs, const Grou
 
 bool ScientificMatcher::match(StringSegment& segment, ParsedNumber& result, UErrorCode& status) const {
     // Only accept scientific notation after the mantissa.
-    // Most places use result.hasNumber(), but we need a stronger condition here (i.e., exponent is
-    // not well-defined after NaN or infinity).
-    if (result.quantity.bogus) {
+    if (!result.seenNumber()) {
         return false;
     }
 
@@ -95,8 +93,13 @@ bool ScientificMatcher::match(StringSegment& segment, ParsedNumber& result, UErr
             segment.adjustOffset(overlap2);
         }
 
+        // We are supposed to accept E0 after NaN, so we need to make sure result.quantity is available.
+        bool wasBogus = result.quantity.bogus;
+        result.quantity.bogus = false;
         int digitsOffset = segment.getOffset();
         bool digitsReturnValue = fExponentMatcher.match(segment, result, exponentSign, status);
+        result.quantity.bogus = wasBogus;
+
         if (segment.getOffset() != digitsOffset) {
             // At least one exponent digit was matched.
             result.flags |= FLAG_HAS_EXPONENT;
index 4e4456538b383e3a65e1d1ae1cb5b3cafd77d34f..aa64497545266a2d7a47b7997246d4ebaa55d000 100644 (file)
@@ -159,7 +159,7 @@ class ParsedNumber {
 
     double getDouble() const;
 
-    void populateFormattable(Formattable& output) const;
+    void populateFormattable(Formattable& output, parse_flags_t parseFlags) const;
 
     bool isBetterThan(const ParsedNumber& other);
 };
index fdd9124f0c32b707c08247fa1ea7548775ac4071..db594a786f4c84adece717a1ab9babcbf444bb20 100644 (file)
@@ -366,7 +366,7 @@ void DecimalQuantityTest::testMaxDigits() {
     dq.setFractionLength(0, 2);
     assertEquals("Should trim, toPlainString", "76.54", dq.toPlainString());
     assertEquals("Should trim, toScientificString", "7.654E+1", dq.toScientificString());
-    assertEquals("Should trim, toLong", 76L, dq.toLong());
+    assertEquals("Should trim, toLong", 76L, dq.toLong(true));
     assertEquals("Should trim, toFractionLong", 54L, dq.toFractionLong(false));
     assertEquals("Should trim, toDouble", 76.54, dq.toDouble());
     // To test DecNum output, check the round-trip.
index e5a10c2c3fb9ef0055f10ed769b3b1553ed2530e..97084dc9eeb3931f8507e1bd6c21113ef1bb7b93 100644 (file)
@@ -99,7 +99,7 @@ void NumberParserTest::testBasic() {
                  {3, u".00", u"0", 3, 0.0},
                  {3, u"                              1,234", u"a0", 35, 1234.}, // should not hang
                  {3, u"NaN", u"0", 3, NAN},
-                 {3, u"NaN E5", u"0", 3, NAN},
+                 {3, u"NaN E5", u"0", 6, NAN},
                  {3, u"0", u"0", 1, 0.0}};
 
     parse_flags_t parseFlags = PARSE_FLAG_IGNORE_CASE | PARSE_FLAG_INCLUDE_UNPAIRED_AFFIXES;
index e4852bd4cdcb6203a8541e79916c1b5ae4e0477a..56e85120e6d99e0f0ba0b1a0a4ce3d99b53169bf 100644 (file)
@@ -806,29 +806,29 @@ void NumberFormatRegressionTest::Test4092480 (void)
         dfFoo->applyPattern("0000;-000", status);
         failure(status, "dfFoo->applyPattern");
         UnicodeString temp;
-        if (dfFoo->toPattern(temp) != UnicodeString("#0000"))
-            errln("dfFoo.toPattern : " + dfFoo->toPattern(temp));
+        if (dfFoo->toPattern(temp) != UnicodeString("0000"))
+            errln("ERROR: dfFoo.toPattern : " + dfFoo->toPattern(temp));
         FieldPosition pos(FieldPosition::DONT_CARE);
         logln(dfFoo->format((int32_t)42, temp, pos));
         logln(dfFoo->format((int32_t)-42, temp, pos));
         dfFoo->applyPattern("000;-000", status);
         failure(status, "dfFoo->applyPattern");
-        if (dfFoo->toPattern(temp) != UnicodeString("#000"))
-            errln("dfFoo.toPattern : " + dfFoo->toPattern(temp));
+        if (dfFoo->toPattern(temp) != UnicodeString("000"))
+            errln("ERROR: dfFoo.toPattern : " + dfFoo->toPattern(temp));
         logln(dfFoo->format((int32_t)42,temp, pos));
         logln(dfFoo->format((int32_t)-42, temp, pos));
 
         dfFoo->applyPattern("000;-0000", status);
         failure(status, "dfFoo->applyPattern");
-        if (dfFoo->toPattern(temp) != UnicodeString("#000"))
-            errln("dfFoo.toPattern : " + dfFoo->toPattern(temp));
+        if (dfFoo->toPattern(temp) != UnicodeString("000"))
+            errln("ERROR: dfFoo.toPattern : " + dfFoo->toPattern(temp));
         logln(dfFoo->format((int32_t)42, temp, pos));
         logln(dfFoo->format((int32_t)-42, temp, pos));
 
         dfFoo->applyPattern("0000;-000", status);
         failure(status, "dfFoo->applyPattern");
-        if (dfFoo->toPattern(temp) != UnicodeString("#0000"))
-            errln("dfFoo.toPattern : " + dfFoo->toPattern(temp));
+        if (dfFoo->toPattern(temp) != UnicodeString("0000"))
+            errln("ERROR: dfFoo.toPattern : " + dfFoo->toPattern(temp));
         logln(dfFoo->format((int32_t)42, temp, pos));
         logln(dfFoo->format((int32_t)-42, temp, pos));
     /*} catch (Exception foo) {
@@ -1691,6 +1691,12 @@ void NumberFormatRegressionTest::Test4122840(void)
         // Create a DecimalFormat using the pattern we got and format a number
         DecimalFormatSymbols *symbols = new DecimalFormatSymbols(locales[i], status);
         failure(status, "new DecimalFormatSymbols");
+
+        // Disable currency spacing for the purposes of this test.
+        // To do this, set the spacing insert to the empty string both before and after the symbol.
+        symbols->setPatternForCurrencySpacing(UNUM_CURRENCY_INSERT, FALSE, u"");
+        symbols->setPatternForCurrencySpacing(UNUM_CURRENCY_INSERT, TRUE, u"");
+
         DecimalFormat *fmt1 = new DecimalFormat(pattern, *symbols, status);
         failure(status, "new DecimalFormat");
         
@@ -2003,6 +2009,8 @@ void NumberFormatRegressionTest::Test4145457() {
  * DecimalFormat.applyPattern() sets minimum integer digits incorrectly.
  * CANNOT REPRODUCE
  * This bug is a duplicate of 4139344, which is a duplicate of 4134300
+ *
+ * ICU 62: minInt is always at least one, and the getter should reflect that!
  */
 void NumberFormatRegressionTest::Test4147295(void) 
 {
@@ -2013,7 +2021,7 @@ void NumberFormatRegressionTest::Test4147295(void)
     sdf->applyPattern(pattern, status);
     if (!failure(status, "sdf->applyPattern")) {
         int minIntDig = sdf->getMinimumIntegerDigits();
-        if (minIntDig != 0) {
+        if (minIntDig != 1) {
             errln("Test failed");
             errln(UnicodeString(" Minimum integer digits : ") + minIntDig);
             UnicodeString temp;
@@ -2205,26 +2213,28 @@ void NumberFormatRegressionTest::Test4167494(void) {
  * DecimalFormat.parse() fails when ParseIntegerOnly set to true
  */
 void NumberFormatRegressionTest::Test4170798(void) {
-    UErrorCode status = U_ZERO_ERROR;
-    NumberFormat *nf = NumberFormat::createInstance(Locale::getUS(), status);
-    if (failure(status, "NumberFormat::createInstance", TRUE)){
-        delete nf;
-        return;
-    };
-    DecimalFormat *df = dynamic_cast<DecimalFormat *>(nf);
-    if(df == NULL) {
-        errln("DecimalFormat needed to continue");
-        return;
+    IcuTestErrorCode status(*this, "Test4170798");
+    LocalPointer<DecimalFormat> df(dynamic_cast<DecimalFormat*>(
+            NumberFormat::createInstance(Locale::getUS(), status)), status);
+    {
+        Formattable n;
+        ParsePosition pos(0);
+        df->parse("-0.0", n, pos);
+        if (n.getType() != Formattable::kDouble
+            || n.getDouble() != -0.0) {
+            errln(UnicodeString("FAIL: default parse(\"-0.0\") returns ") + toString(n));
+        }
     }
     df->setParseIntegerOnly(TRUE);
-    Formattable n;
-    ParsePosition pos(0);
-    df->parse("-0.0", n, pos);
-    if (n.getType() != Formattable::kLong
-        || n.getLong() != 0) {
-        errln(UnicodeString("FAIL: parse(\"-0.0\") returns ") + toString(n));
+    {
+        Formattable n;
+        ParsePosition pos(0);
+        df->parse("-0.0", n, pos);
+        if (n.getType() != Formattable::kLong
+            || n.getLong() != 0) {
+            errln(UnicodeString("FAIL: integer parse(\"-0.0\") returns ") + toString(n));
+        }
     }
-    delete nf;
 }
 
 /**
@@ -2233,15 +2243,15 @@ void NumberFormatRegressionTest::Test4170798(void) {
  */
 void NumberFormatRegressionTest::Test4176114(void) {
     const char* DATA[] = {
-        "00", "#00",
-        "000", "#000", // No grouping
-        "#000", "#000", // No grouping
+        "00", "00",
+        "000", "000", // No grouping
+        "#000", "000", // No grouping
         "#,##0", "#,##0",
         "#,000", "#,000",
-        "0,000", "#0,000",
-        "00,000", "#00,000",
-        "000,000", "#,000,000",
-        "0,000,000,000,000.0000", "#0,000,000,000,000.0000", // Reported
+        "0,000", "0,000",
+        "00,000", "00,000",
+        "000,000", "000,000",
+        "0,000,000,000,000.0000", "0,000,000,000,000.0000", // Reported
     };
     int DATA_length = UPRV_LENGTHOF(DATA);
     UErrorCode status = U_ZERO_ERROR;
@@ -2372,9 +2382,9 @@ void NumberFormatRegressionTest::Test4212072(void) {
     sym.setSymbol(DecimalFormatSymbols::kCurrencySymbol, "usd");
     fmt.setDecimalFormatSymbols(sym);
     s.remove();
-    if (fmt.format(12.5, s, pos) != UnicodeString("usd12.50")) {
+    if (fmt.format(12.5, s, pos) != UnicodeString(u"usd\u00A012.50")) {
         errln(UnicodeString("FAIL: 12.5 x (currency=usd) -> ") + s +
-              ", exp usd12.50");
+              u", exp usd\u00A012.50");
     }
     s.remove();
     if (fmt.getPositivePrefix(s) != UnicodeString("usd")) {
@@ -2388,9 +2398,9 @@ void NumberFormatRegressionTest::Test4212072(void) {
     sym.setSymbol(DecimalFormatSymbols::kIntlCurrencySymbol, "DOL");
     fmt.setDecimalFormatSymbols(sym);
     s.remove();
-    if (fmt.format(12.5, s, pos) != UnicodeString("DOL12.50")) {
+    if (fmt.format(12.5, s, pos) != UnicodeString(u"DOL\u00A012.50")) {
         errln(UnicodeString("FAIL: 12.5 x (intlcurrency=DOL) -> ") + s +
-              ", exp DOL12.50");
+              u", exp DOL\u00A012.50");
     }
     s.remove();
     if (fmt.getPositivePrefix(s) != UnicodeString("DOL")) {
@@ -2734,7 +2744,7 @@ void NumberFormatRegressionTest::TestJ691(void) {
 #define TEST_ASSERT_EQUALS(x,y)                  \
     {                                                                     \
       char _msg[1000]; \
-      int32_t len = sprintf (_msg,"File %s, line %d: Assertion Failed: " #x "==" #y "\n", __FILE__, __LINE__); \
+      int32_t len = sprintf (_msg,"File %s, line %d: " #x "==" #y, __FILE__, __LINE__); \
       (void)len;                                                         \
       U_ASSERT(len < (int32_t) sizeof(_msg));                            \
       assertEquals((const char*) _msg, x,y);                             \
@@ -2759,10 +2769,10 @@ void NumberFormatRegressionTest::Test8199(void) {
     Formattable val;
     nf->parse(numStr, val, status);
     TEST_CHECK_STATUS(status);
-    TEST_ASSERT(Formattable::kDouble == val.getType());
-    TEST_ASSERT(1000000000 == val.getInt64(status));
+    TEST_ASSERT_EQUALS(Formattable::kDouble, val.getType());
+    TEST_ASSERT_EQUALS(1000000000L, val.getInt64(status));
     TEST_CHECK_STATUS(status);
-    TEST_ASSERT(1000000000.6 == val.getDouble(status));
+    TEST_ASSERT_EQUALS(1000000000.6, val.getDouble(status));
     TEST_CHECK_STATUS(status);
 
     numStr = "100000000000000001.1";   // approx 1E17, parses as a double rather
@@ -2770,25 +2780,25 @@ void NumberFormatRegressionTest::Test8199(void) {
                                        //   even though int64 is more precise.
     nf->parse(numStr, val, status);
     TEST_CHECK_STATUS(status);
-    TEST_ASSERT(Formattable::kDouble == val.getType());
-    TEST_ASSERT(100000000000000001LL == val.getInt64(status));
+    TEST_ASSERT_EQUALS(Formattable::kDouble, val.getType());
+    TEST_ASSERT_EQUALS(100000000000000001LL, val.getInt64(status));
     TEST_CHECK_STATUS(status);
-    TEST_ASSERT(100000000000000000.0 == val.getDouble(status));
+    TEST_ASSERT_EQUALS(100000000000000000.0, val.getDouble(status));
     TEST_CHECK_STATUS(status);
 
     numStr = "1E17";  // Parses with the internal decimal number having non-zero exponent
     nf->parse(numStr, val, status);
     TEST_CHECK_STATUS(status);
-    TEST_ASSERT(Formattable::kInt64 == val.getType());
-    TEST_ASSERT(100000000000000000LL == val.getInt64());
-    TEST_ASSERT(1.0E17 == val.getDouble(status));
+    TEST_ASSERT_EQUALS(Formattable::kInt64, val.getType());
+    TEST_ASSERT_EQUALS(100000000000000000LL, val.getInt64());
+    TEST_ASSERT_EQUALS(1.0E17, val.getDouble(status));
     TEST_CHECK_STATUS(status);
 
     numStr = "9223372036854775807";  // largest int64_t
     nf->parse(numStr, val, status);
     TEST_CHECK_STATUS(status);
-    TEST_ASSERT(Formattable::kInt64 == val.getType());
-    TEST_ASSERT(9223372036854775807LL == val.getInt64());
+    TEST_ASSERT_EQUALS(Formattable::kInt64, val.getType());
+    TEST_ASSERT_EQUALS(9223372036854775807LL, val.getInt64());
     // In the following check, note that a substantial range of integers will
     //    convert to the same double value.  There are also platform variations
     //    in the rounding at compile time of double constants.
@@ -2799,31 +2809,31 @@ void NumberFormatRegressionTest::Test8199(void) {
     numStr = "-9223372036854775808";  // smallest int64_t
     nf->parse(numStr, val, status);
     TEST_CHECK_STATUS(status);
-    TEST_ASSERT(Formattable::kInt64 == val.getType());
-    // TEST_ASSERT(-9223372036854775808LL == val.getInt64()); // Compiler chokes on constant.
-    TEST_ASSERT((int64_t)0x8000000000000000LL == val.getInt64());
-    TEST_ASSERT(-9223372036854775808.0 == val.getDouble(status));
+    TEST_ASSERT_EQUALS(Formattable::kInt64, val.getType());
+    // TEST_ASSERT_EQUALS(-9223372036854775808LL, val.getInt64()); // Compiler chokes on constant.
+    TEST_ASSERT_EQUALS((int64_t)0x8000000000000000LL, val.getInt64());
+    TEST_ASSERT_EQUALS(-9223372036854775808.0, val.getDouble(status));
     TEST_CHECK_STATUS(status);
 
     numStr = "9223372036854775808";  // largest int64_t + 1
     nf->parse(numStr, val, status);
     TEST_CHECK_STATUS(status);
-    TEST_ASSERT(Formattable::kDouble == val.getType());
-    TEST_ASSERT(9223372036854775807LL == val.getInt64(status));
-    TEST_ASSERT(status == U_INVALID_FORMAT_ERROR);
+    TEST_ASSERT_EQUALS(Formattable::kDouble, val.getType());
+    TEST_ASSERT_EQUALS(9223372036854775807LL, val.getInt64(status));
+    TEST_ASSERT_EQUALS(status, U_INVALID_FORMAT_ERROR);
     status = U_ZERO_ERROR;
-    TEST_ASSERT(9223372036854775810.0 == val.getDouble(status));
+    TEST_ASSERT_EQUALS(9223372036854775810.0, val.getDouble(status));
     TEST_CHECK_STATUS(status);
 
     numStr = "-9223372036854775809";  // smallest int64_t - 1
     nf->parse(numStr, val, status);
     TEST_CHECK_STATUS(status);
-    TEST_ASSERT(Formattable::kDouble == val.getType());
-    // TEST_ASSERT(-9223372036854775808LL == val.getInt64(status));  // spurious compiler warnings
-    TEST_ASSERT((int64_t)0x8000000000000000LL == val.getInt64(status));
-    TEST_ASSERT(status == U_INVALID_FORMAT_ERROR);
+    TEST_ASSERT_EQUALS(Formattable::kDouble, val.getType());
+    // TEST_ASSERT_EQUALS(-9223372036854775808LL, val.getInt64(status));  // spurious compiler warnings
+    TEST_ASSERT_EQUALS((int64_t)0x8000000000000000LL, val.getInt64(status));
+    TEST_ASSERT_EQUALS(status, U_INVALID_FORMAT_ERROR);
     status = U_ZERO_ERROR;
-    TEST_ASSERT(-9223372036854775810.0 == val.getDouble(status));
+    TEST_ASSERT_EQUALS(-9223372036854775810.0, val.getDouble(status));
     TEST_CHECK_STATUS(status);
 
     // Test values near the limit of where doubles can represent all integers.
@@ -2837,25 +2847,25 @@ void NumberFormatRegressionTest::Test8199(void) {
     nf->parse(numStr, val, status);
     TEST_CHECK_STATUS(status);
     // printf("getInt64() returns %lld\n", val.getInt64(status));
-    TEST_ASSERT(Formattable::kDouble == val.getType());
-    TEST_ASSERT(9007199254740991LL == val.getInt64(status));
-    TEST_ASSERT(9007199254740991.0 == val.getDouble(status));
+    TEST_ASSERT_EQUALS(Formattable::kDouble, val.getType());
+    TEST_ASSERT_EQUALS(9007199254740991LL, val.getInt64(status));
+    TEST_ASSERT_EQUALS(9007199254740991.0, val.getDouble(status));
     TEST_CHECK_STATUS(status);
 
     status = U_ZERO_ERROR;
     numStr = "9007199254740992.1";  // 54 bits for the int part.
     nf->parse(numStr, val, status);
     TEST_CHECK_STATUS(status);
-    TEST_ASSERT(Formattable::kDouble == val.getType());
-    TEST_ASSERT(9007199254740992LL == val.getInt64(status));
-    TEST_ASSERT(9007199254740992.0 == val.getDouble(status));
+    TEST_ASSERT_EQUALS(Formattable::kDouble, val.getType());
+    TEST_ASSERT_EQUALS(9007199254740992LL, val.getInt64(status));
+    TEST_ASSERT_EQUALS(9007199254740992.0, val.getDouble(status));
     TEST_CHECK_STATUS(status);
 
     status = U_ZERO_ERROR;
     numStr = "9007199254740993.1";  // 54 bits for the int part.  Double will round
     nf->parse(numStr, val, status); //    the ones digit, putting it up to ...994
     TEST_CHECK_STATUS(status);
-    TEST_ASSERT(Formattable::kDouble == val.getType());
+    TEST_ASSERT_EQUALS(Formattable::kDouble, val.getType());
     TEST_ASSERT_EQUALS((int64_t)9007199254740993LL,val.getInt64(status));
     TEST_ASSERT_EQUALS((double)9007199254740994.0,(double)val.getDouble(status));
     TEST_CHECK_STATUS(status);
index d4e6ab695212b847d9d492ef0d888411d4f3ea2b..a3e5adfbdb9fc36d16436dff5de1c6b8844d9eaa 100644 (file)
@@ -990,8 +990,8 @@ void TestMessageFormat::testSetLocale()
     // {sfb} to get $, would need Locale::US, not Locale::ENGLISH
     // Just use unlocalized currency symbol.
     //UnicodeString compareStrEng = "At <time> on Aug 8, 1997, you made a deposit of $456.83.";
-    UnicodeString compareStrEng = "At <time> on Aug 8, 1997, you made a deposit of ";
-    compareStrEng += (UChar) 0x00a4;
+    UnicodeString compareStrEng = "At <time> on Aug 8, 1997, you made a deposit of XXX";
+    compareStrEng += (UChar) 0x00a0;
     compareStrEng += "456.83.";
     // {sfb} to get DM, would need Locale::GERMANY, not Locale::GERMAN
     // Just use unlocalized currency symbol.
@@ -999,8 +999,7 @@ void TestMessageFormat::testSetLocale()
     UnicodeString compareStrGer = "At <time> on 08.08.1997, you made a deposit of ";
     compareStrGer += "456,83";
     compareStrGer += (UChar) 0x00a0;
-    compareStrGer += (UChar) 0x00a4;
-    compareStrGer += ".";
+    compareStrGer += "XXX.";
 
     MessageFormat msg( formatStr, err);
     result = "";
index 1ed6d760e677fcc592920a65f97987876bb4f498..d033754f1d7a046b95c884614d4a67b8ef440475 100644 (file)
@@ -207,7 +207,7 @@ void IntlTestDecimalFormatSymbols::testSymbols(/* char *par */)
     sym.setSymbol(DecimalFormatSymbols::kPercentSymbol, (UnicodeString)"P");
     Verify(34.5, (UnicodeString)"00 %", sym, (UnicodeString)"3450 P");
     sym.setSymbol(DecimalFormatSymbols::kCurrencySymbol, (UnicodeString)"D");
-    Verify(34.5, CharsToUnicodeString("\\u00a4##.##"), sym, (UnicodeString)"D34.5");
+    Verify(34.5, CharsToUnicodeString("\\u00a4##.##"), sym, (UnicodeString)"D 34.50");
     sym.setSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol, (UnicodeString)"|");
     Verify(3456.5, (UnicodeString)"0,000.##", sym, (UnicodeString)"3|456S5");
 
index e859e576f75cfdc8956c986fc1e20cbb9883f5ca..82bd2e0860c184c564cdca82c760fda4551d7223 100644 (file)
@@ -159,7 +159,7 @@ public class DecimalFormatProperties implements Cloneable, Serializable {
         exponentSignAlwaysShown = false;
         formatWidth = -1;
         groupingSize = -1;
-        groupingUsed = false;
+        groupingUsed = true;
         magnitudeMultiplier = 0;
         mathContext = null;
         maximumFractionDigits = -1;
index 19dd535fa29e982c51075d14a46b4a5f3344be41..1bc1021acdf25a1748340637f1886778aa355fde 100644 (file)
@@ -19,8 +19,8 @@ import com.ibm.icu.impl.number.PatternStringParser;
 import com.ibm.icu.impl.number.PatternStringParser.ParsedPatternInfo;
 import com.ibm.icu.impl.number.PropertiesAffixPatternProvider;
 import com.ibm.icu.impl.number.RoundingUtils;
-import com.ibm.icu.number.Scale;
 import com.ibm.icu.number.NumberFormatter.GroupingStrategy;
+import com.ibm.icu.number.Scale;
 import com.ibm.icu.text.DecimalFormatSymbols;
 import com.ibm.icu.util.Currency;
 import com.ibm.icu.util.CurrencyAmount;
@@ -155,6 +155,9 @@ public class NumberParserImpl {
         if (properties.getParseIntegerOnly()) {
             parseFlags |= ParsingUtils.PARSE_FLAG_INTEGER_ONLY;
         }
+        if (properties.getParseToBigDecimal()) {
+            parseFlags |= ParsingUtils.PARSE_FLAG_FORCE_BIG_DECIMAL;
+        }
         if (properties.getSignAlwaysShown()) {
             parseFlags |= ParsingUtils.PARSE_FLAG_PLUS_SIGN_ALLOWED;
         }
@@ -289,6 +292,10 @@ public class NumberParserImpl {
         frozen = true;
     }
 
+    public int getParseFlags() {
+        return parseFlags;
+    }
+
     public void parse(String input, boolean greedy, ParsedNumber result) {
         parse(input, 0, greedy, result);
     }
index 7ad95317b624d4624c23700c3d451990142cb56d..315eac33e261602d3cb686d6fef68839bbd03888 100644 (file)
@@ -131,12 +131,15 @@ public class ParsedNumber {
     }
 
     public Number getNumber() {
-        return getNumber(false);
+        return getNumber(0);
     }
 
-    public Number getNumber(boolean forceBigDecimal) {
+    /** @param parseFlags Configuration settings from ParsingUtils.java */
+    public Number getNumber(int parseFlags) {
         boolean sawNaN = 0 != (flags & FLAG_NAN);
         boolean sawInfinity = 0 != (flags & FLAG_INFINITY);
+        boolean forceBigDecimal = 0 != (parseFlags & ParsingUtils.PARSE_FLAG_FORCE_BIG_DECIMAL);
+        boolean integerOnly = 0 != (parseFlags & ParsingUtils.PARSE_FLAG_INTEGER_ONLY);
 
         // Check for NaN, infinity, and -0.0
         if (sawNaN) {
@@ -150,7 +153,7 @@ public class ParsedNumber {
             }
         }
         assert quantity != null;
-        if (quantity.isZero() && quantity.isNegative()) {
+        if (quantity.isZero() && quantity.isNegative() && !integerOnly) {
             return -0.0;
         }
 
index ec63ce68f4c5f40470611ca604cc971799e66cce..e174724b01eaa252718ee16488c9e133e77ca2e5 100644 (file)
@@ -22,6 +22,7 @@ public class ParsingUtils {
     public static final int PARSE_FLAG_EXACT_AFFIX = 0x0200;
     public static final int PARSE_FLAG_PLUS_SIGN_ALLOWED = 0x0400;
     // public static final int PARSE_FLAG_OPTIMIZE = 0x0800; // no longer used
+    public static final int PARSE_FLAG_FORCE_BIG_DECIMAL = 0x1000;
 
     public static void putLeadCodePoints(UnicodeSet input, UnicodeSet output) {
         for (EntryRange range : input.ranges()) {
index 9e0f1fa71e127de5e41f50f3bf9179e35ffe13bf..6b5c1123552b2cd20f593daa8c14557724614c75 100644 (file)
@@ -3,6 +3,7 @@
 package com.ibm.icu.impl.number.parse;
 
 import com.ibm.icu.impl.StringSegment;
+import com.ibm.icu.impl.number.DecimalQuantity_DualStorageBCD;
 import com.ibm.icu.impl.number.Grouper;
 import com.ibm.icu.text.DecimalFormatSymbols;
 import com.ibm.icu.text.UnicodeSet;
@@ -46,9 +47,7 @@ public class ScientificMatcher implements NumberParseMatcher {
     @Override
     public boolean match(StringSegment segment, ParsedNumber result) {
         // Only accept scientific notation after the mantissa.
-        // Most places use result.hasNumber(), but we need a stronger condition here (i.e., exponent is
-        // not well-defined after NaN or infinity).
-        if (result.quantity == null) {
+        if (!result.seenNumber()) {
             return false;
         }
 
@@ -89,8 +88,17 @@ public class ScientificMatcher implements NumberParseMatcher {
                 segment.adjustOffset(overlap2);
             }
 
+            // We are supposed to accept E0 after NaN, so we need to make sure result.quantity is available.
+            boolean wasNull = (result.quantity == null);
+            if (wasNull) {
+                result.quantity = new DecimalQuantity_DualStorageBCD();
+            }
             int digitsOffset = segment.getOffset();
             boolean digitsReturnValue = exponentMatcher.match(segment, result, exponentSign);
+            if (wasNull) {
+                result.quantity = null;
+            }
+
             if (segment.getOffset() != digitsOffset) {
                 // At least one exponent digit was matched.
                 result.flags |= ParsedNumber.FLAG_HAS_EXPONENT;
index ccc67a44109e92f97f4b20e8d44dd10905de44ae..99af4cd5224fedff6f342b248a3cf1915ac7c3c3 100644 (file)
@@ -139,8 +139,7 @@ final class NumberPropertyMapper {
         boolean explicitMinMaxFrac = minFrac != -1 || maxFrac != -1;
         boolean explicitMinMaxSig = minSig != -1 || maxSig != -1;
         // Resolve min/max frac for currencies, required for the validation logic and for when minFrac or
-        // maxFrac was
-        // set (but not both) on a currency instance.
+        // maxFrac was set (but not both) on a currency instance.
         // NOTE: Increments are handled in "Rounder.constructCurrency()".
         if (useCurrency) {
             if (minFrac == -1 && maxFrac == -1) {
index e7ddd4657900684d4dbc3f365cb3d39d983cf5e8..71d9675e30959ac6f179735084b266676f555527 100644 (file)
@@ -822,7 +822,7 @@ public class DecimalFormat extends NumberFormat {
       if (result.success()) {
           parsePosition.setIndex(result.charEnd);
           // TODO: Accessing properties here is technically not thread-safe
-          Number number = result.getNumber(properties.getParseToBigDecimal());
+          Number number = result.getNumber(parser.getParseFlags());
           // Backwards compatibility: return com.ibm.icu.math.BigDecimal
           if (number instanceof java.math.BigDecimal) {
               number = safeConvertBigDecimal((java.math.BigDecimal) number);
@@ -861,7 +861,7 @@ public class DecimalFormat extends NumberFormat {
       if (result.success()) {
           parsePosition.setIndex(result.charEnd);
           // TODO: Accessing properties here is technically not thread-safe
-          Number number = result.getNumber(properties.getParseToBigDecimal());
+          Number number = result.getNumber(parserWithCurrency.getParseFlags());
           // Backwards compatibility: return com.ibm.icu.math.BigDecimal
           if (number instanceof java.math.BigDecimal) {
               number = safeConvertBigDecimal((java.math.BigDecimal) number);
index 3a38ffde9c52ac26243a83045e7f305cdfa8346d..3bf1db732d397be5eb1a1dbb0c58f55dac55b36b 100644 (file)
@@ -460,9 +460,8 @@ public class NumberFormatDataDrivenTest {
     if (tuple.maxSigDigits != null) {
       properties.setMaximumSignificantDigits(tuple.maxSigDigits);
     }
-    if (tuple.useGrouping != null && tuple.useGrouping == 0) {
-      properties.setGroupingSize(-1);
-      properties.setSecondaryGroupingSize(-1);
+    if (tuple.useGrouping != null) {
+      properties.setGroupingUsed(tuple.useGrouping > 0);
     }
     if (tuple.multiplier != null) {
       properties.setMultiplier(new BigDecimal(tuple.multiplier));
index af4eb3e54c8036a3d70c6541f5a0a2a0bd68c856..0afff8be2f0b9e101807a4dfa9e1d38c07b790cd 100644 (file)
@@ -1384,17 +1384,18 @@ public class NumberRegressionTests extends TestFmwk {
      */
     @Test
     public void Test4170798() {
-        Locale savedLocale = Locale.getDefault();
-        Locale.setDefault(Locale.US);
-        DecimalFormat df = new DecimalFormat();
+        DecimalFormat df = (DecimalFormat) NumberFormat.getInstance(ULocale.US);
+        {
+            ParsePosition ppos = new ParsePosition(0);
+            Number result = df.parse("-0.0", ppos);
+            assertEquals("Should parse to double -0.0", new Double(-0.0), result);
+        }
         df.setParseIntegerOnly(true);
-        Number n = df.parse("-0.0", new ParsePosition(0));
-        if (!(n instanceof Double)
-            || n.intValue() != 0) {
-            errln("FAIL: parse(\"-0.0\") returns " +
-                  n + " (" + n.getClass().getName() + ')');
+        {
+            ParsePosition ppos = new ParsePosition(0);
+            Number result = df.parse("-0.0", ppos);
+            assertEquals("Should parse to an integer type, not a double", new Long(0), result);
         }
-        Locale.setDefault(savedLocale);
     }
 
     /**
index cf6ed3dc5b887810a5180d0be6b22861c706d2c7..1f310a76e47c77e962ed194d1bd78e7f8643269a 100644 (file)
@@ -105,7 +105,7 @@ public class NumberParserTest {
                 { 3, ".00", "0", 3, 0.0 },
                 { 3, "                              1,234", "a0", 35, 1234. }, // should not hang
                 { 3, "NaN", "0", 3, Double.NaN },
-                { 3, "NaN E5", "0", 3, Double.NaN },
+                { 3, "NaN E5", "0", 6, Double.NaN },
                 { 3, "0", "0", 1, 0.0 } };
 
         int parseFlags = ParsingUtils.PARSE_FLAG_IGNORE_CASE