ICU-21544 Throw argument error when the units are not convertible.

This commit is contained in:
Younies 2021-09-22 16:07:43 +02:00 committed by Younies Mahmoud
parent b405c1c8db
commit f1f0b22a2a
5 changed files with 70 additions and 7 deletions

View 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;
}

View file

@ -67,6 +67,7 @@ class NumberFormatterApiTest : public IntlTestWithFieldPosition {
void unitCurrency();
void unitInflections();
void unitGender();
void unitNotConvertible();
void unitPercent();
void percentParity();
void roundingFraction();

View 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",

View 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);

View 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(