]> granicus.if.org Git - icu/commitdiff
ICU-13443 Change digit width types to int16_t and change maximum setting to 999....
authorShane Carr <shane@unicode.org>
Thu, 8 Feb 2018 06:06:08 +0000 (06:06 +0000)
committerShane Carr <shane@unicode.org>
Thu, 8 Feb 2018 06:06:08 +0000 (06:06 +0000)
X-SVN-Rev: 40866

14 files changed:
icu4c/source/common/unicode/utypes.h
icu4c/source/common/utypes.cpp
icu4c/source/i18n/number_integerwidth.cpp
icu4c/source/i18n/number_notation.cpp
icu4c/source/i18n/number_padding.cpp
icu4c/source/i18n/number_rounding.cpp
icu4c/source/i18n/number_types.h
icu4c/source/i18n/unicode/numberformatter.h
icu4c/source/test/intltest/intltest.cpp
icu4c/source/test/intltest/intltest.h
icu4c/source/test/intltest/numbertest.h
icu4c/source/test/intltest/numbertest_api.cpp
icu4j/main/classes/core/src/com/ibm/icu/impl/number/RoundingUtils.java
icu4j/main/tests/core/src/com/ibm/icu/dev/test/number/NumberFormatterApiTest.java

index d60450b5a563d06cbf728497c31e5e437fa72c41..b7796cb7ddaf2a03ed5a49d5b9029c65b2abb49e 100644 (file)
@@ -539,6 +539,7 @@ typedef enum UErrorCode {
     U_DEFAULT_KEYWORD_MISSING,        /**< Missing DEFAULT rule in plural rules */
     U_DECIMAL_NUMBER_SYNTAX_ERROR,    /**< Decimal number syntax error */
     U_FORMAT_INEXACT_ERROR,           /**< Cannot format a number exactly and rounding mode is ROUND_UNNECESSARY @stable ICU 4.8 */
+    U_NUMBER_ARG_OUTOFBOUNDS_ERROR,   /**< The argument to a NumberFormatter helper method was out of bounds; the bounds are usually 0 to 999. @draft ICU 61 */
 #ifndef U_HIDE_DEPRECATED_API
     /**
      * One more than the highest normal formatting API error code.
index 8f5791be160e1727464af68b720ba88b7fcc99af..5d6a0504ba682a32461ff20626e82fc2a87f0dd1 100644 (file)
@@ -125,7 +125,8 @@ _uFmtErrorName[U_FMT_PARSE_ERROR_LIMIT - U_FMT_PARSE_ERROR_START] = {
     "U_UNDEFINED_KEYWORD",
     "U_DEFAULT_KEYWORD_MISSING",
     "U_DECIMAL_NUMBER_SYNTAX_ERROR",
-    "U_FORMAT_INEXACT_ERROR"
+    "U_FORMAT_INEXACT_ERROR",
+    "U_NUMBER_ARG_OUTOFBOUNDS_ERROR"
 };
 
 static const char * const
index 10dacfc4acb96f442b3ca3be5a6ef7e7d4d357c7..4a612273f5e530f25f7fd729325e32b8a06ec183 100644 (file)
@@ -13,25 +13,28 @@ using namespace icu;
 using namespace icu::number;
 using namespace icu::number::impl;
 
-IntegerWidth::IntegerWidth(int8_t minInt, int8_t maxInt) {
+IntegerWidth::IntegerWidth(digits_t minInt, digits_t maxInt) {
     fUnion.minMaxInt.fMinInt = minInt;
     fUnion.minMaxInt.fMaxInt = maxInt;
 }
 
 IntegerWidth IntegerWidth::zeroFillTo(int32_t minInt) {
     if (minInt >= 0 && minInt <= kMaxIntFracSig) {
-        return {static_cast<int8_t>(minInt), -1};
+        return {static_cast<digits_t>(minInt), -1};
     } else {
-        return {U_NUMBER_DIGIT_WIDTH_OUTOFBOUNDS_ERROR};
+        return {U_NUMBER_ARG_OUTOFBOUNDS_ERROR};
     }
 }
 
 IntegerWidth IntegerWidth::truncateAt(int32_t maxInt) {
     if (fHasError) { return *this; }  // No-op on error
-    if (maxInt >= 0 && maxInt <= kMaxIntFracSig) {
-        return {fUnion.minMaxInt.fMinInt, static_cast<int8_t>(maxInt)};
+    digits_t minInt = fUnion.minMaxInt.fMinInt;
+    if (maxInt >= 0 && maxInt <= kMaxIntFracSig && minInt <= maxInt) {
+        return {minInt, static_cast<digits_t>(maxInt)};
+    } else if (maxInt == -1) {
+        return {minInt, -1};
     } else {
-        return {U_NUMBER_DIGIT_WIDTH_OUTOFBOUNDS_ERROR};
+        return {U_NUMBER_ARG_OUTOFBOUNDS_ERROR};
     }
 }
 
index ff0cd9505de299d8537b215564ff7bd9bd334a8a..f4ad333354d0c7ee48b10fa91c4357c871a6e390 100644 (file)
@@ -54,13 +54,13 @@ Notation Notation::simple() {
 
 ScientificNotation
 ScientificNotation::withMinExponentDigits(int32_t minExponentDigits) const {
-    if (minExponentDigits >= 0 && minExponentDigits < kMaxIntFracSig) {
+    if (minExponentDigits >= 1 && minExponentDigits <= kMaxIntFracSig) {
         ScientificSettings settings = fUnion.scientific;
-        settings.fMinExponentDigits = (int8_t) minExponentDigits;
+        settings.fMinExponentDigits = static_cast<digits_t>(minExponentDigits);
         NotationUnion union_ = {settings};
         return {NTN_SCIENTIFIC, union_};
     } else {
-        return {U_NUMBER_DIGIT_WIDTH_OUTOFBOUNDS_ERROR};
+        return {U_NUMBER_ARG_OUTOFBOUNDS_ERROR};
     }
 }
 
index a478af60541dde532bb135c80c81ec951c5fc56f..b1db3490cd4489f3f9371d08ef784006c879d698 100644 (file)
@@ -43,7 +43,7 @@ Padder Padder::codePoints(UChar32 cp, int32_t targetWidth, UNumberFormatPadPosit
     if (targetWidth >= 0) {
         return {cp, targetWidth, position};
     } else {
-        return {U_NUMBER_PADDING_WIDTH_OUTOFBOUNDS_ERROR};
+        return {U_NUMBER_ARG_OUTOFBOUNDS_ERROR};
     }
 }
 
index 2f31727e994f75526cfb5da161080a42766e8439..fd4dafdf983b61a289be460d8af4eef6fac78be5 100644 (file)
@@ -58,7 +58,7 @@ FractionRounder Rounder::fixedFraction(int32_t minMaxFractionPlaces) {
     if (minMaxFractionPlaces >= 0 && minMaxFractionPlaces <= kMaxIntFracSig) {
         return constructFraction(minMaxFractionPlaces, minMaxFractionPlaces);
     } else {
-        return {U_NUMBER_DIGIT_WIDTH_OUTOFBOUNDS_ERROR};
+        return {U_NUMBER_ARG_OUTOFBOUNDS_ERROR};
     }
 }
 
@@ -66,7 +66,7 @@ FractionRounder Rounder::minFraction(int32_t minFractionPlaces) {
     if (minFractionPlaces >= 0 && minFractionPlaces <= kMaxIntFracSig) {
         return constructFraction(minFractionPlaces, -1);
     } else {
-        return {U_NUMBER_DIGIT_WIDTH_OUTOFBOUNDS_ERROR};
+        return {U_NUMBER_ARG_OUTOFBOUNDS_ERROR};
     }
 }
 
@@ -74,7 +74,7 @@ FractionRounder Rounder::maxFraction(int32_t maxFractionPlaces) {
     if (maxFractionPlaces >= 0 && maxFractionPlaces <= kMaxIntFracSig) {
         return constructFraction(0, maxFractionPlaces);
     } else {
-        return {U_NUMBER_DIGIT_WIDTH_OUTOFBOUNDS_ERROR};
+        return {U_NUMBER_ARG_OUTOFBOUNDS_ERROR};
     }
 }
 
@@ -83,40 +83,40 @@ FractionRounder Rounder::minMaxFraction(int32_t minFractionPlaces, int32_t maxFr
         minFractionPlaces <= maxFractionPlaces) {
         return constructFraction(minFractionPlaces, maxFractionPlaces);
     } else {
-        return {U_NUMBER_DIGIT_WIDTH_OUTOFBOUNDS_ERROR};
+        return {U_NUMBER_ARG_OUTOFBOUNDS_ERROR};
     }
 }
 
 Rounder Rounder::fixedDigits(int32_t minMaxSignificantDigits) {
-    if (minMaxSignificantDigits >= 0 && minMaxSignificantDigits <= kMaxIntFracSig) {
+    if (minMaxSignificantDigits >= 1 && minMaxSignificantDigits <= kMaxIntFracSig) {
         return constructSignificant(minMaxSignificantDigits, minMaxSignificantDigits);
     } else {
-        return {U_NUMBER_DIGIT_WIDTH_OUTOFBOUNDS_ERROR};
+        return {U_NUMBER_ARG_OUTOFBOUNDS_ERROR};
     }
 }
 
 Rounder Rounder::minDigits(int32_t minSignificantDigits) {
-    if (minSignificantDigits >= 0 && minSignificantDigits <= kMaxIntFracSig) {
+    if (minSignificantDigits >= 1 && minSignificantDigits <= kMaxIntFracSig) {
         return constructSignificant(minSignificantDigits, -1);
     } else {
-        return {U_NUMBER_DIGIT_WIDTH_OUTOFBOUNDS_ERROR};
+        return {U_NUMBER_ARG_OUTOFBOUNDS_ERROR};
     }
 }
 
 Rounder Rounder::maxDigits(int32_t maxSignificantDigits) {
-    if (maxSignificantDigits >= 0 && maxSignificantDigits <= kMaxIntFracSig) {
-        return constructSignificant(0, maxSignificantDigits);
+    if (maxSignificantDigits >= 1 && maxSignificantDigits <= kMaxIntFracSig) {
+        return constructSignificant(1, maxSignificantDigits);
     } else {
-        return {U_NUMBER_DIGIT_WIDTH_OUTOFBOUNDS_ERROR};
+        return {U_NUMBER_ARG_OUTOFBOUNDS_ERROR};
     }
 }
 
 Rounder Rounder::minMaxDigits(int32_t minSignificantDigits, int32_t maxSignificantDigits) {
-    if (minSignificantDigits >= 0 && maxSignificantDigits <= kMaxIntFracSig &&
+    if (minSignificantDigits >= 1 && maxSignificantDigits <= kMaxIntFracSig &&
         minSignificantDigits <= maxSignificantDigits) {
         return constructSignificant(minSignificantDigits, maxSignificantDigits);
     } else {
-        return {U_NUMBER_DIGIT_WIDTH_OUTOFBOUNDS_ERROR};
+        return {U_NUMBER_ARG_OUTOFBOUNDS_ERROR};
     }
 }
 
@@ -124,7 +124,7 @@ IncrementRounder Rounder::increment(double roundingIncrement) {
     if (roundingIncrement > 0.0) {
         return constructIncrement(roundingIncrement, 0);
     } else {
-        return {U_NUMBER_DIGIT_WIDTH_OUTOFBOUNDS_ERROR};
+        return {U_NUMBER_ARG_OUTOFBOUNDS_ERROR};
     }
 }
 
@@ -139,19 +139,19 @@ Rounder Rounder::withMode(RoundingMode roundingMode) const {
 
 Rounder FractionRounder::withMinDigits(int32_t minSignificantDigits) const {
     if (fType == RND_ERROR) { return *this; } // no-op in error state
-    if (minSignificantDigits >= 0 && minSignificantDigits <= kMaxIntFracSig) {
+    if (minSignificantDigits >= 1 && minSignificantDigits <= kMaxIntFracSig) {
         return constructFractionSignificant(*this, minSignificantDigits, -1);
     } else {
-        return {U_NUMBER_DIGIT_WIDTH_OUTOFBOUNDS_ERROR};
+        return {U_NUMBER_ARG_OUTOFBOUNDS_ERROR};
     }
 }
 
 Rounder FractionRounder::withMaxDigits(int32_t maxSignificantDigits) const {
     if (fType == RND_ERROR) { return *this; } // no-op in error state
-    if (maxSignificantDigits >= 0 && maxSignificantDigits <= kMaxIntFracSig) {
+    if (maxSignificantDigits >= 1 && maxSignificantDigits <= kMaxIntFracSig) {
         return constructFractionSignificant(*this, -1, maxSignificantDigits);
     } else {
-        return {U_NUMBER_DIGIT_WIDTH_OUTOFBOUNDS_ERROR};
+        return {U_NUMBER_ARG_OUTOFBOUNDS_ERROR};
     }
 }
 
@@ -185,14 +185,14 @@ Rounder IncrementRounder::withMinFraction(int32_t minFrac) const {
     if (minFrac >= 0 && minFrac <= kMaxIntFracSig) {
         return constructIncrement(fUnion.increment.fIncrement, minFrac);
     } else {
-        return {U_NUMBER_DIGIT_WIDTH_OUTOFBOUNDS_ERROR};
+        return {U_NUMBER_ARG_OUTOFBOUNDS_ERROR};
     }
 }
 
 FractionRounder Rounder::constructFraction(int32_t minFrac, int32_t maxFrac) {
     FractionSignificantSettings settings;
-    settings.fMinFrac = static_cast<int8_t> (minFrac);
-    settings.fMaxFrac = static_cast<int8_t> (maxFrac);
+    settings.fMinFrac = static_cast<digits_t>(minFrac);
+    settings.fMaxFrac = static_cast<digits_t>(maxFrac);
     settings.fMinSig = -1;
     settings.fMaxSig = -1;
     RounderUnion union_;
@@ -204,8 +204,8 @@ Rounder Rounder::constructSignificant(int32_t minSig, int32_t maxSig) {
     FractionSignificantSettings settings;
     settings.fMinFrac = -1;
     settings.fMaxFrac = -1;
-    settings.fMinSig = static_cast<int8_t>(minSig);
-    settings.fMaxSig = static_cast<int8_t>(maxSig);
+    settings.fMinSig = static_cast<digits_t>(minSig);
+    settings.fMaxSig = static_cast<digits_t>(maxSig);
     RounderUnion union_;
     union_.fracSig = settings;
     return {RND_SIGNIFICANT, union_, kDefaultMode};
@@ -214,8 +214,8 @@ Rounder Rounder::constructSignificant(int32_t minSig, int32_t maxSig) {
 Rounder
 Rounder::constructFractionSignificant(const FractionRounder &base, int32_t minSig, int32_t maxSig) {
     FractionSignificantSettings settings = base.fUnion.fracSig;
-    settings.fMinSig = static_cast<int8_t>(minSig);
-    settings.fMaxSig = static_cast<int8_t>(maxSig);
+    settings.fMinSig = static_cast<digits_t>(minSig);
+    settings.fMaxSig = static_cast<digits_t>(maxSig);
     RounderUnion union_;
     union_.fracSig = settings;
     return {RND_FRACTION_SIGNIFICANT, union_, kDefaultMode};
@@ -224,7 +224,7 @@ Rounder::constructFractionSignificant(const FractionRounder &base, int32_t minSi
 IncrementRounder Rounder::constructIncrement(double increment, int32_t minFrac) {
     IncrementSettings settings;
     settings.fIncrement = increment;
-    settings.fMinFrac = minFrac;
+    settings.fMinFrac = static_cast<digits_t>(minFrac);
     RounderUnion union_;
     union_.increment = settings;
     return {RND_INCREMENT, union_, kDefaultMode};
index e914ef71ac085c97e4071d98d9745a21a2a92e66..c01765e2cea6c6c0f3dacdd24407fc272cce18cf 100644 (file)
@@ -31,7 +31,7 @@ typedef UNumberFormatPadPosition PadPosition;
 typedef UNumberCompactStyle CompactStyle;
 
 // ICU4J Equivalent: RoundingUtils.MAX_INT_FRAC_SIG
-static constexpr int32_t kMaxIntFracSig = 100;
+static constexpr int32_t kMaxIntFracSig = 999;
 
 // ICU4J Equivalent: RoundingUtils.DEFAULT_ROUNDING_MODE
 static constexpr RoundingMode kDefaultMode = RoundingMode::UNUM_FOUND_HALFEVEN;
@@ -42,10 +42,6 @@ static constexpr char16_t kFallbackPaddingString[] = u" ";
 // ICU4J Equivalent: NumberFormatterImpl.DEFAULT_CURRENCY
 static constexpr char16_t kDefaultCurrency[] = u"XXX";
 
-// FIXME: New error codes:
-static constexpr UErrorCode U_NUMBER_DIGIT_WIDTH_OUTOFBOUNDS_ERROR = U_ILLEGAL_ARGUMENT_ERROR;
-static constexpr UErrorCode U_NUMBER_PADDING_WIDTH_OUTOFBOUNDS_ERROR = U_ILLEGAL_ARGUMENT_ERROR;
-
 // Forward declarations:
 
 class Modifier;
index 4c4f542b4ddd4d2d0d1e58551af28e4e2a2ed71a..be4593309e794a54d5b193e8e6932ffd2c30beb7 100644 (file)
@@ -394,6 +394,21 @@ class IntegerWidth;
 
 namespace impl {
 
+/**
+ * Datatype for minimum/maximum fraction digits. Must be able to hold kMaxIntFracSig.
+ *
+ * @internal
+ */
+typedef int16_t digits_t;
+
+/**
+ * Use a default threshold of 3. This means that the third time .format() is called, the data structures get built
+ * using the "safe" code path. The first two calls to .format() will trigger the unsafe code path.
+ *
+ * @internal
+ */
+static constexpr int32_t DEFAULT_THRESHOLD = 3;
+
 // Forward declarations:
 class Padder;
 struct MacroProps;
@@ -577,7 +592,7 @@ class U_I18N_API Notation : public UMemory {
         struct ScientificSettings {
             int8_t fEngineeringInterval;
             bool fRequireMinInt;
-            int8_t fMinExponentDigits;
+            impl::digits_t fMinExponentDigits;
             UNumberSignDisplay fExponentSignDisplay;
         } scientific;
 
@@ -892,14 +907,14 @@ class U_I18N_API Rounder : public UMemory {
     union RounderUnion {
         struct FractionSignificantSettings {
             // For RND_FRACTION, RND_SIGNIFICANT, and RND_FRACTION_SIGNIFICANT
-            int8_t fMinFrac;
-            int8_t fMaxFrac;
-            int8_t fMinSig;
-            int8_t fMaxSig;
+            impl::digits_t fMinFrac;
+            impl::digits_t fMaxFrac;
+            impl::digits_t fMinSig;
+            impl::digits_t fMaxSig;
         } fracSig;
         struct IncrementSettings {
             double fIncrement;
-            int32_t fMinFrac;
+            impl::digits_t fMinFrac;
         } increment; // For RND_INCREMENT
         UCurrencyUsage currencyUsage; // For RND_CURRENCY
         UErrorCode errorCode; // For RND_ERROR
@@ -1153,7 +1168,8 @@ class U_I18N_API IntegerWidth : public UMemory {
      * For example, with maxInt=3, the number 1234 will get printed as "234".
      *
      * @param maxInt
-     *            The maximum number of places before the decimal separator.
+     *            The maximum number of places before the decimal separator. maxInt == -1 means no
+     *            truncation.
      * @return An IntegerWidth for passing to the NumberFormatter integerWidth() setter.
      * @draft ICU 60
      * @see NumberFormatter
@@ -1163,14 +1179,14 @@ class U_I18N_API IntegerWidth : public UMemory {
   private:
     union {
         struct {
-            int8_t fMinInt;
-            int8_t fMaxInt;
+            impl::digits_t fMinInt;
+            impl::digits_t fMaxInt;
         } minMaxInt;
         UErrorCode errorCode;
     } fUnion;
     bool fHasError = false;
 
-    IntegerWidth(int8_t minInt, int8_t maxInt);
+    IntegerWidth(impl::digits_t minInt, impl::digits_t maxInt);
 
     IntegerWidth(UErrorCode errorCode) { // NOLINT
         fUnion.errorCode = errorCode;
@@ -1205,14 +1221,6 @@ class U_I18N_API IntegerWidth : public UMemory {
 
 namespace impl {
 
-/**
- * Use a default threshold of 3. This means that the third time .format() is called, the data structures get built
- * using the "safe" code path. The first two calls to .format() will trigger the unsafe code path.
- *
- * @internal
- */
-static constexpr int32_t DEFAULT_THRESHOLD = 3;
-
 /** @internal */
 class U_I18N_API SymbolsWrapper : public UMemory {
   public:
index 5edf872d3b72170dfe9a15ce4c541f4e1b36cc7b..c45913796a461cd6c6a91527192819dae71c8f63 100644 (file)
@@ -2030,6 +2030,25 @@ UBool IntlTest::assertEquals(const char* message,
     return TRUE;
 }
 
+
+UBool IntlTest::assertEquals(const char* message,
+                             UErrorCode expected,
+                             UErrorCode actual) {
+    if (expected != actual) {
+        errln((UnicodeString)"FAIL: " + message + "; got " +
+              u_errorName(actual) + 
+              "; expected " + u_errorName(expected));
+        return FALSE;
+    }
+#ifdef VERBOSE_ASSERTIONS
+    else {
+        logln((UnicodeString)"Ok: " + message + "; got " + u_errorName(actual));
+    }
+#endif
+    return TRUE;
+}
+
+
 #if !UCONFIG_NO_FORMATTING
 UBool IntlTest::assertEquals(const char* message,
                              const Formattable& expected,
@@ -2105,6 +2124,16 @@ UBool IntlTest::assertEquals(const UnicodeString& message,
                              int64_t actual) {
     return assertEquals(extractToAssertBuf(message), expected, actual);
 }
+UBool IntlTest::assertEquals(const UnicodeString& message,
+                             double expected,
+                             double actual) {
+    return assertEquals(extractToAssertBuf(message), expected, actual);
+}
+UBool IntlTest::assertEquals(const UnicodeString& message,
+                             UErrorCode expected,
+                             UErrorCode actual) {
+    return assertEquals(extractToAssertBuf(message), expected, actual);
+}
 
 #if !UCONFIG_NO_FORMATTING
 UBool IntlTest::assertEquals(const UnicodeString& message,
index 1f7c80d4794ebc80f8e5e49a3ab443606cf2eac2..08765b707d0ebed84291831dc023bfde055bbad6 100644 (file)
@@ -289,13 +289,12 @@ public:
     UBool assertSuccess(const char* message, UErrorCode ec, UBool possibleDataError=FALSE, const char *file=NULL, int line=0);
     UBool assertEquals(const char* message, const UnicodeString& expected,
                        const UnicodeString& actual, UBool possibleDataError=FALSE);
-    UBool assertEquals(const char* message, const char* expected,
-                       const char* actual);
-    UBool assertEquals(const char* message, UBool expected,
-                       UBool actual);
+    UBool assertEquals(const char* message, const char* expected, const char* actual);
+    UBool assertEquals(const char* message, UBool expected, UBool actual);
     UBool assertEquals(const char* message, int32_t expected, int32_t actual);
     UBool assertEquals(const char* message, int64_t expected, int64_t actual);
     UBool assertEquals(const char* message, double expected, double actual);
+    UBool assertEquals(const char* message, UErrorCode expected, UErrorCode actual);
 #if !UCONFIG_NO_FORMATTING
     UBool assertEquals(const char* message, const Formattable& expected,
                        const Formattable& actual, UBool possibleDataError=FALSE);
@@ -307,11 +306,12 @@ public:
     UBool assertSuccess(const UnicodeString& message, UErrorCode ec);
     UBool assertEquals(const UnicodeString& message, const UnicodeString& expected,
                        const UnicodeString& actual, UBool possibleDataError=FALSE);
-    UBool assertEquals(const UnicodeString& message, const char* expected,
-                       const char* actual);
+    UBool assertEquals(const UnicodeString& message, const char* expected, const char* actual);
     UBool assertEquals(const UnicodeString& message, UBool expected, UBool actual);
     UBool assertEquals(const UnicodeString& message, int32_t expected, int32_t actual);
     UBool assertEquals(const UnicodeString& message, int64_t expected, int64_t actual);
+    UBool assertEquals(const UnicodeString& message, double expected, double actual);
+    UBool assertEquals(const UnicodeString& message, UErrorCode expected, UErrorCode actual);
 
     virtual void runIndexedTest( int32_t index, UBool exec, const char* &name, char* par = NULL ); // overide !
 
index 9d4ffb7cef0d2afbc832b536f2785fad1610fe8b..5b4030a94942961d731fc64c03a6eed03b391698 100644 (file)
@@ -63,6 +63,7 @@ class NumberFormatterApiTest : public IntlTest {
     void locale();
     void formatTypes();
     void errors();
+    void validRanges();
 
     void runIndexedTest(int32_t index, UBool exec, const char *&name, char *par = 0);
 
index 62db705eac794598e4b211e1be6d174ee2923d5e..2d625877f304b0725dfa6f3830a4ae95b7f0d82f 100644 (file)
@@ -76,6 +76,7 @@ void NumberFormatterApiTest::runIndexedTest(int32_t index, UBool exec, const cha
         TESTCASE_AUTO(locale);
         TESTCASE_AUTO(formatTypes);
         TESTCASE_AUTO(errors);
+        TESTCASE_AUTO(validRanges);
     TESTCASE_AUTO_END;
 }
 
@@ -1748,27 +1749,83 @@ void NumberFormatterApiTest::errors() {
         UErrorCode status2 = U_ZERO_ERROR;
         FormattedNumber fn = lnf.formatInt(1, status1);
         assertEquals(
-                "Should fail with U_ILLEGAL_ARGUMENT_ERROR since rounder is not legal",
-                U_ILLEGAL_ARGUMENT_ERROR,
-                status1);
+                "Should fail since rounder is not legal",
+                (UBool) TRUE,
+                (UBool) U_FAILURE(status1));
         FieldPosition fp;
         fn.populateFieldPosition(fp, status2);
         assertEquals(
-                "Should fail with U_ILLEGAL_ARGUMENT_ERROR on terminal method",
-                U_ILLEGAL_ARGUMENT_ERROR,
-                status2);
+                "Should fail on terminal method",
+                (UBool) TRUE,
+                (UBool) U_FAILURE(status2));
     }
 
     {
         UErrorCode status = U_ZERO_ERROR;
         lnf.copyErrorTo(status);
         assertEquals(
-                "Should fail with U_ILLEGAL_ARGUMENT_ERROR since rounder is not legal",
-                U_ILLEGAL_ARGUMENT_ERROR,
-                status);
+                "Should fail since rounder is not legal",
+                (UBool) TRUE,
+                (UBool) U_FAILURE(status));
     }
 }
 
+void NumberFormatterApiTest::validRanges() {
+
+#define EXPECTED_MAX_INT_FRAC_SIG 999
+
+#define VALID_RANGE_ASSERT(status, method, lowerBound, argument) { \
+    UErrorCode expectedStatus = ((lowerBound <= argument) && (argument <= EXPECTED_MAX_INT_FRAC_SIG)) \
+        ? U_ZERO_ERROR \
+        : U_NUMBER_ARG_OUTOFBOUNDS_ERROR; \
+    assertEquals( \
+        UnicodeString(u"Incorrect status for " #method " on input ") \
+            + Int64ToUnicodeString(argument), \
+        expectedStatus, \
+        status); \
+}
+
+#define VALID_RANGE_ONEARG(setting, method, lowerBound) { \
+    for (int32_t argument = -2; argument <= EXPECTED_MAX_INT_FRAC_SIG + 2; argument++) { \
+        UErrorCode status = U_ZERO_ERROR; \
+        NumberFormatter::with().setting(method(argument)).copyErrorTo(status); \
+        VALID_RANGE_ASSERT(status, method, lowerBound, argument); \
+    } \
+}
+
+#define VALID_RANGE_TWOARGS(setting, method, lowerBound) { \
+    for (int32_t argument = -2; argument <= EXPECTED_MAX_INT_FRAC_SIG + 2; argument++) { \
+        UErrorCode status = U_ZERO_ERROR; \
+        /* Pass EXPECTED_MAX_INT_FRAC_SIG as the second argument so arg1 <= arg2 in expected cases */ \
+        NumberFormatter::with().setting(method(argument, EXPECTED_MAX_INT_FRAC_SIG)).copyErrorTo(status); \
+        VALID_RANGE_ASSERT(status, method, lowerBound, argument); \
+        status = U_ZERO_ERROR; \
+        /* Pass lowerBound as the first argument so arg1 <= arg2 in expected cases */ \
+        NumberFormatter::with().setting(method(lowerBound, argument)).copyErrorTo(status); \
+        VALID_RANGE_ASSERT(status, method, lowerBound, argument); \
+        /* Check that first argument must be less than or equal to second argument */ \
+        NumberFormatter::with().setting(method(argument, argument - 1)).copyErrorTo(status); \
+        assertEquals("Incorrect status for " #method " on max < min input", \
+            U_NUMBER_ARG_OUTOFBOUNDS_ERROR, \
+            status); \
+    } \
+}
+
+    VALID_RANGE_ONEARG(rounding, Rounder::fixedFraction, 0);
+    VALID_RANGE_ONEARG(rounding, Rounder::minFraction, 0);
+    VALID_RANGE_ONEARG(rounding, Rounder::maxFraction, 0);
+    VALID_RANGE_TWOARGS(rounding, Rounder::minMaxFraction, 0);
+    VALID_RANGE_ONEARG(rounding, Rounder::fixedDigits, 1);
+    VALID_RANGE_ONEARG(rounding, Rounder::minDigits, 1);
+    VALID_RANGE_ONEARG(rounding, Rounder::maxDigits, 1);
+    VALID_RANGE_TWOARGS(rounding, Rounder::minMaxDigits, 1);
+    VALID_RANGE_ONEARG(rounding, Rounder::fixedFraction(1).withMinDigits, 1);
+    VALID_RANGE_ONEARG(rounding, Rounder::fixedFraction(1).withMaxDigits, 1);
+    VALID_RANGE_ONEARG(notation, Notation::scientific().withMinExponentDigits, 1);
+    VALID_RANGE_ONEARG(integerWidth, IntegerWidth::zeroFillTo, 0);
+    VALID_RANGE_ONEARG(integerWidth, IntegerWidth::zeroFillTo(0).truncateAt, -1);
+}
+
 
 void NumberFormatterApiTest::assertFormatDescending(const UnicodeString &message,
                                                  const UnlocalizedNumberFormatter &f,
index 9098d8c6aa2ac0ab34a6ae3dadab91752bcfa6a7..b9a3cdb6da1b53b53cc346c48ef1e47a66c7512d 100644 (file)
@@ -22,7 +22,7 @@ public class RoundingUtils {
      * The maximum number of fraction places, integer numerals, or significant digits. TODO: This does
      * not feel like the best home for this value.
      */
-    public static final int MAX_INT_FRAC_SIG = 100;
+    public static final int MAX_INT_FRAC_SIG = 999;
 
     /**
      * Converts a rounding mode and metadata about the quantity being rounded to a boolean determining
index 3f9969ad6f7ec243b18e93f77365939776792c42..eb9cb5f2a2851c7ff47a379214ed0d21c9a8f3d7 100644 (file)
@@ -1897,12 +1897,12 @@ public class NumberFormatterApiTest {
                 Rounder.class.getDeclaredMethod("minMaxFraction", Integer.TYPE, Integer.TYPE),
                 Rounder.class.getDeclaredMethod("minMaxDigits", Integer.TYPE, Integer.TYPE), };
 
-        final int EXPECTED_MAX_INT_FRAC_SIG = 100;
-        final String expectedSubstring0 = "between 0 and 100 (inclusive)";
-        final String expectedSubstring1 = "between 1 and 100 (inclusive)";
-        final String expectedSubstringN1 = "between -1 and 100 (inclusive)";
+        final int EXPECTED_MAX_INT_FRAC_SIG = 999;
+        final String expectedSubstring0 = "between 0 and 999 (inclusive)";
+        final String expectedSubstring1 = "between 1 and 999 (inclusive)";
+        final String expectedSubstringN1 = "between -1 and 999 (inclusive)";
 
-        // We require that the upper bounds all be 100 inclusive.
+        // We require that the upper bounds all be 999 inclusive.
         // The lower bound may be either -1, 0, or 1.
         Set<String> methodsWithLowerBound1 = new HashSet();
         methodsWithLowerBound1.add("fixedDigits");
@@ -1912,6 +1912,12 @@ public class NumberFormatterApiTest {
         methodsWithLowerBound1.add("withMinDigits");
         methodsWithLowerBound1.add("withMaxDigits");
         methodsWithLowerBound1.add("withMinExponentDigits");
+        // Methods with lower bound 0:
+        // fixedFraction
+        // minFraction
+        // maxFraction
+        // minMaxFraction
+        // zeroFillTo
         Set<String> methodsWithLowerBoundN1 = new HashSet();
         methodsWithLowerBoundN1.add("truncateAt");