]> granicus.if.org Git - icu/commitdiff
ICU-11276 Adding test cases and more API coverage.
authorShane Carr <shane@unicode.org>
Thu, 6 Sep 2018 06:04:32 +0000 (23:04 -0700)
committerShane Carr <shane@unicode.org>
Thu, 27 Sep 2018 21:27:40 +0000 (14:27 -0700)
icu4c/source/i18n/number_decimalquantity.cpp
icu4c/source/i18n/number_modifiers.cpp
icu4c/source/i18n/number_stringbuilder.cpp
icu4c/source/i18n/number_stringbuilder.h
icu4c/source/i18n/numrange_fluent.cpp
icu4c/source/i18n/numrange_impl.cpp
icu4c/source/i18n/unicode/numberrangeformatter.h
icu4c/source/test/intltest/numbertest.h
icu4c/source/test/intltest/numbertest_range.cpp

index 9d80e3349cb8aa19e398f7ecb47e2a54152741c8..760914e26f82784f297089b24f4e19ffef5d51ff 100644 (file)
@@ -1155,7 +1155,7 @@ const char16_t* DecimalQuantity::checkHealth() const {
 
 bool DecimalQuantity::operator==(const DecimalQuantity& other) const {
     // FIXME: Make a faster implementation.
-    return toString() == other.toString();
+    return toScientificString() == other.toScientificString();
 }
 
 UnicodeString DecimalQuantity::toString() const {
index 07adce16c49788c7f95d34b323b81ea4442384fa..6d0096055c8ba5756d32f266c7a08916a72af918 100644 (file)
@@ -280,10 +280,7 @@ bool ConstantMultiFieldModifier::isStrong() const {
 }
 
 bool ConstantMultiFieldModifier::containsField(UNumberFormatFields field) const {
-    (void)field;
-    // This method is not currently used.
-    U_ASSERT(false);
-    return false;
+    return fPrefix.containsField(field) || fSuffix.containsField(field);
 }
 
 bool ConstantMultiFieldModifier::operator==(const Modifier& other) const {
index 2806fefbaa99037d7dce824f50a0282db61a467f..74ba33fbbc159fd1e44c6cb3af8d163190c00015 100644 (file)
@@ -488,4 +488,13 @@ void NumberStringBuilder::getAllFieldPositions(FieldPositionIteratorHandler& fpi
     }
 }
 
+bool NumberStringBuilder::containsField(Field field) const {
+    for (int32_t i = 0; i < fLength; i++) {
+        if (field == fieldAt(i)) {
+            return true;
+        }
+    }
+    return false;
+}
+
 #endif /* #if !UCONFIG_NO_FORMATTING */
index cd8ce2f805e994f8fb1e3af67cb54b0dec593a3f..b14ad9ede2f90f47194344dfacd07a07f7a29fad 100644 (file)
@@ -106,6 +106,8 @@ class U_I18N_API NumberStringBuilder : public UMemory {
 
     void getAllFieldPositions(FieldPositionIteratorHandler& fpih, UErrorCode& status) const;
 
+    bool containsField(Field field) const;
+
   private:
     bool fUsingHeap = false;
     ValueOrHeapArray<char16_t> fChars;
index d2c5edcd2bf62576ee05255fd473df271e8ace01..ee81cb7aa07bc83263e9db8aabb793c9087f3607 100644 (file)
@@ -114,6 +114,34 @@ Derived NumberRangeFormatterSettings<Derived>::numberFormatterSecond(Unlocalized
     return move;
 }
 
+template<typename Derived>
+Derived NumberRangeFormatterSettings<Derived>::collapse(UNumberRangeCollapse collapse) const& {
+    Derived copy(*this);
+    copy.fMacros.collapse = collapse;
+    return copy;
+}
+
+template<typename Derived>
+Derived NumberRangeFormatterSettings<Derived>::collapse(UNumberRangeCollapse collapse) && {
+    Derived move(std::move(*this));
+    move.fMacros.collapse = collapse;
+    return move;
+}
+
+template<typename Derived>
+Derived NumberRangeFormatterSettings<Derived>::identityFallback(UNumberRangeIdentityFallback identityFallback) const& {
+    Derived copy(*this);
+    copy.fMacros.identityFallback = identityFallback;
+    return copy;
+}
+
+template<typename Derived>
+Derived NumberRangeFormatterSettings<Derived>::identityFallback(UNumberRangeIdentityFallback identityFallback) && {
+    Derived move(std::move(*this));
+    move.fMacros.identityFallback = identityFallback;
+    return move;
+}
+
 // Declare all classes that implement NumberRangeFormatterSettings
 // See https://stackoverflow.com/a/495056/1407170
 template
index 6e52d3498b0f5fc47cb4ac96a1930968135148fb..be6d38c5b6fbfc7e99bbd9c44408313742c6c648 100644 (file)
@@ -21,7 +21,7 @@ using namespace icu::number::impl;
 namespace {
 
 // Helper function for 2-dimensional switch statement
-constexpr int8_t identity2d(UNumberIdentityFallback a, UNumberRangeIdentityResult b) {
+constexpr int8_t identity2d(UNumberRangeIdentityFallback a, UNumberRangeIdentityResult b) {
     return static_cast<int8_t>(a) | (static_cast<int8_t>(b) << 4);
 }
 
@@ -111,10 +111,18 @@ void NumberRangeFormatterImpl::format(UFormattedNumberRangeData& data, bool equa
         formatterImpl1.preProcess(data.quantity1, micros1, status);
         formatterImpl1.preProcess(data.quantity2, micros2, status);
     } else {
-        // If the formatters are different, an identity is not possible.
-        // Always use formatRange().
         formatterImpl1.preProcess(data.quantity1, micros1, status);
         formatterImpl2.preProcess(data.quantity2, micros2, status);
+    }
+
+    // If any of the affixes are different, an identity is not possible
+    // and we must use formatRange().
+    // TODO: Write this as MicroProps operator==() ?
+    // TODO: Avoid the redundancy of these equality operations with the
+    // ones in formatRange?
+    if (!(*micros1.modInner == *micros2.modInner)
+            || !(*micros1.modMiddle == *micros2.modMiddle)
+            || !(*micros1.modOuter == *micros2.modOuter)) {
         formatRange(data, micros1, micros2, status);
         return;
     }
@@ -174,7 +182,8 @@ void NumberRangeFormatterImpl::formatSingleValue(UFormattedNumberRangeData& data
                                                  UErrorCode& status) const {
     if (U_FAILURE(status)) { return; }
     if (fSameFormatters) {
-        formatterImpl1.format(data.quantity1, data.string, status);
+        int32_t length = formatterImpl1.writeNumber(micros1, data.quantity1, data.string, 0, status);
+        formatterImpl1.writeAffixes(micros1, data.string, 0, length, status);
     } else {
         formatRange(data, micros1, micros2, status);
     }
@@ -186,7 +195,8 @@ void NumberRangeFormatterImpl::formatApproximately (UFormattedNumberRangeData& d
                                                     UErrorCode& status) const {
     if (U_FAILURE(status)) { return; }
     if (fSameFormatters) {
-        int32_t length = formatterImpl1.format(data.quantity1, data.string, status);
+        int32_t length = formatterImpl1.writeNumber(micros1, data.quantity1, data.string, 0, status);
+        length += formatterImpl1.writeAffixes(micros1, data.string, 0, length, status);
         fApproximatelyModifier.apply(data.string, 0, length, status);
     } else {
         formatRange(data, micros1, micros2, status);
@@ -242,8 +252,8 @@ void NumberRangeFormatterImpl::formatRange(UFormattedNumberRangeData& data,
                     collapseMiddle = false;
                 }
             } else if (fCollapse == UNUM_RANGE_COLLAPSE_AUTO) {
-                // Heuristic as of ICU 63: collapse only if the modifier is exactly one code point.
-                if (mm->getCodePointCount() != 1) {
+                // Heuristic as of ICU 63: collapse only if the modifier is more than one code point.
+                if (mm->getCodePointCount() <= 1) {
                     collapseMiddle = false;
                 }
             }
@@ -273,6 +283,8 @@ void NumberRangeFormatterImpl::formatRange(UFormattedNumberRangeData& data,
     int32_t lengthInfix = 0;
     int32_t length2 = 0;
     int32_t lengthSuffix = 0;
+
+    // Use #define so that these are evaluated at the call site.
     #define UPRV_INDEX_0 (lengthPrefix)
     #define UPRV_INDEX_1 (lengthPrefix + length1)
     #define UPRV_INDEX_2 (lengthPrefix + length1 + lengthInfix)
@@ -291,6 +303,7 @@ void NumberRangeFormatterImpl::formatRange(UFormattedNumberRangeData& data,
 
     // SPACING HEURISTIC
     // Add spacing unless all modifiers are collapsed.
+    // TODO: add API to control this?
     {
         bool repeatInner = !collapseInner && micros1.modInner->getCodePointCount() > 0;
         bool repeatMiddle = !collapseMiddle && micros1.modMiddle->getCodePointCount() > 0;
index 583361df1da738c19ca550aa4fa4bf82d9f74eb4..30a7c1e805082735cd1abf9663f55da363b12437 100644 (file)
@@ -116,7 +116,7 @@ typedef enum UNumberRangeIdentityFallback {
      * @draft ICU 63
      */
     UNUM_IDENTITY_FALLBACK_RANGE
-} UNumberIdentityFallback;
+} UNumberRangeIdentityFallback;
 
 /**
  * Used in the result class FormattedNumberRange to indicate to the user whether the numbers formatted in the range
@@ -199,7 +199,7 @@ struct U_I18N_API RangeMacroProps : public UMemory {
     UNumberRangeCollapse collapse = UNUM_RANGE_COLLAPSE_AUTO;
 
     /** @internal */
-    UNumberIdentityFallback identityFallback = UNUM_IDENTITY_FALLBACK_APPROXIMATELY;
+    UNumberRangeIdentityFallback identityFallback = UNUM_IDENTITY_FALLBACK_APPROXIMATELY;
 
     /** @internal */
     Locale locale;
@@ -414,7 +414,7 @@ class U_I18N_API NumberRangeFormatterSettings {
      * @return The fluent chain.
      * @draft ICU 63
      */
-    Derived identityFallback(UNumberIdentityFallback identityFallback) const &;
+    Derived identityFallback(UNumberRangeIdentityFallback identityFallback) const &;
 
     /**
      * Overload of identityFallback() for use on an rvalue reference.
@@ -425,7 +425,7 @@ class U_I18N_API NumberRangeFormatterSettings {
      * @see #identityFallback
      * @draft ICU 63
      */
-    Derived identityFallback(UNumberIdentityFallback identityFallback) &&;
+    Derived identityFallback(UNumberRangeIdentityFallback identityFallback) &&;
 
     /**
      * Sets the UErrorCode if an error occurred in the fluent chain.
index 74e5987156dc4f5877516f73564244e14cf05c54..03ef809d6e5f4942dfc56fc2f461ab4d6f610543 100644 (file)
@@ -253,6 +253,9 @@ class NumberRangeFormatterTest : public IntlTest {
 
     void testSanity();
     void testBasic();
+    void testCollapse();
+    void testIdentity();
+    void testDifferentFormatters();
 
     void runIndexedTest(int32_t index, UBool exec, const char *&name, char *par = 0);
 
index 6257e03f9685b2bf0d4a6ba0b9fe06f3f25124d2..7d5cb0467a5166147abfc1d2c15f095cb493bed9 100644 (file)
@@ -44,6 +44,9 @@ void NumberRangeFormatterTest::runIndexedTest(int32_t index, UBool exec, const c
     TESTCASE_AUTO_BEGIN;
         TESTCASE_AUTO(testSanity);
         TESTCASE_AUTO(testBasic);
+        TESTCASE_AUTO(testCollapse);
+        TESTCASE_AUTO(testIdentity);
+        TESTCASE_AUTO(testDifferentFormatters);
     TESTCASE_AUTO_END;
 }
 
@@ -106,6 +109,376 @@ void NumberRangeFormatterTest::testBasic() {
         u"5,000 m – 5,000,000 km");
 }
 
+void NumberRangeFormatterTest::testCollapse() {
+    assertFormatRange(
+        u"Default collapse on currency (default rounding)",
+        NumberRangeFormatter::with()
+            .numberFormatterBoth(NumberFormatter::with().unit(USD)),
+        Locale("en-us"),
+        u"$1.00 – $5.00",
+        u"~$5.00",
+        u"~$5.00",
+        u"$0.00 – $3.00",
+        u"~$0.00",
+        u"$3.00 – $3,000.00",
+        u"$3,000.00 – $5,000.00",
+        u"$4,999.00 – $5,001.00",
+        u"~$5,000.00",
+        u"$5,000.00 – $5,000,000.00");
+
+    assertFormatRange(
+        u"Default collapse on currency",
+        NumberRangeFormatter::with()
+            .numberFormatterBoth(NumberFormatter::with().unit(USD).precision(Precision::integer())),
+        Locale("en-us"),
+        u"$1 – $5",
+        u"~$5",
+        u"~$5",
+        u"$0 – $3",
+        u"~$0",
+        u"$3 – $3,000",
+        u"$3,000 – $5,000",
+        u"$4,999 – $5,001",
+        u"~$5,000",
+        u"$5,000 – $5,000,000");
+
+    assertFormatRange(
+        u"No collapse on currency",
+        NumberRangeFormatter::with()
+            .collapse(UNUM_RANGE_COLLAPSE_NONE)
+            .numberFormatterBoth(NumberFormatter::with().unit(USD).precision(Precision::integer())),
+        Locale("en-us"),
+        u"$1 – $5",
+        u"~$5",
+        u"~$5",
+        u"$0 – $3",
+        u"~$0",
+        u"$3 – $3,000",
+        u"$3,000 – $5,000",
+        u"$4,999 – $5,001",
+        u"~$5,000",
+        u"$5,000 – $5,000,000");
+
+    assertFormatRange(
+        u"Unit collapse on currency",
+        NumberRangeFormatter::with()
+            .collapse(UNUM_RANGE_COLLAPSE_UNIT)
+            .numberFormatterBoth(NumberFormatter::with().unit(USD).precision(Precision::integer())),
+        Locale("en-us"),
+        u"$1–5",
+        u"~$5",
+        u"~$5",
+        u"$0–3",
+        u"~$0",
+        u"$3–3,000",
+        u"$3,000–5,000",
+        u"$4,999–5,001",
+        u"~$5,000",
+        u"$5,000–5,000,000");
+
+    assertFormatRange(
+        u"All collapse on currency",
+        NumberRangeFormatter::with()
+            .collapse(UNUM_RANGE_COLLAPSE_ALL)
+            .numberFormatterBoth(NumberFormatter::with().unit(USD).precision(Precision::integer())),
+        Locale("en-us"),
+        u"$1–5",
+        u"~$5",
+        u"~$5",
+        u"$0–3",
+        u"~$0",
+        u"$3–3,000",
+        u"$3,000–5,000",
+        u"$4,999–5,001",
+        u"~$5,000",
+        u"$5,000–5,000,000");
+
+    assertFormatRange(
+        u"Default collapse on currency ISO code",
+        NumberRangeFormatter::with()
+            .numberFormatterBoth(NumberFormatter::with()
+                .unit(GBP)
+                .unitWidth(UNUM_UNIT_WIDTH_ISO_CODE)
+                .precision(Precision::integer())),
+        Locale("en-us"),
+        u"GBP 1–5",
+        u"~GBP 5",  // TODO: Fix this at some point
+        u"~GBP 5",
+        u"GBP 0–3",
+        u"~GBP 0",
+        u"GBP 3–3,000",
+        u"GBP 3,000–5,000",
+        u"GBP 4,999–5,001",
+        u"~GBP 5,000",
+        u"GBP 5,000–5,000,000");
+
+    assertFormatRange(
+        u"No collapse on currency ISO code",
+        NumberRangeFormatter::with()
+            .collapse(UNUM_RANGE_COLLAPSE_NONE)
+            .numberFormatterBoth(NumberFormatter::with()
+                .unit(GBP)
+                .unitWidth(UNUM_UNIT_WIDTH_ISO_CODE)
+                .precision(Precision::integer())),
+        Locale("en-us"),
+        u"GBP 1 – GBP 5",
+        u"~GBP 5",  // TODO: Fix this at some point
+        u"~GBP 5",
+        u"GBP 0 – GBP 3",
+        u"~GBP 0",
+        u"GBP 3 – GBP 3,000",
+        u"GBP 3,000 – GBP 5,000",
+        u"GBP 4,999 – GBP 5,001",
+        u"~GBP 5,000",
+        u"GBP 5,000 – GBP 5,000,000");
+
+    assertFormatRange(
+        u"Unit collapse on currency ISO code",
+        NumberRangeFormatter::with()
+            .collapse(UNUM_RANGE_COLLAPSE_UNIT)
+            .numberFormatterBoth(NumberFormatter::with()
+                .unit(GBP)
+                .unitWidth(UNUM_UNIT_WIDTH_ISO_CODE)
+                .precision(Precision::integer())),
+        Locale("en-us"),
+        u"GBP 1–5",
+        u"~GBP 5",  // TODO: Fix this at some point
+        u"~GBP 5",
+        u"GBP 0–3",
+        u"~GBP 0",
+        u"GBP 3–3,000",
+        u"GBP 3,000–5,000",
+        u"GBP 4,999–5,001",
+        u"~GBP 5,000",
+        u"GBP 5,000–5,000,000");
+
+    assertFormatRange(
+        u"All collapse on currency ISO code",
+        NumberRangeFormatter::with()
+            .collapse(UNUM_RANGE_COLLAPSE_ALL)
+            .numberFormatterBoth(NumberFormatter::with()
+                .unit(GBP)
+                .unitWidth(UNUM_UNIT_WIDTH_ISO_CODE)
+                .precision(Precision::integer())),
+        Locale("en-us"),
+        u"GBP 1–5",
+        u"~GBP 5",  // TODO: Fix this at some point
+        u"~GBP 5",
+        u"GBP 0–3",
+        u"~GBP 0",
+        u"GBP 3–3,000",
+        u"GBP 3,000–5,000",
+        u"GBP 4,999–5,001",
+        u"~GBP 5,000",
+        u"GBP 5,000–5,000,000");
+
+    // Default collapse on measurement unit is in testBasic()
+
+    assertFormatRange(
+        u"No collapse on measurement unit",
+        NumberRangeFormatter::with()
+            .collapse(UNUM_RANGE_COLLAPSE_NONE)
+            .numberFormatterBoth(NumberFormatter::with().unit(METER)),
+        Locale("en-us"),
+        u"1 m – 5 m",
+        u"~5 m",
+        u"~5 m",
+        u"0 m – 3 m",
+        u"~0 m",
+        u"3 m – 3,000 m",
+        u"3,000 m – 5,000 m",
+        u"4,999 m – 5,001 m",
+        u"~5,000 m",
+        u"5,000 m – 5,000,000 m");
+
+    assertFormatRange(
+        u"Unit collapse on measurement unit",
+        NumberRangeFormatter::with()
+            .collapse(UNUM_RANGE_COLLAPSE_UNIT)
+            .numberFormatterBoth(NumberFormatter::with().unit(METER)),
+        Locale("en-us"),
+        u"1–5 m",
+        u"~5 m",
+        u"~5 m",
+        u"0–3 m",
+        u"~0 m",
+        u"3–3,000 m",
+        u"3,000–5,000 m",
+        u"4,999–5,001 m",
+        u"~5,000 m",
+        u"5,000–5,000,000 m");
+
+    assertFormatRange(
+        u"All collapse on measurement unit",
+        NumberRangeFormatter::with()
+            .collapse(UNUM_RANGE_COLLAPSE_ALL)
+            .numberFormatterBoth(NumberFormatter::with().unit(METER)),
+        Locale("en-us"),
+        u"1–5 m",
+        u"~5 m",
+        u"~5 m",
+        u"0–3 m",
+        u"~0 m",
+        u"3–3,000 m",
+        u"3,000–5,000 m",
+        u"4,999–5,001 m",
+        u"~5,000 m",
+        u"5,000–5,000,000 m");
+
+    assertFormatRange(
+        u"Default collapse on measurement unit with compact-short notation",
+        NumberRangeFormatter::with()
+            .numberFormatterBoth(NumberFormatter::with().notation(Notation::compactShort()).unit(METER)),
+        Locale("en-us"),
+        u"1–5 m",
+        u"~5 m",
+        u"~5 m",
+        u"0–3 m",
+        u"~0 m",
+        u"3–3K m",
+        u"3K – 5K m",
+        u"~5K m",
+        u"~5K m",
+        u"5K – 5M m");
+
+    assertFormatRange(
+        u"No collapse on measurement unit with compact-short notation",
+        NumberRangeFormatter::with()
+            .collapse(UNUM_RANGE_COLLAPSE_NONE)
+            .numberFormatterBoth(NumberFormatter::with().notation(Notation::compactShort()).unit(METER)),
+        Locale("en-us"),
+        u"1 m – 5 m",
+        u"~5 m",
+        u"~5 m",
+        u"0 m – 3 m",
+        u"~0 m",
+        u"3 m – 3K m",
+        u"3K m – 5K m",
+        u"~5K m",
+        u"~5K m",
+        u"5K m – 5M m");
+
+    assertFormatRange(
+        u"Unit collapse on measurement unit with compact-short notation",
+        NumberRangeFormatter::with()
+            .collapse(UNUM_RANGE_COLLAPSE_UNIT)
+            .numberFormatterBoth(NumberFormatter::with().notation(Notation::compactShort()).unit(METER)),
+        Locale("en-us"),
+        u"1–5 m",
+        u"~5 m",
+        u"~5 m",
+        u"0–3 m",
+        u"~0 m",
+        u"3–3K m",
+        u"3K – 5K m",
+        u"~5K m",
+        u"~5K m",
+        u"5K – 5M m");
+
+    assertFormatRange(
+        u"All collapse on measurement unit with compact-short notation",
+        NumberRangeFormatter::with()
+            .collapse(UNUM_RANGE_COLLAPSE_ALL)
+            .numberFormatterBoth(NumberFormatter::with().notation(Notation::compactShort()).unit(METER)),
+        Locale("en-us"),
+        u"1–5 m",
+        u"~5 m",
+        u"~5 m",
+        u"0–3 m",
+        u"~0 m",
+        u"3–3K m",
+        u"3–5K m",  // this one is the key use case for ALL
+        u"~5K m",
+        u"~5K m",
+        u"5K – 5M m");
+
+    // TODO: Test compact currency?
+    // The code is not smart enough to differentiate the notation from the unit.
+}
+
+void NumberRangeFormatterTest::testIdentity() {
+    assertFormatRange(
+        u"Identity fallback Range",
+        NumberRangeFormatter::with().identityFallback(UNUM_IDENTITY_FALLBACK_RANGE),
+        Locale("en-us"),
+        u"1–5",
+        u"5–5",
+        u"5–5",
+        u"0–3",
+        u"0–0",
+        u"3–3,000",
+        u"3,000–5,000",
+        u"4,999–5,001",
+        u"5,000–5,000",
+        u"5,000–5,000,000");
+
+    assertFormatRange(
+        u"Identity fallback Approximately or Single Value",
+        NumberRangeFormatter::with().identityFallback(UNUM_IDENTITY_FALLBACK_APPROXIMATELY_OR_SINGLE_VALUE),
+        Locale("en-us"),
+        u"1–5",
+        u"~5",
+        u"5",
+        u"0–3",
+        u"0",
+        u"3–3,000",
+        u"3,000–5,000",
+        u"4,999–5,001",
+        u"5,000",
+        u"5,000–5,000,000");
+
+    assertFormatRange(
+        u"Identity fallback  Single Value",
+        NumberRangeFormatter::with().identityFallback(UNUM_IDENTITY_FALLBACK_SINGLE_VALUE),
+        Locale("en-us"),
+        u"1–5",
+        u"5",
+        u"5",
+        u"0–3",
+        u"0",
+        u"3–3,000",
+        u"3,000–5,000",
+        u"4,999–5,001",
+        u"5,000",
+        u"5,000–5,000,000");
+
+    assertFormatRange(
+        u"Identity fallback Approximately or Single Value with compact notation",
+        NumberRangeFormatter::with()
+            .identityFallback(UNUM_IDENTITY_FALLBACK_APPROXIMATELY_OR_SINGLE_VALUE)
+            .numberFormatterBoth(NumberFormatter::with().notation(Notation::compactShort())),
+        Locale("en-us"),
+        u"1–5",
+        u"~5",
+        u"5",
+        u"0–3",
+        u"0",
+        u"3–3K",
+        u"3K – 5K",
+        u"~5K",
+        u"5K",
+        u"5K – 5M");
+}
+
+void NumberRangeFormatterTest::testDifferentFormatters() {
+    assertFormatRange(
+        u"Different rounding rules",
+        NumberRangeFormatter::with()
+            .numberFormatterFirst(NumberFormatter::with().precision(Precision::integer()))
+            .numberFormatterSecond(NumberFormatter::with().precision(Precision::fixedDigits(2))),
+        Locale("en-us"),
+        u"1–5.0",
+        u"5–5.0",
+        u"5–5.0",
+        u"0–3.0",
+        u"0–0.0",
+        u"3–3,000",
+        u"3,000–5,000",
+        u"4,999–5,000",
+        u"5,000–5,000",  // TODO: Should this one be ~5,000?
+        u"5,000–5,000,000");
+}
+
 void  NumberRangeFormatterTest::assertFormatRange(
       const char16_t* message,
       const UnlocalizedNumberRangeFormatter& f,