]> granicus.if.org Git - icu/commitdiff
ICU-13634 Adding "formatFailIfMoreThanMaxDigits" property to C++ NumberFormatter...
authorShane Carr <shane@unicode.org>
Wed, 18 Apr 2018 03:59:39 +0000 (03:59 +0000)
committerShane Carr <shane@unicode.org>
Wed, 18 Apr 2018 03:59:39 +0000 (03:59 +0000)
X-SVN-Rev: 41239

13 files changed:
icu4c/source/i18n/decimfmt.cpp
icu4c/source/i18n/number_decimfmtprops.cpp
icu4c/source/i18n/number_decimfmtprops.h
icu4c/source/i18n/number_integerwidth.cpp
icu4c/source/i18n/number_mapper.cpp
icu4c/source/i18n/number_patternstring.cpp
icu4c/source/i18n/unicode/decimfmt.h
icu4c/source/i18n/unicode/numberformatter.h
icu4c/source/test/cintltst/cnumtst.c
icu4c/source/test/intltest/numfmtst.cpp
icu4c/source/test/testdata/numberformattestspecification.txt
icu4j/main/classes/core/src/com/ibm/icu/text/DecimalFormat.java
icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/NumberFormatTest.java

index 1708b0d2e8174124dcceba99d8383e3b7b865b8e..43399d1a139db0ee43352af445e591a625946d66 100644 (file)
@@ -221,11 +221,14 @@ DecimalFormat::setAttribute(UNumberFormatAttribute attr, int32_t newValue, UErro
             setSignAlwaysShown(static_cast<UBool>(newValue));
             break;
 
+        case UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS:
+            setFormatFailIfMoreThanMaxDigits(static_cast<UBool>(newValue));
+            break;
+
         default:
             status = U_UNSUPPORTED_ERROR;
             break;
     }
-    // TODO: UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS?
     return *this;
 }
 
