]> granicus.if.org Git - icu/commitdiff
ICU-21544 Throw argument error when the units are not convertible.
authorYounies <younies.mahmoud@gmail.com>
Wed, 22 Sep 2021 14:07:43 +0000 (16:07 +0200)
committerYounies Mahmoud <younies@chromium.org>
Wed, 22 Sep 2021 17:55:58 +0000 (19:55 +0200)
icu4c/source/i18n/units_converter.cpp
icu4c/source/test/intltest/numbertest.h
icu4c/source/test/intltest/numbertest_api.cpp
icu4j/main/classes/core/src/com/ibm/icu/impl/units/UnitsConverter.java
icu4j/main/tests/core/src/com/ibm/icu/dev/test/number/NumberFormatterApiTest.java

index 4858cbd233c1f59a05bc342771ae4bbbeed0cbe6..7e946e584bb76a99db3373fd8cf22a8d29b1da1b 100644 (file)
@@ -461,7 +461,7 @@ Convertibility U_I18N_API extractConvertibility(const MeasureUnitImpl &source,
 
     if (source.complexity == UMeasureUnitComplexity::UMEASURE_UNIT_MIXED ||
         target.complexity == UMeasureUnitComplexity::UMEASURE_UNIT_MIXED) {
-        status = U_INTERNAL_PROGRAM_ERROR;
+        status = U_ARGUMENT_TYPE_MISMATCH;
         return UNCONVERTIBLE;
     }
 
@@ -514,7 +514,7 @@ void UnitsConverter::init(const ConversionRates &ratesInfo, UErrorCode &status)
 
     if (this->conversionRate_.source.complexity == UMeasureUnitComplexity::UMEASURE_UNIT_MIXED ||
         this->conversionRate_.target.complexity == UMeasureUnitComplexity::UMEASURE_UNIT_MIXED) {
-        status = U_INTERNAL_PROGRAM_ERROR;
+        status = U_ARGUMENT_TYPE_MISMATCH;
         return;
     }
 
@@ -522,7 +522,7 @@ void UnitsConverter::init(const ConversionRates &ratesInfo, UErrorCode &status)
                                                       this->conversionRate_.target, ratesInfo, status);
     if (U_FAILURE(status)) return;
     if (unitsState == Convertibility::UNCONVERTIBLE) {
-        status = U_INTERNAL_PROGRAM_ERROR;
+        status = U_ARGUMENT_TYPE_MISMATCH;
         return;
     }
 
