| /******************************************************************** |
| * COPYRIGHT: |
| * Copyright (c) 1997-2015, International Business Machines Corporation and |
| * others. All Rights Reserved. |
| ********************************************************************/ |
| /* Modification History: |
| * Date Name Description |
| * 07/15/99 helena Ported to HPUX 10/11 CC. |
| */ |
| |
| #include "unicode/utypes.h" |
| |
| #if !UCONFIG_NO_FORMATTING |
| |
| #include "numfmtst.h" |
| #include "unicode/dcfmtsym.h" |
| #include "unicode/decimfmt.h" |
| #include "unicode/localpointer.h" |
| #include "unicode/ucurr.h" |
| #include "unicode/ustring.h" |
| #include "unicode/measfmt.h" |
| #include "unicode/curramt.h" |
| #include "digitlst.h" |
| #include "textfile.h" |
| #include "tokiter.h" |
| #include "charstr.h" |
| #include "putilimp.h" |
| #include "winnmtst.h" |
| #include <float.h> |
| #include <string.h> |
| #include <stdlib.h> |
| #include "cstring.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); |
| } |
| |
| 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; |
| } |
| |
| 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; |
| } |
| |
| //#define NUMFMTST_CACHE_DEBUG 1 |
| #include "stdio.h" /* for sprintf */ |
| // #include "iostream" // for cout |
| |
| //#define NUMFMTST_DEBUG 1 |
| |
| static const UChar EUR[] = {69,85,82,0}; // "EUR" |
| static const UChar ISO_CURRENCY_USD[] = {0x55, 0x53, 0x44, 0}; // "USD" |
| |
| |
| // ***************************************************************************** |
| // class NumberFormatTest |
| // ***************************************************************************** |
| |
| #define CHECK(status,str) if (U_FAILURE(status)) { errcheckln(status, UnicodeString("FAIL: ") + str + " - " + u_errorName(status)); return; } |
| #define CHECK_DATA(status,str) if (U_FAILURE(status)) { dataerrln(UnicodeString("FAIL: ") + str + " - " + u_errorName(status)); return; } |
| |
| void NumberFormatTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ ) |
| { |
| TESTCASE_AUTO_BEGIN; |
| TESTCASE_AUTO(TestCurrencySign); |
| TESTCASE_AUTO(TestCurrency); |
| TESTCASE_AUTO(TestParse); |
| TESTCASE_AUTO(TestRounding487); |
| TESTCASE_AUTO(TestQuotes); |
| TESTCASE_AUTO(TestExponential); |
| TESTCASE_AUTO(TestPatterns); |
| |
| // Upgrade to alphaWorks - liu 5/99 |
| TESTCASE_AUTO(TestExponent); |
| TESTCASE_AUTO(TestScientific); |
| TESTCASE_AUTO(TestPad); |
| TESTCASE_AUTO(TestPatterns2); |
| TESTCASE_AUTO(TestSecondaryGrouping); |
| TESTCASE_AUTO(TestSurrogateSupport); |
| TESTCASE_AUTO(TestAPI); |
| |
| TESTCASE_AUTO(TestCurrencyObject); |
| TESTCASE_AUTO(TestCurrencyPatterns); |
| //TESTCASE_AUTO(TestDigitList); |
| TESTCASE_AUTO(TestWhiteSpaceParsing); |
| TESTCASE_AUTO(TestComplexCurrency); // This test removed because CLDR no longer uses choice formats in currency symbols. |
| TESTCASE_AUTO(TestRegCurrency); |
| TESTCASE_AUTO(TestSymbolsWithBadLocale); |
| TESTCASE_AUTO(TestAdoptDecimalFormatSymbols); |
| |
| TESTCASE_AUTO(TestScientific2); |
| TESTCASE_AUTO(TestScientificGrouping); |
| TESTCASE_AUTO(TestInt64); |
| |
| TESTCASE_AUTO(TestPerMill); |
| TESTCASE_AUTO(TestIllegalPatterns); |
| TESTCASE_AUTO(TestCases); |
| |
| TESTCASE_AUTO(TestCurrencyNames); |
| TESTCASE_AUTO(TestCurrencyAmount); |
| TESTCASE_AUTO(TestCurrencyUnit); |
| TESTCASE_AUTO(TestCoverage); |
| TESTCASE_AUTO(TestJB3832); |
| TESTCASE_AUTO(TestHost); |
| TESTCASE_AUTO(TestHostClone); |
| TESTCASE_AUTO(TestCurrencyFormat); |
| TESTCASE_AUTO(TestRounding); |
| TESTCASE_AUTO(TestNonpositiveMultiplier); |
| TESTCASE_AUTO(TestNumberingSystems); |
| TESTCASE_AUTO(TestSpaceParsing); |
| TESTCASE_AUTO(TestMultiCurrencySign); |
| TESTCASE_AUTO(TestCurrencyFormatForMixParsing); |
| TESTCASE_AUTO(TestDecimalFormatCurrencyParse); |
| TESTCASE_AUTO(TestCurrencyIsoPluralFormat); |
| TESTCASE_AUTO(TestCurrencyParsing); |
| TESTCASE_AUTO(TestParseCurrencyInUCurr); |
| TESTCASE_AUTO(TestFormatAttributes); |
| TESTCASE_AUTO(TestFieldPositionIterator); |
| TESTCASE_AUTO(TestDecimal); |
| TESTCASE_AUTO(TestCurrencyFractionDigits); |
| TESTCASE_AUTO(TestExponentParse); |
| TESTCASE_AUTO(TestExplicitParents); |
| TESTCASE_AUTO(TestLenientParse); |
| TESTCASE_AUTO(TestAvailableNumberingSystems); |
| TESTCASE_AUTO(TestRoundingPattern); |
| TESTCASE_AUTO(Test9087); |
| TESTCASE_AUTO(TestFormatFastpaths); |
| TESTCASE_AUTO(TestFormattableSize); |
| TESTCASE_AUTO(TestUFormattable); |
| TESTCASE_AUTO(TestSignificantDigits); |
| TESTCASE_AUTO(TestShowZero); |
| TESTCASE_AUTO(TestCompatibleCurrencies); |
| TESTCASE_AUTO(TestBug9936); |
| TESTCASE_AUTO(TestParseNegativeWithFaLocale); |
| TESTCASE_AUTO(TestParseNegativeWithAlternateMinusSign); |
| TESTCASE_AUTO(TestCustomCurrencySignAndSeparator); |
| TESTCASE_AUTO(TestParseSignsAndMarks); |
| TESTCASE_AUTO(Test10419RoundingWith0FractionDigits); |
| TESTCASE_AUTO(Test10468ApplyPattern); |
| TESTCASE_AUTO(TestRoundingScientific10542); |
| TESTCASE_AUTO(TestZeroScientific10547); |
| 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(TestCtorApplyPatternDifference); |
| TESTCASE_AUTO(TestFractionalDigitsForCurrency); |
| TESTCASE_AUTO(TestFormatCurrencyPlural); |
| TESTCASE_AUTO(Test11868); |
| TESTCASE_AUTO(Test10727_RoundingZero); |
| TESTCASE_AUTO(Test11376_getAndSetPositivePrefix); |
| TESTCASE_AUTO(Test11475_signRecognition); |
| TESTCASE_AUTO(Test11640_getAffixes); |
| TESTCASE_AUTO(Test11649_toPatternWithMultiCurrency); |
| TESTCASE_AUTO_END; |
| } |
| |
| // ------------------------------------- |
| |
| // Test API (increase code coverage) |
| void |
| NumberFormatTest::TestAPI(void) |
| { |
| logln("Test API"); |
| UErrorCode status = U_ZERO_ERROR; |
| NumberFormat *test = NumberFormat::createInstance("root", status); |
| if(U_FAILURE(status)) { |
| dataerrln("unable to create format object - %s", u_errorName(status)); |
| } |
| if(test != NULL) { |
| test->setMinimumIntegerDigits(10); |
| test->setMaximumIntegerDigits(2); |
| |
| test->setMinimumFractionDigits(10); |
| test->setMaximumFractionDigits(2); |
| |
| UnicodeString result; |
| FieldPosition pos; |
| Formattable bla("Paja Patak"); // Donald Duck for non Serbian speakers |
| test->format(bla, result, pos, status); |
| if(U_SUCCESS(status)) { |
| errln("Yuck... Formatted a duck... As a number!"); |
| } else { |
| status = U_ZERO_ERROR; |
| } |
| |
| result.remove(); |
| int64_t ll = 12; |
| test->format(ll, result); |
| if (result != "12.00"){ |
| errln("format int64_t error"); |
| } |
| |
| ParsePosition ppos; |
| LocalPointer<CurrencyAmount> currAmt(test->parseCurrency("",ppos)); |
| // old test for (U_FAILURE(status)) was bogus here, method does not set status! |
| if (ppos.getIndex()) { |
| errln("Parsed empty string as currency"); |
| } |
| |
| delete test; |
| } |
| } |
| |
| class StubNumberFormat :public NumberFormat{ |
| public: |
| StubNumberFormat(){}; |
| virtual UnicodeString& format(double ,UnicodeString& appendTo,FieldPosition& ) const { |
| return appendTo; |
| } |
| virtual UnicodeString& format(int32_t ,UnicodeString& appendTo,FieldPosition& ) const { |
| return appendTo.append((UChar)0x0033); |
| } |
| virtual UnicodeString& format(int64_t number,UnicodeString& appendTo,FieldPosition& pos) const { |
| return NumberFormat::format(number, appendTo, pos); |
| } |
| virtual UnicodeString& format(const Formattable& , UnicodeString& appendTo, FieldPosition& , UErrorCode& ) const { |
| return appendTo; |
| } |
| virtual void parse(const UnicodeString& , |
| Formattable& , |
| ParsePosition& ) const {} |
| virtual void parse( const UnicodeString& , |
| Formattable& , |
| UErrorCode& ) const {} |
| virtual UClassID getDynamicClassID(void) const { |
| static char classID = 0; |
| return (UClassID)&classID; |
| } |
| virtual Format* clone() const {return NULL;} |
| }; |
| |
| void |
| NumberFormatTest::TestCoverage(void){ |
| StubNumberFormat stub; |
| UnicodeString agent("agent"); |
| FieldPosition pos; |
| int64_t num = 4; |
| if (stub.format(num, agent, pos) != UnicodeString("agent3")){ |
| errln("NumberFormat::format(int64, UnicodString&, FieldPosition&) should delegate to (int32, ,)"); |
| }; |
| } |
| |
| // Test various patterns |
| void |
| NumberFormatTest::TestPatterns(void) |
| { |
| UErrorCode status = U_ZERO_ERROR; |
| DecimalFormatSymbols sym(Locale::getUS(), status); |
| if (U_FAILURE(status)) { errcheckln(status, "FAIL: Could not construct DecimalFormatSymbols - %s", u_errorName(status)); return; } |
| |
| const char* pat[] = { "#.#", "#.", ".#", "#" }; |
| int32_t pat_length = (int32_t)(sizeof(pat) / sizeof(pat[0])); |
| const char* newpat[] = { "#0.#", "#0.", "#.0", "#" }; |
| const char* num[] = { "0", "0.", ".0", "0" }; |
| for (int32_t i=0; i<pat_length; ++i) |
| { |
| status = U_ZERO_ERROR; |
| DecimalFormat fmt(pat[i], sym, status); |
| if (U_FAILURE(status)) { errln((UnicodeString)"FAIL: DecimalFormat constructor failed for " + pat[i]); continue; } |
| UnicodeString newp; fmt.toPattern(newp); |
| if (!(newp == newpat[i])) |
| errln((UnicodeString)"FAIL: Pattern " + pat[i] + " should transmute to " + newpat[i] + |
| "; " + newp + " seen instead"); |
| |
| UnicodeString s; (*(NumberFormat*)&fmt).format((int32_t)0, s); |
| if (!(s == num[i])) |
| { |
| errln((UnicodeString)"FAIL: Pattern " + pat[i] + " should format zero as " + num[i] + |
| "; " + s + " seen instead"); |
| logln((UnicodeString)"Min integer digits = " + fmt.getMinimumIntegerDigits()); |
| } |
| } |
| } |
| |
| /* |
| icu_2_4::DigitList::operator== 0 0 2 icuuc24d.dll digitlst.cpp Doug |
| icu_2_4::DigitList::append 0 0 4 icuin24d.dll digitlst.h Doug |
| icu_2_4::DigitList::operator!= 0 0 1 icuuc24d.dll digitlst.h Doug |
| */ |
| /* |
| void |
| NumberFormatTest::TestDigitList(void) |
| { |
| // API coverage for DigitList |
| DigitList list1; |
| list1.append('1'); |
| list1.fDecimalAt = 1; |
| DigitList list2; |
| list2.set((int32_t)1); |
| if (list1 != list2) { |
| errln("digitlist append, operator!= or set failed "); |
| } |
| if (!(list1 == list2)) { |
| errln("digitlist append, operator== or set failed "); |
| } |
| } |
| */ |
| |
| // ------------------------------------- |
| |
| // Test exponential pattern |
| void |
| NumberFormatTest::TestExponential(void) |
| { |
| UErrorCode status = U_ZERO_ERROR; |
| DecimalFormatSymbols sym(Locale::getUS(), status); |
| if (U_FAILURE(status)) { errcheckln(status, "FAIL: Bad status returned by DecimalFormatSymbols ct - %s", u_errorName(status)); return; } |
| const char* pat[] = { "0.####E0", "00.000E00", "##0.######E000", "0.###E0;[0.###E0]" }; |
| int32_t pat_length = (int32_t)(sizeof(pat) / sizeof(pat[0])); |
| |
| // The following #if statements allow this test to be built and run on |
| // platforms that do not have standard IEEE numerics. For example, |
| // S/390 doubles have an exponent range of -78 to +75. For the |
| // following #if statements to work, float.h must define |
| // DBL_MAX_10_EXP to be a compile-time constant. |
| |
| // This section may be expanded as needed. |
| |
| #if DBL_MAX_10_EXP > 300 |
| double val[] = { 0.01234, 123456789, 1.23e300, -3.141592653e-271 }; |
| int32_t val_length = (int32_t)(sizeof(val) / sizeof(val[0])); |
| const char* valFormat[] = |
| { |
| // 0.####E0 |
| "1.234E-2", "1.2346E8", "1.23E300", "-3.1416E-271", |
| // 00.000E00 |
| "12.340E-03", "12.346E07", "12.300E299", "-31.416E-272", |
| // ##0.######E000 |
| "12.34E-003", "123.4568E006", "1.23E300", "-314.1593E-273", |
| // 0.###E0;[0.###E0] |
| "1.234E-2", "1.235E8", "1.23E300", "[3.142E-271]" |
| }; |
| double valParse[] = |
| { |
| 0.01234, 123460000, 1.23E300, -3.1416E-271, |
| 0.01234, 123460000, 1.23E300, -3.1416E-271, |
| 0.01234, 123456800, 1.23E300, -3.141593E-271, |
| 0.01234, 123500000, 1.23E300, -3.142E-271, |
| }; |
| #elif DBL_MAX_10_EXP > 70 |
| double val[] = { 0.01234, 123456789, 1.23e70, -3.141592653e-71 }; |
| int32_t val_length = sizeof(val) / sizeof(val[0]); |
| char* valFormat[] = |
| { |
| // 0.####E0 |
| "1.234E-2", "1.2346E8", "1.23E70", "-3.1416E-71", |
| // 00.000E00 |
| "12.340E-03", "12.346E07", "12.300E69", "-31.416E-72", |
| // ##0.######E000 |
| "12.34E-003", "123.4568E006", "12.3E069", "-31.41593E-072", |
| // 0.###E0;[0.###E0] |
| "1.234E-2", "1.235E8", "1.23E70", "[3.142E-71]" |
| }; |
| double valParse[] = |
| { |
| 0.01234, 123460000, 1.23E70, -3.1416E-71, |
| 0.01234, 123460000, 1.23E70, -3.1416E-71, |
| 0.01234, 123456800, 1.23E70, -3.141593E-71, |
| 0.01234, 123500000, 1.23E70, -3.142E-71, |
| }; |
| #else |
| // Don't test double conversion |
| double* val = 0; |
| int32_t val_length = 0; |
| char** valFormat = 0; |
| double* valParse = 0; |
| logln("Warning: Skipping double conversion tests"); |
| #endif |
| |
| int32_t lval[] = { 0, -1, 1, 123456789 }; |
| int32_t lval_length = (int32_t)(sizeof(lval) / sizeof(lval[0])); |
| const char* lvalFormat[] = |
| { |
| // 0.####E0 |
| "0E0", "-1E0", "1E0", "1.2346E8", |
| // 00.000E00 |
| "00.000E00", "-10.000E-01", "10.000E-01", "12.346E07", |
| // ##0.######E000 |
| "0E000", "-1E000", "1E000", "123.4568E006", |
| // 0.###E0;[0.###E0] |
| "0E0", "[1E0]", "1E0", "1.235E8" |
| }; |
| int32_t lvalParse[] = |
| { |
| 0, -1, 1, 123460000, |
| 0, -1, 1, 123460000, |
| 0, -1, 1, 123456800, |
| 0, -1, 1, 123500000, |
| }; |
| int32_t ival = 0, ilval = 0; |
| for (int32_t p=0; p<pat_length; ++p) |
| { |
| DecimalFormat fmt(pat[p], sym, status); |
| if (U_FAILURE(status)) { errln("FAIL: Bad status returned by DecimalFormat ct"); continue; } |
| UnicodeString pattern; |
| logln((UnicodeString)"Pattern \"" + pat[p] + "\" -toPattern-> \"" + |
| fmt.toPattern(pattern) + "\""); |
| int32_t v; |
| for (v=0; v<val_length; ++v) |
| { |
| UnicodeString s; (*(NumberFormat*)&fmt).format(val[v], s); |
| logln((UnicodeString)" " + val[v] + " -format-> " + s); |
| if (s != valFormat[v+ival]) |
| errln((UnicodeString)"FAIL: Expected " + valFormat[v+ival]); |
| |
| ParsePosition pos(0); |
| Formattable af; |
| fmt.parse(s, af, pos); |
| double a; |
| UBool useEpsilon = FALSE; |
| if (af.getType() == Formattable::kLong) |
| a = af.getLong(); |
| else if (af.getType() == Formattable::kDouble) { |
| a = af.getDouble(); |
| #if U_PF_OS390 <= U_PLATFORM && U_PLATFORM <= U_PF_OS400 |
| // S/390 will show a failure like this: |
| //| -3.141592652999999e-271 -format-> -3.1416E-271 |
| //| -parse-> -3.1416e-271 |
| //| FAIL: Expected -3.141599999999999e-271 |
| // To compensate, we use an epsilon-based equality |
| // test on S/390 only. We don't want to do this in |
| // general because it's less exacting. |
| useEpsilon = TRUE; |
| #endif |
| } |
| else { |
| errln((UnicodeString)"FAIL: Non-numeric Formattable returned"); |
| continue; |
| } |
| if (pos.getIndex() == s.length()) |
| { |
| logln((UnicodeString)" -parse-> " + a); |
| // Use epsilon comparison as necessary |
| if ((useEpsilon && |
| (uprv_fabs(a - valParse[v+ival]) / a > (2*DBL_EPSILON))) || |
| (!useEpsilon && a != valParse[v+ival])) |
| { |
| errln((UnicodeString)"FAIL: Expected " + valParse[v+ival]); |
| } |
| } |
| else { |
| errln((UnicodeString)"FAIL: Partial parse (" + pos.getIndex() + " chars) -> " + a); |
| errln((UnicodeString)" should be (" + s.length() + " chars) -> " + valParse[v+ival]); |
| } |
| } |
| for (v=0; v<lval_length; ++v) |
| { |
| UnicodeString s; |
| (*(NumberFormat*)&fmt).format(lval[v], s); |
| logln((UnicodeString)" " + lval[v] + "L -format-> " + s); |
| if (s != lvalFormat[v+ilval]) |
| errln((UnicodeString)"ERROR: Expected " + lvalFormat[v+ilval] + " Got: " + s); |
| |
| ParsePosition pos(0); |
| Formattable af; |
| fmt.parse(s, af, pos); |
| if (af.getType() == Formattable::kLong || |
| af.getType() == Formattable::kInt64) { |
| UErrorCode status = U_ZERO_ERROR; |
| int32_t a = af.getLong(status); |
| if (pos.getIndex() == s.length()) |
| { |
| logln((UnicodeString)" -parse-> " + a); |
| if (a != lvalParse[v+ilval]) |
| errln((UnicodeString)"FAIL: Expected " + lvalParse[v+ilval]); |
| } |
| else |
| errln((UnicodeString)"FAIL: Partial parse (" + pos.getIndex() + " chars) -> " + a); |
| } |
| else |
| errln((UnicodeString)"FAIL: Non-long Formattable returned for " + s |
| + " Double: " + af.getDouble() |
| + ", Long: " + af.getLong()); |
| } |
| ival += val_length; |
| ilval += lval_length; |
| } |
| } |
| |
| void |
| NumberFormatTest::TestScientific2() { |
| // jb 2552 |
| UErrorCode status = U_ZERO_ERROR; |
| DecimalFormat* fmt = (DecimalFormat*)NumberFormat::createCurrencyInstance("en_US", status); |
| if (U_SUCCESS(status)) { |
| double num = 12.34; |
| expect(*fmt, num, "$12.34"); |
| fmt->setScientificNotation(TRUE); |
| expect(*fmt, num, "$1.23E1"); |
| fmt->setScientificNotation(FALSE); |
| expect(*fmt, num, "$12.34"); |
| } |
| delete fmt; |
| } |
| |
| void |
| NumberFormatTest::TestScientificGrouping() { |
| // jb 2552 |
| UErrorCode status = U_ZERO_ERROR; |
| DecimalFormat fmt("##0.00E0",status); |
| if (U_SUCCESS(status)) { |
| expect(fmt, .01234, "12.3E-3"); |
| expect(fmt, .1234, "123E-3"); |
| expect(fmt, 1.234, "1.23E0"); |
| expect(fmt, 12.34, "12.3E0"); |
| expect(fmt, 123.4, "123E0"); |
| expect(fmt, 1234., "1.23E3"); |
| } |
| } |
| |
| /*static void setFromString(DigitList& dl, const char* str) { |
| char c; |
| UBool decimalSet = FALSE; |
| dl.clear(); |
| while ((c = *str++)) { |
| if (c == '-') { |
| dl.fIsPositive = FALSE; |
| } else if (c == '+') { |
| dl.fIsPositive = TRUE; |
| } else if (c == '.') { |
| dl.fDecimalAt = dl.fCount; |
| decimalSet = TRUE; |
| } else { |
| dl.append(c); |
| } |
| } |
| if (!decimalSet) { |
| dl.fDecimalAt = dl.fCount; |
| } |
| }*/ |
| |
| void |
| NumberFormatTest::TestInt64() { |
| UErrorCode status = U_ZERO_ERROR; |
| DecimalFormat fmt("#.#E0",status); |
| if (U_FAILURE(status)) { |
| dataerrln("Error creating DecimalFormat - %s", u_errorName(status)); |
| return; |
| } |
| fmt.setMaximumFractionDigits(20); |
| if (U_SUCCESS(status)) { |
| expect(fmt, (Formattable)(int64_t)0, "0E0"); |
| expect(fmt, (Formattable)(int64_t)-1, "-1E0"); |
| expect(fmt, (Formattable)(int64_t)1, "1E0"); |
| expect(fmt, (Formattable)(int64_t)2147483647, "2.147483647E9"); |
| expect(fmt, (Formattable)((int64_t)-2147483647-1), "-2.147483648E9"); |
| expect(fmt, (Formattable)(int64_t)U_INT64_MAX, "9.223372036854775807E18"); |
| expect(fmt, (Formattable)(int64_t)U_INT64_MIN, "-9.223372036854775808E18"); |
| } |
| |
| // also test digitlist |
| /* int64_t int64max = U_INT64_MAX; |
| int64_t int64min = U_INT64_MIN; |
| const char* int64maxstr = "9223372036854775807"; |
| const char* int64minstr = "-9223372036854775808"; |
| UnicodeString fail("fail: "); |
| |
| // test max int64 value |
| DigitList dl; |
| setFromString(dl, int64maxstr); |
| { |
| if (!dl.fitsIntoInt64(FALSE)) { |
| errln(fail + int64maxstr + " didn't fit"); |
| } |
| int64_t int64Value = dl.getInt64(); |
| if (int64Value != int64max) { |
| errln(fail + int64maxstr); |
| } |
| dl.set(int64Value); |
| int64Value = dl.getInt64(); |
| if (int64Value != int64max) { |
| errln(fail + int64maxstr); |
| } |
| } |
| // test negative of max int64 value (1 shy of min int64 value) |
| dl.fIsPositive = FALSE; |
| { |
| if (!dl.fitsIntoInt64(FALSE)) { |
| errln(fail + "-" + int64maxstr + " didn't fit"); |
| } |
| int64_t int64Value = dl.getInt64(); |
| if (int64Value != -int64max) { |
| errln(fail + "-" + int64maxstr); |
| } |
| dl.set(int64Value); |
| int64Value = dl.getInt64(); |
| if (int64Value != -int64max) { |
| errln(fail + "-" + int64maxstr); |
| } |
| } |
| // test min int64 value |
| setFromString(dl, int64minstr); |
| { |
| if (!dl.fitsIntoInt64(FALSE)) { |
| errln(fail + "-" + int64minstr + " didn't fit"); |
| } |
| int64_t int64Value = dl.getInt64(); |
| if (int64Value != int64min) { |
| errln(fail + int64minstr); |
| } |
| dl.set(int64Value); |
| int64Value = dl.getInt64(); |
| if (int64Value != int64min) { |
| errln(fail + int64minstr); |
| } |
| } |
| // test negative of min int 64 value (1 more than max int64 value) |
| dl.fIsPositive = TRUE; // won't fit |
| { |
| if (dl.fitsIntoInt64(FALSE)) { |
| errln(fail + "-(" + int64minstr + ") didn't fit"); |
| } |
| }*/ |
| } |
| |
| // ------------------------------------- |
| |
| // Test the handling of quotes |
| void |
| NumberFormatTest::TestQuotes(void) |
| { |
| UErrorCode status = U_ZERO_ERROR; |
| UnicodeString *pat; |
| DecimalFormatSymbols *sym = new DecimalFormatSymbols(Locale::getUS(), status); |
| if (U_FAILURE(status)) { |
| errcheckln(status, "Fail to create DecimalFormatSymbols - %s", u_errorName(status)); |
| delete sym; |
| return; |
| } |
| pat = new UnicodeString("a'fo''o'b#"); |
| DecimalFormat *fmt = new DecimalFormat(*pat, *sym, status); |
| UnicodeString s; |
| ((NumberFormat*)fmt)->format((int32_t)123, s); |
| logln((UnicodeString)"Pattern \"" + *pat + "\""); |
| logln((UnicodeString)" Format 123 -> " + escape(s)); |
| if (!(s=="afo'ob123")) |
| errln((UnicodeString)"FAIL: Expected afo'ob123"); |
| |
| s.truncate(0); |
| delete fmt; |
| delete pat; |
| |
| pat = new UnicodeString("a''b#"); |
| fmt = new DecimalFormat(*pat, *sym, status); |
| ((NumberFormat*)fmt)->format((int32_t)123, s); |
| logln((UnicodeString)"Pattern \"" + *pat + "\""); |
| logln((UnicodeString)" Format 123 -> " + escape(s)); |
| if (!(s=="a'b123")) |
| errln((UnicodeString)"FAIL: Expected a'b123"); |
| delete fmt; |
| delete pat; |
| delete sym; |
| } |
| |
| /** |
| * Test the handling of the currency symbol in patterns. |
| */ |
| void |
| NumberFormatTest::TestCurrencySign(void) |
| { |
| UErrorCode status = U_ZERO_ERROR; |
| DecimalFormatSymbols* sym = new DecimalFormatSymbols(Locale::getUS(), status); |
| UnicodeString pat; |
| UChar currency = 0x00A4; |
| if (U_FAILURE(status)) { |
| errcheckln(status, "Fail to create DecimalFormatSymbols - %s", u_errorName(status)); |
| delete sym; |
| return; |
| } |
| // "\xA4#,##0.00;-\xA4#,##0.00" |
| pat.append(currency).append("#,##0.00;-"). |
| append(currency).append("#,##0.00"); |
| DecimalFormat *fmt = new DecimalFormat(pat, *sym, status); |
| UnicodeString s; ((NumberFormat*)fmt)->format(1234.56, s); |
| pat.truncate(0); |
| logln((UnicodeString)"Pattern \"" + fmt->toPattern(pat) + "\""); |
| logln((UnicodeString)" Format " + 1234.56 + " -> " + escape(s)); |
| if (s != "$1,234.56") dataerrln((UnicodeString)"FAIL: Expected $1,234.56"); |
| s.truncate(0); |
| ((NumberFormat*)fmt)->format(- 1234.56, s); |
| logln((UnicodeString)" Format " + (-1234.56) + " -> " + escape(s)); |
| if (s != "-$1,234.56") dataerrln((UnicodeString)"FAIL: Expected -$1,234.56"); |
| delete fmt; |
| pat.truncate(0); |
| // "\xA4\xA4 #,##0.00;\xA4\xA4 -#,##0.00" |
| pat.append(currency).append(currency). |
| append(" #,##0.00;"). |
| append(currency).append(currency). |
| append(" -#,##0.00"); |
| fmt = new DecimalFormat(pat, *sym, status); |
| s.truncate(0); |
| ((NumberFormat*)fmt)->format(1234.56, s); |
| logln((UnicodeString)"Pattern \"" + fmt->toPattern(pat) + "\""); |
| logln((UnicodeString)" Format " + 1234.56 + " -> " + escape(s)); |
| if (s != "USD 1,234.56") dataerrln((UnicodeString)"FAIL: Expected USD 1,234.56"); |
| s.truncate(0); |
| ((NumberFormat*)fmt)->format(-1234.56, s); |
| logln((UnicodeString)" Format " + (-1234.56) + " -> " + escape(s)); |
| if (s != "USD -1,234.56") dataerrln((UnicodeString)"FAIL: Expected USD -1,234.56"); |
| delete fmt; |
| delete sym; |
| if (U_FAILURE(status)) errln((UnicodeString)"FAIL: Status " + u_errorName(status)); |
| } |
| |
| // ------------------------------------- |
| |
| static UChar toHexString(int32_t i) { return (UChar)(i + (i < 10 ? 0x30 : (0x41 - 10))); } |
| |
| UnicodeString& |
| NumberFormatTest::escape(UnicodeString& s) |
| { |
| UnicodeString buf; |
| for (int32_t i=0; i<s.length(); ++i) |
| { |
| UChar c = s[(int32_t)i]; |
| if (c <= (UChar)0x7F) buf += c; |
| else { |
| buf += (UChar)0x5c; buf += (UChar)0x55; |
| buf += toHexString((c & 0xF000) >> 12); |
| buf += toHexString((c & 0x0F00) >> 8); |
| buf += toHexString((c & 0x00F0) >> 4); |
| buf += toHexString(c & 0x000F); |
| } |
| } |
| return (s = buf); |
| } |
| |
| |
| // ------------------------------------- |
| static const char* testCases[][2]= { |
| /* locale ID */ /* expected */ |
| {"ca_ES_PREEURO", "\\u20A7\\u00A01.150" }, |
| {"de_LU_PREEURO", "1,150\\u00A0F" }, |
| {"el_GR_PREEURO", "1.150,50\\u00A0\\u0394\\u03C1\\u03C7" }, |
| {"en_BE_PREEURO", "1.150,50\\u00A0BEF" }, |
| {"es_ES_PREEURO", "1.150\\u00A0\\u20A7" }, |
| {"eu_ES_PREEURO", "\\u20A7\\u00A01.150" }, |
| {"gl_ES_PREEURO", "1.150\\u00A0\\u20A7" }, |
| {"it_IT_PREEURO", "ITL\\u00A01.150" }, |
| {"pt_PT_PREEURO", "1,150$50\\u00A0\\u200B"}, // per cldrbug 7670 |
| {"en_US@currency=JPY", "\\u00A51,150"}, |
| {"en_US@currency=jpy", "\\u00A51,150"}, |
| {"en-US-u-cu-jpy", "\\u00A51,150"} |
| }; |
| /** |
| * Test localized currency patterns. |
| */ |
| void |
| NumberFormatTest::TestCurrency(void) |
| { |
| UErrorCode status = U_ZERO_ERROR; |
| NumberFormat* currencyFmt = NumberFormat::createCurrencyInstance(Locale::getCanadaFrench(), status); |
| if (U_FAILURE(status)) { |
| dataerrln("Error calling NumberFormat::createCurrencyInstance()"); |
| return; |
| } |
| |
| 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>$"); |
| delete currencyFmt; |
| s.truncate(0); |
| char loc[256]={0}; |
| int len = uloc_canonicalize("de_DE_PREEURO", loc, 256, &status); |
| (void)len; // Suppress unused variable warning. |
| currencyFmt = NumberFormat::createCurrencyInstance(Locale(loc),status); |
| 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"); |
| delete currencyFmt; |
| s.truncate(0); |
| len = uloc_canonicalize("fr_FR_PREEURO", loc, 256, &status); |
| currencyFmt = NumberFormat::createCurrencyInstance(Locale(loc), status); |
| currencyFmt->format(1.50, s); |
| logln((UnicodeString)"Un pauvre en France a....." + s); |
| if (!(s==CharsToUnicodeString("1,50\\u00A0F"))) |
| errln((UnicodeString)"FAIL: Expected 1,50<nbsp>F"); |
| delete currencyFmt; |
| if (U_FAILURE(status)) |
| errln((UnicodeString)"FAIL: Status " + (int32_t)status); |
| |
| for(int i=0; i < (int)(sizeof(testCases)/sizeof(testCases[i])); i++){ |
| status = U_ZERO_ERROR; |
| const char *localeID = testCases[i][0]; |
| UnicodeString expected(testCases[i][1], -1, US_INV); |
| expected = expected.unescape(); |
| s.truncate(0); |
| char loc[256]={0}; |
| uloc_canonicalize(localeID, loc, 256, &status); |
| currencyFmt = NumberFormat::createCurrencyInstance(Locale(loc), status); |
| if(U_FAILURE(status)){ |
| errln("Could not create currency formatter for locale %s",localeID); |
| continue; |
| } |
| currencyFmt->format(1150.50, s); |
| if(s!=expected){ |
| errln(UnicodeString("FAIL: Expected: ")+expected |
| + UnicodeString(" Got: ") + s |
| + UnicodeString( " for locale: ")+ UnicodeString(localeID) ); |
| } |
| if (U_FAILURE(status)){ |
| errln((UnicodeString)"FAIL: Status " + (int32_t)status); |
| } |
| delete currencyFmt; |
| } |
| } |
| |
| // ------------------------------------- |
| |
| /** |
| * Test the Currency object handling, new as of ICU 2.2. |
| */ |
| void NumberFormatTest::TestCurrencyObject() { |
| UErrorCode ec = U_ZERO_ERROR; |
| NumberFormat* fmt = |
| NumberFormat::createCurrencyInstance(Locale::getUS(), ec); |
| |
| if (U_FAILURE(ec)) { |
| dataerrln("FAIL: getCurrencyInstance(US) - %s", u_errorName(ec)); |
| delete fmt; |
| return; |
| } |
| |
| Locale null("", "", ""); |
| |
| expectCurrency(*fmt, null, 1234.56, "$1,234.56"); |
| |
| expectCurrency(*fmt, Locale::getFrance(), |
| 1234.56, CharsToUnicodeString("\\u20AC1,234.56")); // Euro |
| |
| expectCurrency(*fmt, Locale::getJapan(), |
| 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 |
| |
| expectCurrency(*fmt, Locale::getUS(), |
| 1234.56, "$1,234.56"); |
| |
| delete fmt; |
| fmt = NumberFormat::createCurrencyInstance(Locale::getFrance(), ec); |
| |
| if (U_FAILURE(ec)) { |
| errln("FAIL: getCurrencyInstance(FRANCE)"); |
| delete fmt; |
| return; |
| } |
| |
| expectCurrency(*fmt, null, 1234.56, CharsToUnicodeString("1 234,56 \\u20AC")); |
| |
| expectCurrency(*fmt, Locale::getJapan(), |
| 1234.56, CharsToUnicodeString("1 235 JPY")); // Yen |
| |
| expectCurrency(*fmt, Locale("fr", "CH", ""), |
| 1234.56, "1 234,56 CHF"); // no more 0.05 rounding here, see cldrbug 5548 |
| |
| expectCurrency(*fmt, Locale::getUS(), |
| 1234.56, "1 234,56 $US"); |
| |
| expectCurrency(*fmt, Locale::getFrance(), |
| 1234.56, CharsToUnicodeString("1 234,56 \\u20AC")); // Euro |
| |
| delete fmt; |
| } |
| |
| // ------------------------------------- |
| |
| /** |
| * Do rudimentary testing of parsing. |
| */ |
| void |
| NumberFormatTest::TestParse(void) |
| { |
| UErrorCode status = U_ZERO_ERROR; |
| UnicodeString arg("0"); |
| DecimalFormat* format = new DecimalFormat("00", status); |
| //try { |
| Formattable n; format->parse(arg, n, status); |
| logln((UnicodeString)"parse(" + arg + ") = " + n.getLong()); |
| if (n.getType() != Formattable::kLong || |
| n.getLong() != 0) errln((UnicodeString)"FAIL: Expected 0"); |
| delete format; |
| if (U_FAILURE(status)) errcheckln(status, (UnicodeString)"FAIL: Status " + u_errorName(status)); |
| //} |
| //catch(Exception e) { |
| // errln((UnicodeString)"Exception caught: " + e); |
| //} |
| } |
| |
| // ------------------------------------- |
| |
| static const char *lenientAffixTestCases[] = { |
| "(1)", |
| "( 1)", |
| "(1 )", |
| "( 1 )" |
| }; |
| |
| static const char *lenientMinusTestCases[] = { |
| "-5", |
| "\\u22125", |
| "\\u20105" |
| }; |
| |
| static const char *lenientCurrencyTestCases[] = { |
| "$1,000", |
| "$ 1,000", |
| "$1000", |
| "$ 1000", |
| "$1 000.00", |
| "$ 1 000.00", |
| "$ 1\\u00A0000.00", |
| "1000.00" |
| }; |
| |
| // changed from () to - per cldrbug 5674 |
| static const char *lenientNegativeCurrencyTestCases[] = { |
| "-$1,000", |
| "-$ 1,000", |
| "-$1000", |
| "-$ 1000", |
| "-$1 000.00", |
| "-$ 1 000.00", |
| "- $ 1,000.00 ", |
| "-$ 1\\u00A0000.00", |
| "-1000.00" |
| }; |
| |
| static const char *lenientPercentTestCases[] = { |
| "25%", |
| " 25%", |
| " 25 %", |
| "25 %", |
| "25\\u00A0%", |
| "25" |
| }; |
| |
| static const char *lenientNegativePercentTestCases[] = { |
| "-25%", |
| " -25%", |
| " - 25%", |
| "- 25 %", |
| " - 25 %", |
| "-25 %", |
| "-25\\u00A0%", |
| "-25", |
| "- 25" |
| }; |
| |
| static const char *strictFailureTestCases[] = { |
| " 1000", |
| "10,00", |
| "1,000,.0" |
| }; |
| |
| #define ARRAY_SIZE(array) ((int32_t) (sizeof (array) / sizeof(array[0]))) |
| |
| /** |
| * Test lenient parsing. |
| */ |
| void |
| NumberFormatTest::TestLenientParse(void) |
| { |
| UErrorCode status = U_ZERO_ERROR; |
| DecimalFormat *format = new DecimalFormat("(#,##0)", status); |
| Formattable n; |
| |
| if (format == NULL || U_FAILURE(status)) { |
| dataerrln("Unable to create DecimalFormat (#,##0) - %s", u_errorName(status)); |
| } else { |
| format->setLenient(TRUE); |
| for (int32_t t = 0; t < ARRAY_SIZE (lenientAffixTestCases); t += 1) { |
| UnicodeString testCase = ctou(lenientAffixTestCases[t]); |
| |
| format->parse(testCase, n, status); |
| logln((UnicodeString)"parse(" + testCase + ") = " + n.getLong()); |
| |
| if (U_FAILURE(status) || n.getType() != Formattable::kLong || |
| n.getLong() != 1) { |
| errln((UnicodeString)"Lenient parse failed for \"" + (UnicodeString) lenientAffixTestCases[t] + (UnicodeString) "\""); |
| status = U_ZERO_ERROR; |
| } |
| } |
| delete format; |
| } |
| |
| 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 < ARRAY_SIZE(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) "\""); |
| 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 < ARRAY_SIZE(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) "\""); |
| status = U_ZERO_ERROR; |
| } |
| } |
| delete mFormat; |
| } |
| |
| NumberFormat *cFormat = NumberFormat::createInstance(en_US, UNUM_CURRENCY, status); |
| |
| if (cFormat == NULL || U_FAILURE(status)) { |
| dataerrln("Unable to create NumberFormat (en_US, UNUM_CURRENCY) - %s", u_errorName(status)); |
| } else { |
| cFormat->setLenient(TRUE); |
| for (int32_t t = 0; t < ARRAY_SIZE (lenientCurrencyTestCases); t += 1) { |
| UnicodeString testCase = ctou(lenientCurrencyTestCases[t]); |
| |
| cFormat->parse(testCase, n, status); |
| logln((UnicodeString)"parse(" + testCase + ") = " + n.getLong()); |
| |
| if (U_FAILURE(status) ||n.getType() != Formattable::kLong || |
| n.getLong() != 1000) { |
| errln((UnicodeString)"Lenient parse failed for \"" + (UnicodeString) lenientCurrencyTestCases[t] + (UnicodeString) "\""); |
| status = U_ZERO_ERROR; |
| } |
| } |
| |
| for (int32_t t = 0; t < ARRAY_SIZE (lenientNegativeCurrencyTestCases); t += 1) { |
| UnicodeString testCase = ctou(lenientNegativeCurrencyTestCases[t]); |
| |
| cFormat->parse(testCase, n, status); |
| logln((UnicodeString)"parse(" + testCase + ") = " + n.getLong()); |
| |
| if (U_FAILURE(status) ||n.getType() != Formattable::kLong || |
| n.getLong() != -1000) { |
| errln((UnicodeString)"Lenient parse failed for \"" + (UnicodeString) lenientNegativeCurrencyTestCases[t] + (UnicodeString) "\""); |
| status = U_ZERO_ERROR; |
| } |
| } |
| |
| delete cFormat; |
| } |
| |
| NumberFormat *pFormat = NumberFormat::createPercentInstance(en_US, status); |
| |
| if (pFormat == NULL || U_FAILURE(status)) { |
| dataerrln("Unable to create NumberFormat::createPercentInstance (en_US) - %s", u_errorName(status)); |
| } else { |
| pFormat->setLenient(TRUE); |
| for (int32_t t = 0; t < ARRAY_SIZE (lenientPercentTestCases); t += 1) { |
| UnicodeString testCase = ctou(lenientPercentTestCases[t]); |
| |
| pFormat->parse(testCase, n, status); |
| logln((UnicodeString)"parse(" + testCase + ") = " + n.getDouble()); |
| |
| if (U_FAILURE(status) ||n.getType() != Formattable::kDouble || |
| n.getDouble() != 0.25) { |
| errln((UnicodeString)"Lenient parse failed for \"" + (UnicodeString) lenientPercentTestCases[t] + (UnicodeString) "\""); |
| status = U_ZERO_ERROR; |
| } |
| } |
| |
| for (int32_t t = 0; t < ARRAY_SIZE (lenientNegativePercentTestCases); t += 1) { |
| UnicodeString testCase = ctou(lenientNegativePercentTestCases[t]); |
| |
| pFormat->parse(testCase, n, status); |
| logln((UnicodeString)"parse(" + testCase + ") = " + n.getDouble()); |
| |
| if (U_FAILURE(status) ||n.getType() != Formattable::kDouble || |
| n.getDouble() != -0.25) { |
| errln((UnicodeString)"Lenient parse failed for \"" + (UnicodeString) lenientNegativePercentTestCases[t] + (UnicodeString) "\""); |
| status = U_ZERO_ERROR; |
| } |
| } |
| |
| delete pFormat; |
| } |
| |
| // 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 { |
| // first, make sure that they fail with a strict parse |
| for (int32_t t = 0; t < ARRAY_SIZE(strictFailureTestCases); t += 1) { |
| UnicodeString testCase = ctou(strictFailureTestCases[t]); |
| |
| nFormat->parse(testCase, n, status); |
| logln((UnicodeString)"parse(" + testCase + ") = " + n.getLong()); |
| |
| if (! U_FAILURE(status)) { |
| errln((UnicodeString)"Strict Parse succeeded for \"" + (UnicodeString) strictFailureTestCases[t] + (UnicodeString) "\""); |
| } |
| |
| status = U_ZERO_ERROR; |
| } |
| |
| // then, make sure that they pass with a lenient parse |
| nFormat->setLenient(TRUE); |
| for (int32_t t = 0; t < ARRAY_SIZE(strictFailureTestCases); t += 1) { |
| UnicodeString testCase = ctou(strictFailureTestCases[t]); |
| |
| nFormat->parse(testCase, n, status); |
| logln((UnicodeString)"parse(" + testCase + ") = " + n.getLong()); |
| |
| if (U_FAILURE(status) ||n.getType() != Formattable::kLong || |
| n.getLong() != 1000) { |
| errln((UnicodeString)"Lenient parse failed for \"" + (UnicodeString) strictFailureTestCases[t] + (UnicodeString) "\""); |
| status = U_ZERO_ERROR; |
| } |
| } |
| |
| delete nFormat; |
| } |
| } |
| |
| // ------------------------------------- |
| |
| /** |
| * Test proper rounding by the format method. |
| */ |
| void |
| NumberFormatTest::TestRounding487(void) |
| { |
| UErrorCode status = U_ZERO_ERROR; |
| NumberFormat *nf = NumberFormat::createInstance(status); |
| if (U_FAILURE(status)) { |
| dataerrln("Error calling NumberFormat::createInstance()"); |
| return; |
| } |
| |
| roundingTest(*nf, 0.00159999, 4, "0.0016"); |
| roundingTest(*nf, 0.00995, 4, "0.01"); |
| |
| roundingTest(*nf, 12.3995, 3, "12.4"); |
| |
| roundingTest(*nf, 12.4999, 0, "12"); |
| roundingTest(*nf, - 19.5, 0, "-20"); |
| delete nf; |
| if (U_FAILURE(status)) errln((UnicodeString)"FAIL: Status " + (int32_t)status); |
| } |
| |
| /** |
| * Test the functioning of the secondary grouping value. |
| */ |
| void NumberFormatTest::TestSecondaryGrouping(void) { |
| UErrorCode status = U_ZERO_ERROR; |
| DecimalFormatSymbols US(Locale::getUS(), status); |
| CHECK(status, "DecimalFormatSymbols ct"); |
| |
| DecimalFormat f("#,##,###", US, status); |
| CHECK(status, "DecimalFormat ct"); |
| |
| expect2(f, (int32_t)123456789L, "12,34,56,789"); |
| expectPat(f, "#,##,###"); |
| f.applyPattern("#,###", status); |
| CHECK(status, "applyPattern"); |
| |
| f.setSecondaryGroupingSize(4); |
| expect2(f, (int32_t)123456789L, "12,3456,789"); |
| expectPat(f, "#,####,###"); |
| NumberFormat *g = NumberFormat::createInstance(Locale("hi", "IN"), status); |
| CHECK_DATA(status, "createInstance(hi_IN)"); |
| |
| UnicodeString out; |
| int32_t l = (int32_t)1876543210L; |
| g->format(l, out); |
| delete g; |
| // expect "1,87,65,43,210", but with Hindi digits |
| // 01234567890123 |
| UBool ok = TRUE; |
| if (out.length() != 14) { |
| ok = FALSE; |
| } else { |
| for (int32_t i=0; i<out.length(); ++i) { |
| UBool expectGroup = FALSE; |
| switch (i) { |
| case 1: |
| case 4: |
| case 7: |
| case 10: |
| expectGroup = TRUE; |
| break; |
| } |
| // Later -- fix this to get the actual grouping |
| // character from the resource bundle. |
| UBool isGroup = (out.charAt(i) == 0x002C); |
| if (isGroup != expectGroup) { |
| ok = FALSE; |
| break; |
| } |
| } |
| } |
| if (!ok) { |
| errln((UnicodeString)"FAIL Expected " + l + |
| " x hi_IN -> \"1,87,65,43,210\" (with Hindi digits), got \"" + |
| escape(out) + "\""); |
| } else { |
| logln((UnicodeString)"Ok " + l + |
| " x hi_IN -> \"" + |
| escape(out) + "\""); |
| } |
| } |
| |
| void NumberFormatTest::TestWhiteSpaceParsing(void) { |
| UErrorCode ec = U_ZERO_ERROR; |
| DecimalFormatSymbols US(Locale::getUS(), ec); |
| DecimalFormat fmt("a b#0c ", US, ec); |
| if (U_FAILURE(ec)) { |
| errcheckln(ec, "FAIL: Constructor - %s", u_errorName(ec)); |
| return; |
| } |
| int32_t n = 1234; |
| expect(fmt, "a b1234c ", n); |
| expect(fmt, "a b1234c ", n); |
| } |
| |
| /** |
| * Test currencies whose display name is a ChoiceFormat. |
| */ |
| void NumberFormatTest::TestComplexCurrency() { |
| |
| // UErrorCode ec = U_ZERO_ERROR; |
| // Locale loc("kn", "IN", ""); |
| // NumberFormat* fmt = NumberFormat::createCurrencyInstance(loc, ec); |
| // if (U_SUCCESS(ec)) { |
| // expect2(*fmt, 1.0, CharsToUnicodeString("Re.\\u00A01.00")); |
| // Use .00392625 because that's 2^-8. Any value less than 0.005 is fine. |
| // expect(*fmt, 1.00390625, CharsToUnicodeString("Re.\\u00A01.00")); // tricky |
| // expect2(*fmt, 12345678.0, CharsToUnicodeString("Rs.\\u00A01,23,45,678.00")); |
| // expect2(*fmt, 0.5, CharsToUnicodeString("Rs.\\u00A00.50")); |
| // expect2(*fmt, -1.0, CharsToUnicodeString("-Re.\\u00A01.00")); |
| // expect2(*fmt, -10.0, CharsToUnicodeString("-Rs.\\u00A010.00")); |
| // } else { |
| // errln("FAIL: getCurrencyInstance(kn_IN)"); |
| // } |
| // delete fmt; |
| |
| } |
| |
| // ------------------------------------- |
| |
| void |
| NumberFormatTest::roundingTest(NumberFormat& nf, double x, int32_t maxFractionDigits, const char* expected) |
| { |
| nf.setMaximumFractionDigits(maxFractionDigits); |
| UnicodeString out; nf.format(x, out); |
| logln((UnicodeString)"" + x + " formats with " + maxFractionDigits + " fractional digits to " + out); |
| if (!(out==expected)) errln((UnicodeString)"FAIL: Expected " + expected); |
| } |
| |
| /** |
| * Upgrade to alphaWorks |
| */ |
| void NumberFormatTest::TestExponent(void) { |
| UErrorCode status = U_ZERO_ERROR; |
| DecimalFormatSymbols US(Locale::getUS(), status); |
| CHECK(status, "DecimalFormatSymbols constructor"); |
| DecimalFormat fmt1(UnicodeString("0.###E0"), US, status); |
| CHECK(status, "DecimalFormat(0.###E0)"); |
| DecimalFormat fmt2(UnicodeString("0.###E+0"), US, status); |
| CHECK(status, "DecimalFormat(0.###E+0)"); |
| int32_t n = 1234; |
| expect2(fmt1, n, "1.234E3"); |
| expect2(fmt2, n, "1.234E+3"); |
| expect(fmt1, "1.234E+3", n); // Either format should parse "E+3" |
| } |
| |
| /** |
| * Upgrade to alphaWorks |
| */ |
| void NumberFormatTest::TestScientific(void) { |
| UErrorCode status = U_ZERO_ERROR; |
| DecimalFormatSymbols US(Locale::getUS(), status); |
| CHECK(status, "DecimalFormatSymbols constructor"); |
| |
| // Test pattern round-trip |
| const char* PAT[] = { "#E0", "0.####E0", "00.000E00", "##0.####E000", |
| "0.###E0;[0.###E0]" }; |
| int32_t PAT_length = (int32_t)(sizeof(PAT) / sizeof(PAT[0])); |
| int32_t DIGITS[] = { |
| // min int, max int, min frac, max frac |
| 0, 1, 0, 0, // "#E0" |
| 1, 1, 0, 4, // "0.####E0" |
| 2, 2, 3, 3, // "00.000E00" |
| 1, 3, 0, 4, // "##0.####E000" |
| 1, 1, 0, 3, // "0.###E0;[0.###E0]" |
| }; |
| for (int32_t i=0; i<PAT_length; ++i) { |
| UnicodeString pat(PAT[i]); |
| DecimalFormat df(pat, US, status); |
| CHECK(status, "DecimalFormat constructor"); |
| UnicodeString pat2; |
| df.toPattern(pat2); |
| if (pat == pat2) { |
| logln(UnicodeString("Ok Pattern rt \"") + |
| pat + "\" -> \"" + |
| pat2 + "\""); |
| } else { |
| errln(UnicodeString("FAIL Pattern rt \"") + |
| pat + "\" -> \"" + |
| pat2 + "\""); |
| } |
| // Make sure digit counts match what we expect |
| if (df.getMinimumIntegerDigits() != DIGITS[4*i] || |
| df.getMaximumIntegerDigits() != DIGITS[4*i+1] || |
| df.getMinimumFractionDigits() != DIGITS[4*i+2] || |
| df.getMaximumFractionDigits() != DIGITS[4*i+3]) { |
| errln(UnicodeString("FAIL \"" + pat + |
| "\" min/max int; min/max frac = ") + |
| df.getMinimumIntegerDigits() + "/" + |
| df.getMaximumIntegerDigits() + ";" + |
| df.getMinimumFractionDigits() + "/" + |
| df.getMaximumFractionDigits() + ", expect " + |
| DIGITS[4*i] + "/" + |
| DIGITS[4*i+1] + ";" + |
| DIGITS[4*i+2] + "/" + |
| DIGITS[4*i+3]); |
| } |
| } |
| |
| |
| // Test the constructor for default locale. We have to |
| // manually set the default locale, as there is no |
| // guarantee that the default locale has the same |
| // scientific format. |
| Locale def = Locale::getDefault(); |
| Locale::setDefault(Locale::getUS(), status); |
| expect2(NumberFormat::createScientificInstance(status), |
| 12345.678901, |
| "1.2345678901E4", status); |
| Locale::setDefault(def, status); |
| |
| expect2(new DecimalFormat("#E0", US, status), |
| 12345.0, |
| "1.2345E4", status); |
| expect(new DecimalFormat("0E0", US, status), |
| 12345.0, |
| "1E4", status); |
| expect2(NumberFormat::createScientificInstance(Locale::getUS(), status), |
| 12345.678901, |
| "1.2345678901E4", status); |
| expect(new DecimalFormat("##0.###E0", US, status), |
| 12345.0, |
| "12.34E3", status); |
| expect(new DecimalFormat("##0.###E0", US, status), |
| 12345.00001, |
| "12.35E3", status); |
| expect2(new DecimalFormat("##0.####E0", US, status), |
| (int32_t) 12345, |
| "12.345E3", status); |
| expect2(NumberFormat::createScientificInstance(Locale::getFrance(), status), |
| 12345.678901, |
| "1,2345678901E4", status); |
| expect(new DecimalFormat("##0.####E0", US, status), |
| 789.12345e-9, |
| "789.12E-9", status); |
| expect2(new DecimalFormat("##0.####E0", US, status), |
| 780.e-9, |
| "780E-9", status); |
| expect(new DecimalFormat(".###E0", US, status), |
| 45678.0, |
| ".457E5", status); |
| expect2(new DecimalFormat(".###E0", US, status), |
| (int32_t) 0, |
| ".0E0", status); |
| /* |
| expect(new DecimalFormat[] { new DecimalFormat("#E0", US), |
| new DecimalFormat("##E0", US), |
| new DecimalFormat("####E0", US), |
| new DecimalFormat("0E0", US), |
| new DecimalFormat("00E0", US), |
| new DecimalFormat("000E0", US), |
| }, |
| new Long(45678000), |
| new String[] { "4.5678E7", |
| "45.678E6", |
| "4567.8E4", |
| "5E7", |
| "46E6", |
| "457E5", |
| } |
| ); |
| ! |
| ! Unroll this test into individual tests below... |
| ! |
| */ |
| expect2(new DecimalFormat("#E0", US, status), |
| (int32_t) 45678000, "4.5678E7", status); |
| expect2(new DecimalFormat("##E0", US, status), |
| (int32_t) 45678000, "45.678E6", status); |
| expect2(new DecimalFormat("####E0", US, status), |
| (int32_t) 45678000, "4567.8E4", status); |
| expect(new DecimalFormat("0E0", US, status), |
| (int32_t) 45678000, "5E7", status); |
| expect(new DecimalFormat("00E0", US, status), |
| (int32_t) 45678000, "46E6", status); |
| expect(new DecimalFormat("000E0", US, status), |
| (int32_t) 45678000, "457E5", status); |
| /* |
| expect(new DecimalFormat("###E0", US, status), |
| new Object[] { new Double(0.0000123), "12.3E-6", |
| new Double(0.000123), "123E-6", |
| new Double(0.00123), "1.23E-3", |
| new Double(0.0123), "12.3E-3", |
| new Double(0.123), "123E-3", |
| new Double(1.23), "1.23E0", |
| new Double(12.3), "12.3E0", |
| new Double(123), "123E0", |
| new Double(1230), "1.23E3", |
| }); |
| ! |
| ! Unroll this test into individual tests below... |
| ! |
| */ |
| expect2(new DecimalFormat("###E0", US, status), |
| 0.0000123, "12.3E-6", status); |
| expect2(new DecimalFormat("###E0", US, status), |
| 0.000123, "123E-6", status); |
| expect2(new DecimalFormat("###E0", US, status), |
| 0.00123, "1.23E-3", status); |
| expect2(new DecimalFormat("###E0", US, status), |
| 0.0123, "12.3E-3", status); |
| expect2(new DecimalFormat("###E0", US, status), |
| 0.123, "123E-3", status); |
| expect2(new DecimalFormat("###E0", US, status), |
| 1.23, "1.23E0", status); |
| expect2(new DecimalFormat("###E0", US, status), |
| 12.3, "12.3E0", status); |
| expect2(new DecimalFormat("###E0", US, status), |
| 123.0, "123E0", status); |
| expect2(new DecimalFormat("###E0", US, status), |
| 1230.0, "1.23E3", status); |
| /* |
| expect(new DecimalFormat("0.#E+00", US, status), |
| new Object[] { new Double(0.00012), "1.2E-04", |
| new Long(12000), "1.2E+04", |
| }); |
| ! |
| ! Unroll this test into individual tests below... |
| ! |
| */ |
| expect2(new DecimalFormat("0.#E+00", US, status), |
| 0.00012, "1.2E-04", status); |
| expect2(new DecimalFormat("0.#E+00", US, status), |
| (int32_t) 12000, "1.2E+04", status); |
| } |
| |
| /** |
| * Upgrade to alphaWorks |
| */ |
| void NumberFormatTest::TestPad(void) { |
| UErrorCode status = U_ZERO_ERROR; |
| DecimalFormatSymbols US(Locale::getUS(), status); |
| CHECK(status, "DecimalFormatSymbols constructor"); |
| |
| expect2(new DecimalFormat("*^##.##", US, status), |
| int32_t(0), "^^^^0", status); |
| expect2(new DecimalFormat("*^##.##", US, status), |
| -1.3, "^-1.3", status); |
| expect2(new DecimalFormat("##0.0####E0*_ 'g-m/s^2'", US, status), |
| int32_t(0), "0.0E0______ g-m/s^2", status); |
| expect(new DecimalFormat("##0.0####E0*_ 'g-m/s^2'", US, status), |
| 1.0/3, "333.333E-3_ g-m/s^2", status); |
| expect2(new DecimalFormat("##0.0####*_ 'g-m/s^2'", US, status), |
| int32_t(0), "0.0______ g-m/s^2", status); |
| expect(new DecimalFormat("##0.0####*_ 'g-m/s^2'", US, status), |
| 1.0/3, "0.33333__ g-m/s^2", status); |
| |
| // Test padding before a sign |
| const char *formatStr = "*x#,###,###,##0.0#;*x(###,###,##0.0#)"; |
| expect2(new DecimalFormat(formatStr, US, status), |
| int32_t(-10), "xxxxxxxxxx(10.0)", status); |
| expect2(new DecimalFormat(formatStr, US, status), |
| int32_t(-1000),"xxxxxxx(1,000.0)", status); |
| expect2(new DecimalFormat(formatStr, US, status), |
| int32_t(-1000000),"xxx(1,000,000.0)", status); |
| expect2(new DecimalFormat(formatStr, US, status), |
| -100.37, "xxxxxxxx(100.37)", status); |
| expect2(new DecimalFormat(formatStr, US, status), |
| -10456.37, "xxxxx(10,456.37)", status); |
| expect2(new DecimalFormat(formatStr, US, status), |
| -1120456.37, "xx(1,120,456.37)", status); |
| expect2(new DecimalFormat(formatStr, US, status), |
| -112045600.37, "(112,045,600.37)", status); |
| expect2(new DecimalFormat(formatStr, US, status), |
| -1252045600.37,"(1,252,045,600.37)", status); |
| |
| expect2(new DecimalFormat(formatStr, US, status), |
| int32_t(10), "xxxxxxxxxxxx10.0", status); |
| expect2(new DecimalFormat(formatStr, US, status), |
| int32_t(1000),"xxxxxxxxx1,000.0", status); |
| expect2(new DecimalFormat(formatStr, US, status), |
| int32_t(1000000),"xxxxx1,000,000.0", status); |
| expect2(new DecimalFormat(formatStr, US, status), |
| 100.37, "xxxxxxxxxx100.37", status); |
| expect2(new DecimalFormat(formatStr, US, status), |
| 10456.37, "xxxxxxx10,456.37", status); |
| expect2(new DecimalFormat(formatStr, US, status), |
| 1120456.37, "xxxx1,120,456.37", status); |
| expect2(new DecimalFormat(formatStr, US, status), |
| 112045600.37, "xx112,045,600.37", status); |
| expect2(new DecimalFormat(formatStr, US, status), |
| 10252045600.37,"10,252,045,600.37", status); |
| |
| |
| // Test padding between a sign and a number |
| const char *formatStr2 = "#,###,###,##0.0#*x;(###,###,##0.0#*x)"; |
| expect2(new DecimalFormat(formatStr2, US, status), |
| int32_t(-10), "(10.0xxxxxxxxxx)", status); |
| expect2(new DecimalFormat(formatStr2, US, status), |
| int32_t(-1000),"(1,000.0xxxxxxx)", status); |
| expect2(new DecimalFormat(formatStr2, US, status), |
| int32_t(-1000000),"(1,000,000.0xxx)", status); |
| expect2(new DecimalFormat(formatStr2, US, status), |
| -100.37, "(100.37xxxxxxxx)", status); |
| expect2(new DecimalFormat(formatStr2, US, status), |
| -10456.37, "(10,456.37xxxxx)", status); |
| expect2(new DecimalFormat(formatStr2, US, status), |
| -1120456.37, "(1,120,456.37xx)", status); |
| expect2(new DecimalFormat(formatStr2, US, status), |
| -112045600.37, "(112,045,600.37)", status); |
| expect2(new DecimalFormat(formatStr2, US, status), |
| -1252045600.37,"(1,252,045,600.37)", status); |
| |
| expect2(new DecimalFormat(formatStr2, US, status), |
| int32_t(10), "10.0xxxxxxxxxxxx", status); |
| expect2(new DecimalFormat(formatStr2, US, status), |
| int32_t(1000),"1,000.0xxxxxxxxx", status); |
| expect2(new DecimalFormat(formatStr2, US, status), |
| int32_t(1000000),"1,000,000.0xxxxx", status); |
| expect2(new DecimalFormat(formatStr2, US, status), |
| 100.37, "100.37xxxxxxxxxx", status); |
| expect2(new DecimalFormat(formatStr2, US, status), |
| 10456.37, "10,456.37xxxxxxx", status); |
| expect2(new DecimalFormat(formatStr2, US, status), |
| 1120456.37, "1,120,456.37xxxx", status); |
| expect2(new DecimalFormat(formatStr2, US, status), |
| 112045600.37, "112,045,600.37xx", status); |
| expect2(new DecimalFormat(formatStr2, US, status), |
| 10252045600.37,"10,252,045,600.37", status); |
| |
| //testing the setPadCharacter(UnicodeString) and getPadCharacterString() |
| DecimalFormat fmt("#", US, status); |
| CHECK(status, "DecimalFormat constructor"); |
| UnicodeString padString("P"); |
| fmt.setPadCharacter(padString); |
| expectPad(fmt, "*P##.##", DecimalFormat::kPadBeforePrefix, 5, padString); |
| fmt.setPadCharacter((UnicodeString)"^"); |
| expectPad(fmt, "*^#", DecimalFormat::kPadBeforePrefix, 1, (UnicodeString)"^"); |
| //commented untill implementation is complete |
| /* fmt.setPadCharacter((UnicodeString)"^^^"); |
| expectPad(fmt, "*^^^#", DecimalFormat::kPadBeforePrefix, 3, (UnicodeString)"^^^"); |
| padString.remove(); |
| padString.append((UChar)0x0061); |
| padString.append((UChar)0x0302); |
| fmt.setPadCharacter(padString); |
| UChar patternChars[]={0x002a, 0x0061, 0x0302, 0x0061, 0x0302, 0x0023, 0x0000}; |
| UnicodeString pattern(patternChars); |
| expectPad(fmt, pattern , DecimalFormat::kPadBeforePrefix, 4, padString); |
| */ |
| |
| } |
| |
| /** |
| * Upgrade to alphaWorks |
| */ |
| void NumberFormatTest::TestPatterns2(void) { |
| UErrorCode status = U_ZERO_ERROR; |
| DecimalFormatSymbols US(Locale::getUS(), status); |
| CHECK(status, "DecimalFormatSymbols constructor"); |
| |
| DecimalFormat fmt("#", US, status); |
| CHECK(status, "DecimalFormat constructor"); |
| |
| UChar hat = 0x005E; /*^*/ |
| |
| expectPad(fmt, "*^#", DecimalFormat::kPadBeforePrefix, 1, hat); |
| expectPad(fmt, "$*^#", DecimalFormat::kPadAfterPrefix, 2, hat); |
| expectPad(fmt, "#*^", DecimalFormat::kPadBeforeSuffix, 1, hat); |
| expectPad(fmt, "#$*^", DecimalFormat::kPadAfterSuffix, 2, hat); |
| expectPad(fmt, "$*^$#", ILLEGAL); |
| expectPad(fmt, "#$*^$", ILLEGAL); |
| expectPad(fmt, "'pre'#,##0*x'post'", DecimalFormat::kPadBeforeSuffix, |
| 12, (UChar)0x0078 /*x*/); |
| expectPad(fmt, "''#0*x", DecimalFormat::kPadBeforeSuffix, |
| 3, (UChar)0x0078 /*x*/); |
| expectPad(fmt, "'I''ll'*a###.##", DecimalFormat::kPadAfterPrefix, |
| 10, (UChar)0x0061 /*a*/); |
| |
| fmt.applyPattern("AA#,##0.00ZZ", status); |
| CHECK(status, "applyPattern"); |
| fmt.setPadCharacter(hat); |
| |
| fmt.setFormatWidth(10); |
| |
| fmt.setPadPosition(DecimalFormat::kPadBeforePrefix); |
| expectPat(fmt, "*^AA#,##0.00ZZ"); |
| |
| fmt.setPadPosition(DecimalFormat::kPadBeforeSuffix); |
| expectPat(fmt, "AA#,##0.00*^ZZ"); |
| |
| fmt.setPadPosition(DecimalFormat::kPadAfterSuffix); |
| expectPat(fmt, "AA#,##0.00ZZ*^"); |
| |
| // 12 3456789012 |
| UnicodeString exp("AA*^#,##0.00ZZ", ""); |
| fmt.setFormatWidth(12); |
| fmt.setPadPosition(DecimalFormat::kPadAfterPrefix); |
| expectPat(fmt, exp); |
| |
| fmt.setFormatWidth(13); |
| // 12 34567890123 |
| expectPat(fmt, "AA*^##,##0.00ZZ"); |
| |
| fmt.setFormatWidth(14); |
| // 12 345678901234 |
| expectPat(fmt, "AA*^###,##0.00ZZ"); |
| |
| fmt.setFormatWidth(15); |
| // 12 3456789012345 |
| expectPat(fmt, "AA*^####,##0.00ZZ"); // This is the interesting case |
| |
| fmt.setFormatWidth(16); |
| // 12 34567890123456 |
| expectPat(fmt, "AA*^#,###,##0.00ZZ"); |
| } |
| |
| void NumberFormatTest::TestSurrogateSupport(void) { |
| UErrorCode status = U_ZERO_ERROR; |
| DecimalFormatSymbols custom(Locale::getUS(), status); |
| CHECK(status, "DecimalFormatSymbols constructor"); |
| |
| custom.setSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol, "decimal"); |
| custom.setSymbol(DecimalFormatSymbols::kPlusSignSymbol, "plus"); |
| custom.setSymbol(DecimalFormatSymbols::kMinusSignSymbol, " minus "); |
| custom.setSymbol(DecimalFormatSymbols::kExponentialSymbol, "exponent"); |
| |
| UnicodeString patternStr("*\\U00010000##.##", ""); |
| patternStr = patternStr.unescape(); |
| UnicodeString expStr("\\U00010000\\U00010000\\U00010000\\U000100000", ""); |
| expStr = expStr.unescape(); |
| expect2(new DecimalFormat(patternStr, custom, status), |
| int32_t(0), expStr, status); |
| |
| status = U_ZERO_ERROR; |
| expect2(new DecimalFormat("*^##.##", custom, status), |
| int32_t(0), "^^^^0", status); |
| status = U_ZERO_ERROR; |
| expect2(new DecimalFormat("##.##", custom, status), |
| -1.3, " minus 1decimal3", status); |
| status = U_ZERO_ERROR; |
| expect2(new DecimalFormat("##0.0####E0 'g-m/s^2'", custom, status), |
| int32_t(0), "0decimal0exponent0 g-m/s^2", status); |
| status = U_ZERO_ERROR; |
| expect(new DecimalFormat("##0.0####E0 'g-m/s^2'", custom, status), |
| 1.0/3, "333decimal333exponent minus 3 g-m/s^2", status); |
| status = U_ZERO_ERROR; |
| expect2(new DecimalFormat("##0.0#### 'g-m/s^2'", custom, status), |
| int32_t(0), "0decimal0 g-m/s^2", status); |
| status = U_ZERO_ERROR; |
| expect(new DecimalFormat("##0.0#### 'g-m/s^2'", custom, status), |
| 1.0/3, "0decimal33333 g-m/s^2", status); |
| |
| UnicodeString zero((UChar32)0x10000); |
| UnicodeString one((UChar32)0x10001); |
| UnicodeString two((UChar32)0x10002); |
| UnicodeString five((UChar32)0x10005); |
| custom.setSymbol(DecimalFormatSymbols::kZeroDigitSymbol, zero); |
| custom.setSymbol(DecimalFormatSymbols::kOneDigitSymbol, one); |
| custom.setSymbol(DecimalFormatSymbols::kTwoDigitSymbol, two); |
| custom.setSymbol(DecimalFormatSymbols::kFiveDigitSymbol, five); |
| expStr = UnicodeString("\\U00010001decimal\\U00010002\\U00010005\\U00010000", ""); |
| expStr = expStr.unescape(); |
| status = U_ZERO_ERROR; |
| expect2(new DecimalFormat("##0.000", custom, status), |
| 1.25, expStr, status); |
| |
| custom.setSymbol(DecimalFormatSymbols::kZeroDigitSymbol, (UChar)0x30); |
| custom.setSymbol(DecimalFormatSymbols::kCurrencySymbol, "units of money"); |
| custom.setSymbol(DecimalFormatSymbols::kMonetarySeparatorSymbol, "money separator"); |
| patternStr = UNICODE_STRING_SIMPLE("0.00 \\u00A4' in your bank account'"); |
| patternStr = patternStr.unescape(); |
| expStr = UnicodeString(" minus 20money separator00 units of money in your bank account", ""); |
| status = U_ZERO_ERROR; |
| expect2(new DecimalFormat(patternStr, custom, status), |
| int32_t(-20), expStr, status); |
| |
| custom.setSymbol(DecimalFormatSymbols::kPercentSymbol, "percent"); |
| patternStr = "'You''ve lost ' -0.00 %' of your money today'"; |
| patternStr = patternStr.unescape(); |
| expStr = UnicodeString(" minus You've lost minus 2000decimal00 percent of your money today", ""); |
| status = U_ZERO_ERROR; |
| expect2(new DecimalFormat(patternStr, custom, status), |
| int32_t(-20), expStr, status); |
| } |
| |
| void NumberFormatTest::TestCurrencyPatterns(void) { |
| int32_t i, locCount; |
| const Locale* locs = NumberFormat::getAvailableLocales(locCount); |
| for (i=0; i<locCount; ++i) { |
| UErrorCode ec = U_ZERO_ERROR; |
| NumberFormat* nf = NumberFormat::createCurrencyInstance(locs[i], ec); |
| if (U_FAILURE(ec)) { |
| errln("FAIL: Can't create NumberFormat(%s) - %s", locs[i].getName(), u_errorName(ec)); |
| } else { |
| // Make sure currency formats do not have a variable number |
| // of fraction digits |
| int32_t min = nf->getMinimumFractionDigits(); |
| int32_t max = nf->getMaximumFractionDigits(); |
| if (min != max) { |
| UnicodeString a, b; |
| nf->format(1.0, a); |
| nf->format(1.125, b); |
| errln((UnicodeString)"FAIL: " + locs[i].getName() + |
| " min fraction digits != max fraction digits; " |
| "x 1.0 => " + escape(a) + |
| "; x 1.125 => " + escape(b)); |
| } |
| |
| // Make sure EURO currency formats have exactly 2 fraction digits |
| DecimalFormat* df = dynamic_cast<DecimalFormat*>(nf); |
| if (df != NULL) { |
| if (u_strcmp(EUR, df->getCurrency()) == 0) { |
| if (min != 2 || max != 2) { |
| UnicodeString a; |
| nf->format(1.0, a); |
| errln((UnicodeString)"FAIL: " + locs[i].getName() + |
| " is a EURO format but it does not have 2 fraction digits; " |
| "x 1.0 => " + |
| escape(a)); |
| } |
| } |
| } |
| } |
| delete nf; |
| } |
| } |
| |
| void NumberFormatTest::TestRegCurrency(void) { |
| #if !UCONFIG_NO_SERVICE |
| UErrorCode status = U_ZERO_ERROR; |
| UChar USD[4]; |
| ucurr_forLocale("en_US", USD, 4, &status); |
| UChar YEN[4]; |
| ucurr_forLocale("ja_JP", YEN, 4, &status); |
| UChar TMP[4]; |
| static const UChar QQQ[] = {0x51, 0x51, 0x51, 0}; |
| if(U_FAILURE(status)) { |
| errcheckln(status, "Unable to get currency for locale, error %s", u_errorName(status)); |
| return; |
| } |
| |
| UCurrRegistryKey enkey = ucurr_register(YEN, "en_US", &status); |
| UCurrRegistryKey enUSEUROkey = ucurr_register(QQQ, "en_US_EURO", &status); |
| |
| ucurr_forLocale("en_US", TMP, 4, &status); |
| if (u_strcmp(YEN, TMP) != 0) { |
| errln("FAIL: didn't return YEN registered for en_US"); |
| } |
| |
| ucurr_forLocale("en_US_EURO", TMP, 4, &status); |
| if (u_strcmp(QQQ, TMP) != 0) { |
| errln("FAIL: didn't return QQQ for en_US_EURO"); |
| } |
| |
| int32_t fallbackLen = ucurr_forLocale("en_XX_BAR", TMP, 4, &status); |
| if (fallbackLen) { |
| errln("FAIL: tried to fallback en_XX_BAR"); |
| } |
| status = U_ZERO_ERROR; // reset |
| |
| if (!ucurr_unregister(enkey, &status)) { |
| errln("FAIL: couldn't unregister enkey"); |
| } |
| |
| ucurr_forLocale("en_US", TMP, 4, &status); |
| if (u_strcmp(USD, TMP) != 0) { |
| errln("FAIL: didn't return USD for en_US after unregister of en_US"); |
| } |
| status = U_ZERO_ERROR; // reset |
| |
| ucurr_forLocale("en_US_EURO", TMP, 4, &status); |
| if (u_strcmp(QQQ, TMP) != 0) { |
| errln("FAIL: didn't return QQQ for en_US_EURO after unregister of en_US"); |
| } |
| |
| ucurr_forLocale("en_US_BLAH", TMP, 4, &status); |
| if (u_strcmp(USD, TMP) != 0) { |
| errln("FAIL: could not find USD for en_US_BLAH after unregister of en"); |
| } |
| status = U_ZERO_ERROR; // reset |
| |
| if (!ucurr_unregister(enUSEUROkey, &status)) { |
| errln("FAIL: couldn't unregister enUSEUROkey"); |
| } |
| |
| ucurr_forLocale("en_US_EURO", TMP, 4, &status); |
| if (u_strcmp(EUR, TMP) != 0) { |
| errln("FAIL: didn't return EUR for en_US_EURO after unregister of en_US_EURO"); |
| } |
| status = U_ZERO_ERROR; // reset |
| #endif |
| } |
| |
| void NumberFormatTest::TestCurrencyNames(void) { |
| // Do a basic check of getName() |
| // USD { "US$", "US Dollar" } // 04/04/1792- |
| UErrorCode ec = U_ZERO_ERROR; |
| static const UChar USD[] = {0x55, 0x53, 0x44, 0}; /*USD*/ |
| static const UChar USX[] = {0x55, 0x53, 0x58, 0}; /*USX*/ |
| static const UChar CAD[] = {0x43, 0x41, 0x44, 0}; /*CAD*/ |
| static const UChar ITL[] = {0x49, 0x54, 0x4C, 0}; /*ITL*/ |
| UBool isChoiceFormat; |
| int32_t len; |
| 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)", |
| UnicodeString("$"), |
| UnicodeString(ucurr_getName(USD, "en", |
| UCURR_SYMBOL_NAME, |
| &isChoiceFormat, &len, &ec)), |
| possibleDataError); |
| assertEquals("USD.getName(LONG_NAME)", |
| UnicodeString("US Dollar"), |
| UnicodeString(ucurr_getName(USD, "en", |
| UCURR_LONG_NAME, |
| &isChoiceFormat, &len, &ec)), |
| possibleDataError); |
| assertEquals("CAD.getName(SYMBOL_NAME)", |
| UnicodeString("CA$"), |
| UnicodeString(ucurr_getName(CAD, "en", |
| UCURR_SYMBOL_NAME, |
| &isChoiceFormat, &len, &ec)), |
| possibleDataError); |
| assertEquals("CAD.getName(SYMBOL_NAME)", |
| UnicodeString("$"), |
| UnicodeString(ucurr_getName(CAD, "en_CA", |
| UCURR_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("CAD.getName(SYMBOL_NAME)", |
| UnicodeString("CA$"), |
| UnicodeString(ucurr_getName(CAD, "en_NZ", |
| UCURR_SYMBOL_NAME, |
| &isChoiceFormat, &len, &ec)), |
| possibleDataError); |
| assertEquals("USX.getName(LONG_NAME)", |
| UnicodeString("USX"), |
| UnicodeString(ucurr_getName(USX, "en_US", |
| UCURR_LONG_NAME, |
| &isChoiceFormat, &len, &ec)), |
| possibleDataError); |
| assertSuccess("ucurr_getName", ec); |
| |
| ec = U_ZERO_ERROR; |
| |
| // Test that a default or fallback warning is being returned. JB 4239. |
| ucurr_getName(CAD, "es_ES", UCURR_LONG_NAME, &isChoiceFormat, |
| &len, &ec); |
| assertTrue("ucurr_getName (es_ES fallback)", |
| U_USING_FALLBACK_WARNING == ec, TRUE, possibleDataError); |
| |
| ucurr_getName(CAD, "zh_TW", UCURR_LONG_NAME, &isChoiceFormat, |
| &len, &ec); |
| assertTrue("ucurr_getName (zh_TW fallback)", |
| U_USING_FALLBACK_WARNING == ec, TRUE, possibleDataError); |
| |
| ucurr_getName(CAD, "en_US", UCURR_LONG_NAME, &isChoiceFormat, |
| &len, &ec); |
| assertTrue("ucurr_getName (en_US default)", |
| U_USING_DEFAULT_WARNING == ec || U_USING_FALLBACK_WARNING == ec, TRUE); |
| |
| ucurr_getName(CAD, "ti", UCURR_LONG_NAME, &isChoiceFormat, |
| &len, &ec); |
| assertTrue("ucurr_getName (ti default)", |
| U_USING_DEFAULT_WARNING == ec, TRUE); |
| |
| // Test that a default warning is being returned when falling back to root. JB 4536. |
| ucurr_getName(ITL, "cy", UCURR_LONG_NAME, &isChoiceFormat, |
| &len, &ec); |
| assertTrue("ucurr_getName (cy default to root)", |
| U_USING_DEFAULT_WARNING == ec, TRUE); |
| |
| // TODO add more tests later |
| } |
| |
| 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}; /*???*/ |
| CurrencyUnit cu(USD, ec); |
| assertSuccess("CurrencyUnit", ec); |
| |
| const UChar * r = cu.getISOCurrency(); // who is the buffer owner ? |
| assertEquals("getISOCurrency()", USD, r); |
| |
| CurrencyUnit cu2(cu); |
| if (!(cu2 == cu)){ |
| errln("CurrencyUnit copy constructed object should be same"); |
| } |
| |
| CurrencyUnit * cu3 = (CurrencyUnit *)cu.clone(); |
| if (!(*cu3 == cu)){ |
| errln("CurrencyUnit cloned object should be same"); |
| } |
| CurrencyUnit bad(BAD, ec); |
| assertSuccess("CurrencyUnit", ec); |
| if (cu.getIndex() == bad.getIndex()) { |
| errln("Indexes of different currencies should differ."); |
| } |
| CurrencyUnit bad2(BAD2, ec); |
| assertSuccess("CurrencyUnit", ec); |
| if (bad2.getIndex() != bad.getIndex()) { |
| errln("Indexes of unrecognized currencies should be the same."); |
| } |
| if (bad == bad2) { |
| errln("Different unrecognized currencies should not be equal."); |
| } |
| bad = bad2; |
| if (bad != bad2) { |
| errln("Currency unit assignment should be the same."); |
| } |
| delete cu3; |
| } |
| |
| void NumberFormatTest::TestCurrencyAmount(void){ |
| UErrorCode ec = U_ZERO_ERROR; |
| static const UChar USD[] = {85, 83, 68, 0}; /*USD*/ |
| CurrencyAmount ca(9, USD, ec); |
| assertSuccess("CurrencyAmount", ec); |
| |
| CurrencyAmount ca2(ca); |
| if (!(ca2 == ca)){ |
| errln("CurrencyAmount copy constructed object should be same"); |
| } |
| |
| ca2=ca; |
| if (!(ca2 == ca)){ |
| errln("CurrencyAmount assigned object should be same"); |
| } |
| |
| CurrencyAmount *ca3 = (CurrencyAmount *)ca.clone(); |
| if (!(*ca3 == ca)){ |
| errln("CurrencyAmount cloned object should be same"); |
| } |
| delete ca3; |
| } |
| |
| void NumberFormatTest::TestSymbolsWithBadLocale(void) { |
| Locale locDefault; |
| static const char *badLocales[] = { |
| // length < ULOC_FULLNAME_CAPACITY |
| "x-crazy_ZZ_MY_SPECIAL_ADMINISTRATION_REGION_NEEDS_A_SPECIAL_VARIANT_WITH_A_REALLY_REALLY_REALLY_REALLY_REALLY_REALLY_REALLY_LONG_NAME", |
| |
| // length > ULOC_FULLNAME_CAPACITY |
| "x-crazy_ZZ_MY_SPECIAL_ADMINISTRATION_REGION_NEEDS_A_SPECIAL_VARIANT_WITH_A_REALLY_REALLY_REALLY_REALLY_REALLY_REALLY_REALLY_REALLY_REALLY_REALLY_REALLY_LONG_NAME" |
| }; // expect U_USING_DEFAULT_WARNING for both |
| |
| unsigned int i; |
| for (i = 0; i < sizeof(badLocales) / sizeof(char*); i++) { |
| const char *localeName = badLocales[i]; |
| Locale locBad(localeName); |
| UErrorCode status = U_ZERO_ERROR; |
| 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()); |
| DecimalFormatSymbols mySymbols(status); |
| if (status != U_USING_DEFAULT_WARNING) { |
| errln("DecimalFormatSymbols should return U_USING_DEFAULT_WARNING."); |
| } |
| if (strcmp(mySymbols.getLocale().getName(), locBad.getName()) != 0) { |
| errln("DecimalFormatSymbols does not have the right locale.", locBad.getName()); |
| } |
| int symbolEnum = (int)DecimalFormatSymbols::kDecimalSeparatorSymbol; |
| for (; symbolEnum < (int)DecimalFormatSymbols::kFormatSymbolCount; symbolEnum++) { |
| UnicodeString symbolString = mySymbols.getSymbol((DecimalFormatSymbols::ENumberFormatSymbol)symbolEnum); |
| logln(UnicodeString("DecimalFormatSymbols[") + symbolEnum + UnicodeString("] = ") + prettify(symbolString)); |
| if (symbolString.length() == 0 |
| && symbolEnum != (int)DecimalFormatSymbols::kGroupingSeparatorSymbol |
| && symbolEnum != (int)DecimalFormatSymbols::kMonetaryGroupingSeparatorSymbol) |
| { |
| errln("DecimalFormatSymbols has an empty string at index %d.", symbolEnum); |
| } |
| } |
| |
| status = U_ZERO_ERROR; |
| Locale::setDefault(locDefault, status); |
| logln("Current locale is %s", Locale::getDefault().getName()); |
| } |
| } |
| |
| /** |
| * Check that adoptDecimalFormatSymbols and setDecimalFormatSymbols |
| * behave the same, except for memory ownership semantics. (No |
| * version of this test on Java, since Java has only one method.) |
| */ |
| void NumberFormatTest::TestAdoptDecimalFormatSymbols(void) { |
| UErrorCode ec = U_ZERO_ERROR; |
| DecimalFormatSymbols *sym = new DecimalFormatSymbols(Locale::getUS(), ec); |
| if (U_FAILURE(ec)) { |
| errcheckln(ec, "Fail: DecimalFormatSymbols constructor - %s", u_errorName(ec)); |
| delete sym; |
| return; |
| } |
| UnicodeString pat(" #,##0.00"); |
| pat.insert(0, (UChar)0x00A4); |
| DecimalFormat fmt(pat, sym, ec); |
| if (U_FAILURE(ec)) { |
| errln("Fail: DecimalFormat constructor"); |
| return; |
| } |
| |
| UnicodeString str; |
| fmt.format(2350.75, str); |
| if (str == "$ 2,350.75") { |
| logln(str); |
| } else { |
| dataerrln("Fail: " + str + ", expected $ 2,350.75"); |
| } |
| |
| sym = new DecimalFormatSymbols(Locale::getUS(), ec); |
| if (U_FAILURE(ec)) { |
| errln("Fail: DecimalFormatSymbols constructor"); |
| delete sym; |
| return; |
| } |
| sym->setSymbol(DecimalFormatSymbols::kCurrencySymbol, "Q"); |
| fmt.adoptDecimalFormatSymbols(sym); |
| |
| str.truncate(0); |
| fmt.format(2350.75, str); |
| if (str == "Q 2,350.75") { |
| logln(str); |
| } else { |
| dataerrln("Fail: adoptDecimalFormatSymbols -> " + str + ", expected Q 2,350.75"); |
| } |
| |
| sym = new DecimalFormatSymbols(Locale::getUS(), ec); |
| if (U_FAILURE(ec)) { |
| errln("Fail: DecimalFormatSymbols constructor"); |
| delete sym; |
| return; |
| } |
| DecimalFormat fmt2(pat, sym, ec); |
| if (U_FAILURE(ec)) { |
| errln("Fail: DecimalFormat constructor"); |
| return; |
| } |
| |
| DecimalFormatSymbols sym2(Locale::getUS(), ec); |
| if (U_FAILURE(ec)) { |
| errln("Fail: DecimalFormatSymbols constructor"); |
| return; |
| } |
| sym2.setSymbol(DecimalFormatSymbols::kCurrencySymbol, "Q"); |
| fmt2.setDecimalFormatSymbols(sym2); |
| |
| str.truncate(0); |
| fmt2.format(2350.75, str); |
| if (str == "Q 2,350.75") { |
| logln(str); |
| } else { |
| dataerrln("Fail: setDecimalFormatSymbols -> " + str + ", expected Q 2,350.75"); |
| } |
| } |
| |
| void NumberFormatTest::TestPerMill() { |
| UErrorCode ec = U_ZERO_ERROR; |
| UnicodeString str; |
| 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)); |
| |
| DecimalFormatSymbols sym(Locale::getUS(), ec); |
| sym.setSymbol(DecimalFormatSymbols::kPerMillSymbol, ctou("m")); |
| DecimalFormat fmt2("", sym, ec); |
| fmt2.applyLocalizedPattern("###.###m", ec); |
| if (!assertSuccess("setup", ec)) return; |
| str.truncate(0); |
| assertEquals("0.4857 x ###.###m", |
| "485.7m", fmt2.format(0.4857, str)); |
| } |
| |
| /** |
| * Generic test for patterns that should be legal/illegal. |
| */ |
| void NumberFormatTest::TestIllegalPatterns() { |
| // Test cases: |
| // Prefix with "-:" for illegal patterns |
| // Prefix with "+:" for legal patterns |
| const char* DATA[] = { |
| // Unquoted special characters in the suffix are illegal |
| "-:000.000|###", |
| "+:000.000'|###'", |
| 0 |
| }; |
| for (int32_t i=0; DATA[i]; ++i) { |
| const char* pat=DATA[i]; |
| UBool valid = (*pat) == '+'; |
| pat += 2; |
| UErrorCode ec = U_ZERO_ERROR; |
| DecimalFormat fmt(pat, ec); // locale doesn't matter here |
| if (U_SUCCESS(ec) == valid) { |
| logln("Ok: pattern \"%s\": %s", |
| pat, u_errorName(ec)); |
| } else { |
| errcheckln(ec, "FAIL: pattern \"%s\" should have %s; got %s", |
| pat, (valid?"succeeded":"failed"), |
| u_errorName(ec)); |
| } |
| } |
| } |
| |
| //---------------------------------------------------------------------- |
| |
| static const char* KEYWORDS[] = { |
| /*0*/ "ref=", // <reference pattern to parse numbers> |
| /*1*/ "loc=", // <locale for formats> |
| /*2*/ "f:", // <pattern or '-'> <number> <exp. string> |
| /*3*/ "fp:", // <pattern or '-'> <number> <exp. string> <exp. number> |
| /*4*/ "rt:", // <pattern or '-'> <(exp.) number> <(exp.) string> |
| /*5*/ "p:", // <pattern or '-'> <string> <exp. number> |
| /*6*/ "perr:", // <pattern or '-'> <invalid string> |
| /*7*/ "pat:", // <pattern or '-'> <exp. toPattern or '-' or 'err'> |
| /*8*/ "fpc:", // <pattern or '-'> <curr.amt> <exp. string> <exp. curr.amt> |
| 0 |
| }; |
| |
| /** |
| * Return an integer representing the next token from this |
| * iterator. The integer will be an index into the given list, or |
| * -1 if there are no more tokens, or -2 if the token is not on |
| * the list. |
| */ |
| static int32_t keywordIndex(const UnicodeString& tok) { |
| for (int32_t i=0; KEYWORDS[i]!=0; ++i) { |
| if (tok==KEYWORDS[i]) { |
| return i; |
| } |
| } |
| return -1; |
| } |
| |
| /** |
| * Parse a CurrencyAmount using the given NumberFormat, with |
| * the 'delim' character separating the number and the currency. |
| */ |
| static void parseCurrencyAmount(const UnicodeString& str, |
| const NumberFormat& fmt, |
| UChar delim, |
| Formattable& result, |
| UErrorCode& ec) { |
| UnicodeString num, cur; |
| int32_t i = str.indexOf(delim); |
| str.extractBetween(0, i, num); |
| str.extractBetween(i+1, INT32_MAX, cur); |
| Formattable n; |
| fmt.parse(num, n, ec); |
| result.adoptObject(new CurrencyAmount(n, cur.getTerminatedBuffer(), ec)); |
| } |
| |
| void NumberFormatTest::TestCases() { |
| UErrorCode ec = U_ZERO_ERROR; |
| TextFile reader("NumberFormatTestCases.txt", "UTF8", ec); |
| if (U_FAILURE(ec)) { |
| dataerrln("Couldn't open NumberFormatTestCases.txt"); |
| return; |
| } |
| TokenIterator tokens(&reader); |
| |
| Locale loc("en", "US", ""); |
| DecimalFormat *ref = 0, *fmt = 0; |
| MeasureFormat *mfmt = 0; |
| UnicodeString pat, tok, mloc, str, out, where, currAmt; |
| Formattable n; |
| |
| for (;;) { |
| ec = U_ZERO_ERROR; |
| if (!tokens.next(tok, ec)) { |
| break; |
| } |
| where = UnicodeString("(") + tokens.getLineNumber() + ") "; |
| int32_t cmd = keywordIndex(tok); |
| switch (cmd) { |
| case 0: |
| // ref= <reference pattern> |
| if (!tokens.next(tok, ec)) goto error; |
| delete ref; |
| ref = new DecimalFormat(tok, |
| new DecimalFormatSymbols(Locale::getUS(), ec), ec); |
| if (U_FAILURE(ec)) { |
| dataerrln("Error constructing DecimalFormat"); |
| goto error; |
| } |
| break; |
| case 1: |
| // loc= <locale> |
| if (!tokens.next(tok, ec)) goto error; |
| loc = Locale::createFromName(CharString().appendInvariantChars(tok, ec).data()); |
| break; |
| case 2: // f: |
| case 3: // fp: |
| case 4: // rt: |
| case 5: // p: |
| if (!tokens.next(tok, ec)) goto error; |
| if (tok != "-") { |
| pat = tok; |
| delete fmt; |
| fmt = new DecimalFormat(pat, new DecimalFormatSymbols(loc, ec), ec); |
| if (U_FAILURE(ec)) { |
| errln("FAIL: " + where + "Pattern \"" + pat + "\": " + u_errorName(ec)); |
| ec = U_ZERO_ERROR; |
| if (!tokens.next(tok, ec)) goto error; |
| if (!tokens.next(tok, ec)) goto error; |
| if (cmd == 3) { |
| if (!tokens.next(tok, ec)) goto error; |
| } |
| continue; |
| } |
| } |
| if (cmd == 2 || cmd == 3 || cmd == 4) { |
| // f: <pattern or '-'> <number> <exp. string> |
| // fp: <pattern or '-'> <number> <exp. string> <exp. number> |
| // rt: <pattern or '-'> <number> <string> |
| UnicodeString num; |
| if (!tokens.next(num, ec)) goto error; |
| if (!tokens.next(str, ec)) goto error; |
| ref->parse(num, n, ec); |
| assertSuccess("parse", ec); |
| assertEquals(where + "\"" + pat + "\".format(" + num + ")", |
| str, fmt->format(n, out.remove(), ec)); |
| assertSuccess("format", ec); |
| if (cmd == 3) { // fp: |
| if (!tokens.next(num, ec)) goto error; |
| ref->parse(num, n, ec); |
| assertSuccess("parse", ec); |
| |