@@ -312,6 +315,9 @@ int32_t DecimalFormat::getAttribute(UNumberFormatAttribute attr, UErrorCode& sta
         case UNUM_SIGN_ALWAYS_SHOWN:
             return isSignAlwaysShown();
 
+        case UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS:
+            return isFormatFailIfMoreThanMaxDigits();
+
         default:
             status = U_UNSUPPORTED_ERROR;
             break;
@@ -775,9 +781,8 @@ void DecimalFormat::setGroupingSize(int32_t newValue) {
 }
 
 int32_t DecimalFormat::getSecondaryGroupingSize(void) const {
-    int grouping1 = fProperties->groupingSize;
     int grouping2 = fProperties->secondaryGroupingSize;
-    if (grouping1 == grouping2 || grouping2 < 0) {
+    if (grouping2 < 0) {
         return 0;
     }
     return grouping2;
@@ -833,6 +838,15 @@ void DecimalFormat::setParseCaseSensitive(UBool value) {
     refreshFormatterNoError();
 }
 
+UBool DecimalFormat::isFormatFailIfMoreThanMaxDigits() const {
+    return fProperties->formatFailIfMoreThanMaxDigits;
+}
+
+void DecimalFormat::setFormatFailIfMoreThanMaxDigits(UBool value) {
+    fProperties->formatFailIfMoreThanMaxDigits = value;
+    refreshFormatterNoError();
+}
+
 UnicodeString& DecimalFormat::toPattern(UnicodeString& result) const {
     // Pull some properties from exportedProperties and others from properties
     // to keep affix patterns intact.  In particular, pull rounding properties
index 10a9eb00293af662878c732cdc371759a88f77b0..a292197e42abae012a840515b847eadc7e1ad9ae 100644 (file)
@@ -23,6 +23,7 @@ void DecimalFormatProperties::clear() {
     decimalPatternMatchRequired = false;
     decimalSeparatorAlwaysShown = false;
     exponentSignAlwaysShown = false;
+    formatFailIfMoreThanMaxDigits = false;
     formatWidth = -1;
     groupingSize = -1;
     groupingUsed = true;
@@ -68,6 +69,7 @@ bool DecimalFormatProperties::operator==(const DecimalFormatProperties &other) c
     eq = eq && decimalPatternMatchRequired == other.decimalPatternMatchRequired;
     eq = eq && decimalSeparatorAlwaysShown == other.decimalSeparatorAlwaysShown;
     eq = eq && exponentSignAlwaysShown == other.exponentSignAlwaysShown;
+    eq = eq && formatFailIfMoreThanMaxDigits == other.formatFailIfMoreThanMaxDigits;
     eq = eq && formatWidth == other.formatWidth;
     eq = eq && groupingSize == other.groupingSize;
     eq = eq && groupingUsed == other.groupingUsed;
index 8e823a80067a5031e4d755bfc1568c3a8ecb0ad2..067c148ac7561cfd9f751c563e62bc8a90b31ca3 100644 (file)
@@ -96,6 +96,7 @@ struct U_I18N_API DecimalFormatProperties {
     bool decimalPatternMatchRequired;
     bool decimalSeparatorAlwaysShown;
     bool exponentSignAlwaysShown;
+    bool formatFailIfMoreThanMaxDigits; // ICU4C-only
     int32_t formatWidth;
     int32_t groupingSize;
     bool groupingUsed;
index 87e543622cc9c2548a5d58ae9bbb158058c02588..fa9991be0fa5c0c6cbf05f0e1bdc15b0f070623b 100644 (file)
@@ -14,14 +14,15 @@ using namespace icu;
 using namespace icu::number;
 using namespace icu::number::impl;
 
-IntegerWidth::IntegerWidth(digits_t minInt, digits_t maxInt) {
+IntegerWidth::IntegerWidth(digits_t minInt, digits_t maxInt, bool formatFailIfMoreThanMaxDigits) {
     fUnion.minMaxInt.fMinInt = minInt;
     fUnion.minMaxInt.fMaxInt = maxInt;
+    fUnion.minMaxInt.fFormatFailIfMoreThanMaxDigits = formatFailIfMoreThanMaxDigits;
 }
 
 IntegerWidth IntegerWidth::zeroFillTo(int32_t minInt) {
     if (minInt >= 0 && minInt <= kMaxIntFracSig) {
-        return {static_cast<digits_t>(minInt), -1};
+        return {static_cast<digits_t>(minInt), -1, false};
     } else {
         return {U_NUMBER_ARG_OUTOFBOUNDS_ERROR};
     }
@@ -31,9 +32,9 @@ IntegerWidth IntegerWidth::truncateAt(int32_t maxInt) {
     if (fHasError) { return *this; }  // No-op on error
     digits_t minInt = fUnion.minMaxInt.fMinInt;
     if (maxInt >= 0 && maxInt <= kMaxIntFracSig && minInt <= maxInt) {
-        return {minInt, static_cast<digits_t>(maxInt)};
+        return {minInt, static_cast<digits_t>(maxInt), false};
     } else if (maxInt == -1) {
-        return {minInt, -1};
+        return {minInt, -1, false};
     } else {
         return {U_NUMBER_ARG_OUTOFBOUNDS_ERROR};
     }
@@ -45,6 +46,11 @@ void IntegerWidth::apply(impl::DecimalQuantity& quantity, UErrorCode& status) co
     } else if (fUnion.minMaxInt.fMaxInt == -1) {
         quantity.setIntegerLength(fUnion.minMaxInt.fMinInt, INT32_MAX);
     } else {
+        // Enforce the backwards-compatibility feature "FormatFailIfMoreThanMaxDigits"
+        if (fUnion.minMaxInt.fFormatFailIfMoreThanMaxDigits &&
+            fUnion.minMaxInt.fMaxInt < quantity.getMagnitude()) {
+            status = U_ILLEGAL_ARGUMENT_ERROR;
+        }
         quantity.setIntegerLength(fUnion.minMaxInt.fMinInt, fUnion.minMaxInt.fMaxInt);
     }
 }
index 22fe87fc67cd6ca37d332e25d4a350eead290243..b2cad1224d7deb885f3c52c037b56a79a1bb2503 100644 (file)
@@ -159,7 +159,10 @@ MacroProps NumberPropertyMapper::oldToNew(const DecimalFormatProperties& propert
     // INTEGER WIDTH //
     ///////////////////
 
-    macros.integerWidth = IntegerWidth::zeroFillTo(minInt).truncateAt(maxInt);
+    macros.integerWidth = IntegerWidth(
+            static_cast<digits_t>(minInt),
+            static_cast<digits_t>(maxInt),
+            properties.formatFailIfMoreThanMaxDigits);
 
     ///////////////////////
     // GROUPING STRATEGY //
index e96f958da0faaed0a19dcbf777ab1b068ef5d76b..f967fb4bba6e23eb30f60f41f1c925b5bcd02700 100644 (file)
@@ -819,7 +819,10 @@ UnicodeString PatternStringUtils::propertiesToPatternString(const DecimalFormatP
         sb.append(AffixUtils::escape(UnicodeStringCharSequence(np)));
         // Copy the positive digit format into the negative.
         // This is optional; the pattern is the same as if '#' were appended here instead.
-        sb.append(sb, afterPrefixPos, beforeSuffixPos - afterPrefixPos);
+        // NOTE: It is not safe to append the UnicodeString to itself, so we need to copy.
+        // See http://bugs.icu-project.org/trac/ticket/13707
+        UnicodeString copy(sb);
+        sb.append(copy, afterPrefixPos, beforeSuffixPos - afterPrefixPos);
         if (!nsp.isBogus()) {
             sb.append(nsp);
         }
index 1ce1ea93981e6a840d787fef41c18e225aa54bd2..d59e50d06d063ee2fcb2eafd36f86ee3845c0571 100644 (file)
@@ -1724,7 +1724,7 @@ class U_I18N_API DecimalFormat : public NumberFormat {
      * @param value true to prevent exponents from being parsed; false to allow them to be parsed.
      * @internal This API is a technical preview. It may change in an upcoming release.
      */
-    void setParseNoExponent(UBool value);
+    virtual void setParseNoExponent(UBool value);
 
     /**
      * {@icu} Returns whether parsing is sensitive to case (lowercase/uppercase).
@@ -1738,11 +1738,30 @@ class U_I18N_API DecimalFormat : public NumberFormat {
      * {@icu} Whether to pay attention to case when parsing; default is to ignore case (perform
      * case-folding). For example, "A" == "a" in case-insensitive but not case-sensitive mode.
      *
-     * Currency codes are never case-folded. For example, "us$1.00" will not parse in case-insensitive
+     * Currency symbols are never case-folded. For example, "us$1.00" will not parse in case-insensitive
      * mode, even though "US$1.00" parses.
+     *
+     * @internal This API is a technical preview. It may change in an upcoming release.
      */
     void setParseCaseSensitive(UBool value);
 
+    /**
+     * {@icu} Returns whether truncation of high-order integer digits should result in an error.
+     * By default, setMaximumIntegerDigits truncates high-order digits silently.
+     *
+     * @see setFormatFailIfMoreThanMaxDigits
+     * @internal This API is a technical preview. It may change in an upcoming release.
+     */
+    UBool isFormatFailIfMoreThanMaxDigits() const;
+
+    /**
+     * {@icu} Sets whether truncation of high-order integer digits should result in an error.
+     * By default, setMaximumIntegerDigits truncates high-order digits silently.
+     *
+     * @internal This API is a technical preview. It may change in an upcoming release.
+     */
+    virtual void setFormatFailIfMoreThanMaxDigits(UBool value);
+
 
     /**
      * Synthesizes a pattern string that represents the current state
index 897e4c45eb9b28a3c8aade9c747b8118af70ad43..5f4a6bb7ac55a8a2bd17ffc4c4dd71444cc7212c 100644 (file)
@@ -918,12 +918,13 @@ class U_I18N_API IntegerWidth : public UMemory {
         struct {
             impl::digits_t fMinInt;
             impl::digits_t fMaxInt;
+            bool fFormatFailIfMoreThanMaxDigits;
         } minMaxInt;
         UErrorCode errorCode;
     } fUnion;
     bool fHasError = false;
 
-    IntegerWidth(impl::digits_t minInt, impl::digits_t maxInt);
+    IntegerWidth(impl::digits_t minInt, impl::digits_t maxInt, bool formatFailIfMoreThanMaxDigits);
 
     IntegerWidth(UErrorCode errorCode) { // NOLINT
         fUnion.errorCode = errorCode;
@@ -962,6 +963,9 @@ class U_I18N_API IntegerWidth : public UMemory {
     // To allow NumberFormatterImpl to access isBogus() and perform other operations:
     friend class impl::NumberFormatterImpl;
 
+    // So that NumberPropertyMapper can create instances
+    friend class impl::NumberPropertyMapper;
+
     // To allow access to the skeleton generation code:
     friend class impl::GeneratorHelpers;
 };
index d11cca78b3eef1f0059ea6dedc96e0f05dfb6cf3..f6ad0340a0b6b93656ccff66221c192b7366e3ad 100644 (file)
@@ -765,7 +765,8 @@ free(result);
     newvalue=2;
     unum_setAttribute(def, attr, newvalue);
     if(unum_getAttribute(def,attr) != 2)
-        log_err("error in setting and getting attributes for UNUM_SECONDARY_GROUPING_SIZE\n");
+        log_err("error in setting and getting attributes for UNUM_SECONDARY_GROUPING_SIZE: got %d\n",
+                unum_getAttribute(def,attr));
     else
         log_verbose("Pass:setting and getting attributes for UNUM_SECONDARY_GROUPING_SIZE works fine\n");
 
@@ -840,7 +841,8 @@ free(result);
         const char *bdpattern = "#,##0.#########";
         const char *numInitial     = "12345678900987654321.1234567896";
         const char *numFormatted  = "12,345,678,900,987,654,321.12345679";
-        const char *parseExpected = "12345678900987654321.12345679";
+        const char *parseExpected = "1.234567890098765432112345679E+19";
+        const char *parseExpected2 = "3.4567890098765432112345679E+17";
         int32_t resultSize    = 0;
         int32_t parsePos      = 0;     /* Output parameter for Parse operations. */
         #define DESTCAPACITY 100
@@ -898,9 +900,12 @@ free(result);
         if (U_FAILURE(status)) {
             log_err("File %s, Line %d, status = %s\n", __FILE__, __LINE__, u_errorName(status));
         }
-        if (strcmp(parseExpected, desta) != 0) {
+        if (uprv_strcmp(parseExpected, desta) != 0) {
             log_err("File %s, Line %d, (expected, actual) = (\"%s\", \"%s\")\n",
                     __FILE__, __LINE__, parseExpected, desta);
+        } else {
+            log_verbose("File %s, Line %d, got expected = \"%s\"\n",
+                    __FILE__, __LINE__, desta);
         }
         if (strlen(parseExpected) != resultSize) {
             log_err("File %s, Line %d, (expected, actual) = (%d, %d)\n",
@@ -917,9 +922,12 @@ free(result);
         if (U_FAILURE(status)) {
             log_err("File %s, Line %d, status = %s\n", __FILE__, __LINE__, u_errorName(status));
         }
-        if (strcmp(parseExpected+2, desta) != 0) {   /*  "345678900987654321.12345679" */
+        if (strcmp(parseExpected2, desta) != 0) {   /*  "3.4567890098765432112345679E+17" */
             log_err("File %s, Line %d, (expected, actual) = (\"%s\", \"%s\")\n",
-                    __FILE__, __LINE__, parseExpected+2, desta);
+                    __FILE__, __LINE__, parseExpected2, desta);
+        } else {
+            log_verbose("File %s, Line %d, got expected = \"%s\"\n",
+                    __FILE__, __LINE__, desta);
         }
         if (strlen(numFormatted) != parsePos) {
             log_err("File %s, Line %d, parsePos (expected, actual) = (\"%d\", \"%d\")\n",
@@ -1016,9 +1024,12 @@ typedef struct {
     const char *  descrip;
     const UChar * currStr;
     const UChar * plurStr;
+    // ICU 62: currencies are accepted in non-currency mode
+    /*
     UErrorCode    parsDoubExpectErr;
     int32_t       parsDoubExpectPos;
     double        parsDoubExpectVal;
+    */
     UErrorCode    parsCurrExpectErr;
     int32_t       parsCurrExpectPos;
     double        parsCurrExpectVal;
@@ -1026,29 +1037,29 @@ typedef struct {
 } ParseCurrencyItem;
 
 static const ParseCurrencyItem parseCurrencyItems[] = {
-    { "en_US", "dollars2", dollars2Sym, NULL,          U_ZERO_ERROR,  5, 2.0, U_ZERO_ERROR,  5, 2.0, "USD" },
-    { "en_US", "dollars4", dollars4Sym, dollars4PluEn, U_ZERO_ERROR,  2, 4.0, U_ZERO_ERROR,  2, 4.0, "USD" },
-    { "en_US", "dollars9", dollars9Sym, NULL,          U_PARSE_ERROR, 1, 0.0, U_PARSE_ERROR, 1, 0.0, ""    },
-    { "en_US", "pounds3",  pounds3Sym,  NULL,          U_PARSE_ERROR, 0, 0.0, U_ZERO_ERROR,  5, 3.0, "GBP" },
-    { "en_US", "pounds5",  pounds5Sym,  pounds5PluEn,  U_PARSE_ERROR, 0, 0.0, U_ZERO_ERROR,  2, 5.0, "GBP" },
-    { "en_US", "pounds7",  pounds7Sym,  NULL,          U_PARSE_ERROR, 1, 0.0, U_PARSE_ERROR, 1, 0.0, ""    },
-    { "en_US", "euros8",   euros8Sym,   euros8PluEn,   U_PARSE_ERROR, 0, 0.0, U_ZERO_ERROR,  2, 8.0, "EUR" },
-
-    { "en_GB", "pounds3",  pounds3Sym,  NULL,          U_ZERO_ERROR,  5, 3.0, U_ZERO_ERROR,  5, 3.0, "GBP" },
-    { "en_GB", "pounds5",  pounds5Sym,  pounds5PluEn,  U_ZERO_ERROR,  2, 5.0, U_ZERO_ERROR,  2, 5.0, "GBP" },
-    { "en_GB", "pounds7",  pounds7Sym,  NULL,          U_PARSE_ERROR, 1, 0.0, U_PARSE_ERROR, 1, 0.0, ""    },
-    { "en_GB", "euros4",   euros4Sym,   NULL,          U_PARSE_ERROR, 4, 0.0, U_PARSE_ERROR, 4, 0.0, ""    },
-    { "en_GB", "euros6",   euros6Sym,   NULL,          U_PARSE_ERROR, 1, 0.0, U_PARSE_ERROR, 1, 0.0, ""    },
-    { "en_GB", "euros8",   euros8Sym,     euros8PluEn,   U_PARSE_ERROR, 0, 0.0, U_ZERO_ERROR,  2, 8.0, "EUR" },
-    { "en_GB", "dollars4", dollarsUS4Sym, dollars4PluEn, U_PARSE_ERROR, 0, 0.0, U_ZERO_ERROR,  4, 4.0, "USD" },
-
-    { "fr_FR", "euros4",   euros4Sym,   NULL,          U_ZERO_ERROR,  6, 4.0, U_ZERO_ERROR,  6, 4.0, "EUR" },
-    { "fr_FR", "euros6",   euros6Sym,   euros6PluFr,   U_ZERO_ERROR,  3, 6.0, U_ZERO_ERROR,  3, 6.0, "EUR" },
-    { "fr_FR", "euros8",   euros8Sym,   NULL,          U_PARSE_ERROR, 0, 0.0, U_PARSE_ERROR, 0, 0.0, ""    },
-    { "fr_FR", "dollars2", dollars2Sym, NULL,          U_PARSE_ERROR, 0, 0.0, U_PARSE_ERROR, 0, 0.0, ""    },
-    { "fr_FR", "dollars4", dollars4Sym, NULL,          U_PARSE_ERROR, 0, 0.0, U_PARSE_ERROR, 0, 0.0, ""    },
+    { "en_US", "dollars2", dollars2Sym, NULL,           /* U_ZERO_ERROR,  5, 2.0, */ U_ZERO_ERROR,  5, 2.0, "USD" },
+    { "en_US", "dollars4", dollars4Sym, dollars4PluEn,  /* U_ZERO_ERROR,  2, 4.0, */ U_ZERO_ERROR,  2, 4.0, "USD" },
+    { "en_US", "dollars9", dollars9Sym, NULL,           /* U_PARSE_ERROR, 1, 0.0, */ U_PARSE_ERROR, 1, 0.0, ""    },
+    { "en_US", "pounds3",  pounds3Sym,  NULL,           /* U_PARSE_ERROR, 0, 0.0, */ U_ZERO_ERROR,  5, 3.0, "GBP" },
+    { "en_US", "pounds5",  pounds5Sym,  pounds5PluEn,   /* U_PARSE_ERROR, 0, 0.0, */ U_ZERO_ERROR,  2, 5.0, "GBP" },
+    { "en_US", "pounds7",  pounds7Sym,  NULL,           /* U_PARSE_ERROR, 1, 0.0, */ U_PARSE_ERROR, 1, 0.0, ""    },
+    { "en_US", "euros8",   euros8Sym,   euros8PluEn,    /* U_PARSE_ERROR, 0, 0.0, */ U_ZERO_ERROR,  2, 8.0, "EUR" },
+
+    { "en_GB", "pounds3",  pounds3Sym,  NULL,           /* U_ZERO_ERROR,  5, 3.0, */ U_ZERO_ERROR,  5, 3.0, "GBP" },
+    { "en_GB", "pounds5",  pounds5Sym,  pounds5PluEn,   /* U_ZERO_ERROR,  2, 5.0, */ U_ZERO_ERROR,  2, 5.0, "GBP" },
+    { "en_GB", "pounds7",  pounds7Sym,  NULL,           /* U_PARSE_ERROR, 1, 0.0, */ U_PARSE_ERROR, 1, 0.0, ""    },
+    { "en_GB", "euros4",   euros4Sym,   NULL,           /* U_PARSE_ERROR, 4, 0.0, */ U_PARSE_ERROR, 0, 0.0, ""    },
+    { "en_GB", "euros6",   euros6Sym,   NULL,           /* U_PARSE_ERROR, 1, 0.0, */ U_PARSE_ERROR, 1, 0.0, ""    },
+    { "en_GB", "euros8",   euros8Sym,    euros8PluEn,   /* U_PARSE_ERROR, 0, 0.0, */ U_ZERO_ERROR,  2, 8.0, "EUR" },
+    { "en_GB", "dollars4", dollarsUS4Sym,dollars4PluEn, /* U_PARSE_ERROR, 0, 0.0, */ U_ZERO_ERROR,  4, 4.0, "USD" },
+
+    { "fr_FR", "euros4",   euros4Sym,   NULL,           /* U_ZERO_ERROR,  6, 4.0, */ U_ZERO_ERROR,  6, 4.0, "EUR" },
+    { "fr_FR", "euros6",   euros6Sym,   euros6PluFr,    /* U_ZERO_ERROR,  3, 6.0, */ U_ZERO_ERROR,  3, 6.0, "EUR" },
+    { "fr_FR", "euros8",   euros8Sym,   NULL,           /* U_PARSE_ERROR, 0, 0.0, */ U_PARSE_ERROR, 2, 0.0, ""    },
+    { "fr_FR", "dollars2", dollars2Sym, NULL,           /* U_PARSE_ERROR, 0, 0.0, */ U_PARSE_ERROR, 0, 0.0, ""    },
+    { "fr_FR", "dollars4", dollars4Sym, NULL,           /* U_PARSE_ERROR, 0, 0.0, */ U_PARSE_ERROR, 0, 0.0, ""    },
     
-    { NULL,    NULL,       NULL,        NULL,          0,             0, 0.0, 0,             0, 0.0, NULL  }
+    { NULL,    NULL,       NULL,        NULL,           /* 0,             0, 0.0, */ 0,             0, 0.0, NULL  }
 };
 
 static void TestParseCurrency()
@@ -1070,10 +1081,10 @@ static void TestParseCurrency()
             status = U_ZERO_ERROR;
             parsePos = 0;
             parseVal = unum_parseDouble(unum, currStr, -1, &parsePos, &status);
-            if (status != itemPtr->parsDoubExpectErr || parsePos != itemPtr->parsDoubExpectPos || parseVal != itemPtr->parsDoubExpectVal) {
+            if (status != itemPtr->parsCurrExpectErr || parsePos != itemPtr->parsCurrExpectPos || parseVal != itemPtr->parsCurrExpectVal) {
                 log_err("UNUM_CURRENCY parseDouble %s/%s, expect %s pos %d val %.1f, get %s pos %d val %.1f\n",
                         itemPtr->locale, itemPtr->descrip,
-                        u_errorName(itemPtr->parsDoubExpectErr), itemPtr->parsDoubExpectPos, itemPtr->parsDoubExpectVal,
+                        u_errorName(itemPtr->parsCurrExpectErr), itemPtr->parsCurrExpectPos, itemPtr->parsCurrExpectVal,
                         u_errorName(status), parsePos, parseVal );
             }
             status = U_ZERO_ERROR;
@@ -1100,10 +1111,10 @@ static void TestParseCurrency()
                 status = U_ZERO_ERROR;
                 parsePos = 0;
                 parseVal = unum_parseDouble(unum, itemPtr->plurStr, -1, &parsePos, &status);
-                if (status != itemPtr->parsDoubExpectErr || parseVal != itemPtr->parsDoubExpectVal) {
+                if (status != itemPtr->parsCurrExpectErr || parseVal != itemPtr->parsCurrExpectVal) {
                     log_err("UNUM_CURRENCY parseDouble %s/%s, expect %s val %.1f, get %s val %.1f\n",
                             itemPtr->locale, itemPtr->descrip,
-                            u_errorName(itemPtr->parsDoubExpectErr), itemPtr->parsDoubExpectVal,
+                            u_errorName(itemPtr->parsCurrExpectErr), itemPtr->parsCurrExpectVal,
                             u_errorName(status), parseVal );
                 }
                 status = U_ZERO_ERROR;
@@ -1269,6 +1280,7 @@ static void TestNumberFormatPadding()
 {
     UChar *result=NULL;
     UChar temp1[512];
+    UChar temp2[512];
 
     UErrorCode status=U_ZERO_ERROR;
     int32_t resultlength;
@@ -1294,7 +1306,8 @@ static void TestNumberFormatPadding()
     }
 
 /*    u_uastrcpy(temp1, "*x#,###,###,##0.0#;(*x#,###,###,##0.0#)"); */
-    u_uastrcpy(temp1, "*x#,###,###,##0.0#;*x(###,###,##0.0#)");
+    u_uastrcpy(temp1, "*x#,###,###,##0.0#;*x(###,###,##0.0#)"); // input pattern
+    u_uastrcpy(temp2, "*x#########,##0.0#;(#########,##0.0#)"); // equivalent (?) output pattern
     status=U_ZERO_ERROR;
     pattern=unum_open(UNUM_IGNORE,temp1, u_strlen(temp1), "en_US",NULL, &status);
     if(U_FAILURE(status))
@@ -1321,12 +1334,17 @@ static void TestNumberFormatPadding()
         }
         else
         {
-            if(u_strcmp(result, temp1)!=0)
-                log_err("FAIL: Error in extracting the padding pattern using unum_toPattern()\n");
-            else
+            if(u_strncmp(result, temp2, resultlengthneeded)!=0) {
+                log_err(
+                        "FAIL: Error in extracting the padding pattern using unum_toPattern(): %d: %s != %s\n",
+                        resultlengthneeded,
+                        austrdup(temp2),
+                        austrdup(result));
+            } else {
                 log_verbose("Pass: extracted the padding pattern correctly using unum_toPattern()\n");
-free(result);
+            }
         }
+        free(result);
 /*        u_uastrcpy(temp1, "(xxxxxxx10,456.37)"); */
         u_uastrcpy(temp1, "xxxxx(10,456.37)");
         resultlength=0;
index 0e259e0d2920360045305ab9dab71aeaaf062da2..524a29361d26143f6877f84820909f1f2511c2f2 100644 (file)
@@ -3670,7 +3670,7 @@ NumberFormatTest::TestSpaceParsing() {
         {"$\\u00A0124 ",   5, -1, FALSE},
         {" $ 124 ",        0,  0, FALSE},
         {"124$",           0,  4, FALSE},
-        {"124 $",          0,  5, FALSE},
+        {"124 $",          0,  3, FALSE},
         {"$124",           4, -1, TRUE},
         {"$124 $124",      4, -1, TRUE},
         {"$124 ",          4, -1, TRUE},
index 7b375222ca8f800fd24e069da48b2fb320563f8c..cd5b479d1f8fe9d5c2c88bbc144e560a9e4c53f9 100644 (file)
@@ -742,8 +742,8 @@ parse       output  breaks
 // JDK stops parsing at the spaces. JDK doesn't see space as a grouping separator
 (34  25E-1)    -342.5  K
 (34,,25E-1)    -342.5
-// J doesn't allow trailing separators before E but C does
-(34,,25,E-1)   -342.5  J
+// J doesn't allow trailing separators before E
+(34,,25,E-1)   -342.5  CJ
 (34  25 E-1)   -342.5  JK
 (34,,25 E-1)   -342.5  JK
 // Spaces are not allowed after exponent symbol
@@ -806,7 +806,7 @@ parse       output  breaks
 1,234,,,+      1234    JK
 1,234- -1234
 // J bails because of trailing separators
-1,234,-        -1234   J
+1,234,-        -1234   CJ
 // J bails here too
 1234  -        -1234   J
 
index 71d9675e30959ac6f179735084b266676f555527..3ea823c482bbde83a09178f32655fbba974814d4 100644 (file)
@@ -1913,9 +1913,8 @@ public class DecimalFormat extends NumberFormat {
    * @stable ICU 2.0
    */
   public synchronized int getSecondaryGroupingSize() {
-    int grouping1 = properties.getGroupingSize();
     int grouping2 = properties.getSecondaryGroupingSize();
-    if (grouping1 == grouping2 || grouping2 < 0) {
+    if (grouping2 < 0) {
       return 0;
     }
     return grouping2;
index 4b63eab0982a7dffe3224bf234edcd831ee510f5..5c679f30d83709c7735682992fb954771f512e92 100644 (file)
@@ -5258,7 +5258,7 @@ public class NumberFormatTest extends TestFmwk {
         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 still return 0", 0, df.getSecondaryGroupingSize());
+        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());