ICU-22017 Fix numbering system resolution in NumberRangeFormatter

See #2085
This commit is contained in:
Shane Carr 2022-06-10 02:19:29 +00:00 committed by Frank Yung-Fong Tang
parent df8fbc22e8
commit c5872e7f67
6 changed files with 97 additions and 2 deletions

View file

@ -354,6 +354,7 @@ LocalizedNumberRangeFormatter::getFormatter(UErrorCode& status) const {
// Try computing the formatter on our own
auto* temp = new NumberRangeFormatterImpl(fMacros, status);
if (U_FAILURE(status)) {
delete temp;
return nullptr;
}
if (temp == nullptr) {

View file

@ -130,7 +130,7 @@ NumberRangeFormatterImpl::NumberRangeFormatterImpl(const RangeMacroProps& macros
fApproximatelyFormatter(status) {
const char* nsName = formatterImpl1.getRawMicroProps().nsName;
if (uprv_strcmp(nsName, formatterImpl2.getRawMicroProps().nsName) != 0) {
if (!fSameFormatters && uprv_strcmp(nsName, formatterImpl2.getRawMicroProps().nsName) != 0) {
status = U_ILLEGAL_ARGUMENT_ERROR;
return;
}

View file

@ -326,6 +326,7 @@ class NumberRangeFormatterTest : public IntlTestWithFieldPosition {
void test21684_Performance();
void test21358_SignPosition();
void test21683_StateLeak();
void testCreateLNRFFromNumberingSystemInSkeleton();
void runIndexedTest(int32_t index, UBool exec, const char *&name, char *par = 0) override;

View file

@ -57,6 +57,7 @@ void NumberRangeFormatterTest::runIndexedTest(int32_t index, UBool exec, const c
TESTCASE_AUTO(test21684_Performance);
TESTCASE_AUTO(test21358_SignPosition);
TESTCASE_AUTO(test21683_StateLeak);
TESTCASE_AUTO(testCreateLNRFFromNumberingSystemInSkeleton);
TESTCASE_AUTO_END;
}
@ -1031,6 +1032,51 @@ void NumberRangeFormatterTest::test21358_SignPosition() {
}
}
void NumberRangeFormatterTest::testCreateLNRFFromNumberingSystemInSkeleton() {
IcuTestErrorCode status(*this, "testCreateLNRFFromNumberingSystemInSkeleton");
{
LocalizedNumberRangeFormatter lnrf = NumberRangeFormatter::withLocale("en")
.numberFormatterBoth(NumberFormatter::forSkeleton(
u".### rounding-mode-half-up", status));
UnicodeString actual = lnrf.formatFormattableRange(1, 234, status).toString(status);
assertEquals("default numbering system", u"1234", actual);
status.errIfFailureAndReset("default numbering system");
}
{
LocalizedNumberRangeFormatter lnrf = NumberRangeFormatter::withLocale("th")
.numberFormatterBoth(NumberFormatter::forSkeleton(
u".### rounding-mode-half-up numbering-system/thai", status));
UnicodeString actual = lnrf.formatFormattableRange(1, 234, status).toString(status);
assertEquals("Thai numbering system", u"๑-๒๓๔", actual);
status.errIfFailureAndReset("thai numbering system");
}
{
LocalizedNumberRangeFormatter lnrf = NumberRangeFormatter::withLocale("en")
.numberFormatterBoth(NumberFormatter::forSkeleton(
u".### rounding-mode-half-up numbering-system/arab", status));
UnicodeString actual = lnrf.formatFormattableRange(1, 234, status).toString(status);
assertEquals("Arabic numbering system", u"١–٢٣٤", actual);
status.errIfFailureAndReset("arab numbering system");
}
{
LocalizedNumberRangeFormatter lnrf = NumberRangeFormatter::withLocale("en")
.numberFormatterFirst(NumberFormatter::forSkeleton(u"numbering-system/arab", status))
.numberFormatterSecond(NumberFormatter::forSkeleton(u"numbering-system/arab", status));
UnicodeString actual = lnrf.formatFormattableRange(1, 234, status).toString(status);
assertEquals("Double Arabic numbering system", u"١–٢٣٤", actual);
status.errIfFailureAndReset("double arab numbering system");
}
{
LocalizedNumberRangeFormatter lnrf = NumberRangeFormatter::withLocale("en")
.numberFormatterFirst(NumberFormatter::forSkeleton(u"numbering-system/arab", status))
.numberFormatterSecond(NumberFormatter::forSkeleton(u"numbering-system/latn", status));
// Note: The error is not set until `formatFormattableRange` because this is where the
// formatter object gets built.
lnrf.formatFormattableRange(1, 234, status);
status.expectErrorAndReset(U_ILLEGAL_ARGUMENT_ERROR);
}
}
void NumberRangeFormatterTest::test21683_StateLeak() {
IcuTestErrorCode status(*this, "test21683_StateLeak");
UNumberRangeFormatter* nrf = nullptr;

View file

@ -157,7 +157,7 @@ class NumberRangeFormatterImpl {
: NumberRangeFormatter.RangeIdentityFallback.APPROXIMATELY;
String nsName = formatterImpl1.getRawMicroProps().nsName;
if (nsName == null || !nsName.equals(formatterImpl2.getRawMicroProps().nsName)) {
if (nsName == null || (!fSameFormatters && !nsName.equals(formatterImpl2.getRawMicroProps().nsName))) {
throw new IllegalArgumentException("Both formatters must have same numbering system");
}
getNumberRangeData(macros.loc, nsName, this);

View file

@ -966,6 +966,53 @@ public class NumberRangeFormatterTest extends TestFmwk {
}
}
@Test
public void testCreateLNRFFromNumberingSystemInSkeleton() {
{
LocalizedNumberRangeFormatter lnrf = NumberRangeFormatter
.withLocale(ULocale.forLanguageTag("en"))
.numberFormatterBoth(NumberFormatter.forSkeleton(
".### rounding-mode-half-up"));
String actual = lnrf.formatRange(1, 234).toString();
assertEquals("default numbering system", "1234", actual);
}
{
LocalizedNumberRangeFormatter lnrf = NumberRangeFormatter
.withLocale(ULocale.forLanguageTag("th"))
.numberFormatterBoth(NumberFormatter.forSkeleton(
".### rounding-mode-half-up numbering-system/thai"));
String actual = lnrf.formatRange(1, 234).toString();
assertEquals("Thai numbering system", "๑-๒๓๔", actual);
}
{
LocalizedNumberRangeFormatter lnrf = NumberRangeFormatter
.withLocale(ULocale.forLanguageTag("en"))
.numberFormatterBoth(NumberFormatter.forSkeleton(
".### rounding-mode-half-up numbering-system/arab"));
String actual = lnrf.formatRange(1, 234).toString();
assertEquals("Arabic numbering system", "١–٢٣٤", actual);
}
{
LocalizedNumberRangeFormatter lnrf = NumberRangeFormatter
.withLocale(ULocale.forLanguageTag("en"))
.numberFormatterFirst(NumberFormatter.forSkeleton("numbering-system/arab"))
.numberFormatterSecond(NumberFormatter.forSkeleton("numbering-system/arab"));
String actual = lnrf.formatRange(1, 234).toString();
assertEquals("Double Arabic numbering system", "١–٢٣٤", actual);
}
}
@Test(expected = IllegalArgumentException.class)
public void testCreateLNRFFromNumberingSystemInSkeletonError() {
LocalizedNumberRangeFormatter lnrf = NumberRangeFormatter
.withLocale(ULocale.forLanguageTag("en"))
.numberFormatterFirst(NumberFormatter.forSkeleton("numbering-system/arab"))
.numberFormatterSecond(NumberFormatter.forSkeleton("numbering-system/latn"));
// Note: The error is not thrown until `formatRange` because this is where the
// formatter object gets built.
lnrf.formatRange(1, 234);
}
static void assertFormatRange(
String message,
UnlocalizedNumberRangeFormatter f,