From 04d300adebcd448a11025d0e5f9371a675571ac3 Mon Sep 17 00:00:00 2001 From: Andy Heninger Date: Mon, 11 Jun 2018 03:56:58 +0000 Subject: [PATCH] ICU-13828 DecimalFormat Error Code handling cleanups. X-SVN-Rev: 41515 --- icu4c/source/i18n/decimfmt.cpp | 27 ++++-- icu4c/source/i18n/number_mapper.h | 2 +- icu4c/source/test/intltest/dcfmapts.cpp | 116 ++++++++++++++++++++++++ icu4c/source/test/intltest/dcfmapts.h | 1 + 4 files changed, 137 insertions(+), 9 deletions(-) diff --git a/icu4c/source/i18n/decimfmt.cpp b/icu4c/source/i18n/decimfmt.cpp index b5f6a073716..a2638bb7429 100644 --- a/icu4c/source/i18n/decimfmt.cpp +++ b/icu4c/source/i18n/decimfmt.cpp @@ -96,17 +96,21 @@ DecimalFormat::DecimalFormat(const UnicodeString& pattern, DecimalFormatSymbols* } DecimalFormat::DecimalFormat(const DecimalFormatSymbols* symbolsToAdopt, UErrorCode& status) { + LocalPointer adoptedSymbols(symbolsToAdopt); fields = new DecimalFormatFields(); + if (U_FAILURE(status)) { + return; + } if (fields == nullptr) { status = U_MEMORY_ALLOCATION_ERROR; return; } fields->properties.adoptInsteadAndCheckErrorCode(new DecimalFormatProperties(), status); fields->exportedProperties.adoptInsteadAndCheckErrorCode(new DecimalFormatProperties(), status); - if (symbolsToAdopt == nullptr) { + if (adoptedSymbols.isNull()) { fields->symbols.adoptInsteadAndCheckErrorCode(new DecimalFormatSymbols(status), status); } else { - fields->symbols.adoptInsteadAndCheckErrorCode(symbolsToAdopt, status); + fields->symbols.adoptInsteadAndCheckErrorCode(adoptedSymbols.orphan(), status); } } @@ -968,9 +972,11 @@ void DecimalFormat::applyLocalizedPattern(const UnicodeString& localizedPattern, } void DecimalFormat::applyLocalizedPattern(const UnicodeString& localizedPattern, UErrorCode& status) { - UnicodeString pattern = PatternStringUtils::convertLocalized( - localizedPattern, *fields->symbols, false, status); - applyPattern(pattern, status); + if (U_SUCCESS(status)) { + UnicodeString pattern = PatternStringUtils::convertLocalized( + localizedPattern, *fields->symbols, false, status); + applyPattern(pattern, status); + } } void DecimalFormat::setMaximumIntegerDigits(int32_t newValue) { @@ -1080,6 +1086,9 @@ void DecimalFormat::setCurrency(const char16_t* theCurrency) { } void DecimalFormat::setCurrencyUsage(UCurrencyUsage newUsage, UErrorCode* ec) { + if (U_FAILURE(*ec)) { + return; + } if (!fields->properties->currencyUsage.isNull() && newUsage == fields->properties->currencyUsage.getNoError()) { return; } @@ -1158,9 +1167,11 @@ void DecimalFormat::touchNoError() { void DecimalFormat::setPropertiesFromPattern(const UnicodeString& pattern, int32_t ignoreRounding, UErrorCode& status) { - // Cast workaround to get around putting the enum in the public header file - auto actualIgnoreRounding = static_cast(ignoreRounding); - PatternParser::parseToExistingProperties(pattern, *fields->properties, actualIgnoreRounding, status); + if (U_SUCCESS(status)) { + // Cast workaround to get around putting the enum in the public header file + auto actualIgnoreRounding = static_cast(ignoreRounding); + PatternParser::parseToExistingProperties(pattern, *fields->properties, actualIgnoreRounding, status); + } } const numparse::impl::NumberParserImpl* DecimalFormat::getParser(UErrorCode& status) const { diff --git a/icu4c/source/i18n/number_mapper.h b/icu4c/source/i18n/number_mapper.h index 40d264f0e2b..82c5711c8d0 100644 --- a/icu4c/source/i18n/number_mapper.h +++ b/icu4c/source/i18n/number_mapper.h @@ -150,7 +150,7 @@ struct DecimalFormatFields : public UMemory { LocalPointer exportedProperties; // Data for fastpath - bool canUseFastFormat; + bool canUseFastFormat = false; struct FastFormatData { char16_t cpZero; char16_t cpGroupingSeparator; diff --git a/icu4c/source/test/intltest/dcfmapts.cpp b/icu4c/source/test/intltest/dcfmapts.cpp index 33014340c3d..6a79bab8509 100644 --- a/icu4c/source/test/intltest/dcfmapts.cpp +++ b/icu4c/source/test/intltest/dcfmapts.cpp @@ -89,6 +89,12 @@ void IntlTestDecimalFormatAPI::runIndexedTest( int32_t index, UBool exec, const TestRequiredDecimalPoint(); } break; + case 8: name = "testErrorCode"; + if(exec) { + logln((UnicodeString)"testErrorCode ---"); + testErrorCode(); + } + break; default: name = ""; break; } } @@ -1022,4 +1028,114 @@ void IntlTestDecimalFormatAPI::TestRequiredDecimalPoint() { } } +// WHERE Macro yields a literal string of the form "source_file_name:line number " +#define WHERE __FILE__ ":" XLINE(__LINE__) " " +#define XLINE(s) LINE(s) +#define LINE(s) #s + +void IntlTestDecimalFormatAPI::testErrorCode() { + // Try each DecimalFormat constructor with an errorCode set on input, + // Verify no crashes or leaks, and that the errorCode is not altered. + + UErrorCode status = U_ZERO_ERROR; + const UnicodeString pattern(u"0.###E0"); + UParseError pe; + DecimalFormatSymbols symbols(Locale::getUS(), status); + assertSuccess(WHERE, status); + + { + status = U_INTERNAL_PROGRAM_ERROR; + DecimalFormat df(status); + assertEquals(WHERE, U_INTERNAL_PROGRAM_ERROR, status); + } + { + status = U_INTERNAL_PROGRAM_ERROR; + DecimalFormat df(pattern, status); + assertEquals(WHERE, U_INTERNAL_PROGRAM_ERROR, status); + } + { + status = U_INTERNAL_PROGRAM_ERROR; + DecimalFormat df(pattern, new DecimalFormatSymbols(symbols), status); + assertEquals(WHERE, U_INTERNAL_PROGRAM_ERROR, status); + } + { + status = U_INTERNAL_PROGRAM_ERROR; + DecimalFormat df(pattern, new DecimalFormatSymbols(symbols), UNUM_DECIMAL_COMPACT_LONG, status); + assertEquals(WHERE, U_INTERNAL_PROGRAM_ERROR, status); + } + { + status = U_INTERNAL_PROGRAM_ERROR; + DecimalFormat df(pattern, new DecimalFormatSymbols(symbols), pe, status); + assertEquals(WHERE, U_INTERNAL_PROGRAM_ERROR, status); + } + { + status = U_INTERNAL_PROGRAM_ERROR; + DecimalFormat df(pattern, symbols ,status); + assertEquals(WHERE, U_INTERNAL_PROGRAM_ERROR, status); + } + + // Try each DecimalFormat method with an error code parameter, verifying that + // an input error is not altered. + + status = U_INTERNAL_PROGRAM_ERROR; + DecimalFormat dfBogus(status); + assertEquals(WHERE, U_INTERNAL_PROGRAM_ERROR, status); + + status = U_ZERO_ERROR; + DecimalFormat dfGood(pattern, new DecimalFormatSymbols(symbols), status); + assertSuccess(WHERE, status); + + for (DecimalFormat *df: {&dfBogus, &dfGood}) { + status = U_INTERNAL_PROGRAM_ERROR; + df->setAttribute(UNUM_PARSE_INT_ONLY, 0, status); + assertEquals(WHERE, U_INTERNAL_PROGRAM_ERROR, status); + + status = U_INTERNAL_PROGRAM_ERROR; + df->getAttribute(UNUM_MAX_FRACTION_DIGITS, status); + assertEquals(WHERE, U_INTERNAL_PROGRAM_ERROR, status); + + status = U_INTERNAL_PROGRAM_ERROR; + UnicodeString dest; + FieldPosition fp; + df->format(1.2, dest, fp, status); + assertEquals(WHERE, U_INTERNAL_PROGRAM_ERROR, status); + + status = U_INTERNAL_PROGRAM_ERROR; + df->format(1.2, dest, nullptr, status); + assertEquals(WHERE, U_INTERNAL_PROGRAM_ERROR, status); + + status = U_INTERNAL_PROGRAM_ERROR; + df->format((int32_t)666, dest, nullptr, status); + assertEquals(WHERE, U_INTERNAL_PROGRAM_ERROR, status); + + status = U_INTERNAL_PROGRAM_ERROR; + df->format((int64_t)666, dest, nullptr, status); + assertEquals(WHERE, U_INTERNAL_PROGRAM_ERROR, status); + + status = U_INTERNAL_PROGRAM_ERROR; + df->format(StringPiece("3.1415926535897932384626"), dest, nullptr, status); + assertEquals(WHERE, U_INTERNAL_PROGRAM_ERROR, status); + + status = U_INTERNAL_PROGRAM_ERROR; + df->applyPattern(pattern, status); + assertEquals(WHERE, U_INTERNAL_PROGRAM_ERROR, status); + + status = U_INTERNAL_PROGRAM_ERROR; + df->applyLocalizedPattern(pattern, pe, status); + assertEquals(WHERE, U_INTERNAL_PROGRAM_ERROR, status); + + status = U_INTERNAL_PROGRAM_ERROR; + df->applyLocalizedPattern(pattern, status); + assertEquals(WHERE, U_INTERNAL_PROGRAM_ERROR, status); + + status = U_INTERNAL_PROGRAM_ERROR; + df->setCurrency(u"USD", status); + assertEquals(WHERE, U_INTERNAL_PROGRAM_ERROR, status); + + status = U_INTERNAL_PROGRAM_ERROR; + df->setCurrencyUsage(UCURR_USAGE_CASH, &status); + assertEquals(WHERE, U_INTERNAL_PROGRAM_ERROR, status); + } +} + #endif /* #if !UCONFIG_NO_FORMATTING */ diff --git a/icu4c/source/test/intltest/dcfmapts.h b/icu4c/source/test/intltest/dcfmapts.h index 1af38140db4..2e4bff7fb7b 100644 --- a/icu4c/source/test/intltest/dcfmapts.h +++ b/icu4c/source/test/intltest/dcfmapts.h @@ -33,6 +33,7 @@ public: void TestFixedDecimal(); void TestBadFastpath(); void TestRequiredDecimalPoint(); + void testErrorCode(); private: /*Helper functions */ void verify(const UnicodeString& message, const UnicodeString& got, double expected);