@@ -540,7 +540,7 @@ int32_t UnitsConverter::compareTwoUnits(const MeasureUnitImpl &firstUnit,
 
     if (firstUnit.complexity == UMeasureUnitComplexity::UMEASURE_UNIT_MIXED ||
         secondUnit.complexity == UMeasureUnitComplexity::UMEASURE_UNIT_MIXED) {
-        status = U_INTERNAL_PROGRAM_ERROR;
+        status = U_ARGUMENT_TYPE_MISMATCH;
         return 0;
     }
 
@@ -550,7 +550,7 @@ int32_t UnitsConverter::compareTwoUnits(const MeasureUnitImpl &firstUnit,
     }
 
     if (unitsState == Convertibility::UNCONVERTIBLE || unitsState == Convertibility::RECIPROCAL) {
-        status = U_INTERNAL_PROGRAM_ERROR;
+        status = U_ARGUMENT_TYPE_MISMATCH;
         return 0;
     }
 
index be6fe89eb150964eb882f2562b35b28bb6001ba2..d6d71543fb605f7741f133d838074ec2de0a4c57 100644 (file)
@@ -67,6 +67,7 @@ class NumberFormatterApiTest : public IntlTestWithFieldPosition {
     void unitCurrency();
     void unitInflections();
     void unitGender();
+    void unitNotConvertible();
     void unitPercent();
     void percentParity();
     void roundingFraction();
index 8d26b902a6b2e2db83478c717d9bf6aa801c2504..cf8fecc0a284ea2e14cab90a2468a4ff863da8ae 100644 (file)
@@ -88,6 +88,7 @@ void NumberFormatterApiTest::runIndexedTest(int32_t index, UBool exec, const cha
         TESTCASE_AUTO(unitCurrency);
         TESTCASE_AUTO(unitInflections);
         TESTCASE_AUTO(unitGender);
+        TESTCASE_AUTO(unitNotConvertible);
         TESTCASE_AUTO(unitPercent);
         if (!quick) {
             // Slow test: run in exhaustive mode only
@@ -2699,6 +2700,31 @@ void NumberFormatterApiTest::unitGender() {
     assertEquals("getGender for a genderless language", "", fn.getGender(status));
 }
 
+void NumberFormatterApiTest::unitNotConvertible() {
+    IcuTestErrorCode status(*this, "unitNotConvertible");
+    const double randomNumber = 1234;
+
+    NumberFormatter::with()
+        .unit(MeasureUnit::forIdentifier("meter-and-liter", status))
+        .locale("en_US")
+        .formatDouble(randomNumber, status);
+    assertEquals(u"error must be returned", status.errorName(), u"U_ARGUMENT_TYPE_MISMATCH");
+
+    status.reset();
+    NumberFormatter::with()
+        .unit(MeasureUnit::forIdentifier("month-and-week", status))
+        .locale("en_US")
+        .formatDouble(randomNumber, status);
+    assertEquals(u"error must be returned", status.errorName(), u"U_ARGUMENT_TYPE_MISMATCH");
+
+    status.reset();
+    NumberFormatter::with()
+        .unit(MeasureUnit::forIdentifier("week-and-day", status))
+        .locale("en_US")
+        .formatDouble(randomNumber, status);
+    assertTrue(u"no error", !U_FAILURE(status));
+}
+
 void NumberFormatterApiTest::unitPercent() {
     assertFormatDescending(
             u"Percent",
index 9f80f439246deb51f04779c3ea24196bc97c27db..acece19279e76fc3f10816bfd9d59e75398aef46 100644 (file)
@@ -9,6 +9,7 @@ import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.regex.Pattern;
 
+import com.ibm.icu.impl.IllegalIcuArgumentException;
 import com.ibm.icu.util.MeasureUnit;
 
 public class UnitsConverter {
@@ -48,8 +49,9 @@ public class UnitsConverter {
      */
     public UnitsConverter(MeasureUnitImpl source, MeasureUnitImpl target, ConversionRates conversionRates) {
         Convertibility convertibility = extractConvertibility(source, target, conversionRates);
-        // TODO(icu-units#82): throw exception if conversion between incompatible types was requested?
-        assert (convertibility == Convertibility.CONVERTIBLE || convertibility == Convertibility.RECIPROCAL);
+        if (convertibility != Convertibility.CONVERTIBLE && convertibility != Convertibility.RECIPROCAL) {
+            throw new IllegalIcuArgumentException("input units must be convertible or reciprocal");
+        }
 
         Factor sourceToBase = conversionRates.getFactorToBase(source);
         Factor targetToBase = conversionRates.getFactorToBase(target);
index 9c2a0918ab191a3164b0021f5829ab82e5ccb2f2..c0ab0dadeb3d4af68b0d75705c158560f6277e76 100644 (file)
@@ -2690,6 +2690,40 @@ public class NumberFormatterApiTest extends TestFmwk {
         assertEquals("getGender for a genderless language", "", fn.getGender());
     }
 
+    @Test
+    public void unitNotConvertible() {
+        final double randomNumber = 1234;
+
+        try {
+            NumberFormatter.with()
+                    .unit(MeasureUnit.forIdentifier("meter-and-liter"))
+                    .locale(new ULocale("en_US"))
+                    .format(randomNumber);
+        } catch (Exception e) {
+            assertEquals("error must be thrown", "class com.ibm.icu.impl.IllegalIcuArgumentException", e.getClass().toString());
+        }
+
+        try {
+            NumberFormatter.with()
+                    .unit(MeasureUnit.forIdentifier("month-and-week"))
+                    .locale(new ULocale("en_US"))
+                    .format(randomNumber);
+        } catch (Exception e) {
+            assertEquals("error must be thrown", "class com.ibm.icu.impl.IllegalIcuArgumentException", e.getClass().toString());
+        }
+
+        try {
+            NumberFormatter.with()
+                    .unit(MeasureUnit.forIdentifier("day-and-hour"))
+                    .locale(new ULocale("en_US"))
+                    .format(2.5);
+        } catch (Exception e) {
+            // No errors.
+            assert false;
+        }
+
+    }
+
     @Test
     public void unitPercent() {
         assertFormatDescending(