#if !UCONFIG_NO_FORMATTING
#include "numfmtst.h"
+#include "unicode/currpinf.h"
#include "unicode/dcfmtsym.h"
#include "unicode/decimfmt.h"
#include "unicode/localpointer.h"
#include "unicode/measfmt.h"
#include "unicode/curramt.h"
#include "unicode/strenum.h"
-#include "digitlst.h"
#include "textfile.h"
#include "tokiter.h"
#include "charstr.h"
+#include "cstr.h"
#include "putilimp.h"
#include "winnmtst.h"
+#include <cmath>
#include <float.h>
#include <string.h>
#include <stdlib.h>
#include "unicode/numsys.h"
#include "fmtableimp.h"
#include "numberformattesttuple.h"
-#include "datadrivennumberformattestsuite.h"
#include "unicode/msgfmt.h"
-
-class NumberFormatTestDataDriven : public DataDrivenNumberFormatTestSuite {
-protected:
-UBool isFormatPass(
- const NumberFormatTestTuple &tuple,
- UnicodeString &appendErrorMessage,
- UErrorCode &status);
-UBool isToPatternPass(
- const NumberFormatTestTuple &tuple,
- UnicodeString &appendErrorMessage,
- UErrorCode &status);
-UBool isParsePass(
- const NumberFormatTestTuple &tuple,
- UnicodeString &appendErrorMessage,
- UErrorCode &status);
-UBool isParseCurrencyPass(
- const NumberFormatTestTuple &tuple,
- UnicodeString &appendErrorMessage,
- UErrorCode &status);
-};
-
-static DigitList &strToDigitList(
- const UnicodeString &str,
- DigitList &digitList,
- UErrorCode &status) {
- if (U_FAILURE(status)) {
- return digitList;
- }
- if (str == "NaN") {
- digitList.set(uprv_getNaN());
- return digitList;
- }
- if (str == "-Inf") {
- digitList.set(-1*uprv_getInfinity());
- return digitList;
- }
- if (str == "Inf") {
- digitList.set(uprv_getInfinity());
- return digitList;
- }
- CharString formatValue;
- formatValue.appendInvariantChars(str, status);
- digitList.set(StringPiece(formatValue.data()), status, 0);
- return digitList;
-}
-
-static UnicodeString &format(
- const DecimalFormat &fmt,
- const DigitList &digitList,
- UnicodeString &appendTo,
- UErrorCode &status) {
- if (U_FAILURE(status)) {
- return appendTo;
- }
- FieldPosition fpos(FieldPosition::DONT_CARE);
- return fmt.format(digitList, appendTo, fpos, status);
-}
-
-template<class T>
-static UnicodeString &format(
- const DecimalFormat &fmt,
- T value,
- UnicodeString &appendTo,
- UErrorCode &status) {
- if (U_FAILURE(status)) {
- return appendTo;
- }
- FieldPosition fpos(FieldPosition::DONT_CARE);
- return fmt.format(value, appendTo, fpos, status);
-}
-
-static void adjustDecimalFormat(
- const NumberFormatTestTuple &tuple,
- DecimalFormat &fmt,
- UnicodeString &appendErrorMessage) {
- if (tuple.minIntegerDigitsFlag) {
- fmt.setMinimumIntegerDigits(tuple.minIntegerDigits);
- }
- if (tuple.maxIntegerDigitsFlag) {
- fmt.setMaximumIntegerDigits(tuple.maxIntegerDigits);
- }
- if (tuple.minFractionDigitsFlag) {
- fmt.setMinimumFractionDigits(tuple.minFractionDigits);
- }
- if (tuple.maxFractionDigitsFlag) {
- fmt.setMaximumFractionDigits(tuple.maxFractionDigits);
- }
- if (tuple.currencyFlag) {
- UErrorCode status = U_ZERO_ERROR;
- UnicodeString currency(tuple.currency);
- const UChar *terminatedCurrency = currency.getTerminatedBuffer();
- fmt.setCurrency(terminatedCurrency, status);
- if (U_FAILURE(status)) {
- appendErrorMessage.append("Error setting currency.");
- }
- }
- if (tuple.minGroupingDigitsFlag) {
- fmt.setMinimumGroupingDigits(tuple.minGroupingDigits);
- }
- if (tuple.useSigDigitsFlag) {
- fmt.setSignificantDigitsUsed(tuple.useSigDigits != 0);
- }
- if (tuple.minSigDigitsFlag) {
- fmt.setMinimumSignificantDigits(tuple.minSigDigits);
- }
- if (tuple.maxSigDigitsFlag) {
- fmt.setMaximumSignificantDigits(tuple.maxSigDigits);
- }
- if (tuple.useGroupingFlag) {
- fmt.setGroupingUsed(tuple.useGrouping != 0);
- }
- if (tuple.multiplierFlag) {
- fmt.setMultiplier(tuple.multiplier);
- }
- if (tuple.roundingIncrementFlag) {
- fmt.setRoundingIncrement(tuple.roundingIncrement);
- }
- if (tuple.formatWidthFlag) {
- fmt.setFormatWidth(tuple.formatWidth);
- }
- if (tuple.padCharacterFlag) {
- fmt.setPadCharacter(tuple.padCharacter);
- }
- if (tuple.useScientificFlag) {
- fmt.setScientificNotation(tuple.useScientific != 0);
- }
- if (tuple.groupingFlag) {
- fmt.setGroupingSize(tuple.grouping);
- }
- if (tuple.grouping2Flag) {
- fmt.setSecondaryGroupingSize(tuple.grouping2);
- }
- if (tuple.roundingModeFlag) {
- fmt.setRoundingMode(tuple.roundingMode);
- }
- if (tuple.currencyUsageFlag) {
- UErrorCode status = U_ZERO_ERROR;
- fmt.setCurrencyUsage(tuple.currencyUsage, &status);
- if (U_FAILURE(status)) {
- appendErrorMessage.append("CurrencyUsage: error setting.");
- }
- }
- if (tuple.minimumExponentDigitsFlag) {
- fmt.setMinimumExponentDigits(tuple.minimumExponentDigits);
- }
- if (tuple.exponentSignAlwaysShownFlag) {
- fmt.setExponentSignAlwaysShown(tuple.exponentSignAlwaysShown != 0);
- }
- if (tuple.decimalSeparatorAlwaysShownFlag) {
- fmt.setDecimalSeparatorAlwaysShown(
- tuple.decimalSeparatorAlwaysShown != 0);
- }
- if (tuple.padPositionFlag) {
- fmt.setPadPosition(tuple.padPosition);
- }
- if (tuple.positivePrefixFlag) {
- fmt.setPositivePrefix(tuple.positivePrefix);
- }
- if (tuple.positiveSuffixFlag) {
- fmt.setPositiveSuffix(tuple.positiveSuffix);
- }
- if (tuple.negativePrefixFlag) {
- fmt.setNegativePrefix(tuple.negativePrefix);
- }
- if (tuple.negativeSuffixFlag) {
- fmt.setNegativeSuffix(tuple.negativeSuffix);
- }
- if (tuple.localizedPatternFlag) {
- UErrorCode status = U_ZERO_ERROR;
- fmt.applyLocalizedPattern(tuple.localizedPattern, status);
- if (U_FAILURE(status)) {
- appendErrorMessage.append("Error setting localized pattern.");
- }
- }
- fmt.setLenient(NFTT_GET_FIELD(tuple, lenient, 1) != 0);
- if (tuple.parseIntegerOnlyFlag) {
- fmt.setParseIntegerOnly(tuple.parseIntegerOnly != 0);
- }
- if (tuple.decimalPatternMatchRequiredFlag) {
- fmt.setDecimalPatternMatchRequired(
- tuple.decimalPatternMatchRequired != 0);
- }
- if (tuple.parseNoExponentFlag) {
- UErrorCode status = U_ZERO_ERROR;
- fmt.setAttribute(
- UNUM_PARSE_NO_EXPONENT,
- tuple.parseNoExponent,
- status);
- if (U_FAILURE(status)) {
- appendErrorMessage.append("Error setting parse no exponent flag.");
- }
- }
-}
-
-static DecimalFormat *newDecimalFormat(
- const Locale &locale,
- const UnicodeString &pattern,
- UErrorCode &status) {
- if (U_FAILURE(status)) {
- return NULL;
- }
- LocalPointer<DecimalFormatSymbols> symbols(
- new DecimalFormatSymbols(locale, status), status);
- if (U_FAILURE(status)) {
- return NULL;
- }
- UParseError perror;
- LocalPointer<DecimalFormat> result(new DecimalFormat(
- pattern, symbols.getAlias(), perror, status), status);
- if (!result.isNull()) {
- symbols.orphan();
- }
- if (U_FAILURE(status)) {
- return NULL;
- }
- return result.orphan();
-}
-
-static DecimalFormat *newDecimalFormat(
- const NumberFormatTestTuple &tuple,
- UErrorCode &status) {
- if (U_FAILURE(status)) {
- return NULL;
- }
- Locale en("en");
- return newDecimalFormat(
- NFTT_GET_FIELD(tuple, locale, en),
- NFTT_GET_FIELD(tuple, pattern, "0"),
- status);
+#include "number_decimalquantity.h"
+#include "unicode/numberformatter.h"
+
+#if (U_PLATFORM == U_PF_AIX) || (U_PLATFORM == U_PF_OS390)
+// These should not be macros. If they are,
+// replace them with std::isnan and std::isinf
+#if defined(isnan)
+#undef isnan
+namespace std {
+ bool isnan(double x) {
+ return _isnan(x);
+ }
}
-
-UBool NumberFormatTestDataDriven::isFormatPass(
- const NumberFormatTestTuple &tuple,
- UnicodeString &appendErrorMessage,
- UErrorCode &status) {
- if (U_FAILURE(status)) {
- return FALSE;
- }
- LocalPointer<DecimalFormat> fmtPtr(newDecimalFormat(tuple, status));
- if (U_FAILURE(status)) {
- appendErrorMessage.append("Error creating DecimalFormat.");
- return FALSE;
- }
- adjustDecimalFormat(tuple, *fmtPtr, appendErrorMessage);
- if (appendErrorMessage.length() > 0) {
- return FALSE;
- }
- DigitList digitList;
- strToDigitList(tuple.format, digitList, status);
- {
- UnicodeString appendTo;
- format(*fmtPtr, digitList, appendTo, status);
- if (U_FAILURE(status)) {
- appendErrorMessage.append("Error formatting.");
- return FALSE;
- }
- if (appendTo != tuple.output) {
- appendErrorMessage.append(
- UnicodeString("Expected: ") + tuple.output + ", got: " + appendTo);
- return FALSE;
- }
- }
- double doubleVal = digitList.getDouble();
- {
- UnicodeString appendTo;
- format(*fmtPtr, doubleVal, appendTo, status);
- if (U_FAILURE(status)) {
- appendErrorMessage.append("Error formatting.");
- return FALSE;
- }
- if (appendTo != tuple.output) {
- appendErrorMessage.append(
- UnicodeString("double Expected: ") + tuple.output + ", got: " + appendTo);
- return FALSE;
- }
- }
- if (!uprv_isNaN(doubleVal) && !uprv_isInfinite(doubleVal) && doubleVal == uprv_floor(doubleVal)) {
- int64_t intVal = digitList.getInt64();
- {
- UnicodeString appendTo;
- format(*fmtPtr, intVal, appendTo, status);
- if (U_FAILURE(status)) {
- appendErrorMessage.append("Error formatting.");
- return FALSE;
- }
- if (appendTo != tuple.output) {
- appendErrorMessage.append(
- UnicodeString("int64 Expected: ") + tuple.output + ", got: " + appendTo);
- return FALSE;
- }
- }
- }
- return TRUE;
-}
-
-UBool NumberFormatTestDataDriven::isToPatternPass(
- const NumberFormatTestTuple &tuple,
- UnicodeString &appendErrorMessage,
- UErrorCode &status) {
- if (U_FAILURE(status)) {
- return FALSE;
- }
- LocalPointer<DecimalFormat> fmtPtr(newDecimalFormat(tuple, status));
- if (U_FAILURE(status)) {
- appendErrorMessage.append("Error creating DecimalFormat.");
- return FALSE;
- }
- adjustDecimalFormat(tuple, *fmtPtr, appendErrorMessage);
- if (appendErrorMessage.length() > 0) {
- return FALSE;
- }
- if (tuple.toPatternFlag) {
- UnicodeString actual;
- fmtPtr->toPattern(actual);
- if (actual != tuple.toPattern) {
- appendErrorMessage.append(
- UnicodeString("Expected: ") + tuple.toPattern + ", got: " + actual + ". ");
- }
- }
- if (tuple.toLocalizedPatternFlag) {
- UnicodeString actual;
- fmtPtr->toLocalizedPattern(actual);
- if (actual != tuple.toLocalizedPattern) {
- appendErrorMessage.append(
- UnicodeString("Expected: ") + tuple.toLocalizedPattern + ", got: " + actual + ". ");
- }
- }
- return appendErrorMessage.length() == 0;
-}
-
-UBool NumberFormatTestDataDriven::isParsePass(
- const NumberFormatTestTuple &tuple,
- UnicodeString &appendErrorMessage,
- UErrorCode &status) {
- if (U_FAILURE(status)) {
- return FALSE;
- }
- LocalPointer<DecimalFormat> fmtPtr(newDecimalFormat(tuple, status));
- if (U_FAILURE(status)) {
- appendErrorMessage.append("Error creating DecimalFormat.");
- return FALSE;
- }
- adjustDecimalFormat(tuple, *fmtPtr, appendErrorMessage);
- if (appendErrorMessage.length() > 0) {
- return FALSE;
- }
- Formattable result;
- ParsePosition ppos;
- fmtPtr->parse(tuple.parse, result, ppos);
- if (ppos.getIndex() == 0) {
- if (tuple.output != "fail") {
- appendErrorMessage.append("Parse failed but was expected to succeed.");
- return FALSE;
- }
- return TRUE;
- }
- UnicodeString resultStr(UnicodeString::fromUTF8(result.getDecimalNumber(status)));
- if (tuple.output == "fail") {
- appendErrorMessage.append(UnicodeString("Parse succeeded: ") + resultStr + ", but was expected to fail.");
- return FALSE;
- }
- DigitList expected;
- strToDigitList(tuple.output, expected, status);
- if (U_FAILURE(status)) {
- appendErrorMessage.append("Error parsing.");
- return FALSE;
- }
- if (expected != *result.getDigitList()) {
- appendErrorMessage.append(
- UnicodeString("Expected: ") + tuple.output + ", got: " + resultStr + ". ");
- return FALSE;
- }
- return TRUE;
+#endif
+#if defined(isinf)
+#undef isinf
+namespace std {
+ bool isinf(double x) {
+ return _isinf(x);
+ }
}
+#endif
+#endif
-UBool NumberFormatTestDataDriven::isParseCurrencyPass(
- const NumberFormatTestTuple &tuple,
- UnicodeString &appendErrorMessage,
- UErrorCode &status) {
- if (U_FAILURE(status)) {
- return FALSE;
- }
- LocalPointer<DecimalFormat> fmtPtr(newDecimalFormat(tuple, status));
- if (U_FAILURE(status)) {
- appendErrorMessage.append("Error creating DecimalFormat.");
- return FALSE;
- }
- adjustDecimalFormat(tuple, *fmtPtr, appendErrorMessage);
- if (appendErrorMessage.length() > 0) {
- return FALSE;
- }
- ParsePosition ppos;
- LocalPointer<CurrencyAmount> currAmt(
- fmtPtr->parseCurrency(tuple.parse, ppos));
- if (ppos.getIndex() == 0) {
- if (tuple.output != "fail") {
- appendErrorMessage.append("Parse failed but was expected to succeed.");
- return FALSE;
- }
- return TRUE;
- }
- UnicodeString currStr(currAmt->getISOCurrency());
- Formattable resultFormattable(currAmt->getNumber());
- UnicodeString resultStr(UnicodeString::fromUTF8(resultFormattable.getDecimalNumber(status)));
- if (tuple.output == "fail") {
- appendErrorMessage.append(UnicodeString("Parse succeeded: ") + resultStr + ", but was expected to fail.");
- return FALSE;
- }
- DigitList expected;
- strToDigitList(tuple.output, expected, status);
- if (U_FAILURE(status)) {
- appendErrorMessage.append("Error parsing.");
- return FALSE;
- }
- if (expected != *currAmt->getNumber().getDigitList()) {
- appendErrorMessage.append(
- UnicodeString("Expected: ") + tuple.output + ", got: " + resultStr + ". ");
- return FALSE;
- }
- if (currStr != tuple.outputCurrency) {
- appendErrorMessage.append(UnicodeString(
- "Expected currency: ") + tuple.outputCurrency + ", got: " + currStr + ". ");
- return FALSE;
- }
- return TRUE;
-}
+using icu::number::impl::DecimalQuantity;
+using namespace icu::number;
//#define NUMFMTST_CACHE_DEBUG 1
#include "stdio.h" /* for sprintf */
TESTCASE_AUTO(TestCurrencyAmount);
TESTCASE_AUTO(TestCurrencyUnit);
TESTCASE_AUTO(TestCoverage);
+ //TESTCASE_AUTO(TestLocalizedPatternSymbolCoverage);
TESTCASE_AUTO(TestJB3832);
TESTCASE_AUTO(TestHost);
TESTCASE_AUTO(TestHostClone);
TESTCASE_AUTO(TestSpaceParsing);
TESTCASE_AUTO(TestMultiCurrencySign);
TESTCASE_AUTO(TestCurrencyFormatForMixParsing);
+ //TESTCASE_AUTO(TestMismatchedCurrencyFormatFail);
TESTCASE_AUTO(TestDecimalFormatCurrencyParse);
TESTCASE_AUTO(TestCurrencyIsoPluralFormat);
TESTCASE_AUTO(TestCurrencyParsing);
TESTCASE_AUTO(TestFieldPositionIterator);
TESTCASE_AUTO(TestDecimal);
TESTCASE_AUTO(TestCurrencyFractionDigits);
- TESTCASE_AUTO(TestExponentParse);
- TESTCASE_AUTO(TestExplicitParents);
+ TESTCASE_AUTO(TestExponentParse);
+ TESTCASE_AUTO(TestExplicitParents);
TESTCASE_AUTO(TestLenientParse);
TESTCASE_AUTO(TestAvailableNumberingSystems);
TESTCASE_AUTO(TestRoundingPattern);
TESTCASE_AUTO(TestAccountingCurrency);
TESTCASE_AUTO(TestEquality);
TESTCASE_AUTO(TestCurrencyUsage);
- TESTCASE_AUTO(TestNumberFormatTestTuple);
- TESTCASE_AUTO(TestDataDriven);
TESTCASE_AUTO(TestDoubleLimit11439);
- TESTCASE_AUTO(TestFastPathConsistent11524);
TESTCASE_AUTO(TestGetAffixes);
TESTCASE_AUTO(TestToPatternScientific11648);
TESTCASE_AUTO(TestBenchmark);
TESTCASE_AUTO(TestFractionalDigitsForCurrency);
TESTCASE_AUTO(TestFormatCurrencyPlural);
TESTCASE_AUTO(Test11868);
+ TESTCASE_AUTO(Test11739_ParseLongCurrency);
+ //TESTCASE_AUTO(Test13035_MultiCodePointPaddingInPattern);
+ TESTCASE_AUTO(Test13737_ParseScientificStrict);
TESTCASE_AUTO(Test10727_RoundingZero);
TESTCASE_AUTO(Test11376_getAndSetPositivePrefix);
TESTCASE_AUTO(Test11475_signRecognition);
TESTCASE_AUTO(Test11640_getAffixes);
TESTCASE_AUTO(Test11649_toPatternWithMultiCurrency);
+ TESTCASE_AUTO(Test13327_numberingSystemBufferOverflow);
+ TESTCASE_AUTO(Test13391_chakmaParsing);
+ TESTCASE_AUTO(Test11735_ExceptionIssue);
+ TESTCASE_AUTO(Test11035_FormatCurrencyAmount);
+ TESTCASE_AUTO(Test11318_DoubleConversion);
+ TESTCASE_AUTO(TestParsePercentRegression);
+ TESTCASE_AUTO(TestMultiplierWithScale);
+ TESTCASE_AUTO(TestFastFormatInt32);
+ TESTCASE_AUTO(Test11646_Equality);
+ TESTCASE_AUTO(TestParseNaN);
+ TESTCASE_AUTO(Test11897_LocalizedPatternSeparator);
+ TESTCASE_AUTO(Test13055_PercentageRounding);
+ TESTCASE_AUTO(Test11839);
+ TESTCASE_AUTO(Test10354);
+ TESTCASE_AUTO(Test11645_ApplyPatternEquality);
+ TESTCASE_AUTO(Test12567);
+ TESTCASE_AUTO(Test11626_CustomizeCurrencyPluralInfo);
+ TESTCASE_AUTO(Test13056_GroupingSize);
+ TESTCASE_AUTO(Test11025_CurrencyPadding);
+ TESTCASE_AUTO(Test11648_ExpDecFormatMalPattern);
+ //TESTCASE_AUTO(Test11649_DecFmtCurrencies);
+ TESTCASE_AUTO(Test13148_ParseGroupingSeparators);
+ TESTCASE_AUTO(Test12753_PatternDecimalPoint);
+ TESTCASE_AUTO(Test11647_PatternCurrencySymbols);
+ TESTCASE_AUTO(Test11913_BigDecimal);
+ TESTCASE_AUTO(Test11020_RoundingInScientificNotation);
+ TESTCASE_AUTO(Test11640_TripleCurrencySymbol);
+ TESTCASE_AUTO(Test13763_FieldPositionIteratorOffset);
+ TESTCASE_AUTO(Test13777_ParseLongNameNonCurrencyMode);
+ TESTCASE_AUTO(Test13804_EmptyStringsWhenParsing);
TESTCASE_AUTO_END;
}
}
if(test != NULL) {
test->setMinimumIntegerDigits(10);
- test->setMaximumIntegerDigits(2);
+ test->setMaximumIntegerDigits(1);
test->setMinimumFractionDigits(10);
- test->setMaximumFractionDigits(2);
+ test->setMaximumFractionDigits(1);
UnicodeString result;
FieldPosition pos;
result.remove();
int64_t ll = 12;
test->format(ll, result);
- if (result != "12.00"){
- errln("format int64_t error");
- }
+ assertEquals("format int64_t error", u"2.0", result);
+
+ test->setMinimumIntegerDigits(4);
+ test->setMinimumFractionDigits(4);
+
+ result.remove();
+ test->format(ll, result);
+ assertEquals("format int64_t error", u"0,012.0000", result);
ParsePosition ppos;
LocalPointer<CurrencyAmount> currAmt(test->parseCurrency("",ppos));
};
}
+void NumberFormatTest::TestLocalizedPatternSymbolCoverage() {
+ IcuTestErrorCode errorCode(*this, "TestLocalizedPatternSymbolCoverage");
+ // Ticket #12961: DecimalFormat::toLocalizedPattern() is not working as designed.
+ DecimalFormatSymbols dfs(errorCode);
+ dfs.setSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol, u'⁖');
+ dfs.setSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol, u'⁘');
+ dfs.setSymbol(DecimalFormatSymbols::kPatternSeparatorSymbol, u'⁙');
+ dfs.setSymbol(DecimalFormatSymbols::kDigitSymbol, u'▰');
+ dfs.setSymbol(DecimalFormatSymbols::kZeroDigitSymbol, u'໐');
+ dfs.setSymbol(DecimalFormatSymbols::kSignificantDigitSymbol, u'⁕');
+ dfs.setSymbol(DecimalFormatSymbols::kPlusSignSymbol, u'†');
+ dfs.setSymbol(DecimalFormatSymbols::kMinusSignSymbol, u'‡');
+ dfs.setSymbol(DecimalFormatSymbols::kPercentSymbol, u'⁜');
+ dfs.setSymbol(DecimalFormatSymbols::kPerMillSymbol, u'‱');
+ dfs.setSymbol(DecimalFormatSymbols::kExponentialSymbol, u"⁑⁑"); // tests multi-char sequence
+ dfs.setSymbol(DecimalFormatSymbols::kPadEscapeSymbol, u'⁂');
+
+ {
+ UnicodeString standardPattern(u"#,##0.05+%;#,##0.05-%");
+ UnicodeString localizedPattern(u"▰⁖▰▰໐⁘໐໕†⁜⁙▰⁖▰▰໐⁘໐໕‡⁜");
+
+ DecimalFormat df1("#", new DecimalFormatSymbols(dfs), errorCode);
+ df1.applyPattern(standardPattern, errorCode);
+ DecimalFormat df2("#", new DecimalFormatSymbols(dfs), errorCode);
+ df2.applyLocalizedPattern(localizedPattern, errorCode);
+ assertTrue("DecimalFormat instances should be equal", df1 == df2);
+ UnicodeString p2;
+ assertEquals("toPattern should match on localizedPattern instance",
+ standardPattern, df2.toPattern(p2));
+ UnicodeString lp1;
+ assertEquals("toLocalizedPattern should match on standardPattern instance",
+ localizedPattern, df1.toLocalizedPattern(lp1));
+ }
+
+ {
+ UnicodeString standardPattern(u"* @@@E0‰");
+ UnicodeString localizedPattern(u"⁂ ⁕⁕⁕⁑⁑໐‱");
+
+ DecimalFormat df1("#", new DecimalFormatSymbols(dfs), errorCode);
+ df1.applyPattern(standardPattern, errorCode);
+ DecimalFormat df2("#", new DecimalFormatSymbols(dfs), errorCode);
+ df2.applyLocalizedPattern(localizedPattern, errorCode);
+ assertTrue("DecimalFormat instances should be equal", df1 == df2);
+ UnicodeString p2;
+ assertEquals("toPattern should match on localizedPattern instance",
+ standardPattern, df2.toPattern(p2));
+ UnicodeString lp1;
+ assertEquals("toLocalizedPattern should match on standardPattern instance",
+ localizedPattern, df1.toLocalizedPattern(lp1));
+ }
+}
+
// Test various patterns
void
NumberFormatTest::TestPatterns(void)
const char* pat[] = { "#.#", "#.", ".#", "#" };
int32_t pat_length = UPRV_LENGTHOF(pat);
- const char* newpat[] = { "#0.#", "#0.", "#.0", "#" };
+ const char* newpat[] = { "#0.#", "#0.", "#.0", "#" }; // use ICU 61 behavior
const char* num[] = { "0", "0.", ".0", "0" };
for (int32_t i=0; i<pat_length; ++i)
{
#endif
}
else {
- errln((UnicodeString)"FAIL: Non-numeric Formattable returned");
+ errln(UnicodeString("FAIL: Non-numeric Formattable returned: ") + pattern + " " + s);
continue;
}
if (pos.getIndex() == s.length())
(uprv_fabs(a - valParse[v+ival]) / a > (2*DBL_EPSILON))) ||
(!useEpsilon && a != valParse[v+ival]))
{
- errln((UnicodeString)"FAIL: Expected " + valParse[v+ival]);
+ errln((UnicodeString)"FAIL: Expected " + valParse[v+ival] + " but got " + a
+ + " on input " + s);
}
}
else {
{
logln((UnicodeString)" -parse-> " + a);
if (a != lvalParse[v+ilval])
- errln((UnicodeString)"FAIL: Expected " + lvalParse[v+ilval]);
+ errln((UnicodeString)"FAIL: Expected " + lvalParse[v+ilval] + " but got " + a);
}
else
errln((UnicodeString)"FAIL: Partial parse (" + pos.getIndex() + " chars) -> " + a);
// jb 2552
UErrorCode status = U_ZERO_ERROR;
DecimalFormat fmt("##0.00E0",status);
- if (U_SUCCESS(status)) {
+ if (assertSuccess("", status, true, __FILE__, __LINE__)) {
expect(fmt, .01234, "12.3E-3");
expect(fmt, .1234, "123E-3");
expect(fmt, 1.234, "1.23E0");
UnicodeString s; currencyFmt->format(1.50, s);
logln((UnicodeString)"Un pauvre ici a..........." + s);
if (!(s==CharsToUnicodeString("1,50\\u00A0$")))
- errln((UnicodeString)"FAIL: Expected 1,50<nbsp>$");
+ errln((UnicodeString)"FAIL: Expected 1,50<nbsp>$ but got " + s);
delete currencyFmt;
s.truncate(0);
char loc[256]={0};
currencyFmt->format(1.50, s);
logln((UnicodeString)"Un pauvre en Allemagne a.." + s);
if (!(s==CharsToUnicodeString("1,50\\u00A0DM")))
- errln((UnicodeString)"FAIL: Expected 1,50<nbsp>DM");
+ errln((UnicodeString)"FAIL: Expected 1,50<nbsp>DM but got " + s);
delete currencyFmt;
s.truncate(0);
len = uloc_canonicalize("fr_FR_PREEURO", loc, 256, &status);
1234.56, CharsToUnicodeString("\\u00A51,235")); // Yen
expectCurrency(*fmt, Locale("fr", "CH", ""),
- 1234.56, "CHF1,234.56"); // no more 0.05 rounding here, see cldrbug 5548
+ 1234.56, "CHF1,234.56"); // no more 0.05 rounding here, see cldrbug 5548 // use ICU 61 behavior
expectCurrency(*fmt, Locale::getUS(),
1234.56, "$1,234.56");
static const char *lenientMinusTestCases[] = {
"-5",
"\\u22125",
- "\\u20105"
+ "\\u27965"
};
static const char *lenientCurrencyTestCases[] = {
if (U_FAILURE(status) || n.getType() != Formattable::kLong ||
n.getLong() != 1) {
- errln((UnicodeString)"Lenient parse failed for \"" + (UnicodeString) lenientAffixTestCases[t] + (UnicodeString) "\"");
+ dataerrln((UnicodeString)"Lenient parse failed for \"" + (UnicodeString) lenientAffixTestCases[t]
+ + (UnicodeString) "\"; error code = " + u_errorName(status));
status = U_ZERO_ERROR;
}
}
Locale en_US("en_US");
Locale sv_SE("sv_SE");
-
+
NumberFormat *mFormat = NumberFormat::createInstance(sv_SE, UNUM_DECIMAL, status);
-
+
if (mFormat == NULL || U_FAILURE(status)) {
dataerrln("Unable to create NumberFormat (sv_SE, UNUM_DECIMAL) - %s", u_errorName(status));
} else {
mFormat->setLenient(TRUE);
for (int32_t t = 0; t < UPRV_LENGTHOF(lenientMinusTestCases); t += 1) {
UnicodeString testCase = ctou(lenientMinusTestCases[t]);
-
+
mFormat->parse(testCase, n, status);
logln((UnicodeString)"parse(" + testCase + ") = " + n.getLong());
-
+
if (U_FAILURE(status) || n.getType() != Formattable::kLong || n.getLong() != -5) {
- errln((UnicodeString)"Lenient parse failed for \"" + (UnicodeString) lenientMinusTestCases[t] + (UnicodeString) "\"");
+ errln((UnicodeString)"Lenient parse failed for \"" + (UnicodeString) lenientMinusTestCases[t]
+ + (UnicodeString) "\"; error code = " + u_errorName(status));
status = U_ZERO_ERROR;
}
}
delete mFormat;
}
-
+
mFormat = NumberFormat::createInstance(en_US, UNUM_DECIMAL, status);
-
+
if (mFormat == NULL || U_FAILURE(status)) {
dataerrln("Unable to create NumberFormat (en_US, UNUM_DECIMAL) - %s", u_errorName(status));
} else {
mFormat->setLenient(TRUE);
for (int32_t t = 0; t < UPRV_LENGTHOF(lenientMinusTestCases); t += 1) {
UnicodeString testCase = ctou(lenientMinusTestCases[t]);
-
+
mFormat->parse(testCase, n, status);
logln((UnicodeString)"parse(" + testCase + ") = " + n.getLong());
-
+
if (U_FAILURE(status) || n.getType() != Formattable::kLong || n.getLong() != -5) {
- errln((UnicodeString)"Lenient parse failed for \"" + (UnicodeString) lenientMinusTestCases[t] + (UnicodeString) "\"");
+ errln((UnicodeString)"Lenient parse failed for \"" + (UnicodeString) lenientMinusTestCases[t]
+ + (UnicodeString) "\"; error code = " + u_errorName(status));
status = U_ZERO_ERROR;
}
}
delete mFormat;
}
-
+
NumberFormat *cFormat = NumberFormat::createInstance(en_US, UNUM_CURRENCY, status);
if (cFormat == NULL || U_FAILURE(status)) {
if (U_FAILURE(status) ||n.getType() != Formattable::kLong ||
n.getLong() != 1000) {
- errln((UnicodeString)"Lenient parse failed for \"" + (UnicodeString) lenientCurrencyTestCases[t] + (UnicodeString) "\"");
+ errln((UnicodeString)"Lenient parse failed for \"" + (UnicodeString) lenientCurrencyTestCases[t]
+ + (UnicodeString) "\"; error code = " + u_errorName(status));
status = U_ZERO_ERROR;
}
}
if (U_FAILURE(status) ||n.getType() != Formattable::kLong ||
n.getLong() != -1000) {
- errln((UnicodeString)"Lenient parse failed for \"" + (UnicodeString) lenientNegativeCurrencyTestCases[t] + (UnicodeString) "\"");
+ errln((UnicodeString)"Lenient parse failed for \"" + (UnicodeString) lenientNegativeCurrencyTestCases[t]
+ + (UnicodeString) "\"; error code = " + u_errorName(status));
status = U_ZERO_ERROR;
}
}
if (U_FAILURE(status) ||n.getType() != Formattable::kDouble ||
n.getDouble() != 0.25) {
- errln((UnicodeString)"Lenient parse failed for \"" + (UnicodeString) lenientPercentTestCases[t] + (UnicodeString) "\"");
+ errln((UnicodeString)"Lenient parse failed for \"" + (UnicodeString) lenientPercentTestCases[t]
+ + (UnicodeString) "\"; error code = " + u_errorName(status)
+ + "; got: " + n.getDouble(status));
status = U_ZERO_ERROR;
}
}
if (U_FAILURE(status) ||n.getType() != Formattable::kDouble ||
n.getDouble() != -0.25) {
- errln((UnicodeString)"Lenient parse failed for \"" + (UnicodeString) lenientNegativePercentTestCases[t] + (UnicodeString) "\"");
+ errln((UnicodeString)"Lenient parse failed for \"" + (UnicodeString) lenientNegativePercentTestCases[t]
+ + (UnicodeString) "\"; error code = " + u_errorName(status)
+ + "; got: " + n.getDouble(status));
status = U_ZERO_ERROR;
}
}
// Test cases that should fail with a strict parse and pass with a
// lenient parse.
NumberFormat *nFormat = NumberFormat::createInstance(en_US, status);
-
+
if (nFormat == NULL || U_FAILURE(status)) {
dataerrln("Unable to create NumberFormat (en_US) - %s", u_errorName(status));
- } else {
+ } else {
// first, make sure that they fail with a strict parse
for (int32_t t = 0; t < UPRV_LENGTHOF(strictFailureTestCases); t += 1) {
UnicodeString testCase = ctou(strictFailureTestCases[t]);
logln((UnicodeString)"parse(" + testCase + ") = " + n.getLong());
if (! U_FAILURE(status)) {
- errln((UnicodeString)"Strict Parse succeeded for \"" + (UnicodeString) strictFailureTestCases[t] + (UnicodeString) "\"");
+ errln((UnicodeString)"Strict Parse succeeded for \"" + (UnicodeString) strictFailureTestCases[t]
+ + (UnicodeString) "\"; error code = " + u_errorName(status));
}
status = U_ZERO_ERROR;
if (U_FAILURE(status) ||n.getType() != Formattable::kLong ||
n.getLong() != 1000) {
- errln((UnicodeString)"Lenient parse failed for \"" + (UnicodeString) strictFailureTestCases[t] + (UnicodeString) "\"");
+ errln((UnicodeString)"Lenient parse failed for \"" + (UnicodeString) strictFailureTestCases[t]
+ + (UnicodeString) "\"; error code = " + u_errorName(status));
status = U_ZERO_ERROR;
}
}
CHECK(status, "DecimalFormat ct");
expect2(f, (int32_t)123456789L, "12,34,56,789");
- expectPat(f, "#,##,###");
+ expectPat(f, "#,##,###"); // use ICU 61 behavior
f.applyPattern("#,###", status);
CHECK(status, "applyPattern");
f.setSecondaryGroupingSize(4);
expect2(f, (int32_t)123456789L, "12,3456,789");
- expectPat(f, "#,####,###");
+ expectPat(f, "#,####,###"); // use ICU 61 behavior
NumberFormat *g = NumberFormat::createInstance(Locale("hi", "IN"), status);
CHECK_DATA(status, "createInstance(hi_IN)");
errcheckln(ec, "FAIL: Constructor - %s", u_errorName(ec));
return;
}
+ // From ICU 62, flexible whitespace needs lenient mode
+ fmt.setLenient(TRUE);
int32_t n = 1234;
expect(fmt, "a b1234c ", n);
expect(fmt, "a b1234c ", n);
int32_t PAT_length = UPRV_LENGTHOF(PAT);
int32_t DIGITS[] = {
// min int, max int, min frac, max frac
- 0, 1, 0, 0, // "#E0"
+ 0, 1, 0, 0, // "#E0" // expect ICU 61 behavior
1, 1, 0, 4, // "0.####E0"
2, 2, 3, 3, // "00.000E00"
1, 3, 0, 4, // "##0.####E000"
fmt.setFormatWidth(16);
// 12 34567890123456
- expectPat(fmt, "AA*^#,###,##0.00ZZ");
+ expectPat(fmt, "AA*^#,###,##0.00ZZ"); // use ICU 61 behavior
}
void NumberFormatTest::TestSurrogateSupport(void) {
const UBool possibleDataError = TRUE;
// Warning: HARD-CODED LOCALE DATA in this test. If it fails, CHECK
// THE LOCALE DATA before diving into the code.
- assertEquals("USD.getName(SYMBOL_NAME)",
+ assertEquals("USD.getName(SYMBOL_NAME, en)",
UnicodeString("$"),
UnicodeString(ucurr_getName(USD, "en",
UCURR_SYMBOL_NAME,
&isChoiceFormat, &len, &ec)),
possibleDataError);
- assertEquals("USD.getName(LONG_NAME)",
+ assertEquals("USD.getName(NARROW_SYMBOL_NAME, en)",
+ UnicodeString("$"),
+ UnicodeString(ucurr_getName(USD, "en",
+ UCURR_NARROW_SYMBOL_NAME,
+ &isChoiceFormat, &len, &ec)),
+ possibleDataError);
+ assertEquals("USD.getName(LONG_NAME, en)",
UnicodeString("US Dollar"),
UnicodeString(ucurr_getName(USD, "en",
UCURR_LONG_NAME,
&isChoiceFormat, &len, &ec)),
possibleDataError);
- assertEquals("CAD.getName(SYMBOL_NAME)",
+ assertEquals("CAD.getName(SYMBOL_NAME, en)",
UnicodeString("CA$"),
UnicodeString(ucurr_getName(CAD, "en",
UCURR_SYMBOL_NAME,
&isChoiceFormat, &len, &ec)),
possibleDataError);
- assertEquals("CAD.getName(SYMBOL_NAME)",
+ assertEquals("CAD.getName(NARROW_SYMBOL_NAME, en)",
+ UnicodeString("$"),
+ UnicodeString(ucurr_getName(CAD, "en",
+ UCURR_NARROW_SYMBOL_NAME,
+ &isChoiceFormat, &len, &ec)),
+ possibleDataError);
+ assertEquals("CAD.getName(SYMBOL_NAME, en_CA)",
UnicodeString("$"),
UnicodeString(ucurr_getName(CAD, "en_CA",
UCURR_SYMBOL_NAME,
&isChoiceFormat, &len, &ec)),
possibleDataError);
+ assertEquals("USD.getName(SYMBOL_NAME, en_CA)",
+ UnicodeString("US$"),
+ UnicodeString(ucurr_getName(USD, "en_CA",
+ UCURR_SYMBOL_NAME,
+ &isChoiceFormat, &len, &ec)),
+ possibleDataError);
+ assertEquals("USD.getName(NARROW_SYMBOL_NAME, en_CA)",
+ UnicodeString("$"),
+ UnicodeString(ucurr_getName(USD, "en_CA",
+ UCURR_NARROW_SYMBOL_NAME,
+ &isChoiceFormat, &len, &ec)),
+ possibleDataError);
assertEquals("USD.getName(SYMBOL_NAME) in en_NZ",
UnicodeString("US$"),
UnicodeString(ucurr_getName(USD, "en_NZ",
UCURR_SYMBOL_NAME,
&isChoiceFormat, &len, &ec)),
possibleDataError);
+ assertEquals("USX.getName(SYMBOL_NAME)",
+ UnicodeString("USX"),
+ UnicodeString(ucurr_getName(USX, "en_US",
+ UCURR_SYMBOL_NAME,
+ &isChoiceFormat, &len, &ec)),
+ possibleDataError);
+ assertEquals("USX.getName(NARROW_SYMBOL_NAME)",
+ UnicodeString("USX"),
+ UnicodeString(ucurr_getName(USX, "en_US",
+ UCURR_NARROW_SYMBOL_NAME,
+ &isChoiceFormat, &len, &ec)),
+ possibleDataError);
assertEquals("USX.getName(LONG_NAME)",
UnicodeString("USX"),
UnicodeString(ucurr_getName(USX, "en_US",
void NumberFormatTest::TestCurrencyUnit(void){
UErrorCode ec = U_ZERO_ERROR;
- static const UChar USD[] = {85, 83, 68, 0}; /*USD*/
- static const UChar BAD[] = {63, 63, 63, 0}; /*???*/
- static const UChar BAD2[] = {63, 63, 65, 0}; /*???*/
+ static const UChar USD[] = u"USD";
+ static const char USD8[] = "USD";
+ static const UChar BAD[] = u"???";
+ static const UChar BAD2[] = u"??A";
+ static const UChar XXX[] = u"XXX";
+ static const char XXX8[] = "XXX";
CurrencyUnit cu(USD, ec);
assertSuccess("CurrencyUnit", ec);
- const UChar * r = cu.getISOCurrency(); // who is the buffer owner ?
- assertEquals("getISOCurrency()", USD, r);
+ assertEquals("getISOCurrency()", USD, cu.getISOCurrency());
+ assertEquals("getSubtype()", USD8, cu.getSubtype());
CurrencyUnit cu2(cu);
if (!(cu2 == cu)){
errln("Currency unit assignment should be the same.");
}
delete cu3;
+
+ // Test default constructor
+ CurrencyUnit def;
+ assertEquals("Default currency", XXX, def.getISOCurrency());
+ assertEquals("Default currency as subtype", XXX8, def.getSubtype());
+
+ // Test slicing
+ MeasureUnit sliced1 = cu;
+ MeasureUnit sliced2 = cu;
+ assertEquals("Subtype after slicing 1", USD8, sliced1.getSubtype());
+ assertEquals("Subtype after slicing 2", USD8, sliced2.getSubtype());
+ CurrencyUnit restored1(sliced1, ec);
+ CurrencyUnit restored2(sliced2, ec);
+ assertSuccess("Restoring from MeasureUnit", ec);
+ assertEquals("Subtype after restoring 1", USD8, restored1.getSubtype());
+ assertEquals("Subtype after restoring 2", USD8, restored2.getSubtype());
+ assertEquals("ISO Code after restoring 1", USD, restored1.getISOCurrency());
+ assertEquals("ISO Code after restoring 2", USD, restored2.getISOCurrency());
+
+ // Test copy constructor failure
+ LocalPointer<MeasureUnit> meter(MeasureUnit::createMeter(ec));
+ assertSuccess("Creating meter", ec);
+ CurrencyUnit failure(*meter, ec);
+ assertEquals("Copying from meter should fail", ec, U_ILLEGAL_ARGUMENT_ERROR);
+ assertEquals("Copying should not give uninitialized ISO code", u"", failure.getISOCurrency());
}
void NumberFormatTest::TestCurrencyAmount(void){
UnicodeString intlCurrencySymbol((UChar)0xa4);
intlCurrencySymbol.append((UChar)0xa4);
-
+
logln("Current locale is %s", Locale::getDefault().getName());
Locale::setDefault(locBad, status);
logln("Current locale is %s", Locale::getDefault().getName());
DecimalFormat fmt(ctou("###.###\\u2030"), ec);
if (!assertSuccess("DecimalFormat ct", ec)) return;
assertEquals("0.4857 x ###.###\\u2030",
- ctou("485.7\\u2030"), fmt.format(0.4857, str));
+ ctou("485.7\\u2030"), fmt.format(0.4857, str), true);
DecimalFormatSymbols sym(Locale::getUS(), ec);
+ if (!assertSuccess("", ec, true, __FILE__, __LINE__)) {
+ return;
+ }
sym.setSymbol(DecimalFormatSymbols::kPerMillSymbol, ctou("m"));
DecimalFormat fmt2("", sym, ec);
+ if (!assertSuccess("", ec, true, __FILE__, __LINE__)) {
+ return;
+ }
fmt2.applyLocalizedPattern("###.###m", ec);
if (!assertSuccess("setup", ec)) return;
str.truncate(0);
expectParseCurrency(*fmtJP, JPY, 1235, "\\u00A51,235");
logln("%s:%d - testing parse of fullwidth yen sign in JP\n", __FILE__, __LINE__);
expectParseCurrency(*fmtJP, JPY, 1235, "\\uFFE51,235");
-
+
// more..
*/
}
fmt.getLocale(ULOC_ACTUAL_LOCALE, status).getBaseName(),
text);
u_austrcpy(theInfo+uprv_strlen(theInfo), currency);
-
+
char theOperation[100];
uprv_strcpy(theOperation, theInfo);
uprv_strcat(theOperation, ", check currency:");
assertEquals(theOperation, currency, currencyAmount->getISOCurrency());
}
-
+
void NumberFormatTest::TestJB3832(){
const char* localeID = "pt_PT@currency=PTE";
foo->setLenient(DATA[i].lenient);
Formattable result;
foo->parse(stringToBeParsed, result, parsePosition);
+ logln("Parsing: " + stringToBeParsed);
if (parsePosition.getIndex() != parsedPosition ||
parsePosition.getErrorIndex() != errorIndex) {
errln("FAILED parse " + stringToBeParsed + "; lenient: " + DATA[i].lenient + "; wrong position, expected: (" + parsedPosition + ", " + errorIndex + "); got (" + parsePosition.getIndex() + ", " + parsePosition.getErrorIndex() + ")");
NumberFormat *fmt = (NumberFormat *) origFmt->clone();
delete origFmt;
-
+
if (item->isRBNF) {
expect3(*fmt,item->value,CharsToUnicodeString(item->expectedResult));
} else {
"$1,234.56", // string to be parsed
"USD1,234.56",
"US dollars1,234.56",
- "1,234.56 US dollars"
+ // "1,234.56 US dollars" // Fails in 62 because currency format is not compatible with pattern.
};
const CurrencyAmount* curramt = NULL;
for (uint32_t i = 0; i < UPRV_LENGTHOF(formats); ++i) {
}
+/** Starting in ICU 62, strict mode is actually strict with currency formats. */
+void NumberFormatTest::TestMismatchedCurrencyFormatFail() {
+ IcuTestErrorCode status(*this, "TestMismatchedCurrencyFormatFail");
+ LocalPointer<DecimalFormat> df(
+ dynamic_cast<DecimalFormat*>(DecimalFormat::createCurrencyInstance("en", status)), status);
+ if (!assertSuccess("createCurrencyInstance() failed.", status, true, __FILE__, __LINE__)) {return;}
+ UnicodeString pattern;
+ assertEquals("Test assumes that currency sign is at the beginning",
+ u"\u00A4#,##0.00",
+ df->toPattern(pattern));
+ // Should round-trip on the correct currency format:
+ expect2(*df, 1.23, u"XXX\u00A01.23");
+ df->setCurrency(u"EUR", status);
+ expect2(*df, 1.23, u"\u20AC1.23");
+ // Should parse with currency in the wrong place in lenient mode
+ df->setLenient(TRUE);
+ expect(*df, u"1.23\u20AC", 1.23);
+ expectParseCurrency(*df, u"EUR", 1.23, "1.23\\u20AC");
+ // Should NOT parse with currency in the wrong place in STRICT mode
+ df->setLenient(FALSE);
+ {
+ Formattable result;
+ ErrorCode failStatus;
+ df->parse(u"1.23\u20AC", result, failStatus);
+ assertEquals("Should fail to parse", U_INVALID_FORMAT_ERROR, failStatus);
+ }
+ {
+ ParsePosition ppos;
+ df->parseCurrency(u"1.23\u20AC", ppos);
+ assertEquals("Should fail to parse currency", 0, ppos.getIndex());
+ }
+}
+
+
void
NumberFormatTest::TestDecimalFormatCurrencyParse() {
// Locale.US
{"USD1,234.56", "1234.56"},
{"1,234.56 US dollar", "1234.56"},
};
+ // NOTE: ICU 62 requires that the currency format match the pattern in strict mode.
+ fmt->setLenient(TRUE);
for (uint32_t i = 0; i < UPRV_LENGTHOF(DATA); ++i) {
UnicodeString stringToBeParsed = ctou(DATA[i][0]);
double parsedResult = atof(DATA[i][1]);
UErrorCode status = U_ZERO_ERROR;
Formattable result;
fmt->parse(stringToBeParsed, result, status);
+ logln((UnicodeString)"Input: " + stringToBeParsed + "; output: " + result.getDouble(status));
if (U_FAILURE(status) ||
(result.getType() == Formattable::kDouble &&
result.getDouble() != parsedResult) ||
};
for (int32_t i=0; i<UPRV_LENGTHOF(DATA); ++i) {
+ const char* localeString = DATA[i][0];
+ double numberToBeFormat = atof(DATA[i][1]);
+ const char* currencyISOCode = DATA[i][2];
+ logln(UnicodeString(u"Locale: ") + localeString + "; amount: " + numberToBeFormat);
+ Locale locale(localeString);
for (int32_t kIndex = 0; kIndex < UPRV_LENGTHOF(currencyStyles); ++kIndex) {
UNumberFormatStyle k = currencyStyles[kIndex];
- const char* localeString = DATA[i][0];
- double numberToBeFormat = atof(DATA[i][1]);
- const char* currencyISOCode = DATA[i][2];
- Locale locale(localeString);
+ logln(UnicodeString(u"UNumberFormatStyle: ") + k);
UErrorCode status = U_ZERO_ERROR;
NumberFormat* numFmt = NumberFormat::createInstance(locale, k, status);
if (U_FAILURE(status)) {
errln("FAIL: Expected " + formatResult + " actual: " + strBuf);
}
// test parsing, and test parsing for all currency formats.
+ // NOTE: ICU 62 requires that the currency format match the pattern in strict mode.
+ numFmt->setLenient(TRUE);
for (int j = 3; j < 6; ++j) {
// DATA[i][3] is the currency format result using
// CURRENCYSTYLE formatter.
// format result using CURRENCYSTYLE,
// format result using ISOCURRENCYSTYLE,
// format result using PLURALCURRENCYSTYLE,
- {"en_US", "1", "USD", "$1.00", "USD1.00", "1.00 US dollar"},
+ {"en_US", "1", "USD", "$1.00", "USD\\u00A01.00", "1.00 US dollars"},
{"pa_IN", "1", "USD", "US$\\u00A01.00", "USD\\u00A01.00", "1.00 \\u0a2f\\u0a42.\\u0a10\\u0a38. \\u0a21\\u0a3e\\u0a32\\u0a30"},
{"es_AR", "1", "USD", "US$\\u00A01,00", "USD\\u00A01,00", "1,00 d\\u00f3lar estadounidense"},
{"ar_EG", "1", "USD", "\\u0661\\u066b\\u0660\\u0660\\u00a0US$", "\\u0661\\u066b\\u0660\\u0660\\u00a0USD", "\\u0661\\u066b\\u0660\\u0660 \\u062f\\u0648\\u0644\\u0627\\u0631 \\u0623\\u0645\\u0631\\u064a\\u0643\\u064a"},
- {"fa_CA", "1", "USD", "\\u06f1\\u066b\\u06f0\\u06f0\\u00a0\\u061c$", "\\u06f1\\u066b\\u06f0\\u06f0\\u00a0\\u061cUSD", "\\u06f1\\u066b\\u06f0\\u06f0 \\u062f\\u0644\\u0627\\u0631 \\u0627\\u0645\\u0631\\u06cc\\u06a9\\u0627"},
+ {"fa_CA", "1", "USD", "\\u200e$\\u06f1\\u066b\\u06f0\\u06f0", "\\u200eUSD\\u06f1\\u066b\\u06f0\\u06f0", "\\u06f1\\u066b\\u06f0\\u06f0 \\u062f\\u0644\\u0627\\u0631 \\u0627\\u0645\\u0631\\u06cc\\u06a9\\u0627"},
{"he_IL", "1", "USD", "\\u200f1.00\\u00a0$", "\\u200f1.00\\u00a0USD", "1.00 \\u05d3\\u05d5\\u05dc\\u05e8 \\u05d0\\u05de\\u05e8\\u05d9\\u05e7\\u05d0\\u05d9"},
- {"hr_HR", "1", "USD", "1,00\\u00a0USD", "1,00\\u00a0USD", "1,00 Ameri\\u010dki dolar"},
- {"id_ID", "1", "USD", "US$1,00", "USD1,00", "1,00 Dolar Amerika Serikat"},
- {"it_IT", "1", "USD", "1,00\\u00a0US$", "1,00\\u00a0USD", "1,00 Dollaro Statunitense"},
- {"ko_KR", "1", "USD", "US$1.00", "USD1.00", "1.00 \\ubbf8\\uad6d \\ub2ec\\ub7ec"},
- {"ja_JP", "1", "USD", "$1.00", "USD1.00", "1.00\\u7c73\\u30c9\\u30eb"},
- {"zh_CN", "1", "CNY", "\\uFFE51.00", "CNY01.00", "1.00\\u4EBA\\u6C11\\u5E01"},
- {"zh_TW", "1", "CNY", "CN\\u00A51.00", "CNY1.00", "1.00 \\u4eba\\u6c11\\u5e63"},
- {"zh_Hant", "1", "CNY", "CN\\u00A51.00", "CNY1.00", "1.00 \\u4eba\\u6c11\\u5e63"},
- {"zh_Hant", "1", "JPY", "\\u00A51.00", "JPY1.00", "1.00 \\u65e5\\u5713"},
- {"ja_JP", "1", "JPY", "\\uFFE51.00", "JPY1.00", "1.00\\u65e5\\u672c\\u5186"},
- {"ja_JP", "1", "JPY", "\\u00A51.00", "JPY1.00", "1.00\\u65e5\\u672c\\u5186"},
- {"ru_RU", "1", "RUB", "1,00\\u00A0\\u20BD", "1,00\\u00A0RUB", "1,00 \\u0420\\u043E\\u0441\\u0441\\u0438\\u0439\\u0441\\u043A\\u0438\\u0439 \\u0440\\u0443\\u0431\\u043B\\u044C"}
+ {"hr_HR", "1", "USD", "1,00\\u00a0USD", "1,00\\u00a0USD", "1,00 ameri\\u010Dkih dolara"},
+ {"id_ID", "1", "USD", "US$\\u00A01,00", "USD\\u00A01,00", "1,00 Dolar Amerika Serikat"},
+ {"it_IT", "1", "USD", "1,00\\u00a0USD", "1,00\\u00a0USD", "1,00 dollari statunitensi"},
+ {"ko_KR", "1", "USD", "US$\\u00A01.00", "USD\\u00A01.00", "1.00 \\ubbf8\\uad6d \\ub2ec\\ub7ec"},
+ {"ja_JP", "1", "USD", "$1.00", "USD\\u00A01.00", "1.00\\u7c73\\u30c9\\u30eb"},
+ {"zh_CN", "1", "CNY", "\\uFFE51.00", "CNY\\u00A001.00", "1.00\\u4EBA\\u6C11\\u5E01"},
+ {"zh_TW", "1", "CNY", "CN\\u00A51.00", "CNY\\u00A01.00", "1.00 \\u4eba\\u6c11\\u5e63"},
+ {"zh_Hant", "1", "CNY", "CN\\u00A51.00", "CNY\\u00A01.00", "1.00 \\u4eba\\u6c11\\u5e63"},
+ {"zh_Hant", "1", "JPY", "\\u00A51.00", "JPY\\u00A01.00", "1 \\u65E5\\u5713"},
+ {"ja_JP", "1", "JPY", "\\uFFE51.00", "JPY\\u00A01.00", "1\\u5186"},
+ // ICU 62 requires #parseCurrency() to recognize variants when parsing
+ // {"ja_JP", "1", "JPY", "\\u00A51.00", "JPY\\u00A01.00", "1\\u00A0\\u5186"},
+ {"ru_RU", "1", "RUB", "1,00\\u00A0\\u00A0\\u20BD", "1,00\\u00A0\\u00A0RUB", "1,00 \\u0440\\u043E\\u0441\\u0441\\u0438\\u0439\\u0441\\u043A\\u043E\\u0433\\u043E \\u0440\\u0443\\u0431\\u043B\\u044F"}
};
static const UNumberFormatStyle currencyStyles[] = {
UNUM_CURRENCY,
UErrorCode status = U_ZERO_ERROR;
NumberFormat* numFmt = NumberFormat::createInstance(locale, k, status);
logln("#%d NumberFormat(%s, %s) Currency=%s\n",
- i, localeString, currencyStyleNames[kIndex],
+ i, localeString, currencyStyleNames[kIndex],
currencyISOCode);
if (U_FAILURE(status)) {
UnicodeString strBuf;
numFmt->format(numberToBeFormat, strBuf);
- /*
int resultDataIndex = 3 + kIndex;
// DATA[i][resultDataIndex] is the currency format result
// using 'k' currency style.
if (strBuf.compare(formatResult)) {
errln("FAIL: Expected " + formatResult + " actual: " + strBuf);
}
- */
// test parsing, and test parsing for all currency formats.
+ // NOTE: ICU 62 requires that the currency format match the pattern in strict mode.
+ numFmt->setLenient(TRUE);
for (int j = 3; j < 6; ++j) {
// DATA[i][3] is the currency format result using
// CURRENCYSTYLE formatter.
"Peruvian soles1.00",
"Peruvian sol (1863\\u20131965)1.00",
"Peruvian soles (1863\\u20131965)1.00",
- "Philippine Peso1.00",
- "Philippine peso1.00",
- "Philippine pesos1.00",
+ "Philippine Piso1.00",
+ "Philippine piso1.00",
+ "Philippine pisos1.00",
"Platinum1.00",
"Platinum1.00",
"Polish Zloty (1950\\u20131995)1.00",
"1.00 Peruvian soles random",
"1.00 Peruvian sol (1863\\u20131965) random",
"1.00 Peruvian soles (1863\\u20131965) random",
- "1.00 Philippine Peso random",
- "1.00 Philippine peso random",
- "1.00 Philippine pesos random",
+ "1.00 Philippine Piso random",
+ "1.00 Philippine piso random",
+ "1.00 Philippine pisos random",
"1.00 Platinum random",
"1.00 Platinum random",
"1.00 Polish Zloty (1950\\u20131995) random",
Locale locale("en_US");
for (uint32_t i=0; i<UPRV_LENGTHOF(DATA); ++i) {
- UnicodeString formatted = ctou(DATA[i]);
- UErrorCode status = U_ZERO_ERROR;
- NumberFormat* numFmt = NumberFormat::createInstance(locale, UNUM_CURRENCY, status);
- if (numFmt != NULL && U_SUCCESS(status)) {
- ParsePosition parsePos;
- LocalPointer<CurrencyAmount> currAmt(numFmt->parseCurrency(formatted, parsePos));
- if (parsePos.getIndex() > 0) {
- double doubleVal = currAmt->getNumber().getDouble(status);
- if ( doubleVal != 1.0 ) {
- errln("Parsed as currency value other than 1.0: " + formatted + " -> " + doubleVal);
- }
- } else {
- errln("Failed to parse as currency: " + formatted);
- }
- } else {
- dataerrln("Unable to create NumberFormat. - %s", u_errorName(status));
- delete numFmt;
- break;
- }
- delete numFmt;
+ UnicodeString formatted = ctou(DATA[i]);
+ UErrorCode status = U_ZERO_ERROR;
+ LocalPointer<NumberFormat> numFmt(NumberFormat::createInstance(locale, UNUM_CURRENCY, status), status);
+ if (!assertSuccess("", status, true, __FILE__, __LINE__)) {
+ return;
+ }
+ // NOTE: ICU 62 requires that the currency format match the pattern in strict mode.
+ numFmt->setLenient(TRUE);
+ ParsePosition parsePos;
+ LocalPointer<CurrencyAmount> currAmt(numFmt->parseCurrency(formatted, parsePos));
+ if (parsePos.getIndex() > 0) {
+ double doubleVal = currAmt->getNumber().getDouble(status);
+ if ( doubleVal != 1.0 ) {
+ errln("Parsed as currency value other than 1.0: " + formatted + " -> " + doubleVal);
+ }
+ } else {
+ errln("Failed to parse as currency: " + formatted);
+ }
}
for (uint32_t i=0; i<UPRV_LENGTHOF(WRONG_DATA); ++i) {
DecimalFormat *decFmt = (DecimalFormat *) NumberFormat::createInstance(locale, UNUM_CURRENCY, status);
if (failure(status, "NumberFormat::createInstance", TRUE)) return;
double val = 12345.67;
-
+
{
int32_t expected[] = {
UNUM_CURRENCY_FIELD, 0, 1,
//
// Test formatting & parsing of big decimals.
-// API test, not a comprehensive test.
+// API test, not a comprehensive test.
// See DecimalFormatTest/DataDrivenTests
//
-#define ASSERT_SUCCESS(status) {if (U_FAILURE(status)) errln("file %s, line %d: status: %s", \
- __FILE__, __LINE__, u_errorName(status));}
-#define ASSERT_EQUALS(expected, actual) {if ((expected) != (actual)) \
- errln("file %s, line %d: %s != %s", __FILE__, __LINE__, #expected, #actual);}
-
-static UBool operator != (const char *s1, UnicodeString &s2) {
- // This function lets ASSERT_EQUALS("literal", UnicodeString) work.
- UnicodeString us1(s1);
- return us1 != s2;
+#define ASSERT_SUCCESS(status) { \
+ assertSuccess(UnicodeString("file ") + __FILE__ + ", line " + __LINE__, (status)); \
+}
+#define ASSERT_EQUALS(expected, actual) { \
+ assertEquals(UnicodeString("file ") + __FILE__ + ", line " + __LINE__, (expected), (actual)); \
}
void NumberFormatTest::TestDecimal() {
ASSERT_SUCCESS(status);
StringPiece s = f.getDecimalNumber(status);
ASSERT_SUCCESS(status);
- ASSERT_EQUALS("1.2345678999987654321E+667", s);
+ ASSERT_EQUALS("1.2345678999987654321E+667", s.data());
//printf("%s\n", s.data());
}
ASSERT_EQUALS(123.45, f.getDouble());
ASSERT_EQUALS(123.45, f.getDouble(status));
ASSERT_SUCCESS(status);
- ASSERT_EQUALS("123.45", f.getDecimalNumber(status));
+ ASSERT_EQUALS("123.45", f.getDecimalNumber(status).data());
ASSERT_SUCCESS(status);
f.setDecimalNumber("4.5678E7", status);
ASSERT_EQUALS(-123, f.getLong());
ASSERT_EQUALS(-123, f.getLong(status));
ASSERT_SUCCESS(status);
- ASSERT_EQUALS("-123", f.getDecimalNumber(status));
+ ASSERT_EQUALS("-123", f.getDecimalNumber(status).data());
ASSERT_SUCCESS(status);
status = U_ZERO_ERROR;
ASSERT_EQUALS(1234567890123LL, f.getInt64());
ASSERT_EQUALS(1234567890123LL, f.getInt64(status));
ASSERT_SUCCESS(status);
- ASSERT_EQUALS("1234567890123", f.getDecimalNumber(status));
+ ASSERT_EQUALS("1234567890123", f.getDecimalNumber(status).data());
ASSERT_SUCCESS(status);
}
Formattable result;
fmtr->parse(input, result, status);
ASSERT_SUCCESS(status);
- ASSERT_EQUALS(0, strcmp("0.0184", result.getDecimalNumber(status).data()));
+ ASSERT_EQUALS("0.0184", result.getDecimalNumber(status).data());
//std::cout << result.getDecimalNumber(status).data();
delete fmtr;
}
}
-
+
#if U_PLATFORM != U_PF_CYGWIN || defined(CYGWINMSVC)
/*
* This test fails on Cygwin (1.7.16) using GCC because of a rounding issue with strtod().
errln((UnicodeString)"NumberFormat::format() should return the same result - text1="
+ text1 + " text2=" + text2);
}
- delete fmt;
}
+ delete fmt;
}
-void NumberFormatTest::TestExponentParse() {
-
- UErrorCode status = U_ZERO_ERROR;
- Formattable result;
- ParsePosition parsePos(0);
-
- // set the exponent symbol
- status = U_ZERO_ERROR;
- DecimalFormatSymbols *symbols = new DecimalFormatSymbols(Locale::getDefault(), status);
- if(U_FAILURE(status)) {
- dataerrln((UnicodeString)"ERROR: Could not create DecimalFormatSymbols (Default)");
- return;
- }
-
- // create format instance
- status = U_ZERO_ERROR;
- DecimalFormat fmt("#####", symbols, status);
- if(U_FAILURE(status)) {
- errln((UnicodeString)"ERROR: Could not create DecimalFormat (pattern, symbols*)");
- }
-
- // parse the text
- fmt.parse("5.06e-27", result, parsePos);
- if(result.getType() != Formattable::kDouble &&
- result.getDouble() != 5.06E-27 &&
- parsePos.getIndex() != 8
- )
- {
- errln("ERROR: parse failed - expected 5.06E-27, 8 - returned %d, %i",
- result.getDouble(), parsePos.getIndex());
- }
-}
+void NumberFormatTest::TestExponentParse() {
+
+ UErrorCode status = U_ZERO_ERROR;
+ Formattable result;
+ ParsePosition parsePos(0);
+
+ // set the exponent symbol
+ status = U_ZERO_ERROR;
+ DecimalFormatSymbols symbols(Locale::getDefault(), status);
+ if(U_FAILURE(status)) {
+ dataerrln((UnicodeString)"ERROR: Could not create DecimalFormatSymbols (Default)");
+ return;
+ }
+
+ // create format instance
+ status = U_ZERO_ERROR;
+ DecimalFormat fmt(u"#####", symbols, status);
+ if(U_FAILURE(status)) {
+ errln((UnicodeString)"ERROR: Could not create DecimalFormat (pattern, symbols*)");
+ }
+
+ // parse the text
+ fmt.parse("5.06e-27", result, parsePos);
+ if(result.getType() != Formattable::kDouble &&
+ result.getDouble() != 5.06E-27 &&
+ parsePos.getIndex() != 8
+ )
+ {
+ errln("ERROR: parse failed - expected 5.06E-27, 8 - returned %d, %i",
+ result.getDouble(), parsePos.getIndex());
+ }
+}
void NumberFormatTest::TestExplicitParents() {
{
U_STRING_DECL(pattern,"#",1);
U_STRING_INIT(pattern,"#",1);
-
+
U_STRING_DECL(infstr,"INF",3);
U_STRING_INIT(infstr,"INF",3);
U_STRING_DECL(nanstr,"NAN",3);
U_STRING_INIT(nanstr,"NAN",3);
-
+
UChar outputbuf[50] = {0};
UErrorCode status = U_ZERO_ERROR;
UNumberFormat* fmt = unum_open(UNUM_PATTERN_DECIMAL,pattern,1,NULL,NULL,&status);
UFieldPosition position = { 0, 0, 0};
unum_formatDouble(fmt,inf,outputbuf,50,&position,&status);
-
+
if ( u_strcmp(infstr, outputbuf)) {
errln((UnicodeString)"FAIL: unexpected result for infinity - expected " + infstr + " got " + outputbuf);
}
unum_close(fmt);
}
-#include "dcfmtimp.h"
-
void NumberFormatTest::TestFormatFastpaths() {
-#if UCONFIG_FORMAT_FASTPATHS_49
- logln("Sizeof DecimalFormat = %d, Sizeof DecimalFormatInternal=%d, UNUM_DECIMALFORMAT_INTERNAL_SIZE=%d\n",
- sizeof(DecimalFormat), sizeof(DecimalFormatInternal), UNUM_DECIMALFORMAT_INTERNAL_SIZE);
- if(UNUM_DECIMALFORMAT_INTERNAL_SIZE < sizeof(DecimalFormatInternal)) {
- errln("Error: sizeof(DecimalFormatInternal)=%d but UNUM_DECIMALFORMAT_INTERNAL_SIZE is only %d. Increase the #define?\n", sizeof(DecimalFormatInternal), UNUM_DECIMALFORMAT_INTERNAL_SIZE);
- } else if(UNUM_DECIMALFORMAT_INTERNAL_SIZE > (sizeof(DecimalFormatInternal)+16)) {
- infoln("Note: sizeof(DecimalFormatInternal)=%d but UNUM_DECIMALFORMAT_INTERNAL_SIZE is %d. Decrease the #define? sizeof(DecimalFormat)=%d\n", sizeof(DecimalFormatInternal), UNUM_DECIMALFORMAT_INTERNAL_SIZE, sizeof(DecimalFormat));
- }
-#else
- infoln("NOTE: UCONFIG_FORMAT_FASTPATHS not set, test skipped.");
-#endif
-
// get some additional case
{
UErrorCode status=U_ZERO_ERROR;
- DecimalFormat df(UnicodeString("0000",""),status);
+ DecimalFormat df(UnicodeString(u"0000"),status);
if (U_FAILURE(status)) {
dataerrln("Error creating DecimalFormat - %s", u_errorName(status));
} else {
FieldPosition pos;
df.format(long_number, result, pos);
if(U_FAILURE(status)||expect!=result) {
- errcheckln(status, "FAIL: expected '"+expect+"' got '"+result+"' status "+UnicodeString(u_errorName(status),""));
- } else {
+ dataerrln("%s:%d FAIL: expected '%s' got '%s' status %s",
+ __FILE__, __LINE__, CStr(expect)(), CStr(result)(), u_errorName(status));
+ } else {
logln("OK: got expected '"+result+"' status "+UnicodeString(u_errorName(status),""));
}
}
}
{
UErrorCode status=U_ZERO_ERROR;
- DecimalFormat df(UnicodeString("0000000000000000000",""),status);
+ DecimalFormat df(UnicodeString(u"0000000000000000000"),status);
if (U_FAILURE(status)) {
dataerrln("Error creating DecimalFormat - %s", u_errorName(status));
} else {
FieldPosition pos;
df.format(long_number, result, pos);
if(U_FAILURE(status)||expect!=result) {
- errcheckln(status, "FAIL: expected '"+expect+"' got '"+result+"' status "+UnicodeString(u_errorName(status),"")+" on -9223372036854775808");
+ dataerrln("%s:%d FAIL: expected '%s' got '%s' status %s on -9223372036854775808",
+ __FILE__, __LINE__, CStr(expect)(), CStr(result)(), u_errorName(status));
} else {
logln("OK: got expected '"+result+"' status "+UnicodeString(u_errorName(status),"")+" on -9223372036854775808");
}
}
{
UErrorCode status=U_ZERO_ERROR;
- DecimalFormat df(UnicodeString("0000000000000000000",""),status);
+ DecimalFormat df(UnicodeString(u"0000000000000000000"),status);
if (U_FAILURE(status)) {
dataerrln("Error creating DecimalFormat - %s", u_errorName(status));
} else {
FieldPosition pos;
df.format(long_number, result, pos);
if(U_FAILURE(status)||expect!=result) {
- errcheckln(status, "FAIL: expected '"+expect+"' got '"+result+"' status "+UnicodeString(u_errorName(status),"")+" on U_INT64_MAX");
+ dataerrln("%s:%d FAIL: expected '%s' got '%s' status %s on U_INT64_MAX",
+ __FILE__, __LINE__, CStr(expect)(), CStr(result)(), u_errorName(status));
} else {
logln("OK: got expected '"+result+"' status "+UnicodeString(u_errorName(status),"")+" on U_INT64_MAX");
}
FieldPosition pos;
df.format(long_number, result, pos);
if(U_FAILURE(status)||expect!=result) {
- errcheckln(status, "FAIL: expected '"+expect+"' got '"+result+"' status "+UnicodeString(u_errorName(status),"")+" on 0");
+ dataerrln("%s:%d FAIL: expected '%s' got '%s' status %s on 0",
+ __FILE__, __LINE__, CStr(expect)(), CStr(result)(), u_errorName(status));
} else {
logln("OK: got expected '"+result+"' status "+UnicodeString(u_errorName(status),"")+" on 0");
}
FieldPosition pos;
df.format(long_number, result, pos);
if(U_FAILURE(status)||expect!=result) {
- errcheckln(status, "FAIL: expected '"+expect+"' got '"+result+"' status "+UnicodeString(u_errorName(status),"")+" on -9223372036854775807");
+ dataerrln("%s:%d FAIL: expected '%s' got '%s' status %s on -9223372036854775807",
+ __FILE__, __LINE__, CStr(expect)(), CStr(result)(), u_errorName(status));
} else {
logln("OK: got expected '"+result+"' status "+UnicodeString(u_errorName(status),"")+" on -9223372036854775807");
}
}
-void NumberFormatTest::TestFormattableSize(void) {
+void NumberFormatTest::TestFormattableSize(void) { // test ICU 61 behavior
if(sizeof(FmtStackData) > UNUM_INTERNAL_STACKARRAY_SIZE) {
errln("Error: sizeof(FmtStackData)=%d, UNUM_INTERNAL_STACKARRAY_SIZE=%d\n",
sizeof(FmtStackData), UNUM_INTERNAL_STACKARRAY_SIZE);
logln("Warning: sizeof(FmtStackData)=%d, UNUM_INTERNAL_STACKARRAY_SIZE=%d\n",
sizeof(FmtStackData), UNUM_INTERNAL_STACKARRAY_SIZE);
} else {
- logln("sizeof(FmtStackData)=%d, UNUM_INTERNAL_STACKARRAY_SIZE=%d\n",
- sizeof(FmtStackData), UNUM_INTERNAL_STACKARRAY_SIZE);
+ logln("sizeof(Formattable)=%d, 112=%d\n",
+ sizeof(Formattable), 112);
}
}
UErrorCode int64ConversionU = U_ZERO_ERROR;
int64_t r = ufmt_getInt64(u, &int64ConversionU);
- if( (l==r)
+ if( (l==r)
&& ( uType != UFMT_INT64 ) // int64 better not overflow
- && (U_INVALID_FORMAT_ERROR==int64ConversionU)
+ && (U_INVALID_FORMAT_ERROR==int64ConversionU)
&& (U_INVALID_FORMAT_ERROR==int64ConversionF) ) {
logln("%s:%d: OK: 64 bit overflow", file, line);
} else {
numberFormat->setMinimumSignificantDigits(3);
numberFormat->setMaximumSignificantDigits(5);
numberFormat->setGroupingUsed(false);
-
+
UnicodeString result;
UnicodeString expectedResult;
for (unsigned int i = 0; i < UPRV_LENGTHOF(input); ++i) {
numberFormat->setSignificantDigitsUsed(TRUE);
numberFormat->setMaximumSignificantDigits(3);
-
+
UnicodeString result;
numberFormat->format(0.0, result);
if (result != "0") {
dataerrln("File %s, Line %d: status = %s.\n", __FILE__, __LINE__, u_errorName(status));
return;
}
-
+
if (numberFormat->areSignificantDigitsUsed() == TRUE) {
errln("File %s, Line %d: areSignificantDigitsUsed() was TRUE, expected FALSE.\n", __FILE__, __LINE__);
}
if (numberFormat->areSignificantDigitsUsed() == FALSE) {
errln("File %s, Line %d: areSignificantDigitsUsed() was FALSE, expected TRUE.\n", __FILE__, __LINE__);
}
-
+
}
void NumberFormatTest::TestParseNegativeWithFaLocale() {
{ "en@numbers=arabext", FALSE, CharsToUnicodeString("\\u200E-\\u200E\\u06F6\\u06F7"), -67 },
{ "en@numbers=arabext", TRUE, CharsToUnicodeString("\\u200E-\\u200E\\u06F6\\u06F7"), -67 },
{ "en@numbers=arabext", TRUE, CharsToUnicodeString("\\u200E-\\u200E \\u06F6\\u06F7"), -67 },
-
+
{ "he", FALSE, CharsToUnicodeString("12"), 12 },
{ "he", TRUE, CharsToUnicodeString("12"), 12 },
{ "he", FALSE, CharsToUnicodeString("-23"), -23 },
return;
}
- if (fmt.getPadCharacterString() != UnicodeString("a")) {
- errln("Padding character should be 'a'.");
- return;
- }
+ assertEquals("Padding character should be 'a'.", u"a", fmt.getPadCharacterString());
// Padding char of fmt ought to be '*' since that is the default and no
// explicit padding char is specified in the new pattern.
fmt.applyPattern("AA#,##0.00ZZ", status);
- // Oops this still prints 'a' even though we changed the pattern.
- if (fmt.getPadCharacterString() != UnicodeString(" ")) {
- errln("applyPattern did not clear padding character.");
- }
+ // Oops this still prints 'a' even though we changed the pattern.
+ assertEquals("applyPattern did not clear padding character.", u" ", fmt.getPadCharacterString());
}
void NumberFormatTest::TestRoundingScientific10542() {
errcheckln(status, "DecimalFormat constructor failed - %s", u_errorName(status));
return;
}
-
+
DecimalFormat::ERoundingMode roundingModes[] = {
DecimalFormat::kRoundCeiling,
DecimalFormat::kRoundDown,
"Round half even",
"Round half up",
"Round up"};
-
+
{
double values[] = {-0.003006, -0.003005, -0.003004, 0.003014, 0.003015, 0.003016};
// The order of these expected values correspond to the order of roundingModes and the order of values.
void NumberFormatTest::TestZeroScientific10547() {
UErrorCode status = U_ZERO_ERROR;
DecimalFormat fmt("0.00E0", status);
- if (!assertSuccess("Formt creation", status)) {
+ if (!assertSuccess("Format creation", status)) {
return;
}
UnicodeString out;
fmt.format(-0.0, out);
- assertEquals("format", "-0.00E0", out);
+ assertEquals("format", "-0.00E0", out, true);
}
void NumberFormatTest::verifyRounding(
UnicodeString actual;
format.format(values[j], actual);
if (currentExpected != actual) {
- char buffer[256];
- sprintf(
- buffer,
- "For %s value %f, expected ",
- descriptions[i],
- values[j]);
- errln(UnicodeString(buffer) + currentExpected + ", got " + actual);
+ dataerrln("For %s value %f, expected '%s', got '%s'",
+ descriptions[i], values[j], CStr(currentExpected)(), CStr(actual)());
}
}
}
// for #5186
void NumberFormatTest::TestEquality() {
UErrorCode status = U_ZERO_ERROR;
- DecimalFormatSymbols* symbols = new DecimalFormatSymbols(Locale("root"), status);
+ DecimalFormatSymbols symbols(Locale("root"), status);
if (U_FAILURE(status)) {
dataerrln("Fail: can't create DecimalFormatSymbols for root");
return;
}
UnicodeString pattern("#,##0.###");
- DecimalFormat* fmtBase = new DecimalFormat(pattern, symbols, status);
+ DecimalFormat fmtBase(pattern, symbols, status);
if (U_FAILURE(status)) {
dataerrln("Fail: can't create DecimalFormat using root symbols");
return;
}
- DecimalFormat* fmtClone = (DecimalFormat*)fmtBase->clone();
- fmtClone->setFormatWidth(fmtBase->getFormatWidth() + 32);
- if (*fmtClone == *fmtBase) {
+ DecimalFormat* fmtClone = (DecimalFormat*)fmtBase.clone();
+ fmtClone->setFormatWidth(fmtBase.getFormatWidth() + 32);
+ if (*fmtClone == fmtBase) {
errln("Error: DecimalFormat == does not distinguish objects that differ only in FormatWidth");
}
delete fmtClone;
-
- delete fmtBase;
}
void NumberFormatTest::TestCurrencyUsage() {
UnicodeString original;
fmt->format(agent,original);
- assertEquals("Test Currency Usage 1", UnicodeString("PKR124"), original);
+ assertEquals("Test Currency Usage 1", u"PKR124", original); // use ICU 61 behavior
// test the getter here
UCurrencyUsage curUsage = fmt->getCurrencyUsage();
UnicodeString cash_currency;
fmt->format(agent,cash_currency);
- assertEquals("Test Currency Usage 2", UnicodeString("PKR124"), cash_currency);
+ assertEquals("Test Currency Usage 2", u"PKR124", cash_currency); // use ICU 61 behavior
delete fmt;
}
UnicodeString original_rounding;
fmt->format(agent, original_rounding);
- assertEquals("Test Currency Usage 3", UnicodeString("CA$123.57"), original_rounding);
+ assertEquals("Test Currency Usage 3", u"CA$123.57", original_rounding);
fmt->setCurrencyUsage(UCURR_USAGE_CASH, &status);
}else{
- fmt = (DecimalFormat *) NumberFormat::createInstance(enUS_CAD, UNUM_CASH_CURRENCY, status);
+ fmt = (DecimalFormat *) NumberFormat::createInstance(enUS_CAD, UNUM_CASH_CURRENCY, status);
if (assertSuccess("en_US@currency=CAD/CASH", status, TRUE) == FALSE) {
continue;
}
UnicodeString cash_rounding_currency;
fmt->format(agent, cash_rounding_currency);
- assertEquals("Test Currency Usage 4", UnicodeString("CA$123.55"), cash_rounding_currency);
+ assertEquals("Test Currency Usage 4", u"CA$123.55", cash_rounding_currency);
delete fmt;
}
UnicodeString cur_original;
fmt->setCurrencyUsage(UCURR_USAGE_STANDARD, &status);
fmt->format(agent, cur_original);
- assertEquals("Test Currency Usage 5", UnicodeString("CA$123.57"), cur_original);
+ assertEquals("Test Currency Usage 5", u"CA$123.57", cur_original);
fmt->setCurrency(CUR_PKR, status);
assertSuccess("Set currency to PKR", status);
UnicodeString PKR_changed;
fmt->format(agent, PKR_changed);
- assertEquals("Test Currency Usage 6", UnicodeString("PKR124"), PKR_changed);
+ assertEquals("Test Currency Usage 6", u"PKR124", PKR_changed); // use ICU 61 behavior
delete fmt;
}
}
-void NumberFormatTest::TestNumberFormatTestTuple() {
- NumberFormatTestTuple tuple;
- UErrorCode status = U_ZERO_ERROR;
-
- tuple.setField(
- NumberFormatTestTuple::getFieldByName("locale"),
- "en",
- status);
- tuple.setField(
- NumberFormatTestTuple::getFieldByName("pattern"),
- "#,##0.00",
- status);
- tuple.setField(
- NumberFormatTestTuple::getFieldByName("minIntegerDigits"),
- "-10",
- status);
- if (!assertSuccess("", status)) {
- return;
- }
-
- // only what we set should be set.
- assertEquals("", "en", tuple.locale.getName());
- assertEquals("", "#,##0.00", tuple.pattern);
- assertEquals("", -10, tuple.minIntegerDigits);
- assertTrue("", tuple.localeFlag);
- assertTrue("", tuple.patternFlag);
- assertTrue("", tuple.minIntegerDigitsFlag);
- assertFalse("", tuple.formatFlag);
-
- UnicodeString appendTo;
- assertEquals(
- "",
- "{locale: en, pattern: #,##0.00, minIntegerDigits: -10}",
- tuple.toString(appendTo));
-
- tuple.clear();
- appendTo.remove();
- assertEquals(
- "",
- "{}",
- tuple.toString(appendTo));
- tuple.setField(
- NumberFormatTestTuple::getFieldByName("aBadFieldName"),
- "someValue",
- status);
- if (status != U_ILLEGAL_ARGUMENT_ERROR) {
- errln("Expected U_ILLEGAL_ARGUMENT_ERROR");
- }
- status = U_ZERO_ERROR;
- tuple.setField(
- NumberFormatTestTuple::getFieldByName("minIntegerDigits"),
- "someBadValue",
- status);
- if (status != U_ILLEGAL_ARGUMENT_ERROR) {
- errln("Expected U_ILLEGAL_ARGUMENT_ERROR");
- }
-}
-
-void
-NumberFormatTest::TestDataDriven() {
- NumberFormatTestDataDriven dd;
- dd.setCaller(this);
- dd.run("numberformattestspecification.txt", FALSE);
-}
-
// Check the constant MAX_INT64_IN_DOUBLE.
// The value should convert to a double with no loss of precision.
sprintf(buf, "%lld", (long long)num);
double fNum = 0.0;
sscanf(buf, "%lf", &fNum);
- int64_t rtNum = fNum;
+ int64_t rtNum = static_cast<int64_t>(fNum);
if (num != rtNum) {
errln("%s:%d MAX_INT64_IN_DOUBLE test, %lld did not round trip. Got %lld", __FILE__, __LINE__, (long long)num, (long long)rtNum);
return;
sprintf(buf, "%lld", (long long)num);
double fNum = 0.0;
sscanf(buf, "%lf", &fNum);
- int64_t rtNum = fNum;
+ int64_t rtNum = static_cast<int64_t>(fNum);
if (num != rtNum) {
errln("%s:%d MAX_INT64_IN_DOUBLE test, %lld did not round trip. Got %lld", __FILE__, __LINE__, (long long)num, (long long)rtNum);
return;
}
}
-void NumberFormatTest::TestFastPathConsistent11524() {
- UErrorCode status = U_ZERO_ERROR;
- NumberFormat *fmt = NumberFormat::createInstance("en", status);
- if (U_FAILURE(status) || fmt == NULL) {
- dataerrln("Failed call to NumberFormat::createInstance() - %s", u_errorName(status));
- return;
- }
- fmt->setMaximumIntegerDigits(INT32_MIN);
- UnicodeString appendTo;
- assertEquals("", "0", fmt->format((int32_t)123, appendTo));
- appendTo.remove();
- assertEquals("", "0", fmt->format((int32_t)12345, appendTo));
- delete fmt;
-}
-
void NumberFormatTest::TestGetAffixes() {
UErrorCode status = U_ZERO_ERROR;
DecimalFormatSymbols sym("en_US", status);
}
void NumberFormatTest::Test10727_RoundingZero() {
- DigitList d;
- d.set(-0.0);
- assertFalse("", d.isPositive());
- d.round(3);
- assertFalse("", d.isPositive());
+ IcuTestErrorCode status(*this, "Test10727_RoundingZero");
+ DecimalQuantity dq;
+ dq.setToDouble(-0.0);
+ assertTrue("", dq.isNegative());
+ dq.roundToMagnitude(0, UNUM_ROUND_HALFEVEN, status);
+ assertTrue("", dq.isNegative());
+}
+
+void NumberFormatTest::Test11739_ParseLongCurrency() {
+ IcuTestErrorCode status(*this, "Test11739_ParseLongCurrency");
+ LocalPointer<NumberFormat> nf(NumberFormat::createCurrencyInstance("sr_BA", status));
+ if (status.errDataIfFailureAndReset()) { return; }
+ ((DecimalFormat*) nf.getAlias())->applyPattern(u"#,##0.0 ¤¤¤", status);
+ ParsePosition ppos(0);
+ LocalPointer<CurrencyAmount> result(nf->parseCurrency(u"1.500 амерички долар", ppos));
+ assertEquals("Should parse to 1500 USD", -1, ppos.getErrorIndex());
+ assertEquals("Should parse to 1500 USD", 1500LL, result->getNumber().getInt64(status));
+ assertEquals("Should parse to 1500 USD", u"USD", result->getISOCurrency());
+}
+
+void NumberFormatTest::Test13035_MultiCodePointPaddingInPattern() {
+ IcuTestErrorCode status(*this, "Test13035_MultiCodePointPaddingInPattern");
+ DecimalFormat df(u"a*'நி'###0b", status);
+ if (!assertSuccess("", status, true, __FILE__, __LINE__)) { return; }
+ UnicodeString result;
+ df.format(12, result.remove());
+ // TODO(13034): Re-enable this test when support is added in ICU4C.
+ //assertEquals("Multi-codepoint padding should not be split", u"aநிநி12b", result);
+ df = DecimalFormat(u"a*\U0001F601###0b", status);
+ if (!assertSuccess("", status, true, __FILE__, __LINE__)) { return; }
+ result = df.format(12, result.remove());
+ assertEquals("Single-codepoint padding should not be split", u"a\U0001F601\U0001F60112b", result, true);
+ df = DecimalFormat(u"a*''###0b", status);
+ if (!assertSuccess("", status, true, __FILE__, __LINE__)) { return; }
+ result = df.format(12, result.remove());
+ assertEquals("Quote should be escapable in padding syntax", "a''12b", result, true);
+}
+
+void NumberFormatTest::Test13737_ParseScientificStrict() {
+ IcuTestErrorCode status(*this, "Test13737_ParseScientificStrict");
+ LocalPointer<NumberFormat> df(NumberFormat::createScientificInstance("en", status), status);
+ if (!assertSuccess("", status, true, __FILE__, __LINE__)) {return;}
+ df->setLenient(FALSE);
+ // Parse Test
+ expect(*df, u"1.2", 1.2);
}
void NumberFormatTest::Test11376_getAndSetPositivePrefix() {
DecimalFormat *dfmt = (DecimalFormat *) fmt.getAlias();
dfmt->setCurrency(USD);
UnicodeString result;
-
+
// This line should be a no-op. I am setting the positive prefix
// to be the same thing it was before.
dfmt->setPositivePrefix(dfmt->getPositivePrefix(result));
UnicodeString result;
UnicodeString tripleIntlCurrency(" \\u00a4\\u00a4\\u00a4");
tripleIntlCurrency = tripleIntlCurrency.unescape();
- assertEquals("", tripleIntlCurrency, dfmt->getPositiveSuffix(result));
+ assertEquals("", tripleIntlCurrency, dfmt->getPositiveSuffix(result)); // use ICU 61 behavior
dfmt->setCurrency(USD);
// getPositiveSuffix() always returns the suffix for the
static UChar USD[] = {0x55, 0x53, 0x44, 0x0};
fmt.setCurrency(USD);
UnicodeString appendTo;
-
+
assertEquals("", "US dollars 12.34", fmt.format(12.34, appendTo));
UnicodeString topattern;
return;
}
fmt2.setCurrency(USD);
-
+
appendTo.remove();
assertEquals("", "US dollars 12.34", fmt2.format(12.34, appendTo));
}
+void NumberFormatTest::Test13327_numberingSystemBufferOverflow() {
+ UErrorCode status = U_ZERO_ERROR;
+ for (int runId = 0; runId < 2; runId++) {
+ // Construct a locale string with a very long "numbers" value.
+ // The first time, make the value length exactly equal to ULOC_KEYWORDS_CAPACITY.
+ // The second time, make it exceed ULOC_KEYWORDS_CAPACITY.
+ int extraLength = (runId == 0) ? 0 : 5;
+
+ CharString localeId("en@numbers=", status);
+ for (int i = 0; i < ULOC_KEYWORDS_CAPACITY + extraLength; i++) {
+ localeId.append('x', status);
+ }
+ assertSuccess("Constructing locale string", status);
+ Locale locale(localeId.data());
+
+ LocalPointer<NumberingSystem> ns(NumberingSystem::createInstance(locale, status));
+ assertFalse("Should not be null", ns.getAlias() == nullptr);
+ assertSuccess("Should create with no error", status);
+ }
+}
+
+void NumberFormatTest::Test13391_chakmaParsing() {
+ UErrorCode status = U_ZERO_ERROR;
+ LocalPointer<DecimalFormat> df(dynamic_cast<DecimalFormat*>(
+ NumberFormat::createInstance(Locale("ccp"), status)));
+ if (df == nullptr) {
+ dataerrln("%s %d Chakma df is null", __FILE__, __LINE__);
+ return;
+ }
+ const UChar* expected = u"\U00011137\U00011138,\U00011139\U0001113A\U0001113B";
+ UnicodeString actual;
+ df->format(12345, actual, status);
+ assertSuccess("Should not fail when formatting in ccp", status);
+ assertEquals("Should produce expected output in ccp", expected, actual);
+
+ Formattable result;
+ df->parse(expected, result, status);
+ assertSuccess("Should not fail when parsing in ccp", status);
+ assertEquals("Should parse to 12345 in ccp", 12345, result);
+
+ const UChar* expectedScientific = u"\U00011137.\U00011139E\U00011138";
+ UnicodeString actualScientific;
+ df.adoptInstead(static_cast<DecimalFormat*>(
+ NumberFormat::createScientificInstance(Locale("ccp"), status)));
+ df->format(130, actualScientific, status);
+ assertSuccess("Should not fail when formatting scientific in ccp", status);
+ assertEquals("Should produce expected scientific output in ccp",
+ expectedScientific, actualScientific);
+
+ Formattable resultScientific;
+ df->parse(expectedScientific, resultScientific, status);
+ assertSuccess("Should not fail when parsing scientific in ccp", status);
+ assertEquals("Should parse scientific to 130 in ccp", 130, resultScientific);
+}
+
void NumberFormatTest::verifyFieldPositionIterator(
NumberFormatTest_Attributes *expected, FieldPositionIterator &iter) {
}
}
-void NumberFormatTest::checkExceptionIssue11735() {
- UErrorCode status;
+void NumberFormatTest::Test11735_ExceptionIssue() {
+ IcuTestErrorCode status(*this, "Test11735_ExceptionIssue");
Locale enLocale("en");
DecimalFormatSymbols symbols(enLocale, status);
+ if (status.isSuccess()) {
+ DecimalFormat fmt("0", symbols, status);
+ assertSuccess("Fail: Construct DecimalFormat formatter", status, true, __FILE__, __LINE__);
+ ParsePosition ppos(0);
+ fmt.parseCurrency("53.45", ppos); // NPE thrown here in ICU4J.
+ assertEquals("Issue11735 ppos", 0, ppos.getIndex());
+ }
+}
+
+void NumberFormatTest::Test11035_FormatCurrencyAmount() {
+ UErrorCode status = U_ZERO_ERROR;
+ double amount = 12345.67;
+ const char16_t* expected = u"12,345$67 ";
+
+ // Test two ways to set a currency via API
+ Locale loc1 = Locale("pt_PT");
+ LocalPointer<NumberFormat> fmt1(NumberFormat::createCurrencyInstance("loc1", status),
+ status);
if (U_FAILURE(status)) {
- errln((UnicodeString)
- "Fail: Construct DecimalFormatSymbols");
+ dataerrln("%s %d NumberFormat instance fmt1 is null", __FILE__, __LINE__);
+ return;
+ }
+ fmt1->setCurrency(u"PTE", status);
+ assertSuccess("Setting currency on fmt1", status);
+ UnicodeString actualSetCurrency;
+ fmt1->format(amount, actualSetCurrency);
+
+ Locale loc2 = Locale("pt_PT@currency=PTE");
+ LocalPointer<NumberFormat> fmt2(NumberFormat::createCurrencyInstance(loc2, status));
+ assertSuccess("Creating fmt2", status);
+ UnicodeString actualLocaleString;
+ fmt2->format(amount, actualLocaleString);
+
+ // TODO: The following test will fail until DecimalFormat wraps NumberFormatter.
+ if (!logKnownIssue("13574")) {
+ assertEquals("Custom Currency Pattern, Set Currency", expected, actualSetCurrency);
}
+}
- DecimalFormat fmt("0", symbols, status);
+void NumberFormatTest::Test11318_DoubleConversion() {
+ IcuTestErrorCode status(*this, "Test11318_DoubleConversion");
+ LocalPointer<NumberFormat> nf(NumberFormat::createInstance("en", status), status);
if (U_FAILURE(status)) {
- errln((UnicodeString)
- "Fail: Construct DecimalFormat formatter");
+ dataerrln("%s %d Error in NumberFormat instance creation", __FILE__, __LINE__);
+ return;
+ }
+ nf->setMaximumFractionDigits(40);
+ nf->setMaximumIntegerDigits(40);
+ DecimalFormat* df = dynamic_cast<DecimalFormat*>(nf.getAlias());
+ if (df != NULL) {
+ UErrorCode status = U_ZERO_ERROR;
+ df->setAttribute(UNUM_FORMAT_WITH_FULL_PRECISION, TRUE, status); // Apple
}
+ UnicodeString appendTo;
+ nf->format(999999999999999.9, appendTo);
+ assertEquals("Should render all digits", u"999,999,999,999,999.9", appendTo);
+}
- ParsePosition ppos(0);
- fmt.parseCurrency("53.45", ppos); // NPE thrown here in ICU4J.
- assertEquals("Issue11735 ppos", 0, ppos.getIndex());
+void NumberFormatTest::TestParsePercentRegression() {
+ IcuTestErrorCode status(*this, "TestParsePercentRegression");
+ LocalPointer<DecimalFormat> df1((DecimalFormat*) NumberFormat::createInstance("en", status), status);
+ LocalPointer<DecimalFormat> df2((DecimalFormat*) NumberFormat::createPercentInstance("en", status), status);
+ if (status.isFailure()) {return; }
+ df1->setLenient(TRUE);
+ df2->setLenient(TRUE);
+
+ {
+ ParsePosition ppos;
+ Formattable result;
+ df1->parse("50%", result, ppos);
+ assertEquals("df1 should accept a number but not the percent sign", 2, ppos.getIndex());
+ assertEquals("df1 should return the number as 50", 50.0, result.getDouble(status));
+ }
+ {
+ ParsePosition ppos;
+ Formattable result;
+ df2->parse("50%", result, ppos);
+ assertEquals("df2 should accept the percent sign", 3, ppos.getIndex());
+ assertEquals("df2 should return the number as 0.5", 0.5, result.getDouble(status));
+ }
+ {
+ ParsePosition ppos;
+ Formattable result;
+ df2->parse("50", result, ppos);
+ assertEquals("df2 should return the number as 0.5 even though the percent sign is missing",
+ 0.5,
+ result.getDouble(status));
+ }
+}
+
+void NumberFormatTest::TestMultiplierWithScale() {
+ // to be added
+}
+
+void NumberFormatTest::TestFastFormatInt32() {
+ IcuTestErrorCode status(*this, "TestFastFormatInt32");
+
+ // The two simplest formatters, old API and new API.
+ // Old API should use the fastpath for ints.
+ LocalizedNumberFormatter lnf = NumberFormatter::withLocale("en");
+ LocalPointer<NumberFormat> df(NumberFormat::createInstance("en", status), status);
+ if (!assertSuccess("", status, true, __FILE__, __LINE__)) {return;}
+
+ double nums[] = {
+ 0.0,
+ -0.0,
+ NAN,
+ INFINITY,
+ 0.1,
+ 1.0,
+ 1.1,
+ 2.0,
+ 3.0,
+ 9.0,
+ 10.0,
+ 99.0,
+ 100.0,
+ 999.0,
+ 1000.0,
+ 9999.0,
+ 10000.0,
+ 99999.0,
+ 100000.0,
+ 999999.0,
+ 1000000.0,
+ static_cast<double>(INT32_MAX) - 1,
+ static_cast<double>(INT32_MAX),
+ static_cast<double>(INT32_MAX) + 1,
+ static_cast<double>(INT32_MIN) - 1,
+ static_cast<double>(INT32_MIN),
+ static_cast<double>(INT32_MIN) + 1};
+
+ for (auto num : nums) {
+ UnicodeString expected = lnf.formatDouble(num, status).toString();
+ UnicodeString actual;
+ df->format(num, actual);
+ assertEquals(UnicodeString("d = ") + num, expected, actual);
+ }
+}
+
+void NumberFormatTest::Test11646_Equality() {
+ UErrorCode status = U_ZERO_ERROR;
+ DecimalFormatSymbols symbols(Locale::getEnglish(), status);
+ UnicodeString pattern(u"\u00a4\u00a4\u00a4 0.00 %\u00a4\u00a4");
+ DecimalFormat fmt(pattern, symbols, status);
+ if (!assertSuccess("", status)) return;
+
+ // Test equality with affixes. set affix methods can't capture special
+ // characters which is why equality should fail.
+ {
+ DecimalFormat fmtCopy(fmt);
+ assertTrue("", fmt == fmtCopy);
+ UnicodeString positivePrefix;
+ fmtCopy.setPositivePrefix(fmtCopy.getPositivePrefix(positivePrefix));
+ assertFalse("", fmt == fmtCopy);
+ }
+ {
+ DecimalFormat fmtCopy = DecimalFormat(fmt);
+ assertTrue("", fmt == fmtCopy);
+ UnicodeString positivePrefix;
+ fmtCopy.setPositiveSuffix(fmtCopy.getPositiveSuffix(positivePrefix));
+ assertFalse("", fmt == fmtCopy);
+ }
+ {
+ DecimalFormat fmtCopy(fmt);
+ assertTrue("", fmt == fmtCopy);
+ UnicodeString negativePrefix;
+ fmtCopy.setNegativePrefix(fmtCopy.getNegativePrefix(negativePrefix));
+ assertFalse("", fmt == fmtCopy);
+ }
+ {
+ DecimalFormat fmtCopy(fmt);
+ assertTrue("", fmt == fmtCopy);
+ UnicodeString negativePrefix;
+ fmtCopy.setNegativeSuffix(fmtCopy.getNegativeSuffix(negativePrefix));
+ assertFalse("", fmt == fmtCopy);
+ }
+}
+
+void NumberFormatTest::TestParseNaN() {
+ IcuTestErrorCode status(*this, "TestParseNaN");
+
+ DecimalFormat df("0", { "en", status }, status);
+ if (!assertSuccess("", status, true, __FILE__, __LINE__)) { return; }
+ Formattable parseResult;
+ df.parse(u"NaN", parseResult, status);
+ assertEquals("NaN should parse successfully", NAN, parseResult.getDouble());
+ assertFalse("Result NaN should be positive", std::signbit(parseResult.getDouble()));
+ UnicodeString formatResult;
+ df.format(parseResult.getDouble(), formatResult);
+ assertEquals("NaN should round-trip", u"NaN", formatResult);
+}
+
+void NumberFormatTest::Test11897_LocalizedPatternSeparator() {
+ IcuTestErrorCode status(*this, "Test11897_LocalizedPatternSeparator");
+
+ // In a locale with a different <list> symbol, like arabic,
+ // kPatternSeparatorSymbol should still be ';'
+ {
+ DecimalFormatSymbols dfs("ar", status);
+ assertEquals("pattern separator symbol should be ;",
+ u";",
+ dfs.getSymbol(DecimalFormatSymbols::kPatternSeparatorSymbol));
+ }
+
+ // However, the custom symbol should be used in localized notation
+ // when set manually via API
+ {
+ DecimalFormatSymbols dfs("en", status);
+ dfs.setSymbol(DecimalFormatSymbols::kPatternSeparatorSymbol, u"!", FALSE);
+ DecimalFormat df(u"0", dfs, status);
+ if (!assertSuccess("", status, true, __FILE__, __LINE__)) { return; }
+ df.applyPattern("a0;b0", status); // should not throw
+ UnicodeString result;
+ assertEquals("should apply the normal pattern",
+ df.getNegativePrefix(result.remove()),
+ "b");
+ df.applyLocalizedPattern(u"c0!d0", status); // should not throw
+ assertEquals("should apply the localized pattern",
+ df.getNegativePrefix(result.remove()),
+ "d");
+ }
+}
+
+void NumberFormatTest::Test13055_PercentageRounding() {
+ IcuTestErrorCode status(*this, "PercentageRounding");
+ UnicodeString actual;
+ LocalPointer<NumberFormat>pFormat(NumberFormat::createPercentInstance("en_US", status));
+ if (U_FAILURE(status)) {
+ dataerrln("Failure creating DecimalFormat %s", u_errorName(status));
+ return;
+ }
+ pFormat->setMaximumFractionDigits(0);
+ pFormat->setRoundingMode(DecimalFormat::kRoundHalfEven);
+ pFormat->format(2.155, actual);
+ assertEquals("Should round percent toward even number", "216%", actual);
+}
+
+void NumberFormatTest::Test11839() {
+ IcuTestErrorCode errorCode(*this, "Test11839");
+ // Ticket #11839: DecimalFormat does not respect custom plus sign
+ LocalPointer<DecimalFormatSymbols> dfs(new DecimalFormatSymbols(Locale::getEnglish(), errorCode), errorCode);
+ if (!assertSuccess("", errorCode, true, __FILE__, __LINE__)) { return; }
+ dfs->setSymbol(DecimalFormatSymbols::kMinusSignSymbol, u"a∸");
+ dfs->setSymbol(DecimalFormatSymbols::kPlusSignSymbol, u"b∔"); // ∔ U+2214 DOT PLUS
+ DecimalFormat df(u"0.00+;0.00-", dfs.orphan(), errorCode);
+ UnicodeString result;
+ df.format(-1.234, result, errorCode);
+ assertEquals("Locale-specific minus sign should be used", u"1.23a∸", result);
+ df.format(1.234, result.remove(), errorCode);
+ assertEquals("Locale-specific plus sign should be used", u"1.23b∔", result);
+ // Test round-trip with parse
+ expect2(df, -456, u"456.00a∸");
+ expect2(df, 456, u"456.00b∔");
+}
+
+void NumberFormatTest::Test10354() {
+ IcuTestErrorCode errorCode(*this, "Test10354");
+ // Ticket #10354: invalid FieldPositionIterator when formatting with empty NaN
+ DecimalFormatSymbols dfs(errorCode);
+ UnicodeString empty;
+ dfs.setSymbol(DecimalFormatSymbols::kNaNSymbol, empty);
+ DecimalFormat df(errorCode);
+ df.setDecimalFormatSymbols(dfs);
+ UnicodeString result;
+ FieldPositionIterator positions;
+ df.format(NAN, result, &positions, errorCode);
+ errorCode.errIfFailureAndReset("DecimalFormat.format(NAN, FieldPositionIterator) failed");
+ FieldPosition fp;
+ while (positions.next(fp)) {
+ // Should not loop forever
+ }
+}
+
+void NumberFormatTest::Test11645_ApplyPatternEquality() {
+ IcuTestErrorCode status(*this, "Test11645_ApplyPatternEquality");
+ const char16_t* pattern = u"#,##0.0#";
+ LocalPointer<DecimalFormat> fmt((DecimalFormat*) NumberFormat::createInstance(status), status);
+ if (!assertSuccess("", status, true, __FILE__, __LINE__)) { return; }
+ fmt->applyPattern(pattern, status);
+ LocalPointer<DecimalFormat> fmtCopy;
+
+ static const int32_t newMultiplier = 37;
+ fmtCopy.adoptInstead(new DecimalFormat(*fmt));
+ assertFalse("Value before setter", fmtCopy->getMultiplier() == newMultiplier);
+ fmtCopy->setMultiplier(newMultiplier);
+ assertEquals("Value after setter", fmtCopy->getMultiplier(), newMultiplier);
+ fmtCopy->applyPattern(pattern, status);
+ //assertEquals("Value after applyPattern", fmtCopy->getMultiplier(), newMultiplier);
+ //assertFalse("multiplier", *fmt == *fmtCopy);
+
+ static const NumberFormat::ERoundingMode newRoundingMode = NumberFormat::ERoundingMode::kRoundCeiling;
+ fmtCopy.adoptInstead(new DecimalFormat(*fmt));
+ assertFalse("Value before setter", fmtCopy->getRoundingMode() == newRoundingMode);
+ fmtCopy->setRoundingMode(newRoundingMode);
+ assertEquals("Value after setter", fmtCopy->getRoundingMode(), newRoundingMode);
+ fmtCopy->applyPattern(pattern, status);
+ assertEquals("Value after applyPattern", fmtCopy->getRoundingMode(), newRoundingMode);
+ assertFalse("roundingMode", *fmt == *fmtCopy);
+
+ static const char16_t *const newCurrency = u"EAT";
+ fmtCopy.adoptInstead(new DecimalFormat(*fmt));
+ assertFalse("Value before setter", fmtCopy->getCurrency() == newCurrency);
+ fmtCopy->setCurrency(newCurrency);
+ assertEquals("Value after setter", fmtCopy->getCurrency(), newCurrency);
+ fmtCopy->applyPattern(pattern, status);
+ assertEquals("Value after applyPattern", fmtCopy->getCurrency(), newCurrency);
+ assertFalse("currency", *fmt == *fmtCopy);
+
+ static const UCurrencyUsage newCurrencyUsage = UCurrencyUsage::UCURR_USAGE_CASH;
+ fmtCopy.adoptInstead(new DecimalFormat(*fmt));
+ assertFalse("Value before setter", fmtCopy->getCurrencyUsage() == newCurrencyUsage);
+ fmtCopy->setCurrencyUsage(newCurrencyUsage, status);
+ assertEquals("Value after setter", fmtCopy->getCurrencyUsage(), newCurrencyUsage);
+ fmtCopy->applyPattern(pattern, status);
+ assertEquals("Value after applyPattern", fmtCopy->getCurrencyUsage(), newCurrencyUsage);
+ assertFalse("currencyUsage", *fmt == *fmtCopy);
+}
+
+void NumberFormatTest::Test12567() {
+ IcuTestErrorCode errorCode(*this, "Test12567");
+ // Ticket #12567: DecimalFormat.equals() may not be symmetric
+ LocalPointer<DecimalFormat> df1((DecimalFormat *)
+ NumberFormat::createInstance(Locale::getUS(), UNUM_CURRENCY, errorCode));
+ LocalPointer<DecimalFormat> df2((DecimalFormat *)
+ NumberFormat::createInstance(Locale::getUS(), UNUM_DECIMAL, errorCode));
+ if (!assertSuccess("", errorCode, true, __FILE__, __LINE__)) { return; }
+ // NOTE: CurrencyPluralInfo equality not tested in C++ because its operator== is not defined.
+ df1->applyPattern(u"0.00", errorCode);
+ df2->applyPattern(u"0.00", errorCode);
+ //assertTrue("df1 == df2", *df1 == *df2);
+ //assertTrue("df2 == df1", *df2 == *df1);
+ df2->setPositivePrefix(u"abc");
+ assertTrue("df1 != df2", *df1 != *df2);
+ assertTrue("df2 != df1", *df2 != *df1);
+}
+
+void NumberFormatTest::Test11626_CustomizeCurrencyPluralInfo() {
+ IcuTestErrorCode errorCode(*this, "Test11626_CustomizeCurrencyPluralInfo");
+ // Ticket #11626: No unit test demonstrating how to use CurrencyPluralInfo to
+ // change formatting spelled out currencies
+ // Use locale sr because it has interesting plural rules.
+ Locale locale("sr");
+ LocalPointer<DecimalFormatSymbols> symbols(new DecimalFormatSymbols(locale, errorCode), errorCode);
+ CurrencyPluralInfo info(locale, errorCode);
+ if (!assertSuccess("", errorCode, true, __FILE__, __LINE__)) { return; }
+ info.setCurrencyPluralPattern(u"one", u"0 qwerty", errorCode);
+ info.setCurrencyPluralPattern(u"few", u"0 dvorak", errorCode);
+ DecimalFormat df(u"#", symbols.orphan(), UNUM_CURRENCY_PLURAL, errorCode);
+ df.setCurrencyPluralInfo(info);
+ df.setCurrency(u"USD");
+ df.setMaximumFractionDigits(0);
+
+ UnicodeString result;
+ //assertEquals("Plural one", u"1 qwerty", df.format(1, result, errorCode));
+ //assertEquals("Plural few", u"3 dvorak", df.format(3, result.remove(), errorCode));
+ assertEquals("Plural other", u"99 америчких долара", df.format(99, result.remove(), errorCode));
+
+ info.setPluralRules(u"few: n is 1; one: n in 2..4", errorCode);
+ df.setCurrencyPluralInfo(info);
+ //assertEquals("Plural one", u"1 dvorak", df.format(1, result.remove(), errorCode));
+ //assertEquals("Plural few", u"3 qwerty", df.format(3, result.remove(), errorCode));
+ assertEquals("Plural other", u"99 америчких долара", df.format(99, result.remove(), errorCode));
+}
+
+void NumberFormatTest::Test13056_GroupingSize() {
+ UErrorCode status = U_ZERO_ERROR;
+ DecimalFormat df(u"#,##0", status);
+ if (!assertSuccess("", status)) return;
+ assertEquals("Primary grouping should return 3", 3, df.getGroupingSize());
+ assertEquals("Secondary grouping should return 0", 0, df.getSecondaryGroupingSize());
+ df.setSecondaryGroupingSize(3);
+ assertEquals("Primary grouping should still return 3", 3, df.getGroupingSize());
+ assertEquals("Secondary grouping should round-trip", 3, df.getSecondaryGroupingSize());
+ df.setGroupingSize(4);
+ assertEquals("Primary grouping should return 4", 4, df.getGroupingSize());
+ assertEquals("Secondary should remember explicit setting and return 3", 3, df.getSecondaryGroupingSize());
+}
+
+
+void NumberFormatTest::Test11025_CurrencyPadding() {
+ UErrorCode status = U_ZERO_ERROR;
+ UnicodeString pattern(u"¤¤ **####0.00");
+ DecimalFormatSymbols sym(Locale::getFrance(), status);
+ if (!assertSuccess("", status)) return;
+ DecimalFormat fmt(pattern, sym, status);
+ if (!assertSuccess("", status)) return;
+ UnicodeString result;
+ fmt.format(433.0, result);
+ assertEquals("Number should be padded to 11 characters", "EUR *433,00", result);
+}
+
+void NumberFormatTest::Test11648_ExpDecFormatMalPattern() {
+ UErrorCode status = U_ZERO_ERROR;
+
+ DecimalFormat fmt("0.00", {"en", status}, status);
+ if (!assertSuccess("", status, true, __FILE__, __LINE__)) { return; }
+ fmt.setScientificNotation(TRUE);
+ UnicodeString pattern;
+
+ assertEquals("A valid scientific notation pattern should be produced",
+ "0.00E0",
+ fmt.toPattern(pattern));
+
+ DecimalFormat fmt2(pattern, status);
+ assertSuccess("", status);
+}
+
+void NumberFormatTest::Test11649_DecFmtCurrencies() {
+ IcuTestErrorCode status(*this, "Test11649_DecFmtCurrencies");
+ UnicodeString pattern("\\u00a4\\u00a4\\u00a4 0.00");
+ pattern = pattern.unescape();
+ DecimalFormat fmt(pattern, status);
+ if (!assertSuccess("", status, true, __FILE__, __LINE__)) { return; }
+ static const UChar USD[] = u"USD";
+ fmt.setCurrency(USD);
+ UnicodeString appendTo;
+
+ assertEquals("", "US dollars 12.34", fmt.format(12.34, appendTo));
+ UnicodeString topattern;
+
+ // assertEquals("", pattern, fmt.toPattern(topattern));
+ DecimalFormat fmt2(topattern, status);
+ fmt2.setCurrency(USD);
+
+ appendTo.remove();
+ assertEquals("", "US dollars 12.34", fmt2.format(12.34, appendTo));
+}
+
+void NumberFormatTest::Test13148_ParseGroupingSeparators() {
+ IcuTestErrorCode status(*this, "Test13148");
+ LocalPointer<DecimalFormat> fmt(
+ (DecimalFormat*)NumberFormat::createInstance("en-ZA", status), status);
+ if (!assertSuccess("", status, true, __FILE__, __LINE__)) { return; }
+
+ DecimalFormatSymbols symbols = *fmt->getDecimalFormatSymbols();
+
+ symbols.setSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol, u'.');
+ symbols.setSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol, u',');
+ fmt->setDecimalFormatSymbols(symbols);
+ Formattable number;
+ fmt->parse(u"300,000", number, status);
+ assertEquals("Should parse as 300000", 300000LL, number.getInt64(status));
+}
+
+void NumberFormatTest::Test12753_PatternDecimalPoint() {
+ UErrorCode status = U_ZERO_ERROR;
+ DecimalFormatSymbols symbols(Locale::getUS(), status);
+ symbols.setSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol, u"*", false);
+ DecimalFormat df(u"0.00", symbols, status);
+ if (!assertSuccess("", status)) return;
+ df.setDecimalPatternMatchRequired(true);
+ Formattable result;
+ df.parse(u"123",result, status);
+ assertEquals("Parsing integer succeeded even though setDecimalPatternMatchRequired was set",
+ U_INVALID_FORMAT_ERROR, status);
+ }
+
+ void NumberFormatTest::Test11647_PatternCurrencySymbols() {
+ UErrorCode status = U_ZERO_ERROR;
+ DecimalFormat df(status);
+ df.applyPattern(u"¤¤¤¤#", status);
+ if (!assertSuccess("", status)) return;
+ UnicodeString actual;
+ df.format(123, actual);
+ //assertEquals("Should replace 4 currency signs with U+FFFD", u"\uFFFD123", actual);
+}
+
+void NumberFormatTest::Test11913_BigDecimal() {
+ UErrorCode status = U_ZERO_ERROR;
+ LocalPointer<NumberFormat> df(NumberFormat::createInstance(Locale::getEnglish(), status), status);
+ if (!assertSuccess("", status)) return;
+ UnicodeString result;
+ df->format(StringPiece("1.23456789E400"), result, nullptr, status);
+ assertSuccess("", status);
+ assertEquals("Should format more than 309 digits", u"12,345,678", UnicodeString(result, 0, 10));
+ assertEquals("Should format more than 309 digits", 534, result.length());
+}
+
+void NumberFormatTest::Test11020_RoundingInScientificNotation() {
+ UErrorCode status = U_ZERO_ERROR;
+ DecimalFormatSymbols sym(Locale::getFrance(), status);
+ DecimalFormat fmt(u"0.05E0", sym, status);
+ if (!assertSuccess("", status, true, __FILE__, __LINE__)) { return; }
+ assertSuccess("", status);
+ UnicodeString result;
+ fmt.format(12301.2, result);
+ assertEquals("Rounding increment should be applied after magnitude scaling", u"1,25E4", result);
+}
+
+void NumberFormatTest::Test11640_TripleCurrencySymbol() {
+ IcuTestErrorCode status(*this, "Test11640_TripleCurrencySymbol");
+ UnicodeString actual;
+ DecimalFormat dFormat(u"¤¤¤ 0", status);
+ if (U_FAILURE(status)) {
+ dataerrln("Failure creating DecimalFormat %s", u_errorName(status));
+ return;
+ }
+ dFormat.setCurrency(u"USD");
+ UnicodeString result;
+ dFormat.getPositivePrefix(result);
+ assertEquals("Triple-currency should give long name on getPositivePrefix",
+ "US dollars ", result);
+}
+
+
+void NumberFormatTest::Test13763_FieldPositionIteratorOffset() {
+ IcuTestErrorCode status(*this, "Test13763_FieldPositionIteratorOffset");
+ FieldPositionIterator fpi;
+ UnicodeString result(u"foo\U0001F4FBbar"); // 8 code units
+ LocalPointer<NumberFormat> nf(NumberFormat::createInstance("en", status), status);
+ if (!assertSuccess("", status, true, __FILE__, __LINE__)) { return; }
+ nf->format(5142.3, result, &fpi, status);
+
+ int32_t expected[] = {
+ UNUM_GROUPING_SEPARATOR_FIELD, 9, 10,
+ UNUM_INTEGER_FIELD, 8, 13,
+ UNUM_DECIMAL_SEPARATOR_FIELD, 13, 14,
+ UNUM_FRACTION_FIELD, 14, 15,
+ };
+ int32_t tupleCount = UPRV_LENGTHOF(expected)/3;
+ expectPositions(fpi, expected, tupleCount, result);
+}
+
+void NumberFormatTest::Test13777_ParseLongNameNonCurrencyMode() {
+ IcuTestErrorCode status(*this, "Test13777_ParseLongNameNonCurrencyMode");
+
+ LocalPointer<NumberFormat> df(
+ NumberFormat::createInstance("en-us", UNumberFormatStyle::UNUM_CURRENCY_PLURAL, status), status);
+ if (!assertSuccess("", status, true, __FILE__, __LINE__)) { return; }
+ expect2(*df, 1.5, u"1.50 US dollars");
+}
+
+void NumberFormatTest::Test13804_EmptyStringsWhenParsing() {
+ IcuTestErrorCode status(*this, "Test13804_EmptyStringsWhenParsing");
+
+ DecimalFormatSymbols dfs("en", status);
+ if (status.errIfFailureAndReset()) {
+ return;
+ }
+ dfs.setSymbol(DecimalFormatSymbols::kCurrencySymbol, u"", FALSE);
+ dfs.setSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol, u"", FALSE);
+ dfs.setSymbol(DecimalFormatSymbols::kZeroDigitSymbol, u"", FALSE);
+ dfs.setSymbol(DecimalFormatSymbols::kOneDigitSymbol, u"", FALSE);
+ dfs.setSymbol(DecimalFormatSymbols::kTwoDigitSymbol, u"", FALSE);
+ dfs.setSymbol(DecimalFormatSymbols::kThreeDigitSymbol, u"", FALSE);
+ dfs.setSymbol(DecimalFormatSymbols::kFourDigitSymbol, u"", FALSE);
+ dfs.setSymbol(DecimalFormatSymbols::kFiveDigitSymbol, u"", FALSE);
+ dfs.setSymbol(DecimalFormatSymbols::kSixDigitSymbol, u"", FALSE);
+ dfs.setSymbol(DecimalFormatSymbols::kSevenDigitSymbol, u"", FALSE);
+ dfs.setSymbol(DecimalFormatSymbols::kEightDigitSymbol, u"", FALSE);
+ dfs.setSymbol(DecimalFormatSymbols::kNineDigitSymbol, u"", FALSE);
+ dfs.setSymbol(DecimalFormatSymbols::kExponentMultiplicationSymbol, u"", FALSE);
+ dfs.setSymbol(DecimalFormatSymbols::kExponentialSymbol, u"", FALSE);
+ dfs.setSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol, u"", FALSE);
+ dfs.setSymbol(DecimalFormatSymbols::kInfinitySymbol, u"", FALSE);
+ dfs.setSymbol(DecimalFormatSymbols::kIntlCurrencySymbol, u"", FALSE);
+ dfs.setSymbol(DecimalFormatSymbols::kMinusSignSymbol, u"", FALSE);
+ dfs.setSymbol(DecimalFormatSymbols::kMonetarySeparatorSymbol, u"", FALSE);
+ dfs.setSymbol(DecimalFormatSymbols::kMonetaryGroupingSeparatorSymbol, u"", FALSE);
+ dfs.setSymbol(DecimalFormatSymbols::kNaNSymbol, u"", FALSE);
+ dfs.setPatternForCurrencySpacing(UNUM_CURRENCY_INSERT, FALSE, u"");
+ dfs.setPatternForCurrencySpacing(UNUM_CURRENCY_INSERT, TRUE, u"");
+ dfs.setSymbol(DecimalFormatSymbols::kPercentSymbol, u"", FALSE);
+ dfs.setSymbol(DecimalFormatSymbols::kPerMillSymbol, u"", FALSE);
+ dfs.setSymbol(DecimalFormatSymbols::kPlusSignSymbol, u"", FALSE);
+
+ DecimalFormat df("0", dfs, status);
+ if (status.errIfFailureAndReset()) {
+ return;
+ }
+ df.setGroupingUsed(TRUE);
+ df.setScientificNotation(TRUE);
+ df.setLenient(TRUE); // enable all matchers
+ {
+ UnicodeString result;
+ df.format(0, result); // should not crash or hit infinite loop
+ }
+ const char16_t* samples[] = {
+ u"",
+ u"123",
+ u"$123",
+ u"-",
+ u"+",
+ u"44%",
+ u"1E+2.3"
+ };
+ for (auto& sample : samples) {
+ logln(UnicodeString(u"Attempting parse on: ") + sample);
+ status.setScope(sample);
+ // We don't care about the results, only that we don't crash and don't loop.
+ Formattable result;
+ ParsePosition ppos(0);
+ df.parse(sample, result, ppos);
+ ppos = ParsePosition(0);
+ LocalPointer<CurrencyAmount> curramt(df.parseCurrency(sample, ppos));
+ status.errIfFailureAndReset();
+ }
+
+ // Test with a nonempty exponent separator symbol to cover more code
+ dfs.setSymbol(DecimalFormatSymbols::kExponentialSymbol, u"E", FALSE);
+ df.setDecimalFormatSymbols(dfs);
+ {
+ Formattable result;
+ ParsePosition ppos(0);
+ df.parse(u"1E+2.3", result, ppos);
+ }
}
#endif /* #if !UCONFIG_NO_FORMATTING */