ICU-20844 remove restriction on minInt=minFrac=0, ensure doFastFormatInt32

and NumberFormatterImpl::writeNumber produce at least 1 result digit (#917)
This commit is contained in:
Peter Edberg 2019-11-11 19:14:07 -08:00 committed by pedberg-icu
parent afbd1b91d9
commit ceb84b5dde
5 changed files with 111 additions and 5 deletions

View file

@ -1834,7 +1834,8 @@ void DecimalFormat::doFastFormatInt32(int32_t input, bool isNegative, UnicodeStr
char16_t localBuffer[localCapacity];
char16_t* ptr = localBuffer + localCapacity;
int8_t group = 0;
for (int8_t i = 0; i < fields->fastData.maxInt && (input != 0 || i < fields->fastData.minInt); i++) {
int8_t minInt = (fields->fastData.minInt < 1)? 1: fields->fastData.minInt;
for (int8_t i = 0; i < fields->fastData.maxInt && (input != 0 || i < minInt); i++) {
if (group++ == 3 && fields->fastData.cpGroupingSeparator != 0) {
*(--ptr) = fields->fastData.cpGroupingSeparator;
group = 1;

View file

@ -509,6 +509,12 @@ int32_t NumberFormatterImpl::writeNumber(const MicroProps& micros, DecimalQuanti
// Add the fraction digits
length += writeFractionDigits(micros, quantity, string, length + index, status);
if (length == 0) {
// Force output of the digit for value 0
length += utils::insertDigitFromSymbols(
string, index, 0, *micros.symbols, UNUM_INTEGER_FIELD, status);
}
}
return length;

View file

@ -125,10 +125,8 @@ MacroProps NumberPropertyMapper::oldToNew(const DecimalFormatProperties& propert
}
// Validate min/max int/frac.
// For backwards compatibility, minimum overrides maximum if the two conflict.
// The following logic ensures that there is always a minimum of at least one digit.
if (minInt == 0 && maxFrac != 0) {
// Force a digit after the decimal point.
minFrac = minFrac <= 0 ? 1 : minFrac;
minFrac = (minFrac < 0 || (minFrac == 0 && maxInt == 0)) ? 1 : minFrac;
maxFrac = maxFrac < 0 ? -1 : maxFrac < minFrac ? minFrac : maxFrac;
minInt = 0;
maxInt = maxInt < 0 ? -1 : maxInt > kMaxIntFracSig ? -1 : maxInt;

View file

@ -74,6 +74,7 @@ static void TestParseCases(void);
static void TestSetMaxFracAndRoundIncr(void);
static void TestIgnorePadding(void);
static void TestSciNotationMaxFracCap(void);
static void TestMinIntMinFracZero(void);
#define TESTCASE(x) addTest(root, &x, "tsformat/cnumtst/" #x)
@ -114,6 +115,7 @@ void addNumForTest(TestNode** root)
TESTCASE(TestSetMaxFracAndRoundIncr);
TESTCASE(TestIgnorePadding);
TESTCASE(TestSciNotationMaxFracCap);
TESTCASE(TestMinIntMinFracZero);
}
/* test Parse int 64 */
@ -3475,4 +3477,103 @@ static void TestSciNotationMaxFracCap(void) {
}
}
static void TestMinIntMinFracZero(void) {
UErrorCode status = U_ZERO_ERROR;
UNumberFormat* unum = unum_open(UNUM_DECIMAL, NULL, 0, "en_US", NULL, &status);
if ( U_FAILURE(status) ) {
log_data_err("unum_open UNUM_DECIMAL for en_US fails with %s\n", u_errorName(status));
} else {
UChar ubuf[kUBufMax];
char bbuf[kBBufMax];
int minInt, minFrac, ulen;
unum_setAttribute(unum, UNUM_MIN_INTEGER_DIGITS, 0);
unum_setAttribute(unum, UNUM_MIN_FRACTION_DIGITS, 0);
minInt = unum_getAttribute(unum, UNUM_MIN_INTEGER_DIGITS);
minFrac = unum_getAttribute(unum, UNUM_MIN_FRACTION_DIGITS);
if (minInt != 0 || minFrac != 0) {
log_err("after setting minInt=minFrac=0, get minInt %d, minFrac %d\n", minInt, minFrac);
}
ulen = unum_toPattern(unum, FALSE, ubuf, kUBufMax, &status);
if ( U_FAILURE(status) ) {
log_err("unum_toPattern fails with %s\n", u_errorName(status));
} else if (ulen < 3 || u_strstr(ubuf, u"#.#")==NULL) {
u_austrncpy(bbuf, ubuf, kUBufMax);
log_info("after setting minInt=minFrac=0, expect pattern to contain \"#.#\", but get (%d): \"%s\"\n", ulen, bbuf);
}
status = U_ZERO_ERROR;
ulen = unum_formatDouble(unum, 10.0, ubuf, kUBufMax, NULL, &status);
if ( U_FAILURE(status) ) {
log_err("unum_formatDouble 10.0 ulen %d fails with %s\n", ulen, u_errorName(status));
} else if (u_strcmp(ubuf, u"10") != 0) {
u_austrncpy(bbuf, ubuf, kUBufMax);
log_err("unum_formatDouble 10.0 expected \"10\", got \"%s\"\n", bbuf);
}
status = U_ZERO_ERROR;
ulen = unum_formatDouble(unum, 0.9, ubuf, kUBufMax, NULL, &status);
if ( U_FAILURE(status) ) {
log_err("unum_formatDouble 0.9 ulen %d fails with %s\n", ulen, u_errorName(status));
} else if (u_strcmp(ubuf, u".9") != 0) {
u_austrncpy(bbuf, ubuf, kUBufMax);
log_err("unum_formatDouble 0.9 expected \".9\", got \"%s\"\n", bbuf);
}
status = U_ZERO_ERROR;
ulen = unum_formatDouble(unum, 0.0, ubuf, kUBufMax, NULL, &status);
if ( U_FAILURE(status) ) {
log_err("unum_formatDouble 0.0 ulen %d fails with %s\n", ulen, u_errorName(status));
} else if (u_strcmp(ubuf, u"0") != 0) {
u_austrncpy(bbuf, ubuf, kUBufMax);
log_err("unum_formatDouble 0.0 expected \"0\", got \"%s\"\n", bbuf);
}
unum_close(unum);
status = U_ZERO_ERROR;
unum = unum_open(UNUM_CURRENCY, NULL, 0, "en_US", NULL, &status);
if ( U_FAILURE(status) ) {
log_data_err("unum_open UNUM_CURRENCY for en_US fails with %s\n", u_errorName(status));
} else {
unum_setAttribute(unum, UNUM_MIN_INTEGER_DIGITS, 0);
unum_setAttribute(unum, UNUM_MIN_FRACTION_DIGITS, 0);
minInt = unum_getAttribute(unum, UNUM_MIN_INTEGER_DIGITS);
minFrac = unum_getAttribute(unum, UNUM_MIN_FRACTION_DIGITS);
if (minInt != 0 || minFrac != 0) {
log_err("after setting CURRENCY minInt=minFrac=0, get minInt %d, minFrac %d\n", minInt, minFrac);
}
status = U_ZERO_ERROR;
ulen = unum_formatDouble(unum, 10.0, ubuf, kUBufMax, NULL, &status);
if ( U_FAILURE(status) ) {
log_err("unum_formatDouble (CURRRENCY) 10.0 ulen %d fails with %s\n", ulen, u_errorName(status));
} else if (u_strcmp(ubuf, u"$10") != 0) {
u_austrncpy(bbuf, ubuf, kUBufMax);
log_err("unum_formatDouble (CURRRENCY) 10.0 expected \"$10\", got \"%s\"\n", bbuf);
}
status = U_ZERO_ERROR;
ulen = unum_formatDouble(unum, 0.9, ubuf, kUBufMax, NULL, &status);
if ( U_FAILURE(status) ) {
log_err("unum_formatDouble (CURRRENCY) 0.9 ulen %d fails with %s\n", ulen, u_errorName(status));
} else if (u_strcmp(ubuf, u"$.9") != 0) {
u_austrncpy(bbuf, ubuf, kUBufMax);
log_err("unum_formatDouble (CURRRENCY) 0.9 expected \"$.9\", got \"%s\"\n", bbuf);
}
status = U_ZERO_ERROR;
ulen = unum_formatDouble(unum, 0.0, ubuf, kUBufMax, NULL, &status);
if ( U_FAILURE(status) ) {
log_err("unum_formatDouble (CURRRENCY) 0.0 ulen %d fails with %s\n", ulen, u_errorName(status));
} else if (u_strcmp(ubuf, u"$0") != 0) {
u_austrncpy(bbuf, ubuf, kUBufMax);
log_err("unum_formatDouble (CURRRENCY) 0.0 expected \"$0\", got \"%s\"\n", bbuf);
}
unum_close(unum);
}
}
}
#endif /* #if !UCONFIG_NO_FORMATTING */

View file

@ -1648,7 +1648,7 @@ void NumberFormatterApiTest::integerWidth() {
u".8765",
u".08765",
u".008765",
u""); // TODO: Avoid the empty string here?
u"0"); // see ICU-20844
assertFormatDescending(
u"Integer Width Zero Fill 3",